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; }