2016-04-12 7 views
0

Ich habe eine Aufgabe, in der ich mehrere Datentypen zusammen haben werde; Zeichen, mehrere ganze Zahlen und ein doppelter Genauigkeitswert, die eine Lösung für ein Problem darstellen.Ein Problem mit MPI_GATHER/MPI_GATHERV in F90 mit abgeleiteten Datentypen

Im Moment habe ich ein "Spielzeug" F90-Programm, das MPI mit Zufallszahlen und eine erfundene Zeichenfolge für jeden Prozessor verwendet. Ich möchte einen Datentyp haben, der das Zeichen und die Zufallszahl mit doppelter Genauigkeit enthält.

Ich werde MPI_REDUCE verwenden, um den Minimalwert für die doppelten Genauigkeitswerte zu erhalten. Ich werde den Datentyp für jeden Prozess über die Funktion MPI_GATHERV zum Stamm (Rang = 0) zusammenführen lassen.

Mein Ziel ist es, den Mindestwert aus den zufälligen Werten auf den Datentyp abzustimmen. Das wäre die endgültige Antwort. Ich habe bis jetzt alle möglichen Ideen ausprobiert, aber ohne Erfolg. Ich lande mit "forrtl: schwere SIGSEGV, Segmentierung Fehler aufgetreten".

Nun habe ich auch einige der anderen Beiträge angeschaut. Zum Beispiel kann ich die Anweisung "use mpif.h" für dieses spezielle System nicht verwenden.

Aber, endlich, hier ist der Code:

program fredtype 
    implicit none 
    include '/opt/apps/intel15/mvapich2/2.1/include/mpif.h' 



    integer rank,size,ierror,tag,status(MPI_STATUS_SIZE),i,np,irank 
    integer blocklen(2),type(2),num,rcount(4) 
    double precision :: x,aout 
    character(len=4) :: y 

    type, BIND(C) :: mytype 
    double precision :: x,aout,test 
    character :: y 
    end type mytype 

    type(mytype) :: foo,foobag(4) 
    integer(KIND=MPI_ADDRESS_KIND) :: disp(2),base 


    call MPI_INIT(ierror) 

call MPI_COMM_SIZE(MPI_COMM_WORLD,size,ierror) 
    call MPI_COMM_RANK(MPI_COMM_WORLD,rank,ierror) 

    aout = 99999999999.99 

    call random_seed() 
    call random_number(x) 



    if(rank.eq.0)y="dogs" 
    if(rank.eq.1)y="cats" 
    if(rank.eq.2)y="tree" 
    if(rank.eq.3)y="woof" 

    print *,rank,x,y 


    call MPI_GET_ADDRESS(foo%x,disp(1),ierror) 
    call MPI_GET_ADDRESS(foo%y,disp(2),ierror) 

    base = disp(1) 
call MPI_COMM_SIZE(MPI_COMM_WORLD,size,ierror) 
    call MPI_COMM_RANK(MPI_COMM_WORLD,rank,ierror) 

    aout = 99999999999.99 

    call random_seed() 
    call random_number(x) 



    if(rank.eq.0)y="dogs" 
    if(rank.eq.1)y="cats" 
    if(rank.eq.2)y="tree" 
    if(rank.eq.3)y="woof" 

    print *,rank,x,y 


    call MPI_GET_ADDRESS(foo%x,disp(1),ierror) 
    call MPI_GET_ADDRESS(foo%y,disp(2),ierror) 

    base = disp(1) 
call MPI_COMM_SIZE(MPI_COMM_WORLD,size,ierror) 
    call MPI_COMM_RANK(MPI_COMM_WORLD,rank,ierror) 

    aout = 99999999999.99 

    call random_seed() 
    call random_number(x) 



    if(rank.eq.0)y="dogs" 
    if(rank.eq.1)y="cats" 
    if(rank.eq.2)y="tree" 
    if(rank.eq.3)y="woof" 

    print *,rank,x,y 


    call MPI_GET_ADDRESS(foo%x,disp(1),ierror) 
    call MPI_GET_ADDRESS(foo%y,disp(2),ierror) 

    base = disp(1) 
    disp(2) = disp(2) - base 

    blocklen(1) = 1 
    blocklen(2) = 1 

    type(1) = MPI_DOUBLE_PRECISION 
    type(2) = MPI_CHARACTER 


    call MPI_TYPE_CREATE_STRUCT(2,blocklen,disp,type,foo,ierror) 
    call MPI_TYPE_COMMIT(foo,ierror) 




     call MPI_REDUCE(x,aout,1,MPI_DOUBLE_PRECISION,MPI_MIN,0,MPI_COMM_WORLD,i\ 
error) 

     call MPI_GATHER(num,1,MPI_INT,rcount,1,MPI_INT,0,MPI_COMM_WORLD) 
     call MPI_GATHERV(foo,num,type,foobag,rcount,disp,type,0,MPI_COMM_WORLD) 


     if(rank.eq.0)then 
      print *,'fin ',aout 

      end if 




end program fredtype 

Vielen Dank für jede Hilfe. Mit freundlichen Grüßen Erin

+0

Nur eine Gesundheitsprüfung, Ihr tatsächlicher Code wiederholt nicht den mittleren Block 3 Mal als die Version, die Sie hier gepostet haben, richtig? Ich denke nicht, dass das ein Problem verursachen würde, aber das ist definitiv seltsam. – Gilles

Antwort

1

Ihr Code ist definitiv zu verwirrend für mich zu versuchen, es vollständig zu beheben. Lassen Sie sich also einfach mal davon aus, dass Sie Ihre Art haben mytype wie folgt definiert:

type, bind(C) :: mytype 
    double precision :: x, aout, test 
    character(len=4) :: y 
end type mytype 

(Rk. Habe ich len=4 die Definition von y hinzufügen, wie es schien, von Ihrem ursprünglichen Code zu fehlen könnte ich falsch es dass und wenn ja, nur einstellen blocklen(2) in den nachfolgenden Code entsprechend)

Nun nehmen wir an, dass Sie nur die x und y Felder Ihrer Variablen vom Typ mytype übertragen möchten. Dazu müssen Sie einen geeigneten abgeleiteten MPI-Typ erstellen, indem Sie zunächst die grundlegenden Typen und deren Position in Ihrer Struktur definieren und dann MPI_Type_create_resized() definieren, um die wahre Ausdehnung und Untergrenze des Typs einschließlich der Löcher zu definieren.

Der schwierige Teil ist normalerweise zu bewerten, was die untere Grenze und das Ausmaß Ihres Fortran-Typs ist. Hier, wie Sie in die Felder, die Sie übertragen die erste und letzte von ihnen, und wie Sie bind(C) hinzugefügt haben, können Sie einfach MPI_Type_get_extend() verwenden, um diese Informationen zu erhalten. Wenn Sie jedoch x oder y (die ersten und letzten Felder des Typs) nicht in den Datentyp MPI aufgenommen haben, würde MPI_Type_get_extent() nicht zurückgeben, was Sie benötigt hätten. Also werde ich Ihnen eine Alternative vorschlagen (etwas umständlich) Ansatz, wird, glaube ich, immer funktionieren:

integer :: ierror, typefoo, tmptypefoo 
integer :: blocklen(2), types(2) 
type(mytype) :: foobag(4) 
integer(kind=MPI_ADDRESS_KIND) :: disp(2), lb, extent 

call MPI_Get_address(foobag(1), lb, ierror) 
call MPI_Get_address(foobag(1)%x, disp(1), ierror) 
call MPI_Get_address(foobag(1)%y, disp(2), ierror) 
call MPI_Get_address(foobag(2), extent, ierror) 
disp(1) = MPI_Aint_diff(disp(1), lb) 
disp(2) = MPI_Aint_diff(disp(2), lb) 
extent = MPI_Aint_diff(extent, lb) 
lb = 0 

blocklen(1) = 1 
blocklen(2) = 4 

types(1) = MPI_DOUBLE_PRECISION 
types(2) = MPI_CHARACTER 

call MPI_Type_create_struct(2, blocklen, disp, types, tmptypefoo, ierror) 
call MPI_Type_create_resized(tmptypefoo, lb, extent, typefoo, ierror) 
call MPI_Type_commit(typefoo, ierror) 

So wie Sie sehen können, lb dient als Basisadresse für die Verschiebungen in der Struktur und der type extent wird berechnet, indem die relativen Adressen zweier aufeinanderfolgender Elemente eines Arrays vom Typ mytype verwendet werden.
Dann erstellen wir einen intermediaten MPI-Datentyp tmptypefoo, der nur die Informationen über die tatsächlichen Daten enthält, die wir übertragen werden, und wir erweitern es mit Informationen über die tatsächliche untere Grenze und das Ausmaß des Fortran-Typs in typefoo. Zu guter Letzt muss nur noch der letzte Code eingegeben werden, da er nur für den Datentransfer verwendet werden kann.

+0

Wow! Das ist fantastisch! Vielen Dank. Darf ich noch eine Frage stellen, dann übergebe ich bitte typefoo in der Funktion MPI_GATHERV? Danke noch einmal. – user1544953