Dendro  5.01
Dendro in Greek language means tree. The Dendro library is a large scale (262K cores on ORNL's Titan) distributed memory adaptive octree framework. The main goal of Dendro is to perform large scale multiphysics simulations efficeiently in mordern supercomputers. Dendro consists of efficient parallel data structures and algorithms to perform variational ( finite element) methods and finite difference mthods on 2:1 balanced arbitary adaptive octrees which enables the users to perform simulations raning from black holes (binary black hole mergers) to blood flow in human body, where applications ranging from relativity, astrophysics to biomedical engineering.
feMatrix.h
1 //
2 // Created by milinda on 10/30/18.
3 //
8 #ifndef DENDRO_5_0_FEMATRIX_H
9 #define DENDRO_5_0_FEMATRIX_H
10 
11 #include "feMat.h"
12 
13 template<typename T>
14 void fem_eMatTogMat(ot::MatRecord *eMat, const T *Imat_p2c, unsigned int pOrder,unsigned int dof=1) {
15  const unsigned int n = (pOrder + 1);
16  const unsigned int nPe = n * n * n;
17  const unsigned int N = nPe * dof;
18  const unsigned int dof2=dof*dof;
19 
20  // todo : need to fix this properly, with efficient matrix matrix multiplication.
21  T * IT_Ke_I =new T[N * N];
22 
23  for(unsigned int di =0; di< dof; di++)
24  for(unsigned int dj=0; dj< dof; dj++)
25  {
26  const unsigned int offset = (di*dof + dj)*nPe*nPe;
27  for (unsigned int i = 0; i < nPe; i++)
28  for(unsigned int j=0; j < nPe; j++)
29  {
30  T val = (T)0;
31  for(unsigned int k=0;k< nPe; k++)
32  {
33  val += (eMat[offset + i*nPe +k].getMatVal() * Imat_p2c[k * nPe + j]);
34  }
35  IT_Ke_I[offset + i*nPe +j] = val;
36  }
37  }
38 
39  for(unsigned int di =0; di< dof; di++)
40  for(unsigned int dj=0; dj< dof; dj++)
41  {
42  const unsigned int offset = (di*dof + dj)*nPe*nPe;
43 
44  for (unsigned int i = 0; i < nPe; i++)
45  for(unsigned int j=0; j < nPe; j++)
46  {
47  eMat[offset + i*nPe +j].setMatValue(IT_Ke_I[offset + i*nPe +j]);
48  }
49  }
50 
51 
52  for(unsigned int di =0; di< dof; di++)
53  for(unsigned int dj =0; dj< dof; dj++)
54  {
55  const unsigned int offset = (di*dof + dj)*nPe*nPe;
56  for (unsigned int i = 0; i < nPe; i++)
57  for(unsigned int j=0; j < nPe; j++)
58  {
59  T val = (T)0;
60  for(unsigned int k=0;k< nPe; k++)
61  {
62  val += ( Imat_p2c[k * nPe + i] * eMat[offset + k*nPe +j].getMatVal());
63  }
64  IT_Ke_I[offset + i*nPe + j] = val;
65  }
66  }
67 
68  for(unsigned int di =0; di< dof; di++)
69  for(unsigned int dj=0; dj< dof; dj++)
70  {
71  const unsigned int offset = (di*dof + dj)*nPe*nPe;
72  for (unsigned int i = 0; i < nPe; i++)
73  for(unsigned int j=0; j < nPe; j++)
74  {
75  eMat[offset + i*nPe + j].setMatValue(IT_Ke_I[offset + i*nPe + j]);
76  }
77  }
78 
79 
80  delete [] IT_Ke_I;
81 }
82 
83 
84 template<typename T>
85 class feMatrix : public feMat {
86 
87 protected:
88 
90  unsigned int m_uiDof;
91 
93  VECType *m_uiEleVecIn;
94 
95  /***@brief element nodal vecOut */
96  VECType *m_uiEleVecOut;
97 
99  double *m_uiEleCoords;
100 
101 public:
106  feMatrix(ot::DA *da, unsigned int dof = 1);
107 
108  ~feMatrix();
109 
115  virtual void matVec(const VECType *in, VECType *out, double scale = 1.0);
116 
117 
123  virtual void elementalMatVec(const VECType *in, VECType *out, double *coords = NULL, double scale = 1.0) = 0;
124 
125 
126 #ifdef BUILD_WITH_PETSC
127 
133  virtual void matVec(const Vec &in, Vec &out, double scale = 1.0);
134 
141  virtual bool getAssembledMatrix(Mat *J, MatType mtype);
142 
143 
144 #endif
145 
147  T &asLeaf() { return static_cast<T &>(*this); }
148 
149 
157  bool preMatVec(const VECType *in, VECType *out, double scale = 1.0) {
158  return asLeaf().preMatVec(in, out, scale);
159  }
160 
161 
168  bool postMatVec(const VECType *in, VECType *out, double scale = 1.0) {
169  return asLeaf().postMatVec(in, out, scale);
170  }
171 
173  bool preMat() {
174  return asLeaf().preMat();
175  }
176 
178  bool postMat() {
179  return asLeaf().postMat();
180  }
181 
189  void getElementalMatrix(unsigned int eleID, std::vector<ot::MatRecord> &records, double *coords) {
190  return asLeaf().getElementalMatrix(eleID, records, coords);
191  }
192 
193 
194 };
195 
196 template<typename T>
197 feMatrix<T>::feMatrix(ot::DA *da, unsigned int dof) : feMat(da) {
198  m_uiDof = dof;
199  const unsigned int nPe = m_uiOctDA->getNumNodesPerElement();
200  m_uiEleVecIn = new VECType[m_uiDof * nPe];
201  m_uiEleVecOut = new VECType[m_uiDof * nPe];
202 
203  m_uiEleCoords = new double[m_uiDim * nPe];
204 
205 }
206 
207 template<typename T>
209  delete[] m_uiEleVecIn;
210  delete[] m_uiEleVecOut;
211  delete[] m_uiEleCoords;
212 
213  m_uiEleVecIn = NULL;
214  m_uiEleVecOut = NULL;
215  m_uiEleCoords = NULL;
216 
217 }
218 
219 template<typename T>
220 void feMatrix<T>::matVec(const VECType *in, VECType *out, double scale) {
221 
222  VECType *_in = NULL;
223  VECType *_out = NULL;
224 
225  if (!(m_uiOctDA->isActive()))
226  return;
227 
228 
229  preMatVec(in, out, scale);
230 
231  m_uiOctDA->nodalVecToGhostedNodal(in, _in, false, m_uiDof);
232  m_uiOctDA->createVector(_out, false, true, m_uiDof);
233 
234  VECType *val = new VECType[m_uiDof];
235  for (unsigned int var = 0; var < m_uiDof; var++)
236  val[var] = (VECType) 0;
237 
238  m_uiOctDA->setVectorByScalar(_out, val, false, true, m_uiDof);
239 
240  delete[] val;
241 
242  const ot::Mesh * pMesh = m_uiOctDA->getMesh();
243  const unsigned int nPe = pMesh->getNumNodesPerElement();
244  double * qMat = new double[nPe*nPe];
245  const unsigned int * e2n_cg = &(*(pMesh->getE2NMapping().begin()));
246  const ot::TreeNode* allElements = &(*(pMesh->getAllElements().begin()));
247 
248  m_uiOctDA->readFromGhostBegin(_in, m_uiDof);
249 
250 
251  const unsigned int totalNodalSize = m_uiOctDA->getTotalNodalSz();
252  for (m_uiOctDA->init<ot::DA_FLAGS::INDEPENDENT>(); m_uiOctDA->curr() < m_uiOctDA->end<ot::DA_FLAGS::INDEPENDENT>(); m_uiOctDA->next<ot::DA_FLAGS::INDEPENDENT>()) {
253 
255  const unsigned int currentId = m_uiOctDA->curr();
256  pMesh->getElementQMat(m_uiOctDA->curr(),qMat,true);
258  elementalMatVec(m_uiEleVecIn, m_uiEleVecOut, m_uiEleCoords, scale);
259 
260  for (unsigned int dof = 0; dof < m_uiDof; dof++) {
261  for (unsigned int i = 0; i < nPe; i++) {
262  VECType ss = (VECType) 0;
263  for (unsigned int j = 0; j < nPe; j++) {
264  ss += qMat[j * nPe + i] * m_uiEleVecOut[dof*nPe + j];
265  }
266  _out[dof*totalNodalSize + e2n_cg[currentId * nPe + i]] += (VECType) ss;
267 
268  }
269  }
270 
271  }
272 
273  m_uiOctDA->readFromGhostEnd(_in, m_uiDof);
274 
275  const unsigned int eleLocalBegin = pMesh->getElementLocalBegin();
276  const unsigned int eleLocalEnd = pMesh -> getElementLocalEnd();
277 
278  for (m_uiOctDA->init<ot::DA_FLAGS::W_DEPENDENT>(); m_uiOctDA->curr() < m_uiOctDA->end<ot::DA_FLAGS::W_DEPENDENT>(); m_uiOctDA->next<ot::DA_FLAGS::W_DEPENDENT>()) {
279 
280  // temporary fix to skip ghost writable.
281  if( m_uiOctDA->curr()< eleLocalBegin || m_uiOctDA->curr()>=eleLocalEnd )
282  continue;
283 
285  const unsigned int currentId = m_uiOctDA->curr();
286  pMesh->getElementQMat(m_uiOctDA->curr(),qMat,true);
288  elementalMatVec(m_uiEleVecIn, m_uiEleVecOut, m_uiEleCoords, scale);
289 
290  for (unsigned int dof = 0; dof < m_uiDof; dof++) {
291  for (unsigned int i = 0; i < nPe; i++) {
292  VECType ss = (VECType) 0;
293  for (unsigned int j = 0; j < nPe; j++) {
294  ss += qMat[j * nPe + i] * m_uiEleVecOut[dof*nPe + j];
295  }
296  _out[dof*totalNodalSize + e2n_cg[currentId * nPe + i]] += (VECType) ss;
297 
298  }
299  }
300 
301  }
302 
303 
304  delete [] qMat;
305 
306  // accumilate from write ghost.
307  m_uiOctDA->writeToGhostsBegin(_out,m_uiDof);
308  m_uiOctDA->writeToGhostsEnd(_out,ot::DA_FLAGS::WriteMode::ADD_VALUES,m_uiDof);
309 
310  m_uiOctDA->ghostedNodalToNodalVec(_out, out, true, m_uiDof);
311 
312  m_uiOctDA->destroyVector(_in);
313  m_uiOctDA->destroyVector(_out);
314 
315  postMatVec(in, out, scale);
316 
317 
318  return;
319 
320 }
321 
322 #ifdef BUILD_WITH_PETSC
323 
324 template<typename T>
325 void feMatrix<T>::matVec(const Vec &in, Vec &out, double scale) {
326 
327  const PetscScalar *inArry = NULL;
328  PetscScalar *outArry = NULL;
329 
330  VecGetArrayRead(in, &inArry);
331  VecGetArray(out, &outArry);
332 
333  matVec(inArry, outArry, scale);
334 
335  VecRestoreArrayRead(in, &inArry);
336  VecRestoreArray(out, &outArry);
337 
338 }
339 
340 
341 template<typename T>
342 bool feMatrix<T>::getAssembledMatrix(Mat *J, MatType mtype) {
343 
344 
345  if(m_uiOctDA->isActive())
346  {
347  MatZeroEntries(*J);
348  std::vector<ot::MatRecord> records;
349  //
350  const unsigned int eleOrder = m_uiOctDA->getElementOrder();
351  const unsigned int npe_1d = eleOrder + 1;
352  const unsigned int npe_2d = (eleOrder + 1) * (eleOrder + 1);
353  const unsigned int nPe = (eleOrder + 1) * (eleOrder + 1) * (eleOrder + 1);
354 
355  const ot::Mesh *pMesh = m_uiOctDA->getMesh();
356  const ot::TreeNode *allElements = &(*(pMesh->getAllElements().begin()));
357 
358  DendroScalar *p2cEleMat = new DendroScalar[nPe * nPe];
359 
360  preMat();
361  unsigned int nCount = 0;
362 
363  double *coords = new double[m_uiDim * nPe];
364 
365  bool faceHang[NUM_FACES];
366  bool edgeHang[NUM_EDGES];
367  unsigned int cnumFace[NUM_FACES];
368  unsigned int cnumEdge[NUM_EDGES];
369 
370  const unsigned int * e2n_cg = &(*(pMesh->getE2NMapping().begin()));
371  const unsigned int * e2n_dg = &(*(pMesh->getE2NMapping_DG().begin()));
372  const unsigned int * e2e = &(*(pMesh->getE2EMapping().begin()));
373 
374  const unsigned int eleLocalBegin = pMesh->getElementLocalBegin();
375  const unsigned int eleLocalEnd = pMesh -> getElementLocalEnd();
376 
377  for (m_uiOctDA->init<ot::DA_FLAGS::LOCAL_ELEMENTS>();m_uiOctDA->curr() < m_uiOctDA->end<ot::DA_FLAGS::LOCAL_ELEMENTS>(); m_uiOctDA->next<ot::DA_FLAGS::LOCAL_ELEMENTS>()) {
378 
379  const unsigned int currentId = m_uiOctDA->curr();
380  m_uiOctDA->getElementalCoords(currentId, coords);
381  getElementalMatrix(m_uiOctDA->curr(), records, coords);
382  const unsigned int cnum = allElements[currentId].getMortonIndex();
383 
384  pMesh->getElementQMat(m_uiOctDA->curr(),p2cEleMat,true);
385  //printArray_2D(p2cEleMat,nPe,nPe);
386 
387 
388  fem_eMatTogMat(&(*(records.begin() + nCount)), p2cEleMat, eleOrder,m_uiDof);
389  nCount += (m_uiDof*nPe*nPe*m_uiDof);
390  if (records.size() > 500) {
391  m_uiOctDA->petscSetValuesInMatrix(*J, records, m_uiDof, ADD_VALUES);
392  nCount = 0;
393  }
394 
395  }//end writable
396 
397  m_uiOctDA->petscSetValuesInMatrix(*J, records, m_uiDof, ADD_VALUES);
398 
399  postMat();
400 
401  MatAssemblyBegin(*J, MAT_FINAL_ASSEMBLY);
402  MatAssemblyEnd(*J, MAT_FINAL_ASSEMBLY);
403 
404  delete[] p2cEleMat;
405  delete[] coords;
406 
407  PetscFunctionReturn(0);
408  }
409 
410 
411 }
412 
413 
414 #endif
415 
416 
417 #endif //DENDRO_5_0_FEMATRIX_H
bool postMat()
executed after the matrix assembly
Definition: feMatrix.h:178
unsigned int getNumNodesPerElement() const
get number of nodes per element
Definition: oda.h:257
DendroScalar getMatVal() const
returns the entry value
Definition: matRecord.h:133
void getElementQMat(unsigned int currentId, double *&qMat, bool isAllocated=true) const
: Compute the elemental interpolation matrix.
Definition: mesh.cpp:9436
virtual void elementalMatVec(const VECType *in, VECType *out, double *coords=NULL, double scale=1.0)=0
Computes the elemental matvec.
bool postMatVec(const VECType *in, VECType *out, double scale=1.0)
executed just after the matVec loop in matvec function
Definition: feMatrix.h:168
Abstract class for stiffness matrix computation.
Definition: feMat.h:18
VECType * m_uiEleVecIn
element nodal vec in
Definition: feMatrix.h:93
A class to manage octants.
Definition: TreeNode.h:35
T & asLeaf()
static cast to the leaf node of the inheritance
Definition: feMatrix.h:147
void readFromGhostEnd(T *vec, unsigned int dof=1)
Sync the ghost element exchange.
unsigned int end()
Returns if the current element has reached end or not.
void next()
: increment it to the next element.
void getElementalMatrix(unsigned int eleID, std::vector< ot::MatRecord > &records, double *coords)
Compute the elemental Matrix.
Definition: feMatrix.h:189
void getElementNodalValues(const T *in, T *eleVecOut, unsigned int eleID, unsigned int dof=1) const
computes the element nodal values using interpolation if needed.
Definition: mesh.h:179
void ghostedNodalToNodalVec(const T *gVec, T *&local, bool isAllocated=false, unsigned int dof=1) const
convert ghosted nodal vector to local vector (without ghosting)
void readFromGhostBegin(T *vec, unsigned int dof=1)
Initiate the ghost nodal value exchange.
const std::vector< unsigned int > & getE2NMapping_DG() const
Definition: mesh.h:1082
void nodalVecToGhostedNodal(const T *in, T *&out, bool isAllocated=false, unsigned int dof=1) const
convert nodal local vector with ghosted buffer regions.
unsigned int getElementLocalBegin() const
return the begin location of element local
Definition: mesh.h:1030
void setMatValue(DendroScalar value)
sets matrix value
Definition: matRecord.h:136
unsigned int m_uiDof
number of dof
Definition: feMatrix.h:90
void destroyVector(T *&local) const
deallocates the memory allocated for a vector
Definition: matRecord.h:26
const std::vector< ot::TreeNode > & getAllElements() const
returns the pointer to All elements array.
Definition: mesh.h:1058
unsigned int getNumNodesPerElement() const
return the number of nodes per element.
Definition: mesh.h:1090
ot::DA * m_uiOctDA
: pointer to OCT DA
Definition: feMat.h:23
bool preMat()
executed before the matrix assembly
Definition: feMatrix.h:173
feMatrix(ot::DA *da, unsigned int dof=1)
constructs an FEM stiffness matrix class.
Definition: feMatrix.h:197
double * m_uiEleCoords
Definition: feMatrix.h:99
unsigned int curr()
get the current elmenent in the iteration
unsigned int getElementOrder() const
get element order
Definition: oda.h:260
Definition: oda.h:125
const std::vector< unsigned int > & getE2NMapping() const
Definition: mesh.h:1073
virtual void matVec(const VECType *in, VECType *out, double scale=1.0)
Computes the LHS of the weak formulation, normally the stifness matrix times a given vector...
Definition: feMatrix.h:220
void writeToGhostsEnd(T *vec, DA_FLAGS::WriteMode mode, unsigned int dof=1)
Sync accumilation across ghost elements.
void getElementalCoords(unsigned int eleID, double *coords) const
computes the elementCoordinates (based on the nodal placement)
Definition: oda.cpp:264
bool isActive() const
see if the current DA is active
Definition: oda.h:254
int createVector(T *&local, bool isElemental=false, bool isGhosted=false, unsigned int dof=1) const
Creates a ODA vector.
const std::vector< unsigned int > & getE2EMapping() const
returns const e2e mapping instance.
Definition: mesh.h:1070
void setVectorByScalar(T *local, const T *value, bool isElemental=false, bool isGhosted=false, unsigned int dof=1) const
initialize a variable vector to a function depends on spatial coords.
void writeToGhostsBegin(T *vec, unsigned int dof=1)
Initiate accumilation across ghost elements.
const ot::Mesh * getMesh() const
returns the mesh
Definition: oda.h:269
unsigned int getTotalNodalSz() const
returns the total nodal size (this includes the ghosted region as well.)
Definition: oda.h:245
Definition: feMatrix.h:85
void init()
initialize the loop counters.
bool preMatVec(const VECType *in, VECType *out, double scale=1.0)
executed just before the matVec loop in matvec function
Definition: feMatrix.h:157