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 : // MOOOSE includes
13 : #include "MooseObject.h"
14 : #include "BlockRestrictable.h"
15 : #include "BoundaryRestrictable.h"
16 : #include "SetupInterface.h"
17 : #include "MooseVariableDependencyInterface.h"
18 : #include "ScalarCoupleable.h"
19 : #include "FunctionInterface.h"
20 : #include "DistributionInterface.h"
21 : #include "UserObjectInterface.h"
22 : #include "TransientInterface.h"
23 : #include "PostprocessorInterface.h"
24 : #include "VectorPostprocessorInterface.h"
25 : #include "DependencyResolverInterface.h"
26 : #include "Restartable.h"
27 : #include "MeshChangedInterface.h"
28 : #include "OutputInterface.h"
29 : #include "RandomInterface.h"
30 : #include "ElementIDInterface.h"
31 : #include "MaterialProperty.h"
32 : #include "MaterialData.h"
33 : #include "MathUtils.h"
34 : #include "Assembly.h"
35 : #include "GeometricSearchInterface.h"
36 : #include "ADFunctorInterface.h"
37 : #include "SolutionInvalidInterface.h"
38 : #include "MaterialPropertyInterface.h"
39 :
40 : #define usingMaterialBaseMembers \
41 : usingMooseObjectMembers; \
42 : usingTransientInterfaceMembers; \
43 : using MaterialBase::_subproblem; \
44 : using MaterialBase::_fe_problem; \
45 : using MaterialBase::_tid; \
46 : using MaterialBase::_assembly; \
47 : using MaterialBase::_qp; \
48 : using MaterialBase::_coord; \
49 : using MaterialBase::_normals; \
50 : using MaterialBase::_mesh
51 :
52 : // forward declarations
53 : class MaterialBase;
54 : class MooseMesh;
55 : class SubProblem;
56 : class FaceInfo;
57 : class FEProblemBase;
58 :
59 : /**
60 : * MaterialBases compute MaterialProperties.
61 : */
62 : class MaterialBase : public MooseObject,
63 : public BlockRestrictable,
64 : public BoundaryRestrictable,
65 : public SetupInterface,
66 : public MooseVariableDependencyInterface,
67 : public ScalarCoupleable,
68 : public FunctionInterface,
69 : public DistributionInterface,
70 : public UserObjectInterface,
71 : public TransientInterface,
72 : public PostprocessorInterface,
73 : public VectorPostprocessorInterface,
74 : public DependencyResolverInterface,
75 : public Restartable,
76 : public MeshChangedInterface,
77 : public OutputInterface,
78 : public RandomInterface,
79 : public ElementIDInterface,
80 : protected GeometricSearchInterface,
81 : protected ADFunctorInterface,
82 : protected SolutionInvalidInterface
83 : {
84 : public:
85 : static InputParameters validParams();
86 :
87 : MaterialBase(const InputParameters & parameters);
88 :
89 : /**
90 : * Initialize stateful properties (if material has some)
91 : *
92 : * This is _only_ called if this material has properties that are
93 : * requested as stateful
94 : */
95 : virtual void initStatefulProperties(unsigned int n_points);
96 :
97 0 : virtual bool isInterfaceMaterial() { return false; };
98 :
99 : /**
100 : * Performs the quadrature point loop, calling computeQpProperties
101 : */
102 : virtual void computeProperties() = 0;
103 :
104 : /**
105 : * Resets the properties at each quadrature point (see resetQpProperties), only called if 'compute
106 : * = false'.
107 : *
108 : * This method is called internally by MOOSE, you probably don't want to mess with this.
109 : */
110 : virtual void resetProperties();
111 :
112 : /**
113 : * A method for (re)computing the properties of a MaterialBase.
114 : *
115 : * This is intended to be called from other objects, by first calling
116 : * MaterialPropertyInterface::getMaterial and then calling this method on the MaterialBase object
117 : * returned.
118 : */
119 : virtual void computePropertiesAtQp(unsigned int qp);
120 :
121 : ///@{
122 : /**
123 : * Declare the property named "name"
124 : */
125 : template <typename T>
126 38356 : MaterialProperty<T> & declarePropertyByName(const std::string & prop_name)
127 : {
128 38356 : return declareGenericPropertyByName<T, false>(prop_name);
129 : }
130 : template <typename T>
131 : MaterialProperty<T> & declareProperty(const std::string & name);
132 : template <typename T>
133 10670 : ADMaterialProperty<T> & declareADPropertyByName(const std::string & prop_name)
134 : {
135 10670 : return declareGenericPropertyByName<T, true>(prop_name);
136 : }
137 : template <typename T>
138 : ADMaterialProperty<T> & declareADProperty(const std::string & name);
139 :
140 : template <typename T, bool is_ad>
141 31466 : auto & declareGenericProperty(const std::string & prop_name)
142 : {
143 : if constexpr (is_ad)
144 9103 : return declareADProperty<T>(prop_name);
145 : else
146 22363 : return declareProperty<T>(prop_name);
147 : }
148 : template <typename T, bool is_ad>
149 : GenericMaterialProperty<T, is_ad> & declareGenericPropertyByName(const std::string & prop_name);
150 : ///@}
151 :
152 : /**
153 : * Return a material property that is initialized to zero by default and does
154 : * not need to (but can) be declared by another material.
155 : */
156 : template <typename T, bool is_ad>
157 : const GenericMaterialProperty<T, is_ad> &
158 : getGenericZeroMaterialProperty(const std::string & name);
159 : template <typename T, bool is_ad>
160 : const GenericMaterialProperty<T, is_ad> &
161 : getGenericZeroMaterialPropertyByName(const std::string & prop_name);
162 :
163 : /**
164 : * Return a constant zero anonymous material property
165 : */
166 : template <typename T, bool is_ad>
167 : const GenericMaterialProperty<T, is_ad> & getGenericZeroMaterialProperty();
168 :
169 : /// for backwards compatibility
170 : template <typename T, typename... Ts>
171 : const MaterialProperty<T> & getZeroMaterialProperty(Ts... args)
172 : {
173 : return getGenericZeroMaterialProperty<T, false>(args...);
174 : }
175 :
176 : /// for backwards compatibility
177 : template <typename T, typename... Ts>
178 : const MaterialProperty<T> & getZeroMaterialPropertyByName(Ts... args)
179 : {
180 : return getGenericZeroMaterialPropertyByName<T, false>(args...);
181 : }
182 :
183 : /**
184 : * Return a set of properties accessed with getMaterialProperty
185 : * @return A reference to the set of properties with calls to getMaterialProperty
186 : */
187 37403 : virtual const std::set<std::string> & getRequestedItems() override { return _requested_props; }
188 :
189 : /**
190 : * Return a set of properties accessed with declareProperty
191 : * @return A reference to the set of properties with calls to declareProperty
192 : */
193 216488 : virtual const std::set<std::string> & getSuppliedItems() override { return _supplied_props; }
194 :
195 : /**
196 : * Get the prop ids corresponding to \p declareProperty
197 : * @return A reference to the set of properties with calls to \p declareProperty
198 : */
199 630802 : const std::set<unsigned int> & getSuppliedPropIDs() { return _supplied_prop_ids; }
200 :
201 : void checkStatefulSanity() const;
202 :
203 : /**
204 : * Get the list of output objects that this class is restricted
205 : * @return A vector of OutputNames
206 : */
207 : std::set<OutputName> getOutputs();
208 :
209 : /**
210 : * Returns true of the MaterialData type is not associated with volume data
211 : */
212 : virtual bool isBoundaryMaterial() const = 0;
213 :
214 : /**
215 : * Subdomain setup evaluating material properties when required
216 : */
217 : virtual void subdomainSetup() override;
218 :
219 : /**
220 : * Retrieve the set of material properties that _this_ object depends on.
221 : *
222 : * @return The IDs corresponding to the material properties that
223 : * MUST be reinited before evaluating this object
224 : */
225 : virtual const std::unordered_set<unsigned int> & getMatPropDependencies() const = 0;
226 :
227 : /**
228 : * @return Whether this material has stateful properties
229 : */
230 636 : bool hasStatefulProperties() const { return _has_stateful_property; }
231 :
232 : /**
233 : * Whether this material supports ghosted computations. This is important for finite volume
234 : * calculations in which variables have defined values on ghost cells/elements and for which these
235 : * ghost values may need to flow through material calculations to be eventually consumed by FV
236 : * flux kernels or boundary conditions
237 : */
238 0 : virtual bool ghostable() const { return false; }
239 :
240 19392 : void setFaceInfo(const FaceInfo & fi) { _face_info = &fi; }
241 :
242 : /**
243 : * Build the materials required by a set of consumer objects
244 : */
245 : template <typename Consumers>
246 : static std::deque<MaterialBase *>
247 : buildRequiredMaterials(const Consumers & mat_consumers,
248 : const std::vector<std::shared_ptr<MaterialBase>> & mats,
249 : const bool allow_stateful);
250 :
251 : /**
252 : * Set active properties of this material
253 : * Note: This function is called by FEProblemBase::setActiveMaterialProperties in an element loop
254 : * typically when switching subdomains.
255 : */
256 : void setActiveProperties(const std::unordered_set<unsigned int> & needed_props);
257 :
258 : /**
259 : * @return Whether or not this material should forcefully call
260 : * initStatefulProperties() even if it doesn't produce properties
261 : * that needs state.
262 : *
263 : * Please don't set this to true :(
264 : */
265 221062 : bool forceStatefulInit() const { return _force_stateful_init; }
266 :
267 : protected:
268 : /**
269 : * Users must override this method.
270 : */
271 : virtual void computeQpProperties();
272 :
273 : /**
274 : * Resets the properties prior to calculation of traditional materials (only if 'compute =
275 : * false').
276 : *
277 : * This method must be overridden in your class. This is called just prior to the re-calculation
278 : * of
279 : * traditional material properties to ensure that the properties are in a proper state for
280 : * calculation.
281 : */
282 : virtual void resetQpProperties();
283 :
284 : /**
285 : * Initialize stateful properties at quadrature points. Note when using this function you only
286 : * need to address
287 : * the "current" material properties not the old ones directly, i.e. if you have a property named
288 : * "_diffusivity"
289 : * and an older property named "_diffusivity_old". You only need to initialize diffusivity.
290 : * MOOSE will use
291 : * copy that initial value to the old and older values as necessary.
292 : *
293 : * This is _only_ called if this material has properties that are
294 : * requested as stateful
295 : */
296 : virtual void initQpStatefulProperties();
297 :
298 : virtual const MaterialData & materialData() const = 0;
299 : virtual MaterialData & materialData() = 0;
300 :
301 0 : virtual const FEProblemBase & miProblem() const { return _fe_problem; }
302 0 : virtual FEProblemBase & miProblem() { return _fe_problem; }
303 :
304 : virtual const QBase & qRule() const = 0;
305 :
306 : /**
307 : * Check whether a material property is active
308 : */
309 5128 : bool isPropertyActive(const unsigned int prop_id) const
310 : {
311 5128 : return _active_prop_ids.count(prop_id) > 0;
312 : }
313 :
314 : SubProblem & _subproblem;
315 :
316 : FEProblemBase & _fe_problem;
317 : THREAD_ID _tid;
318 : Assembly & _assembly;
319 :
320 : unsigned int _qp;
321 :
322 : const MooseArray<Real> & _coord;
323 : /// normals at quadrature points (valid only in boundary materials)
324 : const MooseArray<Point> & _normals;
325 :
326 : MooseMesh & _mesh;
327 :
328 : /// Coordinate system
329 : const Moose::CoordinateSystemType & _coord_sys;
330 :
331 : /// Set of properties accessed via get method
332 : std::set<std::string> _requested_props;
333 :
334 : /// Set of properties declared
335 : std::set<std::string> _supplied_props;
336 :
337 : /// The ids of the supplied properties, i.e. the indices where they
338 : /// are stored in the _material_data->props(). Note: these ids ARE
339 : /// NOT IN THE SAME ORDER AS THE _supplied_props set, which is
340 : /// ordered alphabetically by name. The intention of this container
341 : /// is to allow rapid copying of MaterialProperty values in
342 : /// MaterialBase::computeProperties() without looking up the ids from
343 : /// the name strings each time.
344 : std::set<unsigned int> _supplied_prop_ids;
345 :
346 : /// The ids of the current active supplied properties
347 : std::unordered_set<unsigned int> _active_prop_ids;
348 :
349 : /// If False MOOSE does not compute this property
350 : const bool _compute;
351 :
352 : enum QP_Data_Type
353 : {
354 : CURR,
355 : PREV
356 : };
357 :
358 : /// The minimum states requested (0 = current, 1 = old, 2 = older)
359 : /// This is sparse and is used to keep track of whether or not stateful
360 : /// properties are requested without state 0 being requested
361 : std::unordered_map<unsigned int, unsigned int> _props_to_min_states;
362 :
363 : /// Small helper function to call store{Subdomain,Boundary}MatPropName
364 : void registerPropName(const std::string & prop_name, bool is_get, const unsigned int state);
365 :
366 : /// Check and throw an error if the execution has progressed past the construction stage
367 : void checkExecutionStage();
368 :
369 : std::vector<unsigned int> _displacements;
370 :
371 : bool _has_stateful_property;
372 :
373 : bool _overrides_init_stateful_props = true;
374 :
375 : const FaceInfo * _face_info = nullptr;
376 :
377 : private:
378 : /**
379 : * Helper method for adding a material property name to the material property requested set
380 : */
381 : void markMatPropRequested(const std::string & name);
382 :
383 : /**
384 : * Adds to a map based on block ids of material properties for which a zero
385 : * value can be returned. These properties are optional and will not trigger a
386 : * missing material property error.
387 : *
388 : * @param block_id The block id for the MaterialProperty
389 : * @param name The name of the property
390 : */
391 : void storeSubdomainZeroMatProp(SubdomainID block_id, const MaterialPropertyName & name);
392 :
393 : /**
394 : * Adds to a map based on boundary ids of material properties for which a zero
395 : * value can be returned. These properties are optional and will not trigger a
396 : * missing material property error.
397 : *
398 : * @param boundary_id The block id for the MaterialProperty
399 : * @param name The name of the property
400 : */
401 : void storeBoundaryZeroMatProp(BoundaryID boundary_id, const MaterialPropertyName & name);
402 :
403 : /**
404 : * @return The maximum number of quadrature points in use on any element in this problem.
405 : */
406 : unsigned int getMaxQps() const;
407 :
408 : /// Suffix to append to the name of the material property/ies when declaring it/them
409 : const MaterialPropertyName _declare_suffix;
410 :
411 : /// Whether or not to force stateful init; see forceStatefulInit()
412 : const bool _force_stateful_init;
413 :
414 : /// To let it access the declaration suffix
415 : friend class FunctorMaterial;
416 : };
417 :
418 : template <typename T>
419 : MaterialProperty<T> &
420 38356 : MaterialBase::declareProperty(const std::string & name)
421 : {
422 : // Check if the supplied parameter is a valid input parameter key
423 38356 : std::string prop_name = name;
424 38356 : if (_pars.have_parameter<MaterialPropertyName>(name))
425 594 : prop_name = _pars.get<MaterialPropertyName>(name);
426 :
427 76712 : return declarePropertyByName<T>(prop_name);
428 38356 : }
429 :
430 : template <typename T, bool is_ad>
431 : GenericMaterialProperty<T, is_ad> &
432 58673 : MaterialBase::declareGenericPropertyByName(const std::string & prop_name)
433 : {
434 117541 : const auto prop_name_modified =
435 58673 : _declare_suffix.empty()
436 58673 : ? prop_name
437 59258 : : MooseUtils::join(std::vector<std::string>({prop_name, _declare_suffix}), "_");
438 :
439 : // Call this before so that the ID is valid
440 58673 : auto & prop = materialData().declareProperty<T, is_ad>(prop_name_modified, *this);
441 :
442 58673 : registerPropName(prop_name_modified, false, 0);
443 58673 : return prop;
444 58868 : }
445 :
446 : template <typename T, bool is_ad>
447 : const GenericMaterialProperty<T, is_ad> &
448 4023 : MaterialBase::getGenericZeroMaterialProperty(const std::string & name)
449 : {
450 : // Check if the supplied parameter is a valid input parameter key
451 4023 : std::string prop_name = name;
452 4023 : if (_pars.have_parameter<MaterialPropertyName>(name))
453 0 : prop_name = _pars.get<MaterialPropertyName>(name);
454 :
455 8046 : return getGenericZeroMaterialPropertyByName<T, is_ad>(prop_name);
456 4023 : }
457 :
458 : template <typename T, bool is_ad>
459 : const GenericMaterialProperty<T, is_ad> &
460 8799 : MaterialBase::getGenericZeroMaterialPropertyByName(const std::string & prop_name)
461 : {
462 8799 : checkExecutionStage();
463 8799 : auto & preload_with_zero = materialData().getProperty<T, is_ad>(prop_name, 0, *this);
464 :
465 8799 : _requested_props.insert(prop_name);
466 8799 : registerPropName(prop_name, true, 0);
467 8799 : markMatPropRequested(prop_name);
468 :
469 : // Register this material on these blocks and boundaries as a zero property with relaxed
470 : // consistency checking
471 17598 : for (std::set<SubdomainID>::const_iterator it = blockIDs().begin(); it != blockIDs().end(); ++it)
472 8799 : storeSubdomainZeroMatProp(*it, prop_name);
473 17598 : for (std::set<BoundaryID>::const_iterator it = boundaryIDs().begin(); it != boundaryIDs().end();
474 8799 : ++it)
475 8799 : storeBoundaryZeroMatProp(*it, prop_name);
476 :
477 : // set values for all qpoints to zero
478 : // (in multiapp scenarios getMaxQps can return different values in each app; we need the max)
479 8799 : unsigned int nqp = getMaxQps();
480 8799 : if (nqp > preload_with_zero.size())
481 6933 : preload_with_zero.resize(nqp);
482 48753 : for (unsigned int qp = 0; qp < nqp; ++qp)
483 39954 : MathUtils::mooseSetToZero(preload_with_zero[qp]);
484 :
485 8799 : return preload_with_zero;
486 : }
487 :
488 : template <typename T, bool is_ad>
489 : const GenericMaterialProperty<T, is_ad> &
490 576 : MaterialBase::getGenericZeroMaterialProperty()
491 : {
492 : // static zero property storage
493 576 : static GenericMaterialProperty<T, is_ad> zero(MaterialPropertyInterface::zero_property_id);
494 :
495 : // resize to accomodate maximum number of qpoints
496 : // (in multiapp scenarios getMaxQps can return different values in each app; we need the max)
497 576 : unsigned int nqp = getMaxQps();
498 576 : if (nqp > zero.size())
499 28 : zero.resize(nqp);
500 :
501 : // set values for all qpoints to zero
502 2880 : for (unsigned int qp = 0; qp < nqp; ++qp)
503 2304 : MathUtils::mooseSetToZero(zero[qp]);
504 :
505 576 : return zero;
506 : }
507 :
508 : template <typename T>
509 : ADMaterialProperty<T> &
510 10670 : MaterialBase::declareADProperty(const std::string & name)
511 : {
512 : // Check if the supplied parameter is a valid input parameter key
513 10670 : std::string prop_name = name;
514 10670 : if (_pars.have_parameter<MaterialPropertyName>(name))
515 403 : prop_name = _pars.get<MaterialPropertyName>(name);
516 :
517 21340 : return declareADPropertyByName<T>(prop_name);
518 10670 : }
519 :
520 : template <typename Consumers>
521 : std::deque<MaterialBase *>
522 3164 : MaterialBase::buildRequiredMaterials(const Consumers & mat_consumers,
523 : const std::vector<std::shared_ptr<MaterialBase>> & mats,
524 : const bool allow_stateful)
525 : {
526 3164 : std::deque<MaterialBase *> required_mats;
527 :
528 3164 : std::unordered_set<unsigned int> needed_mat_props;
529 6808 : for (const auto & consumer : mat_consumers)
530 : {
531 3644 : const auto & mp_deps = consumer->getMatPropDependencies();
532 3644 : needed_mat_props.insert(mp_deps.begin(), mp_deps.end());
533 : }
534 :
535 : // A predicate of calling this function is that these materials come in already sorted by
536 : // dependency with the front of the container having no other material dependencies and following
537 : // materials potentially depending on the ones in front of them. So we can start at the back and
538 : // iterate forward checking whether the current material supplies anything that is needed, and if
539 : // not we discard it
540 16380 : for (auto it = mats.rbegin(); it != mats.rend(); ++it)
541 : {
542 13216 : auto * const mat = it->get();
543 13216 : bool supplies_needed = false;
544 :
545 13216 : const auto & supplied_props = mat->getSuppliedPropIDs();
546 :
547 : // Do O(N) with the small container
548 40598 : for (const auto supplied_prop : supplied_props)
549 : {
550 30142 : if (needed_mat_props.count(supplied_prop))
551 : {
552 2760 : supplies_needed = true;
553 2760 : break;
554 : }
555 : }
556 :
557 13216 : if (!supplies_needed)
558 10456 : continue;
559 :
560 2760 : if (!allow_stateful && mat->hasStatefulProperties())
561 0 : ::mooseError(
562 : "Someone called buildRequiredMaterials with allow_stateful = false but a material "
563 : "dependency ",
564 0 : mat->name(),
565 : " computes stateful properties.");
566 :
567 2760 : const auto & mp_deps = mat->getMatPropDependencies();
568 2760 : needed_mat_props.insert(mp_deps.begin(), mp_deps.end());
569 2760 : required_mats.push_front(mat);
570 : }
571 :
572 6328 : return required_mats;
573 3164 : }
|