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