Program Listing for File addNonIdealMHDFlux.hpp

Return to documentation for file (hydro/addNonIdealMHDFlux.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_ADDNONIDEALMHDFLUX_HPP_
#define HYDRO_ADDNONIDEALMHDFLUX_HPP_

#include "hydro.hpp"
#include "dataBlock.hpp"

// Compute parabolic fluxes
template <int dir>
void Hydro::AddNonIdealMHDFlux(const real t) {
  idfx::pushRegion("Hydro::addNonIdealMHDFlux");

#if MHD == YES

  int ioffset,joffset,koffset;

  IdefixArray4D<real> Flux = this->FluxRiemann;
  IdefixArray4D<real> Vc   = this->Vc;
  IdefixArray4D<real> Vs   = this->Vs;
  IdefixArray3D<real> dMax = this->dMax;
  IdefixArray4D<real> J    = this->J;
  IdefixArray3D<real> etaArr = this->etaOhmic;
  IdefixArray3D<real> xAmbiArr = this->xAmbipolar;

  // these two are required to ensure that the type is captured by KOKKOS_LAMBDA
  HydroModuleStatus resistivity = resistivityStatus.status;
  HydroModuleStatus ambipolar   = ambipolarStatus.status;

  bool haveResistivity{false};
  bool haveAmbipolar{false};

  if(data->rklCycle) {
    haveResistivity = resistivityStatus.isRKL;
    haveAmbipolar = ambipolarStatus.isRKL;
  } else {
    haveResistivity = resistivityStatus.isExplicit;
    haveAmbipolar = ambipolarStatus.isExplicit;
  }

  real etaConstant = this->etaO;
  real xAConstant  = this->xA;

  ioffset=joffset=koffset=0;

  switch(dir) {
    case(IDIR):
      ioffset = 1;
      break;
    case(JDIR):
      joffset = 1;
      break;
    case(KDIR):
      koffset=1;
      break;
    default:
      IDEFIX_ERROR("Wrong direction");
  }

  // Load the diffusivity array when required
  if(resistivity == UserDefFunction && dir == IDIR) {
    if(ohmicDiffusivityFunc)
      ohmicDiffusivityFunc(*data, t, etaArr);
    else
      IDEFIX_ERROR("No user-defined Ohmic diffusivity function has been enrolled");
  }

  if(ambipolar == UserDefFunction && dir == IDIR) {
    if(ambipolarDiffusivityFunc)
      ambipolarDiffusivityFunc(*data, t, xAmbiArr);
    else
      IDEFIX_ERROR("No user-defined ambipolar diffusivity function has been enrolled");
  }

  // Note the flux follows the same sign convention as the hyperbolic flux
  // HEnce signs are reversed compared to the parabolic fluxes found in Pluto 4.3
  idefix_for("CalcParabolicFlux",
             data->beg[KDIR],data->end[KDIR]+koffset,
             data->beg[JDIR],data->end[JDIR]+joffset,
             data->beg[IDIR],data->end[IDIR]+ioffset,
    KOKKOS_LAMBDA (int k, int j, int i) {
      real Jx1, Jx2, Jx3;
      real Bx1, Bx2, Bx3;
      real eta,xA;
      real locdmax = 0.0;

      int ip1;  // Offset indieces
      [[maybe_unused]] int jp1, kp1;
      ip1=i+1;
#if DIMENSIONS >=2
      jp1 = j+1;
#else
      jp1=j;
#endif
#if DIMENSIONS == 3
      kp1 = k+1;
#else
      kp1 = k;
#endif


      Jx1=Jx2=Jx3=ZERO_F;

      if(resistivity == Constant)
        eta = etaConstant;

      if(ambipolar == Constant)
        xA = xAConstant;

      if(dir==IDIR) {
        EXPAND(                                              ,
                Jx3 = AVERAGE_4D_Y(J, KDIR, k, jp1, i);      ,
                Jx2 = AVERAGE_4D_Z(J, JDIR, kp1, j, i);
                Jx1 = AVERAGE_4D_XYZ(J, IDIR, kp1, jp1, i);  )

        EXPAND( Bx1 = Vs(BX1s,k,j,i);                             ,
                Bx2 = HALF_F*( Vc(BX2,k,j,i-1) + Vc(BX2,k,j,i));  ,
                Bx3 = HALF_F*( Vc(BX3,k,j,i-1) + Vc(BX3,k,j,i));  )
        if(haveResistivity) {
          if(resistivity == UserDefFunction)
            eta = AVERAGE_3D_X(etaArr,k,j,i);

          // Do not update BX2 if BX2s is defined
          #if (DIMENSIONS < 2 && COMPONENTS >= 2)
            Flux(BX2,k,j,i) += - eta * Jx3;
          #endif
          #if (DIMENSIONS < 3 && COMPONENTS == 3)
            Flux(BX3,k,j,i) +=   eta * Jx2;
          #endif

          #if HAVE_ENERGY
            Flux(ENG,k,j,i) += EXPAND( ZERO_F            ,
                                      - Bx2 * eta * Jx3  ,
                                      + Bx3 * eta * Jx2  );
          #endif

          locdmax += eta;
        }

        if(haveAmbipolar) {
          if(ambipolar == UserDefFunction)
            xA = AVERAGE_3D_X(xAmbiArr,k,j,i);

          [[maybe_unused]] real BdotB = EXPAND( Bx1*Bx1, +Bx2*Bx2, +Bx3*Bx3);

          [[maybe_unused]] real Fx2 = -xA * BdotB * Jx3;
          [[maybe_unused]] real Fx3 = xA * BdotB * Jx2;
          #if COMPONENTS == 3
            real JdotB = Jx1 * Bx1 + Jx2 * Bx2 + Jx3 * Bx3;
            Fx2 += xA * JdotB * Bx3;
            Fx3 += -xA * JdotB * Bx2;
          #endif
          #if (DIMENSIONS < 2 && COMPONENTS >= 2)
            Flux(BX2,k,j,i) += Fx2;
          #endif
          #if (DIMENSIONS < 3 && COMPONENTS == 3)
            Flux(BX3,k,j,i) += Fx3;
          #endif

          #if HAVE_ENERGY
            Flux(ENG,k,j,i) += EXPAND( ZERO_F      ,
                                      + Bx2 * Fx2  ,
                                      + Bx3 * Fx3  );
          #endif

          locdmax += xA*BdotB;
        }
      }

      if(dir==JDIR) {
        EXPAND( Jx3 = AVERAGE_4D_X(J, KDIR, k, j, ip1);   ,
                                                          ,
                Jx1 = AVERAGE_4D_Z(J, IDIR, kp1, j, i);
                Jx2 = AVERAGE_4D_XYZ(J, JDIR, kp1, j, ip1);  )

        EXPAND( Bx1 = HALF_F*( Vc(BX1,k,j-1,i) + Vc(BX1,k,j,i));  ,
                Bx2 = Vs(BX2s,k,j,i);                             ,
                Bx3 = HALF_F*( Vc(BX3,k,j-1,i) + Vc(BX3,k,j,i));  )

        if(haveResistivity) {
          if(resistivity == UserDefFunction)
            eta = AVERAGE_3D_Y(etaArr,k,j,i);

          // This term is always overwritten by CT, since this sweep is performed whenver
          // DIMENSIONS>=2
          //#if DIMENSIONS == 1
          //  Flux(BX1,k,j,i) += eta * Jx3;
          //#endif
          #if (DIMENSIONS < 3 && COMPONENTS == 3)
            Flux(BX3,k,j,i) += - eta * Jx1;
          #endif

          #if HAVE_ENERGY
            Flux(ENG,k,j,i) += EXPAND( Bx1 * eta * Jx3   ,
                                                        ,
                                      - Bx3 * eta * Jx1  );
          #endif
          locdmax += eta;
        }


        if(haveAmbipolar) {
          if(ambipolar == UserDefFunction)
            xA = AVERAGE_3D_Y(xAmbiArr,k,j,i);

          [[maybe_unused]] real BdotB = EXPAND( Bx1*Bx1, +Bx2*Bx2, +Bx3*Bx3);

          [[maybe_unused]] real Fx1 = xA * BdotB * Jx3;
          [[maybe_unused]] real Fx3 = -xA * BdotB * Jx1;
          #if COMPONENTS == 3
            real JdotB = Jx1 * Bx1 + Jx2 * Bx2 + Jx3 * Bx3;
            Fx1 += -xA * JdotB * Bx3;
            Fx3 += xA * JdotB * Bx1;
          #endif

          // This term is always overwritten by CT, since this sweep is performed whenver
          // DIMENSIONS>=2
          //#if DIMENSIONS == 1
          //  Flux(BX1,k,j,i) += Fx1;
          //#endif
          #if (DIMENSIONS < 3 && COMPONENTS == 3)
            Flux(BX3,k,j,i) += Fx3;
          #endif

          #if HAVE_ENERGY
            Flux(ENG,k,j,i) += EXPAND( + Bx1 * Fx1  ,
                                      + ZERO_F     ,
                                      + Bx3 * Fx3  );
          #endif

          locdmax += xA*BdotB;
        }
      }

      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);

        Bx1 = HALF_F*( Vc(BX1,k-1,j,i) + Vc(BX1,k,j,i));
        Bx2 = HALF_F*( Vc(BX2,k-1,j,i) + Vc(BX2,k,j,i));
        Bx3 = Vs(BX3s,k,j,i);


        if(haveResistivity) {
          if(resistivity == UserDefFunction)
            eta = AVERAGE_3D_Z(etaArr,k,j,i);

          // This ie never needed since this is overwritten by CT
          //Flux(BX1,k,j,i) += -eta * Jx2;
          //Flux(BX2,k,j,i) += eta * Jx1;

          #if HAVE_ENERGY
            Flux(ENG,k,j,i) += - Bx1 * eta * Jx2 + Bx2 * eta * Jx1;
          #endif
          dMax(k,j,i) += eta;
        }

        if(haveAmbipolar) {
          if(ambipolar == UserDefFunction)
            xA = AVERAGE_3D_Z(xAmbiArr,k,j,i);

          [[maybe_unused]] real BdotB = Bx1*Bx1 + Bx2*Bx2 + Bx3*Bx3;

          [[maybe_unused]] real Fx1 = -xA * BdotB * Jx2;
          [[maybe_unused]] real Fx2 = xA * BdotB * Jx1;
          #if COMPONENTS == 3
            real JdotB = Jx1 * Bx1 + Jx2 * Bx2 + Jx3 * Bx3;
            Fx1 += xA * JdotB * Bx2;
            Fx2 += -xA * JdotB * Bx1;
          #endif
          // This is never needed since this is overwritten by CT
          //Flux(BX1,k,j,i) += Fx1;
          //Flux(BX2,k,j,i) += Fx2;

          #if HAVE_ENERGY
            Flux(ENG,k,j,i) += Bx1 * Fx1  + Bx2 * Fx2;
          #endif

          locdmax += xA*BdotB;
        }
      }
      dMax(k,j,i) = FMAX(dMax(k,j,i),locdmax);
    }
  );

#endif
  idfx::popRegion();
}

#endif // HYDRO_ADDNONIDEALMHDFLUX_HPP_