OGS
ProcessVariable.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (c) OpenGeoSys Community (opengeosys.org)
2// SPDX-License-Identifier: BSD-3-Clause
3
4#include "ProcessVariable.h"
5
6#include <algorithm>
7#include <utility>
8
9#include "BaseLib/Algorithm.h"
10#include "BaseLib/Logging.h"
12#include "MeshLib/Mesh.h"
13#include "MeshLib/Node.h"
15#include "ParameterLib/Utils.h"
25
26namespace
27{
28std::vector<std::reference_wrapper<const MeshLib::Mesh>> findMeshInConfig(
29 BaseLib::ConfigTree const& config,
30 std::vector<std::unique_ptr<MeshLib::Mesh>> const& meshes)
31{
32 //
33 // Get the mesh name from the config.
34 //
35 std::vector<std::string>
36 mesh_names; // Either given directly in <mesh> or <meshes> or
37 // constructed from <geometrical_set>_<geometry>.
38
39#ifdef DOXYGEN_DOCU_ONLY
41 config.getConfigParameterOptional<std::string>("mesh");
42#endif // DOXYGEN_DOCU_ONLY
43
44 auto optional_mesh_name =
46 config.getConfigParameterOptional<std::string>("mesh");
47
48 if (optional_mesh_name)
49 {
50 mesh_names.emplace_back(*optional_mesh_name);
51 INFO("Configure mesh '{}' for boundary condition or source term.",
52 mesh_names.back());
53 }
54 else if (
55 auto const geometrical_set_name =
58 config.getConfigParameterOptional<std::string>("geometrical_set"))
59 {
60#ifdef DOXYGEN_DOCU_ONLY
62 config.getConfigParameterOptional<std::string>("geometrical_set");
64 config.getConfigParameter<std::string>("geometry");
65#endif // DOXYGEN_DOCU_ONLY
66
67 auto const geometry_name =
69 config.getConfigParameter<std::string>("geometry");
70
71 mesh_names.emplace_back(MeshGeoToolsLib::meshNameFromGeometry(
72 *geometrical_set_name, geometry_name));
73 }
74 else if (
75 auto const meshes_config =
77 config.getConfigSubtreeOptional("meshes"))
78 {
80 for (auto mesh_config : meshes_config->getConfigParameterList("mesh"))
81 {
82 mesh_names.push_back(mesh_config.getValue<std::string>());
83 INFO("Configure mesh '{:s}' for boundary condition.",
84 mesh_names.back());
85 }
86 }
87
88 //
89 // Find and extract mesh from the list of meshes.
90 //
91 std::vector<std::reference_wrapper<const MeshLib::Mesh>> bc_meshes;
92 for (auto const& mesh_name : mesh_names)
93 {
94 bc_meshes.push_back(MeshLib::findMeshByName(meshes, mesh_name));
95 DBUG("Found mesh '{:s}' with id {:d}.", mesh_name,
96 bc_meshes.back().get().getID());
97 }
98
99 return bc_meshes;
100}
101} // namespace
102
103namespace ProcessLib
104{
106 BaseLib::ConfigTree const& config, MeshLib::Mesh& mesh,
107 std::vector<std::unique_ptr<MeshLib::Mesh>> const& meshes,
108 std::vector<std::unique_ptr<ParameterLib::ParameterBase>> const& parameters,
109 std::map<std::string,
110 std::unique_ptr<MathLib::PiecewiseLinearInterpolation>> const&
111 curves)
112 :
113 _name(config.getConfigParameter<std::string>("name")),
114 _mesh(mesh),
116 _n_components(config.getConfigParameter<int>("components")),
118 _shapefunction_order(config.getConfigParameter<unsigned>("order")),
120 createDeactivatedSubdomains(config, mesh, parameters, curves)),
121 _initial_condition(ParameterLib::findParameter<double>(
123 config.getConfigParameter<std::string>("initial_condition"),
124 parameters, _n_components, &mesh)),
127 config.getConfigParameter<bool>(
128 "compensate_non_equilibrium_initial_residuum", false))
129{
130 DBUG("Constructing process variable {:s}", _name);
131
133 {
134 OGS_FATAL("The given shape function order {:d} is not supported",
136 }
137
138 // Boundary conditions
139 if (auto bcs_config =
141 config.getConfigSubtreeOptional("boundary_conditions"))
142 {
143 for (
144 auto bc_config :
146 bcs_config->getConfigSubtreeList("boundary_condition"))
147 {
148 auto const bc_meshes = findMeshInConfig(bc_config, meshes);
149 auto component_id =
151 bc_config.getConfigParameterOptional<int>("component");
152
153 if (!component_id && _n_components == 1)
154 {
155 // default value for single component vars.
156 component_id = 0;
157 }
158
159 _bc_configs.emplace_back(
160 std::move(bc_config), bc_meshes, component_id,
162 }
163 }
164 else
165 {
166 INFO("No boundary conditions for process variable '{:s}' found.",
167 _name);
168 }
169
170 // Source terms
172 if (auto sts_config = config.getConfigSubtreeOptional("source_terms"))
173 {
174 for (
175 auto st_config :
177 sts_config->getConfigSubtreeList("source_term"))
178 {
179 auto st_meshes = findMeshInConfig(st_config, meshes);
180 auto component_id =
182 st_config.getConfigParameterOptional<int>("component");
183 auto const type =
185 st_config.peekConfigParameter<std::string>("type");
186
187 if (!component_id)
188 {
189 if (_n_components == 1)
190 {
191 // default value for single component vars.
192 component_id = 0;
193 }
194 else if (type == "Anchor")
195 {
196 // dummy value
197 component_id = 0;
198 }
199 else if (type == "EmbeddedAnchor")
200 {
201 // dummy value
202 component_id = 0;
203 }
204 else
205 {
206 OGS_FATAL(
207 "Specifying the component id (<component>) for a "
208 "source term for a non-scalar process variable is "
209 "mandatory.");
210 }
211 }
212
213 _source_term_configs.emplace_back(std::move(st_config),
214 st_meshes.front(), *component_id);
215 }
216 }
217 else
218 {
219 INFO("No source terms for process variable '{:s}' found.", _name);
220 }
221
222 if (!_deactivated_subdomains.empty())
223 {
224 _is_active = getOrCreateMeshProperty<unsigned char>(
225 _mesh, _name + "_active", MeshLib::MeshItemType::Cell, 1);
226 std::fill(std::begin(*_is_active), std::end(*_is_active), 1u);
227 }
228}
229
231
233{
234 return _mesh;
235}
236
237std::vector<std::unique_ptr<BoundaryCondition>>
239 const NumLib::LocalToGlobalIndexMap& dof_table,
240 const int variable_id,
241 unsigned const integration_order,
242 std::vector<std::unique_ptr<ParameterLib::ParameterBase>> const& parameters,
243 Process const& process,
244 std::vector<std::reference_wrapper<ProcessVariable>> const&
245 all_process_variables_for_this_process,
246 std::map<int, std::shared_ptr<MaterialPropertyLib::Medium>> const& media)
247{
248 std::vector<std::unique_ptr<BoundaryCondition>> bcs;
249 bcs.reserve(_bc_configs.size());
250
251 for (auto const& config : _bc_configs)
252 {
253 auto bc_vec = createBoundaryCondition(
254 config, dof_table, _mesh, variable_id, integration_order,
255 _shapefunction_order, parameters, process,
256 all_process_variables_for_this_process, media);
257 for (auto& bc : bc_vec)
258 {
259 // bc can be a nullptr if in parallel execution the bc isn't
260 // associated to the particular subdomain
261 if (bc != nullptr)
262 {
263 bcs.push_back(std::move(bc));
264 }
265 }
266 }
267
269 parameters, bcs);
270
271 // Clear configs to trigger ConfigTree destruction and validation of
272 // unprocessed parameters before the simulation starts.
273 _bc_configs.clear();
274
275 return bcs;
276}
277
279 const NumLib::LocalToGlobalIndexMap& dof_table, const int variable_id,
280 std::vector<std::unique_ptr<ParameterLib::ParameterBase>> const& parameters,
281 std::vector<std::unique_ptr<BoundaryCondition>>& bcs)
282{
283 for (auto const& deactivated_subdomain : _deactivated_subdomains)
284 {
285 auto const& deactivated_subdomain_mesh =
286 deactivated_subdomain.deactivated_subdomain_mesh;
287 auto const* parameter = &ParameterLib::findParameter<double>(
289 bool const set_outer_nodes_dirichlet_values =
290 deactivated_subdomain.boundary_value_parameter != nullptr;
291 if (set_outer_nodes_dirichlet_values)
292 {
293 parameter = deactivated_subdomain.boundary_value_parameter;
294 }
295
296 for (int component_id = 0;
297 component_id <
298 dof_table.getNumberOfVariableComponents(variable_id);
299 component_id++)
300 {
301 auto bc = std::make_unique<DeactivatedSubdomainDirichlet>(
302 *_is_active, deactivated_subdomain.time_interval, *parameter,
303 set_outer_nodes_dirichlet_values, deactivated_subdomain_mesh,
304 dof_table, variable_id, component_id);
305
306#ifdef USE_PETSC
307 // TODO: make it work under PETSc too.
308 if (bc == nullptr)
309 {
310 continue;
311 }
312#endif // USE_PETSC
313 bcs.push_back(std::move(bc));
314 }
315 }
316}
317
319{
320 if (_deactivated_subdomains.empty())
321 {
322 return;
323 }
324
326
327 // If none of the deactivated subdomains is active at current time, then the
328 // _ids_of_active_elements remain empty.
329 if (std::none_of(begin(_deactivated_subdomains),
330 end(_deactivated_subdomains), [&](auto const& ds)
331 { return ds.isInTimeSupportInterval(time); }))
332 {
333 // Also mark all of the elements as active.
334 assert(_is_active != nullptr); // guaranteed by constructor
335 std::fill(std::begin(*_is_active), std::end(*_is_active), 1u);
336
337 return;
338 }
339
340 auto is_active_in_subdomain = [&](std::size_t const element_id,
341 DeactivatedSubdomain const& ds) -> bool
342 {
343 return (!ds.isInTimeSupportInterval(time)) ||
344 !ds.isDeactivated(*_mesh.getElement(element_id), time);
345 };
346
347 auto is_active_in_all_subdomains = [&](std::size_t const element_id) -> bool
348 {
349 return std::all_of(begin(_deactivated_subdomains),
351 [&](auto const& ds)
352 { return is_active_in_subdomain(element_id, ds); });
353 };
354
355 auto const number_of_elements = _mesh.getNumberOfElements();
356 for (std::size_t element_id = 0; element_id < number_of_elements;
357 element_id++)
358 {
359 if (is_active_in_all_subdomains(element_id))
360 {
361 _ids_of_active_elements.push_back(element_id);
362 }
363 }
364
365 // all elements are deactivated
366 std::fill(std::begin(*_is_active), std::end(*_is_active), 0u);
367
368 for (auto const id : _ids_of_active_elements)
369 {
370 (*_is_active)[id] = 1u;
371 }
372}
373
374std::vector<std::unique_ptr<SourceTermBase>> ProcessVariable::createSourceTerms(
375 const NumLib::LocalToGlobalIndexMap& dof_table, const int variable_id,
376 unsigned const integration_order,
377 std::vector<std::unique_ptr<ParameterLib::ParameterBase>> const& parameters,
378 std::vector<std::reference_wrapper<ProcessVariable>> const&
379 all_process_variables_for_this_process,
380 const MeshLib::Mesh& bulk_mesh)
381{
382 std::vector<std::unique_ptr<SourceTermBase>> source_terms;
383
384 transform(cbegin(_source_term_configs), cend(_source_term_configs),
385 back_inserter(source_terms),
386 [&](auto const& config)
387 {
388 return createSourceTerm(
389 config, dof_table, config.mesh, variable_id,
390 integration_order, _shapefunction_order, parameters,
391 all_process_variables_for_this_process, bulk_mesh);
392 });
393
394 // Clear configs to trigger ConfigTree destruction and validation of
395 // unprocessed parameters before the simulation starts.
396 _source_term_configs.clear();
397
398 return source_terms;
399}
400
402
403} // namespace ProcessLib
#define OGS_FATAL(...)
Definition Error.h:19
void INFO(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:28
void DBUG(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:22
std::optional< ConfigTree > getConfigSubtreeOptional(std::string const &root) const
std::optional< T > getConfigParameterOptional(std::string const &param) const
T getConfigParameter(std::string const &param) const
int getNumberOfVariableComponents(int variable_id) const
void updateDeactivatedSubdomains(double const time)
std::vector< std::unique_ptr< SourceTermBase > > createSourceTerms(const NumLib::LocalToGlobalIndexMap &dof_table, const int variable_id, unsigned const integration_order, std::vector< std::unique_ptr< ParameterLib::ParameterBase > > const &parameters, std::vector< std::reference_wrapper< ProcessVariable > > const &all_process_variables_for_this_process, const MeshLib::Mesh &bulk_mesh)
ParameterLib::Parameter< double > const & _initial_condition
std::vector< BoundaryConditionConfig > _bc_configs
ProcessVariable(BaseLib::ConfigTree const &config, MeshLib::Mesh &mesh, std::vector< std::unique_ptr< MeshLib::Mesh > > const &meshes, std::vector< std::unique_ptr< ParameterLib::ParameterBase > > const &parameters, std::map< std::string, std::unique_ptr< MathLib::PiecewiseLinearInterpolation > > const &curves)
MeshLib::Mesh const & getMesh() const
Returns a mesh on which the process variable is defined.
std::vector< DeactivatedSubdomain > _deactivated_subdomains
const bool _compensate_non_equilibrium_initial_residuum
MeshLib::PropertyVector< unsigned char > * _is_active
std::vector< std::size_t > _ids_of_active_elements
std::vector< SourceTermConfig > _source_term_configs
std::vector< std::unique_ptr< BoundaryCondition > > createBoundaryConditions(const NumLib::LocalToGlobalIndexMap &dof_table, const int variable_id, unsigned const integration_order, std::vector< std::unique_ptr< ParameterLib::ParameterBase > > const &parameters, Process const &process, std::vector< std::reference_wrapper< ProcessVariable > > const &all_process_variables_for_this_process, std::map< int, std::shared_ptr< MaterialPropertyLib::Medium > > const &media)
void createBoundaryConditionsForDeactivatedSubDomains(const NumLib::LocalToGlobalIndexMap &dof_table, const int variable_id, std::vector< std::unique_ptr< ParameterLib::ParameterBase > > const &parameters, std::vector< std::unique_ptr< BoundaryCondition > > &bcs)
std::string meshNameFromGeometry(std::string const &geometrical_set_name, std::string const &geometry_name)
Mesh & findMeshByName(std::vector< std::unique_ptr< Mesh > > const &meshes, std::string_view const name)
Definition Mesh.cpp:354
OGS_NO_DANGLING Parameter< ParameterDataType > & findParameter(std::string const &parameter_name, std::vector< std::unique_ptr< ParameterBase > > const &parameters, int const num_components, MeshLib::Mesh const *const mesh=nullptr)
std::vector< DeactivatedSubdomain > createDeactivatedSubdomains(BaseLib::ConfigTree const &config, MeshLib::Mesh const &mesh, std::vector< std::unique_ptr< ParameterLib::ParameterBase > > const &parameters, std::map< std::string, std::unique_ptr< MathLib::PiecewiseLinearInterpolation > > const &curves)
std::unique_ptr< SourceTermBase > createSourceTerm(const SourceTermConfig &config, const NumLib::LocalToGlobalIndexMap &dof_table_bulk, const MeshLib::Mesh &source_term_mesh, const int variable_id, const unsigned integration_order, const unsigned shapefunction_order, std::vector< std::unique_ptr< ParameterLib::ParameterBase > > const &parameters, std::vector< std::reference_wrapper< ProcessVariable > > const &all_process_variables_for_this_process, const MeshLib::Mesh &bulk_mesh)
std::vector< std::unique_ptr< BoundaryCondition > > createBoundaryCondition(const BoundaryConditionConfig &config, const NumLib::LocalToGlobalIndexMap &dof_table, const MeshLib::Mesh &bulk_mesh, const int variable_id, const unsigned integration_order, const unsigned shapefunction_order, const std::vector< std::unique_ptr< ParameterLib::ParameterBase > > &parameters, const Process &process, std::vector< std::reference_wrapper< ProcessVariable > > const &all_process_variables_for_this_process, std::map< int, std::shared_ptr< MaterialPropertyLib::Medium > > const &media)
std::vector< std::reference_wrapper< const MeshLib::Mesh > > findMeshInConfig(BaseLib::ConfigTree const &config, std::vector< std::unique_ptr< MeshLib::Mesh > > const &meshes)
static PROCESSLIB_EXPORT const std::string zero_parameter_name