Task #2595

Reusable Utilities for Schedules

Added by Prashanth Kanduri 4 months ago. Updated 8 days ago.

core library
Target version:


Please refer to #2574 (Schedule Abstraction) and #2594 (GMX API)

The current implementation of do_forcecutsVERLET(...) performs many operation sequences that could serve as reusable utilities in other custom schedule as these would always be executed together.

The other benefit of doing so is to greatly improve code readability in the schedule and thereby encapsulate implementation details for developers assembling a customized schedule. It would also help shrink the lines of code.

Some examples can be:

void initShiftVectors()
    /* Compute shift vectors every step,
     * because of pressure coupling or box deformation!
    if ((flags & GMX_FORCE_DYNAMICBOX) && bStateChanged)
        calc_shifts(box, fr->shift_vec);

    if (bCalcCGCM)
        put_atoms_in_box_omp(fr->ePBC, box, x.subArray(0, homenr));
        inc_nrnb(nrnb, eNR_SHIFTX, homenr);
    else if (EI_ENERGY_MINIMIZATION(inputrec->eI) && graph)
        unshift_self(graph, box, as_rvec_array(;

    nbnxn_atomdata_copy_shiftvec(flags & GMX_FORCE_DYNAMICBOX,
                             fr->shift_vec, nbv->nbat);

It can make use of objects that are pointed by the members of ForceSchedule class.

void doNSGridding()
    if (bNS)
        if (graph && bStateChanged)
 /* Calculate intramolecular shift vectors to make molecules whole */
            mk_mshift(fplog, graph, fr->ePBC, box, as_rvec_array(;

        box_diag[XX] = box[XX][XX];
        box_diag[YY] = box[YY][YY];
        box_diag[ZZ] = box[ZZ][ZZ];

        wallcycle_start(wcycle, ewcNS);
        if (!fr->bDomDec)
            wallcycle_sub_start(wcycle, ewcsNBS_GRID_LOCAL);
            nbnxn_put_on_grid(nbv->nbs, fr->ePBC, box,
                              0, vzero, box_diag,
                              0, mdatoms->homenr, -1, fr->cginfo,
                              0, nullptr,
            wallcycle_sub_stop(wcycle, ewcsNBS_GRID_LOCAL);
            wallcycle_sub_start(wcycle, ewcsNBS_GRID_NONLOCAL);

            nbnxn_put_on_grid_nonlocal(nbv->nbs, domdec_zones(cr->dd), fr->cginfo, as_rvec_array(, nbv->grp[eintNonlocal].kernel_type, nbv->nbat);

            wallcycle_sub_stop(wcycle, ewcsNBS_GRID_NONLOCAL);

        nbnxn_atomdata_set(nbv->nbat, nbv->nbs, mdatoms, fr->cginfo);
        wallcycle_stop(wcycle, ewcNS);


#1 Updated by Prashanth Kanduri 4 months ago

For more details on the Schedule Abstraction:

#2 Updated by Prashanth Kanduri 8 days ago

Another change might be to declare several static functions within sim_util.cpp as non-static functions that can be used to compose more reusable utilities for assembling concrete schedules.

For example, the following functions can be made non-static and new reusable functions can be declared in say, schedule_utils.h:

static void post_process_forces(const t_commrec           *cr,
                                int64_t                    step,
                                t_nrnb                    *nrnb,
                                gmx_wallcycle_t            wcycle,
                                const gmx_localtop_t      *top,
                                const matrix               box,
                                const rvec                 x[],
                                rvec                       f[],
                                gmx::ForceWithVirial      *forceWithVirial,
                                tensor                     vir_force,
                                const t_mdatoms           *mdatoms,
                                const t_graph             *graph,
                                const t_forcerec          *fr,
                                const gmx_vsite_t         *vsite,
                                int                        flags);

static inline void clear_rvecs_omp(int n, rvec v[]);

static void do_nb_verlet(const t_forcerec *fr,
                         const interaction_const_t *ic,
                         gmx_enerdata_t *enerd,
                         int flags, int ilocality,
                         int clearF,
                         int64_t step,
                         t_nrnb *nrnb,
                         gmx_wallcycle_t wcycle);

static void do_nb_verlet_fep(nbnxn_pairlist_set_t *nbl_lists,
                             t_forcerec           *fr,
                             rvec                  x[],
                             rvec                  f[],
                             const t_mdatoms      *mdatoms,
                             t_lambda             *fepvals,
                             real                 *lambda,
                             gmx_enerdata_t       *enerd,
                             int                   flags,
                             t_nrnb               *nrnb,
                             gmx_wallcycle_t       wcycle);

static void calc_virial(int start, int homenr, const rvec x[], const rvec f[],
                        tensor vir_part, const t_graph *graph, const matrix box,
                        t_nrnb *nrnb, const t_forcerec *fr, int ePBC);

static void checkPotentialEnergyValidity(int64_t               step,
                                         const gmx_enerdata_t &enerd,
                                         const t_inputrec     &inputrec);

Also available in: Atom PDF