VecDoub Potential_JS::dPhidRdz(const VecDoub& Rz){ double Delta = 0.001; VecDoub Rplus = Forces({Rz[0]+Delta,0.,Rz[1]}); VecDoub Rminus = Forces({Rz[0]-Delta,0.,Rz[1]}); VecDoub zplus = Forces({Rz[0],0.,Rz[1]+Delta}); VecDoub zminus = Forces({Rz[0],0.,Rz[1]-Delta}); return {0.5*(Rminus[0]-Rplus[0])/Delta, 0.5*(Rminus[2]-Rplus[2])/Delta, 0.5*(zminus[2]-zplus[2])/Delta}; }
double Potential_JS::DeltaGuess(const VecDoub& x){ // Returns a guess of Alpha-Gamma assuming dldv((l-v)V)=0 double R = norm<double>({x[0],x[1]}), z = x[2]; VecDoub F = Forces({R,0.,z}); VecDoub d2P = dPhidRdz({R,z}); return z*z-R*R+(-3.0*z*F[0]+3.0*R*F[2]+R*z*(d2P[0]-d2P[2]))/d2P[1]; }
// Convert from PWM->Newton void SamplesInput::ConvertForce_Avalon(base::samples::Joints &sample, base::samples::Joints &forcesTorques) { forcesTorques.elements.resize(6); int n_thruster = sample.elements.size(); base::VectorXd forces = Eigen::VectorXd::Zero(n_thruster); base::VectorXd pwm = Eigen::VectorXd::Zero(n_thruster); base::VectorXd DC_volt = Eigen::VectorXd::Zero(n_thruster); base::Vector6d forces_torques = Eigen::VectorXd::Zero(6); if (sample.elements.size() > 0) {for (int i=0; i<sample.elements.size(); i++) { pwm[i] = sample.elements[i].raw * (-1); // forces according the movement } } // AVALON DATA/////// //convert the wrong direction pwm[3] *=-1; double ThrusterVoltage = 33; // Constant to be verified double pos_Cv = (0.0471 / 2.0); // Constants to be verified double neg_Cv = (0.0547 / 2.0); Eigen::MatrixXd TCM; TCM.resize(6,6); double DDT0 = 0.10; double DDT1 = 0.20; double DDT2 = 0.30; double DDT3 = 0.30; double DDT4 = 0.80; double DDT5 = 0.75; //Thruster Control Matrix of Avalon (Based on the work of Sankar-2010) // O^2 Ov1 O^3 // O->0 0z ->y // COG | // Ov4 vx // O->5 TCM << 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, DDT1, 0, 0, -DDT4, 0, DDT0, 0, DDT2, -DDT3, 0, 0; //////////////////// PWMtoDC(pwm, DC_volt, ThrusterVoltage); Forces(DC_volt, forces, pos_Cv, neg_Cv); ForcesTorques(forces, forces_torques, TCM); for (int i=0; i<6; i++) { forcesTorques.elements[i].effort = forces_torques[i]; } forcesTorques.time = sample.time; }
// Seabotix forces void SamplesInput::ConvertForce_Seabotix(base::samples::Joints &sample, base::samples::Joints &forcesTorques) { forcesTorques.elements.resize(6); int n_thruster = sample.elements.size(); base::VectorXd forces = Eigen::VectorXd::Zero(n_thruster); base::VectorXd pwm = Eigen::VectorXd::Zero(n_thruster); base::VectorXd DC_volt = Eigen::VectorXd::Zero(n_thruster); base::Vector6d forces_torques = Eigen::VectorXd::Zero(6); if (sample.elements.size() > 0) {for (int i=0; i<sample.elements.size(); i++) { pwm[i] = sample.elements[i].effort ;//* (-1); // forces according the movement } } // SEABOTIX DATA/////// double ThrusterVoltage = 19; // Constant to be verified double pos_Cv = 0.04005; // Constants to be verified double neg_Cv = 0.03457; Eigen::MatrixXd TCM; TCM.resize(6,4); //Thruster Control Matrix of Avalon (Based on the work of Sankar-2010) // O^1 Ov1 O^2 // O^3 <-Y xZ // COG | // O->4 vX TCM << 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0.04, 0.04, 0.04, 0, 0.05, -0.05, 0, 0.01; //////////////////// PWMtoDC(pwm, DC_volt, ThrusterVoltage); Forces(DC_volt, forces, pos_Cv, neg_Cv); ForcesTorques(forces, forces_torques, TCM); for (int i=0; i<6; i++) { forcesTorques.elements[i].effort = forces_torques[i]; } forcesTorques.time = sample.time + base::Time::fromSeconds(1.0155); // Add delay of seabotix }
double NFW::density(const VecDoub& x){ double Delta = 0.005; VecDoub xtmp=x; xtmp[0]+=Delta; VecDoub plus = Forces(xtmp); xtmp[0]-=2.*Delta; VecDoub minus = Forces(xtmp); double d2p = (minus[0]-plus[0])/2./Delta; xtmp[0]=x[0]; xtmp[1]+=Delta; plus = Forces(xtmp); xtmp[1]-=2.*Delta; minus = Forces(xtmp); d2p += (minus[1]-plus[1])/2./Delta; xtmp[1]=x[1]; xtmp[2]+=Delta; plus = Forces(xtmp); xtmp[2]-=2.*Delta; minus = Forces(xtmp); d2p += (minus[2]-plus[2])/2./Delta; xtmp[2]=x[2]; return d2p/4./PI; }
double Potential_JS::torb(const VecDoub &x){ double R = R_E(x); return 2.*PI*sqrt(R/-Forces({R,0.,0.})[0]); }
double Potential_JS::L_E(const VecDoub &x){ double R_e = R_E(x); return sqrt(pow(R_e,3.)*-Forces({R_e,0.,0.})[0]); }
double Potential_JS::L_E(double E){ double R_e = R_E(E); return sqrt(pow(R_e,3.)*-Forces({R_e,0.,0.})[0]); }
double GalPot::Vc(double R){ return sqrt(R*-Forces({R,0.,0.})[0]); }
// A master routine called from main.c to calculate the acceleration // ================================================================= void GetDisplacements(void) { int j; #ifdef TIMING double startcpu, endcpu; double startwall, endwall; #endif // First we check whether all the particles are on the correct processor after the last time step/ // original 2LPT displacement and move them if not if (ThisTask == 0) printf("Moving particles across task boundaries...\n"); #ifdef TIMING startcpu = (double)clock(); startwall = MPI_Wtime(); #endif MoveParticles(); #ifdef TIMING endcpu = (double)clock(); endwall = MPI_Wtime(); CpuTime_Move[timeSteptot-1] = (endcpu-startcpu)/(double)CLOCKS_PER_SEC; WallTime_Move[timeSteptot-1] = endwall-startwall; #endif #ifdef MEMORY_MODE density = (float_kind *)malloc(2*Total_size*sizeof(float_kind)); P3D = (complex_kind*)density; #ifdef SINGLE_PRECISION plan = fftwf_mpi_plan_dft_r2c_3d(Nmesh,Nmesh,Nmesh,density,P3D,MPI_COMM_WORLD,FFTW_ESTIMATE); #else plan = fftw_mpi_plan_dft_r2c_3d(Nmesh,Nmesh,Nmesh,density,P3D,MPI_COMM_WORLD,FFTW_ESTIMATE); #endif #endif // Then we do the Cloud-in-Cell assignment to get the density grid and FFT it. if (ThisTask == 0) printf("Calculating density using Cloud-in-Cell...\n"); #ifdef TIMING startcpu = (double)clock(); startwall = MPI_Wtime(); #endif PtoMesh(); #ifdef TIMING endcpu = (double)clock(); endwall = MPI_Wtime(); CpuTime_PtoMesh[timeSteptot-1] = (endcpu-startcpu)/(double)CLOCKS_PER_SEC; WallTime_PtoMesh[timeSteptot-1] = endwall-startwall; #endif #ifdef MEMORY_MODE N11 = (float_kind *)malloc(2*Total_size*sizeof(float_kind)); N12 = (float_kind *)malloc(2*Total_size*sizeof(float_kind)); N13 = (float_kind *)malloc(2*Total_size*sizeof(float_kind)); FN11 = (complex_kind*)N11; FN12 = (complex_kind*)N12; FN13 = (complex_kind*)N13; #ifdef SINGLE_PRECISION p11 = fftwf_mpi_plan_dft_c2r_3d(Nmesh,Nmesh,Nmesh,FN11,N11,MPI_COMM_WORLD,FFTW_ESTIMATE); p12 = fftwf_mpi_plan_dft_c2r_3d(Nmesh,Nmesh,Nmesh,FN12,N12,MPI_COMM_WORLD,FFTW_ESTIMATE); p13 = fftwf_mpi_plan_dft_c2r_3d(Nmesh,Nmesh,Nmesh,FN13,N13,MPI_COMM_WORLD,FFTW_ESTIMATE); #else p11 = fftw_mpi_plan_dft_c2r_3d(Nmesh,Nmesh,Nmesh,FN11,N11,MPI_COMM_WORLD,FFTW_ESTIMATE); p12 = fftw_mpi_plan_dft_c2r_3d(Nmesh,Nmesh,Nmesh,FN12,N12,MPI_COMM_WORLD,FFTW_ESTIMATE); p13 = fftw_mpi_plan_dft_c2r_3d(Nmesh,Nmesh,Nmesh,FN13,N13,MPI_COMM_WORLD,FFTW_ESTIMATE); #endif #endif // This returns N11,N12,N13 which hold the components of // the vector (grad grad^{-2} density) on a grid. if (ThisTask == 0) printf("Calculating forces...\n"); #ifdef TIMING startcpu = (double)clock(); startwall = MPI_Wtime(); #endif Forces(); #ifdef TIMING endcpu = (double)clock(); endwall = MPI_Wtime(); CpuTime_Forces[timeSteptot-1] = (endcpu-startcpu)/(double)CLOCKS_PER_SEC; WallTime_Forces[timeSteptot-1] = endwall-startwall; #endif #ifdef MEMORY_MODE free(density); for (j=0; j<3; j++) Disp[j] = (float *)malloc(NumPart*sizeof(float)); #ifdef SINGLE_PRECISION fftwf_destroy_plan(plan); #else fftw_destroy_plan(plan); #endif #else for (j=0; j<3; j++) Disp[j] = (float_kind *)malloc(NumPart*sizeof(float_kind)); #endif // Now find the accelerations at the particle positions using 3-linear interpolation. if (ThisTask == 0) printf("Calculating accelerations...\n"); #ifdef TIMING startcpu = (double)clock(); startwall = MPI_Wtime(); #endif MtoParticles(); #ifdef TIMING endcpu = (double)clock(); endwall = MPI_Wtime(); CpuTime_MtoParticles[timeSteptot-1] = (endcpu-startcpu)/(double)CLOCKS_PER_SEC; WallTime_MtoParticles[timeSteptot-1] = endwall-startwall; #endif #ifdef MEMORY_MODE free(N11); free(N12); free(N13); #ifdef SINGLE_PRECISION fftwf_destroy_plan(p11); fftwf_destroy_plan(p12); fftwf_destroy_plan(p13); #else fftw_destroy_plan(p11); fftw_destroy_plan(p12); fftw_destroy_plan(p13); #endif #endif }
int main(int argc, char **argv) { // Set up MPI // ========== ierr = MPI_Init(&argc, &argv); ierr = MPI_Comm_rank(MPI_COMM_WORLD, &ThisTask); ierr = MPI_Comm_size(MPI_COMM_WORLD, &NTask); #ifdef SINGLE_PRECISION fftwf_mpi_init(); #else fftw_mpi_init(); #endif if(argc < 2) { if(ThisTask == 0) { fprintf(stdout, "Input parameters not found\n"); fprintf(stdout, "Call with <ParameterFile>\n"); } ierr = MPI_Finalize(); exit(0); } // Read the run parameters and setup code // ====================================== int stepDistr; int subtractLPT; double da=0; read_parameterfile(argv[1]); if (UseCOLA == 1){ subtractLPT = 1; stepDistr = 0; StdDA = 0; } else{ subtractLPT = 0; stepDistr = 1; StdDA = 2; } if (StdDA == 0){ fullT = 1; nLPT = -2.5; } filter = 0; // Whether or not to smooth the forces Scale = 2.*M_PI/Box; // The force smoothing scale if(ThisTask == 0) { printf("Run Parameters\n"); printf("==============\n"); printf("Cosmology:\n"); printf(" Omega Matter(z=0) = %lf\n",Omega); printf(" Omega Baryon(z=0) = %lf\n",OmegaBaryon); printf(" Hubble Parameter(z=0) = %lf\n",HubbleParam); printf(" Sigma8(z=0) = %lf\n",Sigma8); #ifndef GAUSSIAN printf(" F_nl = %lf\n",Fnl); #endif printf(" Primordial Index = %lf\n",PrimordialIndex); printf(" Initial Redshift = %lf\n",Init_Redshift); printf(" Final Redshift = %lf\n",Final_Redshift); #ifndef GAUSSIAN printf(" F_nl Redshift = %lf\n",Fnl_Redshift); #endif printf("Simulation:\n"); printf(" Nmesh = %d\n", Nmesh); printf(" Nsample = %d\n", Nsample); printf(" Boxsize = %lf\n", Box); printf(" Buffer Size = %lf\n", Buffer); switch(WhichSpectrum) { case 0: switch (WhichTransfer) { case 1: printf(" Using Eisenstein & Hu Transfer Function\n"); break; case 2: printf(" Using Tabulated Transfer Function\n"); break; default: printf(" Using Efstathiou Transfer Function\n"); break; } break; case 1: printf(" Using Eisenstein & Hu Power Spectrum\n"); break; case 2: printf(" Using Tabulated Power Spectrum\n"); break; default: printf(" Using Efstathiou Power Spectrum\n"); break; } printf(" Number of Timesteps = %d\n",nsteps); if (UseCOLA) { printf(" Using COLA method\n\n"); } else { printf(" Using Standard PM method\n\n"); } fflush(stdout); } // Initial and final scale factors: double ai=1.0/(1.0+Init_Redshift); double af=1.0/(1.0+Final_Redshift); if (stepDistr == 0) da=(af-ai)/((double)nsteps); if (stepDistr == 1) da=(log(af)-log(ai))/((double)nsteps); if (stepDistr == 2) da=(CosmoTime(af)-CosmoTime(ai))/((double)nsteps); set_units(); if (ThisTask == 0) { printf("Initialising Transfer Function/Power Spectrum\n"); printf("=============================================\n"); } initialize_transferfunction(); initialize_powerspectrum(); initialize_ffts(); initialize_parts(); if(ThisTask == 0) { printf("Creating initial conditions\n"); printf("===========================\n"); fflush(stdout); } // Create the calculate the Zeldovich and 2LPT displacements and create the initial conditions // =========================================================================================== int i, j, k, m; unsigned int n, coord; double A=ai; // This is the scale factor which we'll be advancing below. double Di=growthD(1.0, A); // initial growth factor double Di2=growthD2(A); // initial 2nd order growth factor double Dv=DprimeQ(A,1.0); // T[D_{za}]=dD_{za}/dy double Dv2=growthD2v(A); // T[D_{2lpt}]=dD_{2lpt}/dy displacement_fields(); P = (struct part_data *) malloc((int)(ceil(NumPart*Buffer))*sizeof(struct part_data)); // Generate the initial particle positions and velocities // If subtractLPT = 0 (non-COLA), then velocity is ds/dy, which is simply the 2LPT IC. // Else set vel = 0 if we subtract LPT. This is the same as the action of the operator L_- from TZE, as initial velocities are in 2LPT. for(i=0; i<Local_np; i++) { for (j=0; j<Nsample; j++) { for (k=0; k<Nsample; k++) { coord = (i * Nsample + j) * Nsample + k; P[coord].ID = ((i + Local_p_start) * Nsample + j) * Nsample + k; for (m=0; m<3; m++) { P[coord].Dz[m] = ZA[m][coord]; P[coord].D2[m] = LPT[m][coord]; if (subtractLPT == 0) { P[coord].Vel[m]=P[coord].Dz[m]*Dv+P[coord].D2[m]*Dv2; } else { P[coord].Vel[m] = 0.0; } } P[coord].Pos[0] = periodic_wrap((i+Local_p_start)*(Box/Nsample)+P[coord].Dz[0]*Di+P[coord].D2[0]*Di2); P[coord].Pos[1] = periodic_wrap(j*(Box/Nsample)+P[coord].Dz[1]*Di+P[coord].D2[1]*Di2); P[coord].Pos[2] = periodic_wrap(k*(Box/Nsample)+P[coord].Dz[2]*Di+P[coord].D2[2]*Di2); } } } for (i=0; i<3; i++) { free(ZA[i]); free(LPT[i]); } // Now, we get to the N-Body part where we evolve with time via the Kick-Drift-Kick Method // ======================================================================================= int timeStep; double AF=0,AI,AC,AFF=0; double growth1 = Di; double growth1L2 = Di2; // The density grid and force grids and associated fftw plans #ifndef MEMORY_MODE density = (float_kind *)calloc(2*Total_size,sizeof(float_kind)); N11 = (float_kind *)calloc(2*Total_size,sizeof(float_kind)); N12 = (float_kind *)calloc(2*Total_size,sizeof(float_kind)); N13 = (float_kind *)calloc(2*Total_size,sizeof(float_kind)); P3D = (complex_kind*)density; FN11 = (complex_kind*)N11; FN12 = (complex_kind*)N12; FN13 = (complex_kind*)N13; #ifdef SINGLE_PRECISION plan = fftwf_mpi_plan_dft_r2c_3d(Nmesh,Nmesh,Nmesh,density,P3D,MPI_COMM_WORLD,FFTW_ESTIMATE); p11 = fftwf_mpi_plan_dft_c2r_3d(Nmesh,Nmesh,Nmesh,FN11,N11,MPI_COMM_WORLD,FFTW_ESTIMATE); p12 = fftwf_mpi_plan_dft_c2r_3d(Nmesh,Nmesh,Nmesh,FN12,N12,MPI_COMM_WORLD,FFTW_ESTIMATE); p13 = fftwf_mpi_plan_dft_c2r_3d(Nmesh,Nmesh,Nmesh,FN13,N13,MPI_COMM_WORLD,FFTW_ESTIMATE); #else plan = fftw_mpi_plan_dft_r2c_3d(Nmesh,Nmesh,Nmesh,density,P3D,MPI_COMM_WORLD,FFTW_ESTIMATE); p11 = fftw_mpi_plan_dft_c2r_3d(Nmesh,Nmesh,Nmesh,FN11,N11,MPI_COMM_WORLD,FFTW_ESTIMATE); p12 = fftw_mpi_plan_dft_c2r_3d(Nmesh,Nmesh,Nmesh,FN12,N12,MPI_COMM_WORLD,FFTW_ESTIMATE); p13 = fftw_mpi_plan_dft_c2r_3d(Nmesh,Nmesh,Nmesh,FN13,N13,MPI_COMM_WORLD,FFTW_ESTIMATE); #endif #endif if(ThisTask == 0) { printf("Beginning timestepping\n"); printf("======================\n"); fflush(stdout); } // AI stores the scale factor to which the velocities have been kicked to. Initially it's just A. AI=A; for (timeStep=0;timeStep<=nsteps;timeStep++){ // AFF is the scale factor to which we should drift the particle positions. // AF is the scale factor to which we should kick the particle velocities. if (stepDistr == 0) AFF=A+da; if (stepDistr == 1) AFF=A*exp(da); if (stepDistr == 2) AFF=AofTime(CosmoTime(A)+da); // half time-step for final kick if (timeStep == nsteps) { AF=A; } else { // Set to mid-point of interval. In the infinitesimal timestep limit, these choices are identical. // How one chooses the mid-point when not in that limit is really an extra degree of freedom in the code // but Tassev et al. report negligible effects from the different choices below. // Hence, this is not exported as an extra switch at this point. if (stepDistr == 0) AF=A+da*0.5; if (stepDistr == 1) AF=A*exp(da*0.5); if (stepDistr == 2) AF=AofTime((CosmoTime(AFF)+CosmoTime(A))*0.5); } if (ThisTask == 0) { printf("Iteration = %d\n------------------\n",timeStep+1); printf("a = %lf\n",A); printf("z = %lf\n",1.0/A-1.0); fflush(stdout); } // First we check whether all the particles are on the correct processor after the last time step/ // original 2LPT displacement and move them if not if (ThisTask == 0) printf("Moving particles across task boundaries...\n"); MoveParticles(); #ifdef MEMORY_MODE density = (float_kind *)calloc(2*Total_size,sizeof(float_kind)); P3D = (complex_kind*)density; #ifdef SINGLE_PRECISION plan = fftwf_mpi_plan_dft_r2c_3d(Nmesh,Nmesh,Nmesh,density,P3D,MPI_COMM_WORLD,FFTW_ESTIMATE); #else plan = fftw_mpi_plan_dft_r2c_3d(Nmesh,Nmesh,Nmesh,density,P3D,MPI_COMM_WORLD,FFTW_ESTIMATE); #endif #endif // Then we do the Cloud-in-Cell assignment to get the density grid and FFT it. if (ThisTask == 0) printf("Calculating density using Cloud-in-Cell...\n"); PtoMesh(); #ifdef MEMORY_MODE N11 = (float_kind *)calloc(2*Total_size,sizeof(float_kind)); N12 = (float_kind *)calloc(2*Total_size,sizeof(float_kind)); N13 = (float_kind *)calloc(2*Total_size,sizeof(float_kind)); FN11 = (complex_kind*)N11; FN12 = (complex_kind*)N12; FN13 = (complex_kind*)N13; #ifdef SINGLE_PRECISION p11 = fftwf_mpi_plan_dft_c2r_3d(Nmesh,Nmesh,Nmesh,FN11,N11,MPI_COMM_WORLD,FFTW_ESTIMATE); p12 = fftwf_mpi_plan_dft_c2r_3d(Nmesh,Nmesh,Nmesh,FN12,N12,MPI_COMM_WORLD,FFTW_ESTIMATE); p13 = fftwf_mpi_plan_dft_c2r_3d(Nmesh,Nmesh,Nmesh,FN13,N13,MPI_COMM_WORLD,FFTW_ESTIMATE); #else p11 = fftw_mpi_plan_dft_c2r_3d(Nmesh,Nmesh,Nmesh,FN11,N11,MPI_COMM_WORLD,FFTW_ESTIMATE); p12 = fftw_mpi_plan_dft_c2r_3d(Nmesh,Nmesh,Nmesh,FN12,N12,MPI_COMM_WORLD,FFTW_ESTIMATE); p13 = fftw_mpi_plan_dft_c2r_3d(Nmesh,Nmesh,Nmesh,FN13,N13,MPI_COMM_WORLD,FFTW_ESTIMATE); #endif #endif // This returns N11,N12,N13 which hold the components of // the vector (grad grad^{-2} density) on a grid. if (ThisTask == 0) printf("Calculating forces...\n"); Forces(); #ifdef MEMORY_MODE free(density); for (i=0; i<3; i++) Disp[i] = (float *)malloc(NumPart*sizeof(float)); #ifdef SINGLE_PRECISION fftwf_destroy_plan(plan); #else fftw_destroy_plan(plan); #endif #else for (i=0; i<3; i++) Disp[i] = (float_kind *)malloc(NumPart*sizeof(float_kind)); #endif // Now find the accelerations at the particle positions using 3-linear interpolation. if (ThisTask == 0) printf("Calculating accelerations...\n"); MtoParticles(); #ifdef MEMORY_MODE free(N11); free(N12); free(N13); #ifdef SINGLE_PRECISION fftwf_destroy_plan(p11); fftwf_destroy_plan(p12); fftwf_destroy_plan(p13); #else fftw_destroy_plan(p11); fftw_destroy_plan(p12); fftw_destroy_plan(p13); #endif #endif // Calculate the mean displacement and subtract later. if (ThisTask == 0) printf("Calculating mean of displacements...\n"); double sumDx=0,sumDy=0,sumDz=0; for(n=0; n<NumPart; n++) { sumDx += Disp[0][n]; sumDy += Disp[1][n]; sumDz += Disp[2][n]; } // Make sumDx, sumDy and sumDz global averages ierr = MPI_Allreduce(MPI_IN_PLACE,&sumDx,1,MPI_DOUBLE,MPI_SUM,MPI_COMM_WORLD); ierr = MPI_Allreduce(MPI_IN_PLACE,&sumDy,1,MPI_DOUBLE,MPI_SUM,MPI_COMM_WORLD); ierr = MPI_Allreduce(MPI_IN_PLACE,&sumDz,1,MPI_DOUBLE,MPI_SUM,MPI_COMM_WORLD); sumDx /= (double)TotNumPart; // We will subtract these below to conserve momentum. sumDy /= (double)TotNumPart; sumDz /= (double)TotNumPart; if (ThisTask == 0) { printf("Kicking the particles...\n"); fflush(stdout); } // Kick // =============== double dda; double q1,q2; double ax,ay,az; double sumx=0,sumy=0,sumz=0; double Om143=pow(Omega/(Omega+(1-Omega)*A*A*A),1./143.); if (StdDA == 0) { dda=Sphi(AI,AF,A); } else if (StdDA == 1) { dda=(AF-AI)*A/Qfactor(A); } else { dda=SphiStd(AI,AF); } q2=1.5*Omega*growth1*growth1*(1.0+7./3.*Om143)*A; // T^2[D_{2lpt}]=d^2 D_{2lpt}/dy^2 q1=1.5*Omega*growth1*A; // T^2[D_{ZA}]=d^2 D_{ZA}/dy^2 for(n=0; n<NumPart; n++) { Disp[0][n] -= sumDx; Disp[1][n] -= sumDy; Disp[2][n] -= sumDz; ax=-1.5*Omega*Disp[0][n]-subtractLPT*(P[n].Dz[0]*q1+P[n].D2[0]*q2)/A; ay=-1.5*Omega*Disp[1][n]-subtractLPT*(P[n].Dz[1]*q1+P[n].D2[1]*q2)/A; az=-1.5*Omega*Disp[2][n]-subtractLPT*(P[n].Dz[2]*q1+P[n].D2[2]*q2)/A; P[n].Vel[0] += ax*dda; P[n].Vel[1] += ay*dda; P[n].Vel[2] += az*dda; sumx += P[n].Vel[0]; sumy += P[n].Vel[1]; sumz += P[n].Vel[2]; } for (i=0; i<3; i++) free(Disp[i]); // Make sumx, sumy and sumz global averages ierr = MPI_Allreduce(MPI_IN_PLACE,&sumx,1,MPI_DOUBLE,MPI_SUM,MPI_COMM_WORLD); ierr = MPI_Allreduce(MPI_IN_PLACE,&sumy,1,MPI_DOUBLE,MPI_SUM,MPI_COMM_WORLD); ierr = MPI_Allreduce(MPI_IN_PLACE,&sumz,1,MPI_DOUBLE,MPI_SUM,MPI_COMM_WORLD); sumx /= (double)TotNumPart; // We will subtract these below to conserve momentum. sumy /= (double)TotNumPart; // Should be conserved, but just in case 3-linear interpolation makes a problem. sumz /= (double)TotNumPart; // Never checked whether this makes a difference. if (timeStep == nsteps) { if (ThisTask == 0) { printf("Iteration %d finished\n------------------\n\n", timeStep+1); printf("Timestepping finished\n\n"); fflush(stdout); } // At final timestep, add back LPT velocities if we had subtracted them. // This corresponds to L_+ operator in TZE. Dv = DprimeQ(A,1.0); // dD_{za}/dy Dv2 = growthD2v(A); // dD_{2lpt}/dy for(n=0; n<NumPart; n++) { P[n].Vel[0] += -sumx+(P[n].Dz[0]*Dv+P[n].D2[0]*Dv2)*subtractLPT; P[n].Vel[1] += -sumy+(P[n].Dz[1]*Dv+P[n].D2[1]*Dv2)*subtractLPT; P[n].Vel[2] += -sumz+(P[n].Dz[2]*Dv+P[n].D2[2]*Dv2)*subtractLPT; } goto finalize; // Sorry for "goto" :) } if (ThisTask == 0) { printf("Drifting the particles...\n"); fflush(stdout); } // Drift // ============= double dyyy; double da1,da2; AC = AF; AF = AFF; if (StdDA == 0) { dyyy=Sq(A,AF,AC); } else if (StdDA == 1) { dyyy=(AF-A)/Qfactor(AC); } else { dyyy=SqStd(A,AF); } da1=growthD(1.0, AF)-growth1; // change in D da2=growthD2(AF)-growth1L2; // change in D_{2lpt} for(n=0; n<NumPart; n++) { P[n].Pos[0] += (P[n].Vel[0]-sumx)*dyyy; P[n].Pos[1] += (P[n].Vel[1]-sumy)*dyyy; P[n].Pos[2] += (P[n].Vel[2]-sumz)*dyyy; P[n].Pos[0] = periodic_wrap(P[n].Pos[0]+subtractLPT*(P[n].Dz[0]*da1+P[n].D2[0]*da2)); P[n].Pos[1] = periodic_wrap(P[n].Pos[1]+subtractLPT*(P[n].Dz[1]*da1+P[n].D2[1]*da2)); P[n].Pos[2] = periodic_wrap(P[n].Pos[2]+subtractLPT*(P[n].Dz[2]*da1+P[n].D2[2]*da2)); } // Step in time // ================ A = AF; // WRT to the above name change, A = AFF AI = AC; // WRT to the above name change, AI = AF growth1 = growthD(1.0, A); growth1L2 = growthD2(A); if (ThisTask == 0) { printf("Iteration %d finished\n------------------\n\n", timeStep+1); fflush(stdout); } ierr = MPI_Barrier(MPI_COMM_WORLD); } // Here is the last little bit // =========================== finalize: if (ThisTask == 0) { printf("Finishing up\n"); printf("============\n"); fflush(stdout); } // Now convert velocities to v_{rsd}\equiv (ds/d\eta)/(a H(a)) velRSD(A); // Output a slice just for the sake of doing something with P. if (ThisTask == 0) { printf("Converting to RSD velocities...\n"); printf("Outputting particles...\n"); } slice(); print_spec(); fflush(stdout); free_powertable(); free_transfertable(); #ifdef GENERIC_FNL free(KernelTable); #endif free(P); free(Slab_to_task); free(Part_to_task); free(Local_nx_table); free(Local_np_table); #ifndef MEMORY_MODE free(density); free(N11); free(N12); free(N13); #ifdef SINGLE_PRECISION fftwf_destroy_plan(plan); fftwf_destroy_plan(p11); fftwf_destroy_plan(p12); fftwf_destroy_plan(p13); #else fftw_destroy_plan(plan); fftw_destroy_plan(p11); fftw_destroy_plan(p12); fftw_destroy_plan(p13); #endif #endif #ifdef SINGLE_PRECISION fftwf_mpi_cleanup(); #else fftw_mpi_cleanup(); #endif if (ThisTask == 0) printf("Done :)\n"); MPI_Finalize(); return 0; }