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 : #include <vector>
13 : #include <memory>
14 : #include <typeinfo>
15 :
16 : #include "MooseArray.h"
17 : #include "MooseTypes.h"
18 : #include "DataIO.h"
19 : #include "MooseError.h"
20 : #include "UniqueStorage.h"
21 : #include "MooseUtils.h"
22 :
23 : #include "libmesh/libmesh_common.h"
24 : #include "libmesh/tensor_value.h"
25 : #include "libmesh/vector_value.h"
26 : #include "libmesh/int_range.h"
27 :
28 : #include "metaphysicl/raw_type.h"
29 :
30 : class PropertyValue;
31 : class Material;
32 : class MaterialPropertyInterface;
33 :
34 : /**
35 : * Abstract definition of a property value.
36 : */
37 : class PropertyValue
38 : {
39 : public:
40 : /// The type for a material property ID
41 : typedef unsigned int id_type;
42 :
43 233594 : PropertyValue(const id_type id) : _id(id) {}
44 :
45 227348 : virtual ~PropertyValue(){};
46 :
47 : /// The material property ID for an invalid property
48 : /// We only have this because there are a few cases where folks want to instantiate their
49 : /// own fake materials, and we should at least force them to be consistent
50 : static constexpr id_type invalid_property_id = std::numeric_limits<id_type>::max() - 1;
51 :
52 : /**
53 : * @return The ID of the underlying material property
54 : */
55 170080 : id_type id() const { return _id; }
56 :
57 : /**
58 : * String identifying the type of parameter stored.
59 : */
60 : virtual const std::string & type() const = 0;
61 :
62 : /**
63 : * Clone this value. Useful in copy-construction.
64 : */
65 : virtual std::unique_ptr<PropertyValue> clone(const std::size_t) const = 0;
66 :
67 : virtual unsigned int size() const = 0;
68 :
69 : /**
70 : * Resizes the property to the size n
71 : */
72 : virtual void resize(const std::size_t size) = 0;
73 :
74 : virtual void swap(PropertyValue & rhs) = 0;
75 :
76 : virtual bool isAD() const = 0;
77 :
78 : /**
79 : * Copy the value of a Property from one specific to a specific qp in this Property.
80 : * Important note: this copy operation loses AD derivative information if either this
81 : * or the rhs is not an AD material property
82 : *
83 : * @param to_qp The quadrature point in _this_ Property that you want to copy to.
84 : * @param rhs The Property you want to copy _from_.
85 : * @param from_qp The quadrature point in rhs you want to copy _from_.
86 : */
87 : virtual void
88 : qpCopy(const unsigned int to_qp, const PropertyValue & rhs, const unsigned int from_qp) = 0;
89 :
90 : // save/restore in a file
91 : virtual void store(std::ostream & stream) = 0;
92 : virtual void load(std::istream & stream) = 0;
93 :
94 : /**
95 : * @return The type_info for the underlying stored type T
96 : */
97 : virtual const std::type_info & typeID() const = 0;
98 :
99 : protected:
100 : /// The material property ID
101 : const id_type _id;
102 : };
103 :
104 : /**
105 : * Concrete definition of a parameter value
106 : * for a specified type.
107 : */
108 : template <typename T, bool is_ad>
109 : class MaterialPropertyBase : public PropertyValue
110 : {
111 : public:
112 : typedef Moose::GenericType<T, is_ad> value_type;
113 :
114 233594 : MaterialPropertyBase(const PropertyValue::id_type id) : PropertyValue(id) {}
115 :
116 26595018 : bool isAD() const override final { return is_ad; }
117 :
118 : /**
119 : * @returns a read-only reference to the parameter value.
120 : */
121 62 : const MooseArray<Moose::GenericType<T, is_ad>> & get() const { return _value; }
122 :
123 : /**
124 : * @returns a writable reference to the parameter value.
125 : */
126 0 : MooseArray<Moose::GenericType<T, is_ad>> & set() { return _value; }
127 :
128 : /**
129 : * String identifying the type of parameter stored.
130 : */
131 : virtual const std::string & type() const override final;
132 :
133 : /**
134 : * Resizes the property to the size n
135 : */
136 : virtual void resize(const std::size_t size) override final;
137 :
138 446808 : virtual unsigned int size() const override final { return _value.size(); }
139 :
140 : /**
141 : * Get element i out of the array as a writeable reference.
142 : */
143 109511729 : Moose::GenericType<T, is_ad> & operator[](const unsigned int i) { return _value[i]; }
144 :
145 : /**
146 : * Get element i out of the array as a ready-only reference.
147 : */
148 1166130424 : const Moose::GenericType<T, is_ad> & operator[](const unsigned int i) const { return _value[i]; }
149 :
150 : /**
151 : * Copy the value of a Property from one specific to a specific qp in this Property.
152 : *
153 : * @param to_qp The quadrature point in _this_ Property that you want to copy to.
154 : * @param rhs The Property you want to copy _from_.
155 : * @param from_qp The quadrature point in rhs you want to copy _from_.
156 : */
157 : virtual void qpCopy(const unsigned int to_qp,
158 : const PropertyValue & rhs,
159 : const unsigned int from_qp) override final;
160 :
161 : /**
162 : * Store the property into a binary stream
163 : */
164 : virtual void store(std::ostream & stream) override final;
165 :
166 : /**
167 : * Load the property from a binary stream
168 : */
169 : virtual void load(std::istream & stream) override final;
170 :
171 : virtual void swap(PropertyValue & rhs) override final;
172 :
173 : const std::type_info & typeID() const override final;
174 :
175 : /**
176 : * @return A clone of this property.
177 : *
178 : * Note that this will only ever return a non-AD clone, even if this property
179 : * is an AD property. This is on purpose; whenever we need clones, it's for
180 : * older states in which we don't store derivatives beacuse it's too expensive.
181 : */
182 : virtual std::unique_ptr<PropertyValue> clone(const std::size_t size) const override final;
183 :
184 : private:
185 : /// private copy constructor to avoid shallow copying of material properties
186 : MaterialPropertyBase(const MaterialPropertyBase<T, is_ad> & /*src*/)
187 : {
188 : mooseError("Material properties must be assigned to references (missing '&')");
189 : }
190 :
191 : /// private assignment operator to avoid shallow copying of material properties
192 : MaterialPropertyBase<T, is_ad> & operator=(const MaterialPropertyBase<T, is_ad> & /*rhs*/)
193 : {
194 : mooseError("Material properties must be assigned to references (missing '&')");
195 : }
196 :
197 : protected:
198 : /// Stored parameter value.
199 : MooseArray<Moose::GenericType<T, is_ad>> _value;
200 : };
201 :
202 : template <typename T>
203 : class MaterialProperty;
204 : template <typename T>
205 : class ADMaterialProperty;
206 :
207 : // ------------------------------------------------------------
208 : // Material::Property<> class inline methods
209 :
210 : namespace moose
211 : {
212 : namespace internal
213 : {
214 : template <typename T1, typename T2>
215 : void
216 682440 : rawValueEqualityHelper(T1 & out, const T2 & in)
217 : {
218 682440 : out = MetaPhysicL::raw_value(in);
219 682440 : }
220 :
221 : template <typename T1, typename T2>
222 : void
223 0 : rawValueEqualityHelper(std::vector<T1> & out, const std::vector<T2> & in)
224 : {
225 0 : out.resize(in.size());
226 0 : for (MooseIndex(in) i = 0; i < in.size(); ++i)
227 0 : rawValueEqualityHelper(out[i], in[i]);
228 0 : }
229 :
230 : template <typename T1, typename T2, std::size_t N>
231 : void
232 : rawValueEqualityHelper(std::array<T1, N> & out, const std::array<T2, N> & in)
233 : {
234 : for (MooseIndex(in) i = 0; i < in.size(); ++i)
235 : rawValueEqualityHelper(out[i], in[i]);
236 : }
237 : }
238 : }
239 :
240 : template <typename T, bool is_ad>
241 : inline const std::string &
242 12 : MaterialPropertyBase<T, is_ad>::type() const
243 : {
244 12 : static const std::string type_name = MooseUtils::prettyCppType<T>();
245 12 : return type_name;
246 : }
247 :
248 : template <typename T, bool is_ad>
249 : inline void
250 1068660 : MaterialPropertyBase<T, is_ad>::resize(const std::size_t size)
251 : {
252 1068660 : _value.template resize</*value_initalize=*/true>(size);
253 1068660 : }
254 :
255 : template <typename T, bool is_ad>
256 : inline void
257 11488243 : MaterialPropertyBase<T, is_ad>::qpCopy(const unsigned int to_qp,
258 : const PropertyValue & rhs,
259 : const unsigned int from_qp)
260 : {
261 : // If we're the same
262 11488243 : if (rhs.isAD() == is_ad)
263 11488243 : _value[to_qp] =
264 11488243 : libMesh::cast_ptr<const MaterialPropertyBase<T, is_ad> *>(&rhs)->_value[from_qp];
265 : else
266 0 : moose::internal::rawValueEqualityHelper(
267 : _value[to_qp],
268 0 : (*libMesh::cast_ptr<const MaterialPropertyBase<T, !is_ad> *>(&rhs))[from_qp]);
269 11488243 : }
270 :
271 : template <typename T, bool is_ad>
272 : inline void
273 50311 : MaterialPropertyBase<T, is_ad>::store(std::ostream & stream)
274 : {
275 235087 : for (const auto i : index_range(_value))
276 184776 : storeHelper(stream, _value[i], nullptr);
277 50311 : }
278 :
279 : template <typename T, bool is_ad>
280 : inline void
281 20858 : MaterialPropertyBase<T, is_ad>::load(std::istream & stream)
282 : {
283 126360 : for (const auto i : index_range(_value))
284 105502 : loadHelper(stream, _value[i], nullptr);
285 20858 : }
286 :
287 : template <typename T, bool is_ad>
288 : inline void
289 15106763 : MaterialPropertyBase<T, is_ad>::swap(PropertyValue & rhs)
290 : {
291 : mooseAssert(this->id() == rhs.id(), "Inconsistent properties");
292 : mooseAssert(this->typeID() == rhs.typeID(), "Inconsistent types");
293 :
294 : // If we're the same
295 15106763 : if (rhs.isAD() == is_ad)
296 : {
297 : mooseAssert(dynamic_cast<decltype(this)>(&rhs), "Expected same type is not the same");
298 14935943 : this->_value.swap(libMesh::cast_ptr<decltype(this)>(&rhs)->_value);
299 14935943 : return;
300 : }
301 :
302 : // We may call this function when doing swap between MaterialData material properties (you can
303 : // think of these as the current element properties) and MaterialPropertyStorage material
304 : // properties (these are the stateful material properties that we store for *every* element). We
305 : // never store ADMaterialProperty in stateful storage (e.g. MaterialPropertyStorage) for memory
306 : // resource reasons; instead we keep a regular MaterialProperty version of it. Hence we do have a
307 : // need to exchange data between the AD and regular copies which we implement below. The below
308 : // is obviously not a swap, for which you cannot identify a giver and receiver. Instead the below
309 : // has a clear giver and receiver. The giver is the object passed in as the rhs. The receiver is
310 : // *this* object. This directionality, although not conceptually appropriate given the method
311 : // name, *is* appropriate to how this method is used in practice. See shallowCopyData and
312 : // shallowCopyDataBack in MaterialPropertyStorage.C
313 :
314 170820 : auto * different_type_prop = libMesh::cast_ptr<MaterialPropertyBase<T, !is_ad> *>(&rhs);
315 :
316 170820 : this->resize(different_type_prop->size());
317 853260 : for (const auto qp : make_range(this->size()))
318 682440 : moose::internal::rawValueEqualityHelper(this->_value[qp], (*different_type_prop)[qp]);
319 : }
320 :
321 : template <typename T, bool is_ad>
322 : inline const std::type_info &
323 0 : MaterialPropertyBase<T, is_ad>::typeID() const
324 : {
325 : static const auto & info = typeid(T);
326 0 : return info;
327 : }
328 :
329 : template <typename T, bool is_ad>
330 : std::unique_ptr<PropertyValue>
331 164952 : MaterialPropertyBase<T, is_ad>::clone(const std::size_t size) const
332 : {
333 164952 : auto prop = std::make_unique<MaterialProperty<T>>(this->id());
334 164952 : if (size)
335 164952 : prop->resize(size);
336 329904 : return prop;
337 164952 : }
338 :
339 : template <typename T>
340 : class MaterialProperty : public MaterialPropertyBase<T, false>
341 : {
342 : public:
343 218624 : MaterialProperty(const PropertyValue::id_type id = PropertyValue::invalid_property_id)
344 218624 : : MaterialPropertyBase<T, false>(id)
345 : {
346 218624 : }
347 :
348 : private:
349 : /// private copy constructor to avoid shallow copying of material properties
350 : MaterialProperty(const MaterialProperty<T> & /*src*/)
351 : {
352 : mooseError("Material properties must be assigned to references (missing '&')");
353 : }
354 :
355 : /// private assignment operator to avoid shallow copying of material properties
356 : MaterialProperty<T> & operator=(const MaterialProperty<T> & /*rhs*/)
357 : {
358 : mooseError("Material properties must be assigned to references (missing '&')");
359 : }
360 : };
361 :
362 : template <typename T>
363 : class ADMaterialProperty : public MaterialPropertyBase<T, true>
364 : {
365 : public:
366 14970 : ADMaterialProperty(const PropertyValue::id_type id = PropertyValue::invalid_property_id)
367 14970 : : MaterialPropertyBase<T, true>(id)
368 : {
369 14970 : }
370 :
371 : using typename MaterialPropertyBase<T, true>::value_type;
372 :
373 : private:
374 : /// private copy constructor to avoid shallow copying of material properties
375 : ADMaterialProperty(const ADMaterialProperty<T> & /*src*/)
376 : {
377 : mooseError("Material properties must be assigned to references (missing '&')");
378 : }
379 :
380 : /// private assignment operator to avoid shallow copying of material properties
381 : ADMaterialProperty<T> & operator=(const ADMaterialProperty<T> & /*rhs*/)
382 : {
383 : mooseError("Material properties must be assigned to references (missing '&')");
384 : }
385 : };
386 :
387 : class MaterialData;
388 : class MaterialPropertyStorage;
389 :
390 : class MaterialProperties : public UniqueStorage<PropertyValue>
391 : {
392 : public:
393 : class WriteKey
394 : {
395 : friend class MaterialData;
396 : friend class MaterialPropertyStorage;
397 : friend void dataLoad(std::istream &, MaterialPropertyStorage &, void *);
398 :
399 492881 : WriteKey() {}
400 : WriteKey(const WriteKey &) {}
401 : };
402 :
403 : /**
404 : * Resize items in this array, i.e. the number of values needed in PropertyValue array
405 : * @param n_qpoints The number of values needed to store (equals the the number of quadrature
406 : * points per mesh element)
407 : */
408 62714 : void resizeItems(const std::size_t n_qpoints, const WriteKey)
409 : {
410 132838 : for (const auto i : index_range(*this))
411 70124 : if (auto value = queryValue(i))
412 69063 : value->resize(n_qpoints);
413 62714 : }
414 :
415 207403 : void resize(const std::size_t size, const WriteKey)
416 : {
417 207403 : UniqueStorage<PropertyValue>::resize(size);
418 207403 : }
419 :
420 222764 : void setPointer(const std::size_t i, std::unique_ptr<PropertyValue> && ptr, const WriteKey)
421 : {
422 222764 : return UniqueStorage<PropertyValue>::setPointer(i, std::move(ptr));
423 : }
424 : };
425 :
426 : template <typename T, bool is_ad>
427 : struct GenericMaterialPropertyStruct
428 : {
429 : typedef MaterialProperty<T> type;
430 : };
431 :
432 : template <typename T>
433 : struct GenericMaterialPropertyStruct<T, true>
434 : {
435 : typedef ADMaterialProperty<T> type;
436 : };
437 :
438 : template <typename T, bool is_ad>
439 : using GenericMaterialProperty = typename GenericMaterialPropertyStruct<T, is_ad>::type;
440 :
441 : /**
442 : * Base class to facilitate storage using unique pointers
443 : */
444 : class GenericOptionalMaterialPropertyBase
445 : {
446 : public:
447 1326 : virtual ~GenericOptionalMaterialPropertyBase() {}
448 : };
449 :
450 : template <class M, typename T, bool is_ad>
451 : class OptionalMaterialPropertyProxy;
452 :
453 : /**
454 : * Wrapper around a material property pointer. Copying this wrapper is disabled
455 : * to enforce capture via reference. Used by the optional material property
456 : * API, which requires late binding updates of the stored pointer.
457 : */
458 : template <typename T, bool is_ad>
459 : class GenericOptionalMaterialProperty : public GenericOptionalMaterialPropertyBase
460 : {
461 : typedef GenericMaterialProperty<T, is_ad> P;
462 :
463 : public:
464 : GenericOptionalMaterialProperty(const P * pointer) : _pointer(pointer) {}
465 :
466 : /// no copy construction is permitted
467 : GenericOptionalMaterialProperty(const GenericOptionalMaterialProperty<T, is_ad> &) = delete;
468 : /// no copy assignment is permitted
469 : GenericOptionalMaterialProperty &
470 : operator=(const GenericOptionalMaterialProperty<T, is_ad> &) = delete;
471 :
472 : /// pass through operator[] to provide a similar API as MaterialProperty
473 68420 : const Moose::GenericType<T, is_ad> & operator[](const unsigned int i) const
474 : {
475 : // check if the optional property is valid in debug mode
476 : mooseAssert(
477 : _pointer,
478 : "Attempting to access an optional material property that was not provided by any material "
479 : "class. Make sure to check optional material properties before using them.");
480 68420 : return (*_pointer)[i];
481 : }
482 :
483 : /// pass through size calls
484 : unsigned int size() const { return (*_pointer).size(); }
485 :
486 : /// implicit cast to bool to check the if the material property exists
487 142898 : operator bool() const { return _pointer; }
488 :
489 : /// get a pointer to the underlying property (only do this in initialSetup or later)
490 : const P * get() const { return _pointer; }
491 :
492 : private:
493 : /// the default constructor is only called from the friend class
494 1566 : GenericOptionalMaterialProperty() : _pointer(nullptr) {}
495 :
496 : /// setting the pointer is only permitted through the optional material proxy system
497 672 : void set(const P * pointer) { _pointer = pointer; }
498 : const P * _pointer;
499 :
500 : friend class OptionalMaterialPropertyProxy<Material, T, is_ad>;
501 : friend class OptionalMaterialPropertyProxy<MaterialPropertyInterface, T, is_ad>;
502 : };
503 :
504 : void dataStore(std::ostream & stream, PropertyValue & p, void * context);
505 : void dataLoad(std::istream & stream, PropertyValue & p, void * context);
506 :
507 : void dataStore(std::ostream & stream, MaterialProperties & v, void * context);
508 : void dataLoad(std::istream & stream, MaterialProperties & v, void * context);
509 :
510 : template <typename T>
511 : using OptionalMaterialProperty = GenericOptionalMaterialProperty<T, false>;
512 : template <typename T>
513 : using OptionalADMaterialProperty = GenericOptionalMaterialProperty<T, true>;
|