https://mooseframework.inl.gov
Loading...
Searching...
No Matches
ElementGroupCentroidPositions.C
Go to the documentation of this file.
1//* This file is part of the MOOSE framework
2//* https://mooseframework.inl.gov
3//*
4//* All rights reserved, see COPYRIGHT for full restrictions
5//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6//*
7//* Licensed under LGPL 2.1, please see LICENSE for details
8//* https://www.gnu.org/licenses/lgpl-2.1.html
9
11
12#include "libmesh/parallel_algebra.h"
13
15
18{
21 params.addClassDescription("Gets the Positions of the centroid of groups of elements. "
22 "Groups may be defined using subdomains or element extra ids.");
23
24 // To enable extra element ID groups
25 params.addParam<MooseEnum>("grouping_type", groupTypeEnum(), "Type of group of elements");
26 params.addParam<std::vector<ExtraElementIDName>>("extra_id_name",
27 "Name(s) of the extra element ID(s) to use");
28 params.addParam<std::vector<std::vector<dof_id_type>>>(
29 "extra_id",
30 "Specific ID(s), for each extra id name, for grouping elements. "
31 "If empty, all *valid* ids will be used to bin");
32
33 // Order already arises from the block/ID bins
34 params.set<bool>("auto_sort") = false;
35 // Full replicated mesh is used on every rank to generate positions
36 params.set<bool>("auto_broadcast") = false;
37
38 return params;
39}
40
42 : Positions(parameters),
44 _mesh(_subproblem.mesh()),
45 _group_type(getParam<MooseEnum>("grouping_type"))
46{
47 // We are not excluding using both block restriction and extra element ids
48 if (_group_type == "extra_id" || _group_type == "block_and_extra_id")
49 {
50 _extra_id_names = getParam<std::vector<ExtraElementIDName>>("extra_id_name");
51 for (const auto & name : _extra_id_names)
52 _extra_id_indices.push_back(_mesh.getMesh().get_elem_integer_index(name));
53
54 if (isParamValid("extra_id"))
55 _extra_id_group_indices = getParam<std::vector<std::vector<dof_id_type>>>("extra_id");
56 else
58
59 if (_extra_id_group_indices.size() != _extra_id_names.size())
60 paramError("extra_id",
61 "Number of extra id names and the indices to select must match. "
62 "If you want all indices for an extra id, use an empty vector entry");
63
64 // Can only have so many groups though, considering 4D max capability
65 if (_extra_id_indices.size() > unsigned(3 + blockRestricted()))
66 mooseError("Positions currently supports only up to 4D storage");
67 }
68 else
69 {
70 if (isParamValid("extra_id_name"))
71 paramError("extra_id_name",
72 "An extra id name was specified but elements are not grouped by extra ids");
73 if (isParamValid("extra_ids"))
74 paramError("extra_ids",
75 "An extra id was specified but elements are not grouped by extra ids");
76 }
77
78 // Insert subdomain as an extra element id to simplify computation logic
79 if (blockRestricted() || !isParamValid("extra_id_name"))
80 {
81 _blocks_in_use = true;
82 _extra_id_names.insert(_extra_id_names.begin(), "block");
83 _extra_id_indices.insert(_extra_id_indices.begin(), std::numeric_limits<unsigned short>::max());
84 _extra_id_group_indices.insert(_extra_id_group_indices.begin(), std::vector<dof_id_type>());
85 // Add real block restriction
86 if (blockRestricted())
87 for (const auto & block : blockIDs())
88 _extra_id_group_indices[0].push_back(block);
89 // Just add all blocks
90 else
91 for (const auto & block : meshBlockIDs())
92 _extra_id_group_indices[0].push_back(block);
93 }
94 else
95 _blocks_in_use = false;
96
97 // Mesh is ready at construction
98 initialize();
99 // Sort the output (by XYZ) if requested
100 finalize();
101}
102
103void
105{
107 // By default, initialize should be called on meshChanged()
108
109 // If users did not specify a value for an extra element integer, they want all the bins
110 // We'll need to loop through the mesh to find the element extra ids
111 for (const auto i : index_range(_extra_id_group_indices))
112 {
113 auto & indices = _extra_id_group_indices[i];
114 if (indices.empty())
115 {
116 std::set<dof_id_type> ids;
117 for (const auto & elem : _mesh.getMesh().active_local_element_ptr_range())
118 {
119 auto eeid = id(*elem, _extra_id_indices[i], _blocks_in_use && i == 0);
120 if (eeid != DofObject::invalid_id)
121 ids.insert(eeid);
122 }
123 _mesh.comm().set_union(ids);
124 for (const auto & id : ids)
125 indices.push_back(id);
126 }
127 }
128
129 // Allocate some vectors holding the volumes
130 std::vector<Real> volumes;
131 std::vector<std::vector<Real>> volumes_2d;
132 std::vector<std::vector<std::vector<Real>>> volumes_3d;
133 std::vector<std::vector<std::vector<std::vector<Real>>>> volumes_4d;
134
135 // Default indexing: blocks, extra_id_name_1, extra_id_name_2 ...
136 // Allocate vectors holding the positions
137 if (_extra_id_names.size() == 1)
138 {
139 _positions.resize(_extra_id_group_indices[0].size());
140 volumes.resize(_positions.size());
141 }
142 else if (_extra_id_names.size() == 2)
143 {
144 _positions_2d.resize(_extra_id_group_indices[0].size());
145 volumes_2d.resize(_positions_2d.size());
146 for (auto & pos_group : _positions_2d)
147 pos_group.resize(_extra_id_group_indices[1].size());
148 for (auto & vol_group : volumes_2d)
149 vol_group.resize(_extra_id_group_indices[1].size());
150 }
151 else if (_extra_id_names.size() == 3)
152 {
153 _positions_3d.resize(_extra_id_group_indices[0].size());
154 volumes_3d.resize(_positions_3d.size());
155 for (auto & vec_pos_group : _positions_3d)
156 {
157 vec_pos_group.resize(_extra_id_group_indices[1].size());
158 for (auto & pos_group : vec_pos_group)
159 pos_group.resize(_extra_id_group_indices[2].size());
160 }
161 for (auto & vec_vol_group : volumes_3d)
162 {
163 vec_vol_group.resize(_extra_id_group_indices[1].size());
164 for (auto & vol_group : vec_vol_group)
165 vol_group.resize(_extra_id_group_indices[2].size());
166 }
167 }
168 else if (_extra_id_names.size() == 4)
169 {
170 _positions_4d.resize(_extra_id_group_indices[0].size());
171 volumes_4d.resize(_positions_4d.size());
172 for (auto & vec_vec_pos_group : _positions_4d)
173 {
174 vec_vec_pos_group.resize(_extra_id_group_indices[1].size());
175 for (auto & vec_pos_group : vec_vec_pos_group)
176 {
177 vec_pos_group.resize(_extra_id_group_indices[2].size());
178 for (auto & pos_group : vec_pos_group)
179 pos_group.resize(_extra_id_group_indices[3].size());
180 }
181 }
182 for (auto & vec_vec_vol_group : volumes_4d)
183 {
184 vec_vec_vol_group.resize(_extra_id_group_indices[1].size());
185 for (auto & vec_vol_group : vec_vec_vol_group)
186 {
187 vec_vol_group.resize(_extra_id_group_indices[2].size());
188 for (auto & vol_group : vec_vol_group)
189 vol_group.resize(_extra_id_group_indices[3].size());
190 }
191 }
192 }
193 else
194 mooseError("Too much dimensionality for positions");
195
196 // To simplify retrieving the final positions vector
197 auto getNestedPositions =
198 [this](const std::vector<unsigned int> & indices) -> std::vector<Point> &
199 {
200 mooseAssert(indices[_extra_id_names.size() - 1] == 0, "Indexing issue");
201 if (_extra_id_names.size() == 1)
202 return _positions;
203 else if (_extra_id_names.size() == 2)
204 return _positions_2d[indices[0]];
205 else if (_extra_id_names.size() == 3)
206 return _positions_3d[indices[0]][indices[1]];
207 else
208 return _positions_4d[indices[0]][indices[1]][indices[2]];
209 };
210 auto getNestedVolumes = [this, &volumes, &volumes_2d, &volumes_3d, &volumes_4d](
211 const std::vector<unsigned int> & indices) -> std::vector<Real> &
212 {
213 mooseAssert(indices[_extra_id_names.size() - 1] == 0, "Indexing issue");
214 if (_extra_id_names.size() == 1)
215 return volumes;
216 else if (_extra_id_names.size() == 2)
217 return volumes_2d[indices[0]];
218 else if (_extra_id_names.size() == 3)
219 return volumes_3d[indices[0]][indices[1]];
220 else
221 return volumes_4d[indices[0]][indices[1]][indices[2]];
222 };
223
224 std::vector<std::map<unsigned int, unsigned int>> positions_indexing(
226
227 // Make index maps to go from the extra element id to the positions array index
228 for (const auto i : index_range(_extra_id_group_indices))
229 {
230 auto & indices = _extra_id_group_indices[i];
231 auto j = 0;
232 for (const auto extra_id : indices)
233 positions_indexing[i][extra_id] = j++;
234 }
235
236 for (const auto & elem : _mesh.getMesh().active_local_element_ptr_range())
237 {
238 // Pre-compute the centroid, this is expensive but may be used for multiple element ids
239 const auto centroid = elem->true_centroid();
240 const auto volume = elem->volume();
241
242 // Keeps track of indices in multi-D arrays
243 std::vector<unsigned int> previous_indices(4);
244
245 for (const auto i : index_range(_extra_id_names))
246 {
247 auto iter =
248 positions_indexing[i].find(id(*elem, _extra_id_indices[i], _blocks_in_use && (i == 0)));
249 if (iter == positions_indexing[i].end())
250 break;
251 else if (_extra_id_names.size() == i + 1)
252 {
253 getNestedPositions(previous_indices)[iter->second] += volume * centroid;
254 getNestedVolumes(previous_indices)[iter->second] += volume;
255 break;
256 }
257 else
258 previous_indices[i] = iter->second;
259 }
260 }
261
262 // Report the zero volumes
263 unsigned int num_zeros = 0;
264 if (_extra_id_names.size() == 1)
265 {
266 _mesh.comm().sum(volumes);
268 for (const auto & vol : volumes)
269 if (MooseUtils::absoluteFuzzyEqual(vol, 0))
270 num_zeros++;
271 }
272 if (_extra_id_names.size() == 2)
273 {
274 for (const auto i : index_range(volumes_2d))
275 {
276 _mesh.comm().sum(volumes_2d[i]);
278 }
279 for (const auto & vol_vec : volumes_2d)
280 for (const auto & vol : vol_vec)
281 if (MooseUtils::absoluteFuzzyEqual(vol, 0))
282 num_zeros++;
283 }
284 if (_extra_id_names.size() == 3)
285 {
286 for (const auto i : index_range(volumes_3d))
287 for (const auto j : index_range(volumes_3d[i]))
288 {
289 _mesh.comm().sum(volumes_3d[i][j]);
290 _mesh.comm().sum(_positions_3d[i][j]);
291 }
292 for (const auto & vol_vec_vec : volumes_3d)
293 for (const auto & vol_vec : vol_vec_vec)
294 for (const auto & vol : vol_vec)
295 if (MooseUtils::absoluteFuzzyEqual(vol, 0))
296 num_zeros++;
297 }
298 if (_extra_id_names.size() == 4)
299 {
300 for (const auto i : index_range(volumes_4d))
301 for (const auto j : index_range(volumes_4d[i]))
302 for (const auto k : index_range(volumes_4d[i][j]))
303 {
304 _mesh.comm().sum(volumes_4d[i][j][k]);
305 _mesh.comm().sum(_positions_4d[i][j][k]);
306 }
307 for (const auto & vol_vec_vec_vec : volumes_4d)
308 for (const auto & vol_vec_vec : vol_vec_vec_vec)
309 for (const auto & vol_vec : vol_vec_vec)
310 for (const auto & vol : vol_vec)
311 if (MooseUtils::absoluteFuzzyEqual(vol, 0))
312 num_zeros++;
313 }
314 if (num_zeros)
315 mooseWarning(std::to_string(num_zeros) +
316 " zero volume bins detected during group centroid position calculation. "
317 "The corresponding positions will be removed from consideration.");
318
319 // Renormalize by the total bin volumes
320 if (_extra_id_names.size() == 1)
321 for (MooseIndex(_positions) i = 0; i < _positions.size(); i++)
322 {
323 if (volumes[i] != 0)
324 _positions[i] /= volumes[i];
325 else
326 {
327 _positions.erase(_positions.begin() + i);
328 volumes.erase(volumes.begin() + i);
329 i--;
330 }
331 }
332 else if (_extra_id_names.size() == 2)
333 for (const auto i : index_range(_positions_2d))
334 for (MooseIndex(_positions) j = 0; j < _positions_2d[i].size(); j++)
335 {
336 if (volumes_2d[i][j] != 0)
337 _positions_2d[i][j] /= volumes_2d[i][j];
338 else
339 {
340 _positions_2d[i].erase(_positions_2d[i].begin() + j);
341 volumes_2d[i].erase(volumes_2d[i].begin() + j);
342 j--;
343 }
344 }
345 else if (_extra_id_names.size() == 3)
346 for (const auto i : index_range(_positions_3d))
347 for (const auto j : index_range(_positions_3d[i]))
348 for (MooseIndex(_positions) k = 0; k < _positions_3d[i][j].size(); k++)
349 {
350 if (volumes_3d[i][j][k] != 0)
351 _positions_3d[i][j][k] /= volumes_3d[i][j][k];
352 else
353 {
354 _positions_3d[i][j].erase(_positions_3d[i][j].begin() + k);
355 volumes_3d[i][j].erase(volumes_3d[i][j].begin() + k);
356 k--;
357 }
358 }
359 else if (_extra_id_names.size() == 4)
360 for (const auto i : index_range(_positions_4d))
361 for (const auto j : index_range(_positions_4d[i]))
362 for (const auto k : index_range(_positions_4d[i][j]))
363 for (MooseIndex(_positions) l = 0; l < _positions_4d[i][j][k].size(); l++)
364 {
365 if (volumes_4d[i][j][k][l] != 0)
366 _positions_4d[i][j][k][l] /= volumes_4d[i][j][k][l];
367 else
368 {
369 _positions_4d[i][j][k].erase(_positions_4d[i][j][k].begin() + l);
370 volumes_4d[i][j][k].erase(volumes_4d[i][j][k].begin() + l);
371 l--;
372 }
373 }
374
375 // Fill the 1D position vector
377 _initialized = true;
378}
379
380dof_id_type
381ElementGroupCentroidPositions::id(const Elem & elem, unsigned int id_index, bool use_subdomains)
382{
383 mooseAssert(!use_subdomains || (id_index == std::numeric_limits<unsigned short>::max()),
384 "We do not expect a valid element extra integer index for subdomains");
385 if (use_subdomains)
386 return elem.subdomain_id();
387 else
388 return elem.get_extra_integer(id_index);
389}
registerMooseObject("MooseApp", ElementGroupCentroidPositions)
void mooseWarning(Args &&... args)
Emit a warning message with the given stringified, concatenated args.
Definition MooseError.h:345
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application.
Definition MooseError.h:311
An interface that restricts an object to subdomains via the 'blocks' input parameter.
virtual const std::set< SubdomainID > & blockIDs() const
Return the block subdomain ids for this object Note, if this is not block restricted,...
const std::set< SubdomainID > & meshBlockIDs() const
Return all of the SubdomainIDs for the mesh.
virtual bool blockRestricted() const
Returns true if this object has been restricted to a block.
static InputParameters validParams()
Positions from centroids of groups of elements (subdomains, extra element ids) in the mesh.
dof_id_type id(const Elem &elem, unsigned int id_index, bool use_subdomains)
std::vector< std::vector< dof_id_type > > _extra_id_group_indices
The particular extra id values, for each extra id of interest.
ElementGroupCentroidPositions(const InputParameters &parameters)
std::vector< unsigned int > _extra_id_indices
The indices of the extra element ids to use to make groups.
void initialize() override
In charge of computing / loading the positions.
static MooseEnum groupTypeEnum()
{ How to group elements, to compute centroids for these groups
std::vector< ExtraElementIDName > _extra_id_names
The names of the extra element ids to use to make groups.
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system.
void addParam(const std::string &name, const S &value, const std::string &doc_string)
These methods add an optional parameter and a documentation string to the InputParameters object.
void addClassDescription(const std::string &doc_string)
This method adds a description of the class that will be displayed in the input file syntax dump.
T & set(const std::string &name, bool quiet_mode=false)
Returns a writable reference to the named parameters.
const std::string & name() const
Get the name of the class.
Definition MooseBase.h:103
void paramError(const std::string &param, Args... args) const
Emits an error prefixed with the file and line number of the given param (from the input file) along ...
Definition MooseBase.h:457
const T & getParam(const std::string &name) const
Retrieve a parameter for the object.
Definition MooseBase.h:406
bool isParamValid(const std::string &name) const
Test if the supplied parameter is valid.
Definition MooseBase.h:199
This is a "smart" enum class intended to replace many of the shortcomings in the C++ enum type It sho...
Definition MooseEnum.h:55
MeshBase & getMesh()
Accessor for the underlying libMesh Mesh object.
Definition MooseMesh.C:3549
Positions objects are under the hood Reporters.
Definition Positions.h:21
std::vector< std::vector< std::vector< std::vector< Point > > > > _positions_4d
4D storage for all the positions : space & time
Definition Positions.h:101
std::vector< std::vector< Point > > _positions_2d
2D storage for all the positions
Definition Positions.h:95
void clearPositions()
Clear all positions vectors.
Definition Positions.C:154
std::vector< Point > & _positions
For now, only the 1D vector will be shared across all ranks.
Definition Positions.h:92
void unrollMultiDPositions()
Unrolls the multi-dimensional position vectors.
Definition Positions.C:163
static InputParameters validParams()
Definition Positions.C:15
std::vector< std::vector< std::vector< Point > > > _positions_3d
3D storage for all the positions
Definition Positions.h:98
virtual void finalize() override
In charge of reduction across all ranks & sorting for consistent output.
Definition Positions.C:220
bool _initialized
Whether the positions object has been initialized. This must be set by derived objects.
Definition Positions.h:116
void set_union(T &data, const unsigned int root_id) const
const Parallel::Communicator & comm() const
MeshBase & mesh