C++ 优化c++;长动态阵列的蒙特卡罗模拟

C++ 优化c++;长动态阵列的蒙特卡罗模拟,c++,optimization,simulation,dynamic-arrays,C++,Optimization,Simulation,Dynamic Arrays,这是我在这里的第一篇文章,我没有那么丰富的经验,所以请原谅我的无知 我正在为我的博士学位在C++中构建一个蒙特卡洛模拟,我需要帮助优化它的计算时间和性能。我有一个三维立方体,在每个坐标系中作为模拟体重复,在每个立方体内部,磁性粒子以簇的形式生成。然后,在中央立方体中产生一个质子环并移动,在每一步计算它们感觉到的所有粒子(除其他外)的总磁场 此时,我定义了主函数中的所有内容,因为我需要计算粒子的位置(我计算粒子放置期间以及质子移动期间粒子之间的距离),所以我将它们存储在动态阵列中。我还没有使用任何

这是我在这里的第一篇文章,我没有那么丰富的经验,所以请原谅我的无知

我正在为我的博士学位在C++中构建一个蒙特卡洛模拟,我需要帮助优化它的计算时间和性能。我有一个三维立方体,在每个坐标系中作为模拟体重复,在每个立方体内部,磁性粒子以簇的形式生成。然后,在中央立方体中产生一个质子环并移动,在每一步计算它们感觉到的所有粒子(除其他外)的总磁场

此时,我定义了主函数中的所有内容,因为我需要计算粒子的位置(我计算粒子放置期间以及质子移动期间粒子之间的距离),所以我将它们存储在动态阵列中。我还没有使用任何类或函数。这使得我的模拟速度非常慢,因为我最终不得不使用数百万个粒子和数千个质子。即使有几百个,也需要几天。我还使用了很多for和while循环以及对.dat文件的读/写

我真的需要你的帮助。我花了数周的时间试图优化我的代码,我的项目落后于计划。你有什么建议吗?我需要数组来存储粒子的位置。你认为类或函数会更有效吗?一般来说,任何建议都是有益的。抱歉,如果时间太长,但我很绝望

好的,我编辑了我的原始帖子,并分享了我的完整脚本。我希望这将给你一些关于我的模拟的见解。多谢各位

另外,我添加了两个输入文件

#包括
#包括
#包括
#包括
#包括
#包括//输出精度
//#包括
#包括
#包括
#包括
#包括
//#包括
#包含//随机生成器
#包括
使用名称空间std;
#定义PI 3.14159265
#定义tN 500000/#个时间点(步数)以仅定义阵列
#定义D_常数3.0E-9//扩散常数(m^2/s)
#定义Beq 0.16//Tesla
#定义gI 2.6752218744E8/(sT)^-1
int main(){
//梅森捻线机随机发动机
mt19937 rng(时钟::稳定时钟::现在().时间自纪元().计数());
//均匀分布区间(0,1);
均匀实分布实数分布(0,1.);
//对于(int i=1;itemp_cubAxN){
ionpN=(int)temp_ionpN;
aggN=(int)临时加总;
cubAxN=(int)temp_cubAxN;
}
inIONP.close();

我用了更多的步骤来讨论这个问题,第一件事是让运行重现:

  mt19937 rng(127386261); //I want a deterministic seed
然后我创建一个脚本来比较程序生成的三个输出文件:

#!/bin/bash

diff V3_MAT_positionAggreg_spherical.dat V3_MAT_positionAggreg_spherical2.dat
diff V3_MAT_positionSingle_spherical.dat V3_MAT_positionSingle_spherical2.dat
diff V3_MAT_positionSPM_spherical.dat V3_MAT_positionSPM_spherical2.dat
其中以两个结尾的文件由优化代码创建,另一个由您的版本创建

我使用O3标志运行您的版本编译并标记时间(对于20个磁性粒子和10个质子,在我的盒子上需要79秒,我的架构没有那么重要,因为我们只是要比较差异)

然后我开始一步一步地重构,通过比较输出文件和时间,运行每一个小更改,以下是所有迭代:

如果获得5秒(总运行74.0秒),则删除冗余else

现在,每次改进的增益都会减少很多,但仍然是

移除冗余sqrt增益(总运行12.9秒)

如果(总运行11.9秒)删除一个(另一个)冗余else


微优化可能会将运行时间减少100倍,但听起来你必须改进得远远不止这些。这导致了我的第二个评论,我在你的一个函数中计算了7个嵌套循环。你确定你的算法是正确的吗?你知道它的复杂性吗?如果它是大O(n^3)没有任何优化可以将粒子数从100个增加到1000000个(GPU或多线程)。我同意问题在于整体算法的复杂性。我能想到的一个微观优化是使用平方距离()对于
ionpDist
,因此删除sqrt调用谢谢您的快速响应。我已经测试了10000个粒子和1000个质子,大约需要5天。将它们与实验进行比较的实际和预期数字,我计算它们为10^(10)粒子和5000-10000个质子。请问,你有什么建议或建议吗?我正在考虑将粒子和簇定义为类,并将它们作为单独的标题,因为现在我只有一个main并生成函数,而不是for循环。另外,我不知道数组。干净的代码更容易优化。这将有很大的帮助使用函数分解主函数,使用<代码> STD::向量< /代码>代替手动内存管理等。请考虑把这个问题移到更深入的复习中。非常感谢!非常感谢您的帮助!只需替换变量就行了!谢谢!我一定会实现的!我想进一步改进模拟的逻辑,也许是粒子的产生和重复,或者是用我所做的质子来控制所有这些控制,这样它们就没有那么多的时间和内存消耗了。我正试图尽可能多地学习和实现,因为C++是真实的。我很强大,我想提高我自己。:)谢谢你,以及所有提到建议的人。我将尝试改进我的代码。最后一个问题。我应该将粒子实现到类中,并有方法创建它们或测试距离吗?这会改进模拟吗?谢谢。@FOXYL707它可能会,肯定会增加可读性,优化的关键是实验,做一个小的改变,运行一个测试,确保结果是相同的,并重复这个循环。你运行的时间不应该太长(我会说大约一分钟)。另一件小事,如果你使用的是gcc或clang,一定要同时分析O3和O2。有时O2会给你更好的速度
#!/bin/bash

diff V3_MAT_positionAggreg_spherical.dat V3_MAT_positionAggreg_spherical2.dat
diff V3_MAT_positionSingle_spherical.dat V3_MAT_positionSingle_spherical2.dat
diff V3_MAT_positionSPM_spherical.dat V3_MAT_positionSPM_spherical2.dat
if(sqrt(pow(x1_ionp[k]-x0[0],2.)+pow(x2_ionp[k]-x0[1],2.)+pow(x3_ionp[k]-x0[2],2.)) <= 7*Rionp){
  //spm closer than 8R
  stepL = Rionp/8;
  cnt_stpMin ++;
  break;
}
else { //this was an else if and an else for error that will never happen
  stepL = Rionp;
}
double square(double d)
{
  return d*d;
}
double cube(double d)
{
  return d*d*d;
}
 double ionpDist = square(x1_ionp[m]-x1_ionp[ionpCounter])+square(x2_ionp[m]-x2_ionp[ionpCounter])+square(x3_ionp[m]-x3_ionp[ionpCounter]);
 //cout<<"spmDist: "<<spmDist<<endl;
 if((j>0) && (ionpDist <= 4*square_Rionp)){
const double square_Rionp = square(Rionp);
const double cube_Rionp = cube(Rionp);
//replaced in the code like this
if((j>0) && (ionpDist <= 4*square_Rionp)){
const double Two_PI = PI*2.0;
const double FourThird_PI = PI*4.0/3.0;
if(pIONPDist <= 0.){
  cout<<"proton inside IONP => reposition! Distance: "<<pIONPDist<<" Rionp: "<<Rionp<<endl;
  hit_ionp = true;
}
else { //this was an else if without any reason
  hit_ionp=false; //with this I don't have to reset flag in the end
  //calculations of Bloc for this position
  pIONPCosTheta = (x3_ionp[k]-xt[2])/pIONPDist;
...
}
const double Seven_Rionp_squared =square(7*Rionp);
...
for(int k=0; k<ionpCounter; k++){
  if(square(x1_ionp[k]-x0[0])+square(x2_ionp[k]-x0[1])+square(x3_ionp[k]-x0[2]) <= Seven_Rionp_squared){
  //spm closer than 8R
  stepL = stepL_min;
  cnt_stpMin ++;
  break;
}
cosPhase_S[stepCounter] = cos(phase);
sinPhase_S[stepCounter] = sin(phase);