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
65 #define TIME_EXPLICIT 0
66 #define TIME_CONTINUE 1
71 #define FLAGS (TRX_READ_X | TRX_READ_V | TRX_READ_F)
73 static void scan_trj_files(char **fnms
, int nfiles
, real
*readtime
,
74 real
*timestep
, atom_id imax
,
75 const output_env_t oenv
)
77 /* Check start time of all files */
78 int i
, status
, natoms
= 0;
83 for (i
= 0; i
< nfiles
; i
++)
85 ok
= read_first_frame(oenv
, &status
, fnms
[i
], &fr
, FLAGS
);
88 gmx_fatal(FARGS
,"\nCouldn't read frame from file." );
94 fprintf(stderr
,"\nWARNING: Couldn't find a time in the frame.\n");
105 if(natoms
!=fr
.natoms
)
106 gmx_fatal(FARGS
,"\nDifferent numbers of atoms (%d/%d) in files",
111 if(fr
.natoms
<= imax
)
113 gmx_fatal(FARGS
,"\nNot enough atoms (%d) for index group (%d)",
118 ok
=read_next_frame(oenv
,status
,&fr
);
121 timestep
[i
] = fr
.time
- readtime
[i
];
130 fprintf(stderr
,"\n");
135 static void sort_files(char **fnms
, real
*settime
, int nfile
)
141 for (i
= 0; i
< nfile
; i
++)
144 for (j
= i
+ 1; j
< nfile
; j
++)
146 if (settime
[j
] < settime
[minidx
])
153 timeswap
= settime
[i
];
154 settime
[i
] = settime
[minidx
];
155 settime
[minidx
] = timeswap
;
157 fnms
[i
] = fnms
[minidx
];
158 fnms
[minidx
] = chptr
;
163 static void edit_files(char **fnms
, int nfiles
, real
*readtime
, real
*timestep
,
164 real
*settime
, int *cont_type
, bool bSetTime
,
165 bool bSort
, const output_env_t oenv
)
169 char inputstring
[STRLEN
], *chptr
;
173 fprintf(stderr
, "\n\nEnter the new start time (%s) for each file.\n"
174 "There are two special options, both disable sorting:\n\n"
175 "c (continue) - The start time is taken from the end\n"
176 "of the previous file. Use it when your continuation run\n"
177 "restarts with t=0.\n\n"
178 "l (last) - The time in this file will be changed the\n"
179 "same amount as in the previous. Use it when the time in the\n"
180 "new run continues from the end of the previous one,\n"
181 "since this takes possible overlap into account.\n\n",
182 get_time_unit(oenv
));
186 " File Current start (%s) New start (%s)\n"
187 "---------------------------------------------------------\n",
188 get_time_unit(oenv
), get_time_unit(oenv
));
190 for (i
= 0; i
< nfiles
; i
++)
192 fprintf(stderr
, "%25s %10.3f %s ", fnms
[i
],
193 conv_time(oenv
, readtime
[i
]), get_time_unit(oenv
));
197 if (NULL
== fgets(inputstring
, STRLEN
- 1, stdin
))
199 gmx_fatal(FARGS
,"Error reading user input" );
202 inputstring
[strlen(inputstring
)-1]=0;
204 if(inputstring
[0]=='c' || inputstring
[0]=='C')
206 cont_type
[i
]=TIME_CONTINUE
;
211 else if(inputstring
[0]=='l' ||
214 cont_type
[i
]=TIME_LAST
;
221 settime
[i
]=strtod(inputstring
,&chptr
)*
222 get_time_invfactor(oenv
);
223 if(chptr
==inputstring
)
225 fprintf(stderr
,"'%s' not recognized as a floating point number, 'c' or 'l'. "
226 "Try again: ",inputstring
);
229 cont_type
[i
]=TIME_EXPLICIT
;
235 if(cont_type
[0]!=TIME_EXPLICIT
)
237 cont_type
[0]=TIME_EXPLICIT
;
243 for(i
=0;i
<nfiles
;i
++)
245 settime
[i
]=readtime
[i
];
250 fprintf(stderr
,"Sorting disabled.\n");
254 sort_files(fnms
,settime
,nfiles
);
256 /* Write out the new order and start times */
257 fprintf(stderr
,"\nSummary of files and start times used:\n\n"
258 " File Start time Time step\n"
259 "---------------------------------------------------------\n");
260 for(i
=0;i
<nfiles
;i
++)
264 fprintf(stderr
,"%25s %10.3f %s %10.3f %s",
266 conv_time(oenv
,settime
[i
]),get_time_unit(oenv
),
267 conv_time(oenv
,timestep
[i
]),get_time_unit(oenv
));
269 cont_type
[i
-1]==TIME_EXPLICIT
&& settime
[i
]==settime
[i
-1] )
270 fprintf(stderr
," WARNING: same Start time as previous");
271 fprintf(stderr
,"\n");
274 fprintf(stderr
,"%25s Continue from last file\n",fnms
[i
]);
277 fprintf(stderr
,"%25s Change by same amount as last file\n",
281 fprintf(stderr
,"\n");
283 settime
[nfiles
]=FLT_MAX
;
284 cont_type
[nfiles
]=TIME_EXPLICIT
;
285 readtime
[nfiles
]=FLT_MAX
;
288 static void do_demux(int nset
, char *fnms
[], char *fnms_out
[], int nval
,
289 real
**value
, real
*time
, real dt_remd
, int isize
,
290 atom_id index
[], real dt
, const output_env_t oenv
)
292 int i
, j
, k
, natoms
, nnn
;
295 real t
, first_time
= 0;
303 for (i
= 0; (i
< nset
); i
++)
305 nnn
= read_first_frame(oenv
, &(fp_in
[i
]), fnms
[i
], &(trx
[i
]),
310 first_time
= trx
[i
].time
;
312 else if (natoms
!= nnn
)
314 gmx_fatal(FARGS
,"Trajectory file %s has %d atoms while previous trajs had %d atoms" ,fnms
[i
],nnn
,natoms
);
320 else if (t
!= trx
[i
].time
)
322 gmx_fatal(FARGS
,"Trajectory file %s has time %f while previous trajs had time %f",fnms
[i
],trx
[i
].time
,t
);
327 for(i
=0; (i
<nset
); i
++)
329 fp_out
[i
] = open_trx(fnms_out
[i
],"w");
332 if (gmx_nint(time
[k
] - t
) != 0)
334 gmx_fatal(FARGS
,"First time in demuxing table does not match trajectories");
338 while ((k
+1 < nval
) && ((trx
[0].time
- time
[k
+1]) > dt_remd
*0.1))
344 fprintf(debug
,"trx[0].time = %g, time[k] = %g\n",trx
[0].time
,time
[k
]);
346 for(i
=0; (i
<nset
); i
++)
350 for(i
=0; (i
<nset
); i
++)
352 j
= gmx_nint(value
[i
][k
]);
353 range_check(j
,0,nset
);
356 gmx_fatal(FARGS
,"Demuxing the same replica %d twice at time %f",
361 if (dt
==0 || bRmod(trx
[i
].time
,first_time
,dt
))
365 write_trxframe_indexed(fp_out
[j
],&trx
[i
],isize
,index
,NULL
);
369 write_trxframe(fp_out
[j
],&trx
[i
],NULL
);
375 for(i
=0; (i
<nset
); i
++)
377 bCont
= bCont
&& read_next_frame(oenv
,fp_in
[i
],&trx
[i
]);
381 for(i
=0; (i
<nset
); i
++)
384 close_trx(fp_out
[i
]);
388 int gmx_trjcat(int argc
, char *argv
[])
393 "trjcat concatenates several input trajectory files in sorted order. ",
394 "In case of double time frames the one in the later file is used. ",
395 "By specifying [TT]-settime[tt] you will be asked for the start time ",
396 "of each file. The input files are taken from the command line, ",
397 "such that a command like [TT]trjcat -o fixed.trr *.trr[tt] should do ",
398 "the trick. Using [TT]-cat[tt] you can simply paste several files ",
399 "together without removal of frames with identical time stamps.[PAR]",
400 "One important option is inferred when the output file is amongst the",
401 "input files. In that case that particular file will be appended to",
402 "which implies you do not need to store double the amount of data.",
403 "Obviously the file to append to has to be the one with lowest starting",
404 "time since one can only append at the end of a file.[PAR]",
405 "If the [TT]-demux[tt] option is given, the N trajectories that are",
406 "read, are written in another order as specified in the xvg file."
407 "The xvg file should contain something like:[PAR]",
410 "Where the first number is the time, and subsequent numbers point to",
411 "trajectory indices.",
412 "The frames corresponding to the numbers present at the first line",
413 "are collected into the output trajectory. If the number of frames in",
414 "the trajectory does not match that in the xvg file then the program",
415 "tries to be smart. Beware." };
416 static bool bVels
= TRUE
;
418 static bool bCat
= FALSE
;
419 static bool bSort
= TRUE
;
420 static bool bKeepLast
= FALSE
;
421 static bool bKeepLastAppend
= FALSE
;
422 static bool bOverwrite
= FALSE
;
423 static bool bSetTime
= FALSE
;
425 static real begin
= -1;
426 static real end
= -1;
432 { "-b", FALSE
, etTIME
,
433 { &begin
}, "First time to use (%t)" },
434 { "-e", FALSE
, etTIME
,
435 { &end
}, "Last time to use (%t)" },
436 { "-dt", FALSE
, etTIME
,
437 { &dt
}, "Only write frame when t MOD dt = first time (%t)" },
438 { "-prec", FALSE
, etINT
,
439 { &prec
}, "Precision for .xtc and .gro writing in number of decimal places" },
440 { "-vel", FALSE
, etBOOL
,
441 { &bVels
}, "Read and write velocities if possible" },
442 { "-settime", FALSE
, etBOOL
,
443 { &bSetTime
}, "Change starting time interactively" },
444 { "-sort", FALSE
, etBOOL
,
445 { &bSort
}, "Sort trajectory files (not frames)" },
446 { "-keeplast", FALSE
, etBOOL
,
447 { &bKeepLast
}, "keep overlapping frames at end of trajectory" },
448 { "-overwrite", FALSE
, etBOOL
,
449 { &bOverwrite
}, "overwrite overlapping frames during appending" },
450 { "-cat", FALSE
, etBOOL
,
451 { &bCat
}, "do not discard double time frames" } };
452 #define npargs asize(pa)
453 int status
, ftpin
, i
, frame
, frame_out
, step
= 0, trjout
= 0;
456 t_trxframe fr
, frout
;
457 char **fnms
, **fnms_out
, *in_file
, *out_file
;
460 bool bNewFile
, bIndex
, bWrite
;
461 int earliersteps
, nfile_in
, nfile_out
, *cont_type
, last_ok_step
;
462 real
*readtime
, *timest
, *settime
;
463 real first_time
= 0, lasttime
= NOTSET
, last_ok_t
= -1, timestep
;
464 real last_frame_time
, searchtime
;
466 atom_id
*index
= NULL
, imax
;
468 real
**val
= NULL
, *t
= NULL
, dt_remd
;
474 { efTRX
, "-f", NULL
, ffRDMULT
},
475 { efTRO
, "-o", NULL
, ffWRMULT
},
476 { efNDX
, "-n", "index", ffOPTRD
},
477 { efXVG
, "-demux", "remd", ffOPTRD
} };
479 #define NFILE asize(fnm)
481 CopyRight(stderr
, argv
[0]);
482 parse_common_args(&argc
, argv
, PCA_BE_NICE
| PCA_TIME_UNIT
, NFILE
, fnm
,
483 asize(pa
), pa
, asize(desc
), desc
, 0, NULL
, &oenv
);
485 bIndex
= ftp2bSet(efNDX
, NFILE
, fnm
);
486 bDeMux
= ftp2bSet(efXVG
, NFILE
, fnm
);
487 bSort
= bSort
&& !bDeMux
;
492 printf("Select group for output\n");
493 rd_index(ftp2fn(efNDX
, NFILE
, fnm
), 1, &isize
, &index
, &grpname
);
496 for (i
= 1; i
< isize
; i
++)
498 imax
= max(imax
, index
[i
]);
505 val
= read_xvg_time(opt2fn("-demux", NFILE
, fnm
), TRUE
,
506 opt2parg_bSet("-b", npargs
, pa
), begin
,
507 opt2parg_bSet("-e", npargs
, pa
), end
, 1, &nset
, &n
,
509 printf("Read %d sets of %d points, dt = %g\n\n", nset
, n
, dt_remd
);
512 fprintf(debug
, "Dump of replica_index.xvg\n");
513 for (i
= 0; (i
< n
); i
++)
515 fprintf(debug
, "%10g", t
[i
]);
516 for (j
= 0; (j
< nset
); j
++)
518 fprintf(debug
, " %3d", gmx_nint(val
[j
][i
]));
520 fprintf(debug
, "\n");
524 /* prec is in nr of decimal places, xtcprec is a multiplication factor: */
526 for (i
= 0; i
< prec
; i
++)
531 nfile_in
= opt2fns(&fnms
, "-f", NFILE
, fnm
);
534 gmx_fatal(FARGS
,"No input files!" );
537 if (bDeMux
&& (nfile_in
!= nset
))
539 gmx_fatal(FARGS
,"You have specified %d files and %d entries in the demux table",nfile_in
,nset
);
542 nfile_out
= opt2fns(&fnms_out
,"-o",NFILE
,fnm
);
545 gmx_fatal(FARGS
,"No output files!");
547 if ((nfile_out
> 1) && !bDeMux
)
549 gmx_fatal(FARGS
,"Don't know what to do with more than 1 output file if not demultiplexing");
551 else if (bDeMux
&& (nfile_out
!= nset
) && (nfile_out
!= 1))
553 gmx_fatal(FARGS
,"Number of output files should be 1 or %d (#input files), not %d",nset
,nfile_out
);
557 if (nfile_out
!= nset
)
559 char *buf
= strdup(fnms_out
[0]);
561 for(i
=0; (i
<nset
); i
++)
563 snew(fnms_out
[i
],strlen(buf
)+32);
564 sprintf(fnms_out
[i
],"%d_%s",i
,buf
);
567 do_demux(nfile_in
,fnms
,fnms_out
,n
,val
,t
,dt_remd
,isize
,index
,dt
,oenv
);
571 snew(readtime
,nfile_in
+1);
572 snew(timest
,nfile_in
+1);
573 scan_trj_files(fnms
,nfile_in
,readtime
,timest
,imax
,oenv
);
575 snew(settime
,nfile_in
+1);
576 snew(cont_type
,nfile_in
+1);
577 edit_files(fnms
,nfile_in
,readtime
,timest
,settime
,cont_type
,bSetTime
,bSort
,
580 /* Check whether the output file is amongst the input files
581 * This has to be done after sorting etc.
583 out_file
= fnms_out
[0];
585 for(i
=0; ((i
<nfile_in
) && (n_append
==-1)); i
++)
587 if (strcmp(fnms
[i
],out_file
) == 0)
593 fprintf(stderr
,"Will append to %s rather than creating a new file\n",
596 else if (n_append
!= -1)
598 gmx_fatal(FARGS
,"Can only append to the first file which is %s (not %s)",
603 /* Not checking input format, could be dangerous :-) */
604 /* Not checking output format, equally dangerous :-) */
608 /* the default is not to change the time at all,
609 * but this is overridden by the edit_files routine
615 trxout
= open_trx(out_file
,"w");
616 memset(&frout
,0,sizeof(frout
));
620 if (!read_first_frame(oenv
,&status
,out_file
,&fr
,FLAGS
))
621 gmx_fatal(FARGS
,"Reading first frame from %s",out_file
);
622 if (!bKeepLast
&& !bOverwrite
)
624 fprintf(stderr
, "\n\nWARNING: Appending without -overwrite implies -keeplast "
625 "between the first two files. \n"
626 "If the trajectories have an overlap and have not been written binary \n"
627 "reproducible this will produce an incorrect trajectory!\n\n");
629 /* Fails if last frame is incomplete
630 * We can't do anything about it without overwriting
632 if (gmx_fio_getftp(status
) == efXTC
)
634 lasttime
= xdr_xtc_get_last_frame_time(gmx_fio_getfp(status
),gmx_fio_getxdr(status
),fr
.natoms
,&bOK
);
638 gmx_fatal(FARGS
,"Error reading last frame. Maybe seek not supported." );
643 while (read_next_frame(oenv
,status
,&fr
))
647 bKeepLastAppend
= TRUE
;
649 trxout
= open_trx(out_file
,"a");
653 if (gmx_fio_getftp(status
) != efXTC
) {
654 gmx_fatal(FARGS
,"Overwrite only supported for XTC." );
656 last_frame_time
= xdr_xtc_get_last_frame_time(gmx_fio_getfp(status
),gmx_fio_getxdr(status
),fr
.natoms
,&bOK
);
659 gmx_fatal(FARGS
,"Error reading last frame. Maybe seek not supported." );
661 /* xtc_seek_time broken for trajectories containing only 1 or 2 frames
662 * or when seek time = 0 */
663 if (nfile_in
>1 && settime
[1]<last_frame_time
+timest
[0]*0.5)
665 /* Jump to one time-frame before the start of next
667 searchtime
= settime
[1]-timest
[0]*1.25;
671 searchtime
= last_frame_time
;
673 if (xtc_seek_time(searchtime
,status
,fr
.natoms
))
675 gmx_fatal(FARGS
,"Error seeking to append position.");
677 read_next_frame(oenv
,status
,&fr
);
678 if (fabs(searchtime
- fr
.time
) > timest
[0]*0.5)
680 gmx_fatal(FARGS
,"Error seeking: attempted to seek to %f but got %f.",
684 fpos
= gmx_fio_ftell(status
);
686 trxout
= open_trx(out_file
,"r+");
687 if (gmx_fio_seek(trxout
,fpos
)) {
688 gmx_fatal(FARGS
,"Error seeking to append position.");
691 printf("\n Will append after %f \n",lasttime
);
694 /* Lets stitch up some files */
695 timestep
= timest
[0];
696 for(i
=n_append
+1; (i
<nfile_in
); i
++)
700 /* set the next time from the last frame in previous file */
705 if(cont_type
[i
]==TIME_CONTINUE
)
708 begin
+= 0.5*timestep
;
709 settime
[i
]=frout
.time
;
710 cont_type
[i
]=TIME_EXPLICIT
;
712 else if(cont_type
[i
]==TIME_LAST
)
715 begin
+= 0.5*timestep
;
717 /* Or, if the time in the next part should be changed by the
718 * same amount, start at half a timestep from the last time
719 * so we dont repeat frames.
721 /* I don't understand the comment above, but for all the cases
722 * I tried the code seems to work properly. B. Hess 2008-4-2.
725 /* Or, if time is set explicitly, we check for overlap/gap */
726 if(cont_type
[i
]==TIME_EXPLICIT
)
728 if( ( i
< nfile_in
) &&
729 ( frout
.time
< settime
[i
]-1.5*timestep
) )
731 fprintf(stderr
, "WARNING: Frames around t=%f %s have a different "
732 "spacing than the rest,\n"
733 "might be a gap or overlap that couldn't be corrected "
734 "automatically.\n",conv_time(oenv
,frout
.time
),
735 get_time_unit(oenv
));
740 /* if we don't have a timestep in the current file, use the old one */
741 if ( timest
[i
] != 0 )
743 timestep
= timest
[i
];
745 read_first_frame(oenv
,&status
,fnms
[i
],&fr
,FLAGS
);
749 fprintf(stderr
,"\nWARNING: Couldn't find a time in the frame.\n");
752 if(cont_type
[i
]==TIME_EXPLICIT
)
754 t_corr
=settime
[i
]-fr
.time
;
756 /* t_corr is the amount we want to change the time.
757 * If the user has chosen not to change the time for
758 * this part of the trajectory t_corr remains at
759 * the value it had in the last part, changing this
760 * by the same amount.
761 * If no value was given for the first trajectory part
762 * we let the time start at zero, see the edit_files routine.
768 if (lasttime
!= NOTSET
)
770 printf("lasttime %g\n", lasttime
);
775 /* copy the input frame to the output frame */
777 /* set the new time by adding the correct calculated above */
778 frout
.time
+= t_corr
;
779 /* quit if we have reached the end of what should be written */
780 if((end
> 0) && (frout
.time
> end
+GMX_REAL_EPS
))
786 /* determine if we should write this frame (dt is handled elsewhere) */
787 if (bCat
) /* write all frames of all files */
791 else if ( bKeepLast
|| (bKeepLastAppend
&& i
==1))
792 /* write till last frame of this traj
793 and skip first frame(s) of next traj */
795 bWrite
= ( frout
.time
> lasttime
+0.5*timestep
);
797 else /* write till first frame of next traj */
799 bWrite
= ( frout
.time
< settime
[i
+1]-0.5*timestep
);
802 if( bWrite
&& (frout
.time
>= begin
) )
806 first_time
= frout
.time
;
807 lasttime
= frout
.time
;
808 if (dt
==0 || bRmod(frout
.time
,first_time
,dt
))
811 last_ok_t
=frout
.time
;
814 fprintf(stderr
,"\nContinue writing frames from %s t=%g %s, "
816 fnms
[i
],conv_time(oenv
,frout
.time
),get_time_unit(oenv
),
823 write_trxframe_indexed(trxout
,&frout
,isize
,index
,NULL
);
827 write_trxframe(trxout
,&frout
,NULL
);
829 if ( ((frame
% 10) == 0) || (frame
< 10) )
831 fprintf(stderr
," -> frame %6d time %8.3f %s \r",
832 frame_out
,conv_time(oenv
,frout
.time
),get_time_unit(oenv
));
836 } while( read_next_frame(oenv
,status
,&fr
));
846 fprintf(stderr
,"\nLast frame written was %d, time %f %s\n",
847 frame
,conv_time(oenv
,last_ok_t
),get_time_unit(oenv
));