Documentation of the rsas library

This library allows you to model transport through arbitrary control volumes using rank StorAge Selection (rSAS) functions.

Getting started

Before you install

rsas depends on the Python libraries numpy, scipy, and cython, and the example codes use pandas to wrangle the timeseries data. These must all be installed. The Anaconda package (https://store.continuum.io/cshop/anaconda/) contains all the needed pieces, and is an easy way to get started. Install it before you install rsas.

Parts of rsas must be compiled with a C compiler. This generally happens seamlessly on OSX and *nix if you follow the steps below. On Windows you may need to first install Microsoft Visual C++ Compiler for Python 2.7 BEFORE you install Anaconda Python.

https://www.microsoft.com/en-us/download/details.aspx?id=44266

Getting rsas

rsas is available from github: https://github.com/charman2/rsas

The code is still very much in beta. USE AT YOUR OWN RISK. I make no assurances.

The code can be downloaded zipped, but a git clone is recommended so updates can be provided as they are developed.

Installation

The main part of the code is written in Cython to allow fast execution. Before you use rsas you must comile and install it. Open a terminal in the rsas directory and run:

> python setup.py install

It may take a few minutes. You may get warning messages, all of which can be ignored. Error messages cannot though, and will prevent the compilation from completion.

If you are getting strange messages about vcvarsall.bat you may need to install the MS Visual C++ compiler (see above) and then re-install Anaconda Python.

Once the code has compiled successfully you don’t need to do it again unless this code is changed.

Examples

Example uses of rsas are available in the ./examples directory. These should run right out of the box.

steady.py

# -*- coding: utf-8 -*-
"""Storage selection (SAS) functions: example with one flux out at steady state

Runs the rSAS model for a synthetic dataset with one flux in and out
and steady state flow

Theory is presented in:
Harman, C. J. (2014), Time-variable transit time distributions and transport:
Theory and application to storage-dependent transport of chloride in a watershed,
Water Resour. Res., 51, doi:10.1002/2014WR015707.
"""
from __future__ import division
import rsas
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
# =====================================
# Generate the input timeseries
# =====================================
# length of the dataset
S_0 = 4. # <-- volume of the uniformly sampled store
Q_0 = 1.0 # <-- steady-state flow rate
T_0 = S_0 / Q_0
N = 10
n_substeps = 10
# Steady-state flow in and out for N timesteps
J = np.ones(N) * Q_0
Q = np.ones((N,1)) * Q_0
# A timeseries of concentrations
C_J = np.ones((N,1))
#C_J = -np.log(np.random.rand(N,1))
# =========================
# Parameters needed by rsas
# =========================
# The concentration of water older than the start of observations
C_old = 0.
# =========================
# Create the rsas functions
# =========================
# Parameters for the rSAS function
# The uniform distribution extends between S_T=a and S_T=b.
Q_rSAS_fun_type = 'uniform'
ST_min = np.ones(N) * 0.
ST_max = np.ones(N) * S_0
Q_rSAS_fun_parameters = np.c_[ST_min, ST_max]
rSAS_fun_Q1 = rsas.create_function(Q_rSAS_fun_type, Q_rSAS_fun_parameters)
# =================
# Initial condition
# =================
# Unknown initial age distribution, so just set this to zeros
ST_init = np.zeros(N + 1)
# =============
# Run the model - first method
# =============
# Run it
outputs = rsas.solve(J, Q, [rSAS_fun_Q1], ST_init=ST_init,
                     mode='RK4', dt = 1., n_substeps=n_substeps, C_J=C_J, C_old=[C_old], verbose=False, debug=False)
#%%
# Timestep-averaged outflow concentration
# ROWS of C_Q are t - times
# COLUMNS of PQ are q - fluxes
C_Qm1 = outputs['C_Q'][:,0,0]
# =============
# Run the model - second method
# =============
# Run it
print "start this"
outputs = rsas.solve(J, Q, [rSAS_fun_Q1], ST_init=ST_init,
                     mode='RK4', dt = 1., n_substeps=n_substeps, verbose=False, debug=False)
print "done this"
# Age-ranked storage
# ROWS of ST are T - ages
# COLUMNS of ST are t - times
# LAYERS of MS are s - solutes
ST = outputs['ST']
# Timestep-averaged backwards TTD
# ROWS of PQ are T - ages
# COLUMNS of PQ are t - times
# LAYERS of PQ are q - fluxes
PQm = outputs['PQ'][:,:,0]
# Timestep-averaged outflow concentration
# ROWS of C_Q are t - times
# COLUMNS of PQ are q - fluxes
# Use rsas.transport to convolve the input concentration with the TTD
C_Qm2, C_mod_raw, observed_fraction = rsas.transport(PQm, C_J[:,0], C_old)
# ==================================
# Plot the age-ranked storage
# ==================================
print 'Plotting ST at the last timestep'
# The analytical solution for the age-ranked storage is
T = np.arange(N+1)
ST_exact = S_0 * (1 - np.exp(-T/T_0))
# plot this with the rsas estimate
fig = plt.figure(1)
plt.clf()
plt.plot(ST[:,-1], 'b-', label='rsas model', lw=2)
plt.plot(ST_exact, 'r-.', label='analytical solution', lw=2)
plt.ylim((0,S_0))
plt.legend(loc=0)
plt.ylabel('$S_T(T)$')
plt.xlabel('age $T$')
plt.title('Age-ranked storage')
#%%
# =====================================================================
# Outflow concentration estimated using several different TTD
# =====================================================================
# Lets get the instantaneous value of the TTD at the end of each timestep
print 'Getting the instantaneous TTD'
PQi = np.zeros((N+1, N+1))
PQi[:,0]  = rSAS_fun_Q1.cdf_i(ST[:,0],0)
PQi[:,1:] = np.r_[[rSAS_fun_Q1.cdf_i(ST[:,i+1],i) for i in range(N)]].T
# Lets also get the exact TTD
print 'Getting the exact solution'
n=100
T=np.arange(N*n+1.)/n
PQe = np.tile(1-np.exp(-T/T_0), (N*n+1., 1)).T
# Use the transit time distribution and input timeseries to estimate
# the output timeseries for the exact and instantaneous cases
print 'Getting the concentrations'
C_Qi, C_mod_raw, observed_fraction = rsas.transport(PQi, C_J[:,0], C_old)
C_Qei, C_mod_raw, observed_fraction = rsas.transport(PQe, C_J[:,0].repeat(n), C_old)
# This calculates an exact timestep-averaged value
C_Qem = np.reshape(C_Qei,(N,n)).mean(axis=1)
# Plot the results
print 'Plotting concentrations'
fig = plt.figure(2)
plt.clf()
plt.step(np.arange(N), C_Qem, 'r', ls='-', label='mean exact', lw=2, where='post')
plt.step(np.arange(N), C_Qm1, 'g', ls='--', label='mean rsas internal', lw=2, where='post')
plt.step(np.arange(N), C_Qm2, 'b', ls=':', label='mean rsas.transport', lw=2, where='post')
plt.plot((np.arange(N*n) + 1.)/n, C_Qei, 'r-', label='inst. exact', lw=1)
plt.plot(np.arange(N)+1, C_Qi, 'b:o', label='inst. rsas.transport', lw=1)
plt.legend(loc=0)
plt.ylim((0,1))
plt.ylabel('Concentration [-]')
plt.xlabel('time')
plt.title('Outflow concentration')
plt.draw()
plt.show()

steady2.py

# -*- coding: utf-8 -*-
"""Storage selection (SAS) functions: example with multiple fluxes out at steady state

Runs the rSAS model for a synthetic dataset with one flux in and
multiple fluxes out and steady state flow

Theory is presented in:
Harman, C. J. (2014), Time-variable transit time distributions and transport:
Theory and application to storage-dependent transport of chloride in a watershed,
Water Resour. Res., 51, doi:10.1002/2014WR015707.
"""
from __future__ import division
import rsas
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
# Initializes the random number generator so we always get the same result
np.random.seed(0)
# =====================================
# Generate the input timeseries
# =====================================
# length of the dataset
S_0 = 3. # <-- volume of the uniformly sampled store
Q1_0 = 1. # <-- steady-state flow rate
Q2_0 = 1. # <-- steady-state flow rate
T_0 = S_0 / (Q1_0 + Q2_0)
N = 10
n_substeps = 10
# Steady-state flow in and out for N timesteps
J = np.ones(N) * (Q1_0 + Q2_0)
Q = np.c_[[np.ones(N) * Q1_0, np.ones(N) * Q2_0]].T
# A random timeseries of concentrations
C_J = np.ones((N,1))
#C_J = -np.log(np.random.rand(N,1))
# =========================
# Parameters needed by rsas
# =========================
# The concentration of water older than the start of observations
C_old = 0.
# =========================
# Create the rsas functions
# =========================
# Parameters for the rSAS function
# The uniform distribution extends between S_T=a and S_T=b.
Q_rSAS_fun_type = 'uniform'
ST_min = np.ones(N) * 0.
ST_max = np.ones(N) * S_0
Q_rSAS_fun_parameters = np.c_[ST_min, ST_max]
rSAS_fun_Q1 = rsas.create_function(Q_rSAS_fun_type, Q_rSAS_fun_parameters)
Q_rSAS_fun_type = 'uniform'
ST_min = np.ones(N) * 0.
ST_max = np.ones(N) * S_0
Q_rSAS_fun_parameters = np.c_[ST_min, ST_max]
rSAS_fun_Q2 = rsas.create_function(Q_rSAS_fun_type, Q_rSAS_fun_parameters)
rSAS_fun = [rSAS_fun_Q1, rSAS_fun_Q2]
# =================
# Initial condition
# =================
# Unknown initial age distribution, so just set this to zeros
ST_init = np.zeros(N + 1)
# =============
# Run the model
# =============
# Run it
outputs = rsas.solve(J, Q, rSAS_fun, ST_init=ST_init,
                     mode='RK4', dt = 1., n_substeps=n_substeps, C_J=C_J, C_old=[C_old], verbose=False, debug=False)
# Let's pull these out to make the outputs from rsas crystal clear
# State variables: age-ranked storage of water and solutes
# ROWS of ST, MS are T - ages
# COLUMNS of ST, MS are t - times
# LAYERS of MS are s - solutes
ST = outputs['ST']
MS = outputs['MS'][:,:,0]
# Timestep-averaged backwards TTD
# ROWS of PQ are T - ages
# COLUMNS of PQ are t - times
# LAYERS of PQ are q - fluxes
PQ1m = outputs['PQ'][:,:,0]
PQ2m = outputs['PQ'][:,:,1]
# Timestep-averaged outflow concentration
# ROWS of C_Q are t - times
# COLUMNS of C_Q are q - fluxes
C_Q1m1 = outputs['C_Q'][:,0,0]
C_Q2m1 = outputs['C_Q'][:,1,0]
# Timestep averaged solute load out
# ROWS of MQ are T - ages
# COLUMNS of MQ are t - times
# LAYERS of MQ are q - fluxes
# Last dimension of MQ are s - solutes
MQ1m = outputs['MQ'][:,:,0,0]
MQ2m = outputs['MQ'][:,:,1,0]
#%%
# ==================================
# Plot the age-ranked storage
# ==================================
# The analytical solution for the age-ranked storage is
T = np.arange(N+1)
ST_exact = S_0 * (1 - np.exp(-T/T_0))
# plot this with the rsas estimate
fig = plt.figure(1)
plt.clf()
plt.plot(ST[:,-1], 'b-', label='rsas model', lw=2)
plt.plot(ST_exact, 'r-.', label='analytical solution', lw=2)
plt.ylim((0,S_0))
plt.legend(loc=0)
plt.ylabel('$S_T(T)$')
plt.xlabel('age $T$')
plt.title('Age-ranked storage')
#%%
# =====================================================================
# Outflow concentration estimated using several different TTD
# =====================================================================
# Lets get the instantaneous value of the TTD at the end of each timestep
PQ1i = np.zeros((N+1, N+1))
PQ1i[:,0]  = rSAS_fun_Q1.cdf_i(ST[:,0],0)
PQ1i[:,1:] = np.r_[[rSAS_fun_Q1.cdf_i(ST[:,i+1],i) for i in range(N)]].T
# Lets also get the exact TTD for the combined flux out
n=100
T=np.arange(N*n+1.)/n
PQ1e = np.tile(1-np.exp(-T/T_0), (N*n+1., 1)).T
# Use the transit time distribution and input timeseries to estimate
# the output timeseries for the exact, instantaneous and timestep-averaged cases
C_Q1m2, C_mod_raw, observed_fraction = rsas.transport(PQ1m, C_J[:,0], C_old)
C_Q1i, C_mod_raw, observed_fraction = rsas.transport(PQ1i, C_J[:,0], C_old)
C_Q1ei, C_mod_raw, observed_fraction = rsas.transport(PQ1e, C_J[:,0].repeat(n), C_old)
# This calculates an exact timestep-averaged value
C_Q1em = np.reshape(C_Q1ei,(N,n)).mean(axis=1)
# Plot the results
fig = plt.figure(2)
plt.clf()
plt.step(np.arange(N), C_Q1em, 'r', ls='-', label='mean exact', lw=2, where='post')
plt.step(np.arange(N), C_Q1m1, 'g', ls='--', label='mean rsas internal', lw=2, where='post')
plt.step(np.arange(N), C_Q1m2, 'b', ls=':', label='mean rsas.transport', lw=2, where='post')
plt.plot((np.arange(N*n) + 1.)/n, C_Q1ei, 'r-', label='inst. exact', lw=1)
plt.plot(np.arange(N)+1, C_Q1i, 'b:o', label='inst. rsas.transport', lw=1)
plt.legend(loc=0)
plt.ylabel('Concentration [-]')
plt.xlabel('time')
plt.title('Outflow concentration')
plt.show()

unsteady.py

# -*- coding: utf-8 -*-
"""Storage selection (SAS) functions: example with multiple fluxes out at steady state

Runs the rSAS model for a synthetic dataset with one flux in and
multiple fluxes out and steady state flow

Theory is presented in:
Harman, C. J. (2014), Time-variable transit time distributions and transport:
Theory and application to storage-dependent transport of chloride in a watershed,
Water Resour. Res., 51, doi:10.1002/2014WR015707.
"""
from __future__ import division
import rsas
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
# Initializes the random number generator so we always get the same result
np.random.seed(0)
# =====================================
# Load the input data
# =====================================
data = pd.read_csv('Q1.csv', index_col=0, parse_dates=[1])
# length of the dataset
N = len(data)
# The individual timeseries can be pulled out of the dataframe
S = data['S'].values
J = data['J'].values
Q = data['Q1'].values
C_J = data['C_J'].values-2
C_Q1 = data['C_Q1'].values
ST_min = data['ST_min'].values
ST_max = data['ST_max'].values
# =========================
# Parameters needed by rsas
# =========================
# The concentration of water older than the start of observations
C_old = ((J*C_J)[J>0]).sum()/((J)[J>0]).sum()
# =========================
# Create the rsas functions
# =========================
S_dead = 10.
#lam = 0.
# Uniform
# Parameters for the rSAS function
Q_rSAS_fun_type = 'uniform'
ST_min = np.zeros(N)
ST_max = S + S_dead
Q_rSAS_fun_parameters = np.c_[ST_min, ST_max]
rSAS_fun_Q1 = rsas.create_function(Q_rSAS_fun_type, Q_rSAS_fun_parameters)
rSAS_fun = [rSAS_fun_Q1]
# Kumaraswami
## Parameters for the rSAS function
#Q_rSAS_fun_type = 'kumaraswami'
#ST_min = np.ones(N) * 0.
#ST_max = S + S_dead
#a = np.maximum(0.01, 2. +  lam * (S - S.mean())/S.std())
#b = np.ones(N) * 5.
#Q_rSAS_fun_parameters = np.c_[a, b, ST_min, ST_max]
#rSAS_fun_Q1 = rsas.create_function(Q_rSAS_fun_type, Q_rSAS_fun_parameters)
#rSAS_fun = [rSAS_fun_Q1]
# =================
# Initial condition
# =================
# Unknown initial age distribution, so just set this to zeros
ST_init = np.zeros(N + 1)
# =============
# Run the model
# =============
# Run it
outputs = rsas.solve(J, Q, rSAS_fun, ST_init=ST_init,
                     mode='RK4', dt = 1., n_substeps=3, C_J=C_J, C_old=[C_old], verbose=False, debug=False)
# Let's pull these out to make the outputs from rsas crystal clear
# State variables: age-ranked storage of water and solutes
# ROWS of ST, MS are T - ages
# COLUMNS of ST, MS are t - times
# LAYERS of MS are s - solutes
ST = outputs['ST']
MS = outputs['MS'][:,:,0]
# Timestep-averaged backwards TTD
# ROWS of PQ are T - ages
# COLUMNS of PQ are t - times
# LAYERS of PQ are q - fluxes
PQ1m = outputs['PQ'][:,:,0]
# Timestep-averaged outflow concentration
# ROWS of C_Q are t - times
# COLUMNS of PQ are q - fluxes
C_Q1m1 = outputs['C_Q'][:,0,0]
# Timestep averaged solute load out
# ROWS of MQ are T - ages
# COLUMNS of MQ are t - times
# LAYERS of MQ are q - fluxes
# Last dimension of MS are s - solutes
MQ1m = outputs['MQ'][:,:,0,0]
#%%
# ==================================
# Plot the rSAS function
# ==================================
STx = np.linspace(0,S.max()+S_dead,100)
Omega = np.r_[[rSAS_fun_Q1.cdf_i(STx,i) for i in range(N)]].T
import matplotlib.cm as cm
fig = plt.figure(0)
plt.clf()
for i in range(N):
    plt.plot(STx, Omega[:,i], lw=1, color=cm.jet((S[i]-S.min())/S.ptp()))
plt.ylim((0,1))
plt.ylabel('$\Omega_Q(T)$')
plt.xlabel('age-ranked storage $S_T$')
plt.title('Cumulative rSAS function')
#%%
# ==================================
# Plot the transit time distribution
# ==================================
fig = plt.figure(1)
plt.clf()
plt.plot(PQ1m, lw=1)
plt.ylim((0,1))
plt.ylabel('$P_Q(T)$')
plt.xlabel('age $T$')
plt.title('Cumulative transit time distribution')
#%%
# =====================================================================
# Outflow concentration estimated using several different TTD
# =====================================================================
# Lets get the instantaneous value of the TTD at the end of each timestep
PQ1i = np.zeros((N+1, N+1))
PQ1i[:,0]  = rSAS_fun_Q1.cdf_i(ST[:,0],0)
PQ1i[:,1:] = np.r_[[rSAS_fun_Q1.cdf_i(ST[:,i+1],i) for i in range(N)]].T
# Use the transit time distribution and input timeseries to estimate
# the output timeseries for the instantaneous and timestep-averaged cases
C_Q1i, C_Q1i_raw, Q1i_observed_fraction = rsas.transport(PQ1i, C_J, C_old)
C_Q1m2, C_Q1m2_raw, Q1m2_observed_fraction = rsas.transport(PQ1m, C_J, C_old)
# Plot the results
fig = plt.figure(2)
plt.clf()
plt.step(data['datetime'], C_Q1m1, 'g', ls='--', label='mean rsas internal', lw=2, where='post')
plt.step(data['datetime'], C_Q1m2, 'b', ls=':', label='mean rsas.transport', lw=2, where='post')
plt.step(data['datetime'], C_Q1m2_raw, '0.5', ls=':', label='mean rsas.transport (obs part)', lw=2, where='post')
plt.plot(data['datetime'], C_Q1i, 'b:o', label='inst. rsas.transport', lw=1)
#plt.plot(data['datetime'], data['C_Q1'], 'r.', label='observed', lw=2)
plt.ylim((-2, 0))
plt.legend(loc=0)
plt.ylabel('Concentration [-]')
plt.xlabel('time')
plt.title('Outflow concentration')
plt.show()

Further reading

The rSAS theory is described in:

Harman, C. J. (2014), Time-variable transit time distributions and transport: Theory and application to storage-dependent transport of chloride in a watershed, Water Resour. Res., 51, doi:10.1002/2014WR015707.

More information may be available at: http://landscapehydrology.com/rsas/

Documentation for the code

rsas.solve()

Solve the rSAS model for given fluxes

Args:
J : n x 1 float64 ndarray
Timestep-averaged inflow timeseries for n timesteps
Q : n x q float64 ndarray or list of length n 1D float64 ndarray
Timestep-averaged outflow timeseries for n timesteps and q outflow fluxes. Must have same units and length as J. For multiple outflows, each column represents one outflow
rSAS_fun : rSASFunctionClass or list of rSASFunctionClass generated by rsas.create_function
The number of rSASFunctionClass in this list must be the same as the number of columns in Q if Q is an ndarray, or elements in Q if it is a list.
Kwargs:
ST_init : m+1 x 1 float64 ndarray
Initial condition for the age-ranked storage. The length of ST_init determines the maximum age calculated. The first entry must be 0 (corresponding to zero age). To calculate transit time dsitributions up to m timesteps in age, ST_init should have length m + 1. The default initial condition is ST_init=np.zeros(len(J) + 1).
dt : float (default 1)
Timestep, assuming same units as J
n_substeps : int (default 1)
If n_substeps>1, the timesteps are subdivided to allow a more accurate solution.
full_outputs : bool (default True)
Option to return the full state variables array ST the cumulative transit time distributions PQ, and other variables
verbose : bool (default False)
Print information about the progression of the model
debug : bool (default False)
Print information ever substep
C_J : n x s float64 ndarray (default None)
Optional timeseries of inflow concentrations for s solutes
CS_init : s X 1 or m+1 x s float64 ndarray
Initial condition for calculating the age-ranked solute mass. Must be a 2-D array the same length as ST_init or a 1-D array, where the concentration in storage is assumed to be constant for all ages.
C_old : s x 1 float64 ndarray (default None)
Optional concentration of the ‘unobserved fraction’ of Q (from inflows prior to the start of the simulation) for correcting C_Q. If ST_init is not given or set to all zeros, the unobserved fraction will be assumed for water that entered prior to time zero (diagonal of the PQ matrix). Otherwise it will be used for water older than the oldest water in ST (the bottom row of the PQ matrix).
alpha : n x q x s or q x s float64 ndarray
Optional partitioning coefficient relating discharge concentrations cQ and storage concentration cS as cQ = alpha x cS. Alpha can be specified as a 2D q x s array if it is assumed to be constant, or as a n x q x s array if it is to vary in time.
k1 : s x 1 or n x s float64 ndarray (default none)
Optional first order reaction rate. May be specified as n x s if allowed to vary in time, or s x 1 if constant.
C_eq : s x 1 or n x s float64 ndarray (default none)
Optional equilibrium concentration for first-order reaction rate. Assumed to be 0 if omitted.
Returns:
A dict with the following keys:
‘ST’ : m+1 x n+1 numpy float64 2D array
Array of age-ranked storage for n times, m ages. (full_outputs=True only)
‘PQ’ : m+1 x n+1 x q numpy float64 2D array
List of time-varying cumulative transit time distributions for n times, m ages, and q fluxes. (full_outputs=True only)
‘WaterBalance’ : m x n numpy float64 2D array
Should always be within tolerances of zero, unless something is very wrong. (full_outputs=True only)
‘C_Q’ : n x q x s float64 ndarray
If C_J is supplied, C_Q is the timeseries of outflow concentration
‘MS’ : m+1 x n+1 x s float64 ndarray
Array of age-ranked solute mass for n times, m ages, and s solutes. (full_outputs=True only)
‘MQ’ : m+1 x n+1 x q x s float64 ndarray
Array of age-ranked solute mass flux for n times, m ages, q fluxes and s solutes. (full_outputs=True only)
‘MR’ : m+1 x n+1 x s float64 ndarray
Array of age-ranked solute reaction flux for n times, m ages, and s solutes. (full_outputs=True only)
‘SoluteBalance’ : m x n x s float64 ndarray
Should always be within tolerances of zero, unless something is very wrong. (full_outputs=True only)

For each of the arrays in the full outputs each row represents an age, and each column is a timestep. For n timesteps and m ages, ST will have dimensions (n+1) x (m+1), with the first row representing age T = 0 and the first column derived from the initial condition.

rsas.create_function()

Initialize an rSAS function

Args:
rSAS_type : str
A string indicating the requested rSAS functional form.
params : n x k float64 ndarray
Parameters for the rSAS function. The number of columns and their meaning depends on which rSAS type is chosen. For all the rSAS functions implemented so far, each row corresponds with a timestep.
Returns:
rSAS_fun : rSASFunctionClass
An rSAS function of the chosen type

The created function object will have methods that vary between types. All must have a constructor (“__init__”) and two methods cdf_all and cdf_i. See the documentation for rSASFunctionClass for more information.

Available choices for rSAS_type, and a description of parameter array, are below. These all take one parameter set (row) per timestep:

‘uniform’ : Uniform distribution over the range [a, b].
  • Q_params[:, 0] = ST_min
  • Q_params[:, 1] = ST_max
‘kumaraswami’: Kumaraswami distribution
  • Q_params[:, 0] = ST_min parameter
  • Q_params[:, 1] = ST_max parameter
  • Q_params[:, 2] = a parameter
  • Q_params[:, 3] = b parameter
‘gamma’ : Gamma distribution, truncated at a maximum value (can be inf)
  • Q_params[:, 0] = ST_min parameter
  • Q_params[:, 1] = ST_max parameter (set as inf if undefined)
  • Q_params[:, 2] = scale parameter
  • Q_params[:, 3] = shape parameter
‘lookuptable’ : Lookup table of values. First value of Omega must be 0 and last must be 1.
  • Q_params[:, 0] = S_T
  • Q_params[:, 1] = Omega(S_T)
rsas.transport()

Apply a time-varying transit time distribution to an input concentration timseries

Args:
PQ : numpy float64 2D array, size N x N
The CDF of the backwards transit time distribution P_Q1(T,t)
C_in : numpy float64 1D array, length N.
Timestep-averaged inflow concentration.
C_old : float
Concentration to be assumed for portion of outflows older than initial timestep
Returns:
C_out : numpy float64 1D array, length N.
Timestep-averaged outflow concentration.
C_mod_raw : numpy float64 1D array, length N.
Timestep-averaged outflow concentration, prior to correction with C_old.
observed_fraction : numpy float64 1D array, length N.
Fraction of outflow older than the first timestep

Indices and tables