Bladeren bron

Multiple coils are supported, preliminary nmr modeling added, but not yet verified.

master
T-bone 8 jaren geleden
bovenliggende
commit
602750cc78
4 gewijzigde bestanden met toevoegingen van 189 en 42 verwijderingen
  1. 0
    1
      examples/CMakeLists.txt
  2. 2
    2
      examples/KernelV0.cpp
  3. 39
    5
      include/KernelV0.h
  4. 148
    34
      src/KernelV0.cpp

+ 0
- 1
examples/CMakeLists.txt Bestand weergeven

@@ -4,7 +4,6 @@ target_link_libraries(  KernelV0  "lemmacore" "fdem1d" "merlin")
4 4
 # Linking
5 5
 if ( LEMMA_VTK6_SUPPORT OR LEMMA_VTK7_SUPPORT ) 
6 6
 	target_link_libraries( KernelV0 ${VTK_LIBRARIES})
7
-#	target_link_libraries(lemmacore "matplot")
8 7
 endif()
9 8
 
10 9
 INSTALL_TARGETS( "/share/Merlin/"

+ 2
- 2
examples/KernelV0.cpp Bestand weergeven

@@ -31,7 +31,7 @@ int main() {
31 31
 
32 32
     // Transmitter loops
33 33
     auto Tx1 = CircularLoop(60, 15, 100, 100);
34
-    auto Tx2 = CircularLoop(60, 15, 55, 50);
34
+    auto Tx2 = CircularLoop(60, 15, 100, 120);
35 35
     //auto Tx1 = CircularLoop(60, 15, 0, 0); // was 60
36 36
 
37 37
     auto Kern = KernelV0::NewSP();
@@ -43,7 +43,7 @@ int main() {
43 43
     // We could, I suppose, take the earth model in here? For non-linear that
44 44
     // may be more natural to work with?
45 45
     std::vector<std::string> tx = {std::string("Coil 1")};
46
-    std::vector<std::string> rx = {std::string("Coil 1")};
46
+    std::vector<std::string> rx = {std::string("Coil 2")};
47 47
     Kern->CalculateK0( tx, rx , true ); //, false );
48 48
     //Kern->CalculateK0( "Coil 1", "Coil 1" );
49 49
 

+ 39
- 5
include/KernelV0.h Bestand weergeven

@@ -34,6 +34,19 @@
34 34
 
35 35
 namespace Lemma {
36 36
 
37
+    struct EllipticB {
38
+        Vector3r  bhat;
39
+        Vector3r  bhatp;
40
+        Real      alpha;
41
+        Real      beta;
42
+        Complex   eizt;
43
+        Real      zeta;
44
+    };
45
+
46
+    template <typename T> int sgn(T val) {
47
+        return (val > T(0)) - (val < T(0));
48
+    }
49
+
37 50
     /**
38 51
      * \ingroup Merlin
39 52
      * \brief
@@ -162,7 +175,18 @@ namespace Lemma {
162 175
         /**
163 176
          *  Returns the kernel value for an input prism
164 177
          */
165
-        Complex f( const Vector3r& r, const Real& volume , const Vector3cr& Bt);
178
+        Complex f( const Vector3r& r, const Real& volume , const Vector3cr& Ht, const Vector3cr& Hr);
179
+
180
+        Complex ComputeV0Cell(const Vector3cr& Bt, const Vector3cr& Br, const Real& vol,
181
+            const Real& phi);
182
+
183
+        Complex ComputeV0Cell(const EllipticB& EBT, const EllipticB& EBR,
184
+                const Real& sintheta, const Real& phase, const Real& Mn0Abs,
185
+                const Real& vol);
186
+
187
+        EllipticB EllipticFieldRep (const Vector3cr& B, const Vector3r& B0hat);
188
+
189
+        Vector3r ComputeMn0(const Real& Porosity, const Vector3r& B0);
166 190
 
167 191
         void IntegrateOnOctreeGrid( const Real& tolerance , bool vtkOutput=false );
168 192
 
@@ -192,27 +216,37 @@ namespace Lemma {
192 216
 
193 217
         // ====================  DATA MEMBERS  =========================
194 218
 
195
-        Complex                                   SUM;
219
+        int                                       nleaves;
196 220
 
197 221
         Real                                      VOLSUM;
198
-
199 222
         Real                                      tol=1e-3;
223
+        //Real                                        Temperature;
200 224
 
201
-        int                                       nleaves;
225
+        Complex                                   SUM;
202 226
 
203 227
         Vector3r   Size;
204 228
         Vector3r   Origin;
205 229
 
206 230
         std::shared_ptr< LayeredEarthEM >         SigmaModel = nullptr;
207 231
 
232
+        std::shared_ptr< FieldPoints >            cpoints;
233
+
208 234
         std::map< std::string , std::shared_ptr< PolygonalWireAntenna > >  TxRx;
209 235
 
210
-        std::vector< std::shared_ptr<EMEarth1D> > EMEarths;
236
+        std::map< std::string , std::shared_ptr< EMEarth1D > >             EMEarths;
211 237
 
212 238
         #ifdef LEMMAUSEVTK
213 239
         std::map< int, Complex  >                 LeafDict;
214 240
         #endif
215 241
 
242
+        // Physical constants and conversion factors
243
+        static constexpr Real GAMMA = 2.67518e8;                  // MKS units
244
+        static constexpr Real INVSQRT2 = 0.70710678118654746;
245
+        static constexpr Real HBAR = 1.05457148e-34;              // m2 kg / s
246
+        static constexpr Real NH2O = 6.692e28;                    // [m^3]
247
+        static constexpr Real KB = 1.3805e-23;                    // m^2 kg s-2 K-1
248
+        static constexpr Real CHI_N = 3.29e-3;                    // MKS units
249
+
216 250
         /** ASCII string representation of the class name */
217 251
         static constexpr auto CName = "KernelV0";
218 252
 

+ 148
- 34
src/KernelV0.cpp Bestand weergeven

@@ -106,19 +106,34 @@ namespace Lemma {
106 106
             bool vtkOutput ) {
107 107
 
108 108
         // All EM calculations will share same field points
109
-        auto points = FieldPoints::NewSP();
110
-            points->SetNumberOfPoints(8);
109
+        cpoints = FieldPoints::NewSP();
110
+            cpoints->SetNumberOfPoints(8);
111 111
         for (auto tx : Tx) {
112 112
             // Set up EMEarth
113
-            EMEarths.push_back( EMEarth1D::NewSP() );
114
-                EMEarths.back()->AttachWireAntenna(TxRx[tx]);
115
-                EMEarths.back()->AttachLayeredEarthEM(SigmaModel);
116
-                EMEarths.back()->AttachFieldPoints( points );
117
-         		EMEarths.back()->SetFieldsToCalculate(H);
113
+            EMEarths[tx] = EMEarth1D::NewSP();
114
+                EMEarths[tx]->AttachWireAntenna(TxRx[tx]);
115
+                EMEarths[tx]->AttachLayeredEarthEM(SigmaModel);
116
+                EMEarths[tx]->AttachFieldPoints( cpoints );
117
+         		EMEarths[tx]->SetFieldsToCalculate(H);
118 118
                 // TODO query for method, altough with flat antennae, this is fastest
119
-                EMEarths.back()->SetHankelTransformMethod(ANDERSON801);
119
+                EMEarths[tx]->SetHankelTransformMethod(ANDERSON801);
120
+                EMEarths[tx]->SetTxRxMode(TX);
120 121
         }
121
-        IntegrateOnOctreeGrid( 1e-5, vtkOutput );
122
+        for (auto rx : Rx) {
123
+            if (EMEarths.count(rx)) {
124
+                EMEarths[rx]->SetTxRxMode(TXRX);
125
+            } else {
126
+                EMEarths[rx] = EMEarth1D::NewSP();
127
+                    EMEarths[rx]->AttachWireAntenna(TxRx[rx]);
128
+                    EMEarths[rx]->AttachLayeredEarthEM(SigmaModel);
129
+                    EMEarths[rx]->AttachFieldPoints( cpoints );
130
+         		    EMEarths[rx]->SetFieldsToCalculate(H);
131
+                    // TODO query for method, altough with flat antennae, this is fastest
132
+                    EMEarths[rx]->SetHankelTransformMethod(ANDERSON801);
133
+                    EMEarths[rx]->SetTxRxMode(RX);
134
+            }
135
+        }
136
+        IntegrateOnOctreeGrid( 1e-7, vtkOutput );
122 137
 
123 138
     }
124 139
 
@@ -130,9 +145,9 @@ namespace Lemma {
130 145
 
131 146
         this->tol = tolerance;
132 147
         //Vector3r                Size;
133
-            Size << 200,200,200;
148
+            Size << 200,200,20;
134 149
         //Vector3r                Origin;
135
-            Origin << 0,0,1.0;
150
+            Origin << 0,0,5.0;
136 151
         Vector3r                cpos;  // centre position
137 152
             //cpos << 100,100,50;
138 153
             cpos = (Size-Origin).array() / 2.;
@@ -185,7 +200,8 @@ namespace Lemma {
185 200
         #endif
186 201
 
187 202
         }
188
-        std::cout << "\nVOLSUM=" << VOLSUM << "\tActual=" <<  Size(0)*Size(1)*Size(2) << "\tDifference=" << VOLSUM - (Size(0)*Size(1)*Size(2)) <<  std::endl;
203
+        std::cout << "\nVOLSUM=" << VOLSUM << "\tActual=" <<  Size(0)*Size(1)*Size(2)
204
+                  << "\tDifference=" << VOLSUM - (Size(0)*Size(1)*Size(2)) <<  std::endl;
189 205
         std::cout << "nleaves\t" << nleaves << std::endl;
190 206
         std::cout << "KSUM\t" << SUM << std::endl;
191 207
 
@@ -195,13 +211,83 @@ namespace Lemma {
195 211
     //       Class:  KernelV0
196 212
     //      Method:  f
197 213
     //--------------------------------------------------------------------------------------
198
-    Complex KernelV0::f( const Vector3r& r, const Real& volume, const Vector3cr& Bt ) {
199
-        //std::cout << volume*Bt.norm() << std::endl;
200
-        //return Complex(volume*Bt.norm());
201
-        return Complex(volume*Bt.norm());
202
-        //return Complex(volume);
214
+    Complex KernelV0::f( const Vector3r& r, const Real& volume, const Vector3cr& Ht, const Vector3cr& Hr ) {
215
+        return Complex(volume*Ht.dot(Hr));
216
+        //return ComputeV0Cell(MU0*Ht, MU0*Hr, volume, 1.0);
217
+    }
218
+
219
+    //--------------------------------------------------------------------------------------
220
+    //       Class:  KernelV0
221
+    //      Method:  ComputeV0Cell
222
+    //--------------------------------------------------------------------------------------
223
+    Complex KernelV0::ComputeV0Cell(const Vector3cr& Bt,
224
+                const Vector3cr& Br, const Real& vol, const Real& phi) {
225
+
226
+        // Compute the elliptic fields
227
+        Vector3r B0hat = {1,0,0};
228
+        Vector3r B0 = 53000 * B0hat; // nT
229
+        EllipticB EBT = EllipticFieldRep(Bt, B0hat);
230
+        EllipticB EBR = EllipticFieldRep(Br, B0hat);
203 231
 
204
-//        Vn(ir) = ComputeV0Cell(Bt, Br, volume, 1.0);
232
+        // Compute Mn0
233
+        Vector3r Mn0 = ComputeMn0(phi, B0);
234
+        Real Mn0Abs = Mn0.norm();
235
+
236
+        Real Taup = 0.020; // s
237
+        Real Ip = 10;      // A
238
+
239
+        // Compute the tipping angle
240
+        Real sintheta = std::sin(0.5*GAMMA*Ip*Taup*std::abs(EBT.alpha-EBT.beta));
241
+
242
+        // Compute phase delay, TODO add transmiiter phase and delay time phase!
243
+        Real phase = EBR.zeta+EBT.zeta;
244
+
245
+        return ComputeV0Cell(EBT, EBR, sintheta, phase, Mn0Abs, vol);
246
+    }
247
+
248
+    //--------------------------------------------------------------------------------------
249
+    //       Class:  KernelV0
250
+    //      Method:  ComputeV0Cell
251
+    //--------------------------------------------------------------------------------------
252
+    Complex KernelV0::ComputeV0Cell(const EllipticB& EBT, const EllipticB& EBR,
253
+                const Real& sintheta, const Real& phase, const Real& Mn0Abs,
254
+                const Real& vol) {
255
+
256
+        Vector3r B0hat = {1,0,0};
257
+        Real Larmor = 2500.*2.*PI;
258
+
259
+        // earth response of receiver adjoint field
260
+        Complex ejztr = std::exp(Complex(0, EBR.zeta + EBT.zeta));
261
+
262
+        Complex PhaseTerm = EBR.bhat.dot(EBT.bhat) +
263
+               (B0hat.dot(EBR.bhat.cross(EBT.bhat) ));
264
+        return -vol*Complex(0,Larmor)*Mn0Abs*(EBR.alpha+EBR.beta)*ejztr*sintheta*PhaseTerm;
265
+    }
266
+
267
+    Vector3r KernelV0::ComputeMn0(const Real& Porosity, const Vector3r& B0) {
268
+        Real Temperature = 283; // in K
269
+        Real chi_n = NH2O*((GAMMA*GAMMA*HBAR*HBAR)/(4.*KB*Temperature));
270
+        return chi_n*Porosity*B0;
271
+    }
272
+
273
+    //--------------------------------------------------------------------------------------
274
+    //       Class:  KernelV0
275
+    //      Method:  ComputeV0Cell
276
+    //--------------------------------------------------------------------------------------
277
+    EllipticB KernelV0::EllipticFieldRep (const Vector3cr& B, const Vector3r& B0hat) {
278
+        EllipticB ElipB = EllipticB();
279
+        Vector3cr Bperp = B.array() - B0hat.dot(B)*B0hat.array();
280
+        Real BperpNorm = Bperp.norm();
281
+        Complex Bp2 = Bperp.transpose() * Bperp;
282
+        VectorXcr iB0 = Complex(0,1)*B0hat.cast<Complex>().array();
283
+        ElipB.eizt = std::sqrt(Bp2 / std::abs(Bp2));
284
+        ElipB.alpha = INVSQRT2*std::sqrt(BperpNorm*BperpNorm + std::abs(Bp2));
285
+        ElipB.beta = sgn(std::real(iB0.dot(Bperp.cross(Bperp.conjugate())))) *
286
+                (INVSQRT2)*std::sqrt(std::abs(BperpNorm*BperpNorm-std::abs(Bp2)));
287
+        ElipB.bhat = ((Real)1./ElipB.alpha)*(((Real)1./ElipB.eizt)*Bperp.array()).real().array();
288
+        ElipB.bhatp = B0hat.cross(ElipB.bhat);
289
+        ElipB.zeta = std::real(std::log(ElipB.eizt)/Complex(0,1));
290
+        return ElipB;
205 291
     }
206 292
 
207 293
     //--------------------------------------------------------------------------------------
@@ -233,26 +319,39 @@ namespace Lemma {
233 319
                   step[0], step[1], step[2] ).finished();
234 320
 
235 321
         VectorXcr kvals(8);       // individual kernel vals
236
-        FieldPoints* cpoints = EMEarths[0]->GetFieldPoints();
237
-            cpoints->ClearFields();
322
+        cpoints->ClearFields();
238 323
         for (int ichild=0; ichild<8; ++ichild) {
239 324
             Vector3r cp = pos;    // Eigen complains about combining these
240 325
             cp += posadd.row(ichild);
241 326
             cpoints->SetLocation( ichild, cp );
242 327
         }
243 328
 
244
-        Vector3Xcr Bt;
329
+        Eigen::Matrix<Complex, 3, 8> Ht = Eigen::Matrix<Complex, 3, 8>::Zero();
330
+        Eigen::Matrix<Complex, 3, 8> Hr = Eigen::Matrix<Complex, 3, 8>::Zero();
245 331
         //Eigen::Matrix< Complex, 8, 3 > Bt;
246 332
         for ( auto EMCalc : EMEarths ) {
247 333
             //EMCalc->GetFieldPoints()->ClearFields();
248
-            EMCalc->CalculateWireAntennaFields();
249
-            Bt = EMCalc->GetFieldPoints()->GetHfield(0);
334
+            EMCalc.second->CalculateWireAntennaFields();
335
+            switch (EMCalc.second->GetTxRxMode()) {
336
+                case TX:
337
+                    Ht += EMCalc.second->GetFieldPoints()->GetHfield(0);
338
+                    break;
339
+                case RX:
340
+                    Hr += EMCalc.second->GetFieldPoints()->GetHfield(0);
341
+                    break;
342
+                case TXRX:
343
+                    Ht += EMCalc.second->GetFieldPoints()->GetHfield(0);
344
+                    Hr += EMCalc.second->GetFieldPoints()->GetHfield(0);
345
+                    break;
346
+                default:
347
+                    break;
348
+            }
250 349
         }
251 350
 
252 351
         for (int ichild=0; ichild<8; ++ichild) {
253 352
             Vector3r cp = pos;    // Eigen complains about combining these
254 353
             cp += posadd.row(ichild);
255
-            kvals(ichild) = f(cp, vol, Bt.col(ichild));
354
+            kvals(ichild) = f(cp, vol, Ht.col(ichild), Hr.col(ichild));
256 355
         }
257 356
 
258 357
         Complex ksum = kvals.sum();     // Kernel sum
@@ -304,25 +403,38 @@ namespace Lemma {
304 403
                   step[0], step[1], step[2] ).finished();
305 404
 
306 405
         VectorXcr kvals(8);                     // individual kernel vals
307
-        FieldPoints* cpoints = EMEarths[0]->GetFieldPoints();
308
-            cpoints->ClearFields();
406
+        cpoints->ClearFields();
309 407
         for (int ichild=0; ichild<8; ++ichild) {
310 408
             Vector3r cp = pos;    // Eigen complains about combining these
311 409
             cp += posadd.row(ichild);
312 410
             cpoints->SetLocation( ichild, cp );
313 411
         }
314 412
 
315
-        Vector3Xcr Bt;
413
+        Eigen::Matrix<Complex, 3, 8> Ht = Eigen::Matrix<Complex, 3, 8>::Zero();
414
+        Eigen::Matrix<Complex, 3, 8> Hr = Eigen::Matrix<Complex, 3, 8>::Zero();
316 415
         for ( auto EMCalc : EMEarths ) {
317 416
             //EMCalc->GetFieldPoints()->ClearFields();
318
-            EMCalc->CalculateWireAntennaFields();
319
-            Bt = EMCalc->GetFieldPoints()->GetHfield(0);
417
+            EMCalc.second->CalculateWireAntennaFields();
418
+            switch (EMCalc.second->GetTxRxMode()) {
419
+                case TX:
420
+                    Ht += EMCalc.second->GetFieldPoints()->GetHfield(0);
421
+                    break;
422
+                case RX:
423
+                    Hr += EMCalc.second->GetFieldPoints()->GetHfield(0);
424
+                    break;
425
+                case TXRX:
426
+                    Ht += EMCalc.second->GetFieldPoints()->GetHfield(0);
427
+                    Hr += EMCalc.second->GetFieldPoints()->GetHfield(0);
428
+                    break;
429
+                default:
430
+                    break;
431
+            }
320 432
         }
321 433
 
322 434
         for (int ichild=0; ichild<8; ++ichild) {
323 435
             Vector3r cp = pos; // Eigen complains about combining these
324 436
             cp += posadd.row(ichild);
325
-            kvals(ichild) = f(cp, vol, Bt.col(ichild));
437
+            kvals(ichild) = f(cp, vol, Ht.col(ichild), Hr.col(ichild));
326 438
         }
327 439
 
328 440
         Complex ksum = kvals.sum();     // Kernel sum
@@ -333,10 +445,12 @@ namespace Lemma {
333 445
                 curse->ToChild(ichild);
334 446
                 Vector3r cp = pos; // Eigen complains about combining these
335 447
                 cp += posadd.row(ichild);
336
-                // Testing for position via alternative means
337
-                //Real p[3];
338
-                //GetPosition(curse, p);
339
-                //std::cout << cp[0] << "\t" << p[0] << "\t" << cp[1] << "\t" << p[1] << "\t" << cp[2] << "\t" << p[2] << "\t" <<  vol<< std::endl;
448
+                /* Test for position via alternative means
449
+                Real p[3];
450
+                GetPosition(curse, p);
451
+                std::cout << cp[0] << "\t" << p[0] << "\t" << cp[1] << "\t" << p[1]
452
+                          << "\t" << cp[2] << "\t" << p[2] << "\t" <<  vol<< std::endl;
453
+                */
340 454
                 bool isleaf = EvaluateKids2( size, level+1, cp, kvals(ichild), oct, curse );
341 455
                 if (isleaf) {  // Include result in final integral
342 456
                     LeafDict[curse->GetLeafId()] = kvals(ichild);       // VTK

Laden…
Annuleren
Opslaan