Cantera  4.0.0a1
Loading...
Searching...
No Matches
DenseMatrix.cpp
Go to the documentation of this file.
1/**
2 * @file DenseMatrix.cpp
3 */
4
5// This file is part of Cantera. See License.txt in the top-level directory or
6// at https://cantera.org/license.txt for license and copyright information.
7
10#include "cantera/base/global.h"
11#if CT_USE_LAPACK
13#else
14 #include "cantera/numerics/eigen_dense.h"
15#endif
16
17namespace Cantera
18{
19
20DenseMatrix::DenseMatrix(size_t n, size_t m, double v) :
21 Array2D(n, m, v)
22{
23 m_ipiv.resize(std::max(n, m));
24}
25
27 Array2D(y)
28{
29 m_ipiv = y.ipiv();
30}
31
32DenseMatrix& DenseMatrix::operator=(const DenseMatrix& y)
33{
34 if (&y == this) {
35 return *this;
36 }
37 Array2D::operator=(y);
38 m_ipiv = y.ipiv();
39 return *this;
40}
41
42void DenseMatrix::resize(size_t n, size_t m, double v)
43{
44 Array2D::resize(n,m,v);
45 m_ipiv.resize(std::max(n,m));
46}
47
48void DenseMatrix::mult(span<const double> b, span<double> prod) const
49{
50 checkArraySize("DenseMatrix::mult", b.size(), nColumns());
51 checkArraySize("DenseMatrix::mult", prod.size(), nRows());
52#if CT_USE_LAPACK
53 ct_dgemv(ctlapack::ColMajor, ctlapack::NoTranspose,
54 static_cast<int>(nRows()),
55 static_cast<int>(nColumns()), 1.0, col(0).data(),
56 static_cast<int>(nRows()), b.data(), 1, 0.0, prod.data(), 1);
57#else
58 MappedMatrix mat(const_cast<double*>(m_data.data()), nRows(), nColumns());
59 MappedVector bm(const_cast<double*>(b.data()), nColumns());
60 MappedVector pm(prod.data(), nRows());
61 pm = mat * bm;
62#endif
63}
64
65void DenseMatrix::mult(const DenseMatrix& B, DenseMatrix& prod) const
66{
67 if (nColumns() != B.nRows()) {
68 throw CanteraError("DenseMatrix::mult",
69 "Inner matrix dimensions do not agree: {} != {}", nColumns(), B.nRows());
70 }
71 if (nRows() != prod.nRows() || B.nColumns() != prod.nColumns()) {
72 throw CanteraError("DenseMatrix::mult",
73 "Output matrix has wrong dimensions: {}x{} != {}x{}",
74 prod.nRows(), prod.nColumns(), nRows(), B.nColumns());
75 }
76 for (size_t col=0; col < B.nColumns(); ++col) {
77 // Loop over ncols multiplying A*column of B and storing in
78 // corresponding prod column
79 mult(B.col(col), prod.col(col));
80 }
81}
82
83void DenseMatrix::leftMult(span<const double> b, span<double> prod) const
84{
85 checkArraySize("DenseMatrix::leftMult", b.size(), nRows());
86 checkArraySize("DenseMatrix::leftMult", prod.size(), nColumns());
87 for (size_t n = 0; n < nColumns(); n++) {
88 double sum = 0.0;
89 for (size_t i = 0; i < nRows(); i++) {
90 sum += value(i,n)*b[i];
91 }
92 prod[n] = sum;
93 }
94}
95
96vector<int>& DenseMatrix::ipiv()
97{
98 return m_ipiv;
99}
100
101void solve(DenseMatrix& A, span<double> b, size_t nrhs, size_t ldb)
102{
103 if (A.nColumns() != A.nRows()) {
104 throw CanteraError("solve(DenseMatrix& A, span<double> b)",
105 "Can only solve a square matrix");
106 }
107
108 int info = 0;
109 if (ldb == 0) {
110 ldb = A.nColumns();
111 }
112 checkArraySize("solve(DenseMatrix& A, span<double> b)", b.size(), ldb * nrhs);
113 #if CT_USE_LAPACK
114 ct_dgetrf(A.nRows(), A.nColumns(), A.data().data(),
115 A.nRows(), &A.ipiv()[0], info);
116 if (info > 0) {
117 throw CanteraError("solve(DenseMatrix& A, span<double> b)",
118 "DGETRF returned INFO = {}. U(i,i) is exactly zero. The factorization has"
119 " been completed, but the factor U is exactly singular, and division by zero will occur if "
120 "it is used to solve a system of equations.", info);
121 } else if (info < 0) {
122 throw CanteraError("solve(DenseMatrix& A, span<double> b)",
123 "DGETRF returned INFO = {}. The argument i has an illegal value", info);
124 }
125
126 ct_dgetrs(ctlapack::NoTranspose, A.nRows(), nrhs, A.data().data(),
127 A.nRows(), &A.ipiv()[0], b.data(), ldb, info);
128 if (info != 0) {
129 throw CanteraError("solve(DenseMatrix& A, span<double> b)",
130 "DGETRS returned INFO = {}", info);
131 }
132 #else
133 MappedMatrix Am(&A(0,0), A.nRows(), A.nColumns());
134 #ifdef NDEBUG
135 auto lu = Am.partialPivLu();
136 #else
137 auto lu = Am.fullPivLu();
138 if (lu.nonzeroPivots() < static_cast<long int>(A.nColumns())) {
139 throw CanteraError("solve(DenseMatrix& A, span<double> b)",
140 "Matrix appears to be rank-deficient: non-zero pivots = {}; columns = {}",
141 lu.nonzeroPivots(), A.nColumns());
142 }
143 #endif
144 for (size_t i = 0; i < nrhs; i++) {
145 MappedVector bm(b.data() + ldb*i, A.nColumns());
146 bm = lu.solve(bm);
147 }
148 #endif
149}
150
152{
153 solve(A, b.data(), b.nColumns(), b.nRows());
154}
155
156void multiply(const DenseMatrix& A, span<const double> b, span<double> prod)
157{
158 A.mult(b, prod);
159}
160
161void increment(const DenseMatrix& A, span<const double> b, span<double> prod)
162{
163 checkArraySize("increment", b.size(), A.nColumns());
164 checkArraySize("increment", prod.size(), A.nRows());
165 #if CT_USE_LAPACK
166 ct_dgemv(ctlapack::ColMajor, ctlapack::NoTranspose,
167 static_cast<int>(A.nRows()), static_cast<int>(A.nColumns()), 1.0,
168 A.data().data(), static_cast<int>(A.nRows()), b.data(), 1, 1.0, prod.data(), 1);
169 #else
170 MappedMatrix Am(&const_cast<DenseMatrix&>(A)(0,0), A.nRows(), A.nColumns());
171 MappedVector bm(const_cast<double*>(b.data()), A.nColumns());
172 MappedVector pm(prod.data(), A.nRows());
173 pm += Am * bm;
174 #endif
175}
176
177void invert(DenseMatrix& A, size_t nn)
178{
179 int info=0;
180 #if CT_USE_LAPACK
181 integer n = static_cast<int>(nn != npos ? nn : A.nRows());
182 ct_dgetrf(n, n, A.data().data(), static_cast<int>(A.nRows()),
183 &A.ipiv()[0], info);
184 if (info != 0) {
185 throw CanteraError("invert(DenseMatrix& A, size_t nn)", "DGETRF returned INFO = {}", info);
186 }
187
188 vector<double> work(n);
189 integer lwork = static_cast<int>(work.size());
190 ct_dgetri(n, A.data().data(), static_cast<int>(A.nRows()),
191 &A.ipiv()[0], &work[0], lwork, info);
192 if (info != 0) {
193 throw CanteraError("invert(DenseMatrix& A, size_t nn)", "DGETRI returned INFO={}", info);
194 }
195 #else
196 MappedMatrix Am(&A(0,0), A.nRows(), A.nColumns());
197 if (nn == npos) {
198 Am = Am.inverse();
199 } else {
200 Am.topLeftCorner(nn, nn) = Am.topLeftCorner(nn, nn).inverse();
201 }
202 #endif
203}
204
205}
Headers for the DenseMatrix object, which deals with dense rectangular matrices and description of th...
A class for 2D arrays stored in column-major (Fortran-compatible) form.
Definition Array.h:32
vector< double > m_data
Data stored in a single array.
Definition Array.h:200
size_t nRows() const
Number of rows.
Definition Array.h:167
size_t nColumns() const
Number of columns.
Definition Array.h:172
span< double > col(size_t j)
Return a writable span over column j.
Definition Array.h:189
vector< double > & data()
Return a reference to the data vector.
Definition Array.h:177
double & value(size_t i, size_t j)
Returns a changeable reference to position in the matrix.
Definition Array.h:151
virtual void resize(size_t n, size_t m, double v=0.0)
Resize the array, and fill the new entries with 'v'.
Definition Array.cpp:52
Base class for exceptions thrown by Cantera classes.
A class for full (non-sparse) matrices with Fortran-compatible data storage, which adds matrix operat...
Definition DenseMatrix.h:42
void resize(size_t n, size_t m, double v=0.0) override
Resize the matrix.
vector< int > & ipiv()
Return a changeable value of the pivot vector.
DenseMatrix()=default
Default Constructor.
virtual void leftMult(span< const double > b, span< double > prod) const
Left-multiply the matrix by transpose(b), and write the result to prod.
vector< int > m_ipiv
Vector of pivots. Length is equal to the max of m and n.
This file contains definitions for utility functions and text for modules, inputfiles and logging,...
Namespace for the Cantera kernel.
Definition AnyMap.cpp:595
const size_t npos
index returned by functions to indicate "no position"
Definition ct_defs.h:183
void increment(const DenseMatrix &A, span< const double > b, span< double > prod)
Multiply A*b and add it to the result in prod. Uses BLAS routine DGEMV.
void solve(DenseMatrix &A, span< double > b, size_t nrhs, size_t ldb)
Solve Ax = b. Array b is overwritten on exit with x.
void multiply(const DenseMatrix &A, span< const double > b, span< double > prod)
Multiply A*b and return the result in prod. Uses BLAS routine DGEMV.
void invert(DenseMatrix &A, size_t nn)
invert A. A is overwritten with A^-1.
void checkArraySize(const char *procedure, size_t available, size_t required)
Wrapper for throwing ArraySizeError.
Contains declarations for string manipulation functions within Cantera.