@@ -4425,11 +4425,13 @@ def get_grid_capacity(n, region, year):
4425
4425
] *= 0.5
4426
4426
4427
4427
# NEP subsets
4428
+ current_year = n .generators .build_year .max ()
4428
4429
nep_dc = dc_links .query (
4429
- "index.str.startswith('DC') or index=='TYNDP2020_1' or index=='TYNDP2020_2' or index=='TYNDP2020_23'"
4430
+ "(index.str.startswith('DC') or index.str.startswith('TYNDP')) and build_year > 2025 and (@current_year - 5 < build_year <= @current_year)"
4431
+ ).index
4432
+ nep_ac = ac_lines .query (
4433
+ "(build_year > 2025) and (@current_year - 5 < build_year <= @current_year)"
4430
4434
).index
4431
- nep_ac = ac_lines .query ("build_year > 2000" ).index
4432
-
4433
4435
var ["Capacity|Electricity|Transmission|DC" ] = (
4434
4436
dc_links .eval ("p_nom_opt * length" ).sum () * MW2GW
4435
4437
)
@@ -4448,15 +4450,15 @@ def get_grid_capacity(n, region, year):
4448
4450
snakemake .params .post_discretization ["link_unit_size" ]["DC" ]
4449
4451
- 5 # To account for numerical errors subtract a small capacity
4450
4452
)
4451
- .multiply ( snakemake .params .post_discretization ["link_unit_size" ]["DC" ] / 2000 )
4453
+ .div ( 2000 // ( snakemake .params .post_discretization ["link_unit_size" ]["DC" ] - 5 ) )
4452
4454
.multiply (dc_links .length )
4453
4455
.sum ()
4454
4456
)
4455
4457
var ["Length Additions|Electricity|Transmission|DC|NEP" ] = (
4456
4458
dc_links .loc [nep_dc ]
4457
4459
.eval ("p_nom_opt - p_nom_min" )
4458
4460
.floordiv (snakemake .params .post_discretization ["link_unit_size" ]["DC" ] - 5 )
4459
- .multiply ( snakemake .params .post_discretization ["link_unit_size" ]["DC" ] / 2000 )
4461
+ .div ( 2000 // ( snakemake .params .post_discretization ["link_unit_size" ]["DC" ] - 5 ) )
4460
4462
.multiply (dc_links .length )
4461
4463
.sum ()
4462
4464
)
@@ -4474,18 +4476,18 @@ def get_grid_capacity(n, region, year):
4474
4476
)
4475
4477
var ["Length Additions|Electricity|Transmission|AC" ] = (
4476
4478
ac_lines .eval ("s_nom_opt - s_nom_min" )
4477
- .floordiv (snakemake . params . post_discretization [ "line_unit_size" ] - 5 )
4478
- . mul (
4479
- snakemake . params . post_discretization [ "line_unit_size" ] / ( 2 * 2633 )
4480
- ) # Trassen size is 2 * 2633, we allow "fractional Trassen" to account for different line types
4479
+ .floordiv (
4480
+ snakemake . params . post_discretization [ "line_unit_size" ] - 5
4481
+ ) # To account for numerical errors subtract a small capacity
4482
+ . div ( 5265 // ( snakemake . params . post_discretization [ "line_unit_size" ] - 5 ))
4481
4483
.multiply (ac_lines .length )
4482
4484
.sum ()
4483
4485
)
4484
4486
var ["Length Additions|Electricity|Transmission|AC|NEP" ] = (
4485
4487
ac_lines .loc [nep_ac ]
4486
4488
.eval ("s_nom_opt - s_nom_min" )
4487
4489
.floordiv (snakemake .params .post_discretization ["line_unit_size" ] - 5 )
4488
- .mul ( snakemake .params .post_discretization ["line_unit_size" ] / ( 2 * 2633 ))
4490
+ .div ( 5265 // ( snakemake .params .post_discretization ["line_unit_size" ] - 5 ))
4489
4491
.multiply (ac_lines .length )
4490
4492
.sum ()
4491
4493
)
@@ -4530,7 +4532,7 @@ def get_grid_capacity(n, region, year):
4530
4532
return var
4531
4533
4532
4534
4533
- def hack_DC_projects (n , n_start , model_year , snakemake , costs ):
4535
+ def hack_DC_projects (n , p_nom_start , p_nom_planned , model_year , snakemake , costs ):
4534
4536
4535
4537
logger .info (f"Hacking DC projects for year { model_year } " )
4536
4538
@@ -4548,30 +4550,10 @@ def hack_DC_projects(n, n_start, model_year, snakemake, costs):
4548
4550
]
4549
4551
past_projects = tprojs [n .links .loc [tprojs , "build_year" ] <= (model_year - 5 )]
4550
4552
4551
- logger .info ("Post-Discretizing DC projects" )
4552
-
4553
- p_nom_start = n_start .links .loc [current_projects , "p_nom" ].apply (
4554
- lambda x : get_discretized_value (
4555
- x ,
4556
- snakemake .params .post_discretization ["link_unit_size" ]["DC" ],
4557
- snakemake .params .post_discretization ["link_threshold" ]["DC" ],
4558
- )
4559
- )
4560
-
4561
- # The values in p_nom_opt may already be discretized, here we make sure that
4562
- # the same logic is applied to p_nom and p_nom_min
4563
- for attr in ["p_nom_opt" , "p_nom" , "p_nom_min" ]:
4564
- n .links .loc [tprojs , attr ] = n .links .loc [tprojs , attr ].apply (
4565
- lambda x : get_discretized_value (
4566
- x ,
4567
- snakemake .params .post_discretization ["link_unit_size" ]["DC" ],
4568
- snakemake .params .post_discretization ["link_threshold" ]["DC" ],
4569
- )
4570
- )
4571
4553
for proj in tprojs :
4572
- if not isclose (n .links .loc [proj , "p_nom" ], n_start . links . loc [proj , "p_nom" ]):
4554
+ if not isclose (n .links .loc [proj , "p_nom" ], p_nom_planned [proj ]):
4573
4555
logger .warning (
4574
- f"Changed p_nom of { proj } from { n_start . links . loc [proj , 'p_nom' ]} to { n .links .loc [proj , 'p_nom' ]} "
4556
+ f"(Post-)discretization changed p_nom of { proj } from { p_nom_planned [proj ]} to { n .links .loc [proj , 'p_nom' ]} "
4575
4557
)
4576
4558
4577
4559
# Future projects should not have any capacity
@@ -4587,7 +4569,7 @@ def hack_DC_projects(n, n_start, model_year, snakemake, costs):
4587
4569
if (snakemake .params .NEP_year == 2021 ) or (
4588
4570
snakemake .params .NEP_transmission == "overhead"
4589
4571
):
4590
- logger .warning ("Switching DC projects to NEP23 costs post-optimization " )
4572
+ logger .warning ("Switching DC projects to NEP23 and underground costs. " )
4591
4573
n .links .loc [current_projects , "overnight_cost" ] = (
4592
4574
n .links .loc [current_projects , "length" ]
4593
4575
* (
@@ -4601,22 +4583,23 @@ def hack_DC_projects(n, n_start, model_year, snakemake, costs):
4601
4583
+ costs [0 ].at ["HVDC inverter pair" , "investment" ] / 1e-9
4602
4584
)
4603
4585
# Current projects should have their p_nom_opt bigger or equal to p_nom until the year 2030 (Startnetz that we force in)
4586
+ # TODO 2030 is hard coded but should be read from snakemake config
4604
4587
if model_year <= 2030 :
4605
4588
assert (
4606
4589
n .links .loc [current_projects , "p_nom_opt" ] + 0.1
4607
4590
>= n .links .loc [current_projects , "p_nom" ]
4608
4591
).all ()
4609
4592
4610
- n .links .loc [current_projects , "p_nom" ] -= p_nom_start
4611
- n .links .loc [current_projects , "p_nom_min" ] -= p_nom_start
4593
+ n .links .loc [current_projects , "p_nom" ] -= p_nom_start [ current_projects ]
4594
+ n .links .loc [current_projects , "p_nom_min" ] -= p_nom_start [ current_projects ]
4612
4595
4613
4596
else :
4614
4597
n .links .loc [current_projects , "p_nom" ] = n .links .loc [
4615
4598
current_projects , "p_nom_min"
4616
4599
]
4617
4600
4618
4601
# Past projects should have their p_nom_opt bigger or equal to p_nom
4619
- if model_year <= 2035 :
4602
+ if model_year <= 2030 + 5 :
4620
4603
assert (
4621
4604
n .links .loc [past_projects , "p_nom_opt" ] + 0.1 # numerical error tolerance
4622
4605
>= n .links .loc [past_projects , "p_nom" ]
@@ -4625,53 +4608,58 @@ def hack_DC_projects(n, n_start, model_year, snakemake, costs):
4625
4608
return n
4626
4609
4627
4610
4628
- def hack_AC_projects (n , n_start , model_year , snakemake ):
4611
+ def hack_AC_projects (n , s_nom_start , model_year , snakemake ):
4629
4612
logger .info (f"Hacking AC projects for year { model_year } " )
4630
4613
4631
- # All transmission projects have build_year > 0, this is implicit in the query
4632
- ac_projs = n .lines .query ("build_year > 0" ).index
4633
4614
current_projects = n .lines .query (
4634
4615
"@model_year - 5 < build_year <= @model_year"
4635
4616
).index
4636
4617
4637
- logger .info ("Post-Discretizing AC projects" )
4638
-
4639
- for attr in ["s_nom_opt" , "s_nom" , "s_nom_min" ]:
4640
- # The values in s_nom_opt may already be discretized, here we make sure that
4641
- # the same logic is applied to s_nom and s_nom_min
4642
- n .lines .loc [ac_projs , attr ] = n .lines .loc [ac_projs , attr ].apply (
4643
- lambda x : get_discretized_value (
4644
- x ,
4645
- snakemake .params .post_discretization ["line_unit_size" ],
4646
- snakemake .params .post_discretization ["line_threshold" ],
4647
- )
4648
- )
4649
-
4650
- s_nom_start = n_start .lines .loc [current_projects , "s_nom" ].apply (
4651
- lambda x : get_discretized_value (
4652
- x ,
4653
- snakemake .params .post_discretization ["line_unit_size" ],
4654
- snakemake .params .post_discretization ["line_threshold" ],
4655
- )
4656
- )
4657
-
4658
4618
if snakemake .params .NEP_year == 2021 :
4659
4619
logger .warning ("Switching AC projects to NEP23 costs post-optimization" )
4660
4620
n .lines .loc [current_projects , "overnight_cost" ] *= 772 / 472
4661
4621
4662
4622
# Eventhough the lines are available to the model from the start,
4663
- # we pretend that the lines were in expanded in this year
4623
+ # we pretend that the lines were expanded in the current year
4664
4624
# s_nom_start is used, because the model may expand lines
4665
4625
# endogenously before that or after that
4666
- n .lines .loc [current_projects , "s_nom" ] -= s_nom_start
4667
- n .lines .loc [current_projects , "s_nom_min" ] -= s_nom_start
4626
+ n .lines .loc [current_projects , "s_nom" ] -= s_nom_start [ current_projects ]
4627
+ n .lines .loc [current_projects , "s_nom_min" ] -= s_nom_start [ current_projects ]
4668
4628
4669
4629
return n
4670
4630
4671
4631
4672
- def hack_transmission_projects (n , n_start , model_year , snakemake , costs ):
4673
- n = hack_DC_projects (n , n_start , model_year , snakemake , costs )
4674
- n = hack_AC_projects (n , n_start , model_year , snakemake )
4632
+ def process_postnetworks (n , n_start , model_year , snakemake , costs ):
4633
+
4634
+ logger .info ("Post-Discretizing DC links" )
4635
+ _dc_lambda = lambda x : get_discretized_value (
4636
+ x ,
4637
+ snakemake .params .post_discretization ["link_unit_size" ]["DC" ],
4638
+ snakemake .params .post_discretization ["link_threshold" ]["DC" ],
4639
+ )
4640
+ for attr in ["p_nom_opt" , "p_nom" , "p_nom_min" ]:
4641
+ # The values in p_nom_opt may already be discretized, here we make sure that
4642
+ # the same logic is applied to p_nom and p_nom_min
4643
+ n .links [attr ] = n .links [attr ].apply (_dc_lambda )
4644
+
4645
+ p_nom_planned = n_start .links ["p_nom" ]
4646
+ p_nom_start = n_start .links ["p_nom" ].apply (_dc_lambda )
4647
+
4648
+ logger .info ("Post-Discretizing AC lines" )
4649
+ _ac_lambda = lambda x : get_discretized_value (
4650
+ x ,
4651
+ snakemake .params .post_discretization ["line_unit_size" ],
4652
+ snakemake .params .post_discretization ["line_threshold" ],
4653
+ )
4654
+ for attr in ["s_nom_opt" , "s_nom" , "s_nom_min" ]:
4655
+ # The values in s_nom_opt may already be discretized, here we make sure that
4656
+ # the same logic is applied to s_nom and s_nom_min
4657
+ n .lines [attr ] = n .lines [attr ].apply (_ac_lambda )
4658
+
4659
+ s_nom_start = n_start .lines ["s_nom" ].apply (_ac_lambda )
4660
+
4661
+ n = hack_DC_projects (n , p_nom_start , p_nom_planned , model_year , snakemake , costs )
4662
+ n = hack_AC_projects (n , s_nom_start , model_year , snakemake )
4675
4663
return n
4676
4664
4677
4665
@@ -4878,7 +4866,7 @@ def get_data(
4878
4866
modelyears = [fn [- 7 :- 3 ] for fn in snakemake .input .networks ]
4879
4867
# Hack the transmission projects
4880
4868
networks = [
4881
- hack_transmission_projects (n .copy (), _networks [0 ], int (my ), snakemake , costs )
4869
+ process_postnetworks (n .copy (), _networks [0 ], int (my ), snakemake , costs )
4882
4870
for n , my in zip (_networks , modelyears )
4883
4871
]
4884
4872
0 commit comments