aboutsummaryrefslogtreecommitdiff
path: root/Source/Filter/BilinearFilter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/Filter/BilinearFilter.cpp')
-rw-r--r--Source/Filter/BilinearFilter.cpp156
1 files changed, 156 insertions, 0 deletions
diff --git a/Source/Filter/BilinearFilter.cpp b/Source/Filter/BilinearFilter.cpp
new file mode 100644
index 000000000..17857a416
--- /dev/null
+++ b/Source/Filter/BilinearFilter.cpp
@@ -0,0 +1,156 @@
+#include <WarpX.H>
+#include <BilinearFilter.H>
+#include <WarpX_f.H>
+
+#ifdef _OPENMP
+#include <omp.h>
+#endif
+
+using namespace amrex;
+
+namespace {
+void compute_stencil(Vector<Real> &stencil, int npass){
+ Vector<Real> old_s(1+npass,0.);
+ Vector<Real> 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<npass+1; ipass++){
+ // element 0 has to be treated in its own way
+ new_s[0] = 0.5 * old_s[0];
+ if (1<jmax) new_s[0] += 0.5 * old_s[1];
+ loc = 0.;
+ // For each element j, apply the filter to
+ // old_s to get new_s[j]. loc stores the tmp
+ // filtered value.
+ for(int j=1; j<jmax+1; j++){
+ loc = 0.5 * old_s[j];
+ loc += 0.25 * old_s[j-1];
+ if (j<jmax) loc += 0.25 * old_s[j+1];
+ new_s[j] = loc;
+ }
+ // copy new_s into old_s
+ old_s = new_s;
+ // extend the stencil length for next iteration
+ jmax += 1;
+ }
+ // we use old_s here to make sure the stencil
+ // is corrent even when npass = 0
+ stencil = old_s;
+ stencil[0] *= 0.5; // because we will use it twice
+}
+}
+
+void BilinearFilter::ComputeStencils(){
+ BL_PROFILE("BilinearFilter::ComputeStencils()");
+ stencil_length_each_dir = npass_each_dir;
+ stencil_length_each_dir += 1.;
+#if (AMREX_SPACEDIM == 3)
+ // npass_each_dir = npass_x npass_y npass_z
+ stencil_x.resize( 1 + npass_each_dir[0] );
+ stencil_y.resize( 1 + npass_each_dir[1] );
+ stencil_z.resize( 1 + npass_each_dir[2] );
+ compute_stencil(stencil_x, npass_each_dir[0]);
+ compute_stencil(stencil_y, npass_each_dir[1]);
+ compute_stencil(stencil_z, npass_each_dir[2]);
+#elif (AMREX_SPACEDIM == 2)
+ // npass_each_dir = npass_x npass_z
+ stencil_x.resize( 1 + npass_each_dir[0] );
+ stencil_z.resize( 1 + npass_each_dir[1] );
+ compute_stencil(stencil_x, npass_each_dir[0]);
+ compute_stencil(stencil_z, npass_each_dir[1]);
+#endif
+ slen = stencil_length_each_dir.dim3();
+#if (AMREX_SPACEDIM == 2)
+ slen.z = 1;
+#endif
+}
+
+
+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, dstfab, 0, dcomp, ncomp);
+ }
+ }
+}
+
+void BilinearFilter::Filter (const Box& tbx, FArrayBox const& tmpfab, FArrayBox &dstfab,
+ int scomp, int dcomp, int ncomp)
+{
+ const auto lo = amrex::lbound(tbx);
+ const auto hi = amrex::ubound(tbx);
+ const auto tmp = tmpfab.array();
+ const auto dst = dstfab.array();
+ // 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
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+