1ae2b091fSJames Wright // SPDX-FileCopyrightText: Copyright (c) 2017-2024, HONEE contributors.
2ae2b091fSJames Wright // SPDX-License-Identifier: Apache-2.0 OR BSD-2-Clause
3c38c977aSJames Wright
4c38c977aSJames Wright /// @file
5c38c977aSJames Wright /// Element anisotropy tensor, as defined in 'Invariant data-driven subgrid stress modeling in the strain-rate eigenframe for large eddy simulation'
6c38c977aSJames Wright /// Prakash et al. 2022
7*3e17a7a1SJames Wright #include <ceed/types.h>
8c38c977aSJames Wright
9c38c977aSJames Wright #include "utils.h"
10c38c977aSJames Wright #include "utils_eigensolver_jacobi.h"
11c38c977aSJames Wright
12c38c977aSJames Wright // @brief Get Anisotropy tensor from xi_{i,j}
13c38c977aSJames Wright // @details A_ij = \Delta_{ij} / ||\Delta_ij||, \Delta_ij = (xi_{i,j})^(-1/2)
AnisotropyTensor(const CeedScalar km_g_ij[6],CeedScalar A_ij[3][3],CeedScalar * delta,const CeedInt n_sweeps)14c38c977aSJames Wright CEED_QFUNCTION_HELPER void AnisotropyTensor(const CeedScalar km_g_ij[6], CeedScalar A_ij[3][3], CeedScalar *delta, const CeedInt n_sweeps) {
15c38c977aSJames Wright CeedScalar evals[3], evecs[3][3], evals_evecs[3][3] = {{0.}}, g_ij[3][3];
167df379d9SJames Wright CeedInt work_vector[3];
17c38c977aSJames Wright
18c38c977aSJames Wright // Invert square root of metric tensor to get \Delta_ij
19c38c977aSJames Wright KMUnpack(km_g_ij, g_ij);
20c38c977aSJames Wright Diagonalize3(g_ij, evals, evecs, work_vector, SORT_DECREASING_EVALS, true, n_sweeps);
21c38c977aSJames Wright for (int i = 0; i < 3; i++) evals[i] = 1 / sqrt(evals[i]);
22c38c977aSJames Wright MatDiag3(evecs, evals, CEED_NOTRANSPOSE, evals_evecs);
23c38c977aSJames Wright MatMat3(evecs, evals_evecs, CEED_TRANSPOSE, CEED_NOTRANSPOSE, A_ij); // A_ij = E^T D E
24c38c977aSJames Wright
25c38c977aSJames Wright // Scale by delta to get anisotropy tensor
2664667825SJames Wright *delta = Norm3(evals);
27c38c977aSJames Wright ScaleN((CeedScalar *)A_ij, 1 / *delta, 9);
28c38c977aSJames Wright // NOTE Need 2 factor to get physical element size (rather than projected onto [-1,1]^dim)
29c38c977aSJames Wright // Should attempt to auto-determine this from the quadrature point coordinates in reference space
30c38c977aSJames Wright *delta *= 2;
31c38c977aSJames Wright }
32c38c977aSJames Wright
33c38c977aSJames Wright // @brief RHS for L^2 projection of anisotropic tensor and it's Frobenius norm
AnisotropyTensorProjection(void * ctx,CeedInt Q,const CeedScalar * const * in,CeedScalar * const * out)34c38c977aSJames Wright CEED_QFUNCTION(AnisotropyTensorProjection)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) {
35c38c977aSJames Wright const CeedScalar(*q_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0];
36c38c977aSJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0];
37c38c977aSJames Wright
38c38c977aSJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) {
39c38c977aSJames Wright const CeedScalar wdetJ = q_data[0][i];
40c38c977aSJames Wright const CeedScalar dXdx[3][3] = {
41c38c977aSJames Wright {q_data[1][i], q_data[2][i], q_data[3][i]},
42c38c977aSJames Wright {q_data[4][i], q_data[5][i], q_data[6][i]},
43c38c977aSJames Wright {q_data[7][i], q_data[8][i], q_data[9][i]}
44c38c977aSJames Wright };
45c38c977aSJames Wright
46c38c977aSJames Wright CeedScalar km_g_ij[6] = {0.}, A_ij[3][3] = {{0.}}, km_A_ij[6], delta;
47c38c977aSJames Wright KMMetricTensor(dXdx, km_g_ij);
48c38c977aSJames Wright AnisotropyTensor(km_g_ij, A_ij, &delta, 15);
49c38c977aSJames Wright KMPack(A_ij, km_A_ij);
50c38c977aSJames Wright
51c38c977aSJames Wright for (CeedInt j = 0; j < 6; j++) v[j][i] = wdetJ * km_A_ij[j];
52c38c977aSJames Wright v[6][i] = wdetJ * delta;
53c38c977aSJames Wright }
54c38c977aSJames Wright return 0;
55c38c977aSJames Wright }
56c38c977aSJames Wright
578dadcfbdSJames Wright // @brief Get anisotropic tensor and it's Frobenius norm at quadrature points
AnisotropyTensorCollocate(void * ctx,CeedInt Q,const CeedScalar * const * in,CeedScalar * const * out)588dadcfbdSJames Wright CEED_QFUNCTION(AnisotropyTensorCollocate)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) {
598dadcfbdSJames Wright const CeedScalar(*q_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0];
608dadcfbdSJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0];
618dadcfbdSJames Wright
628dadcfbdSJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) {
638dadcfbdSJames Wright const CeedScalar dXdx[3][3] = {
648dadcfbdSJames Wright {q_data[1][i], q_data[2][i], q_data[3][i]},
658dadcfbdSJames Wright {q_data[4][i], q_data[5][i], q_data[6][i]},
668dadcfbdSJames Wright {q_data[7][i], q_data[8][i], q_data[9][i]}
678dadcfbdSJames Wright };
688dadcfbdSJames Wright
698dadcfbdSJames Wright CeedScalar km_g_ij[6] = {0.}, A_ij[3][3] = {{0.}}, km_A_ij[6], delta;
708dadcfbdSJames Wright KMMetricTensor(dXdx, km_g_ij);
718dadcfbdSJames Wright AnisotropyTensor(km_g_ij, A_ij, &delta, 15);
728dadcfbdSJames Wright KMPack(A_ij, km_A_ij);
738dadcfbdSJames Wright
748dadcfbdSJames Wright for (CeedInt j = 0; j < 6; j++) v[j][i] = km_A_ij[j];
758dadcfbdSJames Wright v[6][i] = delta;
768dadcfbdSJames Wright }
778dadcfbdSJames Wright return 0;
788dadcfbdSJames Wright }
79