1052409adSJames Wright // Copyright (c) 2017-2023, Lawrence Livermore National Security, LLC and other CEED contributors. 2052409adSJames Wright // All Rights Reserved. See the top-level LICENSE and NOTICE files for details. 3052409adSJames Wright // 4052409adSJames Wright // SPDX-License-Identifier: BSD-2-Clause 5052409adSJames Wright // 6052409adSJames Wright // This file is part of CEED: http://github.com/ceed 7052409adSJames Wright 8052409adSJames Wright /// @file 9052409adSJames Wright /// Element anisotropy tensor, as defined in 'Invariant data-driven subgrid stress modeling in the strain-rate eigenframe for large eddy simulation' 10052409adSJames Wright /// Prakash et al. 2022 11052409adSJames Wright 12052409adSJames Wright #ifndef grid_anisotropy_tensor_h 13052409adSJames Wright #define grid_anisotropy_tensor_h 14052409adSJames Wright 15052409adSJames Wright #include <ceed.h> 16052409adSJames Wright 17052409adSJames Wright #include "utils.h" 18052409adSJames Wright #include "utils_eigensolver_jacobi.h" 19052409adSJames Wright 20052409adSJames Wright // @brief Get Anisotropy tensor from xi_{i,j} 21052409adSJames Wright // @details A_ij = \Delta_{ij} / ||\Delta_ij||, \Delta_ij = (xi_{i,j})^(-1/2) 22052409adSJames Wright CEED_QFUNCTION_HELPER void AnisotropyTensor(const CeedScalar km_g_ij[6], CeedScalar A_ij[3][3], CeedScalar *delta, const CeedInt n_sweeps) { 23052409adSJames Wright CeedScalar evals[3], evecs[3][3], evals_evecs[3][3] = {{0.}}, g_ij[3][3]; 24*1b561cd6SJames Wright CeedInt work_vector[3]; 25052409adSJames Wright 26052409adSJames Wright // Invert square root of metric tensor to get \Delta_ij 27052409adSJames Wright KMUnpack(km_g_ij, g_ij); 28052409adSJames Wright Diagonalize3(g_ij, evals, evecs, work_vector, SORT_DECREASING_EVALS, true, n_sweeps); 29052409adSJames Wright for (int i = 0; i < 3; i++) evals[i] = 1 / sqrt(evals[i]); 30052409adSJames Wright MatDiag3(evecs, evals, CEED_NOTRANSPOSE, evals_evecs); 31052409adSJames Wright MatMat3(evecs, evals_evecs, CEED_TRANSPOSE, CEED_NOTRANSPOSE, A_ij); // A_ij = E^T D E 32052409adSJames Wright 33052409adSJames Wright // Scale by delta to get anisotropy tensor 34052409adSJames Wright *delta = sqrt(Dot3(evals, evals)); 35052409adSJames Wright ScaleN((CeedScalar *)A_ij, 1 / *delta, 9); 36052409adSJames Wright // NOTE Need 2 factor to get physical element size (rather than projected onto [-1,1]^dim) 37052409adSJames Wright // Should attempt to auto-determine this from the quadrature point coordinates in reference space 38052409adSJames Wright *delta *= 2; 39052409adSJames Wright } 40052409adSJames Wright 41052409adSJames Wright // @brief RHS for L^2 projection of anisotropic tensor and it's Frobenius norm 42052409adSJames Wright CEED_QFUNCTION(AnisotropyTensorProjection)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 43052409adSJames Wright const CeedScalar(*q_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 44052409adSJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 45052409adSJames Wright 46052409adSJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 47052409adSJames Wright const CeedScalar wdetJ = q_data[0][i]; 48052409adSJames Wright const CeedScalar dXdx[3][3] = { 49052409adSJames Wright {q_data[1][i], q_data[2][i], q_data[3][i]}, 50052409adSJames Wright {q_data[4][i], q_data[5][i], q_data[6][i]}, 51052409adSJames Wright {q_data[7][i], q_data[8][i], q_data[9][i]} 52052409adSJames Wright }; 53052409adSJames Wright 54052409adSJames Wright CeedScalar km_g_ij[6] = {0.}, A_ij[3][3] = {{0.}}, km_A_ij[6], delta; 55052409adSJames Wright KMMetricTensor(dXdx, km_g_ij); 56052409adSJames Wright AnisotropyTensor(km_g_ij, A_ij, &delta, 15); 57052409adSJames Wright KMPack(A_ij, km_A_ij); 58052409adSJames Wright 59052409adSJames Wright for (CeedInt j = 0; j < 6; j++) v[j][i] = wdetJ * km_A_ij[j]; 60052409adSJames Wright v[6][i] = wdetJ * delta; 61052409adSJames Wright } 62052409adSJames Wright return 0; 63052409adSJames Wright } 64052409adSJames Wright 65900aec75SJames Wright // @brief Get anisotropic tensor and it's Frobenius norm at quadrature points 66900aec75SJames Wright CEED_QFUNCTION(AnisotropyTensorCollocate)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 67900aec75SJames Wright const CeedScalar(*q_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 68900aec75SJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 69900aec75SJames Wright 70900aec75SJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 71900aec75SJames Wright const CeedScalar dXdx[3][3] = { 72900aec75SJames Wright {q_data[1][i], q_data[2][i], q_data[3][i]}, 73900aec75SJames Wright {q_data[4][i], q_data[5][i], q_data[6][i]}, 74900aec75SJames Wright {q_data[7][i], q_data[8][i], q_data[9][i]} 75900aec75SJames Wright }; 76900aec75SJames Wright 77900aec75SJames Wright CeedScalar km_g_ij[6] = {0.}, A_ij[3][3] = {{0.}}, km_A_ij[6], delta; 78900aec75SJames Wright KMMetricTensor(dXdx, km_g_ij); 79900aec75SJames Wright AnisotropyTensor(km_g_ij, A_ij, &delta, 15); 80900aec75SJames Wright KMPack(A_ij, km_A_ij); 81900aec75SJames Wright 82900aec75SJames Wright for (CeedInt j = 0; j < 6; j++) v[j][i] = km_A_ij[j]; 83900aec75SJames Wright v[6][i] = delta; 84900aec75SJames Wright } 85900aec75SJames Wright return 0; 86900aec75SJames Wright } 87900aec75SJames Wright 88052409adSJames Wright #endif /* ifndef grid_anisotropy_tensor_h */ 89