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 : #include "MooseMesh.h"
13 : #include "MooseTypes.h"
14 : #include "MooseError.h"
15 : #include "MooseFunctor.h"
16 : #include "Moose.h"
17 : #include "Limiter.h"
18 : #include "MathFVUtils.h"
19 : #include "GreenGaussGradient.h"
20 :
21 : #include "libmesh/elem.h"
22 : #include "libmesh/remote_elem.h"
23 : #include "libmesh/tensor_tools.h"
24 :
25 : #include <unordered_map>
26 : #include <functional>
27 :
28 : /**
29 : * A material property that is evaluated on-the-fly via calls to various overloads of \p operator()
30 : */
31 : template <typename T>
32 : class PiecewiseByBlockLambdaFunctor : public Moose::FunctorBase<T>
33 : {
34 : public:
35 : template <typename PolymorphicLambda>
36 : PiecewiseByBlockLambdaFunctor(const std::string & name,
37 : PolymorphicLambda my_lammy,
38 : const std::set<ExecFlagType> & clearance_schedule,
39 : const MooseMesh & mesh,
40 : const std::set<SubdomainID> & block_ids);
41 :
42 : /**
43 : * Set the functor that will be used in calls to \p evaluate overloads
44 : * @param mesh The mesh that the functor is defined on
45 : * @param block_ids The block/subdomain IDs that the user-provided functor is valid for
46 : * @param my_lammy The functor that defines how this object is evaluated
47 : */
48 : template <typename PolymorphicLambda>
49 : void setFunctor(const MooseMesh & mesh,
50 : const std::set<SubdomainID> & block_ids,
51 : PolymorphicLambda my_lammy);
52 :
53 14888 : virtual ~PiecewiseByBlockLambdaFunctor() = default;
54 :
55 : bool isExtrapolatedBoundaryFace(const FaceInfo & fi,
56 : const Elem * elem,
57 : const Moose::StateArg & time) const override;
58 :
59 : bool hasBlocks(SubdomainID id) const override;
60 :
61 0 : bool supportsFaceArg() const override final { return true; }
62 0 : bool supportsElemSideQpArg() const override final { return true; }
63 :
64 : using typename Moose::FunctorBase<T>::FunctorType;
65 : using typename Moose::FunctorBase<T>::ValueType;
66 : using typename Moose::FunctorBase<T>::DotType;
67 : using typename Moose::FunctorBase<T>::GradientType;
68 :
69 : protected:
70 : using ElemFn = std::function<T(const Moose::ElemArg &, const Moose::StateArg &)>;
71 : using FaceFn = std::function<T(const Moose::FaceArg &, const Moose::StateArg &)>;
72 : using ElemQpFn = std::function<T(const Moose::ElemQpArg &, const Moose::StateArg &)>;
73 : using ElemSideQpFn = std::function<T(const Moose::ElemSideQpArg &, const Moose::StateArg &)>;
74 : using ElemPointFn = std::function<T(const Moose::ElemPointArg &, const Moose::StateArg &)>;
75 : using NodeFn = std::function<T(const Moose::NodeArg &, const Moose::StateArg &)>;
76 :
77 : ValueType evaluate(const Moose::ElemArg & elem_arg, const Moose::StateArg & time) const override;
78 : ValueType evaluate(const Moose::FaceArg & face, const Moose::StateArg & time) const override;
79 : ValueType evaluate(const Moose::ElemQpArg & elem_qp, const Moose::StateArg & time) const override;
80 : ValueType evaluate(const Moose::ElemSideQpArg & elem_side_qp,
81 : const Moose::StateArg & time) const override;
82 : ValueType evaluate(const Moose::ElemPointArg & elem_point,
83 : const Moose::StateArg & time) const override;
84 : ValueType evaluate(const Moose::NodeArg & node_arg, const Moose::StateArg & time) const override;
85 :
86 : using Moose::FunctorBase<T>::evaluateGradient;
87 : GradientType evaluateGradient(const Moose::ElemArg & elem_arg,
88 : const Moose::StateArg &) const override;
89 : GradientType evaluateGradient(const Moose::FaceArg & face_arg,
90 : const Moose::StateArg &) const override;
91 :
92 : private:
93 : /**
94 : * Provide a useful error message about lack of functor material property on the provided
95 : * subdomain \p sub_id
96 : * @param sub_id subdomain id on which the functor was missing
97 : * @param functors map of functors, used to show list of blocks with a definition
98 : */
99 : template <typename C>
100 : void subdomainErrorMessage(SubdomainID sub_id,
101 : const std::unordered_map<SubdomainID, C> & functors) const;
102 :
103 : /**
104 : * Format a subdomain ID with its name, when available.
105 : */
106 : std::string subdomainNameAndID(SubdomainID sub_id) const;
107 :
108 : /// Functors that return element average values (or cell centroid values or whatever the
109 : /// implementer wants to return for a given element argument)
110 : std::unordered_map<SubdomainID, ElemFn> _elem_functor;
111 :
112 : /// Functors that return the property value on the requested side of the face (e.g. the
113 : /// infinitesimal + or - side of the face)
114 : std::unordered_map<SubdomainID, FaceFn> _face_functor;
115 :
116 : /// Functors that will evaluate elements at quadrature points
117 : std::unordered_map<SubdomainID, ElemQpFn> _elem_qp_functor;
118 :
119 : /// Functors that will evaluate elements at side quadrature points
120 : std::unordered_map<SubdomainID, ElemSideQpFn> _elem_side_qp_functor;
121 :
122 : /// Functors that return evaluations at an arbitrary physical point in an element
123 : std::unordered_map<SubdomainID, ElemPointFn> _elem_point_functor;
124 :
125 : /// Functors that return nodal values
126 : std::unordered_map<SubdomainID, NodeFn> _node_functor;
127 :
128 : /// The mesh that this functor operates on
129 : const MooseMesh & _mesh;
130 : };
131 :
132 : template <typename T>
133 : template <typename PolymorphicLambda>
134 7773 : PiecewiseByBlockLambdaFunctor<T>::PiecewiseByBlockLambdaFunctor(
135 : const std::string & name,
136 : PolymorphicLambda my_lammy,
137 : const std::set<ExecFlagType> & clearance_schedule,
138 : const MooseMesh & mesh,
139 : const std::set<SubdomainID> & block_ids)
140 7773 : : Moose::FunctorBase<T>(name, clearance_schedule), _mesh(mesh)
141 : {
142 7773 : setFunctor(mesh, block_ids, my_lammy);
143 7773 : }
144 :
145 : template <typename T>
146 : template <typename PolymorphicLambda>
147 : void
148 8600 : PiecewiseByBlockLambdaFunctor<T>::setFunctor(const MooseMesh & mesh,
149 : const std::set<SubdomainID> & block_ids,
150 : PolymorphicLambda my_lammy)
151 : {
152 : mooseAssert(&mesh == &_mesh,
153 : "We should always be setting this functor with the same mesh. We may relax this "
154 : "assertion later");
155 :
156 37471 : auto add_lammy = [this, my_lammy](const SubdomainID block_id)
157 : {
158 28874 : auto pr = _elem_functor.emplace(block_id, my_lammy);
159 28874 : if (!pr.second)
160 3 : mooseError("No insertion for the functor material property '",
161 : this->functorName(),
162 : "' for block id ",
163 : block_id,
164 : ". Another material must already declare this property on that block.");
165 28871 : _face_functor.emplace(block_id, my_lammy);
166 28871 : _elem_qp_functor.emplace(block_id, my_lammy);
167 28871 : _elem_side_qp_functor.emplace(block_id, my_lammy);
168 28871 : _elem_point_functor.emplace(block_id, my_lammy);
169 28871 : _node_functor.emplace(block_id, my_lammy);
170 : };
171 :
172 32202 : for (const auto block_id : block_ids)
173 23605 : add_lammy(block_id);
174 :
175 : // Handle special case of ANY_BLOCK_ID and empty block restriction that also cover
176 : // INVALID_BLOCK_ID
177 17192 : if (block_ids.count(Moose::ANY_BLOCK_ID) || block_ids.empty() ||
178 8595 : block_ids == mesh.meshSubdomains())
179 5269 : add_lammy(Moose::INVALID_BLOCK_ID);
180 8597 : }
181 :
182 : template <typename T>
183 : bool
184 1688 : PiecewiseByBlockLambdaFunctor<T>::isExtrapolatedBoundaryFace(const FaceInfo & fi,
185 : const Elem *,
186 : const Moose::StateArg &) const
187 : {
188 1688 : if (!fi.neighborPtr())
189 848 : return true;
190 :
191 840 : const bool defined_on_elem = _elem_functor.count(fi.elem().subdomain_id());
192 840 : const bool defined_on_neighbor = _elem_functor.count(fi.neighbor().subdomain_id());
193 840 : const bool extrapolated = (defined_on_elem + defined_on_neighbor) == 1;
194 :
195 : mooseAssert(defined_on_elem || defined_on_neighbor,
196 : "This shouldn't be called if we aren't defined on either side.");
197 840 : return extrapolated;
198 : }
199 :
200 : template <typename T>
201 : bool
202 20064 : PiecewiseByBlockLambdaFunctor<T>::hasBlocks(const SubdomainID id) const
203 : {
204 : // If any of the maps has a functor for that block, it has the block
205 20064 : const bool has_blocks = _elem_functor.count(id);
206 : mooseAssert(has_blocks == _face_functor.count(id),
207 : "All functor sets should agree on whether we have this sub id");
208 : mooseAssert(has_blocks == _elem_qp_functor.count(id),
209 : "All functor sets should agree on whether we have this sub id");
210 : mooseAssert(has_blocks == _elem_side_qp_functor.count(id),
211 : "All functor sets should agree on whether we have this sub id");
212 20064 : return has_blocks;
213 : }
214 :
215 : template <typename T>
216 : std::string
217 30 : PiecewiseByBlockLambdaFunctor<T>::subdomainNameAndID(const SubdomainID sub_id) const
218 : {
219 30 : const auto & name = _mesh.getSubdomainName(sub_id);
220 30 : if (name.empty())
221 24 : return Moose::stringify(sub_id);
222 6 : return "'" + name + "' (" + Moose::stringify(sub_id) + ")";
223 : }
224 :
225 : template <typename T>
226 : template <typename C>
227 : void
228 15 : PiecewiseByBlockLambdaFunctor<T>::subdomainErrorMessage(
229 : const SubdomainID sub_id, const std::unordered_map<SubdomainID, C> & functors) const
230 : {
231 15 : std::vector<std::string> block_names_and_ids;
232 15 : block_names_and_ids.reserve(functors.size());
233 30 : for (const auto & [available_sub_id, functor] : functors)
234 : {
235 15 : libmesh_ignore(functor);
236 15 : block_names_and_ids.push_back(subdomainNameAndID(available_sub_id));
237 : }
238 78 : mooseError("The provided subdomain ",
239 : subdomainNameAndID(sub_id),
240 : " doesn't exist in the map for lambda functor '",
241 : this->functorName(),
242 : "'! This is likely because you did not provide a functor material "
243 : "definition on that subdomain.\nSubdomains in the map: ",
244 : Moose::stringify(block_names_and_ids));
245 12 : }
246 :
247 : template <typename T>
248 : typename PiecewiseByBlockLambdaFunctor<T>::ValueType
249 3846468 : PiecewiseByBlockLambdaFunctor<T>::evaluate(const Moose::ElemArg & elem_arg,
250 : const Moose::StateArg & time) const
251 : {
252 3846468 : const Elem * const elem = elem_arg.elem;
253 : mooseAssert(elem && elem != libMesh::remote_elem,
254 : "The element must be non-null and non-remote in functor material properties");
255 3846468 : auto it = _elem_functor.find(elem->subdomain_id());
256 3846468 : if (it == _elem_functor.end())
257 2 : subdomainErrorMessage(elem->subdomain_id(), _elem_functor);
258 :
259 7692932 : return it->second(elem_arg, time);
260 : }
261 :
262 : template <typename T>
263 : typename PiecewiseByBlockLambdaFunctor<T>::ValueType
264 395559 : PiecewiseByBlockLambdaFunctor<T>::evaluate(const Moose::FaceArg & face,
265 : const Moose::StateArg & time) const
266 : {
267 : using namespace Moose::FV;
268 :
269 395559 : if (face.face_side)
270 : {
271 151305 : const auto sub_id = face.face_side->subdomain_id();
272 151305 : auto it = _face_functor.find(sub_id);
273 151305 : if (it == _face_functor.end())
274 2 : subdomainErrorMessage(sub_id, _face_functor);
275 :
276 151303 : return it->second(face, time);
277 : }
278 :
279 : mooseAssert(this->isInternalFace(*face.fi),
280 : "If we did not have a face side, then we must be an internal face");
281 244254 : return interpolate(*this, face, time);
282 : }
283 :
284 : template <typename T>
285 : typename PiecewiseByBlockLambdaFunctor<T>::ValueType
286 9077001 : PiecewiseByBlockLambdaFunctor<T>::evaluate(const Moose::ElemQpArg & elem_qp,
287 : const Moose::StateArg & time) const
288 : {
289 9077001 : const auto sub_id = elem_qp.elem->subdomain_id();
290 9077001 : auto it = _elem_qp_functor.find(sub_id);
291 9077001 : if (it == _elem_qp_functor.end())
292 5 : subdomainErrorMessage(sub_id, _elem_qp_functor);
293 :
294 18153992 : return it->second(elem_qp, time);
295 : }
296 :
297 : template <typename T>
298 : typename PiecewiseByBlockLambdaFunctor<T>::ValueType
299 97634 : PiecewiseByBlockLambdaFunctor<T>::evaluate(const Moose::ElemSideQpArg & elem_side_qp,
300 : const Moose::StateArg & time) const
301 : {
302 97634 : const auto sub_id = elem_side_qp.elem->subdomain_id();
303 97634 : auto it = _elem_side_qp_functor.find(sub_id);
304 97634 : if (it == _elem_side_qp_functor.end())
305 2 : subdomainErrorMessage(sub_id, _elem_side_qp_functor);
306 :
307 195264 : return it->second(elem_side_qp, time);
308 : }
309 :
310 : template <typename T>
311 : typename PiecewiseByBlockLambdaFunctor<T>::ValueType
312 4 : PiecewiseByBlockLambdaFunctor<T>::evaluate(const Moose::ElemPointArg & elem_point_arg,
313 : const Moose::StateArg & time) const
314 : {
315 4 : const Elem * const elem = elem_point_arg.elem;
316 : mooseAssert(elem && elem != libMesh::remote_elem,
317 : "The element must be non-null and non-remote in functor material properties");
318 4 : auto it = _elem_point_functor.find(elem->subdomain_id());
319 4 : if (it == _elem_point_functor.end())
320 2 : subdomainErrorMessage(elem->subdomain_id(), _elem_point_functor);
321 :
322 4 : return it->second(elem_point_arg, time);
323 : }
324 :
325 : template <typename T>
326 : typename PiecewiseByBlockLambdaFunctor<T>::ValueType
327 14 : PiecewiseByBlockLambdaFunctor<T>::evaluate(const Moose::NodeArg & node_arg,
328 : const Moose::StateArg & time) const
329 : {
330 : mooseAssert(node_arg.node, "The node must be non-null in functor material properties");
331 14 : if (node_arg.subdomain_ids->size() != 1)
332 0 : mooseError("We do not currently support multi-subdomain evaluation of nodal arguments");
333 14 : const auto sub_id = *(node_arg.subdomain_ids->begin());
334 14 : auto it = _node_functor.find(sub_id);
335 14 : if (it == _node_functor.end())
336 2 : subdomainErrorMessage(sub_id, _node_functor);
337 :
338 24 : return it->second(node_arg, time);
339 : }
340 :
341 : template <typename T>
342 : typename PiecewiseByBlockLambdaFunctor<T>::GradientType
343 320 : PiecewiseByBlockLambdaFunctor<T>::evaluateGradient(const Moose::ElemArg & elem_arg,
344 : const Moose::StateArg & time) const
345 : {
346 320 : return Moose::FV::greenGaussGradient(elem_arg, time, *this, true, _mesh);
347 : }
348 :
349 : template <typename T>
350 : typename PiecewiseByBlockLambdaFunctor<T>::GradientType
351 144 : PiecewiseByBlockLambdaFunctor<T>::evaluateGradient(const Moose::FaceArg & face_arg,
352 : const Moose::StateArg & time) const
353 : {
354 144 : return Moose::FV::greenGaussGradient(face_arg, time, *this, true, _mesh);
355 : }
|