BatteriesΒΆ
This notebook
[1]:
import os
import numpy as np
from pyltmapi import LtmSession, LtmPlot
import logging
logging.basicConfig(level=logging.INFO)
from pathlib import Path
ltm_core_path = os.environ.get("LTM_CORE_PATH", str(Path("~").expanduser().joinpath("ltm/release/bin/")))
license_file = os.environ.get("LTM_CORE_LICENSE_FILE", str(Path("~").expanduser().joinpath("ltm/ltm-license.dat")))
[2]:
from IPython.display import display, display_markdown
ltmapi_version = LtmSession.version()
display(ltmapi_version)
'PyLTM version: 0.21.0'
[3]:
def usercallback(program_info: dict, userdata: any):
print(userdata)
print(program_info)
return True
def print_have_results(busbar):
print(
f"{busbar}.have_detailed_hydro_results() = {busbar.have_detailed_hydro_results()}"
)
print(
f"{busbar}.have_aggregated_hydro_results() = {busbar.have_aggregated_hydro_results()}"
)
print(
f"{busbar}.have_battery_results() = {busbar.have_battery_results()}"
)
print(
f"{busbar}.have_water_value_results() = {busbar.have_water_value_results()}"
)
print(
f"{busbar}.have_market_results() = {busbar.have_market_results()}"
)
def generate_plots(ltm):
# Water values and price series
for dc_line in ltm.model.dclines():
dc_line_exchange = dc_line.transmission_results(time_axis=False)
if dc_line_exchange != None:
dc_line_exchange = np.array(dc_line_exchange, copy=False)
dim = np.size(dc_line_exchange)
for battery in reversed(ltm.model.battery_modules()):
LtmPlot.make_generic_plot(
battery.sum_power_production(), f"Sum Battery Power Prod: {battery.name}"
)
LtmPlot.make_generic_plot(
battery.sum_energy(), f"Sum Battery Energy: {battery.name}"
)
pass
for agg in reversed(ltm.model.aggregated_hydro_modules()):
LtmPlot.make_generic_plot(
agg.sum_hydro_power_production(), f"Sum Hydro Power Prod: {agg.name}"
)
LtmPlot.make_generic_plot(
agg.sum_hydro_energy(), f"Sum Hydro Energy: {agg.name}"
)
pass
for busbar in reversed(ltm.model.busbars()):
print_have_results(busbar)
# Market results
LtmPlot.make_market_results_plot(busbar.market_result_price(), busbar.name)
#
LtmPlot.make_generic_plot(
busbar.sum_hydro_production(), f"Sum Hydro Prod: {busbar.name}"
)
#
LtmPlot.make_generic_plot(
busbar.sum_reservoir(), f"Sum reservoir: {busbar.name}"
)
# Sum load
LtmPlot.make_generic_plot(busbar.sum_load(), f"Sum load: {busbar.name}")
LtmPlot.make_generic_plot(
busbar.sum_production_from_market_steps(),
f"Sum production from market steps: {busbar.name}",
)
# Water values
LtmPlot.make_water_value_plot(busbar.water_value_results(), busbar.name)
# Detailed hydro results from
for busbar in ltm.model.busbars():
print(busbar)
# Busbar reservoirs
for rsv in busbar.reservoirs():
display("Reservoir")
LtmPlot.make_generic_plot(rsv.reservoir(), f"Reservoir '{rsv.name}'")
LtmPlot.make_generic_plot(rsv.discharge(), f"Discharge '{rsv.name}'")
LtmPlot.make_generic_plot(rsv.inflow(), f"Inflow '{rsv.name}'")
LtmPlot.make_generic_plot(rsv.production(), f"Production '{rsv.name}'")
[4]:
from pyltmapi import LtmDot
def open_and_write_model(filename: str):
session = LtmSession("ikernel", ltm_core_path=ltm_core_path, overwrite_session=True)
# Explicitly set license file
session.model.global_settings.ltm_license_file_path = license_file
with session:
try:
# Load model from file.
session.load(filename=filename)
# Write model to disk, and automatically generate an output directory.
session.write_model()
# Display model graph
LtmDot.display_dot_image(session.build_connection_tree())
LtmDot.display_dot_image(session.build_busbar_graph())
# Execute/run LTM/EMPS on the model
last_rc, results = session.execute_model()
# If last return code is not 0, then there was an error.
if last_rc != 0:
err = results[0]["log_file_contents"]
display_markdown(err)
else:
# Make plots from the results
generate_plots(session)
except Exception as e:
print(e)
raise (e)
[5]:
open_and_write_model("busbar_battery.json")
INFO:LtmApiModel:(ikernel) Loading model from file: busbar_battery.json
INFO:LtmApiModel:(ikernel) LtmApiModel::maybe_generate_output_dir: output_path: /builds/energy/ltm/pyltmapi/docs/ltm-api/guides/batteries/testout_batteries/2026-03-24-133824.442-EMPS-parallell
INFO:LtmApiModel:(ikernel) Using license file '/builds/energy/ltm/pyltmapi.tmp/CI_LTM_LICENSE_FILE'
INFO:LtmApiModel:(ikernel) Using license file '/builds/energy/ltm/pyltmapi.tmp/CI_LTM_LICENSE_FILE'
INFO:Validator:(ikernel) Model validation succeeded
INFO:LtmApiModel:(ikernel) Writing model to path /builds/energy/ltm/pyltmapi/docs/ltm-api/guides/batteries/testout_batteries/2026-03-24-133824.442-EMPS-parallell
INFO:Validator:(ikernel) Model validation succeeded
INFO:LtmApiModel:(ikernel) Model executed successfully
busbar/battery_busbar.have_detailed_hydro_results() = False
busbar/battery_busbar.have_aggregated_hydro_results() = False
busbar/battery_busbar.have_battery_results() = True
busbar/battery_busbar.have_water_value_results() = True
busbar/battery_busbar.have_market_results() = True
busbar/tev.have_detailed_hydro_results() = False
busbar/tev.have_aggregated_hydro_results() = True
busbar/tev.have_battery_results() = False
busbar/tev.have_water_value_results() = True
busbar/tev.have_market_results() = True
busbar/numedal.have_detailed_hydro_results() = True
busbar/numedal.have_aggregated_hydro_results() = True
busbar/numedal.have_battery_results() = False
busbar/numedal.have_water_value_results() = True
busbar/numedal.have_market_results() = True
busbar/numedal
'Reservoir'
'Reservoir'
INFO:LtmApiModel:(ikernel) Not deleting output dir (/builds/energy/ltm/pyltmapi/docs/ltm-api/guides/batteries/testout_batteries/2026-03-24-133824.442-EMPS-parallell), as delete_output_dir: false, and has_generated_output_dir: true
INFO:LtmApiModel:(ikernel) Not deleting output dir (/builds/energy/ltm/pyltmapi/docs/ltm-api/guides/batteries/testout_batteries/2026-03-24-133824.442-EMPS-parallell), as delete_output_dir: false, and has_generated_output_dir: true
busbar/tev
busbar/battery_busbar