CEPS  24.01
Cardiac ElectroPhysiology Simulator
BoundaryConditionManager.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 
35 
37  CepsObject(),
38  ceps::HoldsDimension(),
39  m_dofs (nullptr),
40  m_rowsAlreadyUsed({}),
41  m_dictionary (dico)
42 {
43  m_dirichlet = ceps::getNew<Manager>();
44  m_neumann = ceps::getNew<Manager>();
45  m_robin = ceps::getNew<Manager>();
46 }
47 
49 {
50  this->reset();
51 }
52 
53 void
55 {
56  m_dofs = dofs;
57  return;
58 }
59 
60 void
62 {
63  auto kr = ceps::splitAtNthDelimiter(params,1);
64  CepsString key = ceps::toKey(kr[0]);
65  CepsString rest = kr[1];
66 
67  CEPS_ABORT_IF(rest.empty(),
68  "When adding boundary condition, no parameters found after key " << key
69  );
70 
71  add(key,rest);
72  return;
73 }
74 
75 void
77 {
78 
79  auto kr = ceps::splitAtNthDelimiter(params,1);
80  CepsString type = ceps::toKey(kr[0]);
81  CepsString rest = kr[1];
82 
83  CEPS_ABORT_IF(rest.empty(),
84  "When adding boundary condition, no parameters found after keyword " << type
85  );
86 
87  if (type == "DIRICHLET")
89  else if (type == "NEUMANN")
91  else if (type == "ROBIN")
93  else
94  {
95  CEPS_ABORT(
96  "When adding boundary condition with key " << key << ", unknown type " << type << "\n" <<
97  " Valid types are DIRICHLET, NEUMANN and ROBIN"
98  );
99  }
100  return;
101 }
102 
103 void
105  const CepsString& key,
106  const CepsBoundaryConditionFlag& type,
107  const CepsString& params
108 )
109 {
110 
111  auto kr = ceps::splitAtNthDelimiter(params,1);
112  CepsString dicoKey = ceps::toKey(kr[0]);
113  CepsString rest = kr[1];
114 
115  CEPS_ABORT_IF(rest.empty(),
116  "When adding boundary condition, no parameters found after dictionary entry " << dicoKey
117  );
118 
119  ScalarSAFunc* func;
120 
121  if (not m_dictionary->hasScalar(dicoKey))
122  {
123  CepsString ndicokey = key+"_CONSTANT";
124  m_dictionary->addConstant(ndicokey,dicoKey);
125  func = ceps::runtimeCast<ScalarSAFunc*>(m_dictionary->getScalar(ndicokey));
126  }
127  else
128  func = ceps::runtimeCast<ScalarSAFunc*>(m_dictionary->getScalar(dicoKey));
129 
130 
131  return add(key,type,rest,func);
132 }
133 
134 void
136  const CepsString& key,
137  const CepsBoundaryConditionFlag& type,
138  const CepsString& params,
139  ScalarSAFunc* functor
140 )
141 {
144  and (not (functor->hasOption(CepsFunctionFlag::Space) or
149  "Function passed for Neumann/Robin BC must be defined either as\n" <<
150  " - a constant function (in space, may be time dependant)\n" <<
151  " - a function of any point x,\n" <<
152  " - a piecewise function using region attributes to determine the value,\n" <<
153  " - a piecewise function using cell ID to determine the value,\n" <<
154  " This function may be evaluated at points of the boundary which do not coincide\n" <<
155  " with degrees of freedom or geometrical nodes"
156  );
157 
158  // Set base BC internal multipliers to activate or deactivate terms in alpha u + beta dnu = g
159  if (not m_dictionary->hasScalar("0.0"))
160  m_dictionary->addConstant("0.0",0.0);
161  if (not m_dictionary->hasScalar("1.0"))
162  m_dictionary->addConstant("1.0",1.0);
163 
164  // -------------------------------------------------- //
165  // Read parameters. currently supported keywords :
166  // - UNKNOWN
167  // - ATTRIBUTE(S)
168  // - SCALE
169  // - VOLUMIC [only for dirichlet...]
170  // - ROBINCOEFF  [for Robin BC...]
171  // -------------------------------------------------- //
172 
173  const CepsString &UNKNOWN = "UNKNOWN";
174  const CepsString &ATTRIBUTE = "ATTRIBUTE";
175  const CepsString &ATTRIBUTES = "ATTRIBUTES";
176  const CepsString &SCALE = "SCALE";
177  const CepsString &VOLUMIC = "VOLUMIC";
178  const CepsString &ROBINCOEFF = "ROBINCOEFF";
179 
180  auto options = ceps::splitByKeyword(params,{UNKNOWN,ATTRIBUTE,ATTRIBUTES,SCALE,VOLUMIC,ROBINCOEFF});
181 
182  // Unknown
183  CepsUnknownIndex unknown = 0u;
184  if (options.contains(UNKNOWN))
185  {
186  CEPS_ABORT_IF(options[UNKNOWN].empty(),
187  "When adding boundary condition, missing unknown identifier after "<< UNKNOWN << " keyword"
188  );
189  unknown = CepsUnknownIndex(ceps::toInt(options[UNKNOWN][0]));
190  }
191 
192  // Attributes
193  CepsSet<CepsUInt> attributes = {};
194 
195  for (auto label : {ATTRIBUTE, ATTRIBUTES})
196  if (options.contains(label))
197  {
198  CEPS_ABORT_IF(options[label].empty(),
199  "When adding boundary condition, could not find any attribute after " << label << " keyword"
200  );
201  for (CepsString s : options[label])
202  attributes.insert(CepsAttribute(ceps::toInt(s)));
203  }
204 
205  if (attributes.empty())
206  attributes.insert(CepsUniversal);
207 
208  // Scaling factor
209  CepsReal scale = 1.;
210  if (options.contains(SCALE))
211  {
212  CEPS_ABORT_IF(options[SCALE].empty() or not ceps::isNumber(options[SCALE][0]),
213  "When adding boundary condition, could not find real number after SCALE keyword"
214  );
215  scale = ceps::toReal(options[SCALE].at(0));
216  }
217 
218  // Robin coefficient beta in dnu + beta u = g (alpha will be 1)
220  if (options.contains(ROBINCOEFF))
221  {
222  CepsString opt = options[ROBINCOEFF][0];
223  CEPS_ABORT_IF(not m_dictionary->hasScalar(opt) and not ceps::isNumber(opt),
224  "When adding boundary condition, unable to find "<< std::quoted(opt) << " in dictionary\n"
225  " or convert it to a real constant"
226  );
227  if (m_dictionary->hasScalar(opt))
228  beta = m_dictionary->getScalar(opt);
229  else
230  {
231  m_dictionary->addConstant("robin_coeff_"+key,ceps::toReal(opt));
232  beta = m_dictionary->getScalar("robin_coeff_"+key);
233  }
234  }
235 
236  // "Volumic" bc for "dirichlet"
237  CepsBool volumic = options.contains(VOLUMIC);
238 
239  // Now create the boundary condition
240  ScalarBoundaryCondition *bc = ceps::getNew<ScalarBoundaryCondition>(functor,&(m_dofs->getOwned()),unknown);
241  bc->setBoundaryConditionType(type);
242  bc->setScaleFactor (scale);
243 
244  // needed during the loop on elements, support contains halo
246  bc->addDomain(&(m_dofs->getHalo()));
247 
248  // Compute support of boundary condition, mandatory for BCs
249  // First, boundary filter
250  if (not volumic)
251  {
254  bc->computeSupport(&selecb);
255  }
256 
257  // Attributes ?
258  if (not attributes.empty())
259  {
261  selec.setAttributes(attributes.begin(),attributes.end());
263  selec.onlyOnBoundary(not volumic);
264  bc->computeSupport(&selec,not volumic);
265  bc->setAttributes(attributes.begin(), attributes.end());
266  }
267 
268  // Filter by unknown
269  std::function<CepsBool(DegreeOfFreedom*)> unknownSelector = [&] (DegreeOfFreedom* d) -> CepsBool {
270  return d->getUnknown()->getIdentifier() == unknown;
271  };
274  selec2.onlyOnBoundary(not volumic);
275  bc->computeSupport(&selec2,not volumic);
276 
277  // Store dofIds that are added, to avoid multiple BCs on a single dof
279  for (DegreeOfFreedom* dof: bc->getSupport())
280  {
281  auto [_,added] = m_rowsAlreadyUsed.insert(dof);
282  CEPS_ABORT_IF(not added,
283  "When adding boundary condition " << key << ", one of the degrees of freedom\n" <<
284  " selected from the given options already has a boundary condition assigned to it"
285  );
286  }
287 
290 
291  switch (type)
292  {
294  bc->setAlpha(Zero);
295  bc->setBeta (One);
296  break;
298  bc->setAlpha(One);
299  bc->setBeta (Zero);
300  break;
302  bc->setAlpha(One);
303  bc->setBeta (beta);
304  }
305 
306  add(key,bc);
307  ceps::barrier();
308  return;
309 }
310 
311 void
313 {
314  CepsString nkey = ceps::toKey(key);
315  Manager *manager = getBCs(bc->getBoundaryConditionType());
316 
317  if (manager->contains(nkey))
318  {
319  CEPS_WARNS("already contains a boundary condition with the key " << nkey << ". Ignoring.");
321  return;
322  }
323 
324  manager->insert(std::make_pair(nkey,bc));
325 
326  CepsString bctype = "not set";
327  switch (bc->getBoundaryConditionType())
328  {
330  bctype = "Dirichlet";
331  break;
333  bctype = "Neumann";
334  break;
336  bctype = "Robin";
337  break;
338  }
339 
340  CEPS_SAYS (" Added new boundary condition : " << key << " (type: " + bctype + ")");
341 
342  return;
343 
344 }
345 
348  CepsString key,
349  const CepsBoundaryConditionFlag &type
350 ) const
351 {
352  return getBCs(type)->at(ceps::toKey(key));
353 }
354 
357 {
359  return m_dirichlet;
360  else if (type == CepsBoundaryConditionFlag::Neumann)
361  return m_neumann;
362  return m_robin;
363 }
364 
367 {
368  return m_dirichlet;
369 }
370 
373 {
374  return m_neumann;
375 }
376 
379 {
380  return m_robin;
381 }
382 
383 void
385 {
386  for (auto toParse : {m_dirichlet,m_neumann,m_robin})
387  {
388  for (auto [name,bc]: *toParse)
390  ceps::destroyObject(toParse);
391  }
392  return;
393 }
394 
395 void
397 {
398  actualizeAllDirichlet(time);
399  actualizeAllNeumann (time);
400  actualizeAllRobin (time);
401 
402  return;
403 }
404 
405 void
407 {
408  for (Manager::value_type obj : *m_dirichlet)
409  obj.second->actualize(time);
410  return;
411 }
412 
413 void
415 {
416  for (Manager::value_type obj : *m_neumann)
417  obj.second->actualize(time);
418 
419  return;
420 }
421 
422 void
424 {
425  for (Manager::value_type obj : *m_robin)
426  obj.second->actualize(time);
427 
428  return;
429 }
430 
431 // std::ostream &
432 // operator<< (std::ostream &os, const BoundaryConditionManager &manager)
433 // {
434 // if (manager.m_dirichlet->size () > 0)
435 // os << "--> Dirichlet " << *manager.m_dirichlet << std::endl;
436 
437 // for (CepsUInt i = 0; i < 3; ++i)
438 // if (manager.m_neumann[i]->size () > 0)
439 // os << "--> Neumann " + std::to_string (i) + "D " << *manager.m_neumann[i] << std::endl;
440 
441 // for (CepsUInt i = 0; i < 3; ++i)
442 // if (manager.m_robin[i]->size () > 0)
443 // os << "--> Robin " + std::to_string (i) + "D " << *manager.m_robin[i] << std::endl;
444 
445 // return os;
446 // }
CepsBoundaryConditionFlag
Enumeration for boundary condition type.
Definition: CepsEnums.hpp:155
@ Dirichlet
Dirichlet BC.
@ CellIndex
Use cell index to determine position.
@ Solution
Depends on the content of a solution vector with values at dofs.
@ None
No dependance, constant functions.
@ Space
Depends on position x.
@ Attribute
Depends on the attribute of the region of evaluation.
#define CEPS_ABORT(message)
Stops the execution with a message. If testing is enabled, only throws a runtime_error.
#define CEPS_SAYS(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_WARNS(message)
Writes a warning in the debug log and in the terminal (stderr).
std::basic_string< CepsChar > CepsString
C++ format string.
Definition: CepsTypes.hpp:128
CepsIndex CepsUnknownIndex
For unknowns.
Definition: CepsTypes.hpp:217
std::set< _Type, _Compare, _Alloc > CepsSet
C++ set.
Definition: CepsTypes.hpp:209
bool CepsBool
Booleans.
Definition: CepsTypes.hpp:124
CepsInt CepsAttribute
Used to define regions.
Definition: CepsTypes.hpp:215
float CepsReal
Need single precision floating point.
Definition: CepsTypes.hpp:100
constexpr CepsAttribute CepsUniversal
This attribute means "everywhere".
Definition: CepsTypes.hpp:232
void onlyOnThisProc(CepsBool value=true)
Choose only object that belongs to this proc.
void onlyOnBoundary(CepsBool value=true)
Choose only objects that are on boundary.
void setDofsInfos(DistributedInfos< DegreeOfFreedom * > *dof)
Set dofs infos in this class.
Manager * m_dirichlet
managers for dirichlet
void actualizeAllRobin(CepsReal time)
Actualize only Robin conditions.
CepsMap< CepsString, ScalarBoundaryCondition * > Manager
Alias for manager inside.
void actualizeAllDirichlet(CepsReal time)
Actualize only Dirichlet conditions.
Manager * getRobinBCs() const
Get the manager for Robin conditions of dim.
Manager * m_neumann
managers for neumann
void add(const CepsString &params)
Add a boundary condition term from parameters.
~BoundaryConditionManager() final
Destroy the Boundary Condition Manager object : default destructor.
Manager * m_robin
managers for robin
Manager * getNeumannBCs() const
Get the manager for Neumann conditions of dim.
void actualizeAll(CepsReal time)
Actualize all bc.
FunctionDictionary * m_dictionary
link to the dictionary
virtual void reset()
Reset the boundary conditions manager.
void actualizeAllNeumann(CepsReal time)
Actualize only Neumann conditions.
CepsSet< DegreeOfFreedom * > m_rowsAlreadyUsed
rows that have a BC
ScalarBoundaryCondition * getBC(CepsString key, const CepsBoundaryConditionFlag &type) const
Get the boundary condition with name 'key' of type 'type' on dimension 'dim'.
DistributedInfos< DegreeOfFreedom * > * m_dofs
dofs
Manager * getBCs(const CepsBoundaryConditionFlag &type) const
Get th correct manager for bc.
Manager * getDirichletBCs() const
Get the manager for Dirichlet conditions.
BoundaryConditionManager(FunctionDictionary *dico)
Construct a new Boundary Condition Manager object dimension.
Boundary condition.
void setBoundaryConditionType(CepsBoundaryConditionFlag type)
Set boundary condition type.
void setAlpha(CoeffFunc alpha)
Set alpha in .
void setBeta(CoeffFunc beta)
Set beta in .
CepsBoundaryConditionFlag getBoundaryConditionType() const
Get boundary condition type.
Base class for other (big) CEPS classes. All classes can get a pointer to this base class and also co...
Definition: CepsObject.hpp:40
A degree of freedom for any kind of problem The dof can be associated to a geometrical element or not...
const CepsVector< _Type > & getOwned() const
Get data owned by the processor, const.
const CepsVector< _Type > & getHalo() const
Get halo data owned by neighbor processor, const.
const CepsVector< _SupportType * > & getSupport()
Get suppor.
void addDomain(const _Domain *domain)
Add another domain of definition.
void setScaleFactor(CepsReal scaleFactor)
Scale the result.
void computeSupport(AbstractSelector< _Iterator > *selector, CepsBool canStartEmpty=false)
Computes the support in the domains of definition, using the given selector.
FunctionDictionary that holds functions which can be used to define source terms, boundary conditions...
void addConstant(const CepsString &label, const CepsString &params)
Add a constant function through parameter string.
CepsBool hasScalar(const CepsString &label) const
Tells if function "label" is registered.
const ScalarEntry getScalar(const CepsString &label) const
Get a single scalar entry, const version.
A SAFunc is a ceps::Function that uses CepsStandardArgs as argument of call operator (),...
Definition: SAFunc.hpp:100
CepsBool hasOption(CepsFunctionFlag flag)
Tells if option is activated.
void setAttributes(const CepsVector< CepsAttribute > &attributes)
Sets the attributes of the entity.
A namespace for all utility methods.
CepsString toKey(const CepsString &s)
Transform to key type a std::string, upper case and no spaces.
Definition: CepsString.cpp:157
CepsMap< CepsString, CepsVector< CepsString > > splitByKeyword(const CepsString &s, const CepsSet< CepsString > &tags)
Extract parameters in the CepsString given by tags. Builds a map of keywords and parameter words acco...
Definition: CepsString.cpp:384
void barrier()
Explicit barrier: wait for all processors before continuing.
CepsVector< CepsString > splitAtNthDelimiter(const CepsString &s, CepsUInt n, CepsString delimiters=CepsString(" \t"))
Split a string a the n-th delimeter. This ignores the doubled delimiter (eg multiple spaces count as ...
Definition: CepsString.cpp:419
CepsInt toInt(const CepsString &s)
Cast CepsString to CepsInt.
Definition: CepsString.cpp:270
CepsBool isNumber(const CepsString &s)
Check if the string contains only digit numbers.
Definition: CepsString.cpp:322
void destroyObject(_Type &)
Destroy[delete] any type.
Definition: CepsMemory.hpp:116
CepsReal toReal(const CepsString &s)
Cast CepsString to CepsReal.
Definition: CepsString.cpp:193