static void calc_virial(FILE *fplog,int start,int homenr,rvec x[],rvec f[],
			tensor vir_part,t_graph *graph,matrix box,
			t_nrnb *nrnb,const t_forcerec *fr,int ePBC)
{
  int i,j;
  tensor virtest;

  /* The short-range virial from surrounding boxes */
  clear_mat(vir_part);
  calc_vir(fplog,SHIFTS,fr->shift_vec,fr->fshift,vir_part,ePBC==epbcSCREW,box);
  inc_nrnb(nrnb,eNR_VIRIAL,SHIFTS);
  
  /* Calculate partial virial, for local atoms only, based on short range. 
   * Total virial is computed in global_stat, called from do_md 
   */
  f_calc_vir(fplog,start,start+homenr,x,f,vir_part,graph,box);
  inc_nrnb(nrnb,eNR_VIRIAL,homenr);

  /* Add position restraint contribution */
  for(i=0; i<DIM; i++) {
    vir_part[i][i] += fr->vir_diag_posres[i];
  }

  /* Add wall contribution */
  for(i=0; i<DIM; i++) {
    vir_part[i][ZZ] += fr->vir_wall_z[i];
  }

  if (debug)
    pr_rvecs(debug,0,"vir_part",vir_part,DIM);
}
Example #2
0
void solve_pppm(FILE *fp,t_commrec *cr,
		t_fftgrid *grid,real ***ghat,rvec box,
		bool bVerbose,t_nrnb *nrnb)
{
  int  ntot,npppm;
  
/*  if (bVerbose) 
    print_fftgrid(fp,"Q-Real",grid,grid->nxyz,"qreal.pdb",box,TRUE);*/
  
  gmxfft3D(grid,FFTW_FORWARD,cr);
  
/*  if (bVerbose) {
    print_fftgrid(fp,"Q-k",grid,1.0,"qk-re.pdb",box,TRUE);
    print_fftgrid(fp,"Q-k",grid,1.0,"qk-im.pdb",box,FALSE);
    fprintf(stderr,"Doing convolution\n");
    }*/
  
  convolution(fp,bVerbose,grid,ghat,cr); 
  
  if (bVerbose) 
/*    print_fftgrid(fp,"Convolution",grid,1.0,
      "convolute.pdb",box,TRUE);*/
  
  gmxfft3D(grid,FFTW_BACKWARD,cr);
  
/*  if (bVerbose) 
    print_fftgrid(fp,"Potential",grid,1.0,"pot.pdb",box,TRUE);*/
  
  ntot  = grid->nxyz;  
  npppm = ntot*log((real)ntot)/log(2.0);
  inc_nrnb(nrnb,eNR_FFT,2*npppm);
  inc_nrnb(nrnb,eNR_CONV,ntot);
}
Example #3
0
void berendsen_pscale(t_inputrec *ir,matrix mu,
		      matrix box,matrix box_rel,
		      int start,int nr_atoms,
		      rvec x[],unsigned short cFREEZE[],
		      t_nrnb *nrnb)
{
  ivec   *nFreeze=ir->opts.nFreeze;
  int    n,d,g=0;
      
  /* Scale the positions */
  for (n=start; n<start+nr_atoms; n++) {
    if (cFREEZE)
      g = cFREEZE[n];
    
    if (!nFreeze[g][XX])
      x[n][XX] = mu[XX][XX]*x[n][XX]+mu[YY][XX]*x[n][YY]+mu[ZZ][XX]*x[n][ZZ];
    if (!nFreeze[g][YY])
      x[n][YY] = mu[YY][YY]*x[n][YY]+mu[ZZ][YY]*x[n][ZZ];
    if (!nFreeze[g][ZZ])
      x[n][ZZ] = mu[ZZ][ZZ]*x[n][ZZ];
  }
  /* compute final boxlengths */
  for (d=0; d<DIM; d++) {
    box[d][XX] = mu[XX][XX]*box[d][XX]+mu[YY][XX]*box[d][YY]+mu[ZZ][XX]*box[d][ZZ];
    box[d][YY] = mu[YY][YY]*box[d][YY]+mu[ZZ][YY]*box[d][ZZ];
    box[d][ZZ] = mu[ZZ][ZZ]*box[d][ZZ];
  }      

  preserve_box_shape(ir,box_rel,box);
  
  /* (un)shifting should NOT be done after this,
   * since the box vectors might have changed
   */
  inc_nrnb(nrnb,eNR_PCOUPL,nr_atoms);
}
void
posres_wrapper(t_nrnb             *nrnb,
               const t_idef       *idef,
               const struct t_pbc *pbc,
               const rvec          x[],
               gmx_enerdata_t     *enerd,
               real               *lambda,
               t_forcerec         *fr)
{
    real  v, dvdl;

    dvdl = 0;
    v    = posres(idef->il[F_POSRES].nr, idef->il[F_POSRES].iatoms,
                  idef->iparams_posres,
                  x, fr->f_novirsum, fr->vir_diag_posres,
                  fr->ePBC == epbcNONE ? NULL : pbc,
                  lambda[efptRESTRAINT], &dvdl,
                  fr->rc_scaling, fr->ePBC, fr->posres_com, fr->posres_comB);
    enerd->term[F_POSRES] += v;
    /* If just the force constant changes, the FEP term is linear,
     * but if k changes, it is not.
     */
    enerd->dvdl_nonlin[efptRESTRAINT] += dvdl;
    inc_nrnb(nrnb, eNR_POSRES, idef->il[F_POSRES].nr/2);
}
Example #5
0
void calc_ke_part_visc(matrix box,rvec x[],rvec v[],
                       t_grpopts *opts,t_mdatoms *md,
		       gmx_ekindata_t *ekind,
                       t_nrnb *nrnb,real lambda)
{
  int          start=md->start,homenr=md->homenr;
  int          g,d,n,gt=0;
  rvec         v_corrt;
  real         hm;
  t_grp_tcstat *tcstat=ekind->tcstat;
  t_cos_acc    *cosacc=&(ekind->cosacc);
  real         dekindl;
  real         fac,cosz;
  double       mvcos;

  for(g=0; g<opts->ngtc; g++) {
    copy_mat(ekind->tcstat[g].ekinh,ekind->tcstat[g].ekinh_old);
    clear_mat(ekind->tcstat[g].ekinh);
  }
  ekind->dekindl_old = ekind->dekindl;

  fac = 2*M_PI/box[ZZ][ZZ];
  mvcos = 0;
  dekindl = 0;
  for(n=start; n<start+homenr; n++) {
    if (md->cTC)
      gt = md->cTC[n];
    hm   = 0.5*md->massT[n];

    /* Note that the times of x and v differ by half a step */
    cosz         = cos(fac*x[n][ZZ]);
    /* Calculate the amplitude of the new velocity profile */
    mvcos       += 2*cosz*md->massT[n]*v[n][XX];

    copy_rvec(v[n],v_corrt);
    /* Subtract the profile for the kinetic energy */
    v_corrt[XX] -= cosz*cosacc->vcos;
    for(d=0; (d<DIM); d++) {
      tcstat[gt].ekinh[XX][d]+=hm*v_corrt[XX]*v_corrt[d];
      tcstat[gt].ekinh[YY][d]+=hm*v_corrt[YY]*v_corrt[d];
      tcstat[gt].ekinh[ZZ][d]+=hm*v_corrt[ZZ]*v_corrt[d];
    }
    if(md->nPerturbed && md->bPerturbed[n])
      dekindl -= 0.5*(md->massB[n] - md->massA[n])*iprod(v_corrt,v_corrt);
  }
  ekind->dekindl = dekindl;
  cosacc->mvcos = mvcos;

  inc_nrnb(nrnb,eNR_EKIN,homenr);
}
/*! \brief Helper function that wraps calls to fbposres for
    free-energy perturbation */
void fbposres_wrapper(t_nrnb             *nrnb,
                      const t_idef       *idef,
                      const struct t_pbc *pbc,
                      const rvec          x[],
                      gmx_enerdata_t     *enerd,
                      t_forcerec         *fr)
{
    real  v;

    v = fbposres(idef->il[F_FBPOSRES].nr, idef->il[F_FBPOSRES].iatoms,
                 idef->iparams_fbposres,
                 x, fr->f_novirsum, fr->vir_diag_posres,
                 fr->ePBC == epbcNONE ? NULL : pbc,
                 fr->rc_scaling, fr->ePBC, fr->posres_com);
    enerd->term[F_FBPOSRES] += v;
    inc_nrnb(nrnb, eNR_FBPOSRES, idef->il[F_FBPOSRES].nr/2);
}
Example #7
0
void calc_ke_part(rvec v[],t_grpopts *opts,t_mdatoms *md,
		  gmx_ekindata_t *ekind,
                  t_nrnb *nrnb,real lambda)
{
  int          start=md->start,homenr=md->homenr;
  int          g,d,n,ga=0,gt=0;
  rvec         v_corrt;
  real         hm;
  t_grp_tcstat *tcstat=ekind->tcstat;
  t_grp_acc    *grpstat=ekind->grpstat;
  real         dekindl;

  /* group velocities are calculated in update_ekindata and
   * accumulated in acumulate_groups.
   * Now the partial global and groups ekin.
   */
  for(g=0; (g<opts->ngtc); g++) {
    copy_mat(ekind->tcstat[g].ekinh,ekind->tcstat[g].ekinh_old);
    clear_mat(ekind->tcstat[g].ekinh);
  }
  ekind->dekindl_old = ekind->dekindl;

  dekindl = 0;
  for(n=start; (n<start+homenr); n++) {
    if (md->cACC)
      ga = md->cACC[n];
    if (md->cTC)
      gt = md->cTC[n];
    hm   = 0.5*md->massT[n];

    for(d=0; (d<DIM); d++) {
      v_corrt[d] = v[n][d] - grpstat[ga].u[d];
    }
    for(d=0; (d<DIM); d++) {
      tcstat[gt].ekinh[XX][d]+=hm*v_corrt[XX]*v_corrt[d];
      tcstat[gt].ekinh[YY][d]+=hm*v_corrt[YY]*v_corrt[d];
      tcstat[gt].ekinh[ZZ][d]+=hm*v_corrt[ZZ]*v_corrt[d];
    }
    if (md->nMassPerturbed && md->bPerturbed[n])
      dekindl -= 0.5*(md->massB[n] - md->massA[n])*iprod(v_corrt,v_corrt);
  }
  ekind->dekindl = dekindl;

  inc_nrnb(nrnb,eNR_EKIN,homenr);
}
Example #8
0
void calc_virial(FILE *log,int start,int homenr,rvec x[],rvec f[],
		 tensor vir_part,tensor pme_vir,
		 t_graph *graph,matrix box,
		 t_nrnb *nrnb,t_forcerec *fr,bool bTweak)
{
  int i,j;
  tensor virtest;
  
  /* Now it is time for the short range virial. At this timepoint vir_part
   * already contains the virial from surrounding boxes.
   * Calculate partial virial, for local atoms only, based on short range. 
   * Total virial is computed in global_stat, called from do_md 
   */
  f_calc_vir(log,start,start+homenr,x,f,vir_part,graph,box);
  inc_nrnb(nrnb,eNR_VIRIAL,homenr);

  /* Add up the long range forces if necessary */
  /* if (!bTweak) {
    sum_lrforces(f,fr,start,homenr);
    }*/
  
  /* Add up virial if necessary */  
  if (EEL_LR(fr->eeltype) && (fr->eeltype != eelPPPM)) {
    if (debug && bTweak) {
      clear_mat(virtest);
      f_calc_vir(log,start,start+homenr,x,fr->f_pme,virtest,graph,box);
      pr_rvecs(debug,0,"virtest",virtest,DIM);
      pr_rvecs(debug,0,"pme_vir",pme_vir,DIM);
    }    
    /* PPPM virial sucks */
    if (!bTweak)
      for(i=0; (i<DIM); i++) 
	for(j=0; (j<DIM); j++) 
	  vir_part[i][j]+=pme_vir[i][j];
  }
  if (debug)
    pr_rvecs(debug,0,"vir_part",vir_part,DIM);
}
Example #9
0
gmx_bool constrain_lincs(FILE *fplog,gmx_bool bLog,gmx_bool bEner,
                     t_inputrec *ir,
                     gmx_large_int_t step,
                     struct gmx_lincsdata *lincsd,t_mdatoms *md,
                     t_commrec *cr, 
                     rvec *x,rvec *xprime,rvec *min_proj,matrix box,
                     real lambda,real *dvdlambda,
                     real invdt,rvec *v,
                     gmx_bool bCalcVir,tensor rmdr,
                     int econq,
                     t_nrnb *nrnb,
                     int maxwarn,int *warncount)
{
    char  buf[STRLEN],buf2[22],buf3[STRLEN];
    int   i,warn,p_imax,error;
    real  ncons_loc,p_ssd,p_max;
    t_pbc pbc,*pbc_null;
    rvec  dx;
    gmx_bool  bOK;
    
    bOK = TRUE;
    
    if (lincsd->nc == 0 && cr->dd == NULL)
    {
        if (bLog || bEner)
        {
            lincsd->rmsd_data[0] = 0;
            if (ir->eI == eiSD2 && v == NULL)
            {
                i = 2;
            }
            else
            {
                i = 1;
            }
            lincsd->rmsd_data[i] = 0;
        }
        
        return bOK;
    }
    
    /* We do not need full pbc when constraints do not cross charge groups,
     * i.e. when dd->constraint_comm==NULL
     */
    if ((cr->dd || ir->bPeriodicMols) && !(cr->dd && cr->dd->constraint_comm==NULL))
    {
        /* With pbc=screw the screw has been changed to a shift
         * by the constraint coordinate communication routine,
         * so that here we can use normal pbc.
         */
        pbc_null = set_pbc_dd(&pbc,ir->ePBC,cr->dd,FALSE,box);
    }
    else
    {
        pbc_null = NULL;
    }
    if (cr->dd)
    {
        /* Communicate the coordinates required for the non-local constraints */
        dd_move_x_constraints(cr->dd,box,x,xprime);
        /* dump_conf(dd,lincsd,NULL,"con",TRUE,xprime,box); */
    }
	else if (PARTDECOMP(cr))
	{
		pd_move_x_constraints(cr,x,xprime);
	}	
	
    if (econq == econqCoord)
    {
        if (ir->efep != efepNO)
        {
            if (md->nMassPerturbed && lincsd->matlam != md->lambda)
            {
                set_lincs_matrix(lincsd,md->invmass,md->lambda);
            }
            
            for(i=0; i<lincsd->nc; i++)
            {
                lincsd->bllen[i] = lincsd->bllen0[i] + lambda*lincsd->ddist[i];
            }
        }
        
        if (lincsd->ncg_flex)
        {
            /* Set the flexible constraint lengths to the old lengths */
            if (pbc_null)
            {
                for(i=0; i<lincsd->nc; i++)
                {
                    if (lincsd->bllen[i] == 0) {
                        pbc_dx_aiuc(pbc_null,x[lincsd->bla[2*i]],x[lincsd->bla[2*i+1]],dx);
                        lincsd->bllen[i] = norm(dx);
                    }
                }
            }
            else
            {
                for(i=0; i<lincsd->nc; i++)
                {
                    if (lincsd->bllen[i] == 0)
                    {
                        lincsd->bllen[i] =
                            sqrt(distance2(x[lincsd->bla[2*i]],
                                           x[lincsd->bla[2*i+1]]));
                    }
                }
            }
        }
        
        if (bLog && fplog)
        {
            cconerr(cr->dd,lincsd->nc,lincsd->bla,lincsd->bllen,xprime,pbc_null,
                    &ncons_loc,&p_ssd,&p_max,&p_imax);
        }
        
        do_lincs(x,xprime,box,pbc_null,lincsd,md->invmass,cr,
                 ir->LincsWarnAngle,&warn,
                 invdt,v,bCalcVir,rmdr);
        
        if (ir->efep != efepNO)
        {
            real dt_2,dvdl=0;
            
            dt_2 = 1.0/(ir->delta_t*ir->delta_t);
            for(i=0; (i<lincsd->nc); i++)
            {
                dvdl += lincsd->lambda[i]*dt_2*lincsd->ddist[i];
            }
            *dvdlambda += dvdl;
		}
        
        if (bLog && fplog && lincsd->nc > 0)
        {
            fprintf(fplog,"   Rel. Constraint Deviation:  RMS         MAX     between atoms\n");
            fprintf(fplog,"       Before LINCS          %.6f    %.6f %6d %6d\n",
                    sqrt(p_ssd/ncons_loc),p_max,
                    ddglatnr(cr->dd,lincsd->bla[2*p_imax]),
                    ddglatnr(cr->dd,lincsd->bla[2*p_imax+1]));
        }
        if (bLog || bEner)
        {
            cconerr(cr->dd,lincsd->nc,lincsd->bla,lincsd->bllen,xprime,pbc_null,
                    &ncons_loc,&p_ssd,&p_max,&p_imax);
            /* Check if we are doing the second part of SD */
            if (ir->eI == eiSD2 && v == NULL)
            {
                i = 2;
            }
            else
            {
                i = 1;
            }
            lincsd->rmsd_data[0] = ncons_loc;
            lincsd->rmsd_data[i] = p_ssd;
        }
        else
        {
            lincsd->rmsd_data[0] = 0;
            lincsd->rmsd_data[1] = 0;
            lincsd->rmsd_data[2] = 0;
        }
        if (bLog && fplog && lincsd->nc > 0)
        {
            fprintf(fplog,
                    "        After LINCS          %.6f    %.6f %6d %6d\n\n",
                    sqrt(p_ssd/ncons_loc),p_max,
                    ddglatnr(cr->dd,lincsd->bla[2*p_imax]),
                    ddglatnr(cr->dd,lincsd->bla[2*p_imax+1]));
        }
        
        if (warn > 0)
        {
            if (maxwarn >= 0)
            {
                cconerr(cr->dd,lincsd->nc,lincsd->bla,lincsd->bllen,xprime,pbc_null,
                        &ncons_loc,&p_ssd,&p_max,&p_imax);
                if (MULTISIM(cr))
                {
                    sprintf(buf3," in simulation %d", cr->ms->sim);
                }
                else
                {
                    buf3[0] = 0;
                }
                sprintf(buf,"\nStep %s, time %g (ps)  LINCS WARNING%s\n"
                        "relative constraint deviation after LINCS:\n"
                        "rms %.6f, max %.6f (between atoms %d and %d)\n",
                        gmx_step_str(step,buf2),ir->init_t+step*ir->delta_t,
                        buf3,
                        sqrt(p_ssd/ncons_loc),p_max,
                        ddglatnr(cr->dd,lincsd->bla[2*p_imax]),
                        ddglatnr(cr->dd,lincsd->bla[2*p_imax+1]));
                if (fplog)
                {
                    fprintf(fplog,"%s",buf);
                }
                fprintf(stderr,"%s",buf);
                lincs_warning(fplog,cr->dd,x,xprime,pbc_null,
                              lincsd->nc,lincsd->bla,lincsd->bllen,
                              ir->LincsWarnAngle,maxwarn,warncount);
            }
            bOK = (p_max < 0.5);
        }
        
        if (lincsd->ncg_flex) {
            for(i=0; (i<lincsd->nc); i++)
                if (lincsd->bllen0[i] == 0 && lincsd->ddist[i] == 0)
                    lincsd->bllen[i] = 0;
        }
    } 
    else
    {
        do_lincsp(x,xprime,min_proj,pbc_null,lincsd,md->invmass,econq,dvdlambda,
                  bCalcVir,rmdr);
    }
  
    /* count assuming nit=1 */
    inc_nrnb(nrnb,eNR_LINCS,lincsd->nc);
    inc_nrnb(nrnb,eNR_LINCSMAT,(2+lincsd->nOrder)*lincsd->ncc);
    if (lincsd->ntriangle > 0)
    {
        inc_nrnb(nrnb,eNR_LINCSMAT,lincsd->nOrder*lincsd->ncc_triangle);
    }
    if (v)
    {
        inc_nrnb(nrnb,eNR_CONSTR_V,lincsd->nc*2);
    }
    if (bCalcVir)
    {
        inc_nrnb(nrnb,eNR_CONSTR_VIR,lincsd->nc);
    }

    return bOK;
}
Example #10
0
void
gmx_nb_generic_kernel(t_nblist *                nlist,
                      rvec *                    xx,
                      rvec *                    ff,
                      t_forcerec *              fr,
                      t_mdatoms *               mdatoms,
                      nb_kernel_data_t *        kernel_data,
                      t_nrnb *                  nrnb)
{
    int           ntype, table_nelements, ielec, ivdw;
    real          facel;
    int           n, ii, is3, ii3, k, nj0, nj1, jnr, j3, ggid, nnn, n0;
    real          shX, shY, shZ;
    real          fscal, felec, fvdw, velec, vvdw, tx, ty, tz;
    real          rinvsq;
    real          iq;
    real          qq, vctot;
    int           nti, nvdwparam;
    int           tj;
    real          rt, r, eps, eps2, Y, F, Geps, Heps2, VV, FF, Fp, fijD, fijR;
    real          rinvsix;
    real          vvdwtot;
    real          vvdw_rep, vvdw_disp;
    real          ix, iy, iz, fix, fiy, fiz;
    real          jx, jy, jz;
    real          dx, dy, dz, rsq, rinv;
    real          c6, c12, c6grid, cexp1, cexp2, br;
    real *        charge;
    real *        shiftvec;
    real *        vdwparam, *vdwgridparam;
    int *         type;
    real *        fshift;
    real *        velecgrp;
    real *        vvdwgrp;
    real          tabscale;
    real *        VFtab;
    real *        x;
    real *        f;
    int           ewitab;
    real          ewtabscale, eweps, ewrt, ewtabhalfspace;
    real *        ewtab;
    real          rcoulomb2, rvdw, rvdw2, sh_dispersion, sh_repulsion;
    real          rcutoff, rcutoff2;
    real          d, d2, sw, dsw, rinvcorr;
    real          elec_swV3, elec_swV4, elec_swV5, elec_swF2, elec_swF3, elec_swF4;
    real          vdw_swV3, vdw_swV4, vdw_swV5, vdw_swF2, vdw_swF3, vdw_swF4;
    real          ewclj, ewclj2, ewclj6, ewcljrsq, poly, exponent, sh_lj_ewald;
    gmx_bool      bExactElecCutoff, bExactVdwCutoff, bExactCutoff;
    gmx_bool      do_tab;

#ifdef BUILD_WITH_FDA
    FDA *         fda;
    real          pf_coul, pf_vdw;

    fda                 = fr->fda;
    pf_coul             = 0.0;
    pf_vdw              = 0.0;
#endif

    x                   = xx[0];
    f                   = ff[0];
    ielec               = nlist->ielec;
    ivdw                = nlist->ivdw;

    fshift              = fr->fshift[0];
    velecgrp            = kernel_data->energygrp_elec;
    vvdwgrp             = kernel_data->energygrp_vdw;

    do_tab = (ielec == GMX_NBKERNEL_ELEC_CUBICSPLINETABLE ||
              ivdw == GMX_NBKERNEL_VDW_CUBICSPLINETABLE);
    if (do_tab)
    {
        tabscale         = kernel_data->table_elec_vdw->scale;
        VFtab            = kernel_data->table_elec_vdw->data;
    }
    else
    {
        tabscale        = 0;
        VFtab           = nullptr;
    }

    const interaction_const_t *ic = fr->ic;

    ewtab               = ic->tabq_coul_FDV0;
    ewtabscale          = ic->tabq_scale;
    ewtabhalfspace      = 0.5/ewtabscale;

    rcoulomb2           = ic->rcoulomb*ic->rcoulomb;
    rvdw                = ic->rvdw;
    rvdw2               = rvdw*rvdw;
    sh_dispersion       = ic->dispersion_shift.cpot;
    sh_repulsion        = ic->repulsion_shift.cpot;
    sh_lj_ewald         = ic->sh_lj_ewald;

    ewclj               = ic->ewaldcoeff_lj;
    ewclj2              = ewclj*ewclj;
    ewclj6              = ewclj2*ewclj2*ewclj2;

    if (ic->coulomb_modifier == eintmodPOTSWITCH)
    {
        d               = ic->rcoulomb - ic->rcoulomb_switch;
        elec_swV3       = -10.0/(d*d*d);
        elec_swV4       =  15.0/(d*d*d*d);
        elec_swV5       =  -6.0/(d*d*d*d*d);
        elec_swF2       = -30.0/(d*d*d);
        elec_swF3       =  60.0/(d*d*d*d);
        elec_swF4       = -30.0/(d*d*d*d*d);
    }
    else
    {
        /* Avoid warnings from stupid compilers (looking at you, Clang!) */
        elec_swV3 = elec_swV4 = elec_swV5 = elec_swF2 = elec_swF3 = elec_swF4 = 0.0;
    }
    if (ic->vdw_modifier == eintmodPOTSWITCH)
    {
        d               = ic->rvdw - ic->rvdw_switch;
        vdw_swV3        = -10.0/(d*d*d);
        vdw_swV4        =  15.0/(d*d*d*d);
        vdw_swV5        =  -6.0/(d*d*d*d*d);
        vdw_swF2        = -30.0/(d*d*d);
        vdw_swF3        =  60.0/(d*d*d*d);
        vdw_swF4        = -30.0/(d*d*d*d*d);
    }
    else
    {
        /* Avoid warnings from stupid compilers (looking at you, Clang!) */
        vdw_swV3 = vdw_swV4 = vdw_swV5 = vdw_swF2 = vdw_swF3 = vdw_swF4 = 0.0;
    }

    bExactElecCutoff    = (ic->coulomb_modifier != eintmodNONE) || ic->eeltype == eelRF_ZERO;
    bExactVdwCutoff     = (ic->vdw_modifier != eintmodNONE);
    bExactCutoff        = bExactElecCutoff && bExactVdwCutoff;

    if (bExactCutoff)
    {
        rcutoff  = ( ic->rcoulomb > ic->rvdw ) ? ic->rcoulomb : ic->rvdw;
        rcutoff2 = rcutoff*rcutoff;
    }
    else
    {
        /* Fix warnings for stupid compilers */
        rcutoff2 = 1e30;
    }

    /* avoid compiler warnings for cases that cannot happen */
    nnn                 = 0;
    eps                 = 0.0;
    eps2                = 0.0;

    /* 3 VdW parameters for Buckingham, otherwise 2 */
    nvdwparam           = (ivdw == GMX_NBKERNEL_VDW_BUCKINGHAM) ? 3 : 2;
    table_nelements     = 12;

    charge              = mdatoms->chargeA;
    type                = mdatoms->typeA;
    facel               = fr->ic->epsfac;
    shiftvec            = fr->shift_vec[0];
    vdwparam            = fr->nbfp;
    ntype               = fr->ntype;
    vdwgridparam        = fr->ljpme_c6grid;

    for (n = 0; (n < nlist->nri); n++)
    {
        is3              = 3*nlist->shift[n];
        shX              = shiftvec[is3];
        shY              = shiftvec[is3+1];
        shZ              = shiftvec[is3+2];
        nj0              = nlist->jindex[n];
        nj1              = nlist->jindex[n+1];
        ii               = nlist->iinr[n];
        ii3              = 3*ii;
        ix               = shX + x[ii3+0];
        iy               = shY + x[ii3+1];
        iz               = shZ + x[ii3+2];
        iq               = facel*charge[ii];
        nti              = nvdwparam*ntype*type[ii];
        vctot            = 0;
        vvdwtot          = 0;
        fix              = 0;
        fiy              = 0;
        fiz              = 0;

        for (k = nj0; (k < nj1); k++)
        {
            jnr              = nlist->jjnr[k];
            j3               = 3*jnr;
            jx               = x[j3+0];
            jy               = x[j3+1];
            jz               = x[j3+2];
            dx               = ix - jx;
            dy               = iy - jy;
            dz               = iz - jz;
            rsq              = dx*dx+dy*dy+dz*dz;
            rinv             = gmx::invsqrt(rsq);
            rinvsq           = rinv*rinv;
            felec            = 0;
            fvdw             = 0;
            velec            = 0;
            vvdw             = 0;

            if (bExactCutoff && rsq >= rcutoff2)
            {
                continue;
            }

            if (ielec == GMX_NBKERNEL_ELEC_CUBICSPLINETABLE || ivdw == GMX_NBKERNEL_VDW_CUBICSPLINETABLE)
            {
                r                = rsq*rinv;
                rt               = r*tabscale;
                n0               = rt;
                eps              = rt-n0;
                eps2             = eps*eps;
                nnn              = table_nelements*n0;
            }

            /* Coulomb interaction. ielec==0 means no interaction */
            if (ielec != GMX_NBKERNEL_ELEC_NONE)
            {
                qq               = iq*charge[jnr];

                switch (ielec)
                {
                    case GMX_NBKERNEL_ELEC_NONE:
                        break;

                    case GMX_NBKERNEL_ELEC_COULOMB:
                        /* Vanilla cutoff coulomb */
                        velec            = qq*rinv;
                        felec            = velec*rinvsq;
#ifdef BUILD_WITH_FDA
                        pf_coul          = felec;
#endif
                        /* The shift for the Coulomb potential is stored in
                         * the RF parameter c_rf, which is 0 without shift
                         */
                        velec           -= qq*ic->c_rf;
                        break;

                    case GMX_NBKERNEL_ELEC_REACTIONFIELD:
                        /* Reaction-field */
                        velec            = qq*(rinv + ic->k_rf*rsq-ic->c_rf);
                        felec            = qq*(rinv*rinvsq - 2.0*ic->k_rf);
#ifdef BUILD_WITH_FDA
                        pf_coul          = felec;
#endif
                        break;

                    case GMX_NBKERNEL_ELEC_CUBICSPLINETABLE:
                        /* Tabulated coulomb */
                        Y                = VFtab[nnn];
                        F                = VFtab[nnn+1];
                        Geps             = eps*VFtab[nnn+2];
                        Heps2            = eps2*VFtab[nnn+3];
                        Fp               = F+Geps+Heps2;
                        VV               = Y+eps*Fp;
                        FF               = Fp+Geps+2.0*Heps2;
                        velec            = qq*VV;
                        felec            = -qq*FF*tabscale*rinv;
#ifdef BUILD_WITH_FDA
                        pf_coul          = felec;
#endif
                        break;

                    case GMX_NBKERNEL_ELEC_GENERALIZEDBORN:
                        /* GB */
                        gmx_fatal(FARGS, "Death & horror! GB generic interaction not implemented.\n");
                        break;

                    case GMX_NBKERNEL_ELEC_EWALD:
                        ewrt             = rsq*rinv*ewtabscale;
                        ewitab           = ewrt;
                        eweps            = ewrt-ewitab;
                        ewitab           = 4*ewitab;
                        felec            = ewtab[ewitab]+eweps*ewtab[ewitab+1];
                        rinvcorr         = (ic->coulomb_modifier == eintmodPOTSHIFT) ? rinv - ic->sh_ewald : rinv;
                        velec            = qq*(rinvcorr-(ewtab[ewitab+2]-ewtabhalfspace*eweps*(ewtab[ewitab]+felec)));
                        felec            = qq*rinv*(rinvsq-felec);
#ifdef BUILD_WITH_FDA
                        pf_coul          = felec;
#endif
                        break;

                    default:
                        gmx_fatal(FARGS, "Death & horror! No generic coulomb interaction for ielec=%d.\n", ielec);
                        break;
                }
                if (ic->coulomb_modifier == eintmodPOTSWITCH)
                {
                    d                = rsq*rinv - ic->rcoulomb_switch;
                    d                = (d > 0.0) ? d : 0.0;
                    d2               = d*d;
                    sw               = 1.0+d2*d*(elec_swV3+d*(elec_swV4+d*elec_swV5));
                    dsw              = d2*(elec_swF2+d*(elec_swF3+d*elec_swF4));
                    /* Apply switch function. Note that felec=f/r since it will be multiplied
                     * by the i-j displacement vector. This means felec'=f'/r=-(v*sw)'/r=
                     * -(v'*sw+v*dsw)/r=-v'*sw/r-v*dsw/r=felec*sw-v*dsw/r
                     */
                    felec            = felec*sw - rinv*velec*dsw;
                    /* Once we have used velec to update felec we can modify velec too */
                    velec           *= sw;
                }
                if (bExactElecCutoff)
                {
                    felec            = (rsq < rcoulomb2) ? felec : 0.0;
                    velec            = (rsq < rcoulomb2) ? velec : 0.0;
                }
                vctot           += velec;
            } /* End of coulomb interactions */


            /* VdW interaction. ivdw==0 means no interaction */
            if (ivdw != GMX_NBKERNEL_VDW_NONE)
            {
                tj               = nti+nvdwparam*type[jnr];

                switch (ivdw)
                {
                    case GMX_NBKERNEL_VDW_NONE:
                        break;

                    case GMX_NBKERNEL_VDW_LENNARDJONES:
                        /* Vanilla Lennard-Jones cutoff */
                        c6               = vdwparam[tj];
                        c12              = vdwparam[tj+1];
                        rinvsix          = rinvsq*rinvsq*rinvsq;
                        vvdw_disp        = c6*rinvsix;
                        vvdw_rep         = c12*rinvsix*rinvsix;
                        fvdw             = (vvdw_rep-vvdw_disp)*rinvsq;
#ifdef BUILD_WITH_FDA
                        pf_vdw           = fvdw;
#endif
                        if (ic->vdw_modifier == eintmodPOTSHIFT)
                        {
                            vvdw             = (vvdw_rep + c12*sh_repulsion)/12.0 - (vvdw_disp + c6*sh_dispersion)/6.0;
                        }
                        else
                        {
                            vvdw             = vvdw_rep/12.0-vvdw_disp/6.0;
                        }
                        break;

                    case GMX_NBKERNEL_VDW_BUCKINGHAM:
                        /* Buckingham */
                        c6               = vdwparam[tj];
                        cexp1            = vdwparam[tj+1];
                        cexp2            = vdwparam[tj+2];

                        rinvsix          = rinvsq*rinvsq*rinvsq;
                        vvdw_disp        = c6*rinvsix;
                        br               = cexp2*rsq*rinv;
                        vvdw_rep         = cexp1*std::exp(-br);
                        fvdw             = (br*vvdw_rep-vvdw_disp)*rinvsq;
#ifdef BUILD_WITH_FDA
                        pf_vdw           = fvdw;
#endif
                        if (ic->vdw_modifier == eintmodPOTSHIFT)
                        {
                            vvdw             = (vvdw_rep-cexp1*std::exp(-cexp2*rvdw))-(vvdw_disp + c6*sh_dispersion)/6.0;
                        }
                        else
                        {
                            vvdw             = vvdw_rep-vvdw_disp/6.0;
                        }
                        break;

                    case GMX_NBKERNEL_VDW_CUBICSPLINETABLE:
                        /* Tabulated VdW */
                        c6               = vdwparam[tj];
                        c12              = vdwparam[tj+1];
                        Y                = VFtab[nnn+4];
                        F                = VFtab[nnn+5];
                        Geps             = eps*VFtab[nnn+6];
                        Heps2            = eps2*VFtab[nnn+7];
                        Fp               = F+Geps+Heps2;
                        VV               = Y+eps*Fp;
                        FF               = Fp+Geps+2.0*Heps2;
                        vvdw_disp        = c6*VV;
                        fijD             = c6*FF;
                        Y                = VFtab[nnn+8];
                        F                = VFtab[nnn+9];
                        Geps             = eps*VFtab[nnn+10];
                        Heps2            = eps2*VFtab[nnn+11];
                        Fp               = F+Geps+Heps2;
                        VV               = Y+eps*Fp;
                        FF               = Fp+Geps+2.0*Heps2;
                        vvdw_rep         = c12*VV;
                        fijR             = c12*FF;
                        fvdw             = -(fijD+fijR)*tabscale*rinv;
#ifdef BUILD_WITH_FDA
                        pf_vdw           = fvdw;
#endif
                        vvdw             = vvdw_disp + vvdw_rep;
                        break;


                    case GMX_NBKERNEL_VDW_LJEWALD:
                        /* LJ-PME */
                        rinvsix          = rinvsq*rinvsq*rinvsq;
                        ewcljrsq         = ewclj2*rsq;
                        exponent         = std::exp(-ewcljrsq);
                        poly             = exponent*(1.0 + ewcljrsq + ewcljrsq*ewcljrsq*0.5);
                        c6               = vdwparam[tj];
                        c12              = vdwparam[tj+1];
                        c6grid           = vdwgridparam[tj];
                        vvdw_disp        = (c6-c6grid*(1.0-poly))*rinvsix;
                        vvdw_rep         = c12*rinvsix*rinvsix;
                        fvdw             = (vvdw_rep - vvdw_disp - c6grid*(1.0/6.0)*exponent*ewclj6)*rinvsq;
#ifdef BUILD_WITH_FDA
                        pf_vdw           = fvdw;
#endif
                        if (ic->vdw_modifier == eintmodPOTSHIFT)
                        {
                            vvdw             = (vvdw_rep + c12*sh_repulsion)/12.0 - (vvdw_disp + c6*sh_dispersion - c6grid*sh_lj_ewald)/6.0;
                        }
                        else
                        {
                            vvdw             = vvdw_rep/12.0-vvdw_disp/6.0;
                        }
                        break;

                    default:
                        gmx_fatal(FARGS, "Death & horror! No generic VdW interaction for ivdw=%d.\n", ivdw);
                        break;
                }
                if (ic->vdw_modifier == eintmodPOTSWITCH)
                {
                    d                = rsq*rinv - ic->rvdw_switch;
                    d                = (d > 0.0) ? d : 0.0;
                    d2               = d*d;
                    sw               = 1.0+d2*d*(vdw_swV3+d*(vdw_swV4+d*vdw_swV5));
                    dsw              = d2*(vdw_swF2+d*(vdw_swF3+d*vdw_swF4));
                    /* See coulomb interaction for the force-switch formula */
                    fvdw             = fvdw*sw - rinv*vvdw*dsw;
                    vvdw            *= sw;
                }
                if (bExactVdwCutoff)
                {
                    fvdw             = (rsq < rvdw2) ? fvdw : 0.0;
                    vvdw             = (rsq < rvdw2) ? vvdw : 0.0;
                }
                vvdwtot         += vvdw;
            } /* end VdW interactions */

            fscal            = felec+fvdw;

            tx               = fscal*dx;
            ty               = fscal*dy;
            tz               = fscal*dz;
            fix              = fix + tx;
            fiy              = fiy + ty;
            fiz              = fiz + tz;
            f[j3+0]          = f[j3+0] - tx;
            f[j3+1]          = f[j3+1] - ty;
            f[j3+2]          = f[j3+2] - tz;

#ifdef BUILD_WITH_FDA
            fda->add_nonbonded(ii, jnr, pf_coul, pf_vdw, dx, dy, dz);
            fda->add_virial_bond(ii, jnr, fscal, dx, dy, dz);
#endif
        }

        f[ii3+0]         = f[ii3+0] + fix;
        f[ii3+1]         = f[ii3+1] + fiy;
        f[ii3+2]         = f[ii3+2] + fiz;
        fshift[is3]      = fshift[is3]+fix;
        fshift[is3+1]    = fshift[is3+1]+fiy;
        fshift[is3+2]    = fshift[is3+2]+fiz;
        ggid             = nlist->gid[n];
        velecgrp[ggid]  += vctot;
        vvdwgrp[ggid]   += vvdwtot;
    }
    /* Estimate flops, average for generic kernel:
     * 12 flops per outer iteration
     * 50 flops per inner iteration
     */
    inc_nrnb(nrnb, eNR_NBKERNEL_GENERIC, nlist->nri*12 + nlist->jindex[n]*50);
}
Example #11
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);
}
Example #12
0
void compute_globals(FILE *fplog, gmx_global_stat_t gstat, t_commrec *cr, t_inputrec *ir,
                     t_forcerec *fr, gmx_ekindata_t *ekind,
                     t_state *state, t_state *state_global, t_mdatoms *mdatoms,
                     t_nrnb *nrnb, t_vcm *vcm, gmx_wallcycle_t wcycle,
                     gmx_enerdata_t *enerd, tensor force_vir, tensor shake_vir, tensor total_vir,
                     tensor pres, rvec mu_tot, gmx_constr_t constr,
                     globsig_t *gs, gmx_bool bInterSimGS,
                     matrix box, gmx_mtop_t *top_global,
                     gmx_bool *bSumEkinhOld, int flags)
{
    int      i, gsi;
    real     gs_buf[eglsNR];
    tensor   corr_vir, corr_pres;
    gmx_bool bEner, bPres, bTemp;
    gmx_bool bStopCM, bGStat,
             bReadEkin, bEkinAveVel, bScaleEkin, bConstrain;
    real     prescorr, enercorr, dvdlcorr, dvdl_ekin;

    /* translate CGLO flags to gmx_booleans */
    bStopCM       = flags & CGLO_STOPCM;
    bGStat        = flags & CGLO_GSTAT;
    bReadEkin     = (flags & CGLO_READEKIN);
    bScaleEkin    = (flags & CGLO_SCALEEKIN);
    bEner         = flags & CGLO_ENERGY;
    bTemp         = flags & CGLO_TEMPERATURE;
    bPres         = (flags & CGLO_PRESSURE);
    bConstrain    = (flags & CGLO_CONSTRAINT);

    /* we calculate a full state kinetic energy either with full-step velocity verlet
       or half step where we need the pressure */

    bEkinAveVel = (ir->eI == eiVV || (ir->eI == eiVVAK && bPres) || bReadEkin);

    /* in initalization, it sums the shake virial in vv, and to
       sums ekinh_old in leapfrog (or if we are calculating ekinh_old) for other reasons */

    /* ########## Kinetic energy  ############## */

    if (bTemp)
    {
        /* Non-equilibrium MD: this is parallellized, but only does communication
         * when there really is NEMD.
         */

        if (PAR(cr) && (ekind->bNEMD))
        {
            accumulate_u(cr, &(ir->opts), ekind);
        }
        debug_gmx();
        if (bReadEkin)
        {
            restore_ekinstate_from_state(cr, ekind, &state_global->ekinstate);
        }
        else
        {
            calc_ke_part(state, &(ir->opts), mdatoms, ekind, nrnb, bEkinAveVel);
        }

        debug_gmx();
    }

    /* Calculate center of mass velocity if necessary, also parallellized */
    if (bStopCM)
    {
        calc_vcm_grp(0, mdatoms->homenr, mdatoms,
                     state->x, state->v, vcm);
    }

    if (bTemp || bStopCM || bPres || bEner || bConstrain)
    {
        if (!bGStat)
        {
            /* We will not sum ekinh_old,
             * so signal that we still have to do it.
             */
            *bSumEkinhOld = TRUE;

        }
        else
        {
            if (gs != NULL)
            {
                for (i = 0; i < eglsNR; i++)
                {
                    gs_buf[i] = gs->sig[i];
                }
            }
            if (PAR(cr))
            {
                wallcycle_start(wcycle, ewcMoveE);
                global_stat(fplog, gstat, cr, enerd, force_vir, shake_vir, mu_tot,
                            ir, ekind, constr, bStopCM ? vcm : NULL,
                            gs != NULL ? eglsNR : 0, gs_buf,
                            top_global, state,
                            *bSumEkinhOld, flags);
                wallcycle_stop(wcycle, ewcMoveE);
            }
            if (gs != NULL)
            {
                if (MULTISIM(cr) && bInterSimGS)
                {
                    if (MASTER(cr))
                    {
                        /* Communicate the signals between the simulations */
                        gmx_sum_sim(eglsNR, gs_buf, cr->ms);
                    }
                    /* Communicate the signals form the master to the others */
                    gmx_bcast(eglsNR*sizeof(gs_buf[0]), gs_buf, cr);
                }
                for (i = 0; i < eglsNR; i++)
                {
                    if (bInterSimGS || gs_simlocal[i])
                    {
                        /* Set the communicated signal only when it is non-zero,
                         * since signals might not be processed at each MD step.
                         */
                        gsi = (gs_buf[i] >= 0 ?
                               (int)(gs_buf[i] + 0.5) :
                               (int)(gs_buf[i] - 0.5));
                        if (gsi != 0)
                        {
                            gs->set[i] = gsi;
                        }
                        /* Turn off the local signal */
                        gs->sig[i] = 0;
                    }
                }
            }
            *bSumEkinhOld = FALSE;
        }
    }

    if (!ekind->bNEMD && debug && bTemp && (vcm->nr > 0))
    {
        correct_ekin(debug,
                     0, mdatoms->homenr,
                     state->v, vcm->group_p[0],
                     mdatoms->massT, mdatoms->tmass, ekind->ekin);
    }

    /* Do center of mass motion removal */
    if (bStopCM)
    {
        check_cm_grp(fplog, vcm, ir, 1);
        do_stopcm_grp(0, mdatoms->homenr, mdatoms->cVCM,
                      state->x, state->v, vcm);
        inc_nrnb(nrnb, eNR_STOPCM, mdatoms->homenr);
    }

    if (bEner)
    {
        /* Calculate the amplitude of the cosine velocity profile */
        ekind->cosacc.vcos = ekind->cosacc.mvcos/mdatoms->tmass;
    }

    if (bTemp)
    {
        /* Sum the kinetic energies of the groups & calc temp */
        /* compute full step kinetic energies if vv, or if vv-avek and we are computing the pressure with IR_NPT_TROTTER */
        /* three maincase:  VV with AveVel (md-vv), vv with AveEkin (md-vv-avek), leap with AveEkin (md).
           Leap with AveVel is not supported; it's not clear that it will actually work.
           bEkinAveVel: If TRUE, we simply multiply ekin by ekinscale to get a full step kinetic energy.
           If FALSE, we average ekinh_old and ekinh*ekinscale_nhc to get an averaged half step kinetic energy.
         */
        enerd->term[F_TEMP] = sum_ekin(&(ir->opts), ekind, &dvdl_ekin,
                                       bEkinAveVel, bScaleEkin);
        enerd->dvdl_lin[efptMASS] = (double) dvdl_ekin;

        enerd->term[F_EKIN] = trace(ekind->ekin);
    }

    /* ##########  Long range energy information ###### */

    if (bEner || bPres || bConstrain)
    {
        calc_dispcorr(ir, fr, top_global->natoms, box, state->lambda[efptVDW],
                      corr_pres, corr_vir, &prescorr, &enercorr, &dvdlcorr);
    }

    if (bEner)
    {
        enerd->term[F_DISPCORR]  = enercorr;
        enerd->term[F_EPOT]     += enercorr;
        enerd->term[F_DVDL_VDW] += dvdlcorr;
    }

    /* ########## Now pressure ############## */
    if (bPres || bConstrain)
    {

        m_add(force_vir, shake_vir, total_vir);

        /* Calculate pressure and apply LR correction if PPPM is used.
         * Use the box from last timestep since we already called update().
         */

        enerd->term[F_PRES] = calc_pres(fr->ePBC, ir->nwall, box, ekind->ekin, total_vir, pres);

        /* Calculate long range corrections to pressure and energy */
        /* this adds to enerd->term[F_PRES] and enerd->term[F_ETOT],
           and computes enerd->term[F_DISPCORR].  Also modifies the
           total_vir and pres tesors */

        m_add(total_vir, corr_vir, total_vir);
        m_add(pres, corr_pres, pres);
        enerd->term[F_PDISPCORR] = prescorr;
        enerd->term[F_PRES]     += prescorr;
    }
}
Example #13
0
bool constrain(FILE *fplog,bool bLog,bool bEner,
               struct gmx_constr *constr,
               t_idef *idef,t_inputrec *ir,
               t_commrec *cr,
               gmx_step_t step,int delta_step,
               t_mdatoms *md,
               rvec *x,rvec *xprime,rvec *min_proj,matrix box,
               real lambda,real *dvdlambda,
               rvec *v,tensor *vir,
               t_nrnb *nrnb,int econq)
{
    bool    bOK;
    int     start,homenr;
    int     i,j;
    int     ncons,error;
    tensor  rmdr;
    real    invdt,vir_fac,t;
    t_ilist *settle;
    int     nsettle;
    t_pbc   pbc;
    char    buf[22];
    
    if (econq == econqForceDispl && !EI_ENERGY_MINIMIZATION(ir->eI))
    {
        gmx_incons("constrain called for forces displacements while not doing energy minimization, can not do this while the LINCS and SETTLE constraint connection matrices are mass weighted");
    }
    
    bOK = TRUE;
    
    start  = md->start;
    homenr = md->homenr;
    if (ir->delta_t == 0)
    {
        invdt = 0;
    }
    else
    {
        invdt  = 1/ir->delta_t;
    }

    if (ir->efep != efepNO && EI_DYNAMICS(ir->eI))
    {
        /* Set the constraint lengths for the step at which this configuration
         * is meant to be. The invmasses should not be changed.
         */
        lambda += delta_step*ir->delta_lambda;
    }
    
    if (vir != NULL)
    {
        clear_mat(rmdr);
    }
    
    where();
    if (constr->lincsd)
    {
        bOK = constrain_lincs(fplog,bLog,bEner,ir,step,constr->lincsd,md,cr,
                              x,xprime,min_proj,box,lambda,dvdlambda,
                              invdt,v,vir!=NULL,rmdr,
                              econq,nrnb,
                              constr->maxwarn,&constr->warncount_lincs);
        if (!bOK && constr->maxwarn >= 0 && fplog)
        {
            fprintf(fplog,"Constraint error in algorithm %s at step %s\n",
                    econstr_names[econtLINCS],gmx_step_str(step,buf));
        }
    }	
    
    if (constr->nblocks > 0)
    {
        if (econq != econqCoord)
        {
            gmx_fatal(FARGS,"Internal error, SHAKE called for constraining something else than coordinates");
        }
        
        bOK = bshakef(fplog,constr->shaked,
                      homenr,md->invmass,constr->nblocks,constr->sblock,
                      idef,ir,box,x,xprime,nrnb,
                      constr->lagr,lambda,dvdlambda,
                      invdt,v,vir!=NULL,rmdr,constr->maxwarn>=0);
        if (!bOK && constr->maxwarn >= 0 && fplog)
        {
            fprintf(fplog,"Constraint error in algorithm %s at step %s\n",
                    econstr_names[econtSHAKE],gmx_step_str(step,buf));
        }
    }
    
    settle  = &idef->il[F_SETTLE];
    if (settle->nr > 0)
    {
        nsettle = settle->nr/2;
        
        switch (econq)
        {
        case econqCoord:
            csettle(constr->settled,
                    nsettle,settle->iatoms,x[0],xprime[0],
                    invdt,v[0],vir!=NULL,rmdr,&error);
            inc_nrnb(nrnb,eNR_SETTLE,nsettle);
            if (v != NULL)
            {
                inc_nrnb(nrnb,eNR_CONSTR_V,nsettle*3);
            }
            if (vir != NULL)
            {
                inc_nrnb(nrnb,eNR_CONSTR_VIR,nsettle*3);
            }
            
            bOK = (error < 0);
            if (!bOK && constr->maxwarn >= 0)
            {
                char buf[256];
                sprintf(buf,
                        "\nt = %.3f ps: Water molecule starting at atom %d can not be "
                        "settled.\nCheck for bad contacts and/or reduce the timestep.\n",
                        ir->init_t+step*ir->delta_t,
                        ddglatnr(cr->dd,settle->iatoms[error*2+1]));
                if (fplog)
                {
                    fprintf(fplog,"%s",buf);
                }
                fprintf(stderr,"%s",buf);
                constr->warncount_settle++;
                if (constr->warncount_settle > constr->maxwarn)
                {
                    too_many_constraint_warnings(-1,constr->warncount_settle);
                }
                break;
            case econqVeloc:
            case econqDeriv:
            case econqForce:
            case econqForceDispl:
                settle_proj(fplog,constr->settled,econq,
                            nsettle,settle->iatoms,x,
                            xprime,min_proj,vir!=NULL,rmdr);
                
                /* This is an overestimate */
                inc_nrnb(nrnb,eNR_SETTLE,nsettle);
                break;
            case econqDeriv_FlexCon:
                /* Nothing to do, since the are no flexible constraints in settles */
                break;
            default:
                gmx_incons("Unknown constraint quantity for settle");
            }
        }
    }

    if (vir != NULL)
    {
        switch (econq)
        {
        case econqCoord:
            vir_fac = 0.5/(ir->delta_t*ir->delta_t);
            break;
        case econqVeloc:
            /* Assume that these are velocities */
            vir_fac = 0.5/ir->delta_t;
            break;
        case econqForce:
        case econqForceDispl:
            vir_fac = 0.5;
            break;
        default:
            vir_fac = 0;
            gmx_incons("Unsupported constraint quantity for virial");
        }
        for(i=0; i<DIM; i++)
        {
            for(j=0; j<DIM; j++)
            {
                (*vir)[i][j] = vir_fac*rmdr[i][j];
            }
        }
    }
    
    if (!bOK && constr->maxwarn >= 0)
    {
        dump_confs(fplog,step,constr->warn_mtop,start,homenr,cr,x,xprime,box);
    }
    
    if (econq == econqCoord)
    {
        if (ir->ePull == epullCONSTRAINT)
        {
            if (EI_DYNAMICS(ir->eI))
            {
                t = ir->init_t + (step + delta_step)*ir->delta_t;
            }
            else
            {
                t = ir->init_t;
            }
            set_pbc(&pbc,ir->ePBC,box);
            pull_constraint(ir->pull,md,&pbc,cr,ir->delta_t,t,x,xprime,v,*vir);
        }
        if (constr->ed && delta_step > 0)
        {
            /* apply the essential dynamcs constraints here */
            do_edsam(ir,step,md,cr,xprime,v,box,constr->ed);
        }
    }
    
    return bOK;
}
Example #14
0
void do_nonbonded(t_commrec *cr,t_forcerec *fr,
                  rvec x[],rvec f[],t_mdatoms *mdatoms,t_blocka *excl,
                  real egnb[],real egcoul[],real egpol[],rvec box_size,
                  t_nrnb *nrnb,real lambda,real *dvdlambda,
                  int nls,int eNL,int flags)
{
    gmx_bool            bLR,bDoForces,bForeignLambda;
	t_nblist *      nlist;
	real *          fshift;
	int             n,n0,n1,i,i0,i1,nrnb_ind,sz;
	t_nblists       *nblists;
	gmx_bool            bWater;
	nb_kernel_t *   kernelptr;
	pf_nb_kernel_t *pf_kernelptr;
	FILE *          fp;
	int             fac=0;
	int             nthreads = 1;
	int             tabletype;
	int             outeriter,inneriter;
	real *          tabledata = NULL;
	gmx_gbdata_t    gbdata;
    
    bLR            = (flags & GMX_DONB_LR);
    bDoForces      = (flags & GMX_DONB_FORCES);
    bForeignLambda = (flags & GMX_DONB_FOREIGNLAMBDA); 

	gbdata.gb_epsilon_solvent = fr->gb_epsilon_solvent;
	gbdata.epsilon_r = fr->epsilon_r;
	gbdata.gpol               = egpol;
    
    if(fr->bAllvsAll) 
    {
        if(fr->bGB)
        {
#if (defined GMX_SSE2 || defined GMX_X86_64_SSE || defined GMX_X86_64_SSE2 || defined GMX_IA32_SSE || defined GMX_IA32_SSE2)
# ifdef GMX_DOUBLE
            if(fr->UseOptimizedKernels)
            {
                nb_kernel_allvsallgb_sse2_double(fr,mdatoms,excl,x[0],f[0],egcoul,egnb,egpol,
                                                 &outeriter,&inneriter,&fr->AllvsAll_work);
            }
            else
            {
                nb_kernel_allvsallgb(fr,mdatoms,excl,x[0],f[0],egcoul,egnb,egpol,
                                     &outeriter,&inneriter,&fr->AllvsAll_work);        
            }
#  else /* not double */
            if(fr->UseOptimizedKernels)
            {
                nb_kernel_allvsallgb_sse2_single(fr,mdatoms,excl,x[0],f[0],egcoul,egnb,egpol,
                                                 &outeriter,&inneriter,&fr->AllvsAll_work);
            }
            else
            {
                nb_kernel_allvsallgb(fr,mdatoms,excl,x[0],f[0],egcoul,egnb,egpol,
                                     &outeriter,&inneriter,&fr->AllvsAll_work);        
            }
#  endif /* double/single alt. */
#else /* no SSE support compiled in */
            nb_kernel_allvsallgb(fr,mdatoms,excl,x[0],f[0],egcoul,egnb,egpol,
                                 &outeriter,&inneriter,&fr->AllvsAll_work);                    
#endif
            inc_nrnb(nrnb,eNR_NBKERNEL_ALLVSALLGB,inneriter);
        }
        else
        { 
#if (defined GMX_SSE2 || defined GMX_X86_64_SSE || defined GMX_X86_64_SSE2 || defined GMX_IA32_SSE || defined GMX_IA32_SSE2)
# ifdef GMX_DOUBLE
            if(fr->UseOptimizedKernels)
            {
                nb_kernel_allvsall_sse2_double(fr,mdatoms,excl,x[0],f[0],egcoul,egnb,
                                               &outeriter,&inneriter,&fr->AllvsAll_work);
            }
            else 
            {
                nb_kernel_allvsall(fr,mdatoms,excl,x[0],f[0],egcoul,egnb,
                                   &outeriter,&inneriter,&fr->AllvsAll_work);            
            }
            
#  else /* not double */
            if(fr->UseOptimizedKernels)
            {
                nb_kernel_allvsall_sse2_single(fr,mdatoms,excl,x[0],f[0],egcoul,egnb,
                                               &outeriter,&inneriter,&fr->AllvsAll_work);
            }
            else 
            {
                nb_kernel_allvsall(fr,mdatoms,excl,x[0],f[0],egcoul,egnb,
                                   &outeriter,&inneriter,&fr->AllvsAll_work);            
            }

#  endif /* double/single check */
#else /* No SSE2 support compiled in */
            nb_kernel_allvsall(fr,mdatoms,excl,x[0],f[0],egcoul,egnb,
                               &outeriter,&inneriter,&fr->AllvsAll_work);
#endif            
            
            inc_nrnb(nrnb,eNR_NBKERNEL_ALLVSALL,inneriter);
        }
        inc_nrnb(nrnb,eNR_NBKERNEL_OUTER,outeriter);
        return;
    }
	
    if (eNL >= 0) 
    {
		i0 = eNL;
		i1 = i0+1;
    }
    else
    {
		i0 = 0;
		i1 = eNL_NR;
	}
	
	if (nls >= 0) 
	{
		n0 = nls;
		n1 = nls+1;
	}
	else 
	{
		n0 = 0;
		n1 = fr->nnblists;
	}
	
	if(nb_kernel_list == NULL)
    {
		gmx_fatal(FARGS,"gmx_setup_kernels has not been called");
    }
  
    fshift = fr->fshift[0];
  
	for(n=n0; (n<n1); n++) 
	{
		nblists = &fr->nblists[n];
		for(i=i0; (i<i1); i++) 
		{
			outeriter = inneriter = 0;
      
			if (bLR) 
			{
				nlist = &(nblists->nlist_lr[i]);
			}
			else
			{
				nlist = &(nblists->nlist_sr[i]);
			}
			
			if (nlist->nri > 0) 
			{
				nrnb_ind = nlist->il_code;
				
				if(nrnb_ind==eNR_NBKERNEL_FREE_ENERGY)
				{
					/* generic free energy, use combined table */
					tabledata = nblists->tab.tab;
				}
				else
				{
                    if (bForeignLambda)
                    {
                        /* We don't need the non-perturbed interactions */
                        continue;
                    }

					tabletype = nb_kernel_table[nrnb_ind];
					
					/* normal kernels, not free energy */
					if (!bDoForces)
					{
						nrnb_ind += eNR_NBKERNEL_NR/2;
					}
					
					if(tabletype == TABLE_COMBINED)
					{
						tabledata = nblists->tab.tab;
					}
					else if(tabletype == TABLE_COUL)
					{
						tabledata = nblists->coultab;
					}
					else if(tabletype == TABLE_VDW)
					{
						tabledata = nblists->vdwtab;
					}
					else
					{
						tabledata = NULL;
					}
				}
				
				nlist->count = 0;
				
				if(nlist->free_energy)
				{
					if(nlist->ivdw==2)
					{
						gmx_fatal(FARGS,"Cannot do free energy Buckingham interactions.");
					}
					
					gmx_nb_free_energy_kernel(nlist->icoul,
											  nlist->ivdw,
											  nlist->nri,
											  nlist->iinr,
											  nlist->jindex,
											  nlist->jjnr,
											  nlist->shift,
											  fr->shift_vec[0],
											  fshift,
											  nlist->gid,
											  x[0],
											  f[0],
											  mdatoms->chargeA,
											  mdatoms->chargeB,
											  fr->epsfac,
											  fr->k_rf,
											  fr->c_rf,
											  fr->ewaldcoeff,
											  egcoul,
											  mdatoms->typeA,
											  mdatoms->typeB,
											  fr->ntype,
											  fr->nbfp,
											  egnb,
											  nblists->tab.scale,
											  tabledata,
											  lambda,
											  dvdlambda,
											  fr->sc_alpha,
											  fr->sc_power,
											  fr->sc_sigma6_def,
                                              fr->sc_sigma6_min,
                                              bDoForces,
											  &outeriter,
											  &inneriter);
                }
                else if (nlist->enlist == enlistCG_CG)
                {
                    /* Call the charge group based inner loop */
                    gmx_nb_generic_cg_kernel(nlist,
                                             fr,
                                             mdatoms,
                                             x[0],
                                             f[0],
                                             fshift,
                                             egcoul,
                                             egnb,
                                             nblists->tab.scale,
                                             tabledata,
                                             &outeriter,
                                             &inneriter);
                }
                else
                {
                    /* Not free energy */
		    /* Pairwise forces between solute and solvent don't bring much information, as the molecules of solvent
		     * move around. For this reason, only pairwise forces between solute atoms are calculated.
		     * This allows the normal (non-pairwise force) kernels to be used for solute-solvent and solvent-solvent
		     * interactions; the main reason is performance, as the normal kernels are not slowed down by the
		     * checking whether atom is involved in an interesting interaction.
		     */
		    if ((fr->pf_global) && (nlist->enlist == enlistATOM_ATOM))
		    {
                        pf_kernelptr = pf_nb_kernel_list[nrnb_ind];

                        (*pf_kernelptr)( &(nlist->nri),
                                      nlist->iinr,
                                      nlist->jindex,
                                      nlist->jjnr,
                                      nlist->shift,
                                      fr->shift_vec[0],
                                      fshift,
                                      nlist->gid,
                                      x[0],
                                      f[0],
                                      mdatoms->chargeA,
                                      &(fr->epsfac),
                                      &(fr->k_rf),
                                      &(fr->c_rf),
                                      egcoul,
                                      mdatoms->typeA,
                                      &(fr->ntype),
                                      fr->nbfp,
                                      egnb,
                                      &(nblists->tab.scale),
                                      tabledata,
                                      fr->invsqrta,
                                      fr->dvda,
                                      &(fr->gbtabscale),
                                      fr->gbtab.tab,
                                      &nthreads,
                                      &(nlist->count),
                                      nlist->mtx,
                                      &outeriter,
                                      &inneriter,
                                      (real *)&gbdata,
                                      fr->pf_global);
                    }
                    else {
                        /* non pairwise force kernel */
                        kernelptr = nb_kernel_list[nrnb_ind];

                        if (kernelptr == NULL)
                        {
                            /* Call a generic nonbonded kernel */

                            /* If you want to hack/test your own interactions,
                             * do it in this routine and make sure it is called
                             * by setting the environment variable GMX_NB_GENERIC.
                             */
                            gmx_nb_generic_kernel(nlist,
                                                  fr,
                                                  mdatoms,
                                                  x[0],
                                                  f[0],
                                                  fshift,
                                                  egcoul,
                                                  egnb,
                                                  nblists->tab.scale,
                                                  tabledata,
                                                  &outeriter,
                                                  &inneriter);
                        }
                        else
                        {
                            /* Call nonbonded kernel from function pointer */

                            (*kernelptr)( &(nlist->nri),
                                          nlist->iinr,
                                          nlist->jindex,
                                          nlist->jjnr,
                                          nlist->shift,
                                          fr->shift_vec[0],
                                          fshift,
                                          nlist->gid,
                                          x[0],
                                          f[0],
                                          mdatoms->chargeA,
                                          &(fr->epsfac),
                                          &(fr->k_rf),
                                          &(fr->c_rf),
                                          egcoul,
                                          mdatoms->typeA,
                                          &(fr->ntype),
                                          fr->nbfp,
                                          egnb,
                                          &(nblists->tab.scale),
                                          tabledata,
                                          fr->invsqrta,
                                          fr->dvda,
                                          &(fr->gbtabscale),
                                          fr->gbtab.tab,
                                          &nthreads,
                                          &(nlist->count),
                                          nlist->mtx,
                                          &outeriter,
                                          &inneriter,
                                          (real *)&gbdata);
                        }
                        /* end of non pairwise force kernel */
		    }
                }
                
                /* Update flop accounting */
				
				/* Outer loop in kernel */
                switch (nlist->enlist) {
                case enlistATOM_ATOM:   fac =  1; break;
                case enlistSPC_ATOM:    fac =  3; break;
                case enlistSPC_SPC:     fac =  9; break;
                case enlistTIP4P_ATOM:  fac =  4; break;
                case enlistTIP4P_TIP4P: fac = 16; break;
                case enlistCG_CG:       fac =  1; break;
                }
                inc_nrnb(nrnb,eNR_NBKERNEL_OUTER,fac*outeriter);

                /* inner loop in kernel */
                inc_nrnb(nrnb,nrnb_ind,inneriter);
            }
        }
    }
}
Example #15
0
gmx_bool bshakef(FILE *log, gmx_shakedata_t shaked,
                 real invmass[], int nblocks, int sblock[],
                 t_idef *idef, t_inputrec *ir, rvec x_s[], rvec prime[],
                 t_nrnb *nrnb, real *scaled_lagrange_multiplier, real lambda, real *dvdlambda,
                 real invdt, rvec *v, gmx_bool bCalcVir, tensor vir_r_m_dr,
                 gmx_bool bDumpOnError, int econq)
{
    t_iatom *iatoms;
    real     dt_2, dvdl;
    int      i, n0, ncon, blen, type, ll;
    int      tnit = 0, trij = 0;

#ifdef DEBUG
    fprintf(log, "nblocks=%d, sblock[0]=%d\n", nblocks, sblock[0]);
#endif

    ncon = idef->il[F_CONSTR].nr/3;

    for (ll = 0; ll < ncon; ll++)
    {
        scaled_lagrange_multiplier[ll] = 0;
    }

    iatoms = &(idef->il[F_CONSTR].iatoms[sblock[0]]);
    for (i = 0; (i < nblocks); )
    {
        blen  = (sblock[i+1]-sblock[i]);
        blen /= 3;
        n0    = vec_shakef(log, shaked, invmass, blen, idef->iparams,
                           iatoms, ir->shake_tol, x_s, prime, shaked->omega,
                           ir->efep != efepNO, lambda, scaled_lagrange_multiplier, invdt, v, bCalcVir, vir_r_m_dr,
                           econq);

#ifdef DEBUGSHAKE
        check_cons(log, blen, x_s, prime, v, idef->iparams, iatoms, invmass, econq);
#endif

        if (n0 == 0)
        {
            if (bDumpOnError && log)
            {
                {
                    check_cons(log, blen, x_s, prime, v, idef->iparams, iatoms, invmass, econq);
                }
            }
            return FALSE;
        }
        tnit                       += n0*blen;
        trij                       += blen;
        iatoms                     += 3*blen; /* Increment pointer! */
        scaled_lagrange_multiplier += blen;
        i++;
    }
    /* only for position part? */
    if (econq == econqCoord)
    {
        if (ir->efep != efepNO)
        {
            real bondA, bondB;
            /* TODO This should probably use invdt, so that sd integrator scaling works properly */
            dt_2 = 1/gmx::square(ir->delta_t);
            dvdl = 0;
            for (ll = 0; ll < ncon; ll++)
            {
                type  = idef->il[F_CONSTR].iatoms[3*ll];

                /* Per equations in the manual, dv/dl = -2 \sum_ll lagrangian_ll * r_ll * (d_B - d_A) */
                /* The vector scaled_lagrange_multiplier[ll] contains the value -2 r_ll eta_ll (eta_ll is the
                   estimate of the Langrangian, definition on page 336 of Ryckaert et al 1977),
                   so the pre-factors are already present. */
                bondA = idef->iparams[type].constr.dA;
                bondB = idef->iparams[type].constr.dB;
                dvdl += scaled_lagrange_multiplier[ll] * dt_2 * (bondB - bondA);
            }
            *dvdlambda += dvdl;
        }
    }
#ifdef DEBUG
    fprintf(log, "tnit: %5d  omega: %10.5f\n", tnit, omega);
#endif
    if (ir->bShakeSOR)
    {
        if (tnit > shaked->gamma)
        {
            shaked->delta *= -0.5;
        }
        shaked->omega += shaked->delta;
        shaked->gamma  = tnit;
    }
    inc_nrnb(nrnb, eNR_SHAKE, tnit);
    inc_nrnb(nrnb, eNR_SHAKE_RIJ, trij);
    if (v)
    {
        inc_nrnb(nrnb, eNR_CONSTR_V, trij*2);
    }
    if (bCalcVir)
    {
        inc_nrnb(nrnb, eNR_CONSTR_VIR, trij);
    }

    return TRUE;
}
Example #16
0
void spread_q(FILE *log,bool bVerbose,
	      int start,int nr,
	      rvec x[],real charge[],rvec box,
	      t_fftgrid *grid,t_nrnb *nrnb)
{
  static bool bFirst = TRUE;
  static int  *nnx,*nny,*nnz;
  rvec   invh;
  real   qi,qwt;
#ifdef DEBUG
  real   qt;
#endif
  real   WXYZ[27];
  ivec   ixyz;
  int    i,iX,iY,iZ,index;
  int    jx,jy,jz,jcx,jcy,jcz;
  int    nxyz;
  int    nx,ny,nz,la2,la12;
  t_fft_r *ptr;
  
  unpack_fftgrid(grid,&nx,&ny,&nz,&la2,&la12,TRUE,&ptr);
  
  calc_invh(box,nx,ny,nz,invh);

  if (bFirst) {
    fprintf(log,"Spreading Charges using Triangle Shaped on %dx%dx%d grid\n",
	    nx,ny,nz);
    fprintf(log,"invh = %10g,%10g,%10g\n",invh[XX],invh[YY],invh[ZZ]);
  
    calc_nxyz(nx,ny,nz,&nnx,&nny,&nnz);
    
    bFirst = FALSE;
  }

  for(i=start; (i<start+nr); i++) {
    qi=charge[i];

    /* Each charge is spread over the nearest 27 grid cells,
     * thus we loop over -1..1 in X,Y and Z direction
     * We apply the TSC (triangle shaped charge)
     * see Luty et. al, JCP 103 (1995) 3014
     */
    
    if (fabs(qi) > GMX_REAL_MIN) {
      calc_weights(i,nx,ny,nz,x[i],box,invh,ixyz,WXYZ);
      iX  = ixyz[XX] + nx;
      iY  = ixyz[YY] + ny;
      iZ  = ixyz[ZZ] + nz;

#ifdef DEBUG
      qt=0;
#endif
      nxyz = 0;
      for(jx=-1; (jx<=1); jx++) {
	jcx = nnx[iX + jx];
	for(jy=-1; (jy<=1); jy++) {
	  jcy = nny[iY + jy];
	  for(jz=-1; (jz<=1); jz++,nxyz++) {
	    jcz   = nnz[iZ + jz];
	    index = INDEX(jcx,jcy,jcz);
	    qwt   = qi*WXYZ[nxyz];
	    grid->ptr[index]+=qwt;
#ifdef DEBUG
	    qt   += qwt;
	    if (bVerbose)
	      fprintf(log,"spread %4d %2d %2d %2d  %10.3e, weight=%10.3e\n",
		      index,jcx,jcy,jcz,grid->ptr[index],WXYZ[nxyz]);
#endif
	  }
	}
      }
#ifdef DEBUG
      fprintf(log,"q[%3d] = %6.3f, qwt = %6.3f\n",i,qi,qt);
#endif
    }
  }
  inc_nrnb(nrnb,eNR_SPREADQ,9*nr);
  inc_nrnb(nrnb,eNR_WEIGHTS,3*nr);
}
Example #17
0
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);
}
Example #18
0
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);
    }

}
Example #19
0
static real gather_f(FILE *log,bool bVerbose,
		     int start,int nr,rvec x[],rvec f[],real charge[],rvec box,
		     real pot[],t_fftgrid *grid,rvec beta,t_nrnb *nrnb)
{
  static bool bFirst=TRUE;
  static int  *nnx,*nny,*nnz;
  static int  JCXYZ[81];
  int    i,m;
  real   energy;
  real   qi,pi;
  ivec   ixyz;
  rvec   invh,c1,c2;
  real   WXYZ[27];
  real   c1x,c1y,c1z,c2x,c2y,c2z;
  int    ixw[7],iyw[7],izw[7];
  int    ll;
  int    nx,ny,nz,la2,la12;
  t_fft_r *ptr;
  
  unpack_fftgrid(grid,&nx,&ny,&nz,&la2,&la12,TRUE,&ptr);
  
  calc_invh(box,nx,ny,nz,invh);
  
  for(m=0; (m<DIM); m++) {
    c1[m] = (beta[m]/2.0)*invh[m];
    c2[m] = ((1.0-beta[m])/4.0)*invh[m];
  }
  c1x = c1[XX];
  c1y = c1[YY];
  c1z = c1[ZZ];
  c2x = c2[XX];
  c2y = c2[YY];
  c2z = c2[ZZ];

  if (bFirst) {
    fprintf(log,"Gathering Forces using Triangle Shaped on %dx%dx%d grid\n",
	    nx,ny,nz);
    fprintf(log,"beta = %10g,%10g,%10g\n",beta[XX],beta[YY],beta[ZZ]);
    fprintf(log,"c1   = %10g,%10g,%10g\n",c1[XX],c1[YY],c1[ZZ]);
    fprintf(log,"c2   = %10g,%10g,%10g\n",c2[XX],c2[YY],c2[ZZ]);
    fprintf(log,"invh = %10g,%10g,%10g\n",invh[XX],invh[YY],invh[ZZ]);

    calc_nxyz(nx,ny,nz,&nnx,&nny,&nnz);

    for(i=0; (i<27); i++) {
      JCXYZ[3*i]   = 2 + (i/9);
      JCXYZ[3*i+1] = 2 + (i/3) % 3;
      JCXYZ[3*i+2] = 2 + (i % 3); 
    }
    
    bFirst = FALSE;
  }

  energy=0.0;  	  
  for(i=start; (i<start+nr); i++) {
    /* Each charge is spread over the nearest 27 grid cells,
     * thus we loop over -1..1 in X,Y and Z direction
     * We apply the TSC (triangle shaped charge)
     * see Luty et. al, JCP 103 (1995) 3014
     */
     
    calc_weights(i,nx,ny,nz,x[i],box,invh,ixyz,WXYZ);

    for(ll=llim2; (ll<=ulim2); ll++) {
      ixw[ll-llim2] = nnx[ixyz[XX]+ll+nx];
      iyw[ll-llim2] = nny[ixyz[YY]+ll+ny];
      izw[ll-llim2] = nnz[ixyz[ZZ]+ll+nz];
    }
    
    qi      = charge[i];
    pi      = gather_inner(JCXYZ,WXYZ,ixw,iyw,izw,la2,la12,
			   c1x,c1y,c1z,c2x,c2y,c2z,
			   qi,f[i],ptr);
    
    energy += pi*qi;
    pot[i]  = pi;
  }
  
  inc_nrnb(nrnb,eNR_GATHERF,27*nr);
  inc_nrnb(nrnb,eNR_WEIGHTS,3*nr);
  
  return energy*0.5;
}
Example #20
0
void
gmx_nb_free_energy_kernel(t_nblist *                nlist,
                          rvec *                    xx,
                          rvec *                    ff,
                          t_forcerec *              fr,
                          t_mdatoms *               mdatoms,
                          nb_kernel_data_t *        kernel_data,
                          t_nrnb *                  nrnb)
{

#define  STATE_A  0
#define  STATE_B  1
#define  NSTATES  2
    int           i, j, n, ii, is3, ii3, k, nj0, nj1, jnr, j3, ggid;
    real          shX, shY, shZ;
    real          Fscal, FscalC[NSTATES], FscalV[NSTATES], tx, ty, tz;
    real          Vcoul[NSTATES], Vvdw[NSTATES];
    real          rinv6, r, rt, rtC, rtV;
    real          iqA, iqB;
    real          qq[NSTATES], vctot, krsq;
    int           ntiA, ntiB, tj[NSTATES];
    real          Vvdw6, Vvdw12, vvtot;
    real          ix, iy, iz, fix, fiy, fiz;
    real          dx, dy, dz, rsq, rinv;
    real          c6[NSTATES], c12[NSTATES];
    real          LFC[NSTATES], LFV[NSTATES], DLF[NSTATES];
    double        dvdl_coul, dvdl_vdw;
    real          lfac_coul[NSTATES], dlfac_coul[NSTATES], lfac_vdw[NSTATES], dlfac_vdw[NSTATES];
    real          sigma6[NSTATES], alpha_vdw_eff, alpha_coul_eff, sigma2_def, sigma2_min;
    real          rp, rpm2, rC, rV, rinvC, rpinvC, rinvV, rpinvV;
    real          sigma2[NSTATES], sigma_pow[NSTATES], sigma_powm2[NSTATES], rs, rs2;
    int           do_coultab, do_vdwtab, do_tab, tab_elemsize;
    int           n0, n1C, n1V, nnn;
    real          Y, F, G, H, Fp, Geps, Heps2, epsC, eps2C, epsV, eps2V, VV, FF;
    int           icoul, ivdw;
    int           nri;
    int *         iinr;
    int *         jindex;
    int *         jjnr;
    int *         shift;
    int *         gid;
    int *         typeA;
    int *         typeB;
    int           ntype;
    real *        shiftvec;
    real          dvdl_part;
    real *        fshift;
    real          tabscale;
    real *        VFtab;
    real *        x;
    real *        f;
    real          facel, krf, crf;
    real *        chargeA;
    real *        chargeB;
    real          sigma6_min, sigma6_def, lam_power, sc_power, sc_r_power;
    real          alpha_coul, alpha_vdw, lambda_coul, lambda_vdw, ewc;
    real *        nbfp;
    real *        dvdl;
    real *        Vv;
    real *        Vc;
    gmx_bool      bDoForces;
    real          rcoulomb, rvdw, sh_invrc6;
    gmx_bool      bExactElecCutoff, bExactVdwCutoff;
    real          rcutoff, rcutoff2, rswitch, d, d2, swV3, swV4, swV5, swF2, swF3, swF4, sw, dsw, rinvcorr;

    x                   = xx[0];
    f                   = ff[0];

    fshift              = fr->fshift[0];
    Vc                  = kernel_data->energygrp_elec;
    Vv                  = kernel_data->energygrp_vdw;
    tabscale            = kernel_data->table_elec_vdw->scale;
    VFtab               = kernel_data->table_elec_vdw->data;

    nri                 = nlist->nri;
    iinr                = nlist->iinr;
    jindex              = nlist->jindex;
    jjnr                = nlist->jjnr;
    icoul               = nlist->ielec;
    ivdw                = nlist->ivdw;
    shift               = nlist->shift;
    gid                 = nlist->gid;

    shiftvec            = fr->shift_vec[0];
    chargeA             = mdatoms->chargeA;
    chargeB             = mdatoms->chargeB;
    facel               = fr->epsfac;
    krf                 = fr->k_rf;
    crf                 = fr->c_rf;
    ewc                 = fr->ewaldcoeff;
    Vc                  = kernel_data->energygrp_elec;
    typeA               = mdatoms->typeA;
    typeB               = mdatoms->typeB;
    ntype               = fr->ntype;
    nbfp                = fr->nbfp;
    Vv                  = kernel_data->energygrp_vdw;
    tabscale            = kernel_data->table_elec_vdw->scale;
    VFtab               = kernel_data->table_elec_vdw->data;
    lambda_coul         = kernel_data->lambda[efptCOUL];
    lambda_vdw          = kernel_data->lambda[efptVDW];
    dvdl                = kernel_data->dvdl;
    alpha_coul          = fr->sc_alphacoul;
    alpha_vdw           = fr->sc_alphavdw;
    lam_power           = fr->sc_power;
    sc_r_power          = fr->sc_r_power;
    sigma6_def          = fr->sc_sigma6_def;
    sigma6_min          = fr->sc_sigma6_min;
    bDoForces           = kernel_data->flags & GMX_NONBONDED_DO_FORCE;

    rcoulomb            = fr->rcoulomb;
    rvdw                = fr->rvdw;
    sh_invrc6           = fr->ic->sh_invrc6;

    if (fr->coulomb_modifier == eintmodPOTSWITCH || fr->vdw_modifier == eintmodPOTSWITCH)
    {
        rcutoff         = (fr->coulomb_modifier == eintmodPOTSWITCH) ? fr->rcoulomb : fr->rvdw;
        rcutoff2        = rcutoff*rcutoff;
        rswitch         = (fr->coulomb_modifier == eintmodPOTSWITCH) ? fr->rcoulomb_switch : fr->rvdw_switch;
        d               = rcutoff-rswitch;
        swV3            = -10.0/(d*d*d);
        swV4            =  15.0/(d*d*d*d);
        swV5            =  -6.0/(d*d*d*d*d);
        swF2            = -30.0/(d*d*d);
        swF3            =  60.0/(d*d*d*d);
        swF4            = -30.0/(d*d*d*d*d);
    }
    else
    {
        /* Stupid compilers dont realize these variables will not be used */
        rswitch         = 0.0;
        swV3            = 0.0;
        swV4            = 0.0;
        swV5            = 0.0;
        swF2            = 0.0;
        swF3            = 0.0;
        swF4            = 0.0;
    }

    bExactElecCutoff    = (fr->coulomb_modifier != eintmodNONE) || fr->eeltype == eelRF_ZERO;
    bExactVdwCutoff     = (fr->vdw_modifier != eintmodNONE);

    /* fix compiler warnings */
    nj1   = 0;
    n1C   = n1V   = 0;
    epsC  = epsV  = 0;
    eps2C = eps2V = 0;

    dvdl_coul  = 0;
    dvdl_vdw   = 0;

    /* Lambda factor for state A, 1-lambda*/
    LFC[STATE_A] = 1.0 - lambda_coul;
    LFV[STATE_A] = 1.0 - lambda_vdw;

    /* Lambda factor for state B, lambda*/
    LFC[STATE_B] = lambda_coul;
    LFV[STATE_B] = lambda_vdw;

    /*derivative of the lambda factor for state A and B */
    DLF[STATE_A] = -1;
    DLF[STATE_B] = 1;

    for (i = 0; i < NSTATES; i++)
    {
        lfac_coul[i]  = (lam_power == 2 ? (1-LFC[i])*(1-LFC[i]) : (1-LFC[i]));
        dlfac_coul[i] = DLF[i]*lam_power/sc_r_power*(lam_power == 2 ? (1-LFC[i]) : 1);
        lfac_vdw[i]   = (lam_power == 2 ? (1-LFV[i])*(1-LFV[i]) : (1-LFV[i]));
        dlfac_vdw[i]  = DLF[i]*lam_power/sc_r_power*(lam_power == 2 ? (1-LFV[i]) : 1);
    }
    /* precalculate */
    sigma2_def = pow(sigma6_def, 1.0/3.0);
    sigma2_min = pow(sigma6_min, 1.0/3.0);

    /* Ewald (not PME) table is special (icoul==enbcoulFEWALD) */

    do_coultab = (icoul == GMX_NBKERNEL_ELEC_CUBICSPLINETABLE);
    do_vdwtab  = (ivdw == GMX_NBKERNEL_VDW_CUBICSPLINETABLE);

    do_tab = do_coultab || do_vdwtab;

    /* we always use the combined table here */
    tab_elemsize = 12;

    for (n = 0; (n < nri); n++)
    {
        is3              = 3*shift[n];
        shX              = shiftvec[is3];
        shY              = shiftvec[is3+1];
        shZ              = shiftvec[is3+2];
        nj0              = jindex[n];
        nj1              = jindex[n+1];
        ii               = iinr[n];
        ii3              = 3*ii;
        ix               = shX + x[ii3+0];
        iy               = shY + x[ii3+1];
        iz               = shZ + x[ii3+2];
        iqA              = facel*chargeA[ii];
        iqB              = facel*chargeB[ii];
        ntiA             = 2*ntype*typeA[ii];
        ntiB             = 2*ntype*typeB[ii];
        vctot            = 0;
        vvtot            = 0;
        fix              = 0;
        fiy              = 0;
        fiz              = 0;

        for (k = nj0; (k < nj1); k++)
        {
            jnr              = jjnr[k];
            j3               = 3*jnr;
            dx               = ix - x[j3];
            dy               = iy - x[j3+1];
            dz               = iz - x[j3+2];
            rsq              = dx*dx+dy*dy+dz*dz;
            rinv             = gmx_invsqrt(rsq);
            r                = rsq*rinv;
            if (sc_r_power == 6.0)
            {
                rpm2             = rsq*rsq;  /* r4 */
                rp               = rpm2*rsq; /* r6 */
            }
            else if (sc_r_power == 48.0)
            {
                rp               = rsq*rsq*rsq; /* r6 */
                rp               = rp*rp;       /* r12 */
                rp               = rp*rp;       /* r24 */
                rp               = rp*rp;       /* r48 */
                rpm2             = rp/rsq;      /* r46 */
            }
            else
            {
                rp             = pow(r, sc_r_power);  /* not currently supported as input, but can handle it */
                rpm2           = rp/rsq;
            }

            tj[STATE_A]      = ntiA+2*typeA[jnr];
            tj[STATE_B]      = ntiB+2*typeB[jnr];
            qq[STATE_A]      = iqA*chargeA[jnr];
            qq[STATE_B]      = iqB*chargeB[jnr];

            for (i = 0; i < NSTATES; i++)
            {

                c6[i]              = nbfp[tj[i]];
                c12[i]             = nbfp[tj[i]+1];
                if ((c6[i] > 0) && (c12[i] > 0))
                {
                    /* c12 is stored scaled with 12.0 and c6 is scaled with 6.0 - correct for this */
                    sigma6[i]       = 0.5*c12[i]/c6[i];
                    sigma2[i]       = pow(sigma6[i], 1.0/3.0);
                    /* should be able to get rid of this ^^^ internal pow call eventually.  Will require agreement on
                       what data to store externally.  Can't be fixed without larger scale changes, so not 4.6 */
                    if (sigma6[i] < sigma6_min)   /* for disappearing coul and vdw with soft core at the same time */
                    {
                        sigma6[i] = sigma6_min;
                        sigma2[i] = sigma2_min;
                    }
                }
                else
                {
                    sigma6[i]       = sigma6_def;
                    sigma2[i]       = sigma2_def;
                }
                if (sc_r_power == 6.0)
                {
                    sigma_pow[i]    = sigma6[i];
                    sigma_powm2[i]  = sigma6[i]/sigma2[i];
                }
                else if (sc_r_power == 48.0)
                {
                    sigma_pow[i]    = sigma6[i]*sigma6[i];       /* sigma^12 */
                    sigma_pow[i]    = sigma_pow[i]*sigma_pow[i]; /* sigma^24 */
                    sigma_pow[i]    = sigma_pow[i]*sigma_pow[i]; /* sigma^48 */
                    sigma_powm2[i]  = sigma_pow[i]/sigma2[i];
                }
                else
                {    /* not really supported as input, but in here for testing the general case*/
                    sigma_pow[i]    = pow(sigma2[i], sc_r_power/2);
                    sigma_powm2[i]  = sigma_pow[i]/(sigma2[i]);
                }
            }

            /* only use softcore if one of the states has a zero endstate - softcore is for avoiding infinities!*/
            if ((c12[STATE_A] > 0) && (c12[STATE_B] > 0))
            {
                alpha_vdw_eff    = 0;
                alpha_coul_eff   = 0;
            }
            else
            {
                alpha_vdw_eff    = alpha_vdw;
                alpha_coul_eff   = alpha_coul;
            }

            for (i = 0; i < NSTATES; i++)
            {
                FscalC[i]    = 0;
                FscalV[i]    = 0;
                Vcoul[i]     = 0;
                Vvdw[i]      = 0;

                /* Only spend time on A or B state if it is non-zero */
                if ( (qq[i] != 0) || (c6[i] != 0) || (c12[i] != 0) )
                {

                    /* this section has to be inside the loop becaue of the dependence on sigma_pow */
                    rpinvC         = 1.0/(alpha_coul_eff*lfac_coul[i]*sigma_pow[i]+rp);
                    rinvC          = pow(rpinvC, 1.0/sc_r_power);
                    rC             = 1.0/rinvC;

                    rpinvV         = 1.0/(alpha_vdw_eff*lfac_vdw[i]*sigma_pow[i]+rp);
                    rinvV          = pow(rpinvV, 1.0/sc_r_power);
                    rV             = 1.0/rinvV;

                    if (do_tab)
                    {
                        rtC        = rC*tabscale;
                        n0         = rtC;
                        epsC       = rtC-n0;
                        eps2C      = epsC*epsC;
                        n1C        = tab_elemsize*n0;

                        rtV        = rV*tabscale;
                        n0         = rtV;
                        epsV       = rtV-n0;
                        eps2V      = epsV*epsV;
                        n1V        = tab_elemsize*n0;
                    }

                    /* With Ewald and soft-core we should put the cut-off on r,
                     * not on the soft-cored rC, as the real-space and
                     * reciprocal space contributions should (almost) cancel.
                     */
                    if (qq[i] != 0 &&
                        !(bExactElecCutoff &&
                          ((icoul != GMX_NBKERNEL_ELEC_EWALD && rC >= rcoulomb) ||
                           (icoul == GMX_NBKERNEL_ELEC_EWALD && r >= rcoulomb))))
                    {
                        switch (icoul)
                        {
                            case GMX_NBKERNEL_ELEC_COULOMB:
                            case GMX_NBKERNEL_ELEC_EWALD:
                                /* simple cutoff (yes, ewald is done all on direct space for free energy) */
                                Vcoul[i]   = qq[i]*rinvC;
                                FscalC[i]  = Vcoul[i]*rpinvC;
                                break;

                            case GMX_NBKERNEL_ELEC_REACTIONFIELD:
                                /* reaction-field */
                                Vcoul[i]   = qq[i]*(rinvC+krf*rC*rC-crf);
                                FscalC[i]  = qq[i]*(rinvC*rpinvC-2.0*krf);
                                break;

                            case GMX_NBKERNEL_ELEC_CUBICSPLINETABLE:
                                /* non-Ewald tabulated coulomb */
                                nnn        = n1C;
                                Y          = VFtab[nnn];
                                F          = VFtab[nnn+1];
                                Geps       = epsC*VFtab[nnn+2];
                                Heps2      = eps2C*VFtab[nnn+3];
                                Fp         = F+Geps+Heps2;
                                VV         = Y+epsC*Fp;
                                FF         = Fp+Geps+2.0*Heps2;
                                Vcoul[i]   = qq[i]*VV;
                                FscalC[i]  = -qq[i]*tabscale*FF*rC*rpinvC;
                                break;

                            default:
                                FscalC[i]  = 0.0;
                                Vcoul[i]   = 0.0;
                                break;
                        }

                        if (fr->coulomb_modifier == eintmodPOTSWITCH)
                        {
                            d                = rC-rswitch;
                            d                = (d > 0.0) ? d : 0.0;
                            d2               = d*d;
                            sw               = 1.0+d2*d*(swV3+d*(swV4+d*swV5));
                            dsw              = d2*(swF2+d*(swF3+d*swF4));

                            Vcoul[i]        *= sw;
                            FscalC[i]        = FscalC[i]*sw + Vcoul[i]*dsw;
                        }
                    }

                    if ((c6[i] != 0 || c12[i] != 0) &&
                        !(bExactVdwCutoff && rV >= rvdw))
                    {
                        switch (ivdw)
                        {
                            case GMX_NBKERNEL_VDW_LENNARDJONES:
                                /* cutoff LJ */
                                if (sc_r_power == 6.0)
                                {
                                    rinv6            = rpinvV;
                                }
                                else
                                {
                                    rinv6            = pow(rinvV, 6.0);
                                }
                                Vvdw6            = c6[i]*rinv6;
                                Vvdw12           = c12[i]*rinv6*rinv6;
                                if (fr->vdw_modifier == eintmodPOTSHIFT)
                                {
                                    Vvdw[i]          = ( (Vvdw12-c12[i]*sh_invrc6*sh_invrc6)*(1.0/12.0)
                                                         -(Vvdw6-c6[i]*sh_invrc6)*(1.0/6.0));
                                }
                                else
                                {
                                    Vvdw[i]          = Vvdw12*(1.0/12.0)-Vvdw6*(1.0/6.0);
                                }
                                FscalV[i]        = (Vvdw12-Vvdw6)*rpinvV;
                                break;

                            case GMX_NBKERNEL_VDW_BUCKINGHAM:
                                gmx_fatal(FARGS, "Buckingham free energy not supported.");
                                break;

                            case GMX_NBKERNEL_VDW_CUBICSPLINETABLE:
                                /* Table LJ */
                                nnn = n1V+4;
                                /* dispersion */
                                Y          = VFtab[nnn];
                                F          = VFtab[nnn+1];
                                Geps       = epsV*VFtab[nnn+2];
                                Heps2      = eps2V*VFtab[nnn+3];
                                Fp         = F+Geps+Heps2;
                                VV         = Y+epsV*Fp;
                                FF         = Fp+Geps+2.0*Heps2;
                                Vvdw[i]   += c6[i]*VV;
                                FscalV[i] -= c6[i]*tabscale*FF*rV*rpinvV;

                                /* repulsion */
                                Y          = VFtab[nnn+4];
                                F          = VFtab[nnn+5];
                                Geps       = epsV*VFtab[nnn+6];
                                Heps2      = eps2V*VFtab[nnn+7];
                                Fp         = F+Geps+Heps2;
                                VV         = Y+epsV*Fp;
                                FF         = Fp+Geps+2.0*Heps2;
                                Vvdw[i]   += c12[i]*VV;
                                FscalV[i] -= c12[i]*tabscale*FF*rV*rpinvV;
                                break;

                            default:
                                Vvdw[i]    = 0.0;
                                FscalV[i]  = 0.0;
                                break;
                        }

                        if (fr->vdw_modifier == eintmodPOTSWITCH)
                        {
                            d                = rV-rswitch;
                            d                = (d > 0.0) ? d : 0.0;
                            d2               = d*d;
                            sw               = 1.0+d2*d*(swV3+d*(swV4+d*swV5));
                            dsw              = d2*(swF2+d*(swF3+d*swF4));

                            Vvdw[i]         *= sw;
                            FscalV[i]        = FscalV[i]*sw + Vvdw[i]*dsw;

                            FscalV[i]        = (rV < rvdw) ? FscalV[i] : 0.0;
                            Vvdw[i]          = (rV < rvdw) ? Vvdw[i] : 0.0;
                        }
                    }
                }
            }

            Fscal = 0;

            if (icoul == GMX_NBKERNEL_ELEC_EWALD &&
                !(bExactElecCutoff && r >= rcoulomb))
            {
                /* because we compute the softcore normally,
                   we have to remove the ewald short range portion. Done outside of
                   the states loop because this part doesn't depend on the scaled R */

#ifdef GMX_DOUBLE
                /* Relative accuracy at R_ERF_R_INACC of 3e-10 */
#define         R_ERF_R_INACC 0.006
#else
                /* Relative accuracy at R_ERF_R_INACC of 2e-5 */
#define         R_ERF_R_INACC 0.1
#endif
                if (ewc*r > R_ERF_R_INACC)
                {
                    VV    = gmx_erf(ewc*r)*rinv;
                    FF    = rinv*rinv*(VV - ewc*M_2_SQRTPI*exp(-ewc*ewc*rsq));
                }
                else
                {
                    VV    = ewc*M_2_SQRTPI;
                    FF    = ewc*ewc*ewc*M_2_SQRTPI*(2.0/3.0 - 0.4*ewc*ewc*rsq);
                }

                for (i = 0; i < NSTATES; i++)
                {
                    vctot      -= LFC[i]*qq[i]*VV;
                    Fscal      -= LFC[i]*qq[i]*FF;
                    dvdl_coul  -= (DLF[i]*qq[i])*VV;
                }
            }

            /* Assemble A and B states */
            for (i = 0; i < NSTATES; i++)
            {
                vctot         += LFC[i]*Vcoul[i];
                vvtot         += LFV[i]*Vvdw[i];

                Fscal         += LFC[i]*FscalC[i]*rpm2;
                Fscal         += LFV[i]*FscalV[i]*rpm2;

                dvdl_coul     += Vcoul[i]*DLF[i] + LFC[i]*alpha_coul_eff*dlfac_coul[i]*FscalC[i]*sigma_pow[i];
                dvdl_vdw      += Vvdw[i]*DLF[i] + LFV[i]*alpha_vdw_eff*dlfac_vdw[i]*FscalV[i]*sigma_pow[i];
            }

            if (bDoForces)
            {
                tx         = Fscal*dx;
                ty         = Fscal*dy;
                tz         = Fscal*dz;
                fix        = fix + tx;
                fiy        = fiy + ty;
                fiz        = fiz + tz;
                f[j3]      = f[j3]   - tx;
                f[j3+1]    = f[j3+1] - ty;
                f[j3+2]    = f[j3+2] - tz;
            }
        }

        if (bDoForces)
        {
            f[ii3]         = f[ii3]        + fix;
            f[ii3+1]       = f[ii3+1]      + fiy;
            f[ii3+2]       = f[ii3+2]      + fiz;
            fshift[is3]    = fshift[is3]   + fix;
            fshift[is3+1]  = fshift[is3+1] + fiy;
            fshift[is3+2]  = fshift[is3+2] + fiz;
        }
        ggid               = gid[n];
        Vc[ggid]           = Vc[ggid] + vctot;
        Vv[ggid]           = Vv[ggid] + vvtot;
    }

    dvdl[efptCOUL]     += dvdl_coul;
    dvdl[efptVDW]      += dvdl_vdw;

    /* Estimate flops, average for free energy stuff:
     * 12  flops per outer iteration
     * 150 flops per inner iteration
     */
    inc_nrnb(nrnb, eNR_NBKERNEL_FREE_ENERGY, nlist->nri*12 + nlist->jindex[n]*150);
}
Example #21
0
real do_walls(t_inputrec *ir,t_forcerec *fr,matrix box,t_mdatoms *md,
	      rvec x[],rvec f[],real lambda,real Vlj[],t_nrnb *nrnb)
{
    int  nwall,w,lam,i;
    int  ntw[2],at,ntype,ngid,ggid,*egp_flags,*type;
    real *nbfp,lamfac,fac_d[2],fac_r[2],Cd,Cr,Vtot,Fwall[2];
    real wall_z[2],r,mr,r1,r2,r4,Vd,Vr,V=0,Fd,Fr,F=0,dvdlambda;
    dvec xf_z;
    int  n0,nnn;
    real tabscale,*VFtab,rt,eps,eps2,Yt,Ft,Geps,Heps,Heps2,Fp,VV,FF;
    unsigned short *gid=md->cENER;
    t_forcetable *tab;

    nwall     = ir->nwall;
    ngid      = ir->opts.ngener;
    ntype     = fr->ntype;
    nbfp      = fr->nbfp;
    egp_flags = fr->egp_flags;

    for(w=0; w<nwall; w++)
    {
        ntw[w] = 2*ntype*ir->wall_atomtype[w];
        switch (ir->wall_type)
        {
        case ewt93:
            fac_d[w] = ir->wall_density[w]*M_PI/6;
            fac_r[w] = ir->wall_density[w]*M_PI/45;
            break;
        case ewt104:
            fac_d[w] = ir->wall_density[w]*M_PI/2;
            fac_r[w] = ir->wall_density[w]*M_PI/5;
            break;
        default:
            break;
        }
        Fwall[w] = 0;
    }
    wall_z[0] = 0;
    wall_z[1] = box[ZZ][ZZ];

    Vtot = 0;
    dvdlambda = 0;
    clear_dvec(xf_z);
    for(lam=0; lam<(md->nPerturbed ? 2 : 1); lam++)
    {
        if (md->nPerturbed)
        {
            if (lam == 0)
            {
                lamfac = 1 - lambda;
                type = md->typeA;
            }
            else
            {
                lamfac = 0;
                type = md->typeB;
            }
        }
        else
        {
            lamfac = 1;
            type = md->typeA;
        }
        for(i=md->start; i<md->start+md->homenr; i++)
        {
            for(w=0; w<nwall; w++)
            {
                /* The wall energy groups are always at the end of the list */
                ggid = gid[i]*ngid + ngid - nwall + w;
                at = type[i];
                Cd = nbfp[ntw[w]+2*at];
                Cr = nbfp[ntw[w]+2*at+1];
                if (!((Cd==0 && Cr==0) || (egp_flags[ggid] & EGP_EXCL)))
                {
                    if (w == 0)
                    {
                        r = x[i][ZZ];
                    }
                    else
                    {
                        r = wall_z[1] - x[i][ZZ];
                    }
                    if (r < ir->wall_r_linpot)
                    {
                        mr = ir->wall_r_linpot - r;
                        r  = ir->wall_r_linpot;
                    }
                    else
                    {
                        mr = 0;
                    }
                    switch (ir->wall_type)
                    {
                    case ewtTABLE:
                        if (r < 0)
                        {
                            wall_error(i,x,r);
                        }
                        tab = &(fr->wall_tab[w][gid[i]]);
                        tabscale = tab->scale;
                        VFtab    = tab->tab;
                        
                        rt    = r*tabscale;
                        n0    = rt;
                        if (n0 >= tab->n)
                        {
                            /* Beyond the table range, set V and F to zero */
                            V     = 0;
                            F     = 0;
                        }
                        else
                        {
                            eps   = rt - n0;
                            eps2  = eps*eps;
                            /* Dispersion */
                            nnn   = 8*n0;
                            Yt    = VFtab[nnn];
                            Ft    = VFtab[nnn+1];
                            Geps  = VFtab[nnn+2]*eps;
                            Heps2 = VFtab[nnn+3]*eps2;
                            Fp    = Ft + Geps + Heps2;
                            VV    = Yt + Fp*eps;
                            FF    = Fp + Geps + 2.0*Heps2;
                            Vd    = Cd*VV;
                            Fd    = Cd*FF;
                            /* Repulsion */
                            nnn   = nnn + 4;
                            Yt    = VFtab[nnn];
                            Ft    = VFtab[nnn+1];
                            Geps  = VFtab[nnn+2]*eps;
                            Heps2 = VFtab[nnn+3]*eps2;
                            Fp    = Ft + Geps + Heps2;
                            VV    = Yt + Fp*eps;
                            FF    = Fp + Geps + 2.0*Heps2;
                            Vr    = Cr*VV;
                            Fr    = Cr*FF;
                            V     = Vd + Vr;
                            F     = -lamfac*(Fd + Fr)*tabscale;
                        }
                        break;
                    case ewt93:
                        if (r <= 0)
                        {
                            wall_error(i,x,r);
                        }
                        r1 = 1/r;
                        r2 = r1*r1;
                        r4 = r2*r2;
                        Vd = fac_d[w]*Cd*r2*r1;
                        Vr = fac_r[w]*Cr*r4*r4*r1;
                        V  = Vr - Vd;
                        F  = lamfac*(9*Vr - 3*Vd)*r1;
                        break;
                    case ewt104:
                        if (r <= 0)
                        {
                            wall_error(i,x,r);
                        }
                        r1 = 1/r;
                        r2 = r1*r1;
                        r4 = r2*r2;
                        Vd = fac_d[w]*Cd*r4;
                        Vr = fac_r[w]*Cr*r4*r4*r2;
                        V  = Vr - Vd;
                        F  = lamfac*(10*Vr - 4*Vd)*r1;
                        break;
                    case ewt126:
                        if (r <= 0)
                        {
                            wall_error(i,x,r);
                        }
                        r1 = 1/r;
                        r2 = r1*r1;
                        r4 = r2*r2;
                        Vd = Cd*r4*r2;
                        Vr = Cr*r4*r4*r4;
                        V  = Vr - Vd;
                        F  = lamfac*(12*Vr - 6*Vd)*r1;
                        break;
                    default:
                        break;
                    }
                    if (mr > 0)
                    {
                        V += mr*F;
                    }
                    if (w == 1)
                    {
                        F = -F;
                    }
                    Vlj[ggid] += lamfac*V;
                    Vtot      += V;
                    f[i][ZZ]  += F;
                    /* Because of the single sum virial calculation we need
                     * to add  the full virial contribution of the walls.
                     * Since the force only has a z-component, there is only
                     * a contribution to the z component of the virial tensor.
                     * We could also determine the virial contribution directly,
                     * which would be cheaper here, but that would require extra
                     * communication for f_novirsum for with virtual sites
                     * in parallel.
                     */
                    xf_z[XX]  -= x[i][XX]*F;
                    xf_z[YY]  -= x[i][YY]*F;
                    xf_z[ZZ]  -= wall_z[w]*F;
                }
            }
        }
        if (md->nPerturbed)
        {
            dvdlambda += (lam==0 ? -1 : 1)*Vtot;
        }
        
        inc_nrnb(nrnb,eNR_WALLS,md->homenr);
    }

    for(i=0; i<DIM; i++)
    {
        fr->vir_wall_z[i] = -0.5*xf_z[i];
    }
    
    return dvdlambda;
}
Example #22
0
/* TODO Specialize this routine into init-time and loop-time versions?
   e.g. bReadEkin is only true when restoring from checkpoint */
void compute_globals(FILE *fplog, gmx_global_stat *gstat, t_commrec *cr, t_inputrec *ir,
                     t_forcerec *fr, gmx_ekindata_t *ekind,
                     t_state *state, t_mdatoms *mdatoms,
                     t_nrnb *nrnb, t_vcm *vcm, gmx_wallcycle_t wcycle,
                     gmx_enerdata_t *enerd, tensor force_vir, tensor shake_vir, tensor total_vir,
                     tensor pres, rvec mu_tot, gmx_constr_t constr,
                     gmx::SimulationSignaller *signalCoordinator,
                     matrix box, int *totalNumberOfBondedInteractions,
                     gmx_bool *bSumEkinhOld, int flags)
{
    tensor   corr_vir, corr_pres;
    gmx_bool bEner, bPres, bTemp;
    gmx_bool bStopCM, bGStat,
             bReadEkin, bEkinAveVel, bScaleEkin, bConstrain;
    real     prescorr, enercorr, dvdlcorr, dvdl_ekin;

    /* translate CGLO flags to gmx_booleans */
    bStopCM       = flags & CGLO_STOPCM;
    bGStat        = flags & CGLO_GSTAT;
    bReadEkin     = (flags & CGLO_READEKIN);
    bScaleEkin    = (flags & CGLO_SCALEEKIN);
    bEner         = flags & CGLO_ENERGY;
    bTemp         = flags & CGLO_TEMPERATURE;
    bPres         = (flags & CGLO_PRESSURE);
    bConstrain    = (flags & CGLO_CONSTRAINT);

    /* we calculate a full state kinetic energy either with full-step velocity verlet
       or half step where we need the pressure */

    bEkinAveVel = (ir->eI == eiVV || (ir->eI == eiVVAK && bPres) || bReadEkin);

    /* in initalization, it sums the shake virial in vv, and to
       sums ekinh_old in leapfrog (or if we are calculating ekinh_old) for other reasons */

    /* ########## Kinetic energy  ############## */

    if (bTemp)
    {
        /* Non-equilibrium MD: this is parallellized, but only does communication
         * when there really is NEMD.
         */

        if (PAR(cr) && (ekind->bNEMD))
        {
            accumulate_u(cr, &(ir->opts), ekind);
        }
        if (!bReadEkin)
        {
            calc_ke_part(state, &(ir->opts), mdatoms, ekind, nrnb, bEkinAveVel);
        }
    }

    /* Calculate center of mass velocity if necessary, also parallellized */
    if (bStopCM)
    {
        calc_vcm_grp(0, mdatoms->homenr, mdatoms,
                     state->x, state->v, vcm);
    }

    if (bTemp || bStopCM || bPres || bEner || bConstrain)
    {
        if (!bGStat)
        {
            /* We will not sum ekinh_old,
             * so signal that we still have to do it.
             */
            *bSumEkinhOld = TRUE;

        }
        else
        {
            gmx::ArrayRef<real> signalBuffer = signalCoordinator->getCommunicationBuffer();
            if (PAR(cr))
            {
                wallcycle_start(wcycle, ewcMoveE);
                global_stat(gstat, cr, enerd, force_vir, shake_vir, mu_tot,
                            ir, ekind, constr, bStopCM ? vcm : NULL,
                            signalBuffer.size(), signalBuffer.data(),
                            totalNumberOfBondedInteractions,
                            *bSumEkinhOld, flags);
                wallcycle_stop(wcycle, ewcMoveE);
            }
            signalCoordinator->finalizeSignals();
            *bSumEkinhOld = FALSE;
        }
    }

    if (!ekind->bNEMD && debug && bTemp && (vcm->nr > 0))
    {
        correct_ekin(debug,
                     0, mdatoms->homenr,
                     state->v, vcm->group_p[0],
                     mdatoms->massT, mdatoms->tmass, ekind->ekin);
    }

    /* Do center of mass motion removal */
    if (bStopCM)
    {
        check_cm_grp(fplog, vcm, ir, 1);
        do_stopcm_grp(0, mdatoms->homenr, mdatoms->cVCM,
                      state->x, state->v, vcm);
        inc_nrnb(nrnb, eNR_STOPCM, mdatoms->homenr);
    }

    if (bEner)
    {
        /* Calculate the amplitude of the cosine velocity profile */
        ekind->cosacc.vcos = ekind->cosacc.mvcos/mdatoms->tmass;
    }

    if (bTemp)
    {
        /* Sum the kinetic energies of the groups & calc temp */
        /* compute full step kinetic energies if vv, or if vv-avek and we are computing the pressure with inputrecNptTrotter */
        /* three maincase:  VV with AveVel (md-vv), vv with AveEkin (md-vv-avek), leap with AveEkin (md).
           Leap with AveVel is not supported; it's not clear that it will actually work.
           bEkinAveVel: If TRUE, we simply multiply ekin by ekinscale to get a full step kinetic energy.
           If FALSE, we average ekinh_old and ekinh*ekinscale_nhc to get an averaged half step kinetic energy.
         */
        enerd->term[F_TEMP] = sum_ekin(&(ir->opts), ekind, &dvdl_ekin,
                                       bEkinAveVel, bScaleEkin);
        enerd->dvdl_lin[efptMASS] = (double) dvdl_ekin;

        enerd->term[F_EKIN] = trace(ekind->ekin);
    }

    /* ##########  Long range energy information ###### */

    if (bEner || bPres || bConstrain)
    {
        calc_dispcorr(ir, fr, box, state->lambda[efptVDW],
                      corr_pres, corr_vir, &prescorr, &enercorr, &dvdlcorr);
    }

    if (bEner)
    {
        enerd->term[F_DISPCORR]  = enercorr;
        enerd->term[F_EPOT]     += enercorr;
        enerd->term[F_DVDL_VDW] += dvdlcorr;
    }

    /* ########## Now pressure ############## */
    if (bPres || bConstrain)
    {

        m_add(force_vir, shake_vir, total_vir);

        /* Calculate pressure and apply LR correction if PPPM is used.
         * Use the box from last timestep since we already called update().
         */

        enerd->term[F_PRES] = calc_pres(fr->ePBC, ir->nwall, box, ekind->ekin, total_vir, pres);

        /* Calculate long range corrections to pressure and energy */
        /* this adds to enerd->term[F_PRES] and enerd->term[F_ETOT],
           and computes enerd->term[F_DISPCORR].  Also modifies the
           total_vir and pres tesors */

        m_add(total_vir, corr_vir, total_vir);
        m_add(pres, corr_pres, pres);
        enerd->term[F_PDISPCORR] = prescorr;
        enerd->term[F_PRES]     += prescorr;
    }
}
Example #23
0
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);
            }
Example #24
0
File: force.c Project: nrego/indus
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);

}
Example #25
0
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);

}
Example #26
0
static bool constrain_lincs(FILE *log,t_topology *top,t_inputrec *ir,
			    int step,t_mdatoms *md,int start,int homenr,
			    int *nbl,int **sbl,
			    rvec *x,rvec *xprime,rvec *min_proj,matrix box,
			    real lambda,real *dvdlambda,bool bCoordinates,
			    bool bInit,t_nrnb *nrnb,bool bDumpOnError)
{
  static int       *bla1,*bla2,*blnr,*blbnb,nrtot=0;
  static rvec      *r;
  static real      *bllen,*blc,*blcc,*blm,*tmp1,*tmp2,*tmp3,*lincslam,
                   *bllen0,*ddist;
  static int       nc;
  static bool      bItEqOrder;

  char             buf[STRLEN];
  int              b,i,j,nit,warn,p_imax,error;
  real             wang,p_max,p_rms;
  real             dt,dt_2;
  bool             bOK;
  
  bOK = TRUE;
  if (bInit) {
    nc = top->idef.il[F_SHAKE].nr/3;
    init_lincs(stdlog,top,ir,md,start,homenr,
               &nrtot,
               &r,&bla1,&bla2,&blnr,&blbnb,
               &bllen,&blc,&blcc,&blm,&tmp1,&tmp2,&tmp3,&lincslam,
               &bllen0,&ddist);
#ifdef SPEC_CPU
    bItEqOrder = FALSE;
#else
    bItEqOrder = (getenv("GMX_ACCURATE_LINCS") != NULL);
#endif
  } 
  else if (nc != 0) {
      /* If there are any constraints */
      if (bCoordinates) {
          dt   = ir->delta_t;
          dt_2 = 1.0/(dt*dt);
          
          if (ir->efep != efepNO)
              for(i=0;i<nc;i++)
                  bllen[i]=bllen0[i]+lambda*ddist[i];
          
          /* Set the zero lengths to the old lengths */
          for(b=0; b<nc; b++)
              if (bllen0[b]<GMX_REAL_MIN) {
                  i = bla1[b];
                  j = bla2[b];
                  bllen[b] = sqrt(sqr(x[i][XX]-x[j][XX])+
                                  sqr(x[i][YY]-x[j][YY])+
                                  sqr(x[i][ZZ]-x[j][ZZ]));
              }
                  
                  wang=ir->LincsWarnAngle;
          
          if (do_per_step(step,ir->nstlog) || step<0)
              cconerr(&p_max,&p_rms,&p_imax,xprime,nc,bla1,bla2,bllen);
          
          if ((ir->eI == eiSteep) || (ir->eI == eiCG) || bItEqOrder)
              /* Use more iterations when doing energy minimization, *
              * because we need very accurate positions and forces. */
              nit = ir->nProjOrder;
          else
              nit = 1;
          
#ifdef USE_FORTRAN
#ifdef DOUBLE
          F77_FUNC(flincsd,FLINCSD)(x[0],xprime[0],&nc,bla1,bla2,blnr,blbnb,
                                    bllen,blc,blcc,blm,&nit,&ir->nProjOrder,
                                    md->invmass,r[0],tmp1,tmp2,tmp3,&wang,&warn,
                                    lincslam);
#else
          F77_FUNC(flincs,FLINCS)(x[0],xprime[0],&nc,bla1,bla2,blnr,blbnb,
                                  bllen,blc,blcc,blm,&nit,&ir->nProjOrder,
                                  md->invmass,r[0],tmp1,tmp2,tmp3,&wang,&warn,
                                  lincslam);
#endif
#else
          clincs(x,xprime,nc,bla1,bla2,blnr,blbnb,
                 bllen,blc,blcc,blm,nit,ir->nProjOrder,
                 md->invmass,r,tmp1,tmp2,tmp3,wang,&warn,lincslam);
#endif
          if (ir->efep != efepNO) {
              real dvdl=0;
              
              for(i=0; (i<nc); i++)
                  dvdl+=lincslam[i]*dt_2*ddist[i];
              *dvdlambda+=dvdl;
          }
          
          if(stdlog)
          {
              if (do_per_step(step,ir->nstlog) || (step<0)) 
              {
                  fprintf(stdlog,"   Rel. Constraint Deviation:  Max    between atoms     RMS\n");
                  fprintf(stdlog,"       Before LINCS         %.6f %6d %6d   %.6f\n",
                          p_max,bla1[p_imax]+1,bla2[p_imax]+1,p_rms);
                  cconerr(&p_max,&p_rms,&p_imax,xprime,nc,bla1,bla2,bllen);
                  fprintf(stdlog,"        After LINCS         %.6f %6d %6d   %.6f\n\n",
                          p_max,bla1[p_imax]+1,bla2[p_imax]+1,p_rms);
              }
          }
                  
          if (warn > 0) 
          {
              if (bDumpOnError && stdlog) 
              {
                  cconerr(&p_max,&p_rms,&p_imax,xprime,nc,bla1,bla2,bllen);
                  sprintf(buf,"\nStep %d, time %g (ps)  LINCS WARNING\n"
                          "relative constraint deviation after LINCS:\n"
                          "max %.6f (between atoms %d and %d) rms %.6f\n",
                          step,ir->init_t+step*ir->delta_t,
                          p_max,bla1[p_imax]+1,bla2[p_imax]+1,p_rms);
                  fprintf(stdlog,"%s",buf);
                  fprintf(stderr,"%s",buf);
                  lincs_warning(x,xprime,nc,bla1,bla2,bllen,wang);
              }
              bOK = (p_max < 0.5);
          }
          for(b=0; (b<nc); b++)
              if (bllen0[b] < GMX_REAL_MIN)
                  bllen[b] = 0;
      } 
      else
      {
#ifdef USE_FORTRAN
#ifdef DOUBLE
          F77_FUNC(flincspd,FLINCSPD)(x[0],xprime[0],min_proj[0],&nc,bla1,bla2,blnr,blbnb,
                                      blc,blcc,blm,&ir->nProjOrder,
                                      md->invmass,r[0],tmp1,tmp2,tmp3);
#else
          F77_FUNC(flincsp,FLINCSP)(x[0],xprime[0],min_proj[0],&nc,bla1,bla2,blnr,blbnb,
                                    blc,blcc,blm,&ir->nProjOrder,
                                    md->invmass,r[0],tmp1,tmp2,tmp3);
#endif
#else
          clincsp(x,xprime,min_proj,nc,bla1,bla2,blnr,blbnb,
                  blc,blcc,blm,ir->nProjOrder,
                  md->invmass,r,tmp1,tmp2,tmp3);
#endif
      }
      
      /* count assuming nit=1 */
      inc_nrnb(nrnb,eNR_LINCS,nc);
      inc_nrnb(nrnb,eNR_LINCSMAT,(2+ir->nProjOrder)*nrtot);
  }
  return bOK;
}
Example #27
0
gmx_bool constrain(FILE *fplog, gmx_bool bLog, gmx_bool bEner,
                   struct gmx_constr *constr,
                   t_idef *idef, t_inputrec *ir, gmx_ekindata_t *ekind,
                   t_commrec *cr,
                   gmx_int64_t step, int delta_step,
                   t_mdatoms *md,
                   rvec *x, rvec *xprime, rvec *min_proj,
                   gmx_bool bMolPBC, matrix box,
                   real lambda, real *dvdlambda,
                   rvec *v, tensor *vir,
                   t_nrnb *nrnb, int econq, gmx_bool bPscal,
                   real veta, real vetanew)
{
    gmx_bool    bOK, bDump;
    int         start, homenr, nrend;
    int         i, j, d;
    int         ncons, settle_error;
    tensor      vir_r_m_dr;
    rvec       *vstor;
    real        invdt, vir_fac, t;
    t_ilist    *settle;
    int         nsettle;
    t_pbc       pbc, *pbc_null;
    char        buf[22];
    t_vetavars  vetavar;
    int         nth, th;

    if (econq == econqForceDispl && !EI_ENERGY_MINIMIZATION(ir->eI))
    {
        gmx_incons("constrain called for forces displacements while not doing energy minimization, can not do this while the LINCS and SETTLE constraint connection matrices are mass weighted");
    }

    bOK   = TRUE;
    bDump = FALSE;

    start  = 0;
    homenr = md->homenr;
    nrend  = start+homenr;

    /* set constants for pressure control integration */
    init_vetavars(&vetavar, econq != econqCoord,
                  veta, vetanew, ir, ekind, bPscal);

    if (ir->delta_t == 0)
    {
        invdt = 0;
    }
    else
    {
        invdt  = 1/ir->delta_t;
    }

    if (ir->efep != efepNO && EI_DYNAMICS(ir->eI))
    {
        /* Set the constraint lengths for the step at which this configuration
         * is meant to be. The invmasses should not be changed.
         */
        lambda += delta_step*ir->fepvals->delta_lambda;
    }

    if (vir != NULL)
    {
        clear_mat(vir_r_m_dr);
    }

    where();

    settle  = &idef->il[F_SETTLE];
    nsettle = settle->nr/(1+NRAL(F_SETTLE));

    if (nsettle > 0)
    {
        nth = gmx_omp_nthreads_get(emntSETTLE);
    }
    else
    {
        nth = 1;
    }

    if (nth > 1 && constr->vir_r_m_dr_th == NULL)
    {
        snew(constr->vir_r_m_dr_th, nth);
        snew(constr->settle_error, nth);
    }

    settle_error = -1;

    /* We do not need full pbc when constraints do not cross charge groups,
     * i.e. when dd->constraint_comm==NULL.
     * Note that PBC for constraints is different from PBC for bondeds.
     * For constraints there is both forward and backward communication.
     */
    if (ir->ePBC != epbcNONE &&
        (cr->dd || bMolPBC) && !(cr->dd && cr->dd->constraint_comm == NULL))
    {
        /* With pbc=screw the screw has been changed to a shift
         * by the constraint coordinate communication routine,
         * so that here we can use normal pbc.
         */
        pbc_null = set_pbc_dd(&pbc, ir->ePBC, cr->dd, FALSE, box);
    }
    else
    {
        pbc_null = NULL;
    }

    /* Communicate the coordinates required for the non-local constraints
     * for LINCS and/or SETTLE.
     */
    if (cr->dd)
    {
        dd_move_x_constraints(cr->dd, box, x, xprime, econq == econqCoord);
    }

    if (constr->lincsd != NULL)
    {
        bOK = constrain_lincs(fplog, bLog, bEner, ir, step, constr->lincsd, md, cr,
                              x, xprime, min_proj,
                              box, pbc_null, lambda, dvdlambda,
                              invdt, v, vir != NULL, vir_r_m_dr,
                              econq, nrnb,
                              constr->maxwarn, &constr->warncount_lincs);
        if (!bOK && constr->maxwarn >= 0)
        {
            if (fplog != NULL)
            {
                fprintf(fplog, "Constraint error in algorithm %s at step %s\n",
                        econstr_names[econtLINCS], gmx_step_str(step, buf));
            }
            bDump = TRUE;
        }
    }

    if (constr->nblocks > 0)
    {
        switch (econq)
        {
            case (econqCoord):
                bOK = bshakef(fplog, constr->shaked,
                              md->invmass, constr->nblocks, constr->sblock,
                              idef, ir, x, xprime, nrnb,
                              constr->lagr, lambda, dvdlambda,
                              invdt, v, vir != NULL, vir_r_m_dr,
                              constr->maxwarn >= 0, econq, &vetavar);
                break;
            case (econqVeloc):
                bOK = bshakef(fplog, constr->shaked,
                              md->invmass, constr->nblocks, constr->sblock,
                              idef, ir, x, min_proj, nrnb,
                              constr->lagr, lambda, dvdlambda,
                              invdt, NULL, vir != NULL, vir_r_m_dr,
                              constr->maxwarn >= 0, econq, &vetavar);
                break;
            default:
                gmx_fatal(FARGS, "Internal error, SHAKE called for constraining something else than coordinates");
                break;
        }

        if (!bOK && constr->maxwarn >= 0)
        {
            if (fplog != NULL)
            {
                fprintf(fplog, "Constraint error in algorithm %s at step %s\n",
                        econstr_names[econtSHAKE], gmx_step_str(step, buf));
            }
            bDump = TRUE;
        }
    }

    if (nsettle > 0)
    {
        int calcvir_atom_end;

        if (vir == NULL)
        {
            calcvir_atom_end = 0;
        }
        else
        {
            calcvir_atom_end = md->homenr;
        }

        switch (econq)
        {
            case econqCoord:
#pragma omp parallel for num_threads(nth) schedule(static)
                for (th = 0; th < nth; th++)
                {
                    int start_th, end_th;

                    if (th > 0)
                    {
                        clear_mat(constr->vir_r_m_dr_th[th]);
                    }

                    start_th = (nsettle* th   )/nth;
                    end_th   = (nsettle*(th+1))/nth;
                    if (start_th >= 0 && end_th - start_th > 0)
                    {
                        csettle(constr->settled,
                                end_th-start_th,
                                settle->iatoms+start_th*(1+NRAL(F_SETTLE)),
                                pbc_null,
                                x[0], xprime[0],
                                invdt, v ? v[0] : NULL, calcvir_atom_end,
                                th == 0 ? vir_r_m_dr : constr->vir_r_m_dr_th[th],
                                th == 0 ? &settle_error : &constr->settle_error[th],
                                &vetavar);
                    }
                }
                inc_nrnb(nrnb, eNR_SETTLE, nsettle);
                if (v != NULL)
                {
                    inc_nrnb(nrnb, eNR_CONSTR_V, nsettle*3);
                }
                if (vir != NULL)
                {
                    inc_nrnb(nrnb, eNR_CONSTR_VIR, nsettle*3);
                }
                break;
            case econqVeloc:
            case econqDeriv:
            case econqForce:
            case econqForceDispl:
#pragma omp parallel for num_threads(nth) schedule(static)
                for (th = 0; th < nth; th++)
                {
                    int start_th, end_th;

                    if (th > 0)
                    {
                        clear_mat(constr->vir_r_m_dr_th[th]);
                    }

                    start_th = (nsettle* th   )/nth;
                    end_th   = (nsettle*(th+1))/nth;

                    if (start_th >= 0 && end_th - start_th > 0)
                    {
                        settle_proj(constr->settled, econq,
                                    end_th-start_th,
                                    settle->iatoms+start_th*(1+NRAL(F_SETTLE)),
                                    pbc_null,
                                    x,
                                    xprime, min_proj, calcvir_atom_end,
                                    th == 0 ? vir_r_m_dr : constr->vir_r_m_dr_th[th],
                                    &vetavar);
                    }
                }
                /* This is an overestimate */
                inc_nrnb(nrnb, eNR_SETTLE, nsettle);
                break;
            case econqDeriv_FlexCon:
                /* Nothing to do, since the are no flexible constraints in settles */
                break;
            default:
                gmx_incons("Unknown constraint quantity for settle");
        }
    }

    if (settle->nr > 0)
    {
        /* Combine virial and error info of the other threads */
        for (i = 1; i < nth; i++)
        {
            m_add(vir_r_m_dr, constr->vir_r_m_dr_th[i], vir_r_m_dr);
            settle_error = constr->settle_error[i];
        }

        if (econq == econqCoord && settle_error >= 0)
        {
            bOK = FALSE;
            if (constr->maxwarn >= 0)
            {
                char buf[256];
                sprintf(buf,
                        "\nstep " "%"GMX_PRId64 ": Water molecule starting at atom %d can not be "
                        "settled.\nCheck for bad contacts and/or reduce the timestep if appropriate.\n",
                        step, ddglatnr(cr->dd, settle->iatoms[settle_error*(1+NRAL(F_SETTLE))+1]));
                if (fplog)
                {
                    fprintf(fplog, "%s", buf);
                }
                fprintf(stderr, "%s", buf);
                constr->warncount_settle++;
                if (constr->warncount_settle > constr->maxwarn)
                {
                    too_many_constraint_warnings(-1, constr->warncount_settle);
                }
                bDump = TRUE;
            }
        }
    }

    free_vetavars(&vetavar);

    if (vir != NULL)
    {
        switch (econq)
        {
            case econqCoord:
                vir_fac = 0.5/(ir->delta_t*ir->delta_t);
                break;
            case econqVeloc:
                vir_fac = 0.5/ir->delta_t;
                break;
            case econqForce:
            case econqForceDispl:
                vir_fac = 0.5;
                break;
            default:
                vir_fac = 0;
                gmx_incons("Unsupported constraint quantity for virial");
        }

        if (EI_VV(ir->eI))
        {
            vir_fac *= 2;  /* only constraining over half the distance here */
        }
        for (i = 0; i < DIM; i++)
        {
            for (j = 0; j < DIM; j++)
            {
                (*vir)[i][j] = vir_fac*vir_r_m_dr[i][j];
            }
        }
    }

    if (bDump)
    {
        dump_confs(fplog, step, constr->warn_mtop, start, homenr, cr, x, xprime, box);
    }

    if (econq == econqCoord)
    {
        if (ir->ePull == epullCONSTRAINT)
        {
            if (EI_DYNAMICS(ir->eI))
            {
                t = ir->init_t + (step + delta_step)*ir->delta_t;
            }
            else
            {
                t = ir->init_t;
            }
            set_pbc(&pbc, ir->ePBC, box);
            pull_constraint(ir->pull, md, &pbc, cr, ir->delta_t, t, x, xprime, v, *vir);
        }
        if (constr->ed && delta_step > 0)
        {
            /* apply the essential dynamcs constraints here */
            do_edsam(ir, step, cr, xprime, v, box, constr->ed);
        }
    }

    return bOK;
}
Example #28
0
static bool low_constrain(FILE *log,t_topology *top,t_inputrec *ir,
			  int step,t_mdatoms *md,int start,int homenr,
			  rvec *x,rvec *xprime,rvec *min_proj,matrix box,
			  real lambda,real *dvdlambda,t_nrnb *nrnb,
			  bool bCoordinates,bool bInit)
{
  static int       nblocks=0;
  static int       *sblock=NULL;
  static int       nsettle,settle_type;
  static int       *owptr;
  static bool      bDumpOnError = TRUE;
  
  char        buf[STRLEN];
  bool        bOK;
  t_sortblock *sb;
  t_block     *blocks=&(top->blocks[ebSBLOCKS]);
  t_idef      *idef=&(top->idef);
  t_iatom     *iatom;
  atom_id     *inv_sblock;
  int         i,j,m,bnr;
  int         ncons,bstart,error;
  
  bOK = TRUE;
  if (bInit) {
    /* Output variables, initiate them right away */
    
    if ((ir->etc==etcBERENDSEN) || (ir->epc==epcBERENDSEN))
      please_cite(log,"Berendsen84a");

#ifdef SPEC_CPU
    bDumpOnError = TRUE;
#else    
    bDumpOnError = (getenv("NO_SHAKE_ERROR") == NULL);
#endif
    /* Put the oxygen atoms in the owptr array */
    nsettle=idef->il[F_SETTLE].nr/2;
    if (nsettle > 0) {
      snew(owptr,nsettle);
      settle_type=idef->il[F_SETTLE].iatoms[0];
      for (j=0; (j<idef->il[F_SETTLE].nr); j+=2) {
	if (idef->il[F_SETTLE].iatoms[j] != settle_type)
	  fatal_error(0,"More than one settle type (%d and %d)",
		      settle_type,idef->il[F_SETTLE].iatoms[j]);
	owptr[j/2]=idef->il[F_SETTLE].iatoms[j+1];
#ifdef DEBUG
	fprintf(log,"owptr[%d]=%d\n",j/2,owptr[j/2]);
#endif
      }
      /* We used to free this memory, but ED sampling needs it later on 
       *  sfree(idef->il[F_SETTLE].iatoms);
       */
      
      please_cite(log,"Miyamoto92a");
    }
    
    ncons=idef->il[F_SHAKE].nr/3;
    if (ncons > 0) 
    {
        bstart=(idef->nodeid > 0) ? blocks->multinr[idef->nodeid-1] : 0;
        nblocks=blocks->multinr[idef->nodeid] - bstart;
        if (debug) 
            fprintf(debug,"ncons: %d, bstart: %d, nblocks: %d\n",
                    ncons,bstart,nblocks);
        
        /* Calculate block number for each atom */
        inv_sblock=make_invblock(blocks,md->nr);
        
        /* Store the block number in temp array and
         * sort the constraints in order of the sblock number 
         * and the atom numbers, really sorting a segment of the array!
         */
#ifdef DEBUGIDEF 
        pr_idef(stdlog,0,"Before Sort",idef);
#endif
        iatom=idef->il[F_SHAKE].iatoms;
        snew(sb,ncons);
        for(i=0; (i<ncons); i++,iatom+=3) {
            for(m=0; (m<3); m++)
                sb[i].iatom[m]=iatom[m];
            sb[i].blocknr=inv_sblock[iatom[1]];
        }
        
        /* Now sort the blocks */
        if (debug) {
            pr_sortblock(debug,"Before sorting",ncons,sb);
            fprintf(debug,"Going to sort constraints\n");
        }
      
        qsort(sb,ncons,(size_t)sizeof(*sb),pcomp);
        
        if (debug) {
            fprintf(debug,"I used %d calls to pcomp\n",pcount);
            pr_sortblock(debug,"After sorting",ncons,sb);
        }
        
        iatom=idef->il[F_SHAKE].iatoms;
        for(i=0; (i<ncons); i++,iatom+=3) 
            for(m=0; (m<DIM); m++)
                iatom[m]=sb[i].iatom[m];
#ifdef DEBUGIDEF
        pr_idef(stdlog,0,"After Sort",idef);
#endif
        
        j=0;
        snew(sblock,nblocks+1);
        bnr=-2;
        for(i=0; (i<ncons); i++) {
            if (sb[i].blocknr != bnr) {
                bnr=sb[i].blocknr;
                sblock[j++]=3*i;
            }
        }
        /* Last block... */
        sblock[j++]=3*ncons;
        
        if (j != (nblocks+1) && log) {
            fprintf(log,"bstart: %d\n",bstart);
            fprintf(log,"j: %d, nblocks: %d, ncons: %d\n",
                    j,nblocks,ncons);
            for(i=0; (i<ncons); i++)
                fprintf(log,"i: %5d  sb[i].blocknr: %5u\n",i,sb[i].blocknr);
            for(j=0; (j<=nblocks); j++)
                fprintf(log,"sblock[%3d]=%5d\n",j,(int) sblock[j]);
            fatal_error(0,"DEATH HORROR: "
                        "top->blocks[ebSBLOCKS] does not match idef->il[F_SHAKE]");
        }
        sfree(sb);
        sfree(inv_sblock);
    }
    
    if (idef->il[F_SHAKE].nr) {
        if (ir->eConstrAlg == estLINCS || !bCoordinates) {
            please_cite(stdlog,"Hess97a");
            bOK = constrain_lincs(stdlog,top,ir,0,md,start,homenr,&nblocks,&sblock,
                                  NULL,NULL,NULL,NULL,0,NULL,bCoordinates,TRUE,nrnb,
                                  bDumpOnError);
        } 
        else
            please_cite(stdlog,"Ryckaert77a");
    }
  } 
  else {
      /* !bInit */
      if (nblocks > 0) {
          where();
          
          if (ir->eConstrAlg == estSHAKE)
              bOK = bshakef(stdlog,homenr,md->invmass,nblocks,sblock,idef,
                            ir,box,x,xprime,nrnb,lambda,dvdlambda,bDumpOnError);
          else if (ir->eConstrAlg == estLINCS)
              bOK = constrain_lincs(stdlog,top,ir,step,md,
                                    start,homenr,&nblocks,&sblock,
                                    x,xprime,min_proj,box,lambda,dvdlambda,
                                    bCoordinates,FALSE,nrnb,bDumpOnError);
          if (!bOK && bDumpOnError && stdlog)
              fprintf(stdlog,"Constraint error in algorithm %s at step %d\n",
                      eshake_names[ir->eConstrAlg],step);
      }
      if (nsettle > 0) {
          int  ow1;
          real mO,mH,dOH,dHH;
          
          ow1  = owptr[0];
          mO   = md->massA[ow1];
          mH   = md->massA[ow1+1];
          dOH  = top->idef.iparams[settle_type].settle.doh;
          dHH  = top->idef.iparams[settle_type].settle.dhh;
#ifdef USE_FORTRAN
#ifdef DOUBLE
          F77_FUNC(fsettled,FSETTLED)(&nsettle,owptr,x[0],xprime[0],
                                      &dOH,&dHH,&mO,&mH,&error);
#else
          F77_FUNC(fsettle,FSETTLE)(&nsettle,owptr,x[0],xprime[0],
                                    &dOH,&dHH,&mO,&mH,&error);
#endif
#else
          csettle(stdlog,nsettle,owptr,x[0],xprime[0],dOH,dHH,mO,mH,&error);
#endif
          inc_nrnb(nrnb,eNR_SETTLE,nsettle);
          bOK = (error < 0);
          if (!bOK && bDumpOnError && stdlog)
              fprintf(stdlog,"\nt = %.3f ps: Water molecule starting at atom %d can not be "
                      "settled.\nCheck for bad contacts and/or reduce the timestep.",
                      ir->init_t+step*ir->delta_t,owptr[error]+1);
      }
      if (!bOK && bDumpOnError) 
          dump_confs(step,&(top->atoms),x,xprime,box);
  }
  return bOK;
}
Example #29
0
void
gmx_nb_generic_adress_kernel(t_nblist *                nlist,
                             rvec *                    xx,
                             rvec *                    ff,
                             t_forcerec *              fr,
                             t_mdatoms *               mdatoms,
                             nb_kernel_data_t *        kernel_data,
                             t_nrnb *                  nrnb)
{
    int           nri, ntype, table_nelements, ielec, ivdw;
    real          facel, gbtabscale;
    int           n, ii, is3, ii3, k, nj0, nj1, jnr, j3, ggid, nnn, n0;
    real          shX, shY, shZ;
    real          fscal, felec, fvdw, velec, vvdw, tx, ty, tz;
    real          rinvsq;
    real          iq;
    real          qq, vctot;
    int           nti, nvdwparam;
    int           tj;
    real          rt, r, eps, eps2, Y, F, Geps, Heps2, VV, FF, Fp, fijD, fijR;
    real          rinvsix;
    real          vvdwtot;
    real          vvdw_rep, vvdw_disp;
    real          ix, iy, iz, fix, fiy, fiz;
    real          jx, jy, jz;
    real          dx, dy, dz, rsq, rinv;
    real          c6, c12, cexp1, cexp2, br;
    real *        charge;
    real *        shiftvec;
    real *        vdwparam;
    int *         shift;
    int *         type;
    real *        fshift;
    real *        velecgrp;
    real *        vvdwgrp;
    real          tabscale;
    real *        VFtab;
    real *        x;
    real *        f;
    int           ewitab;
    real          ewtabscale, eweps, sh_ewald, ewrt, ewtabhalfspace;
    real *        ewtab;
    real          rcoulomb2, rvdw, rvdw2, sh_dispersion, sh_repulsion;
    real          rcutoff, rcutoff2;
    real          rswitch_elec, rswitch_vdw, d, d2, sw, dsw, rinvcorr;
    real          elec_swV3, elec_swV4, elec_swV5, elec_swF2, elec_swF3, elec_swF4;
    real          vdw_swV3, vdw_swV4, vdw_swV5, vdw_swF2, vdw_swF3, vdw_swF4;
    gmx_bool      bExactElecCutoff, bExactVdwCutoff, bExactCutoff;

    real    *     wf;
    real          weight_cg1;
    real          weight_cg2;
    real          weight_product;
    real          hybscal; /* the multiplicator to the force for hybrid interactions*/
    real          force_cap;
    gmx_bool      bCG;
    int           egp_nr;

    wf                  = mdatoms->wf;

    force_cap           = fr->adress_ex_forcecap;

    x                   = xx[0];
    f                   = ff[0];
    ielec               = nlist->ielec;
    ivdw                = nlist->ivdw;

    fshift              = fr->fshift[0];
    velecgrp            = kernel_data->energygrp_elec;
    vvdwgrp             = kernel_data->energygrp_vdw;
    tabscale            = kernel_data->table_elec_vdw->scale;
    VFtab               = kernel_data->table_elec_vdw->data;

    sh_ewald            = fr->ic->sh_ewald;
    ewtab               = fr->ic->tabq_coul_FDV0;
    ewtabscale          = fr->ic->tabq_scale;
    ewtabhalfspace      = 0.5/ewtabscale;

    rcoulomb2           = fr->rcoulomb*fr->rcoulomb;
    rvdw                = fr->rvdw;
    rvdw2               = rvdw*rvdw;
    sh_dispersion       = fr->ic->dispersion_shift.cpot;
    sh_repulsion        = fr->ic->repulsion_shift.cpot;

    if (fr->coulomb_modifier == eintmodPOTSWITCH)
    {
        d               = fr->rcoulomb-fr->rcoulomb_switch;
        elec_swV3       = -10.0/(d*d*d);
        elec_swV4       =  15.0/(d*d*d*d);
        elec_swV5       =  -6.0/(d*d*d*d*d);
        elec_swF2       = -30.0/(d*d*d);
        elec_swF3       =  60.0/(d*d*d*d);
        elec_swF4       = -30.0/(d*d*d*d*d);
    }
    else
    {
        /* Avoid warnings from stupid compilers (looking at you, Clang!) */
        elec_swV3 = elec_swV4 = elec_swV5 = elec_swF2 = elec_swF3 = elec_swF4 = 0.0;
    }
    if (fr->vdw_modifier == eintmodPOTSWITCH)
    {
        d               = fr->rvdw-fr->rvdw_switch;
        vdw_swV3        = -10.0/(d*d*d);
        vdw_swV4        =  15.0/(d*d*d*d);
        vdw_swV5        =  -6.0/(d*d*d*d*d);
        vdw_swF2        = -30.0/(d*d*d);
        vdw_swF3        =  60.0/(d*d*d*d);
        vdw_swF4        = -30.0/(d*d*d*d*d);
    }
    else
    {
        /* Avoid warnings from stupid compilers (looking at you, Clang!) */
        vdw_swV3 = vdw_swV4 = vdw_swV5 = vdw_swF2 = vdw_swF3 = vdw_swF4 = 0.0;
    }

    bExactElecCutoff    = (fr->coulomb_modifier != eintmodNONE) || fr->eeltype == eelRF_ZERO;
    bExactVdwCutoff     = (fr->vdw_modifier != eintmodNONE);
    bExactCutoff        = bExactElecCutoff || bExactVdwCutoff;

    if (bExactCutoff)
    {
        rcutoff  = ( fr->rcoulomb > fr->rvdw ) ? fr->rcoulomb : fr->rvdw;
        rcutoff2 = rcutoff*rcutoff;
    }
    else
    {
        /* Fix warnings for stupid compilers */
        rcutoff = rcutoff2 = 1e30;
    }

    /* avoid compiler warnings for cases that cannot happen */
    nnn                 = 0;
    eps                 = 0.0;
    eps2                = 0.0;

    /* 3 VdW parameters for buckingham, otherwise 2 */
    nvdwparam           = (ivdw == GMX_NBKERNEL_VDW_BUCKINGHAM) ? 3 : 2;
    table_nelements     = 12;

    charge              = mdatoms->chargeA;
    type                = mdatoms->typeA;
    facel               = fr->epsfac;
    shiftvec            = fr->shift_vec[0];
    vdwparam            = fr->nbfp;
    ntype               = fr->ntype;

    for (n = 0; (n < nlist->nri); n++)
    {
        is3              = 3*nlist->shift[n];
        shX              = shiftvec[is3];
        shY              = shiftvec[is3+1];
        shZ              = shiftvec[is3+2];
        nj0              = nlist->jindex[n];
        nj1              = nlist->jindex[n+1];
        ii               = nlist->iinr[n];
        ii3              = 3*ii;
        ix               = shX + x[ii3+0];
        iy               = shY + x[ii3+1];
        iz               = shZ + x[ii3+2];
        iq               = facel*charge[ii];
        nti              = nvdwparam*ntype*type[ii];
        vctot            = 0;
        vvdwtot          = 0;
        fix              = 0;
        fiy              = 0;
        fiz              = 0;

        /* We need to find out if this i atom is part of an
           all-atom or CG energy group  */
        egp_nr = mdatoms->cENER[ii];
        bCG    = !fr->adress_group_explicit[egp_nr];

        weight_cg1       = wf[ii];

        if ((!bCG) && weight_cg1 < ALMOST_ZERO)
        {
            continue;
        }

        for (k = nj0; (k < nj1); k++)
        {
            jnr              = nlist->jjnr[k];
            weight_cg2       = wf[jnr];
            weight_product   = weight_cg1*weight_cg2;

            if (weight_product < ALMOST_ZERO)
            {
                /* if it's a explicit loop, skip this atom */
                if (!bCG)
                {
                    continue;
                }
                else /* if it's a coarse grained loop, include this atom */
                {
                    hybscal = 1.0;
                }
            }
            else if (weight_product >= ALMOST_ONE)
            {

                /* if it's a explicit loop, include this atom */
                if (!bCG)
                {
                    hybscal = 1.0;
                }
                else  /* if it's a coarse grained loop, skip this atom */
                {
                    continue;
                }
            }
            /* both have double identity, get hybrid scaling factor */
            else
            {
                hybscal = weight_product;

                if (bCG)
                {
                    hybscal = 1.0 - hybscal;
                }
            }

            j3               = 3*jnr;
            jx               = x[j3+0];
            jy               = x[j3+1];
            jz               = x[j3+2];
            dx               = ix - jx;
            dy               = iy - jy;
            dz               = iz - jz;
            rsq              = dx*dx+dy*dy+dz*dz;
            rinv             = gmx_invsqrt(rsq);
            rinvsq           = rinv*rinv;
            felec            = 0;
            fvdw             = 0;
            velec            = 0;
            vvdw             = 0;

            if (bExactCutoff && rsq > rcutoff2)
            {
                continue;
            }

            if (ielec == GMX_NBKERNEL_ELEC_CUBICSPLINETABLE || ivdw == GMX_NBKERNEL_VDW_CUBICSPLINETABLE)
            {
                r                = rsq*rinv;
                rt               = r*tabscale;
                n0               = rt;
                eps              = rt-n0;
                eps2             = eps*eps;
                nnn              = table_nelements*n0;
            }

            /* Coulomb interaction. ielec==0 means no interaction */
            if (ielec != GMX_NBKERNEL_ELEC_NONE)
            {
                qq               = iq*charge[jnr];

                switch (ielec)
                {
                    case GMX_NBKERNEL_ELEC_NONE:
                        break;

                    case GMX_NBKERNEL_ELEC_COULOMB:
                        /* Vanilla cutoff coulomb */
                        velec            = qq*rinv;
                        felec            = velec*rinvsq;
                        break;

                    case GMX_NBKERNEL_ELEC_REACTIONFIELD:
                        /* Reaction-field */
                        velec            = qq*(rinv+fr->k_rf*rsq-fr->c_rf);
                        felec            = qq*(rinv*rinvsq-2.0*fr->k_rf);
                        break;

                    case GMX_NBKERNEL_ELEC_CUBICSPLINETABLE:
                        /* Tabulated coulomb */
                        Y                = VFtab[nnn];
                        F                = VFtab[nnn+1];
                        Geps             = eps*VFtab[nnn+2];
                        Heps2            = eps2*VFtab[nnn+3];
                        Fp               = F+Geps+Heps2;
                        VV               = Y+eps*Fp;
                        FF               = Fp+Geps+2.0*Heps2;
                        velec            = qq*VV;
                        felec            = -qq*FF*tabscale*rinv;
                        break;

                    case GMX_NBKERNEL_ELEC_GENERALIZEDBORN:
                        /* GB */
                        gmx_fatal(FARGS, "Death & horror! GB generic interaction not implemented.\n");
                        break;

                    case GMX_NBKERNEL_ELEC_EWALD:
                        ewrt             = rsq*rinv*ewtabscale;
                        ewitab           = ewrt;
                        eweps            = ewrt-ewitab;
                        ewitab           = 4*ewitab;
                        felec            = ewtab[ewitab]+eweps*ewtab[ewitab+1];
                        rinvcorr         = (fr->coulomb_modifier == eintmodPOTSHIFT) ? rinv-fr->ic->sh_ewald : rinv;
                        velec            = qq*(rinvcorr-(ewtab[ewitab+2]-ewtabhalfspace*eweps*(ewtab[ewitab]+felec)));
                        felec            = qq*rinv*(rinvsq-felec);
                        break;

                    default:
                        gmx_fatal(FARGS, "Death & horror! No generic coulomb interaction for ielec=%d.\n", ielec);
                        break;
                }
                if (fr->coulomb_modifier == eintmodPOTSWITCH)
                {
                    d                = rsq*rinv-fr->rcoulomb_switch;
                    d                = (d > 0.0) ? d : 0.0;
                    d2               = d*d;
                    sw               = 1.0+d2*d*(elec_swV3+d*(elec_swV4+d*elec_swV5));
                    dsw              = d2*(elec_swF2+d*(elec_swF3+d*elec_swF4));
                    /* Apply switch function. Note that felec=f/r since it will be multiplied
                     * by the i-j displacement vector. This means felec'=f'/r=-(v*sw)'/r=
                     * -(v'*sw+v*dsw)/r=-v'*sw/r-v*dsw/r=felec*sw-v*dsw/r
                     */
                    felec            = felec*sw - rinv*velec*dsw;
                    /* Once we have used velec to update felec we can modify velec too */
                    velec           *= sw;
                }
                if (bExactElecCutoff)
                {
                    felec            = (rsq <= rcoulomb2) ? felec : 0.0;
                    velec            = (rsq <= rcoulomb2) ? velec : 0.0;
                }
                vctot           += velec;
            } /* End of coulomb interactions */


            /* VdW interaction. ivdw==0 means no interaction */
            if (ivdw != GMX_NBKERNEL_VDW_NONE)
            {
                tj               = nti+nvdwparam*type[jnr];

                switch (ivdw)
                {
                    case GMX_NBKERNEL_VDW_NONE:
                        break;

                    case GMX_NBKERNEL_VDW_LENNARDJONES:
                        /* Vanilla Lennard-Jones cutoff */
                        c6               = vdwparam[tj];
                        c12              = vdwparam[tj+1];
                        rinvsix          = rinvsq*rinvsq*rinvsq;
                        vvdw_disp        = c6*rinvsix;
                        vvdw_rep         = c12*rinvsix*rinvsix;
                        fvdw             = (vvdw_rep-vvdw_disp)*rinvsq;
                        if (fr->vdw_modifier == eintmodPOTSHIFT)
                        {
                            vvdw             = (vvdw_rep + c12*sh_repulsion)/12.0 - (vvdw_disp + c6*sh_dispersion)/6.0;
                        }
                        else
                        {
                            vvdw             = vvdw_rep/12.0-vvdw_disp/6.0;
                        }
                        break;

                    case GMX_NBKERNEL_VDW_BUCKINGHAM:
                        /* Buckingham */
                        c6               = vdwparam[tj];
                        cexp1            = vdwparam[tj+1];
                        cexp2            = vdwparam[tj+2];

                        rinvsix          = rinvsq*rinvsq*rinvsq;
                        vvdw_disp        = c6*rinvsix;
                        br               = cexp2*rsq*rinv;
                        vvdw_rep         = cexp1*exp(-br);
                        fvdw             = (br*vvdw_rep-vvdw_disp)*rinvsq;
                        if (fr->vdw_modifier == eintmodPOTSHIFT)
                        {
                            vvdw             = (vvdw_rep-cexp1*exp(-cexp2*rvdw)) - (vvdw_disp + c6*sh_dispersion)/6.0;
                        }
                        else
                        {
                            vvdw             = vvdw_rep-vvdw_disp/6.0;
                        }
                        break;

                    case GMX_NBKERNEL_VDW_CUBICSPLINETABLE:
                        /* Tabulated VdW */
                        c6               = vdwparam[tj];
                        c12              = vdwparam[tj+1];
                        Y                = VFtab[nnn+4];
                        F                = VFtab[nnn+5];
                        Geps             = eps*VFtab[nnn+6];
                        Heps2            = eps2*VFtab[nnn+7];
                        Fp               = F+Geps+Heps2;
                        VV               = Y+eps*Fp;
                        FF               = Fp+Geps+2.0*Heps2;
                        vvdw_disp        = c6*VV;
                        fijD             = c6*FF;
                        Y                = VFtab[nnn+8];
                        F                = VFtab[nnn+9];
                        Geps             = eps*VFtab[nnn+10];
                        Heps2            = eps2*VFtab[nnn+11];
                        Fp               = F+Geps+Heps2;
                        VV               = Y+eps*Fp;
                        FF               = Fp+Geps+2.0*Heps2;
                        vvdw_rep         = c12*VV;
                        fijR             = c12*FF;
                        fvdw             = -(fijD+fijR)*tabscale*rinv;
                        vvdw             = vvdw_disp + vvdw_rep;
                        break;

                    default:
                        gmx_fatal(FARGS, "Death & horror! No generic VdW interaction for ivdw=%d.\n", ivdw);
                        break;
                }
                if (fr->vdw_modifier == eintmodPOTSWITCH)
                {
                    d                = rsq*rinv-fr->rvdw_switch;
                    d                = (d > 0.0) ? d : 0.0;
                    d2               = d*d;
                    sw               = 1.0+d2*d*(vdw_swV3+d*(vdw_swV4+d*vdw_swV5));
                    dsw              = d2*(vdw_swF2+d*(vdw_swF3+d*vdw_swF4));
                    /* See coulomb interaction for the force-switch formula */
                    fvdw             = fvdw*sw - rinv*vvdw*dsw;
                    vvdw            *= sw;
                }
                if (bExactVdwCutoff)
                {
                    fvdw             = (rsq <= rvdw2) ? fvdw : 0.0;
                    vvdw             = (rsq <= rvdw2) ? vvdw : 0.0;
                }
                vvdwtot         += vvdw;
            } /* end VdW interactions */

            fscal            = felec+fvdw;

            if (!bCG && force_cap > 0 && (fabs(fscal) > force_cap))
            {
                fscal = force_cap*fscal/fabs(fscal);
            }

            fscal           *= hybscal;

            tx               = fscal*dx;
            ty               = fscal*dy;
            tz               = fscal*dz;
            fix              = fix + tx;
            fiy              = fiy + ty;
            fiz              = fiz + tz;
            f[j3+0]          = f[j3+0] - tx;
            f[j3+1]          = f[j3+1] - ty;
            f[j3+2]          = f[j3+2] - tz;
        }

        f[ii3+0]         = f[ii3+0] + fix;
        f[ii3+1]         = f[ii3+1] + fiy;
        f[ii3+2]         = f[ii3+2] + fiz;
        fshift[is3]      = fshift[is3]+fix;
        fshift[is3+1]    = fshift[is3+1]+fiy;
        fshift[is3+2]    = fshift[is3+2]+fiz;
        ggid             = nlist->gid[n];
        velecgrp[ggid]  += vctot;
        vvdwgrp[ggid]   += vvdwtot;
    }
    /* Estimate flops, average for generic adress kernel:
     * 14 flops per outer iteration
     * 54 flops per inner iteration
     */
    inc_nrnb(nrnb, eNR_NBKERNEL_GENERIC_ADRESS, nlist->nri*14 + nlist->jindex[n]*54);
}
Example #30
0
void mc_pscale(t_inputrec *ir,matrix mu,
		      matrix box,matrix box_rel,
		      int start,int nr_atoms,
		      rvec x[],unsigned short cFREEZE[],
		      t_nrnb *nrnb,t_block *mols,rvec *xcm,t_graph *graph)
{
  ivec   *nFreeze=ir->opts.nFreeze;
  int    n,m,d,g=0,natoms;
  real  dv; 
  rvec dxcm,dx,*xs;

  snew(xs,nr_atoms);

  for(n=start;n<nr_atoms;n++)
  {
   copy_rvec(x[n],xs[n]);
  }
  shift_self(graph,box,xs);

  for (d=0; d<DIM; d++) {
    box[d][XX] = mu[XX][XX]*box[d][XX]+mu[YY][XX]*box[d][YY]+mu[ZZ][XX]*box[d][ZZ];
    box[d][YY] = mu[YY][YY]*box[d][YY]+mu[ZZ][YY]*box[d][ZZ];
    box[d][ZZ] = mu[ZZ][ZZ]*box[d][ZZ];
  }      
  preserve_box_shape(ir,box_rel,box);

  /* Scale the positions */

  shift_self(graph,box,x);
  for (n=0; n<mols->nr; n++) {
   clear_rvec(dxcm);
   natoms = mols->index[n+1]-mols->index[n];

      dxcm[XX] = mu[XX][XX]*xcm[n][XX]+mu[YY][XX]*xcm[n][YY]+mu[ZZ][XX]*xcm[n][ZZ];
      dxcm[YY] = mu[YY][YY]*xcm[n][YY]+mu[ZZ][YY]*xcm[n][ZZ];
      dxcm[ZZ] = mu[ZZ][ZZ]*xcm[n][ZZ];


   for(m=mols->index[n];m<mols->index[n+1];m++) {
    //rvec_sub(x[m],xcm[n],dx);
    rvec_sub(dxcm,xcm[n],dx);
    rvec_add(xs[m],dx,x[m]);
   }
  }
  unshift_self(graph,box,x);


  /*for (n=start; n<start+nr_atoms; n++) {
    
      x[n][XX] = mu[XX][XX]*x[n][XX]+mu[YY][XX]*x[n][YY]+mu[ZZ][XX]*x[n][ZZ];
      x[n][YY] = mu[YY][YY]*x[n][YY]+mu[ZZ][YY]*x[n][ZZ];
      x[n][ZZ] = mu[ZZ][ZZ]*x[n][ZZ];
  }*/

  /* (un)shifting should NOT be done after this,
   * since the box vectors might have changed
   */
  inc_nrnb(nrnb,eNR_PCOUPL,nr_atoms);

  sfree(xs);
}