Program Listing for File hllMHD.hpp

Return to documentation for file (hydro/MHDsolvers/hllMHD.hpp)

// ***********************************************************************************
// 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
// ***********************************************************************************

#ifndef HYDRO_MHDSOLVERS_HLLMHD_HPP_
#define HYDRO_MHDSOLVERS_HLLMHD_HPP_

#include "../idefix.hpp"
#include "slopeLimiter.hpp"
#include "fluxMHD.hpp"
#include "convertConsToPrimMHD.hpp"
#include "storeFlux.hpp"
#include "electroMotiveForce.hpp"

// Compute Riemann fluxes from states using HLL solver
template<const int DIR>
void Hydro::HllMHD() {
  idfx::pushRegion("Hydro::HLL_MHD");

  constexpr int ioffset = (DIR==IDIR) ? 1 : 0;
  constexpr int joffset = (DIR==JDIR) ? 1 : 0;
  constexpr int koffset = (DIR==KDIR) ? 1 : 0;

  // extension in perp to the direction of integration, as required by CT.
  constexpr int iextend = (DIR==IDIR) ? 0 : 1;
  #if DIMENSIONS > 1
    constexpr int jextend = (DIR==JDIR) ? 0 : 1;
  #else
    constexpr int jextend = 0;
  #endif
  #if DIMENSIONS > 2
    constexpr int kextend = (DIR==KDIR) ? 0 : 1;
  #else
    constexpr int kextend = 0;
  #endif

  IdefixArray4D<real> Vc = this->Vc;
  IdefixArray4D<real> Vs = this->Vs;
  IdefixArray4D<real> Flux = this->FluxRiemann;
  IdefixArray3D<real> cMax = this->cMax;
  IdefixArray3D<real> csIsoArr = this->isoSoundSpeedArray;

  HydroModuleStatus haveHall = this->hallStatus.status;
  IdefixArray4D<real> J = this->J;
  IdefixArray3D<real> xHallArr = this->xHall;
  IdefixArray1D<real> dx = data->dx[DIR];
  IdefixArray1D<real> dx2 = data->dx[JDIR];
  IdefixArray1D<real> x1 = data->x[IDIR];
  IdefixArray1D<real> rt = data->rt;
  IdefixArray1D<real> dmu = data->dmu;

  // References to required emf components
  IdefixArray3D<real> Eb;
  IdefixArray3D<real> Et;

  const ElectroMotiveForce::AveragingType emfAverage = emf.averaging;

  // Required by UCT_Contact
  IdefixArray3D<real> SV;

  // Required by UCT_HLLX
  IdefixArray3D<real> aL;
  IdefixArray3D<real> aR;
  IdefixArray3D<real> dL;
  IdefixArray3D<real> dR;

  real gamma = this->gamma;
  [[maybe_unused]] real xHConstant = this->xH;
  [[maybe_unused]] real gamma_m1=gamma-ONE_F;
  [[maybe_unused]] real csIso = this->isoSoundSpeed;
  [[maybe_unused]] HydroModuleStatus haveIsoCs = this->haveIsoSoundSpeed;

  SlopeLimiter<DIR,NVAR> slopeLim(Vc,data->dx[DIR],shockFlattening);

  // Define normal, tangent and bi-tanget indices
  // st and sb will be useful only when Hall is included
  real st = ONE_F, sb = ONE_F;

  switch(DIR) {
    case(IDIR):
      D_EXPAND(
                st = -ONE_F;  ,
                  ,

                sb = +ONE_F;  )

      Et = this->emf.ezi;
      Eb = this->emf.eyi;

      SV = this->emf.svx;

      aL = this->emf.axL;
      aR = this->emf.axR;

      dL = this->emf.dxL;
      dR = this->emf.dxR;

      break;
#if DIMENSIONS >= 2
    case(JDIR):
      D_EXPAND(
                st = +ONE_F;  ,
                              ,

                sb = -ONE_F;  )

      Et = this->emf.ezj;
      Eb = this->emf.exj;

      SV = this->emf.svy;

      aL = this->emf.ayL;
      aR = this->emf.ayR;

      dL = this->emf.dyL;
      dR = this->emf.dyR;

      break;
#endif
#if DIMENSIONS == 3
    case(KDIR):

      D_EXPAND(

                st = -ONE_F;  ,
                  ,
                sb = +ONE_F;  )

      Et = this->emf.eyk;
      Eb = this->emf.exk;

      SV = this->emf.svz;

      aL = this->emf.azL;
      aR = this->emf.azR;

      dL = this->emf.dzL;
      dR = this->emf.dzR;
      break;
#endif
    default:
      IDEFIX_ERROR("Wrong direction");
  }


  idefix_for("CalcRiemannFlux",
             data->beg[KDIR]-kextend,data->end[KDIR]+koffset+kextend,
             data->beg[JDIR]-jextend,data->end[JDIR]+joffset+jextend,
             data->beg[IDIR]-iextend,data->end[IDIR]+ioffset+iextend,
    KOKKOS_LAMBDA (int k, int j, int i) {
      // Init the directions (should be in the kernel for proper optimisation by the compilers)
      EXPAND( const int Xn = DIR+MX1;                    ,
              const int Xt = (DIR == IDIR ? MX2 : MX1);  ,
              const int Xb = (DIR == KDIR ? MX2 : MX3);  )

      EXPAND( const int BXn = DIR+BX1;                    ,
              const int BXt = (DIR == IDIR ? BX2 : BX1);  ,
              const int BXb = (DIR == KDIR ? BX2 : BX3);   )

      // Primitive variables
      real vL[NVAR];
      real vR[NVAR];

      // Conservative variables
      real uL[NVAR];
      real uR[NVAR];

      // Flux (left and right)
      real fluxL[NVAR];
      real fluxR[NVAR];

      // Signal speeds
      real cL, cR, cmax, c2Iso;

      c2Iso = ZERO_F;

      // 1-- Store the primitive variables on the left, right, and averaged states
      slopeLim.ExtrapolatePrimVar(i, j, k, vL, vR);
      vL[BXn] = Vs(DIR,k,j,i);
      vR[BXn] = vL[BXn];

      // 2-- Get the wave speed
      real gpr, b1, b2, b3, Btmag2, Bmag2;
      real xH;
#if HAVE_ENERGY
      gpr = gamma*vL[PRS];
#else
      if(haveIsoCs == UserDefFunction) {
        c2Iso = HALF_F*(csIsoArr(k,j,i)+csIsoArr(k-koffset,j-joffset,i-ioffset));
        c2Iso = c2Iso*c2Iso;
      } else {
        c2Iso = csIso*csIso;
      }

      gpr = c2Iso*vL[RHO];
#endif

      // -- get total field
      b1 = b2 = b3 = ZERO_F;
      EXPAND (b1 = vL[BXn];  ,
              b2 = vL[BXt];  ,
              b3 = vL[BXb];)

      Btmag2 = b2*b2 + b3*b3;
      Bmag2  = b1*b1 + Btmag2;

      cL = gpr - Bmag2;
      cL = gpr + Bmag2 + std::sqrt(cL*cL + FOUR_F*gpr*Btmag2);
      cL = std::sqrt(HALF_F*cL/vL[RHO]);

#if HAVE_ENERGY
      gpr = gamma*vR[PRS];
#else
      gpr = c2Iso*vR[RHO];
#endif

      // -- get total field
      b1 = b2 = b3 = ZERO_F;
      EXPAND (b1 = vR[BXn];  ,
              b2 = vR[BXt];  ,
              b3 = vR[BXb];)

      Btmag2 = b2*b2 + b3*b3;
      Bmag2  = b1*b1 + Btmag2;

      cR = gpr - Bmag2;
      cR = gpr + Bmag2 + std::sqrt(cR*cR + FOUR_F*gpr*Btmag2);
      cR = std::sqrt(HALF_F*cR/vR[RHO]);

      // 4.1
      real cminL = vL[Xn] - cL;
      real cmaxL = vL[Xn] + cL;

      real cminR = vR[Xn] - cR;
      real cmaxR = vR[Xn] + cR;

      real sl = FMIN(cminL, cminR);
      real sr = FMAX(cmaxL, cmaxR);

      // Signal speeds specific to B (different from the other ones when Hall is enabled)
      real SLb = sl;
      real SRb = sr;
      // if Hall is enabled, add whistler speed to the fan
      if(haveHall) {
        // Compute xHall
        if(haveHall==UserDefFunction) {
            if(DIR==IDIR) xH = AVERAGE_3D_X(xHallArr,k,j,i);
            if(DIR==JDIR) xH = AVERAGE_3D_Y(xHallArr,k,j,i);
            if(DIR==KDIR) xH = AVERAGE_3D_Z(xHallArr,k,j,i);
        } else {
          xH = xHConstant;
        }

        const int ig = ioffset*i + joffset*j + koffset*k;
        real dl = dx(ig);
        #if GEOMETRY == POLAR
            if(DIR==JDIR) dl = dl*x1(i);
        #elif GEOMETRY == SPHERICAL
            if(DIR==JDIR) dl = dl*rt(i);
            if(DIR==KDIR) dl = dl*rt(i)*dmu(j)/dx2(j);
        #endif

        real cw = FABS(xH) * std::sqrt(Bmag2) / dl;

        cminL = cminL - cw;
        cmaxL = cmaxL + cw;
        cminR = cminR - cw;
        cmaxR = cmaxR + cw;

        SLb = FMIN(cminL, cminR);
        SRb = FMAX(cmaxL,cmaxR);
      }

      cmax = FMAX(FABS(SLb), FABS(SRb));

      // 2-- Compute the conservative variables
      K_PrimToCons(uL, vL, gamma_m1);
      K_PrimToCons(uR, vR, gamma_m1);



#pragma unroll
      for(int nv = 0 ; nv < NVAR; nv++) {
        fluxL[nv] = uL[nv];
        fluxR[nv] = uR[nv];
      }



      // 3-- Compute the left and right fluxes
      K_Flux(fluxL, vL, fluxL, c2Iso, ARG_EXPAND(Xn, Xt, Xb), ARG_EXPAND(BXn, BXt, BXb));
      K_Flux(fluxR, vR, fluxR, c2Iso, ARG_EXPAND(Xn, Xt, Xb), ARG_EXPAND(BXn, BXt, BXb));

      // 4-- Compute the Hall flux
      if(haveHall) {
        [[maybe_unused]] int ip1, jp1, kp1;
        real Jx1, Jx2, Jx3;
        ip1=i+1;
        #if DIMENSIONS >=2
            jp1 = j+1;
        #else
            jp1=j;
        #endif
        #if DIMENSIONS == 3
            kp1 = k+1;
        #else
            kp1 = k;
        #endif

        if(DIR == IDIR) {
          Jx1 = AVERAGE_4D_XYZ(J, IDIR, kp1, jp1, i);
          Jx2 = AVERAGE_4D_Z(J, JDIR, kp1, j, i);
          Jx3 = AVERAGE_4D_Y(J, KDIR, k, jp1, i);
          #if COMPONENTS >= 2
          fluxL[BX2] += -xH* (  Jx1*uL[BX2] - Jx2*uL[BX1] );
          fluxR[BX2] += -xH* (  Jx1*uR[BX2] - Jx2*uR[BX1] );
          #endif
          #if COMPONENTS == 3
          fluxL[BX3] += -xH* (  Jx1*uL[BX3] - Jx3*uL[BX1] );
          fluxR[BX3] += -xH* (  Jx1*uR[BX3] - Jx3*uR[BX1] );
          #endif
        }
        if(DIR == JDIR) {
          Jx1 = AVERAGE_4D_Z(J, IDIR, kp1, j, i);
          Jx2 = AVERAGE_4D_XYZ(J, JDIR, kp1, j, ip1);
          Jx3 = AVERAGE_4D_X(J, KDIR, k, j, ip1);

          #if COMPONENTS >= 2
          fluxL[BX1] += -xH* (  Jx2*uL[BX1] - Jx1*uL[BX2] );
          fluxR[BX1] += -xH* (  Jx2*uR[BX1] - Jx1*uR[BX2] );
          #endif

          #if COMPONENTS == 3
          fluxL[BX3] += -xH* (  Jx2*uL[BX3] - Jx3*uL[BX2] );
          fluxR[BX3] += -xH* (  Jx2*uR[BX3] - Jx3*uR[BX2] );
          #endif
        }
        if(DIR == KDIR) {
          Jx1 = AVERAGE_4D_Y(J, IDIR, k, jp1, i);
          Jx2 = AVERAGE_4D_X(J, JDIR, k, j, ip1);
          Jx3 = AVERAGE_4D_XYZ(J, KDIR, k, jp1, ip1);

          fluxL[BX1] += -xH* (  Jx3*uL[BX1]  );
          fluxR[BX1] += -xH* (  Jx3*uR[BX1]  );

          #if COMPONENTS >= 2
          fluxL[BX2] += -xH* (  Jx3*uL[BX2]  );
          fluxR[BX2] += -xH* (  Jx3*uR[BX2]  );

          #if COMPONENTS==3
          fluxL[BX1] += -xH* (   - Jx1*uL[BX3] );
          fluxR[BX1] += -xH* (   - Jx1*uR[BX3] );

          fluxL[BX2] += -xH* (   - Jx2*uL[BX3] );
          fluxR[BX2] += -xH* (   - Jx2*uR[BX3] );
          #endif
          #endif
        }

        #if HAVE_ENERGY
          real JB = EXPAND(uL[BX1]*Jx1,  +uL[BX2]*Jx2, +uL[BX3]*Jx3 );
          real b2 = HALF_F*(EXPAND(uL[BX1]*uL[BX1], +uL[BX2]*uL[BX2], +uL[BX3]*uL[BX3]));
          if(DIR == IDIR) fluxL[ENG] += -xH* (Jx1*b2 - JB*uL[BX1]);
          #if COMPONENTS>=2
          if(DIR == JDIR) fluxL[ENG] += -xH* (Jx2*b2 - JB*uL[BX2]);
          #endif
          #if COMPONENTS >=3
          if(DIR == KDIR) fluxL[ENG] += -xH* (Jx3*b2 - JB*uL[BX3]);
          #endif

          JB = EXPAND(uR[BX1]*Jx1,  +uR[BX2]*Jx2, +uR[BX3]*Jx3 );
          b2 = HALF_F*(EXPAND(uR[BX1]*uR[BX1], +uR[BX2]*uR[BX2], +uR[BX3]*uR[BX3]));
          if(DIR == IDIR) fluxR[ENG] += -xH* (Jx1*b2 - JB*uR[BX1]);
          #if COMPONENTS>=2
          if(DIR == JDIR) fluxR[ENG] += -xH* (Jx2*b2 - JB*uR[BX2]);
          #endif
          #if COMPONENTS >=3
          if(DIR == KDIR) fluxR[ENG] += -xH* (Jx3*b2 - JB*uR[BX3]);
          #endif
      #endif
      }

      // 5-- Compute the flux from the left and right states
      if (sl > 0) {
        Flux(RHO,k,j,i) = fluxL[RHO];
        EXPAND( Flux(MX1,k,j,i) = fluxL[MX1];  ,
                Flux(MX2,k,j,i) = fluxL[MX2];  ,
                Flux(MX3,k,j,i) = fluxL[MX3];  )
      } else if (sr < 0) {
        Flux(RHO,k,j,i) = fluxR[RHO];
        EXPAND( Flux(MX1,k,j,i) = fluxR[MX1];  ,
                Flux(MX2,k,j,i) = fluxR[MX2];  ,
                Flux(MX3,k,j,i) = fluxR[MX3];  )
      } else {
        Flux(RHO,k,j,i) = (sl*sr*uR[RHO] - sl*sr*uL[RHO] + sr*fluxL[RHO] - sl*fluxR[RHO])
                          / (sr - sl);
        EXPAND( Flux(MX1,k,j,i) = (sl*sr*uR[MX1] - sl*sr*uL[MX1] + sr*fluxL[MX1] - sl*fluxR[MX1])
                                  / (sr - sl);  ,
                Flux(MX2,k,j,i) = (sl*sr*uR[MX2] - sl*sr*uL[MX2] + sr*fluxL[MX2] - sl*fluxR[MX2])
                                  / (sr - sl);  ,
                Flux(MX3,k,j,i) = (sl*sr*uR[MX3] - sl*sr*uL[MX3] + sr*fluxL[MX3] - sl*fluxR[MX3])
                                  / (sr - sl);  )
      }

      if (SLb > 0) {
#pragma unroll
        for (int nv = BX1 ; nv < NFLX; nv++) {
          Flux(nv,k,j,i) = fluxL[nv];
        }
      } else if (SRb < 0) {
#pragma unroll
        for (int nv = BX1 ; nv < NFLX; nv++) {
          Flux(nv,k,j,i) = fluxR[nv];
        }
      } else {
#pragma unroll
        for(int nv = BX1 ; nv < NFLX; nv++) {
          Flux(nv,k,j,i) = SLb*SRb*uR[nv] - SLb*SRb*uL[nv] + SRb*fluxL[nv] - SLb*fluxR[nv];
          Flux(nv,k,j,i) *= (1.0 / (SRb - SLb));
        }
      }


      //6-- Compute maximum wave speed for this sweep
      cMax(k,j,i) = cmax;

      // 7-- Store the flux in the emf components
      if (emfAverage==ElectroMotiveForce::arithmetic
                || emfAverage==ElectroMotiveForce::uct0) {
        K_StoreEMF<DIR>(i,j,k,st,sb,Flux,Et,Eb);
      } else if (emfAverage==ElectroMotiveForce::uct_contact) {
        K_StoreContact<DIR>(i,j,k,st,sb,Flux,Et,Eb,SV);
      } else if (emfAverage==ElectroMotiveForce::uct_hll) {
        K_StoreHLL<DIR>(i,j,k,st,sb,sl,sr,vL,vR,Et,Eb,aL,aR,dL,dR);
      }
      /* else if (emfAverage==ElectroMotiveForce::uct_hlld) {
        // We do not have the Alfven speed in the HLL solver
        K_StoreHLLD<DIR>(i,j,k,st,sb,c2Iso,SLb,SRb,vL,vR,uL,uR,Et,Eb,aL,aR,dL,dR);
      }*/
  });

  idfx::popRegion();
}

#endif // HYDRO_MHDSOLVERS_HLLMHD_HPP_