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