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 : #ifdef MOOSE_KOKKOS_ENABLED
13 : #include "KokkosMaterialProperty.h"
14 : #endif
15 :
16 : #include "MaterialProperty.h"
17 : #include "Moose.h"
18 : #include "MooseUtils.h"
19 :
20 : // libMesh
21 : #include "libmesh/elem.h"
22 :
23 : #include <vector>
24 : #include <memory>
25 : #include <typeinfo>
26 :
27 : class MaterialPropertyStorage;
28 : class MooseObject;
29 : class Material;
30 : class XFEM;
31 : class MaterialBase;
32 :
33 : /**
34 : * Proxy for accessing MaterialPropertyStorage.
35 : * MaterialData stores the values associated with a particular material object
36 : */
37 : class MaterialData
38 : {
39 : public:
40 : MaterialData(MaterialPropertyStorage & storage, const THREAD_ID tid);
41 :
42 : /// The max time state supported (2 = older)
43 : static constexpr unsigned int max_state = 2;
44 :
45 : /**
46 : * Resize the data to hold properties for n_qpoints quadrature points.
47 : */
48 : void resize(unsigned int n_qpoints);
49 :
50 : /**
51 : * Returns the number of quadrature points the material properties
52 : * support/hold.
53 : */
54 51136971 : unsigned int nQPoints() const { return _n_qpoints; }
55 :
56 : /// copy material properties from one element to another
57 : void copy(const Elem & elem_to, const Elem & elem_from, unsigned int side);
58 :
59 : /// material properties for given element (and possible side)
60 : void swap(const Elem & elem, unsigned int side = 0);
61 :
62 : /**
63 : * Reinit material properties for given element (and possible side)
64 : * @param mats The material objects for which to compute properties
65 : * @param execute_stateful Whether to execute material objects that have stateful properties. This
66 : * should be \p false when for example executing material objects for mortar contexts in which
67 : * stateful properties don't make sense
68 : */
69 : template <typename MatContainer>
70 : void reinit(const MatContainer & mats);
71 :
72 : /// Calls the reset method of Materials to ensure that they are in a proper state.
73 : void reset(const std::vector<std::shared_ptr<MaterialBase>> & mats);
74 :
75 : /// material properties for given element (and possible side)
76 : void swapBack(const Elem & elem, unsigned int side = 0);
77 :
78 : /**
79 : * @returns The properties for the state \p state (defaults to zero).
80 : *
81 : * This should NEVER be used to modify the size of these objects.
82 : */
83 : ///{
84 : const MaterialProperties & props(const unsigned int state = 0) const;
85 : MaterialProperties & props(const unsigned int state = 0);
86 : ///@}
87 :
88 : template <typename T, bool is_ad>
89 : bool haveGenericProperty(const std::string & prop_name) const;
90 :
91 : /// Returns true if the regular material property exists - defined by any material.
92 : template <typename T>
93 46352 : bool haveProperty(const std::string & prop_name) const
94 : {
95 46352 : return haveGenericProperty<T, false>(prop_name);
96 : }
97 :
98 : /// Returns true if the AD material property exists - defined by any material.
99 : template <typename T>
100 24735 : bool haveADProperty(const std::string & prop_name) const
101 : {
102 24735 : return haveGenericProperty<T, true>(prop_name);
103 : }
104 :
105 : #ifdef MOOSE_KOKKOS_SCOPE
106 : /**
107 : * Get whether a Kokkos material property exists
108 : * @tparam T The property data type
109 : * @tparam dimension The property dimension
110 : * @param prop_name The property name
111 : * @returns Whether the Kokkos material property exists
112 : */
113 : template <typename T, unsigned int dimension>
114 : bool haveKokkosProperty(const std::string & prop_name) const;
115 : #endif
116 :
117 : /**
118 : * Retrieves a material property
119 : * @tparam T The type of the property
120 : * @tparam is_ad Whether or not the property is AD
121 : * @param prop_name The name of the property
122 : * @param state The time state (0 = current, 1 = old, etc; defaults to 0)
123 : * @param requestor The MooseObject requesting the property
124 : * @return The property for the supplied type and name
125 : */
126 : template <typename T, bool is_ad = false>
127 61436 : GenericMaterialProperty<T, is_ad> & getProperty(const std::string & prop_name,
128 : const unsigned int state,
129 : const MooseObject & requestor)
130 : {
131 61436 : return getPropertyHelper<T, is_ad, false>(prop_name, state, requestor);
132 : }
133 : /**
134 : * Declares a material property
135 : * @tparam T The type of the property
136 : * @tparam is_ad Whether or not the property is AD
137 : * @param prop_name The name of the property
138 : * @param requestor The MooseObject declaring the property
139 : * @return The property for the supplied type and name
140 : */
141 : template <typename T, bool is_ad>
142 60396 : GenericMaterialProperty<T, is_ad> & declareProperty(const std::string & prop_name,
143 : const MooseObject & requestor)
144 : {
145 60396 : return getPropertyHelper<T, is_ad, true>(prop_name, 0, requestor);
146 : }
147 :
148 : #ifdef MOOSE_KOKKOS_SCOPE
149 : /**
150 : * Get a Kokkos material property
151 : * @tparam T The property data type
152 : * @tparam dimension The property dimension
153 : * @tparam state The property state
154 : * @param prop_name The property name
155 : * @return The Kokkos material property
156 : */
157 : template <typename T, unsigned int dimension, unsigned int state>
158 : Moose::Kokkos::MaterialProperty<T, dimension> getKokkosProperty(const std::string & prop_name);
159 :
160 : /**
161 : * Declare a Kokkos material property
162 : * @tparam T The property data type
163 : * @tparam dimension The property dimension
164 : * @param prop_name The property name
165 : * @param dims The vector containing the size of each dimension
166 : * @param declarer The Kokkos material declaring the property
167 : * @param bnd Whether the property is a face property
168 : * @param on_demand Whether the property is an on-demand property
169 : * @param constant_option Whether the property is constant on element or subdomain
170 : * @return The Kokkos material property
171 : */
172 : template <typename T, unsigned int dimension>
173 : Moose::Kokkos::MaterialProperty<T, dimension>
174 : declareKokkosProperty(const std::string & prop_name,
175 : const std::vector<unsigned int> & dims,
176 : const MaterialBase * declarer,
177 : const bool bnd,
178 : const bool on_demand,
179 : const Moose::Kokkos::PropertyConstantOption constant_option);
180 : #endif
181 :
182 : /**
183 : * Returns true if the stateful material is in a swapped state.
184 : */
185 378257333 : bool isSwapped() const { return _swapped; }
186 :
187 : /**
188 : * Provide read-only access to the underlying MaterialPropertyStorage object.
189 : */
190 1050730 : const MaterialPropertyStorage & getMaterialPropertyStorage() const { return _storage; }
191 :
192 : /**
193 : * Key that provides access to only the XFEM class.
194 : */
195 : class XFEMKey
196 : {
197 : friend class XFEM;
198 : XFEMKey() {}
199 : XFEMKey(const XFEM &) {}
200 : };
201 :
202 : /**
203 : * Provide write-only access to the underlying MaterialPropertyStorage object JUST FOR XFEM.
204 : *
205 : * This should be removed. To be clear - you should not ever expect to have write access
206 : * to this data. It just turned out that XFEM got away with it when we were storing things
207 : * as pointers instead of smart pointers...
208 : *
209 : * These dirty reasons are why this method is named so egregiously.
210 : */
211 : MaterialPropertyStorage & getMaterialPropertyStorageForXFEM(const XFEMKey) { return _storage; }
212 :
213 : /**
214 : * @return Whether or not a property exists with the name \p name
215 : */
216 : bool hasProperty(const std::string & prop_name) const;
217 :
218 : /**
219 : * Wrapper for MaterialStorage::getPropertyId. Allows classes with a MaterialData object
220 : * (i.e. MaterialPropertyInterface) to access material property IDs.
221 : * @param prop_name The name of the material property
222 : *
223 : * @return An unsigned int corresponding to the property ID of the passed in prop_name
224 : */
225 : unsigned int getPropertyId(const std::string & prop_name) const;
226 :
227 : /**
228 : * Set _resize_only_if_smaller to perform a non-destructive resize. Setting this
229 : * flag to true means that resize(n) will not decrease the size of _props
230 : * if n is smaller than the size of the material data object.
231 : */
232 : void onlyResizeIfSmaller(bool flag) { _resize_only_if_smaller = flag; };
233 :
234 : /**
235 : * Check value of _resize_only_if_smaller
236 : */
237 233882 : bool isOnlyResizeIfSmaller() const { return _resize_only_if_smaller; };
238 :
239 : /**
240 : * Remove the property storage and element pointer from MaterialPropertyStorage data structures
241 : * Use this when elements are deleted so we don't end up with invalid elem pointers (for e.g.
242 : * stateful properties) hanging around in our data structures
243 : */
244 : void eraseProperty(const Elem * elem);
245 :
246 : private:
247 : /// Reference to the MaterialStorage class
248 : MaterialPropertyStorage & _storage;
249 :
250 : /// The thread id
251 : const THREAD_ID _tid;
252 :
253 : /// Number of quadrature points
254 : unsigned int _n_qpoints;
255 :
256 : /// The underlying property data
257 : std::array<MaterialProperties, max_state + 1> _props;
258 :
259 : unsigned int addPropertyHelper(const std::string & prop_name,
260 : const std::type_info & type,
261 : const unsigned int state,
262 : const MaterialBase * const declarer);
263 :
264 : template <typename T, bool is_ad, bool declare>
265 : GenericMaterialProperty<T, is_ad> & getPropertyHelper(const std::string & prop_name,
266 : const unsigned int state,
267 : const MooseObject & requestor);
268 :
269 : #ifdef MOOSE_KOKKOS_ENABLED
270 : /**
271 : * Helper function for adding a Kokkos material property
272 : * @param prop_name The property name
273 : * @param type The property data type
274 : * @param state The property state
275 : * @param shell The managed pointer containing the instance of the property
276 : * @return The Kokkos material property
277 : */
278 : Moose::Kokkos::MaterialPropertyBase &
279 : addKokkosPropertyHelper(const std::string & prop_name,
280 : const std::type_info & type,
281 : const unsigned int state,
282 : std::shared_ptr<Moose::Kokkos::MaterialPropertyBase> shell);
283 :
284 : /**
285 : * Helper function for declaring a Kokkos material property
286 : * @param prop_name The property name
287 : * @param type The property data type
288 : * @param declarer The Kokkos material declaring the property
289 : * @param dims The vector containing the size of each dimension
290 : * @param bnd Whether the property is a face property
291 : * @param on_demand Whether the property is an on-demand property
292 : * @param constant_option Whether the property is constant on element or subdomain
293 : * @param shell The managed pointer containing the instance of the property
294 : * @return The Kokkos material property
295 : */
296 : Moose::Kokkos::MaterialPropertyBase &
297 : declareKokkosPropertyHelper(const std::string & prop_name,
298 : const std::type_info & type,
299 : const MaterialBase * declarer,
300 : const std::vector<unsigned int> & dims,
301 : const bool bnd,
302 : const bool on_demand,
303 : const Moose::Kokkos::PropertyConstantOption constant_option,
304 : std::shared_ptr<Moose::Kokkos::MaterialPropertyBase> shell);
305 :
306 : /**
307 : * Helper function for getting a Kokkos material property
308 : * @param prop_name The property name
309 : * @param state The property state
310 : * @param shell The managed pointer containing the instance of the property
311 : * @return The Kokkos material property
312 : */
313 : Moose::Kokkos::MaterialPropertyBase & getKokkosPropertyHelper(
314 : const std::string & prop_name,
315 : const unsigned int state = 0,
316 : std::shared_ptr<Moose::Kokkos::MaterialPropertyBase> shell = nullptr) const;
317 :
318 : /**
319 : * Helper function for checking whether a Kokkos material property exists
320 : * @param prop_name The property name
321 : * @return Whether the Kokkos material property exists
322 : */
323 : bool haveKokkosPropertyHelper(const std::string & prop_name) const;
324 : /**
325 : * Helper function to register load/store functions of a Kokkos material property to the Kokkos
326 : * material property storage
327 : * @param type The property type index
328 : * @param store The store function pointer
329 : * @param load The load function pointer
330 : */
331 : void kokkosRegisterLoadStoreHelper(std::type_index type,
332 : Moose::Kokkos::PropertyStore store,
333 : Moose::Kokkos::PropertyLoad load);
334 : #endif
335 :
336 : static void mooseErrorHelper(const MooseObject & object, const std::string_view & error);
337 :
338 : /**
339 : * Helper for casting \p requestor to a MaterialBase in addPropertyHelper() (templated)
340 : */
341 : const MaterialBase & castRequestorToDeclarer(const MooseObject & requestor) const;
342 :
343 : /// Status of storage swapping (calling swap sets this to true; swapBack sets it to false)
344 : bool _swapped;
345 :
346 : /// Use non-destructive resize of material data (calling resize() will not reduce size).
347 : /// Default is false (normal resize behaviour)
348 : bool _resize_only_if_smaller;
349 :
350 : /// maximum state id requested for a property
351 : unsigned int getMaxStateRequested(const unsigned int prop_id) const;
352 : };
353 :
354 : inline const MaterialProperties &
355 136114 : MaterialData::props(const unsigned int state) const
356 : {
357 : mooseAssert(_props.size() > state, "Invalid state");
358 136114 : return _props[state];
359 : }
360 :
361 : inline MaterialProperties &
362 27187257 : MaterialData::props(const unsigned int state)
363 : {
364 : mooseAssert(_props.size() > state, "Invalid state");
365 27187257 : return _props[state];
366 : }
367 :
368 : template <typename T, bool is_ad>
369 : inline bool
370 76169 : MaterialData::haveGenericProperty(const std::string & prop_name) const
371 : {
372 76169 : if (!hasProperty(prop_name))
373 7965 : return false;
374 :
375 68204 : const auto prop_id = getPropertyId(prop_name);
376 : // the property id exists, but the property was not created in this instance of the material type
377 68204 : if (prop_id >= props(0).size())
378 294 : return false;
379 :
380 67910 : const PropertyValue * const base_prop = props(0).queryValue(prop_id);
381 67910 : return dynamic_cast<const GenericMaterialProperty<T, is_ad> *>(base_prop) != nullptr;
382 : }
383 :
384 : template <typename T, bool is_ad, bool declare>
385 : GenericMaterialProperty<T, is_ad> &
386 121832 : MaterialData::getPropertyHelper(const std::string & prop_name,
387 : const unsigned int state,
388 : const MooseObject & requestor)
389 : {
390 : if constexpr (is_ad)
391 : mooseAssert(state == 0, "Cannot request/declare AD properties for states other than zero");
392 : if constexpr (declare)
393 : mooseAssert(state == 0, "Cannot declare properties for states other than zero");
394 :
395 : // Register/get the ID of the property
396 182228 : const auto prop_id = addPropertyHelper(
397 60396 : prop_name, typeid(T), state, declare ? &castRequestorToDeclarer(requestor) : nullptr);
398 121832 : const auto size = prop_id + 1;
399 :
400 : // Initialize the states that we need
401 251580 : for (const auto state_i : make_range(getMaxStateRequested(prop_id) + 1))
402 : {
403 129748 : auto & entry = props(state_i);
404 129748 : if (entry.size() < size)
405 59594 : entry.resize(size, {});
406 : // if we are not declaring the property we initialize only what we need (the requested state)
407 129748 : if (!entry.hasValue(prop_id) && (declare || state_i == state))
408 : {
409 59535 : if (state_i == 0)
410 111724 : entry.setPointer(
411 111724 : prop_id, std::move(std::make_unique<GenericMaterialProperty<T, is_ad>>(prop_id)), {});
412 : else
413 3673 : entry.setPointer(prop_id, std::move(std::make_unique<MaterialProperty<T>>(prop_id)), {});
414 : }
415 : }
416 :
417 : // Should be available now
418 121832 : auto & base_prop = props(state)[prop_id];
419 :
420 : // In the event that this property was already declared/requested, make sure
421 : // that the types are consistent
422 121832 : auto prop = dynamic_cast<GenericMaterialProperty<T, is_ad> *>(&base_prop);
423 121832 : if (!prop)
424 : {
425 12 : constexpr std::string_view action = declare ? "declared" : "requested";
426 12 : constexpr auto is_ad_to_str = [](const bool is_ad_bool)
427 12 : { return std::string_view(is_ad_bool ? "AD" : "non-AD"); };
428 12 : constexpr std::string_view ad_type = is_ad_to_str(is_ad);
429 :
430 12 : std::stringstream error;
431 : error << "The " << action << " " << ad_type << " "
432 : << "material property '" + prop_name + "' of type '" << MooseUtils::prettyCppType<T>()
433 24 : << "'\nis already retrieved or declared as a " << is_ad_to_str(base_prop.isAD())
434 12 : << " property of type '" << base_prop.type() << "'.";
435 12 : mooseErrorHelper(requestor, error.str());
436 0 : }
437 :
438 121820 : return *prop;
439 : }
440 :
441 : template <typename MatContainer>
442 : void
443 17440979 : MaterialData::reinit(const MatContainer & mats)
444 : {
445 40317255 : for (const auto & mat : mats)
446 22876332 : mat->computeProperties();
447 17440923 : }
448 :
449 : #ifdef MOOSE_KOKKOS_SCOPE
450 : template <typename T, unsigned int dimension>
451 : bool
452 17 : MaterialData::haveKokkosProperty(const std::string & prop_name) const
453 : {
454 17 : if (!haveKokkosPropertyHelper(prop_name))
455 0 : return false;
456 :
457 17 : auto & prop = getKokkosPropertyHelper(prop_name);
458 17 : return dynamic_cast<Moose::Kokkos::MaterialProperty<T, dimension> *>(&prop) != nullptr;
459 : }
460 :
461 : template <typename T, unsigned int dimension, unsigned int state>
462 : Moose::Kokkos::MaterialProperty<T, dimension>
463 1941 : MaterialData::getKokkosProperty(const std::string & prop_name)
464 : {
465 : // Reserve the storages for the property up to the requested state
466 : // If the storages were already reserved, it will do nothing
467 5147 : for (unsigned int s = 0; s <= state; ++s)
468 : {
469 3206 : auto shell = std::make_shared<Moose::Kokkos::MaterialProperty<T, dimension>>();
470 :
471 3206 : addKokkosPropertyHelper(prop_name, typeid(T), state, shell);
472 :
473 : // Only instantiate load and store functions for stateful properties to avoid requiring users
474 : // to provide custom dataLoad and dataStore for non-trivially-copyable types that are never
475 : // used as stateful properties
476 : if constexpr (state > 0)
477 2252 : kokkosRegisterLoadStoreHelper(shell->propertyType(),
478 : Moose::Kokkos::propertyStore<T, dimension>,
479 : Moose::Kokkos::propertyLoad<T, dimension>);
480 : }
481 :
482 1941 : auto & prop_base = getKokkosPropertyHelper(prop_name, state, nullptr);
483 1941 : auto prop_cast = dynamic_cast<Moose::Kokkos::MaterialProperty<T, dimension> *>(&prop_base);
484 :
485 1941 : if (!prop_cast)
486 0 : mooseError("The requested ",
487 : dimension,
488 : "D Kokkos material property '",
489 : prop_name,
490 : "' of type '",
491 : MooseUtils::prettyCppType<T>(),
492 : "' was already declared or requested as a ",
493 0 : prop_base.dim(),
494 : "D property of type '",
495 0 : prop_base.type(),
496 : "'.");
497 :
498 1941 : return *prop_cast;
499 : }
500 :
501 : template <typename T, unsigned int dimension>
502 : Moose::Kokkos::MaterialProperty<T, dimension>
503 2996 : MaterialData::declareKokkosProperty(const std::string & prop_name,
504 : const std::vector<unsigned int> & dims,
505 : const MaterialBase * declarer,
506 : const bool bnd,
507 : const bool on_demand,
508 : const Moose::Kokkos::PropertyConstantOption constant_option)
509 : {
510 2996 : auto shell = std::make_shared<Moose::Kokkos::MaterialProperty<T, dimension>>();
511 :
512 2996 : auto & prop_base = declareKokkosPropertyHelper(
513 : prop_name, typeid(T), declarer, dims, bnd, on_demand, constant_option, shell);
514 2990 : auto prop_cast = dynamic_cast<Moose::Kokkos::MaterialProperty<T, dimension> *>(&prop_base);
515 :
516 2990 : if (!prop_cast)
517 2 : mooseError("The declared ",
518 : dimension,
519 : "D Kokkos material property '",
520 : prop_name,
521 : "' of type '",
522 : MooseUtils::prettyCppType<T>(),
523 : "' was already declared or requested as a ",
524 2 : prop_base.dim(),
525 : "D property of type '",
526 2 : prop_base.type(),
527 : "'.");
528 :
529 5976 : return *prop_cast;
530 2988 : }
531 : #endif
|