Сложность реализации модели переноса нейтронов
Я работаю над моделированием модели переноса нейтронов методом Монте-Карло. Я впервые реализую последовательный алгоритм, который приведен в книге параллельное программирование с openmp и MPI М. Дж. Куинна
Приведенный ниже (последовательный) код является имитацией модели переноса нейтронов. когда я запускаю исполняемый файл в первый раз, он работает в бесконечном цикле. Когда я остановился и побежал снова, результат, который я получаю, равен 0, 0, 0 и не является ожидаемым результатом для всех возможных значений входных параметров, приведенных в вопросе, как указано в руководстве по решению параллельного программирования M. J. Quinn с openmp и MPI (Q.No 10.8). [1]}Мягкая копия для книги приведена ниже: https://docs.google.com/document/d/19aKs6XF3Gt6BRGSGVysZqam3Cb97rgRvTCYP2Nw-C5M/editожидаемый результат: количество отраженных, поглощенных и переданных скоростей составляет: 25.31, 46.13, 28.56. при компиляции кода ошибки не было. пожалуйста помогать мне. вот следующий код, который я написал:
struct neutron
{
long double d ; // Direction of the neutron (measured in radians between 0 and pi)
long double x ; // Position of particle in plate(0<=x<=H)where H is the thickness of the plate
};
typedef struct neutron neutron;
int main()
{
srand(time(NULL));
double C ; // mean distance between neutron/atom interactions is 1/C
double C_s; // Scattering component of C
double C_c; // Absorbing component of C
int r=0, b=0, t=0; //Counts of reflected, absorbed, transmitted neutrons
int i=0;
int n; // Number of Samples
//double d; //Direction of the neutron (measured in radians between 0 and pi)
int a; //a==0 implies false 1 otherwise
double u; // Uniform random number
double L; // Distance neutron travels before collision
neutron nt;
double H;
double p,q,o;
printf("n Enter the value of C_s:n");
scanf("%lf",&C_s);
printf("nEnter the value of C_c:n");
scanf("%lf",&C_c);
//printf("nEnter the value of L:n");
//scanf("%lf",&L);
printf("nEnter the value of H (Thickness of the plate):n");
scanf("%lf",&H);
printf("n Enter the number of samples you want to simulate for....n");
scanf("%d",&n);
for(i=1;i<=n;i++)
{
u=rand()%n;
u=1/u;
nt.d=0;
nt.x=0;
a=1;
while(a)
{
L=-(1/C)*log(u);
nt.x=nt.x+L*cos(nt.d);
if (nt.x<0)
{
// printf("nparticle %d got reflectedn",i);
r++;
a=0;
}
else
{
if(nt.x>=H)
{
// printf("n particle %d got transmittedn",i);
t++;
a=0;
}
else
{
if(u<C_c/C)
{
// printf("n the particle %d got absorbedn",i);
b++;
a=0;
}
else
nt.d=u*(22/7);
}
}
}
}
o=(r/n)*100;
p=(a/n)*100;
q=(t/n)*100;
printf("nthe amount of reflected, absorbed and transmitted rates are: %lf, %lf, %lfn", o, p, q);
return 0;
}
3 ответа:
У вас есть
o=(r/n)*100;
, который выполняет целочисленное деление перед умножением. Поскольку ваш ожидаемый результат равен
25.31
, это будет означать, что результатr / n
должен быть0.2531
, но результатом такого целочисленного деления является0
, который поддерживает0
, который вы получаете.Я предлагаю следующее
Это позволит выполнить правильную арифметику.o = 100.0 * r / n p = 100.0 * a / n; q = 100.0 * t / n;
Кроме того, вы используете неинициализированные переменные.
У вас есть по крайней мере одна неинициализированная переменная, поэтому ваш код UB (undefined behavior).
L=-(1/C)*log(u); ^ uninitialized
Далее, это выглядит странно:
while(a) { .... }
Поэтому
a
всегда будет равно нулю при выходе изwhile
. Но все же вы делаете:p=(a/n)*100;
, что приведет к тому, что
p
всегда будет равно нулю. Это, вероятно, не то, что вы хотите.Однако я вижу эту строку:
Но я не могу найти никакого кода, где вы используетеb++;
b
.Вы действительно хотели сделать это, как вот это?
p=(b/n)*100; // b instead of a
Я нашел ошибки в своем коде, обсудив их с одноклассниками, исправил их и распараллелил код тоже вот такой код:
/** To compile the program: gcc sequential.c -lm To run the program: ./a.out **/ #include<stdio.h> #include<math.h> #include<stdlib.h> #include<time.h> #define TOTAL_NUMBER_OF_NEUTRONS 10000000 //Total number of neutrons #define SCATTERING_COMPONENT 0.7 // Scattering component of C #define ABSORBING_COMPONENT 0.3 // Absorbing component of C #define THICKNESS_OF_THE_PLATE 8 //Thickness of the Plate #define NUMBER_OF_ITERATIONS 1000 int no_of_particles_reflected=0, no_of_particles_absorbed=0, no_of_particles_transmitted=0; double total_amount_absorbed,total_amount_reflected,total_amount_transmitted; double distance_travelled_before_collision; // Distance travelled by neutron before colliding from the plate double C ; // mean distance between neutron/atom interactions is 1/C int flag= 1; int counter= 0; struct neutron { double d; // Direction of the neutron (measured in radians between 0 and pi) double x; // Position of particle in plate(0<=x<=H),H is the thickness of the plate }; struct neutron nt; void neutron_model() { double random_number_generator; // Uniform random number generator total_amount_absorbed=0,total_amount_reflected=0,total_amount_transmitted=0; for(int i=1;i<=TOTAL_NUMBER_OF_NEUTRONS;i++) { random_number_generator=rand()%TOTAL_NUMBER_OF_NEUTRONS; random_number_generator=1/random_number_generator; nt.d=0; nt.x=0; flag=1; while(flag) { distance_travelled_before_collision=-(1/C)*log(random_number_generator); nt.x=distance_travelled_before_collision*cos(nt.d); if (nt.x<0) { no_of_particles_reflected++; flag=0; } else if(nt.x>=THICKNESS_OF_THE_PLATE) { no_of_particles_transmitted++; flag=0; } else { if(random_number_generator<(ABSORBING_COMPONENT/C)) { no_of_particles_absorbed++; flag=0; } else { nt.d=random_number_generator*(22.0/7.0); counter++; if(counter==NUMBER_OF_ITERATIONS) { no_of_particles_absorbed++; flag=0; counter=0; } } } } } } int main(int argc, char *argv[]) { C=SCATTERING_COMPONENT + ABSORBING_COMPONENT; clock_t start, end; double diff_t; diff_t = 0.0; //start the clock start= clock(); neutron_model(); //stop the clock end = clock(); diff_t = ((double) (end - start)) / CLOCKS_PER_SEC; total_amount_reflected=((double)no_of_particles_reflected/(double)TOTAL_NUMBER_OF_NEUTRONS)*100.0; total_amount_absorbed=((double)no_of_particles_absorbed/(double)TOTAL_NUMBER_OF_NEUTRONS)*100.0; total_amount_transmitted=((double)no_of_particles_transmitted/(double)TOTAL_NUMBER_OF_NEUTRONS)*100.0; printf("\nDATA VALUE ASSUMED:-\n"); printf("***********************************************************************\n"); printf("TOTAL_NUMBER_OF_NEUTRONS: %d\n",TOTAL_NUMBER_OF_NEUTRONS); printf("SCATTERING_COMPONENT: %f\n",SCATTERING_COMPONENT); printf("ABSORBING_COMPONENT: %f\n",ABSORBING_COMPONENT); printf("THICKNESS_OF_THE_PLATE: %d\n",THICKNESS_OF_THE_PLATE); printf("***********************************************************************\n\n"); printf("Total particles reflected,absorbed and transmitted respectively are: %d, %d, %d \n",no_of_particles_reflected,no_of_particles_absorbed,no_of_particles_transmitted); printf("Percentage of particles reflected,absorbed and transmitted respectively are: %lf, %lf, %lf\n", total_amount_reflected, total_amount_absorbed, total_amount_transmitted); printf("Total time taken in sec %10.6lf\n",diff_t); return 0; }
Версия MPI:
/** To compile the program: mpicc -o neutron_transport with_MPI.c -lm To run the program: mpirun -np <specify no. of processes> neutron_transport **/ #include<stdio.h> #include<math.h> #include<stdlib.h> #include<time.h> #include<mpi.h> #define TOTAL_NUMBER_OF_NEUTRONS 1000 //Total number of neutrons #define SCATTERING_COMPONENT 0.7 // Scattering component of C #define ABSORBING_COMPONENT 0.3 // Absorbing component of C #define THICKNESS_OF_THE_PLATE 4 //Thickness of the Plate #define NUMBER_OF_ITERATIONS 1000 #define BLOCK_LOW(id,p,n) ((id)*(n)/(p)) #define BLOCK_HIGH(id,p,n) (BLOCK_LOW((id)+1,p,n)-1) #define BLOCK_SIZE(id,p,n) (BLOCK_LOW((id)+1,p,n)-BLOCK_LOW(id,p,n)) //Block Size for each process struct neutron { long double d; // Direction of the neutron (measured in radians between 0 and pi) long double x; // Position of particle in plate(0<=x<=H) where H is the thickness of the plate }; int main(int argc, char *argv[]) { int process_id; //Process Identifier int number_of_processes; //Number of Processes in the communicator MPI_Init(&argc,&argv); //Starting of MPI program MPI_Comm_rank(MPI_COMM_WORLD,&process_id); //Determine the process ID number in the communicator MPI_Comm_size(MPI_COMM_WORLD,&number_of_processes); //Determine the number of processes in the communicator int i=0; //Loop iterator int counter=0; int buffer_share_for_each_process=0; double C ; // mean distance between neutron/atom interactions is 1/C C=SCATTERING_COMPONENT + ABSORBING_COMPONENT; int flag= 1; double random_number_generator; // Uniform random number double distance_travelled_before_collision; // Distance travelled by neutron before collision struct neutron nt; double total_amount_absorbed,total_amount_reflected,total_amount_transmitted; int count_of_reflected_absorbed_transmitted[3]; count_of_reflected_absorbed_transmitted[0]=0; count_of_reflected_absorbed_transmitted[1]=0; count_of_reflected_absorbed_transmitted[2]=0; int global_count_of_reflected_absorbed_transmitted[3]; buffer_share_for_each_process= BLOCK_SIZE(process_id,number_of_processes,TOTAL_NUMBER_OF_NEUTRONS); double elapsed_time1; //Timer variables elapsed_time1= -MPI_Wtime(); if(number_of_processes > TOTAL_NUMBER_OF_NEUTRONS) { if(!process_id) printf("Too many processes. Kindly provide lesser number of processes.\n"); MPI_Finalize(); exit(1); } for(int i=1;i<=buffer_share_for_each_process;i++) { random_number_generator=rand()%TOTAL_NUMBER_OF_NEUTRONS; random_number_generator=1/random_number_generator; nt.d=0; nt.x=0; flag=1; distance_travelled_before_collision=-(1/C)*log(random_number_generator); nt.x=distance_travelled_before_collision*cos(nt.d); while(flag) { distance_travelled_before_collision=-(1/C)*log(random_number_generator); nt.x=distance_travelled_before_collision*cos(nt.d); if (nt.x<0) { count_of_reflected_absorbed_transmitted[0]++; flag=0; } else if(nt.x>=THICKNESS_OF_THE_PLATE) { count_of_reflected_absorbed_transmitted[2]++; flag=0; } else { if(random_number_generator<(ABSORBING_COMPONENT/C)) { count_of_reflected_absorbed_transmitted[1]++; flag=0; } else { nt.d=random_number_generator*(22.0/7.0); counter++; if(counter==NUMBER_OF_ITERATIONS) { count_of_reflected_absorbed_transmitted[1]++; flag=0; counter=0; } } } } } for(int i= 0 ; i < 3 ; i ++) MPI_Reduce(&count_of_reflected_absorbed_transmitted[i], &global_count_of_reflected_absorbed_transmitted[i], 1, MPI_INT,MPI_SUM,0, MPI_COMM_WORLD) ; elapsed_time1+= MPI_Wtime(); MPI_Barrier(MPI_COMM_WORLD); if(!process_id) { total_amount_reflected=((double)global_count_of_reflected_absorbed_transmitted[0]/(double)TOTAL_NUMBER_OF_NEUTRONS)*100.0; total_amount_absorbed=((double)global_count_of_reflected_absorbed_transmitted[1]/(double)TOTAL_NUMBER_OF_NEUTRONS)*100.0; total_amount_transmitted=((double)global_count_of_reflected_absorbed_transmitted[2]/(double)TOTAL_NUMBER_OF_NEUTRONS)*100.0; printf("\nDATA VALUE ASSUMED:-\n"); printf("*****************************************************************************************\n"); printf("TOTAL_NUMBER_OF_NEUTRONS: %d\n",TOTAL_NUMBER_OF_NEUTRONS); printf("SCATTERING_COMPONENT: %f\n",SCATTERING_COMPONENT); printf("ABSORBING_COMPONENT: %f\n",ABSORBING_COMPONENT); printf("THICKNESS_OF_THE_PLATE: %d\n",THICKNESS_OF_THE_PLATE); printf("TOTAL NUMBER OF PROCESSES: %d\n",number_of_processes); printf("*****************************************************************************************\n\n"); printf("Total particles reflected,absorbed and transmitted respectively are: %d, %d, %d \n",global_count_of_reflected_absorbed_transmitted[0],global_count_of_reflected_absorbed_transmitted[1],global_count_of_reflected_absorbed_transmitted[2]); printf("Percentage of particles reflected,absorbed and transmitted respectively are: %lf, %lf, %lf\n", total_amount_reflected, total_amount_absorbed, total_amount_transmitted); printf("Total time taken in sec %10.6f\n",elapsed_time1); } MPI_Finalize(); return 0; }
OpenMP версия:
/** To compile the program: gcc -fopenmp with_open_mp.c -lm To run the program: ./a.out **/ #include<stdio.h> #include<math.h> #include<stdlib.h> #include<time.h> #include<omp.h> #define TOTAL_NUMBER_OF_NEUTRONS 10000000 //Total number of neutrons #define SCATTERING_COMPONENT 0.7 // Scattering component of C #define ABSORBING_COMPONENT 0.3 // Absorbing component of C #define THICKNESS_OF_THE_PLATE 5 //Thickness of the Plate #define NUMBER_OF_ITERATIONS 1000 #define TOTAL_NUMBER_OF_THREADS 500 struct neutron { double d; // Direction of the neutron (measured in radians between 0 and pi) double x; // Position of particle in plate(0<=x<=H) where H is the thickness of the plate }; int main(int argc, char *argv[]) { double C ; // mean distance between neutron/atom interactions is 1/C C=SCATTERING_COMPONENT + ABSORBING_COMPONENT; int no_of_particles_reflected=0, no_of_particles_absorbed=0, no_of_particles_transmitted=0; int flag= 1; double random_number_generator; // Uniform random number double distance_travelled_before_collision; // Distance travelled by neutron before collision struct neutron nt; double total_amount_absorbed,total_amount_reflected,total_amount_transmitted; int counter= 0; srand(time(NULL)); clock_t start, end; double diff_t; diff_t = 0.0; //start the clock start= clock(); //int t=omp_get_num_procs(); omp_set_num_threads(TOTAL_NUMBER_OF_THREADS); #pragma omp parallel for reduction(+:no_of_particles_reflected,no_of_particles_absorbed,no_of_particles_transmitted) for(int i=1;i<=TOTAL_NUMBER_OF_NEUTRONS;i++) { random_number_generator=rand()%TOTAL_NUMBER_OF_NEUTRONS; random_number_generator=1/random_number_generator; nt.d=0; nt.x=0; flag=1; while(flag) { distance_travelled_before_collision=-(1/C)*log(random_number_generator); nt.x=distance_travelled_before_collision*cos(nt.d); if (nt.x<0) { no_of_particles_reflected++; flag=0; } else if(nt.x>=THICKNESS_OF_THE_PLATE) { no_of_particles_transmitted++; flag=0; } else { if(random_number_generator<(ABSORBING_COMPONENT/C)) { no_of_particles_absorbed++; flag=0; } else { nt.d=random_number_generator*(22.0/7.0); counter++; if(counter==NUMBER_OF_ITERATIONS) { no_of_particles_absorbed++; flag=0; counter=0; } } } } } //stop the clock end = clock(); diff_t = ((double) (end - start)) / CLOCKS_PER_SEC; printf("\nDATA VALUE ASSUMED:-\n"); printf("*****************************************************************************************\n"); printf("TOTAL_NUMBER_OF_NEUTRONS: %d\n",TOTAL_NUMBER_OF_NEUTRONS); printf("SCATTERING_COMPONENT: %f\n",SCATTERING_COMPONENT); printf("ABSORBING_COMPONENT: %f\n",ABSORBING_COMPONENT); printf("THICKNESS_OF_THE_PLATE: %d\n",THICKNESS_OF_THE_PLATE); printf("TOTAL NUMBER OF THREADS: %d\n",TOTAL_NUMBER_OF_THREADS); printf("*****************************************************************************************\n\n"); total_amount_reflected=((double)no_of_particles_reflected/(double)TOTAL_NUMBER_OF_NEUTRONS)*100.0; total_amount_absorbed=((double)no_of_particles_absorbed/(double)TOTAL_NUMBER_OF_NEUTRONS)*100.0; total_amount_transmitted=((double)no_of_particles_transmitted/(double)TOTAL_NUMBER_OF_NEUTRONS)*100.0; printf("Total particles reflected,absorbed and transmitted respectively are: %d, %d, %d \n",no_of_particles_reflected,no_of_particles_absorbed,no_of_particles_transmitted); printf("The amount reflected,absorbed and transmitted respectively are: %lf, %lf, %lf\n", total_amount_reflected, total_amount_absorbed, total_amount_transmitted); printf("Total time taken in sec %10.6lf\n",diff_t); return 0; }
Гибридная версия MPI и OpenMP:
/** To compile the program: mpicc -fopenmp mpi_openmp.c -o hybrid -lm To run the program: mpirun -np <specify number of processes> ./hybrid **/ #include<stdio.h> #include<math.h> #include<stdlib.h> #include<time.h> #include<omp.h> #include<mpi.h> #define TOTAL_NUMBER_OF_NEUTRONS 10000000 //Total number of neutrons #define SCATTERING_COMPONENT 0.7 // Scattering component of C #define ABSORBING_COMPONENT 0.3 // Absorbing component of C #define THICKNESS_OF_THE_PLATE 3 //Thickness of the Plate #define BLOCK_LOW(id,p,n) ((id)*(n)/(p)) #define BLOCK_HIGH(id,p,n) (BLOCK_LOW((id)+1,p,n)-1) #define BLOCK_SIZE(id,p,n) (BLOCK_LOW((id)+1,p,n)-BLOCK_LOW(id,p,n)) //Block Size for each process #define NUMBER_OF_ITERATIONS 1000 #define TOTAL_NUMBER_OF_THREADS 500 //Total number of threads struct neutron { double d; // Direction of the neutron (measured in radians between 0 and pi) double x; // Position of particle in plate(0<=x<=H) where H is the thickness of the plate }; int main(int argc, char *argv[]) { struct neutron nt; int process_id; //Process Identifier int number_of_processes; //Number of Processes in the communicator MPI_Init(&argc,&argv); //Starting of MPI program MPI_Comm_rank(MPI_COMM_WORLD,&process_id); //Determine the process ID number in the communicator MPI_Comm_size(MPI_COMM_WORLD,&number_of_processes); //Determine the number of processes in the communicator double C ; // mean distance between neutron/atom interactions is 1/C C=SCATTERING_COMPONENT + ABSORBING_COMPONENT; int flag= 1; double random_number_generator; // Uniform random number double distance_travelled_before_collision; // Distance travelled by neutron before collision int no_of_particles_reflected=0, no_of_particles_absorbed=0, no_of_particles_transmitted=0; double total_amount_absorbed,total_amount_reflected,total_amount_transmitted; int counter= 0; int buffer_share_for_each_process=0; srand(time(NULL)); int count_of_reflected_absorbed_transmitted[3]; count_of_reflected_absorbed_transmitted[0]=0; count_of_reflected_absorbed_transmitted[1]=0; count_of_reflected_absorbed_transmitted[2]=0; int global_count_of_reflected_absorbed_transmitted[3]; buffer_share_for_each_process= BLOCK_SIZE(process_id,number_of_processes,TOTAL_NUMBER_OF_NEUTRONS); double elapsed_time1; //Timer variables elapsed_time1= -MPI_Wtime(); //int t=omp_get_num_procs(); omp_set_num_threads(TOTAL_NUMBER_OF_THREADS); if((number_of_processes) > TOTAL_NUMBER_OF_NEUTRONS) { if(!process_id) printf("Too many processes. Kindly provide lesser number of processes.\n"); MPI_Finalize(); exit(1); } #pragma omp parallel for for(int i=1;i<=buffer_share_for_each_process;i++) { //printf("Buffer_Share= %d by process %d (thread %d out of %d)\n",buffer_share_for_each_process,process_id,omp_get_thread_num(),omp_get_num_threads()); random_number_generator=rand()%TOTAL_NUMBER_OF_NEUTRONS; random_number_generator=1/random_number_generator; nt.d=0; nt.x=0; flag=1; while(flag) { distance_travelled_before_collision=-(1/C)*log(random_number_generator); nt.x=distance_travelled_before_collision*cos(nt.d); if (nt.x<0) { count_of_reflected_absorbed_transmitted[0]++; flag=0; } else if(nt.x>=THICKNESS_OF_THE_PLATE) { count_of_reflected_absorbed_transmitted[2]++; flag=0; } else { if(random_number_generator<(ABSORBING_COMPONENT/C)) { count_of_reflected_absorbed_transmitted[1]++; flag=0; } else { nt.d=random_number_generator*(22.0/7.0); counter++; if(counter==NUMBER_OF_ITERATIONS) { count_of_reflected_absorbed_transmitted[1]++; flag=0; counter=0; } } } } } for(int i= 0 ; i < 3 ; i ++) MPI_Reduce(&count_of_reflected_absorbed_transmitted[i], &global_count_of_reflected_absorbed_transmitted[i], 1, MPI_INT,MPI_SUM,0, MPI_COMM_WORLD) ; elapsed_time1+= MPI_Wtime(); MPI_Barrier(MPI_COMM_WORLD); if(!process_id) { total_amount_reflected=((double)global_count_of_reflected_absorbed_transmitted[0]/(double)TOTAL_NUMBER_OF_NEUTRONS)*100.0; total_amount_absorbed=((double)global_count_of_reflected_absorbed_transmitted[1]/(double)TOTAL_NUMBER_OF_NEUTRONS)*100.0; total_amount_transmitted=((double)global_count_of_reflected_absorbed_transmitted[2]/(double)TOTAL_NUMBER_OF_NEUTRONS)*100.0; printf("\nDATA VALUE ASSUMED:-\n"); printf("*****************************************************************************************\n"); printf("TOTAL_NUMBER_OF_NEUTRONS: %d\n",TOTAL_NUMBER_OF_NEUTRONS); printf("SCATTERING_COMPONENT: %f\n",SCATTERING_COMPONENT); printf("ABSORBING_COMPONENT: %f\n",ABSORBING_COMPONENT); printf("THICKNESS_OF_THE_PLATE: %d\n",THICKNESS_OF_THE_PLATE); printf("TOTAL NUMBER OF PROCESSES: %d\n",number_of_processes); printf("TOTAL NUMBER OF THREADS: %d\n",TOTAL_NUMBER_OF_THREADS); printf("*****************************************************************************************\n\n"); printf("Total particles reflected,absorbed and transmitted respectively are: %d, %d, %d \n",global_count_of_reflected_absorbed_transmitted[0],global_count_of_reflected_absorbed_transmitted[1],global_count_of_reflected_absorbed_transmitted[2]); printf("Percentage of particles reflected,absorbed and transmitted respectively are: %lf, %lf, %lf\n", total_amount_reflected, total_amount_absorbed, total_amount_transmitted); printf("Total time taken in sec %10.6f\n",elapsed_time1); } MPI_Finalize(); return 0; }