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.

QWEKey.cpp 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  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. /* Original code is port of algorithm published by Key2011
  9. %------------------------------------------------------------------%
  10. % Copyright (c) 2012 by the Society of Exploration Geophysicists. %
  11. % For more information, go to http://software.seg.org/2012/0003 . %
  12. % You must read and accept usage terms at: %
  13. % http://software.seg.org/disclaimer.txt before use. %
  14. %------------------------------------------------------------------%
  15. */
  16. /**
  17. * @file
  18. * @date 02/12/2014 10:28:15 AM
  19. * @version $Id$
  20. * @author Trevor Irons (ti)
  21. * @email Trevor.Irons@xri-geo.com
  22. * @copyright Copyright (c) 2014, XRI Geophysics, LLC
  23. * @copyright Copyright (c) 2014, Trevor Irons
  24. */
  25. #include "QWEKey.h"
  26. //#include <Eigen/Eigenvalues>
  27. namespace Lemma {
  28. // ==================== FRIEND METHODS =====================
  29. std::ostream &operator<<(std::ostream &stream, const QWEKey &ob) {
  30. stream << *(HankelTransform*)(&ob);
  31. return stream;
  32. }
  33. // ==================== LIFECYCLE =======================
  34. //--------------------------------------------------------------------------------------
  35. // Class: QWEKey
  36. // Method: QWEKey
  37. // Description: constructor (protected)
  38. //--------------------------------------------------------------------------------------
  39. //
  40. QWEKey::QWEKey (const std::string& name) : HankelTransform(name), RelTol(1e-12), AbsTol(1e-32), nQuad(61), nDelay(1),
  41. //QWEKey::QWEKey (const std::string& name) : HankelTransform(name), RelTol(1e-38), AbsTol(1e-48), nQuad(39), nDelay(5),
  42. nIntervalsMax(40) {
  43. BesselWeights( J0 ); // TODO experiment with zero weight (J0, J1) options, should be static one time method
  44. } // ----- end of method QWEKey::QWEKey (constructor) -----
  45. //--------------------------------------------------------------------------------------
  46. // Class: QWEKey
  47. // Method: New()
  48. // Description: public constructor
  49. //--------------------------------------------------------------------------------------
  50. QWEKey* QWEKey::New() {
  51. QWEKey* Obj = new QWEKey("QWEKey");
  52. Obj->AttachTo(Obj);
  53. return Obj;
  54. }
  55. //--------------------------------------------------------------------------------------
  56. // Class: QWEKey
  57. // Method: ~QWEKey
  58. // Description: destructor (protected)
  59. //--------------------------------------------------------------------------------------
  60. QWEKey::~QWEKey () {
  61. } // ----- end of method QWEKey::~QWEKey (destructor) -----
  62. //--------------------------------------------------------------------------------------
  63. // Class: QWEKey
  64. // Method: Delete
  65. // Description: public destructor
  66. //--------------------------------------------------------------------------------------
  67. void QWEKey::Delete() {
  68. this->DetachFrom(this);
  69. }
  70. //--------------------------------------------------------------------------------------
  71. // Class: QWEKey
  72. // Method: Release
  73. // Description: destructor (protected)
  74. //--------------------------------------------------------------------------------------
  75. void QWEKey::Release() {
  76. delete this;
  77. }
  78. //--------------------------------------------------------------------------------------
  79. // Class: QWEKey
  80. // Method: Zgauss
  81. //--------------------------------------------------------------------------------------
  82. Complex QWEKey::Zgauss ( const int &ikk, const EMMODE &imode,
  83. const int &itype, const Real &rho,
  84. const Real &wavef, KernelEm1DBase *Kernel ) {
  85. return Textrap(Kernel->GetManagerIndex(), Tn(Kernel->GetManagerIndex())) ;
  86. } // ----- end of method QWEKey::Zgauss -----
  87. //--------------------------------------------------------------------------------------
  88. // Class: QWEKey
  89. // Method: ComputeRelated
  90. //--------------------------------------------------------------------------------------
  91. void QWEKey::ComputeRelated ( const Real& rho, KernelEm1DBase* Kernel ) {
  92. return ;
  93. } // ----- end of method QWEKey::ComputeRelated -----
  94. //--------------------------------------------------------------------------------------
  95. // Class: QWEKey
  96. // Method: ComputeRelated
  97. //--------------------------------------------------------------------------------------
  98. void QWEKey::ComputeRelated ( const Real& rho, std::vector< KernelEm1DBase* > KernelVec ) {
  99. return ;
  100. } // ----- end of method QWEKey::ComputeRelated -----
  101. //--------------------------------------------------------------------------------------
  102. // Class: QWEKey
  103. // Method: ComputeRelated
  104. //--------------------------------------------------------------------------------------
  105. void QWEKey::ComputeRelated ( const Real& rho, KernelEM1DManager* KernelManagerIn ) {
  106. KernelManager = KernelManagerIn; // OK becauase this is internal and we know what we are doing
  107. Lambda = Bx.array()/rho;
  108. Intervals = xInt.array()/rho;
  109. int nrel = (int)(KernelManager->GetSTLVector().size());
  110. Zans = Eigen::Matrix<Complex, Eigen::Dynamic, Eigen::Dynamic>::Zero(1, nrel);
  111. QWE(rho);
  112. return ;
  113. } // ----- end of method QWEKey::ComputeRelated -----
  114. //--------------------------------------------------------------------------------------
  115. // Class: QWEKey
  116. // Method: GaussQuadWeights
  117. //--------------------------------------------------------------------------------------
  118. void QWEKey::GaussQuadWeights(const int& N) {
  119. VectorXr Nv = VectorXr::LinSpaced(N-1, 1, N-1);
  120. VectorXr beta = 0.5 / (1.-(2.*Nv.array()).pow(-2)).sqrt();
  121. MatrixXr T = MatrixXr::Zero(N,N);
  122. //std::cerr << "Eigen ERROR BELOW, QWEKey.cpp QWEKey::GaussQuadWeights, COMMENTED OUT ";
  123. T.bottomLeftCorner(N-1, N-1) = beta.asDiagonal();
  124. Eigen::SelfAdjointEigenSolver<MatrixXr> eig( T.selfadjointView< Eigen::Lower >() );
  125. GaussAbscissa = eig.eigenvalues();
  126. GaussWeights = 2.*eig.eigenvectors().row(0).array().pow(2);
  127. }
  128. //--------------------------------------------------------------------------------------
  129. // Class: QWEKey
  130. // Method: BesselWeights
  131. //--------------------------------------------------------------------------------------
  132. void QWEKey::BesselWeights ( const sZeroType& sType ) {
  133. #ifdef HAVEBOOSTSPECIALFUNCTIONS
  134. GaussQuadWeights(nQuad); // TODO should this be moved out of initializer?
  135. std::vector<Real> bz;
  136. xInt = VectorXr(nIntervalsMax+1);
  137. xInt(0) = 1e-20;
  138. switch (sType) {
  139. case J0:
  140. boost::math::cyl_bessel_j_zero(0.0, 1, nIntervalsMax, std::back_inserter(bz));
  141. xInt.tail(nIntervalsMax) = VectorXr::Map(&bz[0], nIntervalsMax);
  142. break;
  143. case J1:
  144. boost::math::cyl_bessel_j_zero(1.0, 1, nIntervalsMax, std::back_inserter(bz));
  145. xInt.tail(nIntervalsMax) = VectorXr::Map(&bz[0], nIntervalsMax);
  146. break;
  147. case NPI:
  148. xInt << 1e-20, VectorXr::LinSpaced(nIntervalsMax, 1, nIntervalsMax).array() * PI;
  149. break;
  150. }
  151. VectorXr dx = ( xInt.tail(nIntervalsMax) - xInt.head(nIntervalsMax) ).array() / 2.;
  152. // x = GaussAbscissa
  153. // dx in every row GaussWeights+1 rows, cols = n
  154. // dx[0] dx[1] ... dx[N] Gw[0] Gw[0] ... ndX
  155. // dx[0] dx[1] ... dx[N] Gw[1]
  156. MatrixXr Bxm = (dx.transpose().replicate(GaussAbscissa.size(), 1)).eval().array() *
  157. ((GaussAbscissa.replicate(1, dx.size()).array() + 1.));
  158. Bxm.array() += xInt.head(Bxm.cols()).transpose().replicate( Bxm.rows(), 1 ).array();
  159. Bx = VectorXr::Map( &Bxm(0,0), Bxm.size() );
  160. BJ0 = VectorXr(Bx.size());
  161. BJ1 = VectorXr(Bx.size());
  162. int iw = 0;
  163. for (int ii=0; ii<Bx.size(); ++ii) {
  164. BJ0(ii) = boost::math::cyl_bessel_j(0, Bx(ii)) * GaussWeights(iw);
  165. BJ1(ii) = boost::math::cyl_bessel_j(1, Bx(ii)) * GaussWeights(iw);
  166. ++iw;
  167. if (iw == GaussWeights.size()) iw = 0;
  168. }
  169. return ;
  170. # else
  171. std::cerr << "QWEKey requires Boost functionalility that is missing\n";
  172. #endif
  173. } // ----- end of method QWEKey::BesselWeights -----
  174. //--------------------------------------------------------------------------------------
  175. // Class: QWEKey
  176. // Method: QWE
  177. //--------------------------------------------------------------------------------------
  178. void QWEKey::QWE ( const Real& rho ) {
  179. // TODO, is -1 needed here?
  180. int nTerms = nIntervalsMax - nDelay;// - 1;
  181. int nrel = (int)(KernelManager->GetSTLVector().size());
  182. // TODO GREMLINS LIVE IN HERE
  183. MatrixXcr prev = Eigen::Matrix<Complex, Eigen::Dynamic, Eigen::Dynamic>::Zero(1, nrel);
  184. for (int i=0; i<nDelay; ++i) {
  185. getEyKernel(i, 0, rho);
  186. prev += Zans;
  187. }
  188. // Some of these are complex
  189. TS = MatrixXcr::Zero(nrel, nTerms);
  190. Tn = VectorXi::Zero(nrel);
  191. Textrap = MatrixXcr::Zero(nrel, nTerms);
  192. TrelErr = MatrixXr::Zero(nrel, nTerms);
  193. TabsErr = MatrixXr::Zero(nrel, nTerms);
  194. VectorXi Converged = VectorXi::Zero(nrel);
  195. // is nTerms right, 1 array shifting
  196. for (int i=nDelay; i<nTerms; ++i) {
  197. int n = i-nDelay;
  198. getEyKernel(i, 0, rho);
  199. for (int j=0; j<nrel; ++j) {
  200. if (!Converged(j)) { //continue;
  201. Tn(j) = n; // order of the expansion
  202. TS(j,n+1) = TS(j, n) + Zans(0, j); // working array for transformation
  203. /* Compute the Shanks transform using the Epsilon algorithm:
  204. Structured after Weniger (1989, p26) */
  205. /* TI - some kind ob bug here, shanks extrapolation doesn't buy much for TEM at least */
  206. Complex aux2(0);
  207. for (int k=n+1; k>0; --k) {
  208. Complex aux1 = aux2;
  209. aux2 = TS(j,k-1);
  210. Complex ddff = TS(j,k) - aux2;
  211. if (std::abs(ddff) < std::numeric_limits<Real>::min() ) {
  212. TS(j,k-1) = std::numeric_limits<Real>::max() ;
  213. } else {
  214. TS(j,k-1) = aux1 + 1./ddff;
  215. }
  216. }
  217. // The extrapolated result plus the prev integration term:
  218. Textrap(j,n) = TS(j, (n-1)%2)+prev(0, j);
  219. //Textrap(j,n) = TS(j, n%2 + 1)+prev(0, j);
  220. // Step 3: Analyze for convergence:
  221. if (n > 1) {
  222. TabsErr(j,n) = std::abs( Textrap(j, n) - Textrap(j, n-1));
  223. TrelErr(j,n) = TabsErr(j, n) / std::abs(Textrap(j, n)) ;
  224. Converged(j) = TrelErr(j,n) < RelTol + AbsTol/std::abs(Textrap(j,n));
  225. }
  226. }
  227. }
  228. if ( Converged.all() == 1 ) break;
  229. }
  230. // Trim up results
  231. // Clean up the T structure arrays? We can't really do this
  232. // because they are fixed size, maybe see how they are used and
  233. // init to zero. If they are only summed we are OK.
  234. /*
  235. for (int j = 0; j<nrel; ++j) {:nKernels
  236. n = Tn(j);
  237. T(j).extrap = T(j).extrap(1:n);
  238. T(j).relErr = T(j).relErr(1:n);
  239. T(j).absErr = T(j).absErr(1:n);
  240. }
  241. */
  242. return ;
  243. } // ----- end of method QWEKey::QWE -----
  244. //--------------------------------------------------------------------------------------
  245. // Class: QWEKey
  246. // Method: getEyKernel
  247. //--------------------------------------------------------------------------------------
  248. void QWEKey::getEyKernel ( const int& i, const int& idx, const Real& rho ) {
  249. int bidx = i*nQuad;
  250. int nrel = (int)(KernelManager->GetSTLVector().size());
  251. Eigen::Matrix<Complex, Eigen::Dynamic, Eigen::Dynamic > Zwork =
  252. Eigen::Matrix<Complex, Eigen::Dynamic, Eigen::Dynamic>::Zero(nQuad, nrel);
  253. for (int ik=0; ik<nQuad; ++ik) {
  254. KernelManager->ComputeReflectionCoeffs( Lambda(bidx+ik), idx, rho );
  255. for (int ir2=0; ir2<nrel; ++ir2) {
  256. // Zwork* needed due to sign convention (e^-jwt) of FT in filter weights
  257. Zwork(ik, ir2) = std::conj(KernelManager->GetSTLVector()[ir2]->RelBesselArg(Lambda(bidx+ik)));
  258. }
  259. }
  260. Real bma = (Intervals(i+1)-Intervals(i))/2;
  261. for (int ir2=0; ir2<nrel; ++ir2) {
  262. if (KernelManager->GetSTLVector()[ir2]->GetBesselOrder() == 0) {
  263. Zans(0, ir2) = bma * Zwork.col(ir2).dot( BJ0.segment(bidx, nQuad) ); // / rho;
  264. } else {
  265. Zans(0, ir2) = bma * Zwork.col(ir2).dot( BJ1.segment(bidx, nQuad) ); // / rho;
  266. }
  267. }
  268. // fcount += nQuad
  269. return ;
  270. } // ----- end of method QWEKey::getEyKernel -----
  271. void QWEKey::TestPrivate(const int& N) {
  272. //GaussQuadWeights(N);
  273. //std::cout << "abscissa\n" << GaussAbscissa << std::endl;
  274. //std::cout << "weights\n" << GaussWeights << std::endl;
  275. BesselWeights( J1 );
  276. //BesselZeros(0, N);
  277. std::cout << std::scientific;
  278. std::cout << "BJ0" << BJ0 << std::endl;
  279. std::cout << "BJ1" << BJ1 << std::endl;
  280. //std::cout << "Bess Zero\n" << xInt << std::endl;
  281. }
  282. } // ----- end of Lemma name -----