Chapter 11: Building Models with FEMIC ====================================== Learning Objectives ------------------- After reading this chapter, you should be able to: - Explain what FEMIC is and how it relates to ws3 - Create a FEMIC instance (a complete, runnable forest estate model) - Use FEMIC's pipeline and workflow system to automate model building - Bridge FEMIC instances to ws3 for simulation and optimization - Understand the FEMIC configuration and parameter system What Is FEMIC? -------------- **FEMIC** (Forest Estate Modeling Integrated Components) is a framework for building, configuring, and running forest estate models. While ws3 provides the low-level simulation and optimization engine, FEMIC provides the higher-level infrastructure to: 1. **Define instances**: A FEMIC "instance" is a complete, self-contained forest estate model — inventory, growth curves, actions, constraints, and parameters — all configured and ready to run. 2. **Automate model building**: Pipelines and workflows handle the tedious parts: loading inventory data, generating development types, fitting growth curves, defining actions and transitions. 3. **Ensure reproducibility**: Instances are defined by configuration files, not interactive sessions. Run the same instance twice and get the same results. 4. **Bridge to ws3**: FEMIC instances can be materialized into ws3 :py:class:`ws3.forest.ForestModel` objects for simulation and optimization. .. mermaid:: graph TD CONFIG["FEMIC Instance
Configuration"] --> PIPELINE["Pipeline
(automated build)"] PIPELINE --> INSTANCE["Instance
(complete model)"] INSTANCE --> WS3["ws3 ForestModel
(simulation/optimization)"] WS3 --> RESULTS["Results
(schedule, NPV, etc.)"] The Instance Concept -------------------- A **FEMIC instance** is the central unit of work. It represents a complete forest estate model for a specific area of interest, with all parameters defined. Think of it as a "model recipe" — you can instantiate the same recipe for different areas or scenarios. .. code-block:: python from femic.instance_bootstrap import bootstrap_instance from femic.instance_context import InstanceContext # Bootstrap an instance from configuration instance = bootstrap_instance( instance_name="my_fmu", area_of_interest="data/aoi.shp", inventory="data/inventory.geojson" ) # The instance now contains: # - Development types (from inventory) # - Growth curves (from vdyp parameters) # - Actions and transitions # - Model parameters (horizon, period length, etc.) # Inspect the instance print(f"Development types: {len(instance.development_types)}") # Total area is computed from the instance's development type areas total_area = sum(dt.area for dt in instance.development_types) print(f"Total area: {total_area:.1f} ha") print(f"Horizon: {instance.horizon} periods") Pipelines --------- **Pipelines** automate the process of building an instance from raw data. A pipeline is a sequence of steps that transform inventory data into a complete model. Common pipeline steps: 1. **Data loading**: Read inventory from GeoJSON, shapefile, or CSV 2. **Aggregation**: Group inventory records into development types 3. **Curve fitting**: Generate growth curves from inventory data or provincial yield tables 4. **Action definition**: Define management actions and transitions 5. **Validation**: Check the instance for consistency .. code-block:: python from femic.pipeline import Pipeline # Define a pipeline pipeline = Pipeline( steps=[ "load_inventory", "aggregate_development_types", "fit_growth_curves", "define_actions", "validate_instance" ] ) # Run the pipeline instance = pipeline.run( inventory="data/inventory.geojson", output_dir="output/my_instance" ) Workflows --------- **Workflows** orchestrate multiple pipelines and instances. A workflow defines the overall modeling process: build the base model, run scenarios, compare results. .. code-block:: python from femic.workflows import Workflow # Define a workflow with multiple scenarios workflow = Workflow( name="harvest_scenarios", scenarios=[ {"name": "baseline", "params": {"max_harvest": 200}}, {"name": "conservation", "params": {"max_harvest": 100}}, {"name": "intensive", "params": {"max_harvest": 400}} ] ) # Run all scenarios results = workflow.run() # Compare results for scenario_name, result in results.items(): print(f"{scenario_name}: NPV = ${result.npv:,.0f}") The FEMIC-to-ws3 Bridge ----------------------- FEMIC provides a bridge to convert instances into ws3 models: .. code-block:: python from femic.ws3_bridge import instance_to_ws3_model # Convert a FEMIC instance to a ws3 ForestModel ws3_model = instance_to_ws3_model(instance) # Now use ws3 for simulation # Simulation proceeds by resetting actions, applying them, and growing: # ws3_model.reset_actions() # # apply actions for each period... # ws3_model.grow(start_period=1) # Query results via ws3_model.dtypes[key].area(period) # Or for optimization from ws3.opt import Problem prob = Problem("femic_opt") # ... build optimization problem using ws3_model ... prob.solver("highs") prob.solve() This bridge ensures that the complex configuration defined in FEMIC translates correctly into ws3's data structures. FreshForge Integration ---------------------- FEMIC integrates with **FreshForge**, a tool for materializing and managing model configurations. FreshForge handles: - Parameter versioning and tracking - Configuration templating - Reproducible environment setup .. code-block:: python from femic.freshforge import FreshForgeMaterializer # Materialize a configuration from FreshForge materializer = FreshForgeMaterializer( config_repo="freshforge_configs", config_version="v1.2.0" ) instance = materializer.materialize( template="bc_fmu_template", parameters={"fmu_name": "my_fmu", "horizon": 20} ) Configuration Files ------------------- FEMIC instances are typically defined by configuration files: .. code-block:: yaml # instance_config.yaml instance: name: my_fmu area_of_interest: data/aoi.shp horizon: 20 period_length: 5 inventory: source: data/inventory.geojson aggregation: keys: [species, site_index] min_area: 10.0 curves: volume: source: provincial_yield_tables species_mapping: Douglas-fir: Pseudotsuga menziesii Spruce: Picea sitchensis actions: - code: HARV descr: Clearcut harvest transitions: DF-SI50: Bare SP-SI40: Bare - code: PLNT descr: Plant after harvest transitions: Bare: DF-SI50 Best Practices -------------- 1. **Version your configurations**: Use FreshForge to track configuration changes over time 2. **Test instances before running**: Use FEMIC's validation to catch errors early 3. **Use pipelines for reproducibility**: Don't build instances interactively 4. **Separate data from configuration**: Keep inventory data separate from model parameters 5. **Document your instances**: Include metadata about the area, data sources, and assumptions Exercises --------- **Exercise 1 (Easy)**: Create a FEMIC instance from a sample inventory dataset and print the development type summary. **Exercise 2 (Medium)**: Build a pipeline that loads inventory data, aggregates into development types, and fits growth curves. **Exercise 3 (Hard)**: Create a workflow that runs three harvest scenarios (baseline, conservation, intensive) and compares their NPV outcomes. Further Reading --------------- - :doc:`ch12_fhops_integration` — Using fhops for harvest cost curves - :doc:`ch13_freshforge` — Automating workflows with FreshForge - :doc:`/textbook/ch18_carbon_accounting` — Carbon accounting - FEMIC documentation: https://femic.readthedocs.io