root/branches/mcstas-1.x/mcformat.c

Revision 2822, 77.6 KB (checked in by farhi, 2 years ago)

Import main SVN McCode/trunk into 1.x branch. mcrun --test OK. compilation of all example instruments OK.

Line 
1/*******************************************************************************
2*
3* McStas, neutron ray-tracing package
4*         Copyright (C) 1997-2009, All rights reserved
5*         Risoe National Laboratory, Roskilde, Denmark
6*         Institut Laue Langevin, Grenoble, France
7*
8* Instrument: mcformat, McStas format converter
9*
10* %Identification
11* Written by: <a href="mailto:farhi@ill.fr">Emmanuel Farhi</a>
12* Date: 1st Feb 2001.
13* Origin: <a href="http://www.ill.fr">ILL (France)</a>
14* Release: McStas 1.12b
15* Version: $Revision: 1.36 $
16*
17* A McStas format converter to merge/convert data files.
18*
19* %Description
20*
21* A McStas format converter to merge convert data files.
22* Parameters are the files/directories to process, and option flags.
23* May be used to:
24* 1- continue an interupted simulation, and then add (--merge option) the similar
25*    data files.
26* 2- generate complex data formats to be used using different viewer from
27*    original simple text format (--format=...).
28* 3- catenate list files
29* 4- reconstruct parameter scan sumulations (--scan)
30*
31* Limitations: can not convert from binary files; Conversion from HTML/VRML
32* may fail; does not handle event files.
33*
34* %Parameters
35* INPUT PARAMETERS:
36* files [string]:  list of files/directories to convert, separated by spaces
37*
38* %Link
39*
40* %End
41*******************************************************************************/
42
43#ifndef MCFORMAT
44#define MCFORMAT  "$Revision: 1.36 $" /* avoid memory.c to define Pool functions */
45#endif
46
47#ifdef USE_MPI
48#undef USE_MPI
49#endif
50
51#ifdef USE_THREADS
52#undef USE_THREADS
53#endif
54
55#ifndef MCSTAS_VERSION
56#define MCSTAS_VERSION "1.12b - June 2010"
57#endif
58
59/* Instead of including mcstas.h file, which would then require to link most
60   of the functions of the mcstas executable, we just put there some parts of
61   the mcstas.h file.
62   Build: cc -o mcformat mcformat.c -lm
63*/
64
65#define fatal_error printf  /* remove debug.c dependency */
66#define debug(msg)
67
68#define MCSTAS_H                  /* avoids memory.c to import mcstas.h */
69typedef struct Pool_header *Pool; /* allows memory to be included */
70#include "memory.c"
71
72#include "lib/share/mcstas-r.h" /* with decl of MC_PATHSEP */
73
74#ifdef USE_NEXUS
75#include "lib/share/nexus-lib.h"
76#endif
77
78#include "lib/share/mcstas-r.c"
79
80/* end of parts copied from mcstas.h */
81
82#include "lib/share/read_table-lib.h" /* independent library */
83#include "lib/share/read_table-lib.c"
84
85#include <dirent.h>
86#include <errno.h>
87
88/* Functions defined in memory.c */
89
90void *mem(size_t);    /* Allocate memory. */
91void  memfree(void *);    /* Free memory. */
92char *str_dup(char *);    /* Allocate new copy of string. */
93char *str_dup_n(char *string, int n); /* Copies only first N chars. */
94char *str_cat(char *first, ...);/* Concatenate strings to allocated string. */
95char *str_quote(char *string);  /* Quote string for inclusion in C code */
96void  str_free(char *);   /* Free memory for string. */
97
98/* default global variables required by mcstas-r (usually generated in cogen) */
99int  mcdefaultmain         = 1;
100int  mctraceenabled        = 0;
101char mcinstrument_name[CHAR_BUF_LENGTH];
102char mcinstrument_source[CHAR_BUF_LENGTH];
103int  mcnumipar             = 0;
104struct mcinputtable_struct mcinputtable[CHAR_BUF_LENGTH];
105mcstatic FILE *mcsiminfo_file        = NULL;
106
107#ifdef USE_NEXUS
108#include "lib/share/nexus-lib.c"
109#endif
110
111
112/* default global variables for mcformat converter */
113int  files_to_convert_NB    = 0;          /* nb of files to convert */
114int  files_to_convert_Array[CHAR_BUF_LENGTH];  /* index of argv[] for these files */
115char mcforcemode =0;
116char mcverbose   =0;
117char mctestmode  =0;
118char mcmergemode =0;
119char mcscanmode  =0;
120char mcmergesamedir=0;
121int  mcdircount  =0; /* number of directories scanned */
122int  mcnbconvert =0; /* index of current file */
123FILE **mcsimfiles;
124char **mcdirnames;
125char **mcinstrnames;
126char **mcsources;
127char *mcoutputdir=NULL;
128int  ipar_var    =0;  /* column index of scan variable (used in mcformat_scan_compare) */
129
130struct fileparts_struct {
131  char *FullName;
132  char *Path;
133  char *Name;
134  char *Extension;
135};
136
137/* list of functions ******************************************************** */
138/*
139  char                     *str_dup_numeric(char *orig)
140  char                     *str_dup_name(char *orig, int length)
141  char                     *str_dup_label(char *orig)
142  char                     *str_last_word(char *orig)
143  struct                    fileparts_struct fileparts_init(void)
144  struct                    fileparts_struct fileparts(char *name)
145  void                      fileparts_free(struct fileparts_struct parts)
146  struct McStas_file_format mcformat_init_mcstas_struct(void)
147  void                      mcformat_print_mcstas_struct(struct McStas_file_format McStasStruct)
148  struct McStas_file_format mcformat_free_mcstas_struct(struct McStas_file_format McStasStruct)
149  struct McStas_file_format mcformat_read_mcstas(char *filename)
150  int                       mcformat_dirwalk(char *dir, int (*fcn)(char *))
151  static void               mcformat_usedir(char *dir)
152  int                       mcformat_output(struct McStas_file_format McStasStruct)
153  int                       mcformat_convert(char *name)
154  int                       mcformat_count(char *name)
155  int                       mcformat_merge_compare(int nb)
156  void                      mcformat_scan_compare(int nb)
157  int                       mcformat_merge_output(int nb)
158  void                      mcformat_usage(char *pgmname)
159  void                      mcformat_parseoptions(int argc, char *argv[])
160  int                       main(int argc, char *argv[])
161*/
162
163/*******************************************************************************
164* str_dup_numeric: makes a clean copy of a string and allocate as numeric
165*******************************************************************************/
166char *str_dup_numeric(char *orig)
167{
168  long i;
169  char *valid;
170
171  if (!orig || !strlen(orig)) return(NULL);
172
173  for (i=0; i < strlen(orig); i++)
174  {
175    if ( (orig[i] > 122)
176      || (orig[i] < 32)
177      || (strchr("!\"#$%&'()*,:;<=>?@[\\]^`/ ", orig[i]) != NULL) )
178    {
179      orig[i] = ' ';
180    }
181  }
182  orig[i] = '\0';
183  /* now skip spaces */
184  for (i=0; i < strlen(orig); i++) {
185    if (*orig == ' ') orig++;
186    else break;
187  }
188
189  valid=str_dup(orig);
190
191  return(valid);
192} /* str_dup_numeric */
193
194/*******************************************************************************
195* str_dup_name: makes a clean copy of a string and allocate as name
196*******************************************************************************/
197char *str_dup_name(char *orig, int length)
198{
199  char *valid;
200
201  if (!orig || !strlen(orig)) return(NULL);
202
203  valid=str_dup_n(orig, length > 0 ? length : strlen(orig));
204  mcvalid_name(valid, orig, 0);
205
206  return(valid);
207} /* str_dup_name */
208
209/*******************************************************************************
210* str_dup_label: makes a clean copy of a string and allocate as label/title
211*******************************************************************************/
212char *str_dup_label(char *orig)
213{
214  long i;
215  char *valid;
216  int  length=0;
217
218  if (!orig || !strlen(orig)) return(NULL);
219
220  for (i=0; i < strlen(orig); i++)
221  {
222    if ( (orig[i] > 122)
223      || (orig[i] < 32)
224      || (strchr("\"'=:;", orig[i]) != NULL) )
225    {
226      orig[i] = ' ';
227    }
228  }
229  orig[i] = '\0';
230  /* now skip spaces at begining */
231  for (i=0; i < strlen(orig); i++) {
232    if (*orig == ' ') orig++;
233    else break;
234  }
235  length = strlen(orig);
236  /* skip trailing blanks */
237  for (i=strlen(orig)-1; i > 0; i--) {
238    if (orig[i] == ' ') length--;
239    else break;
240  }
241
242  valid=str_dup_n(orig, length);
243
244  return(valid);
245} /* str_dup_label */
246
247/*******************************************************************************
248* str_last_word: points to last word of string
249*******************************************************************************/
250char *str_last_word(char *orig)
251{
252  char *pos_end  =NULL;
253  char *pos_begin=NULL;
254  char separators[]= MC_PATHSEP_S " !\"#$%&'()*,:;<=>?@[\\]^`/.";
255
256  /* first skip trailing separators */
257  pos_end = orig+strlen(orig);
258  while (pos_end > orig) {
259    if (strchr(separators, *pos_end)) pos_end--; /* pass separators at the end */
260    else break;
261  }
262  pos_begin = pos_end-1;
263  /* search for non separators (pass word) */
264  while (pos_begin >= orig) {
265    if (!strchr(separators, *pos_begin)) pos_begin--; /* pass non separators */
266    else break;
267  }
268  pos_begin++;
269
270  if (pos_begin < orig) pos_begin=orig;
271
272  return(pos_begin);
273} /* str_last_word */
274
275
276/*******************************************************************************
277* fileparts_init: Initialize a zero fileparts structure
278*******************************************************************************/
279struct fileparts_struct fileparts_init(void)
280{
281  struct fileparts_struct parts;
282
283  parts.FullName  = NULL;
284  parts.Path      = NULL;
285  parts.Name      = NULL;
286  parts.Extension = NULL;
287
288  return(parts);
289} /* fileparts_init */
290
291/*******************************************************************************
292* fileparts: Split a fully qualified file name/path into pieces
293* Returns a zero structure if called with NULL argument.
294* Returns: fields are non NULL if they exist
295*    Path is NULL if no Path
296*    Name is NULL if just a Path
297*    Extension is "" if just a dot
298*******************************************************************************/
299struct fileparts_struct fileparts(char *name)
300{
301  struct fileparts_struct parts;
302
303  parts = fileparts_init();
304
305  if (name) {
306    char *dot_pos    = NULL;
307    char *path_pos   = NULL;
308    char *end_pos    = NULL;
309    char *name_pos   = NULL;
310    long  dot_length = 0;
311    long  path_length= 0;
312    long  name_length= 0;
313
314    parts.FullName  = str_dup(name);
315    /* extract path+filename+extension from full filename */
316
317    if (strlen(name) == 0) return(parts);
318
319    end_pos = name+strlen(name);  /* end of file name */
320
321    /* extract path: searches for last file separator */
322    path_pos= strrchr(name, MC_PATHSEP_C);  /* last PATHSEP */
323
324    if (!path_pos) {
325      path_pos   =name;
326      path_length=0;
327      name_pos   =name;
328      parts.Path = str_dup("");
329    } else {
330      name_pos    = path_pos+1;
331      path_length = name_pos - name;  /* from start to path+sep */
332      if (path_length) {
333        parts.Path = str_cat(name, MC_PATHSEP_S, NULL);
334        strncpy(parts.Path, name, path_length);
335        parts.Path[path_length]='\0';
336      } else parts.Path = str_dup("");
337    }
338
339    /* extract ext: now looks for the 'dot' */
340    dot_pos = strrchr(name_pos, '.');           /* last dot */
341    if (dot_pos > name_pos) {
342      dot_length = end_pos - dot_pos;
343      if (dot_length > 0) {
344        parts.Extension = str_dup(name);
345        strncpy(parts.Extension, dot_pos+1, dot_length);  /* skip the dot */
346        parts.Extension[dot_length]='\0';
347      }
348    } else dot_pos = end_pos;
349
350    /* extract Name (without extension) */
351    name_length = dot_pos - name_pos; /* from path to dot */
352    if (name_length) {
353      parts.Name = str_dup(name);
354      strncpy(parts.Name, name_pos, name_length);
355      parts.Name[name_length]='\0';
356    }
357  } /* if (name) */
358  return (parts);
359} /* fileparts */
360
361/*******************************************************************************
362* fileparts_free: Free a fileparts_struct fields
363*******************************************************************************/
364void fileparts_free(struct fileparts_struct parts)
365{
366  str_free(parts.FullName);
367  str_free(parts.Path);
368  str_free(parts.Name);
369  str_free(parts.Extension);
370} /* fileparts_free */
371
372struct McStas_file_format {
373  char   *Source;
374  char   *Creator;
375  char   *Editor;
376  char   *InstrName;
377  char   *filename;
378  char   *Format;
379  char   *Date;
380  char   *EndDate;
381  double  Ncount;
382  char   *component;
383  char   *type;
384  char   *title;
385  char   *xlabel;
386  char   *ylabel;
387  char   *zlabel;
388  char   *xvar;
389  char   *yvar;
390  char   *zvar;
391  char   *xylimits;
392  char   *position;
393  char   *gravitation;
394  char   *outputname;
395  char   *Ncount_str;
396
397  t_Table *Data;
398
399  long    m, n, p;
400  double  x1, x2, y1, y2, z1, z2;
401  char   *ratio;
402  double  RunNum;
403  double *p0, *p1, *p2;
404  double Nsum, Psum, P2sum;
405  Coords  POSITION;
406
407  int  mcnumipar;
408  struct mcinputtable_struct *mcinputtable;
409  char *mcdirname;
410  double Scan_ipar_value;
411  int    Scan_ipar_index;
412  double Scan_mon_distance;
413  int    Scan_mon_index;
414}; /* McStas_file_format */
415
416struct McStas_file_format *Files_to_Merge=NULL;
417int                       *Scans_to_merge=NULL;
418
419/*******************************************************************************
420* mcformat_init_mcstas_struct: Init an empty McStas data structure
421*******************************************************************************/
422struct McStas_file_format mcformat_init_mcstas_struct(void)
423{
424  struct McStas_file_format McStasStruct;
425
426  McStasStruct.Format     = NULL;
427  McStasStruct.Creator    = NULL;
428  McStasStruct.Editor     = NULL;
429  McStasStruct.Date       = NULL;
430  McStasStruct.EndDate    = NULL;
431  McStasStruct.Ncount     = 0;
432  McStasStruct.type       = NULL;
433  McStasStruct.Source     = NULL;
434  McStasStruct.InstrName  = NULL;
435  McStasStruct.component  = NULL;
436  McStasStruct.title      = NULL;
437  McStasStruct.ratio      = NULL;
438  McStasStruct.filename   = NULL;
439  McStasStruct.xvar       = NULL;
440  McStasStruct.yvar       = NULL;
441  McStasStruct.xlabel     = NULL;
442  McStasStruct.ylabel     = NULL;
443  McStasStruct.zvar       = NULL;
444  McStasStruct.zlabel     = NULL;
445  McStasStruct.xylimits   = NULL;
446  McStasStruct.position   = NULL;
447  McStasStruct.outputname = NULL;
448  McStasStruct.Ncount_str = NULL;
449
450  McStasStruct.Data       = NULL;
451  McStasStruct.p0         = NULL;
452  McStasStruct.p1         = NULL;
453  McStasStruct.p2         = NULL;
454  McStasStruct.Nsum       = 0;
455  McStasStruct.Psum       = 0;
456  McStasStruct.P2sum      = 0;
457  McStasStruct.POSITION.x=McStasStruct.POSITION.y=McStasStruct.POSITION.z=0;
458
459  McStasStruct.RunNum     = 0;
460  McStasStruct.m          = 0;
461  McStasStruct.n          = 0;
462  McStasStruct.p          = 0;
463  McStasStruct.x1         = 0;
464  McStasStruct.x2         = 0;
465  McStasStruct.y1         = 0;
466  McStasStruct.y2         = 0;
467  McStasStruct.z1         = 0;
468  McStasStruct.z2         = 0;
469
470  McStasStruct.gravitation= NULL;
471
472  McStasStruct.mcnumipar          =0;
473  McStasStruct.mcinputtable       =NULL;
474  McStasStruct.mcdirname          =NULL;
475
476  McStasStruct.Scan_ipar_value  =0;
477  McStasStruct.Scan_ipar_index  =0;
478  McStasStruct.Scan_mon_distance=0;
479  McStasStruct.Scan_mon_index   =0;
480
481  return(McStasStruct);
482} /* mcformat_init_mcstas_struct */
483
484
485void mcformat_print_mcstas_struct(struct McStas_file_format McStasStruct)
486{
487  printf("Structure from file %s\n", McStasStruct.filename);
488  printf("  Format     = %s\n", McStasStruct.Format     );
489  printf("  Creator    = %s\n", McStasStruct.Creator    );
490  printf("  Editor     = %s\n", McStasStruct.Editor     );
491  printf("  Date       = %s\n", McStasStruct.Date       );
492  printf("  EndDate    = %s\n", McStasStruct.EndDate    );
493  printf("  type       = %s\n", McStasStruct.type       );
494  printf("  Source     = %s\n", McStasStruct.Source     );
495  printf("  InstrName  = %s\n", McStasStruct.InstrName  );
496  printf("  component  = %s\n", McStasStruct.component  );
497  printf("  title      = %s\n", McStasStruct.title      );
498  printf("  ratio      = %s\n", McStasStruct.ratio      );
499  printf("  xvar       = %s\n", McStasStruct.xvar       );
500  printf("  yvar       = %s\n", McStasStruct.yvar       );
501  printf("  xlabel     = %s\n", McStasStruct.xlabel     );
502  printf("  ylabel     = %s\n", McStasStruct.ylabel     );
503  printf("  zvar       = %s\n", McStasStruct.zvar       );
504  printf("  zlabel     = %s\n", McStasStruct.zlabel     );
505  printf("  xylimits   = %s\n", McStasStruct.xylimits   );
506  printf("  position   = %s\n", McStasStruct.position   );
507  printf("  outputname = %s\n", McStasStruct.outputname );
508  printf("  Ncount_str = %s\n", McStasStruct.Ncount_str );
509  printf("  mcdirname  = %s\n", McStasStruct.mcdirname );
510
511  printf("  gravitation= %s\n", McStasStruct.gravitation );
512  printf("  Ncount     = %g\n", McStasStruct.Ncount);
513  printf("  RunNum     = %g\n", McStasStruct.RunNum);
514
515  printf("  x1         = %g\n", McStasStruct.x1);
516  printf("  x2         = %g\n", McStasStruct.x2);
517  printf("  y1         = %g\n", McStasStruct.y1);
518  printf("  y2         = %g\n", McStasStruct.y2);
519  printf("  z1         = %g\n", McStasStruct.z1);
520  printf("  z2         = %g\n", McStasStruct.z2);
521
522  printf("  Data       = %s\n", McStasStruct.Data ? "OK" : "NULL");
523
524  printf("  m          = %ld\n", McStasStruct.m);
525  printf("  n          = %ld\n", McStasStruct.n);
526  printf("  p          = %ld\n", McStasStruct.p);
527
528  printf("  p0         = %s\n", McStasStruct.p0 ? "OK": "NULL");
529  printf("  p1         = %s\n", McStasStruct.p1 ? "OK": "NULL");
530  printf("  p2         = %s\n", McStasStruct.p2 ? "OK": "NULL");
531  printf("  POSITION   = %g %g %g\n", McStasStruct.POSITION.x, McStasStruct.POSITION.y, McStasStruct.POSITION.z);
532  printf("  mcnumipar  = %d\n", McStasStruct.mcnumipar);
533  printf("  inputtable = %s\n", McStasStruct.mcinputtable ? "OK": "NULL");
534}
535
536
537/*******************************************************************************
538* mcformat_free_mcstas_struct: Free a McStas data structure
539*******************************************************************************/
540struct McStas_file_format mcformat_free_mcstas_struct(struct McStas_file_format McStasStruct)
541{
542  memfree(McStasStruct.Format   );
543  memfree(McStasStruct.Date     );
544  memfree(McStasStruct.EndDate  );
545  memfree(McStasStruct.Creator  );
546  memfree(McStasStruct.Editor   );
547  memfree(McStasStruct.type     );
548  memfree(McStasStruct.Source   );
549  memfree(McStasStruct.InstrName);
550  memfree(McStasStruct.component);
551  memfree(McStasStruct.gravitation);
552  memfree(McStasStruct.title    );
553  memfree(McStasStruct.ratio    );
554  memfree(McStasStruct.filename );
555  memfree(McStasStruct.xvar     );
556  memfree(McStasStruct.yvar     );
557  memfree(McStasStruct.xlabel   );
558  memfree(McStasStruct.ylabel   );
559  memfree(McStasStruct.zvar     );
560  memfree(McStasStruct.zlabel   );
561  memfree(McStasStruct.xylimits );
562  memfree(McStasStruct.position );
563  memfree(McStasStruct.outputname );
564  memfree(McStasStruct.Ncount_str );
565
566  if (McStasStruct.Data) Table_Free_Array(McStasStruct.Data);
567  if (McStasStruct.p0) memfree(McStasStruct.p0 );
568  if (McStasStruct.p1) memfree(McStasStruct.p1 );
569  if (McStasStruct.p2) memfree(McStasStruct.p2 );
570
571  memfree(McStasStruct.mcdirname          );
572
573  /* free mcinputtable */
574  int i;
575  for (i=0; i<McStasStruct.mcnumipar; i++) {
576    memfree(McStasStruct.mcinputtable[i].name);
577    memfree(McStasStruct.mcinputtable[i].val);
578  }
579  memfree(McStasStruct.mcinputtable       );
580
581  return(McStasStruct);
582} /* mcformat_free_mcstas_struct */
583
584/*******************************************************************************
585* mcformat_read_mcstas:  Reads filename and checks for McStas format
586*                        extracts header and data and return structure
587*                        structure.p1 is NULL in case of failure
588*******************************************************************************/
589struct McStas_file_format mcformat_read_mcstas(char *filename)
590{
591  struct McStas_file_format McStasStruct;
592  int    m=1,n=1,p=1, i,j;
593  long   array_length=0;
594  char   flag_abort=0;
595  char   flag_pgplot1d=0;
596
597  /* init default empty return value */
598  McStasStruct = mcformat_init_mcstas_struct();
599
600  /* opens the file as a t_Table */
601  t_Table *rTable=NULL;
602
603  /* gets header and block 1 */
604  rTable = Table_Read_Array(filename, &array_length); /* reads all data */
605  if (!rTable) { if (mcverbose) fprintf(stderr, "mcformat: file %s not found\n", filename);
606    return(McStasStruct);
607  }
608
609  /* returns if this is not a McStas format file, or invalid */
610  if (!rTable[0].data || (array_length != 1 && array_length != 3))   {
611    if (mcverbose) fprintf(stderr, "mcformat: file %s is invalid (%ld blocks)\n", 
612      filename, array_length);
613    flag_abort=1;
614  } else if (!rTable[0].header) {
615    if (mcverbose) fprintf(stderr, "mcformat: Can not read header from file %s\n"
616      "          Data is [%ld x %ld]\n", filename, rTable[0].rows, rTable[0].columns);
617    flag_abort=1;
618  }
619
620  if (array_length == 3)
621      for (i=1; i<=2; i++)
622      if (rTable[0].rows != rTable[i].rows || rTable[0].columns != rTable[i].columns) {
623        if (mcverbose) fprintf(stderr, "mcformat: file %s Data dimensions are not consistent\n"
624          "          Data[%i] is [%ld x %ld]\n",
625          filename, i, rTable[i].rows, rTable[i].columns);
626          flag_abort=1;
627      }
628  if (flag_abort) {
629    Table_Free_Array(rTable);
630    return(McStasStruct);
631  }
632
633  /* analyze content of file : use read-table:Table_ParseHeader ********** */
634  char **parsing;
635  parsing = Table_ParseHeader(rTable[0].header,
636      "Format", /* original Format */
637      "Editor",
638      "Creator",
639      "Date",
640      "EndDate",
641      "File",   /* original filename */
642      "Source","Instrument-source",
643      "instrument",
644      "Ncount",
645      "Gravitation",
646      "type",
647      "component","parent",
648      "position",
649      "title",
650      "ratio",
651      "xlabel",
652      "ylabel",
653      "zlabel",
654      "xvar",
655      "yvar",
656      "zvar",
657      "xlimits", "xylimits",
658      NULL);
659
660    if (parsing) {
661      if (parsing[0])   McStasStruct.Format     = str_dup_label(parsing[0]);
662      if (parsing[1])   McStasStruct.Editor     = str_dup_label(parsing[1]);
663      if (parsing[2])   McStasStruct.Creator    = str_dup_label(parsing[2]);
664      if (parsing[3])   McStasStruct.Date       = str_dup_numeric(parsing[3]);  /* mcstartdate */
665      if (parsing[4])   McStasStruct.EndDate    = str_dup_numeric(parsing[4]);  /* DATL */
666/*   if (parsing[5])   McStasStruct.filename   = str_dup(parsing[5]); */
667      if (parsing[6])   McStasStruct.Source     = str_dup_label(parsing[6]);  /* mcinstrument_source */
668      if (parsing[7] && !McStasStruct.Source)
669                        McStasStruct.Source     = str_dup_label(parsing[7]);
670      if (parsing[8])   McStasStruct.InstrName  = str_dup_label(parsing[8]);  /* mcinstrument_name */
671      if (parsing[9])   McStasStruct.Ncount_str = str_dup_numeric(parsing[9]);
672      if (parsing[10])  McStasStruct.gravitation= str_dup_numeric(parsing[10]);/* mcgravitation */
673      if (parsing[11])  McStasStruct.type       = str_dup_label(parsing[11]); /* array_Xd */
674      if (parsing[12])  McStasStruct.component  = str_dup_label(parsing[12]); /* NAME_CURRENT_COMP */
675      if (parsing[13] && !McStasStruct.component)
676                        McStasStruct.component  = str_dup_label(parsing[13]);
677      if (parsing[14])  McStasStruct.position   = str_dup_numeric(parsing[14]); /* string(POS_A_CURRENT_COMP) */
678      if (parsing[15])  McStasStruct.title      = str_dup_label(parsing[15]);
679      if (parsing[16])  McStasStruct.ratio      = str_dup_numeric(parsing[16]); /* -> RunNum */
680      if (parsing[17])  McStasStruct.xlabel     = str_dup_label(parsing[17]);
681      if (parsing[18])  McStasStruct.ylabel     = str_dup_label(parsing[18]);
682      if (parsing[19])  McStasStruct.zlabel     = str_dup_label(parsing[19]);
683      if (parsing[20])  McStasStruct.xvar       = str_dup_label(parsing[20]);
684      if (parsing[21])  McStasStruct.yvar       = str_dup_label(parsing[21]);
685      if (parsing[22])  McStasStruct.zvar       = str_dup_label(parsing[22]);
686      if (parsing[23])  McStasStruct.xylimits   = str_dup_numeric(parsing[23]); /* x/y min/max */
687      if (parsing[24] && !McStasStruct.xylimits)
688                        McStasStruct.xylimits   = str_dup_numeric(parsing[24]);
689      for (i=0; i<=24; i++) {
690        if (parsing[i]) free(parsing[i]);
691      }
692      free(parsing);
693    }
694
695/* will be determined over original values when writting  new data file:
696        filename
697        format
698        statistics
699        signal
700        values
701     */
702  if (!McStasStruct.InstrName && !McStasStruct.Source)
703    McStasStruct.Source = str_dup("McStas_Instrument");
704  else if (!McStasStruct.InstrName && McStasStruct.Source) {
705    char *ext=NULL; /* if not found, use instr file name without extension */
706    ext = strstr(McStasStruct.Source, ".ins");
707    if (!ext) ext = strstr(McStasStruct.Source, " ins");
708    if (ext) McStasStruct.InstrName = str_dup_n(McStasStruct.Source, (ext-McStasStruct.Source));
709    else McStasStruct.InstrName = str_dup(McStasStruct.Source);
710  } else if (McStasStruct.InstrName && !McStasStruct.Source) {
711    char *ext=NULL; /* if not found, use instr name without extension */
712    ext = strstr(McStasStruct.InstrName, ".ins");
713    if (!ext) ext = strstr(McStasStruct.InstrName, " ins");
714    if (ext) McStasStruct.Source = str_dup_n(McStasStruct.InstrName, (ext-McStasStruct.InstrName));
715    else McStasStruct.Source = str_dup(McStasStruct.InstrName);
716  }
717
718  if (McStasStruct.Ncount_str) McStasStruct.Ncount=atof(McStasStruct.Ncount_str);
719
720  /* header analysis: general keywords */
721  if (McStasStruct.ratio) {  /* extracts RunNum and Ncount values separated by '/' */
722    double runnum=0, ncount=0;
723    int   i;
724    i = sscanf(McStasStruct.ratio, "%lg %lg", &runnum, &ncount);
725    if (i) McStasStruct.RunNum = runnum;
726    if (i>1) {
727      if (!McStasStruct.Ncount && ncount) McStasStruct.Ncount = ncount;
728      else if (ncount && McStasStruct.Ncount != ncount)
729        fprintf(stderr, "Warning: %s: conflicting Ncount %f value with 'ratio' one %f\n",
730          filename, McStasStruct.Ncount, ncount);
731    } else if (!McStasStruct.Ncount) /* no Ncount and ratio is a single value: Ncount == runnum */
732      McStasStruct.Ncount = McStasStruct.RunNum;
733  }
734  if (!McStasStruct.Ncount) {
735    McStasStruct.Ncount = 1e6;
736    fprintf(stderr, "Warning: %s: can not extract Ncount. using default (%g)\n",
737      filename, McStasStruct.Ncount);
738  }
739  if (!McStasStruct.RunNum) McStasStruct.RunNum = McStasStruct.Ncount;
740  if (McStasStruct.RunNum < McStasStruct.Ncount*0.99)
741    fprintf(stderr, "Warning: %s: Temporary results with ratio %g/%g. Simulation results are not completed.\n",
742      filename, McStasStruct.RunNum, McStasStruct.Ncount);
743 
744  /* analyse type, and check that Data dims are m,n,p */
745  if (McStasStruct.type) {
746    if (!strcmp(McStasStruct.type, "array_0d")) m=n=p=1;
747    else if (sscanf(McStasStruct.type, "array_1d(%d)",&m) == 1) n=p=1;
748    else if (sscanf(McStasStruct.type, "array_2d(%d, %d)",&n,&m) == 2) p=1;
749    else if (sscanf(McStasStruct.type, "array_3d(%d, %d, %d)",&n,&m,&p) == 3) { /* void */ }
750    else if (sscanf(McStasStruct.type, "multiarray_1d(%d)", &m)) {
751      if (!mcscanmode) fprintf(stderr, "Warning: %s: use --scan flag for multiarray/scans (skipped)\n", filename);
752      return(McStasStruct);
753    }
754  } else {
755    fprintf(stderr, "Warning: %s: invalid data type '%s' (not 1d/2d/3d/multiarray)\n", filename, McStasStruct.type);
756    return(McStasStruct);
757  }
758 
759/* Scans: just test existence. If yes, then will skip the SIM file */
760  /*
761  "# Numpoints: "
762  "# xvars: "
763  "# yvars: "
764*/
765  /* check if data block is transposed */
766  if (m != rTable[0].rows    && n != rTable[0].columns
767   && m == rTable[0].columns && n == rTable[0].rows) {
768    if (mcverbose) fprintf(stderr, "Warning: %s: Data block is transposed. Fixing.\n", filename);
769    int tmp=m;
770    m=n; n=tmp;
771  }
772  if (m != rTable[0].rows) {
773    fprintf(stderr, "Warning: %s: conflicting Data row numbers\n"
774                    "         expected=%d found=%ld. Fixing. Check first line of Data block.\n", filename, m, rTable[0].rows);
775    m = rTable[0].rows;
776  }
777  if (McStasStruct.Format && (strstr(McStasStruct.Format, "binary") || strstr(McStasStruct.Format, "float") || strstr(McStasStruct.Format, "double")))
778    fprintf(stderr, "WARNING: %s: Format of data file indicates binary blocks."
779                    "         Not supported. Might crash.\n", filename);
780  if (McStasStruct.Format && McStasStruct.type
781    && strstr(McStasStruct.Format, "PGPLOT") && array_length == 1 
782    && strstr(McStasStruct.type, "array_1d") && rTable[0].columns == 4) flag_pgplot1d=1;
783  if (flag_pgplot1d) n = 4;
784  if (n != rTable[0].columns) {
785    fprintf(stderr, "Warning: %s: conflicting Data column numbers\n"
786                    "         expected=%d found=%ld. Fixing. Check first line of Data block.\n", filename, n, rTable[0].columns);
787    n = rTable[0].columns;
788  }
789  if (flag_pgplot1d) n = 1;
790  McStasStruct.m = rTable[0].rows; /* dimensions from the Table */
791  McStasStruct.n = flag_pgplot1d ? 1 : rTable[0].columns;
792  McStasStruct.p = p; /* extracted from type */
793
794  m = McStasStruct.m;
795  n = McStasStruct.n;
796
797
798  /* extract limits values */
799  McStasStruct.x1=1; McStasStruct.x2=McStasStruct.m;
800  McStasStruct.y1=1; McStasStruct.y2=McStasStruct.n;
801  McStasStruct.z1=1; McStasStruct.z2=McStasStruct.p;
802  if (McStasStruct.xylimits) {
803    i = sscanf(McStasStruct.xylimits, "%lg %lg %lg %lg %lg %lg",
804      &(McStasStruct.x1), &(McStasStruct.x2),
805      &(McStasStruct.y1), &(McStasStruct.y2),
806      &(McStasStruct.z1), &(McStasStruct.z2));
807    if (i != 2 && i != 4 && i != 6)
808      fprintf(stderr, "Warning: %s: invalid xylimits '%s'. extracted %i values\n",
809        filename, McStasStruct.xylimits, i);
810  }
811 
812  /* special case of 2D binary files: axes must be exchanged */
813  if (strstr(mcformat.Name, "binary") || strstr(mcformat.Name, "float") || strstr(mcformat.Name, "double"))
814  if (p == 1 && m>1 && n>1) {
815    double tmp; char* c;
816    tmp=McStasStruct.x1; McStasStruct.x1=McStasStruct.y1; McStasStruct.y1=tmp; 
817    tmp=McStasStruct.x2; McStasStruct.x2=McStasStruct.y2; McStasStruct.y2=tmp; 
818    c=McStasStruct.xlabel; McStasStruct.xlabel=McStasStruct.ylabel; McStasStruct.ylabel=c;
819    c=McStasStruct.xvar;   McStasStruct.xvar=McStasStruct.yvar;     McStasStruct.yvar=c;
820  }
821 
822  McStasStruct.filename   = str_dup(filename);
823  if (!McStasStruct.component) McStasStruct.component=str_dup(filename);
824  struct fileparts_struct file_parts=fileparts(filename);
825  char *tmp=str_cat(file_parts.Name, ".", file_parts.Extension, NULL);
826  McStasStruct.outputname = str_dup_name(tmp, 0);
827  memfree(tmp);
828  fileparts_free(file_parts);
829  McStasStruct.mcdirname  = str_dup(mcdirname);
830  if (McStasStruct.position) sscanf(McStasStruct.position, "%lg %lg %lg",
831    &McStasStruct.POSITION.x,&McStasStruct.POSITION.y,&McStasStruct.POSITION.z);
832 
833  /* header analysis: get instrument parameters and fills numipar and inputtable */
834  char *s = rTable[0].header;
835  char *tok=s;
836  char *equal_sign=NULL;
837  char *name_start=NULL;
838  mcnumipar = 0;
839  while (tok) { /* extract parameter=value as clean names */
840    tok = strstr(s, "Parameters");
841    if (!tok) tok = strstr(s, "parameters");
842    if (!tok) tok = strstr(s, "Param");
843    if (!tok) tok = strstr(s, "param");
844    if (!tok) break;
845    parsing = Table_ParseHeader(tok, "Parameters", NULL); /* get line */
846    if (!parsing[0]) parsing = Table_ParseHeader(tok, "parameters", NULL); /* get line */
847    if (!parsing[0]) parsing = Table_ParseHeader(tok, "Param", NULL); /* get line */
848    if (!parsing[0]) parsing = Table_ParseHeader(tok, "param", NULL); /* get line */
849    name_start = (parsing[0] ? str_dup(parsing[0]) : NULL);
850    memfree(parsing[0]); free(parsing);
851    if (!name_start) break;
852    equal_sign = strchr(name_start+1, '=');
853    if (equal_sign > name_start && strlen(name_start)) {
854      char *name_to_equal=str_dup_n(name_start, equal_sign-name_start);
855      char *name=str_last_word(name_to_equal);
856      char *value      = str_dup(equal_sign+1);
857      if (name && value && strlen(name) && strlen(value)) {
858        char *name_label = str_dup_label(name);
859        /*printf("name_to_equal='%s' name='%s' value='%s'\n", name_to_equal, name, value); */
860        mcinputtable[mcnumipar].name = name_label;
861        mcinputtable[mcnumipar].type = instr_type_string;
862        mcinputtable[mcnumipar].val  = value;
863        mcinputtable[mcnumipar].par  = NULL;
864        mcnumipar++;
865      }
866      memfree(name_to_equal);
867    }
868    memfree(name_start);
869    s = tok+strlen("Param");
870  } /* end while tok */
871
872  /* now transfer mcinputtable into McStasStruct */
873  McStasStruct.mcnumipar = mcnumipar;
874  McStasStruct.mcinputtable = (struct mcinputtable_struct *)mem(mcnumipar*sizeof(struct mcinputtable_struct));
875  for (i=0; i<mcnumipar; i++) {
876    McStasStruct.mcinputtable[i] = mcinputtable[i];
877  }
878
879  McStasStruct.Data = rTable;
880
881  /* transfer Data into p0, p1, p2 */
882  McStasStruct.p1   = (double*)mem(McStasStruct.m*McStasStruct.n*McStasStruct.p*sizeof(double));
883  if ((array_length == 3 || flag_pgplot1d) && !strstr(McStasStruct.Format, " list ")) {
884    McStasStruct.p0 = (double*)mem(McStasStruct.m*McStasStruct.n*McStasStruct.p*sizeof(double));
885    McStasStruct.p2 = (double*)mem(McStasStruct.m*McStasStruct.n*McStasStruct.p*sizeof(double));
886  }
887
888  if (flag_pgplot1d)
889  { /* this is a 1D PGPLOT data file.
890       columns [ xvar, p, err, N ] */
891    memfree(McStasStruct.yvar); McStasStruct.yvar=str_dup("I");
892    for (i=0; i<m; i++) {
893      McStasStruct.p1[i] = Table_Index(McStasStruct.Data[0], i, 1);
894      McStasStruct.p2[i] = Table_Index(McStasStruct.Data[0], i, 2);
895      McStasStruct.p0[i] = Table_Index(McStasStruct.Data[0], i, 3);
896    }
897  } else if (array_length == 1 || strstr(McStasStruct.Format, " list ")) {
898    /* lists are stored as is */
899    for (i=0; i<m; i++)
900      for (j=0; j <n*p; j++) {
901        int tmp=i*n*p+j;
902        McStasStruct.p1[tmp] =
903          Table_Index(McStasStruct.Data[0], i, j);
904    }
905  } else if (array_length == 3) { /* order in files is [p, err, N] */
906    for (i=0; i<m; i++)
907      for (j=0; j <n*p; j++) {
908        int tmp=i*n*p+j;
909        McStasStruct.p1[tmp] = Table_Index(McStasStruct.Data[0], i, j);
910        McStasStruct.p2[tmp] = Table_Index(McStasStruct.Data[1], i, j);
911        McStasStruct.p0[tmp] = Table_Index(McStasStruct.Data[2], i, j);
912      }
913  } else
914    fprintf(stderr, "Warning: %s: can not store data blocks (total %ld).\n",
915                    filename, array_length);
916
917  /* compute back the original sigma->p2 array (see mcestimate_error) */
918  if (McStasStruct.p0 && McStasStruct.p1 && McStasStruct.p2) {
919    double *p0 = McStasStruct.p0;
920    double *p1 = McStasStruct.p1;
921    double *p2 = McStasStruct.p2;
922    for (i=0; i < m*n*p; i++) {
923      if (p2[i] > 0) p2[i] = (p0[i] > 1 ? ((p0[i]-1)*p2[i]*p2[i] + p1[i]*p1[i]/p0[i])/p0[i]
924                         : p1[i]);
925    }
926  }
927  McStasStruct.m *= -1; /* always transposed in files w/r to memory */
928
929  /* free McStasStruct.Data for better memory management */
930  Table_Free_Array(McStasStruct.Data); McStasStruct.Data=NULL;
931
932  return(McStasStruct);
933} /* end mcformat_read_mcstas */
934
935/*******************************************************************************
936* mcformat_dirwalk:  apply fcn to all files in dir (see K & R 'C language')
937*                    returns number of processed files
938*******************************************************************************/
939int mcformat_dirwalk(char *dir, int (*fcn)(char *))
940{
941  char name[CHAR_BUF_LENGTH];
942  int  ret=0;
943  struct dirent *dp;
944  DIR *dfd;
945
946  if ((dfd = opendir(dir)) == NULL) {
947    fprintf(stderr, "mcformat: can't open %s\n", dir);
948    return 0;
949  }
950  while ((dp = readdir(dfd)) != NULL) {
951    if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0)
952      continue;    /* skip self and parent */
953    if (strlen(dir)+strlen(dp->d_name)+2 > sizeof(name))
954      fprintf(stderr, "mcformat: name %s%c%s too long\n",
955        dir, MC_PATHSEP_C, dp->d_name);
956    else {
957      sprintf(name, "%s%c%s", dir, MC_PATHSEP_C, dp->d_name);
958      ret += (*fcn)(name);
959    }
960  }
961  closedir(dfd);
962  return(ret);
963} /* end mcformat_dirwalk */
964
965/*******************************************************************************
966* mcformat_usedir: set directory to use. Same as mcuse_dir with force option.
967*******************************************************************************/
968static void mcformat_usedir(char *dir)
969{
970#ifdef MC_PORTABLE
971  fprintf(stderr, "Error: "
972          "Directory output cannot be used with portable simulation (mcformat_usedir)\n");
973  return;
974#else  /* !MC_PORTABLE */
975#ifndef WIN32
976  if(!mctestmode && mkdir(dir, 0777))
977#else
978  if(!mctestmode && mkdir(dir))
979#endif
980  {
981    int errno_mkdir = errno;
982    if (errno_mkdir == ENOENT) {
983      if (mcverbose) fprintf(stderr, "mkdir: ENOENT A directory component in pathname '%s' does not exist or is a dangling symbolic link.\n", dir);
984      /* we build the required elements in the path */
985      struct fileparts_struct dir_parts = fileparts(dir);
986      if (strlen(dir_parts.Path)) {
987        char *path_pos= strrchr(dir_parts.Path, MC_PATHSEP_C);  /* last PATHSEP */
988        if (path_pos == dir_parts.Path+strlen(dir_parts.Path)-1) dir_parts.Path[strlen(dir_parts.Path)-1] = '\0';
989        if (mcverbose) fprintf(stderr, "mcformat: Warning: building output directory '%s' from '%s'.\n", dir_parts.Path, dir);
990        mcformat_usedir(dir_parts.Path);
991        fileparts_free(dir_parts);
992        mcformat_usedir(dir);
993      }
994    } else if (errno_mkdir == EEXIST) {
995      fprintf(stderr, "mkdir: EEXIST pathname %s already exists (not necessarily as a directory).\n", dir);
996      if (!mcforcemode && mcscanmode != 2) {
997        fprintf(stderr, "Error: unable to create directory '%s' (mcformat_usedir)\n", dir);
998        fprintf(stderr, "(Maybe the directory already exists? Use --force, --scan-only or --test before -d %s to override)\n", dir);
999        exit(1);
1000      }
1001      fprintf(stderr, "mcformat: Warning: re-using output directory '%s'.\n", dir);
1002    } else {
1003      switch (errno_mkdir) {
1004#ifdef EACCES
1005      case EACCES:
1006        fprintf(stderr, "mkdir: EACCES The parent directory does not allow write permission\n"
1007        "       or one of the directories in pathname did not allow search permission.\n"); break;
1008#endif
1009#ifdef EFAULT
1010      case EFAULT:
1011        fprintf(stderr, "mkdir: EFAULT pathname points outside your accessible address space.\n"); break;
1012#endif
1013#ifdef ELOOP
1014      case ELOOP:
1015        fprintf(stderr, "mkdir: ELOOP Too many symbolic links were encountered in resolving pathname.\n"); break;
1016#endif
1017#ifdef ENAMETOOLONG
1018      case ENAMETOOLONG:
1019        fprintf(stderr, "mkdir: ENAMETOOLONG pathname was too long.\n"); break;
1020#endif
1021#ifdef ENOMEM
1022      case ENOMEM:
1023        fprintf(stderr, "mkdir: ENOMEM Insufficient kernel memory was available.\n"); break;
1024#endif
1025#ifdef ENOSPC
1026      case ENOSPC:
1027        fprintf(stderr, "mkdir: ENOSPC The device containing pathname has no room for the new directory.\n"); break;
1028#endif
1029#ifdef ENOTDIR
1030      case ENOTDIR:
1031        fprintf(stderr, "mkdir: ENOTDIR A component used as a directory in pathname is not, in fact, a directory.\n"); break;
1032#endif
1033#ifdef EPERM
1034      case EPERM:
1035        fprintf(stderr, "mkdir: EPERM The filesystem containing pathname does not support the creation of directories.\n"); break;
1036#endif
1037#ifdef EROFS
1038      case EROFS:
1039        fprintf(stderr, "mkdir: EROFS pathname refers to a file on a read-only filesystem.\n"); break;
1040#endif
1041      default:
1042        fprintf(stderr, "mkdir: ERROR %i using mkdir.\n", errno_mkdir); break;
1043      }
1044      fprintf(stderr, "mcformat: Fatal error accessing %s. Aborting.\n", dir);
1045      exit(-1);
1046    }
1047  }
1048  if (mcverbose) printf("mcformat: Creating directory %s.\n", dir);
1049  mcdirname = dir;
1050
1051#endif /* !MC_PORTABLE */
1052} /* mcformat_usedir */
1053
1054/*******************************************************************************
1055* mcformat_output: write monitor file and optionally free memory
1056*******************************************************************************/
1057int mcformat_output(struct McStas_file_format McStasStruct)
1058{
1059  char *currentdir= mcdirname; /* save current dir */
1060  int i;
1061
1062
1063  if (mctestmode) return(1);
1064  if (!McStasStruct.p1) return(0); /* empty data */
1065  /* determine in which directory we are and set SIM file */
1066
1067  if (!mcdircount) {
1068    if (!strlen(mcinstrument_name)) strcpy(mcinstrument_name, McStasStruct.InstrName);
1069    if (!strlen(mcinstrument_source)) strcpy(mcinstrument_source, McStasStruct.Source);
1070    if (!mcsiminfo_file) mcsiminfo_init(NULL); /* open SIM file once */
1071  } else {
1072    if (!mcmergemode) i=mcdircount-1;
1073    else {
1074      for (i=0; i<mcdircount; i++)
1075        if (!strcmp(mcdirnames[i], McStasStruct.mcdirname)) break;
1076    }
1077    if (i >= mcdircount) {
1078        fprintf(stderr, "ERROR: unable to find directory '%s' in scanned list\n", McStasStruct.mcdirname);
1079        return(0);
1080    }
1081    if (!mcsimfiles[i]) {
1082      mcdirname      = McStasStruct.mcdirname;
1083      mcinstrnames[i]= str_dup(McStasStruct.InstrName);
1084      mcsources[i]   = str_dup(McStasStruct.Source);
1085      strncpy(mcinstrument_name,     str_last_word(mcinstrnames[i]), CHAR_BUF_LENGTH);
1086      strncpy(mcinstrument_source  , str_dup(mcsources[i]), CHAR_BUF_LENGTH);
1087      mcsiminfo_init(NULL); /* open new SIM file in this dir for the first time */
1088      mcsimfiles[i]  = mcsiminfo_file;
1089    } else mcsiminfo_file = mcsimfiles[i];
1090    mcdirname = mcdirnames[i];
1091  }
1092
1093/* transfer to global variables used in output functions */
1094  if (!McStasStruct.Date) mcstartdate = 0;
1095  else {
1096    mcstartdate         = atol(McStasStruct.Date);
1097    if (!mcstartdate) sscanf(McStasStruct.Date, "Simulation started %ld", &mcstartdate);
1098  }
1099  mcgravitation       = (McStasStruct.gravitation && strstr(McStasStruct.gravitation, "yes") ? 1 : 0);
1100  mcrun_num = McStasStruct.RunNum;
1101  mcncount  = McStasStruct.Ncount;
1102  strncpy(mcinstrument_source, str_dup(McStasStruct.Source), CHAR_BUF_LENGTH);
1103  strncpy(mcinstrument_name  , str_last_word(McStasStruct.InstrName), CHAR_BUF_LENGTH);
1104  /* transfer mcnumipar */
1105  mcnumipar = McStasStruct.mcnumipar;
1106  for (i=0; i<mcnumipar; i++) {
1107    mcinputtable[i] = McStasStruct.mcinputtable[i];
1108  }
1109  mcdirname = McStasStruct.mcdirname;
1110
1111  /* write data file from McStasStruct */
1112  if (mcverbose) printf("mcformat: Writing %s from %s\n", McStasStruct.outputname, McStasStruct.filename);
1113
1114  if (strstr(McStasStruct.Format, "PGPLOT") && strstr(McStasStruct.type, "array_1d") && !mctestmode) {
1115    mcdetector_out_1D(McStasStruct.title, McStasStruct.xlabel, McStasStruct.ylabel,
1116                  McStasStruct.xvar, McStasStruct.x1, McStasStruct.x2, McStasStruct.m,
1117                  McStasStruct.p0, McStasStruct.p1, McStasStruct.p2, McStasStruct.outputname,
1118                  McStasStruct.component, McStasStruct.POSITION);
1119  } else if (!mctestmode)
1120  mcdetector_out_3D(McStasStruct.title,
1121    McStasStruct.xlabel, McStasStruct.ylabel, McStasStruct.zlabel,
1122    McStasStruct.xvar, McStasStruct.yvar, McStasStruct.zvar,
1123    McStasStruct.x1, McStasStruct.x2, McStasStruct.y1, McStasStruct.y2, McStasStruct.z1, McStasStruct.z2,
1124    McStasStruct.m, McStasStruct.n,  McStasStruct.p,
1125    McStasStruct.p0,
1126    McStasStruct.p1,
1127    McStasStruct.p2,
1128    McStasStruct.outputname,
1129    McStasStruct.component,
1130    McStasStruct.POSITION);
1131
1132  mcdirname = currentdir;
1133  return(1);
1134} /* end mcformat_output */
1135
1136/*******************************************************************************
1137* mcformat_convert: recursive wrapper to the conversion routine (see K & R)
1138*                   returns number of processed files
1139*******************************************************************************/
1140int mcformat_convert(char *name)
1141{
1142  struct stat               stbuf;
1143  struct McStas_file_format McStasFile;
1144  int    ret=0;
1145
1146  if (!name || !strlen(name)) return(0);
1147
1148  if (stat(name, &stbuf) == -1) {
1149    fprintf(stderr, "mcformat: can't access file %s\n", name);
1150    return 0;
1151  }
1152  if ((stbuf.st_mode & S_IFMT) == S_IFDIR) { /* dir: recursive call */
1153    char *upper_dir= mcdirname;
1154    char *name_win=name;
1155#ifdef WIN32
1156    if (isalpha(name[0]) && name[1] == ':') name_win += 2;  // skip Windows disk label before cat
1157#endif
1158    char *lower_dir= mcoutputdir ? str_cat(mcoutputdir, MC_PATHSEP_S, name_win, NULL)
1159                               : str_dup(name);
1160    /* entering new directory */
1161    if (!mctestmode) mcformat_usedir(lower_dir);
1162    else mcdirname = lower_dir;
1163    mcdirnames[mcdircount] = lower_dir;
1164    mcsimfiles[mcdircount] = NULL;
1165    mcinstrnames[mcdircount]=NULL;
1166    mcsources[mcdircount]   =NULL;
1167    mcdircount++; /* number of directories scanned */
1168    ret += mcformat_dirwalk(name, mcformat_convert);
1169    if (mcverbose) printf("mcformat: coming back to upper directory %s\n", upper_dir);
1170    mcdirname = upper_dir;
1171  } else {
1172    /* process the current file */
1173    if (mcverbose) printf("mcformat: reading %s (%ld bytes)\n", name, stbuf.st_size);
1174    McStasFile = mcformat_read_mcstas(name);
1175
1176    if (!McStasFile.p1) {
1177      if (mcverbose) fprintf(stderr, "mcformat: warning: skipping %s (invalid format).\n", name);
1178      return 0;
1179    }
1180
1181    if (!mcmergemode && !mcscanmode) { /* direct conversion */
1182
1183      /* now calls the output routines: sim and data files (0d, 1d, 2d) and free */
1184      if (mcverbose) mcformat_print_mcstas_struct(McStasFile); fflush(stdout);
1185      if (mcformat_output(McStasFile))
1186        if (mcverbose) {
1187          printf("mcformat: converting %s (%ld bytes) ", name, stbuf.st_size);
1188          printf("into %s%s ", mcdirname ? mcdirname : ".", mcdirname ? MC_PATHSEP_S : "");
1189          if (mctestmode) printf(" (--test mode)\n"); else printf("\n");
1190        }
1191
1192      mcformat_free_mcstas_struct(McStasFile);
1193
1194    } else { /* store: merging of all files from either a scan or similar files */
1195      Files_to_Merge[mcnbconvert] = McStasFile; /* copy */
1196      mcnbconvert++; /* global index */
1197    }
1198
1199    ret++; /* number of valid data files loaded from DIR */
1200  } /* end else single file */
1201  return (ret);
1202} /* end mcformat_convert */
1203
1204/*******************************************************************************
1205* mcformat_count: count the number of files to store for merge mode
1206*******************************************************************************/
1207int mcformat_count(char *name)
1208{
1209  struct stat               stbuf;
1210  int    ret=0;
1211
1212  if (!name || !strlen(name)) return(0);
1213
1214  if (stat(name, &stbuf) == -1) {
1215    fprintf(stderr, "mcformat: can't access file %s\n", name);
1216    return 0;
1217  }
1218  if ((stbuf.st_mode & S_IFMT) == S_IFDIR) { /* recursive call */
1219    mcdircount++; /* number of directories scanned */
1220    ret += mcformat_dirwalk(name, mcformat_count);
1221  } else {
1222    ret++;
1223  }
1224  return (ret);
1225} /* end mcformat_count */
1226
1227/*******************************************************************************
1228* mcformat_merge_compare: merge files and free the redundant items. Find scans.
1229*******************************************************************************/
1230int mcformat_merge_compare(int nb)
1231{
1232  int i,j,k;
1233
1234  if (!Files_to_Merge) return(0);
1235  /* loop on Files_to_Merge */
1236  for (i=0; i<nb; i++) {
1237    struct McStas_file_format McStasStruct=Files_to_Merge[i];
1238
1239    /* skip empty elements */
1240    if (!McStasStruct.p1) continue;
1241   
1242    /* we multiply the p1 and p2 by the Ncount so that the operations take
1243       into account the relative Ncount weight of each simulation. We will
1244       divide by the sum(Ncount) at the end of operation */
1245    if (!strstr(McStasStruct.Format, " list ")) /* NOT FOR LISTs (content non additive) */
1246    for (j=0; j<abs(McStasStruct.m*McStasStruct.n*McStasStruct.p); j++) {
1247      Files_to_Merge[i].p1[j] *= Files_to_Merge[i].Ncount;
1248      if (Files_to_Merge[i].p2) Files_to_Merge[i].p2[j] *= Files_to_Merge[i].Ncount;
1249    }
1250   
1251    /* second loop to search for similar items to add to Files_to_Merge[i] */
1252    for (j=i+1; j<nb; j++) {
1253      struct McStas_file_format ThisStruct=Files_to_Merge[j];
1254      if (!ThisStruct.p1) continue;
1255
1256      /* Parameters check: mcinputtable.name and mcinputtable.val */
1257      /* flag_equiv_parname must be true  to go on */
1258      /* flag_equiv_parval  is      false if this is a SCAN item */
1259      char flag_equiv_parname = (ThisStruct.mcnumipar == McStasStruct.mcnumipar);
1260      char flag_equiv_parval  = flag_equiv_parname;
1261      if (flag_equiv_parname) {
1262        for (k=0; k<McStasStruct.mcnumipar; k++) {
1263          /* test if parameter names are the same */
1264          if (strcmp(ThisStruct.mcinputtable[k].name, McStasStruct.mcinputtable[k].name))
1265            { flag_equiv_parname=0; break; }
1266          if (strcmp(ThisStruct.mcinputtable[k].val, McStasStruct.mcinputtable[k].val))
1267            flag_equiv_parval=0;
1268        }
1269      }
1270      if (!flag_equiv_parname) continue;
1271
1272      /* Data/List: must be of same kind */
1273      char flag_list = 0;
1274        if ( strstr(ThisStruct.Format, " list ")      &&  strstr(McStasStruct.Format, " list "))
1275          flag_list=1; /* two lists */
1276        else if (!strstr(ThisStruct.Format, " list ") && !strstr(McStasStruct.Format, " list "))
1277          flag_list=2; /* two monitors */
1278      if (!flag_list) continue;
1279
1280      /* Data type check: dimension, limits, xvar, yvar, zvar, xlabel, ylabel, zlabel */
1281      /* limits may be forced (to avoid rounding errors) */
1282      /* number of rows may be different for lists */
1283      char flag_data = (
1284        (flag_list==1 || ThisStruct.m == McStasStruct.m) &&
1285        ThisStruct.n == McStasStruct.n &&
1286        ThisStruct.p == McStasStruct.p &&
1287        (!ThisStruct.xvar || !McStasStruct.xvar || !strcmp(ThisStruct.xvar, McStasStruct.xvar)) &&
1288        (!ThisStruct.yvar || !McStasStruct.yvar || !strcmp(ThisStruct.yvar, McStasStruct.yvar)) &&
1289        (!ThisStruct.zvar || !McStasStruct.zvar || !strcmp(ThisStruct.zvar, McStasStruct.zvar)) &&
1290        (!ThisStruct.xlabel || !McStasStruct.xlabel || !strcmp(ThisStruct.xlabel, McStasStruct.xlabel)) &&
1291        (!ThisStruct.ylabel || !McStasStruct.ylabel || !strcmp(ThisStruct.ylabel, McStasStruct.ylabel)) &&
1292        (!ThisStruct.zlabel || !McStasStruct.zlabel || !strcmp(ThisStruct.zlabel, McStasStruct.zlabel)) );
1293      if (!flag_data) continue;
1294     
1295      char flag_limits=(mcforcemode || mcscanmode || 
1296          (ThisStruct.n == 1 && ThisStruct.x1 == McStasStruct.x1) ||
1297          (ThisStruct.x1 == McStasStruct.x1 && ThisStruct.y1 == McStasStruct.y1)
1298          );
1299      if (!flag_limits)  {
1300        fprintf(stderr, "Warning: Axes limits are not identical for %s and %s. Skipping (use --force to override).\n",
1301          McStasStruct.filename, ThisStruct.filename);
1302        continue;
1303      }
1304
1305      /* Warning if gravitation not constant (may be forced) */
1306      char flag_gravitation = mcforcemode || (
1307           ThisStruct.gravitation && McStasStruct.gravitation
1308        && !strcmp(ThisStruct.gravitation, McStasStruct.gravitation));
1309      if (!flag_gravitation && (ThisStruct.gravitation || McStasStruct.gravitation))
1310        fprintf(stderr, "Warning: Gravitation is not constant for %s and %s.\n",
1311          McStasStruct.filename, ThisStruct.filename);
1312
1313      /* Names check: InstrName, Source and component */
1314      /* directories must be different except if mcmergesamedir */
1315      char flag_names = (
1316        (!ThisStruct.InstrName || !McStasStruct.InstrName
1317            || !strcmp(ThisStruct.InstrName, McStasStruct.InstrName)) &&
1318        (!ThisStruct.Source || !McStasStruct.Source
1319            || !strcmp(ThisStruct.Source, McStasStruct.Source)) &&
1320        (!ThisStruct.component || !McStasStruct.component
1321            || !strcmp(ThisStruct.component, McStasStruct.component)) &&
1322        (mcmergesamedir || !ThisStruct.mcdirname || !McStasStruct.mcdirname
1323            || strcmp(ThisStruct.mcdirname, McStasStruct.mcdirname)) );
1324      if (!flag_names) continue;
1325
1326      /* handle scan index */
1327      if (!flag_equiv_parval) {
1328        /* attach index j to scan column origin monitor 'i' */
1329        if (Scans_to_merge[i] < 0) Scans_to_merge[i] = i;
1330        if (mcverbose && Scans_to_merge[j] < 0 && Scans_to_merge[i] >= 0) printf("  Gathering Scan step %s/%s (%d) with %s/%s (%d)\n",
1331          McStasStruct.mcdirname, McStasStruct.outputname, i,
1332          ThisStruct.mcdirname,  ThisStruct.outputname,    j);
1333        if (Scans_to_merge[j] < 0) Scans_to_merge[j] = i;
1334        /* next i if this is a scan (no add/cat) */
1335        continue; /* for j */
1336      }
1337
1338      if (!mcmergemode) continue;
1339
1340      if (mcverbose) fprintf(stderr,"  %s %s/%s (%d) with %s/%s (%d) total %ld elements\n",
1341        flag_list==2 ? "Adding" : "Appending",
1342        McStasStruct.mcdirname, McStasStruct.outputname, i,
1343        ThisStruct.mcdirname,  ThisStruct.outputname,    j,
1344        (long)abs(McStasStruct.m*McStasStruct.n*McStasStruct.p));
1345
1346      if (flag_list==1) {  /* if list: catenate data j to end of i */
1347        /* allocate new array of size rows(i+j), same n,p */
1348        double *p1=mem(abs((ThisStruct.m+McStasStruct.m)*McStasStruct.n*McStasStruct.p)*sizeof(double));
1349        /* copy data from i */
1350        int index_i, index_j, index; /* data index is index_i*columns+index_j */
1351        for (index_i=0; index_i<abs(McStasStruct.m); index_i++)
1352          for (index_j=0; index_j<abs(McStasStruct.n*McStasStruct.p); index_j++) {
1353            index=index_i*abs(McStasStruct.n*McStasStruct.p)+index_j;
1354            p1[index] = McStasStruct.p1[index];
1355        }
1356        /* catenate data from j */
1357        for (index_i=0; index_i<abs(ThisStruct.m); index_i++)
1358          for (index_j=0; index_j<abs(McStasStruct.n*McStasStruct.p); index_j++) {
1359            int index_shifted=(index_i+abs(McStasStruct.m))*abs(McStasStruct.n*McStasStruct.p)+index_j;
1360            index=index_i*abs(McStasStruct.n*McStasStruct.p)+index_j;
1361            p1[index_shifted] = ThisStruct.p1[index];
1362        }
1363        Files_to_Merge[i].m += ThisStruct.m;
1364        /* free original arrays in i and j */
1365        memfree(McStasStruct.p1); memfree(ThisStruct.p1);
1366        Files_to_Merge[j].p1 = NULL;
1367        /* attach new array to i and leave j in empty state */
1368        Files_to_Merge[i].p1 = p1;
1369      } else { /* else add data i+j */
1370        int index_i;
1371        /* add data from j to i. p1 and p2 are weighted by their Ncount */
1372        for (index_i=0; index_i<abs(McStasStruct.m*McStasStruct.n*McStasStruct.p); index_i++) {
1373          if (McStasStruct.p0) Files_to_Merge[i].p0[index_i] += ThisStruct.p0[index_i];
1374                               Files_to_Merge[i].p1[index_i] += ThisStruct.Ncount*ThisStruct.p1[index_i];
1375          if (McStasStruct.p2) Files_to_Merge[i].p2[index_i] += ThisStruct.Ncount*ThisStruct.p2[index_i];
1376         
1377        }
1378        /* free and leave j in empty state */
1379        memfree(ThisStruct.p0); memfree(ThisStruct.p1); memfree(ThisStruct.p2);
1380        Files_to_Merge[j].p0=Files_to_Merge[j].p1=Files_to_Merge[j].p2=NULL;
1381      }
1382      Files_to_Merge[i].Ncount += ThisStruct.Ncount;
1383      Files_to_Merge[i].RunNum += ThisStruct.RunNum;
1384    } /* end for j */
1385   
1386    /* divide p1 and p2 by total Ncount to account for the weighted sum */
1387    if (!strstr(McStasStruct.Format, " list ")) /* NOT FOR LISTs (content non additive) */
1388    for (j=0; j<abs(McStasStruct.m*McStasStruct.n*McStasStruct.p); j++) {
1389      Files_to_Merge[i].p1[j] /= Files_to_Merge[i].Ncount;
1390      if (Files_to_Merge[i].p2) Files_to_Merge[i].p2[j] /= Files_to_Merge[i].Ncount;
1391    }
1392     
1393    /* now count integral values for item Files_to_Merge[i] */
1394    double Nsum=0, Psum=0, P2sum=0;
1395    for (j=0; j<abs(Files_to_Merge[i].m*Files_to_Merge[i].n*Files_to_Merge[i].p); j++) {
1396      double N=1,I=0,E=0;
1397      if (Files_to_Merge[i].p0) N = Files_to_Merge[i].p0[j];
1398      if (Files_to_Merge[i].p1) I = Files_to_Merge[i].p1[j];
1399      if (Files_to_Merge[i].p2) E = Files_to_Merge[i].p2[j];
1400      Nsum += N;
1401      Psum += I;
1402      P2sum += Files_to_Merge[i].p2 ? E : I*I;
1403    }
1404    Files_to_Merge[i].Nsum = Nsum;
1405    Files_to_Merge[i].Psum = Psum;
1406    Files_to_Merge[i].P2sum= P2sum;
1407  } /* end for i */
1408  return(nb);
1409} /* mcformat_merge_compare */
1410
1411/* sorting functions for qsort: sort monitor files with distance */
1412#ifdef HAVE_QSORT
1413int sort_distances (const void *a, const void *b)
1414{
1415  const int *pa = (const int *) a;
1416  const int *pb = (const int *) b;
1417  int ia=*pa;
1418  int ib=*pb;
1419  double da=Files_to_Merge[ia].POSITION.x*Files_to_Merge[ia].POSITION.x
1420           +Files_to_Merge[ia].POSITION.y*Files_to_Merge[ia].POSITION.y
1421           +Files_to_Merge[ia].POSITION.z*Files_to_Merge[ia].POSITION.z;
1422  double db=Files_to_Merge[ib].POSITION.x*Files_to_Merge[ib].POSITION.x
1423           +Files_to_Merge[ib].POSITION.y*Files_to_Merge[ib].POSITION.y
1424           +Files_to_Merge[ib].POSITION.z*Files_to_Merge[ib].POSITION.z;
1425  if       (da > db) return 1;
1426  else if (da < db) return -1;
1427  else /* same distance, sort on names */
1428  return strcmp(Files_to_Merge[ia].filename, Files_to_Merge[ib].filename);
1429}
1430
1431/* sorting functions for qsort: sort monitor column with ipar.val */
1432int sort_ipar_mon (const void *a, const void *b)
1433{
1434  const int *pa = (const int *) a;
1435  const int *pb = (const int *) b;
1436  int ia=*pa;
1437  int ib=*pb;
1438  double da=Files_to_Merge[ia].mcinputtable[ipar_var].type == instr_type_string ?
1439    0 : atof(Files_to_Merge[ia].mcinputtable[ipar_var].val);
1440  double db=Files_to_Merge[ib].mcinputtable[ipar_var].type == instr_type_string ?
1441    0 : atof(Files_to_Merge[ib].mcinputtable[ipar_var].val);
1442  if       (da > db) return 1;
1443  else if (da < db) return -1;
1444  else {/* same distance, sort on ipar value then filenames */
1445   int tmp=strcmp(Files_to_Merge[ia].mcinputtable[ipar_var].val,
1446                  Files_to_Merge[ib].mcinputtable[ipar_var].val);
1447   if (tmp) return(tmp);
1448   else return strcmp(Files_to_Merge[ia].filename, Files_to_Merge[ib].filename);
1449  }
1450}
1451#endif
1452
1453/*********************************************************************
1454* mcformat_scan_compare: assemble scanned monitors into multiarray sets
1455*                        warning: this function is a real headache
1456*********************************************************************/
1457void mcformat_scan_compare(int nb)
1458{
1459  /* definition of a scan
1460    Must be 'mergeable' data but with different ipar values
1461    Each Scans_to_merge[] index set is a column of multiarray_1d (this is a scanned monitor)
1462    Must analyse scan columns (Scans_to_merge[]) to gather them with
1463      -common ipar names (set of scanned monitors)
1464      -same set (monitor number) length and monitor names
1465      -same ipar values define rows
1466   */
1467  int scan_index1=0;
1468  int i=0,j;
1469 
1470  /* test if there is scan data to be processed */
1471  for (scan_index1=0; scan_index1<nb; scan_index1++) {
1472    if (Scans_to_merge[scan_index1] < 0 || Scans_to_merge[scan_index1] < scan_index1) continue;
1473    else { i=1; break; }
1474  }
1475   
1476  if (i == 0)
1477    fprintf(stderr, "Warning: Could not find scanned parameter within 'Param' lines in data file headers.\n"
1478          "Ignoring [mcformat:mcformat_scan_compare].\n");
1479
1480  /* loop on Scans_to_merge: index > -1  */
1481  for (scan_index1=0; scan_index1<nb; scan_index1++) {
1482    if (Scans_to_merge[scan_index1] < 0 || Scans_to_merge[scan_index1] < scan_index1) continue;
1483    /* get all sets of given index: Scans_to_merge[j] = index */
1484    int scan_length1= 1;
1485    int next_in_scan=-1;
1486    ipar_var        = 0; /* global variable, as it is used in sorting function 'sort_ipar_mon' */
1487    int scan_index2;
1488    /* compute length of monitor column (length of scan): scan_length1 */
1489    for (scan_index2=scan_index1+1; scan_index2<nb; scan_index2++)
1490      if (Scans_to_merge[scan_index1] == Scans_to_merge[scan_index2]) {
1491        scan_length1++;
1492        if (next_in_scan < 0) next_in_scan = scan_index2;
1493      }
1494    if (scan_length1 <= 1) continue; /* not a scan, single data set: go to next data file */
1495
1496    /* count other monitors in Scans_to_merge with same ipar names and values: mon_count */
1497    int mon_count=0;
1498    int Scan_columns[nb];
1499    for (scan_index2=0; scan_index2<nb; Scan_columns[scan_index2++]=-1);
1500
1501    for (scan_index2=0; scan_index2<nb; scan_index2++) {
1502      char flag_matchpar=0;
1503      if (scan_index1 == scan_index2) {
1504        mon_count++; Scan_columns[scan_index2] = scan_index1; continue;
1505      }
1506      /* must be a scan */
1507      if (Scans_to_merge[scan_index2] < 0) continue; /* scan_index2 */
1508      /* must have same numipar */
1509      if (Files_to_Merge[scan_index1].mcnumipar != Files_to_Merge[scan_index2].mcnumipar) continue; /* scan_index2 */
1510      /* must have same scan length as first monitor */
1511      int scan_length2= 0;
1512      for (j=scan_index2; j<nb; j++)
1513        if (Scans_to_merge[scan_index2] == Scans_to_merge[j]) {
1514          scan_length2++;
1515        }
1516      if (scan_length1 != scan_length2) continue; /* scan_index2 */
1517      /* must have same ipar.name and values along column */
1518      int ipar2;
1519      for (ipar2=0; ipar2<Files_to_Merge[scan_index2].mcnumipar; ipar2++) {
1520        char *this_parname = Files_to_Merge[scan_index2].mcinputtable[ipar2].name;
1521        char *this_parval  = Files_to_Merge[scan_index2].mcinputtable[ipar2].val;
1522        /* look back into 'scan_index1' series for similar parameters */
1523        for(j=scan_index1; j<nb; j++) {
1524          if (Scans_to_merge[j] == Scans_to_merge[scan_index1]) {
1525            /* in original column, look if we can find ipar */
1526            int ipar1;
1527            for (ipar1=0; ipar1<Files_to_Merge[j].mcnumipar; ipar1++) {
1528              if (strcmp(Files_to_Merge[j].mcinputtable[ipar1].name, this_parname)
1529               || strcmp(Files_to_Merge[j].mcinputtable[ipar1].val,  this_parval) ) continue; /* ipar1 */
1530              flag_matchpar=1;
1531              break;
1532            } /* for ipar1 */
1533            if (flag_matchpar) break; /* j: we found matching ipar both in scan_index1 and scan_index2 */
1534          } /* if */
1535        } /* for scan_index1b */
1536        if (!flag_matchpar) break; /* ipar2: ipar of scan_index2 not found in scan_index1 */
1537      } /* for ipar2 */
1538      if (!flag_matchpar) continue; /* scan_index2: an ipar of scan_index2 was not found in scan_index1. try other scan_index2 */
1539      else {
1540        mon_count++;
1541        /* attach that file to first monitor of dir/column */
1542        Scan_columns[scan_index2] = scan_index2;
1543      }
1544    } /* for scan_index2 */
1545
1546    /* get first varying ipar: ipar_var */
1547    for (j=0; j<Files_to_Merge[scan_index1].mcnumipar; j++) {
1548      /* compare ipar value of scan_index1 and next_in_scan: stored in j */
1549      if (strcmp(Files_to_Merge[scan_index1].mcinputtable[j].val, Files_to_Merge[next_in_scan].mcinputtable[j].val)) break;
1550    }
1551    /* test if ipar has changed in scan else go to next data file */
1552    if (j < Files_to_Merge[scan_index1].mcnumipar) ipar_var=j;
1553    /* now we know how many scanned monitor there are */
1554
1555    if (mcverbose)
1556      printf("scan from %s has %d rows (scan steps) of %d columns (monitors) varying %s\n",
1557        Files_to_Merge[scan_index1].filename, scan_length1, mon_count,
1558        Files_to_Merge[scan_index1].mcinputtable[ipar_var].name);
1559
1560    /* single Scan_columns[] is an unsorted row
1561      and have same ipar name/value in same dir/row */
1562
1563    /* single Scans_to_merge[i] value is an unsorted column
1564      and have same name in different directories/columns
1565      but different ipar values */
1566
1567    /* allocate array: scan_length1(rows)*(mcnumipar+2*mon_count) */
1568    t_Table Scan;
1569    if (!Table_Init(&Scan,
1570      scan_length1,
1571      Files_to_Merge[scan_index1].mcnumipar+2*mon_count)) {
1572      fprintf(stderr, "Warning: %s: Can not allocate Scan %ix(%i+2*%i) multiarray_1d. Skipping.\n",
1573          Files_to_Merge[scan_index1].filename, scan_length1,
1574          Files_to_Merge[scan_index1].mcnumipar,
1575          mon_count);
1576      continue;
1577    }
1578    char *header=(char*)mem(64*CHAR_BUF_LENGTH); strcpy(header, "");
1579    char *youts =(char*)mem(64*CHAR_BUF_LENGTH); strcpy(youts,  "");
1580    double ipar_min=FLT_MAX, ipar_max=0;
1581
1582    /* we first sort Scan_columns(monitors) with distance */
1583    int Scan_distances[mon_count];  /* this is column index */
1584    j = 0;
1585
1586    for (scan_index2=0; scan_index2<nb; scan_index2++)
1587      if (Scan_columns[scan_index2]>=0) Scan_distances[j++] = Scan_columns[scan_index2];
1588#ifdef HAVE_QSORT
1589    qsort(Scan_distances, mon_count, sizeof(int), sort_distances);
1590#endif
1591    for (j=0; j<mon_count; j++) { /* loop for each column */
1592      int Monitor_column[scan_length1];
1593      int k=0;
1594      for (i=0; i<scan_length1; Monitor_column[i]=i) { i++; }
1595      for (scan_index2=0; scan_index2<nb; scan_index2++) {
1596        /* find Scan_distances[j] in Scans_to_merge */
1597        if (Scans_to_merge[scan_index2] >= 0 && Scans_to_merge[scan_index2] == Scan_distances[j]) {
1598          Monitor_column[k++] = scan_index2;
1599          Scans_to_merge[scan_index2]=-1; /*unactivate that scan element */
1600        }
1601      }
1602      /* sort each monitor column with ipar value */
1603#ifdef HAVE_QSORT
1604      qsort(Monitor_column, scan_length1, sizeof(int), sort_ipar_mon);
1605#endif
1606      /* extract sorted column and set Scan */
1607      for (i=0; i<scan_length1; i++) { /* loop on column elements(row) */
1608        Table_SetElement(&Scan,
1609          i, 
1610          Files_to_Merge[scan_index1].mcnumipar+2*j,
1611          Files_to_Merge[Monitor_column[i]].Psum);
1612        Table_SetElement(&Scan,
1613          i, Files_to_Merge[scan_index1].mcnumipar+2*j+1,
1614          mcestimate_error(
1615            Files_to_Merge[Monitor_column[i]].Ncount,
1616            Files_to_Merge[Monitor_column[i]].Psum,
1617            Files_to_Merge[Monitor_column[i]].P2sum));
1618        if (j==0) { /* first monitor in row also sets ipar */
1619          for (k=0; k<Files_to_Merge[Monitor_column[i]].mcnumipar; k++) {
1620            Table_SetElement(&Scan,
1621              i, k,
1622              atof(Files_to_Merge[Monitor_column[i]].mcinputtable[k].val));
1623            /* set name of ipar */
1624            if (i==0) {
1625              strcat(header, Files_to_Merge[Monitor_column[i]].mcinputtable[k].name);
1626              strcat(header, " ");
1627            }
1628          }
1629        } /* if j==0 */
1630        double this=atof(Files_to_Merge[Monitor_column[i]].mcinputtable[ipar_var].val);
1631        if (ipar_min > this) ipar_min=this;
1632        if (ipar_max < this) ipar_max=this;
1633      } /* for i */
1634      strcat(header, Files_to_Merge[Scan_distances[j]].outputname); strcat(header, "_I ");
1635      strcat(header, Files_to_Merge[Scan_distances[j]].outputname); strcat(header, "_Err ");
1636      strcat(youts, "("); strcat(youts, Files_to_Merge[Scan_distances[j]].outputname); strcat(youts, "_I,");
1637      strcat(youts, Files_to_Merge[Scan_distances[j]].outputname); strcat(youts, "_Err) ");
1638    } /* for j */
1639    Scan.header=header;
1640
1641    Scans_to_merge[scan_index1]=-1; /* unactivate that scan element */
1642
1643    char *title=str_cat("Scan of ",
1644      Files_to_Merge[scan_index1].mcinputtable[ipar_var].name, NULL);
1645    /* output scan multiarray */
1646    /* for PGPLOT: open mcstas.sim */
1647    if (strstr(mcformat.Name, "McStas")) mcsiminfo_init(NULL); /* open new SIM file in this dir for the first time */
1648    else mcsiminfo_name=NULL;
1649    char *datfile=NULL;
1650    if (mcsingle_file && mcsiminfo_name) datfile=str_dup(mcsiminfo_name);
1651    if (!datfile) datfile = str_cat("mcstas.", strstr(mcformat.Name, "McStas") ? "dat" : mcformat.Extension, NULL);
1652    strcat(mcformat.Name, " scan ");
1653    if (mcverbose)
1654      printf("Writing scan file=%s (%s) into directory %s: %s=%g:%g\n", 
1655        datfile, mcsiminfo_name, mcdirname,
1656        Files_to_Merge[scan_index1].mcinputtable[ipar_var].name, ipar_min, ipar_max);
1657    strcpy(mcinstrument_name,   Files_to_Merge[scan_index1].InstrName);
1658    strcpy(mcinstrument_source, Files_to_Merge[scan_index1].Source);
1659    if (!mctestmode)
1660    mcdetector_out_3D(title,
1661      Files_to_Merge[scan_index1].mcinputtable[ipar_var].name,
1662      Files_to_Merge[scan_index1].ylabel, "",
1663      Files_to_Merge[scan_index1].mcinputtable[ipar_var].name,
1664      youts,
1665      header,
1666      ipar_min, ipar_max, 0, 0, 0, 0,
1667      -scan_length1, Files_to_Merge[scan_index1].mcnumipar+2*mon_count,  1,
1668      NULL, Scan.data, NULL, datfile,
1669      Files_to_Merge[scan_index1].component, 
1670      Files_to_Merge[scan_index1].POSITION);
1671
1672    /* for PGPLOT: close mcstas.sim */
1673    if (strstr(mcformat.Name, "McStas")) mcsiminfo_close();
1674    Table_Free(&Scan);
1675    memfree(datfile);
1676    memfree(youts);
1677    memfree(title);
1678    /* go to end of scan and continue to search for scans */
1679  } /* for scan_index1 */
1680} /*  mcformat_scan_compare */
1681
1682/*******************************************************************************
1683* mcformat_merge_output: output non empty files
1684*                        special handling for multiarray/scans
1685*******************************************************************************/
1686int mcformat_merge_output(int nb)
1687{
1688  int i;
1689  char mctestmode_sav=mctestmode;
1690  if (mcscanmode == 2) mctestmode=1; /* scan only will skip writing for non scan files */
1691  /* output files for non empty elements */
1692  for (i=0; i<nb; i++) {
1693    if (mcformat_output(Files_to_Merge[i])) {
1694      if (mcverbose) {
1695        printf("mcformat: merging/scanning %s ", Files_to_Merge[i].outputname);
1696        printf("into %s%s ",
1697          Files_to_Merge[i].mcdirname ? Files_to_Merge[i].mcdirname : ".",
1698          Files_to_Merge[i].mcdirname ? MC_PATHSEP_S : "");
1699        if (mctestmode) printf(" (--test or --scan-only mode)\n"); else printf("\n");
1700      }
1701    }
1702  }
1703  mctestmode = mctestmode_sav;
1704
1705  if (mcscanmode) {
1706  /* build and output scans (if any) for non empty elements of same index */
1707  mcformat_scan_compare(nb);
1708  /* allocate nb_scan rows of nb_vars+(nb_monitors*3) columns */
1709  /* fill in scan variables extracted from mcinputtable */
1710  /* fill in monitor values */
1711  /* call outout routine for scans (can not be binary format): from mcrun.pl */
1712  }
1713
1714  /* free merged/scan elements */
1715  for (i=0; i<nb; i++) mcformat_free_mcstas_struct(Files_to_Merge[i]);
1716  return(nb);
1717}
1718
1719/*******************************************************************************
1720* mcformat_usage: print mcformat usage/help
1721*******************************************************************************/
1722void mcformat_usage(char *pgmname)
1723{
1724  int i;
1725
1726  fprintf(stderr, "mcformat version %s format conversion tool (" MCSTAS_VERSION ")\n", MCFORMAT);
1727  fprintf(stderr, "Usage: %s [options] file1|dir1 file2|dir2 ...\n", pgmname);
1728  fprintf(stderr,
1729"Convert/merge files and directories from McStas format to an other specified format\n"
1730"Options are:\n"
1731"  -d DIR    --dir=DIR        Put all data files in directory DIR.\n"
1732"  -f FILE   --file=FILE      Put all data in a single file.\n"
1733"  -a        --data-only      Do not put any headers in the data files.\n"
1734"  --no-output-files          Do not write any data files (test data).\n"
1735"  -h        --help           Show this help message.\n"
1736"  -p FORMAT --format=FORMAT  Output data files using format FORMAT\n"
1737"  -c        --force          Force writting in existing directories\n"
1738"  -t        --test           Test mode, does not write files\n"
1739"  -m        --merge          Add/Append equivalent data files and lists\n"
1740"            --merge-samedir  Merges inside same directories (dangerous)\n"
1741"  -s        --scan           Gather simulations per scan series\n"
1742"  -so       --scan-only      Create scan series but does not merge data\n"
1743"            --verbose        Verbose mode\n"
1744"\n"
1745"Examples:\n"
1746"mcformat -d target_dir original_dir\n"
1747"  # using default target format %s\n"
1748"mcformat -d target_dir original_dir --format=target_format\n"
1749"mcformat -d target_dir original_dir1 original_dir2 --merge\n"
1750"  # merge simulation data sets (grids)\n"
1751"mcformat -d target_dir dir1 dir2 ... --scan\n"
1752"  # merge scan data sets\n\n",
1753getenv("MCSTAS_FORMAT") ? getenv("MCSTAS_FORMAT") : MCSTAS_FORMAT);
1754
1755  fprintf(stderr, "Available output formats are (default is %s):\n  ", mcformat.Name);
1756  for (i=0; i < mcNUMFORMATS; fprintf(stderr,"\"%s\" " , mcformats[i++].Name) );
1757  fprintf(stderr, "\n  Format modifiers: FORMAT may be followed by 'binary float' or \n");
1758  fprintf(stderr, "  'binary double' to save data blocks as binary. This removes text headers.\n");
1759  fprintf(stderr, "  The MCSTAS_FORMAT environment variable may set the default FORMAT to use.\n");
1760} /* mcformat_usage */
1761
1762/*******************************************************************************
1763* mcformat_parseoptions: parse command line parameters
1764*******************************************************************************/
1765void
1766mcformat_parseoptions(int argc, char *argv[])
1767{
1768  int i;
1769  char cwd[CHAR_BUF_LENGTH];
1770  mcdirname = NULL;
1771  for(i = 1; i < argc; i++)
1772  {
1773    if(!strcmp("-d", argv[i]) && (i + 1) < argc)
1774      mcformat_usedir(argv[++i]);
1775    else if(!strncmp("-d", argv[i], 2))
1776      mcformat_usedir(&argv[i][2]);
1777    else if(!strcmp("--dir", argv[i]) && (i + 1) < argc)
1778      mcformat_usedir(argv[++i]);
1779    else if(!strncmp("--dir=", argv[i], 6))
1780      mcformat_usedir(&argv[i][6]);
1781    else if(!strcmp("-f", argv[i]) && (i + 1) < argc)
1782      mcuse_file(argv[++i]);
1783    else if(!strncmp("-f", argv[i], 2))
1784      mcuse_file(&argv[i][2]);
1785    else if(!strcmp("--file", argv[i]) && (i + 1) < argc)
1786      mcuse_file(argv[++i]);
1787    else if(!strncmp("--file=", argv[i], 7))
1788      mcuse_file(&argv[i][7]);
1789    else if(!strcmp("-h", argv[i]) || !strcmp("--help", argv[i]))
1790    {  mcformat_usage(argv[0]); exit(-1); }
1791    else if(!strcmp("-v", argv[i]) || !strcmp("--version", argv[i]))
1792    {  fprintf(stderr, "mcformat version %s format conversion tool (" MCSTAS_VERSION ")\n", MCFORMAT); exit(-1); }
1793    else if(!strcmp("-a", argv[i]))
1794      mcascii_only = 1;
1795    else if(!strcmp("+a", argv[i]))
1796      mcascii_only = 0;
1797    else if(!strcmp("-c", argv[i]))
1798      mcforcemode = 1;
1799    else if(!strcmp("--force", argv[i]))
1800      mcforcemode = 1;
1801    else if(!strcmp("--data-only", argv[i]))
1802      mcascii_only = 1;
1803    else if(!strncmp("--format=", argv[i], 9)) {
1804      mcascii_only = 0;
1805      mcformat=mcuse_format(&argv[i][9]);
1806    }
1807    else if(!strcmp("--format", argv[i]) && (i + 1) < argc) {
1808      mcascii_only = 0;
1809      mcformat=mcuse_format(argv[++i]);
1810    }
1811    else if(!strncmp("-p=", argv[i], 3)) {
1812      mcascii_only = 0;
1813      mcformat=mcuse_format(&argv[i][3]);
1814    }
1815    else if(!strcmp("-p", argv[i]) && (i + 1) < argc) {
1816      mcascii_only = 0;
1817      mcformat=mcuse_format(argv[++i]);
1818    }
1819    else if(!strncmp("--format_data=", argv[i], 14) || !strncmp("--format-data=", argv[i], 14)) {
1820      mcascii_only = 0;
1821      mcformat_data=mcuse_format(&argv[i][14]);
1822    }
1823    else if((!strcmp("--format_data", argv[i]) || !strcmp("--format-data", argv[i])) && (i + 1) < argc) {
1824      mcascii_only = 0;
1825      mcformat_data=mcuse_format(argv[++i]);
1826    }
1827    else if(!strcmp("--no-output-files", argv[i]))
1828      mcdisable_output_files = 1;
1829    else if(!strcmp("--verbose", argv[i]))
1830      mcverbose  = 1;
1831    else if(!strcmp("-t", argv[i]) || !strcmp("--test", argv[i]))
1832      mctestmode = 1;
1833    else if(!strcmp("-m", argv[i]) || !strcmp("--merge", argv[i]))
1834      mcmergemode= 1;
1835    else if(!strcmp("-s", argv[i]) || !strcmp("--scan", argv[i]))
1836      mcscanmode = 1;
1837    else if(!strcmp("-so", argv[i]) || !strcmp("--scan-only", argv[i]))
1838      mcscanmode = 2;
1839    else if(!strcmp("--merge-samedir", argv[i]))
1840      mcmergesamedir=mcmergemode=1;
1841    else {
1842      /* convert argv[i]: store index of argument */
1843      if (files_to_convert_NB <CHAR_BUF_LENGTH)
1844        files_to_convert_Array[files_to_convert_NB++] = i;
1845      else
1846        fprintf(stderr, "Warning: Exceeding maximum number of files to process (%d).\n"
1847          "Ignoring %s [mcformat:mcformat_parseoptions].\n",
1848          CHAR_BUF_LENGTH, argv[i]);
1849    }
1850  }
1851  if (!mcascii_only) {
1852    if (strstr(mcformat.Name,"binary"))
1853      fprintf(stderr, "Warning: %s files will contain text headers.\n"
1854                      "         Use -a option to clean up.\n", mcformat.Name);
1855    strcat(mcformat.Name, " with text headers");
1856  }
1857  if (!mcdirname) {
1858    getcwd(cwd, CHAR_BUF_LENGTH);
1859    mcdirname = str_dup(cwd); /* default is to export to PWD */
1860  }
1861} /* mcformat_parseoptions */
1862
1863/*******************************************************************************
1864* main: program entry point (start):calls parseoptions, convert and merge
1865*******************************************************************************/
1866int main(int argc, char *argv[])
1867{
1868  time_t t;
1869  int j;
1870
1871#ifdef MAC
1872  argc = ccommand(&argv);
1873#endif
1874
1875  t = (time_t)mcstartdate;
1876  time(&t);
1877  mcstartdate = t;
1878  mcformat=mcuse_format(getenv("MCSTAS_FORMAT") ? getenv("MCSTAS_FORMAT") : MCSTAS_FORMAT);
1879  /* default is to output as McStas format */
1880  mcformat_data.Name=NULL;
1881
1882  /* parse parameters from the command line and get files to convert */
1883  mcformat_parseoptions(argc, argv);
1884
1885  if (!files_to_convert_NB) {  mcformat_usage(argv[0]); exit(-1); }
1886  if (!mcformat_data.Name && !strcmp(mcformat.Name, "HTML"))
1887    mcformat_data = mcuse_format("VRML");
1888
1889  mcnbconvert = mcdircount = 0;
1890  mcoutputdir = mcdirname; /* base output dir */
1891
1892  if (mcscanmode && mcverbose && !strstr(mcformat.Name, "McStas"))
1893    printf("Warning: Scan gathering mode is only compatible when using --format=McStas\n");
1894
1895  /* count the number of files to store */
1896  for(j = 0; j < files_to_convert_NB; j++) {
1897    int    i;
1898    i = files_to_convert_Array[j]; /* does the job for each file/dir */
1899    mcnbconvert += mcformat_count(argv[i]);
1900  }
1901  if (mcdircount) { /* allocate list of directories amd FILE handles */
1902    mcdirnames  = (char**)mem(mcdircount*sizeof(char*));
1903    mcsimfiles  = (FILE**)mem(mcdircount*sizeof(FILE*));
1904    mcinstrnames= (char**)mem(mcdircount*sizeof(char*));
1905    mcsources   = (char**)mem(mcdircount*sizeof(char*));
1906  }
1907  if (mcmergemode || mcscanmode) {
1908    printf("mcformat: Will process and merge/scan %d data file%s in %d director%s.\n",
1909      mcnbconvert, mcnbconvert > 1 ? "s" : "", mcdircount, mcdircount > 1 ? "ies" : "y");
1910    /* allocate array of Original file structures */
1911    Files_to_Merge = mem(mcnbconvert*sizeof(struct McStas_file_format));
1912    Scans_to_merge = mem(mcnbconvert*sizeof(int));
1913    for (j=0; j<mcnbconvert; j++) {
1914      Files_to_Merge[j] = mcformat_init_mcstas_struct();
1915      Scans_to_merge[j] = -1;
1916    }
1917
1918  }
1919  mcnbconvert = mcdircount = 0;
1920
1921  strcpy(mcinstrument_source, "");
1922  strcpy(mcinstrument_name  , "");
1923
1924  /* calls the conversion routine. SIM file opened at first conversion in mcformat_convert */
1925  for(j = 0; j < files_to_convert_NB; j++) {
1926    int    i;
1927    i = files_to_convert_Array[j]; /* does the job for each file/dir */
1928    mcformat_convert(argv[i]);
1929  }
1930
1931  if (mcmergemode || mcscanmode) {
1932    /* call to merging routine (free some Files_to_Merge elements) */
1933    mcformat_merge_compare(mcnbconvert);
1934    /* iterative call to output routine for remaining elements of Files_to_Merge */
1935    mcformat_merge_output(mcnbconvert);
1936    if (Files_to_Merge) memfree(Files_to_Merge);
1937    if (Scans_to_merge) memfree(Scans_to_merge);
1938  }
1939
1940  /* clean up: close all SIM files */
1941  if (!mctestmode) {
1942    if (!mcdircount) mcsiminfo_close();
1943    else {
1944      for (j=0; j<mcdircount; j++) {
1945        if (mcsimfiles[j]) {
1946          mcdirname = mcdirnames[j];
1947          mcsiminfo_file     = mcsimfiles[j];
1948          strncpy(mcinstrument_source, str_last_word(mcinstrnames[j]), CHAR_BUF_LENGTH);
1949          strncpy(mcinstrument_name  , str_last_word(mcsources[j]), CHAR_BUF_LENGTH);
1950          mcsiminfo_close();
1951          mcsimfiles[j] = NULL;
1952          memfree(mcinstrnames[j]);
1953          memfree(mcsources[j]);
1954          memfree(mcdirnames[j]);
1955        }
1956      }
1957      memfree(mcdirnames);
1958      memfree(mcsimfiles);
1959      memfree(mcinstrnames);
1960      memfree(mcsources);
1961    }
1962  }
1963
1964  mcclear_format(mcformat);
1965  if (mcformat_data.Name) mcclear_format(mcformat_data);
1966
1967  return mcnbconvert; /* number of converted files */
1968
1969} /* main */
1970
1971
Note: See TracBrowser for help on using the browser.