static bool constrain_lincs(FILE *log,t_topology *top,t_inputrec *ir, int step,t_mdatoms *md,int start,int homenr, int *nbl,int **sbl, rvec *x,rvec *xprime,rvec *min_proj,matrix box, real lambda,real *dvdlambda,bool bCoordinates, bool bInit,t_nrnb *nrnb,bool bDumpOnError) { static int *bla1,*bla2,*blnr,*blbnb,nrtot=0; static rvec *r; static real *bllen,*blc,*blcc,*blm,*tmp1,*tmp2,*tmp3,*lincslam, *bllen0,*ddist; static int nc; static bool bItEqOrder; char buf[STRLEN]; int b,i,j,nit,warn,p_imax,error; real wang,p_max,p_rms; real dt,dt_2; bool bOK; bOK = TRUE; if (bInit) { nc = top->idef.il[F_SHAKE].nr/3; init_lincs(stdlog,top,ir,md,start,homenr, &nrtot, &r,&bla1,&bla2,&blnr,&blbnb, &bllen,&blc,&blcc,&blm,&tmp1,&tmp2,&tmp3,&lincslam, &bllen0,&ddist); #ifdef SPEC_CPU bItEqOrder = FALSE; #else bItEqOrder = (getenv("GMX_ACCURATE_LINCS") != NULL); #endif } else if (nc != 0) { /* If there are any constraints */ if (bCoordinates) { dt = ir->delta_t; dt_2 = 1.0/(dt*dt); if (ir->efep != efepNO) for(i=0;i<nc;i++) bllen[i]=bllen0[i]+lambda*ddist[i]; /* Set the zero lengths to the old lengths */ for(b=0; b<nc; b++) if (bllen0[b]<GMX_REAL_MIN) { i = bla1[b]; j = bla2[b]; bllen[b] = sqrt(sqr(x[i][XX]-x[j][XX])+ sqr(x[i][YY]-x[j][YY])+ sqr(x[i][ZZ]-x[j][ZZ])); } wang=ir->LincsWarnAngle; if (do_per_step(step,ir->nstlog) || step<0) cconerr(&p_max,&p_rms,&p_imax,xprime,nc,bla1,bla2,bllen); if ((ir->eI == eiSteep) || (ir->eI == eiCG) || bItEqOrder) /* Use more iterations when doing energy minimization, * * because we need very accurate positions and forces. */ nit = ir->nProjOrder; else nit = 1; #ifdef USE_FORTRAN #ifdef DOUBLE F77_FUNC(flincsd,FLINCSD)(x[0],xprime[0],&nc,bla1,bla2,blnr,blbnb, bllen,blc,blcc,blm,&nit,&ir->nProjOrder, md->invmass,r[0],tmp1,tmp2,tmp3,&wang,&warn, lincslam); #else F77_FUNC(flincs,FLINCS)(x[0],xprime[0],&nc,bla1,bla2,blnr,blbnb, bllen,blc,blcc,blm,&nit,&ir->nProjOrder, md->invmass,r[0],tmp1,tmp2,tmp3,&wang,&warn, lincslam); #endif #else clincs(x,xprime,nc,bla1,bla2,blnr,blbnb, bllen,blc,blcc,blm,nit,ir->nProjOrder, md->invmass,r,tmp1,tmp2,tmp3,wang,&warn,lincslam); #endif if (ir->efep != efepNO) { real dvdl=0; for(i=0; (i<nc); i++) dvdl+=lincslam[i]*dt_2*ddist[i]; *dvdlambda+=dvdl; } if(stdlog) { if (do_per_step(step,ir->nstlog) || (step<0)) { fprintf(stdlog," Rel. Constraint Deviation: Max between atoms RMS\n"); fprintf(stdlog," Before LINCS %.6f %6d %6d %.6f\n", p_max,bla1[p_imax]+1,bla2[p_imax]+1,p_rms); cconerr(&p_max,&p_rms,&p_imax,xprime,nc,bla1,bla2,bllen); fprintf(stdlog," After LINCS %.6f %6d %6d %.6f\n\n", p_max,bla1[p_imax]+1,bla2[p_imax]+1,p_rms); } } if (warn > 0) { if (bDumpOnError && stdlog) { cconerr(&p_max,&p_rms,&p_imax,xprime,nc,bla1,bla2,bllen); sprintf(buf,"\nStep %d, time %g (ps) LINCS WARNING\n" "relative constraint deviation after LINCS:\n" "max %.6f (between atoms %d and %d) rms %.6f\n", step,ir->init_t+step*ir->delta_t, p_max,bla1[p_imax]+1,bla2[p_imax]+1,p_rms); fprintf(stdlog,"%s",buf); fprintf(stderr,"%s",buf); lincs_warning(x,xprime,nc,bla1,bla2,bllen,wang); } bOK = (p_max < 0.5); } for(b=0; (b<nc); b++) if (bllen0[b] < GMX_REAL_MIN) bllen[b] = 0; } else { #ifdef USE_FORTRAN #ifdef DOUBLE F77_FUNC(flincspd,FLINCSPD)(x[0],xprime[0],min_proj[0],&nc,bla1,bla2,blnr,blbnb, blc,blcc,blm,&ir->nProjOrder, md->invmass,r[0],tmp1,tmp2,tmp3); #else F77_FUNC(flincsp,FLINCSP)(x[0],xprime[0],min_proj[0],&nc,bla1,bla2,blnr,blbnb, blc,blcc,blm,&ir->nProjOrder, md->invmass,r[0],tmp1,tmp2,tmp3); #endif #else clincsp(x,xprime,min_proj,nc,bla1,bla2,blnr,blbnb, blc,blcc,blm,ir->nProjOrder, md->invmass,r,tmp1,tmp2,tmp3); #endif } /* count assuming nit=1 */ inc_nrnb(nrnb,eNR_LINCS,nc); inc_nrnb(nrnb,eNR_LINCSMAT,(2+ir->nProjOrder)*nrtot); } return bOK; }
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; }
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; }