Skip to content

Add transmission hurdle rates for flows on specified transmission paths#887

Draft
Copilot wants to merge 7 commits intodevelopfrom
copilot/add-hurdle-rates-to-flows
Draft

Add transmission hurdle rates for flows on specified transmission paths#887
Copilot wants to merge 7 commits intodevelopfrom
copilot/add-hurdle-rates-to-flows

Conversation

Copy link

Copilot AI commented Dec 11, 2025

Description

This PR adds transmission hurdle rates—variable costs per MWh of flow—to model wheeling charges or inter-balancing-area coordination frictions. The implementation is backward compatible: the optional Line_Hurdle_Rates column in Network.csv defaults to zero.

Implementation:

  • Data loading (load_network_data.jl): Load optional Line_Hurdle_Rates column with parameter scaling ($/MWh → $/GWh when scaled)
  • Cost calculation (transmission.jl):
    • Compute absolute flow values using auxiliary variables (reuses existing loss auxiliaries when TRANS_LOSS_SEGS == 1)
    • Add Σ(ωₜ × hₗ × |Φₗ,ₜ|) to objective function
    • Handle all transmission loss segment configurations (0, 1, >1)
  • Cost reporting (write_costs.jl): Add cTransmissionHurdleCosts row to costs.csv (system-wide total only)
  • Documentation: Update User Guide with Line_Hurdle_Rates column description

Example Network.csv:

Network_Lines,Start_Zone,End_Zone,Line_Max_Flow_MW,Line_Hurdle_Rates
1,1,2,2950,5.0
2,1,3,2000,0

What type of PR is this? (check all applicable)

  • Feature
  • Bug Fix
  • Documentation Update
  • Code Refactor
  • Performance Improvements

Related Tickets & Documents

Fixes #848

Checklist

  • Code changes are sufficiently documented; i.e. new functions contain docstrings and .md files under /docs/src have been updated if necessary.
  • The latest changes on the target branch have been incorporated, so that any conflicts are taken care of before merging. This can be accomplished either by merging in the target branch (e.g. 'git merge develop') or by rebasing on top of the target branch (e.g. 'git rebase develop'). Please do not hesitate to reach out to the GenX development team if you need help with this.
  • Code has been tested to ensure all functionality works as intended.
  • CHANGELOG.md has been updated (if this is a 'notable' change).
  • I consent to the release of this PR's code under the GNU General Public license.

How this can be tested

Run any multi-zone example with or without the Line_Hurdle_Rates column. Without the column, behavior is unchanged (backward compatible). With the column, verify cTransmissionHurdleCosts appears in costs.csv and equals Σ(ωₜ × hₗ × |flowₗ,ₜ|).

Post-approval checklist for GenX core developers

After the PR is approved

  • Check that the latest changes on the target branch are incorporated, either via merge or rebase
  • Remember to squash and merge if incorporating into develop

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • https://api.github.com/repos/FluxML/MacroTools.jl/tarball/1e0228a030642014fe5cfe68c2c0a818f9e3f522
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaArrays/ArrayInterface.jl/tarball/d81ae5489e13bc03567d4fbbb06c546a5e53c857
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaArrays/StaticArrays.jl/tarball/b8693004b385c842357406e3af647701fe783f98
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaArrays/StaticArraysCore.jl/tarball/6ab403037779dae8c514bad259f32a447262455a
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaBinaryWrappers/Bzip2_jll.jl/tarball/1b96ea4a01afe0ea4090c5c8039690672dd13f2e
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaBinaryWrappers/HiGHS_jll.jl/tarball/e0539aa3405df00e963a9a56d5e903a280f328e7
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaBinaryWrappers/Libiconv_jll.jl/tarball/be484f5c92fad0bd8acfef35fe017900b0b73809
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaBinaryWrappers/METIS_jll.jl/tarball/2eefa8baa858871ae7770c98c3c2a7e46daba5b4
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaBinaryWrappers/OpenBLAS32_jll.jl/tarball/ece4587683695fe4c5f20e990da0ed7e83c351e7
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaBinaryWrappers/OpenSpecFun_jll.jl/tarball/1346c9208249809840c91b26703912dff463d335
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaCI/BenchmarkTools.jl/tarball/7fecfb1123b8d0232218e2da0c213004ff15358d
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaCollections/DataStructures.jl/tarball/4e1fe97fdaed23e9dc21d4d664bea76b65fc50a0
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaCollections/OrderedCollections.jl/tarball/05868e21324cede2207c6f0f466b4bfef6d5e7ee
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaCollections/SortingAlgorithms.jl/tarball/64d974c2e6fdf07f8155b5b2ca2ffa9069b608d9
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaData/CSV.jl/tarball/deddd8725e5e1cc49ee205a1964256043720a6c3
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaData/DataAPI.jl/tarball/abe83f3a2f1b857aac70ef8b269080af17764bbe
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaData/DataFrames.jl/tarball/d8928e9169ff76c6281f39a659f9bca3a573f24c
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaData/InvertedIndices.jl/tarball/6da3c4316095de0f5ee2ebd875df8721e7e0bdbe
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaData/Missings.jl/tarball/ec4f7fbeab05d7747bdf98eb74d130a2a2ed298d
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaData/Parsers.jl/tarball/7d2f8f21da5db6a806faf7b9b292296da42b2810
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaData/PooledArrays.jl/tarball/36d8b4b899628fb92c2749eb488d884a926614d3
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaData/SentinelArrays.jl/tarball/712fb0231ee6f9120e005ccd56297abbc053e7e0
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaData/StructTypes.jl/tarball/159331b30e94d7b11379037feeb9b690950cace8
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaData/Tables.jl/tarball/f2c1efbc8f3a609aadf318094f8fc5204bdaf344
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaData/WeakRefStrings.jl/tarball/b1be2855ed9ed8eac54e5caff2afcdb442d52c23
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaData/YAML.jl/tarball/a1c0c7585346251353cddede21f180b96388c403
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaDiff/DiffResults.jl/tarball/782dd5f4561f5d267313f23853baaaa4c52ea621
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaDiff/DiffRules.jl/tarball/23163d55f885173722d1e4cf0f6110cdbaf7e272
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaDiff/ForwardDiff.jl/tarball/cd33c7538e68650bd0ddbb3f5bd50a4a0fa95b50
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaDocs/DocStringExtensions.jl/tarball/7442a5dfe1ebb773c29cc2962a8980f47221d76c
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaFunctional/CompositionsBase.jl/tarball/802bb88cd69dfd1509f6670416bd4434015693ad
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaGPU/Adapt.jl/tarball/7e35fca2bdfba44d797c53dfe63a51fabf39bfc0
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaGPU/GPUArrays.jl/tarball/83cf05ab16a73219e5f6bd1bdfa9848fa24ac627
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaIO/CodecBzip2.jl/tarball/84990fa864b7f2b4901901ca12736e45ee79068c
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaIO/CodecZlib.jl/tarball/962834c22b66e32aa10f7611c08c8ca4e20749a9
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaIO/JSON.jl/tarball/5b6bb73f555bc753a6153deec3717b8904f5551c
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaIO/TranscodingStreams.jl/tarball/0c45878dcfdcfa8480052b6ab162cdd138781742
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaLang/Compat.jl/tarball/9d8a54ce4b17aa5bdce0ea5c34bc5e7c340d16ad
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaLang/PrecompileTools.jl/tarball/07a921781cab75691315adc645096ed5e370cb77
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaMath/Combinatorics.jl/tarball/8010b6bb3388abe68d95743dcbea77650bb2eddf
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaMath/InverseFunctions.jl/tarball/a779299d77cd080bf77b97535acecd73e1c5e5cb
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaMath/IrrationalConstants.jl/tarball/b2d91fe939cae05960e760110b328288867b5758
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaMath/NaNMath.jl/tarball/9b8215b1ee9e78a293f99797cd31375471b2bcae
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaMath/SpecialFunctions.jl/tarball/f2685b435df2613e25fc10ad8c26dddb8640f547
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaObjects/Accessors.jl/tarball/856ecd7cebb68e5fc87abecd2326ad59f0f911f3
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaObjects/ConstructionBase.jl/tarball/b4b092499347b18a015186eae3042f72267106cb
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaPackaging/JLLWrappers.jl/tarball/0533e564aae234aff59ab625543145446d8b6ec2
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaPackaging/Preferences.jl/tarball/0f27480397253da18fe2c12a4ba4eb9eb208bf3d
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaPackaging/Requires.jl/tarball/62389eeff14780bfe55195b7204c0d8738436d64
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaPlots/Plots.jl/tarball/5c3d09cc4f31f5fc6af001c250bf1278733100ff
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaServices/StructUtils.jl/tarball/79529b493a44927dd5b13dde1c7ce957c2d049e4
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaServices/WorkerUtilities.jl/tarball/cd1659ba0d57b71a464a29e64dbc67cfe83d54e7
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaStats/Clustering.jl/tarball/3e22db924e2945282e70c33b75d4dde8bfa44c94
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaStats/Distances.jl/tarball/c7e3a542b999843086e2f29dac96a618c105be1d
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaStats/LogExpFunctions.jl/tarball/13ca9e2586b89836fd20cccf56e57e2b9ae7f38f
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaStats/Statistics.jl/tarball/ae3bb1eb3bba077cd276bc5cfc337cc65c3075c0
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaStats/StatsAPI.jl/tarball/178ed29fd5b2a2cfc3bd31c13375ae925623ff36
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaStats/StatsBase.jl/tarball/be5733d4a2b03341bdcab91cea6caa7e31ced14b
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaStrings/InlineStrings.jl/tarball/8f3d257792a522b4601c24a577954b0a8cd7334d
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaStrings/LaTeXStrings.jl/tarball/dda21b8cbd6a6c40d9d02a73230f9d70fed6918c
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaStrings/StringEncodings.jl/tarball/b765e46ba27ecf6b44faf70df40c57aa3a547dcb
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/JuliaTesting/ExprTools.jl/tarball/27415f162e6028e81c72b82ef756bf321213b6ec
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/KristofferC/Crayons.jl/tarball/249fe38abf76d48563e2f4556bebd215aa317e15
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/KristofferC/NearestNeighbors.jl/tarball/5a47e9b249869754ac274953fbe9b7232856eb20
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/LilithHafner/AliasTables.jl/tarball/9876e1e164b144ca45e9e3198d0b689cadfed9ff
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/LilithHafner/PtrArrays.jl/tarball/1d36ef11a9aaf1e8b74dacc6a731dd1de8fd493d
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/SciML/RecursiveArrayTools.jl/tarball/51bdb23afaaa551f923a0e990f7c44a4451a26f1
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/SciML/RuntimeGeneratedFunctions.jl/tarball/2f609ec2295c452685d3142bc4df202686e555d2
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/SciML/SymbolicIndexingInterface.jl/tarball/94c58884e013efff548002e8dc2fdd1cb74dfce5
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/jump-dev/HiGHS.jl/tarball/7eaca80074d6389bbf83e4dfb1eaf6b3cd78d150
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/jump-dev/JuMP.jl/tarball/b76f23c45d75e27e3e9cbd2ee68d8e39491052d0
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/jump-dev/MathOptIIS.jl/tarball/31d4a6353ea00603104f11384aa44dd8b7162b28
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/jump-dev/MathOptInterface.jl/tarball/181c2611c7aa6a362fdf937b1e2af55e6691181f
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/jump-dev/MutableArithmetics.jl/tarball/22df8573f8e7c593ac205455ca088989d0a2c7a0
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/queryverse/DataValueInterfaces.jl/tarball/bfc1187b79289637fa0ef6d4436ebdfe6905cbd6
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/queryverse/IteratorInterfaceExtensions.jl/tarball/a3f24677c21f5bbe9d2a714f95dcd58337fb2856
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/queryverse/TableTraits.jl/tarball/c06b2f539df1c6efa794486abfb6ed2022561a39
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/quinnj/JSON3.jl/tarball/411eccfe8aba0814ffa0fdf4860913ed09c34975
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/rdeits/CommonSubexpressions.jl/tarball/cda2cfaebb4be89c9084adaca7dd7333369715c5
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/rofinn/FilePathsBase.jl/tarball/3bab2c5aa25e7840a4b065805c0cdfc01f3068d2
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/ronisbr/PrettyTables.jl/tarball/c5a07210bd060d6a8491b0ccdee2fa0235fc00bf
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/ronisbr/StringManipulation.jl/tarball/a3c1536470bf8c5e02096ad4853606d7c8f62721
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • https://api.github.com/repos/simonster/Reexport.jl/tarball/45e428421666073eab6f2da5c9d310d99bb12f9b
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (http block)
  • pkg.julialang.org
    • Triggering command: /usr/bin/julia julia --project=. -e using Pkg; Pkg.instantiate() (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Original prompt

This section details on the original issue you should resolve

<issue_title>[Feature]: Add 'hurdle rates' to flows on specified transmission paths</issue_title>
<issue_description>### Feature description

Create option to apply a variable cost reflecting hurdle rates applied to flows on specified transmission paths.

Motivation

This cost can represent 'wheeling charges' between transmission territories (where applied) or frictions between various balancing areas (such as two RTOs) that prevents perfect coordination of dispatch and flows on interconnectors. These 'frictions' are not real costs, but by imposing a variable cost, it will constraint flows to periods when the difference in locational price on either side of the path are larger than this variable cost. This is a common practive to represent imperfect coordination between balancing authorities/areas.

Implementation strategy

Suggested implementation:

  • Add new variable cost input for each path in the Network.csv input file.
  • Create new equation equal to the sum of this vector of variable costs times the vector of positive flows on each path plus this vector of variable costs times the vector of negative flows on each path.
  • Add this equation to the objective function
  • Add a new column to Costs.csv outputs that contains this cost component so it can be tracked separately (and removed from "real" costs if it simply reflects a friction).

Additional context

Requested by users via email.</issue_description>

<agent_instructions>Please implement the planned PR.
Add a new variable cost input column called "Line_Hurdle_Rates" to the Network.csv file for each line, indicating cost per MWh for flows across this line.

Add a new section to load_network_data.csv to load this data. Make this column optional and default to 0 if not included in the input file.

Add a new section to transmission.jl that creates an expression totalling this new cost summed across flows over each line times the hurdle rate for that line for each time step. Apply parameter scaling if appropriate. Add this expression to the objective function.

Add a section to write_costs.jl that adds a new row to the costs.csv output file for cTransmissionHurdleCosts and write costs for the full system to the total column. No output is needed for the zonal columns as this is not a zonal cost.

Add appropriate documentation.

Describe this hurdle rate input in comments and documentation where appropriate as:

"This cost can represent 'wheeling charges' between transmission territories (where applied) or frictions between various balancing areas (such as two RTOs) that prevents perfect coordination of dispatch and flows on interconnectors. (These 'frictions' are not real costs, but by imposing a variable cost, it will constraint flows to periods when the difference in locational price on either side of the path are larger than this variable cost.) This is a common practive to represent imperfect coordination between balancing authorities/areas/jurisdictions. This cost is added to the objective function.</agent_instructions>

Comments on the Issue (you are @copilot in this section)

@sambuddhac Merging PR #858 (after testing, review, and approval) will resolve this issue. @sambuddhac @JesseJenkins , should we have a new output file (something like transmission_hurdle.csv or transmission_operating_cost.csv) for printing the total hurdle costs? @JesseJenkins I would suggest we include them in the cost.csv outputs as a separate category, since they're not "real" costs in some cases (in others they represent real "wheeling charges").

Jesse Jenkins


@.***

On Tue, Jul 15, 2025, 2:51 PM Chakrabarti, Sambuddha (Sam) <
@.***> wrote:

sambuddhac left a comment (#848)
#848 (comment)

@JesseJenkins https://github.com/JesseJenkins , should we have a new
output file (something like transmission_hurdle.csv or
transmission_operating_cost.csv) for printing the total hurdle costs?


Reply to this email directly, view it on GitHub
#848 (comment),
or unsubscribe
https://github.com/notifications/unsubscribe-auth/ACPYTSD4B3GS4H7IIHZQVUL3IVET5AVCNFSM6AAAAAB7FS2Z5KVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZTANZVGAZTMMBYGE
.
You are receiving this because you were mentioned.Message ID:
@.***>

@JesseJenkins @sambuddhac @lbonaldo can we get this implemented asap? Should be simple change. Is there an open PR on this? Qian needs it now for ongoing work. @JesseJenkins

💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI and others added 4 commits December 11, 2025 16:00
- Add Line_Hurdle_Rates loading in load_network_data.jl
- Add hurdle cost expression and constraints in transmission.jl
- Add cTransmissionHurdleCosts output in write_costs.jl

Co-authored-by: JesseJenkins <10455496+JesseJenkins@users.noreply.github.com>
Add init=0.0 to sum expressions to handle empty iterators

Co-authored-by: JesseJenkins <10455496+JesseJenkins@users.noreply.github.com>
Document the new optional Line_Hurdle_Rates column in Network.csv input file documentation

Co-authored-by: JesseJenkins <10455496+JesseJenkins@users.noreply.github.com>
- Fix 'practive' to 'practice'
- Fix 'constraint' to 'constrain'

Co-authored-by: JesseJenkins <10455496+JesseJenkins@users.noreply.github.com>
Copilot AI changed the title [WIP] Add variable cost for hurdle rates on transmission paths Add transmission hurdle rates for flows on specified transmission paths Dec 11, 2025
Copilot AI requested a review from JesseJenkins December 11, 2025 16:13
@lbonaldo lbonaldo changed the base branch from main to develop December 23, 2025 20:52
Comment on lines +353 to +376
@constraints(EP, begin
cTAuxSumHurdle[l in HURDLE_RATE_NO_LOSS_LINES, t = 1:T],
vTAUX_POS_HURDLE[l, t] - vTAUX_NEG_HURDLE[l, t] == vFLOW[l, t]

cTAuxLimitHurdle[l in HURDLE_RATE_NO_LOSS_LINES, t = 1:T],
vTAUX_POS_HURDLE[l, t] + vTAUX_NEG_HURDLE[l, t] <= EP[:eAvail_Trans_Cap][l]
end)

# Expression for total transmission hurdle costs
@expression(EP, eTotalCTransHurdle,
sum(inputs["omega"][t] * inputs["pLine_Hurdle_Rate"][l] *
(vTAUX_POS[l, t] + vTAUX_NEG[l, t])
for l in HURDLE_RATE_LOSS_LINES, t in 1:T, init=0.0) +
sum(inputs["omega"][t] * inputs["pLine_Hurdle_Rate"][l] *
(vTAUX_POS_HURDLE[l, t] + vTAUX_NEG_HURDLE[l, t])
for l in HURDLE_RATE_NO_LOSS_LINES, t in 1:T, init=0.0)
)
elseif TRANS_LOSS_SEGS == 1
# All hurdle rate lines are also loss lines
@expression(EP, eTotalCTransHurdle,
sum(inputs["omega"][t] * inputs["pLine_Hurdle_Rate"][l] *
(vTAUX_POS[l, t] + vTAUX_NEG[l, t])
for l in HURDLE_RATE_LINES, t in 1:T, init=0.0)
)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @sambuddhac, Hi @JesseJenkins, I was reviewing this part of the PR, and I wanted to check if we should make some adjustments for when UCommit == 1.
In the code above, I can see that we make use of the variables vTAUX_POS and vTAUX_NEG to calculate the eTotalCTransHurdle expression, and these variables have an additional set of constraints when UCommit == 1. Should we implement something similar also for the new variables vTAUX_POS_HURDLE and vTAUX_NEG_HURDLE?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lbonaldo the hurdle rate should be applied in the same way whether UCommit == 1 or 0. The additional constraints on the flow auxiliary variables when UCommit==1 are meant to avoid 'phantom' losses, where the model choses to pick a higher segment on the piecewise linearization of the quadratic loss curve in order to dump power when that would help avoid a costly start-up/shut-down. These constraints should not interfere with the additional hurdle cost.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sambuddhac please just confirm that the hurdle rates work as intended for cases with UCommit=1 and =0.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @JesseJenkins, it makes sense. I just wanted to make sure it was okay to use the vTAUX_POS and vTAUX_NEG variables for lines with hurdle rates and losses, instead of creating new ones for all the lines with hurdle rates. I just checked the code again, and it makes sense. Thank you.

@sambuddhac
Copy link
Collaborator

Attached hereby is one of the comparison spreadsheets, in which I have compared the no-hurdle (white) and with hurdle (green) cases for capacity, losses, flow, and LMP comparison [
Comparison_Hurdle.xlsx
]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: Add 'hurdle rates' to flows on specified transmission paths

5 participants