Line data Source code
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 : #pragma once
11 :
12 : // MOOSE includes
13 : #include "SpatialUserObjectFunctor.h"
14 : #include "Enumerate.h"
15 : #include "DelimitedFileReader.h"
16 : #include "LayeredBase.h"
17 : #include "FEProblemBase.h"
18 : #include "Positions.h"
19 :
20 : // Forward Declarations
21 : class UserObject;
22 :
23 : /**
24 : * This UserObject computes averages of a variable storing partial
25 : * sums for the specified number of intervals in a direction (x,y,z).
26 : *
27 : * Given a list of points this object computes the layered average
28 : * closest to each one of those points.
29 : */
30 : template <typename UserObjectType, typename BaseType>
31 : class NearestPointBase : public SpatialUserObjectFunctor<BaseType>
32 : {
33 : public:
34 : static InputParameters validParams();
35 :
36 : NearestPointBase(const InputParameters & parameters);
37 : ~NearestPointBase();
38 :
39 : virtual void initialize() override;
40 : virtual void execute() override;
41 : virtual void finalize() override;
42 : virtual void threadJoin(const UserObject & y) override;
43 :
44 : /**
45 : * Given a Point return the integral value associated with the layer
46 : * that point falls in for the layered average closest to that
47 : * point.
48 : *
49 : * @param p The point to look for in the layers.
50 : */
51 : virtual Real spatialValue(const Point & p) const override;
52 :
53 : /**
54 : * Get the points at which the nearest operation is performed
55 : * @return points
56 : */
57 13 : virtual const std::vector<Point> & getPoints() const { return _points; }
58 :
59 : virtual const std::vector<Point> spatialPoints() const override;
60 :
61 : protected:
62 : /**
63 : * Fills in the `_points` variable from either 'points' or 'points_file' parameter.
64 : * Also performs error checking.
65 : */
66 : void fillPoints();
67 :
68 : /**
69 : * Get the UserObject that is closest to the point.
70 : *
71 : * @param p The point.
72 : * @return The UserObject closest to p.
73 : */
74 : UserObjectType & nearestUserObject(const Point & p) const;
75 :
76 : std::vector<Point> _points;
77 : std::vector<std::unique_ptr<UserObjectType>> _user_objects;
78 :
79 : // To specify whether the distance is defined based on point or radius
80 : const unsigned int _dist_norm;
81 : // The axis around which the radius is determined
82 : const unsigned int _axis;
83 :
84 : using BaseType::_communicator;
85 : using BaseType::_current_elem;
86 : using BaseType::isParamValid;
87 : using BaseType::processor_id;
88 : using MooseBase::name;
89 : };
90 :
91 : template <typename UserObjectType, typename BaseType>
92 : InputParameters
93 157889 : NearestPointBase<UserObjectType, BaseType>::validParams()
94 : {
95 157889 : InputParameters params = SpatialUserObjectFunctor<BaseType>::validParams();
96 :
97 157889 : params.addParam<std::vector<Point>>("points",
98 : "Computations will be lumped into values at these points.");
99 157889 : params.addParam<FileName>("points_file",
100 : "A filename that should be looked in for points. Each "
101 : "set of 3 values in that file will represent a Point. "
102 : "This and 'points' cannot be both supplied.");
103 157889 : params.addParam<PositionsName>(
104 : "positions_object",
105 : "The name of a Positions object that will contain "
106 : "the locations. This, 'points' and 'points(_file)' cannot be both supplied. "
107 : "Note that only the vector of initial Positions are used at this time. "
108 : "Updates to the 'positions' vector are not supported.");
109 :
110 157889 : MooseEnum distnorm("point=0 radius=1", "point");
111 157889 : params.addParam<MooseEnum>(
112 : "dist_norm", distnorm, "To specify whether the distance is defined based on point or radius");
113 157889 : MooseEnum axis("x=0 y=1 z=2", "z");
114 157889 : params.addParam<MooseEnum>("axis", axis, "The axis around which the radius is determined");
115 :
116 157889 : params.addParamNamesToGroup("points points_file dist_norm axis", "Points and distance to points");
117 :
118 : // Add in the valid parameters
119 157889 : params += UserObjectType::validParams();
120 :
121 315778 : return params;
122 157889 : }
123 :
124 : template <typename UserObjectType, typename BaseType>
125 518 : NearestPointBase<UserObjectType, BaseType>::NearestPointBase(const InputParameters & parameters)
126 : : SpatialUserObjectFunctor<BaseType>(parameters),
127 518 : _dist_norm(this->template getParam<MooseEnum>("dist_norm")),
128 1036 : _axis(this->template getParam<MooseEnum>("axis"))
129 : {
130 1526 : if (this->template getParam<MooseEnum>("dist_norm") != "radius" &&
131 1008 : parameters.isParamSetByUser("axis"))
132 0 : this->paramError("axis", "'axis' should only be set if 'dist_norm' is set to 'radius'");
133 :
134 518 : fillPoints();
135 :
136 506 : _user_objects.resize(_points.size());
137 :
138 : // Build each of the UserObject objects that we will manage manually
139 : // If you're looking at this in the future and want to replace this behavior,
140 : // _please_ don't do it. MOOSE should manage these objects.
141 2117 : for (MooseIndex(_points) i = 0; i < _points.size(); ++i)
142 : {
143 1623 : const auto uo_type = MooseUtils::prettyCppType<UserObjectType>();
144 1623 : auto sub_params = this->_app.getFactory().getValidParams(uo_type);
145 1623 : sub_params.applyParameters(parameters, {}, true);
146 :
147 1623 : const auto sub_name = name() + "_sub" + std::to_string(i);
148 1623 : auto uo = this->_app.getFactory().template createUnique<UserObjectType>(
149 1623 : uo_type, sub_name, sub_params, this->_tid);
150 1611 : _user_objects[i] = std::move(uo);
151 : }
152 494 : }
153 :
154 : template <typename UserObjectType, typename BaseType>
155 479 : NearestPointBase<UserObjectType, BaseType>::~NearestPointBase()
156 : {
157 479 : }
158 :
159 : template <typename UserObjectType, typename BaseType>
160 : void
161 518 : NearestPointBase<UserObjectType, BaseType>::fillPoints()
162 : {
163 518 : if (isParamValid("points"))
164 : {
165 440 : _points = this->template getParam<std::vector<Point>>("points");
166 440 : if (isParamValid("points_file"))
167 4 : this->paramError("points_file", "Cannot be specified together with 'points'");
168 436 : if (isParamValid("positions_object"))
169 0 : this->paramError("positions_object", "Cannot be specified together with 'points'");
170 : }
171 78 : else if (isParamValid("points_file"))
172 : {
173 60 : const FileName & points_file = this->template getParam<FileName>("points_file");
174 :
175 60 : MooseUtils::DelimitedFileReader file(points_file, &_communicator);
176 60 : file.setFormatFlag(MooseUtils::DelimitedFileReader::FormatFlag::ROWS);
177 60 : file.read();
178 60 : _points = file.getDataAsPoints();
179 :
180 56 : if (isParamValid("positions_object"))
181 0 : this->paramError("positions_object", "Cannot be specified together with 'points_file'");
182 56 : }
183 18 : else if (isParamValid("positions_object"))
184 : {
185 14 : const auto & positions_name = this->template getParam<PositionsName>("positions_object");
186 14 : const auto problem = this->template getCheckedPointerParam<FEProblemBase *>("_fe_problem_base");
187 14 : _points = problem->getPositionsObject(positions_name).getPositions(/*initial_positions*/ true);
188 : }
189 : else
190 8 : mooseError(
191 4 : name(),
192 : ": You need to supply either 'points', 'points_file' or 'positions_object' parameter.");
193 506 : }
194 :
195 : template <typename UserObjectType, typename BaseType>
196 : void
197 1016 : NearestPointBase<UserObjectType, BaseType>::initialize()
198 : {
199 4719 : for (auto & user_object : _user_objects)
200 3703 : user_object->initialize();
201 1016 : }
202 :
203 : template <typename UserObjectType, typename BaseType>
204 : void
205 902391 : NearestPointBase<UserObjectType, BaseType>::execute()
206 : {
207 902391 : nearestUserObject(_current_elem->vertex_average()).execute();
208 902391 : }
209 :
210 : template <typename UserObjectType, typename BaseType>
211 : void
212 738 : NearestPointBase<UserObjectType, BaseType>::finalize()
213 : {
214 3662 : for (auto & user_object : _user_objects)
215 2924 : user_object->finalize();
216 738 : }
217 :
218 : template <typename UserObjectType, typename BaseType>
219 : void
220 78 : NearestPointBase<UserObjectType, BaseType>::threadJoin(const UserObject & y)
221 : {
222 78 : auto & npla = static_cast<const NearestPointBase &>(y);
223 :
224 361 : for (MooseIndex(_user_objects) i = 0; i < _user_objects.size(); ++i)
225 283 : _user_objects[i]->threadJoin(*npla._user_objects[i]);
226 78 : }
227 :
228 : template <typename UserObjectType, typename BaseType>
229 : Real
230 934712 : NearestPointBase<UserObjectType, BaseType>::spatialValue(const Point & p) const
231 : {
232 934712 : return nearestUserObject(p).spatialValue(p);
233 : }
234 :
235 : template <typename UserObjectType, typename BaseType>
236 : UserObjectType &
237 1837103 : NearestPointBase<UserObjectType, BaseType>::nearestUserObject(const Point & p) const
238 : {
239 1837103 : unsigned int closest = 0;
240 1837103 : Real closest_distance = std::numeric_limits<Real>::max();
241 :
242 10068560 : for (auto it : Moose::enumerate(_points))
243 : {
244 6394354 : const auto & current_point = it.value();
245 :
246 : Real current_distance;
247 6394354 : if (_dist_norm == 0)
248 : // the distance is computed using standard norm
249 5148994 : current_distance = (p - current_point).norm();
250 : else
251 : {
252 : // the distance is to be computed based on radii
253 : // in that case, we need to determine the 2 coordinate indices
254 : // that define the radius
255 1245360 : unsigned int i = 0;
256 1245360 : unsigned int j = 1;
257 :
258 1245360 : if (_axis == 0)
259 0 : i = 2;
260 1245360 : else if (_axis == 1)
261 0 : j = 2;
262 :
263 1245360 : current_distance = std::abs(
264 1245360 : std::sqrt(p(i) * p(i) + p(j) * p(j)) -
265 1245360 : std::sqrt(current_point(i) * current_point(i) + current_point(j) * current_point(j)));
266 : }
267 :
268 6394354 : if (current_distance < closest_distance)
269 : {
270 3609611 : closest_distance = current_distance;
271 3609611 : closest = it.index();
272 : }
273 : }
274 :
275 1837103 : return *_user_objects[closest];
276 : }
277 :
278 : template <typename UserObjectType, typename BaseType>
279 : const std::vector<Point>
280 39 : NearestPointBase<UserObjectType, BaseType>::spatialPoints() const
281 : {
282 39 : std::vector<Point> points;
283 :
284 208 : for (MooseIndex(_points) i = 0; i < _points.size(); ++i)
285 : {
286 169 : auto layered_base = dynamic_cast<LayeredBase *>(_user_objects[i].get());
287 169 : if (layered_base)
288 : {
289 169 : const auto & layers = layered_base->getLayerCenters();
290 169 : auto direction = layered_base->direction();
291 :
292 611 : for (const auto & l : layers)
293 : {
294 442 : Point pt = _points[i];
295 442 : pt(direction) = l;
296 442 : points.push_back(pt);
297 : }
298 : }
299 : }
300 :
301 39 : return points;
302 0 : }
|