PySDM_examples.Jensen_and_Nugent_2017.simulation
1import numpy as np 2from PySDM_examples.utils import BasicSimulation 3from PySDM_examples.Jensen_and_Nugent_2017.settings import Settings 4from PySDM_examples.Jensen_and_Nugent_2017 import table_3 5from PySDM import Builder 6from PySDM.physics import si 7from PySDM.backends import CPU 8from PySDM.products import ( 9 PeakSupersaturation, 10 ParcelDisplacement, 11 Time, 12 ActivatedMeanRadius, 13 RadiusStandardDeviation, 14) 15from PySDM.environments import Parcel 16from PySDM.dynamics import Condensation, AmbientThermodynamics, Coalescence 17from PySDM.dynamics.collisions.collision_kernels import Geometric 18from PySDM.initialisation.sampling.spectral_sampling import Logarithmic 19 20# note: 100 in caption of Table 1 21N_SD_NON_GCCN = 100 22 23 24class Simulation(BasicSimulation): 25 def __init__( 26 self, 27 settings: Settings, 28 gccn: bool = False, 29 gravitational_coalsecence: bool = False, 30 ): 31 const = settings.formulae.constants 32 pvs_water = settings.formulae.saturation_vapour_pressure.pvs_water 33 initial_water_vapour_mixing_ratio = const.eps / ( 34 settings.p0 / settings.RH0 / pvs_water(settings.T0) - 1 35 ) 36 37 n_gccn = np.count_nonzero(table_3.NA) if gccn else 0 38 39 builder = Builder( 40 n_sd=N_SD_NON_GCCN + n_gccn, 41 backend=CPU( 42 formulae=settings.formulae, override_jit_flags={"parallel": False} 43 ), 44 environment=Parcel( 45 dt=settings.dt, 46 mass_of_dry_air=666 * si.kg, 47 p0=settings.p0, 48 initial_water_vapour_mixing_ratio=initial_water_vapour_mixing_ratio, 49 T0=settings.T0, 50 w=settings.vertical_velocity, 51 z0=settings.z0, 52 ), 53 ) 54 55 additional_derived_attributes = ("radius", "equilibrium supersaturation") 56 for additional_derived_attribute in additional_derived_attributes: 57 builder.request_attribute(additional_derived_attribute) 58 59 builder.add_dynamic( 60 AmbientThermodynamics() 61 ) # TODO #1266: order matters here, but error message is not saying it! 62 builder.add_dynamic(Condensation()) 63 if gravitational_coalsecence: 64 builder.add_dynamic(Coalescence(collision_kernel=Geometric())) 65 66 self.r_dry, n_in_unit_volume = Logarithmic( 67 spectrum=settings.dry_radii_spectrum, 68 ).sample(builder.particulator.n_sd - n_gccn) 69 70 if gccn: 71 nonzero_concentration_mask = np.nonzero(table_3.NA) 72 self.r_dry = np.concatenate( 73 [self.r_dry, table_3.RD[nonzero_concentration_mask]] 74 ) 75 n_in_unit_volume = np.concatenate( 76 [n_in_unit_volume, table_3.NA[nonzero_concentration_mask]] 77 ) # TODO #1266: check which temp, pres, RH assumed in the paper for NA??? 78 79 pd0 = settings.formulae.trivia.p_d( 80 settings.p0, initial_water_vapour_mixing_ratio 81 ) 82 rhod0 = settings.formulae.state_variable_triplet.rhod_of_pd_T(pd0, settings.T0) 83 84 attributes = builder.particulator.environment.init_attributes( 85 n_in_dv=n_in_unit_volume 86 * builder.particulator.environment.mass_of_dry_air 87 / rhod0, 88 kappa=settings.kappa, 89 r_dry=self.r_dry, 90 ) 91 92 super().__init__( 93 builder.build( 94 attributes=attributes, 95 products=( 96 PeakSupersaturation(name="S_max"), 97 ParcelDisplacement(name="z"), 98 Time(name="t"), 99 ActivatedMeanRadius( 100 name="r_mean_act", count_activated=True, count_unactivated=False 101 ), 102 RadiusStandardDeviation( 103 name="r_std_act", count_activated=True, count_unactivated=False 104 ), 105 ), 106 ) 107 ) 108 109 # TODO #1266: copied from G & P 2023 110 self.output_attributes = { 111 attr: tuple([] for _ in range(self.particulator.n_sd)) 112 for attr in additional_derived_attributes 113 } 114 115 def run( 116 self, *, n_steps: int = 2250, steps_per_output_interval: int = 10 117 ): # TODO #1266: essentially copied from G & P 2023 118 output_products = super()._run( 119 nt=n_steps, steps_per_output_interval=steps_per_output_interval 120 ) 121 return {"products": output_products, "attributes": self.output_attributes} 122 123 def _save(self, output): # TODO #1266: copied from G&P 2023 124 for key, attr in self.output_attributes.items(): 125 attr_data = self.particulator.attributes[key].to_ndarray() 126 for drop_id in range(self.particulator.n_sd): 127 attr[drop_id].append(attr_data[drop_id]) 128 super()._save(output)
N_SD_NON_GCCN =
100
25class Simulation(BasicSimulation): 26 def __init__( 27 self, 28 settings: Settings, 29 gccn: bool = False, 30 gravitational_coalsecence: bool = False, 31 ): 32 const = settings.formulae.constants 33 pvs_water = settings.formulae.saturation_vapour_pressure.pvs_water 34 initial_water_vapour_mixing_ratio = const.eps / ( 35 settings.p0 / settings.RH0 / pvs_water(settings.T0) - 1 36 ) 37 38 n_gccn = np.count_nonzero(table_3.NA) if gccn else 0 39 40 builder = Builder( 41 n_sd=N_SD_NON_GCCN + n_gccn, 42 backend=CPU( 43 formulae=settings.formulae, override_jit_flags={"parallel": False} 44 ), 45 environment=Parcel( 46 dt=settings.dt, 47 mass_of_dry_air=666 * si.kg, 48 p0=settings.p0, 49 initial_water_vapour_mixing_ratio=initial_water_vapour_mixing_ratio, 50 T0=settings.T0, 51 w=settings.vertical_velocity, 52 z0=settings.z0, 53 ), 54 ) 55 56 additional_derived_attributes = ("radius", "equilibrium supersaturation") 57 for additional_derived_attribute in additional_derived_attributes: 58 builder.request_attribute(additional_derived_attribute) 59 60 builder.add_dynamic( 61 AmbientThermodynamics() 62 ) # TODO #1266: order matters here, but error message is not saying it! 63 builder.add_dynamic(Condensation()) 64 if gravitational_coalsecence: 65 builder.add_dynamic(Coalescence(collision_kernel=Geometric())) 66 67 self.r_dry, n_in_unit_volume = Logarithmic( 68 spectrum=settings.dry_radii_spectrum, 69 ).sample(builder.particulator.n_sd - n_gccn) 70 71 if gccn: 72 nonzero_concentration_mask = np.nonzero(table_3.NA) 73 self.r_dry = np.concatenate( 74 [self.r_dry, table_3.RD[nonzero_concentration_mask]] 75 ) 76 n_in_unit_volume = np.concatenate( 77 [n_in_unit_volume, table_3.NA[nonzero_concentration_mask]] 78 ) # TODO #1266: check which temp, pres, RH assumed in the paper for NA??? 79 80 pd0 = settings.formulae.trivia.p_d( 81 settings.p0, initial_water_vapour_mixing_ratio 82 ) 83 rhod0 = settings.formulae.state_variable_triplet.rhod_of_pd_T(pd0, settings.T0) 84 85 attributes = builder.particulator.environment.init_attributes( 86 n_in_dv=n_in_unit_volume 87 * builder.particulator.environment.mass_of_dry_air 88 / rhod0, 89 kappa=settings.kappa, 90 r_dry=self.r_dry, 91 ) 92 93 super().__init__( 94 builder.build( 95 attributes=attributes, 96 products=( 97 PeakSupersaturation(name="S_max"), 98 ParcelDisplacement(name="z"), 99 Time(name="t"), 100 ActivatedMeanRadius( 101 name="r_mean_act", count_activated=True, count_unactivated=False 102 ), 103 RadiusStandardDeviation( 104 name="r_std_act", count_activated=True, count_unactivated=False 105 ), 106 ), 107 ) 108 ) 109 110 # TODO #1266: copied from G & P 2023 111 self.output_attributes = { 112 attr: tuple([] for _ in range(self.particulator.n_sd)) 113 for attr in additional_derived_attributes 114 } 115 116 def run( 117 self, *, n_steps: int = 2250, steps_per_output_interval: int = 10 118 ): # TODO #1266: essentially copied from G & P 2023 119 output_products = super()._run( 120 nt=n_steps, steps_per_output_interval=steps_per_output_interval 121 ) 122 return {"products": output_products, "attributes": self.output_attributes} 123 124 def _save(self, output): # TODO #1266: copied from G&P 2023 125 for key, attr in self.output_attributes.items(): 126 attr_data = self.particulator.attributes[key].to_ndarray() 127 for drop_id in range(self.particulator.n_sd): 128 attr[drop_id].append(attr_data[drop_id]) 129 super()._save(output)
Simulation( settings: PySDM_examples.Jensen_and_Nugent_2017.settings.Settings, gccn: bool = False, gravitational_coalsecence: bool = False)
26 def __init__( 27 self, 28 settings: Settings, 29 gccn: bool = False, 30 gravitational_coalsecence: bool = False, 31 ): 32 const = settings.formulae.constants 33 pvs_water = settings.formulae.saturation_vapour_pressure.pvs_water 34 initial_water_vapour_mixing_ratio = const.eps / ( 35 settings.p0 / settings.RH0 / pvs_water(settings.T0) - 1 36 ) 37 38 n_gccn = np.count_nonzero(table_3.NA) if gccn else 0 39 40 builder = Builder( 41 n_sd=N_SD_NON_GCCN + n_gccn, 42 backend=CPU( 43 formulae=settings.formulae, override_jit_flags={"parallel": False} 44 ), 45 environment=Parcel( 46 dt=settings.dt, 47 mass_of_dry_air=666 * si.kg, 48 p0=settings.p0, 49 initial_water_vapour_mixing_ratio=initial_water_vapour_mixing_ratio, 50 T0=settings.T0, 51 w=settings.vertical_velocity, 52 z0=settings.z0, 53 ), 54 ) 55 56 additional_derived_attributes = ("radius", "equilibrium supersaturation") 57 for additional_derived_attribute in additional_derived_attributes: 58 builder.request_attribute(additional_derived_attribute) 59 60 builder.add_dynamic( 61 AmbientThermodynamics() 62 ) # TODO #1266: order matters here, but error message is not saying it! 63 builder.add_dynamic(Condensation()) 64 if gravitational_coalsecence: 65 builder.add_dynamic(Coalescence(collision_kernel=Geometric())) 66 67 self.r_dry, n_in_unit_volume = Logarithmic( 68 spectrum=settings.dry_radii_spectrum, 69 ).sample(builder.particulator.n_sd - n_gccn) 70 71 if gccn: 72 nonzero_concentration_mask = np.nonzero(table_3.NA) 73 self.r_dry = np.concatenate( 74 [self.r_dry, table_3.RD[nonzero_concentration_mask]] 75 ) 76 n_in_unit_volume = np.concatenate( 77 [n_in_unit_volume, table_3.NA[nonzero_concentration_mask]] 78 ) # TODO #1266: check which temp, pres, RH assumed in the paper for NA??? 79 80 pd0 = settings.formulae.trivia.p_d( 81 settings.p0, initial_water_vapour_mixing_ratio 82 ) 83 rhod0 = settings.formulae.state_variable_triplet.rhod_of_pd_T(pd0, settings.T0) 84 85 attributes = builder.particulator.environment.init_attributes( 86 n_in_dv=n_in_unit_volume 87 * builder.particulator.environment.mass_of_dry_air 88 / rhod0, 89 kappa=settings.kappa, 90 r_dry=self.r_dry, 91 ) 92 93 super().__init__( 94 builder.build( 95 attributes=attributes, 96 products=( 97 PeakSupersaturation(name="S_max"), 98 ParcelDisplacement(name="z"), 99 Time(name="t"), 100 ActivatedMeanRadius( 101 name="r_mean_act", count_activated=True, count_unactivated=False 102 ), 103 RadiusStandardDeviation( 104 name="r_std_act", count_activated=True, count_unactivated=False 105 ), 106 ), 107 ) 108 ) 109 110 # TODO #1266: copied from G & P 2023 111 self.output_attributes = { 112 attr: tuple([] for _ in range(self.particulator.n_sd)) 113 for attr in additional_derived_attributes 114 }
def
run(self, *, n_steps: int = 2250, steps_per_output_interval: int = 10):
116 def run( 117 self, *, n_steps: int = 2250, steps_per_output_interval: int = 10 118 ): # TODO #1266: essentially copied from G & P 2023 119 output_products = super()._run( 120 nt=n_steps, steps_per_output_interval=steps_per_output_interval 121 ) 122 return {"products": output_products, "attributes": self.output_attributes}