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 39457 : MaterialProperty<T> & declarePropertyByName(const std::string & prop_name)
133 : {
134 39457 : return declareGenericPropertyByName<T, false>(prop_name);
135 : }
136 : template <typename T>
137 : MaterialProperty<T> & declareProperty(const std::string & name);
138 : template <typename T>
139 11257 : ADMaterialProperty<T> & declareADPropertyByName(const std::string & prop_name)
140 : {
141 11257 : 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 33731 : auto & declareGenericProperty(const std::string & prop_name)
148 : {
149 : if constexpr (is_ad)
150 9577 : return declareADProperty<T>(prop_name);
151 : else
152 24154 : 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 24552 : 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 226893 : 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 167266 : const std::set<unsigned int> & getSuppliedPropIDs() const { 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 654 : 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 19392 : 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 : * Whether this material has active properties
270 : */
271 113804 : bool hasActiveProperties() { return _active_prop_ids.size() > 0; }
272 :
273 : /**
274 : * @return Whether or not this material should forcefully call
275 : * initStatefulProperties() even if it doesn't produce properties
276 : * that needs state.
277 : *
278 : * Please don't set this to true :(
279 : */
280 32822 : bool forceStatefulInit() const { return _force_stateful_init; }
281 :
282 : protected:
283 : /**
284 : * Users must override this method.
285 : */
286 : virtual void computeQpProperties();
287 :
288 : /**
289 : * Resets the properties prior to calculation of traditional materials (only if 'compute =
290 : * false').
291 : *
292 : * This method must be overridden in your class. This is called just prior to the re-calculation
293 : * of
294 : * traditional material properties to ensure that the properties are in a proper state for
295 : * calculation.
296 : */
297 : virtual void resetQpProperties();
298 :
299 : /**
300 : * Initialize stateful properties at quadrature points. Note when using this function you only
301 : * need to address
302 : * the "current" material properties not the old ones directly, i.e. if you have a property named
303 : * "_diffusivity"
304 : * and an older property named "_diffusivity_old". You only need to initialize diffusivity.
305 : * MOOSE will use
306 : * copy that initial value to the old and older values as necessary.
307 : *
308 : * This is _only_ called if this material has properties that are
309 : * requested as stateful
310 : */
311 : virtual void initQpStatefulProperties();
312 :
313 : virtual const MaterialData & materialData() const = 0;
314 : virtual MaterialData & materialData() = 0;
315 : virtual Moose::MaterialDataType materialDataType() = 0;
316 :
317 0 : virtual const FEProblemBase & miProblem() const { return _fe_problem; }
318 0 : virtual FEProblemBase & miProblem() { return _fe_problem; }
319 :
320 : virtual const QBase & qRule() const = 0;
321 :
322 : /**
323 : * Check whether a material property is active
324 : */
325 5128 : bool isPropertyActive(const unsigned int prop_id) const
326 : {
327 5128 : return _active_prop_ids.count(prop_id) > 0;
328 : }
329 :
330 : SubProblem & _subproblem;
331 :
332 : FEProblemBase & _fe_problem;
333 : THREAD_ID _tid;
334 : Assembly & _assembly;
335 :
336 : unsigned int _qp;
337 :
338 : const MooseArray<Real> & _coord;
339 : /// normals at quadrature points (valid only in boundary materials)
340 : const MooseArray<Point> & _normals;
341 :
342 : MooseMesh & _mesh;
343 :
344 : /// Coordinate system
345 : const Moose::CoordinateSystemType & _coord_sys;
346 :
347 : /// Set of properties accessed via get method
348 : std::set<std::string> _requested_props;
349 :
350 : /// Set of properties declared
351 : std::set<std::string> _supplied_props;
352 :
353 : /// The ids of the supplied properties, i.e. the indices where they
354 : /// are stored in the _material_data->props(). Note: these ids ARE
355 : /// NOT IN THE SAME ORDER AS THE _supplied_props set, which is
356 : /// ordered alphabetically by name. The intention of this container
357 : /// is to allow rapid copying of MaterialProperty values in
358 : /// MaterialBase::computeProperties() without looking up the ids from
359 : /// the name strings each time.
360 : std::set<unsigned int> _supplied_prop_ids;
361 :
362 : /// The ids of the current active supplied properties
363 : std::unordered_set<unsigned int> _active_prop_ids;
364 :
365 : /// If False MOOSE does not compute this property
366 : const bool _compute;
367 :
368 : enum QP_Data_Type
369 : {
370 : CURR,
371 : PREV
372 : };
373 :
374 : /// The minimum states requested (0 = current, 1 = old, 2 = older)
375 : /// This is sparse and is used to keep track of whether or not stateful
376 : /// properties are requested without state 0 being requested
377 : std::unordered_map<unsigned int, unsigned int> _props_to_min_states;
378 :
379 : /// Small helper function to call store{Subdomain,Boundary}MatPropName
380 : void registerPropName(const std::string & prop_name, bool is_get, const unsigned int state);
381 :
382 : /// Check and throw an error if the execution has progressed past the construction stage
383 : void checkExecutionStage();
384 :
385 : std::vector<unsigned int> _displacements;
386 :
387 : bool _has_stateful_property;
388 :
389 : bool _overrides_init_stateful_props = true;
390 :
391 : const FaceInfo * _face_info = nullptr;
392 :
393 : /// Suffix to append to the name of the material property/ies when declaring it/them
394 : const MaterialPropertyName _declare_suffix;
395 :
396 : private:
397 : /**
398 : * Helper method for adding a material property name to the material property requested set
399 : */
400 : void markMatPropRequested(const std::string & name);
401 :
402 : /**
403 : * Adds to a map based on block ids of material properties for which a zero
404 : * value can be returned. These properties are optional and will not trigger a
405 : * missing material property error.
406 : *
407 : * @param block_id The block id for the MaterialProperty
408 : * @param name The name of the property
409 : */
410 : void storeSubdomainZeroMatProp(SubdomainID block_id, const MaterialPropertyName & name);
411 :
412 : /**
413 : * Adds to a map based on boundary ids of material properties for which a zero
414 : * value can be returned. These properties are optional and will not trigger a
415 : * missing material property error.
416 : *
417 : * @param boundary_id The block id for the MaterialProperty
418 : * @param name The name of the property
419 : */
420 : void storeBoundaryZeroMatProp(BoundaryID boundary_id, const MaterialPropertyName & name);
421 :
422 : /**
423 : * @return The maximum number of quadrature points in use on any element in this problem.
424 : */
425 : unsigned int getMaxQps() const;
426 :
427 : /// Whether or not to force stateful init; see forceStatefulInit()
428 : const bool _force_stateful_init;
429 :
430 : /// To let it access the declaration suffix
431 : friend class FunctorMaterial;
432 : };
433 :
434 : template <typename T>
435 : MaterialProperty<T> &
436 39457 : MaterialBase::declareProperty(const std::string & name)
437 : {
438 : // Check if the supplied parameter is a valid input parameter key
439 39457 : std::string prop_name = name;
440 39457 : if (_pars.have_parameter<MaterialPropertyName>(name))
441 693 : prop_name = _pars.get<MaterialPropertyName>(name);
442 :
443 78914 : return declarePropertyByName<T>(prop_name);
444 39457 : }
445 :
446 : template <typename T, bool is_ad>
447 : GenericMaterialProperty<T, is_ad> &
448 60396 : MaterialBase::declareGenericPropertyByName(const std::string & prop_name)
449 : {
450 120987 : const auto prop_name_modified =
451 60396 : _declare_suffix.empty()
452 60396 : ? prop_name
453 60981 : : MooseUtils::join(std::vector<std::string>({prop_name, _declare_suffix}), "_");
454 :
455 : // Call this before so that the ID is valid
456 60396 : auto & prop = materialData().declareProperty<T, is_ad>(prop_name_modified, *this);
457 :
458 60396 : registerPropName(prop_name_modified, false, 0);
459 60396 : return prop;
460 60591 : }
461 :
462 : template <typename T, bool is_ad>
463 : const GenericMaterialProperty<T, is_ad> &
464 4023 : MaterialBase::getGenericZeroMaterialProperty(const std::string & name)
465 : {
466 : // Check if the supplied parameter is a valid input parameter key
467 4023 : std::string prop_name = name;
468 4023 : if (_pars.have_parameter<MaterialPropertyName>(name))
469 0 : prop_name = _pars.get<MaterialPropertyName>(name);
470 :
471 8046 : return getGenericZeroMaterialPropertyByName<T, is_ad>(prop_name);
472 4023 : }
473 :
474 : template <typename T, bool is_ad>
475 : const GenericMaterialProperty<T, is_ad> &
476 8727 : MaterialBase::getGenericZeroMaterialPropertyByName(const std::string & prop_name)
477 : {
478 8727 : checkExecutionStage();
479 8727 : auto & preload_with_zero = materialData().getProperty<T, is_ad>(prop_name, 0, *this);
480 :
481 8727 : _requested_props.insert(prop_name);
482 8727 : registerPropName(prop_name, true, 0);
483 8727 : markMatPropRequested(prop_name);
484 :
485 : // Register this material on these blocks and boundaries as a zero property with relaxed
486 : // consistency checking
487 17454 : for (std::set<SubdomainID>::const_iterator it = blockIDs().begin(); it != blockIDs().end(); ++it)
488 8727 : storeSubdomainZeroMatProp(*it, prop_name);
489 17454 : for (std::set<BoundaryID>::const_iterator it = boundaryIDs().begin(); it != boundaryIDs().end();
490 8727 : ++it)
491 8727 : storeBoundaryZeroMatProp(*it, prop_name);
492 :
493 : // set values for all qpoints to zero
494 : // (in multiapp scenarios getMaxQps can return different values in each app; we need the max)
495 8727 : unsigned int nqp = getMaxQps();
496 8727 : if (nqp > preload_with_zero.size())
497 6879 : preload_with_zero.resize(nqp);
498 48393 : for (unsigned int qp = 0; qp < nqp; ++qp)
499 39666 : MathUtils::mooseSetToZero(preload_with_zero[qp]);
500 :
501 8727 : return preload_with_zero;
502 : }
503 :
504 : template <typename T, bool is_ad>
505 : const GenericMaterialProperty<T, is_ad> &
506 540 : MaterialBase::getGenericZeroMaterialProperty()
507 : {
508 : // static zero property storage
509 540 : static GenericMaterialProperty<T, is_ad> zero(MaterialPropertyInterface::zero_property_id);
510 :
511 : // resize to accomodate maximum number of qpoints
512 : // (in multiapp scenarios getMaxQps can return different values in each app; we need the max)
513 540 : unsigned int nqp = getMaxQps();
514 540 : if (nqp > zero.size())
515 26 : zero.resize(nqp);
516 :
517 : // set values for all qpoints to zero
518 2700 : for (unsigned int qp = 0; qp < nqp; ++qp)
519 2160 : MathUtils::mooseSetToZero(zero[qp]);
520 :
521 540 : return zero;
522 : }
523 :
524 : template <typename T>
525 : ADMaterialProperty<T> &
526 11257 : MaterialBase::declareADProperty(const std::string & name)
527 : {
528 : // Check if the supplied parameter is a valid input parameter key
529 11257 : std::string prop_name = name;
530 11257 : if (_pars.have_parameter<MaterialPropertyName>(name))
531 628 : prop_name = _pars.get<MaterialPropertyName>(name);
532 :
533 22514 : return declareADPropertyByName<T>(prop_name);
534 11257 : }
535 :
536 : template <typename Consumers>
537 : std::deque<MaterialBase *>
538 3244 : MaterialBase::buildRequiredMaterials(const Consumers & mat_consumers,
539 : const std::vector<std::shared_ptr<MaterialBase>> & mats,
540 : const bool allow_stateful)
541 : {
542 3244 : std::deque<MaterialBase *> required_mats;
543 :
544 3244 : std::unordered_set<unsigned int> needed_mat_props;
545 6968 : for (const auto & consumer : mat_consumers)
546 : {
547 3724 : const auto & mp_deps = consumer->getMatPropDependencies();
548 3724 : needed_mat_props.insert(mp_deps.begin(), mp_deps.end());
549 : }
550 :
551 : // A predicate of calling this function is that these materials come in already sorted by
552 : // dependency with the front of the container having no other material dependencies and following
553 : // materials potentially depending on the ones in front of them. So we can start at the back and
554 : // iterate forward checking whether the current material supplies anything that is needed, and if
555 : // not we discard it
556 16538 : for (auto it = mats.rbegin(); it != mats.rend(); ++it)
557 : {
558 13294 : auto * const mat = it->get();
559 13294 : bool supplies_needed = false;
560 :
561 13294 : const auto & supplied_props = mat->getSuppliedPropIDs();
562 :
563 : // Do O(N) with the small container
564 40736 : for (const auto supplied_prop : supplied_props)
565 : {
566 30220 : if (needed_mat_props.count(supplied_prop))
567 : {
568 2778 : supplies_needed = true;
569 2778 : break;
570 : }
571 : }
572 :
573 13294 : if (!supplies_needed)
574 10516 : continue;
575 :
576 2778 : if (!allow_stateful && mat->hasStatefulProperties())
577 0 : ::mooseError(
578 : "Someone called buildRequiredMaterials with allow_stateful = false but a material "
579 : "dependency ",
580 0 : mat->name(),
581 : " computes stateful properties.");
582 :
583 2778 : const auto & mp_deps = mat->getMatPropDependencies();
584 2778 : needed_mat_props.insert(mp_deps.begin(), mp_deps.end());
585 2778 : required_mats.push_front(mat);
586 : }
587 :
588 6488 : return required_mats;
589 3244 : }
|