int relax_shell_flexcon(FILE *fplog, t_commrec *cr, gmx_bool bVerbose, gmx_int64_t mdstep, t_inputrec *inputrec, gmx_bool bDoNS, int force_flags, gmx_localtop_t *top, gmx_constr_t constr, gmx_enerdata_t *enerd, t_fcdata *fcd, t_state *state, rvec f[], tensor force_vir, t_mdatoms *md, t_nrnb *nrnb, gmx_wallcycle_t wcycle, t_graph *graph, gmx_groups_t *groups, struct gmx_shellfc *shfc, t_forcerec *fr, gmx_bool bBornRadii, double t, rvec mu_tot, gmx_bool *bConverged, gmx_vsite_t *vsite, FILE *fp_field) { int nshell; t_shell *shell; t_idef *idef; rvec *pos[2], *force[2], *acc_dir = NULL, *x_old = NULL; real Epot[2], df[2]; rvec dx; real sf_dir, invdt; real ftol, xiH, xiS, dum = 0; char sbuf[22]; gmx_bool bCont, bInit; int nat, dd_ac0, dd_ac1 = 0, i; int start = 0, homenr = md->homenr, end = start+homenr, cg0, cg1; int nflexcon, g, number_steps, d, Min = 0, count = 0; #define Try (1-Min) /* At start Try = 1 */ bCont = (mdstep == inputrec->init_step) && inputrec->bContinuation; bInit = (mdstep == inputrec->init_step) || shfc->bRequireInit; ftol = inputrec->em_tol; number_steps = inputrec->niter; nshell = shfc->nshell; shell = shfc->shell; nflexcon = shfc->nflexcon; idef = &top->idef; if (DOMAINDECOMP(cr)) { nat = dd_natoms_vsite(cr->dd); if (nflexcon > 0) { dd_get_constraint_range(cr->dd, &dd_ac0, &dd_ac1); nat = max(nat, dd_ac1); } } else { nat = state->natoms; } if (nat > shfc->x_nalloc) { /* Allocate local arrays */ shfc->x_nalloc = over_alloc_dd(nat); for (i = 0; (i < 2); i++) { srenew(shfc->x[i], shfc->x_nalloc); srenew(shfc->f[i], shfc->x_nalloc); } } for (i = 0; (i < 2); i++) { pos[i] = shfc->x[i]; force[i] = shfc->f[i]; } /* When we had particle decomposition, this code only worked with * PD when all particles involved with each shell were in the same * charge group. Not sure if this is still relevant. */ if (bDoNS && inputrec->ePBC != epbcNONE && !DOMAINDECOMP(cr)) { /* This is the only time where the coordinates are used * before do_force is called, which normally puts all * charge groups in the box. */ cg0 = 0; cg1 = top->cgs.nr; put_charge_groups_in_box(fplog, cg0, cg1, fr->ePBC, state->box, &(top->cgs), state->x, fr->cg_cm); if (graph) { mk_mshift(fplog, graph, fr->ePBC, state->box, state->x); } } /* After this all coordinate arrays will contain whole molecules */ if (graph) { shift_self(graph, state->box, state->x); } if (nflexcon) { if (nat > shfc->flex_nalloc) { shfc->flex_nalloc = over_alloc_dd(nat); srenew(shfc->acc_dir, shfc->flex_nalloc); srenew(shfc->x_old, shfc->flex_nalloc); } acc_dir = shfc->acc_dir; x_old = shfc->x_old; for (i = 0; i < homenr; i++) { for (d = 0; d < DIM; d++) { shfc->x_old[i][d] = state->x[start+i][d] - state->v[start+i][d]*inputrec->delta_t; } } } /* Do a prediction of the shell positions */ if (shfc->bPredict && !bCont) { predict_shells(fplog, state->x, state->v, inputrec->delta_t, nshell, shell, md->massT, NULL, bInit); } /* do_force expected the charge groups to be in the box */ if (graph) { unshift_self(graph, state->box, state->x); } /* Calculate the forces first time around */ if (gmx_debug_at) { pr_rvecs(debug, 0, "x b4 do_force", state->x + start, homenr); } do_force(fplog, cr, inputrec, mdstep, nrnb, wcycle, top, groups, state->box, state->x, &state->hist, force[Min], force_vir, md, enerd, fcd, state->lambda, graph, fr, vsite, mu_tot, t, fp_field, NULL, bBornRadii, (bDoNS ? GMX_FORCE_NS : 0) | force_flags); sf_dir = 0; if (nflexcon) { init_adir(fplog, shfc, constr, idef, inputrec, cr, dd_ac1, mdstep, md, start, end, shfc->x_old-start, state->x, state->x, force[Min], shfc->acc_dir-start, fr->bMolPBC, state->box, state->lambda, &dum, nrnb); for (i = start; i < end; i++) { sf_dir += md->massT[i]*norm2(shfc->acc_dir[i-start]); } } Epot[Min] = enerd->term[F_EPOT]; df[Min] = rms_force(cr, shfc->f[Min], nshell, shell, nflexcon, &sf_dir, &Epot[Min]); df[Try] = 0; if (debug) { fprintf(debug, "df = %g %g\n", df[Min], df[Try]); } if (gmx_debug_at) { pr_rvecs(debug, 0, "force0", force[Min], md->nr); } if (nshell+nflexcon > 0) { /* Copy x to pos[Min] & pos[Try]: during minimization only the * shell positions are updated, therefore the other particles must * be set here. */ memcpy(pos[Min], state->x, nat*sizeof(state->x[0])); memcpy(pos[Try], state->x, nat*sizeof(state->x[0])); } if (bVerbose && MASTER(cr)) { print_epot(stdout, mdstep, 0, Epot[Min], df[Min], nflexcon, sf_dir); } if (debug) { fprintf(debug, "%17s: %14.10e\n", interaction_function[F_EKIN].longname, enerd->term[F_EKIN]); fprintf(debug, "%17s: %14.10e\n", interaction_function[F_EPOT].longname, enerd->term[F_EPOT]); fprintf(debug, "%17s: %14.10e\n", interaction_function[F_ETOT].longname, enerd->term[F_ETOT]); fprintf(debug, "SHELLSTEP %s\n", gmx_step_str(mdstep, sbuf)); } /* First check whether we should do shells, or whether the force is * low enough even without minimization. */ *bConverged = (df[Min] < ftol); for (count = 1; (!(*bConverged) && (count < number_steps)); count++) { if (vsite) { construct_vsites(vsite, pos[Min], inputrec->delta_t, state->v, idef->iparams, idef->il, fr->ePBC, fr->bMolPBC, cr, state->box); } if (nflexcon) { init_adir(fplog, shfc, constr, idef, inputrec, cr, dd_ac1, mdstep, md, start, end, x_old-start, state->x, pos[Min], force[Min], acc_dir-start, fr->bMolPBC, state->box, state->lambda, &dum, nrnb); directional_sd(pos[Min], pos[Try], acc_dir-start, start, end, fr->fc_stepsize); } /* New positions, Steepest descent */ shell_pos_sd(pos[Min], pos[Try], force[Min], nshell, shell, count); /* do_force expected the charge groups to be in the box */ if (graph) { unshift_self(graph, state->box, pos[Try]); } if (gmx_debug_at) { pr_rvecs(debug, 0, "RELAX: pos[Min] ", pos[Min] + start, homenr); pr_rvecs(debug, 0, "RELAX: pos[Try] ", pos[Try] + start, homenr); } /* Try the new positions */ do_force(fplog, cr, inputrec, 1, nrnb, wcycle, top, groups, state->box, pos[Try], &state->hist, force[Try], force_vir, md, enerd, fcd, state->lambda, graph, fr, vsite, mu_tot, t, fp_field, NULL, bBornRadii, force_flags); if (gmx_debug_at) { pr_rvecs(debug, 0, "RELAX: force[Min]", force[Min] + start, homenr); pr_rvecs(debug, 0, "RELAX: force[Try]", force[Try] + start, homenr); } sf_dir = 0; if (nflexcon) { init_adir(fplog, shfc, constr, idef, inputrec, cr, dd_ac1, mdstep, md, start, end, x_old-start, state->x, pos[Try], force[Try], acc_dir-start, fr->bMolPBC, state->box, state->lambda, &dum, nrnb); for (i = start; i < end; i++) { sf_dir += md->massT[i]*norm2(acc_dir[i-start]); } } Epot[Try] = enerd->term[F_EPOT]; df[Try] = rms_force(cr, force[Try], nshell, shell, nflexcon, &sf_dir, &Epot[Try]); if (debug) { fprintf(debug, "df = %g %g\n", df[Min], df[Try]); } if (debug) { if (gmx_debug_at) { pr_rvecs(debug, 0, "F na do_force", force[Try] + start, homenr); } if (gmx_debug_at) { fprintf(debug, "SHELL ITER %d\n", count); dump_shells(debug, pos[Try], force[Try], ftol, nshell, shell); } } if (bVerbose && MASTER(cr)) { print_epot(stdout, mdstep, count, Epot[Try], df[Try], nflexcon, sf_dir); } *bConverged = (df[Try] < ftol); if ((df[Try] < df[Min])) { if (debug) { fprintf(debug, "Swapping Min and Try\n"); } if (nflexcon) { /* Correct the velocities for the flexible constraints */ invdt = 1/inputrec->delta_t; for (i = start; i < end; i++) { for (d = 0; d < DIM; d++) { state->v[i][d] += (pos[Try][i][d] - pos[Min][i][d])*invdt; } } } Min = Try; } else { decrease_step_size(nshell, shell); } } if (MASTER(cr) && !(*bConverged)) { /* Note that the energies and virial are incorrect when not converged */ if (fplog) { fprintf(fplog, "step %s: EM did not converge in %d iterations, RMS force %.3f\n", gmx_step_str(mdstep, sbuf), number_steps, df[Min]); } fprintf(stderr, "step %s: EM did not converge in %d iterations, RMS force %.3f\n", gmx_step_str(mdstep, sbuf), number_steps, df[Min]); } /* Copy back the coordinates and the forces */ memcpy(state->x, pos[Min], nat*sizeof(state->x[0])); memcpy(f, force[Min], nat*sizeof(f[0])); return count; }
double do_md_openmm(FILE *fplog,t_commrec *cr,int nfile,const t_filenm fnm[], const output_env_t oenv, gmx_bool bVerbose,gmx_bool bCompact, int nstglobalcomm, gmx_vsite_t *vsite,gmx_constr_t constr, int stepout,t_inputrec *ir, gmx_mtop_t *top_global, t_fcdata *fcd, t_state *state_global, t_mdatoms *mdatoms, t_nrnb *nrnb,gmx_wallcycle_t wcycle, gmx_edsam_t ed,t_forcerec *fr, int repl_ex_nst,int repl_ex_seed, real cpt_period,real max_hours, const char *deviceOptions, unsigned long Flags, gmx_runtime_t *runtime) { gmx_mdoutf_t *outf; gmx_large_int_t step,step_rel; double run_time; double t,t0,lam0; gmx_bool bSimAnn, bFirstStep,bStateFromTPX,bLastStep,bStartingFromCpt; gmx_bool bInitStep=TRUE; gmx_bool do_ene,do_log, do_verbose, bX,bV,bF,bCPT; tensor force_vir,shake_vir,total_vir,pres; int i,m; int mdof_flags; rvec mu_tot; t_vcm *vcm; int nchkpt=1; gmx_localtop_t *top; t_mdebin *mdebin=NULL; t_state *state=NULL; rvec *f_global=NULL; int n_xtc=-1; rvec *x_xtc=NULL; gmx_enerdata_t *enerd; rvec *f=NULL; gmx_global_stat_t gstat; gmx_update_t upd=NULL; t_graph *graph=NULL; globsig_t gs; gmx_groups_t *groups; gmx_ekindata_t *ekind, *ekind_save; gmx_bool bAppend; int a0,a1; matrix lastbox; real reset_counters=0,reset_counters_now=0; char sbuf[STEPSTRSIZE],sbuf2[STEPSTRSIZE]; int handled_stop_condition=gmx_stop_cond_none; const char *ommOptions = NULL; void *openmmData; bAppend = (Flags & MD_APPENDFILES); check_ir_old_tpx_versions(cr,fplog,ir,top_global); groups = &top_global->groups; /* Initial values */ init_md(fplog,cr,ir,oenv,&t,&t0,&state_global->lambda,&lam0, nrnb,top_global,&upd, nfile,fnm,&outf,&mdebin, force_vir,shake_vir,mu_tot,&bSimAnn,&vcm,state_global,Flags); clear_mat(total_vir); clear_mat(pres); /* Energy terms and groups */ snew(enerd,1); init_enerdata(top_global->groups.grps[egcENER].nr,ir->n_flambda,enerd); snew(f,top_global->natoms); /* Kinetic energy data */ snew(ekind,1); init_ekindata(fplog,top_global,&(ir->opts),ekind); /* needed for iteration of constraints */ snew(ekind_save,1); init_ekindata(fplog,top_global,&(ir->opts),ekind_save); /* Copy the cos acceleration to the groups struct */ ekind->cosacc.cos_accel = ir->cos_accel; gstat = global_stat_init(ir); debug_gmx(); { double io = compute_io(ir,top_global->natoms,groups,mdebin->ebin->nener,1); if ((io > 2000) && MASTER(cr)) fprintf(stderr, "\nWARNING: This run will generate roughly %.0f Mb of data\n\n", io); } top = gmx_mtop_generate_local_top(top_global,ir); a0 = 0; a1 = top_global->natoms; state = partdec_init_local_state(cr,state_global); f_global = f; atoms2md(top_global,ir,0,NULL,a0,a1-a0,mdatoms); if (vsite) { set_vsite_top(vsite,top,mdatoms,cr); } if (ir->ePBC != epbcNONE && !ir->bPeriodicMols) { graph = mk_graph(fplog,&(top->idef),0,top_global->natoms,FALSE,FALSE); } update_mdatoms(mdatoms,state->lambda); if (deviceOptions[0]=='\0') { /* empty options, which should default to OpenMM in this build */ ommOptions=deviceOptions; } else { if (gmx_strncasecmp(deviceOptions,"OpenMM",6)!=0) { gmx_fatal(FARGS, "This Gromacs version currently only works with OpenMM. Use -device \"OpenMM:<options>\""); } else { ommOptions=strchr(deviceOptions,':'); if (NULL!=ommOptions) { /* Increase the pointer to skip the colon */ ommOptions++; } } } openmmData = openmm_init(fplog, ommOptions, ir, top_global, top, mdatoms, fr, state); please_cite(fplog,"Friedrichs2009"); if (MASTER(cr)) { /* Update mdebin with energy history if appending to output files */ if ( Flags & MD_APPENDFILES ) { restore_energyhistory_from_state(mdebin,&state_global->enerhist); } /* Set the initial energy history in state to zero by updating once */ update_energyhistory(&state_global->enerhist,mdebin); } if (constr) { set_constraints(constr,top,ir,mdatoms,cr); } if (!ir->bContinuation) { if (mdatoms->cFREEZE && (state->flags & (1<<estV))) { /* Set the velocities of frozen particles to zero */ for (i=mdatoms->start; i<mdatoms->start+mdatoms->homenr; i++) { for (m=0; m<DIM; m++) { if (ir->opts.nFreeze[mdatoms->cFREEZE[i]][m]) { state->v[i][m] = 0; } } } } if (constr) { /* Constrain the initial coordinates and velocities */ do_constrain_first(fplog,constr,ir,mdatoms,state,f, graph,cr,nrnb,fr,top,shake_vir); } if (vsite) { /* Construct the virtual sites for the initial configuration */ construct_vsites(fplog,vsite,state->x,nrnb,ir->delta_t,NULL, top->idef.iparams,top->idef.il, fr->ePBC,fr->bMolPBC,graph,cr,state->box); } } debug_gmx(); if (MASTER(cr)) { char tbuf[20]; fprintf(fplog,"Initial temperature: %g K\n",enerd->term[F_TEMP]); fprintf(stderr,"starting mdrun '%s'\n", *(top_global->name)); if (ir->nsteps >= 0) { sprintf(tbuf,"%8.1f",(ir->init_step+ir->nsteps)*ir->delta_t); } else { sprintf(tbuf,"%s","infinite"); } if (ir->init_step > 0) { fprintf(stderr,"%s steps, %s ps (continuing from step %s, %8.1f ps).\n", gmx_step_str(ir->init_step+ir->nsteps,sbuf),tbuf, gmx_step_str(ir->init_step,sbuf2), ir->init_step*ir->delta_t); } else { fprintf(stderr,"%s steps, %s ps.\n", gmx_step_str(ir->nsteps,sbuf),tbuf); } } fprintf(fplog,"\n"); /* Set and write start time */ runtime_start(runtime); print_date_and_time(fplog,cr->nodeid,"Started mdrun",runtime); wallcycle_start(wcycle,ewcRUN); if (fplog) fprintf(fplog,"\n"); /* safest point to do file checkpointing is here. More general point would be immediately before integrator call */ debug_gmx(); /*********************************************************** * * Loop over MD steps * ************************************************************/ /* loop over MD steps or if rerunMD to end of input trajectory */ bFirstStep = TRUE; /* Skip the first Nose-Hoover integration when we get the state from tpx */ bStateFromTPX = !opt2bSet("-cpi",nfile,fnm); bInitStep = bFirstStep && bStateFromTPX; bStartingFromCpt = (Flags & MD_STARTFROMCPT) && bInitStep; bLastStep = FALSE; init_global_signals(&gs,cr,ir,repl_ex_nst); step = ir->init_step; step_rel = 0; while (!bLastStep) { wallcycle_start(wcycle,ewcSTEP); GMX_MPE_LOG(ev_timestep1); bLastStep = (step_rel == ir->nsteps); t = t0 + step*ir->delta_t; if (gs.set[eglsSTOPCOND] != 0) { bLastStep = TRUE; } do_log = do_per_step(step,ir->nstlog) || bFirstStep || bLastStep; do_verbose = bVerbose && (step % stepout == 0 || bFirstStep || bLastStep); if (MASTER(cr) && do_log) { print_ebin_header(fplog,step,t,state->lambda); } clear_mat(force_vir); GMX_MPE_LOG(ev_timestep2); /* We write a checkpoint at this MD step when: * either when we signalled through gs (in OpenMM NS works different), * or at the last step (but not when we do not want confout), * but never at the first step. */ bCPT = ((gs.set[eglsCHKPT] || (bLastStep && (Flags & MD_CONFOUT))) && step > ir->init_step ); if (bCPT) { gs.set[eglsCHKPT] = 0; } /* Now we have the energies and forces corresponding to the * coordinates at time t. We must output all of this before * the update. * for RerunMD t is read from input trajectory */ GMX_MPE_LOG(ev_output_start); mdof_flags = 0; if (do_per_step(step,ir->nstxout)) { mdof_flags |= MDOF_X; } if (do_per_step(step,ir->nstvout)) { mdof_flags |= MDOF_V; } if (do_per_step(step,ir->nstfout)) { mdof_flags |= MDOF_F; } if (do_per_step(step,ir->nstxtcout)) { mdof_flags |= MDOF_XTC; } if (bCPT) { mdof_flags |= MDOF_CPT; }; do_ene = (do_per_step(step,ir->nstenergy) || bLastStep); if (mdof_flags != 0 || do_ene || do_log) { wallcycle_start(wcycle,ewcTRAJ); bF = (mdof_flags & MDOF_F); bX = (mdof_flags & (MDOF_X | MDOF_XTC | MDOF_CPT)); bV = (mdof_flags & (MDOF_V | MDOF_CPT)); openmm_copy_state(openmmData, state, &t, f, enerd, bX, bV, bF, do_ene); upd_mdebin(mdebin, FALSE,TRUE, t,mdatoms->tmass,enerd,state,lastbox, shake_vir,force_vir,total_vir,pres, ekind,mu_tot,constr); print_ebin(outf->fp_ene,do_ene,FALSE,FALSE,do_log?fplog:NULL, step,t, eprNORMAL,bCompact,mdebin,fcd,groups,&(ir->opts)); write_traj(fplog,cr,outf,mdof_flags,top_global, step,t,state,state_global,f,f_global,&n_xtc,&x_xtc); if (bCPT) { nchkpt++; bCPT = FALSE; } debug_gmx(); if (bLastStep && step_rel == ir->nsteps && (Flags & MD_CONFOUT) && MASTER(cr)) { /* x and v have been collected in write_traj, * because a checkpoint file will always be written * at the last step. */ fprintf(stderr,"\nWriting final coordinates.\n"); if (ir->ePBC != epbcNONE && !ir->bPeriodicMols) { /* Make molecules whole only for confout writing */ do_pbc_mtop(fplog,ir->ePBC,state->box,top_global,state_global->x); } write_sto_conf_mtop(ftp2fn(efSTO,nfile,fnm), *top_global->name,top_global, state_global->x,state_global->v, ir->ePBC,state->box); debug_gmx(); } wallcycle_stop(wcycle,ewcTRAJ); } GMX_MPE_LOG(ev_output_finish); /* Determine the wallclock run time up till now */ run_time = gmx_gettime() - (double)runtime->real; /* Check whether everything is still allright */ if (((int)gmx_get_stop_condition() > handled_stop_condition) #ifdef GMX_THREADS && MASTER(cr) #endif ) { /* this is just make gs.sig compatible with the hack of sending signals around by MPI_Reduce with together with other floats */ /* NOTE: this only works for serial code. For code that allows MPI nodes to propagate their condition, see kernel/md.c*/ if ( gmx_get_stop_condition() == gmx_stop_cond_next_ns ) gs.set[eglsSTOPCOND]=1; if ( gmx_get_stop_condition() == gmx_stop_cond_next ) gs.set[eglsSTOPCOND]=1; /* < 0 means stop at next step, > 0 means stop at next NS step */ if (fplog) { fprintf(fplog, "\n\nReceived the %s signal, stopping at the next %sstep\n\n", gmx_get_signal_name(), gs.sig[eglsSTOPCOND]==1 ? "NS " : ""); fflush(fplog); } fprintf(stderr, "\n\nReceived the %s signal, stopping at the next %sstep\n\n", gmx_get_signal_name(), gs.sig[eglsSTOPCOND]==1 ? "NS " : ""); fflush(stderr); handled_stop_condition=(int)gmx_get_stop_condition(); } else if (MASTER(cr) && (max_hours > 0 && run_time > max_hours*60.0*60.0*0.99) && gs.set[eglsSTOPCOND] == 0) { /* Signal to terminate the run */ gs.set[eglsSTOPCOND] = 1; if (fplog) { fprintf(fplog,"\nStep %s: Run time exceeded %.3f hours, will terminate the run\n",gmx_step_str(step,sbuf),max_hours*0.99); } fprintf(stderr, "\nStep %s: Run time exceeded %.3f hours, will terminate the run\n",gmx_step_str(step,sbuf),max_hours*0.99); } /* checkpoints */ if (MASTER(cr) && (cpt_period >= 0 && (cpt_period == 0 || run_time >= nchkpt*cpt_period*60.0)) && gs.set[eglsCHKPT] == 0) { gs.set[eglsCHKPT] = 1; } /* Time for performance */ if (((step % stepout) == 0) || bLastStep) { runtime_upd_proc(runtime); } if (do_per_step(step,ir->nstlog)) { if (fflush(fplog) != 0) { gmx_fatal(FARGS,"Cannot flush logfile - maybe you are out of quota?"); } } /* Remaining runtime */ if (MULTIMASTER(cr) && (do_verbose || gmx_got_usr_signal() )) { print_time(stderr,runtime,step,ir,cr); } bFirstStep = FALSE; bInitStep = FALSE; bStartingFromCpt = FALSE; step++; step_rel++; openmm_take_one_step(openmmData); } /* End of main MD loop */ debug_gmx(); /* Stop the time */ runtime_end(runtime); if (MASTER(cr)) { if (ir->nstcalcenergy > 0) { print_ebin(outf->fp_ene,FALSE,FALSE,FALSE,fplog,step,t, eprAVER,FALSE,mdebin,fcd,groups,&(ir->opts)); } } openmm_cleanup(fplog, openmmData); done_mdoutf(outf); debug_gmx(); runtime->nsteps_done = step_rel; return 0; }