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.

QWEKey.cpp 15KB

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