Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update transmission.jl to account for asymmetrical directional flow l… #769

Closed
wants to merge 13 commits into from

Conversation

sambuddhac
Copy link
Collaborator

Description

This PR attempts to implement asymmetrical flow limits depending on direction on power flow on transmission lines, so that unidirectional line flows on HVDC lines can be modeled.

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

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

Related Tickets & Documents

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

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

…imits

This PR attempts to implement asymmetrical flow limits depending on direction on power flow on transmission lines, so that unidirectional line flows on HVDC lines can be modeled.
@sambuddhac sambuddhac linked an issue Sep 9, 2024 that may be closed by this pull request
@@ -66,6 +91,25 @@ function load_network_data!(setup::Dict, path::AbstractString, inputs_nw::Dict)
inputs_nw["pMax_Line_Reinforcement"] = map(x -> max(0, x),
to_floats(:Line_Max_Reinforcement_MW)) / scale_factor # convert to GW
inputs_nw["pTrans_Max_Possible"] += inputs_nw["pMax_Line_Reinforcement"]
if setup["asymmetrical_trans_flow_limit"] == 1
# Read between zone network reinforcement costs per peak MW of capacity added
Copy link
Contributor

Choose a reason for hiding this comment

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

[JuliaFormatter] reported by reviewdog 🐶

Suggested change
# Read between zone network reinforcement costs per peak MW of capacity added
# Read between zone network reinforcement costs per peak MW of capacity added

if setup["asymmetrical_trans_flow_limit"] == 1
# Read between zone network reinforcement costs per peak MW of capacity added
inputs_nw["pC_Line_Reinforcement_Pos"] = to_floats(:Line_Reinforcement_Cost_per_MWyr_Pos) /
scale_factor # convert to million $/GW/yr with objective function in millions
Copy link
Contributor

Choose a reason for hiding this comment

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

[JuliaFormatter] reported by reviewdog 🐶

Suggested change
scale_factor # convert to million $/GW/yr with objective function in millions
scale_factor # convert to million $/GW/yr with objective function in millions

to_floats(:Line_Max_Reinforcement_MW_Pos)) / scale_factor # convert to GW
inputs_nw["pTrans_Max_Possible_Pos"] += inputs_nw["pMax_Line_Reinforcement_Pos"]

# Read between zone network reinforcement costs per peak MW of capacity added
Copy link
Contributor

Choose a reason for hiding this comment

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

[JuliaFormatter] reported by reviewdog 🐶

Suggested change
# Read between zone network reinforcement costs per peak MW of capacity added
# Read between zone network reinforcement costs per peak MW of capacity added


# Read between zone network reinforcement costs per peak MW of capacity added
inputs_nw["pC_Line_Reinforcement_Neg"] = to_floats(:Line_Reinforcement_Cost_per_MWyr_Neg) /
scale_factor # convert to million $/GW/yr with objective function in millions
Copy link
Contributor

Choose a reason for hiding this comment

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

[JuliaFormatter] reported by reviewdog 🐶

Suggested change
scale_factor # convert to million $/GW/yr with objective function in millions
scale_factor # convert to million $/GW/yr with objective function in millions

@@ -79,12 +123,23 @@
# Max Flow Possible on Each Line
inputs_nw["pLine_Max_Flow_Possible_MW"] = to_floats(:Line_Max_Flow_Possible_MW) /
scale_factor # Convert to GW
if setup["asymmetrical_trans_flow_limit"] == 1
inputs_nw["pLine_Max_Flow_Possible_MW_Pos"] = to_floats(:Line_Max_Flow_Possible_MW_Pos) /
scale_factor # Convert to GW
Copy link
Contributor

Choose a reason for hiding this comment

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

[JuliaFormatter] reported by reviewdog 🐶

Suggested change
scale_factor # Convert to GW
scale_factor # Convert to GW

Comment on lines +127 to +128
for l in EXPANSION_LINES)+sum(vNEW_TRANS_CAP_Pos[l] * inputs["pC_Line_Reinforcement_Pos"][l]
for l in EXPANSION_LINES_ASYM)+sum(vNEW_TRANS_CAP_Neg[l] * inputs["pC_Line_Reinforcement_Neg"][l]
Copy link
Contributor

Choose a reason for hiding this comment

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

[JuliaFormatter] reported by reviewdog 🐶

Suggested change
for l in EXPANSION_LINES)+sum(vNEW_TRANS_CAP_Pos[l] * inputs["pC_Line_Reinforcement_Pos"][l]
for l in EXPANSION_LINES_ASYM)+sum(vNEW_TRANS_CAP_Neg[l] * inputs["pC_Line_Reinforcement_Neg"][l]
for l in EXPANSION_LINES) +
sum(vNEW_TRANS_CAP_Pos[l] * inputs["pC_Line_Reinforcement_Pos"][l]
for l in EXPANSION_LINES_ASYM) +
sum(vNEW_TRANS_CAP_Neg[l] * inputs["pC_Line_Reinforcement_Neg"][l]

Comment on lines +153 to +154
@constraint(EP, cExistingTransCapPos[l = 1:L_asym], vTRANSMAX_Pos[l]==inputs["pTrans_Max_Pos"][l])
@constraint(EP, cExistingTransCapNeg[l = 1:L_asym], vTRANSMAX_Neg[l]==inputs["pTrans_Max_Neg"][l])
Copy link
Contributor

Choose a reason for hiding this comment

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

[JuliaFormatter] reported by reviewdog 🐶

Suggested change
@constraint(EP, cExistingTransCapPos[l = 1:L_asym], vTRANSMAX_Pos[l]==inputs["pTrans_Max_Pos"][l])
@constraint(EP, cExistingTransCapNeg[l = 1:L_asym], vTRANSMAX_Neg[l]==inputs["pTrans_Max_Neg"][l])
@constraint(EP, cExistingTransCapPos[l = 1:L_asym],
vTRANSMAX_Pos[l]==inputs["pTrans_Max_Pos"][l])
@constraint(EP, cExistingTransCapNeg[l = 1:L_asym],
vTRANSMAX_Neg[l]==inputs["pTrans_Max_Neg"][l])

Comment on lines +166 to +173
if setup["asymmetrical_trans_flow_limit"] == 1
@constraint(EP,
cMaxFlowPossible_Pos[l in EXPANSION_LINES_ASYM],
eAvail_Trans_Cap_Pos[l]<=inputs["pTrans_Max_Possible_Pos"][l])
@constraint(EP,
cMaxFlowPossible_Neg[l in EXPANSION_LINES_ASYM],
eAvail_Trans_Cap_Neg[l]<=inputs["pTrans_Max_Possible_Neg"][l])
end
Copy link
Contributor

Choose a reason for hiding this comment

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

[JuliaFormatter] reported by reviewdog 🐶

Suggested change
if setup["asymmetrical_trans_flow_limit"] == 1
@constraint(EP,
cMaxFlowPossible_Pos[l in EXPANSION_LINES_ASYM],
eAvail_Trans_Cap_Pos[l]<=inputs["pTrans_Max_Possible_Pos"][l])
@constraint(EP,
cMaxFlowPossible_Neg[l in EXPANSION_LINES_ASYM],
eAvail_Trans_Cap_Neg[l]<=inputs["pTrans_Max_Possible_Neg"][l])
end
if setup["asymmetrical_trans_flow_limit"] == 1
@constraint(EP,
cMaxFlowPossible_Pos[l in EXPANSION_LINES_ASYM],
eAvail_Trans_Cap_Pos[l]<=inputs["pTrans_Max_Possible_Pos"][l])
@constraint(EP,
cMaxFlowPossible_Neg[l in EXPANSION_LINES_ASYM],
eAvail_Trans_Cap_Neg[l]<=inputs["pTrans_Max_Possible_Neg"][l])
end

@constraints(EP,
begin
cMaxFlow_out[l = 1:L, t = 1:T], vFLOW[l, t] <= EP[:eAvail_Trans_Cap][l]
cMaxFlow_in[l = 1:L, t = 1:T], vFLOW[l, t] >= -EP[:eAvail_Trans_Cap][l]
end)

if setup["asymmetrical_trans_flow_limit"] ==1
Copy link
Contributor

Choose a reason for hiding this comment

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

[JuliaFormatter] reported by reviewdog 🐶

Suggested change
if setup["asymmetrical_trans_flow_limit"] ==1
if setup["asymmetrical_trans_flow_limit"] == 1

Comment on lines +184 to +185
cMaxFlow_out[l = 1:L_asym, t = 1:T], vTAUX_POS[l, t] <= EP[:eAvail_Trans_Cap_Pos][l] #Change these with Auxiliary
cMaxFlow_in[l = 1:L_asym, t = 1:T], vTAUX_NEG[l, t] >= -EP[:eAvail_Trans_Cap_Neg][l] #Change these with Auxiliary
Copy link
Contributor

Choose a reason for hiding this comment

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

[JuliaFormatter] reported by reviewdog 🐶

Suggested change
cMaxFlow_out[l = 1:L_asym, t = 1:T], vTAUX_POS[l, t] <= EP[:eAvail_Trans_Cap_Pos][l] #Change these with Auxiliary
cMaxFlow_in[l = 1:L_asym, t = 1:T], vTAUX_NEG[l, t] >= -EP[:eAvail_Trans_Cap_Neg][l] #Change these with Auxiliary
cMaxFlow_out[l = 1:L_asym, t = 1:T],
vTAUX_POS[l, t] <= EP[:eAvail_Trans_Cap_Pos][l] #Change these with Auxiliary
cMaxFlow_in[l = 1:L_asym, t = 1:T],
vTAUX_NEG[l, t] >= -EP[:eAvail_Trans_Cap_Neg][l] #Change these with Auxiliary

@JesseJenkins
Copy link
Collaborator

@sambuddhac this PR also needs to address how piecewise quadratic loss segments are established. We should use the max capacity for each direction to set different segment lengths for each direction of flows.

@sambuddhac
Copy link
Collaborator Author

@sambuddhac this PR also needs to address how piecewise quadratic loss segments are established. We should use the max capacity for each direction to set different segment lengths for each direction of flows.

Thanks @JesseJenkins . I'll take care of it today.

# Transmission loss related constraints - linear losses as a function of absolute value
if TRANS_LOSS_SEGS == 1
@constraints(EP,
## Do I need to model different expressions for linear losses for each direction, like the following?
if setup["asymmetrical_trans_flow_limit"] ==1
Copy link
Contributor

Choose a reason for hiding this comment

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

[JuliaFormatter] reported by reviewdog 🐶

Suggested change
if setup["asymmetrical_trans_flow_limit"] ==1
if setup["asymmetrical_trans_flow_limit"] == 1

Comment on lines +193 to +206
begin
# Losses are alpha times absolute values
cTLossPos[l in LOSS_LINES, t = 1:T],
vTLOSSPos[l, t] ==
inputs["pPercent_LossPos"][l] * (vTAUX_POS[l, t])

# Power flow is sum of positive and negative components
cTAuxSum[l in LOSS_LINES, t = 1:T],
vTAUX_POS[l, t] == vFLOW[l, t]

# Sum of auxiliary flow variables in either direction cannot exceed maximum line flow capacity
cTAuxLimitPos[l in LOSS_LINES, t = 1:T],
vTAUX_POS[l, t] <= EP[:eAvail_Trans_Cap_Pos][l]
end)
Copy link
Contributor

Choose a reason for hiding this comment

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

[JuliaFormatter] reported by reviewdog 🐶

Suggested change
begin
# Losses are alpha times absolute values
cTLossPos[l in LOSS_LINES, t = 1:T],
vTLOSSPos[l, t] ==
inputs["pPercent_LossPos"][l] * (vTAUX_POS[l, t])
# Power flow is sum of positive and negative components
cTAuxSum[l in LOSS_LINES, t = 1:T],
vTAUX_POS[l, t] == vFLOW[l, t]
# Sum of auxiliary flow variables in either direction cannot exceed maximum line flow capacity
cTAuxLimitPos[l in LOSS_LINES, t = 1:T],
vTAUX_POS[l, t] <= EP[:eAvail_Trans_Cap_Pos][l]
end)
begin
# Losses are alpha times absolute values
cTLossPos[l in LOSS_LINES, t = 1:T],
vTLOSSPos[l, t] ==
inputs["pPercent_LossPos"][l] * (vTAUX_POS[l, t])
# Power flow is sum of positive and negative components
cTAuxSum[l in LOSS_LINES, t = 1:T],
vTAUX_POS[l, t] == vFLOW[l, t]
# Sum of auxiliary flow variables in either direction cannot exceed maximum line flow capacity
cTAuxLimitPos[l in LOSS_LINES, t = 1:T],
vTAUX_POS[l, t] <= EP[:eAvail_Trans_Cap_Pos][l]
end)

Comment on lines +209 to +222
begin
# Losses are alpha times absolute values
cTLossNeg[l in LOSS_LINES, t = 1:T],
vTLOSSNeg[l, t] ==
inputs["pPercent_LossNeg"][l] * (vTAUX_NEG[l, t])

# Power flow is sum of positive and negative components
cTAuxSum[l in LOSS_LINES, t = 1:T],
vTAUX_NEG[l, t] == vFLOW[l, t]

# Sum of auxiliary flow variables in either direction cannot exceed maximum line flow capacity
cTAuxLimitNeg[l in LOSS_LINES, t = 1:T],
vTAUX_NEG[l, t] <= EP[:eAvail_Trans_Cap_Neg][l]
end)
Copy link
Contributor

Choose a reason for hiding this comment

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

[JuliaFormatter] reported by reviewdog 🐶

Suggested change
begin
# Losses are alpha times absolute values
cTLossNeg[l in LOSS_LINES, t = 1:T],
vTLOSSNeg[l, t] ==
inputs["pPercent_LossNeg"][l] * (vTAUX_NEG[l, t])
# Power flow is sum of positive and negative components
cTAuxSum[l in LOSS_LINES, t = 1:T],
vTAUX_NEG[l, t] == vFLOW[l, t]
# Sum of auxiliary flow variables in either direction cannot exceed maximum line flow capacity
cTAuxLimitNeg[l in LOSS_LINES, t = 1:T],
vTAUX_NEG[l, t] <= EP[:eAvail_Trans_Cap_Neg][l]
end)
begin
# Losses are alpha times absolute values
cTLossNeg[l in LOSS_LINES, t = 1:T],
vTLOSSNeg[l, t] ==
inputs["pPercent_LossNeg"][l] * (vTAUX_NEG[l, t])
# Power flow is sum of positive and negative components
cTAuxSum[l in LOSS_LINES, t = 1:T],
vTAUX_NEG[l, t] == vFLOW[l, t]
# Sum of auxiliary flow variables in either direction cannot exceed maximum line flow capacity
cTAuxLimitNeg[l in LOSS_LINES, t = 1:T],
vTAUX_NEG[l, t] <= EP[:eAvail_Trans_Cap_Neg][l]
end)

vTAUX_NEG[l, t] <= EP[:eAvail_Trans_Cap_Neg][l]
end)
else ## Do I need to model different expressions for linear losses for each direction, like the following?

Copy link
Contributor

Choose a reason for hiding this comment

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

[JuliaFormatter] reported by reviewdog 🐶

Suggested change

(inputs["pTrans_Loss_Coef"][l] *
sum((2 * s - 1) * (inputs["pTrans_Max_Possible"][l] / TRANS_LOSS_SEGS) *
vTAUX_NEG[l, s, t] for s in 1:TRANS_LOSS_SEGS)))
if setup["asymmetrical_trans_flow_limit"] ==1
Copy link
Contributor

Choose a reason for hiding this comment

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

[JuliaFormatter] reported by reviewdog 🐶

Suggested change
if setup["asymmetrical_trans_flow_limit"] ==1
if setup["asymmetrical_trans_flow_limit"] == 1

Comment on lines +284 to +285
sum((2 * s - 1) * (inputs["pTrans_Max_Possible"][l] / TRANS_LOSS_SEGS) *
vTAUX_POS[l, s, t] for s in 1:TRANS_LOSS_SEGS)) +
Copy link
Contributor

Choose a reason for hiding this comment

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

[JuliaFormatter] reported by reviewdog 🐶

Suggested change
sum((2 * s - 1) * (inputs["pTrans_Max_Possible"][l] / TRANS_LOSS_SEGS) *
vTAUX_POS[l, s, t] for s in 1:TRANS_LOSS_SEGS)) +
sum((2 * s - 1) * (inputs["pTrans_Max_Possible"][l] / TRANS_LOSS_SEGS) *
vTAUX_POS[l, s, t] for s in 1:TRANS_LOSS_SEGS)) +

Comment on lines +287 to +288
sum((2 * s - 1) * (inputs["pTrans_Max_Possible"][l] / TRANS_LOSS_SEGS) *
vTAUX_NEG[l, s, t] for s in 1:TRANS_LOSS_SEGS)))
Copy link
Contributor

Choose a reason for hiding this comment

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

[JuliaFormatter] reported by reviewdog 🐶

Suggested change
sum((2 * s - 1) * (inputs["pTrans_Max_Possible"][l] / TRANS_LOSS_SEGS) *
vTAUX_NEG[l, s, t] for s in 1:TRANS_LOSS_SEGS)))
sum((2 * s - 1) * (inputs["pTrans_Max_Possible"][l] / TRANS_LOSS_SEGS) *
vTAUX_NEG[l, s, t] for s in 1:TRANS_LOSS_SEGS)))

Comment on lines +295 to +296
sum((2 * s - 1) * (inputs["pTrans_Max_Possible"][l] / TRANS_LOSS_SEGS) *
vTAUX_POS[l, s, t] for s in 1:TRANS_LOSS_SEGS)) +
Copy link
Contributor

Choose a reason for hiding this comment

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

[JuliaFormatter] reported by reviewdog 🐶

Suggested change
sum((2 * s - 1) * (inputs["pTrans_Max_Possible"][l] / TRANS_LOSS_SEGS) *
vTAUX_POS[l, s, t] for s in 1:TRANS_LOSS_SEGS)) +
sum((2 * s - 1) * (inputs["pTrans_Max_Possible"][l] / TRANS_LOSS_SEGS) *
vTAUX_POS[l, s, t] for s in 1:TRANS_LOSS_SEGS)) +

Comment on lines +298 to +299
sum((2 * s - 1) * (inputs["pTrans_Max_Possible"][l] / TRANS_LOSS_SEGS) *
vTAUX_NEG[l, s, t] for s in 1:TRANS_LOSS_SEGS)))
Copy link
Contributor

Choose a reason for hiding this comment

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

[JuliaFormatter] reported by reviewdog 🐶

Suggested change
sum((2 * s - 1) * (inputs["pTrans_Max_Possible"][l] / TRANS_LOSS_SEGS) *
vTAUX_NEG[l, s, t] for s in 1:TRANS_LOSS_SEGS)))
sum((2 * s - 1) * (inputs["pTrans_Max_Possible"][l] / TRANS_LOSS_SEGS) *
vTAUX_NEG[l, s, t] for s in 1:TRANS_LOSS_SEGS)))

Copy link
Contributor

Choose a reason for hiding this comment

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

[JuliaFormatter] reported by reviewdog 🐶

begin
# Losses are alpha times absolute values
cTLoss[l in LOSS_LINES, t = 1:T],
vTLOSS[l, t] ==
inputs["pPercent_Loss"][l] * (vTAUX_POS[l, t] + vTAUX_NEG[l, t])
# Power flow is sum of positive and negative components
cTAuxSum[l in LOSS_LINES, t = 1:T],
vTAUX_POS[l, t] - vTAUX_NEG[l, t] == vFLOW[l, t]
# Sum of auxiliary flow variables in either direction cannot exceed maximum line flow capacity
cTAuxLimit[l in LOSS_LINES, t = 1:T],
vTAUX_POS[l, t] + vTAUX_NEG[l, t] <= EP[:eAvail_Trans_Cap][l]
end)

@JesseJenkins
Copy link
Collaborator

@sambuddhac will redraft PR based on conversation about how to limit duplication of code. We will create positive and negative instances of the key input parameters (max flows, max expansion, loss coefficients), use these two versions to constrain the positive and negative flow variables within the constraints in transmission.jl and investment_transmission.jl to avoid duplicated code in if/else blocks for assymetric/symmetric lines. Then when reading and setting up inputs, these two input parameters will be equal to one another if the line is symmetric. Then the code works from there for either type of line and we dont need if/else options within the constraints/expressions.

@sambuddhac
Copy link
Collaborator Author

@sambuddhac will redraft PR based on conversation about how to limit duplication of code. We will create positive and negative instances of the key input parameters (max flows, max expansion, loss coefficients), use these two versions to constrain the positive and negative flow variables within the constraints in transmission.jl and investment_transmission.jl to avoid duplicated code in if/else blocks for assymetric/symmetric lines. Then when reading and setting up inputs, these two input parameters will be equal to one another if the line is symmetric. Then the code works from there for either type of line and we dont need if/else options within the constraints/expressions.

PR #789 is the new PR. Please note that I am in the middle of pushing a bunch of updates to that. So, please hang in there for a bit more. Will tag to review and merge once I am done.

@lbonaldo lbonaldo added the enhancement New feature or request label Dec 3, 2024
@sambuddhac sambuddhac closed this Dec 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Forward and reverse ratings for transmission lines
3 participants