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 : #ifdef MOOSE_MFEM_ENABLED 11 : 12 : #pragma once 13 : 14 : #include <map> 15 : #include <string> 16 : #include <tuple> 17 : #include <utility> 18 : #include <variant> 19 : #include <vector> 20 : 21 : #include "MooseException.h" 22 : #include "MooseError.h" 23 : 24 : #include "libmesh/utility.h" 25 : 26 : namespace Moose::MFEM 27 : { 28 : 29 : /** 30 : * Class to manage MFEM coefficient objects representing material 31 : * properties. It can build up piecewise coefficients representing 32 : * properties defined across multiple materials. 33 : */ 34 : template <class T, class Tpw> 35 : class CoefficientMap 36 : { 37 : public: 38 5552 : CoefficientMap() = default; 39 : 40 : /// Make arbitrary coefficients which will be tracked by this object 41 : template <class P, class... Args> 42 15263 : std::shared_ptr<P> make(Args &&... args) 43 : { 44 15263 : auto result = std::make_shared<P>(args...); 45 15263 : this->_iterable_coefficients.push_back(result); 46 15263 : return result; 47 0 : } 48 : 49 : /// Add a named global coefficient. It must have been created with 50 : /// the `make` method on this object. 51 15063 : void addCoefficient(const std::string & name, std::shared_ptr<T> coeff) 52 : { 53 : mooseAssert(std::find(this->_iterable_coefficients.cbegin(), 54 : this->_iterable_coefficients.cend(), 55 : coeff) != this->_iterable_coefficients.cend(), 56 : "Coefficient object was not created by this CoefficientMap."); 57 : 58 15063 : const auto [_, inserted] = this->_coefficients.emplace(name, std::move(coeff)); 59 15063 : if (!inserted) 60 24 : mooseError("Coefficient with name '" + name + "' already present in CoefficientMap object"); 61 15055 : } 62 : 63 : /// Add piecewise material property. The coefficient must have been created with the `make` method on this object. 64 : /// 65 : /// Note: If you attempt to overwrite an existing block then an exception will be thrown and data 66 : /// for that property will be left in an undefined state. 67 451 : void addPiecewiseBlocks(const std::string & name, 68 : std::shared_ptr<T> coeff, 69 : const std::vector<std::string> & blocks) 70 : { 71 : // If list of blocks is empty then treat as a global coefficient 72 451 : if (blocks.size() == 0) 73 : { 74 130 : this->addCoefficient(name, coeff); 75 130 : return; 76 : } 77 : 78 : // Initialise property with empty coefficients, if it does not already exist 79 321 : if (!this->hasCoefficient(name)) 80 234 : this->_coefficients.insert({name, this->emptyPWData(coeff)}); 81 321 : PWData * data = std::get_if<PWData>(&this->_coefficients[name]); 82 : // Throw an exception if the data is not piecewise 83 321 : if (!data) 84 6 : mooseError("Global coefficient with name '" + name + "' already present in CoefficientMap"); 85 : mooseAssert(std::find(this->_iterable_coefficients.cbegin(), 86 : this->_iterable_coefficients.cend(), 87 : coeff) != this->_iterable_coefficients.cend(), 88 : "Coefficient object was not created by the appropriate coefficient manager."); 89 319 : auto & [pw_coeff, coeff_map] = *data; 90 327 : this->checkPWData(coeff, pw_coeff, name); 91 : 92 777 : for (const auto & block : blocks) 93 : { 94 464 : if (coeff_map.count(block) > 0) 95 10 : mooseError("Property with name '" + name + "' already assigned to block " + block + 96 : " in CoefficientMap object"); 97 462 : coeff_map[block] = coeff; 98 462 : pw_coeff->UpdateCoefficient(std::stoi(block), *coeff); 99 : } 100 : } 101 : 102 14 : T & getCoefficient(const std::string & name) { return *this->getCoefficientPtr(name); } 103 : 104 9940 : std::shared_ptr<T> getCoefficientPtr(const std::string & name) 105 : { 106 : try 107 : { 108 9940 : auto & coeff = this->_coefficients.at(name); 109 : try 110 : { 111 9934 : return std::get<std::shared_ptr<T>>(coeff); 112 : } 113 1088 : catch (const std::bad_variant_access &) 114 : { 115 544 : return std::get<0>(std::get<PWData>(coeff)); 116 : } 117 : } 118 12 : catch (const std::out_of_range &) 119 : { 120 18 : mooseError("Property with name '" + name + "' has not been declared."); 121 : } 122 : } 123 : 124 10469 : bool hasCoefficient(const std::string & name) const 125 : { 126 10469 : return this->_coefficients.count(name) > 0; 127 : } 128 : 129 260 : bool propertyDefinedOnBlock(const std::string & name, const std::string & block) const 130 : { 131 260 : if (!this->hasCoefficient(name)) 132 156 : return false; 133 104 : auto & coeff = libmesh_map_find(this->_coefficients, name); 134 104 : if (std::holds_alternative<std::shared_ptr<T>>(coeff)) 135 42 : return true; 136 62 : auto block_map = std::get<1>(std::get<PWData>(coeff)); 137 62 : return block_map.count(block) > 0; 138 62 : } 139 : 140 3144 : void setTime(const mfem::real_t time) 141 : { 142 14496 : for (auto & coef : this->_iterable_coefficients) 143 11352 : coef->SetTime(time); 144 3144 : } 145 : 146 : private: 147 : using PWData = std::tuple<std::shared_ptr<Tpw>, std::map<const std::string, std::shared_ptr<T>>>; 148 : std::map<const std::string, std::variant<std::shared_ptr<T>, PWData>> _coefficients; 149 : std::vector<std::shared_ptr<T>> _iterable_coefficients; 150 : 151 169 : PWData emptyPWData(std::shared_ptr<T> /*coeff*/) 152 : { 153 : return std::make_tuple(this->template make<Tpw>(), 154 169 : std::map<const std::string, std::shared_ptr<T>>()); 155 : } 156 223 : void checkPWData(std::shared_ptr<T> /*coeff*/, 157 : std::shared_ptr<Tpw> /* existing_pw*/, 158 : const std::string & /*name*/) 159 : { 160 223 : } 161 : }; 162 : 163 : using ScalarMap = CoefficientMap<mfem::Coefficient, mfem::PWCoefficient>; 164 : using VectorMap = CoefficientMap<mfem::VectorCoefficient, mfem::PWVectorCoefficient>; 165 : using MatrixMap = CoefficientMap<mfem::MatrixCoefficient, mfem::PWMatrixCoefficient>; 166 : 167 : template <> 168 : VectorMap::PWData VectorMap::emptyPWData(std::shared_ptr<mfem::VectorCoefficient> coeff); 169 : 170 : template <> 171 : MatrixMap::PWData MatrixMap::emptyPWData(std::shared_ptr<mfem::MatrixCoefficient> coeff); 172 : 173 : template <> 174 : void VectorMap::checkPWData(std::shared_ptr<mfem::VectorCoefficient> coeff, 175 : std::shared_ptr<mfem::PWVectorCoefficient> existing_pw, 176 : const std::string & name); 177 : 178 : template <> 179 : void MatrixMap::checkPWData(std::shared_ptr<mfem::MatrixCoefficient> coeff, 180 : std::shared_ptr<mfem::PWMatrixCoefficient> existing_pw, 181 : const std::string & name); 182 : } // namespace Moose::MFEM 183 : 184 : #endif