/******************Public functions**********************/ void System::simulate(double tMax, double ssize, bool stat){ time = 0; h = ssize; statSun = stat; for (int i = 0 ; i<nObj ; i++){ // Saveing the inital values calc_potential(); sys[i].update(sys[i].relR, sys[i].relV, time); } while (time <= tMax){ RK4(); time += h; } }
// Runge-Kutta 4 algorithm void System::RK4(){ vec2dN K1(nObj), K2(nObj), K3(nObj), K4(nObj); vec2dN L1(nObj), L2(nObj), L3(nObj), L4(nObj); vec2dN NewR(nObj), NewV(nObj); if (nObj == 1){ // If only ONE object K1 = h*derX(vec2dN(nObj)); L1 = h*(SunInf(vec2dN(nObj))); K2 = h*derX(L1*0.5); L2 = h*(SunInf(K1*0.5)); K3 = h*derX(L2*0.5); L3 = h*(SunInf(K2*0.5)); K4 = h*derX(L3); L4 = h*(SunInf(K3)); } else { // If more than one object if (!statSun){ // Sun mobile or not pressent K1 = h*derX(vec2dN(nObj)); L1 = h*derV(vec2dN(nObj)); K2 = h*derX(L1*0.5); L2 = h*derV(K1*0.5); K3 = h*derX(L2*0.5); L3 = h*derV(L2*0.5); K4 = h*derX(L3); L4 = h*derV(K4); } else { // If the sun is stationary K1 = h*derX(vec2dN(nObj)); L1 = h*(derV(vec2dN(nObj)) + SunInf(vec2dN(nObj))); K2 = h*derX(L1*0.5); L2 = h*(derV(K1*0.5) + SunInf(K1*0.5)); K3 = h*derX(L2*0.5); L3 = h*(derV(K2*0.5) + SunInf(K2*0.5)); K4 = h*derX(L3); L4 = h*(derV(K3) + SunInf(K3)); } } for (int i = 0 ; i < nObj ; i++){ NewR[i] = sys[i].relR + (K1[i] + 2*K2[i] + 2*K3[i] + K4[i])/(double)6; NewV[i] = sys[i].relV + (L1[i] + 2*L2[i] + 2*L3[i] + L4[i])/(double)6; } calc_potential(); for (int i = 0 ; i < nObj ; i++){ sys[i].update(NewR[i], NewV[i], sys[i].relT+h); } }
int gmx_potential(int argc, char *argv[]) { const char *desc[] = { "[THISMODULE] computes the electrostatical potential across the box. The potential is", "calculated by first summing the charges per slice and then integrating", "twice of this charge distribution. Periodic boundaries are not taken", "into account. Reference of potential is taken to be the left side of", "the box. It is also possible to calculate the potential in spherical", "coordinates as function of r by calculating a charge distribution in", "spherical slices and twice integrating them. epsilon_r is taken as 1,", "but 2 is more appropriate in many cases." }; gmx_output_env_t *oenv; static int axis = 2; /* normal to memb. default z */ static const char *axtitle = "Z"; static int nslices = 10; /* nr of slices defined */ static int ngrps = 1; static gmx_bool bSpherical = FALSE; /* default is bilayer types */ static real fudge_z = 0; /* translate coordinates */ static gmx_bool bCorrect = 0; t_pargs pa [] = { { "-d", FALSE, etSTR, {&axtitle}, "Take the normal on the membrane in direction X, Y or Z." }, { "-sl", FALSE, etINT, {&nslices}, "Calculate potential as function of boxlength, dividing the box" " in this number of slices." }, { "-cb", FALSE, etINT, {&cb}, "Discard this number of first slices of box for integration" }, { "-ce", FALSE, etINT, {&ce}, "Discard this number of last slices of box for integration" }, { "-tz", FALSE, etREAL, {&fudge_z}, "Translate all coordinates by this distance in the direction of the box" }, { "-spherical", FALSE, etBOOL, {&bSpherical}, "Calculate spherical thingie" }, { "-ng", FALSE, etINT, {&ngrps}, "Number of groups to consider" }, { "-correct", FALSE, etBOOL, {&bCorrect}, "Assume net zero charge of groups to improve accuracy" } }; const char *bugs[] = { "Discarding slices for integration should not be necessary." }; double **potential, /* potential per slice */ **charge, /* total charge per slice */ **field, /* field per slice */ slWidth; /* width of one slice */ char **grpname; /* groupnames */ int *ngx; /* sizes of groups */ t_topology *top; /* topology */ int ePBC; int **index; /* indices for all groups */ t_filenm fnm[] = { /* files for g_order */ { efTRX, "-f", NULL, ffREAD }, /* trajectory file */ { efNDX, NULL, NULL, ffREAD }, /* index file */ { efTPR, NULL, NULL, ffREAD }, /* topology file */ { efXVG, "-o", "potential", ffWRITE }, /* xvgr output file */ { efXVG, "-oc", "charge", ffWRITE }, /* xvgr output file */ { efXVG, "-of", "field", ffWRITE }, /* xvgr output file */ }; #define NFILE asize(fnm) if (!parse_common_args(&argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME, NFILE, fnm, asize(pa), pa, asize(desc), desc, asize(bugs), bugs, &oenv)) { return 0; } /* Calculate axis */ axis = toupper(axtitle[0]) - 'X'; top = read_top(ftp2fn(efTPR, NFILE, fnm), &ePBC); /* read topology file */ snew(grpname, ngrps); snew(index, ngrps); snew(ngx, ngrps); rd_index(ftp2fn(efNDX, NFILE, fnm), ngrps, ngx, index, grpname); calc_potential(ftp2fn(efTRX, NFILE, fnm), index, ngx, &potential, &charge, &field, &nslices, top, ePBC, axis, ngrps, &slWidth, fudge_z, bSpherical, bCorrect, oenv); plot_potential(potential, charge, field, opt2fn("-o", NFILE, fnm), opt2fn("-oc", NFILE, fnm), opt2fn("-of", NFILE, fnm), nslices, ngrps, (const char**)grpname, slWidth, oenv); do_view(oenv, opt2fn("-o", NFILE, fnm), NULL); /* view xvgr file */ do_view(oenv, opt2fn("-oc", NFILE, fnm), NULL); /* view xvgr file */ do_view(oenv, opt2fn("-of", NFILE, fnm), NULL); /* view xvgr file */ return 0; }