#include #include #include #ifdef _OPENMP #include #endif using namespace amrex; namespace { void compute_stencil(Gpu::ManagedVector &stencil, int npass) { Gpu::ManagedVector old_s(1+npass,0.); Gpu::ManagedVector new_s(1+npass,0.); old_s[0] = 1.; int jmax = 1; amrex::Real loc; // Convolve the filter with itself npass times for(int ipass=1; ipass const& tmp, Array4 const& dst, int scomp, int dcomp, int ncomp) { amrex::Real const* AMREX_RESTRICT sx = stencil_x.data(); amrex::Real const* AMREX_RESTRICT sy = stencil_y.data(); amrex::Real const* AMREX_RESTRICT sz = stencil_z.data(); Dim3 slen_local = slen; AMREX_PARALLEL_FOR_4D ( tbx, ncomp, i, j, k, n, { Real d = 0.0; for (int iz=0; iz < slen_local.z; ++iz){ for (int iy=0; iy < slen_local.y; ++iy){ for (int ix=0; ix < slen_local.x; ++ix){ #if (AMREX_SPACEDIM == 3) Real sss = sx[ix]*sy[iy]*sz[iz]; #else Real sss = sx[ix]*sz[iy]; #endif #if (AMREX_SPACEDIM == 3) d += sss*( tmp(i-ix,j-iy,k-iz,scomp+n) +tmp(i+ix,j-iy,k-iz,scomp+n) +tmp(i-ix,j+iy,k-iz,scomp+n) +tmp(i+ix,j+iy,k-iz,scomp+n) +tmp(i-ix,j-iy,k+iz,scomp+n) +tmp(i+ix,j-iy,k+iz,scomp+n) +tmp(i-ix,j+iy,k+iz,scomp+n) +tmp(i+ix,j+iy,k+iz,scomp+n)); #else d += sss*( tmp(i-ix,j-iy,k,scomp+n) +tmp(i+ix,j-iy,k,scomp+n) +tmp(i-ix,j+iy,k,scomp+n) +tmp(i+ix,j+iy,k,scomp+n)); #endif } } } dst(i,j,k,dcomp+n) = d; }); } #else void BilinearFilter::ApplyStencil (MultiFab& dstmf, const MultiFab& srcmf, int scomp, int dcomp, int ncomp) { BL_PROFILE("BilinearFilter::ApplyStencil()"); ncomp = std::min(ncomp, srcmf.nComp()); #ifdef _OPENMP #pragma omp parallel #endif { FArrayBox tmpfab; for (MFIter mfi(dstmf,true); mfi.isValid(); ++mfi){ const auto& srcfab = srcmf[mfi]; auto& dstfab = dstmf[mfi]; const Box& tbx = mfi.growntilebox(); const Box& gbx = amrex::grow(tbx,stencil_length_each_dir-1); // tmpfab has enough ghost cells for the stencil tmpfab.resize(gbx,ncomp); tmpfab.setVal(0.0, gbx, 0, ncomp); // Copy values in srcfab into tmpfab const Box& ibx = gbx & srcfab.box(); tmpfab.copy(srcfab, ibx, scomp, ibx, 0, ncomp); // Apply filter Filter(tbx, tmpfab.array(), dstfab.array(), 0, dcomp, ncomp); } } } void BilinearFilter::Filter (const Box& tbx, Array4 const& tmp, Array4 const& dst, int scomp, int dcomp, int ncomp) { const auto lo = amrex::lbound(tbx); const auto hi = amrex::ubound(tbx); // tmp and dst are of type Array4 (Fortran ordering) amrex::Real const* AMREX_RESTRICT sx = stencil_x.data(); amrex::Real const* AMREX_RESTRICT sy = stencil_y.data(); amrex::Real const* AMREX_RESTRICT sz = stencil_z.data(); for (int n = 0; n < ncomp; ++n) { // Set dst value to 0. for (int k = lo.z; k <= hi.z; ++k) { for (int j = lo.y; j <= hi.y; ++j) { for (int i = lo.x; i <= hi.x; ++i) { dst(i,j,k,dcomp+n) = 0.0; } } } // 3 nested loop on 3D stencil for (int iz=0; iz < slen.z; ++iz){ for (int iy=0; iy < slen.y; ++iy){ for (int ix=0; ix < slen.x; ++ix){ #if (AMREX_SPACEDIM == 3) Real sss = sx[ix]*sy[iy]*sz[iz]; #else Real sss = sx[ix]*sz[iy]; #endif // 3 nested loop on 3D array for (int k = lo.z; k <= hi.z; ++k) { for (int j = lo.y; j <= hi.y; ++j) { AMREX_PRAGMA_SIMD for (int i = lo.x; i <= hi.x; ++i) { #if (AMREX_SPACEDIM == 3) dst(i,j,k,dcomp+n) += sss*(tmp(i-ix,j-iy,k-iz,scomp+n) +tmp(i+ix,j-iy,k-iz,scomp+n) +tmp(i-ix,j+iy,k-iz,scomp+n) +tmp(i+ix,j+iy,k-iz,scomp+n) +tmp(i-ix,j-iy,k+iz,scomp+n) +tmp(i+ix,j-iy,k+iz,scomp+n) +tmp(i-ix,j+iy,k+iz,scomp+n) +tmp(i+ix,j+iy,k+iz,scomp+n)); #else dst(i,j,k,dcomp+n) += sss*(tmp(i-ix,j-iy,k,scomp+n) +tmp(i+ix,j-iy,k,scomp+n) +tmp(i-ix,j+iy,k,scomp+n) +tmp(i+ix,j+iy,k,scomp+n)); #endif } } } } } } } } #endif