From aada72aa02005d766b87976368c44bb932d36f4d Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 2 Sep 2026 12:36:15 -0400 Subject: [PATCH 1/4] Fix the programmatic path documentation in README Signed-off-by: Davey Elder --- README.md | 54 ++++++++++++++++++++++++++++++++++++---------------- temoa/cli.py | 4 ++-- 2 files changed, 40 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 6486c09a3..c2c590899 100644 --- a/README.md +++ b/README.md @@ -152,29 +152,51 @@ uv run temoa tutorial # Create tutorial files You can use Temoa as a Python library: ```python -import temoa +from logging import getLogger from pathlib import Path -from temoa import TemoaModel, TemoaConfig, TemoaMode +from temoa._internal.temoa_sequencer import TemoaSequencer +from temoa.core.config import TemoaConfig +from temoa.core.modes import TemoaMode +from temoa.cli import setup_logging +from pyomo.environ import value, check_optimal_termination -# Create configuration +output_path = Path("output_files/my_run") +output_path.mkdir(parents=True, exist_ok=True) + +setup_logging(output_path, debug=False, silent=False) + +logger = getLogger(__name__) + +# OPTION 1: build the config in code config = TemoaConfig( - scenario="my_scenario", + scenario='zulu', scenario_mode=TemoaMode.PERFECT_FORESIGHT, - input_database=Path("path/to/input.db"), - output_database=Path("path/to/output.db"), - output_path=Path("path/to/output"), - solver_name="appsi_highs" + time_sequencing='seasonal_timeslices', + input_database='tutorial_database.sqlite', + output_database='tutorial_database.sqlite', + solver_name='appsi_highs', + output_path=output_path, + silent=False, ) +# OPTION 2: load the config from a file +config = TemoaConfig.build_config( + config_file='tutorial_config.toml', + output_path=output_path, + silent=False, +) + +ts = TemoaSequencer(config=config) +ts.start() -# Build and solve model -model = TemoaModel(config) -result = model.run() # Equivalent to: temoa run tutorial_config.toml +solved_instance = ts.pf_solved_instance # solved Temoa instance with solution values +solver_results = ts.pf_results # information from the solver -# Check if run was successful -if result: - print("Model solved successfully!") -else: - print("Model failed to solve") +# Example code usage of the solved instance and solver results +logger.info(f"Solver results: {solver_results['solver']}") +if check_optimal_termination(solver_results): + logger.info(f"Model solved! Objective value: {value(solved_instance.total_cost):.2f}") + built_capacity = value(solved_instance.v_new_capacity['utopia', 'E51', 2010]) + logger.info(f"Built {built_capacity:.2f} GW of storage in 2010") ``` ## Database Setup diff --git a/temoa/cli.py b/temoa/cli.py index 9feee14d4..418e7250d 100644 --- a/temoa/cli.py +++ b/temoa/cli.py @@ -31,7 +31,7 @@ def _create_output_folder() -> Path: return output_path -def _setup_logging(output_path: Path, debug: bool = False, silent: bool = False) -> None: +def setup_logging(output_path: Path, debug: bool = False, silent: bool = False) -> None: """Set up logging with different levels for console and file.""" # The root logger should be set to the most verbose level required by any handler. # The file handler will always be more verbose than the console in silent mode. @@ -90,7 +90,7 @@ def _setup_sequencer( final_output_path.mkdir(parents=True, exist_ok=True) # Pass the silent flag to the logging setup - _setup_logging(final_output_path, debug=debug, silent=silent) + setup_logging(final_output_path, debug=debug, silent=silent) config = TemoaConfig.build_config( config_file=config_file, output_path=final_output_path, silent=silent From 251822bbad140757a590ba3fa89b6e0f6283dc1b Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 2 Sep 2026 12:36:33 -0400 Subject: [PATCH 2/4] Fix tutorial config to stop trying to save duals with appsi Signed-off-by: Davey Elder --- temoa/tutorial_assets/config_sample.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/temoa/tutorial_assets/config_sample.toml b/temoa/tutorial_assets/config_sample.toml index df3d7b20a..f903f330d 100644 --- a/temoa/tutorial_assets/config_sample.toml +++ b/temoa/tutorial_assets/config_sample.toml @@ -87,7 +87,7 @@ solver_name = "appsi_highs" save_excel = true # save the duals in the output Database (may slow execution slightly?) -save_duals = true +save_duals = false # save storage levels by time slice (may be a large amount of data) save_storage_levels = true From 16d52e2c15320c152ce566251746fb38fa495a34 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 3 Sep 2026 11:12:02 -0400 Subject: [PATCH 3/4] Touch up the sample script Signed-off-by: Davey Elder --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index c2c590899..bb82b76a9 100644 --- a/README.md +++ b/README.md @@ -169,18 +169,18 @@ logger = getLogger(__name__) # OPTION 1: build the config in code config = TemoaConfig( - scenario='zulu', + scenario="zulu", scenario_mode=TemoaMode.PERFECT_FORESIGHT, - time_sequencing='seasonal_timeslices', - input_database='tutorial_database.sqlite', - output_database='tutorial_database.sqlite', - solver_name='appsi_highs', + time_sequencing="seasonal_timeslices", + input_database="tutorial_database.sqlite", + output_database="tutorial_database.sqlite", + solver_name="appsi_highs", output_path=output_path, silent=False, ) # OPTION 2: load the config from a file config = TemoaConfig.build_config( - config_file='tutorial_config.toml', + config_file=Path("tutorial_config.toml"), output_path=output_path, silent=False, ) @@ -192,10 +192,10 @@ solved_instance = ts.pf_solved_instance # solved Temoa instance with solution va solver_results = ts.pf_results # information from the solver # Example code usage of the solved instance and solver results -logger.info(f"Solver results: {solver_results['solver']}") +logger.info(f"Solver results: {solver_results["solver"]}") if check_optimal_termination(solver_results): logger.info(f"Model solved! Objective value: {value(solved_instance.total_cost):.2f}") - built_capacity = value(solved_instance.v_new_capacity['utopia', 'E51', 2010]) + built_capacity = value(solved_instance.v_new_capacity["utopia", "E51", 2010]) logger.info(f"Built {built_capacity:.2f} GW of storage in 2010") ``` From 62486557ef5331e306081f616d37f7235c430f5c Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 3 Sep 2026 15:22:17 -0400 Subject: [PATCH 4/4] Improve commenting Signed-off-by: Davey Elder --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index bb82b76a9..55196dbe4 100644 --- a/README.md +++ b/README.md @@ -167,6 +167,10 @@ setup_logging(output_path, debug=False, silent=False) logger = getLogger(__name__) +# ====================================================================== +# Choose ONE of the following two options for configuring the model run: +# ====================================================================== + # OPTION 1: build the config in code config = TemoaConfig( scenario="zulu", @@ -186,8 +190,9 @@ config = TemoaConfig.build_config( ) ts = TemoaSequencer(config=config) -ts.start() +ts.start() # TemoaSequencer runs the model and handles results +# Results are saved to your output_database but can also be accessed in code, here solved_instance = ts.pf_solved_instance # solved Temoa instance with solution values solver_results = ts.pf_results # information from the solver