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 74158369 : 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 48948 : bool haveProperty(const std::string & prop_name) const
94 : {
95 48948 : 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 25670 : bool haveADProperty(const std::string & prop_name) const
101 : {
102 25670 : 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 65013 : GenericMaterialProperty<T, is_ad> & getProperty(const std::string & prop_name,
128 : const unsigned int state,
129 : const MooseObject & requestor)
130 : {
131 65013 : 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 64264 : GenericMaterialProperty<T, is_ad> & declareProperty(const std::string & prop_name,
143 : const MooseObject & requestor)
144 : {
145 64264 : 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 : * @return The Kokkos material property
169 : */
170 : template <typename T, unsigned int dimension>
171 : Moose::Kokkos::MaterialProperty<T, dimension>
172 : declareKokkosProperty(const std::string & prop_name,
173 : const std::vector<unsigned int> & dims,
174 : const MaterialBase * declarer,
175 : const bool bnd);
176 : #endif
177 :
178 : /**
179 : * Returns true if the stateful material is in a swapped state.
180 : */
181 440268588 : bool isSwapped() const { return _swapped; }
182 :
183 : /**
184 : * Provide read-only access to the underlying MaterialPropertyStorage object.
185 : */
186 1537966 : const MaterialPropertyStorage & getMaterialPropertyStorage() const { return _storage; }
187 :
188 : /**
189 : * Key that provides access to only the XFEM class.
190 : */
191 : class XFEMKey
192 : {
193 : friend class XFEM;
194 : XFEMKey() {}
195 : XFEMKey(const XFEM &) {}
196 : };
197 :
198 : /**
199 : * Provide write-only access to the underlying MaterialPropertyStorage object JUST FOR XFEM.
200 : *
201 : * This should be removed. To be clear - you should not ever expect to have write access
202 : * to this data. It just turned out that XFEM got away with it when we were storing things
203 : * as pointers instead of smart pointers...
204 : *
205 : * These dirty reasons are why this method is named so egregiously.
206 : */
207 : MaterialPropertyStorage & getMaterialPropertyStorageForXFEM(const XFEMKey) { return _storage; }
208 :
209 : /**
210 : * @return Whether or not a property exists with the name \p name
211 : */
212 : bool hasProperty(const std::string & prop_name) const;
213 :
214 : /**
215 : * Wrapper for MaterialStorage::getPropertyId. Allows classes with a MaterialData object
216 : * (i.e. MaterialPropertyInterface) to access material property IDs.
217 : * @param prop_name The name of the material property
218 : *
219 : * @return An unsigned int corresponding to the property ID of the passed in prop_name
220 : */
221 : unsigned int getPropertyId(const std::string & prop_name) const;
222 :
223 : /**
224 : * Set _resize_only_if_smaller to perform a non-destructive resize. Setting this
225 : * flag to true means that resize(n) will not decrease the size of _props
226 : * if n is smaller than the size of the material data object.
227 : */
228 : void onlyResizeIfSmaller(bool flag) { _resize_only_if_smaller = flag; };
229 :
230 : /**
231 : * Check value of _resize_only_if_smaller
232 : */
233 641080 : bool isOnlyResizeIfSmaller() const { return _resize_only_if_smaller; };
234 :
235 : /**
236 : * Remove the property storage and element pointer from MaterialPropertyStorage data structures
237 : * Use this when elements are deleted so we don't end up with invalid elem pointers (for e.g.
238 : * stateful properties) hanging around in our data structures
239 : */
240 : void eraseProperty(const Elem * elem);
241 :
242 : private:
243 : /// Reference to the MaterialStorage class
244 : MaterialPropertyStorage & _storage;
245 :
246 : /// The thread id
247 : const THREAD_ID _tid;
248 :
249 : /// Number of quadrature points
250 : unsigned int _n_qpoints;
251 :
252 : /// The underlying property data
253 : std::array<MaterialProperties, max_state + 1> _props;
254 :
255 : unsigned int addPropertyHelper(const std::string & prop_name,
256 : const std::type_info & type,
257 : const unsigned int state,
258 : const MaterialBase * const declarer);
259 :
260 : template <typename T, bool is_ad, bool declare>
261 : GenericMaterialProperty<T, is_ad> & getPropertyHelper(const std::string & prop_name,
262 : const unsigned int state,
263 : const MooseObject & requestor);
264 :
265 : #ifdef MOOSE_KOKKOS_ENABLED
266 : /**
267 : * Helper function for adding a Kokkos material property
268 : * @param prop_name The property name
269 : * @param type The property data type
270 : * @param state The property state
271 : * @param shell The managed pointer containing the instance of the property
272 : * @return The Kokkos material property
273 : */
274 : Moose::Kokkos::MaterialPropertyBase &
275 : addKokkosPropertyHelper(const std::string & prop_name,
276 : const std::type_info & type,
277 : const unsigned int state,
278 : std::shared_ptr<Moose::Kokkos::MaterialPropertyBase> shell);
279 :
280 : /**
281 : * Helper function for declaring a Kokkos material property
282 : * @param prop_name The property name
283 : * @param type The property data type
284 : * @param declarer The Kokkos material declaring the property
285 : * @param dims The vector containing the size of each dimension
286 : * @param bnd Whether the property is a face property
287 : * @param shell The managed pointer containing the instance of the property
288 : * @return The Kokkos material property
289 : */
290 : Moose::Kokkos::MaterialPropertyBase &
291 : declareKokkosPropertyHelper(const std::string & prop_name,
292 : const std::type_info & type,
293 : const MaterialBase * declarer,
294 : const std::vector<unsigned int> & dims,
295 : const bool bnd,
296 : std::shared_ptr<Moose::Kokkos::MaterialPropertyBase> shell);
297 :
298 : /**
299 : * Helper function for getting a Kokkos material property
300 : * @param prop_name The property name
301 : * @param state The property state
302 : * @param shell The managed pointer containing the instance of the property
303 : * @return The Kokkos material property
304 : */
305 : Moose::Kokkos::MaterialPropertyBase & getKokkosPropertyHelper(
306 : const std::string & prop_name,
307 : const unsigned int state = 0,
308 : std::shared_ptr<Moose::Kokkos::MaterialPropertyBase> shell = nullptr) const;
309 :
310 : /**
311 : * Helper function for checking whether a Kokkos material property exists
312 : * @param prop_name The property name
313 : * @return Whether the Kokkos material property exists
314 : */
315 : bool haveKokkosPropertyHelper(const std::string & prop_name) const;
316 : /**
317 : * Helper function to register load/store functions of a Kokkos material property to the Kokkos
318 : * material property storage
319 : * @param type The property type index
320 : * @param store The store function pointer
321 : * @param load The load function pointer
322 : */
323 : void kokkosRegisterLoadStoreHelper(std::type_index type,
324 : Moose::Kokkos::PropertyStore store,
325 : Moose::Kokkos::PropertyLoad load);
326 : #endif
327 :
328 : static void mooseErrorHelper(const MooseObject & object, const std::string_view & error);
329 :
330 : /**
331 : * Helper for casting \p requestor to a MaterialBase in addPropertyHelper() (templated)
332 : */
333 : const MaterialBase & castRequestorToDeclarer(const MooseObject & requestor) const;
334 :
335 : /// Status of storage swapping (calling swap sets this to true; swapBack sets it to false)
336 : bool _swapped;
337 :
338 : /// Use non-destructive resize of material data (calling resize() will not reduce size).
339 : /// Default is false (normal resize behaviour)
340 : bool _resize_only_if_smaller;
341 :
342 : /// maximum state id requested for a property
343 : unsigned int getMaxStateRequested(const unsigned int prop_id) const;
344 : };
345 :
346 : inline const MaterialProperties &
347 142860 : MaterialData::props(const unsigned int state) const
348 : {
349 : mooseAssert(_props.size() > state, "Invalid state");
350 142860 : return _props[state];
351 : }
352 :
353 : inline MaterialProperties &
354 43180267 : MaterialData::props(const unsigned int state)
355 : {
356 : mooseAssert(_props.size() > state, "Invalid state");
357 43180267 : return _props[state];
358 : }
359 :
360 : template <typename T, bool is_ad>
361 : inline bool
362 80064 : MaterialData::haveGenericProperty(const std::string & prop_name) const
363 : {
364 80064 : if (!hasProperty(prop_name))
365 8474 : return false;
366 :
367 71590 : const auto prop_id = getPropertyId(prop_name);
368 : // the property id exists, but the property was not created in this instance of the material type
369 71590 : if (prop_id >= props(0).size())
370 320 : return false;
371 :
372 71270 : const PropertyValue * const base_prop = props(0).queryValue(prop_id);
373 71270 : return dynamic_cast<const GenericMaterialProperty<T, is_ad> *>(base_prop) != nullptr;
374 : }
375 :
376 : template <typename T, bool is_ad, bool declare>
377 : GenericMaterialProperty<T, is_ad> &
378 129277 : MaterialData::getPropertyHelper(const std::string & prop_name,
379 : const unsigned int state,
380 : const MooseObject & requestor)
381 : {
382 : if constexpr (is_ad)
383 : mooseAssert(state == 0, "Cannot request/declare AD properties for states other than zero");
384 : if constexpr (declare)
385 : mooseAssert(state == 0, "Cannot declare properties for states other than zero");
386 :
387 : // Register/get the ID of the property
388 193541 : const auto prop_id = addPropertyHelper(
389 64264 : prop_name, typeid(T), state, declare ? &castRequestorToDeclarer(requestor) : nullptr);
390 129277 : const auto size = prop_id + 1;
391 :
392 : // Initialize the states that we need
393 267113 : for (const auto state_i : make_range(getMaxStateRequested(prop_id) + 1))
394 : {
395 137836 : auto & entry = props(state_i);
396 137836 : if (entry.size() < size)
397 63366 : entry.resize(size, {});
398 : // if we are not declaring the property we initialize only what we need (the requested state)
399 137836 : if (!entry.hasValue(prop_id) && (declare || state_i == state))
400 : {
401 63319 : if (state_i == 0)
402 118590 : entry.setPointer(
403 118590 : prop_id, std::move(std::make_unique<GenericMaterialProperty<T, is_ad>>(prop_id)), {});
404 : else
405 4024 : entry.setPointer(prop_id, std::move(std::make_unique<MaterialProperty<T>>(prop_id)), {});
406 : }
407 : }
408 :
409 : // Should be available now
410 129277 : auto & base_prop = props(state)[prop_id];
411 :
412 : // In the event that this property was already declared/requested, make sure
413 : // that the types are consistent
414 129277 : auto prop = dynamic_cast<GenericMaterialProperty<T, is_ad> *>(&base_prop);
415 129277 : if (!prop)
416 : {
417 16 : constexpr std::string_view action = declare ? "declared" : "requested";
418 16 : constexpr auto is_ad_to_str = [](const bool is_ad_bool)
419 16 : { return std::string_view(is_ad_bool ? "AD" : "non-AD"); };
420 16 : constexpr std::string_view ad_type = is_ad_to_str(is_ad);
421 :
422 16 : std::stringstream error;
423 : error << "The " << action << " " << ad_type << " "
424 : << "material property '" + prop_name + "' of type '" << MooseUtils::prettyCppType<T>()
425 32 : << "'\nis already retrieved or declared as a " << is_ad_to_str(base_prop.isAD())
426 16 : << " property of type '" << base_prop.type() << "'.";
427 16 : mooseErrorHelper(requestor, error.str());
428 0 : }
429 :
430 129261 : return *prop;
431 : }
432 :
433 : template <typename MatContainer>
434 : void
435 22466147 : MaterialData::reinit(const MatContainer & mats)
436 : {
437 54017518 : for (const auto & mat : mats)
438 31551449 : mat->computeProperties();
439 22466069 : }
440 :
441 : #ifdef MOOSE_KOKKOS_SCOPE
442 : template <typename T, unsigned int dimension>
443 : bool
444 : MaterialData::haveKokkosProperty(const std::string & prop_name) const
445 : {
446 : if (!haveKokkosPropertyHelper(prop_name))
447 : return false;
448 :
449 : auto & prop = getKokkosPropertyHelper(prop_name);
450 : return dynamic_cast<Moose::Kokkos::MaterialProperty<T, dimension> *>(&prop) != nullptr;
451 : }
452 :
453 : template <typename T, unsigned int dimension, unsigned int state>
454 : Moose::Kokkos::MaterialProperty<T, dimension>
455 1129 : MaterialData::getKokkosProperty(const std::string & prop_name)
456 : {
457 : // Reserve the storages for the property up to the requested state
458 : // If the storages were already reserved, it will do nothing
459 3246 : for (unsigned int s = 0; s <= state; ++s)
460 : {
461 2117 : auto shell = std::make_shared<Moose::Kokkos::MaterialProperty<T, dimension>>();
462 :
463 2117 : addKokkosPropertyHelper(prop_name, typeid(T), state, shell);
464 :
465 : // Only instantiate load and store functions for stateful properties to avoid requiring users
466 : // to provide custom dataLoad and dataStore for non-trivially-copyable types that are never
467 : // used as stateful properties
468 : if constexpr (state > 0)
469 1760 : kokkosRegisterLoadStoreHelper(shell->propertyType(),
470 : Moose::Kokkos::propertyStore<T, dimension>,
471 : Moose::Kokkos::propertyLoad<T, dimension>);
472 : }
473 :
474 1129 : auto & prop_base = getKokkosPropertyHelper(prop_name, state, nullptr);
475 1129 : auto prop_cast = dynamic_cast<Moose::Kokkos::MaterialProperty<T, dimension> *>(&prop_base);
476 :
477 1129 : if (!prop_cast)
478 0 : mooseError("The requested ",
479 : dimension,
480 : "D Kokkos material property '",
481 : prop_name,
482 : "' of type '",
483 : MooseUtils::prettyCppType<T>(),
484 : "' was already declared or requested as a ",
485 0 : prop_base.dim(),
486 : "D property of type '",
487 : prop_base.type(),
488 : "'.");
489 :
490 1129 : return *prop_cast;
491 : }
492 :
493 : template <typename T, unsigned int dimension>
494 : Moose::Kokkos::MaterialProperty<T, dimension>
495 1027 : MaterialData::declareKokkosProperty(const std::string & prop_name,
496 : const std::vector<unsigned int> & dims,
497 : const MaterialBase * declarer,
498 : const bool bnd)
499 : {
500 1027 : auto shell = std::make_shared<Moose::Kokkos::MaterialProperty<T, dimension>>();
501 :
502 1027 : auto & prop_base = declareKokkosPropertyHelper(prop_name, typeid(T), declarer, dims, bnd, shell);
503 1023 : auto prop_cast = dynamic_cast<Moose::Kokkos::MaterialProperty<T, dimension> *>(&prop_base);
504 :
505 1023 : if (!prop_cast)
506 4 : mooseError("The declared ",
507 : dimension,
508 : "D Kokkos material property '",
509 : prop_name,
510 : "' of type '",
511 : MooseUtils::prettyCppType<T>(),
512 : "' was already declared or requested as a ",
513 2 : prop_base.dim(),
514 : "D property of type '",
515 : prop_base.type(),
516 : "'.");
517 :
518 2042 : return *prop_cast;
519 1021 : }
520 : #endif
|