# Two-streAm Radiative TransfEr in Snow model

## News

- Snowtartes is an accessible web app to compute albedo using TARTES. It is made to be user-friendly!
- 2016/04/25: Version 1.0 solves thin layers issues. Python 3.5 is supported. TARTES is now mature enough.
- 2015/06/06: Version 0.9.3 solves a syntax issue with Python 3.4.
- 2015/06/03: Version 0.9.2 solves a bug that affects scientific results. It occurs for snowpacks made of a thin layer (e.g. 1cm) above a very thick one (e.g. 1m). The model erroneously removed the large layer from the calculation. This version also adds a feature, it is now possible to select different refractive index tables (Warren et al. 1995 and 2008 are implemented) or specify your own. The code has also being cleaned up following PEP8 recommendations.
- 2014/10/10: Version 0.9. While TARTES has been extensively used for our research up to now, the code has been enhanced to provide a convenient interface with simple function calls (and a lot of optional parameters). Therefore, this version is a 'release candidate' for a stable version in the near future. Please let us know if it's working well.

## Abstract

TARTES is a fast and easy-to-use optical radiative transfer model used to compute spectral albedo of a given snowpack as well as the profiles of energy absorption, irradiance within the snowpack and actinic flux. TARTES represents the snowpack as a stack of horizontal homogeneous layers. Each layer is characterized by the snow specific surface area (SSA), snow density, impurities amount and type, and two parameters for the geometric grain shape: the asymmetry factor g and the absorption enhancement parameter B. The albedo of the bottom interface can be prescribed. The model is fast and easy to use compared to more elaborated models like DISORT - MIE (Stamnes et al. 1988). It is based on the Kokhanovsky and Zege, (2004) formalism for weakly absorbing media to describe the single scattering properties of each layers and the delta-Eddington approximation to solve the radiative transfer equation. Despite its simplicity, it is accurate in the visible and near-infrared range for pristine snow as well as snow containing impurities represented as Rayleigh scatterers (their size is assumed much smaller than the wavelength) whose refractive indices and concentrations can be prescribed.

TARTES is an open source software (GPL License) written in Python and distributed on this site and on github.

TARTES has been initially developed to investigate the influence of the particle shape used to represent snow micro-structure on the penetration of light in the snowpack (Libois et al. 2013, Libois et al. 2014) and to compute the vertical profile of absorbed solar radiation. Nevertheless, it is a general purpose optical radiative transfer model.

## Authors:

Quentin Libois^{1}, Ghislain Picard^{1}

^{1}Laboratoire de Glaciologie et Géophysique de l'Environnement (LGGE) UMR 5183 UJF - CNRS

54 rue Molière - Domaine Universitaire - BP 96

38402 St Martin d'Hères Cedex, FRANCE

While TARTES is free, citation of the initial publication Libois et al. 2013 is appreciated.

## Getting started:

NOTE: the easiest way to perform simple calculation is to use the interactive webapp Snowtartes.

TARTES needs a working Python distribution (version 3.6+) and the numpy and scipy modules. Several examples below require in addition matplotlib to plot graphs. All these modules are available in most Python distributions. Under Linux, Python should be already installed, only numpy and scipy need to be installed in addition using the package manager of your distribution. MacOS and Windows users need to install a Python distribution and ensure to have `pip`

or `easy_install`

installed (Installing Python on Windows).

`pip`

:
`pip install tartes`

`--user`

option if you don't have root privilege under Linux.
If `pip`

is not available, you can try `easy_install`

with the same arguments. Otherwise, download TARTES archive from pypi and uncompress it. Install the module by running:

`python setup.py install`

`--user`

is available if you don't have the root privileges as described in the Python documentation.
If you don't want to install the module, just uncompress the archive and copy the directory `tartes/tartes`

that contains the module into a directory accessible from `python`

(i.e. set `$PYTHONPATH`

for this) or in the directory where you develop the script that import the module. The latter option is the easiest but requires a copy to each script directories which can be make maintenance more tedious.

## Documentation and Examples

The equations and a brief description of the theory implemented in TARTES are described in the scientific documentation. Other details are given in the publications Libois et al. (2013), Libois et al. (2014). TARTES is a python module and is described in the reference documentation of TARTES module (API) generated automatically from the docstrings. In addition, several examples covering the different functionalities of TARTES are commented in the following, their source code can be found in the `examples`

directory. To develop your own script, pick one example, the closest to your need, and make the adequate changes.

### Albedo calculations

To compute the diffuse albedo (hemispherical-hemispherical reflectance) of an homogeneous snowpack with SSA=20 kg m^{-2} at 850nm, use the following script:

File: `examples/semiinfinite_medium_diffuse_albedo.py`

```
import tartes
ssa = 20 # in m^2/kg
density = 300 # in kg/m^3
# the result should be independent of the density for a semi-infinite medium
wavelength = 850e-9 # in m
albedo = tartes.albedo(wavelength, ssa, density)
print(albedo)
```

`tartes`

module, the next two lines define the snowpack (here a single layer / homogeneous semi-infinite medium as the `thickness`

argument is not given), and the wavelength(s) at which the calculation will be done. The `albedo`

function performs the computation using TARTES and return the albedo. The last line print the result which should be about `0.8812`

.
If 'optical radius' sounds more familiar than SSA to you, the conversion can be done using the function `ssa`

as follow:
File: `examples/semiinfinite_medium_diffuse_albedo_with_ropt.py`

```
import tartes
from tartes import ssa
r_opt = 100e-6 # in m
density = 300 # in kg/m^3
# the result should be independent of the density for a semi-infinite medium
wavelength = 850e-9 # in m
albedo = tartes.albedo(wavelength, ssa(r_opt), density)
print(albedo)
```

`0.9058`

.
Note that the diffuse albedo is calculated assuming a directional reflectance at 53° incidence angle rather than a proper integration over all the zenith angle.

To compute the direct albedo (directional-hemispherical reflectance), set the optional parameters `dir_frac=1`

and `sza`

the solar zenith angle in degree.

File: `examples/semiinfinite_medium_direct_albedo.py`

```
import tartes
ssa = 20 # in m^2/kg
density = 300 # in kg/m^3
# the result should be independent of the density for a semi-infinite medium
wavelength = 850e-9 # in m
albedo = tartes.albedo(wavelength, ssa, density, dir_frac=1, sza=30)
print(albedo)
```

`0.8584`

.
To compute and plot the spectrum of diffuse albedo between 300 and 2500 nm with a 10-nm resolution for the same snowpack, use a sequence (list, numpy array, ...) for the `wavelength`

argument:

File: `examples/spectrum_pure_snow.py`

```
import tartes
from pylab import *
ssa = 20 # in m^2/kg
density = 300 # in kg/m^3
wavelengths = arange(300, 2500, 10)*1e-9 # from 300 to 2500nm
albedo = tartes.albedo(wavelengths, ssa, density)
plot(wavelengths*1e9, albedo)
show()
```

For a multi-layered snowpack, the SSA, density and thickness are sequences (list, numpy array, ...) or a constant value if the property is constant throughout the profile. All the sequences must have the same length (= the number of layers).

File: `examples/multilayer.py`

```
import tartes
from pylab import *
ssa = [20, 15, 10] # in m^2/kg
density = [200, 250, 300] # in kg/m^3
thickness = [0.01, 0.10, 1000] # thickness of each layer in meter
wavelengths = arange(300, 2500, 10)*1e-9 # from 300 to 2500 nm
albedo_3layers = tartes.albedo(wavelengths, ssa, density, thickness)
ssa = 20 # in m^2/kg
density = 300 # in kg/m^3
albedo_semiinfinite = tartes.albedo(wavelengths, ssa, density)
# alpha controls the transparency of the curves
plot(wavelengths*1e9, albedo_semiinfinite, alpha=0.7)
plot(wavelengths*1e9, albedo_3layers, alpha=0.7)
show()
```

The albedo of the underlying layer (soil, ice, ...) can be set by using the `soilalbedo`

optional parameter. For instance to test the influence of the thickness of a shallow snowpack overlying a dark surface (albedo = 0.2):

File: `examples/soil.py`

```
import tartes
from pylab import *
ssa = 20 # in m^2/kg
density = 250 # in kg/m^3
thickness = arange(5, 30, 5)*1e-2
wavelengths = arange(300, 1100, 10)*1e-9 # from 300 to 1100nm
for th in thickness:
albedo = tartes.albedo(wavelengths, ssa, density, th, soilalbedo=0.2)
plot(wavelengths*1e9, albedo, label='%g cm' % (th*100))
legend(loc='best')
xlabel('wavelength (nm)')
ylabel('albedo')
show()
```

Impurities are frequent in snow. TARTES is able to compute optical properties of dirty snow provided that the impurity particle size is small with respect to the wavelength (typically less than 500 nm), and their concentration is moderate so that the single scattering albedo remains close to one. The absorption spectrum of different species is provided and new ones can be implemented by the users (see `tartes.impurities`

module). Both the content and the species need to be specified as inputs. Soot is the default species if not specified. The simple example below shows the difference between the reflectance spectra of a semi-infinite snowpack containing soot or HULIS:

File: `examples/spectrum_dirty_snow.py`

```
import tartes
import tartes.impurities
from pylab import *
ssa = 20 # in m^2/kg
density = 300 # in kg/m^3
wavelengths = arange(300, 1000, 10)*1e-9 # from 300 to 2500nm
# pure snow
albedo_pure = tartes.albedo(wavelengths, ssa, density)
# 50ng/g of soot. Soot is the default impurity type
albedo_soot = tartes.albedo(wavelengths, ssa, density, impurities=50e-9)
# 200ng/g of Hulis.
albedo_hulis = tartes.albedo(wavelengths, ssa, density,
impurities=200e-9,
impurities_type=tartes.impurities.HULIS)
plot(wavelengths*1e9, albedo_pure, label='pure snow')
plot(wavelengths*1e9, albedo_soot, label='snow with 50 ng/g soot')
plot(wavelengths*1e9, albedo_hulis, label='snow with 200 ng/g HULIS')
legend(loc='best')
show()
```

For a multi-layered snowpack with several species, the impurities content must be a 2-d array (or any sequence of sequences). The first dimension runs over the layers, and the second over the species.

File: `examples/spectrum_dirty_snow_multilayer.py`

```
import tartes
import tartes.impurities
from pylab import *
ssa = [40, 30, 20] # in m^2/kg
density = [300, 300, 300] # in kg/m^3
thickness = [0.02, 0.05, 1000] # in m
wavelengths = arange(300, 1000, 10)*1e-9 # from 300 to 2500nm
# pure snow
albedo_pure = tartes.albedo(wavelengths, ssa, density, thickness)
# with a profile of soot
albedo_soot = tartes.albedo(wavelengths,
ssa, density, thickness,
impurities=[10e-9, 50e-9, 0])
# A profile of mixture soot+Hulis
impurities_content = [
[10e-9, 50e-9], # soot and HULIS in the first layer
[30e-9, 100e-9], # soot and HULIS in the second layer
[0, 10e-9] # soot and HULIS in the last layer
]
albedo_mixture = tartes.albedo(wavelengths, ssa, density, thickness,
impurities=impurities_content,
impurities_type=[tartes.impurities.Soot,
tartes.impurities.HULIS])
plot(wavelengths*1e9, albedo_pure, label='pure snow')
plot(wavelengths*1e9, albedo_soot, label='snow with a profile of soot')
plot(wavelengths*1e9, albedo_mixture, label='snow with soot and HULIS')
legend(loc='best')
show()
```

### Absorption profile calculations

TARTES can also be used to compute the profile of absorption in the snowpack using the`absorption_profile`

function. It takes the same arguments as the `albedo`

function plus one optional argument `totflux`

to prescribe the incidence flux (diffuse+direct) in W/m^{2}, default value being 1W/m

^{2}. It returns two arrays: the depth of the layers and the absorption in each layer. If

`wavelength`

is a scalar, the latter is a 1-d array with a length of the number of layers plus one, the last value being the absorption by the soil. If `wavelength`

is an array (or any sequence), the result is a 2-d array whose first dimension run over the wavelengths and the second one over the layers (+ the soil).
File: `examples/absorption_profile.py`

```
import tartes
from pylab import *
print(tartes)
nlayer = 200 # number of layers
ssa = [20] * nlayer # nlayer layers with the same SSA... (in m^2/kg)
density = [300] * nlayer # and the same density (in kg/m^3)
# all the layer are 0.01 m thick, the snowpack is nlayer*0.01m deep
thickness = [0.01] * nlayer
wavelengths = [400e-9, 500e-9, 600e-9, 700e-9, 800e-9, 900e-9]
for wl in wavelengths:
z, absorption_profile = tartes.absorption_profile(
wl, ssa, density, thickness, soilalbedo=0.50)
semilogx(absorption_profile, -z, label='%g nm' % (wl * 1e9))
albedo = tartes.albedo(wl, ssa, density, thickness, soilalbedo=0.50)
print(1 - sum(absorption_profile), " ", albedo)
ylabel('depth(m)')
xlabel('absorbed energy (for 1W/m2 incident)')
legend(loc='best')
show()
```

`tartes`

function which returns both albedo and absorption profile in one calculation. See the reference documentation for details.
### Irradiance profile calculations

The profiles of up- and downwelling irradiances in the snowpack can be calculated using the`irradiance_profile`

function. The arguments are the same as for the absorption profile, plus one additional parameter: the depths `z`

at which the irradiance profiles need to be calculated. These depths can be independent of the layer depths. The function returns the up- and downwelling irradiance profiles. Each profile is a 2-d array with the wavelength as the first dimension, and `z`

as the second one, if `wavelength`

is an array, and a 1-d array otherwise like the function `absorption_profile`

.
File: `examples/irradiance_profiles.py`

```
import tartes
from pylab import *
# semi-infinite medium
ssa = [40, 15] # in m^2/kg
density = [300, 350] # in kg/m^3
thickness = [0.3, 1] # in m
# depth at which the calculation is performed (in m)
z = arange(0, 100, 5)*1e-2 # from 0 to 1m depth every 5cm
wavelengths = [400e-9, 600e-9, 800e-9] # in m
for wl in wavelengths:
down_irr_profile, up_irr_profile = tartes.irradiance_profiles(
wl, z, ssa, density, thickness)
semilogx(up_irr_profile, -z, label='upwelling %g nm' % (wl*1e9))
semilogx(down_irr_profile, -z, label='downwelling %g nm' % (wl*1e9))
xlabel('depth (m)')
ylabel('irradiance (W/m^2)')
legend(loc='best')
show()
```

### Actinic fluc profile calculations

The actinic flux profile can be calculated using the`actinic_profile`

function. This function takes the same arguments as `irradiance_profile`

and returns one profile as a 1-d or 2-d array using the same convention as the latter function.
File: `examples/actinic_profile.py`

```
import tartes
from pylab import *
# semi-infinite medium
ssa = [40, 15] # in m^2/kg
density = [300, 350] # in kg/m^3
thickness = [0.3, 1] # in m
# depth at which the calculation is performed
z = arange(0, 100, 1) * 1e-2 # from 0 to 1m depth every cm
wavelengths = [350e-9, 400e-9]
for wl in wavelengths:
actinic_flux_profile = tartes.actinic_profile(
wl, z, ssa, density, thickness)
semilogx(actinic_flux_profile, -z, label='%g nm' % (wl * 1e9))
xlabel('depth (m)')
ylabel('Actinic flux (W/m^2)')
legend(loc='best')
show()
```

## Recommended citation and other articles

### Recommended citation:

- Q. Libois, G. Picard, J. France, L. Arnaud, M. Dumont , C. Carmagnola , and M. D. King, Influence of grain shape on light penetration in snow,
*The Cryosphere*, 7, 1803-1818, 2013, doi:10.5194/tc-7-1803-2013

### Other papers using TARTES:

- Libois, Q., Picard, G., Dumont, M., Arnaud, L., Sergent, C., Pougatch, E., & Vial, D. (2014). Experimental determination of the absorption enhancement parameter of snow.
*Journal of Glaciology*, 60(222), 714., doi:10.3189/2014JoG14J015

## Acknowledgment:

TARTES development was supported by the French Agence Nationale pour la Recherche (ANR) MONISNOW programme.

## Bibliography:

- Stamnes, K., Tsay, S. C., Wiscombe, W., & Jayaweera, K. (1988). Numerically stable algorithm for discrete-ordinate-method radiative transfer in multiple scattering and emitting layered media.
*Applied Optics*, 27(12), 2502-2509, doi:10.1364/AO.27.002502 - Kokhanovsky, A. A., & Zege, E. P. (2004). Scattering optics of snow.
*Applied Optics*, 43(7), 1589-1602, doi: 10.1364/AO.43.001589