diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 94a332b5..54f451bb 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,7 +5,7 @@ exclude: "^LICENSES" repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 + rev: v4.5.0 hooks: - id: check-merge-conflict - id: end-of-file-fixer @@ -45,13 +45,13 @@ repos: args: ["--in-place", "--make-summary-multi-line", "--pre-summary-newline"] - repo: https://github.com/keewis/blackdoc - rev: v0.3.8 + rev: v0.3.9 hooks: - id: blackdoc # Formatting with "black" coding style - repo: https://github.com/psf/black - rev: 23.9.1 + rev: 23.11.0 hooks: # Format Python files - id: black @@ -67,14 +67,14 @@ repos: # Do YAML formatting (before the linter checks it for misses) - repo: https://github.com/macisamuele/language-formatters-pre-commit-hooks - rev: v2.10.0 + rev: v2.11.0 hooks: - id: pretty-format-yaml args: [--autofix, --indent, "2", --preserve-quotes] # Format Snakemake rule / workflow files - repo: https://github.com/snakemake/snakefmt - rev: v0.8.4 + rev: v0.8.5 hooks: - id: snakefmt diff --git a/README.md b/README.md index 97dc4643..4a58d75c 100644 --- a/README.md +++ b/README.md @@ -103,6 +103,6 @@ We strongly welcome anyone interested in contributing to this project. If you ha # Licence The code in PyPSA-Eur is released as free software under the -[MIT License](https://opensource.org/licenses/MIT), see `LICENSE.txt`. +[MIT License](https://opensource.org/licenses/MIT), see [`doc/licenses.rst`](doc/licenses.rst). However, different licenses and terms of use may apply to the various input data. diff --git a/config/config.default.yaml b/config/config.default.yaml index 35f346a3..083abb6f 100644 --- a/config/config.default.yaml +++ b/config/config.default.yaml @@ -18,6 +18,8 @@ remote: ssh: "" path: "" +focus_weights: false + # docs in https://pypsa-eur.readthedocs.io/en/latest/configuration.html#run run: name: "" @@ -68,6 +70,7 @@ enable: retrieve_sector_databundle: true retrieve_cost_data: true build_cutout: false + retrieve_irena: false retrieve_cutout: true build_natura_raster: false retrieve_natura_raster: true @@ -451,10 +454,12 @@ sector: coal_cc: false dac: true co2_vent: false + central_heat_vent: false allam_cycle: false hydrogen_fuel_cell: true hydrogen_turbine: false SMR: true + SMR_cc: true regional_co2_sequestration_potential: enable: false attribute: 'conservative estimate Mt' @@ -801,6 +806,7 @@ plotting: Coal: '#545454' coal: '#545454' Coal marginal: '#545454' + coal for industry: '#343434' solid: '#545454' Lignite: '#826837' lignite: '#826837' @@ -877,6 +883,7 @@ plotting: services rural heat: '#ff9c9c' central heat: '#cc1f1f' urban central heat: '#d15959' + urban central heat vent: '#a74747' decentral heat: '#750606' residential urban decentral heat: '#a33c3c' services urban decentral heat: '#cc1f1f' diff --git a/config/test/config.myopic.yaml b/config/test/config.myopic.yaml index 0bb85ec6..d566c6cb 100644 --- a/config/test/config.myopic.yaml +++ b/config/test/config.myopic.yaml @@ -30,6 +30,9 @@ snapshots: start: "2013-03-01" end: "2013-03-08" +sector: + central_heat_vent: true + electricity: co2limit: 100.e+6 diff --git a/config/test/config.perfect.yaml b/config/test/config.perfect.yaml index c99f4122..49886b26 100644 --- a/config/test/config.perfect.yaml +++ b/config/test/config.perfect.yaml @@ -44,6 +44,7 @@ electricity: sector: min_part_load_fischer_tropsch: 0 min_part_load_methanolisation: 0 + atlite: default_cutout: be-03-2013-era5 cutouts: diff --git a/data/existing_infrastructure/offwind_capacity_IRENA.csv b/data/existing_infrastructure/offwind_capacity_IRENA.csv index 5400e4fb..d2a3f0f1 100644 --- a/data/existing_infrastructure/offwind_capacity_IRENA.csv +++ b/data/existing_infrastructure/offwind_capacity_IRENA.csv @@ -1,34 +1,34 @@ -Country/area,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018 -Albania,,,,,,,,,,,,,,,,,,, -Austria,,,,,,,,,,,,,,,,,,, -Belgium,,,,,,,,,,31.5,196.5,196.5,381,707.7,707.7,712,712.2,877.2,1185.9 -Bosnia Herzg,,,,,,,,,,,,,,,,,,, -Bulgaria,,,,,,,,,,,,,,,,,,, -Croatia,,,,,,,,,,,,,,,,,,, -Czechia,,,,,,,,,,,,,,,,,,, -Denmark,50,50,214,423.4,423.4,423.4,423.4,423.4,423.4,660.9,867.9,871.5,921.9,1271.1,1271.1,1271.1,1271.1,1263.8,1700.8 -Estonia,,,,,,,,,,,,,,,,,,, -Finland,,,,,,,,,24,24,26.3,26.3,26.3,26.3,26.3,32,32,72.7,72.7 -France,,,,,,,,,,,,,,,,,,2,2 -Germany,,,,,,,,,,35,80,188,268,508,994,3283,4132,5406,6396 -Greece,,,,,,,,,,,,,,,,,,, -Hungary,,,,,,,,,,,,,,,,,,, -Ireland,,,,,25.2,25.2,25.2,25.2,25.2,25.2,25.2,25.2,25.2,25.2,25.2,25.2,25.2,25.2,25.2 -Italy,,,,,,,,,,,,,,,,,,, -Latvia,,,,,,,,,,,,,,,,,,, -Lithuania,,,,,,,,,,,,,,,,,,, -Luxembourg,,,,,,,,,,,,,,,,,,, -Montenegro,,,,,,,,,,,,,,,,,,, -Netherlands,,,,,,,108,108,228,228,228,228,228,228,228,357,957,957,957 -North Macedonia,,,,,,,,,,,,,,,,,,, -Norway,,,,,,,,,,2.3,2.3,2.3,2.3,2.3,2.3,2.3,2.3,2.3,2.3 -Poland,,,,,,,,,,,,,,,,,,, -Portugal,,,,,,,,,,,,1.9,2,2,2,2,,, -Romania,,,,,,,,,,,,,,,,,,, -Serbia,,,,,,,,,,,,,,,,,,, -Slovakia,,,,,,,,,,,,,,,,,,, -Slovenia,,,,,,,,,,,,,,,,,,, -Spain,,,,,,,,,,,,,,5,5,5,5,5,5 -Sweden,13,22,22,22,22,22,22,131,133,163,163,163,163,212,213,213,203,203,203 -Switzerland,,,,,,,,,,,,,,,,,,, -UK,3.8,3.8,3.8,63.8,123.8,213.8,303.8,393.8,596.2,951.2,1341.5,1838.3,2995.5,3696,4501.3,5093.4,5293.4,6987.9,8216.5 +Country/area,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020,2021,2022 +Albania,,,,,,,,,,,,,,,,,,,,,,, +Austria,,,,,,,,,,,,,,,,,,,,,,, +Belgium,,,,,,,,,,31.5,196.5,196.5,381.0,707.7,707.7,712.0,712.2,877.2,1185.9,1555.5,2261.8,2261.8,2261.8 +Bosnia Herzg,,,,,,,,,,,,,,,,,,,,,,, +Bulgaria,,,,,,,,,,,,,,,,,,,,,,, +Croatia,,,,,,,,,,,,,,,,,,,,,,, +Czechia,,,,,,,,,,,,,,,,,,,,,,, +Denmark,49.95,49.95,213.95,423.35,423.35,423.35,423.35,423.35,423.35,660.85,867.85,871.45,921.85,1271.05,1271.05,1271.05,1271.05,1263.8,1700.8,1700.8,1700.8,2305.6,2305.6 +Estonia,,,,,,,,,,,,,,,,,,,,,,, +Finland,,,,,,,,,24.0,24.0,26.3,26.3,26.3,26.3,26.3,32.0,32.0,72.7,72.7,73.0,73.0,73.0,73.0 +France,,,,,,,,,,,,,,,,,,2.0,2.0,2.0,2.0,2.0,482.0 +Germany,,,,,,,,,,35.0,80.0,188.0,268.0,508.0,994.0,3283.0,4132.0,5406.0,6393.0,7555.0,7787.0,7787.0,8129.0 +Greece,,,,,,,,,,,,,,,,,,,,,,, +Hungary,,,,,,,,,,,,,,,,,,,,,,, +Ireland,,,,,25.2,25.2,25.2,25.2,25.2,25.2,25.2,25.2,25.2,25.2,25.2,25.2,25.2,25.2,25.2,25.2,25.2,25.2,25.2 +Italy,,,,,,,,,,,,,,,,,,,,,,,30.0 +Latvia,,,,,,,,,,,,,,,,,,,,,,, +Lithuania,,,,,,,,,,,,,,,,,,,,,,, +Luxembourg,,,,,,,,,,,,,,,,,,,,,,, +Montenegro,,,,,,,,,,,,,,,,,,,,,,, +Netherlands,,,,,,,108.0,108.0,228.0,228.0,228.0,228.0,228.0,228.0,228.0,357.0,957.0,957.0,957.0,957.0,2459.5,2459.5,2571.0 +North Macedonia,,,,,,,,,,,,,,,,,,,,,,, +Norway,,,,,,,,,,2.3,2.3,2.3,2.3,2.3,2.3,2.3,2.3,2.3,2.3,2.3,2.3,6.3,66.3 +Poland,,,,,,,,,,,,,,,,,,,,,,, +Portugal,,,,,,,,,,,,1.86,2.0,2.0,2.0,2.0,,,,,25.0,25.0,25.0 +Romania,,,,,,,,,,,,,,,,,,,,,,, +Serbia,,,,,,,,,,,,,,,,,,,,,,, +Slovakia,,,,,,,,,,,,,,,,,,,,,,, +Slovenia,,,,,,,,,,,,,,,,,,,,,,, +Spain,,,,,,,,,,,,,,5.0,5.0,5.0,5.0,5.0,5.0,5.0,5.0,5.0,5.0 +Sweden,13.0,22.0,22.0,22.0,22.0,22.0,22.0,131.0,133.0,163.0,163.0,163.0,163.0,212.0,213.0,213.0,203.0,203.0,203.0,203.0,203.0,193.0,193.0 +Switzerland,,,,,,,,,,,,,,,,,,,,,,, +UK,4.0,4.0,4.0,64.0,124.0,214.0,304.0,394.0,596.2,951.0,1341.0,1838.0,2995.0,3696.0,4501.0,5093.0,5293.0,6988.0,8181.0,9888.0,10383.0,11255.0,13928.0 diff --git a/data/existing_infrastructure/onwind_capacity_IRENA.csv b/data/existing_infrastructure/onwind_capacity_IRENA.csv index ca7bb5ec..cd5ac19c 100644 --- a/data/existing_infrastructure/onwind_capacity_IRENA.csv +++ b/data/existing_infrastructure/onwind_capacity_IRENA.csv @@ -1,34 +1,34 @@ -Country/area,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018 -Albania,,,,,,,,,,,,,,,,,,, -Austria,50,67,109,322,581,825.2,968.3,991.2,992,1001,1015.8,1106,1337.2,1674.5,2110.3,2488.7,2730,2886.7,3132.7 -Belgium,14,26,31,67,96,167,212,276,324,576.5,715.5,872.5,989,1072.3,1236.3,1464,1657.8,1919.3,2074.8 -Bosnia Herzg,,,,,,,,,,,,0.3,0.3,0.3,0.3,0.3,0.3,0.3,50.9 -Bulgaria,,,,,1,8,27,30,114,333,488,541,677,683,699,699,699,698.4,698.9 -Croatia,,,,,6,6,17,17,17,70,79,130,180,254,339,418,483,576.1,586.3 -Czechia,2,,6.4,10.6,16.5,22,43.5,113.8,150,193,213,213,258,262,278,281,282,308.2,316.2 -Denmark,2340.1,2447.2,2680.6,2696.6,2700.4,2704.5,2712.3,2700.9,2739.5,2821.2,2934,3080.5,3240.1,3547.9,3615.4,3805.9,3974.5,4225.8,4419.8 -Estonia,,,1,3,7,31,31,50,77,104,108,180,266,248,275,300,310,311.8,310 -Finland,38,39,43,52,82,82,86,110,119,123,170.7,172.7,230.7,420.7,600.7,973,1533,1971.3,1968.3 -France,38,66,138,218,358,690,1412,2223,3403,4582,5912,6758,7607.5,8156,9201.4,10298.2,11566.6,13497.4,14898.1 -Germany,6095,8754,12001,14381,16419,18248,20474,22116,22794,25697,26823,28524,30711,32969,37620,41297,45303,50174,52447 -Greece,226,270,287,371,470,491,749,846,1022,1171,1298,1640,1753,1809,1978,2091,2370,2624,2877.5 -Hungary,,1,1,3,3,17,33,61,134,203,293,331,325,329,329,329,329,329,329 -Ireland,116.5,122.9,134.8,210.3,311.2,468.1,651.3,715.3,917.1,1226.1,1365.2,1559.4,1679.2,1983,2258.1,2426,2760.8,3292.8,3650.9 -Italy,363,664,780,874,1127,1635,1902,2702,3525,4879,5794,6918,8102,8542,8683,9137,9384,9736.6,10230.2 -Latvia,2,2,22,26,26,26,26,26,28,29,30,36,59,65.9,68.9,68.2,69.9,77.1,78.2 -Lithuania,,,,,1,1,31,47,54,98,133,202,275,279,288,436,509,518,533 -Luxembourg,14,13.9,13.9,20.5,34.9,34.9,34.9,34.9,42.9,42.9,43.7,44.5,58.3,58.3,58.3,63.8,119.7,119.7,122.9 -Montenegro,,,,,,,,,,,,,,,,,,72,118 -Netherlands,447,486,672,905,1075,1224,1453,1641,1921,1994,2009,2088,2205,2485,2637,3034,3300,3245,3436 -North Macedonia,,,,,,,,,,,,,,,37,37,37,37,37 -Norway,13,13,97,97,152,265,284,348,395,420.7,422.7,509.7,702.7,815.7,856.7,864.7,880.7,1204.7,1708 -Poland,4,19,32,35,40,121,172,306,526,709,1108,1800,2564,3429,3836,4886,5747,5759.4,5766.1 -Portugal,83,125,190,268,553,1064,1681,2201,2857,3326,3796,4254.4,4409.6,4607.9,4854.6,4934.8,5124.1,5124.1,5172.4 -Romania,,,,,,1,1,3,5,15,389,988,1822,2773,3244,3130,3025,3029.8,3032.3 -Serbia,,,,,,,,,,,,,0.5,0.5,0.5,10.4,17,25,25 -Slovakia,,,,3,3,5,5,5,5,3,3,3,3,5,3,3,3,4,3 -Slovenia,,,,,,,,,,,,,,4,4,5,5,5,5.2 -Spain,2206,3397,4891,5945,8317,9918,11722,14820,16555,19176,20693,21529,22789,22953,22920,22938,22985,23119.5,23400.1 -Sweden,196,273,335,395,453,500,563,692,956,1312,1854,2601,3443,3982,4875,5606,6232,6408,7097 -Switzerland,3,5,5,5,9,12,12,12,14,18,42,46,49,60,60,60,75,75,75 -UK,408.2,489.2,530.2,678.2,809.2,1351.2,1651.2,2083.2,2849.8,3470.8,4079.8,4758,6035,7586.3,8572.7,9212.2,10832.3,12596.9,13553.9 +Country/area,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020,2021,2022 +Albania,,,,,,,,,,,,,,,,,,,,,,, +Austria,50.0,67.0,109.0,322.0,581.0,825.22,968.27,991.16,991.97,1000.99,1015.83,1105.97,1337.15,1674.54,2110.28,2488.73,2730.0,2886.7,3132.71,3224.12,3225.98,3407.81,3735.81 +Belgium,14.0,26.0,31.0,67.0,96.0,167.0,212.0,276.0,324.0,576.5,715.5,872.5,985.9,1061.3,1225.0,1469.3,1621.6,1902.2,2119.0,2308.0,2410.9,2686.6,2989.6 +Bosnia Herzg,,,,,,,,,,,,0.3,0.3,0.3,0.3,0.3,0.3,0.3,51.0,87.0,87.0,135.0,135.0 +Bulgaria,,,,,1.0,8.0,27.0,30.0,114.0,333.0,488.0,541.0,677.0,683.0,699.0,699.0,699.0,698.39,698.92,703.12,702.8,704.38,704.38 +Croatia,,,,,6.0,6.0,17.0,17.0,17.0,70.0,79.0,130.0,180.0,254.0,339.0,418.0,483.0,576.1,586.3,646.3,801.3,986.9,1042.9 +Czechia,2.0,,6.4,10.6,16.5,22.0,43.5,113.8,150.0,193.0,213.0,213.0,258.0,262.0,278.0,281.0,282.0,308.21,316.2,339.41,339.42,339.41,339.41 +Denmark,2340.07,2447.2,2680.58,2696.57,2700.36,2704.49,2712.35,2700.86,2739.52,2821.24,2933.98,3080.53,3240.09,3547.87,3615.35,3805.92,3974.09,4225.15,4421.86,4409.74,4566.23,4715.24,4782.24 +Estonia,,,1.0,3.0,7.0,31.0,31.0,50.0,77.0,104.0,108.0,180.0,266.0,248.0,275.0,300.0,310.0,311.8,310.0,316.0,317.0,315.0,315.0 +Finland,38.0,39.0,43.0,52.0,82.0,82.0,86.0,110.0,119.0,123.0,170.7,172.7,230.7,420.7,600.7,973.0,1533.0,1971.3,1968.3,2211.0,2513.0,3184.0,5541.0 +France,38.0,66.0,138.0,218.0,358.0,690.0,1412.0,2223.0,3403.0,4582.0,5912.0,6758.02,7607.5,8155.96,9201.42,10298.18,11566.56,13497.35,14898.14,16424.85,17512.0,18737.98,20637.98 +Germany,6095.0,8754.0,12001.0,14381.0,16419.0,18248.0,20474.0,22116.0,22794.0,25697.0,26823.0,28524.0,30711.0,32969.0,37620.0,41297.0,45303.0,50174.0,52328.0,53187.0,54414.0,56046.0,58165.0 +Greece,226.0,270.0,287.0,371.0,470.0,491.0,749.0,846.0,1022.0,1171.0,1298.0,1640.0,1753.0,1809.0,1978.0,2091.0,2370.0,2624.0,2877.5,3589.0,4119.25,4649.13,4879.13 +Hungary,,1.0,1.0,3.0,3.0,17.0,33.0,61.0,134.0,203.0,293.0,331.0,325.0,329.0,329.0,329.0,329.0,329.0,329.0,323.0,323.0,324.0,324.0 +Ireland,116.5,122.9,134.8,210.3,311.2,468.1,651.3,715.3,917.1,1226.1,1365.2,1559.4,1679.15,1898.1,2258.05,2425.95,2776.45,3293.95,3648.65,4101.25,4281.5,4313.84,4593.84 +Italy,363.0,664.0,780.0,874.0,1127.0,1635.0,1902.0,2702.0,3525.0,4879.0,5794.0,6918.0,8102.0,8542.0,8683.0,9137.0,9384.0,9736.58,10230.25,10679.46,10870.62,11253.73,11749.73 +Latvia,2.0,2.0,22.0,26.0,26.0,26.0,26.0,26.0,28.0,29.0,30.0,36.0,59.0,65.89,68.92,68.17,69.91,77.11,78.17,78.07,78.07,77.13,136.13 +Lithuania,,,,,1.0,1.0,31.0,47.0,54.0,98.0,133.0,202.0,275.0,279.0,288.0,436.0,509.0,518.0,533.0,534.0,540.0,671.0,814.0 +Luxembourg,14.0,13.9,13.9,20.5,34.9,34.9,34.9,34.9,42.92,42.93,43.73,44.53,58.33,58.33,58.34,63.79,119.69,119.69,122.89,135.79,152.74,136.44,165.44 +Montenegro,,,,,,,,,,,,,,,,,,72.0,72.0,118.0,118.0,118.0,118.0 +Netherlands,447.0,486.0,672.0,905.0,1075.0,1224.0,1453.0,1641.0,1921.0,1994.0,2009.0,2088.0,2205.0,2485.0,2637.0,3033.84,3300.12,3245.0,3436.11,3527.16,4188.38,5309.87,6176.0 +North Macedonia,,,,,,,,,,,,,,,37.0,37.0,37.0,37.0,37.0,37.0,37.0,37.0,37.0 +Norway,13.0,13.0,97.0,97.0,152.0,265.0,284.0,348.0,395.0,420.7,422.7,509.7,702.7,815.7,856.7,864.7,880.7,1204.7,1707.7,2911.7,4027.7,5042.7,5067.7 +Poland,4.0,19.0,32.0,35.0,40.0,121.0,172.0,306.0,526.0,709.0,1108.0,1800.0,2564.0,3429.0,3836.0,4886.0,5747.0,5759.36,5766.08,5837.76,6298.25,6967.34,7987.34 +Portugal,83.0,125.0,190.0,268.0,553.0,1064.0,1681.0,2201.0,2857.0,3326.0,3796.0,4254.35,4409.55,4607.95,4854.56,4934.84,5124.1,5124.1,5172.36,5222.75,5097.26,5402.33,5430.33 +Romania,,,,,,1.0,1.0,3.0,5.0,15.0,389.0,988.0,1822.0,2773.0,3244.0,3130.0,3025.0,3029.8,3032.26,3037.52,3012.53,3014.96,3014.96 +Serbia,,,,,,,,,,,,,0.5,0.5,0.5,10.4,17.0,25.0,227.0,398.0,398.0,398.0,398.0 +Slovakia,,,,3.0,3.0,5.0,5.0,5.0,5.0,3.0,3.0,3.0,3.0,5.0,3.0,3.0,3.0,4.0,3.0,4.0,4.0,4.0,4.0 +Slovenia,,,,,,,,,,,,,2.0,2.0,3.0,3.0,3.0,3.3,3.3,3.3,3.3,3.33,3.33 +Spain,2206.0,3397.0,4891.0,5945.0,8317.0,9918.0,11722.0,14820.0,16555.0,19176.0,20693.0,21529.0,22789.0,22953.0,22920.0,22938.0,22985.0,23119.48,23400.06,25585.08,26814.19,27902.65,29302.84 +Sweden,196.0,273.0,335.0,395.0,453.0,500.0,563.0,692.0,956.0,1312.0,1854.0,2601.0,3443.0,3982.0,4875.0,5606.0,6232.0,6408.0,7097.0,8478.0,9773.0,11923.0,14364.0 +Switzerland,3.0,5.0,5.0,5.0,9.0,12.0,12.0,12.0,14.0,18.0,42.0,46.0,49.0,60.0,60.0,60.0,75.0,75.0,75.0,75.0,87.0,87.0,87.0 +UK,431.0,490.0,531.0,678.0,809.0,1351.0,1651.0,2083.0,2849.8,3468.0,4080.0,4758.0,6035.0,7586.0,8573.0,9212.0,10833.0,12597.0,13425.0,13999.0,14075.0,14492.0,14832.0 diff --git a/data/existing_infrastructure/solar_capacity_IRENA.csv b/data/existing_infrastructure/solar_capacity_IRENA.csv index ac84c2d1..01683f8d 100644 --- a/data/existing_infrastructure/solar_capacity_IRENA.csv +++ b/data/existing_infrastructure/solar_capacity_IRENA.csv @@ -1,34 +1,34 @@ -Country/area,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018 -Albania,,0.1,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.3,0.4,0.6,0.7,0.8,0.9,1.1,1,1,1 -Austria,5,7,9,23,27,21,22.4,24.2,30.1,48.9,88.8,174.1,337.5,626,785.2,937.1,1096,1269,1437.6 -Belgium,,,1,1,1,2,2,20,62,386,1007,1979,2647,2902,3015.2,3131.7,3327,3616.2,3986.5 -Bosnia Herzg,,,,0.1,0.2,0.3,0.3,0.3,0.3,0.3,0.3,0.3,0.3,1.3,7.2,8.2,14.1,16,18.2 -Bulgaria,,,,,,,,0,0.1,2,25,154,1013,1020,1026,1029,1028,1035.6,1032.7 -Croatia,,,,,,,,,,0.3,0.3,0.3,4,19,33,47.8,55.8,60,67.7 -Czechia,0.1,0.1,0.2,0.3,0.4,0.6,0.8,4,39.5,464.6,1727,1913,2022,2063.5,2067.4,2074.9,2067.9,2069.5,2075.1 -Denmark,1,1,2,2,2,3,3,3,3,5,7,17,402,571,607,782.1,851,906.4,998 -Estonia,,,,,,,,,,0.1,0.1,0.2,0.4,1.5,3.3,6.5,10,15,31.9 -Finland,2,3,3,3,4,4,5,5,6,6,7,7,8,9,11,17,39,82,140 -France,7,7,8,9,11,13,15,26,80,277,1044,3003.6,4358.8,5277.3,6034.4,7137.5,7702.1,8610.4,9617 -Germany,114,195,260,435,1105,2056,2899,4170,6120,10564,18004,25914,34075,36708,37898,39222,40677,42291,45179 -Greece,,1,1,1,1,1,5,9,12,46,202,612,1536,2579,2596,2604,2604,2605.5,2651.6 -Hungary,,,,,,,,0.4,1,1,2,4,12,35,89,172,235,344,726 -Ireland,,,,,,,,,,0.6,0.7,0.8,0.9,1,1.6,2.4,5.9,15.7,24.2 -Italy,19,20,22,26,31,34,45,110,483,1264,3592,13131,16785,18185,18594,18901,19283,19682.3,20107.6 -Latvia,,,,,,,,,,,,,0.2,0.2,0.2,0.2,0.7,0.7,2 -Lithuania,,,,,,,,,0.1,0.1,0.1,0.3,7,68,69,69,70,73.8,82 -Luxembourg,,0.2,1.6,14.2,23.6,23.6,23.7,23.9,24.6,26.4,29.5,40.7,74.7,95,109.9,116.3,121.9,128.1,130.6 -Montenegro,,,,,,,0,0.2,0.4,0.4,0.6,0.8,0.9,1.1,2.1,2.7,3.1,3.4,3.4 -Netherlands,13,21,26,46,50,51,53,54,59,69,90,149,369,746,1048,1515,2049,2903,4522 -North Macedonia,,,,,,,,,,,0,2,4,7,15,17,16.7,16.7,20.6 -Norway,6,6,6,7,7,7,8,8,8.3,8.7,9.1,9.5,10,11,13,15,26.7,44.9,68.4 -Poland,,,,,,,,,,,,1.1,1.3,2.4,27.2,107.8,187.2,287.1,562 -Portugal,1,1,1,2,2,2,3,24,59,115,134,172,238,296,415,447,512.8,579.2,667.4 -Romania,,,,,,,,,0.1,0.1,0.1,1,41,761,1293,1326,1372,1374.1,1385.8 -Serbia,,,,,,0.1,0.2,0.4,0.9,1.2,1.3,1.5,3.1,4.7,6,9,11,10,10 -Slovakia,,,,,,,,,,,19,496,513,533,533,533,533,528,472 -Slovenia,,,0,0,0,0,0.2,0.6,1,4,12,57,142,187,223,238,233,246.8,221.3 -Spain,10,13,17,22,33,52,130,494,3384,3423,3873,4283,4569,4690,4697,4704,4713,4723,4763.5 -Sweden,3,3,3,4,4,4,5,6,8,9,11,12,24,43,60,104,153,402,492 -Switzerland,16,18,20,22,24,28,30,37,49,79,125,223,437,756,1061,1394,1664,1906,2171 -UK,2,3,4,6,8,11,14,18,23,27,95,1000,1753,2937,5528,9601.2,11930.5,12781.8,13118.3 +Country/area,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020,2021,2022 +Albania,,0.1,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.3,0.4,0.56,0.68,0.76,0.87,1.05,1.0,1.0,1.0,14.0,21.0,23.0,28.6 +Austria,5.0,7.0,9.0,23.0,27.0,18.49,19.61,21.42,27.0,45.56,85.27,169.88,333.09,620.78,779.76,931.56,1089.53,1262.01,1447.94,1694.4,2034.74,2773.91,3538.91 +Belgium,,,1.0,1.0,1.0,2.0,2.0,20.0,62.0,386.0,1006.6,1978.6,2646.6,2901.6,3015.0,3131.6,3328.8,3620.6,4000.0,4636.6,5572.8,6012.4,6898.4 +Bosnia Herzg,,,,0.1,0.2,0.3,0.3,0.3,0.3,0.3,0.3,0.3,0.35,1.34,7.17,8.17,14.12,16.0,18.15,22.35,34.89,56.51,107.47 +Bulgaria,,,,,,,,0.03,0.1,2.0,25.0,154.0,921.99,1038.54,1028.92,1027.89,1029.89,1030.7,1033.06,1044.39,1100.21,1274.71,1948.36 +Croatia,,,,,,,,,,0.3,0.3,0.3,4.0,19.0,33.0,47.8,55.8,60.0,67.7,84.8,108.5,138.3,182.3 +Czechia,0.1,0.1,0.2,0.3,0.4,0.59,0.84,3.96,39.5,464.6,1727.0,1913.0,2022.0,2063.5,2067.4,2074.9,2067.9,2075.44,2081.05,2110.67,2171.96,2246.09,2627.09 +Denmark,1.0,1.0,2.0,2.0,2.0,3.0,3.0,3.0,3.0,5.0,7.0,17.0,402.0,571.0,607.0,782.11,850.95,906.35,998.0,1080.0,1304.29,1704.04,3122.04 +Estonia,,,,,,,,,,0.1,0.1,0.2,0.38,1.5,3.34,6.5,10.0,15.0,31.9,120.6,207.67,394.77,534.77 +Finland,2.0,3.0,3.0,3.0,4.0,4.0,5.0,5.0,6.0,6.0,7.0,7.0,8.0,9.0,11.0,17.0,39.0,82.0,140.0,222.0,318.0,425.0,590.6 +France,7.0,7.0,8.0,9.0,11.0,13.0,15.0,26.0,80.0,277.0,1044.0,3003.57,4358.75,5277.29,6034.42,7137.52,7702.08,8610.44,9638.88,10738.39,11812.2,14436.97,17036.97 +Germany,114.0,195.0,260.0,435.0,1105.0,2056.0,2899.0,4170.0,6120.0,10564.0,18004.0,25914.0,34075.0,36708.0,37898.0,39222.0,40677.0,42291.0,45156.0,48912.0,53669.0,59371.0,66662.0 +Greece,,1.0,1.0,1.0,1.0,1.0,5.0,9.0,12.0,46.0,202.0,612.0,1536.0,2579.0,2596.0,2604.0,2604.0,2605.53,2651.57,2833.79,3287.72,4277.42,5557.42 +Hungary,,,,,,,,0.4,1.0,1.0,2.0,4.0,12.0,35.0,89.0,172.0,235.0,344.0,728.0,1400.0,2131.0,2968.0,2988.0 +Ireland,,,,,,,,,,,,,,,,,,,,,,, +Italy,19.0,20.0,22.0,26.0,31.0,34.0,45.0,110.0,483.0,1264.0,3592.0,13131.0,16785.0,18185.0,18594.0,18901.0,19283.0,19682.29,20107.59,20865.28,21650.04,22594.26,25076.56 +Latvia,,,,,,,,,,,,,,,,,0.69,0.69,1.96,3.3,5.1,7.16,56.16 +Lithuania,,,,,,,,,0.1,0.1,0.1,0.3,7.0,68.0,69.0,69.0,70.0,70.08,72.0,73.0,80.0,84.0,397.0 +Luxembourg,,0.16,1.59,14.17,23.56,23.58,23.7,23.93,24.56,26.36,29.45,40.67,74.65,95.02,109.93,116.27,121.9,128.1,130.62,159.74,186.64,277.16,319.16 +Montenegro,,,,,,,,,,,,,,,,,,,,,2.57,2.57,22.2 +Netherlands,13.0,21.0,26.0,46.0,50.0,51.0,53.0,54.0,59.0,69.0,90.0,149.0,287.0,650.0,1007.0,1526.26,2135.02,2910.89,4608.0,7226.0,11108.43,14910.69,18848.69 +North Macedonia,,,,,,,,,,,,2.0,4.0,7.0,15.0,17.0,16.7,16.7,16.7,16.71,84.93,84.93,84.93 +Norway,6.0,6.0,6.0,7.0,7.0,7.0,8.0,8.0,8.3,8.7,9.1,9.5,10.0,11.0,13.0,15.0,26.7,44.9,53.11,102.53,141.53,186.53,302.53 +Poland,,,,,,,,,,,,1.11,1.3,2.39,27.15,107.78,187.25,287.09,561.98,1539.26,3954.96,7415.52,11166.52 +Portugal,1.0,1.0,1.0,2.0,2.0,2.0,3.0,24.0,59.0,115.0,134.0,169.6,235.6,293.6,412.6,441.75,493.05,539.42,617.85,832.74,1010.07,1474.78,2364.78 +Romania,,,,,,,,,0.1,0.1,0.1,1.0,41.0,761.0,1293.0,1326.0,1372.0,1374.13,1385.82,1397.71,1382.54,1393.92,1413.92 +Serbia,,,,,,0.1,0.2,0.4,0.9,1.2,1.3,1.5,3.1,4.7,6.0,9.0,11.0,10.0,11.0,11.0,11.5,11.94,11.94 +Slovakia,,,,,,,,,,,19.0,496.0,513.0,533.0,533.0,533.0,533.0,528.0,472.0,590.0,535.0,537.0,537.0 +Slovenia,1.0,1.0,,,,0.05,0.19,0.59,1.0,4.0,12.0,57.0,142.0,187.0,223.0,238.0,233.0,246.8,246.8,277.88,369.78,461.16,632.16 +Spain,1.0,3.0,6.0,10.0,19.0,37.0,113.0,476.0,3365.0,3403.0,3851.0,4260.0,4545.0,4665.0,4672.0,4677.0,4687.0,4696.0,4730.7,8772.02,10100.42,13678.4,18176.73 +Sweden,3.0,3.0,3.0,4.0,4.0,4.0,5.0,6.0,8.0,9.0,11.0,12.0,24.0,43.0,60.0,104.0,153.0,231.0,411.0,698.0,1090.0,1587.0,2587.0 +Switzerland,16.0,18.0,20.0,22.0,24.0,28.0,30.0,37.0,49.0,79.0,125.0,223.0,437.0,756.0,1061.0,1394.0,1664.0,1906.0,2173.0,2498.0,2973.0,3655.0,4339.92 +UK,2.0,3.0,4.0,6.0,8.0,11.0,14.0,18.0,23.0,27.0,95.0,1000.0,1753.0,2937.0,5528.0,9601.0,11914.0,12760.0,13059.0,13345.0,13579.0,13965.0,14660.0 diff --git a/doc/configtables/enable.csv b/doc/configtables/enable.csv index e1349fef..8dd476cb 100644 --- a/doc/configtables/enable.csv +++ b/doc/configtables/enable.csv @@ -5,6 +5,7 @@ retrieve_databundle,bool,"{true, false}","Switch to retrieve databundle from zen retrieve_sector_databundle,bool,"{true, false}","Switch to retrieve sector databundle from zenodo via the rule :mod:`retrieve_sector_databundle` or whether to keep a custom databundle located in the corresponding folder." retrieve_cost_data,bool,"{true, false}","Switch to retrieve technology cost data from `technology-data repository `_." build_cutout,bool,"{true, false}","Switch to enable the building of cutouts via the rule :mod:`build_cutout`." +retrieve_irena,bool,"{true, false}",Switch to enable the retrieval of ``existing_capacities`` from IRENASTAT with :mod:`retrieve_irena`. retrieve_cutout,bool,"{true, false}","Switch to enable the retrieval of cutouts from zenodo with :mod:`retrieve_cutout`." build_natura_raster,bool,"{true, false}","Switch to enable the creation of the raster ``natura.tiff`` via the rule :mod:`build_natura_raster`." retrieve_natura_raster,bool,"{true, false}","Switch to enable the retrieval of ``natura.tiff`` from zenodo with :mod:`retrieve_natura_raster`." diff --git a/doc/configtables/sector.csv b/doc/configtables/sector.csv index d610c862..856ea074 100644 --- a/doc/configtables/sector.csv +++ b/doc/configtables/sector.csv @@ -79,6 +79,7 @@ allam_cycle,--,"{true, false}",Add option to include `Allam cycle gas power plan hydrogen_fuel_cell,--,"{true, false}",Add option to include hydrogen fuel cell for re-electrification. Assuming OCGT technology costs hydrogen_turbine,--,"{true, false}",Add option to include hydrogen turbine for re-electrification. Assuming OCGT technology costs SMR,--,"{true, false}",Add option for transforming natural gas into hydrogen and CO2 using Steam Methane Reforming (SMR) +SMR CC,--,"{true, false}",Add option for transforming natural gas into hydrogen and CO2 using Steam Methane Reforming (SMR) and Carbon Capture (CC) regional_co2 _sequestration_potential,,, -- enable,--,"{true, false}",Add option for regionally-resolved geological carbon dioxide sequestration potentials based on `CO2StoP `_. -- attribute,--,string,Name of the attribute for the sequestration potential diff --git a/doc/configtables/toplevel.csv b/doc/configtables/toplevel.csv index 67954389..a27623bd 100644 --- a/doc/configtables/toplevel.csv +++ b/doc/configtables/toplevel.csv @@ -10,3 +10,4 @@ private,,, remote,,, -- ssh,--,,Optionally specify the SSH of a remote cluster to be synchronized. -- path,--,,Optionally specify the file path within the remote cluster to be synchronized. +focus_weights,,,Optionally specify the focus weights for the clustering of countries. For instance: `DE: 0.8` will distribute 80% of all nodes to Germany and 20% to the rest of the countries. diff --git a/doc/index.rst b/doc/index.rst index 1552729c..d30dd8b9 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -185,7 +185,7 @@ For sector-coupling studies: :: pages = "1--25" year = "2023", eprint = "2207.05816", - doi = "10.1016/j.joule.2022.04.016", + doi = "10.1016/j.joule.2023.06.016", } For sector-coupling studies with pathway optimisation: :: diff --git a/doc/release_notes.rst b/doc/release_notes.rst index 505c747e..c111e9bc 100644 --- a/doc/release_notes.rst +++ b/doc/release_notes.rst @@ -29,10 +29,17 @@ Upcoming Release * Rule ``purge`` now initiates a dialog to confirm if purge is desired. +* Rule ``retrieve_irena`` get updated values for renewables capacities. + +* Split configuration to enable SMR and SMR CC. + +* The ``mock_snakemake`` function can now be used with a Snakefile from a different directory using the new ``root_dir`` argument. + **Bugs and Compatibility** * A bug preventing custom powerplants specified in ``data/custom_powerplants.csv`` was fixed. (https://github.com/PyPSA/pypsa-eur/pull/732) +* Fix nodal fraction in ``add_existing_year`` when using distributed generators PyPSA-Eur 0.8.1 (27th July 2023) diff --git a/doc/retrieve.rst b/doc/retrieve.rst index ad353cad..83baa9bc 100644 --- a/doc/retrieve.rst +++ b/doc/retrieve.rst @@ -91,7 +91,7 @@ None. **Outputs** -- ``data/load_raw.csv`` +- ``resources/load_raw.csv`` Rule ``retrieve_cost_data`` @@ -118,6 +118,11 @@ This rule downloads techno-economic assumptions from the `technology-data reposi - ``resources/costs.csv`` +Rule ``retrieve_irena`` +================================ + +.. automodule:: retrieve_irena + Rule ``retrieve_ship_raster`` ================================ diff --git a/doc/tutorial.rst b/doc/tutorial.rst index 40c1907c..e58ad123 100644 --- a/doc/tutorial.rst +++ b/doc/tutorial.rst @@ -25,7 +25,7 @@ full model, which allows the user to explore most of its functionalities on a local machine. The tutorial will cover examples on how to configure and customise the PyPSA-Eur model and run the ``snakemake`` workflow step by step from network creation to the solved network. The configuration for the tutorial -is located at ``test/config.electricity.yaml``. It includes parts deviating from +is located at ``config/test/config.electricity.yaml``. It includes parts deviating from the default config file ``config/config.default.yaml``. To run the tutorial with this configuration, execute @@ -96,7 +96,7 @@ open-source solver GLPK. :start-at: solver: :end-before: plotting: -Note, that ``test/config.electricity.yaml`` only includes changes relative to +Note, that ``config/test/config.electricity.yaml`` only includes changes relative to the default configuration. There are many more configuration options, which are documented at :ref:`config`. diff --git a/envs/environment.yaml b/envs/environment.yaml index 3476aad8..51e01338 100644 --- a/envs/environment.yaml +++ b/envs/environment.yaml @@ -11,6 +11,8 @@ dependencies: - pip - atlite>=0.2.9 +- pypsa==0.25.2 +- linopy - dask - jupyter - nbconvert @@ -36,7 +38,7 @@ dependencies: - scipy - shapely>=2.0 - pyomo -- matplotlib<3.6 +- matplotlib - proj - fiona - country_converter @@ -57,5 +59,4 @@ dependencies: - pip: - - git+https://github.com/fneum/tsam.git@performance - - pypsa>=0.25.2 + - tsam>=2.3.1 diff --git a/rules/build_electricity.smk b/rules/build_electricity.smk index be7425aa..cbbaedab 100644 --- a/rules/build_electricity.smk +++ b/rules/build_electricity.smk @@ -24,7 +24,7 @@ rule build_electricity_demand: countries=config["countries"], load=config["load"], input: - ancient("data/load_raw.csv"), + ancient(RESOURCES + "load_raw.csv"), output: RESOURCES + "load.csv", log: @@ -278,7 +278,7 @@ rule build_renewable_profiles: ), ship_density=lambda w: ( RESOURCES + "shipdensity_raster.tif" - if "ship_threshold" in config["renewable"][w.technology].keys() + if config["renewable"][w.technology].get("ship_threshold", False) else [] ), country_shapes=RESOURCES + "country_shapes.geojson", diff --git a/rules/build_sector.smk b/rules/build_sector.smk index 21a588be..5a9e8646 100644 --- a/rules/build_sector.smk +++ b/rules/build_sector.smk @@ -609,7 +609,7 @@ if config["sector"]["retrofitting"]["retro_endogen"]: countries=config["countries"], input: building_stock="data/retro/data_building_stock.csv", - data_tabula="data/retro/tabula-calculator-calcsetbuilding.csv", + data_tabula="data/bundle-sector/retro/tabula-calculator-calcsetbuilding.csv", air_temperature=RESOURCES + "temp_air_total_elec_s{simpl}_{clusters}.nc", u_values_PL="data/retro/u_values_poland.csv", tax_w="data/retro/electricity_taxes_eu.csv", diff --git a/rules/retrieve.smk b/rules/retrieve.smk index e3d50378..75cf8062 100644 --- a/rules/retrieve.smk +++ b/rules/retrieve.smk @@ -42,6 +42,24 @@ if config["enable"]["retrieve"] and config["enable"].get("retrieve_databundle", "../scripts/retrieve_databundle.py" +if config["enable"].get("retrieve_irena"): + + rule retrieve_irena: + output: + offwind="data/existing_infrastructure/offwind_capacity_IRENA.csv", + onwind="data/existing_infrastructure/onwind_capacity_IRENA.csv", + solar="data/existing_infrastructure/solar_capacity_IRENA.csv", + log: + LOGS + "retrieve_irena.log", + resources: + mem_mb=1000, + retries: 2 + conda: + "../envs/environment.yaml" + script: + "../scripts/retrieve_irena.py" + + if config["enable"]["retrieve"] and config["enable"].get("retrieve_cutout", True): rule retrieve_cutout: @@ -180,7 +198,7 @@ if config["enable"]["retrieve"]: static=True, ), output: - "data/load_raw.csv", + RESOURCES + "load_raw.csv", log: LOGS + "retrieve_electricity_demand.log", resources: diff --git a/scripts/_helpers.py b/scripts/_helpers.py index 9362cfbb..398f3a30 100644 --- a/scripts/_helpers.py +++ b/scripts/_helpers.py @@ -191,7 +191,7 @@ def progress_retrieve(url, file, disable=False): urllib.request.urlretrieve(url, file, reporthook=update_to) -def mock_snakemake(rulename, configfiles=[], **wildcards): +def mock_snakemake(rulename, root_dir=None, configfiles=[], **wildcards): """ This function is expected to be executed from the 'scripts'-directory of ' the snakemake project. It returns a snakemake.script.Snakemake object, @@ -203,6 +203,8 @@ def mock_snakemake(rulename, configfiles=[], **wildcards): ---------- rulename: str name of the rule for which the snakemake object should be generated + root_dir: str/path-like + path to the root directory of the snakemake project configfiles: list, str list of configfiles to be used to update the config **wildcards: @@ -217,7 +219,10 @@ def mock_snakemake(rulename, configfiles=[], **wildcards): from snakemake.script import Snakemake script_dir = Path(__file__).parent.resolve() - root_dir = script_dir.parent + if root_dir is None: + root_dir = script_dir.parent + else: + root_dir = Path(root_dir).resolve() user_in_script_dir = Path.cwd().resolve() == script_dir if user_in_script_dir: diff --git a/scripts/add_brownfield.py b/scripts/add_brownfield.py index 679060b3..74102580 100644 --- a/scripts/add_brownfield.py +++ b/scripts/add_brownfield.py @@ -120,7 +120,6 @@ def add_brownfield(n, n_p, year): n.links.loc[new_pipes, "p_nom_min"] = 0.0 -# %% if __name__ == "__main__": if "snakemake" not in globals(): from _helpers import mock_snakemake diff --git a/scripts/add_existing_baseyear.py b/scripts/add_existing_baseyear.py index 7cdca5af..1842166b 100644 --- a/scripts/add_existing_baseyear.py +++ b/scripts/add_existing_baseyear.py @@ -88,7 +88,9 @@ def add_existing_renewables(df_agg): ] cfs = n.generators_t.p_max_pu[gens].mean() cfs_key = cfs / cfs.sum() - nodal_fraction.loc[n.generators.loc[gens, "bus"]] = cfs_key.values + nodal_fraction.loc[n.generators.loc[gens, "bus"]] = cfs_key.groupby( + n.generators.loc[gens, "bus"] + ).sum() nodal_df = df.loc[n.buses.loc[elec_buses, "country"]] nodal_df.index = elec_buses @@ -630,7 +632,6 @@ def add_heating_capacities_installed_before_baseyear( n.mremove("Link", links_i) -# %% if __name__ == "__main__": if "snakemake" not in globals(): from _helpers import mock_snakemake diff --git a/scripts/build_electricity_demand.py b/scripts/build_electricity_demand.py index 46480fce..7edc8871 100755 --- a/scripts/build_electricity_demand.py +++ b/scripts/build_electricity_demand.py @@ -31,7 +31,7 @@ Relevant Settings Inputs ------ -- ``data/load_raw.csv``: +- ``resources/load_raw.csv``: Outputs ------- diff --git a/scripts/build_industrial_distribution_key.py b/scripts/build_industrial_distribution_key.py index 888a1a96..b86d47c2 100644 --- a/scripts/build_industrial_distribution_key.py +++ b/scripts/build_industrial_distribution_key.py @@ -96,23 +96,6 @@ def prepare_hotmaps_database(regions): gdf.rename(columns={"index_right": "bus"}, inplace=True) gdf["country"] = gdf.bus.str[:2] - # the .sjoin can lead to duplicates if a geom is in two regions - if gdf.index.duplicated().any(): - import pycountry - - # get all duplicated entries - duplicated_i = gdf.index[gdf.index.duplicated()] - # convert from raw data country name to iso-2-code - s = df.loc[duplicated_i, "Country"].apply( - lambda x: pycountry.countries.lookup(x).alpha_2 - ) - # Get a boolean mask where gdf's country column matches s's values for the same index - mask = gdf["country"] == gdf.index.map(s) - # Filter gdf using the mask - gdf_filtered = gdf[mask] - # concat not duplicated and filtered gdf - gdf = pd.concat([gdf.drop(duplicated_i), gdf_filtered]).sort_index() - # the .sjoin can lead to duplicates if a geom is in two overlapping regions if gdf.index.duplicated().any(): # get all duplicated entries @@ -164,7 +147,6 @@ def build_nodal_distribution_key(hotmaps, regions, countries): return keys -# %% if __name__ == "__main__": if "snakemake" not in globals(): from _helpers import mock_snakemake diff --git a/scripts/build_renewable_profiles.py b/scripts/build_renewable_profiles.py index ae347dda..3a1c525e 100644 --- a/scripts/build_renewable_profiles.py +++ b/scripts/build_renewable_profiles.py @@ -251,7 +251,7 @@ if __name__ == "__main__": snakemake.input.corine, codes=codes, buffer=buffer, crs=3035 ) - if "ship_threshold" in params: + if params.get("ship_threshold"): shipping_threshold = ( params["ship_threshold"] * 8760 * 6 ) # approximation because 6 years of data which is hourly collected diff --git a/scripts/build_retro_cost.py b/scripts/build_retro_cost.py index 5373f873..f5313c21 100644 --- a/scripts/build_retro_cost.py +++ b/scripts/build_retro_cost.py @@ -102,7 +102,7 @@ solar_energy_transmittance = ( ) # solar global radiation [kWh/(m^2a)] solar_global_radiation = pd.Series( - [246, 401, 246, 148], + [271, 392, 271, 160], index=["east", "south", "west", "north"], name="solar_global_radiation [kWh/(m^2a)]", ) @@ -164,6 +164,12 @@ def prepare_building_stock_data(): }, inplace=True, ) + building_data["feature"].replace( + { + "Construction features (U-value)": "Construction features (U-values)", + }, + inplace=True, + ) building_data.country_code = building_data.country_code.str.upper() building_data["subsector"].replace( @@ -198,12 +204,14 @@ def prepare_building_stock_data(): } ) + building_data["country_code"] = building_data["country"].map(country_iso_dic) + # heated floor area ---------------------------------------------------------- area = building_data[ (building_data.type == "Heated area [Mm²]") & (building_data.subsector != "Total") ] - area_tot = area.groupby(["country", "sector"]).sum() + area_tot = area[["country", "sector", "value"]].groupby(["country", "sector"]).sum() area = pd.concat( [ area, @@ -223,7 +231,7 @@ def prepare_building_stock_data(): usecols=[0, 1, 2, 3], encoding="ISO-8859-1", ) - area_tot = area_tot.append(area_missing.unstack(level=-1).dropna().stack()) + area_tot = pd.concat([area_tot, area_missing.unstack(level=-1).dropna().stack()]) area_tot = area_tot.loc[~area_tot.index.duplicated(keep="last")] # for still missing countries calculate floor area by population size @@ -246,7 +254,7 @@ def prepare_building_stock_data(): averaged_data.index = index averaged_data["estimated"] = 1 if ct not in area_tot.index.levels[0]: - area_tot = area_tot.append(averaged_data, sort=True) + area_tot = pd.concat([area_tot, averaged_data], sort=True) else: area_tot.loc[averaged_data.index] = averaged_data @@ -272,7 +280,7 @@ def prepare_building_stock_data(): ][x["bage"]].iloc[0], axis=1, ) - data_PL_final = data_PL_final.append(data_PL) + data_PL_final = pd.concat([data_PL_final, data_PL]) u_values = pd.concat([u_values, data_PL_final]).reset_index(drop=True) @@ -943,7 +951,8 @@ def sample_dE_costs_area( .rename(index=rename_sectors, level=2) .reset_index() ) - .rename(columns={"country": "country_code"}) + # if uncommented, leads to the second `country_code` column + # .rename(columns={"country": "country_code"}) .set_index(["country_code", "subsector", "bage"]) ) @@ -956,13 +965,14 @@ def sample_dE_costs_area( ) # map missing countries - for ct in countries.difference(cost_dE.index.levels[0]): + for ct in set(countries).difference(cost_dE.index.levels[0]): averaged_data = ( cost_dE.reindex(index=map_for_missings[ct], level=0) - .mean(level=1) + .groupby(level=1) + .mean() .set_index(pd.MultiIndex.from_product([[ct], cost_dE.index.levels[1]])) ) - cost_dE = cost_dE.append(averaged_data) + cost_dE = pd.concat([cost_dE, averaged_data]) # weights costs after construction index if construction_index: @@ -979,24 +989,23 @@ def sample_dE_costs_area( # drop not considered countries cost_dE = cost_dE.reindex(countries, level=0) # get share of residential and service floor area - sec_w = area_tot.value / area_tot.value.groupby(level=0).sum() + sec_w = area_tot.div(area_tot.groupby(level=0).transform("sum")) # get the total cost-energy-savings weight by sector area tot = ( - cost_dE.mul(sec_w, axis=0) - .groupby(level="country_code") + # sec_w has columns "estimated" and "value" + cost_dE.mul(sec_w.value, axis=0) + # for some reasons names of the levels were lost somewhere + # .groupby(level="country_code") + .groupby(level=0) .sum() - .set_index( - pd.MultiIndex.from_product( - [cost_dE.index.unique(level="country_code"), ["tot"]] - ) - ) + .set_index(pd.MultiIndex.from_product([cost_dE.index.unique(level=0), ["tot"]])) ) - cost_dE = cost_dE.append(tot).unstack().stack() + cost_dE = pd.concat([cost_dE, tot]).unstack().stack() - summed_area = pd.DataFrame(area_tot.groupby("country").sum()).set_index( - pd.MultiIndex.from_product([area_tot.index.unique(level="country"), ["tot"]]) + summed_area = pd.DataFrame(area_tot.groupby(level=0).sum()).set_index( + pd.MultiIndex.from_product([area_tot.index.unique(level=0), ["tot"]]) ) - area_tot = area_tot.append(summed_area).unstack().stack() + area_tot = pd.concat([area_tot, summed_area]).unstack().stack() cost_per_saving = cost_dE["cost"] / ( 1 - cost_dE["dE"] diff --git a/scripts/cluster_network.py b/scripts/cluster_network.py index 9dbe887a..df72e633 100644 --- a/scripts/cluster_network.py +++ b/scripts/cluster_network.py @@ -237,7 +237,7 @@ def distribute_clusters(n, n_clusters, focus_weights=None, solver_name="cbc"): n_clusters >= len(N) and n_clusters <= N.sum() ), f"Number of clusters must be {len(N)} <= n_clusters <= {N.sum()} for this selection of countries." - if focus_weights is not None: + if isinstance(focus_weights, dict): total_focus = sum(list(focus_weights.values())) assert ( @@ -271,7 +271,7 @@ def distribute_clusters(n, n_clusters, focus_weights=None, solver_name="cbc"): ) opt = po.SolverFactory(solver_name) - if not opt.has_capability("quadratic_objective"): + if solver_name == "appsi_highs" or not opt.has_capability("quadratic_objective"): logger.warning( f"The configured solver `{solver_name}` does not support quadratic objectives. Falling back to `ipopt`." ) @@ -466,6 +466,7 @@ if __name__ == "__main__": params = snakemake.params solver_name = snakemake.config["solving"]["solver"]["name"] + solver_name = "appsi_highs" if solver_name == "highs" else solver_name n = pypsa.Network(snakemake.input.network) diff --git a/scripts/make_summary_perfect.py b/scripts/make_summary_perfect.py index 8bb225ae..c387c6cf 100644 --- a/scripts/make_summary_perfect.py +++ b/scripts/make_summary_perfect.py @@ -28,6 +28,16 @@ idx = pd.IndexSlice opt_name = {"Store": "e", "Line": "s", "Transformer": "s"} +def reindex_columns(df, cols): + investments = cols.levels[3] + if len(cols.names) != len(df.columns.levels): + df = pd.concat([df] * len(investments), axis=1) + df.columns = cols + df = df.reindex(cols, axis=1) + + return df + + def calculate_costs(n, label, costs): investments = n.investment_periods cols = pd.MultiIndex.from_product( @@ -39,7 +49,8 @@ def calculate_costs(n, label, costs): ], names=costs.columns.names[:3] + ["year"], ) - costs = costs.reindex(cols, axis=1) + + costs = reindex_columns(costs, cols) for c in n.iterate_components( n.branch_components | n.controllable_one_port_components ^ {"Load"} @@ -176,7 +187,7 @@ def calculate_capacities(n, label, capacities): ], names=capacities.columns.names[:3] + ["year"], ) - capacities = capacities.reindex(cols, axis=1) + capacities = reindex_columns(capacities, cols) for c in n.iterate_components( n.branch_components | n.controllable_one_port_components ^ {"Load"} @@ -229,7 +240,7 @@ def calculate_energy(n, label, energy): ], names=energy.columns.names[:3] + ["year"], ) - energy = energy.reindex(cols, axis=1) + energy = reindex_columns(energy, cols) for c in n.iterate_components(n.one_port_components | n.branch_components): if c.name in n.one_port_components: @@ -336,7 +347,7 @@ def calculate_supply_energy(n, label, supply_energy): ], names=supply_energy.columns.names[:3] + ["year"], ) - supply_energy = supply_energy.reindex(cols, axis=1) + supply_energy = reindex_columns(supply_energy, cols) bus_carriers = n.buses.carrier.unique() @@ -604,7 +615,7 @@ def calculate_price_statistics(n, label, price_statistics): price_statistics.at["mean", label] = n.buses_t.marginal_price[buses].mean().mean() price_statistics.at["standard_deviation", label] = ( - n.buses_t.marginal_price[buses].droplevel(0).unstack().std() + n.buses_t.marginal_price[buses].std().std() ) return price_statistics @@ -706,7 +717,6 @@ def to_csv(df): df[key].to_csv(snakemake.output[key]) -# %% if __name__ == "__main__": # Detect running outside of snakemake and mock snakemake for testing if "snakemake" not in globals(): diff --git a/scripts/plot_network.py b/scripts/plot_network.py index c2ba72c7..f44bb6de 100644 --- a/scripts/plot_network.py +++ b/scripts/plot_network.py @@ -1060,7 +1060,6 @@ def plot_map_perfect( ) -# %% if __name__ == "__main__": if "snakemake" not in globals(): from _helpers import mock_snakemake diff --git a/scripts/plot_statistics.py b/scripts/plot_statistics.py index 1e75203f..b2728931 100644 --- a/scripts/plot_statistics.py +++ b/scripts/plot_statistics.py @@ -33,8 +33,6 @@ if __name__ == "__main__": lambda s: s != "", "lightgrey" ) - # %% - def rename_index(ds): specific = ds.index.map(lambda x: f"{x[1]}\n({x[0]})") generic = ds.index.get_level_values("carrier") diff --git a/scripts/plot_summary.py b/scripts/plot_summary.py index a40563f6..5804e785 100644 --- a/scripts/plot_summary.py +++ b/scripts/plot_summary.py @@ -452,7 +452,6 @@ def plot_carbon_budget_distribution(input_eurostat): sns.set() sns.set_style("ticks") - plt.style.use("seaborn-ticks") plt.rcParams["xtick.direction"] = "in" plt.rcParams["ytick.direction"] = "in" plt.rcParams["xtick.labelsize"] = 20 @@ -564,7 +563,6 @@ def plot_carbon_budget_distribution(input_eurostat): plt.savefig(path, bbox_inches="tight") -# %% if __name__ == "__main__": if "snakemake" not in globals(): from _helpers import mock_snakemake diff --git a/scripts/prepare_network.py b/scripts/prepare_network.py index a5a00a3c..90d6ed2e 100755 --- a/scripts/prepare_network.py +++ b/scripts/prepare_network.py @@ -274,7 +274,6 @@ def set_line_nom_max( n.links.p_nom_max.clip(upper=p_nom_max_set, inplace=True) -# %% if __name__ == "__main__": if "snakemake" not in globals(): from _helpers import mock_snakemake diff --git a/scripts/prepare_perfect_foresight.py b/scripts/prepare_perfect_foresight.py index 73b4d0e1..00f23fab 100644 --- a/scripts/prepare_perfect_foresight.py +++ b/scripts/prepare_perfect_foresight.py @@ -493,7 +493,6 @@ def set_temporal_aggregation_SEG(n, opts, solver_name): return n -# %% if __name__ == "__main__": if "snakemake" not in globals(): from _helpers import mock_snakemake diff --git a/scripts/prepare_sector_network.py b/scripts/prepare_sector_network.py index 30e46031..8a4f98ce 100644 --- a/scripts/prepare_sector_network.py +++ b/scripts/prepare_sector_network.py @@ -1392,7 +1392,7 @@ def add_storage_and_grids(n, costs): lifetime=costs.at["coal", "lifetime"], ) - if options["SMR"]: + if options["SMR_cc"]: n.madd( "Link", spatial.nodes, @@ -1410,6 +1410,7 @@ def add_storage_and_grids(n, costs): lifetime=costs.at["SMR CC", "lifetime"], ) + if options["SMR"]: n.madd( "Link", nodes + " SMR", @@ -1555,14 +1556,7 @@ def add_land_transport(n, costs): ) if ice_share > 0: - if "oil" not in n.buses.carrier.unique(): - n.madd( - "Bus", - spatial.oil.nodes, - location=spatial.oil.locations, - carrier="oil", - unit="MWh_LHV", - ) + add_carrier_buses(n, "oil") ice_efficiency = options["transport_internal_combustion_efficiency"] @@ -1699,6 +1693,18 @@ def add_heat(n, costs): unit="MWh_th", ) + if name == "urban central" and options.get("central_heat_vent"): + n.madd( + "Generator", + nodes[name] + f" {name} heat vent", + location=nodes[name], + carrier=name + " heat vent", + p_nom_extendable=True, + p_max_pu=0, + p_min_pu=-1, + unit="MWh_th", + ) + ## Add heat load for sector in sectors: @@ -1953,7 +1959,7 @@ def add_heat(n, costs): # demand 'dE' [per unit of original heat demand] for each country and # different retrofitting strengths [additional insulation thickness in m] retro_data = pd.read_csv( - snakemake.input.retro_cost_energy, + snakemake.input.retro_cost, index_col=[0, 1], skipinitialspace=True, header=[0, 1], @@ -1997,7 +2003,11 @@ def add_heat(n, costs): space_heat_demand = demand * w_space[sec][node] # normed time profile of space heat demand 'space_pu' (values between 0-1), # p_max_pu/p_min_pu of retrofitting generators - space_pu = (space_heat_demand / space_heat_demand.max()).to_frame(name=node) + space_pu = ( + (space_heat_demand / space_heat_demand.max()) + .to_frame(name=node) + .fillna(0) + ) # minimum heat demand 'dE' after retrofitting in units of original heat demand (values between 0-1) dE = retro_data.loc[(ct, sec), ("dE")] @@ -2009,6 +2019,9 @@ def add_heat(n, costs): * floor_area_node / ((1 - dE) * space_heat_demand.max()) ) + if space_heat_demand.max() == 0: + capital_cost = capital_cost.apply(lambda b: 0 if b == np.inf else b) + # number of possible retrofitting measures 'strengths' (set in list at config.yaml 'l_strength') # given in additional insulation thickness [m] # for each measure, a retrofitting generator is added at the node diff --git a/scripts/retrieve_irena.py b/scripts/retrieve_irena.py new file mode 100644 index 00000000..7b123475 --- /dev/null +++ b/scripts/retrieve_irena.py @@ -0,0 +1,107 @@ +# -*- coding: utf-8 -*- +# Copyright 2023 Thomas Gilon (Climact) +# SPDX-FileCopyrightText: : 2017-2023 The PyPSA-Eur Authors +# +# SPDX-License-Identifier: MIT +""" +This rule downloads the existing capacities from `IRENASTAT `_ and extracts it in the ``data/existing_capacities`` sub-directory. + +**Relevant Settings** + +.. code:: yaml + + enable: + retrieve_irena: + +.. seealso:: + Documentation of the configuration file ``config.yaml`` at + :ref:`enable_cf` + +**Outputs** + +- ``data/existing_capacities``: existing capacities for offwind, onwind and solar + +""" + +import logging + +import pandas as pd +from _helpers import configure_logging + +logger = logging.getLogger(__name__) + +REGIONS = [ + "Albania", + "Austria", + "Belgium", + "Bosnia and Herzegovina", + "Bulgaria", + "Croatia", + "Czechia", + "Denmark", + "Estonia", + "Finland", + "France", + "Germany", + "Greece", + "Hungary", + "Ireland", + "Italy", + "Latvia", + "Lithuania", + "Luxembourg", + "Montenegro", + # "Netherlands", + "Netherlands (Kingdom of the)", + "North Macedonia", + "Norway", + "Poland", + "Portugal", + "Romania", + "Serbia", + "Slovakia", + "Slovenia", + "Spain", + "Sweden", + "Switzerland", + # "United Kingdom", + "United Kingdom of Great Britain and Northern Ireland (the)", +] + +REGIONS_DICT = { + "Bosnia and Herzegovina": "Bosnia Herzg", + "Netherlands (Kingdom of the)": "Netherlands", + "United Kingdom of Great Britain and Northern Ireland (the)": "UK", +} + +if __name__ == "__main__": + if "snakemake" not in globals(): + from _helpers import mock_snakemake + + snakemake = mock_snakemake("retrieve_irena") + configure_logging(snakemake) + + irena_raw = pd.read_csv( + "https://pxweb.irena.org:443/sq/99e64b12-fe03-4a7b-92ea-a22cc3713b92", + skiprows=2, + index_col=[0, 1, 3], + encoding="latin-1", + ) + + var = "Installed electricity capacity (MW)" + irena = irena_raw[var].unstack(level=2).reset_index(level=1).replace(0, "") + + irena = irena[irena.index.isin(REGIONS)] + irena.rename(index=REGIONS_DICT, inplace=True) + + df_offwind = irena[irena.Technology.str.contains("Offshore")].drop( + columns=["Technology"] + ) + df_onwind = irena[irena.Technology.str.contains("Onshore")].drop( + columns=["Technology"] + ) + df_pv = irena[irena.Technology.str.contains("Solar")].drop(columns=["Technology"]) + + df_offwind.to_csv(snakemake.output["offwind"]) + df_onwind.to_csv(snakemake.output["onwind"]) + df_pv.to_csv(snakemake.output["solar"]) diff --git a/scripts/solve_network.py b/scripts/solve_network.py index ed566eaf..ff2a2f23 100644 --- a/scripts/solve_network.py +++ b/scripts/solve_network.py @@ -350,7 +350,7 @@ def prepare_network( # http://journal.frontiersin.org/article/10.3389/fenrg.2015.00055/full # TODO: retrieve color and nice name from config n.add("Carrier", "load", color="#dd2e23", nice_name="Load shedding") - buses_i = n.buses.query("carrier == 'AC'").index + buses_i = n.buses.index if not np.isscalar(load_shedding): # TODO: do not scale via sign attribute (use Eur/MWh instead of Eur/kWh) load_shedding = 1e2 # Eur/kWh @@ -844,7 +844,6 @@ def solve_network(n, config, solving, opts="", **kwargs): return n -# %% if __name__ == "__main__": if "snakemake" not in globals(): from _helpers import mock_snakemake