LCOV - code coverage report
Current view: top level - src/series - CompositeSeriesBasisInterface.C (source / functions) Hit Total Coverage
Test: idaholab/moose functional_expansion_tools: #31405 (292dce) with base fef103 Lines: 70 120 58.3 %
Date: 2025-09-04 07:53:29 Functions: 11 16 68.8 %
Legend: Lines: hit not hit

          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() {}

Generated by: LCOV version 1.14