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
282 changes: 282 additions & 0 deletions docs/examples/io_operations.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,282 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "0",
"metadata": {},
"source": [
"# Input/Output Operations\n",
"\n",
"This notebook demonstrates how to perform input/output operations with SMS++ networks using pySMSpp.\n",
"In particular, it shows how to:\n",
"\n",
"1. Load an existing SMS++ network from a NetCDF file\n",
"2. Create a new SMS++ network programmatically\n",
"3. Save a network to a NetCDF file\n",
"4. Reload a saved network and verify its contents\n",
"\n",
"SMS++ stores models in [NetCDF4](https://www.unidata.ucar.edu/software/netcdf/) files (`.nc` or `.nc4`),\n",
"a self-describing, machine-independent data format designed for array-oriented scientific data."
]
},
{
"cell_type": "markdown",
"id": "1",
"metadata": {},
"source": [
"## Setup\n",
"\n",
"First, let's import the necessary modules."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2",
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"import tempfile\n",
"\n",
"import numpy as np\n",
"\n",
"from pysmspp import Block, SMSFileType, SMSNetwork, Variable"
]
},
{
"cell_type": "markdown",
"id": "3",
"metadata": {},
"source": [
"## Loading a Network from a File\n",
"\n",
"An existing SMS++ network stored in a NetCDF file can be loaded by passing the file path to the\n",
"`SMSNetwork` constructor. pySMSpp reads the file and reconstructs the full block hierarchy in memory."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4",
"metadata": {},
"outputs": [],
"source": [
"# Load a sample network from a NetCDF file\n",
"network_path = \"../../test/test_data/microgrid_ALLbutStore_1N.nc4\"\n",
"\n",
"net = SMSNetwork(network_path)\n",
"print(\"Network loaded successfully!\")\n",
"net"
]
},
{
"cell_type": "markdown",
"id": "5",
"metadata": {},
"source": [
"After loading, you can inspect the network structure with `print_tree()`."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6",
"metadata": {},
"outputs": [],
"source": [
"net.print_tree(show_attributes=True)"
]
},
{
"cell_type": "markdown",
"id": "7",
"metadata": {},
"source": [
"## Creating a Network Programmatically\n",
"\n",
"A new SMS++ network can be built from scratch using the `SMSNetwork` and `Block` classes.\n",
"In this example, we create a simple unit commitment network with a single thermal generator."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8",
"metadata": {},
"outputs": [],
"source": [
"# Create an empty network with block-file format\n",
"sn = SMSNetwork(file_type=SMSFileType.eBlockFile)\n",
"\n",
"# Add a UCBlock with a 24-hour time horizon and constant demand of 50 kW\n",
"sn.add(\n",
" \"UCBlock\",\n",
" \"Block_0\",\n",
" id=\"0\",\n",
" TimeHorizon=24,\n",
" NumberUnits=1,\n",
" NumberElectricalGenerators=1,\n",
" NumberNodes=1,\n",
" ActivePowerDemand=Variable(\n",
" \"ActivePowerDemand\",\n",
" \"float\",\n",
" (\"NumberNodes\", \"TimeHorizon\"),\n",
" np.full((1, 24), 50.0),\n",
" ),\n",
")\n",
"\n",
"# Add a thermal generator to the UCBlock\n",
"thermal_unit = Block().from_kwargs(\n",
" block_type=\"ThermalUnitBlock\",\n",
" MinPower=Variable(\"MinPower\", \"float\", (), 0.0),\n",
" MaxPower=Variable(\"MaxPower\", \"float\", (), 100.0),\n",
" LinearTerm=Variable(\"LinearTerm\", \"float\", (), 0.3),\n",
" InitUpDownTime=Variable(\"InitUpDownTime\", \"int\", (), 1),\n",
")\n",
"sn.blocks[\"Block_0\"].add(\"ThermalUnitBlock\", \"UnitBlock_0\", block=thermal_unit)\n",
"\n",
"print(\"Network created successfully!\")\n",
"sn.print_tree(show_dimensions=True)"
]
},
{
"cell_type": "markdown",
"id": "9",
"metadata": {},
"source": [
"## Saving a Network to a File\n",
"\n",
"Any `SMSNetwork` (or `Block`) can be serialized to a NetCDF file using the `to_netcdf()` method.\n",
"By default, `to_netcdf()` raises an error if the target file already exists; pass `force=True` to\n",
"overwrite it."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "10",
"metadata": {},
"outputs": [],
"source": [
"# Save the newly created network to a temporary file\n",
"with tempfile.TemporaryDirectory() as tmpdir:\n",
" output_path = os.path.join(tmpdir, \"my_network.nc4\")\n",
"\n",
" sn.to_netcdf(output_path)\n",
" print(f\"Network saved to: {output_path}\")\n",
" print(f\"File size: {os.path.getsize(output_path)} bytes\")\n",
"\n",
" # --- Reload and verify ---\n",
" reloaded = SMSNetwork(output_path)\n",
" print(\"\\nReloaded network:\")\n",
" reloaded.print_tree(show_dimensions=True)"
]
},
{
"cell_type": "markdown",
"id": "11",
"metadata": {},
"source": [
"The `force=True` flag can be used to overwrite an existing file:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "12",
"metadata": {},
"outputs": [],
"source": [
"with tempfile.TemporaryDirectory() as tmpdir:\n",
" output_path = os.path.join(tmpdir, \"my_network.nc4\")\n",
"\n",
" # First save\n",
" sn.to_netcdf(output_path)\n",
"\n",
" # Overwrite with force=True\n",
" sn.to_netcdf(output_path, force=True)\n",
" print(\"File overwritten successfully with force=True.\")"
]
},
{
"cell_type": "markdown",
"id": "13",
"metadata": {},
"source": [
"## Round-Trip: Save and Reload an Existing Network\n",
"\n",
"A common workflow is to load a network, modify it, and save the updated version.\n",
"The example below loads the sample network, saves it under a new name, and verifies\n",
"that the reloaded copy has the same structure."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "14",
"metadata": {},
"outputs": [],
"source": [
"with tempfile.TemporaryDirectory() as tmpdir:\n",
" resaved_path = os.path.join(tmpdir, \"resaved_network.nc4\")\n",
"\n",
" # Load the original network\n",
" original = SMSNetwork(network_path)\n",
"\n",
" # Save it to a new file\n",
" original.to_netcdf(resaved_path)\n",
"\n",
" # Reload the saved file\n",
" reloaded = SMSNetwork(resaved_path)\n",
"\n",
" # Compare top-level block names\n",
" original_blocks = list(original.blocks.keys())\n",
" reloaded_blocks = list(reloaded.blocks.keys())\n",
"\n",
" print(\"Original blocks :\", original_blocks)\n",
" print(\"Reloaded blocks :\", reloaded_blocks)\n",
" print(\"Blocks match :\", original_blocks == reloaded_blocks)"
]
},
{
"cell_type": "markdown",
"id": "15",
"metadata": {},
"source": [
"## Summary\n",
"\n",
"This notebook demonstrated:\n",
"\n",
"1. **Loading** an SMS++ network from a NetCDF file with `SMSNetwork(fp)`\n",
"2. **Creating** a network programmatically using `SMSNetwork`, `Block`, and `Variable`\n",
"3. **Saving** a network to a NetCDF file with `to_netcdf(fp)` (and `force=True` to overwrite)\n",
"4. **Reloading** a saved network and verifying its contents\n",
"\n",
"These operations form the foundation of any pySMSpp workflow: you can build models in Python,\n",
"persist them to disk, and exchange them with the SMS++ solver or other tools."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "",
"language": "python",
"name": ""
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.0"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
11 changes: 11 additions & 0 deletions docs/examples/ucblock_2thermal_line.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -272,11 +272,13 @@
") # path to the template solver config file \"uc_solverconfig\"\n",
"temporary_smspp_file = \"./2buses_2thermal.nc\" # path to temporary SMS++ file\n",
"output_file = \"./2buses_2thermal.txt\" # path to the output file (optional)\n",
"fp_solution = \"./fp_solution_2buses_2thermal.nc4\" # path to the file where the full problem solution will be saved (optional). When provided, the result.solution object will be populated with the SMS++ solution object\n",
"\n",
"result = sn.optimize(\n",
" configfile,\n",
" temporary_smspp_file,\n",
" output_file,\n",
" fp_solution=fp_solution,\n",
")"
]
},
Expand Down Expand Up @@ -306,6 +308,15 @@
"source": [
"result.log"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"result.solution"
]
}
],
"metadata": {
Expand Down
20 changes: 20 additions & 0 deletions docs/examples/ucblock_thermal_1bus.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -141,11 +141,13 @@
") # path to the template solver config file \"uc_solverconfig\"\n",
"temporary_smspp_file = \"./smspp_temp_file.nc\" # path to temporary SMS++ file\n",
"output_file = \"./smspp_output.txt\" # path to the output file (optional)\n",
"fp_solution = \"./fp_solution.nc4\" # path to the file where the full problem solution will be saved (optional). When provided, the result.solution object will be populated with the SMS++ solution object\n",
"\n",
"result = sn.optimize(\n",
" configfile,\n",
" temporary_smspp_file,\n",
" output_file,\n",
" fp_solution=fp_solution,\n",
")\n",
"\n",
"print(\"Optimization finished.\")"
Expand All @@ -172,6 +174,24 @@
"print(\"Status:\", result.status)\n",
"print(\"Objective value:\", result.objective_value)"
]
},
{
"cell_type": "markdown",
"id": "11",
"metadata": {},
"source": [
"View the solution object saved in `fp_solution` and automatically read in the `result` object"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "12",
"metadata": {},
"outputs": [],
"source": [
"result.solution"
]
}
],
"metadata": {
Expand Down
1 change: 1 addition & 0 deletions docs/release_notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### New Features and Major Changes

* [Introduce example on input/output operations and introduce solution object into the example #80](https://github.com/SPSUnipi/pySMSpp/pull/80)
* [Revise SMSPPSolverTool.is_available to support shell option and move shell option to constructor of SMSPPSolverTool #78](https://github.com/SPSUnipi/pySMSpp/pull/78)
* [Enable shell option in SMSNetwork.optimize #77](https://github.com/SPSUnipi/pySMSpp/pull/77)
* [Enable shell option in subprocess of tools and generalize options: add explicit solverconfig option and kwargs to generalize options #73](https://github.com/SPSUnipi/pySMSpp/pull/73)
Expand Down
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ nav:
- Unit Commitment (2 thermal, line): examples/ucblock_2thermal_line.ipynb
- Navigating SMS Blocks: examples/navigating_sms_blocks.ipynb
- Plotting Variables and Blocks: examples/plotting_variables_and_blocks.ipynb
- Input/Output Operations: examples/io_operations.ipynb
- User Guide:
- API Reference: api_reference.md
- Release Notes: release_notes.md
Expand Down
Loading