Skip to content

Commit

Permalink
Merge pull request #1 from ibaris/Outsourced_Soil
Browse files Browse the repository at this point in the history
Soil reflectance in SAIL
  • Loading branch information
ibaris authored Mar 30, 2018
2 parents 4a9cd0e + 4af69f5 commit 5b25220
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 33 deletions.
9 changes: 6 additions & 3 deletions examples/prospect_sail.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,12 @@
# select the coefficient values for the specific bands of ASTER (B1 - B9) or LANDSAT8 (B2 - B7). To access these bands
# type prospect.L8.Bx (x = 2, 3, ..., 7) for Landsat 8 or prospect.ASTER.Bx (x = 1, 2, ..., 9) for ASTER.

# To calculate the PROSAIL model we need some soil reflectance values. To obtain these we can use the LSM model:
lsm = pyrism.LSM(reflectance=3.14 / 4, moisture=0.15)

# To calculate the PROSAIL model we must call SAIL and specify the scattering and transmittance coefficients with these from PROSPECT like:
prosail = pyrism.SAIL(iza=iza, vza=vza, raa=raa, ks=prospect.ks, kt=prospect.kt, lidf_type='campbell',
lai=3, hotspot=0.25, soil_reflectance=3.14 / 4, soil_moisture=0.15)
# Now we must call SAIL and specify the scattering and transmittance coefficients with these from PROSPECT like:
prosail = pyrism.SAIL(iza=iza, vza=vza, raa=raa, ks=prospect.ks, kt=prospect.kt, rho_surface=lsm.ref,
lidf_type='campbell',
lai=3, hotspot=0.25)

# The accessibility of the attributes are the same as the PROSPECT model.
57 changes: 38 additions & 19 deletions pyrism/models/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -480,15 +480,15 @@ class SAIL(Kernel):
iza, vza, raa : int, float or ndarray
Incidence (iza) and scattering (vza) zenith angle, as well as relative azimuth (raa) angle.
ks, kt : array_like
Continuous leaf reflection (ks) and leaf transmission (kt) values from from 400 until 2500 nm.
Continuous leaf reflection (ks) and leaf transmission (kt) values from from 400 until 2500 nm. One can use the
output from PROSPECT class instance.
lai : float
Leaf area index.
hotspot : float
The hotspot parameter.
soil_reflectance : int or float
Surface (Lambertian) reflectance in optical wavelength.
soil_moisture : int or float
Surface moisture content between 0 and 1.
rho_surface : array_like
Continuous surface reflectance values from from 400 until 2500 nm. One can use the
output from LSM class instance.
lidf_type : {'verhoef', 'campbell'}, optional
Define with which method the LIDF is calculated. Default is 'campbell'
a, b : float, optional
Expand Down Expand Up @@ -525,25 +525,44 @@ class SAIL(Kernel):
"""

def __init__(self, iza, vza, raa, ks, kt, lai, hotspot, soil_reflectance, soil_moisture,
def __init__(self, iza, vza, raa, ks, kt, lai, hotspot, rho_surface,
lidf_type='campbell', a=57, b=0, normalize=False, nbar=0.0, angle_unit='DEG'):

super(SAIL, self).__init__(iza=iza, vza=vza, raa=raa, normalize=normalize, nbar=nbar, angle_unit=angle_unit,
align=True)

if len(ks) != 2101:
raise AssertionError(
"ks must contain continuous leaf reflectance values from from 400 until 2500 nm with a length of 2101. The actual length of ks is {0}".format(
str(len(ks))))

elif len(kt) != 2101:
raise AssertionError(
"kt must contain continuous leaf transmitance values from from 400 until 2500 nm with a length of 2101. The actual length of kt is {0}".format(
str(len(kt))))

elif len(rho_surface) != 2101:
raise AssertionError(
"rho_surface must contain continuous surface reflectance values from from 400 until 2500 nm with a length of 2101. The actual length of rho_surface is {0}".format(
str(len(rho_surface))))

else:
pass

self.ks = ks
self.kt = kt
self.lai = lai
self.hotspot = hotspot

self.Soil = LSM(reflectance=soil_reflectance, moisture=soil_moisture)
self.rho_surface = rho_surface
self.VollScat = VolScatt(iza, vza, raa, angle_unit)

if lidf_type is 'verhoef':
self.VollScat.coef(a=a, b=b, lidf_type='verhoef')
elif lidf_type is 'campbell':
self.VollScat.coef(a=a, lidf_type='campbell')
else:
raise ValueError("The lidf_type must be 'verhoef' or 'campbell'")
raise AssertionError("The lidf_type must be 'verhoef' or 'campbell'")

tss, too, tsstoo, rdd, tdd, rsd, tsd, rdo, tdo, rso, rsos, rsod, rddt, rsdt, rdot, rsodt, rsost, rsot, gammasdf, gammasdb, gammaso = self.__calc()

Expand Down Expand Up @@ -598,12 +617,12 @@ def __calc(self):
rso = 0
rsos = 0
rsod = 0
rddt = self.Soil.ref
rsdt = self.Soil.ref
rdot = self.Soil.ref
rddt = self.rho_surface
rsdt = self.rho_surface
rdot = self.rho_surface
rsodt = 0
rsost = self.Soil.ref
rsot = self.Soil.ref
rsost = self.rho_surface
rsot = self.rho_surface
gammasdf = 0
gammaso = 0
gammasdb = 0
Expand Down Expand Up @@ -689,18 +708,18 @@ def __calc(self):
gammaso = gammasos + gammasod

# Interaction with the soil
dn = 1. - self.Soil.ref * rdd
dn = 1. - self.rho_surface * rdd

try:
dn[dn < 1e-36] = 1e-36
except TypeError:
dn = max(1e-36, dn)

rddt = rdd + tdd * self.Soil.ref * tdd / dn
rsdt = rsd + (tsd + tss) * self.Soil.ref * tdd / dn
rdot = rdo + tdd * self.Soil.ref * (tdo + too) / dn
rsodt = ((tss + tsd) * tdo + (tsd + tss * self.Soil.ref * rdd) * too) * self.Soil.ref / dn
rsost = rso + tsstoo * self.Soil.ref
rddt = rdd + tdd * self.rho_surface * tdd / dn
rsdt = rsd + (tsd + tss) * self.rho_surface * tdd / dn
rdot = rdo + tdd * self.rho_surface * (tdo + too) / dn
rsodt = ((tss + tsd) * tdo + (tsd + tss * self.rho_surface * rdd) * too) * self.rho_surface / dn
rsost = rso + tsstoo * self.rho_surface
rsot = rsost + rsodt

return [tss, too, tsstoo, rdd, tdd, rsd, tsd, rdo, tdo,
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def get_packages():

setup(name='pyrism',

version='0.0.2.1',
version='0.0.3',

description='Python bindings for Remote Sensing Models',

Expand Down
55 changes: 45 additions & 10 deletions tests/test_prospect_prosail.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
from distutils import dir_util

import pytest
from numpy import allclose, loadtxt
from numpy import allclose, loadtxt, atleast_1d
from pytest import fixture
from scipy.io import loadmat

from pyrism import PROSPECT, SAIL
from pyrism import PROSPECT, SAIL, LSM


@fixture
Expand Down Expand Up @@ -79,9 +79,9 @@ def test_sdr_prosail5(self, datadir):
fname = datadir("REFL_CAN.txt")
w, resv, hdr, sdr, bhr, dhr = loadtxt(fname, unpack=True)

lsm = LSM(reflectance=1, moisture=1)
prospect = PROSPECT(N=1.5, Cab=40, Cxc=8., Cbr=0.0, Cw=0.01, Cm=0.009, version="5")
sail = SAIL(iza=30, vza=10, raa=0, ks=prospect.ks, kt=prospect.kt, lai=3, hotspot=0.01, soil_reflectance=1,
soil_moisture=1,
sail = SAIL(iza=30, vza=10, raa=0, ks=prospect.ks, kt=prospect.kt, lai=3, hotspot=0.01, rho_surface=lsm.ref,
a=-0.35, b=-0.15, lidf_type='verhoef')

assert allclose(sdr, sail.BRF.ref, atol=0.01)
Expand All @@ -90,9 +90,9 @@ def test_hdr_prosail5(self, datadir):
fname = datadir("REFL_CAN.txt")
w, resv, hdr, sdr, bhr, dhr = loadtxt(fname, unpack=True)

lsm = LSM(reflectance=1, moisture=1)
prospect = PROSPECT(N=1.5, Cab=40, Cxc=8., Cbr=0.0, Cw=0.01, Cm=0.009, version="5")
sail = SAIL(iza=30, vza=10, raa=0, ks=prospect.ks, kt=prospect.kt, lai=3, hotspot=0.01, soil_reflectance=1,
soil_moisture=1,
sail = SAIL(iza=30, vza=10, raa=0, ks=prospect.ks, kt=prospect.kt, lai=3, hotspot=0.01, rho_surface=lsm.ref,
a=-0.35, b=-0.15, lidf_type='verhoef')

assert allclose(hdr, sail.HDR.ref, atol=0.01)
Expand All @@ -101,9 +101,9 @@ def test_bhr_prosail5(self, datadir):
fname = datadir("REFL_CAN.txt")
w, resv, hdr, sdr, bhr, dhr = loadtxt(fname, unpack=True)

lsm = LSM(reflectance=1, moisture=1)
prospect = PROSPECT(N=1.5, Cab=40, Cxc=8., Cbr=0.0, Cw=0.01, Cm=0.009, version="5")
sail = SAIL(iza=30, vza=10, raa=0, ks=prospect.ks, kt=prospect.kt, lai=3, hotspot=0.01, soil_reflectance=1,
soil_moisture=1,
sail = SAIL(iza=30, vza=10, raa=0, ks=prospect.ks, kt=prospect.kt, lai=3, hotspot=0.01, rho_surface=lsm.ref,
a=-0.35, b=-0.15, lidf_type='verhoef')

assert allclose(bhr, sail.BHR.ref, atol=0.01)
Expand All @@ -112,9 +112,44 @@ def test_dhr_prosail5(self, datadir):
fname = datadir("REFL_CAN.txt")
w, resv, hdr, sdr, bhr, dhr = loadtxt(fname, unpack=True)

lsm = LSM(reflectance=1, moisture=1)
prospect = PROSPECT(N=1.5, Cab=40, Cxc=8., Cbr=0.0, Cw=0.01, Cm=0.009, version="5")
sail = SAIL(iza=30, vza=10, raa=0, ks=prospect.ks, kt=prospect.kt, lai=3, hotspot=0.01, soil_reflectance=1,
soil_moisture=1,
sail = SAIL(iza=30, vza=10, raa=0, ks=prospect.ks, kt=prospect.kt, lai=3, hotspot=0.01, rho_surface=lsm.ref,
a=-0.35, b=-0.15, lidf_type='verhoef')

assert allclose(dhr, sail.DHR.ref, atol=0.01)


class TestPROSAILError:
def test_ks(self, datadir):
fname = datadir("REFL_CAN.txt")
w, resv, hdr, sdr, bhr, dhr = loadtxt(fname, unpack=True)
ks = atleast_1d(0)

lsm = LSM(reflectance=1, moisture=1)
prospect = PROSPECT(N=1.5, Cab=40, Cxc=8., Cbr=0.0, Cw=0.01, Cm=0.009, version="5")
with pytest.raises(AssertionError):
sail = SAIL(iza=30, vza=10, raa=0, ks=ks, kt=prospect.kt, lai=3, hotspot=0.01, rho_surface=lsm.ref,
a=-0.35, b=-0.15, lidf_type='verhoef')

def test_kt(self, datadir):
fname = datadir("REFL_CAN.txt")
w, resv, hdr, sdr, bhr, dhr = loadtxt(fname, unpack=True)
kt = atleast_1d(0)

lsm = LSM(reflectance=1, moisture=1)
prospect = PROSPECT(N=1.5, Cab=40, Cxc=8., Cbr=0.0, Cw=0.01, Cm=0.009, version="5")
with pytest.raises(AssertionError):
sail = SAIL(iza=30, vza=10, raa=0, ks=prospect.ks, kt=kt, lai=3, hotspot=0.01, rho_surface=lsm.ref,
a=-0.35, b=-0.15, lidf_type='verhoef')

def test_surf(self, datadir):
fname = datadir("REFL_CAN.txt")
w, resv, hdr, sdr, bhr, dhr = loadtxt(fname, unpack=True)
kt = atleast_1d(0)

lsm = LSM(reflectance=1, moisture=1)
prospect = PROSPECT(N=1.5, Cab=40, Cxc=8., Cbr=0.0, Cw=0.01, Cm=0.009, version="5")
with pytest.raises(AssertionError):
sail = SAIL(iza=30, vza=10, raa=0, ks=prospect.ks, kt=prospect.kt, lai=3, hotspot=0.01, rho_surface=kt,
a=-0.35, b=-0.15, lidf_type='verhoef')

0 comments on commit 5b25220

Please sign in to comment.