diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 00000000..fd64e164 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,92 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + push: + branches: ["master"] + pull_request: + branches: ["master"] + schedule: + - cron: '23 18 * * 5' + +jobs: + analyze: + name: Analyze (${{ matrix.language }}) + # Runner size impacts CodeQL analysis time. To learn more, please see: + # - https://gh.io/recommended-hardware-resources-for-running-codeql + # - https://gh.io/supported-runners-and-hardware-resources + # - https://gh.io/using-larger-runners (GitHub.com only) + # Consider using larger runners or machines with greater resources for possible analysis time improvements. + runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} + permissions: + # required for all workflows + security-events: write + + # required to fetch internal or private CodeQL packs + packages: read + + # only required for workflows in private repositories + actions: read + contents: read + + strategy: + fail-fast: false + matrix: + include: + - language: python + build-mode: none + # CodeQL supports the following values keywords for 'language': 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift' + # Use `c-cpp` to analyze code written in C, C++ or both + # Use 'java-kotlin' to analyze code written in Java, Kotlin or both + # Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both + # To learn more about changing the languages that are analyzed or customizing the build mode for your analysis, + # see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning. + # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how + # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + build-mode: ${{ matrix.build-mode }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + + # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + # queries: security-extended,security-and-quality + + # If the analyze step fails for one of the languages you are analyzing with + # "We were unable to automatically build your code", modify the matrix above + # to set the build mode to "manual" for that language. Then modify this step + # to build your code. + # ℹ️ Command-line programs to run using the OS shell. + # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + - if: matrix.build-mode == 'manual' + shell: bash + run: | + echo 'If you are using a "manual" build mode for one or more of the' \ + 'languages you are analyzing, replace this with the commands to build' \ + 'your code, for example:' + echo ' make bootstrap' + echo ' make release' + exit 1 + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 + with: + category: "/language:${{matrix.language}}" diff --git a/CITATION.cff b/CITATION.cff index c921a773..2caf4226 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -6,7 +6,7 @@ cff-version: 1.1.0 message: "If you use this package, please cite it in the following way." title: "PyPSA-Eur: An open sector-coupled optimisation model of the European energy system" repository: https://github.com/pypsa/pypsa-eur -version: 0.11.0 +version: 0.12.0 license: MIT authors: - family-names: Brown @@ -36,3 +36,17 @@ authors: - family-names: Hörsch given-names: Jonas orcid: https://orcid.org/0000-0001-9438-767X + - family-names: Schledorn + given-names: Amos + - family-names: Schauß + given-names: Caspar + - family-names: van Greevenbroek + given-names: Koen + - family-names: Millinger + given-names: Markus + - family-names: Glaum + given-names: Philipp + - family-names: Xiong + given-names: Bobby + - family-names: Seibold + given-names: Toni diff --git a/config/config.default.yaml b/config/config.default.yaml index 22a5ac2b..63cdcabf 100644 --- a/config/config.default.yaml +++ b/config/config.default.yaml @@ -3,7 +3,7 @@ # SPDX-License-Identifier: CC0-1.0 # docs in https://pypsa-eur.readthedocs.io/en/latest/configuration.html#top-level-configuration -version: 0.11.0 +version: 0.12.0 tutorial: false logging: @@ -42,7 +42,7 @@ scenario: ll: - vopt clusters: - - 38 + - 39 - 128 - 256 opts: @@ -56,7 +56,7 @@ scenario: - 2050 # docs in https://pypsa-eur.readthedocs.io/en/latest/configuration.html#countries -countries: ['AL', 'AT', 'BA', 'BE', 'BG', 'CH', 'CZ', 'DE', 'DK', 'EE', 'ES', 'FI', 'FR', 'GB', 'GR', 'HR', 'HU', 'IE', 'IT', 'LT', 'LU', 'LV', 'ME', 'MK', 'NL', 'NO', 'PL', 'PT', 'RO', 'RS', 'SE', 'SI', 'SK'] +countries: ['AL', 'AT', 'BA', 'BE', 'BG', 'CH', 'CZ', 'DE', 'DK', 'EE', 'ES', 'FI', 'FR', 'GB', 'GR', 'HR', 'HU', 'IE', 'IT', 'LT', 'LU', 'LV', 'ME', 'MK', 'NL', 'NO', 'PL', 'PT', 'RO', 'RS', 'SE', 'SI', 'SK', 'XK'] # docs in https://pypsa-eur.readthedocs.io/en/latest/configuration.html#snapshots snapshots: @@ -155,7 +155,7 @@ renewable: resource: method: wind turbine: Vestas_V112_3MW - smooth: true + smooth: false add_cutout_windspeed: true capacity_per_sqkm: 3 # correction_factor: 0.93 @@ -175,7 +175,7 @@ renewable: resource: method: wind turbine: NREL_ReferenceTurbine_2020ATB_5.5MW - smooth: true + smooth: false add_cutout_windspeed: true capacity_per_sqkm: 2 correction_factor: 0.8855 @@ -192,7 +192,7 @@ renewable: resource: method: wind turbine: NREL_ReferenceTurbine_2020ATB_5.5MW - smooth: true + smooth: false add_cutout_windspeed: true capacity_per_sqkm: 2 correction_factor: 0.8855 @@ -209,7 +209,7 @@ renewable: resource: method: wind turbine: NREL_ReferenceTurbine_5MW_offshore - smooth: true + smooth: false add_cutout_windspeed: true # ScholzPhd Tab 4.3.1: 10MW/km^2 capacity_per_sqkm: 2 @@ -449,19 +449,23 @@ sector: 2045: 0.8 2050: 1.0 district_heating_loss: 0.15 - # check these numbers! - forward_temperature: - default: 90 - DK: 70 - SE: 70 - NO: 70 - FI: 70 - return_temperature: - default: 50 - DK: 40 - SE: 40 - NO: 40 - FI: 40 + supply_temperature_approximation: + max_forward_temperature: + FR: 110 + DK: 75 + DE: 109 + CZ: 130 + FI: 115 + PL: 130 + SE: 102 + IT: 90 + min_forward_temperature: + DE: 82 + return_temperature: + DE: 58 + lower_threshold_ambient_temperature: 0 + upper_threshold_ambient_temperature: 10 + rolling_window_ambient_temperature: 72 heat_source_cooling: 6 #K heat_pump_cop_approximation: refrigerant: ammonia @@ -583,7 +587,9 @@ sector: resistive_heaters: true oil_boilers: false biomass_boiler: true - overdimension_individual_heating: 1.1 #to cover demand peaks bigger than data + overdimension_heat_generators: + decentral: 1.1 #to cover demand peaks bigger than data + central: 1.0 chp: true micro_chp: false solar_thermal: true @@ -791,6 +797,7 @@ industry: MWh_MeOH_per_tMeOH: 5.528 hotmaps_locate_missing: false reference_year: 2019 + oil_refining_emissions: 0.013 # docs in https://pypsa-eur.readthedocs.io/en/latest/configuration.html#costs @@ -1071,6 +1078,8 @@ plotting: gas pipeline new: '#a87c62' # oil oil: '#c9c9c9' + oil primary: '#d2d2d2' + oil refining: '#e6e6e6' imported oil: '#a3a3a3' oil boiler: '#adadad' residential rural oil boiler: '#a9a9a9' @@ -1114,6 +1123,7 @@ plotting: services rural biomass boiler: '#c6cf98' services urban decentral biomass boiler: '#dde5b5' biomass to liquid: '#32CD32' + unsustainable solid biomass: '#998622' unsustainable bioliquids: '#32CD32' electrobiofuels: 'red' BioSNG: '#123456' diff --git a/config/examples/config.entsoe-all.yaml b/config/examples/config.entsoe-all.yaml index 4e7edd03..9f52094d 100644 --- a/config/examples/config.entsoe-all.yaml +++ b/config/examples/config.entsoe-all.yaml @@ -15,7 +15,7 @@ scenario: ll: - vopt clusters: - - 39 + - 41 - 128 - 256 opts: @@ -26,7 +26,7 @@ scenario: - '' # TODO add Turkey (TR) -countries: ['AL', 'AT', 'BA', 'BE', 'BG', 'CH', 'CZ', 'DE', 'DK', 'EE', 'ES', 'FI', 'FR', 'GB', 'GR', 'HR', 'HU', 'IE', 'IT', 'LT', 'LU', 'LV', 'ME', 'MD', 'MK', 'NL', 'NO', 'PL', 'PT', 'RO', 'RS', 'SE', 'SI', 'SK', 'UA'] +countries: ['AL', 'AT', 'BA', 'BE', 'BG', 'CH', 'CZ', 'DE', 'DK', 'EE', 'ES', 'FI', 'FR', 'GB', 'GR', 'HR', 'HU', 'IE', 'IT', 'LT', 'LU', 'LV', 'ME', 'MD', 'MK', 'NL', 'NO', 'PL', 'PT', 'RO', 'RS', 'SE', 'SI', 'SK', 'UA', 'XK'] electricity: custom_powerplants: true diff --git a/data/ammonia_plants.csv b/data/ammonia_plants.csv new file mode 100644 index 00000000..1317ceb9 --- /dev/null +++ b/data/ammonia_plants.csv @@ -0,0 +1,37 @@ +"Plant","Ammonia [kt/a]","Urea [kt/a]","AN [kt/a]","UAN [kt/a]","CAN [kt/a]","Nitrogen fertilisers [kt/a]","MAP [kt/a]","Country","Latitude","Longitude","Date","Source","Comment" +"Yara Sluiskil","1700","1300",,,,,,"Netherlands","51.27186","3.84896","13-01-2023","https://www.icis.com/explore/resources/news/2023/01/18/10846094/insight-poor-demand-high-costs-stifle-europe-industry-despite-falling-gas-prices/", +"OCI Geleen","550",,,,,,,"Netherlands","50.99738","5.78497","13-01-2023","https://www.icis.com/explore/resources/news/2023/01/18/10846094/insight-poor-demand-high-costs-stifle-europe-industry-despite-falling-gas-prices/", +"CF Fertilisers Billingham","590",,,,,,,"United Kingdom","53.28149","-2.79744","13-01-2023","https://www.icis.com/explore/resources/news/2023/01/18/10846094/insight-poor-demand-high-costs-stifle-europe-industry-despite-falling-gas-prices/; https://www.cfindustries.com/what-we-do/ammonia-productiont", +"Yara Tertre","420",,,,,,,"Belgium","50.47842","3.80285","13-01-2023","https://www.icis.com/explore/resources/news/2023/01/18/10846094/insight-poor-demand-high-costs-stifle-europe-industry-despite-falling-gas-prices/", +"BASF Antwerp","650",,,,,,,"Belgium","51.35583","4.27811","13-01-2023","https://www.icis.com/explore/resources/news/2023/01/18/10846094/insight-poor-demand-high-costs-stifle-europe-industry-despite-falling-gas-prices/", +"Yara Gonfreville","400",,,,,,,"France","49.47982","0.19587","13-01-2023","https://www.icis.com/explore/resources/news/2023/01/18/10846094/insight-poor-demand-high-costs-stifle-europe-industry-despite-falling-gas-prices/", +"Borealis Rouen",,,,,,,,"France","49.41916","1.02584","13-01-2023","https://www.icis.com/explore/resources/news/2023/01/18/10846094/insight-poor-demand-high-costs-stifle-europe-industry-despite-falling-gas-prices/", +"BASF Ludwigshafen","880",,,,,,,"Germany","49.51171","8.42009","13-01-2023","https://www.icis.com/explore/resources/news/2023/01/18/10846094/insight-poor-demand-high-costs-stifle-europe-industry-despite-falling-gas-prices/", +"SKW","1300",,,,,,,"Germany","51.87746","12.5858","13-01-2023","https://www.icis.com/explore/resources/news/2023/01/18/10846094/insight-poor-demand-high-costs-stifle-europe-industry-despite-falling-gas-prices/", +"Yara Brunsbuettel","750",,,,,,,"Germany","53.91152","9.20982","13-01-2023","https://www.icis.com/explore/resources/news/2023/01/18/10846094/insight-poor-demand-high-costs-stifle-europe-industry-despite-falling-gas-prices/", +"Yara Porsgrunn","500",,,,,,,"Norway","59.12444","9.61922","13-01-2023","https://www.icis.com/explore/resources/news/2023/01/18/10846094/insight-poor-demand-high-costs-stifle-europe-industry-despite-falling-gas-prices/", +"Fertiberia Puertollano","400","250",,"200",,,,"Spain","38.67276","-4.0608","13-01-2023","https://www.icis.com/explore/resources/news/2023/01/18/10846094/insight-poor-demand-high-costs-stifle-europe-industry-despite-falling-gas-prices/; https://www.icis.com/explore/resources/news/2021/10/25/10698264/spain-s-fertiberia-urea-ammonia-plants-in-palos-to-remain-shut-on-gas-prices/", +"Fertiberia Huelva","200","130",,,,,,"Spain","37.22572","-6.94742","13-01-2023","https://www.icis.com/explore/resources/news/2023/01/18/10846094/insight-poor-demand-high-costs-stifle-europe-industry-despite-falling-gas-prices/; https://www.icis.com/explore/resources/news/2021/10/25/10698264/spain-s-fertiberia-urea-ammonia-plants-in-palos-to-remain-shut-on-gas-prices/", +"Yara Ferrara","600","600",,,,,,"Italy","44.86206","11.57922","13-01-2023","https://www.icis.com/explore/resources/news/2023/01/18/10846094/insight-poor-demand-high-costs-stifle-europe-industry-despite-falling-gas-prices/", +"Petrokemija",,"500",,,,,,"Croatia","45.46977","16.78944","13-01-2023","https://www.icis.com/explore/resources/news/2023/01/18/10846094/insight-poor-demand-high-costs-stifle-europe-industry-despite-falling-gas-prices/", +"Neochim","450",,"710",,,,,"Bulgaria","42.20514","25.61547","13-01-2023","https://www.icis.com/explore/resources/news/2023/01/18/10846094/insight-poor-demand-high-costs-stifle-europe-industry-despite-falling-gas-prices/", +"Agopolychim",,,"400","800",,,"300","Bulgaria","43.20652","27.65983","13-01-2023","https://www.icis.com/explore/resources/news/2023/01/18/10846094/insight-poor-demand-high-costs-stifle-europe-industry-despite-falling-gas-prices/; https://ammoniaenergy.org/articles/agropolychim-investing-in-ammonia-distribution-from-bulgaria/","no own ammonia plant" +"Azomures","1600",,,,,,,"Romania","46.76187","24.42361","13-01-2023","https://www.icis.com/explore/resources/news/2023/01/18/10846094/insight-poor-demand-high-costs-stifle-europe-industry-despite-falling-gas-prices/","Total for ammonia, AN, NPK, UAN, Urea" +"Nitrogenmuvek","497",,,,"1300",,,"Hungary","47.16691","18.12844","13-01-2023","https://www.icis.com/explore/resources/news/2023/01/18/10846094/insight-poor-demand-high-costs-stifle-europe-industry-despite-falling-gas-prices/", +"DUSLO","530",,,,,,,"Slovakia","48.18705","17.9301","13-01-2023","https://www.icis.com/explore/resources/news/2023/01/18/10846094/insight-poor-demand-high-costs-stifle-europe-industry-despite-falling-gas-prices/", +"Grupa Azoty","524","375",,,,,,"Poland","51.45179","21.98174","13-01-2023","https://www.icis.com/explore/resources/news/2023/01/18/10846094/insight-poor-demand-high-costs-stifle-europe-industry-despite-falling-gas-prices/", +"Anwil",,,,,,"965",,"Poland","52.70438","18.96606","13-01-2023","https://www.icis.com/explore/resources/news/2023/01/18/10846094/insight-poor-demand-high-costs-stifle-europe-industry-despite-falling-gas-prices/", +"Achema","1100","785","651","1300","540",,,"Lithuania","55.081","24.32377","13-01-2023","https://www.icis.com/explore/resources/news/2023/01/18/10846094/insight-poor-demand-high-costs-stifle-europe-industry-despite-falling-gas-prices/", +"Lifosa",,,,,,"3241",,"Lithuania","55.27567","24.01652","13-01-2023","https://www.icis.com/explore/resources/news/2023/01/18/10846094/insight-poor-demand-high-costs-stifle-europe-industry-despite-falling-gas-prices/", +"Unknown (Linz)",,,,,,,,"Austria","48.28749","14.32369","15-08-2024",,"most likely location" +"Unknown (Kothla-Järve)",,,,,,,,"Estonia","59.39984","27.25401","15-08-2024",,"most likely location" +"Unknown (Oulu)",,,,,,,,"Finland","65.0033","25.43731","15-08-2024",,"most likely location" +"Unknown (Ptolemaida)",,,,,,,,"Greece","40.50701","21.71414","15-08-2024",,"most likely location" +"Unknown (Sabac)",,,,,,,,"Serbia","44.76298","19.68426","15-08-2024",,"most likely location" +"Unknown (Lugano)",,,,,,,,"Switzerland","46.02709","8.9641","15-08-2024",,"most likely location" +"Rivneazot","420",,"540","300","470 ",,,"Ukraine","50.70502","26.1630","28-08-2024","https://interfax.com/newsroom/top-stories/100959/; https://interfax.com/newsroom/top-stories/103386/; https://gmk.center/en/news/ostchem-plants-produced-520-6-thousand-tons-of-fertilizers-in-q1/; http://www.ostchem.com/en/o-kompanii/proizvodstvo/rovno", +"Stirol (Horlivka)","1470","940 ","693",,,,,"Ukraine","48.29697","38.10412","28-08-2024","http://ostchem.com/en/o-kompanii/proizvodstvo/stirol", +"Severodonetsk Azot","1020","390","550",,,,,"Ukraine","48.94185","38.47399","28-08-2024",, +"Odessa Port Plant ","1160","942",,,,,,"Ukraine","46.49460","30.73222","28-08-2024","https://www.spfu.gov.ua/userfiles/files/OPP_Teaser_Eng.pdf", +"Cherkazy Azot","963",,"970","500",,,,"Ukraine","49.38241","32.05719","28-08-2024","https://gmk.center/en/news/ostchem-plants-produced-520-6-thousand-tons-of-fertilizers-in-q1/https://gmk.center/en/news/ostchem-plants-produced-520-6-thousand-tons-of-fertilizers-in-q1/; http://ostchem.com/en/o-kompanii/proizvodstvo/azot", +"DneproAZOT","660",,,,,,,"Ukraine","48.49004","34.66667","28-08-2024","https://www.alfalaval.com/media/stories/fertilizers/increased-plant-capacity-and-reduced-maintenance-at-fertilizer-plant/", diff --git a/data/cement-plants-noneu.csv b/data/cement-plants-noneu.csv new file mode 100644 index 00000000..27c046c0 --- /dev/null +++ b/data/cement-plants-noneu.csv @@ -0,0 +1,26 @@ +"Company","Site","Cement [kt/a]","Country","Latitude","Longitude","Date","Source","Comment" +"Titan Cementarnica USJE AD","Skopje",910,"MK",41.96816,21.45604,"28-08-2024","https://www.usgs.gov/centers/national-minerals-information-center/international-minerals-statistics-and-information", +"Colacem Albania Sh.p.k","Balldre plant, Lezhe",500,"AL",41.83689,19.63339,"28-08-2024","https://www.usgs.gov/centers/national-minerals-information-center/international-minerals-statistics-and-information", +"Fushe Kruje Cement Factory, Sh.p.k.","Elbasan cement plant",300,"AL",41.12184,20.04347,"28-08-2024","https://www.usgs.gov/centers/national-minerals-information-center/international-minerals-statistics-and-information", +"Fushe Kruje Cement Factory, Sh.p.k.","Fushe Kruje plant",1330,"AL",40.46403,19.49948,"28-08-2024","https://www.usgs.gov/centers/national-minerals-information-center/international-minerals-statistics-and-information", +"Antea Cement Sh.A","Boka e Kuqe, Burizane",1500,"AL",41.54838,19.72574,"28-08-2024","https://www.usgs.gov/centers/national-minerals-information-center/international-minerals-statistics-and-information", +"Beocinska Fabrika Cementa","Beocin",2000,"RS",45.20952,19.71043,"28-08-2024","https://www.usgs.gov/centers/national-minerals-information-center/international-minerals-statistics-and-information", +"Holcim (Srbija) a.d.","Novi Popovac",1400,"RS",43.90633,21.50378,"28-08-2024","https://www.usgs.gov/centers/national-minerals-information-center/international-minerals-statistics-and-information", +"Titan Cementara Kosjerić Ltd.","Kosjeric",750,"RS",44.0125,19.88831,"28-08-2024","https://www.usgs.gov/centers/national-minerals-information-center/international-minerals-statistics-and-information", +"Sharrcem Sh.p.k.","Hani i Elezit,",850,"XK",42.14704,21.29863,"28-08-2024","https://www.usgs.gov/centers/national-minerals-information-center/international-minerals-statistics-and-information", +"Fabrika Cementa Lukavac d.d.","Lukavac",800,"BA",44.52596,18.52811,"28-08-2024","https://www.usgs.gov/centers/national-minerals-information-center/international-minerals-statistics-and-information", +"Tvornica Cementa Kakanj d.d. ","Kakanj",400,"BA",44.11922,18.10897,"28-08-2024","https://www.usgs.gov/centers/national-minerals-information-center/international-minerals-statistics-and-information", +"Lafarge Ciment Moldova SA","Rezina",1400,"MD",47.79094,28.9553,"28-08-2024","https://www.usgs.gov/centers/national-minerals-information-center/international-minerals-statistics-and-information", +"ZAO Rybnitsa Cement Comple","Rybnitsa",1100,"MD",47.78115,29.02078,"28-08-2024","https://www.usgs.gov/centers/national-minerals-information-center/international-minerals-statistics-and-information", +"ChAO Nikolayevtsemen","Mykolayiv",900,"UA",46.94555,32.06641,"28-08-2024","https://www.usgs.gov/centers/national-minerals-information-center/international-minerals-statistics-and-information; https://cemark.ua/en/zavodi/prat-mikolajivcement ", +"OAO KyivCement ","Kyiv",175,"UA",50.38525,30.55205,"28-08-2024","https://www.usgs.gov/centers/national-minerals-information-center/international-minerals-statistics-and-information https://www.dyckerhoff.com.ua/en/dyckerhoff-cement-ukraine ", +"OAO YuGCement ","Mykolayiv",1250,"UA",46.98512,31.9317,"28-08-2024","https://www.usgs.gov/centers/national-minerals-information-center/international-minerals-statistics-and-information, https://www.dyckerhoff.com.ua/en/yug-cemen", +"OOO Cement","Odessa",550,"UA",46.50818,30.67422,"28-08-2024","https://www.usgs.gov/centers/national-minerals-information-center/international-minerals-statistics-and-information https://se.ua/en/projects/llc-cement-odessa-cement-plant/ ", +"Overin Ltd","Amvrosievka",800,"UA",47.83453,38.46961,"28-08-2024","https://www.usgs.gov/centers/national-minerals-information-center/international-minerals-statistics-and-information","assumed equal split" +"Overin Ltd","Kamenskoye",800,"UA",48.51783,34.63382,"28-08-2024","https://www.usgs.gov/centers/national-minerals-information-center/international-minerals-statistics-and-information","assumed equal split" +"Overin Ltd","Kriviy Rih",800,"UA",47.87454,33.43586,"28-08-2024","https://www.usgs.gov/centers/national-minerals-information-center/international-minerals-statistics-and-information","assumed equal split" +"PAO Eurocement Ukraine","Balakleya, Kharkivs'ka",1000,"UA",49.49314,36.74926,"28-08-2024","https://www.usgs.gov/centers/national-minerals-information-center/international-minerals-statistics-and-information https://www.globalcement.com/news/item/13733-update-on-ukraine-february-2022 ", +"PAO Ivano-Frankovsktsement","Ivano-Frankivsk ",3600,"UA",48.97709,24.71227,"28-08-2024","https://www.usgs.gov/centers/national-minerals-information-center/international-minerals-statistics-and-information", +"PAO Kramatorkiy Tsementnyi Zavod PUSHKA ","Kramatorsk, Donets'ka",138,"UA",48.72802,37.54362,"28-08-2024","https://www.usgs.gov/centers/national-minerals-information-center/international-minerals-statistics-and-information https://www.cemnet.com/News/story/144668/pushka-ups-cement-production-56-6p-per-cent-to138-400t-in-q1.html ", +"PAO Podolsk Cement","Khmel'nyts'ka Oblast' ",2050,"UA",48.7461,26.64664,"28-08-2024","https://www.usgs.gov/centers/national-minerals-information-center/international-minerals-statistics-and-information https://cemark.ua/en/zavodi/at-podilskiy-cement ", +"PAO Volyn'Cement","Volyn'ska Oblast'",2000,"UA",50.54731,26.25774,"28-08-2024","https://www.usgs.gov/centers/national-minerals-information-center/international-minerals-statistics-and-information https://www.dyckerhoff.com.ua/volyn-cement ", diff --git a/data/district_heat_share.csv b/data/district_heat_share.csv index 07d4f51d..ad47fb3b 100644 --- a/data/district_heat_share.csv +++ b/data/district_heat_share.csv @@ -25,7 +25,7 @@ SE,50.4, GB,2, BY,70, EE,52,5406 -KO,3,207 +XK,3,207 RO,23,9962 SK,54,15000 NL,4,9800 diff --git a/data/era5-annual-HDD-per-country.csv b/data/era5-annual-HDD-per-country.csv index 5f6ad45d..4bb02806 100644 --- a/data/era5-annual-HDD-per-country.csv +++ b/data/era5-annual-HDD-per-country.csv @@ -29,6 +29,7 @@ PL,1615,1584,1275,1356,1364,1378,1517,1290,1230,1296,1249,1438,1294,1478,1446,15 PT,114,114,102,113,86,110,95,79,94,96,107,103,99,109,80,131,106,93,93,97,78,106,104,115,103,98,103,97,112,110,115,116,106,109,109,109,99,139,107,102,89,90,95,104,99,108,85,89,75,87,104,96,104,85,66,88,62,82,96,90,90,78,87,97,103,90,91,91,84,96,80,101,100,81,79,87,79,96,81,72,78,98,75 RO,931,939,801,813,874,851,839,815,799,780,736,811,883,948,822,968,810,789,826,731,744,826,890,867,873,706,791,776,858,792,787,798,838,782,752,855,772,836,780,880,801,811,763,807,917,815,882,827,710,700,846,801,848,701,806,869,842,805,740,710,760,721,844,754,799,780,684,695,695,757,793,781,709,662,681,721,720,690,624,648,740,973,611 RS,292,305,246,274,285,276,265,263,261,239,222,252,273,300,249,313,248,249,254,231,226,270,283,271,274,233,253,243,267,254,251,246,272,242,243,265,233,265,241,273,251,255,244,253,275,256,268,254,231,220,275,243,263,223,250,270,259,250,237,217,234,217,262,238,265,247,217,214,222,229,251,244,214,192,222,223,232,211,197,212,234,306,192 +XK,292,305,246,274,285,276,265,263,261,239,222,252,273,300,249,313,248,249,254,231,226,270,283,271,274,233,253,243,267,254,251,246,272,242,243,265,233,265,241,273,251,255,244,253,275,256,268,254,231,220,275,243,263,223,250,270,259,250,237,217,234,217,262,238,265,247,217,214,222,229,251,244,214,192,222,223,232,211,197,212,234,306,192 SK,221,219,199,207,209,201,212,202,189,189,178,210,195,217,208,228,192,193,185,185,178,208,213,211,219,179,187,192,203,200,192,188,195,178,178,197,188,204,193,215,191,190,180,193,212,198,207,187,172,173,202,186,191,171,186,204,193,184,177,162,184,174,190,184,191,182,163,161,170,188,175,179,174,142,161,170,176,157,152,158,180,231,150 SI,81,77,66,74,72,71,72,69,61,65,61,72,67,73,69,78,65,66,62,61,59,75,75,73,73,62,65,67,71,69,67,68,71,62,61,69,62,71,68,74,67,65,65,69,73,71,71,63,59,58,70,61,63,55,61,71,63,62,62,54,59,55,65,63,67,61,54,57,57,65,58,59,59,46,55,57,58,53,52,53,61,77,51 SE,4509,4537,3713,3939,4134,4059,4374,3918,3633,4015,3891,4219,3560,3919,4426,4488,3950,4223,3662,3988,3814,4451,4260,4021,4358,4613,3929,4280,4255,4254,4043,3806,3975,3634,3625,4238,4132,4314,4246,4287,4301,3913,3840,3819,4588,4139,4376,3931,3476,3446,3785,3695,3893,3991,3916,4073,3757,3950,3781,3446,3898,3778,3755,3769,3632,3561,3606,3590,3806,4397,3474,3935,3675,3452,3421,3635,3693,3705,3689,3247,3807,5084,3769 diff --git a/data/era5-annual-runoff-per-country.csv b/data/era5-annual-runoff-per-country.csv index 862ff743..f160f043 100644 --- a/data/era5-annual-runoff-per-country.csv +++ b/data/era5-annual-runoff-per-country.csv @@ -29,6 +29,7 @@ PL,19040.141287526196,13600.003649707409,4232.940272903036,6263.550300160282,117 PT,17389.910347609384,7956.13238827081,8339.728858321132,2075.556471824434,3081.9400195534536,5428.965709165979,13519.093138173732,8266.183051247071,2305.611210847845,4751.414112923152,8372.129135066036,5969.31083523099,2397.6586063764958,3916.9962424030286,9654.699566273128,9603.363148222781,4163.162870337118,9179.465624121007,12131.854156488425,23406.646477036124,10635.077955993413,11029.404714084018,16475.917880350513,12087.55769685171,9804.492049893286,26178.184180984652,5669.820254013018,7559.528320921835,15405.930172416956,11163.387795923936,7088.025310785357,10191.330496756716,7128.069257230898,9335.631563569985,5236.13128329125,4572.251664471752,32605.577182903042,149323.86523586328,34294.81803755196,6061.11721308257,5836.654497517657,4843.7020037722705,7814.782411245904,9395.759000250582,14057.157961109715,8192.288977642056,7655.760207241933,9203.645337709624,7637.7450966202805,7971.812432879156,7421.37678917759,2935.2871895485287,6329.939163930326,8820.796560748415,8944.109217212255,14719.27363438586,11050.779819799696,8379.75073967695,5590.525909815882,10485.131539563748,20476.028147427794,7715.162648805314,11939.81827695821,5116.2596877306005,3047.0903835389504,9273.489011971804,5135.313604526994,3331.418010762715,6338.048693933388,12105.616460835923,7097.468638389797,3348.213951094401,11773.920694867731,13465.586888738457,4379.602415677836,11394.463621230614,3104.8789319036796,7216.150544702967,6653.765864361187,5720.580737490315,6685.493238874142,8486.079863634486,8329.192253601708 RO,46545.50823036229,35517.718755954746,12007.97895282227,19448.903832688356,20440.973051620913,15132.394486734484,21523.767710605425,32075.68337603852,20312.088233477134,14653.654680967496,19346.344374357534,19295.50358149612,27702.617554877004,24644.67023787785,52797.882559506776,42262.7162454671,34689.01143849651,42583.74114324521,28973.147767939397,36882.64868179707,29063.471368254675,39575.626278602576,31898.858414072816,36283.98261870408,42207.50410750205,41714.957670180156,43270.313090823794,40474.54716426176,53565.91349208634,74865.02611452111,48190.11154819992,57257.26135564704,46523.80416861758,44300.83791323246,54901.1701096736,47361.27151969814,49156.09266449866,56461.30009557872,56062.45724028393,58506.511677323855,48499.732173446595,45901.64074770707,33171.12855766741,38310.49272614435,39377.41586450999,28638.803870927226,29424.553978129992,39429.14347226504,39300.73151290347,27525.04968129815,47095.77682827757,30948.90232192865,32939.14262154816,30155.99148400138,35067.04977301419,35592.25066656211,45790.67404045973,42596.77718301701,39223.35618808953,25767.93476452563,30963.38609617001,30034.908201595936,23323.05819720473,28517.276888551194,41560.85308154171,43999.15897330077,21427.19650317167,25084.131072037453,18450.764512377853,38182.39266803458,20422.517191285966,14090.243196787245,21998.55223596247,30809.187151501046,22071.90474198888,31906.454754357772,20763.073093214778,25620.747974742615,19248.368008063957,23289.011422937554,26669.846131314298,27207.74766143675,29386.08741874402 RS,12898.821957973714,11760.375115749226,5762.823681912337,10868.645457667955,6851.647476795101,6489.091511565737,8016.427124526303,11096.059611708006,8784.092785314235,6844.044739629848,5968.673897869134,7450.873145908507,8457.218084424714,10466.134979346216,18700.932768467817,18783.264457747777,9647.157790116991,14650.396388121844,12360.14810912279,11640.673528541236,8882.446980807292,14762.619600006037,18399.930168952076,13646.806400326906,14489.119148714197,14104.804002759012,15462.34970923992,10894.228431882033,15095.088711819322,17853.281396922546,12916.46431873845,14207.379133135786,14418.834370720482,12752.5957180177,15544.588217112372,15820.904121022999,13534.055257847373,15215.146639151637,12996.626380040323,13029.919161637963,10196.668003968522,10284.440766030819,7022.693160251435,8401.249663323453,8435.803252725058,10265.915943082338,8623.546341166757,7782.429841191159,9309.259412625106,4849.32865233776,9480.40891035497,8237.330612702019,6688.9341497267815,7113.796951355988,8945.392918392941,11391.406447517316,8770.78174795334,7797.074404297926,11205.567652241964,7490.638744688466,6890.626375097134,8721.152535625733,6986.899718851523,10014.515393386338,11863.685949406314,12576.12226693591,6930.903954576986,6933.68818306879,8436.351253425808,11680.836931112251,5673.257881932308,4512.930178739657,6094.8735580904795,11616.485592765608,8423.704814584986,9582.260510301834,6280.960312130538,10196.683253538626,5869.428152205924,6637.126459584064,8223.324863109141,9163.49600405833,11744.973584261521 +XK,12898.821957973714,11760.375115749226,5762.823681912337,10868.645457667955,6851.647476795101,6489.091511565737,8016.427124526303,11096.059611708006,8784.092785314235,6844.044739629848,5968.673897869134,7450.873145908507,8457.218084424714,10466.134979346216,18700.932768467817,18783.264457747777,9647.157790116991,14650.396388121844,12360.14810912279,11640.673528541236,8882.446980807292,14762.619600006037,18399.930168952076,13646.806400326906,14489.119148714197,14104.804002759012,15462.34970923992,10894.228431882033,15095.088711819322,17853.281396922546,12916.46431873845,14207.379133135786,14418.834370720482,12752.5957180177,15544.588217112372,15820.904121022999,13534.055257847373,15215.146639151637,12996.626380040323,13029.919161637963,10196.668003968522,10284.440766030819,7022.693160251435,8401.249663323453,8435.803252725058,10265.915943082338,8623.546341166757,7782.429841191159,9309.259412625106,4849.32865233776,9480.40891035497,8237.330612702019,6688.9341497267815,7113.796951355988,8945.392918392941,11391.406447517316,8770.78174795334,7797.074404297926,11205.567652241964,7490.638744688466,6890.626375097134,8721.152535625733,6986.899718851523,10014.515393386338,11863.685949406314,12576.12226693591,6930.903954576986,6933.68818306879,8436.351253425808,11680.836931112251,5673.257881932308,4512.930178739657,6094.8735580904795,11616.485592765608,8423.704814584986,9582.260510301834,6280.960312130538,10196.683253538626,5869.428152205924,6637.126459584064,8223.324863109141,9163.49600405833,11744.973584261521 SK,10526.703178382486,6581.841291454129,2779.6437301689157,6043.293021386589,8068.711762338472,4716.572547513843,4263.788112757618,7436.446538154413,5733.7942336519345,5091.94458281141,6885.47211985414,6956.591212284293,7116.928783228905,4573.269245439668,8169.130903254093,6799.092645889461,7190.199390340817,8819.311158887818,6679.080394471699,8681.76846617681,6714.688996801623,8780.135433744465,9674.052829336924,7510.89080672348,12315.672504913706,11551.288938768861,10658.095118642217,7760.467099195778,7334.701885838525,11743.053621084162,9101.455526104724,11252.254293590808,7089.2297957961755,11692.575497480175,11870.620362608648,8320.411050776946,12664.612697391287,10840.053026355938,9544.145158945727,8285.851845920657,6554.955003499832,6014.385824757616,5119.229272436076,5566.197178944401,8283.751441606055,4576.739002618681,5529.727054286627,4884.285979430572,7030.767074231632,6380.185010419688,6092.06334940043,4789.6919845964085,3988.728835990378,6100.445127127096,6174.336930810738,5839.492530664778,6739.897695678873,6073.547495791424,6239.663814901599,5985.626769812626,5946.910319392802,5350.4706690989715,2897.742723724252,3812.447551889599,5110.734824948982,5466.7571969447445,3822.1224333717755,4189.745228198809,3608.9397299109723,8925.718578619328,5520.297117401385,2338.023634704523,3634.014208205775,5079.021357670912,3789.3939110245783,3599.858750509022,4222.707040620564,3096.1701009538024,2158.8092391216674,4542.203594136759,4220.210061470592,2961.7796555712353,3705.0055429796116 SI,8932.252857660058,6769.672897729603,3971.443731895907,6727.0196008878875,5996.060296331706,4552.96378417224,7787.375795346372,9548.071392837826,4890.204133819321,7094.028640574649,11752.798116380785,9378.602450871665,7169.30972105447,8221.267552376507,10568.142173580174,7705.119699907013,8559.440940655051,9496.2682906945,10641.418485889739,13644.09405840664,8756.865265119286,10877.994032024846,13095.473005855994,10408.222250010325,17110.767148034232,13257.44359305617,10163.420442559087,10743.809603872312,11213.570708968457,12419.028940460184,8518.188189494229,14975.496301661744,10217.449212514946,10521.007791805137,10759.209828867228,9699.803414833696,14530.647692616923,14530.715084460895,12439.143395173185,11990.046930204517,9001.647305603035,10111.423546501868,6824.172499114327,10267.968760960974,10233.709492652128,9562.175707725224,11231.941186997657,8178.692540046128,8568.526412713521,8103.883097000008,9639.895318751553,9157.43571368136,6814.50158997294,8089.913064615838,8170.645053083449,10765.044719853075,6713.170108103339,8936.8362631332,9542.147586182518,8964.110093884974,8653.114721452737,8353.75428643612,4558.589088593759,9432.405903987477,6927.92152111369,7408.760392367348,5834.871486466167,9336.912851251047,8839.494837985663,10766.693939731143,5073.937522450624,6475.598951785893,9482.419717110955,13414.771212079502,5906.5584945059145,9942.151265372298,7696.092255607837,9521.835825354157,8476.124990692872,6361.010018809483,7504.908031281684,6349.444363482254,12494.86342976942 SE,97729.33612275522,104893.13349064675,152164.30605691054,147567.81837152236,172633.569885874,142454.06079467706,109264.12507808255,145966.80578917114,158733.59492028368,161670.6171803483,134822.12256461562,136958.6213484757,175679.6273876132,133962.36617697845,126787.36233921513,130861.49290945902,151133.2982760823,140247.52694114187,130508.52271890236,137421.63579450184,164132.0529341604,142467.57286064525,135886.87305352974,163762.3962091317,161128.38161511483,148196.28633931337,167892.87677861055,132017.696130452,105953.99289036485,119407.22923207263,147139.6039546916,151309.55114963037,164893.61323375857,137608.18237925606,149284.78771947857,108749.15747050248,131859.531763871,117290.48017785426,131751.97960784068,111117.27409251402,110551.615114603,81550.1135393761,114677.940027603,102356.46697333359,128977.80283219383,94483.98267503879,114937.96457142044,93256.91327642264,96751.29026217168,91074.34139788701,87931.96567208324,96560.83822983531,116746.94389793588,64626.25905820224,75156.91767736348,51489.37512699482,74729.26978432719,134673.01513808029,110440.65771030058,149033.9827088587,143576.83069821307,93040.02354987273,64075.160200006496,102493.08906248632,106664.82884715112,90351.43771324471,94801.81222609026,92445.93458012305,88919.20770998915,108111.72872590217,127440.80298482065,124444.06618883039,98961.91573013023,87913.90602563386,115956.48217115598,95526.84265190935,103459.08985036932,86058.90377748368,99040.9103276256,110493.22773914765,94182.7249029169,169752.66741900297,99896.09236620825 diff --git a/data/existing_infrastructure/existing_heating_raw.csv b/data/existing_infrastructure/existing_heating_raw.csv index 18774460..5e2581c9 100644 --- a/data/existing_infrastructure/existing_heating_raw.csv +++ b/data/existing_infrastructure/existing_heating_raw.csv @@ -28,4 +28,5 @@ United Kingdom,160.49,1.26,7.39,13.81,0.81,0.21 Norway,,,,,2.91,0.334 Switzerland,,,,,1,0.849 Serbia,,,,,, +Kosovo,,,,,, Bosnia Herzegovina,,,,,, diff --git a/data/refineries-noneu.csv b/data/refineries-noneu.csv new file mode 100644 index 00000000..e6012797 --- /dev/null +++ b/data/refineries-noneu.csv @@ -0,0 +1,15 @@ +"Site","Capacity [bbl/day]","Country","Latitude","Longitude","Date","Source","Comment" +"Modrica",1,"BA",44.95978,18.31294,"29-08-2024","https://modricaoil.com/Content/Read/onama?lang=en-US","the only one" +"OKTA, Skopje",1,"MK",42.0022,21.65532,"29-08-2024","https://en.wikipedia.org/wiki/OKTA","the only one" +"Ballsh",20000,"AL",40.60468,19.75231,"29-08-2024","https://www.trade.gov/country-commercial-guides/albania-oil-and-gas", +"Fier",10000,"AL",40.70095,19.54698,"29-08-2024","https://www.trade.gov/country-commercial-guides/albania-oil-and-gas", +"Elbasan",5000,"AL",41.08621,20.00762,"29-08-2024","https://www.trade.gov/country-commercial-guides/albania-oil-and-gas", +"Pančevo",96000,"RS",44.83051,20.68127,"29-08-2024","https://en.wikipedia.org/wiki/Naftna_Industrija_Srbije", +"Novi Sad",52000,"RS",45.27559,19.86733,"29-08-2024","https://en.wikipedia.org/wiki/Naftna_Industrija_Srbije", +"Halychyna Refinery (Pryvat), Drohobych",40000,"UA",49.34,23.4851,"29-08-2024","https://en.wikipedia.org/wiki/List_of_oil_refineries", +"Kherson Refinery (Alliance)",36000,"UA",46.65946,32.57479,"29-08-2024","https://en.wikipedia.org/wiki/List_of_oil_refineries", +"Kremenchuk Refinery (Ukrtatnafta)",368500,"UA",49.15299,33.4327,"29-08-2024","https://en.wikipedia.org/wiki/List_of_oil_refineries", +"LINOS Refinery, Lysychansk Oil Refinery (TNK-BP)",320000,"UA",48.84876,38.29979,"29-08-2024","https://en.wikipedia.org/wiki/List_of_oil_refineries", +"Lviv Oil Research & Refinery",18000,"UA",49.80662,24.04376,"29-08-2024","https://en.wikipedia.org/wiki/List_of_oil_refineries","capacity estimated based on number of employees" +"Naftokhimik Prykarpattya (Pryvat) Nadvirna",39000,"UA",48.62873,24.59924,"29-08-2024","https://en.wikipedia.org/wiki/List_of_oil_refineries", +"Odesa Refinery (LUKOIL)",70000,"UA",46.51189,30.68805,"29-08-2024","https://en.wikipedia.org/wiki/List_of_oil_refineries", diff --git a/data/transmission_projects/nep/new_links.csv b/data/transmission_projects/nep/new_links.csv index d237893f..7a551f36 100644 --- a/data/transmission_projects/nep/new_links.csv +++ b/data/transmission_projects/nep/new_links.csv @@ -10,3 +10,9 @@ DC40plus,Dörpen/West,Klostermansfeld/Sachsen-Anhalt,2000.0,426,confirmed,2037,T DC41,Alfstedt/Niedersachsen,Hüffenhardt/Baden-Württemberg,2000.0,607,confirmed,2037,True,"{""url"":""https://data.netzausbau.de/2037-2023/NEP/NEP_2037_2045_Bestaetigung.pdf"", ""status"":""confirmed"", ""origin"":""NEP"",""version"":2024,""location0"":""Alfstedt/Niedersachsen"",""location1"":""Hüffenhardt/Baden-Württemberg""",9.0666915,53.5499782,9.0827453,49.2908862 DC42,Sahms/Schleswig-Holstein,Böblingen/Baden-Württemberg,2000.0,737,confirmed,2037,True,"{""url"":""https://data.netzausbau.de/2037-2023/NEP/NEP_2037_2045_Bestaetigung.pdf"", ""status"":""confirmed"", ""origin"":""NEP"",""version"":2024,""location0"":""Sahms/Schleswig-Holstein"",""location1"":""Böblingen/Baden-Württemberg""",10.5331297,53.5252973,9.0113444,48.684969 DC42plus,Sahms/Schleswig-Holstein,Trennfeld/Bayern,2000.0,546,confirmed,2037,True,"{""url"":""https://data.netzausbau.de/2037-2023/NEP/NEP_2037_2045_Bestaetigung.pdf"", ""status"":""confirmed"", ""origin"":""NEP"",""version"":2024,""location0"":""Sahms/Schleswig-Holstein"",""location1"":""Trennfeld/Bayern""",10.5331297,53.5252973,9.6151453,49.7950676 +DC1,Emden Ost,Osterath,2000,297,in_permitting,2027,True,"{url:https://www.netzentwicklungsplan.de/sites/default/files/2024-04/NEP_2037_2045_V2023_Anhang_2E_Aktualisierung_April_2024_%28komprimiert%29.pdf,TYNDP 2022:132,""location0"":""Emden Ost"",""location1"":""Osterath""",7.2492328,53.3655941,6.6207151,51.2690922 +DC2,Osterath,Philippsburg,2000,299,in_permitting,2026,False,"{url:https://www.netzentwicklungsplan.de/sites/default/files/2024-04/NEP_2037_2045_V2023_Anhang_2E_Aktualisierung_April_2024_%28komprimiert%29.pdf,TYNDP 2022: 254,""location0"":""Osterath"",""location1"":""Philippsburg""",6.6207151,51.2690922,7.5514555,48.9953996 +DC3,Brunsbüttel,Großgartach,2000,694,in_permitting,2028,True,"{url:https://www.netzentwicklungsplan.de/sites/default/files/2024-04/NEP_2037_2045_V2023_Anhang_2E_Aktualisierung_April_2024_%28komprimiert%29.pdf,TYNDP 2022: 235,""location0"":""Brunsbüttel"",""location1"":""Großgartach""",9.1395423,53.8972549,9.1258701,49.1425406 +DC4,Wilster ,Bergrheinfeld,2000,540,in_permitting,2028,True,"{url:https://www.netzentwicklungsplan.de/sites/default/files/2024-04/NEP_2037_2045_V2023_Anhang_2E_Aktualisierung_April_2024_%28komprimiert%29.pdf,TYNDP 2022: 235,""location0"":""Wilster "",""location1"":""Bergrheinfeld""",9.3741366,53.9233519,10.1810033,50.0082136 +DC5,Wolmirstedt,Isar/Bayern,2000,539,in_permitting,2027,True,"{url:https://www.netzentwicklungsplan.de/sites/default/files/2024-04/NEP_2037_2045_V2023_Anhang_2E_Aktualisierung_April_2024_%28komprimiert%29.pdf,TYNDP 2022: 130, name:SuedOstLink,""location0"":""Wolmirstedt"",""location1"":""Isar/Bayern""",11.6267388,52.2484924,11.5745421,47.6691308 +DC20,Klein Rogahn,Isar/Bayern,2000,759,in_permitting,2030,False,"{url:https://www.netzentwicklungsplan.de/sites/default/files/2024-04/NEP_2037_2045_V2023_Anhang_2E_Aktualisierung_April_2024_%28komprimiert%29.pdf, name:SuedOstLink+,""location0"":""Klein Rogahn"",""location1"":""Isar/Bayern""",11.3482229,53.6044461,11.5745421,47.6691308 diff --git a/doc/conf.py b/doc/conf.py index f0d1ca37..bb929a46 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -92,9 +92,9 @@ author = "Tom Brown (KIT, TUB, FIAS), Jonas Hoersch (KIT, FIAS), Fabian Hofmann # built documents. # # The short X.Y version. -version = "0.11" +version = "0.12" # The full version, including alpha/beta/rc tags. -release = "0.11.0" +release = "0.12.0" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/doc/configtables/atlite.csv b/doc/configtables/atlite.csv index 5e0d2bd0..10965eed 100644 --- a/doc/configtables/atlite.csv +++ b/doc/configtables/atlite.csv @@ -4,7 +4,7 @@ nprocesses,--,int,"Number of parallel processes in cutout preparation" show_progress,bool,true/false,"Whether progressbar for atlite conversion processes should be shown. False saves time." cutouts,,, -- {name},--,"Convention is to name cutouts like ``--`` (e.g. ``europe-2013-sarah3-era5``).","Name of the cutout netcdf file. The user may specify multiple cutouts under configuration ``atlite: cutouts:``. Reference is used in configuration ``renewable: {technology}: cutout:``. The cutout ``base`` may be used to automatically calculate temporal and spatial bounds of the network." --- -- module,--,"Subset of {'era5','sarah'}","Source of the reanalysis weather dataset (e.g. `ERA5 `_ or `SARAH-2 `_)" +-- -- module,--,"Subset of {'era5','sarah'}","Source of the reanalysis weather dataset (e.g. `ERA5 `_ or `SARAH-3 `_)" -- -- x,°,"Float interval within [-180, 180]","Range of longitudes to download weather data for. If not defined, it defaults to the spatial bounds of all bus shapes." -- -- y,°,"Float interval within [-90, 90]","Range of latitudes to download weather data for. If not defined, it defaults to the spatial bounds of all bus shapes." -- -- dx,°,"Larger than 0.25","Grid resolution for longitude" diff --git a/doc/configtables/countries.csv b/doc/configtables/countries.csv index 6a386416..41ddd8e9 100644 --- a/doc/configtables/countries.csv +++ b/doc/configtables/countries.csv @@ -1,2 +1,2 @@ ,Unit,Values,Description -countries,--,"Subset of {'AL', 'AT', 'BA', 'BE', 'BG', 'CH', 'CZ', 'DE', 'DK', 'EE', 'ES', 'FI', 'FR', 'GB', 'GR', 'HR', 'HU', 'IE', 'IT', 'LT', 'LU', 'LV', 'ME', 'MK', 'NL', 'NO', 'PL', 'PT', 'RO', 'RS', 'SE', 'SI', 'SK'}","European countries defined by their `Two-letter country codes (ISO 3166-1) `_ which should be included in the energy system model." +countries,--,"Subset of {'AL', 'AT', 'BA', 'BE', 'BG', 'CH', 'CZ', 'DE', 'DK', 'EE', 'ES', 'FI', 'FR', 'GB', 'GR', 'HR', 'HU', 'IE', 'IT', 'LT', 'LU', 'LV', 'ME', 'MK', 'NL', 'NO', 'PL', 'PT', 'RO', 'RS', 'SE', 'SI', 'SK', 'XK'}","European countries defined by their `Two-letter country codes (ISO 3166-1) `_ which should be included in the energy system model." diff --git a/doc/configtables/industry.csv b/doc/configtables/industry.csv index 4187e118..fd80e804 100644 --- a/doc/configtables/industry.csv +++ b/doc/configtables/industry.csv @@ -35,3 +35,4 @@ MWh_CH4_per_tMeOH,MWhCH4/tMeOH,float,"The energy amount of methane needed to pro MWh_MeOH_per_tMeOH,LHV,float,"The energy amount per ton of methanol. From `DECHEMA (2017) `_, page 74." hotmaps_locate_missing,--,"{true,false}",Locate industrial sites without valid locations based on city and countries. reference_year,year,YYYY,The year used as the baseline for industrial energy demand and production. Data extracted from `JRC-IDEES 2015 `_ +oil_refining_emissions,tCO2/MWh,float,"The emissions from oil fuel processing (e.g. oil in petrochemical refinieries). The default value of 0.013 tCO2/MWh is based on DE statistics for 2019; the EU value is very similar." diff --git a/doc/configtables/sector.csv b/doc/configtables/sector.csv index 88442a9e..7de2a173 100644 --- a/doc/configtables/sector.csv +++ b/doc/configtables/sector.csv @@ -9,8 +9,13 @@ district_heating,--,,`prepare_sector_network.py `_ . Can be a string or a dictionary with years as keys which denote the year another turbine model becomes available.","Specifies the solar panel technology and its characteristic attributes." diff --git a/doc/img/intro-workflow.png b/doc/img/intro-workflow.png index 4009fbcd..87cec61f 100644 Binary files a/doc/img/intro-workflow.png and b/doc/img/intro-workflow.png differ diff --git a/doc/preparation.rst b/doc/preparation.rst index 83f9781c..8de4af42 100644 --- a/doc/preparation.rst +++ b/doc/preparation.rst @@ -41,6 +41,17 @@ Rule ``build_cutout`` .. automodule:: build_cutout +Rule ``clean_osm_data`` +============================= + +.. automodule:: clean_osm_data + + +Rule ``build_osm_network`` +============================= + +.. automodule:: build_osm_network + .. _base: Rule ``base_network`` @@ -48,6 +59,12 @@ Rule ``base_network`` .. automodule:: base_network + +Rule ``build_transmission_projects`` +==================================== + +.. automodule:: build_transmission_projects + .. _shapes: Rule ``build_shapes`` @@ -55,6 +72,10 @@ Rule ``build_shapes`` .. automodule:: build_shapes +Rule ``build_gdp_pop_non_nuts3`` +============================= + +.. automodule:: build_gdp_pop_non_nuts3 .. _powerplants: diff --git a/doc/release_notes.rst b/doc/release_notes.rst index d5fbe781..97db4baf 100644 --- a/doc/release_notes.rst +++ b/doc/release_notes.rst @@ -8,103 +8,278 @@ Release Notes ########################################## -Upcoming Release -================ +.. Upcoming Release + +* Updated district heating supply temperatures based on `Euroheat's DHC Market Outlook 2024`__ and `AGFW-Hauptbericht 2022 `__. `min_forward_temperature` and `return_temperature` (not given by Euroheat) are extrapolated based on German values. +* Made the overdimensioning factor for heating systems specific for central/decentral heating, defaults to no overdimensionining for central heating and no changes to decentral heating compared to previous version. + +* bugfix: The carrier of stores was silently overwritten by their bus_carrier as a side effect when building the co2 constraints + +* bugfix: The oil generator was incorrectly dropped when the config `oil_refining_emissions` was greater than zero. This was the default behaviour in 0.12.0. + +PyPSA-Eur 0.12.0 (30th August 2024) +=================================== + +**Data Updates and Extensions** + +* Switch to OpenStreetMap (OSM) data for modelling the high-voltage transmission + grid. The new OSM-based grid is is now the default. The previous ENTSO-E grid + data is now deprecated. It can still be used by setting ``electricity: + base_network: entsoegridkit``. The new default setting "osm-prebuilt" + downloads the latest prebuilt snapshots from Zenodo. The setting "osm-raw" + retrieves and cleans the raw OSM data and subsequently builds the network. + (https://github.com/PyPSA/pypsa-eur/pull/1079) + +* Update energy balances from JRC-IDEES-2015 to `JRC-IDEES-2021 + `__. The + reference year was changed from 2015 to 2019. + (https://github.com/PyPSA/pypsa-eur/pull/1167) + +* Updated pre-built `weather data cutouts + `__. These are now merged cutouts with + solar irradiation from the new SARAH-3 dataset while taking all other + variables from ERA5. Cutouts are now available for multiple years (2010, 2013, + 2019, and 2023). The overall download size was cut in half. + (https://github.com/PyPSA/pypsa-eur/pull/1176) + +* Included data from the `Global Steel Plant Tracker + `__ + provided by Global Energy Monitor. The data includes among other attributes + the locations, ages, operating status, relining dates, manufacturing process + and capacities of steel plants in Europe. This data is used as a spatial + distribution key for the steel production, which is now separated by process + type (EAF, DRI + EAF, integrated). + (https://github.com/PyPSA/pypsa-eur/pull/1241) + +* Added data on the locations and capacities of ammonia plants in Europe. This + data is used as a spatial distribution key for the ammonia demand. The data + manually collected with sources noted in ``data/ammonia_plants.csv``. + (https://github.com/PyPSA/pypsa-eur/pull/1241) + +* Added data on the locations and capacities of cement plants in Europe that are + not included in the Hotmaps industrial database. The data sourced from the + `USGS 2019 Minerals Yearbooks + `__ + of specific countries is used as a spatial distribution key for the cement + demand. The data is stored in ``data/cement-plants-noneu.csv``. + (https://github.com/PyPSA/pypsa-eur/pull/1241) + +* Added data on the locations and capacities of refineries in Europe that are + not included in the Hotmaps industrial database. The data is mostly sourced + from the `Wikipedia list of oil refineries + `__. The data is stored + in ``data/refineries-noneu.csv``. + (https://github.com/PyPSA/pypsa-eur/pull/1241) * Retrieve share of urban population from `World Bank API `__. The data originates from the United Nations Population Division. Previously, a file ``data/urban_percent.csv`` with an undocumented source was used. + (https://github.com/PyPSA/pypsa-eur/pull/1248) + +* Updated Global Energy Monitor's Europe Gas Tracker to May 2024 version. + (https://github.com/PyPSA/pypsa-eur/pull/1235) * Updated country-specific Energy Availability Factors (EAFs) for nuclear power plants based on `IAEA 2021-2023 reported country averages `__. + (https://github.com/PyPSA/pypsa-eur/pull/1236) -* Update GEM Europe Gas Tracker to May 2024 version. +* Updated technology-data to v0.9.2, with added methanol and biomass + assumptions. -* Add investment period dependent CO2 sequestration potentials +* Updated EEZ shapes to v12. This data is now automatically retrieved and was + removed from the data bundle. (https://github.com/PyPSA/pypsa-eur/pull/1188, + https://github.com/PyPSA/pypsa-eur/pull/1210) -* Add option to produce hydrogen from solid biomass (flag ``solid biomass to hydrogen``), combined with carbon capture +* The country shapes from Naturalearth are now automatically retrieved and are + removed from the data bundle. (https://github.com/PyPSA/pypsa-eur/pull/1190) -* Fixed PDF encoding in ``build_biomass_transport_costs`` with update of tabula-py and jpype1 +**New Features** -* More modular and flexible handling of transmission projects. One can now add new transmission projects in a subfolder of `data/transmission projects` similar to the files in the template folder. After adding the new files and updating the config section `transmission_projects:`, transmission projects will be included if they are not duplicates of existing lines or other projects. +* Improved biomass representation: -* Add option to apply a gaussian kernel density smoothing to wind turbine power curves. + * Added unsustainable biomass potentials for solid, gaseous, and liquid biomass + based on current consumption levels from Eurostat energy balances. The + potentials can be phased-out and/or substituted by the phase-in of sustainable + biomass types using the config parameters ``biomass: + share_unsustainable_use_retained`` and ``biomass: + share_sustainable_potential_available``. + (https://github.com/PyPSA/pypsa-eur/pull/1139) -* Update JRC-IDEES-2015 to `JRC-IDEES-2021 `__. The reference year is changed from 2015 to 2019. + * Added energy penalty for BECC applications. + (https://github.com/PyPSA/pypsa-eur/pull/1130) -* Added option to use country-specific district heating forward and return temperatures. Defaults to lower temperatures in Scandinavia. + * Added option to enable the import of solid biomass. + (https://github.com/PyPSA/pypsa-eur/pull/1194) -* Added unsustainable biomass potentials for solid, gaseous, and liquid biomass. The potentials can be phased-out and/or - substituted by the phase-in of sustainable biomass types using the config parameters - ``biomass: share_unsustainable_use_retained`` and ``biomass: share_sustainable_potential_available``. + * Added option to produce electrobiofuels from solid biomass and hydrogen. This + process combined BtL and Fischer-Tropsch to efficiently use the available + biogenic carbon. (https://github.com/PyPSA/pypsa-eur/pull/1193) -* The rule ``prepare_links_p_nom`` was removed since it was outdated and not used. + * Added option to split municipal solid waste from solid biomass. + (https://github.com/PyPSA/pypsa-eur/pull/1195, + https://github.com/PyPSA/pypsa-eur/pull/1134) -* Changed heat pump COP approximation for central heating to be based on `Jensen et al. (2018) `__ and a default forward temperature of 90C. This is more realistic for district heating than the previously used approximation method. + * Added option to produce hydrogen from solid biomass with or without carbon + capture. (https://github.com/PyPSA/pypsa-eur/pull/1213) -* split solid biomass potentials into solid biomass and municipal solid waste. Add option to use municipal solid waste. This option is only activated in combination with the flag ``waste_to_energy`` +* Improved district heating representation: -* Add option to import solid biomass + * Added option to use country-specific district heating forward and return + temperatures. Defaults to lower temperatures in Scandinavia. + (https://github.com/PyPSA/pypsa-eur/pull/1180) -* Add option to produce electrobiofuels (flag ``electrobiofuels``) from solid biomass and hydrogen, as a combination of BtL and Fischer-Tropsch to make more use of the biogenic carbon + * Made central heating supply temperatures dynamic based on an adaptation of a + reference curve from Pieper et al. (2019) + (https://www.sciencedirect.com/science/article/pii/S0360544219305857?via%3Dihub). + (https://github.com/PyPSA/pypsa-eur/pull/1206/) -* Add flag ``sector: fossil_fuels`` in config to remove the option of importing fossil fuels + * Changed heat pump COP approximation for central heating to be based on + `Jensen et al. (2018) + `__ + and a default forward temperature of 90C. This is more realistic for + district heating than the previously used approximation method. + (https://github.com/PyPSA/pypsa-eur/pull/1176) -* Renamed the carrier of batteries in BEVs from `battery storage` to `EV battery` and the corresponding bus carrier from `Li ion` to `EV battery`. This is to avoid confusion with stationary battery storage. + * Added option for various power-to-X processes to specify their share of waste + heat that can be used in district heating. The default was changed from 100% + to 25%. (https://github.com/PyPSA/pypsa-eur/pull/1141) -* Changed default assumptions about waste heat usage from PtX and fuel cells in district heating. - The default value for the link efficiency scaling factor was changed from 100% to 25%. - It can be set to other values in the configuration ``sector: use_TECHNOLOGY_waste_heat``. - -* In simplifying polygons in :mod:`build_shapes` default to no tolerance. - -* Set non-zero capital_cost for methanol stores to avoid unrealistic storage sizes - -* Set p_nom = p_nom_min for generators with baseyear == grouping_year in add_existing_baseyear. This has no effect on the optimization but helps n.statistics to correctly report already installed capacities. - -* Reverted outdated hotfix for doubled renewable capacity in myopic optimization. +* Added option to specify emissions fuel processing (e.g. oil in petrochemical + refinieries) with setting ``industry: oil_refining_emissions:``. * Added Enhanced Geothermal Systems for generation of electricity and district heat. Cost and available capacity assumptions based on `Aghahosseini et al. (2020) `__. See configuration ``sector: enhanced_geothermal`` for details; by default switched off. -* Partially revert https://github.com/PyPSA/pypsa-eur/pull/967 to return to old grouping year logic (which was mostly correct) +* Represent Kosovo (XK) as separate country. + (https://github.com/PyPSA/pypsa-eur/pull/1249) -* Bugfix: Correctly read in threshold capacity below which to remove components from previous planning horizons in :mod:`add_brownfield`. +* Add option to specify carbon sequestration potentials per investment period. + (https://github.com/PyPSA/pypsa-eur/pull/1228) -* For countries not contained in the NUTS3-specific datasets (i.e. MD and UA), the mapping of GDP per capita and population per bus region used to spatially distribute electricity demand is now endogenised in a new rule :mod:`build_gdp_ppp_non_nuts3`. https://github.com/PyPSA/pypsa-eur/pull/1146 +* Add option to completely eliminate the use of fossil fuels. + (https://github.com/PyPSA/pypsa-eur/pull/1187) -* The databundle has been updated to release v0.3.0, which includes raw GDP and population data for countries outside the NUTS system (UA, MD). https://github.com/PyPSA/pypsa-eur/pull/1146 +* Added more modular and flexible handling of planned transmission reinforcement + projects (e.g. TYNDP). See configuration settings ``transmission_projects:``. + (https://github.com/PyPSA/pypsa-eur/pull/1085) -* Updated filtering in :mod:`determine_availability_matrix_MD_UA.py` to improve speed. https://github.com/PyPSA/pypsa-eur/pull/1146 - -* Bugfix: Impose minimum value of zero for district heating progress between current and future market share in :mod:`build_district_heat_share`. - -* The ``{scope}`` wildcard was removed, since its outputs were not used. - -* Enable parallelism in :mod:`determine_availability_matrix_MD_UA.py` and remove plots. This requires the use of temporary files. - -* Added new major feature to create the base_network from OpenStreetMap (OSM) data (PR https://github.com/PyPSA/pypsa-eur/pull/1079). Note that a heuristics based cleaning process is used for lines and links where electrical parameters are incomplete, missing, or ambiguous. Through ``electricity["base_network"]``, the base network can be set to "entsoegridkit" (now deprecated), "osm-prebuilt" (default, downloads the latest prebuilt snapshot based on OSM data from Zenodo), or "osm-raw" which retrieves (once) and cleans the raw OSM data and subsequently builds the network. Note that this process may take a few minutes. - -* Updated pre-built `weather data cutouts - `__. These are now merged cutouts with - solar irradiation from the new SARAH-3 dataset while taking all other - variables from ERA5. Cutouts are now available for multiple years (2010, 2013, - 2019, and 2023). +* Added option to smooth wind turbine power curves with a Gaussian kernel density. + (https://github.com/PyPSA/pypsa-eur/pull/1209). * Added option ``solving: curtailment_mode``` which fixes the dispatch profiles of generators with time-varying p_max_pu by setting ``p_min_pu = p_max_pu`` and adds an auxiliary curtailment generator with negative sign (to absorb excess power) at every AC bus. This can speed up the solving process as the curtailment decision is aggregated into a single generator per region. + (https://github.com/PyPSA/pypsa-eur/pull/1177) + +* Added capital costs to all liquid carbonaceous fuel stores. + (https://github.com/PyPSA/pypsa-eur/pull/1234) + +**Breaking Changes** + +* Due to memory issues, the feature ``n.shapes`` is temporarily disabled. + (https://github.com/PyPSA/pypsa-eur/pull/1238) + +* Renamed the carrier of batteries in BEVs from `battery storage` to `EV + battery` and the corresponding bus carrier from `Li ion` to `EV battery`. This + is to avoid confusion with stationary battery storage. + (https://github.com/PyPSA/pypsa-eur/pull/1116) + +**Changes** + +* Powerplants can now be assigned to all buses, not just substations. + (https://github.com/PyPSA/pypsa-eur/pull/1239) + +* Avoid adding existing gas pipelines repeatedly for different planning + horizons. + (https://github.com/PyPSA/pypsa-eur/pull/1162https://github.com/PyPSA/pypsa-eur/pull/1162) + +* Move custom busmaps to + ``data/busmaps/elec_s{simpl}_{clusters}_{base_network}.csv``. This allows for + different busmaps depending on the base network. + (https://github.com/PyPSA/pypsa-eur/pull/1231) + +* For countries not contained in the NUTS3-specific datasets (i.e. MD and UA), + the mapping of GDP per capita and population per bus region used to spatially + distribute electricity demand is now endogenised in a new rule + :mod:`build_gdp_ppp_non_nuts3`. The databundle has been updated accordingly. + (https://github.com/PyPSA/pypsa-eur/pull/1146) + +* Enable parallelism in :mod:`determine_availability_matrix_MD_UA.py` and remove + plots. This requires the use of temporary files. + (https://github.com/PyPSA/pypsa-eur/pull/1170) * In :mod:`base_network`, replace own voronoi polygon calculation function with Geopandas `gdf.voronoi_polygons` method. + (https://github.com/PyPSA/pypsa-eur/pull/1172) + +* In simplifying polygons in :mod:`build_shapes` default to no tolerance. + (https://github.com/PyPSA/pypsa-eur/pull/1137) + +* Updated filtering in :mod:`determine_availability_matrix_MD_UA.py` to improve + speed. (https://github.com/PyPSA/pypsa-eur/pull/1146) + +* Removed unused data files and rules. + (https://github.com/PyPSA/pypsa-eur/pull/1246, + https://github.com/PyPSA/pypsa-eur/pull/1203) + +* The ``{scope}`` wildcard was removed, since its outputs were not used. + (https://github.com/PyPSA/pypsa-eur/pull/1171) + +* Unify how the oil bus is added. + +* Set ``p_nom = p_nom_min`` for generators with ``baseyear == grouping_year`` in + :mod:`add_existing_baseyear`. This has no effect on the optimization but helps + to correctly report already installed capacities using ``n.statistics()``. + +* Cutouts are no longer marked as ``protected()``. + (https://github.com/PyPSA/pypsa-eur/pull/1220) + +**Bugfixes and Compatibility** + +* Bugfix in :mod:`simplify_network` for spatially resolving Corsica. + (https://github.com/PyPSA/pypsa-eur/pull/1215) + +* Bugfix for running without spatial resolution. + (https://github.com/PyPSA/pypsa-eur/pull/1183) + +* Bugfix: Impose minimum value of zero for district heating progress between + current and future market share in :mod:`build_district_heat_share`. + (https://github.com/PyPSA/pypsa-eur/pull/1168) + +* Bugfix: Correctly read in threshold capacity below which to remove components + from previous planning horizons in :mod:`add_brownfield`. + +* Bugfix for passing function arguments in rule :mod:`solve_operations_network`. + +* Bugfix avoiding infinity values in the intermediate industry sector ratios. + (https://github.com/PyPSA/pypsa-eur/pull/1227) + +* Bugfix: Add floating wind to cost update function in + :mod:`prepare_sector_network`. (https://github.com/PyPSA/pypsa-eur/pull/1106) + +* Fixed PDF encoding in ``build_biomass_transport_costs``. + (https://github.com/PyPSA/pypsa-eur/pull/1219) + +* Dropped ``pycountry`` dependency in favour of ``country_converter``. + (https://github.com/PyPSA/pypsa-eur/pull/1188) + +* Use temporary mirror for broken link to Eurostat energy balances (April 2023). + (https://github.com/PyPSA/pypsa-eur/pull/1147) + +* Compatibility with geopandas 1.0+. + (https://github.com/PyPSA/pypsa-eur/pull/1136) + +* Compatibility with snakemake 8.14+. + (https://github.com/PyPSA/pypsa-eur/pull/1112) + +* Address various deprecations. -* Move custom busmaps to ```data/busmaps/elec_s{simpl}_{clusters}_{base_network}.csv``` (if enabled). This allows for different busmaps depending on the base network and scenario. PyPSA-Eur 0.11.0 (25th May 2024) ===================================== diff --git a/doc/retrieve.rst b/doc/retrieve.rst index 6b339355..a00a8c79 100644 --- a/doc/retrieve.rst +++ b/doc/retrieve.rst @@ -19,13 +19,43 @@ Rule ``retrieve_databundle`` .. automodule:: retrieve_databundle +Rule ``retrieve_eurostat_data`` +=============================== + +.. automodule:: retrieve_eurostat_data + + +Rule ``retrieve_jrc_idees`` +=============================== + +.. automodule:: retrieve_jrc_idees + + + +Rule ``retrieve_eurostat_household_data`` +========================================= + +.. automodule:: retrieve_eurostat_household_data + + +Rule ``retrieve_gas_infrastructure_data`` +========================================= + +.. automodule:: retrieve_gas_infrastructure_data + + +Rule ``retrieve_osm_data`` +========================================= + +.. automodule:: retrieve_osm_data + Rule ``retrieve_cutout`` ============================ .. image:: https://zenodo.org/badge/DOI/10.5281/zenodo.6382570.svg :target: https://doi.org/10.5281/zenodo.6382570 -Cutouts are spatio-temporal subsets of the European weather data from the `ECMWF ERA5 `__ reanalysis dataset and the `CMSAF SARAH-2 `__ solar surface radiation dataset for the year 2013. +Cutouts are spatio-temporal subsets of the European weather data from the `ECMWF ERA5 `__ reanalysis dataset and the `CMSAF SARAH-3 `__ solar surface radiation dataset for the year 2013, 2019 or 2023. They have been prepared by and are for use with the `atlite `__ tool. You can either generate them yourself using the ``build_cutouts`` rule or retrieve them directly from `zenodo `__ through the rule ``retrieve_cutout``. The :ref:`tutorial` uses a smaller cutout than required for the full model (30 MB), which is also automatically downloaded. @@ -47,7 +77,7 @@ The :ref:`tutorial` uses a smaller cutout than required for the full model (30 M **Outputs** -- ``cutouts/{cutout}``: weather data from either the `ERA5 `__ reanalysis weather dataset or `SARAH-2 `__ satellite-based historic weather data. +- ``cutouts/{cutout}``: weather data from either the `ERA5 `__ reanalysis weather dataset and/or `SARAH-3 `__ satellite-based historic weather data. .. seealso:: For details see :mod:`build_cutout` and read the `atlite documentation `__. diff --git a/doc/sector.rst b/doc/sector.rst index e186ccf7..24f3c9e9 100644 --- a/doc/sector.rst +++ b/doc/sector.rst @@ -43,6 +43,11 @@ Rule ``build_biomass_potentials`` .. automodule:: build_biomass_potentials +Rule ``build_egs_potentials`` +============================================================================== + +.. automodule:: build_egs_potentials + Rule ``build_biomass_transport_costs`` ============================================================================== @@ -58,6 +63,11 @@ Rule ``build_cop_profiles`` .. automodule:: build_cop_profiles +Rule ``build_central_heating_temperature_profiles`` +============================================================================== + +.. automodule:: build_central_heating_temperature_profiles + Rule ``build_energy_totals`` ============================================================================== diff --git a/doc/tutorial.rst b/doc/tutorial.rst index 4a07132b..f514491e 100644 --- a/doc/tutorial.rst +++ b/doc/tutorial.rst @@ -80,7 +80,7 @@ adapt the required range of coordinates to the selection of countries. We can also decide which weather data source should be used to calculate potentials and capacity factor time-series for each carrier. For example, we may -want to use the ERA-5 dataset for solar and not the default SARAH-2 dataset. +want to use the ERA-5 dataset for solar and not the default SARAH-3 dataset. .. literalinclude:: ../config/test/config.electricity.yaml :language: yaml @@ -132,88 +132,98 @@ This triggers a workflow of multiple preceding jobs that depend on each rule's i graph[bgcolor=white, margin=0]; node[shape=box, style=rounded, fontname=sans, fontsize=10, penwidth=2]; edge[penwidth=2, color=grey]; - 0[label = "solve_network", color = "0.21 0.6 0.85", style="rounded"]; - 1[label = "prepare_network\nll: copt\nopts: ", color = "0.51 0.6 0.85", style="rounded"]; - 2[label = "add_extra_components", color = "0.43 0.6 0.85", style="rounded"]; - 3[label = "cluster_network\nclusters: 6", color = "0.17 0.6 0.85", style="rounded"]; - 4[label = "simplify_network\nsimpl: ", color = "0.49 0.6 0.85", style="rounded"]; - 5[label = "add_electricity", color = "0.26 0.6 0.85", style="rounded"]; - 6[label = "build_renewable_profiles\ntechnology: solar", color = "0.02 0.6 0.85", style="rounded"]; - 7[label = "base_network", color = "0.35 0.6 0.85", style="rounded"]; - 8[label = "build_shapes", color = "0.62 0.6 0.85", style="rounded"]; - 9[label = "retrieve_databundle", color = "0.24 0.6 0.85", style="rounded"]; - 10[label = "retrieve_cutout\ncutout: be-03-2013-era5", color = "0.36 0.6 0.85", style="rounded"]; - 11[label = "build_renewable_profiles\ntechnology: solar-hsat", color = "0.02 0.6 0.85", style="rounded"]; - 12[label = "build_renewable_profiles\ntechnology: onwind", color = "0.02 0.6 0.85", style="rounded"]; - 13[label = "build_renewable_profiles\ntechnology: offwind-ac", color = "0.02 0.6 0.85", style="rounded"]; - 14[label = "build_ship_raster", color = "0.08 0.6 0.85", style="rounded"]; - 15[label = "retrieve_ship_raster", color = "0.28 0.6 0.85", style="rounded"]; - 16[label = "build_renewable_profiles\ntechnology: offwind-dc", color = "0.02 0.6 0.85", style="rounded"]; - 17[label = "build_renewable_profiles\ntechnology: offwind-float", color = "0.02 0.6 0.85", style="rounded"]; - 18[label = "build_line_rating", color = "0.07 0.6 0.85", style="rounded"]; - 19[label = "retrieve_cost_data\nyear: 2030", color = "0.47 0.6 0.85", style="rounded"]; - 20[label = "build_powerplants", color = "0.11 0.6 0.85", style="rounded"]; - 21[label = "build_electricity_demand", color = "0.05 0.6 0.85", style="rounded"]; - 22[label = "retrieve_electricity_demand", color = "0.58 0.6 0.85", style="rounded"]; - 23[label = "retrieve_synthetic_electricity_demand", color = "0.11 0.6 0.85", style="rounded"]; + 0[label = "solve_network", color = "0.16 0.6 0.85", style="rounded"]; + 1[label = "prepare_network\nll: copt\nopts: ", color = "0.40 0.6 0.85", style="rounded"]; + 2[label = "add_extra_components", color = "0.03 0.6 0.85", style="rounded"]; + 3[label = "cluster_network\nclusters: 6", color = "0.26 0.6 0.85", style="rounded"]; + 4[label = "simplify_network\nsimpl: ", color = "0.17 0.6 0.85", style="rounded"]; + 5[label = "add_electricity", color = "0.39 0.6 0.85", style="rounded"]; + 6[label = "build_renewable_profiles\ntechnology: solar", color = "0.13 0.6 0.85", style="rounded"]; + 7[label = "base_network", color = "0.01 0.6 0.85", style="rounded"]; + 8[label = "retrieve_osm_prebuilt", color = "0.27 0.6 0.85", style="rounded"]; + 9[label = "build_shapes", color = "0.18 0.6 0.85", style="rounded"]; + 10[label = "retrieve_naturalearth_countries", color = "0.41 0.6 0.85", style="rounded"]; + 11[label = "retrieve_eez", color = "0.14 0.6 0.85", style="rounded"]; + 12[label = "retrieve_databundle", color = "0.38 0.6 0.85", style="rounded"]; + 13[label = "retrieve_cutout\ncutout: be-03-2013-era5", color = "0.51 0.6 0.85", style="rounded"]; + 14[label = "build_renewable_profiles\ntechnology: solar-hsat", color = "0.13 0.6 0.85", style="rounded"]; + 15[label = "build_renewable_profiles\ntechnology: onwind", color = "0.13 0.6 0.85", style="rounded"]; + 16[label = "build_renewable_profiles\ntechnology: offwind-ac", color = "0.13 0.6 0.85", style="rounded"]; + 17[label = "build_ship_raster", color = "0.16 0.6 0.85", style="rounded"]; + 18[label = "retrieve_ship_raster", color = "0.53 0.6 0.85", style="rounded"]; + 19[label = "build_renewable_profiles\ntechnology: offwind-dc", color = "0.13 0.6 0.85", style="rounded"]; + 20[label = "build_renewable_profiles\ntechnology: offwind-float", color = "0.13 0.6 0.85", style="rounded"]; + 21[label = "build_line_rating", color = "0.46 0.6 0.85", style="rounded"]; + 22[label = "build_transmission_projects", color = "0.29 0.6 0.85", style="rounded"]; + 23[label = "retrieve_cost_data\nyear: 2030", color = "0.11 0.6 0.85", style="rounded"]; + 24[label = "build_powerplants", color = "0.18 0.6 0.85", style="rounded"]; + 25[label = "build_electricity_demand", color = "0.30 0.6 0.85", style="rounded"]; + 26[label = "retrieve_electricity_demand", color = "0.13 0.6 0.85", style="rounded"]; + 27[label = "retrieve_synthetic_electricity_demand", color = "0.43 0.6 0.85", style="rounded"]; 1 -> 0 2 -> 1 - 19 -> 1 + 23 -> 1 3 -> 2 - 19 -> 2 + 23 -> 2 4 -> 3 - 19 -> 3 + 23 -> 3 5 -> 4 - 19 -> 4 + 23 -> 4 7 -> 4 6 -> 5 - 11 -> 5 - 12 -> 5 - 13 -> 5 + 14 -> 5 + 15 -> 5 16 -> 5 - 17 -> 5 - 7 -> 5 - 18 -> 5 19 -> 5 20 -> 5 + 7 -> 5 21 -> 5 - 8 -> 5 + 22 -> 5 + 23 -> 5 + 24 -> 5 + 25 -> 5 + 9 -> 5 7 -> 6 + 12 -> 6 9 -> 6 - 8 -> 6 - 10 -> 6 + 13 -> 6 8 -> 7 - 9 -> 8 - 7 -> 11 - 9 -> 11 - 8 -> 11 - 10 -> 11 - 7 -> 12 - 9 -> 12 - 8 -> 12 - 10 -> 12 - 7 -> 13 - 9 -> 13 - 14 -> 13 - 8 -> 13 - 10 -> 13 - 15 -> 14 - 10 -> 14 + 9 -> 7 + 10 -> 9 + 11 -> 9 + 12 -> 9 + 7 -> 14 + 12 -> 14 + 9 -> 14 + 13 -> 14 + 7 -> 15 + 12 -> 15 + 9 -> 15 + 13 -> 15 7 -> 16 + 12 -> 16 + 17 -> 16 9 -> 16 - 14 -> 16 - 8 -> 16 - 10 -> 16 - 7 -> 17 - 9 -> 17 - 14 -> 17 - 8 -> 17 - 10 -> 17 - 7 -> 18 - 10 -> 18 + 13 -> 16 + 18 -> 17 + 13 -> 17 + 7 -> 19 + 12 -> 19 + 17 -> 19 + 9 -> 19 + 13 -> 19 7 -> 20 - 22 -> 21 - 23 -> 21 + 12 -> 20 + 17 -> 20 + 9 -> 20 + 13 -> 20 + 7 -> 21 + 13 -> 21 + 7 -> 22 + 9 -> 22 + 7 -> 24 + 26 -> 25 + 27 -> 25 } | @@ -235,17 +245,21 @@ In the terminal, this will show up as a list of jobs to be run: build_renewable_profiles 6 build_shapes 1 build_ship_raster 1 + build_transmission_projects 1 cluster_network 1 prepare_network 1 retrieve_cost_data 1 retrieve_cutout 1 retrieve_databundle 1 + retrieve_eez 1 retrieve_electricity_demand 1 + retrieve_naturalearth_countries 1 + retrieve_osm_prebuilt 1 retrieve_ship_raster 1 retrieve_synthetic_electricity_demand 1 simplify_network 1 solve_network 1 - total 24 + total 28 ``snakemake`` then runs these jobs in the correct order. diff --git a/doc/tutorial_sector.rst b/doc/tutorial_sector.rst index 450f1e69..a369356f 100644 --- a/doc/tutorial_sector.rst +++ b/doc/tutorial_sector.rst @@ -74,6 +74,7 @@ which were already included in the electricity-only tutorial: base_network 1 build_ammonia_production 1 build_biomass_potentials 1 + build_central_heating_temperature_profiles 1 build_clustered_population_layouts 1 build_cop_profiles 1 build_daily_heat_demand 1 @@ -102,8 +103,9 @@ which were already included in the electricity-only tutorial: build_ship_raster 1 build_shipping_demand 1 build_simplified_population_layouts 1 - build_solar_thermal_profiles 3 - build_temperature_profiles 3 + build_solar_thermal_profiles 1 + build_temperature_profiles 1 + build_transmission_projects 1 build_transport_demand 1 cluster_gas_network 1 cluster_network 1 @@ -118,16 +120,23 @@ which were already included in the electricity-only tutorial: retrieve_cost_data 1 retrieve_cutout 1 retrieve_databundle 1 + retrieve_eez 1 retrieve_electricity_demand 1 retrieve_eurostat_data 1 retrieve_eurostat_household_data 1 retrieve_gas_infrastructure_data 1 + retrieve_gem_europe_gas_tracker 1 + retrieve_gem_steel_plant_tracker 1 + retrieve_jrc_idees 1 + retrieve_naturalearth_countries 1 + retrieve_osm_prebuilt 1 retrieve_ship_raster 1 retrieve_synthetic_electricity_demand 1 + retrieve_worldbank_urban_population 1 simplify_network 1 solve_sector_network 1 time_aggregation 1 - total 69 + total 74 This covers the retrieval of additional raw data from online resources and preprocessing data about the transport, industry, and heating sectors as well as @@ -146,264 +155,266 @@ successfully. graph[bgcolor=white, margin=0]; node[shape=box, style=rounded, fontname=sans, fontsize=10, penwidth=2]; edge[penwidth=2, color=grey]; - 0[label = "all", color = "0.28 0.6 0.85", style="rounded"]; - 1[label = "plot_summary", color = "0.60 0.6 0.85", style="rounded"]; + 0[label = "all", color = "0.22 0.6 0.85", style="rounded"]; + 1[label = "plot_summary", color = "0.11 0.6 0.85", style="rounded"]; 2[label = "make_summary", color = "0.30 0.6 0.85", style="rounded"]; - 3[label = "solve_sector_network", color = "0.36 0.6 0.85", style="rounded"]; - 4[label = "prepare_sector_network\nsector_opts: ", color = "0.22 0.6 0.85", style="rounded"]; - 5[label = "build_renewable_profiles\ntechnology: offwind-ac", color = "0.20 0.6 0.85", style="rounded"]; - 6[label = "base_network", color = "0.00 0.6 0.85", style="rounded"]; - 7[label = "build_shapes", color = "0.25 0.6 0.85", style="rounded"]; - 8[label = "retrieve_databundle", color = "0.06 0.6 0.85", style="rounded"]; - 9[label = "build_ship_raster", color = "0.06 0.6 0.85", style="rounded"]; - 10[label = "retrieve_ship_raster", color = "0.27 0.6 0.85", style="rounded"]; - 11[label = "retrieve_cutout\ncutout: be-03-2013-era5", color = "0.26 0.6 0.85", style="rounded"]; - 12[label = "build_renewable_profiles\ntechnology: offwind-dc", color = "0.20 0.6 0.85", style="rounded"]; - 13[label = "build_renewable_profiles\ntechnology: offwind-float", color = "0.20 0.6 0.85", style="rounded"]; - 14[label = "cluster_gas_network", color = "0.37 0.6 0.85", style="rounded"]; - 15[label = "build_gas_network", color = "0.44 0.6 0.85", style="rounded"]; - 16[label = "retrieve_gas_infrastructure_data", color = "0.43 0.6 0.85", style="rounded"]; - 17[label = "cluster_network\nclusters: 5", color = "0.08 0.6 0.85", style="rounded"]; - 18[label = "simplify_network\nsimpl: ", color = "0.01 0.6 0.85", style="rounded"]; - 19[label = "add_electricity", color = "0.53 0.6 0.85", style="rounded"]; - 20[label = "build_renewable_profiles\ntechnology: solar", color = "0.20 0.6 0.85", style="rounded"]; - 21[label = "build_renewable_profiles\ntechnology: solar-hsat", color = "0.20 0.6 0.85", style="rounded"]; - 22[label = "build_renewable_profiles\ntechnology: onwind", color = "0.20 0.6 0.85", style="rounded"]; - 23[label = "retrieve_cost_data\nyear: 2030", color = "0.11 0.6 0.85", style="rounded"]; - 24[label = "build_powerplants", color = "0.62 0.6 0.85", style="rounded"]; - 25[label = "build_electricity_demand", color = "0.66 0.6 0.85", style="rounded"]; - 26[label = "retrieve_electricity_demand", color = "0.20 0.6 0.85", style="rounded"]; - 27[label = "retrieve_synthetic_electricity_demand", color = "0.52 0.6 0.85", style="rounded"]; - 28[label = "build_gas_input_locations", color = "0.21 0.6 0.85", style="rounded"]; - 29[label = "time_aggregation", color = "0.58 0.6 0.85", style="rounded"]; - 30[label = "prepare_network\nll: v1.5\nopts: ", color = "0.61 0.6 0.85", style="rounded"]; - 31[label = "add_extra_components", color = "0.59 0.6 0.85", style="rounded"]; - 32[label = "build_hourly_heat_demand", color = "0.48 0.6 0.85", style="rounded"]; - 33[label = "build_daily_heat_demand\nscope: total", color = "0.12 0.6 0.85", style="rounded"]; - 34[label = "build_population_layouts", color = "0.62 0.6 0.85", style="rounded"]; - 35[label = "build_solar_thermal_profiles\nscope: total", color = "0.23 0.6 0.85", style="rounded"]; - 36[label = "retrieve_eurostat_data", color = "0.45 0.6 0.85", style="rounded"]; - 37[label = "build_population_weighted_energy_totals\nkind: energy", color = "0.22 0.6 0.85", style="rounded"]; - 38[label = "build_energy_totals", color = "0.65 0.6 0.85", style="rounded"]; - 39[label = "retrieve_eurostat_household_data", color = "0.36 0.6 0.85", style="rounded"]; - 40[label = "build_clustered_population_layouts", color = "0.02 0.6 0.85", style="rounded"]; - 41[label = "build_population_weighted_energy_totals\nkind: heat", color = "0.22 0.6 0.85", style="rounded"]; - 42[label = "build_heat_totals", color = "0.53 0.6 0.85", style="rounded"]; - 43[label = "build_shipping_demand", color = "0.17 0.6 0.85", style="rounded"]; - 44[label = "build_transport_demand", color = "0.49 0.6 0.85", style="rounded"]; - 45[label = "build_temperature_profiles\nscope: total", color = "0.32 0.6 0.85", style="rounded"]; - 46[label = "build_biomass_potentials\nplanning_horizons: 2030", color = "0.34 0.6 0.85", style="rounded"]; - 47[label = "build_salt_cavern_potentials", color = "0.55 0.6 0.85", style="rounded"]; - 48[label = "build_simplified_population_layouts", color = "0.46 0.6 0.85", style="rounded"]; - 49[label = "build_industrial_energy_demand_per_node", color = "0.14 0.6 0.85", style="rounded"]; - 50[label = "build_industry_sector_ratios_intermediate\nplanning_horizons: 2030", color = "0.27 0.6 0.85", style="rounded"]; - 51[label = "build_industry_sector_ratios", color = "0.11 0.6 0.85", style="rounded"]; - 52[label = "build_ammonia_production", color = "0.25 0.6 0.85", style="rounded"]; - 53[label = "build_industrial_energy_demand_per_country_today", color = "0.44 0.6 0.85", style="rounded"]; - 54[label = "build_industrial_production_per_country", color = "0.18 0.6 0.85", style="rounded"]; - 55[label = "build_industrial_production_per_node", color = "0.41 0.6 0.85", style="rounded"]; - 56[label = "build_industrial_distribution_key", color = "0.04 0.6 0.85", style="rounded"]; - 57[label = "build_industrial_production_per_country_tomorrow\nplanning_horizons: 2030", color = "0.09 0.6 0.85", style="rounded"]; - 58[label = "build_industrial_energy_demand_per_node_today", color = "0.46 0.6 0.85", style="rounded"]; - 59[label = "build_district_heat_share\nplanning_horizons: 2030", color = "0.39 0.6 0.85", style="rounded"]; - 60[label = "build_temperature_profiles\nscope: rural", color = "0.32 0.6 0.85", style="rounded"]; - 61[label = "build_temperature_profiles\nscope: urban", color = "0.32 0.6 0.85", style="rounded"]; - 62[label = "build_cop_profiles", color = "0.55 0.6 0.85", style="rounded"]; - 63[label = "build_solar_thermal_profiles\nscope: urban", color = "0.23 0.6 0.85", style="rounded"]; - 64[label = "build_solar_thermal_profiles\nscope: rural", color = "0.23 0.6 0.85", style="rounded"]; - 65[label = "plot_power_network_clustered", color = "0.41 0.6 0.85", style="rounded"]; - 66[label = "plot_power_network", color = "0.40 0.6 0.85", style="rounded"]; - 67[label = "plot_hydrogen_network", color = "0.42 0.6 0.85", style="rounded"]; - 68[label = "plot_gas_network", color = "0.32 0.6 0.85", style="rounded"]; + 3[label = "solve_sector_network", color = "0.42 0.6 0.85", style="rounded"]; + 4[label = "prepare_sector_network\nsector_opts: ", color = "0.45 0.6 0.85", style="rounded"]; + 5[label = "build_renewable_profiles\ntechnology: offwind-ac", color = "0.44 0.6 0.85", style="rounded"]; + 6[label = "base_network", color = "0.26 0.6 0.85", style="rounded"]; + 7[label = "retrieve_osm_prebuilt", color = "0.01 0.6 0.85", style="rounded"]; + 8[label = "build_shapes", color = "0.50 0.6 0.85", style="rounded"]; + 9[label = "retrieve_naturalearth_countries", color = "0.09 0.6 0.85", style="rounded"]; + 10[label = "retrieve_eez", color = "0.52 0.6 0.85", style="rounded"]; + 11[label = "retrieve_databundle", color = "0.00 0.6 0.85", style="rounded"]; + 12[label = "build_ship_raster", color = "0.29 0.6 0.85", style="rounded"]; + 13[label = "retrieve_ship_raster", color = "0.13 0.6 0.85", style="rounded"]; + 14[label = "retrieve_cutout\ncutout: be-03-2013-era5", color = "0.06 0.6 0.85", style="rounded"]; + 15[label = "build_renewable_profiles\ntechnology: offwind-dc", color = "0.44 0.6 0.85", style="rounded"]; + 16[label = "build_renewable_profiles\ntechnology: offwind-float", color = "0.44 0.6 0.85", style="rounded"]; + 17[label = "cluster_gas_network", color = "0.48 0.6 0.85", style="rounded"]; + 18[label = "build_gas_network", color = "0.59 0.6 0.85", style="rounded"]; + 19[label = "retrieve_gas_infrastructure_data", color = "0.14 0.6 0.85", style="rounded"]; + 20[label = "cluster_network\nclusters: 5", color = "0.08 0.6 0.85", style="rounded"]; + 21[label = "simplify_network\nsimpl: ", color = "0.25 0.6 0.85", style="rounded"]; + 22[label = "add_electricity", color = "0.46 0.6 0.85", style="rounded"]; + 23[label = "build_renewable_profiles\ntechnology: solar", color = "0.44 0.6 0.85", style="rounded"]; + 24[label = "build_renewable_profiles\ntechnology: solar-hsat", color = "0.44 0.6 0.85", style="rounded"]; + 25[label = "build_renewable_profiles\ntechnology: onwind", color = "0.44 0.6 0.85", style="rounded"]; + 26[label = "build_transmission_projects", color = "0.63 0.6 0.85", style="rounded"]; + 27[label = "retrieve_cost_data\nyear: 2030", color = "0.05 0.6 0.85", style="rounded"]; + 28[label = "build_powerplants", color = "0.43 0.6 0.85", style="rounded"]; + 29[label = "build_electricity_demand", color = "0.39 0.6 0.85", style="rounded"]; + 30[label = "retrieve_electricity_demand", color = "0.62 0.6 0.85", style="rounded"]; + 31[label = "retrieve_synthetic_electricity_demand", color = "0.31 0.6 0.85", style="rounded"]; + 32[label = "build_gas_input_locations", color = "0.45 0.6 0.85", style="rounded"]; + 33[label = "retrieve_gem_europe_gas_tracker", color = "0.33 0.6 0.85", style="rounded"]; + 34[label = "time_aggregation", color = "0.60 0.6 0.85", style="rounded"]; + 35[label = "prepare_network\nll: v1.5\nopts: ", color = "0.23 0.6 0.85", style="rounded"]; + 36[label = "add_extra_components", color = "0.36 0.6 0.85", style="rounded"]; + 37[label = "build_hourly_heat_demand", color = "0.15 0.6 0.85", style="rounded"]; + 38[label = "build_daily_heat_demand", color = "0.57 0.6 0.85", style="rounded"]; + 39[label = "build_population_layouts", color = "0.47 0.6 0.85", style="rounded"]; + 40[label = "retrieve_worldbank_urban_population", color = "0.19 0.6 0.85", style="rounded"]; + 41[label = "build_solar_thermal_profiles", color = "0.11 0.6 0.85", style="rounded"]; + 42[label = "retrieve_eurostat_data", color = "0.04 0.6 0.85", style="rounded"]; + 43[label = "build_population_weighted_energy_totals\nkind: energy", color = "0.04 0.6 0.85", style="rounded"]; + 44[label = "build_energy_totals", color = "0.30 0.6 0.85", style="rounded"]; + 45[label = "retrieve_jrc_idees", color = "0.02 0.6 0.85", style="rounded"]; + 46[label = "retrieve_eurostat_household_data", color = "0.49 0.6 0.85", style="rounded"]; + 47[label = "build_clustered_population_layouts", color = "0.19 0.6 0.85", style="rounded"]; + 48[label = "build_population_weighted_energy_totals\nkind: heat", color = "0.04 0.6 0.85", style="rounded"]; + 49[label = "build_heat_totals", color = "0.08 0.6 0.85", style="rounded"]; + 50[label = "build_shipping_demand", color = "0.52 0.6 0.85", style="rounded"]; + 51[label = "build_transport_demand", color = "0.16 0.6 0.85", style="rounded"]; + 52[label = "build_temperature_profiles", color = "0.58 0.6 0.85", style="rounded"]; + 53[label = "build_biomass_potentials\nplanning_horizons: 2030", color = "0.55 0.6 0.85", style="rounded"]; + 54[label = "build_salt_cavern_potentials", color = "0.28 0.6 0.85", style="rounded"]; + 55[label = "build_simplified_population_layouts", color = "0.14 0.6 0.85", style="rounded"]; + 56[label = "build_industrial_energy_demand_per_node", color = "0.24 0.6 0.85", style="rounded"]; + 57[label = "build_industry_sector_ratios_intermediate\nplanning_horizons: 2030", color = "0.60 0.6 0.85", style="rounded"]; + 58[label = "build_industry_sector_ratios", color = "0.26 0.6 0.85", style="rounded"]; + 59[label = "build_ammonia_production", color = "0.16 0.6 0.85", style="rounded"]; + 60[label = "build_industrial_energy_demand_per_country_today", color = "0.18 0.6 0.85", style="rounded"]; + 61[label = "build_industrial_production_per_country", color = "0.61 0.6 0.85", style="rounded"]; + 62[label = "build_industrial_production_per_node", color = "0.65 0.6 0.85", style="rounded"]; + 63[label = "build_industrial_distribution_key", color = "0.31 0.6 0.85", style="rounded"]; + 64[label = "retrieve_gem_steel_plant_tracker", color = "0.27 0.6 0.85", style="rounded"]; + 65[label = "build_industrial_production_per_country_tomorrow\nplanning_horizons: 2030", color = "0.09 0.6 0.85", style="rounded"]; + 66[label = "build_industrial_energy_demand_per_node_today", color = "0.40 0.6 0.85", style="rounded"]; + 67[label = "build_district_heat_share\nplanning_horizons: 2030", color = "0.07 0.6 0.85", style="rounded"]; + 68[label = "build_cop_profiles", color = "0.38 0.6 0.85", style="rounded"]; + 69[label = "build_central_heating_temperature_profiles", color = "0.55 0.6 0.85", style="rounded"]; + 70[label = "plot_power_network_clustered", color = "0.20 0.6 0.85", style="rounded"]; + 71[label = "plot_power_network", color = "0.53 0.6 0.85", style="rounded"]; + 72[label = "plot_hydrogen_network", color = "0.64 0.6 0.85", style="rounded"]; + 73[label = "plot_gas_network", color = "0.28 0.6 0.85", style="rounded"]; 1 -> 0 2 -> 1 - 36 -> 1 - 8 -> 1 + 42 -> 1 + 11 -> 1 3 -> 2 - 23 -> 2 - 65 -> 2 - 66 -> 2 - 67 -> 2 - 68 -> 2 + 27 -> 2 + 70 -> 2 + 71 -> 2 + 72 -> 2 + 73 -> 2 4 -> 3 5 -> 4 - 12 -> 4 - 13 -> 4 - 14 -> 4 - 28 -> 4 - 29 -> 4 - 30 -> 4 - 36 -> 4 - 37 -> 4 - 41 -> 4 - 43 -> 4 - 44 -> 4 - 38 -> 4 - 8 -> 4 - 46 -> 4 - 23 -> 4 - 47 -> 4 - 18 -> 4 + 15 -> 4 + 16 -> 4 17 -> 4 - 40 -> 4 - 48 -> 4 - 49 -> 4 32 -> 4 - 59 -> 4 - 45 -> 4 - 60 -> 4 - 61 -> 4 - 62 -> 4 + 34 -> 4 35 -> 4 - 63 -> 4 - 64 -> 4 + 42 -> 4 + 43 -> 4 + 48 -> 4 + 50 -> 4 + 51 -> 4 + 44 -> 4 + 11 -> 4 + 53 -> 4 + 27 -> 4 + 54 -> 4 + 21 -> 4 + 20 -> 4 + 47 -> 4 + 55 -> 4 + 56 -> 4 + 37 -> 4 + 67 -> 4 + 52 -> 4 + 68 -> 4 + 41 -> 4 6 -> 5 - 8 -> 5 - 9 -> 5 - 7 -> 5 11 -> 5 + 12 -> 5 + 8 -> 5 + 14 -> 5 7 -> 6 - 8 -> 7 - 10 -> 9 - 11 -> 9 - 6 -> 12 - 8 -> 12 - 9 -> 12 - 7 -> 12 - 11 -> 12 - 6 -> 13 - 8 -> 13 - 9 -> 13 - 7 -> 13 - 11 -> 13 - 15 -> 14 - 17 -> 14 - 16 -> 15 + 8 -> 6 + 9 -> 8 + 10 -> 8 + 11 -> 8 + 13 -> 12 + 14 -> 12 + 6 -> 15 + 11 -> 15 + 12 -> 15 + 8 -> 15 + 14 -> 15 + 6 -> 16 + 11 -> 16 + 12 -> 16 + 8 -> 16 + 14 -> 16 18 -> 17 - 23 -> 17 + 20 -> 17 19 -> 18 - 23 -> 18 - 6 -> 18 - 20 -> 19 - 21 -> 19 - 22 -> 19 - 5 -> 19 - 12 -> 19 - 13 -> 19 - 6 -> 19 - 23 -> 19 - 24 -> 19 - 25 -> 19 - 7 -> 19 - 6 -> 20 - 8 -> 20 - 7 -> 20 - 11 -> 20 + 21 -> 20 + 27 -> 20 + 22 -> 21 + 27 -> 21 6 -> 21 - 8 -> 21 - 7 -> 21 - 11 -> 21 + 23 -> 22 + 24 -> 22 + 25 -> 22 + 5 -> 22 + 15 -> 22 + 16 -> 22 6 -> 22 + 26 -> 22 + 27 -> 22 + 28 -> 22 + 29 -> 22 8 -> 22 - 7 -> 22 - 11 -> 22 + 6 -> 23 + 11 -> 23 + 8 -> 23 + 14 -> 23 6 -> 24 - 26 -> 25 - 27 -> 25 - 16 -> 28 - 17 -> 28 + 11 -> 24 + 8 -> 24 + 14 -> 24 + 6 -> 25 + 11 -> 25 + 8 -> 25 + 14 -> 25 + 6 -> 26 + 8 -> 26 + 6 -> 28 30 -> 29 - 32 -> 29 - 35 -> 29 - 31 -> 30 - 23 -> 30 - 17 -> 31 - 23 -> 31 + 31 -> 29 33 -> 32 - 34 -> 33 - 17 -> 33 - 11 -> 33 - 7 -> 34 - 11 -> 34 - 34 -> 35 - 17 -> 35 - 11 -> 35 + 19 -> 32 + 20 -> 32 + 35 -> 34 + 37 -> 34 + 41 -> 34 + 36 -> 35 + 27 -> 35 + 20 -> 36 + 27 -> 36 38 -> 37 - 40 -> 37 - 7 -> 38 - 8 -> 38 - 36 -> 38 39 -> 38 - 34 -> 40 - 17 -> 40 - 11 -> 40 - 42 -> 41 - 40 -> 41 - 38 -> 42 - 7 -> 43 - 17 -> 43 - 38 -> 43 - 40 -> 44 - 37 -> 44 - 38 -> 44 + 20 -> 38 + 14 -> 38 + 8 -> 39 + 40 -> 39 + 14 -> 39 + 39 -> 41 + 20 -> 41 + 14 -> 41 + 44 -> 43 + 47 -> 43 8 -> 44 + 11 -> 44 45 -> 44 - 34 -> 45 - 17 -> 45 - 11 -> 45 - 8 -> 46 - 17 -> 46 - 7 -> 46 - 8 -> 47 - 17 -> 47 - 34 -> 48 - 18 -> 48 - 11 -> 48 - 50 -> 49 - 55 -> 49 - 58 -> 49 - 51 -> 50 - 53 -> 50 - 54 -> 50 + 42 -> 44 + 46 -> 44 + 39 -> 47 + 20 -> 47 + 14 -> 47 + 49 -> 48 + 47 -> 48 + 44 -> 49 + 8 -> 50 + 20 -> 50 + 44 -> 50 + 47 -> 51 + 43 -> 51 + 44 -> 51 + 11 -> 51 52 -> 51 - 8 -> 51 - 8 -> 52 + 39 -> 52 + 20 -> 52 + 14 -> 52 + 42 -> 53 + 11 -> 53 + 20 -> 53 8 -> 53 - 54 -> 53 - 52 -> 54 - 8 -> 54 - 36 -> 54 - 56 -> 55 - 57 -> 55 - 17 -> 56 - 40 -> 56 - 54 -> 57 - 56 -> 58 - 53 -> 58 - 38 -> 59 - 40 -> 59 - 34 -> 60 - 17 -> 60 - 11 -> 60 - 34 -> 61 - 17 -> 61 - 11 -> 61 - 45 -> 62 - 60 -> 62 - 61 -> 62 - 34 -> 63 - 17 -> 63 - 11 -> 63 - 34 -> 64 - 17 -> 64 - 11 -> 64 - 17 -> 65 - 3 -> 66 - 17 -> 66 - 3 -> 67 - 17 -> 67 - 3 -> 68 - 17 -> 68 + 11 -> 54 + 20 -> 54 + 39 -> 55 + 21 -> 55 + 14 -> 55 + 57 -> 56 + 62 -> 56 + 66 -> 56 + 58 -> 57 + 60 -> 57 + 61 -> 57 + 59 -> 58 + 45 -> 58 + 44 -> 60 + 45 -> 60 + 61 -> 60 + 59 -> 61 + 45 -> 61 + 42 -> 61 + 63 -> 62 + 65 -> 62 + 20 -> 63 + 47 -> 63 + 64 -> 63 + 61 -> 65 + 63 -> 66 + 60 -> 66 + 44 -> 67 + 47 -> 67 + 69 -> 68 + 52 -> 68 + 20 -> 68 + 52 -> 69 + 20 -> 69 + 20 -> 70 + 3 -> 71 + 20 -> 71 + 3 -> 72 + 20 -> 72 + 3 -> 73 + 20 -> 73 } | diff --git a/envs/environment.fixed.yaml b/envs/environment.fixed.yaml index 31dc7527..ac2d7eee 100644 --- a/envs/environment.fixed.yaml +++ b/envs/environment.fixed.yaml @@ -2,468 +2,9 @@ # # SPDX-License-Identifier: CC0-1.0 -name: pypsa-eur +name: pypsa-eur-20240812 channels: +- http://conda.anaconda.org/gurobi - conda-forge -- bioconda -- gurobi - defaults -dependencies: -- _libgcc_mutex=0.1 -- _openmp_mutex=4.5 -- affine=2.4.0 -- alsa-lib=1.2.11 -- ampl-mp=3.1.0 -- amply=0.1.6 -- appdirs=1.4.4 -- argparse-dataclass=2.0.0 -- asttokens=2.4.1 -- atk-1.0=2.38.0 -- atlite=0.2.12 -- attr=2.5.1 -- attrs=23.2.0 -- aws-c-auth=0.7.22 -- aws-c-cal=0.6.14 -- aws-c-common=0.9.19 -- aws-c-compression=0.2.18 -- aws-c-event-stream=0.4.2 -- aws-c-http=0.8.1 -- aws-c-io=0.14.8 -- aws-c-mqtt=0.10.4 -- aws-c-s3=0.5.9 -- aws-c-sdkutils=0.1.16 -- aws-checksums=0.1.18 -- aws-crt-cpp=0.26.9 -- aws-sdk-cpp=1.11.329 -- azure-core-cpp=1.11.1 -- azure-identity-cpp=1.6.0 -- azure-storage-blobs-cpp=12.10.0 -- azure-storage-common-cpp=12.5.0 -- beautifulsoup4=4.12.3 -- blosc=1.21.5 -- bokeh=3.4.1 -- bottleneck=1.3.8 -- branca=0.7.2 -- brotli=1.1.0 -- brotli-bin=1.1.0 -- brotli-python=1.1.0 -- bzip2=1.0.8 -- c-ares=1.28.1 -- c-blosc2=2.14.4 -- ca-certificates=2024.2.2 -- cads-api-client=1.0.3 -- cairo=1.18.0 -- cartopy=0.23.0 -- cdsapi=0.7.0 -- certifi=2024.2.2 -- cffi=1.16.0 -- cfgv=3.3.1 -- cfitsio=4.4.0 -- cftime=1.6.3 -- charset-normalizer=3.3.2 -- click=8.1.7 -- click-plugins=1.1.1 -- cligj=0.7.2 -- cloudpickle=3.0.0 -- coin-or-cbc=2.10.10 -- coin-or-cgl=0.60.7 -- coin-or-clp=1.17.8 -- coin-or-osi=0.108.10 -- coin-or-utils=2.11.11 -- coincbc=2.10.10 -- colorama=0.4.6 -- conda-inject=1.3.1 -- configargparse=1.7 -- connection_pool=0.0.3 -- contourpy=1.2.1 -- country_converter=1.2 -- cppad=20240000.4 -- cycler=0.12.1 -- cytoolz=0.12.3 -- dask=2024.5.1 -- dask-core=2024.5.1 -- dask-expr=1.1.1 -- datrie=0.8.2 -- dbus=1.13.6 -- decorator=5.1.1 -- deprecation=2.1.0 -- descartes=1.1.0 -- distlib=0.3.8 -- distributed=2024.5.1 -- distro=1.9.0 -- docutils=0.21.2 -- dpath=2.1.6 -- entsoe-py=0.6.7 -- et_xmlfile=1.1.0 -- exceptiongroup=1.2.0 -- executing=2.0.1 -- expat=2.6.2 -- filelock=3.14.0 -- fiona=1.9.6 -- fmt=10.2.1 -- folium=0.16.0 -- font-ttf-dejavu-sans-mono=2.37 -- font-ttf-inconsolata=3.000 -- font-ttf-source-code-pro=2.038 -- font-ttf-ubuntu=0.83 -- fontconfig=2.14.2 -- fonts-conda-ecosystem=1 -- fonts-conda-forge=1 -- fonttools=4.52.1 -- freetype=2.12.1 -- freexl=2.0.0 -- fribidi=1.0.10 -- fsspec=2024.5.0 -- gdal=3.8.5 -- gdk-pixbuf=2.42.12 -- geographiclib=2.0 -- geojson-rewind=1.1.0 -- geopandas=0.14.4 -- geopandas-base=0.14.4 -- geopy=2.4.1 -- geos=3.12.1 -- geotiff=1.7.3 -- gettext=0.22.5 -- gettext-tools=0.22.5 -- gflags=2.2.2 -- giflib=5.2.2 -- gitdb=4.0.11 -- gitpython=3.1.43 -- glib=2.80.2 -- glib-tools=2.80.2 -- glog=0.7.0 -- glpk=5.0 -- gmp=6.3.0 -- graphite2=1.3.13 -- graphviz=11.0.0 -- gst-plugins-base=1.24.3 -- gstreamer=1.24.3 -- gtk2=2.24.33 -- gts=0.7.6 -- gurobi=11.0.2 -- harfbuzz=8.5.0 -- hdf4=4.2.15 -- hdf5=1.14.3 -- humanfriendly=10.0 -- icu=73.2 -- identify=2.5.36 -- idna=3.7 -- immutables=0.20 -- importlib-metadata=7.1.0 -- importlib_metadata=7.1.0 -- importlib_resources=6.4.0 -- iniconfig=2.0.0 -- ipopt=3.14.16 -- ipython=8.24.0 -- jedi=0.19.1 -- jinja2=3.1.4 -- joblib=1.4.2 -- json-c=0.17 -- jsonschema=4.22.0 -- jsonschema-specifications=2023.12.1 -- jupyter_core=5.7.2 -- kealib=1.5.3 -- keyutils=1.6.1 -- kiwisolver=1.4.5 -- krb5=1.21.2 -- lame=3.100 -- lcms2=2.16 -- ld_impl_linux-64=2.40 -- lerc=4.0.0 -- libabseil=20240116.2 -- libaec=1.1.3 -- libarchive=3.7.4 -- libarrow=16.1.0 -- libarrow-acero=16.1.0 -- libarrow-dataset=16.1.0 -- libarrow-substrait=16.1.0 -- libasprintf=0.22.5 -- libasprintf-devel=0.22.5 -- libblas=3.9.0 -- libboost-headers=1.85.0 -- libbrotlicommon=1.1.0 -- libbrotlidec=1.1.0 -- libbrotlienc=1.1.0 -- libcap=2.69 -- libcblas=3.9.0 -- libclang-cpp15=15.0.7 -- libclang13=18.1.5 -- libcrc32c=1.1.2 -- libcups=2.3.3 -- libcurl=8.8.0 -- libdeflate=1.20 -- libedit=3.1.20191231 -- libev=4.33 -- libevent=2.1.12 -- libexpat=2.6.2 -- libffi=3.4.2 -- libflac=1.4.3 -- libgcc-ng=13.2.0 -- libgcrypt=1.10.3 -- libgd=2.3.3 -- libgdal=3.8.5 -- libgettextpo=0.22.5 -- libgettextpo-devel=0.22.5 -- libgfortran-ng=13.2.0 -- libgfortran5=13.2.0 -- libglib=2.80.2 -- libgomp=13.2.0 -- libgoogle-cloud=2.24.0 -- libgoogle-cloud-storage=2.24.0 -- libgpg-error=1.49 -- libgrpc=1.62.2 -- libhwloc=2.9.3 -- libiconv=1.17 -- libjpeg-turbo=3.0.0 -- libkml=1.3.0 -- liblapack=3.9.0 -- liblapacke=3.9.0 -- libllvm15=15.0.7 -- libllvm18=18.1.6 -- libnetcdf=4.9.2 -- libnghttp2=1.58.0 -- libnsl=2.0.1 -- libogg=1.3.4 -- libopenblas=0.3.27 -- libopus=1.3.1 -- libparquet=16.1.0 -- libpng=1.6.43 -- libpq=16.3 -- libprotobuf=4.25.3 -- libre2-11=2023.09.01 -- librsvg=2.58.0 -- librttopo=1.1.0 -- libscotch=7.0.4 -- libsndfile=1.2.2 -- libspatialindex=1.9.3 -- libspatialite=5.1.0 -- libspral=2024.01.18 -- libsqlite=3.45.3 -- libssh2=1.11.0 -- libstdcxx-ng=13.2.0 -- libsystemd0=255 -- libthrift=0.19.0 -- libtiff=4.6.0 -- libutf8proc=2.8.0 -- libuuid=2.38.1 -- libvorbis=1.3.7 -- libwebp=1.4.0 -- libwebp-base=1.4.0 -- libxcb=1.15 -- libxcrypt=4.4.36 -- libxkbcommon=1.7.0 -- libxml2=2.12.7 -- libxslt=1.1.39 -- libzip=1.10.1 -- libzlib=1.2.13 -- linopy=0.3.9 -- locket=1.0.0 -- lxml=5.2.2 -- lz4=4.3.3 -- lz4-c=1.9.4 -- lzo=2.10 -- mapclassify=2.6.1 -- markupsafe=2.1.5 -- matplotlib=3.8.4 -- matplotlib-base=3.8.4 -- matplotlib-inline=0.1.7 -- memory_profiler=0.61.0 -- metis=5.1.0 -- minizip=4.0.5 -- mpfr=4.2.1 -- mpg123=1.32.6 -- msgpack-python=1.0.8 -- multiurl=0.3.1 -- mumps-include=5.7.1 -- mumps-seq=5.7.1 -- munkres=1.1.4 -- mysql-common=8.3.0 -- mysql-libs=8.3.0 -- nbformat=5.10.4 -- ncurses=6.5 -- netcdf4=1.6.5 -- networkx=3.3 -- nodeenv=1.8.0 -- nomkl=1.0 -- nspr=4.35 -- nss=3.100 -- numexpr=2.9.0 -- numpy=1.26.4 -- openjdk=22.0.1 -- openjpeg=2.5.2 -- openpyxl=3.1.2 -- openssl=3.3.0 -- orc=2.0.1 -- packaging=24.0 -- pandas=2.2.2 -- pango=1.52.2 -- parso=0.8.4 -- partd=1.4.2 -- patsy=0.5.6 -- pcre2=10.43 -- pexpect=4.9.0 -- pickleshare=0.7.5 -- pillow=10.3.0 -- pip=24.0 -- pixman=0.43.2 -- pkgutil-resolve-name=1.3.10 -- plac=1.4.3 -- platformdirs=4.2.2 -- pluggy=1.5.0 -- ply=3.11 -- poppler=24.04.0 -- poppler-data=0.4.12 -- postgresql=16.3 -- powerplantmatching=0.5.15 -- pre-commit=3.7.1 -- progressbar2=4.4.2 -- proj=9.4.0 -- prompt-toolkit=3.0.42 -- psutil=5.9.8 -- pthread-stubs=0.4 -- ptyprocess=0.7.0 -- pulp=2.8.0 -- pulseaudio-client=17.0 -- pure_eval=0.2.2 -- py-cpuinfo=9.0.0 -- pyarrow=16.1.0 -- pyarrow-core=16.1.0 -- pyarrow-hotfix=0.6 -- pycountry=22.3.5 -- pycparser=2.22 -- pygments=2.18.0 -- pyomo=6.6.1 -- pyparsing=3.1.2 -- pyproj=3.6.1 -- pypsa=0.29.0 -- pyqt=5.15.9 -- pyqt5-sip=12.12.2 -- pyscipopt=5.0.1 -- pyshp=2.3.1 -- pysocks=1.7.1 -- pytables=3.9.2 -- pytest=8.2.1 -- python=3.11.9 -- python-dateutil=2.9.0 -- python-fastjsonschema=2.19.1 -- python-tzdata=2024.1 -- python-utils=3.8.2 -- python_abi=3.11 -- pytz=2024.1 -- pyxlsb=1.0.10 -- pyyaml=6.0.1 -- qt-main=5.15.8 -- rasterio=1.3.10 -- re2=2023.09.01 -- readline=8.2 -- referencing=0.35.1 -- requests=2.32.2 -- reretry=0.11.8 -- rioxarray=0.15.5 -- rpds-py=0.18.1 -- rtree=1.2.0 -- s2n=1.4.15 -- scikit-learn=1.5.0 -- scip=9.0.1 -- scipy=1.13.1 -- scotch=7.0.4 -- seaborn=0.13.2 -- seaborn-base=0.13.2 -- setuptools=70.0.0 -- setuptools-scm=8.1.0 -- setuptools_scm=8.1.0 -- shapely=2.0.4 -- sip=6.7.12 -- six=1.16.0 -- smart_open=7.0.4 -- smmap=5.0.0 -- snakemake-interface-common=1.17.2 -- snakemake-interface-executor-plugins=9.1.1 -- snakemake-interface-report-plugins=1.0.0 -- snakemake-interface-storage-plugins=3.2.2 -- snakemake-minimal=8.11.6 -- snappy=1.2.0 -- snuggs=1.4.7 -- sortedcontainers=2.4.0 -- soupsieve=2.5 -- spdlog=1.13.0 -- sqlite=3.45.3 -- stack_data=0.6.2 -- statsmodels=0.14.2 -- stopit=1.1.2 -- jpype1=1.5.0 -- tabulate=0.9.0 -- tbb=2021.11.0 -- tblib=3.0.0 -- threadpoolctl=3.5.0 -- throttler=1.2.2 -- tiledb=2.23.0 -- tk=8.6.13 -- toml=0.10.2 -- tomli=2.0.1 -- toolz=0.12.1 -- toposort=1.10 -- tornado=6.4 -- tqdm=4.66.4 -- traitlets=5.14.3 -- typing-extensions=4.11.0 -- typing_extensions=4.11.0 -- tzcode=2024a -- tzdata=2024a -- ukkonen=1.0.1 -- unidecode=1.3.8 -- unixodbc=2.3.12 -- uriparser=0.9.8 -- urllib3=2.2.1 -- validators=0.28.2 -- virtualenv=20.26.2 -- wcwidth=0.2.13 -- wheel=0.43.0 -- wrapt=1.16.0 -- xarray=2024.5.0 -- xcb-util=0.4.0 -- xcb-util-image=0.4.0 -- xcb-util-keysyms=0.4.0 -- xcb-util-renderutil=0.3.9 -- xcb-util-wm=0.4.1 -- xerces-c=3.2.5 -- xkeyboard-config=2.41 -- xlrd=2.0.1 -- xorg-fixesproto=5.0 -- xorg-inputproto=2.3.2 -- xorg-kbproto=1.0.7 -- xorg-libice=1.1.1 -- xorg-libsm=1.2.4 -- xorg-libx11=1.8.9 -- xorg-libxau=1.0.11 -- xorg-libxdmcp=1.1.3 -- xorg-libxext=1.3.4 -- xorg-libxfixes=5.0.3 -- xorg-libxi=1.7.10 -- xorg-libxrender=0.9.11 -- xorg-libxt=1.3.0 -- xorg-libxtst=1.2.3 -- xorg-recordproto=1.14.2 -- xorg-renderproto=0.11.1 -- xorg-xextproto=7.3.0 -- xorg-xf86vidmodeproto=2.3.1 -- xorg-xproto=7.0.31 -- xyzservices=2024.4.0 -- xz=5.2.6 -- yaml=0.2.5 -- yte=1.5.4 -- zict=3.0.0 -- zipp=3.17.0 -- zlib=1.2.13 -- zlib-ng=2.0.7 -- zstd=1.5.6 -- pip: - - highspy==1.5.3 - - oauthlib==3.2.2 - - requests-oauthlib==1.3.1 - - snakemake-executor-plugin-cluster-generic==1.0.9 - - snakemake-executor-plugin-slurm==0.5.1 - - snakemake-executor-plugin-slurm-jobstep==0.2.1 - - snakemake-storage-plugin-http==0.2.3 - - tsam==2.3.1 - - tabula-py=2.9.3 +prefix: /home/fneum/miniconda3/envs/pypsa-eur-20240812 diff --git a/rules/build_sector.smk b/rules/build_sector.smk old mode 100644 new mode 100755 index ec7fcd0c..54bbe42e --- a/rules/build_sector.smk +++ b/rules/build_sector.smk @@ -212,17 +212,72 @@ rule build_temperature_profiles: "../scripts/build_temperature_profiles.py" +rule build_central_heating_temperature_profiles: + params: + max_forward_temperature_central_heating=config_provider( + "sector", + "district_heating", + "supply_temperature_approximation", + "max_forward_temperature", + ), + min_forward_temperature_central_heating=config_provider( + "sector", + "district_heating", + "supply_temperature_approximation", + "min_forward_temperature", + ), + return_temperature_central_heating=config_provider( + "sector", + "district_heating", + "supply_temperature_approximation", + "return_temperature", + ), + snapshots=config_provider("snapshots"), + lower_threshold_ambient_temperature=config_provider( + "sector", + "district_heating", + "supply_temperature_approximation", + "lower_threshold_ambient_temperature", + ), + upper_threshold_ambient_temperature=config_provider( + "sector", + "district_heating", + "supply_temperature_approximation", + "upper_threshold_ambient_temperature", + ), + rolling_window_ambient_temperature=config_provider( + "sector", + "district_heating", + "supply_temperature_approximation", + "rolling_window_ambient_temperature", + ), + input: + temp_air_total=resources("temp_air_total_elec_s{simpl}_{clusters}.nc"), + regions_onshore=resources("regions_onshore_elec_s{simpl}_{clusters}.geojson"), + output: + central_heating_forward_temperature_profiles=resources( + "central_heating_forward_temperature_profiles_elec_s{simpl}_{clusters}.nc" + ), + central_heating_return_temperature_profiles=resources( + "central_heating_return_temperature_profiles_elec_s{simpl}_{clusters}.nc" + ), + resources: + mem_mb=20000, + log: + logs("build_central_heating_temperature_profiles_s{simpl}_{clusters}.log"), + benchmark: + benchmarks("build_central_heating_temperature_profiles/s{simpl}_{clusters}") + conda: + "../envs/environment.yaml" + script: + "../scripts/build_central_heating_temperature_profiles/run.py" + + rule build_cop_profiles: params: heat_pump_sink_T_decentral_heating=config_provider( "sector", "heat_pump_sink_T_individual_heating" ), - forward_temperature_central_heating=config_provider( - "sector", "district_heating", "forward_temperature" - ), - return_temperature_central_heating=config_provider( - "sector", "district_heating", "return_temperature" - ), heat_source_cooling_central_heating=config_provider( "sector", "district_heating", "heat_source_cooling" ), @@ -232,6 +287,12 @@ rule build_cop_profiles: heat_pump_sources=config_provider("sector", "heat_pump_sources"), snapshots=config_provider("snapshots"), input: + central_heating_forward_temperature_profiles=resources( + "central_heating_forward_temperature_profiles_elec_s{simpl}_{clusters}.nc" + ), + central_heating_return_temperature_profiles=resources( + "central_heating_return_temperature_profiles_elec_s{simpl}_{clusters}.nc" + ), temp_soil_total=resources("temp_soil_total_elec_s{simpl}_{clusters}.nc"), temp_air_total=resources("temp_air_total_elec_s{simpl}_{clusters}.nc"), regions_onshore=resources("regions_onshore_elec_s{simpl}_{clusters}.geojson"), @@ -576,10 +637,14 @@ rule build_industrial_distribution_key: input: regions_onshore=resources("regions_onshore_elec_s{simpl}_{clusters}.geojson"), clustered_pop_layout=resources("pop_layout_elec_s{simpl}_{clusters}.csv"), - hotmaps_industrial_database=storage( + hotmaps=storage( "https://gitlab.com/hotmaps/industrial_sites/industrial_sites_Industrial_Database/-/raw/master/data/Industrial_Database.csv", keep_local=True, ), + gem_gspt="data/gem/Global-Steel-Plant-Tracker-April-2024-Standard-Copy-V1.xlsx", + ammonia="data/ammonia_plants.csv", + cement_supplement="data/cement-plants-noneu.csv", + refineries_supplement="data/refineries-noneu.csv", output: industrial_distribution_key=resources( "industrial_distribution_key_elec_s{simpl}_{clusters}.csv" diff --git a/rules/retrieve.smk b/rules/retrieve.smk index 5c4af68e..67b91b99 100644 --- a/rules/retrieve.smk +++ b/rules/retrieve.smk @@ -312,10 +312,25 @@ if config["enable"]["retrieve"]: run: import requests - response = requests.get( - "https://globalenergymonitor.org/wp-content/uploads/2024/05/Europe-Gas-Tracker-2024-05.xlsx", - headers={"User-Agent": "Mozilla/5.0"}, - ) + # mirror of https://globalenergymonitor.org/wp-content/uploads/2024/05/Europe-Gas-Tracker-2024-05.xlsx + url = "https://tubcloud.tu-berlin.de/s/LMBJQCsN6Ez5cN2/download/Europe-Gas-Tracker-2024-05.xlsx" + response = requests.get(url) + with open(output[0], "wb") as f: + f.write(response.content) + + + +if config["enable"]["retrieve"]: + + rule retrieve_gem_steel_plant_tracker: + output: + "data/gem/Global-Steel-Plant-Tracker-April-2024-Standard-Copy-V1.xlsx", + run: + import requests + + # mirror or https://globalenergymonitor.org/wp-content/uploads/2024/04/Global-Steel-Plant-Tracker-April-2024-Standard-Copy-V1.xlsx + url = "https://tubcloud.tu-berlin.de/s/Aqebo3rrQZWKGsG/download/Global-Steel-Plant-Tracker-April-2024-Standard-Copy-V1.xlsx" + response = requests.get(url) with open(output[0], "wb") as f: f.write(response.content) diff --git a/rules/solve_electricity.smk b/rules/solve_electricity.smk index 389687a0..e2dbe42e 100644 --- a/rules/solve_electricity.smk +++ b/rules/solve_electricity.smk @@ -41,6 +41,13 @@ rule solve_network: rule solve_operations_network: params: options=config_provider("solving", "options"), + solving=config_provider("solving"), + foresight=config_provider("foresight"), + planning_horizons=config_provider("scenario", "planning_horizons"), + co2_sequestration_potential=config_provider( + "sector", "co2_sequestration_potential", default=200 + ), + custom_extra_functionality=input_custom_extra_functionality, input: network=RESULTS + "networks/elec_s{simpl}_{clusters}_ec_l{ll}_{opts}.nc", output: diff --git a/scripts/_helpers.py b/scripts/_helpers.py index a3b77c1c..f79d9258 100644 --- a/scripts/_helpers.py +++ b/scripts/_helpers.py @@ -507,7 +507,8 @@ def generate_periodic_profiles(dt_index, nodes, weekly_profile, localize=None): week_df = pd.DataFrame(index=dt_index, columns=nodes) for node in nodes: - timezone = pytz.timezone(pytz.country_timezones[node[:2]][0]) + ct = node[:2] if node[:2] != "XK" else "RS" + timezone = pytz.timezone(pytz.country_timezones[ct][0]) tz_dt_index = dt_index.tz_convert(timezone) week_df[node] = [24 * dt.weekday() + dt.hour for dt in tz_dt_index] week_df[node] = week_df[node].map(weekly_profile) diff --git a/scripts/build_biomass_potentials.py b/scripts/build_biomass_potentials.py old mode 100644 new mode 100755 index b69fcfbe..a3c51292 --- a/scripts/build_biomass_potentials.py +++ b/scripts/build_biomass_potentials.py @@ -88,9 +88,11 @@ def build_nuts_population_data(year=2013): pop = pd.concat([pop, pd.concat(swiss)]).to_frame("total") # add missing manually - pop["AL"] = 2893 - pop["BA"] = 3871 - pop["RS"] = 7210 + pop["AL"] = 2778 + pop["BA"] = 3234 + pop["RS"] = 6664 + pop["ME"] = 617 + pop["XK"] = 1587 pop["ct"] = pop.index.str[:2] @@ -149,10 +151,6 @@ def enspreso_biomass_potentials(year=2020, scenario="ENS_Low"): bio = dff.groupby(["NUTS2", "commodity"]).potential.sum().unstack() - # currently Serbia and Kosovo not split, so aggregate - bio.loc["RS"] += bio.loc["XK"] - bio.drop("XK", inplace=True) - return bio @@ -199,7 +197,7 @@ def build_nuts2_shapes(): ) countries = gpd.read_file(snakemake.input.country_shapes).set_index("name") - missing_iso2 = countries.index.intersection(["AL", "RS", "BA"]) + missing_iso2 = countries.index.intersection(["AL", "RS", "XK", "BA"]) missing = countries.loc[missing_iso2] nuts2.rename(index={"ME00": "ME", "MK00": "MK"}, inplace=True) @@ -332,7 +330,7 @@ def add_unsustainable_potentials(df): ) share_sus = params.get("share_sustainable_potential_available").get(investment_year) - df *= share_sus + df.loc[df_wo_ch.index] *= share_sus df = df.join(df_wo_ch.filter(like="unsustainable")).fillna(0) @@ -347,8 +345,8 @@ if __name__ == "__main__": snakemake = mock_snakemake( "build_biomass_potentials", simpl="", - clusters="37", - planning_horizons=2020, + clusters="38", + planning_horizons=2050, ) configure_logging(snakemake) diff --git a/scripts/build_central_heating_temperature_profiles/central_heating_temperature_approximator.py b/scripts/build_central_heating_temperature_profiles/central_heating_temperature_approximator.py new file mode 100644 index 00000000..67f2c019 --- /dev/null +++ b/scripts/build_central_heating_temperature_profiles/central_heating_temperature_approximator.py @@ -0,0 +1,227 @@ +# -*- coding: utf-8 -*- +# SPDX-FileCopyrightText: : 2020-2024 The PyPSA-Eur Authors +# +# SPDX-License-Identifier: MIT + +import pandas as pd +import xarray as xr + + +class CentralHeatingTemperatureApproximator: + """ + A class to approximate central heating temperatures based on ambient + temperature. + + Attributes + ---------- + ambient_temperature : xr.DataArray + The ambient temperature data. + max_forward_temperature : xr.DataArray + The maximum forward temperature. + min_forward_temperature : xr.DataArray + The minimum forward temperature. + fixed_return_temperature : xr.DataArray + The fixed return temperature. + lower_threshold_ambient_temperature : float + Forward temperature is `max_forward_temperature` for ambient temperatures lower-or-equal this threshold. + upper_threshold_ambient_temperature : float + Forward temperature is `min_forward_temperature` for ambient temperatures higher-or-equal this threshold. + """ + + def __init__( + self, + ambient_temperature: xr.DataArray, + max_forward_temperature: float, + min_forward_temperature: float, + fixed_return_temperature: float, + lower_threshold_ambient_temperature: float, + upper_threshold_ambient_temperature: float, + rolling_window_ambient_temperature: int, + ) -> None: + """ + Initialize the CentralHeatingTemperatureApproximator. + + Parameters + ---------- + ambient_temperature : xr.DataArray + The ambient temperature data. + max_forward_temperature : xr.DataArray + The maximum forward temperature. + min_forward_temperature : xr.DataArray + The minimum forward temperature. + fixed_return_temperature : xr.DataArray + The fixed return temperature. + lower_threshold_ambient_temperature : float + Forward temperature is `max_forward_temperature` for ambient temperatures lower-or-equal this threshold. + upper_threshold_ambient_temperature : float + Forward temperature is `min_forward_temperature` for ambient temperatures higher-or-equal this threshold. + rolling_window_ambient_temperature : int + Rolling window size for averaging ambient temperature. + """ + + if any(max_forward_temperature < min_forward_temperature): + raise ValueError( + "max_forward_temperature must be greater than min_forward_temperature" + ) + if any(min_forward_temperature < fixed_return_temperature): + raise ValueError( + "min_forward_temperature must be greater than fixed_return_temperature" + ) + self._ambient_temperature = ambient_temperature + self.max_forward_temperature = max_forward_temperature + self.min_forward_temperature = min_forward_temperature + self.fixed_return_temperature = fixed_return_temperature + self.lower_threshold_ambient_temperature = lower_threshold_ambient_temperature + self.upper_threshold_ambient_temperature = upper_threshold_ambient_temperature + self.rolling_window_ambient_temperature = rolling_window_ambient_temperature + + def ambient_temperature_rolling_mean(self) -> xr.DataArray: + """ + Property to get ambient temperature. + + Returns + ------- + xr.DataArray + Rolling mean of ambient temperature input. + """ + # bfill to avoid NAs in the beginning + return ( + self._ambient_temperature.rolling( + time=self.rolling_window_ambient_temperature + ) + .mean(skip_na=True) + .bfill(dim="time") + ) + + @property + def forward_temperature(self) -> xr.DataArray: + """ + Property to get dynamic forward temperature. + + Returns + ------- + xr.DataArray + Dynamic forward temperatures + """ + return self._approximate_forward_temperature() + + @property + def return_temperature(self) -> float: + """ + Property to get return temperature. + + Returns + ------- + float + Return temperature. + """ + return self._approximate_return_temperature() + + def _approximate_forward_temperature(self) -> xr.DataArray: + """ + Approximate dynamic forward temperature based on reference curve. Adapted from [Pieper et al. (2019)](https://doi.org/10.1016/j.energy.2019.03.165). + + Returns + ------- + xr.DataArray + Dynamic forward temperatures. + """ + + forward_temperature = xr.where( + self.ambient_temperature_rolling_mean() + <= self.lower_threshold_ambient_temperature, + self.max_forward_temperature, + xr.where( + self.ambient_temperature_rolling_mean() + >= self.upper_threshold_ambient_temperature, + self.min_forward_temperature, + self.min_forward_temperature + + (self.max_forward_temperature - self.min_forward_temperature) + * ( + self.upper_threshold_ambient_temperature + - self.ambient_temperature_rolling_mean() + ) + / ( + self.upper_threshold_ambient_temperature + - self.lower_threshold_ambient_temperature + ), + ), + ) + return forward_temperature + + def _approximate_return_temperature(self) -> float: + """ + Approximate return temperature. + + Returns + ------- + float + Return temperature. + """ + return self.fixed_return_temperature + + @property + def forward_temperature(self) -> xr.DataArray: + """ + Property to get dynamic forward temperature. + + Returns + ------- + xr.DataArray + Dynamic forward temperatures. + """ + return self._approximate_forward_temperature() + + @property + def return_temperature(self) -> float: + """ + Property to get return temperature. + + Returns + ------- + float + Return temperature. + """ + return self._approximate_return_temperature() + + def _approximate_forward_temperature(self) -> xr.DataArray: + """ + Approximate dynamic forward temperature. + + Returns + ------- + xr.DataArray + Dynamic forward temperatures. + """ + forward_temperature = xr.where( + self.ambient_temperature_rolling_mean() + <= self.lower_threshold_ambient_temperature, + self.max_forward_temperature, + xr.where( + self.ambient_temperature_rolling_mean() + >= self.upper_threshold_ambient_temperature, + self.min_forward_temperature, + self.min_forward_temperature + + (self.max_forward_temperature - self.min_forward_temperature) + * ( + self.upper_threshold_ambient_temperature + - self.ambient_temperature_rolling_mean() + ) + / ( + self.upper_threshold_ambient_temperature + - self.lower_threshold_ambient_temperature + ), + ), + ) + return forward_temperature + + def _approximate_return_temperature(self) -> float: + """ + Approximate return temperature. + + Returns + ------- + float + Return temperature. + """ + return self.fixed_return_temperature diff --git a/scripts/build_central_heating_temperature_profiles/run.py b/scripts/build_central_heating_temperature_profiles/run.py new file mode 100644 index 00000000..feb4ab4f --- /dev/null +++ b/scripts/build_central_heating_temperature_profiles/run.py @@ -0,0 +1,192 @@ +# -*- coding: utf-8 -*- +# SPDX-FileCopyrightText: : 2020-2024 The PyPSA-Eur Authors +# +# SPDX-License-Identifier: MIT +""" +Approximate district heating forward and return temperature profiles based on +ambient temperature. The method is based on a reference curve from Pieper et +al. 2019, where for ambient temperatures below 0C, the highest possible forward +temperature is assumed and vice versa for temperatures above 10C. Between these +threshold levels, forward temperatures are linearly interpolated. + +By default, `max_forward_temperature` from Euroheat DHC Market Outlook 2024 is used; `min_forward_temperature` and `return_temperature` for Germany is used from AGFW-Hauptbericht 2022. +`min_forward_temperature` and `return_temperature` for other countries are extrapolated based on the ratio between `max_forward_temperature` and `min_forward_temperature` and `return_temperature` for those countries not missing (by default only Germany). + +Relevant Settings +----------------- + +.. code:: yaml + sector: + district_heating: + max_forward_temperature: + min_forward_temperature: + return_temperature: +Inputs +------ +- `resources//temp_air_total`: Air temperature + +Outputs +------- +- `resources//central_heating_temperature_profiles.nc`: + +References +---------- +- Pieper, et al. (2019): "Assessment of a combination of three heat sources for heat pumps to supply district heating" (https://doi.org/10.1016/j.energy.2019.03.165). +- AGFW (2022): "Hauptbericht 2022" (https://www.agfw.de/zahlen-und-statistiken/agfw-hauptbericht) +""" + +import sys + +import geopandas as gpd +import numpy as np +import pandas as pd +import xarray as xr +from _helpers import set_scenario_config +from central_heating_temperature_approximator import ( + CentralHeatingTemperatureApproximator, +) + + +def extrapolate_missing_supply_temperatures_by_country( + extrapolate_from: dict, extrapolate_to: dict +) -> xr.DataArray: + """ + Extrapolates missing supply temperatures by country. + + Parameters: + extrapolate_from (dict): A dictionary containing supply temperatures to extrapolate from. Should contain all countries. + extrapolate_to (dict): A dictionary containing supply temperatures to extrapolate to. Where `country` is present, average ratio between `extrapolate_to[country]` and `extrapolate_from[country]` is applied to all countries for which `country` is not present in `extrapolate_from.keys()` to infer ratio for extrapolation. + + Returns: + xr.DataArray: A DataArray containing the extrapolated supply temperatures. + """ + + if not all([key in extrapolate_from.keys() for key in extrapolate_to.keys()]): + raise ValueError( + "Not all countries in extrapolate_to are present in extrapolate_from." + ) + # average ratio between extrapolate_from and extrapolate_to for those countries that are in both dictionaries + extrapolation_ratio = np.mean( + [extrapolate_to[key] / extrapolate_from[key] for key in extrapolate_to.keys()] + ) + + # apply extrapolation ratio to all keys missing in extrapolate_to + return { + key: ( + extrapolate_to[key] + if key in extrapolate_to.keys() + else extrapolate_from[key] * extrapolation_ratio + ) + for key in extrapolate_from.keys() + } + + +def get_country_from_node_name(node_name: str) -> str: + """ + Extracts the country code from a given node name. + + Parameters: + node_name (str): The name of the node. + + Returns: + str: The country code extracted from the node name. + """ + return node_name[:2] + + +def map_temperature_dict_to_onshore_regions( + supply_temperature_by_country: dict, + regions_onshore: pd.Index, +) -> xr.DataArray: + """ + Map dictionary of temperatures to onshore regions. + + Missing values are replaced by the mean of all values. + + Parameters: + ---------- + supply_temperature_by_country : dictionary + Dictionary with temperatures as values and country keys as keys. + regions_onshore : pd.Index + Names of onshore regions + + Returns: + ------- + xr.DataArray + The dictionary values mapped to onshore regions with onshore regions as coordinates. + """ + return xr.DataArray( + [ + ( + supply_temperature_by_country[get_country_from_node_name(node_name)] + if get_country_from_node_name(node_name) + in supply_temperature_by_country.keys() + else np.mean(list(supply_temperature_by_country.values())) + ) + for node_name in regions_onshore.values + ], + dims=["name"], + coords={"name": regions_onshore}, + ) + + +if __name__ == "__main__": + if "snakemake" not in globals(): + from _helpers import mock_snakemake + + snakemake = mock_snakemake( + "build_cop_profiles", + simpl="", + clusters=48, + ) + + set_scenario_config(snakemake) + + max_forward_temperature = snakemake.params.max_forward_temperature_central_heating + min_forward_temperature = extrapolate_missing_supply_temperatures_by_country( + extrapolate_from=max_forward_temperature, + extrapolate_to=snakemake.params.min_forward_temperature_central_heating, + ) + return_temperature = extrapolate_missing_supply_temperatures_by_country( + extrapolate_from=max_forward_temperature, + extrapolate_to=snakemake.params.return_temperature_central_heating, + ) + + # map forward and return temperatures specified on country-level to onshore regions + regions_onshore = gpd.read_file(snakemake.input.regions_onshore)["name"] + snapshots = pd.date_range(freq="h", **snakemake.params.snapshots) + max_forward_temperature_central_heating_by_node_and_time: xr.DataArray = ( + map_temperature_dict_to_onshore_regions( + supply_temperature_by_country=max_forward_temperature, + regions_onshore=regions_onshore, + ) + ) + min_forward_temperature_central_heating_by_node_and_time: xr.DataArray = ( + map_temperature_dict_to_onshore_regions( + supply_temperature_by_country=min_forward_temperature, + regions_onshore=regions_onshore, + ) + ) + return_temperature_central_heating_by_node_and_time: xr.DataArray = ( + map_temperature_dict_to_onshore_regions( + supply_temperature_by_country=return_temperature, + regions_onshore=regions_onshore, + ) + ) + + central_heating_temperature_approximator = CentralHeatingTemperatureApproximator( + ambient_temperature=xr.open_dataarray(snakemake.input.temp_air_total), + max_forward_temperature=max_forward_temperature_central_heating_by_node_and_time, + min_forward_temperature=min_forward_temperature_central_heating_by_node_and_time, + fixed_return_temperature=return_temperature_central_heating_by_node_and_time, + lower_threshold_ambient_temperature=snakemake.params.lower_threshold_ambient_temperature, + upper_threshold_ambient_temperature=snakemake.params.upper_threshold_ambient_temperature, + rolling_window_ambient_temperature=snakemake.params.rolling_window_ambient_temperature, + ) + + central_heating_temperature_approximator.forward_temperature.to_netcdf( + snakemake.output.central_heating_forward_temperature_profiles + ) + central_heating_temperature_approximator.return_temperature.to_netcdf( + snakemake.output.central_heating_return_temperature_profiles + ) diff --git a/scripts/build_cop_profiles/run.py b/scripts/build_cop_profiles/run.py index b4ec3e43..d1faf1b1 100644 --- a/scripts/build_cop_profiles/run.py +++ b/scripts/build_cop_profiles/run.py @@ -53,47 +53,6 @@ from DecentralHeatingCopApproximator import DecentralHeatingCopApproximator from scripts.definitions.heat_system_type import HeatSystemType -def map_temperature_dict_to_onshore_regions( - supply_temperature_by_country: dict, - regions_onshore: pd.Index, - snapshots: pd.DatetimeIndex, -) -> xr.DataArray: - """ - Map dictionary of temperatures to onshore regions. - - Parameters: - ---------- - supply_temperature_by_country : dictionary - Dictionary with temperatures as values and country keys as keys. One key must be named "default" - regions_onshore : pd.Index - Names of onshore regions - snapshots : pd.DatetimeIndex - Time stamps - - Returns: - ------- - xr.DataArray - The dictionary values mapped to onshore regions with onshore regions as coordinates. - """ - return xr.DataArray( - [ - [ - ( - supply_temperature_by_country[get_country_from_node_name(node_name)] - if get_country_from_node_name(node_name) - in supply_temperature_by_country.keys() - else supply_temperature_by_country["default"] - ) - for node_name in regions_onshore.values - ] - # pass both nodes and snapshots as dimensions to preserve correct data structure - for _ in snapshots - ], - dims=["time", "name"], - coords={"time": snapshots, "name": regions_onshore}, - ) - - def get_cop( heat_system_type: str, heat_source: str, @@ -154,20 +113,13 @@ if __name__ == "__main__": # map forward and return temperatures specified on country-level to onshore regions regions_onshore = gpd.read_file(snakemake.input.regions_onshore)["name"] snapshots = pd.date_range(freq="h", **snakemake.params.snapshots) - forward_temperature_central_heating_by_node_and_time: xr.DataArray = ( - map_temperature_dict_to_onshore_regions( - supply_temperature_by_country=snakemake.params.forward_temperature_central_heating, - regions_onshore=regions_onshore, - snapshots=snapshots, - ) + central_heating_forward_temperature: xr.DataArray = xr.open_dataarray( + snakemake.input.central_heating_forward_temperature_profiles ) - return_temperature_central_heating_by_node_and_time: xr.DataArray = ( - map_temperature_dict_to_onshore_regions( - supply_temperature_by_country=snakemake.params.return_temperature_central_heating, - regions_onshore=regions_onshore, - snapshots=snapshots, - ) + central_heating_return_temperature: xr.DataArray = xr.open_dataarray( + snakemake.input.central_heating_return_temperature_profiles ) + cop_all_system_types = [] for heat_system_type, heat_sources in snakemake.params.heat_pump_sources.items(): cop_this_system_type = [] @@ -179,8 +131,8 @@ if __name__ == "__main__": heat_system_type=heat_system_type, heat_source=heat_source, source_inlet_temperature_celsius=source_inlet_temperature_celsius, - forward_temperature_by_node_and_time=forward_temperature_central_heating_by_node_and_time, - return_temperature_by_node_and_time=return_temperature_central_heating_by_node_and_time, + forward_temperature_by_node_and_time=central_heating_forward_temperature, + return_temperature_by_node_and_time=central_heating_return_temperature, ) cop_this_system_type.append(cop_da) cop_all_system_types.append( diff --git a/scripts/build_cutout.py b/scripts/build_cutout.py index e8d6207c..015eb66a 100644 --- a/scripts/build_cutout.py +++ b/scripts/build_cutout.py @@ -37,7 +37,7 @@ Outputs ------- - ``cutouts/{cutout}``: weather data from either the `ERA5 `_ - reanalysis weather dataset or `SARAH-2 `_ + reanalysis weather dataset or `SARAH-3 `_ satellite-based historic weather data with the following structure: **ERA5 cutout:** @@ -80,7 +80,7 @@ Outputs .. image:: img/era5.png :scale: 40 % -A **SARAH-2 cutout** can be used to amend the fields ``temperature``, ``influx_toa``, ``influx_direct``, ``albedo``, +A **SARAH-3 cutout** can be used to amend the fields ``temperature``, ``influx_toa``, ``influx_direct``, ``albedo``, ``influx_diffuse`` of ERA5 using satellite-based radiation observations. .. image:: img/sarah.png diff --git a/scripts/build_electricity_demand.py b/scripts/build_electricity_demand.py index 622fdafa..d3334ec8 100755 --- a/scripts/build_electricity_demand.py +++ b/scripts/build_electricity_demand.py @@ -192,9 +192,9 @@ def manual_adjustment(load, fn_load, countries): if "ME" in load: load["BA"] = load.HR * (11.0 / 16.2) - if ("KV" not in load or load.KV.isnull().values.all()) and "KV" in countries: + if "XK" not in load and "XK" in countries: if "RS" in load: - load["KV"] = load["RS"] * (4.8 / 27.0) + load["XK"] = load["RS"] * (4.8 / 27.0) copy_timeslice(load, "GR", "2015-08-11 21:00", "2015-08-15 20:00", Delta(weeks=1)) copy_timeslice(load, "AT", "2018-12-31 22:00", "2019-01-01 22:00", Delta(days=2)) @@ -311,8 +311,8 @@ if __name__ == "__main__": logger.info("Supplement missing data with synthetic data.") fn = snakemake.input.synthetic synthetic_load = pd.read_csv(fn, index_col=0, parse_dates=True) - # "UA" does not appear in synthetic load data - countries = list(set(countries) - set(["UA", "MD"])) + # UA, MD, XK do not appear in synthetic load data + countries = list(set(countries) - set(["UA", "MD", "XK"])) synthetic_load = synthetic_load.loc[snapshots, countries] load = load.combine_first(synthetic_load) diff --git a/scripts/build_energy_totals.py b/scripts/build_energy_totals.py index a4064af6..3d37a8ee 100644 --- a/scripts/build_energy_totals.py +++ b/scripts/build_energy_totals.py @@ -1147,7 +1147,7 @@ def build_co2_totals( co2 = eea_co2.reindex(countries) for ct in pd.Index(countries).intersection( - ["BA", "RS", "AL", "ME", "MK", "UA", "MD"] + ["BA", "RS", "XK", "AL", "ME", "MK", "UA", "MD"] ): mappings = { "electricity": (ct, "+", "Electricity & heat generation", np.nan), @@ -1500,10 +1500,10 @@ def update_residential_from_eurostat(energy: pd.DataFrame) -> pd.DataFrame: for nrg_name, (code, siec) in nrg_type.items(): # Select energy balance type, rename columns and countries to match IDEES data, - # convert TJ to TWh, and drop XK data already since included in RS data + # convert TJ to TWh col_to_rename = {"geo": "country", "TIME_PERIOD": "year", "OBS_VALUE": nrg_name} idx_to_rename = {v: k for k, v in idees_rename.items()} - drop_geo = ["EU27_2020", "EA20", "XK"] + drop_geo = ["EU27_2020", "EA20"] nrg_data = eurostat_households.query( "nrg_bal == @code and siec == @siec and geo not in @drop_geo and OBS_VALUE > 0" ).copy() diff --git a/scripts/build_hydro_profile.py b/scripts/build_hydro_profile.py index 6a0315c7..2d0d2e52 100644 --- a/scripts/build_hydro_profile.py +++ b/scripts/build_hydro_profile.py @@ -82,7 +82,7 @@ def get_eia_annual_hydro_generation(fn, countries, capacities=False): countries=["Czechia", "Slovakia"], start=1980, end=1992 ), "Former Serbia and Montenegro": dict( - countries=["Serbia", "Montenegro"], start=1992, end=2005 + countries=["Serbia", "Montenegro", "Kosovo"], start=1992, end=2005 ), "Former Yugoslavia": dict( countries=[ @@ -90,6 +90,7 @@ def get_eia_annual_hydro_generation(fn, countries, capacities=False): "Croatia", "Bosnia and Herzegovina", "Serbia", + "Kosovo", "Montenegro", "North Macedonia", ], @@ -111,9 +112,8 @@ def get_eia_annual_hydro_generation(fn, countries, capacities=False): ) df.loc["Germany"] = df.filter(like="Germany", axis=0).sum() - df.loc["Serbia"] += df.loc["Kosovo"].fillna(0.0) df = df.loc[~df.index.str.contains("Former")] - df.drop(["Europe", "Germany, West", "Germany, East", "Kosovo"], inplace=True) + df.drop(["Europe", "Germany, West", "Germany, East"], inplace=True) df.index = cc.convert(df.index, to="iso2") df.index.name = "countries" @@ -122,6 +122,8 @@ def get_eia_annual_hydro_generation(fn, countries, capacities=False): factor = 1e3 if capacities else 1e6 df = df.T[countries] * factor + df.ffill(axis=0, inplace=True) + return df @@ -129,7 +131,7 @@ def correct_eia_stats_by_capacity(eia_stats, fn, countries, baseyear=2019): cap = get_eia_annual_hydro_generation(fn, countries, capacities=True) ratio = cap / cap.loc[baseyear] eia_stats_corrected = eia_stats / ratio - to_keep = ["AL", "AT", "CH", "DE", "GB", "NL", "RS", "RO", "SK"] + to_keep = ["AL", "AT", "CH", "DE", "GB", "NL", "RS", "XK", "RO", "SK"] to_correct = eia_stats_corrected.columns.difference(to_keep) eia_stats.loc[:, to_correct] = eia_stats_corrected.loc[:, to_correct] diff --git a/scripts/build_industrial_distribution_key.py b/scripts/build_industrial_distribution_key.py index e6654728..76a0e6d6 100644 --- a/scripts/build_industrial_distribution_key.py +++ b/scripts/build_industrial_distribution_key.py @@ -100,7 +100,7 @@ def prepare_hotmaps_database(regions): """ Load hotmaps database of industrial sites and map onto bus regions. """ - df = pd.read_csv(snakemake.input.hotmaps_industrial_database, sep=";", index_col=0) + df = pd.read_csv(snakemake.input.hotmaps, sep=";", index_col=0) df[["srid", "coordinates"]] = df.geom.str.split(";", expand=True) @@ -133,7 +133,97 @@ def prepare_hotmaps_database(regions): return gdf -def build_nodal_distribution_key(hotmaps, regions, countries): +def prepare_gem_database(regions): + """ + Load GEM database of steel plants and map onto bus regions. + """ + + df = pd.read_excel( + snakemake.input.gem_gspt, + sheet_name="Steel Plants", + na_values=["N/A", "unknown", ">0"], + ).query("Region == 'Europe'") + + df["Retired Date"] = pd.to_numeric( + df["Retired Date"].combine_first(df["Idled Date"]), errors="coerce" + ) + df["Start date"] = pd.to_numeric( + df["Start date"].str.split("-").str[0], errors="coerce" + ) + + latlon = ( + df["Coordinates"] + .str.split(", ", expand=True) + .rename(columns={0: "lat", 1: "lon"}) + ) + geometry = gpd.points_from_xy(latlon["lon"], latlon["lat"]) + gdf = gpd.GeoDataFrame(df, geometry=geometry, crs="EPSG:4326") + + gdf = gpd.sjoin(gdf, regions, how="inner", predicate="within") + + gdf.rename(columns={"name": "bus"}, inplace=True) + gdf["country"] = gdf.bus.str[:2] + + return gdf + + +def prepare_ammonia_database(regions): + """ + Load ammonia database of plants and map onto bus regions. + """ + df = pd.read_csv(snakemake.input.ammonia, index_col=0) + + geometry = gpd.points_from_xy(df.Longitude, df.Latitude) + gdf = gpd.GeoDataFrame(df, geometry=geometry, crs="EPSG:4326") + + gdf = gpd.sjoin(gdf, regions, how="inner", predicate="within") + + gdf.rename(columns={"name": "bus"}, inplace=True) + gdf["country"] = gdf.bus.str[:2] + + return gdf + + +def prepare_cement_supplement(regions): + """ + Load supplementary cement plants from non-EU-(NO-CH) and map onto bus + regions. + """ + + df = pd.read_csv(snakemake.input.cement_supplement, index_col=0) + + geometry = gpd.points_from_xy(df.Longitude, df.Latitude) + gdf = gpd.GeoDataFrame(df, geometry=geometry, crs="EPSG:4326") + + gdf = gpd.sjoin(gdf, regions, how="inner", predicate="within") + + gdf.rename(columns={"name": "bus"}, inplace=True) + gdf["country"] = gdf.bus.str[:2] + + return gdf + + +def prepare_refineries_supplement(regions): + """ + Load supplementary refineries from non-EU-(NO-CH) and map onto bus regions. + """ + + df = pd.read_csv(snakemake.input.refineries_supplement, index_col=0) + + geometry = gpd.points_from_xy(df.Longitude, df.Latitude) + gdf = gpd.GeoDataFrame(df, geometry=geometry, crs="EPSG:4326") + + gdf = gpd.sjoin(gdf, regions, how="inner", predicate="within") + + gdf.rename(columns={"name": "bus"}, inplace=True) + gdf["country"] = gdf.bus.str[:2] + + return gdf + + +def build_nodal_distribution_key( + hotmaps, gem, ammonia, cement, refineries, regions, countries +): """ Build nodal distribution keys for each sector. """ @@ -158,15 +248,137 @@ def build_nodal_distribution_key(hotmaps, regions, countries): if emissions.sum() == 0: key = pd.Series(1 / len(facilities), facilities.index) else: - # BEWARE: this is a strong assumption - emissions = emissions.fillna(emissions.mean()) + # assume 20% quantile for missing values + emissions = emissions.fillna(emissions.quantile(0.2)) key = emissions / emissions.sum() key = key.groupby(facilities.bus).sum().reindex(regions_ct, fill_value=0.0) + elif sector == "Cement" and country in cement.country.unique(): + facilities = cement.query("country == @country") + production = facilities["Cement [kt/a]"] + if production.sum() == 0: + key = pd.Series(1 / len(facilities), facilities.index) + else: + key = production / production.sum() + key = key.groupby(facilities.bus).sum().reindex(regions_ct, fill_value=0.0) + elif sector == "Refineries" and country in refineries.country.unique(): + facilities = refineries.query("country == @country") + production = facilities["Capacity [bbl/day]"] + if production.sum() == 0: + key = pd.Series(1 / len(facilities), facilities.index) + else: + key = production / production.sum() + key = key.groupby(facilities.bus).sum().reindex(regions_ct, fill_value=0.0) else: key = keys.loc[regions_ct, "population"] keys.loc[regions_ct, sector] = key + # add specific steel subsectors + steel_processes = ["EAF", "DRI + EAF", "Integrated steelworks"] + for process, country in product(steel_processes, countries): + regions_ct = regions.index[regions.index.str.contains(country)] + + facilities = gem.query("country == @country") + + if process == "EAF": + status_list = [ + "construction", + "operating", + "operating pre-retirement", + "retired", + ] + capacities = facilities.loc[ + facilities["Capacity operating status"].isin(status_list) + & ( + facilities["Retired Date"].isna() + | facilities["Retired Date"].gt(2025) + ), + "Nominal EAF steel capacity (ttpa)", + ].dropna() + elif process == "DRI + EAF": + status_list = [ + "construction", + "operating", + "operating pre-retirement", + "retired", + "announced", + ] + sel = [ + "Nominal BOF steel capacity (ttpa)", + "Nominal OHF steel capacity (ttpa)", + "Nominal iron capacity (ttpa)", + ] + status_filter = facilities["Capacity operating status"].isin(status_list) + retirement_filter = facilities["Retired Date"].isna() | facilities[ + "Retired Date" + ].gt(2030) + start_filter = ( + facilities["Start date"].isna() + & ~facilities["Capacity operating status"].eq("announced") + ) | facilities["Start date"].le(2030) + capacities = ( + facilities.loc[status_filter & retirement_filter & start_filter, sel] + .sum(axis=1) + .dropna() + ) + elif process == "Integrated steelworks": + status_list = [ + "construction", + "operating", + "operating pre-retirement", + "retired", + ] + sel = [ + "Nominal BOF steel capacity (ttpa)", + "Nominal OHF steel capacity (ttpa)", + ] + capacities = ( + facilities.loc[ + facilities["Capacity operating status"].isin(status_list) + & ( + facilities["Retired Date"].isna() + | facilities["Retired Date"].gt(2025) + ), + sel, + ] + .sum(axis=1) + .dropna() + ) + else: + raise ValueError(f"Unknown process {process}") + + if not capacities.empty: + if capacities.sum() == 0: + key = pd.Series(1 / len(capacities), capacities.index) + else: + key = capacities / capacities.sum() + buses = facilities.loc[capacities.index, "bus"] + key = key.groupby(buses).sum().reindex(regions_ct, fill_value=0.0) + else: + key = keys.loc[regions_ct, "population"] + + keys.loc[regions_ct, process] = key + + # add ammonia + for country in countries: + regions_ct = regions.index[regions.index.str.contains(country)] + + facilities = ammonia.query("country == @country") + + if not facilities.empty: + production = facilities["Ammonia [kt/a]"] + if production.sum() == 0: + key = pd.Series(1 / len(facilities), facilities.index) + else: + # assume 50% of the minimum production for missing values + production = production.fillna(0.5 * facilities["Ammonia [kt/a]"].min()) + key = production / production.sum() + key = key.groupby(facilities.bus).sum().reindex(regions_ct, fill_value=0.0) + else: + key = 0.0 + + keys.loc[regions_ct, "Ammonia"] = key + return keys @@ -188,6 +400,16 @@ if __name__ == "__main__": hotmaps = prepare_hotmaps_database(regions) - keys = build_nodal_distribution_key(hotmaps, regions, countries) + gem = prepare_gem_database(regions) + + ammonia = prepare_ammonia_database(regions) + + cement = prepare_cement_supplement(regions) + + refineries = prepare_refineries_supplement(regions) + + keys = build_nodal_distribution_key( + hotmaps, gem, ammonia, cement, refineries, regions, countries + ) keys.to_csv(snakemake.output.industrial_distribution_key) diff --git a/scripts/build_industrial_energy_demand_per_node_today.py b/scripts/build_industrial_energy_demand_per_node_today.py index aa9e9dff..fd7c281c 100644 --- a/scripts/build_industrial_energy_demand_per_node_today.py +++ b/scripts/build_industrial_energy_demand_per_node_today.py @@ -33,10 +33,10 @@ from _helpers import set_scenario_config # map JRC/our sectors to hotmaps sector, where mapping exist sector_mapping = { - "Electric arc": "Iron and steel", - "Integrated steelworks": "Iron and steel", - "DRI + Electric arc": "Iron and steel", - "Ammonia": "Chemical industry", + "Electric arc": "EAF", + "Integrated steelworks": "Integrated steelworks", + "DRI + Electric arc": "DRI + EAF", + "Ammonia": "Ammonia", "Basic chemicals (without ammonia)": "Chemical industry", "Other chemicals": "Chemical industry", "Pharmaceutical products etc.": "Chemical industry", diff --git a/scripts/build_industrial_production_per_country.py b/scripts/build_industrial_production_per_country.py index ccb4feca..b7f98d76 100644 --- a/scripts/build_industrial_production_per_country.py +++ b/scripts/build_industrial_production_per_country.py @@ -345,5 +345,7 @@ if __name__ == "__main__": separate_basic_chemicals(demand, year) + demand.fillna(0.0, inplace=True) + fn = snakemake.output.industrial_production_per_country demand.to_csv(fn, float_format="%.2f") diff --git a/scripts/build_industrial_production_per_node.py b/scripts/build_industrial_production_per_node.py index d3edfa45..862345e5 100644 --- a/scripts/build_industrial_production_per_node.py +++ b/scripts/build_industrial_production_per_node.py @@ -32,10 +32,10 @@ from _helpers import set_scenario_config # map JRC/our sectors to hotmaps sector, where mapping exist sector_mapping = { - "Electric arc": "Iron and steel", - "Integrated steelworks": "Iron and steel", - "DRI + Electric arc": "Iron and steel", - "Ammonia": "Chemical industry", + "Electric arc": "EAF", + "Integrated steelworks": "Integrated steelworks", + "DRI + Electric arc": "DRI + EAF", + "Ammonia": "Ammonia", "HVC": "Chemical industry", "HVC (mechanical recycling)": "Chemical industry", "HVC (chemical recycling)": "Chemical industry", diff --git a/scripts/build_population_layouts.py b/scripts/build_population_layouts.py index 4cabdc7c..b9af8d85 100644 --- a/scripts/build_population_layouts.py +++ b/scripts/build_population_layouts.py @@ -20,8 +20,6 @@ logger = logging.getLogger(__name__) cc = coco.CountryConverter() -coco.logging.getLogger().setLevel(coco.logging.CRITICAL) - if __name__ == "__main__": if "snakemake" not in globals(): from _helpers import mock_snakemake @@ -32,6 +30,7 @@ if __name__ == "__main__": configure_logging(snakemake) set_scenario_config(snakemake) + coco.logging.getLogger().setLevel(coco.logging.CRITICAL) cutout = atlite.Cutout(snakemake.input.cutout) @@ -56,6 +55,8 @@ if __name__ == "__main__": urban_fraction = ( urban_fraction.query("iso2 in @countries").set_index("iso2")["2019"].div(100) ) + if "XK" in countries: + urban_fraction["XK"] = urban_fraction["RS"] # population in each grid cell pop_cells = pd.Series(I.dot(nuts3["pop"])) diff --git a/scripts/build_retro_cost.py b/scripts/build_retro_cost.py index c6dd31cf..42144c1a 100755 --- a/scripts/build_retro_cost.py +++ b/scripts/build_retro_cost.py @@ -198,6 +198,7 @@ def prepare_building_stock_data(): "Iceland": "IS", "Montenegro": "ME", "Serbia": "RS", + "Kosovo": "XK", "Albania": "AL", "United Kingdom": "GB", "Bosnia and Herzegovina": "BA", @@ -1073,6 +1074,7 @@ if __name__ == "__main__": "AL": ["BG", "RO", "GR"], "BA": ["HR"], "RS": ["BG", "RO", "HR", "HU"], + "KV": ["RS"], "MK": ["BG", "GR"], "ME": ["BA", "AL", "RS", "HR"], "CH": ["SE", "DE"], diff --git a/scripts/build_shapes.py b/scripts/build_shapes.py index 4de5370a..2370f2ae 100644 --- a/scripts/build_shapes.py +++ b/scripts/build_shapes.py @@ -106,8 +106,6 @@ def _simplify_polys(polys, minarea=0.1, tolerance=None, filterremote=True): def countries(naturalearth, country_list): - if "RS" in country_list: - country_list.append("KV") df = gpd.read_file(naturalearth) @@ -116,15 +114,12 @@ def countries(naturalearth, country_list): df[x].where(lambda s: s != "-99") for x in ("ISO_A2", "WB_A2", "ADM0_A3") ) df["name"] = reduce(lambda x, y: x.fillna(y), fieldnames, next(fieldnames)).str[:2] + df.replace({"name": {"KV": "XK"}}, inplace=True) df = df.loc[ df.name.isin(country_list) & ((df["scalerank"] == 0) | (df["scalerank"] == 5)) ] s = df.set_index("name")["geometry"].map(_simplify_polys).set_crs(df.crs) - if "RS" in country_list: - s["RS"] = s["RS"].union(s.pop("KV")) - # cleanup shape union - s["RS"] = Polygon(s["RS"].exterior.coords) return s @@ -195,7 +190,9 @@ def nuts3(country_shapes, nuts3, nuts3pop, nuts3gdp, ch_cantons, ch_popgdp): df = df.join(pd.DataFrame(dict(pop=pop, gdp=gdp))) - df["country"] = df.index.to_series().str[:2].replace(dict(UK="GB", EL="GR")) + df["country"] = ( + df.index.to_series().str[:2].replace(dict(UK="GB", EL="GR", KV="XK")) + ) excludenuts = pd.Index( ( @@ -217,13 +214,18 @@ def nuts3(country_shapes, nuts3, nuts3pop, nuts3gdp, ch_cantons, ch_popgdp): "FR9", ) ) - excludecountry = pd.Index(("MT", "TR", "LI", "IS", "CY", "KV")) + excludecountry = pd.Index(("MT", "TR", "LI", "IS", "CY")) df = df.loc[df.index.difference(excludenuts)] df = df.loc[~df.country.isin(excludecountry)] manual = gpd.GeoDataFrame( - [["BA1", "BA", 3871.0], ["RS1", "RS", 7210.0], ["AL1", "AL", 2893.0]], + [ + ["BA1", "BA", 3234.0], + ["RS1", "RS", 6664.0], + ["AL1", "AL", 2778.0], + ["XK1", "XK", 1587.0], + ], columns=["NUTS_ID", "country", "pop"], geometry=gpd.GeoSeries(), crs=df.crs, @@ -234,7 +236,7 @@ def nuts3(country_shapes, nuts3, nuts3pop, nuts3gdp, ch_cantons, ch_popgdp): df = pd.concat([df, manual], sort=False) - df.loc["ME000", "pop"] = 650.0 + df.loc["ME000", "pop"] = 617.0 return df diff --git a/scripts/prepare_sector_network.py b/scripts/prepare_sector_network.py old mode 100644 new mode 100755 index 097f9bb5..d657d6fd --- a/scripts/prepare_sector_network.py +++ b/scripts/prepare_sector_network.py @@ -63,7 +63,8 @@ def define_spatial(nodes, options): if options.get("biomass_spatial", options["biomass_transport"]): spatial.biomass.nodes = nodes + " solid biomass" - spatial.biomass.bioliquids = nodes + " bioliquids" + spatial.biomass.nodes_unsustainable = nodes + " unsustainable solid biomass" + spatial.biomass.bioliquids = nodes + " unsustainable bioliquids" spatial.biomass.locations = nodes spatial.biomass.industry = nodes + " solid biomass for industry" spatial.biomass.industry_cc = nodes + " solid biomass for industry CC" @@ -71,6 +72,7 @@ def define_spatial(nodes, options): spatial.msw.locations = nodes else: spatial.biomass.nodes = ["EU solid biomass"] + spatial.biomass.nodes_unsustainable = ["EU unsustainable solid biomass"] spatial.biomass.bioliquids = ["EU unsustainable bioliquids"] spatial.biomass.locations = ["EU"] spatial.biomass.industry = ["solid biomass for industry"] @@ -281,7 +283,7 @@ def co2_emissions_year( eurostat = build_eurostat(input_eurostat, countries) - # this only affects the estimation of CO2 emissions for BA, RS, AL, ME, MK + # this only affects the estimation of CO2 emissions for BA, RS, AL, ME, MK, XK eurostat_co2 = build_eurostat_co2(eurostat, year) co2_totals = build_co2_totals(countries, eea_co2, eurostat_co2) @@ -573,12 +575,43 @@ def add_carrier_buses(n, carrier, nodes=None): fossils = ["coal", "gas", "oil", "lignite"] if options.get("fossil_fuels", True) and carrier in fossils: + suffix = "" + + if carrier == "oil" and cf_industry["oil_refining_emissions"] > 0: + + n.madd( + "Bus", + nodes + " primary", + location=location, + carrier=carrier + " primary", + unit=unit, + ) + + n.madd( + "Link", + nodes + " refining", + bus0=nodes + " primary", + bus1=nodes, + bus2="co2 atmosphere", + location=location, + carrier=carrier + " refining", + p_nom=1e6, + efficiency=1 + - ( + cf_industry["oil_refining_emissions"] + / costs.at[carrier, "CO2 intensity"] + ), + efficiency2=cf_industry["oil_refining_emissions"], + ) + + suffix = " primary" + n.madd( "Generator", - nodes, - bus=nodes, + nodes + suffix, + bus=nodes + suffix, p_nom_extendable=True, - carrier=carrier, + carrier=carrier + suffix, marginal_cost=costs.at[carrier, "fuel"], ) @@ -1849,8 +1882,6 @@ def add_heat(n: pypsa.Network, costs: pd.DataFrame, cop: xr.DataArray): heat_demand = build_heat_demand(n) - overdim_factor = options["overdimension_individual_heating"] - district_heat_info = pd.read_csv(snakemake.input.district_heat_share, index_col=0) dist_fraction = district_heat_info["district fraction of node"] urban_fraction = district_heat_info["urban fraction"] @@ -1879,6 +1910,9 @@ def add_heat(n: pypsa.Network, costs: pd.DataFrame, cop: xr.DataArray): HeatSystem ): # this loops through all heat systems defined in _entities.HeatSystem + overdim_factor = options["overdimension_heat_generators"][ + heat_system.central_or_decentral + ] if heat_system == HeatSystem.URBAN_CENTRAL: nodes = dist_fraction.index[dist_fraction > 0] else: @@ -2329,8 +2363,7 @@ def add_biomass(n, costs): if ( options["municipal_solid_waste"] and not options["industry"] - and cf_industry["waste_to_energy"] - or cf_industry["waste_to_energy_cc"] + and not (cf_industry["waste_to_energy"] or cf_industry["waste_to_energy_cc"]) ): logger.warning( "Flag municipal_solid_waste can be only used with industry " @@ -2350,12 +2383,9 @@ def add_biomass(n, costs): carrier="municipal solid waste", ) - e_max_pu = np.array( - len(spatial.msw.nodes) * [[1] * (len(n.snapshots) - 1) + [0]] - ).T - e_max_pu = pd.DataFrame( - e_max_pu, index=n.snapshots, columns=spatial.msw.nodes - ).astype(float) + e_max_pu = pd.DataFrame(1, index=n.snapshots, columns=spatial.msw.nodes) + e_max_pu.iloc[-1] = 0 + n.madd( "Store", spatial.msw.nodes, @@ -2470,14 +2500,23 @@ def add_biomass(n, costs): e_max_pu=e_max_pu, ) - e_max_pu = pd.DataFrame(1, index=n.snapshots, columns=spatial.biomass.nodes) + n.madd( + "Bus", + spatial.biomass.nodes_unsustainable, + location=spatial.biomass.locations, + carrier="unsustainable solid biomass", + unit="MWh_LHV", + ) + + e_max_pu = pd.DataFrame( + 1, index=n.snapshots, columns=spatial.biomass.nodes_unsustainable + ) e_max_pu.iloc[-1] = 0 n.madd( "Store", - spatial.biomass.nodes, - suffix=" unsustainable", - bus=spatial.biomass.nodes, + spatial.biomass.nodes_unsustainable, + bus=spatial.biomass.nodes_unsustainable, carrier="unsustainable solid biomass", e_nom=unsustainable_solid_biomass_potentials_spatial, marginal_cost=costs.at["fuelwood", "fuel"], @@ -2486,6 +2525,16 @@ def add_biomass(n, costs): e_max_pu=e_max_pu, ) + n.madd( + "Link", + spatial.biomass.nodes_unsustainable, + bus0=spatial.biomass.nodes_unsustainable, + bus1=spatial.biomass.nodes, + carrier="unsustainable solid biomass", + efficiency=1, + p_nom=unsustainable_solid_biomass_potentials_spatial, + ) + n.madd( "Bus", spatial.biomass.bioliquids, @@ -2502,7 +2551,6 @@ def add_biomass(n, costs): n.madd( "Store", spatial.biomass.bioliquids, - suffix=" unsustainable", bus=spatial.biomass.bioliquids, carrier="unsustainable bioliquids", e_nom=unsustainable_liquid_biofuel_potentials_spatial, @@ -2512,6 +2560,8 @@ def add_biomass(n, costs): e_max_pu=e_max_pu, ) + add_carrier_buses(n, "oil") + n.madd( "Link", spatial.biomass.bioliquids, @@ -2600,13 +2650,15 @@ def add_biomass(n, costs): if options["municipal_solid_waste"]: n.madd( "Link", - biomass_transport.index, - bus0=biomass_transport.bus0 + " municipal solid waste", - bus1=biomass_transport.bus1 + " municipal solid waste", + biomass_transport.index + " municipal solid waste", + bus0=biomass_transport.bus0.values + " municipal solid waste", + bus1=biomass_transport.bus1.values + " municipal solid waste", p_nom_extendable=False, p_nom=5e4, length=biomass_transport.length.values, - marginal_cost=biomass_transport.costs * biomass_transport.length.values, + marginal_cost=( + biomass_transport.costs * biomass_transport.length + ).values, carrier="municipal solid waste transport", ) @@ -2638,6 +2690,32 @@ def add_biomass(n, costs): constant=biomass_potentials["solid biomass"].sum(), type="operational_limit", ) + if biomass_potentials["unsustainable solid biomass"].sum() > 0: + n.madd( + "Generator", + spatial.biomass.nodes_unsustainable, + bus=spatial.biomass.nodes_unsustainable, + carrier="unsustainable solid biomass", + p_nom=10000, + marginal_cost=costs.at["fuelwood", "fuel"] + + bus_transport_costs * average_distance, + ) + # Set last snapshot of e_max_pu for unsustainable solid biomass to 1 to make operational limit work + unsus_stores_idx = n.stores.query( + "carrier == 'unsustainable solid biomass'" + ).index + unsus_stores_idx = unsus_stores_idx.intersection( + n.stores_t.e_max_pu.columns + ) + n.stores_t.e_max_pu.loc[n.snapshots[-1], unsus_stores_idx] = 1 + n.add( + "GlobalConstraint", + "unsustainable biomass limit", + carrier_attribute="unsustainable solid biomass", + sense="==", + constant=biomass_potentials["unsustainable solid biomass"].sum(), + type="operational_limit", + ) if options["municipal_solid_waste"]: # Add municipal solid waste @@ -2729,7 +2807,9 @@ def add_biomass(n, costs): efficiency=costs.at["biomass boiler", "efficiency"], capital_cost=costs.at["biomass boiler", "efficiency"] * costs.at["biomass boiler", "fixed"] - * options["overdimension_individual_heating"], + * options["overdimension_heat_generators"][ + HeatSystem(name).central_or_decentral + ], marginal_cost=costs.at["biomass boiler", "pelletizing cost"], lifetime=costs.at["biomass boiler", "lifetime"], ) @@ -3251,7 +3331,9 @@ def add_industry(n, costs): efficiency2=costs.at["oil", "CO2 intensity"], capital_cost=costs.at["decentral oil boiler", "efficiency"] * costs.at["decentral oil boiler", "fixed"] - * options["overdimension_individual_heating"], + * options["overdimension_heat_generators"][ + heat_system.central_or_decentral + ], lifetime=costs.at["decentral oil boiler", "lifetime"], ) @@ -3354,9 +3436,13 @@ def add_industry(n, costs): spatial.msw.locations, bus0=spatial.msw.nodes, bus1=non_sequestered_hvc_locations, + bus2="co2 atmosphere", carrier="municipal solid waste", p_nom_extendable=True, efficiency=1.0, + efficiency2=-costs.at[ + "oil", "CO2 intensity" + ], # because msw is co2 neutral and will be burned in waste CHP or decomposed as oil ) n.madd( @@ -4252,10 +4338,10 @@ if __name__ == "__main__": "prepare_sector_network", simpl="", opts="", - clusters="37", + clusters="38", ll="vopt", sector_opts="", - planning_horizons="2050", + planning_horizons="2030", ) configure_logging(snakemake) diff --git a/scripts/solve_network.py b/scripts/solve_network.py index 99f7b575..bdc10dd1 100644 --- a/scripts/solve_network.py +++ b/scripts/solve_network.py @@ -330,8 +330,8 @@ def add_carbon_constraint(n, snapshots): continue # stores - n.stores["carrier"] = n.stores.bus.map(n.buses.carrier) - stores = n.stores.query("carrier in @emissions.index and not e_cyclic") + bus_carrier = n.stores.bus.map(n.buses.carrier) + stores = n.stores[bus_carrier.isin(emissions.index) & ~n.stores.e_cyclic] if not stores.empty: last = n.snapshot_weightings.reset_index().groupby("period").last() last_i = last.set_index([last.index, last.timestep]).index @@ -356,8 +356,8 @@ def add_carbon_budget_constraint(n, snapshots): continue # stores - n.stores["carrier"] = n.stores.bus.map(n.buses.carrier) - stores = n.stores.query("carrier in @emissions.index and not e_cyclic") + bus_carrier = n.stores.bus.map(n.buses.carrier) + stores = n.stores[bus_carrier.isin(emissions.index) & ~n.stores.e_cyclic] if not stores.empty: last = n.snapshot_weightings.reset_index().groupby("period").last() last_i = last.set_index([last.index, last.timestep]).index @@ -1000,8 +1000,8 @@ def add_co2_atmosphere_constraint(n, snapshots): continue # stores - n.stores["carrier"] = n.stores.bus.map(n.buses.carrier) - stores = n.stores.query("carrier in @emissions.index and not e_cyclic") + bus_carrier = n.stores.bus.map(n.buses.carrier) + stores = n.stores[bus_carrier.isin(emissions.index) & ~n.stores.e_cyclic] if not stores.empty: last_i = snapshots[-1] lhs = n.model["Store-e"].loc[last_i, stores.index] @@ -1055,8 +1055,8 @@ def extra_functionality(n, snapshots): if config["sector"]["enhanced_geothermal"]["enable"]: add_flexible_egs_constraint(n) - if snakemake.params.custom_extra_functionality: - source_path = snakemake.params.custom_extra_functionality + if n.params.custom_extra_functionality: + source_path = n.params.custom_extra_functionality assert os.path.exists(source_path), f"{source_path} does not exist" sys.path.append(os.path.dirname(source_path)) module_name = os.path.splitext(os.path.basename(source_path))[0] @@ -1065,7 +1065,7 @@ def extra_functionality(n, snapshots): custom_extra_functionality(n, snapshots, snakemake) -def solve_network(n, config, solving, **kwargs): +def solve_network(n, config, params, solving, **kwargs): set_of_options = solving["solver"]["options"] cf_solving = solving["options"] @@ -1093,6 +1093,7 @@ def solve_network(n, config, solving, **kwargs): # add to network for extra_functionality n.config = config + n.params = params if rolling_horizon and snakemake.rule == "solve_operations_network": kwargs["horizon"] = cf_solving.get("horizon", 365) @@ -1165,6 +1166,7 @@ if __name__ == "__main__": n = solve_network( n, config=snakemake.config, + params=snakemake.params, solving=snakemake.params.solving, log_fn=snakemake.log.solver, ) diff --git a/scripts/solve_operations_network.py b/scripts/solve_operations_network.py index bd4ce7aa..4336c3a7 100644 --- a/scripts/solve_operations_network.py +++ b/scripts/solve_operations_network.py @@ -49,7 +49,13 @@ if __name__ == "__main__": n.optimize.fix_optimal_capacities() n = prepare_network(n, solve_opts, config=snakemake.config) - n = solve_network(n, config=snakemake.config, log_fn=snakemake.log.solver) + n = solve_network( + n, + config=snakemake.config, + params=snakemake.params, + solving=snakemake.params.solving, + log_fn=snakemake.log.solver, + ) n.meta = dict(snakemake.config, **dict(wildcards=dict(snakemake.wildcards))) n.export_to_netcdf(snakemake.output[0])