PySDM_examples.Pyrcel.simulation
1import numpy as np 2from PySDM_examples.utils import BasicSimulation 3 4from PySDM import Builder 5from PySDM.backends import CPU 6from PySDM.backends.impl_numba.test_helpers import scipy_ode_condensation_solver 7from PySDM.dynamics import AmbientThermodynamics, Condensation 8from PySDM.environments import Parcel 9from PySDM.initialisation.hygroscopic_equilibrium import equilibrate_wet_radii 10from PySDM.initialisation.sampling.spectral_sampling import ConstantMultiplicity 11from PySDM.physics import si 12 13 14class Simulation(BasicSimulation): 15 def __init__( 16 self, 17 settings, 18 products=None, 19 scipy_solver=False, 20 rtol_thd=1e-10, 21 rtol_x=1e-10, 22 mass_of_dry_air=44 * si.kg, 23 ): 24 n_sd = sum(settings.n_sd_per_mode) 25 builder = Builder( 26 n_sd=n_sd, 27 backend=CPU( 28 formulae=settings.formulae, override_jit_flags={"parallel": False} 29 ), 30 environment=Parcel( 31 dt=settings.timestep, 32 p0=settings.initial_pressure, 33 initial_water_vapour_mixing_ratio=settings.initial_vapour_mixing_ratio, 34 T0=settings.initial_temperature, 35 w=settings.vertical_velocity, 36 mass_of_dry_air=mass_of_dry_air, 37 ), 38 ) 39 builder.add_dynamic(AmbientThermodynamics()) 40 builder.add_dynamic(Condensation(rtol_thd=rtol_thd, rtol_x=rtol_x)) 41 42 volume = ( 43 builder.particulator.environment.mass_of_dry_air 44 / settings.initial_air_density 45 ) 46 attributes = { 47 k: np.empty(0) 48 for k in ("dry volume", "kappa times dry volume", "multiplicity") 49 } 50 for i, (kappa, spectrum) in enumerate(settings.aerosol_modes_by_kappa.items()): 51 sampling = ConstantMultiplicity(spectrum) 52 r_dry, n_per_volume = sampling.sample_deterministic( 53 settings.n_sd_per_mode[i] 54 ) 55 v_dry = settings.formulae.trivia.volume(radius=r_dry) 56 attributes["multiplicity"] = np.append( 57 attributes["multiplicity"], n_per_volume * volume 58 ) 59 attributes["dry volume"] = np.append(attributes["dry volume"], v_dry) 60 attributes["kappa times dry volume"] = np.append( 61 attributes["kappa times dry volume"], v_dry * kappa 62 ) 63 r_wet = equilibrate_wet_radii( 64 r_dry=settings.formulae.trivia.radius(volume=attributes["dry volume"]), 65 environment=builder.particulator.environment, 66 kappa_times_dry_volume=attributes["kappa times dry volume"], 67 ) 68 attributes["volume"] = settings.formulae.trivia.volume(radius=r_wet) 69 70 super().__init__( 71 particulator=builder.build(attributes=attributes, products=products) 72 ) 73 if scipy_solver: 74 scipy_ode_condensation_solver.patch_particulator(self.particulator) 75 76 self.output_attributes = { 77 "volume": tuple([] for _ in range(self.particulator.n_sd)) 78 } 79 self.settings = settings 80 81 self.__sanity_checks(attributes, volume) 82 83 def __sanity_checks(self, attributes, volume): 84 for attribute in attributes.values(): 85 assert attribute.shape[0] == self.particulator.n_sd 86 np.testing.assert_approx_equal( 87 sum(attributes["multiplicity"]) / volume, 88 sum( 89 mode.norm_factor 90 for mode in self.settings.aerosol_modes_by_kappa.values() 91 ), 92 significant=4, 93 ) 94 95 def _save(self, output): 96 for key, attr in self.output_attributes.items(): 97 attr_data = self.particulator.attributes[key].to_ndarray() 98 for drop_id in range(self.particulator.n_sd): 99 attr[drop_id].append(attr_data[drop_id]) 100 super()._save(output) 101 102 def run(self, observers=()): 103 for observer in observers: 104 self.particulator.observers.append(observer) 105 output_products = super()._run( 106 self.settings.nt, self.settings.steps_per_output_interval 107 ) 108 return {"products": output_products, "attributes": self.output_attributes}
15class Simulation(BasicSimulation): 16 def __init__( 17 self, 18 settings, 19 products=None, 20 scipy_solver=False, 21 rtol_thd=1e-10, 22 rtol_x=1e-10, 23 mass_of_dry_air=44 * si.kg, 24 ): 25 n_sd = sum(settings.n_sd_per_mode) 26 builder = Builder( 27 n_sd=n_sd, 28 backend=CPU( 29 formulae=settings.formulae, override_jit_flags={"parallel": False} 30 ), 31 environment=Parcel( 32 dt=settings.timestep, 33 p0=settings.initial_pressure, 34 initial_water_vapour_mixing_ratio=settings.initial_vapour_mixing_ratio, 35 T0=settings.initial_temperature, 36 w=settings.vertical_velocity, 37 mass_of_dry_air=mass_of_dry_air, 38 ), 39 ) 40 builder.add_dynamic(AmbientThermodynamics()) 41 builder.add_dynamic(Condensation(rtol_thd=rtol_thd, rtol_x=rtol_x)) 42 43 volume = ( 44 builder.particulator.environment.mass_of_dry_air 45 / settings.initial_air_density 46 ) 47 attributes = { 48 k: np.empty(0) 49 for k in ("dry volume", "kappa times dry volume", "multiplicity") 50 } 51 for i, (kappa, spectrum) in enumerate(settings.aerosol_modes_by_kappa.items()): 52 sampling = ConstantMultiplicity(spectrum) 53 r_dry, n_per_volume = sampling.sample_deterministic( 54 settings.n_sd_per_mode[i] 55 ) 56 v_dry = settings.formulae.trivia.volume(radius=r_dry) 57 attributes["multiplicity"] = np.append( 58 attributes["multiplicity"], n_per_volume * volume 59 ) 60 attributes["dry volume"] = np.append(attributes["dry volume"], v_dry) 61 attributes["kappa times dry volume"] = np.append( 62 attributes["kappa times dry volume"], v_dry * kappa 63 ) 64 r_wet = equilibrate_wet_radii( 65 r_dry=settings.formulae.trivia.radius(volume=attributes["dry volume"]), 66 environment=builder.particulator.environment, 67 kappa_times_dry_volume=attributes["kappa times dry volume"], 68 ) 69 attributes["volume"] = settings.formulae.trivia.volume(radius=r_wet) 70 71 super().__init__( 72 particulator=builder.build(attributes=attributes, products=products) 73 ) 74 if scipy_solver: 75 scipy_ode_condensation_solver.patch_particulator(self.particulator) 76 77 self.output_attributes = { 78 "volume": tuple([] for _ in range(self.particulator.n_sd)) 79 } 80 self.settings = settings 81 82 self.__sanity_checks(attributes, volume) 83 84 def __sanity_checks(self, attributes, volume): 85 for attribute in attributes.values(): 86 assert attribute.shape[0] == self.particulator.n_sd 87 np.testing.assert_approx_equal( 88 sum(attributes["multiplicity"]) / volume, 89 sum( 90 mode.norm_factor 91 for mode in self.settings.aerosol_modes_by_kappa.values() 92 ), 93 significant=4, 94 ) 95 96 def _save(self, output): 97 for key, attr in self.output_attributes.items(): 98 attr_data = self.particulator.attributes[key].to_ndarray() 99 for drop_id in range(self.particulator.n_sd): 100 attr[drop_id].append(attr_data[drop_id]) 101 super()._save(output) 102 103 def run(self, observers=()): 104 for observer in observers: 105 self.particulator.observers.append(observer) 106 output_products = super()._run( 107 self.settings.nt, self.settings.steps_per_output_interval 108 ) 109 return {"products": output_products, "attributes": self.output_attributes}
Simulation( settings, products=None, scipy_solver=False, rtol_thd=1e-10, rtol_x=1e-10, mass_of_dry_air=44.0)
16 def __init__( 17 self, 18 settings, 19 products=None, 20 scipy_solver=False, 21 rtol_thd=1e-10, 22 rtol_x=1e-10, 23 mass_of_dry_air=44 * si.kg, 24 ): 25 n_sd = sum(settings.n_sd_per_mode) 26 builder = Builder( 27 n_sd=n_sd, 28 backend=CPU( 29 formulae=settings.formulae, override_jit_flags={"parallel": False} 30 ), 31 environment=Parcel( 32 dt=settings.timestep, 33 p0=settings.initial_pressure, 34 initial_water_vapour_mixing_ratio=settings.initial_vapour_mixing_ratio, 35 T0=settings.initial_temperature, 36 w=settings.vertical_velocity, 37 mass_of_dry_air=mass_of_dry_air, 38 ), 39 ) 40 builder.add_dynamic(AmbientThermodynamics()) 41 builder.add_dynamic(Condensation(rtol_thd=rtol_thd, rtol_x=rtol_x)) 42 43 volume = ( 44 builder.particulator.environment.mass_of_dry_air 45 / settings.initial_air_density 46 ) 47 attributes = { 48 k: np.empty(0) 49 for k in ("dry volume", "kappa times dry volume", "multiplicity") 50 } 51 for i, (kappa, spectrum) in enumerate(settings.aerosol_modes_by_kappa.items()): 52 sampling = ConstantMultiplicity(spectrum) 53 r_dry, n_per_volume = sampling.sample_deterministic( 54 settings.n_sd_per_mode[i] 55 ) 56 v_dry = settings.formulae.trivia.volume(radius=r_dry) 57 attributes["multiplicity"] = np.append( 58 attributes["multiplicity"], n_per_volume * volume 59 ) 60 attributes["dry volume"] = np.append(attributes["dry volume"], v_dry) 61 attributes["kappa times dry volume"] = np.append( 62 attributes["kappa times dry volume"], v_dry * kappa 63 ) 64 r_wet = equilibrate_wet_radii( 65 r_dry=settings.formulae.trivia.radius(volume=attributes["dry volume"]), 66 environment=builder.particulator.environment, 67 kappa_times_dry_volume=attributes["kappa times dry volume"], 68 ) 69 attributes["volume"] = settings.formulae.trivia.volume(radius=r_wet) 70 71 super().__init__( 72 particulator=builder.build(attributes=attributes, products=products) 73 ) 74 if scipy_solver: 75 scipy_ode_condensation_solver.patch_particulator(self.particulator) 76 77 self.output_attributes = { 78 "volume": tuple([] for _ in range(self.particulator.n_sd)) 79 } 80 self.settings = settings 81 82 self.__sanity_checks(attributes, volume)