Lemma is an Electromagnetics API
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

CubicSplineInterpolator.cpp 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. /* This file is part of Lemma, a geophysical modelling and inversion API.
  2. * More information is available at http://lemmasoftware.org
  3. */
  4. /* This Source Code Form is subject to the terms of the Mozilla Public
  5. * License, v. 2.0. If a copy of the MPL was not distributed with this
  6. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  7. */
  8. /**
  9. * @file
  10. * @date 02/07/2014 12:50:52 PM
  11. * @version $Id$
  12. * @author Trevor Irons (ti)
  13. * @email Trevor.Irons@lemmasoftware.org
  14. * @copyright Copyright (c) 2014,2018 Trevor Irons
  15. */
  16. #include "CubicSplineInterpolator.h"
  17. #include<iostream>
  18. #include<fstream>
  19. #include<vector>
  20. #include<algorithm>
  21. #include<cmath>
  22. namespace Lemma {
  23. // ==================== FRIEND METHODS =====================
  24. std::ostream &operator << (std::ostream &stream, const CubicSplineInterpolator &ob) {
  25. stream << ob.Serialize() << "\n---\n"; // End of doc ---
  26. return stream;
  27. }
  28. // ==================== LIFECYCLE =======================
  29. //--------------------------------------------------------------------------------------
  30. // Class: CubicSplineInterpolator
  31. // Method: CubicSplineInterpolator
  32. // Description: constructor (locked with ctor_key)
  33. //--------------------------------------------------------------------------------------
  34. CubicSplineInterpolator::CubicSplineInterpolator ( const ctor_key& key ) : LemmaObject( key ) {
  35. } // ----- end of method CubicSplineInterpolator::CubicSplineInterpolator (constructor) -----
  36. //--------------------------------------------------------------------------------------
  37. // Class: CubicSplineInterpolator
  38. // Method: CubicSplineInterpolator
  39. // Description: DeSerializing constructor (locked with ctor_key)
  40. //--------------------------------------------------------------------------------------
  41. CubicSplineInterpolator::CubicSplineInterpolator (const YAML::Node& node, const ctor_key& key ) : LemmaObject(node, key) {
  42. } // ----- end of method CubicSplineInterpolator::CubicSplineInterpolator (constructor) -----
  43. //--------------------------------------------------------------------------------------
  44. // Class: CubicSplineInterpolator
  45. // Method: NewSP()
  46. // Description: public constructor
  47. //--------------------------------------------------------------------------------------
  48. std::shared_ptr<CubicSplineInterpolator> CubicSplineInterpolator::NewSP() {
  49. return std::make_shared<CubicSplineInterpolator>( ctor_key() );
  50. }
  51. //--------------------------------------------------------------------------------------
  52. // Class: CubicSplineInterpolator
  53. // Method: Serialize
  54. //--------------------------------------------------------------------------------------
  55. YAML::Node CubicSplineInterpolator::Serialize ( ) const {
  56. YAML::Node node = LemmaObject::Serialize();;
  57. node.SetTag( GetName() );
  58. // FILL IN CLASS SPECIFICS HERE
  59. return node;
  60. } // ----- end of method CubicSplineInterpolator::Serialize -----
  61. //--------------------------------------------------------------------------------------
  62. // Class: CubicSplineInterpolator
  63. // Method: DeSerialize
  64. //--------------------------------------------------------------------------------------
  65. std::shared_ptr<CubicSplineInterpolator> CubicSplineInterpolator::DeSerialize ( const YAML::Node& node ) {
  66. if (node.Tag() != "CubicSplineInterpolator") {
  67. throw DeSerializeTypeMismatch( "CubicSplineInterpolator", node.Tag());
  68. }
  69. return std::make_shared<CubicSplineInterpolator>( node, ctor_key() );
  70. }
  71. //--------------------------------------------------------------------------------------
  72. // Class: CubicSplineInterpolator
  73. // Method: ~CubicSplineInterpolator
  74. // Description: destructor (protected)
  75. //--------------------------------------------------------------------------------------
  76. CubicSplineInterpolator::~CubicSplineInterpolator () {
  77. } // ----- end of method CubicSplineInterpolator::~CubicSplineInterpolator (destructor) -----
  78. // ==================== OPERATIONS =======================
  79. //--------------------------------------------------------------------------------------
  80. // Class: CubicSplineInterpolator
  81. // Method: SetKnots
  82. //--------------------------------------------------------------------------------------
  83. void CubicSplineInterpolator::SetKnots ( const VectorXr& x, const VectorXr& y ) {
  84. //int n = x.size()-1;
  85. Index n = x.size()-1;
  86. Spline = SplineSet(n);
  87. Spline.a = y;
  88. Spline.x = x;
  89. VectorXr h = VectorXr::Zero(n);
  90. for(Index i=0; i<n; ++i)
  91. h(i) = Spline.x(i+1)-Spline.x(i);
  92. VectorXr alpha(n-1);
  93. for(Index i=1; i<n-1; ++i)
  94. alpha(i) = 3.*(Spline.a[i+1]-Spline.a[i])/h[i] - 3.*(Spline.a[i]-Spline.a[i-1])/h[i-1] ;
  95. VectorXr l = VectorXr::Zero(n+1);
  96. VectorXr mu = VectorXr::Zero(n+1);
  97. VectorXr z = VectorXr::Zero(n+1);
  98. l[0] = 1;
  99. mu[0] = 0;
  100. z[0] = 0;
  101. for(Index i = 1; i < n-1; ++i) {
  102. l[i] = 2 *(Spline.x[i+1]-Spline.x[i-1])-h[i-1]*mu[i-1];
  103. mu[i] = h[i]/l[i];
  104. z[i] = (alpha[i]-h[i-1]*z[i-1])/l[i];
  105. }
  106. l[n] = 1;
  107. z[n] = 0;
  108. for(Index j = n-1; j >= 0; --j) {
  109. Spline.c[j] = z[j] - mu[j] * Spline.c[j+1];
  110. Spline.b[j] = (Spline.a[j+1]-Spline.a[j])/h[j]-h[j]*(Spline.c[j+1]+2*Spline.c[j])/3;
  111. Spline.d[j] = (Spline.c[j+1]-Spline.c[j])/3/h[j];
  112. }
  113. // On OSX, this causes a strange bug 'sometimes', alignment?
  114. //Spline.c = Spline.c.head(n);
  115. return;
  116. } // ----- end of method CubicSplineInterpolator::SetKnots -----
  117. //--------------------------------------------------------------------------------------
  118. // Class: CubicSplineInterplator
  119. // Method: ResetKnotOrdinate
  120. //--------------------------------------------------------------------------------------
  121. void CubicSplineInterpolator::ResetKnotOrdinate ( const VectorXr& y ) {
  122. VectorXr x = Spline.x;
  123. SetKnots(x, y);
  124. return ;
  125. } // ----- end of method CubicSplineInterplator::ResetKnotOrdinate -----
  126. //--------------------------------------------------------------------------------------
  127. // Class: CubicSplineInterpolator
  128. // Method: InterpolateOrderedSet
  129. //--------------------------------------------------------------------------------------
  130. VectorXr CubicSplineInterpolator::InterpolateOrderedSet ( const VectorXr& x ) {
  131. VectorXr y = VectorXr::Zero(x.size());
  132. int ii = 0;
  133. for (int iy=0; iy<y.size(); ++iy) {
  134. y[iy] = Interpolate(x[iy], ii);
  135. }
  136. return y;
  137. } // ----- end of method CubicSplineInterpolator::InterpolateOrderedSet -----
  138. //--------------------------------------------------------------------------------------
  139. // Class: CubicSplineInterpolator
  140. // Method: Interpolate
  141. //--------------------------------------------------------------------------------------
  142. Real CubicSplineInterpolator::Interpolate ( const Real& x, int& i) {
  143. // O(n) search, could do bisection, but if these are sorted, then this is quick
  144. while(Spline.x[i] < x && i<Spline.x.size()-1) {
  145. ++i;
  146. }
  147. --i;
  148. // if ( x > Spline.x[i] ) {
  149. // std::cout << "DOOM in interplate\t x=" << x << "\ti=" << i << "\tSpline.x[i]=" << Spline.x[i] << std::endl;
  150. // std::cout <<"Spline.x.size()" << Spline.x.size() << std::endl;
  151. // std::cout << "Spline.x" << Spline.x.transpose() << std::endl;
  152. // //throw std::runtime_error("CubicSplineInterpolator::Interpolate ATTEMPT TO INTERPOLATE PAST LAST KNOT");
  153. // }
  154. return Spline.a[i] + Spline.b[i]*(x-Spline.x[i]) + Spline.c[i]*((x-Spline.x[i])*(x-Spline.x[i])) +
  155. Spline.d[i]*((x-Spline.x[i])*(x-Spline.x[i])*(x-Spline.x[i]) );
  156. } // ----- end of method CubicSplineInterpolator::Interpolate -----
  157. //--------------------------------------------------------------------------------------
  158. // Class: CubicSplineInterpolator
  159. // Method: Interpolate
  160. //--------------------------------------------------------------------------------------
  161. Real CubicSplineInterpolator::Interpolate ( const Real& x ) {
  162. int ii(0);
  163. return Interpolate(x, ii);
  164. }
  165. //--------------------------------------------------------------------------------------
  166. // Class: CubicSplineInterpolator
  167. // Method: Integrate
  168. //--------------------------------------------------------------------------------------
  169. Real CubicSplineInterpolator::Integrate ( const Real& x0, const Real& x1, const int& n ) {
  170. assert(n > 0);
  171. // force n to be even?
  172. //n += (n % 2);
  173. Real S = Interpolate(x0) + Interpolate(x1);
  174. Real h = (x1 - x0) / Real(n);
  175. int ik = 0;
  176. for (int i=1; i<n; i+=2) {
  177. S += 4. * Interpolate(x0 + (Real)(i)*h, ik);
  178. }
  179. ik = 0;
  180. for (int i=2; i<n-1; i+=2) {
  181. S += 2. * Interpolate(x0 + (Real)(i)*h, ik);
  182. }
  183. return S * h / 3.;
  184. }
  185. //--------------------------------------------------------------------------------------
  186. // Class: CubicSplineInterpolator
  187. // Method: Integrate
  188. //--------------------------------------------------------------------------------------
  189. Real CubicSplineInterpolator::Integrate ( const Real& x0, const Real& x1 ) {
  190. Index i0 = Interval(x0);
  191. Index i1 = Interval(x1);
  192. Real h0 = x0 - Spline.x(i0);
  193. if (mflag == -1) h0 = 0;
  194. Real h1 = x1 - Spline.x(i1);
  195. Real cubint = (((Spline.d(i1)*h1/4.0 + Spline.c(i1) )*h1/3.0 +
  196. Spline.b(i1) )*h1/2.0 + Spline.a(i1) )*h1
  197. - (((Spline.d(i0)*h0/4.0 + Spline.c(i0) )*h0/3.0 +
  198. Spline.b(i0) )*h0/2.0 + Spline.a(i0) )*h0;
  199. // Include integrals over intervening intervals.
  200. if (i1 > i0) {
  201. for (Index i=i0; i<i1-1; ++i) {
  202. Real h = Spline.x(i+1) - Spline.x(i);
  203. cubint += (((Spline.d(i)*h/4.0 + Spline.c(i) )*h/3.0 +
  204. Spline.b(i))*h/2.0 + Spline.a(i) )*h;
  205. }
  206. }
  207. return cubint;
  208. } // ----- end of method CubicSplineInterpolator::Integrate -----
  209. //--------------------------------------------------------------------------------------
  210. // Class: CubicSplineInterpolator
  211. // Method: Interval
  212. //--------------------------------------------------------------------------------------
  213. Index CubicSplineInterpolator::Interval ( const Real& x ) {
  214. std::cerr << "ENTERING CubicSplineInterpolator::Inverval. Known bugs here" << std::endl;
  215. Index nx = Spline.x.size() - 2; // TODO check if this is correct or just -1
  216. // when x not in range
  217. if (x <= Spline.x(0) || nx <= 1 ) {
  218. mflag = -1;
  219. return 1;
  220. }
  221. if (x >= Spline.x(nx)) {
  222. mflag = 1;
  223. return nx;
  224. }
  225. mflag = 0;
  226. if (ilo >= nx) ilo = nx-1;
  227. Index ihi = ilo+1;
  228. // if x is already in the interval
  229. if ( x<Spline.x(ihi) && x >= Spline.x(ilo) ) {
  230. //std::cout << "TRIVIAL INTERVAL " << Spline.x(ilo) << "\t" << x << "\t" << Spline.x(ihi) << std::endl;
  231. return ilo;
  232. }
  233. if (x <= Spline.x(ilo)) { // decrease ilo to capture
  234. Index istep = 1;
  235. for (Index ix=1; ix<nx; ++ix) {
  236. ihi = ilo;
  237. ilo = ihi - istep;
  238. ilo = std::max(Index(1), ilo);
  239. if (x >= Spline.x(ilo) || ilo == 1) break;
  240. istep *= 2;
  241. }
  242. } else if (x >= Spline.x(ihi)) { // increase ihi to capture
  243. Index istep = 1;
  244. for (Index ix=1; ix<nx; ++ix) {
  245. ilo = ihi;
  246. ihi = ilo + istep;
  247. ihi = std::min(ihi, nx);
  248. if (x <= Spline.x(ihi) || ihi == nx) break;
  249. istep *= 2;
  250. }
  251. }
  252. // Now Spline.x(ilo) <= x < Spline.x(ihi) --> Narrow the interval.
  253. //std::cout << "WIDE INTERVAL " << Spline.x(ilo) << "\t" << x << "\t" << Spline.x(ihi) << std::endl;
  254. for (Index ix=1; ix<nx; ++ix) {
  255. Index middle = (ilo+ihi) / 2;
  256. if (middle == ilo) break;
  257. if (x < Spline.x(middle)) {
  258. ihi = middle;
  259. } else {
  260. ilo = middle;
  261. }
  262. }
  263. assert ( Spline.x(ilo) < x && x < Spline.x(ihi) );
  264. return ilo;
  265. } // ----- end of method CubicSplineInterpolator::Inverval -----
  266. //--------------------------------------------------------------------------------------
  267. // Class: CubicSplineInterplator
  268. // Method: GetAbscissa
  269. //--------------------------------------------------------------------------------------
  270. VectorXr CubicSplineInterpolator::GetKnotAbscissa ( ) {
  271. return Spline.x;
  272. } // ----- end of method CubicSplineInterplator::get_GetAbscissa -----
  273. //--------------------------------------------------------------------------------------
  274. // Class: CubicSplineInterpolator
  275. // Method: GetKnotOrdinate
  276. //--------------------------------------------------------------------------------------
  277. VectorXr CubicSplineInterpolator::GetKnotOrdinate ( ) {
  278. return Spline.a;
  279. } // ----- end of method CubicSplineInterpolator::GetKnotOrdinate -----
  280. } // ----- end of Lemma name -----
  281. /* vim: set tabstop=4 expandtab: */
  282. /* vim: set filetype=cpp: */