FMS  v0.2
Field and Mesh Specification
fmsio.c
Go to the documentation of this file.
1 /*
2  Copyright (c) 2021, Lawrence Livermore National Security, LLC. Produced at
3  the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights
4  reserved. See files LICENSE and NOTICE for details.
5 
6  This file is part of CEED, a collection of benchmarks, miniapps, software
7  libraries and APIs for efficient high-order finite element and spectral
8  element discretizations for exascale applications. For more information and
9  source code availability see http://github.com/ceed.
10 
11  The CEED research is supported by the Exascale Computing Project (17-SC-20-SC)
12  a collaborative effort of two U.S. Department of Energy organizations (Office
13  of Science and the National Nuclear Security Administration) responsible for
14  the planning and preparation of a capable exascale ecosystem, including
15  software, applications, hardware, advanced system engineering and early
16  testbed platforms, in support of the nation's exascale computing imperative.
17 */
18 // We use strdup() - this is one way to get it:
19 #define _XOPEN_SOURCE 600
20 
21 #include <fmsio.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <limits.h>
26 #include <errno.h>
27 #include <ctype.h>
28 #include <inttypes.h>
29 
30 #ifdef FMS_HAVE_CONDUIT
31 #include <conduit.h>
32 #include <conduit_relay.h>
33 #endif
34 
35 
36 // #define FREE(PTR) free(PTR)
37 #define FREE(PTR) \
38 do { \
39  if(PTR) \
40  free(PTR); \
41 } while(0)
42 
43 // NOTE: If set to 1 the last line will still have 2 entries.
44 #define FMS_ELE_PER_LINE 3u
45 
46 // printf format string for FmsInt
47 #define FMS_LU "%" PRIu64
48 
49 // Routine used for converting a string to FmsInt
50 #if UINT64_MAX == ULLONG_MAX
51 #define StrToFmsInt strtoull
52 #elif UINT64_MAX == ULONG_MAX
53 #define StrToFmsInt strtoul
54 #else
55 #error "unknown conversion routine for FmsInt"
56 #endif
57 
58 #define FOR_EACH_INT_TYPE(macro) \
59  macro(FMS_INT8, int8_t, "%" PRId8) \
60  macro(FMS_INT16, int16_t, "%" PRId16) \
61  macro(FMS_INT32, int32_t, "%" PRId32) \
62  macro(FMS_INT64, int64_t, "%" PRId64) \
63  macro(FMS_UINT8, uint8_t, "%" PRIu8) \
64  macro(FMS_UINT16, uint16_t, "%" PRIu16) \
65  macro(FMS_UINT32, uint32_t, "%" PRIu32) \
66  macro(FMS_UINT64, uint64_t, "%" PRIu64)
67 
68 #define FOR_EACH_SCALAR_TYPE(macro) \
69  macro(FMS_FLOAT, float, "%f") \
70  macro(FMS_DOUBLE, double, "%f") \
71  macro(FMS_COMPLEX_FLOAT, float, "%f") \
72  macro(FMS_COMPLEX_DOUBLE, double, "%f")
73 
74 /**
75 @note borrowed from fms.c for a bit.
76 */
77 #ifdef NDEBUG
78 #define E_RETURN(code) return (code)
79 #else
80 static void FmsErrorDebug(int err_code, const char *func, const char *file,
81  int line) {
82  fprintf(stderr,
83  "\n\nFMS error encountered!\n"
84  "Error code: %d\n"
85  "Function: %s\n"
86  "File: %s:%d\n\n"
87  /*"Aborting ...\n\n"*/, err_code, func, file, line);
88  // abort();
89 }
90 // __PRETTY_FUNCTION__ is the same as the standard __func__ for most compilers,
91 // with the exception of clang. GCC 9.3.0 with -Wpedantic gives a warning about
92 // __PRETTY_FUNCTION__ not being standard, so we use __PRETTY_FUNCTION__ only
93 // with clang.
94 #if defined(__clang__)
95 #define FMS_PRETTY_FUNCTION __PRETTY_FUNCTION__
96 #elif !defined(_MSC_VER)
97 #define FMS_PRETTY_FUNCTION __func__
98 #else // for Visual Studio C++
99 #define FMS_PRETTY_FUNCTION __FUNCSIG__
100 #endif
101 #define E_RETURN(code) \
102  do { \
103  if (code) { \
104  FmsErrorDebug(code, FMS_PRETTY_FUNCTION, __FILE__, __LINE__); \
105  } \
106  return (code); \
107  } while (0)
108 #endif
109 
110 static inline int FmsIOCopyString(const char *str, char **str_copy_p) {
111  if (str == NULL) { *str_copy_p = NULL; return 0; }
112  char *str_copy = strdup(str);
113  if (str_copy == NULL) { return 1; }
114  *str_copy_p = str_copy;
115  return 0;
116 }
117 
118 // Make sure dst is large enough to hold N + 1 chars. N should be strlen(str) to convert an entire string.
119 #ifdef FMS_HAVE_CONDUIT
120 static inline int FmsIOStringToLower(const char *src, const size_t N,
121  char *dst) {
122  if(!dst) return 1;
123  if(!src) dst[0] = '\0';
124  for(size_t i = 0; i < N; i++)
125  dst[i] = (char)tolower(src[i]);
126  dst[N] = '\0';
127  return 0;
128 }
129 #endif
130 
131 /**
132 Data structures.
133 */
134 typedef struct {
135 #ifdef FMS_HAVE_CONDUIT
136  /* Conduit C-API*/
137  conduit_node *root;
138 
139  char *filename;
140  char *protocol;
141  int writing;
142 #endif
143  FILE *fp;
144  FmsInt temp_strings_size;
145  FmsInt temp_strings_cap;
146  char **temp_strings;
147 } FmsIOContext;
148 
149 typedef struct {
150  /* Function pointers */
151  int (*open)(FmsIOContext *ctx, const char *filename, const char *mode);
152  int (*close)(FmsIOContext *ctx);
153 
154  int (*add_int)(FmsIOContext *ctx, const char *path, FmsInt value);
155  int (*add_int_array)(FmsIOContext *ctx, const char *path, const FmsInt *values,
156  FmsInt n);
157  int (*add_typed_int_array)(FmsIOContext *ctx, const char *path, FmsIntType type,
158  const void *values, FmsInt n);
159  int (*add_float)(FmsIOContext *ctx, const char *path, float value);
160 
161  int (*add_double)(FmsIOContext *ctx, const char *path, double value);
162  int (*add_scalar_array)(FmsIOContext *ctx, const char *path, FmsScalarType type,
163  const void *data, FmsInt n);
164  int (*add_string)(FmsIOContext *ctx, const char *path, const char *value);
165 
166  int (*has_path)(FmsIOContext *ctx, const char *path);
167  int (*get_int)(FmsIOContext *ctx, const char *path, FmsInt *value);
168  int (*get_typed_int_array)(FmsIOContext *ctx, const char *path,
169  FmsIntType *type, void **values, FmsInt *n);
170  int (*get_float)(FmsIOContext *ctx, const char *path, float *value);
171  int (*get_double)(FmsIOContext *ctx, const char *path, double *value);
172  int (*get_scalar_array)(FmsIOContext *ctx, const char *path,
173  FmsScalarType *type, void **values, FmsInt *n);
174  int (*get_string)(FmsIOContext *ctx, const char *path, const char **value);
175 } FmsIOFunctions;
176 
177 // Struct used for building metadata
178 typedef struct {
179  FmsMetaDataType mdtype;
180  union {
181  FmsIntType i_type;
182  FmsScalarType s_type;
183  } subtype;
184  const char *name;
185  FmsInt size;
186  void *data;
187 } FmsIOMetaDataInfo;
188 
189 // Struct used for building a FieldDescriptor on the read end
190 typedef struct {
191  const char *name;
192  const char *component_name;
194  FmsInt *fixed_order; // Type should be FmsInt & size should be 3
195  FmsInt num_dofs;
196 } FmsIOFieldDescriptorInfo;
197 
198 // Struct used for building a Field on the read end
199 typedef struct {
200  const char *name;
201  FmsLayoutType layout;
202  FmsInt num_vec_comps;
203  const char *fd_name;
204  FmsInt data_size;
205  FmsScalarType data_type;
206  void *data; // Currently - should free
207  FmsIOMetaDataInfo *md;
208 } FmsIOFieldInfo;
209 
210 // Struct used to define entities in a domain
211 typedef struct {
212  FmsEntityType ent_type;
213  FmsInt nents;
214  FmsInt size;
215  FmsIntType type;
216  void *values; // Currently - should free
217 } FmsIOEntityInfo;
218 
219 // Struct used to build a domain
220 typedef struct {
221  FmsInt dim; // Implies length of entities array
222  FmsInt nverts;
223  FmsIOEntityInfo *entities;
224 } FmsIODomainInfo;
225 
226 // Struct used for holding domain name info
227 typedef struct {
228  const char *name;
229  FmsInt ndomains;
230  FmsIODomainInfo *domains;
231 } FmsIODomainNameInfo;
232 
233 typedef struct {
234  const char *domain_name;
235  FmsInt domain_id;
236  FmsInt full_domain; // Boolean
237  FmsEntityType part_ent_type;
238  FmsIOEntityInfo entities[FMS_NUM_ENTITY_TYPES];
239 } FmsIOComponentPartInfo;
240 
241 // Struct used for building components
242 typedef struct {
243  const char *name;
244  FmsInt dim;
245  FmsInt nents;
246  const char *coordinates_name;
247  FmsInt nparts;
248  FmsIOComponentPartInfo *parts;
249  FmsInt relation_size;
250  FmsIntType relation_type;
251  FmsInt *relation_values;
252 } FmsIOComponentInfo;
253 
254 // Struct used for building tags
255 typedef struct {
256  const char *name;
257  const char *comp_name;
258  FmsIntType type;
259  void *values;
260  FmsInt size;
261  FmsInt descr_size;
262  FmsInt *tag_values; // For descriptions, TODO: Support unsigned
263  const char **descriptions;
264 } FmsIOTagInfo;
265 
266 // Struct used for building a Mesh
267 typedef struct {
268  FmsInt *partition_info; // Should be a size 2 FmsInt
269  FmsInt ndomain_names;
270  FmsInt ncomponents;
271  FmsInt ntags;
272  FmsIODomainNameInfo *domain_names;
273  FmsIOComponentInfo *components;
274  FmsIOTagInfo *tags;
275 
276 } FmsIOMeshInfo;
277 
278 // Struct used for building a datacollection
279 typedef struct {
280  const char *name;
281  FmsInt nfds;
282  FmsIOFieldDescriptorInfo *fds;
283  FmsInt nfields;
284  FmsIOFieldInfo *fields;
285  FmsIOMeshInfo *mesh_info;
286  FmsIOMetaDataInfo *md;
287 } FmsIODataCollectionInfo;
288 
289 static char *
290 join_keys(const char *k1, const char *k2) {
291  size_t len = 0;
292  char *str = NULL;
293 
294  len = strlen(k1) + 1/*slash*/ + strlen(k2) + 1;
295  str = (char *)malloc(sizeof(char) * len);
296  if(str)
297  sprintf(str, "%s/%s", k1, k2);
298  return str;
299 }
300 
301 /*****************************************************************************
302 *** FMS I/O Functions for ASCII
303 *****************************************************************************/
304 static int
305 FmsIOOpen(FmsIOContext *ctx, const char *filename, const char *mode) {
306  if(!ctx) E_RETURN(1);
307  if(!filename) E_RETURN(2);
308  if(!mode) E_RETURN(3);
309  ctx->fp = fopen(filename, mode);
310  if(!ctx->fp) E_RETURN(4);
311  return 0;
312 }
313 
314 static int
315 FmsIOClose(FmsIOContext *ctx) {
316  if(ctx == NULL) E_RETURN(1);
317  fclose(ctx->fp);
318  ctx->fp = NULL;
319  // Cleanup any temp strings we made
320  for(FmsInt i = 0; i < ctx->temp_strings_size; i++) {
321  FREE(ctx->temp_strings[i]);
322  }
323  FREE(ctx->temp_strings);
324 
325  return 0;
326 }
327 
328 /**
329 NOTE: These functions are where we can control what the ASCII file format looks like
330 */
331 static int
332 FmsIOAddInt(FmsIOContext *ctx, const char *path, FmsInt value) {
333  if(!ctx) E_RETURN(1);
334  if(!path) E_RETURN(2);
335  fprintf(ctx->fp, "%s: " FMS_LU "\n", path, value);
336  return 0;
337 }
338 
339 static int
340 FmsIOAddIntArray(FmsIOContext *ctx, const char *path, const FmsInt *values,
341  FmsInt n) {
342  FmsInt i, j;
343  if(!ctx) E_RETURN(1);
344  if(!path) E_RETURN(2);
345  fprintf(ctx->fp, "%s/Size: " FMS_LU "\n", path, n);
346  fprintf(ctx->fp, "%s/Type: %s\n", path, FmsIntTypeNames[FMS_UINT64]);
347 
348  if(n) {
349  /* Should we make it YAML-like?*/
350  fprintf(ctx->fp, "%s/Values: [", path);
351  for(i = 0; i < n; ++i) {
352  for(j = 0; j < FMS_ELE_PER_LINE && i < n; j++, i++) {
353  fprintf(ctx->fp, FMS_LU, values[i]);
354  if(i < n-1)
355  fprintf(ctx->fp, ", ");
356  }
357  if(i < n-1)
358  fprintf(ctx->fp, "\n");
359  }
360  fprintf(ctx->fp, "]\n");
361  }
362  return 0;
363 }
364 
365 
366 /**
367 NOTE: This function is needed since for metadata we're given void* data with an enum that describes the type.
368  In our ascii format, do we want to consider adding the types to make it unambiguous when we read back?
369 
370  If we added the type as a comment at the end, it would still be valid YAML.
371 
372  key1: value # string
373  key2/path/to/something: "blah" # string
374  key2/path/to/other: 1.2345 # float
375  key2/path/to/other2: [0,1,2,3,4,5,6] # int
376 */
377 static int
378 FmsIOAddTypedIntArray(FmsIOContext *ctx, const char *path, FmsIntType type,
379  const void *values, FmsInt n) {
380  /* Shall we stick some type information into the ASCII to preserve the intended IntType? */
381  size_t i, j;
382  int retval = 0;
383  const unsigned int epl = FMS_ELE_PER_LINE;
384 
385  fprintf(ctx->fp, "%s/Size: " FMS_LU "\n", path, n);
386  fprintf(ctx->fp, "%s/Type: %s\n", path, FmsIntTypeNames[type]);
387 
388 #define PRINT_MACRO(typename, T, format) \
389  do { \
390  const T *v = (const T *)(values); \
391  fprintf(ctx->fp, "%s/Values: [", path); \
392  for(i = 0; i < n;) { \
393  for(j = 0; j < epl && i < n; j++, i++) { \
394  fprintf(ctx->fp, format, v[i]); \
395  if(i < n-1) \
396  fprintf(ctx->fp, ", "); \
397  } \
398  if(i < n-1) \
399  fprintf(ctx->fp, "\n"); \
400  } \
401  fprintf(ctx->fp, "]\n"); \
402  } while(0)
403 
404  switch(type) {
405 #define CASES(typename, T, format) \
406  case typename: \
407  PRINT_MACRO(typename, T, format); \
408  break;
410 #undef CASES
411  default:
412  E_RETURN(1);
413  break;
414  }
415 #undef PRINT_MACRO
416  return retval;
417 }
418 
419 static int
420 FmsIOAddFloat(FmsIOContext *ctx, const char *path, float value) {
421  if(!ctx) E_RETURN(1);
422  if(!path) E_RETURN(2);
423  fprintf(ctx->fp, "%s: %f\n", path, value);
424  return 0;
425 }
426 
427 static int
428 FmsIOAddDouble(FmsIOContext *ctx, const char *path, double value) {
429  if(!ctx) E_RETURN(1);
430  if(!path) E_RETURN(2);
431  fprintf(ctx->fp, "%s: %f\n", path, value);
432  return 0;
433 }
434 
435 static int
436 FmsIOAddScalarArray(FmsIOContext *ctx, const char *path, FmsScalarType type,
437  const void *values, FmsInt n) {
438  /* Shall we stick some type information into the ASCII to preserve the intended IntType? */
439  size_t i, j;
440  int retval = 0;
441  const unsigned int epl = FMS_ELE_PER_LINE;
442 
443  if(type == FMS_COMPLEX_FLOAT || type == FMS_COMPLEX_FLOAT)
444  n = n * 2;
445 
446  fprintf(ctx->fp, "%s/Size: " FMS_LU "\n", path, n);
447  fprintf(ctx->fp, "%s/Type: %s\n", path, FmsScalarTypeNames[type]);
448 
449 #define PRINT_MACRO(typename, T, format) \
450  do { \
451  const T *v = (const T *)(values); \
452  fprintf(ctx->fp, "%s/Values: [", path); \
453  for(i = 0; i < n;) { \
454  for(j = 0; j < epl && i < n; j++, i++) { \
455  fprintf(ctx->fp, format, v[i]); \
456  if(i < n-1) \
457  fprintf(ctx->fp, ", "); \
458  } \
459  if(i < n-1) \
460  fprintf(ctx->fp, "\n"); \
461  } \
462  fprintf(ctx->fp, "]\n"); \
463  } while(0)
464 
465  switch(type) {
466 #define CASES(typename, T, format) \
467  case typename: \
468  PRINT_MACRO(typename, T, format); \
469  break;
471 #undef CASES
472  default:
473  E_RETURN(1);
474  break;
475  }
476 #undef PRINT_MACRO
477  return retval;
478 }
479 
480 static int
481 FmsIOAddString(FmsIOContext *ctx, const char *path, const char *value) {
482  if(!ctx) E_RETURN(1);
483  if(!path) E_RETURN(2);
484  fprintf(ctx->fp, "%s: %s\n", path, value);
485  return 0;
486 }
487 
488 #define FMS_BUFFER_SIZE 512
489 
490 /* Get functions. Assume that the file pointer is at the right place.
491  Q: Do we really need to null check the parameters at this level? */
492 
493 // Buff should be of size FMS_BUFFER_SIZE unless you are sure of the string size
494 static int
495 FmsIOReadLine(FmsIOContext *ctx, char *buff) {
496  FmsInt len = 0;
497  if(!ctx) E_RETURN(1);
498  if(!buff) E_RETURN(2);
499  if(fgets(buff, FMS_BUFFER_SIZE, ctx->fp) == NULL) {
500  E_RETURN(3);
501  }
502  // Remove the newline from the end of the string
503  len = strlen(buff);
504  buff[len-1] = '\0';
505  // buff[len] = '\0';
506  return 0;
507 }
508 
509 static int
510 FmsIOReadKeyValue(FmsIOContext *ctx, char *key, char *value) {
511  char buff[FMS_BUFFER_SIZE * 2];
512  FmsInt N = 0;
513  char *key_end = NULL;
514  if(!ctx) E_RETURN(1);
515  if(fgets(buff, FMS_BUFFER_SIZE * 2, ctx->fp) == NULL)
516  return 2; // This could mean EoF which is not always an error.
517  if((key_end = strchr(buff, ':')) == NULL)
518  E_RETURN(3);
519 
520  if(key) {
521  N = key_end - buff;
522  if(N >= FMS_BUFFER_SIZE)
523  E_RETURN(4);
524  memcpy(key, buff, N);
525  key[N] = '\0';
526  }
527 
528  // After the ':' is a space then the value starts
529  if(value) {
530  N = strlen(key_end+2);
531  if(N >= FMS_BUFFER_SIZE)
532  E_RETURN(5);
533  // Remove the \n from the end
534  memcpy(value, key_end+2, N);
535  value[N-1] = '\0';
536  // value[N] = '\0';
537  }
538  return 0;
539 }
540 
541 static int
542 FmsIOHasPath(FmsIOContext *ctx, const char *path) {
543  int err = 0;
544  char k[FMS_BUFFER_SIZE];
545  if(!ctx) E_RETURN(1);
546  if(!path) E_RETURN(2);
547 
548  long cur_loc = ftell(ctx->fp);
549  if(cur_loc < 0)
550  E_RETURN(3);
551  err = FmsIOReadKeyValue(ctx, k, NULL);
552  fseek(ctx->fp, cur_loc, SEEK_SET);
553  // EoF, not an error in this context - just means return false.
554  if(err == 2)
555  return 0;
556  else if(err)
557  E_RETURN(4);
558 
559  // Need to find each / from the right and compare each time to match conduit functionality
560  int found = 0;
561  while(1) {
562  if(strcmp(k, path) == 0) {
563  found = 1;
564  break;
565  }
566  char *ptr = strrchr(k, '/');
567  if(ptr == NULL)
568  break;
569  *ptr = '\0';
570  }
571  return found;
572 
573 }
574 
575 static int
576 FmsIOGetInt(FmsIOContext *ctx, const char *path, FmsInt *value) {
577  char k[FMS_BUFFER_SIZE], v[FMS_BUFFER_SIZE];
578  if(!ctx) E_RETURN(1);
579  if(!path) E_RETURN(2);
580  if(!value) E_RETURN(3);
581 
582  // Error reading line
583  if(FmsIOReadKeyValue(ctx, k, v))
584  E_RETURN(4);
585 
586  // Path & key do not match
587  if(strcmp(k, path))
588  E_RETURN(5);
589 
590  *value = StrToFmsInt(v, NULL, 10);
591 
592  // Potential errors
593  if (errno == ERANGE) { E_RETURN(6); }
594  if (errno == EINVAL) { E_RETURN(7); }
595 
596  return 0;
597 }
598 
599 /// You are responsible for freeing values
600 static int
601 FmsIOGetTypedIntArray(FmsIOContext *ctx, const char *path, FmsIntType *type,
602  void **values, FmsInt *n) {
603  int err = 0;
604  char k[FMS_BUFFER_SIZE], v[FMS_BUFFER_SIZE];
605  if(!ctx) E_RETURN(1);
606  if(!path) E_RETURN(2);
607  if(!type) E_RETURN(3);
608  if(!values) E_RETURN(4);
609  if(!n) E_RETURN(5);
610 
611  /* Arrays are written like:
612  path/Size: n
613  path/Type: type
614  path/Values: [1,2,3,
615  4,5,6
616  7,8,9]
617  */
618 
619  {
620  // Error reading line
621  if(FmsIOReadKeyValue(ctx, k, v))
622  E_RETURN(6);
623 
624  char *ksize = join_keys(path, "Size");
625  err = strcmp(k, ksize);
626  FREE(ksize);
627  // Path & key didn't match
628  if(err)
629  E_RETURN(7);
630 
631  *n = StrToFmsInt(v, NULL, 10);
632 
633  if (errno == ERANGE) { E_RETURN(8); }
634  if (errno == EINVAL) { E_RETURN(9); }
635  }
636 
637  {
638  // Error reading line
639  if(FmsIOReadKeyValue(ctx, k, v))
640  E_RETURN(10);
641 
642  char *ktype= join_keys(path, "Type");
643  err = strcmp(k, ktype);
644  FREE(ktype);
645  // Path & key didn't match
646  if(err)
647  E_RETURN(11);
648 
649  if(FmsGetIntTypeFromName(v, type))
650  E_RETURN(12);
651  }
652 
653  // Values does not get written if Size == 0
654  if(*n == 0)
655  return 0;
656 
657  if(FmsIOReadKeyValue(ctx, k, v))
658  E_RETURN(14);
659 
660  char *kvalues = join_keys(path, "Values");
661  err = strcmp(k, kvalues);
662  FREE(kvalues);
663  if(err)
664  E_RETURN(15);
665 
666 #define READ_ARRAY_DATA(DEST_T, FUNC) \
667 do { \
668  DEST_T *data = malloc(sizeof(DEST_T) * *n); \
669  FmsInt i = 0; \
670  while(1) { \
671  size_t len = strlen(v); \
672  char *off = v, *newoff = NULL; \
673  if(off[0] == '[') \
674  off++; \
675  while(len && i < *n) { \
676  data[i++] = (DEST_T)FUNC(off, &newoff, 10); \
677  newoff++; \
678  if(*newoff == ' ') newoff++; /* Current flaw in the file format, last element has no trialing space */ \
679  if(newoff >= v + len) break; \
680  off = newoff; \
681  } \
682  if(strchr(v, ']')) break; \
683  if(FmsIOReadLine(ctx, v)) break; \
684  } \
685  *values = (void*)data; \
686 } while(0)
687 
688  switch(*type) {
689  case FMS_INT8:
690  READ_ARRAY_DATA(int8_t, strtoimax);
691  break;
692  case FMS_INT16:
693  READ_ARRAY_DATA(int16_t, strtoimax);
694  break;
695  case FMS_INT32:
696  READ_ARRAY_DATA(int32_t, strtoimax);
697  break;
698  case FMS_INT64:
699  READ_ARRAY_DATA(int64_t, strtoimax);
700  break;
701  case FMS_UINT8:
702  READ_ARRAY_DATA(uint8_t, strtoumax);
703  break;
704  case FMS_UINT16:
705  READ_ARRAY_DATA(uint16_t, strtoumax);
706  break;
707  case FMS_UINT32:
708  READ_ARRAY_DATA(uint32_t, strtoumax);
709  break;
710  case FMS_UINT64:
711  READ_ARRAY_DATA(uint64_t, strtoumax);
712  break;
713  default:
714  E_RETURN(16);
715  break;
716  }
717 #undef READ_ARRAY_DATA
718 
719  return 0;
720 }
721 
722 /// You are responsible for freeing values
723 static int
724 FmsIOGetScalarArray(FmsIOContext *ctx, const char *path, FmsScalarType *type,
725  void **values, FmsInt *n) {
726  int err = 0;
727  char k[FMS_BUFFER_SIZE], v[FMS_BUFFER_SIZE];
728  if(!ctx) E_RETURN(1);
729  if(!path) E_RETURN(2);
730  if(!type) E_RETURN(3);
731  if(!values) E_RETURN(4);
732  if(!n) E_RETURN(5);
733 
734  /* Arrays are written like:
735  path/Size: n
736  path/Type: type
737  path/Values: [1,2,3,
738  4,5,6
739  7,8,9]
740  */
741 
742  {
743  // Error reading line
744  if(FmsIOReadKeyValue(ctx, k, v))
745  E_RETURN(6);
746 
747  char *ksize = join_keys(path, "Size");
748  err = strcmp(k, ksize);
749  FREE(ksize);
750  // Path & key didn't match
751  if(err)
752  E_RETURN(7);
753 
754  *n = StrToFmsInt(v, NULL, 10);
755 
756  if (errno == ERANGE) { E_RETURN(8); }
757  if (errno == EINVAL) { E_RETURN(9); }
758  }
759 
760  {
761  // Error reading line
762  if(FmsIOReadKeyValue(ctx, k, v))
763  E_RETURN(10);
764 
765  char *ktype= join_keys(path, "Type");
766  err = strcmp(k, ktype);
767  FREE(ktype);
768  // Path & key didn't match
769  if(err)
770  E_RETURN(11);
771 
772  if(FmsGetScalarTypeFromName(v, type))
773  E_RETURN(12);
774  }
775 
776  // Values does not get written if Size == 0
777  if(*n == 0)
778  return 0;
779 
780  if(FmsIOReadKeyValue(ctx, k, v))
781  E_RETURN(14);
782 
783  char *kvalues = join_keys(path, "Values");
784  err = strcmp(k, kvalues);
785  FREE(kvalues);
786  if(err)
787  E_RETURN(15);
788 
789 // Had to remake this for scalar because strto(f/d) doesn't take a base
790 #define READ_ARRAY_DATA(DEST_T, FUNC, SIZE) \
791 do { \
792  DEST_T *data = malloc(sizeof(DEST_T) * SIZE); \
793  FmsInt i = 0; \
794  while(1) { \
795  size_t len = strlen(v); \
796  char *off = v, *newoff = NULL; \
797  if(off[0] == '[') \
798  off++; \
799  while(len && i < SIZE) { \
800  data[i++] = (DEST_T)FUNC(off, &newoff); \
801  newoff++; \
802  if(*newoff == ' ') newoff++; /* Current flaw in the file format, last element has no trialing space */ \
803  if(newoff >= v + len) break; \
804  off = newoff; \
805  } \
806  if(strchr(v, ']')) break; \
807  if(FmsIOReadLine(ctx, v)) break; \
808  } \
809  *values = (void*)data; \
810 } while(0)
811 
812  switch(*type) {
813  case FMS_FLOAT:
814  READ_ARRAY_DATA(float, strtof, *n);
815  break;
816  case FMS_DOUBLE:
817  READ_ARRAY_DATA(double, strtod, *n);
818  break;
819  case FMS_COMPLEX_FLOAT:
820  READ_ARRAY_DATA(float, strtof, (*n)*2);
821  break;
822  case FMS_COMPLEX_DOUBLE:
823  READ_ARRAY_DATA(double, strtod, (*n)*2);
824  break;
825  default:
826  E_RETURN(16);
827  break;
828  }
829 #undef READ_ARRAY_DATA
830 
831  return 0;
832 }
833 
834 static int
835 FmsIOGetString(FmsIOContext *ctx, const char *path, const char **value) {
836  char k[FMS_BUFFER_SIZE], v[FMS_BUFFER_SIZE];
837  if(!ctx) E_RETURN(1);
838  if(!path) E_RETURN(2);
839  if(!value) E_RETURN(3);
840 
841  // Error reading line
842  if(FmsIOReadKeyValue(ctx, k, v))
843  E_RETURN(4);
844 
845  // Path & key do not match
846  if(strcmp(k, path))
847  E_RETURN(5);
848 
849  // TODO: Store char pointers in ctx? Need to keep them somewhere for free() later
850  FmsInt len = strlen(v);
851  FmsInt idx = ctx->temp_strings_size++;
852  if(ctx->temp_strings_size >= ctx->temp_strings_cap) {
853  ctx->temp_strings_cap *= 2;
854  ctx->temp_strings = realloc(ctx->temp_strings,
855  sizeof(char*) * ctx->temp_strings_cap);
856  }
857  ctx->temp_strings[idx] = malloc(sizeof(char) * len+1);
858  memcpy(ctx->temp_strings[idx], v, len);
859  ctx->temp_strings[idx][len] = '\0';
860  *value = (const char *)ctx->temp_strings[idx];
861  return 0;
862 }
863 
864 // This function is not used, for now.
865 #if 0
866 static int
867 FmsIOGetStringArray(FmsIOContext *ctx, const char *path, const char ***values,
868  FmsInt *n) {
869  E_RETURN(1); // TODO: Implement
870 }
871 #endif
872 
873 /**
874 @brief This function initializes the IO context .
875 @param ctx The I/O context.
876 */
877 static void
878 FmsIOContextInitialize(FmsIOContext *ctx) {
879  ctx->fp = NULL;
880  ctx->temp_strings_size = 0;
881  ctx->temp_strings_cap = 64;
882  ctx->temp_strings = calloc(sizeof(char*), ctx->temp_strings_cap);
883 }
884 
885 /**
886 @brief This function initializes the functions object with function pointers that
887  perform ASCII I/O.
888 @param ctx The functions object.
889 */
890 static void
891 FmsIOFunctionsInitialize(FmsIOFunctions *obj) {
892  if(obj) {
893  obj->open = FmsIOOpen;
894  obj->close = FmsIOClose;
895  obj->add_int = FmsIOAddInt;
896  obj->add_int_array = FmsIOAddIntArray;
897  obj->add_typed_int_array = FmsIOAddTypedIntArray;
898  obj->add_float = FmsIOAddFloat;
899  obj->add_double = FmsIOAddDouble;
900  obj->add_scalar_array = FmsIOAddScalarArray;
901  obj->add_string = FmsIOAddString;
902  /*...*/
903  obj->has_path = FmsIOHasPath;
904  obj->get_int = FmsIOGetInt;
905  obj->get_typed_int_array = FmsIOGetTypedIntArray;
906  obj->get_scalar_array = FmsIOGetScalarArray;
907  obj->get_string = FmsIOGetString;
908  }
909 }
910 
911 /*****************************************************************************
912 *** FMS I/O Functions for Conduit
913 *****************************************************************************/
914 #ifdef FMS_HAVE_CONDUIT
915 static int
916 FmsIOOpenConduit(FmsIOContext *ctx, const char *filename, const char *mode) {
917  if(!ctx) E_RETURN(1);
918  if(!filename) E_RETURN(2);
919  if(!mode) E_RETURN(3);
920  ctx->filename = strdup(filename);
921  ctx->root = conduit_node_create();
922  ctx->writing = (strstr(mode, "w") != NULL) ? 1 : 0;
923 
924  if(!ctx->writing) {
925  /* If we're not writing then read it all upfront into ctx->root. */
926  conduit_relay_io_load(filename, ctx->protocol, NULL, ctx->root);
927  }
928 
929  return 0;
930 }
931 
932 static int
933 FmsIOCloseConduit(FmsIOContext *ctx) {
934  if(!ctx) E_RETURN(1);
935 
936  if(ctx->writing) {
937  /* For conduit, we have not written anything yet. Do it all now. */
938  conduit_relay_io_save(ctx->root, ctx->filename, ctx->protocol, NULL);
939  }
940 
941  free(ctx->filename);
942  ctx->filename = NULL;
943  free(ctx->protocol);
944  ctx->protocol = NULL;
945  conduit_node_destroy(ctx->root);
946  ctx->root = NULL;
947  return 0;
948 }
949 
950 static int
951 FmsIOHasPathConduit(FmsIOContext *ctx, const char *path) {
952  if(!ctx) E_RETURN(0);
953  if(!path) E_RETURN(0);
954  return conduit_node_has_path(ctx->root, path);
955 }
956 
957 static int
958 FmsIOAddIntConduit(FmsIOContext *ctx, const char *path, FmsInt value) {
959  if(!ctx) E_RETURN(1);
960  if(!path) E_RETURN(2);
961  /*conduit_node_set_path_int(ctx->root, path, value);*/
962  conduit_node_set_path_uint64(ctx->root, path, value);
963  return 0;
964 }
965 
966 static int
967 FmsIOAddIntArrayConduit(FmsIOContext *ctx, const char *path,
968  const FmsInt *values, FmsInt n) {
969  if(!ctx) E_RETURN(1);
970  if(!path) E_RETURN(2);
971 
972  char *ksize = join_keys(path, "Size");
973  conduit_node_set_path_uint64(ctx->root, ksize, n);
974  FREE(ksize);
975 
976  char *ktype = join_keys(path, "Type");
977  conduit_node_set_path_char8_str(ctx->root, ktype, FmsIntTypeNames[FMS_UINT64]);
978  FREE(ktype);
979 
980  if(!values || n == 0)
981  return 0;
982 
983  char *kvalues = join_keys(path, "Values");
984  conduit_node_set_path_uint64_ptr(ctx->root, kvalues, (FmsInt *)values, n);
985  FREE(kvalues);
986  return 0;
987 }
988 
989 static int
990 FmsIOAddTypedIntArrayConduit(FmsIOContext *ctx, const char *path,
991  FmsIntType type, const void *values, FmsInt n) {
992  int retval = 0;
993  if(!ctx) E_RETURN(1);
994  if(!path) E_RETURN(2);
995 
996  char *ksize = join_keys(path, "Size");
997  conduit_node_set_path_uint64(ctx->root, ksize, n);
998  FREE(ksize);
999 
1000  char *ktype = join_keys(path, "Type");
1001  conduit_node_set_path_char8_str(ctx->root, ktype, FmsIntTypeNames[type]);
1002  FREE(ktype);
1003 
1004  if(!values || n == 0)
1005  return 0;
1006 
1007  char *kvalues = join_keys(path, "Values");
1008  switch(type) {
1009  case FMS_INT8:
1010  conduit_node_set_path_int8_ptr(ctx->root, kvalues, (conduit_int8 *)values, n);
1011  break;
1012  case FMS_INT16:
1013  conduit_node_set_path_int16_ptr(ctx->root, kvalues, (conduit_int16 *)values, n);
1014  break;
1015  case FMS_INT32:
1016  conduit_node_set_path_int32_ptr(ctx->root, kvalues, (conduit_int32 *)values, n);
1017  break;
1018  case FMS_INT64:
1019  conduit_node_set_path_int64_ptr(ctx->root, kvalues, (conduit_int64 *)values, n);
1020  break;
1021  case FMS_UINT8:
1022  conduit_node_set_path_uint8_ptr(ctx->root, kvalues, (conduit_uint8 *)values, n);
1023  break;
1024  case FMS_UINT16:
1025  conduit_node_set_path_uint16_ptr(ctx->root, kvalues, (conduit_uint16 *)values,
1026  n);
1027  break;
1028  case FMS_UINT32:
1029  conduit_node_set_path_uint32_ptr(ctx->root, kvalues, (conduit_uint32 *)values,
1030  n);
1031  break;
1032  case FMS_UINT64:
1033  conduit_node_set_path_uint64_ptr(ctx->root, kvalues, (conduit_uint64 *)values,
1034  n);
1035  break;
1036  default:
1037  FREE(kvalues);
1038  E_RETURN(1);
1039  break;
1040  }
1041  FREE(kvalues);
1042  return retval;
1043 }
1044 
1045 static int
1046 FmsIOAddFloatConduit(FmsIOContext *ctx, const char *path, float value) {
1047  if(!ctx) E_RETURN(1);
1048  if(!path) E_RETURN(2);
1049  conduit_node_set_path_float(ctx->root, path, value);
1050  return 0;
1051 }
1052 
1053 static int
1054 FmsIOAddDoubleConduit(FmsIOContext *ctx, const char *path, double value) {
1055  if(!ctx) E_RETURN(1);
1056  if(!path) E_RETURN(2);
1057  conduit_node_set_path_double(ctx->root, path, value);
1058  return 0;
1059 }
1060 
1061 static int
1062 FmsIOAddScalarArrayConduit(FmsIOContext *ctx, const char *path,
1063  FmsScalarType type, const void *data, FmsInt size) {
1064  if(!ctx) E_RETURN(1);
1065  if(!path) E_RETURN(2);
1066 
1067  char *ksize = join_keys(path, "Size");
1068  conduit_node_set_path_uint64(ctx->root, ksize, size);
1069  FREE(ksize);
1070 
1071  char *ktype = join_keys(path, "Type");
1072  conduit_node_set_path_char8_str(ctx->root, ktype, FmsScalarTypeNames[type]);
1073  FREE(ktype);
1074 
1075  if(!data || size == 0)
1076  return 0;
1077 
1078  char *kvalues = join_keys(path, "Values");
1079  switch (type) {
1080  case FMS_FLOAT:
1081  conduit_node_set_path_float32_ptr(ctx->root, kvalues, (conduit_float32 *)data,
1082  size);
1083  break;
1084  case FMS_DOUBLE:
1085  conduit_node_set_path_float64_ptr(ctx->root, kvalues, (conduit_float64 *)data,
1086  size);
1087  break;
1088  case FMS_COMPLEX_FLOAT:
1089  conduit_node_set_path_float32_ptr(ctx->root, kvalues, (conduit_float32 *)data,
1090  size*2);
1091  break;
1092  case FMS_COMPLEX_DOUBLE:
1093  conduit_node_set_path_float64_ptr(ctx->root, kvalues, (conduit_float64 *)data,
1094  size*2);
1095  break;
1096  default:
1097  FREE(kvalues);
1098  E_RETURN(1);
1099  break;
1100  }
1101  FREE(kvalues);
1102  return 0;
1103 }
1104 
1105 static int
1106 FmsIOAddStringConduit(FmsIOContext *ctx, const char *path, const char *value) {
1107  if(!ctx) E_RETURN(1);
1108  if(!path) E_RETURN(2);
1109  conduit_node_set_path_char8_str(ctx->root, path, value);
1110  /* NOT IMPLEMENTED IN CONDUIT conduit_node_set_path_external_char8_str(ctx->root, path, (char *)value);*/
1111  return 0;
1112 }
1113 
1114 /**
1115 Conduit has various back-ends that write/read data. Not all of these can preserve
1116 the exact type information that was used to write the data when it is read back in.
1117 Some of them preserve it all though. To be more forgiving here, allow some fuzz
1118 in the types. We call this rather than functions that expect a specific Conduit
1119 int type so we do not run into errors.
1120 */
1121 static int
1122 FmsIOConduitNode2FmsInt(conduit_node *node, FmsInt *value) {
1123  if(!node) E_RETURN(1);
1124  const conduit_datatype *dt = conduit_node_dtype(node);
1125  if(dt) {
1126  if(conduit_datatype_is_number(dt)) {
1127  if(conduit_datatype_is_char(dt))
1128  *value = (FmsInt)conduit_node_as_char(node);
1129  else if(conduit_datatype_is_short(dt))
1130  *value = (FmsInt)conduit_node_as_short(node);
1131  else if(conduit_datatype_is_int(dt))
1132  *value = (FmsInt)conduit_node_as_int(node);
1133  else if(conduit_datatype_is_long(dt))
1134  *value = (FmsInt)conduit_node_as_long(node);
1135 
1136  else if(conduit_datatype_is_unsigned_char(dt))
1137  *value = (FmsInt)conduit_node_as_unsigned_char(node);
1138  else if(conduit_datatype_is_unsigned_short(dt))
1139  *value = (FmsInt)conduit_node_as_unsigned_short(node);
1140  else if(conduit_datatype_is_unsigned_int(dt))
1141  *value = (FmsInt)conduit_node_as_unsigned_int(node);
1142  else if(conduit_datatype_is_unsigned_long(dt))
1143  *value = (FmsInt)conduit_node_as_unsigned_long(node);
1144 
1145  else if(conduit_datatype_is_int8(dt))
1146  *value = (FmsInt)conduit_node_as_int8(node);
1147  else if(conduit_datatype_is_int16(dt))
1148  *value = (FmsInt)conduit_node_as_int16(node);
1149  else if(conduit_datatype_is_int32(dt))
1150  *value = (FmsInt)conduit_node_as_int32(node);
1151  else if(conduit_datatype_is_int64(dt))
1152  *value = (FmsInt)conduit_node_as_int64(node);
1153 
1154  else if(conduit_datatype_is_uint8(dt))
1155  *value = (FmsInt)conduit_node_as_uint8(node);
1156  else if(conduit_datatype_is_uint16(dt))
1157  *value = (FmsInt)conduit_node_as_uint16(node);
1158  else if(conduit_datatype_is_uint32(dt))
1159  *value = (FmsInt)conduit_node_as_uint32(node);
1160  else if(conduit_datatype_is_uint64(dt))
1161  *value = (FmsInt)conduit_node_as_uint64(node);
1162 
1163  /* It should not be these types. */
1164  else if(conduit_datatype_is_float(dt))
1165  *value = (FmsInt)conduit_node_as_float(node);
1166  else if(conduit_datatype_is_double(dt))
1167  *value = (FmsInt)conduit_node_as_double(node);
1168  else if(conduit_datatype_is_float32(dt))
1169  *value = (FmsInt)conduit_node_as_float32(node);
1170  else if(conduit_datatype_is_float64(dt))
1171  *value = (FmsInt)conduit_node_as_float64(node);
1172 
1173  else if(conduit_datatype_is_empty(dt)) {
1174  E_RETURN(2);
1175  } else if(conduit_datatype_is_object(dt)) {
1176  E_RETURN(3);
1177  } else if(conduit_datatype_is_list(dt)) {
1178  E_RETURN(4);
1179  } else {
1180  E_RETURN(5);
1181  }
1182  } else {
1183  E_RETURN(6);
1184  }
1185  } else {
1186  E_RETURN(7);
1187  }
1188  return 0;
1189 }
1190 
1191 static int
1192 FmsIOGetIntConduit(FmsIOContext *ctx, const char *path, FmsInt *value) {
1193  conduit_node *node = NULL;
1194  int retval = 1;
1195  if(!ctx) E_RETURN(1);
1196  if(!path) E_RETURN(2);
1197  if(!value) E_RETURN(3);
1198  if(!conduit_node_has_path(ctx->root, path))
1199  E_RETURN(4);
1200 
1201  if((node = conduit_node_fetch(ctx->root, path)) != NULL) {
1202  retval = FmsIOConduitNode2FmsInt(node, value);
1203  }
1204  return retval;
1205 }
1206 
1207 /*int (*get_typed_int_array)(FmsIOContext *ctx, const char *path, FmsIntType *type, void **values, FmsInt *n);*/
1208 static int
1209 FmsIOGetTypedIntArrayConduit(FmsIOContext *ctx, const char *path,
1210  FmsIntType *type, void **values, FmsInt *n) {
1211  const conduit_datatype *dt = NULL;
1212  conduit_node *node = NULL, *size_node = NULL, *vnode = NULL;
1213  char *type_str = NULL;
1214  void *conduit_data_ptr = NULL;
1215  if(!ctx) E_RETURN(1);
1216  if(!path) E_RETURN(2);
1217  if(!type) E_RETURN(3);
1218  if(!values) E_RETURN(4);
1219  if(!n) E_RETURN(5);
1220 
1221  if(!conduit_node_has_path(ctx->root, path))
1222  E_RETURN(6);
1223 
1224  if((node = conduit_node_fetch(ctx->root, path)) == NULL)
1225  E_RETURN(7);
1226 
1227  /* Arrays are written with subnodes Size, Type, and Values */
1228  if((size_node = conduit_node_fetch(node, "Size")) == NULL)
1229  E_RETURN(8);
1230  if(FmsIOConduitNode2FmsInt(size_node, n) != 0)
1231  E_RETURN(9);
1232 
1233  if(!conduit_node_has_child(node, "Type"))
1234  E_RETURN(10);
1235 
1236  if((type_str = conduit_node_fetch_path_as_char8_str(node, "Type")) == NULL)
1237  E_RETURN(11);
1238 
1239  if(FmsGetIntTypeFromName(type_str, type))
1240  E_RETURN(12);
1241 
1242  if(*n == 0) {
1243  *values = NULL;
1244  return 0;
1245  }
1246 
1247  if(!conduit_node_has_child(node, "Values"))
1248  E_RETURN(13);
1249 
1250  if((vnode = conduit_node_fetch(node, "Values")) == NULL)
1251  E_RETURN(14);
1252 
1253  dt = conduit_node_dtype(vnode);
1254  conduit_data_ptr = conduit_node_element_ptr(vnode, 0);
1255 
1256 #define CASES(typename, T, format) \
1257  case typename: { \
1258  CT *src = (CT*)conduit_data_ptr; \
1259  T *dest = (T*)malloc(sizeof(T) * *n); \
1260  for(FmsInt i = 0; i < *n; i++) { \
1261  dest[i] = (T)src[i]; \
1262  } \
1263  *values = (void*)dest; \
1264  break; \
1265  }
1266 
1267 #define COPY_AND_CAST \
1268  do { \
1269  switch(*type) { \
1270  FOR_EACH_INT_TYPE(CASES) \
1271  default: \
1272  E_RETURN(15); \
1273  break; \
1274  } \
1275  } while(0)
1276 
1277 
1278  if(conduit_datatype_is_int8(dt)) {
1279  typedef int8_t CT;
1280  COPY_AND_CAST;
1281  } else if(conduit_datatype_is_int16(dt)) {
1282  typedef int16_t CT;
1283  COPY_AND_CAST;
1284  } else if(conduit_datatype_is_int32(dt)) {
1285  typedef int32_t CT;
1286  COPY_AND_CAST;
1287  } else if(conduit_datatype_is_int64(dt)) {
1288  typedef int64_t CT;
1289  COPY_AND_CAST;
1290  } else if(conduit_datatype_is_uint8(dt)) {
1291  typedef uint8_t CT;
1292  COPY_AND_CAST;
1293  } else if(conduit_datatype_is_uint16(dt)) {
1294  typedef uint16_t CT;
1295  COPY_AND_CAST;
1296  } else if(conduit_datatype_is_uint32(dt)) {
1297  typedef uint32_t CT;
1298  COPY_AND_CAST;
1299  } else if(conduit_datatype_is_uint64(dt)) {
1300  typedef uint64_t CT;
1301  COPY_AND_CAST;
1302  } else {
1303  E_RETURN(16);
1304  }
1305 #undef COPY_AND_CAST
1306 #undef CASES
1307  return 0;
1308 }
1309 
1310 /* int (*get_scalar_array)(FmsIOContext *ctx, const char *path, FmsScalarType *type, void **values, FmsInt *n); */
1311 static int
1312 FmsIOGetScalarArrayConduit(FmsIOContext *ctx, const char *path,
1313  FmsScalarType *type, void **values, FmsInt *n) {
1314  conduit_node *node = NULL, *values_node = NULL, *size_node = NULL;
1315  char *type_str = NULL;
1316  void *conduit_data_ptr = NULL;
1317  const conduit_datatype *dt = NULL;
1318 
1319  if(!ctx) E_RETURN(1);
1320  if(!path) E_RETURN(2);
1321  if(!type) E_RETURN(3);
1322  if(!values) E_RETURN(4);
1323  if(!n) E_RETURN(5);
1324 
1325  /* Arrays are written with subnodes Size, Type, and Values */
1326  if((node = conduit_node_fetch(ctx->root, path)) == NULL)
1327  E_RETURN(6);
1328 
1329  if((type_str = conduit_node_fetch_path_as_char8_str(node, "Type")) == NULL)
1330  E_RETURN(7);
1331 
1332  if(FmsGetScalarTypeFromName(type_str, type))
1333  E_RETURN(8);
1334 
1335  /* Thought: Arrays in Conduit know their size already. Is this needed? */
1336  if((size_node = conduit_node_fetch(node, "Size")) == NULL)
1337  E_RETURN(9);
1338  if(FmsIOConduitNode2FmsInt(size_node, n))
1339  E_RETURN(10);
1340 
1341  if(*n == 0) {
1342  *values = NULL;
1343  return 0;
1344  }
1345 
1346  if(!conduit_node_has_child(node, "Values"))
1347  E_RETURN(11);
1348 
1349  values_node = conduit_node_fetch(node, "Values");
1350  if(values_node == NULL)
1351  E_RETURN(12);
1352 
1353  dt = conduit_node_dtype(values_node);
1354  if(dt == NULL)
1355  E_RETURN(13);
1356 
1357  /* Check the Conduit type to see how well it matches the type string. There
1358  are some Conduit protocols that make double even when we gave it float
1359  data (YAML/JSON).
1360  */
1361  if(*type == FMS_FLOAT || *type == FMS_COMPLEX_FLOAT) {
1362  if(conduit_datatype_is_double(dt) || conduit_datatype_is_float64(dt)) {
1363  /* The type was actually double for the data values. */
1364  *type = (*type == FMS_FLOAT) ? FMS_DOUBLE : FMS_COMPLEX_DOUBLE;
1365  }
1366  } else if(*type == FMS_DOUBLE || *type == FMS_COMPLEX_DOUBLE) {
1367  if(conduit_datatype_is_float(dt) || conduit_datatype_is_float32(dt)) {
1368  /* The type was actually float for the data values. */
1369  *type = (*type == FMS_DOUBLE) ? FMS_FLOAT : FMS_COMPLEX_FLOAT;
1370  }
1371  }
1372 
1373  conduit_data_ptr = conduit_node_element_ptr(values_node, 0);
1374 
1375  /* Need to copy the data out of conduit - right? */
1376  switch(*type) {
1377 #define COPY_DATA(typename, T, format) \
1378  case typename: \
1379  { \
1380  void *dest = malloc(sizeof(T) * *n); \
1381  memcpy(dest, conduit_data_ptr, sizeof(T) * *n); \
1382  *values = dest; \
1383  break; \
1384  }
1385  FOR_EACH_SCALAR_TYPE(COPY_DATA)
1386 #undef COPY_DATA
1387  default:
1388  E_RETURN(14);
1389  }
1390 
1391  return 0;
1392 }
1393 
1394 /* int (*get_string)(FmsIOContext *ctx, const char *path, char **value); */
1395 static int
1396 FmsIOGetStringConduit(FmsIOContext *ctx, const char *path, const char **value) {
1397  conduit_node *node = NULL;
1398  const conduit_datatype *dt = NULL;
1399  if(!ctx) E_RETURN(1);
1400  if(!path) E_RETURN(2);
1401  if(!value) E_RETURN(3);
1402 
1403  if(!conduit_node_has_path(ctx->root, path))
1404  E_RETURN(4);
1405 
1406  if((node = conduit_node_fetch(ctx->root, path)) == NULL)
1407  E_RETURN(5);
1408 
1409  dt = conduit_node_dtype(node);
1410 
1411  if(!conduit_datatype_is_char8_str(dt))
1412  E_RETURN(6);
1413 
1414  *value = conduit_node_fetch_path_as_char8_str(ctx->root, path);
1415 
1416  return 0;
1417 }
1418 
1419 static void
1420 FmsIOConduitInformation(const char *msg, const char *srcfile, int line) {
1421  printf("Information: %s: %s: %d\n", msg, srcfile, line);
1422 }
1423 
1424 static void
1425 FmsIOConduitWarning(const char *msg, const char *srcfile, int line) {
1426  printf("Warning: %s: %s: %d\n", msg, srcfile, line);
1427 }
1428 
1429 static void
1430 FmsIOConduitError(const char *msg, const char *srcfile, int line) {
1431  printf("ERROR: \"%s\": \"%s\": %d\n", msg, srcfile, line);
1432 }
1433 
1434 /**
1435 @brief This function initializes the IO context with function pointers that
1436  perform ASCII I/O.
1437 @param ctx The I/O context.
1438 */
1439 static void
1440 FmsIOContextInitializeConduit(FmsIOContext *ctx, const char *protocol) {
1441  if(ctx) {
1442  ctx->filename = NULL;
1443  ctx->root = NULL;
1444  ctx->writing = 0;
1445  /* Store the protocol this way since we do not pass it to the open function */
1446  size_t plen = strlen(protocol);
1447  char *plower = malloc(sizeof(char)*plen+1);
1448  FmsIOStringToLower(protocol, plen, plower);
1449  ctx->protocol = plower;
1450 
1451  /* Install some error handlers for Conduit. */
1452  conduit_utils_set_info_handler(FmsIOConduitInformation);
1453  conduit_utils_set_warning_handler(FmsIOConduitWarning);
1454  conduit_utils_set_error_handler(FmsIOConduitError);
1455  }
1456 }
1457 
1458 /**
1459 @brief This function initializes the functions object with function pointers that
1460  perform ASCII I/O.
1461 @param ctx The functions object.
1462 */
1463 static void
1464 FmsIOFunctionsInitializeConduit(FmsIOFunctions *obj) {
1465  if(obj) {
1466  obj->open = FmsIOOpenConduit;
1467  obj->close = FmsIOCloseConduit;
1468  obj->add_int = FmsIOAddIntConduit;
1469  obj->add_int_array = FmsIOAddIntArrayConduit;
1470  obj->add_typed_int_array = FmsIOAddTypedIntArrayConduit;
1471  obj->add_float = FmsIOAddFloatConduit;
1472  obj->add_double = FmsIOAddDoubleConduit;
1473  obj->add_string = FmsIOAddStringConduit;
1474  obj->add_scalar_array = FmsIOAddScalarArrayConduit;
1475  /*...*/
1476  obj->has_path = FmsIOHasPathConduit;
1477  obj->get_int = FmsIOGetIntConduit;
1478  obj->get_typed_int_array = FmsIOGetTypedIntArrayConduit;
1479  obj->get_scalar_array = FmsIOGetScalarArrayConduit;
1480  obj->get_string = FmsIOGetStringConduit;
1481  }
1482 }
1483 
1484 // Returns negative if there was an error checking support
1485 // Returns 0 if there was no error but the protocol is not ascii or conduit supported
1486 // Returns 1 if the protocol is supported by conduit
1487 // Returns 2 if the protocol is "ascii"
1488 static int CheckProtocolSupportConduit(const char *protocol) {
1489  if(!protocol) return -1;
1490  char plower[24];
1491  size_t plen = strlen(protocol);
1492  // Our buffer only holds 24 chars (longest name is only 20 chars)
1493  if(plen > 23) {
1494  return -2;
1495  }
1496  // Convert the string to lowercase before comparing
1497  FmsIOStringToLower(protocol, plen, plower);
1498 
1499  if(strcmp("ascii", plower) == 0)
1500  return 2;
1501 
1502  conduit_node *details = conduit_node_create();
1503  conduit_relay_io_about(details);
1504  int retval = 0;
1505  if(conduit_node_has_child(details, "protocols")) {
1506  conduit_node *protocols = conduit_node_fetch(details, "protocols");
1507  conduit_index_t nchild = conduit_node_number_of_children(protocols);
1508  for(conduit_index_t i = 0; i < nchild; i++) {
1509  conduit_node *child = conduit_node_child(protocols, i);
1510  char *key = conduit_node_name(child); // We have to free key but not value
1511  const char *value = conduit_node_as_char8_str(child);
1512  if(strcmp("enabled", value) == 0) {
1513  if(strcmp(plower, key) == 0) {
1514  retval = 1;
1515  }
1516  }
1517  free(key);
1518  if(retval) break;
1519  }
1520  } else {
1521  retval = -3;
1522  }
1523  conduit_node_destroy(details);
1524  return retval;
1525 }
1526 
1527 
1528 #endif
1529 
1530 /*****************************************************************************
1531 *** FMS I/O Building Block Functions
1532 *****************************************************************************/
1533 
1534 /**
1535 @brief Write FmsMetaData to the output I/O context.
1536 @param ctx The context
1537 @param io The I/O functions that operate on the context.
1538 @param key The key that identifies the data in the output.
1539 @param mdata The FMS metadata.
1540 @return 0 on success, non-zero otherwise.
1541 */
1542 static int
1543 FmsIOWriteFmsMetaData(FmsIOContext *ctx, FmsIOFunctions *io, const char *key,
1544  FmsMetaData mdata) {
1545  int err = 0;
1546  FmsMetaDataType type;
1547 
1548  /* It says it returns 1 if mdata is empty, but then just checks if its null (if im not mistaken).
1549  We already null checked before we got here so I'm not sure if we need to check for 1. */
1550  int r = FmsMetaDataGetType(mdata, &type);
1551  if(r > 1)
1552  E_RETURN(1);
1553  else if(r == 1)
1554  return 0;
1555 
1556  char *kmdtype = join_keys(key, "MetaDataType");
1557  (*io->add_string)(ctx, kmdtype, FmsMetaDataTypeNames[type]);
1558  FREE(kmdtype);
1559 
1560  switch(type) {
1561  case FMS_INTEGER: {
1562  char *kname = NULL, *kdata = NULL;
1563  const char *mdata_name = NULL;
1564  FmsIntType int_type;
1565  FmsInt size;
1566  const void *data = NULL;
1567 
1568  if(FmsMetaDataGetIntegers(mdata, &mdata_name, &int_type, &size, &data))
1569  E_RETURN(3);
1570 
1571  kname = join_keys(key, "Name");
1572  err = (*io->add_string)(ctx, kname, mdata_name);
1573  FREE(kname);
1574  if (err) { E_RETURN(4); }
1575 
1576  kdata = join_keys(key, "Data");
1577  err = (*io->add_typed_int_array)(ctx, kdata, int_type, data, size);
1578  FREE(kdata);
1579  if (err) { E_RETURN(5); }
1580  break;
1581  }
1582  case FMS_SCALAR: {
1583  char *kname = NULL, *kdata = NULL;
1584  const char *mdata_name = NULL;
1585  FmsScalarType scalar_type;
1586  FmsInt size;
1587  const void *data = NULL;
1588 
1589  if(FmsMetaDataGetScalars(mdata, &mdata_name, &scalar_type, &size, &data))
1590  E_RETURN(6);
1591 
1592  kname = join_keys(key, "Name");
1593  err = (*io->add_string)(ctx, kname, mdata_name);
1594  FREE(kname);
1595  if (err) { E_RETURN(7); }
1596 
1597  kdata = join_keys(key, "Data");
1598  err = (*io->add_scalar_array)(ctx, kdata, scalar_type, data, size);
1599  FREE(kdata);
1600  if (err) { E_RETURN(8); }
1601  break;
1602  }
1603  case FMS_STRING: {
1604  char *kname = NULL, *kdata = NULL;
1605  const char *mdata_name = NULL;
1606  const char *data = NULL;
1607 
1608  if(FmsMetaDataGetString(mdata, &mdata_name, &data))
1609  E_RETURN(9);
1610 
1611  kname = join_keys(key, "Name");
1612  err = (*io->add_string)(ctx, kname, mdata_name);
1613  FREE(kname);
1614  if (err) { E_RETURN(10); }
1615 
1616  kdata = join_keys(key, "Data");
1617  err = (*io->add_string)(ctx, kdata, data);
1618  FREE(kdata);
1619  if (err) { E_RETURN(11); }
1620  break;
1621  }
1622  case FMS_META_DATA: {
1623  char *kname = NULL, *kdata = NULL, *ksize = NULL;
1624  const char *mdata_name = NULL;
1625  FmsInt i, size = 0;
1626  FmsMetaData *data = NULL;
1627 
1628  if(FmsMetaDataGetMetaData(mdata, &mdata_name, &size, &data))
1629  E_RETURN(12);
1630 
1631  if (!data) { E_RETURN(13); }
1632 
1633  kname = join_keys(key, "Name");
1634  err = (*io->add_string)(ctx, kname, mdata_name);
1635  FREE(kname);
1636  if (err) { E_RETURN(14); }
1637 
1638  ksize = join_keys(key, "Size");
1639  err = (*io->add_int)(ctx, ksize, size);
1640  FREE(ksize);
1641  if (err) { E_RETURN(15); }
1642 
1643  kdata = join_keys(key, "Data");
1644  // Recursive?
1645  for(i = 0; i < size; i++) {
1646  char temp[20], *tk = NULL;
1647  sprintf(temp, "%d", (int)i);
1648  tk = join_keys(kdata, temp);
1649  err = FmsIOWriteFmsMetaData(ctx, io, tk, data[i]);
1650  FREE(tk);
1651  if (err) {
1652  FREE(kdata);
1653  E_RETURN(16);
1654  }
1655  }
1656  FREE(kdata);
1657  break;
1658  }
1659  default:
1660  E_RETURN(17);
1661  break;
1662  }
1663  return 0;
1664 }
1665 
1666 static int
1667 FmsIOReadFmsMetaData(FmsIOContext *ctx, FmsIOFunctions *io, const char *key,
1668  FmsIOMetaDataInfo *mdinfo) {
1669  int err = 0;
1670  if(!mdinfo) E_RETURN(1);
1671 
1672  {
1673  char *kmdtype = join_keys(key, "MetaDataType");
1674  const char *str = NULL;
1675  err = (*io->get_string)(ctx, kmdtype, &str);
1676  FREE(kmdtype);
1677  if(err)
1678  E_RETURN(2);
1679  if(FmsGetMetaDataTypeFromName(str, &mdinfo->mdtype))
1680  E_RETURN(3);
1681  }
1682 
1683  // Get name
1684  {
1685  char *kname = join_keys(key, "Name");
1686  err = (*io->get_string)(ctx, kname, &mdinfo->name);
1687  FREE(kname);
1688  if(err)
1689  E_RETURN(4);
1690  }
1691 
1692  switch (mdinfo->mdtype) {
1693  case FMS_INTEGER: {
1694  // Get DataArray
1695  char *kdata = join_keys(key, "Data");
1696  err = (*io->get_typed_int_array)(ctx, kdata, &mdinfo->subtype.i_type,
1697  &mdinfo->data, &mdinfo->size);
1698  FREE(kdata);
1699  if(err)
1700  E_RETURN(5);
1701  break;
1702  }
1703  case FMS_SCALAR: {
1704  // Get data array
1705  char *kdata = join_keys(key, "Data");
1706  err = (*io->get_scalar_array)(ctx, kdata, &mdinfo->subtype.s_type,
1707  &mdinfo->data, &mdinfo->size);
1708  FREE(kdata);
1709  if(err)
1710  E_RETURN(6);
1711  break;
1712  }
1713  case FMS_STRING: {
1714  // Get data array
1715  char *kdata = join_keys(key, "Data");
1716  const char *md_str = NULL;
1717  err = (*io->get_string)(ctx, kdata, &md_str);
1718  FREE(kdata);
1719  /* Copy the string we got from the get_string. Its lifetime has to be tied to the metadata. */
1720  if(err || FmsIOCopyString(md_str, (char **)&mdinfo->data))
1721  E_RETURN(7);
1722  break;
1723  }
1724  case FMS_META_DATA: {
1725  // Get size
1726  FmsInt i;
1727  FmsIOMetaDataInfo *mds = NULL;
1728  char *ksize = join_keys(key, "Size"), *kdata = NULL;
1729  err = (*io->get_int)(ctx, ksize, &mdinfo->size);
1730  FREE(ksize);
1731  if(err)
1732  E_RETURN(8);
1733  mdinfo->data = calloc(mdinfo->size, sizeof(FmsIOMetaDataInfo));
1734  mds = (FmsIOMetaDataInfo *)mdinfo->data;
1735  kdata = join_keys(key, "Data");
1736  for(i = 0; i < mdinfo->size; i++) {
1737  char temp[21], *ki = NULL;
1738  sprintf(temp, FMS_LU, i);
1739  ki = join_keys(kdata, temp);
1740  err |= FmsIOReadFmsMetaData(ctx, io, ki, &mds[i]);
1741  }
1742  FREE(kdata);
1743  if(err)
1744  E_RETURN(9);
1745  break;
1746  }
1747  default:
1748  break;
1749  }
1750  return 0;
1751 }
1752 
1753 static int
1754 FmsIOWriteFmsDomain(FmsIOContext *ctx, FmsIOFunctions *io, const char *key,
1755  FmsDomain dom) {
1756  FmsInt dim = 0;
1757  if(FmsDomainGetDimension(dom, &dim))
1758  E_RETURN(1);
1759  char *kdim = join_keys(key, "Dimension");
1760  (io->add_int)(ctx, kdim, dim);
1761  FREE(kdim);
1762 
1763  FmsInt nverts = 0;
1764  if(FmsDomainGetNumVertices(dom, &nverts))
1765  E_RETURN(2);
1766  char *knverts = join_keys(key, "NumVertices");
1767  (io->add_int)(ctx, knverts, nverts);
1768  FREE(knverts);
1769 
1770  // Skip verticies because we already know what we need to know
1771  char *kentities = join_keys(key, "Entities");
1772  FmsInt i, entries = 0;
1773  for(i = 1; i < FMS_NUM_ENTITY_TYPES; i++) {
1774  FmsInt nents = 0;
1775  FmsDomainGetNumEntities(dom, (FmsEntityType)i, &nents);
1776  if(nents) {
1777  char temp[8];
1778  sprintf(temp, "%d", (int)entries++);
1779  char *kentry = join_keys(kentities, temp);
1780  const char *enttype = FmsEntityTypeNames[i];
1781  char *kenttype = join_keys(kentry, "EntityType");
1782  (*io->add_string)(ctx, kenttype, enttype);
1783  FREE(kenttype);
1784 
1785  char *kne = join_keys(kentry, "NumEntities");
1786  (*io->add_int)(ctx, kne, nents);
1787  FREE(kne);
1788 
1789  FmsIntType idtype;
1790  const void *ents = NULL;
1791  FmsInt ne = 0;
1793  &idtype, &ents, &ne)) {
1794  FREE(kentry); E_RETURN(3);
1795  }
1796 
1797  if(ents == NULL) {
1798  FREE(kentry); E_RETURN(4);
1799  }
1800 
1801  // TODO: Remove this check
1802  if(nents != ne) {
1803  FREE(kentry); E_RETURN(5);
1804  }
1805 
1806  const FmsInt N = FmsEntityNumSides[i] * nents;
1807  (*io->add_typed_int_array)(ctx, kentry, idtype, ents, N);
1808  FREE(kentry);
1809  }
1810  }
1811  FREE(kentities);
1812  // Q: Do we even have to store the orientations? Fms converts everything to standard Fms orientation in memeory.
1813  return 0;
1814 }
1815 
1816 static int
1817 FmsIOReadFmsDomain(FmsIOContext *ctx, FmsIOFunctions *io, const char *key,
1818  FmsIODomainInfo *dinfo) {
1819  int err = 0;
1820  if(!dinfo)
1821  E_RETURN(1);
1822 
1823  // Get dimension
1824  {
1825  char *kdom = join_keys(key, "Dimension");
1826  err = (*io->get_int)(ctx, kdom, &dinfo->dim);
1827  FREE(kdom);
1828  if(err)
1829  E_RETURN(2);
1830  }
1831 
1832  // Get Num verticies
1833  {
1834  char *knverts = join_keys(key, "NumVertices");
1835  err = (*io->get_int)(ctx, knverts, &dinfo->nverts);
1836  FREE(knverts);
1837  if(err)
1838  E_RETURN(3);
1839  }
1840 
1841  if(dinfo->dim) {
1842  char *kentities = join_keys(key, "Entities");
1843  FmsInt i = 0;
1844  dinfo->entities = calloc(sizeof(FmsIOEntityInfo), dinfo->dim);
1845  for(i = 0; i < dinfo->dim; i++) {
1846  char temp[21], *ke = NULL;
1847  sprintf(temp, FMS_LU, i);
1848  ke = join_keys(kentities, temp);
1849  // TODO: Fix err logic so we don't leak on error.
1850  // Get EntityType
1851  {
1852  char *kent_type = join_keys(ke, "EntityType");
1853  const char *ent_name = NULL;
1854  err = (*io->get_string)(ctx, kent_type, &ent_name);
1855  FREE(kent_type);
1856  if(err)
1857  E_RETURN(4);
1858  if(FmsGetEntityTypeFromName(ent_name, &dinfo->entities[i].ent_type))
1859  E_RETURN(5);
1860  }
1861 
1862  // Get NumEnts
1863  {
1864  char *knents = join_keys(ke, "NumEntities");
1865  err = (*io->get_int)(ctx, knents, &dinfo->entities[i].nents);
1866  FREE(knents);
1867  if(err)
1868  E_RETURN(6);
1869  }
1870 
1871  // Get Entity array
1872  err = (*io->get_typed_int_array)(ctx, ke, &dinfo->entities[i].type,
1873  &dinfo->entities[i].values, &dinfo->entities[i].size);
1874  FREE(ke);
1875  if(err)
1876  E_RETURN(7);
1877  }
1878  FREE(kentities);
1879  }
1880  return 0;
1881 }
1882 
1883 static int
1884 FmsIOWriteDomains(FmsIOContext *ctx, FmsIOFunctions *io, const char *key,
1885  FmsMesh mesh, FmsInt di) {
1886  const char *domname = NULL;
1887  FmsInt ndoms = 0;
1888  FmsDomain *doms = NULL;
1889  if(FmsMeshGetDomains(mesh, di, &domname, &ndoms, &doms))
1890  E_RETURN(1);
1891 
1892  if(!domname)
1893  E_RETURN(2);
1894  char *kdname = join_keys(key, "Name");
1895  (*io->add_string)(ctx, kdname, domname);
1896  FREE(kdname);
1897 
1898  char *knd = join_keys(key, "NumDomains");
1899  (*io->add_int)(ctx, knd, ndoms);
1900  FREE(knd);
1901 
1902  char *kdoms = join_keys(key, "Domains");
1903  FmsInt i;
1904  for(i = 0; i < ndoms; i++) {
1905  char tmp[20], *kd = NULL;
1906  sprintf(tmp, "%d", (int)i);
1907  kd = join_keys(kdoms, tmp);
1908  FmsIOWriteFmsDomain(ctx, io, kd, doms[i]);
1909  FREE(kd);
1910  }
1911  FREE(kdoms);
1912  return 0;
1913 }
1914 
1915 static int
1916 FmsIOReadFmsDomainName(FmsIOContext *ctx, FmsIOFunctions *io, const char *key,
1917  FmsIODomainNameInfo *dinfo) {
1918  int err = 0;
1919  if(!dinfo)
1920  E_RETURN(1);
1921 
1922  // Get domain name
1923  {
1924  char *kdname = join_keys(key, "Name");
1925  err = (*io->get_string)(ctx, kdname, &dinfo->name);
1926  FREE(kdname);
1927  if(err)
1928  E_RETURN(2);
1929  }
1930 
1931  // Get number of domains
1932  {
1933  char *kndoms = join_keys(key, "NumDomains");
1934  err = (*io->get_int)(ctx, kndoms, &dinfo->ndomains);
1935  FREE(kndoms);
1936  if(err)
1937  E_RETURN(3);
1938  }
1939 
1940  // Read the domains (if we have any)
1941  if(dinfo->ndomains) {
1942  char *kdoms = join_keys(key, "Domains");
1943  FmsInt i = 0;
1944  dinfo->domains = calloc(sizeof(FmsIODomainInfo), dinfo->ndomains);
1945  for(i = 0; i < dinfo->ndomains; i++) {
1946  char temp[21], *kd = NULL;
1947  sprintf(temp, FMS_LU, i);
1948  kd = join_keys(kdoms, temp);
1949  err |= FmsIOReadFmsDomain(ctx, io, kd, &dinfo->domains[i]);
1950  FREE(kd);
1951  }
1952  FREE(kdoms);
1953  if(err)
1954  E_RETURN(4);
1955  }
1956  return 0;
1957 }
1958 
1959 /**
1960 @brief Write FmsMesh to the output I/O context.
1961 @param ctx The context
1962 @param io The I/O functions that operate on the context.
1963 @param key The key that identifies the data in the output.
1964 @param comp The FMS component.
1965 @return 0 on success, non-zero otherwise.
1966 */
1967 static int
1968 FmsIOWriteComponent(FmsIOContext *ctx, FmsIOFunctions *io, const char *key,
1969  FmsComponent comp) {
1970  const char *comp_name = NULL;
1971  if(FmsComponentGetName(comp, &comp_name))
1972  E_RETURN(1);
1973  char *kcomp_name = join_keys(key, "Name");
1974  (*io->add_string)(ctx, kcomp_name, comp_name);
1975  FREE(kcomp_name);
1976 
1977  FmsInt dim = 0;
1978  if(FmsComponentGetDimension(comp, &dim))
1979  E_RETURN(2);
1980  char *kdim = join_keys(key, "Dimension");
1981  (*io->add_int)(ctx, kdim, dim);
1982  FREE(kdim);
1983 
1984  FmsInt nents = 0;
1985  if(FmsComponentGetNumEntities(comp, &nents))
1986  E_RETURN(3);
1987  char *knents = join_keys(key, "NumEntities");
1988  (*io->add_int)(ctx, knents, nents);
1989  FREE(knents);
1990 
1991  FmsField coords = NULL;
1992  if(FmsComponentGetCoordinates(comp, &coords))
1993  E_RETURN(4);
1994  // Coords can be null
1995  if(coords) {
1996  const char *coords_name = NULL;
1997  FmsFieldGetName(coords, &coords_name);
1998  char *kcoords_name = join_keys(key, "Coordinates");
1999  (*io->add_string)(ctx, kcoords_name, coords_name);
2000  FREE(kcoords_name);
2001  }
2002 
2003  FmsInt nparts = 0;
2004  if(FmsComponentGetNumParts(comp, &nparts))
2005  E_RETURN(5);
2006  char *knparts = join_keys(key, "NumParts");
2007  (*io->add_int)(ctx, knparts, nparts);
2008  FREE(knparts);
2009 
2010  char *kparts = join_keys(key, "Parts");
2011  FmsInt i;
2012  for(i = 0; i < nparts; i++) {
2013  char temp[20], *kpart;
2014  sprintf(temp, "%d", (int)i);
2015  kpart = join_keys(kparts, temp);
2016  FmsDomain dom;
2017  if(FmsComponentGetPart(comp, i, FMS_VERTEX, &dom, NULL, NULL, NULL, NULL))
2018  E_RETURN(6);
2019 
2020  if(dom) {
2021  const char *domain_name = NULL;
2022  FmsInt did = 0;
2023  if(FmsDomainGetName(dom, &domain_name, &did))
2024  E_RETURN(7);
2025 
2026  char *kdomain_name = join_keys(kpart, "DomainName");
2027  (*io->add_string)(ctx, kdomain_name, domain_name);
2028  FREE(kdomain_name);
2029 
2030  char *kdid = join_keys(kpart, "DomainID");
2031  (*io->add_int)(ctx, kdid, did);
2032  FREE(kdid);
2033  }
2034 
2035  char found = 0;
2036  FmsInt et;
2037  for(et = 0; et < FMS_NUM_ENTITY_TYPES; et++) {
2038  FmsIntType ent_id_type;
2039  const void *ents;
2040  FmsInt nents = 0;
2041  // Q: Doing the for loop like this should pickup all the local indexing too?
2042  // FmsComponentGetPart and FmsComponentGetPartSubEntities index into the same arrays.
2043  if(FmsComponentGetPart(comp, i, (FmsEntityType)et,
2044  NULL, &ent_id_type, &ents, NULL, &nents))
2045  E_RETURN(8);
2046  // NULL means use all entities in that domain
2047  if(ents && nents) {
2048  found = 1;
2049  const char *enttype = FmsEntityTypeNames[et];
2050  if(FmsEntityDim[et] == dim) {
2051  char *kenttype = join_keys(kpart, "PartEntityType");
2052  (*io->add_string)(ctx, kenttype, enttype);
2053  FREE(kenttype);
2054  }
2055  char *k = join_keys(kpart, enttype);
2056 
2057  char *knents = join_keys(k, "NumEntities");
2058  (*io->add_int)(ctx, knents, nents);
2059  FREE(knents);
2060 
2061  (*io->add_typed_int_array)(ctx, k, ent_id_type, ents, nents);
2062  FREE(k);
2063  }
2064  }
2065  // "Typically, the whole is represented by a special component of all elements (3-entities) on all domains."
2066  if(!found) {
2067  char *kfull_domain = join_keys(kpart, "FullDomain");
2068  (*io->add_string)(ctx, kfull_domain, "Yes");
2069  FREE(kfull_domain);
2070  }
2071  FREE(kpart);
2072  }
2073  FREE(kparts);
2074 
2075  const FmsInt *rel_comps = NULL;
2076  FmsInt nrelcomps = 0;
2077  if(FmsComponentGetRelations(comp, &rel_comps, &nrelcomps))
2078  E_RETURN(9);
2079 
2080 
2081  char *krelations = join_keys(key, "Relations");
2082  (*io->add_int_array)(ctx, krelations, rel_comps, nrelcomps);
2083  FREE(krelations);
2084 
2085  return 0;
2086 }
2087 
2088 static int
2089 FmsIOReadFmsComponent(FmsIOContext *ctx, FmsIOFunctions *io, const char *key,
2090  FmsIOComponentInfo *comp_info) {
2091  int err = 0;
2092  if(!comp_info) E_RETURN(1);
2093 
2094  // Get Component name
2095  {
2096  char *kcomp_name = join_keys(key, "Name");
2097  err = (*io->get_string)(ctx, kcomp_name, &comp_info->name);
2098  FREE(kcomp_name);
2099  if(err)
2100  E_RETURN(2);
2101  }
2102 
2103  // Get dim
2104  {
2105  char *kcomp_dim = join_keys(key, "Dimension");
2106  err = (*io->get_int)(ctx, kcomp_dim, &comp_info->dim);
2107  FREE(kcomp_dim);
2108  if(err)
2109  E_RETURN(3);
2110  }
2111 
2112  {
2113  char *knents = join_keys(key, "NumEntities");
2114  err = (*io->get_int)(ctx, knents, &comp_info->nents);
2115  FREE(knents);
2116  if(err)
2117  E_RETURN(4);
2118  }
2119 
2120  /// Not all components have Coords
2121  {
2122  char *kcoords = join_keys(key, "Coordinates");
2123  if((*io->has_path)(ctx, kcoords))
2124  err = (*io->get_string)(ctx, kcoords, &comp_info->coordinates_name);
2125  FREE(kcoords);
2126  if(err)
2127  E_RETURN(5);
2128  }
2129 
2130  {
2131  char *knparts = join_keys(key, "NumParts");
2132  err = (*io->get_int)(ctx, knparts, &comp_info->nparts);
2133  FREE(knparts);
2134  if(err)
2135  E_RETURN(6);
2136  }
2137 
2138  // If we have parts get their info
2139  if(comp_info->nparts) {
2140  char *kparts = join_keys(key, "Parts");
2141  FmsInt i, et;
2142  comp_info->parts = calloc(sizeof(FmsIOComponentPartInfo), comp_info->nparts);
2143  for(i = 0; i < comp_info->nparts; i++) {
2144  char temp[21], *kpart = NULL;
2145  sprintf(temp, FMS_LU, i);
2146  kpart = join_keys(kparts, temp);
2147 
2148  // Get the DomainName for this part
2149  {
2150  char *kdom_name = join_keys(kpart, "DomainName");
2151  err = (*io->get_string)(ctx, kdom_name, &comp_info->parts[i].domain_name);
2152  FREE(kdom_name);
2153  if(err)
2154  E_RETURN(7);
2155  }
2156 
2157  // Get the domain id for this part
2158  {
2159  char *kdid = join_keys(kpart, "DomainID");
2160  err = (*io->get_int)(ctx, kdid, &comp_info->parts[i].domain_id);
2161  FREE(kdid);
2162  if(err)
2163  E_RETURN(8);
2164  }
2165 
2166  // Check to see if this is a FullDomain part, this part will be complete if true
2167  {
2168  char *kfulldomain = join_keys(kpart, "FullDomain");
2169  if((*io->has_path)(ctx, kfulldomain)) {
2170  const char *isfulldomain = NULL;
2171  err = (*io->get_string)(ctx, kfulldomain, &isfulldomain);
2172  if(err)
2173  E_RETURN(9);
2174  // Special case, this part is now complete
2175  if(strcmp("Yes", isfulldomain) == 0) {
2176  comp_info->parts[i].full_domain = 1;
2177  FREE(kfulldomain); FREE(kpart);
2178  continue;
2179  }
2180  }
2181  comp_info->parts[i].full_domain = 0;
2182  FREE(kfulldomain);
2183  }
2184 
2185  // If this was not a full domain then we have to figure out the entity & subentities
2186  {
2187  char *kentity = join_keys(kpart, "PartEntityType");
2188  const char *str = NULL;
2189  err = (io->get_string)(ctx, kentity, &str);
2190  FREE(kentity);
2191  if(err)
2192  E_RETURN(10);
2193  if(FmsGetEntityTypeFromName(str, &comp_info->parts[i].part_ent_type))
2194  E_RETURN(11);
2195  }
2196 
2197  // Entity type is encoded into the key for these
2198  for(et = 0; et < FMS_NUM_ENTITY_TYPES; et++) {
2199  char *k = join_keys(kpart, FmsEntityTypeNames[et]);
2200  if((*io->has_path)(ctx, k)) {
2201  // Now we have to populate the entitiy info
2202  comp_info->parts[i].entities[et].ent_type = (FmsEntityType)et;
2203 
2204  // Get nents
2205  {
2206  char *knents = join_keys(k, "NumEntities");
2207  err = (*io->get_int)(ctx, knents, &comp_info->parts[i].entities[et].nents);
2208  FREE(knents);
2209  }
2210 
2211  err |= (*io->get_typed_int_array)(ctx, k,
2212  &comp_info->parts[i].entities[et].type,
2213  &comp_info->parts[i].entities[et].values,
2214  &comp_info->parts[i].entities[et].size);
2215  }
2216  FREE(k);
2217  if(err)
2218  E_RETURN(12);
2219  }
2220  FREE(kpart);
2221  }
2222  FREE(kparts);
2223  }
2224 
2225  // Finally get the relations
2226  {
2227  char *krelcomps = join_keys(key, "Relations");
2228  if((*io->has_path)(ctx, krelcomps)) {
2229  err = (*io->get_typed_int_array)(ctx, krelcomps, &comp_info->relation_type,
2230  (void*)&comp_info->relation_values, &comp_info->relation_size);
2231  // Relations should be of type FmsInt
2232  if(comp_info->relation_type != FMS_UINT64)
2233  err = 1;
2234  }
2235 
2236  FREE(krelcomps);
2237  if(err)
2238  E_RETURN(13);
2239  }
2240  return 0;
2241 }
2242 
2243 /**
2244 @brief Write FmsMesh to the output I/O context.
2245 @param ctx The context
2246 @param io The I/O functions that operate on the context.
2247 @param key The key that identifies the data in the output.
2248 @param tag The FMS tag.
2249 @return 0 on success, non-zero otherwise.
2250 */
2251 static int
2252 FmsIOWriteTag(FmsIOContext *ctx, FmsIOFunctions *io, const char *key,
2253  FmsTag tag) {
2254  const char *tag_name = NULL;
2255  if(FmsTagGetName(tag, &tag_name))
2256  E_RETURN(1);
2257  char *ktag_name = join_keys(key, "TagName");
2258  (*io->add_string)(ctx, ktag_name, tag_name);
2259  FREE(ktag_name);
2260 
2261  FmsComponent comp;
2262  if(FmsTagGetComponent(tag, &comp))
2263  E_RETURN(2);
2264  const char *comp_name = NULL;
2265  if(FmsComponentGetName(comp, &comp_name))
2266  E_RETURN(3);
2267  char *kcomp = join_keys(key, "Component");
2268  (*io->add_string)(ctx, kcomp, comp_name);
2269  FREE(kcomp);
2270 
2271  FmsIntType tag_type;
2272  const void *ent_tags = NULL;
2273  FmsInt ntags = 0;
2274  if(FmsTagGet(tag, &tag_type, &ent_tags, &ntags))
2275  E_RETURN(4);
2276 
2277  (*io->add_typed_int_array)(ctx, key, tag_type, ent_tags, ntags);
2278 
2279  const void *tagvalues = NULL;
2280  const char * const *descriptions = NULL;
2281  if(FmsTagGetDescriptions(tag, NULL, &tagvalues, &descriptions, &ntags))
2282  E_RETURN(5);
2283 
2284  char *kdescriptions = join_keys(key, "Descriptions");
2285 
2286  char *kdescriptions_size = join_keys(kdescriptions, "Size");
2287  (*io->add_int)(ctx, kdescriptions_size, ntags);
2288  FREE(kdescriptions_size);
2289 
2290  FmsInt i;
2291  for(i = 0; i < ntags; i++) {
2292  char temp[21], *kd;
2293  sprintf(temp, FMS_LU, i);
2294  kd = join_keys(kdescriptions, temp);
2295 
2296  {
2297  char *kv = join_keys(kd, "Value");
2298  // TODO: Fix add_int to support signed ints
2299  switch(tag_type) {
2300 #define CASES(typename, T, format) \
2301  case typename: \
2302  { \
2303  T *vs = (T*)tagvalues; \
2304  (*io->add_int)(ctx, kv, (FmsInt)vs[i]); \
2305  break; \
2306  }
2308 #undef CASES
2309  default:
2310  E_RETURN(6);
2311  break;
2312  }
2313  FREE(kv);
2314  }
2315 
2316  {
2317  char *kdstring = join_keys(kd, "Description");
2318  (*io->add_string)(ctx, kdstring, descriptions[i]);
2319  FREE(kdstring);
2320  }
2321  FREE(kd);
2322  }
2323  FREE(kdescriptions);
2324  return 0;
2325 }
2326 
2327 static int
2328 FmsIOReadFmsTag(FmsIOContext *ctx, FmsIOFunctions *io, const char *key,
2329  FmsIOTagInfo *tinfo) {
2330  int err = 0;
2331  if(!tinfo)
2332  E_RETURN(1);
2333 
2334  {
2335  char *ktag_name = join_keys(key, "TagName");
2336  err = (*io->get_string)(ctx, ktag_name, &tinfo->name);
2337  FREE(ktag_name);
2338  if(err)
2339  E_RETURN(2);
2340  }
2341 
2342  {
2343  char *kcomp_name = join_keys(key, "Component");
2344  err = (*io->get_string)(ctx, kcomp_name, &tinfo->comp_name);
2345  FREE(kcomp_name);
2346  if(err)
2347  E_RETURN(3);
2348  }
2349 
2350  err = (*io->get_typed_int_array)(ctx, key, &tinfo->type, &tinfo->values,
2351  &tinfo->size);
2352  if(err)
2353  E_RETURN(4);
2354 
2355  char *kdescriptions = join_keys(key, "Descriptions");
2356  if((*io->has_path)(ctx, kdescriptions)) {
2357  FmsInt i;
2358 
2359  {
2360  char *kdesc_size = join_keys(kdescriptions, "Size");
2361  err = (*io->get_int)(ctx, kdesc_size, &tinfo->descr_size);
2362  FREE(kdesc_size);
2363  }
2364 
2365  tinfo->tag_values = calloc(sizeof(FmsInt), tinfo->descr_size);
2366  tinfo->descriptions = calloc(sizeof(char*), tinfo->descr_size);
2367  for(i = 0; i < tinfo->descr_size; i++) {
2368  char temp[21], *ki = NULL, *kv = NULL, *kd = NULL;
2369  sprintf(temp, FMS_LU, i);
2370  ki = join_keys(kdescriptions, temp);
2371 
2372  // TODO: Support unsigned
2373  kv = join_keys(ki, "Value");
2374  err |= (*io->get_int)(ctx, kv, &tinfo->tag_values[i]);
2375  FREE(kv);
2376 
2377  kd = join_keys(ki, "Description");
2378  err |= (*io->get_string)(ctx, kd, &tinfo->descriptions[i]);
2379  FREE(kd);
2380  FREE(ki);
2381  }
2382  }
2383  FREE(kdescriptions);
2384  if(err)
2385  E_RETURN(5);
2386 
2387  return 0;
2388 }
2389 
2390 
2391 /**
2392 @brief Write FmsMesh to the output I/O context.
2393 @param ctx The context
2394 @param io The I/O functions that operate on the context.
2395 @param key The key that identifies the data in the output.
2396 @param mesh The FMS mesh.
2397 @return 0 on success, non-zero otherwise.
2398 */
2399 static int
2400 FmsIOWriteFmsMesh(FmsIOContext *ctx, FmsIOFunctions *io, const char *key,
2401  FmsMesh mesh) {
2402  /** IDEA: Come back and just reuse one char (stack?) buffer for all these keys? */
2403  FmsInt pinfo[2];
2404  if(FmsMeshGetPartitionId(mesh, &pinfo[0], &pinfo[1]))
2405  E_RETURN(1);
2406 
2407  char *kpinfo = join_keys(key, "PartitionInfo");
2408  (*io->add_int_array)(ctx, kpinfo, pinfo, 2);
2409  FREE(kpinfo);
2410 
2411  FmsInt ndnames = 0;
2412  if(FmsMeshGetNumDomainNames(mesh, &ndnames))
2413  E_RETURN(2);
2414 
2415  char *kndnames = join_keys(key, "NumDomainNames");
2416  (*io->add_int)(ctx, kndnames, ndnames);
2417  FREE(kndnames);
2418 
2419  FmsInt ncomps = 0;
2420  if(FmsMeshGetNumComponents(mesh, &ncomps))
2421  E_RETURN(3);
2422  char *kncomps = join_keys(key, "NumComponents");
2423  (*io->add_int)(ctx, kncomps, ncomps);
2424  FREE(kncomps);
2425 
2426  FmsInt ntags = 0;
2427  if(FmsMeshGetNumTags(mesh, &ntags))
2428  E_RETURN(4);
2429  char *kntags = join_keys(key, "NumTags");
2430  (*io->add_int)(ctx, kntags, ntags);
2431  FREE(kntags);
2432 
2433  char *kdom_names = join_keys(key, "DomainNames");
2434  FmsInt i;
2435  for(i = 0; i < ndnames; i++) {
2436  char tmp[20], *dk = NULL;
2437  sprintf(tmp, "%d", (int)i);
2438  dk = join_keys(kdom_names, tmp);
2439  FmsIOWriteDomains(ctx, io, dk, mesh, i);
2440  FREE(dk);
2441  }
2442  FREE(kdom_names);
2443 
2444  char *kcomps = join_keys(key, "Components");
2445  for(i = 0; i < ncomps; i++) {
2446  char tmp[20], *kc = NULL;
2447  FmsComponent comp;
2448  if(FmsMeshGetComponent(mesh, i, &comp))
2449  E_RETURN(7);
2450 
2451  if(!comp)
2452  E_RETURN(8);
2453 
2454  sprintf(tmp, "%d", (int)i);
2455  kc = join_keys(kcomps, tmp);
2456  FmsIOWriteComponent(ctx, io, kc, comp);
2457  FREE(kc);
2458  }
2459  FREE(kcomps);
2460 
2461  char *ktags = join_keys(key, "Tags");
2462  for(i = 0; i < ntags; i++) {
2463  char tmp[20], *kt;
2464  FmsTag t;
2465  if(FmsMeshGetTag(mesh, i, &t))
2466  E_RETURN(9);
2467 
2468  sprintf(tmp, "%d", (int)i);
2469  kt = join_keys(ktags, tmp);
2470  FmsIOWriteTag(ctx, io, kt, t);
2471  FREE(kt);
2472  }
2473  FREE(ktags);
2474 
2475  return 0;
2476 }
2477 
2478 static int
2479 FmsIOReadFmsMesh(FmsIOContext *ctx, FmsIOFunctions *io, const char *key,
2480  FmsIOMeshInfo *mesh_info) {
2481  int err = 0;
2482  FmsInt i = 0;
2483  if(!mesh_info) E_RETURN(1);
2484 
2485  // Get partition info
2486  {
2487  char *kpinfo = join_keys(key, "PartitionInfo");
2488  FmsIntType type;
2489  FmsInt n = 0;
2490  err = (*io->get_typed_int_array)(ctx, kpinfo, &type,
2491  (void*)&mesh_info->partition_info, &n);
2492  FREE(kpinfo);
2493  if(err)
2494  E_RETURN(2);
2495  }
2496 
2497  // Get num domain names
2498  {
2499  char *kndnames = join_keys(key, "NumDomainNames");
2500  err = (*io->get_int)(ctx, kndnames, &mesh_info->ndomain_names);
2501  FREE(kndnames);
2502  if(err)
2503  E_RETURN(3);
2504  }
2505 
2506  // Get num components
2507  {
2508  char *kncomps = join_keys(key, "NumComponents");
2509  err = (*io->get_int)(ctx, kncomps, &mesh_info->ncomponents);
2510  FREE(kncomps);
2511  if(err)
2512  E_RETURN(4);
2513  }
2514 
2515  // Get num tags
2516  {
2517  char *kntags = join_keys(key, "NumTags");
2518  err = (*io->get_int)(ctx, kntags, &mesh_info->ntags);
2519  FREE(kntags);
2520  if(err)
2521  E_RETURN(5);
2522  }
2523 
2524  // Get domain names
2525  if(mesh_info->ndomain_names) {
2526  char *kdom_names = join_keys(key, "DomainNames");
2527  mesh_info->domain_names = calloc(sizeof(FmsIODomainNameInfo),
2528  mesh_info->ndomain_names);
2529  for(i = 0; i < mesh_info->ndomain_names; i++) {
2530  char temp[21], *dk = NULL;
2531  sprintf(temp, FMS_LU, i);
2532  dk = join_keys(kdom_names, temp);
2533  err |= FmsIOReadFmsDomainName(ctx, io, dk, &mesh_info->domain_names[i]);
2534  FREE(dk);
2535  }
2536  FREE(kdom_names);
2537  if(err)
2538  E_RETURN(6);
2539  }
2540 
2541  // Get components
2542  if(mesh_info->ncomponents) {
2543  char *kcomps = join_keys(key, "Components");
2544  mesh_info->components = calloc(sizeof(FmsIOComponentInfo),
2545  mesh_info->ncomponents);
2546  for(i = 0; i < mesh_info->ncomponents; i++) {
2547  char temp[21], *kc = NULL;
2548  sprintf(temp, FMS_LU, i);
2549  kc = join_keys(kcomps, temp);
2550  err |= FmsIOReadFmsComponent(ctx, io, kc, &mesh_info->components[i]);
2551  FREE(kc);
2552  }
2553  FREE(kcomps);
2554  if(err)
2555  E_RETURN(7);
2556  }
2557 
2558  // Get tags
2559  if(mesh_info->ntags) {
2560  char *ktags = join_keys(key, "Tags");
2561  mesh_info->tags = calloc(sizeof(FmsIOTagInfo), mesh_info->ntags);
2562  for(i = 0; i < mesh_info->ntags; i++) {
2563  char temp[21], *kt = NULL;
2564  sprintf(temp, FMS_LU, i);
2565  kt = join_keys(ktags, temp);
2566  err |= FmsIOReadFmsTag(ctx, io, kt, &mesh_info->tags[i]);
2567  FREE(kt);
2568  }
2569  FREE(ktags);
2570  if(err)
2571  E_RETURN(8);
2572  }
2573  return 0;
2574 }
2575 
2576 /**
2577 @brief Write FmsFieldDescriptor to the output I/O context.
2578 @param ctx The context
2579 @param io The I/O functions that operate on the context.
2580 @param key The key that identifies the data in the output.
2581 @param fd The FMS field descriptor.
2582 @return 0 on success, non-zero otherwise.
2583 */
2584 static int
2585 FmsIOWriteFmsFieldDescriptor(FmsIOContext *ctx, FmsIOFunctions *io,
2586  const char *key,
2587  FmsFieldDescriptor fd) {
2588  // Write the fd's name
2589  const char *fd_name = NULL;
2590  if(FmsFieldDescriptorGetName(fd, &fd_name))
2591  E_RETURN(1);
2592 
2593  char *key_name = join_keys(key, "Name");
2594  (*io->add_string)(ctx, key_name, fd_name);
2595  FREE(key_name);
2596 
2597  // Write which compoenent the fd refers to
2598  FmsComponent fc = NULL;
2599  if(FmsFieldDescriptorGetComponent(fd, &fc))
2600  E_RETURN(2);
2601 
2602  // Q: Do FieldDescriptors ALWAYS refer to a component?
2603  if(!fc)
2604  E_RETURN(3);
2605 
2606  const char *fc_name = NULL;
2607  if(FmsComponentGetName(fc, &fc_name))
2608  E_RETURN(4);
2609 
2610  char *key_fc_name = join_keys(key, "ComponentName");
2611  (*io->add_string)(ctx, key_fc_name, fc_name);
2612  FREE(key_fc_name);
2613 
2614  // Write fd type
2615  FmsFieldDescriptorType fd_type;
2616  if(FmsFieldDescriptorGetType(fd, &fd_type)) {
2617  E_RETURN(5);
2618  }
2619 
2620  char *kfd_type = join_keys(key, "Type");
2621  (*io->add_int)(ctx, kfd_type, (int)fd_type);
2622  FREE(kfd_type);
2623 
2624  // Write fd fixed order
2625  FmsFieldType field_type;
2626  FmsBasisType basis_type;
2627  FmsInt fo[3];
2628  if(FmsFieldDescriptorGetFixedOrder(fd, &field_type, &basis_type, &fo[2]))
2629  E_RETURN(6);
2630  fo[0] = (FmsInt)field_type; fo[1] = (FmsInt)basis_type;
2631 
2632  char *kfield_type = join_keys(key, "FixedOrder");
2633  (*io->add_int_array)(ctx, kfield_type, fo, 3);
2634  FREE(kfield_type);
2635 
2636  // Write fd num dofs
2637  FmsInt ndofs = 0;
2638  if(FmsFieldDescriptorGetNumDofs(fd, &ndofs))
2639  E_RETURN(7);
2640 
2641  char *kndofs = join_keys(key, "NumDofs");
2642  (*io->add_int)(ctx, kndofs, ndofs);
2643  FREE(kndofs);
2644  return 0;
2645 }
2646 
2647 static int
2648 FmsIOReadFmsFieldDescriptor(FmsIOContext *ctx, FmsIOFunctions *io,
2649  const char *key, FmsIOFieldDescriptorInfo *fd_info) {
2650  int err = 0;
2651 
2652  // Get the fd's name
2653  {
2654  char *kfd_name = join_keys(key, "Name");
2655  err = (*io->get_string)(ctx, kfd_name, &fd_info->name);
2656  FREE(kfd_name);
2657  if(err)
2658  E_RETURN(1);
2659  }
2660 
2661  // Get which compoenent the fd refers to
2662  {
2663  char *kcomp_name = join_keys(key, "ComponentName");
2664  err = (*io->get_string)(ctx, kcomp_name, &fd_info->component_name);
2665  FREE(kcomp_name);
2666  if(err)
2667  E_RETURN(2);
2668  }
2669 
2670  // Get the fd type
2671  {
2672  char *kfd_type = join_keys(key, "Type");
2673  FmsInt fdt = 0;
2674  err = (*io->get_int)(ctx, kfd_type, &fdt);
2675  FREE(kfd_type);
2676  if(err)
2677  E_RETURN(3);
2678  fd_info->type = (FmsFieldDescriptorType)fdt;
2679  }
2680  // (There is not setter for fd_type, might not have to write or read)
2681 
2682  // Get FixedOrder
2683  {
2684  char *kfo = join_keys(key, "FixedOrder");
2685  FmsIntType type;
2686  FmsInt n = 0;
2687  err = (*io->get_typed_int_array)(ctx, kfo, &type, (void*)&fd_info->fixed_order,
2688  &n);
2689  FREE(kfo);
2690  // We know is is an array of FmsInts that is length 3
2691  if(err || type != FMS_UINT64 || n != 3u)
2692  E_RETURN(4);
2693  }
2694 
2695  // Get ndofs, no setter either, might not have to write or read
2696  {
2697  char *kndofs = join_keys(key, "NumDofs");
2698  err = (*io->get_int)(ctx, kndofs, &fd_info->num_dofs);
2699  FREE(kndofs);
2700  if(err)
2701  E_RETURN(5);
2702  }
2703 
2704  return 0;
2705 }
2706 
2707 /**
2708 @brief Write FmsField to the output I/O context.
2709 @param ctx The context
2710 @param io The I/O functions that operate on the context.
2711 @param key The key that identifies the data in the output.
2712 @param field The FMS field.
2713 @return 0 on success, non-zero otherwise.
2714 */
2715 static int
2716 FmsIOWriteFmsField(FmsIOContext *ctx, FmsIOFunctions *io, const char *key,
2717  FmsField field) {
2718  const char *field_name;
2719  if(FmsFieldGetName(field, &field_name))
2720  E_RETURN(1);
2721 
2722  char *kfield_name = join_keys(key, "Name");
2723  (*io->add_string)(ctx, kfield_name, field_name);
2724  FREE(kfield_name);
2725 
2726  FmsFieldDescriptor fd = NULL;
2727  FmsInt num_vec_comp = 0;
2729  const void *data;
2730  if(FmsFieldGet(field, &fd, &num_vec_comp, &lt, &dt, &data))
2731  E_RETURN(2);
2732 
2733  char *klt = join_keys(key, "LayoutType");
2734  (*io->add_int)(ctx, klt, (FmsInt)lt);
2735  FREE(klt);
2736 
2737  char *knc = join_keys(key, "NumberOfVectorComponents");
2738  (*io->add_int)(ctx, knc, num_vec_comp);
2739  FREE(knc);
2740 
2741  /* Write field descriptor */
2742  if(!fd)
2743  E_RETURN(3);
2744  const char *fdname = NULL;
2745  if(FmsFieldDescriptorGetName(fd, &fdname))
2746  E_RETURN(4);
2747  char *kfdname = join_keys(key, "FieldDescriptorName");
2748  (*io->add_string)(ctx, kfdname, fdname);
2749  FREE(kfdname);
2750 
2751  FmsInt ndofs = 0;
2752  FmsFieldDescriptorGetNumDofs(fd, &ndofs);
2753 
2754  /* Write data */
2755  char *kdata = join_keys(key, "Data");
2756  (*io->add_scalar_array)(ctx, kdata, dt, data, num_vec_comp * ndofs);
2757  FREE(kdata);
2758 
2759  /* Write metadata */
2760  FmsMetaData md;
2761  if(FmsFieldGetMetaData(field, &md))
2762  E_RETURN(5);
2763  if(md) {
2764  char *kmd = join_keys(key, "MetaData");
2765  FmsIOWriteFmsMetaData(ctx, io, kmd, md);
2766  FREE(kmd);
2767  }
2768 
2769  return 0;
2770 }
2771 
2772 static int
2773 FmsIOReadFmsField(FmsIOContext *ctx, FmsIOFunctions *io, const char *key,
2774  FmsIOFieldInfo *field_info) {
2775  int err = 0;
2776 
2777  // Get Field name
2778  {
2779  char *kfield_name = join_keys(key, "Name");
2780  err = (*io->get_string)(ctx, kfield_name, &field_info->name);
2781  FREE(kfield_name);
2782  if(err)
2783  E_RETURN(1);
2784  }
2785 
2786  // Get layout type
2787  {
2788  char *klt = join_keys(key, "LayoutType");
2789  FmsInt lt = 0;
2790  err = (*io->get_int)(ctx, klt, &lt);
2791  FREE(klt);
2792  if(err)
2793  E_RETURN(2);
2794  field_info->layout = (FmsLayoutType)lt;
2795  }
2796 
2797  // Get Num vec components
2798  {
2799  char *knum_vec_comps = join_keys(key, "NumberOfVectorComponents");
2800  err = (*io->get_int)(ctx, knum_vec_comps, &field_info->num_vec_comps);
2801  FREE(knum_vec_comps);
2802  if(err)
2803  E_RETURN(3);
2804  }
2805 
2806  // Get field descriptor name
2807  {
2808  char *kfd_name = join_keys(key, "FieldDescriptorName");
2809  err = (*io->get_string)(ctx, kfd_name, &field_info->fd_name);
2810  FREE(kfd_name);
2811  if(err)
2812  E_RETURN(4);
2813  }
2814 
2815  // Get scalar data
2816  {
2817  char *kdata = join_keys(key, "Data");
2818  err = (*io->get_scalar_array)(ctx, kdata, &field_info->data_type,
2819  &field_info->data, &field_info->data_size);
2820  FREE(kdata);
2821  if(err)
2822  E_RETURN(5);
2823  }
2824 
2825  // Check for MetaData
2826  {
2827  char *kmd = join_keys(key, "MetaData");
2828  if((*io->has_path)(ctx, kmd)) {
2829  field_info->md = calloc(sizeof(FmsIOMetaDataInfo), 1);
2830  err = FmsIOReadFmsMetaData(ctx, io, kmd, field_info->md);
2831  }
2832  FREE(kmd);
2833  if(err)
2834  E_RETURN(6);
2835  }
2836  return 0;
2837 }
2838 
2839 /**
2840 @brief Write FmsDataCollection to the output I/O context.
2841 @param ctx The context
2842 @param io The I/O functions that operate on the context.
2843 @param key The key that identifies the data in the output.
2844 @param dc The FMS data collection.
2845 @return 0 on success, non-zero otherwise.
2846 */
2847 static int
2848 FmsIOWriteFmsDataCollection(FmsIOContext *ctx, FmsIOFunctions *io,
2849  const char *key,
2850  FmsDataCollection dc) {
2851  int err = 0;
2852  FmsMesh mesh;
2853  FmsFieldDescriptor *fds = NULL;
2854  FmsField *fields;
2855  FmsMetaData md;
2856  FmsInt num_fds = 0, num_fields = 0;
2857  FmsInt i;
2858  const char *name = NULL;
2859 
2860  /** NOTE: FmsDataCollection does not provide a method to get the name. We need one. */
2861  if(FmsDataCollectionGetName(dc, &name) == 0) {
2862  char *n_key = join_keys(key, "Name");
2863  err = (*io->add_string)(ctx, n_key, name);
2864  FREE(n_key);
2865  if(err)
2866  E_RETURN(1);
2867  }
2868 
2869  if(FmsDataCollectionGetFieldDescriptors(dc, &fds, &num_fds) == 0) {
2870  char *fd_key = NULL, *nfds_key = NULL;
2871 
2872  nfds_key = join_keys(key, "NumberOfFieldDescriptors");
2873  if((*io->add_int)(ctx, nfds_key, num_fds) != 0) {
2874  FREE(nfds_key);
2875  E_RETURN(2);
2876  }
2877  FREE(nfds_key);
2878 
2879  fd_key = join_keys(key, "FieldDescriptors");
2880  for(i = 0; i < num_fds && err == 0; ++i) {
2881  char tmp[20], *fdi_key = NULL;
2882  sprintf(tmp, "%d", (int)i);
2883  fdi_key = join_keys(fd_key, tmp);
2884 
2885  /* Writing DataCollection/FieldDescriptors/0/... */
2886  err = FmsIOWriteFmsFieldDescriptor(ctx, io, fdi_key, fds[i]);
2887 
2888  FREE(fdi_key);
2889  }
2890 
2891  FREE(fd_key);
2892  if(err)
2893  E_RETURN(3);
2894  } else {
2895  E_RETURN(4);
2896  }
2897 
2898  if(FmsDataCollectionGetFields(dc, &fields, &num_fields) == 0) {
2899  char *f_key = NULL, *nfs_key = NULL;
2900  nfs_key = join_keys(key, "NumberOfFields");
2901  if((*io->add_int)(ctx, nfs_key, num_fields) != 0) {
2902  FREE(nfs_key);
2903  E_RETURN(5);
2904  }
2905  FREE(nfs_key);
2906 
2907  f_key = join_keys(key, "Fields");
2908  for(i = 0; i < num_fields && err == 0; ++i) {
2909  char tmp[20], *fi_key = NULL;
2910  sprintf(tmp, "%d", (int)i);
2911  fi_key = join_keys(f_key, tmp);
2912 
2913  err = FmsIOWriteFmsField(ctx, io, fi_key, fields[i]);
2914 
2915  FREE(fi_key);
2916  }
2917 
2918  FREE(f_key);
2919  if(err)
2920  E_RETURN(6);
2921  } else {
2922  E_RETURN(7);
2923  }
2924 
2925  if(FmsDataCollectionGetMesh(dc, &mesh) == 0) {
2926  char *m_key = join_keys(key, "Mesh");
2927  err = FmsIOWriteFmsMesh(ctx, io, m_key, mesh);
2928  FREE(m_key);
2929  if(err)
2930  E_RETURN(8);
2931  } else {
2932  E_RETURN(9);
2933  }
2934 
2935  if(FmsDataCollectionGetMetaData(dc, &md) == 0) {
2936  if(md) {
2937  char *md_key = join_keys(key, "MetaData");
2938  err = FmsIOWriteFmsMetaData(ctx, io, md_key, md);
2939  FREE(md_key);
2940  if(err)
2941  E_RETURN(10);
2942  }
2943  } else {
2944  E_RETURN(11);
2945  }
2946 
2947  return 0;
2948 }
2949 
2950 static int
2951 FmsIOReadFmsDataCollection(FmsIOContext *ctx, FmsIOFunctions *io,
2952  const char *key,
2953  FmsIODataCollectionInfo *data_collection) {
2954  if(!ctx) E_RETURN(1);
2955  if(!io) E_RETURN(2);
2956  if(!key) E_RETURN(3);
2957  if(!data_collection) E_RETURN(4);
2958  int err = 0;
2959  FmsInt i = 0;
2960 
2961  // Process DataCollection's Name
2962  data_collection->name = NULL;
2963  {
2964  char *kname = join_keys(key, "Name");
2965  err = (*io->get_string)(ctx, kname, &data_collection->name);
2966  FREE(kname);
2967  if(err)
2968  E_RETURN(6);
2969  }
2970 
2971  if(!data_collection->name)
2972  E_RETURN(7);
2973 
2974  // Process FieldDescriptors
2975  data_collection->nfds = 0;
2976  data_collection->fds = NULL;
2977  {
2978  char *knfds = join_keys(key, "NumberOfFieldDescriptors");
2979  err = (*io->get_int)(ctx, knfds, &data_collection->nfds);
2980  FREE(knfds);
2981  if(err)
2982  E_RETURN(8);
2983 
2984  // Make sure there were actually any FieldDescriptors
2985  if(data_collection->nfds) {
2986  char *kfds = join_keys(key, "FieldDescriptors");
2987  data_collection->fds = calloc(sizeof(FmsIOFieldDescriptorInfo),
2988  data_collection->nfds);
2989  err = 0;
2990  for(i = 0; i < data_collection->nfds; i++) {
2991  char tmp[20], *kfdi = NULL;
2992  sprintf(tmp, "%d", (int)i);
2993  kfdi = join_keys(kfds, tmp);
2994  err |= FmsIOReadFmsFieldDescriptor(ctx, io, kfdi, &data_collection->fds[i]);
2995  FREE(kfdi);
2996  }
2997  FREE(kfds);
2998  if(err)
2999  E_RETURN(11);
3000  }
3001  }
3002 
3003  // Process Fields
3004  data_collection->nfields = 0;
3005  data_collection->fields = NULL;
3006  {
3007  char *knfs = join_keys(key, "NumberOfFields");
3008  err = (*io->get_int)(ctx, knfs, &data_collection->nfields);
3009  FREE(knfs);
3010  if(err)
3011  E_RETURN(12);
3012 
3013  // Make sure there were actually any Fields
3014  if(data_collection->nfields) {
3015  char *kfs = join_keys(key, "Fields");
3016  data_collection->fields = calloc(sizeof(FmsIOFieldInfo),
3017  data_collection->nfields);
3018  err = 0;
3019  for(i = 0; i < data_collection->nfields; i++) {
3020  char tmp[20], *kfi = NULL;
3021  sprintf(tmp, "%d", (int)i);
3022  kfi = join_keys(kfs, tmp);
3023  err |= FmsIOReadFmsField(ctx, io, kfi, &data_collection->fields[i]);
3024  FREE(kfi);
3025  }
3026  FREE(kfs);
3027  if(err)
3028  E_RETURN(13);
3029  }
3030  }
3031 
3032  // Process mesh
3033  data_collection->mesh_info = NULL;
3034  {
3035  char *kmesh = join_keys(key, "Mesh");
3036  data_collection->mesh_info = calloc(sizeof(FmsIOMeshInfo), 1);
3037  err = FmsIOReadFmsMesh(ctx, io, kmesh, data_collection->mesh_info);
3038  FREE(kmesh);
3039  if(err)
3040  E_RETURN(14);
3041  }
3042 
3043 
3044  // Process MetaData (if we have it)
3045  data_collection->md = NULL;
3046  {
3047  char *kmd = join_keys(key, "MetaData");
3048  if((*io->has_path)(ctx, kmd)) {
3049  data_collection->md = calloc(sizeof(FmsIOMetaDataInfo), 1);
3050  if(data_collection->md)
3051  err = FmsIOReadFmsMetaData(ctx, io, kmd, data_collection->md);
3052  }
3053  FREE(kmd);
3054  if(err)
3055  E_RETURN(15);
3056  }
3057 
3058  return 0;
3059 }
3060 
3061 static int
3062 FmsIOBuildFmsMetaData(FmsMetaData md, FmsIOMetaDataInfo *minfo) {
3063  if(!md) E_RETURN(1);
3064  if(!minfo) E_RETURN(2);
3065  switch(minfo->mdtype) {
3066  case FMS_INTEGER: {
3067  void *data = NULL;
3068  FmsMetaDataSetIntegers(md, minfo->name, minfo->subtype.i_type, minfo->size,
3069  &data);
3070  if(data)
3071  memcpy(data, minfo->data,
3072  FmsIntTypeSize[minfo->subtype.i_type]*minfo->size);
3073  else
3074  E_RETURN(3);
3075  break;
3076  }
3077  case FMS_SCALAR: {
3078  void *data = NULL;
3079  FmsMetaDataSetScalars(md, minfo->name, minfo->subtype.s_type, minfo->size,
3080  &data);
3081  if(data)
3082  memcpy(data, minfo->data,
3083  FmsScalarTypeSize[minfo->subtype.s_type]*minfo->size);
3084  else
3085  E_RETURN(4);
3086  break;
3087  }
3088  case FMS_STRING:
3089  FmsMetaDataSetString(md, minfo->name, (const char*)minfo->data);
3090  break;
3091  case FMS_META_DATA: {
3092  /* New scope */
3093  FmsInt i;
3094  FmsMetaData *child = NULL;
3095  FmsIOMetaDataInfo *mds = (FmsIOMetaDataInfo*)minfo->data;
3096  FmsMetaDataSetMetaData(md, minfo->name, minfo->size, &child);
3097  if(child) {
3098  for(i = 0; i < minfo->size; ++i)
3099  FmsIOBuildFmsMetaData(child[i], &mds[i]);
3100  } else
3101  E_RETURN(5);
3102  }
3103  break;
3104  default:
3105  // Corrupt mdtype
3106  E_RETURN(6);
3107  break;
3108  }
3109  return 0;
3110 }
3111 
3112 static int
3113 FmsIOBuildFmsDataCollection(FmsIODataCollectionInfo *dc_info,
3114  FmsDataCollection *dc) {
3115  if(!dc_info) E_RETURN(1);
3116  if(!dc) E_RETURN(2);
3117  if(!dc_info->mesh_info)
3118  E_RETURN(3);
3119 
3120  int err = 0;
3121  FmsMesh mesh = NULL;
3122  FmsMeshConstruct(&mesh);
3123 
3124  // Populate mesh domains
3125  const FmsInt ndomnames = dc_info->mesh_info->ndomain_names;
3126  if(ndomnames) {
3127  FmsInt i;
3128  for(i = 0; i < ndomnames; i++) {
3129  FmsInt j;
3130  FmsInt ndoms = dc_info->mesh_info->domain_names[i].ndomains;
3131  FmsDomain *doms = NULL;
3132  FmsMeshAddDomains(mesh, dc_info->mesh_info->domain_names[i].name, ndoms, &doms);
3133  for(j = 0; j < ndoms; j++) {
3134  FmsInt k = 0;
3135  FmsIODomainInfo *dinfo = &dc_info->mesh_info->domain_names[i].domains[j];
3136  const FmsInt dim = dinfo->dim;
3137  FmsDomainSetNumVertices(doms[j], dinfo->nverts);
3138  for(k = 0; k < dim; k++) {
3139  FmsIOEntityInfo *einfo = &dinfo->entities[k];
3140  FmsDomainSetNumEntities(doms[j], einfo->ent_type, einfo->type, einfo->nents);
3141  FmsDomainAddEntities(doms[j], einfo->ent_type, NULL, einfo->type, einfo->values,
3142  einfo->nents);
3143  }
3144  }
3145  }
3146  }
3147 
3148  // Populate mesh components
3149  const FmsInt ncomponents = dc_info->mesh_info->ncomponents;
3150  if(ncomponents) {
3151  FmsInt i;
3152  for(i = 0; i < ncomponents; i++) {
3153  FmsComponent comp;
3154  FmsIOComponentInfo *comp_info = &dc_info->mesh_info->components[i];
3155  FmsMeshAddComponent(mesh, comp_info->name, &comp);
3156  // TODO: Add Coordinates if they exist? How can I do that if I can't make fields yet. There is no AddCoordinates function
3157  const FmsInt nparts = comp_info->nparts;
3158  FmsInt j;
3159  for(j = 0; j < nparts; j++) {
3160  FmsIOComponentPartInfo *pinfo = &comp_info->parts[j];
3161  // Lookup domain
3162  FmsDomain *doms;
3163  if(FmsMeshGetDomainsByName(mesh, pinfo->domain_name, NULL, &doms))
3164  E_RETURN(4); // Failed to lookup the mesh off id & name
3165  FmsDomain dom = doms[pinfo->domain_id];
3166  if(pinfo->full_domain) {
3167  FmsComponentAddDomain(comp, dom);
3168  continue;
3169  } else {
3170  FmsInt part_id;
3171  FmsComponentAddPart(comp, dom, &part_id);
3172  FmsIOEntityInfo *einfo = &pinfo->entities[pinfo->part_ent_type];
3173  FmsComponentAddPartEntities(comp, part_id, einfo->ent_type,
3174  einfo->type, einfo->type, FMS_INT32, NULL, einfo->values, NULL, einfo->nents);
3175  FmsInt k;
3176  for(k = 0; k < einfo->ent_type; k++) {
3177  FmsIOEntityInfo *seinfo = &pinfo->entities[k];
3178  if(!seinfo->nents) continue;
3179  FmsComponentAddPartSubEntities(comp, part_id, seinfo->ent_type, seinfo->type,
3180  seinfo->type, seinfo->values, seinfo->nents);
3181  }
3182  }
3183  }
3184  // Add the component relations
3185  const FmsInt nrelations = comp_info->relation_size;
3186  if(nrelations) {
3187  FmsInt j;
3188  for(j = 0; j < nrelations; j++) {
3189  FmsComponentAddRelation(comp, comp_info->relation_values[j]);
3190  }
3191  }
3192  }
3193  }
3194 
3195  // Populate mesh tags
3196  const FmsInt ntags = dc_info->mesh_info->ntags;
3197  if(ntags) {
3198  FmsInt i;
3199  for(i = 0; i < ntags; i++) {
3200  FmsIOTagInfo *tinfo = &dc_info->mesh_info->tags[i];
3201  FmsTag tag = NULL;
3202  FmsMeshAddTag(mesh, tinfo->name, &tag);
3203  // Lookup component
3204  FmsInt j;
3205  for(j = 0; j < ncomponents; j++) {
3206  FmsComponent comp;
3207  const char *comp_name = NULL;
3208  FmsMeshGetComponent(mesh, j, &comp);
3209  FmsComponentGetName(comp, &comp_name);
3210  if(strcmp(comp_name, tinfo->comp_name) == 0) {
3211  FmsTagSetComponent(tag, comp);
3212  break;
3213  }
3214  }
3215  FmsTagSet(tag, tinfo->type, tinfo->type, tinfo->values, tinfo->size);
3216  if(tinfo->descr_size) {
3217  FmsTagAddDescriptions(tag, tinfo->type, tinfo->tag_values, tinfo->descriptions,
3218  tinfo->descr_size);
3219  }
3220  }
3221  }
3222 
3223  // Finalize our mesh
3224  FmsMeshFinalize(mesh);
3225  FmsMeshValidate(mesh);
3226 
3227  // Start building the data collection and adding the fields
3228  FmsDataCollectionCreate(mesh, dc_info->name, dc);
3229 
3230  // Add FieldDescriptors
3231  const FmsInt nfds = dc_info->nfds;
3232  if(nfds) {
3233  FmsInt i;
3234  for(i = 0; i < nfds; i++) {
3235  FmsIOFieldDescriptorInfo *fd_info = &dc_info->fds[i];
3236  FmsFieldDescriptor fd;
3237  FmsDataCollectionAddFieldDescriptor(*dc, fd_info->name, &fd);
3238  // Lookup Component by name
3239  FmsInt j;
3240  for(j = 0; j < ncomponents; j++) {
3241  const char *comp_name = NULL;
3242  FmsComponent comp = NULL;
3243  FmsMeshGetComponent(mesh, j, &comp);
3244  FmsComponentGetName(comp, &comp_name);
3245  if(strcmp(comp_name, fd_info->component_name) == 0) {
3247  break;
3248  }
3249  }
3250  FmsFieldDescriptorSetFixedOrder(fd, (FmsFieldType)fd_info->fixed_order[0],
3251  (FmsBasisType)fd_info->fixed_order[1],
3252  fd_info->fixed_order[2]);
3253  // TODO: Check ndofs & type against what was serialized?
3254  }
3255  }
3256 
3257  const FmsInt nfields = dc_info->nfields;
3258  if(nfields) {
3259  FmsInt i;
3260  for(i = 0; i < nfields; i++) {
3261  FmsIOFieldInfo *finfo = &dc_info->fields[i];
3262  FmsField field = NULL;
3263  FmsDataCollectionAddField(*dc, finfo->name, &field);
3264  // Lookup FieldDescriptor by name
3265  FmsInt j;
3266  FmsFieldDescriptor *fds;
3267  FmsDataCollectionGetFieldDescriptors(*dc, &fds, NULL);
3268  for(j = 0; j < nfds; j++) {
3269  const char *fd_name = NULL;
3270  FmsFieldDescriptor fd = fds[j];
3271  FmsFieldDescriptorGetName(fd, &fd_name);
3272  if(strcmp(fd_name, finfo->fd_name) == 0) {
3273  FmsFieldSet(field, fd, finfo->num_vec_comps, finfo->layout, finfo->data_type,
3274  finfo->data);
3275  }
3276  }
3277  if(finfo->md) {
3278  FmsMetaData md = NULL;
3279  FmsFieldAttachMetaData(field, &md);
3280  FmsIOBuildFmsMetaData(md, finfo->md);
3281  }
3282  }
3283  }
3284 
3285  // Now that we have everything setup we have to go back and add coordinates to components that need them
3286  if(ncomponents) {
3287  FmsInt i;
3288  for(i = 0; i < ncomponents; i++) {
3289  FmsIOComponentInfo *cinfo = &dc_info->mesh_info->components[i];
3290  // If this component doesn't have coordinates just skip it
3291  if(!cinfo->coordinates_name)
3292  continue;
3293  FmsComponent comp;
3294  FmsMeshGetComponent(mesh, i, &comp);
3295  // Lookup Coordinate field by name
3296  FmsInt j;
3297  FmsField *fields = NULL;
3298  FmsDataCollectionGetFields(*dc, &fields, NULL);
3299  for(j = 0; j < nfields; j++) {
3300  FmsField field = fields[j];
3301  const char *field_name = NULL;
3302  FmsFieldGetName(field, &field_name);
3303  if(strcmp(field_name, cinfo->coordinates_name) == 0) {
3304  FmsComponentSetCoordinates(comp, field);
3305  break;
3306  }
3307  }
3308  }
3309  }
3310 
3311  // If we have MetaData attach it
3312  if(dc_info->md) {
3313  FmsMetaData md = NULL;
3315  err = FmsIOBuildFmsMetaData(md, dc_info->md);
3316  (void)err; // TODO: error handling
3317  }
3318 
3319  return 0;
3320 }
3321 
3322 static inline int
3323 FmsIODestroyFmsIOMetaDataInfo(FmsIOMetaDataInfo *minfo) {
3324  if(!minfo) E_RETURN(1);
3325  switch(minfo->mdtype) {
3326  case FMS_INTEGER:
3327  FREE(minfo->data);
3328  break;
3329  case FMS_SCALAR:
3330  FREE(minfo->data);
3331  break;
3332  case FMS_STRING:
3333  FREE(minfo->data);
3334  break;
3335  case FMS_META_DATA: {
3336  FmsIOMetaDataInfo *mds = (FmsIOMetaDataInfo*)minfo->data;
3337  for(FmsInt i = 0; i < minfo->size; i++) {
3338  FmsIODestroyFmsIOMetaDataInfo(&mds[i]);
3339  }
3340  FREE(minfo->data);
3341  break;
3342  }
3343  default:
3344  // Corrupt mdtype
3345  E_RETURN(2);
3346  break;
3347  }
3348  return 0;
3349 }
3350 
3351 // Just used to make sure everything is zero-initialized
3352 static int
3353 FmsIOConstructFmsIODataCollectionInfo(FmsIODataCollectionInfo **dc_info) {
3354  if(!dc_info) E_RETURN(1);
3355  *dc_info = calloc(sizeof(FmsIODataCollectionInfo), 1);
3356  if(!*dc_info) E_RETURN(2);
3357  return 0;
3358 }
3359 
3360 static int
3361 FmsIODestroyFmsIODataCollectionInfo(FmsIODataCollectionInfo *dc_info) {
3362  if(!dc_info) E_RETURN(1);
3363 
3364  // Destroy DomainNameInfos & DomainInfos
3365  const FmsInt ndomnames = dc_info->mesh_info->ndomain_names;
3366  if(ndomnames) {
3367  FmsInt i;
3368  for(i = 0; i < ndomnames; i++) {
3369  FmsInt j;
3370  FmsInt ndoms = dc_info->mesh_info->domain_names[i].ndomains;
3371  for(j = 0; j < ndoms; j++) {
3372  FmsInt k = 0;
3373  FmsIODomainInfo *dinfo = &dc_info->mesh_info->domain_names[i].domains[j];
3374  const FmsInt dim = dinfo->dim;
3375  for(k = 0; k < dim; k++) {
3376  FmsIOEntityInfo *einfo = &dinfo->entities[k];
3377  FREE(einfo->values);
3378  // FREE(einfo); // It's a 1-D array
3379  }
3380  FREE(dinfo->entities);
3381  }
3382  FREE(dc_info->mesh_info->domain_names[i].domains);
3383  }
3384  FREE(dc_info->mesh_info->domain_names);
3385  }
3386 
3387  // Destroy ComponentInfos
3388  const FmsInt ncomponents = dc_info->mesh_info->ncomponents;
3389  if(ncomponents) {
3390  FmsInt i;
3391  for(i = 0; i < ncomponents; i++) {
3392  FmsIOComponentInfo *comp_info = &dc_info->mesh_info->components[i];
3393  const FmsInt nparts = comp_info->nparts;
3394  FmsInt j;
3395  for(j = 0; j < nparts; j++) {
3396  FmsIOComponentPartInfo *pinfo = &comp_info->parts[j];
3397  FmsInt k;
3398  for(k = 0; k < FMS_NUM_ENTITY_TYPES; k++) {
3399  if(pinfo->entities[k].nents)
3400  FREE(pinfo->entities[k].values);
3401  }
3402  }
3403  FREE(comp_info->parts);
3404  // Add the component relations
3405  const FmsInt nrelations = comp_info->relation_size;
3406  if(nrelations) {
3407  FREE(comp_info->relation_values);
3408  }
3409  }
3410  FREE(dc_info->mesh_info->components);
3411  }
3412 
3413  // Destroy TagInfos
3414  const FmsInt ntags = dc_info->mesh_info->ntags;
3415  if(ntags) {
3416  FmsInt i;
3417  for(i = 0; i < ntags; i++) {
3418  FmsIOTagInfo *tinfo = &dc_info->mesh_info->tags[i];
3419  FREE(tinfo->values);
3420  FREE(tinfo->tag_values);
3421  FREE(tinfo->descriptions);
3422  }
3423  FREE(dc_info->mesh_info->tags);
3424  }
3425 
3426  FREE(dc_info->mesh_info->partition_info);
3427  FREE(dc_info->mesh_info);
3428 
3429  // Add FieldDescriptors
3430  const FmsInt nfds = dc_info->nfds;
3431  if(nfds) {
3432  FmsInt i;
3433  for(i = 0; i < nfds; i++) {
3434  FmsIOFieldDescriptorInfo *fd_info = &dc_info->fds[i];
3435  FREE(fd_info->fixed_order);
3436  }
3437  FREE(dc_info->fds);
3438  }
3439 
3440  const FmsInt nfields = dc_info->nfields;
3441  if(nfields) {
3442  FmsInt i;
3443  for(i = 0; i < nfields; i++) {
3444  FmsIOFieldInfo *finfo = &dc_info->fields[i];
3445  FREE(finfo->data);
3446  if(finfo->md) {
3447  FmsIODestroyFmsIOMetaDataInfo(finfo->md);
3448  FREE(finfo->md);
3449  }
3450  }
3451  FREE(dc_info->fields);
3452  }
3453 
3454  // If we have MetaData destroy it
3455  if(dc_info->md) {
3456  FmsIODestroyFmsIOMetaDataInfo(dc_info->md);
3457  FREE(dc_info->md);
3458  }
3459 
3460  FREE(dc_info);
3461 
3462  return 0;
3463 }
3464 
3465 
3466 /*****************************************************************************
3467 *** FMS Public Functions
3468 *****************************************************************************/
3469 
3470 int
3471 FmsIOWrite(const char *filename, const char *protocol, FmsDataCollection dc) {
3472  FmsIOContext ctx;
3473  FmsIOFunctions io;
3474 
3475  if(filename == NULL) E_RETURN(1);
3476  if(protocol == NULL) protocol = "ascii";
3477  if(!dc) E_RETURN(3);
3478 
3479 #ifdef FMS_HAVE_CONDUIT
3480  int isSupported = CheckProtocolSupportConduit(protocol);
3481  if(isSupported == 1) {
3482  FmsIOContextInitializeConduit(&ctx, protocol);
3483  FmsIOFunctionsInitializeConduit(&io);
3484  } else if(isSupported == 2) {
3485  FmsIOContextInitialize(&ctx);
3486  FmsIOFunctionsInitialize(&io);
3487  } else if(isSupported == 0) {
3488  // fprintf(stderr, "The protocol %s is not supported by this Conduit runtime.", protocol);
3489  return 2;
3490  } else {
3491  E_RETURN(4);
3492  }
3493 #else
3494  FmsIOContextInitialize(&ctx);
3495  FmsIOFunctionsInitialize(&io);
3496 #endif
3497 
3498  /* "open" the file. */
3499  if((*io.open)(&ctx, filename, "wt") == 0) {
3500  // FMS format version of this writer: 100 = v0.1
3501  const FmsInt fms_format_version = 100;
3502  if((*io.add_int)(&ctx, "FMS", fms_format_version) != 0) {
3503  /* "close" the file. */
3504  (*io.close)(&ctx);
3505  E_RETURN(6);
3506  }
3507 
3508  if(FmsIOWriteFmsDataCollection(&ctx, &io, "DataCollection", dc) != 0) {
3509  /* "close" the file. */
3510  (*io.close)(&ctx);
3511  E_RETURN(7);
3512  }
3513 
3514  if((*io.close)(&ctx) != 0)
3515  E_RETURN(8);
3516  } else {
3517  E_RETURN(5);
3518  }
3519 
3520  return 0;
3521 }
3522 
3523 int
3524 FmsIORead(const char *filename, const char *protocol, FmsDataCollection *dc) {
3525  FmsIOContext ctx;
3526  FmsIOFunctions io;
3527 
3528  if(!filename) E_RETURN(1);
3529  if(!dc) E_RETURN(3);
3530 
3531 #ifdef FMS_HAVE_CONDUIT
3532  /* Since we have Conduit, we want to distinguish between a file written
3533  using Conduit and one written using the normal ASCII FmsIO routines.
3534  */
3535  if(protocol == NULL) {
3536  unsigned char H[4]= {'\0','\0','\0','\0'};
3537  FILE *f = fopen(filename, "rb");
3538  if(f != NULL) {
3539  if(fread(H, sizeof(unsigned char), 4, f) == 4) {
3540  if(H[0] == 'F' && H[1] == 'M' && H[2] == 'S' && H[3] == ':')
3541  protocol = "ascii";
3542  else if(H[0] == '\n' && H[1] == '{')
3543  protocol = "json";
3544  else if(H[0] == '\n' && H[1] == 'F' && H[2] == 'M' && H[3] == 'S')
3545  protocol = "yaml";
3546  else if(H[0] == 137 && H[1] == 'H' && H[2] == 'D' && H[3] == 'F')
3547  protocol = "hdf5";
3548  else {
3549  // Maybe it's conduit_bin, which would have a supporting filename + "_json" file
3550  const char *ext = "_json";
3551  const size_t fname_len = strlen(filename);
3552  const size_t json_fname_size = fname_len + strlen(ext) + 1;
3553  char *json_fname = malloc(sizeof(char) * json_fname_size);
3554  strncpy(json_fname, filename, fname_len+1);
3555  strcat(json_fname, ext);
3556  FILE *json_f = fopen(json_fname, "r");
3557  if(json_f) {
3558  fclose(json_f);
3559  protocol = "conduit_bin";
3560  }
3561  free(json_fname);
3562  }
3563  }
3564  fclose(f);
3565  }
3566  if(protocol == NULL) {
3567  /* We have to guess. */
3568  protocol = "ascii";
3569  }
3570  }
3571 
3572  int isSupported = CheckProtocolSupportConduit(protocol);
3573  if(isSupported == 1) {
3574  FmsIOContextInitializeConduit(&ctx, protocol);
3575  FmsIOFunctionsInitializeConduit(&io);
3576  } else if(isSupported == 2) {
3577  FmsIOContextInitialize(&ctx);
3578  FmsIOFunctionsInitialize(&io);
3579  } else if(isSupported == 0) {
3580  // fprintf(stderr, "The protocol %s is not supported by this Conduit runtime.\n", protocol);
3581  return 2;
3582  } else {
3583  E_RETURN(5);
3584  }
3585 #else
3586  (void)protocol;
3587  FmsIOContextInitialize(&ctx);
3588  FmsIOFunctionsInitialize(&io);
3589 #endif
3590 
3591  /* "open" the file. */
3592  if((*io.open)(&ctx, filename, "r") == 0) {
3593  int err = 0;
3594  FmsInt version = 0;
3595  FmsIODataCollectionInfo *dc_info;
3596  FmsIOConstructFmsIODataCollectionInfo(&dc_info);
3597  // FMS format version of this reader: 100 = v0.1
3598  const FmsInt fms_format_version = 100;
3599  err = (*io.get_int)(&ctx, "FMS", &version);
3600  if(err != 0 || version != fms_format_version) {
3601  /* "close" the file. */
3602  (*io.close)(&ctx);
3603  E_RETURN(6);
3604  }
3605 
3606  if(FmsIOReadFmsDataCollection(&ctx, &io, "DataCollection", dc_info) != 0) {
3607  /* "close" the file. */
3608  FmsIODestroyFmsIODataCollectionInfo(dc_info);
3609  (*io.close)(&ctx);
3610  E_RETURN(7);
3611  }
3612 
3613  FmsIOBuildFmsDataCollection(dc_info, dc);
3614  FmsIODestroyFmsIODataCollectionInfo(dc_info);
3615 
3616  if((*io.close)(&ctx) != 0) {
3617  E_RETURN(8);
3618  }
3619  } else {
3620  E_RETURN(4);
3621  }
3622  return 0;
3623 }
Definition: fms.h:50
FmsFieldType
TODO: dox.
Definition: fms.h:348
Definition: fms.h:53
int FmsComponentAddPartEntities(FmsComponent comp, FmsInt part_id, FmsEntityType type, FmsIntType id_store_type, FmsIntType ent_id_type, FmsIntType orient_type, const FmsOrientation *inv_orient_map, const void *ents, const void *ent_orients, FmsInt num_ents)
TODO: dox.
Definition: fms.c:1504
int FmsComponentGetNumParts(FmsComponent comp, FmsInt *num_parts)
TODO: dox.
Definition: fms.c:2671
int FmsGetMetaDataTypeFromName(const char *const name, FmsMetaDataType *type)
Convert a meta-data-type string to FmsMetaDataType value.
Definition: fms.c:947
int FmsIOWrite(const char *filename, const char *protocol, FmsDataCollection dc)
Writes the provided FmsDataCollection to a file.
Definition: fmsio.c:3471
FmsBasisType
TODO: dox.
Definition: fms.h:357
#define READ_ARRAY_DATA(DEST_T, FUNC)
Definition: fms.h:325
int FmsDomainGetDimension(FmsDomain domain, FmsInt *dim)
Return the highest dimension of an entry in a mesh domain.
Definition: fms.c:2264
int FmsMeshGetDomainsByName(FmsMesh mesh, const char *domain_name, FmsInt *num_domains, FmsDomain **domains)
TODO: dox.
Definition: fms.c:2200
int FmsComponentGetName(FmsComponent comp, const char **comp_name)
Return the name of a mesh component.
Definition: fms.c:2659
Definition: fms.h:48
int FmsMeshFinalize(FmsMesh mesh)
TODO: dox.
Definition: fms.c:980
int FmsTagSetComponent(FmsTag tag, FmsComponent comp)
TODO: dox.
Definition: fms.c:1651
int FmsTagGetName(FmsTag tag, const char **tag_name)
TODO: dox.
Definition: fms.c:2733
int FmsDataCollectionGetMetaData(FmsDataCollection dc, FmsMetaData *mdata)
TODO: dox.
Definition: fms.c:2802
int FmsComponentAddPartSubEntities(FmsComponent comp, FmsInt part_id, FmsEntityType type, FmsIntType id_store_type, FmsIntType ent_id_type, const void *ents, FmsInt num_ents)
TODO: dox Similar to FmsComponentAddPartEntities() but for lower dimensional entities.
Definition: fms.c:1577
int FmsDomainAddEntities(FmsDomain domain, FmsEntityType type, FmsEntityReordering reordering, FmsIntType ent_id_type, const void *ents, FmsInt num_ents)
TODO: dox.
Definition: fms.c:1402
FmsIntType
TODO: dox.
Definition: fms.h:46
int FmsTagGetComponent(FmsTag tag, FmsComponent *comp)
TODO: dox.
Definition: fms.c:2739
int FmsMeshGetNumTags(FmsMesh mesh, FmsInt *num_tags)
TODO: dox.
Definition: fms.c:2236
int FmsMeshGetComponent(FmsMesh mesh, FmsInt comp_id, FmsComponent *comp)
TODO: dox.
Definition: fms.c:2228
int FmsMeshGetNumDomainNames(FmsMesh mesh, FmsInt *num_domain_names)
TODO: dox.
Definition: fms.c:2177
int FmsIORead(const char *filename, const char *protocol, FmsDataCollection *dc)
Reads an FmsDataCollection from a file.
Definition: fmsio.c:3524
const char *const FmsEntityTypeNames[FMS_NUM_ENTITY_TYPES]
String representations of each entity type.
Definition: fms.c:169
#define StrToFmsInt
Definition: fmsio.c:51
int FmsComponentAddRelation(FmsComponent comp, FmsInt other_comp_id)
Describe a relation from one component to another.
Definition: fms.c:1624
FmsMetaDataType
TODO: dox.
Definition: fms.h:374
int FmsDataCollectionGetFieldDescriptors(FmsDataCollection dc, FmsFieldDescriptor **fds, FmsInt *num_fds)
TODO: dox.
Definition: fms.c:2786
struct FmsFieldDescriptor_private * FmsFieldDescriptor
TODO: dox.
Definition: fms.h:423
int FmsTagGetDescriptions(FmsTag tag, FmsIntType *tag_type, const void **tags, const char *const **tag_descr, FmsInt *num_tags)
TODO: dox.
Definition: fms.c:2754
#define FMS_ELE_PER_LINE
Definition: fmsio.c:44
int FmsMeshValidate(FmsMesh mesh)
TODO: dox.
Definition: fms.c:1094
int FmsComponentAddPart(FmsComponent comp, FmsDomain domain, FmsInt *part_id)
TODO: dox.
Definition: fms.c:1482
const char *const FmsMetaDataTypeNames[FMS_NUM_METADATA_TYPES]
Added in version: v0.2.
Definition: fms.c:203
#define FOR_EACH_SCALAR_TYPE(macro)
Definition: fmsio.c:68
struct FmsComponent_private * FmsComponent
TODO: dox.
Definition: fms.h:159
FMS file I/O functions.
int FmsMetaDataGetIntegers(FmsMetaData mdata, const char **mdata_name, FmsIntType *int_type, FmsInt *size, const void **data)
Get the contents of a meta-data structure that stores an array of integers.
Definition: fms.c:2897
#define FMS_BUFFER_SIZE
Definition: fmsio.c:488
int FmsMetaDataGetScalars(FmsMetaData mdata, const char **mdata_name, FmsScalarType *scal_type, FmsInt *size, const void **data)
Get the contents of a meta-data structure that stores an array of scalars.
Definition: fms.c:2908
Definition: fms.h:54
int FmsFieldDescriptorGetComponent(FmsFieldDescriptor fd, FmsComponent *comp)
TODO: dox.
Definition: fms.c:2821
int FmsTagSet(FmsTag tag, FmsIntType stored_tag_type, FmsIntType input_tag_type, const void *ent_tags, FmsInt num_ents)
TODO: dox.
Definition: fms.c:1658
const char *const FmsScalarTypeNames[FMS_NUM_SCALAR_TYPES]
Added in version: v0.2.
Definition: fms.c:196
FmsFieldDescriptorType
Field descriptor types supported by FMS, see FmsFieldDescriptor.
Definition: fms.h:343
int FmsDataCollectionGetName(FmsDataCollection dc, const char **name)
Get the name of the data collection.
Definition: fms.c:2772
int FmsDataCollectionAddFieldDescriptor(FmsDataCollection dc, const char *fd_name, FmsFieldDescriptor *fd)
TODO: dox.
Definition: fms.c:1808
int FmsDomainGetAllEntities(FmsDomain domain, FmsEntityType type, FmsIntType *ent_id_type, const void **ents, FmsInt *num_ents)
TODO: dox No copy, read only access to all entity definitions.
Definition: fms.c:2287
int FmsFieldAttachMetaData(FmsField field, FmsMetaData *mdata)
Make sure the meta-data structure associated with a field is allocated and return it in mdata...
Definition: fms.c:2016
struct FmsDomain_private * FmsDomain
TODO: dox.
Definition: fms.h:106
int FmsMeshConstruct(FmsMesh *mesh)
Allocate a mesh structure and initialize it to be empty.
Definition: fms.c:970
int FmsFieldGet(FmsField field, FmsFieldDescriptor *fd, FmsInt *num_vec_comp, FmsLayoutType *layout_type, FmsScalarType *data_type, const void **data)
TODO: dox.
Definition: fms.c:2866
int FmsDomainSetNumVertices(FmsDomain domain, FmsInt num_verts)
Set the number of vertices in a domain.
Definition: fms.c:1327
int FmsDomainGetNumVertices(FmsDomain domain, FmsInt *num_verts)
Get the number of vertices in a domain.
Definition: fms.c:2271
int FmsFieldDescriptorGetName(FmsFieldDescriptor fd, const char **fd_name)
TODO: dox.
Definition: fms.c:2814
int FmsDataCollectionAddField(FmsDataCollection dc, const char *field_name, FmsField *field)
TODO: dox.
Definition: fms.c:1834
int FmsDataCollectionAttachMetaData(FmsDataCollection dc, FmsMetaData *mdata)
Make sure the meta-data structure associated with a data collection is allocated and return it in mda...
Definition: fms.c:1861
uint64_t FmsInt
Type used by fms for representing and storing sizes and indices.
Definition: fms.h:43
FmsLayoutType
TODO: dox.
Definition: fms.h:368
FmsEntityType
TODO: dox.
Definition: fms.h:235
const char *const FmsIntTypeNames[FMS_NUM_INT_TYPES]
Added in version: v0.2.
Definition: fms.c:158
int FmsComponentGetRelations(FmsComponent comp, const FmsInt **rel_comps, FmsInt *num_rel_comps)
TODO: dox.
Definition: fms.c:2714
int FmsDomainGetNumEntities(FmsDomain domain, FmsEntityType type, FmsInt *num_ents)
Get the number of entities of a given type in a domain.
Definition: fms.c:2278
#define E_RETURN(code)
Definition: fmsio.c:101
int FmsMetaDataGetType(FmsMetaData mdata, FmsMetaDataType *type)
TODO: dox.
Definition: fms.c:2890
int FmsGetIntTypeFromName(const char *const name, FmsIntType *type)
Get the enum representation of an int type from the string name.
Definition: fms.c:877
int FmsFieldDescriptorGetType(FmsFieldDescriptor fd, FmsFieldDescriptorType *fd_type)
TODO: dox.
Definition: fms.c:2828
int FmsTagAddDescriptions(FmsTag tag, FmsIntType tag_type, const void *tags, const char *const *tag_descr, FmsInt num_tags)
TODO: dox.
Definition: fms.c:1705
int FmsDataCollectionCreate(FmsMesh mesh, const char *dc_name, FmsDataCollection *dc)
TODO: dox The new object, dc, assumes ownership of the mesh.
Definition: fms.c:1750
int FmsFieldSet(FmsField field, FmsFieldDescriptor fd, FmsInt num_vec_comp, FmsLayoutType layout_type, FmsScalarType data_type, const void *data)
TODO: dox The size of the data array is num_vec_comp times the number of DOFs as defined by the field...
Definition: fms.c:1985
int FmsMeshGetTag(FmsMesh mesh, FmsInt tag_id, FmsTag *tag)
TODO: dox.
Definition: fms.c:2243
#define FOR_EACH_INT_TYPE(macro)
Definition: fmsio.c:58
int FmsMetaDataSetIntegers(FmsMetaData mdata, const char *mdata_name, FmsIntType int_type, FmsInt size, void **data)
Set the contents of a meta-data structure to store an array of integers.
Definition: fms.c:2037
int FmsMetaDataGetString(FmsMetaData mdata, const char **mdata_name, const char **c_string)
Get the contents of a meta-data structure that stores a c-string.
Definition: fms.c:2919
int FmsMeshGetNumComponents(FmsMesh mesh, FmsInt *num_comp)
TODO: dox.
Definition: fms.c:2221
Definition: fms.h:51
int FmsMeshGetPartitionId(FmsMesh mesh, FmsInt *partition_id, FmsInt *num_partitions)
TODO: dox.
Definition: fms.c:2169
struct FmsTag_private * FmsTag
TODO: dox.
Definition: fms.h:176
int FmsComponentSetCoordinates(FmsComponent comp, FmsField coords)
Set the coordinates field of a component.
Definition: fms.c:1639
int FmsFieldDescriptorSetFixedOrder(FmsFieldDescriptor fd, FmsFieldType field_type, FmsBasisType basis_type, FmsInt order)
TODO: dox.
Definition: fms.c:1888
Definition: fms.h:56
struct FmsField_private * FmsField
Discrete field data type.
Definition: fms.h:435
int FmsMeshAddTag(FmsMesh mesh, const char *tag_name, FmsTag *tag)
Add a new tag to the mesh with the given name and return the new tag in tag.
Definition: fms.c:1298
#define FMS_LU
Definition: fmsio.c:47
int FmsFieldDescriptorGetNumDofs(FmsFieldDescriptor fd, FmsInt *num_dofs)
TODO: dox.
Definition: fms.c:2847
int FmsMetaDataSetString(FmsMetaData mdata, const char *mdata_name, const char *c_string)
Set the contents of a meta-data structure to store a c-string.
Definition: fms.c:2079
int FmsDomainSetNumEntities(FmsDomain domain, FmsEntityType type, FmsIntType id_store_type, FmsInt num_ents)
Allocates memory for the specified entities.
Definition: fms.c:1334
FmsScalarType
Scalar types supported by FMS: floating-point types, real and complex.
Definition: fms.h:324
Definition: fms.h:49
int FmsMetaDataGetMetaData(FmsMetaData mdata, const char **mdata_name, FmsInt *size, FmsMetaData **data)
Get the contents of a meta-data structure that stores an array of meta-data structures.
Definition: fms.c:2927
struct FmsDataCollection_private * FmsDataCollection
Data collection type: contains a mesh, discrete fileds, meta-data, etc.
Definition: fms.h:447
int FmsTagGet(FmsTag tag, FmsIntType *tag_type, const void **ent_tags, FmsInt *num_ents)
TODO: dox No copy, read only access to the entity-tag array.
Definition: fms.c:2745
#define FREE(PTR)
Definition: fmsio.c:37
int FmsFieldDescriptorSetComponent(FmsFieldDescriptor fd, FmsComponent comp)
TODO: dox.
Definition: fms.c:1882
int FmsDataCollectionGetMesh(FmsDataCollection dc, FmsMesh *mesh)
TODO: dox.
Definition: fms.c:2779
const FmsInt FmsEntityNumSides[FMS_NUM_ENTITY_TYPES]
Number of sides of the entity types.
Definition: fms.c:184
int FmsMeshAddDomains(FmsMesh mesh, const char *domain_name, FmsInt num_domains, FmsDomain **domains)
Allocates an array of domains sharing the same name, initializes them, and returns a pointer to the a...
Definition: fms.c:1211
struct FmsMesh_private * FmsMesh
TODO: dox.
Definition: fms.h:82
int FmsDomainGetName(FmsDomain domain, const char **domain_name, FmsInt *domain_id)
Return the name and id of a mesh domain.
Definition: fms.c:2256
int FmsMeshAddComponent(FmsMesh mesh, const char *comp_name, FmsComponent *comp)
Add a new empty component to the mesh with the given name and return the new component in comp...
Definition: fms.c:1270
int FmsComponentGetCoordinates(FmsComponent comp, FmsField *coords)
Return the coordinates field of a component.
Definition: fms.c:2722
int FmsComponentGetPart(FmsComponent comp, FmsInt part_id, FmsEntityType type, FmsDomain *domain, FmsIntType *ent_id_type, const void **ents, const FmsOrientation **ent_orients, FmsInt *num_ents)
TODO: dox.
Definition: fms.c:2677
int FmsFieldGetName(FmsField field, const char **field_name)
TODO: dox.
Definition: fms.c:2859
int FmsGetScalarTypeFromName(const char *const name, FmsScalarType *type)
Get the enum representation of an int type from the string name.
Definition: fms.c:903
Definition: fms.h:55
int FmsComponentAddDomain(FmsComponent comp, FmsDomain domain)
TODO: dox.
Definition: fms.c:1443
int FmsFieldDescriptorGetFixedOrder(FmsFieldDescriptor fd, FmsFieldType *field_type, FmsBasisType *basis_type, FmsInt *order)
TODO: dox.
Definition: fms.c:2836
struct FmsMetaData_private * FmsMetaData
TODO: dox.
Definition: fms.h:401
int FmsMeshGetDomains(FmsMesh mesh, FmsInt domain_name_id, const char **domain_name, FmsInt *num_domains, FmsDomain **domains)
TODO: dox.
Definition: fms.c:2184
int FmsDataCollectionGetFields(FmsDataCollection dc, FmsField **fields, FmsInt *num_fields)
TODO: dox.
Definition: fms.c:2794
int FmsMetaDataSetScalars(FmsMetaData mdata, const char *mdata_name, FmsScalarType scal_type, FmsInt size, void **data)
Set the contents of a meta-data structure to store an array of scalars.
Definition: fms.c:2058
int FmsComponentGetDimension(FmsComponent comp, FmsInt *dim)
Return the dimension of a mesh component.
Definition: fms.c:2665
int FmsGetEntityTypeFromName(const char *const name, FmsEntityType *ent_type)
Convert an entity-type string to FmsEntityType value.
Definition: fms.c:921
int FmsMetaDataSetMetaData(FmsMetaData mdata, const char *mdata_name, FmsInt size, FmsMetaData **data)
Set the contents of a meta-data structure to store an array of meta-data structures.
Definition: fms.c:2095
const size_t FmsScalarTypeSize[FMS_NUM_SCALAR_TYPES]
Definition: fms.c:192
const size_t FmsIntTypeSize[FMS_NUM_INT_TYPES]
Definition: fms.c:154
#define CASES(typename, T, format)
int FmsComponentGetNumEntities(FmsComponent comp, FmsInt *num_ents)
Return the total number of main entities across all parts in the component.
Definition: fms.c:2708
int FmsFieldGetMetaData(FmsField field, FmsMetaData *mdata)
TODO: dox.
Definition: fms.c:2878
const FmsInt FmsEntityDim[FMS_NUM_ENTITY_TYPES]
Dimensions of the entity types.
Definition: fms.c:180