Loading [MathJax]/jax/output/HTML-CSS/config.js
https://mooseframework.inl.gov
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
Positions.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 
10 #include "Positions.h"
11 #include "libmesh/parallel_algebra.h"
12 #include "MooseMeshUtils.h"
13 
16 {
18 
19  params.addParam<PositionsName>("initial_positions",
20  "Positions at the beginning of the simulation");
21 
22  // This parameter should be set by each derived class depending on whether the generation of
23  // positions is replicated or distributed. We want positions to be replicated across all ranks
24  params.addRequiredParam<bool>("auto_broadcast",
25  "Wether Positions should be broadcasted across all ranks");
26  // This parameter should be set by each derived class depending on whether positions should
27  // be sorted after being communicated. Sorting is usually undesirable, as the user input order
28  // should be respected. It may be only desirable for testing reproducibility
29  params.addRequiredParam<bool>("auto_sort", "Whether Positions should be sorted by coordinates");
30 
31  // In general, no need to refresh Positions unless the mesh moved
32  params.set<ExecFlagEnum>("execute_on") = EXEC_NONE;
33 
34  params.addParamNamesToGroup("auto_broadcast auto_sort", "Advanced");
35  params.registerBase("Positions");
36  return params;
37 }
38 
40  : GeneralReporter(parameters),
41  // leverage reporter interface to keep track of consumers
42  _initial_positions(isParamValid("initial_positions")
43  ? &getReporterValueByName<std::vector<Point>>(
44  getParam<PositionsName>("initial_positions") + "/positions_1d")
45  : nullptr),
46  // Positions will be replicated on every rank so transfers may query positions from all ranks
47  _positions(declareValueByName<std::vector<Point>, ReporterVectorContext<Point>>(
48  "positions_1d", REPORTER_MODE_REPLICATED)),
49  _need_broadcast(getParam<bool>("auto_broadcast")),
50  _need_sort(getParam<bool>("auto_sort")),
51  _initialized(false)
52 {
53 
55  _initial_positions_kd_tree = std::make_unique<KDTree>(*_initial_positions, 1);
56 }
57 
58 const Point &
59 Positions::getPosition(unsigned int index, bool initial) const
60 {
61  mooseAssert(initialized(initial), "Positions vector has not been initialized.");
62  // Check sizes of inital positions
63  if (initial && _initial_positions && (*_initial_positions).size() < index)
64  mooseError("Initial positions is not sized or initialized appropriately");
65 
66  // Check sizes of regular positions
67  if (!initial)
68  {
69  if (_initial_positions && _positions.size() != (*_initial_positions).size())
70  mooseError("Initial positions and current positions array length do not match");
71  else if (_positions.size() < index)
72  mooseError("Positions retrieved with an out-of-bound index: '",
73  index,
74  "' when there are only ",
75  _positions.size(),
76  " positions.");
77  }
78 
79  if (initial && _initial_positions)
80  return (*_initial_positions)[index];
81  if (_positions.size())
82  return _positions[index];
83  else
84  mooseError("Positions vector has not been initialized.");
85 }
86 
87 const Point &
88 Positions::getNearestPosition(const Point & target, const bool initial) const
89 {
90  mooseAssert(initialized(initial), "Positions vector has not been initialized.");
91  const auto & positions = (initial && _initial_positions) ? *_initial_positions : _positions;
92  return positions[getNearestPositionIndex(target, initial)];
93 }
94 
95 unsigned int
96 Positions::getNearestPositionIndex(const Point & target, const bool initial) const
97 {
98  mooseAssert(initialized(initial), "Positions vector has not been initialized.");
99  std::vector<std::size_t> return_index(1);
100 
101  if (initial && _initial_positions)
102  {
103  mooseAssert(_initial_positions_kd_tree, "Should have an initial positions KDTree");
104  _initial_positions_kd_tree->neighborSearch(target, 1, return_index);
105  }
106  else
107  {
108  mooseAssert(_positions_kd_tree, "Should have a positions KDTree");
109  _positions_kd_tree->neighborSearch(target, 1, return_index);
110  }
111 
112  return return_index[0];
113 }
114 
115 const std::vector<Point> &
116 Positions::getPositions(bool initial) const
117 {
118  if (initial && _initial_positions)
119  return *_initial_positions;
120  if (_positions.size())
121  return _positions;
122  else
123  mooseError("Positions vector has not been initialized.");
124 }
125 
126 const std::vector<std::vector<Point>> &
128 {
129  if (_positions_2d.size())
130  return _positions_2d;
131  else
132  mooseError("2D positions vectors have not been initialized.");
133 }
134 
135 const std::vector<std::vector<std::vector<Point>>> &
137 {
138  if (_positions_3d.size())
139  return _positions_3d;
140  else
141  mooseError("3D positions vectors have not been initialized.");
142 }
143 
144 const std::vector<std::vector<std::vector<std::vector<Point>>>> &
146 {
147  if (_positions_4d.size())
148  return _positions_4d;
149  else
150  mooseError("4D positions vectors have not been initialized.");
151 }
152 
153 void
155 {
156  _positions.clear();
157  _positions_2d.clear();
158  _positions_3d.clear();
159  _positions_4d.clear();
160 }
161 
162 void
164 {
165  // Unroll in every dimension available
166  std::vector<Point> temp_2d_unrolled;
167  std::vector<Point> temp_3d_unrolled;
168  std::vector<Point> temp_4d_unrolled;
169  for (auto vec : _positions_2d)
170  temp_2d_unrolled.insert(temp_2d_unrolled.end(), vec.begin(), vec.end());
171  for (const auto & vec_vec : _positions_3d)
172  for (const auto & vec : vec_vec)
173  temp_3d_unrolled.insert(temp_3d_unrolled.end(), vec.begin(), vec.end());
174  for (const auto & vec_vec_vec : _positions_4d)
175  for (const auto & vec_vec : vec_vec_vec)
176  for (const auto & vec : vec_vec)
177  temp_4d_unrolled.insert(temp_4d_unrolled.end(), vec.begin(), vec.end());
178 
179  // for now we wont even tolerate a different ordering
180  // 2D & 1D: check for conflicts
181  if (temp_2d_unrolled.size() && _positions.size() && temp_2d_unrolled != _positions)
182  mooseError("Inconsistency between the 2D and 1D position vectors detected. "
183  "The 2D positions must unroll into the 1D positions");
184 
185  // 3D vs 2D & 1D
186  if (temp_3d_unrolled.size() && temp_2d_unrolled.size() && temp_3d_unrolled != temp_3d_unrolled)
187  mooseError("Inconsistency between the 3D and 2D position vectors detected. "
188  "The 3D positions must unroll the same way as the 2D positions");
189  if (temp_3d_unrolled.size() && _positions.size() && temp_3d_unrolled != _positions)
190  mooseError("Inconsistency between the 3D and 1D position vectors detected. "
191  "The 3D positions must unroll into the 1D positions");
192 
193  // 4D vs all lower dimensions
194  if (temp_4d_unrolled.size() && temp_3d_unrolled.size() && temp_4d_unrolled != temp_3d_unrolled)
195  mooseError("Inconsistency between the 4D and 3D position vectors detected. "
196  "The 4D positions must unroll the same way as the 3D positions");
197  if (temp_4d_unrolled.size() && temp_2d_unrolled.size() && temp_4d_unrolled != temp_2d_unrolled)
198  mooseError("Inconsistency between the 4D and 2D position vectors detected. "
199  "The 4D positions must unroll the same way as the 2D positions");
200  if (temp_4d_unrolled.size() && _positions.size() && temp_4d_unrolled != _positions)
201  mooseError("Inconsistency between the 4D and 1D position vectors detected. "
202  "The 4D positions must unroll into the 1D positions");
203 
204  // Use any of the higher D to set the one D vector
205  if (!_positions.size())
206  {
207  if (temp_2d_unrolled.size())
208  _positions = temp_2d_unrolled;
209  else if (temp_3d_unrolled.size())
210  _positions = temp_3d_unrolled;
211  else if (temp_4d_unrolled.size())
212  _positions = temp_4d_unrolled;
213  else
214  mooseError("Positions::unrollMultiDPositions() may only be called if there is at least one "
215  "non-empty positions vector.");
216  }
217 }
218 
219 void
221 {
222  // Gather up the positions vector on all ranks
223  mooseAssert(initialized(false), "Positions vector has not been initialized.");
224  if (_need_broadcast)
225  // The consumer/producer reporter interface can keep track of whether a reduction is needed
226  // (for example if a consumer needs replicated data, but the producer is distributed) however,
227  // we have currently made the decision that positions should ALWAYS be replicated
228  _communicator.allgather(_positions, /* identical buffer lengths = */ false);
229 
230  // Sort positions by X then Y then Z
231  if (_need_sort)
232  std::sort(_positions.begin(), _positions.end());
233 
234  // Make a KDTree with the positions
235  _positions_kd_tree = std::make_unique<KDTree>(_positions, 1);
236 
237  // For now at least, we expect positions to be the same on all ranks
238  mooseAssert(comm().verify(_positions), "Positions should be the same across all MPI processes.");
239 }
240 
241 Real
243 {
244  mooseAssert(initialized(false), "Positions vector has not been initialized.");
245  // Dumb nested loops. We can revisit this once we have a KDTree for nearest position searching
246  // These nested loops are still faster than calling getNearestPositions on each position for now
247  Real min_distance_sq = std::numeric_limits<Real>::max();
248  for (const auto i1 : index_range(_positions))
249  for (auto i2 = i1 + 1; i2 < _positions.size(); i2++)
250  min_distance_sq = std::min(min_distance_sq, (_positions[i1] - _positions[i2]).norm_sq());
251  return std::sqrt(min_distance_sq);
252 }
253 
254 bool
256 {
257  mooseAssert(initialized(false), "Positions vector has not been initialized.");
259 }
260 
261 bool
262 Positions::initialized(bool initial) const
263 {
264  if (initial && _initial_positions)
265  // We do not forward the 'initial' status as we are not currently looking
266  // to support two level nesting for initial positions
267  return _fe_problem.getPositionsObject(getParam<PositionsName>("initial_positions"))
268  .initialized(false);
269  else
270  return _initialized;
271 }
void allgather(const T &send_data, std::vector< T, A > &recv_data) const
A MultiMooseEnum object to hold "execute_on" flags.
Definition: ExecFlagEnum.h:21
const Point & getNearestPosition(const Point &target, bool initial) const
Find the nearest Position for a given point.
Definition: Positions.C:88
static InputParameters validParams()
Definition: Positions.C:15
std::unique_ptr< KDTree > _initial_positions_kd_tree
KDTree to be able to find the nearest position to a point in a fast and scalable manner.
Definition: Positions.h:104
This context is specific for vector types of reporters, mainly for declaring a vector of the type fro...
Reporter object that has a single execution of the "execute" method for for each execute flag...
void clearPositions()
Clear all positions vectors.
Definition: Positions.C:154
const ExecFlagType EXEC_NONE
Definition: Moose.C:27
T & set(const std::string &name, bool quiet_mode=false)
Returns a writable reference to the named parameters.
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
const Parallel::Communicator & comm() const
static InputParameters validParams()
const Point & getPosition(unsigned int index, bool initial) const
Getter for a single position at a known index.
Definition: Positions.C:59
const Parallel::Communicator & _communicator
Positions(const InputParameters &parameters)
Definition: Positions.C:39
void unrollMultiDPositions()
Unrolls the multi-dimensional position vectors.
Definition: Positions.C:163
const Positions & getPositionsObject(const std::string &name) const
Get the Positions object by its name.
void addRequiredParam(const std::string &name, const std::string &doc_string)
This method adds a parameter and documentation string to the InputParameters object that will be extr...
auto max(const L &left, const R &right)
bool _initialized
Whether the positions object has been initialized. This must be set by derived objects.
Definition: Positions.h:116
void registerBase(const std::string &value)
This method must be called from every base "Moose System" to create linkage with the Action System...
std::vector< std::vector< Point > > _positions_2d
2D storage for all the positions
Definition: Positions.h:95
unsigned int getNearestPositionIndex(const Point &target, bool initial) const
Find the nearest Position index for a given point.
Definition: Positions.C:96
std::vector< Point > & _positions
For now, only the 1D vector will be shared across all ranks.
Definition: Positions.h:92
bool initialized(bool initial) const
Whether the positions object has been initialized.
Definition: Positions.C:262
std::vector< std::vector< std::vector< Point > > > _positions_3d
3D storage for all the positions
Definition: Positions.h:98
bool isCoPlanar(const std::vector< Point > vec_pts, const Point plane_nvec, const Point fixed_pt)
Decides whether all the Points of a vector of Points are in a plane that is defined by a normal vecto...
const std::vector< Point > & getPositions(bool initial) const
{ Getters for the positions vector for the desired dimension 1D will be the only one guaranteed to su...
Definition: Positions.C:116
bool _need_broadcast
Whether generation of positions is distributed or not (and therefore needs a broadcast) ...
Definition: Positions.h:108
const std::vector< std::vector< std::vector< Point > > > & getPositionsVector3D() const
Definition: Positions.C:136
std::unique_ptr< KDTree > _positions_kd_tree
Definition: Positions.h:105
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
CTSub CT_OPERATOR_BINARY CTMul CTCompareLess CTCompareGreater CTCompareEqual _arg template * sqrt(_arg)) *_arg.template D< dtag >()) CT_SIMPLE_UNARY_FUNCTION(tanh
FEProblemBase & _fe_problem
Reference to the FEProblemBase for this user object.
Definition: UserObject.h:211
const bool _need_sort
Whether positions should be sorted.
Definition: Positions.h:113
virtual void finalize() override
In charge of reduction across all ranks & sorting for consistent output.
Definition: Positions.C:220
void mooseError(Args &&... args) const
Emits an error prefixed with object name and type.
const std::vector< Point > *const _initial_positions
For initialization of the positions, another position reporter may be used.
Definition: Positions.h:86
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...
const ReporterMode REPORTER_MODE_REPLICATED
bool arePositionsCoplanar() const
Report if the positions are co-planar or not.
Definition: Positions.C:255
Real getMinDistanceBetweenPositions() const
Find the minimum distance between positions.
Definition: Positions.C:242
const std::vector< std::vector< std::vector< std::vector< Point > > > > & getPositionsVector4D() const
Definition: Positions.C:145
auto min(const L &left, const R &right)
const std::vector< std::vector< Point > > & getPositionsVector2D() const
Definition: Positions.C:127
std::vector< std::vector< std::vector< std::vector< Point > > > > _positions_4d
4D storage for all the positions : space & time
Definition: Positions.h:101
auto index_range(const T &sizable)
void addParamNamesToGroup(const std::string &space_delim_names, const std::string group_name)
This method takes a space delimited list of parameter names and adds them to the specified group name...