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 "AuxiliarySystem.h" 13 : #include "MooseError.h" 14 : #include "MooseMesh.h" 15 : #include "MooseVariable.h" 16 : #include "UserObject.h" 17 : 18 : #include "libmesh/quadrature.h" 19 : 20 : #include "FunctionSeries.h" 21 : #include "MutableCoefficientsInterface.h" 22 : 23 : /** 24 : * This class interacts with a MooseApp through functional expansions. It is templated to allow the 25 : * inheritance of two dual classes that operate in a volume (FXVolumeUserObject) or on a boundary 26 : * (FXBoundaryFluxUserObject and FXBoundaryValueUserObject) 27 : * 28 : * It uses an instance of FunctionSeries to generate the orthonormal function series required to 29 : * generate the functional expansion coefficients. 30 : */ 31 : template <class IntegralBaseVariableUserObject> 32 : class FXIntegralBaseUserObject : public IntegralBaseVariableUserObject, 33 : public MutableCoefficientsInterface 34 : { 35 : public: 36 : FXIntegralBaseUserObject(const InputParameters & parameters); 37 : 38 : static InputParameters validParams(); 39 : 40 : /** 41 : * Return a reference to the underlying function series 42 : */ 43 : const FunctionSeries & getFunctionSeries() const; 44 : 45 : // Override from <IntegralBaseVariableUserObject> 46 : virtual Real getValue() const final; 47 : 48 : // Overrides from UserObject 49 : virtual void finalize() final; 50 : virtual void initialize() final; 51 : virtual Real spatialValue(const Point & location) const final; 52 : virtual void threadJoin(const UserObject & sibling) final; 53 : 54 : protected: 55 : // Policy-based design requires us to specify which inherited members we are using 56 : using IntegralBaseVariableUserObject::_communicator; 57 : using IntegralBaseVariableUserObject::_console; 58 : using IntegralBaseVariableUserObject::_coord; 59 : using IntegralBaseVariableUserObject::_integral_value; 60 : using IntegralBaseVariableUserObject::_JxW; 61 : using IntegralBaseVariableUserObject::_q_point; 62 : using IntegralBaseVariableUserObject::_qp; 63 : using IntegralBaseVariableUserObject::_variable; 64 : using IntegralBaseVariableUserObject::computeIntegral; 65 : using IntegralBaseVariableUserObject::computeQpIntegral; 66 : using IntegralBaseVariableUserObject::getFunction; 67 : using IntegralBaseVariableUserObject::name; 68 : 69 : // Override from <IntegralBaseVariableUserObject> 70 : virtual Real computeIntegral() final; 71 : 72 : /** 73 : * Get the centroid of the evaluated unit 74 : */ 75 : virtual Point getCentroid() const = 0; 76 : 77 : /** 78 : * Get the volume of the evaluated unit 79 : */ 80 : virtual Real getVolume() const = 0; 81 : 82 : /// History of the expansion coefficients for each solve 83 : std::vector<std::vector<Real>> _coefficient_history; 84 : 85 : /// Current coefficient partial sums 86 : std::vector<Real> _coefficient_partials; 87 : 88 : /// Reference to the underlying function series 89 : FunctionSeries & _function_series; 90 : 91 : /// Keep the expansion coefficients after each solve 92 : const bool _keep_history; 93 : 94 : /// Flag to prints the state of the zeroth instance in finalize() 95 : const bool _print_state; 96 : 97 : /// Volume of the standardized functional space of integration 98 : const Real _standardized_function_volume; 99 : 100 : /// Moose volume of evaluation 101 : Real _volume; 102 : }; 103 : 104 : template <class IntegralBaseVariableUserObject> 105 : InputParameters 106 549 : FXIntegralBaseUserObject<IntegralBaseVariableUserObject>::validParams() 107 : { 108 549 : InputParameters params = IntegralBaseVariableUserObject::validParams(); 109 549 : params += MutableCoefficientsInterface::validParams(); 110 : 111 549 : params.addClassDescription( 112 : "This UserObject interacts with a MooseApp through functional expansions."); 113 : 114 1098 : params.addRequiredParam<FunctionName>("function", 115 : "The name of the FunctionSeries \"Function\" object with " 116 : "which to generate this functional expansion."); 117 : 118 1098 : params.addParam<bool>( 119 1098 : "keep_history", false, "Keep the expansion coefficients from previous solves"); 120 : 121 1098 : params.addParam<bool>("print_state", false, "Print the state of the zeroth instance each solve"); 122 : 123 549 : return params; 124 0 : } 125 : 126 : template <class IntegralBaseVariableUserObject> 127 320 : FXIntegralBaseUserObject<IntegralBaseVariableUserObject>::FXIntegralBaseUserObject( 128 : const InputParameters & parameters) 129 : : IntegralBaseVariableUserObject(parameters), 130 : MutableCoefficientsInterface(this, parameters), 131 320 : _function_series( 132 320 : FunctionSeries::checkAndConvertFunction(getFunction("function"), this->getBase(), name())), 133 640 : _keep_history(UserObject::getParam<bool>("keep_history")), 134 640 : _print_state(UserObject::getParam<bool>("print_state")), 135 640 : _standardized_function_volume(_function_series.getStandardizedFunctionVolume()) 136 : { 137 : // Size the coefficient arrays 138 320 : _coefficient_partials.resize(_function_series.getNumberOfTerms(), 0.0); 139 320 : _coefficients.resize(_function_series.getNumberOfTerms(), 0.0); 140 320 : _characteristics = _function_series.getOrders(); 141 : 142 320 : if (!_keep_history) 143 320 : _coefficient_history.resize(0); 144 320 : } 145 : 146 : template <class IntegralBaseVariableUserObject> 147 : Real 148 142650 : FXIntegralBaseUserObject<IntegralBaseVariableUserObject>::computeIntegral() 149 : { 150 : Real sum = 0.0; 151 142650 : const Point centroid = getCentroid(); 152 : 153 : // Check to see if this element/side is within the valid boundaries 154 142650 : if (!_function_series.isInPhysicalBounds(centroid)) 155 : return 0.0; 156 : 157 : // Loop over the quadrature points 158 421512 : for (_qp = 0; _qp < _q_point.size(); ++_qp) 159 : { 160 : // Get the functional terms for a vectorized approach 161 281008 : _function_series.setLocation(_q_point[_qp]); 162 281008 : const std::vector<Real> & term_evaluations = _function_series.getGeneration(); 163 : 164 : // Evaluate the functional expansion coefficients at each quadrature point 165 281008 : const Real local_contribution = computeQpIntegral(); 166 281008 : const Real common_evaluation = local_contribution * _JxW[_qp] * _coord[_qp]; 167 1459440 : for (std::size_t c = 0; c < _coefficient_partials.size(); ++c) 168 1178432 : _coefficient_partials[c] += term_evaluations[c] * common_evaluation; 169 : 170 281008 : sum += local_contribution; 171 : } 172 : 173 140504 : _volume += getVolume(); 174 : 175 140504 : return sum; 176 : } 177 : 178 : template <class IntegralBaseVariableUserObject> 179 : void 180 14358 : FXIntegralBaseUserObject<IntegralBaseVariableUserObject>::finalize() 181 : { 182 : // Sum the coefficient arrays over all processes 183 14358 : _communicator.sum(_coefficient_partials); 184 14358 : _communicator.sum(_volume); 185 : 186 : // Normalize the volume of the functional expansion to the FX standard space 187 14358 : const Real volume_normalization = _standardized_function_volume / _volume; 188 73900 : for (auto & partial : _coefficient_partials) 189 59542 : partial *= volume_normalization; 190 : 191 : // We now have the completely evaluated coefficients 192 14358 : _coefficients = _coefficient_partials; 193 : 194 : // The average value is the same as the zeroth coefficient 195 14358 : _integral_value = _coefficient_partials[0]; 196 : 197 14358 : if (_keep_history) 198 0 : _coefficient_history.push_back(_coefficients); 199 : 200 14358 : if (_print_state) 201 : { 202 1626 : _function_series.setCoefficients(_coefficients); 203 2322 : _console << COLOR_YELLOW << _function_series << COLOR_DEFAULT << std::endl; 204 : } 205 14358 : } 206 : 207 : template <class IntegralBaseVariableUserObject> 208 : const FunctionSeries & 209 : FXIntegralBaseUserObject<IntegralBaseVariableUserObject>::getFunctionSeries() const 210 : { 211 : return _function_series; 212 : } 213 : 214 : template <class IntegralBaseVariableUserObject> 215 : Real 216 0 : FXIntegralBaseUserObject<IntegralBaseVariableUserObject>::getValue() const 217 : { 218 0 : return _integral_value; 219 : } 220 : 221 : template <class IntegralBaseVariableUserObject> 222 : void 223 18426 : FXIntegralBaseUserObject<IntegralBaseVariableUserObject>::initialize() 224 : { 225 18426 : IntegralBaseVariableUserObject::initialize(); 226 : 227 : // Clear the partial sums 228 96350 : for (auto & partial : _coefficient_partials) 229 77924 : partial = 0; 230 : 231 18426 : _volume = 0; 232 18426 : } 233 : 234 : template <class IntegralBaseVariableUserObject> 235 : void 236 4068 : FXIntegralBaseUserObject<IntegralBaseVariableUserObject>::threadJoin(const UserObject & s) 237 : { 238 : const FXIntegralBaseUserObject<IntegralBaseVariableUserObject> & sibling = 239 : static_cast<const FXIntegralBaseUserObject<IntegralBaseVariableUserObject> &>(s); 240 : 241 22450 : for (std::size_t c = 0; c < _coefficient_partials.size(); ++c) 242 18382 : _coefficient_partials[c] += sibling._coefficient_partials[c]; 243 : 244 4068 : _volume += sibling._volume; 245 4068 : } 246 : 247 : template <class IntegralBaseVariableUserObject> 248 : Real 249 0 : FXIntegralBaseUserObject<IntegralBaseVariableUserObject>::spatialValue(const Point & location) const 250 : { 251 0 : _function_series.setLocation(location); 252 : 253 0 : return _function_series.expand(_coefficients); 254 : }