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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  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. // throw std::runtime_error("CubicSplineInterpolator::Interpolate ATTEMPT TO INTERPOLATE PAST LAST KNOT");
  149. //}
  150. return Spline.a[i] + Spline.b[i]*(x-Spline.x[i]) + Spline.c[i]*((x-Spline.x[i])*(x-Spline.x[i])) +
  151. Spline.d[i]*((x-Spline.x[i])*(x-Spline.x[i])*(x-Spline.x[i]) );
  152. } // ----- end of method CubicSplineInterpolator::Interpolate -----
  153. //--------------------------------------------------------------------------------------
  154. // Class: CubicSplineInterpolator
  155. // Method: Interpolate
  156. //--------------------------------------------------------------------------------------
  157. Real CubicSplineInterpolator::Interpolate ( const Real& x ) {
  158. int ii(0);
  159. return Interpolate(x, ii);
  160. }
  161. //--------------------------------------------------------------------------------------
  162. // Class: CubicSplineInterpolator
  163. // Method: Integrate
  164. //--------------------------------------------------------------------------------------
  165. Real CubicSplineInterpolator::Integrate ( const Real& x0, const Real& x1, const int& n ) {
  166. assert(n > 0);
  167. // force n to be even?
  168. //n += (n % 2);
  169. Real S = Interpolate(x0) + Interpolate(x1);
  170. Real h = (x1 - x0) / Real(n);
  171. int ik = 0;
  172. for (int i=1; i<n; i+=2) {
  173. S += 4. * Interpolate(x0 + (Real)(i)*h, ik);
  174. }
  175. ik = 0;
  176. for (int i=2; i<n-1; i+=2) {
  177. S += 2. * Interpolate(x0 + (Real)(i)*h, ik);
  178. }
  179. return S * h / 3.;
  180. }
  181. //--------------------------------------------------------------------------------------
  182. // Class: CubicSplineInterpolator
  183. // Method: Integrate
  184. //--------------------------------------------------------------------------------------
  185. Real CubicSplineInterpolator::Integrate ( const Real& x0, const Real& x1 ) {
  186. int i0 = Interval(x0);
  187. int i1 = Interval(x1);
  188. Real h0 = x0 - Spline.x(i0);
  189. if (mflag == -1) h0 = 0;
  190. Real h1 = x1 - Spline.x(i1);
  191. Real cubint = (((Spline.d(i1)*h1/4.0 + Spline.c(i1) )*h1/3.0 +
  192. Spline.b(i1) )*h1/2.0 + Spline.a(i1) )*h1
  193. - (((Spline.d(i0)*h0/4.0 + Spline.c(i0) )*h0/3.0 +
  194. Spline.b(i0) )*h0/2.0 + Spline.a(i0) )*h0;
  195. // Include integrals over intervening intervals.
  196. if (i1 > i0) {
  197. for (int i=i0; i<i1-1; ++i) {
  198. Real h = Spline.x(i+1) - Spline.x(i);
  199. cubint += (((Spline.d(i)*h/4.0 + Spline.c(i) )*h/3.0 +
  200. Spline.b(i))*h/2.0 + Spline.a(i) )*h;
  201. }
  202. }
  203. return cubint;
  204. } // ----- end of method CubicSplineInterpolator::Integrate -----
  205. //--------------------------------------------------------------------------------------
  206. // Class: CubicSplineInterpolator
  207. // Method: Interval
  208. //--------------------------------------------------------------------------------------
  209. int CubicSplineInterpolator::Interval ( const Real& x ) {
  210. std::cerr << "ENTERING CubicSplineInterpolator::Inverval. Known bugs here" << std::endl;
  211. int nx = Spline.x.size() - 2; // TODO check if this is correct or just -1
  212. // when x not in range
  213. if (x <= Spline.x(0) || nx <= 1 ) {
  214. mflag = -1;
  215. return 1;
  216. }
  217. if (x >= Spline.x(nx)) {
  218. mflag = 1;
  219. return nx;
  220. }
  221. mflag = 0;
  222. if (ilo >= nx) ilo = nx-1;
  223. int ihi = ilo+1;
  224. // if x is already in the interval
  225. if ( x<Spline.x(ihi) && x >= Spline.x(ilo) ) {
  226. //std::cout << "TRIVIAL INTERVAL " << Spline.x(ilo) << "\t" << x << "\t" << Spline.x(ihi) << std::endl;
  227. return ilo;
  228. }
  229. if (x <= Spline.x(ilo)) { // decrease ilo to capture
  230. int istep = 1;
  231. for (int ix=1; ix<nx; ++ix) {
  232. ihi = ilo;
  233. ilo = ihi - istep;
  234. ilo = std::max(1, ilo);
  235. if (x >= Spline.x(ilo) || ilo == 1) break;
  236. istep *= 2;
  237. }
  238. } else if (x >= Spline.x(ihi)) { // increase ihi to capture
  239. int istep = 1;
  240. for (int ix=1; ix<nx; ++ix) {
  241. ilo = ihi;
  242. ihi = ilo + istep;
  243. ihi = std::min(ihi, nx);
  244. if (x <= Spline.x(ihi) || ihi == nx) break;
  245. istep *= 2;
  246. }
  247. }
  248. // Now Spline.x(ilo) <= x < Spline.x(ihi) --> Narrow the interval.
  249. //std::cout << "WIDE INTERVAL " << Spline.x(ilo) << "\t" << x << "\t" << Spline.x(ihi) << std::endl;
  250. for (int ix=1; ix<nx; ++ix) {
  251. int middle = (ilo+ihi) / 2;
  252. if (middle == ilo) break;
  253. if (x < Spline.x(middle)) {
  254. ihi = middle;
  255. } else {
  256. ilo = middle;
  257. }
  258. }
  259. assert ( Spline.x(ilo) < x && x < Spline.x(ihi) );
  260. return ilo;
  261. } // ----- end of method CubicSplineInterpolator::Inverval -----
  262. //--------------------------------------------------------------------------------------
  263. // Class: CubicSplineInterplator
  264. // Method: GetAbscissa
  265. //--------------------------------------------------------------------------------------
  266. VectorXr CubicSplineInterpolator::GetKnotAbscissa ( ) {
  267. return Spline.x;
  268. } // ----- end of method CubicSplineInterplator::get_GetAbscissa -----
  269. //--------------------------------------------------------------------------------------
  270. // Class: CubicSplineInterpolator
  271. // Method: GetKnotOrdinate
  272. //--------------------------------------------------------------------------------------
  273. VectorXr CubicSplineInterpolator::GetKnotOrdinate ( ) {
  274. return Spline.a;
  275. } // ----- end of method CubicSplineInterpolator::GetKnotOrdinate -----
  276. } // ----- end of Lemma name -----
  277. /* vim: set tabstop=4 expandtab: */
  278. /* vim: set filetype=cpp: */