LCOV - code coverage report
Current view: top level - src/utils - BilinearInterpolation.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 99787a Lines: 370 410 90.2 %
Date: 2025-10-14 20:01:24 Functions: 11 19 57.9 %
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 "BilinearInterpolation.h"
      11             : #include "libmesh/int_range.h"
      12             : 
      13             : int BilinearInterpolation::_file_number = 0;
      14             : 
      15         172 : BilinearInterpolation::BilinearInterpolation(const std::vector<Real> & xaxis,
      16             :                                              const std::vector<Real> & yaxis,
      17         172 :                                              const ColumnMajorMatrix & zsurface)
      18         172 :   : BidimensionalInterpolation(xaxis, yaxis), _z_surface(zsurface)
      19             : {
      20         172 : }
      21             : 
      22             : void
      23        7520 : BilinearInterpolation::getNeighborIndices(const std::vector<Real> & inArr,
      24             :                                           Real x,
      25             :                                           unsigned int & lowerX,
      26             :                                           unsigned int & upperX) const
      27             : {
      28        7520 :   int N = inArr.size();
      29        7520 :   if (x <= inArr[0])
      30             :   {
      31          48 :     lowerX = 0;
      32          48 :     upperX = 0;
      33             :   }
      34        7472 :   else if (x >= inArr[N - 1])
      35             :   {
      36          48 :     lowerX = N - 1;
      37          48 :     upperX = N - 1;
      38             :   }
      39             :   else
      40             :   {
      41      155994 :     for (const auto i : make_range(1, N))
      42             :     {
      43      155994 :       if (x < inArr[i])
      44             :       {
      45        3952 :         lowerX = i - 1;
      46        3952 :         upperX = i;
      47        3952 :         break;
      48             :       }
      49      152042 :       else if (x == inArr[i])
      50             :       {
      51        3472 :         lowerX = i;
      52        3472 :         upperX = i;
      53        3472 :         break;
      54             :       }
      55             :     }
      56             :   }
      57        7520 : }
      58             : 
      59             : Real
      60        3684 : BilinearInterpolation::sample(Real s1, Real s2) const
      61             : {
      62        3684 :   return sampleInternal(s1, s2);
      63             : }
      64             : 
      65             : ADReal
      66           2 : BilinearInterpolation::sample(const ADReal & s1, const ADReal & s2) const
      67             : {
      68           2 :   return sampleInternal(s1, s2);
      69             : }
      70             : 
      71             : ChainedReal
      72           2 : BilinearInterpolation::sample(const ChainedReal & s1, const ChainedReal & s2) const
      73             : {
      74           2 :   return sampleInternal(s1, s2);
      75             : }
      76             : 
      77             : template <typename T>
      78             : T
      79        3688 : BilinearInterpolation::sampleInternal(const T & s1, const T & s2) const
      80             : {
      81             :   // first find 4 neighboring points
      82        3688 :   unsigned int lx = 0; // index of x coordinate of adjacent grid point to left of P
      83        3688 :   unsigned int ux = 0; // index of x coordinate of adjacent grid point to right of P
      84        3688 :   getNeighborIndices(_x1, MetaPhysicL::raw_value(s1), lx, ux);
      85             : 
      86        3688 :   unsigned int ly = 0; // index of y coordinate of adjacent grid point below P
      87        3688 :   unsigned int uy = 0; // index of y coordinate of adjacent grid point above P
      88        3688 :   getNeighborIndices(_x2, MetaPhysicL::raw_value(s2), ly, uy);
      89             : 
      90        3688 :   const Real & fQ11 = _z_surface(ly, lx);
      91        3688 :   const Real & fQ21 = _z_surface(ly, ux);
      92        3688 :   const Real & fQ12 = _z_surface(uy, lx);
      93        3688 :   const Real & fQ22 = _z_surface(uy, ux);
      94             : 
      95             :   // if point exactly found on a node do not interpolate
      96        3688 :   if ((lx == ux) && (ly == uy))
      97             :   {
      98         810 :     return fQ11;
      99             :   }
     100             : 
     101        2878 :   const auto & x = s1;
     102        2878 :   const auto & y = s2;
     103        2878 :   const Real & x1 = _x1[lx];
     104        2878 :   const Real & x2 = _x1[ux];
     105        2878 :   const Real & y1 = _x2[ly];
     106        2878 :   const Real & y2 = _x2[uy];
     107             : 
     108             :   // if x1 lies exactly on an xAxis node do linear interpolation
     109        2878 :   if (lx == ux)
     110         750 :     return fQ11 + (fQ12 - fQ11) * (y - y1) / (y2 - y1);
     111             : 
     112             :   // if x2 lies exactly on an yAxis node do linear interpolation
     113        2128 :   if (ly == uy)
     114        1102 :     return fQ11 + (fQ21 - fQ11) * (x - x1) / (x2 - x1);
     115             : 
     116        1026 :   auto fxy = fQ11 * (x2 - x) * (y2 - y);
     117        1026 :   fxy += fQ21 * (x - x1) * (y2 - y);
     118        1026 :   fxy += fQ12 * (x2 - x) * (y - y1);
     119        1026 :   fxy += fQ22 * (x - x1) * (y - y1);
     120        1026 :   fxy /= ((x2 - x1) * (y2 - y1));
     121        1026 :   return fxy;
     122           4 : }
     123             : 
     124             : Real
     125          72 : BilinearInterpolation::sampleDerivative(Real s1, Real s2, const unsigned int deriv_var) const
     126             : {
     127          72 :   return sampleDerivativeInternal(s1, s2, deriv_var);
     128             : }
     129             : 
     130             : ADReal
     131           0 : BilinearInterpolation::sampleDerivative(const ADReal & s1,
     132             :                                         const ADReal & s2,
     133             :                                         const unsigned int deriv_var) const
     134             : {
     135           0 :   return sampleDerivativeInternal(s1, s2, deriv_var);
     136             : }
     137             : 
     138             : ChainedReal
     139           0 : BilinearInterpolation::sampleDerivative(const ChainedReal & s1,
     140             :                                         const ChainedReal & s2,
     141             :                                         const unsigned int deriv_var) const
     142             : {
     143           0 :   return sampleDerivativeInternal(s1, s2, deriv_var);
     144             : }
     145             : 
     146             : template <typename T>
     147             : T
     148          72 : BilinearInterpolation::sampleDerivativeInternal(const T s1,
     149             :                                                 const T s2,
     150             :                                                 const unsigned int deriv_var) const
     151             : {
     152             :   // check input
     153          72 :   if (deriv_var != 1 && deriv_var != 2)
     154           0 :     mooseError("deriv_var must equal 1 or 2");
     155             : 
     156             :   // first find 4 neighboring points
     157          72 :   unsigned int lx = 0; // index of x coordinate of adjacent grid point to left of P
     158          72 :   unsigned int ux = 0; // index of x coordinate of adjacent grid point to right of P
     159          72 :   getNeighborIndices(_x1, MetaPhysicL::raw_value(s1), lx, ux);
     160             : 
     161          72 :   unsigned int ly = 0; // index of y coordinate of adjacent grid point below P
     162          72 :   unsigned int uy = 0; // index of y coordinate of adjacent grid point above P
     163          72 :   getNeighborIndices(_x2, MetaPhysicL::raw_value(s2), ly, uy);
     164             : 
     165             :   // xy indexing
     166             :   // 11 is point on lower-left (x low, y low), 22 on upper-right (x high, y high)
     167          72 :   const Real & fQ11 = _z_surface(ly, lx);
     168          72 :   const Real & fQ21 = _z_surface(ly, ux);
     169          72 :   const Real & fQ12 = _z_surface(uy, lx);
     170          72 :   const Real & fQ22 = _z_surface(uy, ux);
     171             :   // when on a grid bound or node, lx can be equal to ux or ly be equal to uy
     172             :   // this would lead to a 0 slope, which isn't desirable
     173             :   // we then refer to 0 as the coordinate before, so 00 is lx-1, ly-1
     174             :   // and 3 as the coordinate after, so 33 is ux+1, uy+1
     175             : 
     176          72 :   const auto & x = s1;
     177          72 :   const auto & y = s2;
     178          72 :   const Real & x1 = _x1[lx];
     179          72 :   const Real & x2 = _x1[ux];
     180          72 :   const Real & y1 = _x2[ly];
     181          72 :   const Real & y2 = _x2[uy];
     182             : 
     183             :   // Grid sizes
     184          72 :   const auto nx1 = _x1.size();
     185          72 :   const auto nx2 = _x2.size();
     186             : 
     187             :   // On interior grid lines, the equal weighting of both sides of both neighbor
     188             :   // cells slopes is an implementation choice
     189             :   // Alternatively on interior grid nodes, we instead use the super cell around the grid node
     190             :   // instead of a weighting of the four neighbor cells
     191             : 
     192             :   // Check all four grid corners, use a quarter of the slope in the cell next to the corner
     193          72 :   if (ux == 0 && uy == 0) // bottom left node
     194             :   {
     195           4 :     const auto & fQ13 = _z_surface(ly + 1, lx);     // fQ at (x1,y3)
     196           4 :     const auto & fQ31 = _z_surface(ly, lx + 1);     // fQ at (x3,y1)
     197           4 :     const auto & fQ33 = _z_surface(ly + 1, lx + 1); // fQ at (x3,y3)
     198           4 :     const Real & x3 = _x1[lx + 1];                 // ux value
     199           4 :     const Real & y3 = _x2[ly + 1];                 // uy value
     200             : 
     201           4 :     if (deriv_var == 1)
     202             :     {
     203           2 :       auto dfdx = fQ11 * (y - y3);
     204           2 :       dfdx += fQ31 * (y3 - y);
     205           2 :       dfdx += fQ13 * (y1 - y);
     206           2 :       dfdx += fQ33 * (y - y1);
     207           2 :       dfdx /= ((x3 - x1) * (y3 - y1));
     208           4 :       return dfdx;
     209           0 :     }
     210           2 :     else if (deriv_var == 2)
     211             :     {
     212           2 :       auto dfdy = fQ11 * (x - x3);
     213           2 :       dfdy += fQ31 * (x1 - x);
     214           2 :       dfdy += fQ13 * (x3 - x);
     215           2 :       dfdy += fQ33 * (x - x1);
     216           2 :       dfdy /= ((x3 - x1) * (y3 - y1));
     217           2 :       return dfdy;
     218           0 :     }
     219           0 :   }
     220          68 :   else if (uy == 0 && lx == nx1 - 1) // bottom right node
     221             :   {
     222           4 :     const auto & fQ01 = _z_surface(ly, lx - 1);     // fQ at (x0,y1)
     223           4 :     const auto & fQ03 = _z_surface(ly + 1, lx - 1); // fQ at (x0,y3)
     224           4 :     const auto & fQ23 = _z_surface(ly + 1, lx);     // fQ at (x2,y3)
     225           4 :     const Real & x0 = _x1[lx - 1];                 // lx value
     226           4 :     const Real & y3 = _x2[ly + 1];                 // uy value
     227             : 
     228           4 :     if (deriv_var == 1)
     229             :     {
     230           2 :       auto dfdx = fQ01 * (y - y3);
     231           2 :       dfdx += fQ21 * (y3 - y);
     232           2 :       dfdx += fQ03 * (y1 - y);
     233           2 :       dfdx += fQ23 * (y - y1);
     234           2 :       dfdx /= ((x2 - x0) * (y3 - y1));
     235           4 :       return dfdx;
     236           0 :     }
     237           2 :     else if (deriv_var == 2)
     238             :     {
     239           2 :       auto dfdy = fQ01 * (x - x2);
     240           2 :       dfdy += fQ21 * (x0 - x);
     241           2 :       dfdy += fQ03 * (x2 - x);
     242           2 :       dfdy += fQ23 * (x - x0);
     243           2 :       dfdy /= ((x2 - x0) * (y3 - y1));
     244           2 :       return dfdy;
     245           0 :     }
     246           0 :   }
     247          64 :   else if (ly == nx2 - 1 && ux == 0) // top left node
     248             :   {
     249           4 :     const auto & fQ10 = _z_surface(ly - 1, lx);     // fQ at (x1,y0)
     250           4 :     const auto & fQ30 = _z_surface(ly - 1, lx + 1); // fQ at (x3,y0)
     251           4 :     const auto & fQ32 = _z_surface(ly, lx + 1);     // fQ at (x3,y2)
     252           4 :     const Real & x3 = _x1[lx + 1];                 // ux value
     253           4 :     const Real & y0 = _x2[ly - 1];                 // ly value
     254             : 
     255           4 :     if (deriv_var == 1)
     256             :     {
     257           2 :       auto dfdx = fQ10 * (y - y2);
     258           2 :       dfdx += fQ30 * (y2 - y);
     259           2 :       dfdx += fQ12 * (y0 - y);
     260           2 :       dfdx += fQ32 * (y - y0);
     261           2 :       dfdx /= ((x3 - x1) * (y2 - y0));
     262           4 :       return dfdx;
     263           0 :     }
     264           2 :     else if (deriv_var == 2)
     265             :     {
     266           2 :       auto dfdy = fQ10 * (x - x3);
     267           2 :       dfdy += fQ30 * (x1 - x);
     268           2 :       dfdy += fQ12 * (x3 - x);
     269           2 :       dfdy += fQ32 * (x - x1);
     270           2 :       dfdy /= ((x3 - x1) * (y2 - y0));
     271           2 :       return dfdy;
     272           0 :     }
     273           0 :   }
     274          60 :   else if (ly == nx2 - 1 && lx == nx1 - 1) // top right node
     275             :   {
     276           4 :     const auto & fQ00 = _z_surface(ly - 1, lx - 1); // fQ at (x0,y0)
     277           4 :     const auto & fQ20 = _z_surface(ly - 1, lx);     // fQ at (x2,y0)
     278           4 :     const auto & fQ02 = _z_surface(ly, lx - 1);     // fQ at (x0,y2)
     279           4 :     const Real & x0 = _x1[lx - 1];                 // lx value
     280           4 :     const Real & y0 = _x2[ly - 1];                 // ly value
     281             : 
     282           4 :     if (deriv_var == 1)
     283             :     {
     284           2 :       auto dfdx = fQ00 * (y - y2);
     285           2 :       dfdx += fQ20 * (y2 - y);
     286           2 :       dfdx += fQ02 * (y0 - y);
     287           2 :       dfdx += fQ22 * (y - y0);
     288           2 :       dfdx /= ((x2 - x0) * (y2 - y0));
     289           4 :       return dfdx;
     290           0 :     }
     291           2 :     else if (deriv_var == 2)
     292             :     {
     293           2 :       auto dfdy = fQ00 * (x - x2);
     294           2 :       dfdy += fQ20 * (x0 - x);
     295           2 :       dfdy += fQ02 * (x2 - x);
     296           2 :       dfdy += fQ22 * (x - x0);
     297           2 :       dfdy /= ((x2 - x0) * (y2 - y0));
     298           2 :       return dfdy;
     299           0 :     }
     300           0 :   }
     301             : 
     302             :   // Nodes along the four grid bounds, use the two grid cells adjacent to the node
     303          56 :   else if (ux == 0 && ly == uy && ux == lx) // when along left boundary, at a grid node
     304             :   {
     305           4 :     const auto & fQ10 = _z_surface(uy - 1, lx);     // fQ at (x1,y0)
     306           4 :     const auto & fQ30 = _z_surface(uy, ux + 1);     // fQ at (x3,y0)
     307           4 :     const auto & fQ13 = _z_surface(uy + 1, lx);     // fQ at (x1,y3)
     308           4 :     const auto & fQ33 = _z_surface(uy + 1, ux + 1); // fQ at (x3,y3)
     309             : 
     310           4 :     const Real & x3 = _x1[lx + 1]; // ux value
     311           4 :     const Real & y0 = _x2[ly - 1]; // ly value
     312           4 :     const Real & y3 = _x2[ly + 1]; // uy value
     313             : 
     314           4 :     if (deriv_var == 1)
     315             :     {
     316           2 :       auto dfdx = fQ10 * (y - y3);
     317           2 :       dfdx += fQ30 * (y3 - y);
     318           2 :       dfdx += fQ13 * (y0 - y);
     319           2 :       dfdx += fQ33 * (y - y0);
     320           2 :       dfdx /= ((x3 - x1) * (y3 - y0));
     321           4 :       return dfdx;
     322           0 :     }
     323           2 :     else if (deriv_var == 2)
     324             :     {
     325           2 :       auto dfdy = fQ10 * (x - x3);
     326           2 :       dfdy += fQ30 * (x1 - x);
     327           2 :       dfdy += fQ13 * (x3 - x);
     328           2 :       dfdy += fQ33 * (x - x1);
     329           2 :       dfdy /= ((x3 - x1) * (y3 - y0));
     330           2 :       return dfdy;
     331           0 :     }
     332           0 :   }
     333          52 :   else if (lx == nx1 - 1 && ly == uy && ux == lx) // when along right boundary, at a grid node
     334             :   {
     335           4 :     const auto & fQ00 = _z_surface(uy - 1, lx - 1); // fQ at (x0,y0)
     336           4 :     const auto & fQ10 = _z_surface(uy - 1, lx);     // fQ at (x1,y0)
     337           4 :     const auto & fQ03 = _z_surface(uy + 1, lx - 1); // fQ at (x0,y3)
     338           4 :     const auto & fQ13 = _z_surface(uy + 1, lx);     // fQ at (x1,y3)
     339             : 
     340           4 :     const Real & x0 = _x1[lx - 1]; // lx value
     341           4 :     const Real & y0 = _x2[ly - 1]; // ly value
     342           4 :     const Real & y3 = _x2[ly + 1]; // uy value
     343             : 
     344           4 :     if (deriv_var == 1)
     345             :     {
     346           2 :       auto dfdx = fQ00 * (y - y3);
     347           2 :       dfdx += fQ10 * (y3 - y);
     348           2 :       dfdx += fQ03 * (y0 - y);
     349           2 :       dfdx += fQ13 * (y - y0);
     350           2 :       dfdx /= ((x1 - x0) * (y3 - y0));
     351           4 :       return dfdx;
     352           0 :     }
     353           2 :     else if (deriv_var == 2)
     354             :     {
     355           2 :       auto dfdy = fQ00 * (x - x1);
     356           2 :       dfdy += fQ10 * (x0 - x);
     357           2 :       dfdy += fQ03 * (x1 - x);
     358           2 :       dfdy += fQ13 * (x - x0);
     359           2 :       dfdy /= ((x1 - x0) * (y3 - y0));
     360           2 :       return dfdy;
     361           0 :     }
     362           0 :   }
     363          48 :   else if (uy == nx2 - 1 && ly == uy && ux == lx) // when along top boundary, at a grid node
     364             :   {
     365           4 :     const auto & fQ00 = _z_surface(uy - 1, lx - 1); // fQ at (x0,y0)
     366           4 :     const auto & fQ01 = _z_surface(uy, lx - 1);     // fQ at (x0,y1)
     367           4 :     const auto & fQ30 = _z_surface(uy - 1, lx + 1); // fQ at (x3,y0)
     368           4 :     const auto & fQ31 = _z_surface(uy, lx + 1);     // fQ at (x3,y1)
     369             : 
     370           4 :     const Real & x0 = _x1[lx - 1]; // lx value
     371           4 :     const Real & x3 = _x1[lx + 1]; // ux value
     372           4 :     const Real & y0 = _x2[ly - 1]; // ly value
     373             : 
     374           4 :     if (deriv_var == 1)
     375             :     {
     376           2 :       auto dfdx = fQ00 * (y - y1);
     377           2 :       dfdx += fQ30 * (y1 - y);
     378           2 :       dfdx += fQ01 * (y0 - y);
     379           2 :       dfdx += fQ31 * (y - y0);
     380           2 :       dfdx /= ((x3 - x0) * (y1 - y0));
     381           4 :       return dfdx;
     382           0 :     }
     383           2 :     else if (deriv_var == 2)
     384             :     {
     385           2 :       auto dfdy = fQ00 * (x - x3);
     386           2 :       dfdy += fQ30 * (x0 - x);
     387           2 :       dfdy += fQ01 * (x3 - x);
     388           2 :       dfdy += fQ31 * (x - x0);
     389           2 :       dfdy /= ((x3 - x0) * (y1 - y0));
     390           2 :       return dfdy;
     391           0 :     }
     392           0 :   }
     393          44 :   else if (uy == 0 && ly == uy && ux == lx) // when along bottom boundary, at a grid node
     394             :   {
     395           4 :     const auto & fQ01 = _z_surface(ly, lx - 1);     // fQ at (x0,y1)
     396           4 :     const auto & fQ03 = _z_surface(ly + 1, lx - 1); // fQ at (x0,y3)
     397           4 :     const auto & fQ31 = _z_surface(ly, lx + 1);     // fQ at (x3,y1)
     398           4 :     const auto & fQ33 = _z_surface(ly + 1, lx + 1); // fQ at (x3,y3)
     399             : 
     400           4 :     const Real & x0 = _x1[lx - 1]; // lx value
     401           4 :     const Real & x3 = _x1[lx + 1]; // ux value
     402           4 :     const Real & y3 = _x2[ly + 1]; // uy value
     403             : 
     404           4 :     if (deriv_var == 1)
     405             :     {
     406           2 :       auto dfdx = fQ01 * (y - y3);
     407           2 :       dfdx += fQ31 * (y3 - y);
     408           2 :       dfdx += fQ03 * (y1 - y);
     409           2 :       dfdx += fQ33 * (y - y1);
     410           2 :       dfdx /= ((x3 - x0) * (y3 - y1));
     411           4 :       return dfdx;
     412           0 :     }
     413           2 :     else if (deriv_var == 2)
     414             :     {
     415           2 :       auto dfdy = fQ01 * (x - x3);
     416           2 :       dfdy += fQ31 * (x0 - x);
     417           2 :       dfdy += fQ03 * (x3 - x);
     418           2 :       dfdy += fQ33 * (x - x0);
     419           2 :       dfdy /= ((x3 - x0) * (y3 - y1));
     420           2 :       return dfdy;
     421           0 :     }
     422           0 :   }
     423             : 
     424             :   // at a grid node inside the domain, use the super box around
     425          40 :   else if (ux == lx && uy == ly)
     426             :   {
     427           4 :     const auto & fQ00 = _z_surface(ly - 1, lx - 1); // fQ at (x0,y0)
     428           4 :     const auto & fQ03 = _z_surface(ly + 1, lx - 1); // fQ at (x0,y3)
     429           4 :     const auto & fQ30 = _z_surface(ly - 1, lx + 1); // fQ at (x3,y0)
     430           4 :     const auto & fQ33 = _z_surface(ly + 1, lx + 1); // fQ at (x3,y3)
     431             : 
     432           4 :     const Real & x0 = _x1[lx - 1]; // lx value
     433           4 :     const Real & x3 = _x1[lx + 1]; // ux value
     434           4 :     const Real & y0 = _x2[ly - 1]; // ly value
     435           4 :     const Real & y3 = _x2[ly + 1]; // uy value
     436             : 
     437           4 :     if (deriv_var == 1)
     438             :     {
     439           2 :       auto dfdx = fQ00 * (y - y3);
     440           2 :       dfdx += fQ30 * (y3 - y);
     441           2 :       dfdx += fQ03 * (y0 - y);
     442           2 :       dfdx += fQ33 * (y - y0);
     443           2 :       dfdx /= ((x3 - x0) * (y3 - y0));
     444           4 :       return dfdx;
     445           0 :     }
     446           2 :     else if (deriv_var == 2)
     447             :     {
     448           2 :       auto dfdy = fQ00 * (x - x3);
     449           2 :       dfdy += fQ30 * (x0 - x);
     450           2 :       dfdy += fQ03 * (x3 - x);
     451           2 :       dfdy += fQ33 * (x - x0);
     452           2 :       dfdy /= ((x3 - x0) * (y3 - y0));
     453           2 :       return dfdy;
     454           0 :     }
     455             :   }
     456             : 
     457             :   // Inside the domain, not at a grid node
     458             :   // calculate derivative wrt to x
     459          36 :   if (deriv_var == 1)
     460             :   {
     461             :     // Find derivative when on interval between two nodes
     462          18 :     if (y == y1)
     463           6 :       return (fQ21 - fQ11) / (x2 - x1);
     464             :     // interior grid line
     465          12 :     else if (lx == ux && lx > 0 && ux < nx1 - 1)
     466             :     {
     467             :       // expand grid size so x1 does not equal x2
     468           2 :       const auto & fQ01 = _z_surface(ly, lx - 1); // new lx at ly
     469           2 :       const auto & fQ31 = _z_surface(ly, lx + 1); // new ux at ly
     470           2 :       const auto & fQ02 = _z_surface(uy, lx - 1); // new lx at uy
     471           2 :       const auto & fQ32 = _z_surface(uy, lx + 1); // new ux at uy
     472             : 
     473           2 :       const Real & x0 = _x1[lx - 1]; // lx value
     474           2 :       const Real & x3 = _x1[lx + 1]; // ux value
     475             : 
     476           2 :       auto dfdx_a = fQ01 * (y - y2);
     477           2 :       dfdx_a += fQ11 * (y2 - y);
     478           2 :       dfdx_a += fQ02 * (y1 - y);
     479           2 :       dfdx_a += fQ12 * (y - y1);
     480           2 :       dfdx_a /= ((x1 - x0) * (y2 - y1));
     481             : 
     482           2 :       auto dfdx_b = fQ11 * (y - y2);
     483           2 :       dfdx_b += fQ31 * (y2 - y);
     484           2 :       dfdx_b += fQ12 * (y1 - y);
     485           2 :       dfdx_b += fQ32 * (y - y1);
     486           2 :       dfdx_b /= ((x3 - x1) * (y2 - y1));
     487           2 :       return 0.5 * (dfdx_a + dfdx_b);
     488           0 :     }
     489             :     // left boundary
     490          10 :     else if (lx == ux && lx == 0)
     491             :     {
     492           2 :       const auto & fQ31 = _z_surface(ly, lx + 1); // new ux at ly
     493           2 :       const auto & fQ32 = _z_surface(uy, lx + 1); // new ux at uy
     494             : 
     495           2 :       const Real & x3 = _x1[lx + 1]; // ux value
     496             : 
     497           2 :       auto dfdx = fQ11 * (y - y2);
     498           2 :       dfdx += fQ31 * (y2 - y);
     499           2 :       dfdx += fQ12 * (y1 - y);
     500           2 :       dfdx += fQ32 * (y - y1);
     501           2 :       dfdx /= ((x3 - x1) * (y2 - y1));
     502           2 :       return dfdx;
     503           0 :     }
     504             :     // right boundary
     505           8 :     else if (lx == ux && ux == nx1 - 1)
     506             :     {
     507           2 :       const auto & fQ01 = _z_surface(ly, ux - 1); // new lx at ly
     508           2 :       const auto & fQ02 = _z_surface(uy, ux - 1); // new lx at uy
     509           2 :       const Real & x0 = _x1[ux - 1];             // lx value
     510             : 
     511           2 :       auto dfdx = fQ01 * (y - y2);
     512           2 :       dfdx += fQ11 * (y2 - y);
     513           2 :       dfdx += fQ02 * (y1 - y);
     514           2 :       dfdx += fQ12 * (y - y1);
     515           2 :       dfdx /= ((x1 - x0) * (y2 - y1));
     516           2 :       return dfdx;
     517           0 :     }
     518             :     // Derivative (w/ respect to x) for some point inside box
     519             :     else
     520             :     {
     521           6 :       auto dfdx_xy = fQ11 * (y - y2);
     522           6 :       dfdx_xy += fQ21 * (y2 - y);
     523           6 :       dfdx_xy += fQ12 * (y1 - y);
     524           6 :       dfdx_xy += fQ22 * (y - y1);
     525           6 :       dfdx_xy /= ((x2 - x1) * (y2 - y1));
     526           6 :       return dfdx_xy;
     527           0 :     }
     528             :   }
     529             : 
     530          18 :   else if (deriv_var == 2)
     531             :   {
     532          18 :     if (x == x1) // if x equal to x1 node
     533           6 :       return (fQ12 - fQ11) / (y2 - y1);
     534             :     // interior grid line
     535          12 :     else if (ly == uy && ly > 0 && uy < nx2 - 1)
     536             :     {
     537             :       // expand grid size so x1 does not equal x2
     538           2 :       const auto & fQ10 = _z_surface(ly - 1, lx); // new ly at lx
     539           2 :       const auto & fQ20 = _z_surface(ly - 1, ux); // new uy at lx
     540           2 :       const auto & fQ13 = _z_surface(ly + 1, lx); // new ly at ux
     541           2 :       const auto & fQ23 = _z_surface(ly + 1, ux); // new uy at ux
     542           2 :       const Real & y0 = _x2[ly - 1];
     543           2 :       const Real & y3 = _x2[ly + 1];
     544             : 
     545           2 :       auto dfdy_a = fQ10 * (x - x2);
     546           2 :       dfdy_a += fQ20 * (x1 - x);
     547           2 :       dfdy_a += fQ11 * (x2 - x);
     548           2 :       dfdy_a += fQ21 * (x - x1);
     549           2 :       dfdy_a /= ((x2 - x1) * (y1 - y0));
     550             : 
     551           2 :       auto dfdy_b = fQ11 * (x - x2);
     552           2 :       dfdy_b += fQ21 * (x1 - x);
     553           2 :       dfdy_b += fQ13 * (x2 - x);
     554           2 :       dfdy_b += fQ23 * (x - x1);
     555           2 :       dfdy_b /= ((x2 - x1) * (y3 - y1));
     556           2 :       return 0.5 * (dfdy_a + dfdy_b);
     557           0 :     }
     558             :     // bottom boundary
     559          10 :     else if (ly == uy && ly == 0)
     560             :     {
     561           2 :       const auto & fQ13 = _z_surface(ly + 1, lx); // new uy at lx
     562           2 :       const auto & fQ23 = _z_surface(ly + 1, ux); // new uy at ux
     563             : 
     564           2 :       const Real & y3 = _x2[ly + 1]; // lx value
     565             : 
     566           2 :       auto dfdy = fQ11 * (x - x2);
     567           2 :       dfdy += fQ21 * (x1 - x);
     568           2 :       dfdy += fQ13 * (x2 - x);
     569           2 :       dfdy += fQ23 * (x - x1);
     570           2 :       dfdy /= ((x2 - x1) * (y3 - y1));
     571           2 :       return dfdy;
     572           0 :     }
     573             :     // top boundary
     574           8 :     else if (ly == uy && uy == nx2 - 1)
     575             :     {
     576           2 :       const auto & fQ10 = _z_surface(ly - 1, lx); // new ly at lx
     577           2 :       const auto & fQ20 = _z_surface(ly - 1, ux); // new ly at ux
     578           2 :       const Real & y0 = _x2[ly - 1];             // lx value
     579             : 
     580           2 :       auto dfdy = fQ10 * (x - x2);
     581           2 :       dfdy += fQ20 * (x1 - x);
     582           2 :       dfdy += fQ11 * (x2 - x);
     583           2 :       dfdy += fQ21 * (x - x1);
     584           2 :       dfdy /= ((x2 - x1) * (y1 - y0));
     585           2 :       return dfdy;
     586           0 :     }
     587             :     else
     588             :     {
     589             :       // Derivative (w/ respect to y) for any point inside box
     590           6 :       auto dfdy_xy = fQ11 * (x - x2);
     591           6 :       dfdy_xy += fQ21 * (x1 - x);
     592           6 :       dfdy_xy += fQ12 * (x2 - x);
     593           6 :       dfdy_xy += fQ22 * (x - x1);
     594           6 :       dfdy_xy /= ((x2 - x1) * (y2 - y1));
     595           6 :       return dfdy_xy;
     596           0 :     }
     597             :   }
     598           0 :   mooseError("Bilinear interpolation failed to select a case for x1= ", s1, " x2= ", s2);
     599             : }
     600             : 
     601             : void
     602           2 : BilinearInterpolation::sampleValueAndDerivatives(
     603             :     Real s1, Real s2, Real & y, Real & dy_ds1, Real & dy_ds2) const
     604             : {
     605           2 :   y = sample(s1, s2);
     606           2 :   dy_ds1 = sampleDerivative(s1, s2, 1);
     607           2 :   dy_ds2 = sampleDerivative(s1, s2, 2);
     608           2 : }

Generated by: LCOV version 1.14