Two-streAm Radiative TransfEr in Snow model
- 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.
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.
Quentin Libois1, Ghislain Picard11Laboratoire 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.
TARTES needs a working Python distribution (version 2.7 or 3.5+) 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
easy_install installed (Installing Python on Windows).
pip install tartes
--useroption if you don't have root privilege under Linux.
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
--useris 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.
To compute the diffuse albedo (hemispherical-hemispherical reflectance) of an homogeneous snowpack with SSA=20 kg m-2 at 850nm, use the following script:
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)
tartesmodule, the next two lines define the snowpack (here a single layer / homogeneous semi-infinite medium as the
thicknessargument is not given), and the wavelength(s) at which the calculation will be done. The
albedofunction 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
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)
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
sza the solar zenith angle in degree.
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)
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
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).
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):
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:
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.
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 calculationsTARTES can also be used to compute the profile of absorption in the snowpack using the
absorption_profilefunction. It takes the same arguments as the
albedofunction plus one optional argument
totfluxto 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
wavelengthis 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
wavelengthis 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).
import tartes from pylab import * print(tartes) nlayer = 200 # number of layers ssa =  * nlayer # nlayer layers with the same SSA... (in m^2/kg) density =  * 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()
tartesfunction which returns both albedo and absorption profile in one calculation. See the reference documentation for details.
Irradiance profile calculationsThe profiles of up- and downwelling irradiances in the snowpack can be calculated using the
irradiance_profilefunction. The arguments are the same as for the absorption profile, plus one additional parameter: the depths
zat 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
zas the second one, if
wavelengthis an array, and a 1-d array otherwise like the function
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 calculationsThe actinic flux profile can be calculated using the
actinic_profilefunction. This function takes the same arguments as
irradiance_profileand returns one profile as a 1-d or 2-d array using the same convention as the latter function.
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
- 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
TARTES development was supported by the French Agence Nationale pour la Recherche (ANR) MONISNOW programme.
- 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