Cantera  2.0
BandMatrix.cpp
Go to the documentation of this file.
1 /**
2  * @file BandMatrix.cpp
3  *
4  * Banded matrices.
5  */
6 
7 // Copyright 2001 California Institute of Technology
8 
11 #include "cantera/base/utilities.h"
14 #include "cantera/base/global.h"
15 
16 #include <cstring>
17 #include <fstream>
18 
19 using namespace std;
20 
21 namespace Cantera
22 {
23 
24 //====================================================================================================================
25 BandMatrix::BandMatrix() :
26  GeneralMatrix(1),
27  m_factored(false),
28  m_n(0),
29  m_kl(0),
30  m_ku(0),
31  m_zero(0.0)
32 {
33  data.clear();
34  ludata.clear();
35 }
36 //====================================================================================================================
37 BandMatrix::BandMatrix(size_t n, size_t kl, size_t ku, doublereal v) :
38  GeneralMatrix(1),
39  m_factored(false),
40  m_n(n),
41  m_kl(kl),
42  m_ku(ku),
43  m_zero(0.0)
44 {
45  data.resize(n*(2*kl + ku + 1));
46  ludata.resize(n*(2*kl + ku + 1));
47  fill(data.begin(), data.end(), v);
48  fill(ludata.begin(), ludata.end(), 0.0);
49  m_ipiv.resize(m_n);
50  m_colPtrs.resize(n);
51  size_t ldab = (2*kl + ku + 1);
52  for (size_t j = 0; j < n; j++) {
53  m_colPtrs[j] = &(data[ldab * j]);
54  }
55 }
56 //====================================================================================================================
58  GeneralMatrix(1),
59  m_factored(false),
60  m_n(0),
61  m_kl(0),
62  m_ku(0),
63  m_zero(0.0)
64 {
65  m_n = y.m_n;
66  m_kl = y.m_kl;
67  m_ku = y.m_ku;
68  data = y.data;
69  ludata = y.ludata;
71  m_ipiv = y.m_ipiv;
72  m_colPtrs.resize(m_n);
73  size_t ldab = (2 *m_kl + m_ku + 1);
74  for (size_t j = 0; j < m_n; j++) {
75  m_colPtrs[j] = &(data[ldab * j]);
76  }
77 }
78 //====================================================================================================================
80 {
81 
82 }
83 //====================================================================================================================
85 {
86  if (&y == this) {
87  return *this;
88  }
90  m_n = y.m_n;
91  m_kl = y.m_kl;
92  m_ku = y.m_ku;
93  m_ipiv = y.m_ipiv;
94  data = y.data;
95  ludata = y.ludata;
97  m_colPtrs.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  }
102  return *this;
103 }
104 //====================================================================================================================
105 void BandMatrix::resize(size_t n, size_t kl, size_t ku, doublereal v)
106 {
107  m_n = n;
108  m_kl = kl;
109  m_ku = ku;
110  data.resize(n*(2*kl + ku + 1));
111  ludata.resize(n*(2*kl + ku + 1));
112  m_ipiv.resize(m_n);
113  fill(data.begin(), data.end(), v);
114  m_colPtrs.resize(m_n);
115  size_t ldab = (2 * m_kl + m_ku + 1);
116  for (size_t j = 0; j < n; j++) {
117  m_colPtrs[j] = &(data[ldab * j]);
118  }
119  m_factored = false;
120 }
121 //====================================================================================================================
122 void BandMatrix::bfill(doublereal v)
123 {
124  std::fill(data.begin(), data.end(), v);
125  m_factored = false;
126 }
127 //====================================================================================================================
129 {
130  std::fill(data.begin(), data.end(), 0.0);
131  m_factored = false;
132 }
133 //====================================================================================================================
134 doublereal& BandMatrix::operator()(size_t i, size_t j)
135 {
136  return value(i,j);
137 }
138 //====================================================================================================================
139 doublereal BandMatrix::operator()(size_t i, size_t j) const
140 {
141  return value(i,j);
142 }
143 //====================================================================================================================
144 doublereal& BandMatrix::value(size_t i, size_t j)
145 {
146  m_factored = false;
147  if (i + m_ku < j || i > j + m_kl) {
148  return m_zero;
149  }
150  return data[index(i,j)];
151 }
152 //====================================================================================================================
153 doublereal BandMatrix::value(size_t i, size_t j) const
154 {
155  if (i + m_ku < j || i > j + m_kl) {
156  return 0.0;
157  }
158  return data[index(i,j)];
159 }
160 //====================================================================================================================
161 size_t BandMatrix::index(size_t i, size_t j) const
162 {
163  int jj = static_cast<int>(j);
164  int ii = static_cast<int>(i);
165  size_t rw = (int) m_kl + (int) m_ku + (int) ii - jj;
166  return (2*m_kl + m_ku + 1)*j + rw;
167 }
168 //====================================================================================================================
169 doublereal BandMatrix::_value(size_t i, size_t j) const
170 {
171  return data[index(i,j)];
172 }
173 //====================================================================================================================
174 // Number of rows
175 size_t BandMatrix::nRows() const
176 {
177  return m_n;
178 }
179 //====================================================================================================================
180 // Number of rows
181 size_t BandMatrix::nRowsAndStruct(size_t* const iStruct) const
182 {
183  if (iStruct) {
184  iStruct[0] = m_kl;
185  iStruct[1] = m_ku;
186  }
187  return m_n;
188 }
189 //====================================================================================================================
190 // Number of columns
191 size_t BandMatrix::nColumns() const
192 {
193  return m_n;
194 }
195 //====================================================================================================================
196 // Number of subdiagonals
198 {
199  return m_kl;
200 }
201 //====================================================================================================================
202 // Number of superdiagonals
204 {
205  return m_ku;
206 }
207 //====================================================================================================================
208 size_t BandMatrix::ldim() const
209 {
210  return 2*m_kl + m_ku + 1;
211 }
212 //====================================================================================================================
214 {
215  return m_ipiv;
216 }
217 //====================================================================================================================
218 /*
219  * Multiply A*b and write result to \c prod.
220  */
221 void BandMatrix::mult(const doublereal* b, doublereal* prod) const
222 {
223  int kl = static_cast<int>(m_kl);
224  int ku = static_cast<int>(m_ku);
225  int nr = static_cast<int>(nRows());
226  doublereal sum = 0.0;
227  for (int m = 0; m < nr; m++) {
228  sum = 0.0;
229  for (int j = m - kl; j <= m + ku; j++) {
230  if (j >= 0 && j < (int) m_n) {
231  sum += _value(m,j) * b[j];
232  }
233  }
234  prod[m] = sum;
235  }
236 }
237 //====================================================================================================================
238 /*
239  * Multiply b*A and write result to \c prod.
240  */
241 void BandMatrix::leftMult(const doublereal* const b, doublereal* const prod) const
242 {
243  int kl = static_cast<int>(m_kl);
244  int ku = static_cast<int>(m_ku);
245  int nc = static_cast<int>(nColumns());
246  doublereal sum = 0.0;
247  for (int n = 0; n < nc; n++) {
248  sum = 0.0;
249  for (int i = n - ku; i <= n + kl; i++) {
250  if (i >= 0 && i < (int) m_n) {
251  size_t ii = i;
252  sum += _value(ii,n) * b[ii];
253  }
254  }
255  prod[n] = sum;
256  }
257 }
258 //====================================================================================================================
259 /*
260  * Perform an LU decomposition. LAPACK routine DGBTRF is used.
261  * The factorization is saved in ludata.
262  */
264 {
265  int info=0;
266  copy(data.begin(), data.end(), ludata.begin());
267  ct_dgbtrf(nRows(), nColumns(), nSubDiagonals(), nSuperDiagonals(),
268  DATA_PTR(ludata), ldim(), DATA_PTR(ipiv()), info);
269 
270  // if info = 0, LU decomp succeeded.
271  if (info == 0) {
272  m_factored = true;
273  } else {
274  m_factored = false;
275  ofstream fout("bandmatrix.csv");
276  fout << *this << endl;
277  fout.close();
278  }
279  return info;
280 }
281 //====================================================================================================================
282 int BandMatrix::solve(const doublereal* const b, doublereal* const x)
283 {
284  copy(b, b + m_n, x);
285  return solve(x);
286 }
287 //====================================================================================================================
288 int BandMatrix::solve(doublereal* b)
289 {
290  int info = 0;
291  if (!m_factored) {
292  info = factor();
293  }
294  if (info == 0)
295  ct_dgbtrs(ctlapack::NoTranspose, nColumns(), nSubDiagonals(),
297  DATA_PTR(ipiv()), b, nColumns(), info);
298 
299  // error handling
300  if (info != 0) {
301  ofstream fout("bandmatrix.csv");
302  fout << *this << endl;
303  fout.close();
304  }
305  return info;
306 }
307 //====================================================================================================================
308 vector_fp::iterator BandMatrix::begin()
309 {
310  m_factored = false;
311  return data.begin();
312 }
313 //====================================================================================================================
314 vector_fp::iterator BandMatrix::end()
315 {
316  m_factored = false;
317  return data.end();
318 }
319 //====================================================================================================================
320 vector_fp::const_iterator BandMatrix::begin() const
321 {
322  return data.begin();
323 }
324 //====================================================================================================================
325 vector_fp::const_iterator BandMatrix::end() const
326 {
327  return data.end();
328 }
329 //====================================================================================================================
330 ostream& operator<<(ostream& s, const BandMatrix& m)
331 {
332  size_t nr = m.nRows();
333  size_t nc = m.nColumns();
334  for (size_t i = 0; i < nr; i++) {
335  for (size_t j = 0; j < nc; j++) {
336  s << m(i,j) << ", ";
337  }
338  s << endl;
339  }
340  return s;
341 }
342 //====================================================================================================================
343 void BandMatrix::err(std::string msg) const
344 {
345  throw CanteraError("BandMatrix() unimplemented function", msg);
346 }
347 //====================================================================================================================
348 // Factors the A matrix using the QR algorithm, overwriting A
349 /*
350  * we set m_factored to 2 to indicate the matrix is now QR factored
351  *
352  * @return Returns the info variable from lapack
353  */
355 {
356  factor();
357  return 0;
358 }
359 //====================================================================================================================
360 // Factors the A matrix using the QR algorithm, overwriting A
361 // Returns an estimate of the inverse of the condition number for the matrix
362 /*
363  * The matrix must have been previously factored using the QR algorithm
364  *
365  * @return returns the inverse of the condition number
366  */
368 {
369  double a1norm = oneNorm();
370  return rcond(a1norm);
371 }
372 //====================================================================================================================
373 // Returns an estimate of the inverse of the condition number for the matrix
374 /*
375  * The matrix must have been previously factored using the LU algorithm
376  *
377  * @param a1norm Norm of the matrix
378  *
379  * @return returns the inverse of the condition number
380  */
381 doublereal BandMatrix::rcond(doublereal a1norm)
382 {
383  int printLevel = 0;
384  int useReturnErrorCode = 0;
385  if (iwork_.size() < m_n) {
386  iwork_.resize(m_n);
387  }
388  if (work_.size() < 3 * m_n) {
389  work_.resize(3 * m_n);
390  }
391  doublereal rcond = 0.0;
392  if (m_factored != 1) {
393  throw CanteraError("BandMatrix::rcond()", "matrix isn't factored correctly");
394  }
395 
396  // doublereal anorm = oneNorm();
397  size_t ldab = (2 *m_kl + m_ku + 1);
398  int rinfo = 0;
399  rcond = ct_dgbcon('1', m_n, m_kl, m_ku, DATA_PTR(ludata), ldab, DATA_PTR(m_ipiv), a1norm, DATA_PTR(work_),
400  DATA_PTR(iwork_), rinfo);
401  if (rinfo != 0) {
402  if (printLevel) {
403  writelogf("BandMatrix::rcond(): DGBCON returned INFO = %d\n", rinfo);
404  }
405  if (! useReturnErrorCode) {
406  throw CanteraError("BandMatrix::rcond()", "DGBCON returned INFO = " + int2str(rinfo));
407  }
408  }
409  return rcond;
410 }
411 //====================================================================================================================
412 // Change the way the matrix is factored
413 /*
414  * @param fAlgorithm integer
415  * 0 LU factorization
416  * 1 QR factorization
417  */
418 void BandMatrix::useFactorAlgorithm(int fAlgorithm)
419 {
420  // QR algorithm isn't implemented for banded matrix.
421 }
422 //====================================================================================================================
424 {
425  return 0;
426 }
427 //====================================================================================================================
428 // Returns the one norm of the matrix
429 doublereal BandMatrix::oneNorm() const
430 {
431  int ku = static_cast<int>(m_ku);
432  int kl = static_cast<int>(m_kl);
433  doublereal value = 0.0;
434  for (int j = 0; j < (int) m_n; j++) {
435  doublereal sum = 0.0;
436  doublereal* colP = m_colPtrs[j];
437  for (int i = j - ku; i <= j + kl; i++) {
438  sum += fabs(colP[kl + ku + i - j]);
439  }
440  if (sum > value) {
441  value = sum;
442  }
443  }
444  return value;
445 }
446 //====================================================================================================================
447 size_t BandMatrix::checkRows(doublereal& valueSmall) const
448 {
449  valueSmall = 1.0E300;
450  size_t iSmall = npos;
451  double vv;
452  for (int i = 0; i < (int) m_n; i++) {
453  double valueS = 0.0;
454  for (int j = i - (int) m_kl; j <= i + (int) m_ku; j++) {
455  if (j >= 0 && j < (int) m_n) {
456  vv = fabs(value(i,j));
457  if (vv > valueS) {
458  valueS = vv;
459  }
460  }
461  }
462  if (valueS < valueSmall) {
463  iSmall = i;
464  valueSmall = valueS;
465  if (valueSmall == 0.0) {
466  return iSmall;
467  }
468  }
469  }
470  return iSmall;
471 }
472 //====================================================================================================================
473 size_t BandMatrix::checkColumns(doublereal& valueSmall) const
474 {
475  valueSmall = 1.0E300;
476  size_t jSmall = npos;
477  double vv;
478  for (int j = 0; j < (int) m_n; j++) {
479  double valueS = 0.0;
480  for (int i = j - (int) m_ku; i <= j + (int) m_kl; i++) {
481  if (i >= 0 && i < (int) m_n) {
482  vv = fabs(value(i,j));
483  if (vv > valueS) {
484  valueS = vv;
485  }
486  }
487  }
488  if (valueS < valueSmall) {
489  jSmall = j;
490  valueSmall = valueS;
491  if (valueSmall == 0.0) {
492  return jSmall;
493  }
494  }
495  }
496  return jSmall;
497 }
498 //====================================================================================================================
500 {
501  BandMatrix* dd = new BandMatrix(*this);
502  return static_cast<GeneralMatrix*>(dd);
503 }
504 //====================================================================================================================
506 {
507  return m_factored;
508 }
509 //====================================================================================================================
510 // Return a pointer to the top of column j, columns are assumed to be contiguous in memory
511 /*
512  * @param j Value of the column
513  *
514  * @return Returns a pointer to the top of the column
515  */
516 doublereal* BandMatrix::ptrColumn(size_t j)
517 {
518  return m_colPtrs[j];
519 }
520 //====================================================================================================================
521 // Return a vector of const pointers to the columns
522 /*
523  * Note the value of the pointers are protected by their being const.
524  * However, the value of the matrix is open to being changed.
525  *
526  * @return returns a vector of pointers to the top of the columns
527  * of the matrices.
528  */
529 doublereal* const* BandMatrix::colPts()
530 {
531  return &(m_colPtrs[0]);
532 }
533 //====================================================================================================================
534 // Copy the data from one array into another without doing any checking
535 /*
536  * This differs from the assignment operator as no resizing is done and memcpy() is used.
537  * @param y Array to be copied
538  */
540 {
541  m_factored = false;
542  size_t n = sizeof(doublereal) * m_n * (2 *m_kl + m_ku + 1);
543  GeneralMatrix* yyPtr = const_cast<GeneralMatrix*>(&y);
544  (void) memcpy(DATA_PTR(data), yyPtr->ptrColumn(0), n);
545 }
546 //====================================================================================================================
547 /*
548  * clear the factored flag
549  */
551 {
552  m_factored = 0;
553 }
554 //====================================================================================================================
555 //====================================================================================================================
556 }
557