5fcd5f89ab176472c867df62d63a7a60fc424660
[alexxy/gromacs.git] / src / gromacs / gmxlib / xvgr.cpp
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 <string.h>
42 #include <ctype.h>
43 #include <time.h>
44
45 #ifdef HAVE_SYS_TIME_H
46 #include <sys/time.h>
47 #endif
48
49 #include "gromacs/utility/cstringutil.h"
50 #include "gromacs/utility/futil.h"
51 #include "copyrite.h"
52 #include "oenv.h"
53 #include "gromacs/utility/smalloc.h"
54 #include "xvgr.h"
55 #include "vec.h"
56 #include "gromacs/fileio/gmxfio.h"
57
58 #include "gromacs/utility/exceptions.h"
59 #include "gromacs/utility/fatalerror.h"
60 #include "gromacs/utility/programcontext.h"
61
62 gmx_bool output_env_get_print_xvgr_codes(const output_env_t oenv)
63 {
64     int xvg_format;
65
66     xvg_format = output_env_get_xvg_format(oenv);
67
68     return (xvg_format == exvgXMGRACE || xvg_format == exvgXMGR);
69 }
70
71 static char *xvgrstr(const char *gmx, const output_env_t oenv,
72                      char *buf, int buflen)
73 {
74     /* Supported greek letter names and corresponding xmgrace/xmgr symbols */
75     const char *sym[]  = { "beta", "chi", "delta", "eta", "lambda", "mu", "omega", "phi", "psi", "rho", "theta", NULL };
76     const char  symc[] = { 'b',    'c',   'd',     'h',   'l',      'm',  'w',     'f',   'y',   'r',   'q',     '\0' };
77     int         xvgf;
78     gmx_bool    bXVGR;
79     int         g, b, i;
80     char        c;
81
82     xvgf  = output_env_get_xvg_format(oenv);
83     bXVGR = (xvgf == exvgXMGRACE || xvgf == exvgXMGR);
84
85     g = 0;
86     b = 0;
87     while (gmx[g] != '\0')
88     {
89         /* Check with the largest string we have ("lambda"), add one for \0 */
90         if (b + 6 + 1 >= buflen)
91         {
92             gmx_fatal(FARGS, "Output buffer length in xvgstr (%d) too small to process xvg input string '%s'", buflen, gmx);
93         }
94         if (gmx[g] == '\\')
95         {
96             g++;
97             if (gmx[g] == 's')
98             {
99                 /* Subscript */
100                 if (bXVGR)
101                 {
102                     buf[b++] = '\\';
103                     buf[b++] = 's';
104                 }
105                 else
106                 {
107                     buf[b++] = '_';
108                 }
109                 g++;
110             }
111             else if (gmx[g] == 'S')
112             {
113                 /* Superscript */
114                 if (bXVGR)
115                 {
116                     buf[b++] = '\\';
117                     buf[b++] = 'S';
118                 }
119                 else
120                 {
121                     buf[b++] = '^';
122                 }
123                 g++;
124             }
125             else if (gmx[g] == 'N')
126             {
127                 /* End sub/superscript */
128                 if (bXVGR)
129                 {
130                     buf[b++] = '\\';
131                     buf[b++] = 'N';
132                 }
133                 else
134                 {
135                     if (gmx[g+1] != ' ')
136                     {
137                         buf[b++] = ' ';
138                     }
139                 }
140                 g++;
141             }
142             else if (gmx[g] == '4')
143             {
144                 /* Backward compatibility for xmgr normal font "\4" */
145                 switch (xvgf)
146                 {
147                     case exvgXMGRACE:
148                         sprintf(buf+b, "%s", "\\f{}");
149                         break;
150                     case exvgXMGR:
151                         sprintf(buf+b, "%s", "\\4");
152                         break;
153                     default:
154                         buf[b] = '\0';
155                         break;
156                 }
157                 g++;
158                 b = strlen(buf);
159             }
160             else if (gmx[g] == '8')
161             {
162                 /* Backward compatibility for xmgr symbol font "\8" */
163                 switch (xvgf)
164                 {
165                     case exvgXMGRACE:
166                         sprintf(buf+b, "%s", "\\x");
167                         break;
168                     case exvgXMGR:
169                         sprintf(buf+b, "%s", "\\8");
170                         break;
171                     default:
172                         buf[b] = '\0';
173                         break;
174                 }
175                 g++;
176                 b = strlen(buf);
177             }
178             else
179             {
180                 /* Check for special symbol */
181                 i = 0;
182                 while (sym[i] != NULL &&
183                        gmx_strncasecmp(sym[i], gmx+g, strlen(sym[i])) != 0)
184                 {
185                     i++;
186                 }
187                 if (sym[i] != NULL)
188                 {
189                     c = symc[i];
190                     if (isupper(gmx[g]))
191                     {
192                         c = toupper(c);
193                     }
194                     switch (xvgf)
195                     {
196                         case exvgXMGRACE:
197                             sprintf(buf+b, "%s%c%s", "\\x", c, "\\f{}");
198                             break;
199                         case exvgXMGR:
200                             sprintf(buf+b, "%s%c%s", "\\8", c, "\\4");
201                             break;
202                         default:
203                             strncat(buf+b, gmx+g, strlen(sym[i]));
204                             b += strlen(sym[i]);
205                             if (gmx[g+strlen(sym[i])] != ' ')
206                             {
207                                 buf[b++] = ' ';
208                             }
209                             buf[b] = '\0';
210                             break;
211                     }
212                     g += strlen(sym[i]);
213                     b  = strlen(buf);
214                 }
215                 else
216                 {
217                     /* Unknown escape sequence, this should not happen.
218                      * We do not generate a fatal error, since that might
219                      * stop otherwise functioning code from working.
220                      * Copy the backslash to the output and continue processing.
221                      */
222                     buf[b++] = '\\';
223                 }
224             }
225         }
226         else
227         {
228             buf[b++] = gmx[g++];
229         }
230     }
231
232     buf[b++] = '\0';
233
234     return buf;
235 }
236
237 void xvgr_header(FILE *fp, const char *title, const char *xaxis,
238                  const char *yaxis, int exvg_graph_type,
239                  const output_env_t oenv)
240 {
241     char   pukestr[100], buf[STRLEN];
242     time_t t;
243
244     if (output_env_get_print_xvgr_codes(oenv))
245     {
246         time(&t);
247         gmx_ctime_r(&t, buf, STRLEN);
248         fprintf(fp, "# This file was created %s", buf);
249         try
250         {
251             gmx::BinaryInformationSettings settings;
252             settings.generatedByHeader(true);
253             settings.linePrefix("# ");
254             gmx::printBinaryInformation(fp, gmx::getProgramContext(), settings);
255         }
256         GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
257         fprintf(fp, "# %s is part of G R O M A C S:\n#\n", ShortProgram());
258         bromacs(pukestr, 99);
259         fprintf(fp, "# %s\n#\n", pukestr);
260         fprintf(fp, "@    title \"%s\"\n", xvgrstr(title, oenv, buf, STRLEN));
261         fprintf(fp, "@    xaxis  label \"%s\"\n",
262                 xvgrstr(xaxis, oenv, buf, STRLEN));
263         fprintf(fp, "@    yaxis  label \"%s\"\n",
264                 xvgrstr(yaxis, oenv, buf, STRLEN));
265         switch (exvg_graph_type)
266         {
267             case exvggtXNY:
268                 if (output_env_get_xvg_format(oenv) == exvgXMGR)
269                 {
270                     fprintf(fp, "@TYPE nxy\n");
271                 }
272                 else
273                 {
274                     fprintf(fp, "@TYPE xy\n");
275                 }
276                 break;
277             case exvggtXYDY:
278                 fprintf(fp, "@TYPE xydy\n");
279                 break;
280             case exvggtXYDYDY:
281                 fprintf(fp, "@TYPE xydydy\n");
282                 break;
283         }
284     }
285 }
286
287 FILE *xvgropen_type(const char *fn, const char *title, const char *xaxis,
288                     const char *yaxis, int exvg_graph_type,
289                     const output_env_t oenv)
290 {
291     FILE  *fp;
292
293     fp = gmx_fio_fopen(fn, "w");
294
295     xvgr_header(fp, title, xaxis, yaxis, exvg_graph_type, oenv);
296
297     return fp;
298 }
299
300 FILE *xvgropen(const char *fn, const char *title, const char *xaxis,
301                const char *yaxis, const output_env_t oenv)
302 {
303     return xvgropen_type(fn, title, xaxis, yaxis, exvggtXNY, oenv);
304 }
305
306 void
307 xvgrclose(FILE *fp)
308 {
309     gmx_fio_fclose(fp);
310 }
311
312 void xvgr_subtitle(FILE *out, const char *subtitle, const output_env_t oenv)
313 {
314     char buf[STRLEN];
315
316     if (output_env_get_print_xvgr_codes(oenv))
317     {
318         fprintf(out, "@ subtitle \"%s\"\n", xvgrstr(subtitle, oenv, buf, STRLEN));
319     }
320 }
321
322 void xvgr_view(FILE *out, real xmin, real ymin, real xmax, real ymax,
323                const output_env_t oenv)
324 {
325     if (output_env_get_print_xvgr_codes(oenv))
326     {
327         fprintf(out, "@ view %g, %g, %g, %g\n", xmin, ymin, xmax, ymax);
328     }
329 }
330
331 void xvgr_world(FILE *out, real xmin, real ymin, real xmax, real ymax,
332                 const output_env_t oenv)
333 {
334     if (output_env_get_print_xvgr_codes(oenv))
335     {
336         fprintf(out, "@ world xmin %g\n"
337                 "@ world ymin %g\n"
338                 "@ world xmax %g\n"
339                 "@ world ymax %g\n", xmin, ymin, xmax, ymax);
340     }
341 }
342
343 void xvgr_legend(FILE *out, int nsets, const char** setname,
344                  const output_env_t oenv)
345 {
346     int  i;
347     char buf[STRLEN];
348
349     if (output_env_get_print_xvgr_codes(oenv))
350     {
351         xvgr_view(out, 0.15, 0.15, 0.75, 0.85, oenv);
352         fprintf(out, "@ legend on\n");
353         fprintf(out, "@ legend box on\n");
354         fprintf(out, "@ legend loctype view\n");
355         fprintf(out, "@ legend %g, %g\n", 0.78, 0.8);
356         fprintf(out, "@ legend length %d\n", 2);
357         for (i = 0; (i < nsets); i++)
358         {
359             if (setname[i])
360             {
361                 if (output_env_get_xvg_format(oenv) == exvgXMGR)
362                 {
363                     fprintf(out, "@ legend string %d \"%s\"\n",
364                             i, xvgrstr(setname[i], oenv, buf, STRLEN));
365                 }
366                 else
367                 {
368                     fprintf(out, "@ s%d legend \"%s\"\n",
369                             i, xvgrstr(setname[i], oenv, buf, STRLEN));
370                 }
371             }
372         }
373     }
374 }
375
376 void xvgr_new_dataset(FILE *out, int nr_first, int nsets,
377                       const char **setname,
378                       const output_env_t oenv)
379 {
380     int  i;
381     char buf[STRLEN];
382
383     if (output_env_get_print_xvgr_codes(oenv))
384     {
385         fprintf(out, "@\n");
386         for (i = 0; (i < nsets); i++)
387         {
388             if (setname[i])
389             {
390                 if (output_env_get_xvg_format(oenv) == exvgXMGR)
391                 {
392                     fprintf(out, "@ legend string %d \"%s\"\n",
393                             i+nr_first, xvgrstr(setname[i], oenv, buf, STRLEN));
394                 }
395                 else
396                 {
397                     fprintf(out, "@ s%d legend \"%s\"\n",
398                             i+nr_first, xvgrstr(setname[i], oenv, buf, STRLEN));
399                 }
400             }
401         }
402     }
403     else
404     {
405         fprintf(out, "\n");
406     }
407 }
408
409 void xvgr_line_props(FILE *out, int NrSet, int LineStyle, int LineColor,
410                      const output_env_t oenv)
411 {
412     if (output_env_get_print_xvgr_codes(oenv))
413     {
414         fprintf(out, "@    with g0\n");
415         fprintf(out, "@    s%d linestyle %d\n", NrSet, LineStyle);
416         fprintf(out, "@    s%d color %d\n", NrSet, LineColor);
417     }
418 }
419
420 static const char *LocTypeStr[] = { "view", "world" };
421 static const char *BoxFillStr[] = { "none", "color", "pattern" };
422
423 void xvgr_box(FILE *out,
424               int LocType,
425               real xmin, real ymin, real xmax, real ymax,
426               int LineStyle, int LineWidth, int LineColor,
427               int BoxFill, int BoxColor, int BoxPattern, const output_env_t oenv)
428 {
429     if (output_env_get_print_xvgr_codes(oenv))
430     {
431         fprintf(out, "@with box\n");
432         fprintf(out, "@    box on\n");
433         fprintf(out, "@    box loctype %s\n", LocTypeStr[LocType]);
434         fprintf(out, "@    box %g, %g, %g, %g\n", xmin, ymin, xmax, ymax);
435         fprintf(out, "@    box linestyle %d\n", LineStyle);
436         fprintf(out, "@    box linewidth %d\n", LineWidth);
437         fprintf(out, "@    box color %d\n", LineColor);
438         fprintf(out, "@    box fill %s\n", BoxFillStr[BoxFill]);
439         fprintf(out, "@    box fill color %d\n", BoxColor);
440         fprintf(out, "@    box fill pattern %d\n", BoxPattern);
441         fprintf(out, "@box def\n");
442     }
443 }
444
445 /* reads a line into ptr, adjusting len and renewing ptr if neccesary */
446 static char *fgets3(FILE *fp, char **ptr, int *len, int maxlen)
447 {
448     int   len_remaining = *len; /* remaining amount of allocated bytes in buf */
449     int   curp          = 0;    /* current position in buf to read into */
450
451     do
452     {
453         if (len_remaining < 2)
454         {
455             if (*len + STRLEN < maxlen)
456             {
457                 /* This line is longer than len characters, let's increase len! */
458                 *len          += STRLEN;
459                 len_remaining += STRLEN;
460                 srenew(*ptr, *len);
461             }
462             else
463             {
464                 /*something is wrong, we'll just keep reading and return NULL*/
465                 len_remaining = STRLEN;
466                 curp          = 0;
467             }
468         }
469         if (fgets(*ptr + curp, len_remaining, fp) == NULL)
470         {
471             /* if last line, skip */
472             return NULL;
473         }
474         curp         += len_remaining-1; /* overwrite the nul char in next iteration */
475         len_remaining = 1;
476     }
477     while ((strchr(*ptr, '\n') == NULL) && (!feof(fp)));
478
479     if (*len + STRLEN >= maxlen)
480     {
481         return NULL; /* this line was too long */
482     }
483
484     if (feof(fp))
485     {
486         /* We reached EOF before '\n', skip this last line. */
487         return NULL;
488     }
489     {
490         /* now remove newline */
491         int slen = strlen(*ptr);
492         if ((*ptr)[slen-1] == '\n')
493         {
494             (*ptr)[slen-1] = '\0';
495         }
496     }
497
498     return *ptr;
499 }
500
501 static int wordcount(char *ptr)
502 {
503     int i, n, is[2];
504     int cur = 0;
505 #define prev (1-cur)
506
507     if (strlen(ptr) == 0)
508     {
509         return 0;
510     }
511     /* fprintf(stderr,"ptr='%s'\n",ptr); */
512     n = 1;
513     for (i = 0; (ptr[i] != '\0'); i++)
514     {
515         is[cur] = isspace(ptr[i]);
516         if ((i > 0)  && (is[cur] && !is[prev]))
517         {
518             n++;
519         }
520         cur = prev;
521     }
522     return n;
523 }
524
525 static char *read_xvgr_string(const char *line)
526 {
527     const char *ptr0, *ptr1;
528     char       *str;
529
530     ptr0 = strchr(line, '"');
531     if (ptr0 != NULL)
532     {
533         ptr0++;
534         ptr1 = strchr(ptr0, '"');
535         if (ptr1 != NULL)
536         {
537             str            = strdup(ptr0);
538             str[ptr1-ptr0] = '\0';
539         }
540         else
541         {
542             str = strdup("");
543         }
544     }
545     else
546     {
547         str = strdup("");
548     }
549
550     return str;
551 }
552
553 int read_xvg_legend(const char *fn, double ***y, int *ny,
554                     char **subtitle, char ***legend)
555 {
556     FILE    *fp;
557     char    *ptr;
558     char    *base = NULL;
559     char    *fmt  = NULL;
560     int      k, line = 0, nny, nx, maxx, rval, legend_nalloc, set, nchar;
561     double   lf;
562     double **yy = NULL;
563     char    *tmpbuf;
564     int      len = STRLEN;
565     *ny  = 0;
566     nny  = 0;
567     nx   = 0;
568     maxx = 0;
569     fp   = gmx_fio_fopen(fn, "r");
570
571     snew(tmpbuf, len);
572     if (subtitle != NULL)
573     {
574         *subtitle = NULL;
575     }
576     legend_nalloc = 0;
577     if (legend != NULL)
578     {
579         *legend = NULL;
580     }
581
582     while ((ptr = fgets3(fp, &tmpbuf, &len, 10*STRLEN)) != NULL && ptr[0] != '&')
583     {
584         line++;
585         trim(ptr);
586         if (ptr[0] == '@')
587         {
588             if (legend != NULL)
589             {
590                 ptr++;
591                 trim(ptr);
592                 set = -1;
593                 if (strncmp(ptr, "subtitle", 8) == 0)
594                 {
595                     ptr += 8;
596                     if (subtitle != NULL)
597                     {
598                         *subtitle = read_xvgr_string(ptr);
599                     }
600                 }
601                 else if (strncmp(ptr, "legend string", 13) == 0)
602                 {
603                     ptr += 13;
604                     sscanf(ptr, "%d%n", &set, &nchar);
605                     ptr += nchar;
606                 }
607                 else if (ptr[0] == 's')
608                 {
609                     ptr++;
610                     sscanf(ptr, "%d%n", &set, &nchar);
611                     ptr += nchar;
612                     trim(ptr);
613                     if (strncmp(ptr, "legend", 6) == 0)
614                     {
615                         ptr += 6;
616                     }
617                     else
618                     {
619                         set = -1;
620                     }
621                 }
622                 if (set >= 0)
623                 {
624                     if (set >= legend_nalloc)
625                     {
626                         legend_nalloc = set + 1;
627                         srenew(*legend, legend_nalloc);
628                         (*legend)[set] = read_xvgr_string(ptr);
629                     }
630                 }
631             }
632         }
633         else if (ptr[0] != '#')
634         {
635             if (nny == 0)
636             {
637                 (*ny) = nny = wordcount(ptr);
638                 /* fprintf(stderr,"There are %d columns in your file\n",nny);*/
639                 if (nny == 0)
640                 {
641                     return 0;
642                 }
643                 snew(yy, nny);
644                 snew(fmt, 3*nny+1);
645                 snew(base, 3*nny+1);
646             }
647             /* Allocate column space */
648             if (nx >= maxx)
649             {
650                 maxx += 1024;
651                 for (k = 0; (k < nny); k++)
652                 {
653                     srenew(yy[k], maxx);
654                 }
655             }
656             /* Initiate format string */
657             fmt[0]  = '\0';
658             base[0] = '\0';
659
660             /* fprintf(stderr,"ptr='%s'\n",ptr);*/
661             for (k = 0; (k < nny); k++)
662             {
663                 strcpy(fmt, base);
664                 strcat(fmt, "%lf");
665                 rval = sscanf(ptr, fmt, &lf);
666                 /* fprintf(stderr,"rval = %d\n",rval);*/
667                 if ((rval == EOF) || (rval == 0))
668                 {
669                     break;
670                 }
671                 yy[k][nx] = lf;
672                 srenew(fmt, 3*(nny+1)+1);
673                 srenew(base, 3*nny+1);
674                 strcat(base, "%*s");
675             }
676             if (k != nny)
677             {
678                 fprintf(stderr, "Only %d columns on line %d in file %s\n",
679                         k, line, fn);
680                 for (; (k < nny); k++)
681                 {
682                     yy[k][nx] = 0.0;
683                 }
684             }
685             nx++;
686         }
687     }
688     gmx_fio_fclose(fp);
689
690     *y = yy;
691     sfree(tmpbuf);
692
693     if (legend_nalloc > 0)
694     {
695         if (*ny - 1 > legend_nalloc)
696         {
697             srenew(*legend, *ny-1);
698             for (set = legend_nalloc; set < *ny-1; set++)
699             {
700                 (*legend)[set] = NULL;
701             }
702         }
703     }
704
705     return nx;
706 }
707
708 int read_xvg(const char *fn, double ***y, int *ny)
709 {
710     return read_xvg_legend(fn, y, ny, NULL, NULL);
711 }
712
713 void write_xvg(const char *fn, const char *title, int nx, int ny, real **y,
714                const char **leg, const output_env_t oenv)
715 {
716     FILE *fp;
717     int   i, j;
718
719     fp = xvgropen(fn, title, "X", "Y", oenv);
720     if (leg)
721     {
722         xvgr_legend(fp, ny-1, leg, oenv);
723     }
724     for (i = 0; (i < nx); i++)
725     {
726         for (j = 0; (j < ny); j++)
727         {
728             fprintf(fp, "  %12.5e", y[j][i]);
729         }
730         fprintf(fp, "\n");
731     }
732     xvgrclose(fp);
733 }
734
735 real **read_xvg_time(const char *fn,
736                      gmx_bool bHaveT, gmx_bool bTB, real tb, gmx_bool bTE, real te,
737                      int nsets_in, int *nset, int *nval, real *dt, real **t)
738 {
739     FILE      *fp;
740 #define MAXLINELEN 16384
741     char       line0[MAXLINELEN];
742     char      *line;
743     int        t_nalloc, *val_nalloc, a, narg, n, sin, set, nchar;
744     double     dbl;
745     gmx_bool   bEndOfSet, bTimeInRange, bFirstLine = TRUE;
746     real     **val;
747
748     t_nalloc   = 0;
749     *t         = NULL;
750     val        = NULL;
751     val_nalloc = NULL;
752     *nset      = 0;
753     *dt        = 0;
754     fp         = gmx_fio_fopen(fn, "r");
755     for (sin = 0; sin < nsets_in; sin++)
756     {
757         if (nsets_in == 1)
758         {
759             narg = 0;
760         }
761         else
762         {
763             narg = bHaveT ? 2 : 1;
764         }
765         n         = 0;
766         bEndOfSet = FALSE;
767         while (!bEndOfSet && fgets(line0, MAXLINELEN, fp))
768         {
769             line = line0;
770             /* Remove whitespace */
771             while (line[0] == ' ' || line[0] == '\t')
772             {
773                 line++;
774             }
775             bEndOfSet = (line[0] == '&');
776             if (line[0] != '#' && line[0] != '@' && line[0] != '\n' && !bEndOfSet)
777             {
778                 if (bFirstLine && bHaveT)
779                 {
780                     /* Check the first line that should contain data */
781                     a = sscanf(line, "%lf%lf", &dbl, &dbl);
782                     if (a == 0)
783                     {
784                         gmx_fatal(FARGS, "Expected a number in %s on line:\n%s", fn, line0);
785                     }
786                     else if (a == 1)
787                     {
788                         fprintf(stderr, "Found only 1 number on line, "
789                                 "assuming no time is present.\n");
790                         bHaveT = FALSE;
791                         if (nsets_in > 1)
792                         {
793                             narg = 1;
794                         }
795                     }
796                 }
797
798                 a            = 0;
799                 bTimeInRange = TRUE;
800                 while ((a < narg || (nsets_in == 1 && n == 0)) &&
801                        sscanf(line, "%lf%n", &dbl, &nchar) == 1 && bTimeInRange)
802                 {
803                     /* Use set=-1 as the time "set" */
804                     if (sin)
805                     {
806                         if (!bHaveT || (a > 0))
807                         {
808                             set = sin;
809                         }
810                         else
811                         {
812                             set = -1;
813                         }
814                     }
815                     else
816                     {
817                         if (!bHaveT)
818                         {
819                             set = a;
820                         }
821                         else
822                         {
823                             set = a-1;
824                         }
825                     }
826                     if (set == -1 && ((bTB && dbl < tb) || (bTE && dbl > te)))
827                     {
828                         bTimeInRange = FALSE;
829                     }
830
831                     if (bTimeInRange)
832                     {
833                         if (n == 0)
834                         {
835                             if (nsets_in == 1)
836                             {
837                                 narg++;
838                             }
839                             if (set >= 0)
840                             {
841                                 *nset = set+1;
842                                 srenew(val, *nset);
843                                 srenew(val_nalloc, *nset);
844                                 val_nalloc[set] = 0;
845                                 val[set]        = NULL;
846                             }
847                         }
848                         if (set == -1)
849                         {
850                             if (sin == 0)
851                             {
852                                 if (n >= t_nalloc)
853                                 {
854                                     t_nalloc = over_alloc_small(n);
855                                     srenew(*t, t_nalloc);
856                                 }
857                                 (*t)[n] = dbl;
858                             }
859                             /* else we should check the time of the next sets with set 0 */
860                         }
861                         else
862                         {
863                             if (n >= val_nalloc[set])
864                             {
865                                 val_nalloc[set] = over_alloc_small(n);
866                                 srenew(val[set], val_nalloc[set]);
867                             }
868                             val[set][n] = (real)dbl;
869                         }
870                     }
871                     a++;
872                     line += nchar;
873                 }
874                 if (line0[strlen(line0)-1] != '\n')
875                 {
876                     fprintf(stderr, "File %s does not end with a newline, ignoring the last line\n", fn);
877                 }
878                 else if (bTimeInRange)
879                 {
880                     if (a == 0)
881                     {
882                         fprintf(stderr, "Ignoring invalid line in %s:\n%s", fn, line0);
883                     }
884                     else
885                     {
886                         if (a != narg)
887                         {
888                             fprintf(stderr, "Invalid line in %s:\n%s"
889                                     "Using zeros for the last %d sets\n",
890                                     fn, line0, narg-a);
891                         }
892                         n++;
893                     }
894                 }
895                 if (a > 0)
896                 {
897                     bFirstLine = FALSE;
898                 }
899             }
900         }
901         if (sin == 0)
902         {
903             *nval = n;
904             if (!bHaveT)
905             {
906                 snew(*t, n);
907                 for (a = 0; a < n; a++)
908                 {
909                     (*t)[a] = a;
910                 }
911             }
912             if (n > 1)
913             {
914                 *dt = (real)((*t)[n-1]-(*t)[0])/(n-1.0);
915             }
916             else
917             {
918                 *dt = 1;
919             }
920         }
921         else
922         {
923             if (n < *nval)
924             {
925                 fprintf(stderr, "Set %d is shorter (%d) than the previous set (%d)\n",
926                         sin+1, n, *nval);
927                 *nval = n;
928                 fprintf(stderr, "Will use only the first %d points of every set\n",
929                         *nval);
930             }
931         }
932     }
933     gmx_fio_fclose(fp);
934
935     sfree(val_nalloc);
936
937     return val;
938 }