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.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  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 05/02/2018 09:46:38 PM
  11. * @author Trevor Irons (ti)
  12. * @email Trevor.Irons@utah.edu
  13. * @copyright Copyright (c) 2018, University of Utah
  14. * @copyright Copyright (c) 2018, Trevor Irons & Lemma Software, LLC
  15. */
  16. #ifndef FHT_INC
  17. #define FHT_INC
  18. #pragma once
  19. #include "HankelTransform.h"
  20. #include "CubicSplineInterpolator.h"
  21. namespace Lemma {
  22. /**
  23. \ingroup FDEM1D
  24. \brief Impliments lagged and related fast Hankel transform through
  25. digital filtering.
  26. \details A general Fast Hankel Transform routine which uses the digital
  27. filter apporach. Both lagged and related kernels are supported in
  28. order to minimize kernel function calls.
  29. This approach performs a complete sweep of the
  30. coefficients , for a variant that uses a longer filter which may
  31. be truncated, see FHTAnderson801.
  32. @see FHTAnderson801
  33. @see GQChave
  34. @see QWEKey
  35. */
  36. template < HANKELTRANSFORMTYPE Type >
  37. class FHT : public HankelTransform {
  38. friend std::ostream &operator<<(std::ostream &stream, const FHT<Type> &ob) {
  39. stream << ob.Serialize(); // << "\n";
  40. return stream;
  41. }
  42. public:
  43. // ==================== LIFECYCLE =======================
  44. /**
  45. * Default protected constructor, use NewSP methods to construct
  46. * @see FHT::NewSP
  47. */
  48. explicit FHT (const ctor_key& key ) : HankelTransform( key ) {
  49. }
  50. /**
  51. * Protected DeDerializing constructor, use factory DeSerialize method.
  52. * @see FHT::DeSerialize
  53. */
  54. FHT (const YAML::Node& node, const ctor_key& key) : HankelTransform(node, key) {
  55. }
  56. /** Default protected destructor, use smart pointers (std::shared_ptr) */
  57. ~FHT () {
  58. }
  59. /**
  60. * Factory method for generating concrete class.
  61. * @return a std::shared_ptr of type FHT
  62. */
  63. static std::shared_ptr< FHT > NewSP() {
  64. return std::make_shared< FHT >( ctor_key() );
  65. }
  66. /**
  67. * Uses YAML to serialize this object.
  68. * @return a YAML::Node
  69. * @see FHT::DeSerialize
  70. */
  71. YAML::Node Serialize() const {
  72. YAML::Node node = HankelTransform::Serialize();
  73. node.SetTag( this->GetName() ); // + enum2String(Type) );
  74. //node.SetTag( enum2String(Type) );
  75. //node["var"] = 0;
  76. return node;
  77. }
  78. /**
  79. * Constructs an FHT object from a YAML::Node.
  80. * @see FHT::Serialize
  81. */
  82. static std::shared_ptr<FHT> DeSerialize(const YAML::Node& node);
  83. // ==================== OPERATORS =======================
  84. // ==================== OPERATIONS =======================
  85. Complex Zgauss(const int&, const Lemma::EMMODE&, const int&, const Real&,
  86. const Real&, Lemma::KernelEM1DBase* Kernel) {
  87. // TODO, in 101 or 51 we never reach here!!
  88. std::cout << "Zgauss " << std::endl;
  89. return this->Zans(0, Kernel->GetManagerIndex());
  90. }
  91. /// Computes related kernels, if applicable, otherwise this is
  92. /// just a dummy function.
  93. void ComputeRelated(const Real& rho, std::shared_ptr<KernelEM1DBase> Kernel) {
  94. }
  95. void ComputeRelated(const Real& rho, std::vector< std::shared_ptr<KernelEM1DBase> > KernelVec) {
  96. }
  97. void ComputeRelated(const Real& rho, std::shared_ptr<KernelEM1DManager> KernelManager);
  98. void ComputeLaggedRelated(const Real& rho, const int& nlag, std::shared_ptr<KernelEM1DManager> KernelManager);
  99. // ==================== ACCESS =======================
  100. /**
  101. * @param[in] rho is the argument for lagged convolution evaluation from the
  102. * spline after calculation.
  103. */
  104. void SetLaggedArg(const Real& rho) {
  105. for (int i=0; i<Zans.cols(); ++ i) {
  106. Zans(0, i) = Complex( splineVecReal[i]->Interpolate(rho),
  107. splineVecImag[i]->Interpolate(rho) );
  108. }
  109. return ;
  110. }
  111. // ==================== INQUIRY =======================
  112. /**
  113. * @return filter asbscissa spacing
  114. */
  115. inline Real GetABSER();
  116. //{
  117. // return 0; //this->WT(0,0)/this->WT(1,0);
  118. //}
  119. /** Returns the name of the underlying class, similiar to Python's type */
  120. inline std::string GetName() const {
  121. return enum2String(Type); //this->CName;
  122. }
  123. protected:
  124. // ==================== LIFECYCLE =======================
  125. // ==================== DATA MEMBERS =========================
  126. private:
  127. // Filter Weights, these are specialized for each template type
  128. static const Eigen::Matrix<Real, Eigen::Dynamic, 3> WT;
  129. /// Spines for lagged convolutions (real part)
  130. std::vector <std::shared_ptr<CubicSplineInterpolator> > splineVecReal;
  131. /// Spines for lagged convolutions (imaginary part)
  132. std::vector < std::shared_ptr<CubicSplineInterpolator> > splineVecImag;
  133. /// Holds answer, dimensions are NumConv, and NumberRelated.
  134. Eigen::Matrix<Complex, Eigen::Dynamic, Eigen::Dynamic> Zans;
  135. /** ASCII string representation of the class name */
  136. //static constexpr auto CName = "FHT";
  137. }; // ----- end of class FHT ----
  138. // Specialisations
  139. // Note that ANDERSON801, CHAVE, QWEKEY will throw errors as they are not consistent
  140. // part of this class
  141. template < HANKELTRANSFORMTYPE Type >
  142. Real FHT< Type >::GetABSER() {
  143. return WT(0,0)/WT(1,0);
  144. }
  145. /* specializations could provide slighly better performance */
  146. // template < >
  147. // Real FHT< FHTKEY201 >::GetABSER() {
  148. // return WT(0,0)/WT(1,0);
  149. // }
  150. //
  151. // template < >
  152. // Real FHT< FHTKEY101 >::GetABSER() {
  153. // return WT(0,0)/WT(1,0);
  154. // }
  155. //
  156. // template < >
  157. // Real FHT< FHTKEY51 >::GetABSER() {
  158. // return WT(0,0)/WT(1,0);
  159. // }
  160. //--------------------------------------------------------------------------------------
  161. // Class: FHT
  162. // Method: ComputeRelated
  163. //--------------------------------------------------------------------------------------
  164. template < HANKELTRANSFORMTYPE Type >
  165. void FHT<Type>::ComputeRelated ( const Real& rho, std::shared_ptr<KernelEM1DManager> KernelManager ) {
  166. int nrel = (int)(KernelManager->GetSTLVector().size());
  167. Eigen::Matrix<Complex, Eigen::Dynamic, Eigen::Dynamic > Zwork;
  168. Zans= Eigen::Matrix<Complex, Eigen::Dynamic, Eigen::Dynamic>::Zero(1, nrel);
  169. Zwork.resize(WT.rows(), nrel);
  170. VectorXr lambda = WT.col(0).array()/rho;
  171. int NumFun = 0;
  172. int idx = 0;
  173. // Get Kernel values
  174. for (int ir=0; ir<lambda.size(); ++ir) {
  175. // irelated loop
  176. ++NumFun;
  177. KernelManager->ComputeReflectionCoeffs(lambda(ir), idx, rho);
  178. for (int ir2=0; ir2<nrel; ++ir2) {
  179. // Zwork* needed due to sign convention of filter weights
  180. Zwork(ir, ir2) = std::conj(KernelManager->GetSTLVector()[ir2]->RelBesselArg(lambda(ir)));
  181. }
  182. }
  183. for (int ir2=0; ir2<nrel; ++ir2) {
  184. Zans(0, ir2) = Zwork.col(ir2).dot(WT.col(KernelManager->GetSTLVector()[ir2]->GetBesselOrder() + 1))/rho;
  185. }
  186. return ;
  187. } // ----- end of method FHT::ComputeRelated -----
  188. //--------------------------------------------------------------------------------------
  189. // Class: FHT
  190. // Method: ComputeLaggedRelated
  191. //--------------------------------------------------------------------------------------
  192. template < HANKELTRANSFORMTYPE Type >
  193. void FHT<Type>::ComputeLaggedRelated ( const Real& rho, const int& nlag, std::shared_ptr<KernelEM1DManager> KernelManager ) {
  194. int nrel = (int)(KernelManager->GetSTLVector().size());
  195. Eigen::Matrix< Complex, Eigen::Dynamic, Eigen::Dynamic > Zwork;
  196. Zans= Eigen::Matrix<Complex, Eigen::Dynamic, Eigen::Dynamic>::Zero(nlag, nrel);
  197. Zwork.resize(WT.rows()+nlag, nrel); // Zwork needs to be expanded to filter length + nlag
  198. // lambda needs to be expanded to include lagged results
  199. VectorXr lambda = (VectorXr(WT.rows()+nlag) << WT.col(0).array()/rho, VectorXr::Zero(nlag)).finished();
  200. for (int ilam =WT.rows(); ilam< nlag+WT.rows(); ++ilam) {
  201. lambda(ilam) = lambda(ilam-1)/GetABSER();
  202. }
  203. int NumFun = 0;
  204. int idx = 0;
  205. VectorXr Arg(nlag);
  206. Arg(nlag-1) = rho;
  207. for (int ilag=nlag-2; ilag>=0; --ilag) {
  208. Arg(ilag) = Arg(ilag+1) * GetABSER();
  209. }
  210. // Get Kernel values
  211. for (int ir=0; ir<lambda.size(); ++ir) {
  212. // irelated loop
  213. ++NumFun;
  214. KernelManager->ComputeReflectionCoeffs(lambda(ir), idx, rho);
  215. for (int ir2=0; ir2<nrel; ++ir2) {
  216. Zwork(ir, ir2) = std::conj(KernelManager->GetSTLVector()[ir2]->RelBesselArg(lambda(ir)));
  217. }
  218. }
  219. // Inner product and scale
  220. int ilagr = nlag-1; // Zwork is in opposite order from Arg
  221. for (int ilag=0; ilag<nlag; ++ilag) {
  222. for (int ir2=0; ir2<nrel; ++ir2) {
  223. Zans(ilagr, ir2) = Zwork.col(ir2).segment(ilag,WT.rows()).dot( WT.col(KernelManager->GetSTLVector()[ir2]->GetBesselOrder()+1) ) / Arg(ilagr);
  224. }
  225. ilagr -= 1;
  226. }
  227. // make sure vectors are empty
  228. splineVecReal.clear();
  229. splineVecImag.clear();
  230. // Now do cubic spline
  231. for (int ii=0; ii<Zans.cols(); ++ii) {
  232. auto SplineR = CubicSplineInterpolator::NewSP();
  233. SplineR->SetKnots( Arg, Zans.col(ii).real() );
  234. splineVecReal.push_back(SplineR);
  235. auto SplineI = CubicSplineInterpolator::NewSP();
  236. SplineI->SetKnots( Arg, Zans.col(ii).imag() );
  237. splineVecImag.push_back(SplineI);
  238. }
  239. return ;
  240. } // ----- end of method FHT::ComputeLaggedRelated -----
  241. } // ----- end of namespace Lemma ----
  242. #endif // ----- #ifndef FHT_INC -----
  243. /* vim: set tabstop=4 expandtab: */
  244. /* vim: set filetype=cpp: */