LCOV - code coverage report
Current view: top level - src/Numeric/Interpolator - Linear.H (source / functions) Coverage Total Hit
Test: coverage_merged.info Lines: 67.7 % 96 65
Test Date: 2025-08-12 17:45:17 Functions: 90.0 % 10 9

            Line data    Source code
       1              : //
       2              : // This is a general-purpose routine for specifying time-interpolated
       3              : // quantities in an input file.
       4              : // Interpolators obey the following syntax:
       5              : // 
       6              : // .. code-block:: bash
       7              : // 
       8              : //    (t1,t2,..,tn;v1,v2,...,vn)
       9              : //
      10              : // where :code:`tn` are times and :code:`vn` are values at those times.
      11              : //
      12              : // :bdg-danger-line:`Note: do not include whitespace in an interpolator, this will mess with the parser.`
      13              : //
      14              : // Interpolators can usually be used in place of regular numbers, but only
      15              : // when supported by the calling parse function.
      16              : // 
      17              : // For instance, the `BC::Operator::Elastic::TensionTest` allows the user to specify
      18              : // fixed displacement; for instance, to specify a value of 0.1:
      19              : // 
      20              : // .. code-block:: bash
      21              : // 
      22              : //    bc.tenstion_test.disp = 0.1
      23              : // 
      24              : // However, it may be desirable to change the value over time.
      25              : // In this case, one may specify an interpolator string instead:
      26              : //
      27              : // .. code-block:: bash
      28              : // 
      29              : //    bc.tenstion_test.disp = (1.0,1.5,2.0;0.0,0.1,0.0)
      30              : // 
      31              : // This will cause the displacement value to be zero for :code:`t<1.0`; 
      32              : // ramp to :code:`0.1` as :code:`1.0<t<2.0`; 
      33              : // ramp back to :code:`0.0` as :code:`2.0<t<3.0`; 
      34              : // and then remain at the constant value of :code:`3.0` for :code:`t>3.0`.
      35              : //
      36              : 
      37              : #ifndef NUMERIC_INTERPOLATOR_LINEAR_H_
      38              : #define NUMERIC_INTERPOLATOR_LINEAR_H_
      39              : 
      40              : #include <AMReX.H>
      41              : #include <AMReX_MultiFab.H>
      42              : #include "Set/Set.H"
      43              : #include "Util/Util.H"
      44              : #include "Numeric/Interpolator/Interpolator.H"
      45              : #include "IO/ParmParse.H"
      46              : 
      47              : #include "Unit/Unit.H"
      48              : 
      49              : namespace Numeric
      50              : {
      51              : namespace Interpolator
      52              : {
      53              : template <class T>
      54              : class Linear : public Interpolator<T>
      55              : {
      56              : public:
      57          466 :     Linear() {};
      58         1546 :     ~Linear() {};
      59          530 :     Linear(const Set::Scalar &a_val)
      60          530 :     {
      61          530 :         interval_points.push_back(0.0);
      62          530 :         data_points.push_back(a_val);
      63          530 :     }
      64          222 :     Linear(const std::string a_str, Unit unit_time = Unit::Less(), Unit unit_data = Unit::Less())
      65          222 :     {
      66          222 :         define(a_str, unit_time, unit_data);
      67          222 :     }
      68            2 :     Linear(const std::vector<T> _data_points, const std::vector<Set::Scalar> _interval_points)
      69            2 :     {
      70            2 :         define(_data_points,_interval_points);
      71            2 :     };
      72              :     
      73          224 :     void define(const std::string a_str, Unit a_unit_time, Unit a_unit_val)
      74              :     {
      75          224 :         std::string str = a_str;
      76              :         
      77         2588 :         if (Util::String::Contains(str,"(") || Util::String::Contains(str,":") || Util::String::Contains(str,")") || Util::String::Contains(str,","))
      78              :         {
      79          108 :             if (!Util::String::Contains(str,"(")) Util::Abort(INFO,"Mismatched parentheses while trying to parse ",str);
      80          108 :             if (!Util::String::Contains(str,")")) Util::Abort(INFO,"Mismatched parentheses while trying to parse ",str);
      81          108 :             if (!Util::String::Contains(str,":")) Util::Abort(INFO,"Missing : in interpolator while trying to parse ",str);
      82          180 :             Util::String::ReplaceAll(str,"(","");
      83          180 :             Util::String::ReplaceAll(str,")","");
      84              : 
      85              :             std::vector<std::string> splitstr = Util::String::Split(str,':');
      86           36 :             std::string str_time = splitstr[0];
      87           36 :             std::string str_val  = splitstr[1];
      88              :             
      89              :             std::vector<std::string> str_time_arr = Util::String::Split(str_time,',');
      90              :             std::vector<std::string> str_val_arr  = Util::String::Split(str_val,',');
      91              : 
      92           36 :             if (str_time_arr.size() != str_val_arr.size()) Util::Abort(INFO,"Mismatched number of time values vs array values while trying to parse ", str);
      93              : 
      94          108 :             for (unsigned int i = 0; i < str_time_arr.size(); i++)
      95              :             {
      96           72 :                 Unit unit_time = Unit::Parse(str_time_arr[i]);
      97           72 :                 if (!unit_time.isType(a_unit_time) && !unit_time.isType(Unit::Less()))
      98            0 :                     Util::Exception(INFO,"Invalid unit, ", str_time_arr[i]);
      99           72 :                 Unit unit_val = Unit::Parse(str_val_arr[i]);
     100           72 :                 if (!unit_val.isType(a_unit_val) && !unit_val.isType(Unit::Less()))
     101            0 :                     Util::Exception(INFO,"Invalid unit, ", str_val_arr[i]);
     102           72 :                 interval_points.push_back(unit_time.normalized_value());
     103           72 :                 if (i > 0) if (interval_points[i] < interval_points[i-1]) Util::Abort(INFO,"Time series must monotonically increase - error while trying to parse ", str);
     104           72 :                 data_points.push_back(unit_val.normalized_value());
     105              :             }
     106           36 :         }
     107              :         else
     108              :         {
     109          188 :             interval_points.push_back(0.0);
     110          188 :             data_points.push_back(std::stod(a_str));
     111              :         }
     112          224 :     }
     113              : 
     114            2 :     void define(const std::vector<T> _data_points, const std::vector<Set::Scalar> _interval_points) 
     115              :     {
     116            2 :         data_points = _data_points;
     117            2 :         interval_points = _interval_points;
     118            2 :         if(data_points.size() != interval_points.size())
     119            0 :             Util::Abort(INFO,"Data points and interval points have different sizes");
     120            2 :     };
     121              : 
     122     94796850 :     T operator() (const Set::Scalar point) const
     123              :     {
     124              :         // If there is only one point stored, return it.
     125     94796850 :         if (data_points.size() == 1) return data_points[0];
     126              : 
     127              :         // Do this if point is below interpolation range
     128         9348 :         if(point < interval_points[0])
     129              :         {
     130          200 :             return data_points[0];
     131              :         }
     132              : 
     133         9148 :         Set::Scalar interval = interval_points[1]-interval_points[0];
     134         9148 :         int start = 0;
     135         9148 :         if (uniform)
     136              :         {
     137         9148 :             start = (int)( (point - interval_points[0]) / interval);
     138         9148 :             start -= 1;
     139         9148 :             start = std::max(start,0);
     140         9148 :             start = std::min(start,(int)(interval_points.size()-2));
     141              :         }
     142              : 
     143              :         // Do this if point is within interpolation range
     144         9544 :         for (unsigned int i = start; i<interval_points.size()-1; i++)
     145              :         {
     146         9346 :             if (interval_points[i] <= point && point <= interval_points[i+1])
     147              :             {
     148         8950 :                 return data_points[i] +
     149         8950 :                         (point - interval_points[i]) * (data_points[i+1] - data_points[i]) /
     150         8950 :                         (interval_points[i+1] - interval_points[i]);
     151              : 
     152              :             }
     153              :         }
     154              : 
     155              :         // Otherwise point must be outside interpolation range, so
     156              :         // return the value for the highest point
     157          198 :         return  data_points[interval_points.size()-1];
     158              :     }
     159              : 
     160            2 :     static void Parse(Linear<T> & value, IO::ParmParse & pp, Unit unit_time = Unit::Less(), Unit unit_value = Unit::Less())
     161              :     {
     162            2 :         std::string in;
     163            2 :         pp_query("str",in); // Interpolator string used when Parsed from queryclass.
     164            2 :         value.define(in, unit_time, unit_value);
     165            2 :     }
     166              : 
     167              : 
     168              :     static Linear<T> Read(std::string filename, int derivative = 0);
     169              : 
     170              : protected:
     171              :     std::vector<T> data_points;
     172              :     std::vector<Set::Scalar> interval_points;
     173              :     bool uniform = true;
     174              : 
     175              : public:
     176              :     template<class U> friend Linear<U> operator * (const Set::Scalar alpha, const Linear<U> &b);
     177              : };
     178              : 
     179              : template<class T>
     180              : AMREX_FORCE_INLINE
     181              : Linear<T> operator * (const Set::Scalar alpha, const Linear<T> &b)
     182              : {
     183              :     Linear<T> ret;
     184              :     for (unsigned int i = 0; i < b.data_points.size(); i++) 
     185              :         ret.data_points.push_back(alpha * b.data_points[i]);
     186              :     ret.interval_points = b.interval_points;
     187              :     ret.uniform = b.uniform;
     188              :     return ret;
     189              : }
     190              : 
     191              : template<>
     192              : ALAMO_SINGLE_DEFINITION
     193            0 : Linear<Set::Scalar> Linear<Set::Scalar>::Read(std::string filename, int derivative)
     194              : {
     195            0 :     std::ifstream input;
     196            0 :     input.open(filename);
     197            0 :     std::string line;
     198            0 :     std::vector<Set::Scalar> theta, w;
     199              :     // parse input 
     200            0 :     while (std::getline(input, line))
     201              :     {        std::vector<std::string> dat = Util::String::Split(line);
     202            0 :         theta.push_back(std::stof(dat[0]));
     203            0 :         w.push_back(std::stof(dat[1]));
     204            0 :     }
     205            0 :     if (derivative == 0)
     206              :     {
     207            0 :         return Linear<Set::Scalar>(w,theta);
     208              :     }
     209            0 :     else if (derivative == 1)
     210              :     {
     211            0 :         std::vector<Set::Scalar> thetasmall, dw;
     212            0 :         for (unsigned int i = 1; i < theta.size() - 1; i++)
     213              :         {
     214            0 :             thetasmall.push_back(theta[i]);
     215            0 :             dw.push_back((w[i + 1] - w[i - 1]) / (theta[i + 1] - theta[i - 1]));
     216              :         }
     217            0 :         return Linear<Set::Scalar>(dw,thetasmall);
     218            0 :     }
     219            0 :     else if (derivative == 2)
     220              :     {
     221            0 :         std::vector<Set::Scalar> thetasmall, ddw;
     222            0 :         for (unsigned int i = 1; i < theta.size() - 1; i++)
     223              :         {
     224            0 :             thetasmall.push_back(theta[i]);
     225            0 :             ddw.push_back((w[i + 1] - 2.0 * w[i] + w[i - 1]) / ((theta[i + 1] - theta[i]) * (theta[i] - theta[i - 1])));
     226              :         }
     227            0 :         return Linear<Set::Scalar>(ddw,thetasmall);
     228            0 :     }
     229            0 :     else Util::Abort(INFO,"derivative must be 0,1,2 but got ",derivative);
     230            0 :     exit(-1);
     231            0 : }
     232              : 
     233              : 
     234              : }
     235              : }
     236              : 
     237              : #endif
        

Generated by: LCOV version 2.0-1