void do_force(FILE *log,t_commrec *cr,t_commrec *mcr, t_parm *parm,t_nsborder *nsb,tensor vir_part,tensor pme_vir, int step,t_nrnb *nrnb,t_topology *top,t_groups *grps, rvec x[],rvec v[],rvec f[],rvec buf[], t_mdatoms *mdatoms,real ener[],t_fcdata *fcd,bool bVerbose, real lambda,t_graph *graph, bool bNS,bool bNBFonly,t_forcerec *fr, rvec mu_tot, bool bGatherOnly) { static rvec box_size; static real dvdl_lr = 0; int cg0,cg1,i,j; int start,homenr; static real mu_and_q[DIM+1]; real qsum; start = START(nsb); homenr = HOMENR(nsb); cg0 = CG0(nsb); cg1 = CG1(nsb); update_forcerec(log,fr,parm->box); /* Calculate total (local) dipole moment in a temporary common array. * This makes it possible to sum them over nodes faster. */ calc_mu_and_q(nsb,x,mdatoms->chargeT,mu_and_q,mu_and_q+DIM); if (fr->ePBC != epbcNONE) { /* Compute shift vectors every step, because of pressure coupling! */ if (parm->ir.epc != epcNO) calc_shifts(parm->box,box_size,fr->shift_vec); if (bNS) { put_charge_groups_in_box(log,cg0,cg1,parm->box,box_size, &(top->blocks[ebCGS]),x,fr->cg_cm); inc_nrnb(nrnb,eNR_RESETX,homenr); } else if (parm->ir.eI==eiSteep || parm->ir.eI==eiCG) unshift_self(graph,parm->box,x); } else if (bNS) calc_cgcm(log,cg0,cg1,&(top->blocks[ebCGS]),x,fr->cg_cm); if (bNS) { inc_nrnb(nrnb,eNR_CGCM,cg1-cg0); if (PAR(cr)) move_cgcm(log,cr,fr->cg_cm,nsb->workload); if (debug) pr_rvecs(debug,0,"cgcm",fr->cg_cm,nsb->cgtotal); } /* Communicate coordinates and sum dipole and net charge if necessary */ if (PAR(cr)) { move_x(log,cr->left,cr->right,x,nsb,nrnb); gmx_sum(DIM+1,mu_and_q,cr); } for(i=0;i<DIM;i++) mu_tot[i]=mu_and_q[i]; qsum=mu_and_q[DIM]; /* Reset energies */ reset_energies(&(parm->ir.opts),grps,fr,bNS,ener); if (bNS) { if (fr->ePBC != epbcNONE) /* Calculate intramolecular shift vectors to make molecules whole */ mk_mshift(log,graph,parm->box,x); /* Reset long range forces if necessary */ if (fr->bTwinRange) { clear_rvecs(nsb->natoms,fr->f_twin); clear_rvecs(SHIFTS,fr->fshift_twin); } /* Do the actual neighbour searching and if twin range electrostatics * also do the calculation of long range forces and energies. */ dvdl_lr = 0; ns(log,fr,x,f,parm->box,grps,&(parm->ir.opts),top,mdatoms, cr,nrnb,nsb,step,lambda,&dvdl_lr); } /* Reset PME/Ewald forces if necessary */ if (EEL_LR(fr->eeltype)) clear_rvecs(homenr,fr->f_pme+start); /* Copy long range forces into normal buffers */ if (fr->bTwinRange) { for(i=0; i<nsb->natoms; i++) copy_rvec(fr->f_twin[i],f[i]); for(i=0; i<SHIFTS; i++) copy_rvec(fr->fshift_twin[i],fr->fshift[i]); } else { clear_rvecs(nsb->natoms,f); clear_rvecs(SHIFTS,fr->fshift); } /* Compute the forces */ force(log,step,fr,&(parm->ir),&(top->idef),nsb,cr,mcr,nrnb,grps,mdatoms, top->atoms.grps[egcENER].nr,&(parm->ir.opts), x,f,ener,fcd,bVerbose,parm->box,lambda,graph,&(top->atoms.excl), bNBFonly,pme_vir,mu_tot,qsum,bGatherOnly); /* Take long range contribution to free energy into account */ ener[F_DVDL] += dvdl_lr; #ifdef DEBUG if (bNS) print_nrnb(log,nrnb); #endif /* The short-range virial from surrounding boxes */ clear_mat(vir_part); calc_vir(log,SHIFTS,fr->shift_vec,fr->fshift,vir_part); inc_nrnb(nrnb,eNR_VIRIAL,SHIFTS); if (debug) pr_rvecs(debug,0,"vir_shifts",vir_part,DIM); /* Compute forces due to electric field */ calc_f_el(start,homenr,mdatoms->chargeT,f,parm->ir.ex); /* When using PME/Ewald we compute the long range virial (pme_vir) there. * otherwise we do it based on long range forces from twin range * cut-off based calculation (or not at all). */ /* Communicate the forces */ if (PAR(cr)) move_f(log,cr->left,cr->right,f,buf,nsb,nrnb); }
void do_force(FILE *fplog,t_commrec *cr, t_inputrec *inputrec, int step,t_nrnb *nrnb,gmx_wallcycle_t wcycle, gmx_localtop_t *top, gmx_groups_t *groups, matrix box,rvec x[],history_t *hist, rvec f[],rvec buf[], tensor vir_force, t_mdatoms *mdatoms, gmx_enerdata_t *enerd,t_fcdata *fcd, real lambda,t_graph *graph, t_forcerec *fr,gmx_vsite_t *vsite,rvec mu_tot, real t,FILE *field,gmx_edsam_t ed, int flags) { static rvec box_size; int cg0,cg1,i,j; int start,homenr; static double mu[2*DIM]; rvec mu_tot_AB[2]; bool bSepDVDL,bStateChanged,bNS,bFillGrid,bCalcCGCM,bBS,bDoForces; matrix boxs; real e,v,dvdl; t_pbc pbc; float cycles_ppdpme,cycles_pme,cycles_force; start = mdatoms->start; homenr = mdatoms->homenr; bSepDVDL = (fr->bSepDVDL && do_per_step(step,inputrec->nstlog)); clear_mat(vir_force); if (PARTDECOMP(cr)) { pd_cg_range(cr,&cg0,&cg1); } else { cg0 = 0; if (DOMAINDECOMP(cr)) cg1 = cr->dd->ncg_tot; else cg1 = top->cgs.nr; if (fr->n_tpi > 0) cg1--; } bStateChanged = (flags & GMX_FORCE_STATECHANGED); bNS = (flags & GMX_FORCE_NS); bFillGrid = (bNS && bStateChanged); bCalcCGCM = (bFillGrid && !DOMAINDECOMP(cr)); bDoForces = (flags & GMX_FORCE_FORCES); if (bStateChanged) { update_forcerec(fplog,fr,box); /* Calculate total (local) dipole moment in a temporary common array. * This makes it possible to sum them over nodes faster. */ calc_mu(start,homenr, x,mdatoms->chargeA,mdatoms->chargeB,mdatoms->nChargePerturbed, mu,mu+DIM); } if (fr->ePBC != epbcNONE) { /* Compute shift vectors every step, * because of pressure coupling or box deformation! */ if (DYNAMIC_BOX(*inputrec) && bStateChanged) calc_shifts(box,fr->shift_vec); if (bCalcCGCM) { put_charge_groups_in_box(fplog,cg0,cg1,fr->ePBC,box, &(top->cgs),x,fr->cg_cm); inc_nrnb(nrnb,eNR_CGCM,homenr); inc_nrnb(nrnb,eNR_RESETX,cg1-cg0); } else if (EI_ENERGY_MINIMIZATION(inputrec->eI) && graph) { unshift_self(graph,box,x); } } else if (bCalcCGCM) { calc_cgcm(fplog,cg0,cg1,&(top->cgs),x,fr->cg_cm); inc_nrnb(nrnb,eNR_CGCM,homenr); } if (bCalcCGCM) { if (PAR(cr)) { move_cgcm(fplog,cr,fr->cg_cm); } if (gmx_debug_at) pr_rvecs(debug,0,"cgcm",fr->cg_cm,top->cgs.nr); } #ifdef GMX_MPI if (!(cr->duty & DUTY_PME)) { /* Send particle coordinates to the pme nodes. * Since this is only implemented for domain decomposition * and domain decomposition does not use the graph, * we do not need to worry about shifting. */ wallcycle_start(wcycle,ewcPP_PMESENDX); GMX_MPE_LOG(ev_send_coordinates_start); bBS = (inputrec->nwall == 2); if (bBS) { copy_mat(box,boxs); svmul(inputrec->wall_ewald_zfac,boxs[ZZ],boxs[ZZ]); } gmx_pme_send_x(cr,bBS ? boxs : box,x,mdatoms->nChargePerturbed,lambda); GMX_MPE_LOG(ev_send_coordinates_finish); wallcycle_stop(wcycle,ewcPP_PMESENDX); } #endif /* GMX_MPI */ /* Communicate coordinates and sum dipole if necessary */ if (PAR(cr)) { wallcycle_start(wcycle,ewcMOVEX); if (DOMAINDECOMP(cr)) { dd_move_x(cr->dd,box,x,buf); } else { move_x(fplog,cr,GMX_LEFT,GMX_RIGHT,x,nrnb); } /* When we don't need the total dipole we sum it in global_stat */ if (NEED_MUTOT(*inputrec)) gmx_sumd(2*DIM,mu,cr); wallcycle_stop(wcycle,ewcMOVEX); } for(i=0; i<2; i++) for(j=0;j<DIM;j++) mu_tot_AB[i][j] = mu[i*DIM + j]; if (fr->efep == efepNO) copy_rvec(mu_tot_AB[0],mu_tot); else for(j=0; j<DIM; j++) mu_tot[j] = (1.0 - lambda)*mu_tot_AB[0][j] + lambda*mu_tot_AB[1][j]; /* Reset energies */ reset_energies(&(inputrec->opts),fr,bNS,enerd,MASTER(cr)); if (bNS) { wallcycle_start(wcycle,ewcNS); if (graph && bStateChanged) /* Calculate intramolecular shift vectors to make molecules whole */ mk_mshift(fplog,graph,fr->ePBC,box,x); /* Reset long range forces if necessary */ if (fr->bTwinRange) { clear_rvecs(fr->f_twin_n,fr->f_twin); clear_rvecs(SHIFTS,fr->fshift_twin); } /* Do the actual neighbour searching and if twin range electrostatics * also do the calculation of long range forces and energies. */ dvdl = 0; ns(fplog,fr,x,f,box,groups,&(inputrec->opts),top,mdatoms, cr,nrnb,step,lambda,&dvdl,&enerd->grpp,bFillGrid,bDoForces); if (bSepDVDL) fprintf(fplog,sepdvdlformat,"LR non-bonded",0,dvdl); enerd->dvdl_lr = dvdl; enerd->term[F_DVDL] += dvdl; wallcycle_stop(wcycle,ewcNS); } if (DOMAINDECOMP(cr)) { if (!(cr->duty & DUTY_PME)) { wallcycle_start(wcycle,ewcPPDURINGPME); dd_force_flop_start(cr->dd,nrnb); } } /* Start the force cycle counter. * This counter is stopped in do_forcelow_level. * No parallel communication should occur while this counter is running, * since that will interfere with the dynamic load balancing. */ wallcycle_start(wcycle,ewcFORCE); if (bDoForces) { /* Reset PME/Ewald forces if necessary */ if (fr->bF_NoVirSum) { GMX_BARRIER(cr->mpi_comm_mygroup); if (fr->bDomDec) clear_rvecs(fr->f_novirsum_n,fr->f_novirsum); else clear_rvecs(homenr,fr->f_novirsum+start); GMX_BARRIER(cr->mpi_comm_mygroup); } /* Copy long range forces into normal buffers */ if (fr->bTwinRange) { for(i=0; i<fr->f_twin_n; i++) copy_rvec(fr->f_twin[i],f[i]); for(i=0; i<SHIFTS; i++) copy_rvec(fr->fshift_twin[i],fr->fshift[i]); } else { if (DOMAINDECOMP(cr)) clear_rvecs(cr->dd->nat_tot,f); else clear_rvecs(mdatoms->nr,f); clear_rvecs(SHIFTS,fr->fshift); } clear_rvec(fr->vir_diag_posres); GMX_BARRIER(cr->mpi_comm_mygroup); } if (inputrec->ePull == epullCONSTRAINT) clear_pull_forces(inputrec->pull); /* update QMMMrec, if necessary */ if(fr->bQMMM) update_QMMMrec(cr,fr,x,mdatoms,box,top); if ((flags & GMX_FORCE_BONDED) && top->idef.il[F_POSRES].nr > 0) { /* Position restraints always require full pbc */ set_pbc(&pbc,inputrec->ePBC,box); v = posres(top->idef.il[F_POSRES].nr,top->idef.il[F_POSRES].iatoms, top->idef.iparams_posres, (const rvec*)x,fr->f_novirsum,fr->vir_diag_posres, inputrec->ePBC==epbcNONE ? NULL : &pbc,lambda,&dvdl, fr->rc_scaling,fr->ePBC,fr->posres_com,fr->posres_comB); if (bSepDVDL) { fprintf(fplog,sepdvdlformat, interaction_function[F_POSRES].longname,v,dvdl); } enerd->term[F_POSRES] += v; enerd->term[F_DVDL] += dvdl; inc_nrnb(nrnb,eNR_POSRES,top->idef.il[F_POSRES].nr/2); } /* Compute the bonded and non-bonded forces */ do_force_lowlevel(fplog,step,fr,inputrec,&(top->idef), cr,nrnb,wcycle,mdatoms,&(inputrec->opts), x,hist,f,enerd,fcd,box,lambda,graph,&(top->excls),mu_tot_AB, flags,&cycles_force); GMX_BARRIER(cr->mpi_comm_mygroup); if (ed) { do_flood(fplog,cr,x,f,ed,box,step); } if (DOMAINDECOMP(cr)) { dd_force_flop_stop(cr->dd,nrnb); if (wcycle) dd_cycles_add(cr->dd,cycles_force,ddCyclF); } if (bDoForces) { /* Compute forces due to electric field */ calc_f_el(MASTER(cr) ? field : NULL, start,homenr,mdatoms->chargeA,x,f,inputrec->ex,inputrec->et,t); /* When using PME/Ewald we compute the long range virial there. * otherwise we do it based on long range forces from twin range * cut-off based calculation (or not at all). */ /* Communicate the forces */ if (PAR(cr)) { wallcycle_start(wcycle,ewcMOVEF); if (DOMAINDECOMP(cr)) { dd_move_f(cr->dd,f,buf,fr->fshift); /* Position restraint do not introduce inter-cg forces */ if (EEL_FULL(fr->eeltype) && cr->dd->n_intercg_excl) dd_move_f(cr->dd,fr->f_novirsum,buf,NULL); } else { move_f(fplog,cr,GMX_LEFT,GMX_RIGHT,f,buf,nrnb); } wallcycle_stop(wcycle,ewcMOVEF); } } if (bDoForces) { if (vsite) { wallcycle_start(wcycle,ewcVSITESPREAD); spread_vsite_f(fplog,vsite,x,f,fr->fshift,nrnb, &top->idef,fr->ePBC,fr->bMolPBC,graph,box,cr); wallcycle_stop(wcycle,ewcVSITESPREAD); } /* Calculation of the virial must be done after vsites! */ calc_virial(fplog,mdatoms->start,mdatoms->homenr,x,f, vir_force,graph,box,nrnb,fr,inputrec->ePBC); } if (inputrec->ePull == epullUMBRELLA || inputrec->ePull == epullCONST_F) { /* Calculate the center of mass forces, this requires communication, * which is why pull_potential is called close to other communication. * The virial contribution is calculated directly, * which is why we call pull_potential after calc_virial. */ set_pbc(&pbc,inputrec->ePBC,box); dvdl = 0; enerd->term[F_COM_PULL] = pull_potential(inputrec->ePull,inputrec->pull,mdatoms,&pbc, cr,t,lambda,x,f,vir_force,&dvdl); if (bSepDVDL) fprintf(fplog,sepdvdlformat,"Com pull",enerd->term[F_COM_PULL],dvdl); enerd->term[F_DVDL] += dvdl; } if (!(cr->duty & DUTY_PME)) { cycles_ppdpme = wallcycle_stop(wcycle,ewcPPDURINGPME); dd_cycles_add(cr->dd,cycles_ppdpme,ddCyclPPduringPME); } #ifdef GMX_MPI if (PAR(cr) && !(cr->duty & DUTY_PME)) { /* In case of node-splitting, the PP nodes receive the long-range * forces, virial and energy from the PME nodes here. */ wallcycle_start(wcycle,ewcPP_PMEWAITRECVF); dvdl = 0; gmx_pme_receive_f(cr,fr->f_novirsum,fr->vir_el_recip,&e,&dvdl, &cycles_pme); if (bSepDVDL) fprintf(fplog,sepdvdlformat,"PME mesh",e,dvdl); enerd->term[F_COUL_RECIP] += e; enerd->term[F_DVDL] += dvdl; if (wcycle) dd_cycles_add(cr->dd,cycles_pme,ddCyclPME); wallcycle_stop(wcycle,ewcPP_PMEWAITRECVF); } #endif if (bDoForces && fr->bF_NoVirSum) { if (vsite) { /* Spread the mesh force on virtual sites to the other particles... * This is parallellized. MPI communication is performed * if the constructing atoms aren't local. */ wallcycle_start(wcycle,ewcVSITESPREAD); spread_vsite_f(fplog,vsite,x,fr->f_novirsum,NULL,nrnb, &top->idef,fr->ePBC,fr->bMolPBC,graph,box,cr); wallcycle_stop(wcycle,ewcVSITESPREAD); } /* Now add the forces, this is local */ if (fr->bDomDec) { sum_forces(0,fr->f_novirsum_n,f,fr->f_novirsum); } else { sum_forces(start,start+homenr,f,fr->f_novirsum); } if (EEL_FULL(fr->eeltype)) { /* Add the mesh contribution to the virial */ m_add(vir_force,fr->vir_el_recip,vir_force); } if (debug) pr_rvecs(debug,0,"vir_force",vir_force,DIM); } /* Sum the potential energy terms from group contributions */ sum_epot(&(inputrec->opts),enerd); if (fr->print_force >= 0 && bDoForces) print_large_forces(stderr,mdatoms,cr,step,fr->print_force,x,f); }
void init_forcerec(FILE *fp, t_forcerec *fr, t_inputrec *ir, t_topology *top, t_commrec *cr, t_mdatoms *mdatoms, t_nsborder *nsb, matrix box, bool bMolEpot, char *tabfn, bool bNoSolvOpt) { int i,j,m,natoms,ngrp,tabelemsize; real q,zsq,nrdf,T; rvec box_size; double rtab; t_block *mols,*cgs; t_idef *idef; if (check_box(box)) fatal_error(0,check_box(box)); cgs = &(top->blocks[ebCGS]); mols = &(top->blocks[ebMOLS]); idef = &(top->idef); natoms = mdatoms->nr; /* Shell stuff */ fr->fc_stepsize = ir->fc_stepsize; /* Free energy */ fr->efep = ir->efep; fr->sc_alpha = ir->sc_alpha; fr->sc_sigma6 = pow(ir->sc_sigma,6); /* Neighbour searching stuff */ fr->bGrid = (ir->ns_type == ensGRID); fr->ndelta = ir->ndelta; fr->ePBC = ir->ePBC; fr->rlist = ir->rlist; fr->rlistlong = max(ir->rlist,max(ir->rcoulomb,ir->rvdw)); fr->eeltype = ir->coulombtype; fr->vdwtype = ir->vdwtype; fr->bTwinRange = fr->rlistlong > fr->rlist; fr->bEwald = fr->eeltype==eelPME || fr->eeltype==eelEWALD; fr->bvdwtab = fr->vdwtype != evdwCUT; fr->bRF = (fr->eeltype==eelRF || fr->eeltype==eelGRF) && fr->vdwtype==evdwCUT; fr->bcoultab = (fr->eeltype!=eelCUT && !fr->bRF) || fr->bEwald; #ifndef SPEC_CPU if (getenv("GMX_FORCE_TABLES")) { fr->bvdwtab = TRUE; fr->bcoultab = TRUE; } #endif if (fp) { fprintf(fp,"Table routines are used for coulomb: %s\n",bool_names[fr->bcoultab]); fprintf(fp,"Table routines are used for vdw: %s\n",bool_names[fr->bvdwtab ]); } /* Tables are used for direct ewald sum */ if(fr->bEwald) { fr->ewaldcoeff=calc_ewaldcoeff(ir->rcoulomb, ir->ewald_rtol); if (fp) fprintf(fp,"Using a Gaussian width (1/beta) of %g nm for Ewald\n", 1/fr->ewaldcoeff); } /* Domain decomposition parallellism... */ fr->bDomDecomp = ir->bDomDecomp; fr->Dimension = ir->decomp_dir; /* Electrostatics */ fr->epsilon_r = ir->epsilon_r; fr->fudgeQQ = ir->fudgeQQ; fr->rcoulomb_switch = ir->rcoulomb_switch; fr->rcoulomb = ir->rcoulomb; #ifndef SPEC_CPU if (bNoSolvOpt || getenv("GMX_NO_SOLV_OPT")) fr->bSolvOpt = FALSE; else #endif fr->bSolvOpt = TRUE; /* Parameters for generalized RF */ fr->zsquare = 0.0; fr->temp = 0.0; if (fr->eeltype == eelGRF) { zsq = 0.0; for (i=0; (i<cgs->nr); i++) { q = 0; for(j=cgs->index[i]; (j<cgs->index[i+1]); j++) q+=mdatoms->chargeT[cgs->a[j]]; if (fabs(q) > GMX_REAL_MIN) /* Changed from square to fabs 990314 DvdS * Does not make a difference for monovalent ions, but doe for * divalent ions (Ca2+!!) */ zsq += fabs(q); } fr->zsquare = zsq; T = 0.0; nrdf = 0.0; for(i=0; (i<ir->opts.ngtc); i++) { nrdf += ir->opts.nrdf[i]; T += (ir->opts.nrdf[i] * ir->opts.ref_t[i]); } if (nrdf < GMX_REAL_MIN) fatal_error(0,"No degrees of freedom!"); fr->temp = T/nrdf; } else if (EEL_LR(fr->eeltype) || (fr->eeltype == eelSHIFT) || (fr->eeltype == eelUSER) || (fr->eeltype == eelSWITCH)) { /* We must use the long range cut-off for neighboursearching... * An extra range of e.g. 0.1 nm (half the size of a charge group) * is necessary for neighboursearching. This allows diffusion * into the cut-off range (between neighborlist updates), * and gives more accurate forces because all atoms within the short-range * cut-off rc must be taken into account, while the ns criterium takes * only those with the center of geometry within the cut-off. * (therefore we have to add half the size of a charge group, plus * something to account for diffusion if we have nstlist > 1) */ for(m=0; (m<DIM); m++) box_size[m]=box[m][m]; if (fr->phi == NULL) snew(fr->phi,mdatoms->nr); if ((fr->eeltype==eelPPPM) || (fr->eeltype==eelPOISSON) || (fr->eeltype == eelSHIFT && fr->rcoulomb > fr->rcoulomb_switch)) set_shift_consts(fp,fr->rcoulomb_switch,fr->rcoulomb,box_size,fr); } /* Initiate arrays */ if (fr->bTwinRange) { snew(fr->f_twin,natoms); snew(fr->fshift_twin,SHIFTS); } if (EEL_LR(fr->eeltype)) { snew(fr->f_pme,natoms); } /* Mask that says whether or not this NBF list should be computed */ /* if (fr->bMask == NULL) { ngrp = ir->opts.ngener*ir->opts.ngener; snew(fr->bMask,ngrp);*/ /* Defaults to always */ /* for(i=0; (i<ngrp); i++) fr->bMask[i] = TRUE; }*/ if (fr->cg_cm == NULL) snew(fr->cg_cm,cgs->nr); if (fr->shift_vec == NULL) snew(fr->shift_vec,SHIFTS); if (fr->fshift == NULL) snew(fr->fshift,SHIFTS); if (bMolEpot && (fr->nmol==0)) { fr->nmol=mols->nr; fr->mol_nr=make_invblock(mols,natoms); snew(fr->mol_epot,fr->nmol); fr->nstcalc=ir->nstenergy; } if (fr->nbfp == NULL) { fr->ntype = idef->atnr; fr->bBHAM = (idef->functype[0] == F_BHAM); fr->nbfp = mk_nbfp(idef,fr->bBHAM); } /* Copy the energy group exclusions */ fr->eg_excl = ir->opts.eg_excl; /* Van der Waals stuff */ fr->rvdw = ir->rvdw; fr->rvdw_switch = ir->rvdw_switch; if ((fr->vdwtype != evdwCUT) && (fr->vdwtype != evdwUSER) && !fr->bBHAM) { if (fr->rvdw_switch >= fr->rvdw) fatal_error(0,"rvdw_switch (%g) must be < rvdw (%g)", fr->rvdw_switch,fr->rvdw); if (fp) fprintf(fp,"Using %s Lennard-Jones, switch between %g and %g nm\n", (fr->eeltype==eelSWITCH) ? "switched":"shifted", fr->rvdw_switch,fr->rvdw); } if (fp) fprintf(fp,"Cut-off's: NS: %g Coulomb: %g %s: %g\n", fr->rlist,fr->rcoulomb,fr->bBHAM ? "BHAM":"LJ",fr->rvdw); if (ir->eDispCorr != edispcNO) set_avcsix(fp,fr,mdatoms); if (fr->bBHAM) set_bham_b_max(fp,fr,mdatoms); /* Now update the rest of the vars */ update_forcerec(fp,fr,box); /* if we are using LR electrostatics, and they are tabulated, * the tables will contain shifted coulomb interactions. * Since we want to use the non-shifted ones for 1-4 * coulombic interactions, we must have an extra set of * tables. This should be done in tables.c, instead of this * ugly hack, but it works for now... */ #define MAX_14_DIST 1.0 /* Shell to account for the maximum chargegroup radius (2*0.2 nm) * * and diffusion during nstlist steps (0.2 nm) */ #define TAB_EXT 0.6 /* Construct tables. * A little unnecessary to make both vdw and coul tables sometimes, * but what the heck... */ if (fr->bcoultab || fr->bvdwtab) { if (EEL_LR(fr->eeltype)) { bool bcoulsave,bvdwsave; /* generate extra tables for 1-4 interactions only * fake the forcerec so make_tables thinks it should * just create the non shifted version */ bcoulsave=fr->bcoultab; bvdwsave=fr->bvdwtab; fr->bcoultab=FALSE; fr->bvdwtab=FALSE; fr->rtab=MAX_14_DIST; make_tables(fp,fr,MASTER(cr),tabfn); fr->bcoultab=bcoulsave; fr->bvdwtab=bvdwsave; fr->coulvdw14tab=fr->coulvdwtab; fr->coulvdwtab=NULL; } fr->rtab = max(fr->rlistlong+TAB_EXT,MAX_14_DIST); } else if (fr->efep != efepNO) { if (fr->rlistlong < GMX_REAL_MIN) { char *ptr,*envvar="FEP_TABLE_LENGTH"; fr->rtab = 5; #ifdef SPEC_CPU ptr = NULL; #else ptr = getenv(envvar); #endif if (ptr) { sscanf(ptr,"%lf",&rtab); fr->rtab = rtab; } if (fp) fprintf(fp,"\nNote: Setting the free energy table length to %g nm\n" " You can set this value with the environment variable %s" "\n\n",fr->rtab,envvar); } else fr->rtab = max(fr->rlistlong+TAB_EXT,MAX_14_DIST); } else fr->rtab = MAX_14_DIST; /* make tables for ordinary interactions */ make_tables(fp,fr,MASTER(cr),tabfn); if(!(EEL_LR(fr->eeltype) && (fr->bcoultab || fr->bvdwtab))) fr->coulvdw14tab=fr->coulvdwtab; /* Copy the contents of the table to separate coulomb and LJ * tables too, to improve cache performance. */ tabelemsize=fr->bBHAM ? 16 : 12; snew(fr->coultab,4*(fr->ntab+1)*sizeof(real)); snew(fr->vdwtab,(tabelemsize-4)*(fr->ntab+1)*sizeof(real)); for(i=0; i<=fr->ntab; i++) { for(j=0; j<4; j++) fr->coultab[4*i+j]=fr->coulvdwtab[tabelemsize*i+j]; for(j=0; j<tabelemsize-4; j++) fr->vdwtab[(tabelemsize-4)*i+j]=fr->coulvdwtab[tabelemsize*i+4+j]; } if (!fr->mno_index) check_solvent(fp,top,fr,mdatoms,nsb); }