Skip to content
Commits on Source (7)
ref-names: $Format:%D$
\ No newline at end of file
etc/pyspectral_rsr_data.tgz filter=lfs diff=lfs merge=lfs -text
pyspectral/etc/pyspectral_rsr_data.tgz filter=lfs diff=lfs merge=lfs -text
doc/_static/mersi2_rsr_band_0040_0070.png filter=lfs diff=lfs merge=lfs -text
doc/_static/mersi2_rsr_band_0040_0070_missingbands.png filter=lfs diff=lfs merge=lfs -text
pyspectral/version.py export-subst
......@@ -21,7 +21,7 @@ lib
lib64
__pycache__
doc/_build
*png
rsr*.png
# Installer logs
pip-log.txt
......
## Version <RELEASE_VERSION> (2019/10/03)
## Version v0.9.3 (2019/12/06)
### Issues Closed
* [Issue 92](https://github.com/pytroll/pyspectral/issues/92) - Fails to pull from Github because of a git-lfs quota limit ([PR 93](https://github.com/pytroll/pyspectral/pull/93))
* [Issue 90](https://github.com/pytroll/pyspectral/issues/90) - CREFL rayleigh Goes-16 ABI L1B
In this release 2 issues were closed.
### Pull Requests Merged
#### Bugs fixed
* [PR 95](https://github.com/pytroll/pyspectral/pull/95) - Adapt for later versions of TQDM
* [PR 93](https://github.com/pytroll/pyspectral/pull/93) - Abandon gitlfs ([92](https://github.com/pytroll/pyspectral/issues/92))
* [PR 87](https://github.com/pytroll/pyspectral/pull/87) - Fix doc strings (flake8 complaints).
#### Features added
* [PR 95](https://github.com/pytroll/pyspectral/pull/95) - Adapt for later versions of TQDM
* [PR 88](https://github.com/pytroll/pyspectral/pull/88) - Feature pytest
* [PR 87](https://github.com/pytroll/pyspectral/pull/87) - Fix doc strings (flake8 complaints).
* [PR 86](https://github.com/pytroll/pyspectral/pull/86) - Switch from versioneer
#### Documentation changes
* [PR 94](https://github.com/pytroll/pyspectral/pull/94) - Add the atm correction paper reference
* [PR 87](https://github.com/pytroll/pyspectral/pull/87) - Fix doc strings (flake8 complaints).
In this release 9 pull requests were closed.
## Version v0.9.2 (2019/10/03)
### Pull Requests Merged
......
PySpectral
Pyspectral
==========
[![Build Status](https://travis-ci.org/pytroll/pyspectral.png?branch=master)](https://travis-ci.org/pytroll/pyspectral)
[![Build status](https://ci.appveyor.com/api/projects/status/5lm42n0l65l5o9xn?svg=true)](https://ci.appveyor.com/project/pytroll/pyspectral)
[![Coverage Status](https://coveralls.io/repos/github/pytroll/pyspectral/badge.svg?branch=master)](https://coveralls.io/github/pytroll/pyspectral?branch=master)
[![PyPI version](https://badge.fury.io/py/pyspectral.svg)](https://badge.fury.io/py/pyspectral)
[![Code Climate](https://codeclimate.com/github/pytroll/pyspectral/badges/gpa.svg)](https://codeclimate.com/github/pytroll/pyspectral)
Given a passive sensor on a meteorological satellite PySpectral provides the
Given a passive sensor on a meteorological satellite Pyspectral provides the
relative spectral response (rsr) function(s) and offer you some basic
operations like convolution with the solar spectrum to derive the in band solar
flux, for instance. The focus is on imaging sensors like AVHRR, VIIRS, MODIS, ABI,
AHI, OLCI and SEVIRI. But more sensors are included and if others are needed they can
be easily added. With PySpectral it is possible to derive the reflective and
be easily added. With Pyspectral it is possible to derive the reflective and
emissive parts of the signal observed in any NIR band around 3-4 microns where
both passive terrestrial emission and solar backscatter mix the information
received by the satellite. Furthermore PySpectral allows correcting true color
received by the satellite. Furthermore Pyspectral allows correcting true color
imagery for the background (climatological) atmospheric signal due to Rayleigh
scattering of molecules, absorption by atmospheric gases and aerosols, and Mie
scattering of aerosols.
......
pyspectral (0.9.3+ds-1) unstable; urgency=medium
* New upstream release.
* Update copyright file.
* debian/patches:
- refresh all patches
* debian/patches:
- new 0003-No-setuptools-scm.patch
-- Antonio Valentino <antonio.valentino@tiscali.it> Sat, 07 Dec 2019 09:27:35 +0000
pyspectral (0.9.2+ds-2) unstable; urgency=medium
* New upstream release.
......
......@@ -21,10 +21,6 @@ Copyright: 2013-2019 Adam Dybbroe
Pytroll
License: GPL-3+
Files: versioneer.py
Copyright: 2018, Brian Warner
License: CC0-1.0
Files: debian/*
Copyright: 2018 Antonio Valentino <antonio.valentino@tiscali.it>
License: GPL-3+
......@@ -45,14 +41,3 @@ License: GPL-3+
.
On Debian systems, the complete text of the GNU General
Public License version 3 can be found in "/usr/share/common-licenses/GPL-3".
License: CC0-1.0
To the extent possible under law, the author(s) have dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
.
You should have received a copy of the CC0 Public Domain Dedication along with
this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
.
On Debian systems, the complete text of the CC0 1.0 Universal license can be
found in ‘/usr/share/common-licenses/CC0-1.0’.
......@@ -4,14 +4,14 @@ Subject: Fix tests
Disable tests that require the network or external data
---
pyspectral/tests/__init__.py | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
pyspectral/tests/__init__.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/pyspectral/tests/__init__.py b/pyspectral/tests/__init__.py
index b930fc2..686ce89 100644
index 4ca68dc..e06a34c 100644
--- a/pyspectral/tests/__init__.py
+++ b/pyspectral/tests/__init__.py
@@ -53,10 +53,10 @@ def suite():
@@ -43,10 +43,10 @@ def suite():
mysuite = unittest.TestSuite()
if not TRAVIS and not APPVEYOR:
# Test sphinx documentation pages:
......@@ -25,12 +25,3 @@ index b930fc2..686ce89 100644
# Test the documentation strings
mysuite.addTests(doctest.DocTestSuite(solar))
mysuite.addTests(doctest.DocTestSuite(near_infrared_reflectance))
@@ -68,7 +68,7 @@ def suite():
mysuite.addTests(test_solarflux.suite())
mysuite.addTests(test_reflectance.suite())
mysuite.addTests(test_utils.suite())
- mysuite.addTests(test_rayleigh.suite())
+ # mysuite.addTests(test_rayleigh.suite())
mysuite.addTests(test_rsr_reader.suite())
return mysuite
......@@ -7,10 +7,10 @@ Subject: Fix install data
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/setup.py b/setup.py
index 2575d1f..66e844f 100644
index dfb3e06..e61c338 100644
--- a/setup.py
+++ b/setup.py
@@ -97,8 +97,8 @@ setup(name='pyspectral',
@@ -99,8 +99,8 @@ setup(name=NAME,
scripts=['bin/plot_rsr.py', 'bin/composite_rsr_plot.py',
'bin/download_atm_correction_luts.py',
'bin/download_rsr.py'],
......
From: Antonio Valentino <antonio.valentino@tiscali.it>
Date: Sat, 7 Dec 2019 09:16:27 +0100
Subject: No setuptools-scm
---
doc/conf.py | 2 +-
setup.cfg | 8 ++++----
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/doc/conf.py b/doc/conf.py
index b3ba906..a69b601 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -39,7 +39,7 @@ sys.path.insert(0, os.path.abspath('../pyspectral'))
# |version| and |release|, also used in various other places throughout the
# built documents.
#
-release = get_distribution('satpy').version
+release = get_distribution('pyspectral').version
# for example take major/minor
version = '.'.join(release.split('.')[:2])
diff --git a/setup.cfg b/setup.cfg
index 0628c31..94e5892 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,7 +1,7 @@
-[options]
-setup_requires =
- setuptools_scm
- setuptools_scm_git_archive
+#[options]
+#setup_requires =
+# setuptools_scm
+# setuptools_scm_git_archive
[bdist_rpm]
0001-Fix-tests.patch
0002-Fix-install-data.patch
0003-No-setuptools-scm.patch
......@@ -13,6 +13,7 @@
import sys
import os
from pkg_resources import get_distribution
# PYTHONPATH = docs/source
DOC_SOURCES_DIR = os.path.dirname(os.path.abspath(__file__))
......@@ -34,6 +35,14 @@ if on_rtd:
sys.path.insert(0, os.path.abspath('../'))
sys.path.insert(0, os.path.abspath('../pyspectral'))
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
release = get_distribution('satpy').version
# for example take major/minor
version = '.'.join(release.split('.')[:2])
class Mock(object):
......@@ -108,16 +117,6 @@ master_doc = 'index'
project = u'Pyspectral'
copyright = u'2013-2018, PyTroll'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
import pyspectral.version as current_version
# The full version, including alpha/beta/rc tags.
release = current_version.get_versions()['version']
# The short X.Y version.
version = ".".join(release.split(".")[: 2])
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
......
......@@ -4,7 +4,7 @@
contain the root `toctree` directive.
Welcome to PySpectral's documentation!
Welcome to Pyspectral's documentation!
======================================
.. figure:: _static/pyspectral_header_montage.png
......
......@@ -6,13 +6,14 @@ Atmospherioc correction in the visible spectrum
In particular at the shorter wavelengths around :math:`400-600 nm`, which
include the region used e.g. for ocean color products or true color imagery,
in particular the Rayleigh scattering due to atmospheric molecules or atoms,
and Mie scattering and absorption of aerosols, becomes significant.
As this atmospheric scattering and absorption is obscuring the retrieval of
surface parameters and since it is strongly dependent on observation geometry,
it is custom to try to correct or subtract this unwanted signal from the data
before performing the geophysical retrieval.
include the region used e.g. for ocean color products or true color imagery, in
particular the Rayleigh scattering due to atmospheric molecules or atoms, and
Mie scattering and absorption of aerosols, becomes significant. As this
atmospheric scattering and absorption is obscuring the retrieval of surface
parameters and since it is strongly dependent on observation geometry, it is
custom to try to correct or subtract this unwanted signal from the data before
performing the geophysical retrieval or generating useful and nice looking
imagery.
In order to correct for this atmospheric effect we have simulated the solar
reflectance under various sun-satellite viewing conditions for a set of
......@@ -34,6 +35,7 @@ in the figure below:
:scale: 70%
:align: center
The method is descriped in detail in a scientific paper_.
To apply the atmospheric correction for a given satellite sensor band, the
procedure involves the following three steps:
......@@ -42,7 +44,9 @@ procedure involves the following three steps:
* Derive the atmospheric absorption and scattering contribution
* Subtract that from the observations
As the Rayleigh scattering is proportional to :math:`\frac{1}{{\lambda}^4}` the
As the Rayleigh scattering, which is the dominating part we are correcting for
under normal situations (when there is no excessive pollution or aerosols in
the line of sight) is proportional to :math:`\frac{1}{{\lambda}^4}` the
effective wavelength is derived by convolving the spectral response with
:math:`\frac{1}{{\lambda}^4}`.
......@@ -106,12 +110,9 @@ if you want another setup, e.g.:
[[ 10.01281363 9.65488615]
[ 9.78070046 9.70335278]]
..
A few words on the radiative transfer simulations and LUTs
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. _Satpy: http://www.github.com/pytroll/satpy
.. _zenodo: https://doi.org/10.5281/zenodo.1288441
.. _paper: https://doi.org/10.3390/rs10040560
.. image:: _static/refl_subarctic_winter_lambda_0400_ssa_000.png
.. image:: _static/refl_subarctic_winter_lambda_0500_ssa_090.png
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (c) 2013 - 2018 PyTroll Community
# Copyright (c) 2013 - 2019 PyTroll Community
# Author(s):
......@@ -22,8 +22,11 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""Pyspectral package init"""
"""Pyspectral package init."""
from .version import get_versions
__version__ = get_versions()['version']
del get_versions
from pkg_resources import get_distribution, DistributionNotFound
try:
__version__ = get_distribution(__name__).version
except DistributionNotFound:
# package is not installed
pass
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (c) 2017 Adam.Dybbroe
# Copyright (c) 2017, 2019 Adam.Dybbroe
# Author(s):
......@@ -21,7 +21,10 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""Depending on the satellite sensor spectral band the upwelling infrared
"""
Draft limb-cooling correction methods - work in progress.
Depending on the satellite sensor spectral band the upwelling infrared
radiation in a cloudfree atmosphere will be subject to absorption by
atmospherical molecules, mainly water vapour, Ozone, CO2 and other trace
gases. This absorption is depending on the observational path length. Usually
......@@ -62,13 +65,15 @@ LOG = logging.getLogger(__name__)
class AtmosphericalCorrection(object):
"""IR atmospherical correction.
"""Container for the IR atmospherical correction of satellite imager IR (dirty)
Container for the IR atmospherical correction of satellite imager IR (dirty)
window bands
"""
def __init__(self, platform_name, sensor, **kwargs):
"""Atmosphere correction in the infrared."""
self.platform_name = platform_name
self.sensor = sensor
self.coeff_filename = None
......@@ -84,23 +89,22 @@ class AtmosphericalCorrection(object):
LOG.info("Atmospherical correction by old DWD parametric method...")
def get_correction(self, sat_zenith, bandname, data):
"""
Get the correction depending on satellite zenith angle and band
"""
"""Get the correction depending on satellite zenith angle and band."""
# From band name we will eventually need the effective wavelength
# and then use that to find the atm contribution depending on zenith
# angle from a LUT
return viewzen_corr(data.copy(), sat_zenith)
def viewzen_corr(data, view_zen):
"""Apply atmospheric correction on the given *data* using the
"""Apply satellite-zenith angle dependent correction.
Apply atmospheric correction on the given *data* using the
specified satellite zenith angles (*view_zen*). Both input data
are given as 2-dimensional Numpy (masked) arrays, and they should
have equal shapes.
The *data* array will be changed in place and has to be copied before.
"""
def ratio(value, v_null, v_ref):
return (value - v_null) / (v_ref - v_null)
......@@ -133,7 +137,6 @@ def viewzen_corr(data, view_zen):
if __name__ == "__main__":
this = AtmosphericalCorrection('Suomi-NPP', 'viirs')
SHAPE = (1000, 3000)
NDIM = SHAPE[0] * SHAPE[1]
......
......@@ -21,7 +21,8 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""Planck radiation equation"""
"""Planck radiation equation."""
import numpy as np
import logging
......@@ -40,12 +41,12 @@ EPSILON = 0.000001
def blackbody_rad2temp(wavelength, radiance):
"""Derive brightness temperatures from radiance using the Planck
function. Wavelength space. Assumes SI units as input and returns
"""Derive brightness temperatures from radiance using the Planck function.
Wavelength space. Assumes SI units as input and returns
temperature in Kelvin
"""
mask = False
if np.isscalar(radiance):
rad = np.array([radiance, ], dtype='float64')
......@@ -85,9 +86,11 @@ def blackbody_rad2temp(wavelength, radiance):
def blackbody_wn_rad2temp(wavenumber, radiance):
"""Derive brightness temperatures from radiance using the Planck
function. Wavenumber space"""
"""Derive brightness temperatures from radiance using the Planck function.
Wavenumber space
"""
if np.isscalar(radiance):
radiance = np.array([radiance], dtype='float64')
elif isinstance(radiance, (list, tuple)):
......@@ -121,8 +124,9 @@ def blackbody_wn_rad2temp(wavenumber, radiance):
def planck(wave, temperature, wavelength=True):
"""The Planck radiation or Blackbody radiation as a function of wavelength
or wavenumber. SI units.
"""Derive the Planck radiation as a function of wavelength or wavenumber.
SI units.
_planck(wave, temperature, wavelength=True)
wave = Wavelength/wavenumber or a sequence of wavelengths/wavenumbers (m or m^-1)
temp = Temperature (scalar) or a sequence of temperatures (K)
......@@ -163,10 +167,12 @@ def planck(wave, temperature, wavelength=True):
nom = 2 * H_PLANCK * (C_SPEED ** 2) * (wln ** 3)
arg1 = H_PLANCK * C_SPEED * wln / K_BOLTZMANN
# use dask functions when needed
np_ = np if isinstance(temperature, np.ndarray) else da
arg2 = np_.where(np.greater(np.abs(temperature), EPSILON),
(1. / temperature), np.nan).reshape(-1, 1)
with np.errstate(divide='ignore', invalid='ignore'):
# use dask functions when needed
np_ = np if isinstance(temperature, np.ndarray) else da
arg2 = np_.where(np_.greater(np.abs(temperature), EPSILON),
np_.divide(1., temperature), np.nan).reshape(-1, 1)
if isinstance(arg2, np.ndarray):
# don't compute min/max if we have dask arrays
LOG.debug("Max and min - arg1: %s %s",
......@@ -192,53 +198,54 @@ def planck(wave, temperature, wavelength=True):
LOG.warning(
"Number of items having dubious values: " + str(dubious.shape[0]))
denom = np.exp(exp_arg) - 1
rad = nom / denom
radshape = rad.shape
if wln.shape[0] == 1:
if temperature.shape[0] == 1:
return rad[0, 0]
else:
return rad[:, 0].reshape(shape)
else:
if temperature.shape[0] == 1:
return rad[0, :]
with np.errstate(over='ignore'):
denom = np.exp(exp_arg) - 1
rad = nom / denom
radshape = rad.shape
if wln.shape[0] == 1:
if temperature.shape[0] == 1:
return rad[0, 0]
else:
return rad[:, 0].reshape(shape)
else:
if len(shape) == 1:
return rad.reshape((shape[0], radshape[1]))
if temperature.shape[0] == 1:
return rad[0, :]
else:
return rad.reshape((shape[0], shape[1], radshape[1]))
if len(shape) == 1:
return rad.reshape((shape[0], radshape[1]))
else:
return rad.reshape((shape[0], shape[1], radshape[1]))
def blackbody_wn(wavenumber, temp):
"""The Planck radiation or Blackbody radiation as a function of wavenumber
SI units!
"""Derive the Planck radiation as a function of wavenumber.
SI units.
blackbody_wn(wavnum, temperature)
wavenumber = A wavenumber (scalar) or a sequence of wave numbers (m-1)
temp = A temperatfure (scalar) or a sequence of temperatures (K)
Output: The spectral radiance in Watts per square meter per steradian
per m-1:
Unit = W/m^2 sr^-1 (m^-1)^-1 = W/m sr^-1
Converting from SI units to mW/m^2 sr^-1 (cm^-1)^-1:
1.0 W/m^2 sr^-1 (m^-1)^-1 = 0.1 mW/m^2 sr^-1 (cm^-1)^-1
"""
"""
return planck(wavenumber, temp, wavelength=False)
def blackbody(wavel, temp):
"""The Planck radiation or Blackbody radiation as a function of wavelength
"""Derive the Planck radiation as a function of wavelength.
SI units.
blackbody(wavelength, temperature)
wavel = Wavelength or a sequence of wavelengths (m)
temp = Temperature (scalar) or a sequence of temperatures (K)
Output: The spectral radiance per meter (not micron!)
Unit = W/m^2 sr^-1 m^-1
"""
"""
return planck(wavel, temp, wavelength=True)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (c) 2017, 2018 Adam.Dybbroe
# Copyright (c) 2017, 2018, 2019 Adam.Dybbroe
# Author(s):
......@@ -20,8 +20,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""PySpectral configuration directory and file handling
"""
"""PySpectral configuration directory and file handling."""
import logging
import os
......@@ -57,7 +56,7 @@ if CONFIG_FILE is not None and (not os.path.exists(CONFIG_FILE) or
def recursive_dict_update(d, u):
"""Recursive dictionary update using
"""Recursive dictionary update.
Copied from:
......@@ -74,7 +73,7 @@ def recursive_dict_update(d, u):
def get_config():
"""Get the configuration from file"""
"""Get the configuration from file."""
if CONFIG_FILE is not None:
configfile = CONFIG_FILE
else:
......
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (c) 2014-2018 Adam.Dybbroe
# Copyright (c) 2014-2019 Adam.Dybbroe
# Author(s):
......@@ -21,7 +21,10 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""Derive the Near-Infrared reflectance of a given band in the solar and
"""
Derive NIR reflectances of a a band in the 3-4 micron window region.
Derive the Near-Infrared reflectance of a given band in the solar and
thermal range (usually the 3.7-3.9 micron band) using a thermal atmospheric
window channel (usually around 11-12 microns).
"""
......@@ -50,8 +53,8 @@ TB_MAX = 360.
class Calculator(RadTbConverter):
"""A thermal near-infrared (~3.7 micron) band reflectance calculator.
"""
A thermal near-infrared (~3.7 micron) band reflectance calculator.
Given the relative spectral response of the NIR band, the solar zenith
angle, and the brightness temperatures of the NIR and the Thermal bands,
......@@ -63,6 +66,7 @@ class Calculator(RadTbConverter):
"""
def __init__(self, platform_name, instrument, band, **kwargs):
"""Initialize the Class instance."""
super(Calculator, self).__init__(platform_name, instrument, band, **kwargs)
from numbers import Number
......@@ -138,13 +142,15 @@ class Calculator(RadTbConverter):
LOG.info("File was there and has been read!")
def derive_rad39_corr(self, bt11, bt13, method='rosenfeld'):
"""Derive the 3.9 radiance correction factor to account for the
"""Derive the CO2 correction to be applied to the 3.9 channel.
Derive the 3.9 radiance correction factor to account for the
attenuation of the emitted 3.9 radiance by CO2
absorption. Requires the 11 micron window band and the 13.4
CO2 absorption band, as e.g. available on SEVIRI. Currently
only supports the Rosenfeld method
"""
"""
if method != 'rosenfeld':
raise AttributeError("Only CO2 correction for SEVIRI using "
"the Rosenfeld equation is supported!")
......@@ -153,9 +159,7 @@ class Calculator(RadTbConverter):
self._rad3x_correction = (bt11 - 0.25 * (bt11 - bt13)) ** 4 / bt11 ** 4
def _get_solarflux(self):
"""Derive the in-band solar flux from rsr over the Near IR band (3.7
or 3.9 microns)
"""
"""Derive the in-band solar flux from rsr over the Near IR band (3.7 or 3.9 microns)."""
solar_spectrum = \
SolarIrradianceSpectrum(TOTAL_IRRADIANCE_SPECTRUM_2000ASTM,
dlambda=0.0005,
......@@ -163,7 +167,7 @@ class Calculator(RadTbConverter):
self.solar_flux = solar_spectrum.inband_solarflux(self.rsr[self.bandname])
def emissive_part_3x(self, tb=True):
"""Get the emissive part of the 3.x band"""
"""Get the emissive part of the 3.x band."""
try:
# Emissive part:
self._e3x = self._rad3x_t11 * (1 - self._r3x)
......@@ -182,7 +186,8 @@ class Calculator(RadTbConverter):
return self._e3x
def reflectance_from_tbs(self, sun_zenith, tb_near_ir, tb_thermal, **kwargs):
"""
"""Derive reflectances from Tb's in the 3.x band.
The relfectance calculated is without units and should be between 0 and 1.
Inputs:
......
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (c) 2014-2018 Adam.Dybbroe
# Copyright (c) 2014-2019 Adam.Dybbroe
# Author(s):
......@@ -21,19 +21,22 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""Conversion between radiances and brightness temperatures for the IR bands of
"""
Converting between radiance and Tb.
Conversion between radiances and brightness temperatures for the IR bands of
various satellite sensors
"""
import numpy as np
from pyspectral.blackbody import (H_PLANCK, K_BOLTZMANN, C_SPEED)
from pyspectral.blackbody import blackbody, blackbody_wn
from pyspectral.utils import WAVE_NUMBER
from pyspectral.utils import WAVE_LENGTH
from pyspectral.utils import BANDNAMES
from pyspectral.utils import get_bandname_from_wavelength
from pyspectral.blackbody import (H_PLANCK, K_BOLTZMANN, C_SPEED)
from pyspectral.utils import convert2wavenumber
from pyspectral.rsr_reader import RelativeSpectralResponse
from pyspectral.utils import WAVE_NUMBER
from pyspectral.utils import WAVE_LENGTH
from numbers import Number
from scipy import integrate
......@@ -89,18 +92,21 @@ SEVIRI = {'IR3.9': {'Meteosat-8': [2567.330, 0.9956, 3.410],
class RadTbConverter(object):
"""A radiance to brightness temperature calculator.
It does the conversion based on direct use of the band relative
spectral response functions.
"""
def __init__(self, platform_name, instrument, band, **options):
"""E.g.:
"""Initialize the Class instance.
E.g.:
platform_name = 'Meteosat-9'
instrument = 'seviri'
band = 3.75
"""
self.platform_name = platform_name
self.instrument = instrument
......@@ -128,7 +134,8 @@ class RadTbConverter(object):
self._get_rsr()
def _get_rsr(self):
"""
"""Get the relative spectral responses.
Get the relative spectral responses from file, find the bandname, and
convert to the requested wave-spave (wavelength or wave number)
......@@ -158,11 +165,7 @@ class RadTbConverter(object):
self.rsr_integral = np.trapz(self.response, self.wavelength_or_wavenumber)
def _getsatname(self):
"""
Get the satellite name used in the rsr-reader, from the platform
and number
"""
"""Get the satellite name used in the rsr-reader, from the platform and number."""
if self.platform_name.startswith("Meteosat"):
return self.platform_name
else:
......@@ -170,8 +173,7 @@ class RadTbConverter(object):
'Platform {0} not yet supported...'.format(self.platform_name))
def tb2radiance(self, tb_, **kwargs):
"""Get the radiance from the brightness temperature (Tb) given the
band name.
"""Get the radiance from the brightness temperature (Tb) given the band name.
Input:
tb_: Brightness temperature of the band (self.band)
......@@ -224,7 +226,7 @@ class RadTbConverter(object):
'scale': scale}
def make_tb2rad_lut(self, filepath, normalized=True):
"""Generate a Tb to radiance look-up table"""
"""Generate a Tb to radiance look-up table."""
tb_ = np.arange(TB_MIN, TB_MAX, self.tb_resolution)
retv = self.tb2radiance(tb_, normalized=normalized)
rad = retv['radiance']
......@@ -232,13 +234,12 @@ class RadTbConverter(object):
@staticmethod
def read_tb2rad_lut(filepath):
"""Read the Tb to radiance look-up table"""
"""Read the Tb to radiance look-up table."""
retv = np.load(filepath, 'r')
return retv
def radiance2tb(self, rad):
"""
Get the Tb from the radiance using the Planck function and the central wavelength of the band
"""Get the Tb from the radiance using the Planck function and the central wavelength of the band.
rad:
Radiance in SI units
......@@ -247,8 +248,7 @@ class RadTbConverter(object):
def radiance2tb(rad, wavelength):
"""
Get the Tb from the radiance using the Planck function
"""Get the Tb from the radiance using the Planck function.
rad:
Radiance in SI units
......@@ -260,15 +260,17 @@ def radiance2tb(rad, wavelength):
class SeviriRadTbConverter(RadTbConverter):
"""
Radiance<->Tb converter for SEVIRI.
"""A radiance to brightness temperature calculator for SEVIRI based on
tabulated standard values using non-linear regression methods, and thus no
use of off line relative spectral response functions
A radiance to brightness temperature calculator for SEVIRI based on
tabulated standard values using non-linear regression methods, and thus no
use of off line relative spectral response functions
"""
def __init__(self, platform_name, band, **kwargs):
"""
"""Initialize the Class instance.
E.g.:
platform_name = Meteosat-9
band = 3.75
......@@ -283,12 +285,11 @@ class SeviriRadTbConverter(RadTbConverter):
raise AttributeError('Band name provided as a string is required')
def _get_rsr(self):
"""Overload the _get_rsr method, since RSR data are ignored here"""
"""Overload the _get_rsr method, since RSR data are ignored here."""
pass
def radiance2tb(self, rad):
"""Get the Tb from the radiance using the simple non-linear regression
method.
"""Get the Tb from the radiance using the simple non-linear regression method.
rad: Radiance in units = 'mW/m^2 sr^-1 (cm^-1)^-1'
......@@ -313,8 +314,9 @@ class SeviriRadTbConverter(RadTbConverter):
return tb_
def tb2radiance(self, tb_, **kwargs):
"""Get the radiance from the Tb using the simple non-linear regression
method. SI units of course!
"""Get the radiance from the Tb using the simple non-linear regression method.
SI units of course!
"""
# L = C1 * νc**3 / (exp (C2 νc / [αTb + β]) − 1)
#
......