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.

EMEarth1D.cpp 36KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888
  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 12/02/2009
  9. **/
  10. #include "EMEarth1D.h"
  11. #include "FieldPoints.h"
  12. #include "WireAntenna.h"
  13. #include "PolygonalWireAntenna.h"
  14. #ifdef LEMMAUSEOMP
  15. #include "omp.h"
  16. #endif
  17. namespace Lemma {
  18. std::ostream &operator << (std::ostream &stream, const EMEarth1D &ob) {
  19. stream << ob.Serialize() << "\n---\n"; // End of doc ---
  20. return stream;
  21. }
  22. #ifdef KIHALEE_EM1D
  23. // Wrapper function for Fortran subroutine Em1D bi kihand
  24. // Returns E or H fields (SLOW)
  25. extern "C" { void em1dcall_(int &itype, // source
  26. int &ipol, // source
  27. int &nlay, // Earth
  28. int &nfreq, // source
  29. int &nfield, // Calculator
  30. int &nres, // Receivers
  31. int &jtype, // N/A
  32. int &jgamma, // Controller
  33. double &acc, // Controller
  34. double *dep, // Earth
  35. std::complex<double> *sig, // Earth
  36. double *susl, // Earth
  37. double *sush, // Earth
  38. double *sustau, // Earth
  39. double *susalp, // Earth
  40. double *eprl, // Earth
  41. double *eprh, // Earth
  42. double *eprtau, // Earth
  43. double *epralp, // Earth
  44. double &finit, // N/A
  45. double &flimit, // N/A
  46. double &dlimit, // N/A
  47. double &lfinc, // N/A
  48. double &tx, // Source
  49. double &ty, // Source
  50. double &tz, // Source
  51. double *rxx, // Receivers
  52. double *rxy, // Receivers
  53. double *rxz, // Receivers
  54. std::complex<double> *ex, // Receivers
  55. std::complex<double> *ey, // |
  56. std::complex<double> *ez, // |
  57. std::complex<double> *hx, // |
  58. std::complex<double> *hy, // V
  59. std::complex<double> *hz ); // ___
  60. }
  61. #endif
  62. // ==================== LIFECYCLE ===================================
  63. // TODO init large arrays here.
  64. EMEarth1D::EMEarth1D( const ctor_key& ) : LemmaObject( ),
  65. Dipole(nullptr), Earth(nullptr), Receivers(nullptr), Antenna(nullptr),
  66. FieldsToCalculate(BOTH), HankelType(ANDERSON801), icalcinner(0), icalc(0)
  67. //#ifdef HAVEBOOSTPROGRESS
  68. // , disp(0)
  69. //#endif
  70. {
  71. }
  72. EMEarth1D::~EMEarth1D() {
  73. }
  74. std::shared_ptr<EMEarth1D> EMEarth1D::NewSP() {
  75. return std::make_shared<EMEarth1D>(ctor_key());
  76. }
  77. YAML::Node EMEarth1D::Serialize() const {
  78. YAML::Node node = LemmaObject::Serialize();
  79. node["FieldsToCalculate"] = enum2String(FieldsToCalculate);
  80. node["HankelType"] = enum2String(HankelType);
  81. //if (Dipole != nullptr) node["Dipole"] = Dipole->Serialize();
  82. if (Earth != nullptr) node["Earth"] = Earth->Serialize();
  83. //if (Receivers != nullptr) node["Receivers"] = Receivers->Serialize(); Can be huge?
  84. if (Antenna != nullptr) node["Antenna"] = Antenna->Serialize();
  85. node.SetTag( this->GetName() );
  86. return node;
  87. }
  88. // ==================== ACCESS ===================================
  89. void EMEarth1D::AttachDipoleSource( std::shared_ptr<DipoleSource> dipoleptr) {
  90. Dipole = dipoleptr;
  91. }
  92. void EMEarth1D::AttachLayeredEarthEM( std::shared_ptr<LayeredEarthEM> earthptr) {
  93. Earth = earthptr;
  94. }
  95. void EMEarth1D::AttachFieldPoints( std::shared_ptr<FieldPoints> recptr) {
  96. Receivers = recptr;
  97. if (Receivers == nullptr) {
  98. std::cout << "nullptr Receivers in emearth1d.cpp " << std::endl;
  99. return;
  100. }
  101. // This has an implicid need to first set a source before receivers, users
  102. // will not expect this. Fix
  103. if (Dipole != nullptr) {
  104. switch (FieldsToCalculate) {
  105. case E:
  106. Receivers->SetNumberOfBinsE(Dipole->GetNumberOfFrequencies());
  107. break;
  108. case H:
  109. Receivers->SetNumberOfBinsH(Dipole->GetNumberOfFrequencies());
  110. break;
  111. case BOTH:
  112. Receivers->SetNumberOfBinsE(Dipole->GetNumberOfFrequencies());
  113. Receivers->SetNumberOfBinsH(Dipole->GetNumberOfFrequencies());
  114. break;
  115. }
  116. } else if (Antenna != nullptr) {
  117. switch (FieldsToCalculate) {
  118. case E:
  119. Receivers->SetNumberOfBinsE(Antenna->GetNumberOfFrequencies());
  120. break;
  121. case H:
  122. Receivers->SetNumberOfBinsH(Antenna->GetNumberOfFrequencies());
  123. break;
  124. case BOTH:
  125. Receivers->SetNumberOfBinsE(Antenna->GetNumberOfFrequencies());
  126. Receivers->SetNumberOfBinsH(Antenna->GetNumberOfFrequencies());
  127. break;
  128. }
  129. }
  130. }
  131. void EMEarth1D::AttachWireAntenna(std::shared_ptr<WireAntenna> antennae) {
  132. this->Antenna = antennae;
  133. }
  134. void EMEarth1D::SetFieldsToCalculate(const FIELDCALCULATIONS &calc) {
  135. FieldsToCalculate = calc;
  136. }
  137. void EMEarth1D::SetHankelTransformMethod( const HANKELTRANSFORMTYPE &type) {
  138. HankelType = type;
  139. }
  140. void EMEarth1D::Query() {
  141. std::cout << "EmEarth1D::Query()" << std::endl;
  142. std::cout << "Dipole " << Dipole;
  143. if (Dipole) std::cout << *Dipole << std::endl;
  144. std::cout << "Earth " << Earth;
  145. if (Earth) std::cout << *Earth << std::endl;
  146. std::cout << "Receivers " << Earth;
  147. if (Earth) std::cout << *Receivers << std::endl;
  148. std::cout << "Antenna " << Earth;
  149. if (Antenna) std::cout << *Antenna << std::endl;
  150. std::cout << "icalc " << icalc << std::endl;
  151. std::cout << "icalcinner " << icalcinner << std::endl;
  152. }
  153. // ==================== OPERATIONS ===================================
  154. void EMEarth1D::CalculateWireAntennaFields(bool progressbar) {
  155. #ifdef HAVEBOOSTPROGRESS
  156. boost::progress_display *disp;
  157. #endif
  158. if (Earth == nullptr) {
  159. throw NullEarth();
  160. }
  161. if (Receivers == nullptr) {
  162. throw NullReceivers();
  163. }
  164. if (Antenna == nullptr) {
  165. throw NullAntenna();
  166. }
  167. if (Dipole != nullptr) {
  168. throw DipoleSourceSpecifiedForWireAntennaCalc();
  169. }
  170. Receivers->ClearFields();
  171. // Check to make sure Receivers are set up for all calculations
  172. switch(FieldsToCalculate) {
  173. case E:
  174. if (Receivers->NumberOfBinsE != Antenna->GetNumberOfFrequencies())
  175. Receivers->SetNumberOfBinsE(Antenna->GetNumberOfFrequencies());
  176. break;
  177. case H:
  178. if (Receivers->NumberOfBinsH != Antenna->GetNumberOfFrequencies())
  179. Receivers->SetNumberOfBinsH(Antenna->GetNumberOfFrequencies());
  180. break;
  181. case BOTH:
  182. if (Receivers->NumberOfBinsH != Antenna->GetNumberOfFrequencies())
  183. Receivers->SetNumberOfBinsH(Antenna->GetNumberOfFrequencies());
  184. if (Receivers->NumberOfBinsE != Antenna->GetNumberOfFrequencies())
  185. Receivers->SetNumberOfBinsE(Antenna->GetNumberOfFrequencies());
  186. break;
  187. }
  188. if (Antenna->GetName() == std::string("PolygonalWireAntenna") || Antenna->GetName() == std::string("TEMTransmitter") ) {
  189. icalc += 1;
  190. // Check to see if they are all on a plane? If so we can do this fast
  191. /* TODO FIX THIS ISSUES */
  192. if (Antenna->IsHorizontallyPlanar() && HankelType == ANDERSON801) {
  193. //std::cout << "Lag baby lag" << std::endl;
  194. for (int ifreq=0; ifreq<Antenna->GetNumberOfFrequencies();++ifreq) {
  195. //std::cout << "Num Recs" << Receivers->GetNumberOfPoints() << std::endl;
  196. Real wavef = 2.*PI* Antenna->GetFrequency(ifreq);
  197. #ifdef LEMMAUSEOMP
  198. #pragma omp parallel
  199. {
  200. #endif
  201. auto Hankel = FHTAnderson801::NewSP();
  202. #ifdef LEMMAUSEOMP
  203. #pragma omp for schedule(static, 1)
  204. #endif
  205. for (int irec=0; irec<Receivers->GetNumberOfPoints(); ++irec) {
  206. //for (int irec=0; irec<2; ++irec) { // TODO FIXME BELO
  207. auto AntCopy = static_cast<PolygonalWireAntenna*>(Antenna.get())->ClonePA();
  208. SolveLaggedTxRxPair(irec, Hankel.get(), wavef, ifreq, AntCopy.get());
  209. //exit(0);
  210. }
  211. //Receivers->ClearFields(); // FIXME DEBUG TODO
  212. #ifdef LEMMAUSEOMP
  213. }
  214. #endif
  215. }
  216. } else
  217. if (Receivers->GetNumberOfPoints() > Antenna->GetNumberOfFrequencies()) {
  218. //std::cout << "freq parallel #1" << std::endl;
  219. //** Progress display bar for long calculations */
  220. #ifdef HAVEBOOSTPROGRESS
  221. if (progressbar) {
  222. disp = new boost::progress_display( Receivers->GetNumberOfPoints()*Antenna->GetNumberOfFrequencies() );
  223. }
  224. #endif
  225. // parallelise across receivers
  226. #ifdef LEMMAUSEOMP
  227. #pragma omp parallel
  228. #endif
  229. { // OpenMP Parallel Block
  230. // Since these antennas change we need a local copy for each
  231. // thread.
  232. auto AntCopy = static_cast<PolygonalWireAntenna*>(Antenna.get())->ClonePA();
  233. std::shared_ptr<HankelTransform> Hankel;
  234. switch (HankelType) {
  235. case ANDERSON801:
  236. Hankel = FHTAnderson801::NewSP();
  237. break;
  238. case CHAVE:
  239. Hankel = GQChave::NewSP();
  240. break;
  241. case FHTKEY201:
  242. Hankel = FHTKey201::NewSP();
  243. break;
  244. case FHTKEY101:
  245. Hankel = FHTKey101::NewSP();
  246. break;
  247. case FHTKEY51:
  248. Hankel = FHTKey51::NewSP();
  249. break;
  250. case QWEKEY:
  251. Hankel = QWEKey::NewSP();
  252. break;
  253. default:
  254. std::cerr << "Hankel transform cannot be created\n";
  255. exit(EXIT_FAILURE);
  256. }
  257. //for (int irec=tid; irec<Receivers->GetNumberOfPoints(); irec+=nthreads) {
  258. #ifdef LEMMAUSEOMP
  259. #pragma omp for schedule(static, 1) //nowait
  260. #endif
  261. for (int irec=0; irec<Receivers->GetNumberOfPoints(); ++irec) {
  262. if (!Receivers->GetMask(irec)) {
  263. AntCopy->ApproximateWithElectricDipoles(Receivers->GetLocation(irec));
  264. for (int idip=0; idip<AntCopy->GetNumberOfDipoles(); ++idip) {
  265. auto tDipole = AntCopy->GetDipoleSource(idip);
  266. //#ifdef LEMMAUSEOMP
  267. //#pragma omp for schedule(static, 1)
  268. //#endif
  269. for (int ifreq=0; ifreq<tDipole->GetNumberOfFrequencies();
  270. ++ifreq) {
  271. // Propogation constant in free space
  272. Real wavef = tDipole->GetAngularFrequency(ifreq) *
  273. std::sqrt(MU0*EPSILON0);
  274. SolveSingleTxRxPair(irec, Hankel.get(), wavef, ifreq, tDipole.get());
  275. } // freq loop
  276. } // dipole loop
  277. } // mask
  278. //std::cout << "Normal Path\n";
  279. //std::cout << Receivers->GetHfield(0, irec) << std::endl;
  280. //if (irec == 1) exit(0);
  281. #ifdef HAVEBOOSTPROGRESS
  282. if (progressbar) ++(*disp);
  283. #endif
  284. } // receiver loop
  285. } // OMP_PARALLEL BLOCK
  286. } else if (Antenna->GetNumberOfFrequencies() > 8) {
  287. // parallel across frequencies
  288. //std::cout << "freq parallel #2" << std::endl;
  289. for (int irec=0; irec<Receivers->GetNumberOfPoints(); ++irec) {
  290. if (!Receivers->GetMask(irec)) {
  291. static_cast<PolygonalWireAntenna*>(Antenna.get())->ApproximateWithElectricDipoles(Receivers->GetLocation(irec));
  292. #ifdef LEMMAUSEOMP
  293. #pragma omp parallel
  294. #endif
  295. { // OpenMP Parallel Block
  296. std::shared_ptr<HankelTransform> Hankel;
  297. switch (HankelType) {
  298. case ANDERSON801:
  299. Hankel = FHTAnderson801::NewSP();
  300. break;
  301. case CHAVE:
  302. Hankel = GQChave::NewSP();
  303. break;
  304. case FHTKEY201:
  305. Hankel = FHTKey201::NewSP();
  306. break;
  307. case FHTKEY101:
  308. Hankel = FHTKey101::NewSP();
  309. break;
  310. case FHTKEY51:
  311. Hankel = FHTKey51::NewSP();
  312. break;
  313. case QWEKEY:
  314. Hankel = QWEKey::NewSP();
  315. break;
  316. default:
  317. std::cerr << "Hankel transform cannot be created\n";
  318. exit(EXIT_FAILURE);
  319. }
  320. #ifdef LEMMAUSEOMP
  321. #pragma omp for schedule(static, 1)
  322. #endif
  323. for (int ifreq=0; ifreq<Antenna->GetNumberOfFrequencies(); ++ifreq) {
  324. for (int idip=0; idip<Antenna->GetNumberOfDipoles(); ++idip) {
  325. auto tDipole = Antenna->GetDipoleSource(idip);
  326. // Propogation constant in free space
  327. Real wavef = tDipole->GetAngularFrequency(ifreq) *
  328. std::sqrt(MU0*EPSILON0);
  329. SolveSingleTxRxPair(irec, Hankel.get(), wavef, ifreq, tDipole.get());
  330. } // dipole loop
  331. } // frequency loop
  332. } // OMP_PARALLEL BLOCK
  333. } // mask loop
  334. #ifdef HAVEBOOSTPROGRESS
  335. //if (Receivers->GetNumberOfPoints() > 100) {
  336. // ++ disp;
  337. //}
  338. #endif
  339. } // receiver loop
  340. //std::cout << "End freq parallel " << std::endl;
  341. } // Frequency Parallel
  342. else {
  343. //std::cout << "parallel across #3 " << std::endl;
  344. for (int irec=0; irec<Receivers->GetNumberOfPoints(); ++irec) {
  345. if (!Receivers->GetMask(irec)) {
  346. static_cast<PolygonalWireAntenna*>(Antenna.get())->ApproximateWithElectricDipoles(Receivers->GetLocation(irec));
  347. // std::cout << "Not Masked " << std::endl;
  348. // std::cout << "n Freqs " << Antenna->GetNumberOfFrequencies() << std::endl;
  349. // std::cout << "n Dipoles " << Antenna->GetNumberOfDipoles() << std::endl;
  350. // if ( !Antenna->GetNumberOfDipoles() ) {
  351. // std::cout << "NO DIPOLES!!!!!!!!!!!!!!!!!!!!!!!!!!\n";
  352. // // std::cout << "rec location " << Receivers->GetLocation(irec) << std::endl;
  353. // // }
  354. #ifdef LEMMAUSEOMP
  355. #pragma omp parallel
  356. #endif
  357. { // OpenMP Parallel Block
  358. std::shared_ptr<HankelTransform> Hankel;
  359. switch (HankelType) {
  360. case ANDERSON801:
  361. Hankel = FHTAnderson801::NewSP();
  362. break;
  363. case CHAVE:
  364. Hankel = GQChave::NewSP();
  365. break;
  366. case FHTKEY201:
  367. Hankel = FHTKey201::NewSP();
  368. break;
  369. case FHTKEY101:
  370. Hankel = FHTKey101::NewSP();
  371. break;
  372. case FHTKEY51:
  373. Hankel = FHTKey51::NewSP();
  374. break;
  375. case QWEKEY:
  376. Hankel = QWEKey::NewSP();
  377. break;
  378. default:
  379. std::cerr << "Hankel transform cannot be created\n";
  380. exit(EXIT_FAILURE);
  381. }
  382. for (int ifreq=0; ifreq<Antenna->GetNumberOfFrequencies(); ++ifreq) {
  383. #ifdef LEMMAUSEOMP
  384. #pragma omp for schedule(static, 1)
  385. #endif
  386. for (int idip=0; idip<Antenna->GetNumberOfDipoles(); ++idip) {
  387. //#pragma omp critical
  388. //{
  389. //cout << "idip=" << idip << "\tthread num=" << omp_get_thread_num() << '\n';
  390. //}
  391. auto tDipole = Antenna->GetDipoleSource(idip);
  392. // Propogation constant in free space
  393. Real wavef = tDipole->GetAngularFrequency(ifreq) *
  394. std::sqrt(MU0*EPSILON0);
  395. SolveSingleTxRxPair(irec, Hankel.get(), wavef, ifreq, tDipole.get());
  396. } // dipole loop
  397. } // frequency loop
  398. } // OMP_PARALLEL BLOCK
  399. } // mask loop
  400. #ifdef HAVEBOOSTPROGRESS
  401. //if (Receivers->GetNumberOfPoints() > 100) {
  402. // ++ disp;
  403. //}
  404. #endif
  405. } // receiver loop
  406. } // Polygonal parallel logic
  407. } else {
  408. std::cerr << "Lemma with WireAntenna class is currently broken"
  409. << " fix or use PolygonalWireAntenna\n" << std::endl;
  410. exit(EXIT_FAILURE);
  411. // TODO, getting wrong answer, curiously worKernel->GetKs() with MakeCalc, maybe
  412. // a threading issue, use SolveSingleTxRxPair maype instead of call
  413. // to MakeCalc3? !!!
  414. for (int idip=0; idip<Antenna->GetNumberOfDipoles(); ++idip) {
  415. this->Dipole = Antenna->GetDipoleSource(idip);
  416. MakeCalc3();
  417. //++disp;
  418. }
  419. this->Dipole = nullptr;
  420. }
  421. #ifdef HAVEBOOSTPROGRESS
  422. if (progressbar) {
  423. delete disp;
  424. }
  425. #endif
  426. }
  427. #ifdef KIHALEE_EM1D
  428. void EMEarth1D::MakeCalc() {
  429. int itype; // 1 = elec, 2 = mag
  430. switch (this->Dipole->GetDipoleSourceType()) {
  431. case (GROUNDEDELECTRICDIPOLE) :
  432. itype = 1;
  433. break;
  434. case (MAGNETICDIPOLE) :
  435. itype = 2;
  436. break;
  437. case (UNGROUNDEDELECTRICDIPOLE) :
  438. std::cerr << "Fortran routine cannot calculate ungrounded"
  439. "electric dipole\n";
  440. default:
  441. throw NonValidDipoleType();
  442. }
  443. int ipol ;
  444. Vector3r Pol = this->Dipole->GetPolarisation();
  445. if (std::abs(Pol[0]-1) < 1e-5) {
  446. ipol = 1;
  447. } else if (std::abs(Pol[1]-1) < 1e-5) {
  448. ipol = 2;
  449. } else if (std::abs(Pol[2]-1) < 1e-5) {
  450. ipol = 3;
  451. } else {
  452. std::cerr << "Fortran routine cannot calculate arbitrary "
  453. "dipole polarisation, set to x, y, or z\n";
  454. }
  455. int nlay = Earth->GetNumberOfNonAirLayers();
  456. if (nlay > MAXLAYERS) {
  457. std::cerr << "FORTRAN CODE CAN ONLY HANDLE " << MAXLAYERS
  458. << " LAYERS\n";
  459. throw EarthModelWithMoreThanMaxLayers();
  460. }
  461. int nfreq = 1; // number of freqs
  462. int nfield; // field output 1 = elec, 2 = mag, 3 = both
  463. switch (FieldsToCalculate) {
  464. case E:
  465. nfield = 1;
  466. break;
  467. case H:
  468. nfield = 2;
  469. break;
  470. case BOTH:
  471. nfield = 3;
  472. break;
  473. default:
  474. throw 7;
  475. }
  476. int nres = Receivers->GetNumberOfPoints();
  477. int jtype = 3; // form ouf output,
  478. // 1 = horizontal,
  479. // 2 = down hole,
  480. // 3 = freq sounding
  481. // 4 = down hole logging
  482. int jgamma = 0; // Units 0 = MKS (H->A/m and E->V/m)
  483. // 1 = h->Gammas E->V/m
  484. double acc = 0.; // Tolerance
  485. // TODO, fix FORTRAN calls so these arrays can be nlay long, not
  486. // MAXLAYERS.
  487. // Model Parameters
  488. double *dep = new double[MAXLAYERS];
  489. dep[0] = 0.; // We always say air starts at 0
  490. for (int ilay=1; ilay<Earth->GetNumberOfLayers(); ++ilay) {
  491. dep[ilay] = dep[ilay-1] + Earth->GetLayerThickness(ilay);
  492. //std::cout << "Depth " << dep[ilay] << std::endl;
  493. }
  494. std::complex<double> *sig = new std::complex<double> [MAXLAYERS];
  495. for (int ilay=1; ilay<=nlay; ++ilay) {
  496. sig[ilay-1] = (std::complex<double>)(Earth->GetLayerConductivity(ilay));
  497. }
  498. // TODO, pass these into Fortran call, and return Cole-Cole model
  499. // parameters. Right now this does nothing
  500. //std::complex<double> *sus = new std::complex<double>[MAXLAYERS];
  501. //std::complex<double> *epr = new std::complex<double>[MAXLAYERS];
  502. // Cole-Cole model stuff
  503. double *susl = new double[MAXLAYERS];
  504. for (int ilay=1; ilay<=nlay; ++ilay) {
  505. susl[ilay-1] = Earth->GetLayerLowFreqSusceptibility(ilay);
  506. }
  507. double *sush = new double[MAXLAYERS];
  508. for (int ilay=1; ilay<=nlay; ++ilay) {
  509. sush[ilay-1] = Earth->GetLayerHighFreqSusceptibility(ilay);
  510. }
  511. double *sustau = new double[MAXLAYERS];
  512. for (int ilay=1; ilay<=nlay; ++ilay) {
  513. sustau[ilay-1] = Earth->GetLayerTauSusceptibility(ilay);
  514. }
  515. double *susalp = new double[MAXLAYERS];
  516. for (int ilay=1; ilay<=nlay; ++ilay) {
  517. susalp[ilay-1] = Earth->GetLayerBreathSusceptibility(ilay);
  518. }
  519. double *eprl = new double[MAXLAYERS];
  520. for (int ilay=1; ilay<=nlay; ++ilay) {
  521. eprl[ilay-1] = Earth->GetLayerLowFreqPermitivity(ilay);
  522. }
  523. double *eprh = new double[MAXLAYERS];
  524. for (int ilay=1; ilay<=nlay; ++ilay) {
  525. eprh[ilay-1] = Earth->GetLayerHighFreqPermitivity(ilay);
  526. }
  527. double *eprtau = new double[MAXLAYERS];
  528. for (int ilay=1; ilay<=nlay; ++ilay) {
  529. eprtau[ilay-1] = Earth->GetLayerTauPermitivity(ilay);
  530. }
  531. double *epralp = new double[MAXLAYERS];
  532. for (int ilay=1; ilay<=nlay; ++ilay) {
  533. epralp[ilay-1] = Earth->GetLayerBreathPermitivity(ilay);
  534. }
  535. // Freq stuff
  536. double finit = Dipole->GetFrequency(0); //(1000); // Starting freq
  537. double flimit = Dipole->GetFrequency(0); //(1000); // max freq
  538. double dlimit = Dipole->GetFrequency(0); //(1000); // difusion limit
  539. double lfinc(1); // no. freq per decade
  540. // tx location jtype != 4
  541. double txx = Dipole->GetLocation(0); // (0.);
  542. double txy = Dipole->GetLocation(1); // (0.);
  543. double txz = Dipole->GetLocation(2); // (0.);
  544. // rx position
  545. // TODO, fix Fortran program to not waste this memory
  546. // maybe
  547. const int MAXREC = 15;
  548. double *rxx = new double [MAXREC];
  549. double *rxy = new double [MAXREC];
  550. double *rxz = new double [MAXREC];
  551. std::complex<double> *ex = new std::complex<double>[MAXREC];
  552. std::complex<double> *ey = new std::complex<double>[MAXREC];
  553. std::complex<double> *ez = new std::complex<double>[MAXREC];
  554. std::complex<double> *hx = new std::complex<double>[MAXREC];
  555. std::complex<double> *hy = new std::complex<double>[MAXREC];
  556. std::complex<double> *hz = new std::complex<double>[MAXREC];
  557. int nres2 = MAXREC;
  558. int ii=0;
  559. for (ii=0; ii<nres-MAXREC; ii+=MAXREC) {
  560. for (int ir=0; ir<MAXREC; ++ir) {
  561. //Vector3r pos = Receivers->GetLocation(ii+ir);
  562. rxx[ir] = Receivers->GetLocation(ii+ir)[0];
  563. rxy[ir] = Receivers->GetLocation(ii+ir)[1];
  564. rxz[ir] = Receivers->GetLocation(ii+ir)[2];
  565. }
  566. em1dcall_(itype, ipol, nlay, nfreq, nfield, nres2, jtype,
  567. jgamma, acc, dep, sig, susl, sush, sustau, susalp,
  568. eprl, eprh, eprtau, epralp, finit, flimit, dlimit,
  569. lfinc, txx, txy, txz, rxx, rxy, rxz, ex, ey, ez,
  570. hx, hy, hz);
  571. // Scale By Moment
  572. for (int ir=0; ir<MAXREC; ++ir) {
  573. ex[ir] *= Dipole->GetMoment();
  574. ey[ir] *= Dipole->GetMoment();
  575. ez[ir] *= Dipole->GetMoment();
  576. hx[ir] *= Dipole->GetMoment();
  577. hy[ir] *= Dipole->GetMoment();
  578. hz[ir] *= Dipole->GetMoment();
  579. // Append values instead of setting them
  580. this->Receivers->AppendEfield(0, ii+ir, (Complex)(ex[ir]),
  581. (Complex)(ey[ir]),
  582. (Complex)(ez[ir]) );
  583. this->Receivers->AppendHfield(0, ii+ir, (Complex)(hx[ir]),
  584. (Complex)(hy[ir]),
  585. (Complex)(hz[ir]) );
  586. }
  587. }
  588. //ii += MAXREC;
  589. nres2 = 0;
  590. // Perform last positions
  591. for (int ir=0; ir<nres-ii; ++ir) {
  592. rxx[ir] = Receivers->GetLocation(ii+ir)[0];
  593. rxy[ir] = Receivers->GetLocation(ii+ir)[1];
  594. rxz[ir] = Receivers->GetLocation(ii+ir)[2];
  595. ++nres2;
  596. }
  597. em1dcall_(itype, ipol, nlay, nfreq, nfield, nres2, jtype,
  598. jgamma, acc, dep, sig, susl, sush, sustau, susalp,
  599. eprl, eprh, eprtau, epralp, finit, flimit, dlimit,
  600. lfinc, txx, txy, txz, rxx, rxy, rxz, ex, ey, ez,
  601. hx, hy, hz);
  602. // Scale By Moment
  603. for (int ir=0; ir<nres-ii; ++ir) {
  604. ex[ir] *= Dipole->GetMoment();
  605. ey[ir] *= Dipole->GetMoment();
  606. ez[ir] *= Dipole->GetMoment();
  607. hx[ir] *= Dipole->GetMoment();
  608. hy[ir] *= Dipole->GetMoment();
  609. hz[ir] *= Dipole->GetMoment();
  610. // Append values instead of setting them
  611. this->Receivers->AppendEfield(0, ii+ir, (Complex)(ex[ir]),
  612. (Complex)(ey[ir]),
  613. (Complex)(ez[ir]) );
  614. this->Receivers->AppendHfield(0, ii+ir, (Complex)(hx[ir]),
  615. (Complex)(hy[ir]),
  616. (Complex)(hz[ir]) );
  617. }
  618. delete [] sig;
  619. delete [] dep;
  620. //delete [] sus;
  621. //delete [] epr;
  622. delete [] susl;
  623. delete [] sush;
  624. delete [] susalp;
  625. delete [] sustau;
  626. delete [] eprl;
  627. delete [] eprh;
  628. delete [] epralp;
  629. delete [] eprtau;
  630. delete [] rxx;
  631. delete [] rxy;
  632. delete [] rxz;
  633. delete [] ex;
  634. delete [] ey;
  635. delete [] ez;
  636. delete [] hx;
  637. delete [] hy;
  638. delete [] hz;
  639. }
  640. #endif
  641. void EMEarth1D::SolveSingleTxRxPair (const int &irec, HankelTransform *Hankel, const Real &wavef, const int &ifreq,
  642. DipoleSource *tDipole) {
  643. ++icalcinner;
  644. Real rho = (Receivers->GetLocation(irec).head<2>() - tDipole->GetLocation().head<2>()).norm();
  645. tDipole->SetKernels(ifreq, FieldsToCalculate, Receivers, irec, Earth);
  646. Hankel->ComputeRelated( rho, tDipole->GetKernelManager() );
  647. tDipole->UpdateFields( ifreq, Hankel, wavef );
  648. }
  649. void EMEarth1D::SolveLaggedTxRxPair(const int &irec, FHTAnderson801* Hankel,
  650. const Real &wavef, const int &ifreq, PolygonalWireAntenna* antenna) {
  651. antenna->ApproximateWithElectricDipoles(Receivers->GetLocation(irec));
  652. // Determine the min and max arguments
  653. Real rhomin = 1e9;
  654. Real rhomax = 1e-9;
  655. for (int idip=0; idip<antenna->GetNumberOfDipoles(); ++idip) {
  656. auto tDipole = antenna->GetDipoleSource(idip);
  657. Real rho = (Receivers->GetLocation(irec).head<2>() - tDipole->GetLocation().head<2>()).norm();
  658. rhomin = std::min(rhomin, rho);
  659. rhomax = std::max(rhomax, rho);
  660. }
  661. //std::cout << "rhomin\t" << rhomin << "\trhomax" << rhomax << std::endl;
  662. // Determine number of lagged convolutions to do
  663. // TODO, can Hankel2 adjust the lagg spacing safely?
  664. int nlag = 1; // We need an extra for some reason for stability
  665. Real lrho ( 1.01* rhomax );
  666. while ( lrho > rhomin ) {
  667. nlag += 1;
  668. lrho *= Hankel->GetABSER();
  669. }
  670. //int nlag = rhomin
  671. auto tDipole = antenna->GetDipoleSource(0);
  672. tDipole->SetKernels(ifreq, FieldsToCalculate, Receivers, irec, Earth);
  673. // Instead we should pass the antenna into this so that Hankel hass all the rho arguments...
  674. Hankel->ComputeLaggedRelated( 1.01* rhomax, nlag, tDipole->GetKernelManager() );
  675. //std::cout << Hankel->GetAnswer() << std::endl;
  676. //std::cout << Hankel->GetArg() << std::endl;
  677. // Sort the dipoles by rho
  678. for (int idip=0; idip<antenna->GetNumberOfDipoles(); ++idip) {
  679. //for (int idip=0; idip<1; ++idip) {
  680. auto tDipole = antenna->GetDipoleSource(idip);
  681. tDipole->SetKernels(ifreq, FieldsToCalculate, Receivers, irec, Earth);
  682. // Pass Hankel2 a message here so it knows which one to return in Zgauss!
  683. Real rho = (Receivers->GetLocation(irec).head<2>() - tDipole->GetLocation().head<2>()).norm();
  684. //std::cout << " in Lagged " << rho << "\t" << rhomin << "\t" << rhomax << std::endl;
  685. Hankel->SetLaggedArg( rho );
  686. //std::cout << "out Lagged" << std::endl;
  687. tDipole->UpdateFields( ifreq, Hankel, wavef );
  688. }
  689. //std::cout << "Spline\n";
  690. //std::cout << Receivers->GetHfield(0, irec) << std::endl;
  691. }
  692. //////////////////////////////////////////////////////////
  693. // Thread safe OO Reimplimentation of KiHand's
  694. // EM1DNEW.for programme
  695. void EMEarth1D::MakeCalc3() {
  696. if ( Dipole == nullptr ) throw NullDipoleSource();
  697. if (Earth == nullptr) throw NullEarth();
  698. if (Receivers == nullptr) throw NullReceivers();
  699. #ifdef LEMMAUSEOMP
  700. #pragma omp parallel
  701. #endif
  702. { // OpenMP Parallel Block
  703. #ifdef LEMMAUSEOMP
  704. int tid = omp_get_thread_num();
  705. int nthreads = omp_get_num_threads();
  706. #else
  707. int tid=0;
  708. int nthreads=1;
  709. #endif
  710. auto tDipole = Dipole->Clone();
  711. std::shared_ptr<HankelTransform> Hankel;
  712. switch (HankelType) {
  713. case ANDERSON801:
  714. Hankel = FHTAnderson801::NewSP();
  715. break;
  716. case CHAVE:
  717. Hankel = GQChave::NewSP();
  718. break;
  719. case FHTKEY201:
  720. Hankel = FHTKey201::NewSP();
  721. break;
  722. case FHTKEY101:
  723. Hankel = FHTKey101::NewSP();
  724. break;
  725. case FHTKEY51:
  726. Hankel = FHTKey51::NewSP();
  727. break;
  728. case QWEKEY:
  729. Hankel = QWEKey::NewSP();
  730. break;
  731. default:
  732. std::cerr << "Hankel transform cannot be created\n";
  733. exit(EXIT_FAILURE);
  734. }
  735. if ( tDipole->GetNumberOfFrequencies() < Receivers->GetNumberOfPoints() ) {
  736. for (int ifreq=0; ifreq<tDipole->GetNumberOfFrequencies(); ++ifreq) {
  737. // Propogation constant in free space being input to Hankel
  738. Real wavef = tDipole->GetAngularFrequency(ifreq) * std::sqrt(MU0*EPSILON0);
  739. for (int irec=tid; irec<Receivers->GetNumberOfPoints(); irec+=nthreads) {
  740. SolveSingleTxRxPair(irec, Hankel.get(), wavef, ifreq, tDipole.get());
  741. }
  742. }
  743. } else {
  744. for (int irec=0; irec<Receivers->GetNumberOfPoints(); ++irec) {
  745. for (int ifreq=tid; ifreq<tDipole->GetNumberOfFrequencies(); ifreq+=nthreads) {
  746. // Propogation constant in free space being input to Hankel
  747. Real wavef = tDipole->GetAngularFrequency(ifreq) * std::sqrt(MU0*EPSILON0);
  748. SolveSingleTxRxPair(irec, Hankel.get(), wavef, ifreq, tDipole.get());
  749. }
  750. }
  751. }
  752. } // OpenMP Parallel Block
  753. }
  754. NullReceivers::NullReceivers() :
  755. runtime_error("nullptr RECEIVERS") {}
  756. NullAntenna::NullAntenna() :
  757. runtime_error("nullptr ANTENNA") {}
  758. NullInstrument::NullInstrument(LemmaObject* ptr) :
  759. runtime_error("nullptr INSTRUMENT") {
  760. std::cout << "Thrown by instance of "
  761. << ptr->GetName() << std::endl;
  762. }
  763. DipoleSourceSpecifiedForWireAntennaCalc::
  764. DipoleSourceSpecifiedForWireAntennaCalc() :
  765. runtime_error("DIPOLE SOURCE SPECIFIED FOR WIRE ANTENNA CALC"){}
  766. } // end of Lemma Namespace