Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 49 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,55 @@

See the [SEALS documentation](https://justinandrewjohnson.com/earth_economy_devstack/seals_overview.html) for full details.

## Developer notes
---

To manually (wihtout using github actions) push a new release to Pypi, run the following command:
## Getting Started

### Environment Setup

See [docs/environment_setup.md](docs/environment_setup.md) for detailed instructions.

Quick start:
```bash
python -m build
python -m twine upload dist/*
```
conda create -n hazelbean_env python=3.10
conda activate hazelbean_env
pip install hazelbean seals
```

### Project Setup

1. **Create project folder structure**
```bash
mkdir -p ~/Files/seals/projects/my_project/my_project_dev
```
- `my_project/` - runtime folder (not version controlled)
- `my_project_dev/` - version controlled code and inputs

2. **Copy and rename the run script**
```bash
cp seals_dev/run_seals_standard.py projects/my_project/my_project_dev/run_my_project.py
```

3. **Modify run_my_project.py**
- Set `project_name = 'my_project'`
- Set `project_dir = '..'` (parent of _dev folder)
- Set `input_data_dir = 'input/my_project_input'`
- Configure scenarios, years, AOI as needed

4. **Create version-controlled input folder**
```bash
mkdir -p my_project_dev/input/my_project_input
```

5. **Add your inputs** to `my_project_dev/input/my_project_input/`:
- [scenarios.csv](docs/scenarios_format.md) - scenario definitions

6. **Run the script**
```bash
conda activate hazelbean_env
cd my_project_dev
python run_my_project.py
```
This creates in `my_project/`:
- `input/` - copied from `my_project_dev/input/my_project_input/`
- `intermediate/` - SEALS outputs and results
38 changes: 38 additions & 0 deletions docs/environment_setup.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# SEALS Environment Setup

## 1. Install Miniforge/Conda

If not already installed, download and install [Miniforge](https://github.com/conda-forge/miniforge).

## 2. Create hazelbean environment

```bash
conda create -n hazelbean_env python=3.10
conda activate hazelbean_env
```

## 3. Install dependencies

**From PyPI:**
```bash
pip install hazelbean
pip install seals
```

**Or from source (for development):**
```bash
cd ~/Files/seals/hazelbean_dev
pip install -e .

cd ~/Files/seals/seals_dev
pip install -e .
```

Both methods install all dependencies automatically.

## 4. Activate environment

Always activate before running SEALS scripts:
```bash
conda activate hazelbean_env
```
43 changes: 43 additions & 0 deletions docs/scenarios_format.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# scenarios.csv Format

The `scenarios.csv` file defines your SEALS scenarios. Each row represents one scenario.

## Column Reference

| Column | Description | Example |
|--------|-------------|---------|
| `scenario_label` | Unique scenario identifier | `baseline`, `ssp2_rcp45` |
| `scenario_type` | `baseline` or `policy` | `baseline` |
| `aoi` | Area of interest | `global` or `from_regional_projections_input_path` |
| `exogenous_label` | Exogenous scenario name | `baseline` |
| `climate_label` | Climate scenario | `rcp45` |
| `model_label` | Model source | `gtap`, `magpie`, `luh2` |
| `counterfactual_label` | Counterfactual reference | `baseline` |
| `years` | Space-separated projection years | `2030 2050` |
| `baseline_reference_label` | Reference scenario for policy | `baseline` (blank for baseline) |
| `base_years` | Base year(s) | `2017` |
| `key_base_year` | Key base year for LULC | `2017` |
| `comparison_counterfactual_labels` | For comparisons | (usually blank) |
| `time_dim_adjustment` | Time adjustment | `add2015` |
| `coarse_projections_input_path` | Path to LUH2 data | `luh2/raw_data/rcp45_ssp2/...nc` |
| `lulc_src_label` | LULC source | `esa` |
| `lulc_simplification_label` | LULC class scheme | `seals7` |
| `lulc_correspondence_path` | LULC correspondence file | `seals/default_inputs/esa_seals7_correspondence.csv` |
| `coarse_src_label` | Coarse data source | `luh2-14` |
| `coarse_simplification_label` | Coarse class scheme | `seals7` |
| `coarse_correspondence_path` | Coarse correspondence file | `seals/default_inputs/luh2-14_seals7_correspondence.csv` |
| `lc_class_varname` | Land class variable | `all_variables` |
| `dimensions` | Dimensions | `time` |
| `calibration_parameters_source` | Calibration file | `seals/default_inputs/default_global_coefficients.csv` |
| `base_year_lulc_path` | Base year LULC raster | `lulc/esa/lulc_esa_2017.tif` |
| `regional_projections_input_path` | Regional projections CSV (optional) | `regional_projections/my_projections.csv` |
| `regions_vector_path` | Regions shapefile | `cartographic/countries_iso3_with_label.gpkg` |
| `regions_column_label` | Region column name | `iso3_label` |

## Example

```csv
scenario_label,scenario_type,aoi,exogenous_label,climate_label,model_label,counterfactual_label,years,baseline_reference_label,base_years,key_base_year,comparison_counterfactual_labels,time_dim_adjustment,coarse_projections_input_path,lulc_src_label,lulc_simplification_label,lulc_correspondence_path,coarse_src_label,coarse_simplification_label,coarse_correspondence_path,lc_class_varname,dimensions,calibration_parameters_source,base_year_lulc_path,regional_projections_input_path,regions_vector_path,regions_column_label
baseline,baseline,global,baseline,rcp45,luh2,baseline,2017,,2017,2017,,add2015,luh2/raw_data/rcp45_ssp2/multiple-states_input4MIPs_landState_ScenarioMIP_UofMD-MESSAGE-ssp245-2-1-f_gn_2015-2100.nc,esa,seals7,seals/default_inputs/esa_seals7_correspondence.csv,luh2-14,seals7,seals/default_inputs/luh2-14_seals7_correspondence.csv,all_variables,time,seals/default_inputs/default_global_coefficients.csv,lulc/esa/lulc_esa_2017.tif,,cartographic/countries_iso3_with_label.gpkg,iso3_label
ssp2_rcp45,policy,global,ssp2,rcp45,luh2,ssp2_rcp45,2030 2050,baseline,2017,2017,,add2015,luh2/raw_data/rcp45_ssp2/multiple-states_input4MIPs_landState_ScenarioMIP_UofMD-MESSAGE-ssp245-2-1-f_gn_2015-2100.nc,esa,seals7,seals/default_inputs/esa_seals7_correspondence.csv,luh2-14,seals7,seals/default_inputs/luh2-14_seals7_correspondence.csv,all_variables,time,seals/default_inputs/default_global_coefficients.csv,lulc/esa/lulc_esa_2017.tif,,cartographic/countries_iso3_with_label.gpkg,iso3_label
```
9 changes: 8 additions & 1 deletion seals/seals_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -715,7 +715,14 @@ def set_derived_attributes(p):
p.fine_resolution = hb.get_cell_size_from_path(p.base_year_lulc_path)
p.fine_resolution_arcseconds = hb.pyramid_compatible_resolution_to_arcseconds[p.fine_resolution]

if hb.path_exists(p.coarse_projections_input_path):
# Check for explicit coarse resolution from scenarios.csv column.
# Regional (non-global) NetCDFs need this because auto-detection assumes
# global extent (180/num_lat_cells) and computes wrong values.
explicit_coarse_resolution = getattr(p, 'coarse_resolution_arcseconds', None)
if explicit_coarse_resolution is not None:
p.coarse_resolution_arcseconds = float(explicit_coarse_resolution)
p.coarse_resolution = hb.pyramid_compatible_resolutions[p.coarse_resolution_arcseconds]
elif hb.path_exists(p.coarse_projections_input_path):
p.coarse_resolution = hb.get_cell_size_from_path(p.coarse_projections_input_path)
p.coarse_resolution_arcseconds = hb.pyramid_compatible_resolution_to_arcseconds[p.coarse_resolution]
else:
Expand Down