/* * vmg - a versatile multigrid solver * Copyright (C) 2012 Institute for Numerical Simulation, University of Bonn * * vmg is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * vmg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ /** * @file dsysv.hpp * @author Julian Iseringhausen * @date Mon Apr 18 13:09:54 2011 * * @brief Lapack solver for symmetric matrices * */ #ifndef DSYSV_HPP_ #define DSYSV_HPP_ #ifndef HAVE_LAPACK #error You need LAPACK in order to use MGDSYSV #endif #include #include #include "base/defs.hpp" namespace VMG { extern "C" { void FC_FUNC(dsysv, DSYSV) (const char* UPLO, const int* N, const int* NRHS, double* A, const int* LDA, int* IPIV, double* B, const int* LDB, double* WORK, const int* LWORK, int* INFO); void FC_FUNC(dsyrfs, DSYRFS) (const char* UPLO, const int* N, const int* NRHS, const vmg_float* A, const int* LDA, double* AF, const int* LDAF, const int* IPIV, const vmg_float* B, const int* LDB, double* X, const int* LDX, double* FERR, double* BERR, double* WORK, int* IWORK, int* INFO); void FC_FUNC(ssysv, SSYSV) (const char* UPLO, const int* N, const int* NRHS, float* A, const int* LDA, int* IPIV, float* B, const int* LDB, float* WORK, const int* LWORK, int* INFO); void FC_FUNC(ssyrfs, SSYRFS) (const char* UPLO, const int* N, const int* NRHS, const vmg_float* A, const int* LDA, float* AF, const int* LDAF, const int* IPIV, const vmg_float* B, const int* LDB, float* X, const int* LDX, float* FERR, float* BERR, double* WORK, int* IWORK, int* INFO); } /* extern "C" */ /* By default, assume fcs_float is double. */ #if defined(FCS_FLOAT_IS_FLOAT) #define dsysv FC_FUNC(ssysv, SSYSV) #define dsyrfs FC_FUNC(ssyrfs, SSYRFS) #else #define dsysv FC_FUNC(dsysv, DSYSV) #define dsyrfs FC_FUNC(dsyrfs, DSYRFS) #endif template class DSYSV : public T { public: DSYSV(bool register_ = true) : T(register_) {Init();} DSYSV(int size, bool register_ = true) : T(size, register_) {Init();} virtual ~DSYSV(); protected: void Compute(); private: void Init(); void Realloc(); char la_uplo; int la_n, la_nrhs, *la_ipiv, la_lwork, la_info, *la_iwork; vmg_float *la_A, *la_A_orig, *la_B, *la_B_orig, *la_work, *la_work2; int cur_lapack_size, max_lapack_size; }; template void DSYSV::Compute() { vmg_float ferr, berr; vmg_float opt_work; this->Realloc(); for (int i=0; icur_lapack_size; i++) { la_B[i] = la_B_orig[i] = this->Rhs(i); for (int j=i; jcur_lapack_size; j++) la_A[j + i*this->cur_lapack_size] = la_A_orig[j + i*this->cur_lapack_size] = this->Mat(i,j); } // Determine optimal size of working space this->la_lwork = -1; dsysv (&la_uplo, &la_n, &la_nrhs, la_A, &la_n, la_ipiv, la_B, &la_n, &opt_work, &la_lwork, &la_info); // Resize working space this->la_lwork = static_cast(opt_work); delete [] this->la_work; this->la_work = new vmg_float[this->la_lwork]; // Solve system dsysv (&la_uplo, &la_n, &la_nrhs, la_A, &la_n, la_ipiv, la_B, &la_n, la_work, &la_lwork, &la_info); // Improve computed solution dsyrfs (&la_uplo, &la_n, &la_nrhs, la_A_orig, &la_n, la_A, &la_n, la_ipiv, la_B_orig, &la_n, la_B, &la_n, &ferr, &berr, la_work2, la_iwork, &la_info); // Write solution back for (int i=0; icur_lapack_size; i++) this->Sol(i) = this->la_B[i]; } template void DSYSV::Realloc() { this->cur_lapack_size = this->Size(); if (this->cur_lapack_size > this->max_lapack_size) { delete [] la_A; delete [] la_A_orig; delete [] la_B; delete [] la_B_orig; delete [] la_ipiv; delete [] la_work2; delete [] la_iwork; this->la_A = new vmg_float[this->cur_lapack_size * this->cur_lapack_size]; this->la_A_orig = new vmg_float[this->cur_lapack_size * this->cur_lapack_size]; this->la_B = new vmg_float[this->cur_lapack_size]; this->la_B_orig = new vmg_float[this->cur_lapack_size]; this->la_ipiv = new int[this->cur_lapack_size]; this->la_work2 = new vmg_float[3 * this->cur_lapack_size]; this->la_iwork = new int[this->cur_lapack_size]; this->la_n = this->cur_lapack_size; this->max_lapack_size = this->cur_lapack_size; } } template void DSYSV::Init() { this->cur_lapack_size = 0; this->max_lapack_size = 0; this->la_A = NULL; this->la_A_orig = NULL; this->la_B = NULL; this->la_B_orig = NULL; this->la_work = NULL; this->la_ipiv = NULL; this->la_work2 = NULL; this->la_iwork = NULL; this->la_nrhs = 1; this->la_uplo = 'L'; } template DSYSV::~DSYSV() { delete [] this->la_A; delete [] this->la_A_orig; delete [] this->la_B; delete [] this->la_B_orig; delete [] this->la_work; delete [] this->la_ipiv; delete [] this->la_work2; delete [] this->la_iwork; } } #endif /* DSYSV_HPP_ */