1 /*************************************************************************
2  *                                                                       *
3  * Vega FEM Simulation Library Version 3.1                               *
4  *                                                                       *
5  * "volumetricMesh" library , Copyright (C) 2007 CMU, 2009 MIT, 2016 USC *
6  * All rights reserved.                                                  *
7  *                                                                       *
8  * Code authors: Jernej Barbic, Yijing Li                                *
9  * http://www.jernejbarbic.com/code                                      *
10  *                                                                       *
11  * Research: Jernej Barbic, Fun Shing Sin, Daniel Schroeder,             *
12  *           Doug L. James, Jovan Popovic                                *
13  *                                                                       *
14  * Funding: National Science Foundation, Link Foundation,                *
15  *          Singapore-MIT GAMBIT Game Lab,                               *
16  *          Zumberge Research and Innovation Fund at USC                 *
17  *                                                                       *
18  * This library is free software; you can redistribute it and/or         *
19  * modify it under the terms of the BSD-style license that is            *
20  * included with this library in the file LICENSE.txt                    *
21  *                                                                       *
22  * This library is distributed in the hope that it will be useful,       *
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the file     *
25  * LICENSE.TXT for more details.                                         *
26  *                                                                       *
27  *************************************************************************/
28 
29 #ifndef _VOLUMETRICMESH_H_
30 #define _VOLUMETRICMESH_H_
31 
32 /*
33   This abstract class can store a generic volumetric 3D mesh.
34   It stores the mesh geometric information (elements and vertices),
35   and also the material parameters of each individual mesh element
36   (Young's modulus, Poisson ratio, mass density). This is done by
37   organizing elements with the same material parameters into a "region".
38   The class supports several geometric queries and interpolation to
39   an embedded triangle mesh ("Free-Form Deformation").  It also
40   supports exporting the mesh to an .ele or .node format (the format
41   used by the Stellar and TetGen mesh generation packages).  Derived classes
42   are the TetMesh (general tetrahedral meshes), and CubicMesh
43   (axis-aligned cubic "voxel" meshes). See description in tetMesh.h and cubicMesh.h.
44 
45   All quantities are 0-indexed, except the input mesh files where the
46   elements and vertices are 1-indexed (same as in TetGen and Stellar).
47 */
48 
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <vector>
53 #include <set>
54 #include <string>
55 #include <map>
56 #include "minivector.h"
57 
58 class VolumetricMesh
59 {
60 public:
61 
62   // Note: This class is abstract and cannot be instantiated; use the constructors in the derived classes (TetMesh, CubicMesh) to initialize a mesh, or use the load routine in volumetricMeshLoader.h
63 
64   // copy constructor, destructor
65   VolumetricMesh(const VolumetricMesh & volumetricMesh);
66   virtual VolumetricMesh * clone() = 0;
67   virtual ~VolumetricMesh();
68 
69   // nested classes to store sets, materials and regions (declared later)
70   class Set;
71   class Material;
72   class Region;
73 
74   // === save/export ===
75 
76   // saves the mesh to a text file (.veg file format, see examples and documentation)
77   virtual int saveToAscii(const char * filename) const = 0;
78   virtual int save(const char * filename) const; // for backward compatibility (just calls saveToAscii)
79 
80   // saves the mesh to binary format
81   // returns: 0 = success, non-zero = error
82   // output: if bytesWritten is non-NULL, it will contain the number of bytes written
83   virtual int saveToBinary(const char * filename, unsigned int * bytesWritten = NULL) const = 0;
84   // if countBytesOnly = true, user can pass NULL to binaryOutputStream
85   virtual int saveToBinary(FILE * binaryOutputStream, unsigned int * bytesWritten = NULL, bool countBytesOnly = false) const = 0;
86 
87   // exports the mesh geometry to an .ele and .node file (TetGen and Stellar format)
88   // if includeRegions=1, an extra column is added to output, identifying the region of each element
89   int exportToEle(const char * baseFilename, int includeRegions=0) const;
90   // exports the mesh geometry to memory arrays (say, for external usage)
91   // all parameters are output parameters
92   // vertices and elements will be allocated inside the routine
93   void exportMeshGeometry(int * numVertices, double ** vertices, int * numElements = NULL, int * numElementVertices = NULL, int ** elements = NULL) const;
94 
95   // === vertex and element access ===
96 
97   typedef enum { INVALID, TET, CUBIC } elementType;
98   typedef enum { ASCII, BINARY, NUM_FILE_FORMATS } fileFormatType; // ASCII is the text .veg format, BINARY is the binary .vegb format
99   // opens the file and returns the element type of the volumetric mesh in the file; returns INVALID if no type information found
100   static elementType getElementType(const char * filename, fileFormatType fileFormat = ASCII);
101   virtual elementType getElementType() const = 0; // calls the derived class to identify itself
102   // advanced usage: returns the element type of the volumetric mesh from a BINARY stream (does not modify fin)
103   //static elementType getElementType(FILE * fin);
104   static elementType getElementType(void * fin, int memoryLoad = 0);
105 
getNumVertices()106   inline int getNumVertices() const { return numVertices; }
getVertex(int i)107   inline Vec3d & getVertex(int i) { return vertices[i]; }
getVertex(int i)108   inline const Vec3d & getVertex(int i) const { return vertices[i]; }
getVertex(int element,int vertex)109   inline Vec3d & getVertex(int element, int vertex) { return vertices[elements[element][vertex]]; }
getVertex(int element,int vertex)110   inline const Vec3d & getVertex(int element, int vertex) const { return vertices[elements[element][vertex]]; }
getVertexIndex(int element,int vertex)111   inline int getVertexIndex(int element, int vertex) const { return elements[element][vertex]; }
getVertexIndices(int element)112   inline const int * getVertexIndices(int element) const { return elements[element]; }
getVertices()113   inline Vec3d * getVertices() { return vertices; } // advanced, internal datastructure
getVertices()114   inline const Vec3d * getVertices() const { return vertices; }
getNumElements()115   inline int getNumElements() const { return numElements; }
getNumElementVertices()116   inline int getNumElementVertices() const { return numElementVertices; }
117   void renumberVertices(const std::vector<int> & permutation); // renumbers the vertices using the provided permutation
setVertex(int i,const Vec3d & pos)118   inline void setVertex(int i, const Vec3d & pos) { vertices[i] = pos; } // set the position of a vertex
119 
120   // === materials access ===
121 
getNumMaterials()122   inline int getNumMaterials() const { return numMaterials; }
getMaterial(int i)123   inline const Material * getMaterial(int i) const { return materials[i]; }
getElementMaterial(int el)124   inline const Material * getElementMaterial(int el) const { return materials[elementMaterial[el]]; }
125   static void getDefaultMaterial(double * E, double * nu, double * density);
126 
getNumSets()127   inline int getNumSets() const { return numSets; }
getSet(int i)128   inline const Set * getSet(int i) const { return sets[i]; }
129 
getNumRegions()130   inline int getNumRegions() const { return numRegions; }
getRegion(int i)131   inline const Region * getRegion(int i) const { return regions[i]; }
132 
133   // === materials editing ===
getMaterial(int i)134   inline Material * getMaterial(int i) { return materials[i]; }
getElementMaterial(int el)135   inline Material * getElementMaterial(int el) { return materials[elementMaterial[el]]; }
136   void setMaterial(int i, const Material * material); // sets i-th material to "material"
137   void setSingleMaterial(double E, double nu, double density); // erases all materials and creates a single material for the entire mesh
138   void addMaterial(const Material * material, const Set & newSet, bool removeEmptySets, bool removeEmptyMaterials);
139 
140   // mass density of an element
getElementDensity(int el)141   double getElementDensity(int el) const { return materials[elementMaterial[el]]->getDensity(); }
142   // computes the mass matrix of a single element
143   // note: to compute the mass matrix for the entire mesh, use generateMassMatrix.h
144   virtual void computeElementMassMatrix(int element, double * massMatrix) const = 0; // massMatrix is numElementVertices_ x numElementVertices_
145 
146   // === geometric queries and transformations ===
147 
148   Vec3d getElementCenter(int el) const;
149 
150   // center of mass and inertia tensor
151   double getVolume() const;
152   virtual double getElementVolume(int el) const = 0;
153   void getVertexVolumes(double * vertexVolumes) const; // compute the volume "belonging" to each vertex
154   virtual void getElementInertiaTensor(int el, Mat3d & inertiaTensor) const = 0; // returns the inertia tensor of a single element, around its center of mass, with unit density
155   double getMass() const; // compute the total mass of the mesh, using the mass density material information
156   void getInertiaParameters(double & mass, Vec3d & centerOfMass, Mat3d & inertiaTensor) const ; // mass, center of mass and inertia tensor for the entire mesh
157 
158   // centroid is the geometric center of all vertices; radius is the tightest fitting sphere centered at the centroid
159   void getMeshGeometricParameters(Vec3d & centroid, double * radius) const;
160 
161   // mesh 1-neighborhood queries
162   void getVerticesInElements(std::vector<int> & elements, std::vector<int> & vertices) const;
163   void getElementsTouchingVertices(std::vector<int> & vertices, std::vector<int> & elements) const;
164   void getVertexNeighborhood(std::vector<int> & vertices, std::vector<int> & neighborhood) const;
165 
166   // proximity queries
167   int getClosestElement(Vec3d pos) const; // finds the closest element to the given position (using linear scan); distance to a element is defined as distance to its center
168   int getClosestVertex(Vec3d pos) const; // finds the closest vertex to the given position (using linear scan)
169   int getContainingElement(Vec3d pos) const; // finds the element that containts the given position (using linear scan); if such element does not exist, -1 is returned
170   virtual bool containsVertex(int element, Vec3d pos)  const = 0; // true if given element contain given position, false otherwise
171 
172   // computes the gravity vector (different forces on different mesh vertices due to potentially varying mass densities)
173   // gravityForce must be a pre-allocated vector of length 3xnumVertices()
174   void computeGravity(double * gravityForce, double g=9.81, bool addForce=false) const;
175 
176   // edge queries
177   virtual int getNumElementEdges() const = 0;
178   virtual void getElementEdges(int el, int * edgeBuffer) const = 0; // edgeBuffer must be pre-allocated, of size 2 x numElementEdges()
179 
180   // (permanently) applies the deformation to the vertices of the mesh
181   void applyDeformation(double * u);
182   void applyLinearTransformation(double * pos, double * R); // transforms every vertex as X |--> pos + R * X (R must be given row-major)
183 
184   // === submesh creation ===
185 
186   // (permanently) set this mesh to its submesh containing the specified elements (i.e., delete the mesh elements not on the given list of elements)
187   // if vertexMap is non-null, it also returns a renaming datastructure: vertexMap[big mesh vertex] is the vertex index in the subset mesh
188   void setToSubsetMesh(std::set<int> & subsetElements, int removeIsolatedVertices=1, std::map<int,int> * vertexMap = NULL);
189 
190   // === interpolation ===
191 
192   // the interpolant is a triple (numTargetLocations, vertices, weights)
193   // Generates interpolation weights to transfer quantities from volumetric mesh to (embedded) surface meshes.
194   // Input is a list of 3D target locations where the interpolant will be computed,
195   // e.g., those could be vertices of a triangle mesh embedded into the volumetric mesh.
196   // Each location is a 3-vector, i.e., 3 consecutive double-precision values.
197   // If zeroThreshold is set positive, than for any target location that is
198   //   more than zeroThreshold away from the closest element,
199   //   all weights will be set to zero; this is useful, e.g. to
200   //   fix locations far away from your mesh.
201   // Output: vertices and weights arrays
202   // vertices: gives a list of integer indices of the vertices of the element
203   //   closest to the target location (numElementVertices entries per target location, one for each element vertex)
204   //   note: if target location is inside a voxel, that voxel will be chosen as closest
205   // weights: a list of numElementVertices_ weights, as per the numElementVertices_ vertices of each element (weights sum to 1)
206   // If zeroThreshold >= 0, then the points that are further than zeroThreshold away from any volumetric mesh vertex, are assigned weights of 0.
207   // If elements is not NULL, the closest elements for each target location will be returned in the integer list "*elements" (allocated inside the function)
208   // If elements is not NULL, the function will allocate an integer array *elements, and return the closest element to each target location in it.
209   // Returns the number of target points that do not lie inside any element.
210   int generateInterpolationWeights(int numTargetLocations, const double * targetLocations, int ** vertices, double ** weights, double zeroThreshold = -1.0, int ** elements = NULL, int verbose=0) const; // this is the "master" function, meant to be typically used to create the interpolant
211 
212   // interpolates 3D vector data from vertices of the
213   //   volumetric mesh (data given in u) to the target locations (output goes into uTarget)
214   //   e.g., use this to interpolate deformation from the volumetric mesh to a triangle mesh
215   static void interpolate(const double * u, double * uTarget, int numTargetLocations, int numElementVertices, const int * vertices, const double * weights);
216 
217   // the following are less often used, more specialized functions
218   // same as "generateInterpolationWeights" above, except here the elements that contain the target locations are assumed to be known, and are provided in array "elements"; returns 0 on success, 1 otherwise
219   int generateInterpolationWeights(int numTargetLocations, const double * targetLocations, int * elements, int ** vertices, double ** weights, double zeroThreshold = -1.0, int verbose=0) const;
220   // generates the integer list "elements" of the elements that contain given vertices; if closestElementIfOutside==1, then vertices outside of the mesh are assigned the closest element, otherwise -1 is assigned; returns the number of target locations outside of the mesh
221   int generateContainingElements(int numTargetLocations, const double * targetLocations, int ** elements, int useClosestElementIfOutside=1, int verbose=0) const;
222   static int getNumInterpolationElementVertices(const char * filename); // looks at the first line of "filename" to determine "numElementVertices" for this particular interpolant
223   static int loadInterpolationWeights(const char * filename, int numTargetLocations, int numElementVertices, int ** vertices, double ** weights); // ASCII version; returns 0 on success
224   static int saveInterpolationWeights(const char * filename, int numTargetLocations, int numElementVertices, const int * vertices, const double * weights); // ASCII version
225   static int loadInterpolationWeightsBinary(const char * filename, int * numTargetLocations, int * numElementVertices, int ** vertices, double ** weights); // binary version; returns 0 on success
226   static int saveInterpolationWeightsBinary(const char * filename, int numTargetLocations, int numElementVertices, const int * vertices, const double * weights); // binary version
227   static int loadInterpolationWeightsBinary(FILE * fin, int * numTargetLocations, int * numElementVertices, int ** vertices, double ** weights); // binary version; returns 0 on success
228   static int saveInterpolationWeightsBinary(FILE * fout, int numTargetLocations, int numElementVertices, const int * vertices, const double * weights); // binary version
229 
230   // computes barycentric weights of the given position with respect to the given element
231   virtual void computeBarycentricWeights(int element, const Vec3d & pos, double * weights) const = 0;
232 
233   // computes the gradient of a 3D vector field (specified at the volumetric mesh vertices), at the location "pos"
234   // "numFields" fields can be interpolated simultaneously; each is given as one column of the U matrix
235   // U is a 3numVertices x numFields matrix; stored column-major
236   // output: grad is 9 x numFields matrix, stored column-major; each column gives the gradient (3x3 matrix), stored row-major format
237   // return: 0 if pos inside the mesh, 1 otherwise
238   int interpolateGradient(const double * U, int numFields, Vec3d pos, double * grad) const;
239   // in this version, the element containing the "pos" must be known, and prescribed directly
240   virtual void interpolateGradient(int element, const double * U, int numFields, Vec3d pos, double * grad) const = 0;
241 
242   // === material-related nested classes ===
243 
244   // a set of integers, with a name (used for example, to store elements that share the same material properties)
245   class Set
246   {
247   public:
248 
249     Set(const std::string & name);
250     Set(const Set & set);
251     Set(const std::string & name, const std::set<int> & elements);
252 
253     inline std::string getName() const;
254     inline int getNumElements() const;
255     inline void getElements(std::set<int> & elements) const;
256     inline const std::set<int> & getElements() const;
257     inline bool isMember(int element) const;
258 
259     inline std::set<int> & getElements();
260     inline void insert(int element);
261     inline void clear();
262 
263   protected:
264     std::string name;
265     std::set<int> elements;
266   };
267 
268   // stores a material (abstract class)
269   class Material
270   {
271   public:
272     Material(const std::string name, double density);
273     Material(const Material & material);
~Material()274     virtual ~Material() {};
275     virtual Material * clone() const = 0;
276 
277     inline std::string getName() const; // material name
278     inline double getDensity() const; // density
279     inline void setName(const std::string name);
280     inline void setDensity(double density);
281 
282     // ENU = any isotropic material parameterized by E (Young's modulus), nu (Poisson's ratio)
283     // ORTHOTROPIC = orthotropic anisotropic material
284     // MOONEYRIVLIN = Mooney-Rivlin material
285     typedef enum { INVALID, ENU, ORTHOTROPIC, MOONEYRIVLIN } materialType;
286     virtual materialType getType() = 0;
287 
288     typedef enum { ENU_DENSITY, ENU_E, ENU_NU, ENU_NUM_PROPERTIES } enuMaterialProperties;
289     typedef enum { ORTHOTROPIC_DENSITY, ORTHOTROPIC_E1, ORTHOTROPIC_E2, ORTHOTROPIC_E3, ORTHOTROPIC_NU12, ORTHOTROPIC_NU23, ORTHOTROPIC_NU31, ORTHOTROPIC_G12, ORTHOTROPIC_G23, ORTHOTROPIC_G31, ORTHOTROPIC_NUM_PROPERTIES } orthotropicMaterialProperties;
290     typedef enum { MOONEYRIVLIN_DENSITY, MOONEYRIVLIN_MU01, MOONEYRIVLIN_MU10, MOONEYRIVLIN_V1, MOONEYRIVLIN_NUM_PROPERTIES } mooneyrivlinMaterialProperties;
291 
292   protected:
293     std::string name;
294     double density;
295   };
296 
297   // material with E (Young's modulus), nu (Poisson's ratio) (defined in volumetricMeshENuMaterial.h)
298   class ENuMaterial;
299   // Mooney-Rivlin material (defined in volumetricMeshMooneyRivlinMaterial.h)
300   class MooneyRivlinMaterial;
301   // Orthotropic material (defined in volumetricMeshOrthotropicMaterial.h)
302   class OrthotropicMaterial;
303 
304   // a volumetric mesh region, i.e., a set of elements sharing the same material
305   class Region
306   {
307   public:
308     Region(int materialIndex, int setIndex);
309     inline int getMaterialIndex() const;
310     inline int getSetIndex() const;
311     inline void setMaterialIndex(int index);
312     inline void setSetIndex(int index);
313 
314   protected:
315     int setIndex, materialIndex;
316   };
317 
318   static double E_default;
319   static double nu_default;
320   static double density_default;
321 
322 protected:
323   int numVertices;
324   Vec3d * vertices;
325 
326   int numElementVertices;
327   int numElements;
328   int ** elements;
329 
330   int numMaterials;
331   int numSets;
332   int numRegions;
333   Material ** materials;
334   Set ** sets;
335   Region ** regions;
336   int * elementMaterial;  // material index of each element
337 
338   // parses the mesh, and returns the mesh element type
339   VolumetricMesh(const char * filename, fileFormatType fileFormat, int numElementVertices, elementType * elementType_, int verbose);
340   // if memoryLoad is 0, binaryInputStream is FILE* (load from a file, via a stream), otherwise, it is char* (load from a memory buffer)
341   VolumetricMesh(void * binaryInputStream, int numElementVertices, elementType * elementType_, int memoryLoad = 0);
VolumetricMesh(int numElementVertices_)342   VolumetricMesh(int numElementVertices_) { numElementVertices = numElementVertices_; }
343   void propagateRegionsToElements();
344   void loadFromBinaryGeneric(void * binaryInputStream, elementType * elementType_, int memoryLoad);
345 
346   // constructs a mesh from the given vertices and elements,
347   // with a single region and material ("E, nu" material)
348   // "vertices" is double-precision array of length 3 x numVertices
349   // "elements" is an integer array of length numElements x numElementVertices
350   VolumetricMesh(int numVertices, double * vertices,
351          int numElements, int numElementVertices, int * elements,
352          double E=E_default, double nu=nu_default, double density=density_default);
353 
354   // constructs a mesh from the given vertices and elements,
355   // with an arbitrary number of sets, regions and materials
356   // "vertices" is double-precision array of length 3 x numVertices
357   // "elements" is an integer array of length numElements x numElementVertices
358   // "materials", "sets" and "regions" will be copied internally (deep copy), so they
359   // can be released after calling this constructor
360   VolumetricMesh(int numVertices, double * vertices,
361          int numElements, int numElementVertices, int * elements,
362          int numMaterials, Material ** materials,
363          int numSets, Set ** sets,
364          int numRegions, Region ** regions);
365 
366   // creates a submesh consisting of the specified elements of the given mesh
367   // if vertexMap is non-null, it also returns a renaming datastructure: vertexMap[big mesh vertex] is the vertex index in the subset mesh
368   VolumetricMesh(const VolumetricMesh & mesh, int numElements, int * elements, std::map<int,int> * vertexMap = NULL);
369 
370   int saveToAscii(const char * filename, elementType elementType_) const;
371   int saveToBinary(const char * filename, unsigned int * bytesWritten, elementType elementType_) const;
372   int saveToBinary(FILE * binaryOutputStream, unsigned int * bytesWritten, elementType elementType_, bool countBytesOnly = false) const;
373 
374   void loadFromAscii(const char * filename, elementType * elementType_, int verbose = 0);
375   void loadFromBinary(const char * filename, elementType * elementType_);
376   void loadFromBinary(FILE * binaryInputStream, elementType * elementType_);
377   void loadFromMemory(unsigned char * binaryInputStream, elementType * elementType_);
378   void assignMaterialsToElements(int verbose);
379 
380   static elementType getElementTypeASCII(const char * filename);
381   static elementType getElementTypeBinary(const char * filename);
382 
383   elementType temp; // auxiliary
384 
385   friend class VolumetricMeshExtensions;
386   friend class VolumetricMeshLoader;
387 
388   static unsigned int readFromFile(void * buf, unsigned int elementSize, unsigned int numElements, void * fin);
389   static unsigned int readFromMemory(void * buf, unsigned int elementSize, unsigned int numElements, void * memoryLocation);
390 };
391 
Set(const std::string & name_)392 inline VolumetricMesh::Set::Set(const std::string & name_) { name = name_; }
Set(const Set & set)393 inline VolumetricMesh::Set::Set(const Set & set) { elements = set.elements; name = set.getName(); }
Set(const std::string & name_,const std::set<int> & elements_)394 inline VolumetricMesh::Set::Set(const std::string & name_, const std::set<int> & elements_) : name(name_), elements(elements_) {}
getName()395 inline std::string VolumetricMesh::Set::getName() const { return name; }
getNumElements()396 inline int VolumetricMesh::Set::getNumElements() const { return (int)(this->elements.size()); }
getElements(std::set<int> & elements)397 inline void VolumetricMesh::Set::getElements(std::set<int> & elements) const { elements = this->elements; }
getElements()398 inline const std::set<int> & VolumetricMesh::Set::getElements() const { return elements; }
getElements()399 inline std::set<int> & VolumetricMesh::Set::getElements() { return elements; }
isMember(int element)400 inline bool VolumetricMesh::Set::isMember(int element) const {return (elements.find(element) != elements.end());}
insert(int element)401 inline void VolumetricMesh::Set::insert(int element) { elements.insert(element); }
clear()402 inline void VolumetricMesh::Set::clear() { elements.clear(); }
403 
Material(const std::string name_,double density_)404 inline VolumetricMesh::Material::Material(const std::string name_, double density_): density(density_) { name = name_; }
Material(const Material & material)405 inline VolumetricMesh::Material::Material(const Material & material) : density(material.getDensity()) { name = material.getName(); }
getName()406 inline std::string VolumetricMesh::Material::getName() const { return name; }  // material name
getDensity()407 inline double VolumetricMesh::Material::getDensity() const { return density; } // density
setName(const std::string name_)408 inline void VolumetricMesh::Material::setName(const std::string name_) { name = name_; }
setDensity(double density_)409 inline void VolumetricMesh::Material::setDensity(double density_) { density = density_; }
410 
Region(int materialIndex_,int setIndex_)411 inline VolumetricMesh::Region::Region(int materialIndex_, int setIndex_): setIndex(setIndex_), materialIndex(materialIndex_) {}
getMaterialIndex()412 inline int VolumetricMesh::Region::getMaterialIndex() const { return materialIndex; }
getSetIndex()413 inline int VolumetricMesh::Region::getSetIndex() const { return setIndex; }
setMaterialIndex(int index)414 inline void VolumetricMesh::Region::setMaterialIndex(int index) { materialIndex = index; }
setSetIndex(int index)415 inline void VolumetricMesh::Region::setSetIndex(int index) { setIndex = index; }
416 
417 #endif
418 
419