im Licht der KOMMENTAR EDITEDFehler bei Parallelisierung MPI_Allgather
I MPI lerne und ich einige Übungen mache einige Aspekte der es zu verstehen. Ich habe einen Code geschrieben, der ein einfaches Monte-Carlo ausführen soll.
Es gibt zwei Hauptschleifen, die durchgeführt werden müssen: eine über die Zeitschritte T
und eine kleinere über die Anzahl der Moleküle N
. Nachdem ich versucht habe, jedes Molekül zu bewegen, geht das Programm zum nächsten Zeitschritt.
Ich habe versucht, es zu parallelisieren, indem Sie die Operationen auf den Molekülen auf den verschiedenen Prozessoren teilen. Leider gibt der Code, der für 1 Prozessor funktioniert, die falschen Ergebnisse für aus, wenn p> 1 ist. Das Problem liegt wahrscheinlich in der folgenden Funktion und genauer ist durch einen Anruf an MPI_Allgather(local_r,n,MPI_DOUBLE,r,n,MPI_DOUBLE,MPI_COMM_WORLD);
Ich verstehe völlig nicht warum. Was mache ich falsch? (Neben einer primitiven Parallelisierungsstrategie)
Meine Logik war, dass ich für jeden Zeitschritt die Bewegungen auf den Molekülen auf den verschiedenen Prozessoren berechnen konnte. Leider, während ich mit den lokalen Vektoren local_r
auf den verschiedenen Prozessoren arbeite, um die Energiedifferenz local_DE
zu berechnen, brauche ich den globalen Vektor r
, da die Energie des i-ten Moleküls von allen anderen abhängt. Daher dachte ich, MPI_Allgather
zu nennen, da ich sowohl den globalen Vektor als auch die lokalen Vektoren aktualisieren muss.
void Step(double (*H)(double,double),double* local_r,double* r,double *E_,int n,int my_rank){
int i;
double* local_rt = calloc(n,sizeof(double));
double local_DE;
for(i=0;i<n;i++){
local_rt[i] = local_r[i] + delta*((double)lrand48()/RAND_MAX-0.5);
local_rt[i] = periodic(local_rt[i]);
local_DE = E_single(H,local_rt,r,i,n,my_rank) - E_single(H,local_r,r,i,n,my_rank);
if (local_DE <= 0.0 || exp(-local_DE) > (double) lrand48()/RAND_MAX ) {
(*E_) += local_DE;
local_r[i] = local_rt[i];
}
MPI_Allgather(local_r,n,MPI_DOUBLE,r,n,MPI_DOUBLE,MPI_COMM_WORLD);
}
return ;
}
Hier ist es die komplette „arbeiten“ Code:
#define _XOPEN_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <mpi.h>
#define N 100
#define L 5.0
#define T_ 5000
#define delta 2.0
void Step(double (*)(double,double),double*,double*,double*,int,int);
double H(double ,double);
double E(double (*)(double,double),double* ,double*,int ,int);
double E_single(double (*)(double,double),double* ,double*,int ,int ,int);
double * pos_ini(void);
double periodic(double);
double dist(double , double);
double sign(double);
int main(int argc,char** argv){
if (argc < 2) {
printf("./program <outfile>\n");
exit(-1);
}
srand48(0);
int my_rank;
int p;
FILE* outfile = fopen(argv[1],"w");
MPI_Init(&argc,&argv);
MPI_Comm_rank(MPI_COMM_WORLD,&my_rank);
MPI_Comm_size(MPI_COMM_WORLD,&p);
double total_E,E_;
int n;
n = N/p;
int t;
double * r = calloc(N,sizeof(double)),*local_r = calloc(n,sizeof(double));
for(t = 0;t<=T_;t++){
if(t ==0){
r = pos_ini();
MPI_Scatter(r,n,MPI_DOUBLE, local_r,n,MPI_DOUBLE, 0, MPI_COMM_WORLD);
E_ = E(H,local_r,r,n,my_rank);
}else{
Step(H,local_r,r,&E_,n,my_rank);
}
total_E = 0;
MPI_Allreduce(&E_,&total_E,1,MPI_DOUBLE,MPI_SUM,MPI_COMM_WORLD);
if(my_rank == 0){
fprintf(outfile,"%d\t%lf\n",t,total_E/N);
}
}
MPI_Finalize();
return 0;
}
double sign(double a){
if(a < 0){
return -1.0 ;
}else{
return 1.0 ;
}
}
double periodic(double a){
if(sqrt(a*a) > L/2.0){
a = a - sign(a)*L;
}
return a;
}
double dist(double a, double b){
double d = a-b;
d = periodic(d);
return sqrt(d*d);
}
double * pos_ini(void){
double * r = calloc(N,sizeof(double));
int i;
for(i = 0;i<N;i++){
r[i] = ((double) lrand48()/RAND_MAX)*L - L/2.0;
}
return r;
}
double H(double a,double b){
if(dist(a,b)<2.0){
return exp(-dist(a,b)*dist(a,b))/dist(a,b);
}else{
return 0.0;
}
}
double E(double (*H)(double,double),double* local_r,double*r,int n,int my_rank){
double local_V = 0;
int i;
for(i = 0;i<n;i++){
local_V += E_single(H,local_r,r,i,n,my_rank);
}
local_V *= 0.5;
return local_V;
}
double E_single(double (*H)(double,double),double* local_r,double*r,int i,int n,int my_rank){
double local_V = 0;
int j;
for(j = 0;j<N;j++){
if((i + n*my_rank) != j){
local_V+=H(local_r[i],r[j]);
}
}
return local_V;
}
void Step(double (*H)(double,double),double* local_r,double* r,double *E_,int n,int my_rank){
int i;
double* local_rt = calloc(n,sizeof(double));
double local_DE;
for(i=0;i<n;i++){
local_rt[i] = local_r[i] + delta*((double)lrand48()/RAND_MAX-0.5);
local_rt[i] = periodic(local_rt[i]);
local_DE = E_single(H,local_rt,r,i,n,my_rank) - E_single(H,local_r,r,i,n,my_rank);
if (local_DE <= 0.0 || exp(-local_DE) > (double) lrand48()/RAND_MAX ) {
(*E_) += local_DE;
local_r[i] = local_rt[i];
}
MPI_Allgather(local_r,n,MPI_DOUBLE,r,n,MPI_DOUBLE,MPI_COMM_WORLD);
}
return ;
}
Ein bedingter 'MPI_Allgather'? Würde das nicht Ihr Programm blockieren, falls es nicht in allen Prozessen aufgerufen wird? –
Sie haben Recht, es aus dem zu entfernen, wenn der Block entfernt wird, leider funktioniert das Programm immer noch nicht – Fra
Also, was ist das neue Problem? –