# This file is part of Py6S.
#
# Copyright 2012 Robin Wilson and contributors listed in the CONTRIBUTORS file.
#
# Py6S is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Py6S is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Py6S. If not, see <http://www.gnu.org/licenses/>.
import collections
# from sixs_exceptions import *
import sys
import numpy as np
try:
import StringIO
except ImportError:
# If Python 3 import io as StringIO (so we can still use StringIO.StringIO)
if sys.version_info[0] >= 3:
import io as StringIO
else:
raise
from ..sixs_exceptions import ParameterError
[docs]class GroundReflectance:
"""Produces strings for the input file for a number of different ground reflectance scenarios.
Options are:
- Homogeneous
- Lambertian
- BRDF
- Walthall et al. model
- Rahman et al. model
- etc
- Heterogeneous
- Lambertian
These are combined to give function names like:
:meth:`.HomogeneousLambertian` or :meth:`.HomogeneousWalthall`
The standard functions (:meth:`.HomogeneousLambertian` and :meth:`.HeterogeneousLambertian`) will decide what to do based on the types of inputs they are given::
model.ground_reflectance = GroundReflectance.HomogeneousLambertian(0.7) # A spectrally-constant reflectance of 0.7
model.ground_reflectance = GroundReflectance.HomogeneousLambertian(GroundReflectance.GreenVegetation) # A built-in green vegetation spectrum
model.ground_reflectance = GroundReflectance.HomogeneousLambertian([0.6, 0.8, 0.34, 0.453]) # A user-defined spectrum given in micrometers with steps of 2.5nm
# A 2D ndarray, such as that returned by any of the Spectra.import_* functions
model.ground_reflectance = GroundReflectance.HomogeneousLambertian(Spectra.import_from_usgs("http://speclab.cr.usgs.gov/spectral.lib06/ds231/ASCII/V/russianolive.dw92-4.30728.asc"))
"""
GreenVegetation = -1
ClearWater = -2
Sand = -3
LakeWater = -4
[docs] @classmethod
def HomogeneousLambertian(cls, ro):
"""Provides parameterisation for homogeneous Lambertian (ie. uniform BRDF) surfaces.
The single argument can be either:
- A single float value (for example, 0.634), in which case it is interpreted as a spectrally-constant reflectance value.
- A constant defined by this class (one of ``GroundReflectance.GreenVegetation``, ``GroundReflectance.ClearWater``, ``GroundReflectance.Sand`` or ``GroundReflectance.LakeWater``) in which case a built-in spectrum of the specified material is used.
- An array of values (for example, [0.67, 0.85, 0.34, 0.65]) in which case the values are taken to be reflectances across the whole wavelength range at a spacing of 2.5nm. In this case, if the start wavelength is s and the end wavelength is e, the values must be given for the wavelengths: ``s, s+2.5, s+5.0, s+7.5, ..., e-2.5, e``
- A multidimensional ndarray giving wavelength (column 0) and reflectance (column 1) values
"""
ro_type, ro_value = cls._GetTargetTypeAndValues(ro)
if ro_value == "":
res = """0 Homogeneous surface
0 No directional effects
%s\n""" % (
ro_type
)
elif ro_type == "-1":
res = """0 Homogeneous surface
0 No directional effects
%s
WV_REPLACE
%s\n""" % (
ro_type,
ro_value,
)
else:
res = """0 Homogeneous surface
0 No directional effects
%s
%s\n""" % (
ro_type,
ro_value,
)
return [res, ro]
[docs] @classmethod
def HeterogeneousLambertian(cls, radius, ro_target, ro_env):
"""Provides parameterisation for heterogeneous Lambertian (ie. uniform BRDF) surfaces.
These surfaces are modelled in 6S as a circular target surrounded by an environment of a different reflectance.
Arguments:
* ``radius`` -- The radius of the target (in km)
* ``ro_target`` -- The reflectance of the target
* ``ro_env`` -- The reflectance of the environment
Both of the reflectances can be set to any of the following:
- A single float value (for example, 0.634), in which case it is interpreted as a spectrally-constant reflectance value.
- A constant defined by this class (one of ``GroundReflectance.GreenVegetation``, ``GroundReflectance.ClearWater``, ``GroundReflectance.Sand`` or ``GroundReflectance.LakeWater``) in which case a built-in spectrum of the specified material is used.
- An array of values (for example, [0.67, 0.85, 0.34, 0.65]) in which case the values are taken to be reflectances across the whole wavelength range at a spacing of 2.5nm. In this case, if the start wavelength is s and the end wavelength is e, the values must be given for the wavelengths: ``s, s+2.5, s+5.0, s+7.5, ..., e-2.5, e``
- A multidimensional ndarray giving wavelength (column 0) and reflectance (column 1) values
"""
ro_target_type, ro_target_values = cls._GetTargetTypeAndValues(ro_target)
ro_env_type, ro_env_values = cls._GetTargetTypeAndValues(ro_env, "REFL_REPLACE_2")
if ro_target_values == "" and ro_env_values == "":
s = """1 (Non homogeneous surface)
%s %s %f (ro1 ro2 radius)\n""" % (
ro_target_type,
ro_env_type,
radius,
)
else:
s = """1 (Non homogeneous surface)
%s %s %f (ro1 ro2 radius)
%s
%s\n""" % (
ro_target_type,
ro_env_type,
radius,
ro_target_values,
ro_env_values,
)
return [s, ro_target, ro_env]
[docs] @classmethod
def HomogeneousWalthall(cls, param1, param2, param3, albedo):
"""Parameterisation for a surface BRDF based on the Walthall et al. model.
The parameters are:
- term in square ts*tv
- term in square ts*ts+tv*tv
- term in ts*tv*cos(phi) (limacon de pascal)
- albedo
"""
return """0 Homogeneous surface
1 (directional effects)
4 (Walthall et al. model)
%f %f %f %f\n""" % (
param1,
param2,
param3,
albedo,
)
[docs] @classmethod
def HomogeneousHapke(cls, albedo, assymetry, amplitude, width):
"""Parameterisation for a surface BRDF based on the Hapke model.
The parameters are:
- albedo
- assymetry parameter for the phase function
- amplitude of hot spot
- width of the hot spot
"""
return """0 Homogeneous surface
1 (directional effects)
1 (Hapke model)
%f %f %f %f\n""" % (
albedo,
assymetry,
amplitude,
width,
)
[docs] @classmethod
def HomogeneousRoujean(cls, albedo, k1, k2):
"""Parameterisation for a surface BRDF based on the Roujean et al. model.
The parameters are:
- albedo
- geometric parameter for hot spot effect
- geometric parameter for hot spot effect
"""
return """0 Homogeneous surface
1 (directional effects)
3 (Roujean model)
%f %f %f\n""" % (
albedo,
k1,
k2,
)
[docs] @classmethod
def HomogeneousMinnaert(cls, k, alb):
"""Parameterisation for a surface BRDF based on the Minnaert BRDF model.
The parameters are:
- K surface parameter
- Surface albedo
"""
return """0 Homogeneous surface
1 (directional effects)
5 (Minnaert model)
%f %f\n""" % (
k,
alb,
)
[docs] @classmethod
def HomogeneousMODISBRDF(cls, par1, par2, par3):
"""Parameterisation for a surface BRDF based on the MODIS Operational BRDF model.
The parameters are:
- Weight for lambertian kernel
- Weight for Ross Thick kernel
- Weight for Li Spare kernel
"""
return """0 Homogeneous surface
1 (directional effects)
10 (MODIS BRDF model)
%f %f %f\n""" % (
par1,
par2,
par3,
)
[docs] @classmethod
def HomogeneousOcean(cls, wind_speed, wind_azimuth, salinity, pigment_concentration):
"""Parameterisation for a surface BRDF based on the Ocean BRDF model.
The parameters are:
- wind speed (in m/s)
- azimuth of the wind (in degrees)
- salinity (in ppt) (set to 34.3ppt if < 0)
- pigment concentration (in mg/m3)
"""
return """0 Homogeneous surface
1 (directional effects)
6 (Ocean BRDF)
%f %f %f %f\n""" % (
wind_speed,
wind_azimuth,
salinity,
pigment_concentration,
)
[docs] @classmethod
def HomogeneousRahman(cls, intensity, asymmetry_factor, structural_parameter):
"""Parameterisation for a surface BRDF based on the Rahman BRDF model.
The parameters are:
- Intensity of the reflectance of the surface (N/D value >= 0)
- Asymmetry factor, N/D value between -1.0 and 1.0
- Structural parameter of the medium
"""
return """0 Homogeneous surface
1 (directional effects)
8 (Rahman model)
%f %f %f\n""" % (
intensity,
asymmetry_factor,
structural_parameter,
)
[docs] @classmethod
def HomogeneousIaquintaPinty(
cls,
leaf_dist,
hot_spot,
lai,
hot_spot_param,
leaf_reflec,
leaf_trans,
soil_albedo,
):
"""Parameterisation for a surface BRDF based on the Iaquinta and Pinty model.
The parameters are:
- Leaf distribution (one of the ``GroundReflectance.LeafDistXXX`` constants)
- Hot spot setting (``GroundReflectance.HotSpot`` or ``GroundReflectance.NoHotSpot``)
- Leaf Area Index (1-15)
- Hot spot parameter 2*r*lambda (0-2)
- Leaf reflectance (0-0.99)
- Leaf transmittance (0-0.99)
- Soil albedo (0-0.99)
Leaf reflectance + Leaf transmittance must be less than 0.99. If this is not the case, a :class:`.ParameterException` is raised.
"""
if leaf_reflec + leaf_trans > 0.99:
raise ParameterError(
"leaf_reflec", "Leaf reflectance + Leaf transmittance must be < 0.99"
)
return """0 Homogeneous surface
1 (directional effects)
7 (Iaquinta and Pinty model)
%d %d
%d %d
%d %d %d\n""" % (
leaf_dist,
hot_spot,
lai,
hot_spot_param,
leaf_reflec,
leaf_trans,
soil_albedo,
)
LeafDistPlanophile = 1
LeafDistErectophile = 2
LeafDistPlagiophile = 3
LeafDistExtremophile = 4
LeafDistUniform = 5
NoHotSpot = 1
HotSpot = 2
[docs] @classmethod
def HomogeneousVerstaeteEtAl(
cls,
kappa_param,
phase_funct,
scattering_type,
leaf_area_density,
sun_flecks_radius,
ssa,
legendre_first,
legendre_second,
k1,
k2,
asym_factor,
chil,
):
"""Parameterisation for a surface BRDF based on the Verstraete, Pinty and Dickinson model.
The parameters are:
- The type of Kappa parameterisation (one of the ``GroundReflectance.KappaXXX`` constants)
- The phase function to use (one of the ``GroundReflectance.PhaseXXX`` constants)
- The scattering type to use (either ``GroundReflectance.SingleScatteringOnly`` or ``GroundReflectance.DickinsonMultipleScattering``)
- Leaf area density (m^2/m^-3)
- Radius of the sun flecks on the scatterer (m)
- Single Scattering Albedo (0-1)
- First coefficient of Legendre polynomial (Only used if phase function is not ``GroundReflectance.PhaseIsotropic``, set to ``None`` otherwise)
- Second coefficient of Legendre polynomial (Only used if phase function is not ``GroundReflectance.PhaseIsotropic``, set to ``None`` otherwise)
- Kappa value k1 (Only used if Kappa parameterisation was ``GroundReflectance.KappaGivenValues``, set to ``None`` otherwise)
- Kappa value k2 (Only used if Kappa parameterisation was ``GroundReflectance.KappaGivenValues``, set to ``None`` otherwise)
- Asymmetry factor for Heyney-Greenstein parameterisation (Only used if Phase function is set to ``GroundReflectance.PhaseHeyneyGreenstein``, set to ``None`` otherwise)
- Goudriaan's chil parameter (Only used if Kappa parameterisation was NOT ``GroundReflectance.KappaGivenValues``, set to ``None`` otherwise)
"""
header = """0 Homogeneous surface
1 (directional effects)
2 (Verstraete Pinty Dickinson model\n"""
params_line = "%d %d %d\n" % (kappa_param, phase_funct, scattering_type)
if kappa_param == cls.KappaGivenValues:
middle_line = "%f %f %f %f\n" % (
leaf_area_density,
sun_flecks_radius,
k1,
k2,
)
else:
middle_line = "%f %f %f\n" % (leaf_area_density, sun_flecks_radius, chil)
if phase_funct == cls.PhaseIsotropic:
last_line = ""
elif phase_funct == cls.PhaseHeyneyGreenstein:
last_line = "%f" % (asym_factor)
else:
last_line == "%f %f\n" % (legendre_first, legendre_second)
return header + params_line + middle_line + last_line
KappaGivenValues = 0
KappaGoudriaan = 1
KappaDickinson = 2
PhaseIsotropic = 0
PhaseHeyneyGreenstein = 1
PhaseLegendre = 2
SingleScatteringOnly = 0
DickinsonMultipleScattering = 1
[docs] @classmethod
def HomogeneousKuuskMultispectralCR(
cls,
lai,
lad_eps,
lad_thm,
relative_leaf_size,
chlorophyll_content,
leaf_water_equiv_thickness,
effective_num_layers,
ratio_refractive_indices,
weight_first_price_function,
):
"""Parameterisation for a surface BRDF based on Kuusk's multispectral CR model.
The Parameters are:
- Leaf Area Index (0.1-10)
- LAD eps (0.0-0.9)
- LAD thm (0.0-90.0)
- Relative leaf size (0.01-1.0)
- Chlorophyll content (ug/cm^2, 0-30)
- Leaf water equivalent thickness (0.01-0.03)
- Effective number of elementary layers inside a leaf (1-225)
- Ratio of refractive indices of the leaf surface wax and internal material (0-1.0)
- Weight of the 1st Price function for the soil reflectance (0.1-0.8)
"""
header = """0 Homogeneous surface
1 (directional effects)
9 (Kuusk's multispectral CR model)\n"""
middle = "%f %f %f %f\n" % (lai, lad_eps, lad_thm, relative_leaf_size)
bottom = "%f %f %f %f %f\n" % (
chlorophyll_content,
leaf_water_equiv_thickness,
effective_num_layers,
ratio_refractive_indices,
weight_first_price_function,
)
return header + middle + bottom
[docs] @classmethod
def HomogeneousUserDefined(
cls, observed_reflectance, albedo, ro_sun_at_thetas, ro_sun_at_thetav
):
"""Parameterisation for a user-defined surface BRDF.
The parameters are:
- `observed_reflectance` -- Observed reflectance in the geometry specified in the Geometry parameterisation
- `albedo` -- Surface spherical albedo
- `ro_sun_at_thetas` -- A reflectance table (described below) for the scenario when the sun is at theta_s
(the solar zenith angle specified in the Geometry parameterisation)
- `ro_sun_at_thetav` -- A reflectance table (described below) for the scenario when the sun is at theta_v
(the view zenith angle specified in the Geometry parameterisation)
The reflectance tables mentioned above must be NumPy arrays (that is, instances of :class:`ndarray`) with a shape of (10, 13) where the table headers are as below,
and each cell contains the reflectance of the surface in the specified geometry::
zenith
0 10 20 30 40 50 60 70 80 85
a 0
z 30
i 60
m 90
u 120
t 150
h .
.
.
"""
header = "0 Homogeneous surface\n1 (directional effects)\n0 Input user's defined model\n"
top_table = cls._ArrayToString(ro_sun_at_thetas)
bottom_table = cls._ArrayToString(ro_sun_at_thetav)
bottom = "%f\n %f\n" % (albedo, observed_reflectance)
return header + top_table + "\n" + bottom_table + bottom
@classmethod
def _ArrayToString(cls, array):
text = StringIO.StringIO()
np.savetxt(text, array, fmt="%.5f", delimiter=" ")
s = text.getvalue()
text.close()
return s
@classmethod
def _GetTargetTypeAndValues(cls, target, name=None):
if name is None:
str_name = "REFL_REPLACE"
else:
str_name = name
if isinstance(target, np.ndarray):
target_type = "-1"
target_value = str_name
elif isinstance(target, collections.abc.Iterable):
# If it has
target_type = "-1"
target_value = " ".join(map(str, target))
else:
# If it's less than zero then it must be one of the predefined types
if target < 0:
target_type = str(-1 * target)
target_value = ""
# Otherwise it must be a constant ro
else:
target_type = "0"
target_value = target
return (target_type, target_value)