xref: /libCEED/examples/fluids/qfunctions/grid_anisotropy_tensor.h (revision d4cc18453651bd0f94c1a2e078b2646a92dafdcc)
1*9ba83ac0SJeremy L Thompson // Copyright (c) 2017-2026, 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
11c0b5abf0SJeremy L Thompson #include <ceed/types.h>
12052409adSJames Wright 
13052409adSJames Wright #include "utils.h"
14052409adSJames Wright #include "utils_eigensolver_jacobi.h"
15052409adSJames Wright 
16052409adSJames Wright // @brief Get Anisotropy tensor from xi_{i,j}
17052409adSJames 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)18052409adSJames Wright CEED_QFUNCTION_HELPER void AnisotropyTensor(const CeedScalar km_g_ij[6], CeedScalar A_ij[3][3], CeedScalar *delta, const CeedInt n_sweeps) {
19052409adSJames Wright   CeedScalar evals[3], evecs[3][3], evals_evecs[3][3] = {{0.}}, g_ij[3][3];
201b561cd6SJames Wright   CeedInt    work_vector[3];
21052409adSJames Wright 
22052409adSJames Wright   // Invert square root of metric tensor to get \Delta_ij
23052409adSJames Wright   KMUnpack(km_g_ij, g_ij);
24052409adSJames Wright   Diagonalize3(g_ij, evals, evecs, work_vector, SORT_DECREASING_EVALS, true, n_sweeps);
25052409adSJames Wright   for (int i = 0; i < 3; i++) evals[i] = 1 / sqrt(evals[i]);
26052409adSJames Wright   MatDiag3(evecs, evals, CEED_NOTRANSPOSE, evals_evecs);
27052409adSJames Wright   MatMat3(evecs, evals_evecs, CEED_TRANSPOSE, CEED_NOTRANSPOSE, A_ij);  // A_ij = E^T D E
28052409adSJames Wright 
29052409adSJames Wright   // Scale by delta to get anisotropy tensor
30052409adSJames Wright   *delta = sqrt(Dot3(evals, evals));
31052409adSJames Wright   ScaleN((CeedScalar *)A_ij, 1 / *delta, 9);
32052409adSJames Wright   // NOTE Need 2 factor to get physical element size (rather than projected onto [-1,1]^dim)
33052409adSJames Wright   // Should attempt to auto-determine this from the quadrature point coordinates in reference space
34052409adSJames Wright   *delta *= 2;
35052409adSJames Wright }
36052409adSJames Wright 
37052409adSJames 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)38052409adSJames Wright CEED_QFUNCTION(AnisotropyTensorProjection)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) {
39052409adSJames Wright   const CeedScalar(*q_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0];
40052409adSJames Wright   CeedScalar(*v)[CEED_Q_VLA]            = (CeedScalar(*)[CEED_Q_VLA])out[0];
41052409adSJames Wright 
42052409adSJames Wright   CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) {
43052409adSJames Wright     const CeedScalar wdetJ      = q_data[0][i];
44052409adSJames Wright     const CeedScalar dXdx[3][3] = {
45052409adSJames Wright         {q_data[1][i], q_data[2][i], q_data[3][i]},
46052409adSJames Wright         {q_data[4][i], q_data[5][i], q_data[6][i]},
47052409adSJames Wright         {q_data[7][i], q_data[8][i], q_data[9][i]}
48052409adSJames Wright     };
49052409adSJames Wright 
50052409adSJames Wright     CeedScalar km_g_ij[6] = {0.}, A_ij[3][3] = {{0.}}, km_A_ij[6], delta;
51052409adSJames Wright     KMMetricTensor(dXdx, km_g_ij);
52052409adSJames Wright     AnisotropyTensor(km_g_ij, A_ij, &delta, 15);
53052409adSJames Wright     KMPack(A_ij, km_A_ij);
54052409adSJames Wright 
55052409adSJames Wright     for (CeedInt j = 0; j < 6; j++) v[j][i] = wdetJ * km_A_ij[j];
56052409adSJames Wright     v[6][i] = wdetJ * delta;
57052409adSJames Wright   }
58052409adSJames Wright   return 0;
59052409adSJames Wright }
60052409adSJames Wright 
61900aec75SJames 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)62900aec75SJames Wright CEED_QFUNCTION(AnisotropyTensorCollocate)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) {
63900aec75SJames Wright   const CeedScalar(*q_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0];
64900aec75SJames Wright   CeedScalar(*v)[CEED_Q_VLA]            = (CeedScalar(*)[CEED_Q_VLA])out[0];
65900aec75SJames Wright 
66900aec75SJames Wright   CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) {
67900aec75SJames Wright     const CeedScalar dXdx[3][3] = {
68900aec75SJames Wright         {q_data[1][i], q_data[2][i], q_data[3][i]},
69900aec75SJames Wright         {q_data[4][i], q_data[5][i], q_data[6][i]},
70900aec75SJames Wright         {q_data[7][i], q_data[8][i], q_data[9][i]}
71900aec75SJames Wright     };
72900aec75SJames Wright 
73900aec75SJames Wright     CeedScalar km_g_ij[6] = {0.}, A_ij[3][3] = {{0.}}, km_A_ij[6], delta;
74900aec75SJames Wright     KMMetricTensor(dXdx, km_g_ij);
75900aec75SJames Wright     AnisotropyTensor(km_g_ij, A_ij, &delta, 15);
76900aec75SJames Wright     KMPack(A_ij, km_A_ij);
77900aec75SJames Wright 
78900aec75SJames Wright     for (CeedInt j = 0; j < 6; j++) v[j][i] = km_A_ij[j];
79900aec75SJames Wright     v[6][i] = delta;
80900aec75SJames Wright   }
81900aec75SJames Wright   return 0;
82900aec75SJames Wright }
83