Program Listing for File viscosity.cpp
↰ Return to documentation for file (hydro/viscosity.cpp
)
// ***********************************************************************************
// Idefix MHD astrophysical code
// Copyright(C) 2020-2022 Geoffroy R. J. Lesur <geoffroy.lesur@univ-grenoble-alpes.fr>
// and other code contributors
// Licensed under CeCILL 2.1 License, see COPYING for more information
// ***********************************************************************************
// This source code is largely inspired from the viscous_flux of Pluto4.2
// ((c) P. Tzeferacos & A. Mignone)
#include <string>
#include "viscosity.hpp"
#include "dataBlock.hpp"
#define D_DX_I(q,n) (q(n,k,j,i) - q(n,k,j,i - 1))
#define D_DY_J(q,n) (q(n,k,j,i) - q(n,k,j - 1,i))
#define D_DZ_K(q,n) (q(n,k,j,i) - q(n,k - 1,j,i))
#define D_DY_I(q,n) ( 0.25*(q(n,k,j + 1,i) + q(n,k,j + 1,i - 1)) \
- 0.25*(q(n,k,j - 1,i) + q(n,k,j - 1,i - 1)))
#define D_DZ_I(q,n) ( 0.25*(q(n,k + 1,j,i) + q(n,k + 1,j,i - 1)) \
- 0.25*(q(n,k - 1,j,i) + q(n,k - 1,j,i - 1)))
#define D_DX_J(q,n) ( 0.25*(q(n,k,j,i + 1) + q(n,k,j - 1,i + 1)) \
- 0.25*(q(n,k,j,i - 1) + q(n,k,j - 1,i - 1)))
#define D_DZ_J(q,n) ( 0.25*(q(n,k + 1,j,i) + q(n,k + 1,j - 1,i)) \
- 0.25*(q(n,k - 1,j,i) + q(n,k - 1,j - 1,i)))
#define D_DX_K(q,n) ( 0.25*(q(n,k,j,i + 1) + q(n,k - 1,j,i + 1)) \
- 0.25*(q(n,k,j,i - 1) + q(n,k - 1,j,i - 1)))
#define D_DY_K(q,n) ( 0.25*(q(n,k,j + 1,i) + q(n,k - 1,j + 1,i)) \
- 0.25*(q(n,k,j - 1,i) + q(n,k - 1,j - 1,i)))
Viscosity::Viscosity() {
// Default constructor
}
void Viscosity::Init(Input &input, Grid &grid, Hydro *hydroin) {
idfx::pushRegion("Viscosity::Init");
// Save the parent hydro object
this->hydro = hydroin;
if(input.CheckEntry("Hydro","viscosity")>=0) {
if(input.Get<std::string>("Hydro","viscosity",1).compare("constant") == 0) {
this->eta1 = input.Get<real>("Hydro","viscosity",2);
// second viscosity?
this->eta2 = input.GetOrSet<real>("Hydro","viscosity",3, 0.0);
this->haveViscosity = Constant;
} else if(input.Get<std::string>("Hydro","viscosity",1).compare("userdef") == 0) {
this->haveViscosity = UserDefFunction;
this->eta1Arr = IdefixArray3D<real>("ViscosityEta1Array",hydro->data->np_tot[KDIR],
hydro->data->np_tot[JDIR],
hydro->data->np_tot[IDIR]);
this->eta2Arr = IdefixArray3D<real>("ViscosityEta1Array",hydro->data->np_tot[KDIR],
hydro->data->np_tot[JDIR],
hydro->data->np_tot[IDIR]);
} else {
IDEFIX_ERROR("Unknown viscosity definition in idefix.ini. "
"Can only be constant or userdef.");
}
} else {
IDEFIX_ERROR("I cannot create a Viscosity object without viscosity defined"
"in the .ini file");
}
// Allocate and fill arrays when needed
#if GEOMETRY != CARTESIAN
one_dmu = IdefixArray1D<real>("Viscosity_1dmu", hydro->data->np_tot[JDIR]);
IdefixArray1D<real> dmu = one_dmu;
IdefixArray1D<real> th = hydro->data->x[JDIR];
idefix_for("ViscousInitGeometry",1,hydro->data->np_tot[JDIR],
KOKKOS_LAMBDA(int j) {
real scrch = FABS((1.0-cos(th(j)))*(sin(th(j)) >= 0.0 ? 1.0:-1.0)
-(1.0-cos(th(j-1))) * (sin(th(j-1)) > 0.0 ? 1.0:-1.0));
dmu(j) = 1.0/scrch;
});
#endif
viscSrc = IdefixArray4D<real>("Viscosity_source", COMPONENTS, hydro->data->np_tot[KDIR],
hydro->data->np_tot[JDIR],
hydro->data->np_tot[IDIR]);
idfx::popRegion();
}
void Viscosity::ShowConfig() {
if(haveViscosity==Constant) {
idfx::cout << "Viscosity: ENEABLED with constant viscosity eta1="
<< this->eta1 << " and eta2=" << this->eta2 << " ."<< std::endl;
} else if (haveViscosity==UserDefFunction) {
idfx::cout << "Viscosity: ENABLED with user-defined viscosity function."
<< std::endl;
if(!viscousDiffusivityFunc) {
IDEFIX_ERROR("No viscosity function has been enrolled");
}
} else {
IDEFIX_ERROR("Unknown viscosity mode");
}
if(hydro->viscosityStatus.isExplicit) {
idfx::cout << "Viscosity: uses an explicit time integration." << std::endl;
} else if(hydro->viscosityStatus.isRKL) {
idfx::cout << "Viscosity: uses a Runge-Kutta-Legendre time integration."
<< std::endl;
} else {
IDEFIX_ERROR("Unknown time integrator for viscosity.");
}
}
void Viscosity::EnrollViscousDiffusivity(ViscousDiffusivityFunc myFunc) {
if(this->haveViscosity < UserDefFunction) {
IDEFIX_WARNING("Viscous diffusivity enrollment requires Hydro/Viscosity "
"to be set to userdef in .ini file");
}
this->viscousDiffusivityFunc = myFunc;
}
// This function computes the viscous flux and stores it in hydro->fluxRiemann
// (this avoids an extra array)
// Associated source terms, present in non-cartesian geometry are also computed
// and stored in this->viscSrc for later use (in calcRhs).
void Viscosity::AddViscousFlux(int dir, const real t) {
idfx::pushRegion("Viscosity::AddViscousFlux");
IdefixArray4D<real> Vc = this->hydro->Vc;
IdefixArray4D<real> Flux = this->hydro->FluxRiemann;
IdefixArray4D<real> viscSrc = this->viscSrc;
IdefixArray3D<real> dMax = this->hydro->dMax;
IdefixArray3D<real> eta1Arr = this->eta1Arr;
IdefixArray3D<real> eta2Arr = this->eta2Arr;
IdefixArray1D<real> one_dmu = this->one_dmu;
IdefixArray1D<real> x1 = this->hydro->data->x[IDIR];
IdefixArray1D<real> x2 = this->hydro->data->x[JDIR];
IdefixArray1D<real> x3 = this->hydro->data->x[KDIR];
IdefixArray1D<real> x1l = this->hydro->data->xl[IDIR];
IdefixArray1D<real> x2l = this->hydro->data->xl[JDIR];
IdefixArray1D<real> x3l = this->hydro->data->xl[KDIR];
IdefixArray1D<real> dx1 = this->hydro->data->dx[IDIR];
IdefixArray1D<real> dx2 = this->hydro->data->dx[JDIR];
IdefixArray1D<real> dx3 = this->hydro->data->dx[KDIR];
#if GEOMETRY == SPHERICAL
IdefixArray1D<real> sinx2 = this->hydro->data->sinx2;
IdefixArray1D<real> tanx2 = this->hydro->data->tanx2;
IdefixArray1D<real> sinx2m = this->hydro->data->sinx2m;
IdefixArray1D<real> tanx2m = this->hydro->data->tanx2m;
#endif
HydroModuleStatus haveViscosity = this->haveViscosity;
// Compute viscosity if needed
if(haveViscosity == UserDefFunction && dir == IDIR) {
if(viscousDiffusivityFunc) {
viscousDiffusivityFunc(*this->hydro->data, t, eta1Arr, eta2Arr);
} else {
IDEFIX_ERROR("No user-defined viscosity function has been enrolled");
}
}
int ibeg, iend, jbeg, jend, kbeg, kend;
ibeg = this->hydro->data->beg[IDIR];
iend = this->hydro->data->end[IDIR];
jbeg = this->hydro->data->beg[JDIR];
jend = this->hydro->data->end[JDIR];
kbeg = this->hydro->data->beg[KDIR];
kend = this->hydro->data->end[KDIR];
real eta1Constant = this->eta1;
real eta2Constant = this->eta2;
// IDIR sweep //
if(dir==IDIR) {
iend++;
idefix_for("ViscousFluxIDIR",kbeg, kend, jbeg, jend, ibeg, iend,
KOKKOS_LAMBDA (int k, int j, int i) {
[[maybe_unused]] real tau_xx, tau_xy, tau_xz;
[[maybe_unused]] real tau_yy, tau_yz;
[[maybe_unused]] real tau_zz;
[[maybe_unused]] real dVxi, dVxj, dVxk;
[[maybe_unused]] real dVyi, dVyj, dVyk;
[[maybe_unused]] real dVzi, dVzj, dVzk;
[[maybe_unused]] real divV;
tau_xx = tau_xy = tau_xz = ZERO_F;
tau_yy = tau_yz = ZERO_F;
tau_zz = ZERO_F;
dVxi = dVxj = dVxk = ZERO_F;
dVyi = dVyj = dVyk = ZERO_F;
dVzi = dVzj = dVzk = ZERO_F;
real eta1, eta2;
[[maybe_unused]] real etaC1, etaC2;
if(haveViscosity == UserDefFunction) {
etaC1 = eta1Arr(k,j ,i);
eta1 = HALF_F*(eta1Arr(k,j,i-1)+eta1Arr(k,j,i));
etaC2 = eta2Arr(k,j,i);
eta2 = HALF_F*(eta2Arr(k,j,i-1)+eta2Arr(k,j,i));
} else {
etaC1 = eta1 = eta1Constant;
etaC2 = eta2 = eta2Constant;
}
EXPAND( dVxi = D_DX_I(Vc,VX1)/dx1(i); ,
dVyi = D_DX_I(Vc,VX2)/dx1(i); ,
dVzi = D_DX_I(Vc,VX3)/dx1(i); )
#if DIMENSIONS >= 2
EXPAND( dVxj = D_DY_I(Vc,VX1)/dx2(j); ,
dVyj = D_DY_I(Vc,VX2)/dx2(j); ,
dVzj = D_DY_I(Vc,VX3)/dx2(j); )
#if DIMENSIONS == 3
dVxk = D_DZ_I(Vc,VX1)/dx3(k);
dVyk = D_DZ_I(Vc,VX2)/dx3(k);
dVzk = D_DZ_I(Vc,VX3)/dx3(k);
#endif
#endif
#if GEOMETRY == CARTESIAN
divV = D_EXPAND(dVxi, + dVyj, + dVzk);
tau_xx = 2.0*eta1*dVxi + (eta2 - (2.0/3.0)*eta1)*divV;
tau_xy = eta1*(dVxj + dVyi);
tau_xz = eta1*(dVxk + dVzi);
// No source term in cartesian geometry
#endif // GEOMETRY == CARTESIAN
#if GEOMETRY == CYLINDRICAL
real one_dVr = x1(i)*FABS(x1(i))-x1(i-1)*FABS(x1(i-1));
real drrVr = (Vc(VX1,k,j,i)*x1(i)- Vc(VX1,k,j,i-1)*FABS(x1(i-1)))*one_dVr;
divV = D_EXPAND( drrVr, + dVyj, +ZERO_F);
tau_xx = 2.0*eta1*drrVr + (eta2 - (2.0/3.0)*eta1)*divV;
tau_xy = eta1*(dVxj + dVyi);
SELECT( ,
,
tau_xz = eta1*0.5*(x1(i)+x1(i-1))/dx1(i)
*(Vc(VX3,k,j,i)/x1(i) - Vc(VX3,k,j,i-1)/x1(i-1)); )
tau_xz = eta1*(dVxk + dVzi);
// compute tau_zz at cell center
divV = D_EXPAND( 0.5*(Vc(VX1,k,j,i+1) - Vc(VX1,k,j,i-1))/dx1(i) + Vc(VX1,k,j,i)/x1(i),
+0.5*(Vc(VX2,k,j+1,i) - Vc(VX2,k,j-1,i))/dx2(j) ,
);
tau_zz = 2.0*etaC1*Vc(VX1,k,j,i)/x1(i) + (etaC2 - (2.0/3.0)*etaC1)*divV;
EXPAND( viscSrc(IDIR,k,j,i) = -tau_zz/x1(i); ,
viscSrc(JDIR,k,j,i) = ZERO_F; ,
viscSrc(KDIR,k,j,i) = ZERO_F; )
#endif // GEOMETRY == CYLINDRICAL
#if GEOMETRY == POLAR
real vx1i = 0.5*(Vc(VX1,k,j,i-1)+Vc(VX1,k,j,i));
#if COMPONENTS >= 2
real vx2i = 0.5*(Vc(VX2,k,j,i-1)+Vc(VX2,k,j,i));
#endif
divV = D_EXPAND(vx1i/x1l(i) + dVxi, + dVyj/x1l(i), + dVzk);
tau_xx = 2.0*eta1*dVxi + (eta2 - (2.0/3.0)*eta1)*divV;
#if DIMENSIONS == 1
tau_xy = eta1*dVyi;
#else
tau_xy = eta1*(dVxj/x1l(i) + dVyi - vx2i/x1l(i));
#endif
tau_xz = eta1*(dVxk + dVzi);
// compute tau_yy at cell center
divV = D_EXPAND( 0.5*(Vc(VX1,k,j,i+1) - Vc(VX1,k,j,i-1))/dx1(i) + Vc(VX1,k,j,i)/x1(i),
+0.5*(Vc(VX2,k,j+1,i) - Vc(VX2,k,j-1,i))/dx2(j)/x1(i) ,
+0.5*(Vc(VX3,k+1,j,i) - Vc(VX3,k-1,j,i))/dx3(k) );
#if DIMENSIONS == 1
tau_yy = 2.0*etaC1*( Vc(VX1,k,j,i)/x1(i)) + (etaC2 - (2.0/3.0)*etaC1)*divV;
#else
tau_yy = 2.0*etaC1*( 0.5*(Vc(VX2,k,j+1,i) - Vc(VX2,k,j-1,i))/dx2(j)/x1(i)
+ Vc(VX1,k,j,i)/x1(i))
+ (etaC2 - (2.0/3.0)*etaC1)*divV;
#endif
EXPAND( viscSrc(IDIR,k,j,i) = -tau_yy/x1(i); ,
viscSrc(JDIR,k,j,i) = ZERO_F; ,
viscSrc(KDIR,k,j,i) = ZERO_F; )
#endif // GEOMETRY == POLAR
#if GEOMETRY == SPHERICAL
real tan_1 = tanx2(j);
real s_1 = sinx2(j);
// Trick to ensure that the axis does not lead to Nans
if(FABS(tan_1) < SMALL_NUMBER) {
tan_1 = ZERO_F;
} else {
tan_1 = ONE_F/tan_1;
}
if(FABS(s_1) < SMALL_NUMBER) {
s_1 = ZERO_F;
} else {
s_1 = ONE_F/s_1;
}
real vx1i = 0.5*(Vc(VX1,k,j,i-1)+Vc(VX1,k,j,i));
#if COMPONENTS >= 2
real vx2i = 0.5*(Vc(VX2,k,j,i-1)+Vc(VX2,k,j,i));
#endif
divV = D_EXPAND(2.0*vx1i/x1l(i) + dVxi,
+ dVyj/x1l(i) + tan_1*vx2i/x1l(i),
+ dVzk/x1l(i)*s_1 );
tau_xx = 2.0*eta1*dVxi + (eta2 - (2.0/3.0)*eta1)*divV;
tau_xy = dVxj/x1l(i) + dVyi;
#if COMPONENTS >= 2
tau_xy += - vx2i/x1l(i);
#endif
tau_xy *= eta1;
tau_xz = dVxk*s_1/x1l(i) + dVzi;
#if COMPONENTS == 3
tau_xz += - 0.5*(Vc(VX3,k,j,i-1)+Vc(VX3,k,j,i))/x1l(i);
#endif
tau_xz *= eta1;
// Compute tau_yy and tau_zz at cell center
divV = D_EXPAND( 0.5*(Vc(VX1,k,j,i+1) - Vc(VX1,k,j,i-1))/dx1(i) + 2.0*Vc(VX1,k,j,i)/x1(i),
+0.5*(Vc(VX2,k,j+1,i) - Vc(VX2,k,j-1,i))/dx2(j)/x1(i)
+Vc(VX2,k,j,i)/x1(i)*tan_1 ,
+0.5*(Vc(VX3,k+1,j,i) - Vc(VX3,k-1,j,i))/dx3(k)/x1(i)*s_1 );
tau_yy = Vc(VX1,k,j,i)/x1(i);
#if DIMENSIONS >= 2
tau_yy += 0.5*(Vc(VX2,k,j+1,i) - Vc(VX2,k,j-1,i))/dx2(j)/x1(i);
#endif
tau_yy = 2.0*etaC1*tau_yy + (etaC2-2.0/3.0*etaC1)*divV;
tau_zz = Vc(VX1,k,j,i)/x1(i);
#if COMPONENTS >= 2
tau_zz += Vc(VX2,k,j,i)*tan_1/x1(i);
#endif
#if DIMENSIONS == 3
tau_zz += 0.5*(Vc(VX3,k+1,j,i) - Vc(VX3,k-1,j,i))/dx3(k)/x1(i)*s_1;
#endif
tau_zz = 2.0*etaC1*tau_zz + (etaC2-2.0/3.0*etaC1)*divV;
EXPAND( viscSrc(IDIR,k,j,i) = -(tau_yy + tau_zz)/x1(i); ,
viscSrc(JDIR,k,j,i) = ZERO_F; ,
viscSrc(KDIR,k,j,i) = ZERO_F; )
#endif // GEOMETRY == SPHERICAL
// Update flux with the stress tensor
EXPAND( Flux(MX1, k, j, i) -= tau_xx; ,
Flux(MX2, k, j, i) -= tau_xy; ,
Flux(MX3, k, j, i) -= tau_xz; )
#if HAVE_ENERGY
Flux(ENG, k, j, i) -= EXPAND( 0.5*(Vc(VX1,k,j,i) + Vc(VX1,k,j,i-1))*tau_xx ,
+ 0.5*(Vc(VX2,k,j,i) + Vc(VX2,k,j,i-1))*tau_xy ,
+ 0.5*(Vc(VX3,k,j,i) + Vc(VX3,k,j,i-1))*tau_xz);
#endif
real locdmax = (FMAX(eta1,eta2))/(0.5*(Vc(RHO,k,j,i)+Vc(RHO,k,j,i-1)));
dMax(k,j,i) = FMAX(dMax(k,j,i),locdmax);
});
} else if(dir==JDIR) {
// JDIR sweep //
jend++;
idefix_for("ViscousFluxJDIR",kbeg, kend, jbeg, jend, ibeg, iend,
KOKKOS_LAMBDA (int k, int j, int i) {
[[maybe_unused]] real tau_xx, tau_xy, tau_xz;
[[maybe_unused]] real tau_yy, tau_yz;
[[maybe_unused]] real tau_zz;
[[maybe_unused]] real dVxi, dVxj, dVxk;
[[maybe_unused]] real dVyi, dVyj, dVyk;
[[maybe_unused]] real dVzi, dVzj, dVzk;
real divV;
tau_xx = tau_xy = tau_xz = ZERO_F;
tau_yy = tau_yz = ZERO_F;
tau_zz = ZERO_F;
dVxi = dVxj = dVxk = ZERO_F;
dVyi = dVyj = dVyk = ZERO_F;
dVzi = dVzj = dVzk = ZERO_F;
real eta1, eta2;
[[maybe_unused]] real etaC1, etaC2;
if(haveViscosity == UserDefFunction) {
etaC1 = eta1Arr(k,j,i);
eta1 = HALF_F*(eta1Arr(k,j-1,i)+eta1Arr(k,j,i));
etaC2 = eta2Arr(k,j,i);
eta2 = HALF_F*(eta2Arr(k,j-1,i)+eta2Arr(k,j,i));
} else {
etaC1 = eta1 = eta1Constant;
etaC2 = eta2 = eta2Constant;
}
EXPAND( dVxi = D_DX_J(Vc,VX1)/dx1(i); ,
dVyi = D_DX_J(Vc,VX2)/dx1(i); ,
dVzi = D_DX_J(Vc,VX3)/dx1(i); )
EXPAND( dVxj = D_DY_J(Vc,VX1)/dx2(j); ,
dVyj = D_DY_J(Vc,VX2)/dx2(j); ,
dVzj = D_DY_J(Vc,VX3)/dx2(j); )
#if DIMENSIONS == 3
dVxk = D_DZ_J(Vc,VX1)/dx3(k);
dVyk = D_DZ_J(Vc,VX2)/dx3(k);
dVzk = D_DZ_J(Vc,VX3)/dx3(k);
#endif
#if GEOMETRY == CARTESIAN
divV = D_EXPAND(dVxi, + dVyj, + dVzk);
tau_xy = eta1*(dVxj+dVyi);
tau_yy = 2.0*eta1*dVyj + (eta2 - (2.0/3.0)*eta1)*divV;
tau_yz = eta1*(dVzj + dVyk);
#endif // GEOMETRY == CARTESIAN
#if GEOMETRY == CYLINDRICAL
real vx1i = 0.5*(Vc(VX1,k,j-1,i)+Vc(VX1,k,j,i));
divV = D_EXPAND(vx1i/x1(i) + dVxi, + dVyj, +0.0);
tau_xy = eta1*(dVxj+dVyi);
tau_yy = 2.0*eta1*dVyj + (eta2 - (2.0/3.0)*eta1)*divV;
#if DIMENSIONS == 3
tau_yz = eta1*(dVyk);
#endif
// no source term
EXPAND( viscSrc(IDIR,k,j,i) = ZERO_F; ,
viscSrc(JDIR,k,j,i) = ZERO_F; ,
viscSrc(KDIR,k,j,i) = ZERO_F; )
#endif // GEOMETRY == CYLINDRICAL
#if GEOMETRY == POLAR
real vx1i = 0.5*(Vc(VX1,k,j-1,i)+Vc(VX1,k,j,i));
real vx2i = 0.5*(Vc(VX2,k,j-1,i)+Vc(VX2,k,j,i));
divV = D_EXPAND(vx1i/x1(i) + dVxi, + dVyj/x1(i), + dVzk);
tau_xy = eta1*(dVxj/x1(i)+dVyi - vx2i/x1(i));
tau_yy = 2.0*eta1*(dVyj/x1(i) + vx1i/x1(i)) + (eta2 - (2.0/3.0)*eta1)*divV;
tau_yz = eta1*(dVzj/x1(i) + dVyk);
// no source term
EXPAND( viscSrc(IDIR,k,j,i) = ZERO_F; ,
viscSrc(JDIR,k,j,i) = ZERO_F; ,
viscSrc(KDIR,k,j,i) = ZERO_F; )
#endif
#if GEOMETRY == SPHERICAL
real tan_1 = tanx2m(j);
real s_1 = sinx2m(j);
// Trick to ensure that the axis does not lead to Nans
if(FABS(tan_1) < SMALL_NUMBER) {
tan_1 = ZERO_F;
} else {
tan_1 = ONE_F/tan_1;
}
if(FABS(s_1) < SMALL_NUMBER) {
s_1 = ZERO_F;
} else {
s_1 = ONE_F/s_1;
}
real vx1i = 0.5*(Vc(VX1,k,j-1,i)+Vc(VX1,k,j,i));
real vx2i = 0.5*(Vc(VX2,k,j-1,i)+Vc(VX2,k,j,i));
divV = D_EXPAND( 2.0*vx1i/x1(i) + dVxi,
+ (sinx2(j)*Vc(VX2,k,j,i) - FABS(sinx2(j-1))*Vc(VX2,k,j-1,i))/x1(i)
*one_dmu(j) ,
+ dVzk/x1(i)*s_1 );
// tau_xy is initially cell centered since it is involved in the source term
tau_xy = etaC1*( 0.5*(Vc(VX1,k,j+1,i)-Vc(VX1,k,j-1,i))/x1(i)/dx2(j)
- Vc(VX2,k,j,i)/x1(i));
tau_yy = 2.0*eta1*(dVyj/x1(i) + vx1i/x1(i)) + (eta2 - (2.0/3.0)*eta1)*divV;
tau_yz = dVzj/x1(i);
#if COMPONENTS == 3
tau_yz += -tan_1/x1(i)*0.5*(Vc(VX3,k,j-1,i)+Vc(VX3,k,j,i));
#endif
#if DIMENSIONS == 3
tau_yz += s_1/x1(i)*dVyk;
#endif
tau_yz *= eta1;
// Compute cell-centered divV & sources terms
tan_1 = tanx2(j);
s_1 = sinx2(j);
// Trick to ensure that the axis does not lead to Nans
if(FABS(tan_1) < SMALL_NUMBER) {
tan_1 = ZERO_F;
} else {
tan_1 = ONE_F/tan_1;
}
if(FABS(s_1) < SMALL_NUMBER) {
s_1 = ZERO_F;
} else {
s_1 = ONE_F/s_1;
}
divV = D_EXPAND( 0.5*(Vc(VX1,k,j,i+1) - Vc(VX1,k,j,i-1))/dx1(i) + 2.0*Vc(VX1,k,j,i)/x1(i),
+0.5*(Vc(VX2,k,j+1,i) - Vc(VX2,k,j-1,i))/dx2(j)/x1(i)
+Vc(VX2,k,j,i)/x1(i)*tan_1 ,
+0.5*(Vc(VX3,k+1,j,i) - Vc(VX3,k-1,j,i))/dx3(k)/x1(i)*s_1 );
tau_zz = Vc(VX1,k,j,i)/x1(i);
#if COMPONENTS >= 2
tau_zz += Vc(VX2,k,j,i)/x1(i)*tan_1;
#endif
#if DIMENSIONS == 3
tau_zz += 0.5*(Vc(VX3,k+1,j,i) - Vc(VX3,k-1,j,i))/dx3(k)/x1(i)*s_1;
#endif
tau_zz = 2*eta1*tau_zz + (eta2-2.0/3.0*eta1)*divV;
EXPAND( viscSrc(IDIR,k,j,i) = ZERO_F; ,
viscSrc(JDIR,k,j,i) = (tau_xy - tau_zz*tan_1)/x1(i); ,
viscSrc(KDIR,k,j,i) = ZERO_F; )
// New tau_xy, this time face-centered
tau_xy = eta1*(dVxj/x1(i)+dVyi - vx2i/x1(i));
#endif
// Update flux with the stress tensor
EXPAND( Flux(MX1, k, j, i) -= tau_xy; ,
Flux(MX2, k, j, i) -= tau_yy; ,
Flux(MX3, k, j, i) -= tau_yz; )
#if HAVE_ENERGY
Flux(ENG, k, j, i) -= EXPAND( 0.5*(Vc(VX1,k,j,i) + Vc(VX1,k,j-1,i))*tau_xy ,
+ 0.5*(Vc(VX2,k,j,i) + Vc(VX2,k,j-1,i))*tau_yy ,
+ 0.5*(Vc(VX3,k,j,i) + Vc(VX3,k,j-1,i))*tau_yz);
#endif
real locdmax = (FMAX(eta1,eta2))/(0.5*(Vc(RHO,k,j,i)+Vc(RHO,k,j-1,i)));
dMax(k,j,i) = FMAX(dMax(k,j,i),locdmax);
});
} else if(dir==KDIR) {
kend++;
// KDIR sweep //
idefix_for("ViscousFluxKDIR",kbeg, kend, jbeg, jend, ibeg, iend,
KOKKOS_LAMBDA (int k, int j, int i) {
[[maybe_unused]] real tau_xx, tau_xy, tau_xz;
[[maybe_unused]] real tau_yy, tau_yz;
[[maybe_unused]] real tau_zz;
[[maybe_unused]] real dVxi, dVxj, dVxk;
[[maybe_unused]] real dVyi, dVyj, dVyk;
[[maybe_unused]] real dVzi, dVzj, dVzk;
real divV;
tau_xx = tau_xy = tau_xz = ZERO_F;
tau_yy = tau_yz = ZERO_F;
tau_zz = ZERO_F;
dVxi = dVxj = dVxk = ZERO_F;
dVyi = dVyj = dVyk = ZERO_F;
dVzi = dVzj = dVzk = ZERO_F;
real eta1, eta2;
[[maybe_unused]] real etaC1, etaC2;
if(haveViscosity == UserDefFunction) {
etaC1 = eta1Arr(k,j,i);
eta1 = HALF_F*(eta1Arr(k-1,j,i)+eta1Arr(k,j,i));
etaC2 = eta2Arr(k,j,i);
eta2 = HALF_F*(eta2Arr(k-1,j,i)+eta2Arr(k,j,i));
} else {
etaC1 = eta1 = eta1Constant;
etaC2 = eta2 = eta2Constant;
}
dVxi = D_DX_K(Vc,VX1)/dx1(i);
dVyi = D_DX_K(Vc,VX2)/dx1(i);
dVzi = D_DX_K(Vc,VX3)/dx1(i);
dVxj = D_DY_K(Vc,VX1)/dx2(j);
dVyj = D_DY_K(Vc,VX2)/dx2(j);
dVzj = D_DY_K(Vc,VX3)/dx2(j);
dVxk = D_DZ_K(Vc,VX1)/dx3(k);
dVyk = D_DZ_K(Vc,VX2)/dx3(k);
dVzk = D_DZ_K(Vc,VX3)/dx3(k);
#if GEOMETRY == CARTESIAN
divV = dVxi + dVyj + dVzk;
tau_xz = eta1*(dVxk+dVzi);
tau_yz = eta1*(dVyk+dVzj);
tau_zz = 2.0*eta1*dVzk + (eta2 - (2.0/3.0)*eta1)*divV;
#endif // GEOMETRY == CARTESIAN
#if GEOMETRY == POLAR
real vx1i = 0.5*(Vc(VX1,k-1,j,i)+Vc(VX1,k,j,i));
divV = vx1i/x1(i) + dVxi + dVyj/x1(i) + dVzk;
tau_xz = eta1*(dVxk+dVzi);
tau_yz = eta1*(dVyk+dVzj);
tau_zz = 2.0*eta1*dVzk + (eta2 - (2.0/3.0)*eta1)*divV;
viscSrc(IDIR,k,j,i) = ZERO_F;
viscSrc(JDIR,k,j,i) = ZERO_F;
viscSrc(KDIR,k,j,i) = ZERO_F;
#endif // GEOMETRY == POLAR
#if GEOMETRY == SPHERICAL
real tan_1 = tanx2(j);
real s_1 = sinx2(j);
// Trick to ensure that the axis does not lead to Nans
if(FABS(tan_1) < SMALL_NUMBER) {
tan_1 = ZERO_F;
} else {
tan_1 = ONE_F/tan_1;
}
if(FABS(s_1) < SMALL_NUMBER) {
s_1 = ZERO_F;
} else {
s_1 = ONE_F/s_1;
}
real vx1i = 0.5*(Vc(VX1,k-1,j,i)+Vc(VX1,k,j,i));
real vx2i = 0.5*(Vc(VX2,k-1,j,i)+Vc(VX2,k,j,i));
real vx3i = 0.5*(Vc(VX3,k-1,j,i)+Vc(VX3,k,j,i));
divV = 2.0*vx1i/x1(i) + dVxi + dVyj/x1(i) + tan_1*vx2i/x1(i) + dVzk/x1(i)*s_1;
tau_xz = eta1*(dVxk*s_1/x1(i) + dVzi - vx3i/x1(i));
tau_yz = eta1*(dVyk*s_1/x1(i) + dVzj/x1(i) - vx3i*tan_1/x1(i));
tau_zz = 2.0*eta1*( dVzk*s_1/x1(i) + vx1i/x1(i) + vx2i*tan_1/x1(i))
+ (eta2 - (2.0/3.0)*eta1)*divV;
viscSrc(IDIR,k,j,i) = ZERO_F;
viscSrc(JDIR,k,j,i) = ZERO_F;
viscSrc(KDIR,k,j,i) = ZERO_F;
#endif //GEOMETRY == SPHERICAL
// Update flux with the stress tensor
EXPAND( Flux(MX1, k, j, i) -= tau_xz; ,
Flux(MX2, k, j, i) -= tau_yz; ,
Flux(MX3, k, j, i) -= tau_zz; )
#if HAVE_ENERGY
Flux(ENG, k, j, i) -= EXPAND( 0.5*(Vc(VX1,k,j,i) + Vc(VX1,k-1,j,i))*tau_xz ,
+ 0.5*(Vc(VX2,k,j,i) + Vc(VX2,k-1,j,i))*tau_yz ,
+ 0.5*(Vc(VX3,k,j,i) + Vc(VX3,k-1,j,i))*tau_zz);
#endif
real locdmax = (FMAX(eta1,eta2))/(0.5*(Vc(RHO,k,j,i)+Vc(RHO,k-1,j,i)));
dMax(k,j,i) = FMAX(dMax(k,j,i),locdmax);;
});
}
idfx::popRegion();
}