void do_pbc_first(FILE *fplog,matrix box,t_forcerec *fr, t_graph *graph,rvec x[]) { if (fplog) fprintf(fplog,"Removing pbc first time\n"); calc_shifts(box,fr->shift_vec); if (graph) { mk_mshift(fplog,graph,fr->ePBC,box,x); if (gmx_debug_at) p_graph(debug,"do_pbc_first 1",graph); shift_self(graph,box,x); /* By doing an extra mk_mshift the molecules that are broken * because they were e.g. imported from another software * will be made whole again. Such are the healing powers * of GROMACS. */ mk_mshift(fplog,graph,fr->ePBC,box,x); if (gmx_debug_at) p_graph(debug,"do_pbc_first 2",graph); } if (fplog) fprintf(fplog,"Done rmpbc\n"); }
void mk_graph_ilist(FILE *fplog, const t_ilist *ilist, int at_start, int at_end, gmx_bool bShakeOnly, gmx_bool bSettle, t_graph *g) { int *nbond; int i, nbtot; gmx_bool bMultiPart; /* The naming is somewhat confusing, but we need g->at0 and g->at1 * for shifthing coordinates to a new array (not in place) when * some atoms are not connected by the graph, which runs from * g->at_start (>= g->at0) to g->at_end (<= g->at1). */ g->at0 = at_start; g->at1 = at_end; snew(nbond, at_end); nbtot = calc_start_end(fplog, g, ilist, at_start, at_end, nbond); if (g->at_start >= g->at_end) { g->at_start = at_start; g->at_end = at_end; g->nnodes = 0; g->nbound = 0; } else { g->nnodes = g->at_end - g->at_start; snew(g->nedge, g->nnodes); snew(g->edge, g->nnodes); /* Allocate a single array and set pointers into it */ snew(g->edge[0], nbtot); for (i = 1; (i < g->nnodes); i++) { g->edge[i] = g->edge[i-1] + nbond[g->at_start+i-1]; } if (!bShakeOnly) { /* First add all the real bonds: they should determine the molecular * graph. */ for (i = 0; (i < F_NRE); i++) { if (interaction_function[i].flags & IF_CHEMBOND) { mk_igraph(g, i, &(ilist[i]), at_start, at_end, NULL); } } /* Determine of which separated parts the IF_CHEMBOND graph consists. * Store the parts in the nbond array. */ bMultiPart = determine_graph_parts(g, nbond); if (bMultiPart) { /* Then add all the other interactions in fixed lists, * but only when they connect parts of the graph * that are not connected through IF_CHEMBOND interactions. */ for (i = 0; (i < F_NRE); i++) { if (!(interaction_function[i].flags & IF_CHEMBOND)) { mk_igraph(g, i, &(ilist[i]), at_start, at_end, nbond); } } } /* Removed all the unused space from the edge array */ compact_graph(fplog, g); } else { /* This is a special thing used in splitter.c to generate shake-blocks */ mk_igraph(g, F_CONSTR, &(ilist[F_CONSTR]), at_start, at_end, NULL); if (bSettle) { mk_igraph(g, F_SETTLE, &(ilist[F_SETTLE]), at_start, at_end, NULL); } } g->nbound = 0; for (i = 0; (i < g->nnodes); i++) { if (g->nedge[i] > 0) { g->nbound++; } } } g->negc = 0; g->egc = NULL; sfree(nbond); snew(g->ishift, g->at1); if (gmx_debug_at) { p_graph(debug, "graph", g); } }
void calc_listed(const gmx_multisim_t *ms, gmx_wallcycle *wcycle, const t_idef *idef, const rvec x[], history_t *hist, rvec f[], t_forcerec *fr, const struct t_pbc *pbc, const struct t_pbc *pbc_full, const struct t_graph *g, gmx_enerdata_t *enerd, t_nrnb *nrnb, real *lambda, const t_mdatoms *md, t_fcdata *fcd, int *global_atom_index, int force_flags) { gmx_bool bCalcEnerVir; int i; real dvdl[efptNR]; /* The dummy array is to have a place to store the dhdl at other values of lambda, which will be thrown away in the end*/ const t_pbc *pbc_null; int thread; assert(fr->nthreads == idef->nthreads); bCalcEnerVir = (force_flags & (GMX_FORCE_VIRIAL | GMX_FORCE_ENERGY)); for (i = 0; i < efptNR; i++) { dvdl[i] = 0.0; } if (fr->bMolPBC) { pbc_null = pbc; } else { pbc_null = NULL; } #ifdef DEBUG if (g && debug) { p_graph(debug, "Bondage is fun", g); } #endif if ((idef->il[F_POSRES].nr > 0) || (idef->il[F_FBPOSRES].nr > 0) || (idef->il[F_ORIRES].nr > 0) || (idef->il[F_DISRES].nr > 0)) { /* TODO Use of restraints triggers further function calls inside the loop over calc_one_bond(), but those are too awkward to account to this subtimer properly in the present code. We don't test / care much about performance with restraints, anyway. */ wallcycle_sub_start(wcycle, ewcsRESTRAINTS); if (idef->il[F_POSRES].nr > 0) { posres_wrapper(nrnb, idef, pbc_full, x, enerd, lambda, fr); } if (idef->il[F_FBPOSRES].nr > 0) { fbposres_wrapper(nrnb, idef, pbc_full, x, enerd, fr); } /* Do pre force calculation stuff which might require communication */ if (idef->il[F_ORIRES].nr > 0) { enerd->term[F_ORIRESDEV] = calc_orires_dev(ms, idef->il[F_ORIRES].nr, idef->il[F_ORIRES].iatoms, idef->iparams, md, x, pbc_null, fcd, hist); } if (idef->il[F_DISRES].nr) { calc_disres_R_6(idef->il[F_DISRES].nr, idef->il[F_DISRES].iatoms, idef->iparams, x, pbc_null, fcd, hist); #ifdef GMX_MPI if (fcd->disres.nsystems > 1) { gmx_sum_sim(2*fcd->disres.nres, fcd->disres.Rt_6, ms); } #endif } wallcycle_sub_stop(wcycle, ewcsRESTRAINTS); } wallcycle_sub_start(wcycle, ewcsLISTED); #pragma omp parallel for num_threads(fr->nthreads) schedule(static) for (thread = 0; thread < fr->nthreads; thread++) { int ftype; real *epot, v; /* thread stuff */ rvec *ft, *fshift; real *dvdlt; gmx_grppairener_t *grpp; if (thread == 0) { ft = f; fshift = fr->fshift; epot = enerd->term; grpp = &enerd->grpp; dvdlt = dvdl; } else { zero_thread_forces(&fr->f_t[thread], fr->natoms_force, fr->red_nblock, 1<<fr->red_ashift); ft = fr->f_t[thread].f; fshift = fr->f_t[thread].fshift; epot = fr->f_t[thread].ener; grpp = &fr->f_t[thread].grpp; dvdlt = fr->f_t[thread].dvdl; } /* Loop over all bonded force types to calculate the bonded forces */ for (ftype = 0; (ftype < F_NRE); ftype++) { if (idef->il[ftype].nr > 0 && ftype_is_bonded_potential(ftype)) { v = calc_one_bond(thread, ftype, idef, x, ft, fshift, fr, pbc_null, g, grpp, nrnb, lambda, dvdlt, md, fcd, bCalcEnerVir, global_atom_index); epot[ftype] += v; } } } wallcycle_sub_stop(wcycle, ewcsLISTED); if (fr->nthreads > 1) { wallcycle_sub_start(wcycle, ewcsLISTED_BUF_OPS); reduce_thread_forces(fr->natoms_force, f, fr->fshift, enerd->term, &enerd->grpp, dvdl, fr->nthreads, fr->f_t, fr->red_nblock, 1<<fr->red_ashift, bCalcEnerVir, force_flags & GMX_FORCE_DHDL); wallcycle_sub_stop(wcycle, ewcsLISTED_BUF_OPS); } /* Remaining code does not have enough flops to bother counting */ if (force_flags & GMX_FORCE_DHDL) { for (i = 0; i < efptNR; i++) { enerd->dvdl_nonlin[i] += dvdl[i]; } } /* Copy the sum of violations for the distance restraints from fcd */ if (fcd) { enerd->term[F_DISRESVIOL] = fcd->disres.sumviol; } }
void gen_sblocks(FILE *fp, int at_start, int at_end, t_idef *idef, t_blocka *sblock, gmx_bool bSettle) { t_graph *g; int i, i0, j, k, istart, n; t_sid *sid; int isid, nsid; g = mk_graph(NULL, idef, at_start, at_end, TRUE, bSettle); if (debug) { p_graph(debug, "Graaf Dracula", g); } snew(sid, at_end); for (i = at_start; (i < at_end); i++) { sid[i].atom = i; sid[i].sid = -1; } nsid = mk_sblocks(fp, g, at_end, sid); if (!nsid) { return; } /* Now sort the shake blocks... */ qsort(sid+at_start, at_end-at_start, (size_t)sizeof(sid[0]), sid_comp); if (debug) { fprintf(debug, "Sorted shake block\n"); for (i = at_start; (i < at_end); i++) { fprintf(debug, "sid[%5d] = atom:%5d sid:%5d\n", i, sid[i].atom, sid[i].sid); } } /* Now check how many are NOT -1, i.e. how many have to be shaken */ for (i0 = at_start; (i0 < at_end); i0++) { if (sid[i0].sid > -1) { break; } } /* Now we have the sids that have to be shaken. We'll check the min and * max atom numbers and this determines the shake block. DvdS 2007-07-19. * For the purpose of making boundaries all atoms in between need to be * part of the shake block too. There may be cases where blocks overlap * and they will have to be merged. */ nsid = merge_sid(at_start, at_end, nsid, sid, sblock); /* Now sort the shake blocks again... */ /*qsort(sid,natoms,(size_t)sizeof(sid[0]),sid_comp);*/ /* Fill the sblock struct */ /* sblock->nr = nsid; sblock->nra = natoms; srenew(sblock->a,sblock->nra); srenew(sblock->index,sblock->nr+1); i = i0; isid = sid[i].sid; n = k = 0; sblock->index[n++]=k; while (i < natoms) { istart = sid[i].atom; while ((i<natoms-1) && (sid[i+1].sid == isid)) i++;*/ /* After while: we found a new block, or are thru with the atoms */ /* for(j=istart; (j<=sid[i].atom); j++,k++) sblock->a[k]=j; sblock->index[n] = k; if (i < natoms-1) n++; if (n > nsid) gmx_fatal(FARGS,"Death Horror: nsid = %d, n= %d",nsid,n); i++; isid = sid[i].sid; } */ sfree(sid); /* Due to unknown reason this free generates a problem sometimes */ done_graph(g); sfree(g); if (debug) { fprintf(debug, "Done gen_sblocks\n"); } }
void force(FILE *fp, int step, t_forcerec *fr, t_inputrec *ir, t_idef *idef, t_nsborder *nsb, t_commrec *cr, t_commrec *mcr, t_nrnb *nrnb, t_groups *grps, t_mdatoms *md, int ngener, t_grpopts *opts, rvec x[], rvec f[], real epot[], t_fcdata *fcd, bool bVerbose, matrix box, real lambda, t_graph *graph, t_block *excl, bool bNBFonly, matrix lr_vir, rvec mu_tot, real qsum, bool bGatherOnly) { int i,nit; bool bDoEpot; rvec box_size; real Vlr,Vcorr=0; /* Reset box */ for(i=0; (i<DIM); i++) box_size[i]=box[i][i]; bDoEpot=((fr->nmol > 0) && (fr->nstcalc > 0) && (mod(step,fr->nstcalc)==0)); /* Reset epot... */ if (bDoEpot) for(i=0; (i<fr->nmol); i++) fr->mol_epot[i]=0.0; debug_gmx(); /* Call the short range functions all in one go. */ do_fnbf(fp,cr,fr,x,f,md, fr->bBHAM ? grps->estat.ee[egBHAM] : grps->estat.ee[egLJ], grps->estat.ee[egCOUL],box_size,nrnb, lambda,&epot[F_DVDL],FALSE,-1); debug_gmx(); if (debug) pr_rvecs(debug,0,"fshift after SR",fr->fshift,SHIFTS); /* Shift the coordinates. Must be done before bonded forces and PPPM, * but is also necessary for SHAKE and update, therefore it can NOT * go when no bonded forces have to be evaluated. */ if (debug && 0) p_graph(debug,"DeBUGGGG",graph); /* Check whether we need to do bondeds */ if (!bNBFonly) { shift_self(graph,box,x); if (debug && 0) { fprintf(debug,"BBBBBBBBBBBBBBBB\n"); fprintf(debug,"%5d\n",graph->nnodes); for(i=graph->start; (i<=graph->end); i++) fprintf(debug,"%5d%5s%5s%5d%8.3f%8.3f%8.3f\n", i,"A","B",i,x[i][XX],x[i][YY],x[i][ZZ]); fprintf(debug,"%10.5f%10.5f%10.5f\n", box[XX][XX],box[YY][YY],box[ZZ][ZZ]); } if (TRICLINIC(box)) inc_nrnb(nrnb,eNR_SHIFTX,2*graph->nnodes); else inc_nrnb(nrnb,eNR_SHIFTX,graph->nnodes); debug_gmx(); } if (EEL_LR(fr->eeltype)) { switch (fr->eeltype) { case eelPPPM: Vlr = do_pppm(fp,FALSE,x,fr->f_pme,md->chargeT, box_size,fr->phi,cr,nsb,nrnb); break; case eelPOISSON: Vlr = do_poisson(fp,FALSE,ir,md->nr,x,fr->f_pme,md->chargeT, box_size,fr->phi,cr,nrnb,&nit,TRUE); break; case eelPME: Vlr = do_pme(fp,FALSE,ir,x,fr->f_pme,md->chargeT, box,cr,nsb,nrnb,lr_vir,fr->ewaldcoeff,bGatherOnly); break; case eelEWALD: Vlr = do_ewald(fp,FALSE,ir,x,fr->f_pme,md->chargeT, box_size,cr,nsb,lr_vir,fr->ewaldcoeff); break; default: Vlr = 0; fatal_error(0,"No such electrostatics method implemented %s", eel_names[fr->eeltype]); } if(fr->bEwald) Vcorr = ewald_LRcorrection(fp,nsb,cr,fr,md->chargeT,excl,x,box,mu_tot,qsum, ir->ewald_geometry,ir->epsilon_surface,lr_vir); else Vcorr = shift_LRcorrection(fp,nsb,cr,fr,md->chargeT,excl,x,TRUE,box,lr_vir); epot[F_LR] = Vlr + Vcorr; if (debug) fprintf(debug,"Vlr = %g, Vcorr = %g, Vlr_corr = %g\n", Vlr,Vcorr,epot[F_LR]); if (debug) { pr_rvecs(debug,0,"lr_vir after corr",lr_vir,DIM); pr_rvecs(debug,0,"fshift after LR Corrections",fr->fshift,SHIFTS); } } debug_gmx(); if (debug) print_nrnb(debug,nrnb); debug_gmx(); if (!bNBFonly) { calc_bonds(fp,cr,mcr, idef,x,f,fr,graph,epot,nrnb,box,lambda,md, opts->ngener,grps->estat.ee[egLJ14],grps->estat.ee[egCOUL14], fcd,step,fr->bSepDVDL && do_per_step(step,ir->nstlog)); debug_gmx(); } if (debug) pr_rvecs(debug,0,"fshift after bondeds",fr->fshift,SHIFTS); for(i=0; (i<F_EPOT); i++) if (i != F_DISRES) epot[F_EPOT]+=epot[i]; }