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 38KB

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