Main Lemma Repository
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.

digitalfilterintegrator.h 18KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541
  1. /* This file is part of Lemma, a geophysical modelling and inversion API */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. /**
  6. @file
  7. @author Trevor Irons
  8. @date 02/07/2011
  9. @version $Id: digitalfilterintegrator.h 124 2014-02-07 04:26:26Z tirons $
  10. **/
  11. #ifndef DIGITALFILTERINTEGRATOR_INC
  12. #define DIGITALFILTERINTEGRATOR_INC
  13. #include "integrator.h"
  14. #include "integrationkernel.h"
  15. namespace Lemma {
  16. // ===================================================================
  17. // Class: DigitalFilterIntegrator
  18. /**
  19. \brief Reimplimentation of Walt Anderson's digital filtering
  20. algorithms which are public domain.
  21. \details Walt Anderson wrote several routines for digital filtering
  22. that reused a lot of code. The original fortran codes are
  23. available at:
  24. ftp://ftpext.usgs.gov/pub/cr/co/denver/musette/pub/anderson/
  25. This is an abstract class. Concrete classes must define the
  26. a function to make arguments.
  27. Template specilizations are found in the implimentation file
  28. digitalfilterintegrator.cpp. This was necessary to support
  29. the design paradigm of Lemma.
  30. */
  31. // ===================================================================
  32. template <typename Scalar>
  33. class DigitalFilterIntegrator : public Integrator {
  34. /** Prints out basic info about the class, Complex implimentation */
  35. template <typename Scalar2>
  36. friend std::ostream &operator<<(std::ostream &stream,
  37. const DigitalFilterIntegrator<Scalar2> &ob);
  38. public:
  39. // ==================== LIFECYCLE =======================
  40. // ==================== OPERATORS =======================
  41. // ==================== OPERATIONS =======================
  42. /** Sets the number of desired convolutions. From Anderson, where
  43. this value is called NB:
  44. NUMBER OF LAGGED CONVOLUTIONS DESIRED (NB.GE.1). USE
  45. NB=1 IF B=BMIN=BMAX (I.E.,NO LAGGING DESIRED). USE
  46. NB>1 IF B IS LAGGED IN (BMIN,BMAX), WHERE
  47. BMIN=BMAX*DEXP(-.1D0*(NB-1)) DOES NOT UNDERFLOW THE DEXP
  48. RANGE. THE B-LAGGED SPACING IS .1D0 IN LOG-SPACE. FOR
  49. CONVENIENCE IN SPLINE INTERPOLATION LATER, EACH B IN
  50. (BMIN,BMAX) IS RETURNED IN ARRAY ARG(I),I=1,NB, WHERE
  51. ARG(I+1)/ARG(I)=DEXP(.1D0) FOR ALL I. IF BMAX>BMIN>0 IS
  52. GIVEN, THEN AN EFFECTIVE VALUE OF NB IS DETERMINED AS
  53. NB=DINT(10.*DLOG(BMAX/BMIN))+I, WHERE I>1 IS RECOMMENDED,
  54. PARTICULARLY IF USING SUBSEQUENT SPLINE INTERPOLATION FOR
  55. A DIFFERENT B-SPACING THAN USED IN THE DIGITAL FILTER. IF
  56. SPLINE INTERPOLATION IS TO BE USED LATER, IT IS GENERALLY
  57. BEST TO USE DLOG(ARG(I)) INSTEAD OF ARG(I) -VS- DANS(I),
  58. FOR I=1,NB.
  59. */
  60. void SetNumConv(const int& i);
  61. /** Evaluates related integrals */
  62. void ComputeRelated(const Real& rho,
  63. IntegrationKernel<Scalar>* Kernel);
  64. /** Evaluates the integral
  65. @param[in]tol REQUESTED TRUNCATION TOLERANCE AT BOTH FILTER TAILS
  66. FOR ADAPTIVE CONVOLUTION FOR ALL NB TRANSFORMS. THE
  67. TRUNCATION CRITERION IS ESTABLISHED DURING CONVOLUTION IN
  68. A FIXED ABSCISSA RANGE (USING WEIGHTS 426-461) OF THE
  69. COSINE FILTER AS THE MAXIMUM ABSOLUTE CONVOLVED PRODUCT
  70. TIMES TOL. THE CONVOLUTION SUMMATION IS TERMINATED
  71. ON EITHER SIDE OF THE FIXED RANGE WHENEVER THE ABSOLUTE
  72. PRODUCT .LE. THE TRUNCATION CRITERION. IN GENERAL, A
  73. DECREASING TOLERANCE WILL PRODUCE HIGHER ACCURACY SINCE
  74. MORE FILTER WEIGHTS ARE USED (UNLESS EXPONENT UNDERFLOW
  75. OCCURS IN THE TRANSFORM INPUT FUNCTION EVALUATION).
  76. ONE MAY SET TOL=0.D0 TO OBTAIN MAXIMUM ACCURACY FOR ALL
  77. NB DOUBLE-PRECISION COSINE TRANSFORMS IN DANS(NB).
  78. HOWEVER, THE ACTUAL RELATIVE ERRORS CANNOT BE EXPECTED TO
  79. BE SMALLER THAN ABOUT .1D-12 REGARDLESS OF THE TOLERANCE
  80. VALUE USED, SINCE DOUBLE-PRECISION FILTER WEIGHTS AND A
  81. DOUBLE-PRECISION FUNCTION ARE USED. IN ANY EVENT,
  82. ONE SHOULD ALWAYS CHOOSE TOL<<DESIRED RELATIVE ERROR.
  83. ** ACCURACY WARNING ** SOME HIGHLY OSCILLATORY FUNCTIONS
  84. FUN(G) AND (OR) LIMITING CASES OF B NEAR MACHINE-ZERO
  85. (OR INFINITY) SHOULD BE AVOIDED, OTHERWISE UNSATISFACTORY
  86. RESULTS (E.G., RELATIVE & ABSOLUTE ERRORS>>TOL) MAY OCCUR.
  87. @param[in] ntol NUMBER OF CONSECUTIVE TIMES THE TRUNCATION CRITERION (TOL)
  88. IS TO BE MET AT EITHER FILTER TAIL BEFORE FILTER
  89. TRUNCATION OCCURS. NTOL=1 SHOULD BE USED FOR INPUT
  90. FUNCTIONS THAT DO NOT HAVE MANY ZEROS IN (0,INFINITY). FOR
  91. OSCILLATORY FUNCTIONS WITH MANY ZEROS, NTOL>1 MAY BE USED
  92. TO INSURE A PREMATURE CUTOFF DOES NOT OCCUR FOR TRUNCATION
  93. (SEE USE OF ITOL,NTOL,TOL IN THE CODE BELOW).
  94. @param[in] rho integration argument argument
  95. */
  96. void Compute(const Real& rho, const int& ntol, const Real& tol);
  97. /** Attaches the integration kernel */
  98. void AttachKernel(IntegrationKernel<Scalar> *Kernel);
  99. /** Detaches the integration kernel */
  100. void DetachKernel( );
  101. // ==================== ACCESS =======================
  102. /** Returns the Vector of Abscissa arguments
  103. */
  104. VectorXr GetAbscissaArguments();
  105. Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic > GetAnswer();
  106. /** Returns the number of evaluations of kernel */
  107. int GetNumFun();
  108. // ==================== INQUIRY =======================
  109. protected:
  110. // ==================== LIFECYCLE =======================
  111. /** Default protected constructor. */
  112. DigitalFilterIntegrator (const std::string& name);
  113. /** Default protected constructor. */
  114. ~DigitalFilterIntegrator ();
  115. // ==================== DATA MEMBERS =========================
  116. /** A rewrite of Anderson's Pseudo-subroutine. */
  117. void StoreRetreive(const int& idx, const int& lag, const Real& y,
  118. Scalar& Zsum, const int& jrel, Scalar& C);
  119. // ==================== OPERATIONS ==============================
  120. /** Sets the filter weights as prescribed by Anderson. This is called
  121. automatically when the SetBesselOrder(int ) is called. This is
  122. a protected function and cannot be called directly.
  123. */
  124. virtual void SetFilterWeights()=0;
  125. /** Computes the absolute maximum of the scalar */
  126. Scalar AbsMax(const Scalar& C, const Scalar& Cmax);
  127. // ==================== DATA MEMBERS ==============================
  128. /** The hankel transform wavenumber embedded in the integral */
  129. Real Lambda;
  130. /** Number of times kernel was evaluated */
  131. int NumFun;
  132. /** Number of lagged convolutions
  133. must be greater or equal to 1
  134. It is set automatically in the @see Compute function so
  135. that \f$ \rho \exp\left( -.1*(\mathtt{NumConv} -1) \right) \f$
  136. does not underflow the exponent range
  137. */
  138. int NumConv;
  139. /** Number of related kernels */
  140. int NumRel;
  141. /** Used as base for filter abscissa generation */
  142. Real ABSCISSA;
  143. /** Also used in abscissa generation \f$ ABSE = \exp{.1} \f$ */
  144. const Real ABSE;
  145. /** Also used in abscissa generation \f$ ABSER = 1 / \exp{.1} \f$ */
  146. const Real ABSER;
  147. /** Counter for calculated */
  148. int icount;
  149. /** Index of special case low side convolution filter weights */
  150. int ilow;
  151. /** Index of special case right side convolution filter weights */
  152. int ihi;
  153. /** Kernel Calculator */
  154. IntegrationKernel<Scalar> *IntKernel;
  155. /** Holds answer, dimensions are NumConv, and NumberRelated. */
  156. Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic> Ans;
  157. /** Filter weight coefficients.
  158. */
  159. VectorXr FilterWeights;
  160. /** Stored abscissa arguments
  161. */
  162. VectorXr Arg;
  163. /** Work from Anderson
  164. */
  165. Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic> Work;
  166. /// Key used internally
  167. Eigen::Matrix<int, Eigen::Dynamic, 1> Key;
  168. private:
  169. }; // ----- end of class DigitalFilterIntegrator -----
  170. /////////////////////////////////////////
  171. /////////////////////////////////////////
  172. // Templated implimentation //
  173. /////////////////////////////////////////
  174. /////////////////////////////////////////
  175. template <typename Scalar>
  176. std::ostream &operator<<(std::ostream &stream,
  177. const DigitalFilterIntegrator<Scalar> &ob) {
  178. stream << *(Integrator*)(&ob);
  179. return stream;
  180. }
  181. // ==================== LIFECYCLE =======================
  182. template <typename Scalar>
  183. DigitalFilterIntegrator<Scalar>::
  184. DigitalFilterIntegrator(const std::string& name) :
  185. Integrator(name), Lambda(0), NumFun(0), NumConv(0), NumRel(0),
  186. ABSCISSA(0),
  187. ABSE(1.10517091807564762), // exp(.1)
  188. ABSER(0.904837418035959573), // 1/exp(.1)
  189. ilow(0), ihi(0), IntKernel(NULL) {
  190. }
  191. template <typename Scalar>
  192. DigitalFilterIntegrator<Scalar>::~DigitalFilterIntegrator( ) {
  193. }
  194. template <typename Scalar>
  195. Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic >
  196. DigitalFilterIntegrator<Scalar>::GetAnswer() {
  197. return Ans;
  198. }
  199. // ==================== OPERATIONS =======================
  200. template <typename Scalar>
  201. void DigitalFilterIntegrator<Scalar>::SetNumConv(const int& i) {
  202. this->NumConv = i;
  203. }
  204. template <typename Scalar>
  205. void DigitalFilterIntegrator<Scalar>::
  206. AttachKernel(IntegrationKernel<Scalar> *ck) {
  207. if (this->IntKernel == ck) return;
  208. if (this->IntKernel != NULL) {
  209. this->IntKernel->DetachFrom(this);
  210. }
  211. ck->AttachTo(this);
  212. this->IntKernel = ck;
  213. }
  214. template <typename Scalar>
  215. void DigitalFilterIntegrator<Scalar>::DetachKernel( ) {
  216. if (this->IntKernel != NULL) {
  217. this->IntKernel->DetachFrom(this);
  218. }
  219. this->IntKernel = NULL;
  220. }
  221. // template < >
  222. // inline Complex DigitalFilterIntegrator<Complex>::AbsMax(const Complex& C,
  223. // const Complex& Cmax) {
  224. // return Complex(std::max(std::abs(real(C)), std::real(Cmax)),
  225. // std::max(std::abs(imag(C)), std::imag(Cmax)) );
  226. // }
  227. // template < >
  228. // Real DigitalFilterIntegrator<Real>::AbsMax(const Real& C,
  229. // const Real& Cmax) {
  230. // return std::max(C, Cmax);
  231. // }
  232. template <typename Scalar>
  233. VectorXr DigitalFilterIntegrator<Scalar>::GetAbscissaArguments() {
  234. return this->Arg;
  235. }
  236. // ///////////////////////////////////////////
  237. // // Computes the transform
  238. //
  239. // template < >
  240. // void DigitalFilterIntegrator<Real>::Compute(const Real& rho,
  241. // const int& ntol, const Real& tol) {
  242. //
  243. // Real y1 = this->ABSCISSA/rho;
  244. // this->Key.setZero();
  245. //
  246. // // Check to make sure everything is set
  247. // if (rho<=0) {
  248. // throw std::runtime_error("In DigitalFilterIntegrator Argument rho < 0.");
  249. // }
  250. //
  251. // if (this->NumConv<1) {
  252. // throw std::runtime_error("In DigitalFilterIntegrator NumConv is less than 1.");
  253. // }
  254. //
  255. // if (this->IntKernel == NULL) {
  256. // throw std::runtime_error("In DigitalFilterIntegrator Unset Kernel Calculator");
  257. // }
  258. //
  259. // Arg = VectorXr::Zero(this->NumConv);
  260. // Real y = std::pow(rho*ABSER, this->NumConv-1);
  261. //
  262. // if (y <= 0) {
  263. // std::cerr << "Exponent Underflow Error";
  264. // throw std::underflow_error("Exponent underflow");
  265. // }
  266. //
  267. // this->Work.resize(Eigen::NoChange, this->IntKernel->GetNumRel());
  268. //
  269. // // Main Loop
  270. // int itol = 0;
  271. // int none = 0;
  272. // this->NumFun = 0;
  273. // int idx = 0;
  274. // int istore = 0;
  275. // Real Sum(0.);
  276. // Real Cmax(0.);
  277. // Real C(0.);
  278. // Ans.resize(this->NumConv, this->IntKernel->GetNumRel());
  279. // Ans.setZero();
  280. // // 1010 Loop
  281. // for (int ilag=0; ilag < this->NumConv; ++ilag) {
  282. // istore = this->NumConv - 1 - ilag;
  283. // if (ilag > 0) y1 *= ABSE;
  284. // Arg(istore) = ABSCISSA/y1;
  285. //
  286. // // 1000 Loop
  287. // for (int irel=0; irel < this->IntKernel->GetNumRel(); ++irel) {
  288. // //this->SetBesselOrder(this->Ckernel->GetBesselOrder(irel));
  289. // none = 0;
  290. // itol = ntol;
  291. // Sum = Real(0);
  292. // Cmax = Real(0);
  293. // y = y1;
  294. // // Begin right side convolution at weight 298
  295. // // counting from 0
  296. // idx = ilow;
  297. // y *= ABSE;
  298. // // Code Block 20 in Anderson
  299. // do {
  300. // this->StoreRetreive(idx, ilag, y, Sum, irel, C);
  301. // Cmax = AbsMax(C, Cmax);
  302. // ++idx;
  303. // y *= ABSE;
  304. // } while (idx <= ihi);
  305. // //if (real(Cmax) == 0 && imag(Cmax) == 0) none = 1;
  306. // if (Cmax == Real(0)) none = 1;
  307. // Cmax *= tol;
  308. // // Code Block 30 in Anderson
  309. // do {
  310. // this->StoreRetreive(idx, ilag, y, Sum, irel, C);
  311. // if (std::abs(C) <= Cmax) {
  312. // --itol;
  313. // if (itol < 0 || idx > FilterWeights.size()-1) break;
  314. // } else {
  315. // itol = ntol;
  316. // }
  317. // ++idx;
  318. // y *= ABSE;
  319. // } while (idx < FilterWeights.size());
  320. // itol = ntol;
  321. // y = y1;
  322. // // Code Block 60 in Anderson
  323. // idx = ilow-1;
  324. // do {
  325. // this->StoreRetreive(idx, ilag, y, Sum, irel, C);
  326. // if (std::abs(C) <= Cmax && none == 0) {
  327. // --itol;
  328. // if (itol < 0 || idx < 0) break;
  329. // } else {
  330. // itol = ntol;
  331. // }
  332. // --idx;
  333. // y *= ABSER;
  334. // } while (idx>=0);
  335. // Ans(istore, irel) = Sum/Arg(istore);
  336. // } // End of 1000 loop
  337. // } // End of 1010 loop
  338. // }
  339. //
  340. //
  341. // template < >
  342. // void DigitalFilterIntegrator<Complex>::Compute(const Real &rho,
  343. // const int& ntol, const Real &tol) {
  344. //
  345. // Real y1 = this->ABSCISSA/rho;
  346. //
  347. // this->Key.setZero();
  348. //
  349. // // Check to make sure everything is set
  350. // if (rho<=0) {
  351. // throw std::runtime_error("In DigitalFilterIntegrator Argument rho < 0.");
  352. // }
  353. //
  354. // if (this->NumConv<1) {
  355. // throw std::runtime_error("In DigitalFilterIntegrator NumConv is less than 1.");
  356. // }
  357. //
  358. // if (this->IntKernel == NULL) {
  359. // throw std::runtime_error("In DigitalFilterIntegrator Unset Kernel Calculator");
  360. // }
  361. //
  362. // Arg = VectorXr::Zero(this->NumConv);
  363. // Real y = std::pow(rho*ABSER, this->NumConv-1);
  364. //
  365. // if (y <= 0) {
  366. // std::cerr << "Exponent Underflow Error";
  367. // throw std::underflow_error("Exponent underflow");
  368. // }
  369. //
  370. // this->Work.resize(Eigen::NoChange, this->IntKernel->GetNumRel());
  371. //
  372. // // Main Loop
  373. // int itol = 0;
  374. // int none = 0;
  375. // this->NumFun = 0;
  376. // int idx = 0;
  377. // int istore = 0;
  378. // Complex Zsum(0.);
  379. // Complex Cmax(0.);
  380. // Complex C(0.);
  381. // Ans.resize(this->NumConv, this->IntKernel->GetNumRel());
  382. // Ans.setZero();
  383. // // 1010 Loop
  384. // for (int ilag=0; ilag < this->NumConv; ++ilag) {
  385. // istore = this->NumConv - 1 - ilag;
  386. // if (ilag > 0) y1 *= ABSE;
  387. // Arg(istore) = ABSCISSA/y1;
  388. // // 1000 Loop
  389. // for (int irel=0; irel < this->IntKernel->GetNumRel(); ++irel) {
  390. // //this->SetBesselOrder(this->Ckernel->GetBesselOrder(irel));
  391. // none = 0;
  392. // itol = ntol;
  393. // Zsum = Complex(0);
  394. // Cmax = Complex(0);
  395. // y = y1;
  396. // // Begin right side convolution at weight 298
  397. // // counting from 0
  398. // idx = ilow;
  399. // y *= ABSE;
  400. // // Code Block 20 in Anderson
  401. // do {
  402. // this->StoreRetreive(idx, ilag, y, Zsum, irel, C);
  403. // Cmax = AbsMax(C, Cmax);
  404. // ++idx;
  405. // y *= ABSE;
  406. // } while (idx <= ihi);
  407. // //if (real(Cmax) == 0 && imag(Cmax) == 0) none = 1;
  408. // if (Cmax == Complex(0)) none = 1;
  409. // Cmax *= tol;
  410. // // Code Block 30 in Anderson
  411. // do {
  412. // this->StoreRetreive(idx, ilag, y, Zsum, irel, C);
  413. // if ( std::abs(real(C)) <= real(Cmax) &&
  414. // std::abs(imag(C)) <= imag(Cmax) ) {
  415. // --itol;
  416. // if (itol < 0 || idx > FilterWeights.size()-1) break;
  417. // } else {
  418. // itol = ntol;
  419. // }
  420. // ++idx;
  421. // y *= ABSE;
  422. // } while (idx < FilterWeights.size());
  423. // itol = ntol;
  424. // y = y1;
  425. // // Code Block 60 in Anderson
  426. // idx = ilow-1;
  427. // do {
  428. // this->StoreRetreive(idx, ilag, y, Zsum, irel, C);
  429. // if ( std::abs(real(C)) <= real(Cmax) &&
  430. // std::abs(imag(C)) <= imag(Cmax) &&
  431. // none == 0 ) {
  432. // --itol;
  433. // if (itol < 0 || idx < 0) break;
  434. // } else {
  435. // itol = ntol;
  436. // }
  437. // --idx;
  438. // y *= ABSER;
  439. // } while (idx>=0);
  440. // Ans(istore, irel) = Zsum/Arg(istore);
  441. // } // End of 1000 loop
  442. // } // End of 1010 loop
  443. // }
  444. template <typename Scalar>
  445. int DigitalFilterIntegrator<Scalar>::GetNumFun() {
  446. return NumFun;
  447. }
  448. // generic rewrite of store-retreive 'pseudo-subroutine'
  449. template <typename Scalar>
  450. void DigitalFilterIntegrator<Scalar>::StoreRetreive(const int &idx,
  451. const int& lag, const Real& y, Scalar& Sum,
  452. const int& jrel, Scalar& C) {
  453. int look = idx+lag;
  454. int iq = look/FilterWeights.size();
  455. int ir = look%FilterWeights.size();
  456. int iroll = iq*(FilterWeights.size()-1);
  457. if(this->Key(ir) <= iroll) {
  458. this->Key(ir) = iroll + ir;
  459. this->Lambda = y;
  460. ++this->NumFun;
  461. for (int ir2=0; ir2<IntKernel->GetNumRel(); ++ir2) {
  462. this->Work(ir, ir2) = this->IntKernel->Argument(this->Lambda, ir2);
  463. }
  464. }
  465. C = this->Work(ir, jrel) * this->FilterWeights(idx);
  466. Sum += C;
  467. return;
  468. }
  469. } // ----- end of Lemma name -----
  470. #endif // ----- #ifndef DIGITALFILTERINTEGRATOR_INC -----