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 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  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. Spline = SplineSet(n);
  86. Spline.a = y;
  87. Spline.x = x;
  88. VectorXr h = VectorXr::Zero(n);
  89. for(int i=0; i<n; ++i)
  90. h(i) = Spline.x(i+1)-Spline.x(i);
  91. VectorXr alpha(n-1);
  92. for(int i=1; i<n-1; ++i)
  93. alpha(i) = 3.*(Spline.a[i+1]-Spline.a[i])/h[i] - 3.*(Spline.a[i]-Spline.a[i-1])/h[i-1] ;
  94. VectorXr l = VectorXr::Zero(n+1);
  95. VectorXr mu = VectorXr::Zero(n+1);
  96. VectorXr z = VectorXr::Zero(n+1);
  97. l[0] = 1;
  98. mu[0] = 0;
  99. z[0] = 0;
  100. for(int i = 1; i < n-1; ++i) {
  101. l[i] = 2 *(Spline.x[i+1]-Spline.x[i-1])-h[i-1]*mu[i-1];
  102. mu[i] = h[i]/l[i];
  103. z[i] = (alpha[i]-h[i-1]*z[i-1])/l[i];
  104. }
  105. l[n] = 1;
  106. z[n] = 0;
  107. for(int j = n-1; j >= 0; --j) {
  108. Spline.c[j] = z[j] - mu[j] * Spline.c[j+1];
  109. Spline.b[j] = (Spline.a[j+1]-Spline.a[j])/h[j]-h[j]*(Spline.c[j+1]+2*Spline.c[j])/3;
  110. Spline.d[j] = (Spline.c[j+1]-Spline.c[j])/3/h[j];
  111. }
  112. // On OSX, this causes a strange bug 'sometimes', alignment?
  113. //Spline.c = Spline.c.head(n);
  114. return;
  115. } // ----- end of method CubicSplineInterpolator::SetKnots -----
  116. //--------------------------------------------------------------------------------------
  117. // Class: CubicSplineInterplator
  118. // Method: ResetKnotOrdinate
  119. //--------------------------------------------------------------------------------------
  120. void CubicSplineInterpolator::ResetKnotOrdinate ( const VectorXr& y ) {
  121. VectorXr x = Spline.x;
  122. SetKnots(x, y);
  123. return ;
  124. } // ----- end of method CubicSplineInterplator::ResetKnotOrdinate -----
  125. //--------------------------------------------------------------------------------------
  126. // Class: CubicSplineInterpolator
  127. // Method: InterpolateOrderedSet
  128. //--------------------------------------------------------------------------------------
  129. VectorXr CubicSplineInterpolator::InterpolateOrderedSet ( const VectorXr& x ) {
  130. VectorXr y = VectorXr::Zero(x.size());
  131. int ii = 0;
  132. for (int iy=0; iy<y.size(); ++iy) {
  133. y[iy] = Interpolate(x[iy], ii);
  134. }
  135. return y;
  136. } // ----- end of method CubicSplineInterpolator::InterpolateOrderedSet -----
  137. //--------------------------------------------------------------------------------------
  138. // Class: CubicSplineInterpolator
  139. // Method: Interpolate
  140. //--------------------------------------------------------------------------------------
  141. Real CubicSplineInterpolator::Interpolate ( const Real& x, int& i) {
  142. // O(n) search, could do bisection, but if these are sorted, then this is quick
  143. while(Spline.x[i] < x && i<Spline.x.size()) {
  144. ++i;
  145. }
  146. --i;
  147. // if ( x > Spline.x[i] ) {
  148. // std::cout << "DOOM\t" << x << "\t" << i << "\t" << Spline.x[i];
  149. // throw std::runtime_error("CubicSplineInterpolator::Interpolate ATTEMPT TO INTERPOLATE PAST LAST KNOT");
  150. // }
  151. return Spline.a[i] + Spline.b[i]*(x-Spline.x[i]) + Spline.c[i]*((x-Spline.x[i])*(x-Spline.x[i])) +
  152. Spline.d[i]*((x-Spline.x[i])*(x-Spline.x[i])*(x-Spline.x[i]) );
  153. } // ----- end of method CubicSplineInterpolator::Interpolate -----
  154. //--------------------------------------------------------------------------------------
  155. // Class: CubicSplineInterpolator
  156. // Method: Interpolate
  157. //--------------------------------------------------------------------------------------
  158. Real CubicSplineInterpolator::Interpolate ( const Real& x ) {
  159. int ii(0);
  160. return Interpolate(x, ii);
  161. }
  162. //--------------------------------------------------------------------------------------
  163. // Class: CubicSplineInterpolator
  164. // Method: Integrate
  165. //--------------------------------------------------------------------------------------
  166. Real CubicSplineInterpolator::Integrate ( const Real& x0, const Real& x1, const int& n ) {
  167. assert(n > 0);
  168. // force n to be even?
  169. //n += (n % 2);
  170. Real S = Interpolate(x0) + Interpolate(x1);
  171. Real h = (x1 - x0) / Real(n);
  172. int ik = 0;
  173. for (int i=1; i<n; i+=2) {
  174. S += 4. * Interpolate(x0 + (Real)(i)*h, ik);
  175. }
  176. ik = 0;
  177. for (int i=2; i<n-1; i+=2) {
  178. S += 2. * Interpolate(x0 + (Real)(i)*h, ik);
  179. }
  180. return S * h / 3.;
  181. }
  182. //--------------------------------------------------------------------------------------
  183. // Class: CubicSplineInterpolator
  184. // Method: Integrate
  185. //--------------------------------------------------------------------------------------
  186. Real CubicSplineInterpolator::Integrate ( const Real& x0, const Real& x1 ) {
  187. int i0 = Interval(x0);
  188. int i1 = Interval(x1);
  189. Real h0 = x0 - Spline.x(i0);
  190. if (mflag == -1) h0 = 0;
  191. Real h1 = x1 - Spline.x(i1);
  192. Real cubint = (((Spline.d(i1)*h1/4.0 + Spline.c(i1) )*h1/3.0 +
  193. Spline.b(i1) )*h1/2.0 + Spline.a(i1) )*h1
  194. - (((Spline.d(i0)*h0/4.0 + Spline.c(i0) )*h0/3.0 +
  195. Spline.b(i0) )*h0/2.0 + Spline.a(i0) )*h0;
  196. // Include integrals over intervening intervals.
  197. if (i1 > i0) {
  198. for (int i=i0; i<i1-1; ++i) {
  199. Real h = Spline.x(i+1) - Spline.x(i);
  200. cubint += (((Spline.d(i)*h/4.0 + Spline.c(i) )*h/3.0 +
  201. Spline.b(i))*h/2.0 + Spline.a(i) )*h;
  202. }
  203. }
  204. return cubint;
  205. } // ----- end of method CubicSplineInterpolator::Integrate -----
  206. //--------------------------------------------------------------------------------------
  207. // Class: CubicSplineInterpolator
  208. // Method: Interval
  209. //--------------------------------------------------------------------------------------
  210. int CubicSplineInterpolator::Interval ( const Real& x ) {
  211. std::cerr << "ENTERING CubicSplineInterpolator::Inverval. Known bugs here" << std::endl;
  212. int nx = Spline.x.size() - 2; // TODO check if this is correct or just -1
  213. // when x not in range
  214. if (x <= Spline.x(0) || nx <= 1 ) {
  215. mflag = -1;
  216. return 1;
  217. }
  218. if (x >= Spline.x(nx)) {
  219. mflag = 1;
  220. return nx;
  221. }
  222. mflag = 0;
  223. if (ilo >= nx) ilo = nx-1;
  224. int ihi = ilo+1;
  225. // if x is already in the interval
  226. if ( x<Spline.x(ihi) && x >= Spline.x(ilo) ) {
  227. //std::cout << "TRIVIAL INTERVAL " << Spline.x(ilo) << "\t" << x << "\t" << Spline.x(ihi) << std::endl;
  228. return ilo;
  229. }
  230. if (x <= Spline.x(ilo)) { // decrease ilo to capture
  231. int istep = 1;
  232. for (int ix=1; ix<nx; ++ix) {
  233. ihi = ilo;
  234. ilo = ihi - istep;
  235. ilo = std::max(1, ilo);
  236. if (x >= Spline.x(ilo) || ilo == 1) break;
  237. istep *= 2;
  238. }
  239. } else if (x >= Spline.x(ihi)) { // increase ihi to capture
  240. int istep = 1;
  241. for (int ix=1; ix<nx; ++ix) {
  242. ilo = ihi;
  243. ihi = ilo + istep;
  244. ihi = std::min(ihi, nx);
  245. if (x <= Spline.x(ihi) || ihi == nx) break;
  246. istep *= 2;
  247. }
  248. }
  249. // Now Spline.x(ilo) <= x < Spline.x(ihi) --> Narrow the interval.
  250. //std::cout << "WIDE INTERVAL " << Spline.x(ilo) << "\t" << x << "\t" << Spline.x(ihi) << std::endl;
  251. for (int ix=1; ix<nx; ++ix) {
  252. int middle = (ilo+ihi) / 2;
  253. if (middle == ilo) break;
  254. if (x < Spline.x(middle)) {
  255. ihi = middle;
  256. } else {
  257. ilo = middle;
  258. }
  259. }
  260. assert ( Spline.x(ilo) < x && x < Spline.x(ihi) );
  261. return ilo;
  262. } // ----- end of method CubicSplineInterpolator::Inverval -----
  263. //--------------------------------------------------------------------------------------
  264. // Class: CubicSplineInterplator
  265. // Method: GetAbscissa
  266. //--------------------------------------------------------------------------------------
  267. VectorXr CubicSplineInterpolator::GetKnotAbscissa ( ) {
  268. return Spline.x;
  269. } // ----- end of method CubicSplineInterplator::get_GetAbscissa -----
  270. //--------------------------------------------------------------------------------------
  271. // Class: CubicSplineInterpolator
  272. // Method: GetKnotOrdinate
  273. //--------------------------------------------------------------------------------------
  274. VectorXr CubicSplineInterpolator::GetKnotOrdinate ( ) {
  275. return Spline.a;
  276. } // ----- end of method CubicSplineInterpolator::GetKnotOrdinate -----
  277. } // ----- end of Lemma name -----
  278. /* vim: set tabstop=4 expandtab: */
  279. /* vim: set filetype=cpp: */