Browse Source

Adding files from SVN and porting over to CMake and latest Lemma

master
Trevor Irons 7 years ago
parent
commit
02cfa86b74
8 changed files with 3536 additions and 0 deletions
  1. 35
    0
      CMakeLists.txt
  2. 0
    0
      examples/CMakeLists.txt
  3. 616
    0
      include/EMSchur3D.h
  4. 438
    0
      include/EMSchur3DBase.h
  5. 936
    0
      include/bicgstab.h
  6. 4
    0
      src/CMakeLists.txt
  7. 1507
    0
      src/EMSchur3DBase.cpp
  8. 0
    0
      testing/CMakeLists.txt

+ 35
- 0
CMakeLists.txt View File

@@ -0,0 +1,35 @@
1
+add_subdirectory("src")
2
+add_library( emschur3d ${EMSCHUR3DSOURCE} )  
3
+target_include_directories( emschur3d PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" )
4
+
5
+set_target_properties(emschur3d PROPERTIES 
6
+	VERSION  "${LEMMA_VERSION_NOQUOTES}"
7
+	SOVERSION "${LEMMA_VERSION_MAJOR}.${LEMMA_VERSION_MINOR}"
8
+	PROJECT_LABEL "FDEM1D ${LABEL_SUFFIX}"
9
+)
10
+
11
+# Linking
12
+target_link_libraries(emschur3d "lemmacore" "fdem1d" )
13
+
14
+# Linking
15
+if ( LEMMA_VTK6_SUPPORT OR LEMMA_VTK7_SUPPORT ) 
16
+	target_link_libraries(emschur3d ${VTK_LIBRARIES})
17
+endif()
18
+
19
+# Testing
20
+if (LEMMA_ENABLE_TESTING)
21
+	add_subdirectory(testing)
22
+endif()
23
+
24
+# Install
25
+install ( TARGETS emschur3d DESTINATION ${CMAKE_INSTALL_PREFIX}/lib )
26
+install ( FILES include/EMSchur3D  DESTINATION ${CMAKE_INSTALL_PREFIX}/include/Lemma ) 
27
+install ( DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_PREFIX}/include/Lemma  FILES_MATCHING PATTERN "*.h")
28
+
29
+#install ( DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_PREFIX}/include/Lemma/  FILES_MATCHING PATTERN "FDEM1D")
30
+#install ( DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_PREFIX}/include/Lemma/FDEM1D  FILES_MATCHING PATTERN "*.h")
31
+
32
+# Examples
33
+if (LEMMA_BUILD_EXAMPLES)
34
+	add_subdirectory(examples)
35
+endif()

+ 0
- 0
examples/CMakeLists.txt View File


+ 616
- 0
include/EMSchur3D.h View File

@@ -0,0 +1,616 @@
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      02/19/2015 01:10:39 PM
13
+ * @version   $Id$
14
+ * @author    Trevor Irons (ti)
15
+ * @email     Trevor.Irons@xri-geo.com
16
+ * @copyright Copyright (c) 2015, XRI Geophysics, LLC
17
+ * @copyright Copyright (c) 2015, Trevor Irons
18
+ * @copyright Copyright (c) 2011, Trevor Irons
19
+ * @copyright Copyright (c) 2011, Colorado School of Mines
20
+ */
21
+
22
+#ifndef  EMSCHUR3D_INC
23
+#define  EMSCHUR3D_INC
24
+
25
+#include "EMSchur3DBase.h"
26
+#include "CSymSimplicialCholesky.h"
27
+
28
+namespace Lemma {
29
+
30
+
31
+    /**
32
+      \brief   Templated concrete classes of EMSChur3DBase.
33
+      \details
34
+     */
35
+    template < class Solver >
36
+    class EMSchur3D : public EMSchur3DBase {
37
+
38
+        //friend std::ostream &operator<<(std::ostream &stream,
39
+        //        const EMSchur3D &ob);
40
+
41
+        public:
42
+
43
+        // ====================  LIFECYCLE     =======================
44
+
45
+        /**
46
+         * @copybrief LemmaObject::New()
47
+         * @copydetails LemmaObject::New()
48
+         */
49
+        static EMSchur3D* New() {
50
+            EMSchur3D<Solver>*  Obj = new EMSchur3D<Solver>("EMSchur3D");
51
+            Obj->AttachTo(Obj);
52
+            return Obj;
53
+        }
54
+
55
+        /**
56
+         *  @copybrief   LemmaObject::Delete()
57
+         *  @copydetails LemmaObject::Delete()
58
+         */
59
+        void Delete() {
60
+            this->DetachFrom(this);
61
+        }
62
+
63
+        // ====================  OPERATORS     =======================
64
+
65
+        // ====================  OPERATIONS    =======================
66
+
67
+        /** Solves a single source problem. This method is thread safe.
68
+         *  @param[in] Source is the source term for generating primary fields
69
+         *  @param[in] isource is the source index
70
+         */
71
+        void SolveSource( DipoleSource* Source , const int& isource);
72
+
73
+        /** Builds the solver for the C matrix */
74
+        void BuildCDirectSolver(  );
75
+
76
+        // ====================  ACCESS        =======================
77
+
78
+        // ====================  INQUIRY       =======================
79
+
80
+#ifdef HAVE_YAMLCPP
81
+//         /**
82
+//          *  Uses YAML to serialize this object.
83
+//          *  @return a YAML::Node
84
+//          */
85
+//         YAML::Node Serialize() const;
86
+//
87
+//         /**
88
+//          *   Constructs an object from a YAML::Node.
89
+//          */
90
+//         static EMSchur3D* DeSerialize(const YAML::Node& node);
91
+#endif
92
+
93
+        protected:
94
+
95
+        // ====================  LIFECYCLE     =======================
96
+
97
+        /** Default protected constructor, use New */
98
+        EMSchur3D (const std::string& name) : EMSchur3DBase(name), CSolver(NULL) {
99
+        }
100
+
101
+// #ifdef HAVE_YAMLCPP
102
+//         /** Protected DeDerializing constructor, use factory DeSerialize  method*/
103
+//         EMSchur3D (const YAML::Node& node): EMSchur3DBase(node), CSolver(NULL) {
104
+//         }
105
+// #endif
106
+
107
+        /** Default protected destructor, use Delete */
108
+        ~EMSchur3D () {
109
+            // TODO delete arrays
110
+        }
111
+
112
+        /**
113
+         *  @copybrief   LemmaObject::Release()
114
+         *  @copydetails LemmaObject::Release()
115
+         */
116
+        void Release() {
117
+            delete this;
118
+        }
119
+
120
+        private:
121
+
122
+        // ====================  DATA MEMBERS  =========================
123
+
124
+        /** The templated solver for C */
125
+        Solver*     CSolver;
126
+
127
+        Eigen::SparseMatrix<Complex>  Csym;
128
+
129
+    }; // -----  end of class  EMSchur3D  -----
130
+
131
+
132
+    ////////////////////////////////////////////////////////////////////////////////////////
133
+    //                    Implimentation and Specialisations                              //
134
+    ////////////////////////////////////////////////////////////////////////////////////////
135
+
136
+    //--------------------------------------------------------------------------------------
137
+    //       Class:  EMSchur3D
138
+    //      Method:  SolveSource
139
+    //--------------------------------------------------------------------------------------
140
+    template < class Solver >
141
+    void EMSchur3D<Solver>::SolveSource ( DipoleSource* Source, const int& isource ) {
142
+
143
+        //  figure out which omega we are working with
144
+        int iw = -1;
145
+        for (int iiw=0; iiw<Omegas.size(); ++iiw) {
146
+           if (Omegas[iiw] - Source->GetAngularFrequency(0) < 1e-3 ) {
147
+               iw = iiw;
148
+           }
149
+        }
150
+        if (iw == -1) {
151
+            std::cerr << "FREQUENCY DOOM IN EMSchur3D::SolveSource \n";
152
+            exit(EXIT_FAILURE);
153
+        }
154
+
155
+        ///////////////////////////////////
156
+        // Set up primary fields
157
+        // TODO, this is a little stupid as they all share the same points. We need to extend
158
+        //       EmEARTH to be able to input a grid so that points are not explicitly needed like
159
+        //       this. This requires some care as calcs are made on faces.
160
+        //       Alternatively, the bins function of ReceiverPoints could be extended quite easily.
161
+        //       This may be the way to do this.
162
+
163
+        Lemma::ReceiverPoints* dpoint = Lemma::ReceiverPoints::New();
164
+
165
+        FillPoints(dpoint);
166
+        PrimaryField(Source, dpoint);
167
+
168
+        // Allocate a ton of memory
169
+        VectorXcr Phi    = VectorXcr::Zero(uns);
170
+        VectorXcr ms(unx+uny+unz);  // mu sigma
171
+
172
+        // Vector potential (A) Vector and phi
173
+        VectorXcr Se     = VectorXcr::Zero(unx+uny+unz);
174
+        //VectorXcr A      = VectorXcr::Zero(unx+uny+unz);
175
+        VectorXcr E      = VectorXcr::Zero(unx+uny+unz);
176
+        VectorXcr E0     = VectorXcr::Zero(unx+uny+unz);
177
+
178
+        // Lets get cracking
179
+        FillSourceTerms(ms, Se, E0, dpoint, Omegas[iw]);
180
+
181
+        /////////////////////////////////////////////////
182
+        // LOG File
183
+        std::string logfile (ResFile);
184
+        logfile += to_string(isource) + std::string(".log");
185
+        ofstream logio(logfile.c_str());
186
+
187
+        logio << *Source << std::endl;
188
+        logio << *Grid << std::endl;
189
+        logio << *LayModel << std::endl;
190
+
191
+        // solve for RHS
192
+        int max_it(nx*ny*nz), iter_done(0);
193
+        Real tol(3e-16), errorn(0);
194
+        logio << "solving RHS for source " << isource << std::endl;
195
+
196
+        // TODO, this is stupid, try and get rid of this copy!
197
+        Eigen::SparseMatrix<Complex>  Cc  = Cvec[iw];
198
+
199
+        jsw_timer timer;
200
+        jsw_timer timer2;
201
+
202
+        timer.begin();
203
+        timer2.begin();
204
+
205
+        /////////////////////////////////////////
206
+        // Solve for RHS
207
+        VectorXcr A = CSolver[iw].solve(Se);
208
+
209
+//         // Solve Real system instead
210
+           // The Real system is quasi-definite, though an LDLT decomposition exists, CHOLMOD doesn't find it.
211
+           // An LU can be done on this, but compute performance is very similiar to the complex system, and diagonal pivoting
212
+           // cannot be assumed to be best, hurting solve time.
213
+//         /* EXPERIMENTAL */
214
+//         VectorXr b2 = VectorXr::Zero(2*(unx+uny+unz));
215
+//         b2.head(unx+uny+unz) = Se.real();
216
+//         b2.tail(unx+uny+unz) = Se.imag();
217
+//         VectorXr A2 = CReSolver[iw].solve(b2);
218
+//         A.real() =   A2.head( unx+uny+unz );
219
+//         A.imag() =  -A2.tail( unx+uny+unz ); // Due to decomp. negative!
220
+//         /* END EXPERIMENTAL */
221
+
222
+        VectorXcr ADiv = D*A;  // ADiv == RHS == D C^I Se
223
+        VectorXcr Error = ((Cc.selfadjointView<Eigen::Lower>()*A).array() - Se.array());
224
+        logio << "|| Div(A) || = " << ADiv.norm()
225
+                // << " in " << iter_done << " iterations"
226
+              //<<  " with error " << errorn << "\t"
227
+              << "\tInital solution error "<<   Error.norm()  // Iteritive info
228
+              << "\ttime " << timer.end() << std::endl;
229
+
230
+        //VectorXcr ADivMAC = ADiv.array() * MAC.array().cast<Complex>();
231
+        //logio << "|| Div(A) || on MAC grid " << ADivMAC.norm() << std::endl;
232
+
233
+        /////////////////////
234
+        // Solve for Phi
235
+        logio << "Solving for Phi " << std::flush;
236
+        timer.begin();
237
+        tol = 1e-18;
238
+        int success(2);
239
+
240
+        success = implicitbicgstab(D, idx, ms, ADiv, Phi, CSolver[iw], max_it, tol, errorn, iter_done, logio);
241
+        //Phi.array() *= MAC.array().cast<Complex>(); // remove phi from air regions
242
+
243
+        /* Restart if necessary */
244
+        int nrestart(1);
245
+        // TODO send MAC to implicitbicgstab?
246
+        while (success == 2 && nrestart < 18 && iter_done > 1) {
247
+            success = implicitbicgstab(D, idx, ms, ADiv, Phi, CSolver[iw], max_it, tol, errorn, iter_done, logio);
248
+            //Phi.array() *= MAC.array().cast<Complex>(); // remove phi from air regions
249
+            nrestart += 1;
250
+        }
251
+
252
+        logio << "Implicit BiCGStab solution in " << iter_done << " iterations."
253
+                << " with error " << std::setprecision(8) << std::scientific << errorn << std::endl;
254
+        logio << "time "<< timer.end() << " [s]" << std::endl;
255
+
256
+
257
+        E = ms.array()*(D.transpose()*Phi).array(); // Temp, field due to charge
258
+
259
+        /////////////////////////////////////
260
+        // Compute A
261
+        /////////////////////////////////////
262
+        logio << "Solving for A using phi" << std::endl;
263
+        std::cout << "Solving for A" << std::endl;
264
+        max_it = nx*ny*nz;
265
+        tol = 5e-16;
266
+        errorn = 0;
267
+        iter_done = 0;
268
+
269
+        timer.begin();
270
+
271
+        A = CSolver[iw].solve( (Se-E).eval() ); // UmfPack requires eval?
272
+
273
+        VectorXcr ADiv2 = D*A;
274
+        logio << "|| Div(A) || = " << ADiv2.norm() ;
275
+              //" in " << iter_done << " iterations"
276
+              //<<  " with error " << errorn << "\t";
277
+
278
+        // Report error of solutions
279
+        Error = ((Cc.selfadjointView<Eigen::Lower>()*A).array() + E.array() - Se.array());
280
+        logio << "\tsolution error " << Error.norm()
281
+              << std::fixed << std::setprecision(2) << "\ttime " << timer.end() << "\ttotal time " << timer2.end() << std::endl;
282
+        logio.close();
283
+
284
+        //////////////////////////////////////
285
+        // Update Fields and report
286
+        E.array() = Complex(0,-Omegas[iw])*A.array() - (D.transpose()*Phi).array();   // Secondary Field Only
287
+        VectorXcr B = StaggeredGridCurl(A);
288
+
289
+        WriteVTKResults( ResFile+ to_string(isource), A, Se, E0, E , Phi, ADiv, ADiv2, B);
290
+
291
+        dpoint->Delete();
292
+        return ;
293
+
294
+    }		// -----  end of method EMSchur3D::SolveSource  -----
295
+
296
+    //--------------------------------------------------------------------------------------
297
+    //       Class:  EMSchur3DBase
298
+    //      Method:  BuildCDirectSolver
299
+    //--------------------------------------------------------------------------------------
300
+    template < class Solver >
301
+    void EMSchur3D<Solver>::BuildCDirectSolver (  ) {
302
+
303
+        CSolver = new Solver[Omegas.size()];
304
+
305
+        for (int iw=0; iw<Omegas.size(); ++iw) {
306
+
307
+            jsw_timer timer;
308
+            timer.begin();
309
+
310
+            /*  Complex system */
311
+            /*
312
+            std::cout << "Generic solver pattern analyzing C_" << iw << ",";
313
+            std::cout.flush();
314
+            CSolver[iw].analyzePattern( Cvec[iw].selfadjointView< Eigen::Lower>() );
315
+            std::cout << " done in " << timer.end() / 60. << " [m]" << std::endl;
316
+
317
+            // factorize
318
+            timer.begin();
319
+            std::cout << "Generic solver factorising C_" << iw << ", ";
320
+            std::cout.flush();
321
+            CSolver[iw].factorize( Cvec[iw].selfadjointView< Eigen::Lower>() );
322
+            */
323
+
324
+            std::cerr << "No solver Specified!" << iw << ",";
325
+            exit(EXIT_FAILURE);
326
+            //CSolver[iw].compute( Cvec[iw].selfadjointView< Eigen::Lower>() );
327
+            std::cout << " done in " << timer.end() / 60. << " [m]" << std::endl;
328
+
329
+        }
330
+    }
331
+
332
+    #ifdef HAVE_SUPERLUMT
333
+    template<>
334
+    void EMSchur3D< Eigen::SuperLU<Eigen::SparseMatrix<Complex, Eigen::ColMajor> > >::BuildCDirectSolver() {
335
+
336
+        CSolver = new Eigen::SuperLU<Eigen::SparseMatrix<Complex, Eigen::ColMajor> > [Omegas.size()];
337
+
338
+        for (int iw=0; iw<Omegas.size(); ++iw) {
339
+            jsw_timer timer;
340
+            timer.begin();
341
+
342
+            /* SuperLU */
343
+            //CSolver[iw].options().DiagPivotThresh = 0.01;
344
+            //CSolver[iw].options().SymmetricMode = YES;
345
+            //CSolver[iw].options().ColPerm = MMD_AT_PLUS_A;
346
+            //CSolver[iw].options().Trans = NOTRANS;
347
+            //CSolver[iw].options().ConditionNumber = NO;
348
+            //std::cout << "SuperLU options:\n";
349
+            //std::cout << "\tPivot Threshold: " << CSolver[iw].options().DiagPivotThresh << std::endl;
350
+            //std::cout << "\tSymmetric mode: " << CSolver[iw].options().SymmetricMode << std::endl;
351
+            //std::cout << "\tEquilibrate: " << CSolver[iw].options().Equil << std::endl;
352
+            //std::cout << "\tCol Permutation: " << CSolver[iw].options().ColPerm << std::endl;
353
+            //std::cout << "\tTrans: " << CSolver[iw].options().Trans << std::endl;
354
+            //std::cout << "\tCondition Number: " << CSolver[iw].options().ConditionNumber << std::endl;
355
+
356
+            /*  Complex system */
357
+            std::cout << "SuperLU_MT pattern analyzing C_" << iw << ",";
358
+            std::cout.flush();
359
+            CSolver[iw].analyzePattern( Cvec[iw].selfadjointView< Eigen::Lower>() );
360
+            std::cout << " done in " << timer.end() / 60. << " [m]" << std::endl;
361
+
362
+            // factorize
363
+            timer.begin();
364
+            std::cout << "SuperLU_MT factorising C_" << iw << ", ";
365
+            std::cout.flush();
366
+            CSolver[iw].factorize( Cvec[iw].selfadjointView< Eigen::Lower>() );
367
+            std::cout << " done in " << timer.end() / 60. << " [m]" << std::endl;
368
+
369
+        }
370
+    }
371
+    #endif
372
+
373
+    template<>
374
+    void EMSchur3D< Eigen::SparseLU<Eigen::SparseMatrix<Complex, Eigen::ColMajor>, Eigen::COLAMDOrdering<int> > >::BuildCDirectSolver() {
375
+        CSolver = new Eigen::SparseLU<Eigen::SparseMatrix<Complex, Eigen::ColMajor>, Eigen::COLAMDOrdering<int> > [Omegas.size()];
376
+        for (int iw=0; iw<Omegas.size(); ++iw) {
377
+            jsw_timer timer;
378
+            timer.begin();
379
+
380
+            CSolver[iw].isSymmetric(true);
381
+            CSolver[iw].setPivotThreshold(0.0);
382
+
383
+            /*  Complex system */
384
+            std::cout << "SparseLU pattern analyzing C_" << iw << ",";
385
+            std::cout.flush();
386
+            CSolver[iw].analyzePattern( Cvec[iw].selfadjointView< Eigen::Lower>() );
387
+            std::cout << " done in " << timer.end() / 60. << " [m]" << std::endl;
388
+
389
+            // factorize
390
+            timer.begin();
391
+            std::cout << "SparseLU factorising C_" << iw << ", ";
392
+            std::cout.flush();
393
+            CSolver[iw].factorize( Cvec[iw].selfadjointView< Eigen::Lower>() );
394
+            std::cout << " done in " << timer.end() / 60. << " [m]" << std::endl;
395
+        }
396
+    }
397
+
398
+//     template<>
399
+//     void EMSchur3D< Eigen::CholmodSupernodalLLT< Eigen::SparseMatrix<Complex, Eigen::ColMajor>, Eigen::Lower > > ::BuildCDirectSolver() {
400
+//         CSolver = new Eigen::CholmodSupernodalLLT< Eigen::SparseMatrix<Complex, Eigen::ColMajor>, Eigen::Lower > [Omegas.size()];
401
+//         for (int iw=0; iw<Omegas.size(); ++iw) {
402
+//             Csym = Cvec[iw].selfadjointView<Eigen::Lower>();
403
+//             jsw_timer timer;
404
+//             timer.begin();
405
+//             /*  Complex system */
406
+//             std::cout << "CholmodSupernodalLLT pattern analyzing C_" << iw << ",";
407
+//             std::cout.flush();
408
+//             CSolver[iw].analyzePattern( Csym );
409
+//             std::cout << " done in " << timer.end() / 60. << " [m]" << std::endl;
410
+//             /* factorize */
411
+//             timer.begin();
412
+//             std::cout << "CholmodSupernodalLLT factorising C_" << iw << ", ";
413
+//             std::cout.flush();
414
+//             CSolver[iw].factorize( Csym );
415
+//             std::cout << " done in " << timer.end() / 60. << " [m]" << std::endl;
416
+//         }
417
+//     }
418
+
419
+    template<>
420
+    void EMSchur3D< Eigen::CSymSimplicialLLT< Eigen::SparseMatrix<Complex, Eigen::ColMajor>, Eigen::Lower, Eigen::NaturalOrdering<int> > > ::BuildCDirectSolver() {
421
+        CSolver = new Eigen::CSymSimplicialLLT< Eigen::SparseMatrix<Complex, Eigen::ColMajor>, Eigen::Lower, Eigen::NaturalOrdering<int> > [Omegas.size()];
422
+        for (int iw=0; iw<Omegas.size(); ++iw) {
423
+            Csym = Cvec[iw].selfadjointView<Eigen::Lower>();
424
+            jsw_timer timer;
425
+            timer.begin();
426
+            /*  Complex system */
427
+            std::cout << "CSymSimplicialLLT<NaturalOrdering> pattern analyzing C_" << iw << ",";
428
+            std::cout.flush();
429
+            CSolver[iw].analyzePattern( Csym );
430
+            std::cout << " done in " << timer.end() / 60. << " [m]" << std::endl;
431
+            /* factorize */
432
+            timer.begin();
433
+            std::cout << "CSymSimplicialLLT<NaturalOrdering> factorising C_" << iw << ", ";
434
+            std::cout.flush();
435
+            CSolver[iw].factorize( Csym );
436
+            std::cout << " done in " << timer.end() / 60. << " [m]" << std::endl;
437
+        }
438
+    }
439
+
440
+    template<>
441
+    void EMSchur3D< Eigen::CSymSimplicialLLT< Eigen::SparseMatrix<Complex, Eigen::ColMajor>, Eigen::Lower, Eigen::AMDOrdering<int> > > ::BuildCDirectSolver() {
442
+        CSolver = new Eigen::CSymSimplicialLLT< Eigen::SparseMatrix<Complex, Eigen::ColMajor>, Eigen::Lower, Eigen::AMDOrdering<int> > [Omegas.size()];
443
+        for (int iw=0; iw<Omegas.size(); ++iw) {
444
+            //Csym = Cvec[iw].selfadjointView<Eigen::Lower>();
445
+            jsw_timer timer;
446
+            timer.begin();
447
+            /*  Complex system */
448
+            std::cout << "CSymSimplicialLLT<AMDOrdering> pattern analyzing C_" << iw << ",";
449
+            std::cout.flush();
450
+            CSolver[iw].analyzePattern( Cvec[iw] );
451
+            std::cout << " done in " << timer.end() / 60. << " [m]" << std::endl;
452
+            /* factorize */
453
+            timer.begin();
454
+            std::cout << "CSymSimplicialLLT<AMDOrdering> factorising C_" << iw << ", ";
455
+            std::cout.flush();
456
+            CSolver[iw].factorize( Cvec[iw] );
457
+            std::cout << " done in " << timer.end() / 60. << " [m]" << std::endl;
458
+        }
459
+    }
460
+
461
+    template<>
462
+    void EMSchur3D< Eigen::CSymSimplicialLDLT< Eigen::SparseMatrix<Complex, Eigen::ColMajor>, Eigen::Lower, Eigen::AMDOrdering<int> > > ::BuildCDirectSolver() {
463
+        CSolver = new Eigen::CSymSimplicialLDLT< Eigen::SparseMatrix<Complex, Eigen::ColMajor>, Eigen::Lower, Eigen::AMDOrdering<int> > [Omegas.size()];
464
+        for (int iw=0; iw<Omegas.size(); ++iw) {
465
+            Csym = Cvec[iw].selfadjointView<Eigen::Lower>();
466
+            jsw_timer timer;
467
+            timer.begin();
468
+            /*  Complex system */
469
+            std::cout << "CSymSimplicialLDLT<AMDOrdering> pattern analyzing C_" << iw << ",";
470
+            std::cout.flush();
471
+            CSolver[iw].analyzePattern( Csym );
472
+            std::cout << " done in " << timer.end() / 60. << " [m]" << std::endl;
473
+            /* factorize */
474
+            timer.begin();
475
+            std::cout << "CSymSimplicialLDLT<AMDOrdering> factorising C_" << iw << ", ";
476
+            std::cout.flush();
477
+            CSolver[iw].factorize( Csym );
478
+            std::cout << " done in " << timer.end() / 60. << " [m]" << std::endl;
479
+        }
480
+    }
481
+
482
+    template<>
483
+    void EMSchur3D< Eigen::BiCGSTAB<Eigen::SparseMatrix<Complex, Eigen::ColMajor>, Eigen::IncompleteLUT<Complex> > > ::BuildCDirectSolver() {
484
+        CSolver = new Eigen::BiCGSTAB<Eigen::SparseMatrix<Complex, Eigen::ColMajor>, Eigen::IncompleteLUT<Complex> > [Omegas.size()];
485
+        for (int iw=0; iw<Omegas.size(); ++iw) {
486
+            Csym = Cvec[iw].selfadjointView<Eigen::Lower>();
487
+            jsw_timer timer;
488
+            timer.begin();
489
+            /*  Complex system */
490
+            std::cout << "BiCGSTAB(ILU) pattern analyzing C_" << iw << ",";
491
+            std::cout.flush();
492
+            CSolver[iw].analyzePattern( Csym );
493
+            std::cout << " done in " << timer.end() / 60. << " [m]" << std::endl;
494
+            /* factorize */
495
+            timer.begin();
496
+            std::cout << "BiCGSTAB(ILU) factorising C_" << iw << ", ";
497
+            std::cout.flush();
498
+            CSolver[iw].factorize( Csym );
499
+            std::cout << " done in " << timer.end() / 60. << " [m]" << std::endl;
500
+        }
501
+    }
502
+
503
+    template<>
504
+    void EMSchur3D< Eigen::BiCGSTAB<Eigen::SparseMatrix<Complex, Eigen::ColMajor> > > ::BuildCDirectSolver() {
505
+        CSolver = new Eigen::BiCGSTAB<Eigen::SparseMatrix<Complex, Eigen::ColMajor> > [Omegas.size()];
506
+        for (int iw=0; iw<Omegas.size(); ++iw) {
507
+            Csym = Cvec[iw].selfadjointView<Eigen::Lower>();
508
+            jsw_timer timer;
509
+            timer.begin();
510
+            /*  Complex system */
511
+            std::cout << "BiCGSTAB pattern analyzing C_" << iw << ",";
512
+            std::cout.flush();
513
+            CSolver[iw].analyzePattern( Csym );
514
+            std::cout << " done in " << timer.end() / 60. << " [m]" << std::endl;
515
+            // factorize
516
+            timer.begin();
517
+            std::cout << "BiCGSTAB factorising C_" << iw << ", ";
518
+            std::cout.flush();
519
+            CSolver[iw].factorize( Csym );
520
+            std::cout << " done in " << timer.end() / 60. << " [m]" << std::endl;
521
+        }
522
+    }
523
+
524
+    template<>
525
+    void EMSchur3D<   Eigen::ConjugateGradient<Eigen::SparseMatrix<Complex, Eigen::ColMajor>, Eigen::Lower > > ::BuildCDirectSolver() {
526
+        CSolver = new Eigen::ConjugateGradient<Eigen::SparseMatrix<Complex, Eigen::ColMajor>, Eigen::Lower > [Omegas.size()];
527
+        for (int iw=0; iw<Omegas.size(); ++iw) {
528
+            //Csym = Cvec[iw].selfadjointView<Eigen::Lower>();
529
+            jsw_timer timer;
530
+            timer.begin();
531
+            /*  Complex system */
532
+            std::cout << "ConjugateGradient pattern analyzing C_" << iw << ",";
533
+            std::cout.flush();
534
+            CSolver[iw].analyzePattern( Cvec[iw] );
535
+            std::cout << " done in " << timer.end() / 60. << " [m]" << std::endl;
536
+            // factorize
537
+            timer.begin();
538
+            std::cout << "ConjugateGradient factorising C_" << iw << ", ";
539
+            std::cout.flush();
540
+            CSolver[iw].factorize( Cvec[iw] );
541
+            std::cout << " done in " << timer.end() / 60. << " [m]" << std::endl;
542
+        }
543
+    }
544
+
545
+//     template<>
546
+//     void EMSchur3D<   Eigen::PastixLLT<Eigen::SparseMatrix<Complex, Eigen::ColMajor>, Eigen::Lower > > ::BuildCDirectSolver() {
547
+//         CSolver = new Eigen::PastixLLT<Eigen::SparseMatrix<Complex, Eigen::ColMajor>, Eigen::Lower > [Omegas.size()];
548
+//         //MPI_Init(NULL, NULL);
549
+//         for (int iw=0; iw<Omegas.size(); ++iw) {
550
+//             //Csym = Cvec[iw].selfadjointView<Eigen::Lower>();
551
+//             jsw_timer timer;
552
+//             timer.begin();
553
+//             /*  Complex system */
554
+//             std::cout << "PaStiX LLT pattern analyzing C_" << iw << ",";
555
+//             std::cout.flush();
556
+//             CSolver[iw].analyzePattern( Cvec[iw] );
557
+//             std::cout << " done in " << timer.end() / 60. << " [m]" << std::endl;
558
+//             // factorize
559
+//             timer.begin();
560
+//             std::cout << "PaStiX LLT factorising C_" << iw << ", ";
561
+//             std::cout.flush();
562
+//             CSolver[iw].factorize( Cvec[iw] );
563
+//             std::cout << " done in " << timer.end() / 60. << " [m]" << std::endl;
564
+//         }
565
+//     }
566
+//
567
+//     template<>
568
+//     void EMSchur3D<   Eigen::PastixLDLT<Eigen::SparseMatrix<Complex, Eigen::ColMajor>, Eigen::Lower > > ::BuildCDirectSolver() {
569
+//         CSolver = new Eigen::PastixLDLT<Eigen::SparseMatrix<Complex, Eigen::ColMajor>, Eigen::Lower > [Omegas.size()];
570
+//         //MPI_Init(NULL, NULL);
571
+//         for (int iw=0; iw<Omegas.size(); ++iw) {
572
+//             //Csym = Cvec[iw].selfadjointView<Eigen::Lower>();
573
+//             jsw_timer timer;
574
+//             timer.begin();
575
+//             /*  Complex system */
576
+//             std::cout << "PaStiX LDLT pattern analyzing C_" << iw << ",";
577
+//             std::cout.flush();
578
+//             CSolver[iw].analyzePattern( Cvec[iw] );
579
+//             std::cout << " done in " << timer.end() / 60. << " [m]" << std::endl;
580
+//             // factorize
581
+//             timer.begin();
582
+//             std::cout << "PaStiX LDLT factorising C_" << iw << ", ";
583
+//             std::cout.flush();
584
+//             CSolver[iw].factorize( Cvec[iw] );
585
+//             std::cout << " done in " << timer.end() / 60. << " [m]" << std::endl;
586
+//             std::cout << "INFO " << CSolver[iw].info(  ) << std::endl;
587
+//         }
588
+//     }
589
+//
590
+//     template<>
591
+//     void EMSchur3D<   Eigen::PastixLU<Eigen::SparseMatrix<Complex, Eigen::ColMajor>, true > > ::BuildCDirectSolver() {
592
+//         CSolver = new Eigen::PastixLU<Eigen::SparseMatrix<Complex, Eigen::ColMajor>, true > [Omegas.size()];
593
+//         //MPI_Init(NULL, NULL);
594
+//         for (int iw=0; iw<Omegas.size(); ++iw) {
595
+//             Csym = Cvec[iw].selfadjointView<Eigen::Lower>();
596
+//             jsw_timer timer;
597
+//             timer.begin();
598
+//             /*  Complex system */
599
+//             std::cout << "PaStiX LU pattern analyzing C_" << iw << ",";
600
+//             std::cout.flush();
601
+//             CSolver[iw].compute( Csym );
602
+//             std::cout << "PaStiX LU Done C_" << iw << std::endl;;
603
+// //             std::cout << " done in " << timer.end() / 60. << " [m]" << std::endl;
604
+// //             // factorize
605
+// //             timer.begin();
606
+// //             std::cout << "PaStiX LU factorising C_" << iw << ", ";
607
+// //             std::cout.flush();
608
+// //             CSolver[iw].factorize( Csym );
609
+// //             std::cout << " done in " << timer.end() / 60. << " [m]" << std::endl;
610
+//         }
611
+//     }
612
+
613
+}		// -----  end of Lemma  name  -----
614
+
615
+#endif   // ----- #ifndef EMSCHUR3D_INC  -----
616
+

+ 438
- 0
include/EMSchur3DBase.h View File

@@ -0,0 +1,438 @@
1
+// ===========================================================================
2
+//
3
+//       Filename:  EMSchur3DBase.h
4
+//
5
+//        Created:  09/20/2013 04:35:57 PM
6
+//       Compiler:  Tested with g++, icpc, and MSVC 2010
7
+//
8
+//         Author:  Trevor Irons (ti)
9
+//
10
+//   Organisation:  University of Utah,
11
+//                  Colorado School of Mines
12
+//                  US Geological Survey
13
+//
14
+//          Email:  tirons@egi.utah.edu
15
+//
16
+// ===========================================================================
17
+
18
+/**
19
+  @file
20
+  @author   Trevor Irons
21
+  @date     09/20/2013
22
+  @version  $Id$
23
+ **/
24
+
25
+
26
+#ifndef  EMSCHUR3DBASE_INC
27
+#define  EMSCHUR3DBASE_INC
28
+
29
+#include <LemmaCore>
30
+#include <FDEM1D>
31
+
32
+//#include "LemmaObject.h"
33
+//#include "rectilineargrid.h"
34
+//#include "RectilinearGridVTKExporter.h"
35
+//#include "ASCIIParser.h"
36
+//#include "AEMSurvey.h"
37
+//#include "receiverpoints.h"
38
+//#include "layeredearthem.h"
39
+//#include "emearth1d.h"
40
+
41
+#include "timer.h"
42
+#include <Eigen/Sparse>
43
+#include "bicgstab.h"
44
+
45
+// Solvers
46
+#ifdef HAVE_PASTIX
47
+#include <Eigen/PaStiXSupport>
48
+#endif
49
+
50
+#ifdef HAVE_METIS
51
+#include <Eigen/MetisSupport>
52
+#endif
53
+
54
+#ifdef HAVE_SUPERLU
55
+#include <Eigen/SuperLUSupport>
56
+#endif
57
+
58
+#ifdef HAVE_SUPERLUMT
59
+#include <Eigen/SuperLUMTSupport>
60
+#endif
61
+
62
+#ifdef HAVE_SPQR
63
+#include <Eigen/SPQRSupport>
64
+#endif
65
+
66
+// Cholmod Support won't compile typedef issue
67
+// #ifdef HAVE_CHOLMOD
68
+// #include <Eigen/CholmodSupport>
69
+// #endif
70
+//
71
+// // Cholmod Support won't compile
72
+// #ifdef HAVE_UMFPACK
73
+// #include <Eigen/UmfPackSupport>
74
+// #endif
75
+
76
+namespace Lemma {
77
+
78
+/**
79
+ \defgroup EMSchur3DBase EMSchur3DBase
80
+  Provides 3D solution to Maxwell's equations.
81
+ */
82
+
83
+enum SOLVER{ SPARSELU, SimplicialLLT, SimplicialLDLT, BiCGStab, SparseQR };
84
+
85
+
86
+/**
87
+  @class EMSchur3DBase
88
+  \ingroup EMSchur3DBase
89
+  \brief Provides a 3D solution to Maxwell's equations.
90
+  \details 3D finite difference solution to maxwells equations
91
+            using a SCHUR decomposition on a staggered grid.
92
+  Performs a Schur decomposition on the vector scalar formulation of
93
+  Maxwell's equations.
94
+   \f[
95
+  -\nabla^2 (\mathbf{A}) - \jmath \omega \mu \sigma  \mathbf{A} - \mu \sigma \nabla (\phi) = -  \mu  \mathbf{J}_s
96
+   \f]
97
+
98
+Which can be written in the functional form
99
+\f[ \begin{pmatrix}
100
+      -\nabla^2 + \jmath \omega \mu \sigma   & \mu \sigma \nabla  \\
101
+       \nabla \cdot  & 0
102
+    \end{pmatrix}
103
+    \begin{pmatrix}   \mathbf{A} \\  \phi   \end{pmatrix}
104
+     = \begin{pmatrix}      \mathbf{s}_E \\   0      \end{pmatrix}
105
+\f]
106
+Using the notation
107
+\f[ \begin{pmatrix}
108
+        \mathbf{C} & \mathbf{B} \\
109
+        \mathbf{D} & \mathbf{0}
110
+    \end{pmatrix}  \begin{pmatrix} \mathbf{A} \\ \phi \end{pmatrix} =
111
+    \begin{pmatrix} \mathbf{s}_E \\ 0 \end{pmatrix}
112
+\f]
113
+Which is decomposed for seperate solutions to \f$ \mathbf{A}, \phi \f$ using a Schur decomposition
114
+  \f[   \begin{matrix}
115
+        \mathbf{D}\mathbf{C}^{-1}\mathbf{B} \phi & = \mathbf{D} \mathbf{C}^{-1} \mathbf{s}_E \\
116
+        \mathbf{C}\mathbf{A}                     & = \mathbf{s}_E - \mathbf{G} \phi
117
+        \end{matrix}
118
+  \f]
119
+
120
+Where \f$ \mathbf{B} = \mu \sigma \mathbf{D}^T \f$. Additional algorithmic details may be found at
121
+@verbatim
122
+@inproceedings{doi:10.1190/segam2012-0896.1,
123
+  author = {Trevor Irons and Yaoguo Li and Jason R. McKenna},
124
+  title = {3D frequency-domain electromagnetics modeling using decoupled scalar and vector potentials},
125
+  booktitle = {SEG Technical Program Expanded Abstracts 2012},
126
+  chapter = {112},
127
+  year = {2012},
128
+  pages = {1-6},
129
+  doi = {10.1190/segam2012-0896.1},
130
+  URL = {http://library.seg.org/doi/abs/10.1190/segam2012-0896.1},
131
+  eprint = {http://library.seg.org/doi/pdf/10.1190/segam2012-0896.1}
132
+}
133
+@endverbatim
134
+*/
135
+
136
+//template< class Solver >
137
+class EMSchur3DBase : public LemmaObject {
138
+
139
+    friend std::ostream &operator<<(std::ostream &stream,
140
+            const EMSchur3DBase &ob);
141
+
142
+    protected:
143
+    struct ctor_key {};
144
+
145
+    public:
146
+
147
+    // ====================  LIFECYCLE     =======================
148
+
149
+    /** Default protected constructor, use New */
150
+    explicit EMSchur3DBase ( const ctor_key& );
151
+
152
+    /** Default protected constructor, use New */
153
+    explicit EMSchur3DBase ( const YAML::Node& node, const ctor_key& );
154
+
155
+    /** Default protected destructor, use Delete */
156
+    virtual ~EMSchur3DBase ();
157
+
158
+    /**
159
+     * Initialises antenna to contain no points, with no current
160
+     * and no frequency. NumberOfTurns set to 1
161
+     */
162
+    static std::shared_ptr<EMSchur3DBase> NewSP();
163
+
164
+    /**
165
+     * Provides deep copy
166
+     */
167
+    virtual std::shared_ptr<EMSchur3DBase> Clone() const ;
168
+
169
+    /**
170
+     *  Uses YAML to serialize this object.
171
+     *  @return a YAML::Node
172
+     */
173
+    YAML::Node Serialize() const;
174
+
175
+    /**
176
+     *   Constructs an object from a YAML::Node.
177
+     */
178
+     static std::shared_ptr<EMSchur3DBase> DeSerialize( const YAML::Node& node );
179
+
180
+    // ====================  OPERATORS     =======================
181
+
182
+    // ====================  OPERATIONS    =======================
183
+
184
+    /* Performs the solution
185
+     * This is thread safe. TODO, but where should the results go? Just to file?
186
+     * Who does the parsing? Actually I think this method is the wrong place to talk
187
+     * about that. This is just a big red button. The details should be worked out in private
188
+     * methods, that this could well call. Still though, where should the damn results go. What if
189
+     * someone wants to use them *right now*, and not go through file IO. This is a good cause for
190
+     * fixing the model class. So the result will be a final RectGrid (or Model) where the results live.
191
+     * THEN users can call a seperate WriteToVTK or whatever based on that.
192
+     */
193
+    void Solve( );
194
+
195
+    // ====================  ACCESS        =======================
196
+
197
+    /** Sets the RectilinearGrid to use
198
+     *  @param[in] Grid is a pointer to the Grid to be used.
199
+     */
200
+    void SetRectilinearGrid( std::shared_ptr<RectilinearGrid> Grid);
201
+
202
+    /** Sets the RectilinearGrid to use
203
+     *  @param[in] Grid is a pointer to the Grid to be used.
204
+     */
205
+    //void SetAEMSurvey(AEMSurvey* Survey);
206
+
207
+    /** Sets the prefix for results files (.log and .vtr) the source fiducial is added as well
208
+     */
209
+    void SetResFileName(const std::string& filename);
210
+
211
+    /** Sets the solver to use to invert the C matrix. This is done many times. If you are reusing the same matrix
212
+        for numerous simulations, it may be benefitial to use the direct (SPARSELU) solver. For one off calculations the BiCGSTAB
213
+        is a good choice. Default is SPARSELU.
214
+     */
215
+    void SetCSolver(const SOLVER& CSOLVER);
216
+
217
+    /**
218
+     *  Sets the LayredEarthEM model that will be used for the primary field calculation as well as deterimining the
219
+     *  bacground conductivity file.
220
+     @  @param[in] LayModel is a pointer to the LayeredEarthEM model to use.
221
+     */
222
+    void SetLayeredEarthEM( std::shared_ptr<LayeredEarthEM> LayModel );
223
+
224
+    /**
225
+     * Loads a MeshTools conductivity model.
226
+     * @param[in] fname is the file to load.
227
+     */
228
+    void LoadMeshToolsConductivityModel( const std::string& fname );
229
+
230
+    /**
231
+     *  Writes out results to into a vtkRectilinearGrid file
232
+     *  @param[in] fname is the file name that is created, the .vtr suffix is added.
233
+     */
234
+    void WriteVTKResults( const std::string& fname, Eigen::Ref<VectorXcr> A,
235
+          Eigen::Ref<VectorXcr> Se, Eigen::Ref<VectorXcr> E0, Eigen::Ref<VectorXcr> E,
236
+          Eigen::Ref<VectorXcr> Phi, Eigen::Ref<VectorXcr> ADiv, Eigen::Ref<VectorXcr> ADiv2,
237
+          Eigen::Ref<VectorXcr> B
238
+        );
239
+
240
+    // ====================  INQUIRY       =======================
241
+
242
+    /** Returns the name of the underlying class, similiar to Python's type */
243
+    virtual std::string GetName() const;
244
+
245
+    protected:
246
+
247
+    // ====================  LIFECYCLE     =======================
248
+
249
+    //private:
250
+
251
+    /** Builds the C matrix */
252
+    void BuildC( Real*** sigmax, Real*** sigmay, Real*** sigmaz, const int& iw);
253
+
254
+    /* Builds the C matrix as a block real system. Benefits of this are the availability of an
255
+     *  LDL^T decomposition. Also, as complex number in C++ are templates and will necessarily have
256
+     *  real and imaginary parts, this formulation will have a reduced cost, due to less computations
257
+     *  with the zero valued imaginary parts (off-diagonals)
258
+     *  The \f$C \in I^3\f$ matrix is instead written as
259
+     *   [  C_r   C_i ] [ x_r ] = [ b_r ]
260
+     *   [  C_i  -C_r ] [ x_i ]   [ b_i ]
261
+     */
262
+    //void BuildCReal( Real*** sigmax, Real*** sigmay, Real*** sigmaz, const int& iw);
263
+
264
+    /** Builds the C matrix */
265
+    void BuildCPreconditioner( const int& iw);
266
+
267
+    /** Builds the C matrix */
268
+    virtual void BuildCDirectSolver( )=0;
269
+
270
+    /** Fills the actual points on the grid that 1D primary field calculations need to be made.
271
+        @todo  This is a little stupid as all threads share the same points. Stupid in that right now
272
+               this is done for every calculation. Not a huge amount of time is spent here, I suppose some extra memory
273
+               though. We need to extend
274
+               EmEARTH to be able to input a grid so that points are not explicitly needed like
275
+               this. This requires some care as calcs are made on faces.
276
+               Alternatively, the bins function of FieldPoints could be extended quite easily.
277
+               This may be the way to do this.
278
+     */
279
+    void FillPoints( std::shared_ptr<FieldPoints> Points );
280
+
281
+    /** Builds D/G
282
+     */
283
+    void BuildD( );
284
+
285
+    /** Used to manage tradititional C 3D array */
286
+    template <typename T>
287
+    void Allocate3DScalar(T ***&Array, T init) {
288
+        Array  = new T**[nx];
289
+        for (int ix=0; ix<nx; ix++){
290
+            Array[ix] = new T*[ny];
291
+            for (int iy=0; iy<ny; iy++){
292
+                Array[ix][iy]  = new T[nz];
293
+                for (int iz=0; iz<nz; iz++) Array[ix][iy][iz] = init;
294
+            }
295
+        }
296
+        return;
297
+    }
298
+
299
+    /** Used to manage tradititional C 3D array */
300
+    template <typename T>
301
+    void Delete3DScalar(T ***&Array) {
302
+        for (int ix=0; ix<nx; ix++){
303
+            for (int iy=0; iy<ny; iy++){
304
+                delete [] Array[ix][iy];
305
+            }
306
+            delete [] Array[ix];
307
+        }
308
+        delete [] Array;
309
+        Array = NULL;
310
+        return;
311
+    }
312
+
313
+    /**
314
+     * This is called just before solve and gets all shared objects ready to go
315
+     */
316
+    void Setup( );
317
+
318
+    /** Solves a single source problem. This method is thread safe.
319
+     *  @param[in] Source is the source term for generating primary fields
320
+     *  @param[in] isource is the source index
321
+     */
322
+    virtual void SolveSource( DipoleSource* Source , const int& isource)=0;
323
+
324
+    /** Computes the primary field
325
+     */
326
+    void PrimaryField( std::shared_ptr<DipoleSource> Source, std::shared_ptr<FieldPoints> dpoint);
327
+
328
+    /**
329
+     *  Fills the vectors that are called in
330
+     */
331
+    void FillSourceTerms(  Eigen::Ref<VectorXcr>  ms,
332
+                                        Eigen::Ref<VectorXcr> Se, Eigen::Ref<VectorXcr> E0,
333
+                                        std::shared_ptr<FieldPoints> dpoint, const Real& omega );
334
+
335
+    /** Computes the curl of A on the staggered grid
336
+     */
337
+    VectorXcr StaggeredGridCurl(Eigen::Ref<VectorXcr> A);
338
+
339
+    // ====================  DATA MEMBERS  =========================
340
+
341
+    /** Grid over which operators are active */
342
+    std::shared_ptr<RectilinearGrid>                    Grid;
343
+
344
+    /* Used to help dump results */
345
+    //std::shared_ptr<RectilinearGridVTKExporter>         VTKGridExporter;
346
+
347
+    /** Class containing information about the AEM survey */
348
+    //AEMSurvey*                      Survey;
349
+
350
+    std::shared_ptr<LayeredEarthEM>                     LayModel;
351
+
352
+    /** Matrix objects representing discrete operators
353
+     */
354
+    Eigen::SparseMatrix<Complex, Eigen::ColMajor>*                  Cvec;
355
+    Eigen::SparseMatrix<Complex, Eigen::ColMajor>                   D;
356
+
357
+    /** Squeezed matrices for reduced phi grid
358
+     */
359
+    Eigen::SparseMatrix<Complex, Eigen::ColMajor>*                  Cvec_s;
360
+    Eigen::SparseMatrix<Complex, Eigen::ColMajor>                   D_s;
361
+
362
+    /** number of cells in x, set when RectilinearGrid is attached */
363
+    int nx;
364
+
365
+    /** number of cells in y, set when RectilinearGrid is attached */
366
+    int ny;
367
+
368
+    /** number of cells in z, set when RectilinearGrid is attached */
369
+    int nz;
370
+
371
+    /** number of fields/faces in x, unwrapped x */
372
+    int unx;
373
+
374
+    /** number of fields/faces in y, unwrapped y */
375
+    int uny;
376
+
377
+    /** number of fields/faces in z, unwrapped z */
378
+    int unz;
379
+
380
+    /** number of cell centres, unwrapped scalars */
381
+    int uns;
382
+
383
+    /** name for log files and VTK files */
384
+    std::string ResFile;
385
+
386
+    /** frequency of source */
387
+    VectorXr Omegas;
388
+
389
+    /** Conductivity model */
390
+    //Complex ***sigma_jwe;
391
+    Real ***sigma;
392
+
393
+    /** Conductivity model minus reference model */
394
+    //Complex ***sigmap;
395
+    Real ***sigmap;
396
+
397
+    /** rectilinear grid spacing in x */
398
+    VectorXr hx;
399
+
400
+    /** rectilinear grid spacing in y */
401
+    VectorXr hy;
402
+
403
+    /** rectilinear grid spacing in z */
404
+    VectorXr hz;
405
+
406
+    /** inverse of hx */
407
+    VectorXr ihx;
408
+
409
+    /** inverse of hx squared */
410
+    VectorXr ihx2;
411
+
412
+    /** inverse of hy */
413
+    VectorXr ihy;
414
+
415
+    /** inverse of hy squared */
416
+    VectorXr ihy2;
417
+
418
+    /** inverse of hz */
419
+    VectorXr ihz;
420
+
421
+    /** inverse of hz squared */
422
+    VectorXr ihz2;
423
+
424
+    /** Marker for air cells */
425
+    VectorXi MAC;
426
+
427
+    /** Marker for air cells */
428
+    std::vector<int> idx;
429
+
430
+    private:
431
+
432
+        static constexpr auto CName = "EMSchur3DBase";
433
+
434
+}; // -----  end of class  EMSchur3DBase  -----
435
+
436
+}
437
+
438
+#endif   // ----- #ifndef EMSCHUR3BASE_INC  -----

+ 936
- 0
include/bicgstab.h View File

@@ -0,0 +1,936 @@
1
+// ===========================================================================
2
+//
3
+//       Filename:  bicgstab.h
4
+//
5
+//    Description:
6
+//
7
+//        Version:  0.0
8
+//        Created:  10/27/2009 03:15:06 PM
9
+//       Revision:  none
10
+//       Compiler:  g++ (c++)
11
+//
12
+//         Author:  Trevor Irons (ti)
13
+//
14
+//   Organisation:  Colorado School of Mines (CSM)
15
+//                  United States Geological Survey (USGS)
16
+//
17
+//          Email:  tirons@mines.edu, tirons@usgs.gov
18
+//
19
+//  This program is free software: you can redistribute it and/or modify
20
+//  it under the terms of the GNU General Public License as published by
21
+//  the Free Software Foundation, either version 3 of the License, or
22
+//  (at your option) any later version.
23
+//
24
+//  This program is distributed in the hope that it will be useful,
25
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
26
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
27
+//  GNU General Public License for more details.
28
+//
29
+//  You should have received a copy of the GNU General Public License
30
+//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
31
+//
32
+// ===========================================================================
33
+
34
+#include <Eigen/Core>
35
+#include <Eigen/Sparse>
36
+
37
+#ifdef CHOLMODPRECONDITION
38
+#include <Eigen/CholmodSupport>
39
+#endif // CHOLMODPRECONDITION
40
+
41
+//#include "unsupported/Eigen/IterativeSolvers"
42
+//#include <unsupported/Eigen/SuperLUSupport>
43
+
44
+#include <iostream>
45
+#include <string>
46
+#include <complex>
47
+#include <fstream>
48
+#include "lemma.h"
49
+#include "timer.h"
50
+
51
+using namespace Eigen;
52
+using namespace Lemma;
53
+
54
+//typedef Eigen::VectorXcd VectorXcr;
55
+typedef Eigen::SparseMatrix<Complex> SparseMat;
56
+
57
+
58
+// On Input
59
+// A = Matrix
60
+// B = Right hand side
61
+// X = initial guess, and solution
62
+// maxit = maximum Number of iterations
63
+// tol = error tolerance
64
+// On Output
65
+// X real solution vector
66
+// errorn = Real error norm
67
+int bicgstab(const SparseMat &A, const SparseMat &M, const VectorXcr &b, VectorXcr &x,
68
+                int &max_it, Real &tol, Real &errorn, int &iter_done,
69
+                const bool& banner = true) {
70
+
71
+    Complex omega, rho, rho_1, alpha, beta;
72
+    Real bnrm2, eps, errmin;
73
+    int n, iter; //, istat;
74
+
75
+    // Determine size of system and init vectors
76
+    n = x.size();
77
+    VectorXcr r(n);
78
+    VectorXcr r_tld(n);
79
+    VectorXcr p(n);
80
+    VectorXcr v(n);
81
+    VectorXcr p_hat(n);
82
+    VectorXcr s(n);
83
+    VectorXcr s_hat(n);
84
+    VectorXcr t(n);
85
+    VectorXcr xmin(n);
86
+
87
+    if (banner) {
88
+        std::cout << "Start BiCGStab, memory needed: "
89
+                  <<  (sizeof(Complex)*(9+2)*n/(1024.*1024*1024)) << " [Gb]\n";
90
+    }
91
+
92
+    // Initialise
93
+    iter_done = 0;
94
+    v.setConstant(0.); // not necessary I don't think
95
+    t.setConstant(0.);
96
+    eps = 1e-100;
97
+
98
+    bnrm2 = b.norm();
99
+    if (bnrm2 == 0) {
100
+        x.setConstant(0.0);
101
+        errorn = 0;
102
+        std::cerr << "Trivial case of Ax = b, where b is 0\n";
103
+        return (0);
104
+    }
105
+
106
+    // If there is an initial guess
107
+    if ( x.norm() ) {
108
+        r = b - A.selfadjointView<Eigen::Upper>()*x;
109
+        //r = b - A*x;
110
+    } else {
111
+        r = b;
112
+    }
113
+
114
+    errorn = r.norm() / bnrm2;
115
+    omega = 1.;
116
+    r_tld = r;
117
+    errmin = 1e30;
118
+
119
+    // Get down to business
120
+    for (iter=0; iter<max_it; ++iter) {
121
+
122
+        rho = r_tld.dot(r);
123
+        if ( abs(rho) < eps) return (0);
124
+
125
+        if (iter > 0) {
126
+            beta = (rho/rho_1) * (alpha/omega);
127
+            p = r.array() + beta*(p.array()-omega*v.array()).array();
128
+        } else {
129
+            p = r;
130
+        }
131
+
132
+        // Use pseudo inverse to get approximate answer
133
+        //#pragma omp sections
134
+        p_hat = M*p;
135
+        //v = A*p_hat; // TODO double check
136
+        v = A.selfadjointView<Eigen::Upper>()*p_hat; // TODO double check
137
+
138
+        alpha = rho / r_tld.dot(v);
139
+        s = r.array() - alpha*v.array();
140
+        errorn = s.norm()/bnrm2;
141
+
142
+        if (errorn < tol && iter > 1) {
143
+            x.array() += alpha*p_hat.array();
144
+            return (0);
145
+        }
146
+
147
+        s_hat = M*s;
148
+        t = A.selfadjointView<Eigen::Upper>()*s_hat;
149
+        //t = A*s_hat;
150
+
151
+        omega = t.dot(s)  / t.dot(t);
152
+        x.array() += alpha*p_hat.array() + omega*s_hat.array();
153
+        r = s.array() - omega*t.array();
154
+        errorn = r.norm() / bnrm2;
155
+        iter_done = iter;
156
+
157
+        if (errorn < errmin) {
158
+            // remember the model with the smallest norm
159
+            errmin = errorn;
160
+            xmin = x;
161
+        }
162
+
163
+        if ( errorn <= tol ) return (0);
164
+        if ( abs(omega) < eps ) return (0);
165
+        rho_1 = rho;
166
+
167
+    }
168
+    return (0);
169
+}
170
+
171
+template <typename Preconditioner>
172
+bool preconditionedBiCGStab(const SparseMat &A, const Preconditioner &M,
173
+        const Ref< VectorXcr const > b,
174
+        Ref <VectorXcr > x,
175
+        const int &max_it, const Real &tol,
176
+        Real &errorn, int &iter_done) {
177
+
178
+    Complex omega, rho, rho_1, alpha, beta;
179
+    Real bnrm2, eps;
180
+    int n, iter;
181
+    Real tol2 = tol*tol;
182
+
183
+    // Determine size of system and init vectors
184
+    n = x.size();
185
+
186
+    VectorXcd r(n);
187
+    VectorXcd r_tld(n);
188
+    VectorXcd p(n);
189
+    VectorXcd s(n);
190
+    VectorXcd s_hat(n);
191
+    VectorXcd p_hat(n);
192
+    VectorXcd v = VectorXcr::Zero(n);
193
+    VectorXcd t = VectorXcr::Zero(n);
194
+
195
+    //std::cout << "Start BiCGStab, memory needed: "
196
+    //          <<  (sizeof(Complex)*(8+2)*n/(1024.*1024)) / (1024.) << " [Gb]\n";
197
+
198
+    // Initialise
199
+    iter_done = 0;
200
+    eps = 1e-100;
201
+
202
+    bnrm2 = b.squaredNorm();
203
+    if (bnrm2 == 0) {
204
+        x.setConstant(0.0);
205
+        errorn = 0;
206
+        std::cerr << "Trivial case of Ax = b, where b is 0\n";
207
+        return (false);
208
+    }
209
+
210
+    // If there is an initial guess
211
+    if ( x.squaredNorm() ) {
212
+        r = b - A.selfadjointView<Eigen::Upper>()*x;
213
+    } else {
214
+        r = b;
215
+    }
216
+
217
+    errorn = r.squaredNorm() / bnrm2;
218
+    omega = 1.;
219
+    r_tld = r;
220
+
221
+    // Get down to business
222
+    for (iter=0; iter<max_it; ++iter) {
223
+
224
+        rho = r_tld.dot(r);
225
+        if (abs(rho) < eps) {
226
+            std::cerr << "arbitrary orthogonality issue in bicgstab\n";
227
+            std::cerr << "consider eigen restarting\n";
228
+            return (false);
229
+        }
230
+
231
+        if (iter > 0) {
232
+            beta = (rho/rho_1) * (alpha/omega);
233
+            p = r + beta*(p-omega*v);
234
+        } else {
235
+            p = r;
236
+        }
237
+
238
+        p_hat = M.solve(p);
239
+        v.noalias() = A.selfadjointView<Eigen::Upper>()*p_hat;
240
+
241
+        alpha = rho / r_tld.dot(v);
242
+        s = r - alpha*v;
243
+        errorn = s.squaredNorm()/bnrm2;
244
+
245
+        if (errorn < tol2 && iter > 1) {
246
+            x = x + alpha*p_hat;
247
+            errorn = std::sqrt(errorn);
248
+            return (true);
249
+        }
250
+
251
+        s_hat = M.solve(s);
252
+        t.noalias() = A.selfadjointView<Eigen::Upper>()*s_hat;
253
+
254
+        omega = t.dot(s)  / t.dot(t);
255
+        x += alpha*p_hat + omega*s_hat;
256
+        r = s - omega*t;
257
+        errorn = r.squaredNorm() / bnrm2;
258
+        iter_done = iter;
259
+
260
+        if ( errorn <= tol2 || abs(omega) < eps) {
261
+            errorn = std::sqrt(errorn);
262
+            return (true);
263
+        }
264
+
265
+        rho_1 = rho;
266
+    }
267
+    return (false);
268
+}
269
+
270
+template <typename Preconditioner>
271
+bool preconditionedSCBiCG(const SparseMat &A, const Preconditioner &M,
272
+        const Ref< VectorXcr const > b,
273
+        Ref <VectorXcr > x,
274
+        const int &max_iter, const Real &tol,
275
+        Real &errorn, int &iter_done) {
276
+
277
+    Real resid;
278
+    VectorXcr p, z, q;
279
+    Complex alpha, beta, rho, rho_1;
280
+
281
+    Real normb = b.norm( );
282
+    VectorXcr r = b - A*x;
283
+
284
+    if (normb == 0.0) normb = 1;
285
+
286
+    if ((resid = r.norm( ) / normb) <= tol) {
287
+        errorn = resid;
288
+        iter_done = 0;
289
+        return 0;
290
+    }
291
+
292
+    for (int i = 1; i <= max_iter; i++) {
293
+        z = M.solve(r);
294
+        rho = r.dot(z);
295
+
296
+        if (i == 1)  p = z;
297
+        else {
298
+            beta = rho / rho_1;
299
+            p = z + beta * p;
300
+        }
301
+
302
+        q = A*p;
303
+        alpha = rho / p.dot(q);
304
+
305
+        x += alpha * p;
306
+        r -= alpha * q;
307
+        std::cout << "resid\t" << resid << std::endl;
308
+        if ((resid = r.norm( ) / normb) <= tol) {
309
+            errorn = resid;
310
+            iter_done = i;
311
+            return 0;
312
+        }
313
+
314
+        rho_1 = rho;
315
+    }
316
+
317
+    errorn = resid;
318
+
319
+    return (false);
320
+}
321
+
322
+
323
+/** \internal Low-level conjugate gradient algorithm
324
+  * \param mat The matrix A
325
+  * \param rhs The right hand side vector b
326
+  * \param x On input and initial solution, on output the computed solution.
327
+  * \param precond A preconditioner being able to efficiently solve for an
328
+  *                approximation of Ax=b (regardless of b)
329
+  * \param iters On input the max number of iteration, on output the number of performed iterations.
330
+  * \param tol_error On input the tolerance error, on output an estimation of the relative error.
331
+  */
332
+template<typename Rhs, typename Dest, typename Preconditioner>
333
+EIGEN_DONT_INLINE
334
+void conjugateGradient(const SparseMat& mat, const Rhs& rhs, Dest& x,
335
+                        const Preconditioner& precond, int& iters,
336
+                        typename Dest::RealScalar& tol_error)
337
+{
338
+  using std::sqrt;
339
+  using std::abs;
340
+  typedef typename Dest::RealScalar RealScalar;
341
+  typedef typename Dest::Scalar Scalar;
342
+  typedef Matrix<Scalar,Dynamic,1> VectorType;
343
+
344
+  RealScalar tol = tol_error;
345
+  int maxIters = iters;
346
+
347
+  int n = mat.cols();
348
+
349
+  VectorType residual = rhs - mat.selfadjointView<Eigen::Upper>() * x; //initial residual
350
+
351
+  RealScalar rhsNorm2 = rhs.squaredNorm();
352
+  if(rhsNorm2 == 0)
353
+  {
354
+    x.setZero();
355
+    iters = 0;
356
+    tol_error = 0;
357
+    return;
358
+  }
359
+  RealScalar threshold = tol*tol*rhsNorm2;
360
+  RealScalar residualNorm2 = residual.squaredNorm();
361
+  if (residualNorm2 < threshold)
362
+  {
363
+    iters = 0;
364
+    tol_error = sqrt(residualNorm2 / rhsNorm2);
365
+    return;
366
+  }
367
+
368
+  VectorType p(n);
369
+  p = precond.solve(residual);      //initial search direction
370
+
371
+  VectorType z(n), tmp(n);
372
+  RealScalar absNew = numext::real(residual.dot(p));  // the square of the absolute value of r scaled by invM
373
+  int i = 0;
374
+  while(i < maxIters)
375
+  {
376
+    tmp.noalias() = mat.selfadjointView<Eigen::Upper>() * p;              // the bottleneck of the algorithm
377
+
378
+    Scalar alpha = absNew / p.dot(tmp);   // the amount we travel on dir
379
+    x += alpha * p;                       // update solution
380
+    residual -= alpha * tmp;              // update residue
381
+
382
+    residualNorm2 = residual.squaredNorm();
383
+    if(residualNorm2 < threshold)
384
+      break;
385
+
386
+    z = precond.solve(residual);          // approximately solve for "A z = residual"
387
+
388
+    RealScalar absOld = absNew;
389
+    absNew = numext::real(residual.dot(z));     // update the absolute value of r
390
+    RealScalar beta = absNew / absOld;            // calculate the Gram-Schmidt value used to create the new search direction
391
+    p = z + beta * p;                             // update search direction
392
+    i++;
393
+  }
394
+  tol_error = sqrt(residualNorm2 / rhsNorm2);
395
+  iters = i;
396
+}
397
+
398
+// // Computes implicit
399
+// VectorXcr implicitDCInvBPhi (const SparseMat& D, const SparseMat& C,
400
+//                         const SparseMat& B, const SparseMat& MC,
401
+//                         const VectorXcr& Phi, Real& tol,
402
+//                         int& max_it) {
403
+//     int iter_done(0);
404
+//     Real errorn(0);
405
+//     VectorXcr b = B*Phi;
406
+//     VectorXcr y = VectorXcr::Zero(C.rows()) ; // = C^1*b;
407
+//     bicgstab(C, MC, b, y, max_it, tol, errorn, iter_done, false);
408
+//     //std::cout << "Temp " << errorn << std::endl;
409
+//     return  D*y;
410
+// }
411
+
412
+// Computes implicit
413
+VectorXcr implicitDCInvBPhi (const SparseMat& D, const SparseMat& C,
414
+                        const VectorXcr& ioms, const SparseMat& MC,
415
+                        const VectorXcr& Phi, Real& tol,
416
+                        int& max_it) {
417
+    int iter_done(0);
418
+    Real errorn(0);
419
+    VectorXcr b = (ioms).asDiagonal() * (D.transpose()*Phi);
420
+    VectorXcr y = VectorXcr::Zero(C.rows()) ; // = C^1*b;
421
+    bicgstab(C, MC, b, y, max_it, tol, errorn, iter_done, false);
422
+    //std::cout << "Temp " << errorn << std::endl;
423
+    max_it = iter_done;
424
+    return  D*y;
425
+}
426
+
427
+// Computes implicit
428
+template <typename Preconditioner>
429
+VectorXcr implicitDCInvBPhi2 (const SparseMat& D, const SparseMat& C,
430
+                        const Ref<VectorXcr const> ioms, const Preconditioner& solver,
431
+                        const Ref<VectorXcr const> Phi, Real& tol,
432
+                        int& max_it) {
433
+
434
+    VectorXcr b = (ioms).asDiagonal() * (D.transpose()*Phi);
435
+    VectorXcr y = VectorXcr::Zero(C.rows()) ; // = C^1*b;
436
+
437
+    // Home Made
438
+    //int iter_done(0);
439
+    //Real errorn(0);
440
+    //preconditionedBiCGStab(C, solver, b, y, max_it, tol, errorn, iter_done); //, false); // Jacobi M
441
+    //max_it = iter_done;
442
+
443
+    // Eigen BiCGStab
444
+    Eigen::BiCGSTAB<SparseMatrix<Complex> > BiCG;
445
+    BiCG.compute( C ); // TODO move this out of this loop!
446
+    y = BiCG.solve(b);
447
+    max_it = BiCG.iterations();
448
+    tol = BiCG.error();
449
+
450
+    // Direct
451
+/*
452
+    std::cout << "Computing LLT" << std::endl;
453
+    Eigen::SimplicialLLT<SparseMatrix<Complex>, Eigen::Upper, Eigen::AMDOrdering<int> >  LLT;
454
+    LLT.compute(C);
455
+    max_it = 1;
456
+    std::cout << "Computed LLT" << std::endl;
457
+    y = LLT.solve(b);
458
+*/
459
+
460
+    return  D*y;
461
+}
462
+
463
+// Computes implicit
464
+//template <typename Solver>
465
+template < typename Solver >
466
+inline VectorXcr implicitDCInvBPhi3 (const SparseMat& D, const Solver& solver,
467
+                        const Ref<VectorXcr const> ioms,
468
+                        const Ref<VectorXcr const> Phi, Real& tol,
469
+                        int& max_it) {
470
+    VectorXcr b = (ioms).asDiagonal() * (D.transpose()*Phi);
471
+    VectorXcr y = solver.solve(b);
472
+    max_it = 0;
473
+    //max_it = solver.iterations();
474
+    //errorn = solver.error();
475
+    return  D*y;
476
+}
477
+
478
+
479
+// // Simple extraction of indices in idx into reduceed array x1
480
+// void vmap( const Ref<VectorXcr const> x0, Ref<VectorXcr> x1, const std::vector<int>& idx ) {
481
+//     for (unsigned int ii=0; ii<idx.size(); ++ii) {
482
+//         x1(ii) = x0(idx[ii]);
483
+//     }
484
+// }
485
+
486
+// Simple extraction of indices in idx into reduceed array x1
487
+VectorXcr vmap( const Ref<VectorXcr const> x0, const std::vector<int>& idx ) {
488
+    VectorXcr x1 = VectorXcr::Zero( idx.size() );
489
+    for (unsigned int ii=0; ii<idx.size(); ++ii) {
490
+        x1(ii) = x0(idx[ii]);
491
+    }
492
+    return x1;
493
+}
494
+
495
+// reverse of above
496
+void ivmap( Ref<VectorXcr > x0, const Ref<VectorXcr const> x1, const std::vector<int>& idx ) {
497
+    for (unsigned int ii=0; ii<idx.size(); ++ii) {
498
+        x0(idx[ii]) = x1(ii);
499
+    }
500
+}
501
+
502
+
503
+// On Input
504
+// A = Matrix
505
+// B = Right hand side
506
+// X = initial guess, and solution
507
+// maxit = maximum Number of iterations
508
+// tol = error tolerance
509
+// On Output
510
+// X real solution vector
511
+// errorn = Real error norm
512
+template < typename CSolver >
513
+int implicitbicgstab(//const SparseMat& D,
514
+                     //const SparseMat& C,
515
+                     const Ref< Eigen::SparseMatrix<Complex> const > D,
516
+                     const std::vector<int>& idx,
517
+                     const Ref< VectorXcr const > ioms,
518
+                     const Ref< VectorXcr const > rhs,
519
+                     Ref <VectorXcr> phi,
520
+                     CSolver& solver,
521
+                     int &max_it, const Real &tol, Real &errorn, int &iter_done, ofstream& logio) {
522
+
523
+    logio << "using the preconditioned implicit solver" << std::endl;
524
+
525
+    Complex omega, rho, rho_1, alpha, beta;
526
+    Real    tol2;
527
+    int     iter, max_it2, max_it1;
528
+
529
+    // Look at reduced problem
530
+    VectorXcr rhs2 = vmap(rhs, idx);
531
+    VectorXcr phi2 = vmap(phi, idx);
532
+
533
+    // Determine size of system and init vectors
534
+    int n = idx.size();        // was phi.size();
535
+    VectorXcr r(n);
536
+    VectorXcr r_tld(n);
537
+    VectorXcr p(n);
538
+    VectorXcr s(n);
539
+    VectorXcr v = VectorXcr::Zero(n);
540
+    VectorXcr t = VectorXcr::Zero(n);
541
+
542
+//     TODO, refigure for implicit large system
543
+//     std::cout << "Start BiCGStab, memory needed: "
544
+//               <<  (sizeof(Complex)*(9+2)*n/(1024.*1024*1024)) << " [Gb]\n";
545
+
546
+    // Initialise
547
+    iter_done = 0;
548
+    Real eps = 1e-100;
549
+
550
+    Real bnrm2 = rhs.norm();
551
+    if (bnrm2 == 0) {
552
+        phi.setConstant(0.0);
553
+        errorn = 0;
554
+        std::cerr << "Trivial case of Ax = b, where b is 0\n";
555
+        return (0);
556
+    }
557
+
558
+    // If there is an initial guess
559
+    if ( phi.norm() ) {
560
+        tol2 = tol;
561
+        max_it2 = 50000;
562
+        //r = rhs - implicitDCInvBPhi3(D, solver, ioms, phi, tol2, max_it2);
563
+        //r = rhs - implicitDCInvBPhi3(D, solver, ioms, phi, tol2, max_it2);
564
+        r = rhs2 - vmap( implicitDCInvBPhi3(D, solver, ioms, phi, tol2, max_it2), idx );
565
+    } else {
566
+        r = vmap(rhs, idx);
567
+    }
568
+
569
+    jsw_timer timer;
570
+
571
+    errorn = r.norm() / bnrm2;
572
+    omega = 1.;
573
+    r_tld = r;
574
+    Real errornold = 1e14;
575
+    // Get down to business
576
+    for (iter=0; iter<max_it; ++iter) {
577
+
578
+        timer.begin();
579
+
580
+        rho = r_tld.dot(r);
581
+        if (abs(rho) < eps) {
582
+            ivmap( phi, phi2, idx );
583
+            return (0);
584
+        }
585
+
586
+        if (iter > 0) {
587
+            beta = (rho/rho_1) * (alpha/omega);
588
+            p = r.array() + beta*(p.array()-omega*v.array()).array();
589
+        } else {
590
+            p = r;
591
+        }
592
+
593
+        tol2 = tol;
594
+
595
+        max_it2 = 500000;
596
+        //v = implicitDCInvBPhi2(D, C, ioms, solver, p, tol2, max_it2);
597
+        ivmap(phi, p, idx);
598
+        v = vmap(implicitDCInvBPhi3(D, solver, ioms, phi, tol2, max_it2), idx);
599
+
600
+        alpha = rho / r_tld.dot(v);
601
+        s = r.array() - alpha*v.array();
602
+        errorn = s.norm()/bnrm2;
603
+
604
+        if (errorn < tol && iter > 1) {
605
+            phi2.array() += alpha*p.array();
606
+            ivmap( phi, phi2, idx );
607
+            return (0);
608
+        }
609
+
610
+        tol2 = tol;
611
+
612
+        max_it1 = 500000;
613
+        //t = implicitDCInvBPhi2(D, C, ioms, solver, s, tol2, max_it1);
614
+        //t = implicitDCInvBPhi3(D, solver, ioms, s, tol2, max_it1);
615
+        ivmap(phi, s, idx);
616
+        t = vmap(implicitDCInvBPhi3(D, solver, ioms, phi, tol2, max_it1), idx);
617
+        omega = t.dot(s)  / t.dot(t);
618
+
619
+        r = s.array() - omega*t.array();
620
+        errorn = r.norm() / bnrm2;
621
+        iter_done = iter;
622
+
623
+        if (errorn <= tol) {
624
+            ivmap( phi, phi2, idx );
625
+            return (0);
626
+        }
627
+
628
+        if (abs(omega) < eps) {
629
+            ivmap( phi, phi2, idx );
630
+            return (0);
631
+        }
632
+
633
+        rho_1 = rho;
634
+
635
+        logio << "iteration " << std::setw(3) << iter
636
+              << "  errorn " << std::setw(6) << std::setprecision(4) << std::scientific << errorn
637
+              //<< "\timplicit iterations " << std::setw(5) << max_it1+max_it2
638
+              << "  time " << std::setw(6) << std::fixed << std::setprecision(2) << timer.end() << std::endl;
639
+
640
+        // Check to see how progress is going
641
+
642
+        if (errornold - errorn < 0) {
643
+            logio << "Irregular non-monotonic (negative) convergence. Recommend restart. \n";
644
+            ivmap( phi, phi2, idx );
645
+            return (2);
646
+        }
647
+
648
+        /*
649
+        if (errornold - errorn < 1e-14) {
650
+            logio << "not making any progress. Giving up\n";
651
+            return (1);
652
+        }
653
+        */
654
+
655
+        //std::cout << "|| p-s ||" << (alpha*p - omega*s).norm() << std::endl;
656
+
657
+        // only update phi if good things are happening
658
+        phi2.array() += alpha*p.array() + omega*s.array();
659
+        errornold = errorn;
660
+
661
+    }
662
+    ivmap( phi, phi2, idx );
663
+    return (0);
664
+}
665
+
666
+// On Input
667
+// A = Matrix
668
+// B = Right hand side
669
+// X = initial guess, and solution
670
+// maxit = maximum Number of iterations
671
+// tol = error tolerance
672
+// On Output
673
+// X real solution vector
674
+// errorn = Real error norm
675
+template < typename Solver >
676
+int implicitbicgstab_ei(const SparseMat&  D,
677
+                        const Ref< VectorXcr const > ioms,
678
+                        const Ref< VectorXcr const > rhs,
679
+                        Ref <VectorXcr> phi,
680
+                        Solver& solver,
681
+                        int &max_it, const Real &tol, Real &errorn, int &iter_done, ofstream& logio) {
682
+
683
+    logio << "using the preconditioned Eigen implicit solver" << std::endl;
684
+
685
+    Complex omega, rho, rho_1, alpha, beta;
686
+    Real tol2;
687
+    int  iter, max_it2,max_it1;
688
+
689
+    // Determine size of system and init vectors
690
+    int n = phi.size();
691
+    VectorXcr r(n);
692
+    VectorXcr r_tld(n);
693
+    VectorXcr p(n);
694
+    VectorXcr v(n);
695
+    VectorXcr s(n);
696
+    VectorXcr t(n);
697
+
698
+    // Initialise
699
+    iter_done = 0;
700
+    Real eps = 1e-100;
701
+
702
+    Real bnrm2 = rhs.norm();
703
+    if (bnrm2 == 0) {
704
+        phi.setConstant(0.0);
705
+        errorn = 0;
706
+        std::cerr << "Trivial case of Ax = b, where b is 0\n";
707
+        return (0);
708
+    }
709
+
710
+    // If there is an initial guess
711
+    if ( phi.norm() ) {
712
+        tol2 = tol;
713
+        max_it2 = 50000;
714
+        r = rhs - implicitDCInvBPhi3(D, solver, ioms, phi, tol2, max_it2);
715
+    } else {
716
+        r = rhs;
717
+    }
718
+
719
+    jsw_timer timer;
720
+
721
+    errorn = r.norm() / bnrm2;
722
+    omega = 1.;
723
+    r_tld = r;
724
+    Real errornold = 1e14;
725
+
726
+    // Get down to business
727
+    for (iter=0; iter<max_it; ++iter) {
728
+
729
+        timer.begin();
730
+
731
+        rho = r_tld.dot(r);
732
+        if (abs(rho) < eps) return (0);
733
+
734
+        if (iter > 0) {
735
+            beta = (rho/rho_1) * (alpha/omega);
736
+            p = r.array() + beta*(p.array()-omega*v.array()).array();
737
+        } else {
738
+            p = r;
739
+        }
740
+
741
+        tol2 = tol;
742
+        max_it2 = 500000;
743
+        v = implicitDCInvBPhi3(D, solver, ioms, p, tol2, max_it2);
744
+        max_it2 = 0; // solver.iterations();
745
+
746
+        alpha = rho / r_tld.dot(v);
747
+        s = r.array() - alpha*v.array();
748
+        errorn = s.norm()/bnrm2;
749
+
750
+        if (errorn < tol && iter > 1) {
751
+            phi.array() += alpha*p.array();
752
+            return (0);
753
+        }
754
+
755
+        tol2 = tol;
756
+        max_it1 = 500000;
757
+        t = implicitDCInvBPhi3(D, solver, ioms, s, tol2, max_it1);
758
+        max_it1 = 0; //solver.iterations();
759
+        omega = t.dot(s)  / t.dot(t);
760
+
761
+        r = s.array() - omega*t.array();
762
+        errorn = r.norm() / bnrm2;
763
+        iter_done = iter;
764
+
765
+        if (errorn <= tol ) return (0);
766
+        if (abs(omega) < eps) return (0);
767
+        rho_1 = rho;
768
+
769
+        logio << "iteration " << std::setw(4) << iter
770
+              << "\terrorn " << std::setw(6) << std::setprecision(4) << std::scientific << errorn
771
+              << "\timplicit iterations " << std::setw(5) << max_it1+max_it2
772
+              << "\ttime " << std::setw(10) << std::fixed << std::setprecision(2) << timer.end() << std::endl;
773
+
774
+        // Check to see how progress is going
775
+        if (errornold - errorn < 0) {
776
+            logio << "irregular (negative) convergence. Try again? \n";
777
+            return (2);
778
+        }
779
+
780
+        // only update phi if good things are happening
781
+        phi.array() += alpha*p.array() + omega*s.array();
782
+        errornold = errorn;
783
+
784
+    }
785
+    return (0);
786
+}
787
+
788
+
789
+// On Input
790
+// A = Matrix
791
+// B = Right hand side
792
+// X = initial guess, and solution
793
+// maxit = maximum Number of iterations
794
+// tol = error tolerance
795
+// On Output
796
+// X real solution vector
797
+// errorn = Real error norm
798
+int implicitbicgstab(const SparseMat& D,
799
+                     const SparseMat& C,
800
+                     const VectorXcr& ioms,
801
+                     const SparseMat& MC,
802
+                     Eigen::Ref< VectorXcr > rhs,
803
+                     VectorXcr& phi,
804
+                     int &max_it, Real &tol, Real &errorn, int &iter_done) {
805
+
806
+    Complex omega, rho, rho_1, alpha, beta;
807
+    Real errmin, tol2;
808
+    int  iter, max_it2;
809
+
810
+//     // Cholesky decomp
811
+//     SparseLLT<SparseMatrix<Complex>, Cholmod>
812
+//         CholC(SparseMatrix<Complex> (C.real()) );
813
+//     if(!CholC.succeeded()) {
814
+//         std::cerr << "decomposiiton failed\n";
815
+//         return EXIT_FAILURE;
816
+//     }
817
+
818
+    // Determine size of system and init vectors
819
+    int n = phi.size();
820
+    VectorXcr r(n);
821
+    VectorXcr r_tld(n);
822
+    VectorXcr p(n);
823
+    VectorXcr v(n);
824
+    //VectorXcr p_hat(n);
825
+    VectorXcr s(n);
826
+    //VectorXcr s_hat(n);
827
+    VectorXcr t(n);
828
+    VectorXcr xmin(n);
829
+
830
+//     TODO, refigure for implicit large system
831
+//     std::cout << "Start BiCGStab, memory needed: "
832
+//               <<  (sizeof(Complex)*(9+2)*n/(1024.*1024*1024)) << " [Gb]\n";
833
+
834
+    // Initialise
835
+    iter_done = 0;
836
+    v.setConstant(0.); // not necessary I don't think
837
+    t.setConstant(0.);
838
+    Real eps = 1e-100;
839
+
840
+    Real bnrm2 = rhs.norm();
841
+    if (bnrm2 == 0) {
842
+        phi.setConstant(0.0);
843
+        errorn = 0;
844
+        std::cerr << "Trivial case of Ax = b, where b is 0\n";
845
+        return (0);
846
+    }
847
+
848
+    // If there is an initial guess
849
+    if ( phi.norm() ) {
850
+        //r = rhs - A*phi;
851
+        tol2 = tol;
852
+        max_it2 = 50000;
853
+        std::cout << "Initial guess " << std::endl;
854
+        r = rhs - implicitDCInvBPhi(D, C, ioms, MC, phi, tol2, max_it2);
855
+        //r = rhs - implicitDCInvBPhi (D, C, B, CholC, phi, tol2, max_it2);
856
+    } else {
857
+        r = rhs;
858
+    }
859
+
860
+
861
+    errorn = r.norm() / bnrm2;
862
+    //std::cout << "Initial |r|  " << r.norm() << "\t" << errorn<< std::endl;
863
+    omega = 1.;
864
+    r_tld = r;
865
+    errmin = 1e30;
866
+    Real errornold = 1e6;
867
+    // Get down to business
868
+    for (iter=0; iter<max_it; ++iter) {
869
+
870
+        rho = r_tld.dot(r);
871
+        if (abs(rho) < eps) return (0);
872
+
873
+        if (iter > 0) {
874
+            beta = (rho/rho_1) * (alpha/omega);
875
+            p = r.array() + beta*(p.array()-omega*v.array()).array();
876
+        } else {
877
+            p = r;
878
+        }
879
+
880
+        // Use pseudo inverse to get approximate answer
881
+        //p_hat = p;
882
+        tol2  = std::max(1e-4*errorn, tol);
883
+        tol2 = tol;
884
+        max_it2 = 500000;
885
+        //v = A*p_hat;
886
+        v = implicitDCInvBPhi(D, C, ioms, MC, p, tol2, max_it2);
887
+        //v = implicitDCInvBPhi(D, C, B, CholC, p, tol2, max_it2);
888
+
889
+        alpha = rho / r_tld.dot(v);
890
+        s = r.array() - alpha*v.array();
891
+        errorn = s.norm()/bnrm2;
892
+
893
+        if (errorn < tol && iter > 1) {
894
+            phi.array() += alpha*p.array();
895
+            return (0);
896
+        }
897
+
898
+        // s_hat = M*s;
899
+        //tol2 = tol;
900
+        tol2  = std::max(1e-4*errorn, tol);
901
+        tol2 = tol;
902
+        max_it2 = 50000;
903
+        // t = A*s_hat;
904
+        t = implicitDCInvBPhi(D, C, ioms, MC, s, tol2, max_it2);
905
+        //t = implicitDCInvBPhi(D, C, B, CholC, s, tol2, max_it2);
906
+        omega = t.dot(s)  / t.dot(t);
907
+        phi.array() += alpha*p.array() + omega*s.array();
908
+        r = s.array() - omega*t.array();
909
+        errorn = r.norm() / bnrm2;
910
+        iter_done = iter;
911
+        if (errorn < errmin) {
912
+            // remember the model with the smallest norm
913
+            errmin = errorn;
914
+            xmin = phi;
915
+        }
916
+
917
+        if (errorn <= tol ) return (0);
918
+        if (abs(omega) < eps) return (0);
919
+        rho_1 = rho;
920
+
921
+        std::cout << "iteration " << std::setw(4) << iter << "\terrorn "  << std::setw(6) << std::scientific << errorn
922
+                  << "\timplicit iterations " << std::setw(5) << max_it2 << std::endl;
923
+        if (errornold - errorn < 1e-14) {
924
+            std::cout << "not making any progress. Giving up\n";
925
+            return (2);
926
+        }
927
+        errornold = errorn;
928
+
929
+    }
930
+    return (0);
931
+}
932
+
933
+
934
+//int bicgstab(const SparseMat &A, Eigen::SparseLU< Eigen::SparseMatrix<Complex, RowMajor> ,
935
+
936
+

+ 4
- 0
src/CMakeLists.txt View File

@@ -0,0 +1,4 @@
1
+set (EMSCHUR3DSOURCE
2
+	${CMAKE_CURRENT_SOURCE_DIR}/EMSchur3DBase.cpp
3
+	PARENT_SCOPE
4
+)

+ 1507
- 0
src/EMSchur3DBase.cpp
File diff suppressed because it is too large
View File


+ 0
- 0
testing/CMakeLists.txt View File


Loading…
Cancel
Save