$extrastylesheet
00001 // The libMesh Finite Element Library. 00002 // Copyright (C) 2002-2014 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner 00003 00004 // This library is free software; you can redistribute it and/or 00005 // modify it under the terms of the GNU Lesser General Public 00006 // License as published by the Free Software Foundation; either 00007 // version 2.1 of the License, or (at your option) any later version. 00008 00009 // This library is distributed in the hope that it will be useful, 00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 // Lesser General Public License for more details. 00013 00014 // You should have received a copy of the GNU Lesser General Public 00015 // License along with this library; if not, write to the Free Software 00016 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00017 00018 00019 00020 #include "libmesh/libmesh_common.h" 00021 00022 #if defined(LIBMESH_HAVE_SLEPC) && defined(LIBMESH_HAVE_PETSC) 00023 00024 00025 // C++ includes 00026 00027 // Local Includes 00028 #include "libmesh/libmesh_logging.h" 00029 #include "libmesh/petsc_matrix.h" 00030 #include "libmesh/petsc_vector.h" 00031 #include "libmesh/slepc_eigen_solver.h" 00032 #include "libmesh/shell_matrix.h" 00033 #include "libmesh/string_to_enum.h" 00034 00035 namespace libMesh 00036 { 00037 00038 extern "C" 00039 { 00040 // Older versions of PETSc do not have the different int typedefs. 00041 // On 64-bit machines, PetscInt may actually be a long long int. 00042 // This change occurred in Petsc-2.2.1. 00043 #if PETSC_VERSION_LESS_THAN(2,2,1) 00044 typedef int PetscErrorCode; 00045 typedef int PetscInt; 00046 #endif 00047 } 00048 00049 00050 /*----------------------- functions ----------------------------------*/ 00051 template <typename T> 00052 void SlepcEigenSolver<T>::clear () 00053 { 00054 if (this->initialized()) 00055 { 00056 this->_is_initialized = false; 00057 00058 PetscErrorCode ierr=0; 00059 00060 ierr = LibMeshEPSDestroy(&_eps); 00061 LIBMESH_CHKERRABORT(ierr); 00062 00063 // SLEPc default eigenproblem solver 00064 #if SLEPC_VERSION_LESS_THAN(2,3,2) 00065 this->_eigen_solver_type = ARNOLDI; 00066 #else 00067 // Krylov-Schur showed up as of Slepc 2.3.2 00068 this->_eigen_solver_type = KRYLOVSCHUR; 00069 #endif 00070 } 00071 } 00072 00073 00074 00075 template <typename T> 00076 void SlepcEigenSolver<T>::init () 00077 { 00078 00079 PetscErrorCode ierr=0; 00080 00081 // Initialize the data structures if not done so already. 00082 if (!this->initialized()) 00083 { 00084 this->_is_initialized = true; 00085 00086 // Create the eigenproblem solver context 00087 ierr = EPSCreate (this->comm().get(), &_eps); 00088 LIBMESH_CHKERRABORT(ierr); 00089 00090 // Set user-specified solver 00091 set_slepc_solver_type(); 00092 } 00093 } 00094 00095 00096 00097 template <typename T> 00098 std::pair<unsigned int, unsigned int> 00099 SlepcEigenSolver<T>::solve_standard (SparseMatrix<T> &matrix_A_in, 00100 int nev, // number of requested eigenpairs 00101 int ncv, // number of basis vectors 00102 const double tol, // solver tolerance 00103 const unsigned int m_its) // maximum number of iterations 00104 { 00105 // START_LOG("solve_standard()", "SlepcEigenSolver"); 00106 00107 this->init (); 00108 00109 // Make sure the SparseMatrix passed in is really a PetscMatrix 00110 PetscMatrix<T>* matrix_A = cast_ptr<PetscMatrix<T>*>(&matrix_A_in); 00111 00112 // Close the matrix and vectors in case this wasn't already done. 00113 matrix_A->close (); 00114 00115 // just for debugging, remove this 00116 // char mat_file[] = "matA.petsc"; 00117 // PetscViewer petsc_viewer; 00118 // ierr = PetscViewerBinaryOpen(this->comm().get(), mat_file, PETSC_FILE_CREATE, &petsc_viewer); 00119 // LIBMESH_CHKERRABORT(ierr); 00120 // ierr = MatView(matrix_A->mat(),petsc_viewer); 00121 // LIBMESH_CHKERRABORT(ierr); 00122 00123 return _solve_standard_helper(matrix_A->mat(), nev, ncv, tol, m_its); 00124 } 00125 00126 00127 template <typename T> 00128 std::pair<unsigned int, unsigned int> 00129 SlepcEigenSolver<T>::solve_standard (ShellMatrix<T> &shell_matrix, 00130 int nev, // number of requested eigenpairs 00131 int ncv, // number of basis vectors 00132 const double tol, // solver tolerance 00133 const unsigned int m_its) // maximum number of iterations 00134 { 00135 this->init (); 00136 00137 PetscErrorCode ierr=0; 00138 00139 // Prepare the matrix. 00140 Mat mat; 00141 ierr = MatCreateShell(this->comm().get(), 00142 shell_matrix.m(), // Specify the number of local rows 00143 shell_matrix.n(), // Specify the number of local columns 00144 PETSC_DETERMINE, 00145 PETSC_DETERMINE, 00146 const_cast<void*>(static_cast<const void*>(&shell_matrix)), 00147 &mat); 00148 LIBMESH_CHKERRABORT(ierr); 00149 00150 /* Note that the const_cast above is only necessary because PETSc 00151 does not accept a const void*. Inside the member function 00152 _petsc_shell_matrix() below, the pointer is casted back to a 00153 const ShellMatrix<T>*. */ 00154 00155 ierr = MatShellSetOperation(mat,MATOP_MULT,reinterpret_cast<void(*)(void)>(_petsc_shell_matrix_mult)); 00156 LIBMESH_CHKERRABORT(ierr); 00157 ierr = MatShellSetOperation(mat,MATOP_GET_DIAGONAL,reinterpret_cast<void(*)(void)>(_petsc_shell_matrix_get_diagonal)); 00158 LIBMESH_CHKERRABORT(ierr); 00159 00160 00161 return _solve_standard_helper(mat, nev, ncv, tol, m_its); 00162 } 00163 00164 template <typename T> 00165 std::pair<unsigned int, unsigned int> 00166 SlepcEigenSolver<T>::_solve_standard_helper 00167 (Mat mat, 00168 int nev, // number of requested eigenpairs 00169 int ncv, // number of basis vectors 00170 const double tol, // solver tolerance 00171 const unsigned int m_its) // maximum number of iterations 00172 { 00173 START_LOG("solve_standard()", "SlepcEigenSolver"); 00174 00175 PetscErrorCode ierr=0; 00176 00177 // converged eigen pairs and number of iterations 00178 PetscInt nconv=0; 00179 PetscInt its=0; 00180 00181 #ifdef DEBUG 00182 // The relative error. 00183 PetscReal error, re, im; 00184 00185 // Pointer to vectors of the real parts, imaginary parts. 00186 PetscScalar kr, ki; 00187 #endif 00188 00189 // Set operators. 00190 ierr = EPSSetOperators (_eps, mat, PETSC_NULL); 00191 LIBMESH_CHKERRABORT(ierr); 00192 00193 //set the problem type and the position of the spectrum 00194 set_slepc_problem_type(); 00195 set_slepc_position_of_spectrum(); 00196 00197 // Set eigenvalues to be computed. 00198 #if SLEPC_VERSION_LESS_THAN(3,0,0) 00199 ierr = EPSSetDimensions (_eps, nev, ncv); 00200 #else 00201 ierr = EPSSetDimensions (_eps, nev, ncv, PETSC_DECIDE); 00202 #endif 00203 LIBMESH_CHKERRABORT(ierr); 00204 // Set the tolerance and maximum iterations. 00205 ierr = EPSSetTolerances (_eps, tol, m_its); 00206 LIBMESH_CHKERRABORT(ierr); 00207 00208 // Set runtime options, e.g., 00209 // -eps_type <type>, -eps_nev <nev>, -eps_ncv <ncv> 00210 // Similar to PETSc, these options will override those specified 00211 // above as long as EPSSetFromOptions() is called _after_ any 00212 // other customization routines. 00213 ierr = EPSSetFromOptions (_eps); 00214 LIBMESH_CHKERRABORT(ierr); 00215 00216 // Solve the eigenproblem. 00217 ierr = EPSSolve (_eps); 00218 LIBMESH_CHKERRABORT(ierr); 00219 00220 // Get the number of iterations. 00221 ierr = EPSGetIterationNumber (_eps, &its); 00222 LIBMESH_CHKERRABORT(ierr); 00223 00224 // Get number of converged eigenpairs. 00225 ierr = EPSGetConverged(_eps,&nconv); 00226 LIBMESH_CHKERRABORT(ierr); 00227 00228 00229 #ifdef DEBUG 00230 // ierr = PetscPrintf(this->comm().get(), 00231 // "\n Number of iterations: %d\n" 00232 // " Number of converged eigenpairs: %d\n\n", its, nconv); 00233 00234 // Display eigenvalues and relative errors. 00235 ierr = PetscPrintf(this->comm().get(), 00236 " k ||Ax-kx||/|kx|\n" 00237 " ----------------- -----------------\n" ); 00238 LIBMESH_CHKERRABORT(ierr); 00239 00240 for(PetscInt i=0; i<nconv; i++ ) 00241 { 00242 ierr = EPSGetEigenpair(_eps, i, &kr, &ki, PETSC_NULL, PETSC_NULL); 00243 LIBMESH_CHKERRABORT(ierr); 00244 00245 ierr = EPSComputeRelativeError(_eps, i, &error); 00246 LIBMESH_CHKERRABORT(ierr); 00247 00248 #ifdef LIBMESH_USE_COMPLEX_NUMBERS 00249 re = PetscRealPart(kr); 00250 im = PetscImaginaryPart(kr); 00251 #else 00252 re = kr; 00253 im = ki; 00254 #endif 00255 00256 if (im != .0) 00257 { 00258 ierr = PetscPrintf(this->comm().get()," %9f%+9f i %12f\n", re, im, error); 00259 LIBMESH_CHKERRABORT(ierr); 00260 } 00261 else 00262 { 00263 ierr = PetscPrintf(this->comm().get()," %12f %12f\n", re, error); 00264 LIBMESH_CHKERRABORT(ierr); 00265 } 00266 } 00267 00268 ierr = PetscPrintf(this->comm().get(),"\n" ); 00269 LIBMESH_CHKERRABORT(ierr); 00270 #endif // DEBUG 00271 00272 00273 STOP_LOG("solve_standard()", "SlepcEigenSolver"); 00274 00275 // return the number of converged eigenpairs 00276 // and the number of iterations 00277 return std::make_pair(nconv, its); 00278 00279 } 00280 00281 00282 00283 00284 00285 template <typename T> 00286 std::pair<unsigned int, unsigned int> 00287 SlepcEigenSolver<T>::solve_generalized (SparseMatrix<T> &matrix_A_in, 00288 SparseMatrix<T> &matrix_B_in, 00289 int nev, // number of requested eigenpairs 00290 int ncv, // number of basis vectors 00291 const double tol, // solver tolerance 00292 const unsigned int m_its) // maximum number of iterations 00293 { 00294 this->init (); 00295 00296 // Make sure the data passed in are really of Petsc types 00297 PetscMatrix<T>* matrix_A = cast_ptr<PetscMatrix<T>*>(&matrix_A_in); 00298 PetscMatrix<T>* matrix_B = cast_ptr<PetscMatrix<T>*>(&matrix_B_in); 00299 00300 // Close the matrix and vectors in case this wasn't already done. 00301 matrix_A->close (); 00302 matrix_B->close (); 00303 00304 00305 return _solve_generalized_helper (matrix_A->mat(), matrix_B->mat(), nev, ncv, tol, m_its); 00306 } 00307 00308 template <typename T> 00309 std::pair<unsigned int, unsigned int> 00310 SlepcEigenSolver<T>::solve_generalized (ShellMatrix<T> &shell_matrix_A, 00311 SparseMatrix<T> &matrix_B_in, 00312 int nev, // number of requested eigenpairs 00313 int ncv, // number of basis vectors 00314 const double tol, // solver tolerance 00315 const unsigned int m_its) // maximum number of iterations 00316 { 00317 this->init (); 00318 00319 PetscErrorCode ierr=0; 00320 00321 // Prepare the matrix. 00322 Mat mat_A; 00323 ierr = MatCreateShell(this->comm().get(), 00324 shell_matrix_A.m(), // Specify the number of local rows 00325 shell_matrix_A.n(), // Specify the number of local columns 00326 PETSC_DETERMINE, 00327 PETSC_DETERMINE, 00328 const_cast<void*>(static_cast<const void*>(&shell_matrix_A)), 00329 &mat_A); 00330 LIBMESH_CHKERRABORT(ierr); 00331 00332 PetscMatrix<T>* matrix_B = cast_ptr<PetscMatrix<T>*>(&matrix_B_in); 00333 00334 // Close the matrix and vectors in case this wasn't already done. 00335 matrix_B->close (); 00336 00337 /* Note that the const_cast above is only necessary because PETSc 00338 does not accept a const void*. Inside the member function 00339 _petsc_shell_matrix() below, the pointer is casted back to a 00340 const ShellMatrix<T>*. */ 00341 00342 ierr = MatShellSetOperation(mat_A,MATOP_MULT,reinterpret_cast<void(*)(void)>(_petsc_shell_matrix_mult)); 00343 LIBMESH_CHKERRABORT(ierr); 00344 ierr = MatShellSetOperation(mat_A,MATOP_GET_DIAGONAL,reinterpret_cast<void(*)(void)>(_petsc_shell_matrix_get_diagonal)); 00345 LIBMESH_CHKERRABORT(ierr); 00346 00347 return _solve_generalized_helper (mat_A, matrix_B->mat(), nev, ncv, tol, m_its); 00348 } 00349 00350 template <typename T> 00351 std::pair<unsigned int, unsigned int> 00352 SlepcEigenSolver<T>::solve_generalized (SparseMatrix<T> &matrix_A_in, 00353 ShellMatrix<T> &shell_matrix_B, 00354 int nev, // number of requested eigenpairs 00355 int ncv, // number of basis vectors 00356 const double tol, // solver tolerance 00357 const unsigned int m_its) // maximum number of iterations 00358 { 00359 this->init (); 00360 00361 PetscErrorCode ierr=0; 00362 00363 PetscMatrix<T>* matrix_A = cast_ptr<PetscMatrix<T>*>(&matrix_A_in); 00364 00365 // Close the matrix and vectors in case this wasn't already done. 00366 matrix_A->close (); 00367 00368 // Prepare the matrix. 00369 Mat mat_B; 00370 ierr = MatCreateShell(this->comm().get(), 00371 shell_matrix_B.m(), // Specify the number of local rows 00372 shell_matrix_B.n(), // Specify the number of local columns 00373 PETSC_DETERMINE, 00374 PETSC_DETERMINE, 00375 const_cast<void*>(static_cast<const void*>(&shell_matrix_B)), 00376 &mat_B); 00377 LIBMESH_CHKERRABORT(ierr); 00378 00379 /* Note that the const_cast above is only necessary because PETSc 00380 does not accept a const void*. Inside the member function 00381 _petsc_shell_matrix() below, the pointer is casted back to a 00382 const ShellMatrix<T>*. */ 00383 00384 ierr = MatShellSetOperation(mat_B,MATOP_MULT,reinterpret_cast<void(*)(void)>(_petsc_shell_matrix_mult)); 00385 LIBMESH_CHKERRABORT(ierr); 00386 ierr = MatShellSetOperation(mat_B,MATOP_GET_DIAGONAL,reinterpret_cast<void(*)(void)>(_petsc_shell_matrix_get_diagonal)); 00387 LIBMESH_CHKERRABORT(ierr); 00388 00389 return _solve_generalized_helper (matrix_A->mat(), mat_B, nev, ncv, tol, m_its); 00390 } 00391 00392 template <typename T> 00393 std::pair<unsigned int, unsigned int> 00394 SlepcEigenSolver<T>::solve_generalized (ShellMatrix<T> &shell_matrix_A, 00395 ShellMatrix<T> &shell_matrix_B, 00396 int nev, // number of requested eigenpairs 00397 int ncv, // number of basis vectors 00398 const double tol, // solver tolerance 00399 const unsigned int m_its) // maximum number of iterations 00400 { 00401 this->init (); 00402 00403 PetscErrorCode ierr=0; 00404 00405 // Prepare the matrix. 00406 Mat mat_A; 00407 ierr = MatCreateShell(this->comm().get(), 00408 shell_matrix_A.m(), // Specify the number of local rows 00409 shell_matrix_A.n(), // Specify the number of local columns 00410 PETSC_DETERMINE, 00411 PETSC_DETERMINE, 00412 const_cast<void*>(static_cast<const void*>(&shell_matrix_A)), 00413 &mat_A); 00414 LIBMESH_CHKERRABORT(ierr); 00415 00416 Mat mat_B; 00417 ierr = MatCreateShell(this->comm().get(), 00418 shell_matrix_B.m(), // Specify the number of local rows 00419 shell_matrix_B.n(), // Specify the number of local columns 00420 PETSC_DETERMINE, 00421 PETSC_DETERMINE, 00422 const_cast<void*>(static_cast<const void*>(&shell_matrix_B)), 00423 &mat_B); 00424 LIBMESH_CHKERRABORT(ierr); 00425 00426 /* Note that the const_cast above is only necessary because PETSc 00427 does not accept a const void*. Inside the member function 00428 _petsc_shell_matrix() below, the pointer is casted back to a 00429 const ShellMatrix<T>*. */ 00430 00431 ierr = MatShellSetOperation(mat_A,MATOP_MULT,reinterpret_cast<void(*)(void)>(_petsc_shell_matrix_mult)); 00432 LIBMESH_CHKERRABORT(ierr); 00433 ierr = MatShellSetOperation(mat_A,MATOP_GET_DIAGONAL,reinterpret_cast<void(*)(void)>(_petsc_shell_matrix_get_diagonal)); 00434 LIBMESH_CHKERRABORT(ierr); 00435 00436 ierr = MatShellSetOperation(mat_B,MATOP_MULT,reinterpret_cast<void(*)(void)>(_petsc_shell_matrix_mult)); 00437 LIBMESH_CHKERRABORT(ierr); 00438 ierr = MatShellSetOperation(mat_B,MATOP_GET_DIAGONAL,reinterpret_cast<void(*)(void)>(_petsc_shell_matrix_get_diagonal)); 00439 LIBMESH_CHKERRABORT(ierr); 00440 00441 return _solve_generalized_helper (mat_A, mat_B, nev, ncv, tol, m_its); 00442 } 00443 00444 00445 00446 template <typename T> 00447 std::pair<unsigned int, unsigned int> 00448 SlepcEigenSolver<T>::_solve_generalized_helper (Mat mat_A, 00449 Mat mat_B, 00450 int nev, // number of requested eigenpairs 00451 int ncv, // number of basis vectors 00452 const double tol, // solver tolerance 00453 const unsigned int m_its) // maximum number of iterations 00454 { 00455 START_LOG("solve_generalized()", "SlepcEigenSolver"); 00456 00457 PetscErrorCode ierr=0; 00458 00459 // converged eigen pairs and number of iterations 00460 PetscInt nconv=0; 00461 PetscInt its=0; 00462 00463 #ifdef DEBUG 00464 // The relative error. 00465 PetscReal error, re, im; 00466 00467 // Pointer to vectors of the real parts, imaginary parts. 00468 PetscScalar kr, ki; 00469 #endif 00470 00471 // Set operators. 00472 ierr = EPSSetOperators (_eps, mat_A, mat_B); 00473 LIBMESH_CHKERRABORT(ierr); 00474 00475 //set the problem type and the position of the spectrum 00476 set_slepc_problem_type(); 00477 set_slepc_position_of_spectrum(); 00478 00479 // Set eigenvalues to be computed. 00480 #if SLEPC_VERSION_LESS_THAN(3,0,0) 00481 ierr = EPSSetDimensions (_eps, nev, ncv); 00482 #else 00483 ierr = EPSSetDimensions (_eps, nev, ncv, PETSC_DECIDE); 00484 #endif 00485 LIBMESH_CHKERRABORT(ierr); 00486 00487 00488 // Set the tolerance and maximum iterations. 00489 ierr = EPSSetTolerances (_eps, tol, m_its); 00490 LIBMESH_CHKERRABORT(ierr); 00491 00492 // Set runtime options, e.g., 00493 // -eps_type <type>, -eps_nev <nev>, -eps_ncv <ncv> 00494 // Similar to PETSc, these options will override those specified 00495 // above as long as EPSSetFromOptions() is called _after_ any 00496 // other customization routines. 00497 ierr = EPSSetFromOptions (_eps); 00498 LIBMESH_CHKERRABORT(ierr); 00499 00500 // Solve the eigenproblem. 00501 ierr = EPSSolve (_eps); 00502 LIBMESH_CHKERRABORT(ierr); 00503 00504 // Get the number of iterations. 00505 ierr = EPSGetIterationNumber (_eps, &its); 00506 LIBMESH_CHKERRABORT(ierr); 00507 00508 // Get number of converged eigenpairs. 00509 ierr = EPSGetConverged(_eps,&nconv); 00510 LIBMESH_CHKERRABORT(ierr); 00511 00512 00513 #ifdef DEBUG 00514 // ierr = PetscPrintf(this->comm().get(), 00515 // "\n Number of iterations: %d\n" 00516 // " Number of converged eigenpairs: %d\n\n", its, nconv); 00517 00518 // Display eigenvalues and relative errors. 00519 ierr = PetscPrintf(this->comm().get(), 00520 " k ||Ax-kx||/|kx|\n" 00521 " ----------------- -----------------\n" ); 00522 LIBMESH_CHKERRABORT(ierr); 00523 00524 for(PetscInt i=0; i<nconv; i++ ) 00525 { 00526 ierr = EPSGetEigenpair(_eps, i, &kr, &ki, PETSC_NULL, PETSC_NULL); 00527 LIBMESH_CHKERRABORT(ierr); 00528 00529 ierr = EPSComputeRelativeError(_eps, i, &error); 00530 LIBMESH_CHKERRABORT(ierr); 00531 00532 #ifdef LIBMESH_USE_COMPLEX_NUMBERS 00533 re = PetscRealPart(kr); 00534 im = PetscImaginaryPart(kr); 00535 #else 00536 re = kr; 00537 im = ki; 00538 #endif 00539 00540 if (im != .0) 00541 { 00542 ierr = PetscPrintf(this->comm().get()," %9f%+9f i %12f\n", re, im, error); 00543 LIBMESH_CHKERRABORT(ierr); 00544 } 00545 else 00546 { 00547 ierr = PetscPrintf(this->comm().get()," %12f %12f\n", re, error); 00548 LIBMESH_CHKERRABORT(ierr); 00549 } 00550 } 00551 00552 ierr = PetscPrintf(this->comm().get(),"\n" ); 00553 LIBMESH_CHKERRABORT(ierr); 00554 #endif // DEBUG 00555 00556 STOP_LOG("solve_generalized()", "SlepcEigenSolver"); 00557 00558 // return the number of converged eigenpairs 00559 // and the number of iterations 00560 return std::make_pair(nconv, its); 00561 00562 } 00563 00564 00565 00566 00567 00568 00569 00570 00571 00572 00573 00574 template <typename T> 00575 void SlepcEigenSolver<T>::set_slepc_solver_type() 00576 { 00577 PetscErrorCode ierr = 0; 00578 00579 switch (this->_eigen_solver_type) 00580 { 00581 case POWER: 00582 ierr = EPSSetType (_eps, (char*) EPSPOWER); LIBMESH_CHKERRABORT(ierr); return; 00583 case SUBSPACE: 00584 ierr = EPSSetType (_eps, (char*) EPSSUBSPACE); LIBMESH_CHKERRABORT(ierr); return; 00585 case LAPACK: 00586 ierr = EPSSetType (_eps, (char*) EPSLAPACK); LIBMESH_CHKERRABORT(ierr); return; 00587 case ARNOLDI: 00588 ierr = EPSSetType (_eps, (char*) EPSARNOLDI); LIBMESH_CHKERRABORT(ierr); return; 00589 case LANCZOS: 00590 ierr = EPSSetType (_eps, (char*) EPSLANCZOS); LIBMESH_CHKERRABORT(ierr); return; 00591 #if !SLEPC_VERSION_LESS_THAN(2,3,2) 00592 // EPSKRYLOVSCHUR added in 2.3.2 00593 case KRYLOVSCHUR: 00594 ierr = EPSSetType (_eps, (char*) EPSKRYLOVSCHUR); LIBMESH_CHKERRABORT(ierr); return; 00595 #endif 00596 // case ARPACK: 00597 // ierr = EPSSetType (_eps, (char*) EPSARPACK); LIBMESH_CHKERRABORT(ierr); return; 00598 00599 default: 00600 libMesh::err << "ERROR: Unsupported SLEPc Eigen Solver: " 00601 << Utility::enum_to_string(this->_eigen_solver_type) << std::endl 00602 << "Continuing with SLEPc defaults" << std::endl; 00603 } 00604 } 00605 00606 00607 00608 00609 template <typename T> 00610 void SlepcEigenSolver<T>:: set_slepc_problem_type() 00611 { 00612 PetscErrorCode ierr = 0; 00613 00614 switch (this->_eigen_problem_type) 00615 { 00616 case NHEP: 00617 ierr = EPSSetProblemType (_eps, EPS_NHEP); LIBMESH_CHKERRABORT(ierr); return; 00618 case GNHEP: 00619 ierr = EPSSetProblemType (_eps, EPS_GNHEP); LIBMESH_CHKERRABORT(ierr); return; 00620 case HEP: 00621 ierr = EPSSetProblemType (_eps, EPS_HEP); LIBMESH_CHKERRABORT(ierr); return; 00622 case GHEP: 00623 ierr = EPSSetProblemType (_eps, EPS_GHEP); LIBMESH_CHKERRABORT(ierr); return; 00624 #if !SLEPC_VERSION_LESS_THAN(3,3,0) 00625 // EPS_GHIEP added in 3.3.0 00626 case GHIEP: 00627 ierr = EPSSetProblemType (_eps, EPS_GHIEP); LIBMESH_CHKERRABORT(ierr); return; 00628 #endif 00629 00630 default: 00631 libMesh::err << "ERROR: Unsupported SLEPc Eigen Problem: " 00632 << this->_eigen_problem_type << std::endl 00633 << "Continuing with SLEPc defaults" << std::endl; 00634 } 00635 } 00636 00637 00638 00639 template <typename T> 00640 void SlepcEigenSolver<T>:: set_slepc_position_of_spectrum() 00641 { 00642 PetscErrorCode ierr = 0; 00643 00644 switch (this->_position_of_spectrum) 00645 { 00646 case LARGEST_MAGNITUDE: 00647 ierr = EPSSetWhichEigenpairs (_eps, EPS_LARGEST_MAGNITUDE); LIBMESH_CHKERRABORT(ierr); return; 00648 case SMALLEST_MAGNITUDE: 00649 ierr = EPSSetWhichEigenpairs (_eps, EPS_SMALLEST_MAGNITUDE); LIBMESH_CHKERRABORT(ierr); return; 00650 case LARGEST_REAL: 00651 ierr = EPSSetWhichEigenpairs (_eps, EPS_LARGEST_REAL); LIBMESH_CHKERRABORT(ierr); return; 00652 case SMALLEST_REAL: 00653 ierr = EPSSetWhichEigenpairs (_eps, EPS_SMALLEST_REAL); LIBMESH_CHKERRABORT(ierr); return; 00654 case LARGEST_IMAGINARY: 00655 ierr = EPSSetWhichEigenpairs (_eps, EPS_LARGEST_IMAGINARY); LIBMESH_CHKERRABORT(ierr); return; 00656 case SMALLEST_IMAGINARY: 00657 ierr = EPSSetWhichEigenpairs (_eps, EPS_SMALLEST_IMAGINARY); LIBMESH_CHKERRABORT(ierr); return; 00658 00659 00660 default: 00661 libmesh_error_msg("ERROR: Unsupported SLEPc position of spectrum: " << this->_position_of_spectrum); 00662 } 00663 } 00664 00665 00666 00667 00668 00669 00670 template <typename T> 00671 std::pair<Real, Real> SlepcEigenSolver<T>::get_eigenpair(unsigned int i, 00672 NumericVector<T> &solution_in) 00673 { 00674 PetscErrorCode ierr=0; 00675 00676 PetscReal re, im; 00677 00678 // Make sure the NumericVector passed in is really a PetscVector 00679 PetscVector<T>* solution = cast_ptr<PetscVector<T>*>(&solution_in); 00680 00681 // real and imaginary part of the ith eigenvalue. 00682 PetscScalar kr, ki; 00683 00684 solution->close(); 00685 00686 ierr = EPSGetEigenpair(_eps, i, &kr, &ki, solution->vec(), PETSC_NULL); 00687 LIBMESH_CHKERRABORT(ierr); 00688 00689 #ifdef LIBMESH_USE_COMPLEX_NUMBERS 00690 re = PetscRealPart(kr); 00691 im = PetscImaginaryPart(kr); 00692 #else 00693 re = kr; 00694 im = ki; 00695 #endif 00696 00697 return std::make_pair(re, im); 00698 } 00699 00700 00701 template <typename T> 00702 std::pair<Real, Real> SlepcEigenSolver<T>::get_eigenvalue(unsigned int i) 00703 { 00704 PetscErrorCode ierr=0; 00705 00706 PetscReal re, im; 00707 00708 // real and imaginary part of the ith eigenvalue. 00709 PetscScalar kr, ki; 00710 00711 ierr = EPSGetEigenvalue(_eps, i, &kr, &ki); 00712 LIBMESH_CHKERRABORT(ierr); 00713 00714 #ifdef LIBMESH_USE_COMPLEX_NUMBERS 00715 re = PetscRealPart(kr); 00716 im = PetscImaginaryPart(kr); 00717 #else 00718 re = kr; 00719 im = ki; 00720 #endif 00721 00722 return std::make_pair(re, im); 00723 } 00724 00725 00726 template <typename T> 00727 Real SlepcEigenSolver<T>::get_relative_error(unsigned int i) 00728 { 00729 PetscErrorCode ierr=0; 00730 PetscReal error; 00731 00732 ierr = EPSComputeRelativeError(_eps, i, &error); 00733 LIBMESH_CHKERRABORT(ierr); 00734 00735 return error; 00736 } 00737 00738 00739 template <typename T> 00740 void SlepcEigenSolver<T>::attach_deflation_space(NumericVector<T>& deflation_vector_in) 00741 { 00742 this->init(); 00743 00744 PetscErrorCode ierr = 0; 00745 Vec deflation_vector = (cast_ptr<PetscVector<T>*>(&deflation_vector_in))->vec(); 00746 Vec* deflation_space = &deflation_vector; 00747 #if SLEPC_VERSION_LESS_THAN(3,1,0) 00748 ierr = EPSAttachDeflationSpace(_eps, 1, deflation_space, PETSC_FALSE); 00749 #else 00750 ierr = EPSSetDeflationSpace(_eps, 1, deflation_space); 00751 #endif 00752 LIBMESH_CHKERRABORT(ierr); 00753 } 00754 00755 template <typename T> 00756 PetscErrorCode SlepcEigenSolver<T>::_petsc_shell_matrix_mult(Mat mat, Vec arg, Vec dest) 00757 { 00758 /* Get the matrix context. */ 00759 PetscErrorCode ierr=0; 00760 void* ctx; 00761 ierr = MatShellGetContext(mat,&ctx); 00762 00763 Parallel::communicator comm; 00764 PetscObjectGetComm((PetscObject)mat,&comm); 00765 CHKERRABORT(comm,ierr); 00766 00767 /* Get user shell matrix object. */ 00768 const ShellMatrix<T>& shell_matrix = *static_cast<const ShellMatrix<T>*>(ctx); 00769 00770 /* Make \p NumericVector instances around the vectors. */ 00771 PetscVector<T> arg_global(arg, shell_matrix.comm()); 00772 PetscVector<T> dest_global(dest, shell_matrix.comm()); 00773 00774 /* Call the user function. */ 00775 shell_matrix.vector_mult(dest_global,arg_global); 00776 00777 return ierr; 00778 } 00779 00780 template <typename T> 00781 PetscErrorCode SlepcEigenSolver<T>::_petsc_shell_matrix_get_diagonal(Mat mat, Vec dest) 00782 { 00783 /* Get the matrix context. */ 00784 PetscErrorCode ierr=0; 00785 void* ctx; 00786 ierr = MatShellGetContext(mat,&ctx); 00787 00788 Parallel::communicator comm; 00789 PetscObjectGetComm((PetscObject)mat,&comm); 00790 CHKERRABORT(comm,ierr); 00791 00792 /* Get user shell matrix object. */ 00793 const ShellMatrix<T>& shell_matrix = *static_cast<const ShellMatrix<T>*>(ctx); 00794 00795 /* Make \p NumericVector instances around the vector. */ 00796 PetscVector<T> dest_global(dest, shell_matrix.comm()); 00797 00798 /* Call the user function. */ 00799 shell_matrix.get_diagonal(dest_global); 00800 00801 return ierr; 00802 } 00803 00804 //------------------------------------------------------------------ 00805 // Explicit instantiations 00806 template class SlepcEigenSolver<Number>; 00807 00808 } // namespace libMesh 00809 00810 00811 00812 #endif // #ifdef LIBMESH_HAVE_SLEPC