2017-10-25 22 views
0

私はMPIを初めて使いましたが、これが正しいアプローチであるかどうかはわかりません。または、私がこの方法でMPIを使用するはずですが、私の問題は次のとおりです:構造体配列の各要素のためのmpiコミュニケータ

私はユーザー定義構造体へのポインタの配列を持っています。各プロセスで何が起きているかによって、配列の要素はNULLか、ユーザー定義の構造体のインスタンスへのポインタになります。私は今、MPI上でお互いに通信するために配列の要素を必要とします。これはいくつか存在しないため、問題があります。

私は詳しく述べるべきです:構造体には、通信が必要な機能へのポインタがあります。要素が存在する場合、関数が呼び出されます。そうでない場合、そうではありません。

私の考え:要素がNOT NULLであるすべてのプロセッサを含むアレイの各要素に対して、専用のMPIコミュニケータを作成します。次に、それぞれの要素の通信中にこのコミュニケータを参照します。

アレイの各要素に1つずつ、MPIコミュニケータの「アレイ」を作成できますか?そして、各要素についてMPI_COMM_ARRAY [i]を参照しますか? または、私は完全に行き詰まっているので、配列のエントリとしてNULLを使用しないでください。 これを「きれいに」コード化する方法は何ですか?

これは私が現在行っていることの単純化です。これは、偶然にも細胞がすべてのプロセスに存在する場合に機能します。そうでないと失敗します。 例コード:

#include <stdio.h> 
#include <stdlib.h> 
#include <mpi.h> 


void * createcell(); 
void Cell_givenumberofvertices(void * _self, int * NbOfVertices); 
void Cell_givenumberofvertices_parallel(void * _self, int * NbOfVertices); 
void Cell_addvertex(void * _self); 
void addvertex(void * _self); 
void getnumberofvertices(void * _self, int * NbOfVertices); 


struct Cell{ 
    unsigned NbOfVertices; 
    void (* givenumberofvertices)(void * _self, int * NbOfVertices); 
    void (* addvertex)(void * _self); 
}; 

void * createcell(){ 
    struct Cell * self = calloc(1, sizeof(struct Cell)); 
    int world_size; 

    MPI_Comm_size(MPI_COMM_WORLD,&world_size); 

    self->NbOfVertices = 0; 
    self->addvertex = Cell_addvertex; 

    if(world_size==0) self->givenumberofvertices = Cell_givenumberofvertices; 
    else self->givenumberofvertices = Cell_givenumberofvertices_parallel; 

    return self; 
} 

void Cell_givenumberofvertices(void * _self, int * NbOfVertices){ 
    struct Cell * self = _self; 
    * NbOfVertices = self->NbOfVertices; 
    return; 
} 

void Cell_givenumberofvertices_parallel(void * _self, int * NbOfVertices){ 
    struct Cell * self = _self; 
    int world_size, world_rank; 
    int i; 
    int * NbVertxOnProcess; 
    int totalnumberofvertices=0; 

    MPI_Comm_size(MPI_COMM_WORLD,&world_size); 
    MPI_Comm_rank(MPI_COMM_WORLD,&world_rank); 
    NbVertxOnProcess = (int *) malloc(world_size*sizeof(int)); 

    MPI_Gather(&(self->NbOfVertices),1,MPI_UNSIGNED,NbVertxOnProcess,1,MPI_INT,0,MPI_COMM_WORLD); 

    for(i=0;i<world_size;i++) totalnumberofvertices+=NbVertxOnProcess[i]; 

    * NbOfVertices = totalnumberofvertices; 
    return; 
} 

void Cell_addvertex(void * _self){ 
    struct Cell * self = _self; 
    self->NbOfVertices ++; 
    return; 
} 

void addvertex(void * _self){ 
    struct Cell * self = _self; 
    self->addvertex(self); 
} 

void getnumberofvertices(void * _self, int * NbOfVertices){ 
    struct Cell * self = _self; 
    self->givenumberofvertices(self, NbOfVertices); 
} 



int main(int argc, char *argv[]) { 
    void ** cells; 
    int i,j; 
    const int numberofcells = 100; 
    const int numberofvertices = 100; 
    const float domainlength = 115.4; 
    float grid[numberofcells]; 
    float vertexcoordinates[numberofvertices]; 
    int world_rank; 

    MPI_Init(NULL,NULL); 

    /* create array of Cell pointers */ 
    cells = (void **) calloc(numberofcells,sizeof(void *)); 

    /* create grid */ 
    for(i=0;i<numberofcells;i++){ 
    grid[i]=domainlength/numberofcells*(i+1); 
    } 
    /* generate random vertex coordinates */ 
    MPI_Comm_rank(MPI_COMM_WORLD,&world_rank); 
    srand((unsigned int) world_rank); 
    for(i=0;i<numberofvertices;i++){ 
    vertexcoordinates[i]=((float)rand()/(float)(RAND_MAX)) * domainlength; 
    } 
    /* find the cell the vertex is in */ 
    for(i=0;i<numberofvertices;i++){ 
    for(j=0;j<numberofcells;j++){ 
     float lb, ub; 
     if(j==0) lb=0.0; 
     else lb=grid[j-1]; 
     ub = grid[j]; 
     if(lb<vertexcoordinates[i]&&vertexcoordinates[i]<ub){ 
     if(!cells[j]){ 
      cells[j]=createcell(); 
     } 
     addvertex(cells[j]); 
     } 
    } 
    } 

    for(i=0;i<numberofcells;i++){ 
    if(cells[i]){ 
     int NbVertxInCell; 
     getnumberofvertices(cells[i], &NbVertxInCell); 
     printf("%i vertices in cell number %i \n",NbVertxInCell,i); 
    } 
    } 
    MPI_Finalize(); 
    return 0; 
} 
+1

ことができますいくつかのコードを表示してください、あなたの説明が続くことは非常に困難です。たとえば、「ユーザー定義構造体の配列」は、ユーザー定義構造体の配列になります。 –

+0

十分に、私はそれが今より明確であることを望む。問題は関数内にある* Cell_givenumberofvertices_parallel()* –

答えて

0

私はまだあなたが達成しようとしているかの全体像も、そのような設計のための理論的根拠を得ることはありません。

とにかく、ここにいくつかの考えがあります。

最初に、一括操作を呼び出すときには、コミュニケータのすべてのタスクが呼び出す必要があります。それ以外のタスクはハングすることがあります。

第2に、Cell_givenumberofvertices_parallel()では、MPI_Gather()MPI_Reduce()に置き換えることができます。そして、すべてのランク上のメインループ印刷するので、私はあなたが本当に私はまた、あなたが がそうでなければ、全てのランクがMPI_COMM_WORLDに集団を起動していないし、それがハングアップします、struct CellMPI_Comm * commフィールドを追加したい疑うMPI_Allreduce()

をしたいと考えています。

第3に、私はポインタ機能の必要性を見ません。

セルが1つのタスクにのみある場合、通信はMPI_COMM_SELFで、MPI_Allreduce()を使用すると2つのサブルーチンは必要ありません。

最後に、関数が時間の経過とともにどのように異なる値を返すのか分からないので、頂点の総数は初期化時に計算され、新しいフィールドとして格納されます。

例えば、それは

struct Cell{ 
    unsigned localNbOfVertices; 
    unsigned totalNbOfVertices; 
    MPI_Comm comm; 
}; 

とあなたのメインループに可能性があり、あなたが

for(i=0;i<numberofcells;i++){ 
    unsigned local=0, total; 
    MPI_Comm comm; 
    if(cells[i]) local=cells[i]->localNbOfVertices; 
    MPI_Allreduce(&local, &total, 1, MPI_UNSIGNED, MPI_SUM, MPI_COMM_WORLD); 
    if(cells[i] cells[i]->totalNbOfVertices = total; 
    printf("%i vertices in cell number %i \n",total,i); 
    if(cells[i]) MPI_Comm_split(MPI_COMM_WORLD, 0, world_rank, &cells[i]->comm); else MPI_Comm_split(MPI_COMM_WORLD, MPI_UNDEFINED, world_rank, &comm); 
    } 
+0

はい、私は小さな例を生成するために私の探求のコードを単純化したかもしれません。実際のアプリケーションでは、頂点の位置は時間とともに変化します。また、関数* get/givenumberovertices()*は単なる簡略化された表現です。実際のアプリケーションでは、使用される関数は頂点の数とその位置に依存します。 struct CellにMPI_Comm * commを追加すると、私が探しているもののように聞こえます。しかし、私はその新しいコミュニケータをどこでどのように作成するのかを理解するのに苦労しています。私が* createCell()*でそれを行うと、私はセルが存在する他のプロセッサを知りません。 –

+0

私はコミュニケータの作成で私の答えを更新しました。すべてのセルが初期化されたら、セルコミュニケータを作成する必要があります。 –

関連する問題