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!
  • If you need to compute irradiance profiles in addition to albedo, you can try the new development version snowtartes-dev
  • 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 Libois1, Ghislain Picard1

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).

With a working python, the easiest way to install TARTES is by using pip:
pip install tartes
add the --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
the option --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)
The first line import the 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)
The results should be 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)
The result should be 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()
Dust could be implemented in the future but these particles are usually not small with respect to the wavelength and the Rayleigh theory used by TARTES for impurities does not apply.

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/m2, default value being 1W/m2. 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()
This code also computes the albedo in a second step and compares it with one minus the sum of the absorption. Both values should be equal. Here TARTES is called twice in this code which is not computationally efficient. An alternative is to use the low-level 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:

Other papers using TARTES:

Acknowledgment:

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

Bibliography: