LCOV - code coverage report
Current view: top level - src/functions - PiecewiseTabularInterface.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #31761 (28487c) with base 701993 Lines: 118 124 95.2 %
Date: 2025-11-11 13:51:07 Functions: 7 7 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             : 
      10             : #include "PiecewiseTabularInterface.h"
      11             : #include "DelimitedFileReader.h"
      12             : #include "JSONFileReader.h"
      13             : 
      14             : #include "libmesh/int_range.h"
      15             : 
      16             : InputParameters
      17       84305 : PiecewiseTabularInterface::validParams()
      18             : {
      19       84305 :   InputParameters params = emptyInputParameters();
      20             : 
      21             :   // Parameters shared across all data input methods
      22      337220 :   MooseEnum axis("x=0 y=1 z=2");
      23      337220 :   params.addParam<MooseEnum>(
      24             :       "axis", axis, "The axis used (x, y, or z) if this is to be a function of position");
      25             : 
      26             :   // Data from input file parameters
      27      337220 :   params.addParam<std::vector<Real>>("xy_data",
      28             :                                      "All function data, supplied in abscissa, ordinate pairs");
      29      337220 :   params.addParam<std::vector<Real>>("x", "The abscissa values");
      30      337220 :   params.addParam<std::vector<Real>>("y", "The ordinate values");
      31             : 
      32             :   // Data from CSV file parameters
      33      337220 :   params.addParam<FileName>("data_file", "File holding CSV data");
      34      337220 :   params.addParam<unsigned int>("x_index_in_file", 0, "The abscissa index in the data file");
      35      337220 :   params.addParam<unsigned int>("y_index_in_file", 1, "The ordinate index in the data file");
      36      337220 :   params.addParam<std::string>(
      37             :       "x_title", "The title of the column/row containing the x data in the data file");
      38      337220 :   params.addParam<std::string>(
      39             :       "y_title", "The title of the column/row containing the y data in the data file");
      40      252915 :   params.addParam<bool>(
      41      168610 :       "xy_in_file_only", true, "If the data file only contains abscissa and ordinate data");
      42      337220 :   MooseEnum format("columns=0 rows=1", "rows");
      43      337220 :   params.addParam<MooseEnum>(
      44             :       "format", format, "Format of csv data file that is in either in columns or rows");
      45             : 
      46             :   // Data from JSON parameters
      47      337220 :   params.addParam<UserObjectName>("json_uo", "JSONFileReader holding the data");
      48      337220 :   params.addParam<std::vector<std::string>>(
      49             :       "x_keys", "Ordered vector of keys in the JSON tree to obtain the abscissa");
      50      337220 :   params.addParam<std::vector<std::string>>(
      51             :       "y_keys", "Ordered vector of keys in the JSON tree to obtain the ordinate");
      52             : 
      53      337220 :   params.addParamNamesToGroup("xy_data x y", "Data from input file");
      54      337220 :   params.addParamNamesToGroup(
      55             :       "data_file x_index_in_file y_index_in_file x_title y_title xy_in_file_only format",
      56             :       "Data from CSV file");
      57      252915 :   params.addParamNamesToGroup("json_uo x_keys y_keys", "Data from JSON");
      58             : 
      59      168610 :   return params;
      60       84305 : }
      61             : 
      62        2253 : PiecewiseTabularInterface::PiecewiseTabularInterface(const MooseObject & object,
      63             :                                                      std::vector<Real> & data_x,
      64        2253 :                                                      std::vector<Real> & data_y)
      65        4506 :   : _has_axis(object.isParamValid("axis")),
      66        2253 :     _object(object),
      67        2253 :     _parameters(object.parameters()),
      68        2253 :     _data_x(data_x),
      69        2253 :     _data_y(data_y)
      70             : {
      71             :   // determine function argument
      72        2253 :   if (_has_axis)
      73         236 :     _axis = _parameters.get<MooseEnum>("axis");
      74             : 
      75             :   // Check all parameters for inconsistencies
      76       11265 :   if (_parameters.isParamValid("data_file") + _parameters.isParamValid("json_uo") +
      77        9966 :           (_parameters.isParamValid("x") || _parameters.isParamValid("y")) +
      78        6759 :           _parameters.isParamValid("xy_data") >
      79             :       1)
      80           8 :     _object.mooseError(
      81             :         "Either 'data_file' or 'json_uo' or 'x' and 'y' or 'xy_data' must be specified "
      82             :         "exclusively.");
      83       11225 :   if ((_parameters.isParamValid("x") + _parameters.isParamValid("y")) % 2 != 0)
      84           4 :     _object.mooseError(
      85             :         "Both 'x' and 'y' parameters or neither (for another input method) must be specified");
      86       10899 :   if (!_parameters.isParamValid("data_file") &&
      87        8046 :       (_parameters.isParamSetByUser("x_index_in_file") ||
      88       13851 :        _parameters.isParamSetByUser("y_index_in_file") || _parameters.isParamValid("x_title") ||
      89       11896 :        _parameters.isParamValid("y_title") || _parameters.isParamSetByUser("xy_in_file_only") ||
      90        8034 :        _parameters.isParamSetByUser("format")))
      91           4 :     _object.mooseError(
      92             :         "A parameter was passed for an option using data from a CSV file but the "
      93             :         "'data_file' parameter has not been set. This is not allowed. Please check the parameter "
      94             :         "groups in the documentation for the list of parameters for each data input method.");
      95       11135 :   if (!_parameters.isParamValid("json_uo") &&
      96       13164 :       (_parameters.isParamValid("x_keys") || _parameters.isParamValid("y_keys")))
      97           4 :     _object.mooseError(
      98             :         "A parameter was passed for a JSON input option but the 'json_uo' parameter has not "
      99             :         "been set. This is not allowed. Please check the parameter groups in the "
     100             :         "documentation for the list of parameters for each data input method.");
     101        2233 : }
     102             : 
     103             : void
     104         306 : PiecewiseTabularInterface::buildFromFile(const libMesh::Parallel::Communicator & comm)
     105             : {
     106             :   // Input parameters
     107         306 :   const auto & data_file_name = _parameters.get<FileName>("data_file");
     108         306 :   const MooseEnum & format = _parameters.get<MooseEnum>("format");
     109             : 
     110             :   // xy_in_file_only does not make sense here as it restricts the file to exactly
     111             :   // two cows/columns, which is not a likely scenario when looking up data by name.
     112             :   // A wrong 'format' parameter would be caught by the failing name resolution anyways.
     113         306 :   bool xy_only = _parameters.get<bool>("xy_in_file_only");
     114        1470 :   if (_parameters.isParamValid("x_title") || _parameters.isParamValid("y_title"))
     115             :   {
     116          90 :     if (_parameters.isParamSetByUser("xy_in_file_only") && xy_only)
     117           0 :       _parameters.paramError(
     118             :           "xy_in_file_only",
     119             :           "When accessing data through 'x_title' or 'y_title' this parameter should not be used");
     120             :     else
     121          30 :       xy_only = false;
     122             :   }
     123             : 
     124             :   // Read the data from CSV file
     125         306 :   MooseUtils::DelimitedFileReader reader(data_file_name, &comm);
     126         306 :   reader.setFormatFlag(format.getEnum<MooseUtils::DelimitedFileReader::FormatFlag>());
     127         306 :   reader.setComment("#");
     128         306 :   reader.read();
     129             : 
     130         302 :   const auto & columns = reader.getNames();
     131         302 :   const auto & data = reader.getData();
     132             : 
     133         302 :   if (data.size() > 2 && xy_only)
     134          16 :     _object.mooseError("In ",
     135          16 :                        _object.name(),
     136             :                        ": Read more than two ",
     137             :                        format,
     138             :                        " of data from file '",
     139             :                        data_file_name,
     140             :                        "'.  Did you mean to use \"format = ",
     141          16 :                        format == "columns" ? "rows" : "columns",
     142             :                        "\" or set \"xy_in_file_only\" to false?");
     143             : 
     144         286 :   unsigned int x_index = libMesh::invalid_uint;
     145         286 :   unsigned int y_index = libMesh::invalid_uint;
     146         564 :   const auto setIndex = [&](unsigned int & index, const std::string & prefix)
     147             :   {
     148         564 :     if (_parameters.isParamValid(prefix + "_title"))
     149             :     {
     150          60 :       const auto name = _parameters.get<std::string>(prefix + "_title");
     151         240 :       for (const auto i : index_range(columns))
     152         180 :         if (columns[i] == name)
     153          60 :           index = i;
     154             : 
     155          60 :       if (index == libMesh::invalid_uint)
     156           0 :         _parameters.paramError(prefix + "_title",
     157             :                                "None of the ",
     158             :                                format,
     159             :                                " in the data file has the title '",
     160             :                                name,
     161             :                                "'.");
     162          60 :     }
     163             :     else
     164         504 :       index = _parameters.get<unsigned int>(prefix + "_index_in_file");
     165             : 
     166         564 :     if (index >= data.size())
     167          16 :       _parameters.paramError(prefix + "_index_in_file",
     168             :                              "Index out-of-range of the available data in '",
     169             :                              data_file_name,
     170             :                              "', which contains ",
     171             :                              data.size(),
     172             :                              " ",
     173             :                              format,
     174             :                              " of data.");
     175         834 :   };
     176             : 
     177         564 :   setIndex(x_index, "x");
     178         278 :   setIndex(y_index, "y");
     179             : 
     180         270 :   if (x_index == y_index)
     181           4 :     _object.mooseError("In ",
     182           4 :                        _object.name(),
     183             :                        ": 'x_index_in_file' and 'y_index_in_file' are set to the same value.");
     184             : 
     185             :   // Update the input vectors to contained the desired data
     186         266 :   _data_x = reader.getData(x_index);
     187         266 :   _data_y = reader.getData(y_index);
     188             : 
     189             :   // Size mismatch error
     190         266 :   if (_data_x.size() != _data_y.size())
     191           6 :     _object.mooseError("In ", _object.name(), ": Lengths of x and y data do not match.");
     192             : 
     193         260 :   _raw_data_loaded = true;
     194         262 : }
     195             : 
     196             : void
     197          50 : PiecewiseTabularInterface::buildFromJSON(const JSONFileReader & json_uo)
     198             : {
     199         150 :   if (!_parameters.isParamValid("x_keys"))
     200           0 :     _object.mooseError("Missing 'x_keys' parameters for loading data from JSON");
     201         150 :   if (!_parameters.isParamValid("y_keys"))
     202           0 :     _object.mooseError("Missing 'y_keys' parameters for loading data from JSON");
     203          50 :   json_uo.getVector<Real>(_parameters.get<std::vector<std::string>>("x_keys"), _data_x);
     204          50 :   json_uo.getVector<Real>(_parameters.get<std::vector<std::string>>("y_keys"), _data_y);
     205          50 :   _raw_data_loaded = true;
     206             : 
     207             :   // Size mismatch error
     208          50 :   if (_data_x.size() != _data_y.size())
     209           0 :     _object.mooseError(
     210           0 :         "Lengths of x (", _data_x.size(), ") and y (", _data_y.size(), ") data do not match.");
     211          50 : }
     212             : 
     213             : void
     214        1768 : PiecewiseTabularInterface::buildFromXandY()
     215             : {
     216        1768 :   _data_x = _parameters.get<std::vector<Real>>("x");
     217        1768 :   _data_y = _parameters.get<std::vector<Real>>("y");
     218        1768 :   _raw_data_loaded = true;
     219        1768 : }
     220             : 
     221             : void
     222         105 : PiecewiseTabularInterface::buildFromXY()
     223             : {
     224         105 :   const auto & xy = _parameters.get<std::vector<Real>>("xy_data");
     225         105 :   const auto xy_size = xy.size();
     226         105 :   if (xy_size % 2 != 0)
     227           4 :     _object.mooseError(
     228           4 :         "In ", _object.name(), ": Length of data provided in 'xy_data' must be a multiple of 2.");
     229             : 
     230         101 :   const auto data_size = xy_size / 2;
     231         101 :   _data_x.resize(data_size);
     232         101 :   _data_y.resize(data_size);
     233         418 :   for (const auto i : make_range(data_size))
     234             :   {
     235         317 :     _data_x[i] = xy[2 * i];
     236         317 :     _data_y[i] = xy[2 * i + 1];
     237             :   }
     238         101 :   _raw_data_loaded = true;
     239         101 : }

Generated by: LCOV version 1.14