LCOV - code coverage report
Current view: top level - src/functions - NearestReporterCoordinatesFunction.C (source / functions) Hit Total Coverage
Test: idaholab/moose optimization: #31405 (292dce) with base fef103 Lines: 74 87 85.1 %
Date: 2025-09-04 07:54:57 Functions: 7 9 77.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 "NearestReporterCoordinatesFunction.h"
      11             : 
      12             : registerMooseObject("OptimizationApp", NearestReporterCoordinatesFunction);
      13             : 
      14             : InputParameters
      15         456 : NearestReporterCoordinatesFunction::validParams()
      16             : {
      17         456 :   InputParameters params = OptimizationFunction::validParams();
      18         456 :   params.addClassDescription(
      19             :       "This Function finds the nearest point in the specified vectors of coordinates and returns "
      20             :       "the values specified in the vector of values at the index of the nearest point.  All the "
      21             :       "vectors must be specified using either vector postprocessors or reporter vectors. This "
      22             :       "function interpolates linearly in time with transient data.");
      23         912 :   params.addParam<ReporterName>("x_coord_name",
      24             :                                 "Name of vector-postprocessor or reporter vector containing "
      25             :                                 "x-coordinate of points, default is assumed to be all 0s.");
      26         912 :   params.addParam<ReporterName>("y_coord_name",
      27             :                                 "Name of vector-postprocessor or reporter vector containing "
      28             :                                 "y-coordinate of points, default is assumed to be all 0s.");
      29         912 :   params.addParam<ReporterName>("z_coord_name",
      30             :                                 "Name of vector-postprocessor or reporter vector containing "
      31             :                                 "z-coordinate of points, default is assumed to be all 0s.");
      32         912 :   params.addParam<ReporterName>("time_name",
      33             :                                 "Name of vector-postprocessor or reporter vector containing time, "
      34             :                                 "default is assumed to be all 0s.");
      35         912 :   params.addRequiredParam<ReporterName>(
      36             :       "value_name", "Name of vector-postprocessor or reporter vector containing value data.");
      37         456 :   return params;
      38           0 : }
      39             : 
      40         238 : NearestReporterCoordinatesFunction::NearestReporterCoordinatesFunction(
      41         238 :     const InputParameters & parameters)
      42             :   : OptimizationFunction(parameters),
      43             :     ReporterInterface(this),
      44         476 :     _coordx(isParamValid("x_coord_name") ? getReporterValue<std::vector<Real>>("x_coord_name")
      45             :                                          : _empty_vec),
      46         659 :     _coordy(isParamValid("y_coord_name") ? getReporterValue<std::vector<Real>>("y_coord_name")
      47             :                                          : _empty_vec),
      48         535 :     _coordz(isParamValid("z_coord_name") ? getReporterValue<std::vector<Real>>("z_coord_name")
      49             :                                          : _empty_vec),
      50         513 :     _coordt(isParamValid("time_name") ? getReporterValue<std::vector<Real>>("time_name")
      51             :                                       : _empty_vec),
      52         476 :     _values(getReporterValue<std::vector<Real>>("value_name"))
      53             : {
      54         238 : }
      55             : 
      56             : Real
      57    46112079 : NearestReporterCoordinatesFunction::value(Real t, const Point & p) const
      58             : {
      59    46112079 :   const std::array<std::pair<Real, std::size_t>, 2> tv = findNearestPoint(t, p);
      60             : 
      61             :   // If the indices are equal then t is either less than the minimum time in the data
      62             :   // or greater than the maximum time. In which case will extrapolate using a constant
      63             :   // value.
      64    46112064 :   if (tv[0].second == tv[1].second)
      65    46106880 :     return _values[tv[0].second];
      66             : 
      67        5184 :   const Real told = tv[0].first;
      68        5184 :   const Real tnew = tv[1].first;
      69        5184 :   const Real vold = _values[tv[0].second];
      70        5184 :   const Real vnew = _values[tv[1].second];
      71        5184 :   return vold + (vnew - vold) * (t - told) / (tnew - told);
      72             : }
      73             : 
      74             : RealGradient
      75           0 : NearestReporterCoordinatesFunction::gradient(Real /*t*/, const Point & /*p*/) const
      76             : {
      77           0 :   return RealGradient(0, 0, 0);
      78             : }
      79             : 
      80             : Real
      81           0 : NearestReporterCoordinatesFunction::timeDerivative(Real t, const Point & p) const
      82             : {
      83           0 :   const std::array<std::pair<Real, std::size_t>, 2> tv = findNearestPoint(t, p);
      84             : 
      85           0 :   if (tv[0].second == tv[1].second)
      86             :     return 0.0;
      87             : 
      88           0 :   const Real told = tv[0].first;
      89           0 :   const Real tnew = tv[1].first;
      90           0 :   const Real vold = _values[tv[0].second];
      91           0 :   const Real vnew = _values[tv[1].second];
      92           0 :   return (vnew - vold) / (tnew - told);
      93             : }
      94             : 
      95             : std::vector<Real>
      96     2223168 : NearestReporterCoordinatesFunction::parameterGradient(Real t, const Point & p) const
      97             : {
      98     2223168 :   const std::array<std::pair<Real, std::size_t>, 2> tv = findNearestPoint(t, p);
      99     2223168 :   std::vector<Real> param_grad(_nval, 0.0);
     100             : 
     101     2223168 :   if (tv[0].second == tv[1].second)
     102     2219712 :     param_grad[tv[0].second] = 1;
     103             :   else
     104             :   {
     105        3456 :     const Real told = tv[0].first;
     106        3456 :     const Real tnew = tv[1].first;
     107        3456 :     param_grad[tv[0].second] = (tnew - t) / (tnew - told);
     108        3456 :     param_grad[tv[1].second] = (t - told) / (tnew - told);
     109             :   }
     110     2223168 :   return param_grad;
     111             : }
     112             : 
     113             : void
     114         238 : NearestReporterCoordinatesFunction::buildCoordinateMapping() const
     115             : {
     116             :   // Do some size checks
     117         238 :   _nval = std::max({_coordx.size(), _coordy.size(), _coordz.size(), _coordt.size()});
     118         238 :   if (_nval == 0)
     119           0 :     paramError("value", "At least one coordinate vector must not be empty.");
     120         238 :   else if (!_coordx.empty() && _coordx.size() != _nval)
     121           3 :     paramError("x_coord_name",
     122             :                "Number of x coordinates (",
     123             :                _coordx.size(),
     124             :                ") does not match number of values (",
     125             :                _nval,
     126             :                ").");
     127         235 :   else if (!_coordy.empty() && _coordy.size() != _nval)
     128           3 :     paramError("y_coord_name",
     129             :                "Number of y coordinates (",
     130             :                _coordy.size(),
     131             :                ") does not match number of values (",
     132             :                _nval,
     133             :                ").");
     134         232 :   else if (!_coordz.empty() && _coordz.size() != _nval)
     135           3 :     paramError("z_coord_name",
     136             :                "Number of z coordinates (",
     137             :                _coordz.size(),
     138             :                ") does not match number of values (",
     139             :                _nval,
     140             :                ").");
     141         229 :   else if (!_coordt.empty() && _coordt.size() != _nval)
     142           3 :     paramError("time_name",
     143             :                "Number of times (",
     144             :                _coordt.size(),
     145             :                ") does not match number of values (",
     146             :                _nval,
     147             :                ").");
     148             : 
     149             :   // Find times for each unique coordinate
     150             :   _coord_mapping.clear();
     151        1752 :   for (const auto & i : make_range(_nval))
     152             :   {
     153             :     Point pt;
     154        1526 :     pt(0) = _coordx.empty() ? 0.0 : _coordx[i];
     155        1526 :     pt(1) = _coordy.empty() ? 0.0 : _coordy[i];
     156        1526 :     pt(2) = _coordz.empty() ? 0.0 : _coordz[i];
     157        1526 :     const Real time = _coordt.empty() ? 0.0 : _coordt[i];
     158             : 
     159             :     std::vector<std::pair<Real, std::size_t>> * vec = nullptr;
     160        5557 :     for (auto & it : _coord_mapping)
     161        4641 :       if (pt.absolute_fuzzy_equals(it.first))
     162             :       {
     163         610 :         vec = &it.second;
     164             :         break;
     165             :       }
     166             :     if (!vec)
     167         916 :       vec = &_coord_mapping[pt];
     168             : 
     169        1526 :     vec->emplace_back(time, i);
     170        1526 :     std::sort(vec->begin(),
     171             :               vec->end(),
     172             :               [](const std::pair<Real, Real> & a, const std::pair<Real, Real> & b)
     173             :               { return a.first < b.first; });
     174             :   }
     175         226 : }
     176             : 
     177             : std::array<std::pair<Real, std::size_t>, 2>
     178    48335247 : NearestReporterCoordinatesFunction::findNearestPoint(Real t, const Point & p) const
     179             : {
     180    48335247 :   if (_coord_mapping.empty())
     181         238 :     buildCoordinateMapping();
     182             : 
     183             :   // Make sure values is correct size
     184    48335235 :   if (_values.size() != _nval)
     185           3 :     paramError("value_name",
     186             :                "Size of value vector (",
     187             :                _values.size(),
     188             :                ") does not match number of coordinates specified (",
     189             :                _nval,
     190             :                ").");
     191             : 
     192             :   const auto & tval =
     193    48335232 :       std::min_element(_coord_mapping.begin(),
     194             :                        _coord_mapping.end(),
     195   137006784 :                        [&p](const std::pair<Point, std::vector<std::pair<Real, std::size_t>>> & p1,
     196             :                             const std::pair<Point, std::vector<std::pair<Real, std::size_t>>> & p2)
     197   137006784 :                        { return (p - p1.first).norm_sq() < (p - p2.first).norm_sq(); })
     198             :           ->second;
     199             : 
     200    48335232 :   if (tval.size() == 1 || MooseUtils::absoluteFuzzyLessEqual(t, tval[0].first))
     201    48325632 :     return {tval[0], tval[0]};
     202        9600 :   else if (MooseUtils::absoluteFuzzyGreaterEqual(t, tval.back().first))
     203         960 :     return {tval.back(), tval.back()};
     204             :   else
     205       12480 :     for (std::size_t ti = 1; ti < tval.size(); ++ti)
     206       12480 :       if (MooseUtils::absoluteFuzzyGreaterEqual(tval[ti].first, t))
     207        8640 :         return {tval[ti - 1], tval[ti]};
     208             : 
     209           0 :   mooseError("Internal error: unable to find nearest point.");
     210             :   return std::array<std::pair<Real, std::size_t>, 2>();
     211             : }

Generated by: LCOV version 1.14