From e061712ec5c811ae3db62d07bc61a3d7aa9a1fd5 Mon Sep 17 00:00:00 2001 From: Shengtai Li Date: Tue, 3 Dec 2024 23:17:20 -0700 Subject: [PATCH 1/9] merge with the develop branch --- src/CMakeLists.txt | 2 + src/artemis.cpp | 27 ++ src/artemis.hpp | 13 +- src/artemis_driver.cpp | 23 +- src/artemis_driver.hpp | 5 +- src/dust/dust.cpp | 794 +++++++++++++++++++++++++++++++++- src/dust/dust.hpp | 59 +++ src/pgen/pgen.hpp | 6 + src/pgen/problem_modifier.hpp | 2 + 9 files changed, 919 insertions(+), 12 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 238c5ac..6055a75 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -27,6 +27,8 @@ set (SRC_LIST dust/dust.cpp dust/dust.hpp + dust/coagulation/coagulation.cpp + dust/coagulation/coagulation.hpp gas/gas.cpp gas/gas.hpp diff --git a/src/artemis.cpp b/src/artemis.cpp index f99db52..63f7297 100644 --- a/src/artemis.cpp +++ b/src/artemis.cpp @@ -15,6 +15,7 @@ #include "artemis.hpp" #include "artemis_driver.hpp" #include "drag/drag.hpp" +#include "dust/coagulation/coagulation.hpp" #include "dust/dust.hpp" #include "gas/cooling/cooling.hpp" #include "gas/gas.hpp" @@ -30,6 +31,8 @@ namespace artemis { +std::vector OperatorSplitTasks; + //---------------------------------------------------------------------------------------- //! \fn Packages_t Artemis::ProcessPackages //! \brief Process and initialize relevant packages @@ -63,6 +66,7 @@ Packages_t ProcessPackages(std::unique_ptr &pin) { const bool do_viscosity = pin->GetOrAddBoolean("physics", "viscosity", false); const bool do_conduction = pin->GetOrAddBoolean("physics", "conduction", false); const bool do_radiation = pin->GetOrAddBoolean("physics", "radiation", false); + const bool do_coagulation = pin->GetOrAddBoolean("physics", "coagulation", false); artemis->AddParam("do_gas", do_gas); artemis->AddParam("do_dust", do_dust); artemis->AddParam("do_gravity", do_gravity); @@ -74,6 +78,7 @@ Packages_t ProcessPackages(std::unique_ptr &pin) { artemis->AddParam("do_conduction", do_conduction); artemis->AddParam("do_diffusion", do_conduction || do_viscosity); artemis->AddParam("do_radiation", do_radiation); + artemis->AddParam("do_coagulation", do_coagulation); PARTHENON_REQUIRE(!(do_cooling) || (do_cooling && do_gas), "Cooling requires the gas package, but there is not gas!"); PARTHENON_REQUIRE(!(do_viscosity) || (do_viscosity && do_gas), @@ -82,6 +87,8 @@ Packages_t ProcessPackages(std::unique_ptr &pin) { "Conduction requires the gas package, but there is not gas!"); PARTHENON_REQUIRE(!(do_radiation) || (do_radiation && do_gas), "Radiation requires the gas package, but there is not gas!"); + PARTHENON_REQUIRE(!(do_coagulation) || (do_coagulation && do_dust), + "Coagulation requires the dust package, but there is not dust!"); // Set coordinate system const int ndim = ProblemDimension(pin.get()); @@ -98,6 +105,7 @@ Packages_t ProcessPackages(std::unique_ptr &pin) { if (do_cooling) packages.Add(Gas::Cooling::Initialize(pin.get())); if (do_drag) packages.Add(Drag::Initialize(pin.get())); if (do_nbody) packages.Add(NBody::Initialize(pin.get())); + if (do_coagulation) packages.Add(Dust::Coagulation::Initialize(pin.get())); if (do_radiation) { auto eos_h = packages.Get("gas")->Param("eos_h"); auto opacity_h = packages.Get("gas")->Param("opacity_h"); @@ -138,6 +146,25 @@ Packages_t ProcessPackages(std::unique_ptr &pin) { parthenon::MetadataFlag MetadataOperatorSplit = parthenon::Metadata::AddUserFlag("OperatorSplit"); + if (do_coagulation) { + typedef Coordinates C; + if (coords == C::cartesian) { + OperatorSplitTasks.push_back(&Dust::OperatorSplitDust); + } else if (coords == C::spherical1D) { + OperatorSplitTasks.push_back(&Dust::OperatorSplitDust); + } else if (coords == C::spherical2D) { + OperatorSplitTasks.push_back(&Dust::OperatorSplitDust); + } else if (coords == C::spherical3D) { + OperatorSplitTasks.push_back(&Dust::OperatorSplitDust); + } else if (coords == C::cylindrical) { + OperatorSplitTasks.push_back(&Dust::OperatorSplitDust); + } else if (coords == C::axisymmetric) { + OperatorSplitTasks.push_back(&Dust::OperatorSplitDust); + } else { + PARTHENON_FAIL("Invalid artemis/coordinate system!"); + } + } + // Add in user-defined AMR criterion callback const bool amr_user = pin->GetOrAddBoolean("artemis", "amr_user", false); if (amr_user) artemis->CheckRefinementBlock = artemis::ProblemCheckRefinementBlock; diff --git a/src/artemis.hpp b/src/artemis.hpp index 5dc7d4a..1350768 100644 --- a/src/artemis.hpp +++ b/src/artemis.hpp @@ -67,11 +67,13 @@ namespace prim { ARTEMIS_VARIABLE(dust.prim, density); ARTEMIS_VARIABLE(dust.prim, velocity); } // namespace prim +ARTEMIS_VARIABLE(dust, stopping_time); } // namespace dust #undef ARTEMIS_VARIABLE // TaskCollection function pointer for operator split tasks -using TaskCollectionFnPtr = TaskCollection (*)(Mesh *pm, const Real time, const Real dt); +using TaskCollectionFnPtr = TaskCollection (*)(Mesh *pm, parthenon::SimTime &tm, + const Real dt); // Constants that enumerate... // ...Coordinate systems @@ -90,6 +92,14 @@ enum class RSolver { hllc, hlle, llf, null }; enum class ReconstructionMethod { pcm, plm, ppm, null }; // ...Fluid types enum class Fluid { gas, dust, null }; +// constants that enumerate dust drag method +enum class DragMethod { + explicitNoFeedback, + explicitFeedback, + implicitNoFeedback, + implicitFeedback, + null +}; // ...Boundary conditions enum class ArtemisBC { reflect, @@ -148,6 +158,7 @@ inline int ProblemDimension(parthenon::ParameterInput *pin) { namespace artemis { extern std::function *mbd)> ProblemCheckRefinementBlock; +extern std::vector OperatorSplitTasks; } // namespace artemis #endif // ARTEMIS_ARTEMIS_HPP_ diff --git a/src/artemis_driver.cpp b/src/artemis_driver.cpp index 1c6d45a..2c0d117 100644 --- a/src/artemis_driver.cpp +++ b/src/artemis_driver.cpp @@ -66,6 +66,7 @@ ArtemisDriver::ArtemisDriver(ParameterInput *pin, ApplicationInput *app_in do_nbody = artemis_pkg->template Param("do_nbody"); do_diffusion = do_viscosity || do_conduction; do_radiation = artemis_pkg->template Param("do_radiation"); + do_coagulation = artemis_pkg->template Param("do_coagulation"); // NBody initialization tasks if (do_nbody) { @@ -111,6 +112,12 @@ TaskListStatus ArtemisDriver::Step() { if (do_radiation) status = IMC::JaybenneIMC(pmesh, tm.time, tm.dt); if (status != TaskListStatus::complete) return status; + // Execute operator split physics + for (auto &fn : OperatorSplitTasks) { + status = fn(pmesh, tm, integrator->dt).Execute(); + if (status != TaskListStatus::complete) return status; + } + // Compute new dt, (de)refine, and handle sparse (if enabled) status = PostStepTasks().Execute(); @@ -182,7 +189,13 @@ TaskCollection ArtemisDriver::StepTasks() { const bool do_pcm = ((stage == 1) && (integrator->GetName() == "vl2")); TaskID gas_flx = none, dust_flx = none; if (do_gas) gas_flx = tl.AddTask(none, Gas::CalculateFluxes, u0.get(), do_pcm); - if (do_dust) dust_flx = tl.AddTask(none, Dust::CalculateFluxes, u0.get(), do_pcm); + if (do_dust) { + // update dust stopping time and dust diffusivity + TaskID dust_stopping_time = + tl.AddTask(none, Dust::UpdateDustStoppingTime, u0.get()); + dust_flx = + tl.AddTask(dust_stopping_time, Dust::CalculateFluxes, u0.get(), do_pcm); + } // Compute (gas) diffusive fluxes TaskID diff_flx = none; @@ -247,9 +260,15 @@ TaskCollection ArtemisDriver::StepTasks() { tl.AddTask(drag_src, Gas::Cooling::CoolingSource, u0.get(), time, bdt); } + // Add dust drag force + TaskID dust_drag_src = cooling_src; + if (do_dust) { + dust_drag_src = tl.AddTask(cooling_src, Dust::ApplyDragForce, u0.get(), bdt); + } + // Set auxillary fields auto set_aux = - tl.AddTask(cooling_src, ArtemisDerived::SetAuxillaryFields, u0.get()); + tl.AddTask(dust_drag_src, ArtemisDerived::SetAuxillaryFields, u0.get()); // Set (remaining) fields to be communicated auto pre_comm = tl.AddTask(set_aux, PreCommFillDerived>, u0.get()); diff --git a/src/artemis_driver.hpp b/src/artemis_driver.hpp index f3116a3..5d41238 100644 --- a/src/artemis_driver.hpp +++ b/src/artemis_driver.hpp @@ -53,11 +53,12 @@ class ArtemisDriver : public EvolutionDriver { IntegratorPtr_t integrator, nbody_integrator; StateDescriptor *artemis_pkg; bool do_gas, do_dust, do_gravity, do_rotating_frame, do_cooling, do_drag, do_viscosity, - do_nbody, do_conduction, do_diffusion, do_radiation; + do_nbody, do_conduction, do_diffusion, do_radiation, do_coagulation; const bool is_restart; }; -using TaskCollectionFnPtr = TaskCollection (*)(Mesh *pm, const Real time, const Real dt); +// using TaskCollectionFnPtr = TaskCollection (*)(Mesh *pm, const Real time, const Real +// dt); Packages_t ProcessPackages(std::unique_ptr &pin); diff --git a/src/dust/dust.cpp b/src/dust/dust.cpp index dfaa916..b17f16d 100644 --- a/src/dust/dust.cpp +++ b/src/dust/dust.cpp @@ -20,6 +20,7 @@ // Artemis includes #include "artemis.hpp" +#include "dust/coagulation/coagulation.hpp" #include "dust/dust.hpp" #include "geometry/geometry.hpp" #include "utils/artemis_utils.hpp" @@ -29,6 +30,7 @@ using ArtemisUtils::VI; namespace Dust { +CGSUnit *cgsunit = NULL; //---------------------------------------------------------------------------------------- //! \fn StateDescriptor Dust::Initialize //! \brief Adds intialization function for dust hydrodynamics package @@ -86,6 +88,10 @@ std::shared_ptr Initialize(ParameterInput *pin) { const Real cfl_number = pin->GetOrAddReal("dust", "cfl", 0.8); params.Add("cfl", cfl_number); + // possible user_dt + const Real user_dt = pin->GetOrAddReal("dust", "user_dt", 1.0e10); + params.Add("user_dt", user_dt); + // Floors const Real dfloor = pin->GetOrAddReal("dust", "dfloor", 1.0e-20); params.Add("dfloor", dfloor); @@ -97,8 +103,46 @@ std::shared_ptr Initialize(ParameterInput *pin) { for (int n = 0; n < nspecies; ++n) dustids.push_back(n); + // dust stopping time flag + bool const_stopping_time = pin->GetOrAddBoolean("dust", "const_stopping_time", true); + params.Add("const_stopping_time", const_stopping_time); + + bool enable_dust_drag = pin->GetOrAddBoolean("dust", "enable_dust_drag", false); + params.Add("enable_dust_drag", enable_dust_drag); + + bool hst_out_d2g = pin->GetOrAddBoolean("dust", "hst_out_d2g", false); + params.Add("hst_out_d2g", hst_out_d2g); + + // coagulation flag + bool enable_dust_coagulation = pin->GetOrAddBoolean("physics", "coagulation", false); + + DragMethod drag_method = DragMethod::null; + if (enable_dust_drag) { + bool enable_dust_feedback = pin->GetBoolean("dust", "enable_dust_feedback"); + std::string drag_method1 = pin->GetOrAddString("dust", "drag_method", "implicit"); + + if (drag_method1 == "implicit") { + if (enable_dust_feedback) { + drag_method = DragMethod::implicitFeedback; + } else { + drag_method = DragMethod::implicitNoFeedback; + } + } else { + if (enable_dust_feedback) { + drag_method = DragMethod::explicitFeedback; + } else { + drag_method = DragMethod::explicitNoFeedback; + } + } + + params.Add("drag_method", drag_method); + } // end if (enable_dust_drag) + // Dust sizes - const auto size_dist = pin->GetOrAddString("dust", "size_input", "direct"); + auto size_dist = pin->GetOrAddString("dust", "size_input", "direct"); + if (enable_dust_coagulation) size_dist = "logspace"; + params.Add("enable_coagulation", enable_dust_coagulation); + if (size_dist == "linspace") { // uniform auto min_size = pin->GetReal("dust", "min_size"); @@ -131,6 +175,11 @@ std::shared_ptr Initialize(ParameterInput *pin) { params.Add("sizes", sizes); params.Add("h_sizes", h_sizes); + if (parthenon::Globals::my_rank == 0) { + for (int n = 0; n < nspecies; n++) { + std::cout << "dust_size(" << n << ")=" << h_sizes(n) << std::endl; + } + } } else if (size_dist == "direct") { // specify them directly auto sizes_v = pin->GetVector("dust", "sizes"); @@ -163,13 +212,51 @@ std::shared_ptr Initialize(ParameterInput *pin) { sizes.DeepCopy(h_sizes); params.Add("sizes", sizes); params.Add("h_sizes", h_sizes); - } else { + } else if (!const_stopping_time) { PARTHENON_FAIL("dust/size_input not recognized!"); } // Dust density - params.Add("grain_density", pin->GetOrAddReal("dust", "grain_density", 1.0)); + const Real rho_p_orig = pin->GetOrAddReal("dust", "grain_density", 1.0); + params.Add("grain_density", rho_p_orig); + + if (const_stopping_time) { + if (enable_dust_drag) { + ParArray1D stopping_time("dust_stopping_time", nspecies); + auto stopping_time_host = stopping_time.GetHostMirror(); + auto stopping_v = pin->GetVector("dust", "stopping_time"); + for (int n = 0; n < nspecies; ++n) { + stopping_time_host(n) = stopping_v[n]; + } + stopping_time.DeepCopy(stopping_time_host); + params.Add("stopping_time", stopping_time); + } + } else { + if (cgsunit == NULL) { + cgsunit = new CGSUnit; + } + if (!cgsunit->isSet()) { + cgsunit->SetCGSUnit(pin); + } + params.Add("cgs_unit", cgsunit); + + Real rho_p = rho_p_orig; + // density in physical unit correspinding to code unit 1. + // const Real rho_g0 = pin->GetOrAddReal("dust", "rho_g0", 1.0); + const Real rho_g0 = cgsunit->mass0 / cgsunit->vol0; + // re-scale rho_p to account for rho_g0 for stopping_time calculation + rho_p /= rho_g0; + + // re-scale rho_p by prefactor coefficient + if (cgsunit->isurface_den) { + rho_p *= 0.5 * M_PI; + } else { + rho_p *= std::sqrt(M_PI / 8.); + rho_p /= cgsunit->length0; + } + params.Add("rho_p", rho_p); + } // Scratch for dust flux const int scr_level = pin->GetOrAddInteger("dust", "scr_level", 0); params.Add("scr_level", scr_level); @@ -207,6 +294,14 @@ std::shared_ptr Initialize(ParameterInput *pin) { m.SetSparseThresholds(0.0, 0.0, 0.0); dust->AddSparsePool(m, control_field, dustids); + // dust stopping-time + m = Metadata({Metadata::Cell, Metadata::Derived, Metadata::Intensive, Metadata::OneCopy, + Metadata::Sparse}); + m.SetSparseThresholds(0.0, 0.0, 0.0); + dust->AddSparsePool(m, control_field, dustids); + // std::vector stopping_id = {0}; + // dust->AddSparsePool(m, control_field, stopping_id); + // Dust hydrodynamics timestep if (coords == Coordinates::cartesian) { dust->EstimateTimestepMesh = EstimateTimestepMesh; @@ -227,6 +322,97 @@ std::shared_ptr Initialize(ParameterInput *pin) { return dust; } +//---------------------------------------------------------------------------------------- +//! \fn TaskStatus Dust::UpdateDustStoppingTime +// \brief Wrapper function for update dust stopping time +template +TaskStatus UpdateDustStoppingTime(MeshData *md) { + + using parthenon::MakePackDescriptor; + + auto pm = md->GetParentPointer(); + + auto &dust_pkg = pm->packages.Get("dust"); + if ((!dust_pkg->template Param("enable_dust_drag")) && + (!dust_pkg->template Param("enable_coagulation"))) { + return TaskStatus::complete; + } + + auto &resolved_pkgs = pm->resolved_packages; + + IndexRange ib = md->GetBoundsI(IndexDomain::interior); + IndexRange jb = md->GetBoundsJ(IndexDomain::interior); + IndexRange kb = md->GetBoundsK(IndexDomain::interior); + + const int nspecies = dust_pkg->template Param("nspecies"); + + const bool const_stopping_time = dust_pkg->template Param("const_stopping_time"); + + if (const_stopping_time) { + ParArray1D stoppingTime = + dust_pkg->template Param>("stopping_time"); + static auto desc = MakePackDescriptor(resolved_pkgs.get()); + + auto vmesh = desc.GetPack(md); + parthenon::par_for( + DEFAULT_LOOP_PATTERN, "Dust::DustStoppingTime", parthenon::DevExecSpace(), 0, + md->NumBlocks() - 1, kb.s, kb.e, jb.s, jb.e, ib.s, ib.e, + KOKKOS_LAMBDA(const int b, const int k, const int j, const int i) { + // usually the stopping time depends gas density, unless constant is used + // constant stopping time + for (int n = 0; n < nspecies; ++n) { + vmesh(b, dust::stopping_time(n), k, j, i) = stoppingTime(n); + } + }); + } else { + const bool isurf_den = cgsunit->isurface_den; + ParArray1D dust_size = dust_pkg->template Param>("sizes"); + static auto desc = + MakePackDescriptor( + resolved_pkgs.get()); + + auto vmesh = desc.GetPack(md); + + auto &gas_pkg = pm->packages.Get("gas"); + + const Real gamma = gas_pkg->template Param("adiabatic_index"); + const Real rho_p = dust_pkg->template Param("rho_p"); + + parthenon::par_for( + DEFAULT_LOOP_PATTERN, "Dust::DustStoppingTime2", parthenon::DevExecSpace(), 0, + md->NumBlocks() - 1, kb.s, kb.e, jb.s, jb.e, ib.s, ib.e, + KOKKOS_LAMBDA(const int b, const int k, const int j, const int i) { + const Real dens_g = vmesh(b, gas::prim::density(0), k, j, i); + // usually the Stokes number depends gas density, unless constant is used + // stopping_time = Stokes_number/Omega_k + + if (isurf_den) { + geometry::Coords coords(vmesh.GetCoordinates(b), k, j, i); + // for surface denstiy, Stokes number = Pi/2*rho_p*s_p/sigma_g + // calculate the Keplerian Omega at mid-plane + Real rad = coords.x1v(); + Real Omega_k = 1.0 / std::sqrt(rad) / rad; + for (int n = 0; n < nspecies; ++n) { + const Real St = rho_p * dust_size(n) / dens_g; + vmesh(b, dust::stopping_time(n), k, j, i) = St / Omega_k; + } + + } else { + + // for density (g/cc), Stokes number = sqrt(Pi/8)*rho_p*s_p*Omega_k/rho_g/Cs + const Real pres = vmesh(b, gas::prim::pressure(0), k, j, i); + const Real cs = std::sqrt(gamma * pres / dens_g); + for (int n = 0; n < nspecies; ++n) { + const Real StOme = rho_p * dust_size(n) / dens_g; + vmesh(b, dust::stopping_time(n), k, j, i) = StOme / cs; + } + } + }); + } + + return TaskStatus::complete; +} + //---------------------------------------------------------------------------------------- //! \fn Real Dust::EstimateTimestepMesh //! \brief Compute dust hydrodynamics timestep @@ -239,8 +425,24 @@ Real EstimateTimestepMesh(MeshData *md) { auto &dust_pkg = pm->packages.Get("dust"); auto ¶ms = dust_pkg->AllParams(); + auto dragDt = params.template Get("user_dt"); + auto nspecies = params.template Get("nspecies"); + + bool dt_stoppingTime = false; + if (params.template Get("enable_dust_drag")) { + UpdateDustStoppingTime(md); + if ((params.template Get("drag_method") == + DragMethod::explicitFeedback) || + (params.template Get("drag_method") == + DragMethod::explicitNoFeedback)) { + dt_stoppingTime = true; + } + } + + const auto cfl_number = params.template Get("cfl"); static auto desc = - MakePackDescriptor(resolved_pkgs.get()); + MakePackDescriptor( + resolved_pkgs.get()); auto vmesh = desc.GetPack(md); IndexRange ib = md->GetBoundsI(IndexDomain::interior); IndexRange jb = md->GetBoundsJ(IndexDomain::interior); @@ -261,13 +463,17 @@ Real EstimateTimestepMesh(MeshData *md) { for (int d = 0; d < ndim; d++) { denom += std::abs(vmesh(b, dust::prim::velocity(VI(n, d)), k, j, i)) / dx[d]; } - ldt = std::min(ldt, 1.0 / denom); + ldt = std::min(ldt, 1.0 / denom * cfl_number); + } + if (dt_stoppingTime) { + for (int n = 0; n < nspecies; ++n) { + ldt = std::min(ldt, vmesh(b, dust::stopping_time(n), k, j, i)); + } } }, Kokkos::Min(min_dt)); - const auto cfl_number = params.template Get("cfl"); - return cfl_number * min_dt; + return std::min(dragDt, min_dt); } //---------------------------------------------------------------------------------------- @@ -320,6 +526,535 @@ TaskStatus FluxSource(MeshData *md, const Real dt) { return TaskStatus::complete; } +//---------------------------------------------------------------------------------------- +//! \fn TaskStatus Dust::ApplyDragForceSelect +// \brief Wrapper function for dust-drag froce based on different drag-method +template +TaskStatus ApplyDragForceSelect(MeshData *md, const Real dt) { + + using parthenon::MakePackDescriptor; + + auto pm = md->GetParentPointer(); + auto &dust_pkg = pm->packages.Get("dust"); + IndexRange ib = md->GetBoundsI(IndexDomain::interior); + IndexRange jb = md->GetBoundsJ(IndexDomain::interior); + IndexRange kb = md->GetBoundsK(IndexDomain::interior); + + auto &resolved_pkgs = pm->resolved_packages; + auto &DUST_DRAG = dust_pkg->template Param("drag_method"); + + static auto desc = + MakePackDescriptor(resolved_pkgs.get()); + + auto vmesh = desc.GetPack(md); + + if ((DUST_DRAG == DragMethod::explicitFeedback) || + (DUST_DRAG == DragMethod::explicitNoFeedback)) { + parthenon::par_for( + DEFAULT_LOOP_PATTERN, "Dust::DustDrag", parthenon::DevExecSpace(), 0, + md->NumBlocks() - 1, kb.s, kb.e, jb.s, jb.e, ib.s, ib.e, + KOKKOS_LAMBDA(const int b, const int k, const int j, const int i) { + const Real dens_g = vmesh(b, gas::prim::density(0), k, j, i); + const int nspecies = vmesh.GetUpperBound(b, dust::prim::density()) - + vmesh.GetLowerBound(b, dust::prim::density()) + 1; + geometry::Coords coords(vmesh.GetCoordinates(b), k, j, i); + const auto &hx = coords.GetScaleFactors(); + + for (int n = 0; n < nspecies; ++n) { + const Real dens_d = vmesh(b, dust::prim::density(n), k, j, i); + const Real tst = vmesh(b, dust::stopping_time(n), k, j, i); + const Real cj = dt * dens_d / tst; + + vmesh(b, dust::cons::momentum(VI(n, 0)), k, j, i) += + cj * hx[0] * + (vmesh(b, gas::prim::velocity(0), k, j, i) - + vmesh(b, dust::prim::velocity(VI(n, 0)), k, j, i)); + + vmesh(b, dust::cons::momentum(VI(n, 1)), k, j, i) += + cj * hx[1] * + (vmesh(b, gas::prim::velocity(1), k, j, i) - + vmesh(b, dust::prim::velocity(VI(n, 1)), k, j, i)); + + vmesh(b, dust::cons::momentum(VI(n, 2)), k, j, i) += + cj * hx[2] * + (vmesh(b, gas::prim::velocity(2), k, j, i) - + vmesh(b, dust::prim::velocity(VI(n, 2)), k, j, i)); + } + if (DUST_DRAG == DragMethod::explicitFeedback) { + const Real dens_g = vmesh(b, gas::cons::density(0), k, j, i); + Real delta_mom1 = 0.0; + Real delta_mom2 = 0.0; + Real delta_mom3 = 0.0; + for (int n = 0; n < nspecies; ++n) { + const Real dens_d = vmesh(b, dust::prim::density(n), k, j, i); + const Real tst = vmesh(b, dust::stopping_time(n), k, j, i); + Real cj = dt * dens_d / tst; + delta_mom1 -= cj * (vmesh(b, gas::prim::velocity(0), k, j, i) - + vmesh(b, dust::prim::velocity(VI(n, 0)), k, j, i)); + delta_mom2 -= cj * (vmesh(b, gas::prim::velocity(1), k, j, i) - + vmesh(b, dust::prim::velocity(VI(n, 1)), k, j, i)); + delta_mom3 -= cj * (vmesh(b, gas::prim::velocity(2), k, j, i) - + vmesh(b, dust::prim::velocity(VI(n, 2)), k, j, i)); + } + vmesh(b, gas::cons::momentum(0), k, j, i) += delta_mom1 * hx[0]; + vmesh(b, gas::cons::momentum(1), k, j, i) += delta_mom2 * hx[1]; + vmesh(b, gas::cons::momentum(2), k, j, i) += delta_mom3 * hx[2]; + + // gas energy update: delta_E = delta_mom*(M_new - 0.5*delta_mom)/rho_g + // delta_E = 0.5*rhog*(V_new^2 - V_old^2) + + vmesh(b, gas::cons::total_energy(0), k, j, i) += + (delta_mom1 * (vmesh(b, gas::cons::momentum(0), k, j, i) / hx[0] - + delta_mom1 * 0.5) + + delta_mom2 * (vmesh(b, gas::cons::momentum(1), k, j, i) / hx[1] - + delta_mom2 * 0.5) + + delta_mom3 * (vmesh(b, gas::cons::momentum(2), k, j, i) / hx[2] - + delta_mom3 * 0.5)) / + dens_g; + } + }); + + } else if ((DUST_DRAG == DragMethod::implicitFeedback) || + (DUST_DRAG == DragMethod::implicitNoFeedback)) { + auto &dfloor = dust_pkg->template Param("dfloor"); + parthenon::par_for( + DEFAULT_LOOP_PATTERN, "Dust::DustDragImp", parthenon::DevExecSpace(), 0, + md->NumBlocks() - 1, kb.s, kb.e, jb.s, jb.e, ib.s, ib.e, + KOKKOS_LAMBDA(const int b, const int k, const int j, const int i) { + geometry::Coords coords(vmesh.GetCoordinates(b), k, j, i); + const auto &hx = coords.GetScaleFactors(); + const int nspecies = vmesh.GetUpperBound(b, dust::prim::density()) - + vmesh.GetLowerBound(b, dust::prim::density()) + 1; + + const Real dens_g = vmesh(b, gas::cons::density(0), k, j, i); + Real mom1_g = vmesh(b, gas::cons::momentum(0), k, j, i); + Real mom2_g = vmesh(b, gas::cons::momentum(1), k, j, i); + Real mom3_g = vmesh(b, gas::cons::momentum(2), k, j, i); + + Real vel1_g = mom1_g / (dens_g * hx[0]); + Real vel2_g = mom2_g / (dens_g * hx[1]); + Real vel3_g = mom3_g / (dens_g * hx[2]); + const Real coef1 = dens_g / vmesh(b, gas::prim::density(0), k, j, i); + + if (DUST_DRAG == DragMethod::implicitFeedback) { + + Real tmp1 = dens_g; + const Real vel1_go = vel1_g; + const Real vel2_go = vel2_g; + const Real vel3_go = vel3_g; + for (int n = 0; n < nspecies; ++n) { + const Real dens_d = vmesh(b, dust::cons::density(n), k, j, i); + const Real tst = vmesh(b, dust::stopping_time(n), k, j, i); + const Real cj = dt * dens_d / tst * coef1; // use updated dens_g + const Real bj1 = vmesh(b, dust::cons::momentum(VI(n, 0)), k, j, i); + const Real bj2 = vmesh(b, dust::cons::momentum(VI(n, 1)), k, j, i); + const Real bj3 = vmesh(b, dust::cons::momentum(VI(n, 2)), k, j, i); + const Real dj = dens_d + cj; + + const Real cjOdj = cj / dj; + tmp1 += (cj - cj * cjOdj); + mom1_g += bj1 * cjOdj; + mom2_g += bj2 * cjOdj; + mom3_g += bj3 * cjOdj; + } + + vel1_g = mom1_g / (tmp1 * hx[0]); + vel2_g = mom2_g / (tmp1 * hx[1]); + vel3_g = mom3_g / (tmp1 * hx[2]); + vmesh(b, gas::cons::momentum(0), k, j, i) = dens_g * vel1_g * hx[0]; + vmesh(b, gas::cons::momentum(1), k, j, i) = dens_g * vel2_g * hx[1]; + vmesh(b, gas::cons::momentum(2), k, j, i) = dens_g * vel3_g * hx[2]; + + // gas energy update: delta_E = 0.5*(v_new^2 - v_old^2)*rho_g + vmesh(b, gas::cons::total_energy(0), k, j, i) += + 0.5 * + (SQR(vel1_g) - SQR(vel1_go) + SQR(vel2_g) - SQR(vel2_go) + SQR(vel3_g) - + SQR(vel3_go)) * + dens_g; + } // end if (DUST_DRAG == DragMethod::implicitFeedback) + + // update the dust + for (int n = 0; n < nspecies; ++n) { + const Real dens_d = + std::max(dfloor, vmesh(b, dust::cons::density(n), k, j, i)); + const Real tst = vmesh(b, dust::stopping_time(n), k, j, i); + const Real cj = dt * dens_d / tst * coef1; // use updated dens_g + const Real bj1 = vmesh(b, dust::cons::momentum(VI(n, 0)), k, j, i); + const Real bj2 = vmesh(b, dust::cons::momentum(VI(n, 1)), k, j, i); + const Real bj3 = vmesh(b, dust::cons::momentum(VI(n, 2)), k, j, i); + const Real dj = dens_d + cj; + vmesh(b, dust::cons::momentum(VI(n, 0)), k, j, i) = + dens_d * (bj1 + cj * vel1_g * hx[0]) / dj; + vmesh(b, dust::cons::momentum(VI(n, 1)), k, j, i) = + dens_d * (bj2 + cj * vel2_g * hx[1]) / dj; + vmesh(b, dust::cons::momentum(VI(n, 2)), k, j, i) = + dens_d * (bj3 + cj * vel3_g * hx[2]) / dj; + } + }); + } + + return TaskStatus::complete; +} + +//---------------------------------------------------------------------------------------- +//! \fn TaskStatus Dust::ApplyDragForce +// \brief Wrapper function for dust-drag froce +TaskStatus ApplyDragForce(MeshData *md, const Real dt) { + + using parthenon::MakePackDescriptor; + + auto pm = md->GetParentPointer(); + auto &dust_pkg = pm->packages.Get("dust"); + if (!dust_pkg->template Param("enable_dust_drag")) { + return TaskStatus::complete; + } + + const Coordinates GEOM = dust_pkg->template Param("coords"); + + if (GEOM == Coordinates::cartesian) { + return ApplyDragForceSelect(md, dt); + } else if (GEOM == Coordinates::spherical1D) { + return ApplyDragForceSelect(md, dt); + } else if (GEOM == Coordinates::spherical2D) { + return ApplyDragForceSelect(md, dt); + } else if (GEOM == Coordinates::spherical3D) { + return ApplyDragForceSelect(md, dt); + } else if (GEOM == Coordinates::cylindrical) { + return ApplyDragForceSelect(md, dt); + } else if (GEOM == Coordinates::axisymmetric) { + return ApplyDragForceSelect(md, dt); + } else { + PARTHENON_FAIL("Coordinate type not recognized!"); + } +} + +//#define COAG_DEBUG +//---------------------------------------------------------------------------------------- +//! \fn TaskStatus Dust::CoagulationOneStep +// \brief Wrapper function for coagulation procedure in one time step +template +TaskStatus CoagulationOneStep(MeshData *md, const Real time, const Real dt) { + + using parthenon::MakePackDescriptor; + auto pm = md->GetParentPointer(); + auto &dust_pkg = pm->packages.Get("dust"); + IndexRange ib = md->GetBoundsI(IndexDomain::interior); + IndexRange jb = md->GetBoundsJ(IndexDomain::interior); + IndexRange kb = md->GetBoundsK(IndexDomain::interior); + + auto &gas_pkg = pm->packages.Get("gas"); + const Real gamma = gas_pkg->template Param("adiabatic_index"); + + auto &resolved_pkgs = pm->resolved_packages; + const int nspecies = dust_pkg->template Param("nspecies"); + + auto &coag_pkg = pm->packages.Get("coagulation"); + auto &coag = coag_pkg->template Param("coag_pars"); + + PARTHENON_REQUIRE(cgsunit->isSet(), + "coagulation requires setting code-to-physical unit in user routine"); + + static auto desc = + MakePackDescriptor(resolved_pkgs.get()); + + auto vmesh = desc.GetPack(md); + + const Real alpha = coag_pkg->template Param("coag_alpha"); // 1e-3 + const int nvel = 3; + + const int scr_level = coag_pkg->template Param("coag_scr_level"); + size_t isize = (5 + nvel) * nspecies; + if (coag.integrator == 3 && coag.mom_coag) isize += nspecies; + size_t scr_size = ScratchPad1D::shmem_size(isize); + const Real den0 = cgsunit->mass0 / cgsunit->vol0; + const Real time0 = cgsunit->time0; + // const Real vol0 = cgsunit->vol0; + const Real vel0 = cgsunit->length0 / cgsunit->time0; + + auto pmb = md->GetBlockData(0)->GetBlockPointer(); + ParArray3D nCalls("nCalls", pmb->cellbounds.ncellsk(IndexDomain::entire), + pmb->cellbounds.ncellsj(IndexDomain::entire), + pmb->cellbounds.ncellsi(IndexDomain::entire)); + + int maxCalls = 0, maxSize = 1; + auto &dfloor = dust_pkg->template Param("dfloor"); + + int maxSize0 = 1; + Real massd = 0.0; + Kokkos::parallel_reduce( + "coag::maxSize0", + Kokkos::MDRangePolicy>( + {0, kb.s, jb.s, ib.s}, {md->NumBlocks(), kb.e + 1, jb.e + 1, ib.e + 1}), + KOKKOS_LAMBDA(const int b, const int k, const int j, const int i, Real &lsum, + int &lmax) { + geometry::Coords coords(vmesh.GetCoordinates(b), k, j, i); + for (int n = 0; n < nspecies; ++n) { + Real &dens_d = vmesh(b, dust::cons::density(n), k, j, i); + lsum += dens_d * coords.Volume(); + } + for (int n = nspecies - 1; n >= 0; --n) { + Real &dens_d = vmesh(b, dust::cons::density(n), k, j, i); + if (dens_d > dfloor) { + lmax = std::max(lmax, n); + break; + } + } + }, + massd, Kokkos::Max(maxSize0)); +#ifdef MPI_PARALLEL + // Sum the perturbations over all processors + MPI_Reduce(MPI_IN_PLACE, &maxSize0, 1, MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD); + MPI_Reduce(MPI_IN_PLACE, &massd, 1, MPI_PARTHENON_REAL, MPI_SUM, 0, MPI_COMM_WORLD); +#endif // MPI_PARALLEL + + Real sumd1 = 0.0; +#ifdef COAG_DEBUG + ParArray3D floor_tmp("floor_tmp", 17, nspecies, 2); +#endif + for (int b = 0; b < md->NumBlocks(); b++) { + parthenon::par_for_outer( + DEFAULT_OUTER_LOOP_PATTERN, "Dust::Coagulation", parthenon::DevExecSpace(), + scr_size, scr_level, kb.s, kb.e, jb.s, jb.e, ib.s, ib.e, + KOKKOS_LAMBDA(parthenon::team_mbr_t mbr, const int k, const int j, const int i) { + // code-to-physical unit + // one-cell coagulation + const int nDust_live = (vmesh.GetUpperBound(b, dust::prim::density()) - + vmesh.GetLowerBound(b, dust::prim::density()) + 1); + + const Real dens_g = vmesh(b, gas::prim::density(0), k, j, i) * den0; + Real dt_sync = dt * time0; + const Real time1 = time * time0; + + geometry::Coords coords(vmesh.GetCoordinates(b), k, j, i); + const auto &hx = coords.GetScaleFactors(); + const Real rad = hx[2]; // cylindrical R_cyl + const Real Omega_k = 1.0 / std::sqrt(rad) / rad; + // const Real vol1 = coords.Volume() * vol0; + + int nCall1 = 0; + + const Real pres = vmesh(b, gas::prim::pressure(0), k, j, i); + const Real cs = std::sqrt(gamma * pres / dens_g * den0) * vel0; + const Real omega1 = Omega_k / time0; + const int nm = nspecies; + + ScratchPad1D rhod(mbr.team_scratch(scr_level), nspecies); + ScratchPad1D stime(mbr.team_scratch(scr_level), nspecies); + ScratchPad1D vel(mbr.team_scratch(scr_level), nvel * nspecies); + ScratchPad1D source(mbr.team_scratch(scr_level), nspecies); + ScratchPad1D Q(mbr.team_scratch(scr_level), nspecies); + ScratchPad1D nQs(mbr.team_scratch(scr_level), nspecies); + [[maybe_unused]] ScratchPad1D Q2; + if (coag.integrator == 3 && coag.mom_coag) { + Q2 = ScratchPad1D(mbr.team_scratch(scr_level), nspecies); + } + + parthenon::par_for_inner( + DEFAULT_INNER_LOOP_PATTERN, mbr, 0, nm - 1, [&](const int n) { + // for (int n = 0; n < nm; ++n) { + stime(n) = vmesh(b, dust::stopping_time(n), k, j, i) * time0; + if (vmesh(b, dust::prim::density(n), k, j, i) > dfloor) { + rhod(n) = vmesh(b, dust::prim::density(n), k, j, i) * den0; + vel(0 + n * 3) = + vmesh(b, dust::prim::velocity(VI(n, 0)), k, j, i) * vel0; + vel(1 + n * 3) = + vmesh(b, dust::prim::velocity(VI(n, 1)), k, j, i) * vel0; + vel(2 + n * 3) = + vmesh(b, dust::prim::velocity(VI(n, 2)), k, j, i) * vel0; + } else { + rhod(n) = 0.0; + vel(0 + n * 3) = 0.0; + vel(1 + n * 3) = 0.0; + vel(2 + n * 3) = 0.0; + } + }); + + Coagulation::CoagulationOneCell(mbr, i, time1, dt_sync, dens_g, rhod, stime, + vel, nvel, Q, nQs, alpha, cs, omega1, coag, + source, nCall1, Q2); + + nCalls(k, j, i) = nCall1; + + // update dust density and velocity after coagulation + parthenon::par_for_inner( + DEFAULT_INNER_LOOP_PATTERN, mbr, 0, nm - 1, [&](const int n) { + // for (int n = 0; n < nspecies; ++n) { + if (rhod(n) > 0.0) { + const Real rhod1 = rhod(n) / den0; + vmesh(b, dust::cons::density(n), k, j, i) = rhod1; + vmesh(b, dust::cons::momentum(VI(n, 0)), k, j, i) = + rhod1 * vel(0 + n * 3) * hx[0] / vel0; + vmesh(b, dust::cons::momentum(VI(n, 1)), k, j, i) = + rhod1 * vel(1 + n * 3) * hx[1] / vel0; + vmesh(b, dust::cons::momentum(VI(n, 2)), k, j, i) = + rhod1 * vel(2 + n * 3) * hx[2] / vel0; + } else { + vmesh(b, dust::cons::density(n), k, j, i) = 0.0; + vmesh(b, dust::cons::momentum(VI(n, 0)), k, j, i) = 0.0; + vmesh(b, dust::cons::momentum(VI(n, 1)), k, j, i) = 0.0; + vmesh(b, dust::cons::momentum(VI(n, 2)), k, j, i) = 0.0; + } + }); +#ifdef COAG_DEBUG + parthenon::par_for_inner( + DEFAULT_INNER_LOOP_PATTERN, mbr, 0, nm - 1, [&](const int n) { + // for (int n = 0; n < nspecies; n++) { + floor_tmp(i - ib.s, n, 0) = source(n); + floor_tmp(i - ib.s, n, 1) = vmesh(b, dust::cons::density(n), k, j, i); + }); +#endif + }); + + Real sumd0 = 0.0; + Kokkos::parallel_reduce( + "coag::nCallsMaximum", + Kokkos::MDRangePolicy>({kb.s, jb.s, ib.s}, + {kb.e + 1, jb.e + 1, ib.e + 1}), + KOKKOS_LAMBDA(const int k, const int j, const int i, Real &lsum, int &lmax1, + int &lmax2) { + geometry::Coords coords(vmesh.GetCoordinates(b), k, j, i); + const Real vol00 = coords.Volume(); + for (int n = 0; n < nspecies; ++n) { + Real &dens_d = vmesh(b, dust::cons::density(n), k, j, i); + lsum += dens_d * vol00; + } + lmax1 = std::max(lmax1, nCalls(k, j, i)); + for (int n = nspecies - 1; n >= 0; --n) { + Real &dens_d = vmesh(b, dust::cons::density(n), k, j, i); + if (dens_d > dfloor) { + lmax2 = std::max(lmax2, n); + break; + } + } + }, + Kokkos::Sum(sumd0), Kokkos::Max(maxCalls), Kokkos::Max(maxSize)); + sumd1 += sumd0; + } // loop of blocks + +#ifdef COAG_DEBUG + auto floor_h = + Kokkos::create_mirror_view_and_copy(parthenon::HostMemSpace(), floor_tmp); + for (int i = 0; i <= 0; i++) { + std::cout << "i=" << i << " "; + for (int n = 0; n < 20; n++) { + std::cout << floor_h(i, n, 0) << " "; + } + std::cout << std::endl; + + std::cout << "i=" << i << " "; + for (int n = 0; n < 20; n++) { + std::cout << floor_h(i, n, 1) << " "; + } + std::cout << std::endl; + } +#endif + +#ifdef MPI_PARALLEL + // over all processors + MPI_Reduce(MPI_IN_PLACE, &maxCalls, 1, MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD); + MPI_Reduce(MPI_IN_PLACE, &maxSize, 1, MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD); + MPI_Reduce(MPI_IN_PLACE, &sumd1, 1, MPI_PARTHENON_REAL, MPI_SUM, 0, MPI_COMM_WORLD); +#endif // MPI_PARALLEL + + if (parthenon::Globals::my_rank == 0) { + std::cout << "maxcalls,size= " << time << " " << maxCalls << " " << maxSize << " " + << maxSize0 << " " << time0 * dt << std::endl + << "total massd =" << time << " " << massd << " " << sumd1 << std::endl; + } + + return TaskStatus::complete; +} + +//---------------------------------------------------------------------------------------- +//! \fn TaskCollection Dust::OperatorSplitDust +//! \brief dust operator split task collection +template +TaskCollection OperatorSplitDust(Mesh *pm, parthenon::SimTime &tm, const Real dt) { + TaskCollection tc; + auto &coag_pkg = pm->packages.Get("coagulation"); + auto *dtCoag = coag_pkg->MutableParam("dtCoag"); + int nstep1Coag = coag_pkg->template Param("nstep1Coag"); + if (tm.ncycle == 0) { + *dtCoag = 0.0; + } + + *dtCoag += dt; + if ((tm.ncycle + 1) % nstep1Coag != 0) { + return tc; + } + + const Real time_local = tm.time + dt - (*dtCoag); + const Real dt_local = (*dtCoag); + if (parthenon::Globals::my_rank == 0) { + std::cout << "coagulation at: time,dt,cycle=" << time_local << " " << dt_local << " " + << tm.ncycle << std::endl; + } + + TaskID none(0); + + // Assemble tasks + using namespace ::parthenon::Update; + const int num_partitions = pm->DefaultNumPartitions(); + TaskRegion &tr = tc.AddRegion(num_partitions); + for (int i = 0; i < num_partitions; i++) { + auto &tl = tr[i]; + auto &base = pm->mesh_data.GetOrAdd("base", i); + auto coag_step = + tl.AddTask(none, CoagulationOneStep, base.get(), time_local, dt_local); + + // Set (remaining) fields to be communicated + auto pre_comm = tl.AddTask(coag_step, PreCommFillDerived>, base.get()); + + // Set boundary conditions (both physical and logical) + auto bcs = parthenon::AddBoundaryExchangeTasks(pre_comm, tl, base, pm->multilevel); + + // Update primitive variables + auto c2p = tl.AddTask(bcs, FillDerived>, base.get()); + } + *dtCoag = 0.0; + + return tc; +} + +//---------------------------------------------------------------------------------------- +//! \fn void Dust::ReduceD2gMaximum +// \brief calculate dust-to-gas ratio maximum +std::vector ReduceD2gMaximum(MeshData *md) { + auto pm = md->GetParentPointer(); + auto &resolved_pkgs = pm->resolved_packages; + + const auto ib = md->GetBoundsI(IndexDomain::interior); + const auto jb = md->GetBoundsJ(IndexDomain::interior); + const auto kb = md->GetBoundsK(IndexDomain::interior); + + static auto desc = + MakePackDescriptor(resolved_pkgs.get()); + auto vmesh = desc.GetPack(md); + const int nblocks = md->NumBlocks(); + std::vector max_d2g(1, 0); + parthenon::par_reduce( + parthenon::loop_pattern_mdrange_tag, "ReduceD2gMaximum", parthenon::DevExecSpace(), + 0, md->NumBlocks() - 1, kb.s, kb.e, jb.s, jb.e, ib.s, ib.e, + KOKKOS_LAMBDA(const int b, const int k, const int j, const int i, Real &lmax) { + const Real &rhog = vmesh(b, gas::prim::density(0), k, j, i); + const int nspecies = (vmesh.GetUpperBound(b, dust::prim::density()) - + vmesh.GetLowerBound(b, dust::prim::density())) + + 1; + Real rhod = 0.0; + for (int n = 0; n < nspecies; ++n) { + rhod += vmesh(b, dust::prim::density(n), k, j, i); + } + lmax = std::max(lmax, rhod / rhog); + }, + Kokkos::Max(max_d2g[0])); + return max_d2g; +} + //---------------------------------------------------------------------------------------- //! \fn void Dust::AddHistoryImpl //! \brief Add history outputs for dust quantities for generic coordinate system @@ -374,4 +1109,49 @@ template Real EstimateTimestepMesh(MeshData *md) template Real EstimateTimestepMesh(MeshData *md); template Real EstimateTimestepMesh(MeshData *md); +template TaskStatus UpdateDustStoppingTime(MeshData *md); +template TaskStatus UpdateDustStoppingTime(MeshData *md); +template TaskStatus UpdateDustStoppingTime(MeshData *md); +template TaskStatus UpdateDustStoppingTime(MeshData *md); +template TaskStatus UpdateDustStoppingTime(MeshData *md); +template TaskStatus UpdateDustStoppingTime(MeshData *md); + +template TaskStatus CoagulationOneStep(MeshData *md, + const Real time, + const Real dt); +template TaskStatus CoagulationOneStep(MeshData *md, + const Real time, + const Real dt); +template TaskStatus CoagulationOneStep(MeshData *md, + const Real time, + const Real dt); +template TaskStatus CoagulationOneStep(MeshData *md, + const Real time, + const Real dt); +template TaskStatus CoagulationOneStep(MeshData *md, + const Real time, + const Real dt); +template TaskStatus CoagulationOneStep(MeshData *md, + const Real time, + const Real dt); + +template TaskCollection OperatorSplitDust(Mesh *pm, + parthenon::SimTime &tm, + const Real dt); +template TaskCollection +OperatorSplitDust(Mesh *pm, parthenon::SimTime &tm, + const Real dt); +template TaskCollection +OperatorSplitDust(Mesh *pm, parthenon::SimTime &tm, + const Real dt); +template TaskCollection +OperatorSplitDust(Mesh *pm, parthenon::SimTime &tm, + const Real dt); +template TaskCollection +OperatorSplitDust(Mesh *pm, parthenon::SimTime &tm, + const Real dt); +template TaskCollection +OperatorSplitDust(Mesh *pm, parthenon::SimTime &tm, + const Real dt); + } // namespace Dust diff --git a/src/dust/dust.hpp b/src/dust/dust.hpp index 72be4ee..535240c 100644 --- a/src/dust/dust.hpp +++ b/src/dust/dust.hpp @@ -33,6 +33,65 @@ TaskStatus FluxSource(MeshData *md, const Real dt); void AddHistory(Coordinates coords, Params ¶ms); +struct CGSUnit { + Real mass0 = 1.0; + Real time0 = 1.0; + Real length0 = 1.0; + Real vol0 = 1.0; + bool isurface_den = true; + bool Code2PhysicalUnit_Set = false; + + bool isSet() const { return Code2PhysicalUnit_Set; } + + void SetCGSUnit(const Real &mass0_in, const Real &length0_in, const Real &time0_in, + const int isurf) { + if (!Code2PhysicalUnit_Set) { + mass0 = mass0_in; + length0 = length0_in; + vol0 = SQR(length0_in); + if (isurf == 0) vol0 *= length0_in; // 3D volume + time0 = time0_in; + Code2PhysicalUnit_Set = true; + } + } + + void SetCGSUnit(ParameterInput *pin) { + if (!Code2PhysicalUnit_Set) { + const Real M_SUN = 1.988409870698051e33; // gram (sun) + const Real AU_LENGTH = 1.4959787070000e13; // cm + const Real GRAV_CONST = + 6.674299999999999e-8; // gravitational const in cm^3 g^-1 s^-2 + + Real mstar = pin->GetOrAddReal("problem", "mstar", 1.0) * M_SUN; + length0 = pin->GetOrAddReal("problem", "r0_length", 1.0) * AU_LENGTH; + const Real omega0 = std::sqrt(GRAV_CONST * mstar / pow(length0, 3)); + time0 = 1. / omega0; + + const Real rho0 = pin->GetReal("problem", "rho0"); + mass0 = rho0 * mstar; + + isurface_den = pin->GetOrAddBoolean("dust", "surface_density_flag", true); + vol0 = SQR(length0); + if (isurface_den == 0) vol0 *= length0; // 3D volume + Code2PhysicalUnit_Set = true; + } + } +}; + +extern CGSUnit *cgsunit; + +template +TaskStatus UpdateDustStoppingTime(MeshData *md); + +TaskStatus ApplyDragForce(MeshData *md, const Real dt); + +// OperatorSplit tasks +template +TaskCollection OperatorSplitDust(Mesh *pm, parthenon::SimTime &tm, const Real dt); + +template +TaskStatus CoagulationOneStep(MeshData *md, const Real time, const Real dt); + } // namespace Dust #endif // DUST_DUST_HPP_ diff --git a/src/pgen/pgen.hpp b/src/pgen/pgen.hpp index abf5887..37228c1 100644 --- a/src/pgen/pgen.hpp +++ b/src/pgen/pgen.hpp @@ -23,6 +23,8 @@ #include "conduction.hpp" #include "constant.hpp" #include "disk.hpp" +#include "dust_coagulation.hpp" +#include "dust_collision.hpp" #include "gaussian_bump.hpp" #include "linear_wave.hpp" #include "shock.hpp" @@ -58,6 +60,10 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { strat::ProblemGenerator(pmb, pin); } else if (name == "thermalization") { thermalization::ProblemGenerator(pmb, pin); + } else if (name == "dust_collision") { + dust_collision::ProblemGenerator(pmb, pin); + } else if (name == "dust_coagulation") { + dust_coagulation::ProblemGenerator(pmb, pin); } else { PARTHENON_FAIL("Invalid problem name!"); } diff --git a/src/pgen/problem_modifier.hpp b/src/pgen/problem_modifier.hpp index 1b93dee..88f3956 100644 --- a/src/pgen/problem_modifier.hpp +++ b/src/pgen/problem_modifier.hpp @@ -126,6 +126,8 @@ void ProblemModifier(parthenon::ParthenonManager *pman) { strat::ExtrapInnerX3); pman->app_input->RegisterBoundaryCondition(BF::outer_x3, "extrap", strat::ExtrapOuterX3); + } else if (artemis_problem == "dust_collision") { + pman->app_input->PreStepMeshUserWorkInLoop = dust_collision::PreStepUserWorkInLoop; } // Register jaybenne swarm boundary conditions From b191975fc8b1c8708e09a5bdf3201e8ac19b516f Mon Sep 17 00:00:00 2001 From: Shengtai Li Date: Tue, 3 Dec 2024 23:19:41 -0700 Subject: [PATCH 2/9] add files from gitlab/sli/coagulation branch and merge with develop --- inputs/dust/SI_strat1_amr_BA.in | 146 ++++++ inputs/dust/SI_strat_AB.in | 135 +++++ inputs/dust/SI_strat_BA.in | 135 +++++ inputs/dust/disk_cyl_dust10.in | 105 ++++ inputs/dust/dust_coagulation.in | 109 ++++ inputs/dust/dust_coagulation_den.in | 108 ++++ inputs/dust/dust_collision.in | 86 ++++ src/dust/coagulation/coagulation.cpp | 308 ++++++++++++ src/dust/coagulation/coagulation.hpp | 719 +++++++++++++++++++++++++++ src/pgen/dust_coagulation.hpp | 190 +++++++ src/pgen/dust_collision.hpp | 239 +++++++++ 11 files changed, 2280 insertions(+) create mode 100644 inputs/dust/SI_strat1_amr_BA.in create mode 100644 inputs/dust/SI_strat_AB.in create mode 100644 inputs/dust/SI_strat_BA.in create mode 100644 inputs/dust/disk_cyl_dust10.in create mode 100644 inputs/dust/dust_coagulation.in create mode 100644 inputs/dust/dust_coagulation_den.in create mode 100644 inputs/dust/dust_collision.in create mode 100644 src/dust/coagulation/coagulation.cpp create mode 100644 src/dust/coagulation/coagulation.hpp create mode 100644 src/pgen/dust_coagulation.hpp create mode 100644 src/pgen/dust_collision.hpp diff --git a/inputs/dust/SI_strat1_amr_BA.in b/inputs/dust/SI_strat1_amr_BA.in new file mode 100644 index 0000000..8e3e24b --- /dev/null +++ b/inputs/dust/SI_strat1_amr_BA.in @@ -0,0 +1,146 @@ +# ======================================================================================== +# (C) (or copyright) 2023-2024. Triad National Security, LLC. All rights reserved. +# +# This program was produced under U.S. Government contract 89233218CNA000001 for Los +# Alamos National Laboratory (LANL), which is operated by Triad National Security, LLC +# for the U.S. Department of Energy/National Nuclear Security Administration. All rights +# in the program are reserved by Triad National Security, LLC, and the U.S. Department +# of Energy/National Nuclear Security Administration. The Government is granted for +# itself and others acting on its behalf a nonexclusive, paid-up, irrevocable worldwide +# license in this material to reproduce, prepare derivative works, distribute copies to +# the public, perform publicly and display publicly, and to permit others to do so. +# ======================================================================================== + + +problem = SI_strat # name of the pgen +coordinates = cartesian + + +problem_id = runBA # problem ID: basename of output filenames + + +file_type = hst +dt = 0.01 + + +variables = gas.prim.density, & + gas.prim.velocity, & + dust.prim.density, & + dust.prim.velocity + +file_type = hdf5 # HDF5 data dump +dt = 2.0 # time increment between outputs + + +file_type = rst +dt = 100.0 + + +nlim = -1 # cycle limit +tlim = 400.0 # time limit +integrator = rk2 # time integration algorithm +ncycle_out = 100 # interval for stdout summary info + + +nx1 = 1024 # Number of zones in X1-direction +x1min = -0.4 # minimum value of X1 +x1max = 0.4 # maximum value of X1 +ix1_bc = extrapolate # Inner-X1 boundary condition flag +ox1_bc = extrapolate # Outer-X1 boundary condition flag + +nx2 = 512 # Number of zones in X2-direction +x2min = -0.2 # minimum value of X2 +x2max = 0.2 # maximum value of X2 +ix2_bc = extrapolate # Inner-X2 boundary condition flag +ox2_bc = extrapolate # Outer-X2 boundary condition flag + +nx3 = 1 # Number of zones in X3-direction +x3min = -0.5 # minimum value of X3 +x3max = 0.5 # maximum value of X3 +ix3_bc = periodic # Inner-X3 boundary condition flag +ox3_bc = periodic # Outer-X3 boundary condition flag + +# nghost = 2 +refinement = static +numlevel = 2 #3 + + +x1min = -0.3 +x1max = 0.3 +x2min = -0.02 +x2max = 0.02 +level = 1 + + + + +nx1 = 16 # Number of cells in each MeshBlock, X1-dir +nx2 = 16 # Number of cells in each MeshBlock, X2-dir +nx3 = 16 # Number of cells in each MeshBlock, X3-dir + + +gas = true +gravity = false +rotating_frame = true +dust = true + + +cfl = 0.6 +gamma = 1.000001 +reconstruct = plm +riemann = hlle +dfloor = 1.0e-10 +siefloor = 1.0e-10 +refine_field = density +refine_type = magnitude +refine_thr = 3.0 +deref_thr = 0.8 + + +reconstruct = plm +riemann = hlle +nspecies = 1 +const_stopping_time = true +size_input = none +stopping_time = 0.3 +Hratio = 0.1 + +hst_out_d2g = true +Kai0 = 0.1 #2*etaVk*iso_cs + +enable_dust_drag = true +enable_dust_feedback = true +drag_method = implicit +#rho_p = 1.25 +#rho_g0 = 0.3555 #g/cm^2, code-to-physical convert +#user_input_size = true +#Size_1 = 10.0 # dust size + + + +#type = uniform +#gx1 = 0.1 # 2*etaVk*Ome0 +#gx2 = 0.0 +#gx3 = 0.0 + +#type = point +#gm = 1e-5 +#soft = .03 +#x = 0 +#y = 0 +#z = 0 + + +omega = 1.0 +qshear = 1.5 +shboxcoord = 2 # 1=xy; 2=xz +stratified_flag = true + + +rho0 = 0.3989422804 #1.0/sqrt(2*pi) +dens_min = 1.0e-10 +pres_min = 1.0e-13 +h = 1.0 +etaVk = 0.05 +amp = 0.1 +dust_to_gas = 0.04 diff --git a/inputs/dust/SI_strat_AB.in b/inputs/dust/SI_strat_AB.in new file mode 100644 index 0000000..0cd6953 --- /dev/null +++ b/inputs/dust/SI_strat_AB.in @@ -0,0 +1,135 @@ +# ======================================================================================== +# (C) (or copyright) 2023-2024. Triad National Security, LLC. All rights reserved. +# +# This program was produced under U.S. Government contract 89233218CNA000001 for Los +# Alamos National Laboratory (LANL), which is operated by Triad National Security, LLC +# for the U.S. Department of Energy/National Nuclear Security Administration. All rights +# in the program are reserved by Triad National Security, LLC, and the U.S. Department +# of Energy/National Nuclear Security Administration. The Government is granted for +# itself and others acting on its behalf a nonexclusive, paid-up, irrevocable worldwide +# license in this material to reproduce, prepare derivative works, distribute copies to +# the public, perform publicly and display publicly, and to permit others to do so. +# ======================================================================================== + + +problem = SI_strat # name of the pgen +coordinates = cartesian + + +problem_id = runAB # problem ID: basename of output filenames + + +file_type = hst +dt = 0.01 + + +variables = gas.prim.density, & + gas.prim.velocity, & + dust.prim.density, & + dust.prim.velocity + +file_type = hdf5 # HDF5 data dump +dt = 0.5 # time increment between outputs + + +file_type = rst +dt = 20.0 + + +nlim = -1 # cycle limit +tlim = 40.0 # time limit +integrator = rk2 # time integration algorithm +ncycle_out = 20 # interval for stdout summary info + + +nx1 = 512 # Number of zones in X1-direction +x1min = -0.05 # minimum value of X1 +x1max = 0.05 # maximum value of X1 +ix1_bc = extrapolate # Inner-X1 boundary condition flag +ox1_bc = extrapolate # Outer-X1 boundary condition flag + +nx2 = 512 # Number of zones in X2-direction +x2min = -0.05 # minimum value of X2 +x2max = 0.05 # maximum value of X2 +ix2_bc = periodic # Inner-X2 boundary condition flag +ox2_bc = periodic # Outer-X2 boundary condition flag + +nx3 = 1 # Number of zones in X3-direction +x3min = -0.5 # minimum value of X3 +x3max = 0.5 # maximum value of X3 +ix3_bc = periodic # Inner-X3 boundary condition flag +ox3_bc = periodic # Outer-X3 boundary condition flag + +# nghost = 2 +# refinement = adaptive +# numlevel = 4 + + +nx1 = 16 # Number of cells in each MeshBlock, X1-dir +nx2 = 16 # Number of cells in each MeshBlock, X2-dir +nx3 = 1 # Number of cells in each MeshBlock, X3-dir + + +gas = true +gravity = false +rotating_frame = true +dust = true + + +cfl = 0.6 +gamma = 1.000001 +reconstruct = plm +riemann = hlle +dfloor = 1.0e-10 +siefloor = 1.0e-10 +refine_field = density +refine_type = magnitude +refine_thr = 3.0 +deref_thr = 0.8 + + +reconstruct = plm +riemann = hlle +nspecies = 1 +const_stopping_time = true +size_input = none +stopping_time = 0.1 +hst_out_d2g = true +Kai0 = 0.1 #2*etaVk*iso_cs + +enable_dust_drag = true +enable_dust_feedback = true +drag_method = explicit +#rho_p = 1.25 +#rho_g0 = 0.3555 #g/cm^2, code-to-physical convert +#user_input_size = true +#Size_1 = 10.0 # dust size + + + +#type = uniform +#gx1 = 0.1 # 2*etaVk*Ome0 +#gx2 = 0.0 +#gx3 = 0.0 + +#type = point +#gm = 1e-5 +#soft = .03 +#x = 0 +#y = 0 +#z = 0 + + +omega = 1.0 +qshear = 1.5 +shboxcoord = 2 # 1=xy; 2=xz +stratified_flag = false + + +rho0 = 1.0 +dens_min = 1.0e-10 +pres_min = 1.0e-13 +h = 1.0 +etaVk = 0.05 +amp = 0.25 +dust_to_gas = 1.0 diff --git a/inputs/dust/SI_strat_BA.in b/inputs/dust/SI_strat_BA.in new file mode 100644 index 0000000..edb8caf --- /dev/null +++ b/inputs/dust/SI_strat_BA.in @@ -0,0 +1,135 @@ +# ======================================================================================== +# (C) (or copyright) 2023-2024. Triad National Security, LLC. All rights reserved. +# +# This program was produced under U.S. Government contract 89233218CNA000001 for Los +# Alamos National Laboratory (LANL), which is operated by Triad National Security, LLC +# for the U.S. Department of Energy/National Nuclear Security Administration. All rights +# in the program are reserved by Triad National Security, LLC, and the U.S. Department +# of Energy/National Nuclear Security Administration. The Government is granted for +# itself and others acting on its behalf a nonexclusive, paid-up, irrevocable worldwide +# license in this material to reproduce, prepare derivative works, distribute copies to +# the public, perform publicly and display publicly, and to permit others to do so. +# ======================================================================================== + + +problem = SI_strat # name of the pgen +coordinates = cartesian + + +problem_id = runBA # problem ID: basename of output filenames + + +file_type = hst +dt = 0.02 + + +variables = gas.prim.density, & + gas.prim.velocity, & + dust.prim.density, & + dust.prim.velocity + +file_type = hdf5 # HDF5 data dump +dt = 10 # time increment between outputs + + +file_type = rst +dt = 100.0 + + +nlim = -1 # cycle limit +tlim = 800.0 # time limit +integrator = rk2 # time integration algorithm +ncycle_out = 20 # interval for stdout summary info + + +nx1 = 512 # Number of zones in X1-direction +x1min = -1.0 # minimum value of X1 +x1max = 1.0 # maximum value of X1 +ix1_bc = extrapolate # Inner-X1 boundary condition flag +ox1_bc = extrapolate # Outer-X1 boundary condition flag + +nx2 = 512 # Number of zones in X2-direction +x2min = -1.0 # minimum value of X2 +x2max = 1.0 # maximum value of X2 +ix2_bc = periodic # Inner-X2 boundary condition flag +ox2_bc = periodic # Outer-X2 boundary condition flag + +nx3 = 1 # Number of zones in X3-direction +x3min = -0.5 # minimum value of X3 +x3max = 0.5 # maximum value of X3 +ix3_bc = periodic # Inner-X3 boundary condition flag +ox3_bc = periodic # Outer-X3 boundary condition flag + +# nghost = 2 +# refinement = adaptive +# numlevel = 4 + + +nx1 = 16 # Number of cells in each MeshBlock, X1-dir +nx2 = 16 # Number of cells in each MeshBlock, X2-dir +nx3 = 16 # Number of cells in each MeshBlock, X3-dir + + +gas = true +gravity = false +rotating_frame = true +dust = true + + +cfl = 0.6 +gamma = 1.000001 +reconstruct = plm +riemann = hlle +dfloor = 1.0e-10 +siefloor = 1.0e-10 +refine_field = density +refine_type = magnitude +refine_thr = 3.0 +deref_thr = 0.8 + + +reconstruct = plm +riemann = hlle +nspecies = 1 +const_stopping_time = true +size_input = none +stopping_time = 1.0 +hst_out_d2g = true +Kai0 = 0.1 #2*etaVk*iso_cs + +enable_dust_drag = true +enable_dust_feedback = true +drag_method = implicit +#rho_p = 1.25 +#rho_g0 = 0.3555 #g/cm^2, code-to-physical convert +#user_input_size = true +#Size_1 = 10.0 # dust size + + + +#type = uniform +#gx1 = 0.1 # 2*etaVk*Ome0 +#gx2 = 0.0 +#gx3 = 0.0 + +#type = point +#gm = 1e-5 +#soft = .03 +#x = 0 +#y = 0 +#z = 0 + + +omega = 1.0 +qshear = 1.5 +shboxcoord = 2 # 1=xy; 2=xz +stratified_flag = false + + +rho0 = 1.0 +dens_min = 1.0e-10 +pres_min = 1.0e-13 +h = 1.0 +etaVk = 0.05 +amp = 0.1 +dust_to_gas = 0.2 diff --git a/inputs/dust/disk_cyl_dust10.in b/inputs/dust/disk_cyl_dust10.in new file mode 100644 index 0000000..79bed84 --- /dev/null +++ b/inputs/dust/disk_cyl_dust10.in @@ -0,0 +1,105 @@ +# ======================================================================================== +# (C) (or copyright) 2023-2024. Triad National Security, LLC. All rights reserved. +# +# This program was produced under U.S. Government contract 89233218CNA000001 for Los +# Alamos National Laboratory (LANL), which is operated by Triad National Security, LLC +# for the U.S. Department of Energy/National Nuclear Security Administration. All rights +# in the program are reserved by Triad National Security, LLC, and the U.S. Department +# of Energy/National Nuclear Security Administration. The Government is granted for +# itself and others acting on its behalf a nonexclusive, paid-up, irrevocable worldwide +# license in this material to reproduce, prepare derivative works, distribute copies to +# the public, perform publicly and display publicly, and to permit others to do so. +# ======================================================================================== + + +problem = disk # name of the pgen +coordinates = axisymmetric #cylindrical # coordinate system + + +problem_id = disk_cyl # problem ID: basename of output filenames + + +file_type = hst +dt = 0.5 + + +variables = gas.prim.density, & + gas.prim.velocity, & + gas.prim.pressure, & + dust.prim.density, & + dust.prim.velocity, & + dust.stopping_time +file_type = hdf5 # HDF5 data dump +dt = 5.0 # time increment between outputs + + +nlim = -1 # cycle limit +tlim = 62.8 # time limit +integrator = rk2 # time integration algorithm +ncycle_out = 1 # interval for stdout summary info + + +nx1 = 128 # Number of zones in X1-direction +x1min = 0.4 # minimum value of X1 +x1max = 2.0 # maximum value of X1 +ix1_bc = ic # Inner-X1 boundary condition flag +ox1_bc = ic # Outer-X1 boundary condition flag + +nx2 = 1 # Number of zones in X2-direction +x2min = 0.0 # minimum value of X2 +x2max = 6.283185307179586 # maximum value of X2 +ix2_bc = periodic # Inner-X2 boundary condition flag +ox2_bc = periodic # Outer-X2 boundary condition flag + +nx3 = 1 # Number of zones in X3-direction +x3min = -0.5 # minimum value of X3 +x3max = 0.5 # maximum value of X3 +ix3_bc = outflow # Inner-X3 boundary condition flag +ox3_bc = outflow # Outer-X3 boundary condition flag + + +nx1 = 128 # Number of cells in each MeshBlock, X1-dir +nx2 = 1 # Number of cells in each MeshBlock, X2-dir +nx3 = 1 # Number of cells in each MeshBlock, X3-dir + + +gas = true +dust = true +gravity = true + + +cfl = 0.8 +gamma = 1.01 +reconstruct = plm +riemann = hllc +dfloor = 1.0e-10 +siefloor = 1.0e-10 + + +reconstruct = plm +riemann = hlle +nspecies = 1 +const_stopping_time = false +enable_dust_drag = true +enable_dust_feedback = true +drag_method = implicit +grain_density = 1.25 +#rho_g0 = 0.3555 #g/cm^2, code-to-physical convert +size_input = direct +sizes = 10.0 # dust size, cm +surface_density_flag = true; #surface or volume density + + +gm = 1.0 + + + +r0 = 1.0 +rho0 = 1.0e-4 #pre-factor +dslope = -1.0 +tslope = -0.5 +h0 = 0.05 +dens_min = 1.0e-10 +pres_min = 1.0e-13 +mstar = 1.0 # Msun +r0_length = 10.0 # AU diff --git a/inputs/dust/dust_coagulation.in b/inputs/dust/dust_coagulation.in new file mode 100644 index 0000000..36455d5 --- /dev/null +++ b/inputs/dust/dust_coagulation.in @@ -0,0 +1,109 @@ +# ======================================================================================== +# (C) (or copyright) 2023-2024. Triad National Security, LLC. All rights reserved. +# +# This program was produced under U.S. Government contract 89233218CNA000001 for Los +# Alamos National Laboratory (LANL), which is operated by Triad National Security, LLC +# for the U.S. Department of Energy/National Nuclear Security Administration. All rights +# in the program are reserved by Triad National Security, LLC, and the U.S. Department +# of Energy/National Nuclear Security Administration. The Government is granted for +# itself and others acting on its behalf a nonexclusive, paid-up, irrevocable worldwide +# license in this material to reproduce, prepare derivative works, distribute copies to +# the public, perform publicly and display publicly, and to permit others to do so. +# ======================================================================================== + + +problem = dust_coagulation # name of the pgen +coordinates = cartesian # coordinate system + + +problem_id = coag # problem ID: basename of output filenames + + + +file_type = hst +dt = 0.628 + + +variables = gas.prim.density, & + dust.prim.density +file_type = hdf5 # tab data dump +dt = 62.8 # time increment between outputs + + +file_type = rst +dt = 628 + + +nlim = -1 # cycle limit +tlim = 6280. # time limit +integrator = rk2 # time integration algorithm +ncycle_out = 1 # interval for stdout summary info + + +nghost = 2 +refinement = none +# numlevel = 1 + +nx1 = 16 # Number of zones in X1-direction +x1min = 9.0 # minimum value of X1 +x1max = 11.0 # maximum value of X1 +ix1_bc = outflow # Inner-X1 boundary condition flag +ox1_bc = outflow # Outer-X1 boundary condition flag + +nx2 = 1 # Number of zones in X2-direction +x2min = 0.0 # minimum value of X2 +x2max = 6.283185307179586 # maximum value of X2 +ix2_bc = periodic # Inner-X2 boundary condition flag +ox2_bc = periodic # Outer-X2 boundary condition flag + +nx3 = 1 # Number of zones in X3-direction +x3min = -0.5 # minimum value of X3 +x3max = 0.5 # maximum value of X3 +ix3_bc = periodic # Inner-X3 boundary condition flag +ox3_bc = periodic # Outer-X3 boundary condition flag + + +nx1 = 16 # Number of cells in each MeshBlock, X1-dir +nx2 = 1 # Number of cells in each MeshBlock, X2-dir +nx3 = 1 # Number of cells in each MeshBlock, X3-dir + + +gas = true +dust = true +coagulation = true + + +cfl = 0.9 +gamma = 1.00001 +iso_sound_speed = 0.05 + + +cfl = 0.9 +nspecies = 121 +const_stopping_time = false +enable_dust_drag = false +enable_dust_feedback = false +drag_method = implicit +#user_dt = 0.005 + + +scr_level = 1 # for reconstruction +surface_density_flag = true +grain_density = 1.25 # dust internal density g/cc +size_input = logspace +min_size = 1e-5 #cm +max_size = 10.0 #cm +vfrag = 1000.0 $cm/s +coag_int = 1 +coag_use_adaptiveStep = false +coag_mom_preserve = true + + + +nInit_dust = 11 # number of dust species initially +dust_to_gas = 0.01 +nstep1Coag = 10 +mstar = 1.0 # central star masss (m_sun) +r0_length = 10.0 # 1 code unit (AU) +rho0 = 2e-5 # code unit value of 1 m_star/r0_length^2 + diff --git a/inputs/dust/dust_coagulation_den.in b/inputs/dust/dust_coagulation_den.in new file mode 100644 index 0000000..be3707b --- /dev/null +++ b/inputs/dust/dust_coagulation_den.in @@ -0,0 +1,108 @@ +# ======================================================================================== +# (C) (or copyright) 2023-2024. Triad National Security, LLC. All rights reserved. +# +# This program was produced under U.S. Government contract 89233218CNA000001 for Los +# Alamos National Laboratory (LANL), which is operated by Triad National Security, LLC +# for the U.S. Department of Energy/National Nuclear Security Administration. All rights +# in the program are reserved by Triad National Security, LLC, and the U.S. Department +# of Energy/National Nuclear Security Administration. The Government is granted for +# itself and others acting on its behalf a nonexclusive, paid-up, irrevocable worldwide +# license in this material to reproduce, prepare derivative works, distribute copies to +# the public, perform publicly and display publicly, and to permit others to do so. +# ======================================================================================== + + +problem = dust_coagulation # name of the pgen +coordinates = cartesian # coordinate system + + +problem_id = coag # problem ID: basename of output filenames + + + +file_type = hst +dt = 0.628 + + +variables = gas.prim.density, & + dust.prim.density +file_type = hdf5 # tab data dump +dt = 62.8 # time increment between outputs + + +file_type = rst +dt = 628 + + +nlim = -1 # cycle limit +tlim = 6280. # time limit +integrator = rk2 # time integration algorithm +ncycle_out = 1 # interval for stdout summary info + + +nghost = 2 +refinement = none +# numlevel = 1 + +nx1 = 16 # Number of zones in X1-direction +x1min = 9.0 # minimum value of X1 +x1max = 11.0 # maximum value of X1 +ix1_bc = outflow # Inner-X1 boundary condition flag +ox1_bc = outflow # Outer-X1 boundary condition flag + +nx2 = 1 # Number of zones in X2-direction +x2min = 0.0 # minimum value of X2 +x2max = 6.283185307179586 # maximum value of X2 +ix2_bc = periodic # Inner-X2 boundary condition flag +ox2_bc = periodic # Outer-X2 boundary condition flag + +nx3 = 1 # Number of zones in X3-direction +x3min = -0.5 # minimum value of X3 +x3max = 0.5 # maximum value of X3 +ix3_bc = periodic # Inner-X3 boundary condition flag +ox3_bc = periodic # Outer-X3 boundary condition flag + + +nx1 = 16 # Number of cells in each MeshBlock, X1-dir +nx2 = 1 # Number of cells in each MeshBlock, X2-dir +nx3 = 1 # Number of cells in each MeshBlock, X3-dir + + +gas = true +dust = true +coagulation = true + + +cfl = 0.9 +gamma = 1.00001 +iso_sound_speed = 0.05 + + +cfl = 0.9 +nspecies = 121 +const_stopping_time = false +enable_dust_drag = false +enable_dust_feedback = false +drag_method = implicit +#user_dt = 0.005 + +scr_level = 1 # for reconstruction +surface_density_flag = false +grain_density = 1.25 # dust internal density g/cc +min_size = 1e-5 #cm +max_size = 10.0 #cm +size_input = logspace +vfrag = 1000.0 $cm/s +coag_int = 1 +coag_use_adaptiveStep = false +coag_mom_preserve = false + + + +nInit_dust = 11 # number of dust species initially +dust_to_gas = 0.01 +nstep1Coag = 10 +mstar = 1.0 # central star masss (m_sun) +r0_length = 10.0 # 1 code unit (AU) +#rho0 = 2e-5 # code unit value of 1 m_star/r0_length^2 +rho0 = 1.59577e-4 # 3D rho diff --git a/inputs/dust/dust_collision.in b/inputs/dust/dust_collision.in new file mode 100644 index 0000000..09a08df --- /dev/null +++ b/inputs/dust/dust_collision.in @@ -0,0 +1,86 @@ +# ======================================================================================== +# (C) (or copyright) 2023-2024. Triad National Security, LLC. All rights reserved. +# +# This program was produced under U.S. Government contract 89233218CNA000001 for Los +# Alamos National Laboratory (LANL), which is operated by Triad National Security, LLC +# for the U.S. Department of Energy/National Nuclear Security Administration. All rights +# in the program are reserved by Triad National Security, LLC, and the U.S. Department +# of Energy/National Nuclear Security Administration. The Government is granted for +# itself and others acting on its behalf a nonexclusive, paid-up, irrevocable worldwide +# license in this material to reproduce, prepare derivative works, distribute copies to +# the public, perform publicly and display publicly, and to permit others to do so. +# ======================================================================================== + + +problem = dust_collision # name of the pgen +coordinates = cartesian # coordinate system + + +problem_id = dc_B # problem ID: basename of output filenames + + +variables = gas.prim.density, & + gas.prim.velocity, & + gas.prim.pressure, & + dust.prim.density, & + dust.prim.velocity +file_type = hdf5 # tab data dump +dt = 0.05 # time increment between outputs + + +nlim = -1 # cycle limit +tlim = 0.05 # time limit +integrator = rk2 # time integration algorithm +ncycle_out = 1 # interval for stdout summary info + + +nghost = 2 +refinement = none +# numlevel = 1 + +nx1 = 16 # Number of zones in X1-direction +x1min = 0.0 # minimum value of X1 +x1max = 1.0 # maximum value of X1 +ix1_bc = periodic # Inner-X1 boundary condition flag +ox1_bc = periodic # Outer-X1 boundary condition flag + +nx2 = 1 # Number of zones in X2-direction +x2min = -0.5 # minimum value of X2 +x2max = 0.5 # maximum value of X2 +ix2_bc = periodic # Inner-X2 boundary condition flag +ox2_bc = periodic # Outer-X2 boundary condition flag + +nx3 = 1 # Number of zones in X3-direction +x3min = -0.5 # minimum value of X3 +x3max = 0.5 # maximum value of X3 +ix3_bc = periodic # Inner-X3 boundary condition flag +ox3_bc = periodic # Outer-X3 boundary condition flag + + +nx1 = 16 # Number of cells in each MeshBlock, X1-dir +nx2 = 1 # Number of cells in each MeshBlock, X2-dir +nx3 = 1 # Number of cells in each MeshBlock, X3-dir + + +gas = true +dust = true + + +cfl = 0.9 +gamma = 1.4 +iso_sound_speed = 0.1 + + +cfl = 0.9 +nspecies = 2 +const_stopping_time = true +enable_dust_drag = true +enable_dust_feedback = true +drag_method = implicit +user_dt = 0.005 + +size_input = none +stopping_time = 0.01, 0.002 + + +iprob = 1 diff --git a/src/dust/coagulation/coagulation.cpp b/src/dust/coagulation/coagulation.cpp new file mode 100644 index 0000000..8431598 --- /dev/null +++ b/src/dust/coagulation/coagulation.cpp @@ -0,0 +1,308 @@ +//======================================================================================== +// (C) (or copyright) 2023-2024. Triad National Security, LLC. All rights reserved. +// +// This program was produced under U.S. Government contract 89233218CNA000001 for Los +// Alamos National Laboratory (LANL), which is operated by Triad National Security, LLC +// for the U.S. Department of Energy/National Nuclear Security Administration. All rights +// in the program are reserved by Triad National Security, LLC, and the U.S. Department +// of Energy/National Nuclear Security Administration. The Government is granted for +// itself and others acting on its behalf a nonexclusive, paid-up, irrevocable worldwide +// license in this material to reproduce, prepare derivative works, distribute copies to +// the public, perform publicly and display publicly, and to permit others to do so. +//======================================================================================== + +// Artemis includes +#include "dust/coagulation/coagulation.hpp" +#include "artemis.hpp" +#include "dust/dust.hpp" +#include "geometry/geometry.hpp" + +using namespace parthenon::package::prelude; + +namespace Dust { +namespace Coagulation { +//---------------------------------------------------------------------------------------- +//! \fn StateDescriptor Coagulalation::Initialize +//! \brief Adds intialization function for coagulation package +std::shared_ptr Initialize(ParameterInput *pin) { + auto coag = std::make_shared("coagulation"); + Params ¶ms = coag->AllParams(); + + CoagParams cpars; + const int nm = pin->GetOrAddInteger("dust", "nspecies", 1); + cpars.nm = nm; + cpars.vfrag = pin->GetOrAddReal("dust", "vfrag", 1.e3); // cm/s + cpars.nlim = 1e10; + cpars.integrator = pin->GetOrAddInteger("dust", "coag_int", 3); + cpars.use_adaptive = pin->GetOrAddBoolean("dust", "coag_use_adaptiveStep", true); + cpars.mom_coag = pin->GetOrAddBoolean("dust", "coag_mom_preserve", true); + cpars.nCall_mx = pin->GetOrAddInteger("dust", "coag_nsteps_mx", 1000); + // dust particle internal density g/cc + const Real rho_p = pin->GetOrAddReal("dust", "rho_p", 1.25); + cpars.rho_p = rho_p; + + cpars.ibounce = pin->GetOrAddBoolean("dust", "coag_bounce", false); + + int coord_type = 0; // density + + const bool isurface_den = pin->GetOrAddBoolean("dust", "surface_density_flag", true); + if (isurface_den) coord_type = 1; + cpars.coord = coord_type; // 1--surface density, 0: 3D + + cpars.err_eps = 1.0e-1; + cpars.S = 0.9; + cpars.cfl = 1.0e-1; + cpars.chi = 1.0; + + // some checks and definition + if (cpars.use_adaptive) { + if (cpars.integrator == 3) { + cpars.pgrow = -0.5; + cpars.pshrink = -1.0; + } else if (cpars.integrator == 5) { + cpars.pgrow = -0.2; + cpars.pshrink = -0.25; + } else { + std::stringstream msg; + msg << "### FATAL ERROR in dust coagulation initialization: " << std::endl + << "### You can not use this integrator with adaptive step sizing: " + << cpars.integrator << std::endl; + PARTHENON_FAIL(msg); + } + cpars.errcon = std::pow((5. / cpars.S), (1. / cpars.pgrow)); + } + + const Real s_min = pin->GetReal("dust", "min_size"); + const Real s_max = pin->GetReal("dust", "max_size"); + const Real mmin = 4.0 * M_PI / 3.0 * rho_p * std::pow(s_min, 3); + const Real mmax = 4.0 * M_PI / 3.0 * rho_p * std::pow(s_max, 3); + const Real cond = 1.0 / (1.0 - nm) * std::log(mmin / mmax); + const Real conc = std::log(mmin); + if (std::exp(cond) > std::sqrt(2.0)) { + std::stringstream msg; + msg << "### FATAL ERROR in dust with coagulation: using nspecies >" + << std::log(mmax / mmin) / (std::log(std::sqrt(2.0))) + 1. << " instead of " << nm + << std::endl; + PARTHENON_FAIL(msg); + } + + ParArray1D dust_size("dustSize", nm); + auto dust_size_host = dust_size.GetHostMirror(); + + for (int n = 0; n < nm; ++n) { + Real mgrid = std::exp(conc + cond * n); + dust_size_host(n) = std::pow(3.0 * mgrid / (4.0 * M_PI * cpars.rho_p), 1. / 3.); + } + dust_size.DeepCopy(dust_size_host); + + // allocate array and assign values + cpars.klf = ParArray2D("klf", nm, nm); + cpars.mass_grid = ParArray1D("mass_grid", nm); + const int n2DRv = coag2DRv::last2; + cpars.coagR3D = ParArray3D("coagReal3D", n2DRv, nm, nm); + cpars.cpod_notzero = ParArray3D("idx_nzcpod", nm, nm, 4); + cpars.cpod_short = ParArray3D("nzcpod", nm, nm, 4); + + if (Dust::cgsunit == NULL) { + Dust::cgsunit = new CGSUnit; + } + if (!Dust::cgsunit->isSet()) { + Dust::cgsunit->SetCGSUnit(pin); + } + const Real dfloor = pin->GetOrAddReal("dust", "dfloor", 1.0e-25); + // convert to CGS unit + cpars.dfloor = dfloor * Dust::cgsunit->mass0 / Dust::cgsunit->vol0; + Real a = std::log10(mmin / mmax) / static_cast(1 - nm); + + initializeArray(nm, cpars.pGrid, cpars.rho_p, cpars.chi, a, dust_size, cpars.klf, + cpars.mass_grid, cpars.coagR3D, cpars.cpod_notzero, cpars.cpod_short); + + params.Add("coag_pars", cpars); + + // other parameters for coagulation + const int nstep1Coag = pin->GetOrAddReal("problem", "nstep1Coag", 50); + params.Add("nstep1Coag", nstep1Coag); + Real dtCoag = 0.0; + params.Add("dtCoag", dtCoag, Params::Mutability::Restart); + const Real alpha = pin->GetOrAddReal("dust", "coag_alpha", 1.e-3); + params.Add("coag_alpha", alpha); + const int scr_level = pin->GetOrAddReal("dust", "coag_scr_level", 0); + params.Add("coag_scr_level", scr_level); + + return coag; +} + +// using Kokkos par_for() loop +void initializeArray(const int nm, int &pGrid, const Real &rho_p, const Real &chi, + const Real &a, const ParArray1D dsize, ParArray2D klf, + ParArray1D mass_grid, ParArray3D coag3D, + ParArray3D cpod_notzero, ParArray3D cpod_short) { + + int ikdelta = coag2DRv::kdelta; + auto kdelta = Kokkos::subview(coag3D, ikdelta, Kokkos::ALL, Kokkos::ALL); + int icoef_fett = coag2DRv::coef_fett; + auto coef_fett = Kokkos::subview(coag3D, icoef_fett, Kokkos::ALL, Kokkos::ALL); + parthenon::par_for( + parthenon::loop_pattern_flatrange_tag, "initializeCoag1", parthenon::DevExecSpace(), + 0, nm - 1, KOKKOS_LAMBDA(const int i) { + // initialize in_idx(*) array + // initialize kdelta array + for (int j = 0; j < nm; j++) { + kdelta(i, j) = 0.0; + } + kdelta(i, i) = 1.0; + mass_grid(i) = 4.0 * M_PI / 3.0 * rho_p * std::pow(dsize(i), 3); + // initialize coef_fett(*,*) + for (int j = 0; j < nm; j++) { + Real tmp1 = (1.0 - 0.5 * kdelta(i, j)); + coef_fett(i, j) = M_PI * SQR(dsize(i) + dsize(j)) * tmp1; + } + }); + + // set fragmentation variables + // Real a = std::log10(massGrid_h(0) / massGrid_h(nm - 1)) / (1 - nm); + Real ten_a = std::pow(10.0, a); + Real ten_ma = 1.0 / ten_a; + int ce = int(-1.0 / a * std::log10(1.0 - ten_ma)) + 1; + + pGrid = floor(1.0 / a); // used in integration + + Real frag_slope = 2.0 - 11.0 / 6.0; + + int iphiFrag = coag2DRv::phiFrag, iepsFrag = coag2DRv::epsFrag; + int iaFrag = coag2DRv::aFrag; + auto phiFrag = Kokkos::subview(coag3D, iphiFrag, Kokkos::ALL, Kokkos::ALL); + auto epsFrag = Kokkos::subview(coag3D, iepsFrag, Kokkos::ALL, Kokkos::ALL); + auto aFrag = Kokkos::subview(coag3D, iaFrag, Kokkos::ALL, Kokkos::ALL); + parthenon::par_for( + parthenon::loop_pattern_flatrange_tag, "initializeCoag2", parthenon::DevExecSpace(), + 0, nm - 1, KOKKOS_LAMBDA(const int i) { + Real sum_pF = 0.0; + for (int j = 0; j <= i; j++) { + phiFrag(j, i) = std::pow(mass_grid(j), frag_slope); + sum_pF += phiFrag(j, i); + } + // normalization + for (int j = 0; j <= i; j++) { + phiFrag(j, i) /= sum_pF; // switch (i,j) from fortran + } + + // Cratering + for (int j = 0; j <= i - pGrid - 1; j++) { + // FRAGMENT DISTRIBUTION + // The largest fragment has the mass of the smaller collision partner + + // Mass bin of largest fragment + klf(i, j) = j; + + aFrag(i, j) = (1.0 + chi) * mass_grid(j); + // |_____________| + // | + // Mass of fragments + epsFrag(i, j) = chi * mass_grid(j) / (mass_grid(i) * (1.0 - ten_ma)); + } + + int i1 = std::max(0, i - pGrid); + for (int j = i1; j <= i; j++) { + // The largest fragment has the mass of the larger collison partner + klf(i, j) = i; + aFrag(i, j) = (mass_grid(i) + mass_grid(j)); + } + }); + + // initialize dalp array + // Calculate the D matrix + // Calculate the E matrix + ParArray2D e("epod", nm, nm); + int idalp = coag2DRv::dalp, idpod = coag2DRv::dpod; + auto dalp = Kokkos::subview(coag3D, idalp, Kokkos::ALL, Kokkos::ALL); + auto dpod = Kokkos::subview(coag3D, idpod, Kokkos::ALL, Kokkos::ALL); + parthenon::par_for( + parthenon::loop_pattern_flatrange_tag, "initializeCoag4", parthenon::DevExecSpace(), + 0, nm - 1, KOKKOS_LAMBDA(const int k) { + for (int j = 0; j < nm; j++) { + if (j <= k + 1 - ce) { + dalp(k, j) = 1.0; + dpod(k, j) = -mass_grid(j) / (mass_grid(k) * (ten_a - 1.0)); + } else { + dpod(k, j) = -1.0; + dalp(k, j) = 0.0; + } + } + // for E matrix------------- + Real mkkme = mass_grid(k) * (1.0 - ten_ma); + Real mkpek = mass_grid(k) * (ten_a - 1.0); + Real mkpeme = mass_grid(k) * (ten_a - ten_ma); + for (int j = 0; j < nm; ++j) { + if (j <= k - ce) { + e(k, j) = mass_grid(j) / mkkme; + } else { + Real theta1 = (mkpeme - mass_grid(j) < 0.0) ? 0.0 : 1.0; + e(k, j) = (1.0 - (mass_grid(j) - mkkme) / mkpek) * theta1; + } + } + }); + + // calculate the coagualtion variables + ParArray3D cpod("cpod", nm, nm, nm); + + // initialize cpod array; + parthenon::par_for( + parthenon::loop_pattern_mdrange_tag, "initializeCoag6", parthenon::DevExecSpace(), + 0, nm - 1, 0, nm - 1, KOKKOS_LAMBDA(const int i, const int j) { + // initialize to zero first + for (int k = 0; k < nm; k++) { + cpod(i, j, k) = 0.0; + } + Real mloc = mass_grid(i) + mass_grid(j); + if (mloc < mass_grid(nm - 1)) { + int gg = 0; + for (int k = std::max(i, j); k < nm - 1; k++) { + if (mloc >= mass_grid(k) && mloc < mass_grid(k + 1)) { + gg = k; + break; + } + } + + cpod(i, j, gg) = + (mass_grid(gg + 1) - mloc) / (mass_grid(gg + 1) - mass_grid(gg)); + cpod(i, j, gg + 1) = 1.0 - cpod(i, j, gg); + + // modified cpod(*) array------------------------- + Real dtheta_ji = (j - i - 0.5 < 0.0) ? 0.0 : 1.0; // theta(j - i - 0.5); + for (int k = 0; k < nm; k++) { + Real theta_kj = (k - j - 1.5 < 0.0) ? 0.0 : 1.0; // theta(k - j - 1.5) + cpod(i, j, k) = (0.5 * kdelta(i, j) * cpod(i, j, k) + + cpod(i, j, k) * theta_kj * dtheta_ji); + } + cpod(i, j, j) += dpod(j, i); + cpod(i, j, j + 1) += e(j + 1, i) * dtheta_ji; + + } // end if + }); + + // initialize cpod_nonzero and cpod_short array + parthenon::par_for( + parthenon::loop_pattern_mdrange_tag, "initializeCoag7", parthenon::DevExecSpace(), + 0, nm - 1, 0, nm - 1, KOKKOS_LAMBDA(const int i, const int j) { + if (j <= i) { + // initialize cpod_notzero(i, j, 4) and cpod_short(i, j, 4) + for (int k = 0; k < 4; k++) { + cpod_notzero(i, j, k) = 0; + cpod_short(i, j, k) = 0.0; + } + int inc = 0; + for (int k = 0; k < nm; ++k) { + Real dum = cpod(i, j, k) + cpod(j, i, k); + if (dum != 0.0) { + cpod_notzero(i, j, inc) = k; + cpod_short(i, j, inc) = dum; + inc++; + } + } + } + }); +} + +} // namespace Coagulation +} // namespace Dust diff --git a/src/dust/coagulation/coagulation.hpp b/src/dust/coagulation/coagulation.hpp new file mode 100644 index 0000000..454e0db --- /dev/null +++ b/src/dust/coagulation/coagulation.hpp @@ -0,0 +1,719 @@ +//======================================================================================== +// (C) (or copyright) 2023-2024. Triad National Security, LLC. All rights reserved. +// +// This program was produced under U.S. Government contract 89233218CNA000001 for Los +// Alamos National Laboratory (LANL), which is operated by Triad National Security, LLC +// for the U.S. Department of Energy/National Nuclear Security Administration. All rights +// in the program are reserved by Triad National Security, LLC, and the U.S. Department +// of Energy/National Nuclear Security Administration. The Government is granted for +// itself and others acting on its behalf a nonexclusive, paid-up, irrevocable worldwide +// license in this material to reproduce, prepare derivative works, distribute copies to +// the public, perform publicly and display publicly, and to permit others to do so. +//======================================================================================== +#ifndef DUST_COAGULATION_HPP_ +#define DUST_COAGULATION_HPP_ + +#include "utils/artemis_utils.hpp" + +//#define COAGULATION_DEBUG +namespace Dust { +namespace Coagulation { + +enum coag2DRv { dpod, aFrag, phiFrag, epsFrag, dalp, kdelta, coef_fett, last2 }; + +std::shared_ptr Initialize(ParameterInput *pin); + +struct CoagParams { + int coord = 0; // 1--surface density, 0: 3D + + int nm; + int nCall_mx = 1000; + bool ibounce = false; + Real nlim; + Real rho_p; + Real vfrag; + Real dfloor; + int integrator; + bool use_adaptive; // adaptive step size + bool mom_coag; // mom-preserving coagulation + + int pGrid; + Real chi; + Real pgrow; // Power for increasing step size + Real pshrink; // Power for decreasing step size + Real err_eps; // Relative tolerance for adaptive step sizing + Real S; // Safety margin for adaptive step sizing + Real cfl; + Real errcon; // Needed for increasing step size + + // pre-calculated array, once-for-all + ParArray2D klf; + ParArray1D mass_grid; + ParArray3D coagR3D; + ParArray3D cpod_notzero; + ParArray3D cpod_short; +}; + +void initializeArray(const int nm, int &pGrid, const Real &rho_p, const Real &chi, + const Real &a, const ParArray1D dsize, ParArray2D klf, + ParArray1D mass_grid, ParArray3D coag3D, + ParArray3D cpod_notzero, ParArray3D cpod_short); + +KOKKOS_INLINE_FUNCTION +Real v_rel_ormel(Real tau_1, Real tau_2, Real t0, Real v0, Real ts, Real vs, + Real reynolds) { + Real st1, st2, tau_mx, tau_mn, vg2; + Real c0, c1, c2, c3, y_star, ya, eps; + Real hulp1, hulp2; + + // sort tau's 1--> correspond to the max. now + if (tau_1 >= tau_2) { + tau_mx = tau_1; + tau_mn = tau_2; + st1 = tau_mx / t0; + st2 = tau_mn / t0; + } else { + tau_mx = tau_2; + tau_mn = tau_1; + st1 = tau_mx / t0; + st2 = tau_mn / t0; + } + + vg2 = 1.5 * pow(v0, 2); // note the square + ya = 1.6; // approximate solution for st*=y*st1; valid for st1 << 1. + + Real sqRe = 1.0 / sqrt(reynolds); + if (tau_mx < 0.2 * ts) { + // very small regime + return 1.5 * pow((vs / ts * (tau_mx - tau_mn)), 2); + } else if (tau_mx < ts / ya) { + return vg2 * (st1 - st2) / (st1 + st2) * + (pow(st1, 2) / (st1 + sqRe) - pow(st2, 2) / (st2 + sqRe)); + } else if (tau_mx < 5.0 * ts) { + // eq. 17 of oc07. the second term with st_i**2.0 is negligible (assuming re>>1) + // hulp1 = eq. 17; hulp2 = eq. 18 + hulp1 = ((st1 - st2) / (st1 + st2) * + (pow(st1, 2) / (st1 + ya * st1) - + pow(st2, 2) / (st2 + ya * st1))); // note the -sign + hulp2 = 2.0 * (ya * st1 - sqRe) + pow(st1, 2.0) / (ya * st1 + st1) - + pow(st1, 2) / (st1 + sqRe) + pow(st2, 2) / (ya * st1 + st2) - + pow(st2, 2) / (st2 + sqRe); + return vg2 * (hulp1 + hulp2); + } else if (tau_mx < t0 / 5.0) { + // full intermediate regime + eps = st2 / st1; // stopping time ratio + return vg2 * + (st1 * (2.0 * ya - (1.0 + eps) + + 2.0 / (1.0 + eps) * (1.0 / (1.0 + ya) + pow(eps, 3) / (ya + eps)))); + } else if (tau_mx < t0) { + // now y* lies between 1.6 (st1 << 1) and 1.0 (st1>=1). the fit below fits ystar to + // less than 1% + c3 = -0.29847604; + c2 = 0.32938936; + c1 = -0.63119577; + c0 = 1.6015125; + y_star = c0 + c1 * st1 + c2 * pow(st1, 2) + c3 * pow(st1, 3); + // we can then employ the same formula as before + eps = st2 / st1; // stopping time ratio + return vg2 * (st1 * (2.0 * y_star - (1.0 + eps) + + 2.0 / (1.0 + eps) * + (1.0 / (1.0 + y_star) + pow(eps, 3) / (y_star + eps)))); + } else { + // heavy particle limit + return vg2 * (1.0 / (1.0 + st1) + 1.0 / (1.0 + st2)); + } +} + +KOKKOS_INLINE_FUNCTION +Real theta(Real x) { return (x < 0 ? 0.0 : 1.0); } + +// Function calculates the new Q value of a particle resulting of a +// collision of particles with masses m1, m2 and Q values Q1, Q2 +KOKKOS_INLINE_FUNCTION +Real Qplus(Real m1, Real Q1, Real m2, Real Q2) { return (m1 * Q1 + m2 * Q2) / (m1 + m2); } + +KOKKOS_INLINE_FUNCTION +Real CoagulationRate(const int i, const int j, const Real kernel4[], + const ScratchPad1D &vel, + const ScratchPad1D &stoppingTime, const CoagParams &coag, + const int itype) { + + const Real &mass_gridi = coag.mass_grid(i); + const Real &mass_gridj = coag.mass_grid(j); + const Real &mass_gride = coag.mass_grid(coag.nm - 1); + if (mass_gridi + mass_gridj >= mass_gride) { + return 0.0; + } + + const Real &gasdens = kernel4[0]; + const Real &alpha = kernel4[1]; + const Real &cs = kernel4[2]; + const Real &omega = kernel4[3]; + const Real &tau_i = stoppingTime(i); + const Real &tau_j = stoppingTime(j); + const Real *vel_i = &vel(3 * i); + const Real *vel_j = &vel(3 * j); + + const Real sig_h2 = 2.0e-15; //! cross section of H2 + const Real mu = 2.3; //! mean molecular mass in proton masses + const Real m_p = 1.6726231e-24; //! proton mass in g + + // calculate some basic properties + const Real hg = cs / omega; + Real re = alpha * sig_h2 * gasdens / (2.0 * mu * m_p); + if (coag.coord == 0) { + re *= std::sqrt(2.0 * M_PI) * hg; + } + + const Real tn = 1.0 / omega; + const Real ts = tn / sqrt(re); + const Real vn = std::sqrt(alpha) * cs; + const Real vs = vn * std::pow(re, -0.25); + + // calculate the relative velocities + const Real c1 = 8.0 / M_PI * cs * cs * mu * m_p; + + const Real stokes_i = tau_i * omega; + const Real stokes_j = tau_j * omega; + + // turbulent relative velocity + Real dv0 = v_rel_ormel(tau_i, tau_j, tn, vn, ts, vs, re); + + // Brownian motion relative velocities + const Real mredu = (mass_gridi * mass_gridj / (mass_gridi + mass_gridj)); + dv0 += (c1 / mredu); + + Real dv2_ij; + Real hij = 1.0; + if (coag.coord == 1) { // surface density + const Real hi = + std::min(std::sqrt(alpha / (std::min(0.5, stokes_i) * (SQR(stokes_i) + 1.0))), + 1.0) * + hg; + const Real hj = + std::min(std::sqrt(alpha / (std::min(0.5, stokes_j) * (SQR(stokes_j) + 1.0))), + 1.0) * + hg; + const Real vs_i = std::min(stokes_i, 1.0) * omega * hi; + const Real vs_j = std::min(stokes_j, 1.0) * omega * hj; + // relative velocity from vertical settling + dv2_ij = SQR(vs_i - vs_j); + dv2_ij += (SQR(vel_i[0] - vel_j[0]) + SQR(vel_i[1] - vel_j[1])); + hij = std::sqrt(2.0 * M_PI * (SQR(hi) + SQR(hj))); + } else { + dv2_ij = + (SQR(vel_i[0] - vel_j[0]) + SQR(vel_i[1] - vel_j[1]) + SQR(vel_i[2] - vel_j[2])); + } + + // after adding up all v_rel**2 take the square root + const Real dv = std::sqrt(dv0 + dv2_ij); + + // new pf calculation: for fragmenation + Real pf = 0.0; + if (dv > 0.0) { + const Real tmp = 1.5 * SQR(coag.vfrag / dv); + pf = (tmp + 1.0) * std::exp(-tmp); + } + + int icoef_fett = coag2DRv::coef_fett; + const Real &coef_fettij = coag.coagR3D(icoef_fett, i, j); + if (itype == 0) { // coagulation + if (coag.ibounce && dv > 0.0) { // including bouncing effect + const Real froll = 1e-4; // Heim et al.(PRL) 1999 + const Real amono = 1e-4; // micro-size + const Real vbounce = std::sqrt(5.0 * M_PI * amono * froll / mredu); + if (vbounce < coag.vfrag) { + const Real tmp = 1.5 * SQR(vbounce / dv); + pf = (tmp + 1.0) * std::exp(-tmp); // using bouncing vel + } + } + const Real pc = 1.0 - pf; + return (coef_fettij * dv * pc / hij); + } else { // fragmentation + return (coef_fettij * dv * pf / hij); + } +} + +KOKKOS_INLINE_FUNCTION +void CoagulationSource(parthenon::team_mbr_t const &mbr, ScratchPad1D &source, + const ScratchPad1D &distri, const int mimax, + const Real kernel4[], const ScratchPad1D &vel, + const ScratchPad1D &stoppingTime, const CoagParams &coag) { + + const int nm = coag.nm; + + // initialize source(*) + parthenon::par_for_inner(DEFAULT_INNER_LOOP_PATTERN, mbr, 0, nm - 1, [&](const int k) { + // for (int k = 0; k < nm; k++) { + source(k) = 0.0; + }); + mbr.team_barrier(); + + // Adding coagulation source terms + parthenon::par_for_inner(DEFAULT_INNER_LOOP_PATTERN, mbr, 0, mimax, [&](const int i) { + // for (int i = 0; i <= mimax; i++) { + for (int j = 0; j <= i; j++) { + // calculate the rate + const Real fett_t = CoagulationRate(i, j, kernel4, vel, stoppingTime, coag, 0); + const Real Rc1 = distri(i) * distri(j) * fett_t; + for (int nz = 0; nz < 4; nz++) { + const int k = coag.cpod_notzero(i, j, nz); + if (k < 0) continue; + const Real src_coag0 = coag.cpod_short(i, j, nz) * Rc1; + Kokkos::atomic_add(&source(k), src_coag0); + } + } + }); + mbr.team_barrier(); + + // FRAGMENTATION------------------------------------------------------ + + // Adding fragment distribution + const int pGrid = coag.pGrid; + int iaFrag = coag2DRv::aFrag; + int iphiFrag = coag2DRv::phiFrag, iepsFrag = coag2DRv::epsFrag; + parthenon::par_for_inner(DEFAULT_INNER_LOOP_PATTERN, mbr, 0, nm - 1, [&](const int k) { + // for (int k = 0; k < nm; k++) { + for (int j = k; j <= mimax; j++) { + // calculate As(j) on fly + Real As_j = 0.0; + for (int i2 = 0; i2 <= mimax; i2++) { + for (int j2 = 0; j2 <= i2; j2++) { + // int klf = (j2 <= i2 - pGrid - 1) ? j2 : i2; + // if (klf == j) { + if (coag.klf(i2, j2) == j) { + const Real fett_l = + CoagulationRate(i2, j2, kernel4, vel, stoppingTime, coag, 1); + As_j += coag.coagR3D(iaFrag, i2, j2) * distri(i2) * distri(j2) * fett_l; + } + } + } + source(k) += coag.coagR3D(iphiFrag, k, j) / coag.mass_grid(k) * As_j; + } + }); + mbr.team_barrier(); + + // Negative terms and cratering remnants + parthenon::par_for_inner(DEFAULT_INNER_LOOP_PATTERN, mbr, 0, mimax, [&](const int j) { + Real sum0(0.0); + for (int i = j; i <= mimax; i++) { + const Real fett_l = CoagulationRate(i, j, kernel4, vel, stoppingTime, coag, 1); + const Real Rf1 = distri(i) * distri(j) * fett_l; + sum0 -= Rf1; + } + source(j) += sum0; + }); + mbr.team_barrier(); + + // for (int i = 0; i <= mimax; i++) { + // Cratering + parthenon::par_for_inner(DEFAULT_INNER_LOOP_PATTERN, mbr, 0, mimax, [&](const int i) { + Real sum0(0.0); + for (int j = 0; j <= i - pGrid - 1; j++) { + const Real fett_l = CoagulationRate(i, j, kernel4, vel, stoppingTime, coag, 1); + const Real Rf1 = distri(i) * distri(j) * fett_l; + const Real dummy = coag.coagR3D(iepsFrag, i, j) * Rf1; + sum0 += dummy; + } + + if (i - pGrid - 1 >= 0) { + Kokkos::atomic_add(&source(i - 1), sum0); + } + + Real sum1 = -sum0; + // Full fragmentation (only negative terms) + int i1 = std::max(0, i - pGrid); + for (int j = i1; j <= i; j++) { + const Real fett_l = CoagulationRate(i, j, kernel4, vel, stoppingTime, coag, 1); + const Real Rf1 = distri(i) * distri(j) * fett_l; + sum1 -= Rf1; + } + Kokkos::atomic_add(&source(i), sum1); + }); + mbr.team_barrier(); +} // end of subroutine source + +KOKKOS_INLINE_FUNCTION +void Coagulation_nQ(parthenon::team_mbr_t const &mbr, ScratchPad1D &nQs, + const ScratchPad1D &Q, const ScratchPad1D &distri, + const int mimax, const Real kernel4[], const ScratchPad1D &vel, + const ScratchPad1D &stoppingTime, const CoagParams &coag) { + + const int nm = coag.nm; + + int iaFrag = coag2DRv::aFrag; + int iphiFrag = coag2DRv::phiFrag, iepsFrag = coag2DRv::epsFrag; + int idalp = coag2DRv::dalp, idpod = coag2DRv::dpod; + // int ikdelta = coag2DRv::kdelta; + // Adding coagulation source terms + parthenon::par_for_inner(DEFAULT_INNER_LOOP_PATTERN, mbr, 0, mimax, [&](const int i) { + // for (int i = 0; i <= mimax; i++) { + for (int j = 0; j <= i; j++) { + // calculate the rate + const Real fett_t = CoagulationRate(i, j, kernel4, vel, stoppingTime, coag, 0); + const Real Rc1 = distri(i) * distri(j) * fett_t; + const Real &mass_gridi = coag.mass_grid(i); + const Real &mass_gridj = coag.mass_grid(j); + const Real &dalpji = coag.coagR3D(idalp, j, i); + const Real &dpodji = coag.coagR3D(idpod, j, i); + const Real &dalpij = coag.coagR3D(idalp, i, j); + const Real &dpodij = coag.coagR3D(idpod, i, j); + + const Real Qp1 = Qplus(mass_gridi, Q(i), mass_gridj, Q(j)); + const Real dphijQ = dalpji * Qp1 * (1.0 + dpodji) - Q(j); + const Real dphjiQ = dalpij * Qp1 * (1.0 + dpodij) - Q(i); + + const Real tmp1 = dphijQ - Qp1 * dpodji; + const Real tmp2 = dphjiQ - Qp1 * dpodij; + for (int nz = 0; nz < 4; nz++) { + const int k = coag.cpod_notzero(i, j, nz); + if (k < 0) continue; + const Real kdeltajk = (j == k) ? 1.0 : 0.0; + const Real kdeltaik = (i == k) ? 1.0 : 0.0; + const Real nqs_k = + (Qp1 * coag.cpod_short(i, j, nz) + tmp1 * kdeltajk + tmp2 * kdeltaik) * Rc1; + Kokkos::atomic_add(&nQs(k), nqs_k); + } + } + }); + mbr.team_barrier(); + + // FRAGMENTATION------------------------------------------------------ + + const int pGrid = coag.pGrid; + // Adding fragment distribution + parthenon::par_for_inner(DEFAULT_INNER_LOOP_PATTERN, mbr, 0, nm - 1, [&](const int k) { + // for (int k = 0; k < nm; k++) { + for (int j = k; j <= mimax; j++) { + // calculate As(j) on fly + Real As_j = 0.0; + for (int i2 = 0; i2 <= mimax; i2++) { + for (int j2 = 0; j2 <= i2; j2++) { + int klf = (j2 <= i2 - pGrid - 1) ? j2 : i2; + // if (coag.klf(i2, j2) == j) { + if (klf == j) { + const Real fett_l = + CoagulationRate(i2, j2, kernel4, vel, stoppingTime, coag, 1); + Real Qf1; + const Real &mass_gridi2 = coag.mass_grid(i2); + const Real &mass_gridj2 = coag.mass_grid(j2); + const Real &aFragi2j2 = coag.coagR3D(iaFrag, i2, j2); + if (j2 <= i2 - pGrid - 1) { + Qf1 = Qplus(coag.chi * mass_gridj2, Q(i2), mass_gridj2, Q(j2)); + } else { + Qf1 = Qplus(mass_gridi2, Q(i2), mass_gridj2, Q(j2)); + } + As_j += aFragi2j2 * distri(i2) * distri(j2) * fett_l * Qf1; + } + } + } + const Real &mass_gridk = coag.mass_grid(k); + nQs(k) += coag.coagR3D(iphiFrag, k, j) / mass_gridk * As_j; + } + }); + mbr.team_barrier(); + + // Negative terms and cratering remnants + parthenon::par_for_inner(DEFAULT_INNER_LOOP_PATTERN, mbr, 0, mimax, [&](const int j) { + // Cratering + Real sum0(0.0); + for (int i = j; i <= mimax; i++) { + const Real fett_l = CoagulationRate(i, j, kernel4, vel, stoppingTime, coag, 1); + const Real Rf1 = distri(i) * distri(j) * fett_l; + sum0 -= Rf1; + } + nQs(j) += (sum0 * Q(j)); + }); + mbr.team_barrier(); + + parthenon::par_for_inner(DEFAULT_INNER_LOOP_PATTERN, mbr, 0, mimax, [&](const int i) { + Real sum0(0.0); + for (int j = 0; j <= i - pGrid - 1; j++) { + const Real fett_l = CoagulationRate(i, j, kernel4, vel, stoppingTime, coag, 1); + const Real Rf1 = distri(i) * distri(j) * fett_l; + const Real dummy = coag.coagR3D(iepsFrag, i, j) * Rf1 * Q(i); + sum0 += dummy; + } + + if (i - pGrid - 1 >= 0) { + Kokkos::atomic_add(&nQs(i - 1), sum0); + } + + Real sum1 = -sum0; + // Full fragmentation (only negative terms) + int i1 = std::max(0, i - pGrid); + for (int j = i1; j <= i; j++) { + const Real fett_l = CoagulationRate(i, j, kernel4, vel, stoppingTime, coag, 1); + const Real Rf1 = distri(i) * distri(j) * fett_l * Q(i); + sum1 -= Rf1; + } + Kokkos::atomic_add(&nQs(i), sum1); + }); + mbr.team_barrier(); +} // end of subroutine source + +KOKKOS_INLINE_FUNCTION +void Coagulation_nQs(parthenon::team_mbr_t const &mbr, const Real &dt, + ScratchPad1D &Q, ScratchPad1D &nQs, + ScratchPad1D &distri, const int mimax, const int nvel, + const Real kernel4[], ScratchPad1D &vel, + const ScratchPad1D &stoppingTime, const CoagParams &coag, + ScratchPad1D &source) { + + const int nm = coag.nm - 1; + + const Real mom_scale = 1.0e10; + const Real mom_iscale = 1.0e-10; + + for (int n = 0; n < nvel; n++) { + parthenon::par_for_inner(DEFAULT_INNER_LOOP_PATTERN, mbr, 0, nm, [&](const int k) { + Q(k) = vel(n + k * 3) * mom_scale; + nQs(k) = 0.0; // initialize source(*) + }); + mbr.team_barrier(); + + Coagulation_nQ(mbr, nQs, Q, distri, mimax, kernel4, vel, stoppingTime, coag); + + parthenon::par_for_inner(DEFAULT_INNER_LOOP_PATTERN, mbr, 0, nm, [&](const int k) { + const Real distri_k = distri(k) + dt * source(k); + if (distri_k > coag.dfloor / coag.mass_grid(k)) { + const Real nQ1 = distri(k) * Q(k) + dt * nQs(k); + vel(n + k * 3) = nQ1 / distri_k * mom_iscale; + } + }); + mbr.team_barrier(); + } // loop of n + + // update the density + parthenon::par_for_inner(DEFAULT_INNER_LOOP_PATTERN, mbr, 0, nm, + [&](const int k) { distri(k) += dt * source(k); }); + mbr.team_barrier(); +} + +KOKKOS_INLINE_FUNCTION +void Coagulation_nQs3(parthenon::team_mbr_t const &mbr, const Real &dt, + ScratchPad1D &Q, ScratchPad1D &nQs, + ScratchPad1D &distri, const int mimax, const int nvel, + const Real kernel4[], ScratchPad1D &vel, + const ScratchPad1D &stoppingTime, const CoagParams &coag, + ScratchPad1D &source, ScratchPad1D &Q2, + const int mimax2) { + + const int nm = coag.nm - 1; + + const Real mom_scale = 1.0e10; + const Real mom_iscale = 1.0e-10; + + parthenon::par_for_inner(DEFAULT_INNER_LOOP_PATTERN, mbr, 0, nm, [&](const int k) { + Q2(k) = nQs(k); // 2nd stage source + }); + mbr.team_barrier(); + + for (int n = 0; n < nvel; n++) { + parthenon::par_for_inner(DEFAULT_INNER_LOOP_PATTERN, mbr, 0, nm, [&](const int k) { + Q(k) = vel(n + k * 3) * mom_scale; + nQs(k) = 0.0; + }); + mbr.team_barrier(); + + // 1st stage + Coagulation_nQ(mbr, nQs, Q, distri, mimax, kernel4, vel, stoppingTime, coag); + + parthenon::par_for_inner(DEFAULT_INNER_LOOP_PATTERN, mbr, 0, nm, [&](const int k) { + const Real distri_k = distri(k) + dt * source(k); + const Real nQ1 = distri(k) * Q(k) + dt * nQs(k); + Q(k) = nQ1 / distri_k; // intermediate Q + }); + mbr.team_barrier(); + + // 2nd stage + Coagulation_nQ(mbr, nQs, Q, distri, mimax2, kernel4, vel, stoppingTime, coag); + + parthenon::par_for_inner(DEFAULT_INNER_LOOP_PATTERN, mbr, 0, nm, [&](const int k) { + const Real nQ_o = distri(k) * vel(n + k * 3) * mom_scale; + const Real distri_k = distri(k) + 0.5 * dt * (source(k) + Q2(k)); + if (distri_k > coag.dfloor / coag.mass_grid(k)) { + Real nQ1 = nQ_o + 0.5 * dt * nQs(k); + vel(n + k * 3) = nQ1 / distri_k * mom_iscale; + } + }); + mbr.team_barrier(); + } + // update the density + parthenon::par_for_inner(DEFAULT_INNER_LOOP_PATTERN, mbr, 0, nm, [&](const int k) { + distri(k) += 0.5 * dt * (source(k) + Q2(k)); + }); + mbr.team_barrier(); +} + +KOKKOS_INLINE_FUNCTION +void CoagulationOneCell(parthenon::team_mbr_t const &mbr, const int cell_i, + const Real &time, Real &dt_sync, const Real &gasdens, + ScratchPad1D &dustdens, ScratchPad1D &stime, + ScratchPad1D &vel, const int nvel, ScratchPad1D &Q, + ScratchPad1D &nQs, const Real &alpha, const Real &cs, + const Real &omega, const CoagParams &coag, + ScratchPad1D &source, int &nCall, ScratchPad1D &Q2) { + + int nm = coag.nm; + + Real dt, time_dummy, time_goal, hnext; + Real dt_sync1 = dt_sync; + + parthenon::par_for_inner(DEFAULT_INNER_LOOP_PATTERN, mbr, 0, nm - 1, [&](const int i) { + // convert to number density + const Real &mass_gridi = coag.mass_grid(i); + dustdens(i) /= mass_gridi; // number density + // take the floor value + dustdens(i) = std::max(dustdens(i), 0.01 * coag.dfloor / mass_gridi); +#ifdef COAGULATION_DEBUG + if (cell_i == 2 && dustdens[i] > coag.dfloor / mass_gridi) { + std::cout << " oneCellBeg: " << time << " " << i << " " << dustdens[i] << " " + << mass_gridi << " " << stime[i] << std::endl; + } +#endif + }); + mbr.team_barrier(); + + nCall = 0; + + // do time steps + time_dummy = time; + time_goal = time_dummy + dt_sync1; + dt = dt_sync1; + hnext = dt; + dt_sync = 1e-15; // works H5 + + Real kernel[4]; + kernel[0] = gasdens; + kernel[1] = alpha; + kernel[2] = cs; + kernel[3] = omega; + + while (std::abs(time_dummy - time_goal) > 1e-6 * dt) { + int mimax = 0; + Kokkos::parallel_reduce( + Kokkos::TeamThreadRange(mbr, nm), + [&](const int i, int &lmax) { + if (dustdens(i) > coag.dfloor / coag.mass_grid(i)) { + lmax = std::max(lmax, i); + } + }, + Kokkos::Max(mimax)); + + CoagulationSource(mbr, source, dustdens, mimax, kernel, vel, stime, coag); + + if (coag.use_adaptive == 0 || coag.integrator == 1) { + // time step control + dt_sync1 = std::numeric_limits::max(); // start with a large number + Kokkos::parallel_reduce( + Kokkos::TeamThreadRange(mbr, nm), + [&](const int i, Real &lmin) { + if (dustdens(i) > coag.dfloor / coag.mass_grid(i) && source(i) < 0.0) { + lmin = std::min(lmin, std::abs(dustdens(i) / source(i))); + } + }, + Kokkos::Min(dt_sync1)); + dt_sync1 *= coag.cfl; + dt = std::min(dt_sync1, time_goal - time_dummy); + dt_sync = dt_sync1; + + if (coag.mom_coag) { + Coagulation_nQs(mbr, dt, Q, nQs, dustdens, mimax, nvel, kernel, vel, stime, coag, + source); + } else { + // integration: first-order + parthenon::par_for_inner(DEFAULT_INNER_LOOP_PATTERN, mbr, 0, nm - 1, + [&](const int i) { dustdens(i) += dt * source(i); }); + mbr.team_barrier(); + } + + } else { + // third-order method + Real h0 = hnext; + Real h = h0; + Real errmax; + int mimax2 = 0; + // Heun's Method + while (1) { + // Q(*) is temprary variable to store the dust number density + mimax2 = 0; + Kokkos::parallel_reduce( + Kokkos::TeamThreadRange(mbr, nm), + [&](const int i, int &lmax) { + Q(i) = dustdens(i) + h * source(i); + if (Q(i) > coag.dfloor / coag.mass_grid(i)) { + lmax = std::max(lmax, i); + } + }, + Kokkos::Max(mimax2)); + + CoagulationSource(mbr, nQs, Q, mimax2, kernel, vel, stime, coag); + + errmax = 0.0; + const int nm1 = std::min(mimax2, mimax); + Kokkos::parallel_reduce( + Kokkos::TeamThreadRange(mbr, nm1), + [&](const int i, Real &lmax) { + Real dscale = std::abs(dustdens(i)) + std::abs(h0 * source(i)); + Real derr = 0.5 * h * (nQs(i) - source(i)) / dscale; + lmax = std::max(lmax, std::abs(derr)); + }, + Kokkos::Max(errmax)); +#ifdef COAGULATION_DEBUG + if (cell_i == 2) + std::cout << nCall << " " << errmax << " " << coag.err_eps << " " << h << " " + << mimax << " " << mimax2 << std::endl; +#endif + errmax /= coag.err_eps; + + if (errmax <= 1.0) break; + + h = std::max(coag.S * h * std::pow(errmax, coag.pshrink), 0.1 * h); + } // end of while (1) + + if (errmax > coag.errcon) { + hnext = coag.S * h * std::pow(errmax, coag.pgrow); + } else { + hnext = 5.0 * h; + } + + // Actual taken step + dt = h; + + if (coag.mom_coag) { + Coagulation_nQs3(mbr, dt, Q, nQs, dustdens, mimax, nvel, kernel, vel, stime, coag, + source, Q2, mimax2); + } else { + parthenon::par_for_inner( + DEFAULT_INNER_LOOP_PATTERN, mbr, 0, nm - 1, + [&](const int i) { dustdens(i) += 0.5 * dt * (source(i) + nQs(i)); }); + mbr.team_barrier(); + } + + } // end of if (coag.use_adaptive == 0) + + // Kokkos::single (Kokkos::PerTeam(mbr), [&]() { + time_dummy += dt; + nCall++; + //}); mbr.team_barrier(); + + if (coag.use_adaptive == 1) { + dt_sync = std::max(hnext, dt_sync); + hnext = std::min(hnext, time_goal - time_dummy); + } + + if (nCall > coag.nCall_mx) break; + } // end of internal timestep + + // from number density to volume density + parthenon::par_for_inner(DEFAULT_INNER_LOOP_PATTERN, mbr, 0, nm - 1, + [&](const int i) { dustdens(i) *= coag.mass_grid(i); }); + mbr.team_barrier(); + +} // end of CoagulationOneCell + +} // namespace Coagulation +} // namespace Dust + +#endif // DUST_COAGULATION_HPP_ diff --git a/src/pgen/dust_coagulation.hpp b/src/pgen/dust_coagulation.hpp new file mode 100644 index 0000000..23988f3 --- /dev/null +++ b/src/pgen/dust_coagulation.hpp @@ -0,0 +1,190 @@ +//======================================================================================== +// (C) (or copyright) 2023-2024. Triad National Security, LLC. All rights reserved. +// +// This program was produced under U.S. Government contract 89233218CNA000001 for Los +// Alamos National Laboratory (LANL), which is operated by Triad National Security, LLC +// for the U.S. Department of Energy/National Nuclear Security Administration. All rights +// in the program are reserved by Triad National Security, LLC, and the U.S. Department +// of Energy/National Nuclear Security Administration. The Government is granted for +// itself and others acting on its behalf a nonexclusive, paid-up, irrevocable worldwide +// license in this material to reproduce, prepare derivative works, distribute copies to +// the public, perform publicly and display publicly, and to permit others to do so. +//======================================================================================== +// AthenaXXX astrophysical plasma code +// Copyright(C) 2020 James M. Stone and the Athena code team +// Licensed under the 3-clause BSD License (the "LICENSE") +//======================================================================================== + +// NOTE(@pdmullen): The following is taken directly from the open-source +// Athena++-dustfluid software, and adapted for Parthenon/Artemis by @Shengtai on 7/30/24 + +//! \file dust_coagulation.hpp +//! \brief dust collision problem generator for 1D problems. + +#ifndef PGEN_DUST_COAGULATION_HPP_ +#define PGEN_DUST_COAGULATION_HPP_ + +// C/C++ headers +#include +#include +#include +#include +#include +#include +#include + +// Artemis headers +#include "artemis.hpp" +#include "geometry/geometry.hpp" +#include "utils/artemis_utils.hpp" +#include "utils/eos/eos.hpp" + +using ArtemisUtils::EOS; +using ArtemisUtils::VI; + +namespace { + +//---------------------------------------------------------------------------------------- +//! \struct DustCoagulationVariable +//! \brief container for variables shared with dust_coagulation pgen +struct DustCoagulationVariable { + int nDust; + int nInit_dust; + Real gamma, gm1; + Real iso_cs; + Real d2g; + int nstep1Coag; + Real rho_g0; + Real mass0; + Real time0; + Real length0; + Real vol0; +}; + +} // end anonymous namespace + +namespace dust_coagulation { + +DustCoagulationVariable dcv; + +//---------------------------------------------------------------------------------------- +//! \fn void ProblemGenerator::DustCollision_() +//! \brief Sets initial conditions for dust coagulation tests +template +inline void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { + using parthenon::MakePackDescriptor; + + auto artemis_pkg = pmb->packages.Get("artemis"); + const auto geom = artemis_pkg->Param("coords"); + PARTHENON_REQUIRE(geom == Coordinates::cartesian, + "dust_coagulation pgen requires Cartesian geometry!"); + const bool do_dust = artemis_pkg->Param("do_dust"); + PARTHENON_REQUIRE(do_dust, "dust_coagulation pgen requires do_dust=true!"); + + auto &dust_pkg = pmb->packages.Get("dust"); + + const bool enable_coagulation = dust_pkg->Param("enable_coagulation"); + // PARTHENON_REQUIRE(enable_coagulation, + // "dust_coagulation pgen requires enable_coagulation=true!"); + + // read global parameters + dcv.nDust = pin->GetOrAddReal("dust", "nspecies", 121); + dcv.nInit_dust = pin->GetOrAddReal("problem", "nInit_dust", 1); + dcv.d2g = pin->GetOrAddReal("problem", "dust_to_gas", 0.01); + dcv.nstep1Coag = pin->GetOrAddReal("problem", "nstep1Coag", 50); + + if (Dust::cgsunit == NULL) { + Dust::cgsunit = new Dust::CGSUnit(); + } + if (!Dust::cgsunit->isSet()) { + Dust::cgsunit->SetCGSUnit(pin); + } + + //bool isurface_den = Dust::cgsunit->isurface_den; + dcv.length0 = Dust::cgsunit->length0; + dcv.mass0 = Dust::cgsunit->mass0; + dcv.time0 = Dust::cgsunit->time0; + + Real den_code2phy = 1.0; + dcv.vol0 = Dust::cgsunit->vol0; + + den_code2phy = dcv.mass0 / dcv.vol0; + + dcv.rho_g0 = den_code2phy; + + // using MRN distribution for the initial dust setup + ParArray1D dust_size = dust_pkg->template Param>("sizes"); + + auto s_p_prefh = Kokkos::create_mirror(dust_size); + Kokkos::deep_copy(s_p_prefh, dust_size); + + Real sum1 = 0.0; + for (int i = 0; i < dcv.nInit_dust; i++) { + sum1 += std::sqrt(s_p_prefh(i)); + } + + for (int i = 0; i < dcv.nInit_dust; i++) { + s_p_prefh(i) = std::sqrt(s_p_prefh(i)) / sum1; + } + + for (int i = dcv.nInit_dust; i < dcv.nDust; i++) { + s_p_prefh(i) = 0.0; + } + ParArray1D s_p_pref("init dust", dcv.nDust); + Kokkos::deep_copy(s_p_pref, s_p_prefh); + + auto gas_pkg = pmb->packages.Get("gas"); + auto eos_d = gas_pkg->template Param("eos_d"); + + dcv.gamma = gas_pkg->Param("adiabatic_index"); + dcv.gm1 = dcv.gamma - 1.0; + dcv.iso_cs = pin->GetOrAddReal("gas", "iso_sound_speed", 1e-1); + + const Real gdens = 1.0; + const Real gtemp = SQR(dcv.iso_cs); + const Real vx_g = 0.0; + const Real gsie = eos_d.InternalEnergyFromDensityTemperature(gdens, gtemp); + std::cout << "gamma,cs,pre=" << dcv.gamma << " " << dcv.iso_cs << " " << gsie * dcv.gm1 + << std::endl; + + const Real vx_d = 0.0; + const Real vy_d = 0.0; + const Real vz_d = 0.0; + + // packing and capture variables for kernel + auto &md = pmb->meshblock_data.Get(); + for (auto &var : md->GetVariableVector()) { + if (!var->IsAllocated()) pmb->AllocateSparse(var->label()); + } + static auto desc = + MakePackDescriptor( + (pmb->resolved_packages).get()); + auto v = desc.GetPack(md.get()); + IndexRange ib = pmb->cellbounds.GetBoundsI(IndexDomain::entire); + IndexRange jb = pmb->cellbounds.GetBoundsJ(IndexDomain::entire); + IndexRange kb = pmb->cellbounds.GetBoundsK(IndexDomain::entire); + auto &dcoag = dcv; + + pmb->par_for( + "pgen_dustCoagulation", kb.s, kb.e, jb.s, jb.e, ib.s, ib.e, + KOKKOS_LAMBDA(const int k, const int j, const int i) { + v(0, gas::prim::density(0), k, j, i) = gdens; + v(0, gas::prim::velocity(0), k, j, i) = vx_g; + v(0, gas::prim::velocity(1), k, j, i) = 0.0; + v(0, gas::prim::velocity(2), k, j, i) = 0.0; + v(0, gas::prim::sie(0), k, j, i) = gsie; + + // dust initial condition + for (int n = 0; n < dcoag.nDust; ++n) { + v(0, dust::prim::density(n), k, j, i) = dcoag.d2g * gdens * s_p_pref(n); + v(0, dust::prim::velocity(n * 3 + 0), k, j, i) = vx_d; + v(0, dust::prim::velocity(n * 3 + 1), k, j, i) = vy_d; + v(0, dust::prim::velocity(n * 3 + 2), k, j, i) = vz_d; + } + }); +} + +} // namespace dust_coagulation + +#endif // PGEN_DUST_COAGULATION_HPP_ diff --git a/src/pgen/dust_collision.hpp b/src/pgen/dust_collision.hpp new file mode 100644 index 0000000..6ae9832 --- /dev/null +++ b/src/pgen/dust_collision.hpp @@ -0,0 +1,239 @@ +//======================================================================================== +// (C) (or copyright) 2023-2024. Triad National Security, LLC. All rights reserved. +// +// This program was produced under U.S. Government contract 89233218CNA000001 for Los +// Alamos National Laboratory (LANL), which is operated by Triad National Security, LLC +// for the U.S. Department of Energy/National Nuclear Security Administration. All rights +// in the program are reserved by Triad National Security, LLC, and the U.S. Department +// of Energy/National Nuclear Security Administration. The Government is granted for +// itself and others acting on its behalf a nonexclusive, paid-up, irrevocable worldwide +// license in this material to reproduce, prepare derivative works, distribute copies to +// the public, perform publicly and display publicly, and to permit others to do so. +//======================================================================================== +// AthenaXXX astrophysical plasma code +// Copyright(C) 2020 James M. Stone and the Athena code team +// Licensed under the 3-clause BSD License (the "LICENSE") +//======================================================================================== + +// NOTE(@pdmullen): The following is taken directly from the open-source +// Athena++-dustfluid software, and adapted for Parthenon/Artemis by @Shengtai on 4/12/24 + +//! \file dust_collision.cpp +//! \brief dust collision problem generator for 1D problems. + +#ifndef PGEN_DUST_COLLISION_HPP_ +#define PGEN_DUST_COLLISION_HPP_ + +// C/C++ headers +#include +#include +#include +#include +#include +#include +#include + +// Artemis headers +#include "artemis.hpp" +#include "geometry/geometry.hpp" +//#include "pgen/pgen.hpp" +#include "utils/artemis_utils.hpp" +#include "utils/eos/eos.hpp" + +using ArtemisUtils::EOS; + +namespace { + +//---------------------------------------------------------------------------------------- +//! \struct DustCollisionVariable +//! \brief container for variables shared with dust collision pgen +struct DustCollisionVariable { + int prob_flag; + int nDust; + Real gamma, gm1; + Real iso_cs; +}; + +} // end anonymous namespace + +namespace dust_collision { + +DustCollisionVariable dcv; + +//---------------------------------------------------------------------------------------- +//! \fn void ProblemGenerator::DustCollision_() +//! \brief Sets initial conditions for dust collision tests +template +inline void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { + using parthenon::MakePackDescriptor; + + auto artemis_pkg = pmb->packages.Get("artemis"); + const auto geom = artemis_pkg->Param("coords"); + PARTHENON_REQUIRE(geom == Coordinates::cartesian, + "dust_collision pgen requires Cartesian geometry!"); + const bool do_dust = artemis_pkg->Param("do_dust"); + PARTHENON_REQUIRE(do_dust, "dust_collision pgen requires do_dust=true!"); + bool const_stopping_time = pin->GetOrAddBoolean("dust", "const_stopping_time", true); + PARTHENON_REQUIRE(do_dust, "dust_collision pgen requires const_stopping_time=true!"); + + // read global parameters + dcv.prob_flag = pin->GetOrAddInteger("problem", "iprob", 1); + dcv.nDust = pin->GetOrAddReal("dust", "nspecies", 2); + PARTHENON_REQUIRE(dcv.nDust == 2, "dust_collision pgen requires dust nspecies == 2!"); + + auto gas_pkg = pmb->packages.Get("gas"); + auto eos_d = gas_pkg->template Param("eos_d"); + + dcv.gamma = gas_pkg->Param("adiabatic_index"); + dcv.gm1 = dcv.gamma - 1.0; + dcv.iso_cs = pin->GetOrAddReal("gas", "iso_sound_speed", 1e-1); + + const Real gdens = 1.0; + const Real gtemp = SQR(dcv.iso_cs); + const Real vx_g = 1.0; + const Real gsie = eos_d.InternalEnergyFromDensityTemperature(gdens, gtemp); + + // packing and capture variables for kernel + auto &md = pmb->meshblock_data.Get(); + for (auto &var : md->GetVariableVector()) { + if (!var->IsAllocated()) pmb->AllocateSparse(var->label()); + } + static auto desc = + MakePackDescriptor( + (pmb->resolved_packages).get()); + auto v = desc.GetPack(md.get()); + IndexRange ib = pmb->cellbounds.GetBoundsI(IndexDomain::entire); + IndexRange jb = pmb->cellbounds.GetBoundsJ(IndexDomain::entire); + IndexRange kb = pmb->cellbounds.GetBoundsK(IndexDomain::entire); + auto &dcol = dcv; + + pmb->par_for( + "pgen_dustCollision", kb.s, kb.e, jb.s, jb.e, ib.s, ib.e, + KOKKOS_LAMBDA(const int k, const int j, const int i) { + v(0, gas::prim::density(), k, j, i) = gdens; + v(0, gas::prim::velocity(0), k, j, i) = vx_g; + v(0, gas::prim::velocity(1), k, j, i) = 0.0; + v(0, gas::prim::velocity(2), k, j, i) = 0.0; + v(0, gas::prim::sie(), k, j, i) = gsie; + + // dust initial condition + if (dcol.prob_flag == 1) { // stiff problem with smaller stopping time + v(0, dust::prim::density(0), k, j, i) = 1.0; + v(0, dust::prim::density(1), k, j, i) = 1.0; + } else { + v(0, dust::prim::density(0), k, j, i) = 10.0; + v(0, dust::prim::density(1), k, j, i) = 100.0; + } + v(0, dust::prim::velocity(0 * 3 + 0), k, j, i) = 2.0; + v(0, dust::prim::velocity(0 * 3 + 1), k, j, i) = 0.0; + v(0, dust::prim::velocity(0 * 3 + 2), k, j, i) = 0.0; + + v(0, dust::prim::velocity(1 * 3 + 0), k, j, i) = 0.5; + v(0, dust::prim::velocity(1 * 3 + 1), k, j, i) = 0.0; + v(0, dust::prim::velocity(1 * 3 + 2), k, j, i) = 0.0; + }); +} + +//---------------------------------------------------------------------------------------- +//! \fn void PreStepUserworkInLoop +//! \brief output numerical solution and analytic solution before each step +//! and writing to file. +inline void PreStepUserWorkInLoop(Mesh *pmesh, ParameterInput *pin, + parthenon::SimTime &tm) { + + // packing and capture variables for kernel + auto &md = pmesh->mesh_data.GetOrAdd("base", 0); + auto pmb = md->GetBlockData(0)->GetBlockPointer(); + static auto desc = MakePackDescriptor( + (pmb->resolved_packages).get()); + auto v = desc.GetPack(md.get()); + + IndexRange ib = pmb->cellbounds.GetBoundsI(IndexDomain::interior); + IndexRange jb = pmb->cellbounds.GetBoundsJ(IndexDomain::interior); + IndexRange kb = pmb->cellbounds.GetBoundsK(IndexDomain::interior); + + // root process opens output file and writes out data + if (parthenon::Globals::my_rank == 0) { + std::string fname; + fname.assign(pin->GetString("parthenon/job", "problem_id")); + fname.append("-solu1.dat"); + static FILE *pfile = NULL; + + // The file exists -- reopen the file in append mode + if (pfile == NULL) { + if ((pfile = std::fopen(fname.c_str(), "r")) != nullptr) { + if ((pfile = std::freopen(fname.c_str(), "a", pfile)) == nullptr) { + PARTHENON_FAIL("Error output file could not be opened"); + } + // The file does not exist -- open the file in write mode and add headers + } else { + if ((pfile = std::fopen(fname.c_str(), "w")) == nullptr) { + PARTHENON_FAIL("Error output file could not be opened"); + } + std::fprintf(pfile, "# time vel-g vel-ge vel-d1 vel-d1e vel-d2 vel-d2e \n"); + } + } + + // analytic solution + Real v_com, c1_g, c2_g, lam1, lam2, c1_d1, c2_d1, c1_d2, c2_d2; + Real v_g, v_d1, v_d2; + if (dcv.prob_flag == 1) { + v_com = 7. / 6.; + c1_g = -0.35610569612832; + c2_g = 0.18943902946166; + lam1 = -141.742430504416, lam2 = -1058.25756949558; + c1_d1 = 0.85310244713865; + c2_d1 = -0.01976911380532; + c1_d2 = -0.49699675101033; + c2_d2 = -0.16966991565634; + } else { + v_com = 0.63963963963963; + c1_g = -0.06458203330249; + c2_g = 0.42494239366285; + lam1 = -0.52370200744224; + lam2 = -105.976297992557; + c1_d1 = 1.36237475791577; + c2_d1 = -0.00201439755542; + c1_d2 = -0.13559165545855; + c2_d2 = -0.00404798418109; + } + + v_g = v_com + c1_g * std::exp(lam1 * tm.time) + c2_g * std::exp(lam2 * tm.time); + v_d1 = v_com + c1_d1 * std::exp(lam1 * tm.time) + c2_d1 * std::exp(lam2 * tm.time); + v_d2 = v_com + c1_d2 * std::exp(lam1 * tm.time) + c2_d2 * std::exp(lam2 * tm.time); + + // write data + + ParArray1D vel("outdat", 3); + + Real vg0 = 0.0, vd10 = 0.0, vd20 = 0.0; + pmb->par_for( + "out_dustCollision", kb.s, kb.e, jb.s, jb.e, ib.s, ib.s, + KOKKOS_LAMBDA(const int k, const int j, const int i) { + vel(0) = v(0, gas::prim::velocity(0), k, j, i); + vel(1) = v(0, dust::prim::velocity(0), k, j, i); + vel(2) = v(0, dust::prim::velocity(3), k, j, i); + }); + + auto dat = Kokkos::create_mirror_view_and_copy(parthenon::HostMemSpace(), vel); + vg0 = dat(0); + vd10 = dat(1); + vd20 = dat(2); + + std::fprintf(pfile, " %e ", tm.time); + std::fprintf(pfile, " %e ", vg0); + std::fprintf(pfile, " %e ", v_g); + std::fprintf(pfile, " %e ", vd10); + std::fprintf(pfile, " %e ", v_d1); + std::fprintf(pfile, " %e ", vd20); + std::fprintf(pfile, " %e ", v_d2); + + std::fprintf(pfile, "\n"); + // std::fclose(pfile); + } +} + +} // namespace dust_collision + +#endif // PGEN_DUST_COLLISION_HPP_ From 63e37b9b466dfa508c2f6977cb66c7ba4ec148a5 Mon Sep 17 00:00:00 2001 From: Shengtai Li Date: Wed, 4 Dec 2024 09:40:52 -0700 Subject: [PATCH 3/9] format fixed in pgen/dust_coagulation.hpp --- src/pgen/dust_coagulation.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pgen/dust_coagulation.hpp b/src/pgen/dust_coagulation.hpp index 23988f3..a8daa71 100644 --- a/src/pgen/dust_coagulation.hpp +++ b/src/pgen/dust_coagulation.hpp @@ -100,7 +100,6 @@ inline void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { Dust::cgsunit->SetCGSUnit(pin); } - //bool isurface_den = Dust::cgsunit->isurface_den; dcv.length0 = Dust::cgsunit->length0; dcv.mass0 = Dust::cgsunit->mass0; dcv.time0 = Dust::cgsunit->time0; From 6ba72b0161aed571d11df19f2c076e0419f48b2c Mon Sep 17 00:00:00 2001 From: Shengtai Li Date: Wed, 4 Dec 2024 22:21:58 -0700 Subject: [PATCH 4/9] fixed omega_k calculation in dust.cpp --- inputs/dust/disk_cyl_dust10.in | 2 +- src/dust/coagulation/coagulation.cpp | 2 +- src/dust/dust.cpp | 31 ++++++++++++++++++++++++---- 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/inputs/dust/disk_cyl_dust10.in b/inputs/dust/disk_cyl_dust10.in index 79bed84..b8999b7 100644 --- a/inputs/dust/disk_cyl_dust10.in +++ b/inputs/dust/disk_cyl_dust10.in @@ -102,4 +102,4 @@ h0 = 0.05 dens_min = 1.0e-10 pres_min = 1.0e-13 mstar = 1.0 # Msun -r0_length = 10.0 # AU +r0_length = 50.0 # AU diff --git a/src/dust/coagulation/coagulation.cpp b/src/dust/coagulation/coagulation.cpp index 8431598..f008076 100644 --- a/src/dust/coagulation/coagulation.cpp +++ b/src/dust/coagulation/coagulation.cpp @@ -38,7 +38,7 @@ std::shared_ptr Initialize(ParameterInput *pin) { cpars.mom_coag = pin->GetOrAddBoolean("dust", "coag_mom_preserve", true); cpars.nCall_mx = pin->GetOrAddInteger("dust", "coag_nsteps_mx", 1000); // dust particle internal density g/cc - const Real rho_p = pin->GetOrAddReal("dust", "rho_p", 1.25); + const Real rho_p = pin->GetOrAddReal("dust", "grain_density", 1.25); cpars.rho_p = rho_p; cpars.ibounce = pin->GetOrAddBoolean("dust", "coag_bounce", false); diff --git a/src/dust/dust.cpp b/src/dust/dust.cpp index b17f16d..06cdcdc 100644 --- a/src/dust/dust.cpp +++ b/src/dust/dust.cpp @@ -255,6 +255,9 @@ std::shared_ptr Initialize(ParameterInput *pin) { rho_p /= cgsunit->length0; } + if (parthenon::Globals::my_rank == 0) { + std::cout << "rho_p, rho_g0=" << rho_p << " " << rho_g0 << std::endl; + } params.Add("rho_p", rho_p); } // Scratch for dust flux @@ -390,7 +393,13 @@ TaskStatus UpdateDustStoppingTime(MeshData *md) { geometry::Coords coords(vmesh.GetCoordinates(b), k, j, i); // for surface denstiy, Stokes number = Pi/2*rho_p*s_p/sigma_g // calculate the Keplerian Omega at mid-plane - Real rad = coords.x1v(); + // const auto &hx = coords.GetScaleFactors(); + Real rad; + if constexpr (GEOM == Coordinates::cylindrical) { + rad = coords.hx2v(); // cylindrical-rad + } else { + rad = coords.hx3v(); + } Real Omega_k = 1.0 / std::sqrt(rad) / rad; for (int n = 0; n < nspecies; ++n) { const Real St = rho_p * dust_size(n) / dens_g; @@ -832,8 +841,11 @@ TaskStatus CoagulationOneStep(MeshData *md, const Real time, const Real dt geometry::Coords coords(vmesh.GetCoordinates(b), k, j, i); const auto &hx = coords.GetScaleFactors(); - const Real rad = hx[2]; // cylindrical R_cyl - const Real Omega_k = 1.0 / std::sqrt(rad) / rad; + Real rad = hx[2]; + if constexpr (GEOM == Coordinates::cylindrical) { + rad = hx[1]; + } + const Real Omega_k = 1.0 / std::sqrt(rad) / rad; // code unit // const Real vol1 = coords.Volume() * vol0; int nCall1 = 0; @@ -998,6 +1010,15 @@ TaskCollection OperatorSplitDust(Mesh *pm, parthenon::SimTime &tm, const Real dt TaskID none(0); // Assemble tasks + auto &coag = coag_pkg->template Param("coag_pars"); + const int nspecies = coag.nm; + std::vector dust_var_names; + for (int n = 0; n < nspecies; n++) { + dust_var_names.push_back(dust::prim::density::name() + '_' + std::to_string(n)); + dust_var_names.push_back(dust::prim::velocity::name() + '_' + std::to_string(n)); + } + auto &dust_subset = + pm->mesh_data.AddShallow("dust_subset", pm->mesh_data.Get(), dust_var_names); using namespace ::parthenon::Update; const int num_partitions = pm->DefaultNumPartitions(); TaskRegion &tr = tc.AddRegion(num_partitions); @@ -1011,7 +1032,9 @@ TaskCollection OperatorSplitDust(Mesh *pm, parthenon::SimTime &tm, const Real dt auto pre_comm = tl.AddTask(coag_step, PreCommFillDerived>, base.get()); // Set boundary conditions (both physical and logical) - auto bcs = parthenon::AddBoundaryExchangeTasks(pre_comm, tl, base, pm->multilevel); + // auto bcs = parthenon::AddBoundaryExchangeTasks(pre_comm, tl, base, pm->multilevel); + auto &md_coag = pm->mesh_data.GetOrAdd("dust_subset", i); + auto bcs = parthenon::AddBoundaryExchangeTasks(pre_comm, tl, md_coag, pm->multilevel); // Update primitive variables auto c2p = tl.AddTask(bcs, FillDerived>, base.get()); From 1beaf24b0c20f13871d99e615e18766c3e53dcd7 Mon Sep 17 00:00:00 2001 From: Shengtai Li Date: Thu, 5 Dec 2024 13:19:51 -0700 Subject: [PATCH 5/9] remove dust_drag --- src/artemis.hpp | 8 - src/artemis_driver.cpp | 8 +- src/dust/dust.cpp | 375 +++++------------------------------------ src/dust/dust.hpp | 2 - 4 files changed, 47 insertions(+), 346 deletions(-) diff --git a/src/artemis.hpp b/src/artemis.hpp index 1350768..8cd3700 100644 --- a/src/artemis.hpp +++ b/src/artemis.hpp @@ -92,14 +92,6 @@ enum class RSolver { hllc, hlle, llf, null }; enum class ReconstructionMethod { pcm, plm, ppm, null }; // ...Fluid types enum class Fluid { gas, dust, null }; -// constants that enumerate dust drag method -enum class DragMethod { - explicitNoFeedback, - explicitFeedback, - implicitNoFeedback, - implicitFeedback, - null -}; // ...Boundary conditions enum class ArtemisBC { reflect, diff --git a/src/artemis_driver.cpp b/src/artemis_driver.cpp index 2c0d117..455360c 100644 --- a/src/artemis_driver.cpp +++ b/src/artemis_driver.cpp @@ -260,15 +260,9 @@ TaskCollection ArtemisDriver::StepTasks() { tl.AddTask(drag_src, Gas::Cooling::CoolingSource, u0.get(), time, bdt); } - // Add dust drag force - TaskID dust_drag_src = cooling_src; - if (do_dust) { - dust_drag_src = tl.AddTask(cooling_src, Dust::ApplyDragForce, u0.get(), bdt); - } - // Set auxillary fields auto set_aux = - tl.AddTask(dust_drag_src, ArtemisDerived::SetAuxillaryFields, u0.get()); + tl.AddTask(cooling_src, ArtemisDerived::SetAuxillaryFields, u0.get()); // Set (remaining) fields to be communicated auto pre_comm = tl.AddTask(set_aux, PreCommFillDerived>, u0.get()); diff --git a/src/dust/dust.cpp b/src/dust/dust.cpp index 06cdcdc..916c672 100644 --- a/src/dust/dust.cpp +++ b/src/dust/dust.cpp @@ -103,41 +103,12 @@ std::shared_ptr Initialize(ParameterInput *pin) { for (int n = 0; n < nspecies; ++n) dustids.push_back(n); - // dust stopping time flag - bool const_stopping_time = pin->GetOrAddBoolean("dust", "const_stopping_time", true); - params.Add("const_stopping_time", const_stopping_time); - - bool enable_dust_drag = pin->GetOrAddBoolean("dust", "enable_dust_drag", false); - params.Add("enable_dust_drag", enable_dust_drag); - bool hst_out_d2g = pin->GetOrAddBoolean("dust", "hst_out_d2g", false); params.Add("hst_out_d2g", hst_out_d2g); // coagulation flag bool enable_dust_coagulation = pin->GetOrAddBoolean("physics", "coagulation", false); - DragMethod drag_method = DragMethod::null; - if (enable_dust_drag) { - bool enable_dust_feedback = pin->GetBoolean("dust", "enable_dust_feedback"); - std::string drag_method1 = pin->GetOrAddString("dust", "drag_method", "implicit"); - - if (drag_method1 == "implicit") { - if (enable_dust_feedback) { - drag_method = DragMethod::implicitFeedback; - } else { - drag_method = DragMethod::implicitNoFeedback; - } - } else { - if (enable_dust_feedback) { - drag_method = DragMethod::explicitFeedback; - } else { - drag_method = DragMethod::explicitNoFeedback; - } - } - - params.Add("drag_method", drag_method); - } // end if (enable_dust_drag) - // Dust sizes auto size_dist = pin->GetOrAddString("dust", "size_input", "direct"); if (enable_dust_coagulation) size_dist = "logspace"; @@ -212,7 +183,7 @@ std::shared_ptr Initialize(ParameterInput *pin) { sizes.DeepCopy(h_sizes); params.Add("sizes", sizes); params.Add("h_sizes", h_sizes); - } else if (!const_stopping_time) { + } else { PARTHENON_FAIL("dust/size_input not recognized!"); } @@ -220,18 +191,7 @@ std::shared_ptr Initialize(ParameterInput *pin) { const Real rho_p_orig = pin->GetOrAddReal("dust", "grain_density", 1.0); params.Add("grain_density", rho_p_orig); - if (const_stopping_time) { - if (enable_dust_drag) { - ParArray1D stopping_time("dust_stopping_time", nspecies); - auto stopping_time_host = stopping_time.GetHostMirror(); - auto stopping_v = pin->GetVector("dust", "stopping_time"); - for (int n = 0; n < nspecies; ++n) { - stopping_time_host(n) = stopping_v[n]; - } - stopping_time.DeepCopy(stopping_time_host); - params.Add("stopping_time", stopping_time); - } - } else { + if (enable_dust_coagulation) { if (cgsunit == NULL) { cgsunit = new CGSUnit; } @@ -336,8 +296,7 @@ TaskStatus UpdateDustStoppingTime(MeshData *md) { auto pm = md->GetParentPointer(); auto &dust_pkg = pm->packages.Get("dust"); - if ((!dust_pkg->template Param("enable_dust_drag")) && - (!dust_pkg->template Param("enable_coagulation"))) { + if ((!dust_pkg->template Param("enable_coagulation"))) { return TaskStatus::complete; } @@ -349,75 +308,54 @@ TaskStatus UpdateDustStoppingTime(MeshData *md) { const int nspecies = dust_pkg->template Param("nspecies"); - const bool const_stopping_time = dust_pkg->template Param("const_stopping_time"); + const bool isurf_den = cgsunit->isurface_den; + ParArray1D dust_size = dust_pkg->template Param>("sizes"); + static auto desc = + MakePackDescriptor( + resolved_pkgs.get()); + + auto vmesh = desc.GetPack(md); + + auto &gas_pkg = pm->packages.Get("gas"); + + const Real gamma = gas_pkg->template Param("adiabatic_index"); + const Real rho_p = dust_pkg->template Param("rho_p"); - if (const_stopping_time) { - ParArray1D stoppingTime = - dust_pkg->template Param>("stopping_time"); - static auto desc = MakePackDescriptor(resolved_pkgs.get()); + parthenon::par_for( + DEFAULT_LOOP_PATTERN, "Dust::DustStoppingTime2", parthenon::DevExecSpace(), 0, + md->NumBlocks() - 1, kb.s, kb.e, jb.s, jb.e, ib.s, ib.e, + KOKKOS_LAMBDA(const int b, const int k, const int j, const int i) { + const Real dens_g = vmesh(b, gas::prim::density(0), k, j, i); + // usually the Stokes number depends gas density, unless constant is used + // stopping_time = Stokes_number/Omega_k - auto vmesh = desc.GetPack(md); - parthenon::par_for( - DEFAULT_LOOP_PATTERN, "Dust::DustStoppingTime", parthenon::DevExecSpace(), 0, - md->NumBlocks() - 1, kb.s, kb.e, jb.s, jb.e, ib.s, ib.e, - KOKKOS_LAMBDA(const int b, const int k, const int j, const int i) { - // usually the stopping time depends gas density, unless constant is used - // constant stopping time + if (isurf_den) { + geometry::Coords coords(vmesh.GetCoordinates(b), k, j, i); + // for surface denstiy, Stokes number = Pi/2*rho_p*s_p/sigma_g + // calculate the Keplerian Omega at mid-plane + Real rad; + if constexpr (GEOM == Coordinates::cylindrical) { + rad = coords.hx2v(); // cylindrical-rad + } else { + rad = coords.hx3v(); + } + Real Omega_k = 1.0 / std::sqrt(rad) / rad; for (int n = 0; n < nspecies; ++n) { - vmesh(b, dust::stopping_time(n), k, j, i) = stoppingTime(n); + const Real St = rho_p * dust_size(n) / dens_g; + vmesh(b, dust::stopping_time(n), k, j, i) = St / Omega_k; } - }); - } else { - const bool isurf_den = cgsunit->isurface_den; - ParArray1D dust_size = dust_pkg->template Param>("sizes"); - static auto desc = - MakePackDescriptor( - resolved_pkgs.get()); - - auto vmesh = desc.GetPack(md); - - auto &gas_pkg = pm->packages.Get("gas"); - - const Real gamma = gas_pkg->template Param("adiabatic_index"); - const Real rho_p = dust_pkg->template Param("rho_p"); - - parthenon::par_for( - DEFAULT_LOOP_PATTERN, "Dust::DustStoppingTime2", parthenon::DevExecSpace(), 0, - md->NumBlocks() - 1, kb.s, kb.e, jb.s, jb.e, ib.s, ib.e, - KOKKOS_LAMBDA(const int b, const int k, const int j, const int i) { - const Real dens_g = vmesh(b, gas::prim::density(0), k, j, i); - // usually the Stokes number depends gas density, unless constant is used - // stopping_time = Stokes_number/Omega_k - - if (isurf_den) { - geometry::Coords coords(vmesh.GetCoordinates(b), k, j, i); - // for surface denstiy, Stokes number = Pi/2*rho_p*s_p/sigma_g - // calculate the Keplerian Omega at mid-plane - // const auto &hx = coords.GetScaleFactors(); - Real rad; - if constexpr (GEOM == Coordinates::cylindrical) { - rad = coords.hx2v(); // cylindrical-rad - } else { - rad = coords.hx3v(); - } - Real Omega_k = 1.0 / std::sqrt(rad) / rad; - for (int n = 0; n < nspecies; ++n) { - const Real St = rho_p * dust_size(n) / dens_g; - vmesh(b, dust::stopping_time(n), k, j, i) = St / Omega_k; - } - } else { + } else { - // for density (g/cc), Stokes number = sqrt(Pi/8)*rho_p*s_p*Omega_k/rho_g/Cs - const Real pres = vmesh(b, gas::prim::pressure(0), k, j, i); - const Real cs = std::sqrt(gamma * pres / dens_g); - for (int n = 0; n < nspecies; ++n) { - const Real StOme = rho_p * dust_size(n) / dens_g; - vmesh(b, dust::stopping_time(n), k, j, i) = StOme / cs; - } + // for density (g/cc), Stokes number = sqrt(Pi/8)*rho_p*s_p*Omega_k/rho_g/Cs + const Real pres = vmesh(b, gas::prim::pressure(0), k, j, i); + const Real cs = std::sqrt(gamma * pres / dens_g); + for (int n = 0; n < nspecies; ++n) { + const Real StOme = rho_p * dust_size(n) / dens_g; + vmesh(b, dust::stopping_time(n), k, j, i) = StOme / cs; } - }); - } + } + }); return TaskStatus::complete; } @@ -434,20 +372,9 @@ Real EstimateTimestepMesh(MeshData *md) { auto &dust_pkg = pm->packages.Get("dust"); auto ¶ms = dust_pkg->AllParams(); - auto dragDt = params.template Get("user_dt"); + auto userDt = params.template Get("user_dt"); auto nspecies = params.template Get("nspecies"); - bool dt_stoppingTime = false; - if (params.template Get("enable_dust_drag")) { - UpdateDustStoppingTime(md); - if ((params.template Get("drag_method") == - DragMethod::explicitFeedback) || - (params.template Get("drag_method") == - DragMethod::explicitNoFeedback)) { - dt_stoppingTime = true; - } - } - const auto cfl_number = params.template Get("cfl"); static auto desc = MakePackDescriptor( @@ -474,15 +401,10 @@ Real EstimateTimestepMesh(MeshData *md) { } ldt = std::min(ldt, 1.0 / denom * cfl_number); } - if (dt_stoppingTime) { - for (int n = 0; n < nspecies; ++n) { - ldt = std::min(ldt, vmesh(b, dust::stopping_time(n), k, j, i)); - } - } }, Kokkos::Min(min_dt)); - return std::min(dragDt, min_dt); + return std::min(userDt, min_dt); } //---------------------------------------------------------------------------------------- @@ -535,211 +457,6 @@ TaskStatus FluxSource(MeshData *md, const Real dt) { return TaskStatus::complete; } -//---------------------------------------------------------------------------------------- -//! \fn TaskStatus Dust::ApplyDragForceSelect -// \brief Wrapper function for dust-drag froce based on different drag-method -template -TaskStatus ApplyDragForceSelect(MeshData *md, const Real dt) { - - using parthenon::MakePackDescriptor; - - auto pm = md->GetParentPointer(); - auto &dust_pkg = pm->packages.Get("dust"); - IndexRange ib = md->GetBoundsI(IndexDomain::interior); - IndexRange jb = md->GetBoundsJ(IndexDomain::interior); - IndexRange kb = md->GetBoundsK(IndexDomain::interior); - - auto &resolved_pkgs = pm->resolved_packages; - auto &DUST_DRAG = dust_pkg->template Param("drag_method"); - - static auto desc = - MakePackDescriptor(resolved_pkgs.get()); - - auto vmesh = desc.GetPack(md); - - if ((DUST_DRAG == DragMethod::explicitFeedback) || - (DUST_DRAG == DragMethod::explicitNoFeedback)) { - parthenon::par_for( - DEFAULT_LOOP_PATTERN, "Dust::DustDrag", parthenon::DevExecSpace(), 0, - md->NumBlocks() - 1, kb.s, kb.e, jb.s, jb.e, ib.s, ib.e, - KOKKOS_LAMBDA(const int b, const int k, const int j, const int i) { - const Real dens_g = vmesh(b, gas::prim::density(0), k, j, i); - const int nspecies = vmesh.GetUpperBound(b, dust::prim::density()) - - vmesh.GetLowerBound(b, dust::prim::density()) + 1; - geometry::Coords coords(vmesh.GetCoordinates(b), k, j, i); - const auto &hx = coords.GetScaleFactors(); - - for (int n = 0; n < nspecies; ++n) { - const Real dens_d = vmesh(b, dust::prim::density(n), k, j, i); - const Real tst = vmesh(b, dust::stopping_time(n), k, j, i); - const Real cj = dt * dens_d / tst; - - vmesh(b, dust::cons::momentum(VI(n, 0)), k, j, i) += - cj * hx[0] * - (vmesh(b, gas::prim::velocity(0), k, j, i) - - vmesh(b, dust::prim::velocity(VI(n, 0)), k, j, i)); - - vmesh(b, dust::cons::momentum(VI(n, 1)), k, j, i) += - cj * hx[1] * - (vmesh(b, gas::prim::velocity(1), k, j, i) - - vmesh(b, dust::prim::velocity(VI(n, 1)), k, j, i)); - - vmesh(b, dust::cons::momentum(VI(n, 2)), k, j, i) += - cj * hx[2] * - (vmesh(b, gas::prim::velocity(2), k, j, i) - - vmesh(b, dust::prim::velocity(VI(n, 2)), k, j, i)); - } - if (DUST_DRAG == DragMethod::explicitFeedback) { - const Real dens_g = vmesh(b, gas::cons::density(0), k, j, i); - Real delta_mom1 = 0.0; - Real delta_mom2 = 0.0; - Real delta_mom3 = 0.0; - for (int n = 0; n < nspecies; ++n) { - const Real dens_d = vmesh(b, dust::prim::density(n), k, j, i); - const Real tst = vmesh(b, dust::stopping_time(n), k, j, i); - Real cj = dt * dens_d / tst; - delta_mom1 -= cj * (vmesh(b, gas::prim::velocity(0), k, j, i) - - vmesh(b, dust::prim::velocity(VI(n, 0)), k, j, i)); - delta_mom2 -= cj * (vmesh(b, gas::prim::velocity(1), k, j, i) - - vmesh(b, dust::prim::velocity(VI(n, 1)), k, j, i)); - delta_mom3 -= cj * (vmesh(b, gas::prim::velocity(2), k, j, i) - - vmesh(b, dust::prim::velocity(VI(n, 2)), k, j, i)); - } - vmesh(b, gas::cons::momentum(0), k, j, i) += delta_mom1 * hx[0]; - vmesh(b, gas::cons::momentum(1), k, j, i) += delta_mom2 * hx[1]; - vmesh(b, gas::cons::momentum(2), k, j, i) += delta_mom3 * hx[2]; - - // gas energy update: delta_E = delta_mom*(M_new - 0.5*delta_mom)/rho_g - // delta_E = 0.5*rhog*(V_new^2 - V_old^2) - - vmesh(b, gas::cons::total_energy(0), k, j, i) += - (delta_mom1 * (vmesh(b, gas::cons::momentum(0), k, j, i) / hx[0] - - delta_mom1 * 0.5) + - delta_mom2 * (vmesh(b, gas::cons::momentum(1), k, j, i) / hx[1] - - delta_mom2 * 0.5) + - delta_mom3 * (vmesh(b, gas::cons::momentum(2), k, j, i) / hx[2] - - delta_mom3 * 0.5)) / - dens_g; - } - }); - - } else if ((DUST_DRAG == DragMethod::implicitFeedback) || - (DUST_DRAG == DragMethod::implicitNoFeedback)) { - auto &dfloor = dust_pkg->template Param("dfloor"); - parthenon::par_for( - DEFAULT_LOOP_PATTERN, "Dust::DustDragImp", parthenon::DevExecSpace(), 0, - md->NumBlocks() - 1, kb.s, kb.e, jb.s, jb.e, ib.s, ib.e, - KOKKOS_LAMBDA(const int b, const int k, const int j, const int i) { - geometry::Coords coords(vmesh.GetCoordinates(b), k, j, i); - const auto &hx = coords.GetScaleFactors(); - const int nspecies = vmesh.GetUpperBound(b, dust::prim::density()) - - vmesh.GetLowerBound(b, dust::prim::density()) + 1; - - const Real dens_g = vmesh(b, gas::cons::density(0), k, j, i); - Real mom1_g = vmesh(b, gas::cons::momentum(0), k, j, i); - Real mom2_g = vmesh(b, gas::cons::momentum(1), k, j, i); - Real mom3_g = vmesh(b, gas::cons::momentum(2), k, j, i); - - Real vel1_g = mom1_g / (dens_g * hx[0]); - Real vel2_g = mom2_g / (dens_g * hx[1]); - Real vel3_g = mom3_g / (dens_g * hx[2]); - const Real coef1 = dens_g / vmesh(b, gas::prim::density(0), k, j, i); - - if (DUST_DRAG == DragMethod::implicitFeedback) { - - Real tmp1 = dens_g; - const Real vel1_go = vel1_g; - const Real vel2_go = vel2_g; - const Real vel3_go = vel3_g; - for (int n = 0; n < nspecies; ++n) { - const Real dens_d = vmesh(b, dust::cons::density(n), k, j, i); - const Real tst = vmesh(b, dust::stopping_time(n), k, j, i); - const Real cj = dt * dens_d / tst * coef1; // use updated dens_g - const Real bj1 = vmesh(b, dust::cons::momentum(VI(n, 0)), k, j, i); - const Real bj2 = vmesh(b, dust::cons::momentum(VI(n, 1)), k, j, i); - const Real bj3 = vmesh(b, dust::cons::momentum(VI(n, 2)), k, j, i); - const Real dj = dens_d + cj; - - const Real cjOdj = cj / dj; - tmp1 += (cj - cj * cjOdj); - mom1_g += bj1 * cjOdj; - mom2_g += bj2 * cjOdj; - mom3_g += bj3 * cjOdj; - } - - vel1_g = mom1_g / (tmp1 * hx[0]); - vel2_g = mom2_g / (tmp1 * hx[1]); - vel3_g = mom3_g / (tmp1 * hx[2]); - vmesh(b, gas::cons::momentum(0), k, j, i) = dens_g * vel1_g * hx[0]; - vmesh(b, gas::cons::momentum(1), k, j, i) = dens_g * vel2_g * hx[1]; - vmesh(b, gas::cons::momentum(2), k, j, i) = dens_g * vel3_g * hx[2]; - - // gas energy update: delta_E = 0.5*(v_new^2 - v_old^2)*rho_g - vmesh(b, gas::cons::total_energy(0), k, j, i) += - 0.5 * - (SQR(vel1_g) - SQR(vel1_go) + SQR(vel2_g) - SQR(vel2_go) + SQR(vel3_g) - - SQR(vel3_go)) * - dens_g; - } // end if (DUST_DRAG == DragMethod::implicitFeedback) - - // update the dust - for (int n = 0; n < nspecies; ++n) { - const Real dens_d = - std::max(dfloor, vmesh(b, dust::cons::density(n), k, j, i)); - const Real tst = vmesh(b, dust::stopping_time(n), k, j, i); - const Real cj = dt * dens_d / tst * coef1; // use updated dens_g - const Real bj1 = vmesh(b, dust::cons::momentum(VI(n, 0)), k, j, i); - const Real bj2 = vmesh(b, dust::cons::momentum(VI(n, 1)), k, j, i); - const Real bj3 = vmesh(b, dust::cons::momentum(VI(n, 2)), k, j, i); - const Real dj = dens_d + cj; - vmesh(b, dust::cons::momentum(VI(n, 0)), k, j, i) = - dens_d * (bj1 + cj * vel1_g * hx[0]) / dj; - vmesh(b, dust::cons::momentum(VI(n, 1)), k, j, i) = - dens_d * (bj2 + cj * vel2_g * hx[1]) / dj; - vmesh(b, dust::cons::momentum(VI(n, 2)), k, j, i) = - dens_d * (bj3 + cj * vel3_g * hx[2]) / dj; - } - }); - } - - return TaskStatus::complete; -} - -//---------------------------------------------------------------------------------------- -//! \fn TaskStatus Dust::ApplyDragForce -// \brief Wrapper function for dust-drag froce -TaskStatus ApplyDragForce(MeshData *md, const Real dt) { - - using parthenon::MakePackDescriptor; - - auto pm = md->GetParentPointer(); - auto &dust_pkg = pm->packages.Get("dust"); - if (!dust_pkg->template Param("enable_dust_drag")) { - return TaskStatus::complete; - } - - const Coordinates GEOM = dust_pkg->template Param("coords"); - - if (GEOM == Coordinates::cartesian) { - return ApplyDragForceSelect(md, dt); - } else if (GEOM == Coordinates::spherical1D) { - return ApplyDragForceSelect(md, dt); - } else if (GEOM == Coordinates::spherical2D) { - return ApplyDragForceSelect(md, dt); - } else if (GEOM == Coordinates::spherical3D) { - return ApplyDragForceSelect(md, dt); - } else if (GEOM == Coordinates::cylindrical) { - return ApplyDragForceSelect(md, dt); - } else if (GEOM == Coordinates::axisymmetric) { - return ApplyDragForceSelect(md, dt); - } else { - PARTHENON_FAIL("Coordinate type not recognized!"); - } -} - //#define COAG_DEBUG //---------------------------------------------------------------------------------------- //! \fn TaskStatus Dust::CoagulationOneStep diff --git a/src/dust/dust.hpp b/src/dust/dust.hpp index 535240c..50dbb06 100644 --- a/src/dust/dust.hpp +++ b/src/dust/dust.hpp @@ -83,8 +83,6 @@ extern CGSUnit *cgsunit; template TaskStatus UpdateDustStoppingTime(MeshData *md); -TaskStatus ApplyDragForce(MeshData *md, const Real dt); - // OperatorSplit tasks template TaskCollection OperatorSplitDust(Mesh *pm, parthenon::SimTime &tm, const Real dt); From a26caada247101a58ce76fbd44cd9a1cc76db340 Mon Sep 17 00:00:00 2001 From: Shengtai Li Date: Wed, 11 Dec 2024 13:42:50 -0700 Subject: [PATCH 6/9] modification based on merge comments --- inputs/dust/SI_strat1_amr_BA.in | 146 -------- inputs/dust/SI_strat_AB.in | 135 -------- inputs/dust/SI_strat_BA.in | 135 -------- inputs/dust/disk_cyl_dust10.in | 105 ------ inputs/dust/dust_coagulation.in | 68 ++-- inputs/dust/dust_coagulation_den.in | 71 ++-- inputs/dust/dust_collision.in | 51 +-- src/artemis.cpp | 24 +- src/artemis.hpp | 6 +- src/artemis_driver.cpp | 15 +- src/dust/coagulation/coagulation.cpp | 120 +++---- src/dust/coagulation/coagulation.hpp | 41 +-- src/dust/dust.cpp | 489 +++++++++++---------------- src/dust/dust.hpp | 53 +-- src/pgen/dust_coagulation.hpp | 149 +++++--- src/pgen/dust_collision.hpp | 2 +- 16 files changed, 471 insertions(+), 1139 deletions(-) delete mode 100644 inputs/dust/SI_strat1_amr_BA.in delete mode 100644 inputs/dust/SI_strat_AB.in delete mode 100644 inputs/dust/SI_strat_BA.in delete mode 100644 inputs/dust/disk_cyl_dust10.in diff --git a/inputs/dust/SI_strat1_amr_BA.in b/inputs/dust/SI_strat1_amr_BA.in deleted file mode 100644 index 8e3e24b..0000000 --- a/inputs/dust/SI_strat1_amr_BA.in +++ /dev/null @@ -1,146 +0,0 @@ -# ======================================================================================== -# (C) (or copyright) 2023-2024. Triad National Security, LLC. All rights reserved. -# -# This program was produced under U.S. Government contract 89233218CNA000001 for Los -# Alamos National Laboratory (LANL), which is operated by Triad National Security, LLC -# for the U.S. Department of Energy/National Nuclear Security Administration. All rights -# in the program are reserved by Triad National Security, LLC, and the U.S. Department -# of Energy/National Nuclear Security Administration. The Government is granted for -# itself and others acting on its behalf a nonexclusive, paid-up, irrevocable worldwide -# license in this material to reproduce, prepare derivative works, distribute copies to -# the public, perform publicly and display publicly, and to permit others to do so. -# ======================================================================================== - - -problem = SI_strat # name of the pgen -coordinates = cartesian - - -problem_id = runBA # problem ID: basename of output filenames - - -file_type = hst -dt = 0.01 - - -variables = gas.prim.density, & - gas.prim.velocity, & - dust.prim.density, & - dust.prim.velocity - -file_type = hdf5 # HDF5 data dump -dt = 2.0 # time increment between outputs - - -file_type = rst -dt = 100.0 - - -nlim = -1 # cycle limit -tlim = 400.0 # time limit -integrator = rk2 # time integration algorithm -ncycle_out = 100 # interval for stdout summary info - - -nx1 = 1024 # Number of zones in X1-direction -x1min = -0.4 # minimum value of X1 -x1max = 0.4 # maximum value of X1 -ix1_bc = extrapolate # Inner-X1 boundary condition flag -ox1_bc = extrapolate # Outer-X1 boundary condition flag - -nx2 = 512 # Number of zones in X2-direction -x2min = -0.2 # minimum value of X2 -x2max = 0.2 # maximum value of X2 -ix2_bc = extrapolate # Inner-X2 boundary condition flag -ox2_bc = extrapolate # Outer-X2 boundary condition flag - -nx3 = 1 # Number of zones in X3-direction -x3min = -0.5 # minimum value of X3 -x3max = 0.5 # maximum value of X3 -ix3_bc = periodic # Inner-X3 boundary condition flag -ox3_bc = periodic # Outer-X3 boundary condition flag - -# nghost = 2 -refinement = static -numlevel = 2 #3 - - -x1min = -0.3 -x1max = 0.3 -x2min = -0.02 -x2max = 0.02 -level = 1 - - - - -nx1 = 16 # Number of cells in each MeshBlock, X1-dir -nx2 = 16 # Number of cells in each MeshBlock, X2-dir -nx3 = 16 # Number of cells in each MeshBlock, X3-dir - - -gas = true -gravity = false -rotating_frame = true -dust = true - - -cfl = 0.6 -gamma = 1.000001 -reconstruct = plm -riemann = hlle -dfloor = 1.0e-10 -siefloor = 1.0e-10 -refine_field = density -refine_type = magnitude -refine_thr = 3.0 -deref_thr = 0.8 - - -reconstruct = plm -riemann = hlle -nspecies = 1 -const_stopping_time = true -size_input = none -stopping_time = 0.3 -Hratio = 0.1 - -hst_out_d2g = true -Kai0 = 0.1 #2*etaVk*iso_cs - -enable_dust_drag = true -enable_dust_feedback = true -drag_method = implicit -#rho_p = 1.25 -#rho_g0 = 0.3555 #g/cm^2, code-to-physical convert -#user_input_size = true -#Size_1 = 10.0 # dust size - - - -#type = uniform -#gx1 = 0.1 # 2*etaVk*Ome0 -#gx2 = 0.0 -#gx3 = 0.0 - -#type = point -#gm = 1e-5 -#soft = .03 -#x = 0 -#y = 0 -#z = 0 - - -omega = 1.0 -qshear = 1.5 -shboxcoord = 2 # 1=xy; 2=xz -stratified_flag = true - - -rho0 = 0.3989422804 #1.0/sqrt(2*pi) -dens_min = 1.0e-10 -pres_min = 1.0e-13 -h = 1.0 -etaVk = 0.05 -amp = 0.1 -dust_to_gas = 0.04 diff --git a/inputs/dust/SI_strat_AB.in b/inputs/dust/SI_strat_AB.in deleted file mode 100644 index 0cd6953..0000000 --- a/inputs/dust/SI_strat_AB.in +++ /dev/null @@ -1,135 +0,0 @@ -# ======================================================================================== -# (C) (or copyright) 2023-2024. Triad National Security, LLC. All rights reserved. -# -# This program was produced under U.S. Government contract 89233218CNA000001 for Los -# Alamos National Laboratory (LANL), which is operated by Triad National Security, LLC -# for the U.S. Department of Energy/National Nuclear Security Administration. All rights -# in the program are reserved by Triad National Security, LLC, and the U.S. Department -# of Energy/National Nuclear Security Administration. The Government is granted for -# itself and others acting on its behalf a nonexclusive, paid-up, irrevocable worldwide -# license in this material to reproduce, prepare derivative works, distribute copies to -# the public, perform publicly and display publicly, and to permit others to do so. -# ======================================================================================== - - -problem = SI_strat # name of the pgen -coordinates = cartesian - - -problem_id = runAB # problem ID: basename of output filenames - - -file_type = hst -dt = 0.01 - - -variables = gas.prim.density, & - gas.prim.velocity, & - dust.prim.density, & - dust.prim.velocity - -file_type = hdf5 # HDF5 data dump -dt = 0.5 # time increment between outputs - - -file_type = rst -dt = 20.0 - - -nlim = -1 # cycle limit -tlim = 40.0 # time limit -integrator = rk2 # time integration algorithm -ncycle_out = 20 # interval for stdout summary info - - -nx1 = 512 # Number of zones in X1-direction -x1min = -0.05 # minimum value of X1 -x1max = 0.05 # maximum value of X1 -ix1_bc = extrapolate # Inner-X1 boundary condition flag -ox1_bc = extrapolate # Outer-X1 boundary condition flag - -nx2 = 512 # Number of zones in X2-direction -x2min = -0.05 # minimum value of X2 -x2max = 0.05 # maximum value of X2 -ix2_bc = periodic # Inner-X2 boundary condition flag -ox2_bc = periodic # Outer-X2 boundary condition flag - -nx3 = 1 # Number of zones in X3-direction -x3min = -0.5 # minimum value of X3 -x3max = 0.5 # maximum value of X3 -ix3_bc = periodic # Inner-X3 boundary condition flag -ox3_bc = periodic # Outer-X3 boundary condition flag - -# nghost = 2 -# refinement = adaptive -# numlevel = 4 - - -nx1 = 16 # Number of cells in each MeshBlock, X1-dir -nx2 = 16 # Number of cells in each MeshBlock, X2-dir -nx3 = 1 # Number of cells in each MeshBlock, X3-dir - - -gas = true -gravity = false -rotating_frame = true -dust = true - - -cfl = 0.6 -gamma = 1.000001 -reconstruct = plm -riemann = hlle -dfloor = 1.0e-10 -siefloor = 1.0e-10 -refine_field = density -refine_type = magnitude -refine_thr = 3.0 -deref_thr = 0.8 - - -reconstruct = plm -riemann = hlle -nspecies = 1 -const_stopping_time = true -size_input = none -stopping_time = 0.1 -hst_out_d2g = true -Kai0 = 0.1 #2*etaVk*iso_cs - -enable_dust_drag = true -enable_dust_feedback = true -drag_method = explicit -#rho_p = 1.25 -#rho_g0 = 0.3555 #g/cm^2, code-to-physical convert -#user_input_size = true -#Size_1 = 10.0 # dust size - - - -#type = uniform -#gx1 = 0.1 # 2*etaVk*Ome0 -#gx2 = 0.0 -#gx3 = 0.0 - -#type = point -#gm = 1e-5 -#soft = .03 -#x = 0 -#y = 0 -#z = 0 - - -omega = 1.0 -qshear = 1.5 -shboxcoord = 2 # 1=xy; 2=xz -stratified_flag = false - - -rho0 = 1.0 -dens_min = 1.0e-10 -pres_min = 1.0e-13 -h = 1.0 -etaVk = 0.05 -amp = 0.25 -dust_to_gas = 1.0 diff --git a/inputs/dust/SI_strat_BA.in b/inputs/dust/SI_strat_BA.in deleted file mode 100644 index edb8caf..0000000 --- a/inputs/dust/SI_strat_BA.in +++ /dev/null @@ -1,135 +0,0 @@ -# ======================================================================================== -# (C) (or copyright) 2023-2024. Triad National Security, LLC. All rights reserved. -# -# This program was produced under U.S. Government contract 89233218CNA000001 for Los -# Alamos National Laboratory (LANL), which is operated by Triad National Security, LLC -# for the U.S. Department of Energy/National Nuclear Security Administration. All rights -# in the program are reserved by Triad National Security, LLC, and the U.S. Department -# of Energy/National Nuclear Security Administration. The Government is granted for -# itself and others acting on its behalf a nonexclusive, paid-up, irrevocable worldwide -# license in this material to reproduce, prepare derivative works, distribute copies to -# the public, perform publicly and display publicly, and to permit others to do so. -# ======================================================================================== - - -problem = SI_strat # name of the pgen -coordinates = cartesian - - -problem_id = runBA # problem ID: basename of output filenames - - -file_type = hst -dt = 0.02 - - -variables = gas.prim.density, & - gas.prim.velocity, & - dust.prim.density, & - dust.prim.velocity - -file_type = hdf5 # HDF5 data dump -dt = 10 # time increment between outputs - - -file_type = rst -dt = 100.0 - - -nlim = -1 # cycle limit -tlim = 800.0 # time limit -integrator = rk2 # time integration algorithm -ncycle_out = 20 # interval for stdout summary info - - -nx1 = 512 # Number of zones in X1-direction -x1min = -1.0 # minimum value of X1 -x1max = 1.0 # maximum value of X1 -ix1_bc = extrapolate # Inner-X1 boundary condition flag -ox1_bc = extrapolate # Outer-X1 boundary condition flag - -nx2 = 512 # Number of zones in X2-direction -x2min = -1.0 # minimum value of X2 -x2max = 1.0 # maximum value of X2 -ix2_bc = periodic # Inner-X2 boundary condition flag -ox2_bc = periodic # Outer-X2 boundary condition flag - -nx3 = 1 # Number of zones in X3-direction -x3min = -0.5 # minimum value of X3 -x3max = 0.5 # maximum value of X3 -ix3_bc = periodic # Inner-X3 boundary condition flag -ox3_bc = periodic # Outer-X3 boundary condition flag - -# nghost = 2 -# refinement = adaptive -# numlevel = 4 - - -nx1 = 16 # Number of cells in each MeshBlock, X1-dir -nx2 = 16 # Number of cells in each MeshBlock, X2-dir -nx3 = 16 # Number of cells in each MeshBlock, X3-dir - - -gas = true -gravity = false -rotating_frame = true -dust = true - - -cfl = 0.6 -gamma = 1.000001 -reconstruct = plm -riemann = hlle -dfloor = 1.0e-10 -siefloor = 1.0e-10 -refine_field = density -refine_type = magnitude -refine_thr = 3.0 -deref_thr = 0.8 - - -reconstruct = plm -riemann = hlle -nspecies = 1 -const_stopping_time = true -size_input = none -stopping_time = 1.0 -hst_out_d2g = true -Kai0 = 0.1 #2*etaVk*iso_cs - -enable_dust_drag = true -enable_dust_feedback = true -drag_method = implicit -#rho_p = 1.25 -#rho_g0 = 0.3555 #g/cm^2, code-to-physical convert -#user_input_size = true -#Size_1 = 10.0 # dust size - - - -#type = uniform -#gx1 = 0.1 # 2*etaVk*Ome0 -#gx2 = 0.0 -#gx3 = 0.0 - -#type = point -#gm = 1e-5 -#soft = .03 -#x = 0 -#y = 0 -#z = 0 - - -omega = 1.0 -qshear = 1.5 -shboxcoord = 2 # 1=xy; 2=xz -stratified_flag = false - - -rho0 = 1.0 -dens_min = 1.0e-10 -pres_min = 1.0e-13 -h = 1.0 -etaVk = 0.05 -amp = 0.1 -dust_to_gas = 0.2 diff --git a/inputs/dust/disk_cyl_dust10.in b/inputs/dust/disk_cyl_dust10.in deleted file mode 100644 index b8999b7..0000000 --- a/inputs/dust/disk_cyl_dust10.in +++ /dev/null @@ -1,105 +0,0 @@ -# ======================================================================================== -# (C) (or copyright) 2023-2024. Triad National Security, LLC. All rights reserved. -# -# This program was produced under U.S. Government contract 89233218CNA000001 for Los -# Alamos National Laboratory (LANL), which is operated by Triad National Security, LLC -# for the U.S. Department of Energy/National Nuclear Security Administration. All rights -# in the program are reserved by Triad National Security, LLC, and the U.S. Department -# of Energy/National Nuclear Security Administration. The Government is granted for -# itself and others acting on its behalf a nonexclusive, paid-up, irrevocable worldwide -# license in this material to reproduce, prepare derivative works, distribute copies to -# the public, perform publicly and display publicly, and to permit others to do so. -# ======================================================================================== - - -problem = disk # name of the pgen -coordinates = axisymmetric #cylindrical # coordinate system - - -problem_id = disk_cyl # problem ID: basename of output filenames - - -file_type = hst -dt = 0.5 - - -variables = gas.prim.density, & - gas.prim.velocity, & - gas.prim.pressure, & - dust.prim.density, & - dust.prim.velocity, & - dust.stopping_time -file_type = hdf5 # HDF5 data dump -dt = 5.0 # time increment between outputs - - -nlim = -1 # cycle limit -tlim = 62.8 # time limit -integrator = rk2 # time integration algorithm -ncycle_out = 1 # interval for stdout summary info - - -nx1 = 128 # Number of zones in X1-direction -x1min = 0.4 # minimum value of X1 -x1max = 2.0 # maximum value of X1 -ix1_bc = ic # Inner-X1 boundary condition flag -ox1_bc = ic # Outer-X1 boundary condition flag - -nx2 = 1 # Number of zones in X2-direction -x2min = 0.0 # minimum value of X2 -x2max = 6.283185307179586 # maximum value of X2 -ix2_bc = periodic # Inner-X2 boundary condition flag -ox2_bc = periodic # Outer-X2 boundary condition flag - -nx3 = 1 # Number of zones in X3-direction -x3min = -0.5 # minimum value of X3 -x3max = 0.5 # maximum value of X3 -ix3_bc = outflow # Inner-X3 boundary condition flag -ox3_bc = outflow # Outer-X3 boundary condition flag - - -nx1 = 128 # Number of cells in each MeshBlock, X1-dir -nx2 = 1 # Number of cells in each MeshBlock, X2-dir -nx3 = 1 # Number of cells in each MeshBlock, X3-dir - - -gas = true -dust = true -gravity = true - - -cfl = 0.8 -gamma = 1.01 -reconstruct = plm -riemann = hllc -dfloor = 1.0e-10 -siefloor = 1.0e-10 - - -reconstruct = plm -riemann = hlle -nspecies = 1 -const_stopping_time = false -enable_dust_drag = true -enable_dust_feedback = true -drag_method = implicit -grain_density = 1.25 -#rho_g0 = 0.3555 #g/cm^2, code-to-physical convert -size_input = direct -sizes = 10.0 # dust size, cm -surface_density_flag = true; #surface or volume density - - -gm = 1.0 - - - -r0 = 1.0 -rho0 = 1.0e-4 #pre-factor -dslope = -1.0 -tslope = -0.5 -h0 = 0.05 -dens_min = 1.0e-10 -pres_min = 1.0e-13 -mstar = 1.0 # Msun -r0_length = 50.0 # AU diff --git a/inputs/dust/dust_coagulation.in b/inputs/dust/dust_coagulation.in index 36455d5..0af7e0f 100644 --- a/inputs/dust/dust_coagulation.in +++ b/inputs/dust/dust_coagulation.in @@ -26,46 +26,46 @@ dt = 0.628 variables = gas.prim.density, & dust.prim.density -file_type = hdf5 # tab data dump -dt = 62.8 # time increment between outputs +file_type = hdf5 # tab data dump +dt = 62.8 # time increment between outputs file_type = rst dt = 628 -nlim = -1 # cycle limit -tlim = 6280. # time limit -integrator = rk2 # time integration algorithm -ncycle_out = 1 # interval for stdout summary info +nlim = -1 # cycle limit +tlim = 6280. # time limit +integrator = rk2 # time integration algorithm +ncycle_out = 1 # interval for stdout summary info nghost = 2 refinement = none # numlevel = 1 -nx1 = 16 # Number of zones in X1-direction -x1min = 9.0 # minimum value of X1 -x1max = 11.0 # maximum value of X1 -ix1_bc = outflow # Inner-X1 boundary condition flag -ox1_bc = outflow # Outer-X1 boundary condition flag +nx1 = 16 # Number of zones in X1-direction +x1min = 1.35e15 # minimum value of X1 +x1max = 1.64e15 # maximum value of X1 +ix1_bc = outflow # Inner-X1 boundary condition flag +ox1_bc = outflow # Outer-X1 boundary condition flag -nx2 = 1 # Number of zones in X2-direction -x2min = 0.0 # minimum value of X2 +nx2 = 1 # Number of zones in X2-direction +x2min = 0.0 # minimum value of X2 x2max = 6.283185307179586 # maximum value of X2 -ix2_bc = periodic # Inner-X2 boundary condition flag -ox2_bc = periodic # Outer-X2 boundary condition flag +ix2_bc = periodic # Inner-X2 boundary condition flag +ox2_bc = periodic # Outer-X2 boundary condition flag -nx3 = 1 # Number of zones in X3-direction -x3min = -0.5 # minimum value of X3 -x3max = 0.5 # maximum value of X3 -ix3_bc = periodic # Inner-X3 boundary condition flag -ox3_bc = periodic # Outer-X3 boundary condition flag +nx3 = 1 # Number of zones in X3-direction +x3min = -0.5 # minimum value of X3 +x3max = 0.5 # maximum value of X3 +ix3_bc = periodic # Inner-X3 boundary condition flag +ox3_bc = periodic # Outer-X3 boundary condition flag -nx1 = 16 # Number of cells in each MeshBlock, X1-dir -nx2 = 1 # Number of cells in each MeshBlock, X2-dir -nx3 = 1 # Number of cells in each MeshBlock, X3-dir +nx1 = 16 # Number of cells in each MeshBlock, X1-dir +nx2 = 1 # Number of cells in each MeshBlock, X2-dir +nx3 = 1 # Number of cells in each MeshBlock, X3-dir gas = true @@ -75,29 +75,26 @@ coagulation = true cfl = 0.9 gamma = 1.00001 -iso_sound_speed = 0.05 +iso_sound_speed = 0.05 # code unit cfl = 0.9 nspecies = 121 -const_stopping_time = false -enable_dust_drag = false -enable_dust_feedback = false -drag_method = implicit -#user_dt = 0.005 - +size_input = logspace scr_level = 1 # for reconstruction -surface_density_flag = true + +surface_density_flag = true # surface or volume density grain_density = 1.25 # dust internal density g/cc -size_input = logspace min_size = 1e-5 #cm max_size = 10.0 #cm -vfrag = 1000.0 $cm/s + + +vfrag = 1000.0 #cm/s coag_int = 1 coag_use_adaptiveStep = false -coag_mom_preserve = true - +coag_mom_preserve = false +coag_info_out = true nInit_dust = 11 # number of dust species initially @@ -106,4 +103,5 @@ nstep1Coag = 10 mstar = 1.0 # central star masss (m_sun) r0_length = 10.0 # 1 code unit (AU) rho0 = 2e-5 # code unit value of 1 m_star/r0_length^2 +const_coag_omega = true # using omega at r0_length diff --git a/inputs/dust/dust_coagulation_den.in b/inputs/dust/dust_coagulation_den.in index be3707b..97de130 100644 --- a/inputs/dust/dust_coagulation_den.in +++ b/inputs/dust/dust_coagulation_den.in @@ -26,46 +26,46 @@ dt = 0.628 variables = gas.prim.density, & dust.prim.density -file_type = hdf5 # tab data dump -dt = 62.8 # time increment between outputs +file_type = hdf5 # tab data dump +dt = 62.8 # time increment between outputs file_type = rst dt = 628 -nlim = -1 # cycle limit -tlim = 6280. # time limit -integrator = rk2 # time integration algorithm -ncycle_out = 1 # interval for stdout summary info +nlim = 5 # cycle limit +tlim = 6280. # time limit +integrator = rk2 # time integration algorithm +ncycle_out = 1 # interval for stdout summary info nghost = 2 refinement = none # numlevel = 1 -nx1 = 16 # Number of zones in X1-direction -x1min = 9.0 # minimum value of X1 -x1max = 11.0 # maximum value of X1 -ix1_bc = outflow # Inner-X1 boundary condition flag -ox1_bc = outflow # Outer-X1 boundary condition flag +nx1 = 16 # Number of zones in X1-direction +x1min = 1.35e15 # minimum value of X1 +x1max = 1.64e15 # maximum value of X1 +ix1_bc = outflow # Inner-X1 boundary condition flag +ox1_bc = outflow # Outer-X1 boundary condition flag -nx2 = 1 # Number of zones in X2-direction -x2min = 0.0 # minimum value of X2 +nx2 = 1 # Number of zones in X2-direction +x2min = 0.0 # minimum value of X2 x2max = 6.283185307179586 # maximum value of X2 -ix2_bc = periodic # Inner-X2 boundary condition flag -ox2_bc = periodic # Outer-X2 boundary condition flag +ix2_bc = periodic # Inner-X2 boundary condition flag +ox2_bc = periodic # Outer-X2 boundary condition flag -nx3 = 1 # Number of zones in X3-direction -x3min = -0.5 # minimum value of X3 -x3max = 0.5 # maximum value of X3 -ix3_bc = periodic # Inner-X3 boundary condition flag -ox3_bc = periodic # Outer-X3 boundary condition flag +nx3 = 1 # Number of zones in X3-direction +x3min = -0.5 # minimum value of X3 +x3max = 0.5 # maximum value of X3 +ix3_bc = periodic # Inner-X3 boundary condition flag +ox3_bc = periodic # Outer-X3 boundary condition flag -nx1 = 16 # Number of cells in each MeshBlock, X1-dir -nx2 = 1 # Number of cells in each MeshBlock, X2-dir -nx3 = 1 # Number of cells in each MeshBlock, X3-dir +nx1 = 16 # Number of cells in each MeshBlock, X1-dir +nx2 = 1 # Number of cells in each MeshBlock, X2-dir +nx3 = 1 # Number of cells in each MeshBlock, X3-dir gas = true @@ -75,34 +75,33 @@ coagulation = true cfl = 0.9 gamma = 1.00001 -iso_sound_speed = 0.05 +iso_sound_speed = 0.05 # code unit cfl = 0.9 nspecies = 121 -const_stopping_time = false -enable_dust_drag = false -enable_dust_feedback = false -drag_method = implicit -#user_dt = 0.005 +size_input = logspace scr_level = 1 # for reconstruction -surface_density_flag = false + +surface_density_flag = false # surface or volume density grain_density = 1.25 # dust internal density g/cc min_size = 1e-5 #cm max_size = 10.0 #cm -size_input = logspace -vfrag = 1000.0 $cm/s + + +vfrag = 1000.0 #cm/s coag_int = 1 coag_use_adaptiveStep = false coag_mom_preserve = false - +coag_info_out = true nInit_dust = 11 # number of dust species initially dust_to_gas = 0.01 -nstep1Coag = 10 +nstep1Coag = 1 mstar = 1.0 # central star masss (m_sun) r0_length = 10.0 # 1 code unit (AU) -#rho0 = 2e-5 # code unit value of 1 m_star/r0_length^2 -rho0 = 1.59577e-4 # 3D rho +rho0 = 2e-5 # code unit value of 1 m_star/r0_length^2 +const_coag_omega = true # using omega at r0_length + diff --git a/inputs/dust/dust_collision.in b/inputs/dust/dust_collision.in index 09a08df..482c46e 100644 --- a/inputs/dust/dust_collision.in +++ b/inputs/dust/dust_collision.in @@ -29,9 +29,10 @@ dt = 0.05 # time increment between outputs nlim = -1 # cycle limit -tlim = 0.05 # time limit +tlim = 0.05 # time limit integrator = rk2 # time integration algorithm ncycle_out = 1 # interval for stdout summary info +dt_user = 0.005 nghost = 2 @@ -39,31 +40,32 @@ refinement = none # numlevel = 1 nx1 = 16 # Number of zones in X1-direction -x1min = 0.0 # minimum value of X1 +x1min = 0.0 # minimum value of X1 x1max = 1.0 # maximum value of X1 -ix1_bc = periodic # Inner-X1 boundary condition flag -ox1_bc = periodic # Outer-X1 boundary condition flag +ix1_bc = periodic # Inner-X1 boundary condition flag +ox1_bc = periodic # Outer-X1 boundary condition flag -nx2 = 1 # Number of zones in X2-direction +nx2 = 1 # Number of zones in X2-direction x2min = -0.5 # minimum value of X2 -x2max = 0.5 # maximum value of X2 -ix2_bc = periodic # Inner-X2 boundary condition flag -ox2_bc = periodic # Outer-X2 boundary condition flag +x2max = 0.5 # maximum value of X2 +ix2_bc = periodic # Inner-X2 boundary condition flag +ox2_bc = periodic # Outer-X2 boundary condition flag -nx3 = 1 # Number of zones in X3-direction +nx3 = 1 # Number of zones in X3-direction x3min = -0.5 # minimum value of X3 -x3max = 0.5 # maximum value of X3 -ix3_bc = periodic # Inner-X3 boundary condition flag -ox3_bc = periodic # Outer-X3 boundary condition flag +x3max = 0.5 # maximum value of X3 +ix3_bc = periodic # Inner-X3 boundary condition flag +ox3_bc = periodic # Outer-X3 boundary condition flag -nx1 = 16 # Number of cells in each MeshBlock, X1-dir -nx2 = 1 # Number of cells in each MeshBlock, X2-dir -nx3 = 1 # Number of cells in each MeshBlock, X3-dir +nx1 = 16 # Number of cells in each MeshBlock, X1-dir +nx2 = 1 # Number of cells in each MeshBlock, X2-dir +nx3 = 1 # Number of cells in each MeshBlock, X3-dir gas = true dust = true +drag = true cfl = 0.9 @@ -73,14 +75,17 @@ iso_sound_speed = 0.1 cfl = 0.9 nspecies = 2 -const_stopping_time = true -enable_dust_drag = true -enable_dust_feedback = true -drag_method = implicit -user_dt = 0.005 -size_input = none -stopping_time = 0.01, 0.002 +sizes = 1.0, 1.0 + + +type = constant +tau = 0.01, 0.001 # for iprob = 1 +#tau = 2.0, 1.0 # for iprob = 2 + + +type = simple_dust + -iprob = 1 +iprob = 1 # 1 or 2 diff --git a/src/artemis.cpp b/src/artemis.cpp index 63f7297..4421dc1 100644 --- a/src/artemis.cpp +++ b/src/artemis.cpp @@ -105,7 +105,10 @@ Packages_t ProcessPackages(std::unique_ptr &pin) { if (do_cooling) packages.Add(Gas::Cooling::Initialize(pin.get())); if (do_drag) packages.Add(Drag::Initialize(pin.get())); if (do_nbody) packages.Add(NBody::Initialize(pin.get())); - if (do_coagulation) packages.Add(Dust::Coagulation::Initialize(pin.get())); + if (do_coagulation) { + auto &dustPars = packages.Get("dust")->AllParams(); + packages.Add(Dust::Coagulation::Initialize(pin.get(), dustPars)); + } if (do_radiation) { auto eos_h = packages.Get("gas")->Param("eos_h"); auto opacity_h = packages.Get("gas")->Param("opacity_h"); @@ -146,25 +149,6 @@ Packages_t ProcessPackages(std::unique_ptr &pin) { parthenon::MetadataFlag MetadataOperatorSplit = parthenon::Metadata::AddUserFlag("OperatorSplit"); - if (do_coagulation) { - typedef Coordinates C; - if (coords == C::cartesian) { - OperatorSplitTasks.push_back(&Dust::OperatorSplitDust); - } else if (coords == C::spherical1D) { - OperatorSplitTasks.push_back(&Dust::OperatorSplitDust); - } else if (coords == C::spherical2D) { - OperatorSplitTasks.push_back(&Dust::OperatorSplitDust); - } else if (coords == C::spherical3D) { - OperatorSplitTasks.push_back(&Dust::OperatorSplitDust); - } else if (coords == C::cylindrical) { - OperatorSplitTasks.push_back(&Dust::OperatorSplitDust); - } else if (coords == C::axisymmetric) { - OperatorSplitTasks.push_back(&Dust::OperatorSplitDust); - } else { - PARTHENON_FAIL("Invalid artemis/coordinate system!"); - } - } - // Add in user-defined AMR criterion callback const bool amr_user = pin->GetOrAddBoolean("artemis", "amr_user", false); if (amr_user) artemis->CheckRefinementBlock = artemis::ProblemCheckRefinementBlock; diff --git a/src/artemis.hpp b/src/artemis.hpp index 8cd3700..38506bf 100644 --- a/src/artemis.hpp +++ b/src/artemis.hpp @@ -67,13 +67,11 @@ namespace prim { ARTEMIS_VARIABLE(dust.prim, density); ARTEMIS_VARIABLE(dust.prim, velocity); } // namespace prim -ARTEMIS_VARIABLE(dust, stopping_time); } // namespace dust #undef ARTEMIS_VARIABLE // TaskCollection function pointer for operator split tasks -using TaskCollectionFnPtr = TaskCollection (*)(Mesh *pm, parthenon::SimTime &tm, - const Real dt); +using TaskCollectionFnPtr = TaskCollection (*)(Mesh *pm, parthenon::SimTime &tm); // Constants that enumerate... // ...Coordinate systems @@ -150,7 +148,7 @@ inline int ProblemDimension(parthenon::ParameterInput *pin) { namespace artemis { extern std::function *mbd)> ProblemCheckRefinementBlock; -extern std::vector OperatorSplitTasks; +// extern std::vector OperatorSplitTasks; } // namespace artemis #endif // ARTEMIS_ARTEMIS_HPP_ diff --git a/src/artemis_driver.cpp b/src/artemis_driver.cpp index 455360c..59960ad 100644 --- a/src/artemis_driver.cpp +++ b/src/artemis_driver.cpp @@ -112,11 +112,8 @@ TaskListStatus ArtemisDriver::Step() { if (do_radiation) status = IMC::JaybenneIMC(pmesh, tm.time, tm.dt); if (status != TaskListStatus::complete) return status; - // Execute operator split physics - for (auto &fn : OperatorSplitTasks) { - status = fn(pmesh, tm, integrator->dt).Execute(); - if (status != TaskListStatus::complete) return status; - } + if (do_coagulation) status = Dust::OperatorSplitDust(pmesh, tm); + if (status != TaskListStatus::complete) return status; // Compute new dt, (de)refine, and handle sparse (if enabled) status = PostStepTasks().Execute(); @@ -189,13 +186,7 @@ TaskCollection ArtemisDriver::StepTasks() { const bool do_pcm = ((stage == 1) && (integrator->GetName() == "vl2")); TaskID gas_flx = none, dust_flx = none; if (do_gas) gas_flx = tl.AddTask(none, Gas::CalculateFluxes, u0.get(), do_pcm); - if (do_dust) { - // update dust stopping time and dust diffusivity - TaskID dust_stopping_time = - tl.AddTask(none, Dust::UpdateDustStoppingTime, u0.get()); - dust_flx = - tl.AddTask(dust_stopping_time, Dust::CalculateFluxes, u0.get(), do_pcm); - } + if (do_dust) dust_flx = tl.AddTask(none, Dust::CalculateFluxes, u0.get(), do_pcm); // Compute (gas) diffusive fluxes TaskID diff_flx = none; diff --git a/src/dust/coagulation/coagulation.cpp b/src/dust/coagulation/coagulation.cpp index f008076..4829e0b 100644 --- a/src/dust/coagulation/coagulation.cpp +++ b/src/dust/coagulation/coagulation.cpp @@ -17,31 +17,43 @@ #include "dust/dust.hpp" #include "geometry/geometry.hpp" -using namespace parthenon::package::prelude; - namespace Dust { namespace Coagulation { //---------------------------------------------------------------------------------------- //! \fn StateDescriptor Coagulalation::Initialize //! \brief Adds intialization function for coagulation package -std::shared_ptr Initialize(ParameterInput *pin) { +std::shared_ptr Initialize(ParameterInput *pin, Params &dustPars) { auto coag = std::make_shared("coagulation"); Params ¶ms = coag->AllParams(); CoagParams cpars; - const int nm = pin->GetOrAddInteger("dust", "nspecies", 1); + + const int nm = dustPars.template Get("nspecies"); + const Real dfloor = dustPars.template Get("dfloor"); + const Real rho_p = dustPars.template Get("grain_density"); cpars.nm = nm; cpars.vfrag = pin->GetOrAddReal("dust", "vfrag", 1.e3); // cm/s cpars.nlim = 1e10; - cpars.integrator = pin->GetOrAddInteger("dust", "coag_int", 3); - cpars.use_adaptive = pin->GetOrAddBoolean("dust", "coag_use_adaptiveStep", true); - cpars.mom_coag = pin->GetOrAddBoolean("dust", "coag_mom_preserve", true); - cpars.nCall_mx = pin->GetOrAddInteger("dust", "coag_nsteps_mx", 1000); - // dust particle internal density g/cc - const Real rho_p = pin->GetOrAddReal("dust", "grain_density", 1.25); + cpars.integrator = pin->GetOrAddInteger("dust/coagulation", "coag_int", 3); + cpars.use_adaptive = + pin->GetOrAddBoolean("dust/coagulation", "coag_use_adaptiveStep", true); + cpars.mom_coag = pin->GetOrAddBoolean("dust/coagulation", "coag_mom_preserve", true); + cpars.nCall_mx = pin->GetOrAddInteger("dust/coagulation", "coag_nsteps_mx", 1000); cpars.rho_p = rho_p; - cpars.ibounce = pin->GetOrAddBoolean("dust", "coag_bounce", false); + const Real M_SUN = 1.988409870698051e33; // gram (sun) + const Real GRAV_CONST = 6.674299999999999e-8; // gravitational const in cm^3 g^-1 s^-2 + const Real mstar = pin->GetOrAddReal("problem", "mstar", 1.0) * M_SUN; + cpars.gm = std::sqrt(GRAV_CONST * mstar); + const bool const_omega = pin->GetOrAddBoolean("problem", "const_coag_omega", false); + cpars.const_omega = const_omega; + if (const_omega) { + const Real AU_LENGTH = 1.4959787070000e13; // cm + const Real r0 = pin->GetOrAddReal("problem", "r0_length", 1.0) * AU_LENGTH; + cpars.gm /= (std::sqrt(r0) * r0); + } + + cpars.ibounce = pin->GetOrAddBoolean("dust/coagulation", "coag_bounce", false); int coord_type = 0; // density @@ -72,28 +84,17 @@ std::shared_ptr Initialize(ParameterInput *pin) { cpars.errcon = std::pow((5. / cpars.S), (1. / cpars.pgrow)); } - const Real s_min = pin->GetReal("dust", "min_size"); - const Real s_max = pin->GetReal("dust", "max_size"); - const Real mmin = 4.0 * M_PI / 3.0 * rho_p * std::pow(s_min, 3); - const Real mmax = 4.0 * M_PI / 3.0 * rho_p * std::pow(s_max, 3); - const Real cond = 1.0 / (1.0 - nm) * std::log(mmin / mmax); - const Real conc = std::log(mmin); + auto h_sizes = dustPars.template Get>("h_sizes"); + const Real cond = 3.0 / (1.0 - nm) * std::log(h_sizes(0) / h_sizes(nm - 1)); if (std::exp(cond) > std::sqrt(2.0)) { std::stringstream msg; msg << "### FATAL ERROR in dust with coagulation: using nspecies >" - << std::log(mmax / mmin) / (std::log(std::sqrt(2.0))) + 1. << " instead of " << nm - << std::endl; + << 3.0 * std::log(h_sizes(nm - 1) / h_sizes(0)) / (std::log(std::sqrt(2.0))) + 1. + << " instead of " << nm << std::endl; PARTHENON_FAIL(msg); } - ParArray1D dust_size("dustSize", nm); - auto dust_size_host = dust_size.GetHostMirror(); - - for (int n = 0; n < nm; ++n) { - Real mgrid = std::exp(conc + cond * n); - dust_size_host(n) = std::pow(3.0 * mgrid / (4.0 * M_PI * cpars.rho_p), 1. / 3.); - } - dust_size.DeepCopy(dust_size_host); + auto dust_size = dustPars.template Get>("sizes"); // allocate array and assign values cpars.klf = ParArray2D("klf", nm, nm); @@ -103,16 +104,8 @@ std::shared_ptr Initialize(ParameterInput *pin) { cpars.cpod_notzero = ParArray3D("idx_nzcpod", nm, nm, 4); cpars.cpod_short = ParArray3D("nzcpod", nm, nm, 4); - if (Dust::cgsunit == NULL) { - Dust::cgsunit = new CGSUnit; - } - if (!Dust::cgsunit->isSet()) { - Dust::cgsunit->SetCGSUnit(pin); - } - const Real dfloor = pin->GetOrAddReal("dust", "dfloor", 1.0e-25); - // convert to CGS unit - cpars.dfloor = dfloor * Dust::cgsunit->mass0 / Dust::cgsunit->vol0; - Real a = std::log10(mmin / mmax) / static_cast(1 - nm); + cpars.dfloor = dfloor; + Real a = 3.0 * std::log10(h_sizes(0) / h_sizes(nm - 1)) / static_cast(1 - nm); initializeArray(nm, cpars.pGrid, cpars.rho_p, cpars.chi, a, dust_size, cpars.klf, cpars.mass_grid, cpars.coagR3D, cpars.cpod_notzero, cpars.cpod_short); @@ -124,10 +117,12 @@ std::shared_ptr Initialize(ParameterInput *pin) { params.Add("nstep1Coag", nstep1Coag); Real dtCoag = 0.0; params.Add("dtCoag", dtCoag, Params::Mutability::Restart); - const Real alpha = pin->GetOrAddReal("dust", "coag_alpha", 1.e-3); + const Real alpha = pin->GetOrAddReal("dust/coagulation", "coag_alpha", 1.e-3); params.Add("coag_alpha", alpha); - const int scr_level = pin->GetOrAddReal("dust", "coag_scr_level", 0); + const int scr_level = pin->GetOrAddReal("dust/coagulation", "coag_scr_level", 0); params.Add("coag_scr_level", scr_level); + const bool info_out = pin->GetOrAddBoolean("dust/coagulation", "coag_info_out", false); + params.Add("coag_info_out", info_out); return coag; } @@ -139,23 +134,21 @@ void initializeArray(const int nm, int &pGrid, const Real &rho_p, const Real &ch ParArray3D cpod_notzero, ParArray3D cpod_short) { int ikdelta = coag2DRv::kdelta; - auto kdelta = Kokkos::subview(coag3D, ikdelta, Kokkos::ALL, Kokkos::ALL); int icoef_fett = coag2DRv::coef_fett; - auto coef_fett = Kokkos::subview(coag3D, icoef_fett, Kokkos::ALL, Kokkos::ALL); parthenon::par_for( parthenon::loop_pattern_flatrange_tag, "initializeCoag1", parthenon::DevExecSpace(), 0, nm - 1, KOKKOS_LAMBDA(const int i) { // initialize in_idx(*) array // initialize kdelta array for (int j = 0; j < nm; j++) { - kdelta(i, j) = 0.0; + coag3D(ikdelta, i, j) = 0.0; } - kdelta(i, i) = 1.0; - mass_grid(i) = 4.0 * M_PI / 3.0 * rho_p * std::pow(dsize(i), 3); - // initialize coef_fett(*,*) + coag3D(ikdelta, i, i) = 1.0; + mass_grid(i) = 4.0 * M_PI / 3.0 * rho_p * dsize(i) * dsize(i) * dsize(i); + // initialize coag3D(icoef_fett, *,*) for (int j = 0; j < nm; j++) { - Real tmp1 = (1.0 - 0.5 * kdelta(i, j)); - coef_fett(i, j) = M_PI * SQR(dsize(i) + dsize(j)) * tmp1; + Real tmp1 = (1.0 - 0.5 * coag3D(ikdelta, i, j)); + coag3D(icoef_fett, i, j) = M_PI * SQR(dsize(i) + dsize(j)) * tmp1; } }); @@ -171,20 +164,17 @@ void initializeArray(const int nm, int &pGrid, const Real &rho_p, const Real &ch int iphiFrag = coag2DRv::phiFrag, iepsFrag = coag2DRv::epsFrag; int iaFrag = coag2DRv::aFrag; - auto phiFrag = Kokkos::subview(coag3D, iphiFrag, Kokkos::ALL, Kokkos::ALL); - auto epsFrag = Kokkos::subview(coag3D, iepsFrag, Kokkos::ALL, Kokkos::ALL); - auto aFrag = Kokkos::subview(coag3D, iaFrag, Kokkos::ALL, Kokkos::ALL); parthenon::par_for( parthenon::loop_pattern_flatrange_tag, "initializeCoag2", parthenon::DevExecSpace(), 0, nm - 1, KOKKOS_LAMBDA(const int i) { Real sum_pF = 0.0; for (int j = 0; j <= i; j++) { - phiFrag(j, i) = std::pow(mass_grid(j), frag_slope); - sum_pF += phiFrag(j, i); + coag3D(iphiFrag, j, i) = std::pow(mass_grid(j), frag_slope); + sum_pF += coag3D(iphiFrag, j, i); } // normalization for (int j = 0; j <= i; j++) { - phiFrag(j, i) /= sum_pF; // switch (i,j) from fortran + coag3D(iphiFrag, j, i) /= sum_pF; // switch (i,j) from fortran } // Cratering @@ -195,18 +185,18 @@ void initializeArray(const int nm, int &pGrid, const Real &rho_p, const Real &ch // Mass bin of largest fragment klf(i, j) = j; - aFrag(i, j) = (1.0 + chi) * mass_grid(j); - // |_____________| - // | + coag3D(iaFrag, i, j) = (1.0 + chi) * mass_grid(j); + // |_______| + // | // Mass of fragments - epsFrag(i, j) = chi * mass_grid(j) / (mass_grid(i) * (1.0 - ten_ma)); + coag3D(iepsFrag, i, j) = chi * mass_grid(j) / (mass_grid(i) * (1.0 - ten_ma)); } int i1 = std::max(0, i - pGrid); for (int j = i1; j <= i; j++) { // The largest fragment has the mass of the larger collison partner klf(i, j) = i; - aFrag(i, j) = (mass_grid(i) + mass_grid(j)); + coag3D(iaFrag, i, j) = (mass_grid(i) + mass_grid(j)); } }); @@ -215,18 +205,16 @@ void initializeArray(const int nm, int &pGrid, const Real &rho_p, const Real &ch // Calculate the E matrix ParArray2D e("epod", nm, nm); int idalp = coag2DRv::dalp, idpod = coag2DRv::dpod; - auto dalp = Kokkos::subview(coag3D, idalp, Kokkos::ALL, Kokkos::ALL); - auto dpod = Kokkos::subview(coag3D, idpod, Kokkos::ALL, Kokkos::ALL); parthenon::par_for( parthenon::loop_pattern_flatrange_tag, "initializeCoag4", parthenon::DevExecSpace(), 0, nm - 1, KOKKOS_LAMBDA(const int k) { for (int j = 0; j < nm; j++) { if (j <= k + 1 - ce) { - dalp(k, j) = 1.0; - dpod(k, j) = -mass_grid(j) / (mass_grid(k) * (ten_a - 1.0)); + coag3D(idalp, k, j) = 1.0; + coag3D(idpod, k, j) = -mass_grid(j) / (mass_grid(k) * (ten_a - 1.0)); } else { - dpod(k, j) = -1.0; - dalp(k, j) = 0.0; + coag3D(idpod, k, j) = -1.0; + coag3D(idalp, k, j) = 0.0; } } // for E matrix------------- @@ -272,10 +260,10 @@ void initializeArray(const int nm, int &pGrid, const Real &rho_p, const Real &ch Real dtheta_ji = (j - i - 0.5 < 0.0) ? 0.0 : 1.0; // theta(j - i - 0.5); for (int k = 0; k < nm; k++) { Real theta_kj = (k - j - 1.5 < 0.0) ? 0.0 : 1.0; // theta(k - j - 1.5) - cpod(i, j, k) = (0.5 * kdelta(i, j) * cpod(i, j, k) + + cpod(i, j, k) = (0.5 * coag3D(ikdelta, i, j) * cpod(i, j, k) + cpod(i, j, k) * theta_kj * dtheta_ji); } - cpod(i, j, j) += dpod(j, i); + cpod(i, j, j) += coag3D(idpod, j, i); cpod(i, j, j + 1) += e(j + 1, i) * dtheta_ji; } // end if diff --git a/src/dust/coagulation/coagulation.hpp b/src/dust/coagulation/coagulation.hpp index 454e0db..5e5a835 100644 --- a/src/dust/coagulation/coagulation.hpp +++ b/src/dust/coagulation/coagulation.hpp @@ -21,7 +21,7 @@ namespace Coagulation { enum coag2DRv { dpod, aFrag, phiFrag, epsFrag, dalp, kdelta, coef_fett, last2 }; -std::shared_ptr Initialize(ParameterInput *pin); +std::shared_ptr Initialize(ParameterInput *pin, Params &dustPars); struct CoagParams { int coord = 0; // 1--surface density, 0: 3D @@ -44,7 +44,9 @@ struct CoagParams { Real err_eps; // Relative tolerance for adaptive step sizing Real S; // Safety margin for adaptive step sizing Real cfl; - Real errcon; // Needed for increasing step size + Real errcon; // Needed for increasing step size + Real gm; // sqrt(grav_const * mstar); + bool const_omega; // for shearing-box or testing // pre-calculated array, once-for-all ParArray2D klf; @@ -79,32 +81,32 @@ Real v_rel_ormel(Real tau_1, Real tau_2, Real t0, Real v0, Real ts, Real vs, st2 = tau_mn / t0; } - vg2 = 1.5 * pow(v0, 2); // note the square - ya = 1.6; // approximate solution for st*=y*st1; valid for st1 << 1. + vg2 = 1.5 * SQR(v0); // note the square + ya = 1.6; // approximate solution for st*=y*st1; valid for st1 << 1. Real sqRe = 1.0 / sqrt(reynolds); if (tau_mx < 0.2 * ts) { // very small regime - return 1.5 * pow((vs / ts * (tau_mx - tau_mn)), 2); + return 1.5 * SQR((vs / ts * (tau_mx - tau_mn))); } else if (tau_mx < ts / ya) { return vg2 * (st1 - st2) / (st1 + st2) * - (pow(st1, 2) / (st1 + sqRe) - pow(st2, 2) / (st2 + sqRe)); + (SQR(st1) / (st1 + sqRe) - SQR(st2) / (st2 + sqRe)); } else if (tau_mx < 5.0 * ts) { // eq. 17 of oc07. the second term with st_i**2.0 is negligible (assuming re>>1) // hulp1 = eq. 17; hulp2 = eq. 18 - hulp1 = ((st1 - st2) / (st1 + st2) * - (pow(st1, 2) / (st1 + ya * st1) - - pow(st2, 2) / (st2 + ya * st1))); // note the -sign - hulp2 = 2.0 * (ya * st1 - sqRe) + pow(st1, 2.0) / (ya * st1 + st1) - - pow(st1, 2) / (st1 + sqRe) + pow(st2, 2) / (ya * st1 + st2) - - pow(st2, 2) / (st2 + sqRe); + hulp1 = + ((st1 - st2) / (st1 + st2) * + (SQR(st1) / (st1 + ya * st1) - SQR(st2) / (st2 + ya * st1))); // note the -sign + hulp2 = 2.0 * (ya * st1 - sqRe) + SQR(st1) / (ya * st1 + st1) - + SQR(st1) / (st1 + sqRe) + SQR(st2) / (ya * st1 + st2) - + SQR(st2) / (st2 + sqRe); return vg2 * (hulp1 + hulp2); } else if (tau_mx < t0 / 5.0) { // full intermediate regime eps = st2 / st1; // stopping time ratio - return vg2 * - (st1 * (2.0 * ya - (1.0 + eps) + - 2.0 / (1.0 + eps) * (1.0 / (1.0 + ya) + pow(eps, 3) / (ya + eps)))); + return vg2 * (st1 * (2.0 * ya - (1.0 + eps) + + 2.0 / (1.0 + eps) * + (1.0 / (1.0 + ya) + (eps * eps * eps) / (ya + eps)))); } else if (tau_mx < t0) { // now y* lies between 1.6 (st1 << 1) and 1.0 (st1>=1). the fit below fits ystar to // less than 1% @@ -112,12 +114,13 @@ Real v_rel_ormel(Real tau_1, Real tau_2, Real t0, Real v0, Real ts, Real vs, c2 = 0.32938936; c1 = -0.63119577; c0 = 1.6015125; - y_star = c0 + c1 * st1 + c2 * pow(st1, 2) + c3 * pow(st1, 3); + y_star = c0 + c1 * st1 + c2 * SQR(st1) + c3 * (st1 * st1 * st1); // we can then employ the same formula as before eps = st2 / st1; // stopping time ratio - return vg2 * (st1 * (2.0 * y_star - (1.0 + eps) + - 2.0 / (1.0 + eps) * - (1.0 / (1.0 + y_star) + pow(eps, 3) / (y_star + eps)))); + return vg2 * + (st1 * (2.0 * y_star - (1.0 + eps) + + 2.0 / (1.0 + eps) * + (1.0 / (1.0 + y_star) + (eps * eps * eps) / (y_star + eps)))); } else { // heavy particle limit return vg2 * (1.0 / (1.0 + st1) + 1.0 / (1.0 + st2)); diff --git a/src/dust/dust.cpp b/src/dust/dust.cpp index 916c672..b01494b 100644 --- a/src/dust/dust.cpp +++ b/src/dust/dust.cpp @@ -27,10 +27,10 @@ #include "utils/fluxes/fluid_fluxes.hpp" #include "utils/history.hpp" +using ArtemisUtils::EOS; using ArtemisUtils::VI; namespace Dust { -CGSUnit *cgsunit = NULL; //---------------------------------------------------------------------------------------- //! \fn StateDescriptor Dust::Initialize //! \brief Adds intialization function for dust hydrodynamics package @@ -107,12 +107,14 @@ std::shared_ptr Initialize(ParameterInput *pin) { params.Add("hst_out_d2g", hst_out_d2g); // coagulation flag - bool enable_dust_coagulation = pin->GetOrAddBoolean("physics", "coagulation", false); + bool do_coagulation = pin->GetOrAddBoolean("physics", "coagulation", false); // Dust sizes auto size_dist = pin->GetOrAddString("dust", "size_input", "direct"); - if (enable_dust_coagulation) size_dist = "logspace"; - params.Add("enable_coagulation", enable_dust_coagulation); + if (do_coagulation) { + PARTHENON_REQUIRE(size_dist == "logspace", + "dust coagulation requires size_input = logspace!"); + } if (size_dist == "linspace") { // uniform @@ -146,11 +148,6 @@ std::shared_ptr Initialize(ParameterInput *pin) { params.Add("sizes", sizes); params.Add("h_sizes", h_sizes); - if (parthenon::Globals::my_rank == 0) { - for (int n = 0; n < nspecies; n++) { - std::cout << "dust_size(" << n << ")=" << h_sizes(n) << std::endl; - } - } } else if (size_dist == "direct") { // specify them directly auto sizes_v = pin->GetVector("dust", "sizes"); @@ -188,38 +185,8 @@ std::shared_ptr Initialize(ParameterInput *pin) { } // Dust density - const Real rho_p_orig = pin->GetOrAddReal("dust", "grain_density", 1.0); - params.Add("grain_density", rho_p_orig); - - if (enable_dust_coagulation) { - if (cgsunit == NULL) { - cgsunit = new CGSUnit; - } - if (!cgsunit->isSet()) { - cgsunit->SetCGSUnit(pin); - } - params.Add("cgs_unit", cgsunit); - - Real rho_p = rho_p_orig; - // density in physical unit correspinding to code unit 1. - // const Real rho_g0 = pin->GetOrAddReal("dust", "rho_g0", 1.0); - const Real rho_g0 = cgsunit->mass0 / cgsunit->vol0; - // re-scale rho_p to account for rho_g0 for stopping_time calculation - rho_p /= rho_g0; - - // re-scale rho_p by prefactor coefficient - if (cgsunit->isurface_den) { - rho_p *= 0.5 * M_PI; - } else { - rho_p *= std::sqrt(M_PI / 8.); - rho_p /= cgsunit->length0; - } + params.Add("grain_density", pin->GetOrAddReal("dust", "grain_density", 1.0)); - if (parthenon::Globals::my_rank == 0) { - std::cout << "rho_p, rho_g0=" << rho_p << " " << rho_g0 << std::endl; - } - params.Add("rho_p", rho_p); - } // Scratch for dust flux const int scr_level = pin->GetOrAddInteger("dust", "scr_level", 0); params.Add("scr_level", scr_level); @@ -257,14 +224,6 @@ std::shared_ptr Initialize(ParameterInput *pin) { m.SetSparseThresholds(0.0, 0.0, 0.0); dust->AddSparsePool(m, control_field, dustids); - // dust stopping-time - m = Metadata({Metadata::Cell, Metadata::Derived, Metadata::Intensive, Metadata::OneCopy, - Metadata::Sparse}); - m.SetSparseThresholds(0.0, 0.0, 0.0); - dust->AddSparsePool(m, control_field, dustids); - // std::vector stopping_id = {0}; - // dust->AddSparsePool(m, control_field, stopping_id); - // Dust hydrodynamics timestep if (coords == Coordinates::cartesian) { dust->EstimateTimestepMesh = EstimateTimestepMesh; @@ -285,81 +244,6 @@ std::shared_ptr Initialize(ParameterInput *pin) { return dust; } -//---------------------------------------------------------------------------------------- -//! \fn TaskStatus Dust::UpdateDustStoppingTime -// \brief Wrapper function for update dust stopping time -template -TaskStatus UpdateDustStoppingTime(MeshData *md) { - - using parthenon::MakePackDescriptor; - - auto pm = md->GetParentPointer(); - - auto &dust_pkg = pm->packages.Get("dust"); - if ((!dust_pkg->template Param("enable_coagulation"))) { - return TaskStatus::complete; - } - - auto &resolved_pkgs = pm->resolved_packages; - - IndexRange ib = md->GetBoundsI(IndexDomain::interior); - IndexRange jb = md->GetBoundsJ(IndexDomain::interior); - IndexRange kb = md->GetBoundsK(IndexDomain::interior); - - const int nspecies = dust_pkg->template Param("nspecies"); - - const bool isurf_den = cgsunit->isurface_den; - ParArray1D dust_size = dust_pkg->template Param>("sizes"); - static auto desc = - MakePackDescriptor( - resolved_pkgs.get()); - - auto vmesh = desc.GetPack(md); - - auto &gas_pkg = pm->packages.Get("gas"); - - const Real gamma = gas_pkg->template Param("adiabatic_index"); - const Real rho_p = dust_pkg->template Param("rho_p"); - - parthenon::par_for( - DEFAULT_LOOP_PATTERN, "Dust::DustStoppingTime2", parthenon::DevExecSpace(), 0, - md->NumBlocks() - 1, kb.s, kb.e, jb.s, jb.e, ib.s, ib.e, - KOKKOS_LAMBDA(const int b, const int k, const int j, const int i) { - const Real dens_g = vmesh(b, gas::prim::density(0), k, j, i); - // usually the Stokes number depends gas density, unless constant is used - // stopping_time = Stokes_number/Omega_k - - if (isurf_den) { - geometry::Coords coords(vmesh.GetCoordinates(b), k, j, i); - // for surface denstiy, Stokes number = Pi/2*rho_p*s_p/sigma_g - // calculate the Keplerian Omega at mid-plane - Real rad; - if constexpr (GEOM == Coordinates::cylindrical) { - rad = coords.hx2v(); // cylindrical-rad - } else { - rad = coords.hx3v(); - } - Real Omega_k = 1.0 / std::sqrt(rad) / rad; - for (int n = 0; n < nspecies; ++n) { - const Real St = rho_p * dust_size(n) / dens_g; - vmesh(b, dust::stopping_time(n), k, j, i) = St / Omega_k; - } - - } else { - - // for density (g/cc), Stokes number = sqrt(Pi/8)*rho_p*s_p*Omega_k/rho_g/Cs - const Real pres = vmesh(b, gas::prim::pressure(0), k, j, i); - const Real cs = std::sqrt(gamma * pres / dens_g); - for (int n = 0; n < nspecies; ++n) { - const Real StOme = rho_p * dust_size(n) / dens_g; - vmesh(b, dust::stopping_time(n), k, j, i) = StOme / cs; - } - } - }); - - return TaskStatus::complete; -} - //---------------------------------------------------------------------------------------- //! \fn Real Dust::EstimateTimestepMesh //! \brief Compute dust hydrodynamics timestep @@ -372,13 +256,11 @@ Real EstimateTimestepMesh(MeshData *md) { auto &dust_pkg = pm->packages.Get("dust"); auto ¶ms = dust_pkg->AllParams(); - auto userDt = params.template Get("user_dt"); auto nspecies = params.template Get("nspecies"); const auto cfl_number = params.template Get("cfl"); static auto desc = - MakePackDescriptor( - resolved_pkgs.get()); + MakePackDescriptor(resolved_pkgs.get()); auto vmesh = desc.GetPack(md); IndexRange ib = md->GetBoundsI(IndexDomain::interior); IndexRange jb = md->GetBoundsJ(IndexDomain::interior); @@ -399,12 +281,12 @@ Real EstimateTimestepMesh(MeshData *md) { for (int d = 0; d < ndim; d++) { denom += std::abs(vmesh(b, dust::prim::velocity(VI(n, d)), k, j, i)) / dx[d]; } - ldt = std::min(ldt, 1.0 / denom * cfl_number); + ldt = std::min(ldt, 1.0 / denom); } }, Kokkos::Min(min_dt)); - return std::min(userDt, min_dt); + return (cfl_number * min_dt); } //---------------------------------------------------------------------------------------- @@ -457,7 +339,6 @@ TaskStatus FluxSource(MeshData *md, const Real dt) { return TaskStatus::complete; } -//#define COAG_DEBUG //---------------------------------------------------------------------------------------- //! \fn TaskStatus Dust::CoagulationOneStep // \brief Wrapper function for coagulation procedure in one time step @@ -472,76 +353,76 @@ TaskStatus CoagulationOneStep(MeshData *md, const Real time, const Real dt IndexRange kb = md->GetBoundsK(IndexDomain::interior); auto &gas_pkg = pm->packages.Get("gas"); - const Real gamma = gas_pkg->template Param("adiabatic_index"); + auto eos_d = gas_pkg->template Param("eos_d"); auto &resolved_pkgs = pm->resolved_packages; const int nspecies = dust_pkg->template Param("nspecies"); + auto &dust_size = dust_pkg->template Param>("sizes"); auto &coag_pkg = pm->packages.Get("coagulation"); auto &coag = coag_pkg->template Param("coag_pars"); - PARTHENON_REQUIRE(cgsunit->isSet(), - "coagulation requires setting code-to-physical unit in user routine"); - static auto desc = - MakePackDescriptor(resolved_pkgs.get()); + MakePackDescriptor( + resolved_pkgs.get()); auto vmesh = desc.GetPack(md); const Real alpha = coag_pkg->template Param("coag_alpha"); // 1e-3 - const int nvel = 3; + int nvel = 3; + if (coag.coord) nvel = 2; // surface-density + auto &dfloor = dust_pkg->template Param("dfloor"); const int scr_level = coag_pkg->template Param("coag_scr_level"); + auto info_out_flag = coag_pkg->template Param("coag_info_out"); + size_t isize = (5 + nvel) * nspecies; if (coag.integrator == 3 && coag.mom_coag) isize += nspecies; size_t scr_size = ScratchPad1D::shmem_size(isize); - const Real den0 = cgsunit->mass0 / cgsunit->vol0; - const Real time0 = cgsunit->time0; - // const Real vol0 = cgsunit->vol0; - const Real vel0 = cgsunit->length0 / cgsunit->time0; auto pmb = md->GetBlockData(0)->GetBlockPointer(); - ParArray3D nCalls("nCalls", pmb->cellbounds.ncellsk(IndexDomain::entire), - pmb->cellbounds.ncellsj(IndexDomain::entire), - pmb->cellbounds.ncellsi(IndexDomain::entire)); + ParArray3D nCalls; + int maxCalls, maxSize, maxSize0; + Real massd0, massd; + if (info_out_flag) { + nCalls = ParArray3D("coag_nCalls", pmb->cellbounds.ncellsk(IndexDomain::entire), + pmb->cellbounds.ncellsj(IndexDomain::entire), + pmb->cellbounds.ncellsi(IndexDomain::entire)); + maxCalls = 0; + maxSize = 1; + massd = 0.0; + + maxSize0 = 1; + massd0 = 0.0; - int maxCalls = 0, maxSize = 1; - auto &dfloor = dust_pkg->template Param("dfloor"); - - int maxSize0 = 1; - Real massd = 0.0; - Kokkos::parallel_reduce( - "coag::maxSize0", - Kokkos::MDRangePolicy>( - {0, kb.s, jb.s, ib.s}, {md->NumBlocks(), kb.e + 1, jb.e + 1, ib.e + 1}), - KOKKOS_LAMBDA(const int b, const int k, const int j, const int i, Real &lsum, - int &lmax) { - geometry::Coords coords(vmesh.GetCoordinates(b), k, j, i); - for (int n = 0; n < nspecies; ++n) { - Real &dens_d = vmesh(b, dust::cons::density(n), k, j, i); - lsum += dens_d * coords.Volume(); - } - for (int n = nspecies - 1; n >= 0; --n) { - Real &dens_d = vmesh(b, dust::cons::density(n), k, j, i); - if (dens_d > dfloor) { - lmax = std::max(lmax, n); - break; + Kokkos::parallel_reduce( + "coag::maxSize0", + Kokkos::MDRangePolicy>( + {0, kb.s, jb.s, ib.s}, {md->NumBlocks(), kb.e + 1, jb.e + 1, ib.e + 1}), + KOKKOS_LAMBDA(const int b, const int k, const int j, const int i, Real &lsum, + int &lmax) { + geometry::Coords coords(vmesh.GetCoordinates(b), k, j, i); + for (int n = 0; n < nspecies; ++n) { + Real &dens_d = vmesh(b, dust::cons::density(n), k, j, i); + lsum += dens_d * coords.Volume(); } - } - }, - massd, Kokkos::Max(maxSize0)); + for (int n = nspecies - 1; n >= 0; --n) { + Real &dens_d = vmesh(b, dust::cons::density(n), k, j, i); + if (dens_d > dfloor) { + lmax = std::max(lmax, n); + break; + } + } + }, + massd0, Kokkos::Max(maxSize0)); #ifdef MPI_PARALLEL - // Sum the perturbations over all processors - MPI_Reduce(MPI_IN_PLACE, &maxSize0, 1, MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD); - MPI_Reduce(MPI_IN_PLACE, &massd, 1, MPI_PARTHENON_REAL, MPI_SUM, 0, MPI_COMM_WORLD); + // Sum over all processors + MPI_Reduce(MPI_IN_PLACE, &maxSize0, 1, MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD); + MPI_Reduce(MPI_IN_PLACE, &massd0, 1, MPI_PARTHENON_REAL, MPI_SUM, 0, MPI_COMM_WORLD); #endif // MPI_PARALLEL + } // end if (info_out_flag) - Real sumd1 = 0.0; -#ifdef COAG_DEBUG - ParArray3D floor_tmp("floor_tmp", 17, nspecies, 2); -#endif for (int b = 0; b < md->NumBlocks(); b++) { parthenon::par_for_outer( DEFAULT_OUTER_LOOP_PATTERN, "Dust::Coagulation", parthenon::DevExecSpace(), @@ -552,24 +433,25 @@ TaskStatus CoagulationOneStep(MeshData *md, const Real time, const Real dt const int nDust_live = (vmesh.GetUpperBound(b, dust::prim::density()) - vmesh.GetLowerBound(b, dust::prim::density()) + 1); - const Real dens_g = vmesh(b, gas::prim::density(0), k, j, i) * den0; - Real dt_sync = dt * time0; - const Real time1 = time * time0; + const Real dens_g = vmesh(b, gas::prim::density(0), k, j, i); + Real dt_sync = dt; + const Real time1 = time; geometry::Coords coords(vmesh.GetCoordinates(b), k, j, i); const auto &hx = coords.GetScaleFactors(); - Real rad = hx[2]; - if constexpr (GEOM == Coordinates::cylindrical) { - rad = hx[1]; - } - const Real Omega_k = 1.0 / std::sqrt(rad) / rad; // code unit - // const Real vol1 = coords.Volume() * vol0; + const auto &xv = coords.GetCellCenter(); + const auto &xcyl = coords.ConvertToCyl(xv); + + const Real rad = xcyl[0]; // cylindrical + const Real Omega_k = + coag.const_omega ? coag.gm : coag.gm / std::sqrt(rad) / rad; // code unit int nCall1 = 0; - const Real pres = vmesh(b, gas::prim::pressure(0), k, j, i); - const Real cs = std::sqrt(gamma * pres / dens_g * den0) * vel0; - const Real omega1 = Omega_k / time0; + const Real sie = vmesh(b, gas::prim::sie(0), k, j, i); + const Real bulk = eos_d.BulkModulusFromDensityInternalEnergy(dens_g, sie); + const Real cs = std::sqrt(bulk / dens_g); + const Real omega1 = Omega_k; const int nm = nspecies; ScratchPad1D rhod(mbr.team_scratch(scr_level), nspecies); @@ -583,23 +465,28 @@ TaskStatus CoagulationOneStep(MeshData *md, const Real time, const Real dt Q2 = ScratchPad1D(mbr.team_scratch(scr_level), nspecies); } + // calculate the stopping time on the fly + Real st0 = 1.0; + if (coag.coord) { // surface density + st0 = 0.5 * M_PI * coag.rho_p / dens_g / omega1; + } else { + st0 = std::sqrt(M_PI / 8.0) * coag.rho_p / dens_g / cs; + } + parthenon::par_for_inner( DEFAULT_INNER_LOOP_PATTERN, mbr, 0, nm - 1, [&](const int n) { - // for (int n = 0; n < nm; ++n) { - stime(n) = vmesh(b, dust::stopping_time(n), k, j, i) * time0; + // calculate the stopping time on fly + stime(n) = st0 * dust_size(n); if (vmesh(b, dust::prim::density(n), k, j, i) > dfloor) { - rhod(n) = vmesh(b, dust::prim::density(n), k, j, i) * den0; - vel(0 + n * 3) = - vmesh(b, dust::prim::velocity(VI(n, 0)), k, j, i) * vel0; - vel(1 + n * 3) = - vmesh(b, dust::prim::velocity(VI(n, 1)), k, j, i) * vel0; - vel(2 + n * 3) = - vmesh(b, dust::prim::velocity(VI(n, 2)), k, j, i) * vel0; + rhod(n) = vmesh(b, dust::prim::density(n), k, j, i); + for (int d = 0; d < nvel; d++) { + vel(VI(n, d)) = vmesh(b, dust::prim::velocity(VI(n, d)), k, j, i); + } } else { rhod(n) = 0.0; - vel(0 + n * 3) = 0.0; - vel(1 + n * 3) = 0.0; - vel(2 + n * 3) = 0.0; + for (int d = 0; d < nvel; d++) { + vel(VI(n, d)) = 0.0; + } } }); @@ -607,94 +494,98 @@ TaskStatus CoagulationOneStep(MeshData *md, const Real time, const Real dt vel, nvel, Q, nQs, alpha, cs, omega1, coag, source, nCall1, Q2); - nCalls(k, j, i) = nCall1; + if (info_out_flag) nCalls(k, j, i) = nCall1; // update dust density and velocity after coagulation parthenon::par_for_inner( DEFAULT_INNER_LOOP_PATTERN, mbr, 0, nm - 1, [&](const int n) { // for (int n = 0; n < nspecies; ++n) { if (rhod(n) > 0.0) { - const Real rhod1 = rhod(n) / den0; + const Real rhod1 = rhod(n); vmesh(b, dust::cons::density(n), k, j, i) = rhod1; - vmesh(b, dust::cons::momentum(VI(n, 0)), k, j, i) = - rhod1 * vel(0 + n * 3) * hx[0] / vel0; - vmesh(b, dust::cons::momentum(VI(n, 1)), k, j, i) = - rhod1 * vel(1 + n * 3) * hx[1] / vel0; - vmesh(b, dust::cons::momentum(VI(n, 2)), k, j, i) = - rhod1 * vel(2 + n * 3) * hx[2] / vel0; + for (int d = 0; d < nvel; d++) { + vmesh(b, dust::cons::momentum(VI(n, d)), k, j, i) = + rhod1 * vel(VI(n, d)) * hx[d]; + } } else { vmesh(b, dust::cons::density(n), k, j, i) = 0.0; - vmesh(b, dust::cons::momentum(VI(n, 0)), k, j, i) = 0.0; - vmesh(b, dust::cons::momentum(VI(n, 1)), k, j, i) = 0.0; - vmesh(b, dust::cons::momentum(VI(n, 2)), k, j, i) = 0.0; + for (int d = 0; d < nvel; d++) { + vmesh(b, dust::cons::momentum(VI(n, d)), k, j, i) = 0.0; + } } }); -#ifdef COAG_DEBUG - parthenon::par_for_inner( - DEFAULT_INNER_LOOP_PATTERN, mbr, 0, nm - 1, [&](const int n) { - // for (int n = 0; n < nspecies; n++) { - floor_tmp(i - ib.s, n, 0) = source(n); - floor_tmp(i - ib.s, n, 1) = vmesh(b, dust::cons::density(n), k, j, i); - }); -#endif }); - Real sumd0 = 0.0; - Kokkos::parallel_reduce( - "coag::nCallsMaximum", - Kokkos::MDRangePolicy>({kb.s, jb.s, ib.s}, - {kb.e + 1, jb.e + 1, ib.e + 1}), - KOKKOS_LAMBDA(const int k, const int j, const int i, Real &lsum, int &lmax1, - int &lmax2) { - geometry::Coords coords(vmesh.GetCoordinates(b), k, j, i); - const Real vol00 = coords.Volume(); - for (int n = 0; n < nspecies; ++n) { - Real &dens_d = vmesh(b, dust::cons::density(n), k, j, i); - lsum += dens_d * vol00; - } - lmax1 = std::max(lmax1, nCalls(k, j, i)); - for (int n = nspecies - 1; n >= 0; --n) { - Real &dens_d = vmesh(b, dust::cons::density(n), k, j, i); - if (dens_d > dfloor) { - lmax2 = std::max(lmax2, n); - break; + if (info_out_flag) { + Real sumd0 = 0.0; + int maxCalls1 = 1, maxSize1 = 1; + Kokkos::parallel_reduce( + "coag::nCallsMaximum", + Kokkos::MDRangePolicy>({kb.s, jb.s, ib.s}, + {kb.e + 1, jb.e + 1, ib.e + 1}), + KOKKOS_LAMBDA(const int k, const int j, const int i, Real &lsum, int &lmax1, + int &lmax2) { + geometry::Coords coords(vmesh.GetCoordinates(b), k, j, i); + const Real vol00 = coords.Volume(); + for (int n = 0; n < nspecies; ++n) { + Real &dens_d = vmesh(b, dust::cons::density(n), k, j, i); + lsum += dens_d * vol00; } - } - }, - Kokkos::Sum(sumd0), Kokkos::Max(maxCalls), Kokkos::Max(maxSize)); - sumd1 += sumd0; - } // loop of blocks - -#ifdef COAG_DEBUG - auto floor_h = - Kokkos::create_mirror_view_and_copy(parthenon::HostMemSpace(), floor_tmp); - for (int i = 0; i <= 0; i++) { - std::cout << "i=" << i << " "; - for (int n = 0; n < 20; n++) { - std::cout << floor_h(i, n, 0) << " "; - } - std::cout << std::endl; - - std::cout << "i=" << i << " "; - for (int n = 0; n < 20; n++) { - std::cout << floor_h(i, n, 1) << " "; - } - std::cout << std::endl; - } -#endif - + lmax1 = std::max(lmax1, nCalls(k, j, i)); + for (int n = nspecies - 1; n >= 0; --n) { + Real &dens_d = vmesh(b, dust::cons::density(n), k, j, i); + if (dens_d > dfloor) { + lmax2 = std::max(lmax2, n); + break; + } + } + }, + Kokkos::Sum(sumd0), Kokkos::Max(maxCalls1), + Kokkos::Max(maxSize1)); + massd += sumd0; + maxCalls = std::max(maxCalls, maxCalls1); + maxSize = std::max(maxSize, maxSize1); + } // end if (info_out_flag) + } // loop of blocks + + if (info_out_flag) { #ifdef MPI_PARALLEL - // over all processors - MPI_Reduce(MPI_IN_PLACE, &maxCalls, 1, MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD); - MPI_Reduce(MPI_IN_PLACE, &maxSize, 1, MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD); - MPI_Reduce(MPI_IN_PLACE, &sumd1, 1, MPI_PARTHENON_REAL, MPI_SUM, 0, MPI_COMM_WORLD); + // over all processors + MPI_Reduce(MPI_IN_PLACE, &maxCalls, 1, MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD); + MPI_Reduce(MPI_IN_PLACE, &maxSize, 1, MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD); + MPI_Reduce(MPI_IN_PLACE, &massd, 1, MPI_PARTHENON_REAL, MPI_SUM, 0, MPI_COMM_WORLD); #endif // MPI_PARALLEL - if (parthenon::Globals::my_rank == 0) { - std::cout << "maxcalls,size= " << time << " " << maxCalls << " " << maxSize << " " - << maxSize0 << " " << time0 * dt << std::endl - << "total massd =" << time << " " << massd << " " << sumd1 << std::endl; - } + if (parthenon::Globals::my_rank == 0) { + std::string fname; + // fname.assign(pin->GetString("parthenon/job", "problem_id")); + fname = "artemis"; + fname.append("_coag_info.dat"); + static FILE *pfile = NULL; + + // The file exists -- reopen the file in append mode + if (pfile == NULL) { + if ((pfile = std::fopen(fname.c_str(), "r")) != nullptr) { + if ((pfile = std::freopen(fname.c_str(), "a", pfile)) == nullptr) { + PARTHENON_FAIL("Error output file could not be opened"); + } + // The file does not exist -- open the file in write mode and add headers + } else { + if ((pfile = std::fopen(fname.c_str(), "w")) == nullptr) { + PARTHENON_FAIL("Error output file could not be opened"); + } + std::string label = "# time dt maxCall end_maxSize beg_massSize "; + label.append("end_total_massd beg_total_massd diff_massd \n"); + std::fprintf(pfile, label.c_str()); + } + } + std::fprintf(pfile, " %e ", time); + std::fprintf(pfile, " %e ", dt); + std::fprintf(pfile, " %d %d %d ", maxCalls, maxSize, maxSize0); + std::fprintf(pfile, " %e %e %e", massd, massd0, (massd - massd0) / massd); + std::fprintf(pfile, "\n"); + } + } // end if (info_out_flag) return TaskStatus::complete; } @@ -703,7 +594,7 @@ TaskStatus CoagulationOneStep(MeshData *md, const Real time, const Real dt //! \fn TaskCollection Dust::OperatorSplitDust //! \brief dust operator split task collection template -TaskCollection OperatorSplitDust(Mesh *pm, parthenon::SimTime &tm, const Real dt) { +TaskCollection OperatorSplitDustSelect(Mesh *pm, parthenon::SimTime &tm) { TaskCollection tc; auto &coag_pkg = pm->packages.Get("coagulation"); auto *dtCoag = coag_pkg->MutableParam("dtCoag"); @@ -712,12 +603,12 @@ TaskCollection OperatorSplitDust(Mesh *pm, parthenon::SimTime &tm, const Real dt *dtCoag = 0.0; } - *dtCoag += dt; + *dtCoag += tm.dt; if ((tm.ncycle + 1) % nstep1Coag != 0) { return tc; } - const Real time_local = tm.time + dt - (*dtCoag); + const Real time_local = tm.time + tm.dt - (*dtCoag); const Real dt_local = (*dtCoag); if (parthenon::Globals::my_rank == 0) { std::cout << "coagulation at: time,dt,cycle=" << time_local << " " << dt_local << " " @@ -736,6 +627,7 @@ TaskCollection OperatorSplitDust(Mesh *pm, parthenon::SimTime &tm, const Real dt } auto &dust_subset = pm->mesh_data.AddShallow("dust_subset", pm->mesh_data.Get(), dust_var_names); + using namespace ::parthenon::Update; const int num_partitions = pm->DefaultNumPartitions(); TaskRegion &tr = tc.AddRegion(num_partitions); @@ -761,6 +653,31 @@ TaskCollection OperatorSplitDust(Mesh *pm, parthenon::SimTime &tm, const Real dt return tc; } +//---------------------------------------------------------------------------------------- +//! \fn TaskStatus Dust::OperatorSplit +// \brief Wrapper function for Dust::OperatorSplitDust +TaskListStatus OperatorSplitDust(Mesh *pm, parthenon::SimTime &tm) { + auto &dust_pkg = pm->packages.Get("dust"); + typedef Coordinates C; + const C coords = dust_pkg->template Param("coords"); + + if (coords == C::cartesian) { + return OperatorSplitDustSelect(pm, tm).Execute(); + } else if (coords == C::spherical1D) { + return OperatorSplitDustSelect(pm, tm).Execute(); + } else if (coords == C::spherical2D) { + return OperatorSplitDustSelect(pm, tm).Execute(); + } else if (coords == C::spherical3D) { + return OperatorSplitDustSelect(pm, tm).Execute(); + } else if (coords == C::cylindrical) { + return OperatorSplitDustSelect(pm, tm).Execute(); + } else if (coords == C::axisymmetric) { + return OperatorSplitDustSelect(pm, tm).Execute(); + } else { + PARTHENON_FAIL("Invalid artemis/coordinate system!"); + } +} + //---------------------------------------------------------------------------------------- //! \fn void Dust::ReduceD2gMaximum // \brief calculate dust-to-gas ratio maximum @@ -849,13 +766,6 @@ template Real EstimateTimestepMesh(MeshData *md) template Real EstimateTimestepMesh(MeshData *md); template Real EstimateTimestepMesh(MeshData *md); -template TaskStatus UpdateDustStoppingTime(MeshData *md); -template TaskStatus UpdateDustStoppingTime(MeshData *md); -template TaskStatus UpdateDustStoppingTime(MeshData *md); -template TaskStatus UpdateDustStoppingTime(MeshData *md); -template TaskStatus UpdateDustStoppingTime(MeshData *md); -template TaskStatus UpdateDustStoppingTime(MeshData *md); - template TaskStatus CoagulationOneStep(MeshData *md, const Real time, const Real dt); @@ -875,23 +785,4 @@ template TaskStatus CoagulationOneStep(MeshData const Real time, const Real dt); -template TaskCollection OperatorSplitDust(Mesh *pm, - parthenon::SimTime &tm, - const Real dt); -template TaskCollection -OperatorSplitDust(Mesh *pm, parthenon::SimTime &tm, - const Real dt); -template TaskCollection -OperatorSplitDust(Mesh *pm, parthenon::SimTime &tm, - const Real dt); -template TaskCollection -OperatorSplitDust(Mesh *pm, parthenon::SimTime &tm, - const Real dt); -template TaskCollection -OperatorSplitDust(Mesh *pm, parthenon::SimTime &tm, - const Real dt); -template TaskCollection -OperatorSplitDust(Mesh *pm, parthenon::SimTime &tm, - const Real dt); - } // namespace Dust diff --git a/src/dust/dust.hpp b/src/dust/dust.hpp index 50dbb06..be355d0 100644 --- a/src/dust/dust.hpp +++ b/src/dust/dust.hpp @@ -33,59 +33,8 @@ TaskStatus FluxSource(MeshData *md, const Real dt); void AddHistory(Coordinates coords, Params ¶ms); -struct CGSUnit { - Real mass0 = 1.0; - Real time0 = 1.0; - Real length0 = 1.0; - Real vol0 = 1.0; - bool isurface_den = true; - bool Code2PhysicalUnit_Set = false; - - bool isSet() const { return Code2PhysicalUnit_Set; } - - void SetCGSUnit(const Real &mass0_in, const Real &length0_in, const Real &time0_in, - const int isurf) { - if (!Code2PhysicalUnit_Set) { - mass0 = mass0_in; - length0 = length0_in; - vol0 = SQR(length0_in); - if (isurf == 0) vol0 *= length0_in; // 3D volume - time0 = time0_in; - Code2PhysicalUnit_Set = true; - } - } - - void SetCGSUnit(ParameterInput *pin) { - if (!Code2PhysicalUnit_Set) { - const Real M_SUN = 1.988409870698051e33; // gram (sun) - const Real AU_LENGTH = 1.4959787070000e13; // cm - const Real GRAV_CONST = - 6.674299999999999e-8; // gravitational const in cm^3 g^-1 s^-2 - - Real mstar = pin->GetOrAddReal("problem", "mstar", 1.0) * M_SUN; - length0 = pin->GetOrAddReal("problem", "r0_length", 1.0) * AU_LENGTH; - const Real omega0 = std::sqrt(GRAV_CONST * mstar / pow(length0, 3)); - time0 = 1. / omega0; - - const Real rho0 = pin->GetReal("problem", "rho0"); - mass0 = rho0 * mstar; - - isurface_den = pin->GetOrAddBoolean("dust", "surface_density_flag", true); - vol0 = SQR(length0); - if (isurface_den == 0) vol0 *= length0; // 3D volume - Code2PhysicalUnit_Set = true; - } - } -}; - -extern CGSUnit *cgsunit; - -template -TaskStatus UpdateDustStoppingTime(MeshData *md); - // OperatorSplit tasks -template -TaskCollection OperatorSplitDust(Mesh *pm, parthenon::SimTime &tm, const Real dt); +TaskListStatus OperatorSplitDust(Mesh *pm, parthenon::SimTime &tm); template TaskStatus CoagulationOneStep(MeshData *md, const Real time, const Real dt); diff --git a/src/pgen/dust_coagulation.hpp b/src/pgen/dust_coagulation.hpp index a8daa71..9e2daae 100644 --- a/src/pgen/dust_coagulation.hpp +++ b/src/pgen/dust_coagulation.hpp @@ -53,18 +53,57 @@ struct DustCoagulationVariable { Real gamma, gm1; Real iso_cs; Real d2g; - int nstep1Coag; - Real rho_g0; - Real mass0; - Real time0; - Real length0; - Real vol0; }; } // end anonymous namespace namespace dust_coagulation { +struct CGSUnit { + Real mass0 = 1.0; + Real time0 = 1.0; + Real length0 = 1.0; + Real vol0 = 1.0; + bool isurface_den = true; + bool Code2PhysicalUnit_Set = false; + + bool isSet() const { return Code2PhysicalUnit_Set; } + + void SetCGSUnit(const Real &mass0_in, const Real &length0_in, const Real &time0_in, + const int isurf) { + if (!Code2PhysicalUnit_Set) { + mass0 = mass0_in; + length0 = length0_in; + vol0 = SQR(length0_in); + if (isurf == 0) vol0 *= length0_in; // 3D volume + time0 = time0_in; + Code2PhysicalUnit_Set = true; + } + } + + void SetCGSUnit(ParameterInput *pin) { + if (!Code2PhysicalUnit_Set) { + const Real M_SUN = 1.988409870698051e33; // gram (sun) + const Real AU_LENGTH = 1.4959787070000e13; // cm + const Real GRAV_CONST = + 6.674299999999999e-8; // gravitational const in cm^3 g^-1 s^-2 + + Real mstar = pin->GetOrAddReal("problem", "mstar", 1.0) * M_SUN; + length0 = pin->GetOrAddReal("problem", "r0_length", 1.0) * AU_LENGTH; + const Real omega0 = std::sqrt(GRAV_CONST * mstar / (length0 * length0 * length0)); + time0 = 1. / omega0; + + const Real rho0 = pin->GetReal("problem", "rho0"); + mass0 = rho0 * mstar; + + isurface_den = pin->GetOrAddBoolean("dust", "surface_density_flag", true); + vol0 = SQR(length0); + if (isurface_den == 0) vol0 *= length0; // 3D volume + Code2PhysicalUnit_Set = true; + } + } +}; + DustCoagulationVariable dcv; //---------------------------------------------------------------------------------------- @@ -83,72 +122,69 @@ inline void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { auto &dust_pkg = pmb->packages.Get("dust"); - const bool enable_coagulation = dust_pkg->Param("enable_coagulation"); - // PARTHENON_REQUIRE(enable_coagulation, - // "dust_coagulation pgen requires enable_coagulation=true!"); + const bool do_coagulation = artemis_pkg->Param("do_coagulation"); + PARTHENON_REQUIRE(do_coagulation, + "dust_coagulation pgen requires physics coagulation=true!"); // read global parameters dcv.nDust = pin->GetOrAddReal("dust", "nspecies", 121); dcv.nInit_dust = pin->GetOrAddReal("problem", "nInit_dust", 1); dcv.d2g = pin->GetOrAddReal("problem", "dust_to_gas", 0.01); - dcv.nstep1Coag = pin->GetOrAddReal("problem", "nstep1Coag", 50); - - if (Dust::cgsunit == NULL) { - Dust::cgsunit = new Dust::CGSUnit(); - } - if (!Dust::cgsunit->isSet()) { - Dust::cgsunit->SetCGSUnit(pin); - } - - dcv.length0 = Dust::cgsunit->length0; - dcv.mass0 = Dust::cgsunit->mass0; - dcv.time0 = Dust::cgsunit->time0; - - Real den_code2phy = 1.0; - dcv.vol0 = Dust::cgsunit->vol0; - - den_code2phy = dcv.mass0 / dcv.vol0; - - dcv.rho_g0 = den_code2phy; // using MRN distribution for the initial dust setup ParArray1D dust_size = dust_pkg->template Param>("sizes"); - auto s_p_prefh = Kokkos::create_mirror(dust_size); - Kokkos::deep_copy(s_p_prefh, dust_size); + // convert input "AU" and "mstar" to CGS unit + CGSUnit *cgsunit = new CGSUnit(); + cgsunit->SetCGSUnit(pin); + const Real den0 = cgsunit->mass0 / cgsunit->vol0; // density + const Real time0 = cgsunit->time0; + const Real vel0 = cgsunit->length0 / cgsunit->time0; - Real sum1 = 0.0; - for (int i = 0; i < dcv.nInit_dust; i++) { - sum1 += std::sqrt(s_p_prefh(i)); + const Real tlim_in = pin->GetReal("parthenon/time", "tlim"); + pin->SetReal("parthenon/time", "tlim", tlim_in * time0); + + if (pin->DoesBlockExist("parthenon/output0")) { + const Real dt = pin->GetReal("parthenon/output0", "dt"); + pin->SetReal("parthenon/output0", "dt", dt * time0); } - for (int i = 0; i < dcv.nInit_dust; i++) { - s_p_prefh(i) = std::sqrt(s_p_prefh(i)) / sum1; + if (pin->DoesBlockExist("parthenon/output1")) { + const Real dt = pin->GetReal("parthenon/output1", "dt"); + pin->SetReal("parthenon/output1", "dt", dt * time0); } - for (int i = dcv.nInit_dust; i < dcv.nDust; i++) { - s_p_prefh(i) = 0.0; + if (pin->DoesBlockExist("parthenon/output2")) { + const Real dt = pin->GetReal("parthenon/output2", "dt"); + pin->SetReal("parthenon/output2", "dt", dt * time0); } - ParArray1D s_p_pref("init dust", dcv.nDust); - Kokkos::deep_copy(s_p_pref, s_p_prefh); + const Real x1max = pin->GetReal("parthenon/mesh", "x1max"); + if (x1max < 1e10) { + std::stringstream msg; + msg << " reset x1min and x1max using cgs unit = " << cgsunit->length0 << std::endl; + PARTHENON_FAIL(msg); + } auto gas_pkg = pmb->packages.Get("gas"); auto eos_d = gas_pkg->template Param("eos_d"); dcv.gamma = gas_pkg->Param("adiabatic_index"); dcv.gm1 = dcv.gamma - 1.0; dcv.iso_cs = pin->GetOrAddReal("gas", "iso_sound_speed", 1e-1); + dcv.iso_cs *= vel0; - const Real gdens = 1.0; + const Real gdens = 1.0 * den0; const Real gtemp = SQR(dcv.iso_cs); - const Real vx_g = 0.0; const Real gsie = eos_d.InternalEnergyFromDensityTemperature(gdens, gtemp); - std::cout << "gamma,cs,pre=" << dcv.gamma << " " << dcv.iso_cs << " " << gsie * dcv.gm1 - << std::endl; + if (pmb->gid == 0) { + std::cout << "gamma,cs,temp=" << dcv.gamma << " " << dcv.iso_cs << " " + << gsie * dcv.gm1 << ", time0,length0,mass0,den0,vel0=" << time0 << " " + << cgsunit->length0 << " " << cgsunit->mass0 << " " << den0 << " " << vel0 + << std::endl; + } - const Real vx_d = 0.0; - const Real vy_d = 0.0; - const Real vz_d = 0.0; + const Real vx_g = 0.0 * vel0; + const Real vx_d = 0.0 * vel0; // packing and capture variables for kernel auto &md = pmb->meshblock_data.Get(); @@ -165,6 +201,11 @@ inline void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { IndexRange kb = pmb->cellbounds.GetBoundsK(IndexDomain::entire); auto &dcoag = dcv; + Real sum1 = 0.0; + pmb->par_reduce( + "pgen_partialSum", 0, dcoag.nInit_dust - 1, + KOKKOS_LAMBDA(const int n, Real &lsum) { lsum += std::sqrt(dust_size(n)); }, sum1); + pmb->par_for( "pgen_dustCoagulation", kb.s, kb.e, jb.s, jb.e, ib.s, ib.e, KOKKOS_LAMBDA(const int k, const int j, const int i) { @@ -174,12 +215,18 @@ inline void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { v(0, gas::prim::velocity(2), k, j, i) = 0.0; v(0, gas::prim::sie(0), k, j, i) = gsie; - // dust initial condition - for (int n = 0; n < dcoag.nDust; ++n) { - v(0, dust::prim::density(n), k, j, i) = dcoag.d2g * gdens * s_p_pref(n); + for (int n = 0; n < dcoag.nInit_dust; ++n) { + const Real sratio = std::sqrt(dust_size(n)) / sum1; + v(0, dust::prim::density(n), k, j, i) = dcoag.d2g * gdens * sratio; + v(0, dust::prim::velocity(n * 3 + 0), k, j, i) = vx_d; + v(0, dust::prim::velocity(n * 3 + 1), k, j, i) = 0.0; + v(0, dust::prim::velocity(n * 3 + 2), k, j, i) = 0.0; + } + for (int n = dcoag.nInit_dust; n < dcoag.nDust; ++n) { + v(0, dust::prim::density(n), k, j, i) = 0.0; v(0, dust::prim::velocity(n * 3 + 0), k, j, i) = vx_d; - v(0, dust::prim::velocity(n * 3 + 1), k, j, i) = vy_d; - v(0, dust::prim::velocity(n * 3 + 2), k, j, i) = vz_d; + v(0, dust::prim::velocity(n * 3 + 1), k, j, i) = 0.0; + v(0, dust::prim::velocity(n * 3 + 2), k, j, i) = 0.0; } }); } diff --git a/src/pgen/dust_collision.hpp b/src/pgen/dust_collision.hpp index 6ae9832..b7983c0 100644 --- a/src/pgen/dust_collision.hpp +++ b/src/pgen/dust_collision.hpp @@ -15,7 +15,7 @@ // Licensed under the 3-clause BSD License (the "LICENSE") //======================================================================================== -// NOTE(@pdmullen): The following is taken directly from the open-source +// NOTE(@Shengtai): The following is taken directly from the open-source // Athena++-dustfluid software, and adapted for Parthenon/Artemis by @Shengtai on 4/12/24 //! \file dust_collision.cpp From 347ea013e7d4916a2c4bb29f440d433c103fcaf8 Mon Sep 17 00:00:00 2001 From: Shengtai Li Date: Wed, 11 Dec 2024 14:30:03 -0700 Subject: [PATCH 7/9] merge with the head version and modify c2p to p2c in dust.cpp --- external/parthenon | 2 +- src/dust/dust.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/external/parthenon b/external/parthenon index 75ec2e2..b559452 160000 --- a/external/parthenon +++ b/external/parthenon @@ -1 +1 @@ -Subproject commit 75ec2e2e1951b1d35022f33105eaa7dedf112c69 +Subproject commit b5594528e31cbcb3bd5d2aaa0f944d36d10b2c8f diff --git a/src/dust/dust.cpp b/src/dust/dust.cpp index b01494b..15e4121 100644 --- a/src/dust/dust.cpp +++ b/src/dust/dust.cpp @@ -645,8 +645,8 @@ TaskCollection OperatorSplitDustSelect(Mesh *pm, parthenon::SimTime &tm) { auto &md_coag = pm->mesh_data.GetOrAdd("dust_subset", i); auto bcs = parthenon::AddBoundaryExchangeTasks(pre_comm, tl, md_coag, pm->multilevel); - // Update primitive variables - auto c2p = tl.AddTask(bcs, FillDerived>, base.get()); + // Sync fields + auto p2c = tl.AddTask(bcs, FillDerived>, base.get()); } *dtCoag = 0.0; From 053f77bca1824f8129aaf76605742fa6d6ae42d4 Mon Sep 17 00:00:00 2001 From: Shengtai Li Date: Fri, 3 Jan 2025 14:50:51 -0700 Subject: [PATCH 8/9] new modification based on units --- inputs/dust/dust_coagulation.in | 18 +- inputs/dust/dust_coagulation_den.in | 18 +- inputs/dust/dust_collision.in | 91 ---------- src/artemis_driver.cpp | 2 +- src/dust/coagulation/coagulation.cpp | 22 +-- src/dust/coagulation/coagulation.hpp | 8 +- src/dust/dust.cpp | 87 +++++----- src/dust/dust.hpp | 1 + src/pgen/dust_coagulation.hpp | 89 +--------- src/pgen/dust_collision.hpp | 239 --------------------------- src/pgen/pgen.hpp | 3 - src/pgen/problem_modifier.hpp | 2 - src/utils/units.cpp | 8 +- 13 files changed, 93 insertions(+), 495 deletions(-) delete mode 100644 inputs/dust/dust_collision.in delete mode 100644 src/pgen/dust_collision.hpp diff --git a/inputs/dust/dust_coagulation.in b/inputs/dust/dust_coagulation.in index 0af7e0f..4ebd23a 100644 --- a/inputs/dust/dust_coagulation.in +++ b/inputs/dust/dust_coagulation.in @@ -13,7 +13,12 @@ problem = dust_coagulation # name of the pgen -coordinates = cartesian # coordinate system +coordinates = cartesian # coordinate system +unit_conversion = ppd # ppd (code unit: AU, Msun, year/(2*pi) +r0_length = 10. # AU +mstar = 1.0 # M_sun +rho0 = 2e-5 +physical_units = cgs # problem_id = coag # problem ID: basename of output filenames @@ -45,8 +50,8 @@ refinement = none # numlevel = 1 nx1 = 16 # Number of zones in X1-direction -x1min = 1.35e15 # minimum value of X1 -x1max = 1.64e15 # maximum value of X1 +x1min = 9.0 # minimum value of X1 +x1max = 11.0 # maximum value of X1 ix1_bc = outflow # Inner-X1 boundary condition flag ox1_bc = outflow # Outer-X1 boundary condition flag @@ -76,6 +81,7 @@ coagulation = true cfl = 0.9 gamma = 1.00001 iso_sound_speed = 0.05 # code unit +cv = 1e5 # 1/(gamma-1) cfl = 0.9 @@ -99,9 +105,7 @@ coag_info_out = true nInit_dust = 11 # number of dust species initially dust_to_gas = 0.01 -nstep1Coag = 10 -mstar = 1.0 # central star masss (m_sun) -r0_length = 10.0 # 1 code unit (AU) -rho0 = 2e-5 # code unit value of 1 m_star/r0_length^2 +nstep1Coag = 1 +#rho0 = 2e-5 # code unit value of 1 m_star/r0_length^2 const_coag_omega = true # using omega at r0_length diff --git a/inputs/dust/dust_coagulation_den.in b/inputs/dust/dust_coagulation_den.in index 97de130..c1bb60a 100644 --- a/inputs/dust/dust_coagulation_den.in +++ b/inputs/dust/dust_coagulation_den.in @@ -13,7 +13,12 @@ problem = dust_coagulation # name of the pgen -coordinates = cartesian # coordinate system +coordinates = cartesian # coordinate system +unit_conversion = ppd # ppd (code unit: AU, Msun, year/(2*pi) +r0_length = 10. # AU +mstar = 1.0 # M_sun +rho0 = 1.59577e-4 # 3D rho (mstar/r0^3) +physical_units = cgs # problem_id = coag # problem ID: basename of output filenames @@ -34,7 +39,7 @@ file_type = rst dt = 628 -nlim = 5 # cycle limit +nlim = -1 # cycle limit tlim = 6280. # time limit integrator = rk2 # time integration algorithm ncycle_out = 1 # interval for stdout summary info @@ -45,8 +50,8 @@ refinement = none # numlevel = 1 nx1 = 16 # Number of zones in X1-direction -x1min = 1.35e15 # minimum value of X1 -x1max = 1.64e15 # maximum value of X1 +x1min = 9.0 # minimum value of X1 +x1max = 11.0 # maximum value of X1 ix1_bc = outflow # Inner-X1 boundary condition flag ox1_bc = outflow # Outer-X1 boundary condition flag @@ -76,6 +81,7 @@ coagulation = true cfl = 0.9 gamma = 1.00001 iso_sound_speed = 0.05 # code unit +cv = 1e5 # 1/(gamma-1) cfl = 0.9 @@ -100,8 +106,6 @@ coag_info_out = true nInit_dust = 11 # number of dust species initially dust_to_gas = 0.01 nstep1Coag = 1 -mstar = 1.0 # central star masss (m_sun) -r0_length = 10.0 # 1 code unit (AU) -rho0 = 2e-5 # code unit value of 1 m_star/r0_length^2 +#rho0 = 2e-5 # code unit value of 1 m_star/r0_length^2 const_coag_omega = true # using omega at r0_length diff --git a/inputs/dust/dust_collision.in b/inputs/dust/dust_collision.in deleted file mode 100644 index 482c46e..0000000 --- a/inputs/dust/dust_collision.in +++ /dev/null @@ -1,91 +0,0 @@ -# ======================================================================================== -# (C) (or copyright) 2023-2024. Triad National Security, LLC. All rights reserved. -# -# This program was produced under U.S. Government contract 89233218CNA000001 for Los -# Alamos National Laboratory (LANL), which is operated by Triad National Security, LLC -# for the U.S. Department of Energy/National Nuclear Security Administration. All rights -# in the program are reserved by Triad National Security, LLC, and the U.S. Department -# of Energy/National Nuclear Security Administration. The Government is granted for -# itself and others acting on its behalf a nonexclusive, paid-up, irrevocable worldwide -# license in this material to reproduce, prepare derivative works, distribute copies to -# the public, perform publicly and display publicly, and to permit others to do so. -# ======================================================================================== - - -problem = dust_collision # name of the pgen -coordinates = cartesian # coordinate system - - -problem_id = dc_B # problem ID: basename of output filenames - - -variables = gas.prim.density, & - gas.prim.velocity, & - gas.prim.pressure, & - dust.prim.density, & - dust.prim.velocity -file_type = hdf5 # tab data dump -dt = 0.05 # time increment between outputs - - -nlim = -1 # cycle limit -tlim = 0.05 # time limit -integrator = rk2 # time integration algorithm -ncycle_out = 1 # interval for stdout summary info -dt_user = 0.005 - - -nghost = 2 -refinement = none -# numlevel = 1 - -nx1 = 16 # Number of zones in X1-direction -x1min = 0.0 # minimum value of X1 -x1max = 1.0 # maximum value of X1 -ix1_bc = periodic # Inner-X1 boundary condition flag -ox1_bc = periodic # Outer-X1 boundary condition flag - -nx2 = 1 # Number of zones in X2-direction -x2min = -0.5 # minimum value of X2 -x2max = 0.5 # maximum value of X2 -ix2_bc = periodic # Inner-X2 boundary condition flag -ox2_bc = periodic # Outer-X2 boundary condition flag - -nx3 = 1 # Number of zones in X3-direction -x3min = -0.5 # minimum value of X3 -x3max = 0.5 # maximum value of X3 -ix3_bc = periodic # Inner-X3 boundary condition flag -ox3_bc = periodic # Outer-X3 boundary condition flag - - -nx1 = 16 # Number of cells in each MeshBlock, X1-dir -nx2 = 1 # Number of cells in each MeshBlock, X2-dir -nx3 = 1 # Number of cells in each MeshBlock, X3-dir - - -gas = true -dust = true -drag = true - - -cfl = 0.9 -gamma = 1.4 -iso_sound_speed = 0.1 - - -cfl = 0.9 -nspecies = 2 - -sizes = 1.0, 1.0 - - -type = constant -tau = 0.01, 0.001 # for iprob = 1 -#tau = 2.0, 1.0 # for iprob = 2 - - -type = simple_dust - - - -iprob = 1 # 1 or 2 diff --git a/src/artemis_driver.cpp b/src/artemis_driver.cpp index 222d329..5860b5e 100644 --- a/src/artemis_driver.cpp +++ b/src/artemis_driver.cpp @@ -112,7 +112,7 @@ TaskListStatus ArtemisDriver::Step() { if (do_radiation) status = IMC::JaybenneIMC(pmesh, tm.time, tm.dt); if (status != TaskListStatus::complete) return status; - if (do_coagulation) status = Dust::OperatorSplitDust(pmesh, tm); + if (do_coagulation) status = Dust::OperatorSplitDust(pmesh, tm); if (status != TaskListStatus::complete) return status; // Compute new dt, (de)refine, and handle sparse (if enabled) diff --git a/src/dust/coagulation/coagulation.cpp b/src/dust/coagulation/coagulation.cpp index 4829e0b..a8d899b 100644 --- a/src/dust/coagulation/coagulation.cpp +++ b/src/dust/coagulation/coagulation.cpp @@ -16,16 +16,22 @@ #include "artemis.hpp" #include "dust/dust.hpp" #include "geometry/geometry.hpp" +#include "utils/units.hpp" namespace Dust { namespace Coagulation { //---------------------------------------------------------------------------------------- //! \fn StateDescriptor Coagulalation::Initialize //! \brief Adds intialization function for coagulation package -std::shared_ptr Initialize(ParameterInput *pin, Params &dustPars) { +std::shared_ptr Initialize(ParameterInput *pin, Params &dustPars, + ArtemisUtils::Units &units, + ArtemisUtils::Constants &constants) { auto coag = std::make_shared("coagulation"); Params ¶ms = coag->AllParams(); + PARTHENON_REQUIRE(units.GetPhysicalUnits() == ArtemisUtils::PhysicalUnits::cgs, + "coagulation physics requires physical_units = cgs"); + CoagParams cpars; const int nm = dustPars.template Get("nspecies"); @@ -41,17 +47,8 @@ std::shared_ptr Initialize(ParameterInput *pin, Params &dustPar cpars.nCall_mx = pin->GetOrAddInteger("dust/coagulation", "coag_nsteps_mx", 1000); cpars.rho_p = rho_p; - const Real M_SUN = 1.988409870698051e33; // gram (sun) - const Real GRAV_CONST = 6.674299999999999e-8; // gravitational const in cm^3 g^-1 s^-2 - const Real mstar = pin->GetOrAddReal("problem", "mstar", 1.0) * M_SUN; - cpars.gm = std::sqrt(GRAV_CONST * mstar); const bool const_omega = pin->GetOrAddBoolean("problem", "const_coag_omega", false); cpars.const_omega = const_omega; - if (const_omega) { - const Real AU_LENGTH = 1.4959787070000e13; // cm - const Real r0 = pin->GetOrAddReal("problem", "r0_length", 1.0) * AU_LENGTH; - cpars.gm /= (std::sqrt(r0) * r0); - } cpars.ibounce = pin->GetOrAddBoolean("dust/coagulation", "coag_bounce", false); @@ -61,6 +58,9 @@ std::shared_ptr Initialize(ParameterInput *pin, Params &dustPar if (isurface_den) coord_type = 1; cpars.coord = coord_type; // 1--surface density, 0: 3D + cpars.rho0 = units.GetMassDensityCodeToPhysical(); + if (isurface_den) cpars.rho0 *= units.GetLengthCodeToPhysical(); + cpars.err_eps = 1.0e-1; cpars.S = 0.9; cpars.cfl = 1.0e-1; @@ -104,7 +104,7 @@ std::shared_ptr Initialize(ParameterInput *pin, Params &dustPar cpars.cpod_notzero = ParArray3D("idx_nzcpod", nm, nm, 4); cpars.cpod_short = ParArray3D("nzcpod", nm, nm, 4); - cpars.dfloor = dfloor; + cpars.dfloor = dfloor * cpars.rho0; Real a = 3.0 * std::log10(h_sizes(0) / h_sizes(nm - 1)) / static_cast(1 - nm); initializeArray(nm, cpars.pGrid, cpars.rho_p, cpars.chi, a, dust_size, cpars.klf, diff --git a/src/dust/coagulation/coagulation.hpp b/src/dust/coagulation/coagulation.hpp index 5e5a835..659d44b 100644 --- a/src/dust/coagulation/coagulation.hpp +++ b/src/dust/coagulation/coagulation.hpp @@ -14,6 +14,7 @@ #define DUST_COAGULATION_HPP_ #include "utils/artemis_utils.hpp" +#include "utils/units.hpp" //#define COAGULATION_DEBUG namespace Dust { @@ -21,7 +22,9 @@ namespace Coagulation { enum coag2DRv { dpod, aFrag, phiFrag, epsFrag, dalp, kdelta, coef_fett, last2 }; -std::shared_ptr Initialize(ParameterInput *pin, Params &dustPars); +std::shared_ptr Initialize(ParameterInput *pin, Params &dustPars, + ArtemisUtils::Units &units, + ArtemisUtils::Constants &constants); struct CoagParams { int coord = 0; // 1--surface density, 0: 3D @@ -45,9 +48,10 @@ struct CoagParams { Real S; // Safety margin for adaptive step sizing Real cfl; Real errcon; // Needed for increasing step size - Real gm; // sqrt(grav_const * mstar); bool const_omega; // for shearing-box or testing + Real rho0; // physical-to-code unit conversion + // pre-calculated array, once-for-all ParArray2D klf; ParArray1D mass_grid; diff --git a/src/dust/dust.cpp b/src/dust/dust.cpp index 15e4121..d6785c0 100644 --- a/src/dust/dust.cpp +++ b/src/dust/dust.cpp @@ -347,6 +347,7 @@ TaskStatus CoagulationOneStep(MeshData *md, const Real time, const Real dt using parthenon::MakePackDescriptor; auto pm = md->GetParentPointer(); + auto &artemis_pkg = pm->packages.Get("artemis"); auto &dust_pkg = pm->packages.Get("dust"); IndexRange ib = md->GetBoundsI(IndexDomain::interior); IndexRange jb = md->GetBoundsJ(IndexDomain::interior); @@ -374,6 +375,13 @@ TaskStatus CoagulationOneStep(MeshData *md, const Real time, const Real dt if (coag.coord) nvel = 2; // surface-density auto &dfloor = dust_pkg->template Param("dfloor"); + // unit: coagulation using cgs physical unit + auto &units = artemis_pkg->template Param("units"); + const Real time0 = units.GetTimeCodeToPhysical(); + const Real length0 = units.GetLengthCodeToPhysical(); + const Real rho0 = coag.rho0; + const Real vel0 = length0 / time0; + const int scr_level = coag_pkg->template Param("coag_scr_level"); auto info_out_flag = coag_pkg->template Param("coag_info_out"); @@ -434,25 +442,26 @@ TaskStatus CoagulationOneStep(MeshData *md, const Real time, const Real dt vmesh.GetLowerBound(b, dust::prim::density()) + 1); const Real dens_g = vmesh(b, gas::prim::density(0), k, j, i); - Real dt_sync = dt; - const Real time1 = time; + Real dt_sync = dt * time0; geometry::Coords coords(vmesh.GetCoordinates(b), k, j, i); const auto &hx = coords.GetScaleFactors(); const auto &xv = coords.GetCellCenter(); const auto &xcyl = coords.ConvertToCyl(xv); - const Real rad = xcyl[0]; // cylindrical - const Real Omega_k = - coag.const_omega ? coag.gm : coag.gm / std::sqrt(rad) / rad; // code unit + const Real rad = coag.const_omega ? 1.0 : xcyl[0]; // cylindrical + + const Real Omega_k = 1.0 / std::sqrt(rad) / rad; int nCall1 = 0; const Real sie = vmesh(b, gas::prim::sie(0), k, j, i); const Real bulk = eos_d.BulkModulusFromDensityInternalEnergy(dens_g, sie); - const Real cs = std::sqrt(bulk / dens_g); - const Real omega1 = Omega_k; + const Real cs1 = std::sqrt(bulk / dens_g) * vel0; + const Real omega1 = Omega_k / time0; const int nm = nspecies; + const Real time1 = time * time0; + const Real dens_g1 = dens_g * rho0; ScratchPad1D rhod(mbr.team_scratch(scr_level), nspecies); ScratchPad1D stime(mbr.team_scratch(scr_level), nspecies); @@ -468,9 +477,9 @@ TaskStatus CoagulationOneStep(MeshData *md, const Real time, const Real dt // calculate the stopping time on the fly Real st0 = 1.0; if (coag.coord) { // surface density - st0 = 0.5 * M_PI * coag.rho_p / dens_g / omega1; + st0 = 0.5 * M_PI * coag.rho_p / dens_g1 / omega1; } else { - st0 = std::sqrt(M_PI / 8.0) * coag.rho_p / dens_g / cs; + st0 = std::sqrt(M_PI / 8.0) * coag.rho_p / dens_g1 / cs1; } parthenon::par_for_inner( @@ -478,9 +487,10 @@ TaskStatus CoagulationOneStep(MeshData *md, const Real time, const Real dt // calculate the stopping time on fly stime(n) = st0 * dust_size(n); if (vmesh(b, dust::prim::density(n), k, j, i) > dfloor) { - rhod(n) = vmesh(b, dust::prim::density(n), k, j, i); + rhod(n) = vmesh(b, dust::prim::density(n), k, j, i) * rho0; for (int d = 0; d < nvel; d++) { - vel(VI(n, d)) = vmesh(b, dust::prim::velocity(VI(n, d)), k, j, i); + vel(VI(n, d)) = + vmesh(b, dust::prim::velocity(VI(n, d)), k, j, i) * vel0; } } else { rhod(n) = 0.0; @@ -490,8 +500,8 @@ TaskStatus CoagulationOneStep(MeshData *md, const Real time, const Real dt } }); - Coagulation::CoagulationOneCell(mbr, i, time1, dt_sync, dens_g, rhod, stime, - vel, nvel, Q, nQs, alpha, cs, omega1, coag, + Coagulation::CoagulationOneCell(mbr, i, time1, dt_sync, dens_g1, rhod, stime, + vel, nvel, Q, nQs, alpha, cs1, omega1, coag, source, nCall1, Q2); if (info_out_flag) nCalls(k, j, i) = nCall1; @@ -502,10 +512,10 @@ TaskStatus CoagulationOneStep(MeshData *md, const Real time, const Real dt // for (int n = 0; n < nspecies; ++n) { if (rhod(n) > 0.0) { const Real rhod1 = rhod(n); - vmesh(b, dust::cons::density(n), k, j, i) = rhod1; + vmesh(b, dust::cons::density(n), k, j, i) = rhod1 / rho0; for (int d = 0; d < nvel; d++) { vmesh(b, dust::cons::momentum(VI(n, d)), k, j, i) = - rhod1 * vel(VI(n, d)) * hx[d]; + rhod1 * vel(VI(n, d)) * hx[d] / vel0; } } else { vmesh(b, dust::cons::density(n), k, j, i) = 0.0; @@ -592,10 +602,9 @@ TaskStatus CoagulationOneStep(MeshData *md, const Real time, const Real dt //---------------------------------------------------------------------------------------- //! \fn TaskCollection Dust::OperatorSplitDust -//! \brief dust operator split task collection +//! \brief dust wrapper function for operatorsplitDust template -TaskCollection OperatorSplitDustSelect(Mesh *pm, parthenon::SimTime &tm) { - TaskCollection tc; +TaskListStatus OperatorSplitDust(Mesh *pm, parthenon::SimTime &tm) { auto &coag_pkg = pm->packages.Get("coagulation"); auto *dtCoag = coag_pkg->MutableParam("dtCoag"); int nstep1Coag = coag_pkg->template Param("nstep1Coag"); @@ -605,7 +614,7 @@ TaskCollection OperatorSplitDustSelect(Mesh *pm, parthenon::SimTime &tm) { *dtCoag += tm.dt; if ((tm.ncycle + 1) % nstep1Coag != 0) { - return tc; + return TaskListStatus::complete; } const Real time_local = tm.time + tm.dt - (*dtCoag); @@ -615,6 +624,7 @@ TaskCollection OperatorSplitDustSelect(Mesh *pm, parthenon::SimTime &tm) { << tm.ncycle << std::endl; } + TaskCollection tc; TaskID none(0); // Assemble tasks @@ -650,32 +660,7 @@ TaskCollection OperatorSplitDustSelect(Mesh *pm, parthenon::SimTime &tm) { } *dtCoag = 0.0; - return tc; -} - -//---------------------------------------------------------------------------------------- -//! \fn TaskStatus Dust::OperatorSplit -// \brief Wrapper function for Dust::OperatorSplitDust -TaskListStatus OperatorSplitDust(Mesh *pm, parthenon::SimTime &tm) { - auto &dust_pkg = pm->packages.Get("dust"); - typedef Coordinates C; - const C coords = dust_pkg->template Param("coords"); - - if (coords == C::cartesian) { - return OperatorSplitDustSelect(pm, tm).Execute(); - } else if (coords == C::spherical1D) { - return OperatorSplitDustSelect(pm, tm).Execute(); - } else if (coords == C::spherical2D) { - return OperatorSplitDustSelect(pm, tm).Execute(); - } else if (coords == C::spherical3D) { - return OperatorSplitDustSelect(pm, tm).Execute(); - } else if (coords == C::cylindrical) { - return OperatorSplitDustSelect(pm, tm).Execute(); - } else if (coords == C::axisymmetric) { - return OperatorSplitDustSelect(pm, tm).Execute(); - } else { - PARTHENON_FAIL("Invalid artemis/coordinate system!"); - } + return tc.Execute(); } //---------------------------------------------------------------------------------------- @@ -784,5 +769,17 @@ template TaskStatus CoagulationOneStep(MeshData template TaskStatus CoagulationOneStep(MeshData *md, const Real time, const Real dt); +template TaskListStatus OperatorSplitDust(Mesh *pm, + parthenon::SimTime &tm); +template TaskListStatus +OperatorSplitDust(Mesh *pm, parthenon::SimTime &tm); +template TaskListStatus +OperatorSplitDust(Mesh *pm, parthenon::SimTime &tm); +template TaskListStatus +OperatorSplitDust(Mesh *pm, parthenon::SimTime &tm); +template TaskListStatus +OperatorSplitDust(Mesh *pm, parthenon::SimTime &tm); +template TaskListStatus +OperatorSplitDust(Mesh *pm, parthenon::SimTime &tm); } // namespace Dust diff --git a/src/dust/dust.hpp b/src/dust/dust.hpp index be355d0..1145d11 100644 --- a/src/dust/dust.hpp +++ b/src/dust/dust.hpp @@ -34,6 +34,7 @@ TaskStatus FluxSource(MeshData *md, const Real dt); void AddHistory(Coordinates coords, Params ¶ms); // OperatorSplit tasks +template TaskListStatus OperatorSplitDust(Mesh *pm, parthenon::SimTime &tm); template diff --git a/src/pgen/dust_coagulation.hpp b/src/pgen/dust_coagulation.hpp index 9e2daae..5c50b07 100644 --- a/src/pgen/dust_coagulation.hpp +++ b/src/pgen/dust_coagulation.hpp @@ -59,51 +59,6 @@ struct DustCoagulationVariable { namespace dust_coagulation { -struct CGSUnit { - Real mass0 = 1.0; - Real time0 = 1.0; - Real length0 = 1.0; - Real vol0 = 1.0; - bool isurface_den = true; - bool Code2PhysicalUnit_Set = false; - - bool isSet() const { return Code2PhysicalUnit_Set; } - - void SetCGSUnit(const Real &mass0_in, const Real &length0_in, const Real &time0_in, - const int isurf) { - if (!Code2PhysicalUnit_Set) { - mass0 = mass0_in; - length0 = length0_in; - vol0 = SQR(length0_in); - if (isurf == 0) vol0 *= length0_in; // 3D volume - time0 = time0_in; - Code2PhysicalUnit_Set = true; - } - } - - void SetCGSUnit(ParameterInput *pin) { - if (!Code2PhysicalUnit_Set) { - const Real M_SUN = 1.988409870698051e33; // gram (sun) - const Real AU_LENGTH = 1.4959787070000e13; // cm - const Real GRAV_CONST = - 6.674299999999999e-8; // gravitational const in cm^3 g^-1 s^-2 - - Real mstar = pin->GetOrAddReal("problem", "mstar", 1.0) * M_SUN; - length0 = pin->GetOrAddReal("problem", "r0_length", 1.0) * AU_LENGTH; - const Real omega0 = std::sqrt(GRAV_CONST * mstar / (length0 * length0 * length0)); - time0 = 1. / omega0; - - const Real rho0 = pin->GetReal("problem", "rho0"); - mass0 = rho0 * mstar; - - isurface_den = pin->GetOrAddBoolean("dust", "surface_density_flag", true); - vol0 = SQR(length0); - if (isurface_den == 0) vol0 *= length0; // 3D volume - Code2PhysicalUnit_Set = true; - } - } -}; - DustCoagulationVariable dcv; //---------------------------------------------------------------------------------------- @@ -134,57 +89,23 @@ inline void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { // using MRN distribution for the initial dust setup ParArray1D dust_size = dust_pkg->template Param>("sizes"); - // convert input "AU" and "mstar" to CGS unit - CGSUnit *cgsunit = new CGSUnit(); - cgsunit->SetCGSUnit(pin); - const Real den0 = cgsunit->mass0 / cgsunit->vol0; // density - const Real time0 = cgsunit->time0; - const Real vel0 = cgsunit->length0 / cgsunit->time0; - - const Real tlim_in = pin->GetReal("parthenon/time", "tlim"); - pin->SetReal("parthenon/time", "tlim", tlim_in * time0); - - if (pin->DoesBlockExist("parthenon/output0")) { - const Real dt = pin->GetReal("parthenon/output0", "dt"); - pin->SetReal("parthenon/output0", "dt", dt * time0); - } - - if (pin->DoesBlockExist("parthenon/output1")) { - const Real dt = pin->GetReal("parthenon/output1", "dt"); - pin->SetReal("parthenon/output1", "dt", dt * time0); - } - - if (pin->DoesBlockExist("parthenon/output2")) { - const Real dt = pin->GetReal("parthenon/output2", "dt"); - pin->SetReal("parthenon/output2", "dt", dt * time0); - } - - const Real x1max = pin->GetReal("parthenon/mesh", "x1max"); - if (x1max < 1e10) { - std::stringstream msg; - msg << " reset x1min and x1max using cgs unit = " << cgsunit->length0 << std::endl; - PARTHENON_FAIL(msg); - } auto gas_pkg = pmb->packages.Get("gas"); auto eos_d = gas_pkg->template Param("eos_d"); dcv.gamma = gas_pkg->Param("adiabatic_index"); dcv.gm1 = dcv.gamma - 1.0; dcv.iso_cs = pin->GetOrAddReal("gas", "iso_sound_speed", 1e-1); - dcv.iso_cs *= vel0; - const Real gdens = 1.0 * den0; + const Real gdens = 1.0; const Real gtemp = SQR(dcv.iso_cs); const Real gsie = eos_d.InternalEnergyFromDensityTemperature(gdens, gtemp); if (pmb->gid == 0) { - std::cout << "gamma,cs,temp=" << dcv.gamma << " " << dcv.iso_cs << " " - << gsie * dcv.gm1 << ", time0,length0,mass0,den0,vel0=" << time0 << " " - << cgsunit->length0 << " " << cgsunit->mass0 << " " << den0 << " " << vel0 - << std::endl; + std::cout << "gamma,cs,pre=" << dcv.gamma << " " << dcv.iso_cs << " " + << gsie * dcv.gm1 * gdens << std::endl; } - const Real vx_g = 0.0 * vel0; - const Real vx_d = 0.0 * vel0; + const Real vx_g = 0.0; + const Real vx_d = 0.0; // packing and capture variables for kernel auto &md = pmb->meshblock_data.Get(); diff --git a/src/pgen/dust_collision.hpp b/src/pgen/dust_collision.hpp deleted file mode 100644 index b7983c0..0000000 --- a/src/pgen/dust_collision.hpp +++ /dev/null @@ -1,239 +0,0 @@ -//======================================================================================== -// (C) (or copyright) 2023-2024. Triad National Security, LLC. All rights reserved. -// -// This program was produced under U.S. Government contract 89233218CNA000001 for Los -// Alamos National Laboratory (LANL), which is operated by Triad National Security, LLC -// for the U.S. Department of Energy/National Nuclear Security Administration. All rights -// in the program are reserved by Triad National Security, LLC, and the U.S. Department -// of Energy/National Nuclear Security Administration. The Government is granted for -// itself and others acting on its behalf a nonexclusive, paid-up, irrevocable worldwide -// license in this material to reproduce, prepare derivative works, distribute copies to -// the public, perform publicly and display publicly, and to permit others to do so. -//======================================================================================== -// AthenaXXX astrophysical plasma code -// Copyright(C) 2020 James M. Stone and the Athena code team -// Licensed under the 3-clause BSD License (the "LICENSE") -//======================================================================================== - -// NOTE(@Shengtai): The following is taken directly from the open-source -// Athena++-dustfluid software, and adapted for Parthenon/Artemis by @Shengtai on 4/12/24 - -//! \file dust_collision.cpp -//! \brief dust collision problem generator for 1D problems. - -#ifndef PGEN_DUST_COLLISION_HPP_ -#define PGEN_DUST_COLLISION_HPP_ - -// C/C++ headers -#include -#include -#include -#include -#include -#include -#include - -// Artemis headers -#include "artemis.hpp" -#include "geometry/geometry.hpp" -//#include "pgen/pgen.hpp" -#include "utils/artemis_utils.hpp" -#include "utils/eos/eos.hpp" - -using ArtemisUtils::EOS; - -namespace { - -//---------------------------------------------------------------------------------------- -//! \struct DustCollisionVariable -//! \brief container for variables shared with dust collision pgen -struct DustCollisionVariable { - int prob_flag; - int nDust; - Real gamma, gm1; - Real iso_cs; -}; - -} // end anonymous namespace - -namespace dust_collision { - -DustCollisionVariable dcv; - -//---------------------------------------------------------------------------------------- -//! \fn void ProblemGenerator::DustCollision_() -//! \brief Sets initial conditions for dust collision tests -template -inline void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { - using parthenon::MakePackDescriptor; - - auto artemis_pkg = pmb->packages.Get("artemis"); - const auto geom = artemis_pkg->Param("coords"); - PARTHENON_REQUIRE(geom == Coordinates::cartesian, - "dust_collision pgen requires Cartesian geometry!"); - const bool do_dust = artemis_pkg->Param("do_dust"); - PARTHENON_REQUIRE(do_dust, "dust_collision pgen requires do_dust=true!"); - bool const_stopping_time = pin->GetOrAddBoolean("dust", "const_stopping_time", true); - PARTHENON_REQUIRE(do_dust, "dust_collision pgen requires const_stopping_time=true!"); - - // read global parameters - dcv.prob_flag = pin->GetOrAddInteger("problem", "iprob", 1); - dcv.nDust = pin->GetOrAddReal("dust", "nspecies", 2); - PARTHENON_REQUIRE(dcv.nDust == 2, "dust_collision pgen requires dust nspecies == 2!"); - - auto gas_pkg = pmb->packages.Get("gas"); - auto eos_d = gas_pkg->template Param("eos_d"); - - dcv.gamma = gas_pkg->Param("adiabatic_index"); - dcv.gm1 = dcv.gamma - 1.0; - dcv.iso_cs = pin->GetOrAddReal("gas", "iso_sound_speed", 1e-1); - - const Real gdens = 1.0; - const Real gtemp = SQR(dcv.iso_cs); - const Real vx_g = 1.0; - const Real gsie = eos_d.InternalEnergyFromDensityTemperature(gdens, gtemp); - - // packing and capture variables for kernel - auto &md = pmb->meshblock_data.Get(); - for (auto &var : md->GetVariableVector()) { - if (!var->IsAllocated()) pmb->AllocateSparse(var->label()); - } - static auto desc = - MakePackDescriptor( - (pmb->resolved_packages).get()); - auto v = desc.GetPack(md.get()); - IndexRange ib = pmb->cellbounds.GetBoundsI(IndexDomain::entire); - IndexRange jb = pmb->cellbounds.GetBoundsJ(IndexDomain::entire); - IndexRange kb = pmb->cellbounds.GetBoundsK(IndexDomain::entire); - auto &dcol = dcv; - - pmb->par_for( - "pgen_dustCollision", kb.s, kb.e, jb.s, jb.e, ib.s, ib.e, - KOKKOS_LAMBDA(const int k, const int j, const int i) { - v(0, gas::prim::density(), k, j, i) = gdens; - v(0, gas::prim::velocity(0), k, j, i) = vx_g; - v(0, gas::prim::velocity(1), k, j, i) = 0.0; - v(0, gas::prim::velocity(2), k, j, i) = 0.0; - v(0, gas::prim::sie(), k, j, i) = gsie; - - // dust initial condition - if (dcol.prob_flag == 1) { // stiff problem with smaller stopping time - v(0, dust::prim::density(0), k, j, i) = 1.0; - v(0, dust::prim::density(1), k, j, i) = 1.0; - } else { - v(0, dust::prim::density(0), k, j, i) = 10.0; - v(0, dust::prim::density(1), k, j, i) = 100.0; - } - v(0, dust::prim::velocity(0 * 3 + 0), k, j, i) = 2.0; - v(0, dust::prim::velocity(0 * 3 + 1), k, j, i) = 0.0; - v(0, dust::prim::velocity(0 * 3 + 2), k, j, i) = 0.0; - - v(0, dust::prim::velocity(1 * 3 + 0), k, j, i) = 0.5; - v(0, dust::prim::velocity(1 * 3 + 1), k, j, i) = 0.0; - v(0, dust::prim::velocity(1 * 3 + 2), k, j, i) = 0.0; - }); -} - -//---------------------------------------------------------------------------------------- -//! \fn void PreStepUserworkInLoop -//! \brief output numerical solution and analytic solution before each step -//! and writing to file. -inline void PreStepUserWorkInLoop(Mesh *pmesh, ParameterInput *pin, - parthenon::SimTime &tm) { - - // packing and capture variables for kernel - auto &md = pmesh->mesh_data.GetOrAdd("base", 0); - auto pmb = md->GetBlockData(0)->GetBlockPointer(); - static auto desc = MakePackDescriptor( - (pmb->resolved_packages).get()); - auto v = desc.GetPack(md.get()); - - IndexRange ib = pmb->cellbounds.GetBoundsI(IndexDomain::interior); - IndexRange jb = pmb->cellbounds.GetBoundsJ(IndexDomain::interior); - IndexRange kb = pmb->cellbounds.GetBoundsK(IndexDomain::interior); - - // root process opens output file and writes out data - if (parthenon::Globals::my_rank == 0) { - std::string fname; - fname.assign(pin->GetString("parthenon/job", "problem_id")); - fname.append("-solu1.dat"); - static FILE *pfile = NULL; - - // The file exists -- reopen the file in append mode - if (pfile == NULL) { - if ((pfile = std::fopen(fname.c_str(), "r")) != nullptr) { - if ((pfile = std::freopen(fname.c_str(), "a", pfile)) == nullptr) { - PARTHENON_FAIL("Error output file could not be opened"); - } - // The file does not exist -- open the file in write mode and add headers - } else { - if ((pfile = std::fopen(fname.c_str(), "w")) == nullptr) { - PARTHENON_FAIL("Error output file could not be opened"); - } - std::fprintf(pfile, "# time vel-g vel-ge vel-d1 vel-d1e vel-d2 vel-d2e \n"); - } - } - - // analytic solution - Real v_com, c1_g, c2_g, lam1, lam2, c1_d1, c2_d1, c1_d2, c2_d2; - Real v_g, v_d1, v_d2; - if (dcv.prob_flag == 1) { - v_com = 7. / 6.; - c1_g = -0.35610569612832; - c2_g = 0.18943902946166; - lam1 = -141.742430504416, lam2 = -1058.25756949558; - c1_d1 = 0.85310244713865; - c2_d1 = -0.01976911380532; - c1_d2 = -0.49699675101033; - c2_d2 = -0.16966991565634; - } else { - v_com = 0.63963963963963; - c1_g = -0.06458203330249; - c2_g = 0.42494239366285; - lam1 = -0.52370200744224; - lam2 = -105.976297992557; - c1_d1 = 1.36237475791577; - c2_d1 = -0.00201439755542; - c1_d2 = -0.13559165545855; - c2_d2 = -0.00404798418109; - } - - v_g = v_com + c1_g * std::exp(lam1 * tm.time) + c2_g * std::exp(lam2 * tm.time); - v_d1 = v_com + c1_d1 * std::exp(lam1 * tm.time) + c2_d1 * std::exp(lam2 * tm.time); - v_d2 = v_com + c1_d2 * std::exp(lam1 * tm.time) + c2_d2 * std::exp(lam2 * tm.time); - - // write data - - ParArray1D vel("outdat", 3); - - Real vg0 = 0.0, vd10 = 0.0, vd20 = 0.0; - pmb->par_for( - "out_dustCollision", kb.s, kb.e, jb.s, jb.e, ib.s, ib.s, - KOKKOS_LAMBDA(const int k, const int j, const int i) { - vel(0) = v(0, gas::prim::velocity(0), k, j, i); - vel(1) = v(0, dust::prim::velocity(0), k, j, i); - vel(2) = v(0, dust::prim::velocity(3), k, j, i); - }); - - auto dat = Kokkos::create_mirror_view_and_copy(parthenon::HostMemSpace(), vel); - vg0 = dat(0); - vd10 = dat(1); - vd20 = dat(2); - - std::fprintf(pfile, " %e ", tm.time); - std::fprintf(pfile, " %e ", vg0); - std::fprintf(pfile, " %e ", v_g); - std::fprintf(pfile, " %e ", vd10); - std::fprintf(pfile, " %e ", v_d1); - std::fprintf(pfile, " %e ", vd20); - std::fprintf(pfile, " %e ", v_d2); - - std::fprintf(pfile, "\n"); - // std::fclose(pfile); - } -} - -} // namespace dust_collision - -#endif // PGEN_DUST_COLLISION_HPP_ diff --git a/src/pgen/pgen.hpp b/src/pgen/pgen.hpp index 37228c1..ef69677 100644 --- a/src/pgen/pgen.hpp +++ b/src/pgen/pgen.hpp @@ -24,7 +24,6 @@ #include "constant.hpp" #include "disk.hpp" #include "dust_coagulation.hpp" -#include "dust_collision.hpp" #include "gaussian_bump.hpp" #include "linear_wave.hpp" #include "shock.hpp" @@ -60,8 +59,6 @@ void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin) { strat::ProblemGenerator(pmb, pin); } else if (name == "thermalization") { thermalization::ProblemGenerator(pmb, pin); - } else if (name == "dust_collision") { - dust_collision::ProblemGenerator(pmb, pin); } else if (name == "dust_coagulation") { dust_coagulation::ProblemGenerator(pmb, pin); } else { diff --git a/src/pgen/problem_modifier.hpp b/src/pgen/problem_modifier.hpp index 88f3956..1b93dee 100644 --- a/src/pgen/problem_modifier.hpp +++ b/src/pgen/problem_modifier.hpp @@ -126,8 +126,6 @@ void ProblemModifier(parthenon::ParthenonManager *pman) { strat::ExtrapInnerX3); pman->app_input->RegisterBoundaryCondition(BF::outer_x3, "extrap", strat::ExtrapOuterX3); - } else if (artemis_problem == "dust_collision") { - pman->app_input->PreStepMeshUserWorkInLoop = dust_collision::PreStepUserWorkInLoop; } // Register jaybenne swarm boundary conditions diff --git a/src/utils/units.cpp b/src/utils/units.cpp index 86f26af..92f004a 100644 --- a/src/utils/units.cpp +++ b/src/utils/units.cpp @@ -45,9 +45,11 @@ Units::Units(ParameterInput *pin, std::shared_ptr pkg) { time_ = pin->GetReal("artemis", "time"); mass_ = pin->GetReal("artemis", "mass"); } else if (unit_conversion == "ppd") { - length_ = AU; - mass_ = Msolar; - time_ = Year / (2. * M_PI); + const Real r0_length = pin->GetOrAddReal("artemis", "r0_length", 1.0); // in AU + const Real mstar = pin->GetOrAddReal("artemis", "mstar", 1.0); // M_sun + length_ = r0_length * AU; + mass_ = mstar * Msolar * pin->GetReal("artemis", "rho0"); + time_ = Year / (2. * M_PI) * std::sqrt(r0_length / mstar) * r0_length; } else { PARTHENON_FAIL("Unit conversion not recognized! Choices are [base, ppd]"); } From 0198b3b9fb3df07950a043b0468ca3537cc4ced1 Mon Sep 17 00:00:00 2001 From: Shengtai Li Date: Fri, 3 Jan 2025 16:25:37 -0700 Subject: [PATCH 9/9] new output file name based on problem_id --- inputs/dust/dust_coagulation.in | 32 ++++++++++++++--------------- inputs/dust/dust_coagulation_den.in | 32 ++++++++++++++--------------- src/dust/dust.cpp | 5 ++--- 3 files changed, 32 insertions(+), 37 deletions(-) diff --git a/inputs/dust/dust_coagulation.in b/inputs/dust/dust_coagulation.in index 4ebd23a..151f5ea 100644 --- a/inputs/dust/dust_coagulation.in +++ b/inputs/dust/dust_coagulation.in @@ -15,9 +15,9 @@ problem = dust_coagulation # name of the pgen coordinates = cartesian # coordinate system unit_conversion = ppd # ppd (code unit: AU, Msun, year/(2*pi) -r0_length = 10. # AU +r0_length = 10. # AU mstar = 1.0 # M_sun -rho0 = 2e-5 +rho0 = 2e-5 # prefactor for density profile physical_units = cgs # @@ -47,7 +47,6 @@ ncycle_out = 1 # interval for stdout summary info nghost = 2 refinement = none -# numlevel = 1 nx1 = 16 # Number of zones in X1-direction x1min = 9.0 # minimum value of X1 @@ -78,34 +77,33 @@ dust = true coagulation = true -cfl = 0.9 -gamma = 1.00001 +cfl = 0.9 # gas cfl number +gamma = 1.00001 # adiabatic index iso_sound_speed = 0.05 # code unit -cv = 1e5 # 1/(gamma-1) +cv = 1e5 # code unit: 1/(gamma-1) -cfl = 0.9 -nspecies = 121 -size_input = logspace +cfl = 0.9 # dust cfl number +nspecies = 121 # number of dust size +size_input = logspace # dust size distribution scr_level = 1 # for reconstruction surface_density_flag = true # surface or volume density grain_density = 1.25 # dust internal density g/cc -min_size = 1e-5 #cm -max_size = 10.0 #cm +min_size = 1e-5 #cm +max_size = 10.0 #cm vfrag = 1000.0 #cm/s coag_int = 1 -coag_use_adaptiveStep = false -coag_mom_preserve = false -coag_info_out = true +coag_use_adaptiveStep = false +coag_mom_preserve = false +coag_info_out = true nInit_dust = 11 # number of dust species initially -dust_to_gas = 0.01 -nstep1Coag = 1 -#rho0 = 2e-5 # code unit value of 1 m_star/r0_length^2 +dust_to_gas = 0.01 # init dust-to-gas ratio +nstep1Coag = 10 # number of steps for one coagulation call const_coag_omega = true # using omega at r0_length diff --git a/inputs/dust/dust_coagulation_den.in b/inputs/dust/dust_coagulation_den.in index c1bb60a..91684e5 100644 --- a/inputs/dust/dust_coagulation_den.in +++ b/inputs/dust/dust_coagulation_den.in @@ -15,9 +15,9 @@ problem = dust_coagulation # name of the pgen coordinates = cartesian # coordinate system unit_conversion = ppd # ppd (code unit: AU, Msun, year/(2*pi) -r0_length = 10. # AU +r0_length = 10. # AU mstar = 1.0 # M_sun -rho0 = 1.59577e-4 # 3D rho (mstar/r0^3) +rho0 = 1.59577e-4 # prefactor for 3D density profile physical_units = cgs # @@ -47,7 +47,6 @@ ncycle_out = 1 # interval for stdout summary info nghost = 2 refinement = none -# numlevel = 1 nx1 = 16 # Number of zones in X1-direction x1min = 9.0 # minimum value of X1 @@ -78,34 +77,33 @@ dust = true coagulation = true -cfl = 0.9 -gamma = 1.00001 +cfl = 0.9 # gas cfl number +gamma = 1.00001 # adiabatic index iso_sound_speed = 0.05 # code unit -cv = 1e5 # 1/(gamma-1) +cv = 1e5 # code unit: 1/(gamma-1) -cfl = 0.9 -nspecies = 121 -size_input = logspace +cfl = 0.9 # dust cfl number +nspecies = 121 # number of dust size +size_input = logspace # dust size distribution scr_level = 1 # for reconstruction surface_density_flag = false # surface or volume density grain_density = 1.25 # dust internal density g/cc -min_size = 1e-5 #cm -max_size = 10.0 #cm +min_size = 1e-5 #cm +max_size = 10.0 #cm vfrag = 1000.0 #cm/s coag_int = 1 -coag_use_adaptiveStep = false -coag_mom_preserve = false -coag_info_out = true +coag_use_adaptiveStep = false +coag_mom_preserve = false +coag_info_out = true nInit_dust = 11 # number of dust species initially -dust_to_gas = 0.01 -nstep1Coag = 1 -#rho0 = 2e-5 # code unit value of 1 m_star/r0_length^2 +dust_to_gas = 0.01 # init dust-to-gas ratio +nstep1Coag = 10 # number of steps for one coagulation call const_coag_omega = true # using omega at r0_length diff --git a/src/dust/dust.cpp b/src/dust/dust.cpp index d6785c0..84bf8a2 100644 --- a/src/dust/dust.cpp +++ b/src/dust/dust.cpp @@ -568,9 +568,8 @@ TaskStatus CoagulationOneStep(MeshData *md, const Real time, const Real dt if (parthenon::Globals::my_rank == 0) { std::string fname; - // fname.assign(pin->GetString("parthenon/job", "problem_id")); - fname = "artemis"; - fname.append("_coag_info.dat"); + fname.assign(artemis_pkg->template Param("job_name")); + fname.append("_info.dat"); static FILE *pfile = NULL; // The file exists -- reopen the file in append mode