diff --git a/src_compressible/compressible_functions.cpp b/src_compressible/compressible_functions.cpp index e2cf9142..3ffe274d 100644 --- a/src_compressible/compressible_functions.cpp +++ b/src_compressible/compressible_functions.cpp @@ -3,6 +3,7 @@ AMREX_GPU_MANAGED int compressible::transport_type; AMREX_GPU_MANAGED int compressible::membrane_cell; +AMREX_GPU_MANAGED int compressible::membrane_type; AMREX_GPU_MANAGED amrex::GpuArray compressible::transmission; AMREX_GPU_MANAGED int compressible::do_1D; AMREX_GPU_MANAGED int compressible::do_2D; @@ -39,6 +40,12 @@ void InitializeCompressibleNamespace() pp.query("membrane_cell",membrane_cell); if (membrane_cell >= 0) amrex::Print() << "Membrane cell is: " << membrane_cell << "\n"; + // get membrane type + membrane_type = 0; // membrane type (0: SSA; 1: Langevin) + pp.query("membrane_type",membrane_type); + if (membrane_type == 0) amrex::Print() << "SSA membrane type" << "\n"; + if (membrane_type == 1) amrex::Print() << "Langevin membrane type" << "\n"; + // get membrane transmission for (int i=0; i transmission; extern AMREX_GPU_MANAGED int do_1D; extern AMREX_GPU_MANAGED int do_2D; diff --git a/src_compressible_stag/boundaryStag.cpp b/src_compressible_stag/boundaryStag.cpp index b4c10039..f7bbfa31 100644 --- a/src_compressible_stag/boundaryStag.cpp +++ b/src_compressible_stag/boundaryStag.cpp @@ -270,7 +270,7 @@ void setBCStag(MultiFab& prim_in, MultiFab& cons_in, Abort("setBC: momentum and velocity need the same number of ghost cells"); } - if (membrane_cell >= 0) { // set adiabatic slip BC at the membrane + if ((membrane_cell >= 0) and (membrane_type == 1)) { // set adiabatic slip BC at the membrane (Langevin) BCMem(prim_in, cons_in, cumom_in, vel_in, geom); } diff --git a/src_compressible_stag/compressible_functions_stag.H b/src_compressible_stag/compressible_functions_stag.H index f68d9e0e..8b123d0c 100644 --- a/src_compressible_stag/compressible_functions_stag.H +++ b/src_compressible_stag/compressible_functions_stag.H @@ -150,6 +150,27 @@ void applyEffusion(std::array& faceflux, MultiFab& cons_in, std::array< MultiFab, AMREX_SPACEDIM >& cumom); +void +ResetMembraneMom(std::array& cumom, + const std::array& cumom_mem, + const amrex::Geometry& geom); + +void +ResetMembraneFluxes(const std::array& faceflux_mem, + std::array& faceflux, + std::array< MultiFab, 2 >& edgeflux_x, + std::array< MultiFab, 2 >& edgeflux_y, + std::array< MultiFab, 2 >& edgeflux_z, + const amrex::Geometry& geom); + +void +ComputeFluxMomMembrane(const MultiFab& cons0_in, const MultiFab& prim0_in, + const std::array& vel0, + std::array& cumom_mem, + std::array& faceflux_mem, + const amrex::Geometry& geom, + const amrex::Real dt); + void ComputeFluxMomReservoir(const MultiFab& cons0_in, const MultiFab& prim0_in, const std::array& vel0, diff --git a/src_compressible_stag/fluxStag.cpp b/src_compressible_stag/fluxStag.cpp index c733d2b3..1bf2ef96 100644 --- a/src_compressible_stag/fluxStag.cpp +++ b/src_compressible_stag/fluxStag.cpp @@ -806,7 +806,7 @@ void calculateFluxStag(const MultiFab& cons_in, const std::array< MultiFab, AMRE // Enforce flux boundary conditions StochFluxStag(faceflux_in,cenflux_in,edgeflux_x_in,edgeflux_y_in,edgeflux_z_in,geom); - if (membrane_cell >= 0) { + if ((membrane_cell >= 0) and (membrane_type == 1)) { StochFluxMem(faceflux_in,edgeflux_x_in,edgeflux_y_in,edgeflux_z_in); } diff --git a/src_compressible_stag/main_driver.cpp b/src_compressible_stag/main_driver.cpp index af1bcb18..e9d6c24d 100644 --- a/src_compressible_stag/main_driver.cpp +++ b/src_compressible_stag/main_driver.cpp @@ -219,6 +219,7 @@ void main_driver(const char* argv) if ((all_correl == 1) and (cross_cell > 0) and (cross_cell < n_cells[0]-1)) { amrex::Print() << "Correlations will be done at four equi-distant x* because all_correl = 1" << "\n"; } + if ((membrane_cell > 0) and ((membrane_type < 0) or (membrane_type > 1))) Abort("membrane_type needs to be 0 (SSA) or 1 (Langevin)"); // contains yz-averaged running & instantaneous averages of conserved variables (2*nvars) + primitive variables [vx, vy, vz, T, Yk]: 2*4 + 2*nspecies Vector dataSliceMeans_xcross(2*nvars+8+2*nspecies, 0.0); diff --git a/src_compressible_stag/membraneStag.cpp b/src_compressible_stag/membraneStag.cpp index 4ed2d0a3..87903633 100644 --- a/src_compressible_stag/membraneStag.cpp +++ b/src_compressible_stag/membraneStag.cpp @@ -2,6 +2,7 @@ #include "compressible_functions.H" #include "common_functions.H" #include "rng_functions.H" +#include "reservoirStag_K.H" #include void doMembraneStag(MultiFab& cons, @@ -470,3 +471,239 @@ void applyEffusion(std::array& faceflux, } } + +/////////////////////////////////////////////////////////////////////////// +// compute momentum and fluxes at the membrane //////////////////////////// +// for SSA-type membrane; for now membrane is always perpendicular to x /// +/////////////////////////////////////////////////////////////////////////// +void +ComputeFluxMomMembrane(const MultiFab& cons0_in, const MultiFab& prim0_in, + const std::array& vel0, + std::array& cumom_mem, + std::array& faceflux_mem, + const amrex::Geometry& geom, + const amrex::Real dt) +{ + BL_PROFILE_VAR("ComputeFluxMomMembrane()",ComputeFluxMomMembrane); + + const GpuArray dx = geom.CellSizeArray(); + Box dom(geom.Domain()); + + Real N_A = Runiv/k_B; // Avagadro's number + + GpuArray mass; + for (int l=0;l cons0 = cons0_in.array(mfi); + const Array4 prim0 = prim0_in.array(mfi); + const Array4& xvel0 = (vel0[0]).array(mfi); + const Array4& yvel0 = (vel0[1]).array(mfi); + const Array4& zvel0 = (vel0[2]).array(mfi); + + const Array4& xmom = (cumom_mem[0]).array(mfi); + const Array4& xflux = (faceflux_mem[0]).array(mfi); + + // membrane on hi side of bx + if ((membrane_cell >= bx.smallEnd(0)) and (membrane_cell <= bx.bigEnd(0))) { + amrex::ParallelForRNG(bx, + [=] AMREX_GPU_DEVICE (int i, int j, int k, amrex::RandomEngine const& engine) noexcept + { + if (i == membrane_cell) { + ////////////////// left cell /////////////////////// + + //////////////////////////////////////////////////// + // number of particles in FHD cell (for correction) + //Real N = 0.0; + //GpuArray N_i; + //for (int n=0;n mom_cross; // total momentum into membrane + Real en_cross; // total energy into membrane + GpuArray spec_mass_cross; + GpuArray rhoYk; + for (int n=0;n& faceflux_mem, + std::array& faceflux, + std::array< MultiFab, 2 >& edgeflux_x, + std::array< MultiFab, 2 >& edgeflux_y, + std::array< MultiFab, 2 >& edgeflux_z, + const amrex::Geometry& geom) +{ + BL_PROFILE_VAR("ResetMembraneFluxes()",ResetMembraneFluxes); + + for (MFIter mfi(faceflux[0]); mfi.isValid(); ++mfi) { + const Box& bx = mfi.validbox(); + const Array4& xflux = (faceflux[0]).array(mfi); + const Array4& xflux_mem = (faceflux_mem[0]).array(mfi); + + if ((membrane_cell >= bx.smallEnd(0)) and (membrane_cell <= bx.bigEnd(0))) { + amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept + { + if (i == membrane_cell) { + xflux(i,j,k,0) = xflux_mem(i,j,k,0); // mass flux + xflux(i,j,k,4) = xflux_mem(i,j,k,4); // energy flux + for (int n=0;n& cumom, + const std::array& cumom_mem, + const amrex::Geometry& geom) +{ + BL_PROFILE_VAR("ResetMembraneMom()",ResetMembraneMom); + + for (MFIter mfi(cumom[0]); mfi.isValid(); ++mfi) { + const Box& bx = mfi.validbox(); + const Array4& xmom = (cumom[0]).array(mfi); + const Array4& xmom_mem = (cumom_mem[0]).array(mfi); + + if ((membrane_cell >= bx.smallEnd(0)) and (membrane_cell <= bx.bigEnd(0))) { + amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept + { + if (i == membrane_cell) { + xmom(i,j,k) = xmom_mem(i,j,k); +// xmom(i,j,k) = 0.0; + } + }); + } + } +} + diff --git a/src_compressible_stag/reservoirStag_K.H b/src_compressible_stag/reservoirStag_K.H index 213cfd92..b1aa962b 100644 --- a/src_compressible_stag/reservoirStag_K.H +++ b/src_compressible_stag/reservoirStag_K.H @@ -158,4 +158,124 @@ poisson_process_reservoir(const amrex::GpuArray& mass, } } +AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE +void +poisson_process_membrane(const amrex::GpuArray& mass, + const amrex::GpuArray& rhoYk, + const amrex::Real& T, // temperature + const amrex::Real& Vnormal, // normal velocity + const int& nspec, + const amrex::Real& area, + const amrex::Real& kB, + const amrex::Real& dt, + amrex::Real& mass_cross, + amrex::GpuArray& mom_cross, + amrex::Real& en_cross, + amrex::GpuArray& spec_mass_cross, + int dim, // dimension + amrex::Real VT1, // tangential velocity 1 + amrex::Real VT2, // tangential velocity 2 + const amrex::GpuArray transmission, + amrex::RandomEngine const& engine) + +{ + constexpr amrex::Real small_number = 1.0e-13; + constexpr amrex::Real sqrtPI = 1.77245385091; + + mass_cross = 0.0; + en_cross = 0.0; + for (int n=0;n<3;++n) { + mom_cross[n] = 0.0; + } + for (int n=0;n particle_rate; + amrex::GpuArray timer; + amrex::GpuArray thermal_speed; + amrex::GpuArray speed_ratio; + amrex::GpuArray stop_flag; + + for (int n=0;n small_number) { + particle_rate[n] = transmission[n]*(1.0/(2.0*sqrtPI))*num_density*area*thermal_speed[n]* + (exp(-1.0*speed_ratio[n]*speed_ratio[n]) + speed_ratio[n]*sqrtPI*(1.0 + erf(speed_ratio[n]))); + if (particle_rate[n] < 0.0) { + amrex::Abort("negative particle rate encountered"); + } + } + else { + particle_rate[n] = transmission[n]*(1.0/(2.0*sqrtPI))*num_density*area*thermal_speed[n]; + if (particle_rate[n] < 0.0) { + amrex::Abort("negative particle rate encountered"); + } + } + timer[n] = 0.0; + stop_flag[n] = false; + } + + // Run Poisson Process + bool stop = false; + while(!stop) { + + // add a particle for each species (if stop[n] = false) + amrex::Real vel_rand; + for (int n=0;n= 2) { +// vel_rand = random_cross_vel(speed_ratio[n],thermal_speed[n],true,VT1,engine); // get random velocity +// mom_cross[1] += mass[n]*vel_rand; // add a particle crossing for total momentum +// en_cross += 0.5*mass[n]*(vel_rand)*(vel_rand); // add a particle crossing for total energy + mom_cross[1] += 0.0; + en_cross += 0.0; + } + + // tangential component 2 + if (dim == 3) { + //vel_rand = random_cross_vel(speed_ratio[n],thermal_speed[n],true,VT2,engine); // get random velocity + //mom_cross[2] += mass[n]*vel_rand; // add a particle crossing for total momentum + //en_cross += 0.5*mass[n]*(vel_rand)*(vel_rand); // add a particle crossing for total energy + mom_cross[1] += 0.0; + en_cross += 0.0; + } + } + } + } + + stop = true; + for (int n=0;n= dt) stop_flag[n] = true; + } + stop = stop and stop_flag[n]; + } + } +} + + #endif diff --git a/src_compressible_stag/timeStepStag.cpp b/src_compressible_stag/timeStepStag.cpp index e6663567..07062d47 100644 --- a/src_compressible_stag/timeStepStag.cpp +++ b/src_compressible_stag/timeStepStag.cpp @@ -36,12 +36,27 @@ void RK3stepStag(MultiFab& cu, // Reservoir stuff std::array< MultiFab, AMREX_SPACEDIM > cumom_res; // MFab for storing momentum from reservoir update std::array< MultiFab, AMREX_SPACEDIM > faceflux_res; // MFab for storing fluxes (face-based) from reservoir update - for (int d=0; d cumom_mem; // MFab for storing momentum from membrane update + std::array< MultiFab, AMREX_SPACEDIM > faceflux_mem; // MFab for storing fluxes (face-based) from membrane update + if ((membrane_cell>=0) and (membrane_type == 0)) { + for (int d=0; d cupmom; std::array< MultiFab, AMREX_SPACEDIM > cup2mom; @@ -335,8 +350,12 @@ void RK3stepStag(MultiFab& cu, geom, stoch_weights,dt); // reservoir timers - Real aux1, aux2, aux3, aux4, aux5, aux6; + Real aux1, aux2, aux3, aux4, aux5, aux6; + // membrane timers + Real auxm1, auxm2, auxm3, auxm4, auxm5, auxm6; + //////////////////////////////////////////////////////////////////////////////////////////////////////// + // Reservoir stuff // add to the total continuum fluxes based on RK3 weight if (do_reservoir) { aux1 = ParallelDescriptor::second(); @@ -350,6 +369,26 @@ void RK3stepStag(MultiFab& cu, aux2 = ParallelDescriptor::second() - aux1; ParallelDescriptor::ReduceRealMax(aux2, ParallelDescriptor::IOProcessorNumber()); } + // Reservoir stuff + //////////////////////////////////////////////////////////////////////////////////////////////////////// + + //////////////////////////////////////////////////////////////////////////////////////////////////////// + // Membrane stuff (SSA) + // add to the total continuum fluxes based on RK3 weight + if ((membrane_cell>=0) and (membrane_type == 0)) { + auxm1 = ParallelDescriptor::second(); + ComputeFluxMomMembrane(cu,prim,vel,cumom_mem, + faceflux_mem,geom,dt); // compute fluxes and momentum from membrane particle update + ResetMembraneFluxes(faceflux_mem, faceflux, + edgeflux_x, + edgeflux_y, + edgeflux_z, + geom); // reset fluxes at the membrane from particle update + auxm2 = ParallelDescriptor::second() - auxm1; + ParallelDescriptor::ReduceRealMax(auxm2, ParallelDescriptor::IOProcessorNumber()); + } + // Membrane stuff (SSA) + //////////////////////////////////////////////////////////////////////////////////////////////////////// if (nreaction>0) { MultiFab::LinComb(ranchem, @@ -535,9 +574,21 @@ void RK3stepStag(MultiFab& cu, BCMomTrans(cupmom[i], vel[i], geom, i); } + //////////////////////////////////////////////////////////////////////////////////////////////////////// + // Reservoir stuff if (do_reservoir) { ResetReservoirMom(cupmom, cumom_res, geom); // set momentum at the reservoir interface to its value from particle update } + // Reservoir stuff + //////////////////////////////////////////////////////////////////////////////////////////////////////// + + //////////////////////////////////////////////////////////////////////////////////////////////////////// + // Membrane stuff (SSA) + if ((membrane_cell>=0) and (membrane_type == 0)) { + ResetMembraneMom(cupmom, cumom_mem, geom); // set momentum at the membrane to its value from particle update + } + // Membrane stuff (SSA) + //////////////////////////////////////////////////////////////////////////////////////////////////////// // Fill boundaries for conserved variables for (int d=0; d=0) and (membrane_type == 0)) { + auxm3 = ParallelDescriptor::second(); + ComputeFluxMomMembrane(cup,prim,vel,cumom_mem, + faceflux_mem, + geom,0.25*dt); // compute fluxes and momentum from membrane particle update + ResetMembraneFluxes(faceflux_mem, faceflux, + edgeflux_x, + edgeflux_y, + edgeflux_z, + geom); // reset fluxes at the membrane from particle update + auxm4 = ParallelDescriptor::second() - auxm3; + ParallelDescriptor::ReduceRealMax(auxm4, ParallelDescriptor::IOProcessorNumber()); + } + // Membrane stuff (SSA) + //////////////////////////////////////////////////////////////////////////////////////////////////////// if (nreaction>0) { MultiFab::LinComb(ranchem, @@ -869,9 +943,21 @@ void RK3stepStag(MultiFab& cu, BCMomTrans(cup2mom[i], vel[i], geom, i); } + //////////////////////////////////////////////////////////////////////////////////////////////////////// + // Reservoir stuff if (do_reservoir) { ResetReservoirMom(cup2mom, cumom_res, geom); // set momentum at the reservoir interface to its value from particle update } + // Reservoir stuff + //////////////////////////////////////////////////////////////////////////////////////////////////////// + + //////////////////////////////////////////////////////////////////////////////////////////////////////// + // Membrane stuff (SSA) + if ((membrane_cell>=0) and (membrane_type == 0)) { + ResetMembraneMom(cup2mom, cumom_mem, geom); // set momentum at the membrane to its value from particle update + } + // Membrane stuff (SSA) + //////////////////////////////////////////////////////////////////////////////////////////////////////// // Fill boundaries for conserved variables for (int d=0; d=0) and (membrane_type == 0)) { + auxm5 = ParallelDescriptor::second(); + ComputeFluxMomMembrane(cup2,prim,vel,cumom_mem, + faceflux_mem, + geom,(2.0/3.0)*dt); // compute fluxes and momentum from membrane particle update + ResetMembraneFluxes(faceflux_mem, faceflux, + edgeflux_x, + edgeflux_y, + edgeflux_z, + geom); // reset fluxes at the membrane from particle update + auxm6 = ParallelDescriptor::second() - auxm5; + ParallelDescriptor::ReduceRealMax(auxm6, ParallelDescriptor::IOProcessorNumber()); + } + // Membrane stuff (SSA) + //////////////////////////////////////////////////////////////////////////////////////////////////////// if (nreaction>0) { MultiFab::LinComb(ranchem, @@ -1210,9 +1319,21 @@ void RK3stepStag(MultiFab& cu, BCMomTrans(cumom[i], vel[i], geom, i); } + //////////////////////////////////////////////////////////////////////////////////////////////////////// + // Reservoir stuff if (do_reservoir) { ResetReservoirMom(cumom, cumom_res, geom); // set momentum at the reservoir interface to its value from particle update } + // Reservoir stuff + //////////////////////////////////////////////////////////////////////////////////////////////////////// + + //////////////////////////////////////////////////////////////////////////////////////////////////////// + // Membrane stuff (SSA) + if ((membrane_cell>=0) and (membrane_type == 0)) { + ResetMembraneMom(cumom, cumom_mem, geom); // set momentum at the membrane to its value from particle update + } + // Membrane stuff (SSA) + //////////////////////////////////////////////////////////////////////////////////////////////////////// // Fill boundaries for conserved variables for (int d=0; d= 0) { + //////////////////////////////////////////////////////////////////////////////////////////////////////// + // Membrane stuff (Langevin) + if ((membrane_cell >= 0) and (membrane_type == 1)) { doMembraneStag(cu,cumom,prim,vel,faceflux,edgeflux_x,geom,dt); } + // Membrane stuff (Langevin) + //////////////////////////////////////////////////////////////////////////////////////////////////////// // Correctly set momentum and velocity at the walls & temperature, pressure, density & mass/mole fractions in ghost cells setBCStag(prim, cu, cumom, vel, geom); + //////////////////////////////////////////////////////////////////////////////////////////////////////// + // Reservoir stuff if (do_reservoir) { if (step%100 == 0) { amrex::Print() << "Step: " << step << " Reservoir generator time: " << aux2 + aux4 + aux6 << " seconds\n"; } } + // Reservoir stuff + //////////////////////////////////////////////////////////////////////////////////////////////////////// + + //////////////////////////////////////////////////////////////////////////////////////////////////////// + // Membrane stuff + if ((membrane_cell >= 0) and (membrane_type == 0)) { + if (step%100 == 0) { + amrex::Print() << "Step: " << step << " Membrane (SSA) time: " << auxm2 + auxm4 + auxm6 << " seconds\n"; + } + } + // Membrane + //////////////////////////////////////////////////////////////////////////////////////////////////////// }