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.

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