Redefine the default boolean type to gmx_bool.
[alexxy/gromacs.git] / src / gmxlib / xvgr.c
1 /*  -*- mode: c; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; c-file-style: "stroustrup"; -*-
2  *
3  * 
4  *                This source code is part of
5  * 
6  *                 G   R   O   M   A   C   S
7  * 
8  *          GROningen MAchine for Chemical Simulations
9  * 
10  *                        VERSION 3.2.0
11  * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
12  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
13  * Copyright (c) 2001-2004, The GROMACS development team,
14  * check out http://www.gromacs.org for more information.
15
16  * This program is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU General Public License
18  * as published by the Free Software Foundation; either version 2
19  * of the License, or (at your option) any later version.
20  * 
21  * If you want to redistribute modifications, please consider that
22  * scientific software is very special. Version control is crucial -
23  * bugs must be traceable. We will be happy to consider code for
24  * inclusion in the official distribution, but derived work must not
25  * be called official GROMACS. Details are found in the README & COPYING
26  * files - if they are missing, get the official version at www.gromacs.org.
27  * 
28  * To help us fund GROMACS development, we humbly ask that you cite
29  * the papers on the package - you can find them in the top README file.
30  * 
31  * For more info, check our website at http://www.gromacs.org
32  * 
33  * And Hey:
34  * GROningen Mixture of Alchemy and Childrens' Stories
35  */
36 #ifdef HAVE_CONFIG_H
37 #include <config.h>
38 #endif
39
40 #include <string.h>
41 #include <ctype.h>
42 #include <time.h>
43
44 #ifdef HAVE_SYS_TIME_H
45 #include <sys/time.h>
46 #endif
47
48 #include "sysstuff.h"
49 #include "string2.h"
50 #include "futil.h"
51 #include "statutil.h"
52 #include "copyrite.h"
53 #include "smalloc.h"
54 #include "xvgr.h"
55 #include "viewit.h"
56 #include "vec.h"
57 #include "gmxfio.h"
58
59 /* Portable version of ctime_r implemented in src/gmxlib/string2.c, but we do not want it declared in public installed headers */
60 char *
61 gmx_ctime_r(const time_t *clock,char *buf, int n);
62
63
64 gmx_bool output_env_get_print_xvgr_codes(const output_env_t oenv)
65 {
66     int xvg_format;
67
68     xvg_format = output_env_get_xvg_format(oenv);
69
70     return (xvg_format == exvgXMGRACE || xvg_format == exvgXMGR);
71 }
72
73 static char *xvgrstr(const char *gmx,const output_env_t oenv,
74                      char *buf,int buflen)
75 {
76     /* Supported greek letter names and corresponding xmgrace/xmgr symbols */
77     const char *sym[]={ "beta", "chi", "delta", "eta", "lambda", "mu", "omega", "phi", "psi", "rho", "theta", NULL };
78     const char symc[]={ 'b',    'c',   'd',     'h',   'l',      'm',  'w',     'f',   'y',   'r',   'q',     '\0' };
79     int  xvgf;
80     gmx_bool bXVGR;
81     int  g,b,i;
82     char c;
83
84     xvgf  = output_env_get_xvg_format(oenv);
85     bXVGR = (xvgf == exvgXMGRACE || xvgf == exvgXMGR);
86
87     g = 0;
88     b = 0;
89     while (gmx[g] != '\0')
90     {
91         /* Check with the largest string we have ("lambda"), add one for \0 */
92         if (b + 6 + 1 >= buflen)
93         {
94             gmx_fatal(FARGS,"Output buffer length in xvgstr (%d) too small to process xvg input string '%s'",buflen,gmx);
95         }
96         if (gmx[g] == '\\')
97         {
98             g++;
99             if (gmx[g] == 's')
100             {
101                 /* Subscript */
102                 if (bXVGR)
103                 {
104                     buf[b++] = '\\';
105                     buf[b++] = 's';
106                 }
107                 else
108                 {
109                     buf[b++] = '_';
110                 }
111                 g++;
112             }
113             else if (gmx[g] == 'S')
114             {
115                 /* Superscript */
116                 if (bXVGR)
117                 {
118                     buf[b++] = '\\';
119                     buf[b++] = 'S';
120                 }
121                 else
122                 {
123                     buf[b++] = '^';
124                 }
125                 g++;
126             }
127             else if (gmx[g] == 'N')
128             {
129                 /* End sub/superscript */
130                 if (bXVGR)
131                 {
132                     buf[b++] = '\\';
133                     buf[b++] = 'N';
134                 }
135                 else
136                 {
137                     if (gmx[g+1] != ' ')
138                     {
139                         buf[b++] = ' ';
140                     }
141                 }
142                 g++;
143             }
144             else if (gmx[g] == '4')
145             {
146                 /* Backward compatibility for xmgr normal font "\4" */
147                 switch (xvgf)
148                 {
149                 case exvgXMGRACE:
150                     sprintf(buf+b,"%s","\\f{}");
151                     break;
152                 case exvgXMGR:
153                     sprintf(buf+b,"%s","\\4");
154                     break;
155                 default:
156                     buf[b] = '\0';
157                     break;
158                 }
159                 g++;
160                 b = strlen(buf);
161             }
162             else if (gmx[g] == '8')
163             {
164                 /* Backward compatibility for xmgr symbol font "\8" */
165                 switch (xvgf)
166                 {
167                 case exvgXMGRACE:
168                     sprintf(buf+b,"%s","\\x");
169                     break;
170                 case exvgXMGR:
171                     sprintf(buf+b,"%s","\\8");
172                     break;
173                 default:
174                     buf[b] = '\0';
175                     break;
176                 }
177                 g++;
178                 b = strlen(buf);
179             }
180             else
181             {
182                 /* Check for special symbol */
183                 i = 0;
184                 while (sym[i] != NULL &&
185                        gmx_strncasecmp(sym[i],gmx+g,strlen(sym[i])) != 0)
186                 {
187                     i++;
188                 }
189                 if (sym[i] != NULL)
190                 {
191                     c = symc[i];
192                     if (isupper(gmx[g]))
193                     {
194                         c = toupper(c);
195                     }
196                     switch (xvgf)
197                     {
198                     case exvgXMGRACE:
199                         sprintf(buf+b,"%s%c%s","\\x",c,"\\f{}");
200                         break;
201                     case exvgXMGR:
202                         sprintf(buf+b,"%s%c%s","\\8",c,"\\4");
203                         break;
204                     default:
205                         strncat(buf+b,gmx+g,strlen(sym[i]));
206                         b += strlen(sym[i]);
207                         if (gmx[g+strlen(sym[i])] != ' ')
208                         {
209                             buf[b++] = ' ';
210                         }
211                         buf[b] = '\0';
212                         break;
213                     }
214                     g += strlen(sym[i]);
215                     b  = strlen(buf);
216                 }
217                 else
218                 {
219                     /* Unknown escape sequence, this should not happen.
220                      * We do not generate a fatal error, since that might
221                      * stop otherwise functioning code from working.
222                      * Copy the backslash to the output and continue processing.
223                      */
224                     buf[b++] = '\\';
225                 }
226             }
227         }
228         else
229         {
230             buf[b++] = gmx[g++];
231         }
232     }
233
234     buf[b++] = '\0';
235
236     return buf;
237 }
238
239 void xvgr_header(FILE *fp,const char *title,const char *xaxis,
240                  const char *yaxis,int exvg_graph_type,
241                  const output_env_t oenv)
242 {
243     char pukestr[100],buf[STRLEN];
244     time_t t;
245  
246     if (output_env_get_print_xvgr_codes(oenv)) 
247     {
248         time(&t);
249         gmx_ctime_r(&t,buf,STRLEN);
250         fprintf(fp,"# This file was created %s",buf);
251         fprintf(fp,"# by the following command:\n# %s\n#\n",command_line());
252         fprintf(fp,"# %s is part of G R O M A C S:\n#\n",ShortProgram());
253         bromacs(pukestr,99);
254         fprintf(fp,"# %s\n#\n",pukestr);
255         fprintf(fp,"@    title \"%s\"\n",xvgrstr(title,oenv,buf,STRLEN));
256         fprintf(fp,"@    xaxis  label \"%s\"\n",
257                 xvgrstr(xaxis,oenv,buf,STRLEN));
258         fprintf(fp,"@    yaxis  label \"%s\"\n",
259                 xvgrstr(yaxis,oenv,buf,STRLEN));
260         switch (exvg_graph_type)
261         {
262         case exvggtXNY:
263             if (output_env_get_xvg_format(oenv) == exvgXMGR)
264             {
265                 fprintf(fp,"@TYPE nxy\n");
266             }
267             else
268             {
269                 fprintf(fp,"@TYPE xy\n");
270             }
271             break;
272         case exvggtXYDY:
273             fprintf(fp,"@TYPE xydy\n");
274             break;
275         case exvggtXYDYDY:
276             fprintf(fp,"@TYPE xydydy\n");
277             break;
278         }
279     }
280 }
281
282 FILE *xvgropen_type(const char *fn,const char *title,const char *xaxis,
283                     const char *yaxis,int exvg_graph_type,
284                     const output_env_t oenv)
285 {
286     FILE *fp;
287     time_t t;
288
289     fp = gmx_fio_fopen(fn,"w");
290
291     xvgr_header(fp,title,xaxis,yaxis,exvg_graph_type,oenv);
292
293     return fp;
294 }
295
296 FILE *xvgropen(const char *fn,const char *title,const char *xaxis,
297                const char *yaxis,const output_env_t oenv)
298 {
299     return xvgropen_type(fn,title,xaxis,yaxis,exvggtXNY,oenv);
300 }
301
302 void
303 xvgrclose(FILE *fp)
304 {
305         gmx_fio_fclose(fp);
306 }
307
308 void xvgr_subtitle(FILE *out,const char *subtitle,const output_env_t oenv)
309 {
310     char buf[STRLEN];
311
312     if (output_env_get_print_xvgr_codes(oenv))
313     {
314         fprintf(out,"@ subtitle \"%s\"\n",xvgrstr(subtitle,oenv,buf,STRLEN));
315     }
316 }
317
318 void xvgr_view(FILE *out,real xmin,real ymin,real xmax,real ymax,
319                const output_env_t oenv)
320 {
321     if (output_env_get_print_xvgr_codes(oenv))
322     {
323         fprintf(out,"@ view %g, %g, %g, %g\n",xmin,ymin,xmax,ymax);
324     }
325 }
326
327 void xvgr_world(FILE *out,real xmin,real ymin,real xmax,real ymax,
328                 const output_env_t oenv)
329 {
330     if (output_env_get_print_xvgr_codes(oenv))
331     {
332         fprintf(out,"@ world xmin %g\n"
333                 "@ world ymin %g\n"
334                 "@ world xmax %g\n"
335                 "@ world ymax %g\n",xmin,ymin,xmax,ymax);
336     }
337 }
338
339 void xvgr_legend(FILE *out,int nsets,const char** setname,const output_env_t oenv)
340 {
341     int  i;
342     char buf[STRLEN];
343     
344     if (output_env_get_print_xvgr_codes(oenv))
345     {
346         xvgr_view(out,0.15,0.15,0.75,0.85,oenv);
347         fprintf(out,"@ legend on\n");
348         fprintf(out,"@ legend box on\n");
349         fprintf(out,"@ legend loctype view\n");
350         fprintf(out,"@ legend %g, %g\n",0.78,0.8);
351         fprintf(out,"@ legend length %d\n",2);
352         for(i=0; (i<nsets); i++)
353         {
354             if (setname[i]) {
355                 if (output_env_get_xvg_format(oenv) == exvgXMGR)
356                 {
357                     fprintf(out,"@ legend string %d \"%s\"\n",
358                             i,xvgrstr(setname[i],oenv,buf,STRLEN));
359                 }
360                 else
361                 {
362                     fprintf(out,"@ s%d legend \"%s\"\n",
363                             i,xvgrstr(setname[i],oenv,buf,STRLEN));
364                 }
365             }
366         }
367     }
368 }
369
370 void xvgr_new_dataset(FILE *out, const output_env_t oenv)
371 {
372     if (output_env_get_print_xvgr_codes(oenv))
373     {
374         fprintf(out,"@\n");
375     }
376     else
377     {
378         fprintf(out,"\n");
379     }
380 }
381
382 void xvgr_line_props(FILE *out, int NrSet, int LineStyle, int LineColor,
383                      const output_env_t oenv)
384 {
385     if (output_env_get_print_xvgr_codes(oenv))
386     {
387         fprintf(out, "@    with g0\n");
388         fprintf(out, "@    s%d linestyle %d\n", NrSet, LineStyle);
389         fprintf(out, "@    s%d color %d\n", NrSet, LineColor);
390     }
391 }
392
393 static const char *LocTypeStr[] = { "view", "world" };
394 static const char *BoxFillStr[] = { "none", "color", "pattern" };
395  
396 void xvgr_box(FILE *out,
397               int LocType,
398               real xmin,real ymin,real xmax,real ymax,
399               int LineStyle,int LineWidth,int LineColor,
400               int BoxFill,int BoxColor,int BoxPattern,const output_env_t oenv)
401 {
402     if (output_env_get_print_xvgr_codes(oenv))
403     {
404         fprintf(out,"@with box\n");
405         fprintf(out,"@    box on\n");
406         fprintf(out,"@    box loctype %s\n",LocTypeStr[LocType]);
407         fprintf(out,"@    box %g, %g, %g, %g\n",xmin,ymin,xmax,ymax);
408         fprintf(out,"@    box linestyle %d\n",LineStyle);
409         fprintf(out,"@    box linewidth %d\n",LineWidth);
410         fprintf(out,"@    box color %d\n",LineColor);
411         fprintf(out,"@    box fill %s\n",BoxFillStr[BoxFill]);
412         fprintf(out,"@    box fill color %d\n",BoxColor);
413         fprintf(out,"@    box fill pattern %d\n",BoxPattern);
414         fprintf(out,"@box def\n");
415     }
416 }
417
418 static char *fgets3(FILE *fp,char ptr[],int *len)
419 {
420     char *p;
421     int  slen;
422
423     if (fgets(ptr,*len-1,fp) == NULL)
424     {
425         return NULL;
426     }
427     p = ptr;
428     while ((strchr(ptr,'\n') == NULL) && (!feof(fp)))
429     {
430         /* This line is longer than len characters, let's increase len! */
431         *len += STRLEN;
432         p    += STRLEN;
433         srenew(ptr,*len);
434         if (fgets(p-1,STRLEN,fp) == NULL)
435         {
436             break;
437         }
438     }
439     if (feof(fp))
440     {
441         /* We reached EOF before '\n', skip this last line. */
442         return NULL;
443     }
444     slen = strlen(ptr);
445     if (ptr[slen-1] == '\n')
446     {
447         ptr[slen-1] = '\0';
448     }
449
450     return ptr;
451 }
452
453 static int wordcount(char *ptr)
454 {
455   int i,n,is[2];
456   int cur=0;
457 #define prev (1-cur)
458   
459   if (strlen(ptr) == 0)
460     return 0;
461   /* fprintf(stderr,"ptr='%s'\n",ptr); */
462   n=1;
463   for(i=0; (ptr[i] != '\0'); i++) {
464     is[cur] = isspace(ptr[i]);
465     if ((i > 0)  && (is[cur] && !is[prev]))
466       n++;
467     cur=prev;
468   }
469   return n;
470 }
471
472 static char *read_xvgr_string(const char *line)
473 {
474     const char *ptr0,*ptr1;
475     char *str;
476     
477     ptr0 = strchr(line,'"');
478     if (ptr0 != NULL) {
479         ptr0++;
480         ptr1 = strchr(ptr0,'"');
481         if (ptr1 != NULL)
482         {
483             str = strdup(ptr0);
484             str[ptr1-ptr0] = '\0';
485         }
486         else
487         {
488             str = strdup("");
489         }
490     }
491     else
492     {
493         str = strdup("");
494     }
495
496     return str;
497 }
498
499 int read_xvg_legend(const char *fn,double ***y,int *ny,
500                     char **subtitle,char ***legend)
501 {
502   FILE   *fp;
503   char   *ptr,*ptr0,*ptr1;
504   char   *base=NULL;
505   char   *fmt=NULL;
506   int    k,line=0,nny,nx,maxx,rval,legend_nalloc,set,nchar;
507   double lf;
508   double **yy=NULL;
509   char  *tmpbuf;
510   int    len=STRLEN;
511   *ny  = 0;
512   nny  = 0;
513   nx   = 0;
514   maxx = 0;
515   fp   = gmx_fio_fopen(fn,"r");
516
517   snew(tmpbuf,len);
518   if (subtitle != NULL) {
519     *subtitle = NULL;
520   }
521   legend_nalloc = 0;
522   if (legend != NULL) {
523     *legend = NULL;
524   }
525
526   while ((ptr = fgets3(fp,tmpbuf,&len)) != NULL && ptr[0]!='&') {
527     line++;
528     trim(ptr);
529     if (ptr[0] == '@') {
530       if (legend != NULL) {
531         ptr++;
532         trim(ptr);
533         set = -1;
534     if (strncmp(ptr,"subtitle",8) == 0) {
535           ptr += 8;
536       if (subtitle != NULL)
537       {
538           *subtitle = read_xvgr_string(ptr);
539       }
540         } else if (strncmp(ptr,"legend string",13) == 0) {
541           ptr += 13;
542           sscanf(ptr,"%d%n",&set,&nchar);
543           ptr += nchar;
544         } else if (ptr[0] == 's') {
545           ptr++;
546           sscanf(ptr,"%d%n",&set,&nchar);
547           ptr += nchar;
548           trim(ptr);
549           if (strncmp(ptr,"legend",6) == 0) {
550             ptr += 6;
551           } else {
552             set = -1;
553           }
554         }
555         if (set >= 0) {
556           if (set >= legend_nalloc) {
557             legend_nalloc = set + 1;
558             srenew(*legend,legend_nalloc);
559         (*legend)[set] = read_xvgr_string(ptr);
560       }
561     }
562       }
563     } else if (ptr[0] != '#') {
564       if (nny == 0) {
565         (*ny) = nny = wordcount(ptr);
566         /* fprintf(stderr,"There are %d columns in your file\n",nny);*/
567         if (nny == 0)
568           return 0;
569         snew(yy,nny);
570         snew(fmt,3*nny+1);
571         snew(base,3*nny+1);
572       }
573       /* Allocate column space */
574       if (nx >= maxx) {
575         maxx+=1024;
576         for(k=0; (k<nny); k++)
577           srenew(yy[k],maxx);
578       }
579       /* Initiate format string */
580       fmt[0]  = '\0';
581       base[0] = '\0';
582       
583       /* fprintf(stderr,"ptr='%s'\n",ptr);*/
584       for(k=0; (k<nny); k++) {
585         strcpy(fmt,base);
586         strcat(fmt,"%lf");
587         rval = sscanf(ptr,fmt,&lf);
588         /* fprintf(stderr,"rval = %d\n",rval);*/
589         if ((rval == EOF) || (rval == 0))
590           break;
591         yy[k][nx] = lf;
592         srenew(fmt,3*(nny+1)+1);
593         srenew(base,3*nny+1);
594         strcat(base,"%*s");
595       }
596       if (k != nny) {
597         fprintf(stderr,"Only %d columns on line %d in file %s\n",
598                 k,line,fn);
599         for( ; (k<nny); k++)
600           yy[k][nx] = 0.0;
601       }
602       nx++;
603     }
604   }
605   gmx_fio_fclose(fp);
606   
607   *y = yy;
608   sfree(tmpbuf);
609
610   if (legend_nalloc > 0) {
611     if (*ny - 1 > legend_nalloc) {
612       srenew(*legend,*ny-1);
613       for(set=legend_nalloc; set<*ny-1; set++) {
614         (*legend)[set] = NULL;
615       }
616     }
617   }
618
619   return nx;
620 }
621
622 int read_xvg(const char *fn,double ***y,int *ny)
623 {
624     return read_xvg_legend(fn,y,ny,NULL,NULL);
625 }
626
627 void write_xvg(const char *fn,const char *title,int nx,int ny,real **y,
628                const char **leg,const output_env_t oenv)
629 {
630     FILE *fp;
631     int  i,j;
632
633     fp=xvgropen(fn,title,"X","Y",oenv);
634     if (leg)
635         xvgr_legend(fp,ny-1,leg,oenv);
636     for(i=0; (i<nx); i++) {
637         for(j=0; (j<ny); j++) {
638             fprintf(fp,"  %12.5e",y[j][i]);
639         }
640         fprintf(fp,"\n");
641     }
642     xvgrclose(fp);
643 }
644
645 real **read_xvg_time(const char *fn,
646                      gmx_bool bHaveT,gmx_bool bTB,real tb,gmx_bool bTE,real te,
647                      int nsets_in,int *nset,int *nval,real *dt,real **t)
648 {
649   FILE   *fp;
650 #define MAXLINELEN 16384
651   char line0[MAXLINELEN];
652   char   *line;
653   int    t_nalloc,*val_nalloc,a,narg,n,sin,set,nchar;
654   double dbl,tend=0;
655   gmx_bool   bEndOfSet,bTimeInRange,bFirstLine=TRUE;
656   real   **val;
657   
658   t_nalloc = 0;
659   *t  = NULL;
660   val = NULL;
661   val_nalloc = NULL;
662   *nset = 0;
663   *dt = 0;
664   fp  = gmx_fio_fopen(fn,"r");
665   for(sin=0; sin<nsets_in; sin++) {
666     if (nsets_in == 1)
667       narg = 0;
668     else 
669       narg = bHaveT ? 2 : 1;
670     n = 0;
671     bEndOfSet = FALSE;
672     while (!bEndOfSet && fgets(line0,MAXLINELEN,fp)) {
673       line = line0;
674       /* Remove whitespace */
675       while (line[0]==' ' || line[0]=='\t')
676         line++;
677       bEndOfSet = (line[0] == '&');
678       if (line[0]!='#' && line[0]!='@' && line[0]!='\n' && !bEndOfSet) {
679         if (bFirstLine && bHaveT) {
680           /* Check the first line that should contain data */
681           a = sscanf(line,"%lf%lf",&dbl,&dbl);
682           if (a == 0) 
683             gmx_fatal(FARGS,"Expected a number in %s on line:\n%s",fn,line0);
684           else if (a == 1) {
685             fprintf(stderr,"Found only 1 number on line, "
686                     "assuming no time is present.\n");
687             bHaveT = FALSE;
688             if (nsets_in > 1)
689               narg = 1;
690           }
691         }
692
693         a = 0;
694         bTimeInRange = TRUE;
695         while ((a<narg || (nsets_in==1 && n==0)) && 
696                sscanf(line,"%lf%n",&dbl,&nchar)==1 && bTimeInRange) {
697           /* Use set=-1 as the time "set" */
698           if (sin) {
699             if (!bHaveT || (a>0))
700               set = sin;
701             else
702               set = -1;
703           } else {
704             if (!bHaveT)
705               set = a;
706             else
707               set = a-1;
708           }
709           if (set==-1 && ((bTB && dbl<tb) || (bTE && dbl>te)))
710             bTimeInRange = FALSE;
711             
712           if (bTimeInRange) {
713             if (n==0) {
714               if (nsets_in == 1)
715                 narg++;
716               if (set >= 0) {
717                 *nset = set+1;
718                 srenew(val,*nset);
719                 srenew(val_nalloc,*nset);
720                 val_nalloc[set] = 0;
721                 val[set] = NULL;
722               }
723             }
724             if (set == -1) {
725               if (sin == 0) {
726                 if (n >= t_nalloc) {
727                   t_nalloc = over_alloc_small(n);
728                   srenew(*t,t_nalloc);
729                 }
730                 (*t)[n] = dbl;
731               }
732               /* else we should check the time of the next sets with set 0 */
733             } else {
734               if (n >= val_nalloc[set]) {
735                 val_nalloc[set] = over_alloc_small(n);
736                 srenew(val[set],val_nalloc[set]);
737               }
738               val[set][n] = (real)dbl;
739             }
740           }
741           a++;
742           line += nchar;
743         }
744         if (line0[strlen(line0)-1] != '\n') {
745           fprintf(stderr,"File %s does not end with a newline, ignoring the last line\n",fn);
746         } else if (bTimeInRange) {
747           if (a == 0) {
748             fprintf(stderr,"Ignoring invalid line in %s:\n%s",fn,line0);
749           } else {
750             if (a != narg)
751               fprintf(stderr,"Invalid line in %s:\n%s"
752                       "Using zeros for the last %d sets\n",
753                       fn,line0,narg-a);
754             n++;
755           }
756         }
757         if (a > 0)
758           bFirstLine = FALSE;
759       }
760     }
761     if (sin==0) {
762       *nval = n;
763       if (!bHaveT) {
764         snew(*t,n);
765         for(a=0; a<n; a++)
766           (*t)[a] = a;
767       }
768       if (n > 1)
769         *dt = (real)((*t)[n-1]-(*t)[0])/(n-1.0);
770       else
771         *dt = 1;
772     } else {
773       if (n < *nval) {
774         fprintf(stderr,"Set %d is shorter (%d) than the previous set (%d)\n",
775                 sin+1,n,*nval);
776         *nval = n;
777         fprintf(stderr,"Will use only the first %d points of every set\n",
778                 *nval);
779       }
780     }
781   }
782   gmx_fio_fclose(fp);
783
784   sfree(val_nalloc);
785   
786   return val;
787 }
788