Refactor gmx_group_t to SimulationAtomGroups
[alexxy/gromacs.git] / src / gromacs / mdlib / energyoutput.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5  * Copyright (c) 2001-2004, The GROMACS development team.
6  * Copyright (c) 2013,2014,2015,2016,2017,2018,2019, by the GROMACS development team, led by
7  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
8  * and including many others, as listed in the AUTHORS file in the
9  * top-level source directory and at http://www.gromacs.org.
10  *
11  * GROMACS is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public License
13  * as published by the Free Software Foundation; either version 2.1
14  * of the License, or (at your option) any later version.
15  *
16  * GROMACS is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with GROMACS; if not, see
23  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
24  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
25  *
26  * If you want to redistribute modifications to GROMACS, please
27  * consider that scientific software is very special. Version
28  * control is crucial - bugs must be traceable. We will be happy to
29  * consider code for inclusion in the official distribution, but
30  * derived work must not be called official GROMACS. Details are found
31  * in the README & COPYING files - if they are missing, get the
32  * official version at http://www.gromacs.org.
33  *
34  * To help us fund GROMACS development, we humbly ask that you cite
35  * the research papers on the package. Check out http://www.gromacs.org.
36  */
37 #include "gmxpre.h"
38
39 #include "energyoutput.h"
40
41 #include <cfloat>
42 #include <cstdlib>
43 #include <cstring>
44
45 #include <string>
46
47 #include "gromacs/awh/awh.h"
48 #include "gromacs/fileio/enxio.h"
49 #include "gromacs/fileio/gmxfio.h"
50 #include "gromacs/fileio/xvgr.h"
51 #include "gromacs/gmxlib/network.h"
52 #include "gromacs/listed_forces/disre.h"
53 #include "gromacs/listed_forces/orires.h"
54 #include "gromacs/math/functions.h"
55 #include "gromacs/math/units.h"
56 #include "gromacs/math/vec.h"
57 #include "gromacs/mdlib/constr.h"
58 #include "gromacs/mdlib/ebin.h"
59 #include "gromacs/mdlib/mdebin_bar.h"
60 #include "gromacs/mdtypes/energyhistory.h"
61 #include "gromacs/mdtypes/fcdata.h"
62 #include "gromacs/mdtypes/group.h"
63 #include "gromacs/mdtypes/inputrec.h"
64 #include "gromacs/mdtypes/md_enums.h"
65 #include "gromacs/mdtypes/state.h"
66 #include "gromacs/pbcutil/pbc.h"
67 #include "gromacs/pulling/pull.h"
68 #include "gromacs/topology/mtop_util.h"
69 #include "gromacs/trajectory/energyframe.h"
70 #include "gromacs/utility/arraysize.h"
71 #include "gromacs/utility/fatalerror.h"
72 #include "gromacs/utility/smalloc.h"
73 #include "gromacs/utility/stringutil.h"
74
75 static const char *conrmsd_nm[] = { "Constr. rmsd", "Constr.2 rmsd" };
76
77 static const char *boxs_nm[] = { "Box-X", "Box-Y", "Box-Z" };
78
79 static const char *tricl_boxs_nm[] = {
80     "Box-XX", "Box-YY", "Box-ZZ",
81     "Box-YX", "Box-ZX", "Box-ZY"
82 };
83
84 static const char *vol_nm[] = { "Volume" };
85
86 static const char *dens_nm[] = {"Density" };
87
88 static const char *pv_nm[] = {"pV" };
89
90 static const char *enthalpy_nm[] = {"Enthalpy" };
91
92 static const char *boxvel_nm[] = {
93     "Box-Vel-XX", "Box-Vel-YY", "Box-Vel-ZZ",
94     "Box-Vel-YX", "Box-Vel-ZX", "Box-Vel-ZY"
95 };
96
97 #define NBOXS asize(boxs_nm)
98 #define NTRICLBOXS asize(tricl_boxs_nm)
99
100 const char *egrp_nm[egNR+1] = {
101     "Coul-SR", "LJ-SR", "Buck-SR",
102     "Coul-14", "LJ-14", nullptr
103 };
104
105 /* forward declaration */
106 typedef struct t_mde_delta_h_coll t_mde_delta_h_coll;
107
108 namespace gmx
109 {
110
111 namespace detail
112 {
113
114 /* This is the collection of energy averages collected during mdrun, and to
115    be written out to the .edr file. */
116 struct t_mdebin
117 {
118     double              delta_t;
119     t_ebin             *ebin;
120     int                 ie, iconrmsd, ib, ivol, idens, ipv, ienthalpy;
121     int                 isvir, ifvir, ipres, ivir, isurft, ipc, itemp, itc, itcb, iu, imu;
122     int                 ivcos, ivisc;
123     int                 nE, nEg, nEc, nTC, nTCP, nU, nNHC;
124     int                *igrp;
125     int                 mde_n, mdeb_n;
126     real               *tmp_r;
127     rvec               *tmp_v;
128     gmx_bool            bConstr;
129     gmx_bool            bConstrVir;
130     gmx_bool            bTricl;
131     gmx_bool            bDynBox;
132     gmx_bool            bNHC_trotter;
133     gmx_bool            bPrintNHChains;
134     gmx_bool            bMTTK;
135     gmx_bool            bMu; /* true if dipole is calculated */
136     gmx_bool            bDiagPres;
137     gmx_bool            bPres;
138     int                 f_nre;
139     int                 epc;
140     real                ref_p;
141     int                 etc;
142     int                 nCrmsd;
143     gmx_bool            bEner[F_NRE];
144     gmx_bool            bEInd[egNR];
145     char              **print_grpnms;
146
147     FILE               *fp_dhdl; /* the dhdl.xvg output file */
148     double             *dE;      /* energy components for dhdl.xvg output */
149     t_mde_delta_h_coll *dhc;     /* the delta U components (raw data + histogram) */
150     real               *temperatures;
151 };
152
153 }   // namespace detail
154
155 using detail::t_mdebin;
156
157 namespace
158 {
159
160 //! Legacy init function
161 t_mdebin *init_mdebin(ener_file_t       fp_ene,
162                       const gmx_mtop_t *mtop,
163                       const t_inputrec *ir,
164                       FILE             *fp_dhdl,
165                       bool              isRerun)
166 {
167     const char                *ener_nm[F_NRE];
168     static const char         *vir_nm[] = {
169         "Vir-XX", "Vir-XY", "Vir-XZ",
170         "Vir-YX", "Vir-YY", "Vir-YZ",
171         "Vir-ZX", "Vir-ZY", "Vir-ZZ"
172     };
173     static const char         *sv_nm[] = {
174         "ShakeVir-XX", "ShakeVir-XY", "ShakeVir-XZ",
175         "ShakeVir-YX", "ShakeVir-YY", "ShakeVir-YZ",
176         "ShakeVir-ZX", "ShakeVir-ZY", "ShakeVir-ZZ"
177     };
178     static const char         *fv_nm[] = {
179         "ForceVir-XX", "ForceVir-XY", "ForceVir-XZ",
180         "ForceVir-YX", "ForceVir-YY", "ForceVir-YZ",
181         "ForceVir-ZX", "ForceVir-ZY", "ForceVir-ZZ"
182     };
183     static const char         *pres_nm[] = {
184         "Pres-XX", "Pres-XY", "Pres-XZ",
185         "Pres-YX", "Pres-YY", "Pres-YZ",
186         "Pres-ZX", "Pres-ZY", "Pres-ZZ"
187     };
188     static const char         *surft_nm[] = {
189         "#Surf*SurfTen"
190     };
191     static const char         *mu_nm[] = {
192         "Mu-X", "Mu-Y", "Mu-Z"
193     };
194     static const char         *vcos_nm[] = {
195         "2CosZ*Vel-X"
196     };
197     static const char         *visc_nm[] = {
198         "1/Viscosity"
199     };
200     static const char         *baro_nm[] = {
201         "Barostat"
202     };
203
204     const SimulationGroups    *groups;
205     char                     **gnm;
206     char                       buf[256];
207     const char                *bufi;
208     t_mdebin                  *md;
209     int                        i, j, ni, nj, n, k, kk, ncon, nset;
210     gmx_bool                   bBHAM, b14;
211
212     snew(md, 1);
213
214     if (EI_DYNAMICS(ir->eI))
215     {
216         md->delta_t = ir->delta_t;
217     }
218     else
219     {
220         md->delta_t = 0;
221     }
222
223     groups = &mtop->groups;
224
225     bBHAM = (mtop->ffparams.numTypes() > 0) && (mtop->ffparams.functype[0] == F_BHAM);
226     b14   = (gmx_mtop_ftype_count(mtop, F_LJ14) > 0 ||
227              gmx_mtop_ftype_count(mtop, F_LJC14_Q) > 0);
228
229     ncon           = gmx_mtop_ftype_count(mtop, F_CONSTR);
230     nset           = gmx_mtop_ftype_count(mtop, F_SETTLE);
231     md->bConstr    = (ncon > 0 || nset > 0) && !isRerun;
232     md->bConstrVir = FALSE;
233     if (md->bConstr)
234     {
235         if (ncon > 0 && ir->eConstrAlg == econtLINCS)
236         {
237             md->nCrmsd = 1;
238         }
239         md->bConstrVir = (getenv("GMX_CONSTRAINTVIR") != nullptr);
240     }
241     else
242     {
243         md->nCrmsd = 0;
244     }
245
246     /* Energy monitoring */
247     for (i = 0; i < egNR; i++)
248     {
249         md->bEInd[i] = FALSE;
250     }
251
252     for (i = 0; i < F_NRE; i++)
253     {
254         md->bEner[i] = FALSE;
255         if (isRerun &&
256             (i == F_EKIN || i == F_ETOT || i == F_ECONSERVED ||
257              i == F_TEMP || i == F_PDISPCORR || i == F_PRES))
258         {
259             continue;
260         }
261         if (i == F_LJ)
262         {
263             md->bEner[i] = !bBHAM;
264         }
265         else if (i == F_BHAM)
266         {
267             md->bEner[i] = bBHAM;
268         }
269         else if (i == F_EQM)
270         {
271             md->bEner[i] = ir->bQMMM;
272         }
273         else if (i == F_RF_EXCL)
274         {
275             md->bEner[i] = (EEL_RF(ir->coulombtype) && ir->cutoff_scheme == ecutsGROUP);
276         }
277         else if (i == F_COUL_RECIP)
278         {
279             md->bEner[i] = EEL_FULL(ir->coulombtype);
280         }
281         else if (i == F_LJ_RECIP)
282         {
283             md->bEner[i] = EVDW_PME(ir->vdwtype);
284         }
285         else if (i == F_LJ14)
286         {
287             md->bEner[i] = b14;
288         }
289         else if (i == F_COUL14)
290         {
291             md->bEner[i] = b14;
292         }
293         else if (i == F_LJC14_Q || i == F_LJC_PAIRS_NB)
294         {
295             md->bEner[i] = FALSE;
296         }
297         else if ((i == F_DVDL_COUL && ir->fepvals->separate_dvdl[efptCOUL]) ||
298                  (i == F_DVDL_VDW  && ir->fepvals->separate_dvdl[efptVDW]) ||
299                  (i == F_DVDL_BONDED && ir->fepvals->separate_dvdl[efptBONDED]) ||
300                  (i == F_DVDL_RESTRAINT && ir->fepvals->separate_dvdl[efptRESTRAINT]) ||
301                  (i == F_DKDL && ir->fepvals->separate_dvdl[efptMASS]) ||
302                  (i == F_DVDL && ir->fepvals->separate_dvdl[efptFEP]))
303         {
304             md->bEner[i] = (ir->efep != efepNO);
305         }
306         else if ((interaction_function[i].flags & IF_VSITE) ||
307                  (i == F_CONSTR) || (i == F_CONSTRNC) || (i == F_SETTLE))
308         {
309             md->bEner[i] = FALSE;
310         }
311         else if ((i == F_COUL_SR) || (i == F_EPOT) || (i == F_PRES)  || (i == F_EQM))
312         {
313             md->bEner[i] = TRUE;
314         }
315         else if ((i == F_ETOT) || (i == F_EKIN) || (i == F_TEMP))
316         {
317             md->bEner[i] = EI_DYNAMICS(ir->eI);
318         }
319         else if (i == F_DISPCORR || i == F_PDISPCORR)
320         {
321             md->bEner[i] = (ir->eDispCorr != edispcNO);
322         }
323         else if (i == F_DISRESVIOL)
324         {
325             md->bEner[i] = (gmx_mtop_ftype_count(mtop, F_DISRES) > 0);
326         }
327         else if (i == F_ORIRESDEV)
328         {
329             md->bEner[i] = (gmx_mtop_ftype_count(mtop, F_ORIRES) > 0);
330         }
331         else if (i == F_CONNBONDS)
332         {
333             md->bEner[i] = FALSE;
334         }
335         else if (i == F_COM_PULL)
336         {
337             md->bEner[i] = ((ir->bPull && pull_have_potential(ir->pull_work)) ||
338                             ir->bRot);
339         }
340         else if (i == F_ECONSERVED)
341         {
342             md->bEner[i] = (integratorHasConservedEnergyQuantity(ir));
343         }
344         else
345         {
346             md->bEner[i] = (gmx_mtop_ftype_count(mtop, i) > 0);
347         }
348     }
349
350     md->f_nre = 0;
351     for (i = 0; i < F_NRE; i++)
352     {
353         if (md->bEner[i])
354         {
355             ener_nm[md->f_nre] = interaction_function[i].longname;
356             md->f_nre++;
357         }
358     }
359
360     md->epc            = isRerun ? epcNO : ir->epc;
361     md->bDiagPres      = !TRICLINIC(ir->ref_p) && !isRerun;
362     md->ref_p          = (ir->ref_p[XX][XX]+ir->ref_p[YY][YY]+ir->ref_p[ZZ][ZZ])/DIM;
363     md->bTricl         = TRICLINIC(ir->compress) || TRICLINIC(ir->deform);
364     md->bDynBox        = inputrecDynamicBox(ir);
365     md->etc            = isRerun ? etcNO : ir->etc;
366     md->bNHC_trotter   = inputrecNvtTrotter(ir) && !isRerun;
367     md->bPrintNHChains = ir->bPrintNHChains && !isRerun;
368     md->bMTTK          = (inputrecNptTrotter(ir) || inputrecNphTrotter(ir)) && !isRerun;
369     md->bMu            = inputrecNeedMutot(ir);
370     md->bPres          = !isRerun;
371
372     md->ebin  = mk_ebin();
373     /* Pass NULL for unit to let get_ebin_space determine the units
374      * for interaction_function[i].longname
375      */
376     md->ie    = get_ebin_space(md->ebin, md->f_nre, ener_nm, nullptr);
377     if (md->nCrmsd)
378     {
379         /* This should be called directly after the call for md->ie,
380          * such that md->iconrmsd follows directly in the list.
381          */
382         md->iconrmsd = get_ebin_space(md->ebin, md->nCrmsd, conrmsd_nm, "");
383     }
384     if (md->bDynBox)
385     {
386         md->ib    = get_ebin_space(md->ebin,
387                                    md->bTricl ? NTRICLBOXS : NBOXS,
388                                    md->bTricl ? tricl_boxs_nm : boxs_nm,
389                                    unit_length);
390         md->ivol  = get_ebin_space(md->ebin, 1, vol_nm,  unit_volume);
391         md->idens = get_ebin_space(md->ebin, 1, dens_nm, unit_density_SI);
392         if (md->bDiagPres)
393         {
394             md->ipv       = get_ebin_space(md->ebin, 1, pv_nm,   unit_energy);
395             md->ienthalpy = get_ebin_space(md->ebin, 1, enthalpy_nm,   unit_energy);
396         }
397     }
398     if (md->bConstrVir)
399     {
400         md->isvir = get_ebin_space(md->ebin, asize(sv_nm), sv_nm, unit_energy);
401         md->ifvir = get_ebin_space(md->ebin, asize(fv_nm), fv_nm, unit_energy);
402     }
403     if (md->bPres)
404     {
405         md->ivir   = get_ebin_space(md->ebin, asize(vir_nm), vir_nm, unit_energy);
406         md->ipres  = get_ebin_space(md->ebin, asize(pres_nm), pres_nm, unit_pres_bar);
407         md->isurft = get_ebin_space(md->ebin, asize(surft_nm), surft_nm,
408                                     unit_surft_bar);
409     }
410     if (md->epc == epcPARRINELLORAHMAN || md->epc == epcMTTK)
411     {
412         md->ipc = get_ebin_space(md->ebin, md->bTricl ? 6 : 3,
413                                  boxvel_nm, unit_vel);
414     }
415     if (md->bMu)
416     {
417         md->imu    = get_ebin_space(md->ebin, asize(mu_nm), mu_nm, unit_dipole_D);
418     }
419     if (ir->cos_accel != 0)
420     {
421         md->ivcos = get_ebin_space(md->ebin, asize(vcos_nm), vcos_nm, unit_vel);
422         md->ivisc = get_ebin_space(md->ebin, asize(visc_nm), visc_nm,
423                                    unit_invvisc_SI);
424     }
425
426     /* Energy monitoring */
427     for (i = 0; i < egNR; i++)
428     {
429         md->bEInd[i] = FALSE;
430     }
431     md->bEInd[egCOULSR] = TRUE;
432     md->bEInd[egLJSR  ] = TRUE;
433
434     if (bBHAM)
435     {
436         md->bEInd[egLJSR]   = FALSE;
437         md->bEInd[egBHAMSR] = TRUE;
438     }
439     if (b14)
440     {
441         md->bEInd[egLJ14]   = TRUE;
442         md->bEInd[egCOUL14] = TRUE;
443     }
444     md->nEc = 0;
445     for (i = 0; (i < egNR); i++)
446     {
447         if (md->bEInd[i])
448         {
449             md->nEc++;
450         }
451     }
452     n       = groups->groups[SimulationAtomGroupType::EnergyOutput].nr;
453     md->nEg = n;
454     md->nE  = (n*(n+1))/2;
455
456     snew(md->igrp, md->nE);
457     if (md->nE > 1)
458     {
459         n = 0;
460         snew(gnm, md->nEc);
461         for (k = 0; (k < md->nEc); k++)
462         {
463             snew(gnm[k], STRLEN);
464         }
465         for (i = 0; (i < groups->groups[SimulationAtomGroupType::EnergyOutput].nr); i++)
466         {
467             ni = groups->groups[SimulationAtomGroupType::EnergyOutput].nm_ind[i];
468             for (j = i; (j < groups->groups[SimulationAtomGroupType::EnergyOutput].nr); j++)
469             {
470                 nj = groups->groups[SimulationAtomGroupType::EnergyOutput].nm_ind[j];
471                 for (k = kk = 0; (k < egNR); k++)
472                 {
473                     if (md->bEInd[k])
474                     {
475                         sprintf(gnm[kk], "%s:%s-%s", egrp_nm[k],
476                                 *(groups->groupNames[ni]), *(groups->groupNames[nj]));
477                         kk++;
478                     }
479                 }
480                 md->igrp[n] = get_ebin_space(md->ebin, md->nEc,
481                                              gnm, unit_energy);
482                 n++;
483             }
484         }
485         for (k = 0; (k < md->nEc); k++)
486         {
487             sfree(gnm[k]);
488         }
489         sfree(gnm);
490
491         if (n != md->nE)
492         {
493             gmx_incons("Number of energy terms wrong");
494         }
495     }
496
497     md->nTC  = isRerun ? 0 : groups->groups[SimulationAtomGroupType::TemperatureCoupling].nr;
498     md->nNHC = ir->opts.nhchainlength; /* shorthand for number of NH chains */
499     if (md->bMTTK)
500     {
501         md->nTCP = 1;  /* assume only one possible coupling system for barostat
502                           for now */
503     }
504     else
505     {
506         md->nTCP = 0;
507     }
508     if (md->etc == etcNOSEHOOVER)
509     {
510         if (md->bNHC_trotter)
511         {
512             md->mde_n = 2*md->nNHC*md->nTC;
513         }
514         else
515         {
516             md->mde_n = 2*md->nTC;
517         }
518         if (md->epc == epcMTTK)
519         {
520             md->mdeb_n = 2*md->nNHC*md->nTCP;
521         }
522     }
523     else
524     {
525         md->mde_n  = md->nTC;
526         md->mdeb_n = 0;
527     }
528
529     snew(md->tmp_r, md->mde_n);
530     snew(md->tmp_v, md->mde_n);
531     char **grpnms;
532     snew(grpnms, md->mde_n);
533
534     for (i = 0; (i < md->nTC); i++)
535     {
536         ni = groups->groups[SimulationAtomGroupType::TemperatureCoupling].nm_ind[i];
537         sprintf(buf, "T-%s", *(groups->groupNames[ni]));
538         grpnms[i] = gmx_strdup(buf);
539     }
540     md->itemp = get_ebin_space(md->ebin, md->nTC, grpnms,
541                                unit_temp_K);
542
543     if (md->etc == etcNOSEHOOVER)
544     {
545         if (md->bPrintNHChains)
546         {
547             if (md->bNHC_trotter)
548             {
549                 for (i = 0; (i < md->nTC); i++)
550                 {
551                     ni   = groups->groups[SimulationAtomGroupType::TemperatureCoupling].nm_ind[i];
552                     bufi = *(groups->groupNames[ni]);
553                     for (j = 0; (j < md->nNHC); j++)
554                     {
555                         sprintf(buf, "Xi-%d-%s", j, bufi);
556                         grpnms[2*(i*md->nNHC+j)] = gmx_strdup(buf);
557                         sprintf(buf, "vXi-%d-%s", j, bufi);
558                         grpnms[2*(i*md->nNHC+j)+1] = gmx_strdup(buf);
559                     }
560                 }
561                 md->itc = get_ebin_space(md->ebin, md->mde_n,
562                                          grpnms, unit_invtime);
563                 if (md->bMTTK)
564                 {
565                     for (i = 0; (i < md->nTCP); i++)
566                     {
567                         bufi = baro_nm[0];  /* All barostat DOF's together for now. */
568                         for (j = 0; (j < md->nNHC); j++)
569                         {
570                             sprintf(buf, "Xi-%d-%s", j, bufi);
571                             grpnms[2*(i*md->nNHC+j)] = gmx_strdup(buf);
572                             sprintf(buf, "vXi-%d-%s", j, bufi);
573                             grpnms[2*(i*md->nNHC+j)+1] = gmx_strdup(buf);
574                         }
575                     }
576                     md->itcb = get_ebin_space(md->ebin, md->mdeb_n,
577                                               grpnms, unit_invtime);
578                 }
579             }
580             else
581             {
582                 for (i = 0; (i < md->nTC); i++)
583                 {
584                     ni   = groups->groups[SimulationAtomGroupType::TemperatureCoupling].nm_ind[i];
585                     bufi = *(groups->groupNames[ni]);
586                     sprintf(buf, "Xi-%s", bufi);
587                     grpnms[2*i] = gmx_strdup(buf);
588                     sprintf(buf, "vXi-%s", bufi);
589                     grpnms[2*i+1] = gmx_strdup(buf);
590                 }
591                 md->itc = get_ebin_space(md->ebin, md->mde_n,
592                                          grpnms, unit_invtime);
593             }
594         }
595     }
596     else if (md->etc == etcBERENDSEN || md->etc == etcYES ||
597              md->etc == etcVRESCALE)
598     {
599         for (i = 0; (i < md->nTC); i++)
600         {
601             ni = groups->groups[SimulationAtomGroupType::TemperatureCoupling].nm_ind[i];
602             sprintf(buf, "Lamb-%s", *(groups->groupNames[ni]));
603             grpnms[i] = gmx_strdup(buf);
604         }
605         md->itc = get_ebin_space(md->ebin, md->mde_n, grpnms, "");
606     }
607
608     for (i = 0; i < md->mde_n; i++)
609     {
610         sfree(grpnms[i]);
611     }
612     sfree(grpnms);
613
614     md->nU = groups->groups[SimulationAtomGroupType::Acceleration].nr;
615     if (md->nU > 1)
616     {
617         snew(grpnms, 3*md->nU);
618         for (i = 0; (i < md->nU); i++)
619         {
620             ni = groups->groups[SimulationAtomGroupType::Acceleration].nm_ind[i];
621             sprintf(buf, "Ux-%s", *(groups->groupNames[ni]));
622             grpnms[3*i+XX] = gmx_strdup(buf);
623             sprintf(buf, "Uy-%s", *(groups->groupNames[ni]));
624             grpnms[3*i+YY] = gmx_strdup(buf);
625             sprintf(buf, "Uz-%s", *(groups->groupNames[ni]));
626             grpnms[3*i+ZZ] = gmx_strdup(buf);
627         }
628         md->iu = get_ebin_space(md->ebin, 3*md->nU, grpnms, unit_vel);
629         sfree(grpnms);
630     }
631
632     if (fp_ene)
633     {
634         do_enxnms(fp_ene, &md->ebin->nener, &md->ebin->enm);
635     }
636
637     md->print_grpnms = nullptr;
638
639     /* check whether we're going to write dh histograms */
640     md->dhc = nullptr;
641     if (ir->fepvals->separate_dhdl_file == esepdhdlfileNO)
642     {
643         /* Currently dh histograms are only written with dynamics */
644         if (EI_DYNAMICS(ir->eI))
645         {
646             snew(md->dhc, 1);
647
648             mde_delta_h_coll_init(md->dhc, ir);
649         }
650         md->fp_dhdl = nullptr;
651         snew(md->dE, ir->fepvals->n_lambda);
652     }
653     else
654     {
655         md->fp_dhdl = fp_dhdl;
656         snew(md->dE, ir->fepvals->n_lambda);
657     }
658     if (ir->bSimTemp)
659     {
660         int i;
661         snew(md->temperatures, ir->fepvals->n_lambda);
662         for (i = 0; i < ir->fepvals->n_lambda; i++)
663         {
664             md->temperatures[i] = ir->simtempvals->temperatures[i];
665         }
666     }
667     return md;
668 }
669
670 //! Legacy cleanup function
671 void done_mdebin(t_mdebin *mdebin)
672 {
673     sfree(mdebin->igrp);
674     sfree(mdebin->tmp_r);
675     sfree(mdebin->tmp_v);
676     done_ebin(mdebin->ebin);
677     done_mde_delta_h_coll(mdebin->dhc);
678     sfree(mdebin->dE);
679     sfree(mdebin->temperatures);
680     sfree(mdebin);
681 }
682
683 } // namespace
684 } // namespace gmx
685
686 /* print a lambda vector to a string
687    fep = the inputrec's FEP input data
688    i = the index of the lambda vector
689    get_native_lambda = whether to print the native lambda
690    get_names = whether to print the names rather than the values
691    str = the pre-allocated string buffer to print to. */
692 static void print_lambda_vector(t_lambda *fep, int i,
693                                 gmx_bool get_native_lambda, gmx_bool get_names,
694                                 char *str)
695 {
696     int    j, k = 0;
697     int    Nsep = 0;
698
699     for (j = 0; j < efptNR; j++)
700     {
701         if (fep->separate_dvdl[j])
702         {
703             Nsep++;
704         }
705     }
706     str[0] = 0; /* reset the string */
707     if (Nsep > 1)
708     {
709         str += sprintf(str, "("); /* set the opening parenthesis*/
710     }
711     for (j = 0; j < efptNR; j++)
712     {
713         if (fep->separate_dvdl[j])
714         {
715             if (!get_names)
716             {
717                 if (get_native_lambda && fep->init_lambda >= 0)
718                 {
719                     str += sprintf(str, "%.4f", fep->init_lambda);
720                 }
721                 else
722                 {
723                     str += sprintf(str, "%.4f", fep->all_lambda[j][i]);
724                 }
725             }
726             else
727             {
728                 str += sprintf(str, "%s", efpt_singular_names[j]);
729             }
730             /* print comma for the next item */
731             if (k < Nsep-1)
732             {
733                 str += sprintf(str, ", ");
734             }
735             k++;
736         }
737     }
738     if (Nsep > 1)
739     {
740         /* and add the closing parenthesis */
741         sprintf(str, ")");
742     }
743 }
744
745 FILE *open_dhdl(const char *filename, const t_inputrec *ir,
746                 const gmx_output_env_t *oenv)
747 {
748     FILE       *fp;
749     const char *dhdl = "dH/d\\lambda", *deltag = "\\DeltaH", *lambda = "\\lambda",
750     *lambdastate     = "\\lambda state";
751     int         i, nsets, nsets_de, nsetsbegin;
752     int         n_lambda_terms = 0;
753     t_lambda   *fep            = ir->fepvals; /* for simplicity */
754     t_expanded *expand         = ir->expandedvals;
755     char        lambda_vec_str[STRLEN], lambda_name_str[STRLEN];
756
757     int         nsets_dhdl = 0;
758     int         s          = 0;
759     int         nsetsextend;
760     gmx_bool    write_pV = FALSE;
761
762     /* count the number of different lambda terms */
763     for (i = 0; i < efptNR; i++)
764     {
765         if (fep->separate_dvdl[i])
766         {
767             n_lambda_terms++;
768         }
769     }
770
771     std::string title, label_x, label_y;
772     if (fep->n_lambda == 0)
773     {
774         title   = gmx::formatString("%s", dhdl);
775         label_x = gmx::formatString("Time (ps)");
776         label_y = gmx::formatString("%s (%s %s)",
777                                     dhdl, unit_energy, "[\\lambda]\\S-1\\N");
778     }
779     else
780     {
781         title   = gmx::formatString("%s and %s", dhdl, deltag);
782         label_x = gmx::formatString("Time (ps)");
783         label_y = gmx::formatString("%s and %s (%s %s)",
784                                     dhdl, deltag, unit_energy, "[\\8l\\4]\\S-1\\N");
785     }
786     fp = gmx_fio_fopen(filename, "w+");
787     xvgr_header(fp, title.c_str(), label_x, label_y, exvggtXNY, oenv);
788
789     std::string buf;
790     if (!(ir->bSimTemp))
791     {
792         buf = gmx::formatString("T = %g (K) ", ir->opts.ref_t[0]);
793     }
794     if ((ir->efep != efepSLOWGROWTH) && (ir->efep != efepEXPANDED))
795     {
796         if ( (fep->init_lambda >= 0)  && (n_lambda_terms == 1 ))
797         {
798             /* compatibility output */
799             buf += gmx::formatString("%s = %.4f", lambda, fep->init_lambda);
800         }
801         else
802         {
803             print_lambda_vector(fep, fep->init_fep_state, TRUE, FALSE,
804                                 lambda_vec_str);
805             print_lambda_vector(fep, fep->init_fep_state, TRUE, TRUE,
806                                 lambda_name_str);
807             buf += gmx::formatString("%s %d: %s = %s",
808                                      lambdastate, fep->init_fep_state,
809                                      lambda_name_str, lambda_vec_str);
810         }
811     }
812     xvgr_subtitle(fp, buf.c_str(), oenv);
813
814
815     nsets_dhdl = 0;
816     if (fep->dhdl_derivatives == edhdlderivativesYES)
817     {
818         nsets_dhdl = n_lambda_terms;
819     }
820     /* count the number of delta_g states */
821     nsets_de = fep->lambda_stop_n - fep->lambda_start_n;
822
823     nsets = nsets_dhdl + nsets_de; /* dhdl + fep differences */
824
825     if (fep->n_lambda > 0 && (expand->elmcmove > elmcmoveNO))
826     {
827         nsets += 1;   /*add fep state for expanded ensemble */
828     }
829
830     if (fep->edHdLPrintEnergy != edHdLPrintEnergyNO)
831     {
832         nsets += 1;  /* add energy to the dhdl as well */
833     }
834
835     nsetsextend = nsets;
836     if ((ir->epc != epcNO) && (fep->n_lambda > 0) && (fep->init_lambda < 0))
837     {
838         nsetsextend += 1; /* for PV term, other terms possible if required for
839                              the reduced potential (only needed with foreign
840                              lambda, and only output when init_lambda is not
841                              set in order to maintain compatibility of the
842                              dhdl.xvg file) */
843         write_pV     = TRUE;
844     }
845     std::vector<std::string> setname(nsetsextend);
846
847     if (expand->elmcmove > elmcmoveNO)
848     {
849         /* state for the fep_vals, if we have alchemical sampling */
850         setname[s++] = "Thermodynamic state";
851     }
852
853     if (fep->edHdLPrintEnergy != edHdLPrintEnergyNO)
854     {
855         std::string energy;
856         switch (fep->edHdLPrintEnergy)
857         {
858             case edHdLPrintEnergyPOTENTIAL:
859                 energy = gmx::formatString("%s (%s)", "Potential Energy", unit_energy);
860                 break;
861             case edHdLPrintEnergyTOTAL:
862             case edHdLPrintEnergyYES:
863             default:
864                 energy = gmx::formatString("%s (%s)", "Total Energy", unit_energy);
865         }
866         setname[s++] = energy;
867     }
868
869     if (fep->dhdl_derivatives == edhdlderivativesYES)
870     {
871         for (i = 0; i < efptNR; i++)
872         {
873             if (fep->separate_dvdl[i])
874             {
875                 std::string derivative;
876                 if ( (fep->init_lambda >= 0)  && (n_lambda_terms == 1 ))
877                 {
878                     /* compatibility output */
879                     derivative = gmx::formatString("%s %s %.4f", dhdl, lambda, fep->init_lambda);
880                 }
881                 else
882                 {
883                     double lam = fep->init_lambda;
884                     if (fep->init_lambda < 0)
885                     {
886                         lam = fep->all_lambda[i][fep->init_fep_state];
887                     }
888                     derivative = gmx::formatString("%s %s = %.4f", dhdl, efpt_singular_names[i],
889                                                    lam);
890                 }
891                 setname[s++] = derivative;
892             }
893         }
894     }
895
896     if (fep->n_lambda > 0)
897     {
898         /* g_bar has to determine the lambda values used in this simulation
899          * from this xvg legend.
900          */
901
902         if (expand->elmcmove > elmcmoveNO)
903         {
904             nsetsbegin = 1;  /* for including the expanded ensemble */
905         }
906         else
907         {
908             nsetsbegin = 0;
909         }
910
911         if (fep->edHdLPrintEnergy != edHdLPrintEnergyNO)
912         {
913             nsetsbegin += 1;
914         }
915         nsetsbegin += nsets_dhdl;
916
917         for (i = fep->lambda_start_n; i < fep->lambda_stop_n; i++)
918         {
919             print_lambda_vector(fep, i, FALSE, FALSE, lambda_vec_str);
920             std::string buf;
921             if ( (fep->init_lambda >= 0)  && (n_lambda_terms == 1 ))
922             {
923                 /* for compatible dhdl.xvg files */
924                 buf = gmx::formatString("%s %s %s", deltag, lambda, lambda_vec_str);
925             }
926             else
927             {
928                 buf = gmx::formatString("%s %s to %s", deltag, lambda, lambda_vec_str);
929             }
930
931             if (ir->bSimTemp)
932             {
933                 /* print the temperature for this state if doing simulated annealing */
934                 buf += gmx::formatString("T = %g (%s)",
935                                          ir->simtempvals->temperatures[s-(nsetsbegin)],
936                                          unit_temp_K);
937             }
938             setname[s++] = buf;
939         }
940         if (write_pV)
941         {
942             setname[s++] = gmx::formatString("pV (%s)", unit_energy);
943         }
944
945         xvgrLegend(fp, setname, oenv);
946     }
947
948     return fp;
949 }
950
951 namespace gmx
952 {
953 namespace
954 {
955
956 //! Legacy update function
957 void upd_mdebin(t_mdebin               *md,
958                 gmx_bool                bDoDHDL,
959                 gmx_bool                bSum,
960                 double                  time,
961                 real                    tmass,
962                 gmx_enerdata_t         *enerd,
963                 t_state                *state,
964                 t_lambda               *fep,
965                 t_expanded             *expand,
966                 matrix                  box,
967                 tensor                  svir,
968                 tensor                  fvir,
969                 tensor                  vir,
970                 tensor                  pres,
971                 gmx_ekindata_t         *ekind,
972                 rvec                    mu_tot,
973                 const gmx::Constraints *constr)
974 {
975     int    i, j, k, kk, n, gid;
976     real   crmsd[2], tmp6[6];
977     real   bs[NTRICLBOXS], vol, dens, pv, enthalpy;
978     real   eee[egNR];
979     double store_dhdl[efptNR];
980     real   store_energy = 0;
981     real   tmp;
982
983     /* Do NOT use the box in the state variable, but the separate box provided
984      * as an argument. This is because we sometimes need to write the box from
985      * the last timestep to match the trajectory frames.
986      */
987     add_ebin_indexed(md->ebin, md->ie, gmx::ArrayRef<gmx_bool>(md->bEner), enerd->term, bSum);
988     if (md->nCrmsd)
989     {
990         crmsd[0] = constr->rmsd();
991         add_ebin(md->ebin, md->iconrmsd, md->nCrmsd, crmsd, FALSE);
992     }
993     if (md->bDynBox)
994     {
995         int nboxs;
996         if (md->bTricl)
997         {
998             bs[0] = box[XX][XX];
999             bs[1] = box[YY][YY];
1000             bs[2] = box[ZZ][ZZ];
1001             bs[3] = box[YY][XX];
1002             bs[4] = box[ZZ][XX];
1003             bs[5] = box[ZZ][YY];
1004             nboxs = NTRICLBOXS;
1005         }
1006         else
1007         {
1008             bs[0] = box[XX][XX];
1009             bs[1] = box[YY][YY];
1010             bs[2] = box[ZZ][ZZ];
1011             nboxs = NBOXS;
1012         }
1013         vol  = box[XX][XX]*box[YY][YY]*box[ZZ][ZZ];
1014         dens = (tmass*AMU)/(vol*NANO*NANO*NANO);
1015         add_ebin(md->ebin, md->ib, nboxs, bs, bSum);
1016         add_ebin(md->ebin, md->ivol, 1, &vol, bSum);
1017         add_ebin(md->ebin, md->idens, 1, &dens, bSum);
1018
1019         if (md->bDiagPres)
1020         {
1021             /* This is pV (in kJ/mol).  The pressure is the reference pressure,
1022                not the instantaneous pressure */
1023             pv = vol*md->ref_p/PRESFAC;
1024
1025             add_ebin(md->ebin, md->ipv, 1, &pv, bSum);
1026             enthalpy = pv + enerd->term[F_ETOT];
1027             add_ebin(md->ebin, md->ienthalpy, 1, &enthalpy, bSum);
1028         }
1029     }
1030     if (md->bConstrVir)
1031     {
1032         add_ebin(md->ebin, md->isvir, 9, svir[0], bSum);
1033         add_ebin(md->ebin, md->ifvir, 9, fvir[0], bSum);
1034     }
1035     if (md->bPres)
1036     {
1037         add_ebin(md->ebin, md->ivir, 9, vir[0], bSum);
1038         add_ebin(md->ebin, md->ipres, 9, pres[0], bSum);
1039         tmp = (pres[ZZ][ZZ]-(pres[XX][XX]+pres[YY][YY])*0.5)*box[ZZ][ZZ];
1040         add_ebin(md->ebin, md->isurft, 1, &tmp, bSum);
1041     }
1042     if (md->epc == epcPARRINELLORAHMAN || md->epc == epcMTTK)
1043     {
1044         tmp6[0] = state->boxv[XX][XX];
1045         tmp6[1] = state->boxv[YY][YY];
1046         tmp6[2] = state->boxv[ZZ][ZZ];
1047         tmp6[3] = state->boxv[YY][XX];
1048         tmp6[4] = state->boxv[ZZ][XX];
1049         tmp6[5] = state->boxv[ZZ][YY];
1050         add_ebin(md->ebin, md->ipc, md->bTricl ? 6 : 3, tmp6, bSum);
1051     }
1052     if (md->bMu)
1053     {
1054         add_ebin(md->ebin, md->imu, 3, mu_tot, bSum);
1055     }
1056     if (ekind && ekind->cosacc.cos_accel != 0)
1057     {
1058         vol  = box[XX][XX]*box[YY][YY]*box[ZZ][ZZ];
1059         dens = (tmass*AMU)/(vol*NANO*NANO*NANO);
1060         add_ebin(md->ebin, md->ivcos, 1, &(ekind->cosacc.vcos), bSum);
1061         /* 1/viscosity, unit 1/(kg m^-1 s^-1) */
1062         tmp = 1/(ekind->cosacc.cos_accel/(ekind->cosacc.vcos*PICO)
1063                  *dens*gmx::square(box[ZZ][ZZ]*NANO/(2*M_PI)));
1064         add_ebin(md->ebin, md->ivisc, 1, &tmp, bSum);
1065     }
1066     if (md->nE > 1)
1067     {
1068         n = 0;
1069         for (i = 0; (i < md->nEg); i++)
1070         {
1071             for (j = i; (j < md->nEg); j++)
1072             {
1073                 gid = GID(i, j, md->nEg);
1074                 for (k = kk = 0; (k < egNR); k++)
1075                 {
1076                     if (md->bEInd[k])
1077                     {
1078                         eee[kk++] = enerd->grpp.ener[k][gid];
1079                     }
1080                 }
1081                 add_ebin(md->ebin, md->igrp[n], md->nEc, eee, bSum);
1082                 n++;
1083             }
1084         }
1085     }
1086
1087     if (ekind)
1088     {
1089         for (i = 0; (i < md->nTC); i++)
1090         {
1091             md->tmp_r[i] = ekind->tcstat[i].T;
1092         }
1093         add_ebin(md->ebin, md->itemp, md->nTC, md->tmp_r, bSum);
1094
1095         if (md->etc == etcNOSEHOOVER)
1096         {
1097             /* whether to print Nose-Hoover chains: */
1098             if (md->bPrintNHChains)
1099             {
1100                 if (md->bNHC_trotter)
1101                 {
1102                     for (i = 0; (i < md->nTC); i++)
1103                     {
1104                         for (j = 0; j < md->nNHC; j++)
1105                         {
1106                             k                = i*md->nNHC+j;
1107                             md->tmp_r[2*k]   = state->nosehoover_xi[k];
1108                             md->tmp_r[2*k+1] = state->nosehoover_vxi[k];
1109                         }
1110                     }
1111                     add_ebin(md->ebin, md->itc, md->mde_n, md->tmp_r, bSum);
1112
1113                     if (md->bMTTK)
1114                     {
1115                         for (i = 0; (i < md->nTCP); i++)
1116                         {
1117                             for (j = 0; j < md->nNHC; j++)
1118                             {
1119                                 k                = i*md->nNHC+j;
1120                                 md->tmp_r[2*k]   = state->nhpres_xi[k];
1121                                 md->tmp_r[2*k+1] = state->nhpres_vxi[k];
1122                             }
1123                         }
1124                         add_ebin(md->ebin, md->itcb, md->mdeb_n, md->tmp_r, bSum);
1125                     }
1126                 }
1127                 else
1128                 {
1129                     for (i = 0; (i < md->nTC); i++)
1130                     {
1131                         md->tmp_r[2*i]   = state->nosehoover_xi[i];
1132                         md->tmp_r[2*i+1] = state->nosehoover_vxi[i];
1133                     }
1134                     add_ebin(md->ebin, md->itc, md->mde_n, md->tmp_r, bSum);
1135                 }
1136             }
1137         }
1138         else if (md->etc == etcBERENDSEN || md->etc == etcYES ||
1139                  md->etc == etcVRESCALE)
1140         {
1141             for (i = 0; (i < md->nTC); i++)
1142             {
1143                 md->tmp_r[i] = ekind->tcstat[i].lambda;
1144             }
1145             add_ebin(md->ebin, md->itc, md->nTC, md->tmp_r, bSum);
1146         }
1147     }
1148
1149     if (ekind && md->nU > 1)
1150     {
1151         for (i = 0; (i < md->nU); i++)
1152         {
1153             copy_rvec(ekind->grpstat[i].u, md->tmp_v[i]);
1154         }
1155         add_ebin(md->ebin, md->iu, 3*md->nU, md->tmp_v[0], bSum);
1156     }
1157
1158     ebin_increase_count(md->ebin, bSum);
1159
1160     /* BAR + thermodynamic integration values */
1161     if ((md->fp_dhdl || md->dhc) && bDoDHDL)
1162     {
1163         for (i = 0; i < enerd->n_lambda-1; i++)
1164         {
1165             /* zero for simulated tempering */
1166             md->dE[i] = enerd->enerpart_lambda[i+1]-enerd->enerpart_lambda[0];
1167             if (md->temperatures != nullptr)
1168             {
1169                 /* MRS: is this right, given the way we have defined the exchange probabilities? */
1170                 /* is this even useful to have at all? */
1171                 md->dE[i] += (md->temperatures[i]/
1172                               md->temperatures[state->fep_state]-1.0)*
1173                     enerd->term[F_EKIN];
1174             }
1175         }
1176
1177         if (md->fp_dhdl)
1178         {
1179             fprintf(md->fp_dhdl, "%.4f", time);
1180             /* the current free energy state */
1181
1182             /* print the current state if we are doing expanded ensemble */
1183             if (expand->elmcmove > elmcmoveNO)
1184             {
1185                 fprintf(md->fp_dhdl, " %4d", state->fep_state);
1186             }
1187             /* total energy (for if the temperature changes */
1188
1189             if (fep->edHdLPrintEnergy != edHdLPrintEnergyNO)
1190             {
1191                 switch (fep->edHdLPrintEnergy)
1192                 {
1193                     case edHdLPrintEnergyPOTENTIAL:
1194                         store_energy = enerd->term[F_EPOT];
1195                         break;
1196                     case edHdLPrintEnergyTOTAL:
1197                     case edHdLPrintEnergyYES:
1198                     default:
1199                         store_energy = enerd->term[F_ETOT];
1200                 }
1201                 fprintf(md->fp_dhdl, " %#.8g", store_energy);
1202             }
1203
1204             if (fep->dhdl_derivatives == edhdlderivativesYES)
1205             {
1206                 for (i = 0; i < efptNR; i++)
1207                 {
1208                     if (fep->separate_dvdl[i])
1209                     {
1210                         /* assumes F_DVDL is first */
1211                         fprintf(md->fp_dhdl, " %#.8g", enerd->term[F_DVDL+i]);
1212                     }
1213                 }
1214             }
1215             for (i = fep->lambda_start_n; i < fep->lambda_stop_n; i++)
1216             {
1217                 fprintf(md->fp_dhdl, " %#.8g", md->dE[i]);
1218             }
1219             if (md->bDynBox &&
1220                 md->bDiagPres &&
1221                 (md->epc != epcNO) &&
1222                 (enerd->n_lambda > 0) &&
1223                 (fep->init_lambda < 0))
1224             {
1225                 fprintf(md->fp_dhdl, " %#.8g", pv);  /* PV term only needed when
1226                                                         there are alternate state
1227                                                         lambda and we're not in
1228                                                         compatibility mode */
1229             }
1230             fprintf(md->fp_dhdl, "\n");
1231             /* and the binary free energy output */
1232         }
1233         if (md->dhc && bDoDHDL)
1234         {
1235             int idhdl = 0;
1236             for (i = 0; i < efptNR; i++)
1237             {
1238                 if (fep->separate_dvdl[i])
1239                 {
1240                     /* assumes F_DVDL is first */
1241                     store_dhdl[idhdl] = enerd->term[F_DVDL+i];
1242                     idhdl            += 1;
1243                 }
1244             }
1245             store_energy = enerd->term[F_ETOT];
1246             /* store_dh is dE */
1247             mde_delta_h_coll_add_dh(md->dhc,
1248                                     static_cast<double>(state->fep_state),
1249                                     store_energy,
1250                                     pv,
1251                                     store_dhdl,
1252                                     md->dE + fep->lambda_start_n,
1253                                     time);
1254         }
1255     }
1256 }
1257
1258 }   // namespace
1259
1260 void EnergyOutput::recordNonEnergyStep()
1261 {
1262     ebin_increase_count(mdebin->ebin, false);
1263 }
1264
1265 namespace
1266 {
1267
1268 //! Legacy output function
1269 void npr(FILE *log, int n, char c)
1270 {
1271     for (; (n > 0); n--)
1272     {
1273         fprintf(log, "%c", c);
1274     }
1275 }
1276
1277 //! Legacy output function
1278 void pprint(FILE *log, const char *s, t_mdebin *md)
1279 {
1280     char CHAR = '#';
1281     int  slen;
1282     char buf1[22], buf2[22];
1283
1284     slen = strlen(s);
1285     fprintf(log, "\t<======  ");
1286     npr(log, slen, CHAR);
1287     fprintf(log, "  ==>\n");
1288     fprintf(log, "\t<====  %s  ====>\n", s);
1289     fprintf(log, "\t<==  ");
1290     npr(log, slen, CHAR);
1291     fprintf(log, "  ======>\n\n");
1292
1293     fprintf(log, "\tStatistics over %s steps using %s frames\n",
1294             gmx_step_str(md->ebin->nsteps_sim, buf1),
1295             gmx_step_str(md->ebin->nsum_sim, buf2));
1296     fprintf(log, "\n");
1297 }
1298
1299 }   // namespace
1300
1301 void print_ebin_header(FILE *log, int64_t steps, double time)
1302 {
1303     char buf[22];
1304
1305     fprintf(log, "   %12s   %12s\n"
1306             "   %12s   %12.5f\n\n",
1307             "Step", "Time", gmx_step_str(steps, buf), time);
1308 }
1309
1310 namespace
1311 {
1312
1313 // TODO It is too many responsibilities for this function to handle
1314 // both .edr and .log output for both per-time and time-average data.
1315 //! Legacy ebin output function
1316 void print_ebin(ener_file_t fp_ene, gmx_bool bEne, gmx_bool bDR, gmx_bool bOR,
1317                 FILE *log,
1318                 int64_t step, double time,
1319                 int mode,
1320                 t_mdebin *md, t_fcdata *fcd,
1321                 SimulationGroups *groups, t_grpopts *opts,
1322                 gmx::Awh *awh)
1323 {
1324     /*static char **grpnms=NULL;*/
1325     char         buf[246];
1326     int          i, j, n, ni, nj, b;
1327     int          ndisre = 0;
1328
1329     /* these are for the old-style blocks (1 subblock, only reals), because
1330        there can be only one per ID for these */
1331     int          nr[enxNR];
1332     int          id[enxNR];
1333     real        *block[enxNR];
1334
1335     t_enxframe   fr;
1336
1337     if (mode == eprAVER && md->ebin->nsum_sim <= 0)
1338     {
1339         if (log)
1340         {
1341             fprintf(log, "Not enough data recorded to report energy averages\n");
1342         }
1343         return;
1344     }
1345
1346     switch (mode)
1347     {
1348         case eprNORMAL:
1349             init_enxframe(&fr);
1350             fr.t            = time;
1351             fr.step         = step;
1352             fr.nsteps       = md->ebin->nsteps;
1353             fr.dt           = md->delta_t;
1354             fr.nsum         = md->ebin->nsum;
1355             fr.nre          = (bEne) ? md->ebin->nener : 0;
1356             fr.ener         = md->ebin->e;
1357             ndisre          = bDR ? fcd->disres.npair : 0;
1358             /* Optional additional old-style (real-only) blocks. */
1359             for (i = 0; i < enxNR; i++)
1360             {
1361                 nr[i] = 0;
1362             }
1363             if (bOR && fcd->orires.nr > 0)
1364             {
1365                 diagonalize_orires_tensors(&(fcd->orires));
1366                 nr[enxOR]     = fcd->orires.nr;
1367                 block[enxOR]  = fcd->orires.otav;
1368                 id[enxOR]     = enxOR;
1369                 nr[enxORI]    = (fcd->orires.oinsl != fcd->orires.otav) ?
1370                     fcd->orires.nr : 0;
1371                 block[enxORI] = fcd->orires.oinsl;
1372                 id[enxORI]    = enxORI;
1373                 nr[enxORT]    = fcd->orires.nex*12;
1374                 block[enxORT] = fcd->orires.eig;
1375                 id[enxORT]    = enxORT;
1376             }
1377
1378             /* whether we are going to wrte anything out: */
1379             if (fr.nre || ndisre || nr[enxOR] || nr[enxORI])
1380             {
1381
1382                 /* the old-style blocks go first */
1383                 fr.nblock = 0;
1384                 for (i = 0; i < enxNR; i++)
1385                 {
1386                     if (nr[i] > 0)
1387                     {
1388                         fr.nblock = i + 1;
1389                     }
1390                 }
1391                 add_blocks_enxframe(&fr, fr.nblock);
1392                 for (b = 0; b < fr.nblock; b++)
1393                 {
1394                     add_subblocks_enxblock(&(fr.block[b]), 1);
1395                     fr.block[b].id        = id[b];
1396                     fr.block[b].sub[0].nr = nr[b];
1397 #if !GMX_DOUBLE
1398                     fr.block[b].sub[0].type = xdr_datatype_float;
1399                     fr.block[b].sub[0].fval = block[b];
1400 #else
1401                     fr.block[b].sub[0].type = xdr_datatype_double;
1402                     fr.block[b].sub[0].dval = block[b];
1403 #endif
1404                 }
1405
1406                 /* check for disre block & fill it. */
1407                 if (ndisre > 0)
1408                 {
1409                     int db = fr.nblock;
1410                     fr.nblock += 1;
1411                     add_blocks_enxframe(&fr, fr.nblock);
1412
1413                     add_subblocks_enxblock(&(fr.block[db]), 2);
1414                     fr.block[db].id        = enxDISRE;
1415                     fr.block[db].sub[0].nr = ndisre;
1416                     fr.block[db].sub[1].nr = ndisre;
1417 #if !GMX_DOUBLE
1418                     fr.block[db].sub[0].type = xdr_datatype_float;
1419                     fr.block[db].sub[1].type = xdr_datatype_float;
1420                     fr.block[db].sub[0].fval = fcd->disres.rt;
1421                     fr.block[db].sub[1].fval = fcd->disres.rm3tav;
1422 #else
1423                     fr.block[db].sub[0].type = xdr_datatype_double;
1424                     fr.block[db].sub[1].type = xdr_datatype_double;
1425                     fr.block[db].sub[0].dval = fcd->disres.rt;
1426                     fr.block[db].sub[1].dval = fcd->disres.rm3tav;
1427 #endif
1428                 }
1429                 /* here we can put new-style blocks */
1430
1431                 /* Free energy perturbation blocks */
1432                 if (md->dhc)
1433                 {
1434                     mde_delta_h_coll_handle_block(md->dhc, &fr, fr.nblock);
1435                 }
1436
1437                 /* we can now free & reset the data in the blocks */
1438                 if (md->dhc)
1439                 {
1440                     mde_delta_h_coll_reset(md->dhc);
1441                 }
1442
1443                 /* AWH bias blocks. */
1444                 if (awh != nullptr)  // TODO: add boolean in t_mdebin. See in mdebin.h.
1445                 {
1446                     awh->writeToEnergyFrame(step, &fr);
1447                 }
1448
1449                 /* do the actual I/O */
1450                 do_enx(fp_ene, &fr);
1451                 if (fr.nre)
1452                 {
1453                     /* We have stored the sums, so reset the sum history */
1454                     reset_ebin_sums(md->ebin);
1455                 }
1456             }
1457             free_enxframe(&fr);
1458             break;
1459         case eprAVER:
1460             if (log)
1461             {
1462                 pprint(log, "A V E R A G E S", md);
1463             }
1464             break;
1465         case eprRMS:
1466             if (log)
1467             {
1468                 pprint(log, "R M S - F L U C T U A T I O N S", md);
1469             }
1470             break;
1471         default:
1472             gmx_fatal(FARGS, "Invalid print mode (%d)", mode);
1473     }
1474
1475     if (log)
1476     {
1477         if (opts)
1478         {
1479             for (i = 0; i < opts->ngtc; i++)
1480             {
1481                 if (opts->annealing[i] != eannNO)
1482                 {
1483                     fprintf(log, "Current ref_t for group %s: %8.1f\n",
1484                             *(groups->groupNames[groups->groups[SimulationAtomGroupType::TemperatureCoupling].nm_ind[i]]),
1485                             opts->ref_t[i]);
1486                 }
1487             }
1488         }
1489         if (mode == eprNORMAL && bOR && fcd->orires.nr > 0)
1490         {
1491             print_orires_log(log, &(fcd->orires));
1492         }
1493         fprintf(log, "   Energies (%s)\n", unit_energy);
1494         pr_ebin(log, md->ebin, md->ie, md->f_nre+md->nCrmsd, 5, mode, TRUE);
1495         fprintf(log, "\n");
1496
1497         if (mode == eprAVER)
1498         {
1499             if (md->bDynBox)
1500             {
1501                 pr_ebin(log, md->ebin, md->ib, md->bTricl ? NTRICLBOXS : NBOXS, 5,
1502                         mode, TRUE);
1503                 fprintf(log, "\n");
1504             }
1505             if (md->bConstrVir)
1506             {
1507                 fprintf(log, "   Constraint Virial (%s)\n", unit_energy);
1508                 pr_ebin(log, md->ebin, md->isvir, 9, 3, mode, FALSE);
1509                 fprintf(log, "\n");
1510                 fprintf(log, "   Force Virial (%s)\n", unit_energy);
1511                 pr_ebin(log, md->ebin, md->ifvir, 9, 3, mode, FALSE);
1512                 fprintf(log, "\n");
1513             }
1514             if (md->bPres)
1515             {
1516                 fprintf(log, "   Total Virial (%s)\n", unit_energy);
1517                 pr_ebin(log, md->ebin, md->ivir, 9, 3, mode, FALSE);
1518                 fprintf(log, "\n");
1519                 fprintf(log, "   Pressure (%s)\n", unit_pres_bar);
1520                 pr_ebin(log, md->ebin, md->ipres, 9, 3, mode, FALSE);
1521                 fprintf(log, "\n");
1522             }
1523             if (md->bMu)
1524             {
1525                 fprintf(log, "   Total Dipole (%s)\n", unit_dipole_D);
1526                 pr_ebin(log, md->ebin, md->imu, 3, 3, mode, FALSE);
1527                 fprintf(log, "\n");
1528             }
1529
1530             if (md->nE > 1)
1531             {
1532                 if (md->print_grpnms == nullptr)
1533                 {
1534                     snew(md->print_grpnms, md->nE);
1535                     n = 0;
1536                     for (i = 0; (i < md->nEg); i++)
1537                     {
1538                         ni = groups->groups[SimulationAtomGroupType::EnergyOutput].nm_ind[i];
1539                         for (j = i; (j < md->nEg); j++)
1540                         {
1541                             nj = groups->groups[SimulationAtomGroupType::EnergyOutput].nm_ind[j];
1542                             sprintf(buf, "%s-%s", *(groups->groupNames[ni]),
1543                                     *(groups->groupNames[nj]));
1544                             md->print_grpnms[n++] = gmx_strdup(buf);
1545                         }
1546                     }
1547                 }
1548                 sprintf(buf, "Epot (%s)", unit_energy);
1549                 fprintf(log, "%15s   ", buf);
1550                 for (i = 0; (i < egNR); i++)
1551                 {
1552                     if (md->bEInd[i])
1553                     {
1554                         fprintf(log, "%12s   ", egrp_nm[i]);
1555                     }
1556                 }
1557                 fprintf(log, "\n");
1558                 for (i = 0; (i < md->nE); i++)
1559                 {
1560                     fprintf(log, "%15s", md->print_grpnms[i]);
1561                     pr_ebin(log, md->ebin, md->igrp[i], md->nEc, md->nEc, mode,
1562                             FALSE);
1563                 }
1564                 fprintf(log, "\n");
1565             }
1566             if (md->nTC > 1)
1567             {
1568                 pr_ebin(log, md->ebin, md->itemp, md->nTC, 4, mode, TRUE);
1569                 fprintf(log, "\n");
1570             }
1571             if (md->nU > 1)
1572             {
1573                 fprintf(log, "%15s   %12s   %12s   %12s\n",
1574                         "Group", "Ux", "Uy", "Uz");
1575                 for (i = 0; (i < md->nU); i++)
1576                 {
1577                     ni = groups->groups[SimulationAtomGroupType::Acceleration].nm_ind[i];
1578                     fprintf(log, "%15s", *groups->groupNames[ni]);
1579                     pr_ebin(log, md->ebin, md->iu+3*i, 3, 3, mode, FALSE);
1580                 }
1581                 fprintf(log, "\n");
1582             }
1583         }
1584     }
1585
1586 }
1587
1588 //! Legacy update function
1589 void update_energyhistory(energyhistory_t * enerhist, const t_mdebin * mdebin)
1590 {
1591     const t_ebin * const ebin = mdebin->ebin;
1592
1593     enerhist->nsteps     = ebin->nsteps;
1594     enerhist->nsum       = ebin->nsum;
1595     enerhist->nsteps_sim = ebin->nsteps_sim;
1596     enerhist->nsum_sim   = ebin->nsum_sim;
1597
1598     if (ebin->nsum > 0)
1599     {
1600         /* This will only actually resize the first time */
1601         enerhist->ener_ave.resize(ebin->nener);
1602         enerhist->ener_sum.resize(ebin->nener);
1603
1604         for (int i = 0; i < ebin->nener; i++)
1605         {
1606             enerhist->ener_ave[i] = ebin->e[i].eav;
1607             enerhist->ener_sum[i] = ebin->e[i].esum;
1608         }
1609     }
1610
1611     if (ebin->nsum_sim > 0)
1612     {
1613         /* This will only actually resize the first time */
1614         enerhist->ener_sum_sim.resize(ebin->nener);
1615
1616         for (int i = 0; i < ebin->nener; i++)
1617         {
1618             enerhist->ener_sum_sim[i] = ebin->e_sim[i].esum;
1619         }
1620     }
1621     if (mdebin->dhc)
1622     {
1623         mde_delta_h_coll_update_energyhistory(mdebin->dhc, enerhist);
1624     }
1625 }
1626
1627 //! Legacy restore function
1628 void restore_energyhistory_from_state(t_mdebin              * mdebin,
1629                                       const energyhistory_t * enerhist)
1630 {
1631     unsigned int nener = static_cast<unsigned int>(mdebin->ebin->nener);
1632
1633     GMX_RELEASE_ASSERT(enerhist, "Need valid history to restore");
1634
1635     if ((enerhist->nsum     > 0 && nener != enerhist->ener_sum.size()) ||
1636         (enerhist->nsum_sim > 0 && nener != enerhist->ener_sum_sim.size()))
1637     {
1638         gmx_fatal(FARGS, "Mismatch between number of energies in run input (%u) and checkpoint file (%zu or %zu).",
1639                   nener, enerhist->ener_sum.size(), enerhist->ener_sum_sim.size());
1640     }
1641
1642     mdebin->ebin->nsteps     = enerhist->nsteps;
1643     mdebin->ebin->nsum       = enerhist->nsum;
1644     mdebin->ebin->nsteps_sim = enerhist->nsteps_sim;
1645     mdebin->ebin->nsum_sim   = enerhist->nsum_sim;
1646
1647     for (int i = 0; i < mdebin->ebin->nener; i++)
1648     {
1649         mdebin->ebin->e[i].eav  =
1650             (enerhist->nsum > 0 ? enerhist->ener_ave[i] : 0);
1651         mdebin->ebin->e[i].esum =
1652             (enerhist->nsum > 0 ? enerhist->ener_sum[i] : 0);
1653         mdebin->ebin->e_sim[i].esum =
1654             (enerhist->nsum_sim > 0 ? enerhist->ener_sum_sim[i] : 0);
1655     }
1656     if (mdebin->dhc)
1657     {
1658         mde_delta_h_coll_restore_energyhistory(mdebin->dhc, enerhist->deltaHForeignLambdas.get());
1659     }
1660 }
1661
1662 }   // namespace
1663
1664 EnergyOutput::EnergyOutput()
1665     : mdebin(nullptr)
1666 {
1667 }
1668
1669 void EnergyOutput::prepare(ener_file        *fp_ene,
1670                            const gmx_mtop_t *mtop,
1671                            const t_inputrec *ir,
1672                            FILE             *fp_dhdl,
1673                            bool              isRerun)
1674 {
1675     mdebin = init_mdebin(fp_ene, mtop, ir, fp_dhdl, isRerun);
1676 }
1677
1678 EnergyOutput::~EnergyOutput()
1679 {
1680     done_mdebin(mdebin);
1681 }
1682
1683 t_ebin *EnergyOutput::getEbin()
1684 {
1685     return mdebin->ebin;
1686 }
1687
1688 void EnergyOutput::addDataAtEnergyStep(bool                    bDoDHDL,
1689                                        bool                    bSum,
1690                                        double                  time,
1691                                        real                    tmass,
1692                                        gmx_enerdata_t         *enerd,
1693                                        t_state                *state,
1694                                        t_lambda               *fep,
1695                                        t_expanded             *expand,
1696                                        matrix                  box,
1697                                        tensor                  svir,
1698                                        tensor                  fvir,
1699                                        tensor                  vir,
1700                                        tensor                  pres,
1701                                        gmx_ekindata_t         *ekind,
1702                                        rvec                    mu_tot,
1703                                        const gmx::Constraints *constr)
1704 {
1705     upd_mdebin(mdebin, bDoDHDL, bSum, time, tmass, enerd, state, fep,
1706                expand, box, svir, fvir, vir, pres, ekind, mu_tot, constr);
1707 }
1708
1709 void EnergyOutput::printStepToEnergyFile(ener_file *fp_ene, bool bEne, bool bDR, bool bOR,
1710                                          FILE *log,
1711                                          int64_t step, double time,
1712                                          int mode,
1713                                          t_fcdata *fcd,
1714                                          SimulationGroups *groups, t_grpopts *opts,
1715                                          gmx::Awh *awh)
1716 {
1717     print_ebin(fp_ene, bEne, bDR, bOR, log, step, time, mode,
1718                mdebin, fcd, groups, opts, awh);
1719 }
1720
1721 int EnergyOutput::numEnergyTerms() const
1722 {
1723     return mdebin->ebin->nener;
1724 }
1725
1726 void EnergyOutput::fillEnergyHistory(energyhistory_t *enerhist) const
1727 {
1728     update_energyhistory(enerhist, mdebin);
1729 }
1730
1731 void EnergyOutput::restoreFromEnergyHistory(const energyhistory_t &enerhist)
1732 {
1733     restore_energyhistory_from_state(mdebin, &enerhist);
1734 }
1735
1736 } // namespace gmx