Pumps

This notebook is an example on how to use pumps with and without power plants. It contains an example on how to use revisions (unavailable capacity) on pumps and plants.

Unavailable capacity is set by attribute unavailable_capacity on Plant and Pump.

"unavailable_capacity": {
    "timestamps": [
        "2023-01-02T00:00:00Z",
        "2024-06-01T00:00:00Z",
        "2024-12-01T00:00:00Z"
    ],
    "scenarios": [
        [
            170,
            150,
            0
        ]
    ]
}

Example plot for a plant with a pump:

No revisions:

image.png

  • No revisions set

Plant revision:

image-2.png

  • A substantial revision set on the power plant to reduce production. Max power production is down to ~45WM from ~150MW.

Pump and plant revisions:

image-3.png

  • Same revision on the plant.

  • Pump capacity is down to ~25MW, from ~100MW.

[1]:
import os
import numpy as np
from pyltmapi import LtmSession, LtmPlot, LtmDot
import pyltm
import json

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 HTML, Image, display, display_markdown

ltmapi_version = LtmSession.version()
display(f"pyltm version {ltmapi_version}")
'pyltm version PyLTM version: 0.25.2'
[3]:
def usercallback(program_info, userdata):
    # print(userdata)
    # print(program_info)

    return True


def generate_plots(ltm):

    for dc_line in ltm.model.dclines():
        if(dc_line.have_transmission_results()):
            LtmPlot.make_generic_plot(dc_line.transmission_results(),name="Exchange " + '"'+dc_line.name+'"')

    # Water values and price series
    for area in ltm.model.areas():
        display_markdown(f"# area: {area}", raw=True)

        # Pumped energy
        if (area.have_pump_results()):
            pumped_energy = area.sum_pumped_power()
            LtmPlot.make_generic_plot(pumped_energy, f"sum_pumped_power '{area.name}'")

            energy_pumping = area.sum_power_used_for_pumping()
            LtmPlot.make_generic_plot(energy_pumping, f"sum_power_used_for_pumping '{area.name}'")

        # Water values
        if (area.have_water_value_results()):
            LtmPlot.make_water_value_plot(area.water_value_results(), area.name)

        # Market results
        if (area.have_market_results()):
            LtmPlot.make_market_results_plot(area.market_result_price(), area.name)

        # extract market step results
        for market_step in ltm.model.market_steps():
            if(market_step.have_results()):
                if(area.name == market_step.area_name):
                    time, ms = market_step.results()
                    LtmPlot.generic_plot(time, ms, name="Market step"+'"'+market_step.name+'"' +' "'+area.name+'"')


    # Detailed hydro results from
    for area in ltm.model.areas():
        if(area.have_detailed_hydro_results()):
            display_markdown(f"## {area}", raw=True)

            LtmDot.display_dot_image(area.build_connection_tree())

            # area reservoirs
            for rsv in area.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}'")
                LtmPlot.make_generic_plot(rsv.bypass(), f"Bypass '{rsv.name}'")
                LtmPlot.make_generic_plot(rsv.spill(), f"Spill '{rsv.name}'")
[4]:
def open_and_write_model(filename: str):
    session = LtmSession("ikernel", ltm_core_path=ltm_core_path, overwrite_session=True)

    session.set_execute_callback(usercallback, None)

    # Explicitly set license file
    session.model.global_settings.ltm_license_file_path = license_file

    session.model.global_settings.simulation_type = pyltm.SimulationType.Parallel

    with session:
        try:
            print(f"python pid: {os.getpid()}")  # for debugging

            # Load model from file.
            session.load(filename=filename)
            # print(vars(session.model.global_settings))

            session.model.global_settings.model_type = pyltm.ModelType.EMPS

            # Write model to disk, and automatically generate an output directory.
            session.write_model()


            # session.dump_model("pump_dump")

            # Display model graph
            LtmDot.display_dot_image(session.build_connection_tree())
            LtmDot.display_dot_image(session.build_area_graph())

            # return

            # 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"]
                LtmDot.print(err)
            else:
                # Make plots from the results
                generate_plots(session)

        except Exception as e:
            print(e)
            raise (e)
[5]:
open_and_write_model("pumps.json")
INFO:LtmApiModel:(ikernel) Loading model from file: pumps.json
INFO:LtmApiModel:(ikernel) LtmApiModel::maybe_generate_output_dir: output_path: /builds/energy/ltm/pyltmapi/docs/ltm-api/guides/pumps/testout_pumps/2026-07-12-103637.592-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/pumps/testout_pumps/2026-07-12-103637.592-EMPS-parallell
INFO:InflowHandler:(ikernel) Writing inflow series
INFO:InflowHandler:(ikernel) Writing Forecast for 'after_one_year'
INFO:InflowHandler:(ikernel) Writing Forecast for 'after_one_year'
INFO:InflowHandler:(ikernel) Writing Forecast for 'after_one_year'
INFO:Validator:(ikernel) Model validation succeeded
python pid: 266
../../../_images/ltm-api_guides_pumps_pumps-notebook_5_2.svg
../../../_images/ltm-api_guides_pumps_pumps-notebook_5_3.svg
INFO:LtmApiModel:(ikernel) Model executed successfully
../../../_images/ltm-api_guides_pumps_pumps-notebook_5_5.png

area: area/pumpekraft

../../../_images/ltm-api_guides_pumps_pumps-notebook_5_7.png
../../../_images/ltm-api_guides_pumps_pumps-notebook_5_8.png
../../../_images/ltm-api_guides_pumps_pumps-notebook_5_9.png
../../../_images/ltm-api_guides_pumps_pumps-notebook_5_10.png
../../../_images/ltm-api_guides_pumps_pumps-notebook_5_11.png
../../../_images/ltm-api_guides_pumps_pumps-notebook_5_12.png
../../../_images/ltm-api_guides_pumps_pumps-notebook_5_13.png

area: area/tev

../../../_images/ltm-api_guides_pumps_pumps-notebook_5_15.png
../../../_images/ltm-api_guides_pumps_pumps-notebook_5_16.png
../../../_images/ltm-api_guides_pumps_pumps-notebook_5_17.png
../../../_images/ltm-api_guides_pumps_pumps-notebook_5_18.png
../../../_images/ltm-api_guides_pumps_pumps-notebook_5_19.png
../../../_images/ltm-api_guides_pumps_pumps-notebook_5_20.png

area/pumpekraft

../../../_images/ltm-api_guides_pumps_pumps-notebook_5_22.svg
'Reservoir'
../../../_images/ltm-api_guides_pumps_pumps-notebook_5_24.png
../../../_images/ltm-api_guides_pumps_pumps-notebook_5_25.png
../../../_images/ltm-api_guides_pumps_pumps-notebook_5_26.png
../../../_images/ltm-api_guides_pumps_pumps-notebook_5_27.png
../../../_images/ltm-api_guides_pumps_pumps-notebook_5_28.png
../../../_images/ltm-api_guides_pumps_pumps-notebook_5_29.png
'Reservoir'
../../../_images/ltm-api_guides_pumps_pumps-notebook_5_31.png
../../../_images/ltm-api_guides_pumps_pumps-notebook_5_32.png
../../../_images/ltm-api_guides_pumps_pumps-notebook_5_33.png
../../../_images/ltm-api_guides_pumps_pumps-notebook_5_34.png
../../../_images/ltm-api_guides_pumps_pumps-notebook_5_35.png
../../../_images/ltm-api_guides_pumps_pumps-notebook_5_36.png
'Reservoir'
../../../_images/ltm-api_guides_pumps_pumps-notebook_5_38.png
../../../_images/ltm-api_guides_pumps_pumps-notebook_5_39.png
../../../_images/ltm-api_guides_pumps_pumps-notebook_5_40.png
../../../_images/ltm-api_guides_pumps_pumps-notebook_5_41.png
../../../_images/ltm-api_guides_pumps_pumps-notebook_5_42.png
../../../_images/ltm-api_guides_pumps_pumps-notebook_5_43.png
'Reservoir'
../../../_images/ltm-api_guides_pumps_pumps-notebook_5_45.png
../../../_images/ltm-api_guides_pumps_pumps-notebook_5_46.png
../../../_images/ltm-api_guides_pumps_pumps-notebook_5_47.png
../../../_images/ltm-api_guides_pumps_pumps-notebook_5_48.png
../../../_images/ltm-api_guides_pumps_pumps-notebook_5_49.png
../../../_images/ltm-api_guides_pumps_pumps-notebook_5_50.png

area/tev

../../../_images/ltm-api_guides_pumps_pumps-notebook_5_52.svg
'Reservoir'
../../../_images/ltm-api_guides_pumps_pumps-notebook_5_54.png
../../../_images/ltm-api_guides_pumps_pumps-notebook_5_55.png
../../../_images/ltm-api_guides_pumps_pumps-notebook_5_56.png
../../../_images/ltm-api_guides_pumps_pumps-notebook_5_57.png
../../../_images/ltm-api_guides_pumps_pumps-notebook_5_58.png
../../../_images/ltm-api_guides_pumps_pumps-notebook_5_59.png
INFO:LtmApiModel:(ikernel) Not deleting output dir (/builds/energy/ltm/pyltmapi/docs/ltm-api/guides/pumps/testout_pumps/2026-07-12-103637.592-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/pumps/testout_pumps/2026-07-12-103637.592-EMPS-parallell), as delete_output_dir: false, and has_generated_output_dir: true