我正在使用蒙特卡罗方法模拟中子输运模型。我首先实现了本书中提供的顺序算法使用openmp进行并行编程和MPI由M. J. Quinn
给出的下面(顺序)代码是中子输运模型的模拟。当我第一次运行可执行文件时,它在无限循环中运行。当我停止并再次运行时,输出的输出为0,0,0并且不是输入参数的所有可能值的预期输出,在MJQuinn并行编程的解决方案手册中提到的问题中给出openmp和MPI(Q.No 10.8)。
本书的软拷贝如下: 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 reflected\n",i);
r++;
a=0;
}
else
{
if(nt.x>=H)
{
// printf("\n particle %d got transmitted\n",i);
t++;
a=0;
}
else
{
if(u<C_c/C)
{
// printf("\n the particle %d got absorbed\n",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, %lf\n", o, p, q);
return 0;
}
答案 0 :(得分:2)
您至少有一个未初始化的变量,因此您的代码是UB(未定义的行为)。
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
答案 1 :(得分:2)
你有
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;
这将执行正确的算术。
此外,您正在使用未初始化的变量。
答案 2 :(得分:0)
我通过与同学讨论并纠正错误并在代码中并行化了我的代码中的错误,这里是以下代码:
/**
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;
}