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.

digitalfilterintegrator.h 18KB

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