Example #1
0
static void cconerr(gmx_domdec_t *dd,
                    int ncons,int *bla,real *bllen,rvec *x,t_pbc *pbc,
                    real *ncons_loc,real *ssd,real *max,int *imax)
{
    real      len,d,ma,ssd2,r2;
    int       *nlocat,count,b,im;
    rvec      dx;
    
    if (dd && dd->constraints)
    {
        nlocat = dd_constraints_nlocalatoms(dd);
    }
    else
    {
        nlocat = 0;
    }
    
    ma = 0;
    ssd2 = 0;
    im = 0;
    count = 0;
    for(b=0;b<ncons;b++)
    {
        if (pbc)
        {
            pbc_dx_aiuc(pbc,x[bla[2*b]],x[bla[2*b+1]],dx);
        }
        else {
            rvec_sub(x[bla[2*b]],x[bla[2*b+1]],dx);
        }
        r2 = norm2(dx);
        len = r2*gmx_invsqrt(r2);
        d = fabs(len/bllen[b]-1);
        if (d > ma && (nlocat==NULL || nlocat[b]))
        {
            ma = d;
            im = b;
        }
        if (nlocat == NULL)
        {
            ssd2 += d*d;
            count++;
        }
        else
        {
            ssd2 += nlocat[b]*d*d;
            count += nlocat[b];
        }
    }
    
    *ncons_loc = (nlocat ? 0.5 : 1)*count;
    *ssd       = (nlocat ? 0.5 : 1)*ssd2;
    *max = ma;
    *imax = im;
}
static bool in_box(t_pbc *pbc,rvec x)
{
  rvec box_center,dx;
  int  shift;
  
  calc_box_center(ecenterTRIC,pbc->box,box_center);
  
  shift = pbc_dx_aiuc(pbc,x,box_center,dx);
  
  return (shift == CENTRAL);
}
Example #3
0
static gmx_bool in_box(t_pbc *pbc, rvec x)
{
    rvec box_center, dx;
    int  shift;

    /* pbc_dx_aiuc only works correctly with the rectangular box center */
    calc_box_center(ecenterRECT, pbc->box, box_center);

    shift = pbc_dx_aiuc(pbc, x, box_center, dx);

    return (shift == CENTRAL);
}
Example #4
0
// The position to look for the closest periodic image
// ref_pos The reference position
void colvarproxy_gromacs::select_closest_image (cvm::atom_pos &pos,
			   cvm::atom_pos const &ref_pos) {
  rvec r1, r2, dr;
  r1[0] = pos.x;
  r1[1] = pos.y;
  r1[2] = pos.z;
  r2[0] = ref_pos.x;
  r2[1] = ref_pos.y;
  r2[2] = ref_pos.z;
  pbc_dx_aiuc(&gmx_pbc, r1, r2, dr);

  // dr is the closest distance vector.
  pos.x = r2[0]+dr[0];
  pos.y = r1[1]+dr[1];
  pos.z = r1[2]+dr[2];
}
Example #5
0
real 
do_listed_vdw_q(int ftype,int nbonds,
                const t_iatom iatoms[],const t_iparams iparams[],
                const rvec x[],rvec f[],rvec fshift[],
                const t_pbc *pbc,const t_graph *g,
                real lambda,real *dvdlambda,
                const t_mdatoms *md,
                const t_forcerec *fr,gmx_grppairener_t *grppener,
                int *global_atom_index)
{
    static    gmx_bool bWarn=FALSE;
    real      eps,r2,*tab,rtab2=0;
    rvec      dx,x14[2],f14[2];
    int       i,ai,aj,itype;
    int       typeA[2]={0,0},typeB[2]={0,1};
    real      chargeA[2]={0,0},chargeB[2];
    int       gid,shift_vir,shift_f;
    int       j_index[] = { 0, 1 };
    int       i0=0,i1=1,i2=2;
    ivec      dt;
    int       outeriter,inneriter;
    int       nthreads = 1;
    int       count;
    real      krf,crf,tabscale;
    int       ntype=0;
    real      *nbfp=NULL;
    real      *egnb=NULL,*egcoul=NULL;
    t_nblist  tmplist;
    int       icoul,ivdw;
    gmx_bool      bMolPBC,bFreeEnergy;
    t_pf_global *pf_global;
    
    
#if GMX_THREAD_SHM_FDECOMP
    pthread_mutex_t mtx;
#else
    void *    mtx = NULL;
#endif

    
#if GMX_THREAD_SHM_FDECOMP
    pthread_mutex_initialize(&mtx);
#endif

    bMolPBC = fr->bMolPBC;

    pf_global = fr->pf_global;
    
    switch (ftype) {
    case F_LJ14:
    case F_LJC14_Q:
        eps = fr->epsfac*fr->fudgeQQ;
        ntype  = 1;
        egnb   = grppener->ener[egLJ14];
        egcoul = grppener->ener[egCOUL14];
        break;
    case F_LJC_PAIRS_NB:
        eps = fr->epsfac;
        ntype  = 1;
        egnb   = grppener->ener[egLJSR];
        egcoul = grppener->ener[egCOULSR];
        break;
    default:
        gmx_fatal(FARGS,"Unknown function type %d in do_nonbonded14",
                  ftype);
    }
    tab = fr->tab14.tab;
    rtab2 = sqr(fr->tab14.r);
    tabscale = fr->tab14.scale;

    krf = fr->k_rf;
    crf = fr->c_rf;

    /* Determine the values for icoul/ivdw. */
    if (fr->bEwald) {
        icoul = 1;
    } 
    else if(fr->bcoultab)
    {
        icoul = 3;
    }
    else if(fr->eeltype == eelRF_NEC)
    {
        icoul = 2;
    }
    else 
    {
        icoul = 1;
    }
    
    if(fr->bvdwtab)
    {
        ivdw = 3;
    }
    else if(fr->bBHAM)
    {
        ivdw = 2;
    }
    else 
    {
        ivdw = 1;
    }
    
    
    /* We don't do SSE or altivec here, due to large overhead for 4-fold 
     * unrolling on short lists 
     */
    
    bFreeEnergy = FALSE;
    for(i=0; (i<nbonds); ) 
    {
        itype = iatoms[i++];
        ai    = iatoms[i++];
        aj    = iatoms[i++];
        gid   = GID(md->cENER[ai],md->cENER[aj],md->nenergrp);
        
        switch (ftype) {
        case F_LJ14:
            bFreeEnergy =
                (fr->efep != efepNO &&
                 ((md->nPerturbed && (md->bPerturbed[ai] || md->bPerturbed[aj])) ||
                  iparams[itype].lj14.c6A != iparams[itype].lj14.c6B ||
                  iparams[itype].lj14.c12A != iparams[itype].lj14.c12B));
            chargeA[0] = md->chargeA[ai];
            chargeA[1] = md->chargeA[aj];
            nbfp = (real *)&(iparams[itype].lj14.c6A);
            break;
        case F_LJC14_Q:
            eps = fr->epsfac*iparams[itype].ljc14.fqq;
            chargeA[0] = iparams[itype].ljc14.qi;
            chargeA[1] = iparams[itype].ljc14.qj;
            nbfp = (real *)&(iparams[itype].ljc14.c6);
            break;
        case F_LJC_PAIRS_NB:
            chargeA[0] = iparams[itype].ljcnb.qi;
            chargeA[1] = iparams[itype].ljcnb.qj;
            nbfp = (real *)&(iparams[itype].ljcnb.c6);
            break;
        }
        
        if (!bMolPBC) 
        {
            /* This is a bonded interaction, atoms are in the same box */
            shift_f = CENTRAL;
            r2 = distance2(x[ai],x[aj]);
        }
        else 
        {
            /* Apply full periodic boundary conditions */
            shift_f = pbc_dx_aiuc(pbc,x[ai],x[aj],dx);
            r2 = norm2(dx);
        }

        if (r2 >= rtab2) 
        {
            if (!bWarn) 
            {
                fprintf(stderr,"Warning: 1-4 interaction between %d and %d "
                        "at distance %.3f which is larger than the 1-4 table size %.3f nm\n", 
			glatnr(global_atom_index,ai),
			glatnr(global_atom_index,aj),
			sqrt(r2), sqrt(rtab2));
                fprintf(stderr,"These are ignored for the rest of the simulation\n");
                fprintf(stderr,"This usually means your system is exploding,\n"
                        "if not, you should increase table-extension in your mdp file\n"
                        "or with user tables increase the table size\n");
                bWarn = TRUE;
            }
            if (debug) 
	      fprintf(debug,"%8f %8f %8f\n%8f %8f %8f\n1-4 (%d,%d) interaction not within cut-off! r=%g. Ignored\n",
		      x[ai][XX],x[ai][YY],x[ai][ZZ],
		      x[aj][XX],x[aj][YY],x[aj][ZZ],
		      glatnr(global_atom_index,ai),
		      glatnr(global_atom_index,aj),
		      sqrt(r2));
        }
        else 
        {
            copy_rvec(x[ai],x14[0]);
            copy_rvec(x[aj],x14[1]);
            clear_rvec(f14[0]);
            clear_rvec(f14[1]);
#ifdef DEBUG
            fprintf(debug,"LJ14: grp-i=%2d, grp-j=%2d, ngrp=%2d, GID=%d\n",
                    md->cENER[ai],md->cENER[aj],md->nenergrp,gid);
#endif
            
	    outeriter = inneriter = count = 0;
	    if (bFreeEnergy)
        {
            chargeB[0] = md->chargeB[ai];
            chargeB[1] = md->chargeB[aj];
            /* We pass &(iparams[itype].lj14.c6A) as LJ parameter matrix
             * to the innerloops.
             * Here we use that the LJ-14 parameters are stored in iparams
             * as c6A,c12A,c6B,c12B, which are referenced correctly
             * in the innerloops if we assign type combinations 0-0 and 0-1
             * to atom pair ai-aj in topologies A and B respectively.
             */
            if(ivdw==2)
            {
                gmx_fatal(FARGS,"Cannot do free energy Buckingham interactions.");
            }
            count = 0;
            gmx_nb_free_energy_kernel(icoul,
                                      ivdw,
                                      i1,
                                      &i0,
                                      j_index,
                                      &i1,
                                      &shift_f,
                                      fr->shift_vec[0],
                                      fshift[0],
                                      &gid,
                                      x14[0],
                                      f14[0],
                                      chargeA,
                                      chargeB,
                                      eps,
                                      krf,
                                      crf,
                                      fr->ewaldcoeff,
                                      egcoul,
                                      typeA,
                                      typeB,
                                      ntype,
                                      nbfp,
                                      egnb,
                                      tabscale,
                                      tab,
                                      lambda,
                                      dvdlambda,
                                      fr->sc_alpha,
                                      fr->sc_power,
                                      fr->sc_sigma6_def,
                                      fr->sc_sigma6_min,
                                      TRUE,
                                      &outeriter,
                                      &inneriter);
        }
        else 
        { 
            /* Not perturbed - call kernel 330 */
            nb_kernel330
                ( &i1,
                  &i0,
                  j_index,
                  &i1,
                  &shift_f,
                  fr->shift_vec[0],
                  fshift[0],
                  &gid,
                  x14[0],
                  f14[0],
                  chargeA,
                  &eps,
                  &krf,
                  &crf,
                  egcoul,
                  typeA,
                  &ntype,
                  nbfp,
                  egnb,
                  &tabscale,
                  tab,
                  NULL,
                  NULL,
                  NULL,
                  NULL,
                  &nthreads,
                  &count,
                  (void *)&mtx,
                  &outeriter,
                  &inneriter,
                  NULL);                
        }
        
        /* Add the forces */
        rvec_inc(f[ai],f14[0]);
        rvec_dec(f[aj],f14[0]);

	if (pf_global->bInitialized)
	    pf_atom_add_bonded(pf_global, ai, aj, PF_INTER_NB14, f14[0]);

        if (g) 
        {
            /* Correct the shift forces using the graph */
            ivec_sub(SHIFT_IVEC(g,ai),SHIFT_IVEC(g,aj),dt);    
            shift_vir = IVEC2IS(dt);
            rvec_inc(fshift[shift_vir],f14[0]);
            rvec_dec(fshift[CENTRAL],f14[0]);
        }
        
	    /* flops: eNR_KERNEL_OUTER + eNR_KERNEL330 + 12 */
        }
    }
    return 0.0;
}
Example #6
0
real orires(int nfa,const t_iatom forceatoms[],const t_iparams ip[],
            const rvec x[],rvec f[],rvec fshift[],
            const t_pbc *pbc,const t_graph *g,
            real lambda,real *dvdlambda,
            const t_mdatoms *md,t_fcdata *fcd,
            int *global_atom_index,int ftype,gmx_mc_move *mc_move)
{
    atom_id      ai,aj;
    int          fa,d,i,type,ex,power,ki=CENTRAL;
    ivec         dt;
    real         r2,invr,invr2,fc,smooth_fc,dev,devins,pfac;
    rvec         r,Sr,fij;
    real         vtot;
    const t_oriresdata *od;
    bool         bTAV;
    
    vtot = 0;
    od = &(fcd->orires);
    
    if (od->fc != 0)
    {
        bTAV = (od->edt != 0);

        smooth_fc = od->fc;
        if (bTAV)
        {
            /* Smoothly switch on the restraining when time averaging is used */
            smooth_fc *= (1.0 - od->exp_min_t_tau);
        }
        
        d = 0;
        for(fa=0; fa<nfa; fa+=3)
        {
            type  = forceatoms[fa];
            ai    = forceatoms[fa+1];
            aj    = forceatoms[fa+2];
            if (pbc)
            {
                ki = pbc_dx_aiuc(pbc,x[ai],x[aj],r);
            }
            else
            {
                rvec_sub(x[ai],x[aj],r);
            }
            r2    = norm2(r);
            invr  = invsqrt(r2);
            invr2 = invr*invr;
            ex    = ip[type].orires.ex;
            power = ip[type].orires.power;
            fc    = smooth_fc*ip[type].orires.kfac;
            dev   = od->otav[d] - ip[type].orires.obs;
            
            /* NOTE:
             * there is no real potential when time averaging is applied
             */
            vtot += 0.5*fc*sqr(dev);
            
            if (bTAV)
            {
                /* Calculate the force as the sqrt of tav times instantaneous */
                devins = od->oins[d] - ip[type].orires.obs;
                if (dev*devins <= 0)
                {
                    dev = 0;
                }
                else
                {
                    dev = sqrt(dev*devins);
                    if (devins < 0)
                    {
                        dev = -dev;
                    }
                }
            }
            
            pfac  = fc*ip[type].orires.c*invr2;
            for(i=0; i<power; i++)
            {
                pfac *= invr;
            }
            mvmul(od->S[ex],r,Sr);
            for(i=0; i<DIM; i++)
            {
                fij[i] =
                    -pfac*dev*(4*Sr[i] - 2*(2+power)*invr2*iprod(Sr,r)*r[i]);
            }
            
            if (g)
            {
                ivec_sub(SHIFT_IVEC(g,ai),SHIFT_IVEC(g,aj),dt);
                ki=IVEC2IS(dt);
            }
            
            for(i=0; i<DIM; i++)
            {
                f[ai][i]           += fij[i];
                f[aj][i]           -= fij[i];
                fshift[ki][i]      += fij[i];
                fshift[CENTRAL][i] -= fij[i];
            }
            d++;
        }
    }
    
    return vtot;
    
    /* Approx. 80*nfa/3 flops */
}
Example #7
0
real calc_orires_dev(const gmx_multisim_t *ms,
                     int nfa,const t_iatom forceatoms[],const t_iparams ip[],
                     const t_mdatoms *md,const rvec x[],const t_pbc *pbc,
                     t_fcdata *fcd,history_t *hist)
{
    int          fa,d,i,j,type,ex,nref;
    real         edt,edt1,invn,pfac,r2,invr,corrfac,weight,wsv2,sw,dev;
    tensor       *S,R,TMP;
    rvec5        *Dinsl,*Dins,*Dtav,*rhs;
    real         *mref,***T;
    double       mtot;
    rvec         *xref,*xtmp,com,r_unrot,r;
    t_oriresdata *od;
    bool         bTAV;
    const real   two_thr=2.0/3.0;
    
    od = &(fcd->orires);

    if (od->nr == 0)
    {
        /* This means that this is not the master node */
        gmx_fatal(FARGS,"Orientation restraints are only supported on the master node, use less processors");
    }
    
    bTAV = (od->edt != 0);
    edt  = od->edt;
    edt1 = od->edt1;
    S    = od->S;
    Dinsl= od->Dinsl;
    Dins = od->Dins;
    Dtav = od->Dtav;
    T    = od->TMP;
    rhs  = od->tmp;
    nref = od->nref;
    mref = od->mref;
    xref = od->xref;
    xtmp = od->xtmp;
    
    if (bTAV)
    {
        od->exp_min_t_tau = hist->orire_initf*edt;
        
        /* Correction factor to correct for the lack of history
         * at short times.
         */
        corrfac = 1.0/(1.0 - od->exp_min_t_tau);
    }
    else
    {
        corrfac = 1.0;
    }

    if (ms)
    {
        invn = 1.0/ms->nsim;
    }
    else
    {
        invn = 1.0;
    }
    
    clear_rvec(com);
    mtot = 0;
    j=0;
    for(i=0; i<md->nr; i++)
    {
        if (md->cORF[i] == 0)
        {
            copy_rvec(x[i],xtmp[j]);
            mref[j] = md->massT[i];
            for(d=0; d<DIM; d++)
            {
                com[d] += mref[j]*xref[j][d];
            }
            mtot += mref[j];
            j++;
        }
    }
    svmul(1.0/mtot,com,com);
    for(j=0; j<nref; j++)
    {
        rvec_dec(xtmp[j],com);
    }
    /* Calculate the rotation matrix to rotate x to the reference orientation */
    calc_fit_R(DIM,nref,mref,xref,xtmp,R);
    copy_mat(R,od->R);
    
    d = 0;
    for(fa=0; fa<nfa; fa+=3)
    {
        type = forceatoms[fa];
        if (pbc)
        {
            pbc_dx_aiuc(pbc,x[forceatoms[fa+1]],x[forceatoms[fa+2]],r_unrot);
        }
        else
        {
            rvec_sub(x[forceatoms[fa+1]],x[forceatoms[fa+2]],r_unrot);
        }
        mvmul(R,r_unrot,r);
        r2   = norm2(r);
        invr = invsqrt(r2);
        /* Calculate the prefactor for the D tensor, this includes the factor 3! */
        pfac = ip[type].orires.c*invr*invr*3;
        for(i=0; i<ip[type].orires.power; i++)
        {
            pfac *= invr;
        }
        Dinsl[d][0] = pfac*(2*r[0]*r[0] + r[1]*r[1] - r2);
        Dinsl[d][1] = pfac*(2*r[0]*r[1]);
        Dinsl[d][2] = pfac*(2*r[0]*r[2]);
        Dinsl[d][3] = pfac*(2*r[1]*r[1] + r[0]*r[0] - r2);
        Dinsl[d][4] = pfac*(2*r[1]*r[2]);
        
        if (ms)
        {
            for(i=0; i<5; i++)
            {
                Dins[d][i] = Dinsl[d][i]*invn;
            }
        }

        d++;
    }
  
    if (ms)
    {
        gmx_sum_sim(5*od->nr,Dins[0],ms);
    }
   
    /* Calculate the order tensor S for each experiment via optimization */
    for(ex=0; ex<od->nex; ex++)
    {
        for(i=0; i<5; i++)
        {
            rhs[ex][i] = 0;
            for(j=0; j<=i; j++)
            {
                T[ex][i][j] = 0;
            }
        }
    }
    d = 0;
    for(fa=0; fa<nfa; fa+=3)
    {
        if (bTAV)
        {
            /* Here we update Dtav in t_fcdata using the data in history_t.
             * Thus the results stay correct when this routine
             * is called multiple times.
             */
            for(i=0; i<5; i++)
            {
                Dtav[d][i] = edt*hist->orire_Dtav[d*5+i] + edt1*Dins[d][i];
            }
        }
        
        type   = forceatoms[fa];
        ex     = ip[type].orires.ex;
        weight = ip[type].orires.kfac;
        /* Calculate the vector rhs and half the matrix T for the 5 equations */
        for(i=0; i<5; i++) {
            rhs[ex][i] += Dtav[d][i]*ip[type].orires.obs*weight;
            for(j=0; j<=i; j++)
            {
                T[ex][i][j] += Dtav[d][i]*Dtav[d][j]*weight;
            }
        }
        d++;
    }
    /* Now we have all the data we can calculate S */
    for(ex=0; ex<od->nex; ex++)
    {
        /* Correct corrfac and copy one half of T to the other half */
        for(i=0; i<5; i++)
        {
            rhs[ex][i]  *= corrfac;
            T[ex][i][i] *= sqr(corrfac);
            for(j=0; j<i; j++)
            {
                T[ex][i][j] *= sqr(corrfac);
                T[ex][j][i]  = T[ex][i][j];
            }
        }
        m_inv_gen(T[ex],5,T[ex]);
        /* Calculate the orientation tensor S for this experiment */
        S[ex][0][0] = 0;
        S[ex][0][1] = 0;
        S[ex][0][2] = 0;
        S[ex][1][1] = 0;
        S[ex][1][2] = 0;
        for(i=0; i<5; i++)
        {
            S[ex][0][0] += 1.5*T[ex][0][i]*rhs[ex][i];
            S[ex][0][1] += 1.5*T[ex][1][i]*rhs[ex][i];
            S[ex][0][2] += 1.5*T[ex][2][i]*rhs[ex][i];
            S[ex][1][1] += 1.5*T[ex][3][i]*rhs[ex][i];
            S[ex][1][2] += 1.5*T[ex][4][i]*rhs[ex][i];
        }
        S[ex][1][0] = S[ex][0][1];
        S[ex][2][0] = S[ex][0][2];
        S[ex][2][1] = S[ex][1][2];
        S[ex][2][2] = -S[ex][0][0] - S[ex][1][1];
    }
    
    wsv2 = 0;
    sw   = 0;
    
    d = 0;
    for(fa=0; fa<nfa; fa+=3)
    {
        type = forceatoms[fa];
        ex = ip[type].orires.ex;
        
        od->otav[d] = two_thr*
            corrfac*(S[ex][0][0]*Dtav[d][0] + S[ex][0][1]*Dtav[d][1] +
                     S[ex][0][2]*Dtav[d][2] + S[ex][1][1]*Dtav[d][3] +
                     S[ex][1][2]*Dtav[d][4]);
        if (bTAV)
        {
            od->oins[d] = two_thr*(S[ex][0][0]*Dins[d][0] + S[ex][0][1]*Dins[d][1] +
                                   S[ex][0][2]*Dins[d][2] + S[ex][1][1]*Dins[d][3] +
                                   S[ex][1][2]*Dins[d][4]);
        }
        if (ms)
        {
            /* When ensemble averaging is used recalculate the local orientation
             * for output to the energy file.
             */
            od->oinsl[d] = two_thr*
                (S[ex][0][0]*Dinsl[d][0] + S[ex][0][1]*Dinsl[d][1] +
                 S[ex][0][2]*Dinsl[d][2] + S[ex][1][1]*Dinsl[d][3] +
                 S[ex][1][2]*Dinsl[d][4]);
        }
        
        dev = od->otav[d] - ip[type].orires.obs;
        
        wsv2 += ip[type].orires.kfac*sqr(dev);
        sw   += ip[type].orires.kfac;
        
        d++;
    }
    od->rmsdev = sqrt(wsv2/sw);
    
    /* Rotate the S matrices back, so we get the correct grad(tr(S D)) */
    for(ex=0; ex<od->nex; ex++)
    {
        tmmul(R,S[ex],TMP);
        mmul(TMP,R,S[ex]);
    }
    
    return od->rmsdev;
    
    /* Approx. 120*nfa/3 flops */
}
Example #8
0
static void lincs_warning(FILE *fplog,
                          gmx_domdec_t *dd,rvec *x,rvec *xprime,t_pbc *pbc,
                          int ncons,int *bla,real *bllen,real wangle,
                          int maxwarn,int *warncount)
{
    int b,i,j;
    rvec v0,v1;
    real wfac,d0,d1,cosine;
    char buf[STRLEN];
    
    wfac=cos(DEG2RAD*wangle);
    
    sprintf(buf,"bonds that rotated more than %g degrees:\n"
            " atom 1 atom 2  angle  previous, current, constraint length\n",
            wangle);
    fprintf(stderr,"%s",buf);
    if (fplog)
    {
        fprintf(fplog,"%s",buf);
    }
    
    for(b=0;b<ncons;b++)
    {
        i = bla[2*b];
        j = bla[2*b+1];
        if (pbc)
        {
            pbc_dx_aiuc(pbc,x[i],x[j],v0);
            pbc_dx_aiuc(pbc,xprime[i],xprime[j],v1);
        }
        else
        {
            rvec_sub(x[i],x[j],v0);
            rvec_sub(xprime[i],xprime[j],v1);
        }
        d0 = norm(v0);
        d1 = norm(v1);
        cosine = iprod(v0,v1)/(d0*d1);
        if (cosine < wfac)
        {
            sprintf(buf," %6d %6d  %5.1f  %8.4f %8.4f    %8.4f\n",
                    ddglatnr(dd,i),ddglatnr(dd,j),
                    RAD2DEG*acos(cosine),d0,d1,bllen[b]);
            fprintf(stderr,"%s",buf);
            if (fplog)
            {
                fprintf(fplog,"%s",buf);
            }
            if (!gmx_isfinite(d1))
            {
                gmx_fatal(FARGS,"Bond length not finite.");
            }

            (*warncount)++;
        }
    }
    if (*warncount > maxwarn)
    {
        too_many_constraint_warnings(econtLINCS,*warncount);
    }
}
Example #9
0
static void do_lincs(rvec *x,rvec *xp,matrix box,t_pbc *pbc,
                     struct gmx_lincsdata *lincsd,real *invmass,
					 t_commrec *cr,
                     real wangle,int *warn,
                     real invdt,rvec *v,
                     gmx_bool bCalcVir,tensor rmdr)
{
    int     b,i,j,k,n,iter;
    real    tmp0,tmp1,tmp2,im1,im2,mvb,rlen,len,len2,dlen2,wfac,lam;  
    rvec    dx;
    int     ncons,*bla,*blnr,*blbnb;
    rvec    *r;
    real    *blc,*blmf,*bllen,*blcc,*rhs1,*rhs2,*sol,*lambda;
    int     *nlocat;
    
    ncons  = lincsd->nc;
    bla    = lincsd->bla;
    r      = lincsd->tmpv;
    blnr   = lincsd->blnr;
    blbnb  = lincsd->blbnb;
    blc    = lincsd->blc;
    blmf   = lincsd->blmf;
    bllen  = lincsd->bllen;
    blcc   = lincsd->tmpncc;
    rhs1   = lincsd->tmp1;
    rhs2   = lincsd->tmp2;
    sol    = lincsd->tmp3;
    lambda = lincsd->lambda;
    
    if (DOMAINDECOMP(cr) && cr->dd->constraints)
    {
        nlocat = dd_constraints_nlocalatoms(cr->dd);
    }
    else if (PARTDECOMP(cr))
    {
        nlocat = pd_constraints_nlocalatoms(cr->pd);
    }
    else
    {
        nlocat = NULL;
    }
    
    *warn = 0;

    if (pbc)
    {
        /* Compute normalized i-j vectors */
        for(b=0; b<ncons; b++)
        {
            pbc_dx_aiuc(pbc,x[bla[2*b]],x[bla[2*b+1]],dx);
            unitv(dx,r[b]);
        }  
        for(b=0; b<ncons; b++)
        {
            for(n=blnr[b]; n<blnr[b+1]; n++)
            {
                blcc[n] = blmf[n]*iprod(r[b],r[blbnb[n]]);
            }
            pbc_dx_aiuc(pbc,xp[bla[2*b]],xp[bla[2*b+1]],dx);
            mvb = blc[b]*(iprod(r[b],dx) - bllen[b]);
            rhs1[b] = mvb;
            sol[b]  = mvb;
        }
    }
    else
    {
        /* Compute normalized i-j vectors */
        for(b=0; b<ncons; b++)
        {
            i = bla[2*b];
            j = bla[2*b+1];
            tmp0 = x[i][0] - x[j][0];
            tmp1 = x[i][1] - x[j][1];
            tmp2 = x[i][2] - x[j][2];
            rlen = gmx_invsqrt(tmp0*tmp0+tmp1*tmp1+tmp2*tmp2);
            r[b][0] = rlen*tmp0;
            r[b][1] = rlen*tmp1;
            r[b][2] = rlen*tmp2;
        } /* 16 ncons flops */
        
        for(b=0; b<ncons; b++)
        {
            tmp0 = r[b][0];
            tmp1 = r[b][1];
            tmp2 = r[b][2];
            len = bllen[b];
            i = bla[2*b];
            j = bla[2*b+1];
            for(n=blnr[b]; n<blnr[b+1]; n++)
            {
                k = blbnb[n];
                blcc[n] = blmf[n]*(tmp0*r[k][0] + tmp1*r[k][1] + tmp2*r[k][2]); 
            } /* 6 nr flops */
            mvb = blc[b]*(tmp0*(xp[i][0] - xp[j][0]) +
                          tmp1*(xp[i][1] - xp[j][1]) +    
                          tmp2*(xp[i][2] - xp[j][2]) - len);
            rhs1[b] = mvb;
            sol[b]  = mvb;
            /* 10 flops */
        }
        /* Together: 26*ncons + 6*nrtot flops */
    }
    
    lincs_matrix_expand(lincsd,blcc,rhs1,rhs2,sol);
    /* nrec*(ncons+2*nrtot) flops */
    
    for(b=0; b<ncons; b++)
    {
        i = bla[2*b];
        j = bla[2*b+1];
        mvb = blc[b]*sol[b];
        lambda[b] = -mvb;
        im1 = invmass[i];
        im2 = invmass[j];
        tmp0 = r[b][0]*mvb;
        tmp1 = r[b][1]*mvb;
        tmp2 = r[b][2]*mvb;
        xp[i][0] -= tmp0*im1;
        xp[i][1] -= tmp1*im1;
        xp[i][2] -= tmp2*im1;
        xp[j][0] += tmp0*im2;
        xp[j][1] += tmp1*im2;
        xp[j][2] += tmp2*im2;
    } /* 16 ncons flops */


    /*     
     ********  Correction for centripetal effects  ********  
     */
  
    wfac = cos(DEG2RAD*wangle);
    wfac = wfac*wfac;
	
    for(iter=0; iter<lincsd->nIter; iter++)
    {
        if (DOMAINDECOMP(cr) && cr->dd->constraints)
        {
            /* Communicate the corrected non-local coordinates */
            dd_move_x_constraints(cr->dd,box,xp,NULL);
        } 
		else if (PARTDECOMP(cr))
		{
			pd_move_x_constraints(cr,xp,NULL);
		}	
        
        for(b=0; b<ncons; b++)
        {
            len = bllen[b];
            if (pbc)
            {
                pbc_dx_aiuc(pbc,xp[bla[2*b]],xp[bla[2*b+1]],dx);
            }
            else
            {
                rvec_sub(xp[bla[2*b]],xp[bla[2*b+1]],dx);
            }
            len2 = len*len;
            dlen2 = 2*len2 - norm2(dx);
            if (dlen2 < wfac*len2 && (nlocat==NULL || nlocat[b]))
            {
                *warn = b;
            }
            if (dlen2 > 0)
            {
                mvb = blc[b]*(len - dlen2*gmx_invsqrt(dlen2));
            }
            else
            {
                mvb = blc[b]*len;
            }
            rhs1[b] = mvb;
            sol[b]  = mvb;
        } /* 20*ncons flops */
        
        lincs_matrix_expand(lincsd,blcc,rhs1,rhs2,sol);
        /* nrec*(ncons+2*nrtot) flops */
        
        for(b=0; b<ncons; b++)
        {
            i = bla[2*b];
            j = bla[2*b+1];
            lam = lambda[b];
            mvb = blc[b]*sol[b];
            lambda[b] = lam - mvb;
            im1 = invmass[i];
            im2 = invmass[j];
            tmp0 = r[b][0]*mvb;
            tmp1 = r[b][1]*mvb;
            tmp2 = r[b][2]*mvb;
            xp[i][0] -= tmp0*im1;
            xp[i][1] -= tmp1*im1;
            xp[i][2] -= tmp2*im1;
            xp[j][0] += tmp0*im2;
            xp[j][1] += tmp1*im2;
            xp[j][2] += tmp2*im2;
        } /* 17 ncons flops */
    } /* nit*ncons*(37+9*nrec) flops */
    
    if (v)
    {
        /* Correct the velocities */
        for(b=0; b<ncons; b++)
        {
            i = bla[2*b];
            j = bla[2*b+1];
            im1 = invmass[i]*lambda[b]*invdt;
            im2 = invmass[j]*lambda[b]*invdt;
            v[i][0] += im1*r[b][0];
            v[i][1] += im1*r[b][1];
            v[i][2] += im1*r[b][2];
            v[j][0] -= im2*r[b][0];
            v[j][1] -= im2*r[b][1];
            v[j][2] -= im2*r[b][2];
        } /* 16 ncons flops */
    }
    
    if (nlocat)
    {
        /* Only account for local atoms */
        for(b=0; b<ncons; b++)
        {
            lambda[b] *= 0.5*nlocat[b];
        }
    }
    
    if (bCalcVir)
    {
        /* Constraint virial */
        for(b=0; b<ncons; b++)
        {
            tmp0 = bllen[b]*lambda[b];
            for(i=0; i<DIM; i++)
            {
                tmp1 = tmp0*r[b][i];
                for(j=0; j<DIM; j++)
                {
                    rmdr[i][j] -= tmp1*r[b][j];
                }
            }
        } /* 22 ncons flops */
    }
    
    /* Total:
     * 26*ncons + 6*nrtot + nrec*(ncons+2*nrtot)
     * + nit * (20*ncons + nrec*(ncons+2*nrtot) + 17 ncons)
     *
     * (26+nrec)*ncons + (6+2*nrec)*nrtot
     * + nit * ((37+nrec)*ncons + 2*nrec*nrtot)
     * if nit=1
     * (63+nrec)*ncons + (6+4*nrec)*nrtot
     */
}
Example #10
0
/* LINCS projection, works on derivatives of the coordinates */
static void do_lincsp(rvec *x,rvec *f,rvec *fp,t_pbc *pbc,
                      struct gmx_lincsdata *lincsd,int th,
                      real *invmass,
                      int econq,real *dvdlambda,
                      gmx_bool bCalcVir,tensor rmdf)
{
    int     b0,b1,b,i,j,k,n;
    real    tmp0,tmp1,tmp2,im1,im2,mvb,rlen,len,wfac,lam;  
    rvec    dx;
    int     *bla,*blnr,*blbnb;
    rvec    *r;
    real    *blc,*blmf,*blcc,*rhs1,*rhs2,*sol;

    b0 = lincsd->th[th].b0;
    b1 = lincsd->th[th].b1;
    
    bla    = lincsd->bla;
    r      = lincsd->tmpv;
    blnr   = lincsd->blnr;
    blbnb  = lincsd->blbnb;
    if (econq != econqForce)
    {
        /* Use mass-weighted parameters */
        blc  = lincsd->blc;
        blmf = lincsd->blmf; 
    }
    else
    {
        /* Use non mass-weighted parameters */
        blc  = lincsd->blc1;
        blmf = lincsd->blmf1;
    }
    blcc   = lincsd->tmpncc;
    rhs1   = lincsd->tmp1;
    rhs2   = lincsd->tmp2;
    sol    = lincsd->tmp3;
    
    /* Compute normalized i-j vectors */
    if (pbc)
    {
        for(b=b0; b<b1; b++)
        {
            pbc_dx_aiuc(pbc,x[bla[2*b]],x[bla[2*b+1]],dx);
            unitv(dx,r[b]);
        }
    }
    else
    {
        for(b=b0; b<b1; b++)
        {
            rvec_sub(x[bla[2*b]],x[bla[2*b+1]],dx);
            unitv(dx,r[b]);
        } /* 16 ncons flops */
    }
    
#pragma omp barrier
    for(b=b0; b<b1; b++)
    {
        tmp0 = r[b][0];
        tmp1 = r[b][1];
        tmp2 = r[b][2];
        i = bla[2*b];
        j = bla[2*b+1];
        for(n=blnr[b]; n<blnr[b+1]; n++)
        {
            k = blbnb[n];
            blcc[n] = blmf[n]*(tmp0*r[k][0] + tmp1*r[k][1] + tmp2*r[k][2]); 
        } /* 6 nr flops */
        mvb = blc[b]*(tmp0*(f[i][0] - f[j][0]) +
                      tmp1*(f[i][1] - f[j][1]) +    
                      tmp2*(f[i][2] - f[j][2]));
        rhs1[b] = mvb;
        sol[b]  = mvb;
        /* 7 flops */
    }
    /* Together: 23*ncons + 6*nrtot flops */
    
    lincs_matrix_expand(lincsd,b0,b1,blcc,rhs1,rhs2,sol);
    /* nrec*(ncons+2*nrtot) flops */
    
    if (econq == econqDeriv_FlexCon)
    {
        /* We only want to constraint the flexible constraints,
         * so we mask out the normal ones by setting sol to 0.
         */
        for(b=b0; b<b1; b++)
        {
            if (!(lincsd->bllen0[b] == 0 && lincsd->ddist[b] == 0))
            {
                sol[b] = 0;
            }
        }
    }

    if (econq != econqForce)
    {
        lincs_update_atoms(lincsd,th,1.0,sol,r,invmass,fp);
    }
    else
    {
        for(b=b0; b<b1; b++)
        {
            i = bla[2*b];
            j = bla[2*b+1];
            mvb = blc[b]*sol[b];
            tmp0 = r[b][0]*mvb;
            tmp1 = r[b][1]*mvb;
            tmp2 = r[b][2]*mvb;
            fp[i][0] -= tmp0;
            fp[i][1] -= tmp1;
            fp[i][2] -= tmp2;
            fp[j][0] += tmp0;
            fp[j][1] += tmp1;
            fp[j][2] += tmp2;
        }

        if (dvdlambda != NULL)
        {
#pragma omp barrier
            for(b=b0; b<b1; b++)
            {
                *dvdlambda -= blc[b]*sol[b]*lincsd->ddist[b];
            }
        }
        /* 10 ncons flops */
    }

    if (bCalcVir)
    {
        /* Constraint virial,
         * determines sum r_bond x delta f,
         * where delta f is the constraint correction
         * of the quantity that is being constrained.
         */
        for(b=b0; b<b1; b++)
        {
            mvb = lincsd->bllen[b]*blc[b]*sol[b];
            for(i=0; i<DIM; i++)
            {
                tmp1 = mvb*r[b][i];
                for(j=0; j<DIM; j++)
                {
                    rmdf[i][j] += tmp1*r[b][j];
                }
            }
        } /* 23 ncons flops */
    }
}
Example #11
0
void csettle(gmx_settledata_t settled,
             int nsettle, t_iatom iatoms[],
             const t_pbc *pbc,
             real b4[], real after[],
             real invdt, real *v, int CalcVirAtomEnd,
             tensor vir_r_m_dr,
             int *error)
{
    /* ***************************************************************** */
    /*                                                               ** */
    /*    Subroutine : setlep - reset positions of TIP3P waters      ** */
    /*    Author : Shuichi Miyamoto                                  ** */
    /*    Date of last update : Oct. 1, 1992                         ** */
    /*                                                               ** */
    /*    Reference for the SETTLE algorithm                         ** */
    /*           S. Miyamoto et al., J. Comp. Chem., 13, 952 (1992). ** */
    /*                                                               ** */
    /* ***************************************************************** */

    /* Initialized data */
    settleparam_t *p;
    real           wh, ra, rb, rc, irc2;
    real           mO, mH;

    /* Local variables */
    real     gama, beta, alpa, xcom, ycom, zcom, al2be2, tmp, tmp2;
    real     axlng, aylng, azlng, trns11, trns21, trns31, trns12, trns22,
             trns32, trns13, trns23, trns33, cosphi, costhe, sinphi, sinthe,
             cospsi, xaksxd, yaksxd, xakszd, yakszd, zakszd, zaksxd, xaksyd,
             xb0, yb0, zb0, xc0, yc0, zc0, xa1;
    real     ya1, za1, xb1, yb1;
    real     zb1, xc1, yc1, zc1, yaksyd, zaksyd, sinpsi, xa3, ya3, za3,
             xb3, yb3, zb3, xc3, yc3, zc3, xb0d, yb0d, xc0d, yc0d,
             za1d, xb1d, yb1d, zb1d, xc1d, yc1d, zc1d, ya2d, xb2d, yb2d, yc2d,
             xa3d, ya3d, za3d, xb3d, yb3d, zb3d, xc3d, yc3d, zc3d;
    real     t1, t2;
    real     dax, day, daz, dbx, dby, dbz, dcx, dcy, dcz;
    real     mdax, mday, mdaz, mdbx, mdby, mdbz, mdcx, mdcy, mdcz;

    gmx_bool bOK;

    int      i, ow1, hw2, hw3;

    rvec     dx, sh_hw2 = {0, 0, 0}, sh_hw3 = {0, 0, 0};
    rvec     doh2, doh3;
    int      is;

    *error = -1;

    CalcVirAtomEnd *= 3;

    p     = &settled->massw;
    wh    = p->wh;
    rc    = p->rc;
    ra    = p->ra;
    rb    = p->rb;
    irc2  = p->irc2;
    mO    = p->mO;
    mH    = p->mH;

#ifdef PRAGMAS
#pragma ivdep
#endif
    for (i = 0; i < nsettle; ++i)
    {
        bOK = TRUE;
        /*    --- Step1  A1' ---      */
        ow1 = iatoms[i*4+1] * 3;
        hw2 = iatoms[i*4+2] * 3;
        hw3 = iatoms[i*4+3] * 3;
        if (pbc == NULL)
        {
            xb0 = b4[hw2 + XX] - b4[ow1 + XX];
            yb0 = b4[hw2 + YY] - b4[ow1 + YY];
            zb0 = b4[hw2 + ZZ] - b4[ow1 + ZZ];
            xc0 = b4[hw3 + XX] - b4[ow1 + XX];
            yc0 = b4[hw3 + YY] - b4[ow1 + YY];
            zc0 = b4[hw3 + ZZ] - b4[ow1 + ZZ];
            /* 6 flops */

            rvec_sub(after+hw2, after+ow1, doh2);
            rvec_sub(after+hw3, after+ow1, doh3);
            /* 6 flops */
        }
        else
        {
            pbc_dx_aiuc(pbc, b4+hw2, b4+ow1, dx);
            xb0 = dx[XX];
            yb0 = dx[YY];
            zb0 = dx[ZZ];
            pbc_dx_aiuc(pbc, b4+hw3, b4+ow1, dx);
            xc0 = dx[XX];
            yc0 = dx[YY];
            zc0 = dx[ZZ];

            /* Tedious way of doing pbc */
            is = pbc_dx_aiuc(pbc, after+hw2, after+ow1, doh2);
            if (is == CENTRAL)
            {
                clear_rvec(sh_hw2);
            }
            else
            {
                sh_hw2[XX] = after[hw2 + XX] - (after[ow1 + XX] + doh2[XX]);
                sh_hw2[YY] = after[hw2 + YY] - (after[ow1 + YY] + doh2[YY]);
                sh_hw2[ZZ] = after[hw2 + ZZ] - (after[ow1 + ZZ] + doh2[ZZ]);
                rvec_dec(after+hw2, sh_hw2);
            }
            is = pbc_dx_aiuc(pbc, after+hw3, after+ow1, doh3);
            if (is == CENTRAL)
            {
                clear_rvec(sh_hw3);
            }
            else
            {
                sh_hw3[XX] = after[hw3 + XX] - (after[ow1 + XX] + doh3[XX]);
                sh_hw3[YY] = after[hw3 + YY] - (after[ow1 + YY] + doh3[YY]);
                sh_hw3[ZZ] = after[hw3 + ZZ] - (after[ow1 + ZZ] + doh3[ZZ]);
                rvec_dec(after+hw3, sh_hw3);
            }
        }

        /* Not calculating the center of mass using the oxygen position
         * and the O-H distances, as done below, will make SETTLE
         * the largest source of energy drift for simulations of water,
         * as then the oxygen coordinate is multiplied by 0.89 at every step,
         * which can then transfer a systematic rounding to the oxygen velocity.
         */
        xa1 = -(doh2[XX] + doh3[XX]) * wh;
        ya1 = -(doh2[YY] + doh3[YY]) * wh;
        za1 = -(doh2[ZZ] + doh3[ZZ]) * wh;

        xcom = after[ow1 + XX] - xa1;
        ycom = after[ow1 + YY] - ya1;
        zcom = after[ow1 + ZZ] - za1;

        xb1 = after[hw2 + XX] - xcom;
        yb1 = after[hw2 + YY] - ycom;
        zb1 = after[hw2 + ZZ] - zcom;
        xc1 = after[hw3 + XX] - xcom;
        yc1 = after[hw3 + YY] - ycom;
        zc1 = after[hw3 + ZZ] - zcom;
        /* 15 flops */

        xakszd = yb0 * zc0 - zb0 * yc0;
        yakszd = zb0 * xc0 - xb0 * zc0;
        zakszd = xb0 * yc0 - yb0 * xc0;
        xaksxd = ya1 * zakszd - za1 * yakszd;
        yaksxd = za1 * xakszd - xa1 * zakszd;
        zaksxd = xa1 * yakszd - ya1 * xakszd;
        xaksyd = yakszd * zaksxd - zakszd * yaksxd;
        yaksyd = zakszd * xaksxd - xakszd * zaksxd;
        zaksyd = xakszd * yaksxd - yakszd * xaksxd;
        /* 27 flops */

        axlng = gmx_invsqrt(xaksxd * xaksxd + yaksxd * yaksxd + zaksxd * zaksxd);
        aylng = gmx_invsqrt(xaksyd * xaksyd + yaksyd * yaksyd + zaksyd * zaksyd);
        azlng = gmx_invsqrt(xakszd * xakszd + yakszd * yakszd + zakszd * zakszd);

        trns11 = xaksxd * axlng;
        trns21 = yaksxd * axlng;
        trns31 = zaksxd * axlng;
        trns12 = xaksyd * aylng;
        trns22 = yaksyd * aylng;
        trns32 = zaksyd * aylng;
        trns13 = xakszd * azlng;
        trns23 = yakszd * azlng;
        trns33 = zakszd * azlng;
        /* 24 flops */

        xb0d = trns11 * xb0 + trns21 * yb0 + trns31 * zb0;
        yb0d = trns12 * xb0 + trns22 * yb0 + trns32 * zb0;
        xc0d = trns11 * xc0 + trns21 * yc0 + trns31 * zc0;
        yc0d = trns12 * xc0 + trns22 * yc0 + trns32 * zc0;
        /*
           xa1d = trns11 * xa1 + trns21 * ya1 + trns31 * za1;
           ya1d = trns12 * xa1 + trns22 * ya1 + trns32 * za1;
         */
        za1d = trns13 * xa1 + trns23 * ya1 + trns33 * za1;
        xb1d = trns11 * xb1 + trns21 * yb1 + trns31 * zb1;
        yb1d = trns12 * xb1 + trns22 * yb1 + trns32 * zb1;
        zb1d = trns13 * xb1 + trns23 * yb1 + trns33 * zb1;
        xc1d = trns11 * xc1 + trns21 * yc1 + trns31 * zc1;
        yc1d = trns12 * xc1 + trns22 * yc1 + trns32 * zc1;
        zc1d = trns13 * xc1 + trns23 * yc1 + trns33 * zc1;
        /* 65 flops */

        sinphi = za1d * gmx_invsqrt(ra*ra);
        tmp    = 1.0 - sinphi * sinphi;
        if (tmp <= 0)
        {
            bOK = FALSE;
        }
        else
        {
            tmp2   = gmx_invsqrt(tmp);
            cosphi = tmp*tmp2;
            sinpsi = (zb1d - zc1d) * irc2 * tmp2;
            tmp2   = 1.0 - sinpsi * sinpsi;
            if (tmp2 <= 0)
            {
                bOK = FALSE;
            }
            else
            {
                cospsi = tmp2*gmx_invsqrt(tmp2);
            }
        }
        /* 46 flops */

        if (bOK)
        {
            ya2d =  ra * cosphi;
            xb2d = -rc * cospsi;
            t1   = -rb * cosphi;
            t2   =  rc * sinpsi * sinphi;
            yb2d =  t1 - t2;
            yc2d =  t1 + t2;
            /* 7 flops */

            /*     --- Step3  al,be,ga            --- */
            alpa   = xb2d * (xb0d - xc0d) + yb0d * yb2d + yc0d * yc2d;
            beta   = xb2d * (yc0d - yb0d) + xb0d * yb2d + xc0d * yc2d;
            gama   = xb0d * yb1d - xb1d * yb0d + xc0d * yc1d - xc1d * yc0d;
            al2be2 = alpa * alpa + beta * beta;
            tmp2   = (al2be2 - gama * gama);
            sinthe = (alpa * gama - beta * tmp2*gmx_invsqrt(tmp2)) * gmx_invsqrt(al2be2*al2be2);
            /* 47 flops */

            /*  --- Step4  A3' --- */
            tmp2   = 1.0 - sinthe * sinthe;
            costhe = tmp2*gmx_invsqrt(tmp2);
            xa3d   = -ya2d * sinthe;
            ya3d   = ya2d * costhe;
            za3d   = za1d;
            xb3d   = xb2d * costhe - yb2d * sinthe;
            yb3d   = xb2d * sinthe + yb2d * costhe;
            zb3d   = zb1d;
            xc3d   = -xb2d * costhe - yc2d * sinthe;
            yc3d   = -xb2d * sinthe + yc2d * costhe;
            zc3d   = zc1d;
            /* 26 flops */

            /*    --- Step5  A3 --- */
            xa3 = trns11 * xa3d + trns12 * ya3d + trns13 * za3d;
            ya3 = trns21 * xa3d + trns22 * ya3d + trns23 * za3d;
            za3 = trns31 * xa3d + trns32 * ya3d + trns33 * za3d;
            xb3 = trns11 * xb3d + trns12 * yb3d + trns13 * zb3d;
            yb3 = trns21 * xb3d + trns22 * yb3d + trns23 * zb3d;
            zb3 = trns31 * xb3d + trns32 * yb3d + trns33 * zb3d;
            xc3 = trns11 * xc3d + trns12 * yc3d + trns13 * zc3d;
            yc3 = trns21 * xc3d + trns22 * yc3d + trns23 * zc3d;
            zc3 = trns31 * xc3d + trns32 * yc3d + trns33 * zc3d;
            /* 45 flops */
            after[ow1]     = xcom + xa3;
            after[ow1 + 1] = ycom + ya3;
            after[ow1 + 2] = zcom + za3;
            after[hw2]     = xcom + xb3;
            after[hw2 + 1] = ycom + yb3;
            after[hw2 + 2] = zcom + zb3;
            after[hw3]     = xcom + xc3;
            after[hw3 + 1] = ycom + yc3;
            after[hw3 + 2] = zcom + zc3;
            /* 9 flops */

            if (pbc != NULL)
            {
                rvec_inc(after+hw2, sh_hw2);
                rvec_inc(after+hw3, sh_hw3);
            }

            dax = xa3 - xa1;
            day = ya3 - ya1;
            daz = za3 - za1;
            dbx = xb3 - xb1;
            dby = yb3 - yb1;
            dbz = zb3 - zb1;
            dcx = xc3 - xc1;
            dcy = yc3 - yc1;
            dcz = zc3 - zc1;
            /* 9 flops, counted with the virial */

            if (v != NULL)
            {
                v[ow1]     += dax*invdt;
                v[ow1 + 1] += day*invdt;
                v[ow1 + 2] += daz*invdt;
                v[hw2]     += dbx*invdt;
                v[hw2 + 1] += dby*invdt;
                v[hw2 + 2] += dbz*invdt;
                v[hw3]     += dcx*invdt;
                v[hw3 + 1] += dcy*invdt;
                v[hw3 + 2] += dcz*invdt;
                /* 3*6 flops */
            }

            if (ow1 < CalcVirAtomEnd)
            {
                mdax                = mO*dax;
                mday                = mO*day;
                mdaz                = mO*daz;
                mdbx                = mH*dbx;
                mdby                = mH*dby;
                mdbz                = mH*dbz;
                mdcx                = mH*dcx;
                mdcy                = mH*dcy;
                mdcz                = mH*dcz;
                vir_r_m_dr[XX][XX] -= b4[ow1  ]*mdax + (b4[ow1  ]+xb0)*mdbx + (b4[ow1  ]+xc0)*mdcx;
                vir_r_m_dr[XX][YY] -= b4[ow1  ]*mday + (b4[ow1  ]+xb0)*mdby + (b4[ow1  ]+xc0)*mdcy;
                vir_r_m_dr[XX][ZZ] -= b4[ow1  ]*mdaz + (b4[ow1  ]+xb0)*mdbz + (b4[ow1  ]+xc0)*mdcz;
                vir_r_m_dr[YY][XX] -= b4[ow1+1]*mdax + (b4[ow1+1]+yb0)*mdbx + (b4[ow1+1]+yc0)*mdcx;
                vir_r_m_dr[YY][YY] -= b4[ow1+1]*mday + (b4[ow1+1]+yb0)*mdby + (b4[ow1+1]+yc0)*mdcy;
                vir_r_m_dr[YY][ZZ] -= b4[ow1+1]*mdaz + (b4[ow1+1]+yb0)*mdbz + (b4[ow1+1]+yc0)*mdcz;
                vir_r_m_dr[ZZ][XX] -= b4[ow1+2]*mdax + (b4[ow1+2]+zb0)*mdbx + (b4[ow1+2]+zc0)*mdcx;
                vir_r_m_dr[ZZ][YY] -= b4[ow1+2]*mday + (b4[ow1+2]+zb0)*mdby + (b4[ow1+2]+zc0)*mdcy;
                vir_r_m_dr[ZZ][ZZ] -= b4[ow1+2]*mdaz + (b4[ow1+2]+zb0)*mdbz + (b4[ow1+2]+zc0)*mdcz;
                /* 3*24 - 9 flops */
            }
        }
        else
        {
            *error = i;
        }
#ifdef DEBUG
        if (debug)
        {
            check_cons(debug, "settle", after, ow1, hw2, hw3);
        }
#endif
    }
}
Example #12
0
void settle_proj(gmx_settledata_t settled, int econq,
                 int nsettle, t_iatom iatoms[],
                 const t_pbc *pbc,
                 rvec x[],
                 rvec *der, rvec *derp,
                 int calcvir_atom_end, tensor vir_r_m_dder)
{
    /* Settle for projection out constraint components
     * of derivatives of the coordinates.
     * Berk Hess 2008-1-10
     */

    settleparam_t *p;
    real           imO, imH, dOH, dHH, invdOH, invdHH;
    matrix         invmat;
    int            i, m, m2, ow1, hw2, hw3;
    rvec           roh2, roh3, rhh, dc, fc;

    calcvir_atom_end *= DIM;

    if (econq == econqForce)
    {
        p = &settled->mass1;
    }
    else
    {
        p = &settled->massw;
    }
    imO    = p->imO;
    imH    = p->imH;
    copy_mat(p->invmat, invmat);
    dOH    = p->dOH;
    dHH    = p->dHH;
    invdOH = p->invdOH;
    invdHH = p->invdHH;

#ifdef PRAGMAS
#pragma ivdep
#endif

    for (i = 0; i < nsettle; i++)
    {
        ow1 = iatoms[i*4+1];
        hw2 = iatoms[i*4+2];
        hw3 = iatoms[i*4+3];

        if (pbc == NULL)
        {
            rvec_sub(x[ow1], x[hw2], roh2);
            rvec_sub(x[ow1], x[hw3], roh3);
            rvec_sub(x[hw2], x[hw3], rhh);
        }
        else
        {
            pbc_dx_aiuc(pbc, x[ow1], x[hw2], roh2);
            pbc_dx_aiuc(pbc, x[ow1], x[hw3], roh3);
            pbc_dx_aiuc(pbc, x[hw2], x[hw3], rhh);
        }
        svmul(invdOH, roh2, roh2);
        svmul(invdOH, roh3, roh3);
        svmul(invdHH, rhh, rhh);
        /* 18 flops */

        /* Determine the projections of der on the bonds */
        clear_rvec(dc);
        for (m = 0; m < DIM; m++)
        {
            dc[0] += (der[ow1][m] - der[hw2][m])*roh2[m];
            dc[1] += (der[ow1][m] - der[hw3][m])*roh3[m];
            dc[2] += (der[hw2][m] - der[hw3][m])*rhh [m];
        }
        /* 27 flops */

        /* Determine the correction for the three bonds */
        mvmul(invmat, dc, fc);
        /* 15 flops */

        /* Subtract the corrections from derp */
        for (m = 0; m < DIM; m++)
        {
            derp[ow1][m] -= imO*( fc[0]*roh2[m] + fc[1]*roh3[m]);
            derp[hw2][m] -= imH*(-fc[0]*roh2[m] + fc[2]*rhh [m]);
            derp[hw3][m] -= imH*(-fc[1]*roh3[m] - fc[2]*rhh [m]);
        }

        /* 45 flops */

        if (ow1 < calcvir_atom_end)
        {
            /* Determining r \dot m der is easy,
             * since fc contains the mass weighted corrections for der.
             */

            for (m = 0; m < DIM; m++)
            {
                for (m2 = 0; m2 < DIM; m2++)
                {
                    vir_r_m_dder[m][m2] +=
                        dOH*roh2[m]*roh2[m2]*fc[0] +
                        dOH*roh3[m]*roh3[m2]*fc[1] +
                        dHH*rhh [m]*rhh [m2]*fc[2];
                }
            }
        }
    }
}
Example #13
0
/*! \brief
 * Does a grid search.
 */
static gmx_bool
grid_search(gmx_ana_nbsearch_t *d,
            gmx_bool (*action)(gmx_ana_nbsearch_t *d, int i, real r2))
{
    int  i;
    rvec dx;
    real r2;

    if (d->bGrid)
    {
        int  nbi, ci, cai;

        nbi = d->prevnbi;
        cai = d->prevcai + 1;

        for (; nbi < d->ngridnb; ++nbi)
        {
            ivec cell;

            ivec_add(d->testcell, d->gnboffs[nbi], cell);
            /* TODO: Support for 2D and screw PBC */
            cell[XX] = (cell[XX] + d->ncelldim[XX]) % d->ncelldim[XX];
            cell[YY] = (cell[YY] + d->ncelldim[YY]) % d->ncelldim[YY];
            cell[ZZ] = (cell[ZZ] + d->ncelldim[ZZ]) % d->ncelldim[ZZ];
            ci       = grid_index(d, cell);
            /* TODO: Calculate the required PBC shift outside the inner loop */
            for (; cai < d->ncatoms[ci]; ++cai)
            {
                i = d->catom[ci][cai];
                if (is_excluded(d, i))
                {
                    continue;
                }
                pbc_dx_aiuc(d->pbc, d->xtest, d->xref[i], dx);
                r2 = norm2(dx);
                if (r2 <= d->cutoff2)
                {
                    if (action(d, i, r2))
                    {
                        d->prevnbi = nbi;
                        d->prevcai = cai;
                        d->previ   = i;
                        return TRUE;
                    }
                }
            }
            d->exclind = 0;
            cai        = 0;
        }
    }
    else
    {
        i = d->previ + 1;
        for (; i < d->nref; ++i)
        {
            if (is_excluded(d, i))
            {
                continue;
            }
            if (d->pbc)
            {
                pbc_dx(d->pbc, d->xtest, d->xref[i], dx);
            }
            else
            {
                rvec_sub(d->xtest, d->xref[i], dx);
            }
            r2 = norm2(dx);
            if (r2 <= d->cutoff2)
            {
                if (action(d, i, r2))
                {
                    d->previ = i;
                    return TRUE;
                }
            }
        }
    }
    return FALSE;
}
Example #14
0
static void make_cyl_refgrps(t_commrec *cr, struct pull_t *pull, t_mdatoms *md,
                             t_pbc *pbc, double t, rvec *x)
{
    /* The size and stride per coord for the reduction buffer */
    const int       stride = 9;
    int             c, i, ii, m, start, end;
    rvec            g_x, dx, dir;
    double          inv_cyl_r2;
    pull_comm_t    *comm;
    gmx_ga2la_t    *ga2la = NULL;

    comm = &pull->comm;

    if (comm->dbuf_cyl == NULL)
    {
        snew(comm->dbuf_cyl, pull->ncoord*stride);
    }

    if (cr && DOMAINDECOMP(cr))
    {
        ga2la = cr->dd->ga2la;
    }

    start = 0;
    end   = md->homenr;

    inv_cyl_r2 = 1.0/gmx::square(pull->params.cylinder_r);

    /* loop over all groups to make a reference group for each*/
    for (c = 0; c < pull->ncoord; c++)
    {
        pull_coord_work_t *pcrd;
        double             sum_a, wmass, wwmass;
        dvec               radf_fac0, radf_fac1;

        pcrd   = &pull->coord[c];

        sum_a  = 0;
        wmass  = 0;
        wwmass = 0;
        clear_dvec(radf_fac0);
        clear_dvec(radf_fac1);

        if (pcrd->params.eGeom == epullgCYL)
        {
            pull_group_work_t *pref, *pgrp, *pdyna;

            /* pref will be the same group for all pull coordinates */
            pref  = &pull->group[pcrd->params.group[0]];
            pgrp  = &pull->group[pcrd->params.group[1]];
            pdyna = &pull->dyna[c];
            copy_rvec(pcrd->vec, dir);
            pdyna->nat_loc = 0;

            /* We calculate distances with respect to the reference location
             * of this cylinder group (g_x), which we already have now since
             * we reduced the other group COM over the ranks. This resolves
             * any PBC issues and we don't need to use a PBC-atom here.
             */
            if (pcrd->params.rate != 0)
            {
                /* With rate=0, value_ref is set initially */
                pcrd->value_ref = pcrd->params.init + pcrd->params.rate*t;
            }
            for (m = 0; m < DIM; m++)
            {
                g_x[m] = pgrp->x[m] - pcrd->vec[m]*pcrd->value_ref;
            }

            /* loop over all atoms in the main ref group */
            for (i = 0; i < pref->params.nat; i++)
            {
                ii = pref->params.ind[i];
                if (ga2la)
                {
                    if (!ga2la_get_home(ga2la, pref->params.ind[i], &ii))
                    {
                        ii = -1;
                    }
                }
                if (ii >= start && ii < end)
                {
                    double dr2, dr2_rel, inp;
                    dvec   dr;

                    pbc_dx_aiuc(pbc, x[ii], g_x, dx);
                    inp = iprod(dir, dx);
                    dr2 = 0;
                    for (m = 0; m < DIM; m++)
                    {
                        /* Determine the radial components */
                        dr[m] = dx[m] - inp*dir[m];
                        dr2  += dr[m]*dr[m];
                    }
                    dr2_rel = dr2*inv_cyl_r2;

                    if (dr2_rel < 1)
                    {
                        double mass, weight, dweight_r;
                        dvec   mdw;

                        /* add to index, to sum of COM, to weight array */
                        if (pdyna->nat_loc >= pdyna->nalloc_loc)
                        {
                            pdyna->nalloc_loc = over_alloc_large(pdyna->nat_loc+1);
                            srenew(pdyna->ind_loc,    pdyna->nalloc_loc);
                            srenew(pdyna->weight_loc, pdyna->nalloc_loc);
                            srenew(pdyna->mdw,        pdyna->nalloc_loc);
                            srenew(pdyna->dv,         pdyna->nalloc_loc);
                        }
                        pdyna->ind_loc[pdyna->nat_loc] = ii;

                        mass      = md->massT[ii];
                        /* The radial weight function is 1-2x^2+x^4,
                         * where x=r/cylinder_r. Since this function depends
                         * on the radial component, we also get radial forces
                         * on both groups.
                         */
                        weight    = 1 + (-2 + dr2_rel)*dr2_rel;
                        dweight_r = (-4 + 4*dr2_rel)*inv_cyl_r2;
                        pdyna->weight_loc[pdyna->nat_loc] = weight;
                        sum_a    += mass*weight*inp;
                        wmass    += mass*weight;
                        wwmass   += mass*weight*weight;
                        dsvmul(mass*dweight_r, dr, mdw);
                        copy_dvec(mdw, pdyna->mdw[pdyna->nat_loc]);
                        /* Currently we only have the axial component of the
                         * distance (inp) up to an unkown offset. We add this
                         * offset after the reduction needs to determine the
                         * COM of the cylinder group.
                         */
                        pdyna->dv[pdyna->nat_loc] = inp;
                        for (m = 0; m < DIM; m++)
                        {
                            radf_fac0[m] += mdw[m];
                            radf_fac1[m] += mdw[m]*inp;
                        }
                        pdyna->nat_loc++;
                    }
                }
            }
        }
        comm->dbuf_cyl[c*stride+0] = wmass;
        comm->dbuf_cyl[c*stride+1] = wwmass;
        comm->dbuf_cyl[c*stride+2] = sum_a;
        comm->dbuf_cyl[c*stride+3] = radf_fac0[XX];
        comm->dbuf_cyl[c*stride+4] = radf_fac0[YY];
        comm->dbuf_cyl[c*stride+5] = radf_fac0[ZZ];
        comm->dbuf_cyl[c*stride+6] = radf_fac1[XX];
        comm->dbuf_cyl[c*stride+7] = radf_fac1[YY];
        comm->dbuf_cyl[c*stride+8] = radf_fac1[ZZ];
    }

    if (cr != NULL && PAR(cr))
    {
        /* Sum the contributions over the ranks */
        pull_reduce_double(cr, comm, pull->ncoord*stride, comm->dbuf_cyl);
    }

    for (c = 0; c < pull->ncoord; c++)
    {
        pull_coord_work_t *pcrd;

        pcrd  = &pull->coord[c];

        if (pcrd->params.eGeom == epullgCYL)
        {
            pull_group_work_t *pdyna, *pgrp;
            double             wmass, wwmass, dist;

            pdyna = &pull->dyna[c];
            pgrp  = &pull->group[pcrd->params.group[1]];

            wmass          = comm->dbuf_cyl[c*stride+0];
            wwmass         = comm->dbuf_cyl[c*stride+1];
            pdyna->mwscale = 1.0/wmass;
            /* Cylinder pulling can't be used with constraints, but we set
             * wscale and invtm anyhow, in case someone would like to use them.
             */
            pdyna->wscale  = wmass/wwmass;
            pdyna->invtm   = wwmass/(wmass*wmass);

            /* We store the deviation of the COM from the reference location
             * used above, since we need it when we apply the radial forces
             * to the atoms in the cylinder group.
             */
            pcrd->cyl_dev  = 0;
            for (m = 0; m < DIM; m++)
            {
                g_x[m]         = pgrp->x[m] - pcrd->vec[m]*pcrd->value_ref;
                dist           = -pcrd->vec[m]*comm->dbuf_cyl[c*stride+2]*pdyna->mwscale;
                pdyna->x[m]    = g_x[m] - dist;
                pcrd->cyl_dev += dist;
            }
            /* Now we know the exact COM of the cylinder reference group,
             * we can determine the radial force factor (ffrad) that when
             * multiplied with the axial pull force will give the radial
             * force on the pulled (non-cylinder) group.
             */
            for (m = 0; m < DIM; m++)
            {
                pcrd->ffrad[m] = (comm->dbuf_cyl[c*stride+6+m] +
                                  comm->dbuf_cyl[c*stride+3+m]*pcrd->cyl_dev)/wmass;
            }

            if (debug)
            {
                fprintf(debug, "Pull cylinder group %d:%8.3f%8.3f%8.3f m:%8.3f\n",
                        c, pdyna->x[0], pdyna->x[1],
                        pdyna->x[2], 1.0/pdyna->invtm);
                fprintf(debug, "ffrad %8.3f %8.3f %8.3f\n",
                        pcrd->ffrad[XX], pcrd->ffrad[YY], pcrd->ffrad[ZZ]);
            }
        }
    }
}
Example #15
0
real ta_disres(int nfa,const t_iatom forceatoms[],const t_iparams ip[],
               const rvec x[],rvec f[],rvec fshift[],
               const t_pbc *pbc,const t_graph *g,
               real lambda,real *dvdlambda,
               const t_mdatoms *md,t_fcdata *fcd,
               int *global_atom_index)
{
    const real sixth=1.0/6.0;
    const real seven_three=7.0/3.0;
    
    atom_id     ai,aj;
    int         fa,res,npair,p,pair,ki=CENTRAL,m;
    int         type;
    rvec        dx;
    real        weight_rt_1;
    real        smooth_fc,Rt,Rtav,rt2,*Rtl_6,*Rt_6,*Rtav_6;
    real        k0,f_scal=0,fmax_scal,fk_scal,fij;
    real        tav_viol,instant_viol,mixed_viol,violtot,vtot;
    real        tav_viol_Rtav7,instant_viol_Rtav7;
    real        up1,up2,low;
    gmx_bool        bConservative,bMixed,bViolation;
    ivec        it,jt,dt;
    t_disresdata *dd;
    int         dr_weighting;
    gmx_bool        dr_bMixed;
    
    dd = &(fcd->disres);
    dr_weighting = dd->dr_weighting;
    dr_bMixed    = dd->dr_bMixed;
    Rtl_6        = dd->Rtl_6;
    Rt_6         = dd->Rt_6;
    Rtav_6       = dd->Rtav_6;

    tav_viol=instant_viol=mixed_viol=tav_viol_Rtav7=instant_viol_Rtav7=0;

    smooth_fc = dd->dr_fc;
    if (dd->dr_tau != 0)
    {
        /* scaling factor to smoothly turn on the restraint forces *
         * when using time averaging                               */
        smooth_fc *= (1.0 - dd->exp_min_t_tau); 
    }
    
    violtot = 0;
    vtot    = 0;
    
    /* 'loop' over all atom pairs (pair_nr=fa/3) involved in restraints, *
     * the total number of atoms pairs is nfa/3                          */
    res  = 0;
    fa   = 0;
    while (fa < nfa)
    {
        type  = forceatoms[fa];
        /* Take action depending on restraint, calculate scalar force */
        npair = ip[type].disres.npair;
        up1   = ip[type].disres.up1;
        up2   = ip[type].disres.up2;
        low   = ip[type].disres.low;
        k0    = smooth_fc*ip[type].disres.kfac;
        
        /* save some flops when there is only one pair */
        if (ip[type].disres.type != 2)
        {
            bConservative = (dr_weighting == edrwConservative) && (npair > 1);
            bMixed        = dr_bMixed;
            Rt   = pow(Rt_6[res],-sixth);
            Rtav = pow(Rtav_6[res],-sixth);
        }
        else
        {
            /* When rtype=2 use instantaneous not ensemble avereged distance */
            bConservative = (npair > 1);
            bMixed        = FALSE;
            Rt   = pow(Rtl_6[res],-sixth);
            Rtav = Rt;
        }
        
        if (Rtav > up1)
        {
            bViolation = TRUE;
            tav_viol = Rtav - up1;
        }
        else if (Rtav < low)
        {
            bViolation = TRUE;
            tav_viol = Rtav - low;
        }
        else
        {
            bViolation = FALSE;
        }
        
        if (bViolation)
        {
            /* NOTE:
             * there is no real potential when time averaging is applied
             */
            vtot += 0.5*k0*sqr(tav_viol);
            if (1/vtot == 0)
            {
                printf("vtot is inf: %f\n",vtot);
            }
            if (!bMixed)
            {
                f_scal   = -k0*tav_viol;
                violtot += fabs(tav_viol);
            }
            else
            {
                if (Rt > up1)
                {
                    if (tav_viol > 0)
                    {
                        instant_viol = Rt - up1;
                    }
                    else
                    {
                        bViolation = FALSE;
                    }
                }
                else if (Rt < low)
                {
                    if (tav_viol < 0)
                    {
                        instant_viol = Rt - low;
                    }
                    else
                    {
                        bViolation = FALSE;
                    }
                }
                else
                {
                    bViolation = FALSE;
                }
                if (bViolation)
                {
                    mixed_viol = sqrt(tav_viol*instant_viol);
                    f_scal     = -k0*mixed_viol;
                    violtot   += mixed_viol;
                }
            }
        }

        if (bViolation)
        {
            fmax_scal = -k0*(up2-up1);
            /* Correct the force for the number of restraints */
            if (bConservative)
            {
                f_scal  = max(f_scal,fmax_scal);
                if (!bMixed)
                {
                    f_scal *= Rtav/Rtav_6[res];
                }
                else
                {
                    f_scal /= 2*mixed_viol;
                    tav_viol_Rtav7     = tav_viol*Rtav/Rtav_6[res];
                    instant_viol_Rtav7 = instant_viol*Rt/Rt_6[res];
                }
            }
            else
            {
                f_scal /= (real)npair;
                f_scal  = max(f_scal,fmax_scal);
            }    
            
            /* Exert the force ... */
            
            /* Loop over the atom pairs of 'this' restraint */
            for(p=0; p<npair; p++)
            {
                pair = fa/3;
                ai   = forceatoms[fa+1];
                aj   = forceatoms[fa+2];
                
                if (pbc)
                {
                    ki = pbc_dx_aiuc(pbc,x[ai],x[aj],dx);
                }
                else
                {
                    rvec_sub(x[ai],x[aj],dx);
                }
                rt2 = iprod(dx,dx);
                
                weight_rt_1 = gmx_invsqrt(rt2);
                
                if (bConservative)
                {
                    if (!dr_bMixed)
                    {
                        weight_rt_1 *= pow(dd->rm3tav[pair],seven_three);
                    }
                    else
                    {
                        weight_rt_1 *= tav_viol_Rtav7*pow(dd->rm3tav[pair],seven_three)+
                            instant_viol_Rtav7*pow(dd->rt[pair],-7);
                    }
                }
                
                fk_scal  = f_scal*weight_rt_1;
                
                if (g)
                {
                    ivec_sub(SHIFT_IVEC(g,ai),SHIFT_IVEC(g,aj),dt);
                    ki=IVEC2IS(dt);
                }
                
                for(m=0; m<DIM; m++)
                {
                    fij            = fk_scal*dx[m];
                    
                    f[ai][m]      += fij;
                    f[aj][m]      -= fij;
                    fshift[ki][m] += fij;
                    fshift[CENTRAL][m] -= fij;
                }
                fa += 3;
            }
        }
        else
        {
            /* No violation so force and potential contributions */
            fa += 3*npair;
        }
        res++;
    }
    
    dd->sumviol = violtot;
    
    /* Return energy */
    return vtot;
}
Example #16
0
void calc_disres_R_6(const gmx_multisim_t *ms,
                     int nfa,const t_iatom forceatoms[],const t_iparams ip[],
                     const rvec x[],const t_pbc *pbc,
                     t_fcdata *fcd,history_t *hist)
{
    atom_id     ai,aj;
    int         fa,res,i,pair,ki,kj,m;
    int         type,npair,np;
    rvec        dx;
    real        *rt,*rm3tav,*Rtl_6,*Rt_6,*Rtav_6;
    real        rt_1,rt_3,rt2;
    ivec        it,jt,dt;
    t_disresdata *dd;
    real        ETerm,ETerm1,cf1=0,cf2=0,invn=0;
    gmx_bool        bTav;

    dd = &(fcd->disres);
    bTav         = (dd->dr_tau != 0);
    ETerm        = dd->ETerm;
    ETerm1       = dd->ETerm1;
    rt           = dd->rt;
    rm3tav       = dd->rm3tav;
    Rtl_6        = dd->Rtl_6;
    Rt_6         = dd->Rt_6;
    Rtav_6       = dd->Rtav_6;
    
    if (bTav)
    {
        /* scaling factor to smoothly turn on the restraint forces *
         * when using time averaging                               */
        dd->exp_min_t_tau = hist->disre_initf*ETerm;
        
        cf1 = dd->exp_min_t_tau;
        cf2 = 1.0/(1.0 - dd->exp_min_t_tau);
    }
    
    if (dd->nsystems > 1)
    {
        invn = 1.0/dd->nsystems;
    }
    
    /* 'loop' over all atom pairs (pair_nr=fa/3) involved in restraints, *
     * the total number of atoms pairs is nfa/3                          */
    res = 0;
    fa  = 0;
    while (fa < nfa)
    {
        type  = forceatoms[fa];
        npair = ip[type].disres.npair;
        
        Rtav_6[res] = 0.0;
        Rt_6[res]   = 0.0;
        
        /* Loop over the atom pairs of 'this' restraint */
        np = 0;
        while (fa < nfa && np < npair)
        {
            pair = fa/3;
            ai   = forceatoms[fa+1];
            aj   = forceatoms[fa+2];
            
            if (pbc)
            {
                pbc_dx_aiuc(pbc,x[ai],x[aj],dx);
            }
            else
            {
                rvec_sub(x[ai],x[aj],dx);
            }
            rt2  = iprod(dx,dx);
            rt_1 = gmx_invsqrt(rt2);
            rt_3 = rt_1*rt_1*rt_1;
            
            rt[pair]         = sqrt(rt2);
            if (bTav)
            {
                /* Here we update rm3tav in t_fcdata using the data
                 * in history_t.
                 * Thus the results stay correct when this routine
                 * is called multiple times.
                 */
                rm3tav[pair] = cf2*((ETerm - cf1)*hist->disre_rm3tav[pair] +
                                    ETerm1*rt_3);
            }
            else
            {
                rm3tav[pair] = rt_3;
            }

            Rt_6[res]       += rt_3*rt_3;
            Rtav_6[res]     += rm3tav[pair]*rm3tav[pair];

            fa += 3;
            np++;
        }
        if (dd->nsystems > 1)
        {
            Rtl_6[res]   = Rt_6[res];
            Rt_6[res]   *= invn;
            Rtav_6[res] *= invn;
        }

        res++;
    }
    
#ifdef GMX_MPI
    if (dd->nsystems > 1)
    {
        gmx_sum_comm(2*dd->nres,Rt_6,dd->mpi_comm_ensemble);
    }
#endif
}
Example #17
0
real RF_excl_correction(FILE *log,
			const t_forcerec *fr,t_graph *g,
			const t_mdatoms *mdatoms,const t_blocka *excl,
			rvec x[],rvec f[],rvec *fshift,const t_pbc *pbc,
			real lambda,real *dvdlambda)
{
  /* Calculate the reaction-field energy correction for this node:
   * epsfac q_i q_j (k_rf r_ij^2 - c_rf)
   * and force correction for all excluded pairs, including self pairs.
   */
  int    top,i,j,j1,j2,k,ki;
  double q2sumA,q2sumB,ener;
  const real *chargeA,*chargeB;
  real   ek,ec,L1,qiA,qiB,qqA,qqB,qqL,v;
  rvec   dx,df;
  atom_id *AA;
  ivec   dt;
  int    start = mdatoms->start;
  int    end   = mdatoms->homenr+start;
  int    niat;
  gmx_bool   bMolPBC = fr->bMolPBC;

  if (fr->n_tpi)
    /* For test particle insertion we only correct for the test molecule */
    start = mdatoms->nr - fr->n_tpi;

  ek = fr->epsfac*fr->k_rf;
  ec = fr->epsfac*fr->c_rf;
  chargeA = mdatoms->chargeA;
  chargeB = mdatoms->chargeB;
  AA = excl->a;
  ki = CENTRAL;

  if (fr->bDomDec)
    niat = excl->nr;
  else
    niat = end;

  q2sumA = 0;
  q2sumB = 0;
  ener = 0;
  if (mdatoms->nChargePerturbed == 0) {
    for(i=start; i<niat; i++) {
      qiA = chargeA[i];
      if (i < end)
	q2sumA += qiA*qiA;
      /* Do the exclusions */
      j1  = excl->index[i];
      j2  = excl->index[i+1];
      for(j=j1; j<j2; j++) {
	k = AA[j];
	if (k > i) {
	  qqA = qiA*chargeA[k];
	  if (qqA != 0) {
	    if (g) {
	      rvec_sub(x[i],x[k],dx);
	      ivec_sub(SHIFT_IVEC(g,i),SHIFT_IVEC(g,k),dt);
	      ki=IVEC2IS(dt);
	    } else if (bMolPBC) {
	      ki = pbc_dx_aiuc(pbc,x[i],x[k],dx);
	    } else
	      rvec_sub(x[i],x[k],dx);
	    ener += qqA*(ek*norm2(dx) - ec);
	    svmul(-2*qqA*ek,dx,df);
	    rvec_inc(f[i],df);
	    rvec_dec(f[k],df);
	    rvec_inc(fshift[ki],df);
	    rvec_dec(fshift[CENTRAL],df);
	  }
	}
      }
    }
    ener += -0.5*ec*q2sumA;
  } else {
    L1 = 1.0 - lambda;
    for(i=start; i<niat; i++) {
      qiA = chargeA[i];
      qiB = chargeB[i];
      if (i < end) {
	q2sumA += qiA*qiA;
	q2sumB += qiB*qiB;
      }
      /* Do the exclusions */
      j1  = excl->index[i];
      j2  = excl->index[i+1];
      for(j=j1; j<j2; j++) {
	k = AA[j];
	if (k > i) {
	  qqA = qiA*chargeA[k];
	  qqB = qiB*chargeB[k];
	  if (qqA != 0 || qqB != 0) {
	    qqL = L1*qqA + lambda*qqB;
	    if (g) {
	      rvec_sub(x[i],x[k],dx);
	      ivec_sub(SHIFT_IVEC(g,i),SHIFT_IVEC(g,k),dt);
	      ki=IVEC2IS(dt);
	    } else if (bMolPBC) {
	      ki = pbc_dx_aiuc(pbc,x[i],x[k],dx);
	    } else
	      rvec_sub(x[i],x[k],dx);
	    v = ek*norm2(dx) - ec;
	    ener += qqL*v;
	    svmul(-2*qqL*ek,dx,df);
	    rvec_inc(f[i],df);
	    rvec_dec(f[k],df);
	    rvec_inc(fshift[ki],df);
	    rvec_dec(fshift[CENTRAL],df);
	    *dvdlambda += (qqB - qqA)*v;
	  }
	}
      }
    }
    ener += -0.5*ec*(L1*q2sumA + lambda*q2sumB);
    *dvdlambda += -0.5*ec*(q2sumB - q2sumA);
  }
  
  if (debug)
    fprintf(debug,"RF exclusion energy: %g\n",ener);
  
  return ener;
}
Example #18
0
real
do_nonbonded_listed(int ftype, int nbonds,
                    const t_iatom iatoms[], const t_iparams iparams[],
                    const rvec x[], rvec f[], rvec fshift[],
                    const t_pbc *pbc, const t_graph *g,
                    real *lambda, real *dvdl,
                    const t_mdatoms *md,
                    const t_forcerec *fr, gmx_grppairener_t *grppener,
                    int *global_atom_index)
{
    int              ielec, ivdw;
    real             qq, c6, c12;
    rvec             dx;
    ivec             dt;
    int              i, j, itype, ai, aj, gid;
    int              fshift_index;
    real             r2, rinv;
    real             fscal, velec, vvdw;
    real *           energygrp_elec;
    real *           energygrp_vdw;
    static gmx_bool  warned_rlimit = FALSE;
    /* Free energy stuff */
    gmx_bool         bFreeEnergy;
    real             LFC[2], LFV[2], DLF[2], lfac_coul[2], lfac_vdw[2], dlfac_coul[2], dlfac_vdw[2];
    real             qqB, c6B, c12B, sigma2_def, sigma2_min;


    switch (ftype)
    {
        case F_LJ14:
        case F_LJC14_Q:
            energygrp_elec = grppener->ener[egCOUL14];
            energygrp_vdw  = grppener->ener[egLJ14];
            break;
        case F_LJC_PAIRS_NB:
            energygrp_elec = grppener->ener[egCOULSR];
            energygrp_vdw  = grppener->ener[egLJSR];
            break;
        default:
            energygrp_elec = NULL; /* Keep compiler happy */
            energygrp_vdw  = NULL; /* Keep compiler happy */
            gmx_fatal(FARGS, "Unknown function type %d in do_nonbonded14", ftype);
            break;
    }

    if (fr->efep != efepNO)
    {
        /* Lambda factor for state A=1-lambda and B=lambda */
        LFC[0] = 1.0 - lambda[efptCOUL];
        LFV[0] = 1.0 - lambda[efptVDW];
        LFC[1] = lambda[efptCOUL];
        LFV[1] = lambda[efptVDW];

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

        /* precalculate */
        sigma2_def = pow(fr->sc_sigma6_def, 1.0/3.0);
        sigma2_min = pow(fr->sc_sigma6_min, 1.0/3.0);

        for (i = 0; i < 2; i++)
        {
            lfac_coul[i]  = (fr->sc_power == 2 ? (1-LFC[i])*(1-LFC[i]) : (1-LFC[i]));
            dlfac_coul[i] = DLF[i]*fr->sc_power/fr->sc_r_power*(fr->sc_power == 2 ? (1-LFC[i]) : 1);
            lfac_vdw[i]   = (fr->sc_power == 2 ? (1-LFV[i])*(1-LFV[i]) : (1-LFV[i]));
            dlfac_vdw[i]  = DLF[i]*fr->sc_power/fr->sc_r_power*(fr->sc_power == 2 ? (1-LFV[i]) : 1);
        }
    }
    else
    {
        sigma2_min = sigma2_def = 0;
    }

    bFreeEnergy = FALSE;
    for (i = 0; (i < nbonds); )
    {
        itype = iatoms[i++];
        ai    = iatoms[i++];
        aj    = iatoms[i++];
        gid   = GID(md->cENER[ai], md->cENER[aj], md->nenergrp);

        /* Get parameters */
        switch (ftype)
        {
            case F_LJ14:
                bFreeEnergy =
                    (fr->efep != efepNO &&
                     ((md->nPerturbed && (md->bPerturbed[ai] || md->bPerturbed[aj])) ||
                      iparams[itype].lj14.c6A != iparams[itype].lj14.c6B ||
                      iparams[itype].lj14.c12A != iparams[itype].lj14.c12B));
                qq               = md->chargeA[ai]*md->chargeA[aj]*fr->epsfac*fr->fudgeQQ;
                c6               = iparams[itype].lj14.c6A;
                c12              = iparams[itype].lj14.c12A;
                break;
            case F_LJC14_Q:
                qq               = iparams[itype].ljc14.qi*iparams[itype].ljc14.qj*fr->epsfac*iparams[itype].ljc14.fqq;
                c6               = iparams[itype].ljc14.c6;
                c12              = iparams[itype].ljc14.c12;
                break;
            case F_LJC_PAIRS_NB:
                qq               = iparams[itype].ljcnb.qi*iparams[itype].ljcnb.qj*fr->epsfac;
                c6               = iparams[itype].ljcnb.c6;
                c12              = iparams[itype].ljcnb.c12;
                break;
            default:
                /* Cannot happen since we called gmx_fatal() above in this case */
                qq = c6 = c12 = 0; /* Keep compiler happy */
                break;
        }

        /* To save flops in the optimized kernels, c6/c12 have 6.0/12.0 derivative prefactors
         * included in the general nfbp array now. This means the tables are scaled down by the
         * same factor, so when we use the original c6/c12 parameters from iparams[] they must
         * be scaled up.
         */
        c6  *= 6.0;
        c12 *= 12.0;

        /* Do we need to apply full periodic boundary conditions? */
        if (fr->bMolPBC == TRUE)
        {
            fshift_index = pbc_dx_aiuc(pbc, x[ai], x[aj], dx);
        }
        else
        {
            fshift_index = CENTRAL;
            rvec_sub(x[ai], x[aj], dx);
        }
        r2           = norm2(dx);

        if (r2 >= fr->tab14.r*fr->tab14.r)
        {
            if (warned_rlimit == FALSE)
            {
                nb_listed_warning_rlimit(x, ai, aj, global_atom_index, sqrt(r2), fr->tab14.r);
                warned_rlimit = TRUE;
            }
            continue;
        }

        if (bFreeEnergy)
        {
            /* Currently free energy is only supported for F_LJ14, so no need to check for that if we got here */
            qqB              = md->chargeB[ai]*md->chargeB[aj]*fr->epsfac*fr->fudgeQQ;
            c6B              = iparams[itype].lj14.c6B*6.0;
            c12B             = iparams[itype].lj14.c12B*12.0;

            fscal            = nb_free_energy_evaluate_single(r2, fr->sc_r_power, fr->sc_alphacoul, fr->sc_alphavdw,
                                                              fr->tab14.scale, fr->tab14.data, qq, c6, c12, qqB, c6B, c12B,
                                                              LFC, LFV, DLF, lfac_coul, lfac_vdw, dlfac_coul, dlfac_vdw,
                                                              fr->sc_sigma6_def, fr->sc_sigma6_min, sigma2_def, sigma2_min, &velec, &vvdw, dvdl);
        }
        else
        {
            /* Evaluate tabulated interaction without free energy */
            fscal            = nb_evaluate_single(r2, fr->tab14.scale, fr->tab14.data, qq, c6, c12, &velec, &vvdw);
        }

        energygrp_elec[gid]  += velec;
        energygrp_vdw[gid]   += vvdw;
        svmul(fscal, dx, dx);

        /* Add the forces */
        rvec_inc(f[ai], dx);
        rvec_dec(f[aj], dx);

        if (g)
        {
            /* Correct the shift forces using the graph */
            ivec_sub(SHIFT_IVEC(g, ai), SHIFT_IVEC(g, aj), dt);
            fshift_index = IVEC2IS(dt);
        }
        if (fshift_index != CENTRAL)
        {
            rvec_inc(fshift[fshift_index], dx);
            rvec_dec(fshift[CENTRAL], dx);
        }
    }
    return 0.0;
}
Example #19
0
static void make_cyl_refgrps(t_commrec *cr, t_pull *pull, t_mdatoms *md,
                             t_pbc *pbc, double t, rvec *x, rvec *xp)
{
    int           c, i, ii, m, start, end;
    rvec          g_x, dx, dir;
    double        r0_2, sum_a, sum_ap, dr2, mass, weight, wmass, wwmass, inp;
    t_pull_coord *pcrd;
    t_pull_group *pref, *pgrp, *pdyna;
    gmx_ga2la_t   ga2la = NULL;

    if (pull->dbuf_cyl == NULL)
    {
        snew(pull->dbuf_cyl, pull->ncoord*4);
    }

    if (cr && DOMAINDECOMP(cr))
    {
        ga2la = cr->dd->ga2la;
    }

    start = 0;
    end   = md->homenr;

    r0_2 = dsqr(pull->cyl_r0);

    /* loop over all groups to make a reference group for each*/
    for (c = 0; c < pull->ncoord; c++)
    {
        pcrd  = &pull->coord[c];

        /* pref will be the same group for all pull coordinates */
        pref  = &pull->group[pcrd->group[0]];
        pgrp  = &pull->group[pcrd->group[1]];
        pdyna = &pull->dyna[c];
        copy_rvec(pcrd->vec, dir);
        sum_a          = 0;
        sum_ap         = 0;
        wmass          = 0;
        wwmass         = 0;
        pdyna->nat_loc = 0;

        for (m = 0; m < DIM; m++)
        {
            g_x[m] = pgrp->x[m] - pcrd->vec[m]*(pcrd->init + pcrd->rate*t);
        }

        /* loop over all atoms in the main ref group */
        for (i = 0; i < pref->nat; i++)
        {
            ii = pref->ind[i];
            if (ga2la)
            {
                if (!ga2la_get_home(ga2la, pref->ind[i], &ii))
                {
                    ii = -1;
                }
            }
            if (ii >= start && ii < end)
            {
                pbc_dx_aiuc(pbc, x[ii], g_x, dx);
                inp = iprod(dir, dx);
                dr2 = 0;
                for (m = 0; m < DIM; m++)
                {
                    dr2 += dsqr(dx[m] - inp*dir[m]);
                }

                if (dr2 < r0_2)
                {
                    /* add to index, to sum of COM, to weight array */
                    if (pdyna->nat_loc >= pdyna->nalloc_loc)
                    {
                        pdyna->nalloc_loc = over_alloc_large(pdyna->nat_loc+1);
                        srenew(pdyna->ind_loc, pdyna->nalloc_loc);
                        srenew(pdyna->weight_loc, pdyna->nalloc_loc);
                    }
                    pdyna->ind_loc[pdyna->nat_loc] = ii;
                    mass   = md->massT[ii];
                    weight = get_weight(sqrt(dr2), pull->cyl_r1, pull->cyl_r0);
                    pdyna->weight_loc[pdyna->nat_loc] = weight;
                    sum_a += mass*weight*inp;
                    if (xp)
                    {
                        pbc_dx_aiuc(pbc, xp[ii], g_x, dx);
                        inp     = iprod(dir, dx);
                        sum_ap += mass*weight*inp;
                    }
                    wmass  += mass*weight;
                    wwmass += mass*sqr(weight);
                    pdyna->nat_loc++;
                }
            }
        }
        pull->dbuf_cyl[c*4+0] = wmass;
        pull->dbuf_cyl[c*4+1] = wwmass;
        pull->dbuf_cyl[c*4+2] = sum_a;
        pull->dbuf_cyl[c*4+3] = sum_ap;
    }

    if (cr && PAR(cr))
    {
        /* Sum the contributions over the nodes */
        gmx_sumd(pull->ncoord*4, pull->dbuf_cyl, cr);
    }

    for (c = 0; c < pull->ncoord; c++)
    {
        pcrd  = &pull->coord[c];

        pdyna = &pull->dyna[c];
        pgrp  = &pull->group[pcrd->group[1]];

        wmass         = pull->dbuf_cyl[c*4+0];
        wwmass        = pull->dbuf_cyl[c*4+1];
        pdyna->wscale = wmass/wwmass;
        pdyna->invtm  = 1.0/(pdyna->wscale*wmass);

        for (m = 0; m < DIM; m++)
        {
            g_x[m]      = pgrp->x[m] - pcrd->vec[m]*(pcrd->init + pcrd->rate*t);
            pdyna->x[m] = g_x[m] + pcrd->vec[m]*pull->dbuf_cyl[c*4+2]/wmass;
            if (xp)
            {
                pdyna->xp[m] = g_x[m] + pcrd->vec[m]*pull->dbuf_cyl[c*4+3]/wmass;
            }
        }

        if (debug)
        {
            fprintf(debug, "Pull cylinder group %d:%8.3f%8.3f%8.3f m:%8.3f\n",
                    c, pdyna->x[0], pdyna->x[1],
                    pdyna->x[2], 1.0/pdyna->invtm);
        }
    }
}
Example #20
0
File: qmmm.c Project: t-/adaptive
void update_QMMMrec(t_commrec *cr,
		    t_forcerec *fr,
		    rvec x[],
		    t_mdatoms *md,
		    matrix box,
		    gmx_localtop_t *top)
{
  /* updates the coordinates of both QM atoms and MM atoms and stores
   * them in the QMMMrec.
   *
   * NOTE: is NOT yet working if there are no PBC. Also in ns.c, simple
   * ns needs to be fixed!
   */
  int
    mm_max=0,mm_nr=0,mm_nr_new,i,j,is,k,shift;
  t_j_particle
    *mm_j_particles=NULL,*qm_i_particles=NULL;
  t_QMMMrec
    *qr;
  t_nblist
    QMMMlist;
  rvec
    dx,crd;
  int
    *MMatoms;
  t_QMrec
    *qm;
  t_MMrec
    *mm;
  t_pbc
    pbc;
  int
    *parallelMMarray=NULL;
  real
    c12au,c6au;

  c6au  = (HARTREE2KJ*AVOGADRO*pow(BOHR2NM,6));
  c12au = (HARTREE2KJ*AVOGADRO*pow(BOHR2NM,12));

  /* every cpu has this array. On every processor we fill this array
   * with 1's and 0's. 1's indicate the atoms is a QM atom on the
   * current cpu in a later stage these arrays are all summed. indexes
   * > 0 indicate the atom is a QM atom. Every node therefore knows
   * whcih atoms are part of the QM subsystem.
   */
  /* copy some pointers */
  qr          = fr->qr;
  mm          = qr->mm;
  QMMMlist    = fr->QMMMlist;



  /*  init_pbc(box);  needs to be called first, see pbc.h */
  set_pbc_dd(&pbc,fr->ePBC,DOMAINDECOMP(cr) ? cr->dd : NULL,FALSE,box);
  /* only in standard (normal) QMMM we need the neighbouring MM
   * particles to provide a electric field of point charges for the QM
   * atoms.
   */
  if(qr->QMMMscheme==eQMMMschemenormal){ /* also implies 1 QM-layer */
    /* we NOW create/update a number of QMMMrec entries:
     *
     * 1) the shiftQM, containing the shifts of the QM atoms
     *
     * 2) the indexMM array, containing the index of the MM atoms
     *
     * 3) the shiftMM, containing the shifts of the MM atoms
     *
     * 4) the shifted coordinates of the MM atoms
     *
     * the shifts are used for computing virial of the QM/MM particles.
     */
    qm = qr->qm[0]; /* in case of normal QMMM, there is only one group */
    snew(qm_i_particles,QMMMlist.nri);
    if(QMMMlist.nri){
      qm_i_particles[0].shift = XYZ2IS(0,0,0);
      for(i=0;i<QMMMlist.nri;i++){
	qm_i_particles[i].j     = QMMMlist.iinr[i];

	if(i){
	  qm_i_particles[i].shift = pbc_dx_aiuc(&pbc,x[QMMMlist.iinr[0]],
						x[QMMMlist.iinr[i]],dx);

	}
	/* However, since nri >= nrQMatoms, we do a quicksort, and throw
	 * out double, triple, etc. entries later, as we do for the MM
	 * list too.
	 */

	/* compute the shift for the MM j-particles with respect to
	 * the QM i-particle and store them.
	 */

	crd[0] = IS2X(QMMMlist.shift[i]) + IS2X(qm_i_particles[i].shift);
	crd[1] = IS2Y(QMMMlist.shift[i]) + IS2Y(qm_i_particles[i].shift);
	crd[2] = IS2Z(QMMMlist.shift[i]) + IS2Z(qm_i_particles[i].shift);
	is = XYZ2IS(crd[0],crd[1],crd[2]);
	for(j=QMMMlist.jindex[i];
	    j<QMMMlist.jindex[i+1];
	    j++){
	  if(mm_nr >= mm_max){
	    mm_max += 1000;
	    srenew(mm_j_particles,mm_max);
	  }

	  mm_j_particles[mm_nr].j = QMMMlist.jjnr[j];
	  mm_j_particles[mm_nr].shift = is;
	  mm_nr++;
	}
      }

      /* quicksort QM and MM shift arrays and throw away multiple entries */



      qsort(qm_i_particles,QMMMlist.nri,
	    (size_t)sizeof(qm_i_particles[0]),
	    struct_comp);
      qsort(mm_j_particles,mm_nr,
	    (size_t)sizeof(mm_j_particles[0]),
	    struct_comp);
      /* remove multiples in the QM shift array, since in init_QMMM() we
       * went through the atom numbers from 0 to md.nr, the order sorted
       * here matches the one of QMindex already.
       */
      j=0;
      for(i=0;i<QMMMlist.nri;i++){
	if (i==0 || qm_i_particles[i].j!=qm_i_particles[i-1].j){
	  qm_i_particles[j++] = qm_i_particles[i];
	}
      }
      mm_nr_new = 0;
      if(qm->bTS||qm->bOPT){
	/* only remove double entries for the MM array */
	for(i=0;i<mm_nr;i++){
	  if((i==0 || mm_j_particles[i].j!=mm_j_particles[i-1].j)
	     && !md->bQM[mm_j_particles[i].j]){
	    mm_j_particles[mm_nr_new++] = mm_j_particles[i];
	  }
	}
      }
      /* we also remove mm atoms that have no charges!
      * actually this is already done in the ns.c
      */
      else{
	for(i=0;i<mm_nr;i++){
	  if((i==0 || mm_j_particles[i].j!=mm_j_particles[i-1].j)
	     && !md->bQM[mm_j_particles[i].j]
	     && (md->chargeA[mm_j_particles[i].j]
		 || (md->chargeB && md->chargeB[mm_j_particles[i].j]))) {
	    mm_j_particles[mm_nr_new++] = mm_j_particles[i];
	  }
	}
      }
      mm_nr = mm_nr_new;
      /* store the data retrieved above into the QMMMrec
       */
      k=0;
      /* Keep the compiler happy,
       * shift will always be set in the loop for i=0
       */
      shift = 0;
      for(i=0;i<qm->nrQMatoms;i++){
	/* not all qm particles might have appeared as i
	 * particles. They might have been part of the same charge
	 * group for instance.
	 */
	if (qm->indexQM[i] == qm_i_particles[k].j) {
	  shift = qm_i_particles[k++].shift;
	}
	/* use previous shift, assuming they belong the same charge
	 * group anyway,
	 */

	qm->shiftQM[i] = shift;
      }
    }
    /* parallel excecution */
    if(PAR(cr)){
      snew(parallelMMarray,2*(md->nr));
      /* only MM particles have a 1 at their atomnumber. The second part
       * of the array contains the shifts. Thus:
       * p[i]=1/0 depending on wether atomnumber i is a MM particle in the QM
       * step or not. p[i+md->nr] is the shift of atomnumber i.
       */
      for(i=0;i<2*(md->nr);i++){
	parallelMMarray[i]=0;
      }

      for(i=0;i<mm_nr;i++){
	parallelMMarray[mm_j_particles[i].j]=1;
	parallelMMarray[mm_j_particles[i].j+(md->nr)]=mm_j_particles[i].shift;
      }
      gmx_sumi(md->nr,parallelMMarray,cr);
      mm_nr=0;

      mm_max = 0;
      for(i=0;i<md->nr;i++){
	if(parallelMMarray[i]){
	  if(mm_nr >= mm_max){
	    mm_max += 1000;
	    srenew(mm->indexMM,mm_max);
	    srenew(mm->shiftMM,mm_max);
	  }
	  mm->indexMM[mm_nr]  = i;
	  mm->shiftMM[mm_nr++]= parallelMMarray[i+md->nr]/parallelMMarray[i];
	}
      }
      mm->nrMMatoms=mm_nr;
      free(parallelMMarray);
    }
    /* serial execution */
    else{
      mm->nrMMatoms = mm_nr;
      srenew(mm->shiftMM,mm_nr);
      srenew(mm->indexMM,mm_nr);
      for(i=0;i<mm_nr;i++){
	mm->indexMM[i]=mm_j_particles[i].j;
	mm->shiftMM[i]=mm_j_particles[i].shift;
      }

    }
    /* (re) allocate memory for the MM coordiate array. The QM
     * coordinate array was already allocated in init_QMMM, and is
     * only (re)filled in the update_QMMM_coordinates routine
     */
    srenew(mm->xMM,mm->nrMMatoms);
    /* now we (re) fill the array that contains the MM charges with
     * the forcefield charges. If requested, these charges will be
     * scaled by a factor
     */
    srenew(mm->MMcharges,mm->nrMMatoms);
    for(i=0;i<mm->nrMMatoms;i++){/* no free energy yet */
      mm->MMcharges[i]=md->chargeA[mm->indexMM[i]]*mm->scalefactor;
    }
    if(qm->bTS||qm->bOPT){
      /* store (copy) the c6 and c12 parameters into the MMrec struct
       */
      srenew(mm->c6,mm->nrMMatoms);
      srenew(mm->c12,mm->nrMMatoms);
      for (i=0;i<mm->nrMMatoms;i++){
	mm->c6[i]  = C6(fr->nbfp,top->idef.atnr,
			md->typeA[mm->indexMM[i]],
			md->typeA[mm->indexMM[i]])/c6au;
	mm->c12[i] =C12(fr->nbfp,top->idef.atnr,
			md->typeA[mm->indexMM[i]],
			md->typeA[mm->indexMM[i]])/c12au;
      }
      punch_QMMM_excl(qr->qm[0],mm,&(top->excls));
    }
    /* the next routine fills the coordinate fields in the QMMM rec of
     * both the qunatum atoms and the MM atoms, using the shifts
     * calculated above.
     */

    update_QMMM_coord(x,fr,qr->qm[0],qr->mm);
    free(qm_i_particles);
    free(mm_j_particles);
  }
  else { /* ONIOM */ /* ????? */
    mm->nrMMatoms=0;
    /* do for each layer */
    for (j=0;j<qr->nrQMlayers;j++){
      qm = qr->qm[j];
      qm->shiftQM[0]=XYZ2IS(0,0,0);
      for(i=1;i<qm->nrQMatoms;i++){
	qm->shiftQM[i] = pbc_dx_aiuc(&pbc,x[qm->indexQM[0]],x[qm->indexQM[i]],
				     dx);
      }
      update_QMMM_coord(x,fr,qm,mm);
    }
  }
} /* update_QMMM_rec */
Example #21
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 #22
0
static void do_lincsp(rvec *x,rvec *f,rvec *fp,t_pbc *pbc,
                      struct gmx_lincsdata *lincsd,real *invmass,
                      int econq,real *dvdlambda,
                      gmx_bool bCalcVir,tensor rmdf)
{
    int     b,i,j,k,n;
    real    tmp0,tmp1,tmp2,im1,im2,mvb,rlen,len,wfac,lam;  
    rvec    dx;
    int     ncons,*bla,*blnr,*blbnb;
    rvec    *r;
    real    *blc,*blmf,*blcc,*rhs1,*rhs2,*sol;
    
    ncons  = lincsd->nc;
    bla    = lincsd->bla;
    r      = lincsd->tmpv;
    blnr   = lincsd->blnr;
    blbnb  = lincsd->blbnb;
    if (econq != econqForce)
    {
        /* Use mass-weighted parameters */
        blc  = lincsd->blc;
        blmf = lincsd->blmf; 
    }
    else
    {
        /* Use non mass-weighted parameters */
        blc  = lincsd->blc1;
        blmf = lincsd->blmf1;
    }
    blcc   = lincsd->tmpncc;
    rhs1   = lincsd->tmp1;
    rhs2   = lincsd->tmp2;
    sol    = lincsd->tmp3;
    
    if (econq != econqForce)
    {
        dvdlambda = NULL;
    }
    
    /* Compute normalized i-j vectors */
    if (pbc)
    {
        for(b=0; b<ncons; b++)
        {
            pbc_dx_aiuc(pbc,x[bla[2*b]],x[bla[2*b+1]],dx);
            unitv(dx,r[b]);
        }
    }
    else
    {
        for(b=0; b<ncons; b++)
        {
            rvec_sub(x[bla[2*b]],x[bla[2*b+1]],dx);
            unitv(dx,r[b]);
        } /* 16 ncons flops */
    }
    
    for(b=0; b<ncons; b++)
    {
        tmp0 = r[b][0];
        tmp1 = r[b][1];
        tmp2 = r[b][2];
        i = bla[2*b];
        j = bla[2*b+1];
        for(n=blnr[b]; n<blnr[b+1]; n++)
        {
            k = blbnb[n];
            blcc[n] = blmf[n]*(tmp0*r[k][0] + tmp1*r[k][1] + tmp2*r[k][2]); 
        } /* 6 nr flops */
        mvb = blc[b]*(tmp0*(f[i][0] - f[j][0]) +
                      tmp1*(f[i][1] - f[j][1]) +    
                      tmp2*(f[i][2] - f[j][2]));
        rhs1[b] = mvb;
        sol[b]  = mvb;
        /* 7 flops */
    }
    /* Together: 23*ncons + 6*nrtot flops */
    
    lincs_matrix_expand(lincsd,blcc,rhs1,rhs2,sol);
    /* nrec*(ncons+2*nrtot) flops */
    
    if (econq != econqForce)
    {
        for(b=0; b<ncons; b++)
        {
            /* With econqDeriv_FlexCon only use the flexible constraints */
            if (econq != econqDeriv_FlexCon ||
                (lincsd->bllen0[b] == 0 && lincsd->ddist[b] == 0))
            {
                i = bla[2*b];
                j = bla[2*b+1];
                mvb = blc[b]*sol[b];
                im1 = invmass[i];
                im2 = invmass[j];
                tmp0 = r[b][0]*mvb;
                tmp1 = r[b][1]*mvb;
                tmp2 = r[b][2]*mvb;
                fp[i][0] -= tmp0*im1;
                fp[i][1] -= tmp1*im1;
                fp[i][2] -= tmp2*im1;
                fp[j][0] += tmp0*im2;
                fp[j][1] += tmp1*im2;
                fp[j][2] += tmp2*im2;
                if (dvdlambda)
                {
                    /* This is only correct with forces and invmass=1 */
                    *dvdlambda -= mvb*lincsd->ddist[b];
                }
            }
        } /* 16 ncons flops */
    }
    else
    {
        for(b=0; b<ncons; b++)
        {
            i = bla[2*b];
            j = bla[2*b+1];
            mvb = blc[b]*sol[b];
            tmp0 = r[b][0]*mvb;
            tmp1 = r[b][1]*mvb;
            tmp2 = r[b][2]*mvb;
            fp[i][0] -= tmp0;
            fp[i][1] -= tmp1;
            fp[i][2] -= tmp2;
            fp[j][0] += tmp0;
            fp[j][1] += tmp1;
            fp[j][2] += tmp2;
            if (dvdlambda)
            {
                *dvdlambda -= mvb*lincsd->ddist[b];
            }
        }
        /* 10 ncons flops */
    }
    
    if (bCalcVir)
    {
        /* Constraint virial,
         * determines sum r_bond x delta f,
         * where delta f is the constraint correction
         * of the quantity that is being constrained.
         */
        for(b=0; b<ncons; b++)
        {
            mvb = lincsd->bllen[b]*blc[b]*sol[b];
            for(i=0; i<DIM; i++)
            {
                tmp1 = mvb*r[b][i];
                for(j=0; j<DIM; j++)
                {
                    rmdf[i][j] += tmp1*r[b][j];
                }
            }
        } /* 23 ncons flops */
    }
}
Example #23
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,t_pbc *pbc,
                         real lambda,real *dvdlambda,
                         real invdt,rvec *v,
                         gmx_bool bCalcVir,tensor vir_r_m_dr,
                         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=0;
    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;
    }
    
    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,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,
                    &ncons_loc,&p_ssd,&p_max,&p_imax);
        }

        /* This warn var can be updated by multiple threads
         * at the same time. But as we only need to detect
         * if a warning occured or not, this is not an issue.
         */
        warn = -1;

        /* The OpenMP parallel region of constrain_lincs for coords */
#pragma omp parallel num_threads(lincsd->nth)
        {
            int th=gmx_omp_get_thread_num();

            clear_mat(lincsd->th[th].vir_r_m_dr);

            do_lincs(x,xprime,box,pbc,lincsd,th,
                     md->invmass,cr,
                     bCalcVir || (ir->efep != efepNO),
                     ir->LincsWarnAngle,&warn,
                     invdt,v,bCalcVir,
                     th==0 ? vir_r_m_dr : lincsd->th[th].vir_r_m_dr);
        }

        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->mlambda[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,
                    &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,
                        &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,
                              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
    {
        /* The OpenMP parallel region of constrain_lincs for derivatives */
#pragma omp parallel num_threads(lincsd->nth)
        {
            int th=gmx_omp_get_thread_num();

            do_lincsp(x,xprime,min_proj,pbc,lincsd,th,
                      md->invmass,econq,ir->efep != efepNO ? dvdlambda : NULL,
                      bCalcVir,th==0 ? vir_r_m_dr : lincsd->th[th].vir_r_m_dr);
        }
    }

    if (bCalcVir && lincsd->nth > 1)
    {
        for(i=1; i<lincsd->nth; i++)
        {
            m_add(vir_r_m_dr,lincsd->th[i].vir_r_m_dr,vir_r_m_dr);
        }
    }
 
    /* 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;
}