CEPS  24.01
Cardiac ElectroPhysiology Simulator
FiniteElements.cpp
Go to the documentation of this file.
1 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2  This file is part of CEPS.
3 
4  CEPS is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8 
9  CEPS is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with CEPS (see file LICENSE at root of project).
16  If not, see <https://www.gnu.org/licenses/>.
17 
18 
19  Copyright 2019-2024 Inria, Universite de Bordeaux
20 
21  Authors, in alphabetical order:
22 
23  Pierre-Elliott BECUE, Florian CARO, Yves COUDIERE(*), Andjela DAVIDOVIC,
24  Charlie DOUANLA-LONTSI, Marc FUENTES, Mehdi JUHOOR, Michael LEGUEBE(*),
25  Pauline MIGERDITICHAN, Valentin PANNETIER(*), Nejib ZEMZEMI.
26  * : currently active authors
27 
28 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
37 
38 // ----------------------------------------------------------------------------------------
39 // Public methods
40 // ----------------------------------------------------------------------------------------
41 
43  AbstractDiscretization(problem),
44  m_order (order),
45  m_refElems ({}),
46  m_nodes (nullptr),
47  m_volElems (nullptr),
48  m_bdrElems (nullptr)
49 {
50 
51  m_spatialUnknownsLocation = CepsLocationFlag::Point;
52 
53  CEPS_SAYS("Creating Finite Elements...");
54  if (ceps::isProfiling())
55  getProfiler()->start("buildFE","building finite elements and degrees of freedom");
56 
57  // Initialize reference finite elements
58  CEPS_SAYS_NOENDL(" 1/4 Creating reference finite elements of order " << order << "...");
59  initializeRefElements();
60  CEPS_SAYS_INLINE(" Done.");
61 
62  ceps::barrier();
63 
64  // Create all DistributedInfos structures with nodes and elements
65  CEPS_SAYS_NOENDL(" 2/4 Building finite elements...");
66  buildElements();
67 
68  ceps::barrier();
69 
70  computeNeighbors();
71  // Synchronize all containers
72  // The globalId of cells was already set from geometry global id (one geom cell = one finite elem)
73  // For nodes, the loop through nodes is not the same as geom, and there may be additional nodes.
74  // So we need to recompute the global indices of FE nodes.
75  m_volElems->synchronize(false);
76  m_bdrElems->synchronize(false);
77  m_nodes ->synchronize(true,&setGlobalIndexFunction<FENode>);
78 
79  CEPS_SAYS_INLINE(" Done.");
80 
81  ceps::barrier();
82 
83  // Build degrees of freedom tree from the problem data, then distributed infos and factory
84  CEPS_SAYS_NOENDL(" 3/4 Building degrees of freedom on FE nodes...");
85  buildDofs();
86  CEPS_SAYS_INLINE(" Done.");
87 
88  CEPS_SAYS_NOENDL(" 4/4 Assembling finite elements mass and stiffness matrices...");
89  m_mass = newDofMatrix();
90  m_stiff = newDofMatrix();
91 
92  FEMassAssembler asbm(this);
93  FEDivKGradAssembler asbs(this);
94  for (Unknown* u: m_problem->getSpatialUnknowns())
95  asbs.setKForUnknown(u,1.);
96 
97  asbm.setMatrix(m_mass .get());
98  asbs.setMatrix(m_stiff.get());
99  asbm.assemble();
100  asbs.assemble();
101  CEPS_SAYS_INLINE(" Done.");
102 
103  CEPS_SAYS("Finite elements ready");
104  if (ceps::isProfiling())
105  getProfiler()->stop("buildFE");
106 
107 }
108 
110 {
111  for (auto& it : m_refElems)
112  for (auto& ref: it.second)
113  ceps::destroyObject(ref);
114 
121 }
122 
125 {
126  return m_volElems->getOwned();
127 }
128 
131 {
132  return m_bdrElems->getOwned();
133 }
134 
135 CepsUInt
137 {
138  return m_nodes->getNumberOfHalo();
139 }
140 
141 CepsUInt
143 {
144  return m_nodes->getNumberOfOwned();
145 }
146 
147 const CepsVector<FENode*>&
149 {
150  return m_nodes->getOwned();
151 }
152 
153 const CepsVector<FENode*>&
155 {
156  return m_nodes->getHalo();
157 }
158 
159 FENode*
161 {
162  if (isOwnedFENode(nID))
163  return m_nodes->getOwnedMapping()->atGlobal(nID);
164 
165  if (isHaloFENode(nID))
166  return m_nodes->getHaloMapping()->atGlobal(nID);
167 
168  return nullptr;
169 }
170 
171 CepsBool
173 {
174  return m_nodes->getOwnedMapping()->hasGlobal(nID);
175 }
176 
177 CepsBool
179 {
180  return m_nodes->getHaloMapping()->hasGlobal(nID);
181 }
182 
185 {
187  CepsUInt iloc = static_cast<CepsUInt> (CepsLocationFlag::Point);
188  for (FENode* node: elem->getNodes())
189  for (DegreeOfFreedom* dof: m_dofsTree[iloc][node->getGlobalIndex()])
190  res.push_back(dof);
191 
192  return res;
193 }
194 
197 {
199 
200  CepsUInt iloc = static_cast<CepsUInt> (CepsLocationFlag::Point);
201  for (FENode* node: elem->getNodes())
202  for (DegreeOfFreedom* dof: m_dofsTree[iloc][node->getGlobalIndex()])
203  if (ceps::contains(us, dof->getUnknown()))
204  res.push_back(dof);
205 
206  iloc = static_cast<CepsUInt> (CepsLocationFlag::Cell);
207  for (DegreeOfFreedom* dof: m_dofsTree[iloc][elem->getProperties()->getGlobalIndex()])
208  if (ceps::contains(us, dof->getUnknown()))
209  res.push_back(dof);
210 
211  iloc = static_cast<CepsUInt> (CepsLocationFlag::ZeroD);
212  for (auto l: m_dofsTree[iloc])
213  for (DegreeOfFreedom* dof: l.second)
214  if (ceps::contains(us, dof->getUnknown()))
215  res.push_back(dof);
216 
217  return res;
218 }
219 
220 CepsIndex
222 {
224  "nullptr dof"
225  );
226  CEPS_ABORT_IF(not dof->getUnknown()->isSpatial(),
227  "you are trying to return a spatial index for a non-local "
228  "unknown with name '"
229  << dof->getUnknown()->getName() << "'"
230  );
231  return dof->getGeomId();
232 }
233 
234 // --------------------------------------------------------------------------
235 
236 DMatPtr
238 {
239  return m_mass;
240 }
241 
242 DMatPtr
244 {
245  return m_stiff;
246 }
247 
248 
249 // --------------------------------------------------------------------------
250 
251 CepsReal
253  DHVecPtr u,
254  DHVecPtr v,
255  CepsBool boundary,
256  const CepsSet<CepsAttribute>& attrs,
257  const CepsVector<Unknown*>& unknowns
258 )
259 {
260 
261  CepsBool restrictions = boundary or not attrs.empty() or not unknowns.empty();
262 
263  if (not restrictions) { // Simply use the precomputed mass matrix
264  DVecPtr tmp = newDofVector();
265  tmp->mult(*m_mass,*u);
266  return v->dot(*tmp);
267  }
268 
269  // Create a special assembler for this purpose
270  // FIXME this is higly memory and time inefficient.
271  // We should implement integrators in parallel to assemblers, which, instead of
272  // of storing the coefficients in the matrix, simply add the element contribution to a sum
273  // {
274  // FEMassAssembler asb(this,boundary,attrs,unknowns);
275  // DMatPtr mat = newDofMatrix();
276  // asb.setMatrix(mat.get());
277  // asb.assemble();
278  // tmp->mult(*mat,*u);
279  FEMassIntegrator itg(this,boundary,attrs,unknowns);
280  return itg.integrate(v,u);
281  // }
282 
283 
284 }
285 
286 CepsReal
288  DHVecPtr u,
289  DHVecPtr v,
290  CepsBool boundary,
291  const CepsSet<CepsAttribute>& attrs,
292  const CepsVector<Unknown*>& unknowns
293 )
294 {
295  CepsBool restrictions = boundary or not attrs.empty() or not unknowns.empty();
296 
297  DVecPtr tmp = newDofVector();
298 
299  if (not restrictions) { // Simply use the precomputed mass matrix
300  tmp->mult(*m_stiff,*u);
301  }
302  else // Create a special assembler for this purpose
303  // this is higly memory and time inefficient.
304  {
305  FEDivKGradAssembler asb(this,boundary,attrs,unknowns);
306  for (Unknown* un: unknowns.empty() ? m_problem->getSpatialUnknowns() : unknowns)
307  asb.setKForUnknown(un,1.);
308  DMatPtr mat = newDofMatrix();
309  asb.setMatrix(mat.get());
310  asb.assemble();
311  tmp->mult(*mat,*u);
312  }
313  return v->dot(*tmp);
314 }
315 
316 CepsReal
318  DHVecPtr v,
319  CepsBool boundary,
320  const CepsSet<CepsAttribute>& attrs,
321  const CepsVector<Unknown*>& unknowns
322 )
323 {
324  return(std::sqrt(stiffProduct(v,v,boundary,attrs,unknowns)));
325 }
326 
327 
328 // --------------------------------------------------------------------------
329 // Protected methods
330 // --------------------------------------------------------------------------
331 
332 void
334 {
335  for (CepsCellType type : {CepsCellType::Simplex})
336  {
337  CepsFeLagrangeType fetype = {type,m_order};
338  for (CepsUInt dim=0; dim<=3; dim++)
339  m_refElems[type][dim] = ceps::getNew<ReferenceFE>(dim,fetype);
340  }
341  return;
342 }
343 
346 {
347  return m_refElems.at(type).at(dim);
348 }
349 
350 void
352 {
356 
357  CepsUInt nVolCells = 0u, nBdrCells = 0u;
358  for (CepsUInt dim=1;dim<=3;dim++)
359  if (m_geometry->hasMeshOfDim(dim))
360  {
361  nVolCells += m_geometry->getMeshOfDim(dim)->getLocalNbCells();
362  nBdrCells += m_geometry->getMeshOfDim(dim)->getLocalNbBoundaryCells();
363  }
364  m_volElems->getOwned().reserve(nVolCells);
365  m_bdrElems->getOwned().reserve(nBdrCells);
366 
367  // Builds volumic and boundary elements
368  for (CepsUInt dim=1; dim<=3; dim++)
369  {
370  if (m_geometry->hasMeshOfDim(dim))
371  {
374  }
375  }
376 
377 }
378 
379 void
381 {
382 
383  // Some shortcuts
384  ReferenceFE* refElem = nullptr;
385  LocalGlobalMapping<FEBase*>* toBuild = nullptr;
386 
387  if (onBoundary)
388  toBuild = m_bdrElems->getOwnedMapping();
389  else
390  toBuild = m_volElems->getOwnedMapping();
391 
392  CepsCellGlobalIndex cellId;
393  CepsBool foundSameNode;
394  // Loop on geometrical cells
395  for (GeomCell *cell : onBoundary ? mesh->getBoundaryCells() : mesh->getCells())
396  {
397  cellId = cell->getGlobalIndex();
398  // Get the correct reference element for this geometrical element
399  refElem = getReferenceElementOfDim(cell->getCellType(),cell->getDimension());
400 
401  // Create a FiniteElement with the same global index than geometrical cell.
402  // Order is set from reference element.
403  FEBase* fElem = ceps::getNew<FEBase>(cell,false,refElem);
404 
405  // Create the missing FENodes for that element
406  const CepsUInt &n = refElem->getNumberOfBasisVertices();
407 
408  for (CepsUInt i=0U; i<n; ++i)
409  {
410  // Check if the node was not already added in a neighbouring element
411  foundSameNode = false;
412  for (CepsCellGlobalIndex neighId : cell->getNodeSharingCellsIndices())
413  {
414  FEBase* nElem = nullptr;
415  if (m_volElems->hasGlobal(neighId,ceps::getRank()))
416  nElem = m_volElems->atGlobal(neighId,ceps::getRank());
417  else if (m_bdrElems->hasGlobal(neighId,ceps::getRank()))
418  nElem = m_bdrElems->atGlobal(neighId,ceps::getRank());
419 
420  if (ceps::isValidPtr(nElem))
421  checkNeighborsBeforeAssign(fElem,nElem,i,onBoundary,foundSameNode);
422 
423  if (foundSameNode)
424  break;
425  }
426 
427  if (not foundSameNode)
428  createNewNode(fElem, i, onBoundary, mesh);
429  }
430 
431  toBuild->append(fElem,cellId,cellId);
432  }
433  return;
434 }
435 
436 void
438  FEBase* fElem,
439  FEBase* nElem,
440  CepsUInt vertexId,
441  CepsBool boundary,
442  CepsBool& foundSameNode
443 )
444 {
445 
446  ReferenceFE* refFElem = fElem->getReferenceElement();
447  CepsReal3D p = refFElem->getTransformedBasisVertex(vertexId,fElem->getGeomObject());
448 
449  // Loop through all FE nodes of neighbor element that were already created (!=nullptr)
450  for (FENode* node : nElem->getValidNodes())
451  {
452 
453  CepsReal3D q = node->getGeomObject()->getCoordinates();
454 
455  // p is obtained by multiplication by jacobian, so it is prone to floating point errors
456  // We check equality to reach the same level of precision than CepsHash3
457  foundSameNode = areSameArray(p,q,CEPS_HASH3_PRECISION/std::numeric_limits<CepsReal>::epsilon());
458 
459  if (foundSameNode)
460  {
461  node->getProperties()->setOnBoundary(boundary);
462  node->addCell(fElem);
463  fElem->setNodeAt(vertexId,node);
464  return;
465  }
466  }
467 
468  return;
469 }
470 
471 void
472 FiniteElements::createNewNode(FEBase* el, CepsUInt vertexId, CepsBool isBoundary, Mesh* mesh)
473 {
474  const ReferenceFE* refElement = el->getReferenceElement();
475  GeomCell* gCell = el->getGeomObject();
476  CepsInt feNodeCellIndex = refElement->getBasisVertexGeomCellIndex(vertexId);
477  CepsSet<CepsAttribute> attributes = {};
478  CepsUInt owner = 0U;
479  FENode* fenode = nullptr;
480 
481  // if the node is built on a geom node, we can directly use this geom node to get some information
482  if (feNodeCellIndex!=-1)
483  {
484  const GeomNode* gNode = gCell->getNodeAt(feNodeCellIndex);
485  attributes = gNode->getAttributes();
486  owner = gNode->getOwner();
487  fenode = ceps::getNew<FENode>(const_cast<GeomNode*>(gNode),false);
488 
489  }
490  // else, we need to create these informations
491  else
492  {
493 
494  // Compute coordinates of new node
495  CepsReal3D p = refElement->getTransformedBasisVertex(vertexId,gCell);
496  // We need to determine the owner and attributes of this new node.
497  // The rule is given by the reference element.
498  // If the node is -on a face : get data from node with min geom index on the face
499  // -inside the cell : use cell data (normally owner is of node with min geomid)
500 
501  GeomNode* ownerNode = refElement->getNodeOfOwnerForBasisVertex(vertexId,gCell);
502 
503  // We give the global index -1 to say that it is not part of the initial geometry
504  GeomNode* gNode = ceps::getNew<GeomNode>(p[0],p[1],p[2],-1);
505 
506  // Set owner
507  owner = ownerNode->getOwner();
508  gNode->setOwner(owner);
509 
510  // Set attributes
511  attributes = ownerNode->getAttributes();
512  gNode->setAttributes(attributes.begin(),attributes.end());
513 
514  fenode = ceps::getNew<FENode>(gNode,true);
515  }
516 
517  fenode->addCell(el);
518  fenode->getProperties()->setOnBoundary(isBoundary);
519 
520  el->setNodeAt(vertexId,fenode);
521 
522 
523  m_nodes->add(fenode,getNodeHash(fenode),owner);
524 
525  return;
526 }
527 
528 void
530 {
531  // FE Nodes
532  for (auto &all : {m_volElems, m_bdrElems})
533  for (FEBase* el : all->getOwned())
534  {
535  CepsVector<FENode*> nodes = el->getNodes();
536  CepsUInt n = nodes.size();
537  for (CepsUInt i=0U; i<n; ++i)
538  for (CepsUInt j=0U; j<n; ++j)
539  if (i!=j)
540  {
541  if (ceps::argVector(nodes[i]->getNodes(),nodes[j])==-1)
542  {
543  nodes[i]->addNode(nodes[j]);
544  }
545  }
546  }
547 
548  // Elements
549  for (auto &list : {m_nodes->getOwned(), m_nodes->getHalo()})
550  for (FENode* nd : list)
551  {
552  CepsVector<FEBase*> elems = nd->getCells();
553  CepsUInt n = elems.size();
554  for (CepsUInt i=0U; i<n; ++i)
555  for (CepsUInt j=i+1; j<n; ++j)
556  if (ceps::argVector(elems[i]->getCells(),elems[j])==-1)
557  elems[i]->addCell(elems[j]);
558  }
559 
560  return;
561 }
562 
563 CepsHash3
565 {
567 }
568 
569 void
571 {
572 
573  // Set unknowns to be computed on points (FENodes)
574  for (Unknown* u: m_problem->getUnknowns())
575  if (u->isSpatial())
577 
578  // Loops on FE Nodes, owned then halo.
579  // A dof for each unknown defined in at least one of a neighboring cell will be created.
580  // Owned/halo distribution for dofs follows the distribution of FE Nodes.
581  // Unknowns are defined on points, but the discrete variational formulation involves
582  // integrals on cells
583  CepsUInt iloc = static_cast<CepsUInt> (CepsLocationFlag::Point);
584  for (const CepsVector<FENode*>& toParse : {m_nodes->getOwned(), m_nodes->getHalo()})
585  {
586  for (FENode* feNode : toParse)
587  {
588 
589  // Build the set of attributes in cells around this node
590  // We also add the cell attributes to the dofs afterwards
591  // CepsSet<CepsAttribute> attrs;
592  // for (FEBase* nElem : feNode->getCells())
593  // for(CepsAttribute a: nElem->getGeomObject()->getAttributes())
594  // attrs.insert(a);
595  auto attrs = feNode->getGeomObject()->getAttributes();
596 
597  CepsNodeGlobalIndex feId = feNode->getGlobalIndex();
598  CepsNodeGlobalIndex gId = feNode->getGeomObject()->getGlobalIndex();
599  // Now check matching unknowns and create dof when needed
600 
601  for (Unknown* u: m_problem->getUnknowns())
602  {
603  if (u->isSpatial() and (u->hasOneOfAttributes(attrs) or u->hasAttribute(CepsUniversal)))
604  {
605  auto dof = ceps::getNew<DegreeOfFreedom>(u,attrs,gId,0x0,feNode->getGeomObject()->getOwner());
606  dof->setDiscrId(feId);
607  dof->setVertex(feNode->getGeomObject());
608  dof->setOnBoundary(feNode->getGeomObject()->isBoundary());
609  m_dofsTree[iloc][feId].push_back(dof);
610  // The global id of the dof is now 0,
611  // but it will be synchronized when calling buildDofsDistributedInfo
612  }
613  }
614  }
615  }
616 }
617 
618 void
620 {
621 
623  for (FEBase* elem: toParse->getOwned())
624  {
625  auto dofs = getDofsOnElement(elem);
626  for (DegreeOfFreedom* dof1 : dofs)
627  for (DegreeOfFreedom* dof2 : dofs)
628  if (dof1 != dof2)
629  {
630 
631  Unknown* u1 = dof1->getUnknown();
632  Unknown* u2 = dof2->getUnknown();
633 
634  // Couple the dofs if they are for the same unknown
635  CepsBool coupled = u1==u2;
636  // Otherwise check in interactions defined in the problem
637  CepsUInt i = 0;
638  auto interactions = m_problem->getUnknownsInteractions();
639  while (not coupled and i<interactions.size())
640  {
641  CepsBool okAttribute = interactions[i]->hasAttribute(CepsUniversal)
642  or interactions[i]->getNumberOfAttributes()==0
643  or elem->getGeomObject()->hasOneOfAttributes(interactions[i]->getAttributes());
644 
645  coupled = okAttribute and
646  ((u1==interactions[i]->u1 and u2==interactions[i]->u2) or
647  (u1==interactions[i]->u2 and u2==interactions[i]->u1));
648  i++;
649  }
650 
651  if (coupled)
652  {
653  dof1->addNeighbor(dof2);
654  dof2->addNeighbor(dof1);
655 
656  // If both dofs belong to another processor, there is a case in 3D where
657  // this other processor does not know the existence of the "edge" between the two dofs
658  // (all cells around this edge can belong to another processor than the owner of the dofs)
659  // We store this relationship, so that can give a safe non-zero stucture for allocation to petsc
660  CepsProcId owner1 = dof1->getOwner();
661  CepsProcId owner2 = dof2->getOwner();
662  if (owner1==owner2 and owner1!=ceps::getRank())
663  {
664  m_extraAdjacencyToSend[owner1][dof1->getGlobalIndex()].insert(dof2->getGlobalIndex());
665  m_extraAdjacencyToSend[owner1][dof2->getGlobalIndex()].insert(dof1->getGlobalIndex());
666  }
667  }
668  }
669  }
670 
671  // Commmunicate the extra adjacency
672  MPI_Status status;
673  MPI_Request request;
674  MPI_Comm comm = ceps::getCommunicator();
675  CepsUInt gridSize = ceps::getGridSize();
676  CepsProcId rank = ceps::getRank();
677 
678  // For now, slow communication matrix, needed barrier at each comm (???)
679  for (CepsProcId sndr=0; sndr<gridSize; sndr++)
680  for (CepsProcId rcvr=0; rcvr<gridSize; rcvr++)
681  if (sndr!=rcvr)
682  {
683 
686  CepsVector<CepsUInt> adjPtr;
687 
688  CepsUInt adjSize = 0u;
689  CepsUInt adjRowsSize = 0u;
690 
691  CepsInt tag = 5*(gridSize*sndr+rcvr);
692 
693  if (rank==sndr)
694  {
695  for (auto& adjm: m_extraAdjacencyToSend[rcvr])
696  adjSize += adjm.second.size();
697  adjRowsSize = m_extraAdjacencyToSend[rcvr].size();
698  MPI_Isend(&adjSize ,1,CEPS_MPI_UINT,rcvr,0+tag,comm,&request);
699  MPI_Isend(&adjRowsSize,1,CEPS_MPI_UINT,rcvr,1+tag,comm,&request);
700  }
701  else if(rank==rcvr)
702  {
703  MPI_Recv(&adjSize ,1,CEPS_MPI_UINT,sndr,0+tag,comm,&status);
704  MPI_Recv(&adjRowsSize,1,CEPS_MPI_UINT,sndr,1+tag,comm,&status);
705  }
706 
707  adj .resize(adjSize );
708  adjPtr .resize(adjRowsSize+1);
709  adjRows.resize(adjRowsSize );
710 
711  if (adjSize!= 0 and rank==sndr)
712  {
713  CepsUInt i = 0;
714  CepsUInt count = 0;
715  for (auto& adjm: m_extraAdjacencyToSend[rcvr])
716  {
717  for (CepsDofGlobalIndex dofId: adjm.second)
718  {
719  adj[count] = dofId;
720  count++;
721  }
722  adjRows[i ] = adjm.first;
723  adjPtr [i+1] = count;
724  i++;
725  }
726  MPI_Isend(adj .data(),adjSize ,CEPS_MPI_GLOBAL_INDEX,rcvr,2+tag,comm,&request);
727  MPI_Isend(adjRows.data(),adjRowsSize ,CEPS_MPI_GLOBAL_INDEX,rcvr,3+tag,comm,&request);
728  MPI_Isend(adjPtr .data(),adjRowsSize+1,CEPS_MPI_UINT ,rcvr,4+tag,comm,&request);
729  }
730  else if (adjSize!=0 and rank==rcvr)
731  {
732  MPI_Recv(adj .data(),adjSize ,CEPS_MPI_GLOBAL_INDEX,sndr,2+tag,comm,&status);
733  MPI_Recv(adjRows.data(),adjRowsSize ,CEPS_MPI_GLOBAL_INDEX,sndr,3+tag,comm,&status);
734  MPI_Recv(adjPtr .data(),adjRowsSize+1,CEPS_MPI_UINT ,sndr,4+tag,comm,&status);
735 
736  for (CepsUInt i=0;i<adjRowsSize;i++)
737  for (CepsUInt ptr=adjPtr[i];ptr<adjPtr[i+1];ptr++)
738  m_extraAdjacencyToRecv[adjRows[i]].insert(adj[ptr]);
739  }
740  ceps::barrier();
741 
742  }
743 
744 }
745 
746 void
748  const CepsUnknownIndex& uId,
749  DVecPtr vec,
750  CepsVector<CepsIndex>& indices,
751  CepsVector<CepsReal>& values,
752  CepsBool sendToMaster,
753  CepsBool returnGeomIndices
754 )
755 {
756 
757  CepsProcId rank = ceps::getRank();
758 
759  // The selection criteria for dofs, based on arguments
760  std::function<CepsBool(DegreeOfFreedom*)> selector = [&] (DegreeOfFreedom* dof) ->CepsBool {
761 
762  GeomNode* node = nullptr;
763  if (returnGeomIndices)
764  node = this->getFENode(dof->getDiscrId())->getGeomObject();
765 
766  // If extraction is for outputs, only give dofs defined on geometry
767  return ((not returnGeomIndices) or node->getGlobalIndex()!=-1)
768  // If we regroup on master, use only owned dofs, not halos
769  and ((not sendToMaster) or dof->getOwner()==rank);
770  };
771 
773  uId,vec,indices,values,sendToMaster,returnGeomIndices,selector
774  );
775  return;
776 }
777 
778 CepsReal
780  const CepsVector<FEBase*>& cells,
781  const CepsSet<CepsAttribute>& attributes,
782  CepsBool onlyOfThisProc
783 )
784 {
785  CEPS_ABORT_IF(attributes.empty(), "missing attributes");
786 
788  selector_t selec;
789  selec.setAttributes(attributes.begin(), attributes.end());
790  selec.onlyOnThisProc(true);
791  selec.selectBetween(cells.begin(), cells.end());
792  return getDomainMeasure(selec.getSelected(), onlyOfThisProc);
793 }
794 
795 CepsReal
796 getDomainMeasure(const CepsVector<FEBase*>& cells, CepsBool onlyOfThisProc)
797 {
798  CepsReal locMeas = 0.0;
799  CepsReal globMeas = 0.0;
800 
801  for (auto cell : cells)
802  locMeas += cell->getGeomObject()->getMeasure();
803 
804  if (onlyOfThisProc)
805  return locMeas;
806 
807  MPI_Allreduce(&locMeas, &globMeas, 1, CEPS_MPI_REAL, MPI_SUM, ceps::getCommunicator());
808  return globMeas;
809 }
CepsBool areSameArray(const CepsArray< _Type, _N > &a, const CepsArray< _Type, _N > &b, const CepsReal error=1.)
Test equality of arrays, suitable for real numbers.
Definition: CepsArray.hpp:51
@ Cell
Data is defined at cell centers.
@ Point
Data is defined on each point.
@ ZeroD
Data is defined once.
CepsCellType
Enum for different shapes of cells.
Definition: CepsEnums.hpp:128
@ Simplex
Simplices.
#define CEPS_SAYS(message)
Writes a message in the debug log and in the terminal (stdio).
#define CEPS_SAYS_NOENDL(message)
Writes a message in the debug log and in the terminal (stdio).
#define CEPS_SAYS_INLINE(message)
Writes a message in the debug log and in the terminal (stdio).
#define CEPS_ABORT_IF(condition, message)
Stops the execution with a message if condition is true. If testing is enabled, only throws a runtime...
#define CEPS_HASH3_PRECISION
CepsIndex CepsUnknownIndex
For unknowns.
Definition: CepsTypes.hpp:217
CepsGlobalIndex CepsCellGlobalIndex
Indices of cells.
Definition: CepsTypes.hpp:222
std::set< _Type, _Compare, _Alloc > CepsSet
C++ set.
Definition: CepsTypes.hpp:209
#define CEPS_MPI_GLOBAL_INDEX
Definition: CepsTypes.hpp:345
std::vector< _Type, _Alloc > CepsVector
C++ vector.
Definition: CepsTypes.hpp:155
bool CepsBool
Booleans.
Definition: CepsTypes.hpp:124
#define CEPS_MPI_REAL
Definition: CepsTypes.hpp:315
CepsGlobalIndex CepsDofGlobalIndex
Indices of degrees of freedom.
Definition: CepsTypes.hpp:226
CepsIndex CepsGlobalIndex
Many uses. Has to be signed for PETSc.
Definition: CepsTypes.hpp:218
std::make_unsigned_t< CepsInt > CepsUInt
Unsigned version on CepsInt.
Definition: CepsTypes.hpp:109
float CepsReal
Need single precision floating point.
Definition: CepsTypes.hpp:100
CepsGlobalIndex CepsNodeGlobalIndex
Indices of nodes.
Definition: CepsTypes.hpp:224
CepsUInt CepsProcId
For CPU indices.
Definition: CepsTypes.hpp:123
CepsArray3< CepsReal > CepsReal3D
Three real scalars, used like this for compatibility in polynomials.
Definition: CepsTypes.hpp:178
int32_t CepsInt
Need 32 bit integer.
Definition: CepsTypes.hpp:106
constexpr CepsAttribute CepsUniversal
This attribute means "everywhere".
Definition: CepsTypes.hpp:232
#define CEPS_MPI_UINT
Definition: CepsTypes.hpp:325
CepsInt CepsIndex
Index rowid etc.
Definition: CepsTypes.hpp:111
std::shared_ptr< DistributedHaloVector > DHVecPtr
Typedef for pointer on Distributed Halo CepsVector.
std::shared_ptr< DistributedMatrix > DMatPtr
Short typedef for pointer on dist matrix.
std::shared_ptr< DistributedVector > DVecPtr
Short typedef for pointer on distributed vector.
std::pair< CepsCellType, CepsUInt > CepsFeLagrangeType
Typedef for descriptor of Lagrange finite elements type.
Definition: FEType.hpp:35
CepsReal getDomainMeasure(const CepsVector< FEBase * > &cells, const CepsSet< CepsAttribute > &attributes, CepsBool onlyOfThisProc)
Compute the measure of a set of a cells.
void setMatrix(DistributedMatrix *mat)
The matrix to assemble.
Abstract Class for all numerical method (FE, FD, FV etc)
void extractValuesForUnknownInternal(const CepsUnknownIndex &uId, DVecPtr vec, CepsVector< CepsIndex > &indices, CepsVector< CepsReal > &values, CepsBool sendToMaster, CepsBool returnGeomIndices, std::function< CepsBool(DegreeOfFreedom *)> &selector)
Slicing method that extracts the data corresponding to a specific unknown.
AbstractPdeProblem * m_problem
[not owned] Pointer on the pde problem
CepsMap< CepsDofGlobalIndex, CepsSet< CepsDofGlobalIndex > > m_extraAdjacencyToRecv
A map to correct the missing adjacency that can occur in rare occasions in 3D.
DVecPtr newDofVector() const
Get a new vector from the factory.
Geometry * m_geometry
[not owned] Pointer on the geometry
DMatPtr newDofMatrix() const
Get a new matrix from the factory.
CepsVector< CepsMap< CepsDofGlobalIndex, CepsSet< CepsDofGlobalIndex > > > m_extraAdjacencyToSend
A map to correct the missing adjacency that can occur in rare occasions in 3D.
DegreeOfFreedomTree m_dofsTree
[owned] Pointer on the distributed degree of freedom tree
virtual void registerSpatialUnkown(Unknown *u)
Changes the location of unknown u to be adapted to the discrectization for example CepsLocationFlag::...
Base class for creating PDEs to solve.
CepsVector< Unknown * > getSpatialUnknowns() const
A vector of all unknowns of pb defined on cells or points.
const CepsVector< UnknownInteraction * > & getUnknownsInteractions() const
All the interactions between unknowns.
const CepsVector< Unknown * > & getUnknowns() const
List of unknowns of the pb.
CepsReal3D & getCoordinates()
Get three coordinates, read & write.
Definition: CepsVertex.cpp:174
A degree of freedom for any kind of problem The dof can be associated to a geometrical element or not...
const CepsGlobalIndex & getGeomId() const
Get the Geom Identity for the dof (-1 means no geometric entity)
Unknown * getUnknown() const
Get the unknow defined at this dof.
const CepsVector< _Type > & getOwned() const
Get data owned by the processor, const.
CepsUInt getNumberOfHalo() const
Number of shared data from other process stored.
LocalGlobalMapping< _Type, _Hash > * getHaloMapping()
Mapping between global and local index of halo data.
void add(const _Type &x, const _Hash &hashValue, const CepsGlobalIndex &globalId, const CepsUInt &pId)
Add entry with global ID to the container, hash must be provided, pId selects owned or halo.
CepsUInt getNumberOfOwned() const
Number of owned data stored.
LocalGlobalMapping< _Type, _Hash > * getOwnedMapping()
Mapping between global and local index of owned data.
_Type & atGlobal(const CepsGlobalIndex &globalId, const CepsUInt &pId)
Access with given global ID.
CepsBool hasGlobal(const CepsGlobalIndex &globalId, const CepsUInt &pId) const
Check if container has data with given global ID.
const CepsVector< _Type > & getHalo() const
Get halo data owned by neighbor processor, const.
void destroyObjects()
Clears the contents, keeps structure.
void assemble(CepsReal t=0., CepsBool finalize=true) override
Main assembly call. Fills the linear system pointed by the class.
Definition: FEAssembler.cpp:40
Abstract class for finite elements.
Definition: FEBase.hpp:65
ReferenceFE * getReferenceElement() const
Pointer on Reference element.
Definition: FEBase.cpp:75
Assembles the stiffness matrix for a given k-simplexes geometry.
void setKForUnknown(Unknown *u, CepsMathScalar k)
Register the diffusion coefficient (x,t,...) for given unknown.
Computes the integral of a quantity on the whole domain or subdomains, using a FE matrix.
CepsReal integrate(DHVecPtr u, DMatPtr mat=nullptr)
Returns the value of the integral by computing ones dot Mu.
Assembles the mass matrix for a given k-simplexes geometry.
A nodal point on a finite element. It is different from a geom node as it may have different properti...
Definition: FENode.hpp:46
FENode * getFENode(CepsGlobalIndex nID)
Link to a single node.
CepsReal dotProduct(DHVecPtr u, DHVecPtr v, CepsBool boundary=false, const CepsSet< CepsAttribute > &attrs={}, const CepsVector< Unknown * > &unknowns={}) final
returns where is the mass matrix
DMatPtr m_mass
Mass matrix, computed at instantiation.
void initializeRefElements()
Configure reference elements.
CepsHash3 getNodeHash(const FENode *n) const
Get the hash value from the coordinates of the node.
CepsVector< FEBase * > & getBoundaryFiniteElements()
Get vector containing all finite elements of the maximum valid dim.
ReferenceFE * getReferenceElementOfDim(CepsCellType type, CepsUInt dim) const
Access to reference elements.
CepsVector< DegreeOfFreedom * > getDofsOnElement(FEBase *elem)
ALl the dofs defined on an element.
CepsUInt getNumberOfOwnedFENodes() const
Local number of nodes belonging to this process, halo nodes NOT included.
void createNewNode(FEBase *el, CepsUInt indexDof, CepsBool isBoundary, Mesh *mesh)
Allocate new node that it is not a geometrical node.
void buildElements()
main routine of FiniteElements called in the constructor
~FiniteElements() override
Destructor.
FiniteElements()=delete
Default Constuctor deleted.
const CepsVector< FENode * > & getHaloFENodes()
vector of halo nodes
CepsVector< FEBase * > & getFiniteElements()
Get vector containing all finite elements of the maximum valid dim.
CepsBool isHaloFENode(CepsGlobalIndex globalID) const
Tells if node is halo by current CPU.
void setSpatialUnknownsDofsInteractions() override
Build dofs neighboring list for spatial unknowns. Different in FE (same element dofs) and VF,...
CepsIndex getDofSpatialId(const DegreeOfFreedom *dof) const override
Return the Geom Node Id for a node (not the FENode index returned by dof->getGeomId())
DistributedInfos< FEBase * > * m_bdrElems
Holds 1D-3D finite boundary elements.
DMatPtr m_stiff
Stiffness matrix, computed at instantiation.
const CepsVector< FENode * > & getOwnedFENodes()
vector of owned nodes
DistributedInfos< FENode *, CepsHash3 > * m_nodes
Holds nodes.
DistributedInfos< FEBase * > * m_volElems
Holds 1D-3D finite elements.
CepsVector< DegreeOfFreedom * > getDofsOnElementForUnknowns(FEBase *elem, const CepsVector< Unknown * > &us)
All dofs defined on an element, considering unknowns us.
void checkNeighborsBeforeAssign(FEBase *fElem, FEBase *nElem, CepsUInt nID, CepsBool boundary, CepsBool &foundSameDof)
Checks if a FE node already exists in a neighbor element.
void extractValuesForUnknown(const CepsUnknownIndex &uId, DVecPtr vec, CepsVector< CepsIndex > &indices, CepsVector< CepsReal > &values, CepsBool sendToMaster=false, CepsBool returnGeomIndices=false) override
Slicing method that extracts the data corresponding to a specific unknown.
CepsReal h1Norm(DHVecPtr v, CepsBool boundary=false, const CepsSet< CepsAttribute > &attrs={}, const CepsVector< Unknown * > &unknowns={}) override
sqrt(stiffproduct(v,v))
CepsReal stiffProduct(DHVecPtr u, DHVecPtr v, CepsBool boundary=false, const CepsSet< CepsAttribute > &attrs={}, const CepsVector< Unknown * > &unknowns={})
returns where is the stiffness matrix
void buildDofsTree() override
Builds the degrees of freedom tree from the PDE data, uses previously build elements and nodes....
CepsMap< CepsCellType, CepsArray4< ReferenceFE * > > m_refElems
Reference elements (point, segment, tri, tetra)
CepsUInt getNumberOfHaloFENodes() const
Global number of owned nodes.
void computeNeighbors()
Compute Neighbors.
CepsUInt m_order
Order used to build elements.
DMatPtr getStiffnessMatrix() const
Pointer on stiffness matrix.
DMatPtr getMassMatrix() const
Pointer on mass matrix.
CepsBool isOwnedFENode(CepsGlobalIndex globalID) const
Tells if node is owned by current CPU.
Abstract class for geometrical cell. On top of index and attributes managament, the cell has informat...
Definition: GeomCell.hpp:48
Base class for nodes used in meshes.
Definition: GeomNode.hpp:53
Mesh * getMeshOfDim(CepsUInt dim) const
Return the mesh of requested dimension.
Definition: Geometry.cpp:139
CepsBool hasMeshOfDim(CepsUInt dim) const
true if geometry has data of requested dimension
Definition: Geometry.cpp:167
A map destined for things that have (or could have) a global index and must be distributed amongst CP...
void append(const _Type &x, const _Hash &hashValue)
Emplace an element in the map.
Geometrical information of 1,2 or 3D distributed cells.
Definition: Mesh.hpp:57
CepsUInt getLocalNbCells() const
Number of non-boundary cells stored on this process.
Definition: Mesh.cpp:246
const CepsVector< GeomCell * > & getCells()
CepsVector of cells stored on this process.
Definition: Mesh.cpp:204
CepsUInt getLocalNbBoundaryCells() const
Number of boundary cells stored on this process.
Definition: Mesh.cpp:252
const CepsVector< GeomCell * > & getBoundaryCells()
CepsVector of boundary cells stored on this process.
Definition: Mesh.cpp:210
Base class for reference finite elements.
Definition: ReferenceFE.hpp:48
CepsReal3D getTransformedBasisVertex(CepsUInt i, GeomCell *cell) const
Get vertex 'i' used to create basis functions and transform it on GeomCell.
CepsInt getBasisVertexGeomCellIndex(CepsUInt i) const
Returns the index in geom cell of a basis vertex. -1 if basis vertex does not match a geom vertex.
CepsUInt getNumberOfBasisVertices() const
Get number of vertices used to create basis functions.
GeomNode * getNodeOfOwnerForBasisVertex(CepsUInt i, GeomCell *cell) const
Returns a node that determines ownership of a basis vertex, especially for those that do not match a ...
A class used to defined an unknown of a PDE problem The unknown can be defined on a specific region,...
Definition: Unknown.hpp:45
const CepsString & getName() const
Get the name of the unknown.
Definition: Unknown.cpp:69
CepsBool isSpatial() const
Tells if unknown is defined on geometrical elements.
Definition: Unknown.cpp:120
void setAttributes(const CepsVector< CepsAttribute > &attributes)
Sets the attributes of the entity.
CepsSet< CepsAttribute > & getAttributes()
Returns the attributes of the entity.
void setOnBoundary(CepsBool value=true)
Sets the entity as being on boundary or not.
void addCell(CellType *&name)
Adds a cell to the list.
_GeomObject * getProperties() const
Get the properties (in fact it's just the geom object)
_GeomObject * getGeomObject() const
Get the geom object.
const CepsGlobalIndex & getGlobalIndex() const
Get the index
CepsVector< NodeType * > & getNodes()
Reference to the node pointers array.
void setNodeAt(const CepsUInt &i, NodeType *neigh)
Set the i-th node. If i>nNodes, nullptrs fill the vector.
CepsVector< NodeType * > getValidNodes() const
Get pointers on all valid nodes.
NodeType * getNodeAt(const CepsUInt &i)
Pointer to the i-th node.
const CepsProcId & getOwner() const
Get owner (processus id) of this entity.
void setOwner(const CepsProcId &pid)
Set shared between several processes ?
constexpr CepsHash get(_Type const &i)
get a hash from a single value
CepsHash3 getHash3(const CepsReal3D &xyz)
Get a triple hash from real coordinates.
void insert(CepsVector< _Type, _Alloc > &vec, const _Type &value)
Conditional insertion of several elements.
Definition: CepsVector.hpp:105
CepsBool contains(const CepsVector< _Type, _Alloc > &vec, const _Type &item)
Tells if vectors contains a given item.
Definition: CepsVector.hpp:56
CepsUInt getRank()
Returns current processor rank.
MPI_Comm getCommunicator()
Get the communicator.
CepsBool isValidPtr(_Type *ptr)
Tells if pointer is not null.
Definition: CepsMemory.hpp:61
CepsInt argVector(const CepsVector< _Type, _Alloc > &vec, const _Type &value)
Get position of element in vector, -1 if not found.
Definition: CepsVector.hpp:200
CepsUInt getGridSize()
Returns the number of process on the computing grid.
CepsBool isNullPtr(_Type *ptr)
Tells if passed pointer is null.
Definition: CepsMemory.hpp:45
void barrier()
Explicit barrier: wait for all processors before continuing.
CepsBool isProfiling()
Check if we are currently profiling on the master proc (always false on slave procs).
Definition: CepsFlags.cpp:257
void destroyObject(_Type &)
Destroy[delete] any type.
Definition: CepsMemory.hpp:116
A triple hash to be used for coordinates (multiplied *10^12 then truncated)