Esempio n. 1
0
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;
}
Esempio n. 2
0
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);
  }
}
Esempio n. 3
0
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;
}
Esempio n. 4
0
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);

}
Esempio n. 5
0
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];
    }
  }
}
Esempio n. 6
0
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);
}
Esempio n. 7
0
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);
}
Esempio n. 8
0
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);
  }
}