std::pair<unsigned int, Real> LaspackLinearSolver<T>::adjoint_solve (SparseMatrix<T> &matrix_in, NumericVector<T> &solution_in, NumericVector<T> &rhs_in, const double tol, const unsigned int m_its) { START_LOG("adjoint_solve()", "LaspackLinearSolver"); this->init (); // Make sure the data passed in are really in Laspack types LaspackMatrix<T>* matrix = cast_ptr<LaspackMatrix<T>*>(&matrix_in); LaspackVector<T>* solution = cast_ptr<LaspackVector<T>*>(&solution_in); LaspackVector<T>* rhs = cast_ptr<LaspackVector<T>*>(&rhs_in); // Zero-out the solution to prevent the solver from exiting in 0 // iterations (?) //TODO:[BSK] Why does Laspack do this? Comment out this and try ex13... solution->zero(); // Close the matrix and vectors in case this wasn't already done. matrix->close (); solution->close (); rhs->close (); // Set the preconditioner type this->set_laspack_preconditioner_type (); // Set the solver tolerance SetRTCAccuracy (tol); // Solve the linear system switch (this->_solver_type) { // Conjugate-Gradient case CG: { CGIter (Transp_Q(&matrix->_QMat), &solution->_vec, &rhs->_vec, m_its, _precond_type, 1.); break; } // Conjugate-Gradient Normalized case CGN: { CGNIter (Transp_Q(&matrix->_QMat), &solution->_vec, &rhs->_vec, m_its, _precond_type, 1.); break; } // Conjugate-Gradient Squared case CGS: { CGSIter (Transp_Q(&matrix->_QMat), &solution->_vec, &rhs->_vec, m_its, _precond_type, 1.); break; } // Bi-Conjugate Gradient case BICG: { BiCGIter (Transp_Q(&matrix->_QMat), &solution->_vec, &rhs->_vec, m_its, _precond_type, 1.); break; } // Bi-Conjugate Gradient Stabilized case BICGSTAB: { BiCGSTABIter (Transp_Q(&matrix->_QMat), &solution->_vec, &rhs->_vec, m_its, _precond_type, 1.); break; } // Quasi-Minimum Residual case QMR: { QMRIter (Transp_Q(&matrix->_QMat), &solution->_vec, &rhs->_vec, m_its, _precond_type, 1.); break; } // Symmetric over-relaxation case SSOR: { SSORIter (Transp_Q(&matrix->_QMat), &solution->_vec, &rhs->_vec, m_its, _precond_type, 1.); break; } // Jacobi Relaxation case JACOBI: { JacobiIter (Transp_Q(&matrix->_QMat), &solution->_vec, &rhs->_vec, m_its, _precond_type, 1.); break; } // Generalized Minimum Residual case GMRES: { SetGMRESRestart (30); GMRESIter (Transp_Q(&matrix->_QMat), &solution->_vec, &rhs->_vec, m_its, _precond_type, 1.); break; } // Unknown solver, use GMRES default: { libMesh::err << "ERROR: Unsupported LASPACK Solver: " << Utility::enum_to_string(this->_solver_type) << std::endl << "Continuing with GMRES" << std::endl; this->_solver_type = GMRES; return this->solve (*matrix, *solution, *rhs, tol, m_its); } } // Check for an error if (LASResult() != LASOK) { WriteLASErrDescr(stdout); libmesh_error_msg("Exiting after LASPACK Error!"); } STOP_LOG("adjoint_solve()", "LaspackLinearSolver"); // Get the convergence step # and residual return std::make_pair(GetLastNoIter(), GetLastAccuracy()); }
static void EstimEigenvals(QMatrix *A, PrecondProcType PrecondProc, double OmegaPrecond) /* estimates extremal eigenvalues of the matrix A by means of the Lanczos method */ { /* * for details to the Lanczos algorithm see * * G. H. Golub, Ch. F. van Loan: * Matrix Computations; * North Oxford Academic, Oxford, 1986 * * (for modification for preconditioned matrices compare with sec. 10.3) * */ double LambdaMin = 0.0, LambdaMax = 0.0; double LambdaMinOld, LambdaMaxOld; double GershBoundMin = 0.0, GershBoundMax = 0.0; double *Alpha, *Beta; size_t Dim, j; Boolean Found; Vector q, qOld, h, p; Q_Lock(A); Dim = Q_GetDim(A); V_Constr(&q, "q", Dim, Normal, True); V_Constr(&qOld, "qOld", Dim, Normal, True); V_Constr(&h, "h", Dim, Normal, True); if (PrecondProc != NULL) V_Constr(&p, "p", Dim, Normal, True); if (LASResult() == LASOK) { Alpha = (double *)malloc((Dim + 1) * sizeof(double)); Beta = (double *)malloc((Dim + 1) * sizeof(double)); if (Alpha != NULL && Beta != NULL) { j = 0; V_SetAllCmp(&qOld, 0.0); V_SetRndCmp(&q); if (Q_KerDefined(A)) OrthoRightKer_VQ(&q, A); if (Q_GetSymmetry(A) && PrecondProc != NULL) { (*PrecondProc)(A, &p, &q, OmegaPrecond); MulAsgn_VS(&q, 1.0 / sqrt(Mul_VV(&q, &p))); } else { MulAsgn_VS(&q, 1.0 / l2Norm_V(&q)); } Beta[0] = 1.0; do { j++; if (Q_GetSymmetry(A) && PrecondProc != NULL) { /* p = M^(-1) q */ (*PrecondProc)(A, &p, &q, OmegaPrecond); /* h = A p */ Asgn_VV(&h, Mul_QV(A, &p)); if (Q_KerDefined(A)) OrthoRightKer_VQ(&h, A); /* Alpha = p . h */ Alpha[j] = Mul_VV(&p, &h); /* r = h - Alpha q - Beta qOld */ SubAsgn_VV(&h, Add_VV(Mul_SV(Alpha[j], &q), Mul_SV(Beta[j-1], &qOld))); /* z = M^(-1) r */ (*PrecondProc)(A, &p, &h, OmegaPrecond); /* Beta = sqrt(r . z) */ Beta[j] = sqrt(Mul_VV(&h, &p)); Asgn_VV(&qOld, &q); /* q = r / Beta */ Asgn_VV(&q, Mul_SV(1.0 / Beta[j], &h)); } else { /* h = A p */ if (Q_GetSymmetry(A)) { Asgn_VV(&h, Mul_QV(A, &q)); } else { if (PrecondProc != NULL) { (*PrecondProc)(A, &h, Mul_QV(A, &q), OmegaPrecond); (*PrecondProc)(Transp_Q(A), &h, &h, OmegaPrecond); Asgn_VV(&h, Mul_QV(Transp_Q(A), &h)); } else { Asgn_VV(&h, Mul_QV(Transp_Q(A), Mul_QV(A, &q))); } } if (Q_KerDefined(A)) OrthoRightKer_VQ(&h, A); /* Alpha = q . h */ Alpha[j] = Mul_VV(&q, &h); /* r = h - Alpha q - Beta qOld */ SubAsgn_VV(&h, Add_VV(Mul_SV(Alpha[j], &q), Mul_SV(Beta[j-1], &qOld))); /* Beta = || r || */ Beta[j] = l2Norm_V(&h); Asgn_VV(&qOld, &q); /* q = r / Beta */ Asgn_VV(&q, Mul_SV(1.0 / Beta[j], &h)); } LambdaMaxOld = LambdaMax; LambdaMinOld = LambdaMin; /* determination of extremal eigenvalues of the tridiagonal matrix (Beta[i-1] Alpha[i] Beta[i]) (where 1 <= i <= j) by means of the method of bisection; bounds for eigenvalues are determined after Gershgorin circle theorem */ if (j == 1) { GershBoundMin = Alpha[1] - fabs(Beta[1]); GershBoundMax = Alpha[1] + fabs(Beta[1]); LambdaMin = Alpha[1]; LambdaMax = Alpha[1]; } else { GershBoundMin = min(Alpha[j] - fabs(Beta[j]) - fabs(Beta[j - 1]), GershBoundMin); GershBoundMax = max(Alpha[j] + fabs(Beta[j]) + fabs(Beta[j - 1]), GershBoundMax); SearchEigenval(j, Alpha, Beta, 1, GershBoundMin, LambdaMin, &Found, &LambdaMin); if (!Found) SearchEigenval(j, Alpha, Beta, 1, GershBoundMin, GershBoundMax, &Found, &LambdaMin); SearchEigenval(j, Alpha, Beta, j, LambdaMax, GershBoundMax, &Found, &LambdaMax); if (!Found) SearchEigenval(j, Alpha, Beta, j, GershBoundMin, GershBoundMax, &Found, &LambdaMax); } } while (!IsZero(Beta[j]) && j < Dim && (fabs(LambdaMin - LambdaMinOld) > EigenvalEps * LambdaMin || fabs(LambdaMax - LambdaMaxOld) > EigenvalEps * LambdaMax) && LASResult() == LASOK); if (Q_GetSymmetry(A)) { LambdaMin = (1.0 - j * EigenvalEps) * LambdaMin; } else { LambdaMin = (1.0 - sqrt(j) * EigenvalEps) * sqrt(LambdaMin); } if (Alpha != NULL) free(Alpha); if (Beta != NULL) free(Beta); } else { LASError(LASMemAllocErr, "EstimEigenvals", Q_GetName(A), NULL, NULL); } } V_Destr(&q); V_Destr(&qOld); V_Destr(&h); if (PrecondProc != NULL) V_Destr(&p); if (LASResult() == LASOK) { ((EigenvalInfoType *)*(Q_EigenvalInfo(A)))->MinEigenval = LambdaMin; ((EigenvalInfoType *)*(Q_EigenvalInfo(A)))->MaxEigenval = LambdaMax; ((EigenvalInfoType *)*(Q_EigenvalInfo(A)))->PrecondProcUsed = PrecondProc; ((EigenvalInfoType *)*(Q_EigenvalInfo(A)))->OmegaPrecondUsed = OmegaPrecond; } else { ((EigenvalInfoType *)*(Q_EigenvalInfo(A)))->MinEigenval = 1.0; ((EigenvalInfoType *)*(Q_EigenvalInfo(A)))->MaxEigenval = 1.0; ((EigenvalInfoType *)*(Q_EigenvalInfo(A)))->PrecondProcUsed = NULL; ((EigenvalInfoType *)*(Q_EigenvalInfo(A)))->OmegaPrecondUsed = 1.0; } Q_Unlock(A); }