FMS  v0.2
Field and Mesh Specification
fms.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 
19 // We use strdup() - this is one way to get it:
20 #define _XOPEN_SOURCE 600
21 
22 #include "fms.h"
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdio.h>
26 
27 
28 struct FmsMesh_private {
29  FmsInt num_domains; ///< Number of entries in the #domains array.
30  FmsInt num_comps; ///< Number of entries in the #comps array.
31  FmsInt num_tags; ///< Number of entries in the #tags array.
32  FmsInt partition_id; ///< A partition id.
33  FmsInt num_partitions; ///< Total number of partitions.
34  FmsDomain *domains; ///< An array of FmsDomain%s.
35  FmsComponent *comps; ///< An array of FmsComponent%s.
36  FmsTag *tags; ///< An array of FmsTag%s.
37 
38  FmsInt num_domain_names; /**< Number of entries in the #domain_names array,
39  i.e. number of unique domain names. */
40  FmsInt *domain_offsets; /**< Offsets into the #domains array to the beginning
41  of a sequence of domains that share the same
42  name; the size of this array is
43  #num_domain_names + 1. */
44  char **domain_names; ///< An array of domain names.
45 };
46 
47 struct FmsDomain_private {
48  /// Number of entities stored in the #entities and #orientstions arrays
49  FmsInt num_entities[FMS_NUM_ENTITY_TYPES];
50  /** @brief Capacity (allocated size) of the #entities and #orientstions
51  arrays, in number of entities. */
52  FmsInt entities_caps[FMS_NUM_ENTITY_TYPES];
53  /// Types of the side ids used in the arrays #entities.
54  FmsIntType side_ids_type[FMS_NUM_ENTITY_TYPES];
55  /// Mesh entities described as tuples of ids of side entities.
56  void *entities[FMS_NUM_ENTITY_TYPES];
57  /// Orientations of the side entities of all entities.
58  FmsOrientation *orientations[FMS_NUM_ENTITY_TYPES];
59  /** Pointer to the domain name stored in FmsMesh_private::domain_names. Not
60  owned. */
61  char *name;
62  /// Id of the domain.
63  FmsInt id;
64  /** Dimension of the domain, i.e. the largest dimension of an entity in the
65  domain. */
66  FmsInt dim;
67 };
68 
69 // An internal structure used by FmsComponent_private.
70 struct _FmsPart_private {
71  FmsDomain domain; // Associated domain. Not owned.
72  FmsInt num_entities[FMS_NUM_ENTITY_TYPES];
73  // Types of the entities ids used by the arrays in entities_ids.
74  FmsIntType entities_ids_type[FMS_NUM_ENTITY_TYPES];
75  void *entities_ids[FMS_NUM_ENTITY_TYPES];
76  // Orientations of the main entities relative to the entity definitions in the
77  // domain. Only the orientation for the main entities will be defined and
78  // used.
79  FmsOrientation *orientations[FMS_NUM_ENTITY_TYPES];
80 };
81 
82 struct FmsComponent_private {
83  char *name; ///< Component name. Owned.
84  FmsInt id; ///< Component id: index into the components array of its mesh.
85  FmsInt dim; ///< Dimension of the mesh component.
86  FmsInt num_main_entities; ///< Total number of main entities in all parts.
87  FmsInt num_parts;
88  FmsInt num_relations;
89  struct _FmsPart_private *parts;
90  FmsField coordinates; ///< Not owned.
91  FmsInt *relations; ///< An array of FmsComponent ids.
92 };
93 
94 struct FmsTag_private {
95  char *name; ///< Tag name. Owned.
96  FmsComponent comp; ///< The associated mesh component. Not Owned.
97  FmsInt num_tag_descriptions; ///< Number of tag descriptions.
98  FmsIntType tag_type; ///< Type of the entires of the #tags array.
99  void *tags; /**< Integer tags assciated with all main entries of the
100  associated mesh component, ordered part-by-part. */
101  void *described_tags; ///< List of tags that have descriptions.
102  char **tag_descriptions;
103 };
104 
105 struct FmsMetaData_private {
106  FmsMetaDataType md_type; ///< Type of the meta-data.
107  union {
108  FmsIntType int_type;
109  FmsScalarType scalar_type;
110  } sub_type; /// Subtype of the meta-data.
111  char *name; ///< Name of the meta-data.
112  FmsInt num_entries; ///< Number of entries in the data array.
113  void *data; ///< Meta-data array.
114 };
115 
116 // Internal type used by FmsFieldDescriptor
117 struct _FmsFieldDescriptor_FixedOrder {
118  FmsFieldType field_type;
119  FmsBasisType basis_type;
120  FmsInt order;
121 };
122 
123 struct FmsFieldDescriptor_private {
124  char *name;
125  FmsComponent component; ///< Not Owned.
126  FmsFieldDescriptorType descr_type;
127  union {
128  void *any;
129  struct _FmsFieldDescriptor_FixedOrder *fixed_order;
130  } descriptor;
131  FmsInt num_dofs;
132 };
133 
134 struct FmsField_private {
135  char *name;
136  FmsMetaData mdata;
137  FmsFieldDescriptor fd; ///< Not owned.
138  FmsInt num_vec_comp;
139  FmsLayoutType layout;
140  FmsScalarType scalar_type;
141  void *data;
142 };
143 
144 struct FmsDataCollection_private {
145  char *name;
146  FmsMetaData mdata;
147  FmsMesh mesh;
148  FmsInt num_fds;
149  FmsFieldDescriptor *fds;
150  FmsInt num_fields;
151  FmsField *fields;
152 };
153 
155  1, 2, 4, 8, 1, 2, 4, 8
156 };
157 
158 const char * const FmsIntTypeNames[FMS_NUM_INT_TYPES] = {
159  "FMS_INT8",
160  "FMS_INT16",
161  "FMS_INT32",
162  "FMS_INT64",
163  "FMS_UINT8",
164  "FMS_UINT16",
165  "FMS_UINT32",
166  "FMS_UINT64",
167 };
168 
170  "FMS_VERTEX",
171  "FMS_EDGE",
172  "FMS_TRIANGLE",
173  "FMS_QUADRILATERAL",
174  "FMS_TETRAHEDRON",
175  "FMS_HEXAHEDRON",
176  "FMS_WEDGE",
177  "FMS_PYRAMID"
178 };
179 
181  0, 1, 2, 2, 3, 3, 3, 3
182 };
183 
185  0, 2, 3, 4, 4, 6, 5, 5
186 };
187 
189  1, 2, 3, 4, 4, 8, 6, 5
190 };
191 
193  sizeof(float), sizeof(double), 2*sizeof(float), 2*sizeof(double)
194 };
195 
197  "FMS_FLOAT",
198  "FMS_DOUBLE",
199  "FMS_COMPLEX_FLOAT",
200  "FMS_COMPLEX_DOUBLE",
201 };
202 
204  "FMS_INTEGER",
205  "FMS_SCALAR",
206  "FMS_STRING",
207  "FMS_META_DATA",
208 };
209 
210 
211 /* -------------------------------------------------------------------------- */
212 /* Auxiliary macros and static functions */
213 /* -------------------------------------------------------------------------- */
214 
215 #ifdef NDEBUG
216 #define E_RETURN(code) return (code)
217 #else
218 static void FmsErrorDebug(int err_code, const char *func, const char *file,
219  int line) {
220  fprintf(stderr,
221  "\n\nFMS error encountered!\n"
222  "Error code: %d\n"
223  "Function: %s\n"
224  "File: %s:%d\n\n"
225  "Aborting ...\n\n", err_code, func, file, line);
226  abort();
227 }
228 // __PRETTY_FUNCTION__ is the same as the standard __func__ for most compilers,
229 // with the exception of clang. GCC 9.3.0 with -Wpedantic gives a warning about
230 // __PRETTY_FUNCTION__ not being standard, so we use __PRETTY_FUNCTION__ only
231 // with clang.
232 #if defined(__clang__)
233 #define FMS_PRETTY_FUNCTION __PRETTY_FUNCTION__
234 #elif !defined(_MSC_VER)
235 #define FMS_PRETTY_FUNCTION __func__
236 #else // for Visual Studio C++
237 #define FMS_PRETTY_FUNCTION __FUNCSIG__
238 #endif
239 #define E_RETURN(code) \
240  do { \
241  if (code) { \
242  FmsErrorDebug(code, FMS_PRETTY_FUNCTION, __FILE__, __LINE__); \
243  } \
244  return (code); \
245  } while (0)
246 #endif
247 
248 static int UpdateError(int old_err, int new_err) {
249  return old_err ? old_err : new_err;
250 }
251 
252 static inline FmsInt FmsIntMin(FmsInt a, FmsInt b) {
253  return (a <= b) ? a : b;
254 }
255 
256 static inline FmsInt FmsIntMax(FmsInt a, FmsInt b) {
257  return (a >= b) ? a : b;
258 }
259 
260 // Return m=2^k, k-integer, such that: m >= n > m/2
261 static inline FmsInt NextPow2(FmsInt n) {
262  FmsInt m = 1;
263  while (m < n) { m *= 2; }
264  return m;
265 }
266 
267 static void FmsAbortNotImplemented() {
268  fprintf(stderr, "\n\nNot implemented! Aborting ...\n\n");
269  abort();
270 }
271 
272 #ifndef NDEBUG
273 static void FmsInternalError() {
274  fprintf(stderr, "\n\nFMS internal error detected! Aborting ...\n\n");
275  abort();
276 }
277 #endif
278 
279 static inline int FmsCopyString(const char *str, char **str_copy_p) {
280  if (str == NULL) { *str_copy_p = NULL; return 0; }
281  char *str_copy = strdup(str);
282  if (str_copy == NULL) { return 1; }
283  *str_copy_p = str_copy;
284  return 0;
285 }
286 
287 // Macro used in FmsIntConvertCopy()
288 #define FMS_ICC_IL(src_t,src,dst_t,dst,size) \
289  do { \
290  for (FmsInt idx = 0; idx < (size); idx++) { \
291  ((dst_t*)(dst))[idx] = (dst_t)(((src_t*)(src))[idx]); \
292  } \
293  } while (0)
294 
295 // Macro used in FmsIntConvertCopy()
296 #define FMS_ICC_SW(src_type,src,dst_t,dst,size) \
297  switch (src_type) { \
298  case FMS_INT8: FMS_ICC_IL( int8_t,src,dst_t,dst,size); break; \
299  case FMS_INT16: FMS_ICC_IL( int16_t,src,dst_t,dst,size); break; \
300  case FMS_INT32: FMS_ICC_IL( int32_t,src,dst_t,dst,size); break; \
301  case FMS_INT64: FMS_ICC_IL( int64_t,src,dst_t,dst,size); break; \
302  case FMS_UINT8: FMS_ICC_IL( uint8_t,src,dst_t,dst,size); break; \
303  case FMS_UINT16: FMS_ICC_IL(uint16_t,src,dst_t,dst,size); break; \
304  case FMS_UINT32: FMS_ICC_IL(uint32_t,src,dst_t,dst,size); break; \
305  case FMS_UINT64: FMS_ICC_IL(uint64_t,src,dst_t,dst,size); break; \
306  default: FmsAbortNotImplemented(); \
307  } \
308  break
309 
310 // Copy items from one integer array to another, converting the entries.
311 static int FmsIntConvertCopy(FmsIntType src_type, const void *src,
312  FmsIntType dst_type, void *dst, FmsInt size) {
313  if (src_type >= FMS_NUM_INT_TYPES || dst_type >= FMS_NUM_INT_TYPES) {
314  E_RETURN(1);
315  }
316  switch (dst_type) {
317  case FMS_INT8: FMS_ICC_SW(src_type,src, int8_t,dst,size);
318  case FMS_INT16: FMS_ICC_SW(src_type,src, int16_t,dst,size);
319  case FMS_INT32: FMS_ICC_SW(src_type,src, int32_t,dst,size);
320  case FMS_INT64: FMS_ICC_SW(src_type,src, int64_t,dst,size);
321  case FMS_UINT8: FMS_ICC_SW(src_type,src, uint8_t,dst,size);
322  case FMS_UINT16: FMS_ICC_SW(src_type,src,uint16_t,dst,size);
323  case FMS_UINT32: FMS_ICC_SW(src_type,src,uint32_t,dst,size);
324  case FMS_UINT64: FMS_ICC_SW(src_type,src,uint64_t,dst,size);
325  default: FmsAbortNotImplemented();
326  }
327  return 0;
328 }
329 
330 // Macro used in FmsIntPermuteConvertCopy()
331 #define FMS_IPCC_IL(src_t,src,dst_t,dst,tuple_size,perm,tot_size) \
332  do { \
333  for (FmsInt i = 0; i < (tot_size); i += (tuple_size)) { \
334  src_t *loc_src = (src_t*)(src) + i; \
335  dst_t *loc_dst = (dst_t*)(dst) + i; \
336  for (FmsInt j = 0; j < (tuple_size); j++) { \
337  loc_dst[j] = (dst_t)(loc_src[perm[j]]); \
338  } \
339  } \
340  } while (0)
341 
342 // Macro used in FmsIntPermuteConvertCopy()
343 #define FMS_IPCC_SW(src_type,src,dst_t,dst,ts,perm,size) \
344  switch (src_type) { \
345  case FMS_INT8: FMS_IPCC_IL( int8_t,src,dst_t,dst,ts,perm,size); break; \
346  case FMS_INT16: FMS_IPCC_IL( int16_t,src,dst_t,dst,ts,perm,size); break; \
347  case FMS_INT32: FMS_IPCC_IL( int32_t,src,dst_t,dst,ts,perm,size); break; \
348  case FMS_INT64: FMS_IPCC_IL( int64_t,src,dst_t,dst,ts,perm,size); break; \
349  case FMS_UINT8: FMS_IPCC_IL( uint8_t,src,dst_t,dst,ts,perm,size); break; \
350  case FMS_UINT16: FMS_IPCC_IL(uint16_t,src,dst_t,dst,ts,perm,size); break; \
351  case FMS_UINT32: FMS_IPCC_IL(uint32_t,src,dst_t,dst,ts,perm,size); break; \
352  case FMS_UINT64: FMS_IPCC_IL(uint64_t,src,dst_t,dst,ts,perm,size); break; \
353  default: FmsAbortNotImplemented(); \
354  } \
355  break
356 
357 // Copy items from one integer array to another, converting the entries and
358 // permuting the entries within tuples of given size.
359 static int FmsIntPermuteConvertCopy(FmsIntType src_type, const void *src,
360  FmsIntType dst_type, void *dst,
361  const int *perm, FmsInt tuple_size,
362  FmsInt tot_size) {
363  if (src_type >= FMS_NUM_INT_TYPES || dst_type >= FMS_NUM_INT_TYPES) {
364  E_RETURN(1);
365  }
366  if (tuple_size == 0 || tot_size % tuple_size != 0) { E_RETURN(2); }
367  const FmsInt ts = tuple_size;
368  switch (dst_type) {
369  case FMS_INT8: FMS_IPCC_SW(src_type,src, int8_t,dst,ts,perm,tot_size);
370  case FMS_INT16: FMS_IPCC_SW(src_type,src, int16_t,dst,ts,perm,tot_size);
371  case FMS_INT32: FMS_IPCC_SW(src_type,src, int32_t,dst,ts,perm,tot_size);
372  case FMS_INT64: FMS_IPCC_SW(src_type,src, int64_t,dst,ts,perm,tot_size);
373  case FMS_UINT8: FMS_IPCC_SW(src_type,src, uint8_t,dst,ts,perm,tot_size);
374  case FMS_UINT16: FMS_IPCC_SW(src_type,src,uint16_t,dst,ts,perm,tot_size);
375  case FMS_UINT32: FMS_IPCC_SW(src_type,src,uint32_t,dst,ts,perm,tot_size);
376  case FMS_UINT64: FMS_IPCC_SW(src_type,src,uint64_t,dst,ts,perm,tot_size);
377  default: FmsAbortNotImplemented();
378  }
379  return 0;
380 }
381 
382 // Macro used in FmsIntMapCopy()
383 #define FMS_IMC_IL(src_t,src,dst_t,dst,map,size) \
384  do { \
385  for (FmsInt idx = 0; idx < (size); idx++) { \
386  ((dst_t*)(dst))[idx] = ((dst_t*)(map))[((src_t*)(src))[idx]]; \
387  } \
388  } while (0)
389 
390 // Macro used in FmsIntMapCopy()
391 #define FMS_IMC_SW(src_type,src,dst_t,dst,map,size) \
392  switch (src_type) { \
393  case FMS_INT8: FMS_IMC_IL( int8_t,src,dst_t,dst,map,size); break; \
394  case FMS_INT16: FMS_IMC_IL( int16_t,src,dst_t,dst,map,size); break; \
395  case FMS_INT32: FMS_IMC_IL( int32_t,src,dst_t,dst,map,size); break; \
396  case FMS_INT64: FMS_IMC_IL( int64_t,src,dst_t,dst,map,size); break; \
397  case FMS_UINT8: FMS_IMC_IL( uint8_t,src,dst_t,dst,map,size); break; \
398  case FMS_UINT16: FMS_IMC_IL(uint16_t,src,dst_t,dst,map,size); break; \
399  case FMS_UINT32: FMS_IMC_IL(uint32_t,src,dst_t,dst,map,size); break; \
400  case FMS_UINT64: FMS_IMC_IL(uint64_t,src,dst_t,dst,map,size); break; \
401  default: FmsAbortNotImplemented(); \
402  } \
403  break
404 
405 static int FmsIntMapCopy(FmsIntType src_type, const void *src,
406  FmsIntType dst_type, void *dst, const void *map,
407  FmsInt size) {
408  if (src_type >= FMS_NUM_INT_TYPES || dst_type >= FMS_NUM_INT_TYPES) {
409  E_RETURN(1);
410  }
411  switch (dst_type) {
412  case FMS_INT8: FMS_IMC_SW(src_type,src, int8_t,dst,map,size);
413  case FMS_INT16: FMS_IMC_SW(src_type,src, int16_t,dst,map,size);
414  case FMS_INT32: FMS_IMC_SW(src_type,src, int32_t,dst,map,size);
415  case FMS_INT64: FMS_IMC_SW(src_type,src, int64_t,dst,map,size);
416  case FMS_UINT8: FMS_IMC_SW(src_type,src, uint8_t,dst,map,size);
417  case FMS_UINT16: FMS_IMC_SW(src_type,src,uint16_t,dst,map,size);
418  case FMS_UINT32: FMS_IMC_SW(src_type,src,uint32_t,dst,map,size);
419  case FMS_UINT64: FMS_IMC_SW(src_type,src,uint64_t,dst,map,size);
420  default: FmsAbortNotImplemented();
421  }
422  return 0;
423 }
424 
425 // Macro used in FmsEntitiesToSides()
426 #define FMS_E2S_TEMPL(idx_t) \
427  do { \
428  const idx_t *ents_ = (idx_t*)ents + loc_side_begin; \
429  const idx_t *sides_ = sides; \
430  for (FmsInt ent_id = 0; ent_id < num_ents; ent_id++) { \
431  const idx_t *ent_off = &ents_[ent_id*ent_sides]; \
432  FmsInt *res_ent = &res_[ent_id*res_stride]; \
433  for (FmsInt loc_off = 0; loc_off < num_loc_sides; loc_off++) { \
434  const idx_t side_id = ent_off[loc_off]; \
435  const idx_t *side = &sides_[side_id*side_sides]; \
436  FmsInt *res_side = &res_ent[loc_off*side_sides]; \
437  for (FmsInt ss_id = 0; ss_id < side_sides; ss_id++) { \
438  res_side[ss_id] = side[ss_id]; \
439  } \
440  } \
441  } \
442  } while (0); break
443 
444 // Helper function for converting entities given as tuples of side ids to
445 // tuples of tuples where the inner tuples are the tuples defining the sides of
446 // the starting entities.
447 static int FmsEntitiesToSides(FmsIntType idx_type, FmsInt ent_sides,
448  FmsInt loc_side_begin, FmsInt num_loc_sides,
449  const void *ents, FmsInt side_sides,
450  const void *sides, FmsInt res_stride,
451  FmsInt res_off, FmsInt *res, FmsInt num_ents) {
452  if (idx_type >= FMS_NUM_INT_TYPES) { E_RETURN(1); }
453  FmsInt *res_ = res + res_off;
454  switch (idx_type) {
455  case FMS_INT8: FMS_E2S_TEMPL(int8_t);
456  case FMS_INT16: FMS_E2S_TEMPL(int16_t);
457  case FMS_INT32: FMS_E2S_TEMPL(int32_t);
458  case FMS_INT64: FMS_E2S_TEMPL(int64_t);
459  case FMS_UINT8: FMS_E2S_TEMPL(uint8_t);
460  case FMS_UINT16: FMS_E2S_TEMPL(uint16_t);
461  case FMS_UINT32: FMS_E2S_TEMPL(uint32_t);
462  case FMS_UINT64: FMS_E2S_TEMPL(uint64_t);
463  default: FmsAbortNotImplemented();
464  }
465  return 0;
466 }
467 
468 static inline int FmsIntersectTwoEdges(FmsInt *edge1, FmsInt *edge2,
469  FmsInt *v_common) {
470  int num_common = 0;
471  if (edge1[0] == edge2[0] || edge1[0] == edge2[1]) {
472  *v_common = edge1[0];
473  num_common++;
474  }
475  if (edge1[0] != edge1[1]) {
476  if (edge1[1] == edge2[0] || edge1[1] == edge2[1]) {
477  *v_common = edge1[1];
478  num_common++;
479  }
480  }
481  return num_common;
482 }
483 
484 static int FmsOrientFaceSides(FmsInt num_sides, FmsInt num_faces,
485  FmsInt *face_verts,
486  FmsOrientation *orientations) {
487  // The size of 'face_verts' must be 2 x 'num_sides' x 'num_faces'.
488  // The size of 'orientations' must be 'num_sides' x 'num_faces'.
489 
490  // Find edge orientations that if applied to 'face_verts' lead to an array of
491  // the form: (a,b,b,c,c,a), for triangles, or (a,b,b,c,c,d,d,a), for quads.
492  // If one of the edge orientations cannot be uniquely determined, that edge in
493  // the 'orientations' array will remain unmodified, e.g. as initialized by the
494  // user.
495 
496  const int n = num_sides;
497  for (FmsInt k = 0; k < num_faces; k++) {
498  FmsInt nc[4], vi[4]; // at most 4 vertices/sides
499  for (int i = 0; i < n; i++) {
500  nc[i] = FmsIntersectTwoEdges(face_verts+2*((i+n-1)%n),
501  face_verts+2*i, vi+i);
502  if (nc[i] == 0) { E_RETURN(1); }
503  }
504  for (int ei = 0; ei < n; ei++) {
505  int ej = (ei+1)%n;
506  if (face_verts[2*ei+0] == face_verts[2*ei+1] ||
507  (nc[ei] != 1 && nc[ej] != 1)) {
508  // Keep the value of 'orientations[ei]' as is, e.g. as defined by the
509  // user.
510  } else {
511  if (nc[ei] == 1) {
512  orientations[ei] = (vi[ei] == face_verts[2*ei+0]) ? 0 : 1;
513  } else {
514  orientations[ei] = (vi[ej] == face_verts[2*ei+1]) ? 0 : 1;
515  }
516  }
517  }
518  face_verts += 2*n;
519  orientations += n;
520  }
521  return 0;
522 }
523 
524 static inline void Sort3(const FmsInt *a, FmsInt *s) {
525  FmsInt a0 = a[0], a1 = a[1], a2 = a[2];
526  if (a0 > a1) {
527  if (a2 <= a1) {
528  s[0] = a2;
529  s[1] = a1;
530  s[2] = a0;
531  } else {
532  s[0] = a1;
533  if (a2 < a0) {
534  s[1] = a2;
535  s[2] = a0;
536  } else {
537  s[1] = a0;
538  s[2] = a2;
539  }
540  }
541  } else { // a0 <= a1
542  if (a1 <= a2) { // already sorted
543  s[0] = a0;
544  s[1] = a1;
545  s[2] = a2;
546  } else {
547  if (a0 <= a2) {
548  s[0] = a0;
549  s[1] = a2;
550  } else {
551  s[0] = a2;
552  s[1] = a0;
553  }
554  s[2] = a1;
555  }
556  }
557 }
558 
559 static inline void Sort4(const FmsInt *a, FmsInt *s) {
560  FmsInt b0, b1, b2, b3;
561  {
562  FmsInt a0 = a[0], a1 = a[1];
563  if (a0 <= a1) {
564  b0 = a0;
565  b1 = a1;
566  } else {
567  b0 = a1;
568  b1 = a0;
569  }
570  a0 = a[2];
571  a1 = a[3];
572  if (a0 <= a1) {
573  b2 = a0;
574  b3 = a1;
575  } else {
576  b2 = a1;
577  b3 = a0;
578  }
579  }
580  if (b0 <= b2) { // b0 <= b2 <= b3, and b0 <= b1
581  s[0] = b0;
582  if (b1 <= b2) {
583  s[1] = b1;
584  s[2] = b2;
585  s[3] = b3;
586  } else {
587  s[1] = b2;
588  if (b1 <= b3) { // b0 <= b2 < b1 <= b3
589  s[2] = b1;
590  s[3] = b3;
591  } else { // b0 <= b2 <= b3 < b1
592  s[2] = b3;
593  s[3] = b1;
594  }
595  }
596  } else { // b2 < b0 <= b1, and b2 <= b3
597  s[0] = b2;
598  if (b3 <= b0) { // b2 <= b3 <= b0 <= b1
599  s[1] = b3;
600  s[2] = b0;
601  s[3] = b1;
602  } else {
603  s[1] = b0;
604  if (b3 <= b1) { // b2 < b0 < b3 <= b1
605  s[2] = b3;
606  s[3] = b1;
607  } else { // b2 < b0 <= b1 < b3
608  s[2] = b1;
609  s[3] = b3;
610  }
611  }
612  }
613 }
614 
615 // Assuming 'face1' and 'face2' are sorted
616 static inline int FmsIntersectSorted(int n1, int n2, FmsInt *face1,
617  FmsInt *face2, FmsInt *edge_common) {
618  int num_common = 0;
619  FmsInt e1 = face1[0], e2 = face2[0];
620  for (int i1 = 0, i2 = 0; 1; ) {
621  if (e1 == e2) {
622  num_common++;
623  *edge_common = e1;
624  do {
625  if (++i2 == n2) { return num_common; }
626  e2 = face2[i2];
627  } while (e1 == e2);
628  do {
629  if (++i1 == n1) { return num_common; }
630  e1 = face1[i1];
631  } while (e1 < e2);
632  } else if (e1 < e2) {
633  do {
634  if (++i1 == n1) { return num_common; }
635  e1 = face1[i1];
636  } while (e1 < e2);
637  } else { // e1 > e2
638  do {
639  if (++i2 == n2) { return num_common; }
640  e2 = face2[i2];
641  } while (e1 > e2);
642  }
643  }
644  // not reachable
645 }
646 
647 static inline FmsOrientation GetTriangleOrientation(int *ne, FmsInt *ee,
648  FmsInt *be) {
649  // For orientation definitions, see the Doxygen documentation at the
650  // definition of type FmsOrientation in fms.h.
651 
652  // To determine the orientation of a triangle we need at least two of the
653  // edges to be uniquely determined, i.e. their ne[i] to be 1.
654 
655  // Orientations will be computed relative to (be[0],be[1],be[2]).
656 
657  // If there are repetitions in 'be', the orientation is unknown.
658  if (be[0] == be[1] || be[0] == be[2] || be[1] == be[2]) {
660  }
661  if (ne[0] == 1) {
662  int i0 = 0;
663  while (ee[0] != be[i0]) {
664  i0++;
665 #ifndef NDEBUG
666  if (i0 == 3) { FmsInternalError(); }
667 #endif
668  }
669  if (ne[1] == 1) {
670  // Find the orientation of (ee[0],ee[1],*)
671  return (be[(i0+1)%3] == ee[1]) ? 2*i0 : 2*i0+1;
672  } else if (ne[2] == 1) {
673  // Find the orientation of (ee[0],*,ee[2])
674  return (be[(i0+2)%3] == ee[2]) ? 2*i0 : 2*i0+1;
675  }
676  } else if (ne[1] == 1 && ne[2] == 1) {
677  // Find the orientation of (*,ee[1],ee[2])
678  int i1 = 0;
679  while (ee[1] != be[i1]) {
680  i1++;
681 #ifndef NDEBUG
682  if (i1 == 3) { FmsInternalError(); }
683 #endif
684  }
685  if (be[(i1+1)%3] == ee[2]) {
686  static const FmsOrientation oo[3] = { 4, 0, 2 };
687  return oo[i1];
688  } else {
689  static const FmsOrientation oo[3] = { 3, 5, 1 };
690  return oo[i1];
691  }
692  }
694 }
695 
696 static inline FmsOrientation GetQuadOrientation(int *ne, FmsInt *ee,
697  FmsInt *be, FmsInt *se) {
698  // For orientation definitions, see the Doxygen documentation at the
699  // definition of type FmsOrientation in fms.h.
700 
701  // To determine the orientation of a quad we need at least two consecutive of
702  // its edges to be uniquely determined, i.e. their ne[i] to be 1.
703 
704  // Orientations will be computed relative to (be[0],be[1],be[2],be[3]).
705 
706  // If there are repeated edge indices in 'be' (or in its sorted version 'se')
707  // then treat the orientation as unknown, even though it still may be possible
708  // to determine the orientation.
709  if (se[0] == se[1] || se[1] == se[2] || se[2] == se[3]) {
711  }
712  // For now, if not all edges are uniquely deterined, i.e. ne[i] is not 1 for
713  // some i, then treat the orientation as unknown, even though it still may be
714  // possible to determine the orientation.
715  if (ne[0] != 1 || ne[1] != 1 || ne[2] != 1 || ne[3] != 1) {
717  }
718  int i0 = 0;
719  while (ee[0] != be[i0]) {
720  i0++;
721 #ifndef NDEBUG
722  if (i0 == 4) { FmsInternalError(); }
723 #endif
724  }
725  // Find the orientation of (ee[0],ee[1],*,*)
726  return (be[(i0+1)%4] == ee[1]) ? 2*i0 : 2*i0+1;
727 }
728 
729 static int FmsOrientTetSides(FmsInt num_tets, FmsInt *tet_edges,
730  FmsOrientation *orientations) {
731  for (FmsInt i = 0; i < num_tets; i++) {
732  FmsInt tet_edges_sorted[4][3];
733  for (int loc_face_id = 0; loc_face_id < 4; loc_face_id++) {
734  Sort3(tet_edges+3*loc_face_id, tet_edges_sorted[loc_face_id]);
735  }
736  int nc[6];
737  FmsInt ei[6];
738 
739  // Array describing the tet edges as intersections of two tet faces.
740  // For the definitions of the faces and edges, see the diagram in fms.h.
741  static const int tet_edge_face[6][2] = {
742  // a=A^B b=A^D c=A^C d=B^C e=B^D f=C^D
743  // A=0, B=1, C=2, D=3
744  {0, 1}, {0, 3}, {0, 2}, {1, 2}, {1, 3}, {2, 3}
745  };
746  // Array describing the tet faces through their edges.
747  // For the definitions of the faces and edges, see the diagram in fms.h.
748  static const int tet_face_edge[4][3] = {
749  // a=0, b=1, c=2, d=3, e=4, f=5
750  {0, 2, 1}, {0, 4, 3}, {2, 3, 5}, {1, 5, 4}
751  };
752 
753  // Intersect the faces to find the edges
754  for (int i = 0; i < 6; i++) {
755  const int *f = tet_edge_face[i];
756  nc[i] = FmsIntersectSorted(3, 3, tet_edges_sorted[f[0]],
757  tet_edges_sorted[f[1]], ei+i);
758  if (nc[i] == 0) { E_RETURN(1); }
759  }
760 
761  // Determine side orientations
762  for (int loc_face_id = 0; loc_face_id < 4; loc_face_id++) {
763  const int *e = tet_face_edge[loc_face_id];
764  int ne[3] = { nc[e[0]], nc[e[1]], nc[e[2]] };
765  FmsInt ee[3] = { ei[e[0]], ei[e[1]], ei[e[2]] };
766  FmsInt *be = tet_edges+3*loc_face_id;
767  // Orientations will be computed relative to (be[0],be[1],be[2])
768  FmsOrientation ori = GetTriangleOrientation(ne, ee, be);
769  if (ori != FMS_ORIENTATION_UNKNOWN) {
770  orientations[loc_face_id] = ori;
771  } else {
772  // The orientation of this face is unknown, so leave the value of
773  // 'orientations[loc_face_id]' unmodified, e.g. as set by the user.
774  }
775  }
776  tet_edges += 12;
777  orientations += 4;
778  }
779  return 0;
780 }
781 
782 static int FmsOrientHexSides(FmsInt num_hexes, FmsInt *hex_edges,
783  FmsOrientation *orientations) {
784  for (FmsInt i = 0; i < num_hexes; i++) {
785  FmsInt hex_edges_sorted[6][4];
786  for (int loc_face_id = 0; loc_face_id < 6; loc_face_id++) {
787  Sort4(hex_edges+4*loc_face_id, hex_edges_sorted[loc_face_id]);
788  }
789  int nc[12];
790  FmsInt ei[12];
791 
792  // Array describing the hex edges as intersections of two hex faces.
793  // For the definitions of the faces and edges, see the diagram in fms.h.
794  static const int hex_edge_face[12][2] = {
795  // a=A^C b=A^F c=A^D d=A^E e=B^C f=B^F
796  // g=B^D h=B^E i=C^E j=C^F k=D^F l=D^E
797  // A=0, B=1, C=2, D=3, E=4, F=5
798  {0, 2}, {0, 5}, {0, 3}, {0, 4}, {1, 2}, {1, 5},
799  {1, 3}, {1, 4}, {2, 4}, {2, 5}, {3, 5}, {3, 4}
800  };
801  // Array describing the hex faces through their edges.
802  // For the definitions of the faces and edges, see the diagram in fms.h.
803  static const int hex_face_edge[6][4] = {
804  // a=0, b=1, c=2, d=3, e=4, f=5, g=6, h=7, i=8, j=9, k=10, l=11
805  {0, 3, 2, 1}, {4, 5, 6, 7}, {0, 9, 4, 8},
806  {2, 11, 6, 10}, {3, 8, 7, 11}, {1, 10, 5, 9}
807  };
808 
809  // Intersect the faces to find the edges
810  for (int i = 0; i < 12; i++) {
811  const int *f = hex_edge_face[i];
812  nc[i] = FmsIntersectSorted(4, 4, hex_edges_sorted[f[0]],
813  hex_edges_sorted[f[1]], ei+i);
814  if (nc[i] == 0) { E_RETURN(1); }
815  }
816 
817  // Determine side orientations
818  for (int loc_face_id = 0; loc_face_id < 6; loc_face_id++) {
819  const int *e = hex_face_edge[loc_face_id];
820  int ne[4] = { nc[e[0]], nc[e[1]], nc[e[2]], nc[e[3]] };
821  FmsInt ee[4] = { ei[e[0]], ei[e[1]], ei[e[2]], ei[e[3]] };
822  FmsInt *be = hex_edges+4*loc_face_id;
823  // Orientations will be computed relative to (be[0],be[1],be[2],be[3])
824  FmsOrientation ori =
825  GetQuadOrientation(ne, ee, be, hex_edges_sorted[loc_face_id]);
826  if (ori != FMS_ORIENTATION_UNKNOWN) {
827  orientations[loc_face_id] = ori;
828  } else {
829  // The orientation of this face is unknown, so leave the value of
830  // 'orientations[loc_face_id]' unmodified, e.g. as set by the user.
831  }
832  }
833  hex_edges += 24;
834  orientations += 6;
835  }
836  return 0;
837 }
838 
839 // Permute the edges/vertices of a triangle according to a given orientation.
840 // Note that the permutation arrays for the edges and the vertices are the same.
841 static inline void FmsPermuteTriBdr(FmsOrientation ori, const FmsInt *e_in,
842  FmsInt *e_out) {
843  static const int tri_perm[6][3] = {
844  {0, 1, 2}, {0, 2, 1}, {1, 2, 0}, {1, 0, 2}, {2, 0, 1}, {2, 1, 0}
845  };
846  const int *perm = tri_perm[ori];
847  for (int i = 0; i < 3; i++) {
848  e_out[i] = e_in[perm[i]];
849  }
850 }
851 
852 // Permute the edges/vertices of a quad according to a given orientation.
853 // Note that the permutation arrays for the edges and the vertices are the same.
854 static inline void FmsPermuteQuadBdr(FmsOrientation ori, const FmsInt *e_in,
855  FmsInt *e_out) {
856  static const int quad_perm[8][4] = {
857  {0, 1, 2, 3}, {0, 3, 2, 1}, {1, 2, 3, 0}, {1, 0, 3, 2},
858  {2, 3, 0, 1}, {2, 1, 0, 3}, {3, 0, 1, 2}, {3, 2, 1, 0}
859  };
860  const int *perm = quad_perm[ori];
861  for (int i = 0; i < 4; i++) {
862  e_out[i] = e_in[perm[i]];
863  }
864 }
865 
866 
867 /* -------------------------------------------------------------------------- */
868 /* Fms general functions */
869 /* -------------------------------------------------------------------------- */
870 
872  if (!version) { E_RETURN(1); }
873  *version = FMS_INTERFACE_VERSION;
874  return 0;
875 }
876 
877 int FmsGetIntTypeFromName(const char * const name, FmsIntType *type) {
878  if(!name) E_RETURN(1);
879  if(!type) E_RETURN(2);
880 
881  if(strcmp(FmsIntTypeNames[FMS_INT8], name) == 0)
882  *type = FMS_INT8;
883  else if(strcmp(FmsIntTypeNames[FMS_INT16], name) == 0)
884  *type = FMS_INT16;
885  else if(strcmp(FmsIntTypeNames[FMS_INT32], name) == 0)
886  *type = FMS_INT32;
887  else if(strcmp(FmsIntTypeNames[FMS_INT64], name) == 0)
888  *type = FMS_INT64;
889  else if(strcmp(FmsIntTypeNames[FMS_UINT8], name) == 0)
890  *type = FMS_UINT8;
891  else if(strcmp(FmsIntTypeNames[FMS_UINT16], name) == 0)
892  *type = FMS_UINT16;
893  else if(strcmp(FmsIntTypeNames[FMS_UINT32], name) == 0)
894  *type = FMS_UINT32;
895  else if(strcmp(FmsIntTypeNames[FMS_UINT64], name) == 0)
896  *type = FMS_UINT64;
897  else
898  E_RETURN(3);
899 
900  return 0;
901 }
902 
903 int FmsGetScalarTypeFromName(const char * const name, FmsScalarType *type) {
904  if(!name) E_RETURN(1);
905  if(!type) E_RETURN(2);
906 
907  if(strcmp(FmsScalarTypeNames[FMS_FLOAT], name) == 0)
908  *type = FMS_FLOAT;
909  else if(strcmp(FmsScalarTypeNames[FMS_DOUBLE], name) == 0)
910  *type = FMS_DOUBLE;
911  else if(strcmp(FmsScalarTypeNames[FMS_COMPLEX_FLOAT], name) == 0)
912  *type = FMS_COMPLEX_FLOAT;
913  else if(strcmp(FmsScalarTypeNames[FMS_COMPLEX_DOUBLE], name) == 0)
914  *type = FMS_COMPLEX_DOUBLE;
915  else
916  E_RETURN(3);
917 
918  return 0;
919 }
920 
921 int FmsGetEntityTypeFromName(const char * const name, FmsEntityType *ent_type) {
922  if(!name) E_RETURN(1);
923  if(!ent_type) E_RETURN(2);
924 
925  if(strcmp(FmsEntityTypeNames[FMS_VERTEX], name) == 0)
926  *ent_type = FMS_VERTEX;
927  else if(strcmp(FmsEntityTypeNames[FMS_EDGE], name) == 0)
928  *ent_type = FMS_EDGE;
929  else if(strcmp(FmsEntityTypeNames[FMS_TRIANGLE], name) == 0)
930  *ent_type = FMS_TRIANGLE;
931  else if(strcmp(FmsEntityTypeNames[FMS_QUADRILATERAL], name) == 0)
932  *ent_type = FMS_QUADRILATERAL;
933  else if(strcmp(FmsEntityTypeNames[FMS_TETRAHEDRON], name) == 0)
934  *ent_type = FMS_TETRAHEDRON;
935  else if(strcmp(FmsEntityTypeNames[FMS_HEXAHEDRON], name) == 0)
936  *ent_type = FMS_HEXAHEDRON;
937  else if(strcmp(FmsEntityTypeNames[FMS_WEDGE], name) == 0)
938  *ent_type = FMS_WEDGE;
939  else if(strcmp(FmsEntityTypeNames[FMS_PYRAMID], name) == 0)
940  *ent_type = FMS_PYRAMID;
941  else
942  E_RETURN(3);
943 
944  return 0;
945 }
946 
947 int FmsGetMetaDataTypeFromName(const char * const name, FmsMetaDataType *type) {
948  if(!name) E_RETURN(1);
949  if(!type) E_RETURN(2);
950 
951  if(strcmp(FmsMetaDataTypeNames[FMS_INTEGER], name) == 0)
952  *type = FMS_INTEGER;
953  else if(strcmp(FmsMetaDataTypeNames[FMS_SCALAR], name) == 0)
954  *type = FMS_SCALAR;
955  else if(strcmp(FmsMetaDataTypeNames[FMS_STRING], name) == 0)
956  *type = FMS_STRING;
957  else if(strcmp(FmsMetaDataTypeNames[FMS_META_DATA], name) == 0)
958  *type = FMS_META_DATA;
959  else
960  E_RETURN(3);
961 
962  return 0;
963 }
964 
965 
966 /* -------------------------------------------------------------------------- */
967 /* FmsMesh functions: construction */
968 /* -------------------------------------------------------------------------- */
969 
971  if (!mesh) { E_RETURN(1); }
972  FmsMesh m;
973  m = calloc(1, sizeof(*m));
974  if (!m) { E_RETURN(2); }
975  m->num_partitions = 1;
976  *mesh = m;
977  return 0;
978 }
979 
981  if (!mesh) { E_RETURN(1); }
982  // Generate the side entity orientations for all entities in all domains
983  for (FmsInt domain_id = 0; domain_id < mesh->num_domains; domain_id++) {
984  FmsDomain domain = mesh->domains[domain_id];
985  // Triangles
986  if (domain->num_entities[FMS_TRIANGLE]) {
987  const FmsEntityType et = FMS_TRIANGLE;
988  const FmsIntType side_ids_type = domain->side_ids_type[et];
989  if (side_ids_type != domain->side_ids_type[FMS_EDGE]) { E_RETURN(2); }
990  const size_t sizeof_side_ids = FmsIntTypeSize[side_ids_type];
991  const FmsInt num_tri = domain->num_entities[et];
992  const char *all_tris = domain->entities[et];
993  const void *all_edges = domain->entities[FMS_EDGE];
994  FmsOrientation *oris = domain->orientations[et];
995  const int bsize = 1024;
996  FmsInt tri_verts[6*bsize];
997  for (FmsInt off = 0; off < num_tri; off += bsize) {
998  const FmsInt sz = FmsIntMin(bsize, num_tri-off);
999  FmsEntitiesToSides(side_ids_type, 3, 0, 3, all_tris, 2, all_edges,
1000  6, 0, tri_verts, sz);
1001  int err = FmsOrientFaceSides(3, sz, tri_verts, oris);
1002  if (err) { E_RETURN(err); }
1003  // TODO: create/update a list of the unknown side orientations
1004  all_tris += 3*sz*sizeof_side_ids;
1005  oris += 3*sz;
1006  }
1007  }
1008  // Quads
1009  if (domain->num_entities[FMS_QUADRILATERAL]) {
1010  const FmsEntityType et = FMS_QUADRILATERAL;
1011  const FmsIntType side_ids_type = domain->side_ids_type[et];
1012  if (side_ids_type != domain->side_ids_type[FMS_EDGE]) { E_RETURN(2); }
1013  const size_t sizeof_side_ids = FmsIntTypeSize[side_ids_type];
1014  const FmsInt num_quads = domain->num_entities[et];
1015  const char *all_quads = domain->entities[et];
1016  const void *all_edges = domain->entities[FMS_EDGE];
1017  FmsOrientation *oris = domain->orientations[et];
1018  const int bsize = 1024;
1019  FmsInt quad_verts[8*bsize];
1020  for (FmsInt off = 0; off < num_quads; off += bsize) {
1021  const FmsInt sz = FmsIntMin(bsize, num_quads-off);
1022  FmsEntitiesToSides(side_ids_type, 4, 0, 4, all_quads, 2, all_edges,
1023  8, 0, quad_verts, sz);
1024  int err = FmsOrientFaceSides(4, sz, quad_verts, oris);
1025  if (err) { E_RETURN(err); }
1026  // TODO: create/update a list of the unknown side orientations
1027  all_quads += 4*sz*sizeof_side_ids;
1028  oris += 4*sz;
1029  }
1030  }
1031  // Tets
1032  if (domain->num_entities[FMS_TETRAHEDRON]) {
1033  const FmsEntityType et = FMS_TETRAHEDRON;
1034  const FmsIntType side_ids_type = domain->side_ids_type[et];
1035  if (side_ids_type != domain->side_ids_type[FMS_TRIANGLE]) { E_RETURN(2); }
1036  const size_t sizeof_side_ids = FmsIntTypeSize[side_ids_type];
1037  const FmsInt num_tets = domain->num_entities[et];
1038  const char *all_tets = domain->entities[et];
1039  const void *all_tris = domain->entities[FMS_TRIANGLE];
1040  FmsOrientation *oris = domain->orientations[et];
1041  const int bsize = 512;
1042  FmsInt tet_edges[12*bsize];
1043  for (FmsInt off = 0; off < num_tets; off += bsize) {
1044  const FmsInt sz = FmsIntMin(bsize, num_tets-off);
1045  FmsEntitiesToSides(side_ids_type, 4, 0, 4, all_tets, 3, all_tris,
1046  12, 0, tet_edges, sz);
1047  int err = FmsOrientTetSides(sz, tet_edges, oris);
1048  if (err) { E_RETURN(err); }
1049  // TODO: create/update a list of the unknown side orientations
1050  all_tets += 4*sz*sizeof_side_ids;
1051  oris += 4*sz;
1052  }
1053  }
1054  // Hexes
1055  if (domain->num_entities[FMS_HEXAHEDRON]) {
1056  const FmsEntityType et = FMS_HEXAHEDRON;
1057  const FmsIntType side_ids_type = domain->side_ids_type[et];
1058  if (side_ids_type != domain->side_ids_type[FMS_QUADRILATERAL]) {
1059  E_RETURN(2);
1060  }
1061  const size_t sizeof_side_ids = FmsIntTypeSize[side_ids_type];
1062  const FmsInt num_hexes = domain->num_entities[et];
1063  const char *all_hexes = domain->entities[et];
1064  const void *all_quads = domain->entities[FMS_QUADRILATERAL];
1065  FmsOrientation *oris = domain->orientations[et];
1066  const int bsize = 256;
1067  FmsInt hex_edges[24*bsize];
1068  for (FmsInt off = 0; off < num_hexes; off += bsize) {
1069  const FmsInt sz = FmsIntMin(bsize, num_hexes-off);
1070  FmsEntitiesToSides(side_ids_type, 6, 0, 6, all_hexes, 4, all_quads,
1071  24, 0, hex_edges, sz);
1072  int err = FmsOrientHexSides(sz, hex_edges, oris);
1073  if (err) { E_RETURN(err); }
1074  // TODO: create/update a list of the unknown side orientations
1075  all_hexes += 6*sz*sizeof_side_ids;
1076  oris += 6*sz;
1077  }
1078  }
1079  // Wedges
1080  if (domain->num_entities[FMS_WEDGE]) {
1081  // TODO ...
1082  FmsAbortNotImplemented();
1083  }
1084  // Pyramids
1085  if (domain->num_entities[FMS_PYRAMID]) {
1086  // TODO ...
1087  FmsAbortNotImplemented();
1088  }
1089  }
1090  // TODO ...
1091  return 0;
1092 }
1093 
1095  if (!mesh) { E_RETURN(1); }
1096  // Perform some validation
1097  if (mesh->domain_offsets[0] != 0) { E_RETURN(2); }
1098  if (mesh->domain_offsets[mesh->num_domain_names] != mesh->num_domains) {
1099  E_RETURN(3);
1100  }
1101  if (mesh->partition_id >= mesh->num_partitions) { E_RETURN(4); }
1102  // Check domains for consistency
1103  for (FmsInt name_id = 0; name_id < mesh->num_domain_names; name_id++) {
1104  const FmsInt name_start = mesh->domain_offsets[name_id];
1105  const FmsInt name_end = mesh->domain_offsets[name_id+1];
1106  for (FmsInt domain_id = name_start; domain_id < name_end; domain_id++) {
1107  FmsDomain domain = mesh->domains[domain_id];
1108  if (domain->name != mesh->domain_names[name_id]) { E_RETURN(5); }
1109  if (name_start + domain->id != domain_id) { E_RETURN(6); }
1110  // TODO: Check that all side ids are in the expected ranges
1111  }
1112  }
1113  // Check that all components use domains from the same mesh
1114  char **domain_names = mesh->domain_names;
1115  for (FmsInt comp_id = 0; comp_id < mesh->num_comps; comp_id++) {
1116  FmsComponent comp = mesh->comps[comp_id];
1117  if (comp->id != comp_id) { E_RETURN(7); }
1118  if (comp->dim == FMS_INVALID_DIM) { E_RETURN(8); }
1119  for (FmsInt part_id = 0; part_id < comp->num_parts; part_id++) {
1120  FmsDomain domain = comp->parts[part_id].domain;
1121  FmsInt domain_name_id = 0;
1122  for ( ; 1; domain_name_id++) {
1123  if (domain_name_id == mesh->num_domain_names) { E_RETURN(9); }
1124  if (strcmp(domain->name, domain_names[domain_name_id]) == 0) { break; }
1125  }
1126  FmsInt b_offset = mesh->domain_offsets[domain_name_id];
1127  FmsInt num_domains = mesh->domain_offsets[domain_name_id+1] - b_offset;
1128  if (domain->id >= num_domains) { E_RETURN(10); }
1129  if (mesh->domains[b_offset + domain->id] != domain) { E_RETURN(11); }
1130  }
1131  }
1132  // Check that all tags use components from the same mesh
1133  for (FmsInt tag_id = 0; tag_id < mesh->num_tags; tag_id++) {
1134  FmsTag tag = mesh->tags[tag_id];
1135  FmsInt comp_id = tag->comp->id;
1136  if (comp_id >= mesh->num_comps) { E_RETURN(12); }
1137  if (mesh->comps[comp_id] != tag->comp) { E_RETURN(13); }
1138  }
1139  return 0;
1140 }
1141 
1143  if (!mesh) { E_RETURN(1); }
1144  FmsMesh m = *mesh;
1145  if (m) {
1146  // Delete domains
1147  for (FmsInt i = 0; i < m->num_domains; i++) {
1148  FmsDomain domain = m->domains[i];
1149  for (FmsInt j = 0; j < FMS_NUM_ENTITY_TYPES; j++) {
1150  free(domain->orientations[j]);
1151  free(domain->entities[j]);
1152  }
1153  // domain->name is not owned
1154  free(domain);
1155  }
1156  free(m->domains);
1157  // Delete components
1158  for (FmsInt i = 0; i < m->num_comps; i++) {
1159  FmsComponent comp = m->comps[i];
1160  free(comp->relations);
1161  // comp->coordinates is not owned
1162  // Delete parts
1163  for (FmsInt j = 0; j < comp->num_parts; j++) {
1164  struct _FmsPart_private *part = &comp->parts[j];
1165  for (FmsInt k = 0; k < FMS_NUM_ENTITY_TYPES; k++) {
1166  free(part->orientations[k]);
1167  free(part->entities_ids[k]);
1168  }
1169  }
1170  free(comp->parts);
1171  free(comp->name);
1172  free(comp);
1173  }
1174  free(m->comps);
1175  // Delete tags
1176  for (FmsInt i = 0; i < m->num_tags; i++) {
1177  FmsTag tag = m->tags[i];
1178  for (FmsInt j = 0; j < tag->num_tag_descriptions; j++) {
1179  free(tag->tag_descriptions[j]);
1180  }
1181  free(tag->tag_descriptions);
1182  free(tag->described_tags);
1183  free(tag->tags);
1184  free(tag->name);
1185  free(tag);
1186  }
1187  free(m->tags);
1188  // Delete domain names and offsets
1189  for (FmsInt i = 0; i < m->num_domain_names; i++) {
1190  free(m->domain_names[i]);
1191  }
1192  free(m->domain_names);
1193  free(m->domain_offsets);
1194  // Delete the mesh struct
1195  free(m);
1196  *mesh = NULL;
1197  }
1198  return 0;
1199 }
1200 
1201 int FmsMeshSetPartitionId(FmsMesh mesh, FmsInt partition_id,
1202  FmsInt num_partitions) {
1203  if (!mesh) { E_RETURN(1); }
1204  // if (partition_id < 0) { E_RETURN(2); } // if FmsInt is signed
1205  if (partition_id >= num_partitions) { E_RETURN(2); }
1206  mesh->partition_id = partition_id;
1207  mesh->num_partitions = num_partitions;
1208  return 0;
1209 }
1210 
1211 int FmsMeshAddDomains(FmsMesh mesh, const char *domain_name, FmsInt num_domains,
1212  FmsDomain **domains) {
1213  if (!mesh) { E_RETURN(1); }
1214  if (!domain_name) { E_RETURN(2); }
1215  if (!domains) { E_RETURN(3); }
1216  FmsInt num_domain_names = mesh->num_domain_names;
1217  char **domain_names = mesh->domain_names;
1218  // Make sure the 'domain_name' is not already used
1219  for (FmsInt i = 0; i < num_domain_names; i++) {
1220  if (strcmp(domain_name, domain_names[i]) == 0) { E_RETURN(4); }
1221  }
1222  FmsInt *domain_offsets = mesh->domain_offsets;
1223  // Reallocate mesh->domain_names and mesh->domain_offsets, if necessary
1224  FmsInt nc = NextPow2(num_domain_names+1);
1225  if (num_domain_names <= nc/2) {
1226  domain_names = realloc(domain_names, nc*sizeof(*domain_names));
1227  if (domain_names == NULL) { E_RETURN(5); }
1228  mesh->domain_names = domain_names;
1229  domain_offsets = realloc(domain_offsets, (nc+1)*sizeof(FmsInt));
1230  if (domain_offsets == NULL) { E_RETURN(5); }
1231  domain_offsets[0] = 0;
1232  mesh->domain_offsets = domain_offsets;
1233  }
1234  FmsDomain *m_domains = mesh->domains;
1235  const FmsInt m_num_domains = mesh->num_domains;
1236  // Reallocate mesh->domains, if necessary
1237  if (num_domains != 0) {
1238  nc = NextPow2(m_num_domains + num_domains);
1239  if (m_num_domains <= nc/2) {
1240  m_domains = realloc(m_domains, nc*sizeof(FmsDomain));
1241  if (m_domains == NULL) { E_RETURN(5); }
1242  mesh->domains = m_domains;
1243  }
1244  }
1245  char *domain_name_copy;
1246  if (FmsCopyString(domain_name, &domain_name_copy)) { E_RETURN(5); }
1247  // On error, call free(domain_name_copy)
1248  for (FmsInt i = 0; i < num_domains; i++) {
1249  FmsDomain domain;
1250  domain = calloc(1, sizeof(*domain));
1251  if (domain == NULL) {
1252  while (i != 0) { free(m_domains[m_num_domains + (--i)]); }
1253  free(domain_name_copy);
1254  E_RETURN(5);
1255  }
1256  // Init the domain name, id, and dim
1257  domain->name = domain_name_copy;
1258  domain->id = i;
1259  domain->dim = FMS_INVALID_DIM;
1260  m_domains[m_num_domains + i] = domain;
1261  }
1262  domain_names[num_domain_names] = domain_name_copy;
1263  mesh->num_domain_names = ++num_domain_names;
1264  mesh->num_domains = domain_offsets[num_domain_names] = m_num_domains +
1265  num_domains;
1266  *domains = m_domains + m_num_domains;
1267  return 0;
1268 }
1269 
1270 int FmsMeshAddComponent(FmsMesh mesh, const char *comp_name,
1271  FmsComponent *comp) {
1272  if (!mesh) { E_RETURN(1); }
1273  if (!comp) { E_RETURN(2); }
1274  FmsInt num_comps = mesh->num_comps;
1275  FmsComponent *comps = mesh->comps;
1276  // Reallocate mesh->comps, if necessary
1277  FmsInt nc = NextPow2(num_comps+1);
1278  if (num_comps <= nc/2) {
1279  comps = realloc(comps, nc*sizeof(*comps));
1280  if (comps == NULL) { E_RETURN(3); }
1281  mesh->comps = comps;
1282  }
1283  FmsComponent component;
1284  component = calloc(1, sizeof(*component));
1285  if (component == NULL) { E_RETURN(3); }
1286  // On error, call free(component)
1287  if (FmsCopyString(comp_name, &component->name)) {
1288  free(component); E_RETURN(3);
1289  }
1290  component->id = num_comps;
1291  component->dim = FMS_INVALID_DIM;
1292  comps[num_comps] = component;
1293  mesh->num_comps = num_comps+1;
1294  *comp = component;
1295  return 0;
1296 }
1297 
1298 int FmsMeshAddTag(FmsMesh mesh, const char *tag_name, FmsTag *tag) {
1299  if (!mesh) { E_RETURN(1); }
1300  if (!tag) { E_RETURN(2); }
1301  FmsInt num_tags = mesh->num_tags;
1302  FmsTag *tags = mesh->tags;
1303  // Reallocate mesh->tags, if necessary
1304  FmsInt nc = NextPow2(num_tags+1);
1305  if (num_tags <= nc/2) {
1306  tags = realloc(tags, nc*sizeof(*tags));
1307  if (tags == NULL) { E_RETURN(3); }
1308  mesh->tags = tags;
1309  }
1310  FmsTag t;
1311  t = calloc(1, sizeof(*t));
1312  if (t == NULL) { E_RETURN(3); }
1313  // On error, call free(t)
1314  if (FmsCopyString(tag_name, &t->name)) { free(t); E_RETURN(3); }
1315  t->tag_type = FMS_NUM_INT_TYPES; // invalid type
1316  tags[num_tags] = t;
1317  mesh->num_tags = num_tags+1;
1318  *tag = t;
1319  return 0;
1320 }
1321 
1322 
1323 /* -------------------------------------------------------------------------- */
1324 /* FmsDomain functions: construction */
1325 /* -------------------------------------------------------------------------- */
1326 
1327 int FmsDomainSetNumVertices(FmsDomain domain, FmsInt num_verts) {
1328  if (!domain) { E_RETURN(1); }
1329  domain->num_entities[FMS_VERTEX] = num_verts;
1330  if (domain->dim == FMS_INVALID_DIM) { domain->dim = 0; }
1331  return 0;
1332 }
1333 
1335  FmsIntType id_store_type, FmsInt num_ents) {
1336  if (!domain) { E_RETURN(1); }
1337  if (type >= FMS_NUM_ENTITY_TYPES) { E_RETURN(2); }
1338  if (type == FMS_VERTEX) {
1339  domain->num_entities[type] = num_ents;
1340  if (domain->dim == FMS_INVALID_DIM) { domain->dim = 0; }
1341  return 0;
1342  }
1343  if (id_store_type >= FMS_NUM_INT_TYPES) { E_RETURN(3); }
1344  const size_t sizeof_side_ids = FmsIntTypeSize[id_store_type];
1345  const FmsInt num_sides = FmsEntityNumSides[type];
1346  domain->num_entities[type] = 0;
1347  domain->entities_caps[type] = 0;
1348  free(domain->orientations[type]);
1349  free(domain->entities[type]);
1350  if (num_ents != 0) {
1351  FmsInt tot_sides = num_ents*num_sides;
1352  domain->entities[type] = malloc(tot_sides*sizeof_side_ids);
1353  if (domain->entities[type] == NULL) {
1354  domain->orientations[type] = NULL;
1355  E_RETURN(4);
1356  }
1357  domain->orientations[type] = malloc(tot_sides*sizeof(FmsOrientation));
1358  if (domain->orientations[type] == NULL) {
1359  free(domain->entities[type]);
1360  domain->entities[type] = NULL;
1361  E_RETURN(4);
1362  }
1363  FmsOrientation *orientations = domain->orientations[type];
1364  for (FmsInt i = 0; i < tot_sides; i++) {
1365  orientations[i] = FMS_ORIENTATION_UNKNOWN;
1366  }
1367  } else {
1368  domain->entities[type] = NULL;
1369  domain->orientations[type] = NULL;
1370  }
1371  domain->entities_caps[type] = num_ents;
1372  domain->side_ids_type[type] = id_store_type;
1373  if (domain->dim == FMS_INVALID_DIM) {
1374  domain->dim = FmsEntityDim[type];
1375  } else {
1376  domain->dim = FmsIntMax(domain->dim, FmsEntityDim[type]);
1377  }
1378  return 0;
1379 }
1380 
1382  void **ents) {
1383  if (!domain) { E_RETURN(1); }
1384  if (type == FMS_VERTEX || type >= FMS_NUM_ENTITY_TYPES) { E_RETURN(2); }
1385  if (ents == NULL) { E_RETURN(3); }
1386  // This function assumes that all domain->entities_caps[type] entities in the
1387  // returned array *ents will be set.
1388  domain->num_entities[type] = domain->entities_caps[type];
1389  *ents = domain->entities[type];
1390  return 0;
1391 }
1392 
1394  FmsOrientation **side_orients) {
1395  if (!domain) { E_RETURN(1); }
1396  if (type == FMS_VERTEX || type >= FMS_NUM_ENTITY_TYPES) { E_RETURN(2); }
1397  if (side_orients == NULL) { E_RETURN(3); }
1398  *side_orients = domain->orientations[type];
1399  return 0;
1400 }
1401 
1403  FmsEntityReordering reordering, FmsIntType ent_id_type,
1404  const void *ents, FmsInt num_ents) {
1405  if (!domain) { E_RETURN(1); }
1406  if (type == FMS_VERTEX || type >= FMS_NUM_ENTITY_TYPES) { E_RETURN(2); }
1407  const FmsInt num_entities = domain->num_entities[type];
1408  if (num_entities + num_ents > domain->entities_caps[type]) { E_RETURN(3); }
1409  const FmsIntType side_ids_type = domain->side_ids_type[type];
1410  const size_t sizeof_side_ids = FmsIntTypeSize[side_ids_type];
1411  const FmsInt num_sides = FmsEntityNumSides[type];
1412  void *ents_dst = (char*)(domain->entities[type]) +
1413  num_entities*num_sides*sizeof_side_ids;
1414  const int *perm = reordering ? reordering[type] : NULL;
1415  if (perm == NULL) {
1416  FmsIntConvertCopy(ent_id_type, ents, side_ids_type, ents_dst,
1417  num_ents*num_sides);
1418  } else {
1419  FmsIntPermuteConvertCopy(ent_id_type, ents, side_ids_type, ents_dst,
1420  perm, num_sides, num_ents*num_sides);
1421  }
1422  domain->num_entities[type] = num_entities + num_ents;
1423  return 0;
1424 }
1425 
1427  FmsInt loc_side_id, FmsOrientation side_orient) {
1428  if (!domain) { E_RETURN(1); }
1429  if (type == FMS_VERTEX || type >= FMS_NUM_ENTITY_TYPES) { E_RETURN(2); }
1430  if (ent_id >= domain->entities_caps[type]) { E_RETURN(3); }
1431  const FmsInt num_sides = FmsEntityNumSides[type];
1432  if (loc_side_id >= num_sides) { E_RETURN(4); }
1433  FmsOrientation *orientations = domain->orientations[type];
1434  orientations[ent_id*num_sides + loc_side_id] = side_orient;
1435  return 0;
1436 }
1437 
1438 
1439 /* -------------------------------------------------------------------------- */
1440 /* FmsComponent functions: construction */
1441 /* -------------------------------------------------------------------------- */
1442 
1444  if (!comp) { E_RETURN(1); }
1445  if (!domain) { E_RETURN(2); }
1446  const FmsInt num_parts = comp->num_parts;
1447  const FmsInt comp_dim = comp->dim;
1448  const FmsInt dim = domain->dim;
1449  if (comp_dim != FMS_INVALID_DIM && comp_dim != dim) { E_RETURN(3); }
1450  struct _FmsPart_private *parts = comp->parts;
1451  // Reallocate comp->parts, if necessary
1452  FmsInt nc = NextPow2(num_parts + 1);
1453  if (num_parts <= nc/2) {
1454  parts = realloc(parts, nc*sizeof(*parts));
1455  if (parts == NULL) { E_RETURN(4); }
1456  comp->parts = parts;
1457  }
1458  struct _FmsPart_private *part = parts + num_parts;
1459  // Initialize part, counting the number of main entities
1460  memset(part, 0, sizeof(*part));
1461  part->domain = domain;
1462  FmsInt num_main_entities = comp->num_main_entities;
1463  for (FmsInt t = 0; t < FMS_NUM_ENTITY_TYPES; t++) {
1464  FmsInt num_entities = domain->num_entities[t];
1465  part->num_entities[t] = num_entities;
1466  if (FmsEntityDim[t] == dim) {
1467  num_main_entities += num_entities;
1468  }
1469  // the value of part->entities_ids_type[t] is not used
1470  // part->entities_ids[t] is already set to NULL
1471  // part->orientations[t] is already set to NULL
1472  }
1473  // Update comp
1474  if (comp_dim == FMS_INVALID_DIM) {
1475  comp->dim = dim;
1476  }
1477  comp->num_main_entities = num_main_entities;
1478  comp->num_parts = num_parts + 1;
1479  return 0;
1480 }
1481 
1482 int FmsComponentAddPart(FmsComponent comp, FmsDomain domain, FmsInt *part_id) {
1483  if (!comp) { E_RETURN(1); }
1484  if (!domain) { E_RETURN(2); }
1485  if (!part_id) { E_RETURN(3); }
1486  const FmsInt num_parts = comp->num_parts;
1487  struct _FmsPart_private *parts = comp->parts;
1488  // Reallocate comp->parts, if necessary
1489  FmsInt nc = NextPow2(num_parts + 1);
1490  if (num_parts <= nc/2) {
1491  parts = realloc(parts, nc*sizeof(*parts));
1492  if (parts == NULL) { E_RETURN(4); }
1493  comp->parts = parts;
1494  }
1495  struct _FmsPart_private *part = parts + num_parts;
1496  // Initialize part
1497  memset(part, 0, sizeof(*part));
1498  part->domain = domain;
1499  comp->num_parts = num_parts + 1;
1500  *part_id = num_parts;
1501  return 0;
1502 }
1503 
1505  FmsEntityType type, FmsIntType id_store_type,
1506  FmsIntType ent_id_type, FmsIntType orient_type,
1507  const FmsOrientation *inv_orient_map,
1508  const void *ents, const void *ent_orients,
1509  FmsInt num_ents) {
1510  if (!comp) { E_RETURN(1); }
1511  if (part_id >= comp->num_parts) { E_RETURN(2); }
1512  if (type >= FMS_NUM_ENTITY_TYPES) { E_RETURN(3); }
1513  if (comp->dim != FMS_INVALID_DIM && comp->dim != FmsEntityDim[type]) {
1514  E_RETURN(3);
1515  }
1516  if (id_store_type >= FMS_NUM_INT_TYPES) { E_RETURN(4); }
1517  if (ent_id_type >= FMS_NUM_INT_TYPES) { E_RETURN(5); }
1518  if (orient_type >= FMS_NUM_INT_TYPES) { E_RETURN(6); }
1519  struct _FmsPart_private *part = comp->parts + part_id;
1520  const FmsInt num_entities = part->num_entities[type];
1521  void *entities_ids = part->entities_ids[type];
1522  FmsOrientation *orientations = part->orientations[type];
1523  if (num_entities != 0) {
1524  if (entities_ids == NULL) { E_RETURN(7); }
1525  if (orientations == NULL) { E_RETURN(8); }
1526  if (ents == NULL) { E_RETURN(9); }
1527  if (ent_orients == NULL) { E_RETURN(10); }
1528  if (part->entities_ids_type[type] != id_store_type) { E_RETURN(11); }
1529  } else if (ents == NULL) {
1530  if (num_ents != part->domain->num_entities[type]) { E_RETURN(12); }
1531  }
1532  const size_t sizeof_ent_ids = FmsIntTypeSize[id_store_type];
1533  if (num_ents != 0) {
1534  const FmsInt nc = NextPow2(num_entities + num_ents);
1535  if (ents != NULL) {
1536  if (num_entities <= nc/2) {
1537  entities_ids = realloc(entities_ids, nc*sizeof_ent_ids);
1538  if (entities_ids == NULL) { E_RETURN(13); }
1539  part->entities_ids[type] = entities_ids;
1540  }
1541  FmsIntConvertCopy(ent_id_type, ents, id_store_type,
1542  (char*)entities_ids + num_entities*sizeof_ent_ids,
1543  num_ents);
1544  } else {
1545  // part->entities_ids[type] is already NULL since num_entities is 0
1546  }
1547  if (ent_orients != NULL) {
1548  if (num_entities <= nc/2) {
1549  orientations = realloc(orientations, nc*sizeof(FmsOrientation));
1550  if (orientations == NULL) { E_RETURN(13); }
1551  part->orientations[type] = orientations;
1552  }
1553  if (inv_orient_map != NULL) {
1554  FmsIntMapCopy(orient_type, ent_orients, FMS_ORIENTATION_INT_TYPE,
1555  orientations + num_entities, inv_orient_map, num_ents);
1556  } else {
1557  FmsIntConvertCopy(orient_type, ent_orients, FMS_ORIENTATION_INT_TYPE,
1558  orientations + num_entities, num_ents);
1559  }
1560  } else {
1561  // part->orientations[type] is already NULL since num_entities is 0
1562  }
1563  }
1564  // Update the part
1565  part->num_entities[type] = num_entities + num_ents;
1566  if (num_entities == 0) {
1567  part->entities_ids_type[type] = id_store_type;
1568  }
1569  // Update the component
1570  if (comp->dim == FMS_INVALID_DIM) {
1571  comp->dim = FmsEntityDim[type];
1572  }
1573  comp->num_main_entities += num_ents;
1574  return 0;
1575 }
1576 
1578  FmsEntityType type, FmsIntType id_store_type,
1579  FmsIntType ent_id_type, const void *ents,
1580  FmsInt num_ents) {
1581  if (!comp) { E_RETURN(1); }
1582  if (part_id >= comp->num_parts) { E_RETURN(2); }
1583  if (type >= FMS_NUM_ENTITY_TYPES) { E_RETURN(3); }
1584  if (comp->dim != FMS_INVALID_DIM && comp->dim <= FmsEntityDim[type]) {
1585  E_RETURN(4);
1586  }
1587  if (id_store_type >= FMS_NUM_INT_TYPES) { E_RETURN(5); }
1588  if (ent_id_type >= FMS_NUM_INT_TYPES) { E_RETURN(6); }
1589  struct _FmsPart_private *part = comp->parts + part_id;
1590  const FmsInt num_entities = part->num_entities[type];
1591  void *entities_ids = part->entities_ids[type];
1592  if (num_entities != 0) {
1593  if (entities_ids == NULL) { E_RETURN(7); }
1594  if (ents == NULL) { E_RETURN(8); }
1595  if (part->entities_ids_type[type] != id_store_type) { E_RETURN(9); }
1596  } else if (ents == NULL) {
1597  if (num_ents != part->domain->num_entities[type]) { E_RETURN(10); }
1598  }
1599  const size_t sizeof_ent_ids = FmsIntTypeSize[id_store_type];
1600  if (num_ents != 0) {
1601  const FmsInt nc = NextPow2(num_entities + num_ents);
1602  if (ents != NULL) {
1603  if (num_entities <= nc/2) {
1604  entities_ids = realloc(entities_ids, nc*sizeof_ent_ids);
1605  if (entities_ids == NULL) { E_RETURN(11); }
1606  part->entities_ids[type] = entities_ids;
1607  }
1608  FmsIntConvertCopy(ent_id_type, ents, id_store_type,
1609  (char*)entities_ids + num_entities*sizeof_ent_ids,
1610  num_ents);
1611  } else {
1612  // part->entities_ids[type] is already NULL since num_entities is 0
1613  }
1614  }
1615  // Update the part
1616  part->num_entities[type] = num_entities + num_ents;
1617  if (num_entities == 0) {
1618  part->entities_ids_type[type] = id_store_type;
1619  }
1620  // Nothing to update in the component
1621  return 0;
1622 }
1623 
1624 int FmsComponentAddRelation(FmsComponent comp, FmsInt other_comp_id) {
1625  if (!comp) { E_RETURN(1); }
1626  FmsInt num_relations = comp->num_relations;
1627  FmsInt *relations = comp->relations;
1628  FmsInt nc = NextPow2(num_relations + 1);
1629  if (num_relations <= nc/2) {
1630  relations = realloc(relations, nc*sizeof(FmsInt));
1631  if (relations == NULL) { E_RETURN(2); }
1632  comp->relations = relations;
1633  }
1634  relations[num_relations] = other_comp_id;
1635  comp->num_relations = num_relations + 1;
1636  return 0;
1637 }
1638 
1640  if (!comp) { E_RETURN(1); }
1641  if (coords->fd->component != comp) { E_RETURN(2); }
1642  comp->coordinates = coords;
1643  return 0;
1644 }
1645 
1646 
1647 /* -------------------------------------------------------------------------- */
1648 /* FmsTag functions: construction */
1649 /* -------------------------------------------------------------------------- */
1650 
1652  if (!tag) { E_RETURN(1); }
1653  if (!comp) { E_RETURN(2); }
1654  tag->comp = comp;
1655  return 0;
1656 }
1657 
1658 int FmsTagSet(FmsTag tag, FmsIntType stored_tag_type, FmsIntType input_tag_type,
1659  const void *ent_tags, FmsInt num_ents) {
1660  if (!tag) { E_RETURN(1); }
1661  if (stored_tag_type >= FMS_NUM_INT_TYPES) { E_RETURN(2); }
1662  if (tag->tag_type != FMS_NUM_INT_TYPES && tag->tag_type != stored_tag_type) {
1663  E_RETURN(3);
1664  }
1665  if (input_tag_type >= FMS_NUM_INT_TYPES) { E_RETURN(4); }
1666  FmsComponent comp = tag->comp;
1667  if (!comp) { E_RETURN(5); }
1668  if (comp->num_main_entities != num_ents) { E_RETURN(6); }
1669  if (num_ents != 0 && ent_tags == NULL) { E_RETURN(7); }
1670  free(tag->tags);
1671  tag->tags = NULL;
1672  if (num_ents != 0) {
1673  tag->tags = malloc(num_ents*FmsIntTypeSize[stored_tag_type]);
1674  if (tag->tags == NULL) { E_RETURN(8); }
1675  FmsIntConvertCopy(input_tag_type, ent_tags, stored_tag_type, tag->tags,
1676  num_ents);
1677  }
1678  tag->tag_type = stored_tag_type;
1679  return 0;
1680 }
1681 
1682 int FmsTagAllocate(FmsTag tag, FmsIntType stored_tag_type, void **ent_tags,
1683  FmsInt *num_ents) {
1684  if (!tag) { E_RETURN(1); }
1685  if (stored_tag_type >= FMS_NUM_INT_TYPES) { E_RETURN(2); }
1686  if (tag->tag_type != FMS_NUM_INT_TYPES && tag->tag_type != stored_tag_type) {
1687  E_RETURN(3);
1688  }
1689  if (ent_tags == NULL) { E_RETURN(4); }
1690  FmsComponent comp = tag->comp;
1691  if (!comp) { E_RETURN(5); }
1692  free(tag->tags);
1693  tag->tags = NULL;
1694  FmsInt num_entities = comp->num_main_entities;
1695  if (num_entities != 0) {
1696  tag->tags = malloc(num_entities*FmsIntTypeSize[stored_tag_type]);
1697  if (tag->tags == NULL) { E_RETURN(6); }
1698  }
1699  tag->tag_type = stored_tag_type;
1700  *ent_tags = tag->tags;
1701  if (num_ents != NULL) { *num_ents = num_entities; }
1702  return 0;
1703 }
1704 
1705 int FmsTagAddDescriptions(FmsTag tag, FmsIntType tag_type, const void *tags,
1706  const char *const *tag_descr, FmsInt num_tags) {
1707  if (!tag) { E_RETURN(1); }
1708  if (tag_type >= FMS_NUM_INT_TYPES) { E_RETURN(2); }
1709  if (tag->tag_type == FMS_NUM_INT_TYPES) { E_RETURN(3); }
1710  if (num_tags == 0) { return 0; }
1711  if (tags == NULL) { E_RETURN(4); }
1712  if (tag_descr == NULL) { E_RETURN(5); }
1713  const FmsInt num_tag_descriptions = tag->num_tag_descriptions;
1714  char *described_tags = tag->described_tags;
1715  char **tag_descriptions = tag->tag_descriptions;
1716  const size_t sizeof_tag_type = FmsIntTypeSize[tag->tag_type];
1717  const FmsInt nc = NextPow2(num_tag_descriptions + num_tags);
1718  if (num_tag_descriptions <= nc/2) {
1719  described_tags = realloc(described_tags, nc*sizeof_tag_type);
1720  if (described_tags == NULL) { E_RETURN(6); }
1721  tag->described_tags = described_tags;
1722  tag_descriptions = realloc(tag_descriptions, nc*sizeof(char*));
1723  if (tag_descriptions == NULL) { E_RETURN(6); }
1724  tag->tag_descriptions = tag_descriptions;
1725  }
1726  // Copy the new described tags
1727  FmsIntConvertCopy(tag_type, tags, tag->tag_type,
1728  described_tags + num_tag_descriptions*sizeof_tag_type,
1729  num_tags);
1730  // Copy the new description strings
1731  for (FmsInt i = 0; i < num_tags; i++) {
1732  if (FmsCopyString(tag_descr[i],
1733  &tag_descriptions[num_tag_descriptions + i])) {
1734  while (i != 0) {
1735  free(tag_descriptions[num_tag_descriptions + (--i)]);
1736  }
1737  E_RETURN(6);
1738  }
1739  }
1740  // Update tag
1741  tag->num_tag_descriptions = num_tag_descriptions + num_tags;
1742  return 0;
1743 }
1744 
1745 
1746 /* -------------------------------------------------------------------------- */
1747 /* FmsDataCollection functions: construction */
1748 /* -------------------------------------------------------------------------- */
1749 
1750 int FmsDataCollectionCreate(FmsMesh mesh, const char *dc_name,
1751  FmsDataCollection *dc) {
1752  if (!mesh) { E_RETURN(1); }
1753  if (!dc) { E_RETURN(2); }
1754  FmsDataCollection dcoll;
1755  dcoll = calloc(1, sizeof(*dcoll));
1756  if (dcoll == NULL) { E_RETURN(3); }
1757  // On error, call free(dcoll)
1758  // Init dcoll
1759  if (FmsCopyString(dc_name, &dcoll->name)) { free(dcoll); E_RETURN(3); }
1760  dcoll->mesh = mesh;
1761  *dc = dcoll;
1762  return 0;
1763 }
1764 
1766  int err = 0;
1767  if (!dc) { E_RETURN(1); }
1768  FmsDataCollection dcoll = *dc;
1769  if (dcoll != NULL) {
1770  // Delete fields
1771  FmsInt num_fields = dcoll->num_fields;
1772  FmsField *fields = dcoll->fields;
1773  for (FmsInt i = 0; i < num_fields; i++) {
1774  FmsField field = fields[i];
1775  free(field->data);
1776  err = UpdateError(err, FmsMetaDataDestroy(&field->mdata));
1777  free(field->name);
1778  free(field);
1779  }
1780  free(fields);
1781 
1782  // Delete field-descriptors
1783  FmsInt num_fds = dcoll->num_fds;
1784  FmsFieldDescriptor *fds = dcoll->fds;
1785  for (FmsInt i = 0; i < num_fds; i++) {
1786  FmsFieldDescriptor fd = fds[i];
1787  switch (fd->descr_type) {
1788  case FMS_FIXED_ORDER: free(fd->descriptor.fixed_order); break;
1789  default: err = UpdateError(err, 2);
1790  }
1791  free(fd->name);
1792  free(fd);
1793  }
1794  free(fds);
1795 
1796  // Delete mesh, meta-data, and name
1797  err = UpdateError(err, FmsMeshDestroy(&dcoll->mesh));
1798  err = UpdateError(err, FmsMetaDataDestroy(&dcoll->mdata));
1799  free(dcoll->name);
1800 
1801  // Delete dcoll
1802  free(dcoll);
1803  *dc = NULL;
1804  }
1805  E_RETURN(err);
1806 }
1807 
1809  const char *fd_name,
1810  FmsFieldDescriptor *fd) {
1811  if (!dc) { E_RETURN(1); }
1812  if (!fd) { E_RETURN(2); }
1813  const FmsInt num_fds = dc->num_fds;
1814  FmsFieldDescriptor *fds = dc->fds;
1815  // Reallocate dc->fds, if necessary
1816  const FmsInt nc = NextPow2(num_fds + 1);
1817  if (num_fds <= nc/2) {
1818  fds = realloc(fds, nc*sizeof(*fds));
1819  if (fds == NULL) { E_RETURN(3); }
1820  dc->fds = fds;
1821  }
1822  FmsFieldDescriptor new_fd;
1823  new_fd = calloc(1, sizeof(*new_fd));
1824  if (new_fd == NULL) { E_RETURN(3); }
1825  // On error, call free(new_fd)
1826  if (FmsCopyString(fd_name, &new_fd->name)) { free(new_fd); E_RETURN(3); }
1827  // Update the field descriptor
1828  dc->num_fds = num_fds + 1;
1829  dc->fds[num_fds] = new_fd;
1830  *fd = new_fd;
1831  return 0;
1832 }
1833 
1834 int FmsDataCollectionAddField(FmsDataCollection dc, const char *field_name,
1835  FmsField *field) {
1836  if (!dc) { E_RETURN(1); }
1837  if (!field) { E_RETURN(2); }
1838  const FmsInt num_fields = dc->num_fields;
1839  FmsField *fields = dc->fields;
1840  // Reallocate dc->fields, if necessary
1841  const FmsInt nc = NextPow2(num_fields + 1);
1842  if (num_fields <= nc/2) {
1843  fields = realloc(fields, nc*sizeof(*fields));
1844  if (fields == NULL) { E_RETURN(3); }
1845  dc->fields = fields;
1846  }
1847  FmsField new_field;
1848  new_field = calloc(1, sizeof(*new_field));
1849  if (new_field == NULL) { E_RETURN(3); }
1850  // On error, call free(new_field)
1851  if (FmsCopyString(field_name, &new_field->name)) {
1852  free(new_field); E_RETURN(3);
1853  }
1854  // Update the field
1855  dc->num_fields = num_fields + 1;
1856  dc->fields[num_fields] = new_field;
1857  *field = new_field;
1858  return 0;
1859 }
1860 
1862  if (!dc) { E_RETURN(1); }
1863  if (!mdata) { E_RETURN(2); }
1864  FmsMetaData md = dc->mdata;
1865  if (md == NULL) {
1866  md = calloc(1, sizeof(*md));
1867  if (md == NULL) { E_RETURN(3); }
1868  dc->mdata = md;
1869  } else {
1870  int err = FmsMetaDataClear(md);
1871  if (err) { E_RETURN(err); }
1872  }
1873  *mdata = md;
1874  return 0;
1875 }
1876 
1877 
1878 /* -------------------------------------------------------------------------- */
1879 /* FmsFieldDescriptor functions: construction */
1880 /* -------------------------------------------------------------------------- */
1881 
1883  if (!fd) { E_RETURN(1); }
1884  fd->component = comp;
1885  return 0;
1886 }
1887 
1889  FmsFieldType field_type,
1890  FmsBasisType basis_type, FmsInt order) {
1891  if (!fd) { E_RETURN(1); }
1892  FmsComponent comp = fd->component;
1893  if (!comp) { E_RETURN(2); }
1894  if (fd->descriptor.any != NULL) { E_RETURN(3); }
1895  FmsInt num_dofs = 0;
1896  // Count the number of dofs - based on component, field_type and order
1897  FmsInt ent_dofs[FMS_NUM_ENTITY_TYPES];
1898  const FmsInt dim = comp->dim;
1899  const FmsInt p = order;
1900  switch (field_type) {
1901  case FMS_CONTINUOUS: {
1902  const FmsInt pm1 = p-1, pm2 = p-2, pm3 = p-3;
1903  if (p <= 0) { E_RETURN(4); }
1904  ent_dofs[FMS_VERTEX] = 1;
1905  ent_dofs[FMS_EDGE] = pm1;
1906  ent_dofs[FMS_TRIANGLE] = (pm1*pm2)/2;
1907  ent_dofs[FMS_QUADRILATERAL] = pm1*pm1;
1908  ent_dofs[FMS_TETRAHEDRON] = (ent_dofs[FMS_TRIANGLE]*pm3)/3;
1909  ent_dofs[FMS_HEXAHEDRON] = ent_dofs[FMS_QUADRILATERAL]*pm1;
1910  ent_dofs[FMS_WEDGE] = ent_dofs[FMS_TRIANGLE]*pm1;
1911  ent_dofs[FMS_PYRAMID] = (ent_dofs[FMS_TRIANGLE]*(p+pm3))/3;
1912  break;
1913  }
1914  case FMS_DISCONTINUOUS:
1916  const FmsInt pp1 = p+1, pp2 = p+2, pp3 = p+3;
1917  // if (p < 0) { E_RETURN(4); } // If we make FmsInt a signed type
1918  ent_dofs[FMS_VERTEX] = 1;
1919  ent_dofs[FMS_EDGE] = pp1;
1920  ent_dofs[FMS_TRIANGLE] = (pp1*pp2)/2;
1921  ent_dofs[FMS_QUADRILATERAL] = pp1*pp1;
1922  ent_dofs[FMS_TETRAHEDRON] = (ent_dofs[FMS_TRIANGLE]*pp3)/3;
1923  ent_dofs[FMS_HEXAHEDRON] = ent_dofs[FMS_QUADRILATERAL]*pp1;
1924  ent_dofs[FMS_WEDGE] = ent_dofs[FMS_TRIANGLE]*pp1;
1925  ent_dofs[FMS_PYRAMID] = (ent_dofs[FMS_TRIANGLE]*(p+pp3))/3;
1926  for (FmsInt et = 0; et < FMS_NUM_ENTITY_TYPES; et++) {
1927  if (FmsEntityDim[et] < dim) {
1928  ent_dofs[et] = 0;
1929  }
1930  }
1931  break;
1932  }
1933  case FMS_HCURL: {
1934  FmsAbortNotImplemented();
1935  break;
1936  }
1937  case FMS_HDIV: {
1938  const FmsInt pp1 = p + 1, pp2 = p + 2;
1939  ent_dofs[FMS_VERTEX] = 0;
1940  ent_dofs[FMS_EDGE] = 0;
1941  ent_dofs[FMS_TETRAHEDRON] = 0;
1942  ent_dofs[FMS_HEXAHEDRON] = 0;
1943  if(dim == 2) {
1944  ent_dofs[FMS_EDGE] = pp1;
1945  ent_dofs[FMS_TRIANGLE] = p*pp1;
1946  ent_dofs[FMS_QUADRILATERAL] = 2*p*pp1;
1947  } else {
1948  ent_dofs[FMS_TRIANGLE] = pp1*pp2/2;
1949  ent_dofs[FMS_QUADRILATERAL] = pp1*pp1;
1950  ent_dofs[FMS_TETRAHEDRON] = p*pp1*(p + 2)/2;
1951  ent_dofs[FMS_HEXAHEDRON] = 3*p*pp1*pp1;
1952  }
1953  ent_dofs[FMS_WEDGE] = 0;
1954  ent_dofs[FMS_PYRAMID] = 0;
1955  break;
1956  }
1957  default: E_RETURN(5);
1958  }
1959  // Count the dofs part by part
1960  for (FmsInt i = 0; i < comp->num_parts; i++) {
1961  for (FmsInt et = 0; et < FMS_NUM_ENTITY_TYPES; et++) {
1962  num_dofs += comp->parts[i].num_entities[et] * ent_dofs[et];
1963  }
1964  }
1965 
1966  // Construct fixed-order descriptor
1967  struct _FmsFieldDescriptor_FixedOrder *fo;
1968  fo = malloc(sizeof(*fo));
1969  if (fo == NULL) { E_RETURN(6); }
1970  fo->field_type = field_type;
1971  fo->basis_type = basis_type;
1972  fo->order = order;
1973  // Update fd
1974  fd->descr_type = FMS_FIXED_ORDER;
1975  fd->descriptor.fixed_order = fo;
1976  fd->num_dofs = num_dofs;
1977  return 0;
1978 }
1979 
1980 
1981 /* -------------------------------------------------------------------------- */
1982 /* FmsField functions: construction */
1983 /* -------------------------------------------------------------------------- */
1984 
1985 int FmsFieldSet(FmsField field, FmsFieldDescriptor fd, FmsInt num_vec_comp,
1986  FmsLayoutType layout_type, FmsScalarType data_type,
1987  const void *data) {
1988  if (!field) { E_RETURN(1); }
1989  if (field->fd != NULL) { E_RETURN(2); }
1990  if (!fd) { E_RETURN(3); }
1991  if (!fd->descriptor.any) { E_RETURN(4); }
1992  if (layout_type != FMS_BY_NODES &&
1993  layout_type != FMS_BY_VDIM) { E_RETURN(5); }
1994  if (data_type >= FMS_NUM_SCALAR_TYPES) { E_RETURN(6); }
1995  if (!data) { E_RETURN(7); }
1996  // Make a copy of the data array
1997  const FmsInt num_vdofs = fd->num_dofs * num_vec_comp;
1998  const size_t sizeof_data_type = FmsScalarTypeSize[data_type];
1999  void *data_copy;
2000  if (num_vdofs != 0) {
2001  data_copy = malloc(num_vdofs*sizeof_data_type);
2002  if (data_copy == NULL) { E_RETURN(8); }
2003  memcpy(data_copy, data, num_vdofs*sizeof_data_type);
2004  } else {
2005  data_copy = NULL;
2006  }
2007  // Update field
2008  field->fd = fd;
2009  field->num_vec_comp = num_vec_comp;
2010  field->layout = layout_type;
2011  field->scalar_type = data_type;
2012  field->data = data_copy;
2013  return 0;
2014 }
2015 
2017  if (!field) { E_RETURN(1); }
2018  if (!mdata) { E_RETURN(2); }
2019  FmsMetaData md = field->mdata;
2020  if (md == NULL) {
2021  md = calloc(1, sizeof(*md));
2022  if (md == NULL) { E_RETURN(3); }
2023  field->mdata = md;
2024  } else {
2025  int err = FmsMetaDataClear(md);
2026  if (err) { E_RETURN(err); }
2027  }
2028  *mdata = md;
2029  return 0;
2030 }
2031 
2032 
2033 /* -------------------------------------------------------------------------- */
2034 /* FmsMetaData functions: construction */
2035 /* -------------------------------------------------------------------------- */
2036 
2037 int FmsMetaDataSetIntegers(FmsMetaData mdata, const char *mdata_name,
2038  FmsIntType int_type, FmsInt size, void **data) {
2039  if (!mdata) { E_RETURN(1); }
2040  if (int_type >= FMS_NUM_INT_TYPES) { E_RETURN(2); }
2041  if (size && !data) { E_RETURN(3); }
2042  int err = FmsMetaDataClear(mdata);
2043  if (err) { E_RETURN(err); }
2044  const size_t sizeof_int_type = FmsIntTypeSize[int_type];
2045  void *md_data = size ? malloc(size*sizeof_int_type) : NULL;
2046  if (size && md_data == NULL) { E_RETURN(4); }
2047  // On error, call free(md_data)
2048  // Update mdata
2049  if (FmsCopyString(mdata_name, &mdata->name)) { free(md_data); E_RETURN(4); }
2050  mdata->md_type = FMS_INTEGER;
2051  mdata->sub_type.int_type = int_type;
2052  mdata->num_entries = size;
2053  mdata->data = md_data;
2054  *data = md_data;
2055  return 0;
2056 }
2057 
2058 int FmsMetaDataSetScalars(FmsMetaData mdata, const char *mdata_name,
2059  FmsScalarType scal_type, FmsInt size, void **data) {
2060  if (!mdata) { E_RETURN(1); }
2061  if (scal_type >= FMS_NUM_SCALAR_TYPES) { E_RETURN(2); }
2062  if (size && !data) { E_RETURN(3); }
2063  int err = FmsMetaDataClear(mdata);
2064  if (err) { E_RETURN(err); }
2065  const size_t sizeof_scal_type = FmsScalarTypeSize[scal_type];
2066  void *md_data = size ? malloc(size*sizeof_scal_type) : NULL;
2067  if (size && md_data == NULL) { E_RETURN(4); }
2068  // On error, call free(md_data)
2069  // Update mdata
2070  if (FmsCopyString(mdata_name, &mdata->name)) { free(md_data); E_RETURN(4); }
2071  mdata->md_type = FMS_SCALAR;
2072  mdata->sub_type.scalar_type = scal_type;
2073  mdata->num_entries = size;
2074  mdata->data = md_data;
2075  *data = md_data;
2076  return 0;
2077 }
2078 
2079 int FmsMetaDataSetString(FmsMetaData mdata, const char *mdata_name,
2080  const char *c_string) {
2081  if (!mdata) { E_RETURN(1); }
2082  int err = FmsMetaDataClear(mdata);
2083  if (err) { E_RETURN(err); }
2084  char *md_data;
2085  if (FmsCopyString(c_string, &md_data)) { E_RETURN(2); }
2086  // On error, call free(md_data)
2087  // Update mdata
2088  if (FmsCopyString(mdata_name, &mdata->name)) { free(md_data); E_RETURN(2); }
2089  mdata->md_type = FMS_STRING;
2090  mdata->num_entries = md_data ? strlen(md_data) : 0;
2091  mdata->data = md_data;
2092  return 0;
2093 }
2094 
2095 int FmsMetaDataSetMetaData(FmsMetaData mdata, const char *mdata_name,
2096  FmsInt size, FmsMetaData **data) {
2097  if (!mdata) { E_RETURN(1); }
2098  int err = FmsMetaDataClear(mdata);
2099  if (err) { E_RETURN(err); }
2100  char *name_copy;
2101  if (FmsCopyString(mdata_name, &name_copy)) { E_RETURN(2); }
2102  // On error, call free(name_copy)
2103  FmsMetaData *md_data = size ? malloc(size*sizeof(*md_data)) : NULL;
2104  if (size && md_data == NULL) { free(name_copy); E_RETURN(2); }
2105  // On error, call free(md_data)
2106  for (FmsInt i = 0; i < size; i++) {
2107  FmsMetaData md;
2108  md = calloc(1, sizeof(*md));
2109  if (md == NULL) {
2110  while (i != 0) { free(md_data[--i]); }
2111  free(md_data);
2112  free(name_copy);
2113  E_RETURN(2);
2114  }
2115  md_data[i] = md;
2116  }
2117  // Update mdata
2118  mdata->name = name_copy;
2119  mdata->md_type = FMS_META_DATA;
2120  mdata->num_entries = size;
2121  mdata->data = md_data;
2122  *data = md_data;
2123  return 0;
2124 }
2125 
2127  int err = 0;
2128  if (!mdata) { E_RETURN(1); }
2129  if (mdata->data) {
2130  switch (mdata->md_type) {
2131  case FMS_INTEGER:
2132  case FMS_SCALAR:
2133  case FMS_STRING: break;
2134  case FMS_META_DATA: {
2135  FmsMetaData *mds = (FmsMetaData*)(mdata->data);
2136  for (FmsInt i = mdata->num_entries; i != 0; ) {
2137  err = UpdateError(err, FmsMetaDataDestroy(&mds[--i]));
2138  }
2139  break;
2140  }
2141  default: err = UpdateError(err, 2);
2142  }
2143  free(mdata->data);
2144  mdata->data = NULL;
2145  }
2146  free(mdata->name);
2147  mdata->name = NULL;
2148  mdata->num_entries = 0;
2149  E_RETURN(err);
2150 }
2151 
2153  int err = 0;
2154  if (!mdata) { E_RETURN(1); }
2155  FmsMetaData md = *mdata;
2156  if (md) {
2157  err = UpdateError(err, FmsMetaDataClear(md));
2158  free(md);
2159  *mdata = NULL;
2160  }
2161  E_RETURN(err);
2162 }
2163 
2164 
2165 /* -------------------------------------------------------------------------- */
2166 /* FmsMesh functions: query interface */
2167 /* -------------------------------------------------------------------------- */
2168 
2169 int FmsMeshGetPartitionId(FmsMesh mesh, FmsInt *partition_id,
2170  FmsInt *num_partitions) {
2171  if (!mesh) { E_RETURN(1); }
2172  if (partition_id) { *partition_id = mesh->partition_id; }
2173  if (num_partitions) { *num_partitions = mesh->num_partitions; }
2174  return 0;
2175 }
2176 
2177 int FmsMeshGetNumDomainNames(FmsMesh mesh, FmsInt *num_domain_names) {
2178  if (!mesh) { E_RETURN(1); }
2179  if (!num_domain_names) { E_RETURN(2); }
2180  *num_domain_names = mesh->num_domain_names;
2181  return 0;
2182 }
2183 
2184 int FmsMeshGetDomains(FmsMesh mesh, FmsInt domain_name_id,
2185  const char **domain_name, FmsInt *num_domains,
2186  FmsDomain **domains) {
2187  if (!mesh) { E_RETURN(1); }
2188  if (domain_name_id >= mesh->num_domain_names) { E_RETURN(2); }
2189  if (domain_name) { *domain_name = mesh->domain_names[domain_name_id]; }
2190  if (num_domains) {
2191  *num_domains = mesh->domain_offsets[domain_name_id+1] -
2192  mesh->domain_offsets[domain_name_id];
2193  }
2194  if (domains) {
2195  *domains = mesh->domains + mesh->domain_offsets[domain_name_id];
2196  }
2197  return 0;
2198 }
2199 
2200 int FmsMeshGetDomainsByName(FmsMesh mesh, const char *domain_name,
2201  FmsInt *num_domains, FmsDomain **domains) {
2202  if (!mesh) { E_RETURN(1); }
2203  if (!domain_name) { E_RETURN(2); }
2204  const FmsInt num_domain_names = mesh->num_domain_names;
2205  char **domain_names = mesh->domain_names;
2206  FmsInt domain_name_id = 0;
2207  for ( ; 1; domain_name_id++) {
2208  if (domain_name_id == num_domain_names) { E_RETURN(4); }
2209  if (strcmp(domain_name, domain_names[domain_name_id]) == 0) { break; }
2210  }
2211  if (num_domains) {
2212  *num_domains = mesh->domain_offsets[domain_name_id+1] -
2213  mesh->domain_offsets[domain_name_id];
2214  }
2215  if (domains) {
2216  *domains = mesh->domains + mesh->domain_offsets[domain_name_id];
2217  }
2218  return 0;
2219 }
2220 
2222  if (!mesh) { E_RETURN(1); }
2223  if (!num_comp) { E_RETURN(2); }
2224  *num_comp = mesh->num_comps;
2225  return 0;
2226 }
2227 
2228 int FmsMeshGetComponent(FmsMesh mesh, FmsInt comp_id, FmsComponent *comp) {
2229  if (!mesh) { E_RETURN(1); }
2230  if (comp_id >= mesh->num_comps) { E_RETURN(2); }
2231  if (!comp) { E_RETURN(3); }
2232  *comp = mesh->comps[comp_id];
2233  return 0;
2234 }
2235 
2236 int FmsMeshGetNumTags(FmsMesh mesh, FmsInt *num_tags) {
2237  if (!mesh) { E_RETURN(1); }
2238  if (!num_tags) { E_RETURN(2); }
2239  *num_tags = mesh->num_tags;
2240  return 0;
2241 }
2242 
2243 int FmsMeshGetTag(FmsMesh mesh, FmsInt tag_id, FmsTag *tag) {
2244  if (!mesh) { E_RETURN(1); }
2245  if (tag_id >= mesh->num_tags) { E_RETURN(2); }
2246  if (!tag) { E_RETURN(3); }
2247  *tag = mesh->tags[tag_id];
2248  return 0;
2249 }
2250 
2251 
2252 /* -------------------------------------------------------------------------- */
2253 /* FmsDomain functions: query interface */
2254 /* -------------------------------------------------------------------------- */
2255 
2256 int FmsDomainGetName(FmsDomain domain, const char **domain_name,
2257  FmsInt *domain_id) {
2258  if (!domain) { E_RETURN(1); }
2259  if (domain_name) { *domain_name = domain->name; }
2260  if (domain_id) { *domain_id = domain->id; }
2261  return 0;
2262 }
2263 
2265  if (!domain) { E_RETURN(1); }
2266  if (!dim) { E_RETURN(2); }
2267  *dim = domain->dim;
2268  return 0;
2269 }
2270 
2271 int FmsDomainGetNumVertices(FmsDomain domain, FmsInt *num_verts) {
2272  if (!domain) { E_RETURN(1); }
2273  if (!num_verts) { E_RETURN(2); }
2274  *num_verts = domain->num_entities[FMS_VERTEX];
2275  return 0;
2276 }
2277 
2279  FmsInt *num_ents) {
2280  if (!domain) { E_RETURN(1); }
2281  if (type >= FMS_NUM_ENTITY_TYPES) { E_RETURN(2); }
2282  if (!num_ents) { E_RETURN(3); }
2283  *num_ents = domain->num_entities[type];
2284  return 0;
2285 }
2286 
2288  FmsIntType *ent_id_type, const void **ents,
2289  FmsInt *num_ents) {
2290  if (!domain) { E_RETURN(1); }
2291  if (type >= FMS_NUM_ENTITY_TYPES) { E_RETURN(2); }
2292  if (ent_id_type) { *ent_id_type = domain->side_ids_type[type]; }
2293  if (ents) { *ents = domain->entities[type]; }
2294  if (num_ents) { *num_ents = domain->num_entities[type]; }
2295  return 0;
2296 }
2297 
2299  FmsEntityReordering reordering, FmsIntType ent_id_type,
2300  FmsInt first_ent, void *ents, FmsInt num_ents) {
2301  if (!domain) { E_RETURN(1); }
2302  if (type == FMS_VERTEX || type >= FMS_NUM_ENTITY_TYPES) { E_RETURN(2); }
2303  if (ent_id_type >= FMS_NUM_INT_TYPES) { E_RETURN(3); }
2304  if (num_ents == 0) { return 0; }
2305  if (first_ent >= domain->num_entities[type]) { E_RETURN(4); }
2306  if (!ents) { E_RETURN(5); }
2307  if (first_ent + num_ents > domain->num_entities[type]) { E_RETURN(6); }
2308  void *src_ents = domain->entities[type];
2309  if (!src_ents) { E_RETURN(7); }
2310  const FmsIntType side_ids_type = domain->side_ids_type[type];
2311  const size_t sizeof_side_ids = FmsIntTypeSize[side_ids_type];
2312  const FmsInt num_sides = FmsEntityNumSides[type];
2313  src_ents = (char*)src_ents + first_ent*num_sides*sizeof_side_ids;
2314  if (reordering == NULL || reordering[type] == NULL) {
2315  FmsIntConvertCopy(side_ids_type, src_ents, ent_id_type, ents,
2316  num_ents*num_sides);
2317  } else {
2318  const int *perm = reordering[type];
2319  int inv_perm[num_sides]; // variable length array
2320  for (FmsInt i = 0; i < num_sides; i++) {
2321  inv_perm[perm[i]] = i;
2322  }
2323  FmsIntPermuteConvertCopy(side_ids_type, src_ents, ent_id_type, ents,
2324  inv_perm, num_sides, num_ents*num_sides);
2325  }
2326  return 0;
2327 }
2328 
2330  FmsEntityReordering vert_reordering,
2331  FmsIntType ent_id_type, FmsInt first_ent,
2332  void *ents_verts, FmsInt num_ents) {
2333  if (!domain) { E_RETURN(1); }
2334  if (type == FMS_VERTEX || type >= FMS_NUM_ENTITY_TYPES) { E_RETURN(2); }
2335  if (ent_id_type >= FMS_NUM_INT_TYPES) { E_RETURN(3); }
2336  if (num_ents == 0) { return 0; }
2337  if (first_ent >= domain->num_entities[type]) { E_RETURN(4); }
2338  if (!ents_verts) { E_RETURN(5); }
2339  if (first_ent + num_ents > domain->num_entities[type]) { E_RETURN(6); }
2340  const char *src_ents = domain->entities[type];
2341  if (!src_ents) { E_RETURN(7); }
2342  const FmsIntType idx_type = domain->side_ids_type[FMS_EDGE];
2343  if (idx_type != domain->side_ids_type[type]) { E_RETURN(8); }
2344  const FmsOrientation *side_ori = domain->orientations[type];
2345  if (type != FMS_EDGE && !side_ori) { E_RETURN(9); }
2346  const int *perm = vert_reordering ? vert_reordering[type] : NULL;
2347  const size_t sizeof_idx_type = FmsIntTypeSize[idx_type];
2348  const FmsInt num_verts = FmsEntityNumVerts[type];
2349  const FmsInt num_sides = FmsEntityNumSides[type];
2350  src_ents += first_ent*num_sides*sizeof_idx_type;
2351  if (type != FMS_EDGE) { side_ori += first_ent*num_sides; }
2352  switch (type) {
2353  case FMS_EDGE:
2354  if (!perm) {
2355  FmsIntConvertCopy(idx_type, src_ents, ent_id_type, ents_verts,
2356  num_ents*num_verts);
2357  } else {
2358  int inv_perm[2];
2359  for (FmsInt i = 0; i < 2; i++) { inv_perm[perm[i]] = i; }
2360  FmsIntPermuteConvertCopy(idx_type, src_ents, ent_id_type, ents_verts,
2361  inv_perm, num_verts, num_ents*num_verts);
2362  }
2363  break;
2364  case FMS_TRIANGLE: {
2365  const void *all_edges = domain->entities[FMS_EDGE];
2366  int inv_perm[3];
2367  if (perm) {
2368  for (FmsInt i = 0; i < 3; i++) { inv_perm[perm[i]] = i; }
2369  }
2370  const int bsize = 1024;
2371  FmsInt tri_vert[4*bsize]; // the vertices of the first two edges
2372  FmsInt tri_vert_x[3*bsize]; // vertices before applying the permutation
2373  for (FmsInt off = 0; off < num_ents; off += bsize) {
2374  const FmsInt sz = FmsIntMin(bsize, num_ents-off);
2375  // src_ents -> tri_vert
2376  FmsEntitiesToSides(idx_type, num_sides, 0, 2, src_ents, 2,
2377  all_edges, 4, 0, tri_vert, sz);
2378  // tri_vert + side_ori -> tri_vert_x
2379  for (FmsInt i = 0; i < sz; i++) {
2380  const FmsInt *tv = tri_vert+4*i;
2381  const FmsOrientation *eo = side_ori+3*i;
2382  FmsInt *verts = tri_vert_x+3*i;
2383  if (eo[0] == 0) {
2384  verts[0] = tv[0];
2385  verts[1] = tv[1];
2386  } else {
2387  verts[0] = tv[1];
2388  verts[1] = tv[0];
2389  }
2390  verts[2] = (eo[1] == 0) ? tv[3] : tv[2];
2391  }
2392  // tri_vert_x -> ents_verts, i.e. convert + vertex permutation
2393  if (!perm) {
2394  FmsIntConvertCopy(FMS_INT_TYPE, tri_vert_x, ent_id_type, ents_verts,
2395  sz*num_verts);
2396  } else {
2397  FmsIntPermuteConvertCopy(FMS_INT_TYPE, tri_vert_x, ent_id_type,
2398  ents_verts, inv_perm, num_verts, sz*num_sides);
2399  }
2400  src_ents += sz*num_sides*sizeof_idx_type;
2401  side_ori += sz*num_sides;
2402  ents_verts = (char*)ents_verts + sz*num_verts*FmsIntTypeSize[ent_id_type];
2403  }
2404  break;
2405  }
2406  case FMS_QUADRILATERAL: {
2407  const void *all_edges = domain->entities[FMS_EDGE];
2408  int inv_perm[4];
2409  if (perm) {
2410  for (FmsInt i = 0; i < 4; i++) { inv_perm[perm[i]] = i; }
2411  }
2412  const int bsize = 1024;
2413  FmsInt quad_vert[4*bsize]; // the vertices of edges 0 and 2
2414  FmsInt quad_vert_x[4*bsize]; // vertices before applying the permutation
2415  for (FmsInt off = 0; off < num_ents; off += bsize) {
2416  const FmsInt sz = FmsIntMin(bsize, num_ents-off);
2417  // src_ents -> quad_vert
2418  FmsEntitiesToSides(idx_type, num_sides, 0, 1, src_ents, 2,
2419  all_edges, 4, 0, quad_vert, sz);
2420  FmsEntitiesToSides(idx_type, num_sides, 2, 1, src_ents, 2,
2421  all_edges, 4, 2, quad_vert, sz);
2422  // quad_vert + side_ori -> quad_vert_x
2423  for (FmsInt i = 0; i < sz; i++) {
2424  const FmsInt *qv = quad_vert+4*i;
2425  const FmsOrientation *eo = side_ori+4*i;
2426  FmsInt *verts = quad_vert_x+4*i;
2427  if (eo[0] == 0) {
2428  verts[0] = qv[0];
2429  verts[1] = qv[1];
2430  } else {
2431  verts[0] = qv[1];
2432  verts[1] = qv[0];
2433  }
2434  if (eo[2] == 0) {
2435  verts[2] = qv[2];
2436  verts[3] = qv[3];
2437  } else {
2438  verts[2] = qv[3];
2439  verts[3] = qv[2];
2440  }
2441  }
2442  // quad_vert_x -> ents_verts, i.e. convert + vertex permutation
2443  if (!perm) {
2444  FmsIntConvertCopy(FMS_INT_TYPE, quad_vert_x, ent_id_type, ents_verts,
2445  sz*num_verts);
2446  } else {
2447  FmsIntPermuteConvertCopy(FMS_INT_TYPE, quad_vert_x, ent_id_type,
2448  ents_verts, inv_perm, num_verts, sz*num_sides);
2449  }
2450  src_ents += sz*num_sides*sizeof_idx_type;
2451  side_ori += sz*num_sides;
2452  ents_verts = (char*)ents_verts + sz*num_verts*FmsIntTypeSize[ent_id_type];
2453  }
2454  break;
2455  }
2456  case FMS_TETRAHEDRON: {
2457  if (idx_type != domain->side_ids_type[FMS_TRIANGLE]) { E_RETURN(10); }
2458  const void *all_edges = domain->entities[FMS_EDGE];
2459  const void *all_tris = domain->entities[FMS_TRIANGLE];
2460  const FmsOrientation *tri_side_ori = domain->orientations[FMS_TRIANGLE];
2461  if (!tri_side_ori) { E_RETURN(11); }
2462  int inv_perm[4];
2463  if (perm) {
2464  for (FmsInt i = 0; i < 4; i++) { inv_perm[perm[i]] = i; }
2465  }
2466  const int bsize = 1024;
2467  FmsInt tet_face[4*bsize]; // the 4 faces of the tets
2468  FmsInt tet_edge[6*bsize]; // the edges of faces B and C
2469  FmsInt tet_vert_x[4*bsize]; // vertices before applying the permutation
2470  for (FmsInt off = 0; off < num_ents; off += bsize) {
2471  const FmsInt sz = FmsIntMin(bsize, num_ents-off);
2472  // src_ents -> tet_face
2473  FmsIntConvertCopy(idx_type, src_ents, FMS_INT_TYPE, tet_face, sz*4);
2474  // src_ents -> tet_edge
2475  FmsEntitiesToSides(idx_type, num_sides, 1, 2, src_ents, 3,
2476  all_tris, 6, 0, tet_edge, sz);
2477  // tet_edge -> tet_edge[mod]
2478  for (FmsInt i = 0; i < sz; i++) {
2479  const FmsInt *tf = tet_face+4*i;
2480  const FmsInt *te = tet_edge+6*i;
2481  const FmsOrientation *so = side_ori+4*i;
2482  FmsInt eo[6]; // side (edge) orientations for faces B and C
2483  FmsInt te_x[6], eo_x[6];
2484  for (int j = 0; j < 2; j++) {
2485  for (int e = 0; e < 3; e++) {
2486  eo[3*j+e] = tri_side_ori[3*tf[j+1]+e];
2487  }
2488  }
2489  if (so[1] == FMS_ORIENTATION_UNKNOWN ||
2490  so[2] == FMS_ORIENTATION_UNKNOWN) {
2491  E_RETURN(12);
2492  }
2493  FmsPermuteTriBdr(so[1], te+0, te_x+0);
2494  FmsPermuteTriBdr(so[1], eo+0, eo_x+0);
2495  if (so[1]%2) { for (int j = 0; j < 3; j++) { eo_x[j] = 1-eo_x[j]; } }
2496  FmsPermuteTriBdr(so[2], te+3, te_x+3);
2497  FmsPermuteTriBdr(so[2], eo+3, eo_x+3);
2498  if (so[2]%2) { for (int j = 3; j < 6; j++) { eo_x[j] = 1-eo_x[j]; } }
2499 #ifndef NDEBUG
2500  if (te_x[2] != te_x[4]) { FmsInternalError(); }
2501  if (eo_x[2] != 1-eo_x[4]) { FmsInternalError(); }
2502 #endif
2503  tet_edge[2*i+0] = te_x[0];
2504  tet_edge[2*i+1] = te_x[5];
2505  tet_face[2*i+0] = eo_x[0];
2506  tet_face[2*i+1] = eo_x[5];
2507  }
2508  // tet_edge[mod] -> tet_vert_x[mod]
2509  FmsIntConvertCopy(FMS_INT_TYPE, tet_edge,
2510  idx_type, &tet_edge[2*bsize], 2*sz);
2511  FmsEntitiesToSides(idx_type, 2*sz, 0, 2*sz, &tet_edge[2*bsize],
2512  2, all_edges, 4*sz, 0, tet_vert_x, 1);
2513  // tet_vert_x[mod] -> tet_vert_x
2514  for (FmsInt i = 0; i < sz; i++) {
2515  FmsInt *tv = tet_vert_x+4*i, z;
2516  if (tet_face[2*i+0] != 0) {
2517  z = tv[0];
2518  tv[0] = tv[1];
2519  tv[1] = z;
2520  }
2521  if (tet_face[2*i+1] == 0) {
2522  z = tv[2];
2523  tv[2] = tv[3];
2524  tv[3] = z;
2525  }
2526  }
2527  // tet_vert_x -> ents_verts, i.e. convert + vertex permutation
2528  if (!perm) {
2529  FmsIntConvertCopy(FMS_INT_TYPE, tet_vert_x, ent_id_type, ents_verts,
2530  sz*num_verts);
2531  } else {
2532  FmsIntPermuteConvertCopy(FMS_INT_TYPE, tet_vert_x, ent_id_type,
2533  ents_verts, inv_perm, num_verts, sz*num_sides);
2534  }
2535  src_ents += sz*num_sides*sizeof_idx_type;
2536  side_ori += sz*num_sides;
2537  ents_verts = (char*)ents_verts + sz*num_verts*FmsIntTypeSize[ent_id_type];
2538  }
2539  break;
2540  }
2541  case FMS_HEXAHEDRON: {
2542  if (idx_type != domain->side_ids_type[FMS_QUADRILATERAL]) { E_RETURN(10); }
2543  const void *all_edges = domain->entities[FMS_EDGE];
2544  const void *all_quads = domain->entities[FMS_QUADRILATERAL];
2545  const FmsOrientation *quad_side_ori =
2546  domain->orientations[FMS_QUADRILATERAL];
2547  if (!quad_side_ori) { E_RETURN(11); }
2548  int inv_perm[8];
2549  if (perm) {
2550  for (FmsInt i = 0; i < 8; i++) { inv_perm[perm[i]] = i; }
2551  }
2552  const int bsize = 1024;
2553  FmsInt hex_face[6*bsize]; // the 6 faces of the hexes
2554  FmsInt hex_edge[8*bsize]; // the edges of faces A and B
2555  FmsInt hex_vert_x[8*bsize]; // vertices before applying the permutation
2556  for (FmsInt off = 0; off < num_ents; off += bsize) {
2557  const FmsInt sz = FmsIntMin(bsize, num_ents-off);
2558  // src_ents -> hex_face
2559  FmsIntConvertCopy(idx_type, src_ents, FMS_INT_TYPE, hex_face, sz*6);
2560  // src_ents -> hex_edge
2561  FmsEntitiesToSides(idx_type, num_sides, 0, 2, src_ents, 4,
2562  all_quads, 8, 0, hex_edge, sz);
2563  // hex_edge -> hex_edge[mod]
2564  for (FmsInt i = 0; i < sz; i++) {
2565  const FmsInt *hf = hex_face+6*i;
2566  const FmsInt *he = hex_edge+8*i;
2567  const FmsOrientation *so = side_ori+6*i;
2568  FmsInt eo[8]; // side (edge) orientations for faces A and B
2569  FmsInt he_x[8], eo_x[8];
2570  for (int j = 0; j < 2; j++) {
2571  for (int e = 0; e < 4; e++) {
2572  eo[4*j+e] = quad_side_ori[4*hf[j]+e];
2573  }
2574  }
2575  if (so[0] == FMS_ORIENTATION_UNKNOWN ||
2576  so[1] == FMS_ORIENTATION_UNKNOWN) {
2577  E_RETURN(12);
2578  }
2579  FmsPermuteQuadBdr(so[0], he+0, he_x+0);
2580  FmsPermuteQuadBdr(so[0], eo+0, eo_x+0);
2581  if (so[0]%2) { for (int j = 0; j < 4; j++) { eo_x[j] = 1-eo_x[j]; } }
2582  FmsPermuteQuadBdr(so[1], he+4, he_x+4);
2583  FmsPermuteQuadBdr(so[1], eo+4, eo_x+4);
2584  if (so[1]%2) { for (int j = 4; j < 8; j++) { eo_x[j] = 1-eo_x[j]; } }
2585  hex_edge[4*i+0] = he_x[0];
2586  hex_edge[4*i+1] = he_x[2];
2587  hex_edge[4*i+2] = he_x[4];
2588  hex_edge[4*i+3] = he_x[6];
2589  hex_face[4*i+0] = eo_x[0];
2590  hex_face[4*i+1] = eo_x[2];
2591  hex_face[4*i+2] = eo_x[4];
2592  hex_face[4*i+3] = eo_x[6];
2593  }
2594  // hex_edge[mod] -> hex_vert_x[mod]
2595  FmsIntConvertCopy(FMS_INT_TYPE, hex_edge,
2596  idx_type, &hex_edge[4*bsize], 4*sz);
2597  FmsEntitiesToSides(idx_type, 4*sz, 0, 4*sz, &hex_edge[4*bsize],
2598  2, all_edges, 8*sz, 0, hex_vert_x, 1);
2599  // hex_vert_x[mod] -> hex_vert_x
2600  for (FmsInt i = 0; i < sz; i++) {
2601  FmsInt *hv = hex_vert_x+8*i, z;
2602  if (hex_face[4*i+0] == 0) {
2603  z = hv[0];
2604  hv[0] = hv[1];
2605  hv[1] = z;
2606  }
2607  if (hex_face[4*i+1] == 0) {
2608  z = hv[2];
2609  hv[2] = hv[3];
2610  hv[3] = z;
2611  }
2612  if (hex_face[4*i+2] != 0) {
2613  z = hv[4];
2614  hv[4] = hv[5];
2615  hv[5] = z;
2616  }
2617  if (hex_face[4*i+3] != 0) {
2618  z = hv[6];
2619  hv[6] = hv[7];
2620  hv[7] = z;
2621  }
2622  }
2623  // hex_vert_x -> ents_verts, i.e. convert + vertex permutation
2624  if (!perm) {
2625  FmsIntConvertCopy(FMS_INT_TYPE, hex_vert_x, ent_id_type, ents_verts,
2626  sz*num_verts);
2627  } else {
2628  FmsIntPermuteConvertCopy(FMS_INT_TYPE, hex_vert_x, ent_id_type,
2629  ents_verts, inv_perm, num_verts, sz*num_sides);
2630  }
2631  src_ents += sz*num_sides*sizeof_idx_type;
2632  side_ori += sz*num_sides;
2633  ents_verts = (char*)ents_verts + sz*num_verts*FmsIntTypeSize[ent_id_type];
2634  }
2635  break;
2636  }
2637  case FMS_WEDGE:
2638  case FMS_PYRAMID:
2639  default: FmsAbortNotImplemented();
2640  }
2641  return 0;
2642 }
2643 
2645  const FmsOrientation **side_orients,
2646  FmsInt *num_ents) {
2647  if (!domain) { E_RETURN(1); }
2648  if (type >= FMS_NUM_ENTITY_TYPES) { E_RETURN(2); }
2649  if (side_orients) { *side_orients = domain->orientations[type]; }
2650  if (num_ents) { *num_ents = domain->num_entities[type]; }
2651  return 0;
2652 }
2653 
2654 
2655 /* -------------------------------------------------------------------------- */
2656 /* FmsComponent functions: query interface */
2657 /* -------------------------------------------------------------------------- */
2658 
2659 int FmsComponentGetName(FmsComponent comp, const char **comp_name) {
2660  if (!comp) { E_RETURN(1); }
2661  if (comp_name) { *comp_name = comp->name; }
2662  return 0;
2663 }
2664 
2666  if (!comp) { E_RETURN(1); }
2667  if (dim) { *dim = comp->dim; }
2668  return 0;
2669 }
2670 
2672  if (!comp) { E_RETURN(1); }
2673  if (num_parts) { *num_parts = comp->num_parts; }
2674  return 0;
2675 }
2676 
2678  FmsDomain *domain, FmsIntType *ent_id_type,
2679  const void **ents, const FmsOrientation **ent_orients,
2680  FmsInt *num_ents) {
2681  if (!comp) { E_RETURN(1); }
2682  if (part_id >= comp->num_parts) { E_RETURN(2); }
2683  if (type >= FMS_NUM_ENTITY_TYPES) { E_RETURN(3); }
2684  // if (FmsEntityDim[type] != comp->dim) { E_RETURN(4); }
2685  struct _FmsPart_private *part = &comp->parts[part_id];
2686  if (domain) { *domain = part->domain; }
2687  if (ent_id_type) { *ent_id_type = part->entities_ids_type[type]; }
2688  if (ents) { *ents = part->entities_ids[type]; }
2689  if (ent_orients) { *ent_orients = part->orientations[type]; }
2690  if (num_ents) { *num_ents = part->num_entities[type]; }
2691  return 0;
2692 }
2693 
2695  FmsEntityType type, FmsIntType *ent_id_type,
2696  const void **ents, FmsInt *num_ents) {
2697  if (!comp) { E_RETURN(1); }
2698  if (part_id >= comp->num_parts) { E_RETURN(2); }
2699  if (type >= FMS_NUM_ENTITY_TYPES) { E_RETURN(3); }
2700  // if (FmsEntityDim[type] >= comp->dim) { E_RETURN(4); }
2701  struct _FmsPart_private *part = &comp->parts[part_id];
2702  if (ent_id_type) { *ent_id_type = part->entities_ids_type[type]; }
2703  if (ents) { *ents = part->entities_ids[type]; }
2704  if (num_ents) { *num_ents = part->num_entities[type]; }
2705  return 0;
2706 }
2707 
2709  if (!comp) { E_RETURN(1); }
2710  if (num_ents) { *num_ents = comp->num_main_entities; }
2711  return 0;
2712 }
2713 
2714 int FmsComponentGetRelations(FmsComponent comp, const FmsInt **rel_comps,
2715  FmsInt *num_rel_comps) {
2716  if (!comp) { E_RETURN(1); }
2717  if (rel_comps) { *rel_comps = comp->relations; }
2718  if (num_rel_comps) { *num_rel_comps = comp->num_relations; }
2719  return 0;
2720 }
2721 
2723  if (!comp) { E_RETURN(1); }
2724  if (coords) { *coords = comp->coordinates; }
2725  return 0;
2726 }
2727 
2728 
2729 /* -------------------------------------------------------------------------- */
2730 /* FmsTag functions: query interface */
2731 /* -------------------------------------------------------------------------- */
2732 
2733 int FmsTagGetName(FmsTag tag, const char **tag_name) {
2734  if (!tag) { E_RETURN(1); }
2735  if (tag_name) { *tag_name = tag->name; }
2736  return 0;
2737 }
2738 
2740  if (!tag) { E_RETURN(1); }
2741  if (comp) { *comp = tag->comp; }
2742  return 0;
2743 }
2744 
2745 int FmsTagGet(FmsTag tag, FmsIntType *tag_type, const void **ent_tags,
2746  FmsInt *num_ents) {
2747  if (!tag) { E_RETURN(1); }
2748  if (tag_type) { *tag_type = tag->tag_type; }
2749  if (ent_tags) { *ent_tags = tag->tags; }
2750  if (num_ents) { *num_ents = tag->comp->num_main_entities; }
2751  return 0;
2752 }
2753 
2754 int FmsTagGetDescriptions(FmsTag tag, FmsIntType *tag_type, const void **tags,
2755  const char *const **tag_descr, FmsInt *num_tags) {
2756  if (!tag) { E_RETURN(1); }
2757  if (tag_type) { *tag_type = tag->tag_type; }
2758  if (tags) { *tags = tag->described_tags; }
2759  if (tag_descr) {
2760  // without the explicit typecast, there is a warning; why?
2761  *tag_descr = (const char *const *)(tag->tag_descriptions);
2762  }
2763  if (num_tags) { *num_tags = tag->num_tag_descriptions; }
2764  return 0;
2765 }
2766 
2767 
2768 /* -------------------------------------------------------------------------- */
2769 /* FmsDataCollection functions: query interface */
2770 /* -------------------------------------------------------------------------- */
2771 
2772 int FmsDataCollectionGetName(FmsDataCollection dc, const char **name) {
2773  if (!dc) { E_RETURN(1); }
2774  if (!name) { E_RETURN(2); }
2775  *name = dc->name;
2776  return 0;
2777 }
2778 
2780  if (!dc) { E_RETURN(1); }
2781  if (!mesh) { E_RETURN(2); }
2782  *mesh = dc->mesh;
2783  return 0;
2784 }
2785 
2787  FmsFieldDescriptor **fds, FmsInt *num_fds) {
2788  if (!dc) { E_RETURN(1); }
2789  if (fds) { *fds = dc->fds; }
2790  if (num_fds) { *num_fds = dc->num_fds; }
2791  return 0;
2792 }
2793 
2795  FmsInt *num_fields) {
2796  if (!dc) { E_RETURN(1); }
2797  if (fields) { *fields = dc->fields; }
2798  if (num_fields) { *num_fields = dc->num_fields; }
2799  return 0;
2800 }
2801 
2803  if (!dc) { E_RETURN(1); }
2804  if (!mdata) { E_RETURN(2); }
2805  *mdata = dc->mdata;
2806  return 0;
2807 }
2808 
2809 
2810 /* -------------------------------------------------------------------------- */
2811 /* FmsFieldDescriptor functions: query interface */
2812 /* -------------------------------------------------------------------------- */
2813 
2814 int FmsFieldDescriptorGetName(FmsFieldDescriptor fd, const char **fd_name) {
2815  if (!fd) { E_RETURN(1); }
2816  if (!fd_name) { E_RETURN(2); }
2817  *fd_name = fd->name;
2818  return 0;
2819 }
2820 
2822  if (!fd) { E_RETURN(1); }
2823  if (!comp) { E_RETURN(2); }
2824  *comp = fd->component;
2825  return 0;
2826 }
2827 
2829  FmsFieldDescriptorType *fd_type) {
2830  if (!fd) { E_RETURN(1); }
2831  if (!fd_type) { E_RETURN(2); }
2832  *fd_type = fd->descr_type;
2833  return 0;
2834 }
2835 
2837  FmsFieldType *field_type,
2838  FmsBasisType *basis_type, FmsInt *order) {
2839  if (!fd) { E_RETURN(1); }
2840  struct _FmsFieldDescriptor_FixedOrder *fo = fd->descriptor.fixed_order;
2841  if (field_type) { *field_type = fo->field_type; }
2842  if (basis_type) { *basis_type = fo->basis_type; }
2843  if (order) { *order = fo->order; }
2844  return 0;
2845 }
2846 
2848  if (!fd) { E_RETURN(1); }
2849  if (!num_dofs) { E_RETURN(2); }
2850  *num_dofs = fd->num_dofs;
2851  return 0;
2852 }
2853 
2854 
2855 /* -------------------------------------------------------------------------- */
2856 /* FmsField functions: query interface */
2857 /* -------------------------------------------------------------------------- */
2858 
2859 int FmsFieldGetName(FmsField field, const char **field_name) {
2860  if (!field) { E_RETURN(1); }
2861  if (!field_name) { E_RETURN(2); }
2862  *field_name = field->name;
2863  return 0;
2864 }
2865 
2866 int FmsFieldGet(FmsField field, FmsFieldDescriptor *fd, FmsInt *num_vec_comp,
2867  FmsLayoutType *layout_type, FmsScalarType *data_type,
2868  const void **data) {
2869  if (!field) { E_RETURN(1); }
2870  if (fd) { *fd = field->fd; }
2871  if (num_vec_comp) { *num_vec_comp = field->num_vec_comp; }
2872  if (layout_type) { *layout_type = field->layout; }
2873  if (data_type) { *data_type = field->scalar_type; }
2874  if (data) { *data = field->data; }
2875  return 0;
2876 }
2877 
2879  if (!field) { E_RETURN(1); }
2880  if (!mdata) { E_RETURN(2); }
2881  *mdata = field->mdata;
2882  return 0;
2883 }
2884 
2885 
2886 /* -------------------------------------------------------------------------- */
2887 /* FmsMetaData functions: query interface */
2888 /* -------------------------------------------------------------------------- */
2889 
2891  if (!mdata) { E_RETURN(1); }
2892  if (!type) { E_RETURN(2); }
2893  *type = mdata->md_type;
2894  return 0;
2895 }
2896 
2897 int FmsMetaDataGetIntegers(FmsMetaData mdata, const char **mdata_name,
2898  FmsIntType *int_type, FmsInt *size,
2899  const void **data) {
2900  if (!mdata) { E_RETURN(1); }
2901  if (mdata_name) { *mdata_name = mdata->name; }
2902  if (int_type) { *int_type = mdata->sub_type.int_type; }
2903  if (size) { *size = mdata->num_entries; }
2904  if (data) { *data = mdata->data; }
2905  return 0;
2906 }
2907 
2908 int FmsMetaDataGetScalars(FmsMetaData mdata, const char **mdata_name,
2909  FmsScalarType *scal_type, FmsInt *size,
2910  const void **data) {
2911  if (!mdata) { E_RETURN(1); }
2912  if (mdata_name) { *mdata_name = mdata->name; }
2913  if (scal_type) { *scal_type = mdata->sub_type.scalar_type; }
2914  if (size) { *size = mdata->num_entries; }
2915  if (data) { *data = mdata->data; }
2916  return 0;
2917 }
2918 
2919 int FmsMetaDataGetString(FmsMetaData mdata, const char **mdata_name,
2920  const char **c_string) {
2921  if (!mdata) { E_RETURN(1); }
2922  if (mdata_name) { *mdata_name = mdata->name; }
2923  if (c_string) { *c_string = mdata->data; }
2924  return 0;
2925 }
2926 
2927 int FmsMetaDataGetMetaData(FmsMetaData mdata, const char **mdata_name,
2928  FmsInt *size, FmsMetaData **data) {
2929  if (!mdata) { E_RETURN(1); }
2930  if (mdata_name) { *mdata_name = mdata->name; }
2931  if (size) { *size = mdata->num_entries; }
2932  if (data) { *data = mdata->data; }
2933  return 0;
2934 }
2935 
2936 /* -------------------------------------------------------------------------- */
2937 /* Compare interface */
2938 /* -------------------------------------------------------------------------- */
2939 static inline double FmsAbs(const double x) {
2940  if(x < 0.) return -x;
2941  return x;
2942 }
2943 
2944 // Q: Does this need to be a smarter algorithm?
2945 #define COMPARE_SCALAR_DATA(T, lhs, rhs, n, OUT_FmsInt_isdifferent) \
2946  do { \
2947  const T *lhs_data = (const T*)lhs; \
2948  const T *rhs_data = (const T*)rhs; \
2949  const FmsInt N = n; \
2950  OUT_FmsInt_isdifferent = 0; \
2951  for(FmsInt i = 0; i < N; i++) { \
2952  if(FmsAbs(lhs_data[i] - rhs_data[i]) > 1e-6) { \
2953  OUT_FmsInt_isdifferent = i+1; \
2954  break; \
2955  } \
2956  } \
2957  } while(0)
2958 
2959 #define COMPARE_INT_DATA(T, lhs, rhs, n, OUT_FmsInt_isdifferent) \
2960  do { \
2961  const T *lhs_data = (const T*)lhs; \
2962  const T *rhs_data = (const T*)rhs; \
2963  const FmsInt N = n; \
2964  OUT_FmsInt_isdifferent = 0; \
2965  for(FmsInt i = 0; i < N; i++) { \
2966  if(lhs_data[i] != rhs_data[i]) { \
2967  OUT_FmsInt_isdifferent = i+1; \
2968  break; \
2969  } \
2970  } \
2971  } while(0)
2972 
2973 static inline FmsInt CompareScalarData(FmsScalarType stype, FmsInt size,
2974  const void *lhs, const void *rhs) {
2975  if(lhs == rhs) return 0;
2976  if(!lhs) return 1;
2977  if(!rhs) return 1;
2978  FmsInt isDifferent = 0;
2979  switch(stype) {
2980  case FMS_FLOAT:
2981  COMPARE_SCALAR_DATA(float, lhs, rhs, size, isDifferent);
2982  break;
2983  case FMS_DOUBLE:
2984  COMPARE_SCALAR_DATA(double, lhs, rhs, size, isDifferent);
2985  break;
2986  case FMS_COMPLEX_FLOAT:
2987  COMPARE_SCALAR_DATA(float, lhs, rhs, size*2, isDifferent);
2988  break;
2989  case FMS_COMPLEX_DOUBLE:
2990  COMPARE_SCALAR_DATA(double, lhs, rhs, size*2, isDifferent);
2991  break;
2992  default:
2993  return 2;
2994  }
2995  return isDifferent;
2996 }
2997 
2998 static inline FmsInt CompareIntData(FmsIntType itype, FmsInt size,
2999  const void *lhs, const void *rhs) {
3000  if(lhs == rhs) return 0;
3001  if(!lhs) return 1;
3002  if(!rhs) return 1;
3003  FmsInt isDifferent = 0;
3004  switch(itype) {
3005  case FMS_INT8:
3006  COMPARE_INT_DATA(int8_t, lhs, rhs, size, isDifferent);
3007  break;
3008  case FMS_INT16:
3009  COMPARE_INT_DATA(int16_t, lhs, rhs, size, isDifferent);
3010  break;
3011  case FMS_INT32:
3012  COMPARE_INT_DATA(int32_t, lhs, rhs, size, isDifferent);
3013  break;
3014  case FMS_INT64:
3015  COMPARE_INT_DATA(int64_t, lhs, rhs, size, isDifferent);
3016  break;
3017  case FMS_UINT8:
3018  COMPARE_INT_DATA(uint8_t, lhs, rhs, size, isDifferent);
3019  break;
3020  case FMS_UINT16:
3021  COMPARE_INT_DATA(uint16_t, lhs, rhs, size, isDifferent);
3022  break;
3023  case FMS_UINT32:
3024  COMPARE_INT_DATA(uint32_t, lhs, rhs, size, isDifferent);
3025  break;
3026  case FMS_UINT64:
3027  COMPARE_INT_DATA(uint64_t, lhs, rhs, size, isDifferent);
3028  break;
3029  default:
3030  return 2;
3031  }
3032  return isDifferent;
3033 }
3034 
3036  if(lhs == rhs) return 0;
3037  if(!lhs) return -1;
3038  if(!rhs) return -2;
3039  // Compare names
3040  int diff = 0;
3041  const char *lhs_name = NULL;
3042  const char *rhs_name = NULL;
3043  FmsDataCollectionGetName(lhs, &lhs_name);
3044  FmsDataCollectionGetName(rhs, &rhs_name);
3045  if(strcmp(lhs_name, rhs_name)) {
3046  diff += 1;
3047  }
3048 
3049  // Compare mesh topologies
3050  FmsMesh lhs_mesh = NULL, rhs_mesh = NULL;
3051  FmsDataCollectionGetMesh(lhs, &lhs_mesh);
3052  FmsDataCollectionGetMesh(rhs, &rhs_mesh);
3053  if(FmsMeshCompare(lhs_mesh, rhs_mesh)) {
3054  diff += 10;
3055  }
3056 
3057  // Compare FieldDescriptors
3058  FmsFieldDescriptor *lhs_fds = NULL, *rhs_fds = NULL;
3059  FmsInt lhs_nfds = 0, rhs_nfds = -1;
3060  FmsDataCollectionGetFieldDescriptors(lhs, &lhs_fds, &lhs_nfds);
3061  FmsDataCollectionGetFieldDescriptors(rhs, &rhs_fds, &rhs_nfds);
3062  if(lhs_nfds != rhs_nfds) {
3063  diff += 100;
3064  } else {
3065  for(FmsInt i = 0; i < lhs_nfds; i++) {
3066  if(FmsFieldDescriptorCompare(lhs_fds[i], rhs_fds[i])) {
3067  diff += 100;
3068  }
3069  }
3070  }
3071 
3072  // Compare Fields
3073  FmsField *lhs_fields = NULL, *rhs_fields = NULL;
3074  FmsInt lhs_nfields = 0, rhs_nfields = -1;
3075  FmsDataCollectionGetFields(lhs, &lhs_fields, &lhs_nfields);
3076  FmsDataCollectionGetFields(rhs, &rhs_fields, &rhs_nfields);
3077  if(lhs_nfds != rhs_nfds) {
3078  diff += 1000;
3079  } else {
3080  for(FmsInt i = 0; i < lhs_nfds; i++) {
3081  if(FmsFieldCompare(lhs_fields[i], rhs_fields[i])) {
3082  diff += 1000;
3083  }
3084  }
3085  }
3086 
3087  // Compare MetaData
3088  FmsMetaData lhs_md = NULL, rhs_md = NULL;
3089  FmsDataCollectionGetMetaData(lhs, &lhs_md);
3090  FmsDataCollectionGetMetaData(rhs, &rhs_md);
3091  if(FmsMetaDataCompare(lhs_md, rhs_md)) {
3092  diff += 10000;
3093  }
3094  return diff;
3095 }
3096 
3098  if(lhs == rhs) return 0;
3099  if(!lhs) return -1;
3100  if(!rhs) return -2;
3101  int diff = 0;
3102  // Compare domain names size
3103  FmsInt lhs_ndnames = 0, rhs_ndnames = -1;
3104  FmsMeshGetNumDomainNames(lhs, &lhs_ndnames);
3105  FmsMeshGetNumDomainNames(rhs, &rhs_ndnames);
3106 
3107  // Compare domain names & domains
3108  if(lhs_ndnames != rhs_ndnames) {
3109  diff += 1;
3110  } else {
3111  for(FmsInt i = 0; i < lhs_ndnames; i++) {
3112  const char *lhs_dname = NULL, *rhs_dname = NULL;
3113  FmsInt lhs_ndomains = 0, rhs_ndomains = -1;
3114  FmsDomain *lhs_domains = NULL, *rhs_domains = NULL;
3115  FmsMeshGetDomains(lhs, i, &lhs_dname, &lhs_ndomains, &lhs_domains);
3116  FmsMeshGetDomains(rhs, i, &rhs_dname, &rhs_ndomains, &rhs_domains);
3117  if(strcmp(lhs_dname, rhs_dname)) {
3118  diff += 10;
3119  continue;
3120  }
3121  if(lhs_ndomains != rhs_ndomains) {
3122  diff += 10;
3123  continue;
3124  }
3125  for(FmsInt j = 0; j < lhs_ndnames; j++) {
3126  if(FmsDomainCompare(lhs_domains[j], rhs_domains[j])) {
3127  diff += 100;
3128  }
3129  }
3130  }
3131  }
3132 
3133  // Compare components
3134  FmsInt lhs_ncomponents = 0, rhs_ncomponents = -1;
3135  FmsMeshGetNumComponents(lhs, &lhs_ncomponents);
3136  FmsMeshGetNumComponents(rhs, &rhs_ncomponents);
3137  if(lhs_ncomponents != rhs_ncomponents) {
3138  diff += 1000;
3139  } else {
3140  for(FmsInt i = 0; i < lhs_ncomponents; i++) {
3141  FmsComponent lhs_component = NULL, rhs_component = NULL;
3142  FmsMeshGetComponent(lhs, i, &lhs_component);
3143  FmsMeshGetComponent(rhs, i, &rhs_component);
3144  if(FmsComponentCompare(lhs_component, rhs_component)) {
3145  diff += 1000;
3146  }
3147  }
3148  }
3149 
3150  // Compare tags
3151  FmsInt lhs_ntags = 0, rhs_ntags = -1;
3152  FmsMeshGetNumTags(lhs, &lhs_ntags);
3153  FmsMeshGetNumTags(rhs, &rhs_ntags);
3154  if(lhs_ntags != rhs_ntags) {
3155  diff += 10000;
3156  } else {
3157  for(FmsInt i = 0; i < lhs_ntags; i++) {
3158  FmsTag lhs_tag = NULL, rhs_tag = NULL;
3159  FmsMeshGetTag(lhs, i, &lhs_tag);
3160  FmsMeshGetTag(rhs, i, &rhs_tag);
3161  if(FmsTagCompare(lhs_tag, rhs_tag)) {
3162  diff += 10000;
3163  }
3164  }
3165  }
3166 
3167  // Q: Should we actually compare PartitionId?
3168  // I feel like if two meshes identical meshes came from two different partitions
3169  // then we should say they are equal.
3170  // FmsMeshGetPartitionId
3171  return diff;
3172 }
3173 
3175  if(lhs == rhs) return 0;
3176  if(!lhs) return -1;
3177  if(!rhs) return -2;
3178  int diff = 0;
3179 
3180  if(strcmp(lhs->name, rhs->name)) {
3181  diff += 1;
3182  }
3183 
3184  if(lhs->descr_type != rhs->descr_type) {
3185  diff += 10;
3186  } else {
3187  if(lhs->descr_type == FMS_FIXED_ORDER) {
3188  // Make sure both of their fixed orders have been set
3189  if(lhs->descriptor.fixed_order && rhs->descriptor.fixed_order) {
3190  if(lhs->descriptor.fixed_order->basis_type !=
3191  rhs->descriptor.fixed_order->basis_type) {
3192  diff += 100;
3193  }
3194  if(lhs->descriptor.fixed_order->field_type !=
3195  rhs->descriptor.fixed_order->field_type) {
3196  diff += 1000;
3197  }
3198  if(lhs->descriptor.fixed_order->order != rhs->descriptor.fixed_order->order) {
3199  diff += 10000;
3200  }
3201  } else if(!lhs->descriptor.fixed_order) {
3202  diff += 20;
3203  } else if(!rhs->descriptor.fixed_order) {
3204  diff += 30;
3205  }
3206  } else {
3207  // TODO: Update this when it's possible to set a non fixed order.
3208  }
3209  }
3210 
3211  if(lhs->num_dofs != rhs->num_dofs) {
3212  diff += 100000;
3213  }
3214 
3215  // If they have the same num_dofs & the same component name, probably okay
3216  // If we call FmsComponentCompare here we end up with endless recursion
3217  if(diff == 0) {
3218  if(lhs->component && rhs->component) {
3219  if(lhs->component->name && rhs->component->name) {
3220  if(strcmp(lhs->component->name, rhs->component->name)) {
3221  diff += 1000000;
3222  }
3223  } else if(!lhs->component->name)
3224  diff += 2000000;
3225  else if(!rhs->component->name)
3226  diff += 3000000;
3227  } else if(!lhs->component)
3228  diff += 4000000;
3229  else if(!rhs->component)
3230  diff += 5000000;
3231  }
3232 
3233  return diff;
3234 }
3235 
3237  if(lhs == rhs) return 0;
3238  if(!lhs) return -1;
3239  if(!rhs) return -2;
3240  int diff = 0;
3241 
3242  if(strcmp(lhs->name, rhs->name)) {
3243  diff += 1;
3244  }
3245 
3246  if(FmsFieldDescriptorCompare(lhs->fd, rhs->fd)) {
3247  diff += 10;
3248  }
3249 
3250  if(lhs->num_vec_comp != rhs->num_vec_comp) {
3251  diff += 100;
3252  }
3253 
3254  if(lhs->scalar_type != rhs->scalar_type) {
3255  diff += 1000;
3256  }
3257 
3258  // Potentially shouldn't care about layout?
3259  if(lhs->layout != rhs->layout) {
3260  diff += 10000;
3261  }
3262 
3263  // Only compare the data arrays if everything has matched so far
3264  if(diff == 0) {
3265  FmsInt nvdim = lhs->num_vec_comp;
3266  FmsInt nDofs = 0;
3267  if(lhs->fd)
3268  nDofs = lhs->fd->num_dofs;
3269  if(CompareScalarData(lhs->scalar_type, nvdim * nDofs, lhs->data, rhs->data))
3270  diff += 100000;
3271  }
3272 
3273  return diff;
3274 }
3275 
3277  if(lhs == rhs) return 0;
3278  if(!lhs) return -1;
3279  if(!rhs) return -2;
3280  int diff = 0;
3281 
3282  // It's possible for metadata not to have a name (because it was never set)
3283  if(lhs->name && rhs->name) {
3284  if(strcmp(lhs->name, rhs->name))
3285  diff += 1;
3286  } else if(!lhs->name)
3287  diff += 2;
3288  else if(!rhs->name)
3289  diff += 3;
3290  // If they are both null then they are the same
3291 
3292  if(lhs->md_type != rhs->md_type) {
3293  diff += 10;
3294  }
3295 
3296  // Only compare the data is everything has been the same so far
3297  if(diff == 0) {
3298  switch(lhs->md_type) {
3299  case FMS_INTEGER: {
3300  if(lhs->sub_type.int_type != rhs->sub_type.int_type)
3301  diff += 100;
3302 
3303  if(lhs->num_entries != rhs->num_entries)
3304  diff += 1000;
3305 
3306  if(diff == 0) {
3307  if(CompareIntData(lhs->sub_type.int_type, lhs->num_entries, lhs->data,
3308  rhs->data))
3309  diff += 100000;
3310  }
3311  break;
3312  }
3313  case FMS_SCALAR: {
3314  if(lhs->sub_type.scalar_type != rhs->sub_type.scalar_type)
3315  diff += 100;
3316 
3317  if(lhs->num_entries != rhs->num_entries)
3318  diff += 1000;
3319 
3320  if(diff == 0) {
3321  if(CompareScalarData(lhs->sub_type.scalar_type, lhs->num_entries, lhs->data,
3322  rhs->data))
3323  diff += 100000;
3324  }
3325  break;
3326  }
3327  case FMS_STRING: {
3328  if(lhs->data && rhs->data) {
3329  if(strcmp(lhs->data, rhs->data))
3330  diff += 100000;
3331  } else if(!lhs->name)
3332  diff += 100;
3333  else if(!rhs->name)
3334  diff += 200;
3335  break;
3336  }
3337  case FMS_META_DATA: {
3338  if(lhs->num_entries != rhs->num_entries)
3339  diff += 100;
3340 
3341  if(diff == 0) {
3342  FmsMetaData *ldata = (FmsMetaData*)lhs->data;
3343  FmsMetaData *rdata = (FmsMetaData*)rhs->data;
3344  const FmsInt NE = lhs->num_entries;
3345  for(FmsInt i = 0; i < NE; i++) {
3346  diff += FmsMetaDataCompare(ldata[i], rdata[i]);
3347  if(diff)
3348  break;
3349  }
3350  }
3351  break;
3352  }
3353  default: {
3354  diff += 1000000;
3355  break;
3356  }
3357  }
3358  }
3359  return diff;
3360 }
3361 
3363  if(lhs == rhs) return 0;
3364  if(!lhs) return -1;
3365  if(!rhs) return -2;
3366  int diff = 0;
3367 
3368  // Compare names
3369  if(lhs->name && rhs->name) {
3370  if(strcmp(lhs->name, rhs->name))
3371  diff += 1;
3372  } else if(!lhs->name)
3373  diff += 2;
3374  else if(!rhs->name)
3375  diff += 3;
3376 
3377  // Compare ids
3378  if(lhs->id != rhs->id)
3379  diff += 10;
3380 
3381  // Compare dimension
3382  if(lhs->dim != rhs->dim)
3383  diff += 100;
3384 
3385  // Compare num ents
3386  for(int i = 0; i < FMS_NUM_ENTITY_TYPES; i++) {
3387  if(lhs->num_entities[i] != rhs->num_entities[i]) {
3388  diff += 1000;
3389  break;
3390  }
3391  }
3392 
3393  // Make sure everything is stored using the same types
3394  for(int i = 0; i < FMS_NUM_ENTITY_TYPES; i++) {
3395  if(lhs->side_ids_type[i] != rhs->side_ids_type[i]) {
3396  diff += 10000;
3397  break;
3398  }
3399  }
3400 
3401  // Compare the entities
3402  if(diff == 0) {
3403  for(int i = 0; i < FMS_NUM_ENTITY_TYPES; i++) {
3404  if(CompareIntData(lhs->side_ids_type[i],
3405  lhs->num_entities[i]*FmsEntityNumSides[i],
3406  lhs->entities[i], rhs->entities[i])) {
3407  diff += 100000;
3408  break;
3409  }
3410  }
3411  }
3412 
3413  if(diff == 0) {
3414  for(int i = 0; i < FMS_NUM_ENTITY_TYPES; i++) {
3415  if(CompareIntData(FMS_ORIENTATION_INT_TYPE,
3416  lhs->num_entities[i]*FmsEntityNumSides[i],
3417  lhs->orientations[i], rhs->orientations[i])) {
3418  diff += 1000000;
3419  break;
3420  }
3421  }
3422  }
3423 
3424  return diff;
3425 }
3426 
3428  if(lhs == rhs) return 0;
3429  if(!lhs) return -1;
3430  if(!rhs) return -2;
3431  int diff = 0;
3432 
3433  if(lhs->name && rhs->name) {
3434  if(strcmp(lhs->name, rhs->name))
3435  diff += 1;
3436  } else if(!lhs->name)
3437  diff += 2;
3438  else if(!rhs->name)
3439  diff += 3;
3440 
3441  if(lhs->id != rhs->id)
3442  diff += 10;
3443 
3444  if(lhs->dim != rhs->dim)
3445  diff += 100;
3446 
3447  if(lhs->num_main_entities != rhs->num_main_entities)
3448  diff += 1000;
3449 
3450  if(lhs->num_parts != rhs->num_parts)
3451  diff += 2000;
3452 
3453  if(lhs->num_relations != rhs->num_relations)
3454  diff += 3000;
3455 
3456  if(diff == 0) {
3457  const FmsInt np = lhs->num_parts;
3458  for(FmsInt i = 0; i < np; i++) {
3459  const struct _FmsPart_private *lpart = &lhs->parts[i];
3460  const struct _FmsPart_private *rpart = &rhs->parts[i];
3461  if(FmsDomainCompare(lpart->domain, rpart->domain)) {
3462  diff += 10000;
3463  break;
3464  }
3465  for(FmsInt j = 0; j < FMS_NUM_ENTITY_TYPES; j++) {
3466  if(lpart->num_entities[j] != rpart->num_entities[j]) {
3467  diff += 20000;
3468  break;
3469  }
3470  if(lpart->entities_ids_type[j] != rpart->entities_ids_type[j]) {
3471  diff += 30000;
3472  break;
3473  }
3474  if(CompareIntData(lpart->entities_ids_type[j],
3475  lpart->num_entities[j],
3476  lpart->entities_ids[j], rpart->entities_ids[j])) {
3477  diff += 40000;
3478  break;
3479  }
3480  }
3481  if(diff)
3482  break;
3483  }
3484  }
3485 
3486  if(diff == 0) {
3487  if(CompareIntData(FMS_INT_TYPE, lhs->num_relations, lhs->relations,
3488  rhs->relations))
3489  diff += 50000;
3490  }
3491 
3492  if(diff == 0) {
3493  // Ensure they refer to the same coordinates field
3494  if(FmsFieldCompare(lhs->coordinates, rhs->coordinates))
3495  diff += 60000;
3496  }
3497 
3498  return diff;
3499 }
3500 
3501 int FmsTagCompare(FmsTag lhs, FmsTag rhs) {
3502  if(lhs == rhs) return 0;
3503  if(!lhs) return -1;
3504  if(!rhs) return -2;
3505  int diff = 0;
3506 
3507  if(lhs->name && rhs->name) {
3508  if(strcmp(lhs->name, rhs->name))
3509  diff += 1;
3510  } else if(!lhs->name)
3511  diff += 2;
3512  else if(!rhs->name)
3513  diff += 3;
3514 
3515  if(lhs->tag_type != rhs->tag_type)
3516  diff += 10;
3517 
3518  if(lhs->num_tag_descriptions != rhs->num_tag_descriptions)
3519  diff += 20;
3520 
3521  if(diff == 0) {
3522  if(FmsComponentCompare(lhs->comp, rhs->comp))
3523  diff += 100;
3524  }
3525 
3526  if(diff == 0) {
3527  FmsInt ne = lhs->comp->num_main_entities;
3528  if(CompareIntData(lhs->tag_type, ne, lhs->tags, rhs->tags))
3529  diff += 1000;
3530  }
3531 
3532  return diff;
3533 }
Definition: fms.h:50
int FmsGetInterfaceVersion(FmsInt *version)
Get the interface version.
Definition: fms.c:871
FmsFieldType
TODO: dox.
Definition: fms.h:348
Definition: fms.h:53
#define FMS_ICC_SW(src_type, src, dst_t, dst, size)
Definition: fms.c:296
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
FmsBasisType
TODO: dox.
Definition: fms.h:357
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
#define E_RETURN(code)
Definition: fms.c:239
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
const int * FmsEntityReordering[FMS_NUM_ENTITY_TYPES]
A type describing user-defined local orderings of the side entities defining an enitity.
Definition: fms.h:281
int FmsMeshGetNumDomainNames(FmsMesh mesh, FmsInt *num_domain_names)
TODO: dox.
Definition: fms.c:2177
const char *const FmsEntityTypeNames[FMS_NUM_ENTITY_TYPES]
String representations of each entity type.
Definition: fms.c:169
Definition: fms.h:242
int FmsFieldCompare(FmsField lhs, FmsField rhs)
Return 0 if equivalent, not 0 otherwise.
Definition: fms.c:3236
int FmsComponentAddRelation(FmsComponent comp, FmsInt other_comp_id)
Describe a relation from one component to another.
Definition: fms.c:1624
int FmsDomainGetEntitiesArray(FmsDomain domain, FmsEntityType type, void **ents)
TODO: dox.
Definition: fms.c:1381
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 FmsComponentCompare(FmsComponent lhs, FmsComponent rhs)
Return 0 if equivalent, not 0 otherwise.
Definition: fms.c:3427
int FmsTagGetDescriptions(FmsTag tag, FmsIntType *tag_type, const void **tags, const char *const **tag_descr, FmsInt *num_tags)
TODO: dox.
Definition: fms.c:2754
int FmsDomainGetEntitiesVerts(FmsDomain domain, FmsEntityType type, FmsEntityReordering vert_reordering, FmsIntType ent_id_type, FmsInt first_ent, void *ents_verts, FmsInt num_ents)
TODO: dox Extract a subset of the entity definitions in terms of their vertices.
Definition: fms.c:2329
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
The type of FmsInt identified as FmsIntType.
Definition: fms.h:61
struct FmsComponent_private * FmsComponent
TODO: dox.
Definition: fms.h:159
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
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
int FmsDomainGetAllOrientations(FmsDomain domain, FmsEntityType type, const FmsOrientation **side_orients, FmsInt *num_ents)
TODO: dox No copy, read only access to all entity side orientations.
Definition: fms.c:2644
int FmsDomainGetEntities(FmsDomain domain, FmsEntityType type, FmsEntityReordering reordering, FmsIntType ent_id_type, FmsInt first_ent, void *ents, FmsInt num_ents)
TODO: dox Extract a subset of the entity definitions.
Definition: fms.c:2298
int FmsMetaDataCompare(FmsMetaData lhs, FmsMetaData rhs)
Return 0 if equivalent, not 0 otherwise.
Definition: fms.c:3276
Definition: fms.h:54
int FmsFieldDescriptorGetComponent(FmsFieldDescriptor fd, FmsComponent *comp)
TODO: dox.
Definition: fms.c:2821
const FmsInt FmsEntityNumVerts[FMS_NUM_ENTITY_TYPES]
Number of vertices of the entity types.
Definition: fms.c:188
int FmsMetaDataDestroy(FmsMetaData *mdata)
Destroy the object that *mdata refers to and set *mdata to NULL.
Definition: fms.c:2152
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 FmsMeshDestroy(FmsMesh *mesh)
TODO: dox.
Definition: fms.c:1142
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
Definition: fms.h:237
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
See FmsFieldDescriptorSetFixedOrder()
Definition: fms.h:344
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
#define COMPARE_SCALAR_DATA(T, lhs, rhs, n, OUT_FmsInt_isdifferent)
Definition: fms.c:2945
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
int FmsMetaDataClear(FmsMetaData mdata)
Clear the contents of mdata without destroying the object.
Definition: fms.c:2126
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 FmsTagAllocate(FmsTag tag, FmsIntType stored_tag_type, void **ent_tags, FmsInt *num_ents)
TODO: dox.
Definition: fms.c:1682
int FmsDataCollectionCompare(FmsDataCollection lhs, FmsDataCollection rhs)
Comparison interface.
Definition: fms.c:3035
Definition: fms.h:353
int FmsTagCompare(FmsTag lhs, FmsTag rhs)
Return 0 if equivalent, not 0 otherwise.
Definition: fms.c:3501
#define COMPARE_INT_DATA(T, lhs, rhs, n, OUT_FmsInt_isdifferent)
Definition: fms.c:2959
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 FmsFieldDescriptorCompare(FmsFieldDescriptor lhs, FmsFieldDescriptor rhs)
Return 0 if equivalent, not 0 otherwise.
Definition: fms.c:3174
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
The type of FmsOrientation as FmsIntType.
Definition: fms.h:63
int FmsMeshSetPartitionId(FmsMesh mesh, FmsInt partition_id, FmsInt num_partitions)
TODO: dox.
Definition: fms.c:1201
int FmsDomainCompare(FmsDomain lhs, FmsDomain rhs)
Return 0 if equivalent, not 0 otherwise.
Definition: fms.c:3362
Definition: fms.h:352
int FmsDataCollectionDestroy(FmsDataCollection *dc)
Destroy a data collection object.
Definition: fms.c:1765
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 FmsDomainGetOrientationsArray(FmsDomain domain, FmsEntityType type, FmsOrientation **side_orients)
TODO: dox.
Definition: fms.c:1393
#define FMS_E2S_TEMPL(idx_t)
Definition: fms.c:426
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
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
int FmsDomainAddOrientation(FmsDomain domain, FmsEntityType type, FmsInt ent_id, FmsInt loc_side_id, FmsOrientation side_orient)
TODO: dox.
Definition: fms.c:1426
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
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
int FmsComponentGetPartSubEntities(FmsComponent comp, FmsInt part_id, FmsEntityType type, FmsIntType *ent_id_type, const void **ents, FmsInt *num_ents)
TODO: dox Similar to FmsComponentGetPart() but for lower dimensional entities.
Definition: fms.c:2694
struct FmsMetaData_private * FmsMetaData
TODO: dox.
Definition: fms.h:401
#define FMS_IPCC_SW(src_type, src, dst_t, dst, ts, perm, size)
Definition: fms.c:343
int FmsMeshGetDomains(FmsMesh mesh, FmsInt domain_name_id, const char **domain_name, FmsInt *num_domains, FmsDomain **domains)
TODO: dox.
Definition: fms.c:2184
#define FMS_IMC_SW(src_type, src, dst_t, dst, map, size)
Definition: fms.c:391
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
Added in version: v0.2.
Definition: fms.h:379
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
int FmsMeshCompare(FmsMesh lhs, FmsMesh rhs)
Return 0 if equivalent, not 0 otherwise.
Definition: fms.c:3097
uint8_t FmsOrientation
A type used by fms to represent and store entity orientations.
Definition: fms.h:319
const size_t FmsIntTypeSize[FMS_NUM_INT_TYPES]
Definition: fms.c:154
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