3 * This source code is part of
7 * GROningen MAchine for Chemical Simulations
10 * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
11 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
12 * Copyright (c) 2001-2004, The GROMACS development team,
13 * check out http://www.gromacs.org for more information.
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
20 * If you want to redistribute modifications, please consider that
21 * scientific software is very special. Version control is crucial -
22 * bugs must be traceable. We will be happy to consider code for
23 * inclusion in the official distribution, but derived work must not
24 * be called official GROMACS. Details are found in the README & COPYING
25 * files - if they are missing, get the official version at www.gromacs.org.
27 * To help us fund GROMACS development, we humbly ask that you cite
28 * the papers on the package - you can find them in the top README file.
30 * For more info, check our website at http://www.gromacs.org
33 * Green Red Orange Magenta Azure Cyan Skyblue
49 #include "gmx_fatal.h"
54 #define TIME_EXPLICIT 0
55 #define TIME_CONTINUE 1
61 static int *select_it(int nre
,gmx_enxnm_t
*nm
,int *nset
)
68 if ((getenv("VERBOSE")) != NULL
)
71 fprintf(stderr
,"Select the terms you want to scale from the following list\n");
72 fprintf(stderr
,"End your selection with 0\n");
76 for(j
=0; (j
<4) && (k
<nre
); j
++,k
++)
77 fprintf(stderr
," %3d=%14s",k
+1,nm
[k
].name
);
84 if(1 != scanf("%d",&n
))
86 gmx_fatal(FARGS
,"Cannot read energy term");
88 if ((n
>0) && (n
<=nre
))
93 for(i
=(*nset
)=0; (i
<nre
); i
++)
102 static bool same_time(real t1
,real t2
)
106 return (fabs(t1
-t2
) < tol
);
110 bool bRgt(double a
,double b
)
114 if ( a
> (b
- tol
*(a
+b
)) )
120 static void sort_files(char **fnms
,real
*settime
,int nfile
)
126 for(i
=0;i
<nfile
;i
++) {
128 for(j
=i
+1;j
<nfile
;j
++) {
129 if(settime
[j
]<settime
[minidx
])
134 settime
[i
]=settime
[minidx
];
135 settime
[minidx
]=timeswap
;
137 fnms
[i
]=fnms
[minidx
];
144 static int scan_ene_files(char **fnms
, int nfiles
,
145 real
*readtime
, real
*timestep
, int *nremax
)
147 /* Check number of energy terms and start time of all files */
148 int f
,i
,nre
,nremin
=0,nresav
=0;
151 char inputstring
[STRLEN
];
157 for(f
=0; f
<nfiles
; f
++) {
158 in
= open_enx(fnms
[f
],"r");
160 do_enxnms(in
,&nre
,&enm
);
174 nremin
= min(nremin
,fr
->nre
);
175 *nremax
= max(*nremax
,fr
->nre
);
178 "Energy files don't match, different number of energies:\n"
179 " %s: %d\n %s: %d\n",fnms
[f
-1],nresav
,fnms
[f
],fr
->nre
);
181 "\nContinue conversion using only the first %d terms (n/y)?\n"
182 "(you should be sure that the energy terms match)\n",nremin
);
183 if(NULL
==fgets(inputstring
,STRLEN
-1,stdin
))
185 gmx_fatal(FARGS
,"Error reading user input");
187 if (inputstring
[0]!='y' && inputstring
[0]!='Y') {
188 fprintf(stderr
,"Will not convert\n");
197 fprintf(stderr
,"\n");
198 free_enxnms(nre
,enm
);
208 static void edit_files(char **fnms
,int nfiles
,real
*readtime
,
209 real
*settime
,int *cont_type
,bool bSetTime
,bool bSort
)
213 char inputstring
[STRLEN
],*chptr
;
217 fprintf(stderr
,"\n\nEnter the new start time:\n\n");
219 fprintf(stderr
,"\n\nEnter the new start time for each file.\n"
220 "There are two special options, both disables sorting:\n\n"
221 "c (continue) - The start time is taken from the end\n"
222 "of the previous file. Use it when your continuation run\n"
223 "restarts with t=0 and there is no overlap.\n\n"
224 "l (last) - The time in this file will be changed the\n"
225 "same amount as in the previous. Use it when the time in the\n"
226 "new run continues from the end of the previous one,\n"
227 "since this takes possible overlap into account.\n\n");
229 fprintf(stderr
," File Current start New start\n"
230 "---------------------------------------------------------\n");
232 for(i
=0;i
<nfiles
;i
++) {
233 fprintf(stderr
,"%25s %10.3f ",fnms
[i
],readtime
[i
]);
236 if(NULL
==fgets(inputstring
,STRLEN
-1,stdin
))
238 gmx_fatal(FARGS
,"Error reading user input");
240 inputstring
[strlen(inputstring
)-1]=0;
242 if(inputstring
[0]=='c' || inputstring
[0]=='C') {
243 cont_type
[i
]=TIME_CONTINUE
;
248 else if(inputstring
[0]=='l' ||
249 inputstring
[0]=='L') {
250 cont_type
[i
]=TIME_LAST
;
256 settime
[i
]=strtod(inputstring
,&chptr
);
257 if(chptr
==inputstring
) {
258 fprintf(stderr
,"Try that again: ");
261 cont_type
[i
]=TIME_EXPLICIT
;
267 if(cont_type
[0]!=TIME_EXPLICIT
) {
268 cont_type
[0]=TIME_EXPLICIT
;
273 for(i
=0;i
<nfiles
;i
++)
274 settime
[i
]=readtime
[i
];
276 if(bSort
&& (nfiles
>1))
277 sort_files(fnms
,settime
,nfiles
);
279 fprintf(stderr
,"Sorting disabled.\n");
282 /* Write out the new order and start times */
283 fprintf(stderr
,"\nSummary of files and start times used:\n\n"
285 "-----------------------------------------\n");
286 for(i
=0;i
<nfiles
;i
++)
287 switch(cont_type
[i
]) {
289 fprintf(stderr
,"%25s %10.3f\n",fnms
[i
],settime
[i
]);
292 fprintf(stderr
,"%25s Continue from end of last file\n",fnms
[i
]);
295 fprintf(stderr
,"%25s Change by same amount as last file\n",fnms
[i
]);
298 fprintf(stderr
,"\n");
300 settime
[nfiles
]=FLT_MAX
;
301 cont_type
[nfiles
]=TIME_EXPLICIT
;
302 readtime
[nfiles
]=FLT_MAX
;
306 static void copy_ee(t_energy
*src
, t_energy
*dst
, int nre
)
312 dst
[i
].esum
=src
[i
].esum
;
313 dst
[i
].eav
=src
[i
].eav
;
318 static void remove_last_eeframe(t_energy
*lastee
, gmx_large_int_t laststep
,
319 t_energy
*ee
, int nre
)
322 gmx_large_int_t p
=laststep
+1;
326 lastee
[i
].esum
-=ee
[i
].e
;
327 sigmacorr
=lastee
[i
].esum
-(p
-1)*ee
[i
].e
;
328 lastee
[i
].eav
-=(sigmacorr
*sigmacorr
)/((p
-1)*p
);
334 static void update_ee(t_energy
*lastee
,gmx_large_int_t laststep
,
335 t_energy
*startee
,gmx_large_int_t startstep
,
336 t_energy
*ee
, int step
,
337 t_energy
*outee
, int nre
)
340 double sigmacorr
,nom
,denom
;
341 double prestart_esum
;
342 double prestart_sigma
;
346 /* add statistics from earlier file if present */
348 outee
[i
].esum
=lastee
[i
].esum
+ee
[i
].esum
;
349 nom
=(lastee
[i
].esum
*(step
+1)-ee
[i
].esum
*(laststep
));
350 denom
=((step
+1.0)*(laststep
)*(step
+1.0+laststep
));
351 sigmacorr
=nom
*nom
/denom
;
352 outee
[i
].eav
=lastee
[i
].eav
+ee
[i
].eav
+sigmacorr
;
355 /* otherwise just copy to output */
356 outee
[i
].esum
=ee
[i
].esum
;
357 outee
[i
].eav
=ee
[i
].eav
;
360 /* if we didnt start to write at the first frame
361 * we must compensate the statistics for this
362 * there are laststep frames in the earlier file
363 * and step+1 frames in this one.
366 gmx_large_int_t q
=laststep
+step
;
367 gmx_large_int_t p
=startstep
+1;
368 prestart_esum
=startee
[i
].esum
-startee
[i
].e
;
369 sigmacorr
=prestart_esum
-(p
-1)*startee
[i
].e
;
370 prestart_sigma
=startee
[i
].eav
-
371 sigmacorr
*sigmacorr
/(p
*(p
-1));
372 sigmacorr
=prestart_esum
/(p
-1)-
374 outee
[i
].esum
-=prestart_esum
;
376 outee
[i
].eav
=outee
[i
].eav
-prestart_sigma
-
377 sigmacorr
*sigmacorr
*((p
-1)*q
)/(q
-p
+1);
380 if((outee
[i
].eav
/(laststep
+step
+1))<(GMX_REAL_EPS
))
386 static void update_last_ee(t_energy
*lastee
, gmx_large_int_t laststep
,
387 t_energy
*ee
,gmx_large_int_t step
,int nre
)
391 update_ee(lastee
,laststep
,NULL
,0,ee
,step
,tmp
,nre
);
392 copy_ee(tmp
,lastee
,nre
);
396 static void update_ee_sum(int nre
,
397 gmx_large_int_t
*ee_sum_step
,
398 gmx_large_int_t
*ee_sum_nsteps
,
399 gmx_large_int_t
*ee_sum_nsum
,
401 t_enxframe
*fr
,int out_step
)
403 gmx_large_int_t nsteps
,nsum
,fr_nsum
;
406 nsteps
= *ee_sum_nsteps
;
417 ee_sum
[i
].esum
= fr
->ener
[i
].e
;
422 ee_sum
[i
].esum
= fr
->ener
[i
].esum
;
423 ee_sum
[i
].eav
= fr
->ener
[i
].eav
;
428 } else if (out_step
- *ee_sum_step
== nsteps
+ fr
->nsteps
) {
432 dsqr(ee_sum
[i
].esum
/nsum
433 - (ee_sum
[i
].esum
+ fr
->ener
[i
].e
)/(nsum
+ 1))*nsum
*(nsum
+ 1);
434 ee_sum
[i
].esum
+= fr
->ener
[i
].e
;
437 for(i
=0; i
<fr
->nre
; i
++) {
440 dsqr(ee_sum
[i
].esum
/nsum
441 - (ee_sum
[i
].esum
+ fr
->ener
[i
].esum
)/(nsum
+ fr
->nsum
))*
442 nsum
*(nsum
+ fr
->nsum
)/(double)fr
->nsum
;
443 ee_sum
[i
].esum
+= fr
->ener
[i
].esum
;
446 nsteps
+= fr
->nsteps
;
450 fprintf(stderr
,"\nWARNING: missing energy sums at time %f\n",fr
->t
);
456 *ee_sum_step
= out_step
;
457 *ee_sum_nsteps
= nsteps
;
461 int gmx_eneconv(int argc
,char *argv
[])
463 const char *desc
[] = {
464 "With [IT]multiple files[it] specified for the [TT]-f[tt] option:[BR]",
465 "Concatenates several energy files in sorted order.",
466 "In case of double time frames the one",
467 "in the later file is used. By specifying [TT]-settime[tt] you will be",
468 "asked for the start time of each file. The input files are taken",
469 "from the command line,",
470 "such that the command [TT]eneconv -o fixed.edr *.edr[tt] should do",
472 "With [IT]one file[it] specified for [TT]-f[tt]:[BR]",
473 "Reads one energy file and writes another, applying the [TT]-dt[tt],",
474 "[TT]-offset[tt], [TT]-t0[tt] and [TT]-settime[tt] options and",
475 "converting to a different format if necessary (indicated by file",
477 "[TT]-settime[tt] is applied first, then [TT]-dt[tt]/[TT]-offset[tt]",
478 "followed by [TT]-b[tt] and [TT]-e[tt] to select which frames to write."
480 const char *bugs
[] = {
481 "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."
483 ener_file_t in
=NULL
, out
=NULL
;
484 gmx_enxnm_t
*enm
=NULL
;
486 ener_file_t in
,out
=NULL
;
487 gmx_enxnm_t
*enm
=NULL
;
490 gmx_large_int_t ee_sum_step
=0,ee_sum_nsteps
,ee_sum_nsum
;
492 gmx_large_int_t lastfilestep
,laststep
,startstep
,startstep_file
=0;
494 int nre
,nremax
,this_nre
,nfile
,f
,i
,j
,kkk
,nset
,*set
=NULL
;
497 real
*readtime
,*settime
,timestep
,t1
,tadjust
;
498 char inputstring
[STRLEN
],*chptr
,buf
[22],buf2
[22],buf3
[22];
501 bool bNewFile
,bFirst
,bNewOutput
;
505 { efEDR
, "-f", NULL
, ffRDMULT
},
506 { efEDR
, "-o", "fixed", ffWRITE
},
509 #define NFILE asize(fnm)
511 static real delta_t
=0.0, toffset
=0,scalefac
=1;
512 static bool bSetTime
=FALSE
;
513 static bool bSort
=TRUE
,bError
=TRUE
;
514 static real begin
=-1;
518 { "-b", FALSE
, etREAL
, {&begin
},
519 "First time to use"},
520 { "-e", FALSE
, etREAL
, {&end
},
522 { "-dt", FALSE
, etREAL
, {&delta_t
},
523 "Only write out frame when t MOD dt = offset" },
524 { "-offset", FALSE
, etREAL
, {&toffset
},
525 "Time offset for -dt option" },
526 { "-settime", FALSE
, etBOOL
, {&bSetTime
},
527 "Change starting time interactively" },
528 { "-sort", FALSE
, etBOOL
, {&bSort
},
529 "Sort energy files (not frames)"},
530 { "-scalefac", FALSE
, etREAL
, {&scalefac
},
531 "Multiply energy component by this factor" },
532 { "-error", FALSE
, etBOOL
, {&bError
},
533 "Stop on errors in the file" }
536 CopyRight(stderr
,argv
[0]);
537 parse_common_args(&argc
,argv
,PCA_BE_NICE
,NFILE
,fnm
,asize(pa
),
538 pa
,asize(desc
),desc
,asize(bugs
),bugs
,&oenv
);
546 laststep
=startstep
=0;
548 nfile
= opt2fns(&fnms
,"-f",NFILE
,fnm
);
551 gmx_fatal(FARGS
,"No input files!");
553 snew(settime
,nfile
+1);
554 snew(readtime
,nfile
+1);
555 snew(cont_type
,nfile
+1);
557 nre
=scan_ene_files(fnms
,nfile
,readtime
,×tep
,&nremax
);
558 edit_files(fnms
,nfile
,readtime
,settime
,cont_type
,bSetTime
,bSort
);
568 snew(fro
->ener
,nremax
);
574 for(f
=0;f
<nfile
;f
++) {
577 in
=open_enx(fnms
[f
],"r");
579 do_enxnms(in
,&this_nre
,&enm
);
582 set
= select_it(nre
,enm
,&nset
);
584 /* write names to the output file */
585 out
=open_enx(opt2fn("-o",NFILE
,fnm
),"w");
586 do_enxnms(out
,&nre
,&enm
);
589 /* start reading from the next file */
590 while ((fro
->t
<= (settime
[f
+1] + GMX_REAL_EPS
)) &&
593 startstep_file
= fr
->step
;
594 tadjust
= settime
[f
] - fr
->t
;
595 if(cont_type
[f
+1]==TIME_LAST
) {
596 settime
[f
+1] = readtime
[f
+1]-readtime
[f
]+settime
[f
];
597 cont_type
[f
+1] = TIME_EXPLICIT
;
602 if (tadjust
+ fr
->t
<= last_t
) {
603 /* Skip this frame, since we already have it / past it */
605 fprintf(debug
,"fr->step %s, fr->t %.4f\n",
606 gmx_step_str(fr
->step
,buf
),fr
->t
);
607 fprintf(debug
,"tadjust %12.6e + fr->t %12.6e <= t %12.6e\n",
608 tadjust
,fr
->t
,last_t
);
613 fro
->step
= lastfilestep
+ fr
->step
- startstep_file
;
614 fro
->t
= tadjust
+ fr
->t
;
616 bWrite
= ((begin
<0 || (begin
>=0 && (fro
->t
>= begin
-GMX_REAL_EPS
))) &&
617 (end
<0 || (end
>=0 && (fro
->t
<= end
+GMX_REAL_EPS
))) &&
618 (fro
->t
<= settime
[f
+1]+0.5*timestep
));
622 "fr->step %s, fr->t %.4f, fro->step %s fro->t %.4f, w %d\n",
623 gmx_step_str(fr
->step
,buf
),fr
->t
,
624 gmx_step_str(fro
->step
,buf2
),fro
->t
,bWrite
);
628 if ((end
> 0) && (fro
->t
> end
+GMX_REAL_EPS
)) {
633 if (fro
->t
>= begin
-GMX_REAL_EPS
) {
636 startstep
= fr
->step
;
639 update_ee_sum(nre
,&ee_sum_step
,&ee_sum_nsteps
,&ee_sum_nsum
,ee_sum
,
644 /* determine if we should write it */
645 if (bWrite
&& (delta_t
==0 || bRmod(fro
->t
,toffset
,delta_t
))) {
646 laststep
= fro
->step
;
650 fprintf(stderr
,"\nContinue writing frames from t=%g, step=%s\n",
651 fro
->t
,gmx_step_str(fro
->step
,buf
));
654 /* Copy the energies */
655 for(i
=0; i
<nre
; i
++) {
656 fro
->ener
[i
].e
= fr
->ener
[i
].e
;
659 fro
->nsteps
= ee_sum_nsteps
;
661 if (ee_sum_nsum
<= 1) {
664 fro
->nsum
= ee_sum_nsum
;
665 /* Copy the energy sums */
666 for(i
=0; i
<nre
; i
++) {
667 fro
->ener
[i
].esum
= ee_sum
[i
].esum
;
668 fro
->ener
[i
].eav
= ee_sum
[i
].eav
;
671 /* We wrote the energies, so reset the counts */
676 for(kkk
=0; kkk
<nset
; kkk
++) {
677 fro
->ener
[set
[kkk
]].e
*= scalefac
;
679 fro
->ener
[set
[kkk
]].eav
*= scalefac
*scalefac
;
680 fro
->ener
[set
[kkk
]].esum
*= scalefac
;
684 /* Copy restraint stuff */
685 fro
->ndisre
= fr
->ndisre
;
686 fro
->disre_rm3tav
= fr
->disre_rm3tav
;
687 fro
->disre_rt
= fr
->disre_rt
;
688 fro
->nblock
= fr
->nblock
;
690 fro
->block
= fr
->block
;
693 if (noutfr
% 1000 == 0)
694 fprintf(stderr
,"Writing frame time %g ",fro
->t
);
699 printf("\nLast step written from %s: t %g, step %s\n",
700 fnms
[f
],last_t
,gmx_step_str(laststep
,buf
));
701 lastfilestep
= laststep
;
703 /* set the next time from the last in previous file */
704 if (cont_type
[f
+1]==TIME_CONTINUE
) {
705 settime
[f
+1] = fro
->t
;
706 /* in this case we have already written the last frame of
707 * previous file, so update begin to avoid doubling it
708 * with the start of the next file
710 begin
= fro
->t
+0.5*timestep
;
711 /* cont_type[f+1]==TIME_EXPLICIT; */
714 if ((fro
->t
< end
) && (f
< nfile
-1) &&
715 (fro
->t
< settime
[f
+1]-1.5*timestep
))
717 "\nWARNING: There might be a gap around t=%g\n",fro
->t
);
719 /* move energies to lastee */
721 free_enxnms(this_nre
,enm
);
723 fprintf(stderr
,"\n");
726 fprintf(stderr
,"No frames written.\n");
728 fprintf(stderr
,"Last frame written was at step %s, time %f\n",
729 gmx_step_str(fro
->step
,buf
),fro
->t
);
730 fprintf(stderr
,"Wrote %d frames\n",noutfr
);