CEPS  24.01
Cardiac ElectroPhysiology Simulator
FEAssembler.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 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
31 
33 {
34  for (auto it: m_tools)
35  for (auto tool: it.second)
36  ceps::destroyObject(tool);
37 }
38 
39 void
41 {
42 
43  // Spatial assembly
44  init();
45 
46  // ceps::beginSequential();
47  while (not finished())
48  {
50  next();
51  }
52  // ceps::endSequential();
53 
54  // ZeroD unknowns,
55  // They are added if they were specified in the list at instanciation, or no unknowns specified,
56  // if the assembler is not restricted to boundary, and if the assembler has not attribute or the
57  // CepsUniversal attribute
58  // Also, their contribution is not added in "integral" computation
59  if (not m_boundaryOnly)
60  if (this->hasAttribute(CepsUniversal) or this->getNumberOfAttributes()==0)
62  if (m_unknownsWL.empty() or ceps::argVector(m_unknownsWL,u)!=-1)
63  {
65  if (zddof->getOwner()==ceps::getRank())
66  assembleForZeroDDof(zddof, t);
67  }
68 
69  if (finalize)
70  {
71  if (isAssemblingMatrix())
72  m_gMat->finalize();
73  if (isAssemblingVector())
74  m_gVec->finalize();
75  }
76 
77  return;
78 }
79 
82  m_fe (nullptr),
83  m_boundaryOnly (false),
84  m_toParse (nullptr),
85  m_tools ({}),
86  m_bMat ({}),
87  m_bVec ({}),
88  m_dofsBlockMapping({})
89 {
90 }
91 
93  CepsBool isBoundary,
94  const CepsSet<CepsAttribute>& attributes,
95  const CepsVector<Unknown*>& unknowns
96  ):
97  AbstractAssembler(fe,attributes,unknowns),
98  m_fe (fe),
99  m_boundaryOnly (isBoundary),
100  m_toParse (nullptr),
101  m_tools ({}),
102  m_bMat ({}),
103  m_bVec ({}),
104  m_dofsBlockMapping({})
105 {
106 
107  if (isBoundary)
108  m_toParse = &(fe->getBoundaryFiniteElements());
109  else
110  m_toParse = &(fe->getFiniteElements());
111  CEPS_WARNS_IF(m_toParse->empty(),
112  "An assembler has no elements to parse. This can occur when the mesh has no boundary elements"
113  );
114 
115  // Set the iterators on elements to the first to parse
116  init();
117 
118  prepareQuadratures();
119 
120 }
121 
122 void
124 {
125 
126  // No quads for now
127  //for (auto cellType : {CepsCellType::Simplex,CepsCellType::Quad})
129  for (CepsUInt dim = 0U; dim <= 3U; dim++)
130  {
131  m_tools[cellType][dim] = new IntegrationTools;
132  IntegrationTools* tool = m_tools[cellType][dim];
133 
134  tool->ref = m_fe->getReferenceElementOfDim(cellType,dim);
135 
137 
138  const CepsUInt &n = tool->quadrature.getNbQuadPoints();
139  tool->phi .reserve(n);
140  tool->gradPhi.reserve(n);
141 
142  for (CepsUInt i=0U; i<n; ++i)
143  {
144  const CepsMathVertex &xQ = tool->quadrature.getQuadPoint(i);
145  const CepsReal3D &x = {xQ(0U),xQ(1U),xQ(2U)};
146 
147  tool->phi .push_back(tool->ref->computeBasisFunctions (x));
148  tool->gradPhi.push_back(tool->ref->computeBasisFunctionDerivatives(x));
149  }
150 
151  }
152  return;
153 }
154 
155 void
157 {
158  if (m_toParse->empty())
159  return;
160 
161  // The first element may not have the correct attributes
162  CepsBool isUniversal = this->hasAttribute(CepsUniversal);
163  m_elem = m_toParse->begin();
164  if (not (isUniversal or hasOneOfAttributes((*m_elem)->getGeomObject()->getAttributes())))
165  next();
166 
167 }
168 
169 CepsBool
171 {
172  return m_toParse->empty() or m_elem == m_toParse->end();
173 }
174 
175 void
177 {
178  CepsBool isUniversal = this->hasAttribute(CepsUniversal);
179  CepsBool stop = false;
180  do
181  {
182  ++m_elem;
183  stop = finished() or isUniversal
184  or hasOneOfAttributes((*m_elem)->getGeomObject()->getAttributes());
185  }
186  while (not stop);
187 
188 }
189 
190 void
192 {
193 
194  // Fetch some information
195  GeomCell* gCell = (*m_elem)->getGeomObject();
196  CepsUInt dim = gCell->getDimension();
197  auto J = gCell->getJacobianMatrix();
198  auto invJt = gCell->getInverseJacobianMatrix().transpose();
199  auto det = gCell->getJacobianDeterminant();
200 
201  // Select the right quadrature
202  IntegrationTools* itg = m_tools.at((*m_elem)->getReferenceElement()->getCellType()).at(dim);
203 
204  // Loop on quadrature points
205  m_newBlocksNeeded = true;
206 
207  CepsUInt nQ = itg->quadrature.getNbQuadPoints();
208  for (CepsUInt iQ = 0U; iQ < nQ; iQ++)
209  {
210  // Use only the necessary dimensions of the quadrature point in reference element
211  auto xQ = itg->quadrature.getQuadPoint(iQ).topLeftCorner(dim,1);
212  CepsReal wQ = itg->quadrature.getWeight(iQ);
213 
214  // transform grad_phi using inverse jacobian
215  // We use the part of grad phi which concerns the dimension of the element
216  // grad_phi = (J^-1)^T * grad_phi
217  auto gradPhi = invJt*itg->gradPhi[iQ].topLeftCorner(dim,(*m_elem)->getNumberOfNodes());
218  auto phi = itg->phi[iQ];
219 
220  // compute weight (quadrature*jacobian) and point
221  CepsReal weight = det*wQ;
222  CepsMathVertex p = J*xQ + (*m_elem)->getOrigin();
223  CepsReal3D x({p[0],p[1],p[2]});
224  computeBlocksOnElementAtQuadPoint(*m_elem,x,t,phi,gradPhi);
225  sumBlockContribution(weight);
226  }
228 
229  return;
230 }
231 
234 {
235  CepsVector<Unknown*> res = {};
236  for (Unknown* u: us)
237  {
238  if (not ceps::contains(m_unknownsWL, u) and not m_unknownsWL.empty())
239  continue;
240  if (not (
241  u->hasUniversalAttribute() or
242  u->hasOneOfAttributes(elem->getProperties()->getAttributes())
243  ))
244  continue;
245 
246  res.push_back(u);
247  }
248  return res;
249 }
250 
251 void
253 {
255  return;
256 }
257 
258 void
260  FEBase* elem,
261  const CepsVector<Unknown*>& us
262 )
263 {
264  // If we don't need to allocate the blocks
265  // just zero them
266  if (not m_newBlocksNeeded)
267  {
268  for (CepsUInt i = 0UL; i < m_bMat.size(); ++i)
269  for (CepsUInt j = 0UL; j < m_bMat[i].size(); ++j)
270  m_bMat[i][j].setZero();
271 
272  for (CepsUInt i = 0UL; i < m_bVec.size(); ++i)
273  m_bVec[i].setZero();
274 
275  return;
276  }
277 
278  CepsUInt nu = us.size();
279  CepsUInt nn = elem->getNumberOfNodes();
280  auto attrs = elem->getGeomObject()->getAttributes();
281 
283  // allDofs was built with external loop on FE Nodes, so by taking only one per node,
284  // dofs should be sorted in the same order as FE Nodes, ie the order of basis vertices.
285  // \sa FiniteElements::getDofsOnElement \sa FiniteElements::buildElements
286 
287  m_dofsBlockMapping.clear();
288  m_dofsBlockMapping.resize(nu);
289  m_dofsBlock .clear();
290  m_dofsBlock .resize(nu);
291 
292  for (CepsUInt i=0; i<nu; i++)
293  {
294  m_dofsBlockMapping[i].clear();
295  m_dofsBlockMapping[i].reserve(nn);
296  m_dofsBlock [i].clear();
297  m_dofsBlock [i].reserve(nn);
298  for (DegreeOfFreedom* dof:allDofs)
299  if (dof->getUnknown()==us[i])
300  {
301  m_dofsBlock [i].push_back(dof);
302  m_dofsBlockMapping[i].push_back(dof->getGlobalIndex());
303  }
304  }
305 
306  // Prepare the submatrices
307  m_bMat.clear();
308  m_bMat.resize(nu);
309  m_bMatSumQuads.clear();
310  m_bMatSumQuads.resize(nu);
311 
312  m_addMatBlock.clear();
313  m_addMatBlock.resize(nu);
314 
315  // Prepare the subvectors
316  m_bVec.clear();
317  m_bVec.resize(nu);
318  m_bVecSumQuads.clear();
319  m_bVecSumQuads.resize(nu);
320 
321  m_addVecBlock.clear();
322  m_addVecBlock.resize(nu);
323 
324  CepsUInt N, M;
325 
326  for (CepsUInt i = 0UL; i < nu; i++)
327  {
328  m_bMat[i].resize(nu);
329  m_bMatSumQuads[i].resize(nu);
330  m_addMatBlock[i].resize(nu);
331 
332  for (CepsUInt j = 0UL; j < nu; j++)
333  {
334  N = m_dofsBlockMapping[i].size();
335  M = m_dofsBlockMapping[j].size();
336 
337  m_bMat[i][j].setZero(N, M);
338  m_bMatSumQuads[i][j].setZero(N, M);
339 
340  m_addMatBlock[i][j] = m_fe->getProblem()->unknownsInteract(us[i],us[j],attrs)
341  and (N != 0) and (M != 0);
342  }
343 
344  m_bVec[i].setZero(N);
345  m_bVecSumQuads[i].setZero(N);
346  m_addVecBlock[i] = true;
347  }
348 
349  m_newBlocksNeeded = false;
350 }
351 
352 void
355  const CepsMathDynamic2D&)
356 {}
357 
358 void
360 {
361  for (CepsUInt i = 0UL; i < m_bMatSumQuads.size(); i++)
362  for (CepsUInt j = 0UL; j < m_bMatSumQuads[i].size(); j++)
363  m_bMatSumQuads[i][j] += weight * m_bMat[i][j];
364 
365  for (CepsUInt i = 0UL; i < m_bVecSumQuads.size(); i++)
366  m_bVecSumQuads[i] += weight * m_bVec[i];
367 }
368 
369 void
371 {
372  if (isAssemblingMatrix())
374 }
375 
376 void
378  const CepsVector<CepsReal>& values,
379  DegreeOfFreedom* a,
381  CepsReal factor
382 )
383 {
384  if (not isAssemblingMatrix())
385  return;
386 
387  CEPS_ABORT_IF(values.size() != b.size(), "incompatible size");
388  const CepsUInt& n = b.size();
389  for (CepsUInt i = 0UL; i < n; ++i)
390  addZeroDMatBlockContribution(factor * values[i], a, b[i]);
391 
392  return;
393 }
394 
395 void
397 {
398  if (isAssemblingVector())
399  m_gVec->addValue(m_scaleFactor * value, dof->getGlobalIndex());
400 }
401 
402 void
404 {
407 }
408 
409 void
411 {
412  if (not isAssemblingMatrix())
413  return;
414 
415  for (CepsUInt i = 0UL; i < m_bMatSumQuads.size(); i++)
416  for (CepsUInt j = 0UL; j < m_bMatSumQuads[i].size(); j++)
417  if (m_addMatBlock[i][j]) // Add only if there is an interaction
420 }
421 
422 void
424 {
425  if (not isAssemblingVector())
426  return;
427 
428  for (CepsUInt i = 0UL; i < m_bVecSumQuads.size(); i++)
429  if (m_addVecBlock[i])
431  m_dofsBlockMapping[i]);
432 }
433 
434 
CepsCellType
Enum for different shapes of cells.
Definition: CepsEnums.hpp:128
@ Simplex
Simplices.
#define CEPS_WARNS_IF(condition, message)
If condition is true, writes a warning in the debug log and in the terminal (stderr).
#define CEPS_ABORT_IF(condition, message)
Stops the execution with a message if condition is true. If testing is enabled, only throws a runtime...
Eigen::Matrix< CepsScalar, Eigen::Dynamic, 1 > CepsMathDynamic1D
Dynamic 1D array, eigen format.
Definition: CepsTypes.hpp:139
std::set< _Type, _Compare, _Alloc > CepsSet
C++ set.
Definition: CepsTypes.hpp:209
std::vector< _Type, _Alloc > CepsVector
C++ vector.
Definition: CepsTypes.hpp:155
bool CepsBool
Booleans.
Definition: CepsTypes.hpp:124
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
Eigen::Matrix< CepsScalar, 3, 1 > CepsMathVertex
Vertex, eigen format.
Definition: CepsTypes.hpp:135
CepsArray3< CepsReal > CepsReal3D
Three real scalars, used like this for compatibility in polynomials.
Definition: CepsTypes.hpp:178
constexpr CepsAttribute CepsUniversal
This attribute means "everywhere".
Definition: CepsTypes.hpp:232
Eigen::Matrix< CepsScalar, Eigen::Dynamic, Eigen::Dynamic > CepsMathDynamic2D
Dynamic 2D array, eigen format.
Definition: CepsTypes.hpp:140
Common elements for linear system assembly.
CepsBool isAssemblingMatrix() const
True if ptr to matrix has been set.
AbstractPdeProblem * m_problem
Direct link to problem, you may write getXXXProblem methods in derived classes that return the right ...
CepsVector< Unknown * > m_unknownsWL
White list of unknowns.
DistributedMatrix * m_gMat
Global matrix.
CepsBool isAssemblingVector() const
True if ptr to vector has been set.
virtual void assembleForZeroDDof(DegreeOfFreedom *dof, CepsReal t=0.)
Assembly routine for zeroD dofs. Does nothing by default, redefine in derived classes.
CepsReal m_scaleFactor
Scale factor.
DistributedVector * m_gVec
Global Vector.
const CepsMap< CepsUnknownIndex, CepsVector< DegreeOfFreedom * > > & getDegreesOfFreedomForUnknown()
Dofs sorted by unknown.
AbstractPdeProblem * getProblem() const
Return link to pde problem.
CepsBool unknownsInteract(Unknown *u1, Unknown *u2, const CepsSet< CepsAttribute > &attrs={CepsUniversal}) const
Tells if unknowns interact on an entity with attributes.
CepsVector< Unknown * > getZeroDUnknowns() const
A vector of all zeroD unknowns of the pb.
A degree of freedom for any kind of problem The dof can be associated to a geometrical element or not...
void addValue(CepsMathScalar value, CepsGlobalIndex i, CepsGlobalIndex j)
Adds value to A(i,j) (sets if not existing already)
void addSubMatrix(const CepsMathDynamic2D &subMat, const CepsVector< CepsGlobalIndex > &indicesI, const CepsVector< CepsGlobalIndex > &indicesJ)
Add each element of a small square matrix in a distributed matrix.
void finalize()
Performs assembly.
void finalize()
Calls both beginAssembly() and endAssembly()
void addSubVector(const CepsMathDynamic1D &subVector, const CepsVector< CepsGlobalIndex > &rowIndices)
Adds a vector in a distributed vector.
void addValue(CepsMathScalar value, CepsGlobalIndex i)
Adds given scalar to the currently existing value or set it if not.
FEAssembler()
default constructor used for virtual inheritance
Definition: FEAssembler.cpp:80
CepsVector< CepsVector< CepsMathDynamic2D > > m_bMatSumQuads
Block submatrices. The first two vectors account for unknowns: if assembly on element if for unknowns...
void prepareQuadratures()
Precompute phi and grad phi at quadrature points.
virtual void addZeroDVecBlockContribution(CepsReal value, DegreeOfFreedom *dof)
Add a 0D contribution into the vector.
CepsVector< CepsMathDynamic1D > m_bVec
Block vector,.
void assembleForCurrentElement(CepsReal t)
Computes the submatrix and subvector for the currently selected element and add its contribution to t...
virtual void setupBlocksOnElementForUnknowns(FEBase *elem, const CepsVector< Unknown * > &unknowns)
Get all the dofs on an element related to the given unknowns. This routine MUST be called before addB...
CepsBool m_boundaryOnly
Flag for localization of what to assemble.
void sumBlockContribution(CepsReal weight)
Adds w*m_bMat to m_bMatTemp, same for vectors. The weight should be jacobian*quad weight for which co...
void addZeroDMatBlockContributions(const CepsVector< CepsReal > &values, DegreeOfFreedom *a, const CepsVector< DegreeOfFreedom * > &b, CepsReal factor=1.0)
Add 0D contributions into the matrix.
void init()
Set the element iterator to the right place.
virtual void addVectorBlockContribution()
Add the content of the block vectors in the the global vector.
CepsVector< CepsBool > m_addVecBlock
Prevents additions of blocks for interactions between unknowns that have not been set.
void next()
Move to next element, selected by attribute.
void assemble(CepsReal t=0., CepsBool finalize=true) override
Main assembly call. Fills the linear system pointed by the class.
Definition: FEAssembler.cpp:40
CepsVector< Unknown * > extractUnknownsFrom(const CepsVector< Unknown * > &us, FEBase *elem) const
From a vector of unknowns, get the ones defined on that element.
void setupBlocksOnElementForUnknown(FEBase *elem, Unknown *unknown)
Get all the dofs on an element related to the given unknowns. This routine MUST be called before sumB...
void addBlockContribution()
Add the content of the block matrices in the global matrix, and the content of the block vectors in t...
CepsVector< CepsMathDynamic1D > m_bVecSumQuads
Block vector,.
~FEAssembler() override
Destructor.
Definition: FEAssembler.cpp:32
CepsVector< CepsVector< CepsMathDynamic2D > > m_bMat
Block submatrices. The first two vectors account for unknowns: if assembly on element if for unknowns...
virtual void addMatrixBlockContribution()
Add the content of the block matrices in the global matrix.
FiniteElements * m_fe
Pointer to finite elements structure.
CepsVector< CepsVector< DegreeOfFreedom * > > m_dofsBlock
Degrees of freedom corresponding to elementary matrix rows.
CepsVector< FEBase * > * m_toParse
The vector of elements to parse;.
virtual void addZeroDMatBlockContribution(CepsReal value, DegreeOfFreedom *a, DegreeOfFreedom *b)
Add a 0D contribution into the matrix.
virtual void computeBlocksOnElementAtQuadPoint(FEBase *element, CepsReal3D xQ, CepsReal t, const CepsMathDynamic1D &phi, const CepsMathDynamic2D &gradPhi)
The function that is called to get the coefficients of the submatrix on a given finite element....
CepsVector< FEBase * >::iterator m_elem
Iterator on elements. It will loop through elements for dim3, dim2 then dim1 of m_fe.
CepsMap< CepsCellType, CepsArray4< IntegrationTools * > > m_tools
Integration tools.
CepsBool finished()
Tells if end of loop is reached.
CepsVector< CepsVector< CepsBool > > m_addMatBlock
Prevents additions of blocks for interactions between unknowns that have not been set.
CepsVector< CepsVector< CepsDofGlobalIndex > > m_dofsBlockMapping
Mapping between lines of submatrix m_bMat m_bVec and global matrix indices.
CepsBool m_newBlocksNeeded
Flag to ensure that the blocks are resized only once.
Abstract class for finite elements.
Definition: FEBase.hpp:65
Holds all finite elements corresponding to each geometrical element.
ReferenceFE * getReferenceElementOfDim(CepsCellType type, CepsUInt dim) const
Access to reference elements.
CepsVector< DegreeOfFreedom * > getDofsOnElementForUnknowns(FEBase *elem, const CepsVector< Unknown * > &us)
All dofs defined on an element, considering unknowns us.
const CepsMathVertex & getQuadPoint(CepsUInt i) const
Coordinates of quadrature point of index i.
void initializeQuadrature(CepsUInt order, CepsUInt dim)
Sets coords and weights for quadrature of given order in element of dimension dim.
CepsUInt getNbQuadPoints() const
Number of quadrature points.
CepsReal getWeight(CepsUInt i) const
Weight of quadrature point of index i.
Abstract class for geometrical cell. On top of index and attributes managament, the cell has informat...
Definition: GeomCell.hpp:48
CepsReal getJacobianDeterminant() const
Jacobian of geometrical deformation from reference cell.
Definition: GeomCell.cpp:95
virtual const JacobianMatrixType & getJacobianMatrix()
Jacobian Matrix of deformation from reference cell (3 rows for R^3, element dimension columns)
Definition: GeomCell.cpp:101
virtual const InverseJacobianMatrixType & getInverseJacobianMatrix()
Jacobian Matrix of deformation from reference cell (3 rows for R^3, element dimension columns)
Definition: GeomCell.cpp:111
CepsUInt getPolynomialOrder() const
Order.
Definition: ReferenceFE.cpp:54
CepsMathDynamic1D computeBasisFunctions(const CepsReal3D &point)
Get values of basis functions at given point.
Definition: ReferenceFE.cpp:66
CepsMathDynamic2D computeBasisFunctionDerivatives(const CepsReal3D &point)
Get values of basis function derivatives at given point.
Definition: ReferenceFE.cpp:77
A class used to defined an unknown of a PDE problem The unknown can be defined on a specific region,...
Definition: Unknown.hpp:45
CepsBool hasOneOfAttributes(const CepsSet< CepsAttribute > &attributes) const
Tells if the entity has one of the attributes in argument.
CepsBool hasAttribute(const CepsAttribute &name) const
Tells if the entity has the attribute in argument.
CepsSet< CepsAttribute > & getAttributes()
Returns the attributes of the entity.
CepsUInt getNumberOfAttributes() const
Returns number of attributes of the entity.
const CepsUInt & getDimension() const
Get the dimension of the object.
_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
CepsUInt getNumberOfNodes() const
Returns the total number of nodes.
const CepsProcId & getOwner() const
Get owner (processus id) of this entity.
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.
CepsInt argVector(const CepsVector< _Type, _Alloc > &vec, const _Type &value)
Get position of element in vector, -1 if not found.
Definition: CepsVector.hpp:200
void finalize()
Finalizes parallel environment.
void destroyObject(_Type &)
Destroy[delete] any type.
Definition: CepsMemory.hpp:116
Integration tools which contains quadrature rule, and values of the basis functions and basis functio...
CepsVector< CepsMathDynamic2D > gradPhi
Derivatives of basis functions evaluated.
ReferenceFE * ref
Reference element.
CepsVector< CepsMathDynamic1D > phi
Basis functions evaluated at quad points.
GaussianQuadrature quadrature
Quadrature rule.