forked from idaholab/moose
/
PiecewiseByBlockLambdaFunctor.h
327 lines (280 loc) · 12.7 KB
/
PiecewiseByBlockLambdaFunctor.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
//* This file is part of the MOOSE framework
//* https://www.mooseframework.org
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html
#pragma once
#include "MooseMesh.h"
#include "MooseTypes.h"
#include "MooseError.h"
#include "MooseFunctor.h"
#include "Moose.h"
#include "Limiter.h"
#include "MathFVUtils.h"
#include "GreenGaussGradient.h"
#include "libmesh/elem.h"
#include "libmesh/remote_elem.h"
#include "libmesh/tensor_tools.h"
#include <unordered_map>
#include <functional>
/**
* A material property that is evaluated on-the-fly via calls to various overloads of \p operator()
*/
template <typename T>
class PiecewiseByBlockLambdaFunctor : public Moose::FunctorBase<T>
{
public:
template <typename PolymorphicLambda>
PiecewiseByBlockLambdaFunctor(const std::string & name,
PolymorphicLambda my_lammy,
const std::set<ExecFlagType> & clearance_schedule,
const MooseMesh & mesh,
const std::set<SubdomainID> & block_ids);
/**
* Set the functor that will be used in calls to \p evaluate overloads
* @param mesh The mesh that the functor is defined on
* @param block_ids The block/subdomain IDs that the user-provided functor is valid for
* @param my_lammy The functor that defines how this object is evaluated
*/
template <typename PolymorphicLambda>
void setFunctor(const MooseMesh & mesh,
const std::set<SubdomainID> & block_ids,
PolymorphicLambda my_lammy);
virtual ~PiecewiseByBlockLambdaFunctor() = default;
bool isExtrapolatedBoundaryFace(const FaceInfo & fi,
const Elem * elem,
const Moose::StateArg & time) const override;
bool hasBlocks(SubdomainID id) const override;
using typename Moose::FunctorBase<T>::FunctorType;
using typename Moose::FunctorBase<T>::ValueType;
using typename Moose::FunctorBase<T>::DotType;
using typename Moose::FunctorBase<T>::GradientType;
using typename Moose::FunctorBase<T>::FunctorReturnType;
protected:
using ElemFn = std::function<T(const Moose::ElemArg &, const Moose::StateArg &)>;
using FaceFn = std::function<T(const Moose::FaceArg &, const Moose::StateArg &)>;
using ElemQpFn = std::function<T(const Moose::ElemQpArg &, const Moose::StateArg &)>;
using ElemSideQpFn = std::function<T(const Moose::ElemSideQpArg &, const Moose::StateArg &)>;
using ElemPointFn = std::function<T(const Moose::ElemPointArg &, const Moose::StateArg &)>;
using NodeFn = std::function<T(const Moose::NodeArg &, const Moose::StateArg &)>;
ValueType evaluate(const Moose::ElemArg & elem_arg, const Moose::StateArg & time) const override;
ValueType evaluate(const Moose::FaceArg & face, const Moose::StateArg & time) const override;
ValueType evaluate(const Moose::ElemQpArg & elem_qp, const Moose::StateArg & time) const override;
ValueType evaluate(const Moose::ElemSideQpArg & elem_side_qp,
const Moose::StateArg & time) const override;
ValueType evaluate(const Moose::ElemPointArg & elem_point,
const Moose::StateArg & time) const override;
ValueType evaluate(const Moose::NodeArg & node_arg, const Moose::StateArg & time) const override;
using Moose::FunctorBase<T>::evaluateGradient;
GradientType evaluateGradient(const Moose::ElemArg & elem_arg,
const Moose::StateArg &) const override;
GradientType evaluateGradient(const Moose::FaceArg & face_arg,
const Moose::StateArg &) const override;
GradientType evaluateGradient(const Moose::NodeArg & node_arg,
const Moose::StateArg &) const override;
private:
/**
* Provide a useful error message about lack of functor material property on the provided
* subdomain \p sub_id
*/
void subdomainErrorMessage(SubdomainID sub_id) const;
/// Functors that return element average values (or cell centroid values or whatever the
/// implementer wants to return for a given element argument)
std::unordered_map<SubdomainID, ElemFn> _elem_functor;
/// Functors that return the property value on the requested side of the face (e.g. the
/// infinitesimal + or - side of the face)
std::unordered_map<SubdomainID, FaceFn> _face_functor;
/// Functors that will evaluate elements at quadrature points
std::unordered_map<SubdomainID, ElemQpFn> _elem_qp_functor;
/// Functors that will evaluate elements at side quadrature points
std::unordered_map<SubdomainID, ElemSideQpFn> _elem_side_qp_functor;
/// Functors that return evaluations at an arbitrary physical point in an element
std::unordered_map<SubdomainID, ElemPointFn> _elem_point_functor;
/// Functors that return element average values (or cell centroid values or whatever the
/// implementer wants to return for a given element argument)
std::unordered_map<SubdomainID, NodeFn> _node_functor;
/// The mesh that this functor operates on
const MooseMesh & _mesh;
};
template <typename T>
template <typename PolymorphicLambda>
PiecewiseByBlockLambdaFunctor<T>::PiecewiseByBlockLambdaFunctor(
const std::string & name,
PolymorphicLambda my_lammy,
const std::set<ExecFlagType> & clearance_schedule,
const MooseMesh & mesh,
const std::set<SubdomainID> & block_ids)
: Moose::FunctorBase<T>(name, clearance_schedule), _mesh(mesh)
{
setFunctor(mesh, block_ids, my_lammy);
}
template <typename T>
template <typename PolymorphicLambda>
void
PiecewiseByBlockLambdaFunctor<T>::setFunctor(const MooseMesh & libmesh_dbg_var(mesh),
const std::set<SubdomainID> & block_ids,
PolymorphicLambda my_lammy)
{
mooseAssert(&mesh == &_mesh,
"We should always be setting this functor with the same mesh. We may relax this "
"assertion later");
auto add_lammy = [this, my_lammy](const SubdomainID block_id)
{
auto pr = _elem_functor.emplace(block_id, my_lammy);
if (!pr.second)
mooseError("No insertion for the functor material property '",
this->functorName(),
"' for block id ",
block_id,
". Another material must already declare this property on that block.");
_face_functor.emplace(block_id, my_lammy);
_elem_qp_functor.emplace(block_id, my_lammy);
_elem_side_qp_functor.emplace(block_id, my_lammy);
_elem_point_functor.emplace(block_id, my_lammy);
};
for (const auto block_id : block_ids)
add_lammy(block_id);
}
template <typename T>
bool
PiecewiseByBlockLambdaFunctor<T>::isExtrapolatedBoundaryFace(const FaceInfo & fi,
const Elem *,
const Moose::StateArg &) const
{
if (!fi.neighborPtr())
return true;
const bool defined_on_elem = _elem_functor.count(fi.elem().subdomain_id());
const bool defined_on_neighbor = _elem_functor.count(fi.neighbor().subdomain_id());
const bool extrapolated = (defined_on_elem + defined_on_neighbor) == 1;
mooseAssert(defined_on_elem || defined_on_neighbor,
"This shouldn't be called if we aren't defined on either side.");
return extrapolated;
}
template <typename T>
bool
PiecewiseByBlockLambdaFunctor<T>::hasBlocks(const SubdomainID id) const
{
// If any of the maps has a functor for that block, it has the block
const bool has_blocks = _elem_functor.count(id);
mooseAssert(has_blocks == _face_functor.count(id),
"All functor sets should agree on whether we have this sub id");
mooseAssert(has_blocks == _elem_qp_functor.count(id),
"All functor sets should agree on whether we have this sub id");
mooseAssert(has_blocks == _elem_side_qp_functor.count(id),
"All functor sets should agree on whether we have this sub id");
return has_blocks;
}
template <typename T>
void
PiecewiseByBlockLambdaFunctor<T>::subdomainErrorMessage(const SubdomainID sub_id) const
{
mooseError("The provided subdomain ID ",
std::to_string(sub_id),
" doesn't exist in the map for lambda functor '",
this->functorName(),
"'! This is likely because you did not provide a functor material "
"definition on that subdomain");
}
template <typename T>
typename PiecewiseByBlockLambdaFunctor<T>::ValueType
PiecewiseByBlockLambdaFunctor<T>::evaluate(const Moose::ElemArg & elem_arg,
const Moose::StateArg & time) const
{
const Elem * const elem = elem_arg.elem;
mooseAssert(elem && elem != libMesh::remote_elem,
"The element must be non-null and non-remote in functor material properties");
auto it = _elem_functor.find(elem->subdomain_id());
if (it == _elem_functor.end())
subdomainErrorMessage(elem->subdomain_id());
return it->second(elem_arg, time);
}
template <typename T>
typename PiecewiseByBlockLambdaFunctor<T>::ValueType
PiecewiseByBlockLambdaFunctor<T>::evaluate(const Moose::FaceArg & face,
const Moose::StateArg & time) const
{
using namespace Moose::FV;
if (face.face_side)
{
const auto sub_id = face.face_side->subdomain_id();
auto it = _face_functor.find(sub_id);
if (it == _face_functor.end())
subdomainErrorMessage(sub_id);
return it->second(face, time);
}
mooseAssert(this->isInternalFace(*face.fi),
"If we did not have a face side, then we must be an internal face");
return interpolate(*this, face, time);
}
template <typename T>
typename PiecewiseByBlockLambdaFunctor<T>::ValueType
PiecewiseByBlockLambdaFunctor<T>::evaluate(const Moose::ElemQpArg & elem_qp,
const Moose::StateArg & time) const
{
const auto sub_id = elem_qp.elem->subdomain_id();
auto it = _elem_qp_functor.find(sub_id);
if (it == _elem_qp_functor.end())
subdomainErrorMessage(sub_id);
return it->second(elem_qp, time);
}
template <typename T>
typename PiecewiseByBlockLambdaFunctor<T>::ValueType
PiecewiseByBlockLambdaFunctor<T>::evaluate(const Moose::ElemSideQpArg & elem_side_qp,
const Moose::StateArg & time) const
{
const auto sub_id = elem_side_qp.elem->subdomain_id();
auto it = _elem_side_qp_functor.find(sub_id);
if (it == _elem_side_qp_functor.end())
subdomainErrorMessage(sub_id);
return it->second(elem_side_qp, time);
}
template <typename T>
typename PiecewiseByBlockLambdaFunctor<T>::ValueType
PiecewiseByBlockLambdaFunctor<T>::evaluate(const Moose::ElemPointArg & elem_point_arg,
const Moose::StateArg & time) const
{
const Elem * const elem = elem_point_arg.elem;
mooseAssert(elem && elem != libMesh::remote_elem,
"The element must be non-null and non-remote in functor material properties");
auto it = _elem_point_functor.find(elem->subdomain_id());
if (it == _elem_point_functor.end())
subdomainErrorMessage(elem->subdomain_id());
return it->second(elem_point_arg, time);
}
template <typename T>
typename PiecewiseByBlockLambdaFunctor<T>::ValueType
PiecewiseByBlockLambdaFunctor<T>::evaluate(const Moose::NodeArg & node_arg,
const Moose::StateArg & time) const
{
const Node * const node = node_arg.node;
mooseAssert(node && node != libMesh::remote_node,
"The element must be non-null and non-remote in functor material properties");
auto it = _node_functor.find(node->subdomain_id());
if (it == _node_functor.end())
subdomainErrorMessage(node->subdomain_id());
return it->second(node_arg, time);
}
template <typename T>
typename PiecewiseByBlockLambdaFunctor<T>::GradientType
PiecewiseByBlockLambdaFunctor<T>::evaluateGradient(const Moose::ElemArg & elem_arg,
const Moose::StateArg & time) const
{
return Moose::FV::greenGaussGradient(elem_arg, time, *this, true, _mesh);
}
template <typename T>
typename PiecewiseByBlockLambdaFunctor<T>::GradientType
PiecewiseByBlockLambdaFunctor<T>::evaluateGradient(const Moose::FaceArg & face_arg,
const Moose::StateArg & time) const
{
return Moose::FV::greenGaussGradient(face_arg, time, *this, true, _mesh);
}
template <typename T>
typename PiecewiseByBlockLambdaFunctor<T>::GradientType
PiecewiseByBlockLambdaFunctor<T>::evaluateGradient(const Moose::NodeArg & node_arg,
const Moose::StateArg & time) const
{
return Moose::FV::greenGaussGradient(node_arg, time, *this, true, _mesh);
}