00001 #include "myrlog.h"
00002
00003 #include "ml_include.h"
00004 #include "EpetraExt_MatrixMatrix.h"
00005 #include "matrix_matrix.h"
00006
00007
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
00066 if (capt.get_stdout().size() > 0)
00067 rDebug("%s", capt.get_stdout().c_str());
00068 }
00069
00070 int LinearEigsolvOperators::buildPreconditioner(double sigma) {
00071
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
00085 Aprec = new Epetra_LinearProblem();
00086 Aprec->SetOperator(K);
00087
00088 AprecSolver = new AztecOO(*Aprec);
00089
00090
00091 AprecSolver->SetAztecOption(AZ_precond, AZ_Neumann);
00092 AprecSolver->SetAztecOption(AZ_poly_ord, 10);
00093
00094
00095 AprecSolver->SetAztecOption(AZ_output, AZ_none);
00096
00097
00098 AprecSolver->SetAztecOption(AZ_solver, AZ_gmres);
00099
00100
00101
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,
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
00124
00125
00126 } else if (asigma_precon_type == "lu") {
00127
00128
00129 Prec = new DirectSolverOperator(*K, params_.sublist("asigma_precon").sublist("amesos_params"));
00130
00131 } else if (asigma_precon_type == "diag") {
00132
00133
00134 Prec = new DiagonalPreconditioner(*K);
00135
00136 } else if (asigma_precon_type == "if") {
00137
00138
00139
00140
00141
00142 Ifpack Factory;
00143
00144
00145
00146 string PrecType = "IC stand-alone";
00147
00148 int OverlapLevel = 1;
00149
00150 Prec = Factory.Create(PrecType, K, OverlapLevel);
00151 assert(Prec != 0);
00152
00153
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
00160
00161 IFPACK_CHK_ERR(dynamic_cast<Ifpack_Preconditioner*>(Prec)->Initialize());
00162
00163
00164
00165 IFPACK_CHK_ERR(dynamic_cast<Ifpack_Preconditioner*>(Prec)->Compute());
00166
00167
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
00185 #if 1
00186 std::vector<int> owned_dofs;
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
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
00212
00213
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
00217 #endif
00218
00219
00220
00221
00222 rInfo("Assemble finite element matrices...");
00223
00224
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
00232
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
00241
00242
00243
00244
00245
00246
00247
00248
00249
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
00263
00264
00265
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
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
00298
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
00336
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
00344 h_solver_op_ = new DirectSolverOperator(*H, params_.sublist("h_solver").sublist("amesos_params"));
00345 } else if (h_solver_type == "prec") {
00346
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
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
00372 HPrec = new DiagonalPreconditioner(*H);
00373
00374 } else if (h_precon_type == "if") {
00375
00376
00377
00378 Teuchos::ParameterList List;
00379
00380
00381
00382 Ifpack Factory;
00383
00384
00385
00386 string PrecType = "IC stand-alone";
00387 int OverlapLevel = 1;
00388
00389
00390 HPrec = Factory.Create(PrecType, H, OverlapLevel);
00391 assert(HPrec != 0);
00392
00393
00394 List.set("fact: drop tolerance", 1e-9);
00395 List.set("fact: level-of-fill", 1);
00396
00397
00398 int info;
00399 info = dynamic_cast<Ifpack_Preconditioner*>(HPrec)->SetParameters(List);
00400 rAssert(info >= 0);
00401
00402
00403
00404 info = dynamic_cast<Ifpack_Preconditioner*>(HPrec)->Initialize();
00405 rAssert(info >= 0);
00406
00407
00408
00409 info = dynamic_cast<Ifpack_Preconditioner*>(HPrec)->Compute();
00410 rAssert(info >= 0);
00411
00412
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 }