Main Lemma Repository
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

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