From: Menno Fraters Date: Fri, 28 Feb 2020 18:19:09 +0000 (-0800) Subject: Add ranke 2 tensor ortogonalization function. X-Git-Tag: v9.2.0-rc1~453^2~4 X-Git-Url: https://gitweb.dealii.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=51ba75a6a1cf844e1600d6a30b95ea914ab83de4;p=dealii.git Add ranke 2 tensor ortogonalization function. --- diff --git a/include/deal.II/base/tensor.h b/include/deal.II/base/tensor.h index a1952271f1..81a06ca789 100644 --- a/include/deal.II/base/tensor.h +++ b/include/deal.II/base/tensor.h @@ -26,6 +26,8 @@ #include #include +#include + #ifdef DEAL_II_WITH_ADOLC # include // Taped double #endif @@ -45,6 +47,8 @@ template class Tensor; template class Vector; +template +class FullMatrix; namespace Differentiation { namespace SD @@ -2613,6 +2617,53 @@ cofactor(const Tensor<2, dim, Number> &t) } +/** + * Return the nearest orthogonal matrix using a SVD if the + * deteriminant is more than a tolerance away from one. + * The orthogonalization is done by combining the products + * of the SVD decomposition: $((U*I)*V^T)^T$, where I is the + * idententy matrix and $U$ and $V$ are computed from the SVD + * decomposition: $\mathbf U \cdot \mathbf S \cdot \mathbf V^T$ + * @relatesalso Tensor + */ +template +constexpr Tensor<2, dim, Number> +orthogonalize(const Tensor<2, dim, Number> &tensor, const double tolerance) +{ + if (std::abs(determinant(tensor) - 1.0) > tolerance) + { + LAPACKFullMatrix identity_matrix(dim); + for (size_t i = 0; i < dim; i++) + { + identity_matrix.set(i, i, 1.); + } + + Tensor<2, dim, Number> output_tensor; + FullMatrix matrix(dim); + LAPACKFullMatrix lapack_matrix(dim); + LAPACKFullMatrix result(dim); + LAPACKFullMatrix result2(dim); + + // todo: find or add dealii functionallity to copy in one step. + matrix.copy_from(tensor); + lapack_matrix.copy_from(matrix); + + // now compute the svd of the matrices + lapack_matrix.compute_svd(); + + // Use the SVD results to orthogonalize: ((U*I)*V^T)^T + lapack_matrix.get_svd_u().mmult(result, identity_matrix); + result.mmult(result2, (lapack_matrix.get_svd_vt())); + + // todo: find or add dealii functionallity to copy in one step. + matrix = result2; + matrix.copy_to(output_tensor); + return output_tensor; + } + return tensor; +} + + /** * Return the $l_1$ norm of the given rank-2 tensor, where $||t||_1 = \max_j * \sum_i |t_{ij}|$ (maximum of the sums over columns).