Browse Source

Added a templated class for coil interferences

master
Trevor Irons 7 years ago
parent
commit
e4d6a682b1

+ 5
- 0
examples/CMakeLists.txt View File

@@ -4,13 +4,18 @@ target_link_libraries(  KernelV0  "lemmacore" "fdem1d" "merlin")
4 4
 add_executable( Coupling Coupling.cpp  )
5 5
 target_link_libraries(  Coupling  "lemmacore" "fdem1d" "merlin")
6 6
 
7
+add_executable( Interference Interference.cpp  )
8
+target_link_libraries(  Interference  "lemmacore" "fdem1d" "merlin")
9
+
7 10
 # Linking
8 11
 if ( LEMMA_VTK6_SUPPORT OR LEMMA_VTK7_SUPPORT ) 
9 12
 	target_link_libraries( KernelV0 ${VTK_LIBRARIES})
10 13
 	target_link_libraries( Coupling ${VTK_LIBRARIES})
14
+	target_link_libraries( Interference ${VTK_LIBRARIES})
11 15
 endif()
12 16
 
13 17
 INSTALL_TARGETS( "/share/Merlin/"
14 18
 	KernelV0
15 19
 	Coupling
20
+	Interference
16 21
 )

+ 6
- 6
examples/Coupling.cpp View File

@@ -38,8 +38,8 @@ int main(int argc, char** argv) {
38 38
     // RedButtes model, also how you can generate your own files
39 39
 	auto earth = LayeredEarthEM::NewSP();
40 40
 		earth->SetNumberOfLayers(3);
41
-		//earth->SetLayerConductivity( (VectorXcr(3) << Complex(0.,0), Complex(1./50.,0), Complex(1./100.)).finished() );
42
-		earth->SetLayerConductivity( (VectorXcr(3) << Complex(0.,0), Complex(1./7.,0), Complex(1./100.)).finished() );
41
+		earth->SetLayerConductivity( (VectorXcr(3) << Complex(0.,0), Complex(1./50.,0), Complex(1./100.)).finished() );
42
+		//earth->SetLayerConductivity( (VectorXcr(3) << Complex(0.,0), Complex(1./7.,0), Complex(1./100.)).finished() );
43 43
 		earth->SetLayerThickness( (VectorXr(1) << 10).finished() );
44 44
         // Set mag field info
45 45
         // From NOAA, Laramie WY, June 9 2016, aligned with mag. north
@@ -54,18 +54,18 @@ int main(int argc, char** argv) {
54 54
     auto Tx1 = CircularLoop(21, 15, 50, 50, Larmor);
55 55
     auto Tx2 = CircularLoop(21, 15, 50, 50, Larmor); // initially coincident
56 56
 
57
-    auto Kern = Coupling::NewSP();
57
+    auto Kern = LoopInteractions<COUPLING>::NewSP();
58 58
         Kern->PushCoil( "Coil 1", Tx1 );
59 59
         Kern->PushCoil( "Coil 2", Tx2 );
60 60
         Kern->SetLayeredEarthEM( earth );
61 61
 
62
-        Kern->SetIntegrationSize( (Vector3r() << 50,100,20).finished() );
62
+        Kern->SetIntegrationSize( (Vector3r() << 50,200,20).finished() );
63 63
         Kern->SetIntegrationOrigin( (Vector3r() << 0,0,0.01).finished() );
64
-        Kern->SetTolerance( 1e-3 ); // 1e-12
64
+        Kern->SetTolerance( 1e-12 ); // 1e-12
65 65
 
66 66
     std::vector<std::string> tx = {std::string("Coil 1")};//,std::string("Coil 2")};
67 67
     std::vector<std::string> rx = {std::string("Coil 2")};
68
-    VectorXr Offsets = VectorXr::LinSpaced(6, 15.00, 23.0); // nbins, low, high
68
+    VectorXr Offsets = VectorXr::LinSpaced(30, 0.00, 45.0); // nbins, low, high
69 69
 
70 70
     auto outfile = std::ofstream("coupling.dat");
71 71
     for (int ii=0; ii< Offsets.size(); ++ii) {

+ 117
- 0
examples/Interference.cpp View File

@@ -0,0 +1,117 @@
1
+/* This file is part of Lemma, a geophysical modelling and inversion API.
2
+ * More information is available at http://lemmasoftware.org
3
+ */
4
+
5
+/* This Source Code Form is subject to the terms of the Mozilla Public
6
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
7
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
+ */
9
+
10
+/**
11
+ * @file
12
+ * @date      11/11/2016 02:44:37 PM
13
+ * @version   $Id$
14
+ * @author    Trevor Irons (ti)
15
+ * @email     tirons@egi.utah.edu
16
+ * @copyright Copyright (c) 2016, University of Utah
17
+ * @copyright Copyright (c) 2016, Lemma Software, LLC
18
+ */
19
+
20
+#include <Merlin>
21
+using namespace Lemma;
22
+
23
+static constexpr Real GAMMA = 2.67518e8;                  // MKS units
24
+
25
+std::shared_ptr<PolygonalWireAntenna> CircularLoop ( int nd, Real radius, Real Offsetx, Real Offsety, Real wL ) ;
26
+void MoveLoop( std::shared_ptr<PolygonalWireAntenna> Loop, int nd, Real Radius, Real Offsetx, Real Offsety, Real wL );
27
+
28
+int main(int argc, char** argv) {
29
+    /*
30
+    if ( argc < 2 ) {
31
+        std::cout << "Calculates the coupling between two sNMR loops at the Larmor frequency. Usage\n"
32
+                  << "\t./Coupling   EarthModel.yaml" << std::endl;
33
+        exit(0);
34
+    }
35
+    //Real offset = atof(argv[1]);
36
+    auto earth = LayeredEarthEM::DeSerialize( YAML::LoadFile(argv[1]) );
37
+    */
38
+    // RedButtes model, also how you can generate your own files
39
+	auto earth = LayeredEarthEM::NewSP();
40
+		earth->SetNumberOfLayers(3);
41
+		earth->SetLayerConductivity( (VectorXcr(3) << Complex(0.,0), Complex(1./50.,0), Complex(1./100.)).finished() );
42
+		earth->SetLayerThickness( (VectorXr(1) << 10).finished() );
43
+        // Set mag field info
44
+        // From NOAA, Laramie WY, June 9 2016, aligned with mag. north
45
+        earth->SetMagneticFieldIncDecMag( 67, 0, 52750, NANOTESLA );
46
+//     auto sig = std::ofstream("SigmaModel.yaml");
47
+//         sig << *earth << std::endl;
48
+//         sig.close();
49
+
50
+    Real Larmor = earth->GetMagneticFieldMagnitude()*GAMMA/(2*PI);
51
+
52
+    // Transmitter loops
53
+    auto Tx1 = CircularLoop(21, 15, 50, 50, Larmor);
54
+    auto Tx2 = CircularLoop(21, 15, 50, 50, Larmor); // initially coincident
55
+
56
+    auto Kern = LoopInteractions<INTERFERENCE>::NewSP();
57
+        Kern->PushCoil( "Coil 1", Tx1 );
58
+        Kern->PushCoil( "Coil 2", Tx2 );
59
+        Kern->SetLayeredEarthEM( earth );
60
+
61
+        Kern->SetIntegrationSize( (Vector3r()   << 50,200,50).finished() );
62
+        Kern->SetIntegrationOrigin( (Vector3r() << 0,0,5.0).finished() );
63
+        Kern->SetTolerance( 1e-3 ); // 1e-12
64
+
65
+    std::vector<std::string> tx = {std::string("Coil 1")};//,std::string("Coil 2")};
66
+    std::vector<std::string> rx = {std::string("Coil 2")};
67
+    VectorXr Offsets = VectorXr::LinSpaced(61, 0.00, 60.0); // nbins, low, high
68
+
69
+    auto outfile = std::ofstream("interference.dat");
70
+    for (int ii=0; ii< Offsets.size(); ++ii) {
71
+        MoveLoop(Tx2, 21, 15, 50, 50 + Offsets(ii), Larmor);
72
+        #ifdef LEMMAUSEVTK
73
+        Complex coupling = Kern->Calculate( tx, rx, true );
74
+        #else
75
+        Complex coupling = Kern->Calculate( tx, rx, false );
76
+        #endif
77
+        std::cout << "coupling " << coupling << std::endl;
78
+        outfile << Offsets(ii) << "\t" <<  std::real(coupling) << "\t" << std::imag(coupling) << std::endl;
79
+    }
80
+    outfile.close();
81
+}
82
+
83
+std::shared_ptr<Lemma::PolygonalWireAntenna> CircularLoop ( int nd, Real Radius, Real Offsetx, Real Offsety, Real wL ) {
84
+
85
+    auto Tx1 = Lemma::PolygonalWireAntenna::NewSP();
86
+         Tx1->SetNumberOfPoints(nd);
87
+
88
+    VectorXr range = VectorXr::LinSpaced(nd, 0, 2*PI);
89
+    int ii;
90
+    for (ii=0; ii<nd; ++ii) {
91
+        Tx1->SetPoint(ii, Vector3r(Offsetx+Radius*std::cos(range(ii)), Offsety+Radius*std::sin(range(ii)),  -1e-3));
92
+    }
93
+
94
+    Tx1->SetCurrent(1.);
95
+    Tx1->SetNumberOfTurns(1);
96
+    Tx1->SetNumberOfFrequencies(1);
97
+    Tx1->SetFrequency(0,wL);
98
+
99
+    return Tx1;
100
+}
101
+
102
+void MoveLoop( std::shared_ptr<Lemma::PolygonalWireAntenna> Tx1, int nd, Real Radius, Real Offsetx, Real Offsety, Real wL ) {
103
+
104
+    Tx1->SetNumberOfPoints(nd);
105
+
106
+    VectorXr range = VectorXr::LinSpaced(nd, 0, 2*PI);
107
+    int ii;
108
+    for (ii=0; ii<nd; ++ii) {
109
+        Tx1->SetPoint(ii, Vector3r(Offsetx+Radius*std::cos(range(ii)), Offsety+Radius*std::sin(range(ii)),  -1e-3));
110
+    }
111
+
112
+    Tx1->SetCurrent(1.);
113
+    Tx1->SetNumberOfTurns(1);
114
+    Tx1->SetNumberOfFrequencies(1);
115
+    Tx1->SetFrequency(0,wL);
116
+
117
+}

+ 645
- 0
include/LoopInteractions.h View File

@@ -0,0 +1,645 @@
1
+/* This file is part of Lemma, a geophysical modelling and inversion API.
2
+ * More information is available at http://lemmasoftware.org
3
+ */
4
+
5
+/* This Source Code Form is subject to the terms of the Mozilla Public
6
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
7
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
+ */
9
+
10
+/**
11
+ * @file
12
+ * @date      11/11/2016 01:47:34 PM
13
+ * @author    Trevor Irons (ti)
14
+ * @email     tirons@egi.utah.edu
15
+ * @copyright Copyright (c) 2016, University of Utah
16
+ * @copyright Copyright (c) 2016, Lemma Software, LLC
17
+ * @copyright Copyright (c) 2008, Colorado School of Mines
18
+ */
19
+#ifndef  LOOPINTERACTIONS
20
+#define  LOOPINTERACTIONS
21
+
22
+#pragma once
23
+#include "LemmaObject.h"
24
+#include "LayeredEarthEM.h"
25
+#include "PolygonalWireAntenna.h"
26
+#include "EMEarth1D.h"
27
+#include "FieldPoints.h"
28
+
29
+#ifdef LEMMAUSEVTK
30
+#include "vtkHyperOctree.h"
31
+#include "vtkHyperOctreeCursor.h"
32
+#include "vtkXMLHyperOctreeWriter.h"
33
+#include "vtkDoubleArray.h"
34
+#endif
35
+
36
+namespace Lemma {
37
+
38
+    enum INTERACTION {COUPLING, INTERFERENCE, PHASE};
39
+    /// convert enums to string saves repeated code useful for YAML serializing
40
+    std::string enum2String(const INTERACTION& type);
41
+
42
+    /**
43
+     * \ingroup Merlin
44
+     * \brief
45
+     * \details
46
+     */
47
+    template< INTERACTION Type  >
48
+    class LoopInteractions : public LemmaObject {
49
+
50
+        friend std::ostream &operator << (std::ostream &stream, const LoopInteractions &ob) {
51
+            stream << ob.Serialize()  << "\n---\n"; // End of doc ---
52
+            return stream;
53
+        }
54
+
55
+        protected:
56
+        /*
57
+         *  This key is used to lock the constructor. It is protected so that inhereted
58
+         *  classes also have the key to contruct their base class.
59
+         */
60
+        struct ctor_key {};
61
+
62
+        public:
63
+
64
+        // ====================  LIFECYCLE     =======================
65
+
66
+        /**
67
+         * Default constructor.
68
+         * @note This method is locked, and cannot be called directly.
69
+         *       The reason that the method is public is to enable the use
70
+         *       of make_shared whilst enforcing the use of shared_ptr,
71
+         *       in c++-17, this curiosity may be resolved.
72
+         * @see LoopInteractions::NewSP
73
+         */
74
+        explicit LoopInteractions ( const ctor_key& ) : LemmaObject () { }
75
+
76
+        /**
77
+         * DeSerializing constructor.
78
+         * @note This method is locked, and cannot be called directly.
79
+         *       The reason that the method is public is to enable the use
80
+         *       of make_shared whilst enforcing the use of shared_ptr,
81
+         *       in c++-17, this curiosity may be resolved.
82
+         * @see LoopInteractions::DeSerialize
83
+         */
84
+        LoopInteractions ( const YAML::Node& node, const ctor_key& ) : LemmaObject(node) { }
85
+
86
+        /**
87
+         * Default destructor.
88
+         * @note This method should never be called due to the mandated
89
+         *       use of smart pointers. It is necessary to keep the method
90
+         *       public in order to allow for the use of the more efficient
91
+         *       make_shared constructor.
92
+         */
93
+        virtual ~LoopInteractions () { }
94
+
95
+        /**
96
+         *  Uses YAML to serialize this object.
97
+         *  @return a YAML::Node
98
+         *  @see LoopInteractions::DeSerialize
99
+         */
100
+        virtual YAML::Node Serialize() const {
101
+            YAML::Node node = LemmaObject::Serialize();
102
+            node.SetTag( GetName() );
103
+
104
+            // Coils Transmitters & Receivers
105
+            for ( auto txm : TxRx) {
106
+                node[txm.first] = txm.second->Serialize();
107
+            }
108
+            // LayeredEarthEM
109
+            node["SigmaModel"] = SigmaModel->Serialize();
110
+
111
+            node["tol"] = tol;
112
+            node["minLevel"] = minLevel;
113
+            node["maxLevel"] = maxLevel;
114
+
115
+            return node;
116
+        }
117
+
118
+        /*
119
+         *  Factory method for generating concrete class.
120
+         *  @return a std::shared_ptr of type LoopInteractions
121
+         */
122
+        static std::shared_ptr< LoopInteractions > NewSP() {
123
+            return std::make_shared< LoopInteractions >( ctor_key() );
124
+        }
125
+
126
+        /**
127
+         *   Constructs an LoopInteractions object from a YAML::Node.
128
+         *   @see LoopInteractions::Serialize
129
+         */
130
+        static std::shared_ptr<LoopInteractions> DeSerialize(const YAML::Node& node) {
131
+            if (node.Tag() !=  "LoopInteractions" ) {
132
+                throw  DeSerializeTypeMismatch( "LoopInteractions", node.Tag());
133
+            }
134
+            return std::make_shared< LoopInteractions > ( node, ctor_key() );
135
+        }		// -----  end of method LoopInteractions::DeSerialize  -----
136
+
137
+        // ====================  OPERATORS     =======================
138
+
139
+        // ====================  OPERATIONS    =======================
140
+
141
+        /**
142
+         * @return std::shared_ptr<LayeredEarthEM>
143
+         */
144
+        inline std::shared_ptr<LayeredEarthEM> GetSigmaModel (  ) {
145
+            return SigmaModel;
146
+        }		// -----  end of method LoopInteractions::get_SigmaModel  -----
147
+
148
+        /**
149
+         * @param[in] value the 1D-EM model used for calculations
150
+         */
151
+        inline void SetLayeredEarthEM ( std::shared_ptr< LayeredEarthEM > value ) {
152
+            SigmaModel	= value;
153
+            return ;
154
+        }		// -----  end of method LoopInteractions::set_SigmaModel  -----
155
+
156
+        /**
157
+         *
158
+         */
159
+        inline void SetIntegrationSize ( const Vector3r& size ) {
160
+            Size = size;
161
+            return ;
162
+        }		// -----  end of method LoopInteractions::SetIntegrationSize  -----
163
+
164
+        /**
165
+         *
166
+         */
167
+        inline void SetIntegrationOrigin ( const Vector3r& origin ) {
168
+            Origin = origin;
169
+            return ;
170
+        }		// -----  end of method LoopInteractions::SetIntegrationOrigin  -----
171
+
172
+        /**
173
+         *   Assign transmiter coils
174
+         */
175
+        inline void PushCoil( const std::string& label, std::shared_ptr<PolygonalWireAntenna> ant ) {
176
+            TxRx[label] = ant;
177
+        }
178
+
179
+        /**
180
+         *   Calculates a single imaging kernel, however, phased arrays are supported
181
+         *   so that more than one transmitter and/or receiver can be specified.
182
+         *   @param[in] tx is the list of transmitters to use for a kernel, use the same labels as
183
+         *              used in PushCoil.
184
+         *   @param[in] rx is the list of receivers to use for a kernel, use the same labels as
185
+         *              used in PushCoil. @see PushCoil
186
+         *   @param[in] vtkOutput generates a VTK hyperoctree file as well, useful for visualization.
187
+         *              requires compilation of Lemma with VTK.
188
+         */
189
+        Complex Calculate (const std::vector< std::string >& tx, const std::vector< std::string >& rx,
190
+                bool vtkOutput=false );
191
+
192
+        /**
193
+         *  Sets the tolerance to use for making the adaptive mesh
194
+         *
195
+         */
196
+        inline void SetTolerance(const Real& ttol) {
197
+            tol = ttol;
198
+        }
199
+
200
+        inline void SetPulseDuration(const Real& taup) {
201
+            Taup = taup;
202
+        }
203
+
204
+        // ====================  INQUIRY       =======================
205
+        /**
206
+         *  Returns the name of the underlying class, similiar to Python's type
207
+         *  @return string of class name
208
+         */
209
+        virtual inline std::string GetName() const {
210
+            return CName;
211
+        }
212
+
213
+        protected:
214
+
215
+        // ====================  LIFECYCLE     =======================
216
+
217
+        /** Copy is disabled */
218
+        LoopInteractions( const LoopInteractions& ) = delete;
219
+
220
+        private:
221
+
222
+        /**
223
+         *  Returns the kernel value for an input prism
224
+         */
225
+        virtual Complex f( const Vector3r& r, const Real& volume , const Vector3cr& Ht, const Vector3cr& Hr);
226
+
227
+        void IntegrateOnOctreeGrid( bool vtkOutput=false );
228
+
229
+        /**
230
+         *  Recursive call to integrate a function on an adaptive Octree Grid.
231
+         *  For efficiency's sake the octree grid is not stored, as only the
232
+         *  integral (sum) is of interest. The logic for grid refinement is based
233
+         *  on an Octree representation of the domain. If an Octree representation
234
+         *  of the kernel is desired, call alternative version @see EvaluateKids2
235
+         *  @param[in] size gives the domain size, in  metres
236
+         *  @param[in] level gives the current level of the octree grid, call with 0 initially
237
+         *  @param[in] cpos is the centre position of the parent cuboid
238
+         */
239
+        void EvaluateKids(  const Vector3r& size, const int& level, const Vector3r& cpos,
240
+                            const Complex& parentVal );
241
+
242
+        #ifdef LEMMAUSEVTK
243
+        /**
244
+         *  Same functionality as @see EvaluateKids, but includes generation of a VTK
245
+         *  HyperOctree, which is useful for visualization.
246
+         */
247
+        void EvaluateKids2(  const Vector3r& size, const int& level, const Vector3r& cpos,
248
+                            const Complex& parentVal, vtkHyperOctree* octree, vtkHyperOctreeCursor* curse );
249
+
250
+        void GetPosition( vtkHyperOctreeCursor* Cursor, Real* p );
251
+        #endif
252
+
253
+        // ====================  DATA MEMBERS  =========================
254
+
255
+        int                                       ilay;
256
+        int                                       nleaves;
257
+        int                                       minLevel=4;
258
+        int                                       maxLevel=8;
259
+
260
+        Real                                      VOLSUM;
261
+        Real                                      tol=1e-11;
262
+        Real                                      Taup = .020;  // Sec
263
+
264
+        Complex                                   SUM;
265
+
266
+        Vector3r                                  Size;
267
+        Vector3r                                  Origin;
268
+
269
+        std::shared_ptr< LayeredEarthEM >         SigmaModel = nullptr;
270
+        std::shared_ptr< FieldPoints >            cpoints;
271
+
272
+        std::map< std::string , std::shared_ptr< PolygonalWireAntenna > >  TxRx;
273
+        std::map< std::string , std::shared_ptr< EMEarth1D > >             EMEarths;
274
+
275
+        #ifdef LEMMAUSEVTK
276
+        std::map< int, Complex  >                 LeafDict;
277
+        std::map< int, int     >                  LeafDictIdx;
278
+        std::map< int, Real     >                 LeafDictErr;
279
+        #endif
280
+
281
+        /** ASCII string representation of the class name */
282
+        static constexpr auto CName = "LoopInteractions";
283
+
284
+    }; // -----  end of class  LoopInteractions  -----
285
+
286
+    ///////////////////////////////////////////////////////////////
287
+    // Implimentation of non specialized args -- templated class //
288
+    ///////////////////////////////////////////////////////////////
289
+
290
+    // forward declare specs
291
+
292
+    template <>
293
+    Complex LoopInteractions<COUPLING>::f( const Vector3r& r, const Real& volume, const Vector3cr& Ht, const Vector3cr& Hr );
294
+
295
+    template <>
296
+    Complex LoopInteractions<INTERFERENCE>::f( const Vector3r& r, const Real& volume, const Vector3cr& Ht, const Vector3cr& Hr );
297
+
298
+    template <>
299
+    Complex LoopInteractions<PHASE>::f( const Vector3r& r, const Real& volume, const Vector3cr& Ht, const Vector3cr& Hr );
300
+
301
+    //--------------------------------------------------------------------------------------
302
+    //       Class:  LoopInteractions
303
+    //      Method:  DeSerialize
304
+    //--------------------------------------------------------------------------------------
305
+    template< INTERACTION Type  >
306
+    Complex LoopInteractions<Type>::Calculate (const std::vector< std::string>& Tx, const std::vector<std::string >& Rx,
307
+            bool vtkOutput ) {
308
+
309
+        static bool first = false; // a little hackish
310
+        if (!first) {
311
+            // All EM calculations will share same field points
312
+            cpoints = FieldPoints::NewSP();
313
+                cpoints->SetNumberOfPoints(8);
314
+        }
315
+        first = true;
316
+
317
+        for (auto tx : Tx) {
318
+            // Set up EMEarth
319
+            EMEarths[tx] = EMEarth1D::NewSP();
320
+                EMEarths[tx]->AttachWireAntenna(TxRx[tx]);
321
+                EMEarths[tx]->AttachLayeredEarthEM(SigmaModel);
322
+                EMEarths[tx]->AttachFieldPoints( cpoints );
323
+         		EMEarths[tx]->SetFieldsToCalculate(H);
324
+                // TODO query for method, altough with flat antennae, this is fastest
325
+                EMEarths[tx]->SetHankelTransformMethod(ANDERSON801);
326
+                EMEarths[tx]->SetTxRxMode(TX);
327
+                TxRx[tx]->SetCurrent(1.);
328
+        }
329
+        for (auto rx : Rx) {
330
+            if (EMEarths.count(rx)) {
331
+                EMEarths[rx]->SetTxRxMode(TXRX);
332
+            } else {
333
+                EMEarths[rx] = EMEarth1D::NewSP();
334
+                    EMEarths[rx]->AttachWireAntenna(TxRx[rx]);
335
+                    EMEarths[rx]->AttachLayeredEarthEM(SigmaModel);
336
+                    EMEarths[rx]->AttachFieldPoints( cpoints );
337
+         		    EMEarths[rx]->SetFieldsToCalculate(H);
338
+                    // TODO query for method, altough with flat antennae, this is fastest
339
+                    EMEarths[rx]->SetHankelTransformMethod(ANDERSON801);
340
+                    EMEarths[rx]->SetTxRxMode(RX);
341
+                    TxRx[rx]->SetCurrent(1.);
342
+            }
343
+        }
344
+        SUM = 0;
345
+        IntegrateOnOctreeGrid( vtkOutput );
346
+        std::cout << "\nFinished KERNEL\n";
347
+        EMEarths.clear();
348
+        return SUM;
349
+    }
350
+
351
+
352
+    //--------------------------------------------------------------------------------------
353
+    //       Class:  LoopInteractions
354
+    //      Method:  IntegrateOnOctreeGrid
355
+    //--------------------------------------------------------------------------------------
356
+    template< INTERACTION Type  >
357
+    void LoopInteractions<Type>::IntegrateOnOctreeGrid( bool vtkOutput ) {
358
+
359
+        static int count = 0;
360
+
361
+        Vector3r cpos = Origin + Size/2.;
362
+
363
+        VOLSUM = 0;
364
+        nleaves = 0;
365
+        if (!vtkOutput) {
366
+            EvaluateKids( Size, 0, cpos, Complex(100.));
367
+        } else {
368
+        #ifdef LEMMAUSEVTK
369
+            vtkHyperOctree* oct = vtkHyperOctree::New();
370
+                oct->SetDimension(3);
371
+                oct->SetOrigin( Origin(0), Origin(1), Origin(2) );
372
+                oct->SetSize( Size(0), Size(1), Size(2) );
373
+            vtkHyperOctreeCursor* curse = oct->NewCellCursor();
374
+                curse->ToRoot();
375
+            EvaluateKids2( Size, 0, cpos, Complex(100.0), oct, curse );
376
+
377
+            // Fill in leaf data
378
+            vtkDoubleArray* kr = vtkDoubleArray::New();
379
+                kr->SetNumberOfComponents(1);
380
+                kr->SetName("Re($\\sum$)");
381
+                kr->SetNumberOfTuples( oct->GetNumberOfLeaves() );
382
+            vtkDoubleArray* ki = vtkDoubleArray::New();
383
+                ki->SetNumberOfComponents(1);
384
+                ki->SetName("Im($\\sum$)");
385
+                ki->SetNumberOfTuples( oct->GetNumberOfLeaves() );
386
+            vtkDoubleArray* km = vtkDoubleArray::New();
387
+                km->SetNumberOfComponents(1);
388
+                km->SetName("mod($\\sum$)");
389
+                km->SetNumberOfTuples( oct->GetNumberOfLeaves() );
390
+            vtkIntArray* kid = vtkIntArray::New();
391
+                kid->SetNumberOfComponents(1);
392
+                kid->SetName("ID");
393
+                kid->SetNumberOfTuples( oct->GetNumberOfLeaves() );
394
+            vtkIntArray* kerr = vtkIntArray::New();
395
+                kerr->SetNumberOfComponents(1);
396
+                kerr->SetName("nleaf");
397
+
398
+            //Real LeafVol(0);
399
+            for (auto leaf : LeafDict) {
400
+                kr->InsertTuple1( leaf.first, std::real(leaf.second) );
401
+                ki->InsertTuple1( leaf.first, std::imag(leaf.second) );
402
+                km->InsertTuple1( leaf.first, std::abs(leaf.second) );
403
+                kid->InsertTuple1( leaf.first, leaf.first );
404
+                //LeafVol += std::real(leaf.second);
405
+            }
406
+            //std::cout << "\n\nLeafVol=" << LeafVol << std::endl;
407
+
408
+            for (auto leaf : LeafDictIdx) {
409
+                kerr->InsertTuple1( leaf.first, leaf.second );
410
+            }
411
+
412
+            auto kri = oct->GetLeafData()->AddArray(kr);
413
+            auto kii = oct->GetLeafData()->AddArray(ki);
414
+            auto kmi = oct->GetLeafData()->AddArray(km);
415
+            auto kidi = oct->GetLeafData()->AddArray(kid);
416
+            auto keri = oct->GetLeafData()->AddArray(kerr);
417
+
418
+            auto write = vtkXMLHyperOctreeWriter::New();
419
+                //write.SetDataModeToAscii()
420
+                write->SetInputData(oct);
421
+                std::string fname = std::string("octree-") + enum2String(Type) + std::string("-")
422
+                                    + to_string(count) + std::string(".vto");
423
+                write->SetFileName(fname.c_str());
424
+                write->Write();
425
+                write->Delete();
426
+
427
+            oct->GetLeafData()->RemoveArray( kri );
428
+            oct->GetLeafData()->RemoveArray( kii );
429
+            oct->GetLeafData()->RemoveArray( kmi );
430
+            oct->GetLeafData()->RemoveArray( kidi );
431
+            oct->GetLeafData()->RemoveArray( keri );
432
+
433
+            kerr->Delete();
434
+            kid->Delete();
435
+            kr->Delete();
436
+            ki->Delete();
437
+            km->Delete();
438
+
439
+            curse->Delete();
440
+            oct->Delete();
441
+        #else
442
+            throw std::runtime_error("IntegrateOnOctreeGrid with vtkOutput requires Lemma with VTK support");
443
+        #endif
444
+
445
+        }
446
+        std::cout << "\nVOLSUM=" << VOLSUM << "\tActual=" <<  Size(0)*Size(1)*Size(2)
447
+                  << "\tDifference=" << VOLSUM - (Size(0)*Size(1)*Size(2)) <<  std::endl;
448
+        count += 1;
449
+    }
450
+
451
+    //--------------------------------------------------------------------------------------
452
+    //       Class:  LoopInteractions
453
+    //      Method:  EvaluateKids
454
+    //--------------------------------------------------------------------------------------
455
+    template< INTERACTION Type  >
456
+    void LoopInteractions<Type>::EvaluateKids( const Vector3r& size, const int& level, const Vector3r& cpos,
457
+        const Complex& parentVal ) {
458
+
459
+        std::cout << "\r" << (int)(1e2*VOLSUM/(Size[0]*Size[1]*Size[2])) << "\t" << nleaves;
460
+        std::cout.flush();
461
+
462
+        // Next level step, interested in one level below
463
+        // bitshift requires one extra, faster than, and equivalent to std::pow(2, level+1)
464
+        Vector3r step  = size.array() / (Real)(1 << (level+1) );
465
+        Real vol = (step(0)*step(1)*step(2));     // volume of each child
466
+
467
+        Vector3r pos =  cpos - step/2.;
468
+        Eigen::Matrix<Real, 8, 3> posadd = (Eigen::Matrix<Real, 8, 3>() <<
469
+                        0,       0,       0,
470
+                  step[0],       0,       0,
471
+                        0, step[1],       0,
472
+                  step[0], step[1],       0,
473
+                        0,       0, step[2],
474
+                  step[0],       0, step[2],
475
+                        0, step[1], step[2],
476
+                  step[0], step[1], step[2] ).finished();
477
+
478
+        VectorXcr kvals(8);       // individual kernel vals
479
+        cpoints->ClearFields();
480
+        for (int ichild=0; ichild<8; ++ichild) {
481
+            Vector3r cp = pos;    // Eigen complains about combining these
482
+            cp += posadd.row(ichild);
483
+            cpoints->SetLocation( ichild, cp );
484
+        }
485
+
486
+        Eigen::Matrix<Complex, 3, 8> Ht = Eigen::Matrix<Complex, 3, 8>::Zero();
487
+        Eigen::Matrix<Complex, 3, 8> Hr = Eigen::Matrix<Complex, 3, 8>::Zero();
488
+        for ( auto EMCalc : EMEarths ) {
489
+            EMCalc.second->GetFieldPoints()->ClearFields();
490
+            EMCalc.second->CalculateWireAntennaFields();
491
+            switch (EMCalc.second->GetTxRxMode()) {
492
+                case TX:
493
+                    Ht += EMCalc.second->GetFieldPoints()->GetHfield(0);
494
+                    break;
495
+                case RX:
496
+                    Hr += EMCalc.second->GetFieldPoints()->GetHfield(0);
497
+                    break;
498
+                case TXRX:
499
+                    Ht += EMCalc.second->GetFieldPoints()->GetHfield(0);
500
+                    Hr += EMCalc.second->GetFieldPoints()->GetHfield(0);
501
+                    break;
502
+                default:
503
+                    break;
504
+            }
505
+        }
506
+
507
+        for (int ichild=0; ichild<8; ++ichild) {
508
+            Vector3r cp = pos;    // Eigen complains about combining these
509
+            cp += posadd.row(ichild);
510
+            kvals(ichild) = f(cp, vol, Ht.col(ichild), Hr.col(ichild));
511
+        }
512
+
513
+        Complex ksum = kvals.sum();     // Kernel sum
514
+        // Evaluate whether or not furthur splitting is needed
515
+        if ( (std::abs(ksum-parentVal) > tol && level < maxLevel) || level < minLevel ) {
516
+            // Not a leaf dive further in
517
+            for (int ichild=0; ichild<8; ++ichild) {
518
+                Vector3r cp = pos; // Eigen complains about combining these
519
+                cp += posadd.row(ichild);
520
+                EvaluateKids( size, level+1, cp, kvals(ichild) );
521
+            }
522
+            return; // not leaf
523
+        }
524
+        // implicit else, is a leaf
525
+        SUM += ksum;
526
+        VOLSUM  += 8.*vol;
527
+        nleaves += 1; // could say += 8 just as fairly
528
+        return;     // is leaf
529
+    }
530
+
531
+    #ifdef LEMMAUSEVTK
532
+    //--------------------------------------------------------------------------------------
533
+    //       Class:  LoopInteractions
534
+    //      Method:  EvaluateKids2 -- same as Evaluate Kids, but include VTK octree generation
535
+    //--------------------------------------------------------------------------------------
536
+    template< INTERACTION Type  >
537
+    void LoopInteractions<Type>::EvaluateKids2( const Vector3r& size, const int& level, const Vector3r& cpos,
538
+        const Complex& parentVal, vtkHyperOctree* oct, vtkHyperOctreeCursor* curse) {
539
+
540
+        std::cout << "\r" << (int)(1e2*VOLSUM/(Size[0]*Size[1]*Size[2])) << "\t" << nleaves;
541
+        std::cout.flush();
542
+
543
+        // Next level step, interested in one level below
544
+        // bitshift requires one extra, faster than, and equivalent to std::pow(2, level+1)
545
+        Vector3r step  = size.array() / (Real)(1 << (level+1) );
546
+        Real vol = (step(0)*step(1)*step(2));         // volume of each child
547
+
548
+        Vector3r pos =  cpos - step/2.;
549
+        Eigen::Matrix<Real, 8, 3> posadd = (Eigen::Matrix<Real, 8, 3>() <<
550
+                        0,       0,       0,
551
+                  step[0],       0,       0,
552
+                        0, step[1],       0,
553
+                  step[0], step[1],       0,
554
+                        0,       0, step[2],
555
+                  step[0],       0, step[2],
556
+                        0, step[1], step[2],
557
+                  step[0], step[1], step[2] ).finished();
558
+
559
+        VectorXcr kvals(8);       // individual kernel vals
560
+        cpoints->ClearFields();
561
+        for (int ichild=0; ichild<8; ++ichild) {
562
+            Vector3r cp = pos;    // Eigen complains about combining these
563
+            cp += posadd.row(ichild);
564
+            cpoints->SetLocation( ichild, cp );
565
+        }
566
+
567
+        Eigen::Matrix<Complex, 3, 8> Ht = Eigen::Matrix<Complex, 3, 8>::Zero();
568
+        Eigen::Matrix<Complex, 3, 8> Hr = Eigen::Matrix<Complex, 3, 8>::Zero();
569
+        for ( auto EMCalc : EMEarths ) {
570
+            //EMCalc->GetFieldPoints()->ClearFields();
571
+            EMCalc.second->CalculateWireAntennaFields();
572
+            switch (EMCalc.second->GetTxRxMode()) {
573
+                case TX:
574
+                    Ht += EMCalc.second->GetFieldPoints()->GetHfield(0);
575
+                    break;
576
+                case RX:
577
+                    Hr += EMCalc.second->GetFieldPoints()->GetHfield(0);
578
+                    break;
579
+                case TXRX:
580
+                    Ht += EMCalc.second->GetFieldPoints()->GetHfield(0);
581
+                    Hr += EMCalc.second->GetFieldPoints()->GetHfield(0);
582
+                    break;
583
+                default:
584
+                    break;
585
+            }
586
+        }
587
+
588
+        for (int ichild=0; ichild<8; ++ichild) {
589
+            Vector3r cp = pos;    // Eigen complains about combining these
590
+            cp += posadd.row(ichild);
591
+            kvals(ichild) = f(cp, vol, Ht.col(ichild), Hr.col(ichild));
592
+        }
593
+
594
+        Complex ksum = kvals.sum();     // Kernel sum
595
+        // Evaluate whether or not furthur splitting is needed
596
+        if ( (std::abs(ksum-parentVal) > tol && level < maxLevel) || level < minLevel ) {
597
+            oct->SubdivideLeaf(curse);
598
+            for (int ichild=0; ichild<8; ++ichild) {
599
+                curse->ToChild(ichild);
600
+                Vector3r cp = pos; // Eigen complains about combining these
601
+                cp += posadd.row(ichild);
602
+                /* Test for position via alternative means */
603
+                /*
604
+                Real p[3];
605
+                GetPosition(curse, p);
606
+                if ( (Vector3r(p) - cp).norm() > 1e-8 ) {
607
+                    std::cout << "ERROR @ nleaves" << nleaves << "\n" << cp[0] << "\t" << p[0] << "\t" << cp[1] << "\t" << p[1]
608
+                              << "\t" << cp[2] << "\t" << p[2] << "\t" << vol<< std::endl;
609
+                    throw std::runtime_error("doom");
610
+                }
611
+                */
612
+                /* End of position test */
613
+                EvaluateKids2( size, level+1, cp, kvals(ichild), oct, curse );
614
+                curse->ToParent();
615
+            }
616
+            return;  // not a leaf
617
+        }
618
+        LeafDict[curse->GetLeafId()] = ksum/(8.*vol);
619
+        LeafDictIdx[curse->GetLeafId()] = nleaves;
620
+        SUM += ksum;
621
+        VOLSUM += 8*vol;
622
+        nleaves += 1;
623
+        return;     // is a leaf
624
+    }
625
+
626
+    //--------------------------------------------------------------------------------------
627
+    //       Class:  LoopInteractions
628
+    //      Method:  GetPosition
629
+    //--------------------------------------------------------------------------------------
630
+    template< INTERACTION Type  >
631
+    void LoopInteractions<Type>::GetPosition( vtkHyperOctreeCursor* Cursor, Real* p ) {
632
+        Real ratio=1.0/(1<<(Cursor->GetCurrentLevel()));
633
+        //step  = ((Size).array() / std::pow(2.,Cursor->GetCurrentLevel()));
634
+        p[0]=(Cursor->GetIndex(0)+.5)*ratio*this->Size[0]+this->Origin[0] ;//+ .5*step[0];
635
+        p[1]=(Cursor->GetIndex(1)+.5)*ratio*this->Size[1]+this->Origin[1] ;//+ .5*step[1];
636
+        p[2]=(Cursor->GetIndex(2)+.5)*ratio*this->Size[2]+this->Origin[2] ;//+ .5*step[2];
637
+    }
638
+    #endif
639
+
640
+}  // -----  end of namespace Lemma ----
641
+
642
+/* vim: set tabstop=4 expandtab */
643
+/* vim: set filetype=cpp */
644
+
645
+#endif   // ----- #ifndef LOOPINTERACTIONS  -----

+ 1
- 0
include/Merlin View File

@@ -1,5 +1,6 @@
1 1
 #include "KernelV0.h"
2 2
 #include "Coupling.h"
3
+#include "LoopInteractions.h"
3 4
 
4 5
 /* vim: set tabstop=4 expandtab: */
5 6
 /* vim: set filetype=cpp: */

+ 1
- 0
src/CMakeLists.txt View File

@@ -1,5 +1,6 @@
1 1
 set (MERLINSOURCE
2 2
 	${CMAKE_CURRENT_SOURCE_DIR}/KernelV0.cpp
3 3
 	${CMAKE_CURRENT_SOURCE_DIR}/Coupling.cpp
4
+	${CMAKE_CURRENT_SOURCE_DIR}/LoopInteractions.cpp
4 5
 	PARENT_SCOPE
5 6
 )

+ 62
- 0
src/LoopInteractions.cpp View File

@@ -0,0 +1,62 @@
1
+/* This file is part of Lemma, a geophysical modelling and inversion API.
2
+ * More information is available at http://lemmasoftware.org
3
+ */
4
+
5
+/* This Source Code Form is subject to the terms of the Mozilla Public
6
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
7
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
+ */
9
+
10
+/**
11
+ * @file
12
+ * @date      11/11/2016 01:47:25 PM
13
+ * @author    Trevor Irons (ti)
14
+ * @email     tirons@egi.utah.edu
15
+ * @copyright Copyright (c) 2016, University of Utah
16
+ * @copyright Copyright (c) 2016, Lemma Software, LLC
17
+ * @copyright Copyright (c) 2008, Colorado School of Mines
18
+ */
19
+#include "LoopInteractions.h"
20
+
21
+namespace Lemma {
22
+
23
+    std::string enum2String(const INTERACTION& type) {
24
+        std::string t;
25
+        switch (type) {
26
+        case COUPLING:
27
+            t = std::string("COUPLING");
28
+            break;
29
+        case INTERFERENCE:
30
+            t = std::string("INTERFERENCE");
31
+            break;
32
+        case PHASE:
33
+            t = std::string("PHASE");
34
+            break;
35
+        }
36
+        return t;
37
+    }
38
+
39
+    //--------------------------------------------------------------------------------------
40
+    //       Class:  LoopInteractions
41
+    //      Method:  f
42
+    //--------------------------------------------------------------------------------------
43
+    template <>
44
+    Complex LoopInteractions<COUPLING>::f( const Vector3r& r, const Real& volume, const Vector3cr& Ht, const Vector3cr& Hr ) {
45
+        return volume * ( Ht.dot(Hr) );                              // coupling
46
+    }
47
+
48
+    template <>
49
+    Complex LoopInteractions<INTERFERENCE>::f( const Vector3r& r, const Real& volume, const Vector3cr& Ht, const Vector3cr& Hr ) {
50
+        return volume * (1.-((Ht+Hr).norm()/(Hr.norm() + Ht.norm()))); // interference
51
+    }
52
+
53
+    template <>
54
+    Complex LoopInteractions<PHASE>::f( const Vector3r& r, const Real& volume, const Vector3cr& Ht, const Vector3cr& Hr ) {
55
+        return volume * std::acos( (Ht.dot(Hr) / (Ht.norm()*Hr.norm())) ); // angle
56
+    }
57
+
58
+} // ----  end of namespace Lemma  ----
59
+
60
+/* vim: set tabstop=4 expandtab */
61
+/* vim: set filetype=cpp */
62
+

Loading…
Cancel
Save