Lemma is an Electromagnetics API
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.

PolygonalWireAntenna.cpp 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  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 05/18/2010
  9. **/
  10. #include "PolygonalWireAntenna.h"
  11. namespace Lemma {
  12. std::ostream &operator << (std::ostream &stream, const PolygonalWireAntenna &ob) {
  13. stream << ob.Serialize() << "\n";
  14. return stream;
  15. }
  16. // ==================== LIFECYCLE =======================
  17. PolygonalWireAntenna::PolygonalWireAntenna( const ctor_key& key ) :
  18. WireAntenna( key ), minDipoleRatio(.15),
  19. minDipoleMoment(1e-6), maxDipoleMoment(1e1), rRepeat(1e10,1e10,1e10) {
  20. Points.setZero();
  21. //rRepeat.setOnes();
  22. }
  23. PolygonalWireAntenna::PolygonalWireAntenna( const YAML::Node& node, const ctor_key& key) : WireAntenna(node, key ) {
  24. minDipoleRatio = node["minDipoleRatio"].as<Real>();
  25. maxDipoleMoment = node["maxDipoleMoment"].as<Real>();
  26. minDipoleMoment = node["minDipoleMoment"].as<Real>();
  27. }
  28. PolygonalWireAntenna::~PolygonalWireAntenna() {
  29. }
  30. //--------------------------------------------------------------------------------------
  31. // Class: PolygonalWireAntenna
  32. // Method: Serialize
  33. //--------------------------------------------------------------------------------------
  34. YAML::Node PolygonalWireAntenna::Serialize ( ) const {
  35. YAML::Node node = WireAntenna::Serialize();
  36. node.SetTag( this->GetName() );
  37. node["minDipoleRatio"] = minDipoleRatio;
  38. node["maxDipoleMoment"] = maxDipoleMoment;
  39. node["minDipoleMoment"] = minDipoleMoment;
  40. return node;
  41. } // ----- end of method PolygonalWireAntenna::Serialize -----
  42. //--------------------------------------------------------------------------------------
  43. // Class: WireAntenna
  44. // Method: DeSerialize
  45. //--------------------------------------------------------------------------------------
  46. std::shared_ptr<PolygonalWireAntenna> PolygonalWireAntenna::DeSerialize ( const YAML::Node& node ) {
  47. if (node.Tag() != "PolygonalWireAntenna") {
  48. throw DeSerializeTypeMismatch( "PolygonalWireAntenna", node.Tag());
  49. }
  50. return std::make_shared<PolygonalWireAntenna> ( node, ctor_key() );
  51. } // ----- end of method WireAntenna::DeSerialize -----
  52. std::shared_ptr<PolygonalWireAntenna> PolygonalWireAntenna::NewSP() {
  53. return std::make_shared<PolygonalWireAntenna>( ctor_key() );
  54. }
  55. std::shared_ptr<WireAntenna> PolygonalWireAntenna::Clone() const {
  56. auto copy = PolygonalWireAntenna::NewSP();
  57. copy->minDipoleRatio = this->minDipoleRatio;
  58. copy->minDipoleMoment = this->minDipoleMoment;
  59. copy->maxDipoleMoment = this->maxDipoleMoment;
  60. copy->NumberOfPoints = this->NumberOfPoints;
  61. copy->Freqs = this->Freqs;
  62. copy->Current = this->Current;
  63. copy->NumberOfTurns = this->NumberOfTurns;
  64. copy->Points = this->Points;
  65. //copy->Dipoles = this->Dipoles; // no, disaster
  66. return copy;
  67. }
  68. std::shared_ptr<PolygonalWireAntenna> PolygonalWireAntenna::ClonePA() const {
  69. auto copy = PolygonalWireAntenna::NewSP();
  70. copy->minDipoleRatio = this->minDipoleRatio;
  71. copy->minDipoleMoment = this->minDipoleMoment;
  72. copy->maxDipoleMoment = this->maxDipoleMoment;
  73. copy->NumberOfPoints = this->NumberOfPoints;
  74. copy->Freqs = this->Freqs;
  75. copy->Current = this->Current;
  76. copy->NumberOfTurns = this->NumberOfTurns;
  77. copy->Points = this->Points;
  78. //copy->Dipoles = this->Dipoles; // no, disaster
  79. return copy;
  80. }
  81. //--------------------------------------------------------------------------------------
  82. // Class: PolygonalWireAntenna
  83. // Method: GetName
  84. // Description: Class identifier
  85. //--------------------------------------------------------------------------------------
  86. inline std::string PolygonalWireAntenna::GetName ( ) const {
  87. return CName;
  88. } // ----- end of method PolygonalWireAntenna::GetName -----
  89. void PolygonalWireAntenna::SetMinDipoleRatio (const Real& ratio) {
  90. minDipoleRatio = ratio;
  91. }
  92. void PolygonalWireAntenna::SetMinDipoleMoment (const Real& m) {
  93. minDipoleMoment = m;
  94. }
  95. void PolygonalWireAntenna::SetMaxDipoleMoment (const Real& m) {
  96. maxDipoleMoment = m;
  97. }
  98. // ==================== OPERATIONS =======================
  99. void PolygonalWireAntenna::ApproximateWithElectricDipoles(const Vector3r &rp) {
  100. // Only resplit if necessary. Save a few cycles if repeated
  101. if ( (rRepeat-rp).norm() > 1e-16 ) {
  102. Dipoles.clear();
  103. ///////////////////
  104. // dipole array, this has impoved performance over directly pushing
  105. std::vector< std::shared_ptr<DipoleSource> > xDipoles;
  106. // check to see if loop is closed
  107. /*
  108. int lastPoint = Points.cols()-1;
  109. if ( (Points.col(0) - Points.col(lastPoint)).norm() > 1e-3 ) {
  110. AddGroundingPoint( Points.col(0), Points.col(1)-Points.col(0), xDipoles );
  111. }
  112. */
  113. // loop over all segments, TODO fix for closed loops
  114. int iseg;
  115. for (iseg=0; iseg<NumberOfPoints-1; ++iseg) { // closed loop
  116. //for (iseg=1; iseg<NumberOfPoints-2; ++iseg) { // grounded wire
  117. InterpolateLineSegment(Points.col(iseg), Points.col(iseg+1), rp, xDipoles);
  118. }
  119. // check to see if loop is closed
  120. /*
  121. if ( (Points.col(lastPoint)-Points.col( lastPoint-1 )).norm() > 1e-3 ) {
  122. AddGroundingPoint( Points.col(lastPoint), Points.col(lastPoint)-Points.col(lastPoint-1), xDipoles );
  123. }
  124. */
  125. // Check to see if the loop is closed, if not, assume its grounded on ends,
  126. //if ( (Points.col(0)-Points.col(iseg)).norm() > 1e-3 ) {
  127. // xDipoles[0]->SetType(GROUNDEDELECTRICDIPOLE);
  128. // xDipoles.back()->SetType(GROUNDEDELECTRICDIPOLE);
  129. //}
  130. Dipoles = std::move(xDipoles);
  131. rRepeat = rp;
  132. } else {
  133. for (unsigned int id=0; id<Dipoles.size(); ++id) {
  134. Dipoles[id]->SetFrequencies(Freqs);
  135. }
  136. }
  137. }
  138. void PolygonalWireAntenna::AddGroundingPoint( const Vector3r &cp, const Vector3r& dir,
  139. std::vector< std::shared_ptr<DipoleSource> > &xDipoles) {
  140. Real scale = (Real)(NumberOfTurns)*Current;
  141. auto tx = DipoleSource::NewSP();
  142. tx->SetLocation(cp);
  143. tx->SetType(GROUNDINGPOINT);
  144. //tx->SetType(GROUNDEDELECTRICDIPOLE);
  145. //tx->SetType(MAGNETICDIPOLE);
  146. tx->SetPolarisation(dir.array()); //dir.norm());
  147. tx->SetFrequencies(Freqs);
  148. tx->SetMoment(scale);
  149. xDipoles.push_back(tx);
  150. //std::cout << "cp " << cp.transpose() << std::endl;
  151. //std::cout << "pol " << tx->GetPolarisation().transpose() << std::endl;
  152. //std::cout << "moment " << tx->GetMoment() << std::endl;
  153. }
  154. Vector3r PolygonalWireAntenna::ClosestPointOnLine(const Vector3r &p1,
  155. const Vector3r &p2, const Vector3r &tp) {
  156. Vector3r v1 = p2 - p1;
  157. Vector3r v2 = p1 - tp;
  158. Vector3r v3 = p1 - p2;
  159. Vector3r v4 = p2 - tp;
  160. Real dot1 = v2.dot(v1);
  161. Real dot2 = v1.dot(v1);
  162. Real dot3 = v4.dot(v3);
  163. Real dot4 = v3.dot(v3);
  164. Real t1 = -1.*dot1/dot2;
  165. Real t2 = -1.*dot3/dot4;
  166. Vector3r pos = p1+v1*t1 ;
  167. // check if on line
  168. // else give back the closest end point
  169. if ( t1>=0 && t2>=0. ) {
  170. return pos;
  171. } else if (t1<0) {
  172. return p1;
  173. } else {
  174. return p2;
  175. }
  176. }
  177. void PolygonalWireAntenna::PushXYZDipoles(const Vector3r &step,
  178. const Vector3r &cp, const Vector3r &dir,
  179. std::vector< std::shared_ptr<DipoleSource> > &xDipoles) {
  180. Real scale = (Real)(NumberOfTurns)*Current;
  181. auto tx = DipoleSource::NewSP();
  182. tx->SetLocation(cp);
  183. tx->SetType(UNGROUNDEDELECTRICDIPOLE);
  184. tx->SetPolarisation(dir);
  185. tx->SetFrequencies(Freqs);
  186. tx->SetMoment(scale*step.norm());
  187. xDipoles.push_back(tx);
  188. }
  189. void PolygonalWireAntenna::CorrectOverstepXYZDipoles(const Vector3r &step,
  190. const Vector3r &cp, const Vector3r &dir,
  191. std::vector< std::shared_ptr<DipoleSource> > &xDipoles ) {
  192. Real scale = (Real)(NumberOfTurns)*Current;
  193. // X oriented dipoles
  194. if (step.norm() > minDipoleMoment) {
  195. xDipoles[xDipoles.size()-1]->SetLocation(cp);
  196. xDipoles[xDipoles.size()-1]->SetMoment(scale*step.norm());
  197. }
  198. }
  199. void PolygonalWireAntenna::InterpolateLineSegment(const Vector3r &p1,
  200. const Vector3r &p2, const Vector3r & tp,
  201. std::vector< std::shared_ptr<DipoleSource> > &xDipoles ) {
  202. Vector3r phat = (p1-p2).array() / (p1-p2).norm();
  203. Vector3r c = this->ClosestPointOnLine(p1, p2, tp);
  204. Real dtp = (tp-c).norm(); // distance to point at c
  205. Real dc1 = (p1-c).norm(); // distance to c from p1
  206. Real dc2 = (p2-c).norm(); // distance to c from p1
  207. // unit vector
  208. Vector3r cdir = (p2-p1).array() / (p2-p1).norm();
  209. // go towards p1
  210. if ( ((c-p1).array().abs() > minDipoleMoment).any() ) {
  211. // cp = current pos, lp = last pos
  212. Vector3r cp = c + phat*(dtp*minDipoleRatio)*.5;
  213. Vector3r lp = c;
  214. Real dist = (cp-p1).norm();
  215. Real dist_old = dist+1.;
  216. // check that we didn't run past the end, or that we aren't starting at
  217. // the end, or that initial step runs over!
  218. Vector3r dir = (p1-cp).array() / (p1-cp).norm(); // direction of movement
  219. Vector3r step = phat*(dtp*minDipoleRatio);
  220. Vector3r stepold = Vector3r::Zero();
  221. // (dir-phat) just shows if we are stepping towards or away from p1
  222. while (dist < dist_old && (dir-phat).norm() < 1e-8) {
  223. PushXYZDipoles(step, cp, cdir, xDipoles);
  224. // Make 1/2 of previous step, 1/2 of this step, store this step
  225. stepold = step;
  226. step = phat*( (cp-tp).norm()*minDipoleRatio );
  227. while ( (step.array().abs() > maxDipoleMoment).any() ) {
  228. step *= .5;
  229. }
  230. lp = cp;
  231. cp += .5*stepold + .5*step;
  232. dist = (cp-p1).norm();
  233. dir = (p1-cp).array() / (p1-cp).norm();
  234. }
  235. // cp now points to end last of dipole moments
  236. cp -= .5*step;
  237. // Fix last dipole position, so that entire wire is represented,
  238. // and no more
  239. Real distLastSeg = (c - cp).norm();
  240. if (distLastSeg + minDipoleMoment < dc1) {
  241. // case 1: understep, add dipole
  242. step = (p1-cp).array();
  243. cp += .5*step;
  244. PushXYZDipoles(step, cp, cdir, xDipoles);
  245. } else if (distLastSeg > dc1 + minDipoleMoment) {
  246. // case 2: overstep, reposition dipole and size
  247. step = (p1 - (lp-.5*stepold));
  248. cp = (lp-.5*stepold) + (.5*step);
  249. CorrectOverstepXYZDipoles(step, cp, cdir, xDipoles);
  250. }
  251. // else case 0: nearly 'perfect' fit do nothing
  252. }
  253. // go towards p2
  254. if ( ( (c-p2).array().abs() > minDipoleMoment).any() ) {
  255. // cp = current pos, lp = last pos
  256. Vector3r step = -phat*(dtp*minDipoleRatio);
  257. while ( (step.array().abs() > maxDipoleMoment).any() ) {
  258. step *= .5;
  259. }
  260. Vector3r cp = c + step*.5;
  261. Vector3r lp = c;
  262. Real dist = (p2-cp).norm();
  263. Real dist_old = dist+1e3;
  264. // check that we didn't run past the end, or that we aren't starting at
  265. // the end, or that initial step runs over!
  266. Vector3r dir = (p2-cp).array() / (p2-cp).norm(); // direction of movement
  267. Vector3r stepold = Vector3r::Zero();
  268. // (dir-phat) just shows if we are stepping towards or away from p1
  269. while (dist < dist_old && (dir+phat).norm() < 1e-8) {
  270. PushXYZDipoles(step, cp, cdir, xDipoles);
  271. // Make 1/2 of previous step, 1/2 of this step, store this step
  272. stepold = step;
  273. step = -phat*( (cp-tp).norm()*minDipoleRatio );
  274. while ( (step.array().abs() > maxDipoleMoment).any() ) {
  275. step *= .5;
  276. }
  277. lp = cp;
  278. cp += .5*stepold + .5*step;
  279. dist = (cp-p2).norm();
  280. dir = (p2-cp).array() / (p2-cp).norm();
  281. }
  282. // cp now points to end last of dipole moments
  283. cp -= .5*step;
  284. // Fix last dipole position, so that entire wire is represented,
  285. // and no more
  286. Real distLastSeg = (c - cp).norm();
  287. if (distLastSeg + minDipoleMoment < dc2) {
  288. // case 1: understep, add dipole
  289. step = (p2-cp).array();
  290. cp += .5*step;
  291. PushXYZDipoles(step, cp, cdir, xDipoles);
  292. } else if (distLastSeg > dc2 + minDipoleMoment) {
  293. // case 2: overstep, reposition dipole and size
  294. step = (p2 - (lp-.5*stepold));
  295. cp = (lp-.5*stepold) + (.5*step);
  296. CorrectOverstepXYZDipoles(step, cp, cdir, xDipoles);
  297. }
  298. // else case 0: nearly 'perfect' fit do nothing
  299. }
  300. //Dipoles.insert(Dipoles.end(), xDipoles.begin(), xDipoles.end());
  301. //Dipoles = xDipoles;
  302. //xDipoles.clear();
  303. }
  304. }