Program Listing for File thermalDiffusion.cpp

Return to documentation for file (hydro/thermalDiffusion.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
// ***********************************************************************************


#include <string>

#include "thermalDiffusion.hpp"
#include "dataBlock.hpp"



ThermalDiffusion::ThermalDiffusion() {
  // Default constructor
}

void ThermalDiffusion::Init(Input &input, Grid &grid, Hydro *hydroin) {
  idfx::pushRegion("ThermalDiffusion::Init");
  // Save the parent hydro object
  this->hydro = hydroin;

  if(input.CheckEntry("Hydro","TDiffusion")>=0) {
    if(input.Get<std::string>("Hydro","TDiffusion",1).compare("constant") == 0) {
        this->kappa = input.Get<real>("Hydro","TDiffusion",2);
        this->haveThermalDiffusion = Constant;
      } else if(input.Get<std::string>("Hydro","TDiffusion",1).compare("userdef") == 0) {
        this->haveThermalDiffusion = UserDefFunction;
        this->kappaArr = IdefixArray3D<real>("ThermalDiffusionKappaArray",hydro->data->np_tot[KDIR],
                                                                 hydro->data->np_tot[JDIR],
                                                                 hydro->data->np_tot[IDIR]);

      } else {
        IDEFIX_ERROR("Unknown thermal diffusion definition in idefix.ini. "
                     "Can only be constant or userdef.");
      }
  } else {
    IDEFIX_ERROR("I cannot create a ThermalDiffusion object without TDiffusion defined"
                   "in the .ini file");
  }

  #ifdef ISOTHERMAL
    IDEFIX_ERROR("Thermal diffusion is not compatible with the ISOTHERMAL approximation");
  #endif

  idfx::popRegion();
}

void ThermalDiffusion::ShowConfig() {
  if(haveThermalDiffusion==Constant) {
    idfx::cout << "Thermal Diffusion: ENEABLED with constant diffusivity kappa="
                    << this->kappa << " ."<< std::endl;
  } else if (haveThermalDiffusion==UserDefFunction) {
    idfx::cout << "Thermal Diffusion: ENABLED with user-defined diffusivity function."
                   << std::endl;
    if(!diffusivityFunc) {
      IDEFIX_ERROR("No thermal diffusion function has been enrolled");
    }
  } else {
    IDEFIX_ERROR("Unknown thermal diffusion mode");
  }
  if(hydro->thermalDiffusionStatus.isExplicit) {
    idfx::cout << "Thermal Diffusion: uses an explicit time integration." << std::endl;
  } else if(hydro->thermalDiffusionStatus.isRKL) {
    idfx::cout << "Thermal Diffusion: uses a Runge-Kutta-Legendre time integration."
                << std::endl;
  } else {
    IDEFIX_ERROR("Unknown time integrator for viscosity.");
  }
}

void ThermalDiffusion::EnrollThermalDiffusivity(DiffusivityFunc myFunc) {
  if(this->haveThermalDiffusion < UserDefFunction) {
    IDEFIX_WARNING("Thermal diffusivity enrollment requires Hydro/ThermalDiffusion "
                 "to be set to userdef in .ini file");
  }
  this->diffusivityFunc = myFunc;
  idfx::cout << "ThermalDiffusion: User-defined thermal diffusion has been enrolled." << std::endl;
}

// 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 ThermalDiffusion::AddDiffusiveFlux(int dir, const real t) {
#if HAVE_ENERGY == 1
  idfx::pushRegion("ThermalDiffusion::AddDiffusiveFlux");
  IdefixArray4D<real> Vc = this->hydro->Vc;
  IdefixArray4D<real> Flux = this->hydro->FluxRiemann;
  IdefixArray3D<real> dMax = this->hydro->dMax;
  IdefixArray3D<real> kappaArr = this->kappaArr;
  IdefixArray1D<real> dx = this->hydro->data->dx[dir];

  #if GEOMETRY == POLAR
    IdefixArray1D<real> x1 = this->hydro->data->x[IDIR];
  #endif
  #if GEOMETRY == SPHERICAL
    IdefixArray1D<real> rt   = this->hydro->data->rt;
    IdefixArray1D<real> dmu  = this->hydro->data->dmu;
    IdefixArray1D<real> dx2 = this->hydro->data->dx[JDIR];
  #endif

  HydroModuleStatus haveThermalDiffusion = this->haveThermalDiffusion;

  // Compute thermal diffusion if needed
  if(haveThermalDiffusion == UserDefFunction && dir == IDIR) {
    if(diffusivityFunc) {
      idfx::pushRegion("UserDef::ThermalDiffusivityFunction");
      diffusivityFunc(*this->hydro->data, t, kappaArr);
      idfx::popRegion();
    } else {
      IDEFIX_ERROR("No user-defined thermal diffusion 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 kappaConstant = this->kappa;
  real gamma = hydro->gamma;

  if(dir==IDIR) iend++;
  if(dir==JDIR) jend++;
  if(dir==KDIR) kend++;

  const int ioffset = (dir==IDIR) ? 1 : 0;
  const int joffset = (dir==JDIR) ? 1 : 0;
  const int koffset = (dir==KDIR) ? 1 : 0;

  idefix_for("ThermalDiffusionFlux",kbeg, kend, jbeg, jend, ibeg, iend,
      KOKKOS_LAMBDA (int k, int j, int i) {
        // Compute gradT
        real gradT;

        gradT = Vc(PRS,k,j,i) / Vc(RHO,k,j,i)
               - Vc(PRS,k-koffset,j-joffset,i-ioffset) / Vc(RHO,k-koffset,j-joffset,i-ioffset);

        // index along dir
        const int ig = ioffset*i + joffset*j + koffset*k;

        // dx at the interface is the averaged between the two adjacent centered dx
        real dl = HALF_F*(dx(ig-1) + dx(ig));
        #if GEOMETRY == POLAR
        if(dir==JDIR)
          dl = dl*x1(i);

        #elif GEOMETRY == SPHERICAL
          if(dir==JDIR)
            dl = dl*rt(i);
          else
            if(dir==KDIR)
              dl = dl*rt(i)*dmu(j)/dx2(j);
        #endif // GEOMETRY

        gradT = gradT/dl;

        // Compute diffusion coefficient at the interface
        real kappa;
        if(haveThermalDiffusion == UserDefFunction) {
          kappa = HALF_F*(kappaArr(k,j,i) +  kappaArr(k-koffset,j-joffset,i-ioffset));
        } else {
          kappa = kappaConstant;
        }

        // Add thermal diffusion to the flux
        Flux(ENG,k,j,i) += -kappa*gradT;

        // Compute total diffusion coefficient
        real locdmax = kappa * (gamma-ONE_F) /
                        (HALF_F * ( Vc(RHO,k,j,i) + Vc(RHO,k-koffset,j-joffset,i-ioffset)));
        dMax(k,j,i) = FMAX(dMax(k,j,i) , locdmax);
      });
  idfx::popRegion();
#endif // HAVE_ENERGY
}