svMultiPhysics
Loading...
Searching...
No Matches
mat_fun.h
1// SPDX-FileCopyrightText: Copyright (c) Stanford University, The Regents of the University of California, and others.
2// SPDX-License-Identifier: BSD-3-Clause
3
4#ifndef MAT_FUN_H
5#define MAT_FUN_H
6#include "eigen3/Eigen/Core"
7#include "eigen3/Eigen/Dense"
8#include "eigen3/unsupported/Eigen/CXX11/Tensor"
9#include <stdexcept>
10
11#include "Array.h"
12#include "Tensor4.h"
13#include "Vector.h"
15
16/// @brief The classes defined here duplicate the data structures in the
17/// Fortran MATFUN module defined in MATFUN.f.
18///
19/// This module defines data structures for generally performed matrix and tensor operations.
20///
21/// \todo [TODO:DaveP] this should just be a namespace?
22//
23namespace mat_fun {
24 // Define templated type aliases for Eigen matrices and tensors for convenience
25 template<size_t nsd>
26 using Matrix = Eigen::Matrix<double, nsd, nsd>;
27
28 template<size_t nsd>
29 using Tensor = Eigen::TensorFixedSize<double, Eigen::Sizes<nsd, nsd, nsd, nsd>>;
30
31 // Function to convert Array<double> to Eigen::Matrix
32 template <typename MatrixType>
33 MatrixType convert_to_eigen_matrix(const Array<double>& src) {
34 MatrixType mat;
35 for (int i = 0; i < mat.rows(); ++i)
36 for (int j = 0; j < mat.cols(); ++j)
37 mat(i, j) = src(i, j);
38 return mat;
39 }
40
41 // Function to convert Eigen::Matrix to Array<double>
42 template <typename MatrixType>
43 void convert_to_array(const MatrixType& mat, Array<double>& dest) {
44 for (int i = 0; i < mat.rows(); ++i)
45 for (int j = 0; j < mat.cols(); ++j)
46 dest(i, j) = mat(i, j);
47 }
48
49 // Function to convert a higher-dimensional array like Dm
50 template <typename MatrixType>
51 void copy_Dm(const MatrixType& mat, Array<double>& dest) {
52 if ((mat.rows() != dest.nrows()) || (mat.cols() != dest.ncols())) {
53 auto mat_dims = (std::stringstream() << "(" << mat.rows() << "x" << mat.cols() << ")").str();
54 auto dest_dims = (std::stringstream() << "(" << dest.nrows() << "x" << dest.ncols() << ")").str();
55 svmp::raise<svmp::FE::InvalidArgumentException>( SVMP_HERE, "The 'mat" + mat_dims + "' and 'dest" + dest_dims +
56 "' arrays have incompatible sizes.");
57 }
58
59 for (int i = 0; i < mat.rows(); ++i) {
60 for (int j = 0; j < mat.cols(); ++j) {
61 dest(i, j) = mat(i, j);
62 }
63 }
64 }
65
66 template <int nsd>
67 Eigen::Matrix<double, nsd, 1> cross_product(const Eigen::Matrix<double, nsd, 1>& u, const Eigen::Matrix<double, nsd, 1>& v) {
68 if constexpr (nsd == 2) {
69 return Eigen::Matrix<double, 2, 1>(v(1), - v(0));
70 }
71 else if constexpr (nsd == 3) {
72 return u.cross(v);
73 }
74 else {
75 throw std::runtime_error("[cross_product] Invalid number of spatial dimensions '" + std::to_string(nsd) + "'. Valid dimensions are 2 or 3.");
76 }
77 }
78
79 double mat_ddot(const Array<double>& A, const Array<double>& B, const int nd);
80
81 template <int nsd>
82 double double_dot_product(const Matrix<nsd>& A, const Matrix<nsd>& B) {
83 return A.cwiseProduct(B).sum();
84 }
85
86 double mat_det(const Array<double>& A, const int nd);
87 Array<double> mat_dev(const Array<double>& A, const int nd);
88
89 Array<double> mat_dyad_prod(const Vector<double>& u, const Vector<double>& v, const int nd);
90
91 Array<double> mat_id(const int nsd);
92 Array<double> mat_inv(const Array<double>& A, const int nd, bool debug = false);
93 Array<double> mat_inv_ge(const Array<double>& A, const int nd, bool debug = false);
94 Array<double> mat_inv_lp(const Array<double>& A, const int nd);
95
96 Vector<double> mat_mul(const Array<double>& A, const Vector<double>& v);
97 Array<double> mat_mul(const Array<double>& A, const Array<double>& B);
98 void mat_mul(const Array<double>& A, const Array<double>& B, Array<double>& result);
99 void mat_mul6x3(const Array<double>& A, const Array<double>& B, Array<double>& C);
100
101 Array<double> mat_symm(const Array<double>& A, const int nd);
102 Array<double> mat_symm_prod(const Vector<double>& u, const Vector<double>& v, const int nd);
103
104 double mat_trace(const Array<double>& A, const int nd);
105
106 Tensor4<double> ten_asym_prod12(const Array<double>& A, const Array<double>& B, const int nd);
107 Tensor4<double> ten_ddot(const Tensor4<double>& A, const Tensor4<double>& B, const int nd);
108 Tensor4<double> ten_ddot_2412(const Tensor4<double>& A, const Tensor4<double>& B, const int nd);
109 Tensor4<double> ten_ddot_3424(const Tensor4<double>& A, const Tensor4<double>& B, const int nd);
110
111 /**
112 * @brief Contracts two 4th order tensors A and B over two dimensions,
113 *
114 */
115 template <int nsd>
116 Tensor<nsd>
117 double_dot_product(const Tensor<nsd>& A, const std::array<int, 2>& dimsA,
118 const Tensor<nsd>& B, const std::array<int, 2>& dimsB) {
119
120 // Define the contraction dimensions
121 Eigen::array<Eigen::IndexPair<int>, 2> contractionDims = {
122 Eigen::IndexPair<int>(dimsA[0], dimsB[0]), // Contract A's dimsA[0] with B's dimsB[0]
123 Eigen::IndexPair<int>(dimsA[1], dimsB[1]) // Contract A's dimsA[1] with B's dimsB[1]
124 };
125
126 // Return the double dot product
127 return A.contract(B, contractionDims);
128
129 // For some reason, in this case the Eigen::Tensor contract function is
130 // faster than a for loop implementation.
131 }
132
133 Tensor4<double> ten_dyad_prod(const Array<double>& A, const Array<double>& B, const int nd);
134
135 /**
136 * @brief Compute the dyadic product of two 2nd order tensors A and B, C_ijkl = A_ij * B_kl
137 *
138 * @tparam nsd, the number of spatial dimensions
139 * @param A, the first 2nd order tensor
140 * @param B, the second 2nd order tensor
141 * @return Tensor<nsd>
142 */
143 template <int nsd>
144 Tensor<nsd>
145 dyadic_product(const Matrix<nsd>& A, const Matrix<nsd>& B) {
146 // Initialize the result tensor
147 Tensor<nsd> C;
148
149 // Compute the dyadic product: C_ijkl = A_ij * B_kl
150 for (int i = 0; i < nsd; ++i) {
151 for (int j = 0; j < nsd; ++j) {
152 for (int k = 0; k < nsd; ++k) {
153 for (int l = 0; l < nsd; ++l) {
154 C(i,j,k,l) = A(i,j) * B(k,l);
155 }
156 }
157 }
158 }
159 // For some reason, in this case the Eigen::Tensor contract function is
160 // slower than the for loop implementation
161
162 return C;
163 }
164
165 Tensor4<double> ten_ids(const int nd);
166
167 /**
168 * @brief Create a 4th order identity tensor:
169 * I_ijkl = 0.5 * (δ_ik * δ_jl + δ_il * δ_jk)
170 *
171 * @tparam nsd, the number of spatial dimensions
172 * @return Tensor<nsd>
173 */
174 template <int nsd>
175 Tensor<nsd>
177 // Initialize as zero
178 Tensor<nsd> I;
179 I.setZero();
180
181 // Set only non-zero entries
182 for (int i = 0; i < nsd; ++i) {
183 for (int j = 0; j < nsd; ++j) {
184 I(i,j,i,j) += 0.5;
185 I(i,j,j,i) += 0.5;
186 }
187 }
188
189 return I;
190 }
191
192 Array<double> ten_mddot(const Tensor4<double>& A, const Array<double>& B, const int nd);
193
194 Tensor4<double> ten_symm_prod(const Array<double>& A, const Array<double>& B, const int nd);
195
196 /// @brief Create a 4th order tensor from symmetric outer product of two matrices: C_ijkl = 0.5 * (A_ik * B_jl + A_il * B_jk)
197 ///
198 /// Reproduces 'FUNCTION TEN_SYMMPROD(A, B, nd) RESULT(C)'.
199 //
200 template <int nsd>
201 Tensor<nsd>
202 symmetric_dyadic_product(const Matrix<nsd>& A, const Matrix<nsd>& B) {
203
204 // Initialize the result tensor
205 Tensor<nsd> C;
206
207 // Compute the symmetric product: C_ijkl = 0.5 * (A_ik * B_jl + A_il * B_jk)
208 for (int i = 0; i < nsd; ++i) {
209 for (int j = 0; j < nsd; ++j) {
210 for (int k = 0; k < nsd; ++k) {
211 for (int l = 0; l < nsd; ++l) {
212 C(i,j,k,l) = 0.5 * (A(i,k) * B(j,l) + A(i,l) * B(j,k));
213 }
214 }
215 }
216 }
217 // For some reason, in this case the for loop implementation is faster
218 // than the Eigen::Tensor contract method
219
220 // Return the symmetric product
221 return C;
222 }
223
224 Tensor4<double> ten_transpose(const Tensor4<double>& A, const int nd);
225
226 /**
227 * @brief Performs a tensor transpose operation on a 4th order tensor A, B_ijkl = A_klij
228 *
229 * @tparam nsd, the number of spatial dimensions
230 * @param A, the input 4th order tensor
231 * @return Tensor<nsd>
232 */
233 template <int nsd>
234 Tensor<nsd>
235 transpose(const Tensor<nsd>& A) {
236
237 // Initialize the result tensor
238 Tensor<nsd> B;
239
240 // Permute the tensor indices to perform the transpose operation
241 for (int i = 0; i < nsd; ++i) {
242 for (int j = 0; j < nsd; ++j) {
243 for (int k = 0; k < nsd; ++k) {
244 for (int l = 0; l < nsd; ++l) {
245 B(i,j,k,l) = A(k,l,i,j);
246 }
247 }
248 }
249 }
250
251 return B;
252 }
253
254 Array<double> transpose(const Array<double>& A);
255
256 void ten_init(const int nd);
257
258};
259
260#endif
261
Exception hierarchy for error handling in the FE library.
The Tensor4 template class implements a simple interface to 4th order tensors.
Definition Tensor4.h:20
The Vector template class is used for storing int and double data.
Definition Vector.h:24
The classes defined here duplicate the data structures in the Fortran MATFUN module defined in MATFUN...
Definition mat_fun.cpp:14
Tensor< nsd > symmetric_dyadic_product(const Matrix< nsd > &A, const Matrix< nsd > &B)
Create a 4th order tensor from symmetric outer product of two matrices: C_ijkl = 0....
Definition mat_fun.h:202
void ten_init(const int nd)
Initialize tensor index pointer.
Definition mat_fun.cpp:760
Tensor4< double > ten_symm_prod(const Array< double > &A, const Array< double > &B, const int nd)
Create a 4th order tensor from symmetric outer product of two matrices.
Definition mat_fun.cpp:852
Array< double > ten_mddot(const Tensor4< double > &A, const Array< double > &B, const int nd)
Double dot product of a 4th order tensor and a 2nd order tensor.
Definition mat_fun.cpp:822
Array< double > mat_symm(const Array< double > &A, const int nd)
Symmetric part of a matrix, S = (A + A.T)/2.
Definition mat_fun.cpp:555
Tensor4< double > ten_ids(const int nd)
Create a 4th order order symmetric identity tensor.
Definition mat_fun.cpp:803
Array< double > transpose(const Array< double > &A)
Reproduces Fortran TRANSPOSE.
Definition mat_fun.cpp:888
Vector< double > mat_mul(const Array< double > &A, const Vector< double > &v)
Multiply a matrix by a vector.
Definition mat_fun.cpp:466
double mat_trace(const Array< double > &A, const int nd)
Trace of second order matrix of rank nd.
Definition mat_fun.cpp:587
Tensor4< double > ten_ddot(const Tensor4< double > &A, const Tensor4< double > &B, const int nd)
Double dot product of 2 4th order tensors T_ijkl = A_ijmn * B_klmn.
Definition mat_fun.cpp:626
Tensor4< double > ten_dyad_prod(const Array< double > &A, const Array< double > &B, const int nd)
Create a 4th order tensor from outer product of two matrices.
Definition mat_fun.cpp:784
Array< double > mat_inv_lp(const Array< double > &A, const int nd)
This function computes inverse of a square matrix using Lapack functions (DGETRF + DGETRI)
Definition mat_fun.cpp:396
Array< double > mat_inv(const Array< double > &A, const int nd, bool debug)
This function computes inverse of a square matrix.
Definition mat_fun.cpp:109
Array< double > mat_inv_ge(const Array< double > &Ain, const int n, bool debug)
This function computes inverse of a square matrix using Gauss Elimination method.
Definition mat_fun.cpp:166
Array< double > mat_symm_prod(const Vector< double > &u, const Vector< double > &v, const int nd)
Create a matrix from symmetric product of two vectors.
Definition mat_fun.cpp:572
Array< double > mat_dyad_prod(const Vector< double > &u, const Vector< double > &v, const int nd)
Create a matrix from outer product of two vectors.
Definition mat_fun.cpp:81
Tensor< nsd > fourth_order_identity()
Create a 4th order identity tensor: I_ijkl = 0.5 * (δ_ik * δ_jl + δ_il * δ_jk)
Definition mat_fun.h:176
double mat_ddot(const Array< double > &A, const Array< double > &B, const int nd)
Double dot product of 2 square matrices.
Definition mat_fun.cpp:20
Tensor4< double > ten_ddot_2412(const Tensor4< double > &A, const Tensor4< double > &B, const int nd)
T_ijkl = A_imjn * B_mnkl.
Definition mat_fun.cpp:671
Tensor4< double > ten_asym_prod12(const Array< double > &A, const Array< double > &B, const int nd)
Create a 4th order tensor from antisymmetric outer product of two matrices.
Definition mat_fun.cpp:604
Tensor< nsd > dyadic_product(const Matrix< nsd > &A, const Matrix< nsd > &B)
Compute the dyadic product of two 2nd order tensors A and B, C_ijkl = A_ij * B_kl.
Definition mat_fun.h:145