Skip to main content
Version: 1.0.0

How to run an HV Intrinsic Hosting Capacity Work Package

This guide shows a basic Python example for starting an HV node headroom work package through the Energy Workbench Python client.

An HV node headroom work package estimates headroom at selected HV node locations. It uses the same feeder/year/scenario scope, initial load state, injection resource, constraints, model configuration, and solve configuration patterns as an intrinsic work package. For a conceptual overview of how both modes work, see What is Intrinsic Hosting Capacity Mode?.

In this mode, HCM finds every HV node in the selected feeders that matches the configured nodeLocationSelector types. It tests those HV nodes one at a time by injecting additional load or generation at that point in the network until that node's headroom is found. That additional load or generation is then removed before the next HV node is tested.

Minimal Example

Create an EasClient, build an HvNodeHeadroomWorkPackageInput, then submit it using Mutation.run_hv_node_headroom_work_package.

from zepben.eas.client.eas_client import EasClient
from zepben.eas.lib.custom_mutations import Mutation
from zepben.eas.lib import (
HvNodeHeadroomWorkPackageInput,
IntrinsicInitialLoadStateConfigInput,
IntrinsicInitialStateSelectorMode,
IntrinsicSyfConfigInput,
)

client = EasClient(
host=eas_server_host,
port=eas_server_port,
protocol=eas_server_protocol,
client_id=eas_server_client_id,
username=eas_server_username,
password=eas_server_password,
client_secret=eas_server_client_secret,
verify_certificate=eas_server_verify_certificate,
ca_filename=eas_server_ca_filename,
)

work_package = HvNodeHeadroomWorkPackageInput(
syf=IntrinsicSyfConfigInput(
feeders=["feeder-mrid-1"],
year=2030,
scenario="base",
),
initial_state_selector=IntrinsicInitialLoadStateConfigInput(
selector_mode=IntrinsicInitialStateSelectorMode.FIXED_TIME,
start_time="2030-01-01T12:00:00",
include_loads=True,
include_existing_der=True,
load_scaling_factor=1.0,
der_scaling_factor=1.0,
),
)

result = client.mutation(
Mutation.run_hv_node_headroom_work_package(
input=work_package,
work_package_name="Example HV node headroom work package",
)
)

print(result)

The mutation returns the new work package ID if the request is accepted.

Shared Configuration

HV node headroom work packages reuse these inputs from intrinsic work packages:

FieldNotes
syfSame feeder, year, and scenario input as intrinsic work packages. See SYF Config.
initial_state_selectorSame initial load state selector as intrinsic work packages. See Initial State Selector Config.
injection_resourceSame injection resource input as intrinsic work packages. See Injection Resource Config.
constraintsSame voltage and thermal constraint input as intrinsic work packages. See Constraints Config.
modelUses the same model configuration input as a normal hosting capacity work package.
solveUses the same solve configuration input as the intrinsic and normal hosting capacity work package inputs.

HV-Specific Configuration

Search Config

Use search to control the HV node headroom search.

from zepben.eas.lib import HvNodeHeadroomSearchConfigInput

work_package.search = HvNodeHeadroomSearchConfigInput(
step_kw_per_node=5.0,
max_steps_per_node=1000,
)
FieldDefaultRestriction
step_kw_per_node1.0Optional search increment in kW per node.
max_steps_per_node1000Must be 1000 or less.

HV Node Location Selector Config

Use nodeLocationSelector to choose which HV node locations are included in the headroom calculation.

from zepben.eas.lib import HvNodeLocationKind, HvNodeLocationSelectorInput

work_package.node_location_selector = HvNodeLocationSelectorInput(
location_kinds=[
HvNodeLocationKind.DTX_HV_TERMINAL,
HvNodeLocationKind.LINE_TEE,
],
)
FieldDefaultNotes
location_kinds[DTX_HV_TERMINAL]Optional list of HV node location kinds to include.

Supported location_kinds values:

  • DTX_HV_TERMINAL
  • SWITCH_UPSTREAM_TERMINAL
  • LINE_TEE

Full Example

from zepben.eas.client.eas_client import EasClient
from zepben.eas.lib.custom_mutations import Mutation
from zepben.eas.lib import (
HvNodeHeadroomSearchConfigInput,
HvNodeHeadroomWorkPackageInput,
HvNodeLocationKind,
HvNodeLocationSelectorInput,
IntrinsicConstraintsConfigInput,
IntrinsicHvVoltageConstraintInput,
IntrinsicInitialLoadStateConfigInput,
IntrinsicInitialStateSelectorMode,
IntrinsicInjectionResourceConfigInput,
IntrinsicInjectionResourceMethod,
IntrinsicLoadModelType,
IntrinsicLvVoltageConstraintInput,
IntrinsicRatingBasis,
IntrinsicSyfConfigInput,
IntrinsicThermalConstraintInput,
IntrinsicThermalConstraintsInput,
IntrinsicVoltageConstraintsInput,
)

client = EasClient(...)

work_package = HvNodeHeadroomWorkPackageInput(
syf=IntrinsicSyfConfigInput(
feeders=["feeder-mrid-1"],
year=2030,
scenario="base",
),
initial_state_selector=IntrinsicInitialLoadStateConfigInput(
selector_mode=IntrinsicInitialStateSelectorMode.FIXED_TIME,
start_time="2030-01-01T12:00:00",
include_loads=True,
include_existing_der=True,
load_scaling_factor=1.0,
der_scaling_factor=1.0,
),
search=HvNodeHeadroomSearchConfigInput(
step_kw_per_node=5.0,
max_steps_per_node=1000,
),
node_location_selector=HvNodeLocationSelectorInput(
location_kinds=[
HvNodeLocationKind.DTX_HV_TERMINAL,
HvNodeLocationKind.LINE_TEE,
],
),
injection_resource=IntrinsicInjectionResourceConfigInput(
method=IntrinsicInjectionResourceMethod.EXPORT_GENERATION,
load_model_type=IntrinsicLoadModelType.NEGATIVE_LOAD,
power_factor=0.95,
),
constraints=IntrinsicConstraintsConfigInput(
voltage=IntrinsicVoltageConstraintsInput(
hv=IntrinsicHvVoltageConstraintInput(min_pu=0.95, max_pu=1.05),
lv=IntrinsicLvVoltageConstraintInput(min=216.0, max=253.0),
),
thermal=IntrinsicThermalConstraintsInput(
hv=IntrinsicThermalConstraintInput(
percent_of_rating=100.0,
rating_basis=IntrinsicRatingBasis.NORMAL,
),
lv=IntrinsicThermalConstraintInput(
percent_of_rating=100.0,
rating_basis=IntrinsicRatingBasis.NORMAL,
),
),
),
)

result = client.mutation(
Mutation.run_hv_node_headroom_work_package(
input=work_package,
work_package_name="2030 HV node headroom",
)
)

Monitoring The Run

After the mutation returns a work package ID, use the standard work package manager or progress APIs described in How to run a work package and How to manage work packages.

Understanding the Results

Once the work package completes, results are written to the Intrinsic Hosting Capacity output tables. HV node headroom runs produce the hv_node_headroom, binding_constraints, and constraint_violations tables. Note that lv_group_hosting_capacity and customer_allocations are not produced by HV node headroom runs.

Where to start: hv_node_headroom

The hv_node_headroom table is your primary result. Each row is one HV node that was tested and reports the maximum additional kW that can be injected at that point before a network constraint is breached.

The key columns:

  • available_headroom_kw - the additional kW of load or generation that can connect at this HV node before any configured voltage or thermal limit is hit.
  • headroom_direction - whether this is export (generation connecting to the HV network) or import (load connecting).
  • location_type - the type of HV node (DTX_HV_TERMINAL, LINE_TEE, or SWITCH_UPSTREAM_TERMINAL).
  • asset_name - human-readable name of the asset at this location, useful for cross-referencing with network maps or GIS data.

Unlike the LV intrinsic mode, HV nodes are tested one at a time in isolation. The headroom figure represents the capacity at that point assuming only that one injection is added, with the rest of the network in its initial state.

Understanding what constrained each node: constraint_violations

For any node where you want to understand the limiting factor, join through binding_constraints to constraint_violations:

The metric column tells you whether the search stopped on a voltage limit or a thermal current limit. The conducting_equipment_mrid identifies the specific asset - a transformer, line segment, or cable - that was the binding constraint.