LCOV - code coverage report
Current view: top level - src/functions - PiecewiseBilinear.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 101 116 87.1 %
Date: 2025-07-17 01:28:37 Functions: 7 11 63.6 %
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 "PiecewiseBilinear.h"
      11             : #include "ColumnMajorMatrix.h"
      12             : #include "BilinearInterpolation.h"
      13             : #include "MooseUtils.h"
      14             : 
      15             : #include <fstream>
      16             : 
      17             : registerMooseObject("MooseApp", PiecewiseBilinear);
      18             : 
      19             : InputParameters
      20       14617 : PiecewiseBilinear::validParams()
      21             : {
      22       14617 :   InputParameters params = Function::validParams();
      23       14617 :   params.addParam<FileName>(
      24             :       "data_file", "", "File holding csv data for use with PiecewiseBilinear");
      25       14617 :   params.addParam<std::vector<Real>>("x", "The x abscissa values");
      26       14617 :   params.addParam<std::vector<Real>>("y", "The y abscissa values");
      27       14617 :   params.addParam<std::vector<Real>>("z", "The ordinate values");
      28       14617 :   params.addParam<int>("axis", -1, "The axis used (0, 1, or 2 for x, y, or z).");
      29       43851 :   params.addParam<int>(
      30       29234 :       "xaxis", -1, "The coordinate used for x-axis data (0, 1, or 2 for x, y, or z).");
      31       43851 :   params.addParam<int>(
      32       29234 :       "yaxis", -1, "The coordinate used for y-axis data (0, 1, or 2 for x, y, or z).");
      33       43851 :   params.addParam<Real>(
      34       29234 :       "scale_factor", 1.0, "Scale factor to be applied to the axis, yaxis, or xaxis values");
      35       43851 :   params.addParam<bool>("radial",
      36       29234 :                         false,
      37             :                         "Set to true if you want to interpolate along a radius "
      38             :                         "rather that along a specific axis, and note that you "
      39             :                         "have to define xaxis and yaxis in the input file");
      40       14617 :   params.addClassDescription("Interpolates values from a csv file");
      41       14617 :   return params;
      42           0 : }
      43             : 
      44         168 : PiecewiseBilinear::PiecewiseBilinear(const InputParameters & parameters)
      45             :   : Function(parameters),
      46         168 :     _data_file_name(getParam<FileName>("data_file")),
      47         168 :     _axis(getParam<int>("axis")),
      48         168 :     _yaxis(getParam<int>("yaxis")),
      49         168 :     _xaxis(getParam<int>("xaxis")),
      50         168 :     _axisValid(_axis > -1 && _axis < 3),
      51         168 :     _yaxisValid(_yaxis > -1 && _yaxis < 3),
      52         168 :     _xaxisValid(_xaxis > -1 && _xaxis < 3),
      53         168 :     _scale_factor(getParam<Real>("scale_factor")),
      54         336 :     _radial(getParam<bool>("radial"))
      55             : {
      56             : 
      57         168 :   if (!_axisValid && !_yaxisValid && !_xaxisValid)
      58           0 :     mooseError("In PiecewiseBilinear ",
      59           0 :                _name,
      60             :                ": None of axis, yaxis, or xaxis properly defined.  Allowable range is 0-2");
      61             : 
      62         168 :   if (_axisValid && (_yaxisValid || _xaxisValid))
      63           0 :     mooseError("In PiecewiseBilinear ", _name, ": Cannot define axis with either yaxis or xaxis");
      64             : 
      65         168 :   if (_radial && (!_yaxisValid || !_xaxisValid))
      66           0 :     mooseError(
      67           0 :         "In PiecewiseBilinear ", _name, ": yaxis and xaxis must be defined when radial = true");
      68             : 
      69         168 :   std::vector<Real> x;
      70         168 :   std::vector<Real> y;
      71         168 :   ColumnMajorMatrix z;
      72         168 :   std::vector<Real> z_vec;
      73             : 
      74         168 :   if (!_data_file_name.empty())
      75             :   {
      76         242 :     if (parameters.isParamValid("x") || parameters.isParamValid("y") ||
      77         160 :         parameters.isParamValid("z"))
      78           4 :       mooseError("In PiecewiseBilinear: Cannot specify 'data_file' and 'x', 'y', or 'z' together.");
      79             :     else
      80          78 :       parse(_data_file_name, x, y, z, name());
      81             :   }
      82             : 
      83         254 :   else if (!(parameters.isParamValid("x") && parameters.isParamValid("y") &&
      84         168 :              parameters.isParamValid("z")))
      85           4 :     mooseError("In PiecewiseBilinear: 'x' and 'y' and 'z' must be specified if any one is "
      86             :                "specified or no 'data_file' is specified.");
      87             : 
      88             :   else
      89             :   {
      90          82 :     x = getParam<std::vector<Real>>("x");
      91          82 :     y = getParam<std::vector<Real>>("y");
      92          82 :     z_vec = getParam<std::vector<Real>>("z");
      93             : 
      94             :     // check that size of z = (size of x)*(size of y)
      95          82 :     if (z_vec.size() != x.size() * y.size())
      96           4 :       mooseError("In PiecewiseBilinear: Size of z should be the size of x times the size of y.");
      97             : 
      98             :     // reshape and populate z matrix
      99          78 :     z.reshape(y.size(), x.size());
     100          78 :     int idx = 0;
     101         312 :     for (unsigned int i = 0; i < y.size(); i++)
     102         936 :       for (unsigned int j = 0; j < x.size(); j++)
     103             :       {
     104         702 :         z(i, j) = z_vec[idx];
     105         702 :         idx += 1;
     106             :       }
     107             :   }
     108             : 
     109         156 :   _bilinear_interp = std::make_unique<BilinearInterpolation>(x, y, z);
     110         156 : }
     111             : 
     112         312 : PiecewiseBilinear::~PiecewiseBilinear() {}
     113             : 
     114             : Real
     115        3072 : PiecewiseBilinear::value(Real t, const Point & p) const
     116             : {
     117        3072 :   return valueInternal(t, p);
     118             : }
     119             : 
     120             : ADReal
     121           0 : PiecewiseBilinear::value(const ADReal & t, const ADPoint & p) const
     122             : {
     123           0 :   return valueInternal(t, p);
     124             : }
     125             : 
     126             : template <typename T, typename P>
     127             : T
     128        3072 : PiecewiseBilinear::valueInternal(T t, const P & p) const
     129             : {
     130        3072 :   T retVal = 0.0;
     131        3072 :   if (_yaxisValid && _xaxisValid && _radial)
     132             :   {
     133         512 :     const auto rx = p(_xaxis) * p(_xaxis);
     134         512 :     const auto ry = p(_yaxis) * p(_yaxis);
     135         512 :     const auto r = std::sqrt(rx + ry);
     136         512 :     retVal = _bilinear_interp->sample(r, t);
     137         512 :   }
     138        2560 :   else if (_axisValid)
     139        1024 :     retVal = _bilinear_interp->sample(p(_axis), t);
     140        1536 :   else if (_yaxisValid && !_radial)
     141             :   {
     142        1024 :     if (_xaxisValid)
     143         512 :       retVal = _bilinear_interp->sample(p(_xaxis), p(_yaxis));
     144             :     else
     145         512 :       retVal = _bilinear_interp->sample(t, p(_yaxis));
     146             :   }
     147             :   else
     148         512 :     retVal = _bilinear_interp->sample(p(_xaxis), t);
     149             : 
     150        3072 :   return retVal * _scale_factor;
     151           0 : }
     152             : 
     153             : void
     154          78 : PiecewiseBilinear::parse(const std::string & data_file_name,
     155             :                          std::vector<Real> & x,
     156             :                          std::vector<Real> & y,
     157             :                          ColumnMajorMatrix & z,
     158             :                          const std::string & object_name)
     159             : {
     160          78 :   std::ifstream file(data_file_name.c_str());
     161          78 :   if (!file.good())
     162           0 :     ::mooseError(object_name, " : Error opening file '", data_file_name, "'.");
     163             : 
     164          78 :   std::size_t num_lines = 0;
     165          78 :   std::size_t num_cols = libMesh::invalid_uint;
     166          78 :   std::vector<Real> data;
     167             : 
     168          78 :   std::string line;
     169          78 :   std::vector<Real> line_data;
     170         390 :   while (std::getline(file, line))
     171             :   {
     172         312 :     num_lines++;
     173         312 :     if (!MooseUtils::tokenizeAndConvert<double>(line, line_data, ", "))
     174           0 :       ::mooseError(object_name, " : Error parsing file '", data_file_name, "' on line ", num_lines);
     175             : 
     176         312 :     data.insert(data.end(), line_data.begin(), line_data.end());
     177             : 
     178         312 :     if (num_cols == libMesh::invalid_uint)
     179          78 :       num_cols = line_data.size();
     180         234 :     else if (line_data.size() != num_cols + 1)
     181           0 :       ::mooseError(object_name,
     182             :                    " : Read ",
     183           0 :                    line_data.size(),
     184             :                    " columns of data but expected ",
     185           0 :                    num_cols + 1,
     186             :                    " columns in line ",
     187             :                    num_lines);
     188             :   }
     189             : 
     190          78 :   x.resize(num_cols);
     191          78 :   y.resize(num_lines - 1);
     192          78 :   z.reshape(num_lines - 1, num_cols);
     193          78 :   std::size_t offset = 0;
     194             : 
     195             :   // Extract the first line's data (the x axis data)
     196         312 :   for (unsigned int j = 0; j < num_cols; ++j)
     197         234 :     x[j] = data[offset++];
     198             : 
     199         312 :   for (unsigned int i = 0; i < num_lines - 1; ++i)
     200             :   {
     201             :     // Extract the y axis entry for this line
     202         234 :     y[i] = data[offset++];
     203             : 
     204             :     // Extract the function values for this row in the matrix
     205         936 :     for (unsigned int j = 0; j < num_cols; ++j)
     206         702 :       z(i, j) = data[offset++];
     207             :   }
     208             : 
     209          78 :   if (data.size() != offset)
     210           0 :     ::mooseError(object_name, " : Inconsistency in data read from '", data_file_name, "'.");
     211          78 : }

Generated by: LCOV version 1.14