CppNoddy  0.92
Loading...
Searching...
No Matches
BandedLinearSystem.cpp
Go to the documentation of this file.
1
2/// \file BandedLinearSystem.cpp
3/// Implementation for the LinearSystem class
4
5#include <vector>
6#include <set>
7#include <cassert>
8
9#include <FortranLAPACK.h>
10#include <BandedLinearSystem.h>
11#include <Exceptions.h>
12#include <Utility.h>
13#include <Types.h>
14
15namespace CppNoddy {
16
17 template <typename _Type>
19 (BandedMatrix<_Type>* Aptr, DenseVector<_Type>* Bptr, std::string which) :
20 m_detSign(0), m_monitorDet(false) {
21 m_pA = Aptr;
22 m_pB = Bptr;
23 m_version = which;
24 if((m_version != "lapack") && (m_version != "native")) {
25 std::string problem;
26 problem = "The BandedLinearSystem has been instantiated with an unrecognised\n";
27 problem += "request for a solver type. Options are 'native' or 'lapack'. \n";
28 throw ExceptionRuntime(problem);
29 }
30 }
31
32
33 template <typename _Type>
35 if("lapack" == m_version) {
36 solve_lapack();
37 } else { // we catch incorrect m_version choices in the ctor
38 solve_native();
39 }
40 }
41
42 // only the specialised solvers below are available
43 template <typename _Type>
45 std::string problem;
46 problem = "The solve method for a BandedLinearSystem has not been implemented\n";
47 problem += "for the element type used here. \n";
48 throw ExceptionExternal(problem);
49 }
50
51 // lapack LU solver for double-element banded matrices
52 template <>
53 void BandedLinearSystem<double>::solve_lapack() {
54#ifndef LAPACK
55 std::string problem = "The BandedLinearSystem<double>::solve_lapack method has been called\n";
56 problem += "but the compiler option -DLAPACK was not provided when\n";
57 problem += "the library was built and so LAPACK support is not available.";
58 throw ExceptionExternal(problem);
59#else
60 const std::size_t N = m_pA -> nrows();
61 const std::size_t K = 1;
62 const std::size_t L = m_pA -> noffdiag();
63 const std::size_t LDAB = 3 * L + 1;
64 // pivot storage
65 std::vector<int> pivots(N);
66 // warning info
67 int info(0);
68 LAPACK_DGBSV(N, L, L, K, m_pA -> base(), LDAB, &pivots[ 0 ], &(m_pB -> operator[](0)), N, info);
69 m_pivots = pivots;
70 if(0 != info) {
71 std::string problem(" The BandedLinearSystem::solve_lapack method has detected a failure. \n");
72 throw ExceptionExternal(problem, info);
73 }
74 // compute the determinant if asked
75 if(m_monitorDet) {
76 m_detSign = signature(pivots);
77 // product of the diagonals
78 for(std::size_t i = 0; i < N; ++i) {
79 if((*m_pA)(i, i) < 0.0) {
80 m_detSign *= -1;
81 }
82 }
83 }
84#endif
85 }
86
87 // lapack LU re-solver for double-element banded matrices
88 template <>
90#ifndef LAPACK
91 std::string problem = "The BandedLinearSystem<double>::re_solve_lapack method has been called\n";
92 problem += "but the compiler option -DLAPACK was not provided when\n";
93 problem += "the library was built and so LAPACK support is not available.";
94 throw ExceptionExternal(problem);
95#else
96 const std::size_t N = m_pA -> nrows();
97 const std::size_t K = 1;
98 const std::size_t L = m_pA -> noffdiag();
99 const std::size_t LDAB = 3 * L + 1;
100 // warning info
101 int info(0);
102 // LAPACK_DGBSV( N, L, L, K, m_pA -> base(), LDAB, &pivots[ 0 ], &( m_pB -> operator[] ( 0 ) ), N, info );
103 LAPACK_DGBTRS((char*) "N", N, L, L, K, m_pA -> base(), LDAB, &m_pivots[ 0 ], &(m_pB -> operator[](0)), N, info);
104 if(0 != info) {
105 std::string problem(" The BandedLinearSystem::re_solve_lapack method has detected a failure. \n");
106 throw ExceptionExternal(problem, info);
107 }
108#endif
109 }
110
111
112 // lapack LU solver for complex-element banded matrices
113 template <>
115#ifndef LAPACK
116 std::string problem = "The BandedLinearSystem<D_complex>::solve_lapack method has been called\n";
117 problem += "but the compiler option -DLAPACK was not provided when\n";
118 problem += "the library was built and so LAPACK support is not available.";
119 throw ExceptionExternal(problem);
120#else
121 const std::size_t N = m_pA -> nrows();
122 const std::size_t K = 1;
123 const std::size_t L = m_pA -> noffdiag();
124 const std::size_t LDAB = 3 * L + 1;
125 // pivot storage
126 std::vector<int> pivots(N);
127 // warning info
128 int info(0);
129 // LAPACK_ZGBSV( N, L, L, K, m_pA -> base(), LDAB, &pivots[ 0 ], &( m_pB -> operator[]( 0 ).real() ), N, info );
130 LAPACK_ZGBSV(N, L, L, K, m_pA -> base(), LDAB, &pivots[ 0 ], &reinterpret_cast<double(&)[2]>(m_pB -> operator[](0))[0], N, info);
131 if(0 != info) {
132 std::string problem(" The BandedLinearSystem::solve_lapack method has detected a failure. \n");
133 throw ExceptionExternal(problem, info);
134 }
135#endif
136 }
137
138
139 template <typename _Type>
140 void BandedLinearSystem<_Type>::solve_native() {
141 // determinant sign correction from pivotting
142 int sign(1);
143 // number of offdiagonal elts STORED above the main diagonal
144 const unsigned L = m_pA -> noffdiag();
145 const std::size_t N = m_pA -> nrows();
146 // step through rows
147 for(std::size_t l = 0 ; l < N - 1 ; ++l) {
148 _Type diag_entry = (*m_pA)(l, l);
149 // eliminate all entries below
150 // this is the maximum number of non-zero elts below the diagonal
151 // +1 because of usual zero indexing
152 const std::size_t row_end = std::min(N, l + 1 * L + 1);
153 const std::size_t col_end = std::min(N, l + 2 * L + 1);
154
155 // assume the diagonal elt is currently the maximum one
156 std::size_t max_row = l;
157 // partial pivot by looking at this COLUMN for bigger values
158 for(std::size_t row = l + 1; row < row_end; ++row) {
159 if(std::abs((*m_pA)(row, l)) > std::abs(diag_entry)) {
160 diag_entry = (*m_pA)(row, l);
161 max_row = row;
162 }
163 }
164 // swap rows if suitable maximum is found
165 if(max_row != l) {
166 sign *= -1;
167 m_pA -> row_swap(l, max_row);
168 // swap RHS
169 m_pB -> swap(l, max_row);
170 }
171 // eliminate
172 for(std::size_t row = l + 1 ; row < row_end; ++row) {
173 // work out mulitplier
174 const _Type mult = (*m_pA)(row, l) / diag_entry;
175 // how to subtract two rows
176 for(std::size_t col = l; col < col_end; ++col) {
177 (*m_pA)(row, col) -= (*m_pA)(l, col) * mult;
178 }
179 // do the same subtraction of the RHS
180 m_pB -> operator[](row) -= mult * m_pB -> operator[](l);
181 } // close row-loop
182 } // close l-loop
183
184 if(m_monitorDet) {
185 m_detSign = sign;
186 for(std::size_t i = 0; i < N; ++i) {
187 if(lt(m_pA -> operator()(i, i))) {
188 m_detSign *= -1;
189 }
190 }
191 }
192
193 // backsubstitute upper triangular matrix
194 backsub();
195 }
196
197 template <typename _Type>
198 bool BandedLinearSystem<_Type>::lt(_Type value) const {
199 std::string problem;
200 problem = "You've turned on monitoring of the sign of the determinant for a \n";
201 problem += "BandedLinearSystem whose elements are not of type <double>.\n";
202 throw ExceptionRuntime(problem);
203 }
204
205 template <>
206 bool BandedLinearSystem<double>::lt(double value) const {
207 return (value < 0);
208 }
209
210 template <typename _Type>
211 int BandedLinearSystem<_Type>::signature(const std::vector<int> &pivots) const {
212 int sign(1);
213 for(std::size_t i = 0; i < pivots.size(); ++i) {
214 if(pivots[ i ] - 1 != int(i)) {
215 sign *= -1;
216 }
217 }
218 return sign;
219 }
220
221 template <typename _Type>
222 void BandedLinearSystem<_Type >::backsub() const {
223 const std::size_t L = m_pA -> noffdiag();
224 const std::size_t N = m_pB -> size();
225 (*m_pB)[ N - 1 ] /= (*m_pA)(N - 1, N - 1);
226 // Note the unusual row termination condition.
227 // We can't do just "row >= 0" with std::size_t
228 for(std::size_t row = N - 2; (int) row >= 0; --row) {
229 _Type sum(0.0);
230 for(std::size_t col = row + 1; col < std::min(N, row + 2 * L + 1); ++col) {
231 sum += (*m_pA)(row, col) * (*m_pB)[ col ];
232 }
233 (*m_pB)[ row ] -= sum;
234 (*m_pB)[ row ] /= (*m_pA)(row, row);
235 }
236 }
237
238 template<typename _Type>
240 return m_detSign;
241 }
242
243 template<typename _Type>
245 m_monitorDet = flag;
246 }
247
248
249
250 template class BandedLinearSystem<D_complex>
251 ;
252 template class BandedLinearSystem<double>
253 ;
254
255} // end namespace
Specification of the linear system class.
The collection of CppNoddy exceptions.
Some interface definitions for calling external fortran routines in LAPACK.
A spec for a collection of utility functions.
A linear system class for vector right-hand sides.
void re_solve_lapack()
Resolve the banded system.
void solve()
Solve the banded system.
void set_monitor_det(bool flag)
Store the sign of the determinant of the LHS matrix every time a solve is requested on a real system.
int get_det_sign() const
Get the sign of the determinant of the LHS matrix from the linear system just computed.
BandedLinearSystem(BandedMatrix< _Type > *Aptr, DenseVector< _Type > *Bptr, std::string which="native")
Constructor for a banded linear system object.
A matrix class that constructs a BANDED matrix.
Definition: BandedMatrix.h:16
An DenseVector class – a dense vector object.
Definition: DenseVector.h:34
An exception to indicate that an error has been detected in an external (LAPACK) routine.
Definition: Exceptions.h:20
A generic runtime exception.
Definition: Exceptions.h:158
A collection of OO numerical routines aimed at simple (typical) applied problems in continuum mechani...

© 2012

R.E. Hewitt