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