LCOV - code coverage report
Current view: top level - src/covariances - MaternHalfIntCovariance.C (source / functions) Hit Total Coverage
Test: idaholab/moose stochastic_tools: #33416 (b10b36) with base 9fbd27 Lines: 72 78 92.3 %
Date: 2026-07-23 16:21:17 Functions: 6 6 100.0 %
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             : #ifdef MOOSE_LIBTORCH_ENABLED
      10             : 
      11             : #include "MaternHalfIntCovariance.h"
      12             : #include "LibtorchUtils.h"
      13             : #include <cmath>
      14             : 
      15             : registerMooseObject("StochasticToolsApp", MaternHalfIntCovariance);
      16             : 
      17             : InputParameters
      18          48 : MaternHalfIntCovariance::validParams()
      19             : {
      20          48 :   InputParameters params = CovarianceFunctionBase::validParams();
      21          48 :   params.addClassDescription("Matern half-integer covariance function.");
      22          96 :   params.addRequiredParam<std::vector<Real>>("length_factor",
      23             :                                              "Length factors to use for Covariance Kernel");
      24          96 :   params.addRequiredParam<Real>("signal_variance",
      25             :                                 "Signal Variance ($\\sigma_f^2$) to use for kernel calculation.");
      26          96 :   params.addParam<Real>(
      27          96 :       "noise_variance", 0.0, "Noise Variance ($\\sigma_n^2$) to use for kernel calculation.");
      28          96 :   params.addRequiredParam<unsigned int>(
      29             :       "p", "Integer p to use for Matern Half Integer Covariance Kernel");
      30          48 :   return params;
      31           0 : }
      32             : 
      33          24 : MaternHalfIntCovariance::MaternHalfIntCovariance(const InputParameters & parameters)
      34             :   : CovarianceFunctionBase(parameters),
      35          24 :     _length_factor(addVectorRealHyperParameter(
      36             :         "length_factor", getParam<std::vector<Real>>("length_factor"), true)),
      37          24 :     _sigma_f_squared(
      38          72 :         addRealHyperParameter("signal_variance", getParam<Real>("signal_variance"), true)),
      39          24 :     _sigma_n_squared(
      40          72 :         addRealHyperParameter("noise_variance", getParam<Real>("noise_variance"), true)),
      41          72 :     _p(addRealHyperParameter("p", getParam<unsigned int>("p"), false))
      42             : {
      43          24 : }
      44             : 
      45             : void
      46       19524 : MaternHalfIntCovariance::computeCovarianceMatrix(torch::Tensor & K,
      47             :                                                  const torch::Tensor & x,
      48             :                                                  const torch::Tensor & xp,
      49             :                                                  const bool is_self_covariance) const
      50             : {
      51       19524 :   if ((unsigned)x.sizes()[1] != _length_factor.numel())
      52           0 :     mooseError("length_factor size does not match dimension of trainer input.");
      53             : 
      54       19524 :   maternHalfIntFunction(
      55             :       K, x, xp, _length_factor, _sigma_f_squared, _sigma_n_squared, _p, is_self_covariance);
      56       19524 : }
      57             : 
      58             : void
      59       35524 : MaternHalfIntCovariance::maternHalfIntFunction(torch::Tensor & K,
      60             :                                                const torch::Tensor & x,
      61             :                                                const torch::Tensor & xp,
      62             :                                                const torch::Tensor & length_factor,
      63             :                                                const torch::Tensor & sigma_f_squared,
      64             :                                                const torch::Tensor & sigma_n_squared,
      65             :                                                const torch::Tensor & p,
      66             :                                                const bool is_self_covariance)
      67             : {
      68       71048 :   const auto p_value = cast_int<unsigned int>(LibtorchUtils::toCPUContiguous(p).item<Real>());
      69             :   mooseAssert(x.sizes()[1] == xp.sizes()[1],
      70             :               "Number of parameters do not match in covariance kernel calculation");
      71             : 
      72             :   const auto l_factor = length_factor.unsqueeze(0);
      73       71048 :   K = torch::cdist(torch::div(x, l_factor), torch::div(xp, l_factor), 2.0);
      74       35524 :   const Real factor = std::sqrt(2 * p_value + 1);
      75       35524 :   const Real normalization = std::tgamma(p_value + 1) / std::tgamma(2 * p_value + 1);
      76             : 
      77       35524 :   auto summation = torch::zeros_like(K);
      78      142096 :   for (const auto tt : make_range(p_value + 1))
      79             :   {
      80             :     const Real coefficient =
      81      106572 :         std::tgamma(p_value + tt + 1) / (std::tgamma(tt + 1) * std::tgamma(p_value - tt + 1));
      82      426288 :     summation = summation + coefficient * torch::pow(2.0 * factor * K, Real(p_value - tt));
      83             :   }
      84             : 
      85       71048 :   K = sigma_f_squared * torch::exp(-factor * K) * normalization * summation;
      86       35524 :   if (is_self_covariance)
      87       35548 :     K.diagonal().add_(sigma_n_squared);
      88       35524 : }
      89             : 
      90             : bool
      91       48000 : MaternHalfIntCovariance::computedKdhyper(torch::Tensor & dKdhp,
      92             :                                          const torch::Tensor & x,
      93             :                                          const std::string & hyper_param_name,
      94             :                                          unsigned int ind) const
      95             : {
      96       48000 :   if (name().length() + 1 > hyper_param_name.length())
      97             :     return false;
      98             : 
      99       48000 :   const std::string name_without_prefix = hyper_param_name.substr(name().length() + 1);
     100             : 
     101       48000 :   if (name_without_prefix == "noise_variance")
     102             :   {
     103           0 :     const auto options = x.options().dtype(at::kDouble);
     104           0 :     maternHalfIntFunction(dKdhp,
     105             :                           x,
     106             :                           x,
     107             :                           _length_factor,
     108           0 :                           torch::tensor(0.0, options),
     109           0 :                           torch::tensor(1.0, options),
     110             :                           _p,
     111             :                           true);
     112             :     return true;
     113             :   }
     114             : 
     115       48000 :   if (name_without_prefix == "signal_variance")
     116             :   {
     117       16000 :     const auto options = x.options().dtype(at::kDouble);
     118       32000 :     maternHalfIntFunction(dKdhp,
     119             :                           x,
     120             :                           x,
     121             :                           _length_factor,
     122       32000 :                           torch::tensor(1.0, options),
     123       32000 :                           torch::tensor(0.0, options),
     124             :                           _p,
     125             :                           false);
     126             :     return true;
     127             :   }
     128             : 
     129       32000 :   if (name_without_prefix == "length_factor")
     130             :   {
     131       32000 :     computedKdlf(dKdhp, x, _length_factor, _sigma_f_squared, _p, ind);
     132             :     return true;
     133             :   }
     134             : 
     135             :   return false;
     136             : }
     137             : 
     138             : void
     139       32000 : MaternHalfIntCovariance::computedKdlf(torch::Tensor & K,
     140             :                                       const torch::Tensor & x,
     141             :                                       const torch::Tensor & length_factor,
     142             :                                       const torch::Tensor & sigma_f_squared,
     143             :                                       const torch::Tensor & p,
     144             :                                       const int ind)
     145             : {
     146       64000 :   const auto p_value = cast_int<unsigned int>(LibtorchUtils::toCPUContiguous(p).item<Real>());
     147             : 
     148             :   mooseAssert(ind < x.sizes()[1], "Incorrect length factor index");
     149             : 
     150             :   const auto l_factor = length_factor.unsqueeze(0);
     151       96000 :   const auto scaled_distance = torch::cdist(torch::div(x, l_factor), torch::div(x, l_factor), 2.0);
     152       32000 :   const auto nonzero_distance = scaled_distance > 0;
     153             :   const auto safe_scaled_distance =
     154       32000 :       torch::where(nonzero_distance, scaled_distance, torch::ones_like(scaled_distance));
     155       32000 :   const Real factor = std::sqrt(2 * p_value + 1);
     156       32000 :   const Real normalization = std::tgamma(p_value + 1) / std::tgamma(2 * p_value + 1);
     157             : 
     158       32000 :   auto summation = torch::zeros_like(safe_scaled_distance);
     159      128000 :   for (const auto tt : make_range(p_value + 1))
     160             :   {
     161             :     const Real coefficient =
     162       96000 :         std::tgamma(p_value + tt + 1) / (std::tgamma(tt + 1) * std::tgamma(p_value - tt + 1));
     163       96000 :     summation = summation +
     164      288000 :                 coefficient * torch::pow(2.0 * factor * safe_scaled_distance, Real(p_value - tt));
     165             :   }
     166             : 
     167       32000 :   auto summation_derivative = torch::zeros_like(safe_scaled_distance);
     168       96000 :   for (const auto tt : make_range(p_value))
     169             :   {
     170             :     const Real coefficient =
     171       64000 :         std::tgamma(p_value + tt + 1) / (std::tgamma(tt + 1) * std::tgamma(p_value - tt + 1));
     172             :     summation_derivative =
     173       64000 :         summation_derivative +
     174      128000 :         coefficient * 2.0 * factor * (p_value - tt) *
     175      128000 :             torch::pow(2.0 * factor * safe_scaled_distance, Real(p_value - tt - 1));
     176             :   }
     177             : 
     178       32000 :   const auto coordinate = x.select(1, ind);
     179             :   const auto coordinate_distance_squared =
     180       96000 :       torch::pow(coordinate.unsqueeze(1) - coordinate.unsqueeze(0), 2);
     181       32000 :   const auto length_factor_ind = length_factor.select(0, ind);
     182             :   const auto dr_dlength_factor =
     183       64000 :       -coordinate_distance_squared / (torch::pow(length_factor_ind, 3) * safe_scaled_distance);
     184       32000 :   const auto dK_dlength_factor = sigma_f_squared * normalization *
     185       64000 :                                  torch::exp(-factor * safe_scaled_distance) *
     186       64000 :                                  (summation_derivative - factor * summation) * dr_dlength_factor;
     187             : 
     188       64000 :   K = torch::where(nonzero_distance, dK_dlength_factor, torch::zeros_like(dK_dlength_factor));
     189       32000 : }
     190             : 
     191             : #endif

Generated by: LCOV version 1.14