OGS
LIE/SmallDeformation/SmallDeformationProcess.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
5
11#include "MeshLib/Mesh.h"
12#include "MeshLib/Properties.h"
17
18namespace ProcessLib
19{
20namespace LIE
21{
22namespace SmallDeformation
23{
24template <int DisplacementDim>
26 std::string name,
27 MeshLib::Mesh& mesh,
28 std::unique_ptr<ProcessLib::AbstractJacobianAssembler>&& jacobian_assembler,
29 std::vector<std::unique_ptr<ParameterLib::ParameterBase>> const& parameters,
30 unsigned const integration_order,
31 std::vector<std::vector<std::reference_wrapper<ProcessVariable>>>&&
32 process_variables,
34 SecondaryVariableCollection&& secondary_variables)
35 : Process(std::move(name), mesh, std::move(jacobian_assembler), parameters,
36 integration_order, std::move(process_variables),
37 std::move(secondary_variables)),
38 _process_data(std::move(process_data))
39{
40 // For numerical Jacobian assembler
41 if (this->_jacobian_assembler->isPerturbationEnabled())
42 {
43 OGS_FATAL(
44 "The numericial Jacobian assembler is not supported for the "
45 "LIE SmallDeformationProcess.");
46 }
47
48 INFO("[LIE/M] looking for fracture elements in the given mesh");
49 std::vector<std::pair<std::size_t, std::vector<int>>>
50 vec_branch_nodeID_matIDs;
51 std::vector<std::pair<std::size_t, std::vector<int>>>
52 vec_junction_nodeID_matIDs;
56 _vec_fracture_nodes, vec_branch_nodeID_matIDs,
57 vec_junction_nodeID_matIDs);
58
59 if (_vec_fracture_mat_IDs.size() !=
60 _process_data.fracture_properties.size())
61 {
63 "The number of the given fracture properties ({:d}) are not "
64 "consistent with the number of fracture groups in a mesh "
65 "({:d}).",
66 _process_data.fracture_properties.size(),
68 }
69
70 // create a map from a material ID to a fracture ID
71 auto max_frac_mat_id = std::max_element(_vec_fracture_mat_IDs.begin(),
73 _process_data.map_materialID_to_fractureID.resize(*max_frac_mat_id + 1);
74 for (unsigned i = 0; i < _vec_fracture_mat_IDs.size(); i++)
75 {
76 _process_data.map_materialID_to_fractureID[_vec_fracture_mat_IDs[i]] =
77 i;
78 }
79
80 // create a table of connected fracture IDs for each element
81 _process_data.vec_ele_connected_fractureIDs.resize(
82 mesh.getNumberOfElements());
83 for (unsigned i = 0; i < _vec_fracture_matrix_elements.size(); i++)
84 {
85 for (auto e : _vec_fracture_matrix_elements[i])
86 {
87 _process_data.vec_ele_connected_fractureIDs[e->getID()].push_back(
88 i);
89 }
90 }
91
92 // set fracture property
93 for (auto& fracture_prop : _process_data.fracture_properties)
94 {
95 // based on the 1st element assuming a fracture forms a straight
96 // line
98 DisplacementDim,
99 *_vec_fracture_elements[fracture_prop.fracture_id][0],
100 fracture_prop);
101 }
102
103 // set branches
104 for (auto const& [vec_branch_nodeID, matID] : vec_branch_nodeID_matIDs)
105 {
106 auto const master_matId = matID[0];
107 auto const slave_matId = matID[1];
108 auto& master_frac =
109 _process_data.fracture_properties
110 [_process_data.map_materialID_to_fractureID[master_matId]];
111 auto& slave_frac =
112 _process_data.fracture_properties
113 [_process_data.map_materialID_to_fractureID[slave_matId]];
114
115 master_frac.branches_master.push_back(createBranchProperty(
116 *mesh.getNode(vec_branch_nodeID), master_frac, slave_frac));
117
118 slave_frac.branches_slave.push_back(createBranchProperty(
119 *mesh.getNode(vec_branch_nodeID), master_frac, slave_frac));
120 }
121
122 // set junctions
123 transform(cbegin(vec_junction_nodeID_matIDs),
124 cend(vec_junction_nodeID_matIDs),
125 back_inserter(_vec_junction_nodes),
126 [&](auto& vec_junction_nodeID_matID)
127 {
128 return const_cast<MeshLib::Node*>(
129 _mesh.getNode(vec_junction_nodeID_matID.first));
130 });
131
132 for (std::size_t i = 0; i < vec_junction_nodeID_matIDs.size(); i++)
133 {
134 auto const& material_ids = vec_junction_nodeID_matIDs[i].second;
135 assert(material_ids.size() == 2);
136 std::array<int, 2> fracture_ids{
137 {_process_data.map_materialID_to_fractureID[material_ids[0]],
138 _process_data.map_materialID_to_fractureID[material_ids[1]]}};
139
140 _process_data.junction_properties.emplace_back(
141 i, *mesh.getNode(vec_junction_nodeID_matIDs[i].first),
142 fracture_ids);
143 }
144
145 // create a table of connected junction IDs for each element
146 _process_data.vec_ele_connected_junctionIDs.resize(
147 mesh.getNumberOfElements());
148 for (unsigned i = 0; i < vec_junction_nodeID_matIDs.size(); i++)
149 {
150 auto node = mesh.getNode(vec_junction_nodeID_matIDs[i].first);
151 for (auto id :
153 {
154 _process_data.vec_ele_connected_junctionIDs[id].push_back(i);
155 }
156 }
157
158 // create a table of junction node and connected elements
160 vec_junction_nodeID_matIDs.size());
161 for (unsigned i = 0; i < vec_junction_nodeID_matIDs.size(); i++)
162 {
163 auto node = mesh.getNode(vec_junction_nodeID_matIDs[i].first);
164 for (auto e : mesh.getElementsConnectedToNode(*node))
165 {
167 const_cast<MeshLib::Element*>(e));
168 }
169 }
170
171 //
172 // If Neumann BCs for the displacement_jump variable are required they
173 // need special treatment because of the levelset function. The
174 // implementation exists in the version 6.1.0
175 // (e54815cc07ee89c81f953a4955b1c788595dd725) and was removed due to
176 // lack of applications.
177 //
178
179 MeshLib::PropertyVector<int> const* material_ids(
180 mesh.getProperties().getPropertyVector<int>("MaterialIDs"));
181 _process_data.mesh_prop_materialIDs = material_ids;
182}
183
184template <int DisplacementDim>
186{
187 //------------------------------------------------------------
188 // prepare mesh subsets to define DoFs
189 //------------------------------------------------------------
190 // for extrapolation
192 std::make_unique<MeshLib::MeshSubset>(_mesh, _mesh.getNodes());
193 // regular u
195 std::make_unique<MeshLib::MeshSubset>(_mesh, _mesh.getNodes());
196 // u jump
197 for (auto const& nodes : _vec_fracture_nodes)
198 {
200 std::make_unique<MeshLib::MeshSubset const>(_mesh, nodes));
201 }
202 // enrichment for junctions
204 std::make_unique<MeshLib::MeshSubset>(_mesh, _vec_junction_nodes);
205
206 // Collect the mesh subsets in a vector.
207 std::vector<MeshLib::MeshSubset> all_mesh_subsets;
208 std::generate_n(std::back_inserter(all_mesh_subsets), DisplacementDim,
209 [&]() { return *_mesh_subset_matrix_nodes; });
210 for (auto const& ms : _mesh_subset_fracture_nodes)
211 {
212 std::generate_n(std::back_inserter(all_mesh_subsets),
213 DisplacementDim,
214 [&]() { return *ms; });
215 }
216 std::generate_n(std::back_inserter(all_mesh_subsets),
217 DisplacementDim,
218 [&]() { return *_mesh_subset_junction_nodes; });
219
220 std::vector<int> const vec_n_components(
221 1 + _vec_fracture_mat_IDs.size() + _vec_junction_nodes.size(),
222 DisplacementDim);
223
224 std::vector<std::vector<MeshLib::Element*> const*> vec_var_elements;
225 vec_var_elements.push_back(&_vec_matrix_elements);
226 for (auto const& element : _vec_fracture_matrix_elements)
227 {
228 vec_var_elements.push_back(&element);
229 }
230 for (auto const& element : _vec_junction_fracture_matrix_elements)
231 {
232 vec_var_elements.push_back(&element);
233 }
234
235 INFO("[LIE/M] creating a DoF table");
237 std::make_unique<NumLib::LocalToGlobalIndexMap>(
238 std::move(all_mesh_subsets),
239 vec_n_components,
240 vec_var_elements,
242
243 DBUG("[LIE/M] created {:d} DoF", _local_to_global_index_map->size());
244}
245
246template <int DisplacementDim>
248 MeshLib::Element const& e, MeshLib::Mesh& mesh)
249{
250 Eigen::Vector3d const pt(getCenterOfGravity(e).asEigenVector3d());
251 std::vector<FractureProperty*> e_fracture_props;
252 std::unordered_map<int, int> e_fracID_to_local;
253 unsigned tmpi = 0;
254 for (auto fid : _process_data.vec_ele_connected_fractureIDs[e.getID()])
255 {
256 e_fracture_props.push_back(&_process_data.fracture_properties[fid]);
257 e_fracID_to_local.insert({fid, tmpi++});
258 }
259 std::vector<JunctionProperty*> e_junction_props;
260 std::unordered_map<int, int> e_juncID_to_local;
261 tmpi = 0;
262 for (auto fid : _process_data.vec_ele_connected_junctionIDs[e.getID()])
263 {
264 e_junction_props.push_back(&_process_data.junction_properties[fid]);
265 e_juncID_to_local.insert({fid, tmpi++});
266 }
267 std::vector<double> const levelsets(uGlobalEnrichments(
268 e_fracture_props, e_junction_props, e_fracID_to_local, pt));
269
270 auto update_levelset_property = [&](unsigned const i, int const id,
271 unsigned const levelset_idx_offset,
272 unsigned const name_offset)
273 {
274 auto levelset_property = MeshLib::getOrCreateMeshProperty<double>(
275 const_cast<MeshLib::Mesh&>(mesh),
276 "levelset" + std::to_string(id + 1 + name_offset),
278 levelset_property->resize(mesh.getNumberOfElements());
279 (*levelset_property)[e.getID()] = levelsets[i + levelset_idx_offset];
280 };
281
282 for (unsigned i = 0; i < e_fracture_props.size(); i++)
283 {
284 update_levelset_property(i, e_fracture_props[i]->fracture_id, 0, 0);
285 }
286 for (unsigned i = 0; i < e_junction_props.size(); i++)
287 {
288 update_levelset_property(i, e_junction_props[i]->junction_id,
289 e_fracture_props.size(),
290 _process_data.fracture_properties.size());
291 }
292}
293
294template <int DisplacementDim>
296 NumLib::LocalToGlobalIndexMap const& dof_table,
297 MeshLib::Mesh const& mesh,
298 unsigned const integration_order)
299{
304 mesh.getElements(), dof_table, _local_assemblers,
305 NumLib::IntegrationOrder{integration_order}, mesh.isAxiallySymmetric(),
307
308 // TODO move the two data members somewhere else.
309 // for extrapolation of secondary variables
310 std::vector<MeshLib::MeshSubset> all_mesh_subsets_single_component{
313 std::make_unique<NumLib::LocalToGlobalIndexMap>(
314 std::move(all_mesh_subsets_single_component),
315 // by location order is needed for output
317
318 auto add_secondary_variable = [&](std::string const& name,
319 int const num_components,
320 auto get_ip_values_function)
321 {
322 _secondary_variables.addSecondaryVariable(
323 name,
324 makeExtrapolator(num_components, getExtrapolator(),
326 std::move(get_ip_values_function)));
327 };
328
329 add_secondary_variable("sigma",
331 DisplacementDim>::RowsAtCompileTime,
333
334 add_secondary_variable("epsilon",
336 DisplacementDim>::RowsAtCompileTime,
338
339 add_secondary_variable("fracture_stress", DisplacementDim,
341
342 add_secondary_variable("fracture_aperture", 1,
344
346 const_cast<MeshLib::Mesh&>(mesh), "sigma_avg",
349 DisplacementDim>::RowsAtCompileTime);
350
351 for (MeshLib::Element const* e : _mesh.getElements())
352 {
353 if (e->getDimension() < DisplacementDim)
354 {
355 continue;
356 }
357
358 updateElementLevelSets(*e, const_cast<MeshLib::Mesh&>(mesh));
359 }
360
361 _process_data.element_local_jumps =
363 const_cast<MeshLib::Mesh&>(mesh), "local_jump_w_avg",
364 MeshLib::MeshItemType::Cell, DisplacementDim);
365
366 _process_data.element_fracture_stresses =
368 const_cast<MeshLib::Mesh&>(mesh), "fracture_stress_avg",
369 MeshLib::MeshItemType::Cell, DisplacementDim);
370
372 const_cast<MeshLib::Mesh&>(mesh), "fracture_aperture_avg",
374
375 mesh_prop_b->resize(mesh.getNumberOfElements());
376 auto const& mesh_prop_matid = *_process_data.mesh_prop_materialIDs;
377 for (auto const& fracture_prop : _process_data.fracture_properties)
378 {
379 for (MeshLib::Element const* e : _mesh.getElements())
380 {
381 if (e->getDimension() == DisplacementDim)
382 {
383 continue;
384 }
385 if (mesh_prop_matid[e->getID()] != fracture_prop.mat_id)
386 {
387 continue;
388 }
389 // Mean value for the element. This allows usage of node based
390 // properties for aperture.
391 (*mesh_prop_b)[e->getID()] =
392 fracture_prop.aperture0
393 .getNodalValuesOnElement(*e, /*time independent*/ 0)
394 .mean();
395 }
396 }
397 _process_data.mesh_prop_b = mesh_prop_b;
398}
399
400template <int DisplacementDim>
402 double const t, double const dt, std::vector<GlobalVector*> const& x,
403 GlobalVector const& x_prev, int const process_id)
404{
405 DBUG("Compute the secondary variables for SmallDeformationProcess.");
406 std::vector<NumLib::LocalToGlobalIndexMap const*> dof_tables;
407 dof_tables.reserve(x.size());
408 std::generate_n(std::back_inserter(dof_tables), x.size(),
409 [&]() { return _local_to_global_index_map.get(); });
410
413 _local_assemblers, getActiveElementIDs(), dof_tables, t, dt, x, x_prev,
414 process_id);
415}
416
417template <int DisplacementDim>
419{
420 return false;
421}
422
423template <int DisplacementDim>
425 const double t, double const dt, std::vector<GlobalVector*> const& x,
426 std::vector<GlobalVector*> const& x_prev, int const process_id,
428{
429 DBUG("Assemble SmallDeformationProcess.");
430
431 std::vector<NumLib::LocalToGlobalIndexMap const*> dof_table = {
433 // Call global assembler for each local assembly item.
436 getActiveElementIDs(), dof_table, t, dt, x, x_prev, process_id, &M, &K,
437 &b);
438}
439
440template <int DisplacementDim>
443 const double t, double const dt, std::vector<GlobalVector*> const& x,
444 std::vector<GlobalVector*> const& x_prev, int const process_id,
445 GlobalVector& b, GlobalMatrix& Jac)
446{
447 DBUG("AssembleWithJacobian SmallDeformationProcess.");
448
449 // Call global assembler for each local assembly item.
450 std::vector<NumLib::LocalToGlobalIndexMap const*> dof_table = {
454 _local_assemblers, getActiveElementIDs(), dof_table, t, dt, x, x_prev,
455 process_id, &b, &Jac);
456}
457
458template <int DisplacementDim>
460 std::vector<GlobalVector*> const& x, double const t, double const dt,
461 const int process_id)
462{
463 DBUG("PreTimestep SmallDeformationProcess.");
464
468 *x[process_id], t, dt);
469}
470
471// ------------------------------------------------------------------------------------
472// template instantiation
473// ------------------------------------------------------------------------------------
474template class SmallDeformationProcess<2>;
475template class SmallDeformationProcess<3>;
476
477} // namespace SmallDeformation
478} // namespace LIE
479} // namespace ProcessLib
#define OGS_FATAL(...)
Definition Error.h:19
MathLib::EigenMatrix GlobalMatrix
MathLib::EigenVector GlobalVector
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::size_t getID() const
Returns the ID of the element.
Definition Element.h:80
bool isAxiallySymmetric() const
Definition Mesh.h:130
std::vector< Element * > const & getElements() const
Get the element-vector for the mesh.
Definition Mesh.h:101
const Node * getNode(std::size_t idx) const
Get the node with the given index.
Definition Mesh.h:83
Properties & getProperties()
Definition Mesh.h:127
std::vector< Element const * > const & getElementsConnectedToNode(std::size_t node_id) const
Definition Mesh.cpp:246
std::size_t getNumberOfElements() const
Get the number of elements.
Definition Mesh.h:89
PropertyVector< T > const * getPropertyVector(std::string_view name) const
virtual std::vector< double > const & getIntPtEpsilon(const double t, std::vector< GlobalVector * > const &x, std::vector< NumLib::LocalToGlobalIndexMap const * > const &dof_table, std::vector< double > &cache) const =0
virtual std::vector< double > const & getIntPtFractureAperture(const double t, std::vector< GlobalVector * > const &x, std::vector< NumLib::LocalToGlobalIndexMap const * > const &dof_table, std::vector< double > &cache) const =0
virtual std::vector< double > const & getIntPtSigma(const double t, std::vector< GlobalVector * > const &x, std::vector< NumLib::LocalToGlobalIndexMap const * > const &dof_table, std::vector< double > &cache) const =0
virtual std::vector< double > const & getIntPtFractureStress(const double t, std::vector< GlobalVector * > const &x, std::vector< NumLib::LocalToGlobalIndexMap const * > const &dof_table, std::vector< double > &cache) const =0
void initializeConcreteProcess(NumLib::LocalToGlobalIndexMap const &dof_table, MeshLib::Mesh const &mesh, unsigned const integration_order) override
Process specific initialization called by initialize().
std::vector< std::vector< MeshLib::Element * > > _vec_junction_fracture_matrix_elements
void computeSecondaryVariableConcrete(double const t, double const dt, std::vector< GlobalVector * > const &x, GlobalVector const &x_prev, int const process_id) override
std::unique_ptr< NumLib::LocalToGlobalIndexMap > _local_to_global_index_map_single_component
std::vector< std::unique_ptr< MeshLib::MeshSubset const > > _mesh_subset_fracture_nodes
void preTimestepConcreteProcess(std::vector< GlobalVector * > const &x, double const t, double const dt, const int process_id) override
void assembleWithJacobianConcreteProcess(const double t, double const dt, std::vector< GlobalVector * > const &x, std::vector< GlobalVector * > const &x_prev, int const process_id, GlobalVector &b, GlobalMatrix &Jac) override
SmallDeformationProcess(std::string name, MeshLib::Mesh &mesh, std::unique_ptr< ProcessLib::AbstractJacobianAssembler > &&jacobian_assembler, std::vector< std::unique_ptr< ParameterLib::ParameterBase > > const &parameters, unsigned const integration_order, std::vector< std::vector< std::reference_wrapper< ProcessVariable > > > &&process_variables, SmallDeformationProcessData< DisplacementDim > &&process_data, SecondaryVariableCollection &&secondary_variables)
void assembleConcreteProcess(const double t, double const dt, std::vector< GlobalVector * > const &x, std::vector< GlobalVector * > const &x_prev, int const process_id, GlobalMatrix &M, GlobalMatrix &K, GlobalVector &b) override
std::vector< std::unique_ptr< LocalAssemblerInterface > > _local_assemblers
virtual void computeSecondaryVariable(std::size_t const mesh_item_id, std::vector< NumLib::LocalToGlobalIndexMap const * > const &dof_tables, double const t, double const dt, std::vector< GlobalVector * > const &x, GlobalVector const &x_prev, int const process_id)
virtual void preTimestep(std::size_t const mesh_item_id, NumLib::LocalToGlobalIndexMap const &dof_table, GlobalVector const &x, double const t, double const delta_t)
std::string const name
Definition Process.h:361
Process(std::string name_, MeshLib::Mesh &mesh, std::unique_ptr< AbstractJacobianAssembler > &&jacobian_assembler, std::vector< std::unique_ptr< ParameterLib::ParameterBase > > const &parameters, unsigned const integration_order, std::vector< std::vector< std::reference_wrapper< ProcessVariable > > > &&process_variables, SecondaryVariableCollection &&secondary_variables, const bool use_monolithic_scheme=true)
Definition Process.cpp:37
std::unique_ptr< MeshLib::MeshSubset const > _mesh_subset_all_nodes
Definition Process.h:365
MeshLib::Mesh & _mesh
Definition Process.h:364
std::vector< std::size_t > const & getActiveElementIDs() const
Definition Process.h:160
SecondaryVariableCollection _secondary_variables
Definition Process.h:369
VectorMatrixAssembler _global_assembler
Definition Process.h:376
std::unique_ptr< NumLib::LocalToGlobalIndexMap > _local_to_global_index_map
Definition Process.h:367
std::unique_ptr< ProcessLib::AbstractJacobianAssembler > _jacobian_assembler
Definition Process.h:375
NumLib::Extrapolator & getExtrapolator() const
Definition Process.h:201
Handles configuration of several secondary variables from the project file.
void assemble(std::size_t const mesh_item_id, LocalAssemblerInterface &local_assembler, std::vector< NumLib::LocalToGlobalIndexMap const * > const &dof_tables, double const t, double const dt, std::vector< GlobalVector * > const &x, std::vector< GlobalVector * > const &x_prev, int const process_id, GlobalMatrix *M, GlobalMatrix *K, GlobalVector *b)
void assembleWithJacobian(std::size_t const mesh_item_id, LocalAssemblerInterface &local_assembler, std::vector< NumLib::LocalToGlobalIndexMap const * > const &dof_tables, const double t, double const dt, std::vector< GlobalVector * > const &x, std::vector< GlobalVector * > const &x_prev, int const process_id, GlobalVector *b, GlobalMatrix *Jac)
Eigen::Matrix< double, kelvin_vector_dimensions(DisplacementDim), 1, Eigen::ColMajor > KelvinVectorType
constexpr ranges::views::view_closure ids
For an element of a range view return its id.
Definition Mesh.h:218
PropertyVector< T > * getOrCreateMeshProperty(Mesh &mesh, std::string const &property_name, MeshItemType const item_type, int const number_of_components)
@ BY_LOCATION
Ordering data by spatial location.
@ BY_COMPONENT
Ordering data by component type.
void createLocalAssemblers(std::vector< MeshLib::Element * > const &mesh_elements, NumLib::LocalToGlobalIndexMap const &dof_table, std::vector< std::unique_ptr< LocalAssemblerInterface > > &local_assemblers, NumLib::IntegrationOrder const integration_order, ExtraCtorArgs &&... extra_ctor_args)
void setFractureProperty(int const dim, MeshLib::Element const &e, FractureProperty &frac_prop)
void getFractureMatrixDataInMesh(MeshLib::Mesh const &mesh, std::vector< MeshLib::Element * > &vec_matrix_elements, std::vector< int > &vec_fracture_mat_IDs, std::vector< std::vector< MeshLib::Element * > > &vec_fracture_elements, std::vector< std::vector< MeshLib::Element * > > &vec_fracture_matrix_elements, std::vector< std::vector< MeshLib::Node * > > &vec_fracture_nodes, std::vector< std::pair< std::size_t, std::vector< int > > > &vec_branch_nodeID_matIDs, std::vector< std::pair< std::size_t, std::vector< int > > > &vec_junction_nodeID_matIDs)
std::vector< double > uGlobalEnrichments(std::vector< FractureProperty * > const &frac_props, std::vector< JunctionProperty * > const &junction_props, std::unordered_map< int, int > const &fracID_to_local, Eigen::Vector3d const &x)
BranchProperty createBranchProperty(MeshLib::Node const &branchNode, FractureProperty const &master_frac, FractureProperty const &slave_frac)
SecondaryVariableFunctions makeExtrapolator(const unsigned num_components, NumLib::Extrapolator &extrapolator, LocalAssemblerCollection const &local_assemblers, typename NumLib::ExtrapolatableLocalAssemblerCollection< LocalAssemblerCollection >::IntegrationPointValuesMethod integration_point_values_method)
static void executeSelectedMemberOnDereferenced(Method method, Container const &container, std::vector< std::size_t > const &active_container_ids, Args &&... args)
static void executeSelectedMemberDereferenced(Object &object, Method method, Container const &container, std::vector< std::size_t > const &active_container_ids, Args &&... args)