"""
created matt_dumont
on: 10/07/23
"""
import numpy as np
import pandas as pd
[docs]
def exponential_piston_flow(t, tm, f):
"""
produce an exponential piston flow model pdf
:param t: time steps to calculate pdf for (yrs)
:param tm: mean residence time (yrs)
:param f: fraction of the total source that is in the fast flow component
:return:
"""
t = np.atleast_1d(t)
out = np.zeros_like(t)
idx = t >= tm * (1 - f)
out[idx] = (f * tm) ** -1. * np.e ** (-(t[idx] / f / tm) + (1 / f) - 1)
return out
[docs]
def binary_exp_piston_flow(t, mrt_p1, mrt_p2, frac_p1, f_p1, f_p2):
"""
produce a binary exponential piston flow model pdf
:param t: time steps to calculate pdf for (yrs)
:param mrt_p1: mean residence time of the first piston flow component (yrs)
:param mrt_p2: mean residence time of the second piston flow component (yrs)
:param frac_p1: fraction of the total source that is in the first piston flow component
:param f_p1: fraction of the first piston flow component that is in the fast flow component
:param f_p2: fraction of the second piston flow component that is in the fast flow component
:return: pdf of the binary exponential piston flow model
"""
frac_p2 = 1 - frac_p1
out = (frac_p1 * exponential_piston_flow(t, mrt_p1, f_p1)
+ frac_p2 * exponential_piston_flow(t, mrt_p2, f_p2))
return out
[docs]
def exponential_piston_flow_cdf(t, tm, f):
"""
produce a cdf for an exponential piston flow model
:param t: time steps to calculate cdf for (yrs)
:param tm: mean residence time (yrs)
:param f: fraction of the total source that is in the fast flow component
:return:
"""
t = np.atleast_1d(t).astype(float)
tm = float(tm)
f = float(f)
out = np.zeros_like(t)
idx = t >= tm * (1 - f)
out[idx] = 1 - np.e ** (-(t[idx] / f / tm) + (1 / f) - 1)
return out
[docs]
def binary_exp_piston_flow_cdf(t, mrt_p1, mrt_p2, frac_p1, f_p1, f_p2):
"""
produce a cdf for a binary exponential piston flow model
:param t: time steps to calculate cdf for (yrs)
:param mrt_p1: mean residence time of the first piston flow model (yrs)
:param mrt_p2: mean residence time of the second piston flow model (yrs)
:param frac_p1: fraction of the total source that is in the first piston flow model
:param f_p1: fraction of the first piston flow model that is in the fast flow component
:param f_p2: fraction of the second piston flow model that is in the fast flow component
:return: cdf of the binary exponential piston flow model
"""
frac_p1 = float(frac_p1)
frac_p2 = 1 - frac_p1
out = (frac_p1 * exponential_piston_flow_cdf(t, mrt_p1, f_p1)
+ frac_p2 * exponential_piston_flow_cdf(t, mrt_p2, f_p2))
return out
[docs]
def make_age_dist(mrt, mrt_p1, mrt_p2, frac_p1, precision, f_p1, f_p2, start=np.nan):
"""
make an age distribution for the binary exponential piston flow model
:param mrt: mean residence time of the source (yrs) either mrt or mrt_p2 can be None
:param mrt_p1: mean residence time of the first piston flow component (yrs)
:param mrt_p2: mean residence time of the second piston flow component (yrs)
:param frac_p1: fraction of the total source that is in the first piston flow component
:param precision: precision of the age distribution (decimal places)
:param f_p1: fraction of the first piston flow component that is in the fast flow component
:param f_p2: fraction of the second piston flow component that is in the fast flow component
:param start: start age for the age distribution (yrs) default is np.nan which will use the maximum of the mrt_p1*5 and mrt_p2*5
:return: a tuple
* age_step: the step size of the age distribution (yrs)
* ages: the ages of the age distribution (yrs)
* age_fractions: the fractions of the age distribution (decimal)
"""
check_age_inputs(mrt, mrt_p1, mrt_p2, frac_p1, precision, f_p1, f_p2)
age_step = round(10 ** -precision, precision)
ages = np.arange(0, np.nanmax([mrt_p1*5, mrt_p2*5, start]), age_step).round(precision)
age_cdf = binary_exp_piston_flow_cdf(ages, mrt_p1, mrt_p2, frac_p1, f_p1, f_p2)
age_fractions = np.diff(age_cdf, prepend=0)
age_fractions = age_fractions / age_fractions.sum()
return age_step, ages, age_fractions