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 : #include "CompositeSeriesBasisInterface.h" 11 : #include "Legendre.h" 12 : 13 : #include <memory> 14 : 15 : /* 16 : * Default constructor creates a functional basis with one term. In order for the _series member to 17 : * be initialized, we initialized it with a Legendre series. 18 : */ 19 0 : CompositeSeriesBasisInterface::CompositeSeriesBasisInterface(const std::string & who_is_using_me) 20 0 : : FunctionalBasisInterface(1), _who_is_using_me(who_is_using_me) 21 : { 22 0 : _series.push_back(std::make_unique<Legendre>()); 23 0 : } 24 : 25 : /* 26 : * The non-default constructor is where we actually loop over the series_types and initialize 27 : * pointers to those members. Because we won't know the number of terms until the end of the body 28 : * of the constructor, we need to call the default FunctionalBasisInterface constructor. 29 : */ 30 396 : CompositeSeriesBasisInterface::CompositeSeriesBasisInterface( 31 : const std::vector<std::size_t> & orders, 32 : std::vector<MooseEnum> series_types, 33 396 : const std::string & who_is_using_me) 34 396 : : FunctionalBasisInterface(), _series_types(series_types), _who_is_using_me(who_is_using_me) 35 : { 36 396 : if (orders.size() != _series_types.size()) 37 2 : mooseError(_who_is_using_me, 38 : " calling CSBI::CSBI(...): Incorrect number of 'orders' specified for " 39 : "'FunctionSeries'! Check that 'orders' is the correct length and no invalid " 40 : "enumerations are specified for the series."); 41 394 : } 42 : 43 : void 44 281014 : CompositeSeriesBasisInterface::evaluateGeneration() 45 : { 46 : /* 47 : * Evaluate the generation versions of each of the single series, and collect the results before 48 : * passing them to evaluateSeries, where they will be multiplied together correctly and stored in 49 : * the composite series basis evaluation. 50 : */ 51 : std::vector<std::vector<Real>> single_series_basis_evaluation; 52 562037 : for (auto & series : _series) 53 281023 : single_series_basis_evaluation.push_back(series->getAllGeneration()); 54 : 55 281014 : evaluateSeries(single_series_basis_evaluation); 56 281014 : } 57 : 58 : void 59 441150 : CompositeSeriesBasisInterface::evaluateSeries( 60 : const std::vector<std::vector<Real>> & single_series_basis_evaluations) 61 : { 62 : /* 63 : * Appropriate number of loops based on 1-D, 2-D, or 3-D to multiply the basis evaluations of the 64 : * single series together to form the basis evaluation of the entire composite series. 65 : */ 66 : Real f1, f2, f3; 67 : std::size_t term = 0; 68 : 69 441150 : if (single_series_basis_evaluations.size() == 1) 70 2312948 : for (std::size_t i = 0; i < _series[0]->getNumberOfTerms(); ++i, ++term) 71 1871812 : save(term, single_series_basis_evaluations[0][i]); 72 : 73 441150 : if (single_series_basis_evaluations.size() == 2) 74 108 : for (std::size_t i = 0; i < _series[0]->getNumberOfTerms(); ++i) 75 : { 76 101 : f1 = single_series_basis_evaluations[0][i]; 77 16622 : for (std::size_t j = 0; j < _series[1]->getNumberOfTerms(); ++j, ++term) 78 : { 79 16521 : f2 = single_series_basis_evaluations[1][j]; 80 16521 : save(term, f1 * f2); 81 : } 82 : } 83 : 84 441150 : if (single_series_basis_evaluations.size() == 3) 85 102 : for (std::size_t i = 0; i < _series[0]->getNumberOfTerms(); ++i) 86 : { 87 95 : f1 = single_series_basis_evaluations[0][i]; 88 2105 : for (std::size_t j = 0; j < _series[1]->getNumberOfTerms(); ++j) 89 : { 90 2010 : f2 = single_series_basis_evaluations[1][j]; 91 47670 : for (std::size_t k = 0; k < _series[2]->getNumberOfTerms(); ++k, ++term) 92 : { 93 45660 : f3 = single_series_basis_evaluations[2][k]; 94 45660 : save(term, f1 * f2 * f3); 95 : } 96 : } 97 : } 98 441150 : } 99 : 100 : void 101 160136 : CompositeSeriesBasisInterface::evaluateExpansion() 102 : { 103 : /* 104 : * Evaluate the expansion versions of each of the single series, and collect the results before 105 : * passing them to evaluateSeries, where they will be multiplied together correctly and stored in 106 : * the composite series basis evaluation. 107 : */ 108 : std::vector<std::vector<Real>> single_series_basis_evaluation; 109 320284 : for (auto & series : _series) 110 160148 : single_series_basis_evaluation.push_back(series->getAllExpansion()); 111 : 112 160136 : evaluateSeries(single_series_basis_evaluation); 113 160136 : } 114 : 115 : const std::vector<Real> & 116 0 : CompositeSeriesBasisInterface::getStandardizedFunctionLimits() const 117 : { 118 0 : static const std::vector<Real> function_limits = combineStandardizedFunctionLimits(); 119 : 120 0 : return function_limits; 121 : } 122 : 123 : Real 124 320 : CompositeSeriesBasisInterface::getStandardizedFunctionVolume() const 125 : { 126 : Real function_volume = 1.0; 127 : 128 640 : for (auto & series : _series) 129 320 : function_volume *= series->getStandardizedFunctionVolume(); 130 : 131 320 : return function_volume; 132 : } 133 : 134 : std::vector<Real> 135 0 : CompositeSeriesBasisInterface::combineStandardizedFunctionLimits() const 136 : { 137 : std::vector<Real> function_limits; 138 : 139 0 : for (auto & series : _series) 140 : { 141 0 : std::vector<Real> local_limits = series->getStandardizedFunctionLimits(); 142 0 : for (auto & limit : local_limits) 143 0 : function_limits.push_back(limit); 144 0 : } 145 : 146 0 : return function_limits; 147 0 : } 148 : 149 : void 150 1626 : CompositeSeriesBasisInterface::formatCoefficients(std::ostream & stream, 151 : const std::vector<Real> & coefficients) const 152 : { 153 : // clang-format off 154 1626 : std::ostringstream formatted, domains, orders; 155 : std::size_t term = 0; 156 : 157 : stream << "---------------- Coefficients ----------------\n" 158 1626 : << " == Subindices ==\n"; 159 : 160 1626 : if (_series_types.size() == 1) 161 : { 162 3252 : orders << " Orders: " << std::setw(3) << _series[0]->getOrder(0) << "\n"; 163 1626 : domains << " == Index == " << std::setw(3) << _series[0]->_domains[0] 164 : << " === Value ===\n" 165 1626 : << "----------------------------------------------\n"; 166 : 167 8130 : for (std::size_t i = 0; i < _series[0]->getNumberOfTerms(); ++i, ++term) 168 6504 : formatted << " " << std::setw(4) << term 169 6504 : << " " << std::setw(3) << i 170 6504 : << " " << std::setw(12) << coefficients[term] << "\n"; 171 : } 172 0 : else if (_series_types.size() == 2) 173 : { 174 0 : orders << " Orders: " << std::setw(3) << _series[0]->getOrder(0) 175 0 : << " " << std::setw(3) << _series[1]->getOrder(0) << "\n"; 176 0 : domains << " == Index == " << std::setw(3) << _series[0]->_domains[0] 177 0 : << " " << std::setw(3) << _series[1]->_domains[0] 178 : << " === Value ===\n" 179 0 : << "----------------------------------------------\n"; 180 : 181 0 : for (std::size_t i = 0; i < _series[0]->getNumberOfTerms(); ++i) 182 : { 183 0 : for (std::size_t j = 0; j < _series[1]->getNumberOfTerms(); ++j, ++term) 184 0 : formatted << " " << std::setw(4) << term 185 0 : << " " << std::setw(3) << i 186 0 : << " " << std::setw(3) << j 187 0 : << " " << std::setw(12) << coefficients[term] << "\n"; 188 : } 189 : } 190 0 : else if (_series_types.size() == 3) 191 : { 192 0 : orders << " Orders: " << std::setw(3) << _series[0]->getOrder(0) 193 0 : << " " << std::setw(3) << _series[1]->getOrder(0) 194 0 : << " " << std::setw(3) << _series[2]->getOrder(0) << "\n"; 195 0 : domains << " == Index == " << std::setw(3) << _series[0]->_domains[0] 196 0 : << " " << std::setw(3) << _series[1]->_domains[0] 197 0 : << " " << std::setw(3) << _series[2]->_domains[0] 198 : << " === Value ===\n" 199 0 : << "----------------------------------------------\n"; 200 : 201 0 : for (std::size_t i = 0; i < _series[0]->getNumberOfTerms(); ++i) 202 : { 203 0 : for (std::size_t j = 0; j < _series[1]->getNumberOfTerms(); ++j) 204 : { 205 0 : for (std::size_t k = 0; k < _series[2]->getNumberOfTerms(); ++k, ++term) 206 0 : formatted << " " << std::setw(4) << term 207 0 : << " " << std::setw(3) << i 208 0 : << " " << std::setw(3) << j 209 0 : << " " << std::setw(3) << k 210 0 : << " " << std::setw(12) << coefficients[term] << "\n"; 211 : } 212 : } 213 : } 214 : // clang-format on 215 : 216 1626 : stream << orders.str() << domains.str() << formatted.str() << std::flush; 217 1626 : } 218 : 219 : bool 220 407142 : CompositeSeriesBasisInterface::isCacheInvalid() const 221 : { 222 : /* 223 : * If any one of the single series have an invalid cache, then we need to re-evaluate the entire 224 : * composite series because the terms are multiplied. 225 : */ 226 407142 : for (auto & series : _series) 227 407142 : if (series->isCacheInvalid()) 228 : return true; 229 : 230 : return false; 231 : } 232 : 233 : bool 234 307070 : CompositeSeriesBasisInterface::isInPhysicalBounds(const Point & point) const 235 : { 236 : /* 237 : * A point is in the physical bounds of the composite series if it is in the physical bounds of 238 : * each of the single series 239 : */ 240 607702 : for (auto & series : _series) 241 307070 : if (!series->isInPhysicalBounds(point)) 242 : return false; 243 : 244 : return true; 245 : } 246 : 247 : void 248 392 : CompositeSeriesBasisInterface::setNumberOfTerms() 249 : { 250 : unsigned int number_of_terms = 1; 251 : 252 : // Accumulate the number of terms for each series 253 796 : for (auto & series : _series) 254 404 : number_of_terms *= series->getNumberOfTerms(); 255 : 256 392 : _number_of_terms = number_of_terms; 257 : 258 : /* 259 : * The length of the _basis_evaluation depends on the number of terms, so we need to clear the 260 : * entries because the number of terms in the composite series may have changed. 261 : */ 262 392 : clearBasisEvaluation(_number_of_terms); 263 392 : } 264 : 265 : void 266 0 : CompositeSeriesBasisInterface::setOrder(const std::vector<std::size_t> & orders) 267 : { 268 : // One order must be specified for each single series 269 0 : if (orders.size() != _series.size()) 270 0 : mooseError(_who_is_using_me, 271 : " calling CSBI::setOrder(): Mismatch between the orders provided and the number of " 272 : "series in the functional basis!"); 273 : 274 : // Update the orders of each of the single series 275 0 : for (std::size_t i = 0; i < _series.size(); ++i) 276 0 : _series[i]->setOrder({orders[i]}); 277 : 278 : /* 279 : * After changing the order of each single series, we need to recompute the number of terms by 280 : * looping over those single series. This also clears the basis evaluation of the composite 281 : * series. 282 : */ 283 0 : setNumberOfTerms(); 284 0 : } 285 : 286 : void 287 441144 : CompositeSeriesBasisInterface::setLocation(const Point & point) 288 : { 289 : // Return if this point is the same as the last at which the composite series was evaluated 290 441144 : if (point.absolute_fuzzy_equals(_previous_point)) 291 : return; 292 : 293 : // Set the location of each of the single series 294 882132 : for (auto & series : _series) 295 441072 : series->setLocation(point); 296 : 297 : // Store the previous point 298 441060 : _previous_point = point; 299 : } 300 : 301 360 : CompositeSeriesBasisInterface::~CompositeSeriesBasisInterface() {}