real do_pppm(FILE *log, bool bVerbose, rvec x[], rvec f[], real charge[], rvec box, real phi[], t_commrec *cr, t_nsborder *nsb, t_nrnb *nrnb) { real ener; int start,nr; start = START(nsb); nr = HOMENR(nsb); /* Make the grid empty */ clear_fftgrid(grid); /* First step: spreading the charges over the grid. */ spread_q(log,bVerbose,start,nr,x,charge,box,grid,nrnb); /* In the parallel code we have to sum the grids from neighbouring nodes */ if (PAR(cr)) sum_qgrid(cr,nsb,grid,TRUE); /* Second step: solving the poisson equation in Fourier space */ solve_pppm(log,cr,grid,ghat,box,bVerbose,nrnb); /* In the parallel code we have to sum once again... */ if (PAR(cr)) sum_qgrid(cr,nsb,grid,FALSE); /* Third and last step: gather the forces, energies and potential * from the grid. */ ener=gather_f(log,bVerbose,start,nr,x,f,charge,box,phi,grid,beta,nrnb); return ener; }
static void do_my_pme(FILE *fp,real tm,gmx_bool bVerbose,t_inputrec *ir, rvec x[],rvec xbuf[],rvec f[], real charge[],real qbuf[],real qqbuf[], matrix box,gmx_bool bSort, t_commrec *cr,t_nsborder *nsb,t_nrnb *nrnb, t_block *excl,real qtot, t_forcerec *fr,int index[],FILE *fp_xvg, int ngroups,unsigned short cENER[]) { real ener,vcorr,q,xx,dvdl=0,vdip,vcharge; tensor vir,vir_corr,vir_tot; rvec mu_tot[2]; int i,m,ii,ig,jg; real **epme,*qptr; /* Initiate local variables */ fr->f_el_recip = f; clear_mat(vir); clear_mat(vir_corr); if (ngroups > 1) { fprintf(fp,"There are %d energy groups\n",ngroups); snew(epme,ngroups); for(i=0; (i<ngroups); i++) snew(epme[i],ngroups); } /* Put x is in the box, this part needs to be parallellized properly */ /*put_atoms_in_box(box,nsb->natoms,x);*/ /* Here sorting of X (and q) is done. * Alternatively, one could just put the atoms in one of the * cr->nnodes slabs. That is much cheaper than sorting. */ for(i=0; (i<nsb->natoms); i++) index[i] = i; if (bSort) { xptr = x; qsort(index,nsb->natoms,sizeof(index[0]),comp_xptr); xptr = NULL; /* To trap unintentional use of the ptr */ } /* After sorting we only need the part that is to be computed on * this processor. We also compute the mu_tot here (system dipole) */ clear_rvec(mu_tot[0]); for(i=START(nsb); (i<START(nsb)+HOMENR(nsb)); i++) { ii = index[i]; q = charge[ii]; qbuf[i] = q; for(m=0; (m<DIM); m++) { xx = x[ii][m]; xbuf[i][m] = xx; mu_tot[0][m] += q*xx; } clear_rvec(f[ii]); } copy_rvec(mu_tot[0],mu_tot[1]); if (debug) { pr_rvec(debug,0,"qbuf",qbuf,nsb->natoms,TRUE); pr_rvecs(debug,0,"xbuf",xbuf,nsb->natoms); pr_rvecs(debug,0,"box",box,DIM); } for(ig=0; (ig<ngroups); ig++) { for(jg=ig; (jg<ngroups); jg++) { if (ngroups > 1) { for(i=START(nsb); (i<START(nsb)+HOMENR(nsb)); i++) { if ((cENER[i] == ig) || (cENER[i] == jg)) qqbuf[i] = qbuf[i]; else qqbuf[i] = 0; } qptr = qqbuf; } else qptr = qbuf; ener = do_pme(fp,bVerbose,ir,xbuf,f,qptr,qptr,box,cr, nsb,nrnb,vir,fr->ewaldcoeff,FALSE,0,&dvdl,FALSE); vcorr = ewald_LRcorrection(fp,nsb,cr,fr,qptr,qptr,excl,xbuf,box,mu_tot, ir->ewald_geometry,ir->epsilon_surface, 0,&dvdl,&vdip,&vcharge); gmx_sum(1,&ener,cr); gmx_sum(1,&vcorr,cr); if (ngroups > 1) epme[ig][jg] = ener+vcorr; } } if (ngroups > 1) { if (fp_xvg) fprintf(fp_xvg,"%10.3f",tm); for(ig=0; (ig<ngroups); ig++) { for(jg=ig; (jg<ngroups); jg++) { if (ig != jg) epme[ig][jg] -= epme[ig][ig]+epme[jg][jg]; if (fp_xvg) fprintf(fp_xvg," %12.5e",epme[ig][jg]); } } if (fp_xvg) fprintf(fp_xvg,"\n"); } else { fprintf(fp,"Time: %10.3f Energy: %12.5e Correction: %12.5e Total: %12.5e\n", tm,ener,vcorr,ener+vcorr); if (fp_xvg) fprintf(fp_xvg,"%10.3f %12.5e %12.5e %12.5e\n",tm,ener+vcorr,vdip,vcharge); if (bVerbose) { m_add(vir,vir_corr,vir_tot); gmx_sum(9,vir_tot[0],cr); pr_rvecs(fp,0,"virial",vir_tot,DIM); } fflush(fp); } }
real do_ewald(FILE *log, bool bVerbose, t_inputrec *ir, rvec x[], rvec f[], real charge[], rvec box, t_commrec *cr, t_nsborder *nsb, matrix lrvir, real ewaldcoeff) { static bool bFirst = TRUE; static int nx,ny,nz,kmax; static cvec **eir; static t_complex *tab_xy,*tab_qxyz; real factor=-1.0/(4*ewaldcoeff*ewaldcoeff); real energy; rvec lll; int lowiy,lowiz,ix,iy,iz,n; real tmp,cs,ss,ak,akv,mx,my,mz,m2; if (bFirst) { if (bVerbose) fprintf(log,"Will do ordinary reciprocal space Ewald sum.\n"); if (cr != NULL) { if (cr->nnodes > 1 || cr->nthreads>1) fatal_error(0,"No parallel Ewald. Use PME instead.\n"); } nx = ir->nkx+1; ny = ir->nky+1; nz = ir->nkz+1; kmax = max(nx,max(ny,nz)); snew(eir,kmax); for(n=0;n<kmax;n++) snew(eir[n],HOMENR(nsb)); snew(tab_xy,HOMENR(nsb)); snew(tab_qxyz,HOMENR(nsb)); bFirst = FALSE; } clear_mat(lrvir); calc_lll(box,lll); /* make tables for the structure factor parts */ tabulate_eir(HOMENR(nsb),x,kmax,eir,lll); lowiy=0; lowiz=1; energy=0; for(ix=0;ix<nx;ix++) { mx=ix*lll[XX]; for(iy=lowiy;iy<ny;iy++) { my=iy*lll[YY]; if(iy>=0) for(n=0;n<HOMENR(nsb);n++) tab_xy[n]=cmul(eir[ix][n][XX],eir[iy][n][YY]); else for(n=0;n<HOMENR(nsb);n++) tab_xy[n]=conjmul(eir[ix][n][XX],eir[-iy][n][YY]); for(iz=lowiz;iz<nz;iz++) { mz=iz*lll[ZZ]; m2=mx*mx+my*my+mz*mz; ak=exp(m2*factor)/m2; akv=2.0*ak*(1.0/m2-factor); if(iz>=0) for(n=0;n<HOMENR(nsb);n++) tab_qxyz[n]=rcmul(charge[n],cmul(tab_xy[n],eir[iz][n][ZZ])); else for(n=0;n<HOMENR(nsb);n++) tab_qxyz[n]=rcmul(charge[n],conjmul(tab_xy[n],eir[-iz][n][ZZ])); cs=ss=0; for(n=0;n<HOMENR(nsb);n++) { cs+=tab_qxyz[n].re; ss+=tab_qxyz[n].im; } energy+=ak*(cs*cs+ss*ss); tmp=akv*(cs*cs+ss*ss); lrvir[XX][XX]-=tmp*mx*mx; lrvir[XX][YY]-=tmp*mx*my; lrvir[XX][ZZ]-=tmp*mx*mz; lrvir[YY][YY]-=tmp*my*my; lrvir[YY][ZZ]-=tmp*my*mz; lrvir[ZZ][ZZ]-=tmp*mz*mz; for(n=0;n<HOMENR(nsb);n++) { tmp=ak*(cs*tab_qxyz[n].im-ss*tab_qxyz[n].re); f[n][XX]+=tmp*mx; f[n][YY]+=tmp*my; f[n][ZZ]+=tmp*mz; } lowiz=1-nz; } lowiy=1-ny; } } tmp=4.0*M_PI/(box[XX]*box[YY]*box[ZZ])*ONE_4PI_EPS0; for(n=0;n<HOMENR(nsb);n++) { f[n][XX]*=2*tmp; f[n][YY]*=2*tmp; f[n][ZZ]*=2*tmp; } lrvir[XX][XX]=-0.5*tmp*(lrvir[XX][XX]+energy); lrvir[XX][YY]=-0.5*tmp*(lrvir[XX][YY]); lrvir[XX][ZZ]=-0.5*tmp*(lrvir[XX][ZZ]); lrvir[YY][YY]=-0.5*tmp*(lrvir[YY][YY]+energy); lrvir[YY][ZZ]=-0.5*tmp*(lrvir[YY][ZZ]); lrvir[ZZ][ZZ]=-0.5*tmp*(lrvir[ZZ][ZZ]+energy); lrvir[YY][XX]=lrvir[XX][YY]; lrvir[ZZ][XX]=lrvir[XX][ZZ]; lrvir[ZZ][YY]=lrvir[YY][ZZ]; energy*=tmp; return energy; }
void init_md(t_commrec *cr,t_inputrec *ir,tensor box,real *t,real *t0, real *lambda,real *lam0,real *SAfactor, t_nrnb *mynrnb,bool *bTYZ,t_topology *top, int nfile,t_filenm fnm[],char **traj, char **xtc_traj,int *fp_ene, FILE **fp_dgdl,t_mdebin **mdebin,t_groups *grps, tensor force_vir,tensor pme_vir, tensor shake_vir,t_mdatoms *mdatoms,rvec mu_tot, bool *bNEMD,t_vcm **vcm,t_nsborder *nsb) { bool bBHAM,b14,bLR,bLJLR; int i; /* Initial values */ *t = *t0 = ir->init_t; if (ir->efep != efepNO) { *lambda = *lam0 = ir->init_lambda; } else { *lambda = *lam0 = 0.0; } if (ir->bSimAnn) { *SAfactor = 1.0 - *t0/ir->zero_temp_time; if (*SAfactor < 0) *SAfactor = 0; } else *SAfactor = 1.0; init_nrnb(mynrnb); /* Check Environment variables & other booleans */ #ifdef SPEC_CPU *bTYZ = FALSE; #else *bTYZ=getenv("TYZ") != NULL; #endif set_pot_bools(ir,top,&bLR,&bLJLR,&bBHAM,&b14); if (nfile != -1) { /* Filenames */ *traj = ftp2fn(efTRN,nfile,fnm); *xtc_traj = ftp2fn(efXTC,nfile,fnm); #ifndef SPEC_CPU if (MASTER(cr)) { *fp_ene = open_enx(ftp2fn(efENX,nfile,fnm),"w"); if ((fp_dgdl != NULL) && ir->efep!=efepNO) *fp_dgdl = xvgropen(opt2fn("-dgdl",nfile,fnm), "dG/d\\8l\\4","Time (ps)", "dG/d\\8l\\4 (kJ mol\\S-1\\N nm\\S-2\\N \\8l\\4\\S-1\\N)"); } else #endif *fp_ene = -1; *mdebin = init_mdebin(*fp_ene,grps,&(top->atoms),&(top->idef), bLR,bLJLR,bBHAM,b14,ir->efep!=efepNO,ir->epc, ir->eDispCorr,(TRICLINIC(ir->compress) || TRICLINIC(box)), (ir->etc==etcNOSEHOOVER),cr); } /* Initiate variables */ clear_mat(force_vir); clear_mat(pme_vir); clear_mat(shake_vir); clear_rvec(mu_tot); /* Set initial values for invmass etc. */ init_mdatoms(mdatoms,*lambda,TRUE); *vcm = init_vcm(stdlog,top,cr,mdatoms,START(nsb),HOMENR(nsb),ir->nstcomm); debug_gmx(); *bNEMD = (ir->opts.ngacc > 1) || (norm(ir->opts.acc[0]) > 0); if (ir->eI == eiSD) init_sd_consts(ir->opts.ngtc,ir->opts.tau_t,ir->delta_t); }
void do_shakefirst(FILE *log,bool bTYZ,real lambda,real ener[], t_parm *parm,t_nsborder *nsb,t_mdatoms *md, rvec x[],rvec vold[],rvec buf[],rvec f[], rvec v[],t_graph *graph,t_commrec *cr,t_nrnb *nrnb, t_groups *grps,t_forcerec *fr,t_topology *top, t_edsamyn *edyn,t_pull *pulldata) { int i,m,start,homenr,end,step; tensor shake_vir; double mass,tmass,vcm[4]; real dt=parm->ir.delta_t; real dt_1; if (count_constraints(top,cr)) { start = START(nsb); homenr = HOMENR(nsb); end = start+homenr; if (debug) fprintf(debug,"vcm: start=%d, homenr=%d, end=%d\n",start,homenr,end); /* Do a first SHAKE to reset particles... */ step = -2; if(log) fprintf(log,"\nConstraining the starting coordinates (step %d)\n",step); clear_mat(shake_vir); update(nsb->natoms,start,homenr,step,lambda,&ener[F_DVDL], parm,1.0,md,x,graph, NULL,NULL,vold,NULL,x,top,grps,shake_vir,cr,nrnb,bTYZ, FALSE,edyn,pulldata,FALSE); /* Compute coordinates at t=-dt, store them in buf */ /* for(i=0; (i<nsb->natoms); i++) {*/ for(i=start; (i<end); i++) { for(m=0; (m<DIM); m++) { f[i][m]=x[i][m]; buf[i][m]=x[i][m]-dt*v[i][m]; } } /* Shake the positions at t=-dt with the positions at t=0 * as reference coordinates. */ step = -1; if(log) fprintf(log,"\nConstraining the coordinates at t0-dt (step %d)\n",step); clear_mat(shake_vir); update(nsb->natoms,start,homenr, step,lambda,&ener[F_DVDL],parm,1.0,md,f,graph, NULL,NULL,vold,NULL,buf,top,grps,shake_vir,cr,nrnb,bTYZ,FALSE, edyn,pulldata,FALSE); /* Compute the velocities at t=-dt/2 using the coordinates at * t=-dt and t=0 * Compute velocity of center of mass and total mass */ for(m=0; (m<4); m++) vcm[m] = 0; dt_1=1.0/dt; for(i=start; (i<end); i++) { /*for(i=0; (i<nsb->natoms); i++) {*/ mass = md->massA[i]; for(m=0; (m<DIM); m++) { v[i][m]=(x[i][m]-f[i][m])*dt_1; vcm[m] += v[i][m]*mass; } vcm[3] += mass; } /* Compute the global sum of vcm */ if (debug) fprintf(debug,"vcm: %8.3f %8.3f %8.3f," " total mass = %12.5e\n",vcm[XX],vcm[YY],vcm[ZZ],vcm[3]); if (PAR(cr)) gmx_sumd(4,vcm,cr); tmass = vcm[3]; for(m=0; (m<DIM); m++) vcm[m] /= tmass; if (debug) fprintf(debug,"vcm: %8.3f %8.3f %8.3f," " total mass = %12.5e\n",vcm[XX],vcm[YY],vcm[ZZ],tmass); /* Now we have the velocity of center of mass, let's remove it */ for(i=start; (i<end); i++) { for(m=0; (m<DIM); m++) v[i][m] -= vcm[m]; } } }
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 ns(FILE *fp, t_forcerec *fr, rvec x[], rvec f[], matrix box, t_groups *grps, t_grpopts *opts, t_topology *top, t_mdatoms *md, t_commrec *cr, t_nrnb *nrnb, t_nsborder *nsb, int step, real lambda, real *dvdlambda) { static bool bFirst=TRUE; static int nDNL; char *ptr; int nsearch; if (bFirst) { #ifdef SPEC_CPU ptr = NULL; #else ptr=getenv("DUMPNL"); #endif if (ptr) { nDNL=atoi(ptr); fprintf(fp,"nDNL = %d\n",nDNL); } else nDNL=0; /* Allocate memory for the neighbor lists */ init_neighbor_list(fp,fr,HOMENR(nsb)); bFirst=FALSE; } if (fr->bTwinRange) fr->nlr=0; /* Whether or not we do dynamic load balancing, * workload contains the proper numbers of charge groups * to be searched. */ if (cr->nodeid == 0) fr->cg0=0; else fr->cg0=nsb->workload[cr->nodeid-1]; fr->hcg=nsb->workload[cr->nodeid]; nsearch = search_neighbours(fp,fr,x,box,top,grps,cr,nsb,nrnb,md, lambda,dvdlambda); if (debug) fprintf(debug,"nsearch = %d\n",nsearch); /* Check whether we have to do dynamic load balancing */ /*if ((nsb->nstDlb > 0) && (mod(step,nsb->nstDlb) == 0)) count_nb(cr,nsb,&(top->blocks[ebCGS]),nns,fr->nlr, &(top->idef),opts->ngener); */ if (nDNL > 0) dump_nblist(fp,fr,nDNL); }
static void check_solvent(FILE *fp,t_topology *top,t_forcerec *fr, t_mdatoms *md,t_nsborder *nsb) { /* This routine finds out whether a charge group can be used as * solvent in the innerloops. The routine should be called once * at the beginning of the MD program. */ t_block *cgs,*excl,*mols; atom_id *cgid; int i,j,m,j0,j1,nj,k,aj,ak,tjA,tjB,nl_m,nl_n,nl_o; int warncount; bool bOneCG; bool *bAllExcl,bAE,bOrder; bool *bHaveLJ,*bHaveCoul; cgs = &(top->blocks[ebCGS]); excl = &(top->atoms.excl); mols = &(top->blocks[ebMOLS]); if (fp) fprintf(fp,"Going to determine what solvent types we have.\n"); snew(fr->solvent_type,cgs->nr+1); snew(fr->mno_index,(cgs->nr+1)*3); /* Generate charge group number for all atoms */ cgid = make_invblock(cgs,cgs->nra); warncount=0; /* Loop over molecules */ if (fp) fprintf(fp,"There are %d molecules, %d charge groups and %d atoms\n", mols->nr,cgs->nr,cgs->nra); for(i=0; (i<mols->nr); i++) { /* Set boolean that determines whether the molecules consists of one CG */ bOneCG = TRUE; /* Set some counters */ j0 = mols->index[i]; j1 = mols->index[i+1]; nj = j1-j0; for(j=j0+1; (j<j1); j++) { bOneCG = bOneCG && (cgid[mols->a[j]] == cgid[mols->a[j-1]]); } if (fr->bSolvOpt && bOneCG && nj>1) { /* Check whether everything is excluded */ snew(bAllExcl,nj); bAE = TRUE; /* Loop over all atoms in molecule */ for(j=j0; (j<j1) && bAE; j++) { /* Set a flag for each atom in the molecule that determines whether * it is excluded or not */ for(k=0; (k<nj); k++) bAllExcl[k] = FALSE; /* Now check all the exclusions of this atom */ for(k=excl->index[j]; (k<excl->index[j+1]); k++) { ak = excl->a[k]; /* Consistency and range check */ if ((ak < j0) || (ak >= j1)) fatal_error(0,"Exclusion outside molecule? ak = %d, j0 = %d, j1 = 5d, mol is %d",ak,j0,j1,i); bAllExcl[ak-j0] = TRUE; } /* Now sum up the booleans */ for(k=0; (k<nj); k++) bAE = bAE && bAllExcl[k]; } if (bAE) { snew(bHaveCoul,nj); snew(bHaveLJ,nj); for(j=j0; (j<j1); j++) { /* Check for coulomb */ aj = mols->a[j]; bHaveCoul[j-j0] = ( (fabs(top->atoms.atom[aj].q ) > GMX_REAL_MIN) || (fabs(top->atoms.atom[aj].qB) > GMX_REAL_MIN)); /* Check for LJ. */ tjA = top->atoms.atom[aj].type; tjB = top->atoms.atom[aj].typeB; bHaveLJ[j-j0] = FALSE; for(k=0; (k<fr->ntype); k++) { if (fr->bBHAM) bHaveLJ[j-j0] = (bHaveLJ[j-j0] || (fabs(BHAMA(fr->nbfp,fr->ntype,tjA,k)) > GMX_REAL_MIN) || (fabs(BHAMB(fr->nbfp,fr->ntype,tjA,k)) > GMX_REAL_MIN) || (fabs(BHAMC(fr->nbfp,fr->ntype,tjA,k)) > GMX_REAL_MIN) || (fabs(BHAMA(fr->nbfp,fr->ntype,tjB,k)) > GMX_REAL_MIN) || (fabs(BHAMB(fr->nbfp,fr->ntype,tjB,k)) > GMX_REAL_MIN) || (fabs(BHAMC(fr->nbfp,fr->ntype,tjB,k)) > GMX_REAL_MIN)); else bHaveLJ[j-j0] = (bHaveLJ[j-j0] || (fabs(C6(fr->nbfp,fr->ntype,tjA,k)) > GMX_REAL_MIN) || (fabs(C12(fr->nbfp,fr->ntype,tjA,k)) > GMX_REAL_MIN) || (fabs(C6(fr->nbfp,fr->ntype,tjB,k)) > GMX_REAL_MIN) || (fabs(C12(fr->nbfp,fr->ntype,tjB,k)) > GMX_REAL_MIN)); } } /* Now we have determined what particles have which interactions * In the case of water-like molecules we only check for the number * of particles and the LJ, not for the Coulomb. Let's just assume * that the water loops are faster than the MNO loops anyway. DvdS */ /* No - there's another problem: To optimize the water * innerloop assumes the charge of the first i atom is constant * qO, and charge on atoms 2/3 is constant qH. /EL */ /* I won't write any altivec versions of the general solvent inner * loops. Thus, when USE_PPC_ALTIVEC is defined it is faster * to use the normal loops instead of the MNO solvent version. /EL */ aj=mols->a[j0]; if((nj==3) && bHaveCoul[0] && bHaveLJ[0] && !bHaveLJ[1] && !bHaveLJ[2] && fabs(top->atoms.atom[aj+1].q - top->atoms.atom[aj+2].q) < GMX_REAL_MIN) fr->solvent_type[cgid[aj]] = esolWATER; else { #ifdef USE_PPC_ALTIVEC fr->solvent_type[cgid[aj]] = esolNO; #else /* Time to compute M & N & O */ for(k=0; (k<nj) && (bHaveLJ[k] && bHaveCoul[k]); k++) ; nl_n = k; for(; (k<nj) && (!bHaveLJ[k] && bHaveCoul[k]); k++) ; nl_o = k; for(; (k<nj) && (bHaveLJ[k] && !bHaveCoul[k]); k++) ; nl_m = k; /* Now check whether we're at the end of the pack */ bOrder = FALSE; for(; (k<nj); k++) bOrder = bOrder || (bHaveLJ[k] || bHaveCoul[k]); if (bOrder) { /* If we have a solvent molecule with LJC everywhere, then * we shouldn't issue a warning. Only if we suspect something * could be better. */ if (nl_n != nj) { warncount++; if(warncount<11 && fp) fprintf(fp,"The order in molecule %d could be optimized" " for better performance\n",i); if(warncount==10 && fp) fprintf(fp,"(More than 10 molecules where the order can be optimized)\n"); } nl_m = nl_n = nl_o = nj; } fr->mno_index[cgid[aj]*3] = nl_m; fr->mno_index[cgid[aj]*3+1] = nl_n; fr->mno_index[cgid[aj]*3+2] = nl_o; fr->solvent_type[cgid[aj]] = esolMNO; #endif /* MNO solvent if not using altivec */ } /* Last check for perturbed atoms */ for(j=j0; (j<j1); j++) if (md->bPerturbed[mols->a[j]]) fr->solvent_type[cgid[mols->a[j0]]] = esolNO; sfree(bHaveLJ); sfree(bHaveCoul); } else { /* Turn off solvent optimization for all cg's in the molecule, * here there is only one. */ fr->solvent_type[cgid[mols->a[j0]]] = esolNO; } sfree(bAllExcl); } else { /* Turn off solvent optimization for all cg's in the molecule */ for(j=mols->index[i]; (j<mols->index[i+1]); j++) { fr->solvent_type[cgid[mols->a[j]]] = esolNO; } } } if (debug) { for(i=0; (i<cgs->nr); i++) fprintf(debug,"MNO: cg = %5d, m = %2d, n = %2d, o = %2d\n", i,fr->mno_index[3*i],fr->mno_index[3*i+1],fr->mno_index[3*i+2]); } /* Now compute the number of solvent molecules, could be merged with code above */ fr->nMNOMol = 0; fr->nWatMol = 0; for(m=0; m<3; m++) fr->nMNOav[m] = 0; for(i=0; i<mols->nr; i++) { j = mols->a[mols->index[i]]; if (j>=START(nsb) && j<START(nsb)+HOMENR(nsb)) { if (fr->solvent_type[cgid[j]] == esolMNO) { fr->nMNOMol++; for(m=0; m<3; m++) fr->nMNOav[m] += fr->mno_index[3*cgid[j]+m]; } else if (fr->solvent_type[cgid[j]] == esolWATER) fr->nWatMol++; } } if (fr->nMNOMol > 0) for(m=0; (m<3); m++) fr->nMNOav[m] /= fr->nMNOMol; sfree(cgid); if (fp) { fprintf(fp,"There are %d optimized solvent molecules on node %d\n", fr->nMNOMol,nsb->nodeid); if (fr->nMNOMol > 0) fprintf(fp," aver. nr. of atoms per molecule: vdwc %.1f coul %.1f vdw %.1f\n", fr->nMNOav[1],fr->nMNOav[2]-fr->nMNOav[1],fr->nMNOav[0]-fr->nMNOav[2]); fprintf(fp,"There are %d optimized water molecules on node %d\n", fr->nWatMol,nsb->nodeid); } }