xref: /honee/qfunctions/grid_anisotropy_tensor.h (revision 8dadcfbdda906d5d7f3e4c37975a9ff127e6c6f4)
1c38c977aSJames Wright // Copyright (c) 2017-2023, Lawrence Livermore National Security, LLC and other CEED contributors.
2c38c977aSJames Wright // All Rights Reserved. See the top-level LICENSE and NOTICE files for details.
3c38c977aSJames Wright //
4c38c977aSJames Wright // SPDX-License-Identifier: BSD-2-Clause
5c38c977aSJames Wright //
6c38c977aSJames Wright // This file is part of CEED:  http://github.com/ceed
7c38c977aSJames Wright 
8c38c977aSJames Wright /// @file
9c38c977aSJames Wright /// Element anisotropy tensor, as defined in 'Invariant data-driven subgrid stress modeling in the strain-rate eigenframe for large eddy simulation'
10c38c977aSJames Wright /// Prakash et al. 2022
11c38c977aSJames Wright 
12c38c977aSJames Wright #ifndef grid_anisotropy_tensor_h
13c38c977aSJames Wright #define grid_anisotropy_tensor_h
14c38c977aSJames Wright 
15c38c977aSJames Wright #include <ceed.h>
16c38c977aSJames Wright 
17c38c977aSJames Wright #include "utils.h"
18c38c977aSJames Wright #include "utils_eigensolver_jacobi.h"
19c38c977aSJames Wright 
20c38c977aSJames Wright // @brief Get Anisotropy tensor from xi_{i,j}
21c38c977aSJames Wright // @details A_ij = \Delta_{ij} / ||\Delta_ij||, \Delta_ij = (xi_{i,j})^(-1/2)
22c38c977aSJames Wright CEED_QFUNCTION_HELPER void AnisotropyTensor(const CeedScalar km_g_ij[6], CeedScalar A_ij[3][3], CeedScalar *delta, const CeedInt n_sweeps) {
23c38c977aSJames Wright   CeedScalar evals[3], evecs[3][3], evals_evecs[3][3] = {{0.}}, g_ij[3][3];
24c38c977aSJames Wright   CeedInt    work_vector[2];
25c38c977aSJames Wright 
26c38c977aSJames Wright   // Invert square root of metric tensor to get \Delta_ij
27c38c977aSJames Wright   KMUnpack(km_g_ij, g_ij);
28c38c977aSJames Wright   Diagonalize3(g_ij, evals, evecs, work_vector, SORT_DECREASING_EVALS, true, n_sweeps);
29c38c977aSJames Wright   for (int i = 0; i < 3; i++) evals[i] = 1 / sqrt(evals[i]);
30c38c977aSJames Wright   MatDiag3(evecs, evals, CEED_NOTRANSPOSE, evals_evecs);
31c38c977aSJames Wright   MatMat3(evecs, evals_evecs, CEED_TRANSPOSE, CEED_NOTRANSPOSE, A_ij);  // A_ij = E^T D E
32c38c977aSJames Wright 
33c38c977aSJames Wright   // Scale by delta to get anisotropy tensor
34c38c977aSJames Wright   *delta = sqrt(Dot3(evals, evals));
35c38c977aSJames Wright   ScaleN((CeedScalar *)A_ij, 1 / *delta, 9);
36c38c977aSJames Wright   // NOTE Need 2 factor to get physical element size (rather than projected onto [-1,1]^dim)
37c38c977aSJames Wright   // Should attempt to auto-determine this from the quadrature point coordinates in reference space
38c38c977aSJames Wright   *delta *= 2;
39c38c977aSJames Wright }
40c38c977aSJames Wright 
41c38c977aSJames Wright // @brief RHS for L^2 projection of anisotropic tensor and it's Frobenius norm
42c38c977aSJames Wright CEED_QFUNCTION(AnisotropyTensorProjection)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) {
43c38c977aSJames Wright   const CeedScalar(*q_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0];
44c38c977aSJames Wright   CeedScalar(*v)[CEED_Q_VLA]            = (CeedScalar(*)[CEED_Q_VLA])out[0];
45c38c977aSJames Wright 
46c38c977aSJames Wright   CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) {
47c38c977aSJames Wright     const CeedScalar wdetJ      = q_data[0][i];
48c38c977aSJames Wright     const CeedScalar dXdx[3][3] = {
49c38c977aSJames Wright         {q_data[1][i], q_data[2][i], q_data[3][i]},
50c38c977aSJames Wright         {q_data[4][i], q_data[5][i], q_data[6][i]},
51c38c977aSJames Wright         {q_data[7][i], q_data[8][i], q_data[9][i]}
52c38c977aSJames Wright     };
53c38c977aSJames Wright 
54c38c977aSJames Wright     CeedScalar km_g_ij[6] = {0.}, A_ij[3][3] = {{0.}}, km_A_ij[6], delta;
55c38c977aSJames Wright     KMMetricTensor(dXdx, km_g_ij);
56c38c977aSJames Wright     AnisotropyTensor(km_g_ij, A_ij, &delta, 15);
57c38c977aSJames Wright     KMPack(A_ij, km_A_ij);
58c38c977aSJames Wright 
59c38c977aSJames Wright     for (CeedInt j = 0; j < 6; j++) v[j][i] = wdetJ * km_A_ij[j];
60c38c977aSJames Wright     v[6][i] = wdetJ * delta;
61c38c977aSJames Wright   }
62c38c977aSJames Wright   return 0;
63c38c977aSJames Wright }
64c38c977aSJames Wright 
65*8dadcfbdSJames Wright // @brief Get anisotropic tensor and it's Frobenius norm at quadrature points
66*8dadcfbdSJames Wright CEED_QFUNCTION(AnisotropyTensorCollocate)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) {
67*8dadcfbdSJames Wright   const CeedScalar(*q_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0];
68*8dadcfbdSJames Wright   CeedScalar(*v)[CEED_Q_VLA]            = (CeedScalar(*)[CEED_Q_VLA])out[0];
69*8dadcfbdSJames Wright 
70*8dadcfbdSJames Wright   CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) {
71*8dadcfbdSJames Wright     const CeedScalar dXdx[3][3] = {
72*8dadcfbdSJames Wright         {q_data[1][i], q_data[2][i], q_data[3][i]},
73*8dadcfbdSJames Wright         {q_data[4][i], q_data[5][i], q_data[6][i]},
74*8dadcfbdSJames Wright         {q_data[7][i], q_data[8][i], q_data[9][i]}
75*8dadcfbdSJames Wright     };
76*8dadcfbdSJames Wright 
77*8dadcfbdSJames Wright     CeedScalar km_g_ij[6] = {0.}, A_ij[3][3] = {{0.}}, km_A_ij[6], delta;
78*8dadcfbdSJames Wright     KMMetricTensor(dXdx, km_g_ij);
79*8dadcfbdSJames Wright     AnisotropyTensor(km_g_ij, A_ij, &delta, 15);
80*8dadcfbdSJames Wright     KMPack(A_ij, km_A_ij);
81*8dadcfbdSJames Wright 
82*8dadcfbdSJames Wright     for (CeedInt j = 0; j < 6; j++) v[j][i] = km_A_ij[j];
83*8dadcfbdSJames Wright     v[6][i] = delta;
84*8dadcfbdSJames Wright   }
85*8dadcfbdSJames Wright   return 0;
86*8dadcfbdSJames Wright }
87*8dadcfbdSJames Wright 
88c38c977aSJames Wright #endif /* ifndef grid_anisotropy_tensor_h */
89