コード例 #1
0
def test_partit_var(): # define testing function

	# import functions
	import partit_var
	import ode_solv

	# get Kelvin factor (curvature effect)
	# call on function to calculate Kelvin factor
	[kimt, kelv_fac] = partit_var.kimt_calc(y, mfp, num_sb, num_comp, accom_coeff, y_mw,   
		surfT, R_gas, TEMP, NA, y_dens, N_perbin, DStar_org, 
		x.reshape(1, -1)*1.0e-6, Psat, therm_sp, H2Oi, act_coeff, wall_on, 1)
	
	# call on ode_gen to get solute (Raoult) effect (mole fraction of water in particles)
	mf = ode_solv.ode_solv(y, 1., [], [], [], [],
		[], [], [], [], [], [], [],
		[], [], [], [], [], [], 
		[], [], [], 
		[], [], [], [], [], num_comp, 
		num_sb, wall_on, Psat, [], act_coeff, [], [],
		(num_comp-1), core_diss, kelv_fac, kimt, (num_sb-wall_on), 
		[],
		[], [], [], [],
		[], [], [], [], [], [], 
		[], [], [], [], [], 
		[], [], [], 
		[], [], [], [])

	
	fig, (ax0) = plt.subplots(1, 1, figsize=(6,5))
	ax0.semilogx(x, kelv_fac, label='Curvature (Kelvin) effect')
	ax0.semilogx(x, mf[:, 0].reshape(-1, 1), label='Solute (Raoult) effect')
	# note that the Raoult (solute) effect is calculated differently to eq. 16.39 of
	# Jacobson, the PyCHAM calculation is the mole fraction.  Following eq. 3 of 
	# Riipinen et al. (2010): doi:10.1016/j.atmosenv.2009.11.022, we get the equilibrium
	# saturation ratio by the product of the two effects
	# Whereas the exact inputs used for Fig. 16.1 of Jacobson (2005) are unknown, the 
	# plot here should have similar features despite probably not giving an exact
	# replication
	ax0.semilogx(x, (kelv_fac*(mf[:, 0].reshape(-1, 1))), '--', label='Equilibrium saturation ratio')
	ax0.set_ylim([0.98, 1.02e0])
	ax0.set_xlabel(r'Particle radius ($\rm{\mu}$m)', fontsize=10)
	ax0.set_ylabel(r'Saturation ratio', fontsize=10)
	ax0.legend()
	plt.show()			
コード例 #2
0
ファイル: rec_prep.py プロジェクト: simonom/PyCHAM
def rec_prep(nrec_step, y, y0, rindx, rstoi, pindx, pstoi, nprod, nreac,
             num_sb, num_comp, N_perbin, core_diss, Psat, mfp, accom_coeff,
             y_mw, surfT, R_gas, temp, tempt, NA, y_dens, x, therm_sp, H2Oi,
             act_coeff, RO2_indx, sumt, Pnow, light_stat, light_time,
             light_time_cnt, daytime, lat, lon, af_path, dayOfYear, photo_path,
             Jlen, Cw, kw, Cfactor, tf, light_ad, wall_on, Vbou, tnew, nuc_ad,
             nucv1, nucv2, nucv3, np_sum, update_stp, update_count, injectt,
             gasinj_cnt, inj_indx, Ct, pmode, pconc, pconct, seedt_cnt,
             mean_rad, corei, seed_name, seedx, lowsize, uppsize, rad0, radn,
             std, rbou, const_infl_t, infx_cnt, con_infl_C, MV, partit_cutoff,
             diff_vol, DStar_org, seedi, C_p2w, RH, RHt, tempt_cnt, RHt_cnt,
             Pybel_objects, nuci, nuc_comp, t0, pcont, pcontf, NOi, HO2i, NO3i,
             z_prt_coeff, seed_eq_wat, Vwat_inc, tot_in_res, Compti, tot_time,
             cont_inf_reci, cont_inf_i, tot_in_res_indx, tf_UVC, chamSA, chamV,
             kwf):

    # inputs: --------------------------------------------------------
    # nrec_step - number of steps to record on
    # y - initial concentrations (# molecules/cm3 (air))
    # y0 - component concentrations prior to integration step (# molecules/cm3 (air))
    # rindx - indices of reactants
    # rstoi - stoichiometries of reactants
    # pindx - indices of products
    # pstoi - stoichiometries of products
    # nprod - number of products
    # nreac - number of reactants
    # num_sb - number of size bins
    # num_comp - number of components
    # N_perbin - particle concentration per size bin (#/cc (air))
    # core_diss - dissociation constant of seed
    # Psat - pure component saturation vapour pressure
    #	(# molecules/cm3 (air))
    # mfp - mean free path (m)
    # accom_coeff - accommodation coefficient
    # y_mw - molecular weight (g/mol)
    # surfT - surface tension (g/s2)
    # R_gas - ideal gas constant (kg.m2.s-2.K-1.mol-1)
    # temp - temperature (K)
    # tempt - times temperatures achieved (s)
    # NA - Avogadro constants (molecules/mol)
    # y_dens - component densities (g/cm3)
    # x - particle radii (um)
    # therm_sp - thermal speed (m/s)
    # H2Oi - index for water
    # act_coeff - activity coefficient
    # RO2_indx - index of peroxy radicals
    # sumt - cumulative time through simulation (s)
    # Pnow - chamber pressure (Pa)
    # light_stat - light status
    # light_time - times corresponding to light status
    # light_time_cnt - count on light status array
    # daytime - start time of simulation (s)
    # lat - latitude
    # lon - longitude
    # af_path - path to actinic flux file
    # dayOfYear - day of year
    # photo_path - path to photochemistry file
    # Jlen - length of photochemistry equations
    # Cw - effective absorbing mass of wall (molecules/cc (air))
    # kw - gas-wall partitioning coefficient (/s)
    # Cfactor - conversion factor (ppb/molecules/cc)
    # tf - transmission factor for natural sunlight
    # light_ad - marker for whether to adapt time interval to
    #		changing natural light intensity
    # wall_on - marker for whether wall present
    # Vbou - volume boundary of particle size bins (um3)
    # tnew - the proposed integration time interval (s)
    # nuc_ad - marker for whether to adapt time step based on
    #	nucleation
    # nucv1 - nucleation parameter one
    # nucv2 - nucleation parameter two
    # nucv3 - nucleation parameter three
    # np_sum - cumulative number concentration of new
    #	particles so far (#/cc (air))
    # update_stp - time interval between operator-split processes
    # update_count - count on time since last operator-split (s)
    # injectt - time of instantaneous injection of components (s)
    # gasinj_cnt - count on injection times of components
    # inj_indx - index of component(s) being injected after
    #	experiment start
    # Ct - concentration(s) (ppb) of component(s) injected
    # instantaneously after experiment start
    # pmode - whether number size distributions expressed as modes or explicitly
    # pconc - concentration of injected particles (#/cc (air))
    # pconct - times of particle injection (s)
    # seedt_cnt - count on injection of seed particles
    # mean_rad - mean radius for particle number size
    #	distribution (um)
    # corei - index of core component
    # seed_name - name(s) of component(s) comprising seed particles
    # seedx - mole ratio of components comprising seed particles
    # lowsize - lower size bin boundary (um)
    # uppsize - upper size bin boundary (um)
    # rad0 - initial radius at size bin centres (um)
    # radn - current radius at size bin centres (um)
    # std - standard deviation for injected particle number size
    #	distributions
    # rbou - size bin radius bounds (um)
    # const_infl_t - times for constant influxes (s)
    # infx_cnt - count on constant influx occurrences
    # con_infl_C - influx rates of components with constant influx
    #	(ppb/s)
    # MV - molar volume (cc/mol)
    # partit_cutoff - the product of saturation vapour pressure and
    #		activity coefficient above which gas-particle
    #		partitioning assumed zero (Pa)
    # diff_vol - diffusion volume of components according to Fuller et al. (1969)
    # DStar_org - gas-phase diffusion coefficient of components (cm2/s)
    # seedi - index of seed component(s)
    # C_p2w - concentration of components on the wall due to particle
    # deposition to wall (molecules/cc)
    # RH - relative humidities (fraction 0-1)
    # RHt - times through experiment at which relative humidities reached (s)
    # tempt_cnt - count on chamber temperatures
    # RHt_cnt - chamber relative humidity counts
    # Pybel_objects - the pybel objects for components
    # nuci - index of nucleating component
    # nuc_comp - name of nucleating component
    # t0 - initial integration step (s)
    # pcont - flag for whether particle injection instantaneous or continuous
    # pcontf - current status of particle injection (instantaneous or continuous)
    # NOi - index of NO
    # HO2i - index of HO2
    # NO3i - index of NO3
    # z_prt_coeff - fraction of total gas-particle partitioning coefficient
    #	below which partitioning to a particle size bin is treated as zero,
    #	e.g. because surface area of that size bin is tiny
    # seed_eq_wat - whether seed particles to be equilibrated with water prior to ODE solver
    # Vwat_inc - whether suppled seed particle volume contains equilibrated water
    # tot_in_res - record of total input of injected components (ug/m3)
    # Compti - index for total injection record for instantaneously injected components
    # tot_time - total experiment time (s)
    # cont_inf_reci - index of components with continuous influx in record
    # cont_inf_i - index of components with continuous influx in concentration array
    # tot_in_res_indx - index of components with recorded influx
    # tf_UVC - transmission factor for 254 nm wavelength light (0-1)
    # chamSA - chamber surface area (m2)
    # chamV - chamber volume (m3)
    # kwf - flag for treatment of gas-wall partitioning coefficient
    # ----------------------------------------------------------------

    # note that instaneous changes occur before recording --------------------
    # update chamber variables

    # array to record cumulative influxes of influxing components
    tot_in_res_ft = np.zeros((nrec_step + 1, len(tot_in_res)))
    # index of components being stored for influx
    tot_in_res_ft[0, :] = tot_in_res_indx
    tot_in_res_ft[1, :] = tot_in_res  # influx at start

    [
        temp_now, Pnow, lightm, light_time_cnt, tnew, ic_red, update_stp,
        update_count, Cinfl_now, seedt_cnt, Cfactor, infx_cnt, gasinj_cnt,
        DStar_org, y, tempt_cnt, RHt_cnt, Psat, N_perbin, x, pconcn_frac,
        pcontf, tot_in_res, Cinfl_nowp_indx, Cinfl_nowp
    ] = cham_up.cham_up(
        sumt, temp, tempt, Pnow, light_stat, light_time, light_time_cnt,
        light_ad, 0, nuc_ad, nucv1, nucv2, nucv3, np_sum, update_stp,
        update_count, lat, lon, dayOfYear, photo_path, af_path, injectt,
        gasinj_cnt, inj_indx, Ct, pmode, pconc, pconct, seedt_cnt, num_comp,
        y0, y, N_perbin, mean_rad, corei, seedx, seed_name, lowsize, uppsize,
        num_sb, MV, rad0, radn, std, y_dens, H2Oi, rbou, const_infl_t,
        infx_cnt, con_infl_C, wall_on, Cfactor, seedi, diff_vol, DStar_org, RH,
        RHt, tempt_cnt, RHt_cnt, Pybel_objects, nuci, nuc_comp, y_mw, temp[0],
        Psat, 0, t0, x, pcont, pcontf, 0., surfT, act_coeff, seed_eq_wat,
        Vwat_inc, tot_in_res, Compti, tot_time, cont_inf_reci, cont_inf_i)

    # note that recording occurs after any instaneous changes--------------------
    # array to record time through simulation (s)
    trec = np.zeros((nrec_step))
    # array to record concentrations with time (# molecules/cm3)
    yrec = np.zeros((nrec_step, len(y)))
    yrec[0, :] = y  # record initial concentrations (# molecules/cm3)
    # array to record conversion factor
    Cfactor_vst = np.zeros((nrec_step, 1))
    Cfactor_vst[0] = Cfactor

    # arrays to record particle radii and number size distributions
    if ((num_sb - wall_on) > 0):  # if particle size bins present
        x2 = np.zeros((nrec_step, (num_sb - wall_on)))
        Nres_dry = np.zeros((nrec_step, (num_sb - wall_on)))
        Nres_wet = np.zeros((nrec_step, (num_sb - wall_on)))
        rbou_rec = np.zeros((nrec_step, (num_sb - wall_on + 1)))
        # concentration of components on the wall due to
        # particle-wall loss, stacked by component first then by
        # size bin (molecules/cc)
        yrec_p2w = np.zeros((nrec_step, (num_sb - wall_on) * num_comp))
    else:
        x2 = 0.
        Nres_dry = 0.
        Nres_wet = 0.
        rbou_rec = 0.
        yrec_p2w = 0.

    if ((num_sb - wall_on) > 0
            or wall_on == 1):  # if particles or wall present

        # update partitioning variables
        [kimt, kelv_fac,
         kw] = partit_var.kimt_calc(y, mfp, num_sb, num_comp, accom_coeff,
                                    y_mw, surfT, R_gas, temp_now, NA,
                                    y_dens * 1.e3, N_perbin,
                                    x.reshape(1, -1) * 1.0e-6, Psat, therm_sp,
                                    H2Oi, act_coeff, wall_on, 1, partit_cutoff,
                                    Pnow, DStar_org, z_prt_coeff, chamSA,
                                    chamV, kwf)

    if (num_sb - wall_on) > 0:  # if particles present
        # single particle radius (um) at size bin centre
        # including contribution of water
        x2[0, :] = x

        # single particle size bin bounds including water (um)
        rbou_rec[0, :] = rbou

        # estimate particle number size distributions ----------------------------------
        Vnew = np.zeros((num_sb - wall_on))
        ish = N_perbin[:, 0] > 1.e-10

        if ish.sum() > 0:
            # rearrange particle concentrations into size bins in rows, components in columns
            Cn = y[num_comp:num_comp * (num_sb - wall_on + 1)].reshape(
                num_sb - wall_on, num_comp)
            # new volume of single particle per size bin (um3) excluding volume of water
            Vnew[ish] = (np.sum(
                (Cn[ish, :] /
                 (si.N_A * N_perbin[ish])) * MV[:, 0] * 1.e12, 1) -
                         ((Cn[ish, H2Oi] /
                           (si.N_A * N_perbin[ish, 0])) * MV[H2Oi, 0] * 1.e12))
            # loop through size bins to find number of particles in each
            # (# particle/cc (air))
            for Ni in range(0, (num_sb - wall_on)):
                ish = (Vnew >= Vbou[Ni]) * (Vnew < Vbou[Ni + 1])
                Nres_dry[0, Ni] = N_perbin[ish, 0].sum()
            Nres_wet[0, :] = N_perbin[:, 0]  # record with water

        # end of number size distribution part ----------------------------------------

        # concentration of components on the wall due to particle deposition to wall (# molecules/cm3)
        yrec_p2w[0, :] = C_p2w

    else:  # fillers
        kimt = kelv_fac = 0.

    # update reaction rate coefficients
    rrc = rrc_calc.rrc_calc(RO2_indx, y[H2Oi], temp_now, lightm, y,
                            daytime + sumt, lat, lon, af_path, dayOfYear, Pnow,
                            photo_path, Jlen, tf, y[NOi], y[HO2i], y[NO3i], 0.,
                            tf_UVC)

    # chamber environmental conditions ----------------------------------
    # initiate the array for recording chamber temperature (K), pressure (Pa)
    # and relative humidity (fraction (0-1))
    cham_env = np.zeros((nrec_step, 3))

    cham_env[0, 0] = temp_now  # temperature (K)
    cham_env[0, 1] = Pnow  # pressure (Pa)
    cham_env[0,
             2] = y[H2Oi] / Psat[0, H2Oi]  # relative humidity (fraction (0-1))

    # --------------------------------------------------------------------------------

    return (trec, yrec, Cfactor_vst, Nres_dry, Nres_wet, x2, seedt_cnt,
            rbou_rec, Cfactor, infx_cnt, yrec_p2w, temp_now, cham_env, Pnow,
            Psat, cham_env[0, 2], Cinfl_now, tot_in_res_ft)
コード例 #3
0
ファイル: ode_updater.py プロジェクト: baccandr/PyCHAM
def ode_updater(
        update_stp, tot_time, save_stp, y, rindx, pindx, rstoi, pstoi, nreac,
        nprod, jac_stoi, njac, jac_den_indx, jac_indx, RO2_indx, H2Oi, temp,
        tempt, Pnow, light_stat, light_time, daytime, lat, lon, af_path,
        dayOfYear, photo_path, Jlen, con_infl_C, nrec_steps, dydt_vst, siz_str,
        num_sb, num_comp, seedi, seed_name, seedVr, core_diss, Psat, mfp,
        therm_sp, accom_coeff, y_mw, surfT, R_gas, NA, y_dens, x, Varr,
        act_coeff, Cw, kw, Cfactor, tf, light_ad, y_arr, y_rind,
        uni_y_rind, y_pind, uni_y_pind, reac_col, prod_col, rstoi_flat,
        pstoi_flat, rr_arr, rr_arr_p, rowvals, colptrs, wall_on, jac_wall_indx,
        jac_part_indx, Vbou, N_perbin, Vol0, rad0, np_sum, new_partr, nucv1,
        nucv2, nucv3, nuci, nuc_comp, nuc_ad, RH, RHt, coag_on, inflectDp,
        pwl_xpre, pwl_xpro, inflectk, chamR, McMurry_flag, p_char, e_field,
        injectt, inj_indx, Ct, pmode, pconc, pconct, mean_rad, lowsize,
        uppsize, std, rbou, const_infl_t, MV, rindx_aq, pindx_aq, rstoi_aq,
        pstoi_aq, nreac_aq, nprod_aq, jac_stoi_aq, njac_aq, jac_den_indx_aq,
        jac_indx_aq, y_arr_aq, y_rind_aq, uni_y_rind_aq, y_pind_aq,
        uni_y_pind_aq, reac_col_aq, prod_col_aq, rstoi_flat_aq, pstoi_flat_aq,
        rr_arr_aq, rr_arr_p_aq, eqn_num, partit_cutoff, diff_vol, DStar_org,
        corei, ser_H2O, C_p2w, sch_name, sav_nam, comp_namelist, dydt_trak,
        space_mode, rbou00, ub_rad_amp, indx_plot, comp0, inname, rel_SMILES,
        Psat_Pa_rec, OC, wat_hist, Pybel_objects):

    # inputs: ----------------------------------------------------
    # update_stp - interval at which to update integration
    #		constants (s)
    # tot_time - total time to simulate (s)
    # save_stp - frequency to save results (s)
    # y - initial component concentrations (molecules/cc/s)
    # rindx - index of reactants per equation
    # pindx - index of products per equation
    # nreac - number of reactants per equation
    # nprod - number of products per equation
    # jac_stoi - stoichiometries relevant to Jacobian
    # njac - number of elements of Jacobian affected per equation
    # jac_den_indx - index of denominator components for Jacobian
    # jac_indx - index of Jacobian affected per equation
    # RO2_indx - index of components in peroxy radical list
    # H2Oi - index of water
    # temp - temperature in chamber (K)
    # tempt - times that temperatures reached (s)
    # Pnow - pressure inside chamber (Pa)
    # light_stat - lights status
    # light_time - time light status attained (s)
    # daytime - time of day experiment starts (s)
    # lat - latitude of experiment (degrees)
    # lon - longitude of experiment (degrees)
    # af_path - path to actinic flux values
    # dayOfYear - number of days since 31st December experiment held on
    # photo_path - path to file with absorption cross-sections
    # 		and quantum yields
    # Jlen - number of photochemical reactions
    # con_infl_C - influx of components with constant concentration
    # (molecules/cc/s)
    # nrec_step - number of recording steps
    # dydt_vst - dictionary for holding change tendencies of specified
    #		components
    # siz_str - the size structure
    # num_sb - number of particle size bins
    # num_comp - number of components
    # seedi - index of component(s) comprising seed material
    # seed_name - name(s) of component(s) comprising seed particles
    # seedVr - volume ratio of component(s) comprising seed material
    # core_diss - dissociation constant of seed
    # Psat - pure component saturation vapour pressure
    # 	(molecules/cc (air))
    # mfp - mean free path (m)
    # accom_coeff - accommodation coefficient
    # y_mw - molecular weight (g/mol)
    # surfT - surface tension (g/s2)
    # R_gas - ideal gas constant (kg.m2.s-2.K-1.mol-1)
    # NA - Avogadro's constant (molecules/mol)
    # y_dens - component densities (kg/m3)
    # x - particle radii (um)
    # Varr - particle volume (um3)
    # therm_sp - thermal speed (m/s)
    # act_coeff - activity coefficient
    # Cw - effective absorbing mass of wall (molecules/cc (air))
    # kw - gas-wall mass transfer coefficient (/s)
    # Cfactor - conversion factor for concentrations (ppb/molecules/cc)
    # tf - transmission factor for natural sunlight
    # light_ad - marker for whether to adapt time interval for
    #	changing natural light intensity
    # y_arr - index for arranging concentrations into matrix that
    # 	allows reaction rate coefficient calculation
    # y_rind - index for the concentration array  that
    # 	allows reaction rate coefficient calculation
    # uni_y_rind - unique index of reactants
    # y_pind - index for the concentration array  that
    # 	allows product gains to be indexed
    # uni_y_pind - unique index of products
    # reac_col - column indices for sparse matrix of reaction
    #		losses
    # prod_col - column indices for sparse matrix of production
    #		gains
    # rstoi_flat - 1D array of reactant stoichiometries per
    #	equation
    # pstoi_flat - 1D array of product stoichiometries per
    #	equation
    # rr_arr - index for reaction rates to allow reactant loss
    # 	calculation
    # rr_arr_p - index for reaction rates to allow product gain
    #	calculation
    # rowvals - row indices of Jacobian elements
    # colptrs - indices of  rowvals corresponding to each column of
    # 	the Jacobian
    # wall_on - marker for whether wall partitioning turned on
    # Cw - effective absorbing mass concentration of wall
    #	(molecules/cc (air))
    # kw - mass transfer coefficient of wall partitioning (/s)
    # jac_wall_indx - index of inputs to Jacobian from wall
    # 	partitioning
    # jac_part_indx - index of inputs to Jacobian from particle
    #	partitioning
    # Vbou - volume boundary of size bins (um3)
    # N_perbin - number concentration of particles per size bin
    #	(#/cc (air))
    # Vol0 - initial single particle volumes per size bin (um3)
    # rad0 - initial radius at particle centres (um)
    # np_sum - number concentration of newly nucleated particles
    #		(#/cc (air))
    # new_partr - radius of newly nucleated particles (cm)
    # nucv1, v2, v3 - nucleation parameters
    # nuci - index of nucleating component
    # nuc_comp - the nucleating component
    # nuc_ad - marker for whether to reduce time step to allow
    #	for accurate capture of nucleation
    # RH - relative humidities (fraction 0-1)
    # RHt - times through experiment at which relative humidities reached (s)
    # coag_on - whether coagulation to be modelled
    # inflectDp - particle diameter at which wall loss inflection occurs (m)
    # pwl_xpre - x value preceding inflection point
    # pwl_xpro - x value proceeding inflection point
    # inflectk - deposition rate at inflection (/s)
    # chamR - spherical-equivalent radius of chamber (m2)
    # McMurry_flag - marker for treament of particle deposition to walls
    # p_char - average number of charges per particle (/particle)
    # e_field - average electric field inside chamber (g.m/A.s3)
    # injectt - time of injection of components (s)
    # inj_indx - index of components being instantaneously injected after
    #	experiment start
    # Ct - concentration(s) (ppb) of component(s) injected
    #	instantaneously after experiment start
    # pmode - whether number size distributions expressed as modes or explicitly
    # pconc - concentration of injected particles (#/cc (air))
    # pconct - times of particle injection (s)
    # mean_rad - mean radius for particle number size
    #	distribution (um)
    # lowsize - lower size bin boundary (um)
    # uppsize - upper size bin boundary (um)
    # std - standard deviation for injected particle number size
    #	distributions
    # rbou - size bin radius bounds (um)
    # const_infl_t - times for constant influxes (s)
    # MV - molar volume (cc/mol)
    # rindx_aq - index of reactants for aqueous-phase
    # pindx_aq - index of products for aqueous-phase
    # rstoi_aq - stoichiometry of reactants for aqueous-phase
    # pstoi_aq - stoichiometry of products for aqueous-phase
    # nreac_aq - number of reactants per aqueous-phase reaction
    # nprod_aq - number of products per aqueous-phase reaction
    # jac_stoi_aq - stoichiometry for Jacobian for aqueous-phase
    # njac_aq - number of Jacobian elements per aqueous-phase reaction
    # jac_den_indx_aq - index of Jacobian denominators
    # jac_indx_aq - index of  Jacobian for aqueous-phase
    # y_arr_aq - y indices for aqueous-phase
    # y_rind_aq - reactant indices for aqueous-phase
    # uni_y_rind_aq - y indices for reactants for aqueous-phase
    # y_pind_aq - y indices for products for aqueous-phase
    # uni_y_pind_aq - y indices for products for aqueous-phase
    # reac_col_aq - columns of sparse matrix for aqueous-phase
    # prod_col_aq - columns of sparse matrix for aqueous-phase
    # rstoi_flat_aq - reactant stoichiometries for Jacobian for
    # 	aqueous-phase
    # pstoi_flat_aq - product stoichiometries for Jacobian for
    #	aqueous-phase
    # rr_arr_aq - aqueous-phase reaction rate indices
    # rr_arr_p_aq - aqueous-phase reaction rate indices
    # eqn_num - number of reactions in gas- and aqueous-phase
    # partit_cutoff - the product of saturation vapour pressure
    #	and activity coefficient above which gas-particle
    #	partitioning assumed negligible
    # diff_vol - diffusion volumes of components according to
    #		Fuller et al. (1969)
    # DStar_org - diffusion coefficient of components at initial temperature (cm2/s)
    # corei - index of core component
    # ser_H2O - whether to serialise the gas-particle partitioning of water
    # C_p2w - concentration of components on the wall due to particle
    # deposition to wall (molecules/cc)
    # the following inputs are used only for the saving module:
    # sch_name - path to chemical scheme
    # sav_nam - name of folder to save in
    # comp_namelist - chemical scheme name of components
    # dydt_trak - name of components to track change tendencies
    # space_mode - type of spacing used in particle size distribution
    # rbou00 - original particle size bin bounds
    # ub_rad_amp - amplificatin factor for upper bin size bound
    # indx_plot - indices of components to plot the gas-phase temporal profile of
    # comp0 - names of components to plot the gas-phase temporal profile of
    # inname - path to model variables file
    # rel_SMILES - SMILES strings of components in chemical scheme
    # Psat_Pa_rec - pure component saturation vapour pressures (Pa) at 298.15 K
    # OC - oxygen to carbon ratio of components
    # wat_hist - flag for history of particle-phase with respect to water partitioning,
    # 	where 0 is dry (therefore on the deliquescence curve) and 1 is wet
    #	(therefore on the efflorescence curve)
    # Pybel_objects - the pybel objects for components
    # ------------------------------------------------------------

    # start timer
    st_time = time.time()

    step_no = 0  # track number of time steps
    sumt = 0.0  # track time through simulation (s)
    # counters on updates
    light_time_cnt = 0  # light time status count
    gasinj_cnt = 0  # count on injection times of components
    if (pconct[0, 0] == 0. and len(pconct[0, :]) > 1):
        seedt_cnt = 1  # count on injection times of particles
    else:
        seedt_cnt = 0
    infx_cnt = 0  # count on constant gas-phase influx occurrences
    infx_cnt0 = 0  # remember count at start of integration step
    tempt_cnt = 0  # count on chamber temperatures
    tempt_cnt0 = 0  # remember count at start of integration step
    RHt_cnt = 0  # count on chamber relative humidities
    RHt_cnt0 = 0  # remember count at start of integration step
    save_cnt = 1  # count on recording results

    # count on time since update to integration initial values/constants last called (s)
    update_count = 0.
    y0 = np.zeros(
        (len(y)))  # remember initial concentrations (molecules/cm3 (air))
    N_perbin0 = np.zeros(
        (N_perbin.shape[0], N_perbin.shape[1])
    )  # remember initial particle number concentrations (# particles/cm3)
    x0 = np.zeros((len(x)))  # remember initial particle sizes (um)
    t0 = update_stp  # remember initial integration step (s)
    # flag for changing integration time step due to changing initial values
    ic_red = 0
    tnew = update_stp  # the time to integrate over (s)
    # fraction of newly injected seed particles
    pconcn_frac = 0.

    # prepare recording matrices, including recording of initial
    # conditions, note initial change tendencies not recorded
    # in this call but are below
    [
        trec, yrec, Cfactor_vst, Nres_dry, Nres_wet, x2, seedt_cnt, rbou_rec,
        Cfactor, infx_cnt, yrec_p2w, temp_now, cham_env, Pnow, Psat, RHn
    ] = rec_prep.rec_prep(
        nrec_steps, y, y0, rindx, rstoi, pindx, pstoi, nprod, nreac, num_sb,
        num_comp, N_perbin, core_diss, Psat, mfp, accom_coeff, y_mw, surfT,
        R_gas, temp, tempt, NA, y_dens * 1.e-3, x, therm_sp, H2Oi, act_coeff,
        RO2_indx, sumt, Pnow, light_stat, light_time, light_time_cnt, daytime,
        lat, lon, af_path, dayOfYear, photo_path, Jlen, Cw, kw, Cfactor, tf,
        light_ad, wall_on, Vbou, tnew, nuc_ad, nucv1, nucv2, nucv3, np_sum,
        update_stp, update_count, injectt, gasinj_cnt, inj_indx, Ct, pmode,
        pconc, pconct, seedt_cnt, mean_rad, corei, seed_name, seedVr, lowsize,
        uppsize, rad0, x, std, rbou, const_infl_t, infx_cnt, con_infl_C, MV,
        partit_cutoff, diff_vol, DStar_org, seedi, C_p2w, RH, RHt, tempt_cnt,
        RHt_cnt, Pybel_objects, nuci, nuc_comp, t0)

    importlib.reload(ode_solv)  # import most recent version
    importlib.reload(ode_solv_wat)  # import most recent version
    importlib.reload(dydt_rec)  # import most recent version

    while (tot_time - sumt) > (tot_time / 1.e10):

        # remembering variables at the start of the integration step ------------------------------------------
        y0[:] = y[:]  # remember initial concentrations (molecules/cm3 (air))
        N_perbin0[:] = N_perbin[:]  # remember initial particle number concentration (# particles/cm3)
        x0[:] = x[:]  # remember initial particle sizes (um)
        temp_now0 = temp_now  # remember temperature (K)
        wat_hist0 = wat_hist  # remember water history flag at start of integration step
        RH0 = RHn  # relative humidity at start of integration step
        Pnow0 = Pnow  # pressure (Pa)

        # remember counts at start of integration step
        infx_cnt0 = infx_cnt
        tempt_cnt0 = tempt_cnt
        RHt_cnt0 = RHt_cnt
        seedt_cnt0 = seedt_cnt
        gasinj_cnt0 = gasinj_cnt
        light_time_cnt0 = light_time_cnt

        # --------------------------------------------------------------------------------------------------------------------

        gpp_stab = 0  # flag for stability in gas-particle partitioning
        lin_int = 0  # flag to linearly interpolate changes to chamber
        t00 = tnew  # remember the initial integration step for this integration step (s)

        while (gpp_stab != 1):  # whilst ode solver flagged as unstable

            # if integration interval decreased, reset concentrations to those at start of interval
            if (gpp_stab == -1):
                y[:] = y0[:]  # (molecules/cm3)

            # update chamber variables
            [
                temp_now, Pnow, lightm, light_time_cnt, tnew, ic_red,
                update_stp, update_count, Cinfl_now, seedt_cnt, Cfactor,
                infx_cnt, gasinj_cnt, DStar_org, y, tempt_cnt, RHt_cnt, Psat,
                N_perbin, x, pconcn_frac
            ] = cham_up.cham_up(
                sumt, temp, tempt, Pnow0, light_stat, light_time,
                light_time_cnt0, light_ad, tnew, nuc_ad, nucv1, nucv2, nucv3,
                np_sum, update_stp, update_count, lat, lon, dayOfYear,
                photo_path, af_path, injectt, gasinj_cnt0, inj_indx, Ct, pmode,
                pconc, pconct, seedt_cnt0, num_comp, y0, y, N_perbin0,
                mean_rad, corei, seedVr, seed_name, lowsize, uppsize, num_sb,
                MV, rad0, x0, std, y_dens, H2Oi, rbou, const_infl_t, infx_cnt0,
                con_infl_C, wall_on, Cfactor, seedi, diff_vol, DStar_org, RH,
                RHt, tempt_cnt0, RHt_cnt0, Pybel_objects, nuci, nuc_comp, y_mw,
                temp_now0, Psat, gpp_stab, t00, x0)

            # ensure end of time interval does not surpass recording time
            if ((sumt + tnew) > save_stp * save_cnt):
                tnew = (save_stp * save_cnt) - sumt
                ic_red = 1

            # ensure update to operator-split processes interval not surpassed
            if (update_count + tnew > update_stp):
                tnew = (update_stp - update_count)
                ic_red = 1

            # ensure simulation end time not surpassed
            if (sumt + tnew > tot_time):
                tnew = (tot_time - sumt)
                ic_red = 1

            if ((num_sb - wall_on) > 0
                    and (sum(N_perbin) > 0)):  # if particles present

                # update partitioning variables
                [kimt, kelv_fac] = partit_var.kimt_calc(
                    y, mfp, num_sb, num_comp, accom_coeff, y_mw, surfT, R_gas,
                    temp_now, NA, y_dens, N_perbin,
                    x.reshape(1, -1) * 1.e-6, Psat, therm_sp, H2Oi, act_coeff,
                    wall_on, 1, partit_cutoff, Pnow, DStar_org)

                # update particle-phase activity coefficients, note the output,
                # note that if ODE solver unstable, then y resets to y0 via
                # the cham_up module prior to this call
                [act_coeff, wat_hist, RHn, y, dydt_erh_flag
                 ] = act_coeff_update.ac_up(y, H2Oi, RH0, temp_now, wat_hist0,
                                            act_coeff, num_comp,
                                            (num_sb - wall_on))

            else:  # fillers
                kimt = np.zeros((num_sb - wall_on, num_comp))
                kelv_fac = np.zeros((num_sb - wall_on, 1))
                dydt_erh_flag = 0

            # reaction rate coefficient
            rrc = rrc_calc.rrc_calc(RO2_indx, y[H2Oi], temp_now, lightm, y,
                                    daytime + sumt, lat, lon, af_path,
                                    dayOfYear, Pnow, photo_path, Jlen, tf)

            # update Jacobian inputs based on particle-phase fractions of components
            [
                rowvalsn, colptrsn, jac_part_indxn, jac_mod_len,
                jac_part_hmf_indx, rw_indx, jac_wall_indxn, jac_part_H2O_indx
            ] = jac_up.jac_up(y[num_comp:num_comp * ((num_sb - wall_on + 1))],
                              rowvals, colptrs, (num_sb - wall_on), num_comp,
                              jac_part_indx, H2Oi, y[H2Oi], jac_wall_indx,
                              ser_H2O)

            # before solving ODEs for chemistry, gas-particle partitioning and gas-wall partitioning,
            # estimate and record any change tendencies (molecules/cm3/s) resulting from these processes
            if (len(dydt_vst) > 0):

                # record any change tendencies of specified components
                dydt_vst = dydt_rec.dydt_rec(y, rindx, rstoi, rrc, pindx,
                                             pstoi, nprod, save_cnt - 1,
                                             dydt_vst, nreac, num_sb, num_comp,
                                             pconc, core_diss, Psat, kelv_fac,
                                             kimt, kw, Cw, act_coeff, seedi,
                                             dydt_erh_flag, H2Oi, wat_hist)

            if (ser_H2O == 1 and (num_sb - wall_on) > 0
                    and (sum(N_perbin) >
                         0)):  # if water gas-particle partitioning serialised

                # if on the deliquescence curve rather than the efflorescence curve in terms of water gas-particle partitioning
                if (wat_hist == 1):

                    # call on ode solver for water
                    [y, res_t] = ode_solv_wat.ode_solv(
                        y, tnew, rindx, pindx, rstoi, pstoi, nreac, nprod, rrc,
                        jac_stoi, njac, jac_den_indx, jac_indx, Cinfl_now,
                        y_arr, y_rind, uni_y_rind, y_pind, uni_y_pind,
                        reac_col, prod_col, rstoi_flat, pstoi_flat, rr_arr,
                        rr_arr_p, rowvalsn, colptrsn, num_comp, num_sb,
                        wall_on, Psat, Cw, act_coeff, kw, jac_wall_indxn,
                        seedi, core_diss, kelv_fac, kimt, (num_sb - wall_on),
                        jac_part_indxn, rindx_aq, pindx_aq, rstoi_aq, pstoi_aq,
                        nreac_aq, nprod_aq, jac_stoi_aq, njac_aq,
                        jac_den_indx_aq, jac_indx_aq, y_arr_aq, y_rind_aq,
                        uni_y_rind_aq, y_pind_aq, uni_y_pind_aq, reac_col_aq,
                        prod_col_aq, rstoi_flat_aq, pstoi_flat_aq, rr_arr_aq,
                        rr_arr_p_aq, eqn_num, jac_mod_len, jac_part_hmf_indx,
                        rw_indx, N_perbin, jac_part_H2O_indx, H2Oi)

                    if (any(y[H2Oi::num_comp] < 0.)
                        ):  # check on stability of water partitioning

                        y_H2O = y[
                            H2Oi::
                            num_comp]  # isolate just water concentrations (molecules/cm3)
                        # sum the negative concentrations and convert to absolute value (molecules/cm3)
                        neg_H2O = np.abs(sum(y_H2O[y_H2O < 0.]))

                        # allow a given fraction of water concentrations to be negative
                        if (neg_H2O / sum(np.abs(y[H2Oi::num_comp])) > 0.):

                            gpp_stab = -1  # maintain unstable flag
                            # tell user what's happening
                            yield (str(
                                'Note: negative water concentration generated following call to ode_solv_wat module, the programme assumes this is because of a change in relative humidity in chamber air, and will automatically half the integration time interval and linearly interpolate any change to chamber conditions supplied by the user.  To stop this the simulation must be cancelled using the Quit button in the PyCHAM graphical user interface.  Current update time interval is '
                                + str(tnew) + ' seconds'))

                            if (
                                    tnew < 1.e-20
                            ):  # if time step has decreased to unreasonably low and solver still unstable then break
                                yield (str(
                                    'Error: negative concentrations generated following call to ode_solv_wat module, the programme has assumed this is because of a change in chamber condition (e.g. injection of components), and has automatically halved the integration time interval and linearly interpolated any change to chamber conditions supplied by the user.  However, the integration time interval has now decreased to '
                                    + str(tnew) +
                                    ' seconds, which is assumed too small to be useful, so the programme has been stopped.'
                                ))

                        else:  # if less than 0.1 % negative
                            gpp_stab = 1  # change to stable flag

                    else:  # if solution stable, change stability flag to represent this
                        gpp_stab = 1  # change to stable flag

                # zero partitioning of water to particles for integration without water gas-particle partitioning
                kimt[:, H2Oi] = 0.

            # model component concentration changes to get new concentrations
            # (molecules/cc (air))
            [y, res_t] = ode_solv.ode_solv(
                y, tnew, rindx, pindx, rstoi, pstoi, nreac, nprod, rrc,
                jac_stoi, njac, jac_den_indx, jac_indx, Cinfl_now, y_arr,
                y_rind, uni_y_rind, y_pind, uni_y_pind, reac_col, prod_col,
                rstoi_flat, pstoi_flat, rr_arr, rr_arr_p, rowvalsn, colptrsn,
                num_comp, num_sb, wall_on, Psat, Cw, act_coeff, kw,
                jac_wall_indxn, seedi, core_diss, kelv_fac, kimt,
                (num_sb - wall_on), jac_part_indxn, rindx_aq, pindx_aq,
                rstoi_aq, pstoi_aq, nreac_aq, nprod_aq, jac_stoi_aq, njac_aq,
                jac_den_indx_aq, jac_indx_aq, y_arr_aq, y_rind_aq,
                uni_y_rind_aq, y_pind_aq, uni_y_pind_aq, reac_col_aq,
                prod_col_aq, rstoi_flat_aq, pstoi_flat_aq, rr_arr_aq,
                rr_arr_p_aq, eqn_num, jac_mod_len, jac_part_hmf_indx, rw_indx,
                N_perbin, jac_part_H2O_indx, H2Oi)

            if (any(y < 0.)):  # check on stability of integration of processes

                # identify components with negative concentrations
                neg_comp_indx = y < 0.
                # transform into components in columns, locations in rows
                neg_comp_indx = neg_comp_indx.reshape(num_sb + 1, num_comp)
                # get component indices with negative concentration
                neg_comp_indx = (np.where(neg_comp_indx == 1))[1]

                # loop through components with negative concentrations
                for ci in neg_comp_indx:
                    all_c = y[ci::num_comp]
                    # sum of negative concentrations
                    neg_c = np.abs(sum(all_c[all_c < 0.]))
                    # sum of absolute of all concentrations
                    sum_c = sum(np.abs(all_c))

                    # allow a given fraction to be negative, but any more suggests ODE solver instability
                    if (neg_c / sum_c > 0.):

                        gpp_stab = -1  # maintain unstable flag
                        # tell user what's happening
                        yield (str(
                            'Note: negative concentrations generated following call to ode_solv module, the programme assumes this is because of a change in chamber condition (e.g. injection of components), and will automatically half the integration time interval and linearly interpolate any change to chamber conditions supplied by the user.  To stop this the simulation must be cancelled using the Quit button in the PyCHAM graphical user interface.  Current integration time interval is '
                            + str(tnew) + ' seconds'))

                        if (
                                tnew < 1.e-20
                        ):  # if time step has decreased to unreasonably low and solver still unstable then break
                            yield (str(
                                'Error: negative concentrations generated following call to ode_solv module, the programme has assumed this is because of a change in chamber condition (e.g. injection of components), and has automatically halved the integration time interval and linearly interpolated any change to chamber conditions supplied by the user.  However, the integration time interval has now decreased to '
                                + str(tnew) +
                                ' seconds, which is assumed too small to be useful, so the programme has been stopped.'
                            ))

                        # if negative concentration too great a proportion of total
                        # concentration then stop loop through components with negative concentrations
                        continue

                    else:  # if less than 0.1 % negative
                        gpp_stab = 1  # change to stable flag

            else:  # if solution stable, change stability flag to represent this

                # account for any partial addition of newly injected seed particles
                pconc[:, seedt_cnt] -= pconc[:, seedt_cnt] * pconcn_frac
                # reset fraction of newly injected seed particles
                pconcn_frac = 0.
                gpp_stab = 1  # change to stable flag

            # half the update time step (s) if necessary
            if (gpp_stab == -1):
                tnew = tnew / 2.

        # end of integration stability condition section ----------------------------
        step_no += 1  # track number of steps
        sumt += tnew  # total time through simulation (s)

        if ((num_sb - wall_on) > 0):  # if particle size bins present
            # update particle sizes
            if ((num_sb - wall_on) > 1) and (any(
                    N_perbin > 1.e-10)):  # if particles present

                if (siz_str == 0):  # moving centre
                    (N_perbin, Varr, y, x, redt, t,
                     bc_red) = mov_cen.mov_cen_main(N_perbin, Vbou, num_sb,
                                                    num_comp, y_mw, x, Vol0,
                                                    tnew, update_stp, y0, MV,
                                                    Psat[0, :], ic_red, y,
                                                    res_t, wall_on)

                if redt == 1:
                    import ipdb
                    ipdb.set_trace()

                if (siz_str == 1):  # full-moving
                    (Varr, x, y[num_comp:(num_comp * (num_sb - wall_on + 1))],
                     N_perbin, Vbou, rbou) = fullmov.fullmov(
                         (num_sb - wall_on), N_perbin, num_comp,
                         y[num_comp:(num_comp) * (num_sb - wall_on + 1)],
                         MV * 1.e12, Vol0, Vbou, rbou)

            update_count += tnew  # time since operator-split processes last called (s)

            # if time met to implement operator-split processes
            if (update_count >= (update_stp * 9.999999e-1)):
                if (any(N_perbin > 1.e-10)):

                    # particle-phase concentration(s) (molecules/cc (air))
                    Cp = np.transpose(y[num_comp:(num_comp) *
                                        (num_sb - wall_on + 1)].reshape(
                                            num_sb - wall_on, num_comp))

                    # coagulation
                    [
                        N_perbin,
                        y[num_comp:(num_comp) * (num_sb - wall_on + 1)], x, Gi,
                        eta_ai, Varr, Vbou, rbou
                    ] = coag.coag(RH[RHt_cnt], temp_now, x * 1.e-6,
                                  (Varr * 1.0e-18).reshape(1, -1),
                                  y_mw.reshape(-1, 1), x * 1.e-6, Cp,
                                  (N_perbin).reshape(1, -1), update_count,
                                  (Vbou * 1.0e-18).reshape(1,
                                                           -1), rbou, num_comp,
                                  0, (np.squeeze(y_dens * 1.e-3)), Vol0, rad0,
                                  Pnow, 0, Cp, (N_perbin).reshape(1, -1),
                                  (Varr * 1.e-18).reshape(1, -1), coag_on,
                                  siz_str, wall_on)

                    if ((McMurry_flag > -1) and
                        (wall_on == 1)):  #if particle loss to walls turned on
                        # particle loss to walls
                        [
                            N_perbin,
                            y[num_comp:(num_comp) * (num_sb - wall_on + 1)]
                        ] = wallloss.wallloss(
                            N_perbin.reshape(-1, 1),
                            y[num_comp:(num_comp) * (num_sb - wall_on + 1)],
                            Gi, eta_ai, x * 2.0e-6, y_mw, Varr * 1.0e-18,
                            (num_sb - wall_on), num_comp, temp_now,
                            update_count, inflectDp, pwl_xpre, pwl_xpro,
                            inflectk, chamR, McMurry_flag, 0, p_char, e_field,
                            (num_sb - wall_on), C_p2w)

                if (nucv1 > 0.):  # nucleation

                    [N_perbin, y, x, Varr, np_sum, rbou,
                     Vbou] = nuc.nuc(sumt, np_sum, N_perbin, y,
                                     y_mw.reshape(-1, 1),
                                     np.squeeze(y_dens * 1.0e-3), num_comp,
                                     Varr, x, new_partr, MV, nucv1, nucv2,
                                     nucv3, nuc_comp[0], siz_str, rbou, Vbou,
                                     (num_sb - wall_on))

                # reset count to that since original operator-split processes interval met (s)
                update_count = sumt % t0

        # update the percentage time in the GUI progress bar
        yield (sumt / tot_time * 100.)

        # record output
        if ((sumt - (save_stp * save_cnt) > -1.e-10)
                or (sumt >= (tot_time - tot_time / 1.e10))):

            [
                trec, yrec, Cfactor_vst, save_cnt, Nres_dry, Nres_wet, x2,
                rbou_rec, yrec_p2w, cham_env
            ] = rec.rec(save_cnt, trec, yrec, Cfactor_vst, y, sumt, rindx,
                        rstoi, rrc, pindx, pstoi, nprod, nreac, num_sb,
                        num_comp, N_perbin, core_diss, Psat, kelv_fac, kimt,
                        kw, Cw, act_coeff, Cfactor, Nres_dry, Nres_wet, x2, x,
                        MV, H2Oi, Vbou, rbou, wall_on, rbou_rec, seedi,
                        yrec_p2w, C_p2w, cham_env, temp_now, Pnow)

        # if time step was temporarily reduced, then return
        if (ic_red == 1):
            update_stp = t0
            tnew = update_stp
            ic_red = 0

        # remember the gas-phase water concentration from previous
        # integration step (molecules/cm3)
        y_H2O0 = y[H2Oi]

    time_taken = time.time() - st_time

    # save results
    save.saving(sch_name, yrec, Nres_dry, Nres_wet, trec, sav_nam, dydt_vst,
                num_comp, Cfactor_vst, 0, num_sb, comp_namelist, dydt_trak,
                y_mw, MV, time_taken, seed_name, x2, rbou_rec, wall_on,
                space_mode, rbou00, ub_rad_amp, indx_plot, comp0, yrec_p2w,
                sch_name, inname, rel_SMILES, Psat_Pa_rec, OC, H2Oi, seedi,
                siz_str, cham_env)
    return ()
コード例 #4
0
def init_water_partit(x, y, H2Oi, Psat, mfp, siz_str, num_sb, num_speci,
                      accom_coeff, y_mw, surfT, R_gas, TEMP, NA, y_dens,
                      N_perbin, RH, core_diss, Varr, Vbou, rbou, Vol0, MV,
                      therm_sp, Cw, kgwt, act_coeff, wall_on, partit_cutoff,
                      Press, coll_dia, seedi):

    # inputs: ------------------------------------------------------
    # x - radius of particles per size bin (um)
    # Psat - saturation vapour pressure of components (molecules/cc (air))
    # siz_str - the size structure
    # num_sb - number of size bins
    # N_perbin - initial particle concentration (#/cc (air))
    # Vbou - volume bounds (um3)
    # rbou - radius bounds (um)
    # MV - molar volume of components (cc/mol)
    # therm_sp - thermal speed of components (m/s) (num_speci)
    # Cw - concentration of wall (molecules/cc (air))
    # kgwt - mass transfer coefficient for vapour-wall partitioning (/s)
    # act_coeff - activity coefficients of components (dimensionless)
    # wall_on - marker for whether to consider wall
    # partit_cutoff - product of vapour pressure and activity coefficient
    #		at which gas-particle partitioning assumed zero (Pa)
    # Press - pressure inside chamber (Pa)
    # coll_dia - collision diameters of components (cm)
    # seedi - index of seed components
    # --------------------------------------------------------------

    if sum(N_perbin) > 0.0:  # if seed particles present
        # new array of size bin radii (um)
        print('Equilibrating water in vapour with water in seed particles')

        for sbstep in range(len(x)):  # loop through size bins
            if N_perbin[
                    sbstep] < 1.0e-10:  # no need to partition if no particle present
                continue

            # partitioning coefficient and kelvin factor
            [kimt, kelv_fac] = kimt_calc(y, mfp, num_sb, num_speci,
                                         accom_coeff, y_mw, surfT, R_gas, TEMP,
                                         NA, y_dens, N_perbin,
                                         x.reshape(1, -1) * 1.0e-6, Psat,
                                         therm_sp, H2Oi, act_coeff, wall_on, 0,
                                         partit_cutoff, Press, coll_dia)

            # get seed particle properties: concentration (molecules/cc (air))
            ycore = 0.
            for ci in range(len(seedi)):
                ycore += y[num_speci *
                           (sbstep + 1) + seedi[ci]] * core_diss[ci]

            # first guess of particle-phase water concentration based on RH = mole
            # fraction (molecules/cc (air))
            y[num_speci * (sbstep + 1) +
              H2Oi] = (ycore / kelv_fac[sbstep]) * RH

            # gas phase concentration of water (molecules/cc (air)), will stay constant
            # because RH is constant
            Cgit = y[H2Oi]

            # concentration of water at particle surface in gas phase (molecules/cc (air))
            Wc_surf = y[num_speci * (sbstep + 1) + H2Oi]

            # total particle surface gas-phase concentration of all components
            # (molecules/cc (air)):
            conc_sum = (np.sum(y[num_speci * (sbstep + 1):num_speci *
                                 (sbstep + 2)]))
            # account for seed dissociation constant
            for ci in range(len(seedi)):
                conc_sum = (conc_sum - y[num_speci *
                                         (sbstep + 1) + seedi[ci]] +
                            (y[num_speci *
                               (sbstep + 1) + seedi[ci]] * core_diss[ci]))

            # partitioning coefficient and kelvin factor
            [kimt, kelv_fac] = kimt_calc(y, mfp, num_sb, num_speci,
                                         accom_coeff, y_mw, surfT, R_gas, TEMP,
                                         NA, y_dens, N_perbin,
                                         x.reshape(1, -1) * 1.0e-6, Psat,
                                         therm_sp, H2Oi, act_coeff, wall_on, 0,
                                         partit_cutoff, Press, coll_dia)

            Csit = (Wc_surf / conc_sum) * Psat[0, H2Oi] * kelv_fac[sbstep, 0]

            y0 = np.zeros(len(y))
            y0[:] = y[:]  # initial concentration before moving centre (molecules/cc (air))
            y00 = np.zeros(len(y))
            y00[:] = y[:]  # initial concentration before iteration (molecules/cc (air))
            dydtfac = 1.0e-1
            dydt0 = 0  # change in water concentration (molecules/cc) on previous iteration

            while np.abs(Cgit - Csit) > Cgit / 1.0e6:

                y0[:] = y[:]  # update initial concentrations (molecules/cc (air))

                # new particle size, required to update kelvin factor and partitioning
                # coefficient in kimt_calc below
                # number of moles of each component in a single particle (mol/cc (air))
                nmolC = ((y[num_speci * (sbstep + 1):num_speci *
                            (sbstep + 2)] / (si.Avogadro * N_perbin[sbstep])))
                # new radius of single particle per size bin (um) including volume of
                # water
                Vnew = np.sum(nmolC * MV * 1.e12)  # new volume (um3)
                x[sbstep] = ((3.0 / (4.0 * np.pi)) * Vnew)**(1.0 / 3.0)

                # update partitioning coefficients
                [kimt, kelv_fac
                 ] = kimt_calc(y, mfp, num_sb, num_speci, accom_coeff, y_mw,
                               surfT, R_gas, TEMP, NA, y_dens, N_perbin,
                               x.reshape(1, -1) * 1.0e-6, Psat, therm_sp, H2Oi,
                               act_coeff, wall_on, 0, partit_cutoff, Press,
                               coll_dia)

                # concentration of water at particle surface in gas phase
                # (molecules/cc (air))
                Wc_surf = y[num_speci * (sbstep + 1) + H2Oi]

                # total particle surface gas-phase concentration of all species
                # (molecules/cc (air)):
                conc_sum = (np.sum(y[num_speci * (sbstep + 1):num_speci *
                                     (sbstep + 2)]))

                # account for seed dissociation constant
                for ci in range(len(seedi)):
                    conc_sum = (conc_sum - y[num_speci *
                                             (sbstep + 1) + seedi[ci]] +
                                (y[num_speci *
                                   (sbstep + 1) + seedi[ci]] * core_diss[ci]))

                Csit = (Wc_surf / conc_sum) * Psat[0, H2Oi] * kelv_fac[
                    sbstep, 0] * act_coeff[0, H2Oi]

                dydt = kimt[sbstep, H2Oi] * (
                    Cgit - Csit)  # partitioning rate (molecules/cc.s)
                dydtn = dydt * (dydtfac * RH * x[sbstep]**3.0)
                dydtn = dydt * (dydtfac * RH *
                                x[sbstep]**3.0) / kelv_fac[sbstep, 0]

                # new estimate of concentration of condensed water (molecules/cc (air))
                y[num_speci * (sbstep + 1) + H2Oi] += dydtn
                # if iteration becomes unstable, reset and reduce change per step
                if ((np.sum(y[num_speci * (sbstep + 1):num_speci *
                              (sbstep + 2)])) < 0.0):
                    # return to first guess before iteration on this size bin began
                    y[:] = y00[:]
                    dydtfac = dydtfac / 2.0
                # if iteration oscillates, reduce change per step
                if dydt0 < 0 and dydtn > 0:
                    dydtfac = dydtfac / 2.0

                # remember change in this step
                dydt0 = dydtn

            sbstep += 1

        # call on the moving centre method for redistributing particles that have grown
        # beyond their upper size bin boundary due to water condensation, note, only do this
        # after the iteration per size bin when we know the new particle-phase concentration
        # of water
        # concentration in particles now (molecules/cc (air))
        Cp = y[num_speci:(num_speci * (num_sb - wall_on + 1))]
        Cp = np.transpose(Cp.reshape((num_sb - wall_on), num_speci))

        if (siz_str == 0):  # moving-centre size structure
            import mov_cen_water_eq

            (N_perbin, Varr, Cp, x, redt, blank,
             tnew) = mov_cen_water_eq.mov_cen_main(N_perbin, Vbou, Cp,
                                                   (num_sb - wall_on),
                                                   num_speci, Vol0, 0.0, 0,
                                                   MV * 1.e12)

            if (redt == 1
                ):  # check on whether exception raised by moving centre
                print(
                    'Error whilst equilibrating seed particles with water vapour (inside init_water_partit module).  Please investigate, perhaps by checking rh and pconc inputs in model variables input file.  See README for guidance and how to report bugs.'
                )
                sys.exit()

        if (siz_str == 1):  # full-moving size structure
            import fullmov
            (Varr, x, Cp, N_perbin, Vbou, rbou) = fullmov.fullmov(
                (num_sb - wall_on), N_perbin, num_speci,
                y[num_speci:(num_speci * (num_sb - wall_on + 1))], MV * 1.e12,
                Vol0, Vbou, rbou)

        # new particle-phase concentrations (molecules/cc (air))
        y[num_speci:(num_speci * (num_sb - wall_on + 1))] = Cp

    if kgwt > 1.0e-10 and Cw > 0.0:
        print('Equilibrating water in vapour with water on wall')

        # first guess of wall-phase water concentration based on RH = mole
        # fraction (molecules/cc (air))
        y[num_speci * num_sb + H2Oi] = Cw * RH

        # allow gas-phase water to equilibrate with walls
        while np.abs(y[H2Oi] - Psat[0, H2Oi] *
                     ((y[num_speci *
                         (num_sb) + H2Oi] / Cw)) * act_coeff[0, H2Oi]) > 1.0e2:

            # concentration of water at wall surface in gas phase (molecules/cc (air))
            Csit = y[num_speci * num_sb:num_speci * (num_sb + 1)]
            Csit = (Psat[0, :] * (Csit / Cw) * act_coeff[0, H2Oi]
                    )  # with Raoult term

            dydt = y[H2Oi] - Csit[
                H2Oi]  # distance from equilibrium (molecules/cc)

            dydt = ((dydt / Psat[0, H2Oi]) * Cw) / 2.0

            # new estimate of concentration of condensed water (molecules/cc (air))
            y[num_speci * (num_sb) + H2Oi] += dydt

    print('Finished initiating water condensation')

    return (y, Varr, x, N_perbin, Vbou, rbou)
コード例 #5
0
def ode_updater(update_stp, 
	tot_time, save_stp, y, rindx, 
	pindx, rstoi, pstoi, nreac, nprod, jac_stoi, njac, 
	jac_den_indx, jac_indx, RO2_indx, H2Oi,	temp, tempt, 
	Pnow, light_stat, light_time, daytime, lat, lon, af_path, 
	dayOfYear, photo_path, Jlen, con_infl_C, nrec_steps, 
	dydt_vst, siz_str, num_sb, num_comp, seedi, seed_name, seedVr, 
	core_diss, Psat, mfp, therm_sp,
	accom_coeff, y_mw, surfT, R_gas, NA, y_dens, 
	x, Varr, act_coeff, Cw, kw, Cfactor, tf, light_ad, y_arr, 
	y_rind, 
	uni_y_rind, y_pind, uni_y_pind, reac_col, prod_col, 
	rstoi_flat, pstoi_flat, rr_arr, rr_arr_p, rowvals, 
	colptrs, wall_on, jac_wall_indx, jac_part_indx, Vbou,
	N_perbin, Vol0, rad0, np_sum, new_partr, nucv1, nucv2, 
	nucv3, nuc_comp, nuc_ad, RH, coag_on, inflectDp, pwl_xpre, 
	pwl_xpro, inflectk, chamR, Rader, p_char, e_field, 
	injectt, inj_indx, Ct, pmode, pconc, pconct, mean_rad, lowsize, 
	uppsize, std, rbou, const_infl_t, MV,
	rindx_aq, 
	pindx_aq, rstoi_aq, pstoi_aq, nreac_aq, nprod_aq, jac_stoi_aq, njac_aq, 
	jac_den_indx_aq, jac_indx_aq, y_arr_aq,
	y_rind_aq, 
	uni_y_rind_aq, y_pind_aq, uni_y_pind_aq, reac_col_aq, prod_col_aq, 
	rstoi_flat_aq, pstoi_flat_aq, rr_arr_aq, rr_arr_p_aq, eqn_num, 
	partit_cutoff, coll_dia, corei):

	import ode_solv # import most updated version
	# inputs: ----------------------------------------------------
	# update_stp - interval at which to update integration 
	#		constants (s)
	# tot_time - total time to simulate (s)
	# save_stp - frequency to save results (s)
	# y - initial component concentrations (molecules/cc/s)
	# rindx - index of reactants per equation
	# pindx - index of products per equation
	# nreac - number of reactants per equation
	# nprod - number of products per equation
	# jac_stoi - stoichiometries relevant to Jacobian
	# njac - number of elements of Jacobian affected per equation
	# jac_den_indx - index of denominator components for Jacobian
	# jac_indx - index of Jacobian affected per equation
	# RO2_indx - index of components in peroxy radical list
	# H2Oi - index of water
	# temp - temperature in chamber (K)
	# tempt - times that temperatures reached (s)
	# Pnow - pressure inside chamber (Pa)
	# light_stat - lights status
	# light_time - time light status attained (s)
	# daytime - time of day experiment starts (s)
	# lat - latitude of experiment (degrees)
	# lon - longitude of experiment (degrees)
	# af_path - path to actinic flux values
	# dayOfYear - number of days since 31st December experiment held on
	# photo_path - path to file with absorption cross-sections
	# 		and quantum yields
	# Jlen - number of photochemical reactions
	# con_infl_C - influx of components with constant concentration
	# (molecules/cc/s)
	# nrec_step - number of recording steps
	# dydt_vst - dictionary for holding change tendencies of specified
	#		components
	# siz_str - the size structure
	# num_sb - number of particle size bins
	# num_comp - number of components
	# seedi - index of component(s) comprising seed material
	# seed_name - name(s) of component(s) comprising seed particles
	# seedVr - volume ratio of component(s) comprising seed material
	# core_diss - dissociation constant of seed
	# Psat - pure component saturation vapour pressure 
	# 	(molecules/cc (air))
	# mfp - mean free path (m)
	# accom_coeff - accommodation coefficient
	# y_mw - molecular weight (g/mol)
	# surfT - surface tension (g/s2)
	# R_gas - ideal gas constant (kg.m2.s-2.K-1.mol-1)
	# NA - Avogadro's constant (molecules/mol)
	# y_dens - component densities (kg/m3)
	# x - particle radii (um)
	# Varr - particle volume (um3)
	# therm_sp - thermal speed (m/s)
	# act_coeff - activity coefficient
	# Cw - effective absorbing mass of wall (molecules/cc (air))
	# kw - gas-wall mass transfer coefficient (/s)
	# Cfactor - conversion factor for concentrations (ppb/molecules/cc)
	# tf - transmission factor for natural sunlight
	# light_ad - marker for whether to adapt time interval for 
	#	changing natural light intensity
	# y_arr - index for arranging concentrations into matrix that 
	# 	allows reaction rate coefficient calculation
	# y_rind - index for the concentration array  that 
	# 	allows reaction rate coefficient calculation
	# uni_y_rind - unique index of reactants
	# y_pind - index for the concentration array  that 
	# 	allows product gains to be indexed
	# uni_y_pind - unique index of products
	# reac_col - column indices for sparse matrix of reaction 
	#		losses
	# prod_col - column indices for sparse matrix of production
	#		gains
	# rstoi_flat - 1D array of reactant stoichiometries per 
	#	equation
	# pstoi_flat - 1D array of product stoichiometries per
	#	equation
	# rr_arr - index for reaction rates to allow reactant loss
	# 	calculation
	# rr_arr_p - index for reaction rates to allow product gain
	#	calculation
	# rowvals - row indices of Jacobian elements
	# colptrs - indices of  rowvals corresponding to each column of
	# 	the Jacobian
	# wall_on - marker for whether wall partitioning turned on
	# Cw - effective absorbing mass concentration of wall 
	#	(molecules/cc (air))
	# kw - mass transfer coefficient of wall partitioning (/s)
	# jac_wall_indx - index of inputs to Jacobian from wall 
	# 	partitioning
	# jac_part_indx - index of inputs to Jacobian from particle
	#	partitioning
	# Vbou - volume boundary of size bins (um3)
	# N_perbin - number concentration of particles per size bin 
	#	(#/cc (air))
	# Vol0 - initial single particle volumes per size bin (um3)
	# rad0 - initial radius at particle centres (um)
	# np_sum - number concentration of newly nucleated particles 
	#		(#/cc (air))
	# new_partr - radius of newly nucleated particles (cm)
	# nucv1, v2, v3 - nucleation parameters
	# nuc_comp - the nucleating component
	# nuc_ad - marker for whether to reduce time step to allow 
	#	for accurate capture of nucleation
	# RH - relative humidity
	# coag_on - whether coagulation to be modelled
	# inflectDp - particle diameter at which wall loss inflection occurs (m)
	# pwl_xpre - x value preceding inflection point
	# pwl_xpro - x value proceeding inflection point
	# inflectk - deposition rate at inflection (/s)
	# chamR - spherical-equivalent radius of chamber (m2)
	# Rader - marker for treamnt of particle deposition to walls
	# p_char - average number of charges per particle (/particle)
	# e_field - average electric field inside chamber (g.m/A.s3)
	# injectt - time of injection of components (s)
	# inj_indx - index of component(s) being injected after 
	#	experiment start
	# Ct - concentration(s) (ppb) of component(s) injected 
	#	instantaneously after experiment start
	# pmode - whether number size distributions expressed as modes or explicitly
	# pconc - concentration of injected particles (#/cc (air))
	# pconct - times of particle injection (s)
	# mean_rad - mean radius for particle number size 
	#	distribution (um)
	# lowsize - lower size bin boundary (um)
	# uppsize - upper size bin boundary (um)
	# std - standard deviation for injected particle number size 
	#	distributions
	# rbou - size bin radius bounds (um)
	# const_infl_t - times for constant influxes (s)
	# MV - molar volume (cc/mol)
	# rindx_aq - index of reactants for aqueous-phase 
	# pindx_aq - index of products for aqueous-phase
	# rstoi_aq - stoichiometry of reactants for aqueous-phase
	# pstoi_aq - stoichiometry of products for aqueous-phase
	# nreac_aq - number of reactants per aqueous-phase reaction
	# nprod_aq - number of products per aqueous-phase reaction
	# jac_stoi_aq - stoichiometry for Jacobian for aqueous-phase
	# njac_aq - number of Jacobian elements per aqueous-phase reaction 
	# jac_den_indx_aq - index of Jacobian denominators 
	# jac_indx_aq - index of  Jacobian for aqueous-phase
	# y_arr_aq - y indices for aqueous-phase
	# y_rind_aq - reactant indices for aqueous-phase 
	# uni_y_rind_aq - y indices for reactants for aqueous-phase
	# y_pind_aq - y indices for products for aqueous-phase
	# uni_y_pind_aq - y indices for products for aqueous-phase
	# reac_col_aq - columns of sparse matrix for aqueous-phase
	# prod_col_aq - columns of sparse matrix for aqueous-phase
	# rstoi_flat_aq - reactant stoichiometries for Jacobian for 
	# 	aqueous-phase
	# pstoi_flat_aq - product stoichiometries for Jacobian for
	#	aqueous-phase
	# rr_arr_aq - aqueous-phase reaction rate indices
	# rr_arr_p_aq - aqueous-phase reaction rate indices
	# eqn_num - number of reactions in gas- and aqueous-phase
	# partit_cutoff - the product of saturation vapour pressure
	#	and activity coefficient above which gas-particle
	#	partitioning assumed negligible
	# coll_dia - collision diameter of components (cm)
	# corei - index of core component
	# ------------------------------------------------------------
	
	step_no = 0 # track number of time steps
	sumt = 0.0 # track time through simulation (s)
	# counters on updates
	light_time_cnt = 0 # light time status count
	gasinj_cnt = 0 # count on injection times of components
	if pconct[0, 0] == 0.: 
		seedt_cnt = 1 # count on injection times of particles
	else:
		seedt_cnt = 0
	infx_cnt = 0 # count on constant gas-phase influx occurrences
	save_cnt = 1 # count on recording results
	# count on time since update to integration initial values/constants last called (s)
	update_count = 0.
	y0 = np.zeros((len(y))) # remember initial concentrations (molecules/cc (air))
	t0 = update_stp # remember initial integration step (s)
	# flag for changing integration time step due to changing initial values	
	ic_red = 0
	tnew = update_stp # the time to integrate over (s)
	
	# prepare recording matrices, including recording of initial
	# conditions
	[trec, yrec, dydt_vst, Cfactor_vst, Nres_dry, Nres_wet, x2, 
	seedt_cnt, rbou_rec, Cfactor, infx_cnt, coll_dia] = rec_prep.rec_prep(nrec_steps, 
	y, rindx, 
	rstoi, pindx, pstoi, nprod, dydt_vst, nreac, 
	num_sb, num_comp, N_perbin, core_diss, Psat, mfp,
	accom_coeff, y_mw, surfT, R_gas, temp, tempt, NA,
	y_dens*1.e-3, x, therm_sp, H2Oi, act_coeff,
	RO2_indx, sumt, Pnow, light_stat, light_time, 
	light_time_cnt, daytime, lat, lon, af_path, 
	dayOfYear, photo_path, Jlen, Cw, kw, Cfactor, tf, 
	light_ad, wall_on, Vbou, tnew, nuc_ad, nucv1, nucv2, nucv3, 
	np_sum, update_stp, update_count, injectt, gasinj_cnt, 
	inj_indx, Ct, pmode, pconc, pconct, seedt_cnt, mean_rad, corei, 
	seed_name, seedVr, lowsize, uppsize, rad0, x, std, rbou, const_infl_t, 
	infx_cnt, con_infl_C, MV, partit_cutoff, coll_dia, seedi)

	print('Starting loop through update steps')	
	while (tot_time-sumt)>(tot_time/1.e10):
		
		y0[:] = y[:] # remember initial concentrations (molecules/cc (air))
				
		# update chamber variables
		[temp_now, Pnow, lightm, light_time_cnt, tnew, ic_red, update_stp, 
			update_count, Cinfl_now, seedt_cnt, Cfactor, infx_cnt, 
			gasinj_cnt, coll_dia] = cham_up.cham_up(sumt, temp, tempt, 
			Pnow, light_stat, light_time, light_time_cnt, light_ad, 
			tnew, nuc_ad, nucv1, nucv2, nucv3, np_sum, 
			update_stp, update_count, lat, lon, dayOfYear, photo_path, 
			af_path, injectt, gasinj_cnt, inj_indx, Ct, pmode, pconc, pconct, 
			seedt_cnt, num_comp, y, N_perbin, mean_rad, corei, seedVr, seed_name, 
			lowsize, uppsize, num_sb, MV, rad0, x, std, y_dens, H2Oi, rbou, 
			const_infl_t, infx_cnt, con_infl_C, wall_on, Cfactor, seedi, coll_dia)
		
		# ensure end of time interval does not surpass recording time
		if ((sumt+tnew) > save_stp*save_cnt):
			tnew = (save_stp*save_cnt)-sumt
			ic_red = 1

		# ensure update step interval not surpassed
		if (update_count+tnew > update_stp):
			tnew = (update_stp-update_count)
			ic_red = 1
		
		if ((num_sb-wall_on) > 0): # if particles present

			# update partitioning variables
			[kimt, kelv_fac] = partit_var.kimt_calc(y, mfp, num_sb, num_comp, accom_coeff, y_mw,   
			surfT, R_gas, temp_now, NA, y_dens, N_perbin, 
			x.reshape(1, -1)*1.0e-6, Psat, therm_sp, H2Oi, act_coeff, wall_on, 1, partit_cutoff, 
			Pnow, coll_dia)
						
		else: # fillers
			kimt = kelv_fac = 0.
		
		# reaction rate coefficient
		rrc = rrc_calc.rrc_calc(RO2_indx, 
			y[H2Oi], temp_now, lightm, y, daytime+sumt, 
			lat, lon, af_path, dayOfYear, Pnow, 
			photo_path, Jlen, tf)
		
		# model component concentration changes to get new concentrations
		# (molecules/cc)
		[res, res_t] = ode_solv.ode_solv(y, tnew, rindx, pindx, rstoi, pstoi,
			nreac, nprod, rrc, jac_stoi, njac, jac_den_indx, jac_indx,
			Cinfl_now, y_arr, y_rind, uni_y_rind, y_pind, uni_y_pind, 
			reac_col, prod_col, rstoi_flat, 
			pstoi_flat, rr_arr, rr_arr_p, rowvals, colptrs, num_comp, 
			num_sb, wall_on, Psat, Cw, act_coeff, kw, jac_wall_indx,
			seedi, core_diss, kelv_fac, kimt, (num_sb-wall_on), 
			jac_part_indx,
			rindx_aq, pindx_aq, rstoi_aq, pstoi_aq,
			nreac_aq, nprod_aq, jac_stoi_aq, njac_aq, jac_den_indx_aq, jac_indx_aq, 
			y_arr_aq, y_rind_aq, uni_y_rind_aq, y_pind_aq, uni_y_pind_aq, 
			reac_col_aq, prod_col_aq, rstoi_flat_aq, 
			pstoi_flat_aq, rr_arr_aq, rr_arr_p_aq, eqn_num)
		
		# take last installment from res
		y = res[-1, :]
		
		step_no += 1 # track number of steps
		sumt += tnew # total time through simulation (s)
		
		if (num_sb-wall_on > 0): # if particle size bins present
			# update particle sizes
			if ((num_sb-wall_on) > 1) and ((N_perbin > 1.0e-10).sum()>0): # if particles present
				
				if (siz_str == 0): # moving centre
					(N_perbin, Varr, y, x, redt, t, bc_red) = mov_cen.mov_cen_main(N_perbin, 
					Vbou, num_sb, num_comp, y_mw, x, Vol0, tnew, 
					update_stp, y0, MV, Psat[0, :], ic_red, res, res_t)
				if (siz_str == 1): # full-moving
					(Varr, x, y[num_comp:(num_comp*(num_sb-wall_on+1))], 
					N_perbin, Vbou, rbou) = fullmov.fullmov((num_sb-wall_on), N_perbin,
 					num_comp, y[num_comp:(num_comp)*(num_sb-wall_on+1)], MV*1.e12, 
					Vol0, Vbou, rbou)
			
			update_count += tnew # time since operator-split processes last called (s)

			# if time met to implement operator-split processes
			if (update_count>=update_stp*9.999999e-1):
				if ((N_perbin>1.e-10).sum()>0):
					# particle-phase concentrations (molecules/cc (air))
					Cp = np.transpose(y[num_comp:(num_comp)*(num_sb-wall_on+1)].reshape(num_sb-wall_on, num_comp))
					# coagulation
					[N_perbin, y[num_comp:(num_comp)*(num_sb-wall_on+1)], x, Gi, eta_ai, 
						Varr, Vbou, rbou] = coag.coag(RH, temp_now, x*1.0e-6, 
						(Varr*1.0e-18).reshape(1, -1), 
						y_mw.reshape(-1, 1), x*1.0e-6, 
						Cp, (N_perbin).reshape(1, -1), update_count, 
						(Vbou*1.0e-18).reshape(1, -1), rbou,
						num_comp, 0, (np.squeeze(y_dens*1.0e-3)), Vol0, rad0, Pnow, 0,
						Cp, (N_perbin).reshape(1, -1), (Varr*1.0e-18).reshape(1, -1),
						coag_on, siz_str, wall_on)
				
					if ((Rader>-1) and (wall_on == 1)): #if particle loss to walls turned on
						# particle loss to walls
						[N_perbin, 
						y[num_comp:(num_comp)*(num_sb-wall_on+1)]] = wallloss.wallloss(
							N_perbin.reshape(-1, 1), 
							y[num_comp:(num_comp)*(num_sb-wall_on+1)], Gi, eta_ai,
 							x*2.0e-6, y_mw, 
							Varr*1.0e-18, num_sb, num_comp, temp_now, update_count, 
							inflectDp, pwl_xpre, pwl_xpro, inflectk, chamR, Rader, 
							0, p_char, e_field, (num_sb-wall_on))
			
				if (nucv1 > 0.): # nucleation
					[N_perbin, y, x, Varr, np_sum, rbou, Vbou] = nuc.nuc(sumt, np_sum, 
						N_perbin, y, y_mw.reshape(-1, 1), 
						np.squeeze(y_dens*1.0e-3),  
						num_comp, Varr, x, new_partr, MV, nucv1, nucv2, 
						nucv3, nuc_comp[0], siz_str, rbou, Vbou, (num_sb-wall_on))
					
				# reset count to that since original operator-split processes interval met (s)
				update_count = sumt%t0

		
		print('time through simulation (s): ', sumt)
		
		# record output
		if sumt-(save_stp*save_cnt)>-1.e-10:
			
			[trec, yrec, dydt_vst, Cfactor_vst, save_cnt, 
				Nres_dry, Nres_wet, x2, rbou_rec] = rec.rec(save_cnt, trec, yrec, 
				dydt_vst, Cfactor_vst, y, sumt, rindx, rstoi, rrc, pindx, pstoi, 
				nprod, nreac, num_sb, num_comp, N_perbin, core_diss, 
				Psat, kelv_fac, kimt, kw, Cw, act_coeff, Cfactor, Nres_dry, 
				Nres_wet, x2, x, MV, H2Oi, Vbou, rbou, wall_on, rbou_rec, seedi)		
		
		# if time step was temporarily reduced, then return
		if ic_red == 1:
			update_stp = t0
			tnew = update_stp
			ic_red = 0
	
	return(trec, yrec, dydt_vst, Cfactor_vst, Nres_dry, Nres_wet, x2, rbou_rec)
コード例 #6
0
ファイル: rec_prep.py プロジェクト: vigorss/PyCHAM
def rec_prep(nrec_step, 
	y, rindx, 
	rstoi, pindx, pstoi, nprod, dydt_vst, nreac, 
	num_sb, num_comp, N_perbin, core_diss, Psat, mfp,
	accom_coeff, y_mw, surfT, R_gas, temp, tempt, NA, 
	y_dens, x, therm_sp, H2Oi, act_coeff, 
	RO2_indx, sumt, Pnow, light_stat, light_time, 
	light_time_cnt, daytime, lat, lon, af_path, 
	dayOfYear, photo_path, Jlen, Cw, kw, Cfactor, tf, 
	light_ad, wall_on, Vbou, tnew, nuc_ad, nucv1, nucv2, nucv3, 
	np_sum, update_stp, update_count, injectt, gasinj_cnt, 
	inj_indx, Ct, pmode, pconc, pconct, seedt_cnt, mean_rad, corei, 
	seed_name, seedVr, lowsize, uppsize, rad0, radn, std, rbou, 
	const_infl_t, infx_cnt, con_infl_C, MV, partit_cutoff, coll_dia, seedi):
	
	# inputs: --------------------------------------------------------
	# nrec_step - number of steps to record on
	# y - initial concentrations (molecules/cc (air))
	# rindx - indices of reactants
	# rstoi - stoichiometries of reactants
	# pindx - indices of products
	# pstoi - stoichiometries of products
	# nprod - number of products
	# dydt_vst - recording for change tendencies
	# nreac - number of reactants
	# num_sb - number of size bins
	# num_comp - number of components
	# N_perbin - particle concentration per size bin (#/cc (air))
	# core_diss - dissociation constant of seed
	# Psat - pure component saturation vapour pressure 
	#	(molecules/cm3 (air))
	# mfp - mean free path (m)
	# accom_coeff - accommodation coefficient
	# y_mw - molecular weight (g/mol)
	# surfT - surface tension (g/s2)
	# R_gas - ideal gas constant (kg.m2.s-2.K-1.mol-1)
	# temp - temperature (K)
	# tempt - times temperatures achieved (s)
	# NA - Avogadro constants (molecules/mol)
	# y_dens - component densities (g/cm3)
	# x - particle radii (um)
	# therm_sp - thermal speed (m/s)
	# H2Oi - index for water
	# act_coeff - activity coefficient
	# RO2_indx - index of peroxy radicals
	# sumt - cumulative time through simulation (s)
	# Pnow - chamber pressure (Pa)
	# light_stat - light status
	# light_time - times corresponding to light status
	# light_time_cnt - count on light status array
	# daytime - start time of simulation (s)
	# lat - latitude
	# lon - longitude
	# af_path - path to actinic flux file
	# dayOfYear - day of year
	# photo_path - path to photochemistry file
	# Jlen - length of photochemistry equations
	# Cw - effective absorbing mass of wall (molecules/cc (air))
	# kw - gas-wall partitioning coefficient (/s)
	# Cfactor - conversion factor (ppb/molecules/cc)
	# tf - transmission factor for natural sunlight
	# light_ad - marker for whether to adapt time interval to 
	#		changing natural light intensity
	# wall_on - marker for whether wall present
	# Vbou - volume boundary of particle size bins (um3)
	# tnew - the proposed integration time interval (s)
	# nuc_ad - marker for whether to adapt time step based on 
	#	nucleation
	# nucv1 - nucleation parameter one
	# nucv2 - nucleation parameter two
	# nucv3 - nucleation parameter three
	# np_sum - cumulative number concentration of new 
	#	particles so far (#/cc (air))
	# update_stp - time interval between operator-split processes
	# update_count - count on time since last operator-split (s)
	# injectt - time of instantaneous injection of components (s)
	# gasinj_cnt - count on injection times of components
	# inj_indx - index of component(s) being injected after 
	#	experiment start
	# Ct - concentration(s) (ppb) of component(s) injected 
	# instantaneously after experiment start
	# pmode - whether number size distributions expressed as modes or explicitly
	# pconc - concentration of injected particles (#/cc (air))
	# pconct - times of particle injection (s)
	# seedt_cnt - count on injection of seed particles
	# mean_rad - mean radius for particle number size 
	#	distribution (um)
	# corei - index of core component
	# seedVr - volume ration of component(s) comprising seed particles
	# seed_name - name(s) of component(s) comprising seed particles
	# seedVr - volume ratio of component(s) comprising seed particles
	# lowsize - lower size bin boundary (um)
	# uppsize - upper size bin boundary (um)
	# rad0 - initial radius at size bin centres (um)
	# radn - current radius at size bin centres (um)	
	# std - standard deviation for injected particle number size 
	#	distributions
	# rbou - size bin radius bounds (um)
	# const_infl_t - times for constant influxes (s)
	# infx_cnt - count on constant influx occurrences
	# con_infl_C - influx rates of components with constant influx 
	#	(ppb/s)
	# MV - molar volume (cc/mol)
	# partit_cutoff - the product of saturation vapour pressure and
	#		activity coefficient above which gas-particle
	#		partitioning assumed zero (Pa)
	# coll_dia - collision diameters of components (cm)
	# seedi - index of seed component(s)
	# ----------------------------------------------------------------

	# array to record time through simulation (s)
	trec = np.zeros((nrec_step))
	# array to record concentrations with time (molecules/cc/s)
	yrec = np.zeros((nrec_step, len(y)))
	yrec[0, :] = y # record initial concentrations (molecules/cc/s)
	# array to record conversion factor
	Cfactor_vst = np.zeros((nrec_step, 1))
	Cfactor_vst[0] = Cfactor

	# arrays to record particle radii and number size distributions	
	if ((num_sb-wall_on) > 0):
		x2 = np.zeros((nrec_step, (num_sb-wall_on)))
		Nres_dry = np.zeros((nrec_step, (num_sb-wall_on)))
		Nres_wet = np.zeros((nrec_step, (num_sb-wall_on)))
		rbou_rec = np.zeros((nrec_step, (num_sb-wall_on+1)))
	else:
		x2 = 0.
		Nres_dry = 0.
		Nres_wet = 0.
		rbou_rec = 0.

	# update chamber variables
	[temp_now, Pnow, lightm, light_time_cnt, tnew, ic_red, update_stp, 
		update_count, Cinfl_now, seedt_cnt, Cfactor, infx_cnt, 
		gasinj_cnt, coll_dia] = cham_up.cham_up(sumt, temp, tempt, 
		Pnow, light_stat, light_time, light_time_cnt, light_ad, 0, 
		nuc_ad, nucv1, nucv2, nucv3, np_sum, 
		update_stp, update_count, lat, lon, dayOfYear, photo_path, 
		af_path, injectt, gasinj_cnt, inj_indx, Ct, pmode, pconc, pconct, 
		seedt_cnt, num_comp, y, N_perbin, mean_rad, corei, seedVr, seed_name, 
		lowsize, uppsize, num_sb, MV, rad0, radn, std, y_dens, H2Oi, rbou, 
		const_infl_t, infx_cnt, con_infl_C, wall_on, Cfactor, seedi, coll_dia)
	
	
	if (num_sb-wall_on)>0: # if particles present
		
		# update partitioning variables
		[kimt, kelv_fac] = partit_var.kimt_calc(y, mfp, num_sb, num_comp, accom_coeff, y_mw,   
		surfT, R_gas, temp_now, NA, y_dens*1.e3, N_perbin, 
		x.reshape(1, -1)*1.0e-6, Psat, therm_sp, H2Oi, act_coeff, wall_on, 1, partit_cutoff, 
		Pnow, coll_dia)
		
		# single particle radius (um) at size bin centre 
		# including contribution of water
		x2[0, :] = x

		# single particle size bin bounds including water (um)
		rbou_rec[0, :] = rbou
		
		# estimate particle number size distributions ----------------------------------
		Vnew = np.zeros((num_sb-wall_on))
		ish = N_perbin[:, 0]>1.0e-10
		
		if ish.sum()>0:
			# rearrange particle concentrations into size bins in rows, components in columns
			Cn = y[num_comp:num_comp*(num_sb-wall_on+1)].reshape(num_sb-wall_on, num_comp)
			# new volume of single particle per size bin (um3) excluding volume of water	
			Vnew[ish] = (np.sum((Cn[ish, :]/(si.N_A*N_perbin[ish]))*MV[:, 0]*1.e12, 1)-
					((Cn[ish, H2Oi]/(si.N_A*N_perbin[ish, 0]))*MV[H2Oi, 0]*1.e12))
			# loop through size bins to find number of particles in each 
			# (# particle/cc (air))
			for Ni in range(0, (num_sb-wall_on)):
				ish = (Vnew>=Vbou[Ni])*(Vnew<Vbou[Ni+1])
				Nres_dry[0, Ni] = N_perbin[ish, 0].sum()
			Nres_wet[0, :] = N_perbin[:, 0] # record with water
		
		# end of number size distribution part ----------------------------------------

	else: # fillers
		kimt = kelv_fac = 0.
	
	# update reaction rate coefficients
	rrc = rrc_calc.rrc_calc(RO2_indx, 
			y[H2Oi], temp_now, lightm, y, daytime+sumt, 
			lat, lon, af_path, dayOfYear, Pnow, 
			photo_path, Jlen, tf)

	if len(dydt_vst)>0:		
		# record any change tendencies of specified components
		import dydt_rec
		dydt_vst = dydt_rec.dydt_rec(y, rindx, rstoi, rrc, pindx, pstoi, nprod, 0, 
					dydt_vst, nreac, num_sb, num_comp, N_perbin, core_diss, Psat, kelv_fac, 
					kimt, kw, Cw, act_coeff, corei)


	return(trec, yrec, dydt_vst, Cfactor_vst, Nres_dry, Nres_wet, x2, seedt_cnt, rbou_rec, Cfactor, infx_cnt, coll_dia)