2 * This file is part of the GROMACS molecular simulation package.
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, 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.
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.
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.
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.
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.
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.
43 #include "gromacs/commandline/pargs.h"
44 #include "gromacs/fileio/enxio.h"
45 #include "gromacs/fileio/trxio.h"
46 #include "gromacs/gmxana/gmx_ana.h"
47 #include "gromacs/legacyheaders/disre.h"
48 #include "gromacs/legacyheaders/macros.h"
49 #include "gromacs/legacyheaders/names.h"
50 #include "gromacs/legacyheaders/typedefs.h"
51 #include "gromacs/math/vec.h"
52 #include "gromacs/utility/cstringutil.h"
53 #include "gromacs/utility/fatalerror.h"
54 #include "gromacs/utility/smalloc.h"
56 #define TIME_EXPLICIT 0
57 #define TIME_CONTINUE 1
63 static int *select_it(int nre, gmx_enxnm_t *nm, int *nset)
68 gmx_bool bVerbose = TRUE;
70 if ((getenv("GMX_ENER_VERBOSE")) != NULL)
75 fprintf(stderr, "Select the terms you want to scale from the following list\n");
76 fprintf(stderr, "End your selection with 0\n");
80 for (k = 0; (k < nre); )
82 for (j = 0; (j < 4) && (k < nre); j++, k++)
84 fprintf(stderr, " %3d=%14s", k+1, nm[k].name);
86 fprintf(stderr, "\n");
93 if (1 != scanf("%d", &n))
95 gmx_fatal(FARGS, "Cannot read energy term");
97 if ((n > 0) && (n <= nre))
105 for (i = (*nset) = 0; (i < nre); i++)
118 static void sort_files(char **fnms, real *settime, int nfile)
124 for (i = 0; i < nfile; i++)
127 for (j = i+1; j < nfile; j++)
129 if (settime[j] < settime[minidx])
136 timeswap = settime[i];
137 settime[i] = settime[minidx];
138 settime[minidx] = timeswap;
140 fnms[i] = fnms[minidx];
141 fnms[minidx] = chptr;
147 static int scan_ene_files(char **fnms, int nfiles,
148 real *readtime, real *timestep, int *nremax)
150 /* Check number of energy terms and start time of all files */
151 int f, i, nre, nremin = 0, nresav = 0;
154 char inputstring[STRLEN];
160 for (f = 0; f < nfiles; f++)
162 in = open_enx(fnms[f], "r");
164 do_enxnms(in, &nre, &enm);
181 nremin = min(nremin, fr->nre);
182 *nremax = max(*nremax, fr->nre);
186 "Energy files don't match, different number of energies:\n"
187 " %s: %d\n %s: %d\n", fnms[f-1], nresav, fnms[f], fr->nre);
189 "\nContinue conversion using only the first %d terms (n/y)?\n"
190 "(you should be sure that the energy terms match)\n", nremin);
191 if (NULL == fgets(inputstring, STRLEN-1, stdin))
193 gmx_fatal(FARGS, "Error reading user input");
195 if (inputstring[0] != 'y' && inputstring[0] != 'Y')
197 fprintf(stderr, "Will not convert\n");
206 fprintf(stderr, "\n");
207 free_enxnms(nre, enm);
217 static void edit_files(char **fnms, int nfiles, real *readtime,
218 real *settime, int *cont_type, gmx_bool bSetTime, gmx_bool bSort)
222 char inputstring[STRLEN], *chptr;
228 fprintf(stderr, "\n\nEnter the new start time:\n\n");
232 fprintf(stderr, "\n\nEnter the new start time for each file.\n"
233 "There are two special options, both disables sorting:\n\n"
234 "c (continue) - The start time is taken from the end\n"
235 "of the previous file. Use it when your continuation run\n"
236 "restarts with t=0 and there is no overlap.\n\n"
237 "l (last) - The time in this file will be changed the\n"
238 "same amount as in the previous. Use it when the time in the\n"
239 "new run continues from the end of the previous one,\n"
240 "since this takes possible overlap into account.\n\n");
243 fprintf(stderr, " File Current start New start\n"
244 "---------------------------------------------------------\n");
246 for (i = 0; i < nfiles; i++)
248 fprintf(stderr, "%25s %10.3f ", fnms[i], readtime[i]);
252 if (NULL == fgets(inputstring, STRLEN-1, stdin))
254 gmx_fatal(FARGS, "Error reading user input");
256 inputstring[strlen(inputstring)-1] = 0;
258 if (inputstring[0] == 'c' || inputstring[0] == 'C')
260 cont_type[i] = TIME_CONTINUE;
263 settime[i] = FLT_MAX;
265 else if (inputstring[0] == 'l' ||
266 inputstring[0] == 'L')
268 cont_type[i] = TIME_LAST;
271 settime[i] = FLT_MAX;
275 settime[i] = strtod(inputstring, &chptr);
276 if (chptr == inputstring)
278 fprintf(stderr, "Try that again: ");
282 cont_type[i] = TIME_EXPLICIT;
289 if (cont_type[0] != TIME_EXPLICIT)
291 cont_type[0] = TIME_EXPLICIT;
297 for (i = 0; i < nfiles; i++)
299 settime[i] = readtime[i];
303 if (bSort && (nfiles > 1))
305 sort_files(fnms, settime, nfiles);
309 fprintf(stderr, "Sorting disabled.\n");
313 /* Write out the new order and start times */
314 fprintf(stderr, "\nSummary of files and start times used:\n\n"
316 "-----------------------------------------\n");
317 for (i = 0; i < nfiles; i++)
319 switch (cont_type[i])
322 fprintf(stderr, "%25s %10.3f\n", fnms[i], settime[i]);
325 fprintf(stderr, "%25s Continue from end of last file\n", fnms[i]);
328 fprintf(stderr, "%25s Change by same amount as last file\n", fnms[i]);
332 fprintf(stderr, "\n");
334 settime[nfiles] = FLT_MAX;
335 cont_type[nfiles] = TIME_EXPLICIT;
336 readtime[nfiles] = FLT_MAX;
340 static void copy_ee(t_energy *src, t_energy *dst, int nre)
344 for (i = 0; i < nre; i++)
347 dst[i].esum = src[i].esum;
348 dst[i].eav = src[i].eav;
352 static void update_ee(t_energy *lastee, gmx_int64_t laststep,
353 t_energy *startee, gmx_int64_t startstep,
354 t_energy *ee, int step,
355 t_energy *outee, int nre)
358 double sigmacorr, nom, denom;
359 double prestart_esum;
360 double prestart_sigma;
362 for (i = 0; i < nre; i++)
364 outee[i].e = ee[i].e;
365 /* add statistics from earlier file if present */
368 outee[i].esum = lastee[i].esum+ee[i].esum;
369 nom = (lastee[i].esum*(step+1)-ee[i].esum*(laststep));
370 denom = ((step+1.0)*(laststep)*(step+1.0+laststep));
371 sigmacorr = nom*nom/denom;
372 outee[i].eav = lastee[i].eav+ee[i].eav+sigmacorr;
376 /* otherwise just copy to output */
377 outee[i].esum = ee[i].esum;
378 outee[i].eav = ee[i].eav;
381 /* if we didnt start to write at the first frame
382 * we must compensate the statistics for this
383 * there are laststep frames in the earlier file
384 * and step+1 frames in this one.
388 gmx_int64_t q = laststep+step;
389 gmx_int64_t p = startstep+1;
390 prestart_esum = startee[i].esum-startee[i].e;
391 sigmacorr = prestart_esum-(p-1)*startee[i].e;
392 prestart_sigma = startee[i].eav-
393 sigmacorr*sigmacorr/(p*(p-1));
394 sigmacorr = prestart_esum/(p-1)-
396 outee[i].esum -= prestart_esum;
399 outee[i].eav = outee[i].eav-prestart_sigma-
400 sigmacorr*sigmacorr*((p-1)*q)/(q-p+1);
404 if ((outee[i].eav/(laststep+step+1)) < (GMX_REAL_EPS))
411 static void update_ee_sum(int nre,
412 gmx_int64_t *ee_sum_step,
413 gmx_int64_t *ee_sum_nsteps,
414 gmx_int64_t *ee_sum_nsum,
416 t_enxframe *fr, int out_step)
418 gmx_int64_t nsteps, nsum, fr_nsum;
421 nsteps = *ee_sum_nsteps;
434 for (i = 0; i < nre; i++)
436 ee_sum[i].esum = fr->ener[i].e;
442 for (i = 0; i < nre; i++)
444 ee_sum[i].esum = fr->ener[i].esum;
445 ee_sum[i].eav = fr->ener[i].eav;
451 else if (out_step + *ee_sum_nsum - *ee_sum_step == nsteps + fr->nsteps)
455 for (i = 0; i < nre; i++)
458 dsqr(ee_sum[i].esum/nsum
459 - (ee_sum[i].esum + fr->ener[i].e)/(nsum + 1))*nsum*(nsum + 1);
460 ee_sum[i].esum += fr->ener[i].e;
465 for (i = 0; i < fr->nre; i++)
469 dsqr(ee_sum[i].esum/nsum
470 - (ee_sum[i].esum + fr->ener[i].esum)/(nsum + fr->nsum))*
471 nsum*(nsum + fr->nsum)/(double)fr->nsum;
472 ee_sum[i].esum += fr->ener[i].esum;
475 nsteps += fr->nsteps;
482 fprintf(stderr, "\nWARNING: missing energy sums at time %f\n", fr->t);
488 *ee_sum_step = out_step;
489 *ee_sum_nsteps = nsteps;
493 int gmx_eneconv(int argc, char *argv[])
495 const char *desc[] = {
496 "With [IT]multiple files[it] specified for the [TT]-f[tt] option:[PAR]",
497 "Concatenates several energy files in sorted order.",
498 "In the case of double time frames, the one",
499 "in the later file is used. By specifying [TT]-settime[tt] you will be",
500 "asked for the start time of each file. The input files are taken",
501 "from the command line,",
502 "such that the command [TT]gmx eneconv -f *.edr -o fixed.edr[tt] should do",
504 "With [IT]one file[it] specified for [TT]-f[tt]:[PAR]",
505 "Reads one energy file and writes another, applying the [TT]-dt[tt],",
506 "[TT]-offset[tt], [TT]-t0[tt] and [TT]-settime[tt] options and",
507 "converting to a different format if necessary (indicated by file",
509 "[TT]-settime[tt] is applied first, then [TT]-dt[tt]/[TT]-offset[tt]",
510 "followed by [TT]-b[tt] and [TT]-e[tt] to select which frames to write."
512 const char *bugs[] = {
513 "When combining trajectories the sigma and E^2 (necessary for statistics) are not updated correctly. Only the actual energy is correct. One thus has to compute statistics in another way."
515 ener_file_t in = NULL, out = NULL;
516 gmx_enxnm_t *enm = NULL;
518 ener_file_t in, out = NULL;
519 gmx_enxnm_t *enm = NULL;
521 t_enxframe *fr, *fro;
522 gmx_int64_t ee_sum_step = 0, ee_sum_nsteps, ee_sum_nsum;
524 gmx_int64_t lastfilestep, laststep, startstep, startstep_file = 0;
526 int nre, nremax, this_nre, nfile, f, i, j, kkk, nset, *set = NULL;
529 real *readtime, *settime, timestep, t1, tadjust;
530 char inputstring[STRLEN], *chptr, buf[22], buf2[22], buf3[22];
533 gmx_bool bNewFile, bFirst, bNewOutput;
535 gmx_bool warned_about_dh = FALSE;
536 t_enxblock *blocks = NULL;
538 int nblocks_alloc = 0;
541 { efEDR, "-f", NULL, ffRDMULT },
542 { efEDR, "-o", "fixed", ffWRITE },
545 #define NFILE asize(fnm)
547 static real delta_t = 0.0, toffset = 0, scalefac = 1;
548 static gmx_bool bSetTime = FALSE;
549 static gmx_bool bSort = TRUE, bError = TRUE;
550 static real begin = -1;
551 static real end = -1;
552 gmx_bool remove_dh = FALSE;
555 { "-b", FALSE, etREAL, {&begin},
556 "First time to use"},
557 { "-e", FALSE, etREAL, {&end},
559 { "-dt", FALSE, etREAL, {&delta_t},
560 "Only write out frame when t MOD dt = offset" },
561 { "-offset", FALSE, etREAL, {&toffset},
562 "Time offset for [TT]-dt[tt] option" },
563 { "-settime", FALSE, etBOOL, {&bSetTime},
564 "Change starting time interactively" },
565 { "-sort", FALSE, etBOOL, {&bSort},
566 "Sort energy files (not frames)"},
567 { "-rmdh", FALSE, etBOOL, {&remove_dh},
568 "Remove free energy block data" },
569 { "-scalefac", FALSE, etREAL, {&scalefac},
570 "Multiply energy component by this factor" },
571 { "-error", FALSE, etBOOL, {&bError},
572 "Stop on errors in the file" }
575 if (!parse_common_args(&argc, argv, 0, NFILE, fnm, asize(pa),
576 pa, asize(desc), desc, asize(bugs), bugs, &oenv))
586 laststep = startstep = 0;
588 nfile = opt2fns(&fnms, "-f", NFILE, fnm);
592 gmx_fatal(FARGS, "No input files!");
595 snew(settime, nfile+1);
596 snew(readtime, nfile+1);
597 snew(cont_type, nfile+1);
599 nre = scan_ene_files(fnms, nfile, readtime, ×tep, &nremax);
600 edit_files(fnms, nfile, readtime, settime, cont_type, bSetTime, bSort);
604 snew(ee_sum, nremax);
610 snew(fro->ener, nremax);
616 for (f = 0; f < nfile; f++)
620 in = open_enx(fnms[f], "r");
622 do_enxnms(in, &this_nre, &enm);
627 set = select_it(nre, enm, &nset);
630 /* write names to the output file */
631 out = open_enx(opt2fn("-o", NFILE, fnm), "w");
632 do_enxnms(out, &nre, &enm);
635 /* start reading from the next file */
636 while ((fro->t <= (settime[f+1] + GMX_REAL_EPS)) &&
641 startstep_file = fr->step;
642 tadjust = settime[f] - fr->t;
643 if (cont_type[f+1] == TIME_LAST)
645 settime[f+1] = readtime[f+1]-readtime[f]+settime[f];
646 cont_type[f+1] = TIME_EXPLICIT;
651 if (tadjust + fr->t <= last_t)
653 /* Skip this frame, since we already have it / past it */
656 fprintf(debug, "fr->step %s, fr->t %.4f\n",
657 gmx_step_str(fr->step, buf), fr->t);
658 fprintf(debug, "tadjust %12.6e + fr->t %12.6e <= t %12.6e\n",
659 tadjust, fr->t, last_t);
664 fro->step = lastfilestep + fr->step - startstep_file;
665 fro->t = tadjust + fr->t;
667 bWrite = ((begin < 0 || (begin >= 0 && (fro->t >= begin-GMX_REAL_EPS))) &&
668 (end < 0 || (end >= 0 && (fro->t <= end +GMX_REAL_EPS))) &&
669 (fro->t <= settime[f+1]+0.5*timestep));
674 "fr->step %s, fr->t %.4f, fro->step %s fro->t %.4f, w %d\n",
675 gmx_step_str(fr->step, buf), fr->t,
676 gmx_step_str(fro->step, buf2), fro->t, bWrite);
681 if ((end > 0) && (fro->t > end+GMX_REAL_EPS))
688 if (fro->t >= begin-GMX_REAL_EPS)
693 startstep = fr->step;
697 update_ee_sum(nre, &ee_sum_step, &ee_sum_nsteps, &ee_sum_nsum, ee_sum,
702 /* determine if we should write it */
703 if (bWrite && (delta_t == 0 || bRmod(fro->t, toffset, delta_t)))
705 laststep = fro->step;
710 fprintf(stderr, "\nContinue writing frames from t=%g, step=%s\n",
711 fro->t, gmx_step_str(fro->step, buf));
714 /* Copy the energies */
715 for (i = 0; i < nre; i++)
717 fro->ener[i].e = fr->ener[i].e;
720 fro->nsteps = ee_sum_nsteps;
723 if (ee_sum_nsum <= 1)
729 fro->nsum = gmx_int64_to_int(ee_sum_nsum,
730 "energy average summation");
731 /* Copy the energy sums */
732 for (i = 0; i < nre; i++)
734 fro->ener[i].esum = ee_sum[i].esum;
735 fro->ener[i].eav = ee_sum[i].eav;
738 /* We wrote the energies, so reset the counts */
744 for (kkk = 0; kkk < nset; kkk++)
746 fro->ener[set[kkk]].e *= scalefac;
749 fro->ener[set[kkk]].eav *= scalefac*scalefac;
750 fro->ener[set[kkk]].esum *= scalefac;
754 /* Copy restraint stuff */
755 /*fro->ndisre = fr->ndisre;
756 fro->disre_rm3tav = fr->disre_rm3tav;
757 fro->disre_rt = fr->disre_rt;*/
758 fro->nblock = fr->nblock;
759 /*fro->nr = fr->nr;*/
760 fro->block = fr->block;
762 /* check if we have blocks with delta_h data and are throwing
769 if (!blocks || nblocks_alloc < fr->nblock)
771 /* we pre-allocate the blocks */
772 nblocks_alloc = fr->nblock;
773 snew(blocks, nblocks_alloc);
775 nblocks = 0; /* number of blocks so far */
777 for (i = 0; i < fr->nblock; i++)
779 if ( (fr->block[i].id != enxDHCOLL) &&
780 (fr->block[i].id != enxDH) &&
781 (fr->block[i].id != enxDHHIST) )
783 /* copy everything verbatim */
784 blocks[nblocks] = fr->block[i];
788 /* now set the block pointer to the new blocks */
789 fro->nblock = nblocks;
792 else if (delta_t > 0)
794 if (!warned_about_dh)
796 for (i = 0; i < fr->nblock; i++)
798 if (fr->block[i].id == enxDH ||
799 fr->block[i].id == enxDHHIST)
802 if (fr->block[i].id == enxDH)
804 size = fr->block[i].sub[2].nr;
812 printf("\nWARNING: %s contains delta H blocks or histograms for which\n"
813 " some data is thrown away on a block-by-block basis, where each block\n"
814 " contains up to %d samples.\n"
815 " This is almost certainly not what you want.\n"
816 " Use the -rmdh option to throw all delta H samples away.\n"
817 " Use g_energy -odh option to extract these samples.\n",
819 warned_about_dh = TRUE;
829 if (noutfr % 1000 == 0)
831 fprintf(stderr, "Writing frame time %g ", fro->t);
840 printf("\nLast step written from %s: t %g, step %s\n",
841 fnms[f], last_t, gmx_step_str(laststep, buf));
842 lastfilestep = laststep;
844 /* set the next time from the last in previous file */
845 if (cont_type[f+1] == TIME_CONTINUE)
847 settime[f+1] = fro->t;
848 /* in this case we have already written the last frame of
849 * previous file, so update begin to avoid doubling it
850 * with the start of the next file
852 begin = fro->t+0.5*timestep;
853 /* cont_type[f+1]==TIME_EXPLICIT; */
856 if ((fro->t < end) && (f < nfile-1) &&
857 (fro->t < settime[f+1]-1.5*timestep))
860 "\nWARNING: There might be a gap around t=%g\n", fro->t);
863 /* move energies to lastee */
865 free_enxnms(this_nre, enm);
867 fprintf(stderr, "\n");
871 fprintf(stderr, "No frames written.\n");
875 fprintf(stderr, "Last frame written was at step %s, time %f\n",
876 gmx_step_str(fro->step, buf), fro->t);
877 fprintf(stderr, "Wrote %d frames\n", noutfr);