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.

hantenna_mex.cpp 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. /* MyMEXFunction
  2. * Adds second input to each
  3. * element of first input
  4. * a = MyMEXFunction(a,b);
  5. */
  6. #include "mex.hpp"
  7. #include "mexAdapter.hpp"
  8. #include "MatlabDataArray.hpp"
  9. #include "LemmaCore"
  10. #include "FDEM1D"
  11. #include "timer.h"
  12. #include <Eigen/Core>
  13. #if defined(__clang__)
  14. /* Clang/LLVM. ---------------------------------------------- */
  15. const char* compiler = "clang";
  16. const char* ver = __VERSION__;
  17. #elif defined(__ICC) || defined(__INTEL_COMPILER)
  18. /* Intel ICC/ICPC. ------------------------------------------ */
  19. const char* compiler = "icpc";
  20. const char* ver = __VERSION__;
  21. #elif defined(__GNUC__) || defined(__GNUG__)
  22. /* GNU GCC/G++. --------------------------------------------- */
  23. const char* compiler = "gcc (GCC) ";// __VERSION__;
  24. const char* ver = __VERSION__;
  25. #elif defined(_MSC_VER)
  26. /* Microsoft Visual Studio. --------------------------------- */
  27. const char* compiler = "msvc ";
  28. const int ver = _MSC_FULL_VER;
  29. #elif defined(__PGI)
  30. /* Portland Group PGCC/PGCPP. ------------------------------- */
  31. const char* compiler = "pgc";
  32. #endif
  33. using namespace Lemma;
  34. using namespace matlab::data;
  35. using matlab::mex::ArgumentList;
  36. std::vector<Real> readinpfile(const std::string& fname);
  37. std::vector<std::string> readinpfile2(const std::string& fname);
  38. class MexFunction : public matlab::mex::Function {
  39. public:
  40. void operator()(ArgumentList outputs, ArgumentList inputs) {
  41. const char *buildString = __DATE__ ", " __TIME__;
  42. std::cout
  43. << "===========================================================================\n"
  44. << "Lemma " << LEMMA_VERSION << "\n"
  45. << "[" << compiler << " " << ver << " " << buildString << "]\n"
  46. << "This program is part of Lemma, a geophysical modelling and inversion API. \n"
  47. << " This Source Code Form is subject to the terms of the Mozilla Public\n"
  48. << " License, v. 2.0. If a copy of the MPL was not distributed with this\n"
  49. << " file, You can obtain one at http://mozilla.org/MPL/2.0/. \n"
  50. << "Copyright (C) 2018 Lemma Software \n"
  51. << "More information may be found at: https://lemmasoftware.org\n"
  52. << " info@lemmasoftware.org\n"
  53. << "===========================================================================\n\n"
  54. << "Hantenna calculates the harmonic H field from polygonal wire loop sources\n";
  55. // TODO add this
  56. //checkArguments(outputs, inputs);
  57. // TODO, add this to check arguments and formalize
  58. if (inputs.size() < 4) {
  59. std::cout << "usage: hantenna(trans.inp cond.inp points.inp config.inp) \n";
  60. ArrayFactory ef;
  61. outputs[0] = ef.createCharArray("Insufficient inputs");
  62. return;
  63. //exit(EXIT_SUCCESS);
  64. }
  65. #ifdef LEMMAUSEOMP
  66. std::cout << "OpenMP is using " << omp_get_max_threads() << " threads" << std::endl;
  67. #endif
  68. /*
  69. std::vector<Real> Trans = readinpfile(std::string(inputs[1]));
  70. std::vector<Real> CondMod = readinpfile(std::string(inputs[2]));
  71. std::vector<Real> Points = readinpfile(std::string(inputs[3]));
  72. std::vector<std::string> config = readinpfile2(std::string(inputs[4]));
  73. */
  74. // Let's fix this inputs thing
  75. matlab::data::CharArray charVector2 = inputs[0];
  76. std::string TransFile = charVector2.toAscii();
  77. std::vector<Real> Trans = readinpfile( "trans.inp" );
  78. std::vector<std::string> config = readinpfile2("config.inp");
  79. std::vector<Real> CondMod = readinpfile("cond.inp");
  80. std::vector<Real> Points = readinpfile("points.inp");
  81. //////////////////////////////////////
  82. // Define transmitter
  83. auto trans = PolygonalWireAntenna::NewSP();
  84. trans->SetNumberOfPoints((int)(Trans[0]));
  85. int ip=1;
  86. for ( ; ip<=(int)(Trans[0])*2; ip+=2) {
  87. trans->SetPoint(ip/2, Vector3r (Trans[ip], Trans[ip+1], -1e-3));
  88. //trans->SetPoint(ip/2, Vector3r (Trans[ip], Trans[ip+1], 50.));
  89. }
  90. trans->SetNumberOfFrequencies(1);
  91. trans->SetFrequency(0, Trans[ip]);
  92. trans->SetCurrent(Trans[ip+1]);
  93. trans->SetMinDipoleRatio(atof(config[1].c_str()));
  94. trans->SetMinDipoleMoment(atof(config[2].c_str()));
  95. trans->SetMaxDipoleMoment(atof(config[3].c_str()));
  96. /////////////////////////////////////
  97. // Field calculations
  98. auto receivers = FieldPoints::NewSP();
  99. int nx = (int)Points[0];
  100. int ny = (int)Points[1];
  101. int nz = (int)Points[2];
  102. Real ox = Points[3];
  103. Real oy = Points[4];
  104. Real oz = Points[5];
  105. Vector3r loc;
  106. VectorXr dx(nx-1);
  107. VectorXr dy(ny-1);
  108. VectorXr dz(nz-1);
  109. ip = 6;
  110. int ir = 0;
  111. for ( ; ip <6+nx-1; ++ip) {
  112. dx[ir] = Points[ip];
  113. ++ir;
  114. }
  115. ir = 0;
  116. for ( ; ip <6+ny-1+nx-1; ++ip) {
  117. dy[ir] = Points[ip];
  118. ++ir;
  119. }
  120. ir = 0;
  121. for ( ; ip <6+nz-1+ny-1+nx-1; ++ip) {
  122. dz[ir] = Points[ip];
  123. ++ir;
  124. }
  125. receivers->SetNumberOfPoints(nx*ny*nz);
  126. ir = 0;
  127. Real pz = oz;
  128. for (int iz=0; iz<nz; ++iz) {
  129. Real py = oy;
  130. for (int iy=0; iy<ny; ++iy) {
  131. Real px = ox;
  132. for (int ix=0; ix<nx; ++ix) {
  133. loc << px, py, pz;
  134. receivers->SetLocation(ir, loc);
  135. if (ix < nx-1) px += dx[ix];
  136. ++ ir;
  137. }
  138. if (iy<ny-1) py += dy[iy];
  139. }
  140. if (iz<nz-1) pz += dz[iz];
  141. }
  142. ////////////////////////////////////
  143. // Define model
  144. auto earth = LayeredEarthEM::NewSP();
  145. VectorXcr sigma;
  146. VectorXr thick;
  147. earth->SetNumberOfLayers(static_cast<int>(CondMod[0])+1);
  148. sigma.resize(static_cast<int>(CondMod[0])+1); sigma(0) = 0; // airlayer
  149. thick.resize(static_cast<int>(CondMod[0])-1);
  150. int ilay=1;
  151. for ( ; ilay/2<CondMod[0]-1; ilay+=2) {
  152. sigma(ilay/2+1) = 1./CondMod[ilay];
  153. thick(ilay/2) = CondMod[ilay+1];
  154. }
  155. sigma(ilay/2+1) = 1./ CondMod[ilay];
  156. earth->SetLayerConductivity(sigma);
  157. if (thick.size() > 0) earth->SetLayerThickness(thick);
  158. auto EmEarth = EMEarth1D::NewSP();
  159. EmEarth->AttachWireAntenna(trans);
  160. EmEarth->AttachLayeredEarthEM(earth);
  161. EmEarth->AttachFieldPoints(receivers);
  162. EmEarth->SetFieldsToCalculate(H);
  163. EmEarth->SetHankelTransformMethod(string2Enum<HANKELTRANSFORMTYPE>(config[0]));
  164. ///////////////////////////////////////////////
  165. // Keep track of time
  166. jsw_timer timer;
  167. timer.begin();
  168. clock_t launch = clock();
  169. EmEarth->CalculateWireAntennaFields(false); // false=status bar, doesn't work in Matlab well
  170. Real paTime = timer.end();
  171. std::cout << "\n\n===========================================\ncalc. real time: " << paTime/60. << "\t[m]\n";
  172. std::cout << "calc. user time: " << (clock()-launch)/CLOCKS_PER_SEC/60. << "\t[CPU m]"
  173. << std::endl;
  174. ////////////////////////////////////////////////////////////////////
  175. // This is kind of ugly, but the Matlab conversion is really picky
  176. // Convert C++ arrays to Matlab
  177. ArrayFactory f;
  178. StructArray S = f.createStructArray({ 3,1 }, { "Component", "Data", "Units" });
  179. S[0]["Component"] = f.createCharArray("H_x");
  180. S[0]["Units"] = f.createCharArray("A/m");
  181. Eigen::Array<Complex, Eigen::Dynamic, 1> Hx = receivers->GetHfield(0).row(0).array();
  182. std::vector<Complex> Hxv = std::vector<Complex>(Hx.begin(), Hx.end());
  183. matlab::data::TypedArray<Complex> Hxm = f.createArray<Complex>({1, Hxv.size()}, Hxv.data(), Hxv.data()+Hxv.size());
  184. S[0]["Data"] = std::move(Hxm);
  185. S[1]["Component"] = f.createCharArray("H_y");
  186. S[1]["Units"] = f.createCharArray("A/m");
  187. Eigen::Array<Complex, Eigen::Dynamic, 1> Hy = receivers->GetHfield(0).row(1).array();
  188. std::vector<Complex> Hyv = std::vector<Complex>(Hy.begin(), Hy.end());
  189. matlab::data::TypedArray<Complex> Hym = f.createArray<Complex>({1, Hyv.size()}, Hyv.data(), Hyv.data()+Hyv.size());
  190. S[1]["Data"] = std::move(Hym);
  191. S[2]["Component"] = f.createCharArray("H_z");
  192. S[2]["Units"] = f.createCharArray("A/m");
  193. Eigen::Array<Complex, Eigen::Dynamic, 1> Hz = receivers->GetHfield(0).row(2).array();
  194. std::vector<Complex> Hzv = std::vector<Complex>(Hz.begin(), Hz.end());
  195. matlab::data::TypedArray<Complex> Hzm = f.createArray<Complex>({1, Hzv.size()}, Hzv.data(), Hzv.data()+Hzv.size());
  196. S[2]["Data"] = std::move(Hzm);
  197. outputs[0] = std::move(S);
  198. ////////////////////////////////////
  199. // Report, file write is s l o w
  200. /*
  201. std::fstream hrep("hfield.yaml", std::ios::out);
  202. std::fstream hreal("hfield.dat", std::ios::out);
  203. hrep << *EmEarth << std::endl;
  204. hrep.close();
  205. hreal << "// Right hand coordinate system, z is positive down\n";
  206. hreal << "// x[m]\ty[m]\tz[m]\tRe(Hx[A/m])\tRe(Hy[A/m])\tRe(Hz[A/m])\tIm(Hx)\tIm(Hy)\tIm(Hz)\n";
  207. hreal.precision(8);
  208. int i=0;
  209. for (int iz=0; iz<nz; ++iz) {
  210. for (int iy=0; iy<ny; ++iy) {
  211. for (int ix=0; ix<nx; ++ix) {
  212. hreal << receivers->GetLocation(i).transpose() << "\t";
  213. hreal << receivers->GetHfield(0, i).transpose() << "\n"; // ( complex, notation )
  214. //hreal << receivers->GetHfield(0, i).transpose().real() << "\t";
  215. //hreal << receivers->GetHfield(0, i).transpose().imag() << "\n";
  216. ++i;
  217. }
  218. }
  219. }
  220. hreal.close();
  221. */
  222. // Demo stuff
  223. /*
  224. const double offSet = inputs[0][0];
  225. TypedArray<double> doubleArray = std::move(inputs[1]);
  226. for (auto& elem : doubleArray) {
  227. elem += offSet;
  228. }
  229. outputs[0] = doubleArray;
  230. */
  231. }
  232. void checkArguments(ArgumentList outputs, ArgumentList inputs) {
  233. // Get pointer to engine
  234. std::shared_ptr<matlab::engine::MATLABEngine> matlabPtr = getEngine();
  235. // Get array factory
  236. ArrayFactory factory;
  237. // Check first input argument
  238. if (inputs[0].getType() != ArrayType::CHAR ||
  239. inputs[0].getNumberOfElements() != 1)
  240. {
  241. matlabPtr->feval(u"error",
  242. 0,
  243. std::vector<Array>({ factory.createScalar("First input must be the name of a trans.inp file") }));
  244. }
  245. // Check second input argument
  246. if (inputs[1].getType() != ArrayType::DOUBLE ||
  247. inputs[1].getType() == ArrayType::COMPLEX_DOUBLE)
  248. {
  249. matlabPtr->feval(u"error",
  250. 0,
  251. std::vector<Array>({ factory.createScalar("Input must be double array") }));
  252. }
  253. // Check number of outputs
  254. if (outputs.size() > 1) {
  255. matlabPtr->feval(u"error",
  256. 0,
  257. std::vector<Array>({ factory.createScalar("Only one output is returned") }));
  258. }
  259. }
  260. };
  261. std::vector<Real> readinpfile(const std::string& fname) {
  262. std::string buf;
  263. char dump[255];
  264. std::vector<Real> vals;
  265. std::fstream input(fname.c_str(), std::ios::in);
  266. if (input.fail()) {
  267. std::cerr << "Input file " << fname << " failed to open\n";
  268. exit(EXIT_FAILURE);
  269. }
  270. while (input >> buf) {
  271. if (buf.substr(0,2) == "//") {
  272. input.getline(dump, 255);
  273. } else {
  274. vals.push_back( atof(buf.c_str() ));
  275. }
  276. }
  277. return vals;
  278. }
  279. std::vector<std::string> readinpfile2(const std::string& fname) {
  280. std::string buf;
  281. char dump[255];
  282. std::vector<std::string> vals;
  283. std::fstream input(fname.c_str(), std::ios::in);
  284. if (input.fail()) {
  285. std::cerr << "Input file " << fname << " failed to open\n";
  286. exit(EXIT_FAILURE);
  287. }
  288. while (input >> buf) {
  289. if (buf.substr(0,2) == "//") {
  290. input.getline(dump, 255);
  291. } else {
  292. vals.push_back( std::string(buf.c_str() ));
  293. }
  294. }
  295. return vals;
  296. }