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 * check out http://www.gromacs.org for more information.
7 * Copyright (c) 2012,2013, by the GROMACS development team, led by
8 * David van der Spoel, Berk Hess, Erik Lindahl, and including many
9 * others, as listed in the AUTHORS file in the top-level source
10 * directory and at http://www.gromacs.org.
12 * GROMACS is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public License
14 * as published by the Free Software Foundation; either version 2.1
15 * of the License, or (at your option) any later version.
17 * GROMACS is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with GROMACS; if not, see
24 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
25 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 * If you want to redistribute modifications to GROMACS, please
28 * consider that scientific software is very special. Version
29 * control is crucial - bugs must be traceable. We will be happy to
30 * consider code for inclusion in the official distribution, but
31 * derived work must not be called official GROMACS. Details are found
32 * in the README & COPYING files - if they are missing, get the
33 * official version at http://www.gromacs.org.
35 * To help us fund GROMACS development, we humbly ask that you cite
36 * the research papers on the package. Check out http://www.gromacs.org.
52 #include "gmx_fatal.h"
57 #define TIME_EXPLICIT 0
58 #define TIME_CONTINUE 1
64 static int *select_it(int nre,gmx_enxnm_t *nm,int *nset)
69 gmx_bool bVerbose = TRUE;
71 if ((getenv("VERBOSE")) != NULL)
74 fprintf(stderr,"Select the terms you want to scale from the following list\n");
75 fprintf(stderr,"End your selection with 0\n");
79 for(j=0; (j<4) && (k<nre); j++,k++)
80 fprintf(stderr," %3d=%14s",k+1,nm[k].name);
87 if(1 != scanf("%d",&n))
89 gmx_fatal(FARGS,"Cannot read energy term");
91 if ((n>0) && (n<=nre))
96 for(i=(*nset)=0; (i<nre); i++)
105 static void sort_files(char **fnms,real *settime,int nfile)
111 for(i=0;i<nfile;i++) {
113 for(j=i+1;j<nfile;j++) {
114 if(settime[j]<settime[minidx])
119 settime[i]=settime[minidx];
120 settime[minidx]=timeswap;
122 fnms[i]=fnms[minidx];
129 static int scan_ene_files(char **fnms, int nfiles,
130 real *readtime, real *timestep, int *nremax)
132 /* Check number of energy terms and start time of all files */
133 int f,i,nre,nremin=0,nresav=0;
136 char inputstring[STRLEN];
142 for(f=0; f<nfiles; f++) {
143 in = open_enx(fnms[f],"r");
145 do_enxnms(in,&nre,&enm);
159 nremin = min(nremin,fr->nre);
160 *nremax = max(*nremax,fr->nre);
163 "Energy files don't match, different number of energies:\n"
164 " %s: %d\n %s: %d\n",fnms[f-1],nresav,fnms[f],fr->nre);
166 "\nContinue conversion using only the first %d terms (n/y)?\n"
167 "(you should be sure that the energy terms match)\n",nremin);
168 if(NULL==fgets(inputstring,STRLEN-1,stdin))
170 gmx_fatal(FARGS,"Error reading user input");
172 if (inputstring[0]!='y' && inputstring[0]!='Y') {
173 fprintf(stderr,"Will not convert\n");
182 fprintf(stderr,"\n");
183 free_enxnms(nre,enm);
193 static void edit_files(char **fnms,int nfiles,real *readtime,
194 real *settime,int *cont_type,gmx_bool bSetTime,gmx_bool bSort)
198 char inputstring[STRLEN],*chptr;
202 fprintf(stderr,"\n\nEnter the new start time:\n\n");
204 fprintf(stderr,"\n\nEnter the new start time for each file.\n"
205 "There are two special options, both disables sorting:\n\n"
206 "c (continue) - The start time is taken from the end\n"
207 "of the previous file. Use it when your continuation run\n"
208 "restarts with t=0 and there is no overlap.\n\n"
209 "l (last) - The time in this file will be changed the\n"
210 "same amount as in the previous. Use it when the time in the\n"
211 "new run continues from the end of the previous one,\n"
212 "since this takes possible overlap into account.\n\n");
214 fprintf(stderr," File Current start New start\n"
215 "---------------------------------------------------------\n");
217 for(i=0;i<nfiles;i++) {
218 fprintf(stderr,"%25s %10.3f ",fnms[i],readtime[i]);
221 if(NULL==fgets(inputstring,STRLEN-1,stdin))
223 gmx_fatal(FARGS,"Error reading user input");
225 inputstring[strlen(inputstring)-1]=0;
227 if(inputstring[0]=='c' || inputstring[0]=='C') {
228 cont_type[i]=TIME_CONTINUE;
233 else if(inputstring[0]=='l' ||
234 inputstring[0]=='L') {
235 cont_type[i]=TIME_LAST;
241 settime[i]=strtod(inputstring,&chptr);
242 if(chptr==inputstring) {
243 fprintf(stderr,"Try that again: ");
246 cont_type[i]=TIME_EXPLICIT;
252 if(cont_type[0]!=TIME_EXPLICIT) {
253 cont_type[0]=TIME_EXPLICIT;
258 for(i=0;i<nfiles;i++)
259 settime[i]=readtime[i];
261 if(bSort && (nfiles>1))
262 sort_files(fnms,settime,nfiles);
264 fprintf(stderr,"Sorting disabled.\n");
267 /* Write out the new order and start times */
268 fprintf(stderr,"\nSummary of files and start times used:\n\n"
270 "-----------------------------------------\n");
271 for(i=0;i<nfiles;i++)
272 switch(cont_type[i]) {
274 fprintf(stderr,"%25s %10.3f\n",fnms[i],settime[i]);
277 fprintf(stderr,"%25s Continue from end of last file\n",fnms[i]);
280 fprintf(stderr,"%25s Change by same amount as last file\n",fnms[i]);
283 fprintf(stderr,"\n");
285 settime[nfiles]=FLT_MAX;
286 cont_type[nfiles]=TIME_EXPLICIT;
287 readtime[nfiles]=FLT_MAX;
291 static void copy_ee(t_energy *src, t_energy *dst, int nre)
297 dst[i].esum=src[i].esum;
298 dst[i].eav=src[i].eav;
302 static void update_ee(t_energy *lastee,gmx_large_int_t laststep,
303 t_energy *startee,gmx_large_int_t startstep,
304 t_energy *ee, int step,
305 t_energy *outee, int nre)
308 double sigmacorr,nom,denom;
309 double prestart_esum;
310 double prestart_sigma;
314 /* add statistics from earlier file if present */
316 outee[i].esum=lastee[i].esum+ee[i].esum;
317 nom=(lastee[i].esum*(step+1)-ee[i].esum*(laststep));
318 denom=((step+1.0)*(laststep)*(step+1.0+laststep));
319 sigmacorr=nom*nom/denom;
320 outee[i].eav=lastee[i].eav+ee[i].eav+sigmacorr;
323 /* otherwise just copy to output */
324 outee[i].esum=ee[i].esum;
325 outee[i].eav=ee[i].eav;
328 /* if we didnt start to write at the first frame
329 * we must compensate the statistics for this
330 * there are laststep frames in the earlier file
331 * and step+1 frames in this one.
334 gmx_large_int_t q=laststep+step;
335 gmx_large_int_t p=startstep+1;
336 prestart_esum=startee[i].esum-startee[i].e;
337 sigmacorr=prestart_esum-(p-1)*startee[i].e;
338 prestart_sigma=startee[i].eav-
339 sigmacorr*sigmacorr/(p*(p-1));
340 sigmacorr=prestart_esum/(p-1)-
342 outee[i].esum-=prestart_esum;
344 outee[i].eav=outee[i].eav-prestart_sigma-
345 sigmacorr*sigmacorr*((p-1)*q)/(q-p+1);
348 if((outee[i].eav/(laststep+step+1))<(GMX_REAL_EPS))
353 static void update_ee_sum(int nre,
354 gmx_large_int_t *ee_sum_step,
355 gmx_large_int_t *ee_sum_nsteps,
356 gmx_large_int_t *ee_sum_nsum,
358 t_enxframe *fr,int out_step)
360 gmx_large_int_t nsteps,nsum,fr_nsum;
363 nsteps = *ee_sum_nsteps;
374 ee_sum[i].esum = fr->ener[i].e;
379 ee_sum[i].esum = fr->ener[i].esum;
380 ee_sum[i].eav = fr->ener[i].eav;
385 } else if (out_step + *ee_sum_nsum - *ee_sum_step == nsteps + fr->nsteps) {
389 dsqr(ee_sum[i].esum/nsum
390 - (ee_sum[i].esum + fr->ener[i].e)/(nsum + 1))*nsum*(nsum + 1);
391 ee_sum[i].esum += fr->ener[i].e;
394 for(i=0; i<fr->nre; i++) {
397 dsqr(ee_sum[i].esum/nsum
398 - (ee_sum[i].esum + fr->ener[i].esum)/(nsum + fr->nsum))*
399 nsum*(nsum + fr->nsum)/(double)fr->nsum;
400 ee_sum[i].esum += fr->ener[i].esum;
403 nsteps += fr->nsteps;
407 fprintf(stderr,"\nWARNING: missing energy sums at time %f\n",fr->t);
413 *ee_sum_step = out_step;
414 *ee_sum_nsteps = nsteps;
418 int gmx_eneconv(int argc,char *argv[])
420 const char *desc[] = {
421 "With [IT]multiple files[it] specified for the [TT]-f[tt] option:[BR]",
422 "Concatenates several energy files in sorted order.",
423 "In the case of double time frames, the one",
424 "in the later file is used. By specifying [TT]-settime[tt] you will be",
425 "asked for the start time of each file. The input files are taken",
426 "from the command line,",
427 "such that the command [TT]eneconv -f *.edr -o fixed.edr[tt] should do",
429 "With [IT]one file[it] specified for [TT]-f[tt]:[BR]",
430 "Reads one energy file and writes another, applying the [TT]-dt[tt],",
431 "[TT]-offset[tt], [TT]-t0[tt] and [TT]-settime[tt] options and",
432 "converting to a different format if necessary (indicated by file",
434 "[TT]-settime[tt] is applied first, then [TT]-dt[tt]/[TT]-offset[tt]",
435 "followed by [TT]-b[tt] and [TT]-e[tt] to select which frames to write."
437 const char *bugs[] = {
438 "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."
440 ener_file_t in=NULL, out=NULL;
441 gmx_enxnm_t *enm=NULL;
443 ener_file_t in,out=NULL;
444 gmx_enxnm_t *enm=NULL;
447 gmx_large_int_t ee_sum_step=0,ee_sum_nsteps,ee_sum_nsum;
449 gmx_large_int_t lastfilestep,laststep,startstep,startstep_file=0;
451 int nre,nremax,this_nre,nfile,f,i,j,kkk,nset,*set=NULL;
454 real *readtime,*settime,timestep,t1,tadjust;
455 char inputstring[STRLEN],*chptr,buf[22],buf2[22],buf3[22];
458 gmx_bool bNewFile,bFirst,bNewOutput;
460 gmx_bool warned_about_dh=FALSE;
461 t_enxblock *blocks=NULL;
466 { efEDR, "-f", NULL, ffRDMULT },
467 { efEDR, "-o", "fixed", ffWRITE },
470 #define NFILE asize(fnm)
472 static real delta_t=0.0, toffset=0,scalefac=1;
473 static gmx_bool bSetTime=FALSE;
474 static gmx_bool bSort=TRUE,bError=TRUE;
475 static real begin=-1;
477 gmx_bool remove_dh=FALSE;
480 { "-b", FALSE, etREAL, {&begin},
481 "First time to use"},
482 { "-e", FALSE, etREAL, {&end},
484 { "-dt", FALSE, etREAL, {&delta_t},
485 "Only write out frame when t MOD dt = offset" },
486 { "-offset", FALSE, etREAL, {&toffset},
487 "Time offset for [TT]-dt[tt] option" },
488 { "-settime", FALSE, etBOOL, {&bSetTime},
489 "Change starting time interactively" },
490 { "-sort", FALSE, etBOOL, {&bSort},
491 "Sort energy files (not frames)"},
492 { "-rmdh", FALSE, etBOOL, {&remove_dh},
493 "Remove free energy block data" },
494 { "-scalefac", FALSE, etREAL, {&scalefac},
495 "Multiply energy component by this factor" },
496 { "-error", FALSE, etBOOL, {&bError},
497 "Stop on errors in the file" }
500 CopyRight(stderr,argv[0]);
501 parse_common_args(&argc,argv,PCA_BE_NICE,NFILE,fnm,asize(pa),
502 pa,asize(desc),desc,asize(bugs),bugs,&oenv);
510 laststep=startstep=0;
512 nfile = opt2fns(&fnms,"-f",NFILE,fnm);
515 gmx_fatal(FARGS,"No input files!");
517 snew(settime,nfile+1);
518 snew(readtime,nfile+1);
519 snew(cont_type,nfile+1);
521 nre=scan_ene_files(fnms,nfile,readtime,×tep,&nremax);
522 edit_files(fnms,nfile,readtime,settime,cont_type,bSetTime,bSort);
532 snew(fro->ener,nremax);
538 for(f=0;f<nfile;f++) {
541 in=open_enx(fnms[f],"r");
543 do_enxnms(in,&this_nre,&enm);
546 set = select_it(nre,enm,&nset);
548 /* write names to the output file */
549 out=open_enx(opt2fn("-o",NFILE,fnm),"w");
550 do_enxnms(out,&nre,&enm);
553 /* start reading from the next file */
554 while ((fro->t <= (settime[f+1] + GMX_REAL_EPS)) &&
557 startstep_file = fr->step;
558 tadjust = settime[f] - fr->t;
559 if(cont_type[f+1]==TIME_LAST) {
560 settime[f+1] = readtime[f+1]-readtime[f]+settime[f];
561 cont_type[f+1] = TIME_EXPLICIT;
566 if (tadjust + fr->t <= last_t) {
567 /* Skip this frame, since we already have it / past it */
569 fprintf(debug,"fr->step %s, fr->t %.4f\n",
570 gmx_step_str(fr->step,buf),fr->t);
571 fprintf(debug,"tadjust %12.6e + fr->t %12.6e <= t %12.6e\n",
572 tadjust,fr->t,last_t);
577 fro->step = lastfilestep + fr->step - startstep_file;
578 fro->t = tadjust + fr->t;
580 bWrite = ((begin<0 || (begin>=0 && (fro->t >= begin-GMX_REAL_EPS))) &&
581 (end <0 || (end >=0 && (fro->t <= end +GMX_REAL_EPS))) &&
582 (fro->t <= settime[f+1]+0.5*timestep));
586 "fr->step %s, fr->t %.4f, fro->step %s fro->t %.4f, w %d\n",
587 gmx_step_str(fr->step,buf),fr->t,
588 gmx_step_str(fro->step,buf2),fro->t,bWrite);
592 if ((end > 0) && (fro->t > end+GMX_REAL_EPS)) {
597 if (fro->t >= begin-GMX_REAL_EPS) {
600 startstep = fr->step;
603 update_ee_sum(nre,&ee_sum_step,&ee_sum_nsteps,&ee_sum_nsum,ee_sum,
608 /* determine if we should write it */
609 if (bWrite && (delta_t==0 || bRmod(fro->t,toffset,delta_t))) {
610 laststep = fro->step;
614 fprintf(stderr,"\nContinue writing frames from t=%g, step=%s\n",
615 fro->t,gmx_step_str(fro->step,buf));
618 /* Copy the energies */
619 for(i=0; i<nre; i++) {
620 fro->ener[i].e = fr->ener[i].e;
623 fro->nsteps = ee_sum_nsteps;
626 if (ee_sum_nsum <= 1) {
629 fro->nsum = gmx_large_int_to_int(ee_sum_nsum,
630 "energy average summation");
631 /* Copy the energy sums */
632 for(i=0; i<nre; i++) {
633 fro->ener[i].esum = ee_sum[i].esum;
634 fro->ener[i].eav = ee_sum[i].eav;
637 /* We wrote the energies, so reset the counts */
642 for(kkk=0; kkk<nset; kkk++) {
643 fro->ener[set[kkk]].e *= scalefac;
645 fro->ener[set[kkk]].eav *= scalefac*scalefac;
646 fro->ener[set[kkk]].esum *= scalefac;
650 /* Copy restraint stuff */
651 /*fro->ndisre = fr->ndisre;
652 fro->disre_rm3tav = fr->disre_rm3tav;
653 fro->disre_rt = fr->disre_rt;*/
654 fro->nblock = fr->nblock;
655 /*fro->nr = fr->nr;*/
656 fro->block = fr->block;
658 /* check if we have blocks with delta_h data and are throwing
665 if (!blocks || nblocks_alloc < fr->nblock)
667 /* we pre-allocate the blocks */
668 nblocks_alloc=fr->nblock;
669 snew(blocks, nblocks_alloc);
671 nblocks=0; /* number of blocks so far */
673 for(i=0;i<fr->nblock;i++)
675 if ( (fr->block[i].id != enxDHCOLL) &&
676 (fr->block[i].id != enxDH) &&
677 (fr->block[i].id != enxDHHIST) )
679 /* copy everything verbatim */
680 blocks[nblocks] = fr->block[i];
684 /* now set the block pointer to the new blocks */
685 fro->nblock = nblocks;
688 else if (delta_t > 0)
690 if (!warned_about_dh)
692 for(i=0;i<fr->nblock;i++)
694 if (fr->block[i].id == enxDH ||
695 fr->block[i].id == enxDHHIST)
698 if (fr->block[i].id == enxDH )
700 size=fr->block[i].sub[2].nr;
708 printf("\nWARNING: %s contains delta H blocks or histograms for which\n"
709 " some data is thrown away on a block-by-block basis, where each block\n"
710 " contains up to %d samples.\n"
711 " This is almost certainly not what you want.\n"
712 " Use the -rmdh option to throw all delta H samples away.\n"
713 " Use g_energy -odh option to extract these samples.\n",
715 warned_about_dh=TRUE;
725 if (noutfr % 1000 == 0)
726 fprintf(stderr,"Writing frame time %g ",fro->t);
732 printf("\nLast step written from %s: t %g, step %s\n",
733 fnms[f],last_t,gmx_step_str(laststep,buf));
734 lastfilestep = laststep;
736 /* set the next time from the last in previous file */
737 if (cont_type[f+1]==TIME_CONTINUE) {
738 settime[f+1] = fro->t;
739 /* in this case we have already written the last frame of
740 * previous file, so update begin to avoid doubling it
741 * with the start of the next file
743 begin = fro->t+0.5*timestep;
744 /* cont_type[f+1]==TIME_EXPLICIT; */
747 if ((fro->t < end) && (f < nfile-1) &&
748 (fro->t < settime[f+1]-1.5*timestep))
750 "\nWARNING: There might be a gap around t=%g\n",fro->t);
752 /* move energies to lastee */
754 free_enxnms(this_nre,enm);
756 fprintf(stderr,"\n");
759 fprintf(stderr,"No frames written.\n");
761 fprintf(stderr,"Last frame written was at step %s, time %f\n",
762 gmx_step_str(fro->step,buf),fro->t);
763 fprintf(stderr,"Wrote %d frames\n",noutfr);