GemaMesh
The GeMA Mesh Plugin
gmpCellBase.h
Go to the documentation of this file.
1 /************************************************************************
2 **
3 ** Copyright (C) 2014 by Carlos Augusto Teixera Mendes
4 ** All rights reserved.
5 **
6 ** This file is part of the "GeMA" software. It's use should respect
7 ** the terms in the license agreement that can be found together
8 ** with this source code.
9 ** It is provided AS IS, with NO WARRANTY OF ANY KIND,
10 ** INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR
11 ** A PARTICULAR PURPOSE.
12 **
13 ************************************************************************/
14 
24 #ifndef _GEMA_PLUGIN_CELL_BASE_H_
25 #define _GEMA_PLUGIN_CELL_BASE_H_
26 
27 #include <gmElement.h>
28 #include <gmMesh.h>
29 #include <assert.h>
30 
31 #include <gmPropertySet.h>
32 #include <gmCellMesh.h>
33 #include <gmLuaCell.h>
34 
35 #include <luaProxy.h>
36 
37 #include <QVarLengthArray>
38 
39 #include "gmpCellMeshData.h"
40 
41 
50 #define GM_CELLBASE_ACTIVE_MASK (~(~0u >> 1))
51 
55 #define GM_CELLBASE_MESH_MASK ((~(~0u >> GMP_GEMAMESH_CELL_MESH_BITS)) >> 1)
56 
58 #define GM_CELLBASE_CELL_MASK (~(GM_CELLBASE_ACTIVE_MASK | GM_CELLBASE_MESH_MASK))
59 
60 static_assert((GM_CELLBASE_ACTIVE_MASK | GM_CELLBASE_MESH_MASK | GM_CELLBASE_CELL_MASK) == ~0u, "Invalid masks");
61 static_assert((GM_CELLBASE_ACTIVE_MASK & GM_CELLBASE_MESH_MASK) == 0, "Invalid masks");
62 static_assert((GM_CELLBASE_ACTIVE_MASK & GM_CELLBASE_CELL_MASK) == 0, "Invalid masks");
63 static_assert((GM_CELLBASE_MESH_MASK & GM_CELLBASE_CELL_MASK) == 0, "Invalid masks");
64 
68 static inline bool GmpCellIsActive(int cellId) { return !(cellId & GM_CELLBASE_ACTIVE_MASK); }
69 
71 static inline int GmpCellMakeActive(int cellId) { return cellId & (~GM_CELLBASE_ACTIVE_MASK); }
72 
74 static inline int GmpCellMakeInactive(int cellId) { return cellId | GM_CELLBASE_ACTIVE_MASK; }
75 
77 static inline int GmpCellSetActiveFlag(int cellId, bool active) { return active ? GmpCellMakeActive(cellId) : GmpCellMakeInactive(cellId); }
78 
79 
81 static inline int GmpCellMeshIndex(int cellId) { return (cellId & GM_CELLBASE_MESH_MASK) >> GMP_GEMAMESH_CELL_ID_BITS; }
82 
84 static inline int GmpCellIndex(int cellId) { return (cellId & GM_CELLBASE_CELL_MASK); }
85 
87 static inline int GmpCellUpdateMeshIndex(int id, int oldId) { return (id & ~GM_CELLBASE_MESH_MASK) | (oldId & GM_CELLBASE_MESH_MASK); }
88 
90 static inline int GmpCellEncodeId(int cellIndex, int meshIndex, bool active)
91 {
92  assert(cellIndex >= 0 && cellIndex < GMP_GEMAMESH_MAX_NUM_CELLS);
93  assert(meshIndex >= 0 && meshIndex < GMP_GEMAMESH_MAX_NUM_MESHES);
94  return GmpCellSetActiveFlag(cellIndex | (meshIndex << GMP_GEMAMESH_CELL_ID_BITS), active);
95 }
96 
97 
116 template <class Base, class Proxy, class CellMeshData, GmCellType T, int N, int VN> class GmpCellBase : public Base
117 {
118 public:
121  {
122  assert(N == geometry().numNodes());
123  assert(VN == geometry().numVertices());
124  }
125 
126  // See comments on the base class
127  virtual int numNodes() const { return N; }
128 
129  // See comments on the base class
130  virtual void pushProxy(lua_State* L, const GmLogCategory& logger) { LuaProxy::pushObject(L, new Proxy(this, logger)); }
131 
132  // See comments on the base class
133  virtual GmCellType type() const { return T; }
134 
135  // See comments on the base class
136  virtual int propertyIndex(int propertySet) const
137  {
138  assert(propertySet >= 0 && propertySet < mesh()->propertySets().size());
139  return meshData()->cellPropertiesPtr(cellId())[propertySet];
140  }
141 
142  // See comments on the base class
143  virtual bool setProperties(const int* propList, int nprop)
144  {
145  assert(propList);
146  assert(nprop == mesh()->propertySets().size());
147 
148  memcpy(meshData()->cellPropertiesPtr(cellId()), propList, nprop*sizeof(int));
149  return true;
150  }
151 
152 protected:
154  CellMeshData* meshData() const { return (CellMeshData*)GmpCellMeshDataBase::meshData(meshId()); }
155 };
156 
157 
158 /* The memory layout for GmpCellBaseWithId is the virtual table pointer followed by the cellId integer,
159  usually followed by a 4 bytes packing to align the structure to 8 bytes (due to the vtable poniter).
160 
161  In Visual studio, when this class is later inherited by GmpGemaCell, which adds another int to the
162  structure, the packing is NOT reused to hold that additional int, and so the cell size grows from
163  16 to 24 bytes. Compiling with GCC, that packing is discarded and the offset int from GmpGemaCell is
164  stored just after the id, with a size of 16 bytes.
165 
166  By adding a pragma pack(4) directive in Windows, we force the struct alignment to 4 bytes, meaning
167  that in this context, the size of a GmCellBaseWithId structure will be 12 bytes, with no packing and
168  so when inherited by GmpGemaCell it will result in the desired 16 bytes structure.
169 
170  We can get away with that since a GmpCellBaseWithId struct will NEVER be instanced directly and always
171  be derived. The derived class then MUST take care of the alignment as is done by GmpGemaCell.
172  This is ugly and prone to introducing problems if changing the class layouts but is a really worthy
173  space optimization.
174 
175  IMPORTANT: If the layout for GmpCellBaseWithId or for GmpGemaCell is changed in any way, this
176  optimization should be reviewed.
177 
178 */
179 #ifdef Q_OS_WIN
180 #pragma pack(push, 4)
181 #endif
182 
184 template <class Base, class Proxy, class CellMeshData, GmCellType T, int N, int VN> class GmpCellBaseWithId
185  : public GmpCellBase<Base, Proxy, CellMeshData, T, N, VN>
186 {
187 public:
188  // See comments on the base class
189  virtual int cellId() const { return GmpCellIndex(_cellId); }
190 
191  // See comments on the base class
192  virtual GmCellMesh* mesh() const { return CellMeshData::mesh(GmpCellMeshIndex(_cellId)); }
193 
194  // See comments on the base class
195  virtual int meshId() const { return GmpCellMeshIndex(_cellId); }
196 
197  // See comments on the base class
198  virtual bool active() const { return GmpCellIsActive(_cellId); }
199 
200  // See comments on the base class
201  virtual void setActive(bool active)
202  {
203  if(active == this->active())
204  return;
205 
207  mesh()->activeCellUpdated(type(), active);
208  }
209 
210  // See comments on the base class. For the bold who really know what they are doing
211  virtual void replaceCellId(int id, bool keepActiveFlag)
212  {
214  if(keepActiveFlag)
215  _cellId = GmpCellSetActiveFlag(id, active());
216  else
217  _cellId = id;
218  }
219 
220 protected:
222  GmpCellBaseWithId(int cellId, int meshId)
223  : GmpCellBase<Base, Proxy, CellMeshData, T, N, VN>()
224  {
225  _cellId = GmpCellEncodeId(cellId, meshId, true); // cell is initially active
226  }
227 
228  int _cellId;
229 };
230 
231 #ifdef Q_OS_WIN
232 #pragma pack(pop)
233 #endif
234 
235 
236 
238 template <template<class, class, class, GmCellType, int, int> class CellBase,
239  class Base, class Proxy, class CellMeshData, GmCellType T, int N, int VN>
240 class GmpGhostCellBase : public CellBase<Base, Proxy, CellMeshData, T, N, VN>
241 {
242 public:
244  GmpGhostCellBase(GmCellMesh* mesh, int meshId, int id, int offset)
245  : CellBase<Base, Proxy, CellMeshData, T, N, VN>(mesh, meshId, id, offset)
246  {
247  Q_UNUSED(mesh); // Needed by the surface mesh plugin
248  }
249 
250  // See comments on the base class
251  virtual int numGhostNodes() const { return _ghostList.size(); }
252 
253  // See comments on the base class
254  virtual int addGhostNode(int globalIndex)
255  {
256  int index = GmMesh::clearGhostFlag(globalIndex);
257  if(index < 0 || index >= mesh()->numGhostNodes())
258  return -1;
259 
260  _ghostList.append(GmMesh::setGhostFlag(globalIndex));
261 
262  mesh()->ghostNodesUpdated(_ghostList.size(), _ghostList.size() + N);
263  return N + _ghostList.size() - 1;
264  }
265 
266  // See comments on the base class
267  virtual void removeGhostNode(int localIndex)
268  {
269  assert(localIndex >= N && localIndex < N + (int)_ghostList.size());
270  _ghostList.remove(localIndex-N, 1);
271  }
272 
273  // See comments on the base class
274  virtual int nodeIndex(int localIndex) const
275  {
276  assert(localIndex >= 0 && localIndex < N + (int)_ghostList.size());
277  return localIndex < N ? CellBase<Base, Proxy, CellMeshData, T, N, VN>::nodeIndex(localIndex) : _ghostList[localIndex-N];
278  }
279 
280  // See comments on the base class.
281  virtual void nodes(int* nodeList, bool ghost) const
282  {
283  CellBase<Base, Proxy, CellMeshData, T, N, VN>::nodes(nodeList, false); // Copy geometry nodes
284  if(ghost)
285  memcpy(nodeList+N, _ghostList.data(), _ghostList.size()*sizeof(int));
286  }
287 
288  // See comments on the base class
289  virtual void replaceGhostNodes(int* ghostNodes, int numNodes)
290  {
291  _ghostList.resize(numNodes, GmPODVectorTightGrow);
292  memcpy(_ghostList.data(), ghostNodes, numNodes * sizeof(int));
293  }
294 
295 protected:
296  template <template <class> class Vector> friend struct GmpGemaCellMeshData;
297 
315 };
316 
322 template <int H>
324 {
325 public:
326  // See comments on GmHElement::POrder()
327  virtual int hPOrder() const { return GmpCellMeshDataBase::hierarchicalPOrder(H); }
328 
329  // See comments on GmHElement::QOrder()
330  virtual int hQOrder() const { return GmpCellMeshDataBase::hierarchicalQOrder(H); }
331 };
332 
333 
340 template <template<class, class, class, GmCellType, int, int> class T, class Base, class Proxy, class CellMeshData>
341 GmCell* GmpCellFactory(GmCellMesh* mesh, int meshId, GmCellType type, int hindex, int id, int offset)
342 {
343  Q_UNUSED(hindex);
344  assert(!GmCellGeometry(type).isHierarchical());
345  assert(hindex == -1);
346 
347 #ifdef CREATE_CELL
348 #error Create Cell macro already defined
349 #endif
350 
351 #define CREATE_CELL(type, nn, nv) new T<Base, Proxy, CellMeshData, type, nn, nv>(mesh, meshId, id, offset)
352 
353  switch(type)
354  {
355  // The first macro parameter after the cell type is the number of nodes of that type.
356  // The second, is the number of element vertices (or "topological" nodes), ignoring any
357  // mid edge, face or volume nodes that do not contribute for the cell topology. For a Quad8
358  // element, for example, the number of nodes is 8 but the number of vertices is 4. This
359  // parameter is needed by the surface mesh implementation.
360  case GM_BAR2: return CREATE_CELL(GM_BAR2, 2, 2);
361  case GM_BAR3: return CREATE_CELL(GM_BAR3, 3, 2);
362  case GM_BAR3D2: return CREATE_CELL(GM_BAR3D2, 2, 2);
363  case GM_BAR3D3: return CREATE_CELL(GM_BAR3D3, 3, 2);
364  case GM_QUAD4: return CREATE_CELL(GM_QUAD4, 4, 4);
365  case GM_QUAD8: return CREATE_CELL(GM_QUAD8, 8, 4);
366  case GM_QUAD9: return CREATE_CELL(GM_QUAD9, 9, 4);
367  case GM_QUAD3D4: return CREATE_CELL(GM_QUAD3D4, 4, 4);
368  case GM_QUAD3D8: return CREATE_CELL(GM_QUAD3D8, 8, 4);
369  case GM_TRI3: return CREATE_CELL(GM_TRI3, 3, 3);
370  case GM_TRI6: return CREATE_CELL(GM_TRI6, 6, 3);
371  case GM_TRI3D3: return CREATE_CELL(GM_TRI3D3, 3, 3);
372  case GM_TRI3D6: return CREATE_CELL(GM_TRI3D6, 6, 3);
373  case GM_INT2DL4: return CREATE_CELL(GM_INT2DL4, 4, 4);
374  case GM_INT2DL6: return CREATE_CELL(GM_INT2DL6, 6, 4);
375  case GM_INT2DQ6: return CREATE_CELL(GM_INT2DQ6, 6, 4);
376  //case GM_INT2DQ8: return CREATE_CELL(GM_INT2DQ8, 8, 4);
377  case GM_HEX8: return CREATE_CELL(GM_HEX8, 8, 8);
378  case GM_HEX20: return CREATE_CELL(GM_HEX20, 20, 8);
379  case GM_HEX27: return CREATE_CELL(GM_HEX27, 27, 8);
380  case GM_TET4: return CREATE_CELL(GM_TET4, 4, 4);
381  case GM_TET10: return CREATE_CELL(GM_TET10, 10, 4);
382  case GM_INT3DL8: return CREATE_CELL(GM_INT3DL8, 8, 8);
383  case GM_INT3DL12: return CREATE_CELL(GM_INT3DL12, 12, 8);
384  case GM_INT3DQ16: return CREATE_CELL(GM_INT3DQ16, 16, 8);
385  //case GM_INT3DQ20: return CREATE_CELL(GM_INT3DQ20, 20, 8);
386  case GM_INT3DL6: return CREATE_CELL(GM_INT3DL6, 6, 6);
387  case GM_INT3DL9: return CREATE_CELL(GM_INT3DL9, 9, 6);
388  case GM_INT3DQ12: return CREATE_CELL(GM_INT3DQ12, 12, 6);
389  //case GM_INT3DQ15: return CREATE_CELL(GM_INT3DQ15, 15, 6);
390  case GM_WEDGE6: return CREATE_CELL(GM_WEDGE6, 6, 6);
391  case GM_WEDGE15: return CREATE_CELL(GM_WEDGE15, 15, 6);
392  case GM_PYRA5: return CREATE_CELL(GM_PYRA5, 5, 5);
393  case GM_PYRA13: return CREATE_CELL(GM_PYRA13, 13, 5);
394 
395  default:
396  assert(0);
397  }
398 #undef CREATE_CELL
399 
400  return NULL;
401 }
402 
404 template <template<class, class, class, GmCellType, int, int> class T, class CellMeshData>
405 GmCell* GmpHElementFactory(GmCellMesh* mesh, int meshId, GmCellType type, int hindex, int id, int offset)
406 {
407  assert(GmCellGeometry(type).isHierarchical());
408  assert(hindex >= 0 && hindex < GmpCellMeshDataMaxHTypes);
409 
410 #if GmpCellMeshDataMaxHTypes != 3
411 #error Unexpected value for GmpCellMeshDataMaxHTypes
412 #endif
413 
414 #ifdef CREATE_CELL
415 #error Create Cell macro already defined
416 #endif
417 
418 #define CREATE_CELL(i, type, nn, nv) new T<GmpHElementBase<i>, GmLuaHElement, CellMeshData, type, nn, nv>(mesh, meshId, id, offset)
419 
420  switch(type)
421  {
422  case GM_HQUADP: // Can someone find a better way for doing this? Please, pretty please...
423  if (hindex == 0) return CREATE_CELL(0, GM_HQUADP, 4, 4);
424  else if(hindex == 1) return CREATE_CELL(1, GM_HQUADP, 4, 4);
425  else if(hindex == 2) return CREATE_CELL(2, GM_HQUADP, 4, 4);
426  else
427  assert(0);
428  case GM_DGQUAD:
429  if (hindex == 0) return CREATE_CELL(0, GM_DGQUAD, 4, 4);
430  else if(hindex == 1) return CREATE_CELL(1, GM_DGQUAD, 4, 4);
431  else if(hindex == 2) return CREATE_CELL(2, GM_DGQUAD, 4, 4);
432  else
433  assert(0);
434  case GM_HHEXP:
435  if (hindex == 0) return CREATE_CELL(0, GM_HHEXP, 8, 8);
436  else if(hindex == 1) return CREATE_CELL(1, GM_HHEXP, 8, 8);
437  else if(hindex == 2) return CREATE_CELL(2, GM_HHEXP, 8, 8);
438  else
439  assert(0);
440  case GM_DGHEX:
441  if (hindex == 0) return CREATE_CELL(0, GM_DGHEX, 8, 8);
442  else if(hindex == 1) return CREATE_CELL(1, GM_DGHEX, 8, 8);
443  else if(hindex == 2) return CREATE_CELL(2, GM_DGHEX, 8, 8);
444  else
445  assert(0);
446  default:
447  assert(0);
448  }
449 #undef CREATE_CELL
450 
451  return NULL;
452 }
453 
454 
455 #endif
GM_QUAD3D8
GM_WEDGE6
An auxiliar class that can be used as the base class for GmpCellBase for Hierarchical elements....
Definition: gmpCellBase.h:323
GmpCellBaseWithId(int cellId, int meshId)
Constructs a cell given its id and associated mesh id.
Definition: gmpCellBase.h:222
GmpGhostCellBase(GmCellMesh *mesh, int meshId, int id, int offset)
Constructs a cell given its id and associated mesh id.
Definition: gmpCellBase.h:244
GM_HEX20
GM_QUAD4
static int hierarchicalQOrder(int index)
Returns the Q order for hierarchical elements associated with the given index (returned by hierarchic...
Definition: gmpCellMeshData.h:90
static int GmpCellSetActiveFlag(int cellId, bool active)
Returns the encoded cell id to represent an active/inactive cell dep3ending on the second parameter.
Definition: gmpCellBase.h:77
GM_HEX27
GmpCellBase()
Constructs a cell.
Definition: gmpCellBase.h:120
static int GmpCellMakeActive(int cellId)
Returns the encoded cell id with the flag set to represent an active cell.
Definition: gmpCellBase.h:71
GM_TET4
GmCell * GmpHElementFactory(GmCellMesh *mesh, int meshId, GmCellType type, int hindex, int id, int offset)
An alternative version to GmpCellFactory() for creating hierarchical elements.
Definition: gmpCellBase.h:405
GM_TRI3D6
GM_DGHEX
static int setGhostFlag(int nodeIndex)
GM_HQUADP
GM_INT2DL4
static GmpCellMeshDataBase * meshData(int meshId)
Returns the mesh data pointer associated with the given mesh id.
Definition: gmpCellMeshData.h:98
GM_TRI3D3
GM_QUAD8
virtual void activeCellUpdated(GmCellType type, bool active)=0
GM_BAR3
GM_BAR2
GmPODVector< int, uint32_t, GmPODVectorFastGrow< uint32_t > > _ghostList
List storing cell ghost nodes. Uses a GmPODVector with size control based on a 32 bits value giving a...
Definition: gmpCellBase.h:314
CellMeshData * meshData() const
Returns the mesh data object associated with this cell's mesh.
Definition: gmpCellBase.h:154
#define GMP_GEMAMESH_MAX_NUM_CELLS
The maximum number of allowed cells.
Definition: gmpGemaMeshConfig.h:52
GM_BAR3D3
GM_INT3DL8
bool append(const T &v)
GM_WEDGE15
static int clearGhostFlag(int nodeIndex)
GM_TRI6
GM_INT3DQ16
#define GMP_GEMAMESH_CELL_ID_BITS
The number of bits effectivelly used to encode the cell id inside a 32 bits integer,...
Definition: gmpGemaMeshConfig.h:46
GM_HEX8
GM_INT3DQ12
int _cellId
The cell index inside the mesh. MSB is used to control if the cell is active or not.
Definition: gmpCellBase.h:228
GM_TET10
static bool GmpCellIsActive(int cellId)
Returns true if the given index is an active cell index, false if not. Inactive cells have their most...
Definition: gmpCellBase.h:68
GM_HHEXP
Declaration of the GmpCellMeshData structure.
Auxiliar structure used to share data between GmpGemaCellMesh and GmpMeshLoader.
Definition: gmpGemaCellMeshData.h:36
#define GM_CELLBASE_ACTIVE_MASK
Mask with 1 on the MSB to tell if the cell is active (MSB = 0) or not (MSB = 1)
Definition: gmpCellBase.h:50
#define GmpCellMeshDataMaxHTypes
The maximum number of distinct hierarchical type orders that can be used simmultaneously....
Definition: gmpCellMeshData.h:57
GM_QUAD3D4
Template class used to add ghost node support to template class CellBase.
Definition: gmpCellBase.h:240
static int hierarchicalPOrder(int index)
Returns the P order for hierarchical elements associated with the given index (returned by hierarchic...
Definition: gmpCellMeshData.h:85
bool resize(ControlSize newSize, GmPODGrowT grow=Grow)
GM_TRI3
static int GmpCellUpdateMeshIndex(int id, int oldId)
Returns the value of id with the mesh bits updated with the mesh from oldId.
Definition: gmpCellBase.h:87
#define GM_CELLBASE_CELL_MASK
Mask with 1 on bits representing the cell id part (least significant bits up to the mesh mask).
Definition: gmpCellBase.h:58
GM_PYRA13
static int GmpCellMakeInactive(int cellId)
Returns the encoded cell id with the flag set to represent an inactive cell.
Definition: gmpCellBase.h:74
GM_QUAD9
GM_INT3DL9
Class for storing cell data, implementing the virtual functions needed to store per cell type data,...
Definition: gmpCellBase.h:116
GmCellType
GM_INT2DL6
GM_DGQUAD
#define GM_CELLBASE_MESH_MASK
Mask with 1 on bits 29, 30 and 31. Used to extract the mesh index from the top id bits (taking into a...
Definition: gmpCellBase.h:55
void remove(ControlSize index, ControlSize numValues)
GM_INT2DQ6
GM_BAR3D2
static void pushObject(lua_State *L, Base *obj)
static int GmpCellIndex(int cellId)
Returns the cell index encoded in a cell id.
Definition: gmpCellBase.h:84
GM_INT3DL12
static int GmpCellMeshIndex(int cellId)
Returns the mesh index encoded in a cell id.
Definition: gmpCellBase.h:81
#define GMP_GEMAMESH_MAX_NUM_MESHES
The maximum number of allowed meshes.
Definition: gmpGemaMeshConfig.h:49
Adds cell id and active information to a GmpCellBase class.
Definition: gmpCellBase.h:184
const T * data() const
ControlSize size() const
GM_PYRA5
GM_INT3DL6
static int GmpCellEncodeId(int cellIndex, int meshIndex, bool active)
Encodes the given cell index, mesh index and active flag into a cell id.
Definition: gmpCellBase.h:90
GmCell * GmpCellFactory(GmCellMesh *mesh, int meshId, GmCellType type, int hindex, int id, int offset)
A factory function for allocating cell objects.
Definition: gmpCellBase.h:341