Lemma is an Electromagnetics API
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

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: */