from PySDM.physics.aqueous_chemistry.support import M, EquilibriumConsts from PySDM.physics.constants import ROOM_TEMP, K_H2O from PySDM.physics.formulae import Formulae from PySDM.backends.numba.impl._chemistry_methods import ChemistryMethods from PySDM.dynamics import aqueous_chemistry from chempy import Equilibrium from chempy.equilibria import EqSystem from chempy.chemistry import Species import numpy as np import pytest from collections import defaultdict formulae = Formulae() EQUILIBRIUM_CONST = EquilibriumConsts(formulae).EQUILIBRIUM_CONST class Test_pH: @staticmethod def test_equilibrate_pH_pure_water(): # Arrange eqs = {} for key in EQUILIBRIUM_CONST.keys(): eqs[key] = np.full(1, EQUILIBRIUM_CONST[key].at(ROOM_TEMP)) # Act result = np.empty(1) ChemistryMethods.equilibrate_H_body( within_tolerance=formulae.trivia.within_tolerance, pH2H=formulae.trivia.pH2H, H2pH=formulae.trivia.H2pH,
def __init__(self): self.HENRY_CONST = HenryConsts(self.formulae) self.KINETIC_CONST = KineticConsts(self.formulae) self.EQUILIBRIUM_CONST = EquilibriumConsts(self.formulae)
from PySDM.physics.aqueous_chemistry.support import KineticConsts, EquilibriumConsts, \ DISSOCIATION_FACTORS, k4 from PySDM.physics.constants import T_STP, pi_4_3 import pytest formulae = Formulae() class SUT(ChemistryMethods): def __init__(self): self.formulae = formulae super().__init__() kinetic_consts = KineticConsts(formulae) equilibrium_consts = EquilibriumConsts(formulae) T = T_STP k0 = Storage.from_ndarray(np.full(1, kinetic_consts.KINETIC_CONST['k0'].at(T))) k1 = Storage.from_ndarray(np.full(1, kinetic_consts.KINETIC_CONST['k1'].at(T))) k2 = Storage.from_ndarray(np.full(1, kinetic_consts.KINETIC_CONST['k2'].at(T))) k3 = Storage.from_ndarray(np.full(1, kinetic_consts.KINETIC_CONST['k3'].at(T))) K_SO2 = Storage.from_ndarray( np.full(1, equilibrium_consts.EQUILIBRIUM_CONST['K_SO2'].at(T))) K_HSO3 = Storage.from_ndarray( np.full(1, equilibrium_consts.EQUILIBRIUM_CONST['K_HSO3'].at(T))) volume = pi_4_3 * (1 * si.um)**3 pH = 5. n_sd = 1
def test_calc_ionic_strength(nt, n_sd): formulae = Formulae() EQUILIBRIUM_CONST = EquilibriumConsts(formulae).EQUILIBRIUM_CONST K_NH3 = EQUILIBRIUM_CONST["K_NH3"].at(ROOM_TEMP) K_SO2 = EQUILIBRIUM_CONST["K_SO2"].at(ROOM_TEMP) K_HSO3 = EQUILIBRIUM_CONST["K_HSO3"].at(ROOM_TEMP) K_HSO4 = EQUILIBRIUM_CONST["K_HSO4"].at(ROOM_TEMP) K_HCO3 = EQUILIBRIUM_CONST["K_HCO3"].at(ROOM_TEMP) K_CO2 = EQUILIBRIUM_CONST["K_CO2"].at(ROOM_TEMP) K_HNO3 = EQUILIBRIUM_CONST["K_HNO3"].at(ROOM_TEMP) settings = Settings(dt=1, n_sd=n_sd, n_substep=5) settings.t_max = nt * settings.dt simulation = Simulation(settings) simulation.run() H = simulation.particulator.attributes['conc_N_mIII'].data conc = { 'H+': H, 'N-3': simulation.particulator.attributes['conc_N_mIII'].data, 'N+5': simulation.particulator.attributes['conc_N_V'].data, 'S+4': simulation.particulator.attributes['conc_S_IV'].data, 'S+6': simulation.particulator.attributes['conc_S_VI'].data, 'C+4': simulation.particulator.attributes['conc_C_IV'].data, } alpha_C = (1 + K_CO2 / conc['H+'] + K_CO2 * K_HCO3 / conc['H+']**2) alpha_S = (1 + K_SO2 / conc['H+'] + K_SO2 * K_HSO3 / conc['H+']**2) alpha_N3 = (1 + conc['H+'] * K_NH3 / K_H2O) alpha_N5 = (1 + K_HNO3 / conc['H+']) actual = calc_ionic_strength(H=conc['H+'], N_mIII=conc['N-3'], N_V=conc['N+5'], C_IV=conc['C+4'], S_IV=conc['S+4'], S_VI=conc['S+6'], K_NH3=K_NH3, K_SO2=K_SO2, K_HSO3=K_HSO3, K_HSO4=K_HSO4, K_HCO3=K_HCO3, K_CO2=K_CO2, K_HNO3=K_HNO3) expected = ionic_strength( { 'H+': conc['H+'] / rho_w, 'HCO3-': K_CO2 / conc['H+'] * conc['C+4'] / alpha_C / rho_w, 'CO3-2': K_CO2 / conc['H+'] * K_HCO3 / conc['H+'] * conc['C+4'] / alpha_C / rho_w, 'HSO3-': K_SO2 / conc['H+'] * conc['S+4'] / alpha_S / rho_w, 'SO3-2': K_SO2 / conc['H+'] * K_HSO3 / conc['H+'] * conc['S+4'] / alpha_S / rho_w, 'NH4+': K_NH3 / K_H2O * conc['H+'] * conc['N-3'] / alpha_N3 / rho_w, 'NO3-': K_HNO3 / conc['H+'] * conc['N+5'] / alpha_N5 / rho_w, 'HSO4-': conc['H+'] * conc['S+6'] / (conc['H+'] + K_HSO4) / rho_w, 'SO4-2': K_HSO4 * conc['S+6'] / (conc['H+'] + K_HSO4) / rho_w, 'OH-': K_H2O / conc['H+'] / rho_w }, warn=False) * rho_w np.testing.assert_allclose(actual, expected, rtol=1e-15)