void do_md_trajectory_writing(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[], gmx_int64_t step, gmx_int64_t step_rel, double t, t_inputrec *ir, t_state *state, t_state *state_global, gmx_mtop_t *top_global, t_forcerec *fr, gmx_mdoutf_t outf, t_mdebin *mdebin, gmx_ekindata_t *ekind, rvec *f, rvec *f_global, int *nchkpt, gmx_bool bCPT, gmx_bool bRerunMD, gmx_bool bLastStep, gmx_bool bDoConfOut, gmx_bool bSumEkinhOld ) { int mdof_flags; rvec *x_for_confout = NULL; mdof_flags = 0; if (do_per_step(step, ir->nstxout)) { mdof_flags |= MDOF_X; } if (do_per_step(step, ir->nstvout)) { mdof_flags |= MDOF_V; } if (do_per_step(step, ir->nstfout)) { mdof_flags |= MDOF_F; } if (do_per_step(step, ir->nstxout_compressed)) { mdof_flags |= MDOF_X_COMPRESSED; } if (bCPT) { mdof_flags |= MDOF_CPT; } ; #if defined(GMX_FAHCORE) if (bLastStep) { /* Enforce writing positions and velocities at end of run */ mdof_flags |= (MDOF_X | MDOF_V); } if (MASTER(cr)) { fcReportProgress( ir->nsteps, step ); } #if defined(__native_client__) fcCheckin(MASTER(cr)); #endif /* sync bCPT and fc record-keeping */ if (bCPT && MASTER(cr)) { fcRequestCheckPoint(); } #endif if (mdof_flags != 0) { wallcycle_start(mdoutf_get_wcycle(outf), ewcTRAJ); if (bCPT) { if (MASTER(cr)) { if (bSumEkinhOld) { state_global->ekinstate.bUpToDate = FALSE; } else { update_ekinstate(&state_global->ekinstate, ekind); state_global->ekinstate.bUpToDate = TRUE; } update_energyhistory(state_global->enerhist, mdebin); } } mdoutf_write_to_trajectory_files(fplog, cr, outf, mdof_flags, top_global, step, t, state, state_global, f, f_global); if (bCPT) { (*nchkpt)++; } debug_gmx(); if (bLastStep && step_rel == ir->nsteps && bDoConfOut && MASTER(cr) && !bRerunMD) { if (fr->bMolPBC && state->x == state_global->x) { /* This (single-rank) run needs to allocate a temporary array of size natoms so that any periodicity removal for mdrun -confout does not perturb the update and thus the final .edr output. This makes .cpt restarts look binary identical, and makes .edr restarts binary identical. */ snew(x_for_confout, state_global->natoms); copy_rvecn(state_global->x, x_for_confout, 0, state_global->natoms); } else { /* With DD, or no bMolPBC, it doesn't matter if we change state_global->x */ x_for_confout = state_global->x; } /* x and v have been collected in mdoutf_write_to_trajectory_files, * because a checkpoint file will always be written * at the last step. */ fprintf(stderr, "\nWriting final coordinates.\n"); if (fr->bMolPBC) { /* Make molecules whole only for confout writing */ do_pbc_mtop(fplog, ir->ePBC, state->box, top_global, x_for_confout); } write_sto_conf_mtop(ftp2fn(efSTO, nfile, fnm), *top_global->name, top_global, x_for_confout, state_global->v, ir->ePBC, state->box); if (fr->bMolPBC && state->x == state_global->x) { sfree(x_for_confout); } debug_gmx(); } wallcycle_stop(mdoutf_get_wcycle(outf), ewcTRAJ); } }
void do_md_trajectory_writing(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[], gmx_int64_t step, gmx_int64_t step_rel, double t, t_inputrec *ir, t_state *state, t_state *state_global, gmx_mtop_t *top_global, t_forcerec *fr, gmx_mdoutf_t outf, t_mdebin *mdebin, gmx_ekindata_t *ekind, rvec *f, rvec *f_global, int *nchkpt, gmx_bool bCPT, gmx_bool bRerunMD, gmx_bool bLastStep, gmx_bool bDoConfOut, gmx_bool bSumEkinhOld ) { int mdof_flags; mdof_flags = 0; if (do_per_step(step, ir->nstxout)) { mdof_flags |= MDOF_X; } if (do_per_step(step, ir->nstvout)) { mdof_flags |= MDOF_V; } if (do_per_step(step, ir->nstfout)) { mdof_flags |= MDOF_F; } if (do_per_step(step, ir->nstxout_compressed)) { mdof_flags |= MDOF_X_COMPRESSED; } if (bCPT) { mdof_flags |= MDOF_CPT; } ; #if defined(GMX_FAHCORE) || defined(GMX_WRITELASTSTEP) if (bLastStep) { /* Enforce writing positions and velocities at end of run */ mdof_flags |= (MDOF_X | MDOF_V); } #endif #ifdef GMX_FAHCORE if (MASTER(cr)) { fcReportProgress( ir->nsteps, step ); } #if defined(__native_client__) fcCheckin(MASTER(cr)); #endif /* sync bCPT and fc record-keeping */ if (bCPT && MASTER(cr)) { fcRequestCheckPoint(); } #endif if (mdof_flags != 0) { wallcycle_start(mdoutf_get_wcycle(outf), ewcTRAJ); if (bCPT) { if (MASTER(cr)) { if (bSumEkinhOld) { state_global->ekinstate.bUpToDate = FALSE; } else { update_ekinstate(&state_global->ekinstate, ekind); state_global->ekinstate.bUpToDate = TRUE; } update_energyhistory(&state_global->enerhist, mdebin); } } mdoutf_write_to_trajectory_files(fplog, cr, outf, mdof_flags, top_global, step, t, state, state_global, f, f_global); if (bCPT) { (*nchkpt)++; } debug_gmx(); if (bLastStep && step_rel == ir->nsteps && bDoConfOut && MASTER(cr) && !bRerunMD) { /* x and v have been collected in mdoutf_write_to_trajectory_files, * because a checkpoint file will always be written * at the last step. */ fprintf(stderr, "\nWriting final coordinates.\n"); if (fr->bMolPBC) { /* Make molecules whole only for confout writing */ do_pbc_mtop(fplog, ir->ePBC, state->box, top_global, state_global->x); } write_sto_conf_mtop(ftp2fn(efSTO, nfile, fnm), *top_global->name, top_global, state_global->x, state_global->v, ir->ePBC, state->box); debug_gmx(); } wallcycle_stop(mdoutf_get_wcycle(outf), ewcTRAJ); } }
void do_coupling(FILE *log,int nfile,t_filenm fnm[], t_coupl_rec *tcr,real t,int step,real ener[], t_forcerec *fr,t_inputrec *ir,bool bMaster, t_mdatoms *md,t_idef *idef,real mu_aver,int nmols, t_commrec *cr,matrix box,tensor virial, tensor pres,rvec mu_tot, rvec x[],rvec f[],bool bDoIt) { #define enm2Debye 48.0321 #define d2e(x) (x)/enm2Debye #define enm2kjmol(x) (x)*0.0143952 /* = 2.0*4.0*M_PI*EPSILON0 */ static real *f6,*f12,*fa,*fb,*fc,*fq; static bool bFirst = TRUE; int i,j,ati,atj,atnr2,type,ftype; real deviation[eoObsNR],prdev[eoObsNR],epot0,dist,rmsf; real ff6,ff12,ffa,ffb,ffc,ffq,factor,dt,mu_ind; real Epol,Eintern,Virial,muabs,xiH=-1,xiS=-1,xi6,xi12; rvec fmol[2]; bool bTest,bPrint; t_coupl_LJ *tclj; t_coupl_BU *tcbu; t_coupl_Q *tcq; t_coupl_iparams *tip; atnr2 = idef->atnr * idef->atnr; if (bFirst) { if (PAR(cr)) fprintf(log,"GCT: this is parallel\n"); else fprintf(log,"GCT: this is not parallel\n"); fflush(log); snew(f6, atnr2); snew(f12,atnr2); snew(fa, atnr2); snew(fb, atnr2); snew(fc, atnr2); snew(fq, idef->atnr); if (tcr->bVirial) { int nrdf = 0; real TTT = 0; real Vol = det(box); for(i=0; (i<ir->opts.ngtc); i++) { nrdf += ir->opts.nrdf[i]; TTT += ir->opts.nrdf[i]*ir->opts.ref_t[i]; } TTT /= nrdf; /* Calculate reference virial from reference temperature and pressure */ tcr->ref_value[eoVir] = 0.5*BOLTZ*nrdf*TTT - (3.0/2.0)* Vol*tcr->ref_value[eoPres]; fprintf(log,"GCT: TTT = %g, nrdf = %d, vir0 = %g, Vol = %g\n", TTT,nrdf,tcr->ref_value[eoVir],Vol); fflush(log); } bFirst = FALSE; } bPrint = MASTER(cr) && do_per_step(step,ir->nstlog); dt = ir->delta_t; /* Initiate coupling to the reference pressure and temperature to start * coupling slowly. */ if (step == 0) { for(i=0; (i<eoObsNR); i++) tcr->av_value[i] = tcr->ref_value[i]; if ((tcr->ref_value[eoDipole]) != 0.0) { mu_ind = mu_aver - d2e(tcr->ref_value[eoDipole]); /* in e nm */ Epol = mu_ind*mu_ind/(enm2kjmol(tcr->ref_value[eoPolarizability])); tcr->av_value[eoEpot] -= Epol; fprintf(log,"GCT: mu_aver = %g(D), mu_ind = %g(D), Epol = %g (kJ/mol)\n", mu_aver*enm2Debye,mu_ind*enm2Debye,Epol); } } /* We want to optimize the LJ params, usually to the Vaporization energy * therefore we only count intermolecular degrees of freedom. * Note that this is now optional. switch UseEinter to yes in your gct file * if you want this. */ dist = calc_dist(log,x); muabs = norm(mu_tot); Eintern = Ecouple(tcr,ener)/nmols; Virial = virial[XX][XX]+virial[YY][YY]+virial[ZZ][ZZ]; /*calc_force(md->nr,f,fmol);*/ clear_rvec(fmol[0]); /* Use a memory of tcr->nmemory steps, so we actually couple to the * average observable over the last tcr->nmemory steps. This may help * in avoiding local minima in parameter space. */ set_act_value(tcr,eoPres, ener[F_PRES],step); set_act_value(tcr,eoEpot, Eintern, step); set_act_value(tcr,eoVir, Virial, step); set_act_value(tcr,eoDist, dist, step); set_act_value(tcr,eoMu, muabs, step); set_act_value(tcr,eoFx, fmol[0][XX], step); set_act_value(tcr,eoFy, fmol[0][YY], step); set_act_value(tcr,eoFz, fmol[0][ZZ], step); set_act_value(tcr,eoPx, pres[XX][XX],step); set_act_value(tcr,eoPy, pres[YY][YY],step); set_act_value(tcr,eoPz, pres[ZZ][ZZ],step); epot0 = tcr->ref_value[eoEpot]; /* If dipole != 0.0 assume we want to use polarization corrected coupling */ if ((tcr->ref_value[eoDipole]) != 0.0) { mu_ind = mu_aver - d2e(tcr->ref_value[eoDipole]); /* in e nm */ Epol = mu_ind*mu_ind/(enm2kjmol(tcr->ref_value[eoPolarizability])); epot0 -= Epol; if (debug) { fprintf(debug,"mu_ind: %g (%g D) mu_aver: %g (%g D)\n", mu_ind,mu_ind*enm2Debye,mu_aver,mu_aver*enm2Debye); fprintf(debug,"Eref %g Epol %g Erunav %g Eact %g\n", tcr->ref_value[eoEpot],Epol,tcr->av_value[eoEpot], tcr->act_value[eoEpot]); } } if (bPrint) { pr_ff(tcr,t,idef,cr,nfile,fnm); } /* Calculate the deviation of average value from the target value */ for(i=0; (i<eoObsNR); i++) { deviation[i] = calc_deviation(tcr->av_value[i],tcr->act_value[i], tcr->ref_value[i]); prdev[i] = tcr->ref_value[i] - tcr->act_value[i]; } deviation[eoEpot] = calc_deviation(tcr->av_value[eoEpot],tcr->act_value[eoEpot], epot0); prdev[eoEpot] = epot0 - tcr->act_value[eoEpot]; if (bPrint) pr_dev(tcr,t,prdev,cr,nfile,fnm); /* First set all factors to 1 */ for(i=0; (i<atnr2); i++) { f6[i] = f12[i] = fa[i] = fb[i] = fc[i] = 1.0; } for(i=0; (i<idef->atnr); i++) fq[i] = 1.0; /* Now compute the actual coupling compononents */ if (!fr->bBHAM) { if (bDoIt) { for(i=0; (i<tcr->nLJ); i++) { tclj=&(tcr->tcLJ[i]); ati=tclj->at_i; atj=tclj->at_j; ff6 = ff12 = 1.0; if (tclj->eObs == eoForce) { gmx_fatal(FARGS,"Hack code for this to work again "); if (debug) fprintf(debug,"Have computed derivatives: xiH = %g, xiS = %g\n",xiH,xiS); if (ati == 1) { /* Hydrogen */ ff12 += xiH; } else if (ati == 2) { /* Shell */ ff12 += xiS; } else gmx_fatal(FARGS,"No H, no Shell, edit code at %s, line %d\n", __FILE__,__LINE__); if (ff6 > 0) set_factor_matrix(idef->atnr,f6, sqrt(ff6), ati,atj); if (ff12 > 0) set_factor_matrix(idef->atnr,f12,sqrt(ff12),ati,atj); } else { if (debug) fprintf(debug,"tcr->tcLJ[%d].xi_6 = %g, xi_12 = %g deviation = %g\n",i, tclj->xi_6,tclj->xi_12,deviation[tclj->eObs]); factor=deviation[tclj->eObs]; upd_f_value(log,idef->atnr,tclj->xi_6, dt,factor,f6, ati,atj); upd_f_value(log,idef->atnr,tclj->xi_12,dt,factor,f12,ati,atj); } } } if (PAR(cr)) { gprod(cr,atnr2,f6); gprod(cr,atnr2,f12); #ifdef DEBUGGCT dump_fm(log,idef->atnr,f6,"f6"); dump_fm(log,idef->atnr,f12,"f12"); #endif } upd_nbfplj(log,fr->nbfp,idef->atnr,f6,f12,tcr->combrule); /* Copy for printing */ for(i=0; (i<tcr->nLJ); i++) { tclj=&(tcr->tcLJ[i]); ati = tclj->at_i; atj = tclj->at_j; if (atj == -1) atj = ati; tclj->c6 = C6(fr->nbfp,fr->ntype,ati,atj); tclj->c12 = C12(fr->nbfp,fr->ntype,ati,atj); } } else { if (bDoIt) { for(i=0; (i<tcr->nBU); i++) { tcbu = &(tcr->tcBU[i]); factor = deviation[tcbu->eObs]; ati = tcbu->at_i; atj = tcbu->at_j; upd_f_value(log,idef->atnr,tcbu->xi_a,dt,factor,fa,ati,atj); upd_f_value(log,idef->atnr,tcbu->xi_b,dt,factor,fb,ati,atj); upd_f_value(log,idef->atnr,tcbu->xi_c,dt,factor,fc,ati,atj); } } if (PAR(cr)) { gprod(cr,atnr2,fa); gprod(cr,atnr2,fb); gprod(cr,atnr2,fc); } upd_nbfpbu(log,fr->nbfp,idef->atnr,fa,fb,fc); /* Copy for printing */ for(i=0; (i<tcr->nBU); i++) { tcbu=&(tcr->tcBU[i]); ati = tcbu->at_i; atj = tcbu->at_j; if (atj == -1) atj = ati; tcbu->a = BHAMA(fr->nbfp,fr->ntype,ati,atj); tcbu->b = BHAMB(fr->nbfp,fr->ntype,ati,atj); tcbu->c = BHAMC(fr->nbfp,fr->ntype,ati,atj); if (debug) fprintf(debug,"buck (type=%d) = %e, %e, %e\n", tcbu->at_i,tcbu->a,tcbu->b,tcbu->c); } } if (bDoIt) { for(i=0; (i<tcr->nQ); i++) { tcq=&(tcr->tcQ[i]); if (tcq->xi_Q) ffq = 1.0 + (dt/tcq->xi_Q) * deviation[tcq->eObs]; else ffq = 1.0; fq[tcq->at_i] *= ffq; } } if (PAR(cr)) gprod(cr,idef->atnr,fq); for(j=0; (j<md->nr); j++) { md->chargeA[j] *= fq[md->typeA[j]]; } for(i=0; (i<tcr->nQ); i++) { tcq=&(tcr->tcQ[i]); for(j=0; (j<md->nr); j++) { if (md->typeA[j] == tcq->at_i) { tcq->Q = md->chargeA[j]; break; } } if (j == md->nr) gmx_fatal(FARGS,"Coupling type %d not found",tcq->at_i); } for(i=0; (i<tcr->nIP); i++) { tip = &(tcr->tIP[i]); type = tip->type; ftype = idef->functype[type]; factor = dt*deviation[tip->eObs]; switch(ftype) { case F_BONDS: if (tip->xi.harmonic.krA) idef->iparams[type].harmonic.krA *= (1+factor/tip->xi.harmonic.krA); if (tip->xi.harmonic.rA) idef->iparams[type].harmonic.rA *= (1+factor/tip->xi.harmonic.rA); break; default: break; } tip->iprint=idef->iparams[type]; } }
void do_force_lowlevel(FILE *fplog, gmx_large_int_t step, t_forcerec *fr, t_inputrec *ir, t_idef *idef, t_commrec *cr, t_nrnb *nrnb, gmx_wallcycle_t wcycle, t_mdatoms *md, t_grpopts *opts, rvec x[], history_t *hist, rvec f[], rvec f_longrange[], gmx_enerdata_t *enerd, t_fcdata *fcd, gmx_mtop_t *mtop, gmx_localtop_t *top, gmx_genborn_t *born, t_atomtypes *atype, gmx_bool bBornRadii, matrix box, t_lambda *fepvals, real *lambda, t_graph *graph, t_blocka *excl, rvec mu_tot[], int flags, float *cycles_pme) { int i, j, status; int donb_flags; gmx_bool bDoEpot, bSepDVDL, bSB; int pme_flags; matrix boxs; rvec box_size; real Vsr, Vlr, Vcorr = 0; t_pbc pbc; real dvdgb; char buf[22]; double clam_i, vlam_i; real dvdl_dum[efptNR], dvdl, dvdl_nb[efptNR], lam_i[efptNR]; real dvdlsum; #ifdef GMX_MPI double t0 = 0.0, t1, t2, t3; /* time measurement for coarse load balancing */ #endif #define PRINT_SEPDVDL(s, v, dvdlambda) if (bSepDVDL) {fprintf(fplog, sepdvdlformat, s, v, dvdlambda); } GMX_MPE_LOG(ev_force_start); set_pbc(&pbc, fr->ePBC, box); /* reset free energy components */ for (i = 0; i < efptNR; i++) { dvdl_nb[i] = 0; dvdl_dum[i] = 0; } /* Reset box */ for (i = 0; (i < DIM); i++) { box_size[i] = box[i][i]; } bSepDVDL = (fr->bSepDVDL && do_per_step(step, ir->nstlog)); debug_gmx(); /* do QMMM first if requested */ if (fr->bQMMM) { enerd->term[F_EQM] = calculate_QMMM(cr, x, f, fr, md); } if (bSepDVDL) { fprintf(fplog, "Step %s: non-bonded V and dVdl for node %d:\n", gmx_step_str(step, buf), cr->nodeid); } /* Call the short range functions all in one go. */ GMX_MPE_LOG(ev_do_fnbf_start); #ifdef GMX_MPI /*#define TAKETIME ((cr->npmenodes) && (fr->timesteps < 12))*/ #define TAKETIME FALSE if (TAKETIME) { MPI_Barrier(cr->mpi_comm_mygroup); t0 = MPI_Wtime(); } #endif if (ir->nwall) { /* foreign lambda component for walls */ dvdl = do_walls(ir, fr, box, md, x, f, lambda[efptVDW], enerd->grpp.ener[egLJSR], nrnb); PRINT_SEPDVDL("Walls", 0.0, dvdl); enerd->dvdl_lin[efptVDW] += dvdl; } /* If doing GB, reset dvda and calculate the Born radii */ if (ir->implicit_solvent) { wallcycle_sub_start(wcycle, ewcsNONBONDED); for (i = 0; i < born->nr; i++) { fr->dvda[i] = 0; } if (bBornRadii) { calc_gb_rad(cr, fr, ir, top, atype, x, &(fr->gblist), born, md, nrnb); } wallcycle_sub_stop(wcycle, ewcsNONBONDED); } where(); /* We only do non-bonded calculation with group scheme here, the verlet * calls are done from do_force_cutsVERLET(). */ if (fr->cutoff_scheme == ecutsGROUP && (flags & GMX_FORCE_NONBONDED)) { donb_flags = 0; /* Add short-range interactions */ donb_flags |= GMX_NONBONDED_DO_SR; if (flags & GMX_FORCE_FORCES) { donb_flags |= GMX_NONBONDED_DO_FORCE; } if (flags & GMX_FORCE_ENERGY) { donb_flags |= GMX_NONBONDED_DO_POTENTIAL; } if (flags & GMX_FORCE_DO_LR) { donb_flags |= GMX_NONBONDED_DO_LR; } wallcycle_sub_start(wcycle, ewcsNONBONDED); do_nonbonded(cr, fr, x, f, f_longrange, md, excl, &enerd->grpp, box_size, nrnb, lambda, dvdl_nb, -1, -1, donb_flags); /* If we do foreign lambda and we have soft-core interactions * we have to recalculate the (non-linear) energies contributions. */ if (fepvals->n_lambda > 0 && (flags & GMX_FORCE_DHDL) && fepvals->sc_alpha != 0) { for (i = 0; i < enerd->n_lambda; i++) { for (j = 0; j < efptNR; j++) { lam_i[j] = (i == 0 ? lambda[j] : fepvals->all_lambda[j][i-1]); } reset_foreign_enerdata(enerd); do_nonbonded(cr, fr, x, f, f_longrange, md, excl, &(enerd->foreign_grpp), box_size, nrnb, lam_i, dvdl_dum, -1, -1, (donb_flags & ~GMX_NONBONDED_DO_FORCE) | GMX_NONBONDED_DO_FOREIGNLAMBDA); sum_epot(&ir->opts, &(enerd->foreign_grpp), enerd->foreign_term); enerd->enerpart_lambda[i] += enerd->foreign_term[F_EPOT]; } } wallcycle_sub_stop(wcycle, ewcsNONBONDED); where(); } /* If we are doing GB, calculate bonded forces and apply corrections * to the solvation forces */ /* MRS: Eventually, many need to include free energy contribution here! */ if (ir->implicit_solvent) { wallcycle_sub_start(wcycle, ewcsBONDED); calc_gb_forces(cr, md, born, top, atype, x, f, fr, idef, ir->gb_algorithm, ir->sa_algorithm, nrnb, bBornRadii, &pbc, graph, enerd); wallcycle_sub_stop(wcycle, ewcsBONDED); } #ifdef GMX_MPI if (TAKETIME) { t1 = MPI_Wtime(); fr->t_fnbf += t1-t0; } #endif if (fepvals->sc_alpha != 0) { enerd->dvdl_nonlin[efptVDW] += dvdl_nb[efptVDW]; } else { enerd->dvdl_lin[efptVDW] += dvdl_nb[efptVDW]; } if (fepvals->sc_alpha != 0) /* even though coulomb part is linear, we already added it, beacuse we need to go through the vdw calculation anyway */ { enerd->dvdl_nonlin[efptCOUL] += dvdl_nb[efptCOUL]; } else { enerd->dvdl_lin[efptCOUL] += dvdl_nb[efptCOUL]; } Vsr = 0; if (bSepDVDL) { for (i = 0; i < enerd->grpp.nener; i++) { Vsr += (fr->bBHAM ? enerd->grpp.ener[egBHAMSR][i] : enerd->grpp.ener[egLJSR][i]) + enerd->grpp.ener[egCOULSR][i] + enerd->grpp.ener[egGB][i]; } dvdlsum = dvdl_nb[efptVDW] + dvdl_nb[efptCOUL]; PRINT_SEPDVDL("VdW and Coulomb SR particle-p.", Vsr, dvdlsum); } debug_gmx(); GMX_MPE_LOG(ev_do_fnbf_finish); if (debug) { pr_rvecs(debug, 0, "fshift after SR", fr->fshift, SHIFTS); } /* Shift the coordinates. Must be done before bonded forces and PPPM, * but is also necessary for SHAKE and update, therefore it can NOT * go when no bonded forces have to be evaluated. */ /* Here sometimes we would not need to shift with NBFonly, * but we do so anyhow for consistency of the returned coordinates. */ if (graph) { shift_self(graph, box, x); if (TRICLINIC(box)) { inc_nrnb(nrnb, eNR_SHIFTX, 2*graph->nnodes); } else { inc_nrnb(nrnb, eNR_SHIFTX, graph->nnodes); } } /* Check whether we need to do bondeds or correct for exclusions */ if (fr->bMolPBC && ((flags & GMX_FORCE_BONDED) || EEL_RF(fr->eeltype) || EEL_FULL(fr->eeltype))) { /* Since all atoms are in the rectangular or triclinic unit-cell, * only single box vector shifts (2 in x) are required. */ set_pbc_dd(&pbc, fr->ePBC, cr->dd, TRUE, box); } debug_gmx(); if (flags & GMX_FORCE_BONDED) { GMX_MPE_LOG(ev_calc_bonds_start); wallcycle_sub_start(wcycle, ewcsBONDED); calc_bonds(fplog, cr->ms, idef, x, hist, f, fr, &pbc, graph, enerd, nrnb, lambda, md, fcd, DOMAINDECOMP(cr) ? cr->dd->gatindex : NULL, atype, born, flags, fr->bSepDVDL && do_per_step(step, ir->nstlog), step); /* Check if we have to determine energy differences * at foreign lambda's. */ if (fepvals->n_lambda > 0 && (flags & GMX_FORCE_DHDL) && idef->ilsort != ilsortNO_FE) { if (idef->ilsort != ilsortFE_SORTED) { gmx_incons("The bonded interactions are not sorted for free energy"); } for (i = 0; i < enerd->n_lambda; i++) { reset_foreign_enerdata(enerd); for (j = 0; j < efptNR; j++) { lam_i[j] = (i == 0 ? lambda[j] : fepvals->all_lambda[j][i-1]); } calc_bonds_lambda(fplog, idef, x, fr, &pbc, graph, &(enerd->foreign_grpp), enerd->foreign_term, nrnb, lam_i, md, fcd, DOMAINDECOMP(cr) ? cr->dd->gatindex : NULL); sum_epot(&ir->opts, &(enerd->foreign_grpp), enerd->foreign_term); enerd->enerpart_lambda[i] += enerd->foreign_term[F_EPOT]; } } debug_gmx(); GMX_MPE_LOG(ev_calc_bonds_finish); wallcycle_sub_stop(wcycle, ewcsBONDED); } where(); *cycles_pme = 0; if (EEL_FULL(fr->eeltype)) { bSB = (ir->nwall == 2); if (bSB) { copy_mat(box, boxs); svmul(ir->wall_ewald_zfac, boxs[ZZ], boxs[ZZ]); box_size[ZZ] *= ir->wall_ewald_zfac; } clear_mat(fr->vir_el_recip); if (fr->bEwald) { Vcorr = 0; dvdl = 0; /* With the Verlet scheme exclusion forces are calculated * in the non-bonded kernel. */ /* The TPI molecule does not have exclusions with the rest * of the system and no intra-molecular PME grid contributions * will be calculated in gmx_pme_calc_energy. */ if ((ir->cutoff_scheme == ecutsGROUP && fr->n_tpi == 0) || ir->ewald_geometry != eewg3D || ir->epsilon_surface != 0) { int nthreads, t; wallcycle_sub_start(wcycle, ewcsEWALD_CORRECTION); if (fr->n_tpi > 0) { gmx_fatal(FARGS, "TPI with PME currently only works in a 3D geometry with tin-foil boundary conditions"); } nthreads = gmx_omp_nthreads_get(emntBonded); #pragma omp parallel for num_threads(nthreads) schedule(static) for (t = 0; t < nthreads; t++) { int s, e, i; rvec *fnv; tensor *vir; real *Vcorrt, *dvdlt; if (t == 0) { fnv = fr->f_novirsum; vir = &fr->vir_el_recip; Vcorrt = &Vcorr; dvdlt = &dvdl; } else { fnv = fr->f_t[t].f; vir = &fr->f_t[t].vir; Vcorrt = &fr->f_t[t].Vcorr; dvdlt = &fr->f_t[t].dvdl[efptCOUL]; for (i = 0; i < fr->natoms_force; i++) { clear_rvec(fnv[i]); } clear_mat(*vir); } *dvdlt = 0; *Vcorrt = ewald_LRcorrection(fplog, fr->excl_load[t], fr->excl_load[t+1], cr, t, fr, md->chargeA, md->nChargePerturbed ? md->chargeB : NULL, ir->cutoff_scheme != ecutsVERLET, excl, x, bSB ? boxs : box, mu_tot, ir->ewald_geometry, ir->epsilon_surface, fnv, *vir, lambda[efptCOUL], dvdlt); } if (nthreads > 1) { reduce_thread_forces(fr->natoms_force, fr->f_novirsum, fr->vir_el_recip, &Vcorr, efptCOUL, &dvdl, nthreads, fr->f_t); } wallcycle_sub_stop(wcycle, ewcsEWALD_CORRECTION); } if (fr->n_tpi == 0) { Vcorr += ewald_charge_correction(cr, fr, lambda[efptCOUL], box, &dvdl, fr->vir_el_recip); } PRINT_SEPDVDL("Ewald excl./charge/dip. corr.", Vcorr, dvdl); enerd->dvdl_lin[efptCOUL] += dvdl; } status = 0; Vlr = 0; dvdl = 0; switch (fr->eeltype) { case eelPME: case eelPMESWITCH: case eelPMEUSER: case eelPMEUSERSWITCH: case eelP3M_AD: if (cr->duty & DUTY_PME) { assert(fr->n_tpi >= 0); if (fr->n_tpi == 0 || (flags & GMX_FORCE_STATECHANGED)) { pme_flags = GMX_PME_SPREAD_Q | GMX_PME_SOLVE; if (flags & GMX_FORCE_FORCES) { pme_flags |= GMX_PME_CALC_F; } if (flags & (GMX_FORCE_VIRIAL | GMX_FORCE_ENERGY)) { pme_flags |= GMX_PME_CALC_ENER_VIR; } if (fr->n_tpi > 0) { /* We don't calculate f, but we do want the potential */ pme_flags |= GMX_PME_CALC_POT; } wallcycle_start(wcycle, ewcPMEMESH); status = gmx_pme_do(fr->pmedata, md->start, md->homenr - fr->n_tpi, x, fr->f_novirsum, md->chargeA, md->chargeB, bSB ? boxs : box, cr, DOMAINDECOMP(cr) ? dd_pme_maxshift_x(cr->dd) : 0, DOMAINDECOMP(cr) ? dd_pme_maxshift_y(cr->dd) : 0, nrnb, wcycle, fr->vir_el_recip, fr->ewaldcoeff, &Vlr, lambda[efptCOUL], &dvdl, pme_flags); *cycles_pme = wallcycle_stop(wcycle, ewcPMEMESH); /* We should try to do as little computation after * this as possible, because parallel PME synchronizes * the nodes, so we want all load imbalance of the rest * of the force calculation to be before the PME call. * DD load balancing is done on the whole time of * the force call (without PME). */ } if (fr->n_tpi > 0) { /* Determine the PME grid energy of the test molecule * with the PME grid potential of the other charges. */ gmx_pme_calc_energy(fr->pmedata, fr->n_tpi, x + md->homenr - fr->n_tpi, md->chargeA + md->homenr - fr->n_tpi, &Vlr); } PRINT_SEPDVDL("PME mesh", Vlr, dvdl); } break; case eelEWALD: Vlr = do_ewald(fplog, FALSE, ir, x, fr->f_novirsum, md->chargeA, md->chargeB, box_size, cr, md->homenr, fr->vir_el_recip, fr->ewaldcoeff, lambda[efptCOUL], &dvdl, fr->ewald_table); PRINT_SEPDVDL("Ewald long-range", Vlr, dvdl); break; default: gmx_fatal(FARGS, "No such electrostatics method implemented %s", eel_names[fr->eeltype]); } if (status != 0) { gmx_fatal(FARGS, "Error %d in long range electrostatics routine %s", status, EELTYPE(fr->eeltype)); } /* Note that with separate PME nodes we get the real energies later */ enerd->dvdl_lin[efptCOUL] += dvdl; enerd->term[F_COUL_RECIP] = Vlr + Vcorr; if (debug) { fprintf(debug, "Vlr = %g, Vcorr = %g, Vlr_corr = %g\n", Vlr, Vcorr, enerd->term[F_COUL_RECIP]); pr_rvecs(debug, 0, "vir_el_recip after corr", fr->vir_el_recip, DIM); pr_rvecs(debug, 0, "fshift after LR Corrections", fr->fshift, SHIFTS); } } else { if (EEL_RF(fr->eeltype)) { /* With the Verlet scheme exclusion forces are calculated * in the non-bonded kernel. */ if (ir->cutoff_scheme != ecutsVERLET && fr->eeltype != eelRF_NEC) { dvdl = 0; enerd->term[F_RF_EXCL] = RF_excl_correction(fplog, fr, graph, md, excl, x, f, fr->fshift, &pbc, lambda[efptCOUL], &dvdl); } enerd->dvdl_lin[efptCOUL] += dvdl; PRINT_SEPDVDL("RF exclusion correction", enerd->term[F_RF_EXCL], dvdl); } } where(); debug_gmx(); if (debug) { print_nrnb(debug, nrnb); } debug_gmx(); #ifdef GMX_MPI if (TAKETIME) { t2 = MPI_Wtime(); MPI_Barrier(cr->mpi_comm_mygroup); t3 = MPI_Wtime(); fr->t_wait += t3-t2; if (fr->timesteps == 11) { fprintf(stderr, "* PP load balancing info: node %d, step %s, rel wait time=%3.0f%% , load string value: %7.2f\n", cr->nodeid, gmx_step_str(fr->timesteps, buf), 100*fr->t_wait/(fr->t_wait+fr->t_fnbf), (fr->t_fnbf+fr->t_wait)/fr->t_fnbf); } fr->timesteps++; } #endif if (debug) { pr_rvecs(debug, 0, "fshift after bondeds", fr->fshift, SHIFTS); } GMX_MPE_LOG(ev_force_finish); }
void do_force_lowlevel(FILE *fplog, gmx_large_int_t step, t_forcerec *fr, t_inputrec *ir, t_idef *idef, t_commrec *cr, t_nrnb *nrnb, gmx_wallcycle_t wcycle, t_mdatoms *md, t_grpopts *opts, rvec x[], history_t *hist, rvec f[], gmx_enerdata_t *enerd, t_fcdata *fcd, gmx_mtop_t *mtop, gmx_localtop_t *top, gmx_genborn_t *born, t_atomtypes *atype, gmx_bool bBornRadii, matrix box, real lambda, t_graph *graph, t_blocka *excl, rvec mu_tot[], int flags, float *cycles_pme) { int i,status; int donb_flags; gmx_bool bDoEpot,bSepDVDL,bSB; int pme_flags; matrix boxs; rvec box_size; real dvdlambda,Vsr,Vlr,Vcorr=0,vdip,vcharge; t_pbc pbc; real dvdgb; char buf[22]; gmx_enerdata_t ed_lam; double lam_i; real dvdl_dum; #ifdef GMX_MPI double t0=0.0,t1,t2,t3; /* time measurement for coarse load balancing */ #endif #define PRINT_SEPDVDL(s,v,dvdl) if (bSepDVDL) fprintf(fplog,sepdvdlformat,s,v,dvdl); GMX_MPE_LOG(ev_force_start); set_pbc(&pbc,fr->ePBC,box); /* Reset box */ for(i=0; (i<DIM); i++) { box_size[i]=box[i][i]; } bSepDVDL=(fr->bSepDVDL && do_per_step(step,ir->nstlog)); debug_gmx(); /* do QMMM first if requested */ if(fr->bQMMM) { enerd->term[F_EQM] = calculate_QMMM(cr,x,f,fr,md); } if (bSepDVDL) { fprintf(fplog,"Step %s: non-bonded V and dVdl for node %d:\n", gmx_step_str(step,buf),cr->nodeid); } /* Call the short range functions all in one go. */ GMX_MPE_LOG(ev_do_fnbf_start); dvdlambda = 0; #ifdef GMX_MPI /*#define TAKETIME ((cr->npmenodes) && (fr->timesteps < 12))*/ #define TAKETIME FALSE if (TAKETIME) { MPI_Barrier(cr->mpi_comm_mygroup); t0=MPI_Wtime(); } #endif if (ir->nwall) { dvdlambda = do_walls(ir,fr,box,md,x,f,lambda, enerd->grpp.ener[egLJSR],nrnb); PRINT_SEPDVDL("Walls",0.0,dvdlambda); enerd->dvdl_lin += dvdlambda; } /* If doing GB, reset dvda and calculate the Born radii */ if (ir->implicit_solvent) { /* wallcycle_start(wcycle,ewcGB); */ for(i=0; i<born->nr; i++) { fr->dvda[i]=0; } if(bBornRadii) { calc_gb_rad(cr,fr,ir,top,atype,x,&(fr->gblist),born,md,nrnb); } /* wallcycle_stop(wcycle, ewcGB); */ } where(); donb_flags = 0; if (flags & GMX_FORCE_FORCES) { donb_flags |= GMX_DONB_FORCES; } do_nonbonded(cr,fr,x,f,md,excl, fr->bBHAM ? enerd->grpp.ener[egBHAMSR] : enerd->grpp.ener[egLJSR], enerd->grpp.ener[egCOULSR], enerd->grpp.ener[egGB],box_size,nrnb, lambda,&dvdlambda,-1,-1,donb_flags); /* If we do foreign lambda and we have soft-core interactions * we have to recalculate the (non-linear) energies contributions. */ if (ir->n_flambda > 0 && (flags & GMX_FORCE_DHDL) && ir->sc_alpha != 0) { init_enerdata(mtop->groups.grps[egcENER].nr,ir->n_flambda,&ed_lam); for(i=0; i<enerd->n_lambda; i++) { lam_i = (i==0 ? lambda : ir->flambda[i-1]); dvdl_dum = 0; reset_enerdata(&ir->opts,fr,TRUE,&ed_lam,FALSE); do_nonbonded(cr,fr,x,f,md,excl, fr->bBHAM ? ed_lam.grpp.ener[egBHAMSR] : ed_lam.grpp.ener[egLJSR], ed_lam.grpp.ener[egCOULSR], enerd->grpp.ener[egGB], box_size,nrnb, lam_i,&dvdl_dum,-1,-1, GMX_DONB_FOREIGNLAMBDA); sum_epot(&ir->opts,&ed_lam); enerd->enerpart_lambda[i] += ed_lam.term[F_EPOT]; } destroy_enerdata(&ed_lam); } where(); /* If we are doing GB, calculate bonded forces and apply corrections * to the solvation forces */ if (ir->implicit_solvent) { calc_gb_forces(cr,md,born,top,atype,x,f,fr,idef, ir->gb_algorithm,ir->sa_algorithm,nrnb,bBornRadii,&pbc,graph,enerd); } #ifdef GMX_MPI if (TAKETIME) { t1=MPI_Wtime(); fr->t_fnbf += t1-t0; } #endif if (ir->sc_alpha != 0) { enerd->dvdl_nonlin += dvdlambda; } else { enerd->dvdl_lin += dvdlambda; } Vsr = 0; if (bSepDVDL) { for(i=0; i<enerd->grpp.nener; i++) { Vsr += (fr->bBHAM ? enerd->grpp.ener[egBHAMSR][i] : enerd->grpp.ener[egLJSR][i]) + enerd->grpp.ener[egCOULSR][i] + enerd->grpp.ener[egGB][i]; } } PRINT_SEPDVDL("VdW and Coulomb SR particle-p.",Vsr,dvdlambda); debug_gmx(); GMX_MPE_LOG(ev_do_fnbf_finish); if (debug) { pr_rvecs(debug,0,"fshift after SR",fr->fshift,SHIFTS); } /* Shift the coordinates. Must be done before bonded forces and PPPM, * but is also necessary for SHAKE and update, therefore it can NOT * go when no bonded forces have to be evaluated. */ /* Here sometimes we would not need to shift with NBFonly, * but we do so anyhow for consistency of the returned coordinates. */ if (graph) { shift_self(graph,box,x); if (TRICLINIC(box)) { inc_nrnb(nrnb,eNR_SHIFTX,2*graph->nnodes); } else { inc_nrnb(nrnb,eNR_SHIFTX,graph->nnodes); } } /* Check whether we need to do bondeds or correct for exclusions */ if (fr->bMolPBC && ((flags & GMX_FORCE_BONDED) || EEL_RF(fr->eeltype) || EEL_FULL(fr->eeltype))) { /* Since all atoms are in the rectangular or triclinic unit-cell, * only single box vector shifts (2 in x) are required. */ set_pbc_dd(&pbc,fr->ePBC,cr->dd,TRUE,box); } debug_gmx(); if (flags & GMX_FORCE_BONDED) { GMX_MPE_LOG(ev_calc_bonds_start); calc_bonds(fplog,cr->ms, idef,x,hist,f,fr,&pbc,graph,enerd,nrnb,lambda,md,fcd, DOMAINDECOMP(cr) ? cr->dd->gatindex : NULL, atype, born, fr->bSepDVDL && do_per_step(step,ir->nstlog),step); /* Check if we have to determine energy differences * at foreign lambda's. */ if (ir->n_flambda > 0 && (flags & GMX_FORCE_DHDL) && idef->ilsort != ilsortNO_FE) { if (idef->ilsort != ilsortFE_SORTED) { gmx_incons("The bonded interactions are not sorted for free energy"); } init_enerdata(mtop->groups.grps[egcENER].nr,ir->n_flambda,&ed_lam); for(i=0; i<enerd->n_lambda; i++) { lam_i = (i==0 ? lambda : ir->flambda[i-1]); dvdl_dum = 0; reset_enerdata(&ir->opts,fr,TRUE,&ed_lam,FALSE); calc_bonds_lambda(fplog, idef,x,fr,&pbc,graph,&ed_lam,nrnb,lam_i,md, fcd, DOMAINDECOMP(cr) ? cr->dd->gatindex : NULL); sum_epot(&ir->opts,&ed_lam); enerd->enerpart_lambda[i] += ed_lam.term[F_EPOT]; } destroy_enerdata(&ed_lam); } debug_gmx(); GMX_MPE_LOG(ev_calc_bonds_finish); } where(); *cycles_pme = 0; if (EEL_FULL(fr->eeltype)) { bSB = (ir->nwall == 2); if (bSB) { copy_mat(box,boxs); svmul(ir->wall_ewald_zfac,boxs[ZZ],boxs[ZZ]); box_size[ZZ] *= ir->wall_ewald_zfac; } clear_mat(fr->vir_el_recip); if (fr->bEwald) { if (fr->n_tpi == 0) { dvdlambda = 0; Vcorr = ewald_LRcorrection(fplog,md->start,md->start+md->homenr, cr,fr, md->chargeA, md->nChargePerturbed ? md->chargeB : NULL, excl,x,bSB ? boxs : box,mu_tot, ir->ewald_geometry, ir->epsilon_surface, lambda,&dvdlambda,&vdip,&vcharge); PRINT_SEPDVDL("Ewald excl./charge/dip. corr.",Vcorr,dvdlambda); enerd->dvdl_lin += dvdlambda; } else { if (ir->ewald_geometry != eewg3D || ir->epsilon_surface != 0) { gmx_fatal(FARGS,"TPI with PME currently only works in a 3D geometry with tin-foil boundary conditions"); } /* The TPI molecule does not have exclusions with the rest * of the system and no intra-molecular PME grid contributions * will be calculated in gmx_pme_calc_energy. */ Vcorr = 0; } } else { Vcorr = shift_LRcorrection(fplog,md->start,md->homenr,cr,fr, md->chargeA,excl,x,TRUE,box, fr->vir_el_recip); } dvdlambda = 0; status = 0; switch (fr->eeltype) { case eelPPPM: status = gmx_pppm_do(fplog,fr->pmedata,FALSE,x,fr->f_novirsum, md->chargeA, box_size,fr->phi,cr,md->start,md->homenr, nrnb,ir->pme_order,&Vlr); break; case eelPME: case eelPMESWITCH: case eelPMEUSER: case eelPMEUSERSWITCH: if (cr->duty & DUTY_PME) { if (fr->n_tpi == 0 || (flags & GMX_FORCE_STATECHANGED)) { pme_flags = GMX_PME_SPREAD_Q | GMX_PME_SOLVE; if (flags & GMX_FORCE_FORCES) { pme_flags |= GMX_PME_CALC_F; } if (flags & GMX_FORCE_VIRIAL) { pme_flags |= GMX_PME_CALC_ENER_VIR; } if (fr->n_tpi > 0) { /* We don't calculate f, but we do want the potential */ pme_flags |= GMX_PME_CALC_POT; } wallcycle_start(wcycle,ewcPMEMESH); status = gmx_pme_do(fr->pmedata, md->start,md->homenr - fr->n_tpi, x,fr->f_novirsum, md->chargeA,md->chargeB, bSB ? boxs : box,cr, DOMAINDECOMP(cr) ? dd_pme_maxshift_x(cr->dd) : 0, DOMAINDECOMP(cr) ? dd_pme_maxshift_y(cr->dd) : 0, nrnb,wcycle, fr->vir_el_recip,fr->ewaldcoeff, &Vlr,lambda,&dvdlambda, pme_flags); *cycles_pme = wallcycle_stop(wcycle,ewcPMEMESH); /* We should try to do as little computation after * this as possible, because parallel PME synchronizes * the nodes, so we want all load imbalance of the rest * of the force calculation to be before the PME call. * DD load balancing is done on the whole time of * the force call (without PME). */ } if (fr->n_tpi > 0) { /* Determine the PME grid energy of the test molecule * with the PME grid potential of the other charges. */ gmx_pme_calc_energy(fr->pmedata,fr->n_tpi, x + md->homenr - fr->n_tpi, md->chargeA + md->homenr - fr->n_tpi, &Vlr); } PRINT_SEPDVDL("PME mesh",Vlr,dvdlambda); } else { /* Energies and virial are obtained later from the PME nodes */ /* but values have to be zeroed out here */ Vlr=0.0; } break; case eelEWALD: Vlr = do_ewald(fplog,FALSE,ir,x,fr->f_novirsum, md->chargeA,md->chargeB, box_size,cr,md->homenr, fr->vir_el_recip,fr->ewaldcoeff, lambda,&dvdlambda,fr->ewald_table); PRINT_SEPDVDL("Ewald long-range",Vlr,dvdlambda); break; default: Vlr = 0; gmx_fatal(FARGS,"No such electrostatics method implemented %s", eel_names[fr->eeltype]); } if (status != 0) { gmx_fatal(FARGS,"Error %d in long range electrostatics routine %s", status,EELTYPE(fr->eeltype)); } enerd->dvdl_lin += dvdlambda; enerd->term[F_COUL_RECIP] = Vlr + Vcorr; if (debug) { fprintf(debug,"Vlr = %g, Vcorr = %g, Vlr_corr = %g\n", Vlr,Vcorr,enerd->term[F_COUL_RECIP]); pr_rvecs(debug,0,"vir_el_recip after corr",fr->vir_el_recip,DIM); pr_rvecs(debug,0,"fshift after LR Corrections",fr->fshift,SHIFTS); } } else { if (EEL_RF(fr->eeltype)) { dvdlambda = 0; if (fr->eeltype != eelRF_NEC) { enerd->term[F_RF_EXCL] = RF_excl_correction(fplog,fr,graph,md,excl,x,f, fr->fshift,&pbc,lambda,&dvdlambda); } enerd->dvdl_lin += dvdlambda; PRINT_SEPDVDL("RF exclusion correction", enerd->term[F_RF_EXCL],dvdlambda); } } where(); debug_gmx(); if (debug) { print_nrnb(debug,nrnb); } debug_gmx(); #ifdef GMX_MPI if (TAKETIME) { t2=MPI_Wtime(); MPI_Barrier(cr->mpi_comm_mygroup); t3=MPI_Wtime(); fr->t_wait += t3-t2; if (fr->timesteps == 11) { fprintf(stderr,"* PP load balancing info: node %d, step %s, rel wait time=%3.0f%% , load string value: %7.2f\n", cr->nodeid, gmx_step_str(fr->timesteps,buf), 100*fr->t_wait/(fr->t_wait+fr->t_fnbf), (fr->t_fnbf+fr->t_wait)/fr->t_fnbf); } fr->timesteps++; } #endif if (debug) { pr_rvecs(debug,0,"fshift after bondeds",fr->fshift,SHIFTS); } GMX_MPE_LOG(ev_force_finish); }
static bool constrain_lincs(FILE *log,t_topology *top,t_inputrec *ir, int step,t_mdatoms *md,int start,int homenr, int *nbl,int **sbl, rvec *x,rvec *xprime,rvec *min_proj,matrix box, real lambda,real *dvdlambda,bool bCoordinates, bool bInit,t_nrnb *nrnb,bool bDumpOnError) { static int *bla1,*bla2,*blnr,*blbnb,nrtot=0; static rvec *r; static real *bllen,*blc,*blcc,*blm,*tmp1,*tmp2,*tmp3,*lincslam, *bllen0,*ddist; static int nc; static bool bItEqOrder; char buf[STRLEN]; int b,i,j,nit,warn,p_imax,error; real wang,p_max,p_rms; real dt,dt_2; bool bOK; bOK = TRUE; if (bInit) { nc = top->idef.il[F_SHAKE].nr/3; init_lincs(stdlog,top,ir,md,start,homenr, &nrtot, &r,&bla1,&bla2,&blnr,&blbnb, &bllen,&blc,&blcc,&blm,&tmp1,&tmp2,&tmp3,&lincslam, &bllen0,&ddist); #ifdef SPEC_CPU bItEqOrder = FALSE; #else bItEqOrder = (getenv("GMX_ACCURATE_LINCS") != NULL); #endif } else if (nc != 0) { /* If there are any constraints */ if (bCoordinates) { dt = ir->delta_t; dt_2 = 1.0/(dt*dt); if (ir->efep != efepNO) for(i=0;i<nc;i++) bllen[i]=bllen0[i]+lambda*ddist[i]; /* Set the zero lengths to the old lengths */ for(b=0; b<nc; b++) if (bllen0[b]<GMX_REAL_MIN) { i = bla1[b]; j = bla2[b]; bllen[b] = sqrt(sqr(x[i][XX]-x[j][XX])+ sqr(x[i][YY]-x[j][YY])+ sqr(x[i][ZZ]-x[j][ZZ])); } wang=ir->LincsWarnAngle; if (do_per_step(step,ir->nstlog) || step<0) cconerr(&p_max,&p_rms,&p_imax,xprime,nc,bla1,bla2,bllen); if ((ir->eI == eiSteep) || (ir->eI == eiCG) || bItEqOrder) /* Use more iterations when doing energy minimization, * * because we need very accurate positions and forces. */ nit = ir->nProjOrder; else nit = 1; #ifdef USE_FORTRAN #ifdef DOUBLE F77_FUNC(flincsd,FLINCSD)(x[0],xprime[0],&nc,bla1,bla2,blnr,blbnb, bllen,blc,blcc,blm,&nit,&ir->nProjOrder, md->invmass,r[0],tmp1,tmp2,tmp3,&wang,&warn, lincslam); #else F77_FUNC(flincs,FLINCS)(x[0],xprime[0],&nc,bla1,bla2,blnr,blbnb, bllen,blc,blcc,blm,&nit,&ir->nProjOrder, md->invmass,r[0],tmp1,tmp2,tmp3,&wang,&warn, lincslam); #endif #else clincs(x,xprime,nc,bla1,bla2,blnr,blbnb, bllen,blc,blcc,blm,nit,ir->nProjOrder, md->invmass,r,tmp1,tmp2,tmp3,wang,&warn,lincslam); #endif if (ir->efep != efepNO) { real dvdl=0; for(i=0; (i<nc); i++) dvdl+=lincslam[i]*dt_2*ddist[i]; *dvdlambda+=dvdl; } if(stdlog) { if (do_per_step(step,ir->nstlog) || (step<0)) { fprintf(stdlog," Rel. Constraint Deviation: Max between atoms RMS\n"); fprintf(stdlog," Before LINCS %.6f %6d %6d %.6f\n", p_max,bla1[p_imax]+1,bla2[p_imax]+1,p_rms); cconerr(&p_max,&p_rms,&p_imax,xprime,nc,bla1,bla2,bllen); fprintf(stdlog," After LINCS %.6f %6d %6d %.6f\n\n", p_max,bla1[p_imax]+1,bla2[p_imax]+1,p_rms); } } if (warn > 0) { if (bDumpOnError && stdlog) { cconerr(&p_max,&p_rms,&p_imax,xprime,nc,bla1,bla2,bllen); sprintf(buf,"\nStep %d, time %g (ps) LINCS WARNING\n" "relative constraint deviation after LINCS:\n" "max %.6f (between atoms %d and %d) rms %.6f\n", step,ir->init_t+step*ir->delta_t, p_max,bla1[p_imax]+1,bla2[p_imax]+1,p_rms); fprintf(stdlog,"%s",buf); fprintf(stderr,"%s",buf); lincs_warning(x,xprime,nc,bla1,bla2,bllen,wang); } bOK = (p_max < 0.5); } for(b=0; (b<nc); b++) if (bllen0[b] < GMX_REAL_MIN) bllen[b] = 0; } else { #ifdef USE_FORTRAN #ifdef DOUBLE F77_FUNC(flincspd,FLINCSPD)(x[0],xprime[0],min_proj[0],&nc,bla1,bla2,blnr,blbnb, blc,blcc,blm,&ir->nProjOrder, md->invmass,r[0],tmp1,tmp2,tmp3); #else F77_FUNC(flincsp,FLINCSP)(x[0],xprime[0],min_proj[0],&nc,bla1,bla2,blnr,blbnb, blc,blcc,blm,&ir->nProjOrder, md->invmass,r[0],tmp1,tmp2,tmp3); #endif #else clincsp(x,xprime,min_proj,nc,bla1,bla2,blnr,blbnb, blc,blcc,blm,ir->nProjOrder, md->invmass,r,tmp1,tmp2,tmp3); #endif } /* count assuming nit=1 */ inc_nrnb(nrnb,eNR_LINCS,nc); inc_nrnb(nrnb,eNR_LINCSMAT,(2+ir->nProjOrder)*nrtot); } return bOK; }
void calc_dispcorr(FILE *fplog,t_inputrec *ir,t_forcerec *fr,int step, int natoms,matrix box,real lambda, tensor pres,tensor virial,real ener[]) { static bool bFirst=TRUE; bool bCorrAll,bCorrPres; real dvdlambda,invvol,dens,ninter,avcsix,avctwelve,enerdiff,svir=0,spres=0; int m; ener[F_DISPCORR] = 0.0; if (ir->eDispCorr != edispcNO) { bCorrAll = (ir->eDispCorr == edispcAllEner || ir->eDispCorr == edispcAllEnerPres); bCorrPres = (ir->eDispCorr == edispcEnerPres || ir->eDispCorr == edispcAllEnerPres); if (bFirst) calc_enervirdiff(fplog,ir->eDispCorr,fr); invvol = 1/det(box); if (fr->n_tpi) { /* Only correct for the interactions with the inserted molecule */ dens = (natoms - fr->n_tpi)*invvol; ninter = fr->n_tpi; } else { dens = natoms*invvol; ninter = 0.5*natoms; } if (ir->efep == efepNO) { avcsix = fr->avcsix[0]; avctwelve = fr->avctwelve[0]; } else { avcsix = (1 - lambda)*fr->avcsix[0] + lambda*fr->avcsix[1]; avctwelve = (1 - lambda)*fr->avctwelve[0] + lambda*fr->avctwelve[1]; } enerdiff = ninter*(dens*fr->enerdiffsix - fr->enershiftsix); ener[F_DISPCORR] += avcsix*enerdiff; dvdlambda = 0.0; if (ir->efep != efepNO) dvdlambda += (fr->avcsix[1] - fr->avcsix[0])*enerdiff; if (bCorrAll) { enerdiff = ninter*(dens*fr->enerdifftwelve - fr->enershifttwelve); ener[F_DISPCORR] += avctwelve*enerdiff; if (fr->efep != efepNO) dvdlambda += (fr->avctwelve[1] - fr->avctwelve[0])*enerdiff; } if (bCorrPres) { svir = ninter*dens*avcsix*fr->virdiffsix/3.0; if (ir->eDispCorr == edispcAllEnerPres) svir += ninter*dens*avctwelve*fr->virdifftwelve/3.0; /* The factor 2 is because of the Gromacs virial definition */ spres = -2.0*invvol*svir*PRESFAC; for(m=0; m<DIM; m++) { virial[m][m] += svir; pres[m][m] += spres; } ener[F_PRES] += spres; } if (bFirst && fplog) { if (bCorrAll) fprintf(fplog,"Long Range LJ corr.: <C6> %10.4e, <C12> %10.4e\n", avcsix,avctwelve); else fprintf(fplog,"Long Range LJ corr.: <C6> %10.4e\n",avcsix); if (bCorrPres) fprintf(fplog, "Long Range LJ corr.: Epot %10g, Pres: %10g, Vir: %10g\n", ener[F_DISPCORR],spres,svir); else fprintf(fplog,"Long Range LJ corr.: Epot %10g\n",ener[F_DISPCORR]); } bFirst = FALSE; if (fr->bSepDVDL && do_per_step(step,ir->nstlog)) fprintf(fplog,sepdvdlformat,"Dispersion correction", ener[F_DISPCORR],dvdlambda); ener[F_EPOT] += ener[F_DISPCORR]; if (fr->efep != efepNO) ener[F_DVDL] += dvdlambda; } }
void do_force(FILE *fplog,t_commrec *cr, t_inputrec *inputrec, int step,t_nrnb *nrnb,gmx_wallcycle_t wcycle, gmx_localtop_t *top, gmx_groups_t *groups, matrix box,rvec x[],history_t *hist, rvec f[],rvec buf[], tensor vir_force, t_mdatoms *mdatoms, gmx_enerdata_t *enerd,t_fcdata *fcd, real lambda,t_graph *graph, t_forcerec *fr,gmx_vsite_t *vsite,rvec mu_tot, real t,FILE *field,gmx_edsam_t ed, int flags) { static rvec box_size; int cg0,cg1,i,j; int start,homenr; static double mu[2*DIM]; rvec mu_tot_AB[2]; bool bSepDVDL,bStateChanged,bNS,bFillGrid,bCalcCGCM,bBS,bDoForces; matrix boxs; real e,v,dvdl; t_pbc pbc; float cycles_ppdpme,cycles_pme,cycles_force; start = mdatoms->start; homenr = mdatoms->homenr; bSepDVDL = (fr->bSepDVDL && do_per_step(step,inputrec->nstlog)); clear_mat(vir_force); if (PARTDECOMP(cr)) { pd_cg_range(cr,&cg0,&cg1); } else { cg0 = 0; if (DOMAINDECOMP(cr)) cg1 = cr->dd->ncg_tot; else cg1 = top->cgs.nr; if (fr->n_tpi > 0) cg1--; } bStateChanged = (flags & GMX_FORCE_STATECHANGED); bNS = (flags & GMX_FORCE_NS); bFillGrid = (bNS && bStateChanged); bCalcCGCM = (bFillGrid && !DOMAINDECOMP(cr)); bDoForces = (flags & GMX_FORCE_FORCES); if (bStateChanged) { update_forcerec(fplog,fr,box); /* Calculate total (local) dipole moment in a temporary common array. * This makes it possible to sum them over nodes faster. */ calc_mu(start,homenr, x,mdatoms->chargeA,mdatoms->chargeB,mdatoms->nChargePerturbed, mu,mu+DIM); } if (fr->ePBC != epbcNONE) { /* Compute shift vectors every step, * because of pressure coupling or box deformation! */ if (DYNAMIC_BOX(*inputrec) && bStateChanged) calc_shifts(box,fr->shift_vec); if (bCalcCGCM) { put_charge_groups_in_box(fplog,cg0,cg1,fr->ePBC,box, &(top->cgs),x,fr->cg_cm); inc_nrnb(nrnb,eNR_CGCM,homenr); inc_nrnb(nrnb,eNR_RESETX,cg1-cg0); } else if (EI_ENERGY_MINIMIZATION(inputrec->eI) && graph) { unshift_self(graph,box,x); } } else if (bCalcCGCM) { calc_cgcm(fplog,cg0,cg1,&(top->cgs),x,fr->cg_cm); inc_nrnb(nrnb,eNR_CGCM,homenr); } if (bCalcCGCM) { if (PAR(cr)) { move_cgcm(fplog,cr,fr->cg_cm); } if (gmx_debug_at) pr_rvecs(debug,0,"cgcm",fr->cg_cm,top->cgs.nr); } #ifdef GMX_MPI if (!(cr->duty & DUTY_PME)) { /* Send particle coordinates to the pme nodes. * Since this is only implemented for domain decomposition * and domain decomposition does not use the graph, * we do not need to worry about shifting. */ wallcycle_start(wcycle,ewcPP_PMESENDX); GMX_MPE_LOG(ev_send_coordinates_start); bBS = (inputrec->nwall == 2); if (bBS) { copy_mat(box,boxs); svmul(inputrec->wall_ewald_zfac,boxs[ZZ],boxs[ZZ]); } gmx_pme_send_x(cr,bBS ? boxs : box,x,mdatoms->nChargePerturbed,lambda); GMX_MPE_LOG(ev_send_coordinates_finish); wallcycle_stop(wcycle,ewcPP_PMESENDX); } #endif /* GMX_MPI */ /* Communicate coordinates and sum dipole if necessary */ if (PAR(cr)) { wallcycle_start(wcycle,ewcMOVEX); if (DOMAINDECOMP(cr)) { dd_move_x(cr->dd,box,x,buf); } else { move_x(fplog,cr,GMX_LEFT,GMX_RIGHT,x,nrnb); } /* When we don't need the total dipole we sum it in global_stat */ if (NEED_MUTOT(*inputrec)) gmx_sumd(2*DIM,mu,cr); wallcycle_stop(wcycle,ewcMOVEX); } for(i=0; i<2; i++) for(j=0;j<DIM;j++) mu_tot_AB[i][j] = mu[i*DIM + j]; if (fr->efep == efepNO) copy_rvec(mu_tot_AB[0],mu_tot); else for(j=0; j<DIM; j++) mu_tot[j] = (1.0 - lambda)*mu_tot_AB[0][j] + lambda*mu_tot_AB[1][j]; /* Reset energies */ reset_energies(&(inputrec->opts),fr,bNS,enerd,MASTER(cr)); if (bNS) { wallcycle_start(wcycle,ewcNS); if (graph && bStateChanged) /* Calculate intramolecular shift vectors to make molecules whole */ mk_mshift(fplog,graph,fr->ePBC,box,x); /* Reset long range forces if necessary */ if (fr->bTwinRange) { clear_rvecs(fr->f_twin_n,fr->f_twin); clear_rvecs(SHIFTS,fr->fshift_twin); } /* Do the actual neighbour searching and if twin range electrostatics * also do the calculation of long range forces and energies. */ dvdl = 0; ns(fplog,fr,x,f,box,groups,&(inputrec->opts),top,mdatoms, cr,nrnb,step,lambda,&dvdl,&enerd->grpp,bFillGrid,bDoForces); if (bSepDVDL) fprintf(fplog,sepdvdlformat,"LR non-bonded",0,dvdl); enerd->dvdl_lr = dvdl; enerd->term[F_DVDL] += dvdl; wallcycle_stop(wcycle,ewcNS); } if (DOMAINDECOMP(cr)) { if (!(cr->duty & DUTY_PME)) { wallcycle_start(wcycle,ewcPPDURINGPME); dd_force_flop_start(cr->dd,nrnb); } } /* Start the force cycle counter. * This counter is stopped in do_forcelow_level. * No parallel communication should occur while this counter is running, * since that will interfere with the dynamic load balancing. */ wallcycle_start(wcycle,ewcFORCE); if (bDoForces) { /* Reset PME/Ewald forces if necessary */ if (fr->bF_NoVirSum) { GMX_BARRIER(cr->mpi_comm_mygroup); if (fr->bDomDec) clear_rvecs(fr->f_novirsum_n,fr->f_novirsum); else clear_rvecs(homenr,fr->f_novirsum+start); GMX_BARRIER(cr->mpi_comm_mygroup); } /* Copy long range forces into normal buffers */ if (fr->bTwinRange) { for(i=0; i<fr->f_twin_n; i++) copy_rvec(fr->f_twin[i],f[i]); for(i=0; i<SHIFTS; i++) copy_rvec(fr->fshift_twin[i],fr->fshift[i]); } else { if (DOMAINDECOMP(cr)) clear_rvecs(cr->dd->nat_tot,f); else clear_rvecs(mdatoms->nr,f); clear_rvecs(SHIFTS,fr->fshift); } clear_rvec(fr->vir_diag_posres); GMX_BARRIER(cr->mpi_comm_mygroup); } if (inputrec->ePull == epullCONSTRAINT) clear_pull_forces(inputrec->pull); /* update QMMMrec, if necessary */ if(fr->bQMMM) update_QMMMrec(cr,fr,x,mdatoms,box,top); if ((flags & GMX_FORCE_BONDED) && top->idef.il[F_POSRES].nr > 0) { /* Position restraints always require full pbc */ set_pbc(&pbc,inputrec->ePBC,box); v = posres(top->idef.il[F_POSRES].nr,top->idef.il[F_POSRES].iatoms, top->idef.iparams_posres, (const rvec*)x,fr->f_novirsum,fr->vir_diag_posres, inputrec->ePBC==epbcNONE ? NULL : &pbc,lambda,&dvdl, fr->rc_scaling,fr->ePBC,fr->posres_com,fr->posres_comB); if (bSepDVDL) { fprintf(fplog,sepdvdlformat, interaction_function[F_POSRES].longname,v,dvdl); } enerd->term[F_POSRES] += v; enerd->term[F_DVDL] += dvdl; inc_nrnb(nrnb,eNR_POSRES,top->idef.il[F_POSRES].nr/2); } /* Compute the bonded and non-bonded forces */ do_force_lowlevel(fplog,step,fr,inputrec,&(top->idef), cr,nrnb,wcycle,mdatoms,&(inputrec->opts), x,hist,f,enerd,fcd,box,lambda,graph,&(top->excls),mu_tot_AB, flags,&cycles_force); GMX_BARRIER(cr->mpi_comm_mygroup); if (ed) { do_flood(fplog,cr,x,f,ed,box,step); } if (DOMAINDECOMP(cr)) { dd_force_flop_stop(cr->dd,nrnb); if (wcycle) dd_cycles_add(cr->dd,cycles_force,ddCyclF); } if (bDoForces) { /* Compute forces due to electric field */ calc_f_el(MASTER(cr) ? field : NULL, start,homenr,mdatoms->chargeA,x,f,inputrec->ex,inputrec->et,t); /* When using PME/Ewald we compute the long range virial there. * otherwise we do it based on long range forces from twin range * cut-off based calculation (or not at all). */ /* Communicate the forces */ if (PAR(cr)) { wallcycle_start(wcycle,ewcMOVEF); if (DOMAINDECOMP(cr)) { dd_move_f(cr->dd,f,buf,fr->fshift); /* Position restraint do not introduce inter-cg forces */ if (EEL_FULL(fr->eeltype) && cr->dd->n_intercg_excl) dd_move_f(cr->dd,fr->f_novirsum,buf,NULL); } else { move_f(fplog,cr,GMX_LEFT,GMX_RIGHT,f,buf,nrnb); } wallcycle_stop(wcycle,ewcMOVEF); } } if (bDoForces) { if (vsite) { wallcycle_start(wcycle,ewcVSITESPREAD); spread_vsite_f(fplog,vsite,x,f,fr->fshift,nrnb, &top->idef,fr->ePBC,fr->bMolPBC,graph,box,cr); wallcycle_stop(wcycle,ewcVSITESPREAD); } /* Calculation of the virial must be done after vsites! */ calc_virial(fplog,mdatoms->start,mdatoms->homenr,x,f, vir_force,graph,box,nrnb,fr,inputrec->ePBC); } if (inputrec->ePull == epullUMBRELLA || inputrec->ePull == epullCONST_F) { /* Calculate the center of mass forces, this requires communication, * which is why pull_potential is called close to other communication. * The virial contribution is calculated directly, * which is why we call pull_potential after calc_virial. */ set_pbc(&pbc,inputrec->ePBC,box); dvdl = 0; enerd->term[F_COM_PULL] = pull_potential(inputrec->ePull,inputrec->pull,mdatoms,&pbc, cr,t,lambda,x,f,vir_force,&dvdl); if (bSepDVDL) fprintf(fplog,sepdvdlformat,"Com pull",enerd->term[F_COM_PULL],dvdl); enerd->term[F_DVDL] += dvdl; } if (!(cr->duty & DUTY_PME)) { cycles_ppdpme = wallcycle_stop(wcycle,ewcPPDURINGPME); dd_cycles_add(cr->dd,cycles_ppdpme,ddCyclPPduringPME); } #ifdef GMX_MPI if (PAR(cr) && !(cr->duty & DUTY_PME)) { /* In case of node-splitting, the PP nodes receive the long-range * forces, virial and energy from the PME nodes here. */ wallcycle_start(wcycle,ewcPP_PMEWAITRECVF); dvdl = 0; gmx_pme_receive_f(cr,fr->f_novirsum,fr->vir_el_recip,&e,&dvdl, &cycles_pme); if (bSepDVDL) fprintf(fplog,sepdvdlformat,"PME mesh",e,dvdl); enerd->term[F_COUL_RECIP] += e; enerd->term[F_DVDL] += dvdl; if (wcycle) dd_cycles_add(cr->dd,cycles_pme,ddCyclPME); wallcycle_stop(wcycle,ewcPP_PMEWAITRECVF); } #endif if (bDoForces && fr->bF_NoVirSum) { if (vsite) { /* Spread the mesh force on virtual sites to the other particles... * This is parallellized. MPI communication is performed * if the constructing atoms aren't local. */ wallcycle_start(wcycle,ewcVSITESPREAD); spread_vsite_f(fplog,vsite,x,fr->f_novirsum,NULL,nrnb, &top->idef,fr->ePBC,fr->bMolPBC,graph,box,cr); wallcycle_stop(wcycle,ewcVSITESPREAD); } /* Now add the forces, this is local */ if (fr->bDomDec) { sum_forces(0,fr->f_novirsum_n,f,fr->f_novirsum); } else { sum_forces(start,start+homenr,f,fr->f_novirsum); } if (EEL_FULL(fr->eeltype)) { /* Add the mesh contribution to the virial */ m_add(vir_force,fr->vir_el_recip,vir_force); } if (debug) pr_rvecs(debug,0,"vir_force",vir_force,DIM); } /* Sum the potential energy terms from group contributions */ sum_epot(&(inputrec->opts),enerd); if (fr->print_force >= 0 && bDoForces) print_large_forces(stderr,mdatoms,cr,step,fr->print_force,x,f); }
void trotter_update(t_inputrec *ir,gmx_large_int_t step, gmx_ekindata_t *ekind, gmx_enerdata_t *enerd, t_state *state, tensor vir, t_mdatoms *md, t_extmass *MassQ, int **trotter_seqlist, int trotter_seqno) { int n,i,j,d,ntgrp,ngtc,gc=0; t_grp_tcstat *tcstat; t_grpopts *opts; gmx_large_int_t step_eff; real ecorr,pcorr,dvdlcorr; real bmass,qmass,reft,kT,dt,nd; tensor dumpres,dumvir; double *scalefac,dtc; int *trotter_seq; rvec sumv,consk; gmx_bool bCouple; if (trotter_seqno <= ettTSEQ2) { step_eff = step-1; /* the velocity verlet calls are actually out of order -- the first half step is actually the last half step from the previous step. Thus the first half step actually corresponds to the n-1 step*/ } else { step_eff = step; } bCouple = (ir->nsttcouple == 1 || do_per_step(step_eff+ir->nsttcouple,ir->nsttcouple)); trotter_seq = trotter_seqlist[trotter_seqno]; /* signal we are returning if nothing is going to be done in this routine */ if ((trotter_seq[0] == etrtSKIPALL) || !(bCouple)) { return; } dtc = ir->nsttcouple*ir->delta_t; opts = &(ir->opts); /* just for ease of referencing */ ngtc = opts->ngtc; snew(scalefac,opts->ngtc); for (i=0;i<ngtc;i++) { scalefac[i] = 1; } /* execute the series of trotter updates specified in the trotterpart array */ for (i=0;i<NTROTTERPARTS;i++){ /* allow for doubled intgrators by doubling dt instead of making 2 calls */ if ((trotter_seq[i] == etrtBAROV2) || (trotter_seq[i] == etrtBARONHC2) || (trotter_seq[i] == etrtNHC2)) { dt = 2 * dtc; } else { dt = dtc; } switch (trotter_seq[i]) { case etrtBAROV: case etrtBAROV2: boxv_trotter(ir,&(state->veta),dt,state->box,ekind,vir, enerd->term[F_PDISPCORR],enerd->term[F_DISPCORR],MassQ); break; case etrtBARONHC: case etrtBARONHC2: NHC_trotter(opts,state->nnhpres,ekind,dt,state->nhpres_xi, state->nhpres_vxi,NULL,&(state->veta),MassQ,FALSE); break; case etrtNHC: case etrtNHC2: NHC_trotter(opts,opts->ngtc,ekind,dt,state->nosehoover_xi, state->nosehoover_vxi,scalefac,NULL,MassQ,(ir->eI==eiVV)); /* need to rescale the kinetic energies and velocities here. Could scale the velocities later, but we need them scaled in order to produce the correct outputs, so we'll scale them here. */ for (i=0; i<ngtc;i++) { tcstat = &ekind->tcstat[i]; tcstat->vscale_nhc = scalefac[i]; tcstat->ekinscaleh_nhc *= (scalefac[i]*scalefac[i]); tcstat->ekinscalef_nhc *= (scalefac[i]*scalefac[i]); } /* now that we've scaled the groupwise velocities, we can add them up to get the total */ /* but do we actually need the total? */ /* modify the velocities as well */ for (n=md->start;n<md->start+md->homenr;n++) { if (md->cTC) { gc = md->cTC[n]; } for (d=0;d<DIM;d++) { state->v[n][d] *= scalefac[gc]; } if (debug) { for (d=0;d<DIM;d++) { sumv[d] += (state->v[n][d])/md->invmass[n]; } } } break; default: break; } } /* check for conserved momentum -- worth looking at this again eventually, but not working right now.*/ #if 0 if (debug) { if (bFirstHalf) { for (d=0;d<DIM;d++) { consk[d] = sumv[d]*exp((1 + 1.0/opts->nrdf[0])*((1.0/DIM)*log(det(state->box)/state->vol0)) + state->nosehoover_xi[0]); } fprintf(debug,"Conserved kappa: %15.8f %15.8f %15.8f\n",consk[0],consk[1],consk[2]); } } #endif sfree(scalefac); }
double do_md_openmm(FILE *fplog,t_commrec *cr,int nfile,const t_filenm fnm[], const output_env_t oenv, gmx_bool bVerbose,gmx_bool bCompact, int nstglobalcomm, gmx_vsite_t *vsite,gmx_constr_t constr, int stepout,t_inputrec *ir, gmx_mtop_t *top_global, t_fcdata *fcd, t_state *state_global, t_mdatoms *mdatoms, t_nrnb *nrnb,gmx_wallcycle_t wcycle, gmx_edsam_t ed,t_forcerec *fr, int repl_ex_nst,int repl_ex_seed, real cpt_period,real max_hours, const char *deviceOptions, unsigned long Flags, gmx_runtime_t *runtime) { gmx_mdoutf_t *outf; gmx_large_int_t step,step_rel; double run_time; double t,t0,lam0; gmx_bool bSimAnn, bFirstStep,bStateFromTPX,bLastStep,bStartingFromCpt; gmx_bool bInitStep=TRUE; gmx_bool do_ene,do_log, do_verbose, bX,bV,bF,bCPT; tensor force_vir,shake_vir,total_vir,pres; int i,m; int mdof_flags; rvec mu_tot; t_vcm *vcm; int nchkpt=1; gmx_localtop_t *top; t_mdebin *mdebin=NULL; t_state *state=NULL; rvec *f_global=NULL; int n_xtc=-1; rvec *x_xtc=NULL; gmx_enerdata_t *enerd; rvec *f=NULL; gmx_global_stat_t gstat; gmx_update_t upd=NULL; t_graph *graph=NULL; globsig_t gs; gmx_groups_t *groups; gmx_ekindata_t *ekind, *ekind_save; gmx_bool bAppend; int a0,a1; matrix lastbox; real reset_counters=0,reset_counters_now=0; char sbuf[STEPSTRSIZE],sbuf2[STEPSTRSIZE]; int handled_stop_condition=gmx_stop_cond_none; const char *ommOptions = NULL; void *openmmData; bAppend = (Flags & MD_APPENDFILES); check_ir_old_tpx_versions(cr,fplog,ir,top_global); groups = &top_global->groups; /* Initial values */ init_md(fplog,cr,ir,oenv,&t,&t0,&state_global->lambda,&lam0, nrnb,top_global,&upd, nfile,fnm,&outf,&mdebin, force_vir,shake_vir,mu_tot,&bSimAnn,&vcm,state_global,Flags); clear_mat(total_vir); clear_mat(pres); /* Energy terms and groups */ snew(enerd,1); init_enerdata(top_global->groups.grps[egcENER].nr,ir->n_flambda,enerd); snew(f,top_global->natoms); /* Kinetic energy data */ snew(ekind,1); init_ekindata(fplog,top_global,&(ir->opts),ekind); /* needed for iteration of constraints */ snew(ekind_save,1); init_ekindata(fplog,top_global,&(ir->opts),ekind_save); /* Copy the cos acceleration to the groups struct */ ekind->cosacc.cos_accel = ir->cos_accel; gstat = global_stat_init(ir); debug_gmx(); { double io = compute_io(ir,top_global->natoms,groups,mdebin->ebin->nener,1); if ((io > 2000) && MASTER(cr)) fprintf(stderr, "\nWARNING: This run will generate roughly %.0f Mb of data\n\n", io); } top = gmx_mtop_generate_local_top(top_global,ir); a0 = 0; a1 = top_global->natoms; state = partdec_init_local_state(cr,state_global); f_global = f; atoms2md(top_global,ir,0,NULL,a0,a1-a0,mdatoms); if (vsite) { set_vsite_top(vsite,top,mdatoms,cr); } if (ir->ePBC != epbcNONE && !ir->bPeriodicMols) { graph = mk_graph(fplog,&(top->idef),0,top_global->natoms,FALSE,FALSE); } update_mdatoms(mdatoms,state->lambda); if (deviceOptions[0]=='\0') { /* empty options, which should default to OpenMM in this build */ ommOptions=deviceOptions; } else { if (gmx_strncasecmp(deviceOptions,"OpenMM",6)!=0) { gmx_fatal(FARGS, "This Gromacs version currently only works with OpenMM. Use -device \"OpenMM:<options>\""); } else { ommOptions=strchr(deviceOptions,':'); if (NULL!=ommOptions) { /* Increase the pointer to skip the colon */ ommOptions++; } } } openmmData = openmm_init(fplog, ommOptions, ir, top_global, top, mdatoms, fr, state); please_cite(fplog,"Friedrichs2009"); if (MASTER(cr)) { /* Update mdebin with energy history if appending to output files */ if ( Flags & MD_APPENDFILES ) { restore_energyhistory_from_state(mdebin,&state_global->enerhist); } /* Set the initial energy history in state to zero by updating once */ update_energyhistory(&state_global->enerhist,mdebin); } if (constr) { set_constraints(constr,top,ir,mdatoms,cr); } if (!ir->bContinuation) { if (mdatoms->cFREEZE && (state->flags & (1<<estV))) { /* Set the velocities of frozen particles to zero */ for (i=mdatoms->start; i<mdatoms->start+mdatoms->homenr; i++) { for (m=0; m<DIM; m++) { if (ir->opts.nFreeze[mdatoms->cFREEZE[i]][m]) { state->v[i][m] = 0; } } } } if (constr) { /* Constrain the initial coordinates and velocities */ do_constrain_first(fplog,constr,ir,mdatoms,state,f, graph,cr,nrnb,fr,top,shake_vir); } if (vsite) { /* Construct the virtual sites for the initial configuration */ construct_vsites(fplog,vsite,state->x,nrnb,ir->delta_t,NULL, top->idef.iparams,top->idef.il, fr->ePBC,fr->bMolPBC,graph,cr,state->box); } } debug_gmx(); if (MASTER(cr)) { char tbuf[20]; fprintf(fplog,"Initial temperature: %g K\n",enerd->term[F_TEMP]); fprintf(stderr,"starting mdrun '%s'\n", *(top_global->name)); if (ir->nsteps >= 0) { sprintf(tbuf,"%8.1f",(ir->init_step+ir->nsteps)*ir->delta_t); } else { sprintf(tbuf,"%s","infinite"); } if (ir->init_step > 0) { fprintf(stderr,"%s steps, %s ps (continuing from step %s, %8.1f ps).\n", gmx_step_str(ir->init_step+ir->nsteps,sbuf),tbuf, gmx_step_str(ir->init_step,sbuf2), ir->init_step*ir->delta_t); } else { fprintf(stderr,"%s steps, %s ps.\n", gmx_step_str(ir->nsteps,sbuf),tbuf); } } fprintf(fplog,"\n"); /* Set and write start time */ runtime_start(runtime); print_date_and_time(fplog,cr->nodeid,"Started mdrun",runtime); wallcycle_start(wcycle,ewcRUN); if (fplog) fprintf(fplog,"\n"); /* safest point to do file checkpointing is here. More general point would be immediately before integrator call */ debug_gmx(); /*********************************************************** * * Loop over MD steps * ************************************************************/ /* loop over MD steps or if rerunMD to end of input trajectory */ bFirstStep = TRUE; /* Skip the first Nose-Hoover integration when we get the state from tpx */ bStateFromTPX = !opt2bSet("-cpi",nfile,fnm); bInitStep = bFirstStep && bStateFromTPX; bStartingFromCpt = (Flags & MD_STARTFROMCPT) && bInitStep; bLastStep = FALSE; init_global_signals(&gs,cr,ir,repl_ex_nst); step = ir->init_step; step_rel = 0; while (!bLastStep) { wallcycle_start(wcycle,ewcSTEP); GMX_MPE_LOG(ev_timestep1); bLastStep = (step_rel == ir->nsteps); t = t0 + step*ir->delta_t; if (gs.set[eglsSTOPCOND] != 0) { bLastStep = TRUE; } do_log = do_per_step(step,ir->nstlog) || bFirstStep || bLastStep; do_verbose = bVerbose && (step % stepout == 0 || bFirstStep || bLastStep); if (MASTER(cr) && do_log) { print_ebin_header(fplog,step,t,state->lambda); } clear_mat(force_vir); GMX_MPE_LOG(ev_timestep2); /* We write a checkpoint at this MD step when: * either when we signalled through gs (in OpenMM NS works different), * or at the last step (but not when we do not want confout), * but never at the first step. */ bCPT = ((gs.set[eglsCHKPT] || (bLastStep && (Flags & MD_CONFOUT))) && step > ir->init_step ); if (bCPT) { gs.set[eglsCHKPT] = 0; } /* Now we have the energies and forces corresponding to the * coordinates at time t. We must output all of this before * the update. * for RerunMD t is read from input trajectory */ GMX_MPE_LOG(ev_output_start); mdof_flags = 0; if (do_per_step(step,ir->nstxout)) { mdof_flags |= MDOF_X; } if (do_per_step(step,ir->nstvout)) { mdof_flags |= MDOF_V; } if (do_per_step(step,ir->nstfout)) { mdof_flags |= MDOF_F; } if (do_per_step(step,ir->nstxtcout)) { mdof_flags |= MDOF_XTC; } if (bCPT) { mdof_flags |= MDOF_CPT; }; do_ene = (do_per_step(step,ir->nstenergy) || bLastStep); if (mdof_flags != 0 || do_ene || do_log) { wallcycle_start(wcycle,ewcTRAJ); bF = (mdof_flags & MDOF_F); bX = (mdof_flags & (MDOF_X | MDOF_XTC | MDOF_CPT)); bV = (mdof_flags & (MDOF_V | MDOF_CPT)); openmm_copy_state(openmmData, state, &t, f, enerd, bX, bV, bF, do_ene); upd_mdebin(mdebin, FALSE,TRUE, t,mdatoms->tmass,enerd,state,lastbox, shake_vir,force_vir,total_vir,pres, ekind,mu_tot,constr); print_ebin(outf->fp_ene,do_ene,FALSE,FALSE,do_log?fplog:NULL, step,t, eprNORMAL,bCompact,mdebin,fcd,groups,&(ir->opts)); write_traj(fplog,cr,outf,mdof_flags,top_global, step,t,state,state_global,f,f_global,&n_xtc,&x_xtc); if (bCPT) { nchkpt++; bCPT = FALSE; } debug_gmx(); if (bLastStep && step_rel == ir->nsteps && (Flags & MD_CONFOUT) && MASTER(cr)) { /* x and v have been collected in write_traj, * because a checkpoint file will always be written * at the last step. */ fprintf(stderr,"\nWriting final coordinates.\n"); if (ir->ePBC != epbcNONE && !ir->bPeriodicMols) { /* Make molecules whole only for confout writing */ do_pbc_mtop(fplog,ir->ePBC,state->box,top_global,state_global->x); } write_sto_conf_mtop(ftp2fn(efSTO,nfile,fnm), *top_global->name,top_global, state_global->x,state_global->v, ir->ePBC,state->box); debug_gmx(); } wallcycle_stop(wcycle,ewcTRAJ); } GMX_MPE_LOG(ev_output_finish); /* Determine the wallclock run time up till now */ run_time = gmx_gettime() - (double)runtime->real; /* Check whether everything is still allright */ if (((int)gmx_get_stop_condition() > handled_stop_condition) #ifdef GMX_THREADS && MASTER(cr) #endif ) { /* this is just make gs.sig compatible with the hack of sending signals around by MPI_Reduce with together with other floats */ /* NOTE: this only works for serial code. For code that allows MPI nodes to propagate their condition, see kernel/md.c*/ if ( gmx_get_stop_condition() == gmx_stop_cond_next_ns ) gs.set[eglsSTOPCOND]=1; if ( gmx_get_stop_condition() == gmx_stop_cond_next ) gs.set[eglsSTOPCOND]=1; /* < 0 means stop at next step, > 0 means stop at next NS step */ if (fplog) { fprintf(fplog, "\n\nReceived the %s signal, stopping at the next %sstep\n\n", gmx_get_signal_name(), gs.sig[eglsSTOPCOND]==1 ? "NS " : ""); fflush(fplog); } fprintf(stderr, "\n\nReceived the %s signal, stopping at the next %sstep\n\n", gmx_get_signal_name(), gs.sig[eglsSTOPCOND]==1 ? "NS " : ""); fflush(stderr); handled_stop_condition=(int)gmx_get_stop_condition(); } else if (MASTER(cr) && (max_hours > 0 && run_time > max_hours*60.0*60.0*0.99) && gs.set[eglsSTOPCOND] == 0) { /* Signal to terminate the run */ gs.set[eglsSTOPCOND] = 1; if (fplog) { fprintf(fplog,"\nStep %s: Run time exceeded %.3f hours, will terminate the run\n",gmx_step_str(step,sbuf),max_hours*0.99); } fprintf(stderr, "\nStep %s: Run time exceeded %.3f hours, will terminate the run\n",gmx_step_str(step,sbuf),max_hours*0.99); } /* checkpoints */ if (MASTER(cr) && (cpt_period >= 0 && (cpt_period == 0 || run_time >= nchkpt*cpt_period*60.0)) && gs.set[eglsCHKPT] == 0) { gs.set[eglsCHKPT] = 1; } /* Time for performance */ if (((step % stepout) == 0) || bLastStep) { runtime_upd_proc(runtime); } if (do_per_step(step,ir->nstlog)) { if (fflush(fplog) != 0) { gmx_fatal(FARGS,"Cannot flush logfile - maybe you are out of quota?"); } } /* Remaining runtime */ if (MULTIMASTER(cr) && (do_verbose || gmx_got_usr_signal() )) { print_time(stderr,runtime,step,ir,cr); } bFirstStep = FALSE; bInitStep = FALSE; bStartingFromCpt = FALSE; step++; step_rel++; openmm_take_one_step(openmmData); } /* End of main MD loop */ debug_gmx(); /* Stop the time */ runtime_end(runtime); if (MASTER(cr)) { if (ir->nstcalcenergy > 0) { print_ebin(outf->fp_ene,FALSE,FALSE,FALSE,fplog,step,t, eprAVER,FALSE,mdebin,fcd,groups,&(ir->opts)); } } openmm_cleanup(fplog, openmmData); done_mdoutf(outf); debug_gmx(); runtime->nsteps_done = step_rel; return 0; }
void force(FILE *fp, int step, t_forcerec *fr, t_inputrec *ir, t_idef *idef, t_nsborder *nsb, t_commrec *cr, t_commrec *mcr, t_nrnb *nrnb, t_groups *grps, t_mdatoms *md, int ngener, t_grpopts *opts, rvec x[], rvec f[], real epot[], t_fcdata *fcd, bool bVerbose, matrix box, real lambda, t_graph *graph, t_block *excl, bool bNBFonly, matrix lr_vir, rvec mu_tot, real qsum, bool bGatherOnly) { int i,nit; bool bDoEpot; rvec box_size; real Vlr,Vcorr=0; /* Reset box */ for(i=0; (i<DIM); i++) box_size[i]=box[i][i]; bDoEpot=((fr->nmol > 0) && (fr->nstcalc > 0) && (mod(step,fr->nstcalc)==0)); /* Reset epot... */ if (bDoEpot) for(i=0; (i<fr->nmol); i++) fr->mol_epot[i]=0.0; debug_gmx(); /* Call the short range functions all in one go. */ do_fnbf(fp,cr,fr,x,f,md, fr->bBHAM ? grps->estat.ee[egBHAM] : grps->estat.ee[egLJ], grps->estat.ee[egCOUL],box_size,nrnb, lambda,&epot[F_DVDL],FALSE,-1); debug_gmx(); if (debug) pr_rvecs(debug,0,"fshift after SR",fr->fshift,SHIFTS); /* Shift the coordinates. Must be done before bonded forces and PPPM, * but is also necessary for SHAKE and update, therefore it can NOT * go when no bonded forces have to be evaluated. */ if (debug && 0) p_graph(debug,"DeBUGGGG",graph); /* Check whether we need to do bondeds */ if (!bNBFonly) { shift_self(graph,box,x); if (debug && 0) { fprintf(debug,"BBBBBBBBBBBBBBBB\n"); fprintf(debug,"%5d\n",graph->nnodes); for(i=graph->start; (i<=graph->end); i++) fprintf(debug,"%5d%5s%5s%5d%8.3f%8.3f%8.3f\n", i,"A","B",i,x[i][XX],x[i][YY],x[i][ZZ]); fprintf(debug,"%10.5f%10.5f%10.5f\n", box[XX][XX],box[YY][YY],box[ZZ][ZZ]); } if (TRICLINIC(box)) inc_nrnb(nrnb,eNR_SHIFTX,2*graph->nnodes); else inc_nrnb(nrnb,eNR_SHIFTX,graph->nnodes); debug_gmx(); } if (EEL_LR(fr->eeltype)) { switch (fr->eeltype) { case eelPPPM: Vlr = do_pppm(fp,FALSE,x,fr->f_pme,md->chargeT, box_size,fr->phi,cr,nsb,nrnb); break; case eelPOISSON: Vlr = do_poisson(fp,FALSE,ir,md->nr,x,fr->f_pme,md->chargeT, box_size,fr->phi,cr,nrnb,&nit,TRUE); break; case eelPME: Vlr = do_pme(fp,FALSE,ir,x,fr->f_pme,md->chargeT, box,cr,nsb,nrnb,lr_vir,fr->ewaldcoeff,bGatherOnly); break; case eelEWALD: Vlr = do_ewald(fp,FALSE,ir,x,fr->f_pme,md->chargeT, box_size,cr,nsb,lr_vir,fr->ewaldcoeff); break; default: Vlr = 0; fatal_error(0,"No such electrostatics method implemented %s", eel_names[fr->eeltype]); } if(fr->bEwald) Vcorr = ewald_LRcorrection(fp,nsb,cr,fr,md->chargeT,excl,x,box,mu_tot,qsum, ir->ewald_geometry,ir->epsilon_surface,lr_vir); else Vcorr = shift_LRcorrection(fp,nsb,cr,fr,md->chargeT,excl,x,TRUE,box,lr_vir); epot[F_LR] = Vlr + Vcorr; if (debug) fprintf(debug,"Vlr = %g, Vcorr = %g, Vlr_corr = %g\n", Vlr,Vcorr,epot[F_LR]); if (debug) { pr_rvecs(debug,0,"lr_vir after corr",lr_vir,DIM); pr_rvecs(debug,0,"fshift after LR Corrections",fr->fshift,SHIFTS); } } debug_gmx(); if (debug) print_nrnb(debug,nrnb); debug_gmx(); if (!bNBFonly) { calc_bonds(fp,cr,mcr, idef,x,f,fr,graph,epot,nrnb,box,lambda,md, opts->ngener,grps->estat.ee[egLJ14],grps->estat.ee[egCOUL14], fcd,step,fr->bSepDVDL && do_per_step(step,ir->nstlog)); debug_gmx(); } if (debug) pr_rvecs(debug,0,"fshift after bondeds",fr->fshift,SHIFTS); for(i=0; (i<F_EPOT); i++) if (i != F_DISRES) epot[F_EPOT]+=epot[i]; }