From 21e96427b0646ca79bc7c8f123d38d9e92a7bc9f Mon Sep 17 00:00:00 2001
From: Paul McCarthy <pauldmccarthy@gmail.com>
Date: Wed, 21 Aug 2024 18:46:13 +0100
Subject: [PATCH] ENH: Scaffolding for ability to create a Splinterpolator
 instance from an existing set of spline coefficients

---
 splinterpolator.h | 92 ++++++++++++++++++++++++++++++++++-------------
 1 file changed, 68 insertions(+), 24 deletions(-)

diff --git a/splinterpolator.h b/splinterpolator.h
index 9c367c3..fbd7b4f 100644
--- a/splinterpolator.h
+++ b/splinterpolator.h
@@ -45,35 +45,67 @@ class Splinterpolator
 {
 public:
   // Constructors
-  Splinterpolator() : _valid(false), _own_coef(false), _coef(0), _cptr(0), _ndim(0), _nthr(1) {}
-  Splinterpolator(const T *data, const std::vector<unsigned int>& dim, const std::vector<ExtrapolationType>& et, unsigned int order=3, bool copy_low_order=true, Utilities::NoOfThreads nthr=Utilities::NoOfThreads(1), double prec=1e-8) : _valid(false), _own_coef(false), _coef(0), _cptr(0), _ndim(0), _nthr(nthr._n)
+  Splinterpolator()
+    : _valid(false), _own_coef(false), _coef(0), _cptr(0), _ndim(0), _nthr(1) {}
+  Splinterpolator(const T *data_or_coefs,
+                  const std::vector<unsigned int>& dim,
+                  const std::vector<ExtrapolationType>& et,
+                  unsigned int order=3,
+                  bool copy_low_order=true,
+                  Utilities::NoOfThreads nthr=Utilities::NoOfThreads(1),
+                  double prec=1e-8,
+                  bool data_are_coefs=false)
+    : _valid(false), _own_coef(false), _coef(0), _cptr(0), _ndim(0), _nthr(nthr._n)
   {
-    common_construction(data,dim,order,prec,et,copy_low_order);
+    common_construction(data_or_coefs,dim,order,prec,et,copy_low_order,data_are_coefs);
   }
-  Splinterpolator(const T *data, const std::vector<unsigned int>& dim, ExtrapolationType et=Zeros, unsigned int order=3, bool copy_low_order=true, Utilities::NoOfThreads nthr=Utilities::NoOfThreads(1), double prec=1e-8) : _valid(false), _own_coef(false), _coef(0), _cptr(0), _ndim(0), _nthr(nthr._n)
+  Splinterpolator(const T *data_or_coefs,
+                  const std::vector<unsigned int>& dim,
+                  ExtrapolationType et=Zeros,
+                  unsigned int order=3,
+                  bool copy_low_order=true,
+                  Utilities::NoOfThreads
+                  nthr=Utilities::NoOfThreads(1),
+                  double prec=1e-8,
+                  bool data_are_coefs=false)
+    : _valid(false), _own_coef(false), _coef(0), _cptr(0), _ndim(0), _nthr(nthr._n)
   {
     std::vector<ExtrapolationType>   ett(dim.size(),et);
-    common_construction(data,dim,order,prec,ett,copy_low_order);
+    common_construction(data_or_coefs,dim,order,prec,ett,copy_low_order,data_are_coefs);
   }
   // Copy construction. May be removed in future
-  Splinterpolator(const Splinterpolator<T>& src) : _valid(false), _own_coef(false), _coef(0), _cptr(0), _ndim(0) { assign(src); }
+  Splinterpolator(const Splinterpolator<T>& src)
+    : _valid(false), _own_coef(false), _coef(0), _cptr(0), _ndim(0) { assign(src); }
 
   // Destructor
   ~Splinterpolator() { if(_own_coef) delete [] _coef; }
 
   // Assignment. May be removed in future
-  Splinterpolator& operator=(const Splinterpolator& src) { if(_own_coef) delete [] _coef; assign(src); return(*this); }
+  Splinterpolator& operator=(const Splinterpolator& src)
+  { if(_own_coef) delete [] _coef; assign(src); return(*this); }
 
   // Set new data in Splinterpolator.
-  void Set(const T *data, const std::vector<unsigned int>& dim, const std::vector<ExtrapolationType>& et, unsigned int order=3, bool copy_low_order=true, double prec=1e-8)
+  void Set(const T *data_or_coefs,
+           const std::vector<unsigned int>& dim,
+           const std::vector<ExtrapolationType>& et,
+           unsigned int order=3,
+           bool copy_low_order=true,
+           double prec=1e-8,
+           bool data_are_coefs=false)
   {
     if (_own_coef) delete [] _coef;
-    common_construction(data,dim,order,prec,et,copy_low_order);
+    common_construction(data_or_coefs,dim,order,prec,et,copy_low_order,data_are_coefs);
   }
-  void Set(const T *data, const std::vector<unsigned int>& dim, ExtrapolationType et, unsigned int order=3, bool copy_low_order=true, double prec=1e-8)
+  void Set(const T *data_or_coefs,
+           const std::vector<unsigned int>& dim,
+           ExtrapolationType et,
+           unsigned int order=3,
+           bool copy_low_order=true,
+           double prec=1e-8,
+           bool data_are_coefs=false)
   {
     std::vector<ExtrapolationType>  vet(dim.size(),Zeros);
-    Set(data,dim,vet,order,copy_low_order,prec);
+    Set(data_or_coefs,dim,vet,order,copy_low_order,prec,data_are_coefs);
   }
 
   // Return interpolated value
@@ -204,12 +236,18 @@ private:
   //
   // Private helper-functions
   //
-  void common_construction(const T *data, const std::vector<unsigned int>& dim, unsigned int order, double prec, const std::vector<ExtrapolationType>& et, bool copy);
+  void common_construction(const T *data_or_coefs,
+                           const std::vector<unsigned int>& dim,
+                           unsigned int order,
+                           double prec,
+                           const std::vector<ExtrapolationType>& et,
+                           bool copy,
+                           bool data_are_coefs);
   void assign(const Splinterpolator<T>& src);
-  bool calc_coef(const T *data, bool copy);
+  bool calc_coef(const T *data_or_coefs, bool copy, bool data_are_coefs);
   void deconv_along(unsigned int dim);
-  void deconv_along_mt_helper(unsigned int dim, unsigned int mdim, unsigned int mstep, unsigned int offset, unsigned int step, 
-			      const std::vector<unsigned int>& rdim, const std::vector<unsigned int>& rstep);						
+  void deconv_along_mt_helper(unsigned int dim, unsigned int mdim, unsigned int mstep, unsigned int offset, unsigned int step,
+			      const std::vector<unsigned int>& rdim, const std::vector<unsigned int>& rstep);
   T coef(int *indx) const;
   const T* coef_ptr() const {if (_own_coef) return(_coef); else return(_cptr); }
   unsigned int indx2indx(int indx, unsigned int d) const;
@@ -1329,14 +1367,21 @@ unsigned int Splinterpolator<T>::n_nonzero(const unsigned int *vec) const
 /////////////////////////////////////////////////////////////////////
 
 template<class T>
-void Splinterpolator<T>::common_construction(const T *data, const std::vector<unsigned int>& dim, unsigned int order, double prec, const std::vector<ExtrapolationType>& et, bool copy)
+void Splinterpolator<T>::common_construction(
+  const T *data_or_coefs,
+  const std::vector<unsigned int>& dim,
+  unsigned int order,
+  double prec,
+  const std::vector<ExtrapolationType>& et,
+  bool copy,
+  bool data_are_coefs)
 {
   if (!dim.size()) throw SplinterpolatorException("common_construction: data has zeros dimensions");
   if (dim.size() > 5) throw SplinterpolatorException("common_construction: data cannot have more than 5 dimensions");
   if (dim.size() != et.size()) throw SplinterpolatorException("common_construction: dim and et must have the same size");
   for (unsigned int i=0; i<dim.size(); i++) if (!dim[i]) throw SplinterpolatorException("common_construction: data cannot have zeros size in any direction");
   if (order > 7) throw SplinterpolatorException("common_construction: spline order must be lesst than 7");
-  if (!data) throw SplinterpolatorException("common_construction: zero data pointer");
+  if (!data_or_coefs) throw SplinterpolatorException("common_construction: zero data pointer");
 
   _order = order;
   _prec = prec;
@@ -1345,8 +1390,7 @@ void Splinterpolator<T>::common_construction(const T *data, const std::vector<un
   _ndim = dim.size();
   for (unsigned int i=0; i<5; i++) _dim[i]  = (i < dim.size()) ? dim[i] : 1;
 
-  _own_coef = calc_coef(data,copy);
-
+  _own_coef = calc_coef(data_or_coefs,copy,data_are_coefs);
   _valid = true;
 }
 
@@ -1385,16 +1429,16 @@ void Splinterpolator<T>::assign(const Splinterpolator<T>& src)
 /////////////////////////////////////////////////////////////////////
 
 template<class T>
-bool Splinterpolator<T>::calc_coef(const T *data, bool copy)
+bool Splinterpolator<T>::calc_coef(const T *data_or_coefs, bool copy, bool data_are_coefs)
 {
-  if (_order < 2 && !copy) { _cptr = data; return(false); }
+  if (_order < 2 && !copy) { _cptr = data_or_coefs; return(false); }
 
   // Allocate memory and put the original data into _coef
   //
   unsigned int ts=1;
   for (unsigned int i=0; i<_dim.size(); i++) ts *= _dim[i];
   _coef = new T[ts];
-  memcpy(_coef,data,ts*sizeof(T));
+  memcpy(_coef,data_or_coefs,ts*sizeof(T));
 
   if (_order < 2) return(true);  // If nearest neighbour or linear, that's all we need
 
@@ -1464,8 +1508,8 @@ void Splinterpolator<T>::deconv_along(unsigned int dim)
 
 template<class T>
 void Splinterpolator<T>::deconv_along_mt_helper(unsigned int                     dim,
-						unsigned int                     mdim, 
-						unsigned int                     mstep, 
+						unsigned int                     mdim,
+						unsigned int                     mstep,
 						unsigned int                     offset, // Offset into parallel dimension
 						unsigned int                     step,   // Step size in parallel dimension
 						const std::vector<unsigned int>& rdim,
-- 
GitLab