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 16153 : 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 : /// Functors that return element average values (or cell centroid values or whatever the
104 : /// implementer wants to return for a given element argument)
105 : std::unordered_map<SubdomainID, ElemFn> _elem_functor;
106 :
107 : /// Functors that return the property value on the requested side of the face (e.g. the
108 : /// infinitesimal + or - side of the face)
109 : std::unordered_map<SubdomainID, FaceFn> _face_functor;
110 :
111 : /// Functors that will evaluate elements at quadrature points
112 : std::unordered_map<SubdomainID, ElemQpFn> _elem_qp_functor;
113 :
114 : /// Functors that will evaluate elements at side quadrature points
115 : std::unordered_map<SubdomainID, ElemSideQpFn> _elem_side_qp_functor;
116 :
117 : /// Functors that return evaluations at an arbitrary physical point in an element
118 : std::unordered_map<SubdomainID, ElemPointFn> _elem_point_functor;
119 :
120 : /// Functors that return nodal values
121 : std::unordered_map<SubdomainID, NodeFn> _node_functor;
122 :
123 : /// The mesh that this functor operates on
124 : const MooseMesh & _mesh;
125 : };
126 :
127 : template <typename T>
128 : template <typename PolymorphicLambda>
129 8437 : PiecewiseByBlockLambdaFunctor<T>::PiecewiseByBlockLambdaFunctor(
130 : const std::string & name,
131 : PolymorphicLambda my_lammy,
132 : const std::set<ExecFlagType> & clearance_schedule,
133 : const MooseMesh & mesh,
134 : const std::set<SubdomainID> & block_ids)
135 8437 : : Moose::FunctorBase<T>(name, clearance_schedule), _mesh(mesh)
136 : {
137 8437 : setFunctor(mesh, block_ids, my_lammy);
138 8437 : }
139 :
140 : template <typename T>
141 : template <typename PolymorphicLambda>
142 : void
143 9426 : PiecewiseByBlockLambdaFunctor<T>::setFunctor(const MooseMesh & mesh,
144 : const std::set<SubdomainID> & block_ids,
145 : PolymorphicLambda my_lammy)
146 : {
147 : mooseAssert(&mesh == &_mesh,
148 : "We should always be setting this functor with the same mesh. We may relax this "
149 : "assertion later");
150 :
151 40415 : auto add_lammy = [this, my_lammy](const SubdomainID block_id)
152 : {
153 30993 : auto pr = _elem_functor.emplace(block_id, my_lammy);
154 30993 : if (!pr.second)
155 4 : mooseError("No insertion for the functor material property '",
156 : this->functorName(),
157 : "' for block id ",
158 : block_id,
159 : ". Another material must already declare this property on that block.");
160 30989 : _face_functor.emplace(block_id, my_lammy);
161 30989 : _elem_qp_functor.emplace(block_id, my_lammy);
162 30989 : _elem_side_qp_functor.emplace(block_id, my_lammy);
163 30989 : _elem_point_functor.emplace(block_id, my_lammy);
164 30989 : _node_functor.emplace(block_id, my_lammy);
165 : };
166 :
167 35179 : for (const auto block_id : block_ids)
168 25757 : add_lammy(block_id);
169 :
170 : // Handle special case of ANY_BLOCK_ID and empty block restriction that also cover
171 : // INVALID_BLOCK_ID
172 18843 : if (block_ids.count(Moose::ANY_BLOCK_ID) || block_ids.empty() ||
173 9421 : block_ids == mesh.meshSubdomains())
174 5236 : add_lammy(Moose::INVALID_BLOCK_ID);
175 9422 : }
176 :
177 : template <typename T>
178 : bool
179 844 : PiecewiseByBlockLambdaFunctor<T>::isExtrapolatedBoundaryFace(const FaceInfo & fi,
180 : const Elem *,
181 : const Moose::StateArg &) const
182 : {
183 844 : if (!fi.neighborPtr())
184 424 : return true;
185 :
186 420 : const bool defined_on_elem = _elem_functor.count(fi.elem().subdomain_id());
187 420 : const bool defined_on_neighbor = _elem_functor.count(fi.neighbor().subdomain_id());
188 420 : const bool extrapolated = (defined_on_elem + defined_on_neighbor) == 1;
189 :
190 : mooseAssert(defined_on_elem || defined_on_neighbor,
191 : "This shouldn't be called if we aren't defined on either side.");
192 420 : return extrapolated;
193 : }
194 :
195 : template <typename T>
196 : bool
197 21144 : PiecewiseByBlockLambdaFunctor<T>::hasBlocks(const SubdomainID id) const
198 : {
199 : // If any of the maps has a functor for that block, it has the block
200 21144 : const bool has_blocks = _elem_functor.count(id);
201 : mooseAssert(has_blocks == _face_functor.count(id),
202 : "All functor sets should agree on whether we have this sub id");
203 : mooseAssert(has_blocks == _elem_qp_functor.count(id),
204 : "All functor sets should agree on whether we have this sub id");
205 : mooseAssert(has_blocks == _elem_side_qp_functor.count(id),
206 : "All functor sets should agree on whether we have this sub id");
207 21144 : return has_blocks;
208 : }
209 :
210 : template <typename T>
211 : template <typename C>
212 : void
213 6 : PiecewiseByBlockLambdaFunctor<T>::subdomainErrorMessage(
214 : const SubdomainID sub_id, const std::unordered_map<SubdomainID, C> & functors) const
215 : {
216 6 : std::vector<SubdomainID> block_ids;
217 6 : block_ids.reserve(functors.size());
218 12 : for (const auto & [available_sub_id, functor] : functors)
219 : {
220 6 : libmesh_ignore(functor);
221 6 : block_ids.push_back(available_sub_id);
222 : }
223 42 : mooseError("The provided subdomain ID ",
224 : std::to_string(sub_id),
225 : " doesn't exist in the map for lambda functor '",
226 : this->functorName(),
227 : "'! This is likely because you did not provide a functor material "
228 : "definition on that subdomain.\nSubdomain IDs in the map: ",
229 : Moose::stringify(block_ids));
230 6 : }
231 :
232 : template <typename T>
233 : typename PiecewiseByBlockLambdaFunctor<T>::ValueType
234 5164917 : PiecewiseByBlockLambdaFunctor<T>::evaluate(const Moose::ElemArg & elem_arg,
235 : const Moose::StateArg & time) const
236 : {
237 5164917 : const Elem * const elem = elem_arg.elem;
238 : mooseAssert(elem && elem != libMesh::remote_elem,
239 : "The element must be non-null and non-remote in functor material properties");
240 5164917 : auto it = _elem_functor.find(elem->subdomain_id());
241 5164917 : if (it == _elem_functor.end())
242 1 : subdomainErrorMessage(elem->subdomain_id(), _elem_functor);
243 :
244 10329832 : return it->second(elem_arg, time);
245 : }
246 :
247 : template <typename T>
248 : typename PiecewiseByBlockLambdaFunctor<T>::ValueType
249 645604 : PiecewiseByBlockLambdaFunctor<T>::evaluate(const Moose::FaceArg & face,
250 : const Moose::StateArg & time) const
251 : {
252 : using namespace Moose::FV;
253 :
254 645604 : if (face.face_side)
255 : {
256 193577 : const auto sub_id = face.face_side->subdomain_id();
257 193577 : auto it = _face_functor.find(sub_id);
258 193577 : if (it == _face_functor.end())
259 1 : subdomainErrorMessage(sub_id, _face_functor);
260 :
261 193576 : return it->second(face, time);
262 : }
263 :
264 : mooseAssert(this->isInternalFace(*face.fi),
265 : "If we did not have a face side, then we must be an internal face");
266 452027 : return interpolate(*this, face, time);
267 : }
268 :
269 : template <typename T>
270 : typename PiecewiseByBlockLambdaFunctor<T>::ValueType
271 7702587 : PiecewiseByBlockLambdaFunctor<T>::evaluate(const Moose::ElemQpArg & elem_qp,
272 : const Moose::StateArg & time) const
273 : {
274 7702587 : const auto sub_id = elem_qp.elem->subdomain_id();
275 7702587 : auto it = _elem_qp_functor.find(sub_id);
276 7702587 : if (it == _elem_qp_functor.end())
277 1 : subdomainErrorMessage(sub_id, _elem_qp_functor);
278 :
279 15405172 : return it->second(elem_qp, time);
280 : }
281 :
282 : template <typename T>
283 : typename PiecewiseByBlockLambdaFunctor<T>::ValueType
284 89873 : PiecewiseByBlockLambdaFunctor<T>::evaluate(const Moose::ElemSideQpArg & elem_side_qp,
285 : const Moose::StateArg & time) const
286 : {
287 89873 : const auto sub_id = elem_side_qp.elem->subdomain_id();
288 89873 : auto it = _elem_side_qp_functor.find(sub_id);
289 89873 : if (it == _elem_side_qp_functor.end())
290 1 : subdomainErrorMessage(sub_id, _elem_side_qp_functor);
291 :
292 179744 : return it->second(elem_side_qp, time);
293 : }
294 :
295 : template <typename T>
296 : typename PiecewiseByBlockLambdaFunctor<T>::ValueType
297 2 : PiecewiseByBlockLambdaFunctor<T>::evaluate(const Moose::ElemPointArg & elem_point_arg,
298 : const Moose::StateArg & time) const
299 : {
300 2 : const Elem * const elem = elem_point_arg.elem;
301 : mooseAssert(elem && elem != libMesh::remote_elem,
302 : "The element must be non-null and non-remote in functor material properties");
303 2 : auto it = _elem_point_functor.find(elem->subdomain_id());
304 2 : if (it == _elem_point_functor.end())
305 1 : subdomainErrorMessage(elem->subdomain_id(), _elem_point_functor);
306 :
307 2 : return it->second(elem_point_arg, time);
308 : }
309 :
310 : template <typename T>
311 : typename PiecewiseByBlockLambdaFunctor<T>::ValueType
312 15 : PiecewiseByBlockLambdaFunctor<T>::evaluate(const Moose::NodeArg & node_arg,
313 : const Moose::StateArg & time) const
314 : {
315 : mooseAssert(node_arg.node, "The node must be non-null in functor material properties");
316 15 : if (node_arg.subdomain_ids->size() != 1)
317 0 : mooseError("We do not currently support multi-subdomain evaluation of nodal arguments");
318 15 : const auto sub_id = *(node_arg.subdomain_ids->begin());
319 15 : auto it = _node_functor.find(sub_id);
320 15 : if (it == _node_functor.end())
321 1 : subdomainErrorMessage(sub_id, _node_functor);
322 :
323 28 : return it->second(node_arg, time);
324 : }
325 :
326 : template <typename T>
327 : typename PiecewiseByBlockLambdaFunctor<T>::GradientType
328 160 : PiecewiseByBlockLambdaFunctor<T>::evaluateGradient(const Moose::ElemArg & elem_arg,
329 : const Moose::StateArg & time) const
330 : {
331 160 : return Moose::FV::greenGaussGradient(elem_arg, time, *this, true, _mesh);
332 : }
333 :
334 : template <typename T>
335 : typename PiecewiseByBlockLambdaFunctor<T>::GradientType
336 72 : PiecewiseByBlockLambdaFunctor<T>::evaluateGradient(const Moose::FaceArg & face_arg,
337 : const Moose::StateArg & time) const
338 : {
339 72 : return Moose::FV::greenGaussGradient(face_arg, time, *this, true, _mesh);
340 : }
|