2016-11-14 2 views
2

Ich lerne gerade die Ringtopologie MPI in C++. Ich schrieb ein C++ - Skript, um die 10-dimensionale Monte-Carlo-Integration zu berechnen und ihren mittleren und lokalen Maximalwert zu berechnen. Mein Ziel ist es, den lokalen Maximalwert jedes einzelnen Prozessors durch den "Ring" zu übergeben.MPI C++ - Ringtopologie sendet und empfängt verschiedene Werte, während nur der gleiche Wert übergeben wird?

Jetzt habe ich noch nicht herausgefunden, wie die Max-Werte von verschiedenen Prozessoren in Runtime in einem Array gespeichert werden, so kompilierte und führte ich den Code einmal, und manuell ein Array mit den Werten.

Als nächstes möchte ich jeden der Array-Werte durch den Ring übergeben und schließlich die globalen Maxima berechnen. Jetzt experimentiere ich nur mit der Übergabe des ersten Array-Wertes, und ich sehe, dass die Prozessoren den gleichen Wert senden, aber andere erhalten. Ich weiß ehrlich gesagt nicht, ob C++ die MPI-Bibliothek anders verwendet und ich folgte einem Online-Tutorial für MPI mit C und benutzte irgendwie die gleiche Struktur wie C in meinem C++ - Code.

Ich teile den Code hier.

#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; 
} 

ich mit kompiliert:

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

Die Ausgabe sieht wie folgt aus mit unterschiedlichen mittleren amd max natürlich, aber ich mache mir Sorgen um Sende- und recvd Werte für jetzt:

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 denke, ich bin mit der MPI-Nutzung in C und C++, ich würde mich über jeden Vorschlag freuen, auch habe ich keine gute C++ MPI-Tutorials über das Internet, so ein gutes Beispiel für meinen Code oder Tutorial Link wird sehr hilfreich sein. danke

Antwort

1

Das dritte Argument von MPI_Recv und MPI_Send ist der Datentyp. Jetzt senden Sie eine double, aber Sie legen den Datentyp auf MPI_INT fest. In den meisten Systemen int sind 4 Bytes und double sind 8 Bytes, daher ist die Hälfte der Bytes in der rec_junk nicht initialisiert.

Um es zu beheben nur MPI_INT in allen Anrufen von MPI_Recv und MPI_Send zu MPI_DOUBLE ändern.

Verwandte Themen