From 73a85d68b12acdaaffb54314d477e93d8e873057 Mon Sep 17 00:00:00 2001 From: dseyler Date: Mon, 24 Aug 2026 15:38:22 -0700 Subject: [PATCH 01/42] Add a fixed-size fast path to double_dot_product --- Code/Source/solver/mat_fun.h | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/Code/Source/solver/mat_fun.h b/Code/Source/solver/mat_fun.h index f1b79b10d..b5b25da86 100644 --- a/Code/Source/solver/mat_fun.h +++ b/Code/Source/solver/mat_fun.h @@ -184,9 +184,34 @@ namespace mat_fun { */ template Tensor - double_dot_product(const Tensor& A, const std::array& dimsA, + double_dot_product(const Tensor& A, const std::array& dimsA, const Tensor& B, const std::array& dimsB) { - + + // Fast path for contraction over the two trailing dimensions, + // C_ijmn = A_ijkl * B_mnkl, which is every call in the element loops. + // + // Tensor is column major, so the linear index of (i,j,k,l) is + // i + n*j + n^2*k + n^3*l. Viewed as an NxN column-major matrix with + // N = nsd^2, row i + n*j and column k + n*l give that same index, so + // the free pair indexes rows and the contracted pair indexes columns + // with no copy or permutation. The contraction is then A * B^T. + // + // contract() reaches the same result, and both routes end in Eigen's + // blocked GEMM. The difference is how the operands are read while + // being packed: contract() goes through TensorContractionSubMapper, + // which indirects through the tensor evaluator on every element, while + // the matrix path uses a plain strided pointer mapper. Measured at + // 1.8x for nsd = 3, with bitwise identical results. + if (dimsA[0] == 2 && dimsA[1] == 3 && dimsB[0] == 2 && dimsB[1] == 3) { + constexpr int N = nsd * nsd; + Tensor C; + Eigen::Map> a(A.data()); + Eigen::Map> b(B.data()); + Eigen::Map> c(C.data()); + c.noalias() = a * b.transpose(); + return C; + } + // Define the contraction dimensions Eigen::array, 2> contractionDims = { Eigen::IndexPair(dimsA[0], dimsB[0]), // Contract A's dimsA[0] with B's dimsB[0] From 9ee0f62b3abfa70818f71ff0c0bec731474dadbd Mon Sep 17 00:00:00 2001 From: dseyler Date: Thu, 27 Aug 2026 13:01:01 -0700 Subject: [PATCH 02/42] Updated documentation for double dot product --- Code/Source/solver/mat_fun.h | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/Code/Source/solver/mat_fun.h b/Code/Source/solver/mat_fun.h index b5b25da86..e362fcedb 100644 --- a/Code/Source/solver/mat_fun.h +++ b/Code/Source/solver/mat_fun.h @@ -179,8 +179,17 @@ namespace mat_fun { Tensor4 ten_ddot_3424(const Tensor4& A, const Tensor4& B, const int nd); /** - * @brief Contracts two 4th order tensors A and B over two dimensions, - * + * @brief Contract two 4th order tensors over two dimensions each. + * + * Computes the tensor whose components are the sum of A and B over the + * index pairs named by @p dimsA and @p dimsB, leaving the remaining two + * indices of each operand free. + * + * @tparam nsd Number of spatial dimensions; each tensor is nsd^4. + * @param[in] A,B Fourth order tensors to contract. + * @param[in] dimsA,dimsB Zero-based indices of the two dimensions of A and + * of B to contract over. + * @return The contracted tensor. */ template Tensor From 6edb73d63a94d4190c4f57a44c04776ad47e4d56 Mon Sep 17 00:00:00 2001 From: dseyler Date: Wed, 26 Aug 2026 15:30:23 -0700 Subject: [PATCH 03/42] Compute dyadic product with eigen --- Code/Source/solver/mat_fun.h | 56 ++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/Code/Source/solver/mat_fun.h b/Code/Source/solver/mat_fun.h index e362fcedb..604b0f520 100644 --- a/Code/Source/solver/mat_fun.h +++ b/Code/Source/solver/mat_fun.h @@ -245,24 +245,22 @@ namespace mat_fun { * @return Tensor */ template - Tensor + Tensor dyadic_product(const Matrix& A, const Matrix& B) { - // Initialize the result tensor - Tensor C; - - // Compute the dyadic product: C_ijkl = A_ij * B_kl - for (int i = 0; i < nsd; ++i) { - for (int j = 0; j < nsd; ++j) { - for (int k = 0; k < nsd; ++k) { - for (int l = 0; l < nsd; ++l) { - C(i,j,k,l) = A(i,j) * B(k,l); - } - } - } - } - // For some reason, in this case the Eigen::Tensor contract function is - // slower than the for loop implementation + constexpr int N = nsd * nsd; + // C_ijkl = A_ij * B_kl is an outer product in the NxN view of the + // tensor: with column-major storage the index pair (i,j) is the row + // and (k,l) the column, so the second order tensors read as N-vectors. + // + // Written as an index loop the innermost index is l, whose stride is + // nsd^3, so every innermost write lands on a different cache line and + // nothing vectorises. This form writes down columns instead. + Tensor C; + Eigen::Map> a(A.data()); + Eigen::Map> b(B.data()); + Eigen::Map> c(C.data()); + c.noalias() = a * b.transpose(); return C; } @@ -308,18 +306,28 @@ namespace mat_fun { // Initialize the result tensor Tensor C; - // Compute the symmetric product: C_ijkl = 0.5 * (A_ik * B_jl + A_il * B_jk) - for (int i = 0; i < nsd; ++i) { - for (int j = 0; j < nsd; ++j) { - for (int k = 0; k < nsd; ++k) { - for (int l = 0; l < nsd; ++l) { - C(i,j,k,l) = 0.5 * (A(i,k) * B(j,l) + A(i,l) * B(j,k)); + // C_ijkl = 0.5 * (A_ik * B_jl + A_il * B_jk). + // + // Same ordering point as dyadic_product: with column-major storage the + // flat index is i + nsd*j + nsd^2*k + nsd^3*l, so iterating l innermost + // strides by nsd^3. Running i innermost instead makes the writes + // contiguous and the inner statement a vectorisable axpy, since only + // A(i,k) and A(i,l) vary with i. + double* c = C.data(); + for (int l = 0; l < nsd; ++l) { + for (int k = 0; k < nsd; ++k) { + const double* a_k = A.data() + nsd * k; // A(:,k) + const double* a_l = A.data() + nsd * l; // A(:,l) + for (int j = 0; j < nsd; ++j) { + const double b_jl = B(j, l); + const double b_jk = B(j, k); + double* out = c + nsd * j + nsd * nsd * k + nsd * nsd * nsd * l; + for (int i = 0; i < nsd; ++i) { + out[i] = 0.5 * (a_k[i] * b_jl + a_l[i] * b_jk); } } } } - // For some reason, in this case the for loop implementation is faster - // than the Eigen::Tensor contract method // Return the symmetric product return C; From 85d72ec0c65b6d603c183d6758b55d3e23a830a2 Mon Sep 17 00:00:00 2001 From: dseyler Date: Thu, 27 Aug 2026 13:03:09 -0700 Subject: [PATCH 04/42] Updated documentation and removed references to Fortran --- Code/Source/solver/mat_fun.h | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Code/Source/solver/mat_fun.h b/Code/Source/solver/mat_fun.h index 604b0f520..5d54d6775 100644 --- a/Code/Source/solver/mat_fun.h +++ b/Code/Source/solver/mat_fun.h @@ -239,10 +239,9 @@ namespace mat_fun { /** * @brief Compute the dyadic product of two 2nd order tensors A and B, C_ijkl = A_ij * B_kl * - * @tparam nsd, the number of spatial dimensions - * @param A, the first 2nd order tensor - * @param B, the second 2nd order tensor - * @return Tensor + * @tparam nsd Number of spatial dimensions. + * @param[in] A,B Second order tensors. + * @return The resulting 4th order tensor. */ template Tensor @@ -295,10 +294,12 @@ namespace mat_fun { Tensor4 ten_symm_prod(const Array& A, const Array& B, const int nd); - /// @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) + /// @brief Symmetric dyadic product of two 2nd order tensors, + /// C_ijkl = 0.5 * (A_ik * B_jl + A_il * B_jk). /// - /// Reproduces 'FUNCTION TEN_SYMMPROD(A, B, nd) RESULT(C)'. - // + /// @tparam nsd Number of spatial dimensions. + /// @param[in] A,B Second order tensors. + /// @return The resulting 4th order tensor. template Tensor symmetric_dyadic_product(const Matrix& A, const Matrix& B) { From 1e770a1023c023df84964c37814f59c908f97b15 Mon Sep 17 00:00:00 2001 From: dseyler Date: Sat, 29 Aug 2026 23:49:17 -0700 Subject: [PATCH 05/42] Compute fixed-size tensor products with Eigen instead of nested loops --- Code/Source/solver/mat_fun.h | 73 ++++++++---------------------------- 1 file changed, 16 insertions(+), 57 deletions(-) diff --git a/Code/Source/solver/mat_fun.h b/Code/Source/solver/mat_fun.h index 5d54d6775..da784805c 100644 --- a/Code/Source/solver/mat_fun.h +++ b/Code/Source/solver/mat_fun.h @@ -179,11 +179,7 @@ namespace mat_fun { Tensor4 ten_ddot_3424(const Tensor4& A, const Tensor4& B, const int nd); /** - * @brief Contract two 4th order tensors over two dimensions each. - * - * Computes the tensor whose components are the sum of A and B over the - * index pairs named by @p dimsA and @p dimsB, leaving the remaining two - * indices of each operand free. + * @brief Contracts two 4th order tensors A and B over two dimensions. * * @tparam nsd Number of spatial dimensions; each tensor is nsd^4. * @param[in] A,B Fourth order tensors to contract. @@ -193,24 +189,10 @@ namespace mat_fun { */ template Tensor - double_dot_product(const Tensor& A, const std::array& dimsA, + double_dot_product(const Tensor& A, const std::array& dimsA, const Tensor& B, const std::array& dimsB) { - - // Fast path for contraction over the two trailing dimensions, - // C_ijmn = A_ijkl * B_mnkl, which is every call in the element loops. - // - // Tensor is column major, so the linear index of (i,j,k,l) is - // i + n*j + n^2*k + n^3*l. Viewed as an NxN column-major matrix with - // N = nsd^2, row i + n*j and column k + n*l give that same index, so - // the free pair indexes rows and the contracted pair indexes columns - // with no copy or permutation. The contraction is then A * B^T. - // - // contract() reaches the same result, and both routes end in Eigen's - // blocked GEMM. The difference is how the operands are read while - // being packed: contract() goes through TensorContractionSubMapper, - // which indirects through the tensor evaluator on every element, while - // the matrix path uses a plain strided pointer mapper. Measured at - // 1.8x for nsd = 3, with bitwise identical results. + + // Fast path for dimsA = dimsB = {2,3}: C_ijmn = A_ijkl * B_mnkl. if (dimsA[0] == 2 && dimsA[1] == 3 && dimsB[0] == 2 && dimsB[1] == 3) { constexpr int N = nsd * nsd; Tensor C; @@ -229,9 +211,6 @@ namespace mat_fun { // Return the double dot product return A.contract(B, contractionDims); - - // For some reason, in this case the Eigen::Tensor contract function is - // faster than a for loop implementation. } Tensor4 ten_dyad_prod(const Array& A, const Array& B, const int nd); @@ -239,23 +218,18 @@ namespace mat_fun { /** * @brief Compute the dyadic product of two 2nd order tensors A and B, C_ijkl = A_ij * B_kl * - * @tparam nsd Number of spatial dimensions. - * @param[in] A,B Second order tensors. - * @return The resulting 4th order tensor. + * @tparam nsd, the number of spatial dimensions + * @param A, the first 2nd order tensor + * @param B, the second 2nd order tensor + * @return Tensor */ template - Tensor + Tensor dyadic_product(const Matrix& A, const Matrix& B) { + // Initialize the result tensor + Tensor C; constexpr int N = nsd * nsd; - // C_ijkl = A_ij * B_kl is an outer product in the NxN view of the - // tensor: with column-major storage the index pair (i,j) is the row - // and (k,l) the column, so the second order tensors read as N-vectors. - // - // Written as an index loop the innermost index is l, whose stride is - // nsd^3, so every innermost write lands on a different cache line and - // nothing vectorises. This form writes down columns instead. - Tensor C; Eigen::Map> a(A.data()); Eigen::Map> b(B.data()); Eigen::Map> c(C.data()); @@ -294,8 +268,7 @@ namespace mat_fun { Tensor4 ten_symm_prod(const Array& A, const Array& B, const int nd); - /// @brief Symmetric dyadic product of two 2nd order tensors, - /// C_ijkl = 0.5 * (A_ik * B_jl + A_il * B_jk). + /// @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) /// /// @tparam nsd Number of spatial dimensions. /// @param[in] A,B Second order tensors. @@ -307,26 +280,12 @@ namespace mat_fun { // Initialize the result tensor Tensor C; - // C_ijkl = 0.5 * (A_ik * B_jl + A_il * B_jk). - // - // Same ordering point as dyadic_product: with column-major storage the - // flat index is i + nsd*j + nsd^2*k + nsd^3*l, so iterating l innermost - // strides by nsd^3. Running i innermost instead makes the writes - // contiguous and the inner statement a vectorisable axpy, since only - // A(i,k) and A(i,l) vary with i. - double* c = C.data(); + // Compute the symmetric product: C_ijkl = 0.5 * (A_ik * B_jl + A_il * B_jk) for (int l = 0; l < nsd; ++l) { for (int k = 0; k < nsd; ++k) { - const double* a_k = A.data() + nsd * k; // A(:,k) - const double* a_l = A.data() + nsd * l; // A(:,l) - for (int j = 0; j < nsd; ++j) { - const double b_jl = B(j, l); - const double b_jk = B(j, k); - double* out = c + nsd * j + nsd * nsd * k + nsd * nsd * nsd * l; - for (int i = 0; i < nsd; ++i) { - out[i] = 0.5 * (a_k[i] * b_jl + a_l[i] * b_jk); - } - } + Eigen::Map> blk(C.data() + nsd * nsd * (k + nsd * l)); + blk.noalias() = 0.5 * (A.col(k) * B.col(l).transpose() + + A.col(l) * B.col(k).transpose()); } } From c3b330375492fb457f0358c3f24464a20d076a49 Mon Sep 17 00:00:00 2001 From: dseyler Date: Tue, 25 Aug 2026 14:06:40 -0700 Subject: [PATCH 06/42] Templated viscous stress functions on nsd and implemented fixed-size Eigen --- Code/Source/solver/mat_fun.h | 25 +++ Code/Source/solver/mat_models.cpp | 247 +++++++++++++++++++----------- Code/Source/solver/mat_models.h | 2 +- 3 files changed, 182 insertions(+), 92 deletions(-) diff --git a/Code/Source/solver/mat_fun.h b/Code/Source/solver/mat_fun.h index f1b79b10d..45456534f 100644 --- a/Code/Source/solver/mat_fun.h +++ b/Code/Source/solver/mat_fun.h @@ -169,6 +169,31 @@ namespace mat_fun { } Array mat_symm(const Array& A, const int nd); + + /** + * @brief Symmetric part of a 2nd order tensor, 0.5 * (A + A^T). + * + * Fixed-size overload for the Eigen matrices used by the element kernels. + * + * @tparam nsd, the number of spatial dimensions + */ + template + Matrix mat_symm(const Matrix& A) { + return 0.5 * (A + A.transpose()); + } + + /** + * @brief Deviatoric part of a 2nd order tensor, A - tr(A)/nsd * I. + * + * Fixed-size overload for the Eigen matrices used by the element kernels. + * + * @tparam nsd, the number of spatial dimensions + */ + template + Matrix mat_dev(const Matrix& A) { + return A - (A.trace() / static_cast(nsd)) * Matrix::Identity(); + } + Array mat_symm_prod(const Vector& u, const Vector& v, const int nd); double mat_trace(const Array& A, const int nd); diff --git a/Code/Source/solver/mat_models.cpp b/Code/Source/solver/mat_models.cpp index caef69cea..c577db464 100644 --- a/Code/Source/solver/mat_models.cpp +++ b/Code/Source/solver/mat_models.cpp @@ -1580,64 +1580,93 @@ void g_vol_pen(const ComMod& com_mod, const dmnType& lDmn, const double p, * @param Kvis_u Viscous tangent matrix contribution due to displacement * @param Kvis_v Visous tangent matrix contribution due to velocity */ -void compute_visc_stress_potential(const double mu, const int eNoN, const Array& Nx, const Array& vx, const Array& F, +/// @brief Potential viscous stress and tangent, with the spatial dimension +/// supplied at compile time. +/// +/// Same treatment as compute_visc_stress_newtonian_impl: nsd is a template +/// parameter so the tangent's inner loops unroll, and the nsd-sized +/// intermediates are fixed-size Eigen matrices aliased over the caller's +/// storage rather than copied. +// +template +void compute_visc_stress_potential_impl(const double mu, const int eNoN, const Array& Nx, + const Array& vx, const Array& F, Array& Svis, Array3& Kvis_u, Array3& Kvis_v) { + using MatN = mat_fun::Matrix; + // Columns are sized by eNoN, which is known only at run time but is at most + // 27 (HEX27), as in fluid.cpp. Capping the column count at compile time + // keeps these on the stack: a plain Dynamic matrix heap-allocates and takes + // Eigen's general product path, which measured 5x slower here. + static constexpr int MAX_SIZE = 27; + using MatNX = Eigen::Matrix; + + Eigen::Map Fm(F.data()); + Eigen::Map vxm(vx.data()); + Eigen::Map Nxm(Nx.data(), nsd, eNoN); + + const MatN F_Ft = Fm * Fm.transpose(); + const MatN Ft_vx = Fm.transpose() * vxm; + const MatN F_vxt = Fm * vxm.transpose(); + + // F_Nx(i,a) = sum_j F(i,j) * Nx(j,a), and likewise for vx. + const MatNX F_Nx = Fm * Nxm; + const MatNX vx_Nx = vxm * Nxm; + + // 2nd Piola-Kirchhoff stress due to viscosity, + // Svis = mu * 1/2 * ( (F^T * dv/dX) + (F^T * dv/dX)^T ) + Eigen::Map Svism(Svis.data()); + Svism.noalias() = mu * mat_fun::mat_symm(Ft_vx); - using namespace consts; - using namespace mat_fun; - using namespace utils; - - // Number of spatial dimensions - int nsd = F.nrows(); - - // Initialize Svis, Kvis_u, Kvis_v to zero - Svis = 0.0; - Kvis_u = 0.0; - Kvis_v = 0.0; - - - // Required intermediate terms for stress and tangent - auto Ft = transpose(F); - auto F_Ft = mat_mul(F, Ft); - auto Ft_vx = mat_mul(Ft, vx); - auto vxt = transpose(vx); - auto F_vxt = mat_mul(F, vxt); + // Tangent matrix contributions due to viscosity. Every element of Kvis_u + // and Kvis_v is written below, so neither needs zeroing first. + const double half_mu = 0.5 * mu; - //double F_Nx[nsd][eNoN] = {0}, vx_Nx[nsd][eNoN] = {0}; - Array F_Nx(nsd,eNoN), vx_Nx(nsd,eNoN); - - for (int a = 0; a < eNoN; ++a) { + // Same hoisting as in the Newtonian model: the b-dependent columns are + // lifted out of the a loop, and both sets of columns out of the unrolled + // i/j bodies. + for (int b = 0; b < eNoN; ++b) { + double nxb[nsd], fb[nsd]; for (int i = 0; i < nsd; ++i) { - for (int j = 0; j < nsd; ++j) { - F_Nx(i,a) += F(i,j) * Nx(j,a); - vx_Nx(i,a) += vx(i,j) * Nx(j,a); - } + nxb[i] = Nx(i,b); + fb[i] = F_Nx(i,b); } - } - - // 2nd Piola-Kirchhoff stress due to viscosity - // Svis = mu * 1/2 * ( (F^T * dv/dX) + (F^T * dv/dX)^T ) - Svis = mu * mat_symm(Ft_vx, nsd); - // Tangent matrix contributions due to viscosity - for (int b = 0; b < eNoN; ++b) { for (int a = 0; a < eNoN; ++a) { + double fa[nsd], vna[nsd]; double Nx_Nx = 0.0; for (int i = 0; i < nsd; ++i) { - Nx_Nx += Nx(i,a) * Nx(i,b); + fa[i] = F_Nx(i,a); + vna[i] = vx_Nx(i,a); + Nx_Nx += Nx(i,a) * nxb[i]; } for (int i = 0; i < nsd; ++i) { for (int j = 0; j < nsd; ++j) { - int ii = i * nsd + j; - Kvis_u(ii,a,b) = 0.5 * mu * (F_Nx(i,b) * vx_Nx(j,a) + Nx_Nx * F_vxt(i,j)); - Kvis_v(ii,a,b) = 0.5 * mu * (Nx_Nx * F_Ft(i,j) + F_Nx(i,b) * F_Nx(j,a)); + const int ii = i * nsd + j; + Kvis_u(ii,a,b) = half_mu * (fb[i] * vna[j] + Nx_Nx * F_vxt(i,j)); + Kvis_v(ii,a,b) = half_mu * (Nx_Nx * F_Ft(i,j) + fb[i] * fa[j]); } } } } } +/// @brief Dispatches on the spatial dimension. See the templated implementation. +// +void compute_visc_stress_potential(const double mu, const int eNoN, const Array& Nx, + const Array& vx, const Array& F, + Array& Svis, Array3& Kvis_u, Array3& Kvis_v) { + svmp::throw_if( + eNoN > 27, "[compute_visc_stress_potential] eNoN (" + std::to_string(eNoN) + + ") exceeds the maximum supported element node count of 27."); + + if (F.nrows() == 2) { + compute_visc_stress_potential_impl<2>(mu, eNoN, Nx, vx, F, Svis, Kvis_u, Kvis_v); + } else { + compute_visc_stress_potential_impl<3>(mu, eNoN, Nx, vx, F, Svis, Kvis_u, Kvis_v); + } +} + /** * @brief Get the viscous PK2 stress and corresponding tangent matrix contributions for a solid * with a Newtonian fluid-like viscosity model. @@ -1659,79 +1688,115 @@ void compute_visc_stress_potential(const double mu, const int eNoN, const Array< * @param Kvis_u Viscous tangent matrix contribution due to displacement * @param Kvis_v Visous tangent matrix contribution due to velocity */ -void compute_visc_stress_newtonian(const double mu, const int eNoN, const Array& Nx, const Array& vx, const Array& F, +/// @brief Newtonian viscous stress and tangent, with the spatial dimension +/// supplied at compile time. +/// +/// Templating on nsd lets the innermost i/j loops of the tangent assembly +/// unroll, turns ii = i*nsd + j into a constant per unrolled body, resolves the +/// Kronecker delta at compile time and makes r2d a constant. The nsd-sized +/// intermediates become fixed-size Eigen matrices held on the stack. +/// +/// Array is column major, matching Eigen's default, so the inputs and Svis are +/// aliased with Eigen::Map rather than copied. Kvis_u and Kvis_v stay Array3: +/// they are nsd^2 x eNoN x eNoN, too large to copy in and out. +// +template +void compute_visc_stress_newtonian_impl(const double mu, const int eNoN, const Array& Nx, + const Array& vx, const Array& F, Array& Svis, Array3& Kvis_u, Array3& Kvis_v) { - using namespace consts; - using namespace mat_fun; - using namespace utils; - - // Number of spatial dimensions - int nsd = F.nrows(); - - // Initialize Svis, Kvis_u, Kvis_v to zero - Svis = 0.0; - Kvis_u = 0.0; - Kvis_v = 0.0; - - // Get identity matrix, Jacobian, and F^-1 - auto Idm = mat_id(nsd); - auto J = mat_det(F, nsd); - auto Fi = mat_inv(F, nsd); - - // Required intermediate terms for stress and tangent - // vx_Fi: Velocity gradient in current configuration - auto vx_Fi = mat_mul(vx, Fi); - auto vx_Fi_symm = mat_symm(vx_Fi, nsd); - // ddev: Deviatoric part of rate of strain tensor - auto ddev = mat_dev(vx_Fi_symm, nsd); - //double Nx_Fi[nsd][eNoN] = {0}, ddev_Nx_Fi[nsd][eNoN] = {0}, vx_Fi_Nx_Fi[nsd][eNoN] = {0}; - Array Nx_Fi(nsd,eNoN), ddev_Nx_Fi(nsd,eNoN), vx_Fi_Nx_Fi(nsd,eNoN); - for (int a = 0; a < eNoN; ++a) { + using MatN = mat_fun::Matrix; + // Columns are sized by eNoN, which is known only at run time but is at most + // 27 (HEX27), as in fluid.cpp. Capping the column count at compile time + // keeps these on the stack: a plain Dynamic matrix heap-allocates and takes + // Eigen's general product path, which measured 5x slower here. + static constexpr int MAX_SIZE = 27; + using MatNX = Eigen::Matrix; + + // Alias the caller's storage; no copies. + Eigen::Map Fm(F.data()); + Eigen::Map vxm(vx.data()); + Eigen::Map Nxm(Nx.data(), nsd, eNoN); + + const double J = Fm.determinant(); + const MatN Fi = Fm.inverse(); + + // vx_Fi: velocity gradient in the current configuration. + const MatN vx_Fi = vxm * Fi; + // ddev: deviatoric part of the rate of strain tensor. + const MatN ddev = mat_fun::mat_dev(mat_fun::mat_symm(vx_Fi)); + + // Nx_Fi(i,a) = sum_j Nx(j,a) * Fi(j,i), which is Fi^T * Nx. + const MatNX Nx_Fi = Fi.transpose() * Nxm; + const MatNX ddev_Nx_Fi = ddev * Nx_Fi; + const MatNX vx_Fi_Nx_Fi = vx_Fi * Nx_Fi; + + // 2nd Piola-Kirchhoff stress due to viscosity, + // Svis = 2 * mu * J * F^-1 * d_dev * F^-T. Written straight into the + // caller's array, which it has already sized. + Eigen::Map Svism(Svis.data()); + Svism.noalias() = (2.0 * mu * J) * (Fi * ddev * Fi.transpose()); + + // Tangent matrix contributions due to viscosity. Every element of Kvis_u + // and Kvis_v is written below, so neither needs zeroing first. + constexpr double r2d = 2.0 / nsd; + const double muJ = mu * J; + + // The b columns are invariant across the inner a loop, and the a columns + // across the unrolled i/j bodies, so both are copied into locals first. + // Reading from those instead of re-indexing the matrices lets the compiler + // keep them in registers. + for (int b = 0; b < eNoN; ++b) { + double nb[nsd], db[nsd], vb[nsd]; for (int i = 0; i < nsd; ++i) { - for (int j = 0; j < nsd; ++j) { - Nx_Fi(i,a) += Nx(j,a) * Fi(j,i); - } + nb[i] = Nx_Fi(i,b); + db[i] = ddev_Nx_Fi(i,b); + vb[i] = vx_Fi_Nx_Fi(i,b); } - } - - mat_mul(ddev, Nx_Fi, ddev_Nx_Fi); - mat_mul(vx_Fi, Nx_Fi, vx_Fi_Nx_Fi); - - // 2nd Piola-Kirchhoff stress due to viscosity - // Svis = 2 * mu * J * F^-1 * d_dev * F^-T - auto Fit = transpose(Fi); - auto ddev_Fit = mat_mul(ddev, Fit); - auto Fi_ddev_Fit = mat_mul(Fi, ddev_Fit); - Svis = 2.0 * mu * J * Fi_ddev_Fit; - // Tangent matrix contributions due to viscosity - double r2d = 2.0 / nsd; - for (int b = 0; b < eNoN; ++b) { for (int a = 0; a < eNoN; ++a) { + double na[nsd], da[nsd], va[nsd]; double Nx_Fi_Nx_Fi = 0.0; for (int i = 0; i < nsd; ++i) { - Nx_Fi_Nx_Fi += Nx_Fi(i,a) * Nx_Fi(i,b); + na[i] = Nx_Fi(i,a); + da[i] = ddev_Nx_Fi(i,a); + va[i] = vx_Fi_Nx_Fi(i,a); + Nx_Fi_Nx_Fi += na[i] * nb[i]; } for (int i = 0; i < nsd; ++i) { for (int j = 0; j < nsd; ++j) { - int ii = i * nsd + j; + const int ii = i * nsd + j; // Derivative of the residual w.r.t displacement - Kvis_u(ii,a,b) = mu * J * (2.0 * - (ddev_Nx_Fi(i,a) * Nx_Fi(j,b) - ddev_Nx_Fi(i,b) * Nx_Fi(j,a)) - - (Nx_Fi_Nx_Fi * vx_Fi(i,j) + Nx_Fi(i,b) * vx_Fi_Nx_Fi(j,a) - - r2d * Nx_Fi(i,a) * vx_Fi_Nx_Fi(j,b))); + Kvis_u(ii,a,b) = muJ * (2.0 * (da[i] * nb[j] - db[i] * na[j]) - + (Nx_Fi_Nx_Fi * vx_Fi(i,j) + nb[i] * va[j] - + r2d * na[i] * vb[j])); // Derivative of the residual w.r.t velocity - Kvis_v(ii,a,b) = mu * J * (Nx_Fi_Nx_Fi * Idm(i,j) + - Nx_Fi(i,b) * Nx_Fi(j,a) - r2d * Nx_Fi(i,a) * Nx_Fi(j,b)); + Kvis_v(ii,a,b) = muJ * (Nx_Fi_Nx_Fi * (i == j ? 1.0 : 0.0) + + nb[i] * na[j] - r2d * na[i] * nb[j]); } } } } } +/// @brief Dispatches on the spatial dimension. See the templated implementation. +// +void compute_visc_stress_newtonian(const double mu, const int eNoN, const Array& Nx, + const Array& vx, const Array& F, + Array& Svis, Array3& Kvis_u, Array3& Kvis_v) { + svmp::throw_if( + eNoN > 27, "[compute_visc_stress_newtonian] eNoN (" + std::to_string(eNoN) + + ") exceeds the maximum supported element node count of 27."); + + if (F.nrows() == 2) { + compute_visc_stress_newtonian_impl<2>(mu, eNoN, Nx, vx, F, Svis, Kvis_u, Kvis_v); + } else { + compute_visc_stress_newtonian_impl<3>(mu, eNoN, Nx, vx, F, Svis, Kvis_u, Kvis_v); + } +} + /** * @brief Get the solid viscous PK2 stress and corresponding tangent matrix contributions diff --git a/Code/Source/solver/mat_models.h b/Code/Source/solver/mat_models.h index 6a959e132..a8ef44ff7 100644 --- a/Code/Source/solver/mat_models.h +++ b/Code/Source/solver/mat_models.h @@ -66,7 +66,7 @@ void compute_svol_p(const ComMod& com_mod, const CepMod& cep_mod, const stModelT void g_vol_pen(const ComMod& com_mod, const dmnType& lDmn, const double p, double& ro, double& bt, double& dro, double& dbt, const double Ja); -void compute_visc_stress_potential(const double mu, const int eNoN, const Array& Nx, const double vx, const double F, +void compute_visc_stress_potential(const double mu, const int eNoN, const Array& Nx, const Array& vx, const Array& F, Array& Svis, Array3& Kvis_u, Array3& Kvis_v); void compute_visc_stress_newtonian(const double mu, const int eNoN, const Array& Nx, const Array& vx, const Array& F, From 4915b39bdb166fa6f0b7031f08570137cab78dc5 Mon Sep 17 00:00:00 2001 From: dseyler Date: Thu, 27 Aug 2026 13:04:22 -0700 Subject: [PATCH 07/42] Updated documentation --- Code/Source/solver/mat_models.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/Code/Source/solver/mat_models.h b/Code/Source/solver/mat_models.h index a8ef44ff7..4163d24fd 100644 --- a/Code/Source/solver/mat_models.h +++ b/Code/Source/solver/mat_models.h @@ -66,12 +66,33 @@ void compute_svol_p(const ComMod& com_mod, const CepMod& cep_mod, const stModelT void g_vol_pen(const ComMod& com_mod, const dmnType& lDmn, const double p, double& ro, double& bt, double& dro, double& dbt, const double Ja); +/// @brief Viscous 2nd Piola-Kirchhoff stress and tangent for a potential-based solid. +/// +/// Arguments are as for compute_visc_stress_newtonian(). void compute_visc_stress_potential(const double mu, const int eNoN, const Array& Nx, const Array& vx, const Array& F, Array& Svis, Array3& Kvis_u, Array3& Kvis_v); +/// @brief Viscous 2nd Piola-Kirchhoff stress and tangent for a Newtonian solid. +/// +/// @param[in] mu Dynamic viscosity. +/// @param[in] eNoN Number of element nodes. +/// @param[in] Nx Shape function spatial derivatives. +/// @param[in] vx Velocity gradient. +/// @param[in] F Deformation gradient. +/// @param[out] Svis Viscous 2nd Piola-Kirchhoff stress. +/// @param[out] Kvis_u,Kvis_v Tangent contributions w.r.t. displacement and velocity. void compute_visc_stress_newtonian(const double mu, const int eNoN, const Array& Nx, const Array& vx, const Array& F, Array& Svis, Array3& Kvis_u, Array3& Kvis_v); +/// @brief Dispatch to the viscosity model configured for the domain. +/// +/// Writes zeros to @p Svis, @p Kvis_u and @p Kvis_v when the domain has no +/// viscosity model, so that callers reusing these buffers do not observe the +/// previous element's values. +/// +/// @param[in] lDmn Domain, supplying the viscosity model and its parameters. +/// @param[in] eNoN,Nx,vx,F As for compute_visc_stress_newtonian(). +/// @param[out] Svis,Kvis_u,Kvis_v As for compute_visc_stress_newtonian(). void compute_visc_stress_and_tangent(const dmnType& lDmn, const int eNoN, const Array& Nx, const Array& vx, const Array& F, Array& Svis, Array3& Kvis_u, Array3& Kvis_v); }; From 1c22dad25c133ca6482e33273e2540beea1129a7 Mon Sep 17 00:00:00 2001 From: dseyler Date: Sun, 30 Aug 2026 15:22:15 -0700 Subject: [PATCH 08/42] Trimmed comments from viscous stress functions --- Code/Source/solver/mat_models.cpp | 34 +++++++------------------------ 1 file changed, 7 insertions(+), 27 deletions(-) diff --git a/Code/Source/solver/mat_models.cpp b/Code/Source/solver/mat_models.cpp index c577db464..5db7dc024 100644 --- a/Code/Source/solver/mat_models.cpp +++ b/Code/Source/solver/mat_models.cpp @@ -1582,12 +1582,6 @@ void g_vol_pen(const ComMod& com_mod, const dmnType& lDmn, const double p, */ /// @brief Potential viscous stress and tangent, with the spatial dimension /// supplied at compile time. -/// -/// Same treatment as compute_visc_stress_newtonian_impl: nsd is a template -/// parameter so the tangent's inner loops unroll, and the nsd-sized -/// intermediates are fixed-size Eigen matrices aliased over the caller's -/// storage rather than copied. -// template void compute_visc_stress_potential_impl(const double mu, const int eNoN, const Array& Nx, const Array& vx, const Array& F, @@ -1595,8 +1589,7 @@ void compute_visc_stress_potential_impl(const double mu, const int eNoN, const A using MatN = mat_fun::Matrix; // Columns are sized by eNoN, which is known only at run time but is at most // 27 (HEX27), as in fluid.cpp. Capping the column count at compile time - // keeps these on the stack: a plain Dynamic matrix heap-allocates and takes - // Eigen's general product path, which measured 5x slower here. + // keeps these on the stack. static constexpr int MAX_SIZE = 27; using MatNX = Eigen::Matrix; @@ -1621,9 +1614,7 @@ void compute_visc_stress_potential_impl(const double mu, const int eNoN, const A // and Kvis_v is written below, so neither needs zeroing first. const double half_mu = 0.5 * mu; - // Same hoisting as in the Newtonian model: the b-dependent columns are - // lifted out of the a loop, and both sets of columns out of the unrolled - // i/j bodies. + // The b columns are invariant across the a loop, so they are read once. for (int b = 0; b < eNoN; ++b) { double nxb[nsd], fb[nsd]; for (int i = 0; i < nsd; ++i) { @@ -1651,8 +1642,7 @@ void compute_visc_stress_potential_impl(const double mu, const int eNoN, const A } } -/// @brief Dispatches on the spatial dimension. See the templated implementation. -// +/// @brief Dispatches on the spatial dimension. void compute_visc_stress_potential(const double mu, const int eNoN, const Array& Nx, const Array& vx, const Array& F, Array& Svis, Array3& Kvis_u, Array3& Kvis_v) { @@ -1691,15 +1681,9 @@ void compute_visc_stress_potential(const double mu, const int eNoN, const Array< /// @brief Newtonian viscous stress and tangent, with the spatial dimension /// supplied at compile time. /// -/// Templating on nsd lets the innermost i/j loops of the tangent assembly -/// unroll, turns ii = i*nsd + j into a constant per unrolled body, resolves the -/// Kronecker delta at compile time and makes r2d a constant. The nsd-sized -/// intermediates become fixed-size Eigen matrices held on the stack. -/// /// Array is column major, matching Eigen's default, so the inputs and Svis are /// aliased with Eigen::Map rather than copied. Kvis_u and Kvis_v stay Array3: /// they are nsd^2 x eNoN x eNoN, too large to copy in and out. -// template void compute_visc_stress_newtonian_impl(const double mu, const int eNoN, const Array& Nx, const Array& vx, const Array& F, @@ -1707,8 +1691,7 @@ void compute_visc_stress_newtonian_impl(const double mu, const int eNoN, const A using MatN = mat_fun::Matrix; // Columns are sized by eNoN, which is known only at run time but is at most // 27 (HEX27), as in fluid.cpp. Capping the column count at compile time - // keeps these on the stack: a plain Dynamic matrix heap-allocates and takes - // Eigen's general product path, which measured 5x slower here. + // keeps these on the stack. static constexpr int MAX_SIZE = 27; using MatNX = Eigen::Matrix; @@ -1741,10 +1724,8 @@ void compute_visc_stress_newtonian_impl(const double mu, const int eNoN, const A constexpr double r2d = 2.0 / nsd; const double muJ = mu * J; - // The b columns are invariant across the inner a loop, and the a columns - // across the unrolled i/j bodies, so both are copied into locals first. - // Reading from those instead of re-indexing the matrices lets the compiler - // keep them in registers. + // The b columns are invariant across the a loop, and the a columns across + // the i/j bodies, so both are read into locals once. for (int b = 0; b < eNoN; ++b) { double nb[nsd], db[nsd], vb[nsd]; for (int i = 0; i < nsd; ++i) { @@ -1781,8 +1762,7 @@ void compute_visc_stress_newtonian_impl(const double mu, const int eNoN, const A } } -/// @brief Dispatches on the spatial dimension. See the templated implementation. -// +/// @brief Dispatches on the spatial dimension. void compute_visc_stress_newtonian(const double mu, const int eNoN, const Array& Nx, const Array& vx, const Array& F, Array& Svis, Array3& Kvis_u, Array3& Kvis_v) { From f2f619849aa9da6acc355b84da6dd40aacdbf529 Mon Sep 17 00:00:00 2001 From: dseyler Date: Sun, 30 Aug 2026 18:32:29 -0700 Subject: [PATCH 09/42] trim comments and assume 27-node element bound rather than checking per gauss point --- Code/Source/solver/mat_models.cpp | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/Code/Source/solver/mat_models.cpp b/Code/Source/solver/mat_models.cpp index 5db7dc024..fde5b046b 100644 --- a/Code/Source/solver/mat_models.cpp +++ b/Code/Source/solver/mat_models.cpp @@ -1587,9 +1587,7 @@ void compute_visc_stress_potential_impl(const double mu, const int eNoN, const A const Array& vx, const Array& F, Array& Svis, Array3& Kvis_u, Array3& Kvis_v) { using MatN = mat_fun::Matrix; - // Columns are sized by eNoN, which is known only at run time but is at most - // 27 (HEX27), as in fluid.cpp. Capping the column count at compile time - // keeps these on the stack. + // eNoN is a run-time size but never exceeds 27 (HEX27), as in fluid.cpp. static constexpr int MAX_SIZE = 27; using MatNX = Eigen::Matrix; @@ -1646,10 +1644,6 @@ void compute_visc_stress_potential_impl(const double mu, const int eNoN, const A void compute_visc_stress_potential(const double mu, const int eNoN, const Array& Nx, const Array& vx, const Array& F, Array& Svis, Array3& Kvis_u, Array3& Kvis_v) { - svmp::throw_if( - eNoN > 27, "[compute_visc_stress_potential] eNoN (" + std::to_string(eNoN) + - ") exceeds the maximum supported element node count of 27."); - if (F.nrows() == 2) { compute_visc_stress_potential_impl<2>(mu, eNoN, Nx, vx, F, Svis, Kvis_u, Kvis_v); } else { @@ -1689,9 +1683,7 @@ void compute_visc_stress_newtonian_impl(const double mu, const int eNoN, const A const Array& vx, const Array& F, Array& Svis, Array3& Kvis_u, Array3& Kvis_v) { using MatN = mat_fun::Matrix; - // Columns are sized by eNoN, which is known only at run time but is at most - // 27 (HEX27), as in fluid.cpp. Capping the column count at compile time - // keeps these on the stack. + // eNoN is a run-time size but never exceeds 27 (HEX27), as in fluid.cpp. static constexpr int MAX_SIZE = 27; using MatNX = Eigen::Matrix; @@ -1705,8 +1697,9 @@ void compute_visc_stress_newtonian_impl(const double mu, const int eNoN, const A // vx_Fi: velocity gradient in the current configuration. const MatN vx_Fi = vxm * Fi; + const MatN vx_Fi_symm = mat_fun::mat_symm(vx_Fi); // ddev: deviatoric part of the rate of strain tensor. - const MatN ddev = mat_fun::mat_dev(mat_fun::mat_symm(vx_Fi)); + const MatN ddev = mat_fun::mat_dev(vx_Fi_symm); // Nx_Fi(i,a) = sum_j Nx(j,a) * Fi(j,i), which is Fi^T * Nx. const MatNX Nx_Fi = Fi.transpose() * Nxm; @@ -1766,10 +1759,6 @@ void compute_visc_stress_newtonian_impl(const double mu, const int eNoN, const A void compute_visc_stress_newtonian(const double mu, const int eNoN, const Array& Nx, const Array& vx, const Array& F, Array& Svis, Array3& Kvis_u, Array3& Kvis_v) { - svmp::throw_if( - eNoN > 27, "[compute_visc_stress_newtonian] eNoN (" + std::to_string(eNoN) + - ") exceeds the maximum supported element node count of 27."); - if (F.nrows() == 2) { compute_visc_stress_newtonian_impl<2>(mu, eNoN, Nx, vx, F, Svis, Kvis_u, Kvis_v); } else { From 2f45845382ce09c6b53b34907d642a60b0996ea8 Mon Sep 17 00:00:00 2001 From: dseyler Date: Sun, 30 Aug 2026 19:36:21 -0700 Subject: [PATCH 10/42] Polished documentations, variable names, and types --- Code/Source/solver/mat_fun.h | 10 +- Code/Source/solver/mat_models.cpp | 181 ++++++++++++++---------------- Code/Source/solver/mat_models.h | 5 +- 3 files changed, 94 insertions(+), 102 deletions(-) diff --git a/Code/Source/solver/mat_fun.h b/Code/Source/solver/mat_fun.h index 45456534f..d4b58a500 100644 --- a/Code/Source/solver/mat_fun.h +++ b/Code/Source/solver/mat_fun.h @@ -175,7 +175,9 @@ namespace mat_fun { * * Fixed-size overload for the Eigen matrices used by the element kernels. * - * @tparam nsd, the number of spatial dimensions + * @tparam nsd Number of spatial dimensions. + * @param[in] A Second order tensor. + * @return The symmetric part of A. */ template Matrix mat_symm(const Matrix& A) { @@ -187,11 +189,13 @@ namespace mat_fun { * * Fixed-size overload for the Eigen matrices used by the element kernels. * - * @tparam nsd, the number of spatial dimensions + * @tparam nsd Number of spatial dimensions. + * @param[in] A Second order tensor. + * @return The deviatoric part of A. */ template Matrix mat_dev(const Matrix& A) { - return A - (A.trace() / static_cast(nsd)) * Matrix::Identity(); + return A - (A.trace() / nsd) * Matrix::Identity(); } Array mat_symm_prod(const Vector& u, const Vector& v, const int nd); diff --git a/Code/Source/solver/mat_models.cpp b/Code/Source/solver/mat_models.cpp index fde5b046b..1f3c03012 100644 --- a/Code/Source/solver/mat_models.cpp +++ b/Code/Source/solver/mat_models.cpp @@ -1559,6 +1559,18 @@ void g_vol_pen(const ComMod& com_mod, const dmnType& lDmn, const double p, } } +namespace { + +/// @brief Largest element node count the fixed-size views below allow (HEX27). +constexpr int MAX_ELEMENT_NODES = 27; + +/// @brief An nsd x eNoN matrix whose column count is bounded at compile time, +/// so that it is held on the stack rather than heap allocated. +template +using MatNodes = Eigen::Matrix; + +} // namespace + /** * @brief Get the viscous PK2 stress and corresponding tangent matrix contributions for a solid * with a viscous pseudo-potential model. @@ -1570,70 +1582,60 @@ void g_vol_pen(const ComMod& com_mod, const dmnType& lDmn, const double p, * = mu * 1/2 * F^T * (grad(v) + grad(v)^T) * F * = mu * 1/2 * ( (F^T * Grad(v)) + (F^T * Grad(v))^T ) * - * @tparam nsd Number of spatial dimensions - * @param mu Solid viscosity parameter - * @param eNoN Number of nodes in an element - * @param Nx Shape function gradient w.r.t. reference configuration coordinates (dN/dX) - * @param vx Velocity gradient matrix w.r.t reference configuration coordinates (dv/dX) - * @param F Deformation gradient matrix - * @param Svis Viscous 2nd Piola-Kirchhoff stress matrix - * @param Kvis_u Viscous tangent matrix contribution due to displacement - * @param Kvis_v Visous tangent matrix contribution due to velocity + * Arguments are documented in mat_models.h. Array is column major, matching + * Eigen's default, so the inputs and Svis are aliased with Eigen::Map rather + * than copied. + * + * @tparam nsd Number of spatial dimensions, supplied at compile time. */ -/// @brief Potential viscous stress and tangent, with the spatial dimension -/// supplied at compile time. -template +template void compute_visc_stress_potential_impl(const double mu, const int eNoN, const Array& Nx, const Array& vx, const Array& F, Array& Svis, Array3& Kvis_u, Array3& Kvis_v) { - using MatN = mat_fun::Matrix; - // eNoN is a run-time size but never exceeds 27 (HEX27), as in fluid.cpp. - static constexpr int MAX_SIZE = 27; - using MatNX = Eigen::Matrix; + using MatNsd = mat_fun::Matrix; - Eigen::Map Fm(F.data()); - Eigen::Map vxm(vx.data()); - Eigen::Map Nxm(Nx.data(), nsd, eNoN); + Eigen::Map F_map(F.data()); + Eigen::Map vx_map(vx.data()); + Eigen::Map> Nx_map(Nx.data(), nsd, eNoN); - const MatN F_Ft = Fm * Fm.transpose(); - const MatN Ft_vx = Fm.transpose() * vxm; - const MatN F_vxt = Fm * vxm.transpose(); + const MatNsd F_Ft = F_map * F_map.transpose(); + const MatNsd Ft_vx = F_map.transpose() * vx_map; + const MatNsd F_vxt = F_map * vx_map.transpose(); // F_Nx(i,a) = sum_j F(i,j) * Nx(j,a), and likewise for vx. - const MatNX F_Nx = Fm * Nxm; - const MatNX vx_Nx = vxm * Nxm; + const MatNodes F_Nx = F_map * Nx_map; + const MatNodes vx_Nx = vx_map * Nx_map; // 2nd Piola-Kirchhoff stress due to viscosity, // Svis = mu * 1/2 * ( (F^T * dv/dX) + (F^T * dv/dX)^T ) - Eigen::Map Svism(Svis.data()); - Svism.noalias() = mu * mat_fun::mat_symm(Ft_vx); + Eigen::Map Svis_map(Svis.data()); + Svis_map.noalias() = mu * mat_fun::mat_symm(Ft_vx); // Tangent matrix contributions due to viscosity. Every element of Kvis_u // and Kvis_v is written below, so neither needs zeroing first. - const double half_mu = 0.5 * mu; // The b columns are invariant across the a loop, so they are read once. for (int b = 0; b < eNoN; ++b) { - double nxb[nsd], fb[nsd]; + double Nx_b[nsd], F_Nx_b[nsd]; for (int i = 0; i < nsd; ++i) { - nxb[i] = Nx(i,b); - fb[i] = F_Nx(i,b); + Nx_b[i] = Nx(i,b); + F_Nx_b[i] = F_Nx(i,b); } for (int a = 0; a < eNoN; ++a) { - double fa[nsd], vna[nsd]; + double F_Nx_a[nsd], vx_Nx_a[nsd]; double Nx_Nx = 0.0; for (int i = 0; i < nsd; ++i) { - fa[i] = F_Nx(i,a); - vna[i] = vx_Nx(i,a); - Nx_Nx += Nx(i,a) * nxb[i]; + F_Nx_a[i] = F_Nx(i,a); + vx_Nx_a[i] = vx_Nx(i,a); + Nx_Nx += Nx(i,a) * Nx_b[i]; } for (int i = 0; i < nsd; ++i) { for (int j = 0; j < nsd; ++j) { - const int ii = i * nsd + j; - Kvis_u(ii,a,b) = half_mu * (fb[i] * vna[j] + Nx_Nx * F_vxt(i,j)); - Kvis_v(ii,a,b) = half_mu * (Nx_Nx * F_Ft(i,j) + fb[i] * fa[j]); + int ii = i * nsd + j; + Kvis_u(ii,a,b) = 0.5 * mu * (F_Nx_b[i] * vx_Nx_a[j] + Nx_Nx * F_vxt(i,j)); + Kvis_v(ii,a,b) = 0.5 * mu * (Nx_Nx * F_Ft(i,j) + F_Nx_b[i] * F_Nx_a[j]); } } } @@ -1641,13 +1643,12 @@ void compute_visc_stress_potential_impl(const double mu, const int eNoN, const A } /// @brief Dispatches on the spatial dimension. -void compute_visc_stress_potential(const double mu, const int eNoN, const Array& Nx, - const Array& vx, const Array& F, +void compute_visc_stress_potential(const double mu, const int eNoN, const Array& Nx, const Array& vx, const Array& F, Array& Svis, Array3& Kvis_u, Array3& Kvis_v) { - if (F.nrows() == 2) { - compute_visc_stress_potential_impl<2>(mu, eNoN, Nx, vx, F, Svis, Kvis_u, Kvis_v); - } else { + if (F.nrows() == 3) { compute_visc_stress_potential_impl<3>(mu, eNoN, Nx, vx, F, Svis, Kvis_u, Kvis_v); + } else if (F.nrows() == 2) { + compute_visc_stress_potential_impl<2>(mu, eNoN, Nx, vx, F, Svis, Kvis_u, Kvis_v); } } @@ -1662,93 +1663,82 @@ void compute_visc_stress_potential(const double mu, const int eNoN, const Array< * * Note, there is likely an error/bug in the tangent contributions that leads to suboptimal nonlinear convergence * - * @tparam nsd Number of spatial dimensions - * @param mu Solid viscosity parameter - * @param eNoN Number of nodes in an element - * @param Nx Shape function gradient w.r.t. reference configuration coordinates (dN/dX) - * @param vx Velocity gradient matrix w.r.t reference configuration coordinates (dv/dX) - * @param F Deformation gradient matrix - * @param Svis Viscous 2nd Piola-Kirchhoff stress matrix - * @param Kvis_u Viscous tangent matrix contribution due to displacement - * @param Kvis_v Visous tangent matrix contribution due to velocity + * Arguments are documented in mat_models.h. Array is column major, matching + * Eigen's default, so the inputs and Svis are aliased with Eigen::Map rather + * than copied. Kvis_u and Kvis_v stay Array3: they are nsd^2 x eNoN x eNoN, + * too large to copy in and out. + * + * @tparam nsd Number of spatial dimensions, supplied at compile time. */ -/// @brief Newtonian viscous stress and tangent, with the spatial dimension -/// supplied at compile time. -/// -/// Array is column major, matching Eigen's default, so the inputs and Svis are -/// aliased with Eigen::Map rather than copied. Kvis_u and Kvis_v stay Array3: -/// they are nsd^2 x eNoN x eNoN, too large to copy in and out. -template +template void compute_visc_stress_newtonian_impl(const double mu, const int eNoN, const Array& Nx, const Array& vx, const Array& F, Array& Svis, Array3& Kvis_u, Array3& Kvis_v) { - using MatN = mat_fun::Matrix; - // eNoN is a run-time size but never exceeds 27 (HEX27), as in fluid.cpp. - static constexpr int MAX_SIZE = 27; - using MatNX = Eigen::Matrix; + using MatNsd = mat_fun::Matrix; // Alias the caller's storage; no copies. - Eigen::Map Fm(F.data()); - Eigen::Map vxm(vx.data()); - Eigen::Map Nxm(Nx.data(), nsd, eNoN); + Eigen::Map F_map(F.data()); + Eigen::Map vx_map(vx.data()); + Eigen::Map> Nx_map(Nx.data(), nsd, eNoN); - const double J = Fm.determinant(); - const MatN Fi = Fm.inverse(); + const double J = F_map.determinant(); + const MatNsd Fi = F_map.inverse(); // vx_Fi: velocity gradient in the current configuration. - const MatN vx_Fi = vxm * Fi; - const MatN vx_Fi_symm = mat_fun::mat_symm(vx_Fi); + const MatNsd vx_Fi = vx_map * Fi; + const MatNsd vx_Fi_symm = mat_fun::mat_symm(vx_Fi); // ddev: deviatoric part of the rate of strain tensor. - const MatN ddev = mat_fun::mat_dev(vx_Fi_symm); + const MatNsd ddev = mat_fun::mat_dev(vx_Fi_symm); // Nx_Fi(i,a) = sum_j Nx(j,a) * Fi(j,i), which is Fi^T * Nx. - const MatNX Nx_Fi = Fi.transpose() * Nxm; - const MatNX ddev_Nx_Fi = ddev * Nx_Fi; - const MatNX vx_Fi_Nx_Fi = vx_Fi * Nx_Fi; + const MatNodes Nx_Fi = Fi.transpose() * Nx_map; + const MatNodes ddev_Nx_Fi = ddev * Nx_Fi; + const MatNodes vx_Fi_Nx_Fi = vx_Fi * Nx_Fi; // 2nd Piola-Kirchhoff stress due to viscosity, // Svis = 2 * mu * J * F^-1 * d_dev * F^-T. Written straight into the // caller's array, which it has already sized. - Eigen::Map Svism(Svis.data()); - Svism.noalias() = (2.0 * mu * J) * (Fi * ddev * Fi.transpose()); + Eigen::Map Svis_map(Svis.data()); + Svis_map.noalias() = (2.0 * mu * J) * (Fi * ddev * Fi.transpose()); // Tangent matrix contributions due to viscosity. Every element of Kvis_u // and Kvis_v is written below, so neither needs zeroing first. constexpr double r2d = 2.0 / nsd; - const double muJ = mu * J; + const MatNsd Idm = MatNsd::Identity(); // The b columns are invariant across the a loop, and the a columns across // the i/j bodies, so both are read into locals once. for (int b = 0; b < eNoN; ++b) { - double nb[nsd], db[nsd], vb[nsd]; + double Nx_Fi_b[nsd], ddev_Nx_Fi_b[nsd], vx_Fi_Nx_Fi_b[nsd]; for (int i = 0; i < nsd; ++i) { - nb[i] = Nx_Fi(i,b); - db[i] = ddev_Nx_Fi(i,b); - vb[i] = vx_Fi_Nx_Fi(i,b); + Nx_Fi_b[i] = Nx_Fi(i,b); + ddev_Nx_Fi_b[i] = ddev_Nx_Fi(i,b); + vx_Fi_Nx_Fi_b[i] = vx_Fi_Nx_Fi(i,b); } for (int a = 0; a < eNoN; ++a) { - double na[nsd], da[nsd], va[nsd]; + double Nx_Fi_a[nsd], ddev_Nx_Fi_a[nsd], vx_Fi_Nx_Fi_a[nsd]; double Nx_Fi_Nx_Fi = 0.0; for (int i = 0; i < nsd; ++i) { - na[i] = Nx_Fi(i,a); - da[i] = ddev_Nx_Fi(i,a); - va[i] = vx_Fi_Nx_Fi(i,a); - Nx_Fi_Nx_Fi += na[i] * nb[i]; + Nx_Fi_a[i] = Nx_Fi(i,a); + ddev_Nx_Fi_a[i] = ddev_Nx_Fi(i,a); + vx_Fi_Nx_Fi_a[i] = vx_Fi_Nx_Fi(i,a); + Nx_Fi_Nx_Fi += Nx_Fi_a[i] * Nx_Fi_b[i]; } for (int i = 0; i < nsd; ++i) { for (int j = 0; j < nsd; ++j) { - const int ii = i * nsd + j; + int ii = i * nsd + j; // Derivative of the residual w.r.t displacement - Kvis_u(ii,a,b) = muJ * (2.0 * (da[i] * nb[j] - db[i] * na[j]) - - (Nx_Fi_Nx_Fi * vx_Fi(i,j) + nb[i] * va[j] - - r2d * na[i] * vb[j])); + Kvis_u(ii,a,b) = mu * J * (2.0 * (ddev_Nx_Fi_a[i] * Nx_Fi_b[j] - + ddev_Nx_Fi_b[i] * Nx_Fi_a[j]) - + (Nx_Fi_Nx_Fi * vx_Fi(i,j) + Nx_Fi_b[i] * vx_Fi_Nx_Fi_a[j] - + r2d * Nx_Fi_a[i] * vx_Fi_Nx_Fi_b[j])); // Derivative of the residual w.r.t velocity - Kvis_v(ii,a,b) = muJ * (Nx_Fi_Nx_Fi * (i == j ? 1.0 : 0.0) + - nb[i] * na[j] - r2d * na[i] * nb[j]); + Kvis_v(ii,a,b) = mu * J * (Nx_Fi_Nx_Fi * Idm(i,j) + + Nx_Fi_b[i] * Nx_Fi_a[j] - r2d * Nx_Fi_a[i] * Nx_Fi_b[j]); } } } @@ -1756,13 +1746,12 @@ void compute_visc_stress_newtonian_impl(const double mu, const int eNoN, const A } /// @brief Dispatches on the spatial dimension. -void compute_visc_stress_newtonian(const double mu, const int eNoN, const Array& Nx, - const Array& vx, const Array& F, +void compute_visc_stress_newtonian(const double mu, const int eNoN, const Array& Nx, const Array& vx, const Array& F, Array& Svis, Array3& Kvis_u, Array3& Kvis_v) { - if (F.nrows() == 2) { - compute_visc_stress_newtonian_impl<2>(mu, eNoN, Nx, vx, F, Svis, Kvis_u, Kvis_v); - } else { + if (F.nrows() == 3) { compute_visc_stress_newtonian_impl<3>(mu, eNoN, Nx, vx, F, Svis, Kvis_u, Kvis_v); + } else if (F.nrows() == 2) { + compute_visc_stress_newtonian_impl<2>(mu, eNoN, Nx, vx, F, Svis, Kvis_u, Kvis_v); } } diff --git a/Code/Source/solver/mat_models.h b/Code/Source/solver/mat_models.h index 4163d24fd..1e052274e 100644 --- a/Code/Source/solver/mat_models.h +++ b/Code/Source/solver/mat_models.h @@ -86,9 +86,8 @@ void compute_visc_stress_newtonian(const double mu, const int eNoN, const Array< /// @brief Dispatch to the viscosity model configured for the domain. /// -/// Writes zeros to @p Svis, @p Kvis_u and @p Kvis_v when the domain has no -/// viscosity model, so that callers reusing these buffers do not observe the -/// previous element's values. +/// Leaves @p Svis, @p Kvis_u and @p Kvis_v untouched when the domain has no +/// viscosity model, so callers must not rely on them being cleared here. /// /// @param[in] lDmn Domain, supplying the viscosity model and its parameters. /// @param[in] eNoN,Nx,vx,F As for compute_visc_stress_newtonian(). From 83a4ad26cd2394fe27e3e2f994ed3802ada603da Mon Sep 17 00:00:00 2001 From: dseyler Date: Mon, 31 Aug 2026 09:23:41 -0700 Subject: [PATCH 11/42] Removed column hoisting, which had no impact on runtime --- Code/Source/solver/mat_models.cpp | 71 ++++++++++--------------------- 1 file changed, 23 insertions(+), 48 deletions(-) diff --git a/Code/Source/solver/mat_models.cpp b/Code/Source/solver/mat_models.cpp index 1f3c03012..3c6055898 100644 --- a/Code/Source/solver/mat_models.cpp +++ b/Code/Source/solver/mat_models.cpp @@ -1582,11 +1582,7 @@ using MatNodes = Eigen::Matrix void compute_visc_stress_potential_impl(const double mu, const int eNoN, const Array& Nx, @@ -1594,6 +1590,11 @@ void compute_visc_stress_potential_impl(const double mu, const int eNoN, const A Array& Svis, Array3& Kvis_u, Array3& Kvis_v) { using MatNsd = mat_fun::Matrix; + // Initialize Svis, Kvis_u, Kvis_v to zero + Svis = 0.0; + Kvis_u = 0.0; + Kvis_v = 0.0; + Eigen::Map F_map(F.data()); Eigen::Map vx_map(vx.data()); Eigen::Map> Nx_map(Nx.data(), nsd, eNoN); @@ -1611,31 +1612,19 @@ void compute_visc_stress_potential_impl(const double mu, const int eNoN, const A Eigen::Map Svis_map(Svis.data()); Svis_map.noalias() = mu * mat_fun::mat_symm(Ft_vx); - // Tangent matrix contributions due to viscosity. Every element of Kvis_u - // and Kvis_v is written below, so neither needs zeroing first. - - // The b columns are invariant across the a loop, so they are read once. + // Tangent matrix contributions due to viscosity for (int b = 0; b < eNoN; ++b) { - double Nx_b[nsd], F_Nx_b[nsd]; - for (int i = 0; i < nsd; ++i) { - Nx_b[i] = Nx(i,b); - F_Nx_b[i] = F_Nx(i,b); - } - for (int a = 0; a < eNoN; ++a) { - double F_Nx_a[nsd], vx_Nx_a[nsd]; double Nx_Nx = 0.0; for (int i = 0; i < nsd; ++i) { - F_Nx_a[i] = F_Nx(i,a); - vx_Nx_a[i] = vx_Nx(i,a); - Nx_Nx += Nx(i,a) * Nx_b[i]; + Nx_Nx += Nx(i,a) * Nx(i,b); } for (int i = 0; i < nsd; ++i) { for (int j = 0; j < nsd; ++j) { int ii = i * nsd + j; - Kvis_u(ii,a,b) = 0.5 * mu * (F_Nx_b[i] * vx_Nx_a[j] + Nx_Nx * F_vxt(i,j)); - Kvis_v(ii,a,b) = 0.5 * mu * (Nx_Nx * F_Ft(i,j) + F_Nx_b[i] * F_Nx_a[j]); + Kvis_u(ii,a,b) = 0.5 * mu * (F_Nx(i,b) * vx_Nx(j,a) + Nx_Nx * F_vxt(i,j)); + Kvis_v(ii,a,b) = 0.5 * mu * (Nx_Nx * F_Ft(i,j) + F_Nx(i,b) * F_Nx(j,a)); } } } @@ -1663,12 +1652,7 @@ void compute_visc_stress_potential(const double mu, const int eNoN, const Array< * * Note, there is likely an error/bug in the tangent contributions that leads to suboptimal nonlinear convergence * - * Arguments are documented in mat_models.h. Array is column major, matching - * Eigen's default, so the inputs and Svis are aliased with Eigen::Map rather - * than copied. Kvis_u and Kvis_v stay Array3: they are nsd^2 x eNoN x eNoN, - * too large to copy in and out. - * - * @tparam nsd Number of spatial dimensions, supplied at compile time. + * @tparam nsd Number of spatial dimensions */ template void compute_visc_stress_newtonian_impl(const double mu, const int eNoN, const Array& Nx, @@ -1676,6 +1660,11 @@ void compute_visc_stress_newtonian_impl(const double mu, const int eNoN, const A Array& Svis, Array3& Kvis_u, Array3& Kvis_v) { using MatNsd = mat_fun::Matrix; + // Initialize Svis, Kvis_u, Kvis_v to zero + Svis = 0.0; + Kvis_u = 0.0; + Kvis_v = 0.0; + // Alias the caller's storage; no copies. Eigen::Map F_map(F.data()); Eigen::Map vx_map(vx.data()); @@ -1701,29 +1690,15 @@ void compute_visc_stress_newtonian_impl(const double mu, const int eNoN, const A Eigen::Map Svis_map(Svis.data()); Svis_map.noalias() = (2.0 * mu * J) * (Fi * ddev * Fi.transpose()); - // Tangent matrix contributions due to viscosity. Every element of Kvis_u - // and Kvis_v is written below, so neither needs zeroing first. + // Tangent matrix contributions due to viscosity constexpr double r2d = 2.0 / nsd; const MatNsd Idm = MatNsd::Identity(); - // The b columns are invariant across the a loop, and the a columns across - // the i/j bodies, so both are read into locals once. for (int b = 0; b < eNoN; ++b) { - double Nx_Fi_b[nsd], ddev_Nx_Fi_b[nsd], vx_Fi_Nx_Fi_b[nsd]; - for (int i = 0; i < nsd; ++i) { - Nx_Fi_b[i] = Nx_Fi(i,b); - ddev_Nx_Fi_b[i] = ddev_Nx_Fi(i,b); - vx_Fi_Nx_Fi_b[i] = vx_Fi_Nx_Fi(i,b); - } - for (int a = 0; a < eNoN; ++a) { - double Nx_Fi_a[nsd], ddev_Nx_Fi_a[nsd], vx_Fi_Nx_Fi_a[nsd]; double Nx_Fi_Nx_Fi = 0.0; for (int i = 0; i < nsd; ++i) { - Nx_Fi_a[i] = Nx_Fi(i,a); - ddev_Nx_Fi_a[i] = ddev_Nx_Fi(i,a); - vx_Fi_Nx_Fi_a[i] = vx_Fi_Nx_Fi(i,a); - Nx_Fi_Nx_Fi += Nx_Fi_a[i] * Nx_Fi_b[i]; + Nx_Fi_Nx_Fi += Nx_Fi(i,a) * Nx_Fi(i,b); } for (int i = 0; i < nsd; ++i) { @@ -1731,14 +1706,14 @@ void compute_visc_stress_newtonian_impl(const double mu, const int eNoN, const A int ii = i * nsd + j; // Derivative of the residual w.r.t displacement - Kvis_u(ii,a,b) = mu * J * (2.0 * (ddev_Nx_Fi_a[i] * Nx_Fi_b[j] - - ddev_Nx_Fi_b[i] * Nx_Fi_a[j]) - - (Nx_Fi_Nx_Fi * vx_Fi(i,j) + Nx_Fi_b[i] * vx_Fi_Nx_Fi_a[j] - - r2d * Nx_Fi_a[i] * vx_Fi_Nx_Fi_b[j])); + Kvis_u(ii,a,b) = mu * J * (2.0 * + (ddev_Nx_Fi(i,a) * Nx_Fi(j,b) - ddev_Nx_Fi(i,b) * Nx_Fi(j,a)) - + (Nx_Fi_Nx_Fi * vx_Fi(i,j) + Nx_Fi(i,b) * vx_Fi_Nx_Fi(j,a) - + r2d * Nx_Fi(i,a) * vx_Fi_Nx_Fi(j,b))); // Derivative of the residual w.r.t velocity Kvis_v(ii,a,b) = mu * J * (Nx_Fi_Nx_Fi * Idm(i,j) + - Nx_Fi_b[i] * Nx_Fi_a[j] - r2d * Nx_Fi_a[i] * Nx_Fi_b[j]); + Nx_Fi(i,b) * Nx_Fi(j,a) - r2d * Nx_Fi(i,a) * Nx_Fi(j,b)); } } } From 42a5f4a8c7089a50ee63a54114d96118fe13ed73 Mon Sep 17 00:00:00 2001 From: dseyler Date: Wed, 2 Sep 2026 12:28:24 -0700 Subject: [PATCH 12/42] Dispatch by nsd within compute_visc_stress_and_tangent --- Code/Source/solver/mat_models.cpp | 202 +++++++++++++++--------------- Code/Source/solver/mat_models.h | 21 +--- 2 files changed, 103 insertions(+), 120 deletions(-) diff --git a/Code/Source/solver/mat_models.cpp b/Code/Source/solver/mat_models.cpp index 3c6055898..191c4ed60 100644 --- a/Code/Source/solver/mat_models.cpp +++ b/Code/Source/solver/mat_models.cpp @@ -1564,135 +1564,137 @@ namespace { /// @brief Largest element node count the fixed-size views below allow (HEX27). constexpr int MAX_ELEMENT_NODES = 27; -/// @brief An nsd x eNoN matrix whose column count is bounded at compile time, -/// so that it is held on the stack rather than heap allocated. +/// @brief An nsd x eNoN matrix whose column count is bounded at compile time. template using MatNodes = Eigen::Matrix; } // namespace /** - * @brief Get the viscous PK2 stress and corresponding tangent matrix contributions for a solid - * with a viscous pseudo-potential model. + * @brief Viscous PK2 stress and tangent contributions for the viscous + * pseudo-potential model. + * * This is defined by a viscous pseuo-potential * Psi = mu/2 * tr(E_dot^2) * The viscous 2nd Piola-Kirchhoff stress is given by - * Svis = dPsi/dE_dot + * Svis = dPsi/dE_dot * = mu * E_dot * = mu * 1/2 * F^T * (grad(v) + grad(v)^T) * F * = mu * 1/2 * ( (F^T * Grad(v)) + (F^T * Grad(v))^T ) - * + * * @tparam nsd Number of spatial dimensions + * @param[in] mu Solid viscosity parameter + * @param[in] eNoN Number of nodes in an element + * @param[in] Nx Shape function gradient w.r.t. reference configuration coordinates (dN/dX) + * @param[in] vx Velocity gradient matrix w.r.t. reference configuration coordinates (dv/dX) + * @param[in] F Deformation gradient matrix + * @param[out] Svis Viscous 2nd Piola-Kirchhoff stress matrix + * @param[out] Kvis_u Viscous tangent matrix contribution due to displacement + * @param[out] Kvis_v Viscous tangent matrix contribution due to velocity */ template -void compute_visc_stress_potential_impl(const double mu, const int eNoN, const Array& Nx, - const Array& vx, const Array& F, - Array& Svis, Array3& Kvis_u, Array3& Kvis_v) { - using MatNsd = mat_fun::Matrix; - - // Initialize Svis, Kvis_u, Kvis_v to zero - Svis = 0.0; - Kvis_u = 0.0; - Kvis_v = 0.0; - - Eigen::Map F_map(F.data()); - Eigen::Map vx_map(vx.data()); +void compute_visc_stress_potential(const double mu, const int eNoN, const Array& Nx, + const Array& vx, const Array& F, + Array& Svis, Array3& Kvis_u, Array3& Kvis_v) { + // Alias the caller's storage; no copies. Svis, Kvis_u and Kvis_v are + // written in full below, so they are not zeroed first. + Eigen::Map> F_map(F.data()); + Eigen::Map> vx_map(vx.data()); Eigen::Map> Nx_map(Nx.data(), nsd, eNoN); - const MatNsd F_Ft = F_map * F_map.transpose(); - const MatNsd Ft_vx = F_map.transpose() * vx_map; - const MatNsd F_vxt = F_map * vx_map.transpose(); + const Matrix Ft_vx = F_map.transpose() * vx_map; + + // 2nd Piola-Kirchhoff stress due to viscosity, + // Svis = mu * 1/2 * ( (F^T * dv/dX) + (F^T * dv/dX)^T ) + Eigen::Map> Svis_map(Svis.data()); + Svis_map.noalias() = mu * mat_fun::mat_symm(Ft_vx); + + // The tangent scales every term by 1/2 mu, so fold it in once here rather + // than repeating it for every node pair and component. + const Matrix hF_Ft = (0.5 * mu) * (F_map * F_map.transpose()); + const Matrix hF_vxt = (0.5 * mu) * (F_map * vx_map.transpose()); // F_Nx(i,a) = sum_j F(i,j) * Nx(j,a), and likewise for vx. const MatNodes F_Nx = F_map * Nx_map; const MatNodes vx_Nx = vx_map * Nx_map; + const MatNodes hF_Nx = (0.5 * mu) * F_Nx; - // 2nd Piola-Kirchhoff stress due to viscosity, - // Svis = mu * 1/2 * ( (F^T * dv/dX) + (F^T * dv/dX)^T ) - Eigen::Map Svis_map(Svis.data()); - Svis_map.noalias() = mu * mat_fun::mat_symm(Ft_vx); + // Kvis stores the nsd^2 components at a node pair contiguously, indexed by + // ii = i*nsd + j, so each pair's block is a row major nsd x nsd matrix + using KvisBlock = Eigen::Matrix; - // Tangent matrix contributions due to viscosity for (int b = 0; b < eNoN; ++b) { for (int a = 0; a < eNoN; ++a) { - double Nx_Nx = 0.0; - for (int i = 0; i < nsd; ++i) { - Nx_Nx += Nx(i,a) * Nx(i,b); - } + const double Nx_Nx = Nx_map.col(a).dot(Nx_map.col(b)); - for (int i = 0; i < nsd; ++i) { - for (int j = 0; j < nsd; ++j) { - int ii = i * nsd + j; - Kvis_u(ii,a,b) = 0.5 * mu * (F_Nx(i,b) * vx_Nx(j,a) + Nx_Nx * F_vxt(i,j)); - Kvis_v(ii,a,b) = 0.5 * mu * (Nx_Nx * F_Ft(i,j) + F_Nx(i,b) * F_Nx(j,a)); - } - } - } - } -} + Eigen::Map Kvis_u_ab(&Kvis_u(0,a,b)); + Eigen::Map Kvis_v_ab(&Kvis_v(0,a,b)); -/// @brief Dispatches on the spatial dimension. -void compute_visc_stress_potential(const double mu, const int eNoN, const Array& Nx, const Array& vx, const Array& F, - Array& Svis, Array3& Kvis_u, Array3& Kvis_v) { - if (F.nrows() == 3) { - compute_visc_stress_potential_impl<3>(mu, eNoN, Nx, vx, F, Svis, Kvis_u, Kvis_v); - } else if (F.nrows() == 2) { - compute_visc_stress_potential_impl<2>(mu, eNoN, Nx, vx, F, Svis, Kvis_u, Kvis_v); + Kvis_u_ab.noalias() = hF_Nx.col(b) * vx_Nx.col(a).transpose() + Nx_Nx * hF_vxt; + Kvis_v_ab.noalias() = Nx_Nx * hF_Ft + hF_Nx.col(b) * F_Nx.col(a).transpose(); + } } } /** - * @brief Get the viscous PK2 stress and corresponding tangent matrix contributions for a solid - * with a Newtonian fluid-like viscosity model. + * @brief Viscous PK2 stress and tangent contributions for a solid with a + * Newtonian fluid-like viscosity model. + * * The viscous deviatoric Cauchy stress is given by * sigma_vis_dev = 2 * mu * d_dev * where d_dev = 1/2 * (grad(v) + grad(v)^T) - 1/3 * (div(v)) * I * The viscous 2nd Piola-Kirchhoff stress is given by a pull-back operation * Svis = 2 * mu * J * F^-1 * d_dev * F^-T - * - * Note, there is likely an error/bug in the tangent contributions that leads to suboptimal nonlinear convergence - * + * + * Note, there is likely an error/bug in the tangent contributions + * that leads to suboptimal nonlinear convergence. + * * @tparam nsd Number of spatial dimensions + * @param[in] mu Solid viscosity parameter + * @param[in] eNoN Number of nodes in an element + * @param[in] Nx Shape function gradient w.r.t. reference configuration coordinates (dN/dX) + * @param[in] vx Velocity gradient matrix w.r.t. reference configuration coordinates (dv/dX) + * @param[in] F Deformation gradient matrix + * @param[out] Svis Viscous 2nd Piola-Kirchhoff stress matrix + * @param[out] Kvis_u Viscous tangent matrix contribution due to displacement + * @param[out] Kvis_v Viscous tangent matrix contribution due to velocity */ template -void compute_visc_stress_newtonian_impl(const double mu, const int eNoN, const Array& Nx, +void compute_visc_stress_newtonian(const double mu, const int eNoN, const Array& Nx, const Array& vx, const Array& F, Array& Svis, Array3& Kvis_u, Array3& Kvis_v) { - using MatNsd = mat_fun::Matrix; + // Alias the caller's storage; no copies. Svis, Kvis_u and Kvis_v are + // written in full below, so they are not zeroed first. + Eigen::Map> F_map(F.data()); + Eigen::Map> vx_map(vx.data()); + Eigen::Map> Nx_map(Nx.data(), nsd, eNoN); - // Initialize Svis, Kvis_u, Kvis_v to zero - Svis = 0.0; - Kvis_u = 0.0; - Kvis_v = 0.0; + // Get Jacobian and F^-1 + const double J = F_map.determinant(); + const double mu_J = mu * J; + const Matrix Fi = F_map.inverse(); - // Alias the caller's storage; no copies. - Eigen::Map F_map(F.data()); - Eigen::Map vx_map(vx.data()); - Eigen::Map> Nx_map(Nx.data(), nsd, eNoN); + // vx_Fi: Velocity gradient in current configuration + const Matrix vx_Fi = vx_map * Fi; + const Matrix vx_Fi_symm = mat_fun::mat_symm(vx_Fi); + // ddev: Deviatoric part of rate of strain tensor + const Matrix ddev = mat_fun::mat_dev(vx_Fi_symm); - const double J = F_map.determinant(); - const MatNsd Fi = F_map.inverse(); + // 2nd Piola-Kirchhoff stress due to viscosity, + // Svis = 2 * mu * J * F^-1 * d_dev * F^-T + Eigen::Map> Svis_map(Svis.data()); + Svis_map.noalias() = (2.0 * mu_J) * (Fi * ddev * Fi.transpose()); - // vx_Fi: velocity gradient in the current configuration. - const MatNsd vx_Fi = vx_map * Fi; - const MatNsd vx_Fi_symm = mat_fun::mat_symm(vx_Fi); - // ddev: deviatoric part of the rate of strain tensor. - const MatNsd ddev = mat_fun::mat_dev(vx_Fi_symm); + // The tangent scales every term by mu * J, so fold it in once here. + const Matrix mJ_vx_Fi = mu_J * vx_Fi; // Nx_Fi(i,a) = sum_j Nx(j,a) * Fi(j,i), which is Fi^T * Nx. - const MatNodes Nx_Fi = Fi.transpose() * Nx_map; - const MatNodes ddev_Nx_Fi = ddev * Nx_Fi; - const MatNodes vx_Fi_Nx_Fi = vx_Fi * Nx_Fi; - - // 2nd Piola-Kirchhoff stress due to viscosity, - // Svis = 2 * mu * J * F^-1 * d_dev * F^-T. Written straight into the - // caller's array, which it has already sized. - Eigen::Map Svis_map(Svis.data()); - Svis_map.noalias() = (2.0 * mu * J) * (Fi * ddev * Fi.transpose()); + const MatNodes Nx_Fi = Fi.transpose() * Nx_map; + const MatNodes mJ2_ddev_Nx_Fi = (2.0 * mu_J) * (ddev * Nx_Fi); + const MatNodes mJ_vx_Fi_Nx_Fi = mJ_vx_Fi * Nx_Fi; + const MatNodes mJ_Nx_Fi = mu_J * Nx_Fi; - // Tangent matrix contributions due to viscosity constexpr double r2d = 2.0 / nsd; - const MatNsd Idm = MatNsd::Identity(); for (int b = 0; b < eNoN; ++b) { for (int a = 0; a < eNoN; ++a) { @@ -1706,37 +1708,25 @@ void compute_visc_stress_newtonian_impl(const double mu, const int eNoN, const A int ii = i * nsd + j; // Derivative of the residual w.r.t displacement - Kvis_u(ii,a,b) = mu * J * (2.0 * - (ddev_Nx_Fi(i,a) * Nx_Fi(j,b) - ddev_Nx_Fi(i,b) * Nx_Fi(j,a)) - - (Nx_Fi_Nx_Fi * vx_Fi(i,j) + Nx_Fi(i,b) * vx_Fi_Nx_Fi(j,a) - - r2d * Nx_Fi(i,a) * vx_Fi_Nx_Fi(j,b))); + Kvis_u(ii,a,b) = (mJ2_ddev_Nx_Fi(i,a) * Nx_Fi(j,b) - + mJ2_ddev_Nx_Fi(i,b) * Nx_Fi(j,a)) - + (Nx_Fi_Nx_Fi * mJ_vx_Fi(i,j) + Nx_Fi(i,b) * mJ_vx_Fi_Nx_Fi(j,a) - + r2d * Nx_Fi(i,a) * mJ_vx_Fi_Nx_Fi(j,b)); // Derivative of the residual w.r.t velocity - Kvis_v(ii,a,b) = mu * J * (Nx_Fi_Nx_Fi * Idm(i,j) + - Nx_Fi(i,b) * Nx_Fi(j,a) - r2d * Nx_Fi(i,a) * Nx_Fi(j,b)); + Kvis_v(ii,a,b) = (i == j ? Nx_Fi_Nx_Fi * mu_J : 0.0) + + mJ_Nx_Fi(i,b) * Nx_Fi(j,a) - r2d * mJ_Nx_Fi(i,a) * Nx_Fi(j,b); } } } } } -/// @brief Dispatches on the spatial dimension. -void compute_visc_stress_newtonian(const double mu, const int eNoN, const Array& Nx, const Array& vx, const Array& F, - Array& Svis, Array3& Kvis_u, Array3& Kvis_v) { - if (F.nrows() == 3) { - compute_visc_stress_newtonian_impl<3>(mu, eNoN, Nx, vx, F, Svis, Kvis_u, Kvis_v); - } else if (F.nrows() == 2) { - compute_visc_stress_newtonian_impl<2>(mu, eNoN, Nx, vx, F, Svis, Kvis_u, Kvis_v); - } -} - - /** * @brief Get the solid viscous PK2 stress and corresponding tangent matrix contributions - * Calls the appropriate function based on the viscosity type, either viscous + * Calls the appropriate function based on the viscosity type, either viscous * pseudo-potential or Newtonian viscosity model. - * - * @tparam nsd Number of spatial dimensions + * * @param[in] lDmn Domain object * @param[in] eNoN Number of nodes in an element * @param[in] Nx Shape function gradient w.r.t. reference configuration coordinates (dN/dX) @@ -1751,11 +1741,19 @@ void compute_visc_stress_and_tangent(const dmnType& lDmn, const int eNoN, const switch (lDmn.solid_visc.viscType) { case consts::SolidViscosityModelType::viscType_Newtonian: - compute_visc_stress_newtonian(lDmn.solid_visc.mu, eNoN, Nx, vx, F, Svis, Kvis_u, Kvis_v); + if (F.nrows() == 3) { + compute_visc_stress_newtonian<3>(lDmn.solid_visc.mu, eNoN, Nx, vx, F, Svis, Kvis_u, Kvis_v); + } else if (F.nrows() == 2) { + compute_visc_stress_newtonian<2>(lDmn.solid_visc.mu, eNoN, Nx, vx, F, Svis, Kvis_u, Kvis_v); + } break; case consts::SolidViscosityModelType::viscType_Potential: - compute_visc_stress_potential(lDmn.solid_visc.mu, eNoN, Nx, vx, F, Svis, Kvis_u, Kvis_v); + if (F.nrows() == 3) { + compute_visc_stress_potential<3>(lDmn.solid_visc.mu, eNoN, Nx, vx, F, Svis, Kvis_u, Kvis_v); + } else if (F.nrows() == 2) { + compute_visc_stress_potential<2>(lDmn.solid_visc.mu, eNoN, Nx, vx, F, Svis, Kvis_u, Kvis_v); + } break; } } diff --git a/Code/Source/solver/mat_models.h b/Code/Source/solver/mat_models.h index 1e052274e..e74bc68bf 100644 --- a/Code/Source/solver/mat_models.h +++ b/Code/Source/solver/mat_models.h @@ -66,32 +66,17 @@ void compute_svol_p(const ComMod& com_mod, const CepMod& cep_mod, const stModelT void g_vol_pen(const ComMod& com_mod, const dmnType& lDmn, const double p, double& ro, double& bt, double& dro, double& dbt, const double Ja); -/// @brief Viscous 2nd Piola-Kirchhoff stress and tangent for a potential-based solid. -/// -/// Arguments are as for compute_visc_stress_newtonian(). -void compute_visc_stress_potential(const double mu, const int eNoN, const Array& Nx, const Array& vx, const Array& F, - Array& Svis, Array3& Kvis_u, Array3& Kvis_v); -/// @brief Viscous 2nd Piola-Kirchhoff stress and tangent for a Newtonian solid. +/// @brief Computes viscous PK2 stress and tangent +/// for the viscosity model configured for the domain. /// -/// @param[in] mu Dynamic viscosity. +/// @param[in] lDmn Domain, supplying the viscosity model and its parameters. /// @param[in] eNoN Number of element nodes. /// @param[in] Nx Shape function spatial derivatives. /// @param[in] vx Velocity gradient. /// @param[in] F Deformation gradient. /// @param[out] Svis Viscous 2nd Piola-Kirchhoff stress. /// @param[out] Kvis_u,Kvis_v Tangent contributions w.r.t. displacement and velocity. -void compute_visc_stress_newtonian(const double mu, const int eNoN, const Array& Nx, const Array& vx, const Array& F, - Array& Svis, Array3& Kvis_u, Array3& Kvis_v); - -/// @brief Dispatch to the viscosity model configured for the domain. -/// -/// Leaves @p Svis, @p Kvis_u and @p Kvis_v untouched when the domain has no -/// viscosity model, so callers must not rely on them being cleared here. -/// -/// @param[in] lDmn Domain, supplying the viscosity model and its parameters. -/// @param[in] eNoN,Nx,vx,F As for compute_visc_stress_newtonian(). -/// @param[out] Svis,Kvis_u,Kvis_v As for compute_visc_stress_newtonian(). void compute_visc_stress_and_tangent(const dmnType& lDmn, const int eNoN, const Array& Nx, const Array& vx, const Array& F, Array& Svis, Array3& Kvis_u, Array3& Kvis_v); }; From 990ccb574b4cfc58f7a5e95b2ebeb5293d575e4a Mon Sep 17 00:00:00 2001 From: dseyler Date: Wed, 2 Sep 2026 14:07:31 -0700 Subject: [PATCH 13/42] Reuse viscosity across gauss points for linear elements. lShpF corrected to false for wedge elements --- Code/Source/solver/fsi.cpp | 18 +++++++++++---- Code/Source/solver/mat_models.cpp | 18 ++++++++++++++- Code/Source/solver/mat_models.h | 4 +++- Code/Source/solver/nn_elem_props.h | 2 +- Code/Source/solver/sv_struct.cpp | 36 +++++++++++++++++------------- Code/Source/solver/sv_struct.h | 8 +++++-- Code/Source/solver/ustruct.cpp | 35 ++++++++++++++++------------- Code/Source/solver/ustruct.h | 8 +++++-- 8 files changed, 88 insertions(+), 41 deletions(-) diff --git a/Code/Source/solver/fsi.cpp b/Code/Source/solver/fsi.cpp index 4b7d32c13..cd64c7440 100644 --- a/Code/Source/solver/fsi.cpp +++ b/Code/Source/solver/fsi.cpp @@ -74,6 +74,11 @@ void construct_fsi(ComMod& com_mod, CepMod& cep_mod, const mshType& lM, const So std::array fs_1; fs::get_thood_fs(com_mod, fs_1, lM, vmsStab, 1); + // Viscous response for the solid element routines + Array Svis(nsd,nsd); + Array3 Kvis_u(nsd*nsd,fs_1[0].eNoN,fs_1[0].eNoN); + Array3 Kvis_v(nsd*nsd,fs_1[0].eNoN,fs_1[0].eNoN); + std::array fs_2; fs::get_thood_fs(com_mod, fs_2, lM, vmsStab, 2); @@ -186,7 +191,10 @@ void construct_fsi(ComMod& com_mod, CepMod& cep_mod, const mshType& lM, const So } } - if (g == 0 || !fs_1[0].lShpF) { + // Viscosity is constant at all Gauss points for linear elements + const bool recompute_visc = (g == 0 || !fs_1[0].lShpF); + + if (recompute_visc) { auto Nx = fs_1[0].Nx.rslice(g); nn::gnn(fs_1[0].eNoN, nsd, nsd, Nx, xwl, Nwx, Jac, ksix); if (utils::is_zero(Jac)) { @@ -220,7 +228,8 @@ void construct_fsi(ComMod& com_mod, CepMod& cep_mod, const mshType& lM, const So auto N0 = fs_1[0].N.col(g); struct_ns::struct_3d(com_mod, cep_mod, fs_1[0].eNoN, nFn, w, N0, Nwx, al, yl, dl, bfl, fN, pS0l, pSl, ya_l_f, - ya_l_s, ya_l_n, lR, lK); + ya_l_s, ya_l_n, lR, lK, + Svis, Kvis_u, Kvis_v, recompute_visc); } break; case Equation_lElas: throw std::runtime_error("[construct_fsi] LELAS3D not implemented"); @@ -233,7 +242,7 @@ void construct_fsi(ComMod& com_mod, CepMod& cep_mod, const mshType& lM, const So ustruct::ustruct_3d_m(com_mod, cep_mod, vmsStab, fs_1[0].eNoN, fs_1[1].eNoN, nFn, w, Jac, N0, N1, Nwx, al, yl, dl, bfl, fN, ya_l_f, ya_l_s, ya_l_n, lR, - lK, lKd); + lK, lKd, Svis, Kvis_u, Kvis_v, recompute_visc); break; } @@ -256,7 +265,8 @@ void construct_fsi(ComMod& com_mod, CepMod& cep_mod, const mshType& lM, const So auto N0 = fs_1[0].N.col(g); struct_ns::struct_2d(com_mod, cep_mod, fs_1[0].eNoN, nFn, w, N0, Nwx, al, yl, dl, bfl, fN, pS0l, pSl, ya_l_f, - ya_l_s, ya_l_n, lR, lK); + ya_l_s, ya_l_n, lR, lK, + Svis, Kvis_u, Kvis_v, recompute_visc); } break; case Equation_ustruct: diff --git a/Code/Source/solver/mat_models.cpp b/Code/Source/solver/mat_models.cpp index 191c4ed60..8cbd2d847 100644 --- a/Code/Source/solver/mat_models.cpp +++ b/Code/Source/solver/mat_models.cpp @@ -1737,10 +1737,15 @@ void compute_visc_stress_newtonian(const double mu, const int eNoN, const Array< * @param[out] Kvis_v Viscous tangent matrix contribution due to velocity */ void compute_visc_stress_and_tangent(const dmnType& lDmn, const int eNoN, const Array& Nx, const Array& vx, const Array& F, - Array& Svis, Array3& Kvis_u, Array3& Kvis_v) { + Array& Svis, Array3& Kvis_u, Array3& Kvis_v, + const bool recompute_visc) { switch (lDmn.solid_visc.viscType) { case consts::SolidViscosityModelType::viscType_Newtonian: + // Viscosity is constant at all Gauss points for linear elements + if (!recompute_visc) { + return; + } if (F.nrows() == 3) { compute_visc_stress_newtonian<3>(lDmn.solid_visc.mu, eNoN, Nx, vx, F, Svis, Kvis_u, Kvis_v); } else if (F.nrows() == 2) { @@ -1749,12 +1754,23 @@ void compute_visc_stress_and_tangent(const dmnType& lDmn, const int eNoN, const break; case consts::SolidViscosityModelType::viscType_Potential: + // Viscosity is constant at all Gauss points for linear elements + if (!recompute_visc) { + return; + } if (F.nrows() == 3) { compute_visc_stress_potential<3>(lDmn.solid_visc.mu, eNoN, Nx, vx, F, Svis, Kvis_u, Kvis_v); } else if (F.nrows() == 2) { compute_visc_stress_potential<2>(lDmn.solid_visc.mu, eNoN, Nx, vx, F, Svis, Kvis_u, Kvis_v); } break; + + default: + // No viscosity model for this domain. + Svis = 0.0; + Kvis_u = 0.0; + Kvis_v = 0.0; + break; } } diff --git a/Code/Source/solver/mat_models.h b/Code/Source/solver/mat_models.h index e74bc68bf..a5524fbb9 100644 --- a/Code/Source/solver/mat_models.h +++ b/Code/Source/solver/mat_models.h @@ -77,8 +77,10 @@ void g_vol_pen(const ComMod& com_mod, const dmnType& lDmn, const double p, /// @param[in] F Deformation gradient. /// @param[out] Svis Viscous 2nd Piola-Kirchhoff stress. /// @param[out] Kvis_u,Kvis_v Tangent contributions w.r.t. displacement and velocity. +/// @param[in] recompute False when the outputs are still valid from the previous call. void compute_visc_stress_and_tangent(const dmnType& lDmn, const int eNoN, const Array& Nx, const Array& vx, const Array& F, - Array& Svis, Array3& Kvis_u, Array3& Kvis_v); + Array& Svis, Array3& Kvis_u, Array3& Kvis_v, + const bool recompute_visc); }; #endif diff --git a/Code/Source/solver/nn_elem_props.h b/Code/Source/solver/nn_elem_props.h index 7dc89e380..f63cc9243 100644 --- a/Code/Source/solver/nn_elem_props.h +++ b/Code/Source/solver/nn_elem_props.h @@ -25,7 +25,7 @@ SetElementPropsMapType set_3d_element_props = { mesh.nG = 6; mesh.vtkType = 13; mesh.nEf = 3; - mesh.lShpF = true; + mesh.lShpF = false; } }, diff --git a/Code/Source/solver/sv_struct.cpp b/Code/Source/solver/sv_struct.cpp index 561ee73b5..7ddd5077e 100644 --- a/Code/Source/solver/sv_struct.cpp +++ b/Code/Source/solver/sv_struct.cpp @@ -229,6 +229,9 @@ void construct_dsolid(ComMod& com_mod, CepMod& cep_mod, const mshType& lM, const bfl(nsd,eNoN), fN(nsd,nFn), pS0l(nsymd,eNoN), Nx(nsd,eNoN), lR(dof,eNoN); Array3 lK(dof*dof,eNoN,eNoN); + Array Svis(nsd,nsd); + Array3 Kvis_u(nsd*nsd,eNoN,eNoN), Kvis_v(nsd*nsd,eNoN,eNoN); + // Loop over all elements of mesh for (int e = 0; e < lM.nEl; e++) { @@ -294,7 +297,10 @@ void construct_dsolid(ComMod& com_mod, CepMod& cep_mod, const mshType& lM, const Array ksix(nsd,nsd); for (int g = 0; g < lM.nG; g++) { - if (g == 0 || !lM.lShpF) { + // Viscosity is constant at all Gauss points for linear elements + const bool recompute_visc = (g == 0 || !lM.lShpF); + + if (recompute_visc) { auto Nx_g = lM.Nx.slice(g); nn::gnn(eNoN, nsd, nsd, Nx_g, xl, Nx, Jac, ksix); if (utils::is_zero(Jac)) { @@ -307,7 +313,8 @@ void construct_dsolid(ComMod& com_mod, CepMod& cep_mod, const mshType& lM, const if (nsd == 3) { struct_3d(com_mod, cep_mod, eNoN, nFn, w, N, Nx, al, yl, dl, bfl, fN, - pS0l, pSl, ya_l_f, ya_l_s, ya_l_n, lR, lK); + pS0l, pSl, ya_l_f, ya_l_s, ya_l_n, lR, lK, + Svis, Kvis_u, Kvis_v, recompute_visc); #if 0 if (e == 0 && g == 0) { @@ -321,7 +328,8 @@ void construct_dsolid(ComMod& com_mod, CepMod& cep_mod, const mshType& lM, const } else if (nsd == 2) { struct_2d(com_mod, cep_mod, eNoN, nFn, w, N, Nx, al, yl, dl, bfl, fN, - pS0l, pSl, ya_l_f, ya_l_s, ya_l_n, lR, lK); + pS0l, pSl, ya_l_f, ya_l_s, ya_l_n, lR, lK, + Svis, Kvis_u, Kvis_v, recompute_visc); } // Prestress @@ -349,7 +357,9 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, const Array &fN, const Array &pS0l, Vector &pSl, const Vector &ya_l_f, const Vector &ya_l_s, const Vector &ya_l_n, - Array &lR, Array3 &lK) { + Array &lR, Array3 &lK, + Array &Svis, Array3 &Kvis_u, Array3 &Kvis_v, + const bool recompute_visc) { using namespace consts; using namespace mat_fun; @@ -440,11 +450,8 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, ya_g_n, S, Dm, Ja); // Viscous 2nd Piola-Kirchhoff stress and tangent contributions - Array Svis(2,2); - Array3 Kvis_u(4, eNoN, eNoN); - Array3 Kvis_v(4, eNoN, eNoN); - - mat_models::compute_visc_stress_and_tangent(dmn, eNoN, Nx, vx, F, Svis, Kvis_u, Kvis_v); + mat_models::compute_visc_stress_and_tangent(dmn, eNoN, Nx, vx, F, Svis, Kvis_u, Kvis_v, + recompute_visc); // Elastic + Viscous stresses S = S + Svis; @@ -545,7 +552,9 @@ void struct_3d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, const Array &fN, const Array &pS0l, Vector &pSl, const Vector &ya_l_f, const Vector &ya_l_s, const Vector &ya_l_n, - Array &lR, Array3 &lK) { + Array &lR, Array3 &lK, + Array &Svis, Array3 &Kvis_u, Array3 &Kvis_v, + const bool recompute_visc) { using namespace consts; using namespace mat_fun; @@ -659,11 +668,8 @@ void struct_3d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, ya_g_n, S, Dm, Ja); // Viscous 2nd Piola-Kirchhoff stress and tangent contributions - Array Svis(3,3); - Array3 Kvis_u(9, eNoN, eNoN); - Array3 Kvis_v(9, eNoN, eNoN); - - mat_models::compute_visc_stress_and_tangent(dmn, eNoN, Nx, vx, F, Svis, Kvis_u, Kvis_v); + mat_models::compute_visc_stress_and_tangent(dmn, eNoN, Nx, vx, F, Svis, Kvis_u, Kvis_v, + recompute_visc); // Elastic + Viscous stresses S = S + Svis; diff --git a/Code/Source/solver/sv_struct.h b/Code/Source/solver/sv_struct.h index a0018305c..ae8f1590b 100644 --- a/Code/Source/solver/sv_struct.h +++ b/Code/Source/solver/sv_struct.h @@ -26,7 +26,9 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, const Array &fN, const Array &pS0l, Vector &pSl, const Vector &ya_l_f, const Vector &ya_l_s, const Vector &ya_l_n, - Array &lR, Array3 &lK); + Array &lR, Array3 &lK, + Array &Svis, Array3 &Kvis_u, Array3 &Kvis_v, + const bool recompute_visc); void struct_3d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, const double w, const Vector &N, const Array &Nx, @@ -35,7 +37,9 @@ void struct_3d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, const Array &fN, const Array &pS0l, Vector &pSl, const Vector &ya_l_f, const Vector &ya_l_s, const Vector &ya_l_n, - Array &lR, Array3 &lK); + Array &lR, Array3 &lK, + Array &Svis, Array3 &Kvis_u, Array3 &Kvis_v, + const bool recompute_visc); }; #endif diff --git a/Code/Source/solver/ustruct.cpp b/Code/Source/solver/ustruct.cpp index a698050e7..d5e690f0c 100644 --- a/Code/Source/solver/ustruct.cpp +++ b/Code/Source/solver/ustruct.cpp @@ -313,6 +313,10 @@ void construct_usolid(ComMod& com_mod, CepMod& cep_mod, const mshType& lM, const Array xql(nsd,fs[1].eNoN); Array Nqx(nsd,fs[1].eNoN); + Array Svis(nsd,nsd); + Array3 Kvis_u(nsd*nsd,fs[0].eNoN,fs[0].eNoN); + Array3 Kvis_v(nsd*nsd,fs[0].eNoN,fs[0].eNoN); + xwl = xl; for (int i = 0; i < nsd; i++) { @@ -327,7 +331,10 @@ void construct_usolid(ComMod& com_mod, CepMod& cep_mod, const mshType& lM, const Array ksix(nsd,nsd); for (int g = 0; g < fs[0].nG; g++) { - if (g == 0 || !fs[0].lShpF) { + // Viscosity is constant at all Gauss points for linear elements. + const bool recompute_visc = (g == 0 || !fs[0].lShpF); + + if (recompute_visc) { auto Nx = fs[0].Nx.slice(g); nn::gnn(fs[0].eNoN, nsd, nsd, Nx, xwl, Nwx, Jac, ksix); if (utils::is_zero(Jac)) { @@ -342,14 +349,14 @@ void construct_usolid(ComMod& com_mod, CepMod& cep_mod, const mshType& lM, const auto N1 = fs[1].N.col(g); ustruct_3d_m(com_mod, cep_mod, vmsStab, fs[0].eNoN, fs[1].eNoN, nFn, w, Jac, N0, N1, Nwx, al, yl, dl, bfl, fN, ya_l_f, ya_l_s, - ya_l_n, lR, lK, lKd); + ya_l_n, lR, lK, lKd, Svis, Kvis_u, Kvis_v, recompute_visc); } else if (nsd == 2) { auto N0 = fs[0].N.col(g); auto N1 = fs[1].N.col(g); ustruct_2d_m(com_mod, cep_mod, vmsStab, fs[0].eNoN, fs[1].eNoN, nFn, w, Jac, N0, N1, Nwx, al, yl, dl, bfl, fN, ya_l_f, ya_l_s, - ya_l_n, lR, lK, lKd); + ya_l_n, lR, lK, lKd, Svis, Kvis_u, Kvis_v, recompute_visc); } } // for g = 0 to fs[0].nG @@ -880,7 +887,9 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, const Array &dl, const Array &bfl, const Array &fN, const Vector &ya_l_f, const Vector &ya_l_s, const Vector &ya_l_n, - Array &lR, Array3 &lK, Array3 &lKd) { + Array &lR, Array3 &lK, Array3 &lKd, + Array &Svis, Array3 &Kvis_u, Array3 &Kvis_v, + const bool recompute_visc) { using namespace consts; using namespace mat_fun; @@ -978,11 +987,8 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, ya_g_s, ya_g_n, Siso, Dm, Ja); // Viscous 2nd Piola-Kirchhoff stress and tangent contributions - Array Svis(2,2); - Array3 Kvis_u(4, eNoNw, eNoNw); - Array3 Kvis_v(4, eNoNw, eNoNw); - - mat_models::compute_visc_stress_and_tangent(dmn, eNoNw, Nwx, vx, F, Svis, Kvis_u, Kvis_v); + mat_models::compute_visc_stress_and_tangent(dmn, eNoNw, Nwx, vx, F, Svis, Kvis_u, Kvis_v, + recompute_visc); // Compute rho and beta depending on the volumetric penalty model // @@ -1170,7 +1176,9 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, const Array &dl, const Array &bfl, const Array &fN, const Vector &ya_l_f, const Vector &ya_l_s, const Vector &ya_l_n, - Array &lR, Array3 &lK, Array3 &lKd) { + Array &lR, Array3 &lK, Array3 &lKd, + Array &Svis, Array3 &Kvis_u, Array3 &Kvis_v, + const bool recompute_visc) { using namespace consts; using namespace mat_fun; @@ -1289,11 +1297,8 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, ya_g_s, ya_g_n, Siso, Dm, Ja); // Viscous 2nd Piola-Kirchhoff stress and tangent contributions - Array Svis(3,3); - Array3 Kvis_u(9, eNoNw, eNoNw); - Array3 Kvis_v(9, eNoNw, eNoNw); - - mat_models::compute_visc_stress_and_tangent(dmn, eNoNw, Nwx, vx, F, Svis, Kvis_u, Kvis_v); + mat_models::compute_visc_stress_and_tangent(dmn, eNoNw, Nwx, vx, F, Svis, Kvis_u, Kvis_v, + recompute_visc); // Compute rho and beta depending on the volumetric penalty model diff --git a/Code/Source/solver/ustruct.h b/Code/Source/solver/ustruct.h index 953d4d035..611cb6a79 100644 --- a/Code/Source/solver/ustruct.h +++ b/Code/Source/solver/ustruct.h @@ -37,7 +37,9 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, const Array &dl, const Array &bfl, const Array &fN, const Vector &ya_l_f, const Vector &ya_l_s, const Vector &ya_l_n, - Array &lR, Array3 &lK, Array3 &lKd); + Array &lR, Array3 &lK, Array3 &lKd, + Array &Svis, Array3 &Kvis_u, Array3 &Kvis_v, + const bool recompute_visc); void ustruct_3d_c(ComMod& com_mod, CepMod& cep_mod, const bool vmsFlag, const int eNoNw, const int eNoNq, const double w, const double Je, const Vector& Nw, const Vector& Nq, @@ -53,7 +55,9 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, const Array &dl, const Array &bfl, const Array &fN, const Vector &ya_l_f, const Vector &ya_l_s, const Vector &ya_l_n, - Array &lR, Array3 &lK, Array3 &lKd); + Array &lR, Array3 &lK, Array3 &lKd, + Array &Svis, Array3 &Kvis_u, Array3 &Kvis_v, + const bool recompute_visc); void ustruct_do_assem(ComMod& com_mod, const int d, const Vector& eqN, const Array3& lKd, const Array3& lK, const Array& lR); From f0e2ac0cd9a22cbb63c55d27acac635043617363 Mon Sep 17 00:00:00 2001 From: dseyler Date: Fri, 4 Sep 2026 11:35:03 -0700 Subject: [PATCH 14/42] Reverted minor optimizations that made code less readable --- Code/Source/solver/mat_models.cpp | 92 +++++++++++++++---------------- 1 file changed, 43 insertions(+), 49 deletions(-) diff --git a/Code/Source/solver/mat_models.cpp b/Code/Source/solver/mat_models.cpp index 8cbd2d847..4942e0f57 100644 --- a/Code/Source/solver/mat_models.cpp +++ b/Code/Source/solver/mat_models.cpp @@ -1564,9 +1564,9 @@ namespace { /// @brief Largest element node count the fixed-size views below allow (HEX27). constexpr int MAX_ELEMENT_NODES = 27; -/// @brief An nsd x eNoN matrix whose column count is bounded at compile time. +/// @brief A quantity carrying one nsd-vector per element node, so nsd x eNoN. template -using MatNodes = Eigen::Matrix; +using NodalMatrix = Eigen::Matrix; } // namespace @@ -1600,45 +1600,44 @@ void compute_visc_stress_potential(const double mu, const int eNoN, const Array< // written in full below, so they are not zeroed first. Eigen::Map> F_map(F.data()); Eigen::Map> vx_map(vx.data()); - Eigen::Map> Nx_map(Nx.data(), nsd, eNoN); + Eigen::Map> Nx_map(Nx.data(), nsd, eNoN); + // Required intermediate terms for stress and tangent + const Matrix F_Ft = F_map * F_map.transpose(); const Matrix Ft_vx = F_map.transpose() * vx_map; + const Matrix F_vxt = F_map * vx_map.transpose(); - // 2nd Piola-Kirchhoff stress due to viscosity, + // F_Nx(i,a) = sum_j F(i,j) * Nx(j,a), and likewise for vx. + const NodalMatrix F_Nx = F_map * Nx_map; + const NodalMatrix vx_Nx = vx_map * Nx_map; + + // 2nd Piola-Kirchhoff stress due to viscosity // Svis = mu * 1/2 * ( (F^T * dv/dX) + (F^T * dv/dX)^T ) Eigen::Map> Svis_map(Svis.data()); Svis_map.noalias() = mu * mat_fun::mat_symm(Ft_vx); - // The tangent scales every term by 1/2 mu, so fold it in once here rather - // than repeating it for every node pair and component. - const Matrix hF_Ft = (0.5 * mu) * (F_map * F_map.transpose()); - const Matrix hF_vxt = (0.5 * mu) * (F_map * vx_map.transpose()); - - // F_Nx(i,a) = sum_j F(i,j) * Nx(j,a), and likewise for vx. - const MatNodes F_Nx = F_map * Nx_map; - const MatNodes vx_Nx = vx_map * Nx_map; - const MatNodes hF_Nx = (0.5 * mu) * F_Nx; - - // Kvis stores the nsd^2 components at a node pair contiguously, indexed by - // ii = i*nsd + j, so each pair's block is a row major nsd x nsd matrix - using KvisBlock = Eigen::Matrix; - + // Tangent matrix contributions due to viscosity for (int b = 0; b < eNoN; ++b) { for (int a = 0; a < eNoN; ++a) { - const double Nx_Nx = Nx_map.col(a).dot(Nx_map.col(b)); - - Eigen::Map Kvis_u_ab(&Kvis_u(0,a,b)); - Eigen::Map Kvis_v_ab(&Kvis_v(0,a,b)); + double Nx_Nx = 0.0; + for (int i = 0; i < nsd; ++i) { + Nx_Nx += Nx(i,a) * Nx(i,b); + } - Kvis_u_ab.noalias() = hF_Nx.col(b) * vx_Nx.col(a).transpose() + Nx_Nx * hF_vxt; - Kvis_v_ab.noalias() = Nx_Nx * hF_Ft + hF_Nx.col(b) * F_Nx.col(a).transpose(); + for (int i = 0; i < nsd; ++i) { + for (int j = 0; j < nsd; ++j) { + int ii = i * nsd + j; + Kvis_u(ii,a,b) = 0.5 * mu * (F_Nx(i,b) * vx_Nx(j,a) + Nx_Nx * F_vxt(i,j)); + Kvis_v(ii,a,b) = 0.5 * mu * (Nx_Nx * F_Ft(i,j) + F_Nx(i,b) * F_Nx(j,a)); + } + } } } } /** - * @brief Viscous PK2 stress and tangent contributions for a solid with a - * Newtonian fluid-like viscosity model. + * @brief Get the viscous PK2 stress and corresponding tangent matrix contributions for a solid + * with a Newtonian fluid-like viscosity model. * * The viscous deviatoric Cauchy stress is given by * sigma_vis_dev = 2 * mu * d_dev @@ -1663,15 +1662,14 @@ template void compute_visc_stress_newtonian(const double mu, const int eNoN, const Array& Nx, const Array& vx, const Array& F, Array& Svis, Array3& Kvis_u, Array3& Kvis_v) { - // Alias the caller's storage; no copies. Svis, Kvis_u and Kvis_v are - // written in full below, so they are not zeroed first. + Eigen::Map> F_map(F.data()); Eigen::Map> vx_map(vx.data()); - Eigen::Map> Nx_map(Nx.data(), nsd, eNoN); + Eigen::Map> Nx_map(Nx.data(), nsd, eNoN); - // Get Jacobian and F^-1 + // Get identity matrix, Jacobian, and F^-1 + const auto Idm = Matrix::Identity(); const double J = F_map.determinant(); - const double mu_J = mu * J; const Matrix Fi = F_map.inverse(); // vx_Fi: Velocity gradient in current configuration @@ -1680,22 +1678,18 @@ void compute_visc_stress_newtonian(const double mu, const int eNoN, const Array< // ddev: Deviatoric part of rate of strain tensor const Matrix ddev = mat_fun::mat_dev(vx_Fi_symm); - // 2nd Piola-Kirchhoff stress due to viscosity, + // Nx_Fi(i,a) = sum_j Nx(j,a) * Fi(j,i), which is Fi^T * Nx. + const NodalMatrix Nx_Fi = Fi.transpose() * Nx_map; + const NodalMatrix ddev_Nx_Fi = ddev * Nx_Fi; + const NodalMatrix vx_Fi_Nx_Fi = vx_Fi * Nx_Fi; + + // 2nd Piola-Kirchhoff stress due to viscosity // Svis = 2 * mu * J * F^-1 * d_dev * F^-T Eigen::Map> Svis_map(Svis.data()); - Svis_map.noalias() = (2.0 * mu_J) * (Fi * ddev * Fi.transpose()); - - // The tangent scales every term by mu * J, so fold it in once here. - const Matrix mJ_vx_Fi = mu_J * vx_Fi; - - // Nx_Fi(i,a) = sum_j Nx(j,a) * Fi(j,i), which is Fi^T * Nx. - const MatNodes Nx_Fi = Fi.transpose() * Nx_map; - const MatNodes mJ2_ddev_Nx_Fi = (2.0 * mu_J) * (ddev * Nx_Fi); - const MatNodes mJ_vx_Fi_Nx_Fi = mJ_vx_Fi * Nx_Fi; - const MatNodes mJ_Nx_Fi = mu_J * Nx_Fi; + Svis_map.noalias() = (2.0 * mu * J) * (Fi * ddev * Fi.transpose()); + // Tangent matrix contributions due to viscosity constexpr double r2d = 2.0 / nsd; - for (int b = 0; b < eNoN; ++b) { for (int a = 0; a < eNoN; ++a) { double Nx_Fi_Nx_Fi = 0.0; @@ -1708,14 +1702,14 @@ void compute_visc_stress_newtonian(const double mu, const int eNoN, const Array< int ii = i * nsd + j; // Derivative of the residual w.r.t displacement - Kvis_u(ii,a,b) = (mJ2_ddev_Nx_Fi(i,a) * Nx_Fi(j,b) - - mJ2_ddev_Nx_Fi(i,b) * Nx_Fi(j,a)) - - (Nx_Fi_Nx_Fi * mJ_vx_Fi(i,j) + Nx_Fi(i,b) * mJ_vx_Fi_Nx_Fi(j,a) - - r2d * Nx_Fi(i,a) * mJ_vx_Fi_Nx_Fi(j,b)); + Kvis_u(ii,a,b) = mu * J * (2.0 * + (ddev_Nx_Fi(i,a) * Nx_Fi(j,b) - ddev_Nx_Fi(i,b) * Nx_Fi(j,a)) - + (Nx_Fi_Nx_Fi * vx_Fi(i,j) + Nx_Fi(i,b) * vx_Fi_Nx_Fi(j,a) - + r2d * Nx_Fi(i,a) * vx_Fi_Nx_Fi(j,b))); // Derivative of the residual w.r.t velocity - Kvis_v(ii,a,b) = (i == j ? Nx_Fi_Nx_Fi * mu_J : 0.0) + - mJ_Nx_Fi(i,b) * Nx_Fi(j,a) - r2d * mJ_Nx_Fi(i,a) * Nx_Fi(j,b); + Kvis_v(ii,a,b) = mu * J * (Nx_Fi_Nx_Fi * Idm(i,j) + + Nx_Fi(i,b) * Nx_Fi(j,a) - r2d * Nx_Fi(i,a) * Nx_Fi(j,b)); } } } From 8e25ed23e56b008537d65bd84081bc972e90d937 Mon Sep 17 00:00:00 2001 From: dseyler Date: Thu, 17 Sep 2026 11:24:32 -0700 Subject: [PATCH 15/42] Declare viscous buffers as statics. Moved viscosity models into anonynous namespace. Improved comments --- Code/Source/solver/fsi.cpp | 17 ++++++----------- Code/Source/solver/mat_fun.h | 4 ++-- Code/Source/solver/mat_models.cpp | 10 ++++++---- Code/Source/solver/sv_struct.cpp | 29 +++++++++++++++++++---------- Code/Source/solver/sv_struct.h | 2 -- Code/Source/solver/ustruct.cpp | 28 +++++++++++++++++++--------- Code/Source/solver/ustruct.h | 2 -- 7 files changed, 52 insertions(+), 40 deletions(-) diff --git a/Code/Source/solver/fsi.cpp b/Code/Source/solver/fsi.cpp index cd64c7440..c79ea24f2 100644 --- a/Code/Source/solver/fsi.cpp +++ b/Code/Source/solver/fsi.cpp @@ -74,11 +74,6 @@ void construct_fsi(ComMod& com_mod, CepMod& cep_mod, const mshType& lM, const So std::array fs_1; fs::get_thood_fs(com_mod, fs_1, lM, vmsStab, 1); - // Viscous response for the solid element routines - Array Svis(nsd,nsd); - Array3 Kvis_u(nsd*nsd,fs_1[0].eNoN,fs_1[0].eNoN); - Array3 Kvis_v(nsd*nsd,fs_1[0].eNoN,fs_1[0].eNoN); - std::array fs_2; fs::get_thood_fs(com_mod, fs_2, lM, vmsStab, 2); @@ -191,7 +186,9 @@ void construct_fsi(ComMod& com_mod, CepMod& cep_mod, const mshType& lM, const So } } - // Viscosity is constant at all Gauss points for linear elements + // Shape function gradients and the viscous response, are constant + // within linear simplex elements (tetrahedra, triangles). Bi- and + // trilinear hexahedra are sometimes called linear but do not qualify. const bool recompute_visc = (g == 0 || !fs_1[0].lShpF); if (recompute_visc) { @@ -228,8 +225,7 @@ void construct_fsi(ComMod& com_mod, CepMod& cep_mod, const mshType& lM, const So auto N0 = fs_1[0].N.col(g); struct_ns::struct_3d(com_mod, cep_mod, fs_1[0].eNoN, nFn, w, N0, Nwx, al, yl, dl, bfl, fN, pS0l, pSl, ya_l_f, - ya_l_s, ya_l_n, lR, lK, - Svis, Kvis_u, Kvis_v, recompute_visc); + ya_l_s, ya_l_n, lR, lK, recompute_visc); } break; case Equation_lElas: throw std::runtime_error("[construct_fsi] LELAS3D not implemented"); @@ -242,7 +238,7 @@ void construct_fsi(ComMod& com_mod, CepMod& cep_mod, const mshType& lM, const So ustruct::ustruct_3d_m(com_mod, cep_mod, vmsStab, fs_1[0].eNoN, fs_1[1].eNoN, nFn, w, Jac, N0, N1, Nwx, al, yl, dl, bfl, fN, ya_l_f, ya_l_s, ya_l_n, lR, - lK, lKd, Svis, Kvis_u, Kvis_v, recompute_visc); + lK, lKd, recompute_visc); break; } @@ -265,8 +261,7 @@ void construct_fsi(ComMod& com_mod, CepMod& cep_mod, const mshType& lM, const So auto N0 = fs_1[0].N.col(g); struct_ns::struct_2d(com_mod, cep_mod, fs_1[0].eNoN, nFn, w, N0, Nwx, al, yl, dl, bfl, fN, pS0l, pSl, ya_l_f, - ya_l_s, ya_l_n, lR, lK, - Svis, Kvis_u, Kvis_v, recompute_visc); + ya_l_s, ya_l_n, lR, lK, recompute_visc); } break; case Equation_ustruct: diff --git a/Code/Source/solver/mat_fun.h b/Code/Source/solver/mat_fun.h index d4b58a500..cd3fb88ed 100644 --- a/Code/Source/solver/mat_fun.h +++ b/Code/Source/solver/mat_fun.h @@ -176,7 +176,7 @@ namespace mat_fun { * Fixed-size overload for the Eigen matrices used by the element kernels. * * @tparam nsd Number of spatial dimensions. - * @param[in] A Second order tensor. + * @param[in] A second order tensor. * @return The symmetric part of A. */ template @@ -190,7 +190,7 @@ namespace mat_fun { * Fixed-size overload for the Eigen matrices used by the element kernels. * * @tparam nsd Number of spatial dimensions. - * @param[in] A Second order tensor. + * @param[in] A second order tensor. * @return The deviatoric part of A. */ template diff --git a/Code/Source/solver/mat_models.cpp b/Code/Source/solver/mat_models.cpp index 4942e0f57..db210b9e2 100644 --- a/Code/Source/solver/mat_models.cpp +++ b/Code/Source/solver/mat_models.cpp @@ -1568,8 +1568,6 @@ constexpr int MAX_ELEMENT_NODES = 27; template using NodalMatrix = Eigen::Matrix; -} // namespace - /** * @brief Viscous PK2 stress and tangent contributions for the viscous * pseudo-potential model. @@ -1716,6 +1714,8 @@ void compute_visc_stress_newtonian(const double mu, const int eNoN, const Array< } } +} // namespace + /** * @brief Get the solid viscous PK2 stress and corresponding tangent matrix contributions * Calls the appropriate function based on the viscosity type, either viscous @@ -1736,7 +1736,8 @@ void compute_visc_stress_and_tangent(const dmnType& lDmn, const int eNoN, const switch (lDmn.solid_visc.viscType) { case consts::SolidViscosityModelType::viscType_Newtonian: - // Viscosity is constant at all Gauss points for linear elements + // Constant at all Gauss points for linear simplex elements (triangle / tetrahedra), + // so the caller can ask for the previous result to be kept. if (!recompute_visc) { return; } @@ -1748,7 +1749,8 @@ void compute_visc_stress_and_tangent(const dmnType& lDmn, const int eNoN, const break; case consts::SolidViscosityModelType::viscType_Potential: - // Viscosity is constant at all Gauss points for linear elements + // Constant at all Gauss points for linear simplex elements (triangle / tetrahedra), + // so the caller can ask for the previous result to be kept. if (!recompute_visc) { return; } diff --git a/Code/Source/solver/sv_struct.cpp b/Code/Source/solver/sv_struct.cpp index 7ddd5077e..56a1619d1 100644 --- a/Code/Source/solver/sv_struct.cpp +++ b/Code/Source/solver/sv_struct.cpp @@ -229,9 +229,6 @@ void construct_dsolid(ComMod& com_mod, CepMod& cep_mod, const mshType& lM, const bfl(nsd,eNoN), fN(nsd,nFn), pS0l(nsymd,eNoN), Nx(nsd,eNoN), lR(dof,eNoN); Array3 lK(dof*dof,eNoN,eNoN); - Array Svis(nsd,nsd); - Array3 Kvis_u(nsd*nsd,eNoN,eNoN), Kvis_v(nsd*nsd,eNoN,eNoN); - // Loop over all elements of mesh for (int e = 0; e < lM.nEl; e++) { @@ -297,7 +294,9 @@ void construct_dsolid(ComMod& com_mod, CepMod& cep_mod, const mshType& lM, const Array ksix(nsd,nsd); for (int g = 0; g < lM.nG; g++) { - // Viscosity is constant at all Gauss points for linear elements + // Shape function gradients and the viscous response are constant + // within linear simplex elements (tetrahedra, triangles). Bi- and + // trilinear hexahedra are sometimes called linear but do not qualify. const bool recompute_visc = (g == 0 || !lM.lShpF); if (recompute_visc) { @@ -313,8 +312,7 @@ void construct_dsolid(ComMod& com_mod, CepMod& cep_mod, const mshType& lM, const if (nsd == 3) { struct_3d(com_mod, cep_mod, eNoN, nFn, w, N, Nx, al, yl, dl, bfl, fN, - pS0l, pSl, ya_l_f, ya_l_s, ya_l_n, lR, lK, - Svis, Kvis_u, Kvis_v, recompute_visc); + pS0l, pSl, ya_l_f, ya_l_s, ya_l_n, lR, lK, recompute_visc); #if 0 if (e == 0 && g == 0) { @@ -328,8 +326,7 @@ void construct_dsolid(ComMod& com_mod, CepMod& cep_mod, const mshType& lM, const } else if (nsd == 2) { struct_2d(com_mod, cep_mod, eNoN, nFn, w, N, Nx, al, yl, dl, bfl, fN, - pS0l, pSl, ya_l_f, ya_l_s, ya_l_n, lR, lK, - Svis, Kvis_u, Kvis_v, recompute_visc); + pS0l, pSl, ya_l_f, ya_l_s, ya_l_n, lR, lK, recompute_visc); } // Prestress @@ -358,7 +355,6 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, Vector &pSl, const Vector &ya_l_f, const Vector &ya_l_s, const Vector &ya_l_n, Array &lR, Array3 &lK, - Array &Svis, Array3 &Kvis_u, Array3 &Kvis_v, const bool recompute_visc) { using namespace consts; using namespace mat_fun; @@ -450,6 +446,13 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, ya_g_n, S, Dm, Ja); // Viscous 2nd Piola-Kirchhoff stress and tangent contributions + static Array Svis(2,2); + static Array3 Kvis_u, Kvis_v; + if (Kvis_u.ncols() != eNoN) { + Kvis_u.resize(4, eNoN, eNoN); + Kvis_v.resize(4, eNoN, eNoN); + } + mat_models::compute_visc_stress_and_tangent(dmn, eNoN, Nx, vx, F, Svis, Kvis_u, Kvis_v, recompute_visc); @@ -553,7 +556,6 @@ void struct_3d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, Vector &pSl, const Vector &ya_l_f, const Vector &ya_l_s, const Vector &ya_l_n, Array &lR, Array3 &lK, - Array &Svis, Array3 &Kvis_u, Array3 &Kvis_v, const bool recompute_visc) { using namespace consts; using namespace mat_fun; @@ -668,6 +670,13 @@ void struct_3d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, ya_g_n, S, Dm, Ja); // Viscous 2nd Piola-Kirchhoff stress and tangent contributions + static Array Svis(3,3); + static Array3 Kvis_u, Kvis_v; + if (Kvis_u.ncols() != eNoN) { + Kvis_u.resize(9, eNoN, eNoN); + Kvis_v.resize(9, eNoN, eNoN); + } + mat_models::compute_visc_stress_and_tangent(dmn, eNoN, Nx, vx, F, Svis, Kvis_u, Kvis_v, recompute_visc); diff --git a/Code/Source/solver/sv_struct.h b/Code/Source/solver/sv_struct.h index ae8f1590b..d9ae855ff 100644 --- a/Code/Source/solver/sv_struct.h +++ b/Code/Source/solver/sv_struct.h @@ -27,7 +27,6 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, Vector &pSl, const Vector &ya_l_f, const Vector &ya_l_s, const Vector &ya_l_n, Array &lR, Array3 &lK, - Array &Svis, Array3 &Kvis_u, Array3 &Kvis_v, const bool recompute_visc); void struct_3d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, @@ -38,7 +37,6 @@ void struct_3d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, Vector &pSl, const Vector &ya_l_f, const Vector &ya_l_s, const Vector &ya_l_n, Array &lR, Array3 &lK, - Array &Svis, Array3 &Kvis_u, Array3 &Kvis_v, const bool recompute_visc); }; diff --git a/Code/Source/solver/ustruct.cpp b/Code/Source/solver/ustruct.cpp index d5e690f0c..432982e8f 100644 --- a/Code/Source/solver/ustruct.cpp +++ b/Code/Source/solver/ustruct.cpp @@ -313,10 +313,6 @@ void construct_usolid(ComMod& com_mod, CepMod& cep_mod, const mshType& lM, const Array xql(nsd,fs[1].eNoN); Array Nqx(nsd,fs[1].eNoN); - Array Svis(nsd,nsd); - Array3 Kvis_u(nsd*nsd,fs[0].eNoN,fs[0].eNoN); - Array3 Kvis_v(nsd*nsd,fs[0].eNoN,fs[0].eNoN); - xwl = xl; for (int i = 0; i < nsd; i++) { @@ -331,7 +327,9 @@ void construct_usolid(ComMod& com_mod, CepMod& cep_mod, const mshType& lM, const Array ksix(nsd,nsd); for (int g = 0; g < fs[0].nG; g++) { - // Viscosity is constant at all Gauss points for linear elements. + // Shape function gradients and the viscous response are constant + // within linear simplex elements (tetrahedra, triangles). Bi- and + // trilinear hexahedra are sometimes called linear but do not qualify. const bool recompute_visc = (g == 0 || !fs[0].lShpF); if (recompute_visc) { @@ -349,14 +347,14 @@ void construct_usolid(ComMod& com_mod, CepMod& cep_mod, const mshType& lM, const auto N1 = fs[1].N.col(g); ustruct_3d_m(com_mod, cep_mod, vmsStab, fs[0].eNoN, fs[1].eNoN, nFn, w, Jac, N0, N1, Nwx, al, yl, dl, bfl, fN, ya_l_f, ya_l_s, - ya_l_n, lR, lK, lKd, Svis, Kvis_u, Kvis_v, recompute_visc); + ya_l_n, lR, lK, lKd, recompute_visc); } else if (nsd == 2) { auto N0 = fs[0].N.col(g); auto N1 = fs[1].N.col(g); ustruct_2d_m(com_mod, cep_mod, vmsStab, fs[0].eNoN, fs[1].eNoN, nFn, w, Jac, N0, N1, Nwx, al, yl, dl, bfl, fN, ya_l_f, ya_l_s, - ya_l_n, lR, lK, lKd, Svis, Kvis_u, Kvis_v, recompute_visc); + ya_l_n, lR, lK, lKd, recompute_visc); } } // for g = 0 to fs[0].nG @@ -888,7 +886,6 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, const Array &fN, const Vector &ya_l_f, const Vector &ya_l_s, const Vector &ya_l_n, Array &lR, Array3 &lK, Array3 &lKd, - Array &Svis, Array3 &Kvis_u, Array3 &Kvis_v, const bool recompute_visc) { using namespace consts; using namespace mat_fun; @@ -987,6 +984,13 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, ya_g_s, ya_g_n, Siso, Dm, Ja); // Viscous 2nd Piola-Kirchhoff stress and tangent contributions + static Array Svis(2,2); + static Array3 Kvis_u, Kvis_v; + if (Kvis_u.ncols() != eNoNw) { + Kvis_u.resize(4, eNoNw, eNoNw); + Kvis_v.resize(4, eNoNw, eNoNw); + } + mat_models::compute_visc_stress_and_tangent(dmn, eNoNw, Nwx, vx, F, Svis, Kvis_u, Kvis_v, recompute_visc); @@ -1177,7 +1181,6 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, const Array &fN, const Vector &ya_l_f, const Vector &ya_l_s, const Vector &ya_l_n, Array &lR, Array3 &lK, Array3 &lKd, - Array &Svis, Array3 &Kvis_u, Array3 &Kvis_v, const bool recompute_visc) { using namespace consts; using namespace mat_fun; @@ -1297,6 +1300,13 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, ya_g_s, ya_g_n, Siso, Dm, Ja); // Viscous 2nd Piola-Kirchhoff stress and tangent contributions + static Array Svis(3,3); + static Array3 Kvis_u, Kvis_v; + if (Kvis_u.ncols() != eNoNw) { + Kvis_u.resize(9, eNoNw, eNoNw); + Kvis_v.resize(9, eNoNw, eNoNw); + } + mat_models::compute_visc_stress_and_tangent(dmn, eNoNw, Nwx, vx, F, Svis, Kvis_u, Kvis_v, recompute_visc); diff --git a/Code/Source/solver/ustruct.h b/Code/Source/solver/ustruct.h index 611cb6a79..c89e99c61 100644 --- a/Code/Source/solver/ustruct.h +++ b/Code/Source/solver/ustruct.h @@ -38,7 +38,6 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, const Array &fN, const Vector &ya_l_f, const Vector &ya_l_s, const Vector &ya_l_n, Array &lR, Array3 &lK, Array3 &lKd, - Array &Svis, Array3 &Kvis_u, Array3 &Kvis_v, const bool recompute_visc); void ustruct_3d_c(ComMod& com_mod, CepMod& cep_mod, const bool vmsFlag, const int eNoNw, const int eNoNq, @@ -56,7 +55,6 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, const Array &fN, const Vector &ya_l_f, const Vector &ya_l_s, const Vector &ya_l_n, Array &lR, Array3 &lK, Array3 &lKd, - Array &Svis, Array3 &Kvis_u, Array3 &Kvis_v, const bool recompute_visc); void ustruct_do_assem(ComMod& com_mod, const int d, const Vector& eqN, const Array3& lKd, From 952b7fc76e2102713fae01072cafbc7be7e6430e Mon Sep 17 00:00:00 2001 From: dseyler Date: Thu, 17 Sep 2026 11:44:39 -0700 Subject: [PATCH 16/42] recompute_visc flag checked in struct / ustruct instead of passed into compute_visc_stress_and_tangent --- Code/Source/solver/mat_models.cpp | 13 +------------ Code/Source/solver/mat_models.h | 4 +--- Code/Source/solver/sv_struct.cpp | 14 ++++++++++---- Code/Source/solver/ustruct.cpp | 15 ++++++++++----- 4 files changed, 22 insertions(+), 24 deletions(-) diff --git a/Code/Source/solver/mat_models.cpp b/Code/Source/solver/mat_models.cpp index db210b9e2..0b58a555a 100644 --- a/Code/Source/solver/mat_models.cpp +++ b/Code/Source/solver/mat_models.cpp @@ -1731,16 +1731,10 @@ void compute_visc_stress_newtonian(const double mu, const int eNoN, const Array< * @param[out] Kvis_v Viscous tangent matrix contribution due to velocity */ void compute_visc_stress_and_tangent(const dmnType& lDmn, const int eNoN, const Array& Nx, const Array& vx, const Array& F, - Array& Svis, Array3& Kvis_u, Array3& Kvis_v, - const bool recompute_visc) { + Array& Svis, Array3& Kvis_u, Array3& Kvis_v) { switch (lDmn.solid_visc.viscType) { case consts::SolidViscosityModelType::viscType_Newtonian: - // Constant at all Gauss points for linear simplex elements (triangle / tetrahedra), - // so the caller can ask for the previous result to be kept. - if (!recompute_visc) { - return; - } if (F.nrows() == 3) { compute_visc_stress_newtonian<3>(lDmn.solid_visc.mu, eNoN, Nx, vx, F, Svis, Kvis_u, Kvis_v); } else if (F.nrows() == 2) { @@ -1749,11 +1743,6 @@ void compute_visc_stress_and_tangent(const dmnType& lDmn, const int eNoN, const break; case consts::SolidViscosityModelType::viscType_Potential: - // Constant at all Gauss points for linear simplex elements (triangle / tetrahedra), - // so the caller can ask for the previous result to be kept. - if (!recompute_visc) { - return; - } if (F.nrows() == 3) { compute_visc_stress_potential<3>(lDmn.solid_visc.mu, eNoN, Nx, vx, F, Svis, Kvis_u, Kvis_v); } else if (F.nrows() == 2) { diff --git a/Code/Source/solver/mat_models.h b/Code/Source/solver/mat_models.h index a5524fbb9..e74bc68bf 100644 --- a/Code/Source/solver/mat_models.h +++ b/Code/Source/solver/mat_models.h @@ -77,10 +77,8 @@ void g_vol_pen(const ComMod& com_mod, const dmnType& lDmn, const double p, /// @param[in] F Deformation gradient. /// @param[out] Svis Viscous 2nd Piola-Kirchhoff stress. /// @param[out] Kvis_u,Kvis_v Tangent contributions w.r.t. displacement and velocity. -/// @param[in] recompute False when the outputs are still valid from the previous call. void compute_visc_stress_and_tangent(const dmnType& lDmn, const int eNoN, const Array& Nx, const Array& vx, const Array& F, - Array& Svis, Array3& Kvis_u, Array3& Kvis_v, - const bool recompute_visc); + Array& Svis, Array3& Kvis_u, Array3& Kvis_v); }; #endif diff --git a/Code/Source/solver/sv_struct.cpp b/Code/Source/solver/sv_struct.cpp index 56a1619d1..6ef582fce 100644 --- a/Code/Source/solver/sv_struct.cpp +++ b/Code/Source/solver/sv_struct.cpp @@ -453,8 +453,11 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, Kvis_v.resize(4, eNoN, eNoN); } - mat_models::compute_visc_stress_and_tangent(dmn, eNoN, Nx, vx, F, Svis, Kvis_u, Kvis_v, - recompute_visc); + // Reuse the previous Gauss point's viscous contributions when shape function + // gradients are constant wihtin an element (e.g. linear triangles, tetrahedra). + if (recompute_visc) { + mat_models::compute_visc_stress_and_tangent(dmn, eNoN, Nx, vx, F, Svis, Kvis_u, Kvis_v); + } // Elastic + Viscous stresses S = S + Svis; @@ -677,8 +680,11 @@ void struct_3d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, Kvis_v.resize(9, eNoN, eNoN); } - mat_models::compute_visc_stress_and_tangent(dmn, eNoN, Nx, vx, F, Svis, Kvis_u, Kvis_v, - recompute_visc); + // Reuse the previous Gauss point's viscous contributions when shape function + // gradients are constant wihtin an element (e.g. linear triangles, tetrahedra). + if (recompute_visc) { + mat_models::compute_visc_stress_and_tangent(dmn, eNoN, Nx, vx, F, Svis, Kvis_u, Kvis_v); + } // Elastic + Viscous stresses S = S + Svis; diff --git a/Code/Source/solver/ustruct.cpp b/Code/Source/solver/ustruct.cpp index 432982e8f..2923910bb 100644 --- a/Code/Source/solver/ustruct.cpp +++ b/Code/Source/solver/ustruct.cpp @@ -991,8 +991,11 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, Kvis_v.resize(4, eNoNw, eNoNw); } - mat_models::compute_visc_stress_and_tangent(dmn, eNoNw, Nwx, vx, F, Svis, Kvis_u, Kvis_v, - recompute_visc); + // Reuse the previous Gauss point's viscous contributions when shape function + // gradients are constant within an element (e.g. linear triangles and tetrahedra). + if (recompute_visc) { + mat_models::compute_visc_stress_and_tangent(dmn, eNoNw, Nwx, vx, F, Svis, Kvis_u, Kvis_v); + } // Compute rho and beta depending on the volumetric penalty model // @@ -1306,9 +1309,11 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, Kvis_u.resize(9, eNoNw, eNoNw); Kvis_v.resize(9, eNoNw, eNoNw); } - - mat_models::compute_visc_stress_and_tangent(dmn, eNoNw, Nwx, vx, F, Svis, Kvis_u, Kvis_v, - recompute_visc); + // Reuse the previous Gauss point's viscous contributions when shape function + // gradients are constant within an element (e.g. linear triangles and tetrahedra). + if (recompute_visc) { + mat_models::compute_visc_stress_and_tangent(dmn, eNoNw, Nwx, vx, F, Svis, Kvis_u, Kvis_v); + } // Compute rho and beta depending on the volumetric penalty model From 1ecce85d546fe4ba77791fd6257270414d96209f Mon Sep 17 00:00:00 2001 From: dseyler Date: Fri, 18 Sep 2026 14:48:14 -0700 Subject: [PATCH 17/42] Added nsd-templated compute_pk2cc overloads taking Eigen matrices --- Code/Source/solver/mat_models.cpp | 38 ++++++++++++------------ Code/Source/solver/mat_models.h | 49 ++++++++++++++++++++++++++++++- 2 files changed, 66 insertions(+), 21 deletions(-) diff --git a/Code/Source/solver/mat_models.cpp b/Code/Source/solver/mat_models.cpp index 0b58a555a..e598c3b59 100644 --- a/Code/Source/solver/mat_models.cpp +++ b/Code/Source/solver/mat_models.cpp @@ -14,13 +14,6 @@ namespace mat_models { -// Define templated type aliases for Eigen matrices and 4th order tensors for convenience -template -using Matrix = Eigen::Matrix; - -template -using Tensor = Eigen::TensorFixedSize>; - /// @brief Compute active component of deformation gradient tensor for @@ -228,7 +221,7 @@ void voigt_to_cc(const int nsd, const Array& Dm, Tensor4& CC) * for Hyperelastic Isotropic and Anisotropic Materials" by Cheng and Zhang. * */ -template +template std::pair, Tensor> bar_to_iso( const Matrix& S_bar, const Tensor &CC_bar, const double J2d, const Matrix& C, const Matrix& Ci) @@ -266,7 +259,7 @@ std::pair, Tensor> bar_to_iso( * @return Normalized sheet-normal direction vector. * @throws std::runtime_error if directions are parallel or if called in 2D. */ -template +template Eigen::Matrix compute_sheet_normal(const Eigen::Matrix& fl) { using namespace mat_fun; @@ -287,10 +280,10 @@ Eigen::Matrix compute_sheet_normal(const Eigen::Matrix +template void compute_pk2cc(const ComMod &com_mod, const CepMod &cep_mod, const dmnType &lDmn, const Matrix &F, const int nfd, - const Eigen::Matrix fl, + const FiberMatrix &fl, const double ya_f, const double ya_s, const double ya_n, Matrix &S, Matrix<3 * (nsd - 1)> &Dm, double &Ja) { using namespace consts; @@ -822,6 +815,18 @@ void compute_pk2cc(const ComMod &com_mod, const CepMod &cep_mod, * This is a wrapper function for the templated function compute_pk2cc. * */ +// The element routines know their dimension at compile time and call the +// template directly, so instantiate the dimensions the solver supports. Keep +// this next to the definition: a signature change here that is not mirrored +// below fails at link time rather than at compile time. +template void compute_pk2cc<2>(const ComMod&, const CepMod&, const dmnType&, + const Matrix<2>&, const int, const FiberMatrix<2>&, + const double, const double, const double, Matrix<2>&, Matrix<3>&, double&); + +template void compute_pk2cc<3>(const ComMod&, const CepMod&, const dmnType&, + const Matrix<3>&, const int, const FiberMatrix<3>&, + const double, const double, const double, Matrix<3>&, Matrix<6>&, double&); + void compute_pk2cc(const ComMod& com_mod, const CepMod& cep_mod, const dmnType& lDmn, const Array& F, const int nfd, const Array& fl, const double ya_f, const double ya_s, const double ya_n, Array& S, Array& Dm, double& Ja) { @@ -833,7 +838,7 @@ void compute_pk2cc(const ComMod& com_mod, const CepMod& cep_mod, const dmnType& auto F_2D = mat_fun::convert_to_eigen_matrix(F); // Copy fiber directions to Eigen matrix - Eigen::Matrix fl_2D(2, nfd); + FiberMatrix<2> fl_2D(2, nfd); for (int i = 0; i < nfd; i++) { fl_2D(0, i) = fl(0, i); fl_2D(1, i) = fl(1, i); @@ -855,7 +860,7 @@ void compute_pk2cc(const ComMod& com_mod, const CepMod& cep_mod, const dmnType& auto F_3D = mat_fun::convert_to_eigen_matrix(F); // Copy fiber directions to Eigen matrix - Eigen::Matrix fl_3D(3, nfd); + FiberMatrix<3> fl_3D(3, nfd); for (int i = 0; i < nfd; i++) { fl_3D(0, i) = fl(0, i); fl_3D(1, i) = fl(1, i); @@ -1561,13 +1566,6 @@ void g_vol_pen(const ComMod& com_mod, const dmnType& lDmn, const double p, namespace { -/// @brief Largest element node count the fixed-size views below allow (HEX27). -constexpr int MAX_ELEMENT_NODES = 27; - -/// @brief A quantity carrying one nsd-vector per element node, so nsd x eNoN. -template -using NodalMatrix = Eigen::Matrix; - /** * @brief Viscous PK2 stress and tangent contributions for the viscous * pseudo-potential model. diff --git a/Code/Source/solver/mat_models.h b/Code/Source/solver/mat_models.h index e74bc68bf..ce4861330 100644 --- a/Code/Source/solver/mat_models.h +++ b/Code/Source/solver/mat_models.h @@ -17,7 +17,40 @@ namespace mat_models { -void actv_strain(const ComMod& com_mod, const CepMod& cep_mod, const double gf, +/// @brief Largest number of fiber directions a mesh may declare. +/// +/// Bounds FiberMatrix so it never allocates. read_msh rejects a mesh that +/// declares more, because the overrun would otherwise be silent under NDEBUG. +constexpr int MAX_FIBER_DIRECTIONS = 4; + +/// @brief Largest element node count the bounded views below allow (HEX27). +constexpr int MAX_ELEMENT_NODES = 27; + +/// @brief A second order tensor, nsd x nsd. +template +using Matrix = Eigen::Matrix; + +/// @brief A 4th order tensor, nsd x nsd x nsd x nsd. +template +using Tensor = Eigen::TensorFixedSize>; + +/// @brief Fiber directions, one unit vector per column. +/// +/// The column count is a run-time value, so the capacity is bounded to keep the +/// storage on the stack; a plain dynamic matrix would allocate on every call. +template +using FiberMatrix = + Eigen::Matrix; + +/// @brief A quantity carrying one nsd-vector per element node, so nsd x eNoN. +/// +/// Bounded for the same reason as FiberMatrix. The layout is column major with +/// a column stride of nsd, matching Array, so the two can share storage. +template +using NodalMatrix = + Eigen::Matrix; + +void actv_strain(const ComMod& com_mod, const CepMod& cep_mod, const double gf, const int nfd, const Array& fl, Array& Fa); void cc_to_voigt(const int nsd, const Tensor4& CC, Array& Dm); @@ -45,7 +78,21 @@ void voigt_to_cc(const int nsd, const Array& Dm, Tensor4& CC); * @param[out] Ja Jacobian for active strain * * @return None, but modifies S, Dm, and Ja in place. + * + * @tparam nsd Number of spatial dimensions. Deduced from F, so callers that + * know the dimension at compile time just pass their matrices. + * + * Defined in mat_models.cpp and explicitly instantiated there for nsd = 2 and + * nsd = 3, the only dimensions the solver supports. */ +template +void compute_pk2cc(const ComMod &com_mod, const CepMod &cep_mod, + const dmnType &lDmn, const Matrix &F, const int nfd, + const FiberMatrix &fl, const double ya_f, + const double ya_s, const double ya_n, Matrix &S, + Matrix<3 * (nsd - 1)> &Dm, double &Ja); + +/// @brief Array-based overload, for callers whose dimension is a run-time value. void compute_pk2cc(const ComMod &com_mod, const CepMod &cep_mod, const dmnType &lDmn, const Array &F, const int nfd, const Array &fl, const double ya_f, From fc4511a660fbb1dbcc7f9e49288ae85a0c04331f Mon Sep 17 00:00:00 2001 From: dseyler Date: Mon, 21 Sep 2026 13:32:16 -0700 Subject: [PATCH 18/42] Keep F, vx, S0, Dm, P and Svis as fixed-size Eigen matrices --- Code/Source/solver/mat_models.cpp | 114 +++++++++++++----------------- Code/Source/solver/mat_models.h | 29 +++----- Code/Source/solver/sv_struct.cpp | 80 +++++++++++---------- Code/Source/solver/ustruct.cpp | 67 ++++++++---------- 4 files changed, 134 insertions(+), 156 deletions(-) diff --git a/Code/Source/solver/mat_models.cpp b/Code/Source/solver/mat_models.cpp index e598c3b59..66aa3bc91 100644 --- a/Code/Source/solver/mat_models.cpp +++ b/Code/Source/solver/mat_models.cpp @@ -255,12 +255,14 @@ std::pair, Tensor> bar_to_iso( * Validates that the directions are not parallel and that the operation is valid in 3D. * * @tparam nsd Number of spatial dimensions. - * @param[in] fl Fiber directions matrix (nsd x nfd), where col(0) is fiber, col(1) is sheet. + * @param[in] f Fiber direction. + * @param[in] s Sheet direction. * @return Normalized sheet-normal direction vector. * @throws std::runtime_error if directions are parallel or if called in 2D. */ -template -Eigen::Matrix compute_sheet_normal(const Eigen::Matrix& fl) +template +Eigen::Matrix compute_sheet_normal(const Eigen::Matrix& f, + const Eigen::Matrix& s) { using namespace mat_fun; @@ -268,7 +270,7 @@ Eigen::Matrix compute_sheet_normal(const Eigen::Matrix 0) is not defined in 2D."); } else { // nsd == 3 - auto n_normal = cross_product(fl.col(0), fl.col(1)); + auto n_normal = cross_product(f, s); double norm_n = sqrt(n_normal.dot(n_normal)); static constexpr double sheet_normal_tol = 1.0e-10; @@ -283,13 +285,16 @@ Eigen::Matrix compute_sheet_normal(const Eigen::Matrix void compute_pk2cc(const ComMod &com_mod, const CepMod &cep_mod, const dmnType &lDmn, const Matrix &F, const int nfd, - const FiberMatrix &fl, + const Array &fl, const double ya_f, const double ya_s, const double ya_n, Matrix &S, Matrix<3 * (nsd - 1)> &Dm, double &Ja) { using namespace consts; using namespace mat_fun; using namespace utils; + // Fiber directions are the caller's storage. View rather than copying. + Eigen::Map> fl_m(fl.data(), nsd, nfd); + #define n_debug_compute_pk2cc #ifdef debug_compute_pk2cc DebugMsg dmsg(__func__, com_mod.cm.idcm()); @@ -332,12 +337,12 @@ void compute_pk2cc(const ComMod &com_mod, const CepMod &cep_mod, } // Aliases for fiber directions - const auto& fib_dir1 = fl.col(0); + const auto& fib_dir1 = fl_m.col(0); // fib_dir2 only exists when nfd >= 2 Eigen::Matrix fib_dir2; if (nfd >= 2) { - fib_dir2 = fl.col(1); + fib_dir2 = fl_m.col(1); } else { fib_dir2 = Eigen::Matrix::Zero(); } @@ -509,7 +514,7 @@ void compute_pk2cc(const ComMod &com_mod, const CepMod &cep_mod, } // Compute sheet-normal direction - auto fib_dir3 = compute_sheet_normal(fl); + auto fib_dir3 = compute_sheet_normal(fl_m.col(0), fl_m.col(1)); // Compute isochoric component of E Matrix E = 0.50 * (J2d*C - Idm); @@ -580,7 +585,7 @@ void compute_pk2cc(const ComMod &com_mod, const CepMod &cep_mod, } // Compute sheet-normal direction - auto fib_dir3 = compute_sheet_normal(fl); + auto fib_dir3 = compute_sheet_normal(fl_m.col(0), fl_m.col(1)); // Compute cross fiber-sheet structure tensor Matrix Hfs = 0.5 * (fib_dir1 * fib_dir2.transpose() + fib_dir2 * fib_dir1.transpose()); @@ -677,7 +682,7 @@ void compute_pk2cc(const ComMod &com_mod, const CepMod &cep_mod, } // Compute sheet-normal direction - auto fib_dir3 = compute_sheet_normal(fl); + auto fib_dir3 = compute_sheet_normal(fl_m.col(0), fl_m.col(1)); // Compute cross fiber-sheet structure tensor auto Hfs = 0.5 * (fib_dir1 * fib_dir2.transpose() + fib_dir2 * fib_dir1.transpose()); @@ -780,7 +785,7 @@ void compute_pk2cc(const ComMod &com_mod, const CepMod &cep_mod, Matrix N1; // Compute and store invariants and derivatives wrt C in array of matrices/tensors - CANNModel.computeInvariantsAndDerivatives(C, fl, nfd, J2d, J4d, Ci, Idm, Tfa, N1, psi, Inv, dInv, ddInv); + CANNModel.computeInvariantsAndDerivatives(C, fl_m, nfd, J2d, J4d, Ci, Idm, Tfa, N1, psi, Inv, dInv, ddInv); // Strain energy function and derivatives CANNModel.evaluate(Inv, psi, dpsi, ddpsi); @@ -820,11 +825,11 @@ void compute_pk2cc(const ComMod &com_mod, const CepMod &cep_mod, // this next to the definition: a signature change here that is not mirrored // below fails at link time rather than at compile time. template void compute_pk2cc<2>(const ComMod&, const CepMod&, const dmnType&, - const Matrix<2>&, const int, const FiberMatrix<2>&, + const Matrix<2>&, const int, const Array&, const double, const double, const double, Matrix<2>&, Matrix<3>&, double&); template void compute_pk2cc<3>(const ComMod&, const CepMod&, const dmnType&, - const Matrix<3>&, const int, const FiberMatrix<3>&, + const Matrix<3>&, const int, const Array&, const double, const double, const double, Matrix<3>&, Matrix<6>&, double&); void compute_pk2cc(const ComMod& com_mod, const CepMod& cep_mod, const dmnType& lDmn, const Array& F, const int nfd, @@ -837,19 +842,13 @@ void compute_pk2cc(const ComMod& com_mod, const CepMod& cep_mod, const dmnType& // Copy deformation gradient to Eigen matrix auto F_2D = mat_fun::convert_to_eigen_matrix(F); - // Copy fiber directions to Eigen matrix - FiberMatrix<2> fl_2D(2, nfd); - for (int i = 0; i < nfd; i++) { - fl_2D(0, i) = fl(0, i); - fl_2D(1, i) = fl(1, i); - } // Initialize stress and elasticity tensors Eigen::Matrix2d S_2D = Eigen::Matrix2d::Zero(); Eigen::Matrix3d Dm_2D = Eigen::Matrix3d::Zero(); // Call templated function - compute_pk2cc<2>(com_mod, cep_mod, lDmn, F_2D, nfd, fl_2D, ya_f, ya_s, ya_n, S_2D, Dm_2D, Ja); + compute_pk2cc<2>(com_mod, cep_mod, lDmn, F_2D, nfd, fl, ya_f, ya_s, ya_n, S_2D, Dm_2D, Ja); // Copy results back mat_fun::convert_to_array(S_2D, S); @@ -859,13 +858,6 @@ void compute_pk2cc(const ComMod& com_mod, const CepMod& cep_mod, const dmnType& // Copy deformation gradient to Eigen matrix auto F_3D = mat_fun::convert_to_eigen_matrix(F); - // Copy fiber directions to Eigen matrix - FiberMatrix<3> fl_3D(3, nfd); - for (int i = 0; i < nfd; i++) { - fl_3D(0, i) = fl(0, i); - fl_3D(1, i) = fl(1, i); - fl_3D(2, i) = fl(2, i); - } // Initialize stress and elasticity tensors Eigen::Matrix3d S_3D = Eigen::Matrix3d::Zero(); @@ -873,7 +865,7 @@ void compute_pk2cc(const ComMod& com_mod, const CepMod& cep_mod, const dmnType& Dm_3D.setZero(); // Call templated function - compute_pk2cc<3>(com_mod, cep_mod, lDmn, F_3D, nfd, fl_3D, ya_f, ya_s, ya_n, S_3D, Dm_3D, Ja); + compute_pk2cc<3>(com_mod, cep_mod, lDmn, F_3D, nfd, fl, ya_f, ya_s, ya_n, S_3D, Dm_3D, Ja); // Copy results back mat_fun::convert_to_array(S_3D, S); @@ -1590,27 +1582,23 @@ namespace { */ template void compute_visc_stress_potential(const double mu, const int eNoN, const Array& Nx, - const Array& vx, const Array& F, - Array& Svis, Array3& Kvis_u, Array3& Kvis_v) { - // Alias the caller's storage; no copies. Svis, Kvis_u and Kvis_v are - // written in full below, so they are not zeroed first. - Eigen::Map> F_map(F.data()); - Eigen::Map> vx_map(vx.data()); + const Matrix& vx, const Matrix& F, + Matrix& Svis, Array3& Kvis_u, Array3& Kvis_v) { + Eigen::Map> Nx_map(Nx.data(), nsd, eNoN); // Required intermediate terms for stress and tangent - const Matrix F_Ft = F_map * F_map.transpose(); - const Matrix Ft_vx = F_map.transpose() * vx_map; - const Matrix F_vxt = F_map * vx_map.transpose(); + const Matrix F_Ft = F * F.transpose(); + const Matrix Ft_vx = F.transpose() * vx; + const Matrix F_vxt = F * vx.transpose(); // F_Nx(i,a) = sum_j F(i,j) * Nx(j,a), and likewise for vx. - const NodalMatrix F_Nx = F_map * Nx_map; - const NodalMatrix vx_Nx = vx_map * Nx_map; + const NodalMatrix F_Nx = F * Nx_map; + const NodalMatrix vx_Nx = vx * Nx_map; // 2nd Piola-Kirchhoff stress due to viscosity // Svis = mu * 1/2 * ( (F^T * dv/dX) + (F^T * dv/dX)^T ) - Eigen::Map> Svis_map(Svis.data()); - Svis_map.noalias() = mu * mat_fun::mat_symm(Ft_vx); + Svis.noalias() = mu * mat_fun::mat_symm(Ft_vx); // Tangent matrix contributions due to viscosity for (int b = 0; b < eNoN; ++b) { @@ -1656,20 +1644,18 @@ void compute_visc_stress_potential(const double mu, const int eNoN, const Array< */ template void compute_visc_stress_newtonian(const double mu, const int eNoN, const Array& Nx, - const Array& vx, const Array& F, - Array& Svis, Array3& Kvis_u, Array3& Kvis_v) { + const Matrix& vx, const Matrix& F, + Matrix& Svis, Array3& Kvis_u, Array3& Kvis_v) { - Eigen::Map> F_map(F.data()); - Eigen::Map> vx_map(vx.data()); Eigen::Map> Nx_map(Nx.data(), nsd, eNoN); // Get identity matrix, Jacobian, and F^-1 const auto Idm = Matrix::Identity(); - const double J = F_map.determinant(); - const Matrix Fi = F_map.inverse(); + const double J = F.determinant(); + const Matrix Fi = F.inverse(); // vx_Fi: Velocity gradient in current configuration - const Matrix vx_Fi = vx_map * Fi; + const Matrix vx_Fi = vx * Fi; const Matrix vx_Fi_symm = mat_fun::mat_symm(vx_Fi); // ddev: Deviatoric part of rate of strain tensor const Matrix ddev = mat_fun::mat_dev(vx_Fi_symm); @@ -1681,8 +1667,7 @@ void compute_visc_stress_newtonian(const double mu, const int eNoN, const Array< // 2nd Piola-Kirchhoff stress due to viscosity // Svis = 2 * mu * J * F^-1 * d_dev * F^-T - Eigen::Map> Svis_map(Svis.data()); - Svis_map.noalias() = (2.0 * mu * J) * (Fi * ddev * Fi.transpose()); + Svis.noalias() = (2.0 * mu * J) * (Fi * ddev * Fi.transpose()); // Tangent matrix contributions due to viscosity constexpr double r2d = 2.0 / nsd; @@ -1728,33 +1713,36 @@ void compute_visc_stress_newtonian(const double mu, const int eNoN, const Array< * @param[out] Kvis_u Viscous tangent matrix contribution due to displacement * @param[out] Kvis_v Viscous tangent matrix contribution due to velocity */ -void compute_visc_stress_and_tangent(const dmnType& lDmn, const int eNoN, const Array& Nx, const Array& vx, const Array& F, - Array& Svis, Array3& Kvis_u, Array3& Kvis_v) { +template +void compute_visc_stress_and_tangent(const dmnType& lDmn, const int eNoN, + const Array& Nx, const Matrix& vx, const Matrix& F, + Matrix& Svis, Array3& Kvis_u, Array3& Kvis_v) { switch (lDmn.solid_visc.viscType) { case consts::SolidViscosityModelType::viscType_Newtonian: - if (F.nrows() == 3) { - compute_visc_stress_newtonian<3>(lDmn.solid_visc.mu, eNoN, Nx, vx, F, Svis, Kvis_u, Kvis_v); - } else if (F.nrows() == 2) { - compute_visc_stress_newtonian<2>(lDmn.solid_visc.mu, eNoN, Nx, vx, F, Svis, Kvis_u, Kvis_v); - } + compute_visc_stress_newtonian(lDmn.solid_visc.mu, eNoN, Nx, vx, F, Svis, Kvis_u, Kvis_v); break; case consts::SolidViscosityModelType::viscType_Potential: - if (F.nrows() == 3) { - compute_visc_stress_potential<3>(lDmn.solid_visc.mu, eNoN, Nx, vx, F, Svis, Kvis_u, Kvis_v); - } else if (F.nrows() == 2) { - compute_visc_stress_potential<2>(lDmn.solid_visc.mu, eNoN, Nx, vx, F, Svis, Kvis_u, Kvis_v); - } + compute_visc_stress_potential(lDmn.solid_visc.mu, eNoN, Nx, vx, F, Svis, Kvis_u, Kvis_v); break; default: // No viscosity model for this domain. - Svis = 0.0; + Svis.setZero(); Kvis_u = 0.0; Kvis_v = 0.0; break; } } +// Instantiate the dimensions the solver supports. +template void compute_visc_stress_and_tangent<2>(const dmnType&, const int, + const Array&, const Matrix<2>&, const Matrix<2>&, + Matrix<2>&, Array3&, Array3&); + +template void compute_visc_stress_and_tangent<3>(const dmnType&, const int, + const Array&, const Matrix<3>&, const Matrix<3>&, + Matrix<3>&, Array3&, Array3&); + }; diff --git a/Code/Source/solver/mat_models.h b/Code/Source/solver/mat_models.h index ce4861330..10a98d982 100644 --- a/Code/Source/solver/mat_models.h +++ b/Code/Source/solver/mat_models.h @@ -17,12 +17,6 @@ namespace mat_models { -/// @brief Largest number of fiber directions a mesh may declare. -/// -/// Bounds FiberMatrix so it never allocates. read_msh rejects a mesh that -/// declares more, because the overrun would otherwise be silent under NDEBUG. -constexpr int MAX_FIBER_DIRECTIONS = 4; - /// @brief Largest element node count the bounded views below allow (HEX27). constexpr int MAX_ELEMENT_NODES = 27; @@ -34,18 +28,8 @@ using Matrix = Eigen::Matrix; template using Tensor = Eigen::TensorFixedSize>; -/// @brief Fiber directions, one unit vector per column. -/// -/// The column count is a run-time value, so the capacity is bounded to keep the -/// storage on the stack; a plain dynamic matrix would allocate on every call. -template -using FiberMatrix = - Eigen::Matrix; - /// @brief A quantity carrying one nsd-vector per element node, so nsd x eNoN. /// -/// Bounded for the same reason as FiberMatrix. The layout is column major with -/// a column stride of nsd, matching Array, so the two can share storage. template using NodalMatrix = Eigen::Matrix; @@ -79,8 +63,7 @@ void voigt_to_cc(const int nsd, const Array& Dm, Tensor4& CC); * * @return None, but modifies S, Dm, and Ja in place. * - * @tparam nsd Number of spatial dimensions. Deduced from F, so callers that - * know the dimension at compile time just pass their matrices. + * @tparam nsd Number of spatial dimensions. * * Defined in mat_models.cpp and explicitly instantiated there for nsd = 2 and * nsd = 3, the only dimensions the solver supports. @@ -88,7 +71,7 @@ void voigt_to_cc(const int nsd, const Array& Dm, Tensor4& CC); template void compute_pk2cc(const ComMod &com_mod, const CepMod &cep_mod, const dmnType &lDmn, const Matrix &F, const int nfd, - const FiberMatrix &fl, const double ya_f, + const Array &fl, const double ya_f, const double ya_s, const double ya_n, Matrix &S, Matrix<3 * (nsd - 1)> &Dm, double &Ja); @@ -124,8 +107,12 @@ void g_vol_pen(const ComMod& com_mod, const dmnType& lDmn, const double p, /// @param[in] F Deformation gradient. /// @param[out] Svis Viscous 2nd Piola-Kirchhoff stress. /// @param[out] Kvis_u,Kvis_v Tangent contributions w.r.t. displacement and velocity. -void compute_visc_stress_and_tangent(const dmnType& lDmn, const int eNoN, const Array& Nx, const Array& vx, const Array& F, - Array& Svis, Array3& Kvis_u, Array3& Kvis_v); +/// +/// @tparam nsd Number of spatial dimensions, deduced from F. +template +void compute_visc_stress_and_tangent(const dmnType& lDmn, const int eNoN, + const Array& Nx, const Matrix& vx, const Matrix& F, + Matrix& Svis, Array3& Kvis_u, Array3& Kvis_v); }; #endif diff --git a/Code/Source/solver/sv_struct.cpp b/Code/Source/solver/sv_struct.cpp index 6ef582fce..0b2d581dc 100644 --- a/Code/Source/solver/sv_struct.cpp +++ b/Code/Source/solver/sv_struct.cpp @@ -179,8 +179,16 @@ void b_struct_3d(const ComMod& com_mod, const int eNoN, const double w, const Ve } } -/// @brief Replicates the Fortan 'CONSTRUCT_dSOLID' subroutine. -// +/// @brief Assemble the residual and tangent contributions of one solid mesh. +/// +/// @param[in,out] com_mod Global common variables. The current domain and, when +/// prestress is active, the accumulated nodal stresses are updated here, and +/// the assembled element contributions are written through it. +/// @param[in] cep_mod Electrophysiology variables, supplying the active stress +/// interpolated to each Gauss point. +/// @param[in] lM Mesh whose elements are assembled. +/// @param[in] solutions Acceleration, velocity and displacement at the +/// intermediate time level. void construct_dsolid(ComMod& com_mod, CepMod& cep_mod, const mshType& lM, const SolutionStates& solutions) { const auto& Ag = solutions.intermediate.get_acceleration(); @@ -394,14 +402,13 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, // Inertia, body force and deformation tensor (F) // - Array F(2,2), S0(2,2), vx(2,2); + mat_models::Matrix<2> F, S0, vx; Vector ud(2); ud = -rho*fb; - F = 0.0; - F(0,0) = 1.0; - F(1,1) = 1.0; - S0 = 0.0; + F.setIdentity(); + S0.setZero(); + vx.setZero(); double ya_g_f = 0.0; double ya_g_s = 0.0; @@ -440,13 +447,14 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, S0(1,0) = S0(0,1); // 2nd Piola-Kirchhoff stress (S) and material stiffness tensor in Voight notation (Dm) - Array S(2,2), Dm(3,3); + mat_models::Matrix<2> S; + mat_models::Matrix<3> Dm; double Ja; mat_models::compute_pk2cc(com_mod, cep_mod, dmn, F, nFn, fN, ya_g_f, ya_g_s, ya_g_n, S, Dm, Ja); // Viscous 2nd Piola-Kirchhoff stress and tangent contributions - static Array Svis(2,2); + static mat_models::Matrix<2> Svis; static Array3 Kvis_u, Kvis_v; if (Kvis_u.ncols() != eNoN) { Kvis_u.resize(4, eNoN, eNoN); @@ -472,9 +480,10 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, // 1st Piola-Kirchhoff tensor (P) // - Array P(2,2), DBm(3,2); + mat_models::Matrix<2> P; + Array DBm(3,2); Array3 Bm(3,2,eNoN); - P = mat_fun::mat_mul(F, S); + P.noalias() = F * S; #ifdef debug_struct_2d dmsg << "P: " << P(0,0) << " " << P(0,1); dmsg << " " << P(1,0) << " " << P(1,1); @@ -505,6 +514,17 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, double T1, NxNx, NxSNx, BmDBm; for (int b = 0; b < eNoN; b++) { + + // Material stiffness (Bt*D*B) + DBm(0,0) = Dm(0,0)*Bm(0,0,b) + Dm(0,1)*Bm(1,0,b) + Dm(0,2)*Bm(2,0,b); + DBm(0,1) = Dm(0,0)*Bm(0,1,b) + Dm(0,1)*Bm(1,1,b) + Dm(0,2)*Bm(2,1,b); + + DBm(1,0) = Dm(1,0)*Bm(0,0,b) + Dm(1,1)*Bm(1,0,b) + Dm(1,2)*Bm(2,0,b); + DBm(1,1) = Dm(1,0)*Bm(0,1,b) + Dm(1,1)*Bm(1,1,b) + Dm(1,2)*Bm(2,1,b); + + DBm(2,0) = Dm(2,0)*Bm(0,0,b) + Dm(2,1)*Bm(1,0,b) + Dm(2,2)*Bm(2,0,b); + DBm(2,1) = Dm(2,0)*Bm(0,1,b) + Dm(2,1)*Bm(1,1,b) + Dm(2,2)*Bm(2,1,b); + for (int a = 0; a < eNoN; a++) { // Geometric stiffness @@ -512,16 +532,6 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, Nx(0,a)*S(0,1)*Nx(1,b) + Nx(1,a)*S(1,1)*Nx(1,b); T1 = amd*N(a)*N(b) + afu*NxSNx; - // Material stiffness (Bt*D*B) - DBm(0,0) = Dm(0,0)*Bm(0,0,b) + Dm(0,1)*Bm(1,0,b) + Dm(0,2)*Bm(2,0,b); - DBm(0,1) = Dm(0,0)*Bm(0,1,b) + Dm(0,1)*Bm(1,1,b) + Dm(0,2)*Bm(2,1,b); - - DBm(1,0) = Dm(1,0)*Bm(0,0,b) + Dm(1,1)*Bm(1,0,b) + Dm(1,2)*Bm(2,0,b); - DBm(1,1) = Dm(1,0)*Bm(0,1,b) + Dm(1,1)*Bm(1,1,b) + Dm(1,2)*Bm(2,1,b); - - DBm(2,0) = Dm(2,0)*Bm(0,0,b) + Dm(2,1)*Bm(1,0,b) + Dm(2,2)*Bm(2,0,b); - DBm(2,1) = Dm(2,0)*Bm(0,1,b) + Dm(2,1)*Bm(1,1,b) + Dm(2,2)*Bm(2,1,b); - // dM1/du1 // Material stiffness: Bt*D*B @@ -604,7 +614,7 @@ void struct_3d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, // Inertia, body force and deformation tensor (F) // - Array F(3,3), S0(3,3), vx(3,3); + mat_models::Matrix<3> F, S0, vx; Vector ud(3); double F_f[3][3]={}; @@ -613,11 +623,9 @@ void struct_3d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, F_f[2][2] = 1.0; ud = -rho*fb; - F = 0.0; - F(0,0) = 1.0; - F(1,1) = 1.0; - F(2,2) = 1.0; - S0 = 0.0; + F.setIdentity(); + S0.setZero(); + vx.setZero(); double ya_g_f = 0.0; double ya_g_s = 0.0; @@ -667,13 +675,14 @@ void struct_3d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, // 2nd Piola-Kirchhoff tensor (S) and material stiffness tensor in // Voigt notationa (Dm) // - Array S(3,3), Dm(6,6); + mat_models::Matrix<3> S; + mat_models::Matrix<6> Dm; double Ja; mat_models::compute_pk2cc(com_mod, cep_mod, dmn, F, nFn, fN, ya_g_f, ya_g_s, ya_g_n, S, Dm, Ja); // Viscous 2nd Piola-Kirchhoff stress and tangent contributions - static Array Svis(3,3); + static mat_models::Matrix<3> Svis; static Array3 Kvis_u, Kvis_v; if (Kvis_u.ncols() != eNoN) { Kvis_u.resize(9, eNoN, eNoN); @@ -710,9 +719,9 @@ void struct_3d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, // 1st Piola-Kirchhoff tensor (P) // - Array P(3,3); + mat_models::Matrix<3> P; Array3 Bm(6,3,eNoN); - mat_fun::mat_mul(F, S, P); + P.noalias() = F * S; // Local residual for (int a = 0; a < eNoN; a++) { @@ -756,11 +765,10 @@ void struct_3d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, for (int b = 0; b < eNoN; b++) { - // Material stiffness (D*B). Shapes are fixed by the declarations above -- - // Dm(6,6), Bm(6,3,eNoN), DBm(6,3) -- so state them and skip the run-time - // shape check that the unparameterised overload would otherwise repeat on - // every one of these calls. - mat_mul<6, 6, 3>(Dm, Bm.rslice(b), DBm); + // Material stiffness (D*B) for node b. Dm is Eigen and Bm/DBm are Arrays, + // so view them; this is what mat_mul<6,6,3> did internally. + Eigen::Map> dbm(DBm.data()); + dbm.noalias() = Dm * Eigen::Map>(Bm.slice_data(b)); for (int a = 0; a < eNoN; a++) { diff --git a/Code/Source/solver/ustruct.cpp b/Code/Source/solver/ustruct.cpp index 2923910bb..3e40e4235 100644 --- a/Code/Source/solver/ustruct.cpp +++ b/Code/Source/solver/ustruct.cpp @@ -479,9 +479,8 @@ void ustruct_2d_c(ComMod& com_mod, CepMod& cep_mod, const bool vmsFlag, const in // Vector vd{-fb[0], -fb[1]}; Vector v(2); - Array vx(2,2), F(2,2); - F(0,0) = 1.0; - F(1,1) = 1.0; + mat_models::Matrix<2> vx = mat_models::Matrix<2>::Zero(); + mat_models::Matrix<2> F = mat_models::Matrix<2>::Identity(); for (int a = 0; a < eNoNw; a++) { v(0) = v(0) + Nw(a)*yl(i,a); @@ -501,8 +500,8 @@ void ustruct_2d_c(ComMod& com_mod, CepMod& cep_mod, const bool vmsFlag, const in F(1,1) = F(1,1) + Nwx(1,a)*dl(j,a); } - double Jac = mat_fun::mat_det(F, 2); - auto Fi = mat_fun::mat_inv(F, 2); + double Jac = F.determinant(); + const mat_models::Matrix<2> Fi = F.inverse(); // Pressure and its gradients // @@ -684,10 +683,8 @@ void ustruct_3d_c(ComMod& com_mod, CepMod& cep_mod, const bool vmsFlag, const in // Vector vd{-fb[0], -fb[1], -fb[2]}; Vector v(3); - Array vx(3,3), F(3,3); - F(0,0) = 1.0; - F(1,1) = 1.0; - F(2,2) = 1.0; + mat_models::Matrix<3> vx = mat_models::Matrix<3>::Zero(); + mat_models::Matrix<3> F = mat_models::Matrix<3>::Identity(); for (int a = 0; a < eNoNw; a++) { v(0) = v(0) + Nw(a)*yl(i,a); @@ -723,8 +720,8 @@ void ustruct_3d_c(ComMod& com_mod, CepMod& cep_mod, const bool vmsFlag, const in F(2,2) = F(2,2) + Nwx(2,a)*dl(k,a); } - double Jac = mat_fun::mat_det(F, 3); - auto Fi = mat_fun::mat_inv(F, 3); + double Jac = F.determinant(); + const mat_models::Matrix<3> Fi = F.inverse(); // Pressure and its gradients // @@ -932,14 +929,13 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, // Vector vd{-fb[0], -fb[1]}; Vector v(2); - Array vx(2,2), F(2,2); + mat_models::Matrix<2> vx = mat_models::Matrix<2>::Zero(); + mat_models::Matrix<2> F = mat_models::Matrix<2>::Identity(); double ya_g_f = 0.0; double ya_g_s = 0.0; double ya_g_n = 0.0; - F(0,0) = 1.0; - F(1,1) = 1.0; for (int a = 0; a < eNoNw; a++) { v(0) = v(0) + Nw(a)*yl(i,a); @@ -963,8 +959,8 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, ya_g_n = ya_g_n + Nw(a) * ya_l_n(a); } - double Jac = mat_fun::mat_det(F, 2); - auto Fi = mat_fun::mat_inv(F, 2); + double Jac = F.determinant(); + const mat_models::Matrix<2> Fi = F.inverse(); // Pressure and its time derivative // @@ -978,13 +974,14 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, // Compute deviatoric 2nd Piola-Kirchhoff stress tensor (Siso) and // isochoric elasticity tensor in Voigt notation (Dm) - Array Siso(2,2), Dm(3,3); + mat_models::Matrix<2> Siso; + mat_models::Matrix<3> Dm; double Ja = 0; mat_models::compute_pk2cc(com_mod, cep_mod, eq.dmn[cDmn], F, nFn, fN, ya_g_f, ya_g_s, ya_g_n, Siso, Dm, Ja); // Viscous 2nd Piola-Kirchhoff stress and tangent contributions - static Array Svis(2,2); + static mat_models::Matrix<2> Svis; static Array3 Kvis_u, Kvis_v; if (Kvis_u.ncols() != eNoNw) { Kvis_u.resize(4, eNoNw, eNoNw); @@ -1017,11 +1014,11 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, } // Total isochoric 2nd Piola-Kirchhoff stress (Elastic + Viscous) - Siso = Siso + Svis; + Siso += Svis; // Deviatoric 1st Piola-Kirchhoff tensor (P) // - auto Pdev = mat_fun::mat_mul(F, Siso); + const mat_models::Matrix<2> Pdev = F * Siso; // Shape function gradients in the current configuration @@ -1034,7 +1031,7 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, } // Velocity gradient in current configuration - auto VxFi = mat_mul(vx, Fi); + const mat_models::Matrix<2> VxFi = vx * Fi; double rC = beta*pd + VxFi(1,1) + VxFi(2,2); double rCl = -p + tauC*rC; @@ -1080,7 +1077,7 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, T1{0.0}, T2{0.0}, T3{0.0}, Tv{0.0}, Ku{0.0}; - Array DBm(3,2); + Eigen::Matrix DBm; for (int b = 0; b < eNoNw; b++) { for (int a = 0; a < eNoNw; a++) { @@ -1233,16 +1230,13 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, // Vector vd{-fb[0], -fb[1], -fb[2]}; Vector v(3); - Array vx(3,3), F(3,3); + mat_models::Matrix<3> vx = mat_models::Matrix<3>::Zero(); + mat_models::Matrix<3> F = mat_models::Matrix<3>::Identity(); double ya_g_f = 0.0; double ya_g_s = 0.0; double ya_g_n = 0.0; - F(0,0) = 1.0; - F(1,1) = 1.0; - F(2,2) = 1.0; - for (int a = 0; a < eNoNw; a++) { v(0) = v(0) + Nw(a)*yl(i,a); v(1) = v(1) + Nw(a)*yl(j,a); @@ -1281,8 +1275,8 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, ya_g_n = ya_g_n + Nw(a) * ya_l_n(a); } - double Jac = mat_fun::mat_det(F, 3); - auto Fi = mat_fun::mat_inv(F, 3); + double Jac = F.determinant(); + const mat_models::Matrix<3> Fi = F.inverse(); // Pressure and its time derivative // @@ -1297,13 +1291,14 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, // Compute deviatoric 2nd Piola-Kirchhoff stress tensor (Siso) and // isochoric elasticity tensor in Voigt notation (Dm) // - Array Siso(3,3), Dm(6,6); + mat_models::Matrix<3> Siso; + mat_models::Matrix<6> Dm; double Ja = 0; mat_models::compute_pk2cc(com_mod, cep_mod, eq.dmn[cDmn], F, nFn, fN, ya_g_f, ya_g_s, ya_g_n, Siso, Dm, Ja); // Viscous 2nd Piola-Kirchhoff stress and tangent contributions - static Array Svis(3,3); + static mat_models::Matrix<3> Svis; static Array3 Kvis_u, Kvis_v; if (Kvis_u.ncols() != eNoNw) { Kvis_u.resize(9, eNoNw, eNoNw); @@ -1336,11 +1331,11 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, } // Total isochoric 2nd Piola-Kirchhoff stress (Elastic + Viscous) - Siso = Siso + Svis; + Siso += Svis; // Deviatoric 1st Piola-Kirchhoff tensor (P) // - auto Pdev = mat_fun::mat_mul(F, Siso); + const mat_models::Matrix<3> Pdev = F * Siso; // Shape function gradients in the current configuration // @@ -1353,7 +1348,7 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, } // Velocity gradient in current configuration - auto VxFi = mat_mul(vx, Fi); + const mat_models::Matrix<3> VxFi = vx * Fi; double rC = beta*pd + VxFi(0,0) + VxFi(1,1) + VxFi(2,2); double rCl = -p + tauC*rC; @@ -1423,11 +1418,11 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, double NxSNx{0.0}, BtDB{0.0}; double Tv{0.0}, Ku{0.0}; - Array DBm(6,3); + Eigen::Matrix DBm; for (int b = 0; b < eNoNw; b++) { - mat_mul(Dm, Bm.rslice(b), DBm); + DBm.noalias() = Dm * Eigen::Map>(Bm.slice_data(b)); for (int a = 0; a < eNoNw; a++) { NxSNx = Nwx(0,a)*Siso(0,0)*Nwx(0,b) From 368df7cba5d51ee082080292fe8a05708f0c9593 Mon Sep 17 00:00:00 2001 From: dseyler Date: Mon, 21 Sep 2026 14:08:19 -0700 Subject: [PATCH 19/42] Fixed typos --- Code/Source/solver/fsi.cpp | 2 +- Code/Source/solver/mat_fun.h | 1 + Code/Source/solver/mat_models.cpp | 14 +++++++------- Code/Source/solver/sv_struct.cpp | 4 ++-- Code/Source/solver/ustruct.cpp | 2 +- 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/Code/Source/solver/fsi.cpp b/Code/Source/solver/fsi.cpp index c79ea24f2..e674705eb 100644 --- a/Code/Source/solver/fsi.cpp +++ b/Code/Source/solver/fsi.cpp @@ -186,7 +186,7 @@ void construct_fsi(ComMod& com_mod, CepMod& cep_mod, const mshType& lM, const So } } - // Shape function gradients and the viscous response, are constant + // Shape function gradients and the viscous response are constant // within linear simplex elements (tetrahedra, triangles). Bi- and // trilinear hexahedra are sometimes called linear but do not qualify. const bool recompute_visc = (g == 0 || !fs_1[0].lShpF); diff --git a/Code/Source/solver/mat_fun.h b/Code/Source/solver/mat_fun.h index 04f253b44..3396854e2 100644 --- a/Code/Source/solver/mat_fun.h +++ b/Code/Source/solver/mat_fun.h @@ -312,6 +312,7 @@ namespace mat_fun { // Compute the symmetric product: C_ijkl = 0.5 * (A_ik * B_jl + A_il * B_jk) for (int l = 0; l < nsd; ++l) { for (int k = 0; k < nsd; ++k) { + // blk views the (k,l) block of C, so blk(i,j) is C(i,j,k,l). Eigen::Map> blk(C.data() + nsd * nsd * (k + nsd * l)); blk.noalias() = 0.5 * (A.col(k) * B.col(l).transpose() + A.col(l) * B.col(k).transpose()); diff --git a/Code/Source/solver/mat_models.cpp b/Code/Source/solver/mat_models.cpp index 85c01d094..fcba6e9bb 100644 --- a/Code/Source/solver/mat_models.cpp +++ b/Code/Source/solver/mat_models.cpp @@ -814,12 +814,6 @@ void compute_pk2cc(const ComMod &com_mod, const CepMod &cep_mod, cc_to_voigt_eigen(CC, Dm); } -/** - * @brief Get the 2nd Piola-Kirchhoff stress tensor and material elasticity tensor. - * - * This is a wrapper function for the templated function compute_pk2cc. - * - */ // The element routines know their dimension at compile time and call the // template directly, so instantiate the dimensions the solver supports. Keep // this next to the definition: a signature change here that is not mirrored @@ -832,6 +826,12 @@ template void compute_pk2cc<3>(const ComMod&, const CepMod&, const dmnType&, const Matrix<3>&, const int, const Array&, const double, const double, const double, Matrix<3>&, Matrix<6>&, double&); +/** + * @brief Get the 2nd Piola-Kirchhoff stress tensor and material elasticity tensor. + * + * This is a wrapper function for the templated function compute_pk2cc. + * + */ void compute_pk2cc(const ComMod& com_mod, const CepMod& cep_mod, const dmnType& lDmn, const Array& F, const int nfd, const Array& fl, const double ya_f, const double ya_s, const double ya_n, Array& S, Array& Dm, double& Ja) { @@ -1562,7 +1562,7 @@ namespace { * @brief Viscous PK2 stress and tangent contributions for the viscous * pseudo-potential model. * - * This is defined by a viscous pseuo-potential + * This is defined by a viscous pseudo-potential * Psi = mu/2 * tr(E_dot^2) * The viscous 2nd Piola-Kirchhoff stress is given by * Svis = dPsi/dE_dot diff --git a/Code/Source/solver/sv_struct.cpp b/Code/Source/solver/sv_struct.cpp index ec2586700..72873076e 100644 --- a/Code/Source/solver/sv_struct.cpp +++ b/Code/Source/solver/sv_struct.cpp @@ -462,7 +462,7 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, } // Reuse the previous Gauss point's viscous contributions when shape function - // gradients are constant wihtin an element (e.g. linear triangles, tetrahedra). + // gradients are constant within an element (e.g. linear triangles, tetrahedra). if (recompute_visc) { mat_models::compute_visc_stress_and_tangent(dmn, eNoN, Nx, vx, F, Svis, Kvis_u, Kvis_v); } @@ -690,7 +690,7 @@ void struct_3d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, } // Reuse the previous Gauss point's viscous contributions when shape function - // gradients are constant wihtin an element (e.g. linear triangles, tetrahedra). + // gradients are constant within an element (e.g. linear triangles, tetrahedra). if (recompute_visc) { mat_models::compute_visc_stress_and_tangent(dmn, eNoN, Nx, vx, F, Svis, Kvis_u, Kvis_v); } diff --git a/Code/Source/solver/ustruct.cpp b/Code/Source/solver/ustruct.cpp index 89aa1db4a..221f3efd2 100644 --- a/Code/Source/solver/ustruct.cpp +++ b/Code/Source/solver/ustruct.cpp @@ -1032,7 +1032,7 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, // Velocity gradient in current configuration const mat_models::Matrix<2> VxFi = vx * Fi; - double rC = beta*pd + VxFi(1,1) + VxFi(2,2); + double rC = beta*pd + VxFi(0,0) + VxFi(1,1); double rCl = -p + tauC*rC; // Local residual From 8ea22ae0f114a5f6421933f5c6021f0a3027261f Mon Sep 17 00:00:00 2001 From: dseyler Date: Mon, 21 Sep 2026 14:21:05 -0700 Subject: [PATCH 20/42] max number of nodes = 27 defined in consts.h --- Code/Source/solver/consts.h | 2 ++ Code/Source/solver/fluid.cpp | 20 +++++++------------- Code/Source/solver/mat_models.h | 6 ++---- 3 files changed, 11 insertions(+), 17 deletions(-) diff --git a/Code/Source/solver/consts.h b/Code/Source/solver/consts.h index 507ae8bdb..022626e79 100644 --- a/Code/Source/solver/consts.h +++ b/Code/Source/solver/consts.h @@ -18,6 +18,8 @@ namespace consts { const int maxNSD = 3; +const int maxNoN = 27; + const int maxNProp = 20; const int maxOutput = 5; diff --git a/Code/Source/solver/fluid.cpp b/Code/Source/solver/fluid.cpp index c0ef6eb65..9f151368c 100644 --- a/Code/Source/solver/fluid.cpp +++ b/Code/Source/solver/fluid.cpp @@ -1456,9 +1456,6 @@ void fluid_3d_c(ComMod& com_mod, const int vmsFlag, const int eNoNw, const int e double start_time = utils::cput(); #endif - // Maximum size of arrays sized by (3,eNoNw) -> (3,MAX_SIZE). - const int MAX_SIZE = 27; - using namespace consts; int cEq = com_mod.cEq; @@ -1583,7 +1580,7 @@ void fluid_3d_c(ComMod& com_mod, const int vmsFlag, const int eNoNw, const int e es[1][2] = es[2][1]; es[2][0] = es[0][2]; - double esNx[3][MAX_SIZE]; + double esNx[3][maxNoN]; for (int a = 0; a < eNoNw; a++) { esNx[0][a] = es[0][0]*Nwx(0,a) + es[1][0]*Nwx(1,a) + es[2][0]*Nwx(2,a); @@ -1647,7 +1644,7 @@ void fluid_3d_c(ComMod& com_mod, const int vmsFlag, const int eNoNw, const int e // Stabilization parameters // double up[3] = {}; - double updu[3][3][MAX_SIZE] = {}; + double updu[3][3][maxNoN] = {}; double tauM = 0.0; if (vmsFlag) { @@ -1782,9 +1779,6 @@ void fluid_3d_m(ComMod& com_mod, const int vmsFlag, const int eNoNw, const int e double start_time = utils::cput(); #endif - // Maximum size of arrays sized by (3,eNoNw) -> (3,MAX_SIZE). - const int MAX_SIZE = 27; - using namespace consts; int cEq = com_mod.cEq; @@ -1927,7 +1921,7 @@ void fluid_3d_m(ComMod& com_mod, const int vmsFlag, const int eNoNw, const int e es[1][2] = es[2][1]; es[2][0] = es[0][2]; - double esNx[3][MAX_SIZE]; + double esNx[3][maxNoN]; for (int a = 0; a < eNoNw; a++) { esNx[0][a] = es[0][0]*Nwx(0,a) + es[1][0]*Nwx(1,a) + es[2][0]*Nwx(2,a); @@ -2100,10 +2094,10 @@ void fluid_3d_m(ComMod& com_mod, const int vmsFlag, const int eNoNw, const int e // Local residual // - double updu[3][3][MAX_SIZE] = {}; - double uNx[MAX_SIZE] = {}; - double upNx[MAX_SIZE] = {}; - double uaNx[MAX_SIZE] = {}; + double updu[3][3][maxNoN] = {}; + double uNx[maxNoN] = {}; + double upNx[maxNoN] = {}; + double uaNx[maxNoN] = {}; for (int a = 0; a < eNoNw; a++) { lR(0,a) = lR(0,a) + wr*Nw(a)*rV[0] + w*(Nwx(0,a)*rM[0][0] + Nwx(1,a)*rM[1][0] + Nwx(2,a)*rM[2][0]); diff --git a/Code/Source/solver/mat_models.h b/Code/Source/solver/mat_models.h index 10a98d982..1ab383788 100644 --- a/Code/Source/solver/mat_models.h +++ b/Code/Source/solver/mat_models.h @@ -8,6 +8,7 @@ #include "CepMod.h" #include "ComMod.h" #include "Tensor4.h" +#include "consts.h" #include "mat_fun.h" @@ -17,9 +18,6 @@ namespace mat_models { -/// @brief Largest element node count the bounded views below allow (HEX27). -constexpr int MAX_ELEMENT_NODES = 27; - /// @brief A second order tensor, nsd x nsd. template using Matrix = Eigen::Matrix; @@ -32,7 +30,7 @@ using Tensor = Eigen::TensorFixedSize>; /// template using NodalMatrix = - Eigen::Matrix; + Eigen::Matrix; void actv_strain(const ComMod& com_mod, const CepMod& cep_mod, const double gf, const int nfd, const Array& fl, Array& Fa); From 8dc84f5a0bc1a5178090b04771efe544d713423a Mon Sep 17 00:00:00 2001 From: dseyler Date: Mon, 21 Sep 2026 15:13:53 -0700 Subject: [PATCH 21/42] Consolidate Matrix aliases into mat_fun --- Code/Source/solver/mat_fun.h | 4 +-- Code/Source/solver/mat_models.cpp | 7 +++++ Code/Source/solver/mat_models.h | 16 ++--------- Code/Source/solver/sv_struct.cpp | 20 +++++++------- Code/Source/solver/ustruct.cpp | 44 +++++++++++++++---------------- 5 files changed, 43 insertions(+), 48 deletions(-) diff --git a/Code/Source/solver/mat_fun.h b/Code/Source/solver/mat_fun.h index 3396854e2..3b3a08454 100644 --- a/Code/Source/solver/mat_fun.h +++ b/Code/Source/solver/mat_fun.h @@ -22,10 +22,10 @@ // namespace mat_fun { // Define templated type aliases for Eigen matrices and tensors for convenience - template + template using Matrix = Eigen::Matrix; - template + template using Tensor = Eigen::TensorFixedSize>; // Function to convert Array to Eigen::Matrix diff --git a/Code/Source/solver/mat_models.cpp b/Code/Source/solver/mat_models.cpp index fcba6e9bb..353944e43 100644 --- a/Code/Source/solver/mat_models.cpp +++ b/Code/Source/solver/mat_models.cpp @@ -5,6 +5,7 @@ #include "mat_models.h" +#include "consts.h" #include "mat_fun.h" #include "utils.h" #include "ArtificialNeuralNetMaterial.h" @@ -1558,6 +1559,12 @@ void g_vol_pen(const ComMod& com_mod, const dmnType& lDmn, const double p, namespace { +/// @brief A quantity carrying one nsd-vector per element node, so nsd x eNoN. +/// +template +using NodalMatrix = + Eigen::Matrix; + /** * @brief Viscous PK2 stress and tangent contributions for the viscous * pseudo-potential model. diff --git a/Code/Source/solver/mat_models.h b/Code/Source/solver/mat_models.h index 1ab383788..9dec5acf9 100644 --- a/Code/Source/solver/mat_models.h +++ b/Code/Source/solver/mat_models.h @@ -8,7 +8,6 @@ #include "CepMod.h" #include "ComMod.h" #include "Tensor4.h" -#include "consts.h" #include "mat_fun.h" @@ -18,19 +17,8 @@ namespace mat_models { -/// @brief A second order tensor, nsd x nsd. -template -using Matrix = Eigen::Matrix; - -/// @brief A 4th order tensor, nsd x nsd x nsd x nsd. -template -using Tensor = Eigen::TensorFixedSize>; - -/// @brief A quantity carrying one nsd-vector per element node, so nsd x eNoN. -/// -template -using NodalMatrix = - Eigen::Matrix; +using mat_fun::Matrix; +using mat_fun::Tensor; void actv_strain(const ComMod& com_mod, const CepMod& cep_mod, const double gf, const int nfd, const Array& fl, Array& Fa); diff --git a/Code/Source/solver/sv_struct.cpp b/Code/Source/solver/sv_struct.cpp index 72873076e..448e47951 100644 --- a/Code/Source/solver/sv_struct.cpp +++ b/Code/Source/solver/sv_struct.cpp @@ -402,7 +402,7 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, // Inertia, body force and deformation tensor (F) // - mat_models::Matrix<2> F, S0, vx; + Matrix<2> F, S0, vx; Vector ud(2); ud = -rho*fb; @@ -447,14 +447,14 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, S0(1,0) = S0(0,1); // 2nd Piola-Kirchhoff stress (S) and material stiffness tensor in Voight notation (Dm) - mat_models::Matrix<2> S; - mat_models::Matrix<3> Dm; + Matrix<2> S; + Matrix<3> Dm; double Ja; mat_models::compute_pk2cc(com_mod, cep_mod, dmn, F, nFn, fN, ya_g_f, ya_g_s, ya_g_n, S, Dm, Ja); // Viscous 2nd Piola-Kirchhoff stress and tangent contributions - static mat_models::Matrix<2> Svis; + static Matrix<2> Svis; static Array3 Kvis_u, Kvis_v; if (Kvis_u.ncols() != eNoN) { Kvis_u.resize(4, eNoN, eNoN); @@ -480,7 +480,7 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, // 1st Piola-Kirchhoff tensor (P) // - mat_models::Matrix<2> P; + Matrix<2> P; Array DBm(3,2); Array3 Bm(3,2,eNoN); P.noalias() = F * S; @@ -614,7 +614,7 @@ void struct_3d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, // Inertia, body force and deformation tensor (F) // - mat_models::Matrix<3> F, S0, vx; + Matrix<3> F, S0, vx; Vector ud(3); double F_f[3][3]={}; @@ -675,14 +675,14 @@ void struct_3d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, // 2nd Piola-Kirchhoff tensor (S) and material stiffness tensor in // Voigt notationa (Dm) // - mat_models::Matrix<3> S; - mat_models::Matrix<6> Dm; + Matrix<3> S; + Matrix<6> Dm; double Ja; mat_models::compute_pk2cc(com_mod, cep_mod, dmn, F, nFn, fN, ya_g_f, ya_g_s, ya_g_n, S, Dm, Ja); // Viscous 2nd Piola-Kirchhoff stress and tangent contributions - static mat_models::Matrix<3> Svis; + static Matrix<3> Svis; static Array3 Kvis_u, Kvis_v; if (Kvis_u.ncols() != eNoN) { Kvis_u.resize(9, eNoN, eNoN); @@ -719,7 +719,7 @@ void struct_3d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, // 1st Piola-Kirchhoff tensor (P) // - mat_models::Matrix<3> P; + Matrix<3> P; Array3 Bm(6,3,eNoN); P.noalias() = F * S; diff --git a/Code/Source/solver/ustruct.cpp b/Code/Source/solver/ustruct.cpp index 221f3efd2..36391aad9 100644 --- a/Code/Source/solver/ustruct.cpp +++ b/Code/Source/solver/ustruct.cpp @@ -479,8 +479,8 @@ void ustruct_2d_c(ComMod& com_mod, CepMod& cep_mod, const bool vmsFlag, const in // Vector vd{-fb[0], -fb[1]}; Vector v(2); - mat_models::Matrix<2> vx = mat_models::Matrix<2>::Zero(); - mat_models::Matrix<2> F = mat_models::Matrix<2>::Identity(); + Matrix<2> vx = Matrix<2>::Zero(); + Matrix<2> F = Matrix<2>::Identity(); for (int a = 0; a < eNoNw; a++) { v(0) = v(0) + Nw(a)*yl(i,a); @@ -501,7 +501,7 @@ void ustruct_2d_c(ComMod& com_mod, CepMod& cep_mod, const bool vmsFlag, const in } double Jac = F.determinant(); - const mat_models::Matrix<2> Fi = F.inverse(); + const Matrix<2> Fi = F.inverse(); // Pressure and its gradients // @@ -683,8 +683,8 @@ void ustruct_3d_c(ComMod& com_mod, CepMod& cep_mod, const bool vmsFlag, const in // Vector vd{-fb[0], -fb[1], -fb[2]}; Vector v(3); - mat_models::Matrix<3> vx = mat_models::Matrix<3>::Zero(); - mat_models::Matrix<3> F = mat_models::Matrix<3>::Identity(); + Matrix<3> vx = Matrix<3>::Zero(); + Matrix<3> F = Matrix<3>::Identity(); for (int a = 0; a < eNoNw; a++) { v(0) = v(0) + Nw(a)*yl(i,a); @@ -721,7 +721,7 @@ void ustruct_3d_c(ComMod& com_mod, CepMod& cep_mod, const bool vmsFlag, const in } double Jac = F.determinant(); - const mat_models::Matrix<3> Fi = F.inverse(); + const Matrix<3> Fi = F.inverse(); // Pressure and its gradients // @@ -929,8 +929,8 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, // Vector vd{-fb[0], -fb[1]}; Vector v(2); - mat_models::Matrix<2> vx = mat_models::Matrix<2>::Zero(); - mat_models::Matrix<2> F = mat_models::Matrix<2>::Identity(); + Matrix<2> vx = Matrix<2>::Zero(); + Matrix<2> F = Matrix<2>::Identity(); double ya_g_f = 0.0; double ya_g_s = 0.0; @@ -960,7 +960,7 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, } double Jac = F.determinant(); - const mat_models::Matrix<2> Fi = F.inverse(); + const Matrix<2> Fi = F.inverse(); // Pressure and its time derivative // @@ -974,14 +974,14 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, // Compute deviatoric 2nd Piola-Kirchhoff stress tensor (Siso) and // isochoric elasticity tensor in Voigt notation (Dm) - mat_models::Matrix<2> Siso; - mat_models::Matrix<3> Dm; + Matrix<2> Siso; + Matrix<3> Dm; double Ja = 0; mat_models::compute_pk2cc(com_mod, cep_mod, eq.dmn[cDmn], F, nFn, fN, ya_g_f, ya_g_s, ya_g_n, Siso, Dm, Ja); // Viscous 2nd Piola-Kirchhoff stress and tangent contributions - static mat_models::Matrix<2> Svis; + static Matrix<2> Svis; static Array3 Kvis_u, Kvis_v; if (Kvis_u.ncols() != eNoNw) { Kvis_u.resize(4, eNoNw, eNoNw); @@ -1018,7 +1018,7 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, // Deviatoric 1st Piola-Kirchhoff tensor (P) // - const mat_models::Matrix<2> Pdev = F * Siso; + const Matrix<2> Pdev = F * Siso; // Shape function gradients in the current configuration @@ -1031,7 +1031,7 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, } // Velocity gradient in current configuration - const mat_models::Matrix<2> VxFi = vx * Fi; + const Matrix<2> VxFi = vx * Fi; double rC = beta*pd + VxFi(0,0) + VxFi(1,1); double rCl = -p + tauC*rC; @@ -1230,8 +1230,8 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, // Vector vd{-fb[0], -fb[1], -fb[2]}; Vector v(3); - mat_models::Matrix<3> vx = mat_models::Matrix<3>::Zero(); - mat_models::Matrix<3> F = mat_models::Matrix<3>::Identity(); + Matrix<3> vx = Matrix<3>::Zero(); + Matrix<3> F = Matrix<3>::Identity(); double ya_g_f = 0.0; double ya_g_s = 0.0; @@ -1276,7 +1276,7 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, } double Jac = F.determinant(); - const mat_models::Matrix<3> Fi = F.inverse(); + const Matrix<3> Fi = F.inverse(); // Pressure and its time derivative // @@ -1291,14 +1291,14 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, // Compute deviatoric 2nd Piola-Kirchhoff stress tensor (Siso) and // isochoric elasticity tensor in Voigt notation (Dm) // - mat_models::Matrix<3> Siso; - mat_models::Matrix<6> Dm; + Matrix<3> Siso; + Matrix<6> Dm; double Ja = 0; mat_models::compute_pk2cc(com_mod, cep_mod, eq.dmn[cDmn], F, nFn, fN, ya_g_f, ya_g_s, ya_g_n, Siso, Dm, Ja); // Viscous 2nd Piola-Kirchhoff stress and tangent contributions - static mat_models::Matrix<3> Svis; + static Matrix<3> Svis; static Array3 Kvis_u, Kvis_v; if (Kvis_u.ncols() != eNoNw) { Kvis_u.resize(9, eNoNw, eNoNw); @@ -1335,7 +1335,7 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, // Deviatoric 1st Piola-Kirchhoff tensor (P) // - const mat_models::Matrix<3> Pdev = F * Siso; + const Matrix<3> Pdev = F * Siso; // Shape function gradients in the current configuration // @@ -1348,7 +1348,7 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, } // Velocity gradient in current configuration - const mat_models::Matrix<3> VxFi = vx * Fi; + const Matrix<3> VxFi = vx * Fi; double rC = beta*pd + VxFi(0,0) + VxFi(1,1) + VxFi(2,2); double rCl = -p + tauC*rC; From c6d372776b957ec76ca53a071582e9e838be7387 Mon Sep 17 00:00:00 2001 From: dseyler Date: Mon, 21 Sep 2026 19:39:58 -0700 Subject: [PATCH 22/42] refactor Bm as per-node Eigen blocks --- Code/Source/solver/sv_struct.cpp | 137 +++++++++++-------------------- Code/Source/solver/ustruct.cpp | 137 +++++++++++-------------------- 2 files changed, 97 insertions(+), 177 deletions(-) diff --git a/Code/Source/solver/sv_struct.cpp b/Code/Source/solver/sv_struct.cpp index 448e47951..f93116fb2 100644 --- a/Code/Source/solver/sv_struct.cpp +++ b/Code/Source/solver/sv_struct.cpp @@ -17,6 +17,8 @@ #include "utils.h" #include "DebugMsg.h" +#include + namespace struct_ns { void b_struct_2d(const ComMod& com_mod, const int eNoN, const double w, const Vector& N, @@ -481,8 +483,8 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, // 1st Piola-Kirchhoff tensor (P) // Matrix<2> P; - Array DBm(3,2); - Array3 Bm(3,2,eNoN); + Eigen::Matrix DBm; + std::array, consts::maxNoN> Bm; P.noalias() = F * S; #ifdef debug_struct_2d dmsg << "P: " << P(0,0) << " " << P(0,1); @@ -495,17 +497,17 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, lR(1,a) = lR(1,a) + w*(N(a)*ud(1) + Nx(0,a)*P(1,0) + Nx(1,a)*P(1,1)); } - // Auxilary quantities for computing stiffness tensor + // Strain-displacement matrix; Bm[a] maps node a displacement to Voigt strain // for (int a = 0; a < eNoN; a++) { - Bm(0,0,a) = Nx(0,a)*F(0,0); - Bm(0,1,a) = Nx(0,a)*F(1,0); + Bm[a](0,0) = Nx(0,a)*F(0,0); + Bm[a](0,1) = Nx(0,a)*F(1,0); - Bm(1,0,a) = Nx(1,a)*F(0,1); - Bm(1,1,a) = Nx(1,a)*F(1,1); + Bm[a](1,0) = Nx(1,a)*F(0,1); + Bm[a](1,1) = Nx(1,a)*F(1,1); - Bm(2,0,a) = (Nx(0,a)*F(0,1) + F(0,0)*Nx(1,a)); - Bm(2,1,a) = (Nx(0,a)*F(1,1) + F(1,0)*Nx(1,a)); + Bm[a](2,0) = (Nx(0,a)*F(0,1) + F(0,0)*Nx(1,a)); + Bm[a](2,1) = (Nx(0,a)*F(1,1) + F(1,0)*Nx(1,a)); } Array NxFi(2,eNoN), DdNx(2,eNoN), VxNx(2,eNoN); @@ -515,15 +517,8 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, for (int b = 0; b < eNoN; b++) { - // Material stiffness (Bt*D*B) - DBm(0,0) = Dm(0,0)*Bm(0,0,b) + Dm(0,1)*Bm(1,0,b) + Dm(0,2)*Bm(2,0,b); - DBm(0,1) = Dm(0,0)*Bm(0,1,b) + Dm(0,1)*Bm(1,1,b) + Dm(0,2)*Bm(2,1,b); - - DBm(1,0) = Dm(1,0)*Bm(0,0,b) + Dm(1,1)*Bm(1,0,b) + Dm(1,2)*Bm(2,0,b); - DBm(1,1) = Dm(1,0)*Bm(0,1,b) + Dm(1,1)*Bm(1,1,b) + Dm(1,2)*Bm(2,1,b); - - DBm(2,0) = Dm(2,0)*Bm(0,0,b) + Dm(2,1)*Bm(1,0,b) + Dm(2,2)*Bm(2,0,b); - DBm(2,1) = Dm(2,0)*Bm(0,1,b) + Dm(2,1)*Bm(1,1,b) + Dm(2,2)*Bm(2,1,b); + // Material stiffness (D*B) for node b + DBm.noalias() = Dm * Bm[b]; for (int a = 0; a < eNoN; a++) { @@ -534,26 +529,22 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, // dM1/du1 - // Material stiffness: Bt*D*B - BmDBm = Bm(0,0,a)*DBm(0,0) + Bm(1,0,a)*DBm(1,0) + Bm(2,0,a)*DBm(2,0); + BmDBm = Bm[a].col(0).dot(DBm.col(0)); lK(0,a,b) = lK(0,a,b) + w*( T1 + afu*(BmDBm + Kvis_u(0,a,b)) + afv*Kvis_v(0,a,b) ); // dM1/du2 - // Material stiffness: Bt*D*B - BmDBm = Bm(0,0,a)*DBm(0,1) + Bm(1,0,a)*DBm(1,1) + Bm(2,0,a)*DBm(2,1); + BmDBm = Bm[a].col(0).dot(DBm.col(1)); lK(1,a,b) = lK(1,a,b) + w*( afu*(BmDBm + Kvis_u(1,a,b)) + afv*Kvis_v(1,a,b) ); // dM2/du1 - // Material stiffness: Bt*D*B - BmDBm = Bm(0,1,a)*DBm(0,0) + Bm(1,1,a)*DBm(1,0) + Bm(2,1,a)*DBm(2,0); + BmDBm = Bm[a].col(1).dot(DBm.col(0)); lK(dof+0,a,b) = lK(dof+0,a,b) + w*( afu*(BmDBm + Kvis_u(2,a,b)) + afv*Kvis_v(2,a,b) ); // dM2/du2 - // Material stiffness: Bt*D*B - BmDBm = Bm(0,1,a)*DBm(0,1) + Bm(1,1,a)*DBm(1,1) + Bm(2,1,a)*DBm(2,1); + BmDBm = Bm[a].col(1).dot(DBm.col(1)); lK(dof+1,a,b) = lK(dof+1,a,b) + w*( T1 + afu*(BmDBm + Kvis_u(3,a,b)) + afv*Kvis_v(3,a,b) ); } @@ -720,7 +711,7 @@ void struct_3d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, // 1st Piola-Kirchhoff tensor (P) // Matrix<3> P; - Array3 Bm(6,3,eNoN); + std::array, consts::maxNoN> Bm; P.noalias() = F * S; // Local residual @@ -730,45 +721,43 @@ void struct_3d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, lR(2,a) = lR(2,a) + w*(N(a)*ud(2) + Nx(0,a)*P(2,0) + Nx(1,a)*P(2,1) + Nx(2,a)*P(2,2)); } - // Auxilary quantities for computing stiffness tensor + // Strain-displacement matrix; Bm[a] maps node a displacement to Voigt strain // for (int a = 0; a < eNoN; a++) { - Bm(0,0,a) = Nx(0,a)*F(0,0); - Bm(0,1,a) = Nx(0,a)*F(1,0); - Bm(0,2,a) = Nx(0,a)*F(2,0); + Bm[a](0,0) = Nx(0,a)*F(0,0); + Bm[a](0,1) = Nx(0,a)*F(1,0); + Bm[a](0,2) = Nx(0,a)*F(2,0); - Bm(1,0,a) = Nx(1,a)*F(0,1); - Bm(1,1,a) = Nx(1,a)*F(1,1); - Bm(1,2,a) = Nx(1,a)*F(2,1); + Bm[a](1,0) = Nx(1,a)*F(0,1); + Bm[a](1,1) = Nx(1,a)*F(1,1); + Bm[a](1,2) = Nx(1,a)*F(2,1); - Bm(2,0,a) = Nx(2,a)*F(0,2); - Bm(2,1,a) = Nx(2,a)*F(1,2); - Bm(2,2,a) = Nx(2,a)*F(2,2); + Bm[a](2,0) = Nx(2,a)*F(0,2); + Bm[a](2,1) = Nx(2,a)*F(1,2); + Bm[a](2,2) = Nx(2,a)*F(2,2); - Bm(3,0,a) = (Nx(0,a)*F(0,1) + F(0,0)*Nx(1,a)); - Bm(3,1,a) = (Nx(0,a)*F(1,1) + F(1,0)*Nx(1,a)); - Bm(3,2,a) = (Nx(0,a)*F(2,1) + F(2,0)*Nx(1,a)); + Bm[a](3,0) = (Nx(0,a)*F(0,1) + F(0,0)*Nx(1,a)); + Bm[a](3,1) = (Nx(0,a)*F(1,1) + F(1,0)*Nx(1,a)); + Bm[a](3,2) = (Nx(0,a)*F(2,1) + F(2,0)*Nx(1,a)); - Bm(4,0,a) = (Nx(1,a)*F(0,2) + F(0,1)*Nx(2,a)); - Bm(4,1,a) = (Nx(1,a)*F(1,2) + F(1,1)*Nx(2,a)); - Bm(4,2,a) = (Nx(1,a)*F(2,2) + F(2,1)*Nx(2,a)); + Bm[a](4,0) = (Nx(1,a)*F(0,2) + F(0,1)*Nx(2,a)); + Bm[a](4,1) = (Nx(1,a)*F(1,2) + F(1,1)*Nx(2,a)); + Bm[a](4,2) = (Nx(1,a)*F(2,2) + F(2,1)*Nx(2,a)); - Bm(5,0,a) = (Nx(2,a)*F(0,0) + F(0,2)*Nx(0,a)); - Bm(5,1,a) = (Nx(2,a)*F(1,0) + F(1,2)*Nx(0,a)); - Bm(5,2,a) = (Nx(2,a)*F(2,0) + F(2,2)*Nx(0,a)); + Bm[a](5,0) = (Nx(2,a)*F(0,0) + F(0,2)*Nx(0,a)); + Bm[a](5,1) = (Nx(2,a)*F(1,0) + F(1,2)*Nx(0,a)); + Bm[a](5,2) = (Nx(2,a)*F(2,0) + F(2,2)*Nx(0,a)); } // Local stiffness tensor double NxSNx, T1, NxNx, BmDBm, Tv; - Array DBm(6,3); + Eigen::Matrix DBm; for (int b = 0; b < eNoN; b++) { - // Material stiffness (D*B) for node b. Dm is Eigen and Bm/DBm are Arrays, - // so view them; this is what mat_mul<6,6,3> did internally. - Eigen::Map> dbm(DBm.data()); - dbm.noalias() = Dm * Eigen::Map>(Bm.slice_data(b)); + // Material stiffness (D*B) for node b + DBm.noalias() = Dm * Bm[b]; for (int a = 0; a < eNoN; a++) { @@ -782,75 +771,47 @@ void struct_3d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, T1 = amd*N(a)*N(b) + afu*NxSNx; // dM1/du1 - // Material stiffness: Bt*D*B - BmDBm = Bm(0,0,a)*DBm(0,0) + Bm(1,0,a)*DBm(1,0) + - Bm(2,0,a)*DBm(2,0) + Bm(3,0,a)*DBm(3,0) + - Bm(4,0,a)*DBm(4,0) + Bm(5,0,a)*DBm(5,0); + BmDBm = Bm[a].col(0).dot(DBm.col(0)); lK(0,a,b) = lK(0,a,b) + w*( T1 + afu*(BmDBm + Kvis_u(0,a,b)) + afv*Kvis_v(0,a,b) ); // dM1/du2 - // Material stiffness: Bt*D*B - BmDBm = Bm(0,0,a)*DBm(0,1) + Bm(1,0,a)*DBm(1,1) + - Bm(2,0,a)*DBm(2,1) + Bm(3,0,a)*DBm(3,1) + - Bm(4,0,a)*DBm(4,1) + Bm(5,0,a)*DBm(5,1); - + BmDBm = Bm[a].col(0).dot(DBm.col(1)); lK(1,a,b) = lK(1,a,b) + w*( afu*(BmDBm + Kvis_u(1,a,b)) + afv*(Kvis_v(1,a,b)) ); // dM1/du3 - // Material stiffness: Bt*D*B - BmDBm = Bm(0,0,a)*DBm(0,2) + Bm(1,0,a)*DBm(1,2) + - Bm(2,0,a)*DBm(2,2) + Bm(3,0,a)*DBm(3,2) + - Bm(4,0,a)*DBm(4,2) + Bm(5,0,a)*DBm(5,2); + BmDBm = Bm[a].col(0).dot(DBm.col(2)); lK(2,a,b) = lK(2,a,b) + w*( afu*(BmDBm + Kvis_u(2,a,b)) + afv*Kvis_v(2,a,b) ); // dM2/du1 - // Material stiffness: Bt*D*B - BmDBm = Bm(0,1,a)*DBm(0,0) + Bm(1,1,a)*DBm(1,0) + - Bm(2,1,a)*DBm(2,0) + Bm(3,1,a)*DBm(3,0) + - Bm(4,1,a)*DBm(4,0) + Bm(5,1,a)*DBm(5,0); + BmDBm = Bm[a].col(1).dot(DBm.col(0)); lK(dof+0,a,b) = lK(dof+0,a,b) + w*( afu*(BmDBm + Kvis_u(3,a,b)) + afv*Kvis_v(3,a,b) ); // dM2/du2 - // Material stiffness: Bt*D*B - BmDBm = Bm(0,1,a)*DBm(0,1) + Bm(1,1,a)*DBm(1,1) + - Bm(2,1,a)*DBm(2,1) + Bm(3,1,a)*DBm(3,1) + - Bm(4,1,a)*DBm(4,1) + Bm(5,1,a)*DBm(5,1); + BmDBm = Bm[a].col(1).dot(DBm.col(1)); lK(dof+1,a,b) = lK(dof+1,a,b) + w*(T1 + afu*(BmDBm + Kvis_u(4,a,b)) + afv*Kvis_v(4,a,b) ); // dM2/du3 - // Material stiffness: Bt*D*B - BmDBm = Bm(0,1,a)*DBm(0,2) + Bm(1,1,a)*DBm(1,2) + - Bm(2,1,a)*DBm(2,2) + Bm(3,1,a)*DBm(3,2) + - Bm(4,1,a)*DBm(4,2) + Bm(5,1,a)*DBm(5,2); + BmDBm = Bm[a].col(1).dot(DBm.col(2)); lK(dof+2,a,b) = lK(dof+2,a,b) + w*( afu*(BmDBm + Kvis_u(5,a,b)) + afv*Kvis_v(5,a,b) ); // dM3/du1 - // Material stiffness: Bt*D*B - BmDBm = Bm(0,2,a)*DBm(0,0) + Bm(1,2,a)*DBm(1,0) + - Bm(2,2,a)*DBm(2,0) + Bm(3,2,a)*DBm(3,0) + - Bm(4,2,a)*DBm(4,0) + Bm(5,2,a)*DBm(5,0); + BmDBm = Bm[a].col(2).dot(DBm.col(0)); lK(2*dof+0,a,b) = lK(2*dof+0,a,b) + w*( afu*(BmDBm + Kvis_u(6,a,b)) + afv*Kvis_v(6,a,b) ); // dM3/du2 - // Material stiffness: Bt*D*B - BmDBm = Bm(0,2,a)*DBm(0,1) + Bm(1,2,a)*DBm(1,1) + - Bm(2,2,a)*DBm(2,1) + Bm(3,2,a)*DBm(3,1) + - Bm(4,2,a)*DBm(4,1) + Bm(5,2,a)*DBm(5,1); + BmDBm = Bm[a].col(2).dot(DBm.col(1)); lK(2*dof+1,a,b) = lK(2*dof+1,a,b) + w*( afu*(BmDBm + Kvis_u(7,a,b)) + afv*Kvis_v(7,a,b) ); // dM3/du3 - // Material stiffness: Bt*D*B - BmDBm = Bm(0,2,a)*DBm(0,2) + Bm(1,2,a)*DBm(1,2) + - Bm(2,2,a)*DBm(2,2) + Bm(3,2,a)*DBm(3,2) + - Bm(4,2,a)*DBm(4,2) + Bm(5,2,a)*DBm(5,2); + BmDBm = Bm[a].col(2).dot(DBm.col(2)); lK(2*dof+2,a,b) = lK(2*dof+2,a,b) + w*( T1 + afu*(BmDBm + Kvis_u(8,a,b)) + afv*Kvis_v(8,a,b) ); } diff --git a/Code/Source/solver/ustruct.cpp b/Code/Source/solver/ustruct.cpp index 36391aad9..e50070e19 100644 --- a/Code/Source/solver/ustruct.cpp +++ b/Code/Source/solver/ustruct.cpp @@ -28,6 +28,7 @@ #include "nn.h" #include "utils.h" +#include #include namespace ustruct { @@ -550,12 +551,7 @@ void ustruct_2d_c(ComMod& com_mod, CepMod& cep_mod, const bool vmsFlag, const in NqxFi(1,a) = Nqx(0,a)*Fi(0,1) + Nqx(1,a)*Fi(1,1); } - Array VxFi(2,2); - - VxFi(0,0) = vx(0,0)*Fi(0,0) + vx(0,1)*Fi(1,0); - VxFi(0,1) = vx(0,0)*Fi(0,1) + vx(0,1)*Fi(1,1); - VxFi(1,0) = vx(1,0)*Fi(0,0) + vx(1,1)*Fi(1,0); - VxFi(1,1) = vx(1,0)*Fi(0,1) + vx(1,1)*Fi(1,1); + const Matrix<2> VxFi = vx * Fi; Vector PxFi(2); PxFi(0) = px(0)*Fi(0,0) + px(1)*Fi(1,0); @@ -773,19 +769,7 @@ void ustruct_3d_c(ComMod& com_mod, CepMod& cep_mod, const bool vmsFlag, const in NqxFi(2,a) = Nqx(0,a)*Fi(0,2) + Nqx(1,a)*Fi(1,2) + Nqx(2,a)*Fi(2,2); } - Array VxFi(3,3); - - VxFi(0,0) = vx(0,0)*Fi(0,0) + vx(0,1)*Fi(1,0) + vx(0,2)*Fi(2,0); - VxFi(0,1) = vx(0,0)*Fi(0,1) + vx(0,1)*Fi(1,1) + vx(0,2)*Fi(2,1); - VxFi(0,2) = vx(0,0)*Fi(0,2) + vx(0,1)*Fi(1,2) + vx(0,2)*Fi(2,2); - - VxFi(1,0) = vx(1,0)*Fi(0,0) + vx(1,1)*Fi(1,0) + vx(1,2)*Fi(2,0); - VxFi(1,1) = vx(1,0)*Fi(0,1) + vx(1,1)*Fi(1,1) + vx(1,2)*Fi(2,1); - VxFi(1,2) = vx(1,0)*Fi(0,2) + vx(1,1)*Fi(1,2) + vx(1,2)*Fi(2,2); - - VxFi(2,0) = vx(2,0)*Fi(0,0) + vx(2,1)*Fi(1,0) + vx(2,2)*Fi(2,0); - VxFi(2,1) = vx(2,0)*Fi(0,1) + vx(2,1)*Fi(1,1) + vx(2,2)*Fi(2,1); - VxFi(2,2) = vx(2,0)*Fi(0,2) + vx(2,1)*Fi(1,2) + vx(2,2)*Fi(2,2); + const Matrix<3> VxFi = vx * Fi; Vector PxFi(3); PxFi(0) = px(0)*Fi(0,0) + px(1)*Fi(1,0) + px(2)*Fi(2,0); @@ -1049,19 +1033,19 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, lR(1,a) = lR(1,a) + w*(T1 + T2 + T3); } - // Auxilary quantities for computing stiffness tensors + // Strain-displacement matrix; Bm[a] maps node a displacement to Voigt strain // - Array3 Bm(3,2,eNoNw); + std::array, consts::maxNoN> Bm; for (int a = 0; a < eNoNw; a++) { - Bm(0,0,a) = Nwx(0,a)*F(0,0); - Bm(0,1,a) = Nwx(0,a)*F(1,0); + Bm[a](0,0) = Nwx(0,a)*F(0,0); + Bm[a](0,1) = Nwx(0,a)*F(1,0); - Bm(1,0,a) = Nwx(1,a)*F(0,1); - Bm(1,1,a) = Nwx(1,a)*F(1,1); + Bm[a](1,0) = Nwx(1,a)*F(0,1); + Bm[a](1,1) = Nwx(1,a)*F(1,1); - Bm(2,0,a) = Nwx(2,a)*F(0,2) + F(0,0)*Nwx(1,a); - Bm(2,1,a) = Nwx(2,a)*F(1,2) + F(1,0)*Nwx(1,a); + Bm[a](2,0) = Nwx(0,a)*F(0,1) + F(0,0)*Nwx(1,a); + Bm[a](2,1) = Nwx(0,a)*F(1,1) + F(1,0)*Nwx(1,a); } Array VxNx(2,eNoNw); @@ -1080,25 +1064,18 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, Eigen::Matrix DBm; for (int b = 0; b < eNoNw; b++) { + + DBm.noalias() = Dm * Bm[b]; + for (int a = 0; a < eNoNw; a++) { NxSNx = Nwx(0,a)*Siso(0,0)*Nwx(0,b) + Nwx(0,a)*Siso(0,1)*Nwx(1,b) + Nwx(1,a)*Siso(1,0)*Nwx(0,b) + Nwx(1,a)*Siso(1,1)*Nwx(1,b); - DBm(0,0) = Dm(0,0)*Bm(0,0,b) + Dm(0,1)*Bm(1,0,b) + Dm(0,2)*Bm(2,0,b); - DBm(0,1) = Dm(0,0)*Bm(0,1,b) + Dm(0,1)*Bm(1,1,b) + Dm(0,2)*Bm(2,1,b); - - DBm(1,0) = Dm(1,0)*Bm(0,0,b) + Dm(1,1)*Bm(1,0,b) + Dm(1,2)*Bm(2,0,b); - DBm(1,1) = Dm(1,0)*Bm(0,1,b) + Dm(1,1)*Bm(1,1,b) + Dm(1,2)*Bm(2,1,b); - - DBm(2,0) = Dm(2,0)*Bm(0,0,b) + Dm(2,1)*Bm(1,0,b) + Dm(2,2)*Bm(2,0,b); - DBm(2,1) = Dm(2,0)*Bm(0,1,b) + Dm(2,1)*Bm(1,1,b) + Dm(2,2)*Bm(2,1,b); - - // dM1_dV1 + af/am *dM_1/dU_1 // - BtDB = Bm(0,0,a)*DBm(0,0) + Bm(1,0,a)*DBm(1,0) + Bm(2,0,a)*DBm(2,0); + BtDB = Bm[a].col(0).dot(DBm.col(0)); T1 = Jac*rho*vd(0)*Nw(a)*NxFi(0,b); T2 = -tauC*Jac*NxFi(0,a)*VxNx(0,b); @@ -1112,7 +1089,7 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, // dM_1/dV_2 + af/am *dM_1/dU_2 // - BtDB = Bm(0,0,a)*DBm(0,1) + Bm(1,0,a)*DBm(1,1) + Bm(2,0,a)*DBm(2,1); + BtDB = Bm[a].col(0).dot(DBm.col(1)); T1 = Jac*rho*vd(0)*Nw(a)*NxFi(1,b); T2 = -tauC*Jac*NxFi(0,a)*VxNx(1,b); T3 = Jac*rCl*(NxFi(0,a)*NxFi(1,b) - NxFi(1,a)*NxFi(0,b)); @@ -1126,7 +1103,7 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, // dM_2/dV_1 + af/am *dM_2/dU_1 // - BtDB = Bm(0,1,a)*DBm(0,0) + Bm(1,1,a)*DBm(1,0) + Bm(2,1,a)*DBm(2,0); + BtDB = Bm[a].col(1).dot(DBm.col(0)); T1 = Jac*rho*vd(1)*Nw(a)*NxFi(0,b); T2 = -tauC*Jac*NxFi(1,a)*VxNx(0,b); T3 = Jac*rCl*(NxFi(1,a)*NxFi(0,b) - NxFi(0,a)*NxFi(1,b)); @@ -1140,7 +1117,7 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, // dM_2/dV_2 + af/am *dM_2/dU_2 // - BtDB = Bm(0,1,a)*DBm(0,1) + Bm(1,1,a)*DBm(1,1) + Bm(2,1,a)*DBm(2,1); + BtDB = Bm[a].col(1).dot(DBm.col(1)); T1 = Jac*rho*vd(1)*Nw(a)*NxFi(1,b); T2 = -tauC*Jac*NxFi(1,a)*VxNx(1,b); @@ -1373,34 +1350,34 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, lR(2,a) = lR(2,a) + w*(T1 + T2 + T3); } - // Auxilary quantities for computing stiffness tensors + // Strain-displacement matrix; Bm[a] maps node a displacement to Voigt strain // - Array3 Bm(6,3,eNoNw); + std::array, consts::maxNoN> Bm; for (int a = 0; a < eNoNw; a++) { - Bm(0,0,a) = Nwx(0,a)*F(0,0); - Bm(0,1,a) = Nwx(0,a)*F(1,0); - Bm(0,2,a) = Nwx(0,a)*F(2,0); + Bm[a](0,0) = Nwx(0,a)*F(0,0); + Bm[a](0,1) = Nwx(0,a)*F(1,0); + Bm[a](0,2) = Nwx(0,a)*F(2,0); - Bm(1,0,a) = Nwx(1,a)*F(0,1); - Bm(1,1,a) = Nwx(1,a)*F(1,1); - Bm(1,2,a) = Nwx(1,a)*F(2,1); + Bm[a](1,0) = Nwx(1,a)*F(0,1); + Bm[a](1,1) = Nwx(1,a)*F(1,1); + Bm[a](1,2) = Nwx(1,a)*F(2,1); - Bm(2,0,a) = Nwx(2,a)*F(0,2); - Bm(2,1,a) = Nwx(2,a)*F(1,2); - Bm(2,2,a) = Nwx(2,a)*F(2,2); + Bm[a](2,0) = Nwx(2,a)*F(0,2); + Bm[a](2,1) = Nwx(2,a)*F(1,2); + Bm[a](2,2) = Nwx(2,a)*F(2,2); - Bm(3,0,a) = (Nwx(0,a)*F(0,1) + F(0,0)*Nwx(1,a)); - Bm(3,1,a) = (Nwx(0,a)*F(1,1) + F(1,0)*Nwx(1,a)); - Bm(3,2,a) = (Nwx(0,a)*F(2,1) + F(2,0)*Nwx(1,a)); + Bm[a](3,0) = (Nwx(0,a)*F(0,1) + F(0,0)*Nwx(1,a)); + Bm[a](3,1) = (Nwx(0,a)*F(1,1) + F(1,0)*Nwx(1,a)); + Bm[a](3,2) = (Nwx(0,a)*F(2,1) + F(2,0)*Nwx(1,a)); - Bm(4,0,a) = (Nwx(1,a)*F(0,2) + F(0,1)*Nwx(2,a)); - Bm(4,1,a) = (Nwx(1,a)*F(1,2) + F(1,1)*Nwx(2,a)); - Bm(4,2,a) = (Nwx(1,a)*F(2,2) + F(2,1)*Nwx(2,a)); + Bm[a](4,0) = (Nwx(1,a)*F(0,2) + F(0,1)*Nwx(2,a)); + Bm[a](4,1) = (Nwx(1,a)*F(1,2) + F(1,1)*Nwx(2,a)); + Bm[a](4,2) = (Nwx(1,a)*F(2,2) + F(2,1)*Nwx(2,a)); - Bm(5,0,a) = (Nwx(2,a)*F(0,0) + F(0,2)*Nwx(0,a)); - Bm(5,1,a) = (Nwx(2,a)*F(1,0) + F(1,2)*Nwx(0,a)); - Bm(5,2,a) = (Nwx(2,a)*F(2,0) + F(2,2)*Nwx(0,a)); + Bm[a](5,0) = (Nwx(2,a)*F(0,0) + F(0,2)*Nwx(0,a)); + Bm[a](5,1) = (Nwx(2,a)*F(1,0) + F(1,2)*Nwx(0,a)); + Bm[a](5,2) = (Nwx(2,a)*F(2,0) + F(2,2)*Nwx(0,a)); } Array VxNx(3,eNoNw); @@ -1422,7 +1399,7 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, for (int b = 0; b < eNoNw; b++) { - DBm.noalias() = Dm * Eigen::Map>(Bm.slice_data(b)); + DBm.noalias() = Dm * Bm[b]; for (int a = 0; a < eNoNw; a++) { NxSNx = Nwx(0,a)*Siso(0,0)*Nwx(0,b) @@ -1432,9 +1409,7 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, + Nwx(2,a)*Siso(2,1)*Nwx(1,b) + Nwx(2,a)*Siso(2,2)*Nwx(2,b); // dM1_dV1 + af/am *dM_1/dU_1 - BtDB = Bm(0,0,a)*DBm(0,0) + Bm(1,0,a)*DBm(1,0) + - Bm(2,0,a)*DBm(2,0) + Bm(3,0,a)*DBm(3,0) + - Bm(4,0,a)*DBm(4,0) + Bm(5,0,a)*DBm(5,0); + BtDB = Bm[a].col(0).dot(DBm.col(0)); T1 = Jac*rho*vd(0)*Nw(a)*NxFi(0,b); T2 = -tauC*Jac*NxFi(0,a)*VxNx(0,b); @@ -1447,9 +1422,7 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, lK(0,a,b) = lK(0,a,b) + w*(T2 + Tv) + afm*Ku; // dM_1/dV_2 + af/am *dM_1/dU_2 - BtDB = Bm(0,0,a)*DBm(0,1) + Bm(1,0,a)*DBm(1,1) + - Bm(2,0,a)*DBm(2,1) + Bm(3,0,a)*DBm(3,1) + - Bm(4,0,a)*DBm(4,1) + Bm(5,0,a)*DBm(5,1); + BtDB = Bm[a].col(0).dot(DBm.col(1)); T1 = Jac*rho*vd(0)*Nw(a)*NxFi(1,b); T2 = -tauC*Jac*NxFi(0,a)*VxNx(1,b); T3 = Jac*rCl*(NxFi(0,a)*NxFi(1,b) - NxFi(1,a)*NxFi(0,b)); @@ -1463,9 +1436,7 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, // dM_1/dV_3 + af/am *dM_1/dU_3 // - BtDB = Bm(0,0,a)*DBm(0,2) + Bm(1,0,a)*DBm(1,2) + - Bm(2,0,a)*DBm(2,2) + Bm(3,0,a)*DBm(3,2) + - Bm(4,0,a)*DBm(4,2) + Bm(5,0,a)*DBm(5,2); + BtDB = Bm[a].col(0).dot(DBm.col(2)); T1 = Jac*rho*vd(0)*Nw(a)*NxFi(2,b); T2 = -tauC*Jac*NxFi(0,a)*VxNx(2,b); T3 = Jac*rCl*(NxFi(0,a)*NxFi(2,b) - NxFi(2,a)*NxFi(0,b)); @@ -1479,9 +1450,7 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, // dM_2/dV_1 + af/am *dM_2/dU_1 // - BtDB = Bm(0,1,a)*DBm(0,0) + Bm(1,1,a)*DBm(1,0) + - Bm(2,1,a)*DBm(2,0) + Bm(3,1,a)*DBm(3,0) + - Bm(4,1,a)*DBm(4,0) + Bm(5,1,a)*DBm(5,0); + BtDB = Bm[a].col(1).dot(DBm.col(0)); T1 = Jac*rho*vd(1)*Nw(a)*NxFi(0,b); T2 = -tauC*Jac*NxFi(1,a)*VxNx(0,b); @@ -1497,9 +1466,7 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, // dM_2/dV_2 + af/am *dM_2/dU_2 // - BtDB = Bm(0,1,a)*DBm(0,1) + Bm(1,1,a)*DBm(1,1) + - Bm(2,1,a)*DBm(2,1) + Bm(3,1,a)*DBm(3,1) + - Bm(4,1,a)*DBm(4,1) + Bm(5,1,a)*DBm(5,1); + BtDB = Bm[a].col(1).dot(DBm.col(1)); T1 = Jac*rho*vd(1)*Nw(a)*NxFi(1,b); @@ -1517,9 +1484,7 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, // dM_2/dV_3 + af/am *dM_2/dU_3 // - BtDB = Bm(0,1,a)*DBm(0,2) + Bm(1,1,a)*DBm(1,2) + - Bm(2,1,a)*DBm(2,2) + Bm(3,1,a)*DBm(3,2) + - Bm(4,1,a)*DBm(4,2) + Bm(5,1,a)*DBm(5,2); + BtDB = Bm[a].col(1).dot(DBm.col(2)); T1 = Jac*rho*vd(1)*Nw(a)*NxFi(2,b); T2 = -tauC*Jac*NxFi(1,a)*VxNx(2,b); @@ -1535,9 +1500,7 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, // dM_3/dV_1 + af/am *dM_3/dU_1 // - BtDB = Bm(0,2,a)*DBm(0,0) + Bm(1,2,a)*DBm(1,0) + - Bm(2,2,a)*DBm(2,0) + Bm(3,2,a)*DBm(3,0) + - Bm(4,2,a)*DBm(4,0) + Bm(5,2,a)*DBm(5,0); + BtDB = Bm[a].col(2).dot(DBm.col(0)); T1 = Jac*rho*vd(2)*Nw(a)*NxFi(0,b); T2 = -tauC*Jac*NxFi(2,a)*VxNx(0,b); @@ -1552,9 +1515,7 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, // dM_3/dV_2 + af/am *dM_3/dU_2 // - BtDB = Bm(0,2,a)*DBm(0,1) + Bm(1,2,a)*DBm(1,1) + - Bm(2,2,a)*DBm(2,1) + Bm(3,2,a)*DBm(3,1) + - Bm(4,2,a)*DBm(4,1) + Bm(5,2,a)*DBm(5,1); + BtDB = Bm[a].col(2).dot(DBm.col(1)); T1 = Jac*rho*vd(2)*Nw(a)*NxFi(1,b); T2 = -tauC*Jac*NxFi(2,a)*VxNx(1,b); @@ -1570,9 +1531,7 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, // dM_3/dV_3 + af/am *dM_3/dU_3 // - BtDB = Bm(0,2,a)*DBm(0,2) + Bm(1,2,a)*DBm(1,2) + - Bm(2,2,a)*DBm(2,2) + Bm(3,2,a)*DBm(3,2) + - Bm(4,2,a)*DBm(4,2) + Bm(5,2,a)*DBm(5,2); + BtDB = Bm[a].col(2).dot(DBm.col(2)); T1 = Jac*rho*vd(2)*Nw(a)*NxFi(2,b); T2 = -tauC*Jac*NxFi(2,a)*VxNx(2,b); From 0cbfa491524cc645bcfec15a028d663d2f208352 Mon Sep 17 00:00:00 2001 From: dseyler Date: Mon, 21 Sep 2026 20:10:37 -0700 Subject: [PATCH 23/42] Hoisted and collapsed geometric stiffness computation with Eigen and created eigen view helper --- Code/Source/solver/mat_fun.h | 16 ++++++++++++++++ Code/Source/solver/sv_struct.cpp | 20 ++++++++++++-------- Code/Source/solver/ustruct.cpp | 21 ++++++++++++--------- 3 files changed, 40 insertions(+), 17 deletions(-) diff --git a/Code/Source/solver/mat_fun.h b/Code/Source/solver/mat_fun.h index 3b3a08454..244102071 100644 --- a/Code/Source/solver/mat_fun.h +++ b/Code/Source/solver/mat_fun.h @@ -28,6 +28,22 @@ namespace mat_fun { template using Tensor = Eigen::TensorFixedSize>; + /// @brief Read-only Eigen view of an Array, sharing its storage. + /// + /// The Array must outlive the view. + /// + /// @tparam rows Row count, fixed at compile time; the columns are taken from the Array. + template + Eigen::Map> + eigen_view(const Array& A) { + if (A.nrows() != rows) { + svmp::raise( + "A view of " + std::to_string(rows) + " rows was requested for an array with " + + std::to_string(A.nrows()) + " rows."); + } + return {A.data(), rows, A.ncols()}; + } + // Function to convert Array to Eigen::Matrix template MatrixType convert_to_eigen_matrix(const Array& src) { diff --git a/Code/Source/solver/sv_struct.cpp b/Code/Source/solver/sv_struct.cpp index f93116fb2..6f62231bd 100644 --- a/Code/Source/solver/sv_struct.cpp +++ b/Code/Source/solver/sv_struct.cpp @@ -484,6 +484,8 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, // Matrix<2> P; Eigen::Matrix DBm; + + const auto Nxm = eigen_view<2>(Nx); std::array, consts::maxNoN> Bm; P.noalias() = F * S; #ifdef debug_struct_2d @@ -520,11 +522,13 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, // Material stiffness (D*B) for node b DBm.noalias() = Dm * Bm[b]; + // Geometric stiffness: S*grad(N_b) + const Eigen::Vector2d SNx = S * Nxm.col(b); + for (int a = 0; a < eNoN; a++) { // Geometric stiffness - NxSNx = Nx(0,a)*S(0,0)*Nx(0,b) + Nx(1,a)*S(1,0)*Nx(0,b) + - Nx(0,a)*S(0,1)*Nx(1,b) + Nx(1,a)*S(1,1)*Nx(1,b); + NxSNx = Nxm.col(a).dot(SNx); T1 = amd*N(a)*N(b) + afu*NxSNx; @@ -754,19 +758,19 @@ void struct_3d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, Eigen::Matrix DBm; + const auto Nxm = eigen_view<3>(Nx); + for (int b = 0; b < eNoN; b++) { // Material stiffness (D*B) for node b DBm.noalias() = Dm * Bm[b]; + // Geometric stiffness: S*grad(N_b) + const Eigen::Vector3d SNx = S * Nxm.col(b); + for (int a = 0; a < eNoN; a++) { - // Geometric stiffness - NxSNx = Nx(0,a)*S(0,0)*Nx(0,b) + Nx(1,a)*S(1,0)*Nx(0,b) + - Nx(2,a)*S(2,0)*Nx(0,b) + Nx(0,a)*S(0,1)*Nx(1,b) + - Nx(1,a)*S(1,1)*Nx(1,b) + Nx(2,a)*S(2,1)*Nx(1,b) + - Nx(0,a)*S(0,2)*Nx(2,b) + Nx(1,a)*S(1,2)*Nx(2,b) + - Nx(2,a)*S(2,2)*Nx(2,b); + NxSNx = Nxm.col(a).dot(SNx); T1 = amd*N(a)*N(b) + afu*NxSNx; diff --git a/Code/Source/solver/ustruct.cpp b/Code/Source/solver/ustruct.cpp index e50070e19..56aee6891 100644 --- a/Code/Source/solver/ustruct.cpp +++ b/Code/Source/solver/ustruct.cpp @@ -1063,15 +1063,17 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, Eigen::Matrix DBm; + const auto Nwxm = eigen_view<2>(Nwx); + for (int b = 0; b < eNoNw; b++) { DBm.noalias() = Dm * Bm[b]; + // Geometric stiffness: Siso*grad(N_b) + const Eigen::Vector2d SisoNx = Siso * Nwxm.col(b); + for (int a = 0; a < eNoNw; a++) { - NxSNx = Nwx(0,a)*Siso(0,0)*Nwx(0,b) - + Nwx(0,a)*Siso(0,1)*Nwx(1,b) - + Nwx(1,a)*Siso(1,0)*Nwx(0,b) - + Nwx(1,a)*Siso(1,1)*Nwx(1,b); + NxSNx = Nwxm.col(a).dot(SisoNx); // dM1_dV1 + af/am *dM_1/dU_1 // @@ -1397,16 +1399,17 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, Eigen::Matrix DBm; + const auto Nwxm = eigen_view<3>(Nwx); + for (int b = 0; b < eNoNw; b++) { DBm.noalias() = Dm * Bm[b]; + // Geometric stiffness: Siso*grad(N_b) + const Eigen::Vector3d SisoNx = Siso * Nwxm.col(b); + for (int a = 0; a < eNoNw; a++) { - NxSNx = Nwx(0,a)*Siso(0,0)*Nwx(0,b) - + Nwx(0,a)*Siso(0,1)*Nwx(1,b) + Nwx(0,a)*Siso(0,2)*Nwx(2,b) - + Nwx(1,a)*Siso(1,0)*Nwx(0,b) + Nwx(1,a)*Siso(1,1)*Nwx(1,b) - + Nwx(1,a)*Siso(1,2)*Nwx(2,b) + Nwx(2,a)*Siso(2,0)*Nwx(0,b) - + Nwx(2,a)*Siso(2,1)*Nwx(1,b) + Nwx(2,a)*Siso(2,2)*Nwx(2,b); + NxSNx = Nwxm.col(a).dot(SisoNx); // dM1_dV1 + af/am *dM_1/dU_1 BtDB = Bm[a].col(0).dot(DBm.col(0)); From 3084c8a6b7cf5a4a0d87f07bcc827857a2a2b9db Mon Sep 17 00:00:00 2001 From: dseyler Date: Mon, 21 Sep 2026 20:24:58 -0700 Subject: [PATCH 24/42] Removed unused locals in ustruct and collapsed more arithmetic with eigen ops --- Code/Source/solver/mat_fun.h | 22 +++++++++ Code/Source/solver/mat_models.cpp | 6 --- Code/Source/solver/mat_models.h | 1 + Code/Source/solver/sv_struct.cpp | 2 - Code/Source/solver/ustruct.cpp | 80 ++++++------------------------- 5 files changed, 37 insertions(+), 74 deletions(-) diff --git a/Code/Source/solver/mat_fun.h b/Code/Source/solver/mat_fun.h index 244102071..9ac11a518 100644 --- a/Code/Source/solver/mat_fun.h +++ b/Code/Source/solver/mat_fun.h @@ -9,6 +9,7 @@ #include #include "Array.h" +#include "consts.h" #include "Tensor4.h" #include "Vector.h" #include "FE/Common/FEException.h" @@ -28,6 +29,11 @@ namespace mat_fun { template using Tensor = Eigen::TensorFixedSize>; + /// @brief One nsd-vector per element node, so nsd x eNoN. Stack allocated, + /// so the column count is bounded by the largest element the solver supports. + template + using NodalMatrix = Eigen::Matrix; + /// @brief Read-only Eigen view of an Array, sharing its storage. /// /// The Array must outlive the view. @@ -44,6 +50,22 @@ namespace mat_fun { return {A.data(), rows, A.ncols()}; } + /// @brief Read-only Eigen view of a Vector, sharing its storage. + /// + /// The Vector must outlive the view. + /// + /// @tparam rows Entry count, fixed at compile time. + template + Eigen::Map> + eigen_view(const Vector& v) { + if (v.size() != rows) { + svmp::raise( + "A view of " + std::to_string(rows) + " entries was requested for a vector with " + + std::to_string(v.size()) + " entries."); + } + return Eigen::Map>(v.data()); + } + // Function to convert Array to Eigen::Matrix template MatrixType convert_to_eigen_matrix(const Array& src) { diff --git a/Code/Source/solver/mat_models.cpp b/Code/Source/solver/mat_models.cpp index 353944e43..5726d4898 100644 --- a/Code/Source/solver/mat_models.cpp +++ b/Code/Source/solver/mat_models.cpp @@ -1559,12 +1559,6 @@ void g_vol_pen(const ComMod& com_mod, const dmnType& lDmn, const double p, namespace { -/// @brief A quantity carrying one nsd-vector per element node, so nsd x eNoN. -/// -template -using NodalMatrix = - Eigen::Matrix; - /** * @brief Viscous PK2 stress and tangent contributions for the viscous * pseudo-potential model. diff --git a/Code/Source/solver/mat_models.h b/Code/Source/solver/mat_models.h index 9dec5acf9..a6c1622cf 100644 --- a/Code/Source/solver/mat_models.h +++ b/Code/Source/solver/mat_models.h @@ -19,6 +19,7 @@ namespace mat_models { using mat_fun::Matrix; using mat_fun::Tensor; +using mat_fun::NodalMatrix; void actv_strain(const ComMod& com_mod, const CepMod& cep_mod, const double gf, const int nfd, const Array& fl, Array& Fa); diff --git a/Code/Source/solver/sv_struct.cpp b/Code/Source/solver/sv_struct.cpp index 6f62231bd..48583a568 100644 --- a/Code/Source/solver/sv_struct.cpp +++ b/Code/Source/solver/sv_struct.cpp @@ -512,8 +512,6 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, Bm[a](2,1) = (Nx(0,a)*F(1,1) + F(1,0)*Nx(1,a)); } - Array NxFi(2,eNoN), DdNx(2,eNoN), VxNx(2,eNoN); - // Local stiffness tensor double T1, NxNx, NxSNx, BmDBm; diff --git a/Code/Source/solver/ustruct.cpp b/Code/Source/solver/ustruct.cpp index 56aee6891..2ff41fc95 100644 --- a/Code/Source/solver/ustruct.cpp +++ b/Code/Source/solver/ustruct.cpp @@ -537,25 +537,13 @@ void ustruct_2d_c(ComMod& com_mod, CepMod& cep_mod, const bool vmsFlag, const in tauC = 0.0; } - Array NwxFi(2,eNoNw); + const NodalMatrix<2> NwxFi = Fi.transpose() * eigen_view<2>(Nwx); - for (int a = 0; a < eNoNw; a++) { - NwxFi(0,a) = Nwx(0,a)*Fi(0,0) + Nwx(1,a)*Fi(1,0); - NwxFi(1,a) = Nwx(0,a)*Fi(0,1) + Nwx(1,a)*Fi(1,1); - } - - Array NqxFi(2,eNoNw); - - for (int a = 0; a < eNoNq; a++) { - NqxFi(0,a) = Nqx(0,a)*Fi(0,0) + Nqx(1,a)*Fi(1,0); - NqxFi(1,a) = Nqx(0,a)*Fi(0,1) + Nqx(1,a)*Fi(1,1); - } + const NodalMatrix<2> NqxFi = Fi.transpose() * eigen_view<2>(Nqx); const Matrix<2> VxFi = vx * Fi; - Vector PxFi(2); - PxFi(0) = px(0)*Fi(0,0) + px(1)*Fi(1,0); - PxFi(1) = px(0)*Fi(0,1) + px(1)*Fi(1,1); + const Eigen::Vector2d PxFi = Fi.transpose() * eigen_view<2>(px); double rC = beta*pd + VxFi(0,0) + VxFi(1,1); @@ -572,13 +560,12 @@ void ustruct_2d_c(ComMod& com_mod, CepMod& cep_mod, const bool vmsFlag, const in lR(2,a) = lR(2,a) + w*Jac*(Nq(a)*rC + tauM*rMNqx(a)); } + const NodalMatrix<2> VxNwx = VxFi.transpose() * NwxFi; + Vector rMNwx(eNoNw); - Array VxNwx(3,eNoNw); for (int a = 0; a < eNoNw; a++) { rMNwx(a) = rM(0)*NwxFi(0,a) + rM(1)*NwxFi(1,a); - VxNwx(0,a) = VxFi(0,0)*NwxFi(0,a) + VxFi(1,0)*NwxFi(1,a); - VxNwx(1,a) = VxFi(0,1)*NwxFi(0,a) + VxFi(1,1)*NwxFi(1,a); } // Tangent (stiffness) matrices @@ -753,28 +740,13 @@ void ustruct_3d_c(ComMod& com_mod, CepMod& cep_mod, const bool vmsFlag, const in tauC = 0.0; } - Array NwxFi(3,eNoNw); + const NodalMatrix<3> NwxFi = Fi.transpose() * eigen_view<3>(Nwx); - for (int a = 0; a < eNoNw; a++) { - NwxFi(0,a) = Nwx(0,a)*Fi(0,0) + Nwx(1,a)*Fi(1,0) + Nwx(2,a)*Fi(2,0); - NwxFi(1,a) = Nwx(0,a)*Fi(0,1) + Nwx(1,a)*Fi(1,1) + Nwx(2,a)*Fi(2,1); - NwxFi(2,a) = Nwx(0,a)*Fi(0,2) + Nwx(1,a)*Fi(1,2) + Nwx(2,a)*Fi(2,2); - } - - Array NqxFi(3,eNoNw); - - for (int a = 0; a < eNoNq; a++) { - NqxFi(0,a) = Nqx(0,a)*Fi(0,0) + Nqx(1,a)*Fi(1,0) + Nqx(2,a)*Fi(2,0); - NqxFi(1,a) = Nqx(0,a)*Fi(0,1) + Nqx(1,a)*Fi(1,1) + Nqx(2,a)*Fi(2,1); - NqxFi(2,a) = Nqx(0,a)*Fi(0,2) + Nqx(1,a)*Fi(1,2) + Nqx(2,a)*Fi(2,2); - } + const NodalMatrix<3> NqxFi = Fi.transpose() * eigen_view<3>(Nqx); const Matrix<3> VxFi = vx * Fi; - Vector PxFi(3); - PxFi(0) = px(0)*Fi(0,0) + px(1)*Fi(1,0) + px(2)*Fi(2,0); - PxFi(1) = px(0)*Fi(0,1) + px(1)*Fi(1,1) + px(2)*Fi(2,1); - PxFi(2) = px(0)*Fi(0,2) + px(1)*Fi(1,2) + px(2)*Fi(2,2); + const Eigen::Vector3d PxFi = Fi.transpose() * eigen_view<3>(px); double rC = beta*pd + VxFi(0,0) + VxFi(1,1) + VxFi(2,2); @@ -792,14 +764,12 @@ void ustruct_3d_c(ComMod& com_mod, CepMod& cep_mod, const bool vmsFlag, const in lR(3,a) = lR(3,a) + w*Jac*(Nq(a)*rC + tauM*rMNqx(a)); } + const NodalMatrix<3> VxNwx = VxFi.transpose() * NwxFi; + Vector rMNwx(eNoNw); - Array VxNwx(3,eNoNw); for (int a = 0; a < eNoNw; a++) { rMNwx(a) = rM(0)*NwxFi(0,a) + rM(1)*NwxFi(1,a) + rM(2)*NwxFi(2,a); - VxNwx(0,a) = VxFi(0,0)*NwxFi(0,a) + VxFi(1,0)*NwxFi(1,a) + VxFi(2,0)*NwxFi(2,a); - VxNwx(1,a) = VxFi(0,1)*NwxFi(0,a) + VxFi(1,1)*NwxFi(1,a) + VxFi(2,1)*NwxFi(2,a); - VxNwx(2,a) = VxFi(0,2)*NwxFi(0,a) + VxFi(1,2)*NwxFi(1,a) + VxFi(2,2)*NwxFi(2,a); } // Tangent (stiffness) matrices @@ -1007,12 +977,7 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, // Shape function gradients in the current configuration // - Array NxFi(2,eNoNw); - - for (int a = 0; a < eNoNw; a++) { - NxFi(0,a) = Nwx(0,a)*Fi(0,0) + Nwx(1,a)*Fi(1,0); - NxFi(1,a) = Nwx(0,a)*Fi(0,1) + Nwx(1,a)*Fi(1,1); - } + const NodalMatrix<2> NxFi = Fi.transpose() * eigen_view<2>(Nwx); // Velocity gradient in current configuration const Matrix<2> VxFi = vx * Fi; @@ -1048,12 +1013,7 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, Bm[a](2,1) = Nwx(0,a)*F(1,1) + F(1,0)*Nwx(1,a); } - Array VxNx(2,eNoNw); - - for (int a = 0; a < eNoNw; a++) { - VxNx(0,a) = VxFi(0,0)*NxFi(0,a) + VxFi(1,0)*NxFi(1,a); - VxNx(1,a) = VxFi(0,1)*NxFi(0,a) + VxFi(1,1)*NxFi(1,a); - } + const NodalMatrix<2> VxNx = VxFi.transpose() * NxFi; // Tangent (stiffness) matrices // @@ -1318,13 +1278,7 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, // Shape function gradients in the current configuration // - Array NxFi(3,eNoNw); - - for (int a = 0; a < eNoNw; a++) { - NxFi(0,a) = Nwx(0,a)*Fi(0,0) + Nwx(1,a)*Fi(1,0) + Nwx(2,a)*Fi(2,0); - NxFi(1,a) = Nwx(0,a)*Fi(0,1) + Nwx(1,a)*Fi(1,1) + Nwx(2,a)*Fi(2,1); - NxFi(2,a) = Nwx(0,a)*Fi(0,2) + Nwx(1,a)*Fi(1,2) + Nwx(2,a)*Fi(2,2); - } + const NodalMatrix<3> NxFi = Fi.transpose() * eigen_view<3>(Nwx); // Velocity gradient in current configuration const Matrix<3> VxFi = vx * Fi; @@ -1382,13 +1336,7 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, Bm[a](5,2) = (Nwx(2,a)*F(2,0) + F(2,2)*Nwx(0,a)); } - Array VxNx(3,eNoNw); - - for (int a = 0; a < eNoNw; a++) { - VxNx(0,a) = VxFi(0,0)*NxFi(0,a) + VxFi(1,0)*NxFi(1,a) + VxFi(2,0)*NxFi(2,a); - VxNx(1,a) = VxFi(0,1)*NxFi(0,a) + VxFi(1,1)*NxFi(1,a) + VxFi(2,1)*NxFi(2,a); - VxNx(2,a) = VxFi(0,2)*NxFi(0,a) + VxFi(1,2)*NxFi(1,a) + VxFi(2,2)*NxFi(2,a); - } + const NodalMatrix<3> VxNx = VxFi.transpose() * NxFi; // Tangent (stiffness) matrices // From f8a9e760ddd4ce82949f8fabec3c505ba22daf24 Mon Sep 17 00:00:00 2001 From: dseyler Date: Mon, 21 Sep 2026 20:32:00 -0700 Subject: [PATCH 25/42] Collapse rMNqx and rMNwx with Eigen --- Code/Source/solver/mat_fun.h | 4 ++++ Code/Source/solver/ustruct.cpp | 18 ++++-------------- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/Code/Source/solver/mat_fun.h b/Code/Source/solver/mat_fun.h index 9ac11a518..4aa1c536c 100644 --- a/Code/Source/solver/mat_fun.h +++ b/Code/Source/solver/mat_fun.h @@ -34,6 +34,10 @@ namespace mat_fun { template using NodalMatrix = Eigen::Matrix; + /// @brief One scalar per element node. Stack allocated, so the entry count + /// is bounded by the largest element the solver supports. + using NodalVector = Eigen::Matrix; + /// @brief Read-only Eigen view of an Array, sharing its storage. /// /// The Array must outlive the view. diff --git a/Code/Source/solver/ustruct.cpp b/Code/Source/solver/ustruct.cpp index 2ff41fc95..c2b589418 100644 --- a/Code/Source/solver/ustruct.cpp +++ b/Code/Source/solver/ustruct.cpp @@ -553,20 +553,15 @@ void ustruct_2d_c(ComMod& com_mod, CepMod& cep_mod, const bool vmsFlag, const in // Local residual // - Vector rMNqx(eNoNq); + const NodalVector rMNqx = NqxFi.transpose() * eigen_view<2>(rM); for (int a = 0; a < eNoNq; a++) { - rMNqx(a) = rM(0)*NqxFi(0,a) + rM(1)*NqxFi(1,a); lR(2,a) = lR(2,a) + w*Jac*(Nq(a)*rC + tauM*rMNqx(a)); } const NodalMatrix<2> VxNwx = VxFi.transpose() * NwxFi; - Vector rMNwx(eNoNw); - - for (int a = 0; a < eNoNw; a++) { - rMNwx(a) = rM(0)*NwxFi(0,a) + rM(1)*NwxFi(1,a); - } + const NodalVector rMNwx = NwxFi.transpose() * eigen_view<2>(rM); // Tangent (stiffness) matrices // @@ -757,20 +752,15 @@ void ustruct_3d_c(ComMod& com_mod, CepMod& cep_mod, const bool vmsFlag, const in // Local residual // - Vector rMNqx(eNoNq); + const NodalVector rMNqx = NqxFi.transpose() * eigen_view<3>(rM); for (int a = 0; a < eNoNq; a++) { - rMNqx(a) = rM(0)*NqxFi(0,a) + rM(1)*NqxFi(1,a) + rM(2)*NqxFi(2,a); lR(3,a) = lR(3,a) + w*Jac*(Nq(a)*rC + tauM*rMNqx(a)); } const NodalMatrix<3> VxNwx = VxFi.transpose() * NwxFi; - Vector rMNwx(eNoNw); - - for (int a = 0; a < eNoNw; a++) { - rMNwx(a) = rM(0)*NwxFi(0,a) + rM(1)*NwxFi(1,a) + rM(2)*NwxFi(2,a); - } + const NodalVector rMNwx = NwxFi.transpose() * eigen_view<3>(rM); // Tangent (stiffness) matrices // From 0c401dd6bcdd2597faa2b7a6a90c7029560a6e85 Mon Sep 17 00:00:00 2001 From: dseyler Date: Mon, 21 Sep 2026 21:55:42 -0700 Subject: [PATCH 26/42] Collapsed interpolated quantitied and gradients for readability using Eigen --- Code/Source/solver/mat_fun.h | 27 +++ Code/Source/solver/sv_struct.cpp | 144 +++++++--------- Code/Source/solver/ustruct.cpp | 281 ++++++++++--------------------- 3 files changed, 178 insertions(+), 274 deletions(-) diff --git a/Code/Source/solver/mat_fun.h b/Code/Source/solver/mat_fun.h index 4aa1c536c..2234dfc3d 100644 --- a/Code/Source/solver/mat_fun.h +++ b/Code/Source/solver/mat_fun.h @@ -54,6 +54,33 @@ namespace mat_fun { return {A.data(), rows, A.ncols()}; } + /// @brief Read-only Eigen view of a whole Array, sharing its storage. + /// + /// Both dimensions come from the Array, so a row block of a larger array is + /// reached with e.g. eigen_view(dl).middleRows(i), letting Eigen derive + /// the stride. The Array must outlive the view. + inline Eigen::Map + eigen_view(const Array& A) { + return {A.data(), A.nrows(), A.ncols()}; + } + + /// @brief Writable Eigen view of a whole Array, sharing its storage. + /// + /// Lets a result be accumulated with a single Eigen expression. The Array + /// must outlive the view. + inline Eigen::Map + eigen_view_mut(Array& A) { + return {A.data(), A.nrows(), A.ncols()}; + } + + /// @brief Read-only Eigen view of a whole Vector, sharing its storage. + /// + /// The Vector must outlive the view. + inline Eigen::Map + eigen_view(const Vector& v) { + return {v.data(), v.size()}; + } + /// @brief Read-only Eigen view of a Vector, sharing its storage. /// /// The Vector must outlive the view. diff --git a/Code/Source/solver/sv_struct.cpp b/Code/Source/solver/sv_struct.cpp index 48583a568..c00a0b85d 100644 --- a/Code/Source/solver/sv_struct.cpp +++ b/Code/Source/solver/sv_struct.cpp @@ -402,41 +402,36 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, dmsg << "w: " << w; #endif - // Inertia, body force and deformation tensor (F) - // - Matrix<2> F, S0, vx; - Vector ud(2); - - ud = -rho*fb; - F.setIdentity(); - S0.setZero(); - vx.setZero(); - - double ya_g_f = 0.0; - double ya_g_s = 0.0; - double ya_g_n = 0.0; + double ya_g_f; + double ya_g_s; + double ya_g_n; + + // This element's nodal fields, as Eigen views over the caller's storage + const auto Nxm = eigen_view<2>(Nx); // grad(N_a) per column + const auto Nm = eigen_view(N); // shape functions + const auto disp = eigen_view(dl).middleRows<2>(i); // nodal displacements + const auto vel = eigen_view(yl).middleRows<2>(i); // nodal velocities + const auto acc = eigen_view(al).middleRows<2>(i); // nodal accelerations + const auto bfm = eigen_view<2>(bfl); // nodal body force + const auto fbv = eigen_view<2>(fb); // domain body force, constant over the element + auto lRv = eigen_view_mut(lR).topRows<2>(); // rows this kernel adds to + + // Inertia, damping and body force: the term the residual weights with N + const Eigen::Vector2d ud = (rho*(acc - bfm) + dmp*vel) * Nm - rho * fbv; + + // Active stress activation along fiber, sheet and sheet-normal + ya_g_f = eigen_view(ya_l_f).dot(Nm); + ya_g_s = eigen_view(ya_l_s).dot(Nm); + ya_g_n = eigen_view(ya_l_n).dot(Nm); + + // Prestress at this Gauss point: interpolate pS0l, held in Voigt + // order [11, 22, 12], into the three independent components of S0. + Matrix<2> S0 = Matrix<2>::Zero(); for (int a = 0; a < eNoN; a++) { - ud(0) = ud(0) + N(a)*(rho*(al(i,a)-bfl(0,a)) + dmp*yl(i,a)); - ud(1) = ud(1) + N(a)*(rho*(al(j,a)-bfl(1,a)) + dmp*yl(j,a)); - - vx(0,0) = vx(0,0) + Nx(0,a)*yl(i,a); - vx(0,1) = vx(0,1) + Nx(1,a)*yl(i,a); - vx(1,0) = vx(1,0) + Nx(0,a)*yl(j,a); - vx(1,1) = vx(1,1) + Nx(1,a)*yl(j,a); - - F(0,0) = F(0,0) + Nx(0,a)*dl(i,a); - F(0,1) = F(0,1) + Nx(1,a)*dl(i,a); - F(1,0) = F(1,0) + Nx(0,a)*dl(j,a); - F(1,1) = F(1,1) + Nx(1,a)*dl(j,a); - S0(0,0) = S0(0,0) + N(a)*pS0l(0,a); S0(1,1) = S0(1,1) + N(a)*pS0l(1,a); S0(0,1) = S0(0,1) + N(a)*pS0l(2,a); - - ya_g_f = ya_g_f + N(a) * ya_l_f(a); - ya_g_s = ya_g_s + N(a) * ya_l_s(a); - ya_g_n = ya_g_n + N(a) * ya_l_n(a); } #ifdef debug_struct_2d dmsg << "ud: " << ud(0) << " " << ud(1); @@ -448,6 +443,10 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, S0(1,0) = S0(0,1); + // Velocity and deformation gradients: Grad(v) and F = I + Grad(u) + const Matrix<2> vx = vel * Nxm.transpose(); + const Matrix<2> F = Matrix<2>::Identity() + disp * Nxm.transpose(); + // 2nd Piola-Kirchhoff stress (S) and material stiffness tensor in Voight notation (Dm) Matrix<2> S; Matrix<3> Dm; @@ -485,7 +484,6 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, Matrix<2> P; Eigen::Matrix DBm; - const auto Nxm = eigen_view<2>(Nx); std::array, consts::maxNoN> Bm; P.noalias() = F * S; #ifdef debug_struct_2d @@ -493,11 +491,8 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, dmsg << " " << P(1,0) << " " << P(1,1); #endif - // Local residual - for (int a = 0; a < eNoN; a++) { - lR(0,a) = lR(0,a) + w*(N(a)*ud(0) + Nx(0,a)*P(0,0) + Nx(1,a)*P(0,1)); - lR(1,a) = lR(1,a) + w*(N(a)*ud(1) + Nx(0,a)*P(1,0) + Nx(1,a)*P(1,1)); - } + // Local residual: inertia and body force, plus the divergence of P + lRv += w * (ud * Nm.transpose() + P * Nxm); // Strain-displacement matrix; Bm[a] maps node a displacement to Voigt strain // @@ -529,7 +524,6 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, NxSNx = Nxm.col(a).dot(SNx); T1 = amd*N(a)*N(b) + afu*NxSNx; - // dM1/du1 BmDBm = Bm[a].col(0).dot(DBm.col(0)); @@ -605,66 +599,54 @@ void struct_3d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, int j = i + 1; int k = j + 1; - // Inertia, body force and deformation tensor (F) - // - Matrix<3> F, S0, vx; - Vector ud(3); - double F_f[3][3]={}; F_f[0][0] = 1.0; F_f[1][1] = 1.0; F_f[2][2] = 1.0; - ud = -rho*fb; - F.setIdentity(); - S0.setZero(); - vx.setZero(); + double ya_g_f; + double ya_g_s; + double ya_g_n; - double ya_g_f = 0.0; - double ya_g_s = 0.0; - double ya_g_n = 0.0; + // This element's nodal fields, as Eigen views over the caller's storage + const auto Nxm = eigen_view<3>(Nx); // grad(N_a) per column + const auto Nm = eigen_view(N); // shape functions + const auto disp = eigen_view(dl).middleRows<3>(i); // nodal displacements + const auto vel = eigen_view(yl).middleRows<3>(i); // nodal velocities + const auto acc = eigen_view(al).middleRows<3>(i); // nodal accelerations + const auto bfm = eigen_view<3>(bfl); // nodal body force + const auto fbv = eigen_view<3>(fb); // domain body force, constant over the element + auto lRv = eigen_view_mut(lR).topRows<3>(); // rows this kernel adds to - for (int a = 0; a < eNoN; a++) { - ud(0) = ud(0) + N(a)*(rho*(al(i,a)-bfl(0,a)) + dmp*yl(i,a)); - ud(1) = ud(1) + N(a)*(rho*(al(j,a)-bfl(1,a)) + dmp*yl(j,a)); - ud(2) = ud(2) + N(a)*(rho*(al(k,a)-bfl(2,a)) + dmp*yl(k,a)); - - vx(0,0) = vx(0,0) + Nx(0,a)*yl(i,a); - vx(0,1) = vx(0,1) + Nx(1,a)*yl(i,a); - vx(0,2) = vx(0,2) + Nx(2,a)*yl(i,a); - vx(1,0) = vx(1,0) + Nx(0,a)*yl(j,a); - vx(1,1) = vx(1,1) + Nx(1,a)*yl(j,a); - vx(1,2) = vx(1,2) + Nx(2,a)*yl(j,a); - vx(2,0) = vx(2,0) + Nx(0,a)*yl(k,a); - vx(2,1) = vx(2,1) + Nx(1,a)*yl(k,a); - vx(2,2) = vx(2,2) + Nx(2,a)*yl(k,a); + // Inertia, damping and body force: the term the residual weights with N + const Eigen::Vector3d ud = (rho*(acc - bfm) + dmp*vel) * Nm - rho * fbv; - F(0,0) = F(0,0) + Nx(0,a)*dl(i,a); - F(0,1) = F(0,1) + Nx(1,a)*dl(i,a); - F(0,2) = F(0,2) + Nx(2,a)*dl(i,a); - F(1,0) = F(1,0) + Nx(0,a)*dl(j,a); - F(1,1) = F(1,1) + Nx(1,a)*dl(j,a); - F(1,2) = F(1,2) + Nx(2,a)*dl(j,a); - F(2,0) = F(2,0) + Nx(0,a)*dl(k,a); - F(2,1) = F(2,1) + Nx(1,a)*dl(k,a); - F(2,2) = F(2,2) + Nx(2,a)*dl(k,a); + // Active stress activation along fiber, sheet and sheet-normal + ya_g_f = eigen_view(ya_l_f).dot(Nm); + ya_g_s = eigen_view(ya_l_s).dot(Nm); + ya_g_n = eigen_view(ya_l_n).dot(Nm); + + // Prestress at this Gauss point: interpolate pS0l, held in Voigt + // order [11, 22, 33, 12, 23, 31], into the six independent components of S0. + Matrix<3> S0 = Matrix<3>::Zero(); + for (int a = 0; a < eNoN; a++) { S0(0,0) = S0(0,0) + N(a)*pS0l(0,a); S0(1,1) = S0(1,1) + N(a)*pS0l(1,a); S0(2,2) = S0(2,2) + N(a)*pS0l(2,a); S0(0,1) = S0(0,1) + N(a)*pS0l(3,a); S0(1,2) = S0(1,2) + N(a)*pS0l(4,a); S0(2,0) = S0(2,0) + N(a)*pS0l(5,a); - - ya_g_f = ya_g_f + N(a) * ya_l_f(a); - ya_g_s = ya_g_s + N(a) * ya_l_s(a); - ya_g_n = ya_g_n + N(a) * ya_l_n(a); } S0(1,0) = S0(0,1); S0(2,1) = S0(1,2); S0(0,2) = S0(2,0); + // Velocity and deformation gradients: Grad(v) and F = I + Grad(u) + const Matrix<3> vx = vel * Nxm.transpose(); + const Matrix<3> F = Matrix<3>::Identity() + disp * Nxm.transpose(); + // 2nd Piola-Kirchhoff tensor (S) and material stiffness tensor in // Voigt notationa (Dm) // @@ -716,12 +698,8 @@ void struct_3d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, std::array, consts::maxNoN> Bm; P.noalias() = F * S; - // Local residual - for (int a = 0; a < eNoN; a++) { - lR(0,a) = lR(0,a) + w*(N(a)*ud(0) + Nx(0,a)*P(0,0) + Nx(1,a)*P(0,1) + Nx(2,a)*P(0,2)); - lR(1,a) = lR(1,a) + w*(N(a)*ud(1) + Nx(0,a)*P(1,0) + Nx(1,a)*P(1,1) + Nx(2,a)*P(1,2)); - lR(2,a) = lR(2,a) + w*(N(a)*ud(2) + Nx(0,a)*P(2,0) + Nx(1,a)*P(2,1) + Nx(2,a)*P(2,2)); - } + // Local residual: inertia and body force, plus the divergence of P + lRv += w * (ud * Nm.transpose() + P * Nxm); // Strain-displacement matrix; Bm[a] maps node a displacement to Voigt strain // @@ -756,8 +734,6 @@ void struct_3d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, Eigen::Matrix DBm; - const auto Nxm = eigen_view<3>(Nx); - for (int b = 0; b < eNoN; b++) { // Material stiffness (D*B) for node b diff --git a/Code/Source/solver/ustruct.cpp b/Code/Source/solver/ustruct.cpp index c2b589418..3fba32ada 100644 --- a/Code/Source/solver/ustruct.cpp +++ b/Code/Source/solver/ustruct.cpp @@ -475,31 +475,22 @@ void ustruct_2d_c(ComMod& com_mod, CepMod& cep_mod, const bool vmsFlag, const in dmsg << "i: " << i; #endif - // Inertia (velocity and acceleration), body force, fiber directions, - // and deformation tensor (F) at integration point - // - Vector vd{-fb[0], -fb[1]}; - Vector v(2); - Matrix<2> vx = Matrix<2>::Zero(); - Matrix<2> F = Matrix<2>::Identity(); - - for (int a = 0; a < eNoNw; a++) { - v(0) = v(0) + Nw(a)*yl(i,a); - v(1) = v(1) + Nw(a)*yl(j,a); - - vd(0) = vd(0) + Nw(a)*(al(i,a)-bfl(0,a)); - vd(1) = vd(1) + Nw(a)*(al(j,a)-bfl(1,a)); - - vx(0,0) = vx(0,0) + Nwx(0,a)*yl(i,a); - vx(0,1) = vx(0,1) + Nwx(1,a)*yl(i,a); - vx(1,0) = vx(1,0) + Nwx(0,a)*yl(j,a); - vx(1,1) = vx(1,1) + Nwx(1,a)*yl(j,a); - - F(0,0) = F(0,0) + Nwx(0,a)*dl(i,a); - F(0,1) = F(0,1) + Nwx(1,a)*dl(i,a); - F(1,0) = F(1,0) + Nwx(0,a)*dl(j,a); - F(1,1) = F(1,1) + Nwx(1,a)*dl(j,a); - } + // This element's nodal fields, as Eigen views over the caller's storage + const auto Nwxm = eigen_view<2>(Nwx); // grad(N_a) per column + const auto Nwm = eigen_view(Nw); // shape functions + const auto disp = eigen_view(dl).middleRows<2>(i); // nodal displacements + const auto vel = eigen_view(yl).middleRows<2>(i); // nodal velocities + const auto acc = eigen_view(al).middleRows<2>(i); // nodal accelerations + const auto bfm = eigen_view<2>(bfl); // nodal body force + const auto fbv = eigen_view<2>(fb); // domain body force, constant over the element + + // Velocity, and the inertia less body force, at this Gauss point + const Eigen::Vector2d v = vel * Nwm; + const Eigen::Vector2d vd = (acc - bfm) * Nwm - fbv; + + // Velocity and deformation gradients: Grad(v) and F = I + Grad(u) + const Matrix<2> vx = vel * Nwxm.transpose(); + const Matrix<2> F = Matrix<2>::Identity() + disp * Nwxm.transpose(); double Jac = F.determinant(); const Matrix<2> Fi = F.inverse(); @@ -537,7 +528,7 @@ void ustruct_2d_c(ComMod& com_mod, CepMod& cep_mod, const bool vmsFlag, const in tauC = 0.0; } - const NodalMatrix<2> NwxFi = Fi.transpose() * eigen_view<2>(Nwx); + const NodalMatrix<2> NwxFi = Fi.transpose() * Nwxm; const NodalMatrix<2> NqxFi = Fi.transpose() * eigen_view<2>(Nqx); @@ -656,47 +647,22 @@ void ustruct_3d_c(ComMod& com_mod, CepMod& cep_mod, const bool vmsFlag, const in dmsg << "i: " << i; #endif - // Inertia (velocity and acceleration), body force, fiber directions, - // and deformation tensor (F) at integration point - // - Vector vd{-fb[0], -fb[1], -fb[2]}; - Vector v(3); - Matrix<3> vx = Matrix<3>::Zero(); - Matrix<3> F = Matrix<3>::Identity(); - - for (int a = 0; a < eNoNw; a++) { - v(0) = v(0) + Nw(a)*yl(i,a); - v(1) = v(1) + Nw(a)*yl(j,a); - v(2) = v(2) + Nw(a)*yl(k,a); - - vd(0) = vd(0) + Nw(a)*(al(i,a)-bfl(0,a)); - vd(1) = vd(1) + Nw(a)*(al(j,a)-bfl(1,a)); - vd(2) = vd(2) + Nw(a)*(al(k,a)-bfl(2,a)); - - vx(0,0) = vx(0,0) + Nwx(0,a)*yl(i,a); - vx(0,1) = vx(0,1) + Nwx(1,a)*yl(i,a); - vx(0,2) = vx(0,2) + Nwx(2,a)*yl(i,a); - - vx(1,0) = vx(1,0) + Nwx(0,a)*yl(j,a); - vx(1,1) = vx(1,1) + Nwx(1,a)*yl(j,a); - vx(1,2) = vx(1,2) + Nwx(2,a)*yl(j,a); + // This element's nodal fields, as Eigen views over the caller's storage + const auto Nwxm = eigen_view<3>(Nwx); // grad(N_a) per column + const auto Nwm = eigen_view(Nw); // shape functions + const auto disp = eigen_view(dl).middleRows<3>(i); // nodal displacements + const auto vel = eigen_view(yl).middleRows<3>(i); // nodal velocities + const auto acc = eigen_view(al).middleRows<3>(i); // nodal accelerations + const auto bfm = eigen_view<3>(bfl); // nodal body force + const auto fbv = eigen_view<3>(fb); // domain body force, constant over the element - vx(2,0) = vx(2,0) + Nwx(0,a)*yl(k,a); - vx(2,1) = vx(2,1) + Nwx(1,a)*yl(k,a); - vx(2,2) = vx(2,2) + Nwx(2,a)*yl(k,a); + // Velocity, and the inertia less body force, at this Gauss point + const Eigen::Vector3d v = vel * Nwm; + const Eigen::Vector3d vd = (acc - bfm) * Nwm - fbv; - F(0,0) = F(0,0) + Nwx(0,a)*dl(i,a); - F(0,1) = F(0,1) + Nwx(1,a)*dl(i,a); - F(0,2) = F(0,2) + Nwx(2,a)*dl(i,a); - - F(1,0) = F(1,0) + Nwx(0,a)*dl(j,a); - F(1,1) = F(1,1) + Nwx(1,a)*dl(j,a); - F(1,2) = F(1,2) + Nwx(2,a)*dl(j,a); - - F(2,0) = F(2,0) + Nwx(0,a)*dl(k,a); - F(2,1) = F(2,1) + Nwx(1,a)*dl(k,a); - F(2,2) = F(2,2) + Nwx(2,a)*dl(k,a); - } + // Velocity and deformation gradients: Grad(v) and F = I + Grad(u) + const Matrix<3> vx = vel * Nwxm.transpose(); + const Matrix<3> F = Matrix<3>::Identity() + disp * Nwxm.transpose(); double Jac = F.determinant(); const Matrix<3> Fi = F.inverse(); @@ -735,7 +701,7 @@ void ustruct_3d_c(ComMod& com_mod, CepMod& cep_mod, const bool vmsFlag, const in tauC = 0.0; } - const NodalMatrix<3> NwxFi = Fi.transpose() * eigen_view<3>(Nwx); + const NodalMatrix<3> NwxFi = Fi.transpose() * Nwxm; const NodalMatrix<3> NqxFi = Fi.transpose() * eigen_view<3>(Nqx); @@ -868,40 +834,32 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, dmsg << "i: " << i; #endif - // Inertia (velocity and acceleration), body force, fiber directions, - // and deformation tensor (F) at integration point - // - Vector vd{-fb[0], -fb[1]}; - Vector v(2); - Matrix<2> vx = Matrix<2>::Zero(); - Matrix<2> F = Matrix<2>::Identity(); - - double ya_g_f = 0.0; - double ya_g_s = 0.0; - double ya_g_n = 0.0; - - - for (int a = 0; a < eNoNw; a++) { - v(0) = v(0) + Nw(a)*yl(i,a); - v(1) = v(1) + Nw(a)*yl(j,a); - - vd(0) = vd(0) + Nw(a)*(al(i,a)-bfl(0,a)); - vd(1) = vd(1) + Nw(a)*(al(j,a)-bfl(1,a)); - - vx(0,0) = vx(0,0) + Nwx(0,a)*yl(i,a); - vx(0,1) = vx(0,1) + Nwx(1,a)*yl(i,a); - vx(1,0) = vx(1,0) + Nwx(0,a)*yl(j,a); - vx(1,1) = vx(1,1) + Nwx(1,a)*yl(j,a); - - F(0,0) = F(0,0) + Nwx(0,a)*dl(i,a); - F(0,1) = F(0,1) + Nwx(1,a)*dl(i,a); - F(1,0) = F(1,0) + Nwx(0,a)*dl(j,a); - F(1,1) = F(1,1) + Nwx(1,a)*dl(j,a); - - ya_g_f = ya_g_f + Nw(a) * ya_l_f(a); - ya_g_s = ya_g_s + Nw(a) * ya_l_s(a); - ya_g_n = ya_g_n + Nw(a) * ya_l_n(a); - } + double ya_g_f; + double ya_g_s; + double ya_g_n; + + // This element's nodal fields, as Eigen views over the caller's storage + const auto Nwxm = eigen_view<2>(Nwx); // grad(N_a) per column + const auto Nwm = eigen_view(Nw); // shape functions + const auto disp = eigen_view(dl).middleRows<2>(i); // nodal displacements + const auto vel = eigen_view(yl).middleRows<2>(i); // nodal velocities + const auto acc = eigen_view(al).middleRows<2>(i); // nodal accelerations + const auto bfm = eigen_view<2>(bfl); // nodal body force + const auto fbv = eigen_view<2>(fb); // domain body force, constant over the element + auto lRv = eigen_view_mut(lR).topRows<2>(); // rows this kernel adds to + + // Velocity, and the inertia less body force, at this Gauss point + const Eigen::Vector2d v = vel * Nwm; + const Eigen::Vector2d vd = (acc - bfm) * Nwm - fbv; + + // Active stress activation along fiber, sheet and sheet-normal + ya_g_f = eigen_view(ya_l_f).dot(Nwm); + ya_g_s = eigen_view(ya_l_s).dot(Nwm); + ya_g_n = eigen_view(ya_l_n).dot(Nwm); + + // Velocity and deformation gradients: Grad(v) and F = I + Grad(u) + const Matrix<2> vx = vel * Nwxm.transpose(); + const Matrix<2> F = Matrix<2>::Identity() + disp * Nwxm.transpose(); double Jac = F.determinant(); const Matrix<2> Fi = F.inverse(); @@ -964,10 +922,9 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, // const Matrix<2> Pdev = F * Siso; - // Shape function gradients in the current configuration // - const NodalMatrix<2> NxFi = Fi.transpose() * eigen_view<2>(Nwx); + const NodalMatrix<2> NxFi = Fi.transpose() * Nwxm; // Velocity gradient in current configuration const Matrix<2> VxFi = vx * Fi; @@ -976,17 +933,8 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, // Local residual // - for (int a = 0; a < eNoNw; a++) { - double T1 = Jac*rho*vd(0)*Nw(a); - double T2 = Pdev(0,0)*Nwx(0,a) + Pdev(0,1)*Nwx(1,a); - double T3 = Jac*rCl*NxFi(0,a); - lR(0,a) = lR(0,a) + w*(T1 + T2 + T3); - - T1 = Jac*rho*vd(1)*Nw(a); - T2 = Pdev(1,0)*Nwx(0,a) + Pdev(1,1)*Nwx(1,a); - T3 = Jac*rCl*NxFi(1,a); - lR(1,a) = lR(1,a) + w*(T1 + T2 + T3); - } + // Inertia, the divergence of Pdev, and the pressure/volumetric term + lRv += w * (Jac*rho * vd * Nwm.transpose() + Pdev * Nwxm + Jac*rCl * NxFi); // Strain-displacement matrix; Bm[a] maps node a displacement to Voigt strain // @@ -1013,8 +961,6 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, Eigen::Matrix DBm; - const auto Nwxm = eigen_view<2>(Nwx); - for (int b = 0; b < eNoNw; b++) { DBm.noalias() = Dm * Bm[b]; @@ -1154,55 +1100,32 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, dmsg << "i: " << i; #endif - // Inertia (velocity and acceleration), body force, fiber directions, - // and deformation tensor (F) at integration point - // - Vector vd{-fb[0], -fb[1], -fb[2]}; - Vector v(3); - Matrix<3> vx = Matrix<3>::Zero(); - Matrix<3> F = Matrix<3>::Identity(); - - double ya_g_f = 0.0; - double ya_g_s = 0.0; - double ya_g_n = 0.0; - - for (int a = 0; a < eNoNw; a++) { - v(0) = v(0) + Nw(a)*yl(i,a); - v(1) = v(1) + Nw(a)*yl(j,a); - v(2) = v(2) + Nw(a)*yl(k,a); - - vd(0) = vd(0) + Nw(a)*(al(i,a)-bfl(0,a)); - vd(1) = vd(1) + Nw(a)*(al(j,a)-bfl(1,a)); - vd(2) = vd(2) + Nw(a)*(al(k,a)-bfl(2,a)); - - vx(0,0) = vx(0,0) + Nwx(0,a)*yl(i,a); - vx(0,1) = vx(0,1) + Nwx(1,a)*yl(i,a); - vx(0,2) = vx(0,2) + Nwx(2,a)*yl(i,a); - - vx(1,0) = vx(1,0) + Nwx(0,a)*yl(j,a); - vx(1,1) = vx(1,1) + Nwx(1,a)*yl(j,a); - vx(1,2) = vx(1,2) + Nwx(2,a)*yl(j,a); - - vx(2,0) = vx(2,0) + Nwx(0,a)*yl(k,a); - vx(2,1) = vx(2,1) + Nwx(1,a)*yl(k,a); - vx(2,2) = vx(2,2) + Nwx(2,a)*yl(k,a); - - F(0,0) = F(0,0) + Nwx(0,a)*dl(i,a); - F(0,1) = F(0,1) + Nwx(1,a)*dl(i,a); - F(0,2) = F(0,2) + Nwx(2,a)*dl(i,a); - - F(1,0) = F(1,0) + Nwx(0,a)*dl(j,a); - F(1,1) = F(1,1) + Nwx(1,a)*dl(j,a); - F(1,2) = F(1,2) + Nwx(2,a)*dl(j,a); - - F(2,0) = F(2,0) + Nwx(0,a)*dl(k,a); - F(2,1) = F(2,1) + Nwx(1,a)*dl(k,a); - F(2,2) = F(2,2) + Nwx(2,a)*dl(k,a); - - ya_g_f = ya_g_f + Nw(a) * ya_l_f(a); - ya_g_s = ya_g_s + Nw(a) * ya_l_s(a); - ya_g_n = ya_g_n + Nw(a) * ya_l_n(a); - } + double ya_g_f; + double ya_g_s; + double ya_g_n; + + // This element's nodal fields, as Eigen views over the caller's storage + const auto Nwxm = eigen_view<3>(Nwx); // grad(N_a) per column + const auto Nwm = eigen_view(Nw); // shape functions + const auto disp = eigen_view(dl).middleRows<3>(i); // nodal displacements + const auto vel = eigen_view(yl).middleRows<3>(i); // nodal velocities + const auto acc = eigen_view(al).middleRows<3>(i); // nodal accelerations + const auto bfm = eigen_view<3>(bfl); // nodal body force + const auto fbv = eigen_view<3>(fb); // domain body force, constant over the element + auto lRv = eigen_view_mut(lR).topRows<3>(); // rows this kernel adds to + + // Velocity, and the inertia less body force, at this Gauss point + const Eigen::Vector3d v = vel * Nwm; + const Eigen::Vector3d vd = (acc - bfm) * Nwm - fbv; + + // Active stress activation along fiber, sheet and sheet-normal + ya_g_f = eigen_view(ya_l_f).dot(Nwm); + ya_g_s = eigen_view(ya_l_s).dot(Nwm); + ya_g_n = eigen_view(ya_l_n).dot(Nwm); + + // Velocity and deformation gradients: Grad(v) and F = I + Grad(u) + const Matrix<3> vx = vel * Nwxm.transpose(); + const Matrix<3> F = Matrix<3>::Identity() + disp * Nwxm.transpose(); double Jac = F.determinant(); const Matrix<3> Fi = F.inverse(); @@ -1239,7 +1162,6 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, mat_models::compute_visc_stress_and_tangent(dmn, eNoNw, Nwx, vx, F, Svis, Kvis_u, Kvis_v); } - // Compute rho and beta depending on the volumetric penalty model // double rho= 0; @@ -1268,33 +1190,15 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, // Shape function gradients in the current configuration // - const NodalMatrix<3> NxFi = Fi.transpose() * eigen_view<3>(Nwx); + const NodalMatrix<3> NxFi = Fi.transpose() * Nwxm; // Velocity gradient in current configuration const Matrix<3> VxFi = vx * Fi; double rC = beta*pd + VxFi(0,0) + VxFi(1,1) + VxFi(2,2); double rCl = -p + tauC*rC; - // Local residual - // - double T1, T2, T3; - - for (int a = 0; a < eNoNw; a++) { - T1 = Jac*rho*vd(0)*Nw(a); - T2 = Pdev(0,0)*Nwx(0,a) + Pdev(0,1)*Nwx(1,a) + Pdev(0,2)*Nwx(2,a); - T3 = Jac*rCl*NxFi(0,a); - lR(0,a) = lR(0,a) + w*(T1 + T2 + T3); - - T1 = Jac*rho*vd(1)*Nw(a); - T2 = Pdev(1,0)*Nwx(0,a) + Pdev(1,1)*Nwx(1,a) + Pdev(1,2)*Nwx(2,a); - T3 = Jac*rCl*NxFi(1,a); - lR(1,a) = lR(1,a) + w*(T1 + T2 + T3); - - T1 = Jac*rho*vd(2)*Nw(a); - T2 = Pdev(2,0)*Nwx(0,a) + Pdev(2,1)*Nwx(1,a) + Pdev(2,2)*Nwx(2,a); - T3 = Jac*rCl*NxFi(2,a); - lR(2,a) = lR(2,a) + w*(T1 + T2 + T3); - } + // Inertia, the divergence of Pdev, and the pressure/volumetric term + lRv += w * (Jac*rho * vd * Nwm.transpose() + Pdev * Nwxm + Jac*rCl * NxFi); // Strain-displacement matrix; Bm[a] maps node a displacement to Voigt strain // @@ -1332,13 +1236,11 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, // double r13 = 1.0 / 3.0; double r23 = 2.0 / 3.0; - double NxSNx{0.0}, BtDB{0.0}; + double NxSNx{0.0}, BtDB{0.0}, T1{0.0}, T2{0.0}, T3{0.0}; double Tv{0.0}, Ku{0.0}; Eigen::Matrix DBm; - const auto Nwxm = eigen_view<3>(Nwx); - for (int b = 0; b < eNoNw; b++) { DBm.noalias() = Dm * Bm[b]; @@ -1422,7 +1324,6 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, Tv = af*Kvis_v(4,a,b); lK(5,a,b) = lK(5,a,b) + w*(T2 + Tv) + afm*Ku; - // dM_2/dV_3 + af/am *dM_2/dU_3 // BtDB = Bm[a].col(1).dot(DBm.col(2)); From d424f50a3acea1aa5e69abab8be38a1afdec131a Mon Sep 17 00:00:00 2001 From: dseyler Date: Mon, 21 Sep 2026 22:50:53 -0700 Subject: [PATCH 27/42] condensed strain displacmeent computation --- Code/Source/solver/sv_struct.cpp | 128 ++++++++-------- Code/Source/solver/ustruct.cpp | 242 +++++++++++++++---------------- 2 files changed, 171 insertions(+), 199 deletions(-) diff --git a/Code/Source/solver/sv_struct.cpp b/Code/Source/solver/sv_struct.cpp index c00a0b85d..ef36e8c28 100644 --- a/Code/Source/solver/sv_struct.cpp +++ b/Code/Source/solver/sv_struct.cpp @@ -45,10 +45,10 @@ void b_struct_2d(const ComMod& com_mod, const int eNoN, const double w, const Ve for (int a = 0; a < eNoN; a++) { h = h + N(a)*hl(a); - F(0,0) = F(0,0) + Nx(0,a)*dl(i,a); - F(0,1) = F(0,1) + Nx(1,a)*dl(i,a); - F(1,0) = F(1,0) + Nx(0,a)*dl(j,a); - F(1,1) = F(1,1) + Nx(1,a)*dl(j,a); + F(0,0) += Nx(0,a)*dl(i,a); + F(0,1) += Nx(1,a)*dl(i,a); + F(1,0) += Nx(0,a)*dl(j,a); + F(1,1) += Nx(1,a)*dl(j,a); } double Jac = F(0,0)*F(1,1) - F(0,1)*F(1,0); @@ -69,7 +69,7 @@ void b_struct_2d(const ComMod& com_mod, const int eNoN, const double w, const Ve for (int b = 0; b < eNoN; b++) { double Ku = wl*af*N(a)*(nFi(1)*NxFi(0,b) - nFi(0)*NxFi(1,b)); - lK(1,a,b) = lK(1,a,b) + Ku; + lK(1,a,b) += Ku; lK(dof,a,b) = lK(dof,a,b) - Ku; } } @@ -126,15 +126,15 @@ void b_struct_3d(const ComMod& com_mod, const int eNoN, const double w, const Ve // Compute deformation gradient tensor F for (int a = 0; a < eNoN; a++) { h = h + N(a)*hl(a); - F(0,0) = F(0,0) + Nx(0,a)*dl(i,a); - F(0,1) = F(0,1) + Nx(1,a)*dl(i,a); - F(0,2) = F(0,2) + Nx(2,a)*dl(i,a); - F(1,0) = F(1,0) + Nx(0,a)*dl(j,a); - F(1,1) = F(1,1) + Nx(1,a)*dl(j,a); - F(1,2) = F(1,2) + Nx(2,a)*dl(j,a); - F(2,0) = F(2,0) + Nx(0,a)*dl(k,a); - F(2,1) = F(2,1) + Nx(1,a)*dl(k,a); - F(2,2) = F(2,2) + Nx(2,a)*dl(k,a); + F(0,0) += Nx(0,a)*dl(i,a); + F(0,1) += Nx(1,a)*dl(i,a); + F(0,2) += Nx(2,a)*dl(i,a); + F(1,0) += Nx(0,a)*dl(j,a); + F(1,1) += Nx(1,a)*dl(j,a); + F(1,2) += Nx(2,a)*dl(j,a); + F(2,0) += Nx(0,a)*dl(k,a); + F(2,1) += Nx(1,a)*dl(k,a); + F(2,2) += Nx(2,a)*dl(k,a); } double Jac = mat_fun::mat_det(F, 3); @@ -167,15 +167,15 @@ void b_struct_3d(const ComMod& com_mod, const int eNoN, const double w, const Ve for (int b = 0; b < eNoN; b++) { double Ku = wl * af * N(a) * (nFi(1)*NxFi(0,b) - nFi(0)*NxFi(1,b)); - lK(1,a,b) = lK(1,a,b) + Ku; + lK(1,a,b) += Ku; lK(dof,a,b) = lK(dof,a,b) - Ku; Ku = wl*af*N(a)*(nFi(2)*NxFi(0,b) - nFi(0)*NxFi(2,b)); - lK(2,a,b) = lK(2,a,b) + Ku; + lK(2,a,b) += Ku; lK(2*dof,a,b) = lK(2*dof,a,b) - Ku; Ku = wl*af*N(a)*(nFi(2)*NxFi(1,b) - nFi(1)*NxFi(2,b)); - lK(dof+2,a,b) = lK(dof+2,a,b) + Ku; + lK(dof+2,a,b) += Ku; lK(2*dof+1,a,b) = lK(2*dof+1,a,b) - Ku; } } @@ -343,9 +343,9 @@ void construct_dsolid(ComMod& com_mod, CepMod& cep_mod, const mshType& lM, const if (pstEq) { for (int a = 0; a < eNoN; a++) { int Ac = ptr(a); - pSa(Ac) = pSa(Ac) + w*N(a); + pSa(Ac) += w*N(a); for (int i = 0; i < pSn.nrows(); i++) { - pSn(i,Ac) = pSn(i,Ac) + w*N(a)*pSl(i); + pSn(i,Ac) += w*N(a)*pSl(i); } } } @@ -429,9 +429,9 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, Matrix<2> S0 = Matrix<2>::Zero(); for (int a = 0; a < eNoN; a++) { - S0(0,0) = S0(0,0) + N(a)*pS0l(0,a); - S0(1,1) = S0(1,1) + N(a)*pS0l(1,a); - S0(0,1) = S0(0,1) + N(a)*pS0l(2,a); + S0(0,0) += N(a)*pS0l(0,a); + S0(1,1) += N(a)*pS0l(1,a); + S0(0,1) += N(a)*pS0l(2,a); } #ifdef debug_struct_2d dmsg << "ud: " << ud(0) << " " << ud(1); @@ -496,15 +496,14 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, // Strain-displacement matrix; Bm[a] maps node a displacement to Voigt strain // - for (int a = 0; a < eNoN; a++) { - Bm[a](0,0) = Nx(0,a)*F(0,0); - Bm[a](0,1) = Nx(0,a)*F(1,0); + const Matrix<2> Ft = F.transpose(); - Bm[a](1,0) = Nx(1,a)*F(0,1); - Bm[a](1,1) = Nx(1,a)*F(1,1); + for (int a = 0; a < eNoN; a++) { + const auto g = Nxm.col(a); // grad(N_a) - Bm[a](2,0) = (Nx(0,a)*F(0,1) + F(0,0)*Nx(1,a)); - Bm[a](2,1) = (Nx(0,a)*F(1,1) + F(1,0)*Nx(1,a)); + Bm[a].row(0) = g(0) * Ft.row(0); // dE_11 + Bm[a].row(1) = g(1) * Ft.row(1); // dE_22 + Bm[a].row(2) = g(0) * Ft.row(1) + g(1) * Ft.row(0); // 2 dE_12 } // Local stiffness tensor @@ -527,22 +526,22 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, // dM1/du1 BmDBm = Bm[a].col(0).dot(DBm.col(0)); - lK(0,a,b) = lK(0,a,b) + w*( T1 + afu*(BmDBm + Kvis_u(0,a,b)) + afv*Kvis_v(0,a,b) ); + lK(0,a,b) += w*( T1 + afu*(BmDBm + Kvis_u(0,a,b)) + afv*Kvis_v(0,a,b) ); // dM1/du2 BmDBm = Bm[a].col(0).dot(DBm.col(1)); - lK(1,a,b) = lK(1,a,b) + w*( afu*(BmDBm + Kvis_u(1,a,b)) + afv*Kvis_v(1,a,b) ); + lK(1,a,b) += w*( afu*(BmDBm + Kvis_u(1,a,b)) + afv*Kvis_v(1,a,b) ); // dM2/du1 BmDBm = Bm[a].col(1).dot(DBm.col(0)); - lK(dof+0,a,b) = lK(dof+0,a,b) + w*( afu*(BmDBm + Kvis_u(2,a,b)) + afv*Kvis_v(2,a,b) ); + lK(dof+0,a,b) += w*( afu*(BmDBm + Kvis_u(2,a,b)) + afv*Kvis_v(2,a,b) ); // dM2/du2 BmDBm = Bm[a].col(1).dot(DBm.col(1)); - lK(dof+1,a,b) = lK(dof+1,a,b) + w*( T1 + afu*(BmDBm + Kvis_u(3,a,b)) + afv*Kvis_v(3,a,b) ); + lK(dof+1,a,b) += w*( T1 + afu*(BmDBm + Kvis_u(3,a,b)) + afv*Kvis_v(3,a,b) ); } } } @@ -631,12 +630,12 @@ void struct_3d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, Matrix<3> S0 = Matrix<3>::Zero(); for (int a = 0; a < eNoN; a++) { - S0(0,0) = S0(0,0) + N(a)*pS0l(0,a); - S0(1,1) = S0(1,1) + N(a)*pS0l(1,a); - S0(2,2) = S0(2,2) + N(a)*pS0l(2,a); - S0(0,1) = S0(0,1) + N(a)*pS0l(3,a); - S0(1,2) = S0(1,2) + N(a)*pS0l(4,a); - S0(2,0) = S0(2,0) + N(a)*pS0l(5,a); + S0(0,0) += N(a)*pS0l(0,a); + S0(1,1) += N(a)*pS0l(1,a); + S0(2,2) += N(a)*pS0l(2,a); + S0(0,1) += N(a)*pS0l(3,a); + S0(1,2) += N(a)*pS0l(4,a); + S0(2,0) += N(a)*pS0l(5,a); } S0(1,0) = S0(0,1); @@ -703,30 +702,17 @@ void struct_3d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, // Strain-displacement matrix; Bm[a] maps node a displacement to Voigt strain // - for (int a = 0; a < eNoN; a++) { - Bm[a](0,0) = Nx(0,a)*F(0,0); - Bm[a](0,1) = Nx(0,a)*F(1,0); - Bm[a](0,2) = Nx(0,a)*F(2,0); - - Bm[a](1,0) = Nx(1,a)*F(0,1); - Bm[a](1,1) = Nx(1,a)*F(1,1); - Bm[a](1,2) = Nx(1,a)*F(2,1); + const Matrix<3> Ft = F.transpose(); - Bm[a](2,0) = Nx(2,a)*F(0,2); - Bm[a](2,1) = Nx(2,a)*F(1,2); - Bm[a](2,2) = Nx(2,a)*F(2,2); - - Bm[a](3,0) = (Nx(0,a)*F(0,1) + F(0,0)*Nx(1,a)); - Bm[a](3,1) = (Nx(0,a)*F(1,1) + F(1,0)*Nx(1,a)); - Bm[a](3,2) = (Nx(0,a)*F(2,1) + F(2,0)*Nx(1,a)); - - Bm[a](4,0) = (Nx(1,a)*F(0,2) + F(0,1)*Nx(2,a)); - Bm[a](4,1) = (Nx(1,a)*F(1,2) + F(1,1)*Nx(2,a)); - Bm[a](4,2) = (Nx(1,a)*F(2,2) + F(2,1)*Nx(2,a)); - - Bm[a](5,0) = (Nx(2,a)*F(0,0) + F(0,2)*Nx(0,a)); - Bm[a](5,1) = (Nx(2,a)*F(1,0) + F(1,2)*Nx(0,a)); - Bm[a](5,2) = (Nx(2,a)*F(2,0) + F(2,2)*Nx(0,a)); + for (int a = 0; a < eNoN; a++) { + const auto g = Nxm.col(a); // grad(N_a) + + Bm[a].row(0) = g(0) * Ft.row(0); // dE_11 + Bm[a].row(1) = g(1) * Ft.row(1); // dE_22 + Bm[a].row(2) = g(2) * Ft.row(2); // dE_33 + Bm[a].row(3) = g(0) * Ft.row(1) + g(1) * Ft.row(0); // 2 dE_12 + Bm[a].row(4) = g(1) * Ft.row(2) + g(2) * Ft.row(1); // 2 dE_23 + Bm[a].row(5) = g(2) * Ft.row(0) + g(0) * Ft.row(2); // 2 dE_31 } // Local stiffness tensor @@ -751,47 +737,47 @@ void struct_3d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, // dM1/du1 BmDBm = Bm[a].col(0).dot(DBm.col(0)); - lK(0,a,b) = lK(0,a,b) + w*( T1 + afu*(BmDBm + Kvis_u(0,a,b)) + afv*Kvis_v(0,a,b) ); + lK(0,a,b) += w*( T1 + afu*(BmDBm + Kvis_u(0,a,b)) + afv*Kvis_v(0,a,b) ); // dM1/du2 BmDBm = Bm[a].col(0).dot(DBm.col(1)); - lK(1,a,b) = lK(1,a,b) + w*( afu*(BmDBm + Kvis_u(1,a,b)) + afv*(Kvis_v(1,a,b)) ); + lK(1,a,b) += w*( afu*(BmDBm + Kvis_u(1,a,b)) + afv*Kvis_v(1,a,b) ); // dM1/du3 BmDBm = Bm[a].col(0).dot(DBm.col(2)); - lK(2,a,b) = lK(2,a,b) + w*( afu*(BmDBm + Kvis_u(2,a,b)) + afv*Kvis_v(2,a,b) ); + lK(2,a,b) += w*( afu*(BmDBm + Kvis_u(2,a,b)) + afv*Kvis_v(2,a,b) ); // dM2/du1 BmDBm = Bm[a].col(1).dot(DBm.col(0)); - lK(dof+0,a,b) = lK(dof+0,a,b) + w*( afu*(BmDBm + Kvis_u(3,a,b)) + afv*Kvis_v(3,a,b) ); + lK(dof+0,a,b) += w*( afu*(BmDBm + Kvis_u(3,a,b)) + afv*Kvis_v(3,a,b) ); // dM2/du2 BmDBm = Bm[a].col(1).dot(DBm.col(1)); - lK(dof+1,a,b) = lK(dof+1,a,b) + w*(T1 + afu*(BmDBm + Kvis_u(4,a,b)) + afv*Kvis_v(4,a,b) ); + lK(dof+1,a,b) += w*(T1 + afu*(BmDBm + Kvis_u(4,a,b)) + afv*Kvis_v(4,a,b) ); // dM2/du3 BmDBm = Bm[a].col(1).dot(DBm.col(2)); - lK(dof+2,a,b) = lK(dof+2,a,b) + w*( afu*(BmDBm + Kvis_u(5,a,b)) + afv*Kvis_v(5,a,b) ); + lK(dof+2,a,b) += w*( afu*(BmDBm + Kvis_u(5,a,b)) + afv*Kvis_v(5,a,b) ); // dM3/du1 BmDBm = Bm[a].col(2).dot(DBm.col(0)); - lK(2*dof+0,a,b) = lK(2*dof+0,a,b) + w*( afu*(BmDBm + Kvis_u(6,a,b)) + afv*Kvis_v(6,a,b) ); + lK(2*dof+0,a,b) += w*( afu*(BmDBm + Kvis_u(6,a,b)) + afv*Kvis_v(6,a,b) ); // dM3/du2 BmDBm = Bm[a].col(2).dot(DBm.col(1)); - lK(2*dof+1,a,b) = lK(2*dof+1,a,b) + w*( afu*(BmDBm + Kvis_u(7,a,b)) + afv*Kvis_v(7,a,b) ); + lK(2*dof+1,a,b) += w*( afu*(BmDBm + Kvis_u(7,a,b)) + afv*Kvis_v(7,a,b) ); // dM3/du3 BmDBm = Bm[a].col(2).dot(DBm.col(2)); - lK(2*dof+2,a,b) = lK(2*dof+2,a,b) + w*( T1 + afu*(BmDBm + Kvis_u(8,a,b)) + afv*Kvis_v(8,a,b) ); + lK(2*dof+2,a,b) += w*( T1 + afu*(BmDBm + Kvis_u(8,a,b)) + afv*Kvis_v(8,a,b) ); } } } diff --git a/Code/Source/solver/ustruct.cpp b/Code/Source/solver/ustruct.cpp index 3fba32ada..28749bb0d 100644 --- a/Code/Source/solver/ustruct.cpp +++ b/Code/Source/solver/ustruct.cpp @@ -57,10 +57,10 @@ void b_ustruct_2d(const ComMod& com_mod, const int eNoN, const double w, const V for (int a = 0; a < eNoN; a++) { h = h + N(a)*hl(a); - F(0,0) = F(0,0) + Nx(0,a)*dl(i,a); - F(0,1) = F(0,1) + Nx(1,a)*dl(i,a); - F(1,0) = F(1,0) + Nx(0,a)*dl(j,a); - F(1,1) = F(1,1) + Nx(1,a)*dl(j,a); + F(0,0) += Nx(0,a)*dl(i,a); + F(0,1) += Nx(1,a)*dl(i,a); + F(1,0) += Nx(0,a)*dl(j,a); + F(1,1) += Nx(1,a)*dl(j,a); } double Jac = F(0,0)*F(1,1) - F(0,1)*F(1,0); @@ -81,8 +81,8 @@ void b_ustruct_2d(const ComMod& com_mod, const int eNoN, const double w, const V for (int b = 0; b < eNoN; b++) { double Ku = wl*af*N(a)*(nFi(1)*NxFi(0,b) - nFi(0)*NxFi(1,b)); - lKd(1,a,b) = lKd(1,a,b) + Ku; - lK(1,a,b) = lK(1,a,b) + afm*Ku; + lKd(1,a,b) += Ku; + lK(1,a,b) += afm*Ku; lKd(2,a,b) = lKd(2,a,b) - Ku; lK(3,a,b) = lK(3,a,b) - afm*Ku; @@ -128,15 +128,15 @@ void b_ustruct_3d(const ComMod& com_mod, const int eNoN, const double w, const V for (int a = 0; a < eNoN; a++) { h = h + N(a)*hl(a); - F(0,0) = F(0,0) + Nx(0,a)*dl(i,a); - F(0,1) = F(0,1) + Nx(1,a)*dl(i,a); - F(0,2) = F(0,2) + Nx(2,a)*dl(i,a); - F(1,0) = F(1,0) + Nx(0,a)*dl(j,a); - F(1,1) = F(1,1) + Nx(1,a)*dl(j,a); - F(1,2) = F(1,2) + Nx(2,a)*dl(j,a); - F(2,0) = F(2,0) + Nx(0,a)*dl(k,a); - F(2,1) = F(2,1) + Nx(1,a)*dl(k,a); - F(2,2) = F(2,2) + Nx(2,a)*dl(k,a); + F(0,0) += Nx(0,a)*dl(i,a); + F(0,1) += Nx(1,a)*dl(i,a); + F(0,2) += Nx(2,a)*dl(i,a); + F(1,0) += Nx(0,a)*dl(j,a); + F(1,1) += Nx(1,a)*dl(j,a); + F(1,2) += Nx(2,a)*dl(j,a); + F(2,0) += Nx(0,a)*dl(k,a); + F(2,1) += Nx(1,a)*dl(k,a); + F(2,2) += Nx(2,a)*dl(k,a); } double Jac = mat_fun::mat_det(F, 3); @@ -161,21 +161,21 @@ void b_ustruct_3d(const ComMod& com_mod, const int eNoN, const double w, const V for (int b = 0; b < eNoN; b++) { double Ku = wl*af*N(a)*(nFi(1)*NxFi(0,b) - nFi(0)*NxFi(1,b)); - lKd(1,a,b) = lKd(1,a,b) + Ku; - lK(1,a,b) = lK(1,a,b) + afm*Ku; + lKd(1,a,b) += Ku; + lK(1,a,b) += afm*Ku; lKd(3,a,b) = lKd(3,a,b) - Ku; lK(4,a,b) = lK(4,a,b) - afm*Ku; Ku = wl*af*N(a)*(nFi(2)*NxFi(0,b) - nFi(0)*NxFi(2,b)); - lKd(2,a,b) = lKd(2,a,b) + Ku; + lKd(2,a,b) += Ku; lK(2,a,b) = lK(2,a,b) + afm*Ku; lKd(6,a,b) = lKd(6,a,b) - Ku; lK(8,a,b) = lK(8,a,b) - afm*Ku; Ku = wl*af*N(a)*(nFi(2)*NxFi(1,b) - nFi(1)*NxFi(2,b)); - lKd(5,a,b) = lKd(5,a,b) + Ku; + lKd(5,a,b) += Ku; lK(6,a,b) = lK(6,a,b) + afm*Ku; lKd(7,a,b) = lKd(7,a,b) - Ku; @@ -504,8 +504,8 @@ void ustruct_2d_c(ComMod& com_mod, CepMod& cep_mod, const bool vmsFlag, const in for (int a = 0; a < eNoNq; a++) { p = p + Nq(a)*yl(k,a); pd = pd + Nq(a)*al(k,a); - px(0) = px(0) + Nqx(0,a)*yl(k,a); - px(1) = px(1) + Nqx(1,a)*yl(k,a); + px(0) += Nqx(0,a)*yl(k,a); + px(1) += Nqx(1,a)*yl(k,a); } // Compute rho and beta depending on the volumetric penalty model @@ -547,7 +547,7 @@ void ustruct_2d_c(ComMod& com_mod, CepMod& cep_mod, const bool vmsFlag, const in const NodalVector rMNqx = NqxFi.transpose() * eigen_view<2>(rM); for (int a = 0; a < eNoNq; a++) { - lR(2,a) = lR(2,a) + w*Jac*(Nq(a)*rC + tauM*rMNqx(a)); + lR(2,a) += w*Jac*(Nq(a)*rC + tauM*rMNqx(a)); } const NodalMatrix<2> VxNwx = VxFi.transpose() * NwxFi; @@ -560,7 +560,7 @@ void ustruct_2d_c(ComMod& com_mod, CepMod& cep_mod, const bool vmsFlag, const in for (int b = 0; b < eNoNw; b++) { for (int a = 0; a < eNoNq; a++) { - NxNx = NqxFi(0,a)*NwxFi(0,b) + NqxFi(1,a)*NwxFi(1,b); + NxNx = NqxFi.col(a).dot(NwxFi.col(b)); // dC/dV_1 + af/am *dC/dU_1 // @@ -568,31 +568,31 @@ void ustruct_2d_c(ComMod& com_mod, CepMod& cep_mod, const bool vmsFlag, const in T1 = tauM*(rMNqx(a)*NwxFi(0,b) - rMNwx(b)*NqxFi(0,a)); T2 = -tauM*NxNx*PxFi(0); Ku = w*af*Jac*(T0 + T1 + T2); - lKd(4,a,b) = lKd(4,a,b) + Ku; + lKd(4,a,b) += Ku; T1 = (am*tauM*rho)*NqxFi(0,a)*Nw(b) + af*Nq(a)*NwxFi(0,b); - lK(6,a,b) = lK(6,a,b) + w*Jac*T1 + afm*Ku; + lK(6,a,b) += w*Jac*T1 + afm*Ku; // dC/dV_2 + af/am *dC/dU_2 T0 = Nq(a)*(rC*NwxFi(1,b) - VxNwx(1,b)); T1 = tauM*(rMNqx(a)*NwxFi(1,b) - rMNwx(b)*NqxFi(1,a)); T2 = -tauM*NxNx*PxFi(1); Ku = w*af*Jac*(T0 + T1 + T2); - lKd(5,a,b) = lKd(5,a,b) + Ku; + lKd(5,a,b) += Ku; T1 = (am*tauM*rho)*NqxFi(1,a)*Nw(b) + af*Nq(a)*NwxFi(1,b); - lK(8,a,b) = lK(8,a,b) + w*Jac*T1 + afm*Ku; + lK(8,a,b) += w*Jac*T1 + afm*Ku; } } for (int b = 0; b < eNoNq; b++) { for (int a = 0; a < eNoNq; a++) { // dC/dP - NxNx = NqxFi(0,a)*NqxFi(0,b) + NqxFi(1,a)*NqxFi(1,b); + NxNx = NqxFi.col(a).dot(NqxFi.col(b)); T0 = (am*beta + af*dbeta*pd)*Nq(a)*Nq(b); - T1 = NqxFi(0,a)*vd(0) + NqxFi(1,a)*vd(1); + T1 = NqxFi.col(a).dot(vd); T2 = T0 + af*tauM*(NxNx + drho*T1*Nq(b)); - lK(9,a,b) = lK(9,a,b) + w*Jac*T2; + lK(9,a,b) += w*Jac*T2; } } } @@ -676,9 +676,9 @@ void ustruct_3d_c(ComMod& com_mod, CepMod& cep_mod, const bool vmsFlag, const in for (int a = 0; a < eNoNq; a++) { p = p + Nq(a)*yl(l,a); pd = pd + Nq(a)*al(l,a); - px(0) = px(0) + Nqx(0,a)*yl(l,a); - px(1) = px(1) + Nqx(1,a)*yl(l,a); - px(2) = px(2) + Nqx(2,a)*yl(l,a); + px(0) += Nqx(0,a)*yl(l,a); + px(1) += Nqx(1,a)*yl(l,a); + px(2) += Nqx(2,a)*yl(l,a); } // Compute rho and beta depending on the volumetric penalty model @@ -721,7 +721,7 @@ void ustruct_3d_c(ComMod& com_mod, CepMod& cep_mod, const bool vmsFlag, const in const NodalVector rMNqx = NqxFi.transpose() * eigen_view<3>(rM); for (int a = 0; a < eNoNq; a++) { - lR(3,a) = lR(3,a) + w*Jac*(Nq(a)*rC + tauM*rMNqx(a)); + lR(3,a) += w*Jac*(Nq(a)*rC + tauM*rMNqx(a)); } const NodalMatrix<3> VxNwx = VxFi.transpose() * NwxFi; @@ -734,7 +734,7 @@ void ustruct_3d_c(ComMod& com_mod, CepMod& cep_mod, const bool vmsFlag, const in for (int b = 0; b < eNoNw; b++) { for (int a = 0; a < eNoNq; a++) { - NxNx = NqxFi(0,a)*NwxFi(0,b) + NqxFi(1,a)*NwxFi(1,b) + NqxFi(2,a)*NwxFi(2,b); + NxNx = NqxFi.col(a).dot(NwxFi.col(b)); // dC/dV_1 + af/am *dC/dU_1 // @@ -742,20 +742,20 @@ void ustruct_3d_c(ComMod& com_mod, CepMod& cep_mod, const bool vmsFlag, const in T1 = tauM*(rMNqx(a)*NwxFi(0,b) - rMNwx(b)*NqxFi(0,a)); T2 = -tauM*NxNx*PxFi(0); Ku = w*af*Jac*(T0 + T1 + T2); - lKd(9,a,b) = lKd(9,a,b) + Ku; + lKd(9,a,b) += Ku; T1 = (am*tauM*rho)*NqxFi(0,a)*Nw(b) + af*Nq(a)*NwxFi(0,b); - lK(12,a,b) = lK(12,a,b) + w*Jac*T1 + afm*Ku; + lK(12,a,b) += w*Jac*T1 + afm*Ku; // dC/dV_2 + af/am *dC/dU_2 T0 = Nq(a)*(rC*NwxFi(1,b) - VxNwx(1,b)); T1 = tauM*(rMNqx(a)*NwxFi(1,b) - rMNwx(b)*NqxFi(1,a)); T2 = -tauM*NxNx*PxFi(1); Ku = w*af*Jac*(T0 + T1 + T2); - lKd(10,a,b) = lKd(10,a,b) + Ku; + lKd(10,a,b) += Ku; T1 = (am*tauM*rho)*NqxFi(1,a)*Nw(b) + af*Nq(a)*NwxFi(1,b); - lK(13,a,b) = lK(13,a,b) + w*Jac*T1 + afm*Ku; + lK(13,a,b) += w*Jac*T1 + afm*Ku; // dC/dV_3 + af/am *dC/dU_3 // @@ -763,21 +763,21 @@ void ustruct_3d_c(ComMod& com_mod, CepMod& cep_mod, const bool vmsFlag, const in T1 = tauM*(rMNqx(a)*NwxFi(2,b) - rMNwx(b)*NqxFi(2,a)); T2 = -tauM*NxNx*PxFi(2); Ku = w*af*Jac*(T0 + T1 + T2); - lKd(11,a,b) = lKd(11,a,b) + Ku; + lKd(11,a,b) += Ku; T1 = (am*tauM*rho)*NqxFi(2,a)*Nw(b) + af*Nq(a)*NwxFi(2,b); - lK(14,a,b) = lK(14,a,b) + w*Jac*T1 + afm*Ku; + lK(14,a,b) += w*Jac*T1 + afm*Ku; } } for (int b = 0; b < eNoNq; b++) { for (int a = 0; a < eNoNq; a++) { // dC/dP - NxNx = NqxFi(0,a)*NqxFi(0,b) + NqxFi(1,a)*NqxFi(1,b) + NqxFi(2,a)*NqxFi(2,b); + NxNx = NqxFi.col(a).dot(NqxFi.col(b)); T0 = (am*beta + af*dbeta*pd)*Nq(a)*Nq(b); - T1 = NqxFi(0,a)*vd(0) + NqxFi(1,a)*vd(1) + NqxFi(2,a)*vd(2); + T1 = NqxFi.col(a).dot(vd); T2 = T0 + af*tauM*(NxNx + drho*T1*Nq(b)); - lK(15,a,b) = lK(15,a,b) + w*Jac*T2; + lK(15,a,b) += w*Jac*T2; } } } @@ -940,15 +940,14 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, // std::array, consts::maxNoN> Bm; - for (int a = 0; a < eNoNw; a++) { - Bm[a](0,0) = Nwx(0,a)*F(0,0); - Bm[a](0,1) = Nwx(0,a)*F(1,0); + const Matrix<2> Ft = F.transpose(); - Bm[a](1,0) = Nwx(1,a)*F(0,1); - Bm[a](1,1) = Nwx(1,a)*F(1,1); + for (int a = 0; a < eNoNw; a++) { + const auto g = Nwxm.col(a); // grad(N_a) - Bm[a](2,0) = Nwx(0,a)*F(0,1) + F(0,0)*Nwx(1,a); - Bm[a](2,1) = Nwx(0,a)*F(1,1) + F(1,0)*Nwx(1,a); + Bm[a].row(0) = g(0) * Ft.row(0); // dE_11 + Bm[a].row(1) = g(1) * Ft.row(1); // dE_22 + Bm[a].row(2) = g(0) * Ft.row(1) + g(1) * Ft.row(0); // 2 dE_12 } const NodalMatrix<2> VxNx = VxFi.transpose() * NxFi; @@ -978,7 +977,7 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, T2 = -tauC*Jac*NxFi(0,a)*VxNx(0,b); Ku = w*af*(T1 + T2 + BtDB + NxSNx + Kvis_u(0,a,b)); - lKd(0,a,b) = lKd(0,a,b) + Ku; + lKd(0,a,b) += Ku; T1 = am*Jac*rho*Nw(a)*Nw(b); T2 = T1 + af*Jac*tauC*rho*NxFi(0,a)*NxFi(0,b); @@ -993,11 +992,11 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, T3 = Jac*rCl*(NxFi(0,a)*NxFi(1,b) - NxFi(1,a)*NxFi(0,b)); Ku = w*af*(T1 + T2 + T3 + BtDB + Kvis_u(1,a,b)); - lKd(1,a,b) = lKd(1,a,b) + Ku; + lKd(1,a,b) += Ku; T2 = af*Jac*tauC*rho*NxFi(0,a)*NxFi(1,b); Tv = af*Kvis_v(1,a,b); - lK(1,a,b) = lK(1,a,b) + w*(T2 + Tv) + afm*Ku; + lK(1,a,b) += w*(T2 + Tv) + afm*Ku; // dM_2/dV_1 + af/am *dM_2/dU_1 // @@ -1007,11 +1006,11 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, T3 = Jac*rCl*(NxFi(1,a)*NxFi(0,b) - NxFi(0,a)*NxFi(1,b)); Ku = w*af*(T1 + T2 + T3 + BtDB + Kvis_u(2,a,b)); - lKd(2,a,b) = lKd(2,a,b) + Ku; + lKd(2,a,b) += Ku; T2 = af*Jac*tauC*rho*NxFi(1,a)*NxFi(0,b); Tv = af*Kvis_v(2,a,b); - lK(3,a,b) = lK(3,a,b) + w*(T2 + Tv) + afm*Ku; + lK(3,a,b) += w*(T2 + Tv) + afm*Ku; // dM_2/dV_2 + af/am *dM_2/dU_2 // @@ -1020,12 +1019,12 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, T2 = -tauC*Jac*NxFi(1,a)*VxNx(1,b); Ku = w*af*(T1 + T2 + BtDB + NxSNx + Kvis_u(3,a,b)); - lKd(3,a,b) = lKd(3,a,b) + Ku; + lKd(3,a,b) += Ku; T1 = am*Jac*rho*Nw(a)*Nw(b); T2 = T1 + af*Jac*tauC*rho*NxFi(1,a)*NxFi(1,b); Tv = af*Kvis_v(3,a,b); - lK(4,a,b) = lK(4,a,b) + w*(T2 + Tv) + afm*Ku; + lK(4,a,b) += w*(T2 + Tv) + afm*Ku; } } @@ -1036,11 +1035,11 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, // dM_0/dP T0 = am*tauC*beta + af*(tauC*dbeta*pd - 1.0); T1 = T0*NxFi(0,a)*Nq(b) + af*drho*vd(0)*Nw(a)*Nq(b); - lK(2,a,b) = lK(2,a,b) + w*Jac*T1; + lK(2,a,b) += w*Jac*T1; // dM_1/dP T1 = T0*NxFi(1,a)*Nq(b) + af*drho*vd(1)*Nw(a)*Nq(b); - lK(6,a,b) = lK(6,a,b) + w*Jac*T1; + lK(6,a,b) += w*Jac*T1; } } } @@ -1204,30 +1203,17 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, // std::array, consts::maxNoN> Bm; - for (int a = 0; a < eNoNw; a++) { - Bm[a](0,0) = Nwx(0,a)*F(0,0); - Bm[a](0,1) = Nwx(0,a)*F(1,0); - Bm[a](0,2) = Nwx(0,a)*F(2,0); - - Bm[a](1,0) = Nwx(1,a)*F(0,1); - Bm[a](1,1) = Nwx(1,a)*F(1,1); - Bm[a](1,2) = Nwx(1,a)*F(2,1); + const Matrix<3> Ft = F.transpose(); - Bm[a](2,0) = Nwx(2,a)*F(0,2); - Bm[a](2,1) = Nwx(2,a)*F(1,2); - Bm[a](2,2) = Nwx(2,a)*F(2,2); - - Bm[a](3,0) = (Nwx(0,a)*F(0,1) + F(0,0)*Nwx(1,a)); - Bm[a](3,1) = (Nwx(0,a)*F(1,1) + F(1,0)*Nwx(1,a)); - Bm[a](3,2) = (Nwx(0,a)*F(2,1) + F(2,0)*Nwx(1,a)); - - Bm[a](4,0) = (Nwx(1,a)*F(0,2) + F(0,1)*Nwx(2,a)); - Bm[a](4,1) = (Nwx(1,a)*F(1,2) + F(1,1)*Nwx(2,a)); - Bm[a](4,2) = (Nwx(1,a)*F(2,2) + F(2,1)*Nwx(2,a)); - - Bm[a](5,0) = (Nwx(2,a)*F(0,0) + F(0,2)*Nwx(0,a)); - Bm[a](5,1) = (Nwx(2,a)*F(1,0) + F(1,2)*Nwx(0,a)); - Bm[a](5,2) = (Nwx(2,a)*F(2,0) + F(2,2)*Nwx(0,a)); + for (int a = 0; a < eNoNw; a++) { + const auto g = Nwxm.col(a); // grad(N_a) + + Bm[a].row(0) = g(0) * Ft.row(0); // dE_11 + Bm[a].row(1) = g(1) * Ft.row(1); // dE_22 + Bm[a].row(2) = g(2) * Ft.row(2); // dE_33 + Bm[a].row(3) = g(0) * Ft.row(1) + g(1) * Ft.row(0); // 2 dE_12 + Bm[a].row(4) = g(1) * Ft.row(2) + g(2) * Ft.row(1); // 2 dE_23 + Bm[a].row(5) = g(2) * Ft.row(0) + g(0) * Ft.row(2); // 2 dE_31 } const NodalMatrix<3> VxNx = VxFi.transpose() * NxFi; @@ -1257,7 +1243,7 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, T2 = -tauC*Jac*NxFi(0,a)*VxNx(0,b); Ku = w*af*(T1 + T2 + BtDB + NxSNx + Kvis_u(0,a,b)); - lKd(0,a,b) = lKd(0,a,b) + Ku; + lKd(0,a,b) += Ku; T1 = am*Jac*rho*Nw(a)*Nw(b); T2 = T1 + af*Jac*tauC*rho*NxFi(0,a)*NxFi(0,b); @@ -1271,11 +1257,11 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, T3 = Jac*rCl*(NxFi(0,a)*NxFi(1,b) - NxFi(1,a)*NxFi(0,b)); Ku = w*af*(T1 + T2 + T3 + BtDB + Kvis_u(1,a,b)); - lKd(1,a,b) = lKd(1,a,b) + Ku; + lKd(1,a,b) += Ku; T2 = af*Jac*tauC*rho*NxFi(0,a)*NxFi(1,b); Tv = af*Kvis_v(1,a,b); - lK(1,a,b) = lK(1,a,b) + w*(T2 + Tv) + afm*Ku; + lK(1,a,b) += w*(T2 + Tv) + afm*Ku; // dM_1/dV_3 + af/am *dM_1/dU_3 // @@ -1285,11 +1271,11 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, T3 = Jac*rCl*(NxFi(0,a)*NxFi(2,b) - NxFi(2,a)*NxFi(0,b)); Ku = w*af*(T1 + T2 + T3 + BtDB + Kvis_u(2,a,b)); - lKd(2,a,b) = lKd(2,a,b) + Ku; + lKd(2,a,b) += Ku; T2 = af*Jac*tauC*rho*NxFi(0,a)*NxFi(2,b); Tv = af*Kvis_v(2,a,b); - lK(2,a,b) = lK(2,a,b) + w*(T2 + Tv) + afm*Ku; + lK(2,a,b) += w*(T2 + Tv) + afm*Ku; // dM_2/dV_1 + af/am *dM_2/dU_1 // @@ -1300,12 +1286,12 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, T3 = Jac*rCl*(NxFi(1,a)*NxFi(0,b) - NxFi(0,a)*NxFi(1,b)); Ku = w*af*(T1 + T2 + T3 + BtDB + Kvis_u(3,a,b)); - lKd(3,a,b) = lKd(3,a,b) + Ku; + lKd(3,a,b) += Ku; T2 = af*Jac*tauC*rho*NxFi(1,a)*NxFi(0,b); Tv = af*Kvis_v(3,a,b); - lK(4,a,b) = lK(4,a,b) + w*(T2 + Tv) + afm*Ku; + lK(4,a,b) += w*(T2 + Tv) + afm*Ku; // dM_2/dV_2 + af/am *dM_2/dU_2 // @@ -1317,12 +1303,12 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, Ku = w*af*(T1 + T2 + BtDB + NxSNx + Kvis_u(4,a,b)); - lKd(4,a,b) = lKd(4,a,b) + Ku; + lKd(4,a,b) += Ku; T1 = am*Jac*rho*Nw(a)*Nw(b); T2 = T1 + af*Jac*tauC*rho*NxFi(1,a)*NxFi(1,b); Tv = af*Kvis_v(4,a,b); - lK(5,a,b) = lK(5,a,b) + w*(T2 + Tv) + afm*Ku; + lK(5,a,b) += w*(T2 + Tv) + afm*Ku; // dM_2/dV_3 + af/am *dM_2/dU_3 // @@ -1334,11 +1320,11 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, Ku = w*af*(T1 + T2 + T3 + BtDB + Kvis_u(5,a,b)); - lKd(5,a,b) = lKd(5,a,b) + Ku; + lKd(5,a,b) += Ku; T2 = af*Jac*tauC*rho*NxFi(1,a)*NxFi(2,b); Tv = af*Kvis_v(5,a,b); - lK(6,a,b) = lK(6,a,b) + w*(T2 + Tv) + afm*Ku; + lK(6,a,b) += w*(T2 + Tv) + afm*Ku; // dM_3/dV_1 + af/am *dM_3/dU_1 // @@ -1349,11 +1335,11 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, T3 = Jac*rCl*(NxFi(2,a)*NxFi(0,b) - NxFi(0,a)*NxFi(2,b)); Ku = w*af*(T1 + T2 + T3 + BtDB + Kvis_u(6,a,b)); - lKd(6,a,b) = lKd(6,a,b) + Ku; + lKd(6,a,b) += Ku; T2 = af*Jac*tauC*rho*NxFi(2,a)*NxFi(0,b); Tv = af*Kvis_v(6,a,b); - lK(8,a,b) = lK(8,a,b) + w*(T2 + Tv) + afm*Ku; + lK(8,a,b) += w*(T2 + Tv) + afm*Ku; // dM_3/dV_2 + af/am *dM_3/dU_2 // @@ -1364,12 +1350,12 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, T3 = Jac*rCl*(NxFi(2,a)*NxFi(1,b) - NxFi(1,a)*NxFi(2,b)); Ku = w*af*(T1 + T2 + T3 + BtDB + Kvis_u(7,a,b)); - lKd(7,a,b) = lKd(7,a,b) + Ku; + lKd(7,a,b) += Ku; T2 = af*Jac*tauC*rho*NxFi(2,a)*NxFi(1,b); Tv = af*Kvis_v(7,a,b); - lK(9,a,b) = lK(9,a,b) + w*(T2 + Tv) + afm*Ku; + lK(9,a,b) += w*(T2 + Tv) + afm*Ku; // dM_3/dV_3 + af/am *dM_3/dU_3 // @@ -1379,13 +1365,13 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, T2 = -tauC*Jac*NxFi(2,a)*VxNx(2,b); Ku = w*af*(T1 + T2 + BtDB + NxSNx + Kvis_u(8,a,b)); - lKd(8,a,b) = lKd(8,a,b) + Ku; + lKd(8,a,b) += Ku; T1 = am*Jac*rho*Nw(a)*Nw(b); T2 = T1 + af*Jac*tauC*rho*NxFi(2,a)*NxFi(2,b); Tv = af*Kvis_v(8,a,b); - lK(10,a,b) = lK(10,a,b) + w*(T2 + Tv) + afm*Ku; + lK(10,a,b) += w*(T2 + Tv) + afm*Ku; } } @@ -1396,15 +1382,15 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, // dM_0/dP T0 = am*tauC*beta + af*(tauC*dbeta*pd - 1.0); T1 = T0*NxFi(0,a)*Nq(b) + af*drho*vd(0)*Nw(a)*Nq(b); - lK(3,a,b) = lK(3,a,b) + w*Jac*T1; + lK(3,a,b) += w*Jac*T1; // dM_1/dP T1 = T0*NxFi(1,a)*Nq(b) + af*drho*vd(1)*Nw(a)*Nq(b); - lK(7,a,b) = lK(7,a,b) + w*Jac*T1; + lK(7,a,b) += w*Jac*T1; // dM_2/dP T1 = T0*NxFi(2,a)*Nq(b) + af*drho*vd(2)*Nw(a)*Nq(b); - lK(11,a,b) = lK(11,a,b) + w*Jac*T1; + lK(11,a,b) += w*Jac*T1; } } } @@ -1424,12 +1410,12 @@ void ustruct_do_assem(ComMod& com_mod, const int d, const Vector& eqN, cons // Momentum equation residual is assembled at mapped rows int rowN = idMap(eqN(a)); for (int i = 0; i < nsd; i++) { - R(i,rowN) = R(i,rowN) + lR(i,a); + R(i,rowN) += lR(i,a); } // Continuity equation residual is assembled at unmapped rows rowN = eqN(a); - R(nsd,rowN) = R(nsd,rowN) + lR(nsd,a); + R(nsd,rowN) += lR(nsd,a); } if (nsd == 3) { @@ -1450,9 +1436,9 @@ void ustruct_do_assem(ComMod& com_mod, const int d, const Vector& eqN, cons } for (int i = 0; i < 3; i++) { - Val(i,ptr) = Val(i,ptr) + lK (i,a,b); - Val(i+4,ptr) = Val(i+4,ptr) + lK(i+4,a,b); - Val(i+8,ptr) = Val(i+8,ptr) + lK(i+8,a,b); + Val(i,ptr) += lK (i,a,b); + Val(i+4,ptr) += lK(i+4,a,b); + Val(i+8,ptr) += lK(i+8,a,b); } } @@ -1460,9 +1446,9 @@ void ustruct_do_assem(ComMod& com_mod, const int d, const Vector& eqN, cons for (int b = 0; b < d; b++) { int colN = eqN(b); int ptr = get_col_ptr(com_mod, rowN, colN); - Val(3 ,ptr) = Val(3 ,ptr) + lK(3 ,a,b); - Val(7 ,ptr) = Val(7 ,ptr) + lK(7 ,a,b); - Val(11,ptr) = Val(11,ptr) + lK(11,a,b); + Val(3 ,ptr) += lK(3 ,a,b); + Val(7 ,ptr) += lK(7 ,a,b); + Val(11,ptr) += lK(11,a,b); } } @@ -1479,8 +1465,8 @@ void ustruct_do_assem(ComMod& com_mod, const int d, const Vector& eqN, cons int ptr = get_col_ptr(com_mod, rowN, colN); for (int i = 0; i < 3; i++) { - Kd(i+9,ptr) = Kd(i+9,ptr) + lKd(i+9,a,b); - Val(i+12,ptr) = Val(i+12,ptr) + lK(i+12,a,b); + Kd(i+9,ptr) += lKd(i+9,a,b); + Val(i+12,ptr) += lK(i+12,a,b); } } @@ -1489,7 +1475,7 @@ void ustruct_do_assem(ComMod& com_mod, const int d, const Vector& eqN, cons int colN = eqN(b); int ptr = get_col_ptr(com_mod, rowN, colN); - Val(15,ptr) = Val(15,ptr) + lK(15,a,b); + Val(15,ptr) += lK(15,a,b); } } @@ -1508,12 +1494,12 @@ void ustruct_do_assem(ComMod& com_mod, const int d, const Vector& eqN, cons int ptr = get_col_ptr(com_mod, rowN, colN); for (int i = 0; i < 4; i++) { - Kd(i,ptr) = Kd(i,ptr) + lKd(i,a,b); + Kd(i,ptr) += lKd(i,a,b); } for (int i = 0; i < 2; i++) { - Val(i,ptr) = Val(i,ptr) + lK(i,a,b); - Val(i+3,ptr) = Val(i+3,ptr) + lK(i+3,a,b); + Val(i,ptr) += lK(i,a,b); + Val(i+3,ptr) += lK(i+3,a,b); } } @@ -1522,8 +1508,8 @@ void ustruct_do_assem(ComMod& com_mod, const int d, const Vector& eqN, cons int colN = eqN(b); int ptr = get_col_ptr(com_mod, rowN, colN); - Val(2,ptr) = Val(2,ptr) + lK(2,a,b); - Val(5,ptr) = Val(5,ptr) + lK(5,a,b); + Val(2,ptr) += lK(2,a,b); + Val(5,ptr) += lK(5,a,b); } } @@ -1541,7 +1527,7 @@ void ustruct_do_assem(ComMod& com_mod, const int d, const Vector& eqN, cons for (int i = 0; i < 2; i++) { Kd (i+4,ptr) = Kd(i+4,ptr) + lKd(i+4,a,b); - Val(i+6,ptr) = Val(i+6,ptr) + lK(i+6,a,b); + Val(i+6,ptr) += lK(i+6,a,b); } } @@ -1549,7 +1535,7 @@ void ustruct_do_assem(ComMod& com_mod, const int d, const Vector& eqN, cons for (int b = 0; b < d; b++) { int colN = eqN(b); int ptr = get_col_ptr(com_mod, rowN, colN); - Val(8,ptr) = Val(8,ptr) + lK(8,a,b); + Val(8,ptr) += lK(8,a,b); } } } @@ -1621,10 +1607,10 @@ void ustruct_r(ComMod& com_mod, const SolutionStates& solutions) for (int i = rowPtr(a); i <= rowPtr(a+1)-1; i++) { int c = colPtr(i); - KU(0,a) = KU(0,a) + Kd(0 ,i)*Rd(0,c) + Kd(1 ,i)*Rd(1,c) + Kd(2 ,i)*Rd(2,c); - KU(1,a) = KU(1,a) + Kd(3 ,i)*Rd(0,c) + Kd(4 ,i)*Rd(1,c) + Kd(5 ,i)*Rd(2,c); - KU(2,a) = KU(2,a) + Kd(6 ,i)*Rd(0,c) + Kd(7 ,i)*Rd(1,c) + Kd(8 ,i)*Rd(2,c); - KU(3,a) = KU(3,a) + Kd(9,i)*Rd(0,c) + Kd(10,i)*Rd(1,c) + Kd(11,i)*Rd(2,c); + KU(0,a) += Kd(0 ,i)*Rd(0,c) + Kd(1 ,i)*Rd(1,c) + Kd(2 ,i)*Rd(2,c); + KU(1,a) += Kd(3 ,i)*Rd(0,c) + Kd(4 ,i)*Rd(1,c) + Kd(5 ,i)*Rd(2,c); + KU(2,a) += Kd(6 ,i)*Rd(0,c) + Kd(7 ,i)*Rd(1,c) + Kd(8 ,i)*Rd(2,c); + KU(3,a) += Kd(9,i)*Rd(0,c) + Kd(10,i)*Rd(1,c) + Kd(11,i)*Rd(2,c); } } @@ -1646,9 +1632,9 @@ void ustruct_r(ComMod& com_mod, const SolutionStates& solutions) for (int i = rowPtr(a); i <= rowPtr(a+1); i++) { int c = colPtr(i); - KU(0,a) = KU(0,a) + Kd(0,i)*Rd(0,c) + Kd(1,i)*Rd(1,c); - KU(1,a) = KU(1,a) + Kd(2,i)*Rd(0,c) + Kd(3,i)*Rd(1,c); - KU(2,a) = KU(2,a) + Kd(4,i)*Rd(0,c) + Kd(5,i)*Rd(1,c); + KU(0,a) += Kd(0,i)*Rd(0,c) + Kd(1,i)*Rd(1,c); + KU(1,a) += Kd(2,i)*Rd(0,c) + Kd(3,i)*Rd(1,c); + KU(2,a) += Kd(4,i)*Rd(0,c) + Kd(5,i)*Rd(1,c); } } From cc08b5ebf7e11065f6b32a7925225ba69f5d70cb Mon Sep 17 00:00:00 2001 From: dseyler Date: Mon, 21 Sep 2026 22:51:24 -0700 Subject: [PATCH 28/42] Implemented eigen view helper in viscosity models --- Code/Source/solver/mat_models.cpp | 23 ++++++++--------------- Code/Source/solver/mat_models.h | 1 + 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/Code/Source/solver/mat_models.cpp b/Code/Source/solver/mat_models.cpp index 5726d4898..fd082031c 100644 --- a/Code/Source/solver/mat_models.cpp +++ b/Code/Source/solver/mat_models.cpp @@ -1586,7 +1586,7 @@ void compute_visc_stress_potential(const double mu, const int eNoN, const Array< const Matrix& vx, const Matrix& F, Matrix& Svis, Array3& Kvis_u, Array3& Kvis_v) { - Eigen::Map> Nx_map(Nx.data(), nsd, eNoN); + const auto Nxm = eigen_view(Nx); // Required intermediate terms for stress and tangent const Matrix F_Ft = F * F.transpose(); @@ -1594,8 +1594,8 @@ void compute_visc_stress_potential(const double mu, const int eNoN, const Array< const Matrix F_vxt = F * vx.transpose(); // F_Nx(i,a) = sum_j F(i,j) * Nx(j,a), and likewise for vx. - const NodalMatrix F_Nx = F * Nx_map; - const NodalMatrix vx_Nx = vx * Nx_map; + const NodalMatrix F_Nx = F * Nxm; + const NodalMatrix vx_Nx = vx * Nxm; // 2nd Piola-Kirchhoff stress due to viscosity // Svis = mu * 1/2 * ( (F^T * dv/dX) + (F^T * dv/dX)^T ) @@ -1604,10 +1604,7 @@ void compute_visc_stress_potential(const double mu, const int eNoN, const Array< // Tangent matrix contributions due to viscosity for (int b = 0; b < eNoN; ++b) { for (int a = 0; a < eNoN; ++a) { - double Nx_Nx = 0.0; - for (int i = 0; i < nsd; ++i) { - Nx_Nx += Nx(i,a) * Nx(i,b); - } + const double Nx_Nx = Nxm.col(a).dot(Nxm.col(b)); for (int i = 0; i < nsd; ++i) { for (int j = 0; j < nsd; ++j) { @@ -1648,10 +1645,9 @@ void compute_visc_stress_newtonian(const double mu, const int eNoN, const Array< const Matrix& vx, const Matrix& F, Matrix& Svis, Array3& Kvis_u, Array3& Kvis_v) { - Eigen::Map> Nx_map(Nx.data(), nsd, eNoN); + const auto Nxm = eigen_view(Nx); // Get identity matrix, Jacobian, and F^-1 - const auto Idm = Matrix::Identity(); const double J = F.determinant(); const Matrix Fi = F.inverse(); @@ -1662,7 +1658,7 @@ void compute_visc_stress_newtonian(const double mu, const int eNoN, const Array< const Matrix ddev = mat_fun::mat_dev(vx_Fi_symm); // Nx_Fi(i,a) = sum_j Nx(j,a) * Fi(j,i), which is Fi^T * Nx. - const NodalMatrix Nx_Fi = Fi.transpose() * Nx_map; + const NodalMatrix Nx_Fi = Fi.transpose() * Nxm; const NodalMatrix ddev_Nx_Fi = ddev * Nx_Fi; const NodalMatrix vx_Fi_Nx_Fi = vx_Fi * Nx_Fi; @@ -1674,10 +1670,7 @@ void compute_visc_stress_newtonian(const double mu, const int eNoN, const Array< constexpr double r2d = 2.0 / nsd; for (int b = 0; b < eNoN; ++b) { for (int a = 0; a < eNoN; ++a) { - double Nx_Fi_Nx_Fi = 0.0; - for (int i = 0; i < nsd; ++i) { - Nx_Fi_Nx_Fi += Nx_Fi(i,a) * Nx_Fi(i,b); - } + const double Nx_Fi_Nx_Fi = Nx_Fi.col(a).dot(Nx_Fi.col(b)); for (int i = 0; i < nsd; ++i) { for (int j = 0; j < nsd; ++j) { @@ -1690,7 +1683,7 @@ void compute_visc_stress_newtonian(const double mu, const int eNoN, const Array< r2d * Nx_Fi(i,a) * vx_Fi_Nx_Fi(j,b))); // Derivative of the residual w.r.t velocity - Kvis_v(ii,a,b) = mu * J * (Nx_Fi_Nx_Fi * Idm(i,j) + + Kvis_v(ii,a,b) = mu * J * (Nx_Fi_Nx_Fi * (i == j) + Nx_Fi(i,b) * Nx_Fi(j,a) - r2d * Nx_Fi(i,a) * Nx_Fi(j,b)); } } diff --git a/Code/Source/solver/mat_models.h b/Code/Source/solver/mat_models.h index a6c1622cf..f573c104c 100644 --- a/Code/Source/solver/mat_models.h +++ b/Code/Source/solver/mat_models.h @@ -20,6 +20,7 @@ namespace mat_models { using mat_fun::Matrix; using mat_fun::Tensor; using mat_fun::NodalMatrix; +using mat_fun::eigen_view; void actv_strain(const ComMod& com_mod, const CepMod& cep_mod, const double gf, const int nfd, const Array& fl, Array& Fa); From d2590a694765a19c60b8c7bc2e45af1f30a40133 Mon Sep 17 00:00:00 2001 From: dseyler Date: Mon, 21 Sep 2026 23:21:33 -0700 Subject: [PATCH 29/42] add compound assignments for consistency --- Code/Source/solver/ustruct.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Code/Source/solver/ustruct.cpp b/Code/Source/solver/ustruct.cpp index 28749bb0d..2f5dfbb78 100644 --- a/Code/Source/solver/ustruct.cpp +++ b/Code/Source/solver/ustruct.cpp @@ -982,7 +982,7 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, T1 = am*Jac*rho*Nw(a)*Nw(b); T2 = T1 + af*Jac*tauC*rho*NxFi(0,a)*NxFi(0,b); Tv = af*Kvis_v(0,a,b); - lK(0,a,b) = lK(0,a,b) + w*(T2 + Tv) + afm*Ku; + lK(0,a,b) += w*(T2 + Tv) + afm*Ku; // dM_1/dV_2 + af/am *dM_1/dU_2 // @@ -1248,7 +1248,7 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, T1 = am*Jac*rho*Nw(a)*Nw(b); T2 = T1 + af*Jac*tauC*rho*NxFi(0,a)*NxFi(0,b); Tv = af*Kvis_v(0,a,b); - lK(0,a,b) = lK(0,a,b) + w*(T2 + Tv) + afm*Ku; + lK(0,a,b) += w*(T2 + Tv) + afm*Ku; // dM_1/dV_2 + af/am *dM_1/dU_2 BtDB = Bm[a].col(0).dot(DBm.col(1)); @@ -1617,10 +1617,10 @@ void ustruct_r(ComMod& com_mod, const SolutionStates& solutions) all_fun::commu(com_mod, KU); for (int a = 0; a < tnNo; a++) { - R(0,a) = R(0,a) - ami*KU(0,a); - R(1,a) = R(1,a) - ami*KU(1,a); - R(2,a) = R(2,a) - ami*KU(2,a); - R(3,a) = R(3,a) - ami*KU(3,a); + R(0,a) -= ami*KU(0,a); + R(1,a) -= ami*KU(1,a); + R(2,a) -= ami*KU(2,a); + R(3,a) -= ami*KU(3,a); } } else { Array KU(3,tnNo); @@ -1641,9 +1641,9 @@ void ustruct_r(ComMod& com_mod, const SolutionStates& solutions) all_fun::commu(com_mod, KU); for (int a = 0; a < tnNo; a++) { - R(0,a) = R(0,a) - ami*KU(0,a); - R(1,a) = R(1,a) - ami*KU(1,a); - R(2,a) = R(2,a) - ami*KU(2,a); + R(0,a) -= ami*KU(0,a); + R(1,a) -= ami*KU(1,a); + R(2,a) -= ami*KU(2,a); } } } From a22846f4ffc8edfce6d3dbc8f5ff49f18e8e3910 Mon Sep 17 00:00:00 2001 From: dseyler Date: Tue, 22 Sep 2026 00:21:52 -0700 Subject: [PATCH 30/42] reverted two argument f + s to fl for fiber matrix --- Code/Source/solver/fsi.cpp | 3 +-- Code/Source/solver/mat_models.cpp | 35 ++++++++++++++----------------- Code/Source/solver/mat_models.h | 2 +- Code/Source/solver/sv_struct.cpp | 4 ++-- Code/Source/solver/ustruct.cpp | 4 ++-- 5 files changed, 22 insertions(+), 26 deletions(-) diff --git a/Code/Source/solver/fsi.cpp b/Code/Source/solver/fsi.cpp index e674705eb..7b4e3e730 100644 --- a/Code/Source/solver/fsi.cpp +++ b/Code/Source/solver/fsi.cpp @@ -187,8 +187,7 @@ void construct_fsi(ComMod& com_mod, CepMod& cep_mod, const mshType& lM, const So } // Shape function gradients and the viscous response are constant - // within linear simplex elements (tetrahedra, triangles). Bi- and - // trilinear hexahedra are sometimes called linear but do not qualify. + // within linear triangles and tetrahedra. const bool recompute_visc = (g == 0 || !fs_1[0].lShpF); if (recompute_visc) { diff --git a/Code/Source/solver/mat_models.cpp b/Code/Source/solver/mat_models.cpp index fd082031c..53de423b1 100644 --- a/Code/Source/solver/mat_models.cpp +++ b/Code/Source/solver/mat_models.cpp @@ -256,14 +256,12 @@ std::pair, Tensor> bar_to_iso( * Validates that the directions are not parallel and that the operation is valid in 3D. * * @tparam nsd Number of spatial dimensions. - * @param[in] f Fiber direction. - * @param[in] s Sheet direction. + * @param[in] fl Fiber directions matrix (nsd x nfd), where col(0) is fiber, col(1) is sheet. * @return Normalized sheet-normal direction vector. * @throws std::runtime_error if directions are parallel or if called in 2D. */ template -Eigen::Matrix compute_sheet_normal(const Eigen::Matrix& f, - const Eigen::Matrix& s) +Eigen::Matrix compute_sheet_normal(const Eigen::Map>& fl) { using namespace mat_fun; @@ -271,7 +269,7 @@ Eigen::Matrix compute_sheet_normal(const Eigen::Matrix 0) is not defined in 2D."); } else { // nsd == 3 - auto n_normal = cross_product(f, s); + auto n_normal = cross_product(fl.col(0), fl.col(1)); double norm_n = sqrt(n_normal.dot(n_normal)); static constexpr double sheet_normal_tol = 1.0e-10; @@ -286,16 +284,13 @@ Eigen::Matrix compute_sheet_normal(const Eigen::Matrix void compute_pk2cc(const ComMod &com_mod, const CepMod &cep_mod, const dmnType &lDmn, const Matrix &F, const int nfd, - const Array &fl, + const Eigen::Map> &fl, const double ya_f, const double ya_s, const double ya_n, Matrix &S, Matrix<3 * (nsd - 1)> &Dm, double &Ja) { using namespace consts; using namespace mat_fun; using namespace utils; - // Fiber directions are the caller's storage. View rather than copying. - Eigen::Map> fl_m(fl.data(), nsd, nfd); - #define n_debug_compute_pk2cc #ifdef debug_compute_pk2cc DebugMsg dmsg(__func__, com_mod.cm.idcm()); @@ -338,12 +333,12 @@ void compute_pk2cc(const ComMod &com_mod, const CepMod &cep_mod, } // Aliases for fiber directions - const auto& fib_dir1 = fl_m.col(0); + const auto& fib_dir1 = fl.col(0); // fib_dir2 only exists when nfd >= 2 Eigen::Matrix fib_dir2; if (nfd >= 2) { - fib_dir2 = fl_m.col(1); + fib_dir2 = fl.col(1); } else { fib_dir2 = Eigen::Matrix::Zero(); } @@ -515,7 +510,7 @@ void compute_pk2cc(const ComMod &com_mod, const CepMod &cep_mod, } // Compute sheet-normal direction - auto fib_dir3 = compute_sheet_normal(fl_m.col(0), fl_m.col(1)); + auto fib_dir3 = compute_sheet_normal(fl); // Compute isochoric component of E Matrix E = 0.50 * (J2d*C - Idm); @@ -586,7 +581,7 @@ void compute_pk2cc(const ComMod &com_mod, const CepMod &cep_mod, } // Compute sheet-normal direction - auto fib_dir3 = compute_sheet_normal(fl_m.col(0), fl_m.col(1)); + auto fib_dir3 = compute_sheet_normal(fl); // Compute cross fiber-sheet structure tensor Matrix Hfs = 0.5 * (fib_dir1 * fib_dir2.transpose() + fib_dir2 * fib_dir1.transpose()); @@ -683,7 +678,7 @@ void compute_pk2cc(const ComMod &com_mod, const CepMod &cep_mod, } // Compute sheet-normal direction - auto fib_dir3 = compute_sheet_normal(fl_m.col(0), fl_m.col(1)); + auto fib_dir3 = compute_sheet_normal(fl); // Compute cross fiber-sheet structure tensor auto Hfs = 0.5 * (fib_dir1 * fib_dir2.transpose() + fib_dir2 * fib_dir1.transpose()); @@ -786,7 +781,7 @@ void compute_pk2cc(const ComMod &com_mod, const CepMod &cep_mod, Matrix N1; // Compute and store invariants and derivatives wrt C in array of matrices/tensors - CANNModel.computeInvariantsAndDerivatives(C, fl_m, nfd, J2d, J4d, Ci, Idm, Tfa, N1, psi, Inv, dInv, ddInv); + CANNModel.computeInvariantsAndDerivatives(C, fl, nfd, J2d, J4d, Ci, Idm, Tfa, N1, psi, Inv, dInv, ddInv); // Strain energy function and derivatives CANNModel.evaluate(Inv, psi, dpsi, ddpsi); @@ -820,11 +815,11 @@ void compute_pk2cc(const ComMod &com_mod, const CepMod &cep_mod, // this next to the definition: a signature change here that is not mirrored // below fails at link time rather than at compile time. template void compute_pk2cc<2>(const ComMod&, const CepMod&, const dmnType&, - const Matrix<2>&, const int, const Array&, + const Matrix<2>&, const int, const Eigen::Map>&, const double, const double, const double, Matrix<2>&, Matrix<3>&, double&); template void compute_pk2cc<3>(const ComMod&, const CepMod&, const dmnType&, - const Matrix<3>&, const int, const Array&, + const Matrix<3>&, const int, const Eigen::Map>&, const double, const double, const double, Matrix<3>&, Matrix<6>&, double&); /** @@ -843,13 +838,14 @@ void compute_pk2cc(const ComMod& com_mod, const CepMod& cep_mod, const dmnType& // Copy deformation gradient to Eigen matrix auto F_2D = mat_fun::convert_to_eigen_matrix(F); + const auto fl_2D = eigen_view<2>(fl); // Initialize stress and elasticity tensors Eigen::Matrix2d S_2D = Eigen::Matrix2d::Zero(); Eigen::Matrix3d Dm_2D = Eigen::Matrix3d::Zero(); // Call templated function - compute_pk2cc<2>(com_mod, cep_mod, lDmn, F_2D, nfd, fl, ya_f, ya_s, ya_n, S_2D, Dm_2D, Ja); + compute_pk2cc<2>(com_mod, cep_mod, lDmn, F_2D, nfd, fl_2D, ya_f, ya_s, ya_n, S_2D, Dm_2D, Ja); // Copy results back mat_fun::convert_to_array(S_2D, S); @@ -859,6 +855,7 @@ void compute_pk2cc(const ComMod& com_mod, const CepMod& cep_mod, const dmnType& // Copy deformation gradient to Eigen matrix auto F_3D = mat_fun::convert_to_eigen_matrix(F); + const auto fl_3D = eigen_view<3>(fl); // Initialize stress and elasticity tensors Eigen::Matrix3d S_3D = Eigen::Matrix3d::Zero(); @@ -866,7 +863,7 @@ void compute_pk2cc(const ComMod& com_mod, const CepMod& cep_mod, const dmnType& Dm_3D.setZero(); // Call templated function - compute_pk2cc<3>(com_mod, cep_mod, lDmn, F_3D, nfd, fl, ya_f, ya_s, ya_n, S_3D, Dm_3D, Ja); + compute_pk2cc<3>(com_mod, cep_mod, lDmn, F_3D, nfd, fl_3D, ya_f, ya_s, ya_n, S_3D, Dm_3D, Ja); // Copy results back mat_fun::convert_to_array(S_3D, S); diff --git a/Code/Source/solver/mat_models.h b/Code/Source/solver/mat_models.h index f573c104c..27fbc1d0d 100644 --- a/Code/Source/solver/mat_models.h +++ b/Code/Source/solver/mat_models.h @@ -59,7 +59,7 @@ void voigt_to_cc(const int nsd, const Array& Dm, Tensor4& CC); template void compute_pk2cc(const ComMod &com_mod, const CepMod &cep_mod, const dmnType &lDmn, const Matrix &F, const int nfd, - const Array &fl, const double ya_f, + const Eigen::Map> &fl, const double ya_f, const double ya_s, const double ya_n, Matrix &S, Matrix<3 * (nsd - 1)> &Dm, double &Ja); diff --git a/Code/Source/solver/sv_struct.cpp b/Code/Source/solver/sv_struct.cpp index ef36e8c28..a15408315 100644 --- a/Code/Source/solver/sv_struct.cpp +++ b/Code/Source/solver/sv_struct.cpp @@ -451,7 +451,7 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, Matrix<2> S; Matrix<3> Dm; double Ja; - mat_models::compute_pk2cc(com_mod, cep_mod, dmn, F, nFn, fN, ya_g_f, ya_g_s, + mat_models::compute_pk2cc(com_mod, cep_mod, dmn, F, nFn, eigen_view<2>(fN), ya_g_f, ya_g_s, ya_g_n, S, Dm, Ja); // Viscous 2nd Piola-Kirchhoff stress and tangent contributions @@ -652,7 +652,7 @@ void struct_3d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, Matrix<3> S; Matrix<6> Dm; double Ja; - mat_models::compute_pk2cc(com_mod, cep_mod, dmn, F, nFn, fN, ya_g_f, ya_g_s, + mat_models::compute_pk2cc(com_mod, cep_mod, dmn, F, nFn, eigen_view<3>(fN), ya_g_f, ya_g_s, ya_g_n, S, Dm, Ja); // Viscous 2nd Piola-Kirchhoff stress and tangent contributions diff --git a/Code/Source/solver/ustruct.cpp b/Code/Source/solver/ustruct.cpp index 2f5dfbb78..8d8a3546f 100644 --- a/Code/Source/solver/ustruct.cpp +++ b/Code/Source/solver/ustruct.cpp @@ -879,7 +879,7 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, Matrix<2> Siso; Matrix<3> Dm; double Ja = 0; - mat_models::compute_pk2cc(com_mod, cep_mod, eq.dmn[cDmn], F, nFn, fN, ya_g_f, + mat_models::compute_pk2cc(com_mod, cep_mod, eq.dmn[cDmn], F, nFn, eigen_view<2>(fN), ya_g_f, ya_g_s, ya_g_n, Siso, Dm, Ja); // Viscous 2nd Piola-Kirchhoff stress and tangent contributions @@ -1145,7 +1145,7 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, Matrix<3> Siso; Matrix<6> Dm; double Ja = 0; - mat_models::compute_pk2cc(com_mod, cep_mod, eq.dmn[cDmn], F, nFn, fN, ya_g_f, + mat_models::compute_pk2cc(com_mod, cep_mod, eq.dmn[cDmn], F, nFn, eigen_view<3>(fN), ya_g_f, ya_g_s, ya_g_n, Siso, Dm, Ja); // Viscous 2nd Piola-Kirchhoff stress and tangent contributions From 3c04e255296e9326404ac2d81ad089cfb705e903 Mon Sep 17 00:00:00 2001 From: dseyler Date: Tue, 22 Sep 2026 10:59:24 -0700 Subject: [PATCH 31/42] removed dead locals and bare declarations --- Code/Source/solver/sv_struct.cpp | 51 +++++++-------------- Code/Source/solver/ustruct.cpp | 79 +++++++++++--------------------- 2 files changed, 45 insertions(+), 85 deletions(-) diff --git a/Code/Source/solver/sv_struct.cpp b/Code/Source/solver/sv_struct.cpp index a15408315..e6e0e5a93 100644 --- a/Code/Source/solver/sv_struct.cpp +++ b/Code/Source/solver/sv_struct.cpp @@ -386,26 +386,21 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, // double rho = dmn.prop.at(PhysicalPropertyType::solid_density); double dmp = dmn.prop.at(PhysicalPropertyType::damping); - Vector fb({dmn.prop.at(PhysicalPropertyType::f_x), dmn.prop.at(PhysicalPropertyType::f_y)}); + const Eigen::Vector2d fb{dmn.prop.at(PhysicalPropertyType::f_x), + dmn.prop.at(PhysicalPropertyType::f_y)}; double afu = eq.af * eq.beta*dt*dt; double afv = eq.af * eq.gam*dt; double amd = eq.am * rho + eq.af * eq.gam * dt * dmp; double afl = eq.af * eq.beta * dt * dt; int i = eq.s; - int j = i + 1; #ifdef debug_struct_2d dmsg << "i: " << i; - dmsg << "j: " << j; dmsg << "amd: " << amd; dmsg << "afl: " << afl; dmsg << "w: " << w; #endif - double ya_g_f; - double ya_g_s; - double ya_g_n; - // This element's nodal fields, as Eigen views over the caller's storage const auto Nxm = eigen_view<2>(Nx); // grad(N_a) per column const auto Nm = eigen_view(N); // shape functions @@ -413,16 +408,15 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, const auto vel = eigen_view(yl).middleRows<2>(i); // nodal velocities const auto acc = eigen_view(al).middleRows<2>(i); // nodal accelerations const auto bfm = eigen_view<2>(bfl); // nodal body force - const auto fbv = eigen_view<2>(fb); // domain body force, constant over the element auto lRv = eigen_view_mut(lR).topRows<2>(); // rows this kernel adds to // Inertia, damping and body force: the term the residual weights with N - const Eigen::Vector2d ud = (rho*(acc - bfm) + dmp*vel) * Nm - rho * fbv; + const Eigen::Vector2d ud = (rho*(acc - bfm) + dmp*vel) * Nm - rho * fb; // Active stress activation along fiber, sheet and sheet-normal - ya_g_f = eigen_view(ya_l_f).dot(Nm); - ya_g_s = eigen_view(ya_l_s).dot(Nm); - ya_g_n = eigen_view(ya_l_n).dot(Nm); + const double ya_g_f = eigen_view(ya_l_f).dot(Nm); + const double ya_g_s = eigen_view(ya_l_s).dot(Nm); + const double ya_g_n = eigen_view(ya_l_n).dot(Nm); // Prestress at this Gauss point: interpolate pS0l, held in Voigt // order [11, 22, 12], into the three independent components of S0. @@ -433,6 +427,9 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, S0(1,1) += N(a)*pS0l(1,a); S0(0,1) += N(a)*pS0l(2,a); } + + S0(1,0) = S0(0,1); + #ifdef debug_struct_2d dmsg << "ud: " << ud(0) << " " << ud(1); dmsg << "F: " << F(0,0); @@ -441,8 +438,6 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, dmsg << "ya_g_n: " << ya_g_n; #endif - S0(1,0) = S0(0,1); - // Velocity and deformation gradients: Grad(v) and F = I + Grad(u) const Matrix<2> vx = vel * Nxm.transpose(); const Matrix<2> F = Matrix<2>::Identity() + disp * Nxm.transpose(); @@ -578,9 +573,9 @@ void struct_3d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, // double rho = dmn.prop.at(PhysicalPropertyType::solid_density); double dmp = dmn.prop.at(PhysicalPropertyType::damping); - Vector fb({dmn.prop.at(PhysicalPropertyType::f_x), - dmn.prop.at(PhysicalPropertyType::f_y), - dmn.prop.at(PhysicalPropertyType::f_z)}); + const Eigen::Vector3d fb{dmn.prop.at(PhysicalPropertyType::f_x), + dmn.prop.at(PhysicalPropertyType::f_y), + dmn.prop.at(PhysicalPropertyType::f_z)}; double afu = eq.af * eq.beta*dt*dt; double afv = eq.af * eq.gam*dt; @@ -595,17 +590,6 @@ void struct_3d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, #endif int i = eq.s; - int j = i + 1; - int k = j + 1; - - double F_f[3][3]={}; - F_f[0][0] = 1.0; - F_f[1][1] = 1.0; - F_f[2][2] = 1.0; - - double ya_g_f; - double ya_g_s; - double ya_g_n; // This element's nodal fields, as Eigen views over the caller's storage const auto Nxm = eigen_view<3>(Nx); // grad(N_a) per column @@ -614,16 +598,15 @@ void struct_3d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, const auto vel = eigen_view(yl).middleRows<3>(i); // nodal velocities const auto acc = eigen_view(al).middleRows<3>(i); // nodal accelerations const auto bfm = eigen_view<3>(bfl); // nodal body force - const auto fbv = eigen_view<3>(fb); // domain body force, constant over the element auto lRv = eigen_view_mut(lR).topRows<3>(); // rows this kernel adds to // Inertia, damping and body force: the term the residual weights with N - const Eigen::Vector3d ud = (rho*(acc - bfm) + dmp*vel) * Nm - rho * fbv; + const Eigen::Vector3d ud = (rho*(acc - bfm) + dmp*vel) * Nm - rho * fb; // Active stress activation along fiber, sheet and sheet-normal - ya_g_f = eigen_view(ya_l_f).dot(Nm); - ya_g_s = eigen_view(ya_l_s).dot(Nm); - ya_g_n = eigen_view(ya_l_n).dot(Nm); + const double ya_g_f = eigen_view(ya_l_f).dot(Nm); + const double ya_g_s = eigen_view(ya_l_s).dot(Nm); + const double ya_g_n = eigen_view(ya_l_n).dot(Nm); // Prestress at this Gauss point: interpolate pS0l, held in Voigt // order [11, 22, 33, 12, 23, 31], into the six independent components of S0. @@ -647,7 +630,7 @@ void struct_3d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, const Matrix<3> F = Matrix<3>::Identity() + disp * Nxm.transpose(); // 2nd Piola-Kirchhoff tensor (S) and material stiffness tensor in - // Voigt notationa (Dm) + // Voigt notation (Dm) // Matrix<3> S; Matrix<6> Dm; diff --git a/Code/Source/solver/ustruct.cpp b/Code/Source/solver/ustruct.cpp index 8d8a3546f..475a7933e 100644 --- a/Code/Source/solver/ustruct.cpp +++ b/Code/Source/solver/ustruct.cpp @@ -454,19 +454,16 @@ void ustruct_2d_c(ComMod& com_mod, CepMod& cep_mod, const bool vmsFlag, const in auto& dmn = eq.dmn[cDmn]; const double dt = com_mod.dt; - Vector fb(2); - fb[0] = dmn.prop[PhysicalPropertyType::f_x]; - fb[1] = dmn.prop[PhysicalPropertyType::f_y]; - fb[2] = dmn.prop[PhysicalPropertyType::f_z]; + const Eigen::Vector2d fb{dmn.prop[PhysicalPropertyType::f_x], + dmn.prop[PhysicalPropertyType::f_y]}; double am = eq.am; double af = eq.af * eq.gam * dt; double afm = af / am; - // {i,j} := velocity dofs; {k} := pressure dof + // Velocity dofs start at i; k is the pressure dof. int i = eq.s; - int j = i + 1; - int k = j + 1; + int k = i + 2; #ifdef debug_ustruct_2d_c dmsg << "am: " << am; @@ -482,11 +479,10 @@ void ustruct_2d_c(ComMod& com_mod, CepMod& cep_mod, const bool vmsFlag, const in const auto vel = eigen_view(yl).middleRows<2>(i); // nodal velocities const auto acc = eigen_view(al).middleRows<2>(i); // nodal accelerations const auto bfm = eigen_view<2>(bfl); // nodal body force - const auto fbv = eigen_view<2>(fb); // domain body force, constant over the element // Velocity, and the inertia less body force, at this Gauss point const Eigen::Vector2d v = vel * Nwm; - const Eigen::Vector2d vd = (acc - bfm) * Nwm - fbv; + const Eigen::Vector2d vd = (acc - bfm) * Nwm - fb; // Velocity and deformation gradients: Grad(v) and F = I + Grad(u) const Matrix<2> vx = vel * Nwxm.transpose(); @@ -625,20 +621,17 @@ void ustruct_3d_c(ComMod& com_mod, CepMod& cep_mod, const bool vmsFlag, const in auto& dmn = eq.dmn[cDmn]; const double dt = com_mod.dt; - Vector fb(3); - fb[0] = dmn.prop[PhysicalPropertyType::f_x]; - fb[1] = dmn.prop[PhysicalPropertyType::f_y]; - fb[2] = dmn.prop[PhysicalPropertyType::f_z]; + const Eigen::Vector3d fb{dmn.prop[PhysicalPropertyType::f_x], + dmn.prop[PhysicalPropertyType::f_y], + dmn.prop[PhysicalPropertyType::f_z]}; double am = eq.am; double af = eq.af * eq.gam * dt; double afm = af / am; - // {i,j} := velocity dofs; {k} := pressure dof + // Velocity dofs start at i; l is the pressure dof. int i = eq.s; - int j = i + 1; - int k = j + 1; - int l = k + 1; + int l = i + 3; #ifdef debug_ustruct_3d_c dmsg << "am: " << am; @@ -654,11 +647,10 @@ void ustruct_3d_c(ComMod& com_mod, CepMod& cep_mod, const bool vmsFlag, const in const auto vel = eigen_view(yl).middleRows<3>(i); // nodal velocities const auto acc = eigen_view(al).middleRows<3>(i); // nodal accelerations const auto bfm = eigen_view<3>(bfl); // nodal body force - const auto fbv = eigen_view<3>(fb); // domain body force, constant over the element // Velocity, and the inertia less body force, at this Gauss point const Eigen::Vector3d v = vel * Nwm; - const Eigen::Vector3d vd = (acc - bfm) * Nwm - fbv; + const Eigen::Vector3d vd = (acc - bfm) * Nwm - fb; // Velocity and deformation gradients: Grad(v) and F = I + Grad(u) const Matrix<3> vx = vel * Nwxm.transpose(); @@ -814,18 +806,16 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, // Define parameters // - Vector fb(2); - fb[0] = dmn.prop[PhysicalPropertyType::f_x]; - fb[1] = dmn.prop[PhysicalPropertyType::f_y]; + const Eigen::Vector2d fb{dmn.prop[PhysicalPropertyType::f_x], + dmn.prop[PhysicalPropertyType::f_y]}; double am = eq.am; double af = eq.af * eq.gam * dt; double afm = af / am; - // {i,j} := velocity dofs; {k} := pressure dof + // Velocity dofs start at i; k is the pressure dof. int i = eq.s; - int j = i + 1; - int k = j + 1; + int k = i + 2; #ifdef debug_ustruct_2d_m dmsg << "am: " << am; @@ -834,10 +824,6 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, dmsg << "i: " << i; #endif - double ya_g_f; - double ya_g_s; - double ya_g_n; - // This element's nodal fields, as Eigen views over the caller's storage const auto Nwxm = eigen_view<2>(Nwx); // grad(N_a) per column const auto Nwm = eigen_view(Nw); // shape functions @@ -845,17 +831,16 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, const auto vel = eigen_view(yl).middleRows<2>(i); // nodal velocities const auto acc = eigen_view(al).middleRows<2>(i); // nodal accelerations const auto bfm = eigen_view<2>(bfl); // nodal body force - const auto fbv = eigen_view<2>(fb); // domain body force, constant over the element auto lRv = eigen_view_mut(lR).topRows<2>(); // rows this kernel adds to // Velocity, and the inertia less body force, at this Gauss point const Eigen::Vector2d v = vel * Nwm; - const Eigen::Vector2d vd = (acc - bfm) * Nwm - fbv; + const Eigen::Vector2d vd = (acc - bfm) * Nwm - fb; // Active stress activation along fiber, sheet and sheet-normal - ya_g_f = eigen_view(ya_l_f).dot(Nwm); - ya_g_s = eigen_view(ya_l_s).dot(Nwm); - ya_g_n = eigen_view(ya_l_n).dot(Nwm); + const double ya_g_f = eigen_view(ya_l_f).dot(Nwm); + const double ya_g_s = eigen_view(ya_l_s).dot(Nwm); + const double ya_g_n = eigen_view(ya_l_n).dot(Nwm); // Velocity and deformation gradients: Grad(v) and F = I + Grad(u) const Matrix<2> vx = vel * Nwxm.transpose(); @@ -1076,20 +1061,17 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, // Define parameters - Vector fb(3); - fb[0] = dmn.prop[PhysicalPropertyType::f_x]; - fb[1] = dmn.prop[PhysicalPropertyType::f_y]; - fb[2] = dmn.prop[PhysicalPropertyType::f_z]; + const Eigen::Vector3d fb{dmn.prop[PhysicalPropertyType::f_x], + dmn.prop[PhysicalPropertyType::f_y], + dmn.prop[PhysicalPropertyType::f_z]}; double am = eq.am; double af = eq.af * eq.gam * dt; double afm = af / am; - // {i,j} := velocity dofs; {k} := pressure dof + // Velocity dofs start at i; l is the pressure dof. int i = eq.s; - int j = i + 1; - int k = j + 1; - int l = k + 1; + int l = i + 3; #ifdef debug_ustruct_3d_m dmsg << "fb: " << fb; @@ -1099,10 +1081,6 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, dmsg << "i: " << i; #endif - double ya_g_f; - double ya_g_s; - double ya_g_n; - // This element's nodal fields, as Eigen views over the caller's storage const auto Nwxm = eigen_view<3>(Nwx); // grad(N_a) per column const auto Nwm = eigen_view(Nw); // shape functions @@ -1110,17 +1088,16 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, const auto vel = eigen_view(yl).middleRows<3>(i); // nodal velocities const auto acc = eigen_view(al).middleRows<3>(i); // nodal accelerations const auto bfm = eigen_view<3>(bfl); // nodal body force - const auto fbv = eigen_view<3>(fb); // domain body force, constant over the element auto lRv = eigen_view_mut(lR).topRows<3>(); // rows this kernel adds to // Velocity, and the inertia less body force, at this Gauss point const Eigen::Vector3d v = vel * Nwm; - const Eigen::Vector3d vd = (acc - bfm) * Nwm - fbv; + const Eigen::Vector3d vd = (acc - bfm) * Nwm - fb; // Active stress activation along fiber, sheet and sheet-normal - ya_g_f = eigen_view(ya_l_f).dot(Nwm); - ya_g_s = eigen_view(ya_l_s).dot(Nwm); - ya_g_n = eigen_view(ya_l_n).dot(Nwm); + const double ya_g_f = eigen_view(ya_l_f).dot(Nwm); + const double ya_g_s = eigen_view(ya_l_s).dot(Nwm); + const double ya_g_n = eigen_view(ya_l_n).dot(Nwm); // Velocity and deformation gradients: Grad(v) and F = I + Grad(u) const Matrix<3> vx = vel * Nwxm.transpose(); From ae0043b838d98cf9f99fc73f09fc8933eb82ecf5 Mon Sep 17 00:00:00 2001 From: dseyler Date: Tue, 22 Sep 2026 11:04:03 -0700 Subject: [PATCH 32/42] aligned compute_pk2cc nsd branches for consistency --- Code/Source/solver/mat_models.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Code/Source/solver/mat_models.cpp b/Code/Source/solver/mat_models.cpp index 53de423b1..c906d3c7e 100644 --- a/Code/Source/solver/mat_models.cpp +++ b/Code/Source/solver/mat_models.cpp @@ -836,13 +836,13 @@ void compute_pk2cc(const ComMod& com_mod, const CepMod& cep_mod, const dmnType& if (nsd == 2) { // Copy deformation gradient to Eigen matrix - auto F_2D = mat_fun::convert_to_eigen_matrix(F); - + auto F_2D = mat_fun::convert_to_eigen_matrix>(F); + const auto fl_2D = eigen_view<2>(fl); // Initialize stress and elasticity tensors - Eigen::Matrix2d S_2D = Eigen::Matrix2d::Zero(); - Eigen::Matrix3d Dm_2D = Eigen::Matrix3d::Zero(); + Matrix<2> S_2D = Matrix<2>::Zero(); + Matrix<3> Dm_2D = Matrix<3>::Zero(); // Call templated function compute_pk2cc<2>(com_mod, cep_mod, lDmn, F_2D, nfd, fl_2D, ya_f, ya_s, ya_n, S_2D, Dm_2D, Ja); @@ -853,14 +853,13 @@ void compute_pk2cc(const ComMod& com_mod, const CepMod& cep_mod, const dmnType& } else if (nsd == 3) { // Copy deformation gradient to Eigen matrix - auto F_3D = mat_fun::convert_to_eigen_matrix(F); + auto F_3D = mat_fun::convert_to_eigen_matrix>(F); const auto fl_3D = eigen_view<3>(fl); // Initialize stress and elasticity tensors - Eigen::Matrix3d S_3D = Eigen::Matrix3d::Zero(); - Eigen::Matrix Dm_3D; - Dm_3D.setZero(); + Matrix<3> S_3D = Matrix<3>::Zero(); + Matrix<6> Dm_3D = Matrix<6>::Zero(); // Call templated function compute_pk2cc<3>(com_mod, cep_mod, lDmn, F_3D, nfd, fl_3D, ya_f, ya_s, ya_n, S_3D, Dm_3D, Ja); From a061129d310c5404d3732bb6adcc46ee05b5d93a Mon Sep 17 00:00:00 2001 From: dseyler Date: Tue, 22 Sep 2026 13:24:01 -0700 Subject: [PATCH 33/42] Added comments to dyadic_product, eigen_view, and Kvis buffers --- Code/Source/solver/mat_fun.h | 17 ++++++++--------- Code/Source/solver/sv_struct.cpp | 18 +++--------------- Code/Source/solver/ustruct.cpp | 2 ++ 3 files changed, 13 insertions(+), 24 deletions(-) diff --git a/Code/Source/solver/mat_fun.h b/Code/Source/solver/mat_fun.h index 2234dfc3d..203f322aa 100644 --- a/Code/Source/solver/mat_fun.h +++ b/Code/Source/solver/mat_fun.h @@ -38,10 +38,13 @@ namespace mat_fun { /// is bounded by the largest element the solver supports. using NodalVector = Eigen::Matrix; + // The eigen_view overloads below wrap an Array or Vector in an Eigen::Map that + // shares its storage, so the container must outlive the view. The templated + // forms fix one dimension at compile time and check it at run time. The + // untemplated forms take both dimensions from the container. + /// @brief Read-only Eigen view of an Array, sharing its storage. /// - /// The Array must outlive the view. - /// /// @tparam rows Row count, fixed at compile time; the columns are taken from the Array. template Eigen::Map> @@ -58,7 +61,7 @@ namespace mat_fun { /// /// Both dimensions come from the Array, so a row block of a larger array is /// reached with e.g. eigen_view(dl).middleRows(i), letting Eigen derive - /// the stride. The Array must outlive the view. + /// the stride. inline Eigen::Map eigen_view(const Array& A) { return {A.data(), A.nrows(), A.ncols()}; @@ -66,16 +69,13 @@ namespace mat_fun { /// @brief Writable Eigen view of a whole Array, sharing its storage. /// - /// Lets a result be accumulated with a single Eigen expression. The Array - /// must outlive the view. + /// Lets a result be accumulated with a single Eigen expression. inline Eigen::Map eigen_view_mut(Array& A) { return {A.data(), A.nrows(), A.ncols()}; } /// @brief Read-only Eigen view of a whole Vector, sharing its storage. - /// - /// The Vector must outlive the view. inline Eigen::Map eigen_view(const Vector& v) { return {v.data(), v.size()}; @@ -83,8 +83,6 @@ namespace mat_fun { /// @brief Read-only Eigen view of a Vector, sharing its storage. /// - /// The Vector must outlive the view. - /// /// @tparam rows Entry count, fixed at compile time. template Eigen::Map> @@ -328,6 +326,7 @@ namespace mat_fun { Tensor C; constexpr int N = nsd * nsd; + // Column-major storage flattens index pairs: c(ij,kl) = a(ij) * b(kl). Eigen::Map> a(A.data()); Eigen::Map> b(B.data()); Eigen::Map> c(C.data()); diff --git a/Code/Source/solver/sv_struct.cpp b/Code/Source/solver/sv_struct.cpp index e6e0e5a93..ef74e6642 100644 --- a/Code/Source/solver/sv_struct.cpp +++ b/Code/Source/solver/sv_struct.cpp @@ -451,6 +451,7 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, // Viscous 2nd Piola-Kirchhoff stress and tangent contributions static Matrix<2> Svis; + // Kvis_u and Kvis_v only need to be sized once per element. static Array3 Kvis_u, Kvis_v; if (Kvis_u.ncols() != eNoN) { Kvis_u.resize(4, eNoN, eNoN); @@ -520,22 +521,18 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, // dM1/du1 BmDBm = Bm[a].col(0).dot(DBm.col(0)); - lK(0,a,b) += w*( T1 + afu*(BmDBm + Kvis_u(0,a,b)) + afv*Kvis_v(0,a,b) ); // dM1/du2 BmDBm = Bm[a].col(0).dot(DBm.col(1)); - lK(1,a,b) += w*( afu*(BmDBm + Kvis_u(1,a,b)) + afv*Kvis_v(1,a,b) ); // dM2/du1 BmDBm = Bm[a].col(1).dot(DBm.col(0)); - lK(dof+0,a,b) += w*( afu*(BmDBm + Kvis_u(2,a,b)) + afv*Kvis_v(2,a,b) ); // dM2/du2 BmDBm = Bm[a].col(1).dot(DBm.col(1)); - lK(dof+1,a,b) += w*( T1 + afu*(BmDBm + Kvis_u(3,a,b)) + afv*Kvis_v(3,a,b) ); } } @@ -640,6 +637,7 @@ void struct_3d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, // Viscous 2nd Piola-Kirchhoff stress and tangent contributions static Matrix<3> Svis; + // Kvis_u and Kvis_v only need to be sized once per element. static Array3 Kvis_u, Kvis_v; if (Kvis_u.ncols() != eNoN) { Kvis_u.resize(9, eNoN, eNoN); @@ -714,52 +712,42 @@ void struct_3d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, for (int a = 0; a < eNoN; a++) { NxSNx = Nxm.col(a).dot(SNx); - T1 = amd*N(a)*N(b) + afu*NxSNx; // dM1/du1 BmDBm = Bm[a].col(0).dot(DBm.col(0)); - lK(0,a,b) += w*( T1 + afu*(BmDBm + Kvis_u(0,a,b)) + afv*Kvis_v(0,a,b) ); // dM1/du2 BmDBm = Bm[a].col(0).dot(DBm.col(1)); - lK(1,a,b) += w*( afu*(BmDBm + Kvis_u(1,a,b)) + afv*Kvis_v(1,a,b) ); // dM1/du3 BmDBm = Bm[a].col(0).dot(DBm.col(2)); - lK(2,a,b) += w*( afu*(BmDBm + Kvis_u(2,a,b)) + afv*Kvis_v(2,a,b) ); // dM2/du1 BmDBm = Bm[a].col(1).dot(DBm.col(0)); - lK(dof+0,a,b) += w*( afu*(BmDBm + Kvis_u(3,a,b)) + afv*Kvis_v(3,a,b) ); // dM2/du2 BmDBm = Bm[a].col(1).dot(DBm.col(1)); - lK(dof+1,a,b) += w*(T1 + afu*(BmDBm + Kvis_u(4,a,b)) + afv*Kvis_v(4,a,b) ); // dM2/du3 BmDBm = Bm[a].col(1).dot(DBm.col(2)); - lK(dof+2,a,b) += w*( afu*(BmDBm + Kvis_u(5,a,b)) + afv*Kvis_v(5,a,b) ); // dM3/du1 BmDBm = Bm[a].col(2).dot(DBm.col(0)); - lK(2*dof+0,a,b) += w*( afu*(BmDBm + Kvis_u(6,a,b)) + afv*Kvis_v(6,a,b) ); // dM3/du2 BmDBm = Bm[a].col(2).dot(DBm.col(1)); - - lK(2*dof+1,a,b) += w*( afu*(BmDBm + Kvis_u(7,a,b)) + afv*Kvis_v(7,a,b) ); + lK(2*dof+1,a,b) += w*( afu*(BmDBm + Kvis_u(7,a,b)) + afv*Kvis_v(7,a,b) ); // dM3/du3 BmDBm = Bm[a].col(2).dot(DBm.col(2)); - lK(2*dof+2,a,b) += w*( T1 + afu*(BmDBm + Kvis_u(8,a,b)) + afv*Kvis_v(8,a,b) ); } } diff --git a/Code/Source/solver/ustruct.cpp b/Code/Source/solver/ustruct.cpp index 475a7933e..333cc2701 100644 --- a/Code/Source/solver/ustruct.cpp +++ b/Code/Source/solver/ustruct.cpp @@ -869,6 +869,7 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, // Viscous 2nd Piola-Kirchhoff stress and tangent contributions static Matrix<2> Svis; + // Kvis_u and Kvis_v only need to be sized once per element. static Array3 Kvis_u, Kvis_v; if (Kvis_u.ncols() != eNoNw) { Kvis_u.resize(4, eNoNw, eNoNw); @@ -1127,6 +1128,7 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, // Viscous 2nd Piola-Kirchhoff stress and tangent contributions static Matrix<3> Svis; + // Kvis_u and Kvis_v only need to be sized once per element. static Array3 Kvis_u, Kvis_v; if (Kvis_u.ncols() != eNoNw) { Kvis_u.resize(9, eNoNw, eNoNw); From 793c716e0ffefcb5f3ec268473eaacd8936c3689 Mon Sep 17 00:00:00 2001 From: dseyler Date: Tue, 22 Sep 2026 14:17:54 -0700 Subject: [PATCH 34/42] Removed dead locals and moved declarations closer to use --- Code/Source/solver/sv_struct.cpp | 24 +++++++++--------------- Code/Source/solver/ustruct.cpp | 8 ++------ 2 files changed, 11 insertions(+), 21 deletions(-) diff --git a/Code/Source/solver/sv_struct.cpp b/Code/Source/solver/sv_struct.cpp index ef74e6642..1562e822b 100644 --- a/Code/Source/solver/sv_struct.cpp +++ b/Code/Source/solver/sv_struct.cpp @@ -477,11 +477,7 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, // 1st Piola-Kirchhoff tensor (P) // - Matrix<2> P; - Eigen::Matrix DBm; - - std::array, consts::maxNoN> Bm; - P.noalias() = F * S; + const Matrix<2> P = F * S; #ifdef debug_struct_2d dmsg << "P: " << P(0,0) << " " << P(0,1); dmsg << " " << P(1,0) << " " << P(1,1); @@ -492,6 +488,7 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, // Strain-displacement matrix; Bm[a] maps node a displacement to Voigt strain // + std::array, consts::maxNoN> Bm; const Matrix<2> Ft = F.transpose(); for (int a = 0; a < eNoN; a++) { @@ -503,12 +500,12 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, } // Local stiffness tensor - double T1, NxNx, NxSNx, BmDBm; + double T1, NxSNx, BmDBm; - for (int b = 0; b < eNoN; b++) { + for (int b = 0; b < eNoN; b++) { // Material stiffness (D*B) for node b - DBm.noalias() = Dm * Bm[b]; + const Eigen::Matrix DBm = Dm * Bm[b]; // Geometric stiffness: S*grad(N_b) const Eigen::Vector2d SNx = S * Nxm.col(b); @@ -674,15 +671,14 @@ void struct_3d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, // 1st Piola-Kirchhoff tensor (P) // - Matrix<3> P; - std::array, consts::maxNoN> Bm; - P.noalias() = F * S; + const Matrix<3> P = F * S; // Local residual: inertia and body force, plus the divergence of P lRv += w * (ud * Nm.transpose() + P * Nxm); // Strain-displacement matrix; Bm[a] maps node a displacement to Voigt strain // + std::array, consts::maxNoN> Bm; const Matrix<3> Ft = F.transpose(); for (int a = 0; a < eNoN; a++) { @@ -697,14 +693,12 @@ void struct_3d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, } // Local stiffness tensor - double NxSNx, T1, NxNx, BmDBm, Tv; - - Eigen::Matrix DBm; + double NxSNx, T1, BmDBm; for (int b = 0; b < eNoN; b++) { // Material stiffness (D*B) for node b - DBm.noalias() = Dm * Bm[b]; + const Eigen::Matrix DBm = Dm * Bm[b]; // Geometric stiffness: S*grad(N_b) const Eigen::Vector3d SNx = S * Nxm.col(b); diff --git a/Code/Source/solver/ustruct.cpp b/Code/Source/solver/ustruct.cpp index 333cc2701..df26f0bd0 100644 --- a/Code/Source/solver/ustruct.cpp +++ b/Code/Source/solver/ustruct.cpp @@ -944,11 +944,9 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, T1{0.0}, T2{0.0}, T3{0.0}, Tv{0.0}, Ku{0.0}; - Eigen::Matrix DBm; - for (int b = 0; b < eNoNw; b++) { - DBm.noalias() = Dm * Bm[b]; + const Eigen::Matrix DBm = Dm * Bm[b]; // Geometric stiffness: Siso*grad(N_b) const Eigen::Vector2d SisoNx = Siso * Nwxm.col(b); @@ -1204,11 +1202,9 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, double NxSNx{0.0}, BtDB{0.0}, T1{0.0}, T2{0.0}, T3{0.0}; double Tv{0.0}, Ku{0.0}; - Eigen::Matrix DBm; - for (int b = 0; b < eNoNw; b++) { - DBm.noalias() = Dm * Bm[b]; + const Eigen::Matrix DBm = Dm * Bm[b]; // Geometric stiffness: Siso*grad(N_b) const Eigen::Vector3d SisoNx = Siso * Nwxm.col(b); From 28091dafe5392841ce9d596dbf6df58d5bfb7aa2 Mon Sep 17 00:00:00 2001 From: dseyler Date: Tue, 22 Sep 2026 15:58:14 -0700 Subject: [PATCH 35/42] Organized prestress matrix to show voigt symmetry --- Code/Source/solver/sv_struct.cpp | 36 ++++++++++---------------------- 1 file changed, 11 insertions(+), 25 deletions(-) diff --git a/Code/Source/solver/sv_struct.cpp b/Code/Source/solver/sv_struct.cpp index 1562e822b..9566c94de 100644 --- a/Code/Source/solver/sv_struct.cpp +++ b/Code/Source/solver/sv_struct.cpp @@ -418,17 +418,12 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, const double ya_g_s = eigen_view(ya_l_s).dot(Nm); const double ya_g_n = eigen_view(ya_l_n).dot(Nm); - // Prestress at this Gauss point: interpolate pS0l, held in Voigt - // order [11, 22, 12], into the three independent components of S0. - Matrix<2> S0 = Matrix<2>::Zero(); + // Prestress at this Gauss point, in Voigt order [11, 22, 12] + const Eigen::Vector pS0g = eigen_view<3>(pS0l) * Nm; - for (int a = 0; a < eNoN; a++) { - S0(0,0) += N(a)*pS0l(0,a); - S0(1,1) += N(a)*pS0l(1,a); - S0(0,1) += N(a)*pS0l(2,a); - } - - S0(1,0) = S0(0,1); + Matrix<2> S0; + S0 << pS0g(0), pS0g(2), + pS0g(2), pS0g(1); #ifdef debug_struct_2d dmsg << "ud: " << ud(0) << " " << ud(1); @@ -602,22 +597,13 @@ void struct_3d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, const double ya_g_s = eigen_view(ya_l_s).dot(Nm); const double ya_g_n = eigen_view(ya_l_n).dot(Nm); - // Prestress at this Gauss point: interpolate pS0l, held in Voigt - // order [11, 22, 33, 12, 23, 31], into the six independent components of S0. - Matrix<3> S0 = Matrix<3>::Zero(); - - for (int a = 0; a < eNoN; a++) { - S0(0,0) += N(a)*pS0l(0,a); - S0(1,1) += N(a)*pS0l(1,a); - S0(2,2) += N(a)*pS0l(2,a); - S0(0,1) += N(a)*pS0l(3,a); - S0(1,2) += N(a)*pS0l(4,a); - S0(2,0) += N(a)*pS0l(5,a); - } + // Prestress at this Gauss point, in Voigt order [11, 22, 33, 12, 23, 31] + const Eigen::Vector pS0g = eigen_view<6>(pS0l) * Nm; - S0(1,0) = S0(0,1); - S0(2,1) = S0(1,2); - S0(0,2) = S0(2,0); + Matrix<3> S0; + S0 << pS0g(0), pS0g(3), pS0g(5), + pS0g(3), pS0g(1), pS0g(4), + pS0g(5), pS0g(4), pS0g(2); // Velocity and deformation gradients: Grad(v) and F = I + Grad(u) const Matrix<3> vx = vel * Nxm.transpose(); From 424ea148735a6da5ee464633a5e520ba438a7c0a Mon Sep 17 00:00:00 2001 From: dseyler Date: Tue, 22 Sep 2026 16:00:57 -0700 Subject: [PATCH 36/42] Refactored viscosity to simplify call site and hide Kvis_u, Kvis_v resizing --- Code/Source/solver/mat_models.cpp | 46 ++++++---------- Code/Source/solver/mat_models.h | 47 +++++++++++----- Code/Source/solver/sv_struct.cpp | 64 +++++++++------------- Code/Source/solver/ustruct.cpp | 89 +++++++++++++------------------ 4 files changed, 114 insertions(+), 132 deletions(-) diff --git a/Code/Source/solver/mat_models.cpp b/Code/Source/solver/mat_models.cpp index c906d3c7e..bfb33958d 100644 --- a/Code/Source/solver/mat_models.cpp +++ b/Code/Source/solver/mat_models.cpp @@ -1689,50 +1689,38 @@ void compute_visc_stress_newtonian(const double mu, const int eNoN, const Array< } // namespace -/** - * @brief Get the solid viscous PK2 stress and corresponding tangent matrix contributions - * Calls the appropriate function based on the viscosity type, either viscous - * pseudo-potential or Newtonian viscosity model. - * - * @param[in] lDmn Domain object - * @param[in] eNoN Number of nodes in an element - * @param[in] Nx Shape function gradient w.r.t. reference configuration coordinates (dN/dX) - * @param[in] vx Velocity gradient matrix w.r.t reference configuration coordinates (dv/dX) - * @param[in] F Deformation gradient matrix - * @param[out] Svis Viscous 2nd Piola-Kirchhoff stress matrix - * @param[out] Kvis_u Viscous tangent matrix contribution due to displacement - * @param[out] Kvis_v Viscous tangent matrix contribution due to velocity - */ +/// @brief Dispatches to the viscous pseudo-potential or Newtonian model, or +/// zeroes the contributions when the domain has no viscosity model. template -void compute_visc_stress_and_tangent(const dmnType& lDmn, const int eNoN, - const Array& Nx, const Matrix& vx, const Matrix& F, - Matrix& Svis, Array3& Kvis_u, Array3& Kvis_v) { +void ViscousResponse::update(const dmnType& lDmn, const int eNoN, + const Array& Nx, const Matrix& vx, const Matrix& F) { + + // The buffers only need resizing when the element node count changes. + if (Kvis_u_.ncols() != eNoN) { + Kvis_u_.resize(nsd*nsd, eNoN, eNoN); + Kvis_v_.resize(nsd*nsd, eNoN, eNoN); + } switch (lDmn.solid_visc.viscType) { case consts::SolidViscosityModelType::viscType_Newtonian: - compute_visc_stress_newtonian(lDmn.solid_visc.mu, eNoN, Nx, vx, F, Svis, Kvis_u, Kvis_v); + compute_visc_stress_newtonian(lDmn.solid_visc.mu, eNoN, Nx, vx, F, Svis_, Kvis_u_, Kvis_v_); break; case consts::SolidViscosityModelType::viscType_Potential: - compute_visc_stress_potential(lDmn.solid_visc.mu, eNoN, Nx, vx, F, Svis, Kvis_u, Kvis_v); + compute_visc_stress_potential(lDmn.solid_visc.mu, eNoN, Nx, vx, F, Svis_, Kvis_u_, Kvis_v_); break; default: // No viscosity model for this domain. - Svis.setZero(); - Kvis_u = 0.0; - Kvis_v = 0.0; + Svis_.setZero(); + Kvis_u_ = 0.0; + Kvis_v_ = 0.0; break; } } // Instantiate the dimensions the solver supports. -template void compute_visc_stress_and_tangent<2>(const dmnType&, const int, - const Array&, const Matrix<2>&, const Matrix<2>&, - Matrix<2>&, Array3&, Array3&); - -template void compute_visc_stress_and_tangent<3>(const dmnType&, const int, - const Array&, const Matrix<3>&, const Matrix<3>&, - Matrix<3>&, Array3&, Array3&); +template class ViscousResponse<2>; +template class ViscousResponse<3>; }; diff --git a/Code/Source/solver/mat_models.h b/Code/Source/solver/mat_models.h index 27fbc1d0d..ccb7efe3f 100644 --- a/Code/Source/solver/mat_models.h +++ b/Code/Source/solver/mat_models.h @@ -85,22 +85,43 @@ void g_vol_pen(const ComMod& com_mod, const dmnType& lDmn, const double p, double& ro, double& bt, double& dro, double& dbt, const double Ja); -/// @brief Computes viscous PK2 stress and tangent -/// for the viscosity model configured for the domain. +/// @brief Viscous 2nd Piola-Kirchhoff stress and tangent contributions at a +/// Gauss point, for the viscosity model configured for the domain. /// -/// @param[in] lDmn Domain, supplying the viscosity model and its parameters. -/// @param[in] eNoN Number of element nodes. -/// @param[in] Nx Shape function spatial derivatives. -/// @param[in] vx Velocity gradient. -/// @param[in] F Deformation gradient. -/// @param[out] Svis Viscous 2nd Piola-Kirchhoff stress. -/// @param[out] Kvis_u,Kvis_v Tangent contributions w.r.t. displacement and velocity. +/// Owns the buffers it computes into, so a kernel can hold one instance across +/// an element's Gauss points and skip the calls it does not need. /// -/// @tparam nsd Number of spatial dimensions, deduced from F. +/// @tparam nsd Number of spatial dimensions. +/// +/// Defined in mat_models.cpp and explicitly instantiated there for nsd = 2 and +/// nsd = 3, the only dimensions the solver supports. template -void compute_visc_stress_and_tangent(const dmnType& lDmn, const int eNoN, - const Array& Nx, const Matrix& vx, const Matrix& F, - Matrix& Svis, Array3& Kvis_u, Array3& Kvis_v); +class ViscousResponse { + public: + /// @brief Evaluate the domain's viscosity model at this Gauss point. + /// + /// @param[in] lDmn Domain, supplying the viscosity model and its parameters. + /// @param[in] eNoN Number of element nodes. + /// @param[in] Nx Shape function spatial derivatives. + /// @param[in] vx Velocity gradient. + /// @param[in] F Deformation gradient. + void update(const dmnType& lDmn, const int eNoN, const Array& Nx, + const Matrix& vx, const Matrix& F); + + /// @brief Viscous 2nd Piola-Kirchhoff stress. + const Matrix& S() const { return Svis_; } + + /// @brief Tangent w.r.t. displacement. du(i*nsd + j, a, b) is the (i,j) + /// entry of the block coupling nodes a and b. + double du(const int ij, const int a, const int b) const { return Kvis_u_(ij, a, b); } + + /// @brief Tangent w.r.t. velocity, indexed as du(). + double dv(const int ij, const int a, const int b) const { return Kvis_v_(ij, a, b); } + + private: + Matrix Svis_; + Array3 Kvis_u_, Kvis_v_; +}; }; #endif diff --git a/Code/Source/solver/sv_struct.cpp b/Code/Source/solver/sv_struct.cpp index 9566c94de..2471f38af 100644 --- a/Code/Source/solver/sv_struct.cpp +++ b/Code/Source/solver/sv_struct.cpp @@ -444,23 +444,16 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, mat_models::compute_pk2cc(com_mod, cep_mod, dmn, F, nFn, eigen_view<2>(fN), ya_g_f, ya_g_s, ya_g_n, S, Dm, Ja); - // Viscous 2nd Piola-Kirchhoff stress and tangent contributions - static Matrix<2> Svis; - // Kvis_u and Kvis_v only need to be sized once per element. - static Array3 Kvis_u, Kvis_v; - if (Kvis_u.ncols() != eNoN) { - Kvis_u.resize(4, eNoN, eNoN); - Kvis_v.resize(4, eNoN, eNoN); - } - - // Reuse the previous Gauss point's viscous contributions when shape function - // gradients are constant within an element (e.g. linear triangles, tetrahedra). + // Viscous 2nd Piola-Kirchhoff stress and tangent contributions. Reuse the + // previous Gauss point's when shape function gradients are constant within an + // element (e.g. linear triangles, tetrahedra). + static mat_models::ViscousResponse<2> visc; if (recompute_visc) { - mat_models::compute_visc_stress_and_tangent(dmn, eNoN, Nx, vx, F, Svis, Kvis_u, Kvis_v); + visc.update(dmn, eNoN, Nx, vx, F); } // Elastic + Viscous stresses - S = S + Svis; + S = S + visc.S(); // Prestress pSl(0) = S(0,0); @@ -513,19 +506,19 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, // dM1/du1 BmDBm = Bm[a].col(0).dot(DBm.col(0)); - lK(0,a,b) += w*( T1 + afu*(BmDBm + Kvis_u(0,a,b)) + afv*Kvis_v(0,a,b) ); + lK(0,a,b) += w*( T1 + afu*(BmDBm + visc.du(0,a,b)) + afv*visc.dv(0,a,b) ); // dM1/du2 BmDBm = Bm[a].col(0).dot(DBm.col(1)); - lK(1,a,b) += w*( afu*(BmDBm + Kvis_u(1,a,b)) + afv*Kvis_v(1,a,b) ); + lK(1,a,b) += w*( afu*(BmDBm + visc.du(1,a,b)) + afv*visc.dv(1,a,b) ); // dM2/du1 BmDBm = Bm[a].col(1).dot(DBm.col(0)); - lK(dof+0,a,b) += w*( afu*(BmDBm + Kvis_u(2,a,b)) + afv*Kvis_v(2,a,b) ); + lK(dof+0,a,b) += w*( afu*(BmDBm + visc.du(2,a,b)) + afv*visc.dv(2,a,b) ); // dM2/du2 BmDBm = Bm[a].col(1).dot(DBm.col(1)); - lK(dof+1,a,b) += w*( T1 + afu*(BmDBm + Kvis_u(3,a,b)) + afv*Kvis_v(3,a,b) ); + lK(dof+1,a,b) += w*( T1 + afu*(BmDBm + visc.du(3,a,b)) + afv*visc.dv(3,a,b) ); } } } @@ -618,23 +611,16 @@ void struct_3d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, mat_models::compute_pk2cc(com_mod, cep_mod, dmn, F, nFn, eigen_view<3>(fN), ya_g_f, ya_g_s, ya_g_n, S, Dm, Ja); - // Viscous 2nd Piola-Kirchhoff stress and tangent contributions - static Matrix<3> Svis; - // Kvis_u and Kvis_v only need to be sized once per element. - static Array3 Kvis_u, Kvis_v; - if (Kvis_u.ncols() != eNoN) { - Kvis_u.resize(9, eNoN, eNoN); - Kvis_v.resize(9, eNoN, eNoN); - } - - // Reuse the previous Gauss point's viscous contributions when shape function - // gradients are constant within an element (e.g. linear triangles, tetrahedra). + // Viscous 2nd Piola-Kirchhoff stress and tangent contributions. Reuse the + // previous Gauss point's when shape function gradients are constant within an + // element (e.g. linear triangles, tetrahedra). + static mat_models::ViscousResponse<3> visc; if (recompute_visc) { - mat_models::compute_visc_stress_and_tangent(dmn, eNoN, Nx, vx, F, Svis, Kvis_u, Kvis_v); + visc.update(dmn, eNoN, Nx, vx, F); } // Elastic + Viscous stresses - S = S + Svis; + S = S + visc.S(); #ifdef debug_struct_3d dmsg << "Jac: " << Jac; @@ -696,39 +682,39 @@ void struct_3d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, // dM1/du1 BmDBm = Bm[a].col(0).dot(DBm.col(0)); - lK(0,a,b) += w*( T1 + afu*(BmDBm + Kvis_u(0,a,b)) + afv*Kvis_v(0,a,b) ); + lK(0,a,b) += w*( T1 + afu*(BmDBm + visc.du(0,a,b)) + afv*visc.dv(0,a,b) ); // dM1/du2 BmDBm = Bm[a].col(0).dot(DBm.col(1)); - lK(1,a,b) += w*( afu*(BmDBm + Kvis_u(1,a,b)) + afv*Kvis_v(1,a,b) ); + lK(1,a,b) += w*( afu*(BmDBm + visc.du(1,a,b)) + afv*visc.dv(1,a,b) ); // dM1/du3 BmDBm = Bm[a].col(0).dot(DBm.col(2)); - lK(2,a,b) += w*( afu*(BmDBm + Kvis_u(2,a,b)) + afv*Kvis_v(2,a,b) ); + lK(2,a,b) += w*( afu*(BmDBm + visc.du(2,a,b)) + afv*visc.dv(2,a,b) ); // dM2/du1 BmDBm = Bm[a].col(1).dot(DBm.col(0)); - lK(dof+0,a,b) += w*( afu*(BmDBm + Kvis_u(3,a,b)) + afv*Kvis_v(3,a,b) ); + lK(dof+0,a,b) += w*( afu*(BmDBm + visc.du(3,a,b)) + afv*visc.dv(3,a,b) ); // dM2/du2 BmDBm = Bm[a].col(1).dot(DBm.col(1)); - lK(dof+1,a,b) += w*(T1 + afu*(BmDBm + Kvis_u(4,a,b)) + afv*Kvis_v(4,a,b) ); + lK(dof+1,a,b) += w*(T1 + afu*(BmDBm + visc.du(4,a,b)) + afv*visc.dv(4,a,b) ); // dM2/du3 BmDBm = Bm[a].col(1).dot(DBm.col(2)); - lK(dof+2,a,b) += w*( afu*(BmDBm + Kvis_u(5,a,b)) + afv*Kvis_v(5,a,b) ); + lK(dof+2,a,b) += w*( afu*(BmDBm + visc.du(5,a,b)) + afv*visc.dv(5,a,b) ); // dM3/du1 BmDBm = Bm[a].col(2).dot(DBm.col(0)); - lK(2*dof+0,a,b) += w*( afu*(BmDBm + Kvis_u(6,a,b)) + afv*Kvis_v(6,a,b) ); + lK(2*dof+0,a,b) += w*( afu*(BmDBm + visc.du(6,a,b)) + afv*visc.dv(6,a,b) ); // dM3/du2 BmDBm = Bm[a].col(2).dot(DBm.col(1)); - lK(2*dof+1,a,b) += w*( afu*(BmDBm + Kvis_u(7,a,b)) + afv*Kvis_v(7,a,b) ); + lK(2*dof+1,a,b) += w*( afu*(BmDBm + visc.du(7,a,b)) + afv*visc.dv(7,a,b) ); // dM3/du3 BmDBm = Bm[a].col(2).dot(DBm.col(2)); - lK(2*dof+2,a,b) += w*( T1 + afu*(BmDBm + Kvis_u(8,a,b)) + afv*Kvis_v(8,a,b) ); + lK(2*dof+2,a,b) += w*( T1 + afu*(BmDBm + visc.du(8,a,b)) + afv*visc.dv(8,a,b) ); } } } diff --git a/Code/Source/solver/ustruct.cpp b/Code/Source/solver/ustruct.cpp index df26f0bd0..af01c743c 100644 --- a/Code/Source/solver/ustruct.cpp +++ b/Code/Source/solver/ustruct.cpp @@ -867,19 +867,12 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, mat_models::compute_pk2cc(com_mod, cep_mod, eq.dmn[cDmn], F, nFn, eigen_view<2>(fN), ya_g_f, ya_g_s, ya_g_n, Siso, Dm, Ja); - // Viscous 2nd Piola-Kirchhoff stress and tangent contributions - static Matrix<2> Svis; - // Kvis_u and Kvis_v only need to be sized once per element. - static Array3 Kvis_u, Kvis_v; - if (Kvis_u.ncols() != eNoNw) { - Kvis_u.resize(4, eNoNw, eNoNw); - Kvis_v.resize(4, eNoNw, eNoNw); - } - - // Reuse the previous Gauss point's viscous contributions when shape function - // gradients are constant within an element (e.g. linear triangles and tetrahedra). + // Viscous 2nd Piola-Kirchhoff stress and tangent contributions. Reuse the + // previous Gauss point's when shape function gradients are constant within an + // element (e.g. linear triangles and tetrahedra). + static mat_models::ViscousResponse<2> visc; if (recompute_visc) { - mat_models::compute_visc_stress_and_tangent(dmn, eNoNw, Nwx, vx, F, Svis, Kvis_u, Kvis_v); + visc.update(dmn, eNoNw, Nwx, vx, F); } // Compute rho and beta depending on the volumetric penalty model @@ -902,7 +895,7 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, } // Total isochoric 2nd Piola-Kirchhoff stress (Elastic + Viscous) - Siso += Svis; + Siso += visc.S(); // Deviatoric 1st Piola-Kirchhoff tensor (P) // @@ -960,12 +953,12 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, T1 = Jac*rho*vd(0)*Nw(a)*NxFi(0,b); T2 = -tauC*Jac*NxFi(0,a)*VxNx(0,b); - Ku = w*af*(T1 + T2 + BtDB + NxSNx + Kvis_u(0,a,b)); + Ku = w*af*(T1 + T2 + BtDB + NxSNx + visc.du(0,a,b)); lKd(0,a,b) += Ku; T1 = am*Jac*rho*Nw(a)*Nw(b); T2 = T1 + af*Jac*tauC*rho*NxFi(0,a)*NxFi(0,b); - Tv = af*Kvis_v(0,a,b); + Tv = af*visc.dv(0,a,b); lK(0,a,b) += w*(T2 + Tv) + afm*Ku; // dM_1/dV_2 + af/am *dM_1/dU_2 @@ -975,11 +968,11 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, T2 = -tauC*Jac*NxFi(0,a)*VxNx(1,b); T3 = Jac*rCl*(NxFi(0,a)*NxFi(1,b) - NxFi(1,a)*NxFi(0,b)); - Ku = w*af*(T1 + T2 + T3 + BtDB + Kvis_u(1,a,b)); + Ku = w*af*(T1 + T2 + T3 + BtDB + visc.du(1,a,b)); lKd(1,a,b) += Ku; T2 = af*Jac*tauC*rho*NxFi(0,a)*NxFi(1,b); - Tv = af*Kvis_v(1,a,b); + Tv = af*visc.dv(1,a,b); lK(1,a,b) += w*(T2 + Tv) + afm*Ku; // dM_2/dV_1 + af/am *dM_2/dU_1 @@ -989,11 +982,11 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, T2 = -tauC*Jac*NxFi(1,a)*VxNx(0,b); T3 = Jac*rCl*(NxFi(1,a)*NxFi(0,b) - NxFi(0,a)*NxFi(1,b)); - Ku = w*af*(T1 + T2 + T3 + BtDB + Kvis_u(2,a,b)); + Ku = w*af*(T1 + T2 + T3 + BtDB + visc.du(2,a,b)); lKd(2,a,b) += Ku; T2 = af*Jac*tauC*rho*NxFi(1,a)*NxFi(0,b); - Tv = af*Kvis_v(2,a,b); + Tv = af*visc.dv(2,a,b); lK(3,a,b) += w*(T2 + Tv) + afm*Ku; // dM_2/dV_2 + af/am *dM_2/dU_2 @@ -1002,12 +995,12 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, T1 = Jac*rho*vd(1)*Nw(a)*NxFi(1,b); T2 = -tauC*Jac*NxFi(1,a)*VxNx(1,b); - Ku = w*af*(T1 + T2 + BtDB + NxSNx + Kvis_u(3,a,b)); + Ku = w*af*(T1 + T2 + BtDB + NxSNx + visc.du(3,a,b)); lKd(3,a,b) += Ku; T1 = am*Jac*rho*Nw(a)*Nw(b); T2 = T1 + af*Jac*tauC*rho*NxFi(1,a)*NxFi(1,b); - Tv = af*Kvis_v(3,a,b); + Tv = af*visc.dv(3,a,b); lK(4,a,b) += w*(T2 + Tv) + afm*Ku; } } @@ -1124,18 +1117,12 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, mat_models::compute_pk2cc(com_mod, cep_mod, eq.dmn[cDmn], F, nFn, eigen_view<3>(fN), ya_g_f, ya_g_s, ya_g_n, Siso, Dm, Ja); - // Viscous 2nd Piola-Kirchhoff stress and tangent contributions - static Matrix<3> Svis; - // Kvis_u and Kvis_v only need to be sized once per element. - static Array3 Kvis_u, Kvis_v; - if (Kvis_u.ncols() != eNoNw) { - Kvis_u.resize(9, eNoNw, eNoNw); - Kvis_v.resize(9, eNoNw, eNoNw); - } - // Reuse the previous Gauss point's viscous contributions when shape function - // gradients are constant within an element (e.g. linear triangles and tetrahedra). + // Viscous 2nd Piola-Kirchhoff stress and tangent contributions. Reuse the + // previous Gauss point's when shape function gradients are constant within an + // element (e.g. linear triangles and tetrahedra). + static mat_models::ViscousResponse<3> visc; if (recompute_visc) { - mat_models::compute_visc_stress_and_tangent(dmn, eNoNw, Nwx, vx, F, Svis, Kvis_u, Kvis_v); + visc.update(dmn, eNoNw, Nwx, vx, F); } // Compute rho and beta depending on the volumetric penalty model @@ -1158,7 +1145,7 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, } // Total isochoric 2nd Piola-Kirchhoff stress (Elastic + Viscous) - Siso += Svis; + Siso += visc.S(); // Deviatoric 1st Piola-Kirchhoff tensor (P) // @@ -1217,12 +1204,12 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, T1 = Jac*rho*vd(0)*Nw(a)*NxFi(0,b); T2 = -tauC*Jac*NxFi(0,a)*VxNx(0,b); - Ku = w*af*(T1 + T2 + BtDB + NxSNx + Kvis_u(0,a,b)); + Ku = w*af*(T1 + T2 + BtDB + NxSNx + visc.du(0,a,b)); lKd(0,a,b) += Ku; T1 = am*Jac*rho*Nw(a)*Nw(b); T2 = T1 + af*Jac*tauC*rho*NxFi(0,a)*NxFi(0,b); - Tv = af*Kvis_v(0,a,b); + Tv = af*visc.dv(0,a,b); lK(0,a,b) += w*(T2 + Tv) + afm*Ku; // dM_1/dV_2 + af/am *dM_1/dU_2 @@ -1231,11 +1218,11 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, T2 = -tauC*Jac*NxFi(0,a)*VxNx(1,b); T3 = Jac*rCl*(NxFi(0,a)*NxFi(1,b) - NxFi(1,a)*NxFi(0,b)); - Ku = w*af*(T1 + T2 + T3 + BtDB + Kvis_u(1,a,b)); + Ku = w*af*(T1 + T2 + T3 + BtDB + visc.du(1,a,b)); lKd(1,a,b) += Ku; T2 = af*Jac*tauC*rho*NxFi(0,a)*NxFi(1,b); - Tv = af*Kvis_v(1,a,b); + Tv = af*visc.dv(1,a,b); lK(1,a,b) += w*(T2 + Tv) + afm*Ku; // dM_1/dV_3 + af/am *dM_1/dU_3 @@ -1245,11 +1232,11 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, T2 = -tauC*Jac*NxFi(0,a)*VxNx(2,b); T3 = Jac*rCl*(NxFi(0,a)*NxFi(2,b) - NxFi(2,a)*NxFi(0,b)); - Ku = w*af*(T1 + T2 + T3 + BtDB + Kvis_u(2,a,b)); + Ku = w*af*(T1 + T2 + T3 + BtDB + visc.du(2,a,b)); lKd(2,a,b) += Ku; T2 = af*Jac*tauC*rho*NxFi(0,a)*NxFi(2,b); - Tv = af*Kvis_v(2,a,b); + Tv = af*visc.dv(2,a,b); lK(2,a,b) += w*(T2 + Tv) + afm*Ku; // dM_2/dV_1 + af/am *dM_2/dU_1 @@ -1260,11 +1247,11 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, T2 = -tauC*Jac*NxFi(1,a)*VxNx(0,b); T3 = Jac*rCl*(NxFi(1,a)*NxFi(0,b) - NxFi(0,a)*NxFi(1,b)); - Ku = w*af*(T1 + T2 + T3 + BtDB + Kvis_u(3,a,b)); + Ku = w*af*(T1 + T2 + T3 + BtDB + visc.du(3,a,b)); lKd(3,a,b) += Ku; T2 = af*Jac*tauC*rho*NxFi(1,a)*NxFi(0,b); - Tv = af*Kvis_v(3,a,b); + Tv = af*visc.dv(3,a,b); lK(4,a,b) += w*(T2 + Tv) + afm*Ku; @@ -1277,12 +1264,12 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, T2 = -tauC*Jac*NxFi(1,a)*VxNx(1,b); - Ku = w*af*(T1 + T2 + BtDB + NxSNx + Kvis_u(4,a,b)); + Ku = w*af*(T1 + T2 + BtDB + NxSNx + visc.du(4,a,b)); lKd(4,a,b) += Ku; T1 = am*Jac*rho*Nw(a)*Nw(b); T2 = T1 + af*Jac*tauC*rho*NxFi(1,a)*NxFi(1,b); - Tv = af*Kvis_v(4,a,b); + Tv = af*visc.dv(4,a,b); lK(5,a,b) += w*(T2 + Tv) + afm*Ku; // dM_2/dV_3 + af/am *dM_2/dU_3 @@ -1294,11 +1281,11 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, T3 = Jac*rCl*(NxFi(1,a)*NxFi(2,b) - NxFi(2,a)*NxFi(1,b)); - Ku = w*af*(T1 + T2 + T3 + BtDB + Kvis_u(5,a,b)); + Ku = w*af*(T1 + T2 + T3 + BtDB + visc.du(5,a,b)); lKd(5,a,b) += Ku; T2 = af*Jac*tauC*rho*NxFi(1,a)*NxFi(2,b); - Tv = af*Kvis_v(5,a,b); + Tv = af*visc.dv(5,a,b); lK(6,a,b) += w*(T2 + Tv) + afm*Ku; // dM_3/dV_1 + af/am *dM_3/dU_1 @@ -1309,11 +1296,11 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, T2 = -tauC*Jac*NxFi(2,a)*VxNx(0,b); T3 = Jac*rCl*(NxFi(2,a)*NxFi(0,b) - NxFi(0,a)*NxFi(2,b)); - Ku = w*af*(T1 + T2 + T3 + BtDB + Kvis_u(6,a,b)); + Ku = w*af*(T1 + T2 + T3 + BtDB + visc.du(6,a,b)); lKd(6,a,b) += Ku; T2 = af*Jac*tauC*rho*NxFi(2,a)*NxFi(0,b); - Tv = af*Kvis_v(6,a,b); + Tv = af*visc.dv(6,a,b); lK(8,a,b) += w*(T2 + Tv) + afm*Ku; // dM_3/dV_2 + af/am *dM_3/dU_2 @@ -1324,11 +1311,11 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, T2 = -tauC*Jac*NxFi(2,a)*VxNx(1,b); T3 = Jac*rCl*(NxFi(2,a)*NxFi(1,b) - NxFi(1,a)*NxFi(2,b)); - Ku = w*af*(T1 + T2 + T3 + BtDB + Kvis_u(7,a,b)); + Ku = w*af*(T1 + T2 + T3 + BtDB + visc.du(7,a,b)); lKd(7,a,b) += Ku; T2 = af*Jac*tauC*rho*NxFi(2,a)*NxFi(1,b); - Tv = af*Kvis_v(7,a,b); + Tv = af*visc.dv(7,a,b); lK(9,a,b) += w*(T2 + Tv) + afm*Ku; @@ -1339,12 +1326,12 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, T1 = Jac*rho*vd(2)*Nw(a)*NxFi(2,b); T2 = -tauC*Jac*NxFi(2,a)*VxNx(2,b); - Ku = w*af*(T1 + T2 + BtDB + NxSNx + Kvis_u(8,a,b)); + Ku = w*af*(T1 + T2 + BtDB + NxSNx + visc.du(8,a,b)); lKd(8,a,b) += Ku; T1 = am*Jac*rho*Nw(a)*Nw(b); T2 = T1 + af*Jac*tauC*rho*NxFi(2,a)*NxFi(2,b); - Tv = af*Kvis_v(8,a,b); + Tv = af*visc.dv(8,a,b); lK(10,a,b) += w*(T2 + Tv) + afm*Ku; } From d55b935c80ea1b000865187e15ab67b3caf4df5e Mon Sep 17 00:00:00 2001 From: dseyler Date: Tue, 22 Sep 2026 20:58:07 -0700 Subject: [PATCH 37/42] Moved Eigen declarations closer to use --- Code/Source/solver/mat_models.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/Code/Source/solver/mat_models.cpp b/Code/Source/solver/mat_models.cpp index bfb33958d..10ff2e32c 100644 --- a/Code/Source/solver/mat_models.cpp +++ b/Code/Source/solver/mat_models.cpp @@ -811,9 +811,7 @@ void compute_pk2cc(const ComMod &com_mod, const CepMod &cep_mod, } // The element routines know their dimension at compile time and call the -// template directly, so instantiate the dimensions the solver supports. Keep -// this next to the definition: a signature change here that is not mirrored -// below fails at link time rather than at compile time. +// template directly, so instantiate the dimensions the solver supports. template void compute_pk2cc<2>(const ComMod&, const CepMod&, const dmnType&, const Matrix<2>&, const int, const Eigen::Map>&, const double, const double, const double, Matrix<2>&, Matrix<3>&, double&); @@ -1556,8 +1554,8 @@ void g_vol_pen(const ComMod& com_mod, const dmnType& lDmn, const double p, namespace { /** - * @brief Viscous PK2 stress and tangent contributions for the viscous - * pseudo-potential model. + * @brief Get the viscous PK2 stress and corresponding tangent matrix contributions for a solid + * with a viscous pseudo-potential model. * * This is defined by a viscous pseudo-potential * Psi = mu/2 * tr(E_dot^2) @@ -1582,7 +1580,6 @@ void compute_visc_stress_potential(const double mu, const int eNoN, const Array< const Matrix& vx, const Matrix& F, Matrix& Svis, Array3& Kvis_u, Array3& Kvis_v) { - const auto Nxm = eigen_view(Nx); // Required intermediate terms for stress and tangent const Matrix F_Ft = F * F.transpose(); @@ -1590,6 +1587,7 @@ void compute_visc_stress_potential(const double mu, const int eNoN, const Array< const Matrix F_vxt = F * vx.transpose(); // F_Nx(i,a) = sum_j F(i,j) * Nx(j,a), and likewise for vx. + const auto Nxm = eigen_view(Nx); const NodalMatrix F_Nx = F * Nxm; const NodalMatrix vx_Nx = vx * Nxm; @@ -1640,8 +1638,6 @@ template void compute_visc_stress_newtonian(const double mu, const int eNoN, const Array& Nx, const Matrix& vx, const Matrix& F, Matrix& Svis, Array3& Kvis_u, Array3& Kvis_v) { - - const auto Nxm = eigen_view(Nx); // Get identity matrix, Jacobian, and F^-1 const double J = F.determinant(); @@ -1654,6 +1650,7 @@ void compute_visc_stress_newtonian(const double mu, const int eNoN, const Array< const Matrix ddev = mat_fun::mat_dev(vx_Fi_symm); // Nx_Fi(i,a) = sum_j Nx(j,a) * Fi(j,i), which is Fi^T * Nx. + const auto Nxm = eigen_view(Nx); const NodalMatrix Nx_Fi = Fi.transpose() * Nxm; const NodalMatrix ddev_Nx_Fi = ddev * Nx_Fi; const NodalMatrix vx_Fi_Nx_Fi = vx_Fi * Nx_Fi; From 66720dfc28f2a561d79c7526ee03603a61749145 Mon Sep 17 00:00:00 2001 From: dseyler Date: Wed, 23 Sep 2026 00:03:08 -0700 Subject: [PATCH 38/42] Hoisted Fiber matrix construction out of gauss loop and cleaned up some Eigen expressions --- Code/Source/solver/fsi.cpp | 16 ++++++++-------- Code/Source/solver/mat_models.cpp | 22 ++++++++++++---------- Code/Source/solver/mat_models.h | 12 ++++++------ Code/Source/solver/sv_struct.cpp | 23 +++++++++++------------ Code/Source/solver/ustruct.cpp | 20 ++++++++++---------- 5 files changed, 47 insertions(+), 46 deletions(-) diff --git a/Code/Source/solver/fsi.cpp b/Code/Source/solver/fsi.cpp index 7b4e3e730..bfd54c254 100644 --- a/Code/Source/solver/fsi.cpp +++ b/Code/Source/solver/fsi.cpp @@ -102,6 +102,14 @@ void construct_fsi(ComMod& com_mod, CepMod& cep_mod, const mshType& lM, const So ya_l_s = 0.0; ya_l_n = 0.0; + if (lM.fN.size() != 0) { + for (int iFn = 0; iFn < nFn; iFn++) { + for (int i = 0; i < nsd; i++) { + fN(i,iFn) = lM.fN(i+nsd*iFn,e); + } + } + } + for (int a = 0; a < eNoN; a++) { int Ac = lM.IEN(a,e); ptr(a) = Ac; @@ -116,14 +124,6 @@ void construct_fsi(ComMod& com_mod, CepMod& cep_mod, const mshType& lM, const So dl(i,a) = Dg(i,Ac); } - if (lM.fN.size() != 0) { - for (int iFn = 0; iFn < nFn; iFn++) { - for (int i = 0; i < nsd; i++) { - fN(i,iFn) = lM.fN(i+nsd*iFn,e); - } - } - } - if (pS0.size() != 0) { pS0l.set_col(a, pS0.col(Ac)); } diff --git a/Code/Source/solver/mat_models.cpp b/Code/Source/solver/mat_models.cpp index 10ff2e32c..d74b20a55 100644 --- a/Code/Source/solver/mat_models.cpp +++ b/Code/Source/solver/mat_models.cpp @@ -234,7 +234,7 @@ std::pair, Tensor> bar_to_iso( double r1 = J2d * double_dot_product(C, S_bar) / nsd; // Compute isochoric 2nd Piola-Kirchhoff stress - auto S_iso = J2d*S_bar - r1*Ci; + const Matrix S_iso = J2d*S_bar - r1*Ci; // Compute isochoric material elasticity tensor Tensor PP = fourth_order_identity() - (1.0/nsd) * dyadic_product(Ci, C); // Important: using auto here causes tests to fail @@ -261,7 +261,7 @@ std::pair, Tensor> bar_to_iso( * @throws std::runtime_error if directions are parallel or if called in 2D. */ template -Eigen::Matrix compute_sheet_normal(const Eigen::Map>& fl) +Eigen::Matrix compute_sheet_normal(const FiberRef& fl) { using namespace mat_fun; @@ -284,7 +284,7 @@ Eigen::Matrix compute_sheet_normal(const Eigen::Map void compute_pk2cc(const ComMod &com_mod, const CepMod &cep_mod, const dmnType &lDmn, const Matrix &F, const int nfd, - const Eigen::Map> &fl, + const FiberRef &fl, const double ya_f, const double ya_s, const double ya_n, Matrix &S, Matrix<3 * (nsd - 1)> &Dm, double &Ja) { using namespace consts; @@ -813,11 +813,11 @@ void compute_pk2cc(const ComMod &com_mod, const CepMod &cep_mod, // The element routines know their dimension at compile time and call the // template directly, so instantiate the dimensions the solver supports. template void compute_pk2cc<2>(const ComMod&, const CepMod&, const dmnType&, - const Matrix<2>&, const int, const Eigen::Map>&, + const Matrix<2>&, const int, const FiberRef<2>&, const double, const double, const double, Matrix<2>&, Matrix<3>&, double&); template void compute_pk2cc<3>(const ComMod&, const CepMod&, const dmnType&, - const Matrix<3>&, const int, const Eigen::Map>&, + const Matrix<3>&, const int, const FiberRef<3>&, const double, const double, const double, Matrix<3>&, Matrix<6>&, double&); /** @@ -1593,7 +1593,7 @@ void compute_visc_stress_potential(const double mu, const int eNoN, const Array< // 2nd Piola-Kirchhoff stress due to viscosity // Svis = mu * 1/2 * ( (F^T * dv/dX) + (F^T * dv/dX)^T ) - Svis.noalias() = mu * mat_fun::mat_symm(Ft_vx); + Svis = 0.5 * mu * (Ft_vx + Ft_vx.transpose()); // Tangent matrix contributions due to viscosity for (int b = 0; b < eNoN; ++b) { @@ -1640,14 +1640,16 @@ void compute_visc_stress_newtonian(const double mu, const int eNoN, const Array< Matrix& Svis, Array3& Kvis_u, Array3& Kvis_v) { // Get identity matrix, Jacobian, and F^-1 + const auto Idm = Matrix::Identity(); const double J = F.determinant(); const Matrix Fi = F.inverse(); // vx_Fi: Velocity gradient in current configuration const Matrix vx_Fi = vx * Fi; - const Matrix vx_Fi_symm = mat_fun::mat_symm(vx_Fi); - // ddev: Deviatoric part of rate of strain tensor - const Matrix ddev = mat_fun::mat_dev(vx_Fi_symm); + // d: rate of deformation tensor, the symmetric velocity gradient + const Matrix d = 0.5 * (vx_Fi + vx_Fi.transpose()); + // ddev: its deviatoric part + const Matrix ddev = d - (d.trace() / nsd) * Idm; // Nx_Fi(i,a) = sum_j Nx(j,a) * Fi(j,i), which is Fi^T * Nx. const auto Nxm = eigen_view(Nx); @@ -1676,7 +1678,7 @@ void compute_visc_stress_newtonian(const double mu, const int eNoN, const Array< r2d * Nx_Fi(i,a) * vx_Fi_Nx_Fi(j,b))); // Derivative of the residual w.r.t velocity - Kvis_v(ii,a,b) = mu * J * (Nx_Fi_Nx_Fi * (i == j) + + Kvis_v(ii,a,b) = mu * J * (Nx_Fi_Nx_Fi * Idm(i,j) + Nx_Fi(i,b) * Nx_Fi(j,a) - r2d * Nx_Fi(i,a) * Nx_Fi(j,b)); } } diff --git a/Code/Source/solver/mat_models.h b/Code/Source/solver/mat_models.h index ccb7efe3f..9030b2084 100644 --- a/Code/Source/solver/mat_models.h +++ b/Code/Source/solver/mat_models.h @@ -29,12 +29,15 @@ void cc_to_voigt(const int nsd, const Tensor4& CC, Array& Dm); void voigt_to_cc(const int nsd, const Array& Dm, Tensor4& CC); +/// @brief Fiber directions at a Gauss point, one direction per column +/// with row count fixed at compile time to the number of spatial dimensions. +template +using FiberRef = Eigen::Ref>; + /** * @brief Compute 2nd Piola-Kirchhoff stress and material stiffness tensors * including both dilational and isochoric components. * - * Reproduces the Fortran 'GETPK2CC' subroutine. - * * @param[in] com_mod Object containing global common variables. * @param[in] cep_mod Object containing electrophysiology-specific common * variables. @@ -52,14 +55,11 @@ void voigt_to_cc(const int nsd, const Array& Dm, Tensor4& CC); * @return None, but modifies S, Dm, and Ja in place. * * @tparam nsd Number of spatial dimensions. - * - * Defined in mat_models.cpp and explicitly instantiated there for nsd = 2 and - * nsd = 3, the only dimensions the solver supports. */ template void compute_pk2cc(const ComMod &com_mod, const CepMod &cep_mod, const dmnType &lDmn, const Matrix &F, const int nfd, - const Eigen::Map> &fl, const double ya_f, + const FiberRef &fl, const double ya_f, const double ya_s, const double ya_n, Matrix &S, Matrix<3 * (nsd - 1)> &Dm, double &Ja); diff --git a/Code/Source/solver/sv_struct.cpp b/Code/Source/solver/sv_struct.cpp index 2471f38af..dfd3d792c 100644 --- a/Code/Source/solver/sv_struct.cpp +++ b/Code/Source/solver/sv_struct.cpp @@ -261,6 +261,14 @@ void construct_dsolid(ComMod& com_mod, CepMod& cep_mod, const mshType& lM, const ya_l_s = 0.0; ya_l_n = 0.0; + if (lM.fN.size() != 0) { + for (int iFn = 0; iFn < nFn; iFn++) { + for (int i = 0; i < nsd; i++) { + fN(i,iFn) = lM.fN(i+nsd*iFn,e); + } + } + } + for (int a = 0; a < eNoN; a++) { int Ac = lM.IEN(a,e); ptr(a) = Ac; @@ -276,14 +284,6 @@ void construct_dsolid(ComMod& com_mod, CepMod& cep_mod, const mshType& lM, const yl(i,a) = Yg(i,Ac); } - if (lM.fN.size() != 0) { - for (int iFn = 0; iFn < nFn; iFn++) { - for (int i = 0; i < nsd; i++) { - fN(i,iFn) = lM.fN(i+nsd*iFn,e); - } - } - } - if (pS0.size() != 0) { pS0l.set_col(a, pS0.col(Ac)); } @@ -305,8 +305,7 @@ void construct_dsolid(ComMod& com_mod, CepMod& cep_mod, const mshType& lM, const for (int g = 0; g < lM.nG; g++) { // Shape function gradients and the viscous response are constant - // within linear simplex elements (tetrahedra, triangles). Bi- and - // trilinear hexahedra are sometimes called linear but do not qualify. + // within linear trianlges and tetrahedra. const bool recompute_visc = (g == 0 || !lM.lShpF); if (recompute_visc) { @@ -441,7 +440,7 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, Matrix<2> S; Matrix<3> Dm; double Ja; - mat_models::compute_pk2cc(com_mod, cep_mod, dmn, F, nFn, eigen_view<2>(fN), ya_g_f, ya_g_s, + mat_models::compute_pk2cc<2>(com_mod, cep_mod, dmn, F, nFn, eigen_view<2>(fN), ya_g_f, ya_g_s, ya_g_n, S, Dm, Ja); // Viscous 2nd Piola-Kirchhoff stress and tangent contributions. Reuse the @@ -608,7 +607,7 @@ void struct_3d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, Matrix<3> S; Matrix<6> Dm; double Ja; - mat_models::compute_pk2cc(com_mod, cep_mod, dmn, F, nFn, eigen_view<3>(fN), ya_g_f, ya_g_s, + mat_models::compute_pk2cc<3>(com_mod, cep_mod, dmn, F, nFn, eigen_view<3>(fN), ya_g_f, ya_g_s, ya_g_n, S, Dm, Ja); // Viscous 2nd Piola-Kirchhoff stress and tangent contributions. Reuse the diff --git a/Code/Source/solver/ustruct.cpp b/Code/Source/solver/ustruct.cpp index af01c743c..ffb07d2aa 100644 --- a/Code/Source/solver/ustruct.cpp +++ b/Code/Source/solver/ustruct.cpp @@ -269,6 +269,14 @@ void construct_usolid(ComMod& com_mod, CepMod& cep_mod, const mshType& lM, const ya_l_s = 0.0; ya_l_n = 0.0; + if (lM.fN.size() != 0) { + for (int iFn = 0; iFn < nFn; iFn++) { + for (int i = 0; i < nsd; i++) { + fN(i,iFn) = lM.fN(i+nsd*iFn,e); + } + } + } + for (int a = 0; a < eNoN; a++) { int Ac = lM.IEN(a,e); ptr(a) = Ac; @@ -284,14 +292,6 @@ void construct_usolid(ComMod& com_mod, CepMod& cep_mod, const mshType& lM, const yl(i,a) = Yg(i,Ac); } - if (lM.fN.size() != 0) { - for (int iFn = 0; iFn < nFn; iFn++) { - for (int i = 0; i < nsd; i++) { - fN(i,iFn) = lM.fN(i+nsd*iFn,e); - } - } - } - if (eq.dmn[cDmn].active_stress != nullptr) { ya_l_f(a) = cep_mod.cem.Ya_f[Ac]; ya_l_s(a) = cep_mod.cem.Ya_s[Ac]; @@ -864,7 +864,7 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, Matrix<2> Siso; Matrix<3> Dm; double Ja = 0; - mat_models::compute_pk2cc(com_mod, cep_mod, eq.dmn[cDmn], F, nFn, eigen_view<2>(fN), ya_g_f, + mat_models::compute_pk2cc<2>(com_mod, cep_mod, eq.dmn[cDmn], F, nFn, eigen_view<2>(fN), ya_g_f, ya_g_s, ya_g_n, Siso, Dm, Ja); // Viscous 2nd Piola-Kirchhoff stress and tangent contributions. Reuse the @@ -1114,7 +1114,7 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, Matrix<3> Siso; Matrix<6> Dm; double Ja = 0; - mat_models::compute_pk2cc(com_mod, cep_mod, eq.dmn[cDmn], F, nFn, eigen_view<3>(fN), ya_g_f, + mat_models::compute_pk2cc<3>(com_mod, cep_mod, eq.dmn[cDmn], F, nFn, eigen_view<3>(fN), ya_g_f, ya_g_s, ya_g_n, Siso, Dm, Ja); // Viscous 2nd Piola-Kirchhoff stress and tangent contributions. Reuse the From 48ed4b7dee0455eace7d3fcfcf69635f33b225cc Mon Sep 17 00:00:00 2001 From: dseyler Date: Wed, 23 Sep 2026 00:10:22 -0700 Subject: [PATCH 39/42] Remove dead mat_fun functions --- Code/Source/solver/mat_fun.h | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/Code/Source/solver/mat_fun.h b/Code/Source/solver/mat_fun.h index 203f322aa..f52814a85 100644 --- a/Code/Source/solver/mat_fun.h +++ b/Code/Source/solver/mat_fun.h @@ -237,34 +237,6 @@ namespace mat_fun { Array mat_symm(const Array& A, const int nd); - /** - * @brief Symmetric part of a 2nd order tensor, 0.5 * (A + A^T). - * - * Fixed-size overload for the Eigen matrices used by the element kernels. - * - * @tparam nsd Number of spatial dimensions. - * @param[in] A second order tensor. - * @return The symmetric part of A. - */ - template - Matrix mat_symm(const Matrix& A) { - return 0.5 * (A + A.transpose()); - } - - /** - * @brief Deviatoric part of a 2nd order tensor, A - tr(A)/nsd * I. - * - * Fixed-size overload for the Eigen matrices used by the element kernels. - * - * @tparam nsd Number of spatial dimensions. - * @param[in] A second order tensor. - * @return The deviatoric part of A. - */ - template - Matrix mat_dev(const Matrix& A) { - return A - (A.trace() / nsd) * Matrix::Identity(); - } - Array mat_symm_prod(const Vector& u, const Vector& v, const int nd); double mat_trace(const Array& A, const int nd); From 888f1a5efbea894ea219da58105f42662077cd10 Mon Sep 17 00:00:00 2001 From: dseyler Date: Wed, 23 Sep 2026 11:39:09 -0700 Subject: [PATCH 40/42] Cleaned up comments and out-of-scope edits --- Code/Source/solver/consts.h | 2 +- Code/Source/solver/mat_fun.h | 20 +---- Code/Source/solver/mat_models.cpp | 2 +- Code/Source/solver/mat_models.h | 4 +- Code/Source/solver/sv_struct.cpp | 74 +++++++++---------- Code/Source/solver/sv_struct.h | 6 +- Code/Source/solver/ustruct.cpp | 118 +++++++++++++++--------------- 7 files changed, 102 insertions(+), 124 deletions(-) diff --git a/Code/Source/solver/consts.h b/Code/Source/solver/consts.h index 022626e79..d38864d4f 100644 --- a/Code/Source/solver/consts.h +++ b/Code/Source/solver/consts.h @@ -18,7 +18,7 @@ namespace consts { const int maxNSD = 3; -const int maxNoN = 27; +const int maxNoN = 27; // Max node count in nn_elem_props.h const int maxNProp = 20; diff --git a/Code/Source/solver/mat_fun.h b/Code/Source/solver/mat_fun.h index f52814a85..f933ab1f7 100644 --- a/Code/Source/solver/mat_fun.h +++ b/Code/Source/solver/mat_fun.h @@ -29,19 +29,15 @@ namespace mat_fun { template using Tensor = Eigen::TensorFixedSize>; - /// @brief One nsd-vector per element node, so nsd x eNoN. Stack allocated, - /// so the column count is bounded by the largest element the solver supports. + /// @brief One nsd-vector per element node, so nsd x eNoN, stack allocated. template using NodalMatrix = Eigen::Matrix; - /// @brief One scalar per element node. Stack allocated, so the entry count - /// is bounded by the largest element the solver supports. + /// @brief One scalar per element node, stack allocated. using NodalVector = Eigen::Matrix; // The eigen_view overloads below wrap an Array or Vector in an Eigen::Map that - // shares its storage, so the container must outlive the view. The templated - // forms fix one dimension at compile time and check it at run time. The - // untemplated forms take both dimensions from the container. + // shares its storage, so the container must outlive the view. /// @brief Read-only Eigen view of an Array, sharing its storage. /// @@ -58,18 +54,12 @@ namespace mat_fun { } /// @brief Read-only Eigen view of a whole Array, sharing its storage. - /// - /// Both dimensions come from the Array, so a row block of a larger array is - /// reached with e.g. eigen_view(dl).middleRows(i), letting Eigen derive - /// the stride. inline Eigen::Map eigen_view(const Array& A) { return {A.data(), A.nrows(), A.ncols()}; } /// @brief Writable Eigen view of a whole Array, sharing its storage. - /// - /// Lets a result be accumulated with a single Eigen expression. inline Eigen::Map eigen_view_mut(Array& A) { return {A.data(), A.nrows(), A.ncols()}; @@ -236,7 +226,6 @@ namespace mat_fun { } Array mat_symm(const Array& A, const int nd); - Array mat_symm_prod(const Vector& u, const Vector& v, const int nd); double mat_trace(const Array& A, const int nd); @@ -251,8 +240,7 @@ namespace mat_fun { * * @tparam nsd Number of spatial dimensions; each tensor is nsd^4. * @param[in] A,B Fourth order tensors to contract. - * @param[in] dimsA,dimsB Zero-based indices of the two dimensions of A and - * of B to contract over. + * @param[in] dimsA,dimsB Indices of the contracted dimensions of A and B. * @return The contracted tensor. */ template diff --git a/Code/Source/solver/mat_models.cpp b/Code/Source/solver/mat_models.cpp index d74b20a55..d00bbb374 100644 --- a/Code/Source/solver/mat_models.cpp +++ b/Code/Source/solver/mat_models.cpp @@ -835,7 +835,7 @@ void compute_pk2cc(const ComMod& com_mod, const CepMod& cep_mod, const dmnType& if (nsd == 2) { // Copy deformation gradient to Eigen matrix auto F_2D = mat_fun::convert_to_eigen_matrix>(F); - + const auto fl_2D = eigen_view<2>(fl); // Initialize stress and elasticity tensors diff --git a/Code/Source/solver/mat_models.h b/Code/Source/solver/mat_models.h index 9030b2084..e2a715a00 100644 --- a/Code/Source/solver/mat_models.h +++ b/Code/Source/solver/mat_models.h @@ -93,8 +93,6 @@ void g_vol_pen(const ComMod& com_mod, const dmnType& lDmn, const double p, /// /// @tparam nsd Number of spatial dimensions. /// -/// Defined in mat_models.cpp and explicitly instantiated there for nsd = 2 and -/// nsd = 3, the only dimensions the solver supports. template class ViscousResponse { public: @@ -115,7 +113,7 @@ class ViscousResponse { /// entry of the block coupling nodes a and b. double du(const int ij, const int a, const int b) const { return Kvis_u_(ij, a, b); } - /// @brief Tangent w.r.t. velocity, indexed as du(). + /// @brief Tangent w.r.t. velocity. double dv(const int ij, const int a, const int b) const { return Kvis_v_(ij, a, b); } private: diff --git a/Code/Source/solver/sv_struct.cpp b/Code/Source/solver/sv_struct.cpp index dfd3d792c..33e903a6b 100644 --- a/Code/Source/solver/sv_struct.cpp +++ b/Code/Source/solver/sv_struct.cpp @@ -16,7 +16,6 @@ #include "nn.h" #include "utils.h" #include "DebugMsg.h" - #include namespace struct_ns { @@ -45,10 +44,10 @@ void b_struct_2d(const ComMod& com_mod, const int eNoN, const double w, const Ve for (int a = 0; a < eNoN; a++) { h = h + N(a)*hl(a); - F(0,0) += Nx(0,a)*dl(i,a); - F(0,1) += Nx(1,a)*dl(i,a); - F(1,0) += Nx(0,a)*dl(j,a); - F(1,1) += Nx(1,a)*dl(j,a); + F(0,0) = F(0,0) + Nx(0,a)*dl(i,a); + F(0,1) = F(0,1) + Nx(1,a)*dl(i,a); + F(1,0) = F(1,0) + Nx(0,a)*dl(j,a); + F(1,1) = F(1,1) + Nx(1,a)*dl(j,a); } double Jac = F(0,0)*F(1,1) - F(0,1)*F(1,0); @@ -69,7 +68,7 @@ void b_struct_2d(const ComMod& com_mod, const int eNoN, const double w, const Ve for (int b = 0; b < eNoN; b++) { double Ku = wl*af*N(a)*(nFi(1)*NxFi(0,b) - nFi(0)*NxFi(1,b)); - lK(1,a,b) += Ku; + lK(1,a,b) = lK(1,a,b) + Ku; lK(dof,a,b) = lK(dof,a,b) - Ku; } } @@ -126,15 +125,15 @@ void b_struct_3d(const ComMod& com_mod, const int eNoN, const double w, const Ve // Compute deformation gradient tensor F for (int a = 0; a < eNoN; a++) { h = h + N(a)*hl(a); - F(0,0) += Nx(0,a)*dl(i,a); - F(0,1) += Nx(1,a)*dl(i,a); - F(0,2) += Nx(2,a)*dl(i,a); - F(1,0) += Nx(0,a)*dl(j,a); - F(1,1) += Nx(1,a)*dl(j,a); - F(1,2) += Nx(2,a)*dl(j,a); - F(2,0) += Nx(0,a)*dl(k,a); - F(2,1) += Nx(1,a)*dl(k,a); - F(2,2) += Nx(2,a)*dl(k,a); + F(0,0) = F(0,0) + Nx(0,a)*dl(i,a); + F(0,1) = F(0,1) + Nx(1,a)*dl(i,a); + F(0,2) = F(0,2) + Nx(2,a)*dl(i,a); + F(1,0) = F(1,0) + Nx(0,a)*dl(j,a); + F(1,1) = F(1,1) + Nx(1,a)*dl(j,a); + F(1,2) = F(1,2) + Nx(2,a)*dl(j,a); + F(2,0) = F(2,0) + Nx(0,a)*dl(k,a); + F(2,1) = F(2,1) + Nx(1,a)*dl(k,a); + F(2,2) = F(2,2) + Nx(2,a)*dl(k,a); } double Jac = mat_fun::mat_det(F, 3); @@ -167,15 +166,15 @@ void b_struct_3d(const ComMod& com_mod, const int eNoN, const double w, const Ve for (int b = 0; b < eNoN; b++) { double Ku = wl * af * N(a) * (nFi(1)*NxFi(0,b) - nFi(0)*NxFi(1,b)); - lK(1,a,b) += Ku; + lK(1,a,b) = lK(1,a,b) + Ku; lK(dof,a,b) = lK(dof,a,b) - Ku; Ku = wl*af*N(a)*(nFi(2)*NxFi(0,b) - nFi(0)*NxFi(2,b)); - lK(2,a,b) += Ku; + lK(2,a,b) = lK(2,a,b) + Ku; lK(2*dof,a,b) = lK(2*dof,a,b) - Ku; Ku = wl*af*N(a)*(nFi(2)*NxFi(1,b) - nFi(1)*NxFi(2,b)); - lK(dof+2,a,b) += Ku; + lK(dof+2,a,b) = lK(dof+2,a,b) + Ku; lK(2*dof+1,a,b) = lK(2*dof+1,a,b) - Ku; } } @@ -183,14 +182,10 @@ void b_struct_3d(const ComMod& com_mod, const int eNoN, const double w, const Ve /// @brief Assemble the residual and tangent contributions of one solid mesh. /// -/// @param[in,out] com_mod Global common variables. The current domain and, when -/// prestress is active, the accumulated nodal stresses are updated here, and -/// the assembled element contributions are written through it. -/// @param[in] cep_mod Electrophysiology variables, supplying the active stress -/// interpolated to each Gauss point. +/// @param[in,out] com_mod Global common variables. +/// @param[in] cep_mod Electrophysiology variables, supplying the active stress. /// @param[in] lM Mesh whose elements are assembled. -/// @param[in] solutions Acceleration, velocity and displacement at the -/// intermediate time level. +/// @param[in] solutions Acceleration, velocity and displacement. void construct_dsolid(ComMod& com_mod, CepMod& cep_mod, const mshType& lM, const SolutionStates& solutions) { const auto& Ag = solutions.intermediate.get_acceleration(); @@ -443,9 +438,9 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, mat_models::compute_pk2cc<2>(com_mod, cep_mod, dmn, F, nFn, eigen_view<2>(fN), ya_g_f, ya_g_s, ya_g_n, S, Dm, Ja); - // Viscous 2nd Piola-Kirchhoff stress and tangent contributions. Reuse the - // previous Gauss point's when shape function gradients are constant within an - // element (e.g. linear triangles, tetrahedra). + // Viscous 2nd Piola-Kirchhoff stress and tangent contributions. + // Reuse from the previous Gauss point when shape function gradients + // are constant within an element (e.g. linear triangles, tetrahedra). static mat_models::ViscousResponse<2> visc; if (recompute_visc) { visc.update(dmn, eNoN, Nx, vx, F); @@ -470,10 +465,10 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, dmsg << " " << P(1,0) << " " << P(1,1); #endif - // Local residual: inertia and body force, plus the divergence of P + // Local residual: inertia and body force, plus div P lRv += w * (ud * Nm.transpose() + P * Nxm); - // Strain-displacement matrix; Bm[a] maps node a displacement to Voigt strain + // Strain-displacement matrix; Bm[a] maps node a to Voigt strain // std::array, consts::maxNoN> Bm; const Matrix<2> Ft = F.transpose(); @@ -491,7 +486,7 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, for (int b = 0; b < eNoN; b++) { - // Material stiffness (D*B) for node b + // Material stiffness for node b const Eigen::Matrix DBm = Dm * Bm[b]; // Geometric stiffness: S*grad(N_b) @@ -530,8 +525,7 @@ void struct_3d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, const Array &fN, const Array &pS0l, Vector &pSl, const Vector &ya_l_f, const Vector &ya_l_s, const Vector &ya_l_n, - Array &lR, Array3 &lK, - const bool recompute_visc) { + Array &lR, Array3 &lK, const bool recompute_visc) { using namespace consts; using namespace mat_fun; @@ -581,7 +575,7 @@ void struct_3d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, const auto bfm = eigen_view<3>(bfl); // nodal body force auto lRv = eigen_view_mut(lR).topRows<3>(); // rows this kernel adds to - // Inertia, damping and body force: the term the residual weights with N + // Inertia, damping and body force. const Eigen::Vector3d ud = (rho*(acc - bfm) + dmp*vel) * Nm - rho * fb; // Active stress activation along fiber, sheet and sheet-normal @@ -610,9 +604,9 @@ void struct_3d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, mat_models::compute_pk2cc<3>(com_mod, cep_mod, dmn, F, nFn, eigen_view<3>(fN), ya_g_f, ya_g_s, ya_g_n, S, Dm, Ja); - // Viscous 2nd Piola-Kirchhoff stress and tangent contributions. Reuse the - // previous Gauss point's when shape function gradients are constant within an - // element (e.g. linear triangles, tetrahedra). + // Viscous 2nd Piola-Kirchhoff stress and tangent contributions. + // Reuse from the previous Gauss point when shape function gradients + // are constant within an element (e.g. linear triangles, tetrahedra). static mat_models::ViscousResponse<3> visc; if (recompute_visc) { visc.update(dmn, eNoN, Nx, vx, F); @@ -644,10 +638,10 @@ void struct_3d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, // const Matrix<3> P = F * S; - // Local residual: inertia and body force, plus the divergence of P + // Local residual: inertia and body force, plus div P lRv += w * (ud * Nm.transpose() + P * Nxm); - // Strain-displacement matrix; Bm[a] maps node a displacement to Voigt strain + // Strain-displacement matrix; Bm[a] maps node a to Voigt strain // std::array, consts::maxNoN> Bm; const Matrix<3> Ft = F.transpose(); @@ -668,7 +662,7 @@ void struct_3d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, for (int b = 0; b < eNoN; b++) { - // Material stiffness (D*B) for node b + // Material stiffness for node b const Eigen::Matrix DBm = Dm * Bm[b]; // Geometric stiffness: S*grad(N_b) diff --git a/Code/Source/solver/sv_struct.h b/Code/Source/solver/sv_struct.h index d9ae855ff..89d082d71 100644 --- a/Code/Source/solver/sv_struct.h +++ b/Code/Source/solver/sv_struct.h @@ -26,8 +26,7 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, const Array &fN, const Array &pS0l, Vector &pSl, const Vector &ya_l_f, const Vector &ya_l_s, const Vector &ya_l_n, - Array &lR, Array3 &lK, - const bool recompute_visc); + Array &lR, Array3 &lK, const bool recompute_visc); void struct_3d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, const double w, const Vector &N, const Array &Nx, @@ -36,8 +35,7 @@ void struct_3d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, const Array &fN, const Array &pS0l, Vector &pSl, const Vector &ya_l_f, const Vector &ya_l_s, const Vector &ya_l_n, - Array &lR, Array3 &lK, - const bool recompute_visc); + Array &lR, Array3 &lK, const bool recompute_visc); }; #endif diff --git a/Code/Source/solver/ustruct.cpp b/Code/Source/solver/ustruct.cpp index ffb07d2aa..55806087c 100644 --- a/Code/Source/solver/ustruct.cpp +++ b/Code/Source/solver/ustruct.cpp @@ -27,7 +27,6 @@ #include "mat_models.h" #include "nn.h" #include "utils.h" - #include #include @@ -57,10 +56,10 @@ void b_ustruct_2d(const ComMod& com_mod, const int eNoN, const double w, const V for (int a = 0; a < eNoN; a++) { h = h + N(a)*hl(a); - F(0,0) += Nx(0,a)*dl(i,a); - F(0,1) += Nx(1,a)*dl(i,a); - F(1,0) += Nx(0,a)*dl(j,a); - F(1,1) += Nx(1,a)*dl(j,a); + F(0,0) = F(0,0) + Nx(0,a)*dl(i,a); + F(0,1) = F(0,1) + Nx(1,a)*dl(i,a); + F(1,0) = F(1,0) + Nx(0,a)*dl(j,a); + F(1,1) = F(1,1) + Nx(1,a)*dl(j,a); } double Jac = F(0,0)*F(1,1) - F(0,1)*F(1,0); @@ -81,8 +80,8 @@ void b_ustruct_2d(const ComMod& com_mod, const int eNoN, const double w, const V for (int b = 0; b < eNoN; b++) { double Ku = wl*af*N(a)*(nFi(1)*NxFi(0,b) - nFi(0)*NxFi(1,b)); - lKd(1,a,b) += Ku; - lK(1,a,b) += afm*Ku; + lKd(1,a,b) = lKd(1,a,b) + Ku; + lK(1,a,b) = lK(1,a,b) + afm*Ku; lKd(2,a,b) = lKd(2,a,b) - Ku; lK(3,a,b) = lK(3,a,b) - afm*Ku; @@ -128,15 +127,15 @@ void b_ustruct_3d(const ComMod& com_mod, const int eNoN, const double w, const V for (int a = 0; a < eNoN; a++) { h = h + N(a)*hl(a); - F(0,0) += Nx(0,a)*dl(i,a); - F(0,1) += Nx(1,a)*dl(i,a); - F(0,2) += Nx(2,a)*dl(i,a); - F(1,0) += Nx(0,a)*dl(j,a); - F(1,1) += Nx(1,a)*dl(j,a); - F(1,2) += Nx(2,a)*dl(j,a); - F(2,0) += Nx(0,a)*dl(k,a); - F(2,1) += Nx(1,a)*dl(k,a); - F(2,2) += Nx(2,a)*dl(k,a); + F(0,0) = F(0,0) + Nx(0,a)*dl(i,a); + F(0,1) = F(0,1) + Nx(1,a)*dl(i,a); + F(0,2) = F(0,2) + Nx(2,a)*dl(i,a); + F(1,0) = F(1,0) + Nx(0,a)*dl(j,a); + F(1,1) = F(1,1) + Nx(1,a)*dl(j,a); + F(1,2) = F(1,2) + Nx(2,a)*dl(j,a); + F(2,0) = F(2,0) + Nx(0,a)*dl(k,a); + F(2,1) = F(2,1) + Nx(1,a)*dl(k,a); + F(2,2) = F(2,2) + Nx(2,a)*dl(k,a); } double Jac = mat_fun::mat_det(F, 3); @@ -161,21 +160,21 @@ void b_ustruct_3d(const ComMod& com_mod, const int eNoN, const double w, const V for (int b = 0; b < eNoN; b++) { double Ku = wl*af*N(a)*(nFi(1)*NxFi(0,b) - nFi(0)*NxFi(1,b)); - lKd(1,a,b) += Ku; - lK(1,a,b) += afm*Ku; + lKd(1,a,b) = lKd(1,a,b) + Ku; + lK(1,a,b) = lK(1,a,b) + afm*Ku; lKd(3,a,b) = lKd(3,a,b) - Ku; lK(4,a,b) = lK(4,a,b) - afm*Ku; Ku = wl*af*N(a)*(nFi(2)*NxFi(0,b) - nFi(0)*NxFi(2,b)); - lKd(2,a,b) += Ku; + lKd(2,a,b) = lKd(2,a,b) + Ku; lK(2,a,b) = lK(2,a,b) + afm*Ku; lKd(6,a,b) = lKd(6,a,b) - Ku; lK(8,a,b) = lK(8,a,b) - afm*Ku; Ku = wl*af*N(a)*(nFi(2)*NxFi(1,b) - nFi(1)*NxFi(2,b)); - lKd(5,a,b) += Ku; + lKd(5,a,b) = lKd(5,a,b) + Ku; lK(6,a,b) = lK(6,a,b) + afm*Ku; lKd(7,a,b) = lKd(7,a,b) - Ku; @@ -329,8 +328,7 @@ void construct_usolid(ComMod& com_mod, CepMod& cep_mod, const mshType& lM, const for (int g = 0; g < fs[0].nG; g++) { // Shape function gradients and the viscous response are constant - // within linear simplex elements (tetrahedra, triangles). Bi- and - // trilinear hexahedra are sometimes called linear but do not qualify. + // within linear triangles and tetrahedra. triangles). const bool recompute_visc = (g == 0 || !fs[0].lShpF); if (recompute_visc) { @@ -480,7 +478,7 @@ void ustruct_2d_c(ComMod& com_mod, CepMod& cep_mod, const bool vmsFlag, const in const auto acc = eigen_view(al).middleRows<2>(i); // nodal accelerations const auto bfm = eigen_view<2>(bfl); // nodal body force - // Velocity, and the inertia less body force, at this Gauss point + // Velocity and inertia at this Gauss point const Eigen::Vector2d v = vel * Nwm; const Eigen::Vector2d vd = (acc - bfm) * Nwm - fb; @@ -648,7 +646,7 @@ void ustruct_3d_c(ComMod& com_mod, CepMod& cep_mod, const bool vmsFlag, const in const auto acc = eigen_view(al).middleRows<3>(i); // nodal accelerations const auto bfm = eigen_view<3>(bfl); // nodal body force - // Velocity, and the inertia less body force, at this Gauss point + // Velocity and inertia at this Gauss point const Eigen::Vector3d v = vel * Nwm; const Eigen::Vector3d vd = (acc - bfm) * Nwm - fb; @@ -833,7 +831,7 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, const auto bfm = eigen_view<2>(bfl); // nodal body force auto lRv = eigen_view_mut(lR).topRows<2>(); // rows this kernel adds to - // Velocity, and the inertia less body force, at this Gauss point + // Velocity and inertia at this Gauss point const Eigen::Vector2d v = vel * Nwm; const Eigen::Vector2d vd = (acc - bfm) * Nwm - fb; @@ -915,7 +913,7 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, // Inertia, the divergence of Pdev, and the pressure/volumetric term lRv += w * (Jac*rho * vd * Nwm.transpose() + Pdev * Nwxm + Jac*rCl * NxFi); - // Strain-displacement matrix; Bm[a] maps node a displacement to Voigt strain + // Strain-displacement matrix; Bm[a] maps node a to Voigt strain // std::array, consts::maxNoN> Bm; @@ -1163,7 +1161,7 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, // Inertia, the divergence of Pdev, and the pressure/volumetric term lRv += w * (Jac*rho * vd * Nwm.transpose() + Pdev * Nwxm + Jac*rCl * NxFi); - // Strain-displacement matrix; Bm[a] maps node a displacement to Voigt strain + // Strain-displacement matrix; Bm[a] maps node a to Voigt strain // std::array, consts::maxNoN> Bm; @@ -1357,6 +1355,8 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, } } +/// @brief Replicates 'SUBROUTINE USTRUCT_DOASSEM(d, eqN, lKd, lK, lR)' +// /// @brief Replicates 'SUBROUTINE USTRUCT_DOASSEM(d, eqN, lKd, lK, lR)' // void ustruct_do_assem(ComMod& com_mod, const int d, const Vector& eqN, const Array3& lKd, @@ -1372,12 +1372,12 @@ void ustruct_do_assem(ComMod& com_mod, const int d, const Vector& eqN, cons // Momentum equation residual is assembled at mapped rows int rowN = idMap(eqN(a)); for (int i = 0; i < nsd; i++) { - R(i,rowN) += lR(i,a); + R(i,rowN) = R(i,rowN) + lR(i,a); } // Continuity equation residual is assembled at unmapped rows rowN = eqN(a); - R(nsd,rowN) += lR(nsd,a); + R(nsd,rowN) = R(nsd,rowN) + lR(nsd,a); } if (nsd == 3) { @@ -1398,9 +1398,9 @@ void ustruct_do_assem(ComMod& com_mod, const int d, const Vector& eqN, cons } for (int i = 0; i < 3; i++) { - Val(i,ptr) += lK (i,a,b); - Val(i+4,ptr) += lK(i+4,a,b); - Val(i+8,ptr) += lK(i+8,a,b); + Val(i,ptr) = Val(i,ptr) + lK (i,a,b); + Val(i+4,ptr) = Val(i+4,ptr) + lK(i+4,a,b); + Val(i+8,ptr) = Val(i+8,ptr) + lK(i+8,a,b); } } @@ -1408,9 +1408,9 @@ void ustruct_do_assem(ComMod& com_mod, const int d, const Vector& eqN, cons for (int b = 0; b < d; b++) { int colN = eqN(b); int ptr = get_col_ptr(com_mod, rowN, colN); - Val(3 ,ptr) += lK(3 ,a,b); - Val(7 ,ptr) += lK(7 ,a,b); - Val(11,ptr) += lK(11,a,b); + Val(3 ,ptr) = Val(3 ,ptr) + lK(3 ,a,b); + Val(7 ,ptr) = Val(7 ,ptr) + lK(7 ,a,b); + Val(11,ptr) = Val(11,ptr) + lK(11,a,b); } } @@ -1427,8 +1427,8 @@ void ustruct_do_assem(ComMod& com_mod, const int d, const Vector& eqN, cons int ptr = get_col_ptr(com_mod, rowN, colN); for (int i = 0; i < 3; i++) { - Kd(i+9,ptr) += lKd(i+9,a,b); - Val(i+12,ptr) += lK(i+12,a,b); + Kd(i+9,ptr) = Kd(i+9,ptr) + lKd(i+9,a,b); + Val(i+12,ptr) = Val(i+12,ptr) + lK(i+12,a,b); } } @@ -1437,7 +1437,7 @@ void ustruct_do_assem(ComMod& com_mod, const int d, const Vector& eqN, cons int colN = eqN(b); int ptr = get_col_ptr(com_mod, rowN, colN); - Val(15,ptr) += lK(15,a,b); + Val(15,ptr) = Val(15,ptr) + lK(15,a,b); } } @@ -1456,12 +1456,12 @@ void ustruct_do_assem(ComMod& com_mod, const int d, const Vector& eqN, cons int ptr = get_col_ptr(com_mod, rowN, colN); for (int i = 0; i < 4; i++) { - Kd(i,ptr) += lKd(i,a,b); + Kd(i,ptr) = Kd(i,ptr) + lKd(i,a,b); } for (int i = 0; i < 2; i++) { - Val(i,ptr) += lK(i,a,b); - Val(i+3,ptr) += lK(i+3,a,b); + Val(i,ptr) = Val(i,ptr) + lK(i,a,b); + Val(i+3,ptr) = Val(i+3,ptr) + lK(i+3,a,b); } } @@ -1470,8 +1470,8 @@ void ustruct_do_assem(ComMod& com_mod, const int d, const Vector& eqN, cons int colN = eqN(b); int ptr = get_col_ptr(com_mod, rowN, colN); - Val(2,ptr) += lK(2,a,b); - Val(5,ptr) += lK(5,a,b); + Val(2,ptr) = Val(2,ptr) + lK(2,a,b); + Val(5,ptr) = Val(5,ptr) + lK(5,a,b); } } @@ -1489,7 +1489,7 @@ void ustruct_do_assem(ComMod& com_mod, const int d, const Vector& eqN, cons for (int i = 0; i < 2; i++) { Kd (i+4,ptr) = Kd(i+4,ptr) + lKd(i+4,a,b); - Val(i+6,ptr) += lK(i+6,a,b); + Val(i+6,ptr) = Val(i+6,ptr) + lK(i+6,a,b); } } @@ -1497,7 +1497,7 @@ void ustruct_do_assem(ComMod& com_mod, const int d, const Vector& eqN, cons for (int b = 0; b < d; b++) { int colN = eqN(b); int ptr = get_col_ptr(com_mod, rowN, colN); - Val(8,ptr) += lK(8,a,b); + Val(8,ptr) = Val(8,ptr) + lK(8,a,b); } } } @@ -1569,20 +1569,20 @@ void ustruct_r(ComMod& com_mod, const SolutionStates& solutions) for (int i = rowPtr(a); i <= rowPtr(a+1)-1; i++) { int c = colPtr(i); - KU(0,a) += Kd(0 ,i)*Rd(0,c) + Kd(1 ,i)*Rd(1,c) + Kd(2 ,i)*Rd(2,c); - KU(1,a) += Kd(3 ,i)*Rd(0,c) + Kd(4 ,i)*Rd(1,c) + Kd(5 ,i)*Rd(2,c); - KU(2,a) += Kd(6 ,i)*Rd(0,c) + Kd(7 ,i)*Rd(1,c) + Kd(8 ,i)*Rd(2,c); - KU(3,a) += Kd(9,i)*Rd(0,c) + Kd(10,i)*Rd(1,c) + Kd(11,i)*Rd(2,c); + KU(0,a) = KU(0,a) + Kd(0 ,i)*Rd(0,c) + Kd(1 ,i)*Rd(1,c) + Kd(2 ,i)*Rd(2,c); + KU(1,a) = KU(1,a) + Kd(3 ,i)*Rd(0,c) + Kd(4 ,i)*Rd(1,c) + Kd(5 ,i)*Rd(2,c); + KU(2,a) = KU(2,a) + Kd(6 ,i)*Rd(0,c) + Kd(7 ,i)*Rd(1,c) + Kd(8 ,i)*Rd(2,c); + KU(3,a) = KU(3,a) + Kd(9,i)*Rd(0,c) + Kd(10,i)*Rd(1,c) + Kd(11,i)*Rd(2,c); } } all_fun::commu(com_mod, KU); for (int a = 0; a < tnNo; a++) { - R(0,a) -= ami*KU(0,a); - R(1,a) -= ami*KU(1,a); - R(2,a) -= ami*KU(2,a); - R(3,a) -= ami*KU(3,a); + R(0,a) = R(0,a) - ami*KU(0,a); + R(1,a) = R(1,a) - ami*KU(1,a); + R(2,a) = R(2,a) - ami*KU(2,a); + R(3,a) = R(3,a) - ami*KU(3,a); } } else { Array KU(3,tnNo); @@ -1594,18 +1594,18 @@ void ustruct_r(ComMod& com_mod, const SolutionStates& solutions) for (int i = rowPtr(a); i <= rowPtr(a+1); i++) { int c = colPtr(i); - KU(0,a) += Kd(0,i)*Rd(0,c) + Kd(1,i)*Rd(1,c); - KU(1,a) += Kd(2,i)*Rd(0,c) + Kd(3,i)*Rd(1,c); - KU(2,a) += Kd(4,i)*Rd(0,c) + Kd(5,i)*Rd(1,c); + KU(0,a) = KU(0,a) + Kd(0,i)*Rd(0,c) + Kd(1,i)*Rd(1,c); + KU(1,a) = KU(1,a) + Kd(2,i)*Rd(0,c) + Kd(3,i)*Rd(1,c); + KU(2,a) = KU(2,a) + Kd(4,i)*Rd(0,c) + Kd(5,i)*Rd(1,c); } } all_fun::commu(com_mod, KU); for (int a = 0; a < tnNo; a++) { - R(0,a) -= ami*KU(0,a); - R(1,a) -= ami*KU(1,a); - R(2,a) -= ami*KU(2,a); + R(0,a) = R(0,a) - ami*KU(0,a); + R(1,a) = R(1,a) - ami*KU(1,a); + R(2,a) = R(2,a) - ami*KU(2,a); } } } From 43f93a96e205e25d7174a9b316ac7d5a9d25721b Mon Sep 17 00:00:00 2001 From: dseyler Date: Thu, 24 Sep 2026 11:45:02 -0700 Subject: [PATCH 41/42] Addressed review comments (constexpr, docs, mutable eigen view) --- Code/Source/solver/consts.h | 8 ++++---- Code/Source/solver/mat_fun.h | 23 ++++++++++++++++++----- Code/Source/solver/mat_models.cpp | 7 +++---- Code/Source/solver/sv_struct.cpp | 28 ++++++++++++++-------------- Code/Source/solver/ustruct.cpp | 28 ++++++++++++++-------------- 5 files changed, 53 insertions(+), 41 deletions(-) diff --git a/Code/Source/solver/consts.h b/Code/Source/solver/consts.h index d38864d4f..43e367ff8 100644 --- a/Code/Source/solver/consts.h +++ b/Code/Source/solver/consts.h @@ -16,13 +16,13 @@ namespace consts { -const int maxNSD = 3; +constexpr int maxNSD = 3; -const int maxNoN = 27; // Max node count in nn_elem_props.h +constexpr int maxNoN = 27; // Max node count in nn_elem_props.h -const int maxNProp = 20; +constexpr int maxNProp = 20; -const int maxOutput = 5; +constexpr int maxOutput = 5; /// Use inf numeric values to represent a value that is not set. const int int_inf = std::numeric_limits::infinity(); diff --git a/Code/Source/solver/mat_fun.h b/Code/Source/solver/mat_fun.h index f933ab1f7..c69782465 100644 --- a/Code/Source/solver/mat_fun.h +++ b/Code/Source/solver/mat_fun.h @@ -22,18 +22,28 @@ /// \todo [TODO:DaveP] this should just be a namespace? // namespace mat_fun { - // Define templated type aliases for Eigen matrices and tensors for convenience + /// @brief A 2nd order tensor, nsd x nsd, fixed size and stack allocated. + /// Used for the deformation gradient, stresses and similar quantities that + /// have a known size at compile time. template using Matrix = Eigen::Matrix; + /// @brief A 4th order tensor, nsd x nsd x nsd x nsd, fixed size and stack + /// allocated. Used for the material elasticity tensor and other 4th order tensors + /// that have a known size at compile time. template using Tensor = Eigen::TensorFixedSize>; - /// @brief One nsd-vector per element node, so nsd x eNoN, stack allocated. + /// @brief One nsd-vector per element node, so nsd x eNoN. Row count is fixed + /// at compile time while column count is the element's node count, known only + /// at run time, so it is bounded by consts::maxNoN to stay stack allocated. + /// Used for shape function gradients and other per-node vector quantities. template using NodalMatrix = Eigen::Matrix; - /// @brief One scalar per element node, stack allocated. + /// @brief One scalar per element node, so eNoN entries. Dynamic length bounded + /// by consts::maxNoN to stay stack allocated, as for NodalMatrix. Used for shape + /// function values and other per-node scalar quantities. using NodalVector = Eigen::Matrix; // The eigen_view overloads below wrap an Array or Vector in an Eigen::Map that @@ -61,7 +71,7 @@ namespace mat_fun { /// @brief Writable Eigen view of a whole Array, sharing its storage. inline Eigen::Map - eigen_view_mut(Array& A) { + eigen_view_mutable(Array& A) { return {A.data(), A.nrows(), A.ncols()}; } @@ -236,7 +246,10 @@ namespace mat_fun { Tensor4 ten_ddot_3424(const Tensor4& A, const Tensor4& B, const int nd); /** - * @brief Contracts two 4th order tensors A and B over two dimensions. + * @brief Contracts two 4th order tensors A and B over two dimensions. + * + * For example, if dimsA = {0, 1} and dimsB = {2, 3} this is + * C_klmn = A_ijkl B_mnij (sum over i, j) * * @tparam nsd Number of spatial dimensions; each tensor is nsd^4. * @param[in] A,B Fourth order tensors to contract. diff --git a/Code/Source/solver/mat_models.cpp b/Code/Source/solver/mat_models.cpp index d00bbb374..bb5e9714d 100644 --- a/Code/Source/solver/mat_models.cpp +++ b/Code/Source/solver/mat_models.cpp @@ -810,8 +810,7 @@ void compute_pk2cc(const ComMod &com_mod, const CepMod &cep_mod, cc_to_voigt_eigen(CC, Dm); } -// The element routines know their dimension at compile time and call the -// template directly, so instantiate the dimensions the solver supports. +// Explicitly instantiate compute_pk2cc for 2D and 3D. template void compute_pk2cc<2>(const ComMod&, const CepMod&, const dmnType&, const Matrix<2>&, const int, const FiberRef<2>&, const double, const double, const double, Matrix<2>&, Matrix<3>&, double&); @@ -834,7 +833,7 @@ void compute_pk2cc(const ComMod& com_mod, const CepMod& cep_mod, const dmnType& if (nsd == 2) { // Copy deformation gradient to Eigen matrix - auto F_2D = mat_fun::convert_to_eigen_matrix>(F); + const auto F_2D = mat_fun::convert_to_eigen_matrix>(F); const auto fl_2D = eigen_view<2>(fl); @@ -851,7 +850,7 @@ void compute_pk2cc(const ComMod& com_mod, const CepMod& cep_mod, const dmnType& } else if (nsd == 3) { // Copy deformation gradient to Eigen matrix - auto F_3D = mat_fun::convert_to_eigen_matrix>(F); + const auto F_3D = mat_fun::convert_to_eigen_matrix>(F); const auto fl_3D = eigen_view<3>(fl); diff --git a/Code/Source/solver/sv_struct.cpp b/Code/Source/solver/sv_struct.cpp index 33e903a6b..0786f7d5d 100644 --- a/Code/Source/solver/sv_struct.cpp +++ b/Code/Source/solver/sv_struct.cpp @@ -396,13 +396,13 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, #endif // This element's nodal fields, as Eigen views over the caller's storage - const auto Nxm = eigen_view<2>(Nx); // grad(N_a) per column - const auto Nm = eigen_view(N); // shape functions - const auto disp = eigen_view(dl).middleRows<2>(i); // nodal displacements - const auto vel = eigen_view(yl).middleRows<2>(i); // nodal velocities - const auto acc = eigen_view(al).middleRows<2>(i); // nodal accelerations - const auto bfm = eigen_view<2>(bfl); // nodal body force - auto lRv = eigen_view_mut(lR).topRows<2>(); // rows this kernel adds to + const auto Nxm = eigen_view<2>(Nx); // grad(N_a) per column + const auto Nm = eigen_view(N); // shape functions + const auto disp = eigen_view(dl).middleRows<2>(i); // nodal displacements + const auto vel = eigen_view(yl).middleRows<2>(i); // nodal velocities + const auto acc = eigen_view(al).middleRows<2>(i); // nodal accelerations + const auto bfm = eigen_view<2>(bfl); // nodal body force + auto lRv = eigen_view_mutable(lR).topRows<2>(); // rows this kernel adds to // Inertia, damping and body force: the term the residual weights with N const Eigen::Vector2d ud = (rho*(acc - bfm) + dmp*vel) * Nm - rho * fb; @@ -567,13 +567,13 @@ void struct_3d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, int i = eq.s; // This element's nodal fields, as Eigen views over the caller's storage - const auto Nxm = eigen_view<3>(Nx); // grad(N_a) per column - const auto Nm = eigen_view(N); // shape functions - const auto disp = eigen_view(dl).middleRows<3>(i); // nodal displacements - const auto vel = eigen_view(yl).middleRows<3>(i); // nodal velocities - const auto acc = eigen_view(al).middleRows<3>(i); // nodal accelerations - const auto bfm = eigen_view<3>(bfl); // nodal body force - auto lRv = eigen_view_mut(lR).topRows<3>(); // rows this kernel adds to + const auto Nxm = eigen_view<3>(Nx); // grad(N_a) per column + const auto Nm = eigen_view(N); // shape functions + const auto disp = eigen_view(dl).middleRows<3>(i); // nodal displacements + const auto vel = eigen_view(yl).middleRows<3>(i); // nodal velocities + const auto acc = eigen_view(al).middleRows<3>(i); // nodal accelerations + const auto bfm = eigen_view<3>(bfl); // nodal body force + auto lRv = eigen_view_mutable(lR).topRows<3>(); // rows this kernel adds to // Inertia, damping and body force. const Eigen::Vector3d ud = (rho*(acc - bfm) + dmp*vel) * Nm - rho * fb; diff --git a/Code/Source/solver/ustruct.cpp b/Code/Source/solver/ustruct.cpp index 55806087c..c6f0c5541 100644 --- a/Code/Source/solver/ustruct.cpp +++ b/Code/Source/solver/ustruct.cpp @@ -823,13 +823,13 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, #endif // This element's nodal fields, as Eigen views over the caller's storage - const auto Nwxm = eigen_view<2>(Nwx); // grad(N_a) per column - const auto Nwm = eigen_view(Nw); // shape functions - const auto disp = eigen_view(dl).middleRows<2>(i); // nodal displacements - const auto vel = eigen_view(yl).middleRows<2>(i); // nodal velocities - const auto acc = eigen_view(al).middleRows<2>(i); // nodal accelerations - const auto bfm = eigen_view<2>(bfl); // nodal body force - auto lRv = eigen_view_mut(lR).topRows<2>(); // rows this kernel adds to + const auto Nwxm = eigen_view<2>(Nwx); // grad(N_a) per column + const auto Nwm = eigen_view(Nw); // shape functions + const auto disp = eigen_view(dl).middleRows<2>(i); // nodal displacements + const auto vel = eigen_view(yl).middleRows<2>(i); // nodal velocities + const auto acc = eigen_view(al).middleRows<2>(i); // nodal accelerations + const auto bfm = eigen_view<2>(bfl); // nodal body force + auto lRv = eigen_view_mutable(lR).topRows<2>(); // rows this kernel adds to // Velocity and inertia at this Gauss point const Eigen::Vector2d v = vel * Nwm; @@ -1072,13 +1072,13 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, #endif // This element's nodal fields, as Eigen views over the caller's storage - const auto Nwxm = eigen_view<3>(Nwx); // grad(N_a) per column - const auto Nwm = eigen_view(Nw); // shape functions - const auto disp = eigen_view(dl).middleRows<3>(i); // nodal displacements - const auto vel = eigen_view(yl).middleRows<3>(i); // nodal velocities - const auto acc = eigen_view(al).middleRows<3>(i); // nodal accelerations - const auto bfm = eigen_view<3>(bfl); // nodal body force - auto lRv = eigen_view_mut(lR).topRows<3>(); // rows this kernel adds to + const auto Nwxm = eigen_view<3>(Nwx); // grad(N_a) per column + const auto Nwm = eigen_view(Nw); // shape functions + const auto disp = eigen_view(dl).middleRows<3>(i); // nodal displacements + const auto vel = eigen_view(yl).middleRows<3>(i); // nodal velocities + const auto acc = eigen_view(al).middleRows<3>(i); // nodal accelerations + const auto bfm = eigen_view<3>(bfl); // nodal body force + auto lRv = eigen_view_mutable(lR).topRows<3>(); // rows this kernel adds to // Velocity, and the inertia less body force, at this Gauss point const Eigen::Vector3d v = vel * Nwm; From 0a4248e5e113acb807b4f691693dd540ca178652 Mon Sep 17 00:00:00 2001 From: dseyler Date: Fri, 25 Sep 2026 18:16:34 -0700 Subject: [PATCH 42/42] Recompute_visc is now passed into visc.update() --- Code/Source/solver/mat_models.cpp | 8 +++++++- Code/Source/solver/mat_models.h | 7 ++++++- Code/Source/solver/sv_struct.cpp | 13 ++++--------- Code/Source/solver/ustruct.cpp | 9 +++------ 4 files changed, 20 insertions(+), 17 deletions(-) diff --git a/Code/Source/solver/mat_models.cpp b/Code/Source/solver/mat_models.cpp index bb5e9714d..7be520658 100644 --- a/Code/Source/solver/mat_models.cpp +++ b/Code/Source/solver/mat_models.cpp @@ -1691,7 +1691,13 @@ void compute_visc_stress_newtonian(const double mu, const int eNoN, const Array< /// zeroes the contributions when the domain has no viscosity model. template void ViscousResponse::update(const dmnType& lDmn, const int eNoN, - const Array& Nx, const Matrix& vx, const Matrix& F) { + const Array& Nx, const Matrix& vx, const Matrix& F, + const bool recompute) { + + // Reuse current stored values. + if (!recompute) { + return; + } // The buffers only need resizing when the element node count changes. if (Kvis_u_.ncols() != eNoN) { diff --git a/Code/Source/solver/mat_models.h b/Code/Source/solver/mat_models.h index e2a715a00..a7d0e2892 100644 --- a/Code/Source/solver/mat_models.h +++ b/Code/Source/solver/mat_models.h @@ -98,13 +98,18 @@ class ViscousResponse { public: /// @brief Evaluate the domain's viscosity model at this Gauss point. /// + /// Does nothing when recompute is false, preserving values from the + /// previous call. Used for linear triangules and tetrahedra for which + /// Nx, vx, and F are constant across the element's Gauss points. + /// /// @param[in] lDmn Domain, supplying the viscosity model and its parameters. /// @param[in] eNoN Number of element nodes. /// @param[in] Nx Shape function spatial derivatives. /// @param[in] vx Velocity gradient. /// @param[in] F Deformation gradient. + /// @param[in] recompute Whether the stored values must be recomputed. void update(const dmnType& lDmn, const int eNoN, const Array& Nx, - const Matrix& vx, const Matrix& F); + const Matrix& vx, const Matrix& F, const bool recompute); /// @brief Viscous 2nd Piola-Kirchhoff stress. const Matrix& S() const { return Svis_; } diff --git a/Code/Source/solver/sv_struct.cpp b/Code/Source/solver/sv_struct.cpp index 0786f7d5d..ac198c3ef 100644 --- a/Code/Source/solver/sv_struct.cpp +++ b/Code/Source/solver/sv_struct.cpp @@ -300,7 +300,7 @@ void construct_dsolid(ComMod& com_mod, CepMod& cep_mod, const mshType& lM, const for (int g = 0; g < lM.nG; g++) { // Shape function gradients and the viscous response are constant - // within linear trianlges and tetrahedra. + // within linear triangles and tetrahedra. const bool recompute_visc = (g == 0 || !lM.lShpF); if (recompute_visc) { @@ -358,8 +358,7 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, const Array &fN, const Array &pS0l, Vector &pSl, const Vector &ya_l_f, const Vector &ya_l_s, const Vector &ya_l_n, - Array &lR, Array3 &lK, - const bool recompute_visc) { + Array &lR, Array3 &lK, const bool recompute_visc) { using namespace consts; using namespace mat_fun; @@ -442,9 +441,7 @@ void struct_2d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, // Reuse from the previous Gauss point when shape function gradients // are constant within an element (e.g. linear triangles, tetrahedra). static mat_models::ViscousResponse<2> visc; - if (recompute_visc) { - visc.update(dmn, eNoN, Nx, vx, F); - } + visc.update(dmn, eNoN, Nx, vx, F, recompute_visc); // Elastic + Viscous stresses S = S + visc.S(); @@ -608,9 +605,7 @@ void struct_3d(ComMod &com_mod, CepMod &cep_mod, const int eNoN, const int nFn, // Reuse from the previous Gauss point when shape function gradients // are constant within an element (e.g. linear triangles, tetrahedra). static mat_models::ViscousResponse<3> visc; - if (recompute_visc) { - visc.update(dmn, eNoN, Nx, vx, F); - } + visc.update(dmn, eNoN, Nx, vx, F, recompute_visc); // Elastic + Viscous stresses S = S + visc.S(); diff --git a/Code/Source/solver/ustruct.cpp b/Code/Source/solver/ustruct.cpp index c6f0c5541..a7f3c0908 100644 --- a/Code/Source/solver/ustruct.cpp +++ b/Code/Source/solver/ustruct.cpp @@ -869,9 +869,8 @@ void ustruct_2d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, // previous Gauss point's when shape function gradients are constant within an // element (e.g. linear triangles and tetrahedra). static mat_models::ViscousResponse<2> visc; - if (recompute_visc) { - visc.update(dmn, eNoNw, Nwx, vx, F); - } + + visc.update(dmn, eNoNw, Nwx, vx, F, recompute_visc); // Compute rho and beta depending on the volumetric penalty model // @@ -1119,9 +1118,7 @@ void ustruct_3d_m(ComMod &com_mod, CepMod &cep_mod, const bool vmsFlag, // previous Gauss point's when shape function gradients are constant within an // element (e.g. linear triangles and tetrahedra). static mat_models::ViscousResponse<3> visc; - if (recompute_visc) { - visc.update(dmn, eNoNw, Nwx, vx, F); - } + visc.update(dmn, eNoNw, Nwx, vx, F, recompute_visc); // Compute rho and beta depending on the volumetric penalty model //