Merge release-4-6 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, 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 <string.h>
42 #include <math.h>
43 #include "macros.h"
44 #include "sysstuff.h"
45 #include "smalloc.h"
46 #include "typedefs.h"
47 #include "gromacs/fileio/gmxfio.h"
48 #include "gromacs/fileio/tpxio.h"
49 #include "gromacs/fileio/trxio.h"
50 #include "gromacs/fileio/trnio.h"
51 #include "gromacs/fileio/tngio.h"
52 #include "gromacs/fileio/tngio_for_tools.h"
53 #include "gromacs/commandline/pargs.h"
54 #include "gromacs/fileio/futil.h"
55 #include "gromacs/fileio/pdbio.h"
56 #include "gromacs/fileio/confio.h"
57 #include "names.h"
58 #include "index.h"
59 #include "vec.h"
60 #include "gromacs/fileio/xtcio.h"
61 #include "do_fit.h"
62 #include "rmpbc.h"
63 #include "gromacs/fileio/g87io.h"
64 #include "pbc.h"
65 #include "xvgr.h"
66 #include "gromacs/fileio/xdrf.h"
67 #include "gmx_ana.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)
694                 {
695                     lasttime =
696                         xdr_xtc_get_last_frame_time(gmx_fio_getfp(stfio),
697                                                     gmx_fio_getxdr(stfio),
698                                                     fr.natoms, &bOK);
699                     fr.time = lasttime;
700                     if (!bOK)
701                     {
702                         gmx_fatal(FARGS, "Error reading last frame. Maybe seek not supported." );
703                     }
704                 }
705                 else if (filetype == efTNG)
706                 {
707                     tng_trajectory_t tng = trx_get_tng(status);
708                     if (!tng)
709                     {
710                         gmx_fatal(FARGS, "Error opening TNG file.");
711                     }
712                     lasttime = gmx_tng_get_time_of_final_frame(tng);
713                     fr.time  = lasttime;
714                 }
715                 else
716                 {
717                     while (read_next_frame(oenv, status, &fr))
718                     {
719                         ;
720                     }
721                     lasttime = fr.time;
722                 }
723                 bKeepLastAppend = TRUE;
724                 close_trj(status);
725                 trxout = open_trx(out_file, "a");
726             }
727             else if (bOverwrite)
728             {
729                 if (gmx_fio_getftp(stfio) != efXTC)
730                 {
731                     gmx_fatal(FARGS, "Overwrite only supported for XTC." );
732                 }
733                 last_frame_time =
734                     xdr_xtc_get_last_frame_time(gmx_fio_getfp(stfio),
735                                                 gmx_fio_getxdr(stfio),
736                                                 fr.natoms, &bOK);
737                 if (!bOK)
738                 {
739                     gmx_fatal(FARGS, "Error reading last frame. Maybe seek not supported." );
740                 }
741                 /* xtc_seek_time broken for trajectories containing only 1 or 2 frames
742                  *     or when seek time = 0 */
743                 if (nfile_in > 1 && settime[1] < last_frame_time+timest[0]*0.5)
744                 {
745                     /* Jump to one time-frame before the start of next
746                      *  trajectory file */
747                     searchtime = settime[1]-timest[0]*1.25;
748                 }
749                 else
750                 {
751                     searchtime = last_frame_time;
752                 }
753                 if (xtc_seek_time(stfio, searchtime, fr.natoms, TRUE))
754                 {
755                     gmx_fatal(FARGS, "Error seeking to append position.");
756                 }
757                 read_next_frame(oenv, status, &fr);
758                 if (fabs(searchtime - fr.time) > timest[0]*0.5)
759                 {
760                     gmx_fatal(FARGS, "Error seeking: attempted to seek to %f but got %f.",
761                               searchtime, fr.time);
762                 }
763                 lasttime = fr.time;
764                 fpos     = gmx_fio_ftell(stfio);
765                 close_trj(status);
766                 trxout = open_trx(out_file, "r+");
767                 if (gmx_fio_seek(trx_get_fileio(trxout), fpos))
768                 {
769                     gmx_fatal(FARGS, "Error seeking to append position.");
770                 }
771             }
772             printf("\n Will append after %f \n", lasttime);
773             frout = fr;
774         }
775         /* Lets stitch up some files */
776         timestep = timest[0];
777         for (i = n_append+1; (i < nfile_in); i++)
778         {
779             /* Open next file */
780
781             /* set the next time from the last frame in previous file */
782             if (i > 0)
783             {
784                 /* When writing TNG the step determine which frame to write. Use an
785                  * offset to be able to increase steps properly when changing files. */
786                 if (ftpout == efTNG)
787                 {
788                     prevEndStep = frout.step;
789                 }
790
791                 if (frame_out >= 0)
792                 {
793                     if (cont_type[i] == TIME_CONTINUE)
794                     {
795                         begin        = frout.time;
796                         begin       += 0.5*timestep;
797                         settime[i]   = frout.time;
798                         cont_type[i] = TIME_EXPLICIT;
799                     }
800                     else if (cont_type[i] == TIME_LAST)
801                     {
802                         begin  = frout.time;
803                         begin += 0.5*timestep;
804                     }
805                     /* Or, if the time in the next part should be changed by the
806                      * same amount, start at half a timestep from the last time
807                      * so we dont repeat frames.
808                      */
809                     /* I don't understand the comment above, but for all the cases
810                      * I tried the code seems to work properly. B. Hess 2008-4-2.
811                      */
812                 }
813                 /* Or, if time is set explicitly, we check for overlap/gap */
814                 if (cont_type[i] == TIME_EXPLICIT)
815                 {
816                     if ( ( i < nfile_in ) &&
817                          ( frout.time < settime[i]-1.5*timestep ) )
818                     {
819                         fprintf(stderr, "WARNING: Frames around t=%f %s have a different "
820                                 "spacing than the rest,\n"
821                                 "might be a gap or overlap that couldn't be corrected "
822                                 "automatically.\n", output_env_conv_time(oenv, frout.time),
823                                 output_env_get_time_unit(oenv));
824                     }
825                 }
826             }
827
828             /* if we don't have a timestep in the current file, use the old one */
829             if (timest[i] != 0)
830             {
831                 timestep = timest[i];
832             }
833             read_first_frame(oenv, &status, fnms[i], &fr, FLAGS);
834             if (!fr.bTime)
835             {
836                 fr.time = 0;
837                 fprintf(stderr, "\nWARNING: Couldn't find a time in the frame.\n");
838             }
839
840             if (cont_type[i] == TIME_EXPLICIT)
841             {
842                 t_corr = settime[i]-fr.time;
843             }
844             /* t_corr is the amount we want to change the time.
845              * If the user has chosen not to change the time for
846              * this part of the trajectory t_corr remains at
847              * the value it had in the last part, changing this
848              * by the same amount.
849              * If no value was given for the first trajectory part
850              * we let the time start at zero, see the edit_files routine.
851              */
852
853             bNewFile = TRUE;
854
855             printf("\n");
856             if (lasttime != NOTSET)
857             {
858                 printf("lasttime %g\n", lasttime);
859             }
860
861             do
862             {
863                 /* copy the input frame to the output frame */
864                 frout = fr;
865                 /* set the new time by adding the correct calculated above */
866                 frout.time += t_corr;
867                 if (ftpout == efTNG)
868                 {
869                     frout.step += prevEndStep;
870                 }
871                 /* quit if we have reached the end of what should be written */
872                 if ((end > 0) && (frout.time > end+GMX_REAL_EPS))
873                 {
874                     i = nfile_in;
875                     break;
876                 }
877
878                 /* determine if we should write this frame (dt is handled elsewhere) */
879                 if (bCat) /* write all frames of all files */
880                 {
881                     bWrite = TRUE;
882                 }
883                 else if (bKeepLast || (bKeepLastAppend && i == 1))
884                 /* write till last frame of this traj
885                    and skip first frame(s) of next traj */
886                 {
887                     bWrite = ( frout.time > lasttime+0.5*timestep );
888                 }
889                 else /* write till first frame of next traj */
890                 {
891                     bWrite = ( frout.time < settime[i+1]-0.5*timestep );
892                 }
893
894                 if (bWrite && (frout.time >= begin) )
895                 {
896                     frame++;
897                     if (frame_out == -1)
898                     {
899                         first_time = frout.time;
900                     }
901                     lasttime = frout.time;
902                     if (dt == 0 || bRmod(frout.time, first_time, dt))
903                     {
904                         frame_out++;
905                         last_ok_t = frout.time;
906                         if (bNewFile)
907                         {
908                             fprintf(stderr, "\nContinue writing frames from %s t=%g %s, "
909                                     "frame=%d      \n",
910                                     fnms[i], output_env_conv_time(oenv, frout.time), output_env_get_time_unit(oenv),
911                                     frame);
912                             bNewFile = FALSE;
913                         }
914
915                         if (bIndex)
916                         {
917                             write_trxframe_indexed(trxout, &frout, isize, index,
918                                                    NULL);
919                         }
920                         else
921                         {
922                             write_trxframe(trxout, &frout, NULL);
923                         }
924                         if ( ((frame % 10) == 0) || (frame < 10) )
925                         {
926                             fprintf(stderr, " ->  frame %6d time %8.3f %s     \r",
927                                     frame_out, output_env_conv_time(oenv, frout.time), output_env_get_time_unit(oenv));
928                         }
929                     }
930                 }
931             }
932             while (read_next_frame(oenv, status, &fr));
933
934             close_trj(status);
935
936             earliersteps += step;
937         }
938         if (trxout)
939         {
940             close_trx(trxout);
941         }
942         fprintf(stderr, "\nLast frame written was %d, time %f %s\n",
943                 frame, output_env_conv_time(oenv, last_ok_t), output_env_get_time_unit(oenv));
944     }
945
946     return 0;
947 }