Merge branch 'release/3.10' into task/568
This commit is contained in:
commit
31691cdb67
|
@ -79,11 +79,6 @@ jobs:
|
|||
- name: Build userguide, binaries, installer
|
||||
shell: bash -l {0}
|
||||
run: |
|
||||
# resolves ModuleNotFoundError during pyinstaller build on windows:
|
||||
# On Windows, with Python >= 3.8, DLLs are no longer imported from the PATH.
|
||||
# If gdalXXX.dll is in the PATH, then set the USE_PATH_FOR_GDAL_PYTHON=YES environment variable
|
||||
# to feed the PATH into os.add_dll_directory().
|
||||
export USE_PATH_FOR_GDAL_PYTHON=YES
|
||||
# This builds the users guide, binaries, and installer
|
||||
make windows_installer
|
||||
|
||||
|
|
41
HISTORY.rst
41
HISTORY.rst
|
@ -34,10 +34,51 @@
|
|||
|
||||
.. :changelog:
|
||||
|
||||
|
||||
..
|
||||
Unreleased Changes
|
||||
------------------
|
||||
|
||||
3.9.2 (2021-10-29)
|
||||
------------------
|
||||
* General:
|
||||
* Improving our binary build by including a data file needed for the
|
||||
``charset-normalizer`` python package. This eliminates a warning that
|
||||
was printed to stdout on Windows.
|
||||
* The Annual Water Yield model name is now standardized throughout InVEST.
|
||||
This model has been known in different contexts as Hydropower, Hydropower
|
||||
Water Yield, or Annual Water Yield. This name was chosen to emphasize
|
||||
that the model can be used for purposes other than hydropower (though the
|
||||
valuation component is hydropower-specific) and to highlight its
|
||||
difference from the Seasonal Water Yield model. The corresponding python
|
||||
module, formerly ``natcap.invest.hydropower.hydropower_water_yield``, is
|
||||
now ``natcap.invest.annual_water_yield``.
|
||||
* Minor changes to some other models' display names.
|
||||
* Update and expand on the instructions in the API docs for installing
|
||||
the ``natcap.invest`` package.
|
||||
* The InVEST binaries on Windows now no longer inspect the ``%PATH%``
|
||||
when looking for GDAL DLLs. This fixes an issue where InVEST would not
|
||||
launch on computers where the ``%PATH%`` either contained other
|
||||
environment variables or was malformed.
|
||||
* invest processes announce their logfile path at a very high logging level
|
||||
that cannot be filtered out by the user.
|
||||
* JSON sample data parameter sets are now included in the complete sample
|
||||
data archives.
|
||||
* Seasonal Water Yield
|
||||
* Fixed a bug in validation where providing the monthly alpha table would
|
||||
cause a "Spatial file <monthly alpha table> has no projection" error.
|
||||
The montly alpha table was mistakenly being validated as a spatial file.
|
||||
* Crop Production Regression
|
||||
* Corrected a misspelled column name. The fertilization rate table column
|
||||
must now be named ``phosphorus_rate``, not ``phosphorous_rate``.
|
||||
* Habitat Quality
|
||||
* Fixed a bug where optional input Allow Accessibility to Threats could
|
||||
not be passed as an empty string argument. Now handles falsey values.
|
||||
* Urban Flood Risk
|
||||
* Fixed a bug where lucodes present in the LULC raster but missing from
|
||||
the biophysical table would either raise a cryptic IndexError or silently
|
||||
apply invalid curve numbers. Now a helpful ValueError is raised.
|
||||
|
||||
Unreleased Changes (3.10)
|
||||
-------------------------
|
||||
* General:
|
||||
|
|
12
Makefile
12
Makefile
|
@ -2,15 +2,15 @@
|
|||
DATA_DIR := data
|
||||
GIT_SAMPLE_DATA_REPO := https://bitbucket.org/natcap/invest-sample-data.git
|
||||
GIT_SAMPLE_DATA_REPO_PATH := $(DATA_DIR)/invest-sample-data
|
||||
GIT_SAMPLE_DATA_REPO_REV := f8c3ef11d06cee9d6f5a07f48057c05939e83028
|
||||
GIT_SAMPLE_DATA_REPO_REV := c07883c44e00d4c977849e551891eb27e1ba3b1e
|
||||
|
||||
GIT_TEST_DATA_REPO := https://bitbucket.org/natcap/invest-test-data.git
|
||||
GIT_TEST_DATA_REPO_PATH := $(DATA_DIR)/invest-test-data
|
||||
GIT_TEST_DATA_REPO_REV := bc55f553c9d57baac0931f5691598baa1bcf3923
|
||||
GIT_TEST_DATA_REPO_REV := 8361823d5927f712a1aec2ee61620f92ff4f49b3
|
||||
|
||||
GIT_UG_REPO := https://github.com/natcap/invest.users-guide
|
||||
GIT_UG_REPO_PATH := doc/users-guide
|
||||
GIT_UG_REPO_REV := c53f85cec40c830ddd5b18a61e97c48607dd0ef9
|
||||
GIT_UG_REPO := https://github.com/natcap/invest.users-guide
|
||||
GIT_UG_REPO_PATH := doc/users-guide
|
||||
GIT_UG_REPO_REV := 7d0128ed9341acbcc73daef254be171a6cfba844
|
||||
|
||||
ENV = "./env"
|
||||
ifeq ($(OS),Windows_NT)
|
||||
|
@ -329,7 +329,7 @@ SAMPLEDATA_SINGLE_ARCHIVE := dist/InVEST_$(VERSION)_sample_data.zip
|
|||
sampledata_single: $(SAMPLEDATA_SINGLE_ARCHIVE)
|
||||
|
||||
$(SAMPLEDATA_SINGLE_ARCHIVE): $(GIT_SAMPLE_DATA_REPO_PATH) dist
|
||||
$(BASHLIKE_SHELL_COMMAND) "cd $(GIT_SAMPLE_DATA_REPO_PATH) && $(ZIP) -r ../../$(SAMPLEDATA_SINGLE_ARCHIVE) ./* -x .svn -x .git -x *.json"
|
||||
$(BASHLIKE_SHELL_COMMAND) "cd $(GIT_SAMPLE_DATA_REPO_PATH) && $(ZIP) -r ../../$(SAMPLEDATA_SINGLE_ARCHIVE) ./* -x .svn -x .git"
|
||||
|
||||
|
||||
# Installers for each platform.
|
||||
|
|
|
@ -15,10 +15,11 @@ choco install make vcredist140 pandoc zip 7zip unzip
|
|||
$env:PATH += ";C:\ProgramData\chocolatey\bin"
|
||||
|
||||
# Install Zip. This has been failing recently, so better to just install directly.
|
||||
# See https://sourceforge.net/p/forge/documentation/Mirrors/ for mirror options
|
||||
# See http://gnuwin32.sourceforge.net/setup.html for full list of installer CLI flags.
|
||||
# The installer doesn't add the target directory to the PATH, so we need to do that too.
|
||||
Write-Host "Installing GNU Zip"
|
||||
Invoke-WebRequest https://managedway.dl.sourceforge.net/project/gnuwin32/zip/3.0/zip-3.0-setup.exe -OutFile zip-setup.exe
|
||||
Invoke-WebRequest https://pilotfiber.dl.sourceforge.net/project/gnuwin32/zip/3.0/zip-3.0-setup.exe -OutFile zip-setup.exe
|
||||
& ./zip-setup.exe /VERYSILENT /SP /SUPPRESSMSGBOXES
|
||||
[Environment]::SetEnvironmentVariable("Path", $env:Path + ";C:\Program Files (x86)\GnuWin32\bin", "Machine")
|
||||
|
||||
|
|
|
@ -1,101 +1,84 @@
|
|||
.. _installing:
|
||||
|
||||
=============================
|
||||
Installing InVEST From Source
|
||||
=============================
|
||||
====================================
|
||||
Installing the InVEST Python Package
|
||||
====================================
|
||||
|
||||
.. attention::
|
||||
Most users will want to install the InVEST app (Mac disk image or Windows
|
||||
installer) from the `InVEST download page <https://naturalcapitalproject.stanford.edu/software/invest>`_.
|
||||
The instructions here are for more advanced use cases.
|
||||
|
||||
.. note::
|
||||
To install the ``natcap.invest`` package, you must have a C/C++ compiler
|
||||
installed and configured for your system. MacOS and Linux users should
|
||||
not need to do anything. Windows users should install Microsoft Visual
|
||||
Studio, or at least the Build Tools for Visual Studio, if they have
|
||||
not already. See the `python wiki page on compilation under Windows <https://wiki.python.org/moin/WindowsCompilers>`_ for more information.
|
||||
|
||||
.. _BinaryDependencies:
|
||||
Suggested method
|
||||
----------------
|
||||
|
||||
Binary Dependencies
|
||||
-------------------
|
||||
**Pattern**::
|
||||
|
||||
InVEST itself depends only on python packages, but many of these package
|
||||
dependencies depend on low-level libraries or have complex build processes.
|
||||
Some of these packages (notably, numpy and scipy) have started to release
|
||||
precompiled binary packages of their own. Recently we have had success
|
||||
installing all dependencies through ``conda`` and ``pip``; however you may
|
||||
find it easier to install some through a system package manager.
|
||||
conda create -y -c conda-forge -n <name> python=<python version>
|
||||
conda activate <name>
|
||||
conda install -y -c conda-forge gdal=<gdal version>
|
||||
pip install natcap.invest==<invest version>
|
||||
|
||||
Replace ``<name>`` with any name you'd like to give your environment.
|
||||
Replace ``<python version>`` with a python version known to be compatible with the desired invest version.
|
||||
Replace ``<gdal version>`` with a GDAL version known to be compatible with the desired invest version.
|
||||
Replace ``<invest version>`` with the desired invest version.
|
||||
|
||||
Most of the time, it is not really necessary to specify the versions of ``python``, ``gdal``, and ``natcap.invest``. If you do not specify a version, the latest version will be installed. Usually the latest versions are compatible with each other, but not always. Specifying versions that are known to work can prevent some problems. You can find the supported range of GDAL versions in the [requirements.txt](https://github.com/natcap/invest/blob/main/requirements.txt) (be sure to switch to the desired release tag in the dropdown).
|
||||
|
||||
**Example for InVEST 3.9.1**::
|
||||
|
||||
conda create -y -c conda-forge -n invest391 python=3.9.7
|
||||
conda activate invest391
|
||||
conda install -y -c conda-forge gdal=3.3.1
|
||||
pip install natcap.invest==3.9.1
|
||||
|
||||
|
||||
Conda
|
||||
--------------
|
||||
**Condensed into one line**::
|
||||
|
||||
If you're using a conda environment to manage your ``natcap.invest`` installation,
|
||||
it's easiest to install a few binary packages first before using pip to install
|
||||
the rest::
|
||||
|
||||
$ conda install "gdal>=3" numpy shapely rtree
|
||||
$ pip install natcap.invest
|
||||
conda create -y -c conda-forge -n invest391 python=3.9.7 gdal=3.3.1 && conda activate invest391 && pip install natcap.invest==3.9.1
|
||||
|
||||
|
||||
System Package Managers
|
||||
-----------------------
|
||||
Details
|
||||
-------
|
||||
Here is an explanation of what the commands are doing:
|
||||
|
||||
.. _InstallingOnLinux:
|
||||
1. Create a brand-new environment with the correct python version.
|
||||
|
||||
Linux
|
||||
*****
|
||||
``conda create -y -c conda-forge -n <name> python=<python version>``
|
||||
|
||||
Linux users have it easy, as almost every package required to use
|
||||
natcap.invest is available in the package repositories. The provided
|
||||
commands will install only the libraries and binaries that are needed, allowing
|
||||
``pip`` to install the rest.
|
||||
To be safe, you should **always install ``natcap.invest``` into a brand-new virtual environment**. This way you can be sure you have all the right versions of dependencies. Many issues with installing or using the ``natcap.invest`` package arise from dependency problems, and it's a lot easier to create a new environment than it is to fix an existing one.
|
||||
|
||||
2. Activate the brand-new environment just created.
|
||||
|
||||
Ubuntu & Debian
|
||||
^^^^^^^^^^^^^^^
|
||||
``conda activate <name>``
|
||||
|
||||
.. attention::
|
||||
The package versions in the debian:stable repositories often lag far
|
||||
behind the latest releases. It may be necessary to install a later
|
||||
version of a library from a different package repository, or else build
|
||||
the library from source.
|
||||
If you run ``conda list`` after this, you'll see the specified python version is there along with around 15 other packages that are included with python by default. None of these are specific to invest. You're now in an isolated environment so you can control which versions of dependencies are available to invest.
|
||||
|
||||
3. Install GDAL before installing invest
|
||||
|
||||
::
|
||||
``conda install -y -c conda-forge gdal=<gdal version>``
|
||||
|
||||
$ sudo apt-get install python3-dev python3-setuptools python3-gdal python3-rtree python3-shapely
|
||||
This is important because GDAL is not an ordinary python package. When you install the ``natcap.invest`` package in step 4, ``pip`` will also install all the dependencies of ``natcap.invest``. When ``pip`` tries to install GDAL, you will get an error unless the underlying GDAL binaries are already installed. That's because the ``gdal`` package that ``pip`` installs is just a python wrapper that depends on the GDAL binaries. GDAL itself is not a python package and can't be installed with ``pip``. Luckily, it can be installed with ``conda``!
|
||||
|
||||
4. Install invest
|
||||
|
||||
Fedora
|
||||
^^^^^^
|
||||
``pip install natcap.invest=<invest version>``
|
||||
|
||||
::
|
||||
``pip`` will also install the correct versions of all dependencies of ``natcap.invest``.
|
||||
|
||||
$ sudo yum install python3-devel python3-setuptools python3-gdal python3-rtree python3-shapely
|
||||
Since sometimes we don't need to use the UI at all, the basic ``natcap.invest`` package does not include the dependencies required for the UI. If you try to use the UI without having installed the UI dependencies, you'll get an error. If you do want to use the invest UI via the python package, install ``natcap.invest`` with the UI package extra: ::
|
||||
|
||||
.. _InstallingOnMac:
|
||||
|
||||
Mac OS X
|
||||
********
|
||||
|
||||
The easiest way to install binary packages on Mac OS X is through a package
|
||||
manager such as `Homebrew <http://brew.sh>`_::
|
||||
|
||||
$ brew install gdal spatialindex pyqt
|
||||
|
||||
The GDAL and PyQt packages include their respective python packages.
|
||||
The others will allow their corresponding python packages to be compiled
|
||||
against these binaries via ``pip``.
|
||||
|
||||
.. _InstallingOnWindows:
|
||||
|
||||
Windows
|
||||
*******
|
||||
|
||||
While many packages are available for Windows on the Python Package Index, some
|
||||
may need to be fetched from a different source. Many are available from
|
||||
Christogh Gohlke's unofficial build page:
|
||||
http://www.lfd.uci.edu/~gohlke/pythonlibs/
|
||||
|
||||
PyQt4 installers can also be downloaded from the `Riverbank Computing website <https://www.riverbankcomputing.com/software/pyqt/download>`_.
|
||||
pip install natcap.invest[ui]=<invest version>
|
||||
|
||||
The ``[ui]`` tells `pip` to also install all the dependencies needed for the UI.
|
||||
|
||||
|
||||
Python Dependencies
|
||||
|
@ -104,59 +87,44 @@ Python Dependencies
|
|||
Dependencies for ``natcap.invest`` are listed in ``requirements.txt``:
|
||||
|
||||
.. include:: ../../requirements.txt
|
||||
:literal:
|
||||
:start-line: 14
|
||||
|
||||
Additional dependencies for the UI are listed in ``requirements-gui.txt``:
|
||||
|
||||
.. include:: ../../requirements-gui.txt
|
||||
:literal:
|
||||
:start-line: 9
|
||||
|
||||
Please use ``conda`` and ``pip`` to install the correct versions of these dependencies automatically as described above.
|
||||
|
||||
.. _BinaryDependencies:
|
||||
|
||||
Binary Dependencies
|
||||
-------------------
|
||||
|
||||
Optional Qt User Interface
|
||||
--------------------------
|
||||
|
||||
InVEST's user interface is built with PyQt. Because of the hefty binary
|
||||
requirement of Qt and the relative difficulty of installing PyQt, these
|
||||
dependencies will not be installed with the standard
|
||||
``pip install natcap.invest``. These dependencies are available
|
||||
as extras, however, and can be installed via pip::
|
||||
|
||||
$ pip install natcap.invest[ui]
|
||||
|
||||
|
||||
.. _installing-from-source:
|
||||
|
||||
Installing from Source
|
||||
----------------------
|
||||
|
||||
.. note::
|
||||
|
||||
Python 3.6 users will need to install Microsoft Visual Studio 2017, or at
|
||||
least the Build Tools for Visual Studio 2017.
|
||||
See the `python wiki page on compilation under Windows <https://wiki.python.org/moin/WindowsCompilers>`_
|
||||
for more information.
|
||||
|
||||
Assuming you have a C/C++ compiler installed and configured for your system, and
|
||||
dependencies installed, the easiest way to install InVEST as a python package
|
||||
is::
|
||||
|
||||
$ pip install natcap.invest
|
||||
|
||||
InVEST itself depends only on python packages, but many of these package
|
||||
dependencies, such as numpy, scipy, and GDAL, depend on low-level libraries
|
||||
or have complex build processes. Precompiled binaries of all these dependencies
|
||||
are now available through ``conda`` and/or ``pip``. We recommend using ``conda``
|
||||
to manage these dependencies because it simplifies the install process and
|
||||
helps ensure versions are compatible. However, they may also be available through
|
||||
your system package manager.
|
||||
|
||||
Installing the latest development version
|
||||
-----------------------------------------
|
||||
|
||||
Pre-built binaries
|
||||
******************
|
||||
|
||||
Pre-built binaries for Windows
|
||||
******************************
|
||||
|
||||
Pre-built installers and wheels of development versions of ``natcap.invest``
|
||||
for 32-bit Windows python installations are available from
|
||||
Pre-built installers and wheels of development versions are available from
|
||||
http://releases.naturalcapitalproject.org/?prefix=invest/, along with other
|
||||
distributions of InVEST. Once downloaded, wheels can be installed locally via
|
||||
distributions of InVEST. Once downloaded, wheels can be installed locally via
|
||||
pip.
|
||||
|
||||
|
||||
Installing from our source tree
|
||||
*******************************
|
||||
Installing from source
|
||||
**********************
|
||||
|
||||
The latest development version of InVEST can be installed from our
|
||||
git source tree if you have a compiler installed::
|
||||
|
|
|
@ -65,7 +65,7 @@ Setting up your Python environment
|
|||
See the `pip docs for installing a package from a wheel
|
||||
<https://pip.pypa.io/en/stable/user_guide/#installing-from-wheels>`_
|
||||
* ``.zip`` and ``.tar.gz`` files are source archives.
|
||||
See :ref:`installing-from-source` for details, including how to
|
||||
See :ref:`installing` for details, including how to
|
||||
install specific development versions of ``natcap.invest``.
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
from PyInstaller.utils.hooks import (collect_data_files,
|
||||
copy_metadata)
|
||||
|
||||
datas = copy_metadata("charset_normalizer") + collect_data_files('charset_normalizer')
|
|
@ -0,0 +1,18 @@
|
|||
import os.path
|
||||
import glob
|
||||
|
||||
from PyInstaller.compat import is_win
|
||||
from PyInstaller.utils.hooks import collect_dynamic_libs, get_package_paths
|
||||
|
||||
if is_win:
|
||||
# GDAL appears to need `_gdal.cp38-win_amd64.pyd` located specifically in
|
||||
# `osgeo/_gdal....pyd` in order to work. This is because the GDAL python
|
||||
# __init__ script specifically looks in the `osgeo` directory in order to
|
||||
# find it. This is apparently only an issue on Windows.
|
||||
#
|
||||
# This will take the dynamic libraries in osgeo and put them into osgeo,
|
||||
# relative to the binaries directory.
|
||||
binaries = collect_dynamic_libs('osgeo', 'osgeo')
|
||||
pkg_base, pkg_dir = get_package_paths('osgeo')
|
||||
for pyd_file in glob.glob(os.path.join(pkg_dir, '*.pyd')):
|
||||
binaries.append((pyd_file, 'osgeo'))
|
|
@ -19,9 +19,3 @@ if platform.system() == 'Darwin':
|
|||
# sys._MEIPASS is the path to where the pyinstaller entrypoint bundle
|
||||
# lives. See the pyinstaller docs for more details.
|
||||
os.environ['SPATIALINDEX_C_LIBRARY'] = sys._MEIPASS
|
||||
|
||||
if platform.system() == 'Windows':
|
||||
# On Windows, with Python >= 3.8, DLLs are no longer imported from the PATH.
|
||||
# If gdalXXX.dll is in the PATH, then set the USE_PATH_FOR_GDAL_PYTHON=YES environment variable
|
||||
# to feed the PATH into os.add_dll_directory().
|
||||
os.environ['USE_PATH_FOR_GDAL_PYTHON'] = 'YES'
|
||||
|
|
|
@ -31,7 +31,8 @@ kwargs = {
|
|||
'distutils.dist',
|
||||
'rtree', # mac builds aren't picking up rtree by default.
|
||||
'pkg_resources.py2_warn',
|
||||
'cmath'
|
||||
'cmath',
|
||||
'charset_normalizer',
|
||||
],
|
||||
'datas': [('qt.conf', '.'), proj_datas],
|
||||
'cipher': block_cipher,
|
||||
|
|
|
@ -37,7 +37,7 @@ DATASTACKS = {
|
|||
'globio': ['globio/globio_demo.invs.json'],
|
||||
'habitat_quality': ['HabitatQuality/habitat_quality_willamette.invs.json'],
|
||||
'hra': ['HabitatRiskAssess/hra_wcvi.invs.json'],
|
||||
'hydropower_water_yield': ['Annual_Water_Yield/annual_water_yield_gura.invs.json'],
|
||||
'annual_water_yield': ['Annual_Water_Yield/annual_water_yield_gura.invs.json'],
|
||||
'ndr': ['NDR/ndr_gura.invs.json'],
|
||||
'pollination': ['pollination/pollination_willamette.invs.json'],
|
||||
'recreation': ['recreation/recreation_andros.invs.json'],
|
||||
|
|
1
setup.py
1
setup.py
|
@ -66,7 +66,6 @@ setup(
|
|||
'natcap.invest.delineateit',
|
||||
'natcap.invest.finfish_aquaculture',
|
||||
'natcap.invest.fisheries',
|
||||
'natcap.invest.hydropower',
|
||||
'natcap.invest.ui',
|
||||
'natcap.invest.ndr',
|
||||
'natcap.invest.sdr',
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"""init module for natcap.invest."""
|
||||
import builtins
|
||||
import collections
|
||||
import dataclasses
|
||||
import gettext
|
||||
import logging
|
||||
import os
|
||||
|
@ -22,7 +22,6 @@ except pkg_resources.DistributionNotFound:
|
|||
# package is not installed. Log the exception for debugging.
|
||||
LOGGER.exception('Could not load natcap.invest version information')
|
||||
|
||||
|
||||
# Check if the function _() is available
|
||||
# If not, define it as the identity function
|
||||
# _() is installed into builtins by gettext when we set up to translate
|
||||
|
@ -33,142 +32,185 @@ if not callable(getattr(builtins, '_', None)):
|
|||
def identity(x): return x
|
||||
builtins.__dict__['_'] = identity
|
||||
|
||||
_UIMETA = collections.namedtuple('UIMeta', 'humanname pyname gui aliases')
|
||||
MODEL_UIS = {
|
||||
'carbon': _UIMETA(
|
||||
humanname=_('Carbon Storage and Sequestration'),
|
||||
|
||||
@dataclasses.dataclass
|
||||
class _MODELMETA:
|
||||
"""Dataclass to store frequently used model metadata."""
|
||||
model_title: str # display name for the model
|
||||
pyname: str # importable python module name for the model
|
||||
gui: str # importable python class for the corresponding Qt UI
|
||||
userguide: str # name of the corresponding built userguide file
|
||||
aliases: tuple # alternate names for the model, if any
|
||||
|
||||
|
||||
MODEL_METADATA = {
|
||||
'annual_water_yield': _MODELMETA(
|
||||
model_title='Annual Water Yield',
|
||||
pyname='natcap.invest.annual_water_yield',
|
||||
gui='annual_water_yield.AnnualWaterYield',
|
||||
userguide='annual_water_yield.html',
|
||||
aliases=('hwy', 'awy')),
|
||||
'carbon': _MODELMETA(
|
||||
model_title='Carbon Storage and Sequestration',
|
||||
pyname='natcap.invest.carbon',
|
||||
gui='carbon.Carbon',
|
||||
userguide='carbonstorage.html',
|
||||
aliases=()),
|
||||
'coastal_blue_carbon': _UIMETA(
|
||||
humanname=_('Coastal Blue Carbon'),
|
||||
'coastal_blue_carbon': _MODELMETA(
|
||||
model_title='Coastal Blue Carbon',
|
||||
pyname='natcap.invest.coastal_blue_carbon.coastal_blue_carbon',
|
||||
gui='cbc.CoastalBlueCarbon',
|
||||
userguide='coastal_blue_carbon.html',
|
||||
aliases=('cbc',)),
|
||||
'coastal_blue_carbon_preprocessor': _UIMETA(
|
||||
humanname=_('Coastal Blue Carbon: Preprocessor'),
|
||||
'coastal_blue_carbon_preprocessor': _MODELMETA(
|
||||
model_title='Coastal Blue Carbon Preprocessor',
|
||||
pyname='natcap.invest.coastal_blue_carbon.preprocessor',
|
||||
gui='cbc.CoastalBlueCarbonPreprocessor',
|
||||
userguide='coastal_blue_carbon.html',
|
||||
aliases=('cbc_pre',)),
|
||||
'coastal_vulnerability': _UIMETA(
|
||||
humanname=_('Coastal Vulnerability'),
|
||||
'coastal_vulnerability': _MODELMETA(
|
||||
model_title='Coastal Vulnerability',
|
||||
pyname='natcap.invest.coastal_vulnerability',
|
||||
gui='coastal_vulnerability.CoastalVulnerability',
|
||||
userguide='coastal_vulnerability.html',
|
||||
aliases=('cv',)),
|
||||
'crop_production_percentile': _UIMETA(
|
||||
humanname=_('Crop Production: Percentile Model'),
|
||||
'crop_production_percentile': _MODELMETA(
|
||||
model_title='Crop Production: Percentile',
|
||||
pyname='natcap.invest.crop_production_percentile',
|
||||
gui='crop_production.CropProductionPercentile',
|
||||
userguide='crop_production.html',
|
||||
aliases=('cpp',)),
|
||||
'crop_production_regression': _UIMETA(
|
||||
humanname=_('Crop Production: Regression Model'),
|
||||
'crop_production_regression': _MODELMETA(
|
||||
model_title='Crop Production: Regression',
|
||||
pyname='natcap.invest.crop_production_regression',
|
||||
gui='crop_production.CropProductionRegression',
|
||||
userguide='crop_production.html',
|
||||
aliases=('cpr',)),
|
||||
'delineateit': _UIMETA(
|
||||
humanname=_('DelineateIt'),
|
||||
'delineateit': _MODELMETA(
|
||||
model_title='DelineateIt',
|
||||
pyname='natcap.invest.delineateit.delineateit',
|
||||
gui='delineateit.Delineateit',
|
||||
userguide='delineateit.html',
|
||||
aliases=()),
|
||||
'finfish_aquaculture': _UIMETA(
|
||||
humanname=_('Marine Finfish Aquaculture Production'),
|
||||
'finfish_aquaculture': _MODELMETA(
|
||||
model_title='Finfish Aquaculture',
|
||||
pyname='natcap.invest.finfish_aquaculture.finfish_aquaculture',
|
||||
gui='finfish.FinfishAquaculture',
|
||||
userguide='marine_fish.html',
|
||||
aliases=()),
|
||||
'fisheries': _UIMETA(
|
||||
humanname=_('Fisheries'),
|
||||
'fisheries': _MODELMETA(
|
||||
model_title='Fisheries',
|
||||
pyname='natcap.invest.fisheries.fisheries',
|
||||
gui='fisheries.Fisheries',
|
||||
userguide='fisheries.html',
|
||||
aliases=()),
|
||||
'fisheries_hst': _UIMETA(
|
||||
humanname=_('Fisheries: Habitat Scenario Tool'),
|
||||
'fisheries_hst': _MODELMETA(
|
||||
model_title='Fisheries Habitat Scenario Tool',
|
||||
pyname='natcap.invest.fisheries.fisheries_hst',
|
||||
gui='fisheries.FisheriesHST',
|
||||
userguide='fisheries.html',
|
||||
aliases=()),
|
||||
'forest_carbon_edge_effect': _UIMETA(
|
||||
humanname=_('Forest Carbon Edge Effect'),
|
||||
'forest_carbon_edge_effect': _MODELMETA(
|
||||
model_title='Forest Carbon Edge Effect',
|
||||
pyname='natcap.invest.forest_carbon_edge_effect',
|
||||
gui='forest_carbon.ForestCarbonEdgeEffect',
|
||||
userguide='carbon_edge.html',
|
||||
aliases=('fc',)),
|
||||
'globio': _UIMETA(
|
||||
humanname=_('GLOBIO'),
|
||||
'globio': _MODELMETA(
|
||||
model_title='GLOBIO',
|
||||
pyname='natcap.invest.globio',
|
||||
gui='globio.GLOBIO',
|
||||
userguide='globio.html',
|
||||
aliases=()),
|
||||
'habitat_quality': _UIMETA(
|
||||
humanname=_('Habitat Quality'),
|
||||
'habitat_quality': _MODELMETA(
|
||||
model_title='Habitat Quality',
|
||||
pyname='natcap.invest.habitat_quality',
|
||||
gui='habitat_quality.HabitatQuality',
|
||||
userguide='habitat_quality.html',
|
||||
aliases=('hq',)),
|
||||
'habitat_risk_assessment': _UIMETA(
|
||||
humanname=_('Habitat Risk Assessment'),
|
||||
'habitat_risk_assessment': _MODELMETA(
|
||||
model_title='Habitat Risk Assessment',
|
||||
pyname='natcap.invest.hra',
|
||||
gui='hra.HabitatRiskAssessment',
|
||||
userguide='habitat_risk_assessment.html',
|
||||
aliases=('hra',)),
|
||||
'hydropower_water_yield': _UIMETA(
|
||||
humanname=_('Annual Water Yield'),
|
||||
pyname='natcap.invest.hydropower.hydropower_water_yield',
|
||||
gui='hydropower.HydropowerWaterYield',
|
||||
aliases=('hwy',)),
|
||||
'ndr': _UIMETA(
|
||||
humanname=_('NDR: Nutrient Delivery Ratio'),
|
||||
'ndr': _MODELMETA(
|
||||
model_title='Nutrient Delivery Ratio',
|
||||
pyname='natcap.invest.ndr.ndr',
|
||||
gui='ndr.Nutrient',
|
||||
userguide='ndr.html',
|
||||
aliases=()),
|
||||
'pollination': _UIMETA(
|
||||
humanname=_('Pollinator Abundance: Crop Pollination'),
|
||||
'pollination': _MODELMETA(
|
||||
model_title='Crop Pollination',
|
||||
pyname='natcap.invest.pollination',
|
||||
gui='pollination.Pollination',
|
||||
userguide='croppollination.html',
|
||||
aliases=()),
|
||||
'recreation': _UIMETA(
|
||||
humanname=_('Visitation: Recreation and Tourism'),
|
||||
'recreation': _MODELMETA(
|
||||
model_title='Visitation: Recreation and Tourism',
|
||||
pyname='natcap.invest.recreation.recmodel_client',
|
||||
gui='recreation.Recreation',
|
||||
userguide='recreation.html',
|
||||
aliases=()),
|
||||
'routedem': _UIMETA(
|
||||
humanname=_('RouteDEM'),
|
||||
'routedem': _MODELMETA(
|
||||
model_title='RouteDEM',
|
||||
pyname='natcap.invest.routedem',
|
||||
gui='routedem.RouteDEM',
|
||||
userguide='routedem.html',
|
||||
aliases=()),
|
||||
'scenario_generator_proximity': _UIMETA(
|
||||
humanname=_('Scenario Generator: Proximity Based'),
|
||||
'scenario_generator_proximity': _MODELMETA(
|
||||
model_title='Scenario Generator: Proximity Based',
|
||||
pyname='natcap.invest.scenario_gen_proximity',
|
||||
gui='scenario_gen.ScenarioGenProximity',
|
||||
userguide='scenario_gen_proximity.html',
|
||||
aliases=('sgp',)),
|
||||
'scenic_quality': _UIMETA(
|
||||
humanname=_('Unobstructed Views: Scenic Quality Provision'),
|
||||
'scenic_quality': _MODELMETA(
|
||||
model_title='Unobstructed Views: Scenic Quality Provision',
|
||||
pyname='natcap.invest.scenic_quality.scenic_quality',
|
||||
gui='scenic_quality.ScenicQuality',
|
||||
userguide='scenic_quality.html',
|
||||
aliases=('sq',)),
|
||||
'sdr': _UIMETA(
|
||||
humanname=_('SDR: Sediment Delivery Ratio'),
|
||||
'sdr': _MODELMETA(
|
||||
model_title='Sediment Delivery Ratio',
|
||||
pyname='natcap.invest.sdr.sdr',
|
||||
gui='sdr.SDR',
|
||||
userguide='sdr.html',
|
||||
aliases=()),
|
||||
'seasonal_water_yield': _UIMETA(
|
||||
humanname=_('Seasonal Water Yield'),
|
||||
'seasonal_water_yield': _MODELMETA(
|
||||
model_title='Seasonal Water Yield',
|
||||
pyname='natcap.invest.seasonal_water_yield.seasonal_water_yield',
|
||||
gui='seasonal_water_yield.SeasonalWaterYield',
|
||||
userguide='seasonal_water_yield.html',
|
||||
aliases=('swy',)),
|
||||
'wind_energy': _UIMETA(
|
||||
humanname=_('Offshore Wind Energy Production'),
|
||||
pyname='natcap.invest.wind_energy',
|
||||
gui='wind_energy.WindEnergy',
|
||||
'stormwater': _MODELMETA(
|
||||
model_title='Stormwater',
|
||||
pyname='natcap.invest.stormwater',
|
||||
gui='stormwater.Stormwater',
|
||||
userguide='stormwater.html',
|
||||
aliases=()),
|
||||
'wave_energy': _UIMETA(
|
||||
humanname=_('Wave Energy Production'),
|
||||
'wave_energy': _MODELMETA(
|
||||
model_title='Wave Energy Production',
|
||||
pyname='natcap.invest.wave_energy',
|
||||
gui='wave_energy.WaveEnergy',
|
||||
userguide='wave_energy.html',
|
||||
aliases=()),
|
||||
'urban_flood_risk_mitigation': _UIMETA(
|
||||
humanname=_('Urban Flood Risk Mitigation'),
|
||||
'wind_energy': _MODELMETA(
|
||||
model_title='Wind Energy Production',
|
||||
pyname='natcap.invest.wind_energy',
|
||||
gui='wind_energy.WindEnergy',
|
||||
userguide='wind_energy.html',
|
||||
aliases=()),
|
||||
'urban_flood_risk_mitigation': _MODELMETA(
|
||||
model_title='Urban Flood Risk Mitigation',
|
||||
pyname='natcap.invest.urban_flood_risk_mitigation',
|
||||
gui='urban_flood_risk_mitigation.UrbanFloodRiskMitigation',
|
||||
userguide='urban_flood_risk_mitigation.html',
|
||||
aliases=('ufrm',)),
|
||||
'urban_cooling_model': _UIMETA(
|
||||
humanname=_('Urban Cooling'),
|
||||
'urban_cooling_model': _MODELMETA(
|
||||
model_title='Urban Cooling',
|
||||
pyname='natcap.invest.urban_cooling_model',
|
||||
gui='urban_cooling_model.UrbanCoolingModel',
|
||||
userguide='urban_cooling_model.html',
|
||||
aliases=('ucm',)),
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
"""InVEST Hydropower Water Yield model."""
|
||||
"""InVEST Annual Water Yield model."""
|
||||
import logging
|
||||
import os
|
||||
import math
|
||||
|
@ -10,17 +10,18 @@ from osgeo import ogr
|
|||
import pygeoprocessing
|
||||
import taskgraph
|
||||
|
||||
from .. import utils
|
||||
from .. import spec_utils
|
||||
from ..spec_utils import u
|
||||
from .. import validation
|
||||
from . import utils
|
||||
from . import spec_utils
|
||||
from .spec_utils import u
|
||||
from . import validation
|
||||
from . import MODEL_METADATA
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
||||
ARGS_SPEC = {
|
||||
"model_name": _("Hydropower Water Yield"),
|
||||
"module": __name__,
|
||||
"userguide_html": "reservoirhydropowerproduction.html",
|
||||
"model_name": MODEL_METADATA["annual_water_yield"].model_title,
|
||||
"pyname": MODEL_METADATA["annual_water_yield"].pyname,
|
||||
"userguide_html": MODEL_METADATA["annual_water_yield"].userguide,
|
||||
"args_with_spatial_overlap": {
|
||||
"spatial_keys": ["lulc_path",
|
||||
"depth_to_root_rest_layer_path",
|
||||
|
@ -218,7 +219,7 @@ ARGS_SPEC = {
|
|||
def execute(args):
|
||||
"""Annual Water Yield: Reservoir Hydropower Production.
|
||||
|
||||
Executes the hydropower/water_yield model
|
||||
Executes the hydropower/annual water yield model
|
||||
|
||||
Args:
|
||||
args['workspace_dir'] (string): a path to the directory that will write
|
|
@ -15,13 +15,14 @@ from . import validation
|
|||
from . import utils
|
||||
from . import spec_utils
|
||||
from .spec_utils import u
|
||||
from . import MODEL_METADATA
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
||||
ARGS_SPEC = {
|
||||
"model_name": _("InVEST Carbon Model"),
|
||||
"module": __name__,
|
||||
"userguide_html": "carbonstorage.html",
|
||||
"model_name": MODEL_METADATA["carbon"].model_title,
|
||||
"pyname": MODEL_METADATA["carbon"].pyname,
|
||||
"userguide_html": MODEL_METADATA["carbon"].userguide,
|
||||
"args_with_spatial_overlap": {
|
||||
"spatial_keys": ["lulc_cur_path", "lulc_fut_path", "lulc_redd_path"],
|
||||
},
|
||||
|
|
|
@ -18,27 +18,27 @@ try:
|
|||
from . import __version__
|
||||
from . import utils
|
||||
from . import datastack
|
||||
from . import MODEL_UIS
|
||||
from . import MODEL_METADATA
|
||||
except (ValueError, ImportError):
|
||||
# When we're in a PyInstaller build, this isn't a module.
|
||||
from natcap.invest import __version__
|
||||
from natcap.invest import utils
|
||||
from natcap.invest import datastack
|
||||
from natcap.invest import MODEL_UIS
|
||||
from natcap.invest import MODEL_METADATA
|
||||
|
||||
|
||||
DEFAULT_EXIT_CODE = 1
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
||||
# Build up an index mapping aliases to modelname.
|
||||
# ``modelname`` is the key to the MODEL_UIS dict, above.
|
||||
# Build up an index mapping aliases to model_name.
|
||||
# ``model_name`` is the key to the MODEL_METADATA dict.
|
||||
_MODEL_ALIASES = {}
|
||||
for _modelname, _meta in MODEL_UIS.items():
|
||||
for _alias in _meta.aliases:
|
||||
assert _alias not in _MODEL_ALIASES, (
|
||||
for model_name, meta in MODEL_METADATA.items():
|
||||
for alias in meta.aliases:
|
||||
assert alias not in _MODEL_ALIASES, (
|
||||
'Alias %s already defined for model %s') % (
|
||||
_alias, _MODEL_ALIASES[_alias])
|
||||
_MODEL_ALIASES[_alias] = _modelname
|
||||
alias, _MODEL_ALIASES[alias])
|
||||
_MODEL_ALIASES[alias] = model_name
|
||||
|
||||
|
||||
def build_model_list_table():
|
||||
|
@ -51,27 +51,27 @@ def build_model_list_table():
|
|||
Returns:
|
||||
A string representation of the formatted table.
|
||||
"""
|
||||
model_names = sorted(MODEL_UIS.keys())
|
||||
model_names = sorted(MODEL_METADATA.keys())
|
||||
max_model_name_length = max(len(name) for name in model_names)
|
||||
|
||||
# Adding 3 to max alias name length for the parentheses plus some padding.
|
||||
max_alias_name_length = max(len(', '.join(meta.aliases))
|
||||
for meta in MODEL_UIS.values()) + 3
|
||||
template_string = ' {modelname} {aliases} {humanname} {usage}'
|
||||
strings = [_('Available models:')]
|
||||
for model_name in sorted(MODEL_UIS.keys()):
|
||||
for meta in MODEL_METADATA.values()) + 3
|
||||
template_string = ' {model_name} {aliases} {model_title} {usage}'
|
||||
strings = ['Available models:']
|
||||
for model_name in model_names:
|
||||
usage_string = '(No GUI available)'
|
||||
if MODEL_UIS[model_name].gui is not None:
|
||||
if MODEL_METADATA[model_name].gui is not None:
|
||||
usage_string = ''
|
||||
|
||||
alias_string = ', '.join(MODEL_UIS[model_name].aliases)
|
||||
alias_string = ', '.join(MODEL_METADATA[model_name].aliases)
|
||||
if alias_string:
|
||||
alias_string = '(%s)' % alias_string
|
||||
|
||||
strings.append(template_string.format(
|
||||
modelname=model_name.ljust(max_model_name_length),
|
||||
model_name=model_name.ljust(max_model_name_length),
|
||||
aliases=alias_string.ljust(max_alias_name_length),
|
||||
humanname=MODEL_UIS[model_name].humanname,
|
||||
model_title=MODEL_METADATA[model_name].model_title,
|
||||
usage=usage_string))
|
||||
return '\n'.join(strings) + '\n'
|
||||
|
||||
|
@ -80,7 +80,7 @@ def build_model_list_json():
|
|||
"""Build a json object of relevant information for the CLI.
|
||||
|
||||
The json object returned uses the human-readable model names for keys
|
||||
and the values are another dict containing the internal python name
|
||||
and the values are another dict containing the internal name
|
||||
of the model and the aliases recognized by the CLI.
|
||||
|
||||
Returns:
|
||||
|
@ -88,9 +88,9 @@ def build_model_list_json():
|
|||
|
||||
"""
|
||||
json_object = {}
|
||||
for internal_model_name, model_data in MODEL_UIS.items():
|
||||
json_object[model_data.humanname] = {
|
||||
'internal_name': internal_model_name,
|
||||
for model_name, model_data in MODEL_METADATA.items():
|
||||
json_object[model_data.model_title] = {
|
||||
'model_name': model_name,
|
||||
'aliases': model_data.aliases
|
||||
}
|
||||
|
||||
|
@ -102,12 +102,12 @@ def export_to_python(target_filepath, model, args_dict=None):
|
|||
# coding=UTF-8
|
||||
# -----------------------------------------------
|
||||
# Generated by InVEST {invest_version} on {today}
|
||||
# Model: {modelname}
|
||||
# Model: {model_title}
|
||||
|
||||
import logging
|
||||
import sys
|
||||
|
||||
import {py_model}
|
||||
import {pyname}
|
||||
import natcap.invest.utils
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
@ -123,12 +123,11 @@ def export_to_python(target_filepath, model, args_dict=None):
|
|||
args = {model_args}
|
||||
|
||||
if __name__ == '__main__':
|
||||
{py_model}.execute(args)
|
||||
{pyname}.execute(args)
|
||||
""")
|
||||
|
||||
target_model = MODEL_UIS[model].pyname
|
||||
if args_dict is None:
|
||||
model_module = importlib.import_module(name=target_model)
|
||||
model_module = importlib.import_module(name=MODEL_METADATA[model].pyname)
|
||||
spec = model_module.ARGS_SPEC
|
||||
cast_args = {key: '' for key in spec['args'].keys()}
|
||||
else:
|
||||
|
@ -147,8 +146,8 @@ def export_to_python(target_filepath, model, args_dict=None):
|
|||
py_file.write(script_template.format(
|
||||
invest_version=__version__,
|
||||
today=datetime.datetime.now().strftime('%c'),
|
||||
modelname=MODEL_UIS[model].humanname,
|
||||
py_model=target_model,
|
||||
model_title=MODEL_METADATA[model].model_title,
|
||||
pyname=MODEL_METADATA[model].pyname,
|
||||
model_args=args))
|
||||
|
||||
|
||||
|
@ -167,11 +166,11 @@ class SelectModelAction(argparse.Action):
|
|||
|
||||
Identifiable model names are:
|
||||
|
||||
* the model name (verbatim) as identified in the keys of MODEL_UIS
|
||||
* the model name (verbatim) as identified in the keys of MODEL_METADATA
|
||||
* a uniquely identifiable prefix for the model name (e.g. "d"
|
||||
matches "delineateit", but "fi" matches both "fisheries" and
|
||||
"finfish"
|
||||
* a known model alias, as registered in MODEL_UIS
|
||||
* a known model alias, as registered in MODEL_METADATA
|
||||
|
||||
If no single model can be identified based on these rules, an error
|
||||
message is printed and the parser exits with a nonzero exit code.
|
||||
|
@ -182,7 +181,7 @@ class SelectModelAction(argparse.Action):
|
|||
|
||||
Overridden from argparse.Action.__call__.
|
||||
"""
|
||||
known_models = sorted(list(MODEL_UIS.keys()))
|
||||
known_models = sorted(list(MODEL_METADATA.keys()))
|
||||
|
||||
matching_models = [model for model in known_models if
|
||||
model.startswith(values)]
|
||||
|
@ -251,7 +250,7 @@ def main(user_args=None):
|
|||
verbosity_group.add_argument(
|
||||
'--debug', dest='log_level', default=logging.ERROR,
|
||||
action='store_const', const=logging.DEBUG,
|
||||
help='Enable debug logging. Alias for -vvvv')
|
||||
help='Enable debug logging. Alias for -vvv')
|
||||
|
||||
parser.add_argument(
|
||||
'-L', '--language', default='en', choices=['en', 'es'],
|
||||
|
@ -417,7 +416,7 @@ def main(user_args=None):
|
|||
parser.exit(0)
|
||||
|
||||
if args.subcommand == 'getspec':
|
||||
target_model = MODEL_UIS[args.model].pyname
|
||||
target_model = MODEL_METADATA[args.model].pyname
|
||||
model_module = importlib.import_module(name=target_model)
|
||||
spec = model_module.ARGS_SPEC
|
||||
|
||||
|
@ -447,7 +446,7 @@ def main(user_args=None):
|
|||
else:
|
||||
parsed_datastack.args['workspace_dir'] = args.workspace
|
||||
|
||||
target_model = MODEL_UIS[args.model].pyname
|
||||
target_model = MODEL_METADATA[args.model].pyname
|
||||
model_module = importlib.import_module(name=target_model)
|
||||
LOGGER.info('Imported target %s from %s',
|
||||
model_module.__name__, model_module)
|
||||
|
@ -488,7 +487,7 @@ def main(user_args=None):
|
|||
|
||||
from natcap.invest.ui import inputs
|
||||
|
||||
gui_class = MODEL_UIS[args.model].gui
|
||||
gui_class = MODEL_METADATA[args.model].gui
|
||||
module_name, classname = gui_class.split('.')
|
||||
module = importlib.import_module(
|
||||
name='.ui.%s' % module_name,
|
||||
|
|
|
@ -106,6 +106,7 @@ from .. import utils
|
|||
from .. import spec_utils
|
||||
from ..spec_utils import u
|
||||
from .. import validation
|
||||
from .. import MODEL_METADATA
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -150,9 +151,9 @@ TASKGRAPH_CACHE_DIR_NAME = 'task_cache'
|
|||
OUTPUT_DIR_NAME = 'output'
|
||||
|
||||
ARGS_SPEC = {
|
||||
"model_name": _("Coastal Blue Carbon"),
|
||||
"module": __name__,
|
||||
"userguide_html": "coastal_blue_carbon.html",
|
||||
"model_name": MODEL_METADATA["coastal_blue_carbon"].model_title,
|
||||
"pyname": MODEL_METADATA["coastal_blue_carbon"].pyname,
|
||||
"userguide_html": MODEL_METADATA["coastal_blue_carbon"].userguide,
|
||||
"args": {
|
||||
"workspace_dir": spec_utils.WORKSPACE,
|
||||
"results_suffix": spec_utils.SUFFIX,
|
||||
|
|
|
@ -12,14 +12,15 @@ from .. import utils
|
|||
from .. import spec_utils
|
||||
from ..spec_utils import u
|
||||
from .. import validation
|
||||
from .. import MODEL_METADATA
|
||||
from . import coastal_blue_carbon
|
||||
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
ARGS_SPEC = {
|
||||
"model_name": _("Coastal Blue Carbon Preprocessor"),
|
||||
"module": __name__,
|
||||
"userguide_html": "coastal_blue_carbon.html",
|
||||
"model_name": MODEL_METADATA["coastal_blue_carbon_preprocessor"].model_title,
|
||||
"pyname": MODEL_METADATA["coastal_blue_carbon_preprocessor"].pyname,
|
||||
"userguide_html": MODEL_METADATA["coastal_blue_carbon_preprocessor"].userguide,
|
||||
"args": {
|
||||
"workspace_dir": spec_utils.WORKSPACE,
|
||||
"results_suffix": spec_utils.SUFFIX,
|
||||
|
|
|
@ -24,14 +24,15 @@ from . import utils
|
|||
from . import spec_utils
|
||||
from .spec_utils import u
|
||||
from . import validation
|
||||
from . import MODEL_METADATA
|
||||
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
||||
ARGS_SPEC = {
|
||||
"model_name": _("Coastal Vulnerability"),
|
||||
"module": __name__,
|
||||
"userguide_html": "coastal_vulnerability.html",
|
||||
"model_name": MODEL_METADATA["coastal_vulnerability"].model_title,
|
||||
"pyname": MODEL_METADATA["coastal_vulnerability"].pyname,
|
||||
"userguide_html": MODEL_METADATA["coastal_vulnerability"].userguide,
|
||||
"args_with_spatial_overlap": {
|
||||
"spatial_keys": [
|
||||
"aoi_vector_path",
|
||||
|
|
|
@ -15,14 +15,15 @@ from . import utils
|
|||
from . import spec_utils
|
||||
from .spec_utils import u
|
||||
from . import validation
|
||||
from . import MODEL_METADATA
|
||||
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
||||
ARGS_SPEC = {
|
||||
"model_name": _("Crop Production Percentile Model"),
|
||||
"module": __name__,
|
||||
"userguide_html": "crop_production.html",
|
||||
"model_name": MODEL_METADATA["crop_production_percentile"].model_title,
|
||||
"pyname": MODEL_METADATA["crop_production_percentile"].pyname,
|
||||
"userguide_html": MODEL_METADATA["crop_production_percentile"].userguide,
|
||||
"args_with_spatial_overlap": {
|
||||
"spatial_keys": [
|
||||
"landcover_raster_path",
|
||||
|
|
|
@ -13,6 +13,7 @@ from .spec_utils import u
|
|||
from . import spec_utils
|
||||
from . import utils
|
||||
from . import validation
|
||||
from . import MODEL_METADATA
|
||||
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
@ -22,9 +23,9 @@ CROPS = [
|
|||
"sugarbeet", "sugarcane", "sunflower", "wheat"]
|
||||
|
||||
ARGS_SPEC = {
|
||||
"model_name": _("Crop Production Regression Model"),
|
||||
"module": __name__,
|
||||
"userguide_html": "crop_production.html",
|
||||
"model_name": MODEL_METADATA["crop_production_regression"].model_title,
|
||||
"pyname": MODEL_METADATA["crop_production_regression"].pyname,
|
||||
"userguide_html": MODEL_METADATA["crop_production_regression"].userguide,
|
||||
"args_with_spatial_overlap": {
|
||||
"spatial_keys": ["landcover_raster_path", "aggregate_polygon_path"],
|
||||
"different_projections_ok": True,
|
||||
|
|
|
@ -18,15 +18,16 @@ from .. import utils
|
|||
from .. import spec_utils
|
||||
from ..spec_utils import u
|
||||
from .. import validation
|
||||
from .. import MODEL_METADATA
|
||||
from . import delineateit_core
|
||||
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
||||
ARGS_SPEC = {
|
||||
"model_name": _("DelineateIt: Watershed Delineation"),
|
||||
"module": __name__,
|
||||
"userguide_html": "delineateit.html",
|
||||
"model_name": MODEL_METADATA["delineateit"].model_title,
|
||||
"pyname": MODEL_METADATA["delineateit"].pyname,
|
||||
"userguide_html": MODEL_METADATA["delineateit"].userguide,
|
||||
"args_with_spatial_overlap": {
|
||||
"spatial_keys": ["dem_path", "outlet_vector_path"],
|
||||
"different_projections_ok": True,
|
||||
|
|
|
@ -8,14 +8,15 @@ from .. import utils
|
|||
from .. import spec_utils
|
||||
from ..spec_utils import u
|
||||
from .. import validation
|
||||
from .. import MODEL_METADATA
|
||||
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
||||
ARGS_SPEC = {
|
||||
"model_name": _("Finfish Aquaculture"),
|
||||
"module": __name__,
|
||||
"userguide_html": "marine_fish.html",
|
||||
"model_name": MODEL_METADATA["finfish_aquaculture"].model_title,
|
||||
"pyname": MODEL_METADATA["finfish_aquaculture"].pyname,
|
||||
"userguide_html": MODEL_METADATA["finfish_aquaculture"].userguide,
|
||||
"args": {
|
||||
"workspace_dir": spec_utils.WORKSPACE,
|
||||
"results_suffix": spec_utils.SUFFIX,
|
||||
|
|
|
@ -11,14 +11,15 @@ from .. import utils
|
|||
from .. import spec_utils
|
||||
from ..spec_utils import u
|
||||
from .. import validation
|
||||
from .. import MODEL_METADATA
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
LABEL = 'Fisheries'
|
||||
|
||||
ARGS_SPEC = {
|
||||
"model_name": _("Fisheries"),
|
||||
"module": __name__,
|
||||
"userguide_html": "fisheries.html",
|
||||
"model_name": MODEL_METADATA["fisheries"].model_title,
|
||||
"pyname": MODEL_METADATA["fisheries"].pyname,
|
||||
"userguide_html": MODEL_METADATA["fisheries"].userguide,
|
||||
"args": {
|
||||
"workspace_dir": spec_utils.WORKSPACE,
|
||||
"results_suffix": spec_utils.SUFFIX,
|
||||
|
|
|
@ -11,13 +11,14 @@ import numpy as np
|
|||
from . import fisheries_hst_io as io
|
||||
from .. import validation
|
||||
from .. import spec_utils
|
||||
from .. import MODEL_METADATA
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
||||
ARGS_SPEC = {
|
||||
"model_name": _("Fisheries Habitat Scenario Tool"),
|
||||
"module": __name__,
|
||||
"userguide_html": "fisheries.html",
|
||||
"model_name": MODEL_METADATA["fisheries_hst"].model_title,
|
||||
"pyname": MODEL_METADATA["fisheries_hst"].pyname,
|
||||
"userguide_html": MODEL_METADATA["fisheries_hst"].userguide,
|
||||
"args": {
|
||||
"workspace_dir": spec_utils.WORKSPACE,
|
||||
"results_suffix": spec_utils.SUFFIX,
|
||||
|
|
|
@ -20,6 +20,7 @@ from . import utils
|
|||
from . import spec_utils
|
||||
from .spec_utils import u
|
||||
from . import validation
|
||||
from . import MODEL_METADATA
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -30,9 +31,9 @@ DISTANCE_UPPER_BOUND = 500e3
|
|||
NODATA_VALUE = -1
|
||||
|
||||
ARGS_SPEC = {
|
||||
"model_name": _("Forest Carbon Edge Effect Model"),
|
||||
"module": __name__,
|
||||
"userguide_html": "carbon_edge.html",
|
||||
"model_name": MODEL_METADATA["forest_carbon_edge_effect"].model_title,
|
||||
"pyname": MODEL_METADATA["forest_carbon_edge_effect"].pyname,
|
||||
"userguide_html": MODEL_METADATA["forest_carbon_edge_effect"].userguide,
|
||||
"args_with_spatial_overlap": {
|
||||
"spatial_keys": ["aoi_vector_path", "lulc_raster_path"],
|
||||
},
|
||||
|
|
|
@ -15,6 +15,7 @@ from . import utils
|
|||
from . import spec_utils
|
||||
from .spec_utils import u
|
||||
from . import validation
|
||||
from . import MODEL_METADATA
|
||||
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
@ -25,9 +26,9 @@ LOGGER = logging.getLogger(__name__)
|
|||
SIGMA = 9.0
|
||||
|
||||
ARGS_SPEC = {
|
||||
"model_name": _("GLOBIO"),
|
||||
"module": __name__,
|
||||
"userguide_html": "../documentation/globio.html",
|
||||
"model_name": MODEL_METADATA["globio"].model_title,
|
||||
"pyname": MODEL_METADATA["globio"].pyname,
|
||||
"userguide_html": MODEL_METADATA["globio"].userguide,
|
||||
"args_with_spatial_overlap": {
|
||||
"spatial_keys": [
|
||||
"lulc_path", "pasture_path", "potential_vegetation_path",
|
||||
|
|
|
@ -14,6 +14,7 @@ from . import utils
|
|||
from . import spec_utils
|
||||
from .spec_utils import u
|
||||
from . import validation
|
||||
from . import MODEL_METADATA
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -22,9 +23,9 @@ MISSING_SENSITIVITY_TABLE_THREATS_MSG = (
|
|||
'Sensitivity columns: %s') # (set of missing threats, set of found columns)
|
||||
|
||||
ARGS_SPEC = {
|
||||
"model_name": _("Habitat Quality"),
|
||||
"module": __name__,
|
||||
"userguide_html": "habitat_quality.html",
|
||||
"model_name": MODEL_METADATA["habitat_quality"].model_title,
|
||||
"pyname": MODEL_METADATA["habitat_quality"].pyname,
|
||||
"userguide_html": MODEL_METADATA["habitat_quality"].userguide,
|
||||
"args_with_spatial_overlap": {
|
||||
"spatial_keys": [
|
||||
"lulc_cur_path", "lulc_fut_path", "lulc_bas_path",
|
||||
|
@ -442,7 +443,7 @@ def execute(args):
|
|||
task_name='access_raster')
|
||||
access_task_list = [create_access_raster_task]
|
||||
|
||||
if 'access_vector_path' in args:
|
||||
if 'access_vector_path' in args and args['access_vector_path']:
|
||||
LOGGER.debug("Rasterize Access vector")
|
||||
rasterize_access_task = task_graph.add_task(
|
||||
func=pygeoprocessing.rasterize,
|
||||
|
|
|
@ -18,6 +18,7 @@ from . import utils
|
|||
from . import spec_utils
|
||||
from .spec_utils import u
|
||||
from . import validation
|
||||
from . import MODEL_METADATA
|
||||
|
||||
|
||||
LOGGER = logging.getLogger('natcap.invest.hra')
|
||||
|
@ -66,9 +67,9 @@ _DEFAULT_GTIFF_CREATION_OPTIONS = (
|
|||
'BLOCKXSIZE=256', 'BLOCKYSIZE=256')
|
||||
|
||||
ARGS_SPEC = {
|
||||
"model_name": _("Habitat Risk Assessment"),
|
||||
"module": __name__,
|
||||
"userguide_html": "habitat_risk_assessment.html",
|
||||
"model_name": MODEL_METADATA["habitat_risk_assessment"].model_title,
|
||||
"pyname": MODEL_METADATA["habitat_risk_assessment"].pyname,
|
||||
"userguide_html": MODEL_METADATA["habitat_risk_assessment"].userguide,
|
||||
"args": {
|
||||
"workspace_dir": spec_utils.WORKSPACE,
|
||||
"results_suffix": spec_utils.SUFFIX,
|
||||
|
|
|
@ -14,14 +14,15 @@ from .. import utils
|
|||
from .. import spec_utils
|
||||
from ..spec_utils import u
|
||||
from .. import validation
|
||||
from .. import MODEL_METADATA
|
||||
from . import ndr_core
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
||||
ARGS_SPEC = {
|
||||
"model_name": _("Nutrient Delivery Ratio Model (NDR)"),
|
||||
"module": __name__,
|
||||
"userguide_html": "ndr.html",
|
||||
"model_name": MODEL_METADATA["ndr"].model_title,
|
||||
"pyname": MODEL_METADATA["ndr"].pyname,
|
||||
"userguide_html": MODEL_METADATA["ndr"].userguide,
|
||||
"args_with_spatial_overlap": {
|
||||
"spatial_keys": ["dem_path", "lulc_path", "runoff_proxy_path",
|
||||
"watersheds_path"],
|
||||
|
@ -116,8 +117,8 @@ ARGS_SPEC = {
|
|||
},
|
||||
"calc_p": {
|
||||
"type": "boolean",
|
||||
"about": _("Select to calculate phosphorous export."),
|
||||
"name": _("Calculate phosphorous retention")
|
||||
"about": _("Select to calculate phosphorus export."),
|
||||
"name": _("Calculate phosphorus retention")
|
||||
},
|
||||
"calc_n": {
|
||||
"type": "boolean",
|
||||
|
@ -165,7 +166,7 @@ ARGS_SPEC = {
|
|||
"type": "number",
|
||||
"units": u.meter,
|
||||
"required": "calc_p",
|
||||
"name": _("Subsurface Critical Length (Phosphorous)"),
|
||||
"name": _("Subsurface Critical Length (Phosphorus)"),
|
||||
"about": _(
|
||||
"The distance (traveled subsurface and downslope) after which "
|
||||
"it is assumed that soil retains nutrient at its maximum "
|
||||
|
@ -188,7 +189,7 @@ ARGS_SPEC = {
|
|||
"subsurface_eff_p": {
|
||||
"type": "ratio",
|
||||
"required": "calc_p",
|
||||
"name": _("Subsurface Maximum Retention Efficiency (Phosphorous)"),
|
||||
"name": _("Subsurface Maximum Retention Efficiency (Phosphorus)"),
|
||||
"about": _(
|
||||
"The maximum nutrient retention efficiency that can be "
|
||||
"reached through subsurface flow. This field characterizes "
|
||||
|
@ -282,7 +283,7 @@ def execute(args):
|
|||
If args['calc_n'] is True, must also contain the header
|
||||
'proportion_subsurface_n' field.
|
||||
|
||||
args['calc_p'] (boolean): if True, phosphorous is modeled,
|
||||
args['calc_p'] (boolean): if True, phosphorus is modeled,
|
||||
additionally if True then biophysical table must have p fields in
|
||||
them
|
||||
args['calc_n'] (boolean): if True nitrogen will be modeled,
|
||||
|
@ -348,7 +349,7 @@ def execute(args):
|
|||
"""
|
||||
# Make sure all the nutrient inputs are good
|
||||
if len(nutrients_to_process) == 0:
|
||||
raise ValueError("Neither phosphorous nor nitrogen was selected"
|
||||
raise ValueError("Neither phosphorus nor nitrogen was selected"
|
||||
" to be processed. Choose at least one.")
|
||||
|
||||
# Build up a list that'll let us iterate through all the input tables
|
||||
|
@ -371,7 +372,7 @@ def execute(args):
|
|||
"Missing header %s from %s" % (
|
||||
header, table_type))
|
||||
|
||||
# proportion_subsurface_n is a special case in which phosphorous does
|
||||
# proportion_subsurface_n is a special case in which phosphorus does
|
||||
# not have an equivalent.
|
||||
if ('n' in nutrients_to_process and
|
||||
'proportion_subsurface_n' not in lu_parameter_row):
|
||||
|
|
|
@ -17,13 +17,14 @@ from . import utils
|
|||
from . import spec_utils
|
||||
from .spec_utils import u
|
||||
from . import validation
|
||||
from . import MODEL_METADATA
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
||||
ARGS_SPEC = {
|
||||
"model_name": _("Crop Pollination"),
|
||||
"module": __name__,
|
||||
"userguide_html": "croppollination.html",
|
||||
"model_name": MODEL_METADATA["pollination"].model_title,
|
||||
"pyname": MODEL_METADATA["pollination"].pyname,
|
||||
"userguide_html": MODEL_METADATA["pollination"].userguide,
|
||||
"args": {
|
||||
"workspace_dir": spec_utils.WORKSPACE,
|
||||
"results_suffix": spec_utils.SUFFIX,
|
||||
|
|
|
@ -34,6 +34,7 @@ from .. import utils
|
|||
from .. import spec_utils
|
||||
from ..spec_utils import u
|
||||
from .. import validation
|
||||
from .. import MODEL_METADATA
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -88,9 +89,9 @@ predictor_table_columns = {
|
|||
|
||||
|
||||
ARGS_SPEC = {
|
||||
"model_name": _("Recreation Model"),
|
||||
"module": __name__,
|
||||
"userguide_html": "recreation.html",
|
||||
"model_name": MODEL_METADATA["recreation"].model_title,
|
||||
"pyname": MODEL_METADATA["recreation"].pyname,
|
||||
"userguide_html": MODEL_METADATA["recreation"].userguide,
|
||||
"args": {
|
||||
"workspace_dir": spec_utils.WORKSPACE,
|
||||
"results_suffix": spec_utils.SUFFIX,
|
||||
|
|
|
@ -12,13 +12,14 @@ from . import utils
|
|||
from . import spec_utils
|
||||
from .spec_utils import u
|
||||
from . import validation
|
||||
from . import MODEL_METADATA
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
||||
ARGS_SPEC = {
|
||||
"model_name": _("RouteDEM"),
|
||||
"module": __name__,
|
||||
"userguide_html": "routedem.html",
|
||||
"model_name": MODEL_METADATA["routedem"].model_title,
|
||||
"pyname": MODEL_METADATA["routedem"].pyname,
|
||||
"userguide_html": MODEL_METADATA["routedem"].userguide,
|
||||
"args": {
|
||||
"workspace_dir": spec_utils.WORKSPACE,
|
||||
"results_suffix": spec_utils.SUFFIX,
|
||||
|
|
|
@ -20,13 +20,14 @@ from . import utils
|
|||
from . import spec_utils
|
||||
from .spec_utils import u
|
||||
from . import validation
|
||||
from . import MODEL_METADATA
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
||||
ARGS_SPEC = {
|
||||
"model_name": _("Scenario Generator: Proximity Based"),
|
||||
"module": __name__,
|
||||
"userguide_html": "scenario_gen_proximity.html",
|
||||
"model_name": MODEL_METADATA["scenario_generator_proximity"].model_title,
|
||||
"pyname": MODEL_METADATA["scenario_generator_proximity"].pyname,
|
||||
"userguide_html": MODEL_METADATA["scenario_generator_proximity"].userguide,
|
||||
"args": {
|
||||
"workspace_dir": spec_utils.WORKSPACE,
|
||||
"results_suffix": spec_utils.SUFFIX,
|
||||
|
|
|
@ -19,6 +19,7 @@ from .. import utils
|
|||
from .. import spec_utils
|
||||
from ..spec_utils import u
|
||||
from .. import validation
|
||||
from .. import MODEL_METADATA
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
_VALUATION_NODATA = -99999 # largish negative nodata value.
|
||||
|
@ -47,9 +48,9 @@ _INTERMEDIATE_BASE_FILES = {
|
|||
|
||||
|
||||
ARGS_SPEC = {
|
||||
"model_name": _("Unobstructed Views: Scenic Quality Provision"),
|
||||
"module": __name__,
|
||||
"userguide_html": "scenic_quality.html",
|
||||
"model_name": MODEL_METADATA["scenic_quality"].model_title,
|
||||
"pyname": MODEL_METADATA["scenic_quality"].pyname,
|
||||
"userguide_html": MODEL_METADATA["scenic_quality"].userguide,
|
||||
"args_with_spatial_overlap": {
|
||||
"spatial_keys": ["aoi_path", "structure_path", "dem_path"],
|
||||
"different_projections_ok": True,
|
||||
|
|
|
@ -19,14 +19,15 @@ from .. import utils
|
|||
from .. import spec_utils
|
||||
from ..spec_utils import u
|
||||
from .. import validation
|
||||
from .. import MODEL_METADATA
|
||||
from . import sdr_core
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
||||
ARGS_SPEC = {
|
||||
"model_name": _("Sediment Delivery Ratio Model (SDR)"),
|
||||
"module": __name__,
|
||||
"userguide_html": "sdr.html",
|
||||
"model_name": MODEL_METADATA["sdr"].model_title,
|
||||
"pyname": MODEL_METADATA["sdr"].pyname,
|
||||
"userguide_html": MODEL_METADATA["sdr"].userguide,
|
||||
"args_with_spatial_overlap": {
|
||||
"spatial_keys": ["dem_path", "erosivity_path", "erodibility_path",
|
||||
"lulc_path", "drainage_path", "watersheds_path", ],
|
||||
|
|
|
@ -17,6 +17,7 @@ from .. import utils
|
|||
from .. import spec_utils
|
||||
from ..spec_utils import u
|
||||
from .. import validation
|
||||
from .. import MODEL_METADATA
|
||||
|
||||
from . import seasonal_water_yield_core
|
||||
|
||||
|
@ -31,13 +32,13 @@ MONTH_ID_TO_LABEL = [
|
|||
'nov', 'dec']
|
||||
|
||||
ARGS_SPEC = {
|
||||
"model_name": _("Seasonal Water Yield"),
|
||||
"module": __name__,
|
||||
"userguide_html": "seasonal_water_yield.html",
|
||||
"model_name": MODEL_METADATA["seasonal_water_yield"].model_title,
|
||||
"pyname": MODEL_METADATA["seasonal_water_yield"].pyname,
|
||||
"userguide_html": MODEL_METADATA["seasonal_water_yield"].userguide,
|
||||
"args_with_spatial_overlap": {
|
||||
"spatial_keys": ["dem_raster_path", "lulc_raster_path",
|
||||
"soil_group_path", "aoi_path", "l_path",
|
||||
"monthly_alpha_path"],
|
||||
"climate_zone_raster_path"],
|
||||
"different_projections_ok": True,
|
||||
},
|
||||
"args": {
|
||||
|
@ -245,7 +246,7 @@ ARGS_SPEC = {
|
|||
"Values are the numbers 1-12 corresponding to each "
|
||||
"month.")
|
||||
},
|
||||
"events": {
|
||||
"alpha": {
|
||||
"type": "number",
|
||||
"units": u.none,
|
||||
"about": _("The alpha value for that month")
|
||||
|
|
|
@ -12,6 +12,7 @@ from . import spec_utils
|
|||
from .spec_utils import u
|
||||
from . import utils
|
||||
from . import validation
|
||||
from . import MODEL_METADATA
|
||||
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
@ -22,9 +23,9 @@ UINT8_NODATA = 255
|
|||
UINT16_NODATA = 65535
|
||||
|
||||
ARGS_SPEC = {
|
||||
"model_name": _("Stormwater Retention"),
|
||||
"module": __name__,
|
||||
"userguide_html": "stormwater.html",
|
||||
"model_name": MODEL_METADATA["stormwater"].model_title,
|
||||
"pyname": MODEL_METADATA["stormwater"].pyname,
|
||||
"userguide_html": MODEL_METADATA["stormwater"].userguide,
|
||||
"args_with_spatial_overlap": {
|
||||
"spatial_keys": ["lulc_path", "soil_group_path", "precipitation_path",
|
||||
"road_centerlines_path", "aggregate_areas_path"],
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
# coding=UTF-8
|
||||
|
||||
from natcap.invest.ui import model, inputs
|
||||
from natcap.invest.hydropower import hydropower_water_yield
|
||||
from natcap.invest import annual_water_yield, MODEL_METADATA
|
||||
|
||||
|
||||
class HydropowerWaterYield(model.InVESTModel):
|
||||
class AnnualWaterYield(model.InVESTModel):
|
||||
def __init__(self):
|
||||
model.InVESTModel.__init__(
|
||||
self,
|
||||
label='Hydropower Water Yield',
|
||||
target=hydropower_water_yield.execute,
|
||||
validator=hydropower_water_yield.validate,
|
||||
localdoc='reservoirhydropowerproduction.html')
|
||||
label=MODEL_METADATA['annual_water_yield'].model_title,
|
||||
target=annual_water_yield.execute,
|
||||
validator=annual_water_yield.validate,
|
||||
localdoc=MODEL_METADATA['annual_water_yield'].userguide)
|
||||
|
||||
self.precipitation = inputs.File(
|
||||
args_key='precipitation_path',
|
|
@ -1,16 +1,17 @@
|
|||
# coding=UTF-8
|
||||
|
||||
from natcap.invest.ui import model, inputs
|
||||
import natcap.invest.carbon
|
||||
from natcap.invest import carbon, MODEL_METADATA
|
||||
|
||||
|
||||
class Carbon(model.InVESTModel):
|
||||
def __init__(self):
|
||||
model.InVESTModel.__init__(self,
|
||||
label=_('InVEST Carbon Model'),
|
||||
target=natcap.invest.carbon.execute,
|
||||
validator=natcap.invest.carbon.validate,
|
||||
localdoc='carbonstorage.html')
|
||||
model.InVESTModel.__init__(
|
||||
self,
|
||||
label=MODEL_METADATA['carbon'].model_title,
|
||||
target=carbon.execute,
|
||||
validator=carbon.validate,
|
||||
localdoc=MODEL_METADATA['carbon'].userguide)
|
||||
|
||||
self.cur_lulc_raster = inputs.File(
|
||||
args_key='lulc_cur_path',
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
import functools
|
||||
|
||||
from natcap.invest.ui import model, inputs
|
||||
from natcap.invest.coastal_blue_carbon import coastal_blue_carbon
|
||||
from natcap.invest.coastal_blue_carbon import preprocessor
|
||||
from natcap.invest.coastal_blue_carbon import coastal_blue_carbon, preprocessor
|
||||
from natcap.invest import MODEL_METADATA
|
||||
|
||||
|
||||
def _create_input_kwargs_from_args_spec(
|
||||
|
@ -35,10 +35,10 @@ class CoastalBlueCarbonPreprocessor(model.InVESTModel):
|
|||
def __init__(self):
|
||||
model.InVESTModel.__init__(
|
||||
self,
|
||||
label='Coastal Blue Carbon Preprocessor',
|
||||
label=MODEL_METADATA['coastal_blue_carbon_preprocessor'].model_title,
|
||||
target=preprocessor.execute,
|
||||
validator=preprocessor.validate,
|
||||
localdoc='coastal_blue_carbon.html')
|
||||
localdoc=MODEL_METADATA['coastal_blue_carbon_preprocessor'].userguide)
|
||||
|
||||
_ui_keys = functools.partial(
|
||||
_create_input_kwargs_from_args_spec,
|
||||
|
@ -68,10 +68,10 @@ class CoastalBlueCarbon(model.InVESTModel):
|
|||
def __init__(self):
|
||||
model.InVESTModel.__init__(
|
||||
self,
|
||||
label='Coastal Blue Carbon',
|
||||
label=MODEL_METADATA['coastal_blue_carbon'].model_title,
|
||||
target=coastal_blue_carbon.execute,
|
||||
validator=coastal_blue_carbon.validate,
|
||||
localdoc='coastal_blue_carbon.html')
|
||||
localdoc=MODEL_METADATA['coastal_blue_carbon'].userguide)
|
||||
|
||||
_ui_keys = functools.partial(
|
||||
_create_input_kwargs_from_args_spec,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# coding=UTF-8
|
||||
|
||||
from natcap.invest.ui import model, inputs
|
||||
from natcap.invest import coastal_vulnerability
|
||||
from natcap.invest import coastal_vulnerability, MODEL_METADATA
|
||||
|
||||
from osgeo import gdal
|
||||
|
||||
|
@ -10,10 +10,10 @@ class CoastalVulnerability(model.InVESTModel):
|
|||
def __init__(self):
|
||||
model.InVESTModel.__init__(
|
||||
self,
|
||||
label='Coastal Vulnerability',
|
||||
label=MODEL_METADATA['coastal_vulnerability'].model_title,
|
||||
target=coastal_vulnerability.execute,
|
||||
validator=coastal_vulnerability.validate,
|
||||
localdoc='coastal_vulnerability.html')
|
||||
localdoc=MODEL_METADATA['coastal_vulnerability'].userguide)
|
||||
|
||||
self.aoi_vector_path = inputs.File(
|
||||
args_key='aoi_vector_path',
|
||||
|
|
|
@ -3,16 +3,17 @@ from natcap.invest.ui import model, inputs
|
|||
|
||||
import natcap.invest.crop_production_percentile
|
||||
import natcap.invest.crop_production_regression
|
||||
from natcap.invest import MODEL_METADATA
|
||||
|
||||
|
||||
class CropProductionPercentile(model.InVESTModel):
|
||||
def __init__(self):
|
||||
model.InVESTModel.__init__(
|
||||
self,
|
||||
label='Crop Production Percentile Model',
|
||||
label=MODEL_METADATA['crop_production_percentile'].model_title,
|
||||
target=natcap.invest.crop_production_percentile.execute,
|
||||
validator=natcap.invest.crop_production_percentile.validate,
|
||||
localdoc='crop_production.html')
|
||||
localdoc=MODEL_METADATA['crop_production_percentile'].userguide)
|
||||
|
||||
self.model_data_path = inputs.Folder(
|
||||
args_key='model_data_path',
|
||||
|
@ -107,10 +108,10 @@ class CropProductionRegression(model.InVESTModel):
|
|||
def __init__(self):
|
||||
model.InVESTModel.__init__(
|
||||
self,
|
||||
label='Crop Production Regression Model',
|
||||
label=MODEL_METADATA['crop_production_regression'].model_title,
|
||||
target=natcap.invest.crop_production_regression.execute,
|
||||
validator=natcap.invest.crop_production_regression.validate,
|
||||
localdoc='crop_production.html')
|
||||
localdoc=MODEL_METADATA['crop_production_regression'].userguide)
|
||||
|
||||
self.model_data_path = inputs.Folder(
|
||||
args_key='model_data_path',
|
||||
|
@ -151,7 +152,7 @@ class CropProductionRegression(model.InVESTModel):
|
|||
helptext=(
|
||||
"A table that maps fertilization rates to crops in "
|
||||
"the simulation. Must include the headers "
|
||||
"'crop_name', 'nitrogen_rate', 'phosphorous_rate', "
|
||||
"'crop_name', 'nitrogen_rate', 'phosphorus_rate', "
|
||||
"and 'potassium_rate'."),
|
||||
label='Fertilization Rate Table Path (csv)',
|
||||
validator=self.validator)
|
||||
|
|
|
@ -2,16 +2,17 @@
|
|||
|
||||
from natcap.invest.ui import model, inputs
|
||||
from natcap.invest.delineateit import delineateit
|
||||
from natcap.invest import MODEL_METADATA
|
||||
|
||||
|
||||
class Delineateit(model.InVESTModel):
|
||||
def __init__(self):
|
||||
model.InVESTModel.__init__(
|
||||
self,
|
||||
label='DelineateIt: Watershed Delineation',
|
||||
label=MODEL_METADATA['delineateit'].model_title,
|
||||
target=delineateit.execute,
|
||||
validator=delineateit.validate,
|
||||
localdoc='delineateit.html')
|
||||
localdoc=MODEL_METADATA['delineateit'].userguide)
|
||||
|
||||
self.dem_path = inputs.File(
|
||||
label='Digital Elevation Model (Raster)',
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
from natcap.invest.ui import model, inputs
|
||||
from natcap.invest.finfish_aquaculture import finfish_aquaculture
|
||||
from natcap.invest import MODEL_METADATA
|
||||
|
||||
from osgeo import gdal
|
||||
|
||||
|
@ -10,10 +11,10 @@ class FinfishAquaculture(model.InVESTModel):
|
|||
def __init__(self):
|
||||
model.InVESTModel.__init__(
|
||||
self,
|
||||
label='Marine Aquaculture: Finfish',
|
||||
label=MODEL_METADATA['finfish_aquaculture'].model_title,
|
||||
target=finfish_aquaculture.execute,
|
||||
validator=finfish_aquaculture.validate,
|
||||
localdoc='marine_fish.html')
|
||||
localdoc=MODEL_METADATA['finfish_aquaculture'].userguide)
|
||||
|
||||
self.farm_location = inputs.File(
|
||||
args_key='ff_farm_loc',
|
||||
|
|
|
@ -2,16 +2,17 @@
|
|||
|
||||
from natcap.invest.ui import model, inputs
|
||||
from natcap.invest.fisheries import fisheries, fisheries_hst
|
||||
from natcap.invest import MODEL_METADATA
|
||||
|
||||
|
||||
class Fisheries(model.InVESTModel):
|
||||
def __init__(self):
|
||||
model.InVESTModel.__init__(
|
||||
self,
|
||||
label='Fisheries',
|
||||
label=MODEL_METADATA['fisheries'].model_title,
|
||||
target=fisheries.execute,
|
||||
validator=fisheries.validate,
|
||||
localdoc='fisheries.html')
|
||||
localdoc=MODEL_METADATA['fisheries'].userguide)
|
||||
|
||||
self.alpha_only = inputs.Label(
|
||||
text=(
|
||||
|
@ -315,10 +316,10 @@ class FisheriesHST(model.InVESTModel):
|
|||
def __init__(self):
|
||||
model.InVESTModel.__init__(
|
||||
self,
|
||||
label='Fisheries Habitat Scenario Tool',
|
||||
label=MODEL_METADATA['fisheries_hst'].model_title,
|
||||
target=fisheries_hst.execute,
|
||||
validator=fisheries_hst.validate,
|
||||
localdoc='fisheries.html')
|
||||
localdoc=MODEL_METADATA['fisheries_hst'].userguide)
|
||||
|
||||
self.alpha_only = inputs.Label(
|
||||
text=(
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
# coding=UTF-8
|
||||
|
||||
from natcap.invest.ui import model, inputs
|
||||
import natcap.invest.forest_carbon_edge_effect
|
||||
from natcap.invest import forest_carbon_edge_effect, MODEL_METADATA
|
||||
|
||||
|
||||
class ForestCarbonEdgeEffect(model.InVESTModel):
|
||||
def __init__(self):
|
||||
model.InVESTModel.__init__(
|
||||
self,
|
||||
label='Forest Carbon Edge Effect Model',
|
||||
target=natcap.invest.forest_carbon_edge_effect.execute,
|
||||
validator=natcap.invest.forest_carbon_edge_effect.validate,
|
||||
localdoc=natcap.invest.forest_carbon_edge_effect.ARGS_SPEC['userguide_html'])
|
||||
label=MODEL_METADATA['forest_carbon_edge_effect'].model_title,
|
||||
target=forest_carbon_edge_effect.execute,
|
||||
validator=forest_carbon_edge_effect.validate,
|
||||
localdoc=MODEL_METADATA['forest_carbon_edge_effect'].userguide)
|
||||
|
||||
self.lulc_raster_path = inputs.File(
|
||||
args_key='lulc_raster_path',
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
# coding=UTF-8
|
||||
|
||||
from natcap.invest.ui import model, inputs
|
||||
import natcap.invest.globio
|
||||
from natcap.invest import globio, MODEL_METADATA
|
||||
|
||||
|
||||
class GLOBIO(model.InVESTModel):
|
||||
def __init__(self):
|
||||
model.InVESTModel.__init__(
|
||||
self,
|
||||
label='GLOBIO',
|
||||
target=natcap.invest.globio.execute,
|
||||
validator=natcap.invest.globio.validate,
|
||||
localdoc='globio.html')
|
||||
label=MODEL_METADATA['globio'].model_title,
|
||||
target=globio.execute,
|
||||
validator=globio.validate,
|
||||
localdoc=MODEL_METADATA['globio'].userguide)
|
||||
|
||||
self.lulc_to_globio_table_path = inputs.File(
|
||||
args_key='lulc_to_globio_table_path',
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
# coding=UTF-8
|
||||
|
||||
from natcap.invest.ui import model, inputs
|
||||
import natcap.invest.habitat_quality
|
||||
from natcap.invest import habitat_quality, MODEL_METADATA
|
||||
|
||||
|
||||
class HabitatQuality(model.InVESTModel):
|
||||
def __init__(self):
|
||||
model.InVESTModel.__init__(
|
||||
self,
|
||||
label='Habitat Quality',
|
||||
target=natcap.invest.habitat_quality.execute,
|
||||
validator=natcap.invest.habitat_quality.validate,
|
||||
localdoc='habitat_quality.html')
|
||||
label=MODEL_METADATA['habitat_quality'].model_title,
|
||||
target=habitat_quality.execute,
|
||||
validator=habitat_quality.validate,
|
||||
localdoc=MODEL_METADATA['habitat_quality'].userguide)
|
||||
self.current_landcover = inputs.File(
|
||||
args_key='lulc_cur_path',
|
||||
helptext=(
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
# coding=UTF-8
|
||||
from natcap.invest.ui import model, inputs
|
||||
from natcap.invest import hra
|
||||
from natcap.invest import hra, MODEL_METADATA
|
||||
|
||||
|
||||
class HabitatRiskAssessment(model.InVESTModel):
|
||||
def __init__(self):
|
||||
model.InVESTModel.__init__(
|
||||
self,
|
||||
label='Habitat Risk Assessment',
|
||||
label=MODEL_METADATA['habitat_risk_assessment'].model_title,
|
||||
target=hra.execute,
|
||||
validator=hra.validate,
|
||||
localdoc='habitat_risk_assessment.html')
|
||||
localdoc=MODEL_METADATA['habitat_risk_assessment'].userguide)
|
||||
|
||||
self.info_table_path = inputs.File(
|
||||
args_key='info_table_path',
|
||||
|
|
|
@ -57,14 +57,16 @@ def main():
|
|||
scroll_area.setWidget(main_widget)
|
||||
|
||||
labels_and_buttons = []
|
||||
for model, model_data in sorted(natcap.invest.MODEL_UIS.items()):
|
||||
for model_name, model_data in sorted(natcap.invest.MODEL_METADATA.items(),
|
||||
# sort alphabetically by display name
|
||||
key=lambda item: item[1].model_title):
|
||||
row = layout.rowCount()
|
||||
label = QtWidgets.QLabel()
|
||||
button = ModelLaunchButton('Launch', model)
|
||||
button = ModelLaunchButton('Launch', model_name)
|
||||
labels_and_buttons.append((label, button))
|
||||
|
||||
layout.addWidget(
|
||||
QtWidgets.QLabel(model_data.humanname), row, 0,
|
||||
QtWidgets.QLabel(model_data.model_title), row, 0,
|
||||
QtCore.Qt.AlignRight)
|
||||
layout.addWidget(button, row, 1)
|
||||
|
||||
|
|
|
@ -27,11 +27,11 @@ import qtawesome
|
|||
import natcap.invest
|
||||
|
||||
from . import inputs
|
||||
from . import usage
|
||||
from . import execution
|
||||
from .. import cli, MODEL_UIS
|
||||
from .. import utils
|
||||
from .. import cli, MODEL_METADATA, utils
|
||||
from .. import datastack
|
||||
from .. import usage
|
||||
from .. import utils
|
||||
from .. import validation
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
@ -1970,7 +1970,7 @@ class InVESTModel(QtWidgets.QMainWindow):
|
|||
else:
|
||||
save_filepath = filepath
|
||||
|
||||
for internal_model_name, _meta in MODEL_UIS.items():
|
||||
for internal_model_name, _meta in MODEL_METADATA.items():
|
||||
if _meta.pyname == self.target.__module__:
|
||||
break
|
||||
cli.export_to_python(
|
||||
|
|
|
@ -2,16 +2,17 @@
|
|||
|
||||
from natcap.invest.ui import model, inputs
|
||||
import natcap.invest.ndr.ndr
|
||||
from natcap.invest import MODEL_METADATA
|
||||
|
||||
|
||||
class Nutrient(model.InVESTModel):
|
||||
def __init__(self):
|
||||
model.InVESTModel.__init__(
|
||||
self,
|
||||
label='Nutrient Delivery Ratio Model (NDR)',
|
||||
label=MODEL_METADATA['ndr'].model_title,
|
||||
target=natcap.invest.ndr.ndr.execute,
|
||||
validator=natcap.invest.ndr.ndr.validate,
|
||||
localdoc='ndr.html')
|
||||
localdoc=MODEL_METADATA['ndr'].userguide)
|
||||
|
||||
self.dem_path = inputs.File(
|
||||
args_key='dem_path',
|
||||
|
@ -70,8 +71,8 @@ class Nutrient(model.InVESTModel):
|
|||
self.add_input(self.biophysical_table_path)
|
||||
self.calc_p = inputs.Checkbox(
|
||||
args_key='calc_p',
|
||||
helptext='Select to calculate phosphorous export.',
|
||||
label='Calculate phosphorous retention')
|
||||
helptext='Select to calculate phosphorus export.',
|
||||
label='Calculate phosphorus retention')
|
||||
self.add_input(self.calc_p)
|
||||
self.calc_n = inputs.Checkbox(
|
||||
args_key='calc_n',
|
||||
|
@ -106,7 +107,7 @@ class Nutrient(model.InVESTModel):
|
|||
args_key='subsurface_critical_length_p',
|
||||
helptext='',
|
||||
interactive=False,
|
||||
label='Subsurface Critical Length (Phosphorous)',
|
||||
label='Subsurface Critical Length (Phosphorus)',
|
||||
validator=self.validator)
|
||||
self.add_input(self.subsurface_critical_length_p)
|
||||
self.subsurface_eff_n = inputs.Text(
|
||||
|
@ -120,7 +121,7 @@ class Nutrient(model.InVESTModel):
|
|||
args_key='subsurface_eff_p',
|
||||
helptext='',
|
||||
interactive=False,
|
||||
label='Subsurface Maximum Retention Efficiency (Phosphorous)',
|
||||
label='Subsurface Maximum Retention Efficiency (Phosphorus)',
|
||||
validator=self.validator)
|
||||
self.add_input(self.subsurface_eff_p)
|
||||
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
#TODO: all the other UI modules have a # coding=UTF-8 here, does this one need it too?
|
||||
import logging
|
||||
|
||||
from . import inputs
|
||||
from . import model
|
||||
from .. import pollination
|
||||
from natcap.invest.ui import inputs, model
|
||||
from natcap.invest import pollination, MODEL_METADATA
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -12,10 +10,10 @@ class Pollination(model.InVESTModel):
|
|||
def __init__(self):
|
||||
model.InVESTModel.__init__(
|
||||
self,
|
||||
label='Crop Pollination',
|
||||
label=MODEL_METADATA['pollination'].model_title,
|
||||
target=pollination.execute,
|
||||
validator=pollination.validate,
|
||||
localdoc='croppollination.html')
|
||||
localdoc=MODEL_METADATA['pollination'].userguide)
|
||||
|
||||
self.landcover_raster_path = inputs.File(
|
||||
args_key='landcover_raster_path',
|
||||
|
|
|
@ -2,16 +2,17 @@
|
|||
|
||||
from natcap.invest.ui import model, inputs
|
||||
from natcap.invest.recreation import recmodel_client
|
||||
from natcap.invest import MODEL_METADATA
|
||||
|
||||
|
||||
class Recreation(model.InVESTModel):
|
||||
def __init__(self):
|
||||
model.InVESTModel.__init__(
|
||||
self,
|
||||
label='Recreation Model',
|
||||
label=MODEL_METADATA['recreation'].model_title,
|
||||
target=recmodel_client.execute,
|
||||
validator=recmodel_client.validate,
|
||||
localdoc='recreation.html')
|
||||
localdoc=MODEL_METADATA['recreation'].userguide)
|
||||
|
||||
self.internet_warning = inputs.Label(
|
||||
text=(
|
||||
|
|
|
@ -1,16 +1,17 @@
|
|||
# coding=UTF-8
|
||||
|
||||
from natcap.invest.ui import model, inputs
|
||||
from natcap.invest import routedem
|
||||
from natcap.invest import routedem, MODEL_METADATA
|
||||
|
||||
|
||||
class RouteDEM(model.InVESTModel):
|
||||
def __init__(self):
|
||||
model.InVESTModel.__init__(
|
||||
self,
|
||||
label='RouteDEM',
|
||||
label=MODEL_METADATA['routedem'].model_title,
|
||||
target=routedem.execute,
|
||||
validator=routedem.validate,
|
||||
localdoc='routedem.html')
|
||||
localdoc=MODEL_METADATA['routedem'].userguide)
|
||||
|
||||
self.dem_path = inputs.File(
|
||||
args_key='dem_path',
|
||||
|
|
|
@ -2,9 +2,8 @@
|
|||
import logging
|
||||
|
||||
from natcap.invest.ui import model, inputs
|
||||
import natcap.invest.scenario_gen_proximity
|
||||
from natcap.invest import scenario_gen_proximity, MODEL_METADATA
|
||||
|
||||
from osgeo import gdal
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -13,10 +12,10 @@ class ScenarioGenProximity(model.InVESTModel):
|
|||
def __init__(self):
|
||||
model.InVESTModel.__init__(
|
||||
self,
|
||||
label='Scenario Generator: Proximity Based',
|
||||
target=natcap.invest.scenario_gen_proximity.execute,
|
||||
validator=natcap.invest.scenario_gen_proximity.validate,
|
||||
localdoc='scenario_gen_proximity.html')
|
||||
label=MODEL_METADATA['scenario_generator_proximity'].model_title,
|
||||
target=scenario_gen_proximity.execute,
|
||||
validator=scenario_gen_proximity.validate,
|
||||
localdoc=MODEL_METADATA['scenario_generator_proximity'].userguide)
|
||||
|
||||
self.base_lulc_path = inputs.File(
|
||||
args_key='base_lulc_path',
|
||||
|
|
|
@ -2,16 +2,17 @@
|
|||
|
||||
from natcap.invest.ui import model, inputs
|
||||
from natcap.invest.scenic_quality import scenic_quality
|
||||
from natcap.invest import MODEL_METADATA
|
||||
|
||||
|
||||
class ScenicQuality(model.InVESTModel):
|
||||
def __init__(self):
|
||||
model.InVESTModel.__init__(
|
||||
self,
|
||||
label='Scenic Quality',
|
||||
label=MODEL_METADATA['scenic_quality'].model_title,
|
||||
target=scenic_quality.execute,
|
||||
validator=scenic_quality.validate,
|
||||
localdoc='scenic_quality.html')
|
||||
localdoc=MODEL_METADATA['scenic_quality'].userguide)
|
||||
|
||||
self.general_tab = inputs.Container(
|
||||
interactive=True,
|
||||
|
|
|
@ -2,16 +2,17 @@
|
|||
|
||||
from natcap.invest.ui import model, inputs
|
||||
import natcap.invest.sdr.sdr
|
||||
from natcap.invest import MODEL_METADATA
|
||||
|
||||
|
||||
class SDR(model.InVESTModel):
|
||||
def __init__(self):
|
||||
model.InVESTModel.__init__(
|
||||
self,
|
||||
label='Sediment Delivery Ratio Model (SDR)',
|
||||
label=MODEL_METADATA['sdr'].model_title,
|
||||
target=natcap.invest.sdr.sdr.execute,
|
||||
validator=natcap.invest.sdr.sdr.validate,
|
||||
localdoc='sdr.html')
|
||||
localdoc=MODEL_METADATA['sdr'].userguide)
|
||||
self.dem_path = inputs.File(
|
||||
args_key='dem_path',
|
||||
helptext=(
|
||||
|
|
|
@ -2,16 +2,17 @@
|
|||
|
||||
from natcap.invest.ui import model, inputs
|
||||
from natcap.invest.seasonal_water_yield import seasonal_water_yield
|
||||
from natcap.invest import MODEL_METADATA
|
||||
|
||||
|
||||
class SeasonalWaterYield(model.InVESTModel):
|
||||
def __init__(self):
|
||||
model.InVESTModel.__init__(
|
||||
self,
|
||||
label='Seasonal Water Yield',
|
||||
label=MODEL_METADATA['seasonal_water_yield'].model_title,
|
||||
target=seasonal_water_yield.execute,
|
||||
validator=seasonal_water_yield.validate,
|
||||
localdoc='seasonal_water_yield.html')
|
||||
localdoc=MODEL_METADATA['seasonal_water_yield'].userguide)
|
||||
|
||||
self.threshold_flow_accumulation = inputs.Text(
|
||||
args_key='threshold_flow_accumulation',
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
from natcap.invest.ui import model, inputs
|
||||
import natcap.invest.stormwater
|
||||
from natcap.invest import MODEL_METADATA, stormwater
|
||||
|
||||
|
||||
class Stormwater(model.InVESTModel):
|
||||
def __init__(self):
|
||||
model.InVESTModel.__init__(
|
||||
self,
|
||||
label='InVEST Stormwater Model',
|
||||
target=natcap.invest.stormwater.execute,
|
||||
validator=natcap.invest.stormwater.validate,
|
||||
localdoc='stormwater.html')
|
||||
label=MODEL_METADATA['stormwater'].model_title,
|
||||
target=stormwater.execute,
|
||||
validator=stormwater.validate,
|
||||
localdoc=MODEL_METADATA['stormwater'].userguide)
|
||||
|
||||
self.lulc_path = inputs.File(
|
||||
args_key='lulc_path',
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
# coding=UTF-8
|
||||
|
||||
from natcap.invest.ui import model, inputs
|
||||
import natcap.invest.urban_cooling_model
|
||||
from natcap.invest import urban_cooling_model, MODEL_METADATA
|
||||
|
||||
|
||||
class UrbanCoolingModel(model.InVESTModel):
|
||||
def __init__(self):
|
||||
model.InVESTModel.__init__(
|
||||
self,
|
||||
label='Urban Cooling Model',
|
||||
target=natcap.invest.urban_cooling_model.execute,
|
||||
validator=natcap.invest.urban_cooling_model.validate,
|
||||
localdoc='urban_cooling_model.html')
|
||||
label=MODEL_METADATA['urban_cooling_model'].model_title,
|
||||
target=urban_cooling_model.execute,
|
||||
validator=urban_cooling_model.validate,
|
||||
localdoc=MODEL_METADATA['urban_cooling_model'].userguide)
|
||||
|
||||
self.lulc_raster_path = inputs.File(
|
||||
args_key='lulc_raster_path',
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
# coding=UTF-8
|
||||
|
||||
from natcap.invest.ui import model, inputs
|
||||
import natcap.invest.urban_flood_risk_mitigation
|
||||
from natcap.invest import urban_flood_risk_mitigation, MODEL_METADATA
|
||||
|
||||
|
||||
class UrbanFloodRiskMitigation(model.InVESTModel):
|
||||
def __init__(self):
|
||||
model.InVESTModel.__init__(
|
||||
self,
|
||||
label='UrbanFloodRiskMitigation',
|
||||
target=natcap.invest.urban_flood_risk_mitigation.execute,
|
||||
validator=natcap.invest.urban_flood_risk_mitigation.validate,
|
||||
localdoc='urban_flood_mitigation.html')
|
||||
label=MODEL_METADATA['urban_flood_risk_mitigation'].model_title,
|
||||
target=urban_flood_risk_mitigation.execute,
|
||||
validator=urban_flood_risk_mitigation.validate,
|
||||
localdoc=MODEL_METADATA['urban_flood_risk_mitigation'].userguide)
|
||||
|
||||
self.aoi_watersheds_path = inputs.File(
|
||||
args_key='aoi_watersheds_path',
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
# coding=UTF-8
|
||||
|
||||
from natcap.invest.ui import model, inputs
|
||||
import natcap.invest.wave_energy
|
||||
from natcap.invest import wave_energy, MODEL_METADATA
|
||||
|
||||
|
||||
class WaveEnergy(model.InVESTModel):
|
||||
def __init__(self):
|
||||
model.InVESTModel.__init__(
|
||||
self,
|
||||
label='Wave Energy',
|
||||
target=natcap.invest.wave_energy.execute,
|
||||
validator=natcap.invest.wave_energy.validate,
|
||||
localdoc='wave_energy.html')
|
||||
label=MODEL_METADATA['wave_energy'].model_title,
|
||||
target=wave_energy.execute,
|
||||
validator=wave_energy.validate,
|
||||
localdoc=MODEL_METADATA['wave_energy'].userguide)
|
||||
|
||||
self.wave_base_data = inputs.Folder(
|
||||
args_key='wave_base_data_path',
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
# coding=UTF-8
|
||||
|
||||
from natcap.invest.ui import model, inputs
|
||||
from natcap.invest import wind_energy
|
||||
from natcap.invest import wind_energy, MODEL_METADATA
|
||||
|
||||
|
||||
class WindEnergy(model.InVESTModel):
|
||||
def __init__(self):
|
||||
model.InVESTModel.__init__(
|
||||
self,
|
||||
label='Wind Energy',
|
||||
label=MODEL_METADATA['wind_energy'].model_title,
|
||||
target=wind_energy.execute,
|
||||
validator=wind_energy.validate,
|
||||
localdoc='wind_energy.html'
|
||||
localdoc=MODEL_METADATA['wind_energy'].userguide
|
||||
)
|
||||
|
||||
self.wind_data = inputs.File(
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
"""A Flask app with HTTP endpoints used by the InVEST Workbench."""
|
||||
import collections
|
||||
import importlib
|
||||
import json
|
||||
import logging
|
||||
|
@ -9,21 +8,19 @@ from flask import Flask
|
|||
from flask import request
|
||||
from natcap.invest import cli, MODEL_UIS
|
||||
from natcap.invest import datastack
|
||||
from natcap.invest import install_language
|
||||
from natcap.invest import install_language, MODEL_METADATA
|
||||
from natcap.invest import spec_utils
|
||||
from natcap.invest import usage
|
||||
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
# Lookup names to pass to `invest run` based on python module names
|
||||
_UI_META = collections.namedtuple('UIMeta', ['run_name', 'human_name'])
|
||||
MODULE_MODELRUN_MAP = {
|
||||
value.pyname: _UI_META(
|
||||
run_name=key,
|
||||
human_name=value.humanname)
|
||||
for key, value in MODEL_UIS.items()}
|
||||
PYNAME_TO_MODEL_NAME_MAP = {
|
||||
metadata.pyname: model_name
|
||||
for model_name, metadata in MODEL_METADATA.items()
|
||||
}
|
||||
|
||||
|
||||
def shutdown_server():
|
||||
|
@ -73,7 +70,7 @@ def get_invest_getspec():
|
|||
"""
|
||||
# this will be the model key name, not language specific
|
||||
target_model = request.get_json()
|
||||
target_module = MODEL_UIS[target_model].pyname
|
||||
target_module = MODEL_METADATA[target_model].pyname
|
||||
install_language(request.args.get('language', 'en'))
|
||||
model_module = importlib.import_module(name=target_module)
|
||||
return spec_utils.serialize_args_spec(model_module.ARGS_SPEC)
|
||||
|
@ -151,13 +148,13 @@ def post_datastack_file():
|
|||
filepath = request.get_json()
|
||||
stack_type, stack_info = datastack.get_datastack_info(
|
||||
filepath)
|
||||
run_name, human_name = MODULE_MODELRUN_MAP[stack_info.model_name]
|
||||
model_name = PYNAME_TO_MODEL_NAME_MAP[stack_info.model_name]
|
||||
result_dict = {
|
||||
'type': stack_type,
|
||||
'args': stack_info.args,
|
||||
'module_name': stack_info.model_name,
|
||||
'model_run_name': run_name,
|
||||
'model_human_name': human_name,
|
||||
'model_run_name': model_name,
|
||||
'model_human_name': MODEL_METADATA[model_name].model_title,
|
||||
'invest_version': stack_info.invest_version
|
||||
}
|
||||
return json.dumps(result_dict)
|
||||
|
@ -208,3 +205,23 @@ def save_to_python():
|
|||
save_filepath, modelname, args_dict)
|
||||
|
||||
return 'python script saved'
|
||||
|
||||
|
||||
@app.route('/log_model_start', methods=['POST'])
|
||||
def log_model_start():
|
||||
payload = request.get_json()
|
||||
usage._log_model(
|
||||
payload['model_pyname'],
|
||||
json.loads(payload['model_args']),
|
||||
payload['invest_interface'],
|
||||
payload['session_id'])
|
||||
return 'OK'
|
||||
|
||||
|
||||
@app.route('/log_model_exit', methods=['POST'])
|
||||
def log_model_exit():
|
||||
payload = request.get_json()
|
||||
usage._log_exit_status(
|
||||
payload['session_id'],
|
||||
payload['status'])
|
||||
return 'OK'
|
||||
|
|
|
@ -21,15 +21,16 @@ from . import utils
|
|||
from . import spec_utils
|
||||
from .spec_utils import u
|
||||
from . import validation
|
||||
from . import MODEL_METADATA
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
TARGET_NODATA = -1
|
||||
_LOGGING_PERIOD = 5.0
|
||||
|
||||
ARGS_SPEC = {
|
||||
"model_name": _("Urban Cooling Model"),
|
||||
'module': __name__,
|
||||
"userguide_html": "urban_cooling_model.html",
|
||||
"model_name": MODEL_METADATA["urban_cooling_model"].model_title,
|
||||
"pyname": MODEL_METADATA["urban_cooling_model"].pyname,
|
||||
"userguide_html": MODEL_METADATA["urban_cooling_model"].userguide,
|
||||
"args_with_spatial_overlap": {
|
||||
"spatial_keys": ["lulc_raster_path", "ref_eto_raster_path",
|
||||
"aoi_vector_path", "building_vector_path"],
|
||||
|
|
|
@ -17,13 +17,14 @@ from . import utils
|
|||
from . import spec_utils
|
||||
from .spec_utils import u
|
||||
from . import validation
|
||||
from . import MODEL_METADATA
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
||||
ARGS_SPEC = {
|
||||
"model_name": _("Urban Flood Risk Mitigation"),
|
||||
"module": __name__,
|
||||
"userguide_html": "urban_flood_risk_mitigation.html",
|
||||
"model_name": MODEL_METADATA["urban_flood_risk_mitigation"].model_title,
|
||||
"pyname": MODEL_METADATA["urban_flood_risk_mitigation"].pyname,
|
||||
"userguide_html": MODEL_METADATA["urban_flood_risk_mitigation"].userguide,
|
||||
"args_with_spatial_overlap": {
|
||||
"spatial_keys": ["aoi_watersheds_path", "lulc_path",
|
||||
"built_infrastructure_vector_path",
|
||||
|
@ -757,8 +758,30 @@ def _lu_to_cn_op(
|
|||
# pixel and the rows are the curve number index for the landcover
|
||||
# type under that pixel (0..3 are CN_A..CN_D and 4 is "unknown")
|
||||
valid_lucodes = lucode_array[valid_mask].astype(int)
|
||||
|
||||
try:
|
||||
cn_matrix = lucode_to_cn_table[valid_lucodes]
|
||||
except IndexError:
|
||||
# Find the code that raised the IndexError, and possibly
|
||||
# any others that also would have.
|
||||
lucodes = numpy.unique(valid_lucodes)
|
||||
missing_codes = lucodes[lucodes >= lucode_to_cn_table.shape[0]]
|
||||
raise ValueError(
|
||||
f'The biophysical table is missing a row for lucode(s) '
|
||||
f'{missing_codes.tolist()}')
|
||||
|
||||
# Even without an IndexError, still must guard against
|
||||
# lucodes that can index into the sparse matrix but were
|
||||
# missing from the biophysical table. They have rows of all 0.
|
||||
if not cn_matrix.sum(1).all():
|
||||
empty_rows = numpy.where(lucode_to_cn_table.sum(1) == 0)
|
||||
missing_codes = numpy.intersect1d(valid_lucodes, empty_rows)
|
||||
raise ValueError(
|
||||
f'The biophysical table is missing a row for lucode(s) '
|
||||
f'{missing_codes.tolist()}')
|
||||
|
||||
per_pixel_cn_array = (
|
||||
lucode_to_cn_table[valid_lucodes].toarray().reshape(
|
||||
cn_matrix.toarray().reshape(
|
||||
(-1, 4))).transpose()
|
||||
|
||||
# this is the soil type array with values ranging from 0..4 that will
|
||||
|
|
|
@ -15,12 +15,11 @@ import importlib
|
|||
from urllib.request import urlopen, Request
|
||||
from urllib.parse import urlencode
|
||||
|
||||
from osgeo import gdal
|
||||
from osgeo import osr
|
||||
import natcap.invest
|
||||
import pygeoprocessing
|
||||
|
||||
from .. import utils
|
||||
from . import utils
|
||||
|
||||
ENCODING = sys.getfilesystemencoding()
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
@ -36,19 +35,21 @@ _USAGE_LOGGING_THREAD_NAME = 'usage-logging-thread'
|
|||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def log_run(module, args):
|
||||
def log_run(model_pyname, args):
|
||||
"""Context manager to log an InVEST model run and exit status.
|
||||
|
||||
Args:
|
||||
module (string): The string module name that identifies the model.
|
||||
model_pyname (string): The string module name that identifies the model.
|
||||
args (dict): The full args dictionary.
|
||||
|
||||
Returns:
|
||||
``None``
|
||||
"""
|
||||
invest_interface = 'Qt' # this cm is only used by the Qt interface
|
||||
session_id = str(uuid.uuid4())
|
||||
log_thread = threading.Thread(
|
||||
target=_log_model, args=(module, args, session_id),
|
||||
target=_log_model,
|
||||
args=(model_pyname, args, invest_interface, session_id),
|
||||
name=_USAGE_LOGGING_THREAD_NAME)
|
||||
log_thread.start()
|
||||
|
||||
|
@ -191,17 +192,19 @@ def _log_exit_status(session_id, status):
|
|||
urlopen(Request(log_finish_url, urlencode(payload).encode('utf-8')))
|
||||
except Exception as exception:
|
||||
# An exception was thrown, we don't care.
|
||||
logger.warn(
|
||||
logger.warning(
|
||||
'an exception encountered when _log_exit_status %s',
|
||||
str(exception))
|
||||
|
||||
|
||||
def _log_model(model_name, model_args, session_id=None):
|
||||
def _log_model(pyname, model_args, invest_interface, session_id=None):
|
||||
"""Log information about a model run to a remote server.
|
||||
|
||||
Args:
|
||||
model_name (string): a python string of the package version.
|
||||
pyname (string): a python string of the package version.
|
||||
model_args (dict): the traditional InVEST argument dictionary.
|
||||
invest_interface (string): a string identifying the calling UI,
|
||||
e.g. `Qt` or 'Workbench'.
|
||||
|
||||
Returns:
|
||||
None
|
||||
|
@ -221,15 +224,16 @@ def _log_model(model_name, model_args, session_id=None):
|
|||
md5.update(json.dumps(data).encode('utf-8'))
|
||||
return md5.hexdigest()
|
||||
|
||||
args_spec = importlib.import_module(model_name).ARGS_SPEC
|
||||
args_spec = importlib.import_module(pyname).ARGS_SPEC
|
||||
|
||||
try:
|
||||
bounding_box_intersection, bounding_box_union = (
|
||||
_calculate_args_bounding_box(model_args, args_spec))
|
||||
|
||||
payload = {
|
||||
'model_name': model_name,
|
||||
'model_name': pyname,
|
||||
'invest_release': natcap.invest.__version__,
|
||||
'invest_interface': invest_interface,
|
||||
'node_hash': _node_hash(),
|
||||
'system_full_platform_string': platform.platform(),
|
||||
'system_preferred_encoding': locale.getdefaultlocale()[1],
|
||||
|
@ -246,5 +250,5 @@ def _log_model(model_name, model_args, session_id=None):
|
|||
urlopen(Request(log_start_url, urlencode(payload).encode('utf-8')))
|
||||
except Exception as exception:
|
||||
# An exception was thrown, we don't care.
|
||||
logger.warn(
|
||||
logger.warning(
|
||||
'an exception encountered when logging %s', repr(exception))
|
|
@ -155,7 +155,10 @@ def prepare_workspace(
|
|||
logging_level=logging_level):
|
||||
with sandbox_tempdir(dir=workspace):
|
||||
logging.captureWarnings(True)
|
||||
LOGGER.info('Writing log messages to %s', logfile)
|
||||
# If invest is launched as a subprocess (e.g. the Workbench)
|
||||
# the parent process can rely on this announcement to know the
|
||||
# logfile path, and to know the invest process has started.
|
||||
LOGGER.log(100, 'Writing log messages to %s', logfile)
|
||||
start_time = time.time()
|
||||
try:
|
||||
yield
|
||||
|
|
|
@ -21,13 +21,14 @@ from . import utils
|
|||
from . import spec_utils
|
||||
from .spec_utils import u
|
||||
from . import validation
|
||||
from . import MODEL_METADATA
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
||||
ARGS_SPEC = {
|
||||
"model_name": _("Wave Energy"),
|
||||
"module": __name__,
|
||||
"userguide_html": "wave_energy.html",
|
||||
"model_name": MODEL_METADATA["wave_energy"].model_title,
|
||||
"pyname": MODEL_METADATA["wave_energy"].pyname,
|
||||
"userguide_html": MODEL_METADATA["wave_energy"].userguide,
|
||||
"args": {
|
||||
"workspace_dir": spec_utils.WORKSPACE,
|
||||
"results_suffix": spec_utils.SUFFIX,
|
||||
|
|
|
@ -26,15 +26,16 @@ from . import utils
|
|||
from . import spec_utils
|
||||
from .spec_utils import u
|
||||
from . import validation
|
||||
from . import MODEL_METADATA
|
||||
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
speedups.enable()
|
||||
|
||||
ARGS_SPEC = {
|
||||
"model_name": _("Wind Energy"),
|
||||
"module": __name__,
|
||||
"userguide_html": "wind_energy.html",
|
||||
"model_name": MODEL_METADATA["wind_energy"].model_title,
|
||||
"pyname": MODEL_METADATA["wind_energy"].pyname,
|
||||
"userguide_html": MODEL_METADATA["wind_energy"].userguide,
|
||||
"args_with_spatial_overlap": {
|
||||
"spatial_keys": ['aoi_vector_path', 'bathymetry_path',
|
||||
'land_polygon_vector_path'],
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
"""Module for Regression Testing the InVEST Hydropower module."""
|
||||
"""Module for Regression Testing the InVEST Annual Water Yield module."""
|
||||
import unittest
|
||||
import tempfile
|
||||
import shutil
|
||||
|
@ -8,15 +8,14 @@ import pandas
|
|||
import numpy
|
||||
import pygeoprocessing
|
||||
|
||||
SAMPLE_DATA = os.path.join(
|
||||
os.path.dirname(__file__), '..', 'data', 'invest-test-data', 'hydropower',
|
||||
'input')
|
||||
|
||||
REGRESSION_DATA = os.path.join(
|
||||
os.path.dirname(__file__), '..', 'data', 'invest-test-data', 'hydropower')
|
||||
os.path.dirname(__file__), '..', 'data', 'invest-test-data', 'annual_water_yield')
|
||||
SAMPLE_DATA = os.path.join(REGRESSION_DATA, 'input')
|
||||
|
||||
|
||||
class HydropowerTests(unittest.TestCase):
|
||||
"""Regression Tests for Annual Water Yield Hydropower Model."""
|
||||
class AnnualWaterYieldTests(unittest.TestCase):
|
||||
"""Regression Tests for Annual Water Yield Model."""
|
||||
|
||||
def setUp(self):
|
||||
"""Overriding setUp func. to create temporary workspace directory."""
|
||||
|
@ -50,9 +49,9 @@ class HydropowerTests(unittest.TestCase):
|
|||
|
||||
def test_invalid_lulc_veg(self):
|
||||
"""Hydro: catching invalid LULC_veg values."""
|
||||
from natcap.invest.hydropower import hydropower_water_yield
|
||||
from natcap.invest import annual_water_yield
|
||||
|
||||
args = HydropowerTests.generate_base_args(self.workspace_dir)
|
||||
args = AnnualWaterYieldTests.generate_base_args(self.workspace_dir)
|
||||
|
||||
new_lulc_veg_path = os.path.join(self.workspace_dir,
|
||||
'new_lulc_veg.csv')
|
||||
|
@ -63,7 +62,7 @@ class HydropowerTests(unittest.TestCase):
|
|||
args['biophysical_table_path'] = new_lulc_veg_path
|
||||
|
||||
with self.assertRaises(ValueError) as cm:
|
||||
hydropower_water_yield.execute(args)
|
||||
annual_water_yield.execute(args)
|
||||
self.assertTrue('veg value must be either 1 or 0' in str(cm.exception))
|
||||
|
||||
table_df = pandas.read_csv(args['biophysical_table_path'])
|
||||
|
@ -72,14 +71,14 @@ class HydropowerTests(unittest.TestCase):
|
|||
args['biophysical_table_path'] = new_lulc_veg_path
|
||||
|
||||
with self.assertRaises(ValueError) as cm:
|
||||
hydropower_water_yield.execute(args)
|
||||
annual_water_yield.execute(args)
|
||||
self.assertTrue('veg value must be either 1 or 0' in str(cm.exception))
|
||||
|
||||
def test_missing_lulc_value(self):
|
||||
"""Hydro: catching missing LULC value in Biophysical table."""
|
||||
from natcap.invest.hydropower import hydropower_water_yield
|
||||
from natcap.invest import annual_water_yield
|
||||
|
||||
args = HydropowerTests.generate_base_args(self.workspace_dir)
|
||||
args = AnnualWaterYieldTests.generate_base_args(self.workspace_dir)
|
||||
|
||||
# remove a row from the biophysical table so that lulc value is missing
|
||||
bad_biophysical_path = os.path.join(
|
||||
|
@ -93,16 +92,16 @@ class HydropowerTests(unittest.TestCase):
|
|||
args['biophysical_table_path'] = bad_biophysical_path
|
||||
|
||||
with self.assertRaises(ValueError) as cm:
|
||||
hydropower_water_yield.execute(args)
|
||||
annual_water_yield.execute(args)
|
||||
self.assertTrue(
|
||||
"The missing values found in the LULC raster but not the table"
|
||||
" are: [2]" in str(cm.exception))
|
||||
|
||||
def test_missing_lulc_demand_value(self):
|
||||
"""Hydro: catching missing LULC value in Demand table."""
|
||||
from natcap.invest.hydropower import hydropower_water_yield
|
||||
from natcap.invest import annual_water_yield
|
||||
|
||||
args = HydropowerTests.generate_base_args(self.workspace_dir)
|
||||
args = AnnualWaterYieldTests.generate_base_args(self.workspace_dir)
|
||||
|
||||
args['demand_table_path'] = os.path.join(
|
||||
SAMPLE_DATA, 'water_demand_table.csv')
|
||||
|
@ -121,21 +120,21 @@ class HydropowerTests(unittest.TestCase):
|
|||
args['demand_table_path'] = bad_demand_path
|
||||
|
||||
with self.assertRaises(ValueError) as cm:
|
||||
hydropower_water_yield.execute(args)
|
||||
annual_water_yield.execute(args)
|
||||
self.assertTrue(
|
||||
"The missing values found in the LULC raster but not the table"
|
||||
" are: [2]" in str(cm.exception))
|
||||
|
||||
def test_water_yield_subshed(self):
|
||||
"""Hydro: testing water yield component only w/ subwatershed."""
|
||||
from natcap.invest.hydropower import hydropower_water_yield
|
||||
from natcap.invest import annual_water_yield
|
||||
from natcap.invest import utils
|
||||
|
||||
args = HydropowerTests.generate_base_args(self.workspace_dir)
|
||||
args = AnnualWaterYieldTests.generate_base_args(self.workspace_dir)
|
||||
args['sub_watersheds_path'] = os.path.join(
|
||||
SAMPLE_DATA, 'subwatersheds.shp')
|
||||
args['results_suffix'] = 'test'
|
||||
hydropower_water_yield.execute(args)
|
||||
annual_water_yield.execute(args)
|
||||
|
||||
raster_results = ['aet_test.tif', 'fractp_test.tif', 'wyield_test.tif']
|
||||
for raster_path in raster_results:
|
||||
|
@ -169,16 +168,16 @@ class HydropowerTests(unittest.TestCase):
|
|||
|
||||
def test_scarcity_subshed(self):
|
||||
"""Hydro: testing Scarcity component w/ subwatershed."""
|
||||
from natcap.invest.hydropower import hydropower_water_yield
|
||||
from natcap.invest import annual_water_yield
|
||||
from natcap.invest import utils
|
||||
|
||||
args = HydropowerTests.generate_base_args(self.workspace_dir)
|
||||
args = AnnualWaterYieldTests.generate_base_args(self.workspace_dir)
|
||||
args['demand_table_path'] = os.path.join(
|
||||
SAMPLE_DATA, 'water_demand_table.csv')
|
||||
args['sub_watersheds_path'] = os.path.join(
|
||||
SAMPLE_DATA, 'subwatersheds.shp')
|
||||
|
||||
hydropower_water_yield.execute(args)
|
||||
annual_water_yield.execute(args)
|
||||
|
||||
raster_results = ['aet.tif', 'fractp.tif', 'wyield.tif']
|
||||
for raster_path in raster_results:
|
||||
|
@ -207,10 +206,10 @@ class HydropowerTests(unittest.TestCase):
|
|||
|
||||
def test_valuation_subshed(self):
|
||||
"""Hydro: testing Valuation component w/ subwatershed."""
|
||||
from natcap.invest.hydropower import hydropower_water_yield
|
||||
from natcap.invest import annual_water_yield
|
||||
from natcap.invest import utils
|
||||
|
||||
args = HydropowerTests.generate_base_args(self.workspace_dir)
|
||||
args = AnnualWaterYieldTests.generate_base_args(self.workspace_dir)
|
||||
args['demand_table_path'] = os.path.join(
|
||||
SAMPLE_DATA, 'water_demand_table.csv')
|
||||
args['valuation_table_path'] = os.path.join(
|
||||
|
@ -218,7 +217,7 @@ class HydropowerTests(unittest.TestCase):
|
|||
args['sub_watersheds_path'] = os.path.join(
|
||||
SAMPLE_DATA, 'subwatersheds.shp')
|
||||
|
||||
hydropower_water_yield.execute(args)
|
||||
annual_water_yield.execute(args)
|
||||
|
||||
raster_results = ['aet.tif', 'fractp.tif', 'wyield.tif']
|
||||
for raster_path in raster_results:
|
||||
|
@ -247,34 +246,33 @@ class HydropowerTests(unittest.TestCase):
|
|||
|
||||
def test_validation(self):
|
||||
"""Hydro: test failure cases on the validation function."""
|
||||
from natcap.invest.hydropower import hydropower_water_yield
|
||||
from natcap.invest import validation
|
||||
from natcap.invest import annual_water_yield, validation
|
||||
|
||||
args = HydropowerTests.generate_base_args(self.workspace_dir)
|
||||
args = AnnualWaterYieldTests.generate_base_args(self.workspace_dir)
|
||||
|
||||
# default args should be fine
|
||||
self.assertEqual(hydropower_water_yield.validate(args), [])
|
||||
self.assertEqual(annual_water_yield.validate(args), [])
|
||||
|
||||
args_bad_vector = args.copy()
|
||||
args_bad_vector['watersheds_path'] = args_bad_vector['eto_path']
|
||||
bad_vector_list = hydropower_water_yield.validate(args_bad_vector)
|
||||
bad_vector_list = annual_water_yield.validate(args_bad_vector)
|
||||
self.assertTrue('not be opened as a GDAL vector'
|
||||
in bad_vector_list[0][1])
|
||||
|
||||
args_bad_raster = args.copy()
|
||||
args_bad_raster['eto_path'] = args_bad_raster['watersheds_path']
|
||||
bad_raster_list = hydropower_water_yield.validate(args_bad_raster)
|
||||
bad_raster_list = annual_water_yield.validate(args_bad_raster)
|
||||
self.assertTrue('not be opened as a GDAL raster'
|
||||
in bad_raster_list[0][1])
|
||||
|
||||
args_bad_file = args.copy()
|
||||
args_bad_file['eto_path'] = 'non_existant_file.tif'
|
||||
bad_file_list = hydropower_water_yield.validate(args_bad_file)
|
||||
bad_file_list = annual_water_yield.validate(args_bad_file)
|
||||
self.assertTrue('File not found' in bad_file_list[0][1])
|
||||
|
||||
args_missing_key = args.copy()
|
||||
del args_missing_key['eto_path']
|
||||
validation_warnings = hydropower_water_yield.validate(
|
||||
validation_warnings = annual_water_yield.validate(
|
||||
args_missing_key)
|
||||
self.assertEqual(
|
||||
validation_warnings,
|
||||
|
@ -297,7 +295,7 @@ class HydropowerTests(unittest.TestCase):
|
|||
args_bad_biophysical_table['biophysical_table_path'] = (
|
||||
bad_biophysical_path)
|
||||
with self.assertRaises(ValueError) as cm:
|
||||
hydropower_water_yield.execute(args_bad_biophysical_table)
|
||||
annual_water_yield.execute(args_bad_biophysical_table)
|
||||
actual_message = str(cm.exception)
|
||||
self.assertTrue(
|
||||
"The missing values found in the LULC raster but not the table"
|
||||
|
@ -336,7 +334,7 @@ class HydropowerTests(unittest.TestCase):
|
|||
# ensure that a missing watershed id the valuation table will
|
||||
# raise an exception that's helpful
|
||||
with self.assertRaises(ValueError) as cm:
|
||||
hydropower_water_yield.execute(args_bad_demand_table)
|
||||
annual_water_yield.execute(args_bad_demand_table)
|
||||
actual_message = str(cm.exception)
|
||||
self.assertTrue(
|
||||
"The missing values found in the LULC raster but not the table"
|
||||
|
@ -363,7 +361,7 @@ class HydropowerTests(unittest.TestCase):
|
|||
break
|
||||
|
||||
with self.assertRaises(ValueError) as cm:
|
||||
hydropower_water_yield.execute(args_bad_valuation_table)
|
||||
annual_water_yield.execute(args_bad_valuation_table)
|
||||
actual_message = str(cm.exception)
|
||||
self.assertTrue(
|
||||
'but are not found in the valuation table' in
|
|
@ -2,7 +2,7 @@ import importlib
|
|||
import re
|
||||
import unittest
|
||||
|
||||
from natcap.invest import MODEL_UIS
|
||||
from natcap.invest import MODEL_METADATA
|
||||
import pint
|
||||
|
||||
|
||||
|
@ -49,9 +49,10 @@ class ValidateArgsSpecs(unittest.TestCase):
|
|||
def test_model_specs_are_valid(self):
|
||||
"""ARGS_SPEC: test each spec meets the expected pattern."""
|
||||
|
||||
required_keys = {'model_name', 'module', 'userguide_html', 'args'}
|
||||
required_keys = {'model_name', 'pyname', 'userguide_html', 'args'}
|
||||
optional_spatial_key = 'args_with_spatial_overlap'
|
||||
for model_name, metadata in MODEL_UIS.items():
|
||||
for model_name, metadata in MODEL_METADATA.items():
|
||||
# metadata is a collections.namedtuple, fields accessible by name
|
||||
model = importlib.import_module(metadata.pyname)
|
||||
|
||||
|
@ -333,7 +334,7 @@ class ValidateArgsSpecs(unittest.TestCase):
|
|||
"""ARGS_SPEC: test each ARGS_SPEC can serialize to JSON."""
|
||||
from natcap.invest import spec_utils
|
||||
|
||||
for model_name, metadata in MODEL_UIS.items():
|
||||
for model_name, metadata in MODEL_METADATA.items():
|
||||
model = importlib.import_module(metadata.pyname)
|
||||
try:
|
||||
_ = spec_utils.serialize_args_spec(model.ARGS_SPEC)
|
||||
|
|
|
@ -406,7 +406,7 @@ class CLIUnitTests(unittest.TestCase):
|
|||
|
||||
def test_export_to_python_default_args(self):
|
||||
"""Export a python script w/ default args for a model."""
|
||||
from natcap.invest import cli
|
||||
from natcap.invest import cli, MODEL_METADATA
|
||||
|
||||
filename = 'foo.py'
|
||||
target_filepath = os.path.join(self.workspace_dir, filename)
|
||||
|
@ -416,7 +416,7 @@ class CLIUnitTests(unittest.TestCase):
|
|||
|
||||
self.assertTrue(os.path.exists(target_filepath))
|
||||
|
||||
target_model = cli._MODEL_UIS[target_model].pyname
|
||||
target_model = MODEL_METADATA[target_model].pyname
|
||||
model_module = importlib.import_module(name=target_model)
|
||||
spec = model_module.ARGS_SPEC
|
||||
expected_args = {key: '' for key in spec['args'].keys()}
|
||||
|
|
|
@ -53,7 +53,7 @@ def make_access_shp(access_shp_path):
|
|||
|
||||
# Setup parameters for creating point shapefile
|
||||
fields = {'FID': ogr.OFTInteger64, 'ACCESS': ogr.OFTReal}
|
||||
attrs = [{'FID': 0, 'ACCESS': 0.2}, {'FI': 1, 'ACCESS': 1.0}]
|
||||
attrs = [{'FID': 0, 'ACCESS': 0.2}, {'FID': 1, 'ACCESS': 1.0}]
|
||||
|
||||
poly_geoms = {
|
||||
'poly_1': [(pos_x, pos_y), (pos_x + 100, pos_y),
|
||||
|
|
|
@ -1148,3 +1148,39 @@ class SWYValidationTests(unittest.TestCase):
|
|||
expected_missing_keys.difference_update(
|
||||
{'monthly_alpha', 'alpha_m'})
|
||||
self.assertEqual(invalid_keys, expected_missing_keys)
|
||||
|
||||
def test_all_inputs_valid(self):
|
||||
"""SWY Validate: assert valid inputs have no validation errors."""
|
||||
from natcap.invest.seasonal_water_yield import seasonal_water_yield
|
||||
args = SeasonalWaterYieldRegressionTests.generate_base_args(
|
||||
self.workspace_dir)
|
||||
args.update({
|
||||
'user_defined_climate_zones': False,
|
||||
'user_defined_local_recharge': False,
|
||||
'monthly_alpha': False})
|
||||
|
||||
# first test with none of the optional params
|
||||
validation_errors = seasonal_water_yield.validate(args)
|
||||
self.assertEqual(validation_errors, [])
|
||||
|
||||
cz_csv_path = os.path.join(self.workspace_dir, 'cz.csv')
|
||||
make_climate_zone_csv(cz_csv_path)
|
||||
cz_ras_path = os.path.join(args['workspace_dir'], 'dem.tif')
|
||||
make_gradient_raster(cz_ras_path)
|
||||
args['climate_zone_raster_path'] = cz_ras_path
|
||||
args['climate_zone_table_path'] = cz_csv_path
|
||||
args['user_defined_climate_zones'] = True
|
||||
|
||||
recharge_ras_path = os.path.join(self.workspace_dir, 'L.tif')
|
||||
make_recharge_raster(recharge_ras_path)
|
||||
args['l_path'] = recharge_ras_path
|
||||
args['user_defined_local_recharge'] = True
|
||||
|
||||
alpha_csv_path = os.path.join(self.workspace_dir, 'monthly_alpha.csv')
|
||||
make_alpha_csv(alpha_csv_path)
|
||||
args['monthly_alpha_path'] = alpha_csv_path
|
||||
args['monthly_alpha'] = True
|
||||
|
||||
# test with all of the optional params
|
||||
validation_errors = seasonal_water_yield.validate(args)
|
||||
self.assertEqual(validation_errors, [])
|
||||
|
|
|
@ -149,10 +149,53 @@ class UFRMTests(unittest.TestCase):
|
|||
|
||||
with self.assertRaises(ValueError) as cm:
|
||||
urban_flood_risk_mitigation.execute(args)
|
||||
actual_message = str(cm.exception)
|
||||
expected_message = (
|
||||
'Check that the Soil Group raster does not contain')
|
||||
self.assertTrue(expected_message in actual_message)
|
||||
|
||||
actual_message = str(cm.exception)
|
||||
expected_message = (
|
||||
'Check that the Soil Group raster does not contain')
|
||||
self.assertTrue(expected_message in actual_message)
|
||||
|
||||
def test_ufrm_value_error_on_bad_lucode(self):
|
||||
"""UFRM: assert exception on missing lucodes."""
|
||||
import pandas
|
||||
from natcap.invest import urban_flood_risk_mitigation
|
||||
args = self._make_args()
|
||||
|
||||
bad_cn_table_path = os.path.join(
|
||||
self.workspace_dir, 'bad_cn_table.csv')
|
||||
cn_table = pandas.read_csv(args['curve_number_table_path'])
|
||||
|
||||
# drop a row with an lucode known to exist in lulc raster
|
||||
# This is a code that will successfully index into the
|
||||
# CN table sparse matrix, but will not return valid data.
|
||||
bad_cn_table = cn_table[cn_table['lucode'] != 0]
|
||||
bad_cn_table.to_csv(bad_cn_table_path, index=False)
|
||||
args['curve_number_table_path'] = bad_cn_table_path
|
||||
|
||||
with self.assertRaises(ValueError) as cm:
|
||||
urban_flood_risk_mitigation.execute(args)
|
||||
|
||||
actual_message = str(cm.exception)
|
||||
expected_message = (
|
||||
f'The biophysical table is missing a row for lucode(s) {[0]}')
|
||||
self.assertEqual(expected_message, actual_message)
|
||||
|
||||
# drop rows with lucodes known to exist in lulc raster
|
||||
# These are codes that will raise an IndexError on
|
||||
# indexing into the CN table sparse matrix. The test
|
||||
# LULC raster has values from 0 to 21.
|
||||
bad_cn_table = cn_table[cn_table['lucode'] < 15]
|
||||
bad_cn_table.to_csv(bad_cn_table_path, index=False)
|
||||
args['curve_number_table_path'] = bad_cn_table_path
|
||||
|
||||
with self.assertRaises(ValueError) as cm:
|
||||
urban_flood_risk_mitigation.execute(args)
|
||||
|
||||
actual_message = str(cm.exception)
|
||||
expected_message = (
|
||||
f'The biophysical table is missing a row for lucode(s) '
|
||||
f'{[16, 17, 18, 21]}')
|
||||
self.assertEqual(expected_message, actual_message)
|
||||
|
||||
def test_ufrm_string_damage_to_infrastructure(self):
|
||||
"""UFRM: handle str(int) structure indices.
|
||||
|
|
|
@ -3,6 +3,9 @@ import os
|
|||
import shutil
|
||||
import tempfile
|
||||
import unittest
|
||||
from unittest.mock import Mock, patch
|
||||
|
||||
from natcap.invest import ui_server
|
||||
|
||||
TEST_DATA_PATH = os.path.join(
|
||||
os.path.dirname(__file__), '..', 'data', 'invest-test-data')
|
||||
|
@ -23,7 +26,6 @@ class EndpointFunctionTests(unittest.TestCase):
|
|||
|
||||
def test_get_vector_colnames(self):
|
||||
"""UI server: get_vector_colnames endpoint."""
|
||||
from natcap.invest import ui_server
|
||||
test_client = ui_server.app.test_client()
|
||||
# an empty path
|
||||
response = test_client.post('/colnames', json={'vector_path': ''})
|
||||
|
@ -45,33 +47,31 @@ class EndpointFunctionTests(unittest.TestCase):
|
|||
|
||||
def test_get_invest_models(self):
|
||||
"""UI server: get_invest_models endpoint."""
|
||||
from natcap.invest import ui_server
|
||||
test_client = ui_server.app.test_client()
|
||||
response = test_client.get('/models')
|
||||
models_dict = json.loads(response.get_data(as_text=True))
|
||||
for model in models_dict.values():
|
||||
self.assertEqual(set(model), {'internal_name', 'aliases'})
|
||||
self.assertEqual(set(model), {'model_name', 'aliases'})
|
||||
|
||||
def test_get_invest_spec(self):
|
||||
"""UI server: get_invest_spec endpoint."""
|
||||
from natcap.invest import ui_server
|
||||
test_client = ui_server.app.test_client()
|
||||
response = test_client.post('/getspec', json='sdr')
|
||||
spec = json.loads(response.get_data(as_text=True))
|
||||
self.assertEqual(
|
||||
set(spec),
|
||||
{'model_name', 'module', 'userguide_html',
|
||||
{'model_name', 'pyname', 'userguide_html',
|
||||
'args_with_spatial_overlap', 'args'})
|
||||
|
||||
def test_get_invest_validate(self):
|
||||
"""UI server: get_invest_validate endpoint."""
|
||||
from natcap.invest import ui_server, carbon
|
||||
from natcap.invest import carbon
|
||||
test_client = ui_server.app.test_client()
|
||||
args = {
|
||||
'workspace_dir': 'foo'
|
||||
}
|
||||
payload = {
|
||||
'model_module': carbon.ARGS_SPEC['module'],
|
||||
'model_module': carbon.ARGS_SPEC['pyname'],
|
||||
'args': json.dumps(args)
|
||||
}
|
||||
response = test_client.post('/validate', json=payload)
|
||||
|
@ -83,7 +83,6 @@ class EndpointFunctionTests(unittest.TestCase):
|
|||
|
||||
def test_post_datastack_file(self):
|
||||
"""UI server: post_datastack_file endpoint."""
|
||||
from natcap.invest import ui_server
|
||||
test_client = ui_server.app.test_client()
|
||||
self.workspace_dir = tempfile.mkdtemp()
|
||||
expected_datastack = {
|
||||
|
@ -105,7 +104,6 @@ class EndpointFunctionTests(unittest.TestCase):
|
|||
|
||||
def test_write_parameter_set_file(self):
|
||||
"""UI server: write_parameter_set_file endpoint."""
|
||||
from natcap.invest import ui_server
|
||||
test_client = ui_server.app.test_client()
|
||||
self.workspace_dir = tempfile.mkdtemp()
|
||||
filepath = os.path.join(self.workspace_dir, 'datastack.json')
|
||||
|
@ -126,7 +124,6 @@ class EndpointFunctionTests(unittest.TestCase):
|
|||
|
||||
def test_save_to_python(self):
|
||||
"""UI server: save_to_python endpoint."""
|
||||
from natcap.invest import ui_server
|
||||
test_client = ui_server.app.test_client()
|
||||
self.workspace_dir = tempfile.mkdtemp()
|
||||
filepath = os.path.join(self.workspace_dir, 'script.py')
|
||||
|
@ -140,3 +137,35 @@ class EndpointFunctionTests(unittest.TestCase):
|
|||
_ = test_client.post('/save_to_python', json=payload)
|
||||
# test_cli.py asserts the actual contents of the file
|
||||
self.assertTrue(os.path.exists(filepath))
|
||||
|
||||
@patch('natcap.invest.ui_server.usage.urlopen')
|
||||
def test_log_model_start(self, mock_urlopen):
|
||||
"""UI server: log_model_start endpoint."""
|
||||
mock_response = Mock()
|
||||
mock_response.read.return_value = '{"START": "http://foo.org/bar.html"}'
|
||||
mock_urlopen.return_value = mock_response
|
||||
test_client = ui_server.app.test_client()
|
||||
payload = {
|
||||
'model_pyname': 'natcap.invest.carbon',
|
||||
'model_args': json.dumps({
|
||||
'workspace_dir': 'foo'
|
||||
}),
|
||||
'invest_interface': 'Workbench',
|
||||
'session_id': '12345'
|
||||
}
|
||||
response = test_client.post('/log_model_start', json=payload)
|
||||
self.assertEqual(response.get_data(as_text=True), 'OK')
|
||||
|
||||
@patch('natcap.invest.ui_server.usage.urlopen')
|
||||
def test_log_model_exit(self, mock_urlopen):
|
||||
"""UI server: log_model_start endpoint."""
|
||||
mock_response = Mock()
|
||||
mock_response.read.return_value = '{"FINISH": "http://foo.org/bar.html"}'
|
||||
mock_urlopen.return_value = mock_response
|
||||
test_client = ui_server.app.test_client()
|
||||
payload = {
|
||||
'session_id': '12345',
|
||||
'status': ''
|
||||
}
|
||||
response = test_client.post('/log_model_exit', json=payload)
|
||||
self.assertEqual(response.get_data(as_text=True), 'OK')
|
||||
|
|
|
@ -14,8 +14,8 @@ import numpy
|
|||
import numpy.testing
|
||||
|
||||
|
||||
class ModelLoggingTests(unittest.TestCase):
|
||||
"""Tests for the InVEST model logging framework."""
|
||||
class UsageLoggingTests(unittest.TestCase):
|
||||
"""Tests for the InVEST usage logging framework."""
|
||||
|
||||
def setUp(self):
|
||||
"""Initalize a workspace."""
|
||||
|
@ -28,7 +28,7 @@ class ModelLoggingTests(unittest.TestCase):
|
|||
def test_bounding_boxes(self):
|
||||
"""Usage logger test that we can extract bounding boxes."""
|
||||
from natcap.invest import utils
|
||||
from natcap.invest.ui import usage
|
||||
from natcap.invest import usage
|
||||
|
||||
srs = osr.SpatialReference()
|
||||
srs.ImportFromEPSG(32731) # WGS84 / UTM zone 31s
|
||||
|
@ -81,7 +81,7 @@ class ModelLoggingTests(unittest.TestCase):
|
|||
numpy.testing.assert_allclose(
|
||||
bb_inter, [-87.234108, -85.526151, -87.233424, -85.526205])
|
||||
numpy.testing.assert_allclose(
|
||||
bb_union, [-87.237771, -85.526132, -87.23321 , -85.526491])
|
||||
bb_union, [-87.237771, -85.526132, -87.23321, -85.526491])
|
||||
|
||||
# Verify that no errors were raised in calculating the bounding boxes.
|
||||
self.assertTrue('ERROR' not in open(output_logfile).read(),
|
Loading…
Reference in New Issue