1 #ifndef SUPERDROPLET_PC_H_
2 #define SUPERDROPLET_PC_H_
4 #ifdef ERF_USE_PARTICLES
11 #include <AMReX_StructOfArrays.H>
14 enum class IceCategory {
Ice, Snow, Graupel, Total };
19 class SuperDropletPC :
public ERFPC
21 using MFPtr = std::unique_ptr<amrex::MultiFab>;
22 using BCTypeArr = amrex::GpuArray<ERF_BC, AMREX_SPACEDIM*2>;
27 SuperDropletPC ( amrex::ParGDBBase* a_gdb,
28 const std::vector<Species::Name>& a_species_mat,
29 const std::vector<Species::Name>& a_aerosol_mat,
31 const std::string& a_name =
"super_droplets" )
32 : ERFPC (a_gdb, a_name, ERFPCOptions{ false, true })
34 define( a_species_mat,
36 a_gdb->ParticleBoxArray(0),
37 a_gdb->ParticleDistributionMap(0),
42 SuperDropletPC (
const amrex::Geometry& a_geom,
43 const amrex::DistributionMapping& a_dmap,
44 const amrex::BoxArray& a_ba,
45 const std::vector<Species::Name>& a_species_mat,
46 const std::vector<Species::Name>& a_aerosol_mat,
48 const std::string& a_name =
"super_droplets" )
49 : ERFPC (a_geom, a_dmap, a_ba, a_name, ERFPCOptions{ false, true })
51 define(a_species_mat, a_aerosol_mat, a_ba, a_dmap, a_dt);
57 if (m_mass_change_logging) {
58 fclose(m_mass_change_log);
64 virtual void setSpeciesMaterial (
const Species::Name& a_name )
66 if (a_name == Species::Name::H2O) { m_idx_w = m_species_mat.size(); }
67 if (a_name == Species::Name::ice) { m_idx_i = m_species_mat.size(); }
68 m_species_mat.push_back(std::make_unique<MaterialProperties>(a_name));
69 m_device_props_initialized =
false;
74 virtual void setSpeciesMaterial (
const std::vector<Species::Name>& a_names )
76 for (
auto&
name : a_names) { setSpeciesMaterial(
name); }
81 virtual const MaterialProperties& getSpeciesMaterial (
const Species::Name& a_name)
const
83 for (
auto& species : m_species_mat) {
84 if (species->m_name == a_name) {
return *species; }
86 amrex::Abort(
"SuperDropletPC::getSpeciesMaterial() - species not found");
87 return *m_species_mat[0];
93 virtual void setAerosolMaterial (
const Species::Name& a_name )
95 m_aerosol_mat.push_back(std::make_unique<MaterialProperties>(a_name));
96 m_device_props_initialized =
false;
101 virtual void setAerosolMaterial (
const std::vector<Species::Name>& a_names )
103 for (
auto&
name : a_names) { setAerosolMaterial(
name); }
107 void updateDeviceProperties ();
110 template<
typename SOAType>
111 void setupMassPointers (SOAType& soa, SDPCDefn::SDSpeciesMassArr& sp_mass_ptrs,
112 SDPCDefn::SDAerosolMassArr& ae_mass_ptrs)
const
115 sp_mass_ptrs[i] = soa.GetRealData(idx_s(i, m_num_aerosols,
m_num_species)).data();
117 for (
int i = 0; i < m_num_aerosols; i++) {
118 ae_mass_ptrs[i] = soa.GetRealData(idx_a(i, m_num_aerosols,
m_num_species)).data();
123 AMREX_GPU_DEVICE AMREX_FORCE_INLINE
124 static void updateParticleAttributes (
126 amrex::ParticleReal* radius_ptr,
127 amrex::ParticleReal* mass_ptr,
129 amrex::ParticleReal rho_w,
130 int num_sp,
int num_ae,
131 const int* sp_sol_arr,
132 const int* ae_sol_arr,
133 const SDPCDefn::SDSpeciesMassArr sp_mass_ptrs,
134 const SDPCDefn::SDAerosolMassArr ae_mass_ptrs,
135 const amrex::ParticleReal* sp_rho_arr,
136 const amrex::ParticleReal* ae_rho_arr)
139 radius_ptr[particle_idx] = SD_effective_radius(
140 particle_idx, idx_w, rho_w,
142 sp_sol_arr, ae_sol_arr,
143 sp_mass_ptrs, ae_mass_ptrs,
144 sp_rho_arr, ae_rho_arr);
147 mass_ptr[particle_idx] = SD_total_mass(
148 particle_idx, num_sp, num_ae,
149 sp_mass_ptrs, ae_mass_ptrs);
153 [[nodiscard]]
virtual amrex::Vector<std::string> varNames ()
const override;
156 [[nodiscard]]
virtual amrex::Vector<std::string> meshPlotVarNames ()
const override;
159 virtual void computeMeshVar (
const std::string&,
161 const amrex::MultiFab&,
162 const int )
const override;
165 void InitializeParticles (
const int a_lev,
const double a_t,
const MFPtr& a_ptr);
167 using ERFPC::InitializeParticles;
170 virtual void InjectParticles (
const double,
const MFPtr& a_ptr,
const double);
174 bool composite_init =
false );
177 void setNumSDBoxDistribution (
int a_lev,
181 const amrex::RealBox&,
185 void setNumSDPerBox (
int a_lev,
188 const amrex::RealBox&,
189 const unsigned int );
192 void setNumSDBubbleDistribution (
int a_lev,
196 const amrex::RealBox&,
202 virtual void SetAttributes ( amrex::MultiFab& a_mf,
int a_lev = 0 );
207 virtual void DensityScaling (
const amrex::MultiFab& a_mf,
int a_lev = 0 );
210 virtual void EvolveParticles (
int,
212 amrex::Vector<amrex::Vector<amrex::MultiFab>>&,
213 const amrex::Vector<MFPtr>& )
override
215 amrex::Abort(
"SuperDropletPC::EvolveParticles() is intentionally disabled.");
230 virtual void AdvectParticles (
int a_lev,
233 const amrex::MultiFab*
const a_flow_vel,
234 const amrex::MultiFab& a_density,
235 const amrex::MultiFab& a_pressure,
236 const amrex::MultiFab& a_temperature,
237 const amrex::Vector<MFPtr>& a_z_phys_nd,
238 const BCTypeArr& a_bctypes,
239 const bool a_recycle);
242 virtual void MassChange_LV (
int,
244 const Species::Name&,
245 const amrex::MultiFab&,
246 const amrex::MultiFab&,
247 const amrex::MultiFab&,
248 const amrex::MultiFab&,
249 const amrex::Vector<MFPtr>&,
253 virtual void MassChange_SL (
int,
255 const amrex::MultiFab&,
256 const amrex::MultiFab&,
257 const amrex::MultiFab&,
258 const amrex::Vector<MFPtr>& );
261 virtual void MassChange_SV (
int,
263 const amrex::MultiFab&,
264 const amrex::MultiFab&,
265 const amrex::MultiFab&,
266 const amrex::MultiFab&,
267 const amrex::MultiFab&,
268 const amrex::MultiFab&,
269 const amrex::MultiFab&,
270 const amrex::Vector<MFPtr>& );
273 virtual void Coalescence (
int,
275 const amrex::MultiFab&,
276 const amrex::MultiFab&,
277 const amrex::MultiFab&,
278 const amrex::MultiFab&,
279 const amrex::Vector<MFPtr>& );
288 virtual void Recycle (
const int a_lev,
289 const amrex::Vector<MFPtr>& a_z_phys_nd,
292 const bool a_recycle);
297 void placeRecycledParticles (
const amrex::Vector<MFPtr>& a_z_phys_nd );
301 [[nodiscard]]
inline virtual amrex::Long NumSuperDroplets ()
303 return ERFPC::TotalNumberOfParticles();
307 [[nodiscard]]
virtual amrex::Real TotalNumberOfParticles ();
310 [[nodiscard]]
virtual amrex::Long NumSDDeactivated ();
313 virtual void Diagnostics (
int,
int,
double,
bool);
315 virtual void ComputeDistributions (
int,
int,
317 amrex::ParticleReal );
318 #ifdef ERF_USE_ML_UPHYS_DIAGNOSTICS
320 virtual void ComputeBinnedDistributions (
int,
int );
322 virtual void ComputeBinnedDistributionsCell (
int,
int,
amrex::Real );
326 virtual void SDNumberDensity ( amrex::MultiFab&,
const amrex::MultiFab& a_z_phys_nd,
int a_lev,
const int a_comp=0 )
const;
328 virtual void numberDensity ( amrex::MultiFab&,
const amrex::MultiFab& a_z_phys_nd,
int a_lev,
const int a_comp=0 )
const;
330 virtual void massDensity ( amrex::MultiFab&,
const amrex::MultiFab& a_z_phys_nd,
const int& a_lev,
const int& a_comp=0 )
const override;
332 virtual void massFlux ( amrex::MultiFab&,
const amrex::MultiFab& a_z_phys_nd,
int a_lev,
const int,
const int a_comp=0 )
const;
335 virtual void speciesMassDensity ( amrex::MultiFab&,
336 const amrex::MultiFab& a_z_phys_nd,
339 const int a_comp = 0)
const;
342 virtual void cloudRainDensity ( amrex::MultiFab&,
343 const amrex::MultiFab& a_z_phys_nd,
347 const int a_comp = 0)
const;
350 virtual void iceCategoryDensity ( amrex::MultiFab&,
const amrex::MultiFab& a_z_phys_nd,
352 const int a_comp = 0)
const;
355 virtual void iceDensity ( amrex::MultiFab&,
const amrex::MultiFab& a_z_phys_nd,
356 int a_lev,
amrex::Real,
const int a_comp = 0)
const;
359 virtual void snowDensity ( amrex::MultiFab&,
const amrex::MultiFab& a_z_phys_nd,
360 int a_lev,
amrex::Real,
const int a_comp = 0)
const;
363 virtual void graupelDensity ( amrex::MultiFab&,
const amrex::MultiFab& a_z_phys_nd,
364 int a_lev,
amrex::Real,
const int a_comp = 0)
const;
367 virtual void totalIceDensity ( amrex::MultiFab&,
const amrex::MultiFab& a_z_phys_nd,
368 int a_lev,
const int a_comp = 0)
const;
371 virtual void speciesMassFlux ( amrex::MultiFab&,
const amrex::MultiFab& a_z_phys_nd,
int a_lev,
const int,
const int,
const int a_comp=0 )
const;
374 virtual void aerosolMassDensity ( amrex::MultiFab&,
const amrex::MultiFab& a_z_phys_nd,
int a_lev,
const int,
const int a_comp=0 )
const;
376 virtual void aerosolMassFlux ( amrex::MultiFab&,
const amrex::MultiFab& a_z_phys_nd,
int a_lev,
const int,
const int,
const int a_comp=0 )
const;
379 virtual void effectiveRadius ( amrex::MultiFab&,
const amrex::MultiFab& a_z_phys_nd,
int a_lev,
const int a_comp=0 )
const;
382 virtual void applyBoundaryTreatment (
int,
const amrex::Vector<MFPtr>&,
const BCTypeArr&,
const bool );
389 void SplitParticlesForRefinement (
int a_finest_level )
override;
395 void SplitMergeAtLevelBoundary ()
override;
400 void MergeParticlesAtDerefinement (
int a_lev,
401 const amrex::BoxArray& a_old_fine_ba,
402 const amrex::IntVect& a_ref_ratio )
override;
405 bool splitMergeAMR ()
const {
return m_split_merge_amr; }
409 SDCoalescenceKernelType m_coalescence_kernel;
411 bool m_include_brownian_coalescence;
412 SDKernelRelativeVelocityType m_kernel_relative_velocity;
414 SDTerminalVelocityType m_term_vel_type_w;
415 SDTerminalVelocityType m_term_vel_type_i;
417 int m_num_sd_per_cell;
418 bool m_density_scaling;
419 bool m_nucleate_particles;
420 bool m_prescribed_advection;
422 bool m_split_merge_amr =
false;
425 std::vector<std::unique_ptr<MaterialProperties>> m_species_mat;
427 std::vector<std::unique_ptr<MaterialProperties>> m_aerosol_mat;
436 bool m_mass_change_logging;
437 FILE* m_mass_change_log;
438 std::string m_mass_change_log_fname;
441 SDMassChangeTIMethod m_mass_change_ti;
442 long m_num_unconverged_particles;
445 bool m_mass_change_ventilation;
452 amrex::IntVect m_coalescence_bin_size;
454 int m_distribution_grid_size;
456 amrex::MultiFab m_mf_buf;
458 #ifdef ERF_USE_ML_UPHYS_DIAGNOSTICS
463 amrex::MultiFab m_mass_ln_R_mf;
465 amrex::MultiFab m_num_ln_R_mf;
472 int m_num_initializations = 1;
474 std::vector< std::unique_ptr<SDInitialization> > m_initializations;
477 int m_num_injections = 0;
479 std::vector< std::unique_ptr<SDInjection> > m_injections;
485 bool m_place_randomly_in_cells;
488 std::mt19937 m_rndeng;
500 bool m_save_inactive;
503 amrex::Gpu::DeviceVector<amrex::ParticleReal> m_sp_density;
504 amrex::Gpu::DeviceVector<int> m_sp_solubility;
505 amrex::Gpu::DeviceVector<amrex::ParticleReal> m_sp_ionization;
506 amrex::Gpu::DeviceVector<amrex::ParticleReal> m_sp_mol_weight;
507 amrex::Gpu::DeviceVector<int> m_sp_is_INP;
509 amrex::Gpu::DeviceVector<amrex::ParticleReal> m_ae_density;
510 amrex::Gpu::DeviceVector<int> m_ae_solubility;
511 amrex::Gpu::DeviceVector<amrex::ParticleReal> m_ae_ionization;
512 amrex::Gpu::DeviceVector<amrex::ParticleReal> m_ae_mol_weight;
513 amrex::Gpu::DeviceVector<int> m_ae_is_INP;
516 bool m_device_props_initialized =
false;
527 void initializeDeviceProperties ();
530 SDProcess::ProcessContext buildProcessContext (
int a_lev)
const
532 SDProcess::ProcessContext ctx;
533 const amrex::Geometry& geom = m_gdb->Geom(a_lev);
534 ctx.plo = geom.ProbLoArray();
535 ctx.phi = geom.ProbHiArray();
536 ctx.dxi = geom.InvCellSizeArray();
537 ctx.dx = geom.CellSizeArray();
538 ctx.domain = geom.Domain();
539 for (
int d = 0; d < AMREX_SPACEDIM; d++) {
540 ctx.is_periodic[d] = geom.isPeriodic(d) ? 1 : 0;
542 const auto cell_size = geom.CellSize();
543 ctx.cell_volume = AMREX_D_TERM(cell_size[0], *cell_size[1], *cell_size[2]);
545 ctx.num_aerosols = m_num_aerosols;
546 ctx.idx_water = m_idx_w;
547 ctx.idx_ice = m_idx_i;
548 ctx.rho_water = m_species_mat[m_idx_w]->m_density;
550 ctx.rho_ice = m_species_mat[m_idx_i]->m_density;
556 template<
typename SOAType,
typename AOSType>
557 void setupParticlePointers (
560 SDProcess::ParticlePointers& ptrs)
const
562 using namespace SDPCDefn;
564 constexpr
int rtoff_i = SuperDropletsIntIdx::ncomps;
565 constexpr
int rtoff_r = SuperDropletsRealIdx::ncomps;
567 ptrs.num_particles = aos.numParticles();
568 ptrs.mass_ptr = soa.GetRealData(SuperDropletsRealIdx::mass).data();
569 ptrs.radius_ptr = soa.GetRealData(rtoff_r + SuperDropletsRealIdxSoA_RT::radius).data();
570 ptrs.active_ptr = soa.GetIntData(rtoff_i + SuperDropletsIntIdxSoA_RT::active).data();
571 ptrs.v_ptr[0] = soa.GetRealData(SuperDropletsRealIdx::vx).data();
572 ptrs.v_ptr[1] = soa.GetRealData(SuperDropletsRealIdx::vy).data();
573 ptrs.v_ptr[2] = soa.GetRealData(SuperDropletsRealIdx::vz).data();
574 ptrs.vterm_ptr = soa.GetRealData(rtoff_r + SuperDropletsRealIdxSoA_RT::term_vel).data();
575 ptrs.mult_ptr = soa.GetRealData(rtoff_r + SuperDropletsRealIdxSoA_RT::multiplicity).data();
577 ptrs.Tfz_ptr = soa.GetRealData(idx_ice_Tfz(m_num_aerosols,
m_num_species)).data();
578 ptrs.a_ptr = soa.GetRealData(idx_ice_a(m_num_aerosols,
m_num_species)).data();
579 ptrs.c_ptr = soa.GetRealData(idx_ice_c(m_num_aerosols,
m_num_species)).data();
580 ptrs.mrime_ptr = soa.GetRealData(idx_ice_mrime(m_num_aerosols,
m_num_species)).data();
581 ptrs.nmono_ptr = soa.GetRealData(idx_ice_nmono(m_num_aerosols,
m_num_species)).data();
582 setupMassPointers(soa, ptrs.sp_mass_ptrs, ptrs.ae_mass_ptrs);
583 if (!m_device_props_initialized) {
584 const_cast<SuperDropletPC*
>(
this)->initializeDeviceProperties();
586 ptrs.sp_rho_arr = m_sp_density.data();
587 ptrs.sp_sol_arr = m_sp_solubility.data();
588 ptrs.sp_ion_arr = m_sp_ionization.data();
589 ptrs.sp_mw_arr = m_sp_mol_weight.data();
590 ptrs.sp_INP_arr = m_sp_is_INP.data();
591 ptrs.ae_rho_arr = m_ae_density.data();
592 ptrs.ae_sol_arr = m_ae_solubility.data();
593 ptrs.ae_ion_arr = m_ae_ionization.data();
594 ptrs.ae_mw_arr = m_ae_mol_weight.data();
595 ptrs.ae_INP_arr = m_ae_is_INP.data();
599 template<
typename TileFunc>
600 void forEachParticleTileBody (
601 ParIterType& pti,
int a_lev,
602 const SDProcess::ProcessContext& ctx,
605 int grid = pti.index();
606 auto& ptile = ParticlesAt(a_lev, pti);
607 auto& aos = ptile.GetArrayOfStructs();
608 auto& soa = ptile.GetStructOfArrays();
609 if (aos.numParticles() == 0) {
return; }
610 auto* p_pbox = aos().data();
611 SDProcess::ParticlePointers ptrs;
612 setupParticlePointers(soa, aos, ptrs);
613 func(pti, grid, p_pbox, ptrs, ctx);
617 template<
typename TileFunc>
619 void forEachParticleTile (
621 const SDProcess::ProcessContext& ctx,
625 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
627 for (ParIterType pti(*
this, a_lev); pti.isValid(); ++pti) {
628 forEachParticleTileBody(pti, a_lev, ctx, std::forward<TileFunc>(func));
635 template<
typename TileFunc>
637 void forEachParticleTileSerial (
int a_lev,
const SDProcess::ProcessContext& ctx, TileFunc&& func)
639 for (ParIterType pti(*
this, a_lev); pti.isValid(); ++pti) {
640 forEachParticleTileBody(pti, a_lev, ctx, std::forward<TileFunc>(func));
645 template<
typename TileFunc>
646 void forEachParticleTile (
int a_lev, TileFunc&& func)
649 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
651 for (ParIterType pti(*
this, a_lev); pti.isValid(); ++pti) {
652 int grid = pti.index();
653 auto& ptile = ParticlesAt(a_lev, pti);
654 auto& aos = ptile.GetArrayOfStructs();
655 auto& soa = ptile.GetStructOfArrays();
656 const int num_particles = aos.numParticles();
657 if (num_particles == 0) {
continue; }
658 auto* p_pbox = aos().data();
659 SDProcess::ParticlePointers ptrs;
660 setupParticlePointers(soa, aos, ptrs);
661 func(pti, grid, p_pbox, ptrs, num_particles);
666 virtual void readInputs ()
override
668 amrex::Abort(
"SuperDropletPC::readInputs(): Do not use this interface.");
672 virtual void readInputs (
const double);
675 void initializeParticlesNull (
const MFPtr&) { }
680 void define (
const std::vector<Species::Name>&,
681 const std::vector<Species::Name>&,
682 const amrex::BoxArray&,
683 const amrex::DistributionMapping&,
687 void add_superdroplet_attributes ();
int m_num_species
Definition: ERF_InitCustomPert_MultiSpeciesBubble.H:32
Dimensionless numeric literals and pure mathematical constants.
std::string name
Definition: ERF_Plotfile2DCatalog.cpp:116
amrex::Real Real
Definition: ERF_ShocInterface.H:19
Common data structures for SuperDroplet physical processes.
Super-droplets initial properties.
Definition: ERF_SDInitialization.H:223
Definition: ERF_MaterialProperties.H:178