Tensor migration #2084
Conversation
rjoussen
left a comment
There was a problem hiding this comment.
Thanks for tackling this!
| template <typename T> | ||
| Core::LinAlg::SymmetricTensor<T, 3, 3, 3, 3> Core::LinAlg::FourTensorOperations::kronecker_product( | ||
| const Core::LinAlg::SymmetricTensor<T, 3, 3>& A) | ||
| { | ||
| return 0.5 * (einsum_sym<"ik", "jl">(A, A) + einsum_sym<"il", "jk">(A, A)); | ||
| } |
There was a problem hiding this comment.
This operation returns a symmetric tensor regardless of whether A is symmetric. We should probably overload this or use SquareTensor concept directly here. This would also allow sizes different than 3.
| template <typename T> | ||
| Core::LinAlg::Tensor<T, 3, 3, 3, 3> Core::LinAlg::FourTensorOperations::adbc_tensor_product( | ||
| const Core::LinAlg::Tensor<T, 3, 3>& A, const Core::LinAlg::Tensor<T, 3, 3>& B) | ||
| { | ||
| return einsum<"ad", "bc">(A, B); | ||
| } | ||
|
|
There was a problem hiding this comment.
| template <typename T> | |
| Core::LinAlg::Tensor<T, 3, 3, 3, 3> Core::LinAlg::FourTensorOperations::adbc_tensor_product( | |
| const Core::LinAlg::Tensor<T, 3, 3>& A, const Core::LinAlg::Tensor<T, 3, 3>& B) | |
| { | |
| return einsum<"ad", "bc">(A, B); | |
| } |
Since this purely wraps einsum, which is clearer and easier to understand in my opinion, I would not implement this. Users can just use einsum directly
| template <typename T> | ||
| Core::LinAlg::Tensor<T, 3, 3, 3, 3> Core::LinAlg::FourTensorOperations::non_symmetric_product( | ||
| const Core::LinAlg::Tensor<T, 3, 3>& A, const Core::LinAlg::Tensor<T, 3, 3>& B) | ||
| { | ||
| if (clear_result_tensor) four_tensor_result.clear(); | ||
| for (int i = 0; i < dim; ++i) | ||
| { | ||
| for (int j = 0; j < dim; ++j) | ||
| { | ||
| for (int k = 0; k < dim; ++k) | ||
| { | ||
| for (int l = 0; l < dim; ++l) | ||
| { | ||
| for (int m = 0; m < dim; ++m) | ||
| { // C^ijkl = A^ijkm * B_m^l | ||
| four_tensor_result(i, j, k, l) += four_tensor(i, j, k, m) * matrix(m, l); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| return einsum<"ac", "db">(A, B); |
There was a problem hiding this comment.
Same here, it is much clearer to use einsum directly, I think.
There was a problem hiding this comment.
These new conversion methods will help a lot in the future, thanks for implementing them!
| template <typename T> | ||
| Core::LinAlg::Tensor<T, 3, 3, 3, 3> kronecker_product( | ||
| const Core::LinAlg::Tensor<T, 3, 3>& A, const Core::LinAlg::Tensor<T, 3, 3>& B); | ||
|
|
There was a problem hiding this comment.
This is really a very special kind of kronecker product. For a normal kronecker product, I would probably expect something like
Mainly, I am not sure whether we should introduce tensor helper functions with unclear semantics (unlike dot or ddot which are easy to understand). In contrast to the old Matrix api, specialized tensor products are easy to do on the fly when you need them, and the resulting code is probably easier to understand than having to look up what exactly a Kronecker product means here.
There was a problem hiding this comment.
Yes, I totally agree. I found myself quite confused with the terminology and implementation of the kronecker product (which clashes sometimes).
Therefore, I am also happy with dropping the helper functions, as the einsum is actually self-documenting. But I'm also happy to hear other opinions, from e.g. @dragos-ana and @c-p-schmidt.
There was a problem hiding this comment.
I agree as well. One could easily introduce "his" / "her" own helper functions directly in the cpp where the tensor products are required.
However, I also find the idea of having some products already available quite nice. Since the naming is confusing, maybe this is more explicitly addressed by naming them based on the indices involved, e.g. like in add_adbc_tensor_product. For the composed products such as the Holzapfel product, this gets slightly uglier, e.g., add_half_adbc_half_acbd_product.
dragos-ana
left a comment
There was a problem hiding this comment.
Looks very nice! I added some minor suggestions.
I am not entirely sure what is the best approach now regarding the added tensor product counterparts for some of the matrix products such as the Kronecker product.
The idea of having helper functions for these is nice, but this should be done with consistent, easily understandable names.
| template <typename T> | ||
| Core::LinAlg::Tensor<T, 3, 3, 3, 3> kronecker_product( | ||
| const Core::LinAlg::Tensor<T, 3, 3>& A, const Core::LinAlg::Tensor<T, 3, 3>& B); | ||
|
|
There was a problem hiding this comment.
I agree as well. One could easily introduce "his" / "her" own helper functions directly in the cpp where the tensor products are required.
However, I also find the idea of having some products already available quite nice. Since the naming is confusing, maybe this is more explicitly addressed by naming them based on the indices involved, e.g. like in add_adbc_tensor_product. For the composed products such as the Holzapfel product, this gets slightly uglier, e.g., add_half_adbc_half_acbd_product.
| /*! | ||
| * @brief Creates a 6x9 Voigt matrix from a 4th order tensor that has the minor symmetry in its | ||
| * first index pair (C_ijkl = C_jikl). |
There was a problem hiding this comment.
Really nice, the entire tensor conversion part. The conversion to 9x9 is missing as far as I see, but this is easy to implement based on your nice implementation here, if this will be required in the future.
| double Mtheta_dev_sym_contract_Mtheta_dev_sym = | ||
| Core::LinAlg::FourTensorOperations::contract_matrix_matrix( | ||
| state_quantities.curr_Mtheta_dev_sym_M, state_quantities.curr_Mtheta_dev_sym_M); | ||
| Core::LinAlg::ddot(Core::LinAlg::make_tensor_view(state_quantities.curr_Mtheta_dev_sym_M), |
There was a problem hiding this comment.
Nice start to the tensor migration within the viscoplastic material ;)
| FOUR_C_EXPECT_NEAR(new_voigt, old_voigt, 1e-12); | ||
| } | ||
|
|
||
| TEST(TensorConversionTest, MakeStressLikeVoigtMatrixFromTensorTest) |
There was a problem hiding this comment.
| TEST(TensorConversionTest, MakeStressLikeVoigtMatrixFromTensorTest) | |
| TEST(TensorConversionTest, Make6x6StressLikeVoigtMatrixFromTensorTest) |
Maybe slightly more descriptive and consistent with the other added tests?
Migrate some more fourth-order tensor products to the tensor API + fix two bugs
Part of the ongoing
FourTensorOperations→ tensor-API migration.Added
kronecker_product(A)(symmetric box self product) andkronecker_product(A, B)(full)adbc_tensor_product(A, B)=A_AD B_BC,non_symmetric_product(A, B)=A_AC B_DBmake_6x9 / make_9x6 / make_6x6_voigt_matrix_from_tensorFixed (
add_kronecker_tensor_product, 6x9 overload)C(5,5)assignment (appliedscalar_thistwice)C(5,8)accumulated fromC(5,7)instead ofC(5,8)Refactored / removed
elast_hyper_get_derivs_of_elastic_right_cg_tensornow exemplarly uses the tensor API instead of theFourTensor/9x9-Voigt round-tripcontract_matrix_matrix→Core::LinAlg::ddot; removed unusedmultiply_four_tensor_matrixTests
New unit tests for all added ops: element-wise formula checks plus cross-checks against the legacy Voigt/9x9 implementations.