2016-11-14 8 views
2

私はC++でリングトポロジMPIを学んでいます。私は、10次元モンテカルロ積分を計算し、平均値と局所最大値を計算するためのC++スクリプトを書いた。私の目標は、各proessorsのローカル最大値を "リング"に渡すことです。MPI C++リングトポロジは同じ値を渡しながら異なる値を送受信しますか?

実行時に異なるプロセッサーから生成された最大値を配列に格納する方法をまだ分かりませんでしたので、コードを一度コンパイルして実行し、その値で配列を手動で作成しました。

次のように、配列値のそれぞれをリングに渡して、最終的にグローバル最大値を計算します。 今、私は最初の配列の値を渡すことで実験しています。プロセッサは同じ値を送信しますが、異なる値を受け取ります。私は正直なところ、C++がMPIライブラリを使い方が違っているかどうか分からず、CとMPIのオンラインチュートリアルに従いました。Cと同じ構造をC++コードで使用していました。

ここでコードを共有しています。

#include <iostream> 
#include <fstream> 
#include <iomanip> 
#include <cmath> 
#include <cstdlib> 
#include <ctime> 
#include <mpi.h> 
using namespace std; 


//define multivariate function F(x1, x2, ...xk)    

double f(double x[], int n) 
{ 
    double y; 
    int j; 
    y = 0.0; 

    for (j = 0; j < n-1; j = j+1) 
     { 
     y = y + exp(-pow((1-x[j]),2)-100*(pow((x[j+1] - pow(x[j],2)),2))); 

     }  

    y = y; 
    return y; 
} 

//define function for Monte Carlo Multidimensional integration 

double int_mcnd(double(*fn)(double[],int),double a[], double b[], int n, int m) 

{ 
    double r, x[n], v; 
    int i, j; 
    r = 0.0; 
    v = 1.0; 
    // initial seed value (use system time) 
    //srand(time(NULL)); 


    // step 1: calculate the common factor V 
    for (j = 0; j < n; j = j+1) 
     { 
     v = v*(b[j]-a[j]); 
     } 

    // step 2: integration 
    for (i = 1; i <= m; i=i+1) 
    { 
     // calculate random x[] points 
     for (j = 0; j < n; j = j+1) 
     { 
      x[j] = a[j] + (rand()) /((RAND_MAX/(b[j]-a[j]))); 
     }   
     r = r + fn(x,n); 
    } 
    r = r*v/m; 

    return r; 
} 




double f(double[], int); 
double int_mcnd(double(*)(double[],int), double[], double[], int, int); 



int main(int argc, char **argv) 
{  

    int rank, size; 

    MPI_Init (&argc, &argv);  // initializes MPI 
    MPI_Comm_rank (MPI_COMM_WORLD, &rank); // get current MPI-process ID. O, 1, ... 
    MPI_Comm_size (MPI_COMM_WORLD, &size); // get the total number of processes 


    /* define how many integrals */ 
    const int n = 10;  

    double b[n] = {5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0,5.0};      
    double a[n] = {-5.0, -5.0, -5.0, -5.0, -5.0, -5.0, -5.0, -5.0, -5.0,-5.0}; 

    double result, mean; 
    int m; 

    const unsigned int N = 5; 
    double max = -1; 


    cout.precision(6); 
    cout.setf(ios::fixed | ios::showpoint); 


    srand(time(NULL) * rank); // each MPI process gets a unique seed 

    m = 4;    // initial number of intervals 

    // convert command-line input to N = number of points 
    //N = atoi(argv[1]); 


    for (unsigned int i=0; i <=N; i++) 
    { 
     result = int_mcnd(f, a, b, n, m); 
     mean = result/(pow(10,10)); 

     if(mean > max) 
     { 
     max = mean; 
     } 
     //cout << setw(10) << m << setw(10) << max << setw(10) << mean << setw(10) << rank << setw(10) << size <<endl; 
     m = m*4; 
    } 

    //cout << setw(30) << m << setw(30) << result << setw(30) << mean <<endl; 
    printf("Process %d of %d mean = %1.5e\n and local max = %1.5e\n", rank, size, mean, max); 


    double max_store[4] = {4.43095e-02, 5.76586e-02, 3.15962e-02, 4.23079e-02}; 

    double send_junk = max_store[0]; 
    double rec_junk; 
    MPI_Status status; 


    // This next if-statment implemeents the ring topology 
    // the last process ID is size-1, so the ring topology is: 0->1, 1->2, ... size-1->0 
    // rank 0 starts the chain of events by passing to rank 1 
    if(rank==0) { 
    // only the process with rank ID = 0 will be in this block of code. 
    MPI_Send(&send_junk, 1, MPI_INT, 1, 0, MPI_COMM_WORLD); // send data to process 1 
    MPI_Recv(&rec_junk, 1, MPI_INT, size-1, 0, MPI_COMM_WORLD, &status); // receive data from process size-1 
    } 
    else if(rank == size-1) { 
    MPI_Recv(&rec_junk, 1, MPI_INT, rank-1, 0, MPI_COMM_WORLD, &status); // recieve data from process rank-1 (it "left" neighbor") 
    MPI_Send(&send_junk, 1, MPI_INT, 0, 0, MPI_COMM_WORLD); // send data to its "right neighbor", rank 0 
    } 
    else { 
    MPI_Recv(&rec_junk, 1, MPI_INT, rank-1, 0, MPI_COMM_WORLD, &status); // recieve data from process rank-1 (it "left" neighbor") 
    MPI_Send(&send_junk, 1, MPI_INT, rank+1, 0, MPI_COMM_WORLD); // send data to its "right neighbor" (rank+1) 
    } 
    printf("Process %d send %1.5e\n and recieved %1.5e\n", rank, send_junk, rec_junk); 


    MPI_Finalize(); // programs should always perform a "graceful" shutdown 
    return 0; 
} 

私がしてコンパイル:

mpiCC -std=c++11 -o hg test_code.cpp 
mpirun -np 4 ./hg 

出力はもちろんの異なる平均AMD、最大で次のようになりますが、私は今の送信とRECVD値が心配です:

Process 2 of 4 mean = 2.81817e-02 
and local max = 5.61707e-02 
Process 0 of 4 mean = 2.59220e-02 
and local max = 4.43095e-02 
Process 3 of 4 mean = 2.21734e-02 
and local max = 4.30539e-02 
Process 1 of 4 mean = 2.87403e-02 
and local max = 6.58530e-02 
Process 1 send 4.43095e-02 
and recieved 2.22181e-315 
Process 2 send 4.43095e-02 
and recieved 6.90945e-310 
Process 3 send 4.43095e-02 
and recieved 6.93704e-310 
Process 0 send 4.43095e-02 
and recieved 6.89842e-310 

I私はCとC++でのMPIの使用法を台無しにしていると思います。何か提案がありがたく思っています。また、インターネット上で良いC++ MPIチュートリアルが見られなかったので、コードやチュートリアルリンク非常に役立つでしょう。ありがとう

答えて

1

MPI_RecvMPI_Sendの3番目の引数がデータ型です。今あなたはdoubleを送信していますが、データタイプはMPI_INTに設定しています。ほとんどのシステムでは、intは4バイトであり、doubleは8バイトであるため、rec_junkのバイトの半分は初期化されません。

MPI_RecvMPI_SendのすべてのコールでMPI_INTMPI_DOUBLEに変更するだけです。

関連する問題