Cantera  3.1.0a1
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 
19 using namespace std;
20 
21 namespace Cantera
22 {
23 
24 // pImpl wrapper class for vector of Sundials index types to avoid needing to
25 // include Sundials headers in BandMatrix.h
26 struct BandMatrix::PivData {
27 #if CT_USE_LAPACK
28  vector<int> data;
29 #else
30  vector<sunindextype> data;
31 #endif
32 };
33 
34 BandMatrix::BandMatrix() :
35  m_ipiv{new PivData()}
36 {
37 }
38 
39 BandMatrix::~BandMatrix()
40 {
41  // Needs to be defined here so m_ipiv can be deleted
42 }
43 
44 BandMatrix::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 
65  GeneralMatrix(y),
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 
84 BandMatrix& 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 
107 void 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 
126 void 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 
138 double& BandMatrix::operator()(size_t i, size_t j)
139 {
140  return value(i,j);
141 }
142 
143 double BandMatrix::operator()(size_t i, size_t j) const
144 {
145  return value(i,j);
146 }
147 
148 double& 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 
157 double 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 
165 size_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 
170 double BandMatrix::_value(size_t i, size_t j) const
171 {
172  return data[index(i,j)];
173 }
174 
175 size_t BandMatrix::nRows() const
176 {
177  return m_n;
178 }
179 
180 size_t BandMatrix::nColumns() const
181 {
182  return m_n;
183 }
184 
186 {
187  return m_kl;
188 }
189 
191 {
192  return m_ku;
193 }
194 
195 size_t BandMatrix::ldim() const
196 {
197  return 2*m_kl + m_ku + 1;
198 }
199 
200 void 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 
213 void 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 
253 int BandMatrix::solve(const double* const b, double* const x)
254 {
255  copy(b, b + m_n, x);
256  return solve(x);
257 }
258 
259 int 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 
293 ostream& operator<<(ostream& s, const BandMatrix& m)
294 {
295  for (size_t i = 0; i < m.nRows(); i++) {
296  s << m(i, 0);
297  for (size_t j = 1; j < m.nColumns(); j++) {
298  s << ", " << m(i,j);
299  }
300  s << endl;
301  }
302  return s;
303 }
304 
305 double BandMatrix::rcond(double a1norm)
306 {
307  iwork_.resize(m_n);
308  work_.resize(3 * m_n);
309 
310  if (m_factored != 1) {
311  throw CanteraError("BandMatrix::rcond", "matrix isn't factored correctly");
312  }
313 
314 #if CT_USE_LAPACK
315  size_t ldab = (2 *m_kl + m_ku + 1);
316  int rinfo = 0;
317  double rcond = ct_dgbcon('1', m_n, m_kl, m_ku, ludata.data(),
318  ldab, m_ipiv->data.data(), a1norm, work_.data(), iwork_.data(), rinfo);
319  if (rinfo != 0) {
320  throw CanteraError("BandMatrix::rcond", "DGBCON returned INFO = {}", rinfo);
321  }
322  return rcond;
323 #else
324  throw CanteraError("BandMatrix::rcond", "not implemented when LAPACK is missing");
325 #endif
326 }
327 
329 {
330  return 0;
331 }
332 
333 double BandMatrix::oneNorm() const
334 {
335  double value = 0.0;
336  for (size_t j = 0; j < m_n; j++) {
337  double sum = 0.0;
338  size_t start = (j >= m_ku) ? j - m_ku : 0;
339  size_t stop = std::min(j + m_kl + 1, m_n);
340  for (size_t i = start; i < stop; i++) {
341  sum += std::abs(_value(i,j));
342  }
343  value = std::max(sum, value);
344  }
345  return value;
346 }
347 
348 size_t BandMatrix::checkRows(double& valueSmall) const
349 {
350  valueSmall = 1.0E300;
351  size_t iSmall = npos;
352  for (size_t i = 0; i < m_n; i++) {
353  double valueS = 0.0;
354  size_t start = (i > m_kl) ? i - m_kl : 0;
355  size_t stop = std::min(i + m_ku + 1, m_n);
356  for (size_t j = start; j < stop; j++) {
357  valueS = std::max(fabs(_value(i,j)), valueS);
358  }
359  if (valueS < valueSmall) {
360  iSmall = i;
361  valueSmall = valueS;
362  if (valueSmall == 0.0) {
363  return iSmall;
364  }
365  }
366  }
367  return iSmall;
368 }
369 
370 size_t BandMatrix::checkColumns(double& valueSmall) const
371 {
372  valueSmall = 1.0E300;
373  size_t jSmall = npos;
374  for (size_t j = 0; j < m_n; j++) {
375  double valueS = 0.0;
376  size_t start = (j > m_ku) ? j - m_ku : 0;
377  size_t stop = std::min(j + m_kl + 1, m_n);
378  for (size_t i = start; i < stop; i++) {
379  valueS = std::max(fabs(_value(i,j)), valueS);
380  }
381  if (valueS < valueSmall) {
382  jSmall = j;
383  valueSmall = valueS;
384  if (valueSmall == 0.0) {
385  return jSmall;
386  }
387  }
388  }
389  return jSmall;
390 }
391 
392 double* BandMatrix::ptrColumn(size_t j)
393 {
394  return m_colPtrs[j];
395 }
396 
397 double* const* BandMatrix::colPts()
398 {
399  return &m_colPtrs[0];
400 }
401 
402 }
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.
Definition: BandMatrix.cpp:213
double *const * colPts() override
Return a vector of const pointers to the columns.
Definition: BandMatrix.cpp:397
double & operator()(size_t i, size_t j) override
Index into the (i,j) element.
Definition: BandMatrix.cpp:138
vector< double > ludata
Factorized data.
Definition: BandMatrix.h:246
size_t m_ku
Number of super diagonals of the matrix.
Definition: BandMatrix.h:255
size_t m_kl
Number of subdiagonals of the matrix.
Definition: BandMatrix.h:252
double m_zero
value of zero
Definition: BandMatrix.h:258
double rcond(double a1norm) override
Returns an estimate of the inverse of the condition number for the matrix.
Definition: BandMatrix.cpp:305
size_t nSubDiagonals() const
Number of subdiagonals.
Definition: BandMatrix.cpp:185
void resize(size_t n, size_t kl, size_t ku, double v=0.0)
Resize the matrix problem.
Definition: BandMatrix.cpp:107
size_t ldim() const
Return the number of rows of storage needed for the band storage.
Definition: BandMatrix.cpp:195
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.
Definition: BandMatrix.cpp:165
void bfill(double v=0.0)
Fill or zero the matrix.
Definition: BandMatrix.cpp:126
BandMatrix()
Base Constructor.
Definition: BandMatrix.cpp:34
size_t checkColumns(double &valueSmall) const override
Check to see if we have any zero columns in the Jacobian.
Definition: BandMatrix.cpp:370
vector< double * > m_colPtrs
Vector of column pointers.
Definition: BandMatrix.h:266
double * ptrColumn(size_t j) override
Return a pointer to the top of column j.
Definition: BandMatrix.cpp:392
vector< double > work_
Extra dp work array needed - size = 3n.
Definition: BandMatrix.h:273
int factor() override
Perform an LU decomposition, the LAPACK routine DGBTRF is used.
Definition: BandMatrix.cpp:226
unique_ptr< PivData > m_ipiv
Pivot vector.
Definition: BandMatrix.h:260
size_t nColumns() const
Number of columns.
Definition: BandMatrix.cpp:180
void mult(const double *b, double *prod) const override
Multiply A*b and write result to prod.
Definition: BandMatrix.cpp:200
size_t checkRows(double &valueSmall) const override
Check to see if we have any zero rows in the Jacobian.
Definition: BandMatrix.cpp:348
size_t nSuperDiagonals() const
Number of superdiagonals.
Definition: BandMatrix.cpp:190
size_t nRows() const override
Return the number of rows in the matrix.
Definition: BandMatrix.cpp:175
vector< int > iwork_
Extra work array needed - size = n.
Definition: BandMatrix.h:270
vector< double > data
Matrix data.
Definition: BandMatrix.h:239
int solve(const double *const b, double *const x)
Solve the matrix problem Ax = b.
Definition: BandMatrix.cpp:253
void zero() override
Zero the matrix elements.
Definition: BandMatrix.cpp:132
size_t m_n
Number of rows and columns of the matrix.
Definition: BandMatrix.h:249
double oneNorm() const override
Returns the one norm of the matrix.
Definition: BandMatrix.cpp:333
double _value(size_t i, size_t j) const
Return the value of the (i,j) element for (i,j) within the bandwidth.
Definition: BandMatrix.cpp:170
double & value(size_t i, size_t j)
Return a changeable reference to element (i,j).
Definition: BandMatrix.cpp:148
int factorAlgorithm() const override
Returns the factor algorithm used.
Definition: BandMatrix.cpp:328
Base class for exceptions thrown by Cantera classes.
Definition: ctexceptions.h:66
Generic matrix.
Definition: GeneralMatrix.h:23
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:180
std::ostream & operator<<(std::ostream &s, const Array2D &m)
Output the current contents of the Array2D object.
Definition: Array.cpp:100
Contains declarations for string manipulation functions within Cantera.
Various templated functions that carry out common vector and polynomial operations (see Templated Arr...