void calc_rffac(FILE *fplog,int eel,real eps_r,real eps_rf,real Rc,real Temp, real zsq,matrix box, real *kappa,real *krf,real *crf) { /* Compute constants for Generalized reaction field */ real k1,k2,I,vol,rmin; if (EEL_RF(eel)) { vol = det(box); if (eel == eelGRF) { /* Consistency check */ if (Temp <= 0.0) gmx_fatal(FARGS,"Temperature is %f while using" " Generalized Reaction Field\n",Temp); /* Ionic strength (only needed for eelGRF */ I = 0.5*zsq/vol; *kappa = sqrt(2*I/(EPSILON0*eps_rf*BOLTZ*Temp)); } else { I = 0; *kappa = 0; } /* eps == 0 signals infinite dielectric */ if (eps_rf == 0) { *krf = 1/(2*Rc*Rc*Rc); } else { k1 = 1 + *kappa*Rc; k2 = eps_rf*sqr((real)(*kappa*Rc)); *krf = ((eps_rf - eps_r)*k1 + 0.5*k2)/((2*eps_rf + eps_r)*k1 + k2)/(Rc*Rc*Rc); } *crf = 1/Rc + *krf*Rc*Rc; rmin = pow(*krf*2.0,-1.0/3.0); if (fplog) { if (eel == eelGRF) { please_cite(fplog,"Tironi95a"); fprintf(fplog,"%s:\n" "epsRF = %10g, I = %10g, volume = %10g, kappa = %10g\n" "rc = %10g, krf = %10g, crf = %10g, epsfac = %10g\n", eel_names[eel],eps_rf,I,vol,*kappa,Rc,*krf,*crf, ONE_4PI_EPS0/eps_r); } else { fprintf(fplog,"%s:\n" "epsRF = %g, rc = %g, krf = %g, crf = %g, epsfac = %g\n", eel_names[eel],eps_rf,Rc,*krf,*crf,ONE_4PI_EPS0/eps_r); } fprintf(fplog, "The electrostatics potential has its minimum at r = %g\n", rmin); } } }
void nbnxn_kernel_simd_2xnn(nbnxn_pairlist_set_t gmx_unused *nbl_list, const nbnxn_atomdata_t gmx_unused *nbat, const interaction_const_t gmx_unused *ic, int gmx_unused ewald_excl, rvec gmx_unused *shift_vec, int gmx_unused force_flags, int gmx_unused clearF, real gmx_unused *fshift, real gmx_unused *Vc, real gmx_unused *Vvdw) #ifdef GMX_NBNXN_SIMD_2XNN { int nnbl; nbnxn_pairlist_t **nbl; int coulkt, vdwkt = 0; int nb; int nthreads gmx_unused; nnbl = nbl_list->nnbl; nbl = nbl_list->nbl; if (EEL_RF(ic->eeltype) || ic->eeltype == eelCUT) { coulkt = coulktRF; } else { if (ewald_excl == ewaldexclTable) { if (ic->rcoulomb == ic->rvdw) { coulkt = coulktTAB; } else { coulkt = coulktTAB_TWIN; } } else { if (ic->rcoulomb == ic->rvdw) { coulkt = coulktEWALD; } else { coulkt = coulktEWALD_TWIN; } } } if (ic->vdwtype == evdwCUT) { switch (ic->vdw_modifier) { case eintmodNONE: case eintmodPOTSHIFT: switch (nbat->comb_rule) { case ljcrGEOM: vdwkt = vdwktLJCUT_COMBGEOM; break; case ljcrLB: vdwkt = vdwktLJCUT_COMBLB; break; case ljcrNONE: vdwkt = vdwktLJCUT_COMBNONE; break; default: gmx_incons("Unknown combination rule"); } break; case eintmodFORCESWITCH: vdwkt = vdwktLJFORCESWITCH; break; case eintmodPOTSWITCH: vdwkt = vdwktLJPOTSWITCH; break; default: gmx_incons("Unsupported VdW interaction modifier"); } } else if (ic->vdwtype == evdwPME) { if (ic->ljpme_comb_rule == eljpmeLB) { gmx_incons("The nbnxn SIMD kernels don't suport LJ-PME with LB"); } vdwkt = vdwktLJEWALDCOMBGEOM; } else { gmx_incons("Unsupported VdW interaction type"); } nthreads = gmx_omp_nthreads_get(emntNonbonded); #pragma omp parallel for schedule(static) num_threads(nthreads) for (nb = 0; nb < nnbl; nb++) { nbnxn_atomdata_output_t *out; real *fshift_p; out = &nbat->out[nb]; if (clearF == enbvClearFYes) { clear_f(nbat, nb, out->f); } if ((force_flags & GMX_FORCE_VIRIAL) && nnbl == 1) { fshift_p = fshift; } else { fshift_p = out->fshift; if (clearF == enbvClearFYes) { clear_fshift(fshift_p); } } if (!(force_flags & GMX_FORCE_ENERGY)) { /* Don't calculate energies */ p_nbk_noener[coulkt][vdwkt](nbl[nb], nbat, ic, shift_vec, out->f, fshift_p); } else if (out->nV == 1) { /* No energy groups */ out->Vvdw[0] = 0; out->Vc[0] = 0; p_nbk_ener[coulkt][vdwkt](nbl[nb], nbat, ic, shift_vec, out->f, fshift_p, out->Vvdw, out->Vc); } else { /* Calculate energy group contributions */ int i; for (i = 0; i < out->nVS; i++) { out->VSvdw[i] = 0; } for (i = 0; i < out->nVS; i++) { out->VSc[i] = 0; } p_nbk_energrp[coulkt][vdwkt](nbl[nb], nbat, ic, shift_vec, out->f, fshift_p, out->VSvdw, out->VSc); reduce_group_energies(nbat->nenergrp, nbat->neg_2log, out->VSvdw, out->VSc, out->Vvdw, out->Vc); } } if (force_flags & GMX_FORCE_ENERGY) { reduce_energies_over_lists(nbat, nnbl, Vvdw, Vc); } }
static void pp_verlet_load(gmx_mtop_t *mtop,t_inputrec *ir,matrix box, int *nq_tot, double *cost_pp, gmx_bool *bChargePerturbed) { t_atom *atom; int mb,nmol,atnr,cg,a,a0,nqlj,nq,nlj; gmx_bool bQRF; t_iparams *iparams; gmx_moltype_t *molt; float r_eff; double nat; bQRF = (EEL_RF(ir->coulombtype) || ir->coulombtype == eelCUT); iparams = mtop->ffparams.iparams; atnr = mtop->ffparams.atnr; nqlj = 0; nq = 0; *bChargePerturbed = FALSE; for(mb=0; mb<mtop->nmolblock; mb++) { molt = &mtop->moltype[mtop->molblock[mb].type]; atom = molt->atoms.atom; nmol = mtop->molblock[mb].nmol; a = 0; for(a=0; a<molt->atoms.nr; a++) { if (atom[a].q != 0 || atom[a].qB != 0) { if (iparams[(atnr+1)*atom[a].type].lj.c6 != 0 || iparams[(atnr+1)*atom[a].type].lj.c12 != 0) { nqlj += nmol; } else { nq += nmol; } } if (atom[a].q != atom[a].qB) { *bChargePerturbed = TRUE; } } } nlj = mtop->natoms - nqlj - nq; *nq_tot = nqlj + nq; /* Effective cut-off for cluster pair list of 4x4 atoms */ r_eff = ir->rlist + nbnxn_get_rlist_effective_inc(NBNXN_CPU_CLUSTER_I_SIZE,mtop->natoms/det(box)); if (debug) { fprintf(debug,"nqlj %d nq %d nlj %d rlist %.3f r_eff %.3f\n", nqlj,nq,nlj,ir->rlist,r_eff); } /* For the PP non-bonded cost it is (unrealistically) assumed * that all atoms are distributed homogeneously in space. */ /* Convert mtop->natoms to double to avoid int overflow */ nat = mtop->natoms; *cost_pp = 0.5*(nqlj*nat*(bQRF ? C_VT_QLJ_RF : C_VT_QLJ_TAB) + nq*nat*(bQRF ? C_VT_Q_RF : C_VT_Q_TAB) + nlj*nat*C_VT_LJ) *4/3*M_PI*r_eff*r_eff*r_eff/det(box); }
t_mdebin *init_mdebin(ener_file_t fp_ene, const gmx_mtop_t *mtop, const t_inputrec *ir, FILE *fp_dhdl) { const char *ener_nm[F_NRE]; static const char *vir_nm[] = { "Vir-XX", "Vir-XY", "Vir-XZ", "Vir-YX", "Vir-YY", "Vir-YZ", "Vir-ZX", "Vir-ZY", "Vir-ZZ" }; static const char *sv_nm[] = { "ShakeVir-XX", "ShakeVir-XY", "ShakeVir-XZ", "ShakeVir-YX", "ShakeVir-YY", "ShakeVir-YZ", "ShakeVir-ZX", "ShakeVir-ZY", "ShakeVir-ZZ" }; static const char *fv_nm[] = { "ForceVir-XX", "ForceVir-XY", "ForceVir-XZ", "ForceVir-YX", "ForceVir-YY", "ForceVir-YZ", "ForceVir-ZX", "ForceVir-ZY", "ForceVir-ZZ" }; static const char *pres_nm[] = { "Pres-XX", "Pres-XY", "Pres-XZ", "Pres-YX", "Pres-YY", "Pres-YZ", "Pres-ZX", "Pres-ZY", "Pres-ZZ" }; static const char *surft_nm[] = { "#Surf*SurfTen" }; static const char *mu_nm[] = { "Mu-X", "Mu-Y", "Mu-Z" }; static const char *vcos_nm[] = { "2CosZ*Vel-X" }; static const char *visc_nm[] = { "1/Viscosity" }; static const char *baro_nm[] = { "Barostat" }; char **grpnms; const gmx_groups_t *groups; char **gnm; char buf[256]; const char *bufi; t_mdebin *md; int i, j, ni, nj, n, k, kk, ncon, nset; gmx_bool bBHAM, b14; snew(md, 1); if (EI_DYNAMICS(ir->eI)) { md->delta_t = ir->delta_t; } else { md->delta_t = 0; } groups = &mtop->groups; bBHAM = (mtop->ffparams.functype[0] == F_BHAM); b14 = (gmx_mtop_ftype_count(mtop, F_LJ14) > 0 || gmx_mtop_ftype_count(mtop, F_LJC14_Q) > 0); ncon = gmx_mtop_ftype_count(mtop, F_CONSTR); nset = gmx_mtop_ftype_count(mtop, F_SETTLE); md->bConstr = (ncon > 0 || nset > 0); md->bConstrVir = FALSE; if (md->bConstr) { if (ncon > 0 && ir->eConstrAlg == econtLINCS) { md->nCrmsd = 1; } md->bConstrVir = (getenv("GMX_CONSTRAINTVIR") != NULL); } else { md->nCrmsd = 0; } /* Energy monitoring */ for (i = 0; i < egNR; i++) { md->bEInd[i] = FALSE; } for (i = 0; i < F_NRE; i++) { md->bEner[i] = FALSE; if (i == F_LJ) { md->bEner[i] = !bBHAM; } else if (i == F_BHAM) { md->bEner[i] = bBHAM; } else if (i == F_EQM) { md->bEner[i] = ir->bQMMM; } else if (i == F_RF_EXCL) { md->bEner[i] = (EEL_RF(ir->coulombtype) && ir->cutoff_scheme == ecutsGROUP); } else if (i == F_COUL_RECIP) { md->bEner[i] = EEL_FULL(ir->coulombtype); } else if (i == F_LJ_RECIP) { md->bEner[i] = EVDW_PME(ir->vdwtype); } else if (i == F_LJ14) { md->bEner[i] = b14; } else if (i == F_COUL14) { md->bEner[i] = b14; } else if (i == F_LJC14_Q || i == F_LJC_PAIRS_NB) { md->bEner[i] = FALSE; } else if ((i == F_DVDL_COUL && ir->fepvals->separate_dvdl[efptCOUL]) || (i == F_DVDL_VDW && ir->fepvals->separate_dvdl[efptVDW]) || (i == F_DVDL_BONDED && ir->fepvals->separate_dvdl[efptBONDED]) || (i == F_DVDL_RESTRAINT && ir->fepvals->separate_dvdl[efptRESTRAINT]) || (i == F_DKDL && ir->fepvals->separate_dvdl[efptMASS]) || (i == F_DVDL && ir->fepvals->separate_dvdl[efptFEP])) { md->bEner[i] = (ir->efep != efepNO); } else if ((interaction_function[i].flags & IF_VSITE) || (i == F_CONSTR) || (i == F_CONSTRNC) || (i == F_SETTLE)) { md->bEner[i] = FALSE; } else if ((i == F_COUL_SR) || (i == F_EPOT) || (i == F_PRES) || (i == F_EQM)) { md->bEner[i] = TRUE; } else if ((i == F_GBPOL) && ir->implicit_solvent == eisGBSA) { md->bEner[i] = TRUE; } else if ((i == F_NPSOLVATION) && ir->implicit_solvent == eisGBSA && (ir->sa_algorithm != esaNO)) { md->bEner[i] = TRUE; } else if ((i == F_GB12) || (i == F_GB13) || (i == F_GB14)) { md->bEner[i] = FALSE; } else if ((i == F_ETOT) || (i == F_EKIN) || (i == F_TEMP)) { md->bEner[i] = EI_DYNAMICS(ir->eI); } else if (i == F_DISPCORR || i == F_PDISPCORR) { md->bEner[i] = (ir->eDispCorr != edispcNO); } else if (i == F_DISRESVIOL) { md->bEner[i] = (gmx_mtop_ftype_count(mtop, F_DISRES) > 0); } else if (i == F_ORIRESDEV) { md->bEner[i] = (gmx_mtop_ftype_count(mtop, F_ORIRES) > 0); } else if (i == F_CONNBONDS) { md->bEner[i] = FALSE; } else if (i == F_COM_PULL) { md->bEner[i] = (ir->bPull && pull_have_potential(ir->pull_work)); } else if (i == F_ECONSERVED) { md->bEner[i] = ((ir->etc == etcNOSEHOOVER || ir->etc == etcVRESCALE) && (ir->epc == epcNO || ir->epc == epcMTTK)); } else { md->bEner[i] = (gmx_mtop_ftype_count(mtop, i) > 0); } } md->f_nre = 0; for (i = 0; i < F_NRE; i++) { if (md->bEner[i]) { ener_nm[md->f_nre] = interaction_function[i].longname; md->f_nre++; } } md->epc = ir->epc; md->bDiagPres = !TRICLINIC(ir->ref_p); md->ref_p = (ir->ref_p[XX][XX]+ir->ref_p[YY][YY]+ir->ref_p[ZZ][ZZ])/DIM; md->bTricl = TRICLINIC(ir->compress) || TRICLINIC(ir->deform); md->bDynBox = inputrecDynamicBox(ir); md->etc = ir->etc; md->bNHC_trotter = inputrecNvtTrotter(ir); md->bPrintNHChains = ir->bPrintNHChains; md->bMTTK = (inputrecNptTrotter(ir) || inputrecNphTrotter(ir)); md->bMu = inputrecNeedMutot(ir); md->ebin = mk_ebin(); /* Pass NULL for unit to let get_ebin_space determine the units * for interaction_function[i].longname */ md->ie = get_ebin_space(md->ebin, md->f_nre, ener_nm, NULL); if (md->nCrmsd) { /* This should be called directly after the call for md->ie, * such that md->iconrmsd follows directly in the list. */ md->iconrmsd = get_ebin_space(md->ebin, md->nCrmsd, conrmsd_nm, ""); } if (md->bDynBox) { md->ib = get_ebin_space(md->ebin, md->bTricl ? NTRICLBOXS : NBOXS, md->bTricl ? tricl_boxs_nm : boxs_nm, unit_length); md->ivol = get_ebin_space(md->ebin, 1, vol_nm, unit_volume); md->idens = get_ebin_space(md->ebin, 1, dens_nm, unit_density_SI); if (md->bDiagPres) { md->ipv = get_ebin_space(md->ebin, 1, pv_nm, unit_energy); md->ienthalpy = get_ebin_space(md->ebin, 1, enthalpy_nm, unit_energy); } } if (md->bConstrVir) { md->isvir = get_ebin_space(md->ebin, asize(sv_nm), sv_nm, unit_energy); md->ifvir = get_ebin_space(md->ebin, asize(fv_nm), fv_nm, unit_energy); } md->ivir = get_ebin_space(md->ebin, asize(vir_nm), vir_nm, unit_energy); md->ipres = get_ebin_space(md->ebin, asize(pres_nm), pres_nm, unit_pres_bar); md->isurft = get_ebin_space(md->ebin, asize(surft_nm), surft_nm, unit_surft_bar); if (md->epc == epcPARRINELLORAHMAN || md->epc == epcMTTK) { md->ipc = get_ebin_space(md->ebin, md->bTricl ? 6 : 3, boxvel_nm, unit_vel); } if (md->bMu) { md->imu = get_ebin_space(md->ebin, asize(mu_nm), mu_nm, unit_dipole_D); } if (ir->cos_accel != 0) { md->ivcos = get_ebin_space(md->ebin, asize(vcos_nm), vcos_nm, unit_vel); md->ivisc = get_ebin_space(md->ebin, asize(visc_nm), visc_nm, unit_invvisc_SI); } /* Energy monitoring */ for (i = 0; i < egNR; i++) { md->bEInd[i] = FALSE; } md->bEInd[egCOULSR] = TRUE; md->bEInd[egLJSR ] = TRUE; if (bBHAM) { md->bEInd[egLJSR] = FALSE; md->bEInd[egBHAMSR] = TRUE; } if (b14) { md->bEInd[egLJ14] = TRUE; md->bEInd[egCOUL14] = TRUE; } md->nEc = 0; for (i = 0; (i < egNR); i++) { if (md->bEInd[i]) { md->nEc++; } } n = groups->grps[egcENER].nr; md->nEg = n; md->nE = (n*(n+1))/2; snew(md->igrp, md->nE); if (md->nE > 1) { n = 0; snew(gnm, md->nEc); for (k = 0; (k < md->nEc); k++) { snew(gnm[k], STRLEN); } for (i = 0; (i < groups->grps[egcENER].nr); i++) { ni = groups->grps[egcENER].nm_ind[i]; for (j = i; (j < groups->grps[egcENER].nr); j++) { nj = groups->grps[egcENER].nm_ind[j]; for (k = kk = 0; (k < egNR); k++) { if (md->bEInd[k]) { sprintf(gnm[kk], "%s:%s-%s", egrp_nm[k], *(groups->grpname[ni]), *(groups->grpname[nj])); kk++; } } md->igrp[n] = get_ebin_space(md->ebin, md->nEc, (const char **)gnm, unit_energy); n++; } } for (k = 0; (k < md->nEc); k++) { sfree(gnm[k]); } sfree(gnm); if (n != md->nE) { gmx_incons("Number of energy terms wrong"); } } md->nTC = groups->grps[egcTC].nr; md->nNHC = ir->opts.nhchainlength; /* shorthand for number of NH chains */ if (md->bMTTK) { md->nTCP = 1; /* assume only one possible coupling system for barostat for now */ } else { md->nTCP = 0; } if (md->etc == etcNOSEHOOVER) { if (md->bNHC_trotter) { md->mde_n = 2*md->nNHC*md->nTC; } else { md->mde_n = 2*md->nTC; } if (md->epc == epcMTTK) { md->mdeb_n = 2*md->nNHC*md->nTCP; } } else { md->mde_n = md->nTC; md->mdeb_n = 0; } snew(md->tmp_r, md->mde_n); snew(md->tmp_v, md->mde_n); snew(md->grpnms, md->mde_n); grpnms = md->grpnms; for (i = 0; (i < md->nTC); i++) { ni = groups->grps[egcTC].nm_ind[i]; sprintf(buf, "T-%s", *(groups->grpname[ni])); grpnms[i] = gmx_strdup(buf); } md->itemp = get_ebin_space(md->ebin, md->nTC, (const char **)grpnms, unit_temp_K); if (md->etc == etcNOSEHOOVER) { if (md->bPrintNHChains) { if (md->bNHC_trotter) { for (i = 0; (i < md->nTC); i++) { ni = groups->grps[egcTC].nm_ind[i]; bufi = *(groups->grpname[ni]); for (j = 0; (j < md->nNHC); j++) { sprintf(buf, "Xi-%d-%s", j, bufi); grpnms[2*(i*md->nNHC+j)] = gmx_strdup(buf); sprintf(buf, "vXi-%d-%s", j, bufi); grpnms[2*(i*md->nNHC+j)+1] = gmx_strdup(buf); } } md->itc = get_ebin_space(md->ebin, md->mde_n, (const char **)grpnms, unit_invtime); if (md->bMTTK) { for (i = 0; (i < md->nTCP); i++) { bufi = baro_nm[0]; /* All barostat DOF's together for now. */ for (j = 0; (j < md->nNHC); j++) { sprintf(buf, "Xi-%d-%s", j, bufi); grpnms[2*(i*md->nNHC+j)] = gmx_strdup(buf); sprintf(buf, "vXi-%d-%s", j, bufi); grpnms[2*(i*md->nNHC+j)+1] = gmx_strdup(buf); } } md->itcb = get_ebin_space(md->ebin, md->mdeb_n, (const char **)grpnms, unit_invtime); } } else { for (i = 0; (i < md->nTC); i++) { ni = groups->grps[egcTC].nm_ind[i]; bufi = *(groups->grpname[ni]); sprintf(buf, "Xi-%s", bufi); grpnms[2*i] = gmx_strdup(buf); sprintf(buf, "vXi-%s", bufi); grpnms[2*i+1] = gmx_strdup(buf); } md->itc = get_ebin_space(md->ebin, md->mde_n, (const char **)grpnms, unit_invtime); } } } else if (md->etc == etcBERENDSEN || md->etc == etcYES || md->etc == etcVRESCALE) { for (i = 0; (i < md->nTC); i++) { ni = groups->grps[egcTC].nm_ind[i]; sprintf(buf, "Lamb-%s", *(groups->grpname[ni])); grpnms[i] = gmx_strdup(buf); } md->itc = get_ebin_space(md->ebin, md->mde_n, (const char **)grpnms, ""); } sfree(grpnms); md->nU = groups->grps[egcACC].nr; if (md->nU > 1) { snew(grpnms, 3*md->nU); for (i = 0; (i < md->nU); i++) { ni = groups->grps[egcACC].nm_ind[i]; sprintf(buf, "Ux-%s", *(groups->grpname[ni])); grpnms[3*i+XX] = gmx_strdup(buf); sprintf(buf, "Uy-%s", *(groups->grpname[ni])); grpnms[3*i+YY] = gmx_strdup(buf); sprintf(buf, "Uz-%s", *(groups->grpname[ni])); grpnms[3*i+ZZ] = gmx_strdup(buf); } md->iu = get_ebin_space(md->ebin, 3*md->nU, (const char **)grpnms, unit_vel); sfree(grpnms); } if (fp_ene) { do_enxnms(fp_ene, &md->ebin->nener, &md->ebin->enm); } md->print_grpnms = NULL; /* check whether we're going to write dh histograms */ md->dhc = NULL; if (ir->fepvals->separate_dhdl_file == esepdhdlfileNO) { /* Currently dh histograms are only written with dynamics */ if (EI_DYNAMICS(ir->eI)) { snew(md->dhc, 1); mde_delta_h_coll_init(md->dhc, ir); } md->fp_dhdl = NULL; snew(md->dE, ir->fepvals->n_lambda); } else { md->fp_dhdl = fp_dhdl; snew(md->dE, ir->fepvals->n_lambda); } if (ir->bSimTemp) { int i; snew(md->temperatures, ir->fepvals->n_lambda); for (i = 0; i < ir->fepvals->n_lambda; i++) { md->temperatures[i] = ir->simtempvals->temperatures[i]; } } return md; }
void nbnxn_kernel_ref(const nbnxn_pairlist_set_t *nbl_list, const nbnxn_atomdata_t *nbat, const interaction_const_t *ic, rvec *shift_vec, int force_flags, int clearF, real *fshift, real *Vc, real *Vvdw) { int nnbl; nbnxn_pairlist_t **nbl; int coult; int vdwt; int nb; int nthreads gmx_unused; nnbl = nbl_list->nnbl; nbl = nbl_list->nbl; if (EEL_RF(ic->eeltype) || ic->eeltype == eelCUT) { coult = coultRF; } else { if (ic->rcoulomb == ic->rvdw) { coult = coultTAB; } else { coult = coultTAB_TWIN; } } if (ic->vdwtype == evdwCUT) { switch (ic->vdw_modifier) { case eintmodPOTSHIFT: case eintmodNONE: vdwt = vdwtCUT; break; case eintmodFORCESWITCH: vdwt = vdwtFSWITCH; break; case eintmodPOTSWITCH: vdwt = vdwtPSWITCH; break; default: gmx_incons("Unsupported VdW modifier"); break; } } else if (ic->vdwtype == evdwPME) { if (ic->ljpme_comb_rule == ljcrGEOM) { assert(nbat->comb_rule == ljcrGEOM); vdwt = vdwtEWALDGEOM; } else { assert(nbat->comb_rule == ljcrLB); vdwt = vdwtEWALDLB; } } else { gmx_incons("Unsupported vdwtype in nbnxn reference kernel"); } // cppcheck-suppress unreadVariable nthreads = gmx_omp_nthreads_get(emntNonbonded); #pragma omp parallel for schedule(static) num_threads(nthreads) for (nb = 0; nb < nnbl; nb++) { // Presently, the kernels do not call C++ code that can throw, so // no need for a try/catch pair in this OpenMP region. nbnxn_atomdata_output_t *out; real *fshift_p; out = &nbat->out[nb]; if (clearF == enbvClearFYes) { clear_f(nbat, nb, out->f); } if ((force_flags & GMX_FORCE_VIRIAL) && nnbl == 1) { fshift_p = fshift; } else { fshift_p = out->fshift; if (clearF == enbvClearFYes) { clear_fshift(fshift_p); } } if (!(force_flags & GMX_FORCE_ENERGY)) { /* Don't calculate energies */ p_nbk_c_noener[coult][vdwt](nbl[nb], nbat, ic, shift_vec, out->f, fshift_p); } else if (out->nV == 1) { /* No energy groups */ out->Vvdw[0] = 0; out->Vc[0] = 0; p_nbk_c_ener[coult][vdwt](nbl[nb], nbat, ic, shift_vec, out->f, fshift_p, out->Vvdw, out->Vc); } else { /* Calculate energy group contributions */ int i; for (i = 0; i < out->nV; i++) { out->Vvdw[i] = 0; } for (i = 0; i < out->nV; i++) { out->Vc[i] = 0; } p_nbk_c_energrp[coult][vdwt](nbl[nb], nbat, ic, shift_vec, out->f, fshift_p, out->Vvdw, out->Vc); } } if (force_flags & GMX_FORCE_ENERGY) { reduce_energies_over_lists(nbat, nnbl, Vvdw, Vc); } }
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(t_forcerec *fr, t_inputrec *ir, t_idef *idef, t_commrec *cr, t_nrnb *nrnb, gmx_wallcycle_t wcycle, t_mdatoms *md, rvec x[], history_t *hist, rvec f[], rvec f_longrange[], gmx_enerdata_t *enerd, t_fcdata *fcd, gmx_localtop_t *top, gmx_genborn_t *born, 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; int donb_flags; gmx_bool bSB; int pme_flags; matrix boxs; rvec box_size; t_pbc pbc; real dvdl_dum[efptNR], dvdl_nb[efptNR]; #ifdef GMX_MPI double t0 = 0.0, t1, t2, t3; /* time measurement for coarse load balancing */ #endif 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]; } debug_gmx(); /* do QMMM first if requested */ if (fr->bQMMM) { enerd->term[F_EQM] = calculate_QMMM(cr, x, f, fr); } /* Call the short range functions all in one go. */ #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 */ real dvdl_walls = do_walls(ir, fr, box, md, x, f, lambda[efptVDW], enerd->grpp.ener[egLJSR], nrnb); enerd->dvdl_lin[efptVDW] += dvdl_walls; } /* 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, 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; /* Currently all group scheme kernels always calculate (shift-)forces */ if (flags & GMX_FORCE_FORCES) { donb_flags |= GMX_NONBONDED_DO_FORCE; } if (flags & GMX_FORCE_VIRIAL) { donb_flags |= GMX_NONBONDED_DO_SHIFTFORCE; } 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(fr, x, f, f_longrange, md, excl, &enerd->grpp, 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++) { real lam_i[efptNR]; 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(fr, x, f, f_longrange, md, excl, &(enerd->foreign_grpp), nrnb, lam_i, dvdl_dum, -1, -1, (donb_flags & ~GMX_NONBONDED_DO_FORCE) | GMX_NONBONDED_DO_FOREIGNLAMBDA); sum_epot(&(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, ewcsLISTED); calc_gb_forces(cr, md, born, top, x, f, fr, idef, ir->gb_algorithm, ir->sa_algorithm, nrnb, &pbc, graph, enerd); wallcycle_sub_stop(wcycle, ewcsLISTED); } #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]; } debug_gmx(); if (debug) { pr_rvecs(debug, 0, "fshift after SR", fr->fshift, SHIFTS); } /* Shift the coordinates. Must be done before listed forces and PPPM, * but is also necessary for SHAKE and update, therefore it can NOT * go when no listed forces have to be evaluated. * * The shifting and PBC code is deliberately not timed, since with * the Verlet scheme it only takes non-zero time with triclinic * boxes, and even then the time is around a factor of 100 less * than the next smallest counter. */ /* 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 listed interactions or correct for exclusions */ if (fr->bMolPBC && ((flags & GMX_FORCE_LISTED) || EEL_RF(fr->eeltype) || EEL_FULL(fr->eeltype) || EVDW_PME(fr->vdwtype))) { /* TODO There are no electrostatics methods that require this transformation, when using the Verlet scheme, so update the above conditional. */ /* 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(); do_force_listed(wcycle, box, ir->fepvals, cr->ms, idef, (const rvec *) x, hist, f, fr, &pbc, graph, enerd, nrnb, lambda, md, fcd, DOMAINDECOMP(cr) ? cr->dd->gatindex : NULL, flags); where(); *cycles_pme = 0; clear_mat(fr->vir_el_recip); clear_mat(fr->vir_lj_recip); /* Do long-range electrostatics and/or LJ-PME, including related short-range * corrections. */ if (EEL_FULL(fr->eeltype) || EVDW_PME(fr->vdwtype)) { int status = 0; real Vlr_q = 0, Vlr_lj = 0, Vcorr_q = 0, Vcorr_lj = 0; real dvdl_long_range_q = 0, dvdl_long_range_lj = 0; 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; } if (EEL_PME_EWALD(fr->eeltype) || EVDW_PME(fr->vdwtype)) { real dvdl_long_range_correction_q = 0; real dvdl_long_range_correction_lj = 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 = fr->nthread_ewc; #pragma omp parallel for num_threads(nthreads) schedule(static) for (t = 0; t < nthreads; t++) { try { tensor *vir_q, *vir_lj; real *Vcorrt_q, *Vcorrt_lj, *dvdlt_q, *dvdlt_lj; if (t == 0) { vir_q = &fr->vir_el_recip; vir_lj = &fr->vir_lj_recip; Vcorrt_q = &Vcorr_q; Vcorrt_lj = &Vcorr_lj; dvdlt_q = &dvdl_long_range_correction_q; dvdlt_lj = &dvdl_long_range_correction_lj; } else { vir_q = &fr->ewc_t[t].vir_q; vir_lj = &fr->ewc_t[t].vir_lj; Vcorrt_q = &fr->ewc_t[t].Vcorr_q; Vcorrt_lj = &fr->ewc_t[t].Vcorr_lj; dvdlt_q = &fr->ewc_t[t].dvdl[efptCOUL]; dvdlt_lj = &fr->ewc_t[t].dvdl[efptVDW]; clear_mat(*vir_q); clear_mat(*vir_lj); } *dvdlt_q = 0; *dvdlt_lj = 0; /* Threading is only supported with the Verlet cut-off * scheme and then only single particle forces (no * exclusion forces) are calculated, so we can store * the forces in the normal, single fr->f_novirsum array. */ ewald_LRcorrection(fr->excl_load[t], fr->excl_load[t+1], cr, t, fr, md->chargeA, md->chargeB, md->sqrt_c6A, md->sqrt_c6B, md->sigmaA, md->sigmaB, md->sigma3A, md->sigma3B, md->nChargePerturbed || md->nTypePerturbed, ir->cutoff_scheme != ecutsVERLET, excl, x, bSB ? boxs : box, mu_tot, ir->ewald_geometry, ir->epsilon_surface, fr->f_novirsum, *vir_q, *vir_lj, Vcorrt_q, Vcorrt_lj, lambda[efptCOUL], lambda[efptVDW], dvdlt_q, dvdlt_lj); } GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR; } if (nthreads > 1) { reduce_thread_energies(fr->vir_el_recip, fr->vir_lj_recip, &Vcorr_q, &Vcorr_lj, &dvdl_long_range_correction_q, &dvdl_long_range_correction_lj, nthreads, fr->ewc_t); } wallcycle_sub_stop(wcycle, ewcsEWALD_CORRECTION); }
/*! \brief Returns the kinds of electrostatics and Vdw OpenCL * kernels that will be used. * * Respectively, these values are from enum eelOcl and enum * evdwOcl. */ static void map_interaction_types_to_gpu_kernel_flavors(const interaction_const_t *ic, int combRule, int *gpu_eeltype, int *gpu_vdwtype) { if (ic->vdwtype == evdwCUT) { switch (ic->vdw_modifier) { case eintmodNONE: case eintmodPOTSHIFT: switch (combRule) { case ljcrNONE: *gpu_vdwtype = evdwOclCUT; break; case ljcrGEOM: *gpu_vdwtype = evdwOclCUTCOMBGEOM; break; case ljcrLB: *gpu_vdwtype = evdwOclCUTCOMBLB; break; default: gmx_incons("The requested LJ combination rule is not implemented in the OpenCL GPU accelerated kernels!"); } break; case eintmodFORCESWITCH: *gpu_vdwtype = evdwOclFSWITCH; break; case eintmodPOTSWITCH: *gpu_vdwtype = evdwOclPSWITCH; break; default: gmx_incons("The requested VdW interaction modifier is not implemented in the GPU accelerated kernels!"); } } else if (ic->vdwtype == evdwPME) { if (ic->ljpme_comb_rule == ljcrGEOM) { *gpu_vdwtype = evdwOclEWALDGEOM; } else { *gpu_vdwtype = evdwOclEWALDLB; } } else { gmx_incons("The requested VdW type is not implemented in the GPU accelerated kernels!"); } if (ic->eeltype == eelCUT) { *gpu_eeltype = eelOclCUT; } else if (EEL_RF(ic->eeltype)) { *gpu_eeltype = eelOclRF; } else if ((EEL_PME(ic->eeltype) || ic->eeltype == eelEWALD)) { /* Initially rcoulomb == rvdw, so it's surely not twin cut-off. */ *gpu_eeltype = nbnxn_gpu_pick_ewald_kernel_type(false); } else { /* Shouldn't happen, as this is checked when choosing Verlet-scheme */ gmx_incons("The requested electrostatics type is not implemented in the GPU accelerated kernels!"); } }
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); }
void do_force_lowlevel(t_forcerec *fr, t_inputrec *ir, t_idef *idef, t_commrec *cr, t_nrnb *nrnb, gmx_wallcycle_t wcycle, t_mdatoms *md, rvec x[], history_t *hist, rvec f[], rvec f_longrange[], gmx_enerdata_t *enerd, t_fcdata *fcd, gmx_localtop_t *top, gmx_genborn_t *born, 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; int donb_flags; gmx_bool bSB; int pme_flags; matrix boxs; rvec box_size; t_pbc pbc; real dvdl_dum[efptNR], dvdl_nb[efptNR]; #ifdef GMX_MPI double t0 = 0.0, t1, t2, t3; /* time measurement for coarse load balancing */ #endif 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]; } debug_gmx(); /* do QMMM first if requested */ if (fr->bQMMM) { enerd->term[F_EQM] = calculate_QMMM(cr, x, f, fr); } /* Call the short range functions all in one go. */ #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 */ real dvdl_walls = do_walls(ir, fr, box, md, x, f, lambda[efptVDW], enerd->grpp.ener[egLJSR], nrnb); enerd->dvdl_lin[efptVDW] += dvdl_walls; } /* 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, 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; /* Currently all group scheme kernels always calculate (shift-)forces */ if (flags & GMX_FORCE_FORCES) { donb_flags |= GMX_NONBONDED_DO_FORCE; } if (flags & GMX_FORCE_VIRIAL) { donb_flags |= GMX_NONBONDED_DO_SHIFTFORCE; } 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(fr, x, f, f_longrange, md, excl, &enerd->grpp, 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++) { real lam_i[efptNR]; 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(fr, x, f, f_longrange, md, excl, &(enerd->foreign_grpp), nrnb, lam_i, dvdl_dum, -1, -1, (donb_flags & ~GMX_NONBONDED_DO_FORCE) | GMX_NONBONDED_DO_FOREIGNLAMBDA); sum_epot(&(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, ewcsLISTED); calc_gb_forces(cr, md, born, top, x, f, fr, idef, ir->gb_algorithm, ir->sa_algorithm, nrnb, &pbc, graph, enerd); wallcycle_sub_stop(wcycle, ewcsLISTED); } #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]; } debug_gmx(); if (debug) { pr_rvecs(debug, 0, "fshift after SR", fr->fshift, SHIFTS); } /* Shift the coordinates. Must be done before listed forces and PPPM, * but is also necessary for SHAKE and update, therefore it can NOT * go when no listed forces have to be evaluated. * * The shifting and PBC code is deliberately not timed, since with * the Verlet scheme it only takes non-zero time with triclinic * boxes, and even then the time is around a factor of 100 less * than the next smallest counter. */ /* 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 listed interactions or correct for exclusions */ if (fr->bMolPBC && ((flags & GMX_FORCE_LISTED) || EEL_RF(fr->eeltype) || EEL_FULL(fr->eeltype) || EVDW_PME(fr->vdwtype))) { /* TODO There are no electrostatics methods that require this transformation, when using the Verlet scheme, so update the above conditional. */ /* 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(); do_force_listed(wcycle, box, ir->fepvals, cr->ms, idef, (const rvec *) x, hist, f, fr, &pbc, graph, enerd, nrnb, lambda, md, fcd, DOMAINDECOMP(cr) ? cr->dd->gatindex : NULL, flags); where(); *cycles_pme = 0; clear_mat(fr->vir_el_recip); clear_mat(fr->vir_lj_recip); /* Do long-range electrostatics and/or LJ-PME, including related short-range * corrections. */ if (EEL_FULL(fr->eeltype) || EVDW_PME(fr->vdwtype)) { int status = 0; real Vlr_q = 0, Vlr_lj = 0, Vcorr_q = 0, Vcorr_lj = 0; real dvdl_long_range_q = 0, dvdl_long_range_lj = 0; 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; } if (EEL_PME_EWALD(fr->eeltype) || EVDW_PME(fr->vdwtype)) { real dvdl_long_range_correction_q = 0; real dvdl_long_range_correction_lj = 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 i; rvec *fnv; tensor *vir_q, *vir_lj; real *Vcorrt_q, *Vcorrt_lj, *dvdlt_q, *dvdlt_lj; if (t == 0) { fnv = fr->f_novirsum; vir_q = &fr->vir_el_recip; vir_lj = &fr->vir_lj_recip; Vcorrt_q = &Vcorr_q; Vcorrt_lj = &Vcorr_lj; dvdlt_q = &dvdl_long_range_correction_q; dvdlt_lj = &dvdl_long_range_correction_lj; } else { fnv = fr->f_t[t].f; vir_q = &fr->f_t[t].vir_q; vir_lj = &fr->f_t[t].vir_lj; Vcorrt_q = &fr->f_t[t].Vcorr_q; Vcorrt_lj = &fr->f_t[t].Vcorr_lj; dvdlt_q = &fr->f_t[t].dvdl[efptCOUL]; dvdlt_lj = &fr->f_t[t].dvdl[efptVDW]; for (i = 0; i < fr->natoms_force; i++) { clear_rvec(fnv[i]); } clear_mat(*vir_q); clear_mat(*vir_lj); } *dvdlt_q = 0; *dvdlt_lj = 0; ewald_LRcorrection(fr->excl_load[t], fr->excl_load[t+1], cr, t, fr, md->chargeA, md->chargeB, md->sqrt_c6A, md->sqrt_c6B, md->sigmaA, md->sigmaB, md->sigma3A, md->sigma3B, md->nChargePerturbed || md->nTypePerturbed, ir->cutoff_scheme != ecutsVERLET, excl, x, bSB ? boxs : box, mu_tot, ir->ewald_geometry, ir->epsilon_surface, fnv, *vir_q, *vir_lj, Vcorrt_q, Vcorrt_lj, lambda[efptCOUL], lambda[efptVDW], dvdlt_q, dvdlt_lj); } if (nthreads > 1) { reduce_thread_forces(fr->natoms_force, fr->f_novirsum, fr->vir_el_recip, fr->vir_lj_recip, &Vcorr_q, &Vcorr_lj, &dvdl_long_range_correction_q, &dvdl_long_range_correction_lj, nthreads, fr->f_t); } wallcycle_sub_stop(wcycle, ewcsEWALD_CORRECTION); } if (EEL_PME_EWALD(fr->eeltype) && fr->n_tpi == 0) { /* This is not in a subcounter because it takes a negligible and constant-sized amount of time */ Vcorr_q += ewald_charge_correction(cr, fr, lambda[efptCOUL], box, &dvdl_long_range_correction_q, fr->vir_el_recip); } enerd->dvdl_lin[efptCOUL] += dvdl_long_range_correction_q; enerd->dvdl_lin[efptVDW] += dvdl_long_range_correction_lj; if ((EEL_PME(fr->eeltype) || EVDW_PME(fr->vdwtype)) && (cr->duty & DUTY_PME)) { /* Do reciprocal PME for Coulomb and/or LJ. */ assert(fr->n_tpi >= 0); if (fr->n_tpi == 0 || (flags & GMX_FORCE_STATECHANGED)) { pme_flags = GMX_PME_SPREAD | GMX_PME_SOLVE; if (EEL_PME(fr->eeltype)) { pme_flags |= GMX_PME_DO_COULOMB; } if (EVDW_PME(fr->vdwtype)) { pme_flags |= GMX_PME_DO_LJ; } 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, 0, md->homenr - fr->n_tpi, x, fr->f_novirsum, md->chargeA, md->chargeB, md->sqrt_c6A, md->sqrt_c6B, md->sigmaA, md->sigmaB, 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_q, fr->vir_lj_recip, fr->ewaldcoeff_lj, &Vlr_q, &Vlr_lj, lambda[efptCOUL], lambda[efptVDW], &dvdl_long_range_q, &dvdl_long_range_lj, pme_flags); *cycles_pme = wallcycle_stop(wcycle, ewcPMEMESH); if (status != 0) { gmx_fatal(FARGS, "Error %d in reciprocal PME routine", status); } /* 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) { if (EVDW_PME(ir->vdwtype)) { gmx_fatal(FARGS, "Test particle insertion not implemented with LJ-PME"); } /* 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_q); } } } if (!EEL_PME(fr->eeltype) && EEL_PME_EWALD(fr->eeltype)) { Vlr_q = do_ewald(ir, x, fr->f_novirsum, md->chargeA, md->chargeB, box_size, cr, md->homenr, fr->vir_el_recip, fr->ewaldcoeff_q, lambda[efptCOUL], &dvdl_long_range_q, fr->ewald_table); } /* Note that with separate PME nodes we get the real energies later */ enerd->dvdl_lin[efptCOUL] += dvdl_long_range_q; enerd->dvdl_lin[efptVDW] += dvdl_long_range_lj; enerd->term[F_COUL_RECIP] = Vlr_q + Vcorr_q; enerd->term[F_LJ_RECIP] = Vlr_lj + Vcorr_lj; if (debug) { fprintf(debug, "Vlr_q = %g, Vcorr_q = %g, Vlr_corr_q = %g\n", Vlr_q, Vcorr_q, 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); fprintf(debug, "Vlr_lj: %g, Vcorr_lj = %g, Vlr_corr_lj = %g\n", Vlr_lj, Vcorr_lj, enerd->term[F_LJ_RECIP]); pr_rvecs(debug, 0, "vir_lj_recip after corr", fr->vir_lj_recip, DIM); } } else { /* Is there a reaction-field exclusion correction needed? */ if (EEL_RF(fr->eeltype) && eelRF_NEC != fr->eeltype) { /* With the Verlet scheme, exclusion forces are calculated * in the non-bonded kernel. */ if (ir->cutoff_scheme != ecutsVERLET) { real dvdl_rf_excl = 0; enerd->term[F_RF_EXCL] = RF_excl_correction(fr, graph, md, excl, x, f, fr->fshift, &pbc, lambda[efptCOUL], &dvdl_rf_excl); enerd->dvdl_lin[efptCOUL] += dvdl_rf_excl; } } } 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) { char buf[22]; fprintf(stderr, "* PP load balancing info: rank %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); } }
void nbnxn_kernel_ref(const nbnxn_pairlist_set_t *nbl_list, const nbnxn_atomdata_t *nbat, const interaction_const_t *ic, rvec *shift_vec, int force_flags, int clearF, real *fshift, real *Vc, real *Vvdw) { int nnbl; nbnxn_pairlist_t **nbl; int coult; int nb; nnbl = nbl_list->nnbl; nbl = nbl_list->nbl; if (EEL_RF(ic->eeltype) || ic->eeltype == eelCUT) { coult = coultRF; } else { if (ic->rcoulomb == ic->rvdw) { coult = coultTAB; } else { coult = coultTAB_TWIN; } } #pragma omp parallel for schedule(static) num_threads(gmx_omp_nthreads_get(emntNonbonded)) for (nb = 0; nb < nnbl; nb++) { nbnxn_atomdata_output_t *out; real *fshift_p; out = &nbat->out[nb]; if (clearF == enbvClearFYes) { clear_f(nbat, nb, out->f); } if ((force_flags & GMX_FORCE_VIRIAL) && nnbl == 1) { fshift_p = fshift; } else { fshift_p = out->fshift; if (clearF == enbvClearFYes) { clear_fshift(fshift_p); } } if (!(force_flags & GMX_FORCE_ENERGY)) { /* Don't calculate energies */ p_nbk_c_noener[coult](nbl[nb], nbat, ic, shift_vec, out->f, fshift_p); } else if (out->nV == 1) { /* No energy groups */ out->Vvdw[0] = 0; out->Vc[0] = 0; p_nbk_c_ener[coult](nbl[nb], nbat, ic, shift_vec, out->f, fshift_p, out->Vvdw, out->Vc); } else { /* Calculate energy group contributions */ int i; for (i = 0; i < out->nV; i++) { out->Vvdw[i] = 0; } for (i = 0; i < out->nV; i++) { out->Vc[i] = 0; } p_nbk_c_energrp[coult](nbl[nb], nbat, ic, shift_vec, out->f, fshift_p, out->Vvdw, out->Vc); } } if (force_flags & GMX_FORCE_ENERGY) { reduce_energies_over_lists(nbat, nnbl, Vvdw, Vc); } }
t_mdebin *init_mdebin(ener_file_t fp_ene, const gmx_mtop_t *mtop, const t_inputrec *ir, FILE *fp_dhdl) { const char *ener_nm[F_NRE]; static const char *vir_nm[] = { "Vir-XX", "Vir-XY", "Vir-XZ", "Vir-YX", "Vir-YY", "Vir-YZ", "Vir-ZX", "Vir-ZY", "Vir-ZZ" }; static const char *sv_nm[] = { "ShakeVir-XX", "ShakeVir-XY", "ShakeVir-XZ", "ShakeVir-YX", "ShakeVir-YY", "ShakeVir-YZ", "ShakeVir-ZX", "ShakeVir-ZY", "ShakeVir-ZZ" }; static const char *fv_nm[] = { "ForceVir-XX", "ForceVir-XY", "ForceVir-XZ", "ForceVir-YX", "ForceVir-YY", "ForceVir-YZ", "ForceVir-ZX", "ForceVir-ZY", "ForceVir-ZZ" }; static const char *pres_nm[] = { "Pres-XX","Pres-XY","Pres-XZ", "Pres-YX","Pres-YY","Pres-YZ", "Pres-ZX","Pres-ZY","Pres-ZZ" }; static const char *surft_nm[] = { "#Surf*SurfTen" }; static const char *mu_nm[] = { "Mu-X", "Mu-Y", "Mu-Z" }; static const char *vcos_nm[] = { "2CosZ*Vel-X" }; static const char *visc_nm[] = { "1/Viscosity" }; static const char *baro_nm[] = { "Barostat" }; char **grpnms; const gmx_groups_t *groups; char **gnm; char buf[256]; const char *bufi; t_mdebin *md; int i,j,ni,nj,n,nh,k,kk,ncon,nset; gmx_bool bBHAM,bNoseHoover,b14; snew(md,1); if (EI_DYNAMICS(ir->eI)) { md->delta_t = ir->delta_t; } else { md->delta_t = 0; } groups = &mtop->groups; bBHAM = (mtop->ffparams.functype[0] == F_BHAM); b14 = (gmx_mtop_ftype_count(mtop,F_LJ14) > 0 || gmx_mtop_ftype_count(mtop,F_LJC14_Q) > 0); ncon = gmx_mtop_ftype_count(mtop,F_CONSTR); nset = gmx_mtop_ftype_count(mtop,F_SETTLE); md->bConstr = (ncon > 0 || nset > 0); md->bConstrVir = FALSE; if (md->bConstr) { if (ncon > 0 && ir->eConstrAlg == econtLINCS) { if (ir->eI == eiSD2) md->nCrmsd = 2; else md->nCrmsd = 1; } md->bConstrVir = (getenv("GMX_CONSTRAINTVIR") != NULL); } else { md->nCrmsd = 0; } /* Energy monitoring */ for(i=0;i<egNR;i++) { md->bEInd[i]=FALSE; } #ifndef GMX_OPENMM for(i=0; i<F_NRE; i++) { md->bEner[i] = FALSE; if (i == F_LJ) md->bEner[i] = !bBHAM; else if (i == F_BHAM) md->bEner[i] = bBHAM; else if (i == F_EQM) md->bEner[i] = ir->bQMMM; else if (i == F_COUL_LR) md->bEner[i] = (ir->rcoulomb > ir->rlist); else if (i == F_LJ_LR) md->bEner[i] = (!bBHAM && ir->rvdw > ir->rlist); else if (i == F_BHAM_LR) md->bEner[i] = (bBHAM && ir->rvdw > ir->rlist); else if (i == F_RF_EXCL) md->bEner[i] = (EEL_RF(ir->coulombtype) && ir->coulombtype != eelRF_NEC); else if (i == F_COUL_RECIP) md->bEner[i] = EEL_FULL(ir->coulombtype); else if (i == F_LJ14) md->bEner[i] = b14; else if (i == F_COUL14) md->bEner[i] = b14; else if (i == F_LJC14_Q || i == F_LJC_PAIRS_NB) md->bEner[i] = FALSE; else if ((i == F_DVDL) || (i == F_DKDL)) md->bEner[i] = (ir->efep != efepNO); else if (i == F_DHDL_CON) md->bEner[i] = (ir->efep != efepNO && md->bConstr); else if ((interaction_function[i].flags & IF_VSITE) || (i == F_CONSTR) || (i == F_CONSTRNC) || (i == F_SETTLE)) md->bEner[i] = FALSE; else if ((i == F_COUL_SR) || (i == F_EPOT) || (i == F_PRES) || (i==F_EQM)) md->bEner[i] = TRUE; else if ((i == F_GBPOL) && ir->implicit_solvent==eisGBSA) md->bEner[i] = TRUE; else if ((i == F_NPSOLVATION) && ir->implicit_solvent==eisGBSA && (ir->sa_algorithm != esaNO)) md->bEner[i] = TRUE; else if ((i == F_GB12) || (i == F_GB13) || (i == F_GB14)) md->bEner[i] = FALSE; else if ((i == F_ETOT) || (i == F_EKIN) || (i == F_TEMP)) md->bEner[i] = EI_DYNAMICS(ir->eI); else if (i==F_VTEMP) md->bEner[i] = (EI_DYNAMICS(ir->eI) && getenv("GMX_VIRIAL_TEMPERATURE")); else if (i == F_DISPCORR || i == F_PDISPCORR) md->bEner[i] = (ir->eDispCorr != edispcNO); else if (i == F_DISRESVIOL) md->bEner[i] = (gmx_mtop_ftype_count(mtop,F_DISRES) > 0); else if (i == F_ORIRESDEV) md->bEner[i] = (gmx_mtop_ftype_count(mtop,F_ORIRES) > 0); else if (i == F_CONNBONDS) md->bEner[i] = FALSE; else if (i == F_COM_PULL) md->bEner[i] = (ir->ePull == epullUMBRELLA || ir->ePull == epullCONST_F); else if (i == F_ECONSERVED) md->bEner[i] = ((ir->etc == etcNOSEHOOVER || ir->etc == etcVRESCALE) && (ir->epc == epcNO || ir->epc==epcMTTK)); else md->bEner[i] = (gmx_mtop_ftype_count(mtop,i) > 0); } #else /* OpenMM always produces only the following 4 energy terms */ md->bEner[F_EPOT] = TRUE; md->bEner[F_EKIN] = TRUE; md->bEner[F_ETOT] = TRUE; md->bEner[F_TEMP] = TRUE; #endif md->f_nre=0; for(i=0; i<F_NRE; i++) { if (md->bEner[i]) { /* FIXME: The constness should not be cast away */ /*ener_nm[f_nre]=(char *)interaction_function[i].longname;*/ ener_nm[md->f_nre]=interaction_function[i].longname; md->f_nre++; } } md->epc = ir->epc; for (i=0;i<DIM;i++) { for (j=0;j<DIM;j++) { md->ref_p[i][j] = ir->ref_p[i][j]; } } md->bTricl = TRICLINIC(ir->compress) || TRICLINIC(ir->deform); md->bDynBox = DYNAMIC_BOX(*ir); md->etc = ir->etc; md->bNHC_trotter = IR_NVT_TROTTER(ir); md->bMTTK = IR_NPT_TROTTER(ir); md->ebin = mk_ebin(); /* Pass NULL for unit to let get_ebin_space determine the units * for interaction_function[i].longname */ md->ie = get_ebin_space(md->ebin,md->f_nre,ener_nm,NULL); if (md->nCrmsd) { /* This should be called directly after the call for md->ie, * such that md->iconrmsd follows directly in the list. */ md->iconrmsd = get_ebin_space(md->ebin,md->nCrmsd,conrmsd_nm,""); } if (md->bDynBox) { md->ib = get_ebin_space(md->ebin, md->bTricl ? NTRICLBOXS : NBOXS, md->bTricl ? tricl_boxs_nm : boxs_nm, unit_length); md->ivol = get_ebin_space(md->ebin, 1, vol_nm, unit_volume); md->idens = get_ebin_space(md->ebin, 1, dens_nm, unit_density_SI); md->ipv = get_ebin_space(md->ebin, 1, pv_nm, unit_energy); md->ienthalpy = get_ebin_space(md->ebin, 1, enthalpy_nm, unit_energy); } if (md->bConstrVir) { md->isvir = get_ebin_space(md->ebin,asize(sv_nm),sv_nm,unit_energy); md->ifvir = get_ebin_space(md->ebin,asize(fv_nm),fv_nm,unit_energy); } md->ivir = get_ebin_space(md->ebin,asize(vir_nm),vir_nm,unit_energy); md->ipres = get_ebin_space(md->ebin,asize(pres_nm),pres_nm,unit_pres_bar); md->isurft = get_ebin_space(md->ebin,asize(surft_nm),surft_nm, unit_surft_bar); if (md->epc == epcPARRINELLORAHMAN || md->epc == epcMTTK) { md->ipc = get_ebin_space(md->ebin,md->bTricl ? 6 : 3, boxvel_nm,unit_vel); } md->imu = get_ebin_space(md->ebin,asize(mu_nm),mu_nm,unit_dipole_D); if (ir->cos_accel != 0) { md->ivcos = get_ebin_space(md->ebin,asize(vcos_nm),vcos_nm,unit_vel); md->ivisc = get_ebin_space(md->ebin,asize(visc_nm),visc_nm, unit_invvisc_SI); } /* Energy monitoring */ for(i=0;i<egNR;i++) { md->bEInd[i] = FALSE; } md->bEInd[egCOULSR] = TRUE; md->bEInd[egLJSR ] = TRUE; if (ir->rcoulomb > ir->rlist) { md->bEInd[egCOULLR] = TRUE; } if (!bBHAM) { if (ir->rvdw > ir->rlist) { md->bEInd[egLJLR] = TRUE; } } else { md->bEInd[egLJSR] = FALSE; md->bEInd[egBHAMSR] = TRUE; if (ir->rvdw > ir->rlist) { md->bEInd[egBHAMLR] = TRUE; } } if (b14) { md->bEInd[egLJ14] = TRUE; md->bEInd[egCOUL14] = TRUE; } md->nEc=0; for(i=0; (i<egNR); i++) { if (md->bEInd[i]) { md->nEc++; } } n=groups->grps[egcENER].nr; md->nEg=n; md->nE=(n*(n+1))/2; snew(md->igrp,md->nE); if (md->nE > 1) { n=0; snew(gnm,md->nEc); for(k=0; (k<md->nEc); k++) { snew(gnm[k],STRLEN); } for(i=0; (i<groups->grps[egcENER].nr); i++) { ni=groups->grps[egcENER].nm_ind[i]; for(j=i; (j<groups->grps[egcENER].nr); j++) { nj=groups->grps[egcENER].nm_ind[j]; for(k=kk=0; (k<egNR); k++) { if (md->bEInd[k]) { sprintf(gnm[kk],"%s:%s-%s",egrp_nm[k], *(groups->grpname[ni]),*(groups->grpname[nj])); kk++; } } md->igrp[n]=get_ebin_space(md->ebin,md->nEc, (const char **)gnm,unit_energy); n++; } } for(k=0; (k<md->nEc); k++) { sfree(gnm[k]); } sfree(gnm); if (n != md->nE) { gmx_incons("Number of energy terms wrong"); } } md->nTC=groups->grps[egcTC].nr; md->nNHC = ir->opts.nhchainlength; /* shorthand for number of NH chains */ if (md->bMTTK) { md->nTCP = 1; /* assume only one possible coupling system for barostat for now */ } else { md->nTCP = 0; } if (md->etc == etcNOSEHOOVER) { if (md->bNHC_trotter) { md->mde_n = 2*md->nNHC*md->nTC; } else { md->mde_n = 2*md->nTC; } if (md->epc == epcMTTK) { md->mdeb_n = 2*md->nNHC*md->nTCP; } } else { md->mde_n = md->nTC; md->mdeb_n = 0; } snew(md->tmp_r,md->mde_n); snew(md->tmp_v,md->mde_n); snew(md->grpnms,md->mde_n); grpnms = md->grpnms; for(i=0; (i<md->nTC); i++) { ni=groups->grps[egcTC].nm_ind[i]; sprintf(buf,"T-%s",*(groups->grpname[ni])); grpnms[i]=strdup(buf); } md->itemp=get_ebin_space(md->ebin,md->nTC,(const char **)grpnms, unit_temp_K); bNoseHoover = (getenv("GMX_NOSEHOOVER_CHAINS") != NULL); /* whether to print Nose-Hoover chains */ if (md->etc == etcNOSEHOOVER) { if (bNoseHoover) { if (md->bNHC_trotter) { for(i=0; (i<md->nTC); i++) { ni=groups->grps[egcTC].nm_ind[i]; bufi = *(groups->grpname[ni]); for(j=0; (j<md->nNHC); j++) { sprintf(buf,"Xi-%d-%s",j,bufi); grpnms[2*(i*md->nNHC+j)]=strdup(buf); sprintf(buf,"vXi-%d-%s",j,bufi); grpnms[2*(i*md->nNHC+j)+1]=strdup(buf); } } md->itc=get_ebin_space(md->ebin,md->mde_n, (const char **)grpnms,unit_invtime); if (md->bMTTK) { for(i=0; (i<md->nTCP); i++) { bufi = baro_nm[0]; /* All barostat DOF's together for now. */ for(j=0; (j<md->nNHC); j++) { sprintf(buf,"Xi-%d-%s",j,bufi); grpnms[2*(i*md->nNHC+j)]=strdup(buf); sprintf(buf,"vXi-%d-%s",j,bufi); grpnms[2*(i*md->nNHC+j)+1]=strdup(buf); } } md->itcb=get_ebin_space(md->ebin,md->mdeb_n, (const char **)grpnms,unit_invtime); } } else { for(i=0; (i<md->nTC); i++) { ni=groups->grps[egcTC].nm_ind[i]; bufi = *(groups->grpname[ni]); sprintf(buf,"Xi-%s",bufi); grpnms[2*i]=strdup(buf); sprintf(buf,"vXi-%s",bufi); grpnms[2*i+1]=strdup(buf); } md->itc=get_ebin_space(md->ebin,md->mde_n, (const char **)grpnms,unit_invtime); } } } else if (md->etc == etcBERENDSEN || md->etc == etcYES || md->etc == etcVRESCALE) { for(i=0; (i<md->nTC); i++) { ni=groups->grps[egcTC].nm_ind[i]; sprintf(buf,"Lamb-%s",*(groups->grpname[ni])); grpnms[i]=strdup(buf); } md->itc=get_ebin_space(md->ebin,md->mde_n,(const char **)grpnms,""); } sfree(grpnms); md->nU=groups->grps[egcACC].nr; if (md->nU > 1) { snew(grpnms,3*md->nU); for(i=0; (i<md->nU); i++) { ni=groups->grps[egcACC].nm_ind[i]; sprintf(buf,"Ux-%s",*(groups->grpname[ni])); grpnms[3*i+XX]=strdup(buf); sprintf(buf,"Uy-%s",*(groups->grpname[ni])); grpnms[3*i+YY]=strdup(buf); sprintf(buf,"Uz-%s",*(groups->grpname[ni])); grpnms[3*i+ZZ]=strdup(buf); } md->iu=get_ebin_space(md->ebin,3*md->nU,(const char **)grpnms,unit_vel); sfree(grpnms); } if ( fp_ene ) { do_enxnms(fp_ene,&md->ebin->nener,&md->ebin->enm); } md->print_grpnms=NULL; /* check whether we're going to write dh histograms */ md->dhc=NULL; if (ir->separate_dhdl_file == sepdhdlfileNO ) { int i; snew(md->dhc, 1); mde_delta_h_coll_init(md->dhc, ir); md->fp_dhdl = NULL; } else { md->fp_dhdl = fp_dhdl; } md->dhdl_derivatives = (ir->dhdl_derivatives==dhdlderivativesYES); return md; }
static void pp_verlet_load(const gmx_mtop_t *mtop, const t_inputrec *ir, matrix box, int *nq_tot, int *nlj_tot, double *cost_pp, gmx_bool *bChargePerturbed, gmx_bool *bTypePerturbed) { t_atom *atom; int mb, nmol, atnr, a, nqlj, nq, nlj; gmx_bool bQRF; t_iparams *iparams; gmx_moltype_t *molt; real r_eff; double c_qlj, c_q, c_lj; double nat; /* Conversion factor for reference vs SIMD kernel performance. * The factor is about right for SSE2/4, but should be 2 higher for AVX256. */ #ifdef GMX_DOUBLE const real nbnxn_refkernel_fac = 4.0; #else const real nbnxn_refkernel_fac = 8.0; #endif bQRF = (EEL_RF(ir->coulombtype) || ir->coulombtype == eelCUT); iparams = mtop->ffparams.iparams; atnr = mtop->ffparams.atnr; nqlj = 0; nq = 0; *bChargePerturbed = FALSE; *bTypePerturbed = FALSE; for (mb = 0; mb < mtop->nmolblock; mb++) { molt = &mtop->moltype[mtop->molblock[mb].type]; atom = molt->atoms.atom; nmol = mtop->molblock[mb].nmol; for (a = 0; a < molt->atoms.nr; a++) { if (atom[a].q != 0 || atom[a].qB != 0) { if (iparams[(atnr+1)*atom[a].type].lj.c6 != 0 || iparams[(atnr+1)*atom[a].type].lj.c12 != 0) { nqlj += nmol; } else { nq += nmol; } } if (atom[a].q != atom[a].qB) { *bChargePerturbed = TRUE; } if (atom[a].type != atom[a].typeB) { *bTypePerturbed = TRUE; } } } nlj = mtop->natoms - nqlj - nq; *nq_tot = nqlj + nq; *nlj_tot = nqlj + nlj; /* Effective cut-off for cluster pair list of 4x4 atoms */ r_eff = ir->rlist + nbnxn_get_rlist_effective_inc(NBNXN_CPU_CLUSTER_I_SIZE, mtop->natoms/det(box)); if (debug) { fprintf(debug, "nqlj %d nq %d nlj %d rlist %.3f r_eff %.3f\n", nqlj, nq, nlj, ir->rlist, r_eff); } /* Determine the cost per pair interaction */ c_qlj = (bQRF ? C_VT_QRF_LJ : C_VT_QEXP_LJ); c_q = (bQRF ? C_VT_QRF : C_VT_QEXP); c_lj = C_VT_LJ; if (ir->vdw_modifier == eintmodPOTSWITCH || EVDW_PME(ir->vdwtype)) { c_qlj += C_VT_LJEXP_ADD; c_lj += C_VT_LJEXP_ADD; } if (EVDW_PME(ir->vdwtype) && ir->ljpme_combination_rule == eljpmeLB) { /* We don't have LJ-PME LB comb. rule kernels, we use slow kernels */ c_qlj *= nbnxn_refkernel_fac; c_q *= nbnxn_refkernel_fac; c_lj *= nbnxn_refkernel_fac; } /* For the PP non-bonded cost it is (unrealistically) assumed * that all atoms are distributed homogeneously in space. */ /* Convert mtop->natoms to double to avoid int overflow */ nat = mtop->natoms; *cost_pp = 0.5*nat*(nqlj*c_qlj + nq*c_q + nlj*c_lj) *4/3*M_PI*r_eff*r_eff*r_eff/det(box); }
void nbnxn_kernel_simd_2xnn(nbnxn_pairlist_set_t *nbl_list, const nbnxn_atomdata_t *nbat, const interaction_const_t *ic, int ewald_excl, rvec *shift_vec, int force_flags, int clearF, real *fshift, real *Vc, real *Vvdw) #ifdef GMX_NBNXN_SIMD_2XNN { int nnbl; nbnxn_pairlist_t **nbl; int coult; int nb; nnbl = nbl_list->nnbl; nbl = nbl_list->nbl; if (EEL_RF(ic->eeltype) || ic->eeltype == eelCUT) { coult = coultRF; } else { if (ewald_excl == ewaldexclTable) { if (ic->rcoulomb == ic->rvdw) { coult = coultTAB; } else { coult = coultTAB_TWIN; } } else { if (ic->rcoulomb == ic->rvdw) { coult = coultEWALD; } else { coult = coultEWALD_TWIN; } } } #pragma omp parallel for schedule(static) num_threads(gmx_omp_nthreads_get(emntNonbonded)) for (nb = 0; nb < nnbl; nb++) { nbnxn_atomdata_output_t *out; real *fshift_p; out = &nbat->out[nb]; if (clearF == enbvClearFYes) { clear_f(nbat, nb, out->f); } if ((force_flags & GMX_FORCE_VIRIAL) && nnbl == 1) { fshift_p = fshift; } else { fshift_p = out->fshift; if (clearF == enbvClearFYes) { clear_fshift(fshift_p); } } /* With Ewald type electrostatics we the forces for excluded atom pairs * should not contribute to the virial sum. The exclusion forces * are not calculate in the energy kernels, but are in _noener. */ if (!((force_flags & GMX_FORCE_ENERGY) || (EEL_FULL(ic->eeltype) && (force_flags & GMX_FORCE_VIRIAL)))) { /* Don't calculate energies */ p_nbk_noener[coult][nbat->comb_rule](nbl[nb], nbat, ic, shift_vec, out->f, fshift_p); } else if (out->nV == 1 || !(force_flags & GMX_FORCE_ENERGY)) { /* No energy groups */ out->Vvdw[0] = 0; out->Vc[0] = 0; p_nbk_ener[coult][nbat->comb_rule](nbl[nb], nbat, ic, shift_vec, out->f, fshift_p, out->Vvdw, out->Vc); } else { /* Calculate energy group contributions */ int i; for (i = 0; i < out->nVS; i++) { out->VSvdw[i] = 0; } for (i = 0; i < out->nVS; i++) { out->VSc[i] = 0; } p_nbk_energrp[coult][nbat->comb_rule](nbl[nb], nbat, ic, shift_vec, out->f, fshift_p, out->VSvdw, out->VSc); reduce_group_energies(nbat->nenergrp, nbat->neg_2log, out->VSvdw, out->VSc, out->Vvdw, out->Vc); } } if (force_flags & GMX_FORCE_ENERGY) { reduce_energies_over_lists(nbat, nnbl, Vvdw, Vc); } }
static void pp_verlet_load(gmx_mtop_t *mtop, t_inputrec *ir, matrix box, int *nq_tot, int *nlj_tot, double *cost_pp, gmx_bool *bChargePerturbed, gmx_bool *bTypePerturbed) { t_atom *atom; int mb, nmol, atnr, cg, a, a0, nqlj, nq, nlj; gmx_bool bQRF; t_iparams *iparams; gmx_moltype_t *molt; real r_eff; double c_qlj, c_q, c_lj; double nppa; int j_cluster_size; /* Conversion factor for reference vs SIMD kernel performance. * The factor is about right for SSE2/4, but should be 2 higher for AVX256. */ #ifdef GMX_DOUBLE const real nbnxn_refkernel_fac = 4.0; #else const real nbnxn_refkernel_fac = 8.0; #endif bQRF = (EEL_RF(ir->coulombtype) || ir->coulombtype == eelCUT); iparams = mtop->ffparams.iparams; atnr = mtop->ffparams.atnr; nqlj = 0; nq = 0; *bChargePerturbed = FALSE; *bTypePerturbed = FALSE; for (mb = 0; mb < mtop->nmolblock; mb++) { molt = &mtop->moltype[mtop->molblock[mb].type]; atom = molt->atoms.atom; nmol = mtop->molblock[mb].nmol; a = 0; for (a = 0; a < molt->atoms.nr; a++) { if (atom[a].q != 0 || atom[a].qB != 0) { if (iparams[(atnr+1)*atom[a].type].lj.c6 != 0 || iparams[(atnr+1)*atom[a].type].lj.c12 != 0) { nqlj += nmol; } else { nq += nmol; } } if (atom[a].q != atom[a].qB) { *bChargePerturbed = TRUE; } if (atom[a].type != atom[a].typeB) { *bTypePerturbed = TRUE; } } } nlj = mtop->natoms - nqlj - nq; *nq_tot = nqlj + nq; *nlj_tot = nqlj + nlj; /* Effective cut-off for cluster pair list of 4x4 or 4x8 atoms. * This choice should match the one of pick_nbnxn_kernel_cpu(). * TODO: Make this function use pick_nbnxn_kernel_cpu(). */ #if defined GMX_SIMD_HAVE_REAL && ((GMX_SIMD_REAL_WIDTH == 8 && defined GMX_SIMD_HAVE_FMA) || GMX_SIMD_REAL_WIDTH > 8) j_cluster_size = 8; #else j_cluster_size = 4; #endif r_eff = ir->rlist + nbnxn_get_rlist_effective_inc(j_cluster_size, mtop->natoms/det(box)); /* The average number of pairs per atom */ nppa = 0.5*4/3*M_PI*r_eff*r_eff*r_eff*mtop->natoms/det(box); if (debug) { fprintf(debug, "nqlj %d nq %d nlj %d rlist %.3f r_eff %.3f pairs per atom %.1f\n", nqlj, nq, nlj, ir->rlist, r_eff, nppa); } /* Determine the cost per pair interaction */ c_qlj = (bQRF ? c_nbnxn_qrf_lj : c_nbnxn_qexp_lj); c_q = (bQRF ? c_nbnxn_qrf : c_nbnxn_qexp); c_lj = c_nbnxn_lj; if (ir->vdw_modifier == eintmodPOTSWITCH || EVDW_PME(ir->vdwtype)) { c_qlj += c_nbnxn_ljexp_add; c_lj += c_nbnxn_ljexp_add; } if (EVDW_PME(ir->vdwtype) && ir->ljpme_combination_rule == eljpmeLB) { /* We don't have LJ-PME LB comb. rule kernels, we use slow kernels */ c_qlj *= nbnxn_refkernel_fac; c_q *= nbnxn_refkernel_fac; c_lj *= nbnxn_refkernel_fac; } /* For the PP non-bonded cost it is (unrealistically) assumed * that all atoms are distributed homogeneously in space. */ *cost_pp = (nqlj*c_qlj + nq*c_q + nlj*c_lj)*nppa; *cost_pp *= simd_cycle_factor(bHaveSIMD); }
double do_tpi(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[], const output_env_t oenv, gmx_bool bVerbose, gmx_bool gmx_unused bCompact, int gmx_unused nstglobalcomm, gmx_vsite_t gmx_unused *vsite, gmx_constr_t gmx_unused constr, int gmx_unused stepout, t_inputrec *inputrec, gmx_mtop_t *top_global, t_fcdata *fcd, t_state *state, t_mdatoms *mdatoms, t_nrnb *nrnb, gmx_wallcycle_t wcycle, gmx_edsam_t gmx_unused ed, t_forcerec *fr, int gmx_unused repl_ex_nst, int gmx_unused repl_ex_nex, int gmx_unused repl_ex_seed, gmx_membed_t gmx_unused membed, real gmx_unused cpt_period, real gmx_unused max_hours, const char gmx_unused *deviceOptions, int gmx_unused imdport, unsigned long gmx_unused Flags, gmx_walltime_accounting_t walltime_accounting) { const char *TPI = "Test Particle Insertion"; gmx_localtop_t *top; gmx_groups_t *groups; gmx_enerdata_t *enerd; rvec *f; real lambda, t, temp, beta, drmax, epot; double embU, sum_embU, *sum_UgembU, V, V_all, VembU_all; t_trxstatus *status; t_trxframe rerun_fr; gmx_bool bDispCorr, bCharge, bRFExcl, bNotLastFrame, bStateChanged, bNS; tensor force_vir, shake_vir, vir, pres; int cg_tp, a_tp0, a_tp1, ngid, gid_tp, nener, e; rvec *x_mol; rvec mu_tot, x_init, dx, x_tp; int nnodes, frame; gmx_int64_t frame_step_prev, frame_step; gmx_int64_t nsteps, stepblocksize = 0, step; gmx_int64_t rnd_count_stride, rnd_count; gmx_int64_t seed; double rnd[4]; int i, start, end; FILE *fp_tpi = NULL; char *ptr, *dump_pdb, **leg, str[STRLEN], str2[STRLEN]; double dbl, dump_ener; gmx_bool bCavity; int nat_cavity = 0, d; real *mass_cavity = NULL, mass_tot; int nbin; double invbinw, *bin, refvolshift, logV, bUlogV; real dvdl, prescorr, enercorr, dvdlcorr; gmx_bool bEnergyOutOfBounds; const char *tpid_leg[2] = {"direct", "reweighted"}; /* Since there is no upper limit to the insertion energies, * we need to set an upper limit for the distribution output. */ real bU_bin_limit = 50; real bU_logV_bin_limit = bU_bin_limit + 10; nnodes = cr->nnodes; top = gmx_mtop_generate_local_top(top_global, inputrec); groups = &top_global->groups; bCavity = (inputrec->eI == eiTPIC); if (bCavity) { ptr = getenv("GMX_TPIC_MASSES"); if (ptr == NULL) { nat_cavity = 1; } else { /* Read (multiple) masses from env var GMX_TPIC_MASSES, * The center of mass of the last atoms is then used for TPIC. */ nat_cavity = 0; while (sscanf(ptr, "%lf%n", &dbl, &i) > 0) { srenew(mass_cavity, nat_cavity+1); mass_cavity[nat_cavity] = dbl; fprintf(fplog, "mass[%d] = %f\n", nat_cavity+1, mass_cavity[nat_cavity]); nat_cavity++; ptr += i; } if (nat_cavity == 0) { gmx_fatal(FARGS, "Found %d masses in GMX_TPIC_MASSES", nat_cavity); } } } /* init_em(fplog,TPI,inputrec,&lambda,nrnb,mu_tot, state->box,fr,mdatoms,top,cr,nfile,fnm,NULL,NULL);*/ /* We never need full pbc for TPI */ fr->ePBC = epbcXYZ; /* Determine the temperature for the Boltzmann weighting */ temp = inputrec->opts.ref_t[0]; if (fplog) { for (i = 1; (i < inputrec->opts.ngtc); i++) { if (inputrec->opts.ref_t[i] != temp) { fprintf(fplog, "\nWARNING: The temperatures of the different temperature coupling groups are not identical\n\n"); fprintf(stderr, "\nWARNING: The temperatures of the different temperature coupling groups are not identical\n\n"); } } fprintf(fplog, "\n The temperature for test particle insertion is %.3f K\n\n", temp); } beta = 1.0/(BOLTZ*temp); /* Number of insertions per frame */ nsteps = inputrec->nsteps; /* Use the same neighborlist with more insertions points * in a sphere of radius drmax around the initial point */ /* This should be a proper mdp parameter */ drmax = inputrec->rtpi; /* An environment variable can be set to dump all configurations * to pdb with an insertion energy <= this value. */ dump_pdb = getenv("GMX_TPI_DUMP"); dump_ener = 0; if (dump_pdb) { sscanf(dump_pdb, "%lf", &dump_ener); } atoms2md(top_global, inputrec, 0, NULL, top_global->natoms, mdatoms); update_mdatoms(mdatoms, inputrec->fepvals->init_lambda); snew(enerd, 1); init_enerdata(groups->grps[egcENER].nr, inputrec->fepvals->n_lambda, enerd); snew(f, top_global->natoms); /* Print to log file */ walltime_accounting_start(walltime_accounting); wallcycle_start(wcycle, ewcRUN); print_start(fplog, cr, walltime_accounting, "Test Particle Insertion"); /* The last charge group is the group to be inserted */ cg_tp = top->cgs.nr - 1; a_tp0 = top->cgs.index[cg_tp]; a_tp1 = top->cgs.index[cg_tp+1]; if (debug) { fprintf(debug, "TPI cg %d, atoms %d-%d\n", cg_tp, a_tp0, a_tp1); } if (a_tp1 - a_tp0 > 1 && (inputrec->rlist < inputrec->rcoulomb || inputrec->rlist < inputrec->rvdw)) { gmx_fatal(FARGS, "Can not do TPI for multi-atom molecule with a twin-range cut-off"); } snew(x_mol, a_tp1-a_tp0); bDispCorr = (inputrec->eDispCorr != edispcNO); bCharge = FALSE; for (i = a_tp0; i < a_tp1; i++) { /* Copy the coordinates of the molecule to be insterted */ copy_rvec(state->x[i], x_mol[i-a_tp0]); /* Check if we need to print electrostatic energies */ bCharge |= (mdatoms->chargeA[i] != 0 || (mdatoms->chargeB && mdatoms->chargeB[i] != 0)); } bRFExcl = (bCharge && EEL_RF(fr->eeltype) && fr->eeltype != eelRF_NEC); calc_cgcm(fplog, cg_tp, cg_tp+1, &(top->cgs), state->x, fr->cg_cm); if (bCavity) { if (norm(fr->cg_cm[cg_tp]) > 0.5*inputrec->rlist && fplog) { fprintf(fplog, "WARNING: Your TPI molecule is not centered at 0,0,0\n"); fprintf(stderr, "WARNING: Your TPI molecule is not centered at 0,0,0\n"); } } else { /* Center the molecule to be inserted at zero */ for (i = 0; i < a_tp1-a_tp0; i++) { rvec_dec(x_mol[i], fr->cg_cm[cg_tp]); } } if (fplog) { fprintf(fplog, "\nWill insert %d atoms %s partial charges\n", a_tp1-a_tp0, bCharge ? "with" : "without"); fprintf(fplog, "\nWill insert %d times in each frame of %s\n", (int)nsteps, opt2fn("-rerun", nfile, fnm)); } if (!bCavity) { if (inputrec->nstlist > 1) { if (drmax == 0 && a_tp1-a_tp0 == 1) { gmx_fatal(FARGS, "Re-using the neighborlist %d times for insertions of a single atom in a sphere of radius %f does not make sense", inputrec->nstlist, drmax); } if (fplog) { fprintf(fplog, "Will use the same neighborlist for %d insertions in a sphere of radius %f\n", inputrec->nstlist, drmax); } } } else { if (fplog) { fprintf(fplog, "Will insert randomly in a sphere of radius %f around the center of the cavity\n", drmax); } } ngid = groups->grps[egcENER].nr; gid_tp = GET_CGINFO_GID(fr->cginfo[cg_tp]); nener = 1 + ngid; if (bDispCorr) { nener += 1; } if (bCharge) { nener += ngid; if (bRFExcl) { nener += 1; } if (EEL_FULL(fr->eeltype)) { nener += 1; } } snew(sum_UgembU, nener); /* Copy the random seed set by the user */ seed = inputrec->ld_seed; /* We use the frame step number as one random counter. * The second counter use the insertion (step) count. But we * need multiple random numbers per insertion. This number is * not fixed, since we generate random locations in a sphere * by putting locations in a cube and some of these fail. * A count of 20 is already extremely unlikely, so 10000 is * a safe margin for random numbers per insertion. */ rnd_count_stride = 10000; if (MASTER(cr)) { fp_tpi = xvgropen(opt2fn("-tpi", nfile, fnm), "TPI energies", "Time (ps)", "(kJ mol\\S-1\\N) / (nm\\S3\\N)", oenv); xvgr_subtitle(fp_tpi, "f. are averages over one frame", oenv); snew(leg, 4+nener); e = 0; sprintf(str, "-kT log(<Ve\\S-\\betaU\\N>/<V>)"); leg[e++] = strdup(str); sprintf(str, "f. -kT log<e\\S-\\betaU\\N>"); leg[e++] = strdup(str); sprintf(str, "f. <e\\S-\\betaU\\N>"); leg[e++] = strdup(str); sprintf(str, "f. V"); leg[e++] = strdup(str); sprintf(str, "f. <Ue\\S-\\betaU\\N>"); leg[e++] = strdup(str); for (i = 0; i < ngid; i++) { sprintf(str, "f. <U\\sVdW %s\\Ne\\S-\\betaU\\N>", *(groups->grpname[groups->grps[egcENER].nm_ind[i]])); leg[e++] = strdup(str); } if (bDispCorr) { sprintf(str, "f. <U\\sdisp c\\Ne\\S-\\betaU\\N>"); leg[e++] = strdup(str); } if (bCharge) { for (i = 0; i < ngid; i++) { sprintf(str, "f. <U\\sCoul %s\\Ne\\S-\\betaU\\N>", *(groups->grpname[groups->grps[egcENER].nm_ind[i]])); leg[e++] = strdup(str); } if (bRFExcl) { sprintf(str, "f. <U\\sRF excl\\Ne\\S-\\betaU\\N>"); leg[e++] = strdup(str); } if (EEL_FULL(fr->eeltype)) { sprintf(str, "f. <U\\sCoul recip\\Ne\\S-\\betaU\\N>"); leg[e++] = strdup(str); } } xvgr_legend(fp_tpi, 4+nener, (const char**)leg, oenv); for (i = 0; i < 4+nener; i++) { sfree(leg[i]); } sfree(leg); } clear_rvec(x_init); V_all = 0; VembU_all = 0; invbinw = 10; nbin = 10; snew(bin, nbin); /* Avoid frame step numbers <= -1 */ frame_step_prev = -1; bNotLastFrame = read_first_frame(oenv, &status, opt2fn("-rerun", nfile, fnm), &rerun_fr, TRX_NEED_X); frame = 0; if (rerun_fr.natoms - (bCavity ? nat_cavity : 0) != mdatoms->nr - (a_tp1 - a_tp0)) { gmx_fatal(FARGS, "Number of atoms in trajectory (%d)%s " "is not equal the number in the run input file (%d) " "minus the number of atoms to insert (%d)\n", rerun_fr.natoms, bCavity ? " minus one" : "", mdatoms->nr, a_tp1-a_tp0); } refvolshift = log(det(rerun_fr.box)); switch (inputrec->eI) { case eiTPI: stepblocksize = inputrec->nstlist; break; case eiTPIC: stepblocksize = 1; break; default: gmx_fatal(FARGS, "Unknown integrator %s", ei_names[inputrec->eI]); } #ifdef GMX_SIMD /* Make sure we don't detect SIMD overflow generated before this point */ gmx_simd_check_and_reset_overflow(); #endif while (bNotLastFrame) { frame_step = rerun_fr.step; if (frame_step <= frame_step_prev) { /* We don't have step number in the trajectory file, * or we have constant or decreasing step numbers. * Ensure we have increasing step numbers, since we use * the step numbers as a counter for random numbers. */ frame_step = frame_step_prev + 1; } frame_step_prev = frame_step; lambda = rerun_fr.lambda; t = rerun_fr.time; sum_embU = 0; for (e = 0; e < nener; e++) { sum_UgembU[e] = 0; } /* Copy the coordinates from the input trajectory */ for (i = 0; i < rerun_fr.natoms; i++) { copy_rvec(rerun_fr.x[i], state->x[i]); } copy_mat(rerun_fr.box, state->box); V = det(state->box); logV = log(V); bStateChanged = TRUE; bNS = TRUE; step = cr->nodeid*stepblocksize; while (step < nsteps) { /* Initialize the second counter for random numbers using * the insertion step index. This ensures that we get * the same random numbers independently of how many * MPI ranks we use. Also for the same seed, we get * the same initial random sequence for different nsteps. */ rnd_count = step*rnd_count_stride; if (!bCavity) { /* Random insertion in the whole volume */ bNS = (step % inputrec->nstlist == 0); if (bNS) { /* Generate a random position in the box */ gmx_rng_cycle_2uniform(frame_step, rnd_count++, seed, RND_SEED_TPI, rnd); gmx_rng_cycle_2uniform(frame_step, rnd_count++, seed, RND_SEED_TPI, rnd+2); for (d = 0; d < DIM; d++) { x_init[d] = rnd[d]*state->box[d][d]; } } if (inputrec->nstlist == 1) { copy_rvec(x_init, x_tp); } else { /* Generate coordinates within |dx|=drmax of x_init */ do { gmx_rng_cycle_2uniform(frame_step, rnd_count++, seed, RND_SEED_TPI, rnd); gmx_rng_cycle_2uniform(frame_step, rnd_count++, seed, RND_SEED_TPI, rnd+2); for (d = 0; d < DIM; d++) { dx[d] = (2*rnd[d] - 1)*drmax; } } while (norm2(dx) > drmax*drmax); rvec_add(x_init, dx, x_tp); } } else { /* Random insertion around a cavity location * given by the last coordinate of the trajectory. */ if (step == 0) { if (nat_cavity == 1) { /* Copy the location of the cavity */ copy_rvec(rerun_fr.x[rerun_fr.natoms-1], x_init); } else { /* Determine the center of mass of the last molecule */ clear_rvec(x_init); mass_tot = 0; for (i = 0; i < nat_cavity; i++) { for (d = 0; d < DIM; d++) { x_init[d] += mass_cavity[i]*rerun_fr.x[rerun_fr.natoms-nat_cavity+i][d]; } mass_tot += mass_cavity[i]; } for (d = 0; d < DIM; d++) { x_init[d] /= mass_tot; } } } /* Generate coordinates within |dx|=drmax of x_init */ do { gmx_rng_cycle_2uniform(frame_step, rnd_count++, seed, RND_SEED_TPI, rnd); gmx_rng_cycle_2uniform(frame_step, rnd_count++, seed, RND_SEED_TPI, rnd+2); for (d = 0; d < DIM; d++) { dx[d] = (2*rnd[d] - 1)*drmax; } } while (norm2(dx) > drmax*drmax); rvec_add(x_init, dx, x_tp); } if (a_tp1 - a_tp0 == 1) { /* Insert a single atom, just copy the insertion location */ copy_rvec(x_tp, state->x[a_tp0]); } else { /* Copy the coordinates from the top file */ for (i = a_tp0; i < a_tp1; i++) { copy_rvec(x_mol[i-a_tp0], state->x[i]); } /* Rotate the molecule randomly */ gmx_rng_cycle_2uniform(frame_step, rnd_count++, seed, RND_SEED_TPI, rnd); gmx_rng_cycle_2uniform(frame_step, rnd_count++, seed, RND_SEED_TPI, rnd+2); rotate_conf(a_tp1-a_tp0, state->x+a_tp0, NULL, 2*M_PI*rnd[0], 2*M_PI*rnd[1], 2*M_PI*rnd[2]); /* Shift to the insertion location */ for (i = a_tp0; i < a_tp1; i++) { rvec_inc(state->x[i], x_tp); } } /* Clear some matrix variables */ clear_mat(force_vir); clear_mat(shake_vir); clear_mat(vir); clear_mat(pres); /* Set the charge group center of mass of the test particle */ copy_rvec(x_init, fr->cg_cm[top->cgs.nr-1]); /* Calc energy (no forces) on new positions. * Since we only need the intermolecular energy * and the RF exclusion terms of the inserted molecule occur * within a single charge group we can pass NULL for the graph. * This also avoids shifts that would move charge groups * out of the box. * * Some checks above ensure than we can not have * twin-range interactions together with nstlist > 1, * therefore we do not need to remember the LR energies. */ /* Make do_force do a single node force calculation */ cr->nnodes = 1; do_force(fplog, cr, inputrec, step, nrnb, wcycle, top, &top_global->groups, state->box, state->x, &state->hist, f, force_vir, mdatoms, enerd, fcd, state->lambda, NULL, fr, NULL, mu_tot, t, NULL, NULL, FALSE, GMX_FORCE_NONBONDED | GMX_FORCE_ENERGY | (bNS ? GMX_FORCE_DYNAMICBOX | GMX_FORCE_NS | GMX_FORCE_DO_LR : 0) | (bStateChanged ? GMX_FORCE_STATECHANGED : 0)); cr->nnodes = nnodes; bStateChanged = FALSE; bNS = FALSE; /* Calculate long range corrections to pressure and energy */ calc_dispcorr(fplog, inputrec, fr, step, top_global->natoms, state->box, lambda, pres, vir, &prescorr, &enercorr, &dvdlcorr); /* figure out how to rearrange the next 4 lines MRS 8/4/2009 */ enerd->term[F_DISPCORR] = enercorr; enerd->term[F_EPOT] += enercorr; enerd->term[F_PRES] += prescorr; enerd->term[F_DVDL_VDW] += dvdlcorr; epot = enerd->term[F_EPOT]; bEnergyOutOfBounds = FALSE; #ifdef GMX_SIMD_X86_SSE2_OR_HIGHER /* With SSE the energy can overflow, check for this */ if (gmx_mm_check_and_reset_overflow()) { if (debug) { fprintf(debug, "Found an SSE overflow, assuming the energy is out of bounds\n"); } bEnergyOutOfBounds = TRUE; } #endif /* If the compiler doesn't optimize this check away * we catch the NAN energies. * The epot>GMX_REAL_MAX check catches inf values, * which should nicely result in embU=0 through the exp below, * but it does not hurt to check anyhow. */ /* Non-bonded Interaction usually diverge at r=0. * With tabulated interaction functions the first few entries * should be capped in a consistent fashion between * repulsion, dispersion and Coulomb to avoid accidental * negative values in the total energy. * The table generation code in tables.c does this. * With user tbales the user should take care of this. */ if (epot != epot || epot > GMX_REAL_MAX) { bEnergyOutOfBounds = TRUE; } if (bEnergyOutOfBounds) { if (debug) { fprintf(debug, "\n time %.3f, step %d: non-finite energy %f, using exp(-bU)=0\n", t, (int)step, epot); } embU = 0; } else { embU = exp(-beta*epot); sum_embU += embU; /* Determine the weighted energy contributions of each energy group */ e = 0; sum_UgembU[e++] += epot*embU; if (fr->bBHAM) { for (i = 0; i < ngid; i++) { sum_UgembU[e++] += (enerd->grpp.ener[egBHAMSR][GID(i, gid_tp, ngid)] + enerd->grpp.ener[egBHAMLR][GID(i, gid_tp, ngid)])*embU; } } else { for (i = 0; i < ngid; i++) { sum_UgembU[e++] += (enerd->grpp.ener[egLJSR][GID(i, gid_tp, ngid)] + enerd->grpp.ener[egLJLR][GID(i, gid_tp, ngid)])*embU; } } if (bDispCorr) { sum_UgembU[e++] += enerd->term[F_DISPCORR]*embU; } if (bCharge) { for (i = 0; i < ngid; i++) { sum_UgembU[e++] += (enerd->grpp.ener[egCOULSR][GID(i, gid_tp, ngid)] + enerd->grpp.ener[egCOULLR][GID(i, gid_tp, ngid)])*embU; } if (bRFExcl) { sum_UgembU[e++] += enerd->term[F_RF_EXCL]*embU; } if (EEL_FULL(fr->eeltype)) { sum_UgembU[e++] += enerd->term[F_COUL_RECIP]*embU; } } } if (embU == 0 || beta*epot > bU_bin_limit) { bin[0]++; } else { i = (int)((bU_logV_bin_limit - (beta*epot - logV + refvolshift))*invbinw + 0.5); if (i < 0) { i = 0; } if (i >= nbin) { realloc_bins(&bin, &nbin, i+10); } bin[i]++; } if (debug) { fprintf(debug, "TPI %7d %12.5e %12.5f %12.5f %12.5f\n", (int)step, epot, x_tp[XX], x_tp[YY], x_tp[ZZ]); } if (dump_pdb && epot <= dump_ener) { sprintf(str, "t%g_step%d.pdb", t, (int)step); sprintf(str2, "t: %f step %d ener: %f", t, (int)step, epot); write_sto_conf_mtop(str, str2, top_global, state->x, state->v, inputrec->ePBC, state->box); } step++; if ((step/stepblocksize) % cr->nnodes != cr->nodeid) { /* Skip all steps assigned to the other MPI ranks */ step += (cr->nnodes - 1)*stepblocksize; } } if (PAR(cr)) { /* When running in parallel sum the energies over the processes */ gmx_sumd(1, &sum_embU, cr); gmx_sumd(nener, sum_UgembU, cr); } frame++; V_all += V; VembU_all += V*sum_embU/nsteps; if (fp_tpi) { if (bVerbose || frame%10 == 0 || frame < 10) { fprintf(stderr, "mu %10.3e <mu> %10.3e\n", -log(sum_embU/nsteps)/beta, -log(VembU_all/V_all)/beta); } fprintf(fp_tpi, "%10.3f %12.5e %12.5e %12.5e %12.5e", t, VembU_all == 0 ? 20/beta : -log(VembU_all/V_all)/beta, sum_embU == 0 ? 20/beta : -log(sum_embU/nsteps)/beta, sum_embU/nsteps, V); for (e = 0; e < nener; e++) { fprintf(fp_tpi, " %12.5e", sum_UgembU[e]/nsteps); } fprintf(fp_tpi, "\n"); fflush(fp_tpi); } bNotLastFrame = read_next_frame(oenv, status, &rerun_fr); } /* End of the loop */ walltime_accounting_end(walltime_accounting); close_trj(status); if (fp_tpi != NULL) { gmx_fio_fclose(fp_tpi); } if (fplog != NULL) { fprintf(fplog, "\n"); fprintf(fplog, " <V> = %12.5e nm^3\n", V_all/frame); fprintf(fplog, " <mu> = %12.5e kJ/mol\n", -log(VembU_all/V_all)/beta); } /* Write the Boltzmann factor histogram */ if (PAR(cr)) { /* When running in parallel sum the bins over the processes */ i = nbin; global_max(cr, &i); realloc_bins(&bin, &nbin, i); gmx_sumd(nbin, bin, cr); } if (MASTER(cr)) { fp_tpi = xvgropen(opt2fn("-tpid", nfile, fnm), "TPI energy distribution", "\\betaU - log(V/<V>)", "count", oenv); sprintf(str, "number \\betaU > %g: %9.3e", bU_bin_limit, bin[0]); xvgr_subtitle(fp_tpi, str, oenv); xvgr_legend(fp_tpi, 2, (const char **)tpid_leg, oenv); for (i = nbin-1; i > 0; i--) { bUlogV = -i/invbinw + bU_logV_bin_limit - refvolshift + log(V_all/frame); fprintf(fp_tpi, "%6.2f %10d %12.5e\n", bUlogV, (int)(bin[i]+0.5), bin[i]*exp(-bUlogV)*V_all/VembU_all); } gmx_fio_fclose(fp_tpi); } sfree(bin); sfree(sum_UgembU); walltime_accounting_set_nsteps_done(walltime_accounting, frame*inputrec->nsteps); return 0; }
void calc_verlet_buffer_size(const gmx_mtop_t *mtop, real boxvol, const t_inputrec *ir, real reference_temperature, const verletbuf_list_setup_t *list_setup, int *n_nonlin_vsite, real *rlist) { double resolution; char *env; real particle_distance; real nb_clust_frac_pairs_not_in_list_at_cutoff; verletbuf_atomtype_t *att = NULL; int natt = -1, i; double reppow; real md1_ljd, d2_ljd, md3_ljd; real md1_ljr, d2_ljr, md3_ljr; real md1_el, d2_el; real elfac; real kT_fac, mass_min; int ib0, ib1, ib; real rb, rl; real drift; if (reference_temperature < 0) { if (EI_MD(ir->eI) && ir->etc == etcNO) { /* This case should be handled outside calc_verlet_buffer_size */ gmx_incons("calc_verlet_buffer_size called with an NVE ensemble and reference_temperature < 0"); } /* We use the maximum temperature with multiple T-coupl groups. * We could use a per particle temperature, but since particles * interact, this might underestimate the buffer size. */ reference_temperature = 0; for (i = 0; i < ir->opts.ngtc; i++) { if (ir->opts.tau_t[i] >= 0) { reference_temperature = max(reference_temperature, ir->opts.ref_t[i]); } } } /* Resolution of the buffer size */ resolution = 0.001; env = getenv("GMX_VERLET_BUFFER_RES"); if (env != NULL) { sscanf(env, "%lf", &resolution); } /* In an atom wise pair-list there would be no pairs in the list * beyond the pair-list cut-off. * However, we use a pair-list of groups vs groups of atoms. * For groups of 4 atoms, the parallelism of SSE instructions, only * 10% of the atoms pairs are not in the list just beyond the cut-off. * As this percentage increases slowly compared to the decrease of the * Gaussian displacement distribution over this range, we can simply * reduce the drift by this fraction. * For larger groups, e.g. of 8 atoms, this fraction will be lower, * so then buffer size will be on the conservative (large) side. * * Note that the formulas used here do not take into account * cancellation of errors which could occur by missing both * attractive and repulsive interactions. * * The only major assumption is homogeneous particle distribution. * For an inhomogeneous system, such as a liquid-vapor system, * the buffer will be underestimated. The actual energy drift * will be higher by the factor: local/homogeneous particle density. * * The results of this estimate have been checked againt simulations. * In most cases the real drift differs by less than a factor 2. */ /* Worst case assumption: HCP packing of particles gives largest distance */ particle_distance = pow(boxvol*sqrt(2)/mtop->natoms, 1.0/3.0); get_verlet_buffer_atomtypes(mtop, &att, &natt, n_nonlin_vsite); assert(att != NULL && natt >= 0); if (debug) { fprintf(debug, "particle distance assuming HCP packing: %f nm\n", particle_distance); fprintf(debug, "energy drift atom types: %d\n", natt); } reppow = mtop->ffparams.reppow; md1_ljd = 0; d2_ljd = 0; md3_ljd = 0; md1_ljr = 0; d2_ljr = 0; md3_ljr = 0; if (ir->vdwtype == evdwCUT) { real sw_range, md3_pswf; switch (ir->vdw_modifier) { case eintmodNONE: case eintmodPOTSHIFT: /* -dV/dr of -r^-6 and r^-reppow */ md1_ljd = -6*pow(ir->rvdw, -7.0); md1_ljr = reppow*pow(ir->rvdw, -(reppow+1)); /* The contribution of the higher derivatives is negligible */ break; case eintmodFORCESWITCH: /* At the cut-off: V=V'=V''=0, so we use only V''' */ md3_ljd = -md3_force_switch(6.0, ir->rvdw_switch, ir->rvdw); md3_ljr = md3_force_switch(reppow, ir->rvdw_switch, ir->rvdw); break; case eintmodPOTSWITCH: /* At the cut-off: V=V'=V''=0. * V''' is given by the original potential times * the third derivative of the switch function. */ sw_range = ir->rvdw - ir->rvdw_switch; md3_pswf = 60.0*pow(sw_range, -3.0); md3_ljd = -pow(ir->rvdw, -6.0 )*md3_pswf; md3_ljr = pow(ir->rvdw, -reppow)*md3_pswf; break; default: gmx_incons("Unimplemented VdW modifier"); } } else if (EVDW_PME(ir->vdwtype)) { real b, r, br, br2, br4, br6; b = calc_ewaldcoeff_lj(ir->rvdw, ir->ewald_rtol_lj); r = ir->rvdw; br = b*r; br2 = br*br; br4 = br2*br2; br6 = br4*br2; /* -dV/dr of g(br)*r^-6 [where g(x) = exp(-x^2)(1+x^2+x^4/2), see LJ-PME equations in manual] and r^-reppow */ md1_ljd = -exp(-br2)*(br6 + 3.0*br4 + 6.0*br2 + 6.0)*pow(r, -7.0); md1_ljr = reppow*pow(r, -(reppow+1)); /* The contribution of the higher derivatives is negligible */ } else { gmx_fatal(FARGS, "Energy drift calculation is only implemented for plain cut-off Lennard-Jones interactions"); } elfac = ONE_4PI_EPS0/ir->epsilon_r; /* Determine md=-dV/dr and dd=d^2V/dr^2 */ md1_el = 0; d2_el = 0; if (ir->coulombtype == eelCUT || EEL_RF(ir->coulombtype)) { real eps_rf, k_rf; if (ir->coulombtype == eelCUT) { eps_rf = 1; k_rf = 0; } else { eps_rf = ir->epsilon_rf/ir->epsilon_r; if (eps_rf != 0) { k_rf = pow(ir->rcoulomb, -3.0)*(eps_rf - ir->epsilon_r)/(2*eps_rf + ir->epsilon_r); } else { /* epsilon_rf = infinity */ k_rf = 0.5*pow(ir->rcoulomb, -3.0); } } if (eps_rf > 0) { md1_el = elfac*(pow(ir->rcoulomb, -2.0) - 2*k_rf*ir->rcoulomb); } d2_el = elfac*(2*pow(ir->rcoulomb, -3.0) + 2*k_rf); } else if (EEL_PME(ir->coulombtype) || ir->coulombtype == eelEWALD) { real b, rc, br; b = calc_ewaldcoeff_q(ir->rcoulomb, ir->ewald_rtol); rc = ir->rcoulomb; br = b*rc; md1_el = elfac*(b*exp(-br*br)*M_2_SQRTPI/rc + gmx_erfc(br)/(rc*rc)); d2_el = elfac/(rc*rc)*(2*b*(1 + br*br)*exp(-br*br)*M_2_SQRTPI + 2*gmx_erfc(br)/rc); } else { gmx_fatal(FARGS, "Energy drift calculation is only implemented for Reaction-Field and Ewald electrostatics"); } /* Determine the variance of the atomic displacement * over nstlist-1 steps: kT_fac * For inertial dynamics (not Brownian dynamics) the mass factor * is not included in kT_fac, it is added later. */ if (ir->eI == eiBD) { /* Get the displacement distribution from the random component only. * With accurate integration the systematic (force) displacement * should be negligible (unless nstlist is extremely large, which * you wouldn't do anyhow). */ kT_fac = 2*BOLTZ*reference_temperature*(ir->nstlist-1)*ir->delta_t; if (ir->bd_fric > 0) { /* This is directly sigma^2 of the displacement */ kT_fac /= ir->bd_fric; /* Set the masses to 1 as kT_fac is the full sigma^2, * but we divide by m in ener_drift(). */ for (i = 0; i < natt; i++) { att[i].prop.mass = 1; } } else { real tau_t; /* Per group tau_t is not implemented yet, use the maximum */ tau_t = ir->opts.tau_t[0]; for (i = 1; i < ir->opts.ngtc; i++) { tau_t = max(tau_t, ir->opts.tau_t[i]); } kT_fac *= tau_t; /* This kT_fac needs to be divided by the mass to get sigma^2 */ } } else { kT_fac = BOLTZ*reference_temperature*sqr((ir->nstlist-1)*ir->delta_t); } mass_min = att[0].prop.mass; for (i = 1; i < natt; i++) { mass_min = min(mass_min, att[i].prop.mass); } if (debug) { fprintf(debug, "md1_ljd %9.2e d2_ljd %9.2e md3_ljd %9.2e\n", md1_ljd, d2_ljd, md3_ljd); fprintf(debug, "md1_ljr %9.2e d2_ljr %9.2e md3_ljr %9.2e\n", md1_ljr, d2_ljr, md3_ljr); fprintf(debug, "md1_el %9.2e d2_el %9.2e\n", md1_el, d2_el); fprintf(debug, "sqrt(kT_fac) %f\n", sqrt(kT_fac)); fprintf(debug, "mass_min %f\n", mass_min); } /* Search using bisection */ ib0 = -1; /* The drift will be neglible at 5 times the max sigma */ ib1 = (int)(5*2*sqrt(kT_fac/mass_min)/resolution) + 1; while (ib1 - ib0 > 1) { ib = (ib0 + ib1)/2; rb = ib*resolution; rl = max(ir->rvdw, ir->rcoulomb) + rb; /* Calculate the average energy drift at the last step * of the nstlist steps at which the pair-list is used. */ drift = ener_drift(att, natt, &mtop->ffparams, kT_fac, md1_ljd, d2_ljd, md3_ljd, md1_ljr, d2_ljr, md3_ljr, md1_el, d2_el, rb, rl, boxvol); /* Correct for the fact that we are using a Ni x Nj particle pair list * and not a 1 x 1 particle pair list. This reduces the drift. */ /* We don't have a formula for 8 (yet), use 4 which is conservative */ nb_clust_frac_pairs_not_in_list_at_cutoff = surface_frac(min(list_setup->cluster_size_i, 4), particle_distance, rl)* surface_frac(min(list_setup->cluster_size_j, 4), particle_distance, rl); drift *= nb_clust_frac_pairs_not_in_list_at_cutoff; /* Convert the drift to drift per unit time per atom */ drift /= ir->nstlist*ir->delta_t*mtop->natoms; if (debug) { fprintf(debug, "ib %3d %3d %3d rb %.3f %dx%d fac %.3f drift %.1e\n", ib0, ib, ib1, rb, list_setup->cluster_size_i, list_setup->cluster_size_j, nb_clust_frac_pairs_not_in_list_at_cutoff, drift); } if (fabs(drift) > ir->verletbuf_tol) { ib0 = ib; } else { ib1 = ib; } } sfree(att); *rlist = max(ir->rvdw, ir->rcoulomb) + ib1*resolution; }
t_mdebin *init_mdebin(int fp_ene, const gmx_mtop_t *mtop, const t_inputrec *ir) { char *ener_nm[F_NRE]; static char *vir_nm[] = { "Vir-XX", "Vir-XY", "Vir-XZ", "Vir-YX", "Vir-YY", "Vir-YZ", "Vir-ZX", "Vir-ZY", "Vir-ZZ" }; static char *sv_nm[] = { "ShakeVir-XX", "ShakeVir-XY", "ShakeVir-XZ", "ShakeVir-YX", "ShakeVir-YY", "ShakeVir-YZ", "ShakeVir-ZX", "ShakeVir-ZY", "ShakeVir-ZZ" }; static char *fv_nm[] = { "ForceVir-XX", "ForceVir-XY", "ForceVir-XZ", "ForceVir-YX", "ForceVir-YY", "ForceVir-YZ", "ForceVir-ZX", "ForceVir-ZY", "ForceVir-ZZ" }; static char *pres_nm[] = { "Pres-XX (bar)","Pres-XY (bar)","Pres-XZ (bar)", "Pres-YX (bar)","Pres-YY (bar)","Pres-YZ (bar)", "Pres-ZX (bar)","Pres-ZY (bar)","Pres-ZZ (bar)" }; static char *surft_nm[] = { "#Surf*SurfTen" }; static char *mu_nm[] = { "Mu-X", "Mu-Y", "Mu-Z" }; static char *vcos_nm[] = { "2CosZ*Vel-X" }; static char *visc_nm[] = { "1/Viscosity (SI)" }; static char **grpnms; const gmx_groups_t *groups; char **gnm; char buf[256]; t_mdebin *md; int i,j,ni,nj,n,k,kk,ncon,nset; bool bBHAM,b14; f_nre = 0; // otherwise, multiple calls to mdrunner_integrate are not possible!NnCrmsd; groups = &mtop->groups; bBHAM = (mtop->ffparams.functype[0] == F_BHAM); b14 = (gmx_mtop_ftype_count(mtop,F_LJ14) > 0 || gmx_mtop_ftype_count(mtop,F_LJC14_Q) > 0); ncon = gmx_mtop_ftype_count(mtop,F_CONSTR); nset = gmx_mtop_ftype_count(mtop,F_SETTLE); bConstr = (ncon > 0 || nset > 0); bConstrVir = FALSE; if (bConstr) { if (ncon > 0 && ir->eConstrAlg == econtLINCS) { if (ir->eI == eiSD2) nCrmsd = 2; else nCrmsd = 1; } bConstrVir = (getenv("GMX_CONSTRAINTVIR") != NULL); } else { nCrmsd = 0; } for(i=0; i<F_NRE; i++) { bEner[i] = FALSE; if (i == F_LJ) bEner[i] = !bBHAM; else if (i == F_BHAM) bEner[i] = bBHAM; else if (i == F_EQM) bEner[i] = ir->bQMMM; else if (i == F_COUL_LR) bEner[i] = (ir->rcoulomb > ir->rlist); else if (i == F_LJ_LR) bEner[i] = (!bBHAM && ir->rvdw > ir->rlist); else if (i == F_BHAM_LR) bEner[i] = (bBHAM && ir->rvdw > ir->rlist); else if (i == F_RF_EXCL) bEner[i] = (EEL_RF(ir->coulombtype) && ir->coulombtype != eelRF_NEC); else if (i == F_COUL_RECIP) bEner[i] = EEL_FULL(ir->coulombtype); else if (i == F_LJ14) bEner[i] = b14; else if (i == F_COUL14) bEner[i] = b14; else if (i == F_LJC14_Q || i == F_LJC_PAIRS_NB) bEner[i] = FALSE; else if ((i == F_DVDL) || (i == F_DKDL)) bEner[i] = (ir->efep != efepNO); else if (i == F_DGDL_CON) bEner[i] = (ir->efep != efepNO && bConstr); else if ((interaction_function[i].flags & IF_VSITE) || (i == F_CONSTR) || (i == F_SETTLE)) bEner[i] = FALSE; else if ((i == F_COUL_SR) || (i == F_EPOT) || (i == F_PRES) || (i==F_EQM)) bEner[i] = TRUE; else if ((i == F_ETOT) || (i == F_EKIN) || (i == F_TEMP)) bEner[i] = EI_DYNAMICS(ir->eI); else if (i == F_DISPCORR) bEner[i] = (ir->eDispCorr != edispcNO); else if (i == F_DISRESVIOL) bEner[i] = (gmx_mtop_ftype_count(mtop,F_DISRES) > 0); else if (i == F_ORIRESDEV) bEner[i] = (gmx_mtop_ftype_count(mtop,F_ORIRES) > 0); else if (i == F_CONNBONDS) bEner[i] = FALSE; else if (i == F_COM_PULL) bEner[i] = (ir->ePull == epullUMBRELLA || ir->ePull == epullCONST_F); else if (i == F_ECONSERVED) bEner[i] = ((ir->etc == etcNOSEHOOVER || ir->etc == etcVRESCALE) && ir->epc == epcNO); else bEner[i] = (gmx_mtop_ftype_count(mtop,i) > 0); } for(i=0; i<F_NRE; i++) if (bEner[i]) { ener_nm[f_nre]=interaction_function[i].longname; f_nre++; } epc = ir->epc; bTricl = TRICLINIC(ir->compress) || TRICLINIC(ir->deform); bDynBox = DYNAMIC_BOX(*ir); etc = ir->etc; /* Energy monitoring */ snew(md,1); md->ebin = mk_ebin(); md->ie = get_ebin_space(md->ebin,f_nre,ener_nm); if (nCrmsd) { /* This should be called directly after the call for md->ie, * such that md->iconrmsd follows directly in the list. */ md->iconrmsd = get_ebin_space(md->ebin,nCrmsd,conrmsd_nm); } if (bDynBox) md->ib = get_ebin_space(md->ebin, bTricl ? NTRICLBOXS : NBOXS, bTricl ? tricl_boxs_nm : boxs_nm); if (bConstrVir) { md->isvir = get_ebin_space(md->ebin,asize(sv_nm),sv_nm); md->ifvir = get_ebin_space(md->ebin,asize(fv_nm),fv_nm); } md->ivir = get_ebin_space(md->ebin,asize(vir_nm),vir_nm); md->ipres = get_ebin_space(md->ebin,asize(pres_nm),pres_nm); md->isurft = get_ebin_space(md->ebin,asize(surft_nm),surft_nm); if (epc == epcPARRINELLORAHMAN) { md->ipc = get_ebin_space(md->ebin,bTricl ? 6 : 3,boxvel_nm); } md->imu = get_ebin_space(md->ebin,asize(mu_nm),mu_nm); if (ir->cos_accel != 0) { md->ivcos = get_ebin_space(md->ebin,asize(vcos_nm),vcos_nm); md->ivisc = get_ebin_space(md->ebin,asize(visc_nm),visc_nm); } if (ir->rcoulomb > ir->rlist) bEInd[egCOULLR] = TRUE; if (!bBHAM) { if (ir->rvdw > ir->rlist) bEInd[egLJLR] = TRUE; } else { bEInd[egLJSR] = FALSE; bEInd[egBHAMSR] = TRUE; if (ir->rvdw > ir->rlist) bEInd[egBHAMLR] = TRUE; } if (b14) { bEInd[egLJ14] = TRUE; bEInd[egCOUL14] = TRUE; } md->nEc=0; for(i=0; (i<egNR); i++) if (bEInd[i]) md->nEc++; n=groups->grps[egcENER].nr; md->nEg=n; md->nE=(n*(n+1))/2; snew(md->igrp,md->nE); if (md->nE > 1) { n=0; snew(gnm,md->nEc); for(k=0; (k<md->nEc); k++) snew(gnm[k],STRLEN); for(i=0; (i<groups->grps[egcENER].nr); i++) { ni=groups->grps[egcENER].nm_ind[i]; for(j=i; (j<groups->grps[egcENER].nr); j++) { nj=groups->grps[egcENER].nm_ind[j]; for(k=kk=0; (k<egNR); k++) { if (bEInd[k]) { sprintf(gnm[kk],"%s:%s-%s",egrp_nm[k], *(groups->grpname[ni]),*(groups->grpname[nj])); kk++; } } md->igrp[n]=get_ebin_space(md->ebin,md->nEc,gnm); n++; } } for(k=0; (k<md->nEc); k++) sfree(gnm[k]); sfree(gnm); if (n != md->nE) gmx_incons("Number of energy terms wrong"); } md->nTC=groups->grps[egcTC].nr; snew(grpnms,md->nTC); for(i=0; (i<md->nTC); i++) { ni=groups->grps[egcTC].nm_ind[i]; sprintf(buf,"T-%s",*(groups->grpname[ni])); grpnms[i]=strdup(buf); } md->itemp=get_ebin_space(md->ebin,md->nTC,grpnms); sfree(*grpnms); if (etc == etcNOSEHOOVER) { for(i=0; (i<md->nTC); i++) { ni=groups->grps[egcTC].nm_ind[i]; sprintf(buf,"Xi-%s",*(groups->grpname[ni])); grpnms[i]=strdup(buf); } md->itc=get_ebin_space(md->ebin,md->nTC,grpnms); sfree(*grpnms); } else if (etc == etcBERENDSEN || etc == etcYES || etc == etcVRESCALE) { for(i=0; (i<md->nTC); i++) { ni=groups->grps[egcTC].nm_ind[i]; sprintf(buf,"Lamb-%s",*(groups->grpname[ni])); grpnms[i]=strdup(buf); } md->itc=get_ebin_space(md->ebin,md->nTC,grpnms); sfree(*grpnms); } sfree(grpnms); md->nU=groups->grps[egcACC].nr; if (md->nU > 1) { snew(grpnms,3*md->nU); for(i=0; (i<md->nU); i++) { ni=groups->grps[egcACC].nm_ind[i]; sprintf(buf,"Ux-%s",*(groups->grpname[ni])); grpnms[3*i+XX]=strdup(buf); sprintf(buf,"Uy-%s",*(groups->grpname[ni])); grpnms[3*i+YY]=strdup(buf); sprintf(buf,"Uz-%s",*(groups->grpname[ni])); grpnms[3*i+ZZ]=strdup(buf); } md->iu=get_ebin_space(md->ebin,3*md->nU,grpnms); sfree(*grpnms); sfree(grpnms); } if (fp_ene != -1) do_enxnms(fp_ene,&md->ebin->nener,&md->ebin->enm); return md; }