diff --git a/Docs/sphinx/BoundaryConditions.rst b/Docs/sphinx/BoundaryConditions.rst index 0c119f3f4..f4cfe878d 100644 --- a/Docs/sphinx/BoundaryConditions.rst +++ b/Docs/sphinx/BoundaryConditions.rst @@ -20,6 +20,9 @@ PeleC manages boundary conditions in a form consistent with many AMReX codes. Gh More complex boundary conditions require user input that is prescribed explicitly. Boundaries identified as ``UserBC`` or ``Hard`` in the inputs will be tagged as ``EXT_DIR`` in ``pc_hypfill``. Users will then fill the boundary values, by calling the helper function, ``bcnormal``. The ``bcnormal`` function fills an exterior (ghost) cell based on the value of the outermost interior cell. Its arguments include a problem-specific data structure, the location, direction, and orientation of the boundary being filled, and potentially fluctuating turbulent velocities from the `TurbInflow `_ utility in PelePhysics. This gives the user flexibility to specify a variety of boundary conditions, including faces that contain both walls and inflow regions. Note that the external state ``s_ext`` is prepopulated with the same values as are used for the ``NoSlipWall`` condition, so the default if the ``bcnormal`` function does nothing is to specify a ``NoSlipWall``. +.. note:: + To ensure conservation, when Godunov schemes are used the order of accuracy is reduced at boundaries specified using ``bcnormal``; PLM is used and the predictor step is omitted when computing fluxes through these boundaries. This does not affect any other boundary types or simulations using MOL. + Special care should be taken when prescribing subsonic ``Inflow`` or an ``Outflow`` boundary conditions. It might be tempting to directly impose target values in the boundary filler function (for ``Inflow``), or to perform a simple extrapolation (for ``Outflow``). However, this approach would fail to correctly respect the flow of information along solution characteristics - the system would be ill-posed and would lead to unphysical behavior. In particular, at a subsonic inflow boundary, at a subsonic inlet there is one outgoing characteristic, so one flow variable must be specified using information from inside the domain. Similarly, there is one incoming characteristic at outflow boundaries. The NSCBC method, described below, is the preffered method to account for this, but has not been ported to the all C++ version of PeleC. In the meantime, the recommended strategy for subsonic inflow and outflow boundaries for confined geometries such as nozzles and combustors is as follows: * Subsonic Inflows: Specify the desired temperature, velocity, and composition (if relevant) in the ghost cells. Take the pressure from the domain interior. Based on these values, compute the density, internal energy, and total energy for the ghost cells. @@ -28,6 +31,14 @@ Special care should be taken when prescribing subsonic ``Inflow`` or an ``Outflo A detailed analysis comparing various boundary condition strategies and demonstrating their implementation is available for the :ref:`EB-ConvergingNozzle` case. +Isothermal Walls +~~~~~~~~~~~~~~~~ + +By default, the boundaries specified as ``NoSlipWall`` and ``SlipWall`` are adiabatic. For isothermal wall boundaries, energy fluxes through the isothermal wall are computed separately, rather than being based on values populated in the ghost cells. To activate computation of isothermal wallfluxes, use the input file option ``pelec.do_isothermal_walls = 1`` and then specify the desired wall temperatures using, for example, ``pelec.domlo_wall_temp = -1 -1 300.0`` and ``pelec.domhi_isothermal_temp = -1 -1 400.0``, which would leave the x and y boundaries as adiabatic, make the lower z boundary isothermal at 300 K, and make the upper z boundary isothermal at 400 K. Any boundary with a negative (or zero) value for the specified temperature is treated as adiabatic; boundaries that are not ``NoSlipWall``, ``SlipWall``, ``UserBC``, or ``Hard`` must always have a negative value specified. + +Navier-Stokes Characteristic Boundary Conditions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + .. warning:: This following is currently deprecated as the GS-NSCBC boundary condition has not been ported from Fortran to C++. diff --git a/Docs/sphinx/verification/masscons/figure_conservation_energy.png b/Docs/sphinx/verification/masscons/figure_conservation_energy.png new file mode 100644 index 000000000..d6eb18c69 Binary files /dev/null and b/Docs/sphinx/verification/masscons/figure_conservation_energy.png differ diff --git a/Docs/sphinx/verification/masscons/figure_conservation_mass.png b/Docs/sphinx/verification/masscons/figure_conservation_mass.png new file mode 100644 index 000000000..c685750da Binary files /dev/null and b/Docs/sphinx/verification/masscons/figure_conservation_mass.png differ diff --git a/Docs/sphinx/verification/masscons/figure_convergence.png b/Docs/sphinx/verification/masscons/figure_convergence.png new file mode 100644 index 000000000..4b629fc07 Binary files /dev/null and b/Docs/sphinx/verification/masscons/figure_convergence.png differ diff --git a/Docs/sphinx/verification/masscons/figure_dir0.png b/Docs/sphinx/verification/masscons/figure_dir0.png new file mode 100644 index 000000000..7c67d6ba1 Binary files /dev/null and b/Docs/sphinx/verification/masscons/figure_dir0.png differ diff --git a/Docs/sphinx/verification/masscons/figure_dir1.png b/Docs/sphinx/verification/masscons/figure_dir1.png new file mode 100644 index 000000000..e5e948895 Binary files /dev/null and b/Docs/sphinx/verification/masscons/figure_dir1.png differ diff --git a/Docs/sphinx/verification/verification.rst b/Docs/sphinx/verification/verification.rst index 589c15ac5..70f6ec3c2 100644 --- a/Docs/sphinx/verification/verification.rst +++ b/Docs/sphinx/verification/verification.rst @@ -2,7 +2,7 @@ .. role:: cpp(code) :language: c++ - + .. _Verification: @@ -247,3 +247,37 @@ constant Smagorinsky Large Eddy Simulation model. .. image:: /verification/les/p_error.png :width: 300pt + +Conservation and Isothermal Boundaries +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A simple test cass labeled ``MassCons`` is used to verify mass and energy conservation for all major numerical schemes used in PeleC (MOL without slopes, MOL with slopes, Godunov PLM, Godunov PPM). A python script is also run for all applicable test cases without inflows, outflows, or forcing, to ensure conservation during regression testing to ensure the conservation is maintained. The results shown below demonstrate the machine-precision level conservation of mass and energy for all numerical schemes. The case is arbitrary flow in a box with different types of boundaries (``SlipWall``, ``NoSlipWall``, ``UserBC``, including isothermal options). Note energy is conserved for the isothermal case without hydro turned on because of symmetry in the boundary conditions, but is not conserved for the case with hydro because inclusion of hydrodynamic effects breaks the symmetry. + +- Mass Conservation: + +.. image:: /verification/masscons/figure_conservation_mass.png + +- Energy Conservation: + +.. image:: /verification/masscons/figure_conservation_energy.png + +This case does not include EB, but the conservation script is run for some of the EB test cases (EB-C9, EB-C11, EB-C12). However, it should be noted that the testing suite does not cover cases where EBs intersect the domain boundary at a sharp angle. + +The case with isothermal walls and no hydro allows the convergence of the treatment of diffusion and isothermal boundaries to be verified without using MMS. This case has an initial temperature of 700 K in the 2D domain and temperatures of 600 K, 800 K, 650 K, and 750 K for the low x, high x, low y, and high y boundaries, respectively. Verification is performed at an early time such that thermal diffusion from the various boundaries have not imacted each other yet. Therefore, the solutions are compared against the analytical result for diffusion into a semi-infinite medium: + +.. math:: + \frac{T - T_{wall}}{T_{0} - T_{wall}} = \rm{erf}(x/\sqrt{4Dt}) + +where `x` is the distance from the wall. + +- x temperature profile: + +.. image:: /verification/masscons/figure_dir0.png + +- y temperature profile: + +.. image:: /verification/masscons/figure_dir1.png + +- Convergence: + +.. image:: /verification/masscons/figure_convergence.png diff --git a/Exec/RegTests/MassCons/masscons-isothermal-whydro.inp b/Exec/RegTests/MassCons/masscons-isothermal-whydro.inp new file mode 100644 index 000000000..b3dad6515 --- /dev/null +++ b/Exec/RegTests/MassCons/masscons-isothermal-whydro.inp @@ -0,0 +1,85 @@ +# ------------------ INPUTS TO MAIN PROGRAM ------------------- +max_step = 400 +stop_time = 0.2 + +# PROBLEM SIZE & GEOMETRY +geometry.is_periodic = 0 0 0 +geometry.coord_sys = 0 # 0 => cart, 1 => RZ 2=>spherical +geometry.prob_lo = -0.5 -0.5 -0.5 +geometry.prob_hi = 0.5 0.5 0.5 +amr.n_cell = 16 16 16 + +# >>>>>>>>>>>>> BC KEYWORDS <<<<<<<<<<<<<<<<<<<<<< +# Interior, UserBC, Sysmmetry, SlipWall, NoSlipWall +# >>>>>>>>>>>>> BC KEYWORDS <<<<<<<<<<<<<<<<<<<<<< + +pelec.lo_bc = "SlipWall" "NoSlipWall" "SlipWall" +pelec.hi_bc = "UserBC" "UserBC" "UserBC" +prob.wall_type = 1 0 1 + +pelec.do_isothermal_walls = true +pelec.domlo_isothermal_temp = 600 650 670 +pelec.domhi_isothermal_temp = 800 750 730 + +# WHICH PHYSICS +pelec.ppm_type = 0 +pelec.do_hydro = 1 +pelec.do_mol = 0 +pelec.diffuse_vel = 1 +pelec.diffuse_temp = 1 +pelec.diffuse_spec = 1 +pelec.do_react = 0 +pelec.diffuse_enth = 1 +pelec.add_ext_src = 0 +pelec.external_forcing = 0.0 0.0 0.0 + +transport.const_viscosity = 0 +transport.const_conductivity = 2.7271624e+04 + +# TIME STEP CONTROL +pelec.cfl = 0.8 # cfl number for hyperbolic system +pelec.init_shrink = 1.0 # scale back initial timestep +pelec.change_max = 1.05 # scale back initial timestep +pelec.dt_cutoff = 5.e-20 # level 0 timestep below which we halt +pelec.fixed_dt = 0.4e-6 + +# DIAGNOSTICS & VERBOSITY +pelec.sum_interval = 1 # timesteps between computing mass +pelec.v = 1 # verbosity in PeleC.cpp +amr.v = 1 # verbosity in Amr.cpp +amr.data_log = datlog + +# REFINEMENT / REGRIDDING +amr.max_level = 0 # maximum level number allowed +amr.ref_ratio = 2 2 2 2 # refinement ratio +amr.regrid_int = 2 2 2 2 # how often to regrid +amr.blocking_factor = 4 # block factor in grid generation +amr.max_grid_size = 64 +amr.n_error_buf = 12 8 2 2 # number of buffer cells in error est + +# CHECKPOINT FILES +amr.checkpoint_files_output = 0 +amr.check_file = chk # root name of checkpoint file +amr.check_int = 500 # number of timesteps between checkpoints + +# PLOTFILES +amr.plot_files_output = 1 +amr.plot_file = plt # root name of plotfile +amr.plot_int = 400 # number of timesteps between plotfiles +amr.plot_vars = density Temp +amr.derive_plot_vars = x_velocity y_velocity z_velocity magvel magvort pressure +pelec.plot_rhoy = 0 +pelec.plot_massfrac = 1 + +# PROBLEM PARAMETERS +prob.T_mean = 700.0 +prob.u0 = 0.0 +prob.v0 = 0.0 +prob.w0 = 0.0 + +# Problem setup +eb2.geom_type = "all_regular" + +amrex.fpe_trap_invalid = 0 +amrex.fpe_trap_zero = 0 +amrex.fpe_trap_overflow = 0 diff --git a/Exec/RegTests/MassCons/masscons-isothermal.inp b/Exec/RegTests/MassCons/masscons-isothermal.inp new file mode 100644 index 000000000..5e43eb108 --- /dev/null +++ b/Exec/RegTests/MassCons/masscons-isothermal.inp @@ -0,0 +1,85 @@ +# ------------------ INPUTS TO MAIN PROGRAM ------------------- +max_step = 400 +stop_time = 0.2 + +# PROBLEM SIZE & GEOMETRY +geometry.is_periodic = 0 0 0 +geometry.coord_sys = 0 # 0 => cart, 1 => RZ 2=>spherical +geometry.prob_lo = -0.5 -0.5 -0.5 +geometry.prob_hi = 0.5 0.5 0.5 +amr.n_cell = 16 16 16 + +# >>>>>>>>>>>>> BC KEYWORDS <<<<<<<<<<<<<<<<<<<<<< +# Interior, UserBC, Symmetry, SlipWall, NoSlipWall +# >>>>>>>>>>>>> BC KEYWORDS <<<<<<<<<<<<<<<<<<<<<< + +pelec.lo_bc = "SlipWall" "NoSlipWall" "SlipWall" +pelec.hi_bc = "UserBC" "UserBC" "UserBC" +prob.wall_type = 1 0 1 + +pelec.do_isothermal_walls = true +pelec.domlo_isothermal_temp = 600 650 670 +pelec.domhi_isothermal_temp = 800 750 730 + +# WHICH PHYSICS +pelec.ppm_type = 0 +pelec.do_hydro = 0 +pelec.do_mol = 0 +pelec.diffuse_vel = 1 +pelec.diffuse_temp = 1 +pelec.diffuse_spec = 1 +pelec.do_react = 0 +pelec.diffuse_enth = 1 +pelec.add_ext_src = 0 +pelec.external_forcing = 0.0 0.0 0.0 + +transport.const_viscosity = 0 +transport.const_conductivity = 2.7271624e+04 + +# TIME STEP CONTROL +pelec.cfl = 0.8 # cfl number for hyperbolic system +pelec.init_shrink = 1.0 # scale back initial timestep +pelec.change_max = 1.05 # scale back initial timestep +pelec.dt_cutoff = 5.e-20 # level 0 timestep below which we halt +pelec.fixed_dt = 0.4e-6 + +# DIAGNOSTICS & VERBOSITY +pelec.sum_interval = 1 # timesteps between computing mass +pelec.v = 1 # verbosity in PeleC.cpp +amr.v = 1 # verbosity in Amr.cpp +amr.data_log = datlog + +# REFINEMENT / REGRIDDING +amr.max_level = 0 # maximum level number allowed +amr.ref_ratio = 2 2 2 2 # refinement ratio +amr.regrid_int = 2 2 2 2 # how often to regrid +amr.blocking_factor = 4 # block factor in grid generation +amr.max_grid_size = 64 +amr.n_error_buf = 12 8 2 2 # number of buffer cells in error est + +# CHECKPOINT FILES +amr.checkpoint_files_output = 0 +amr.check_file = chk # root name of checkpoint file +amr.check_int = 500 # number of timesteps between checkpoints + +# PLOTFILES +amr.plot_files_output = 1 +amr.plot_file = plt # root name of plotfile +amr.plot_int = 400 # number of timesteps between plotfiles +amr.plot_vars = density Temp +amr.derive_plot_vars = x_velocity y_velocity z_velocity magvel magvort pressure +pelec.plot_rhoy = 0 +pelec.plot_massfrac = 1 + +# PROBLEM PARAMETERS +prob.T_mean = 700.0 +prob.u0 = 0.0 +prob.v0 = 0.0 +prob.w0 = 0.0 + +# Problem setup +eb2.geom_type = "all_regular" + +amrex.fpe_trap_invalid = 0 +amrex.fpe_trap_zero = 0 +amrex.fpe_trap_overflow = 0 diff --git a/Exec/RegTests/MassCons/run_isothermal_study.py b/Exec/RegTests/MassCons/run_isothermal_study.py new file mode 100644 index 000000000..35c3425ff --- /dev/null +++ b/Exec/RegTests/MassCons/run_isothermal_study.py @@ -0,0 +1,62 @@ +import pandas as pd +import numpy as np +import os +import matplotlib.pyplot as plt +from scipy.special import erf + +npoints = [16, 32, 64, 128, 256] + +#for grid in grid: +alpha = 7.5362000690846E+00 + +pltfile = 'plt00400' + +error = {} +for ngrid in npoints: + error[ngrid] = {} + os.system('rm -r plt*0') + os.system('mpirun -n 4 PeleC2d.gnu.MPI.ex masscons-isothermal.inp amr.n_cell="{} {} {}"'.format(ngrid, ngrid, ngrid)) + for idir in ['0', '1']: + os.system('fextract.gnu.ex -d {} -s slice{} {}'.format(idir,idir,pltfile)) + fname = 'slice'+idir + os.system("sed 's/\#/ /g' "+fname+" > "+fname+'_') + data = pd.read_csv(fname+'_', skiprows=2, sep='\s+') + + with open(fname) as f: + junk = f.readline() + timetext = f.readline() + time = float(timetext.split()[-1]) + + coord = {'0':'x','1':'y','2':'z'}[idir] + + data['zeta1'] = (data[coord] + 0.5) /np.sqrt(4 * alpha * time) + data['zeta2'] = (0.5 - data[coord]) /np.sqrt(4 * alpha * time) + + dT = {'0':100,'1':50,'2':30}[idir] + + data['Tdelta2'] = -dT * erf(data['zeta2'] ) + data['Tdelta1'] = dT * erf(data['zeta1'] ) + data['Ttrue' ] = 700.0 + data['Tdelta2'] + data['Tdelta1'] + + plt.figure(idir) + plt.plot(data[coord], data['Temp'], '-',label=ngrid) + if ngrid == npoints[-1]: + plt.plot(data[coord], data['Ttrue'], 'k:', label ='analytical') + plt.legend(frameon=False) + plt.xlabel(coord + ' (cm)') + plt.ylabel('T (K)') + error[ngrid][idir+'max'] = np.max(np.abs( data['Ttrue' ] - data['Temp'] )) #np.linalg.norm( data['Ttrue' ] - data['Temp'], ord=2) / np.sqrt(len(data[coord])) + error[ngrid][idir+'mse'] = np.linalg.norm( data['Ttrue' ] - data['Temp'], ord=2) / np.sqrt(len(data[coord])) + plt.savefig("figure_dir"+idir+'.png') + +error = pd.DataFrame(error).T +print(error) +plt.figure() +plt.loglog(error.index, error['0mse'], 'r-o', label='x-direction') +plt.loglog(error.index, error['1mse'], 'b-o', label='y-direction') +plt.loglog(error.index, 100*(1.0/error.index)**2, 'k:', label='2nd order') +plt.ylabel('Error') +plt.xlabel('N') +plt.xlim([8,512]) +plt.legend(frameon=False) +plt.savefig('figure_convergence.png') diff --git a/Exec/RegTests/MassCons/run_masscons_study.py b/Exec/RegTests/MassCons/run_masscons_study.py new file mode 100644 index 000000000..8217c4783 --- /dev/null +++ b/Exec/RegTests/MassCons/run_masscons_study.py @@ -0,0 +1,37 @@ +import pandas as pd +import numpy as np +import os +import matplotlib.pyplot as plt + +inputs = ['mol-1', 'mol-2', 'plm', 'ppm', 'isothermal', 'isothermal-whydro'] + +for iname in inputs: + os.system('rm -r datlog plt*0') + os.system('./PeleC2d.gnu.MPI.ex masscons-{}.inp max_step=200'.format(iname)) + data = pd.read_fwf('datlog') + plt.figure('mass') + plt.plot(data.index, (data['mass']-data['mass'][0])/data['mass'][0], label=iname) + + if iname is not 'isothermal-whydro': + plt.figure('energy') + plt.plot(data.index, (data['rho_E']-data['rho_E'][0])/data['rho_E'][0], label = iname) + +plt.figure('mass') +plt.xlabel('Timestep') +plt.ylabel('Relative Mass Change') +plt.ylim([-1e-14, 1e-14]) +plt.legend(frameon=False) +plt.tight_layout() +plt.savefig('figure_conservation_mass.png') +plt.clf() +plt.close() + +plt.figure('energy') +plt.xlabel('Timestep') +plt.ylabel('Relative Energy Change') +plt.ylim([-1e-14, 1e-14]) +plt.legend(frameon=False) +plt.tight_layout() +plt.savefig('figure_conservation_energy.png') +plt.clf() +plt.close() diff --git a/Source/Diffterm.H b/Source/Diffterm.H index 92f9233e6..270aaf547 100644 --- a/Source/Diffterm.H +++ b/Source/Diffterm.H @@ -480,4 +480,106 @@ pc_flux_div( V(i, j, k); } +// This function sets the temperature in isothermal walls +// TODO: expose this to users for problem-specific definition +// for now, if nonuniform isothermal walls are desired, +// this must be hacked +AMREX_GPU_DEVICE +AMREX_FORCE_INLINE +void +pc_set_wall_temperature( + const int i, + const int j, + const int k, + const int /*dir*/, + const int /*normal*/, + const amrex::Real Twall_in, + amrex::GeometryData const& /*geomdata*/, + ProbParmDevice const& /*prob_parm*/, + const amrex::Array4& /*q*/, + const amrex::Array4& Twall) +{ + /* + if desired: compute x,y,z and make wall temp an arbitray function of space + + const amrex::Real* prob_lo = geom.ProbLo(); + const amrex::Real* dx = geom.CellSize(); + const amrex::Real x[AMREX_SPACEDIM] = {AMREX_D_DECL( + prob_lo[0] + static_cast(iv[0] + 0.5) * dx[0], + prob_lo[1] + static_cast(iv[1] + 0.5) * dx[1], + prob_lo[2] + static_cast(iv[2] + 0.5) * dx[2])}; + + Twall(i,j,k) = function of x, dir, normal, prob_parm + or set it using the fluid values (q) for adabatic + */ + Twall(i, j, k) = Twall_in; +} + +// This function computes diffusive energy flux through isothermal walls +// and *adds* it to the flx array +AMREX_GPU_DEVICE +AMREX_FORCE_INLINE +void +pc_isothermal_wall_fluxes( + const int i, + const int j, + const int k, + const int dir, + const int normal, + const amrex::Array4& q, + const amrex::Array4& Twall_arr, + const amrex::Array4& flags, + const amrex::Array4& area, + const amrex::Array4& flx, + amrex::GpuArray const& dxinv, + pele::physics::transport::TransParm< + pele::physics::EosType, + pele::physics::PhysicsType::transport_type> const* tparm) +{ + + // iv: face centered index where flux is computed + amrex::IntVect iv{AMREX_D_DECL(i, j, k)}; + // ivm: cell centered index of interior cell + amrex::IntVect ivm{AMREX_D_DECL(i, j, k)}; + ivm[dir] += ((normal > 0) ? -1 : 0); + // ivr: boundary cell relative to interior cell + amrex::IntVect ivr{0}; + ivr[dir] = normal; + + // Only do anything if the face isn't covered by an EB + if (flags(ivm).isConnected(ivr)) { + + // First get density at wall temp (only comes into play for SRK) + amrex::Real rho_wall = 0.0; + const amrex::Real Twall = Twall_arr(iv); + const amrex::Real pwall = q(ivm, QPRES); + amrex::Real Ywall[NUM_SPECIES] = {0.0}; + for (int ns = 0; ns < NUM_SPECIES; ++ns) { + Ywall[ns] = q(ivm, ns + QFS); + } + auto eos = pele::physics::PhysicsType::eos(); + eos.PYT2R(pwall, Ywall, Twall, rho_wall); + + // Now compute lambda at the wall temperature + const bool wtr_get_xi = false; + const bool wtr_get_mu = false; + const bool wtr_get_lam = true; + const bool wtr_get_Ddiag = false; + const bool wtr_get_chi = false; + amrex::Real* dummy_Ddiag = nullptr; + amrex::Real* dummy_chi_mix = nullptr; + amrex::Real dummy_mu, dummy_xi; + amrex::Real lambda; + auto trans = pele::physics::PhysicsType::transport(); + trans.transport( + wtr_get_xi, wtr_get_mu, wtr_get_lam, wtr_get_Ddiag, wtr_get_chi, Twall, + rho_wall, Ywall, dummy_Ddiag, dummy_chi_mix, dummy_mu, dummy_xi, lambda, + tparm); + + // Compute Fourier flux and scale by area + amrex::Real dTdx = 2.0 * (q(ivm, QTEMP) - Twall) * dxinv[dir] * normal; + flx(i, j, k, UEDEN) += lambda * dTdx * area(iv); + } +} + #endif diff --git a/Source/Diffusion.cpp b/Source/Diffusion.cpp index 969918826..114aab803 100644 --- a/Source/Diffusion.cpp +++ b/Source/Diffusion.cpp @@ -239,6 +239,49 @@ PeleC::getMOLSrcTerm( } } + if (do_isothermal_walls) { + // Compute extensive diffusion flux at domain boundaries + BL_PROFILE("PeleC::isothermal_wall_fluxes()"); + for (int dir = 0; dir < AMREX_SPACEDIM; dir++) { + if ( + (typ == amrex::FabType::singlevalued) || + (typ == amrex::FabType::regular)) { + int normalarr[2] = {-1, 1}; + amrex::Real bc_temp_arr[2] = { + domlo_isothermal_temp[dir], domhi_isothermal_temp[dir]}; + for (int inorm = 0; inorm < 2; inorm++) { + int normal = normalarr[inorm]; + amrex::Real bc_temp = bc_temp_arr[inorm]; + if (bc_temp > 0.0) { + amrex::Box bbox = surroundingNodes(vbox, dir); + if (normal == -1) { + bbox.setBig(dir, geom.Domain().smallEnd(dir)); + } else { + bbox.setSmall(dir, geom.Domain().bigEnd(dir) + 1); + } + if (bbox.ok()) { + amrex::FArrayBox tmpfabtemp( + bbox, 1, amrex::The_Async_Arena()); + amrex::Array4 temp_arr = tmpfabtemp.array(); + const ProbParmDevice* lprobparm = PeleC::d_prob_parm_device; + auto const* ltransparm = trans_parms.device_trans_parm(); + const auto geomdata = geom.data(); + amrex::ParallelFor( + bbox, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { + pc_set_wall_temperature( + i, j, k, dir, normal, bc_temp, geomdata, *lprobparm, + qar, temp_arr); + pc_isothermal_wall_fluxes( + i, j, k, dir, normal, qar, temp_arr, flag_arr, + area_arr[dir], flx[dir], dxinv, ltransparm); + }); + } + } + } + } + } + } + // Shut off unwanted diffusion after the fact. // Under normal conditions, you either have diffusion on all or // none, so this shouldn't be done this way. However, the regression diff --git a/Source/Params/_cpp_parameters b/Source/Params/_cpp_parameters index 653e2de76..c1086f220 100644 --- a/Source/Params/_cpp_parameters +++ b/Source/Params/_cpp_parameters @@ -171,6 +171,15 @@ diffuse_vel bool false # flag for harmonic averaging of transport coefficients to the face transport_harmonic_mean bool true +# flag for isothermal walls +do_isothermal_walls bool false + +# low domain boundary isothermal temperature [K] (negative = adiabatic) +domlo_isothermal_temp dim_array -1.0 + +# hi domain boundary isothermal temperature [K] (negative = adiabatic) +domhi_isothermal_temp dim_array -1.0 + #----------------------------------------------------------------------------- # category: large eddy simulation #----------------------------------------------------------------------------- diff --git a/Source/Params/param_includes/pelec_defaults.H b/Source/Params/param_includes/pelec_defaults.H index 896f85fec..de0b457ce 100644 --- a/Source/Params/param_includes/pelec_defaults.H +++ b/Source/Params/param_includes/pelec_defaults.H @@ -52,6 +52,11 @@ bool PeleC::diffuse_enth = false; bool PeleC::diffuse_spec = false; bool PeleC::diffuse_vel = false; bool PeleC::transport_harmonic_mean = true; +bool PeleC::do_isothermal_walls = false; +amrex::GpuArray PeleC::domlo_isothermal_temp = { + -1.0}; +amrex::GpuArray PeleC::domhi_isothermal_temp = { + -1.0}; bool PeleC::do_les = false; bool PeleC::use_explicit_filter = false; amrex::Real PeleC::Cs = 0.0; diff --git a/Source/Params/param_includes/pelec_params.H b/Source/Params/param_includes/pelec_params.H index a6dfb705d..db689343e 100644 --- a/Source/Params/param_includes/pelec_params.H +++ b/Source/Params/param_includes/pelec_params.H @@ -52,6 +52,9 @@ static bool diffuse_enth; static bool diffuse_spec; static bool diffuse_vel; static bool transport_harmonic_mean; +static bool do_isothermal_walls; +static amrex::GpuArray domlo_isothermal_temp; +static amrex::GpuArray domhi_isothermal_temp; static bool do_les; static bool use_explicit_filter; static amrex::Real Cs; diff --git a/Source/Params/param_includes/pelec_queries.H b/Source/Params/param_includes/pelec_queries.H index 0492d8a2d..8662d938e 100644 --- a/Source/Params/param_includes/pelec_queries.H +++ b/Source/Params/param_includes/pelec_queries.H @@ -58,6 +58,21 @@ pp.query("diffuse_enth", diffuse_enth); pp.query("diffuse_spec", diffuse_spec); pp.query("diffuse_vel", diffuse_vel); pp.query("transport_harmonic_mean", transport_harmonic_mean); +pp.query("do_isothermal_walls", do_isothermal_walls); +{ + amrex::Vector tmp(AMREX_SPACEDIM, -1.0); + pp.queryarr("domlo_isothermal_temp", tmp, 0, AMREX_SPACEDIM); + for (int i = 0; i < tmp.size(); i++) { + domlo_isothermal_temp[i] = tmp[i]; + } +} +{ + amrex::Vector tmp(AMREX_SPACEDIM, -1.0); + pp.queryarr("domhi_isothermal_temp", tmp, 0, AMREX_SPACEDIM); + for (int i = 0; i < tmp.size(); i++) { + domhi_isothermal_temp[i] = tmp[i]; + } +} pp.query("do_les", do_les); pp.query("use_explicit_filter", use_explicit_filter); pp.query("Cs", Cs); diff --git a/Source/Params/parse_pelec_params.py b/Source/Params/parse_pelec_params.py index e4317d5ec..c93b2eac5 100755 --- a/Source/Params/parse_pelec_params.py +++ b/Source/Params/parse_pelec_params.py @@ -154,7 +154,9 @@ def get_query_string(self, language): if language == "C++": if self.dtype == "dim_array": - ostr += "{\n amrex::Vector tmp(AMREX_SPACEDIM, 0.0);\n" + ostr += "{{\n amrex::Vector tmp(AMREX_SPACEDIM, {});\n".format( + self.default + ) ostr += ' pp.queryarr("{}", tmp, 0, AMREX_SPACEDIM);\n'.format( self.name ) diff --git a/Source/PeleC.cpp b/Source/PeleC.cpp index bb93326c4..f270797db 100644 --- a/Source/PeleC.cpp +++ b/Source/PeleC.cpp @@ -294,6 +294,28 @@ PeleC::read_params() } } } + if (do_isothermal_walls) { + for (int dir = 0; dir < AMREX_SPACEDIM; ++dir) { + if ( + domlo_isothermal_temp[dir] > 0.0 and + !(lo_bc[dir] == PCPhysBCType::slip_wall || + lo_bc[dir] == PCPhysBCType::no_slip_wall || + lo_bc[dir] == PCPhysBCType::user_bc || + lo_bc[dir] == PCPhysBCType::inflow)) { + amrex::Abort("Cannot have isothermal wall on a BC that isn't a wall or " + "user defined BC"); + } + if ( + domhi_isothermal_temp[dir] > 0.0 and + !(hi_bc[dir] == PCPhysBCType::slip_wall || + hi_bc[dir] == PCPhysBCType::no_slip_wall || + hi_bc[dir] == PCPhysBCType::user_bc || + hi_bc[dir] == PCPhysBCType::inflow)) { + amrex::Abort("Cannot have isothermal wall on a BC that isn't a wall or " + "user defined BC"); + } + } + } if (amrex::DefaultGeometry().IsRZ() && (lo_bc[0] != PCPhysBCType::symmetry)) { amrex::Error("PeleC::read_params: must set r=0 boundary condition to " diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 250fb2f20..6214bdacc 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -217,6 +217,8 @@ add_test_rv(masscons-mol-1 MassCons) add_test_rv(masscons-mol-2 MassCons) add_test_rv(masscons-plm MassCons) add_test_rv(masscons-ppm MassCons) +add_test_rv(masscons-isothermal MassCons) +add_test_r(masscons-isothermal-whydro MassCons) add_test_rv(tg-1 TG) add_test_rv(tg-2 TG) add_test_rv(hit-1 HIT)