def __init__(self, settings, backend=CPU): t_half = settings.z_half / settings.w_avg dt_output = (2 * t_half) / settings.n_output self.n_substeps = 1 while dt_output / self.n_substeps >= settings.dt_max: # TODO #334 dt_max self.n_substeps += 1 builder = Builder(backend=backend(formulae=settings.formulae), n_sd=1) builder.set_environment( Parcel( dt=dt_output / self.n_substeps, mass_of_dry_air=settings.mass_of_dry_air, p0=settings.p0, q0=settings.q0, T0=settings.T0, w=settings.w, )) builder.add_dynamic(AmbientThermodynamics()) builder.add_dynamic( Condensation( rtol_x=settings.rtol_x, rtol_thd=settings.rtol_thd, dt_cond_range=settings.dt_cond_range, )) attributes = {} r_dry = np.array([settings.r_dry]) attributes["dry volume"] = settings.formulae.trivia.volume( radius=r_dry) attributes["kappa times dry volume"] = attributes[ "dry volume"] * settings.kappa attributes["n"] = np.array([settings.n_in_dv], dtype=np.int64) environment = builder.particulator.environment r_wet = equilibrate_wet_radii( r_dry=r_dry, environment=environment, kappa_times_dry_volume=attributes["kappa times dry volume"], ) attributes["volume"] = settings.formulae.trivia.volume(radius=r_wet) products = [ PySDM_products.MeanRadius(name="radius_m1", unit="um"), PySDM_products.CondensationTimestepMin(name="dt_cond_min"), PySDM_products.ParcelDisplacement(name="z"), PySDM_products.AmbientRelativeHumidity(name="RH", unit="%"), PySDM_products.Time(name="t"), PySDM_products.ActivatingRate(unit="s^-1 mg^-1", name="activating_rate"), PySDM_products.DeactivatingRate(unit="s^-1 mg^-1", name="deactivating_rate"), PySDM_products.RipeningRate(unit="s^-1 mg^-1", name="ripening_rate"), PySDM_products.PeakSupersaturation(unit="%", name="S_max"), ] self.particulator = builder.build(attributes, products) self.n_output = settings.n_output
def __init__(self, settings, backend=CPU): dt_output = (settings.total_time / settings.n_steps ) # TODO #334 overwritten in notebook self.n_substeps = 1 # TODO #334 use condensation substeps while dt_output / self.n_substeps >= settings.dt_max: self.n_substeps += 1 self.formulae = Formulae( condensation_coordinate=settings.coord, saturation_vapour_pressure="AugustRocheMagnus", ) self.bins_edges = self.formulae.trivia.volume(settings.r_bins_edges) builder = Builder(backend=backend(formulae=self.formulae), n_sd=settings.n_sd) builder.set_environment( Parcel( dt=dt_output / self.n_substeps, mass_of_dry_air=settings.mass_of_dry_air, p0=settings.p0, q0=settings.q0, T0=settings.T0, w=settings.w, z0=settings.z0, )) environment = builder.particulator.environment builder.add_dynamic(AmbientThermodynamics()) condensation = Condensation( adaptive=settings.adaptive, rtol_x=settings.rtol_x, rtol_thd=settings.rtol_thd, dt_cond_range=settings.dt_cond_range, ) builder.add_dynamic(condensation) products = [ PySDM_products.ParticleSizeSpectrumPerVolume( name="Particles Wet Size Spectrum", radius_bins_edges=settings.r_bins_edges, ), PySDM_products.CondensationTimestepMin(name="dt_cond_min"), PySDM_products.CondensationTimestepMax(name="dt_cond_max"), PySDM_products.RipeningRate(), ] attributes = environment.init_attributes(n_in_dv=settings.n, kappa=settings.kappa, r_dry=settings.r_dry) self.particulator = builder.build(attributes, products) self.n_steps = settings.n_steps
def __init__( self, settings, products=None, scipy_solver=False, rtol_thd=1e-10, rtol_x=1e-10 ): env = Parcel( dt=settings.timestep, p0=settings.initial_pressure, q0=settings.initial_vapour_mixing_ratio, T0=settings.initial_temperature, w=settings.vertical_velocity, mass_of_dry_air=44 * si.kg, ) n_sd = sum(settings.n_sd_per_mode) builder = Builder(n_sd=n_sd, backend=CPU(formulae=settings.formulae)) builder.set_environment(env) builder.add_dynamic(AmbientThermodynamics()) builder.add_dynamic(Condensation(rtol_thd=rtol_thd, rtol_x=rtol_x)) volume = env.mass_of_dry_air / settings.initial_air_density attributes = { k: np.empty(0) for k in ("dry volume", "kappa times dry volume", "n") } for i, (kappa, spectrum) in enumerate(settings.aerosol_modes_by_kappa.items()): sampling = ConstantMultiplicity(spectrum) r_dry, n_per_volume = sampling.sample(settings.n_sd_per_mode[i]) v_dry = settings.formulae.trivia.volume(radius=r_dry) attributes["n"] = np.append(attributes["n"], n_per_volume * volume) attributes["dry volume"] = np.append(attributes["dry volume"], v_dry) attributes["kappa times dry volume"] = np.append( attributes["kappa times dry volume"], v_dry * kappa ) r_wet = equilibrate_wet_radii( r_dry=settings.formulae.trivia.radius(volume=attributes["dry volume"]), environment=env, kappa_times_dry_volume=attributes["kappa times dry volume"], ) attributes["volume"] = settings.formulae.trivia.volume(radius=r_wet) super().__init__( particulator=builder.build(attributes=attributes, products=products) ) if scipy_solver: bdf.patch_particulator(self.particulator) self.output_attributes = { "volume": tuple([] for _ in range(self.particulator.n_sd)) } self.settings = settings self.__sanity_checks(attributes, volume)
def __init__(self, settings, backend=CPU): t_half = settings.z_half / settings.w_avg dt_output = (2 * t_half) / settings.n_output self.n_substeps = 1 while dt_output / self.n_substeps >= settings.dt_max: # TODO #334 dt_max self.n_substeps += 1 builder = Builder(backend=backend, n_sd=1, formulae=settings.formulae) builder.set_environment(Parcel( dt=dt_output / self.n_substeps, mass_of_dry_air=settings.mass_of_dry_air, p0=settings.p0, q0=settings.q0, T0=settings.T0, w=settings.w )) builder.add_dynamic(AmbientThermodynamics()) builder.add_dynamic(Condensation( kappa=settings.kappa, rtol_x=settings.rtol_x, rtol_thd=settings.rtol_thd, dt_cond_range=settings.dt_cond_range )) attributes = {} r_dry = np.array([settings.r_dry]) attributes['dry volume'] = settings.formulae.trivia.volume(radius=r_dry) attributes['n'] = np.array([settings.n_in_dv], dtype=np.int64) environment = builder.core.environment r_wet = r_wet_init(r_dry, environment, kappa=settings.kappa) attributes['volume'] = settings.formulae.trivia.volume(radius=r_wet) products = [ PySDM_products.ParticleMeanRadius(), PySDM_products.CondensationTimestepMin(), PySDM_products.ParcelDisplacement(), PySDM_products.RelativeHumidity(), PySDM_products.Time(), PySDM_products.ActivatingRate(), PySDM_products.DeactivatingRate(), PySDM_products.RipeningRate(), PySDM_products.PeakSupersaturation() ] self.core = builder.build(attributes, products) self.n_output = settings.n_output
def __init__(self, settings, backend=CPU): dt_output = settings.total_time / settings.n_steps # TODO #334 overwritten in jupyter example self.n_substeps = 1 # TODO #334 use condensation substeps while (dt_output / self.n_substeps >= settings.dt_max): self.n_substeps += 1 self.formulae = Formulae(condensation_coordinate=settings.coord, saturation_vapour_pressure='AugustRocheMagnus') self.bins_edges = self.formulae.trivia.volume(settings.r_bins_edges) builder = Builder(backend=backend, n_sd=settings.n_sd, formulae=self.formulae) builder.set_environment(Parcel( dt=dt_output / self.n_substeps, mass_of_dry_air=settings.mass_of_dry_air, p0=settings.p0, q0=settings.q0, T0=settings.T0, w=settings.w, z0=settings.z0 )) environment = builder.core.environment builder.add_dynamic(AmbientThermodynamics()) condensation = Condensation( kappa=settings.kappa, adaptive=settings.adaptive, rtol_x=settings.rtol_x, rtol_thd=settings.rtol_thd, dt_cond_range=settings.dt_cond_range ) builder.add_dynamic(condensation) products = [ PySDM_products.ParticlesWetSizeSpectrum(v_bins=self.formulae.trivia.volume(settings.r_bins_edges)), PySDM_products.CondensationTimestepMin(), PySDM_products.CondensationTimestepMax(), PySDM_products.RipeningRate() ] attributes = environment.init_attributes( n_in_dv=settings.n, kappa=settings.kappa, r_dry=settings.r_dry ) self.core = builder.build(attributes, products) self.n_steps = settings.n_steps
def __init__(self, settings, backend=CPU): dt_output = settings.total_time / settings.n_steps # TODO: overwritten in jupyter example self.n_substeps = 1 # TODO while (dt_output / self.n_substeps >= settings.dt_max): self.n_substeps += 1 self.bins_edges = phys.volume(settings.r_bins_edges) builder = Builder(backend=backend, n_sd=settings.n_sd) builder.set_environment( Parcel(dt=dt_output / self.n_substeps, mass_of_dry_air=settings.mass_of_dry_air, p0=settings.p0, q0=settings.q0, T0=settings.T0, w=settings.w, z0=settings.z0)) environment = builder.core.environment builder.add_dynamic(AmbientThermodynamics()) condensation = Condensation(kappa=settings.kappa, coord=settings.coord, adaptive=settings.adaptive, rtol_x=settings.rtol_x, rtol_thd=settings.rtol_thd) builder.add_dynamic(condensation) products = [ ParticlesWetSizeSpectrum( v_bins=phys.volume(settings.r_bins_edges)), CondensationTimestep(), RipeningRate() ] attributes = environment.init_attributes(n_in_dv=settings.n, kappa=settings.kappa, r_dry=settings.r_dry) self.core = builder.build(attributes, products) self.n_steps = settings.n_steps
def __init__(self, settings, backend=CPU): t_half = settings.z_half / settings.w_avg dt_output = (2 * t_half) / settings.n_output self.n_substeps = 1 while dt_output / self.n_substeps >= settings.dt_max: # TODO dt_max self.n_substeps += 1 builder = Builder(backend=backend, n_sd=1) builder.set_environment(Parcel( dt=dt_output / self.n_substeps, mass_of_dry_air=settings.mass_of_dry_air, p0=settings.p0, q0=settings.q0, T0=settings.T0, w=settings.w )) builder.add_dynamic(AmbientThermodynamics()) builder.add_dynamic(Condensation( kappa=settings.kappa, rtol_x=settings.rtol_x, rtol_thd=settings.rtol_thd, )) attributes = {} r_dry = np.array([settings.r_dry]) attributes['dry volume'] = phys.volume(radius=r_dry) attributes['n'] = np.array([settings.n_in_dv], dtype=np.int64) environment = builder.core.environment r_wet = r_wet_init(r_dry, environment, np.zeros_like(attributes['n']), settings.kappa) attributes['volume'] = phys.volume(radius=r_wet) products = [ParticleMeanRadius(), CondensationTimestep()] self.core = builder.build(attributes, products) self.n_output = settings.n_output
def reinit(self, products=None): builder = Builder(n_sd=self.settings.n_sd, backend=self.backend) environment = Kinematic2D(dt=self.settings.dt, grid=self.settings.grid, size=self.settings.size, rhod_of=self.settings.rhod, field_values=self.settings.field_values) builder.set_environment(environment) products = products or [ ParticlesWetSizeSpectrum(v_bins=self.settings.v_bins, normalise_by_dv=True), ParticlesDrySizeSpectrum( v_bins=self.settings.v_bins, normalise_by_dv=True), # Note: better v_bins TotalParticleConcentration(), TotalParticleSpecificConcentration(), AerosolConcentration( radius_threshold=self.settings.aerosol_radius_threshold), CloudConcentration( radius_range=(self.settings.aerosol_radius_threshold, self.settings.drizzle_radius_threshold)), DrizzleConcentration( radius_threshold=self.settings.drizzle_radius_threshold), AerosolSpecificConcentration( radius_threshold=self.settings.aerosol_radius_threshold), ParticleMeanRadius(), SuperDropletCount(), RelativeHumidity(), Pressure(), Temperature(), WaterVapourMixingRatio(), DryAirDensity(), DryAirPotentialTemperature(), CPUTime(), WallTime() ] fields = Fields(environment, self.settings.stream_function) if self.settings.processes[ 'fluid advection']: # TODO: ambient thermodynamics checkbox builder.add_dynamic(AmbientThermodynamics()) if self.settings.processes["condensation"]: condensation = Condensation( kappa=self.settings.kappa, rtol_x=self.settings.condensation_rtol_x, rtol_thd=self.settings.condensation_rtol_thd, coord=self.settings.condensation_coord, adaptive=self.settings.adaptive) builder.add_dynamic(condensation) products.append(CondensationTimestep() ) # TODO: and what if a user doesn't want it? if self.settings.processes['fluid advection']: solver = MPDATA(fields=fields, n_iters=self.settings.mpdata_iters, infinite_gauge=self.settings.mpdata_iga, flux_corrected_transport=self.settings.mpdata_fct, third_order_terms=self.settings.mpdata_tot) builder.add_dynamic(EulerianAdvection(solver)) if self.settings.processes["particle advection"]: displacement = Displacement( courant_field=fields.courant_field, scheme='FTBS', enable_sedimentation=self.settings.processes["sedimentation"]) builder.add_dynamic(displacement) products.append(SurfacePrecipitation()) # TODO: ditto if self.settings.processes["coalescence"]: builder.add_dynamic(Coalescence(kernel=self.settings.kernel)) attributes = environment.init_attributes( spatial_discretisation=spatial_sampling.Pseudorandom(), spectral_discretisation=spectral_sampling.ConstantMultiplicity( spectrum=self.settings.spectrum_per_mass_of_dry_air), kappa=self.settings.kappa) self.core = builder.build(attributes, products) SpinUp(self.core, self.settings.n_spin_up) # TODO if self.storage is not None: self.storage.init(self.settings)
def __init__(self, settings, products=None): env = Parcel( dt=settings.dt, mass_of_dry_air=settings.mass_of_dry_air, p0=settings.p0, q0=settings.q0, T0=settings.T0, w=settings.w, ) n_sd = settings.n_sd_per_mode * len(settings.aerosol.modes) builder = Builder(n_sd=n_sd, backend=CPU(formulae=settings.formulae)) builder.set_environment(env) attributes = { "dry volume": np.empty(0), "dry volume organic": np.empty(0), "kappa times dry volume": np.empty(0), "n": np.ndarray(0), } for mode in settings.aerosol.modes: r_dry, n_in_dv = settings.spectral_sampling( spectrum=mode["spectrum"]).sample(settings.n_sd_per_mode) V = settings.mass_of_dry_air / settings.rho0 N = n_in_dv * V v_dry = settings.formulae.trivia.volume(radius=r_dry) attributes["n"] = np.append(attributes["n"], N) attributes["dry volume"] = np.append(attributes["dry volume"], v_dry) attributes["dry volume organic"] = np.append( attributes["dry volume organic"], mode["f_org"] * v_dry) attributes["kappa times dry volume"] = np.append( attributes["kappa times dry volume"], v_dry * mode["kappa"][settings.model], ) for attribute in attributes.values(): assert attribute.shape[0] == n_sd np.testing.assert_approx_equal( np.sum(attributes["n"]) / V, Sum( tuple( settings.aerosol.modes[i]["spectrum"] for i in range(len(settings.aerosol.modes)))).norm_factor, significant=5, ) r_wet = equilibrate_wet_radii( r_dry=settings.formulae.trivia.radius( volume=attributes["dry volume"]), environment=env, kappa_times_dry_volume=attributes["kappa times dry volume"], f_org=attributes["dry volume organic"] / attributes["dry volume"], ) attributes["volume"] = settings.formulae.trivia.volume(radius=r_wet) if settings.model == "Constant": del attributes["dry volume organic"] builder.add_dynamic(AmbientThermodynamics()) builder.add_dynamic(Condensation()) products = products or ( PySDM_products.ParcelDisplacement(name="z"), PySDM_products.Time(name="t"), PySDM_products.PeakSupersaturation(unit="%", name="S_max"), PySDM_products.AmbientRelativeHumidity(unit="%", name="RH"), PySDM_products.ParticleConcentration( name="n_c_cm3", unit="cm^-3", radius_range=settings.cloud_radius_range), PySDM_products.ParticleSizeSpectrumPerVolume( radius_bins_edges=settings.wet_radius_bins_edges), PySDM_products.ActivableFraction(), ) particulator = builder.build(attributes=attributes, products=products) if settings.BDF: bdf.patch_particulator(particulator) self.settings = settings super().__init__(particulator=particulator)
def __init__(self, settings, backend=CPU): self.nt = settings.nt builder = Builder(backend=backend, n_sd=settings.n_sd, formulae=settings.formulae) mesh = Mesh(grid=(settings.nz, ), size=(settings.z_max, )) env = Kinematic1D(dt=settings.dt, mesh=mesh, thd_of_z=settings.thd, rhod_of_z=settings.rhod) mpdata = MPDATA_1D( nz=settings.nz, dt=settings.dt, mpdata_settings=settings.mpdata_settings, advector_of_t=lambda t: settings.w(t) * settings.dt / settings.dz, advectee_of_zZ_at_t0=lambda zZ: settings.qv(zZ * settings.dz), g_factor_of_zZ=lambda zZ: settings.rhod(zZ * settings.dz)) builder.set_environment(env) builder.add_dynamic(AmbientThermodynamics()) builder.add_dynamic( Condensation(adaptive=settings.condensation_adaptive, rtol_thd=settings.condensation_rtol_thd, rtol_x=settings.condensation_rtol_x, kappa=settings.kappa)) builder.add_dynamic(EulerianAdvection(mpdata)) if settings.precip: builder.add_dynamic( Coalescence(kernel=Geometric(collection_efficiency=1), adaptive=settings.coalescence_adaptive)) builder.add_dynamic( Displacement(enable_sedimentation=True, courant_field=(np.zeros(settings.nz + 1), ))) # TODO #414 attributes = env.init_attributes( spatial_discretisation=spatial_sampling.Pseudorandom(), spectral_discretisation=spectral_sampling.ConstantMultiplicity( spectrum=settings.wet_radius_spectrum_per_mass_of_dry_air), kappa=settings.kappa) products = [ PySDM_products.RelativeHumidity(), PySDM_products.Pressure(), PySDM_products.Temperature(), PySDM_products.WaterVapourMixingRatio(), PySDM_products.WaterMixingRatio( name='ql', description_prefix='cloud', radius_range=settings.cloud_water_radius_range), PySDM_products.WaterMixingRatio( name='qr', description_prefix='rain', radius_range=settings.rain_water_radius_range), PySDM_products.DryAirDensity(), PySDM_products.DryAirPotentialTemperature(), PySDM_products.ParticlesDrySizeSpectrum( v_bins=settings.v_bin_edges), PySDM_products.ParticlesWetSizeSpectrum( v_bins=settings.v_bin_edges), PySDM_products.CloudDropletConcentration( radius_range=settings.cloud_water_radius_range), PySDM_products.AerosolConcentration( radius_threshold=settings.cloud_water_radius_range[0]), PySDM_products.ParticleMeanRadius(), PySDM_products.RipeningRate(), PySDM_products.ActivatingRate(), PySDM_products.DeactivatingRate(), PySDM_products.CloudDropletEffectiveRadius( radius_range=settings.cloud_water_radius_range), PySDM_products.PeakSupersaturation() ] self.core = builder.build(attributes=attributes, products=products)
def __init__(self, settings, products=None): env = Parcel( dt=settings.dt, mass_of_dry_air=settings.mass_of_dry_air, p0=settings.p0, q0=settings.q0, T0=settings.T0, w=settings.w, ) builder = Builder(n_sd=settings.n_sd, backend=CPU(formulae=settings.formulae)) builder.set_environment(env) attributes = env.init_attributes(n_in_dv=settings.n_in_dv, kappa=settings.kappa, r_dry=settings.r_dry) attributes = { **attributes, **settings.starting_amounts, "pH": np.zeros(settings.n_sd), } builder.add_dynamic(AmbientThermodynamics()) builder.add_dynamic(Condensation()) builder.add_dynamic( AqueousChemistry( environment_mole_fractions=settings.ENVIRONMENT_MOLE_FRACTIONS, system_type=settings.system_type, n_substep=settings.n_substep, dry_rho=settings.DRY_RHO, dry_molar_mass=settings.dry_molar_mass, )) products = products or ( PySDM_products.AmbientRelativeHumidity(name="RH", unit="%"), PySDM_products.WaterMixingRatio( name="ql", radius_range=[1 * si.um, np.inf], unit="g/kg"), PySDM_products.ParcelDisplacement(name="z"), PySDM_products.AmbientPressure(name="p"), PySDM_products.AmbientTemperature(name="T"), PySDM_products.AmbientDryAirDensity(name="rhod"), PySDM_products.AmbientWaterVapourMixingRatio(name="qv", unit="g/kg"), PySDM_products.Time(name="t"), *(PySDM_products.AqueousMoleFraction( comp, unit="ppb", name=f"aq_{comp}_ppb") for comp in AQUEOUS_COMPOUNDS), *(PySDM_products.GaseousMoleFraction( comp, unit="ppb", name=f"gas_{comp}_ppb") for comp in GASEOUS_COMPOUNDS), PySDM_products.Acidity( name="pH_pH_number_weighted", radius_range=settings.cloud_radius_range, weighting="number", attr="pH", ), PySDM_products.Acidity( name="pH_pH_volume_weighted", radius_range=settings.cloud_radius_range, weighting="volume", attr="pH", ), PySDM_products.Acidity( name="pH_conc_H_number_weighted", radius_range=settings.cloud_radius_range, weighting="number", attr="conc_H", ), PySDM_products.Acidity( name="pH_conc_H_volume_weighted", radius_range=settings.cloud_radius_range, weighting="volume", attr="conc_H", ), PySDM_products.TotalDryMassMixingRatio( settings.DRY_RHO, name="q_dry", unit="ug/kg"), PySDM_products.PeakSupersaturation(unit="%", name="S_max"), PySDM_products.ParticleSpecificConcentration( radius_range=settings.cloud_radius_range, name="n_c_mg", unit="mg^-1"), PySDM_products.AqueousMassSpectrum( key="S_VI", dry_radius_bins_edges=settings.dry_radius_bins_edges, name="dm_S_VI/dlog_10(dry diameter)", unit='ug / m^3"', ), ) particulator = builder.build(attributes=attributes, products=products) self.settings = settings super().__init__(particulator=particulator)
def reinit(self, products=None): builder = Builder(n_sd=self.settings.n_sd, backend=self.backend, formulae=self.settings.formulae) environment = Kinematic2D(dt=self.settings.dt, grid=self.settings.grid, size=self.settings.size, rhod_of=self.settings.rhod, field_values=self.settings.field_values) builder.set_environment(environment) cloud_range = (self.settings.aerosol_radius_threshold, self.settings.drizzle_radius_threshold) if products is not None: products = list(products) products = products or [ PySDM_products.ParticlesWetSizeSpectrum( v_bins=self.settings.v_bins, normalise_by_dv=True), PySDM_products.ParticlesDrySizeSpectrum( v_bins=self.settings.v_bins, normalise_by_dv=True), # Note: better v_bins PySDM_products.TotalParticleConcentration(), PySDM_products.TotalParticleSpecificConcentration(), PySDM_products.AerosolConcentration( radius_threshold=self.settings.aerosol_radius_threshold), PySDM_products.CloudDropletConcentration(radius_range=cloud_range), PySDM_products.WaterMixingRatio(name='qc', description_prefix='Cloud', radius_range=cloud_range), PySDM_products.WaterMixingRatio( name='qr', description_prefix='Rain', radius_range=(self.settings.drizzle_radius_threshold, np.inf)), PySDM_products.DrizzleConcentration( radius_threshold=self.settings.drizzle_radius_threshold), PySDM_products.AerosolSpecificConcentration( radius_threshold=self.settings.aerosol_radius_threshold), PySDM_products.ParticleMeanRadius(), PySDM_products.SuperDropletCount(), PySDM_products.RelativeHumidity(), PySDM_products.Pressure(), PySDM_products.Temperature(), PySDM_products.WaterVapourMixingRatio(), PySDM_products.DryAirDensity(), PySDM_products.DryAirPotentialTemperature(), PySDM_products.CPUTime(), PySDM_products.WallTime(), PySDM_products.CloudDropletEffectiveRadius( radius_range=cloud_range), PySDM_products.PeakSupersaturation(), PySDM_products.ActivatingRate(), PySDM_products.DeactivatingRate(), PySDM_products.RipeningRate() ] fields = Fields(environment, self.settings.stream_function) if self.settings.processes[ 'fluid advection']: # TODO #37 ambient thermodynamics checkbox builder.add_dynamic(AmbientThermodynamics()) if self.settings.processes["condensation"]: condensation = Condensation( kappa=self.settings.kappa, rtol_x=self.settings.condensation_rtol_x, rtol_thd=self.settings.condensation_rtol_thd, adaptive=self.settings.condensation_adaptive, substeps=self.settings.condensation_substeps, dt_cond_range=self.settings.condensation_dt_cond_range, schedule=self.settings.condensation_schedule) builder.add_dynamic(condensation) products.append(PySDM_products.CondensationTimestepMin() ) # TODO #37 and what if a user doesn't want it? products.append(PySDM_products.CondensationTimestepMax()) if self.settings.processes['fluid advection']: solver = MPDATA(fields=fields, n_iters=self.settings.mpdata_iters, infinite_gauge=self.settings.mpdata_iga, flux_corrected_transport=self.settings.mpdata_fct, third_order_terms=self.settings.mpdata_tot) builder.add_dynamic(EulerianAdvection(solver)) if self.settings.processes["particle advection"]: displacement = Displacement( courant_field=fields.courant_field, enable_sedimentation=self.settings.processes["sedimentation"]) builder.add_dynamic(displacement) products.append( PySDM_products.SurfacePrecipitation()) # TODO #37 ditto if self.settings.processes["coalescence"]: builder.add_dynamic( Coalescence( kernel=self.settings.kernel, adaptive=self.settings.coalescence_adaptive, dt_coal_range=self.settings.coalescence_dt_coal_range, substeps=self.settings.coalescence_substeps, optimized_random=self.settings.coalescence_optimized_random )) products.append(PySDM_products.CoalescenceTimestepMean()) products.append(PySDM_products.CoalescenceTimestepMin()) products.append(PySDM_products.CollisionRate()) products.append(PySDM_products.CollisionRateDeficit()) attributes = environment.init_attributes( spatial_discretisation=spatial_sampling.Pseudorandom(), spectral_discretisation=spectral_sampling.ConstantMultiplicity( spectrum=self.settings.spectrum_per_mass_of_dry_air), kappa=self.settings.kappa) self.core = builder.build(attributes, products) SpinUp(self.core, self.settings.n_spin_up) if self.storage is not None: self.storage.init(self.settings)
def __init__(self, settings, products=None): env = Parcel(dt=settings.dt, mass_of_dry_air=settings.mass_of_dry_air, p0=settings.p0, q0=settings.q0, T0=settings.T0, w=settings.w, g=settings.g) builder = Builder(n_sd=settings.n_sd, backend=CPU, formulae=settings.formulae) builder.set_environment(env) attributes = env.init_attributes(n_in_dv=settings.n_in_dv, kappa=settings.kappa, r_dry=settings.r_dry) attributes = { **attributes, **settings.starting_amounts, 'pH': np.zeros(settings.n_sd) } builder.add_dynamic(AmbientThermodynamics()) builder.add_dynamic(Condensation(kappa=settings.kappa)) builder.add_dynamic( AqueousChemistry(settings.ENVIRONMENT_MOLE_FRACTIONS, system_type=settings.system_type, n_substep=settings.n_substep, dry_rho=settings.DRY_RHO, dry_molar_mass=settings.dry_molar_mass)) products = products or ( PySDM_products.RelativeHumidity(), PySDM_products.WaterMixingRatio(name='ql', description_prefix='liquid', radius_range=[1 * si.um, np.inf]), PySDM_products.ParcelDisplacement(), PySDM_products.Pressure(), PySDM_products.Temperature(), PySDM_products.DryAirDensity(), PySDM_products.WaterVapourMixingRatio(), PySDM_products.Time(), *[ PySDM_products.AqueousMoleFraction(compound) for compound in AQUEOUS_COMPOUNDS.keys() ], *[ PySDM_products.GaseousMoleFraction(compound) for compound in GASEOUS_COMPOUNDS.keys() ], PySDM_products.pH(radius_range=settings.cloud_radius_range, weighting='number', attr='pH'), PySDM_products.pH(radius_range=settings.cloud_radius_range, weighting='volume', attr='pH'), PySDM_products.pH(radius_range=settings.cloud_radius_range, weighting='number', attr='conc_H'), PySDM_products.pH(radius_range=settings.cloud_radius_range, weighting='volume', attr='conc_H'), PySDM_products.TotalDryMassMixingRatio( settings.DRY_RHO), PySDM_products.PeakSupersaturation(), PySDM_products.CloudDropletConcentration( radius_range=settings.cloud_radius_range), PySDM_products.AqueousMassSpectrum("S_VI", settings.dry_radius_bins_edges)) self.core = builder.build(attributes=attributes, products=products) self.settings = settings
def run_parcel( w, sol2, N2, rad2, n_sd_per_mode, RH0=1.0, T0=294 * si.K, p0=1e5 * si.Pa, n_steps=50, mass_of_dry_air=1e3 * si.kg, dt=2 * si.s, ): products = ( PySDM_products.WaterMixingRatio(unit="g/kg", name="ql"), PySDM_products.PeakSupersaturation(name="S max"), PySDM_products.AmbientRelativeHumidity(name="RH"), PySDM_products.ParcelDisplacement(name="z"), ) formulae = Formulae() const = formulae.constants pv0 = RH0 * formulae.saturation_vapour_pressure.pvs_Celsius(T0 - const.T0) q0 = const.eps * pv0 / (p0 - pv0) env = Parcel(dt=dt, mass_of_dry_air=mass_of_dry_air, p0=p0, q0=q0, w=w, T0=T0) aerosol = AerosolARG(M2_sol=sol2, M2_N=N2, M2_rad=rad2) n_sd = n_sd_per_mode * len(aerosol.modes) builder = Builder(backend=CPU(), n_sd=n_sd) builder.set_environment(env) builder.add_dynamic(AmbientThermodynamics()) builder.add_dynamic(Condensation()) builder.add_dynamic(Magick()) attributes = { k: np.empty(0) for k in ("dry volume", "kappa times dry volume", "n") } for i, mode in enumerate(aerosol.modes): kappa, spectrum = mode["kappa"]["CompressedFilmOvadnevaite"], mode[ "spectrum"] r_dry, concentration = ConstantMultiplicity(spectrum).sample( n_sd_per_mode) v_dry = builder.formulae.trivia.volume(radius=r_dry) specific_concentration = concentration / builder.formulae.constants.rho_STP attributes["n"] = np.append( attributes["n"], specific_concentration * env.mass_of_dry_air) attributes["dry volume"] = np.append(attributes["dry volume"], v_dry) attributes["kappa times dry volume"] = np.append( attributes["kappa times dry volume"], v_dry * kappa) r_wet = equilibrate_wet_radii( r_dry=builder.formulae.trivia.radius(volume=attributes["dry volume"]), environment=env, kappa_times_dry_volume=attributes["kappa times dry volume"], ) attributes["volume"] = builder.formulae.trivia.volume(radius=r_wet) particulator = builder.build(attributes, products=products) bdf.patch_particulator(particulator) output = {product.name: [] for product in particulator.products.values()} output_attributes = { "n": tuple([] for _ in range(particulator.n_sd)), "volume": tuple([] for _ in range(particulator.n_sd)), "critical volume": tuple([] for _ in range(particulator.n_sd)), "critical supersaturation": tuple([] for _ in range(particulator.n_sd)), } for _ in range(n_steps): particulator.run(steps=1) for product in particulator.products.values(): value = product.get() output[product.name].append(value[0]) for key, attr in output_attributes.items(): attr_data = particulator.attributes[key].to_ndarray() for drop_id in range(particulator.n_sd): attr[drop_id].append(attr_data[drop_id]) error = np.zeros(len(aerosol.modes)) activated_fraction_S = np.zeros(len(aerosol.modes)) activated_fraction_V = np.zeros(len(aerosol.modes)) for j, mode in enumerate(aerosol.modes): activated_drops_j_S = 0 activated_drops_j_V = 0 RHmax = np.nanmax(np.asarray(output["RH"])) for i, volume in enumerate(output_attributes["volume"]): if j * n_sd_per_mode <= i < (j + 1) * n_sd_per_mode: if output_attributes["critical supersaturation"][i][-1] < RHmax: activated_drops_j_S += output_attributes["n"][i][-1] if output_attributes["critical volume"][i][-1] < volume[-1]: activated_drops_j_V += output_attributes["n"][i][-1] Nj = np.asarray(output_attributes["n"])[j * n_sd_per_mode:(j + 1) * n_sd_per_mode, -1] max_multiplicity_j = np.max(Nj) sum_multiplicity_j = np.sum(Nj) error[j] = max_multiplicity_j / sum_multiplicity_j activated_fraction_S[j] = activated_drops_j_S / sum_multiplicity_j activated_fraction_V[j] = activated_drops_j_V / sum_multiplicity_j Output = namedtuple( "Output", [ "profile", "attributes", "aerosol", "activated_fraction_S", "activated_fraction_V", "error", ], ) return Output( profile=output, attributes=output_attributes, aerosol=aerosol, activated_fraction_S=activated_fraction_S, activated_fraction_V=activated_fraction_V, error=error, )
def __init__(self, settings, backend=CPU): self.nt = settings.nt self.z0 = -settings.particle_reservoir_depth builder = Builder(n_sd=settings.n_sd, backend=backend(formulae=settings.formulae)) mesh = Mesh( grid=(settings.nz, ), size=(settings.z_max + settings.particle_reservoir_depth, ), ) env = Kinematic1D( dt=settings.dt, mesh=mesh, thd_of_z=settings.thd, rhod_of_z=settings.rhod, z0=-settings.particle_reservoir_depth, ) def zZ_to_z_above_reservoir(zZ): z_above_reservoir = zZ * (settings.nz * settings.dz) + self.z0 return z_above_reservoir self.mpdata = MPDATA_1D( nz=settings.nz, dt=settings.dt, mpdata_settings=settings.mpdata_settings, advector_of_t=lambda t: settings.rho_times_w(t) * settings.dt / settings.dz, advectee_of_zZ_at_t0=lambda zZ: settings.qv( zZ_to_z_above_reservoir(zZ)), g_factor_of_zZ=lambda zZ: settings.rhod(zZ_to_z_above_reservoir(zZ) ), ) _extra_nz = settings.particle_reservoir_depth // settings.dz _z_vec = settings.dz * np.linspace(-_extra_nz, settings.nz - _extra_nz, settings.nz + 1) self.g_factor_vec = settings.rhod(_z_vec) builder.set_environment(env) builder.add_dynamic(AmbientThermodynamics()) builder.add_dynamic( Condensation( adaptive=settings.condensation_adaptive, rtol_thd=settings.condensation_rtol_thd, rtol_x=settings.condensation_rtol_x, )) builder.add_dynamic(EulerianAdvection(self.mpdata)) if settings.precip: if settings.breakup: builder.add_dynamic( Collision( collision_kernel=Geometric(collection_efficiency=1), coalescence_efficiency=ConstEc(Ec=0.95), breakup_efficiency=ConstEb(Eb=1.0), fragmentation_function=ExponFrag(scale=100 * si.um), adaptive=settings.coalescence_adaptive, )) else: builder.add_dynamic( Coalescence( collision_kernel=Geometric(collection_efficiency=1), adaptive=settings.coalescence_adaptive, )) displacement = Displacement( enable_sedimentation=settings.precip, precipitation_counting_level_index=int( settings.particle_reservoir_depth / settings.dz), ) builder.add_dynamic(displacement) attributes = env.init_attributes( spatial_discretisation=spatial_sampling.Pseudorandom(), spectral_discretisation=spectral_sampling.ConstantMultiplicity( spectrum=settings.wet_radius_spectrum_per_mass_of_dry_air), kappa=settings.kappa, ) products = [ PySDM_products.AmbientRelativeHumidity(name="RH", unit="%"), PySDM_products.AmbientPressure(name="p"), PySDM_products.AmbientTemperature(name="T"), PySDM_products.AmbientWaterVapourMixingRatio(name="qv"), PySDM_products.WaterMixingRatio( name="ql", unit="g/kg", radius_range=settings.cloud_water_radius_range), PySDM_products.WaterMixingRatio( name="qr", unit="g/kg", radius_range=settings.rain_water_radius_range), PySDM_products.AmbientDryAirDensity(name="rhod"), PySDM_products.AmbientDryAirPotentialTemperature(name="thd"), PySDM_products.ParticleSizeSpectrumPerVolume( name="dry spectrum", radius_bins_edges=settings.r_bins_edges, dry=True), PySDM_products.ParticleSizeSpectrumPerVolume( name="wet spectrum", radius_bins_edges=settings.r_bins_edges), PySDM_products.ParticleConcentration( name="nc", radius_range=settings.cloud_water_radius_range), PySDM_products.ParticleConcentration( name="na", radius_range=(0, settings.cloud_water_radius_range[0])), PySDM_products.MeanRadius(), PySDM_products.RipeningRate(), PySDM_products.ActivatingRate(), PySDM_products.DeactivatingRate(), PySDM_products.EffectiveRadius( radius_range=settings.cloud_water_radius_range), PySDM_products.PeakSupersaturation(unit="%"), PySDM_products.SuperDropletCountPerGridbox(), ] self.particulator = builder.build(attributes=attributes, products=products)
def reinit(self, products=None): formulae = self.settings.formulae backend = self.backend_class(formulae=formulae) builder = Builder(n_sd=self.settings.n_sd, backend=backend) environment = Kinematic2D( dt=self.settings.dt, grid=self.settings.grid, size=self.settings.size, rhod_of=self.settings.rhod_of_zZ, mixed_phase=self.settings.processes["freezing"], ) builder.set_environment(environment) if products is not None: products = list(products) else: products = make_default_product_collection(self.settings) if self.settings.processes["fluid advection"]: builder.add_dynamic(AmbientThermodynamics()) if self.settings.processes["condensation"]: condensation = Condensation( rtol_x=self.settings.condensation_rtol_x, rtol_thd=self.settings.condensation_rtol_thd, adaptive=self.settings.condensation_adaptive, substeps=self.settings.condensation_substeps, dt_cond_range=self.settings.condensation_dt_cond_range, schedule=self.settings.condensation_schedule, ) builder.add_dynamic(condensation) displacement = None if self.settings.processes["particle advection"]: displacement = Displacement( enable_sedimentation=self.settings.processes["sedimentation"], adaptive=self.settings.displacement_adaptive, rtol=self.settings.displacement_rtol, ) if self.settings.processes["fluid advection"]: initial_profiles = { "th": self.settings.initial_dry_potential_temperature_profile, "qv": self.settings.initial_vapour_mixing_ratio_profile, } advectees = dict(( key, np.repeat( profile.reshape(1, -1), environment.mesh.grid[0], axis=0), ) for key, profile in initial_profiles.items()) solver = MPDATA_2D( advectees=advectees, stream_function=self.settings.stream_function, rhod_of_zZ=self.settings.rhod_of_zZ, dt=self.settings.dt, grid=self.settings.grid, size=self.settings.size, displacement=displacement, n_iters=self.settings.mpdata_iters, infinite_gauge=self.settings.mpdata_iga, nonoscillatory=self.settings.mpdata_fct, third_order_terms=self.settings.mpdata_tot, ) builder.add_dynamic(EulerianAdvection(solver)) if self.settings.processes["particle advection"]: builder.add_dynamic(displacement) if self.settings.processes["coalescence"]: builder.add_dynamic( Coalescence( collision_kernel=self.settings.kernel, adaptive=self.settings.coalescence_adaptive, dt_coal_range=self.settings.coalescence_dt_coal_range, substeps=self.settings.coalescence_substeps, optimized_random=self.settings. coalescence_optimized_random, )) if self.settings.processes["freezing"]: builder.add_dynamic( Freezing(singular=self.settings.freezing_singular)) attributes = environment.init_attributes( spatial_discretisation=spatial_sampling.Pseudorandom(), dry_radius_spectrum=self.settings.spectrum_per_mass_of_dry_air, kappa=self.settings.kappa, ) if self.settings.processes["freezing"]: if self.settings.freezing_inp_spec is None: immersed_surface_area = formulae.trivia.sphere_surface( diameter=2 * formulae.trivia.radius(volume=attributes["dry volume"])) else: immersed_surface_area = self.settings.freezing_inp_spec.percentiles( np.random.random(self.settings.n_sd), # TODO #599: seed ) if self.settings.freezing_singular: attributes[ "freezing temperature"] = formulae.freezing_temperature_spectrum.invcdf( np.random.random( self.settings.n_sd), # TODO #599: seed immersed_surface_area, ) else: attributes["immersed surface area"] = immersed_surface_area self.particulator = builder.build(attributes, tuple(products)) if self.SpinUp is not None: self.SpinUp(self.particulator, self.settings.n_spin_up) if self.storage is not None: self.storage.init(self.settings)