LCOV - code coverage report
Current view: top level - src/surrogates - PolynomialChaos.C (source / functions) Hit Total Coverage
Test: idaholab/moose stochastic_tools: #31405 (292dce) with base fef103 Lines: 110 114 96.5 %
Date: 2025-09-04 07:57:52 Functions: 14 15 93.3 %
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 "PolynomialChaos.h"
      11             : #include "Sampler.h"
      12             : #include "CartesianProduct.h"
      13             : 
      14             : registerMooseObject("StochasticToolsApp", PolynomialChaos);
      15             : 
      16             : InputParameters
      17         918 : PolynomialChaos::validParams()
      18             : {
      19         918 :   InputParameters params = SurrogateModel::validParams();
      20         918 :   params.addClassDescription("Computes and evaluates polynomial chaos surrogate model.");
      21         918 :   return params;
      22           0 : }
      23             : 
      24         459 : PolynomialChaos::PolynomialChaos(const InputParameters & parameters)
      25             :   : SurrogateModel(parameters),
      26         459 :     _order(getModelData<unsigned int>("_order")),
      27         918 :     _ndim(getModelData<unsigned int>("_ndim")),
      28         918 :     _ncoeff(getModelData<std::size_t>("_ncoeff")),
      29         918 :     _tuple(getModelData<std::vector<std::vector<unsigned int>>>("_tuple")),
      30         918 :     _coeff(getModelData<std::vector<Real>>("_coeff")),
      31         459 :     _poly(
      32         918 :         getModelData<std::vector<std::unique_ptr<const PolynomialQuadrature::Polynomial>>>("_poly"))
      33             : {
      34         459 : }
      35             : 
      36             : Real
      37        6364 : PolynomialChaos::evaluate(const std::vector<Real> & x) const
      38             : {
      39             :   mooseAssert(x.size() == _ndim, "Number of inputted parameters does not match PC model.");
      40             : 
      41        6364 :   DenseMatrix<Real> poly_val(_ndim, _order);
      42             : 
      43             :   // Evaluate polynomials to avoid duplication
      44       20328 :   for (unsigned int d = 0; d < _ndim; ++d)
      45       75464 :     for (unsigned int i = 0; i < _order; ++i)
      46       61500 :       poly_val(d, i) = _poly[d]->compute(i, x[d], /*normalize =*/false);
      47             : 
      48             :   Real val = 0;
      49      140184 :   for (std::size_t i = 0; i < _ncoeff; ++i)
      50             :   {
      51      133820 :     Real tmp = _coeff[i];
      52      499800 :     for (unsigned int d = 0; d < _ndim; ++d)
      53      365980 :       tmp *= poly_val(d, _tuple[i][d]);
      54      133820 :     val += tmp;
      55             :   }
      56             : 
      57        6364 :   return val;
      58        6364 : }
      59             : 
      60             : const std::vector<std::vector<unsigned int>> &
      61          88 : PolynomialChaos::getPolynomialOrders() const
      62             : {
      63          88 :   return _tuple;
      64             : }
      65             : 
      66             : unsigned
      67           0 : PolynomialChaos::getPolynomialOrder(const unsigned int dim, const unsigned int i) const
      68             : {
      69           0 :   return _tuple[i][dim];
      70             : }
      71             : 
      72             : const std::vector<Real> &
      73          88 : PolynomialChaos::getCoefficients() const
      74             : {
      75          88 :   return _coeff;
      76             : }
      77             : 
      78             : Real
      79          88 : PolynomialChaos::computeMean() const
      80             : {
      81             :   mooseAssert(_coeff.size() > 0, "The coefficient matrix is empty.");
      82          88 :   return _coeff[0];
      83             : }
      84             : 
      85             : Real
      86         323 : PolynomialChaos::computeStandardDeviation() const
      87             : {
      88             :   Real var = 0;
      89      103088 :   for (std::size_t i = 1; i < _ncoeff; ++i)
      90             :   {
      91             :     Real norm = 1.0;
      92      519435 :     for (std::size_t d = 0; d < _ndim; ++d)
      93      416670 :       norm *= _poly[d]->innerProduct(_tuple[i][d]);
      94      102765 :     var += _coeff[i] * _coeff[i] * norm;
      95             :   }
      96             : 
      97         323 :   return std::sqrt(var);
      98             : }
      99             : 
     100             : Real
     101          68 : PolynomialChaos::powerExpectation(const unsigned int n) const
     102             : {
     103             :   std::vector<StochasticTools::WeightedCartesianProduct<unsigned int, Real>> order;
     104          68 :   order.reserve(_ndim);
     105          68 :   std::vector<std::vector<Real>> c_1d(n, std::vector<Real>(_coeff.begin() + 1, _coeff.end()));
     106         204 :   for (unsigned int d = 0; d < _ndim; ++d)
     107             :   {
     108         136 :     std::vector<std::vector<unsigned int>> order_1d(n, std::vector<unsigned int>(_ncoeff - 1));
     109        2040 :     for (std::size_t i = 1; i < _ncoeff; ++i)
     110        8568 :       for (unsigned int m = 0; m < n; ++m)
     111        6664 :         order_1d[m][i - 1] = _tuple[i][d];
     112         136 :     order.push_back(StochasticTools::WeightedCartesianProduct<unsigned int, Real>(order_1d, c_1d));
     113         136 :   }
     114             : 
     115             :   dof_id_type n_local, st_local, end_local;
     116          68 :   MooseUtils::linearPartitionItems(
     117             :       order[0].numRows(), n_processors(), processor_id(), n_local, st_local, end_local);
     118             : 
     119             :   Real val = 0;
     120      905588 :   for (dof_id_type i = st_local; i < end_local; ++i)
     121             :   {
     122      905520 :     Real tmp = order[0].computeWeight(i);
     123     1336995 :     for (unsigned int d = 0; d < _ndim; ++d)
     124             :     {
     125     1246971 :       if (MooseUtils::absoluteFuzzyEqual(tmp, 0.0))
     126             :         break;
     127      431475 :       std::vector<unsigned int> comb(n);
     128     2112671 :       for (unsigned int m = 0; m < n; ++m)
     129     1681196 :         comb[m] = order[d].computeValue(i, m);
     130      431475 :       tmp *= _poly[d]->productIntegral(comb);
     131      431475 :     }
     132      905520 :     val += tmp;
     133             :   }
     134             : 
     135          68 :   return val;
     136          68 : }
     137             : 
     138             : Real
     139        4944 : PolynomialChaos::computeDerivative(const unsigned int dim, const std::vector<Real> & x) const
     140             : {
     141        4944 :   return computePartialDerivative({dim}, x);
     142             : }
     143             : 
     144             : Real
     145        4944 : PolynomialChaos::computePartialDerivative(const std::vector<unsigned int> & dim,
     146             :                                           const std::vector<Real> & x) const
     147             : {
     148             :   mooseAssert(x.size() == _ndim, "Number of inputted parameters does not match PC model.");
     149             : 
     150        4944 :   std::vector<unsigned int> grad(_ndim);
     151        9888 :   for (const auto & d : dim)
     152             :   {
     153             :     mooseAssert(d < _ndim, "Specified dimension is greater than total number of parameters.");
     154        4944 :     grad[d]++;
     155             :   }
     156             : 
     157        4944 :   DenseMatrix<Real> poly_val(_ndim, _order);
     158             : 
     159             :   // Evaluate polynomials to avoid duplication
     160       15376 :   for (unsigned int d = 0; d < _ndim; ++d)
     161       68032 :     for (unsigned int i = 0; i < _order; ++i)
     162       57600 :       poly_val(d, i) = _poly[d]->computeDerivative(i, x[d], grad[d]);
     163             : 
     164             :   Real val = 0;
     165      269504 :   for (std::size_t i = 0; i < _ncoeff; ++i)
     166             :   {
     167      264560 :     Real tmp = _coeff[i];
     168     1182640 :     for (unsigned int d = 0; d < _ndim; ++d)
     169      918080 :       tmp *= poly_val(d, _tuple[i][d]);
     170      264560 :     val += tmp;
     171             :   }
     172             : 
     173        4944 :   return val;
     174        4944 : }
     175             : 
     176             : Real
     177        1751 : PolynomialChaos::computeSobolIndex(const std::set<unsigned int> & ind) const
     178             : {
     179        1751 :   linearPartitionCoefficients();
     180             : 
     181             :   // If set is empty, compute mean
     182        1751 :   if (ind.empty())
     183           0 :     return computeMean();
     184             : 
     185             :   // Do some sanity checks in debug
     186             :   mooseAssert(ind.size() <= _ndim, "Number of indices is greater than number of parameters.");
     187             :   mooseAssert(*ind.rbegin() < _ndim, "Maximum index provided exceeds number of parameters.");
     188             : 
     189             :   Real val = 0.0;
     190      374563 :   for (dof_id_type i = _local_coeff_begin; i < _local_coeff_end; ++i)
     191             :   {
     192      372812 :     Real tmp = _coeff[i] * _coeff[i];
     193      696520 :     for (unsigned int d = 0; d < _ndim; ++d)
     194             :     {
     195      683353 :       if ((ind.find(d) != ind.end() && _tuple[i][d] > 0) ||
     196      441584 :           (ind.find(d) == ind.end() && _tuple[i][d] == 0))
     197             :       {
     198      323708 :         tmp *= _poly[d]->innerProduct(_tuple[i][d]);
     199             :       }
     200             :       else
     201             :       {
     202             :         tmp = 0.0;
     203             :         break;
     204             :       }
     205             :     }
     206      372812 :     val += tmp;
     207             :   }
     208             : 
     209             :   return val;
     210             : }
     211             : 
     212             : Real
     213         578 : PolynomialChaos::computeSobolTotal(const unsigned int dim) const
     214             : {
     215         578 :   linearPartitionCoefficients();
     216             : 
     217             :   // Do some sanity checks in debug
     218             :   mooseAssert(dim < _ndim, "Requested dimension is greater than number of parameters.");
     219             : 
     220             :   Real val = 0.0;
     221      143050 :   for (dof_id_type i = _local_coeff_begin; i < _local_coeff_end; ++i)
     222      142472 :     if (_tuple[i][dim] > 0)
     223       92664 :       val += _coeff[i] * _coeff[i] * _poly[dim]->innerProduct(_tuple[i][dim]);
     224             : 
     225         578 :   return val;
     226             : }
     227             : 
     228             : void
     229        2329 : PolynomialChaos::linearPartitionCoefficients() const
     230             : {
     231        2329 :   if (_n_local_coeff == std::numeric_limits<dof_id_type>::max())
     232         119 :     MooseUtils::linearPartitionItems(_ncoeff,
     233             :                                      n_processors(),
     234             :                                      processor_id(),
     235         119 :                                      _n_local_coeff,
     236         119 :                                      _local_coeff_begin,
     237         119 :                                      _local_coeff_end);
     238        2329 : }
     239             : 
     240             : void
     241          88 : PolynomialChaos::store(nlohmann::json & json) const
     242             : {
     243         176 :   json["order"] = _order;
     244         176 :   json["ndim"] = getNumberOfParameters();
     245          88 :   json["ncoeff"] = getNumberofCoefficients();
     246          88 :   json["tuple"] = getPolynomialOrders();
     247          88 :   json["coeff"] = getCoefficients();
     248         352 :   for (const auto & p : _poly)
     249             :   {
     250             :     nlohmann::json jsonp;
     251         264 :     p->store(jsonp);
     252         264 :     json["poly"].push_back(jsonp);
     253             :   }
     254          88 : }

Generated by: LCOV version 1.14