******************************* About the :py:mod:`ws3` Package ******************************* The :py:mod:`ws3` package is implemented using the Python programming language. :py:mod:`ws3` is an aspatial wood supply model, which applies actions (and matching transitions) to development types, simulates growth, and tracks inventory area (by development type and by age class) at each time step. Aspatial models output aspatial activity schedules---each line of the output schedule specifies the stratification variable values (which constitute a unique key into the list of development types), the age class, the time step, the action code, and the area treated. Because the model is aspatial, the area treated on a given line of the output schedule may not be spatially contiguous (i.e., the area may be geographically dispersed throughout the landscape). Furthermore, in the common case where only a subset of available area in a given development type and age class combination is treated in a given time step, an aspatial model provides no information regarding which spatial subset of available area is treated (and, conversely, not treated). Some applications (e.g., linking to spatially-explicit or highly--spatially-referenced models) require a spatially-explicit activity schedule. :py:mod:`ws3` includes a *spatial disturbance allocator* sub-module, which contains functions that can map aspatial multi-period action schedules onto a rasterized spatial representation of the forest. The spatial disturbance allocator is implemented using the :py:mod:`rasterio` package and is available as part of the :py:mod:`ws3.spatial` module. The area-based forest inventory input data for a :py:mod:`ws3` model is typically compiled by *aggregating* stands in a spatially explicity forest inventory data layer (i.e., by combining spatially discontiguous stands into area bins, grouping by stratum and age class). The spatial disturbance allocation functions are effectively *disaggregating* the aspatial disturbance schedule, restoring the spatial dimensionality of the forest inventory data layer. These same functions are also capable of *disaggregating* :py:mod:`ws3` output schedules from multi-year simulation periods into annual time steps (which is useful if you plan to pipe :py:mod:`ws3` output to a downstream spatially-explicit model that also operates on a smaller simulation time step than your source :py:mod:`ws3` model). Note that this disaggregation operation is always going to be somewhat problematic, because we are essentially fabricating details that are not represented in the source data. :py:mod:`ws3` uses a scripted Python interface to control the model, which provides maximum flexibility and makes it easy to automate modelling workflows. This ensures reproducible methodologies, and enables linking :py:mod:`ws3` input or outout to other software packages to form complex modelling pipelines. The scripted interface also makes it relatively easy to implement custom data-importing functions, which makes it easier to import existing data from a variety of ad-hoc sources without the need to recompile the data into a standard :py:mod:`ws3`-specific format (i.e., importing functions can be implemented such that the conversion process is fully automated and applied to raw input data *on the fly*). Similarly, users can easily implement custom functions to re-format :py:mod:`ws3` output data *on the fly* (either for static serialization to disk, or to be piped live into another process). Although we recommend using Jupyter Notebooks as an interactive interface to :py:mod:`ws3` (the package was specifically designed with an interactive notebook interface in mind), :py:mod:`ws3` functions can also be imported and run in fully scripted workflow (e.g., non-interactive batch processes can be run in a massively-paralleled workflow on high-performance--computing resources, if available). The ability to mix interactive and massively-paralleled non-interactive workflows is a unique feature of :py:mod:`ws3`. :py:mod:`ws3` is a complex and flexible collection of functional software units. The following sections describe some of the main classes and functions in the package, and describe some common use cases, and link to sample notebooks that implement these use cases. Overview of Main Classes and Functions ====================================== This section describes some of the main classes and functions that make up the :py:mod:`ws3` pacakge. The :py:class:`ws3.forest.ForestModel` class is the core class in the package. This class encapsulates all the information used to simulate scenarios from a given dataset (i.e., stratified initial inventory, growth and yield functions, action eligibility, transition matrix, action schedule, etc.), as well as a collection of functions to import and export data, generate activity schedules, and simulate application of these schedules (i.e., run scenarios). At the heart of the :py:class:`~ws3.forest.ForestModel` class is a list of :py:class:`ws3.forest.DevelopmentType` instances. Each :py:class:`~ws3.forest.DevelopmentType` instance encapsulates information about one development type (i.e., a forest stratum, which is an aggregate of smaller *stands* that make up the raw forest inventory input data). The :py:class:`~ws3.forest.DevelopmentType` class also stores a list of operable *actions*, maps *state variable transitions* to these actions, stores growth and yield functions, and knows how to *grow itself* when time is incremented during a simulation. .. To Do: Finish documenting main stuff here. Common Use Case and Sample Notebooks ==================================== In this section, we assume an interactive Jupyter Notebook environment is used to interface with :py:mod:`ws3`. A typical use case starts with creating an instance of the :py:class:`~ws3.forest.ForestModel` class. Then, we need to load data into this instance, define one or more scenarios (using a mix of heuristic and optimization approaches), run the scenarios, and export output data to a format suitable for analysis (or link to the next model in a larger modelling pipeline). The first step in a typical workflow is to run a mix of standard :py:mod:`ws3` and custom data-importing functions. These functions import data from various sources, *on-the-fly* reformat this data to be compatible with :py:mod:`ws3`, and load the reformated data into the :py:class:`~ws3.forest.ForestModel` instance using standard methods. For example, :py:mod:`ws3` includes functions to import legacy Woodstock [#]_ model data (including ``LANDSCAPE``, ``CONSTANTS``, ``AREAS``, ``YIELDS``, ``LIFESPAN``, ``ACTIONS``, ``TRANSITIONS``, and ``SCHEDULE`` section data), as well as functions to import and rasterize vector stand inventory data. For example, one might define the following custom Python function in a Jupyter Notebook, to import data formatted for Woodstock. .. code-block:: python from ws3.forest import ForestModel def instantiate_forestmodel(model_name, model_path, horizon, period_length, max_age, add_null_action=True): fm = ForestModel(model_name=model_name, model_path=model_path, horizon=horizon, period_length=period_length, max_age=max_age) fm.import_landscape_section() fm.import_areas_section() fm.import_yields_section() fm.import_actions_section() fm.add_null_action() fm.import_transitions_section() fm.reset_actions() fm.initialize_areas() fm.grow() return fm The next step in a typical workflow is to define one or more scenarios. Assuming that we are using an optimization approach to harvest scheduling, we need to define an objective function (e.g., maximize total harvest volume) and constraints (e.g., species-wise volume and area even-flow constraints, ending standing inventory constraints, periodic minimum late-seral-stage area constraints) [#]_, build the optimization model matrix, solve the model to optimality [#]_. .. [#] *Woodstock* is part of suite of `Forestry Planning and Scheduling `_ software tools offered by Remsoft. .. [#] :py:mod:`ws3` currently implements functions to formulate and solve *Model I* wood supply optimization problems---however, the package was deliberately designed to make it easy to transparently switch between *Model I* , *Model II* and *Model III* formulations without affecting the rest of the modelling workflow. ``ws3`` currently has placeholder function stubs for *Model II* and *Model III* formulations, which will be implemented in later versions as the need arises. For more information on wood supply model formulations, see Chapter 16 of the `Handbook of Operations Research in Natural Resources `_. .. [#] :py:mod:`ws3` currently defaults to the open source `PuLP `_ solver to solve linear programs, and also includes `Gurobi `_ solver bindings. :py:mod:`ws3` may eventually provide a pluggable interface to other solvers (e.g., CPLEX, GLPK, etc.).