Merge remote-tracking branch 'origin/master' into country-specific-dh-forward-temperatures

This commit is contained in:
AmosSchledorn 2024-08-13 17:07:29 +02:00
commit a017802976
17 changed files with 681 additions and 399 deletions

View File

@ -51,7 +51,7 @@ repos:
# Formatting with "black" coding style
- repo: https://github.com/psf/black-pre-commit-mirror
rev: 24.4.2
rev: 24.8.0
hooks:
# Format Python files
- id: black

View File

@ -759,7 +759,7 @@ industry:
MWh_CH4_per_tMeOH: 10.25
MWh_MeOH_per_tMeOH: 5.528
hotmaps_locate_missing: false
reference_year: 2015
reference_year: 2019
# docs in https://pypsa-eur.readthedocs.io/en/latest/configuration.html#costs

View File

@ -0,0 +1,16 @@
sector,2014,2015,2016,2017,2018,2019,2020,2021,2022,2023
Nahrung,19035,17728,16486,16782,16261,17062,17132,17335,15625,15713
Textil / Leder,1845,1742,1450,1497,1433,1488,1331,1496,1371,1112
Papier / Druck,12407,12257,11100,11086,9530,9436,8482,9186,8850,7657
Chemie / Pharma,27253,27050,27501,26953,26506,26055,24889,25595,25028,23240
Zement / Beton,15513,13307,13576,13429,13263,13221,12612,12843,12919,11400
Andere NE-Mineralien,4029,3820,3884,4254,3546,3577,3475,3602,3603,3178
Metall / Eisen,7841,7889,7638,8049,8053,7188,7051,6872,6782,5531
NE-Metall,3386,3037,2833,2813,2743,2931,2719,2992,2896,2653
Metall / Geräte,14652,14993,14272,14689,14300,15037,13946,15042,13862,12578
Maschinen,4561,4724,4861,4957,4365,4364,4061,4290,3698,3545
Andere Industrien,10750,10825,10225,9833,9689,9545,8696,9371,8823,8157
current electricity,55142,53760,51302,52173,51604,51389,48933,51730,50926,46969
,,,,,,,,,,
,,,,,,,,,,
"source: https://pubdb.bfe.admin.ch/de/publication/download/11817, accessed August 2024",,,,,,,,,,
1 sector 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023
2 Nahrung 19035 17728 16486 16782 16261 17062 17132 17335 15625 15713
3 Textil / Leder 1845 1742 1450 1497 1433 1488 1331 1496 1371 1112
4 Papier / Druck 12407 12257 11100 11086 9530 9436 8482 9186 8850 7657
5 Chemie / Pharma 27253 27050 27501 26953 26506 26055 24889 25595 25028 23240
6 Zement / Beton 15513 13307 13576 13429 13263 13221 12612 12843 12919 11400
7 Andere NE-Mineralien 4029 3820 3884 4254 3546 3577 3475 3602 3603 3178
8 Metall / Eisen 7841 7889 7638 8049 8053 7188 7051 6872 6782 5531
9 NE-Metall 3386 3037 2833 2813 2743 2931 2719 2992 2896 2653
10 Metall / Geräte 14652 14993 14272 14689 14300 15037 13946 15042 13862 12578
11 Maschinen 4561 4724 4861 4957 4365 4364 4061 4290 3698 3545
12 Andere Industrien 10750 10825 10225 9833 9689 9545 8696 9371 8823 8157
13 current electricity 55142 53760 51302 52173 51604 51389 48933 51730 50926 46969
14
15
16 source: https://pubdb.bfe.admin.ch/de/publication/download/11817, accessed August 2024

View File

@ -22,7 +22,7 @@ RS,25,5821
SI,8.86,1739
ES,0.251589260787732,1273
SE,50.4,
UK,2,
GB,2,
BY,70,
EE,52,5406
KO,3,207

1 country share to satisfy heat demand (residential) in percent capacity[MWth]
22 SI 8.86 1739
23 ES 0.251589260787732 1273
24 SE 50.4
25 UK GB 2
26 BY 70
27 EE 52 5406
28 KO 3 207

View File

@ -6,7 +6,7 @@ link_id,bus0,bus1,length,underground,under_construction,tags,geometry
5587,1377,2382,76847.0139826037,f,f,'"MW"=>"None", "TSO"=>"None", "oid"=>"32533", "ext1"=>"None", "EIC_2"=>"None", "EIC_3"=>"None", "EIC_4"=>"None", "text_"=>"200", "symbol"=>"DC-Line", "country"=>"IT", "t9_code"=>"0", "visible"=>"1", "EIC_code"=>"None", "tie_line"=>"0", "oneCircuit"=>"0", "CreatedDate"=>"None", "DeletedDate"=>"None", "ModifiedDate"=>"None", "Internalcomments"=>"None", "visible_on_printed"=>"1"','LINESTRING(8.67675371049727 40.6777653795244,9.03900099999999 40.979898,9.22164899999999 41.133159,9.19977299501706 41.2082924934473)'
5640,1422,1638,234733.218840324,f,f,'"MW"=>"None", "TSO"=>"None", "oid"=>"32590", "ext1"=>"None", "EIC_2"=>"None", "EIC_3"=>"None", "EIC_4"=>"None", "text_"=>"Rómulo", "symbol"=>"DC-Line", "country"=>"ES", "t9_code"=>"0", "visible"=>"1", "EIC_code"=>"None", "tie_line"=>"0", "oneCircuit"=>"0", "CreatedDate"=>"None", "DeletedDate"=>"None", "ModifiedDate"=>"None", "Internalcomments"=>"None", "visible_on_printed"=>"1"','LINESTRING(2.48932993486183 39.561252379133,1.13159199999999 39.610978,0 39.710356,-0.234388957535875 39.7314420592468)'
13589,2262,7428,316517.539537871,f,f,,'LINESTRING(9.17009350125146 41.2967653544603,9.38095099999999 41.331451,9.858856 41.352072,10.70755 41.479776,11.25 41.448903,12.100067 41.432431,12.380219 41.426253,12.418671 41.401536,12.704315 41.347948,12.805939 41.368564,12.9016442293009 41.3921592955445)'
14802,2258,7029,391819.608605717,f,t,,'LINESTRING(14.0986517070226 42.4133438660838,14.412689 42.431566,15.115814 42.363618,16.269379 42.067646,16.875 42.126747,16.962891 42.135913,18.531189 42.271212,18.7271798293119 42.3522936900005)'
14802,2258,7029,391819.608605717,f,f,,'LINESTRING(14.0986517070226 42.4133438660838,14.412689 42.431566,15.115814 42.363618,16.269379 42.067646,16.875 42.126747,16.962891 42.135913,18.531189 42.271212,18.7271798293119 42.3522936900005)'
14668,2333,3671,146536.932669904,f,t,,'LINESTRING(6.04271995139229 45.4637174756646,6.16607700000001 45.327048,6.351471 45.183973,6.54922499999999 45.148148,6.62338299999999 45.101638,6.642609 45.089036,6.70440700000001 45.05121,6.980438 45.089036,7.00653099999999 45.092914,7.21939099999999 45.094853,7.223511 45.089036,7.378693 44.871443,7.32136143270145 44.8385424366672)'
14808,2379,2383,103628.671904731,f,f,,'LINESTRING(9.37725891362686 42.7057449479108,9.79980499999999 42.799431,10.5931379465185 42.9693952059839)'
5575,2379,2380,24868.4258834249,f,f,'"MW"=>"None", "TSO"=>"None", "oid"=>"32521", "ext1"=>"None", "EIC_2"=>"None", "EIC_3"=>"None", "EIC_4"=>"None", "text_"=>" ", "symbol"=>"DC-Line", "country"=>"FR", "t9_code"=>"0", "visible"=>"1", "EIC_code"=>"None", "tie_line"=>"0", "oneCircuit"=>"0", "CreatedDate"=>"None", "DeletedDate"=>"None", "ModifiedDate"=>"None", "Internalcomments"=>"None", "visible_on_printed"=>"1"','LINESTRING(9.37679000208623 42.7053229039427,9.357605 42.552069,9.45054814341409 42.5389781005166)'
@ -15,7 +15,7 @@ link_id,bus0,bus1,length,underground,under_construction,tags,geometry
5583,2382,7428,11623.019620339,f,f,'"MW"=>"None", "TSO"=>"None", "oid"=>"32529", "ext1"=>"None", "EIC_2"=>"None", "EIC_3"=>"None", "EIC_4"=>"None", "text_"=>" ", "symbol"=>"DC-Line", "country"=>"IT", "t9_code"=>"FR-IT-01", "visible"=>"1", "EIC_code"=>"None", "tie_line"=>"1", "oneCircuit"=>"0", "CreatedDate"=>"None", "DeletedDate"=>"None", "ModifiedDate"=>"1.555323123e+12", "Internalcomments"=>"None", "visible_on_printed"=>"1"','LINESTRING(9.17008474107272 41.2967639130447,9.168091 41.303603,9.18319700000001 41.250968,9.1995514318356 41.2089447559651)'
14825,2476,2585,45367.7245799963,f,f,,'LINESTRING(2.98259070757654 42.2776059846425,2.90313700000001 42.397094,2.867432 42.467032,2.77404800000001 42.655172)'
8745,3611,8302,9361.61122972312,f,f,'"MW"=>"None", "TSO"=>"None", "oid"=>"120591", "ext1"=>"None", "EIC_2"=>"None", "EIC_3"=>"None", "EIC_4"=>"None", "text_"=>"None", "symbol"=>"DC-Line", "country"=>"CH", "t9_code"=>"None", "visible"=>"1", "EIC_code"=>"None", "tie_line"=>"0", "oneCircuit"=>"1", "CreatedDate"=>"1.556535027e+12", "DeletedDate"=>"None", "ModifiedDate"=>"None", "Internalcomments"=>"None", "visible_on_printed"=>"1"','LINESTRING(7.95410166666667 47.5542867377085,7.928009 47.555214,7.937622 47.526475,7.96895162362761 47.4961125343931)'
14801,4709,4781,50206.4589537583,f,t,,'LINESTRING(6.43068069229957 50.8136946409214,6.020508 50.766865,5.925751 50.755572,5.73118285928413 50.7304278585398)'
14801,4709,4781,50206.4589537583,f,f,,'LINESTRING(6.43068069229957 50.8136946409214,6.020508 50.766865,5.925751 50.755572,5.73118285928413 50.7304278585398)'
14814,4972,5062,232745.802729813,f,f,,'LINESTRING(4.04528166772434 51.9611233898246,2.41561900000001 51.702353,0.794192405058928 51.4189824547604)'
5558,4975,7427,45665.1050240866,f,t,'"MW"=>"None", "TSO"=>"None", "oid"=>"32502", "ext1"=>"None", "EIC_2"=>"None", "EIC_3"=>"None", "EIC_4"=>"None", "text_"=>" ", "symbol"=>"DC-Line", "country"=>"UK", "t9_code"=>" BE-UK-01", "visible"=>"1", "EIC_code"=>"None", "tie_line"=>"1", "oneCircuit"=>"0", "CreatedDate"=>"None", "DeletedDate"=>"None", "ModifiedDate"=>"1.555407949e+12", "Internalcomments"=>"None", "visible_on_printed"=>"1"','LINESTRING(1.92947399999999 51.251601,1.27623412238205 51.2327009391635)'
14826,4977,4983,52725.5506558225,f,f,,'LINESTRING(1.75051314494826 50.9186901861196,1.43508900000001 50.970535,1.02353536683349 51.0370060560335)'
@ -33,16 +33,16 @@ link_id,bus0,bus1,length,underground,under_construction,tags,geometry
5571,5743,7074,89346.6337548304,f,f,'"MW"=>"None", "TSO"=>"None", "oid"=>"32517", "ext1"=>"None", "EIC_2"=>"None", "EIC_3"=>"None", "EIC_4"=>"None", "text_"=>"HelWin1", "symbol"=>"DC-Line", "country"=>"DE", "t9_code"=>"0", "visible"=>"1", "EIC_code"=>"None", "tie_line"=>"0", "oneCircuit"=>"0", "CreatedDate"=>"None", "DeletedDate"=>"None", "ModifiedDate"=>"1.545224101e+12", "Internalcomments"=>"None", "visible_on_printed"=>"1"','LINESTRING(8.12610708224912 54.310749538123,8.238373 54.256401,9.32699442549698 53.9319562532009)'
5567,5744,5787,139209.866527364,f,f,'"MW"=>"None", "TSO"=>"None", "oid"=>"32512", "ext1"=>"None", "EIC_2"=>"None", "EIC_3"=>"None", "EIC_4"=>"None", "text_"=>"DolWin1", "symbol"=>"DC-Line", "country"=>"DE", "t9_code"=>"0", "visible"=>"1", "EIC_code"=>"None", "tie_line"=>"0", "oneCircuit"=>"0", "CreatedDate"=>"None", "DeletedDate"=>"None", "ModifiedDate"=>"1.545224147e+12", "Internalcomments"=>"None", "visible_on_printed"=>"1"','LINESTRING(6.84493115764205 53.880869,6.909027 53.880869,7.116394 53.835512,7.36358600000001 53.396432,7.32101399999999 53.112163,7.33612100000001 52.893992,7.16075117704058 52.8485079587114)'
5570,5745,8272,99066.5793764307,f,f,'"MW"=>"None", "TSO"=>"None", "oid"=>"32515", "ext1"=>"None", "EIC_2"=>"None", "EIC_3"=>"None", "EIC_4"=>"None", "text_"=>"DolWin3", "symbol"=>"DC-Line", "country"=>"DE", "t9_code"=>"0", "visible"=>"1", "EIC_code"=>"None", "tie_line"=>"0", "oneCircuit"=>"0", "CreatedDate"=>"None", "DeletedDate"=>"None", "ModifiedDate"=>"1.545224133e+12", "Internalcomments"=>"None", "visible_on_printed"=>"1"','LINESTRING(6.84423599483409 53.8134043878533,6.71127300000001 53.693454,6.65634200000001 53.59821,6.73461900000001 53.55581,7.112274 53.45126,7.05596900000001 53.340713,7.237244 53.26932,7.223511 53.18135,7.223511 53.1805270078955)'
14803,5751,5803,280301.445474794,f,t,,'LINESTRING(6.75668661933496 53.437616158174,6.838989 53.664171,6.96258499999999 53.785238,7.34298700000001 53.882488,7.80029300000001 54.517096,8.20678699999999 55.297102,8.86005375885099 55.4336013425692)'
14803,5751,5803,280301.445474794,f,f,,'LINESTRING(6.75668661933496 53.437616158174,6.838989 53.664171,6.96258499999999 53.785238,7.34298700000001 53.882488,7.80029300000001 54.517096,8.20678699999999 55.297102,8.86005375885099 55.4336013425692)'
14821,5749,6363,575352.425009444,f,f,,'LINESTRING(6.83036734046461 53.4374933986115,6.253967 53.645452,6.33636499999999 55.776573,6.34597800000001 56.029855,6.34597800000001 56.030622,6.43661500000001 58.130121,6.90176957000565 58.2653404287817)'
5568,5768,5787,131420.09609615,f,f,'"MW"=>"None", "TSO"=>"None", "oid"=>"32513", "ext1"=>"None", "EIC_2"=>"None", "EIC_3"=>"None", "EIC_4"=>"None", "text_"=>"DolWin2", "symbol"=>"DC-Line", "country"=>"DE", "t9_code"=>"0", "visible"=>"1", "EIC_code"=>"None", "tie_line"=>"0", "oneCircuit"=>"0", "CreatedDate"=>"None", "DeletedDate"=>"None", "ModifiedDate"=>"1.545224159e+12", "Internalcomments"=>"None", "visible_on_printed"=>"1"','LINESTRING(7.11083415172816 53.9630966319811,7.07107499999999 53.80795,7.301788 53.39807,7.267456 53.110514,7.29354899999999 52.907246,7.16070024970726 52.8485606886388)'
12932,5770,5773,6905.52230262641,f,t,,'LINESTRING(7.15460523215685 53.4027398808691,7.24823000000001 53.375956)'
14848,5858,6358,574884.998052791,f,t,,'LINESTRING(6.81690675921544 58.6338502746805,6.63024900000001 58.249559,6.78268399999999 57.579197,7.17544599999999 56.532986,7.17407200000001 56.5345,7.46521000000001 55.776573,7.46521000000001 55.776573,7.64099100000001 55.312736,8.458099 54.316523,9.394684 53.934262)'
14848,5858,6358,574884.998052791,f,f,,'LINESTRING(6.81690675921544 58.6338502746805,6.63024900000001 58.249559,6.78268399999999 57.579197,7.17544599999999 56.532986,7.17407200000001 56.5345,7.46521000000001 55.776573,7.46521000000001 55.776573,7.64099100000001 55.312736,8.458099 54.316523,9.394684 53.934262)'
5581,5893,6072,59184.4227659405,f,f,'"MW"=>"None", "TSO"=>"None", "oid"=>"32527", "ext1"=>"None", "EIC_2"=>"None", "EIC_3"=>"None", "EIC_4"=>"None", "text_"=>" ", "symbol"=>"DC-Line", "country"=>"UK", "t9_code"=>"222.1.2", "visible"=>"1", "EIC_code"=>"None", "tie_line"=>"1", "oneCircuit"=>"0", "CreatedDate"=>"None", "DeletedDate"=>"None", "ModifiedDate"=>"None", "Internalcomments"=>"None", "visible_on_printed"=>"1"','LINESTRING(-4.94702447012386 55.0727948492206,-5.137482 55.042188,-5.62500000000001 54.890036,-5.631866 54.887667,-5.7332134509551 54.813550429852)'
5580,5893,6072,58741.4601812995,f,f,'"MW"=>"None", "TSO"=>"None", "oid"=>"32526", "ext1"=>"None", "EIC_2"=>"None", "EIC_3"=>"None", "EIC_4"=>"None", "text_"=>" ", "symbol"=>"DC-Line", "country"=>"UK", "t9_code"=>"222.1.1", "visible"=>"1", "EIC_code"=>"None", "tie_line"=>"1", "oneCircuit"=>"0", "CreatedDate"=>"None", "DeletedDate"=>"None", "ModifiedDate"=>"None", "Internalcomments"=>"None", "visible_on_printed"=>"1"','LINESTRING(-4.94689333475508 55.0726735779237,-5.045471 55.009914,-5.59616099999999 54.840245,-5.62500000000001 54.834709,-5.73306677066227 54.8134313531551)'
8009,5897,5936,363085.503577327,f,f,'"MW"=>"None", "TSO"=>"None", "oid"=>"70191", "ext1"=>"None", "EIC_2"=>"None", "EIC_3"=>"None", "EIC_4"=>"None", "text_"=>"Western HVDC link", "symbol"=>"DC-Line", "country"=>"UK", "t9_code"=>"None", "visible"=>"1", "EIC_code"=>"None", "tie_line"=>"0", "oneCircuit"=>"0", "CreatedDate"=>"1.514994622e+12", "DeletedDate"=>"None", "ModifiedDate"=>"1.51499467e+12", "Internalcomments"=>"None", "visible_on_printed"=>"1"','LINESTRING(-3.18595885129092 53.213699479605,-3.158569 53.308724,-3.40988200000001 53.511735,-4.081421 53.803084,-5.158081 54.013418,-5.28442399999999 54.866334,-5.177307 55.345546,-4.88616899999999 55.586883,-4.8806877889882 55.7044245716822)'
14815,5937,6086,242400.41935291,f,f,,'LINESTRING(-3.12293971810515 53.2087645354697,-3.13934300000001 53.266034,-3.368683 53.377594,-5.18280000000001 53.495399,-5.62500000000001 53.519084,-5.62500000000001 53.519084,-6.101532 53.503568,-6.61057668606004 53.483977180569)'
14804,5949,6684,695432.776022422,f,t,,'LINESTRING(6.64773945778347 59.5995729910866,6.483307 59.539192,6.374817 59.538495,6.24847399999999 59.510636,6.196289 59.448566,5.898285 59.321981,5.64697299999999 59.234284,5.62500000000001 59.223042,4.81338500000001 58.813742,2.03384400000001 57.374679,0 56.170023,-0.650940000000012 55.776573,-1.55838055228731 55.2221613174321)'
14804,5949,6684,695432.776022422,f,f,,'LINESTRING(6.64773945778347 59.5995729910866,6.483307 59.539192,6.374817 59.538495,6.24847399999999 59.510636,6.196289 59.448566,5.898285 59.321981,5.64697299999999 59.234284,5.62500000000001 59.223042,4.81338500000001 58.813742,2.03384400000001 57.374679,0 56.170023,-0.650940000000012 55.776573,-1.55838055228731 55.2221613174321)'
5635,6300,6348,93313.2906756649,f,f,'"MW"=>"None", "TSO"=>"None", "oid"=>"32585", "ext1"=>"None", "EIC_2"=>"None", "EIC_3"=>"None", "EIC_4"=>"None", "text_"=>"150", "symbol"=>"DC-Line", "country"=>"SE", "t9_code"=>"0", "visible"=>"1", "EIC_code"=>"None", "tie_line"=>"0", "oneCircuit"=>"0", "CreatedDate"=>"None", "DeletedDate"=>"None", "ModifiedDate"=>"None", "Internalcomments"=>"None", "visible_on_printed"=>"1"','LINESTRING(18.2272491895352 57.5711315582343,17.274628 57.645401,16.875 57.674052,16.6818074486274 57.692364166947)'
14819,6311,6416,122337.134741418,f,f,,'LINESTRING(10.2163282994747 57.1311139024238,10.567474 57.20771,10.737762 57.192832,10.972595 57.230016,11.25 57.33171,11.532898 57.436081,11.867981 57.556366,12.0227165657676 57.561507168045)'
14809,6311,6416,122935.90852816,f,f,,'LINESTRING(10.2163571716117 57.1310010356663,10.366974 57.123569,10.578461 57.16678,10.740509 57.15263,11.001434 57.197296,11.174469 57.255281,11.25 57.282754,11.56723 57.399104,12.0227887239052 57.5613889668514)'
@ -58,6 +58,6 @@ link_id,bus0,bus1,length,underground,under_construction,tags,geometry
14818,6586,6618,257364.279393886,f,f,,'LINESTRING(21.3559064590049 61.0800030227353,21.303864 61.005076,20.946808 60.801394,18.153534 60.501202,18.007965 60.483615,17.171631 60.503906,17.0593630437863 60.5503864910584)'
14817,6589,6618,197128.229552834,f,f,,'LINESTRING(21.3557421230034 61.0800501553429,20.902863 60.846249,18.224945 60.556604,18.0193872312079 60.533018071939)'
14812,6620,6623,140169.735736189,f,f,,'LINESTRING(22.3045576957813 60.4368452717433,21.404114 60.329667,19.8472351583549 60.129935739173)'
8394,6684,6696,21158.5735245602,f,t,'"MW"=>"None", "TSO"=>"None", "oid"=>"89791", "ext1"=>"None", "EIC_2"=>"None", "EIC_3"=>"None", "EIC_4"=>"None", "text_"=>"None", "symbol"=>"DC-Line", "country"=>"NO", "t9_code"=>"None", "visible"=>"1", "EIC_code"=>"None", "tie_line"=>"0", "oneCircuit"=>"0", "CreatedDate"=>"1.518010133e+12", "DeletedDate"=>"None", "ModifiedDate"=>"None", "Internalcomments"=>"None", "visible_on_printed"=>"1"','LINESTRING(6.64851407057135 59.5996162767494,6.99238592942864 59.5246589234811)'
8394,6684,6696,21158.5735245602,f,f,'"MW"=>"None", "TSO"=>"None", "oid"=>"89791", "ext1"=>"None", "EIC_2"=>"None", "EIC_3"=>"None", "EIC_4"=>"None", "text_"=>"None", "symbol"=>"DC-Line", "country"=>"NO", "t9_code"=>"None", "visible"=>"1", "EIC_code"=>"None", "tie_line"=>"0", "oneCircuit"=>"0", "CreatedDate"=>"1.518010133e+12", "DeletedDate"=>"None", "ModifiedDate"=>"None", "Internalcomments"=>"None", "visible_on_printed"=>"1"','LINESTRING(6.64851407057135 59.5996162767494,6.99238592942864 59.5246589234811)'
5569,5787,8272,38561.1931761179,f,t,'"MW"=>"None", "TSO"=>"None", "oid"=>"32514", "ext1"=>"None", "EIC_2"=>"None", "EIC_3"=>"None", "EIC_4"=>"None", "text_"=>"DolWin 3", "symbol"=>"DC-Line", "country"=>"DE", "t9_code"=>"0", "visible"=>"1", "EIC_code"=>"None", "tie_line"=>"0", "oneCircuit"=>"0", "CreatedDate"=>"None", "DeletedDate"=>"None", "ModifiedDate"=>"1.489072219e+12", "Internalcomments"=>"None", "visible_on_printed"=>"1"','LINESTRING(7.223511 53.1805270078955,7.223511 53.179704,7.21527100000001 53.121229,7.24273699999999 52.932086,7.16056753068224 52.8486333236236)'
14813,7053,7430,192856.020480538,f,f,,'LINESTRING(10.8823542109264 53.948125809387,11.25 54.061,11.657867 54.186548,12.208557 54.386955,12.236023 54.402946,12.43515 54.541003,12.602692 54.684153,12.745514 54.844199,12.744141 54.842618,12.87735 54.979978,12.947388 55.077581,12.9299984288384 55.0630403498842)'

Can't render this file because it contains an unexpected character in line 2 and column 33.

View File

@ -15,6 +15,7 @@ Link:
"115000": 1200 # Caithness Moray HVDC
index:
"14804": 1400 # North-Sea link (NSN Link)
"8394": 1400 # North-Sea Link (NSN Link) continuation
"14822": 700 # NO-DK Skagerrak 4
"14827": 440 # NO-DK Skagerrak 3
"14810": 500 # NO-DK Skagerrak 1-2

View File

@ -9,6 +9,7 @@ Release Notes
Upcoming Release
================
* Update JRC-IDEES-2015 to `JRC-IDEES-2021 <https://publications.jrc.ec.europa.eu/repository/handle/JRC137809>`__. The reference year is changed from 2015 to 2019.
* Added option to use country-specific district heating forward and return temperatures. Defaults to lower temperatures in Scandinavia.

View File

@ -298,11 +298,12 @@ rule build_energy_totals:
co2="data/bundle/eea/UNFCCC_v23.csv",
swiss="data/switzerland-new_format-all_years.csv",
swiss_transport="data/gr-e-11.03.02.01.01-cc.csv",
idees="data/bundle/jrc-idees-2015",
idees="data/jrc-idees-2021",
district_heat_share="data/district_heat_share.csv",
eurostat="data/eurostat/Balances-April2023",
eurostat_households="data/eurostat/eurostat-household_energy_balances-february_2024.csv",
output:
transformation_output_coke=resources("transformation_output_coke.csv"),
energy_name=resources("energy_totals.csv"),
co2_name=resources("co2_totals.csv"),
transport_name=resources("transport_data.csv"),
@ -446,7 +447,9 @@ rule build_salt_cavern_potentials:
rule build_ammonia_production:
input:
usgs="data/bundle/myb1-2017-nitro.xls",
usgs=storage(
"https://d9-wret.s3.us-west-2.amazonaws.com/assets/palladium/production/s3fs-public/media/files/myb1-2022-nitro-ert.xlsx"
),
output:
ammonia_production=resources("ammonia_production.csv"),
threads: 1
@ -468,7 +471,7 @@ rule build_industry_sector_ratios:
ammonia=config_provider("sector", "ammonia", default=False),
input:
ammonia_production=resources("ammonia_production.csv"),
idees="data/bundle/jrc-idees-2015",
idees="data/jrc-idees-2021",
output:
industry_sector_ratios=resources("industry_sector_ratios.csv"),
threads: 1
@ -517,8 +520,9 @@ rule build_industrial_production_per_country:
industry=config_provider("industry"),
countries=config_provider("countries"),
input:
ch_industrial_production="data/ch_industrial_production_per_subsector.csv",
ammonia_production=resources("ammonia_production.csv"),
jrc="data/bundle/jrc-idees-2015",
jrc="data/jrc-idees-2021",
eurostat="data/eurostat/Balances-April2023",
output:
industrial_production_per_country=resources(
@ -665,7 +669,8 @@ rule build_industrial_energy_demand_per_country_today:
countries=config_provider("countries"),
industry=config_provider("industry"),
input:
jrc="data/bundle/jrc-idees-2015",
transformation_output_coke=resources("transformation_output_coke.csv"),
jrc="data/jrc-idees-2021",
industrial_production_per_country=resources(
"industrial_production_per_country.csv"
),

View File

@ -22,7 +22,6 @@ if config["enable"]["retrieve"] and config["enable"].get("retrieve_databundle",
"corine/g250_clc06_V18_5.tif",
"eea/UNFCCC_v23.csv",
"nuts/NUTS_RG_10M_2013_4326_LEVL_2.geojson",
"myb1-2017-nitro.xls",
"emobility/KFZ__count",
"emobility/Pkw__count",
"h2_salt_caverns_GWh_per_sqkm.geojson",
@ -57,6 +56,15 @@ if config["enable"]["retrieve"] and config["enable"].get("retrieve_databundle",
script:
"../scripts/retrieve_eurostat_data.py"
rule retrieve_jrc_idees:
output:
directory("data/jrc-idees-2021"),
log:
"logs/retrieve_jrc_idees.log",
retries: 2
script:
"../scripts/retrieve_jrc_idees.py"
rule retrieve_eurostat_household_data:
output:
"data/eurostat/eurostat-household_energy_balances-february_2024.csv",

View File

@ -18,7 +18,8 @@ Outputs
Description
-------
This functions takes data from the `Minerals Yearbook <https://www.usgs.gov/centers/national-minerals-information-center/nitrogen-statistics-and-information>`_ (June 2024) published by the US Geological Survey (USGS) and the National Minerals Information Center and extracts the annual ammonia production per country in ktonN/a. The data is converted to ktonNH3/a.
This functions takes data from the `Minerals Yearbook <https://www.usgs.gov/centers/national-minerals-information-center/nitrogen-statistics-and-information>`_
(July 2024) published by the US Geological Survey (USGS) and the National Minerals Information Center and extracts the annual ammonia production per country in ktonN/a. The data is converted to ktonNH3/a.
"""
import country_converter as coco
@ -42,15 +43,15 @@ if __name__ == "__main__":
skiprows=5,
header=0,
index_col=0,
skipfooter=19,
skipfooter=7,
na_values=["--"],
)
ammonia.index = cc.convert(ammonia.index, to="iso2")
years = [str(i) for i in range(2013, 2018)]
years = [str(i) for i in range(2018, 2023)]
ammonia = ammonia[years]
ammonia = ammonia.rename(columns=lambda x: str(x))[years]
# convert from ktonN to ktonNH3
ammonia *= 17 / 14

View File

@ -25,7 +25,7 @@ Inputs
- `data/bundle/eea_UNFCCC_v23.csv`: CO2 emissions data from EEA.
- `data/switzerland-new_format-all_years.csv`: Swiss energy data.
- `data/gr-e-11.03.02.01.01-cc.csv`: Swiss transport data
- `data/bundle/jrc-idees`: JRC IDEES data.
- `data/jrc-idees`: JRC IDEES data.
- `data/district_heat_share.csv`: District heating shares.
- `data/eurostat/Balances-April2023`: Eurostat energy balances.
- `data/eurostat/eurostat-household_energy_balances-february_2024.csv`: Eurostat household energy balances.
@ -110,7 +110,7 @@ def reverse(dictionary: dict) -> dict:
idees_rename = {"GR": "EL", "GB": "UK"}
eu28 = cc.EU28as("ISO2").ISO2.tolist()
eu27 = cc.EU27as("ISO2").ISO2.tolist()
eu28_eea = eu28.copy()
eu28_eea.remove("GB")
eu28_eea.append("UK")
@ -170,6 +170,7 @@ def eurostat_per_country(input_eurostat: str, country: str) -> pd.DataFrame:
sheet_name=None,
skiprows=4,
index_col=list(range(4)),
na_values=":",
)
sheet.pop("Cover")
return pd.concat(sheet)
@ -329,9 +330,9 @@ def idees_per_country(ct: str, base_dir: str) -> pd.DataFrame:
"""
ct_idees = idees_rename.get(ct, ct)
fn_residential = f"{base_dir}/JRC-IDEES-2015_Residential_{ct_idees}.xlsx"
fn_tertiary = f"{base_dir}/JRC-IDEES-2015_Tertiary_{ct_idees}.xlsx"
fn_transport = f"{base_dir}/JRC-IDEES-2015_Transport_{ct_idees}.xlsx"
fn_residential = f"{base_dir}/{ct_idees}/JRC-IDEES-2021_Residential_{ct_idees}.xlsx"
fn_tertiary = f"{base_dir}/{ct_idees}/JRC-IDEES-2021_Tertiary_{ct_idees}.xlsx"
fn_transport = f"{base_dir}/{ct_idees}/JRC-IDEES-2021_Transport_{ct_idees}.xlsx"
ct_totals = {}
@ -357,14 +358,14 @@ def idees_per_country(ct: str, base_dir: str) -> pd.DataFrame:
row = "Energy consumption by fuel - Eurostat structure (ktoe)"
ct_totals["total residential"] = df.loc[row]
assert df.index[47] == "Electricity"
ct_totals["electricity residential"] = df.iloc[47]
assert df.index[40] == "Electricity"
ct_totals["electricity residential"] = df.iloc[40]
assert df.index[46] == "Derived heat"
ct_totals["derived heat residential"] = df.iloc[46]
assert df.index[39] == "Distributed heat"
ct_totals["distributed heat residential"] = df.iloc[39]
assert df.index[50] == "Thermal uses"
ct_totals["thermal uses residential"] = df.iloc[50]
assert df.index[43] == "Thermal uses"
ct_totals["thermal uses residential"] = df.iloc[43]
# services
@ -390,14 +391,14 @@ def idees_per_country(ct: str, base_dir: str) -> pd.DataFrame:
row = "Energy consumption by fuel - Eurostat structure (ktoe)"
ct_totals["total services"] = df.loc[row]
assert df.index[50] == "Electricity"
ct_totals["electricity services"] = df.iloc[50]
assert df.index[43] == "Electricity"
ct_totals["electricity services"] = df.iloc[43]
assert df.index[49] == "Derived heat"
ct_totals["derived heat services"] = df.iloc[49]
assert df.index[42] == "Distributed heat"
ct_totals["distributed heat services"] = df.iloc[42]
assert df.index[53] == "Thermal uses"
ct_totals["thermal uses services"] = df.iloc[53]
assert df.index[46] == "Thermal uses"
ct_totals["thermal uses services"] = df.iloc[46]
# agriculture, forestry and fishing
@ -410,7 +411,7 @@ def idees_per_country(ct: str, base_dir: str) -> pd.DataFrame:
"Lighting",
"Ventilation",
"Specific electricity uses",
"Pumping devices (electric)",
"Pumping devices (electricity)",
]
ct_totals["total agriculture electricity"] = df.loc[rows].sum()
@ -419,8 +420,8 @@ def idees_per_country(ct: str, base_dir: str) -> pd.DataFrame:
rows = [
"Motor drives",
"Farming machine drives (diesel oil incl. biofuels)",
"Pumping devices (diesel oil incl. biofuels)",
"Farming machine drives (diesel oil and liquid biofuels)",
"Pumping devices (diesel oil and liquid biofuels)",
]
ct_totals["total agriculture machinery"] = df.loc[rows].sum()
@ -435,7 +436,7 @@ def idees_per_country(ct: str, base_dir: str) -> pd.DataFrame:
ct_totals["electricity road"] = df.loc["Electricity"]
ct_totals["total two-wheel"] = df.loc["Powered 2-wheelers (Gasoline)"]
ct_totals["total two-wheel"] = df.loc["Powered two-wheelers (Gasoline)"]
assert df.index[19] == "Passenger cars"
ct_totals["total passenger cars"] = df.iloc[19]
@ -449,13 +450,13 @@ def idees_per_country(ct: str, base_dir: str) -> pd.DataFrame:
assert df.index[39] == "Battery electric vehicles"
ct_totals["electricity other road passenger"] = df.iloc[39]
assert df.index[41] == "Light duty vehicles"
assert df.index[41] == "Light commercial vehicles"
ct_totals["total light duty road freight"] = df.iloc[41]
assert df.index[49] == "Battery electric vehicles"
ct_totals["electricity light duty road freight"] = df.iloc[49]
row = "Heavy duty vehicles (Diesel oil incl. biofuels)"
row = "Heavy goods vehicles (Diesel oil incl. biofuels)"
ct_totals["total heavy duty road freight"] = df.loc[row]
assert df.index[61] == "Passenger cars"
@ -463,44 +464,45 @@ def idees_per_country(ct: str, base_dir: str) -> pd.DataFrame:
df = pd.read_excel(fn_transport, "TrRail_ene", index_col=0)
ct_totals["total rail"] = df.loc["by fuel (EUROSTAT DATA)"]
ct_totals["total rail"] = df.loc["by fuel"]
ct_totals["electricity rail"] = df.loc["Electricity"]
assert df.index[15] == "Passenger transport"
ct_totals["total rail passenger"] = df.iloc[15]
assert df.index[9] == "Passenger transport"
ct_totals["total rail passenger"] = df.iloc[9]
assert df.index[16] == "Metro and tram, urban light rail"
assert df.index[19] == "Electric"
assert df.index[20] == "High speed passenger trains"
ct_totals["electricity rail passenger"] = df.iloc[[16, 19, 20]].sum()
assert df.index[10] == "Metro and tram, urban light rail"
assert df.index[13] == "Electric"
assert df.index[14] == "High speed passenger trains"
ct_totals["electricity rail passenger"] = df.iloc[[10, 13, 14]].sum()
assert df.index[21] == "Freight transport"
ct_totals["total rail freight"] = df.iloc[21]
assert df.index[15] == "Freight transport"
ct_totals["total rail freight"] = df.iloc[15]
assert df.index[23] == "Electric"
ct_totals["electricity rail freight"] = df.iloc[23]
assert df.index[17] == "Electric"
ct_totals["electricity rail freight"] = df.iloc[17]
df = pd.read_excel(fn_transport, "TrAvia_ene", index_col=0)
assert df.index[6] == "Passenger transport"
ct_totals["total aviation passenger"] = df.iloc[6]
assert df.index[4] == "Passenger transport"
ct_totals["total aviation passenger"] = df.iloc[4]
assert df.index[10] == "Freight transport"
ct_totals["total aviation freight"] = df.iloc[10]
assert df.index[8] == "Freight transport"
ct_totals["total aviation freight"] = df.iloc[8]
assert df.index[7] == "Domestic"
ct_totals["total domestic aviation passenger"] = df.iloc[7]
assert df.index[2] == "Domestic"
ct_totals["total domestic aviation passenger"] = df.iloc[2]
assert df.index[8] == "International - Intra-EU"
assert df.index[9] == "International - Extra-EU"
ct_totals["total international aviation passenger"] = df.iloc[[8, 9]].sum()
assert df.index[6] == "International - Intra-EEAwUK"
assert df.index[7] == "International - Extra-EEAwUK"
ct_totals["total international aviation passenger"] = df.iloc[[6, 7]].sum()
assert df.index[11] == "Domestic and International - Intra-EU"
ct_totals["total domestic aviation freight"] = df.iloc[11]
assert df.index[9] == "Domestic"
assert df.index[10] == "International - Intra-EEAwUK"
ct_totals["total domestic aviation freight"] = df.iloc[[9, 10]].sum()
assert df.index[12] == "International - Extra-EU"
ct_totals["total international aviation freight"] = df.iloc[12]
assert df.index[11] == "International - Extra-EEAwUK"
ct_totals["total international aviation freight"] = df.iloc[11]
ct_totals["total domestic aviation"] = (
ct_totals["total domestic aviation freight"]
@ -515,7 +517,7 @@ def idees_per_country(ct: str, base_dir: str) -> pd.DataFrame:
df = pd.read_excel(fn_transport, "TrNavi_ene", index_col=0)
# coastal and inland
ct_totals["total domestic navigation"] = df.loc["by fuel (EUROSTAT DATA)"]
ct_totals["total domestic navigation"] = df.loc["Energy consumption (ktoe)"]
df = pd.read_excel(fn_transport, "TrRoad_act", index_col=0)
@ -567,15 +569,51 @@ def build_idees(countries: List[str]) -> pd.DataFrame:
names=["country", "year"],
)
# clean up dataframe
years = np.arange(2000, 2022)
totals = totals[totals.index.get_level_values(1).isin(years)]
# efficiency kgoe/100km -> ktoe/100km so that after conversion TWh/100km
totals.loc[:, "passenger car efficiency"] /= 1e6
# convert ktoe to TWh
exclude = totals.columns.str.fullmatch("passenger cars")
totals = totals.copy()
totals.loc[:, ~exclude] *= 11.63 / 1e3
return totals
def fill_missing_years(fill_values: pd.Series) -> pd.Series:
"""
Fill missing years for some countries by first using forward fill (ffill)
and then backward fill (bfill).
Parameters
----------
fill_values : pd.Series
A pandas Series with a MultiIndex (levels: country and year) representing
energy values, where some values may be zero and need to be filled.
Returns
-------
pd.Series
A pandas Series with zero values replaced by the forward-filled and
backward-filled values of the corresponding country.
Notes
-----
- The function groups the data by the 'country' level and performs forward fill
and backward fill to fill zero values.
- Zero values in the original Series are replaced by the ffilled and bfilled
value of their respective country group.
"""
# Forward fill and then backward fill within each country group
fill_values = fill_values.groupby(level="country").ffill().bfill()
return fill_values
def build_energy_totals(
countries: List[str],
eurostat: pd.DataFrame,
@ -629,6 +667,8 @@ def build_energy_totals(
slicer = idx[in_eurostat, :, :, "Bunkers", :]
fill_values = eurostat.loc[slicer, "Total all products"].groupby(level=[0, 1]).sum()
# fill missing years for some countries by mean over the other years
fill_values = fill_missing_years(fill_values)
df.loc[in_eurostat, "total international navigation"] = fill_values
# add swiss energy data
@ -636,6 +676,36 @@ def build_energy_totals(
df = pd.concat([df.drop("CH", errors="ignore"), swiss]).sort_index()
# get values for missing countries based on Eurostat EnergyBalances
# agriculture
to_fill = df.index[
df["total agriculture"].isna()
& df.index.get_level_values("country").isin(eurostat_countries)
]
c = to_fill.get_level_values("country")
y = to_fill.get_level_values("year")
# take total final energy consumption from Eurostat
eurostat_sector = "Agriculture & forestry"
slicer = idx[c, y, :, :, eurostat_sector]
fill_values = eurostat.loc[slicer]["Total all products"].groupby(level=[0, 1]).sum()
# fill missing years for some countries by mean over the other years
fill_values = fill_missing_years(fill_values)
df.loc[to_fill, "total agriculture"] = fill_values
# split into end uses by average EU data from IDEES
uses = ["electricity", "heat", "machinery"]
for use in uses:
avg = (
idees["total agriculture electricity"] / idees["total agriculture"]
).mean()
df.loc[to_fill, f"total agriculture {use}"] = (
df.loc[to_fill, "total agriculture"] * avg
)
# divide cooking/space/water according to averages in EU28
uses = ["space", "cooking", "water"]
@ -657,6 +727,8 @@ def build_energy_totals(
fill_values = (
eurostat.loc[slicer, eurostat_fuels[fuel]].groupby(level=[0, 1]).sum()
)
# fill missing years for some countries by mean over the other years
fill_values = fill_missing_years(fill_values)
df.loc[to_fill, f"{fuel} {sector}"] = fill_values
for sector in ["residential", "services"]:
@ -664,7 +736,9 @@ def build_energy_totals(
for use in uses:
fuel_use = df[f"electricity {sector} {use}"]
fuel = df[f"electricity {sector}"]
fuel = (
df[f"electricity {sector}"].replace(0, np.nan).infer_objects(copy=False)
)
avg = fuel_use.div(fuel).mean()
logger.debug(
f"{sector}: average fraction of electricity for {use} is {avg:.3f}"
@ -680,6 +754,7 @@ def build_energy_totals(
df[f"total {sector} {use}"] - df[f"electricity {sector} {use}"]
)
nonelectric = df[f"total {sector}"] - df[f"electricity {sector}"]
nonelectric = nonelectric.copy().replace(0, np.nan)
avg = nonelectric_use.div(nonelectric).mean()
logger.debug(
f"{sector}: average fraction of non-electric for {use} is {avg:.3f}"
@ -716,6 +791,7 @@ def build_energy_totals(
nonelectric = (
no_norway[f"total {sector}"] - no_norway[f"electricity {sector}"]
)
nonelectric = nonelectric.copy().replace(0, np.nan)
fraction = nonelectric_use.div(nonelectric).mean()
df.loc["NO", f"total {sector} {use}"] = (
total_heating * fraction
@ -728,16 +804,22 @@ def build_energy_totals(
slicer = idx[c, y, :, :, "Domestic aviation"]
fill_values = eurostat.loc[slicer, "Total all products"].groupby(level=[0, 1]).sum()
# fill missing years for some countries by mean over the other years
fill_values = fill_missing_years(fill_values)
df.loc[to_fill, "total domestic aviation"] = fill_values
slicer = idx[c, y, :, :, "International aviation"]
fill_values = eurostat.loc[slicer, "Total all products"].groupby(level=[0, 1]).sum()
# fill missing years for some countries by mean over the other years
fill_values = fill_missing_years(fill_values)
df.loc[to_fill, "total international aviation"] = fill_values
# missing domestic navigation
slicer = idx[c, y, :, :, "Domestic Navigation"]
fill_values = eurostat.loc[slicer, "Total all products"].groupby(level=[0, 1]).sum()
# fill missing years for some countries by mean over the other years
fill_values = fill_missing_years(fill_values)
df.loc[to_fill, "total domestic navigation"] = fill_values
# split road traffic for non-IDEES
@ -793,7 +875,9 @@ def build_energy_totals(
mean_BA = df.loc["BA"].loc[2014:2021, "total residential"].mean()
mean_RS = df.loc["RS"].loc[2014:2021, "total residential"].mean()
ratio = mean_BA / mean_RS
df.loc["BA"] = df.loc["BA"].replace(0.0, np.nan).values
df.loc["BA"] = (
df.loc["BA"].replace(0.0, np.nan).infer_objects(copy=False).values
)
df.loc["BA"] = df.loc["BA"].combine_first(ratio * df.loc["RS"]).values
return df
@ -817,18 +901,20 @@ def build_district_heat_share(countries: List[str], idees: pd.DataFrame) -> pd.S
Notes
-----
- The function calculates the district heating share as the sum of residential and services derived heat, divided by the sum of residential and services thermal uses.
- The function calculates the district heating share as the sum of residential and services distributed heat, divided by the sum of residential and services thermal uses.
- The district heating share is then reindexed to match the provided list of countries.
- Missing district heating shares are filled from `data/district_heat_share.csv`.
- The function makes a conservative assumption and takes the minimum district heating share from both the IDEES data and `data/district_heat_share.csv`.
"""
# district heating share
district_heat = idees[["derived heat residential", "derived heat services"]].sum(
axis=1
)
total_heat = idees[["thermal uses residential", "thermal uses services"]].sum(
axis=1
district_heat = idees[
["distributed heat residential", "distributed heat services"]
].sum(axis=1)
total_heat = (
idees[["thermal uses residential", "thermal uses services"]]
.sum(axis=1)
.replace(0, np.nan)
)
district_heat_share = district_heat / total_heat
@ -842,10 +928,15 @@ def build_district_heat_share(countries: List[str], idees: pd.DataFrame) -> pd.S
.squeeze()
)
# make conservative assumption and take minimum from both data sets
new_index = pd.MultiIndex.from_product(
[dh_share.index, district_heat_share.index.get_level_values(1).unique()]
)
district_heat_share = pd.concat(
[district_heat_share, dh_share.reindex_like(district_heat_share)], axis=1
[district_heat_share, dh_share.reindex(new_index, level=0)], axis=1
).min(axis=1)
district_heat_share = district_heat_share.reindex(countries, level=0)
district_heat_share.name = "district heat share"
# restrict to available years
@ -1086,6 +1177,12 @@ def build_transport_data(
transport_data.rename(columns={"passenger cars": "number cars"}, inplace=True)
# clean up dataframe
years = np.arange(2000, 2022)
transport_data = transport_data[
transport_data.index.get_level_values(1).isin(years)
]
missing = transport_data.index[transport_data["number cars"].isna()]
if not missing.empty:
logger.info(
@ -1123,8 +1220,8 @@ def rescale_idees_from_eurostat(
idees_countries: List[str], energy: pd.DataFrame, eurostat: pd.DataFrame
) -> pd.DataFrame:
"""
Takes JRC IDEES data from 2015 and rescales it by the ratio of the Eurostat
data and the 2015 Eurostat data.
Takes JRC IDEES data from 2021 and rescales it by the ratio of the Eurostat
data and the 2021 Eurostat data.
Missing data: ['passenger car efficiency', 'passenger cars']
Parameters
@ -1154,9 +1251,9 @@ def rescale_idees_from_eurostat(
main_cols = ["Total all products", "Electricity"]
# read in the eurostat data for 2015
eurostat_2015 = eurostat.xs(2015, level="year")[main_cols]
eurostat_2021 = eurostat.xs(2021, level="year")[main_cols]
# calculate the ratio of the two data sets
ratio = eurostat[main_cols] / eurostat_2015
ratio = eurostat[main_cols] / eurostat_2021
ratio = ratio.droplevel([2, 5])
cols_rename = {"Total all products": "total", "Electricity": "ele"}
index_rename = {v: k for k, v in idees_rename.items()}
@ -1169,7 +1266,7 @@ def rescale_idees_from_eurostat(
"total residential water",
"total residential cooking",
"total residential",
"derived heat residential",
"distributed heat residential",
"thermal uses residential",
],
"elec": [
@ -1185,7 +1282,7 @@ def rescale_idees_from_eurostat(
"total services water",
"total services cooking",
"total services",
"derived heat services",
"distributed heat services",
"thermal uses services",
],
"elec": [
@ -1376,6 +1473,33 @@ def update_residential_from_eurostat(energy: pd.DataFrame) -> pd.DataFrame:
)
def build_transformation_output_coke(eurostat, fn):
"""
Extracts and builds the transformation output data for coke ovens from the
Eurostat dataset.
This function specifically filters the Eurostat data to extract
transformation output related to coke ovens.
Since the transformation output for coke ovens
is not included in the final energy consumption of the iron and steel sector,
it needs to be processed and added separately. The filtered data is saved
as a CSV file.
Parameters:
eurostat (pd.DataFrame): A pandas DataFrame containing Eurostat data with
a multi-level index
fn (str): The file path where the resulting CSV file should be saved.
Output:
The resulting transformation output data for coke ovens is saved as a CSV
file at the path specified in fn.
"""
slicer = pd.IndexSlice[:, :, :, "Coke ovens", "Other sources", :]
df = eurostat.loc[slicer, :].droplevel(level=[2, 3, 4, 5])
df.to_csv(fn)
# %%
if __name__ == "__main__":
if "snakemake" not in globals():
from _helpers import mock_snakemake
@ -1391,7 +1515,7 @@ if __name__ == "__main__":
population = nuts3["pop"].groupby(nuts3.country).sum()
countries = snakemake.params.countries
idees_countries = pd.Index(countries).intersection(eu28)
idees_countries = pd.Index(countries).intersection(eu27)
input_eurostat = snakemake.input.eurostat
eurostat = build_eurostat(
@ -1400,15 +1524,16 @@ if __name__ == "__main__":
nprocesses=snakemake.threads,
disable_progressbar=snakemake.config["run"].get("disable_progressbar", False),
)
build_transformation_output_coke(
eurostat, snakemake.output.transformation_output_coke
)
swiss = build_swiss()
idees = build_idees(idees_countries)
energy = build_energy_totals(countries, eurostat, swiss, idees)
# Data from IDEES only exists from 2000-2015.
logger.info("Extrapolate IDEES data based on eurostat for years 2015-2021.")
energy = rescale_idees_from_eurostat(idees_countries, energy, eurostat)
update_residential_from_eurostat(energy)
energy.to_csv(snakemake.output.energy_name)

View File

@ -8,7 +8,7 @@ Build industrial energy demand per country.
Inputs
-------
- ``data/bundle/jrc-idees-2015``
- ``data/jrc-idees-2021``
- ``industrial_production_per_country.csv``
Outputs
@ -34,9 +34,9 @@ For each country and each subcategory of
- Glass production
- HVC
- Integrated steelworks
- Machinery Equipment
- Machinery equipment
- Methanol
- Other Industrial Sectors
- Other industrial sectors
- Other chemicals
- Other non-ferrous metals
- Paper production
@ -44,7 +44,7 @@ For each country and each subcategory of
- Printing and media reproduction
- Pulp production
- Textiles and leather
- Transport Equipment
- Transport equipment
- Wood and wood products
the output file contains the energy demand in TWh/a for the following carriers
@ -74,53 +74,56 @@ ktoe_to_twh = 0.011630
# name in JRC-IDEES Energy Balances
sector_sheets = {
"Integrated steelworks": "cisb",
"Electric arc": "cise",
"Alumina production": "cnfa",
"Aluminium - primary production": "cnfp",
"Aluminium - secondary production": "cnfs",
"Other non-ferrous metals": "cnfo",
"Basic chemicals": "cbch",
"Other chemicals": "coch",
"Pharmaceutical products etc.": "cpha",
"Basic chemicals feedstock": "cpch",
"Cement": "ccem",
"Ceramics & other NMM": "ccer",
"Glass production": "cgla",
"Pulp production": "cpul",
"Paper production": "cpap",
"Printing and media reproduction": "cprp",
"Food, beverages and tobacco": "cfbt",
"Transport Equipment": "ctre",
"Machinery Equipment": "cmae",
"Textiles and leather": "ctel",
"Wood and wood products": "cwwp",
"Mining and quarrying": "cmiq",
"Construction": "ccon",
"Non-specified": "cnsi",
"Integrated steelworks": "FC_IND_IS_BF_E",
"Electric arc": "FC_IND_IS_EA_E",
"Alumina production": "FC_IND_NFM_AM_E",
"Aluminium - primary production": "FC_IND_NFM_PA_E",
"Aluminium - secondary production": "FC_IND_NFM_SA_E",
"Other non-ferrous metals": "FC_IND_NFM_OM_E",
"Basic chemicals": "FC_IND_CPC_BC_E",
"Other chemicals": "FC_IND_CPC_OC_E",
"Pharmaceutical products etc.": "FC_IND_CPC_PH_E",
"Basic chemicals feedstock": "FC_IND_CPC_NE",
"Cement": "FC_IND_NMM_CM_E",
"Ceramics & other NMM": "FC_IND_NMM_CR_E",
"Glass production": "FC_IND_NMM_GL_E",
"Pulp production": "FC_IND_PPP_PU_E",
"Paper production": "FC_IND_PPP_PA_E",
"Printing and media reproduction": "FC_IND_PPP_PR_E",
"Food, beverages and tobacco": "FC_IND_FBT_E",
"Transport equipment": "FC_IND_TE_E",
"Machinery equipment": "FC_IND_MAC_E",
"Textiles and leather": "FC_IND_TL_E",
"Wood and wood products": "FC_IND_WP_E",
"Mining and quarrying": "FC_IND_MQ_E",
"Construction": "FC_IND_CON_E",
"Non-specified": "FC_IND_NSP_E",
}
fuels = {
"All Products": "all",
"Solid Fuels": "solid",
"Total petroleum products (without biofuels)": "liquid",
"Gases": "gas",
"Total": "all",
"Solid fossil fuels": "solid",
"Peat and peat products": "solid",
"Oil shale and oil sands": "solid",
"Oil and petroleum products": "liquid",
"Manufactured gases": "gas",
"Natural gas": "gas",
"Nuclear heat": "heat",
"Derived heat": "heat",
"Biomass and Renewable wastes": "biomass",
"Wastes (non-renewable)": "waste",
"Heat": "heat",
"Renewables and biofuels": "biomass",
"Non-renewable waste": "waste",
"Electricity": "electricity",
}
eu28 = cc.EU28as("ISO2").ISO2.tolist()
eu27 = cc.EU27as("ISO2").ISO2.tolist()
jrc_names = {"GR": "EL", "GB": "UK"}
def industrial_energy_demand_per_country(country, year, jrc_dir):
jrc_country = jrc_names.get(country, country)
fn = f"{jrc_dir}/JRC-IDEES-2015_EnergyBalance_{jrc_country}.xlsx"
fn = f"{jrc_dir}/{jrc_country}/JRC-IDEES-2021_EnergyBalance_{jrc_country}.xlsx"
sheets = list(sector_sheets.values())
df_dict = pd.read_excel(fn, sheet_name=sheets, index_col=0)
@ -139,7 +142,7 @@ def industrial_energy_demand_per_country(country, year, jrc_dir):
)
sel = ["Mining and quarrying", "Construction", "Non-specified"]
df["Other Industrial Sectors"] = df[sel].sum(axis=1)
df["Other industrial sectors"] = df[sel].sum(axis=1)
df["Basic chemicals"] += df["Basic chemicals feedstock"]
df.drop(columns=sel + ["Basic chemicals feedstock"], index="all", inplace=True)
@ -189,20 +192,20 @@ def separate_basic_chemicals(demand, production):
return demand
def add_non_eu28_industrial_energy_demand(countries, demand, production):
non_eu28 = countries.difference(eu28)
if non_eu28.empty:
def add_non_eu27_industrial_energy_demand(countries, demand, production):
non_eu27 = countries.difference(eu27)
if non_eu27.empty:
return demand
eu28_production = production.loc[countries.intersection(eu28)].sum()
eu28_energy = demand.groupby(level=1).sum()
eu28_averages = eu28_energy / eu28_production
eu27_production = production.loc[countries.intersection(eu27)].sum()
eu27_energy = demand.groupby(level=1).sum()
eu27_averages = eu27_energy / eu27_production
demand_non_eu28 = pd.concat(
{k: v * eu28_averages for k, v in production.loc[non_eu28].iterrows()}
demand_non_eu27 = pd.concat(
{k: v * eu27_averages for k, v in production.loc[non_eu27].iterrows()}
)
return pd.concat([demand, demand_non_eu28])
return pd.concat([demand, demand_non_eu27])
def industrial_energy_demand(countries, year):
@ -224,6 +227,48 @@ def industrial_energy_demand(countries, year):
return pd.concat(demand_l, keys=countries)
def add_coke_ovens(demand, fn, year, factor=0.75):
"""
Adds the energy consumption of coke ovens to the energy demand for
integrated steelworks.
This function reads the energy consumption data for coke ovens from a
CSV file, processes it to match the structure of the `demand` DataFrame,
and then adds a specified share of this energy consumption to the energy
demand for integrated steelworks.
The `factor` parameter controls what proportion of the coke ovens' energy
consumption should be attributed to the iron and steel production.
The default value of 75% is based on https://doi.org/10.1016/j.erss.2022.102565
Parameters:
demand (pd.DataFrame): A pandas DataFrame containing energy demand data
with a multi-level column index where one of the
levels corresponds to "Integrated steelworks".
fn (str): The file path to the CSV file containing the coke ovens energy
consumption data.
year (int): The year for which the coke ovens data should be selected.
factor (float, optional): The proportion of coke ovens energy consumption to add to the
integrated steelworks demand. Defaults to 0.75.
Returns:
pd.DataFrame: The updated `demand` DataFrame with the coke ovens energy
consumption added to the integrated steelworks energy demand.
"""
df = pd.read_csv(fn, index_col=[0, 1]).xs(year, level=1)
df = df.rename(columns={"Total all products": "Total"})[fuels.keys()]
df = df.rename(columns=fuels).T.groupby(level=0).sum().T
df["other"] = df["all"] - df.loc[:, df.columns != "all"].sum(axis=1)
df = df.T.reindex_like(demand.xs("Integrated steelworks", axis=1, level=1)).fillna(
0
)
sel = demand.columns.get_level_values(1) == "Integrated steelworks"
demand.loc[:, sel] += factor * df.values
return demand
if __name__ == "__main__":
if "snakemake" not in globals():
from _helpers import mock_snakemake
@ -232,10 +277,10 @@ if __name__ == "__main__":
set_scenario_config(snakemake)
params = snakemake.params.industry
year = params.get("reference_year", 2015)
year = params.get("reference_year", 2019)
countries = pd.Index(snakemake.params.countries)
demand = industrial_energy_demand(countries.intersection(eu28), year)
demand = industrial_energy_demand(countries.intersection(eu27), year)
# output in MtMaterial/a
production = (
@ -245,11 +290,14 @@ if __name__ == "__main__":
demand = separate_basic_chemicals(demand, production)
demand = add_non_eu28_industrial_energy_demand(countries, demand, production)
demand = add_non_eu27_industrial_energy_demand(countries, demand, production)
# for format compatibility
demand = demand.stack(future_stack=True).unstack(level=[0, 2])
# add energy consumption of coke ovens
demand = add_coke_ovens(demand, snakemake.input.transformation_output_coke, year)
# style and annotation
demand.index.name = "TWh/a"
demand.sort_index(axis=1, inplace=True)

View File

@ -16,7 +16,7 @@ Relevant Settings
Inputs
-------
- ``resources/ammonia_production.csv``
- ``data/bundle-sector/jrc-idees-2015``
- ``data/bundle-sector/jrc-idees-2021``
- ``data/eurostat``
Outputs
@ -31,7 +31,7 @@ The industrial production is taken from the `JRC-IDEES <https://joint-research-c
This dataset provides detailed information about the consumption of energy for various processes.
If the country is not part of the EU28, the energy consumption in the industrial sectors is taken from the `Eurostat <https://ec.europa.eu/eurostat/de/data/database>` dataset. The industrial production is calculated for the year specified in the config["industry"]["reference_year"].
The ammonia production is provided by the rule `build_ammonia_production <https://pypsa-eur.readthedocs.io/en/latest/sector.html#module-build_ammonia_production>`. Since Switzerland is not part of the EU28 nor reported by eurostat, the energy consumption in the industrial sectors is taken from the `BFE <https://www.bfe.admin.ch/bfe/de/home/versorgung/statistik-und-geodaten/energiestatistiken/energieverbrauch-nach-verwendungszweck.html> dataset.
The ammonia production is provided by the rule `build_ammonia_production <https://pypsa-eur.readthedocs.io/en/latest/sector.html#module-build_ammonia_production>`. Since Switzerland is not part of the EU28 nor reported by eurostat, the energy consumption in the industrial sectors is taken from the `BFE <https://pubdb.bfe.admin.ch/de/publication/download/11817> dataset.
After the industrial production is calculated, the basic chemicals are separated into ammonia, chlorine, methanol and HVC. The production of these chemicals is assumed to be proportional to the production of basic chemicals without ammonia.
The following subcategories [kton/a] are considered:
@ -50,11 +50,11 @@ The following subcategories [kton/a] are considered:
- Aluminium - primary production
- Aluminium - secondary production
- Other non-ferrous metals
- Transport Equipment
- Machinery Equipment
- Transport equipment
- Machinery equipment
- Textiles and leather
- Wood and wood products
- Other Industrial Sectors
- Other industrial sectors
- Ammonia
- HVC
- Chlorine
@ -79,25 +79,25 @@ ktoe_to_twh = 0.01163
sub_sheet_name_dict = {
"Iron and steel": "ISI",
"Chemicals Industry": "CHI",
"Chemical industry": "CHI",
"Non-metallic mineral products": "NMM",
"Pulp, paper and printing": "PPA",
"Food, beverages and tobacco": "FBT",
"Non Ferrous Metals": "NFM",
"Transport Equipment": "TRE",
"Machinery Equipment": "MAE",
"Transport equipment": "TRE",
"Machinery equipment": "MAE",
"Textiles and leather": "TEL",
"Wood and wood products": "WWP",
"Other Industrial Sectors": "OIS",
"Other industrial sectors": "OIS",
}
eu28 = cc.EU28as("ISO2").ISO2.values
eu27 = cc.EU27as("ISO2").ISO2.values
jrc_names = {"GR": "EL", "GB": "UK"}
sect2sub = {
"Iron and steel": ["Electric arc", "Integrated steelworks"],
"Chemicals Industry": [
"Chemical industry": [
"Basic chemicals",
"Other chemicals",
"Pharmaceutical products etc.",
@ -119,11 +119,11 @@ sect2sub = {
"Aluminium - secondary production",
"Other non-ferrous metals",
],
"Transport Equipment": ["Transport Equipment"],
"Machinery Equipment": ["Machinery Equipment"],
"Transport equipment": ["Transport equipment"],
"Machinery equipment": ["Machinery equipment"],
"Textiles and leather": ["Textiles and leather"],
"Wood and wood products": ["Wood and wood products"],
"Other Industrial Sectors": ["Other Industrial Sectors"],
"Other industrial sectors": ["Other industrial sectors"],
}
sub2sect = {v: k for k, vv in sect2sub.items() for v in vv}
@ -145,47 +145,41 @@ fields = {
"Aluminium - primary production": "Aluminium - primary production",
"Aluminium - secondary production": "Aluminium - secondary production",
"Other non-ferrous metals": "Other non-ferrous metals (kt lead eq.)",
"Transport Equipment": "Physical output (index)",
"Machinery Equipment": "Physical output (index)",
"Transport equipment": "Physical output (index)",
"Machinery equipment": "Physical output (index)",
"Textiles and leather": "Physical output (index)",
"Wood and wood products": "Physical output (index)",
"Other Industrial Sectors": "Physical output (index)",
"Other industrial sectors": "Physical output (index)",
}
eb_sectors = {
"Iron & steel": "Iron and steel",
"Chemical & petrochemical": "Chemicals Industry",
"Chemical & petrochemical": "Chemical industry",
"Non-ferrous metals": "Non-metallic mineral products",
"Paper, pulp & printing": "Pulp, paper and printing",
"Food, beverages & tobacco": "Food, beverages and tobacco",
"Non-metallic minerals": "Non Ferrous Metals",
"Transport equipment": "Transport Equipment",
"Machinery": "Machinery Equipment",
"Transport equipment": "Transport equipment",
"Machinery": "Machinery equipment",
"Textile & leather": "Textiles and leather",
"Wood & wood products": "Wood and wood products",
"Not elsewhere specified (industry)": "Other Industrial Sectors",
"Not elsewhere specified (industry)": "Other industrial sectors",
}
# TODO: this should go in a csv in `data`
# Annual energy consumption in Switzerland by sector in 2015 (in TJ)
# From: Energieverbrauch in der Industrie und im Dienstleistungssektor, Der Bundesrat
# http://www.bfe.admin.ch/themen/00526/00541/00543/index.html?lang=de&dossier_id=00775
e_switzerland = pd.Series(
{
"Iron and steel": 7889.0,
"Chemicals Industry": 26871.0,
"Non-metallic mineral products": 15513.0 + 3820.0,
"Pulp, paper and printing": 12004.0,
"Food, beverages and tobacco": 17728.0,
"Non Ferrous Metals": 3037.0,
"Transport Equipment": 14993.0,
"Machinery Equipment": 4724.0,
"Textiles and leather": 1742.0,
"Wood and wood products": 0.0,
"Other Industrial Sectors": 10825.0,
"current electricity": 53760.0,
}
)
ch_mapping = {
"Nahrung": "Food, beverages and tobacco",
"Textil / Leder": "Textiles and leather",
"Papier / Druck": "Pulp, paper and printing",
"Chemie / Pharma": "Chemical industry",
"Zement / Beton": "Non-metallic mineral products",
"Andere NE-Mineralien": "Other non-ferrous metals",
"Metall / Eisen": "Iron and steel",
"NE-Metall": "Non Ferrous Metals",
"Metall / Geräte": "Transport equipment",
"Maschinen": "Machinery equipment",
"Andere Industrien": "Other industrial sectors",
}
def find_physical_output(df):
@ -197,32 +191,39 @@ def find_physical_output(df):
def get_energy_ratio(country, eurostat_dir, jrc_dir, year):
if country == "CH":
e_country = e_switzerland * tj_to_ktoe
# data ranges between 2014-2023
e_country = pd.read_csv(
snakemake.input.ch_industrial_production, index_col=0
).dropna()
e_country = e_country.rename(index=ch_mapping).groupby(level=0).sum()
e_country = e_country[str(min(2019, year))]
e_country *= tj_to_ktoe
else:
ct_eurostat = country.replace("GB", "UK")
# estimate physical output, energy consumption in the sector and country
fn = f"{eurostat_dir}/{country}-Energy-balance-sheets-April-2023-edition.xlsb"
fn = f"{eurostat_dir}/{ct_eurostat}-Energy-balance-sheets-April-2023-edition.xlsb"
df = pd.read_excel(
fn,
sheet_name=str(min(2021, year)),
sheet_name=str(min(2019, year)),
index_col=2,
header=0,
skiprows=4,
)
e_country = df.loc[eb_sectors.keys(), "Total"].rename(eb_sectors)
fn = f"{jrc_dir}/JRC-IDEES-2015_Industry_EU28.xlsx"
fn = f"{jrc_dir}/EU27/JRC-IDEES-2021_Industry_EU27.xlsx"
with mute_print():
df = pd.read_excel(fn, sheet_name="Ind_Summary", index_col=0, header=0).squeeze(
"columns"
)
assert df.index[48] == "by sector"
assert df.index[49] == "by sector"
year_i = df.columns.get_loc(year)
e_eu28 = df.iloc[49:76, year_i]
e_eu28.index = e_eu28.index.str.lstrip()
e_eu27 = df.iloc[50:77, year_i]
e_eu27.index = e_eu27.index.str.lstrip()
e_ratio = e_country / e_eu28
e_ratio = e_country / e_eu27
return pd.Series({k: e_ratio[v] for k, v in sub2sect.items()})
@ -230,7 +231,7 @@ def get_energy_ratio(country, eurostat_dir, jrc_dir, year):
def industry_production_per_country(country, year, eurostat_dir, jrc_dir):
def get_sector_data(sector, country):
jrc_country = jrc_names.get(country, country)
fn = f"{jrc_dir}/JRC-IDEES-2015_Industry_{jrc_country}.xlsx"
fn = f"{jrc_dir}/{jrc_country}/JRC-IDEES-2021_Industry_{jrc_country}.xlsx"
sheet = sub_sheet_name_dict[sector]
with mute_print():
df = pd.read_excel(fn, sheet_name=sheet, index_col=0, header=0).squeeze(
@ -245,10 +246,10 @@ def industry_production_per_country(country, year, eurostat_dir, jrc_dir):
return df
ct = "EU28" if country not in eu28 else country
ct = "EU27" if country not in eu27 else country
demand = pd.concat([get_sector_data(s, ct) for s in sect2sub])
if country not in eu28:
if country not in eu27:
demand *= get_energy_ratio(country, eurostat_dir, jrc_dir, year)
demand.name = country
@ -287,6 +288,7 @@ def separate_basic_chemicals(demand, year):
"""
Separate basic chemicals into ammonia, chlorine, methanol and HVC.
"""
# ammonia data from 2018-2022
ammonia = pd.read_csv(snakemake.input.ammonia_production, index_col=0)
there = ammonia.index.intersection(demand.index)
@ -296,7 +298,12 @@ def separate_basic_chemicals(demand, year):
demand["Ammonia"] = 0.0
demand.loc[there, "Ammonia"] = ammonia.loc[there, str(year)]
year_to_use = min(max(year, 2018), 2022)
if year_to_use != year:
logger.info(
f"Year {year} outside data range. Using data from {year_to_use} for ammonia production."
)
demand.loc[there, "Ammonia"] = ammonia.loc[there, str(year_to_use)]
demand["Basic chemicals"] -= demand["Ammonia"]

File diff suppressed because it is too large Load Diff

View File

@ -56,8 +56,8 @@ For each bus, the following industry subcategories
- Aluminium - primary production
- Aluminium - secondary production
- Other non-ferrous metals
- Transport Equipment
- Machinery Equipment
- Transport equipment
- Machinery equipment
- Textiles and leather
- Wood and wood products
- Other Industrial Sectors

View File

@ -26,7 +26,7 @@ logger = logging.getLogger(__name__)
def build_nodal_transport_data(fn, pop_layout, year):
# get numbers of car and fuel efficiency per country
transport_data = pd.read_csv(fn, index_col=[0, 1])
transport_data = transport_data.xs(min(2015, year), level="year")
transport_data = transport_data.xs(year, level="year")
# break number of cars down to nodal level based on population density
nodal_transport_data = transport_data.loc[pop_layout.ct].fillna(0.0)

View File

@ -0,0 +1,46 @@
# -*- coding: utf-8 -*-
# SPDX-FileCopyrightText: : 2024- The PyPSA-Eur Authors
#
# SPDX-License-Identifier: MIT
"""
Retrieve and extract JRC IDEES 2021 data.
"""
import logging
import os
import zipfile
from pathlib import Path
from _helpers import configure_logging, progress_retrieve, set_scenario_config
logger = logging.getLogger(__name__)
# Define the base URL
url_jrc = "https://jeodpp.jrc.ec.europa.eu/ftp/jrc-opendata/JRC-IDEES/JRC-IDEES-2021_v1/JRC-IDEES-2021.zip"
if __name__ == "__main__":
if "snakemake" not in globals():
from _helpers import mock_snakemake
snakemake = mock_snakemake("retrieve_jrc_idees")
rootpath = ".."
else:
rootpath = "."
configure_logging(snakemake)
set_scenario_config(snakemake)
disable_progress = snakemake.config["run"].get("disable_progressbar", False)
to_fn = snakemake.output[0]
to_fn_zp = to_fn + ".zip"
# download .zip file
logger.info(f"Downloading JRC IDEES from {url_jrc}.")
progress_retrieve(url_jrc, to_fn_zp, disable=disable_progress)
# extract
logger.info("Extracting JRC IDEES data.")
with zipfile.ZipFile(to_fn_zp, "r") as zip_ref:
zip_ref.extractall(to_fn)
logger.info(f"JRC IDEES data available in '{to_fn}'.")