Program Listing for File coarsenFlow.cpp

Return to documentation for file (hydro/coarsenFlow.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 "hydro.hpp"
#include "dataBlock.hpp"

KOKKOS_INLINE_FUNCTION int Kmax(int n, int m) {
  return( n>m ? n : m);
}
// This function coarsen the flow according to the grid coarsening array

void Hydro::CoarsenFlow(IdefixArray4D<real> &Vi) {
  idfx::pushRegion("Hydro::CoarsenFlow");

  IdefixArray3D<real> dV   = data->dV;
  for(int dir = 0 ; dir < DIMENSIONS ; dir++) {
    if(!data->coarseningDirection[dir]) continue;
    int begDir = data->beg[dir];
    int endDir = data->end[dir];

    IdefixArray2D<int> coarseningLevel = data->coarseningLevel[dir];

    idefix_for("Hydro_CoarsenFlow",
          0, NVAR,
          data->beg[KDIR],data->end[KDIR],
          data->beg[JDIR],data->end[JDIR],
          data->beg[IDIR],data->end[IDIR],
      KOKKOS_LAMBDA (int n, int k, int j, int i) {
        int factor, index;
        int ioffset = 0;
        int joffset = 0;
        int koffset = 0;
        //factor = 2^(coarsening-1)
        if(dir==IDIR) {
          factor = 1 << (coarseningLevel(k,j) - 1);
          index = i;
          ioffset = 1;
        }
        if(dir==JDIR) {
          factor = 1 << (coarseningLevel(k,i) - 1);
          index = j;
          joffset = 1;
        }
        if(dir==KDIR) {
          factor = 1 << (coarseningLevel(j,i) - 1);
          index = k;
          koffset = 1;
        }
        // check if coarsening is required in this region
        if(factor>1) {
          // We average the cells by groups of "factor" in direction "dir",
          // so only the first element of each group will do the job.
          if( (index-begDir)%factor == 0) {
            real q = 0.0;
            real V = 0.0;
            for(int shift = 0 ; shift < factor ; shift++) {
              q = q + Vi(n, k + shift*koffset, j + shift*joffset, i+shift*ioffset)
                    * dV(k + shift*koffset, j + shift*joffset, i+shift*ioffset);
              V = V + dV(k + shift*koffset, j + shift*joffset, i+shift*ioffset);
            }
            // Average
            q = q/V;
            // Write back the cell elements
            for(int shift = 0 ; shift < factor ; shift++) {
              Vi(n, k + shift*koffset, j + shift*joffset, i+shift*ioffset) = q;
            }
          }
        }
    });
  }
  idfx::popRegion();
}

void Hydro::CoarsenMagField(IdefixArray4D<real> &Vsin) {
#if MHD == YES
  idfx::pushRegion("Hydro::CoarsenMagField");
  #if DIMENSIONS >= 2
  /**********************************
   * MHD Part                       *
   * ********************************/
  for(int dir = 0 ; dir < DIMENSIONS ; dir++) {
    if(!data->coarseningDirection[dir]) continue;
    int begDir = data->beg[dir];
    int endDir = data->end[dir];

    IdefixArray2D<int> coarseningLevel = data->coarseningLevel[dir];

    const int BXn = dir;
    const int BXt = (dir == IDIR ? BX2s : BX1s);
    const int BXb = (dir == KDIR ? BX2s : BX3s);

    IdefixArray3D<real> An = data->A[dir];
    IdefixArray3D<real> At = data->A[BXt];
    IdefixArray3D<real> Ab = data->A[BXb];

    int it = 0, ib = 0;
    int jt = 0, jb = 0;
    int kt = 0, kb = 0;
    int endk = data->end[KDIR];
    int endj = data->end[JDIR];
    int endi = data->end[IDIR];

    // find the index over which the faces are off-centered
    // (trick so that we can write a single loop)
    if(dir==IDIR) {
      jt=1;
      kb=1;
      endj++;
      #if DIMENSIONS == 3
      endk++;
      #endif
    }
    if(dir==JDIR) {
      it=1;
      kb=1;
      endi++;
      #if DIMENSIONS == 3
      endk++;
      #endif
    }
    if(dir==KDIR) {
      it=1;
      jb=1;
      endi++;
      endj++;
    }
    #if DIMENSIONS < 3
    // force kb to 0
    kb = 0;
    #endif

    // Coarsen components normal to the coarsening direction first (BXt and BXb)
    idefix_for("Hydro_CoarsenFlow_BXsn",
        data->beg[KDIR],endk,
        data->beg[JDIR],endj,
        data->beg[IDIR],endi,
    KOKKOS_LAMBDA (int k, int j, int i) {
      int coarsening_t =1;
      [[maybe_unused]] int coarsening_b = 1;
      int index;
      int ioffset = 0;
      int joffset = 0;
      int koffset = 0;
      if(dir==IDIR) {
        coarsening_t = Kmax(coarseningLevel(k,j-1), coarseningLevel(k,j));
        #if DIMENSIONS == 3
        coarsening_b = Kmax(coarseningLevel(k-1,j), coarseningLevel(k,j));
        #endif
        ioffset = 1;
        index=i;
      }
      if(dir==JDIR) {
        coarsening_t = Kmax(coarseningLevel(k,i-1), coarseningLevel(k,i));
        #if DIMENSIONS == 3
        coarsening_b = Kmax(coarseningLevel(k-1,i), coarseningLevel(k,i));
        #endif
        joffset = 1;
        index=j;
      }
      if(dir==KDIR) {
        coarsening_t = Kmax(coarseningLevel(j,i-1), coarseningLevel(j,i));
        coarsening_b = Kmax(coarseningLevel(j-1,i), coarseningLevel(j,i));
        koffset = 1;
        index=k;
      }

      //coarsening_t=0;
      //coarsening_b=0;
      // Treat t component
      if(coarsening_t>1) {
        int factor_t = 1 << (coarsening_t-1);
        // We average the cells by groups of "factor" in direction "dir",
        // so only the first element of each group will do the job.
        if( (index-begDir)%factor_t == 0) {
          real q = 0.0;
          real A = 0.0;
          for(int shift = 0 ; shift < factor_t ; shift++) {
            q = q + Vsin(BXt, k + shift*koffset, j + shift*joffset, i+shift*ioffset)
                  * At(k + shift*koffset, j + shift*joffset, i+shift*ioffset);
            A = A + At(k + shift*koffset, j + shift*joffset, i+shift*ioffset);
          }

          // If the Area is zero, do a point average instead (this happens on the axis instance)
          if(FABS(A) < 1e-10) {
            // do a point average instead of a surface average
            q=0.0;
            A=0.0;
            for(int shift = 0 ; shift < factor_t ; shift++) {
              q = q + Vsin(BXt, k + shift*koffset, j + shift*joffset, i+shift*ioffset);
              A = A + 1.0;
            }
          }
          q = q/A;
          // Write back the cell elements
          for(int shift = 0 ; shift < factor_t ; shift++) {
            Vsin(BXt, k + shift*koffset, j + shift*joffset, i+shift*ioffset) = q;
          }
        }
      }
      // Treat b component
      #if DIMENSIONS == 3
      if(coarsening_b>1) {
        int factor_b = 1 << (coarsening_b-1);
        // We average the cells by groups of "factor" in direction "dir",
        // so only the first element of each group will do the job.
        if( (index-begDir)%factor_b == 0) {
          real q = 0.0;
          real A = 0.0;
          for(int shift = 0 ; shift < factor_b ; shift++) {
            q = q + Vsin(BXb, k + shift*koffset, j + shift*joffset, i+shift*ioffset)
                  * Ab(k + shift*koffset, j + shift*joffset, i+shift*ioffset);
            A = A + Ab(k + shift*koffset, j + shift*joffset, i+shift*ioffset);
          }
          // If the Area is zero, do a point average instead (this happens on the axis instance)
          if(FABS(A) < 1e-10) {
            // do a point average instead of a surface average
            q=0.0;
            A=0.0;
            for(int shift = 0 ; shift < factor_b ; shift++) {
              q = q + Vsin(BXb, k + shift*koffset, j + shift*joffset, i+shift*ioffset);
              A = A + 1.0;
            }
          }
          // Average
          q = q/A;
          // Write back the cell elements
          for(int shift = 0 ; shift < factor_b ; shift++) {
            Vsin(BXb, k + shift*koffset, j + shift*joffset, i+shift*ioffset) = q;
          }
        }
      }
      #endif
    });

      // Coarsen components parralel the coarsening direction (BXn)
    idefix_for("Hydro_CoarsenFlow_BXsn",
        data->beg[KDIR],data->end[KDIR],
        data->beg[JDIR],data->end[JDIR],
        data->beg[IDIR],data->end[IDIR],
    KOKKOS_LAMBDA (int k, int j, int i) {
      int coarsening;
      int index;
      int ioffset = 0;
      int joffset = 0;
      int koffset = 0;
      // Pick the highest coarsening level of the current coordinates and its immediate neighbours
      if(dir==IDIR) {
        coarsening = coarseningLevel(k,j);
        coarsening = Kmax(coarsening, coarseningLevel(k,j-1));
        coarsening = Kmax(coarsening, coarseningLevel(k,j+1));
        #if DIMENSIONS == 3
        coarsening = Kmax(coarsening, coarseningLevel(k-1,j));
        coarsening = Kmax(coarsening, coarseningLevel(k+1,j));
        #endif
        ioffset = 1;
        index=i;
      }
      if(dir==JDIR) {
        coarsening = coarseningLevel(k,i);
        coarsening = Kmax(coarsening, coarseningLevel(k,i-1));
        coarsening = Kmax(coarsening, coarseningLevel(k,i+1));
        #if DIMENSIONS == 3
        coarsening = Kmax(coarsening, coarseningLevel(k-1,i));
        coarsening = Kmax(coarsening, coarseningLevel(k+1,i));
        #endif
        joffset = 1;
        index=j;
      }
      if(dir==KDIR) {
        coarsening = coarseningLevel(j,i);
        coarsening = Kmax(coarsening, coarseningLevel(j,i-1));
        coarsening = Kmax(coarsening, coarseningLevel(j,i+1));
        coarsening = Kmax(coarsening, coarseningLevel(j-1,i));
        coarsening = Kmax(coarsening, coarseningLevel(j+1,i));
        koffset = 1;
        index=k;
      }

      if(coarsening > 1) {
        // the current cell had tangential field components which have been coarsened. Hence,
        // We reconstruct the parrallel field component with divB=0

        int factor = 1 << (coarsening-1);
        if( (index-begDir)%factor == 0) {
          for(int shift = 0 ; shift < factor-1 ; shift++) {
            real qt = Vsin(BXt,k+kt+shift*koffset, j+jt+shift*joffset, i+it+shift*ioffset)
                        * At(k+kt+shift*koffset, j+jt+shift*joffset, i+it+shift*ioffset)
                    - Vsin(BXt,k+shift*koffset, j+shift*joffset, i+shift*ioffset)
                        *  At(k+shift*koffset, j+shift*joffset, i+shift*ioffset);
            real qb = Vsin(BXb,k+kb+shift*koffset, j+jb+shift*joffset, i+ib+shift*ioffset)
                        * Ab(k+kb+shift*koffset, j+jb+shift*joffset, i+ib+shift*ioffset)
                    - Vsin(BXb,k+shift*koffset, j+shift*joffset, i+shift*ioffset)
                        *  Ab(k+shift*koffset, j+shift*joffset, i+shift*ioffset);
/*
            if(i==10 && j == 3 && k == 10) {
              idfx::cout << "shift=" << shift << " ; oldBxn=" << Vsin(BXn, k+(shift+1)*koffset, j+(shift+1)*joffset, i+(shift+1)*ioffset) << std::endl;
              idfx::cout << "qt=" << qt << " ; qb=" << qb << std::endl;
            }*/

            Vsin(BXn, k+(shift+1)*koffset, j+(shift+1)*joffset, i+(shift+1)*ioffset) =
                1.0/An(k+(shift+1)*koffset, j+(shift+1)*joffset, i+(shift+1)*ioffset) *
                (
                  Vsin(BXn, k+shift*koffset, j+shift*joffset, i+shift*ioffset) *
                    An(k+shift*koffset, j+shift*joffset, i+shift*ioffset)
                  - qt - qb
                );
                /*
            if(i==10 && j == 3 && k == 10) {
              idfx::cout << "shift=" << shift << " ; newsBxn=" << Vsin(BXn, k+(shift+1)*koffset, j+(shift+1)*joffset, i+(shift+1)*ioffset) << std::endl;
            }*/
          }
        }
      }
    });
  }
  idfx::popRegion();
#endif
}

void Hydro::CoarsenVectorPotential() {
#if MHD == YES && defined(EVOLVE_VECTOR_POTENTIAL)
  idfx::pushRegion("Hydro::VectorPotential");

  IdefixArray4D<real> Ve = this->Ve;

  #if DIMENSIONS < 3
  IDEFIX_ERROR("Grid Coarsening with vector potential is not implemented for DIMENSIONS < 3");
  #endif

  for(int dir = 0 ; dir < DIMENSIONS ; dir++) {
    if(!data->coarseningDirection[dir]) continue;
    int begDir = data->beg[dir];
    int endDir = data->end[dir];

    const int AXn = dir;
    const int AXt = (dir == IDIR ? AX2e : AX1e);
    const int AXb = (dir == KDIR ? AX2e : AX3e);

    IdefixArray2D<int> coarseningLevel = data->coarseningLevel[dir];

    idefix_for("Hydro_CoarsenFlow",
          data->beg[KDIR],data->end[KDIR],
          data->beg[JDIR],data->end[JDIR],
          data->beg[IDIR],data->end[IDIR],
      KOKKOS_LAMBDA (int k, int j, int i) {
        int factor, index;
        int ioffset = 0;
        int joffset = 0;
        int koffset = 0;
        //factor = 2^(coarsening-1)
        if(dir==IDIR) {
          factor = 1 << (coarseningLevel(k,j) - 1);
          index = i;
          ioffset = 1;
        }
        if(dir==JDIR) {
          factor = 1 << (coarseningLevel(k,i) - 1);
          index = j;
          joffset = 1;
        }
        if(dir==KDIR) {
          factor = 1 << (coarseningLevel(j,i) - 1);
          index = k;
          koffset = 1;
        }
        // check if coarsening is required in this region
        if(factor>1) {
          // We average the cells by groups of "factor" in direction "dir",
          // so only the first element of each group will do the job.
          if( (index-begDir)%factor == 0) {
            real q = 0.0;
            for(int shift = 0 ; shift < factor ; shift++) {
              q = q + Ve(AXn, k + shift*koffset, j + shift*joffset, i+shift*ioffset);
            }
            // Average
            q = q/factor;
            // Write back the cell elements
            for(int shift = 0 ; shift < factor ; shift++) {
              Ve(AXn, k + shift*koffset, j + shift*joffset, i+shift*ioffset) = q;
              real a = ((real) shift) / ((real) factor);

              Ve(AXt, k + shift*koffset, j + shift*joffset, i+shift*ioffset) =
                  a * Ve(AXt, k + factor*koffset, j + factor*joffset, i+factor*ioffset)
                  + (1-a) * Ve(AXt, k, j, i);

              Ve(AXb, k + shift*koffset, j + shift*joffset, i+shift*ioffset) =
                  a * Ve(AXb, k + factor*koffset, j + factor*joffset, i+factor*ioffset)
                  + (1-a) * Ve(AXb, k, j, i);
            }
          }
        }
    });
  }

  #endif // DIMENSIONS >= 2
  idfx::popRegion();

  #endif // MHD
}