src/eigsolv/LinearEigsolvOperators.cpp

Go to the documentation of this file.
00001 #include "myrlog.h"
00002 
00003 #include "ml_include.h"
00004 #include "EpetraExt_MatrixMatrix.h"
00005 #include "matrix_matrix.h"
00006 
00007 // for the ML Maxwell preconditioner...
00008 #if !defined(HAVE_ML_EPETRA) || !defined(HAVE_ML_TEUCHOS)
00009 #error Trilinos needs to be configured with --enable-epetra --enable-teuchos
00010 #endif
00011 #include "ml_epetra_preconditioner.h"
00012 #include "Teuchos_ParameterList.hpp"
00013 #include "Ifpack.h"
00014 #include "Ifpack_IC.h"
00015 
00016 #include "pbedefs.h"
00017 #include "OutputCapturer.h"
00018 
00019 #include "directsolveroperator.h"
00020 #include "BlockPCGSolver.h"
00021 #include "diagonalpreconditioner.h"
00022 #include "LinearEigsolvOperators.h"
00023 
00024 using namespace Teuchos;
00025 
00026 LinearEigsolvOperators::LinearEigsolvOperators(FemaxMesh& mesh_mixed,
00027                                                Teuchos::ParameterList& params,
00028                                                const Epetra_Comm& MyComm) :
00029     mesh_mixed_(mesh_mixed),
00030     Comm(MyComm),
00031     A(0),
00032     M(0),
00033     K(0),
00034     H(0),
00035     Y(0),
00036     C(0),
00037     Prec(0),
00038     h_solver_op_(0),
00039     HPrec(0),
00040     _sigma_K(0.0),
00041     params_(params),
00042     Aprec(0),
00043     AprecSolver(0)
00044 {
00045     matrixAssembly(mesh_mixed);
00046 }
00047 
00048 LinearEigsolvOperators::~LinearEigsolvOperators() {
00049     OutputCapturer capt;
00050     capt.begin_capture();
00051     
00052     delete Prec;
00053     delete h_solver_op_;
00054     delete HPrec;
00055     delete Aprec;
00056     delete AprecSolver;
00057     delete A;
00058     delete M;
00059     delete K;
00060     delete Y;
00061     delete H;
00062     delete C;
00063         
00064     capt.end_capture();
00065     // Logging empty strings causes a "[FMT ERROR]: failed to format msg" message in rlog
00066     if (capt.get_stdout().size() > 0)
00067         rDebug("%s", capt.get_stdout().c_str());
00068 }
00069 
00070 int LinearEigsolvOperators::buildPreconditioner(double sigma) {
00071     // construct K = A - sigma*M
00072     K = build_Asigma(*A, *M, sigma);
00073 
00074     if (params_.get<bool>("export_mtx")) {
00075         pbe_start(130, "MatrixMarket export");
00076         export_Epetra_CrsMatrix(*K, 15, "K.mtx");
00077         pbe_stop(130);
00078     }
00079 
00080     Teuchos::ParameterList& asigma_precon(params_.sublist("asigma_precon"));
00081     string asigma_precon_type = asigma_precon.get<string>("type");
00082     if (asigma_precon_type == "neumann") {
00083 
00084         // Setting the AZ_Neumann preconditioner
00085         Aprec = new Epetra_LinearProblem();
00086         Aprec->SetOperator(K);
00087 
00088         AprecSolver = new AztecOO(*Aprec);
00089 
00090         // Specify the preconditioner inside AztecOO
00091         AprecSolver->SetAztecOption(AZ_precond, AZ_Neumann);
00092         AprecSolver->SetAztecOption(AZ_poly_ord, 10);
00093 
00094         // Specify the output level
00095         AprecSolver->SetAztecOption(AZ_output, AZ_none);
00096 
00097         // Specify the iterative solver used
00098         AprecSolver->SetAztecOption(AZ_solver, AZ_gmres);
00099 
00100         // Define an operator for this preconditioner. Preconditioner is then called
00101         // using Prec->ApplyInverse(...).
00102         int iterAztec = 2;
00103         Prec = new AztecOO_Operator(AprecSolver, iterAztec);
00104 
00105     } else if (asigma_precon_type == "ml") {
00106 
00107         OutputCapturer capt;
00108         capt.begin_capture();
00109         Prec = new ML_Epetra::MultiLevelPreconditioner(*K, // A - sigma *M
00110                                                        *Y,
00111                                                        *H,
00112                                                        params_.sublist("asigma_precon").sublist("ml_params"),
00113                                                        false);
00114         dynamic_cast<ML_Epetra::MultiLevelPreconditioner*>(Prec)->ComputePreconditioner();
00115         capt.end_capture();
00116         rLog(RLOG_CHANNEL("debug/all"), "%s", capt.get_stdout().c_str());
00117 
00118         ostringstream buf;
00119         buf << "Unused ML parameters:" << endl;
00120         dynamic_cast<ML_Epetra::MultiLevelPreconditioner*>(Prec)->PrintUnused(buf);
00121         rDebug(buf.str().c_str());
00122 
00123         // The ML preconditioner is applied by Prec->ApplyInverse(...). The Apply() method is not
00124         // implemented.
00125 
00126     } else if (asigma_precon_type == "lu") {
00127 
00128         // Preconditioner is LU-factorisation of K = A -sigma*M
00129         Prec = new DirectSolverOperator(*K, params_.sublist("asigma_precon").sublist("amesos_params"));
00130 
00131     } else if (asigma_precon_type == "diag") {
00132 
00133         // Preconditioner is diagonal of K = A -sigma*M
00134         Prec = new DiagonalPreconditioner(*K);
00135 
00136     } else if (asigma_precon_type == "if") {
00137 
00138         // Preconditioner is incomplete LDLT-factorisation of K = A -sigma*M
00139     
00140         // allocates an IFPACK factory. No data is associated
00141         // to this object (only method Create()).
00142         Ifpack Factory;
00143     
00144         // Create the preconditioner. For valid PrecType values,
00145         // please check the documentation
00146         string PrecType = "IC stand-alone"; // incomplete LU
00147         // string PrecType = "IC"; // incomplete LU
00148         int OverlapLevel = 1; // must be >= 0. If Comm.NumProc() == 1,
00149                               // it is ignored.
00150         Prec = Factory.Create(PrecType, K, OverlapLevel);
00151         assert(Prec != 0);
00152     
00153         // Specify parameters for IC
00154         Teuchos::ParameterList List;
00155         List.set("fact: drop tolerance", 1e-2);
00156         List.set("fact: level-of-fill", 1);
00157         IFPACK_CHK_ERR(dynamic_cast<Ifpack_Preconditioner*>(Prec)->SetParameters(List));
00158     
00159         // Initialize the preconditioner. At this point the matrix must
00160         // have been FillComplete()'d, but actual values are ignored.
00161         IFPACK_CHK_ERR(dynamic_cast<Ifpack_Preconditioner*>(Prec)->Initialize());
00162     
00163         // Builds the preconditioners, by looking for the values of
00164         // the matrix.
00165         IFPACK_CHK_ERR(dynamic_cast<Ifpack_Preconditioner*>(Prec)->Compute());
00166         
00167         // Information about the preconditioner
00168         cout << *dynamic_cast<Ifpack_Preconditioner*>(Prec);
00169         Ifpack_IC* ic_prec = dynamic_cast<Ifpack_IC*>(Prec);
00170         if (ic_prec != 0)
00171             rInfo("#nonzeros of IF-preconditioner for K: %d", ic_prec->NumGlobalNonzeros());
00172     } else {
00173         rExit("Unknown preconditioner for A - sigma * M: %s", asigma_precon_type.c_str());
00174     }
00175 
00176     return(0);
00177 }
00178 
00179 void LinearEigsolvOperators::matrixAssembly(FemaxMesh& mesh_mixed) {
00180     
00181     NedelecMesh&  mesh_nedelec = mesh_mixed.get_nedelec_mesh();
00182     LagrangeMesh& mesh_lagrange = mesh_mixed.get_lagrange_mesh();
00183 
00184     // Create Epetra_Maps
00185 #if 1
00186     std::vector<int> owned_dofs;    // Epetra_Map expects int array
00187     for (mesh::id_t ldof = 0; ldof < mesh_nedelec.get_num_my_dofs(0); ++ ldof) {
00188         mesh::id_t gdof = mesh_nedelec.gdof(ldof);
00189         if (mesh_nedelec.is_owned_gdof(gdof)) {
00190             mesh::id_t mgdof = mesh_nedelec.map_dof(ldof);
00191             if (mgdof != mesh::ID_NONE)
00192                 owned_dofs.push_back(mgdof);
00193         }
00194     }
00195     Epetra_Map map_nedelec (-1, owned_dofs.size(), &owned_dofs[0], 0, Comm);
00196     
00197     owned_dofs.clear();
00198     for (mesh::id_t ldof = 0; ldof < mesh_lagrange.get_num_my_dofs(0); ++ ldof) {
00199         mesh::id_t gdof = mesh_lagrange.gdof(ldof);
00200         if (mesh_lagrange.is_owned_gdof(gdof)) {
00201             mesh::id_t mgdof = mesh_lagrange.map_dof(ldof);
00202             if (mgdof != mesh::ID_NONE)
00203                 owned_dofs.push_back(mgdof);
00204         }
00205     }
00206     Epetra_Map map_lagrange (-1, owned_dofs.size(), &owned_dofs[0], 0, Comm);
00207 #else
00208     //nof_mapped_elements
00209     vector<int> ned_dofs = mesh_nedelec.get_my_dofs();
00210     Epetra_Map map_nedelec (-1, ned_dofs.size(), &ned_dofs[0], 0, Comm);
00211 //     cout << map_nedelec;
00212     
00213     //  Create lagrange map in same way as nedelec map.
00214     vector<int> lag_dofs = mesh_lagrange.get_my_dofs();
00215     Epetra_Map map_lagrange (-1, lag_dofs.size(), &lag_dofs[0], 0, Comm);
00216     // cout << map_lagrange;
00217 #endif
00218 
00219     //
00220     // Matrix assembly
00221     //
00222     rInfo("Assemble finite element matrices...");
00223 
00224     // Allocate matrices A and M
00225     log_mem_footprint(Comm, "before matrix assembly");
00226     pbe_start(60, "assembly of A and M");
00227     A = new Epetra_FECrsMatrix(Copy, map_nedelec, false);
00228     M = new Epetra_FECrsMatrix(Copy, map_nedelec, false);
00229     mesh_nedelec.assembleAM(A, M);
00230     
00231     // Finish data entry
00232     // transforms to local index space, sorts column indices ans merges redundant entries
00233     A->FillComplete(map_nedelec, map_nedelec);
00234     M->FillComplete(map_nedelec, map_nedelec);
00235     pbe_stop(60);
00236     log_matrix_stats("Matrix A", A);
00237     log_matrix_stats("Matrix M", M);
00238     log_mem_footprint(Comm, "after assembly of A and M");
00239 
00240 //     Epetra_FECrsMatrix* A_s = new Epetra_FECrsMatrix(Copy, map_nedelec, false);
00241 //     Epetra_FECrsMatrix* M_s = new Epetra_FECrsMatrix(Copy, map_nedelec, false);
00242 //     mesh_nedelec.generate_sorted_AM(A, M, A_s, M_s);
00243     
00244 //     A_s->FillComplete(map_nedelec, map_nedelec);
00245 //     M_s->FillComplete(map_nedelec, map_nedelec);    
00246 //     log_matrix_stats("Matrix A_sorted", A_s);
00247 //     log_matrix_stats("Matrix M_sorted", M_s);
00248     
00249     // Calculate Y and Y'
00250     pbe_start(61, "construction of Y");
00251     Y = new Epetra_FECrsMatrix(Copy, map_nedelec, false);
00252     mesh_mixed.constructY(*Y, map_lagrange, map_nedelec);
00253 
00254     Epetra_FECrsMatrix* Y_transp = new Epetra_FECrsMatrix (Copy, map_lagrange, false);
00255     mesh_mixed.constructY_transp(*Y_transp, map_nedelec, map_lagrange);
00256 
00257     pbe_stop(61);
00258     log_matrix_stats("Matrix Y", Y);
00259     log_matrix_stats("Matrix Y'", Y_transp);
00260     log_mem_footprint(Comm, "after constr of Y and Y'");
00261    
00262     // Passing true to arg2 of MatrixMatrix::Multiply should be avoided since it slows down the routine by a factor of ~10
00263     // This is the reason why Y_transp is constructed.
00264 
00265     // Calculate C = M * Y
00266     pbe_start(62, "construction of C and C^T");
00267     C = new Epetra_CrsMatrix (Copy, map_nedelec, 0);
00268     EpetraExt::MatrixMatrix::Multiply(*M, false, *Y, false, *C);
00269     pbe_stop(62);
00270     log_matrix_stats("Matrix C", C);
00271     log_mem_footprint(Comm, "after constr of C");
00272 
00273     // Calculate H = Y^T * C
00274     pbe_start(63, "construction of H");
00275     H = new Epetra_CrsMatrix (Copy, map_lagrange, 0);
00276 #ifdef USE_PM_MATRIXMATRIX
00277     poor_man_matrix_matrix(*Y_transp, *C, *H);
00278 #else
00279     EpetraExt::MatrixMatrix::Multiply(*Y_transp, false, *C, false, *H);
00280 #endif
00281     pbe_stop(63);
00282     log_matrix_stats("Matrix H", H);
00283     log_mem_footprint(Comm, "after constr of H");
00284 
00285     if (params_.get<bool>("export_mtx")) {
00286         pbe_start(130, "MatrixMarket export");
00287         export_Epetra_CrsMatrix(*A, 15, "A.mtx");
00288         export_Epetra_CrsMatrix(*M, 15, "M.mtx");
00289         export_Epetra_CrsMatrix(*Y,  2, "Y.mtx");
00290         export_Epetra_CrsMatrix(*Y_transp,  2, "Y_transp.mtx");
00291         export_Epetra_CrsMatrix(*C, 15, "C.mtx");
00292         export_Epetra_CrsMatrix(*H, 15, "H.mtx");
00293         
00294         export_Epetra_Map(A->RowMap(), "A_rowmap.txt");
00295         export_Epetra_Map(H->RowMap(), "H_rowmap.txt");
00296         
00297 //         export_Epetra_CrsMatrix(*A_s, 15, "A_s.mtx");
00298 //         export_Epetra_CrsMatrix(*M_s, 15, "M_s.mtx");
00299         
00300         pbe_stop(130);
00301     }
00302 
00303     delete Y_transp;
00304     log_mem_footprint(Comm, "after deleting Y'");
00305 }
00306 
00307 const Epetra_Operator* LinearEigsolvOperators::getA() const {
00308     return(A);
00309 }
00310 
00311 const Epetra_Operator* LinearEigsolvOperators::getM() const {
00312     return(M);
00313 }
00314 
00315 const Epetra_Operator* LinearEigsolvOperators::getAsigmaPrec(double sigma) {
00316     if (Prec == 0) {
00317         rInfo("Calculate preconditioner for A-sigma*M...");
00318         pbe_start(70, "Preconditioner A-sigma*M construction");
00319         buildPreconditioner(sigma);
00320         pbe_stop(70);
00321     } else {
00322         assert(_sigma_K == sigma);
00323     }
00324     _sigma_K = sigma;
00325     return(Prec);
00326 }
00327 
00328 const Epetra_Operator* LinearEigsolvOperators::getHSolver() {
00329     if (h_solver_op_ == 0) {
00330         rInfo("Calculate solver for H...");
00331         pbe_start(72, "Solver H construction");
00332         Teuchos::ParameterList& h_solver(params_.sublist("h_solver"));
00333         string h_solver_type = h_solver.get<string>("type");
00334         if (h_solver_type == "pcg") {
00335             // block PCG solver
00336             // FIXME: These parameters should be included in the parameter list
00337             int max_iter_cg = 100;
00338             double h_solver_tol = 1e-10;
00339             BlockPCGSolver* pcg = new BlockPCGSolver(Comm, H, h_solver_tol, max_iter_cg, 0);
00340             pcg->setPreconditioner(const_cast<Epetra_Operator*>(getHPrec()));
00341             h_solver_op_ = pcg;
00342         } else if (h_solver_type == "lu") {
00343             // direct solver
00344             h_solver_op_ = new DirectSolverOperator(*H, params_.sublist("h_solver").sublist("amesos_params"));
00345         } else if (h_solver_type == "prec") {
00346             // just do one preconditioning step instead of a full solve
00347             h_solver_op_ = const_cast<Epetra_Operator*>(getHPrec());
00348         } else {
00349             rExit("Unknown solver for H: %s", h_solver_type.c_str());
00350         }
00351         pbe_stop(72);
00352     }
00353     return(h_solver_op_);
00354 }
00355 
00356 const Epetra_Operator* LinearEigsolvOperators::getHPrec() {
00357     if (HPrec == 0) {
00358         rInfo("Calculate preconditioner for H...");
00359         pbe_start(71, "Preconditioner H construction");
00360         Teuchos::ParameterList h_precon(params_.sublist("h_precon"));
00361         string h_precon_type = h_precon.get<string>("type");
00362         if (h_precon_type == "ml") {
00363             // Build ML preconditioner for positive-definite matrix H
00364             OutputCapturer cap;
00365             cap.begin_capture();
00366             HPrec = new ML_Epetra::MultiLevelPreconditioner(*H, params_.sublist("h_precon").sublist("ml_params"));
00367             cap.end_capture();
00368             cap.log("ML output:", RLOG_CHANNEL("debug"));
00369         } else if (h_precon_type == "diag") {
00370     
00371             // Preconditioner is diagonal of K = A -sigma*M
00372             HPrec = new DiagonalPreconditioner(*H);
00373     
00374         } else if (h_precon_type == "if") {
00375     
00376             // Preconditioner is incomplete LDLT-factorisation of K = A -sigma*M
00377         
00378             Teuchos::ParameterList List;
00379         
00380             // allocates an IFPACK factory. No data is associated
00381             // to this object (only method Create()).
00382             Ifpack Factory;
00383         
00384             // create the preconditioner. For valid PrecType values,
00385             // please check the documentation
00386             string PrecType = "IC stand-alone"; // incomplete LU
00387             int OverlapLevel = 1; // must be >= 0. If Comm.NumProc() == 1,
00388                                   // it is ignored.
00389         
00390             HPrec = Factory.Create(PrecType, H, OverlapLevel);
00391             assert(HPrec != 0);
00392         
00393             // specify parameters for IC
00394             List.set("fact: drop tolerance", 1e-9);
00395             List.set("fact: level-of-fill", 1);
00396         
00397             // sets the parameters
00398             int info;
00399             info = dynamic_cast<Ifpack_Preconditioner*>(HPrec)->SetParameters(List);
00400             rAssert(info >= 0);
00401         
00402             // initialize the preconditioner. At this point the matrix must
00403             // have been FillComplete()'d, but actual values are ignored.
00404             info = dynamic_cast<Ifpack_Preconditioner*>(HPrec)->Initialize();
00405             rAssert(info >= 0);
00406         
00407             // Builds the preconditioners, by looking for the values of
00408             // the matrix.
00409             info = dynamic_cast<Ifpack_Preconditioner*>(HPrec)->Compute();
00410             rAssert(info >= 0);
00411             
00412             // information about the preconditioner
00413             Ifpack_IC* ic_prec = dynamic_cast<Ifpack_IC*>(HPrec);
00414             if (ic_prec != 0)
00415                 rInfo("#nonzeros of IF-preconditioner for H: %d", ic_prec->NumGlobalNonzeros());
00416             cout << *dynamic_cast<Ifpack_Preconditioner*>(HPrec);
00417         } else {
00418             rExit("Unknown preconditioner for H: %s", h_precon_type.c_str());
00419         }
00420         pbe_stop(71);
00421     }
00422     return(HPrec);
00423 }
00424 
00425 Epetra_Operator* LinearEigsolvOperators::getH() {
00426     return(H);
00427 }
00428 
00429 Epetra_Operator* LinearEigsolvOperators::getY() const {
00430     return(Y);
00431 }
00432 
00433 Epetra_Operator* LinearEigsolvOperators::getC() const {
00434     return(C);
00435 }

Generated on Fri Oct 26 13:35:11 2007 for FEMAXX (Finite Element Maxwell Eigensolver) by  doxygen 1.4.7