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);
176 void setNumSDBoxDistribution(
int a_lev,
180 const amrex::RealBox&,
184 void setNumSDPerBox(
int a_lev,
187 const amrex::RealBox&,
188 const unsigned int );
191 void setNumSDBubbleDistribution(
int a_lev,
195 const amrex::RealBox&,
201 virtual void SetAttributes ( amrex::MultiFab& a_mf );
206 virtual void DensityScaling (
const amrex::MultiFab& a_mf );
209 virtual void EvolveParticles (
int,
211 amrex::Vector<amrex::Vector<amrex::MultiFab>>&,
212 const amrex::Vector<MFPtr>& )
override
214 amrex::Abort(
"SuperDropletPC::EvolveParticles() is intentionally disabled.");
229 virtual void AdvectParticles (
int a_lev,
232 const amrex::MultiFab*
const a_flow_vel,
233 const amrex::MultiFab& a_density,
234 const amrex::MultiFab& a_pressure,
235 const amrex::MultiFab& a_temperature,
236 const amrex::Vector<MFPtr>& a_z_phys_nd,
237 const BCTypeArr& a_bctypes,
238 const bool a_recycle);
241 virtual void MassChange_LV (
int,
243 const Species::Name&,
244 const amrex::MultiFab&,
245 const amrex::MultiFab&,
246 const amrex::MultiFab&,
247 const amrex::MultiFab&,
248 const amrex::Vector<MFPtr>&,
252 virtual void MassChange_SL (
int,
254 const amrex::MultiFab&,
255 const amrex::MultiFab&,
256 const amrex::MultiFab&,
257 const amrex::Vector<MFPtr>& );
260 virtual void MassChange_SV (
int,
262 const amrex::MultiFab&,
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::Vector<MFPtr>& );
272 virtual void Coalescence (
int,
274 const amrex::MultiFab&,
275 const amrex::MultiFab&,
276 const amrex::MultiFab&,
277 const amrex::MultiFab&,
278 const amrex::Vector<MFPtr>& );
287 virtual void Recycle (
const int a_lev,
288 const amrex::Vector<MFPtr>& a_z_phys_nd,
291 const bool a_recycle);
295 [[nodiscard]]
inline virtual amrex::Long NumSuperDroplets ()
297 return ERFPC::TotalNumberOfParticles();
301 [[nodiscard]]
virtual amrex::Real TotalNumberOfParticles ();
304 [[nodiscard]]
virtual amrex::Long NumSDDeactivated ();
307 virtual void Diagnostics (
int,
int,
double,
bool);
309 virtual void ComputeDistributions (
int,
int,
311 amrex::ParticleReal );
312 #ifdef ERF_USE_ML_UPHYS_DIAGNOSTICS
314 virtual void ComputeBinnedDistributions (
int,
int );
316 virtual void ComputeBinnedDistributionsCell (
int,
int,
amrex::Real );
320 virtual void SDNumberDensity ( amrex::MultiFab&,
const amrex::MultiFab& a_z_phys_nd,
int a_lev,
const int a_comp=0 )
const;
322 virtual void numberDensity ( amrex::MultiFab&,
const amrex::MultiFab& a_z_phys_nd,
int a_lev,
const int a_comp=0 )
const;
324 virtual void massDensity ( amrex::MultiFab&,
const amrex::MultiFab& a_z_phys_nd,
const int& a_lev,
const int& a_comp=0 )
const override;
326 virtual void massFlux ( amrex::MultiFab&,
const amrex::MultiFab& a_z_phys_nd,
int a_lev,
const int,
const int a_comp=0 )
const;
329 virtual void speciesMassDensity ( amrex::MultiFab&,
330 const amrex::MultiFab& a_z_phys_nd,
333 const int a_comp = 0)
const;
336 virtual void cloudRainDensity ( amrex::MultiFab&,
337 const amrex::MultiFab& a_z_phys_nd,
341 const int a_comp = 0)
const;
344 virtual void iceCategoryDensity ( amrex::MultiFab&,
const amrex::MultiFab& a_z_phys_nd,
346 const int a_comp = 0)
const;
349 virtual void iceDensity ( amrex::MultiFab&,
const amrex::MultiFab& a_z_phys_nd,
350 int a_lev,
amrex::Real,
const int a_comp = 0)
const;
353 virtual void snowDensity ( amrex::MultiFab&,
const amrex::MultiFab& a_z_phys_nd,
354 int a_lev,
amrex::Real,
const int a_comp = 0)
const;
357 virtual void graupelDensity ( amrex::MultiFab&,
const amrex::MultiFab& a_z_phys_nd,
358 int a_lev,
amrex::Real,
const int a_comp = 0)
const;
361 virtual void totalIceDensity ( amrex::MultiFab&,
const amrex::MultiFab& a_z_phys_nd,
362 int a_lev,
const int a_comp = 0)
const;
365 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;
368 virtual void aerosolMassDensity ( amrex::MultiFab&,
const amrex::MultiFab& a_z_phys_nd,
int a_lev,
const int,
const int a_comp=0 )
const;
370 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;
373 virtual void effectiveRadius ( amrex::MultiFab&,
const amrex::MultiFab& a_z_phys_nd,
int a_lev,
const int a_comp=0 )
const;
376 virtual void applyBoundaryTreatment (
int,
const amrex::Vector<MFPtr>&,
const BCTypeArr&,
const bool );
383 void SplitParticlesForRefinement (
int a_finest_level )
override;
389 void SplitMergeAtLevelBoundary ()
override;
394 void MergeParticlesAtDerefinement (
int a_lev,
395 const amrex::BoxArray& a_old_fine_ba,
396 const amrex::IntVect& a_ref_ratio )
override;
399 bool splitMergeAMR ()
const {
return m_split_merge_amr; }
403 SDCoalescenceKernelType m_coalescence_kernel;
405 bool m_include_brownian_coalescence;
406 SDKernelRelativeVelocityType m_kernel_relative_velocity;
408 SDTerminalVelocityType m_term_vel_type_w;
409 SDTerminalVelocityType m_term_vel_type_i;
411 int m_num_sd_per_cell;
412 bool m_density_scaling;
413 bool m_nucleate_particles;
414 bool m_prescribed_advection;
416 bool m_split_merge_amr =
false;
419 std::vector<std::unique_ptr<MaterialProperties>> m_species_mat;
421 std::vector<std::unique_ptr<MaterialProperties>> m_aerosol_mat;
430 bool m_mass_change_logging;
431 FILE* m_mass_change_log;
432 std::string m_mass_change_log_fname;
435 SDMassChangeTIMethod m_mass_change_ti;
436 long m_num_unconverged_particles;
439 bool m_mass_change_ventilation;
446 amrex::IntVect m_coalescence_bin_size;
448 int m_distribution_grid_size;
450 amrex::MultiFab m_mf_buf;
452 #ifdef ERF_USE_ML_UPHYS_DIAGNOSTICS
457 amrex::MultiFab m_mass_ln_R_mf;
459 amrex::MultiFab m_num_ln_R_mf;
466 int m_num_initializations = 1;
468 std::vector< std::unique_ptr<SDInitialization> > m_initializations;
471 int m_num_injections = 0;
473 std::vector< std::unique_ptr<SDInjection> > m_injections;
479 bool m_place_randomly_in_cells;
482 std::mt19937 m_rndeng;
494 bool m_save_inactive;
497 amrex::Gpu::DeviceVector<amrex::ParticleReal> m_sp_density;
498 amrex::Gpu::DeviceVector<int> m_sp_solubility;
499 amrex::Gpu::DeviceVector<amrex::ParticleReal> m_sp_ionization;
500 amrex::Gpu::DeviceVector<amrex::ParticleReal> m_sp_mol_weight;
501 amrex::Gpu::DeviceVector<int> m_sp_is_INP;
503 amrex::Gpu::DeviceVector<amrex::ParticleReal> m_ae_density;
504 amrex::Gpu::DeviceVector<int> m_ae_solubility;
505 amrex::Gpu::DeviceVector<amrex::ParticleReal> m_ae_ionization;
506 amrex::Gpu::DeviceVector<amrex::ParticleReal> m_ae_mol_weight;
507 amrex::Gpu::DeviceVector<int> m_ae_is_INP;
510 bool m_device_props_initialized =
false;
521 void initializeDeviceProperties();
524 SDProcess::ProcessContext buildProcessContext(
int a_lev)
const
526 SDProcess::ProcessContext ctx;
527 const amrex::Geometry& geom = m_gdb->Geom(a_lev);
528 ctx.plo = geom.ProbLoArray();
529 ctx.phi = geom.ProbHiArray();
530 ctx.dxi = geom.InvCellSizeArray();
531 ctx.dx = geom.CellSizeArray();
532 ctx.domain = geom.Domain();
533 for (
int d = 0; d < AMREX_SPACEDIM; d++) {
534 ctx.is_periodic[d] = geom.isPeriodic(d) ? 1 : 0;
536 const auto cell_size = geom.CellSize();
537 ctx.cell_volume = AMREX_D_TERM(cell_size[0], *cell_size[1], *cell_size[2]);
539 ctx.num_aerosols = m_num_aerosols;
540 ctx.idx_water = m_idx_w;
541 ctx.idx_ice = m_idx_i;
542 ctx.rho_water = m_species_mat[m_idx_w]->m_density;
544 ctx.rho_ice = m_species_mat[m_idx_i]->m_density;
550 template<
typename SOAType,
typename AOSType>
551 void setupParticlePointers(
554 SDProcess::ParticlePointers& ptrs)
const
556 using namespace SDPCDefn;
558 constexpr
int rtoff_i = SuperDropletsIntIdx::ncomps;
559 constexpr
int rtoff_r = SuperDropletsRealIdx::ncomps;
561 ptrs.num_particles = aos.numParticles();
562 ptrs.mass_ptr = soa.GetRealData(SuperDropletsRealIdx::mass).data();
563 ptrs.radius_ptr = soa.GetRealData(rtoff_r + SuperDropletsRealIdxSoA_RT::radius).data();
564 ptrs.active_ptr = soa.GetIntData(rtoff_i + SuperDropletsIntIdxSoA_RT::active).data();
565 ptrs.v_ptr[0] = soa.GetRealData(SuperDropletsRealIdx::vx).data();
566 ptrs.v_ptr[1] = soa.GetRealData(SuperDropletsRealIdx::vy).data();
567 ptrs.v_ptr[2] = soa.GetRealData(SuperDropletsRealIdx::vz).data();
568 ptrs.vterm_ptr = soa.GetRealData(rtoff_r + SuperDropletsRealIdxSoA_RT::term_vel).data();
569 ptrs.mult_ptr = soa.GetRealData(rtoff_r + SuperDropletsRealIdxSoA_RT::multiplicity).data();
571 ptrs.Tfz_ptr = soa.GetRealData(idx_ice_Tfz(m_num_aerosols,
m_num_species)).data();
572 ptrs.a_ptr = soa.GetRealData(idx_ice_a(m_num_aerosols,
m_num_species)).data();
573 ptrs.c_ptr = soa.GetRealData(idx_ice_c(m_num_aerosols,
m_num_species)).data();
574 ptrs.mrime_ptr = soa.GetRealData(idx_ice_mrime(m_num_aerosols,
m_num_species)).data();
575 ptrs.nmono_ptr = soa.GetRealData(idx_ice_nmono(m_num_aerosols,
m_num_species)).data();
576 setupMassPointers(soa, ptrs.sp_mass_ptrs, ptrs.ae_mass_ptrs);
577 if (!m_device_props_initialized) {
578 const_cast<SuperDropletPC*
>(
this)->initializeDeviceProperties();
580 ptrs.sp_rho_arr = m_sp_density.data();
581 ptrs.sp_sol_arr = m_sp_solubility.data();
582 ptrs.sp_ion_arr = m_sp_ionization.data();
583 ptrs.sp_mw_arr = m_sp_mol_weight.data();
584 ptrs.sp_INP_arr = m_sp_is_INP.data();
585 ptrs.ae_rho_arr = m_ae_density.data();
586 ptrs.ae_sol_arr = m_ae_solubility.data();
587 ptrs.ae_ion_arr = m_ae_ionization.data();
588 ptrs.ae_mw_arr = m_ae_mol_weight.data();
589 ptrs.ae_INP_arr = m_ae_is_INP.data();
593 template<
typename TileFunc>
594 void forEachParticleTileBody(
595 ParIterType& pti,
int a_lev,
596 const SDProcess::ProcessContext& ctx,
599 int grid = pti.index();
600 auto& ptile = ParticlesAt(a_lev, pti);
601 auto& aos = ptile.GetArrayOfStructs();
602 auto& soa = ptile.GetStructOfArrays();
603 if (aos.numParticles() == 0) {
return; }
604 auto* p_pbox = aos().data();
605 SDProcess::ParticlePointers ptrs;
606 setupParticlePointers(soa, aos, ptrs);
607 func(pti, grid, p_pbox, ptrs, ctx);
611 template<
typename TileFunc>
613 void forEachParticleTile(
615 const SDProcess::ProcessContext& ctx,
619 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
621 for (ParIterType pti(*
this, a_lev); pti.isValid(); ++pti) {
622 forEachParticleTileBody(pti, a_lev, ctx, std::forward<TileFunc>(func));
629 template<
typename TileFunc>
631 void forEachParticleTileSerial(
int a_lev,
const SDProcess::ProcessContext& ctx, TileFunc&& func)
633 for (ParIterType pti(*
this, a_lev); pti.isValid(); ++pti) {
634 forEachParticleTileBody(pti, a_lev, ctx, std::forward<TileFunc>(func));
639 template<
typename TileFunc>
640 void forEachParticleTile(
int a_lev, TileFunc&& func)
643 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
645 for (ParIterType pti(*
this, a_lev); pti.isValid(); ++pti) {
646 int grid = pti.index();
647 auto& ptile = ParticlesAt(a_lev, pti);
648 auto& aos = ptile.GetArrayOfStructs();
649 auto& soa = ptile.GetStructOfArrays();
650 const int num_particles = aos.numParticles();
651 if (num_particles == 0) {
continue; }
652 auto* p_pbox = aos().data();
653 SDProcess::ParticlePointers ptrs;
654 setupParticlePointers(soa, aos, ptrs);
655 func(pti, grid, p_pbox, ptrs, num_particles);
660 virtual void readInputs ()
override
662 amrex::Abort(
"SuperDropletPC::readInputs(): Do not use this interface.");
666 virtual void readInputs (
const double);
669 void initializeParticlesNull (
const MFPtr&) { }
674 void define (
const std::vector<Species::Name>&,
675 const std::vector<Species::Name>&,
676 const amrex::BoxArray&,
677 const amrex::DistributionMapping&,
681 void add_superdroplet_attributes();
int m_num_species
Definition: ERF_InitCustomPert_MultiSpeciesBubble.H:28
std::string name
Definition: ERF_Plotfile2DCatalog.cpp:101
amrex::Real Real
Definition: ERF_ShocInterface.H:19
Common data structures for SuperDroplet physical processes.
Super-droplets initial properties.
Definition: ERF_SDInitialization.H:220
Definition: ERF_MaterialProperties.H:187