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.

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. }