Cantera  3.0.0
Loading...
Searching...
No Matches
BandMatrix.cpp
Go to the documentation of this file.
1//! @file BandMatrix.cpp Banded matrices.
2
3// This file is part of Cantera. See License.txt in the top-level directory or
4// at https://cantera.org/license.txt for license and copyright information.
5
9
10#if CT_USE_LAPACK
12#else
13 #include "sunlinsol/sunlinsol_band.h"
14#endif
15
16#include <cstring>
17#include <fstream>
18
19using namespace std;
20
21namespace Cantera
22{
23
24// pImpl wrapper class for vector of Sundials index types to avoid needing to
25// include Sundials headers in BandMatrix.h
26struct BandMatrix::PivData {
27#if CT_USE_LAPACK
28 vector<int> data;
29#else
30 vector<sunindextype> data;
31#endif
32};
33
35 m_ipiv{new PivData()}
36{
37}
38
39BandMatrix::~BandMatrix()
40{
41 // Needs to be defined here so m_ipiv can be deleted
42}
43
44BandMatrix::BandMatrix(size_t n, size_t kl, size_t ku, double v) :
45 m_n(n),
46 m_kl(kl),
47 m_ku(ku),
48 m_ipiv{new PivData()}
49{
50 data.resize(n*(2*kl + ku + 1));
51 ludata.resize(n*(2*kl + ku + 1));
52 fill(data.begin(), data.end(), v);
53 fill(ludata.begin(), ludata.end(), 0.0);
54 m_ipiv->data.resize(m_n);
55 m_colPtrs.resize(n);
56 m_lu_col_ptrs.resize(n);
57 size_t ldab = (2*kl + ku + 1);
58 for (size_t j = 0; j < n; j++) {
59 m_colPtrs[j] = &data[ldab * j];
60 m_lu_col_ptrs[j] = &ludata[ldab * j];
61 }
62}
63
66 data(y.data),
67 ludata(y.ludata),
68 m_n(y.m_n),
69 m_kl(y.m_kl),
70 m_ku(y.m_ku),
71 m_ipiv{new PivData()},
72 m_info(y.m_info)
73{
74 m_ipiv->data = y.m_ipiv->data;
75 m_colPtrs.resize(m_n);
76 m_lu_col_ptrs.resize(m_n);
77 size_t ldab = (2 *m_kl + m_ku + 1);
78 for (size_t j = 0; j < m_n; j++) {
79 m_colPtrs[j] = &data[ldab * j];
80 m_lu_col_ptrs[j] = &ludata[ldab * j];
81 }
82}
83
84BandMatrix& BandMatrix::operator=(const BandMatrix& y)
85{
86 if (&y == this) {
87 return *this;
88 }
89 GeneralMatrix::operator=(y);
90 m_n = y.m_n;
91 m_kl = y.m_kl;
92 m_ku = y.m_ku;
93 m_ipiv->data = y.m_ipiv->data;
94 data = y.data;
95 ludata = y.ludata;
96 m_colPtrs.resize(m_n);
97 m_lu_col_ptrs.resize(m_n);
98 size_t ldab = (2 * m_kl + m_ku + 1);
99 for (size_t j = 0; j < m_n; j++) {
100 m_colPtrs[j] = &data[ldab * j];
101 m_lu_col_ptrs[j] = &ludata[ldab * j];
102 }
103 m_info = y.m_info;
104 return *this;
105}
106
107void BandMatrix::resize(size_t n, size_t kl, size_t ku, double v)
108{
109 m_n = n;
110 m_kl = kl;
111 m_ku = ku;
112 data.resize(n*(2*kl + ku + 1));
113 ludata.resize(n*(2*kl + ku + 1));
114 m_ipiv->data.resize(m_n);
115 fill(data.begin(), data.end(), v);
116 m_colPtrs.resize(m_n);
117 m_lu_col_ptrs.resize(m_n);
118 size_t ldab = (2 * m_kl + m_ku + 1);
119 for (size_t j = 0; j < n; j++) {
120 m_colPtrs[j] = &data[ldab * j];
121 m_lu_col_ptrs[j] = &ludata[ldab * j];
122 }
123 m_factored = false;
124}
125
126void BandMatrix::bfill(double v)
127{
128 std::fill(data.begin(), data.end(), v);
129 m_factored = false;
130}
131
133{
134 std::fill(data.begin(), data.end(), 0.0);
135 m_factored = false;
136}
137
138double& BandMatrix::operator()(size_t i, size_t j)
139{
140 return value(i,j);
141}
142
143double BandMatrix::operator()(size_t i, size_t j) const
144{
145 return value(i,j);
146}
147
148double& BandMatrix::value(size_t i, size_t j)
149{
150 m_factored = false;
151 if (i + m_ku < j || i > j + m_kl) {
152 return m_zero;
153 }
154 return data[index(i,j)];
155}
156
157double BandMatrix::value(size_t i, size_t j) const
158{
159 if (i + m_ku < j || i > j + m_kl) {
160 return 0.0;
161 }
162 return data[index(i,j)];
163}
164
165size_t BandMatrix::index(size_t i, size_t j) const
166{
167 return (2*m_kl + m_ku)*j + m_kl + m_ku + i;
168}
169
170double BandMatrix::_value(size_t i, size_t j) const
171{
172 return data[index(i,j)];
173}
174
175size_t BandMatrix::nRows() const
176{
177 return m_n;
178}
179
181{
182 return m_n;
183}
184
186{
187 return m_kl;
188}
189
191{
192 return m_ku;
193}
194
195size_t BandMatrix::ldim() const
196{
197 return 2*m_kl + m_ku + 1;
198}
199
200void BandMatrix::mult(const double* b, double* prod) const
201{
202 for (size_t m = 0; m < m_n; m++) {
203 double sum = 0.0;
204 size_t start = (m >= m_kl) ? m - m_kl : 0;
205 size_t stop = std::min(m + m_ku + 1, m_n);
206 for (size_t j = start; j < stop; j++) {
207 sum += _value(m,j) * b[j];
208 }
209 prod[m] = sum;
210 }
211}
212
213void BandMatrix::leftMult(const double* const b, double* const prod) const
214{
215 for (size_t n = 0; n < m_n; n++) {
216 double sum = 0.0;
217 size_t start = (n >= m_ku) ? n - m_ku : 0;
218 size_t stop = std::min(n + m_kl + 1, m_n);
219 for (size_t i = start; i < stop; i++) {
220 sum += _value(i,n) * b[i];
221 }
222 prod[n] = sum;
223 }
224}
225
227{
228 ludata = data;
229#if CT_USE_LAPACK
230 ct_dgbtrf(nRows(), nColumns(), nSubDiagonals(), nSuperDiagonals(),
231 ludata.data(), ldim(), m_ipiv->data.data(), m_info);
232#else
233 long int nu = static_cast<long int>(nSuperDiagonals());
234 long int nl = static_cast<long int>(nSubDiagonals());
235 long int smu = nu + nl;
236 #if CT_SUNDIALS_VERSION >= 60
237 m_info = SUNDlsMat_bandGBTRF(m_lu_col_ptrs.data(),
238 static_cast<long int>(nColumns()),
239 nu, nl, smu, m_ipiv->data.data());
240 #else
241 m_info = bandGBTRF(m_lu_col_ptrs.data(), static_cast<long int>(nColumns()),
242 nu, nl, smu, m_ipiv->data.data());
243 #endif
244#endif
245 if (m_info != 0) {
246 throw Cantera::CanteraError("BandMatrix::factor",
247 "Factorization failed with DGBTRF error code {}.", m_info);
248 }
249 m_factored = true;
250 return m_info;
251}
252
253int BandMatrix::solve(const double* const b, double* const x)
254{
255 copy(b, b + m_n, x);
256 return solve(x);
257}
258
259int BandMatrix::solve(double* b, size_t nrhs, size_t ldb)
260{
261 if (!m_factored) {
262 factor();
263 }
264 if (ldb == 0) {
265 ldb = nColumns();
266 }
267#if CT_USE_LAPACK
268 ct_dgbtrs(ctlapack::NoTranspose, nColumns(), nSubDiagonals(),
269 nSuperDiagonals(), nrhs, ludata.data(), ldim(),
270 m_ipiv->data.data(), b, ldb, m_info);
271#else
272 long int nu = static_cast<long int>(nSuperDiagonals());
273 long int nl = static_cast<long int>(nSubDiagonals());
274 long int smu = nu + nl;
275 double** a = m_lu_col_ptrs.data();
276 #if CT_SUNDIALS_VERSION >= 60
277 SUNDlsMat_bandGBTRS(a, static_cast<long int>(nColumns()), smu, nl,
278 m_ipiv->data.data(), b);
279 #else
280 bandGBTRS(a, static_cast<long int>(nColumns()), smu, nl,
281 m_ipiv->data.data(), b);
282 #endif
283 m_info = 0;
284#endif
285
286 if (m_info != 0) {
287 throw Cantera::CanteraError("BandMatrix::solve",
288 "Linear solve failed with DGBTRS error code {}.", m_info);
289 }
290 return m_info;
291}
292
293vector<double>::iterator BandMatrix::begin()
294{
295 warn_deprecated("BandMatrix::begin", "To be removed after Cantera 3.0.");
296 m_factored = false;
297 return data.begin();
298}
299
300vector<double>::iterator BandMatrix::end()
301{
302 warn_deprecated("BandMatrix::end", "To be removed after Cantera 3.0.");
303 m_factored = false;
304 return data.end();
305}
306
307vector<double>::const_iterator BandMatrix::begin() const
308{
309 warn_deprecated("BandMatrix::begin", "To be removed after Cantera 3.0.");
310 return data.begin();
311}
312
313vector<double>::const_iterator BandMatrix::end() const
314{
315 warn_deprecated("BandMatrix::end", "To be removed after Cantera 3.0.");
316 return data.end();
317}
318
319ostream& operator<<(ostream& s, const BandMatrix& m)
320{
321 for (size_t i = 0; i < m.nRows(); i++) {
322 s << m(i, 0);
323 for (size_t j = 1; j < m.nColumns(); j++) {
324 s << ", " << m(i,j);
325 }
326 s << endl;
327 }
328 return s;
329}
330
331double BandMatrix::rcond(double a1norm)
332{
333 iwork_.resize(m_n);
334 work_.resize(3 * m_n);
335
336 if (m_factored != 1) {
337 throw CanteraError("BandMatrix::rcond", "matrix isn't factored correctly");
338 }
339
340#if CT_USE_LAPACK
341 size_t ldab = (2 *m_kl + m_ku + 1);
342 int rinfo = 0;
343 double rcond = ct_dgbcon('1', m_n, m_kl, m_ku, ludata.data(),
344 ldab, m_ipiv->data.data(), a1norm, work_.data(), iwork_.data(), rinfo);
345 if (rinfo != 0) {
346 throw CanteraError("BandMatrix::rcond", "DGBCON returned INFO = {}", rinfo);
347 }
348 return rcond;
349#else
350 throw CanteraError("BandMatrix::rcond", "not implemented when LAPACK is missing");
351#endif
352}
353
355{
356 return 0;
357}
358
360{
361 double value = 0.0;
362 for (size_t j = 0; j < m_n; j++) {
363 double sum = 0.0;
364 size_t start = (j >= m_ku) ? j - m_ku : 0;
365 size_t stop = std::min(j + m_kl + 1, m_n);
366 for (size_t i = start; i < stop; i++) {
367 sum += std::abs(_value(i,j));
368 }
369 value = std::max(sum, value);
370 }
371 return value;
372}
373
374size_t BandMatrix::checkRows(double& valueSmall) const
375{
376 valueSmall = 1.0E300;
377 size_t iSmall = npos;
378 for (size_t i = 0; i < m_n; i++) {
379 double valueS = 0.0;
380 size_t start = (i > m_kl) ? i - m_kl : 0;
381 size_t stop = std::min(i + m_ku + 1, m_n);
382 for (size_t j = start; j < stop; j++) {
383 valueS = std::max(fabs(_value(i,j)), valueS);
384 }
385 if (valueS < valueSmall) {
386 iSmall = i;
387 valueSmall = valueS;
388 if (valueSmall == 0.0) {
389 return iSmall;
390 }
391 }
392 }
393 return iSmall;
394}
395
396size_t BandMatrix::checkColumns(double& valueSmall) const
397{
398 valueSmall = 1.0E300;
399 size_t jSmall = npos;
400 for (size_t j = 0; j < m_n; j++) {
401 double valueS = 0.0;
402 size_t start = (j > m_ku) ? j - m_ku : 0;
403 size_t stop = std::min(j + m_kl + 1, m_n);
404 for (size_t i = start; i < stop; i++) {
405 valueS = std::max(fabs(_value(i,j)), valueS);
406 }
407 if (valueS < valueSmall) {
408 jSmall = j;
409 valueSmall = valueS;
410 if (valueSmall == 0.0) {
411 return jSmall;
412 }
413 }
414 }
415 return jSmall;
416}
417
418double* BandMatrix::ptrColumn(size_t j)
419{
420 return m_colPtrs[j];
421}
422
423double* const* BandMatrix::colPts()
424{
425 return &m_colPtrs[0];
426}
427
428}
Declarations for the class BandMatrix which is a child class of GeneralMatrix for banded matrices han...
A class for banded matrices, involving matrix inversion processes.
Definition BandMatrix.h:37
void leftMult(const double *const b, double *const prod) const override
Multiply b*A and write result to prod.
double *const * colPts() override
Return a vector of const pointers to the columns.
double & operator()(size_t i, size_t j) override
Index into the (i,j) element.
vector< double > ludata
Factorized data.
Definition BandMatrix.h:274
size_t m_ku
Number of super diagonals of the matrix.
Definition BandMatrix.h:283
size_t m_kl
Number of subdiagonals of the matrix.
Definition BandMatrix.h:280
vector< double >::iterator end()
Returns an iterator for the end of the band storage data.
double m_zero
value of zero
Definition BandMatrix.h:286
double rcond(double a1norm) override
Returns an estimate of the inverse of the condition number for the matrix.
size_t nSubDiagonals() const
Number of subdiagonals.
void resize(size_t n, size_t kl, size_t ku, double v=0.0)
Resize the matrix problem.
size_t ldim() const
Return the number of rows of storage needed for the band storage.
size_t index(size_t i, size_t j) const
Returns the location in the internal 1D array corresponding to the (i,j) element in the banded array.
void bfill(double v=0.0)
Fill or zero the matrix.
vector< double >::iterator begin() override
Returns an iterator for the start of the band storage data.
BandMatrix()
Base Constructor.
size_t checkColumns(double &valueSmall) const override
Check to see if we have any zero columns in the Jacobian.
vector< double * > m_colPtrs
Vector of column pointers.
Definition BandMatrix.h:294
double * ptrColumn(size_t j) override
Return a pointer to the top of column j.
vector< double > work_
Extra dp work array needed - size = 3n.
Definition BandMatrix.h:301
int factor() override
Perform an LU decomposition, the LAPACK routine DGBTRF is used.
unique_ptr< PivData > m_ipiv
Pivot vector.
Definition BandMatrix.h:291
size_t nColumns() const
Number of columns.
void mult(const double *b, double *prod) const override
Multiply A*b and write result to prod.
size_t checkRows(double &valueSmall) const override
Check to see if we have any zero rows in the Jacobian.
size_t nSuperDiagonals() const
Number of superdiagonals.
size_t nRows() const override
Return the number of rows in the matrix.
vector< int > iwork_
Extra work array needed - size = n.
Definition BandMatrix.h:298
vector< double > data
Matrix data.
Definition BandMatrix.h:271
int solve(const double *const b, double *const x)
Solve the matrix problem Ax = b.
void zero() override
Zero the matrix elements.
size_t m_n
Number of rows and columns of the matrix.
Definition BandMatrix.h:277
double oneNorm() const override
Returns the one norm of the matrix.
double _value(size_t i, size_t j) const
Return the value of the (i,j) element for (i,j) within the bandwidth.
double & value(size_t i, size_t j)
Return a changeable reference to element (i,j).
int factorAlgorithm() const override
Returns the factor algorithm used.
Base class for exceptions thrown by Cantera classes.
int m_factored
Indicates whether the matrix is factored.
Namespace for the Cantera kernel.
Definition AnyMap.cpp:564
const size_t npos
index returned by functions to indicate "no position"
Definition ct_defs.h:195
void warn_deprecated(const string &source, const AnyBase &node, const string &message)
A deprecation warning for syntax in an input file.
Definition AnyMap.cpp:1926
std::ostream & operator<<(std::ostream &s, const Array2D &m)
Output the current contents of the Array2D object.
Definition Array.cpp:120
Contains declarations for string manipulation functions within Cantera.
Various templated functions that carry out common vector and polynomial operations (see Templated Arr...