Skip to main content
Version: Next

How to run a Hosting Capacity Work Package

Paid Feature - Only available for some customers

This feature is only available to certain customers. If you are interested in using this feature, please contact Zepben for more information.

This guide shows a basic Python example for starting an LV Hosting Capacity work package through the Energy Workbench Python client.

An intrinsic work package estimates additional import or export capacity by adding synthetic load or generation to selected network locations until configured voltage or thermal limits are reached. For a conceptual overview of how this works and what the results mean, see What is Intrinsic Hosting Capacity Mode?.

Prerequisites

Before running an intrinsic work package, you need:

  • Access to an Energy Workbench server.
  • Credentials with permission to create hosting capacity work packages (HC_WORK_PACKAGE:CREATE).
  • Python and the zepben.eas package installed.
  • The feeder mRIDs, scenario names, and years you want to run.
pip install zepben.eas

Minimal Example

Create an EasClient, build an IntrinsicWorkPackageInput, then submit it using Mutation.run_intrinsic_work_package.

from datetime import datetime

import asyncio
from zepben.eas.client.eas_client import EasClient
from zepben.eas import (
Mutation,
IntrinsicInitialLoadStateConfigInput,
IntrinsicInitialStateSelectorMode,
IntrinsicSyfConfigInput,
IntrinsicWorkPackageInput,
)

client = EasClient(
host=eas_server_host,
port=eas_server_port,
protocol=eas_server_protocol,
access_token=eas_server_access_token,
verify_certificate=eas_server_verify_certificate,
ca_filename=eas_server_ca_filename,
)

work_package = IntrinsicWorkPackageInput(
syf=IntrinsicSyfConfigInput(
feeders=["feeder-mrid-1"],
scenario="base",
year=2025,
),
initialStateSelector=IntrinsicInitialLoadStateConfigInput(
selectorMode=IntrinsicInitialStateSelectorMode.FIXED_TIME,
startTime=datetime.fromisoformat("2024-01-11T12:00:00"),
includeLoads=True,
includeExistingDer=True,
loadScalingFactor=1.0,
derScalingFactor=1.0,
),
)

async def main():
result = await client.mutation(
Mutation.run_intrinsic_work_package(
work_package,
work_package_name="Example intrinsic work package",
)
)
print(result)

asyncio.run(main())

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

Required Configuration

SYF Config

syf defines the work package scope.

FieldRequiredNotes
feedersYesList of feeder mRIDs. Must contain at least one feeder. Each feeder is solved independently.
yearYesForecast year (integer).
scenarioNoScenario name used when selecting the initial state. Defaults to "base" on the server if omitted.

Initial State Selector Config

initialStateSelector defines the starting load and generation state for the run.

FieldRequiredNotes
selectorModeYesOne of ZERO_LOAD, FIXED_LOAD, PEAK_FEEDER_IMPORT, PEAK_FEEDER_EXPORT, or FIXED_TIME.
startTimeYesRequired for all modes. For FIXED_TIME, this is the exact load time to use. For PEAK_FEEDER_IMPORT and PEAK_FEEDER_EXPORT, this is the start of the period to search for the peak. For ZERO_LOAD and FIXED_LOAD, this determines the network topology snapshot (switching state) used for the run.
endTimeConditionalRequired for PEAK_FEEDER_IMPORT and PEAK_FEEDER_EXPORT. Must be after startTime.
perCustomerLoadWattsConditionalRequired for FIXED_LOAD; rejected for other selector modes.
perCustomerGenWattsConditionalRequired for FIXED_LOAD; rejected for other selector modes.
perCustomerLoadVarConditionalRequired for FIXED_LOAD; rejected for other selector modes.
perCustomerGenVarConditionalRequired for FIXED_LOAD; rejected for other selector modes.
includeLoadsNoWhether existing loads should be included in initial load states. Defaults to true. Only supported for FIXED_TIME, PEAK_FEEDER_IMPORT, and PEAK_FEEDER_EXPORT.
includeExistingDerNoWhether existing DER should be included in initial load states. Defaults to true. Only supported for FIXED_TIME, PEAK_FEEDER_IMPORT, and PEAK_FEEDER_EXPORT. See Adjusting the Existing Load and DER for what this means and where the data comes from.
loadScalingFactorNoScaling factor applied to existing loads in initial load states. Defaults to 1.0. Only supported for FIXED_TIME, PEAK_FEEDER_IMPORT, and PEAK_FEEDER_EXPORT.
derScalingFactorNoScaling factor applied to existing DER in initial load states. Defaults to 1.0. Only supported for FIXED_TIME, PEAK_FEEDER_IMPORT, and PEAK_FEEDER_EXPORT.

FIXED_TIME - snapshot of actual load and generation at a specific moment:

initialStateSelector=IntrinsicInitialLoadStateConfigInput(
selectorMode=IntrinsicInitialStateSelectorMode.FIXED_TIME,
startTime=datetime.fromisoformat("2024-01-11T12:00:00"),
includeLoads=True,
includeExistingDer=True,
)

PEAK_FEEDER_EXPORT - worst-case export moment in a time window (most conservative for solar hosting capacity):

initialStateSelector=IntrinsicInitialLoadStateConfigInput(
selectorMode=IntrinsicInitialStateSelectorMode.PEAK_FEEDER_EXPORT,
startTime=datetime.fromisoformat("2024-01-01T00:00:00"),
endTime=datetime.fromisoformat("2024-12-31T23:59:59"),
includeLoads=True,
includeExistingDer=True,
)

PEAK_FEEDER_IMPORT - worst-case import moment (most conservative for load growth or EV assessments):

initialStateSelector=IntrinsicInitialLoadStateConfigInput(
selectorMode=IntrinsicInitialStateSelectorMode.PEAK_FEEDER_IMPORT,
startTime=datetime.fromisoformat("2024-01-01T00:00:00"),
endTime=datetime.fromisoformat("2024-12-31T23:59:59"),
includeLoads=True,
includeExistingDer=True,
)

ZERO_LOAD - empty network, no existing load or DER. Produces a theoretical upper bound on network capacity:

initialStateSelector=IntrinsicInitialLoadStateConfigInput(
selectorMode=IntrinsicInitialStateSelectorMode.ZERO_LOAD,
startTime=datetime.fromisoformat("2024-01-01T00:00:00"),
)

FIXED_LOAD - uniform per-customer baseline, useful for standardised comparisons across feeders:

initialStateSelector=IntrinsicInitialLoadStateConfigInput(
selectorMode=IntrinsicInitialStateSelectorMode.FIXED_LOAD,
startTime=datetime.fromisoformat("2024-01-01T00:00:00"),
perCustomerLoadWatts=500.0,
perCustomerGenWatts=0.0,
perCustomerLoadVar=0.0,
perCustomerGenVar=0.0,
)

Common Optional Configuration

Search Config

Use search to control the intrinsic capacity search.


work_package.search = IntrinsicSearchConfigInput(
stepKwPerCustomer=5.0,
maxSteps=1000,
stopOnHvViolation=True,
lockOutCapacityZoneOnViolation=True,
)
FieldDefaultRestriction
stepKwPerCustomer1.0
maxSteps1000Must be 10000 or less.
stopOnHvViolationtrueStops the search when HV violations are observed.
lockOutCapacityZoneOnViolationtrueStops incrementing additional import/export in a capacity zone after it violates constraints.

Injection Resource Config

Use injectionResource to control whether the intrinsic resource is modelled as export generation or import load.


work_package.injectionResource = IntrinsicInjectionResourceConfigInput(
method=IntrinsicInjectionResourceMethod.EXPORT_GENERATION,
loadModelType=IntrinsicLoadModelType.NEGATIVE_LOAD,
powerFactor=0.95,
phaseMatching=IntrinsicPhaseMatching.MATCH_CUSTOMER_PHASES,
)
FieldDefaultNotes
methodEXPORT_GENERATIONUse EXPORT_GENERATION for export hosting capacity or IMPORT_LOAD for import capacity.
loadModelTypeNEGATIVE_LOADUse PV_SYSTEM only when a PV profile is available.
pvProfileIdNoneRequired when loadModelType is PV_SYSTEM (Must exist in the hosting capacity input database).
powerFactor1.0
phaseMatchingMATCH_CUSTOMER_PHASESCurrently the only exposed option.

Allocation Config

Use allocation to control how intrinsic capacity is distributed.

from zepben.eas import (
IntrinsicAllocationConfigInput,
IntrinsicAllocationMethod,
IntrinsicAllocationScope,
IntrinsicExistingCapacityBasis,
)

work_package.allocation = IntrinsicAllocationConfigInput(
method=IntrinsicAllocationMethod.WEIGHTED_BY_EXISTING_CUSTOMER,
scope=IntrinsicAllocationScope.WITHIN_MEASUREMENT_ZONE,
existingCapacityBasis=IntrinsicExistingCapacityBasis.EXISTING_EXPORT_KW,
)
FieldDefaultNotes
methodUNIFORM_PER_INCLUDED_CUSTOMERUse WEIGHTED_BY_EXISTING_CUSTOMER to weight by existing import or export.
scopeNoneRequired when method is WEIGHTED_BY_EXISTING_CUSTOMER. Values: FEEDER_WIDE, WITHIN_MEASUREMENT_ZONE.
existingCapacityBasisNoneRequired when method is WEIGHTED_BY_EXISTING_CUSTOMER. Values: EXISTING_EXPORT_KW, EXISTING_IMPORT_KW.

Constraints Config

Use constraints to enable voltage and thermal limits. Supplying an hv or lv block enables that constraint.

from zepben.eas import (
IntrinsicConstraintsConfigInput,
IntrinsicHvVoltageConstraintInput,
IntrinsicLvVoltageConstraintInput,
IntrinsicRatingBasis,
IntrinsicThermalConstraintInput,
IntrinsicThermalConstraintsInput,
IntrinsicVoltageConstraintsInput,
)

work_package.constraints = IntrinsicConstraintsConfigInput(
voltage=IntrinsicVoltageConstraintsInput(
hv=IntrinsicHvVoltageConstraintInput(minPu=0.95, maxPu=1.05),
lv=IntrinsicLvVoltageConstraintInput(min=216.0, max=253.0),
),
thermal=IntrinsicThermalConstraintsInput(
hv=IntrinsicThermalConstraintInput(
percentOfRating=100.0,
ratingBasis=IntrinsicRatingBasis.NORMAL,
),
lv=IntrinsicThermalConstraintInput(
percentOfRating=100.0,
ratingBasis=IntrinsicRatingBasis.NORMAL,
),
),
)

Model Configuration

The model field uses the same model configuration input (HcModelConfigInput) as a normal hosting capacity work package, so use the existing work package model configuration options when you need to override model generation behaviour.

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. For a guide on interpreting those results - including how to read headroom values, what it means when a result hits maxSteps, and how to trace binding constraints - see Understanding Intrinsic Results.