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