Merge release-5-0 into master
[alexxy/gromacs.git] / src / gromacs / gmxana / gmx_trjcat.c
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, 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 #ifdef HAVE_CONFIG_H
38 #include <config.h>
39 #endif
40
41 #include <math.h>
42 #include <stdlib.h>
43 #include <string.h>
44
45 #include "macros.h"
46 #include "gromacs/utility/smalloc.h"
47 #include "typedefs.h"
48 #include "gromacs/fileio/gmxfio.h"
49 #include "gromacs/fileio/tpxio.h"
50 #include "gromacs/fileio/trxio.h"
51 #include "gromacs/fileio/trnio.h"
52 #include "gromacs/fileio/tngio.h"
53 #include "gromacs/fileio/tngio_for_tools.h"
54 #include "gromacs/commandline/pargs.h"
55 #include "gromacs/utility/futil.h"
56 #include "gromacs/fileio/pdbio.h"
57 #include "gromacs/fileio/confio.h"
58 #include "names.h"
59 #include "index.h"
60 #include "gromacs/math/vec.h"
61 #include "gromacs/fileio/xtcio.h"
62 #include "rmpbc.h"
63 #include "pbc.h"
64 #include "gromacs/fileio/xvgr.h"
65 #include "gmx_ana.h"
66
67 #include "gromacs/utility/fatalerror.h"
68
69 #define TIME_EXPLICIT 0
70 #define TIME_CONTINUE 1
71 #define TIME_LAST     2
72 #ifndef FLT_MAX
73 #define FLT_MAX 1e36
74 #endif
75 #define FLAGS (TRX_READ_X | TRX_READ_V | TRX_READ_F)
76
77 static void scan_trj_files(char **fnms, int nfiles, real *readtime,
78                            real *timestep, atom_id imax,
79                            const output_env_t oenv)
80 {
81     /* Check start time of all files */
82     int          i, natoms = 0;
83     t_trxstatus *status;
84     real         t;
85     t_trxframe   fr;
86     gmx_bool     ok;
87
88     for (i = 0; i < nfiles; i++)
89     {
90         ok = read_first_frame(oenv, &status, fnms[i], &fr, FLAGS);
91
92         if (!ok)
93         {
94             gmx_fatal(FARGS, "\nCouldn't read frame from file." );
95         }
96         if (fr.bTime)
97         {
98             readtime[i] = fr.time;
99         }
100         else
101         {
102             readtime[i] = 0;
103             fprintf(stderr, "\nWARNING: Couldn't find a time in the frame.\n");
104         }
105
106         if (i == 0)
107         {
108             natoms = fr.natoms;
109         }
110         else
111         {
112             if (imax == NO_ATID)
113             {
114                 if (natoms != fr.natoms)
115                 {
116                     gmx_fatal(FARGS, "\nDifferent numbers of atoms (%d/%d) in files",
117                               natoms, fr.natoms);
118                 }
119             }
120             else
121             {
122                 if (fr.natoms <= imax)
123                 {
124                     gmx_fatal(FARGS, "\nNot enough atoms (%d) for index group (%d)",
125                               fr.natoms, imax);
126                 }
127             }
128         }
129         ok = read_next_frame(oenv, status, &fr);
130         if (ok && fr.bTime)
131         {
132             timestep[i] = fr.time - readtime[i];
133         }
134         else
135         {
136             timestep[i] = 0;
137         }
138
139         close_trj(status);
140         if (fr.bX)
141         {
142             sfree(fr.x);
143         }
144         if (fr.bV)
145         {
146             sfree(fr.v);
147         }
148         if (fr.bF)
149         {
150             sfree(fr.f);
151         }
152     }
153     fprintf(stderr, "\n");
154
155 }
156
157 static void sort_files(char **fnms, real *settime, int nfile)
158 {
159     int   i, j, minidx;
160     real  timeswap;
161     char *chptr;
162
163     for (i = 0; i < nfile; i++)
164     {
165         minidx = i;
166         for (j = i + 1; j < nfile; j++)
167         {
168             if (settime[j] < settime[minidx])
169             {
170                 minidx = j;
171             }
172         }
173         if (minidx != i)
174         {
175             timeswap        = settime[i];
176             settime[i]      = settime[minidx];
177             settime[minidx] = timeswap;
178             chptr           = fnms[i];
179             fnms[i]         = fnms[minidx];
180             fnms[minidx]    = chptr;
181         }
182     }
183 }
184
185 static void edit_files(char **fnms, int nfiles, real *readtime, real *timestep,
186                        real *settime, int *cont_type, gmx_bool bSetTime,
187                        gmx_bool bSort, const output_env_t oenv)
188 {
189     int      i;
190     gmx_bool ok;
191     char     inputstring[STRLEN], *chptr;
192
193     if (bSetTime)
194     {
195         fprintf(stderr, "\n\nEnter the new start time (%s) for each file.\n"
196                 "There are two special options, both disable sorting:\n\n"
197                 "c (continue) - The start time is taken from the end\n"
198                 "of the previous file. Use it when your continuation run\n"
199                 "restarts with t=0.\n\n"
200                 "l (last) - The time in this file will be changed the\n"
201                 "same amount as in the previous. Use it when the time in the\n"
202                 "new run continues from the end of the previous one,\n"
203                 "since this takes possible overlap into account.\n\n",
204                 output_env_get_time_unit(oenv));
205
206         fprintf(
207                 stderr,
208                 "          File             Current start (%s)  New start (%s)\n"
209                 "---------------------------------------------------------\n",
210                 output_env_get_time_unit(oenv), output_env_get_time_unit(oenv));
211
212         for (i = 0; i < nfiles; i++)
213         {
214             fprintf(stderr, "%25s   %10.3f %s          ", fnms[i],
215                     output_env_conv_time(oenv, readtime[i]), output_env_get_time_unit(oenv));
216             ok = FALSE;
217             do
218             {
219                 if (NULL == fgets(inputstring, STRLEN - 1, stdin))
220                 {
221                     gmx_fatal(FARGS, "Error reading user input" );
222                 }
223
224                 inputstring[strlen(inputstring)-1] = 0;
225
226                 if (inputstring[0] == 'c' || inputstring[0] == 'C')
227                 {
228                     cont_type[i] = TIME_CONTINUE;
229                     bSort        = FALSE;
230                     ok           = TRUE;
231                     settime[i]   = FLT_MAX;
232                 }
233                 else if (inputstring[0] == 'l' ||
234                          inputstring[0] == 'L')
235                 {
236                     cont_type[i] = TIME_LAST;
237                     bSort        = FALSE;
238                     ok           = TRUE;
239                     settime[i]   = FLT_MAX;
240                 }
241                 else
242                 {
243                     settime[i] = strtod(inputstring, &chptr)*
244                         output_env_get_time_invfactor(oenv);
245                     if (chptr == inputstring)
246                     {
247                         fprintf(stderr, "'%s' not recognized as a floating point number, 'c' or 'l'. "
248                                 "Try again: ", inputstring);
249                     }
250                     else
251                     {
252                         cont_type[i] = TIME_EXPLICIT;
253                         ok           = TRUE;
254                     }
255                 }
256             }
257             while (!ok);
258         }
259         if (cont_type[0] != TIME_EXPLICIT)
260         {
261             cont_type[0] = TIME_EXPLICIT;
262             settime[0]   = 0;
263         }
264     }
265     else
266     {
267         for (i = 0; i < nfiles; i++)
268         {
269             settime[i] = readtime[i];
270         }
271     }
272     if (!bSort)
273     {
274         fprintf(stderr, "Sorting disabled.\n");
275     }
276     else
277     {
278         sort_files(fnms, settime, nfiles);
279     }
280     /* Write out the new order and start times */
281     fprintf(stderr, "\nSummary of files and start times used:\n\n"
282             "          File                Start time       Time step\n"
283             "---------------------------------------------------------\n");
284     for (i = 0; i < nfiles; i++)
285     {
286         switch (cont_type[i])
287         {
288             case TIME_EXPLICIT:
289                 fprintf(stderr, "%25s   %10.3f %s   %10.3f %s",
290                         fnms[i],
291                         output_env_conv_time(oenv, settime[i]), output_env_get_time_unit(oenv),
292                         output_env_conv_time(oenv, timestep[i]), output_env_get_time_unit(oenv));
293                 if (i > 0 &&
294                     cont_type[i-1] == TIME_EXPLICIT && settime[i] == settime[i-1])
295                 {
296                     fprintf(stderr, " WARNING: same Start time as previous");
297                 }
298                 fprintf(stderr, "\n");
299                 break;
300             case TIME_CONTINUE:
301                 fprintf(stderr, "%25s        Continue from last file\n", fnms[i]);
302                 break;
303             case TIME_LAST:
304                 fprintf(stderr, "%25s        Change by same amount as last file\n",
305                         fnms[i]);
306                 break;
307         }
308     }
309     fprintf(stderr, "\n");
310
311     settime[nfiles]   = FLT_MAX;
312     cont_type[nfiles] = TIME_EXPLICIT;
313     readtime[nfiles]  = FLT_MAX;
314 }
315
316 static void do_demux(int nset, char *fnms[], char *fnms_out[], int nval,
317                      real **value, real *time, real dt_remd, int isize,
318                      atom_id index[], real dt, const output_env_t oenv)
319 {
320     int           i, j, k, natoms, nnn;
321     t_trxstatus **fp_in, **fp_out;
322     gmx_bool      bCont, *bSet;
323     real          t, first_time = 0;
324     t_trxframe   *trx;
325
326     snew(fp_in, nset);
327     snew(trx, nset);
328     snew(bSet, nset);
329     natoms = -1;
330     t      = -1;
331     for (i = 0; (i < nset); i++)
332     {
333         nnn = read_first_frame(oenv, &(fp_in[i]), fnms[i], &(trx[i]),
334                                TRX_NEED_X);
335         if (natoms == -1)
336         {
337             natoms     = nnn;
338             first_time = trx[i].time;
339         }
340         else if (natoms != nnn)
341         {
342             gmx_fatal(FARGS, "Trajectory file %s has %d atoms while previous trajs had %d atoms", fnms[i], nnn, natoms);
343         }
344         if (t == -1)
345         {
346             t = trx[i].time;
347         }
348         else if (t != trx[i].time)
349         {
350             gmx_fatal(FARGS, "Trajectory file %s has time %f while previous trajs had time %f", fnms[i], trx[i].time, t);
351         }
352     }
353
354     snew(fp_out, nset);
355     for (i = 0; (i < nset); i++)
356     {
357         fp_out[i] = open_trx(fnms_out[i], "w");
358     }
359     k = 0;
360     if (gmx_nint(time[k] - t) != 0)
361     {
362         gmx_fatal(FARGS, "First time in demuxing table does not match trajectories");
363     }
364     do
365     {
366         while ((k+1 < nval) && ((trx[0].time - time[k+1]) > dt_remd*0.1))
367         {
368             k++;
369         }
370         if (debug)
371         {
372             fprintf(debug, "trx[0].time = %g, time[k] = %g\n", trx[0].time, time[k]);
373         }
374         for (i = 0; (i < nset); i++)
375         {
376             bSet[i] = FALSE;
377         }
378         for (i = 0; (i < nset); i++)
379         {
380             j = gmx_nint(value[i][k]);
381             range_check(j, 0, nset);
382             if (bSet[j])
383             {
384                 gmx_fatal(FARGS, "Demuxing the same replica %d twice at time %f",
385                           j, trx[0].time);
386             }
387             bSet[j] = TRUE;
388
389             if (dt == 0 || bRmod(trx[i].time, first_time, dt))
390             {
391                 if (index)
392                 {
393                     write_trxframe_indexed(fp_out[j], &trx[i], isize, index, NULL);
394                 }
395                 else
396                 {
397                     write_trxframe(fp_out[j], &trx[i], NULL);
398                 }
399             }
400         }
401
402         bCont = (k < nval);
403         for (i = 0; (i < nset); i++)
404         {
405             bCont = bCont && read_next_frame(oenv, fp_in[i], &trx[i]);
406         }
407     }
408     while (bCont);
409
410     for (i = 0; (i < nset); i++)
411     {
412         close_trx(fp_in[i]);
413         close_trx(fp_out[i]);
414     }
415 }
416
417 int gmx_trjcat(int argc, char *argv[])
418 {
419     const char     *desc[] =
420     {
421         "[THISMODULE] concatenates several input trajectory files in sorted order. ",
422         "In case of double time frames the one in the later file is used. ",
423         "By specifying [TT]-settime[tt] you will be asked for the start time ",
424         "of each file. The input files are taken from the command line, ",
425         "such that a command like [TT]gmx trjcat -f *.trr -o fixed.trr[tt] should do ",
426         "the trick. Using [TT]-cat[tt], you can simply paste several files ",
427         "together without removal of frames with identical time stamps.[PAR]",
428         "One important option is inferred when the output file is amongst the",
429         "input files. In that case that particular file will be appended to",
430         "which implies you do not need to store double the amount of data.",
431         "Obviously the file to append to has to be the one with lowest starting",
432         "time since one can only append at the end of a file.[PAR]",
433         "If the [TT]-demux[tt] option is given, the N trajectories that are",
434         "read, are written in another order as specified in the [TT].xvg[tt] file.",
435         "The [TT].xvg[tt] file should contain something like:[PAR]",
436         "[TT]0  0  1  2  3  4  5[BR]",
437         "2  1  0  2  3  5  4[tt][BR]",
438         "Where the first number is the time, and subsequent numbers point to",
439         "trajectory indices.",
440         "The frames corresponding to the numbers present at the first line",
441         "are collected into the output trajectory. If the number of frames in",
442         "the trajectory does not match that in the [TT].xvg[tt] file then the program",
443         "tries to be smart. Beware."
444     };
445     static gmx_bool bVels           = TRUE;
446     static gmx_bool bCat            = FALSE;
447     static gmx_bool bSort           = TRUE;
448     static gmx_bool bKeepLast       = FALSE;
449     static gmx_bool bKeepLastAppend = FALSE;
450     static gmx_bool bOverwrite      = FALSE;
451     static gmx_bool bSetTime        = FALSE;
452     static gmx_bool bDeMux;
453     static real     begin = -1;
454     static real     end   = -1;
455     static real     dt    = 0;
456
457     t_pargs
458         pa[] =
459     {
460         { "-b", FALSE, etTIME,
461           { &begin }, "First time to use (%t)" },
462         { "-e", FALSE, etTIME,
463           { &end }, "Last time to use (%t)" },
464         { "-dt", FALSE, etTIME,
465           { &dt }, "Only write frame when t MOD dt = first time (%t)" },
466         { "-vel", FALSE, etBOOL,
467           { &bVels }, "Read and write velocities if possible" },
468         { "-settime", FALSE, etBOOL,
469           { &bSetTime }, "Change starting time interactively" },
470         { "-sort", FALSE, etBOOL,
471           { &bSort }, "Sort trajectory files (not frames)" },
472         { "-keeplast", FALSE, etBOOL,
473           { &bKeepLast }, "Keep overlapping frames at end of trajectory" },
474         { "-overwrite", FALSE, etBOOL,
475           { &bOverwrite }, "Overwrite overlapping frames during appending" },
476         { "-cat", FALSE, etBOOL,
477           { &bCat }, "Do not discard double time frames" }
478     };
479 #define npargs asize(pa)
480     int          ftpin, i, frame, frame_out, step = 0, trjout = 0;
481     t_trxstatus *status, *trxout = NULL;
482     rvec        *x, *v;
483     real         t_corr;
484     t_trxframe   fr, frout;
485     char       **fnms, **fnms_out, *in_file, *out_file;
486     int          n_append;
487     gmx_bool     bNewFile, bIndex, bWrite;
488     int          earliersteps, nfile_in, nfile_out, *cont_type, last_ok_step;
489     real        *readtime, *timest, *settime;
490     real         first_time = 0, lasttime = NOTSET, last_ok_t = -1, timestep;
491     real         last_frame_time, searchtime;
492     int          isize, j;
493     atom_id     *index = NULL, imax;
494     char        *grpname;
495     real       **val = NULL, *t = NULL, dt_remd;
496     int          n, nset, ftpout = -1, prevEndStep = 0, filetype;
497     gmx_bool     bOK;
498     gmx_off_t    fpos;
499     output_env_t oenv;
500     t_filenm     fnm[] =
501     {
502         { efTRX, "-f", NULL, ffRDMULT },
503         { efTRO, "-o", NULL, ffWRMULT },
504         { efNDX, "-n", "index", ffOPTRD },
505         { efXVG, "-demux", "remd", ffOPTRD }
506     };
507
508 #define NFILE asize(fnm)
509
510     if (!parse_common_args(&argc, argv, PCA_BE_NICE | PCA_TIME_UNIT, NFILE, fnm,
511                            asize(pa), pa, asize(desc), desc, 0, NULL, &oenv))
512     {
513         return 0;
514     }
515
516     bIndex = ftp2bSet(efNDX, NFILE, fnm);
517     bDeMux = ftp2bSet(efXVG, NFILE, fnm);
518     bSort  = bSort && !bDeMux;
519
520     imax = NO_ATID;
521     if (bIndex)
522     {
523         printf("Select group for output\n");
524         rd_index(ftp2fn(efNDX, NFILE, fnm), 1, &isize, &index, &grpname);
525         /* scan index */
526         imax = index[0];
527         for (i = 1; i < isize; i++)
528         {
529             imax = max(imax, index[i]);
530         }
531     }
532     if (bDeMux)
533     {
534         nset    = 0;
535         dt_remd = 0;
536         val     = read_xvg_time(opt2fn("-demux", NFILE, fnm), TRUE,
537                                 opt2parg_bSet("-b", npargs, pa), begin,
538                                 opt2parg_bSet("-e", npargs, pa), end, 1, &nset, &n,
539                                 &dt_remd, &t);
540         printf("Read %d sets of %d points, dt = %g\n\n", nset, n, dt_remd);
541         if (debug)
542         {
543             fprintf(debug, "Dump of replica_index.xvg\n");
544             for (i = 0; (i < n); i++)
545             {
546                 fprintf(debug, "%10g", t[i]);
547                 for (j = 0; (j < nset); j++)
548                 {
549                     fprintf(debug, "  %3d", gmx_nint(val[j][i]));
550                 }
551                 fprintf(debug, "\n");
552             }
553         }
554     }
555
556     nfile_in = opt2fns(&fnms, "-f", NFILE, fnm);
557     if (!nfile_in)
558     {
559         gmx_fatal(FARGS, "No input files!" );
560     }
561
562     if (bDeMux && (nfile_in != nset))
563     {
564         gmx_fatal(FARGS, "You have specified %d files and %d entries in the demux table", nfile_in, nset);
565     }
566
567     ftpin = fn2ftp(fnms[0]);
568
569     for (i = 1; i < nfile_in; i++)
570     {
571         if (ftpin != fn2ftp(fnms[i]))
572         {
573             gmx_fatal(FARGS, "All input files must be of the same format");
574         }
575     }
576
577     nfile_out = opt2fns(&fnms_out, "-o", NFILE, fnm);
578     if (!nfile_out)
579     {
580         gmx_fatal(FARGS, "No output files!");
581     }
582     if ((nfile_out > 1) && !bDeMux)
583     {
584         gmx_fatal(FARGS, "Don't know what to do with more than 1 output file if  not demultiplexing");
585     }
586     else if (bDeMux && (nfile_out != nset) && (nfile_out != 1))
587     {
588         gmx_fatal(FARGS, "Number of output files should be 1 or %d (#input files), not %d", nset, nfile_out);
589     }
590     if (bDeMux)
591     {
592         if (nfile_out != nset)
593         {
594             char *buf = strdup(fnms_out[0]);
595             snew(fnms_out, nset);
596             for (i = 0; (i < nset); i++)
597             {
598                 snew(fnms_out[i], strlen(buf)+32);
599                 sprintf(fnms_out[i], "%d_%s", i, buf);
600             }
601             sfree(buf);
602         }
603         do_demux(nfile_in, fnms, fnms_out, n, val, t, dt_remd, isize, index, dt, oenv);
604     }
605     else
606     {
607         snew(readtime, nfile_in+1);
608         snew(timest, nfile_in+1);
609         scan_trj_files(fnms, nfile_in, readtime, timest, imax, oenv);
610
611         snew(settime, nfile_in+1);
612         snew(cont_type, nfile_in+1);
613         edit_files(fnms, nfile_in, readtime, timest, settime, cont_type, bSetTime, bSort,
614                    oenv);
615
616         /* Check whether the output file is amongst the input files
617          * This has to be done after sorting etc.
618          */
619         out_file = fnms_out[0];
620         ftpout   = fn2ftp(out_file);
621         n_append = -1;
622         for (i = 0; ((i < nfile_in) && (n_append == -1)); i++)
623         {
624             if (strcmp(fnms[i], out_file) == 0)
625             {
626                 n_append = i;
627             }
628         }
629         if (n_append == 0)
630         {
631             fprintf(stderr, "Will append to %s rather than creating a new file\n",
632                     out_file);
633         }
634         else if (n_append != -1)
635         {
636             gmx_fatal(FARGS, "Can only append to the first file which is %s (not %s)",
637                       fnms[0], out_file);
638         }
639         earliersteps = 0;
640
641         /* Not checking input format, could be dangerous :-) */
642         /* Not checking output format, equally dangerous :-) */
643
644         frame     = -1;
645         frame_out = -1;
646         /* the default is not to change the time at all,
647          * but this is overridden by the edit_files routine
648          */
649         t_corr = 0;
650
651         if (n_append == -1)
652         {
653             if (ftpout == efTNG)
654             {
655                 if (bIndex)
656                 {
657                     trjtools_gmx_prepare_tng_writing(out_file, 'w', NULL, &trxout,
658                                                      fnms[0], isize, NULL, index, grpname);
659                 }
660                 else
661                 {
662                     trjtools_gmx_prepare_tng_writing(out_file, 'w', NULL, &trxout,
663                                                      fnms[0], -1, NULL, NULL, NULL);
664                 }
665             }
666             else
667             {
668                 trxout = open_trx(out_file, "w");
669             }
670             memset(&frout, 0, sizeof(frout));
671         }
672         else
673         {
674             t_fileio *stfio;
675
676             if (!read_first_frame(oenv, &status, out_file, &fr, FLAGS))
677             {
678                 gmx_fatal(FARGS, "Reading first frame from %s", out_file);
679             }
680
681             stfio = trx_get_fileio(status);
682             if (!bKeepLast && !bOverwrite)
683             {
684                 fprintf(stderr, "\n\nWARNING: Appending without -overwrite implies -keeplast "
685                         "between the first two files. \n"
686                         "If the trajectories have an overlap and have not been written binary \n"
687                         "reproducible this will produce an incorrect trajectory!\n\n");
688
689                 filetype = gmx_fio_getftp(stfio);
690                 /* Fails if last frame is incomplete
691                  * We can't do anything about it without overwriting
692                  * */
693                 if (filetype == efXTC || filetype == efTNG)
694                 {
695                     lasttime = trx_get_time_of_final_frame(status);
696                     fr.time  = lasttime;
697                 }
698                 else
699                 {
700                     while (read_next_frame(oenv, status, &fr))
701                     {
702                         ;
703                     }
704                     lasttime = fr.time;
705                 }
706                 bKeepLastAppend = TRUE;
707                 close_trj(status);
708                 trxout = open_trx(out_file, "a");
709             }
710             else if (bOverwrite)
711             {
712                 if (gmx_fio_getftp(stfio) != efXTC)
713                 {
714                     gmx_fatal(FARGS, "Overwrite only supported for XTC." );
715                 }
716                 last_frame_time = trx_get_time_of_final_frame(status);
717
718                 /* xtc_seek_time broken for trajectories containing only 1 or 2 frames
719                  *     or when seek time = 0 */
720                 if (nfile_in > 1 && settime[1] < last_frame_time+timest[0]*0.5)
721                 {
722                     /* Jump to one time-frame before the start of next
723                      *  trajectory file */
724                     searchtime = settime[1]-timest[0]*1.25;
725                 }
726                 else
727                 {
728                     searchtime = last_frame_time;
729                 }
730                 if (xtc_seek_time(stfio, searchtime, fr.natoms, TRUE))
731                 {
732                     gmx_fatal(FARGS, "Error seeking to append position.");
733                 }
734                 read_next_frame(oenv, status, &fr);
735                 if (fabs(searchtime - fr.time) > timest[0]*0.5)
736                 {
737                     gmx_fatal(FARGS, "Error seeking: attempted to seek to %f but got %f.",
738                               searchtime, fr.time);
739                 }
740                 lasttime = fr.time;
741                 fpos     = gmx_fio_ftell(stfio);
742                 close_trj(status);
743                 trxout = open_trx(out_file, "r+");
744                 if (gmx_fio_seek(trx_get_fileio(trxout), fpos))
745                 {
746                     gmx_fatal(FARGS, "Error seeking to append position.");
747                 }
748             }
749             printf("\n Will append after %f \n", lasttime);
750             frout = fr;
751         }
752         /* Lets stitch up some files */
753         timestep = timest[0];
754         for (i = n_append+1; (i < nfile_in); i++)
755         {
756             /* Open next file */
757
758             /* set the next time from the last frame in previous file */
759             if (i > 0)
760             {
761                 /* When writing TNG the step determine which frame to write. Use an
762                  * offset to be able to increase steps properly when changing files. */
763                 if (ftpout == efTNG)
764                 {
765                     prevEndStep = frout.step;
766                 }
767
768                 if (frame_out >= 0)
769                 {
770                     if (cont_type[i] == TIME_CONTINUE)
771                     {
772                         begin        = frout.time;
773                         begin       += 0.5*timestep;
774                         settime[i]   = frout.time;
775                         cont_type[i] = TIME_EXPLICIT;
776                     }
777                     else if (cont_type[i] == TIME_LAST)
778                     {
779                         begin  = frout.time;
780                         begin += 0.5*timestep;
781                     }
782                     /* Or, if the time in the next part should be changed by the
783                      * same amount, start at half a timestep from the last time
784                      * so we dont repeat frames.
785                      */
786                     /* I don't understand the comment above, but for all the cases
787                      * I tried the code seems to work properly. B. Hess 2008-4-2.
788                      */
789                 }
790                 /* Or, if time is set explicitly, we check for overlap/gap */
791                 if (cont_type[i] == TIME_EXPLICIT)
792                 {
793                     if ( ( i < nfile_in ) &&
794                          ( frout.time < settime[i]-1.5*timestep ) )
795                     {
796                         fprintf(stderr, "WARNING: Frames around t=%f %s have a different "
797                                 "spacing than the rest,\n"
798                                 "might be a gap or overlap that couldn't be corrected "
799                                 "automatically.\n", output_env_conv_time(oenv, frout.time),
800                                 output_env_get_time_unit(oenv));
801                     }
802                 }
803             }
804
805             /* if we don't have a timestep in the current file, use the old one */
806             if (timest[i] != 0)
807             {
808                 timestep = timest[i];
809             }
810             read_first_frame(oenv, &status, fnms[i], &fr, FLAGS);
811             if (!fr.bTime)
812             {
813                 fr.time = 0;
814                 fprintf(stderr, "\nWARNING: Couldn't find a time in the frame.\n");
815             }
816
817             if (cont_type[i] == TIME_EXPLICIT)
818             {
819                 t_corr = settime[i]-fr.time;
820             }
821             /* t_corr is the amount we want to change the time.
822              * If the user has chosen not to change the time for
823              * this part of the trajectory t_corr remains at
824              * the value it had in the last part, changing this
825              * by the same amount.
826              * If no value was given for the first trajectory part
827              * we let the time start at zero, see the edit_files routine.
828              */
829
830             bNewFile = TRUE;
831
832             printf("\n");
833             if (lasttime != NOTSET)
834             {
835                 printf("lasttime %g\n", lasttime);
836             }
837
838             do
839             {
840                 /* copy the input frame to the output frame */
841                 frout = fr;
842                 /* set the new time by adding the correct calculated above */
843                 frout.time += t_corr;
844                 if (ftpout == efTNG)
845                 {
846                     frout.step += prevEndStep;
847                 }
848                 /* quit if we have reached the end of what should be written */
849                 if ((end > 0) && (frout.time > end+GMX_REAL_EPS))
850                 {
851                     i = nfile_in;
852                     break;
853                 }
854
855                 /* determine if we should write this frame (dt is handled elsewhere) */
856                 if (bCat) /* write all frames of all files */
857                 {
858                     bWrite = TRUE;
859                 }
860                 else if (bKeepLast || (bKeepLastAppend && i == 1))
861                 /* write till last frame of this traj
862                    and skip first frame(s) of next traj */
863                 {
864                     bWrite = ( frout.time > lasttime+0.5*timestep );
865                 }
866                 else /* write till first frame of next traj */
867                 {
868                     bWrite = ( frout.time < settime[i+1]-0.5*timestep );
869                 }
870
871                 if (bWrite && (frout.time >= begin) )
872                 {
873                     frame++;
874                     if (frame_out == -1)
875                     {
876                         first_time = frout.time;
877                     }
878                     lasttime = frout.time;
879                     if (dt == 0 || bRmod(frout.time, first_time, dt))
880                     {
881                         frame_out++;
882                         last_ok_t = frout.time;
883                         if (bNewFile)
884                         {
885                             fprintf(stderr, "\nContinue writing frames from %s t=%g %s, "
886                                     "frame=%d      \n",
887                                     fnms[i], output_env_conv_time(oenv, frout.time), output_env_get_time_unit(oenv),
888                                     frame);
889                             bNewFile = FALSE;
890                         }
891
892                         if (bIndex)
893                         {
894                             write_trxframe_indexed(trxout, &frout, isize, index,
895                                                    NULL);
896                         }
897                         else
898                         {
899                             write_trxframe(trxout, &frout, NULL);
900                         }
901                         if ( ((frame % 10) == 0) || (frame < 10) )
902                         {
903                             fprintf(stderr, " ->  frame %6d time %8.3f %s     \r",
904                                     frame_out, output_env_conv_time(oenv, frout.time), output_env_get_time_unit(oenv));
905                         }
906                     }
907                 }
908             }
909             while (read_next_frame(oenv, status, &fr));
910
911             close_trj(status);
912
913             earliersteps += step;
914         }
915         if (trxout)
916         {
917             close_trx(trxout);
918         }
919         fprintf(stderr, "\nLast frame written was %d, time %f %s\n",
920                 frame, output_env_conv_time(oenv, last_ok_t), output_env_get_time_unit(oenv));
921     }
922
923     return 0;
924 }