LCOV - code coverage report
Current view: top level - include/crpropa - Grid.h (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 173 195 88.7 %
Date: 2024-04-29 14:43:01 Functions: 23 56 41.1 %

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

Generated by: LCOV version 1.14