Browse Source

Opalstack -> GitHub sync test

master
Trevor Irons 1 year ago
parent
commit
85d7200fb4
4 changed files with 49 additions and 2 deletions
  1. 1
    1
      README.md
  2. 15
    0
      include/KernelV0.h
  3. 2
    0
      python/pyMerlin.cpp
  4. 31
    1
      src/KernelV0.cpp

+ 1
- 1
README.md View File

@@ -1,4 +1,4 @@
1 1
 ==About
2
-Merlin is a NMR modelling module for Lemma. 
2
+Merlin is a surface NMR modelling module for Lemma. 
3 3
 
4 4
 =Capabilities 

+ 15
- 0
include/KernelV0.h View File

@@ -216,6 +216,20 @@ namespace Lemma {
216 216
         }
217 217
 
218 218
         /**
219
+         * @param[in] dfin is the transmitter offset from Larmor in Hz. Calculated as Txf - Lf
220
+         */
221
+        inline void SetDf( const Real& dfin ) {
222
+            df = dfin;
223
+        }
224
+
225
+        /**
226
+         * @return the pulse offset from the Larmor frequency
227
+         */
228
+        inline Real GetDf ( ) {
229
+            return df;
230
+        }
231
+
232
+        /**
219 233
          * @param[in] value the 1D-EM model used for calculations
220 234
          */
221 235
         inline void SetLayeredEarthEM ( std::shared_ptr< LayeredEarthEM > value ) {
@@ -376,6 +390,7 @@ namespace Lemma {
376 390
         Real                                      Temperature=283.;
377 391
         Real                                      Taup = .020;  // Sec
378 392
         Real                                      Larmor;
393
+        Real                                      df=0;
379 394
 
380 395
         Vector3r                                  Size;
381 396
         Vector3r                                  Origin;

+ 2
- 0
python/pyMerlin.cpp View File

@@ -56,6 +56,7 @@ PYBIND11_MODULE(Merlin, m) {
56 56
             .def("SetPulseDuration", &Lemma::KernelV0::SetPulseDuration, "Sets the duration of the pulse")
57 57
             .def("SetDepthLayerInterfaces", &Lemma::KernelV0::SetDepthLayerInterfaces, "Sets the layer depth interfaces")
58 58
             .def("SetHankelTransformType", &Lemma::KernelV0::SetHankelTransformType, "Sets the Hankel transform type")
59
+            .def("SetDf", &Lemma::KernelV0::SetDf, "Sets the transmitter offset frequncy in Hz, (Txf - Lf)")
59 60
 
60 61
             // accessors
61 62
             .def("GetName", &Lemma::KernelV0::GetName, "Returns the name of the class")
@@ -65,6 +66,7 @@ PYBIND11_MODULE(Merlin, m) {
65 66
             .def("GetInterfaces", &Lemma::KernelV0::GetInterfaces, "Returns the layer interfaces")
66 67
             .def("GetPulseCurrent", &Lemma::KernelV0::GetPulseCurrent, "Returns the pulse current")
67 68
             .def("GetPulseDuration", &Lemma::KernelV0::GetPulseDuration, "Returns the length of the pulse moment")
69
+            .def("GetDf", &Lemma::KernelV0::GetDf, "Returns the transmitter offset in Hz")
68 70
 
69 71
             // operations
70 72
             .def("CalculateK0", &Lemma::KernelV0::CalculateK0, "Calculates an intial amplitude kernel")

+ 31
- 1
src/KernelV0.cpp View File

@@ -218,6 +218,10 @@ namespace Lemma {
218 218
                 EMEarths[tx]->SetHankelTransformMethod(HankelType);
219 219
                 EMEarths[tx]->SetTxRxMode(TX);
220 220
                 TxRx[tx]->SetCurrent(1.);
221
+
222
+                // calculate df TODO, fix for multiple tx frequencies
223
+                df = TxRx[tx]->GetFrequency(0) - Larmor/(2.*PI);
224
+                std::cout << "df=" << df << std::endl;
221 225
         }
222 226
         for (auto rx : Rx) {
223 227
             if (EMEarths.count(rx)) {
@@ -482,9 +486,35 @@ namespace Lemma {
482 486
         // Calcuate vector of all responses
483 487
         VectorXcr F = VectorXcr::Zero( PulseI.size() );
484 488
         for (int iq=0; iq<PulseI.size(); ++iq) {
485
-            // Compute the tipping angle
489
+
490
+            /////////////////////////////////////////////////////////////////////////////
491
+            // Compute the tipping angle for on-resonance
492
+            // Weichman formulation
493
+            /*
486 494
             Real sintheta = std::sin(0.5*GAMMA*PulseI(iq)*Taup*(EBT.alpha-EBT.beta));
487 495
             F(iq) = -volume*Complex(0,Larmor)*Mn0Abs*(EBR.alpha+EBR.beta)*ejztr*sintheta*PhaseTerm;
496
+            */
497
+
498
+            /////////////////////////////////////////////////////////////////////////////
499
+            // compute tipping ange for off-resonance, from MRSMatlab (Mueller, et. al)
500
+            // but based on seperate works by Grombacher and Walbrecher.
501
+            //theta    = atan2(0.5*gamma*pm_vec(n)/taup*(Bcomps.alpha - Bcomps.beta),(2*pi*df));
502
+            //flip_eff = sqrt((0.5*gamma*pm_vec(n)*(Bcomps.alpha - Bcomps.beta)).^2 + ...
503
+            //            (2*pi*df*taup).^2 );
504
+            //m     = sin(flip_eff) .* sin(theta) + ...
505
+            //    1i*(-1)*sin(theta).*cos(theta) .* (cos(flip_eff) - 1);
506
+            //kern = gamma * earth.erdt^2 * 3.29e-3 * Px .* Bcomps.e_zeta.^2 .* ...
507
+            //            (Bcomps.alpha + Bcomps.beta) .* m;
508
+            //K(n,:) = sum(sum(kern.*dh*dz));
509
+            // TODO, benchmark calls to pow below...modern compilers should optimize this
510
+            // Real df = 25;  // Hz? df is a class data member
511
+            Real theta = std::atan2( 0.5*GAMMA*PulseI(iq)*(EBT.alpha-EBT.beta), 2*PI*df );
512
+            Real flip_eff = std::sqrt( std::pow(0.5*GAMMA*PulseI(iq)*Taup*(EBT.alpha-EBT.beta),2) +
513
+                                       std::pow(2*PI*df*Taup,2));
514
+            Complex m = std::sin(flip_eff)*std::sin(theta) +
515
+                Complex(0,-1)*std::sin(theta)*std::cos(theta) * (std::cos(flip_eff) - 1.);
516
+
517
+            F(iq) = -volume*Complex(0,Larmor)*Mn0Abs*(EBR.alpha+EBR.beta)*ejztr*m*PhaseTerm;
488 518
         }
489 519
         return F;
490 520
     }

Loading…
Cancel
Save