LCOV - code coverage report
Current view: top level - include/crpropa - Grid.h (source / functions) Coverage Total Hit
Test: coverage.info.cleaned Lines: 85.1 % 215 183
Test Date: 2026-06-18 09:49:19 Functions: 42.6 % 61 26

            Line data    Source code
       1              : #ifndef CRPROPA_GRID_H
       2              : #define CRPROPA_GRID_H
       3              : 
       4              : #include "crpropa/Referenced.h"
       5              : #include "crpropa/Vector3.h"
       6              : 
       7              : #include "kiss/string.h"
       8              : #include "kiss/logger.h"
       9              : 
      10              : #include <vector>
      11              : #include <type_traits>
      12              : #include <string>
      13              : #include <sstream>  
      14              : #if HAVE_SIMD
      15              : #include <immintrin.h>
      16              : #include <smmintrin.h>
      17              : #endif // HAVE_SIMD
      18              : 
      19              : namespace crpropa {
      20              : 
      21              : /** If set to TRILINEAR, use trilinear interpolation (standard)
      22              : If set to TRICUBIC, use tricubic interpolation instead of trilinear interpolation
      23              : If set to NEAREST_NEIGHBOUR , use nearest neighbour interpolation instead of trilinear interpolation */
      24              : enum interpolationType {
      25              :   TRILINEAR = 0,
      26              :   TRICUBIC,
      27              :   NEAREST_NEIGHBOUR
      28              : };
      29              : 
      30              : /** Lower and upper neighbour in a periodically continued unit grid */
      31              : inline void periodicClamp(double x, int n, int &lo, int &hi) {
      32       100051 :         lo = ((int(floor(x)) % (n)) + (n)) % (n);
      33           10 :         hi = (lo + 1) % (n);
      34              : }
      35              : 
      36              : /** grid index in a reflective continued unit grid */
      37              : inline int reflectiveBoundary(int index, int n) {
      38         1963 :         while ((index < -0.5) or (index > (n-0.5)))
      39          806 :                 index = 2 * n * (index > (n-0.5)) - index-1;
      40              :         return index;
      41              : }
      42              : 
      43              : /** grid index in a periodically continued unit grid */
      44              : inline int periodicBoundary(int index, int n) {
      45          768 :         return ((index % (n)) + (n)) % (n);
      46              : }
      47              : 
      48              : /** Lower and upper neighbour in a reflectively repeated unit grid */
      49           20 : inline void reflectiveClamp(double x, int n, int &lo, int &hi, double &res) {
      50           36 :         while ((x < -0.5) or (x > (n-0.5)))
      51           16 :                 x = 2 * n * (x > (n-0.5)) -x-1;
      52           20 :         res = x;
      53           20 :         lo = floor(x);
      54           20 :         hi = lo + (lo < n-1);
      55           20 :         if (x<0) {
      56           10 :                 lo=0; 
      57           10 :                 hi=0;
      58              :         }
      59           20 : }
      60              : 
      61              : /** Symmetrical round */
      62           51 : inline double round(double r) {
      63           51 :         return (r > 0.0) ? floor(r + 0.5) : ceil(r - 0.5);
      64              : }
      65              : 
      66              : /**
      67              :  * \addtogroup Core
      68              :  * @{
      69              :  */
      70              : 
      71              : /**
      72              :  @class GridProperties
      73              :  @brief Combines parameters that uniquely define Grid class
      74              :  */
      75              : class GridProperties: public Referenced {
      76              : public:
      77              :         size_t Nx, Ny, Nz;      // Number of grid points
      78              :         Vector3d origin;        // Position of the lower left front corner of the volume
      79              :         Vector3d spacing;       // Spacing vector between gridpoints
      80              :         bool reflective;        // using reflective repetition of the grid instead of periodic
      81              :         interpolationType ipol; // Interpolation type used between grid points
      82              :         bool clipVolume;        // Set grid values to 0 outside the volume if true
      83              : 
      84              :         /** Constructor for cubic grid
      85              :          @param origin  Position of the lower left front corner of the volume
      86              :          @param N               Number of grid points in one direction
      87              :          @param spacing Spacing between grid points
      88              :          */
      89            6 :         GridProperties(Vector3d origin, size_t N, double spacing) :
      90            6 :                 origin(origin), Nx(N), Ny(N), Nz(N), spacing(Vector3d(spacing)), reflective(false), ipol(TRILINEAR), clipVolume(false) {
      91              :         }
      92              : 
      93              :         /** Constructor for non-cubic grid
      94              :          @param origin  Position of the lower left front corner of the volume
      95              :          @param Nx              Number of grid points in x-direction
      96              :          @param Ny              Number of grid points in y-direction
      97              :          @param Nz              Number of grid points in z-direction
      98              :          @param spacing Spacing between grid points
      99              :          */
     100            2 :         GridProperties(Vector3d origin, size_t Nx, size_t Ny, size_t Nz, double spacing) :
     101            2 :                 origin(origin), Nx(Nx), Ny(Ny), Nz(Nz), spacing(Vector3d(spacing)), reflective(false), ipol(TRILINEAR), clipVolume(false) {
     102              :         }
     103              : 
     104              :         /** Constructor for non-cubic grid with spacing vector
     105              :          @param origin  Position of the lower left front corner of the volume
     106              :          @param Nx              Number of grid points in x-direction
     107              :          @param Ny              Number of grid points in y-direction
     108              :          @param Nz              Number of grid points in z-direction
     109              :          @param spacing Spacing vector between grid points
     110              :         */
     111            1 :         GridProperties(Vector3d origin, size_t Nx, size_t Ny, size_t Nz, Vector3d spacing) :
     112            1 :                 origin(origin), Nx(Nx), Ny(Ny), Nz(Nz), spacing(spacing), reflective(false), ipol(TRILINEAR), clipVolume(false) {
     113              :         }
     114              :         
     115            2 :         virtual ~GridProperties() {
     116            4 :         }
     117              :         
     118              :         /** If True, the repetition of the grid is refletive instead of periodic. */
     119              :         void setReflective(bool b) {
     120            0 :                 reflective = b;
     121              :         }
     122              : 
     123              :         /** set the type of interpolation between grid points.
     124              :          * @param i: interpolationType (TRILINEAR, TRICUBIC, NEAREST_NEIGHBOUR) */
     125              :         void setInterpolationType(interpolationType i) {
     126            2 :                 ipol = i;
     127            2 :         }
     128              : 
     129              :         /** If True, the grid is set to zero outside of the volume. */
     130              :         void setClipVolume(bool b) {
     131            2 :                 clipVolume = b;
     132              :         }
     133              : 
     134              :         /** show all GridProperty parameters
     135              :          * @param unit unit for the lengthscale (origin, spacing). Default is 1 = SI units
     136              :          */
     137            0 :         std::string getDescription(double unit = 1) const {
     138            0 :                 std::stringstream ss;
     139            0 :                 ss      << "GridProperties:\torigin: " << origin / unit
     140            0 :                         << "\t" << "Nx: " << Nx << " Ny: " << Ny << " Nz: " << Nz 
     141            0 :                         << "\t" << "spacing: " << spacing / unit
     142            0 :                         << "\t" << "refletive: " << reflective
     143            0 :                         << "\t" << "interpolation: " << ipol
     144            0 :                         << "\n";
     145            0 :                 return ss.str();
     146            0 :         }
     147              : };
     148              : 
     149              : /**
     150              :  @class Grid
     151              :  @brief Template class for fields on a periodic grid with trilinear interpolation
     152              : 
     153              :  The grid spacing is constant with diffrent resolution along all three axes.
     154              :  Values are calculated by trilinear interpolation of the surrounding 8 grid points.
     155              :  The grid is periodically (default) or reflectively extended.
     156              :  The grid sample positions are at 1/2 * size/N, 3/2 * size/N ... (2N-1)/2 * size/N.
     157              :  */
     158              : template<typename T>
     159            9 : class Grid: public Referenced {
     160              :         std::vector<T> grid;
     161              :         size_t Nx, Ny, Nz; /**< Number of grid points */
     162              :         Vector3d origin; /**< Origin of the volume that is represented by the grid. */
     163              :         Vector3d gridOrigin; /**< Grid origin */
     164              :         Vector3d spacing; /**< Distance between grid points, determines the extension of the grid */
     165              :         bool clipVolume; /**< If set to true, all values outside of the grid will be 0*/
     166              :         bool reflective; /**< If set to true, the grid is repeated reflectively instead of periodically */
     167              :         interpolationType ipolType; /**< Type of interpolation between the grid points */
     168              : 
     169              : public:
     170              :         /** Constructor for cubic grid
     171              :          @param origin  Position of the lower left front corner of the volume
     172              :          @param N               Number of grid points in one direction
     173              :          @param spacing Spacing between grid points
     174              :          */
     175           11 :         Grid(Vector3d origin, size_t N, double spacing) {
     176              :                 setOrigin(origin);
     177           11 :                 setGridSize(N, N, N);
     178              :                 setSpacing(Vector3d(spacing));
     179              :                 setReflective(false);
     180              :                 setClipVolume(false);
     181              :                 setInterpolationType(TRILINEAR);
     182            0 :         }
     183              : 
     184              :         /** Constructor for non-cubic grid
     185              :          @param origin  Position of the lower left front corner of the volume
     186              :          @param Nx              Number of grid points in x-direction
     187              :          @param Ny              Number of grid points in y-direction
     188              :          @param Nz              Number of grid points in z-direction
     189              :          @param spacing Spacing between grid points
     190              :          */
     191            7 :         Grid(Vector3d origin, size_t Nx, size_t Ny, size_t Nz, double spacing) {
     192              :                 setOrigin(origin);
     193            7 :                 setGridSize(Nx, Ny, Nz);
     194              :                 setSpacing(Vector3d(spacing));
     195              :                 setReflective(false);
     196              :                 setClipVolume(false);
     197              :                 setInterpolationType(TRILINEAR);
     198            0 :         }
     199              : 
     200              :         /** Constructor for non-cubic grid with spacing vector
     201              :          @param origin  Position of the lower left front corner of the volume
     202              :          @param Nx              Number of grid points in x-direction
     203              :          @param Ny              Number of grid points in y-direction
     204              :          @param Nz              Number of grid points in z-direction
     205              :          @param spacing Spacing vector between grid points
     206              :         */
     207            3 :         Grid(Vector3d origin, size_t Nx, size_t Ny, size_t Nz, Vector3d spacing) {
     208              :                 setOrigin(origin);
     209            3 :                 setGridSize(Nx, Ny, Nz);
     210              :                 setSpacing(spacing);
     211              :                 setReflective(false);
     212              :                 setClipVolume(false);
     213              :                 setInterpolationType(TRILINEAR);
     214            0 :         }
     215              : 
     216              :         /** Constructor for GridProperties
     217              :          @param p       GridProperties instance
     218              :      */
     219           11 :         Grid(const GridProperties &p) :
     220           11 :                 origin(p.origin), spacing(p.spacing), reflective(p.reflective), ipolType(p.ipol) {
     221           11 :                 setGridSize(p.Nx, p.Ny, p.Nz);
     222           11 :                 setClipVolume(p.clipVolume);
     223            0 :         }
     224              : 
     225              :         void setOrigin(Vector3d origin) {
     226              :                 this->origin = origin;
     227              :                 this->gridOrigin = origin + spacing/2;
     228              :         }
     229              : 
     230              :         /** Resize grid, also enlarges the volume as the spacing stays constant */
     231           32 :         void setGridSize(size_t Nx, size_t Ny, size_t Nz) {
     232           32 :                 this->Nx = Nx;
     233           32 :                 this->Ny = Ny;
     234           32 :                 this->Nz = Nz;
     235           32 :                 grid.resize(Nx * Ny * Nz);
     236              :                 setOrigin(origin);
     237           32 :         }
     238              : 
     239              :         void setSpacing(Vector3d spacing) {
     240              :                 this->spacing = spacing;
     241              :                 setOrigin(origin);
     242              :         }
     243              : 
     244              :         void setReflective(bool b) {
     245            8 :                 reflective = b;
     246              :         }
     247              : 
     248              :         // If set to true, all values outside of the grid will be 0.
     249              :         void setClipVolume(bool b) {
     250           23 :                 clipVolume = b;
     251              :         }
     252              : 
     253              :         /** Change the interpolation type to the routine specified by the user. Check if this routine is
     254              :                 contained in the enum interpolationType and thus supported by CRPropa.*/
     255            0 :         void setInterpolationType(interpolationType ipolType) {
     256            0 :                 if (ipolType == TRILINEAR || ipolType == TRICUBIC || ipolType == NEAREST_NEIGHBOUR) {
     257           34 :                         this->ipolType = ipolType;
     258            0 :                         if ((ipolType == TRICUBIC) && (std::is_same<T, Vector3d>::value)) {
     259            0 :                                 KISS_LOG_WARNING << "Tricubic interpolation on Grid3d works only with float-precision, doubles will be downcasted";
     260              :                 }
     261              :                 } else {
     262            0 :                         throw std::runtime_error("InterpolationType: unknown interpolation type");
     263              :                 }
     264            0 :         }
     265              : 
     266              :         interpolationType getInterpolationType() {
     267            2 :                 return ipolType;
     268              :         }
     269              : 
     270            2 :         std::string getInterpolationTypeName() {
     271            2 :                 if (ipolType == TRILINEAR)
     272            0 :                         return "TRILINEAR";
     273            2 :                 if (ipolType == TRICUBIC)
     274            1 :                         return "TRICUBIC";
     275            1 :                 if (ipolType == NEAREST_NEIGHBOUR)
     276            1 :                         return "NEAREST_NEIGHBOUR";
     277              : 
     278            0 :                 return "NOT_UNDERSTOOD";      
     279              :         }
     280              : 
     281              :         /** returns the position of the lower left front corner of the volume */
     282              :         Vector3d getOrigin() const {
     283              :                 return origin;
     284              :         }
     285              : 
     286              :         bool getClipVolume() const {
     287            4 :                 return clipVolume;
     288              :         }
     289              : 
     290              :         size_t getNx() const {
     291          764 :                 return Nx;
     292              :         }
     293              : 
     294              :         size_t getNy() const {
     295        41868 :                 return Ny;
     296              :         }
     297              : 
     298              :         size_t getNz() const {
     299      2663965 :                 return Nz;
     300              :         }
     301              : 
     302              :         /** Calculates the total size of the grid in bytes */
     303              :         size_t getSizeOf() const {
     304            0 :                 return sizeof(grid) + (sizeof(grid[0]) * grid.size());
     305              :         }
     306              : 
     307              :         Vector3d getSpacing() const {
     308              :                 return spacing;
     309              :         }
     310              : 
     311              :         bool isReflective() const {
     312            4 :                 return reflective;
     313              :         }
     314              : 
     315              :         /** Choose the interpolation algorithm based on the set interpolation type.
     316              :           By default this it the trilinear interpolation. The user can change the
     317              :           routine with the setInterpolationType function.*/
     318       100091 :         T interpolate(const Vector3d &position) {
     319              :                 // check for volume
     320       100091 :                 if (clipVolume) {
     321            5 :                         Vector3d edge = origin + Vector3d(Nx, Ny, Nz) * spacing;
     322            5 :                         bool isInVolume = (position.x >= origin.x) && (position.x <= edge.x);
     323            5 :                         isInVolume &= (position.y >= origin.y) && (position.y <= edge.y);
     324            5 :                         isInVolume &= (position.z >= origin.z) && (position.z <= edge.z);
     325            5 :                         if (!isInVolume) 
     326              :                                 return T(0.);
     327              :                 } 
     328              : 
     329       100086 :                 if (ipolType == TRICUBIC)
     330           18 :                         return tricubicInterpolate(T(), position);
     331       100068 :                 else if (ipolType == NEAREST_NEIGHBOUR)
     332           13 :                         return closestValue(position);
     333              :                 else
     334       100055 :                         return trilinearInterpolate(position);
     335              :         }
     336              : 
     337              :         /** Inspector & Mutator */
     338              :         T &get(size_t ix, size_t iy, size_t iz) {
     339      8391214 :                 return grid[ix * Ny * Nz + iy * Nz + iz];
     340              :         }
     341              : 
     342              :         /** Inspector */
     343              :         const T &get(size_t ix, size_t iy, size_t iz) const {
     344       100072 :                 return grid[ix * Ny * Nz + iy * Nz + iz];
     345              :         }
     346              : 
     347              :         const T &periodicGet(size_t ix, size_t iy, size_t iz) const {
     348          192 :                 ix = periodicBoundary(ix, Nx);
     349          192 :                 iy = periodicBoundary(iy, Ny);
     350          192 :                 iz = periodicBoundary(iz, Nz);
     351          192 :                 return grid[ix * Ny * Nz + iy * Nz + iz];
     352              :         }
     353              : 
     354            0 :         const T &reflectiveGet(size_t ix, size_t iy, size_t iz) const {
     355            0 :                 ix = reflectiveBoundary(ix, Nx);
     356            0 :                 iy = reflectiveBoundary(iy, Ny);
     357            0 :                 iz = reflectiveBoundary(iz, Nz);
     358            0 :                 return grid[ix * Ny * Nz + iy * Nz + iz];
     359              :         }
     360              : 
     361              :         T getValue(size_t ix, size_t iy, size_t iz) {
     362            0 :                 return grid[ix * Ny * Nz + iy * Nz + iz];
     363              :         }
     364              : 
     365              :         void setValue(size_t ix, size_t iy, size_t iz, T value) {
     366            0 :                 grid[ix * Ny * Nz + iy * Nz + iz] = value;
     367              :         }
     368              : 
     369              :         /** Return a reference to the grid values */
     370              :         std::vector<T> &getGrid() {
     371        10102 :                 return grid;
     372              :         }
     373              : 
     374              :         /** Position of the grid point of a given index */
     375        10103 :         Vector3d positionFromIndex(int index) const {
     376        10103 :                 int ix = index / (Ny * Nz);
     377        10103 :                 int iy = (index / Nz) % Ny;
     378        10103 :                 int iz = index % Nz;
     379        10103 :                 return Vector3d(ix, iy, iz) * spacing + gridOrigin;
     380              :         }
     381              : 
     382              :         /** Value of a grid point that is closest to a given position / nearest neighbour interpolation */
     383           17 :         T closestValue(const Vector3d &position) const {
     384              :                 Vector3d r = (position - gridOrigin) / spacing;
     385              :                 int ix, iy, iz;
     386           17 :                 if (reflective) {
     387            6 :                         ix = round(r.x);
     388            6 :                         iy = round(r.y);
     389            6 :                         iz = round(r.z);
     390            9 :                         while ((ix < -0.5) or (ix > (Nx-0.5)))
     391            3 :                                 ix = 2 * Nx * (ix > (Nx-0.5)) - ix-1;
     392           11 :                         while ((iy < -0.5) or (iy > (Ny-0.5)))
     393            5 :                                 iy = 2 * Ny * (iy > (Ny-0.5)) - iy-1;
     394            9 :                         while ((iz < -0.5) or (iz > (Nz-0.5)))
     395            3 :                                 iz = 2 * Nz * (iz > (Nz-0.5)) - iz-1;
     396              :                 } else {
     397           11 :                         ix = round(fmod(r.x, Nx));
     398           11 :                         iy = round(fmod(r.y, Ny));
     399           11 :                         iz = round(fmod(r.z, Nz));
     400           11 :                         ix = (ix + Nx * (ix < 0)) % Nx;
     401           11 :                         iy = (iy + Ny * (iy < 0)) % Ny;
     402           11 :                         iz = (iz + Nz * (iz < 0)) % Nz;
     403              :                 }
     404           17 :                 return get(ix, iy, iz);
     405              :         }
     406              : 
     407              : private:
     408              :         #ifdef HAVE_SIMD
     409              :         __m128 simdperiodicGet(size_t ix, size_t iy, size_t iz) const {
     410          576 :                 ix = periodicBoundary(ix, Nx);
     411          576 :                 iy = periodicBoundary(iy, Ny);
     412          576 :                 iz = periodicBoundary(iz, Nz);
     413          576 :                 return convertVector3fToSimd(grid[ix * Ny * Nz + iy * Nz + iz]);
     414              :         }
     415              : 
     416          384 :         __m128 simdreflectiveGet(size_t ix, size_t iy, size_t iz) const {
     417          384 :                 ix = reflectiveBoundary(ix, Nx);
     418          384 :                 iy = reflectiveBoundary(iy, Ny);
     419          384 :                 iz = reflectiveBoundary(iz, Nz);
     420          384 :                 return convertVector3fToSimd(grid[ix * Ny * Nz + iy * Nz + iz]);
     421              :         }
     422              : 
     423              :         __m128 convertVector3fToSimd(const Vector3f v) const {
     424              :                 __m128 simdVar = _mm_set_ps(0,v.z,v.y,v.x);
     425              :                 return simdVar;
     426              :         }
     427              :         
     428              :         Vector3f convertSimdToVector3f(__m128 res) const {
     429              :                 float vec[4];   
     430              :                 _mm_store_ps(&vec[0], res);
     431              :                 Vector3f result = Vector3f(vec[0], vec[1], vec[2]);
     432              :                 return result;
     433              :         }
     434              : 
     435              :         /** Vectorized cubic Interpolator in 1D */
     436              :         __m128 CubicInterpolate(__m128 p0,__m128 p1,__m128 p2,__m128 p3,double position) const {
     437              :                 __m128 c1 = _mm_set1_ps (1/2.);
     438              :                 __m128 c2 = _mm_set1_ps (3/2.);
     439              :                 __m128 c3 = _mm_set1_ps (2.);
     440              :                 __m128 c4 = _mm_set1_ps (5/2.);
     441              : 
     442          315 :                 __m128 pos  = _mm_set1_ps (position);
     443          315 :                 __m128 pos2 = _mm_set1_ps (position*position);
     444          300 :                 __m128 pos3 = _mm_set1_ps (position*position*position);
     445              : 
     446              :                 /** SIMD optimized routine to calculate 'res = ((-0.5*p0+3/2.*p1-3/2.*p2+0.5*p3)*pos*pos*pos+(p0-5/2.*p1+p2*2-0.5*p3)*pos*pos+(-0.5*p0+0.5*p2)*pos+p1);'
     447              :                          where terms are used as:
     448              :                         term = (-0.5*p0+0.5*p2)*pos
     449              :                         term2 = (p0-5/2.*p1+p2*2-0.5*p3)*pos*pos;
     450              :                         term3 = (-0.5*p0+3/2.*p1-3/2.*p2+0.5*p3)*pos*pos*pos;  */
     451              :                 __m128 term = _mm_mul_ps(_mm_sub_ps(_mm_mul_ps(c1,p2),_mm_mul_ps(c1,p0)),pos);
     452              :                 __m128 term2 = _mm_mul_ps(_mm_sub_ps(_mm_add_ps(p0,_mm_mul_ps(c3,p2)),_mm_add_ps(_mm_mul_ps(c4,p1),_mm_mul_ps(c1,p3))),pos2);
     453              :                 __m128 term3 = _mm_mul_ps(_mm_sub_ps(_mm_add_ps(_mm_mul_ps(c2,p1),_mm_mul_ps(c1,p3)),_mm_add_ps(_mm_mul_ps(c1,p0),_mm_mul_ps(c2,p2))),pos3);
     454              :                 __m128 res = _mm_add_ps(_mm_add_ps(_mm_add_ps(term3,term2),term),p1);
     455              :                 return res;
     456              :         }
     457              :         #endif // HAVE_SIMD
     458              :         /** Interpolate the grid tricubic at a given position (see https://www.paulinternet.nl/?page=bicubic, http://graphics.cs.cmu.edu/nsp/course/15-462/Fall04/assts/catmullRom.pdf) */
     459           15 :         Vector3f tricubicInterpolate(Vector3f, const Vector3d &position) const {
     460              :                 #ifdef HAVE_SIMD
     461              :                 // position on a unit grid
     462              :                 Vector3d r = (position - gridOrigin) / spacing;
     463              : 
     464              :                 int iX0, iY0, iZ0;
     465           15 :                 iX0 = floor(r.x);
     466           15 :                 iY0 = floor(r.y);
     467           15 :                 iZ0 = floor(r.z);
     468              : 
     469              :                 double fX, fY, fZ;
     470           15 :                 fX = r.x - iX0;
     471           15 :                 fY = r.y - iY0;
     472           15 :                 fZ = r.z - iZ0;
     473              : 
     474              :                 int nrCubicInterpolations = 4;
     475           15 :                 __m128 interpolateVaryX[nrCubicInterpolations];
     476           15 :                 __m128 interpolateVaryY[nrCubicInterpolations];
     477           15 :                 __m128 interpolateVaryZ[nrCubicInterpolations];
     478              :                 /** Perform 1D interpolations while iterating in each for loop over the index of another direction */
     479           75 :                 for (int iLoopX = -1; iLoopX < nrCubicInterpolations-1; iLoopX++) {
     480          300 :                         for (int iLoopY = -1; iLoopY < nrCubicInterpolations-1; iLoopY++) {
     481         1200 :                                 for (int iLoopZ = -1; iLoopZ < nrCubicInterpolations-1; iLoopZ++) {
     482          960 :                                         if (reflective)
     483          384 :                                                 interpolateVaryZ[iLoopZ+1] = simdreflectiveGet(iX0+iLoopX, iY0+iLoopY, iZ0+iLoopZ);
     484              :                                         else 
     485          576 :                                                 interpolateVaryZ[iLoopZ+1] = simdperiodicGet(iX0+iLoopX, iY0+iLoopY, iZ0+iLoopZ);
     486              :                                 }
     487          240 :                                 interpolateVaryY[iLoopY+1] = CubicInterpolate(interpolateVaryZ[0], interpolateVaryZ[1], interpolateVaryZ[2], interpolateVaryZ[3], fZ);
     488              :                         }
     489           60 :                         interpolateVaryX[iLoopX+1] = CubicInterpolate(interpolateVaryY[0], interpolateVaryY[1], interpolateVaryY[2], interpolateVaryY[3], fY);
     490              :                 }
     491           15 :                 __m128 result = CubicInterpolate(interpolateVaryX[0], interpolateVaryX[1], interpolateVaryX[2], interpolateVaryX[3], fX);
     492           15 :                 return convertSimdToVector3f(result);
     493              :                 #else // HAVE_SIMD
     494              :                 throw std::runtime_error( "Tried to use tricubic Interpolation without SIMD_EXTENSION. SIMD Optimization is necessary for tricubic interpolation of vector grids.\n");
     495              :                 #endif // HAVE_SIMD     
     496           15 :         }
     497              : 
     498              :         /** Vectorized cubic Interpolator in 1D that returns a scalar (see https://www.paulinternet.nl/?page=bicubic, http://graphics.cs.cmu.edu/nsp/course/15-462/Fall04/assts/catmullRom.pdf) */
     499           63 :         double CubicInterpolateScalar(double p0,double p1,double p2,double p3,double pos) const {
     500           63 :                 return((-0.5*p0+3/2.*p1-3/2.*p2+0.5*p3)*pos*pos*pos+(p0-5/2.*p1+p2*2-0.5*p3)*pos*pos+(-0.5*p0+0.5*p2)*pos+p1);
     501              :         }
     502              : 
     503              :   /** Interpolate the grid tricubic at a given position (see https://www.paulinternet.nl/?page=bicubic, http://graphics.cs.cmu.edu/nsp/course/15-462/Fall04/assts/catmullRom.pdf) */
     504            3 :         double tricubicInterpolate(double, const Vector3d &position) const {
     505              :                 /** position on a unit grid */
     506              :                 Vector3d r = (position - gridOrigin) / spacing;
     507              : 
     508              :                 int iX0, iY0, iZ0;
     509            3 :                 iX0 = floor(r.x);
     510            3 :                 iY0 = floor(r.y);
     511            3 :                 iZ0 = floor(r.z);
     512              : 
     513              :                 double fX, fY, fZ;
     514            3 :                 fX = r.x - iX0;
     515            3 :                 fY = r.y - iY0;
     516            3 :                 fZ = r.z - iZ0;
     517              : 
     518              :                 int nrCubicInterpolations = 4;
     519            3 :                 double interpolateVaryX[nrCubicInterpolations];
     520            3 :                 double interpolateVaryY[nrCubicInterpolations];
     521            3 :                 double interpolateVaryZ[nrCubicInterpolations];
     522              :                 /** Perform 1D interpolations while iterating in each for loop over the index of another direction */
     523           15 :                 for (int iLoopX = -1; iLoopX < nrCubicInterpolations-1; iLoopX++) {
     524           60 :                         for (int iLoopY = -1; iLoopY < nrCubicInterpolations-1; iLoopY++) {
     525          240 :                                 for (int iLoopZ = -1; iLoopZ < nrCubicInterpolations-1; iLoopZ++) {
     526          192 :                                         if (reflective)
     527            0 :                                                 interpolateVaryZ[iLoopZ+1] = reflectiveGet(iX0+iLoopX, iY0+iLoopY, iZ0+iLoopZ);
     528              :                                         else
     529          192 :                                                 interpolateVaryZ[iLoopZ+1] = periodicGet(iX0+iLoopX, iY0+iLoopY, iZ0+iLoopZ);
     530              :                                 }
     531           48 :                                 interpolateVaryY[iLoopY+1] = CubicInterpolateScalar(interpolateVaryZ[0], interpolateVaryZ[1], interpolateVaryZ[2], interpolateVaryZ[3], fZ);
     532              :                         }
     533           12 :                         interpolateVaryX[iLoopX+1] = CubicInterpolateScalar(interpolateVaryY[0], interpolateVaryY[1], interpolateVaryY[2], interpolateVaryY[3], fY);
     534              :                 }
     535            3 :                 double result = CubicInterpolateScalar(interpolateVaryX[0], interpolateVaryX[1], interpolateVaryX[2], interpolateVaryX[3], fX);
     536            3 :                 return result;
     537            3 :         }
     538              : 
     539              :         /** Interpolate the grid trilinear at a given position */
     540       100055 :         T trilinearInterpolate(const Vector3d &position) const {
     541              :                 /** position on a unit grid */
     542              :                 Vector3d r = (position - gridOrigin) / spacing;
     543              : 
     544              :                 /** indices of lower (0) and upper (1) neighbours. The neighbours span a grid
     545              :                   with the origin at [iX0, iY0, iZ0] and the most distant corner [iX1, iY1, iZ1]. */
     546              :                 int iX0, iX1, iY0, iY1, iZ0, iZ1;
     547              :                 double resX, resY, resZ, fX0, fY0, fZ0;
     548              : 
     549       100055 :                 if (reflective) {
     550            6 :                         reflectiveClamp(r.x, Nx, iX0, iX1, resX);
     551            6 :                         reflectiveClamp(r.y, Ny, iY0, iY1, resY);
     552            6 :                         reflectiveClamp(r.z, Nz, iZ0, iZ1, resZ);
     553            6 :                         fX0 = resX - floor(resX);
     554            6 :                         fY0 = resY - floor(resY);
     555            6 :                         fZ0 = resZ - floor(resZ);
     556              :                 } else {
     557       100049 :                         periodicClamp(r.x, Nx, iX0, iX1);
     558       100049 :                         periodicClamp(r.y, Ny, iY0, iY1);
     559       100049 :                         periodicClamp(r.z, Nz, iZ0, iZ1);
     560       100049 :                         fX0 = r.x - floor(r.x);
     561       100049 :                         fY0 = r.y - floor(r.y);
     562       100049 :                         fZ0 = r.z - floor(r.z);
     563              :                 }
     564              : 
     565              :                 /** linear fraction to upper neighbours based on lower neighbours calculated above */
     566       100055 :                 double fX1 = 1 - fX0;
     567       100055 :                 double fY1 = 1 - fY0;
     568       100055 :                 double fZ1 = 1 - fZ0;
     569              : 
     570              :                 /** trilinear interpolation (see http://paulbourke.net/miscellaneous/interpolation) */
     571              :                 T b(0.);
     572       100055 :                 b += get(iX0, iY0, iZ0) * fX1 * fY1 * fZ1;
     573       100055 :                 b += get(iX1, iY0, iZ0) * fX0 * fY1 * fZ1;
     574       100055 :                 b += get(iX0, iY1, iZ0) * fX1 * fY0 * fZ1;
     575       100055 :                 b += get(iX0, iY0, iZ1) * fX1 * fY1 * fZ0;
     576            9 :                 b += get(iX1, iY0, iZ1) * fX0 * fY1 * fZ0;
     577            9 :                 b += get(iX0, iY1, iZ1) * fX1 * fY0 * fZ0;
     578            9 :                 b += get(iX1, iY1, iZ0) * fX0 * fY0 * fZ1;
     579            9 :                 b += get(iX1, iY1, iZ1) * fX0 * fY0 * fZ0;
     580              : 
     581       100055 :                 return b;
     582              :         }
     583              : 
     584              : }; // class Grid
     585              : 
     586              : typedef Grid<double> Grid1d;
     587              : typedef Grid<float> Grid1f;
     588              : typedef Grid<Vector3f> Grid3f;
     589              : typedef Grid<Vector3d> Grid3d;
     590              : 
     591              : /** @}*/
     592              : 
     593              : } // namespace crpropa
     594              : 
     595              : #endif // CRPROPA_GRID_H
        

Generated by: LCOV version 2.0-1