Skip to content
Merged
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -598,3 +598,6 @@ docs/source/inputs/yaml/schema/*.rst
worktrees/
test/precheck_testcase/run_precheck_testcase.py
test/precheck_testcase/precheck_testcase.py

# uv lockfile - for flexible dependency resolution
uv.lock
49 changes: 48 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

| Year | Features | Bugfixes | Changes | Maintenance | Docs | Total |
|------|----------|----------|---------|-------------|------|-------|
| 2025 | 26 | 13 | 3 | 26 | 12 | 80 |
| 2025 | 27 | 17 | 3 | 29 | 12 | 88 |
| 2024 | 12 | 17 | 1 | 12 | 1 | 43 |
| 2023 | 11 | 14 | 3 | 9 | 1 | 38 |
| 2022 | 15 | 18 | 0 | 7 | 0 | 40 |
Expand All @@ -34,6 +34,53 @@

## 2025

### 6 Aug 2025
- [maintenance] Moved legacy configuration files from sample_run to test fixtures
- **Moved to test/fixtures/legacy_format/** for conversion tool testing:
- 14 txt configuration files (SUEWS tables): ~85 KB
- 8 namelist (.nml) files: ~9 KB
- Total: 22 files, ~94 KB moved out of main package
- **Purpose**: These files are now test fixtures for:
- `supy-convert` command (table version converter)
- `supy-to-yaml` command (legacy to YAML converter)
- **Impact**:
- Reduces distributed package size by ~94 KB
- Maintains backward compatibility testing capability
- All runtime configuration now exclusively uses YAML (sample_config.yml)
- SPARTACUS, STEBBS, and ESTM configs fully integrated in YAML

- [change] Simplified `suews-convert` command interface with automatic conversion type detection
- Automatically determines conversion type based on target version:
- Versions before 2025 (e.g., 2024a): Table-to-table conversion
- Version 2025a or later: Convert to YAML format
- No subcommands needed - single unified interface
- Examples:
- `suews-convert -f 2020a -t 2024a -i input_dir -o output_dir` (table conversion)
- `suews-convert -f 2024a -t 2025a -i input_dir -o config.yml` (YAML conversion)
- Added missing cmd/to_yaml.py to meson.build sources (#566, #582)

- [bugfix] Fixed empty list handling in modify_df_init when STEBBS disabled
- Prevented DataFrame column name mismatch when no new columns to add

- [bugfix] Fixed missing column handling in from_df_state methods
- Added graceful handling of missing columns in legacy format conversion
- Affected classes: SiteProperties, ArchetypeProperties, StebbsProperties
- Missing columns now use default values from field definitions

- [bugfix] Fixed water surface soilstore validation constraint
- Water surfaces can now have soilstore=0 (physically correct)
- Override constraint in InitialStateWater class

- [bugfix] Fixed missing config/description columns in legacy conversion
- Added default values when converting from legacy format
- Default name: "Converted from legacy format"
- Default description: "Configuration converted from legacy SUEWS table format"
- Added to_yaml.py to meson.build for package installation
- Created test suite using legacy format fixtures
- [bugfix] Fixed STEBBS loading logic in _load.py
- Fixed incorrect dict access (was using path_runcontrol["fileinputpath"] instead of dict_runconfig["fileinputpath"])
- Skip STEBBS file loading when stebbsmethod=0 (disabled) to avoid missing test file dependencies

### 5 Aug 2025
- [doc] Fixed FAIMethod option descriptions inconsistency ([#578](https://github.com/UMEP-dev/SUEWS/issues/578))
- Updated Python data model FAIMethod enum to match Fortran implementation
Expand Down
35 changes: 27 additions & 8 deletions docs/source/inputs/tables/input_converter.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,42 @@ SUEWS input converter
********************************

.. note::
The SUEWS table converter has been integrated into SuPy as a command line tool :ref:`suews-convert` since v2020a.
Please install SuPy and run :ref:`suews-convert` to convert input tables from an older version to a newer one.
The SUEWS converter has been integrated into SuPy as a command line tool :ref:`suews-convert` since v2020a.
From v2025a onwards, SUEWS uses YAML format exclusively. The converter automatically determines the output format based on the target version.

Usage
-----

Please refer to the :ref:`SuPy API page <suews-convert>`.
.. code-block:: shell

suews-convert -f FROM_VERSION -t TO_VERSION -i INPUT_PATH -o OUTPUT_PATH

The converter automatically determines the conversion type:

- **Versions before 2025** (e.g., 2024a): Table-to-table conversion
- **Version 2025a or later**: Converts to YAML format

Parameters
----------

Example (from 2018a to 2020a)
-----------------------------
- ``-f, --from``: Source version (e.g., '2020a', '2024a')
- ``-t, --to``: Target version (e.g., '2024a' for tables, '2025a' for YAML)
- ``-i, --input``: Input directory containing SUEWS files (must have RunControl.nml)
- ``-o, --output``: Output path (directory for table conversion, file path for YAML)

Examples
--------

**Table-to-table conversion (pre-2025):**

.. code-block:: shell

suews-convert -f 2018a -t 2024a -i your_2018a_folder -o your_2024a_folder

Assuming your 2018a files are all included in the folder ``your_2018a_folder`` and your desirable converted files should be placed in a new folder ``your_2020a_folder``, please do the following in your command line tool:
**Table-to-YAML conversion (2025+):**

.. code-block:: shell

suews-convert -f 2018a -t 2020a -i your_2018a_folder -o your_2020a_folder
suews-convert -f 2024a -t 2025a -i your_2024a_folder -o config.yml

.. tip:: `suews-convert` will use the ``RunControl.nml`` file in your original folder to determine the location of input tables.
.. tip:: The converter will use the ``RunControl.nml`` file in your input folder to determine the location of input tables.
74 changes: 50 additions & 24 deletions docs/source/inputs/transition_guide.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,17 @@ Transitioning to YAML-based Configuration

As of 2025, SUEWS has adopted a new YAML-based format for input files to enhance readability, maintainability, and user experience. To help users migrate their existing table-based input files to this new format, a transition tool is provided.

This guide explains how to use the ``to_yaml`` command-line tool to automate the conversion process.
This guide explains how to use the ``suews-convert`` command-line tool to automate the conversion process.

The transition process involves two main steps, which are handled automatically by the tool:
The ``suews-convert`` tool automatically determines the appropriate conversion based on the target version:

1. **Table Version Update (Optional)**: If you are using input files from an older version of SUEWS, the tool first converts them to the latest available table-based format.
2. **Conversion to YAML**: The tool then reads the complete set of (updated) table-based inputs and converts them into a single, comprehensive ``config_suews.yml`` file.
- **Versions before 2025** (e.g., 2024a): Performs table-to-table conversion
- **Version 2025a or later**: Converts to YAML format

When converting to YAML (2025+), the process involves two main steps:

1. **Table Version Update (if needed)**: If you are using input files from an older version of SUEWS, the tool first converts them to the latest available table-based format.
2. **Conversion to YAML**: The tool then reads the complete set of (updated) table-based inputs and converts them into a single, comprehensive YAML file.

Prerequisites
-------------
Expand All @@ -20,49 +25,70 @@ Ensure that ``supy`` is installed in your Python environment. The transition too
Using the Transition Tool
-------------------------

The transition tool, ``to_yaml.py``, is a command-line script. You can run it as a Python module.
The ``suews-convert`` command is installed with the ``supy`` package and can be run directly from the command line.

.. code-block:: bash

python -m supy.cmd.to_yaml [OPTIONS]
suews-convert [OPTIONS]

Command-Line Options
~~~~~~~~~~~~~~~~~~~~

The tool accepts the following arguments:

* ``-i, --input-dir PATH``: **(Required)** The directory containing your existing SUEWS table-based input files. This directory must include a ``RunControl.nml`` file.
* ``-o, --output-file PATH``: **(Required)** The full path for the output YAML file that will be created (e.g., ``/path/to/my/project/config_suews.yml``).
* ``-f, --from-ver TEXT``: (Optional) The version of your source input files (e.g., ``2020a``). If specified, the tool will first convert the tables to the latest supported version before creating the YAML file.
* ``-f, --from VERSION``: **(Required)** The version of your source input files (e.g., ``2020a``, ``2024a``).
* ``-t, --to VERSION``: **(Required)** The target version. Use ``2025a`` or later versions to convert to YAML format.
* ``-i, --input PATH``: **(Required)** The directory containing your existing SUEWS table-based input files. This directory must include a ``RunControl.nml`` file.
* ``-o, --output PATH``: **(Required)** The output path:
- For table conversion (pre-2025): Directory for the converted tables
- For YAML conversion (2025+): Path for the output YAML file

Examples
--------

Example 1: Converting Up-to-Date Tables
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Example 1: Converting to YAML (2025a)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

If your table-based input files are already up-to-date (i.e. after v2025a), you can convert them directly to YAML without specifying version numbers.
To convert table-based input files to the modern YAML format, use version ``2025a`` or later as the target.

Suppose your input files are located in a directory called ``/path/to/suews_run_london/Input``.
Suppose your input files are from version ``2024a`` and located in ``/path/to/suews_run_london/Input``:

.. code-block:: bash

python -m supy.cmd.to_yaml \
--input-dir /path/to/suews_run_london/Input \
--output-file /path/to/suews_run_london/config_london.yml
suews-convert \
-f 2024a \
-t 2025a \
-i /path/to/suews_run_london/Input \
-o /path/to/suews_run_london/config_london.yml

The tool will read the files from the input directory and create ``config_london.yml`` in the specified location.

Example 2: Converting Older Tables
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Example 2: Converting Older Tables to YAML
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

If you have input files from an older SUEWS version (e.g., ``2019b``), you can convert them directly to YAML:

.. code-block:: bash

suews-convert \
-f 2019b \
-t 2025a \
-i /path/to/old_suews_run/Input_v2019b \
-o /path/to/old_suews_run/config_new.yml

The tool will first update the tables from ``2019b`` to the latest table format in a temporary location, and then convert these to YAML.

Example 3: Table-to-Table Conversion (Pre-2025)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

If you have input files from an older SUEWS version (e.g., v2019b), you can specify the source version, and the tool will automatically convert them to the latest available table format before generating the YAML file.
For converting between table versions without creating YAML, use a target version before 2025:

.. code-block:: bash

python -m supy.cmd.to_yaml \
--input-dir /path/to/old_suews_run/Input_v2019b \
--output-file /path/to/old_suews_run/config_new.yml \
--from-ver 2019b
suews-convert \
-f 2020a \
-t 2024a \
-i /path/to/suews_run/Input_v2020a \
-o /path/to/suews_run/Input_v2024a

The tool will first run the table converter to update the files from ``v2019b`` to the latest version in a temporary location, and then use these updated files to generate ``config_new.yml``.
This will convert the tables from ``2020a`` to ``2024a`` format, creating the updated tables in the specified output directory.
2 changes: 1 addition & 1 deletion docs/source/sub-tutorials/tutorials.rst
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,6 @@ Migration from Legacy SUEWS

If you're transitioning from table-based SUEWS to modern SuPy:

1. **Use the conversion tool**: ``suews-convert to-yaml -i legacy_input_dir/ -o config.yml``
1. **Use the conversion tool**: ``suews-convert -f 2024a -t 2025a -i legacy_input_dir/ -o config.yml``
2. **Follow the migration guide**: :doc:`../inputs/transition_guide`
3. **Start with sample data**: The :doc:`../tutorials/python/quick-start` tutorial shows modern approaches
2 changes: 1 addition & 1 deletion docs/source/tutorials/python/tutorial.rst
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ SUEWS uses YAML configuration files for type-safe, hierarchical parameter manage
`GitHub Issues <https://github.com/UMEP-dev/SUEWS/issues>`__.

- **Sample configurations**: Available in `tutorials directory <./>`__
- **Migration tool**: Convert legacy inputs with ``suews-convert to-yaml``
- **Migration tool**: Convert legacy inputs with ``suews-convert -f 2024a -t 2025a``

**Data Integration:**
- **Built-in sample data**: ``sp.load_sample_data()`` for immediate use
Expand Down
4 changes: 2 additions & 2 deletions docs/source/workflow.rst
Original file line number Diff line number Diff line change
Expand Up @@ -529,8 +529,8 @@ Migration Process

.. code-block:: bash

# Convert legacy table inputs to modern YAML
suews-convert to-yaml -i legacy_input_dir/ -o modern_config.yml
# Convert legacy table inputs to modern YAML (2025a+)
suews-convert -f 2024a -t 2025a -i legacy_input_dir/ -o modern_config.yml

# Validate converted configuration
supy-validate modern_config.yml
Expand Down
43 changes: 22 additions & 21 deletions src/supy/_load.py
Original file line number Diff line number Diff line change
Expand Up @@ -1384,33 +1384,31 @@ def load_SUEWS_dict_ModConfig(path_runcontrol, dict_default=dict_RunControl_defa
def load_SUEWS_dict_Stebbs(path_runcontrol, dict_runconfig):
# load STEBBS-specific variables:
stebbs_dict = {}

# Only load STEBBS files if STEBBS is enabled (stebbsmethod == 2)
if dict_runconfig["stebbsmethod"] == 2:
path_stebbs_typologies = (
path_runcontrol.parent
/ path_runcontrol["fileinputpath"]
/ dict_runconfig["fileinputpath"]
/ "stebbs_building_typologies.nml"
)
path_stebbs_general = (
path_runcontrol.parent
/ path_runcontrol["fileinputpath"]
/ dict_runconfig["fileinputpath"]
/ "stebbs_general_params.nml"
)
else:
path_stebbs_typologies = (
trv_supy_module
/ "sample_run"
/ "Input"
/ "test_stebbs_building_typologies.nml"
)
path_stebbs_general = (
trv_supy_module / "sample_run" / "Input" / "test_stebbs_general_params.nml"
)

stebbs_dict_y = {k[0]: v for k, v in load_SUEWS_nml(path_stebbs_typologies).items()}
stebbs_dict.update(stebbs_dict_y)
stebbs_dict_y = {
k[0]: v for k, v in load_SUEWS_nml(path_stebbs_typologies).items()
}
stebbs_dict.update(stebbs_dict_y)

stebbs_dict_z = {k[0]: v for k, v in load_SUEWS_nml(path_stebbs_general).items()}
stebbs_dict.update(stebbs_dict_z)
stebbs_dict_z = {
k[0]: v for k, v in load_SUEWS_nml(path_stebbs_general).items()
}
stebbs_dict.update(stebbs_dict_z)
# For stebbsmethod == 0 or 1, return empty dict (STEBBS disabled)
# Previously this tried to load test files which are now in test fixtures

return stebbs_dict

Expand Down Expand Up @@ -1634,13 +1632,16 @@ def modify_df_init(df_init, list_var_dim):
dict_col_new[(var, ind)] = df_init_mod[val].values.reshape(len_df)
else:
dict_col_new[(var, ind)] = np.repeat(val, len_df)
df_col_new = pd.DataFrame(dict_col_new, index=df_init_mod.index)

# Update column names to match df_init
df_col_new.columns.names = df_init.columns.names
# Only proceed if we have new columns to add
if dict_col_new:
df_col_new = pd.DataFrame(dict_col_new, index=df_init_mod.index)

# Update column names to match df_init
df_col_new.columns.names = df_init.columns.names

# 2. merge new columns into original dataframe
df_init_mod = df_init_mod.merge(df_col_new, left_index=True, right_index=True)
# 2. merge new columns into original dataframe
df_init_mod = df_init_mod.merge(df_col_new, left_index=True, right_index=True)

return df_init_mod

Expand Down
Loading