SMRT

smrt.core package

Submodules

smrt.core.atmosphere module

class AtmosphereBase

Bases: object

smrt.core.error module

Definition of the Exception specific to SMRT.

exception SMRTError

Bases: Exception

Error raised by the model

exception SMRTWarning

Bases: Warning

Warning raised by the model

smrt_warn(message)

smrt.core.filelock module

A platform independent file lock that supports the with-statement.

exception Timeout(lock_file)

Bases: TimeoutError

Raised when the lock could not be acquired in timeout seconds.

lock_file = None

The path of the file lock.

class BaseFileLock(lock_file, timeout=-1)

Bases: object

Implements the base class of a file lock.

lock_file

The path to the lock file.

timeout

You can set a default timeout for the filelock. It will be used as fallback value in the acquire method, if no timeout value (None) is given.

If you want to disable the timeout, set it to a negative value.

A timeout of 0 means, that there is exactly one attempt to acquire the file lock.

New in version 2.0.0.

is_locked

True, if the object holds the file lock.

Changed in version 2.0.0: This was previously a method and is now a property.

acquire(timeout=None, poll_intervall=0.05)

Acquires the file lock or fails with a Timeout error.

# You can use this method in the context manager (recommended)
with lock.acquire():
    pass

# Or use an equivalent try-finally construct:
lock.acquire()
try:
    pass
finally:
    lock.release()
Parameters:
  • timeout (float) – The maximum time waited for the file lock. If timeout < 0, there is no timeout and this method will block until the lock could be acquired. If timeout is None, the default timeout is used.
  • poll_intervall (float) – We check once in poll_intervall seconds if we can acquire the file lock.
Raises:

Timeout – if the lock could not be acquired in timeout seconds.

Changed in version 2.0.0: This method returns now a proxy object instead of self, so that it can be used in a with statement without side effects.

release(force=False)

Releases the file lock.

Please note, that the lock is only completly released, if the lock counter is 0.

Also note, that the lock file itself is not automatically deleted.

Parameters:force (bool) – If true, the lock counter is ignored and the lock is released in every case.
class WindowsFileLock(lock_file, timeout=-1)

Bases: smrt.core.filelock.BaseFileLock

Uses the msvcrt.locking() function to hard lock the lock file on windows systems.

class UnixFileLock(lock_file, timeout=-1)

Bases: smrt.core.filelock.BaseFileLock

Uses the fcntl.flock() to hard lock the lock file on unix systems.

class SoftFileLock(lock_file, timeout=-1)

Bases: smrt.core.filelock.BaseFileLock

Simply watches the existence of the lock file.

FileLock

Alias for the lock, which should be used for the current platform. On Windows, this is an alias for WindowsFileLock, on Unix for UnixFileLock and otherwise for SoftFileLock.

alias of smrt.core.filelock.UnixFileLock

smrt.core.fresnel module

fresnel coefficients formulae used in the packages smrt.interface and smrt.substrate.

fresnel_coefficients_old(eps_1, eps_2, mu1)

compute the reflection in two polarizations (H and V). The equations are only valid for lossless media. Applying these equations for (strongly) lossy media result in (large) errors. Don’t use it. It is here for reference only.

Parameters:
  • eps_1 – permittivity of medium 1.
  • eps_2 – permittivity of medium 2.
  • mu1 – cosine zenith angle in medium 1.
Returns:

rv, rh, mu2 the cosine of the angle in medium 2

fresnel_coefficients_maezawa09_classical(eps_1, eps_2, mu1, full_output=False)

compute the reflection in two polarizations (H and V) for lossly media with the “classical Fresnel” based on Maezawa, H., & Miyauchi, H. (2009). Rigorous expressions for the Fresnel equations at interfaces between absorbing media. Journal of the Optical Society of America A, 26(2), 330. https://doi.org/10.1364/josaa.26.000330

The classical derivation does not respect energy conservation, especially the transmittivity. Don’t use it. It is here for reference only.

Parameters:
  • eps_1 – permittivity of medium 1.
  • eps_2 – permittivity of medium 2.
  • mu1 – cosine zenith angle in medium 1.
Returns:

rv, rh, mu2 the cosine of the angle in medium 2

fresnel_coefficients_maezawa09_rigorous(eps_1, eps_2, mu1, full_output=False)

compute the reflection in two polarizations (H and V) for lossly media with the “rigorous Fresnel” based on Maezawa, H., & Miyauchi, H. (2009). Rigorous expressions for the Fresnel equations at interfaces between absorbing media. Journal of the Optical Society of America A, 26(2), 330. https://doi.org/10.1364/josaa.26.000330

The ‘rigorous’ derivation respect the energy conservation even for strongly loosly media.

Parameters:
  • eps_1 – permittivity of medium 1.
  • eps_2 – permittivity of medium 2.
  • mu1 – cosine zenith angle in medium 1.
Returns:

rv, rh, mu2 the cosine of the angle in medium 2

fresnel_coefficients(eps_1, eps_2, mu1, full_output=False)

compute the reflection in two polarizations (H and V) for lossly media with the “rigorous Fresnel” based on Maezawa, H., & Miyauchi, H. (2009). Rigorous expressions for the Fresnel equations at interfaces between absorbing media. Journal of the Optical Society of America A, 26(2), 330. https://doi.org/10.1364/josaa.26.000330

The ‘rigorous’ derivation respect the energy conservation even for strongly loosly media.

Parameters:
  • eps_1 – permittivity of medium 1.
  • eps_2 – permittivity of medium 2.
  • mu1 – cosine zenith angle in medium 1.
Returns:

rv, rh, mu2 the cosine of the angle in medium 2

snell_angle(eps_1, eps_2, mu1)

compute mu2 the cos(angle) in the second medium according to Snell’s law.

brewster_angle(eps_1, eps_2)

compute the brewster angle

Parameters:
  • eps_1 – permittivity of medium 1.
  • eps_2 – permittivity of medium 2.
Returns:

angle in radians

fresnel_reflection_matrix(eps_1, eps_2, mu1, npol)

compute the fresnel reflection matrix for/in medium 1 laying above medium 2.

Parameters:
  • npol – number of polarizations to return.
  • eps_1 – permittivity of medium 1.
  • eps_2 – permittivity of medium 2.
  • mu1 – cosine zenith angle in medium 1.
Returns:

a matrix or the diagional depending on return_as_diagonal

fresnel_transmission_matrix(eps_1, eps_2, mu1, npol)

compute the fresnel reflection matrix for/in medium 1 laying above medium 2.

Parameters:
  • npol – number of polarizations to return.
  • eps_1 – permittivity of medium 1.
  • eps_2 – permittivity of medium 2.
  • mu1 – cosine zenith angle in medium 1.
Returns:

a matrix or the diagional depending on return_as_diagonal

smrt.core.globalconstants module

Global constants used throughout the model are defined here and imported as needed. The constants are:

Parameter Description Value
DENSITY_OF_ICE Density of pure ice at 273.15K 916.7 kg m -3
FREEZING_POINT Freezing point of pure water 273.15 K
C_SPEED Speed of light in a vacuum 2.99792458 x 10 8 ms -1
PERMITTIVITY_OF_AIR Relative permittivity of air 1

Usage example:

from smrt.core.globalconstants import DENSITY_OF_ICE

smrt.core.interface module

This module implements the base class for all the substrate models. To create a substrate, it is recommended to use help functions such as make_soil() rather than the class constructor.

make_interface(inst_class_or_modulename, broadcast=True, **kwargs)

return an instance corresponding to the interface model with the provided arguments.

This function imports the interface module if necessary and return an instance of the interface class with the provided arguments in **kwargs.

Parameters:
  • inst_class_or_modulename – a class, and instance or the name of the python module in smrt/interface
  • **kwargs

    all the arguments required by the interface class

class Interface(**kwargs)

Bases: object

Abstract class for interface between layer and substrate at the bottom of the snowpack. It provides argument handling.

args = []
optional_args = {}
class SubstrateBase(temperature=None, permittivity_model=None)

Bases: object

Abstract class for substrate at the bottom of the snowpack. It provides calculation of the permittivity constant for soil case. Argument handline is delegated to the instance of the interface

permittivity(frequency)

compute the permittivity for the given frequency using permittivity_model. This method returns None when no permittivity model is available. This must be handled by the calling code and interpreted suitably.

substrate_from_interface(interface_cls)

this decorator transform an interface class into a substrate class with automatic method

class Substrate(temperature=None, permittivity_model=None, **kwargs)

Bases: smrt.core.interface.SubstrateBase, smrt.core.interface.Interface

get_substrate_model(substrate_model)

return the class corresponding to the substrate model called name. This function imports the correct module if possible and returns the class

smrt.core.layer module

Layer instance contains all the properties for a single snow layer (e.g. temperature, frac_volume, etc). It also contains a microstructure attribute that holds the microstructural properties (e.g. radius, corr_length, etc). The class of this attribute defines the microstructure model to use (see smrt.microstructure_model package).

To create a single layer, it is recommended to use the function make_snow_layer() rather than the class constructor. However it is usually more convenient to create a snowpack using make_snowpack().

For developers

The Layer class should not be modified at all even if you need new properties to define the layer (e.g. brine concentration, humidity, …). If the property you need to add is related to geometric aspects, it is probably better to use an existing microstructure model or to create a new one. If the new parameter is not related to geometrical aspect, write a function similar to make_snow_layer() (choose an explicit name for your purpose). In this function, create the layer by calling the Layer constructor as in make_snow_layer() and then add your properties with lay.myproperty=xxx, … See the example of liquid water in make_snow_layer(). This approach avoids specialization of the Layer class. The new function can be in any file (inc. out of smrt directories), and should be added in make_medium if it is of general interest and written in a generic way, that is, covers many use cases for many users with default arguments, etc.

class Layer(thickness, microstructure_model=None, temperature=273.15, permittivity_model=None, inclusion_shape=None, **kwargs)

Bases: object

Contains the properties for a single layer including the microstructure attribute which holds the microstructure properties.

To create layer, it is recommended to use of the functions make_snow_layer() and similar

ssa

return the SSA, compute it if necessary

frac_volume
permittivity(i, frequency)

return the permittivity of the i-th medium depending on the frequency and internal layer properties. Usually i=0 is air and i=1 is ice for dry snow with a low or moderate density.

Parameters:
  • i – number of the medium. 0 is reserved for the background
  • frequency – frequency of the wave (Hz)
Returns:

complex permittivity of the i-th medium

basic_checks()

Function to provide very basic input checks on the layer information

Currently checks:

  • temperature is between 100 and the freezing point (Kelvin units check),
  • density is between 1 and DENSITY_OF_ICE (SI units check)
  • layer thickness is above zero
inverted_medium()

return the layer with inverted autocorrelation and inverted permittivities.

update(**kwargs)

update the attributes. This method is to be used when recalculation of the state of the object is necessary. See for instance SnowLayer.

get_microstructure_model(modulename, classname=None)

return the class corresponding to the microstructure_model defined in modulename.

This function import the correct module if possible and return the class. It is used internally and should not be needed for normal usage.

Parameters:modulename – name of the python module in smrt/microstructure_model
make_microstructure_model(modelname_or_class, **kwargs)

create an microstructure instance.

This function is called internally and should not be needed for normal use.

param modelname_or_class:
 name of the module or directly the class.
param type:string
param **kwargs:all the arguments need for the specific autocorrelation.
returns:instance of the autocorrelation modelname with the parameters given in **kwargs
Example:

To import the StickyHardSpheres class with spheres radius of 1mm, stickiness of 0.5 and fractional_volume of 0.3:

shs = make_autocorrelation("StickyHardSpheres", radius=0.001, stickiness=0.5, frac_volume=0.3)
layer_properties(*required_arguments, optional_arguments=None, **kwargs)

This decorator is used for the permittivity functions (or any other functions) to inject layer’s attributes as arguments. The decorator declares the layer properties needed to call the function and the optional ones. This allows permittivity functions to use any property of the layer, as long as it is defined.

smrt.core.lib module

get(x, i, name=None)
check_argument_size(x, n, name=None)
is_sequence(x)
len_atleast_1d(x)
class smrt_diag(arr)

Bases: object

Scipy.sparse is very slow for diagonal matrix and numpy has no good support for linear algebra. This diag class implements simple diagonal object without numpy subclassing (but without much features). It seems that proper subclassing numpy and overloading matmul is a very difficult problem.

diagonal()
shape
check_type(other)
class smrt_matrix(mat, mtype=None)

Bases: object

SMRT uses two formats of matrix: one most suitable to implement emmodel where equations are different for each polarization and another one suitable for DORT computation where stream and polarization are collapsed in one dimension to allow matrix operation. In addition, the reflection and transmission matrix are often diagonal matrix, which needs to be handled because it saves space and allow much faster operations. This class implemented all these features.

static empty(dims, mtype=None)
static zeros(dims, mtype=None)
static ones(dims, mtype=None)
static full(dims, value, mtype=None)
npol
is_equal_zero()
compress(mode=None, auto_reduce_npol=False)

compress a matrix. This comprises several actions: 1) select one mode, if relevant (dense5, and diagonal5). 2) reduce the number of polarization from 3 to 2 if mode==0 and auto_reduce_npol=True. 3) convert the format of the matrix to compressed numpy, involving a change of the dimension order (pola and streams are merged).

diagonal
sel(**kwargs)
is_zero_scalar(m)
is_equal_zero(m)

return true if the smrt matrix is null

generic_ft_even_matrix(phase_function, m_max, nsamples=None)

Calculation of the Fourier decomposed of the phase or reflection or transmission matrix provided by the function.

This method calculates the Fourier decomposition modes and return the output.

Coefficients within the phase function are

Passive case (m = 0 only) and active (m = 0)

M  = [Pvvp  Pvhp]
     [Phvp  Phhp]

Active case (m > 0):

M =  [Pvvp Pvhp Pvup]
     [Phvp Phhp Phup]
     [Puvp Puhp Puup]
Parameters:
  • phase_function – must be a function taking dphi as input. It is assumed that phi is symmetrical (it is in cos(phi))
  • m_max – maximum Fourier decomposition mode needed
set_max_numerical_threads(nthreads)

set the maximum number of threads for a few known library. This is useful to disable parallel computing in SMRT when using parallel computing to call multiple // SMRT runs. This avoid over-committing the CPUs and results in much better performance. Inspire from joblib.

cached_roots_legendre(n)

Cache roots_legendre results to speed up calls of the fixed_quad function.

smrt.core.model module

A model in SMRT is composed of the electromagnetic scattering theory (smrt.emmodel) and the radiative transfer solver (smrt.rtsolver). The smrt.emmodel is responsible for computation of the scattering and absorption coefficients and the phase function of a layer. It is applied to each layer and it is even possible to choose different emmodel for each layer (for instance for a complex medium made of different materials: snow, soil, water, atmosphere, …). The smrt.rtsolver is responsible for propagation of the incident or emitted energy through the layers, up to the surface, and eventually through the atmosphere.

To build a model, use the make_model() function with the type of emmodel and type of rtsolver as arguments. Then call the Model.run() method of the model instance by specifying the sensor (smrt.core.sensor.Sensor), snowpack (smrt.core.snowpack.Snowpack) and optionally atmosphere (see smrt.atmosphere). The results are returned as a Result which can then been interrogated to retrieve brightness temperature, backscattering coefficient, etc.

Example:

m = make_model("iba", "rtsolver")

result = m.run(sensor, snowpack)  # sensor and snowpack are created before

print(result.TbV())

The model can be run on a list of snowpacks or even more conveniently on a pandas.Series or pandas.DataFrame including snowpacks. The first advantage is that by setting parallel_computation=True, the Model.run() method performs the simulation in parallel

on all the available cores of your machine and even possibly remotely on a high performance cluster using dask. The second advantage is that the returned Result object contains all the simulations and provide an easier way to plot the results or compute statistics.
If a list of snowpacks is provided, it is recommended to also set the snowpack_dimension argument. It takes the form of a tuple
(list of snowpack_dimension values, dimension name). The name and values are used to define the coordinates in the Result object. This is useful with timeseries or sensitivity analysis for instance.

Example:

snowpacks = []
times = []
for file in filenames:
    #  create a snowpack for each time series
    sp = ...
    snowpacks.append(sp)
    times.append(sp)

# now run the model

res = m.run(sensor, snowpacks, snowpack_dimension=('time', times))

The res variable has now a coordinate time and res.TbV() returns a timeseries.

Using pandas.Series offers an even more elegant way to run SMRT and assemble the results of all the simulations.

thickness_list = np.arange(0, 10, 1) snowpacks = pd.Series([make_snowpack(thickness=t, ……..) for t in thickness_list], index=thickness_list) # snowpacks is a pandas Series of snowpack objects with the thickness as index

# now run the model

res = m.run(sensor, snowpacks, parallel_computation=True)

# convert the result into a datframe res = res.to_dataframe()

The res variable is a dataframe with the thickness as index and the channels of the sensor as column.

Using pandas.DataFrame is similar. One column must contain Snowpack objects (see snowpack_column argument). The results of the simulations are automatically joined with this dataframe and returned by to_dataframe() or to_dataframe().

# df is a DataFrame with several parameters in each row.

# add a snowpack object for each row df[‘snowpack’] = [make_snowpack(thickness=row[‘thickness’], ……..) for i, row in df.iterrows()]]

# now run the model res = m.run(sensor, snowpacks, parallel_computation=True)

# convert the result into a datframe res = res.to_dataframe()

The res variable is a pandas.DataFrame equal to df + the results at all sensor’s channel added.

make_model(emmodel, rtsolver=None, emmodel_options=None, rtsolver_options=None, emmodel_kwargs=None, rtsolver_kwargs=None)

create a new model with a given EM model and RT solver. The model is then ready to be run using the Model.run() method. This function is the privileged way to create models compared to class instantiation. It supports automatic import of the emmodel and rtsolver modules.

Parameters:emmodel – type of emmodel to use. Can be given by the name of a file/module in the emmodel directory (as a string) or a class.

List (and dict, respectively) can be provided when a different emmodel is needed for every layer (or every kind of layer medium). :type emmodel: string or class or list of strings or classes or dict of strings or classes. If a list of emmodels is given, the size must be the same as the number of layers in the snowpack. If a dict is given, the keys are the kinds of medium and the values are the associated emmodels to each sort of medium. The layer attribute ‘medium’ is used to determine the emmodel to use for each layer. :type emmodel: string or class; or list of strings or classes; or dict of strings or classes. :param rtsolver: type of RT solver to use. Can be given by the name of a file/module in the rtsolver directeory (as a string) or a class. :type rtsolver: string or class. Can be None when only computation of the layer electromagnetic properties is needed. :param emmodel_options: extra arguments to use to create emmodel instance. Valid arguments depend on the selected emmodel. It is documented in for each emmodel class. :type emmodel_options: dict or a list of dict. In the latter case, the size of the list must be the same as the number of layers in the snowpack. :param rtsolver_options: extra to use to create the rtsolver instance (see __init__ of the solver used). :type rtsolver_options: dict

Returns:a model instance
get_emmodel(emmodel)

get a new emmodel class from the file name

make_emmodel(emmodel, sensor, layer, **emmodel_options)

create a new emmodel instance based on the emmodel class or string :param emmodel: type of emmodel to use. Can be given by the name of a file/module in the emmodel directory (as a string) or a class. :param sensor: sensor to use for the calculation. :param layer: layer to use for the calculation

class Model(emmodel, rtsolver, emmodel_options=None, rtsolver_options=None)

Bases: object

This class drives the whole calculation

set_rtsolver_options(options=None, **kwargs)

set the option for the rtsolver

set_emmodel_options(options=None, **kwargs)

set the options for the emmodel

run(sensor, snowpack, atmosphere=None, snowpack_dimension=None, snowpack_column='snowpack', progressbar=False, parallel_computation=False, runner=None)

Run the model for the given sensor configuration and return the results

Parameters:
  • sensor – sensor to use for the calculation. Can be a list of the same size as the snowpack list. In this case, the computation is performed for each pair (sensor, snowpack).
  • snowpack – snowpack to use for the calculation. Can be a single snowpack, a list of snowpack, a dict of snowpack or a SensitivityStudy object.
  • snowpack_dimension – name and values (as a tuple) of the dimension to create for the results when a list of snowpack is provided. E.g. time, point, longitude, latitude. By default the dimension is called ‘snowpack’ and the values are rom 1 to the number of snowpacks.
  • snowpack_column – when snowpack is a DataFrame this argument is used to specify which column contians the Snowpack objects
  • progressbar – if True, display a progress bar during multi-snowpacks computation
  • parallel_computation – if True, use the joblib library to run the simulation in parallel. Otherwise, the simulations are run sequentially. See ‘runner’ arguments.
  • runner – a ‘runner’ is a function (or more likely a class with a __call__ method) that takes a function and a list/generator of simulations, executes the function on each simulation and returns a list of results. ‘parallel_computation’ allows to select between two default (basic) runners (sequential and joblib). Use ‘runner’ for more advanced parallel distributed computations.
Returns:

result of the calculation(s) as a Results instance

prepare_simulations(sensor, snowpack, snowpack_dimension, snowpack_column)
prepare_emmodels(sensor, snowpack)
run_single_simulation(simulation, atmosphere)
run_later(sensor, snowpack, **kwargs)
class SequentialRunner(progressbar=False)

Bases: object

Run the simulations sequentially on a single (local) core. This is the most simple way to run smrt simulations, but the efficiency is poor.

class JoblibParallelRunner(backend='loky', n_jobs=-1, max_numerical_threads=1)

Bases: object

Run the simulations on the local machine on all the cores, using the joblib library for parallelism.

smrt.core.optional_numba module

smrt.core.plugin module

register_package(pkg)
import_class

Import the modulename and return either the class named “classname” or the first class defined in the module if classname is None.

Parameters:
  • scope – scope where to search for the module.
  • modulename – name of the module to load.
  • classname – name of the class to read from the module.
do_import_class(modulename, classname)

smrt.core.progressbar module

A progress bar copied and adapted from pyMC code (dec 2014)

class TextProgressBar(iterations, printer, width=40, interval=None)

Bases: smrt.core.progressbar.ProgressBar

Use Progress

animate(i, dummy=None)
progbar(i)
bar(percent)
progress_bar(iters, interval=None)

A progress bar for Python/IPython/IPython notebook

Parameters:
  • iters (int) – number of iterations (steps in the loop)
  • interval – number of intervals to use to update the progress bar (20 by default)
from easydev import progress_bar
pb = progress_bar(10)
for i in range(1,10):
    import time
    time.sleep(0.1)
    pb.animate(i)
class Progress(iters, interval=None)

Bases: object

Generic progress bar for python, IPython, IPython notebook

from easydev import Progress
pb = Progress(100, interval=1)
pb.animate(10)
animate(i)
elapsed

smrt.core.result module

The results of RT Solver are hold by the Result class. This class provides several functions to access to the Stokes Vector and Muller matrix in a simple way. Most notable ones are Result.TbV() and Result.TbH() for the passive mode calculations and Result.sigmaHH() and Result.sigmaVV(). Result.to_dataframe() is also very convenient for the sensors with a channel map (all specific satellite sensors have such a map, only generic sensors as smrt.sensor_list.active() and smrt.sensor_list.passive() does not provide a map by default).

In addition, the RT Solver stores some information in Result.other_data. Currently this includes the effective_permittivity, ks and ka for each layer. The data are accessed directly with e.g. result.other_data[‘ks’].

To save results of calculations in a file, simply use the pickle module or other serialization schemes. We may provide a unified and inter-operable solution in the future.

Under the hood, Result uses xarray module which provides multi-dimensional array with explicit, named, dimensions. Here the common dimensions are frequency, polarization, polarization_inc, theta_inc, theta, and phi. They are created by the RT Solver. The interest

of using named dimension is that slice of the xarray (i.e. results) can be selected based on the dimension name whereas with numpy the order of the dimensions matters. Because this is very convenient, users may be interested in adding other dimensions specific to their context such

as time, longitude, latitude, points, … To do so, smrt.core.model.Model.run() accepts a list of snowpack and optionally the parameter snowpack_dimension is used to specify the name and values of the new dimension to build.

Example:

times = [datetime(2012, 1, 1), datetime(2012, 1, 5), , datetime(2012, 1, 10)]
snowpacks = [snowpack_1jan, snowpack_5jan, snowpack_10jan]

res = model.run(sensor, snowpacks, snowpack_dimension=('time', times))

The res variable is a Result instance, so that for all the methods of this class that can be called, they will return a timeseries. For instance result.TbV(theta=53) returns a time-series of brightness temperature at V polarization and 53° incidence angle and the following code plots this timeseries:

plot(times, result.TbV(theta=53))
open_result(filename)

read a result save to disk. See Result.save() method.

make_result(sensor, *args, **kwargs)

create an active or passive result object according to the mode

class Result(intensity, coords=None, channel_map=None, other_data={}, mother_df=None)

Bases: object

Contains the results of a/many computations and provides convenience functions to access these results

coords

Return the coordinates of the result (theta, frequency, …). Note that the coordinates are also result attribute, so result.frequency works (and so on for all the coordinates).

save(filename)

save a result to disk. Under the hood, this is a netCDF file produced by xarray (http://xarray.pydata.org/en/stable/io.html).

sel_data(channel=None, **kwargs)
return_as_dataframe(name, channel_axis=None, **kwargs)
to_series(**kwargs)

return the result as a series with the channels defined in the sensor as index. This requires that the sensor has declared a channel list.

class PassiveResult(intensity, coords=None, channel_map=None, other_data={}, mother_df=None)

Bases: smrt.core.result.Result

mode = 'P'
sel_data(channel=None, **kwargs)
Tb(channel=None, **kwargs)

Return brightness temperature. Any parameter can be added to slice the results (e.g. frequency=37e9 or polarization=’V’). See xarray slicing with sel method (to document). It is also posisble to select by channel if the sensor has a channel_map.

Parameters:
  • channel – channel to select
  • **kwargs

    any parameter to slice the results.

Tb_as_dataframe(channel_axis=None, **kwargs)

See PassiveResult().to_dataframe

to_dataframe(channel_axis='auto', **kwargs)

Return brightness temperature as a pandas.DataFrame. Any parameter can be added to slice the results (e.g. frequency=37e9 or polarization=’V’). See xarray slicing with sel method (to document). In addition channel_axis controls the format of the output. If set to None, the DataFrame has a multi-index with all the dimensions (frequency, polarization, …). If channel_axis is set to “column”, and if the sensor has a channel map, the channels are in columns and the other dimensions are in index. If set to “index”, the channel are in index with all the other dimensions.

The most conviennent is probably channel_axis=”column” while channel_axis=None (default) contains all the data even those not corresponding to a channel and applies to any sensor even those without channel_map. If set to “auto”, the channel_axis is “column” if the channel map exit, otherwise is None.

Parameters:channel_axis – controls whether to use the sensor channel or not and if yes, as a column or index.
TbV(**kwargs)

Return V polarization. Any parameter can be added to slice the results (e.g. frequency=37e9). See xarray slicing with sel method (to document)

TbH(**kwargs)

Return H polarization. Any parameter can be added to slice the results (e.g. frequency=37e9). See xarray slicing with sel method (to document)

polarization_ratio(ratio='H_V', **kwargs)

Return polarization ratio. Any parameter can be added to slice the results (e.g. frequency=37e9). See xarray slicing with sel method (to document)

class ActiveResult(intensity, coords=None, channel_map=None, other_data={}, mother_df=None)

Bases: smrt.core.result.Result

mode = 'A'
sel_data(channel=None, return_backscatter=False, **kwargs)
sigma(channel=None, **kwargs)

Return backscattering coefficient. Any parameter can be added to slice the results (e.g. frequency=37e9 or polarization=’V’). See xarray slicing with sel method (to document). It is also posisble to select by channel if the sensor has a channel_map.

Parameters:
  • channel – channel to select
  • **kwargs

    any parameter to slice the results.

sigma_dB(channel=None, **kwargs)

Return backscattering coefficient. Any parameter can be added to slice the results (e.g. frequency=37e9, polarization_inc=’V’, polarization=’V’). See xarray slicing with sel method (to document)

sigma_as_dataframe(channel_axis=None, **kwargs)

Return backscattering coefficient as a pandas.DataFrame. Any parameter can be added to slice the results (e.g. frequency=37e9 or polarization=’V’). See xarray slicing with sel method (to document). In addition channel_axis controls the format of the output. If set to None, the DataFrame has a multi-index formed with all the dimensions (frequency, polarization, …). If channel_axis is set to “column”, and if the sensor has named channels (channel_map in SMRT wording), the channel are in columns and the other dimensions are in index. If set to “index”, the channel are in index with all the other dimensions.

The most conviennent is probably channel_axis=”column” while channel_axis=None (default) contains all the data even those not corresponding to a channel and applies to any sensor even those without channel_map.

Parameters:channel_axis – controls whether to use the sensor channel or not and if yes, as a column or index.
sigma_dB_as_dataframe(channel_axis=None, **kwargs)

See ActiveResult().to_dataframe

to_dataframe(channel_axis=None, **kwargs)

Return backscattering coefficient in dB as a pandas.DataFrame. Any parameter can be added to slice the results (e.g. frequency=37e9 or polarization=’V’). See xarray slicing with sel method (to document). In addition channel_axis controls the format of the output. If set to None, the DataFrame has a multi-index with all the dimensions (frequency, polarization, …). If channel_axis is set to “column”, and if the sensor has named channels (channel_map in SMRT wording), the channel are in columns and the other dimensions are in index. If set to “index”, the channel are in index with all the other dimensions.

If channel_axis is set to “column”, and if the sensor has a channel map, the channels are in columns and the other dimensions are in index. If set to “index”, the channel are in index with all the other dimensions.

The most conviennent is probably channel_axis=”column” while channel_axis=None (default) contains all the data even those not corresponding to a channel and applies to any sensor even those without channel_map. If set to “auto”, the channel_axis is “column” if the channel map exit, otherwise is None.

Parameters:channel_axis – controls whether to use the sensor channel or not and if yes, as a column or index.
to_series(**kwargs)

return backscattering coefficients in dB as a series with the channels defined in the sensor as index. This requires that the sensor has declared a channel list.

sigmaVV(**kwargs)

Return VV backscattering coefficient. Any parameter can be added to slice the results (e.g. frequency=37e9). See xarray slicing with sel method (to document)

sigmaVV_dB(**kwargs)

Return VV backscattering coefficient in dB. Any parameter can be added to slice the results (e.g. frequency=37e9). See xarray slicing with sel method (to document)

sigmaHH(**kwargs)

Return HH backscattering coefficient. Any parameter can be added to slice the results (e.g. frequency=37e9). See xarray slicing with sel method (to document)

sigmaHH_dB(**kwargs)

Return HH backscattering coefficient in dB. Any parameter can be added to slice the results (e.g. frequency=37e9). See xarray slicing with sel method (to document)

sigmaHV(**kwargs)

Return HV backscattering coefficient. Any parameter can be added to slice the results (e.g. frequency=37e9). See xarray slicing with sel method (to document)

sigmaHV_dB(**kwargs)

Return HV backscattering coefficient in dB. Any parameter can be added to slice the results (e.g. frequency=37e9). See xarray slicing with sel method (to document)

sigmaVH(**kwargs)

Return VH backscattering coefficient. Any parameter can be added to slice the results (e.g. frequency=37e9). See xarray slicing with sel method (to document)

sigmaVH_dB(**kwargs)

Return VH backscattering coefficient in dB. Any parameter can be added to slice the results (e.g. frequency=37e9). See xarray slicing with sel method (to document)

concat_results(result_list, coord)

Concatenate several results from smrt.core.model.Model.run() (of type Result) into a single result (of type Result). This extends the number of dimension in the xarray hold by the instance. The new dimension is specified with coord

Parameters:
  • result_list – list of results returned by smrt.core.model.Model.run() or other functions.
  • coord – a tuple (dimension_name, dimension_values) for the new dimension. Dimension_values must be a sequence or

array with the same length as result_list.

Returns:Result instance

smrt.core.run_promise module

honour_all_promises(directory_or_filename, save_result_to=None, show_progress=True, force_compute=True)

Honour many promises and save the results

Parameters:
  • directory_or_filename – can be a directory, a filename or a list of them
  • save_result_to – directory where to save the results. If None, the results are not saved. The results are always returned as a list by this function.
  • show_progress – print progress of the calculation.
  • force_computate – If False and if a result or lock file is present, the computation is skipped. The order of promise processing is randomized to allow more efficient parallel computation using many calls of this function on the same directory. A lock file is used between the start of a computation and writting the result in order to prevent from running several times the same computation. If the process is interupted (e.g. walltime on clusters), the lock file may persist and prevent any future computation. In this case, lock files must be manually deleted. IF False, the save_result_to argument must be set to a valid directory where the results.
honour_promise(filename, save_result_to=None, force_compute=True)

Honour a promise and optionally save the result.

Parameters:
  • filename – file name of the promise
  • save_result_to – directory where to save the result.
  • force_compute – see honour_all_promise.
load_promise(filename)
class RunPromise(model, sensor, snowpack, kwargs)

Bases: object

run()
save(directory=None, filename=None)

smrt.core.sensitivity_study module

SensitivityStudy is used to easily conduct sensitivity studies.

Example:

times = [datetime(2012, 1, 1), datetime(2012, 1, 5), , datetime(2012, 1, 10)]
snowpacks = SensitivityStudy("time", times, [snowpack_1jan, snowpack_5jan, snowpack_10jan])


res = model.run(sensor, snowpacks)

The res variable is a Result instance, so that for all the methods of this class that can be called, they will return a timeseries. For instance result.TbV(theta=53) returns a time-series of brightness temperature at V polarization and 53° incidence angle and the following code plots this timeseries:

plot(times, result.TbV(theta=53))
class SensitivityStudy(name, values, snowpacks)

Bases: object

sensitivity_study(name, values, snowpacks)

create a sensitivity study

Parameters:
  • name – name of the variable to investigate
  • values – values taken by the variable
  • snowpacks – list of snowpacks. Can be a sequence or a function that takes one argument and return a snowpack.

In the latter case, the function is called for each values to build the list of snowpacks

smrt.core.sensor module

The sensor configuration includes all the information describing the sensor viewing geometry (incidence, …) and operating parameters (frequency, polarization, …). The easiest and recommended way to create a Sensor instance is to use one of the convenience functions such as passive(), active(), amsre(), etc. Adding a function for a new or unlisted sensor can be done in sensor_list if the sensor is common and of general interest. Otherwise, we recommend to add these functions in your own files (outside of smrt directories).

passive(frequency, theta, polarization=None, channel_map=None, name=None)

Generic configuration for passive microwave sensor.

Return a Sensor for a microwave radiometer with given frequency, incidence angle and polarization

Parameters:
  • frequency – frequency in Hz
  • theta – viewing angle or list of viewing angles in degrees from vertical. Note that some RT solvers compute all viewing angles whatever this configuration because it is internally needed part of the multiple scattering calculation. It it therefore often more efficient to call the model once with many viewing angles instead of calling it many times with a single angle.
  • polarization (list of characters) – H and/or V polarizations. Both polarizations is the default. Note that most RT solvers compute all the polarizations whatever this configuration because the polarizations are coupled in the RT equation.
  • channel_map (dict) – map channel names (keys) to configuration (values). A configuration is a dict with frequency, polarization and other such parameters to be used by Result to select the results.
  • name (string) – name of the sensor
Returns:

Sensor instance

Usage example:

from smrt import sensor_list
radiometer = sensor_list.passive(18e9, 50)
radiometer = sensor_list.passive(18e9, 50, "V")
radiometer = sensor_list.passive([18e9,36.5e9], [50,55], ["V","H"])
channel_map_for_radar(frequency=None, polarization='HV', order='fp')

return a channel_map to convert channel name to frequency and polarization. This function assumes the frequency is coded as a two-digit number in GHz with leading 0 if necessary. The polarization is after the frequency if order is ‘fp’ and before if order is ‘pf’.

active(frequency, theta_inc, theta=None, phi=None, polarization_inc=None, polarization=None, channel_map=None, name=None)

Configuration for active microwave sensor.

Return a Sensor for a radar with given frequency, incidence and viewing angles and polarization

If polarizations are not specified, quad-pol is the default (VV, VH, HV and HH). If the angle of incident radiation is not specified, backscatter will be simulated

Parameters:
  • frequency – frequency in Hz
  • theta_inc – incident angle in degrees from the vertical
  • theta – viewing zenith angle in degrees from the vertical. By default, it is equal to theta_inc which corresponds to the backscatter direction
  • phi – viewing azimuth angle in degrees from the incident direction. By default, it is pi which corresponds to the backscatter direction
  • polarization_inc (list of 1-character strings) – list of polarizations of the incidence wave (‘H’ or ‘V’ or both.)
  • polarization (list of 1-character strings) – list of viewing polarizations (‘H’ or ‘V’ or both)
  • channel_map (dict) – map channel names (keys) to configuration (values). A configuration is a dict with frequency, polarization and other such parameters to be used by Result to select the results.
  • name (string) – name of the sensor
Returns:

Sensor instance

Usage example:

from smrt import sensor_list
scatterometer = sensor_list.active(frequency=18e9, theta_inc=50)
scatterometer = sensor_list.active(18e9, 50, 50, 0, "V", "V")
scatterometer = sensor_list.active([18e9,36.5e9], theta=50, theta_inc=50, polarization_inc=["V", "H"], polarization=["V", "H"])
altimeter(channel, **kwargs)
make_multi_channel_altimeter(config, channel)
class SensorBase

Bases: object

class Sensor(frequency=None, theta_inc_deg=None, theta_deg=None, phi_deg=None, polarization_inc=None, polarization=None, channel_map=None, name=None, wavelength=None)

Bases: smrt.core.sensor.SensorBase

Configuration for sensor. Use of the functions passive(), active(), or the sensor specific functions e.g. amsre() are recommended to access this class.

wavelength
wavenumber
mode

returns the mode of observation: “A” for active or “P” for passive.

basic_checks()
configurations()
iterate(axis)

Iterate over the configuration for the given axis.

Parameters:axis – one of the attribute of the sensor (frequency, …) to iterate along
class SensorList(sensor_list, axis='channel')

Bases: smrt.core.sensor.SensorBase

channel
frequency
configurations()
iterate(axis=None)
class Altimeter(frequency, altitude, beamwidth, pulse_bandwidth, sigma_p=None, off_nadir_angle=0, beam_asymmetry=0, ngate=1024, nominal_gate=40, theta_inc_deg=0.0, polarization_inc=None, polarization=None, channel=None)

Bases: smrt.core.sensor.Sensor

Configuration for altimeter. Use of the functions altimeter(), or the sensor specific functions e.g. envisat_ra2() are recommended to access this class.

smrt.core.snowpack module

Snowpack instance contains the description of the snowpack, including a list of layers and interfaces between the layers, and the substrate (soil, ice, …).

To create a snowpack, it is recommended to use the make_snowpack() function which avoids the complexity of creating each layer and then the snowpack from the layers. For more complex media (like lake ice or sea ice), it may be necessary to directly call the functions to create the different layers (such as make_snow_layer()).

Example:

# create a 10-m thick snowpack with a single layer,
# density is 350 kg/m3. The exponential autocorrelation function is
# used to describe the snow and the "size" parameter is therefore
# the correlation length which is given as an optional
# argument of this function (but is required in practice)

sp = make_snowpack([10], "exponential", [350], corr_length=[3e-3])
class Snowpack(layers=None, interfaces=None, substrate=None, atmosphere=None)

Bases: object

holds the description of the snowpack, including the layers, interfaces, and the substrate

nlayer

return the number of layers

layer_thicknesses

return the thickness of each layer

layer_depths

return the depth of the bottom of each layer

bottom_layer_depths

return the depth of the bottom of each layer

top_layer_depths

return the depth of the bottom of each layer

mid_layer_depths

return the depth of the bottom of each layer

z

return the depth of each interface, that is, 0 and the depth of the bottom of each layer

layer_densities

return the density of each layer

profile(property_name, where='all', raise_attributeerror=False)

return the vertical profile of property_name. The property is searched either in the layer, microstructure or interface.

Parameters:
  • property_name – name of the property
  • where – where to search the property. Can be ‘all’, ‘layer’, ‘microstructure’, or ‘interface’
  • raise_attributeerror – raise an attribute error if the attribute is not found
append(layer, interface=None)

append a new layer at the bottom of the stack of layers. The interface is that at the top of the appended layer.

Parameters:
  • layer – instance of Layer
  • interface – type of interface. By default, flat surface (Flat) is considered meaning the coefficients are calculated with Fresnel coefficient and using the effective permittivity of the surrounding layers
delete(ilayer)

delete a layer and the upper interface

Parameters:ilayer – index of the layer
copy()

make a shallow copy of a snowpack by copying the list of layers and interfaces but not the layers and interfaces themselves which are still shared with the original snowpack. This method allows the user to create a new snowpack and remove, append or replace some layers or interfaces afterward. It does not allow to alter the layers or interfaces without changing the original snowpack. See py:meth:~deepcopy.

deepcopy()

make a deep copy of a snowpack.

basic_check()
check_addition_validity(other)
update_layer_number()
to_dataframe(default_columns=True, other_columns=None)

smrt.core.test_globalconstants module

test_density_of_ice()
test_freezing_point()
test_permittivity_of_air()
test_speed_of_light()

smrt.core.test_interface module

test_make_interface_noargs()

smrt.core.test_layer module

test_microstructure_model()

smrt.core.test_lib module

setup_func_sp()
setup_func_em(testpack=None)
test_generic_ft_even_matrix()

smrt.core.test_result module

test_methods()
test_positive_sigmaVV()
test_positive_sigmaVH()
test_positive_sigmaHV()
test_positive_sigmaHH()
test_sigma_dB()
test_sigma_dB_as_dataframe()
test_to_dataframe_with_channel_axis_on_column()
test_to_dataframe_without_channel_axis()
test_return_as_series()
test_concat_results()
test_concat_results_other_data()

smrt.core.test_sensor module

test_iterate()
test_wavelength()
test_no_theta()
test_passive_wrong_frequency_units_warning()
test_duplicate_theta()
test_duplicate_theta_active()
test_passive_mode()
test_active_wrong_frequency_units_warning()
test_active_mode()

smrt.core.test_snowpack module

test_profile()
create_two_snowpacks()
test_addition()
test_layer_addition()
test_inplace_addition()
test_inplace_layer_addition()
test_substrate_addition()
test_atmosphere_addition()
test_atmosphere_addition_double_snowpack()
test_invalid_addition_atmosphere()
test_invalid_addition_atmosphere2()
test_invalid_addition_substrate()
test_invalid_addition_substrate2()

Module contents

The core package contains the SMRT machinery. It provides the infrastructure that provides basic objects and orchestrates the “science” modules in the other packages (such as smrt.emmodel or smrt.rtsolver).

Amongst all, we suggest looking at the documentation of the Result object.

For developers

We strongly warn against changing anything in this directory. In principle this is not needed because no “science” is present and most objects and functions are generic enough to be extendable from outside (without affecting the core definition). Ask advice from the authors if you really want to change something here.