def data(n_output, rtols, schemes, setups_num): resultant_data = {} for scheme in schemes: resultant_data[scheme] = {} if scheme == "BDF": for rtol in rtols: resultant_data[scheme][rtol] = [] for settings_idx in range(setups_num): settings = setups[settings_idx] settings.n_output = n_output simulation = Simulation(settings) bdf.patch_particulator(simulation.particulator) results = simulation.run() for rtol in rtols: resultant_data[scheme][rtol].append(results) else: for rtol in rtols: resultant_data[scheme][rtol] = [] for settings_idx in range(setups_num): settings = setups[settings_idx] settings.rtol_x = rtol settings.rtol_thd = rtol settings.n_output = n_output simulation = Simulation( settings, backend=CPU if scheme == "CPU" else GPU) results = simulation.run() resultant_data[scheme][rtol].append(results) return resultant_data
def test_water_mass_conservation(settings_idx, mass_of_dry_air, scheme, coord): # Arrange assert scheme in ('BDF', 'CPU', 'GPU') settings = Settings(w_avg=setups[settings_idx].w_avg, N_STP=setups[settings_idx].N_STP, r_dry=setups[settings_idx].r_dry, mass_of_dry_air=mass_of_dry_air, coord=coord) settings.n_output = 50 settings.coord = coord simulation = Simulation(settings, GPU if scheme == 'GPU' else CPU) qt0 = settings.q0 + liquid_water_mixing_ratio(simulation) if scheme == 'BDF': bdf.patch_particulator(simulation.particulator) # Act simulation.particulator.products['S_max'].get() output = simulation.run() # Assert ql = liquid_water_mixing_ratio(simulation) qt = simulation.particulator.environment["qv"].to_ndarray() + ql significant = 6 if scheme == 'GPU' else 14 # TODO #540 np.testing.assert_approx_equal(qt, qt0, significant) if scheme != 'BDF': assert simulation.particulator.products['S_max'].get( ) >= output['S'][-1]
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 test_just_do_it(scheme, adaptive, backend_class=CPU): # Arrange if scheme == 'BDF' and (not adaptive or backend_class is GPU): return settings = Settings(dt_output=10 * si.second) settings.adaptive = adaptive if scheme == 'BDF': settings.dt_max = settings.dt_output # TODO #334 'BDF') elif not adaptive: settings.dt_max = 1 * si.second simulation = Simulation(settings, backend_class) if scheme == 'BDF': bdf.patch_particulator(simulation.particulator) # Act output = simulation.run() r = np.array(output['r']).T * si.metres n = settings.n / (settings.mass_of_dry_air * si.kilogram) # Assert condition = (r > 1 * si.micrometre) NTOT = n_tot(n, condition) N1 = NTOT[:int(1 / 3 * len(NTOT))] N2 = NTOT[int(1 / 3 * len(NTOT)):int(2 / 3 * len(NTOT))] N3 = NTOT[int(2 / 3 * len(NTOT)):] n_unit = 1 / si.microgram assert min(N1) == 0.0 * n_unit assert .6 * n_unit < max(N1) < .8 * n_unit assert .17 * n_unit < min(N2) < .18 * n_unit assert .35 * n_unit < max(N2) < .41 * n_unit assert .1 * n_unit < min(N3) < .11 * n_unit assert .27 * n_unit < max(N3) < .4 * n_unit # TODO #527 if backend_class is not GPU: assert max(output['ripening rate']) > 0
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 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, )