Walkthrough

Getting set up

  • Follow the installation page first.
  • This guide assumes you installed SEALS using the devstack layout — its own project folder under ~/Files/, with the repo inside it at ~/Files/seals/seals.

Explore the SEALS code

  • The repo root seals/ holds more than the library — docs, tests, scripts
  • The library itself is the seals/seals subdirectory. The nesting looks redundant but is how Python packaging works
  • Inside it, __init__.py is what makes the directory importable as a package
  • The modules are split by what they hold:
    • seals_main.py, seals_tasks.py, seals_generate_base_data.py — task functions, the actual model logic
    • seals_initialize_project.py — the task-tree builders
    • seals_utils.py — helpers
    • run_seals_standard.py — the run file

Run files

  • You do not run seals_main.py directly
  • A run file configures a project and executes a task tree built from the library’s task functions
  • Two ship with SEALS, both in seals/seals:
    • run_seals_standard.py — three scenarios, 2030 and 2050
    • run_seals_standard_test.py — the same pipeline pared to a baseline, one BAU scenario, one year, Rwanda. Start here
  • Open run_seals_standard.py. It is about 60 lines and has three parts

Part 1: the task tree

  • build_task_tree(p) answers one question: what is this pipeline?
  • It contains nothing but tree construction. For stock SEALS it is one line, delegating to the shared library builder
  • Compose extra library subtrees or your own tasks here if your project diverges
def build_task_tree(p):
    seals_initialize_project.build_standard_task_tree(p)

Part 2: run_project

  • run_project(p) answers how is it executed? It takes only p
  • The rule that decides what goes where:
    • run_project(p) sets what no variant ever changes — base data location, processing resolution
    • the caller sets what a variant might — project name, run mode, scenarios CSV
  • When a constant starts varying, it moves one line up into the caller. There is no signature to edit and no default to keep in sync
def run_project(p):
    p.run_in_parallel = 1        # before the tree: it has parallel iterators
    build_task_tree(p)
    p.skip_tasks(p.tasks_to_skip)

    p.base_data_dir = os.path.join(p.user_dir, 'Files', 'base_data')
    p.processing_resolution = 1.0

    p.scenario_definitions_path = os.path.join(p.input_dir, p.scenario_definitions_filename)
    seals_initialize_project.initialize_scenario_definitions(p)
    seals_initialize_project.set_advanced_options(p)

    p.execute()
    return p

Part 3: the __main__ guard

  • This is where the project is configured — two lines of actual choice
  • The guard is mandatory: importing a run file must never start a run. That is what lets a second run file import this pipeline instead of copying it
if __name__ == '__main__':
    p = hb.ProjectFlow(project_name='seals_standard', run_mode='check')
    p.scenario_definitions_filename = 'standard_scenarios.csv'

    run_project(p)

The p object

  • hb.ProjectFlow() is a class — a recipe for an object. Calling it produces an object, which we assign to p
  • p carries the project’s attributes: p.base_data_dir, p.scenario_definitions_filename, and so on
  • It also has methods that act on it: p.add_task(), p.skip_tasks(), p.get_path(), p.execute()
  • Every task receives p and reads its configuration from it. That is how configuration set in __main__ reaches code deep in the library

Where the project directory goes

  • Not into the repo. Because the run file sits inside a cloned repo, ProjectFlow places the project dir just outside it, at ~/Files/seals/projects/<project_name>/
  • You do not compute this path yourself, and you should not save data in seals/seals
  • run_mode decides how much prior work is reused:
    • 'check' — reuse the stable dir, recompute only what is missing (the default)
    • 'fresh_intermediate' — redo all computation, keep input/ (test projects only)
    • 'full' — a fresh timestamped dir; everything re-runs

Scenario definitions

The scenarios CSV

  • The scenarios CSV specifies the runs you want. Each row is one scenario
  • As the model iterates, it re-hydrates p from the row it is on — which is why scenario-varying values belong in the CSV and not in the run file
  • The tracked copy lives in input_template/ beside the run file. ProjectFlow copies anything missing into the project’s input/ on first run and never overwrites your working copy
  • If the named file is nowhere to be found, SEALS generates a default so a first run still works
p.scenario_definitions_filename = 'standard_scenarios.csv'

Scenario types

  • scenario_type is a column in the CSV, not something a run file sets
  • baseline — the observed anchor; not downscaled, supplies base-year LULC
  • policy — a trajectory to downscale, compared against a counterfactual
  • bau — business-as-usual, being deprecated in favour of baseline; it still appears in shipped CSVs
  • Full column reference: Custom scenarios

Automatically downloading data

  • Paths in the CSV are ref_paths — relative locations resolved by p.get_path(), which searches the project input/ dir, then base_data, then a cloud bucket, downloading what is missing
  • NOTE: The first run downloads a lot of data. The default bucket is public and requires no credentials, but it is large and the download may take hours. Also note that you may need to restart the run file after it all downloads.
  • p.base_data_dir is where those downloads land. Point it somewhere with room for very large files; the same base data serves every project
  • The directory must be named base_data to match the bucket convention
  • The default bucket is public — no credentials needed
p.base_data_dir = os.path.join(p.user_dir, 'Files', 'base_data')

Running it

Run the model

conda activate <your_env>
cd seals/seals
python run_seals_standard_test.py
  • On startup SEALS prints the task tree it is about to compute
  • To understand the model in depth, read the task functions behind those names
  • Run the same command a second time: it finishes almost immediately, because every task is behind an existence check and completed work is skipped

Find the output

  • Go to ~/Files/seals/projects/seals_standard_test/intermediate/
  • There is one directory per task in the tree
  • The downscaled maps are in stitched_lulc_simplified_scenarios/, for example:
lulc_esa_seals7_ssp2_rcp45_luh2-message_bau_2030.tif
  • Open it in QGIS alongside the base-year LULC and compare — that is your high-resolution land-use change projection

Next

SEALS is customized be adding or changing scenarios in the scenarios CSV. See Custom scenarios for the rules and conventions.