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 590825 : PropertyValue(const id_type id) : _id(id) {}
44 :
45 583936 : 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 527492 : 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 590825 : MaterialPropertyBase(const PropertyValue::id_type id) : PropertyValue(id) {}
115 :
116 49894932 : bool isAD() const override final { return is_ad; }
117 :
118 : /**
119 : * @returns a read-only reference to the parameter value.
120 : */
121 4239 : 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 563665 : 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 131314911 : 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 1530724946 : 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 796032 : rawValueEqualityHelper(T1 & out, const T2 & in)
217 : {
218 796032 : out = MetaPhysicL::raw_value(in);
219 796032 : }
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 16 : MaterialPropertyBase<T, is_ad>::type() const
243 : {
244 16 : static const std::string type_name = MooseUtils::prettyCppType<T>();
245 16 : return type_name;
246 : }
247 :
248 : template <typename T, bool is_ad>
249 : inline void
250 1410138 : MaterialPropertyBase<T, is_ad>::resize(const std::size_t size)
251 : {
252 1410138 : _value.template resize</*value_initalize=*/true>(size);
253 1410138 : }
254 :
255 : template <typename T, bool is_ad>
256 : inline void
257 16760981 : 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 16760981 : if (rhs.isAD() == is_ad)
263 16760981 : _value[to_qp] =
264 16760981 : 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 16760981 : }
270 :
271 : template <typename T, bool is_ad>
272 : inline void
273 89829 : MaterialPropertyBase<T, is_ad>::store(std::ostream & stream)
274 : {
275 433015 : for (const auto i : index_range(_value))
276 343186 : storeHelper(stream, _value[i], nullptr);
277 89829 : }
278 :
279 : template <typename T, bool is_ad>
280 : inline void
281 58764 : MaterialPropertyBase<T, is_ad>::load(std::istream & stream)
282 : {
283 316276 : for (const auto i : index_range(_value))
284 257512 : loadHelper(stream, _value[i], nullptr);
285 58764 : }
286 :
287 : template <typename T, bool is_ad>
288 : inline void
289 33133935 : 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 33133935 : if (rhs.isAD() == is_ad)
296 : {
297 : mooseAssert(dynamic_cast<decltype(this)>(&rhs), "Expected same type is not the same");
298 32934719 : this->_value.swap(libMesh::cast_ptr<decltype(this)>(&rhs)->_value);
299 32934719 : 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 199216 : auto * different_type_prop = dynamic_cast<MaterialPropertyBase<T, !is_ad> *>(&rhs);
315 : mooseAssert(different_type_prop,
316 : "Wrong material property type T in MaterialPropertyBase<T, is_ad>::swap");
317 :
318 199216 : this->resize(different_type_prop->size());
319 995248 : for (const auto qp : make_range(this->size()))
320 796032 : moose::internal::rawValueEqualityHelper(this->_value[qp], (*different_type_prop)[qp]);
321 : }
322 :
323 : template <typename T, bool is_ad>
324 : inline const std::type_info &
325 0 : MaterialPropertyBase<T, is_ad>::typeID() const
326 : {
327 : static const auto & info = typeid(T);
328 0 : return info;
329 : }
330 :
331 : template <typename T, bool is_ad>
332 : std::unique_ptr<PropertyValue>
333 522364 : MaterialPropertyBase<T, is_ad>::clone(const std::size_t size) const
334 : {
335 522364 : auto prop = std::make_unique<MaterialProperty<T>>(this->id());
336 522364 : if (size)
337 522364 : prop->resize(size);
338 1044728 : return prop;
339 522364 : }
340 :
341 : template <typename T>
342 : class MaterialProperty : public MaterialPropertyBase<T, false>
343 : {
344 : public:
345 575884 : MaterialProperty(const PropertyValue::id_type id = PropertyValue::invalid_property_id)
346 575884 : : MaterialPropertyBase<T, false>(id)
347 : {
348 575884 : }
349 :
350 : private:
351 : /// private copy constructor to avoid shallow copying of material properties
352 : MaterialProperty(const MaterialProperty<T> & /*src*/)
353 : {
354 : mooseError("Material properties must be assigned to references (missing '&')");
355 : }
356 :
357 : /// private assignment operator to avoid shallow copying of material properties
358 : MaterialProperty<T> & operator=(const MaterialProperty<T> & /*rhs*/)
359 : {
360 : mooseError("Material properties must be assigned to references (missing '&')");
361 : }
362 : };
363 :
364 : template <typename T>
365 : class ADMaterialProperty : public MaterialPropertyBase<T, true>
366 : {
367 : public:
368 14941 : ADMaterialProperty(const PropertyValue::id_type id = PropertyValue::invalid_property_id)
369 14941 : : MaterialPropertyBase<T, true>(id)
370 : {
371 14941 : }
372 :
373 : using typename MaterialPropertyBase<T, true>::value_type;
374 :
375 : private:
376 : /// private copy constructor to avoid shallow copying of material properties
377 : ADMaterialProperty(const ADMaterialProperty<T> & /*src*/)
378 : {
379 : mooseError("Material properties must be assigned to references (missing '&')");
380 : }
381 :
382 : /// private assignment operator to avoid shallow copying of material properties
383 : ADMaterialProperty<T> & operator=(const ADMaterialProperty<T> & /*rhs*/)
384 : {
385 : mooseError("Material properties must be assigned to references (missing '&')");
386 : }
387 : };
388 :
389 : class MaterialData;
390 : class MaterialPropertyStorage;
391 :
392 : class MaterialProperties : public UniqueStorage<PropertyValue>
393 : {
394 : public:
395 : class WriteKey
396 : {
397 : friend class MaterialData;
398 : friend class MaterialPropertyStorage;
399 : friend void dataLoad(std::istream &, MaterialPropertyStorage &, void *);
400 :
401 1026743 : WriteKey() {}
402 : WriteKey(const WriteKey &) {}
403 : };
404 :
405 : /**
406 : * Resize items in this array, i.e. the number of values needed in PropertyValue array
407 : * @param n_qpoints The number of values needed to store (equals the the number of quadrature
408 : * points per mesh element)
409 : */
410 65041 : void resizeItems(const std::size_t n_qpoints, const WriteKey)
411 : {
412 136315 : for (const auto i : index_range(*this))
413 71274 : if (auto value = queryValue(i))
414 70097 : value->resize(n_qpoints);
415 65041 : }
416 :
417 383223 : void resize(const std::size_t size, const WriteKey)
418 : {
419 383223 : UniqueStorage<PropertyValue>::resize(size);
420 383223 : }
421 :
422 578479 : void setPointer(const std::size_t i, std::unique_ptr<PropertyValue> && ptr, const WriteKey)
423 : {
424 578479 : return UniqueStorage<PropertyValue>::setPointer(i, std::move(ptr));
425 : }
426 : };
427 :
428 : template <typename T, bool is_ad>
429 : struct GenericMaterialPropertyStruct
430 : {
431 : typedef MaterialProperty<T> type;
432 : };
433 :
434 : template <typename T>
435 : struct GenericMaterialPropertyStruct<T, true>
436 : {
437 : typedef ADMaterialProperty<T> type;
438 : };
439 :
440 : template <typename T, bool is_ad>
441 : using GenericMaterialProperty = typename GenericMaterialPropertyStruct<T, is_ad>::type;
442 :
443 : /**
444 : * Base class to facilitate storage using unique pointers
445 : */
446 : class GenericOptionalMaterialPropertyBase
447 : {
448 : public:
449 1326 : virtual ~GenericOptionalMaterialPropertyBase() {}
450 : };
451 :
452 : template <class M, typename T, bool is_ad>
453 : class OptionalMaterialPropertyProxy;
454 :
455 : /**
456 : * Wrapper around a material property pointer. Copying this wrapper is disabled
457 : * to enforce capture via reference. Used by the optional material property
458 : * API, which requires late binding updates of the stored pointer.
459 : */
460 : template <typename T, bool is_ad>
461 : class GenericOptionalMaterialProperty : public GenericOptionalMaterialPropertyBase
462 : {
463 : typedef GenericMaterialProperty<T, is_ad> P;
464 :
465 : public:
466 : GenericOptionalMaterialProperty(const P * pointer) : _pointer(pointer) {}
467 :
468 : /// no copy construction is permitted
469 : GenericOptionalMaterialProperty(const GenericOptionalMaterialProperty<T, is_ad> &) = delete;
470 : /// no copy assignment is permitted
471 : GenericOptionalMaterialProperty &
472 : operator=(const GenericOptionalMaterialProperty<T, is_ad> &) = delete;
473 :
474 : /// pass through operator[] to provide a similar API as MaterialProperty
475 67840 : const Moose::GenericType<T, is_ad> & operator[](const unsigned int i) const
476 : {
477 : // check if the optional property is valid in debug mode
478 : mooseAssert(
479 : _pointer,
480 : "Attempting to access an optional material property that was not provided by any material "
481 : "class. Make sure to check optional material properties before using them.");
482 67840 : return (*_pointer)[i];
483 : }
484 :
485 : /// pass through size calls
486 : unsigned int size() const { return (*_pointer).size(); }
487 :
488 : /// implicit cast to bool to check the if the material property exists
489 141924 : operator bool() const { return _pointer; }
490 :
491 : /// get a pointer to the underlying property (only do this in initialSetup or later)
492 : const P * get() const { return _pointer; }
493 :
494 : private:
495 : /// the default constructor is only called from the friend class
496 1530 : GenericOptionalMaterialProperty() : _pointer(nullptr) {}
497 :
498 : /// setting the pointer is only permitted through the optional material proxy system
499 638 : void set(const P * pointer) { _pointer = pointer; }
500 : const P * _pointer;
501 :
502 : friend class OptionalMaterialPropertyProxy<Material, T, is_ad>;
503 : friend class OptionalMaterialPropertyProxy<MaterialPropertyInterface, T, is_ad>;
504 : };
505 :
506 : void dataStore(std::ostream & stream, PropertyValue & p, void * context);
507 : void dataLoad(std::istream & stream, PropertyValue & p, void * context);
508 :
509 : void dataStore(std::ostream & stream, MaterialProperties & v, void * context);
510 : void dataLoad(std::istream & stream, MaterialProperties & v, void * context);
511 :
512 : template <typename T>
513 : using OptionalMaterialProperty = GenericOptionalMaterialProperty<T, false>;
514 : template <typename T>
515 : using OptionalADMaterialProperty = GenericOptionalMaterialProperty<T, true>;
|