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

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