From 5591b09adca8a924fb44d7b622c8534e69df557b Mon Sep 17 00:00:00 2001 From: Bryn Pickering <17178478+brynpickering@users.noreply.github.com> Date: Mon, 23 Oct 2023 15:19:31 +0100 Subject: [PATCH] Restructure project (#488) * Use pyproject.toml as is the recommended way to define python project metadata now. * Move calliope into src to make sure tests are not getting confused about relative filepaths in a way we don't realise. * Move from azure pipelines to github actions, which allow us to leverage the growing number of pre-built actions (like micromamba for speedy env install). * Move tests out of the calliope package itself. * Move and restructure requirements files so that dev install becomes a much easier one-liner for the mamba/conda part. * Remove unused dirs/files --- .azure-pipelines.yml | 172 ----- .coveragerc | 2 - .flake8 | 11 - codecov.yml => .github/.codecov.yml | 0 .github/workflows/commit-ci.yml | 44 ++ .github/workflows/pr-ci.yml | 73 +++ .hound.yml | 3 - .pylintrc | 589 ------------------ .readthedocs.yml | 2 +- CONTRIBUTING.md | 2 +- MANIFEST.in | 1 - README.md | 8 +- calliope/test/common/__init__.py | 0 .../model_config/data/csp_r.csv | 49 -- .../model_config/data/demand-1.csv | 49 -- .../model_config/data/demand-2.csv | 49 -- .../model_config/data/set_t.csv | 48 -- .../model_config/locations.yaml | 64 -- .../national_scale/model_config/model.yaml | 45 -- .../national_scale/model_config/techs.yaml | 98 --- .../model_conversion/national_scale/run.yaml | 73 --- .../notebooks/calliope_model_object.ipynb | 562 +---------------- doc/_static/notebooks/milp.ipynb | 6 +- doc/_static/notebooks/national_scale.ipynb | 17 +- doc/api/api.rst | 8 + doc/conf.py | 4 +- doc/helpers/generate_math.py | 5 +- doc/helpers/generate_readable_schema.py | 2 +- doc/helpers/generate_tables.py | 2 +- doc/user/advanced_constraints.rst | 2 +- doc/user/develop.rst | 29 +- doc/user/installation.rst | 28 +- doc/user/ref_example_models.rst | 16 +- doc/user/tutorials_01_national.rst | 16 +- doc/user/tutorials_02_urban.rst | 22 +- doc/user/tutorials_03_milp.rst | 6 +- paper/codemeta.json | 28 - paper/paper.bib | 78 --- paper/paper.md | 41 -- paper/timeseries.pdf | Bin 31307 -> 0 bytes pyproject.toml | 89 +++ pytest | 0 pytest.ini | 12 - requirements.yml | 16 - requirements.txt => requirements/base.txt | 2 +- requirements/dev.txt | 11 + .../docs.yml | 0 setup.py | 57 -- {calliope => src/calliope}/__init__.py | 0 {calliope => src/calliope}/_version.py | 0 .../calliope}/backend/__init__.py | 0 .../calliope}/backend/backends.py | 0 .../calliope}/backend/expression_parser.py | 0 .../calliope}/backend/helper_functions.py | 0 .../calliope}/backend/latex_backend.py | 0 {calliope => src/calliope}/backend/parsing.py | 0 .../calliope}/backend/where_parser.py | 0 {calliope => src/calliope}/cli.py | 0 .../calliope}/config/defaults.yaml | 0 .../calliope}/config/math_schema.yaml | 0 .../calliope}/config/model_data_lookup.yaml | 0 {calliope => src/calliope}/core/__init__.py | 0 {calliope => src/calliope}/core/attrdict.py | 0 {calliope => src/calliope}/core/io.py | 0 {calliope => src/calliope}/core/model.py | 0 .../calliope}/core/util/__init__.py | 0 .../calliope}/core/util/generate_runs.py | 0 .../calliope}/core/util/logging.py | 0 {calliope => src/calliope}/core/util/tools.py | 0 .../example_models/national_scale/model.yaml | 0 .../model_config/locations.yaml | 0 .../national_scale/model_config/techs.yaml | 0 .../national_scale/scenarios.yaml | 0 .../national_scale/timeseries_data/README.rst | 0 .../timeseries_data/csp_resource.csv | 0 .../timeseries_data/demand-1.csv | 0 .../timeseries_data/demand-2.csv | 0 .../example_models/urban_scale/model.yaml | 0 .../urban_scale/model_config/locations.yaml | 0 .../urban_scale/model_config/techs.yaml | 0 .../example_models/urban_scale/scenarios.yaml | 0 .../timeseries_data/demand_heat.csv | 0 .../timeseries_data/demand_power.csv | 0 .../timeseries_data/export_power.csv | 0 .../timeseries_data/pv_resource.csv | 0 {calliope => src/calliope}/examples.py | 0 {calliope => src/calliope}/exceptions.py | 0 {calliope => src/calliope}/math/base.yaml | 0 {calliope => src/calliope}/math/operate.yaml | 0 {calliope => src/calliope}/math/spores.yaml | 0 .../calliope}/math/storage_inter_cluster.yaml | 0 .../calliope}/postprocess/__init__.py | 0 .../calliope}/postprocess/results.py | 0 .../calliope}/postprocess/util.py | 0 .../calliope}/preprocess/__init__.py | 0 .../calliope}/preprocess/checks.py | 0 .../calliope}/preprocess/model_data.py | 0 .../calliope}/preprocess/model_run.py | 0 .../calliope}/preprocess/nodes.py | 0 {calliope => src/calliope}/preprocess/time.py | 0 {calliope => src/calliope}/preprocess/util.py | 0 {calliope => src/calliope}/time/__init__.py | 0 {calliope => src/calliope}/time/clustering.py | 0 {calliope => src/calliope}/time/funcs.py | 0 {calliope => src/calliope}/time/masks.py | 0 {calliope/test => tests}/__init__.py | 0 .../common/constraint_sets.yaml | 0 .../test => tests}/common/html_strings.yaml | 0 .../common/lp_files/balance_conversion.lp | 0 .../common/lp_files/carrier_production_max.lp | 0 .../common/lp_files/energy_cap.lp | 0 .../common/lp_files/resource_max.lp | 0 .../common/lp_files/storage_max.lp | 0 .../energy_cap_per_storage_cap.yaml | 0 .../common/test_model/model.yaml | 0 .../common/test_model/model_minimal.yaml | 0 .../common/test_model/scenarios.yaml | 0 .../timeseries_data/alternating_cost.csv | 0 .../timeseries_data/binary_one_day.csv | 0 .../timeseries_data/carrier_ratio.csv | 0 .../timeseries_data/cluster_days.csv | 0 .../test_model/timeseries_data/clusters.csv | 0 .../test_model/timeseries_data/cost.csv | 0 .../timeseries_data/demand_elec.csv | 0 .../timeseries_data/demand_elec_15T_to_2h.csv | 0 .../timeseries_data/demand_elec_15mins.csv | 0 .../timeseries_data/demand_elec_positive.csv | 0 .../timeseries_data/demand_heat.csv | 0 .../demand_heat_diff_dateformat.csv | 0 .../demand_heat_wrong_dateformat.csv | 0 .../demand_heat_wrong_length.csv | 0 .../timeseries_data/demand_simple.csv | 0 .../timeseries_data/supply_plus_resource.csv | 0 .../supply_plus_resource_inf.csv | 0 .../timeseries_data/supply_simple.csv | 0 .../common/test_model/weighted_obj_func.yaml | 0 {calliope/test => tests}/common/util.py | 3 +- .../test => tests}/common/yaml_file.yaml | 0 {calliope/test => tests}/conftest.py | 4 +- .../test_backend_expression_parser.py | 4 +- .../test_backend_helper_functions.py | 4 +- .../test_backend_latex_backend.py | 4 +- .../test => tests}/test_backend_parsing.py | 6 +- .../test => tests}/test_backend_pyomo.py | 6 +- ...ckend_pyomo_constraints_conversion_plus.py | 4 +- .../test_backend_pyomo_objective.py | 4 +- .../test_backend_where_parser.py | 4 +- {calliope/test => tests}/test_cli.py | 21 +- .../test => tests}/test_constraint_results.py | 4 +- .../test => tests}/test_core_attrdict.py | 4 +- .../test_core_future_warnings.py | 4 +- {calliope/test => tests}/test_core_model.py | 6 +- .../test => tests}/test_core_preprocess.py | 12 +- {calliope/test => tests}/test_core_time.py | 6 +- {calliope/test => tests}/test_core_util.py | 16 +- .../test => tests}/test_example_models.py | 6 +- {calliope/test => tests}/test_io.py | 3 +- {calliope/test => tests}/test_math.py | 10 +- {calliope/test => tests}/test_model_data.py | 19 +- .../test => tests}/test_model_manipulation.py | 6 +- 160 files changed, 384 insertions(+), 2217 deletions(-) delete mode 100644 .azure-pipelines.yml delete mode 100644 .coveragerc delete mode 100644 .flake8 rename codecov.yml => .github/.codecov.yml (100%) create mode 100644 .github/workflows/commit-ci.yml create mode 100644 .github/workflows/pr-ci.yml delete mode 100644 .hound.yml delete mode 100644 .pylintrc delete mode 100644 MANIFEST.in delete mode 100644 calliope/test/common/__init__.py delete mode 100644 calliope/test/model_conversion/national_scale/model_config/data/csp_r.csv delete mode 100644 calliope/test/model_conversion/national_scale/model_config/data/demand-1.csv delete mode 100644 calliope/test/model_conversion/national_scale/model_config/data/demand-2.csv delete mode 100644 calliope/test/model_conversion/national_scale/model_config/data/set_t.csv delete mode 100644 calliope/test/model_conversion/national_scale/model_config/locations.yaml delete mode 100644 calliope/test/model_conversion/national_scale/model_config/model.yaml delete mode 100644 calliope/test/model_conversion/national_scale/model_config/techs.yaml delete mode 100644 calliope/test/model_conversion/national_scale/run.yaml delete mode 100644 paper/codemeta.json delete mode 100644 paper/paper.bib delete mode 100644 paper/paper.md delete mode 100644 paper/timeseries.pdf delete mode 100644 pytest delete mode 100644 pytest.ini delete mode 100644 requirements.yml rename requirements.txt => requirements/base.txt (93%) create mode 100644 requirements/dev.txt rename requirements_docs.yml => requirements/docs.yml (100%) delete mode 100644 setup.py rename {calliope => src/calliope}/__init__.py (100%) rename {calliope => src/calliope}/_version.py (100%) rename {calliope => src/calliope}/backend/__init__.py (100%) rename {calliope => src/calliope}/backend/backends.py (100%) rename {calliope => src/calliope}/backend/expression_parser.py (100%) rename {calliope => src/calliope}/backend/helper_functions.py (100%) rename {calliope => src/calliope}/backend/latex_backend.py (100%) rename {calliope => src/calliope}/backend/parsing.py (100%) rename {calliope => src/calliope}/backend/where_parser.py (100%) rename {calliope => src/calliope}/cli.py (100%) rename {calliope => src/calliope}/config/defaults.yaml (100%) rename {calliope => src/calliope}/config/math_schema.yaml (100%) rename {calliope => src/calliope}/config/model_data_lookup.yaml (100%) rename {calliope => src/calliope}/core/__init__.py (100%) rename {calliope => src/calliope}/core/attrdict.py (100%) rename {calliope => src/calliope}/core/io.py (100%) rename {calliope => src/calliope}/core/model.py (100%) rename {calliope => src/calliope}/core/util/__init__.py (100%) rename {calliope => src/calliope}/core/util/generate_runs.py (100%) rename {calliope => src/calliope}/core/util/logging.py (100%) rename {calliope => src/calliope}/core/util/tools.py (100%) rename {calliope => src/calliope}/example_models/national_scale/model.yaml (100%) rename {calliope => src/calliope}/example_models/national_scale/model_config/locations.yaml (100%) rename {calliope => src/calliope}/example_models/national_scale/model_config/techs.yaml (100%) rename {calliope => src/calliope}/example_models/national_scale/scenarios.yaml (100%) rename {calliope => src/calliope}/example_models/national_scale/timeseries_data/README.rst (100%) rename {calliope => src/calliope}/example_models/national_scale/timeseries_data/csp_resource.csv (100%) rename {calliope => src/calliope}/example_models/national_scale/timeseries_data/demand-1.csv (100%) rename {calliope => src/calliope}/example_models/national_scale/timeseries_data/demand-2.csv (100%) rename {calliope => src/calliope}/example_models/urban_scale/model.yaml (100%) rename {calliope => src/calliope}/example_models/urban_scale/model_config/locations.yaml (100%) rename {calliope => src/calliope}/example_models/urban_scale/model_config/techs.yaml (100%) rename {calliope => src/calliope}/example_models/urban_scale/scenarios.yaml (100%) rename {calliope => src/calliope}/example_models/urban_scale/timeseries_data/demand_heat.csv (100%) rename {calliope => src/calliope}/example_models/urban_scale/timeseries_data/demand_power.csv (100%) rename {calliope => src/calliope}/example_models/urban_scale/timeseries_data/export_power.csv (100%) rename {calliope => src/calliope}/example_models/urban_scale/timeseries_data/pv_resource.csv (100%) rename {calliope => src/calliope}/examples.py (100%) rename {calliope => src/calliope}/exceptions.py (100%) rename {calliope => src/calliope}/math/base.yaml (100%) rename {calliope => src/calliope}/math/operate.yaml (100%) rename {calliope => src/calliope}/math/spores.yaml (100%) rename {calliope => src/calliope}/math/storage_inter_cluster.yaml (100%) rename {calliope => src/calliope}/postprocess/__init__.py (100%) rename {calliope => src/calliope}/postprocess/results.py (100%) rename {calliope => src/calliope}/postprocess/util.py (100%) rename {calliope => src/calliope}/preprocess/__init__.py (100%) rename {calliope => src/calliope}/preprocess/checks.py (100%) rename {calliope => src/calliope}/preprocess/model_data.py (100%) rename {calliope => src/calliope}/preprocess/model_run.py (100%) rename {calliope => src/calliope}/preprocess/nodes.py (100%) rename {calliope => src/calliope}/preprocess/time.py (100%) rename {calliope => src/calliope}/preprocess/util.py (100%) rename {calliope => src/calliope}/time/__init__.py (100%) rename {calliope => src/calliope}/time/clustering.py (100%) rename {calliope => src/calliope}/time/funcs.py (100%) rename {calliope => src/calliope}/time/masks.py (100%) rename {calliope/test => tests}/__init__.py (100%) rename {calliope/test => tests}/common/constraint_sets.yaml (100%) rename {calliope/test => tests}/common/html_strings.yaml (100%) rename {calliope/test => tests}/common/lp_files/balance_conversion.lp (100%) rename {calliope/test => tests}/common/lp_files/carrier_production_max.lp (100%) rename {calliope/test => tests}/common/lp_files/energy_cap.lp (100%) rename {calliope/test => tests}/common/lp_files/resource_max.lp (100%) rename {calliope/test => tests}/common/lp_files/storage_max.lp (100%) rename {calliope/test => tests}/common/test_model/energy_cap_per_storage_cap.yaml (100%) rename {calliope/test => tests}/common/test_model/model.yaml (100%) rename {calliope/test => tests}/common/test_model/model_minimal.yaml (100%) rename {calliope/test => tests}/common/test_model/scenarios.yaml (100%) rename {calliope/test => tests}/common/test_model/timeseries_data/alternating_cost.csv (100%) rename {calliope/test => tests}/common/test_model/timeseries_data/binary_one_day.csv (100%) rename {calliope/test => tests}/common/test_model/timeseries_data/carrier_ratio.csv (100%) rename {calliope/test => tests}/common/test_model/timeseries_data/cluster_days.csv (100%) rename {calliope/test => tests}/common/test_model/timeseries_data/clusters.csv (100%) rename {calliope/test => tests}/common/test_model/timeseries_data/cost.csv (100%) rename {calliope/test => tests}/common/test_model/timeseries_data/demand_elec.csv (100%) rename {calliope/test => tests}/common/test_model/timeseries_data/demand_elec_15T_to_2h.csv (100%) rename {calliope/test => tests}/common/test_model/timeseries_data/demand_elec_15mins.csv (100%) rename {calliope/test => tests}/common/test_model/timeseries_data/demand_elec_positive.csv (100%) rename {calliope/test => tests}/common/test_model/timeseries_data/demand_heat.csv (100%) rename {calliope/test => tests}/common/test_model/timeseries_data/demand_heat_diff_dateformat.csv (100%) rename {calliope/test => tests}/common/test_model/timeseries_data/demand_heat_wrong_dateformat.csv (100%) rename {calliope/test => tests}/common/test_model/timeseries_data/demand_heat_wrong_length.csv (100%) rename {calliope/test => tests}/common/test_model/timeseries_data/demand_simple.csv (100%) rename {calliope/test => tests}/common/test_model/timeseries_data/supply_plus_resource.csv (100%) rename {calliope/test => tests}/common/test_model/timeseries_data/supply_plus_resource_inf.csv (100%) rename {calliope/test => tests}/common/test_model/timeseries_data/supply_simple.csv (100%) rename {calliope/test => tests}/common/test_model/weighted_obj_func.yaml (100%) rename {calliope/test => tests}/common/util.py (99%) rename {calliope/test => tests}/common/yaml_file.yaml (100%) rename {calliope/test => tests}/conftest.py (99%) rename {calliope/test => tests}/test_backend_expression_parser.py (99%) rename {calliope/test => tests}/test_backend_helper_functions.py (99%) rename {calliope/test => tests}/test_backend_latex_backend.py (99%) rename {calliope/test => tests}/test_backend_parsing.py (99%) rename {calliope/test => tests}/test_backend_pyomo.py (99%) rename {calliope/test => tests}/test_backend_pyomo_constraints_conversion_plus.py (98%) rename {calliope/test => tests}/test_backend_pyomo_objective.py (98%) rename {calliope/test => tests}/test_backend_where_parser.py (99%) rename {calliope/test => tests}/test_cli.py (96%) rename {calliope/test => tests}/test_constraint_results.py (99%) rename {calliope/test => tests}/test_core_attrdict.py (99%) rename {calliope/test => tests}/test_core_future_warnings.py (89%) rename {calliope/test => tests}/test_core_model.py (99%) rename {calliope/test => tests}/test_core_preprocess.py (99%) rename {calliope/test => tests}/test_core_time.py (99%) rename {calliope/test => tests}/test_core_util.py (95%) rename {calliope/test => tests}/test_example_models.py (99%) rename {calliope/test => tests}/test_io.py (99%) rename {calliope/test => tests}/test_math.py (95%) rename {calliope/test => tests}/test_model_data.py (98%) rename {calliope/test => tests}/test_model_manipulation.py (95%) diff --git a/.azure-pipelines.yml b/.azure-pipelines.yml deleted file mode 100644 index 1bb17e844..000000000 --- a/.azure-pipelines.yml +++ /dev/null @@ -1,172 +0,0 @@ -trigger: - branches: - include: - - "main" - - "0.6" - paths: - exclude: - - ".gitattributes" - - ".github" - - ".gitignore" - - ".hound.yml" - - ".pre-commit-config.yaml" - - ".readthedocs.yml" - - "AUTHORS" - - "CITATION" - - "LICENSE" - - "Makefile" - - "changelog.rst" - - "doc" - - "paper" - - "requirements_docs.yml" - - "*.md" - -pr: - autoCancel: true # new PR commits will cancel current pipeline jobs in favour of latest commit - branches: - include: - - "main" - - "0.6" - paths: - exclude: - - ".gitattributes" - - ".github/*" - - ".gitignore" - - ".hound.yml" - - ".pre-commit-config.yaml" - - ".readthedocs.yml" - - "AUTHORS" - - "CITATION" - - "LICENSE" - - "Makefile" - - "changelog.rst" - - "doc" - - "paper" - - "requirements_docs.yml" - - "*.md" - -pool: - vmImage: $(IMAGE_NAME) - -strategy: - maxParallel: 10 # free limit is 10 parallel jobs - matrix: - linux-py3.9: - IMAGE_NAME: ubuntu-latest - PYTHON_VERSION: 3.9 - CODECOV: True # Only run on one build - linux-py3.11: - IMAGE_NAME: ubuntu-latest - PYTHON_VERSION: 3.11 - CODECOV: True # Only run on one build - macos-py3.11: - IMAGE_NAME: macOS-latest - PYTHON_VERSION: 3.11 - windows-py3.11: - IMAGE_NAME: windows-latest - PYTHON_VERSION: 3.11 - -steps: - - bash: echo "##vso[task.prependpath]$CONDA/bin" - displayName: Enable conda (UNIX) - condition: ne( variables['Agent.OS'], 'Windows_NT' ) - - - powershell: Write-Host "##vso[task.prependpath]$env:CONDA\Scripts" - displayName: Enable conda (Windows) - condition: eq( variables['Agent.OS'], 'Windows_NT' ) - - - task: Cache@2 - displayName: Use cached Anaconda environment - inputs: - key: 'conda | "$(Agent.OS)" | "$(PYTHON_VERSION)" | requirements.yml | requirements.txt' - restoreKeys: | - python | "$(Agent.OS)" - python - path: $(CONDA)/envs/calliope - cacheHitVar: CONDA_CACHE_RESTORED - - - powershell: wget https://github.com/coin-or/Cbc/releases/download/releases%2F2.10.8/Cbc-releases.2.10.8-w64-msvc17-md.zip -O cbc.zip - displayName: Download CBC (Windows) - condition: eq( variables['Agent.OS'], 'Windows_NT' ) - - - task: ExtractFiles@1 - inputs: - archiveFilePatterns: 'cbc.zip' # string. Required. Archive file patterns. Default: **/*.zip. - destinationFolder: $(agent.builddirectory)\cbc # string. Required. Destination folder. - cleanDestinationFolder: true # boolean. Required. Clean destination folder before extracting. Default: true. - overwriteExistingFiles: false # boolean. Required. Overwrite existing files. Default: false. - condition: eq( variables['Agent.OS'], 'Windows_NT' ) - - - powershell: Write-Host "##vso[task.prependpath]$(agent.builddirectory)\cbc\bin" - displayName: set path for CBC (Windows) - condition: eq( variables['Agent.OS'], 'Windows_NT' ) - - - bash: sudo chown -R $USER $CONDA - displayName: Take ownership of conda installation (macOS) - condition: eq( variables['Agent.OS'], 'Darwin' ) - - - bash: | - conda config --set always_yes yes --set changeps1 no - conda update -q conda - conda info -a - displayName: Configure and update conda - - - bash: | - conda config --add channels conda-forge - conda create --yes --quiet -n calliope python=$(PYTHON_VERSION) - conda env update --file requirements.yml --name calliope - conda env update --file requirements.txt --name calliope - displayName: Set up environment - condition: eq(variables.CONDA_CACHE_RESTORED, 'false') - - - bash: | - conda install --yes -n calliope coin-or-cbc - displayName: Install coincbc (UNIX) - condition: and(ne(variables['Agent.OS'], 'Windows_NT'), eq(variables.CONDA_CACHE_RESTORED, 'false')) - - - bash: | - source activate calliope - pip install --no-cache-dir --verbose -e . - displayName: Install calliope (UNIX) - condition: and(ne(variables['Agent.OS'], 'Windows_NT'), eq(variables.CONDA_CACHE_RESTORED, 'false')) - - - script: | - call activate calliope - pip install --no-cache-dir --verbose -e . - displayName: Install calliope (Windows) - condition: and(eq(variables['Agent.OS'], 'Windows_NT'), eq(variables.CONDA_CACHE_RESTORED, 'false')) - - - bash: | # cbc -quit may be required to make sure that cbc is 'reset' so its timeout time fits within pyomo's strict limit (see: https://github.com/Pyomo/pyomo/issues/2102) - source activate calliope - cbc -quit - py.test -n 2 --junitxml=junit/test-results.xml --cov=calliope --cov-report=term-missing --cov-report=xml -W ignore::FutureWarning --dist=loadscope - displayName: Run tests (UNIX) - condition: ne( variables['Agent.OS'], 'Windows_NT' ) - - - script: | - call activate calliope - py.test -n 2 --junitxml=junit/test-results.xml --cov=calliope --cov-report=term-missing --cov-report=xml -W ignore::FutureWarning --dist=loadscope - displayName: Run tests (Windows) - condition: eq( variables['Agent.OS'], 'Windows_NT' ) - - - task: PublishTestResults@2 - condition: succeededOrFailed() - inputs: - testResultsFiles: '**/test-*.xml' - testRunTitle: '$(Agent.JobName)' - - - task: PublishCodeCoverageResults@1 - condition: succeededOrFailed() - inputs: - codeCoverageTool: Cobertura - summaryFileLocation: '$(System.DefaultWorkingDirectory)/**/coverage.xml' - - - bash: | - curl -Os https://uploader.codecov.io/latest/linux/codecov - - chmod +x codecov - ./codecov -t ${CODECOV_TOKEN} - displayName: Send results to Codecov - condition: eq( variables['CODECOV'], 'True' ) - env: - CODECOV_TOKEN: $(CodecovToken) diff --git a/.coveragerc b/.coveragerc deleted file mode 100644 index 4df986561..000000000 --- a/.coveragerc +++ /dev/null @@ -1,2 +0,0 @@ -[run] -omit = calliope/test/*, calliope/lib/* diff --git a/.flake8 b/.flake8 deleted file mode 100644 index 23a40ca1c..000000000 --- a/.flake8 +++ /dev/null @@ -1,11 +0,0 @@ -[flake8] -# Recommend matching the black line length (default 88), -# rather than using the flake8 default of 79: -max-line-length = 88 -extend-ignore = - # See https://github.com/PyCQA/pycodestyle/issues/373 - E203, - # E501: line too long - E501, -exclude = .git,__pycache__,dist,doc -max-complexity = 10 diff --git a/codecov.yml b/.github/.codecov.yml similarity index 100% rename from codecov.yml rename to .github/.codecov.yml diff --git a/.github/workflows/commit-ci.yml b/.github/workflows/commit-ci.yml new file mode 100644 index 000000000..71f287c32 --- /dev/null +++ b/.github/workflows/commit-ci.yml @@ -0,0 +1,44 @@ +name: Branch Push CI + +on: + push: + branches: + - "**" + paths-ignore: + - README.md + - changelog.rst + - LICENSE + - CITATION + - AUTHORS + - doc/** + +defaults: + run: + shell: bash -l {0} + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - uses: mamba-org/setup-micromamba@v1 + with: + micromamba-version: latest + environment-name: ${{ github.event.repository.name }}-ubuntu-latest-311 + environment-file: requirements/base.txt + create-args: >- + -f requirements/dev.txt + python=3.11 + coin-or-cbc + post-cleanup: all + cache-environment: true + + - name: Install package + run: pip install --no-dependencies -e . + + - name: Install jupyter kernel + run: python -m ipykernel install --user --name calliope + + - name: run tests + run: pytest diff --git a/.github/workflows/pr-ci.yml b/.github/workflows/pr-ci.yml new file mode 100644 index 000000000..a6ca10736 --- /dev/null +++ b/.github/workflows/pr-ci.yml @@ -0,0 +1,73 @@ +name: Pull Request CI + +on: + pull_request: + branches: + - "main" + paths-ignore: + - README.md + - changelog.rst + - LICENSE + - CITATION + - AUTHORS + - doc/** + +defaults: + run: + shell: bash -l {0} + +concurrency: + # Use github.run_id on main branch + # Use github.event.pull_request.number on pull requests, so it's unique per pull request + # Use github.ref on other branches, so it's unique per branch + group: ${{ github.workflow }}-${{ github.ref == 'refs/heads/main' && github.run_id || github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + test: + strategy: + matrix: + os: [windows-latest, ubuntu-latest, macos-latest] + py3version: ["9", "10", "11"] + fail-fast: false + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v3 + + - uses: mamba-org/setup-micromamba@v1 + with: + micromamba-version: latest + environment-name: ${{ github.event.repository.name }}-${{ matrix.os }}-3${{ matrix.py3version }} + environment-file: requirements/base.txt + create-args: >- + -f requirements/dev.txt + curl + python=3.${{ matrix.py3version }} + post-cleanup: all + cache-environment: true + + - name: Install package + run: pip install --no-dependencies -e . + + - name: install CBC (Windows) + if: matrix.os == 'windows-latest' + run: | + curl -L https://github.com/coin-or/Cbc/releases/download/releases%2F2.10.10/Cbc-releases.2.10.10-w64-msvc17-md.zip -o cbc.zip + unzip cbc.zip -d ${HOME}/cbc + echo "${HOME}/cbc/bin" >> $GITHUB_PATH + + - name: install CBC (Unix) + if: matrix.os != 'windows-latest' + run: micromamba install coin-or-cbc + + - name: Install jupyter kernel + run: python -m ipykernel install --user --name calliope + + - name: run tests + run: pytest + + - name: Upload coverage reports to Codecov + uses: codecov/codecov-action@v3 + if: matrix.os == 'ubuntu-latest' && matrix.py3version == '11' + env: + directory: "./reports/coverage/" \ No newline at end of file diff --git a/.hound.yml b/.hound.yml deleted file mode 100644 index 09d8c1baf..000000000 --- a/.hound.yml +++ /dev/null @@ -1,3 +0,0 @@ -flake8: - enabled: true - config_file: .flake8 diff --git a/.pylintrc b/.pylintrc deleted file mode 100644 index e71568d76..000000000 --- a/.pylintrc +++ /dev/null @@ -1,589 +0,0 @@ -# Based on the Apache-2.0 licensed https://github.com/ClusterHQ/flocker/blob/master/.pylintrc -# Inspiration from https://codewithoutrules.com/2016/10/19/pylint/ - -[MAIN] - -# Specify a configuration file. -#rcfile= - -# Python code to execute, usually for sys.path manipulation such as -# pygtk.require(). -init-hook="import calliope" - -# Add files or directories to the blacklist. They should be base names, not -# paths. -ignore= - -# Pickle collected data for later comparisons. -persistent=no - -# List of plugins (as comma separated values of python modules names) to load, -# usually to register additional checkers. -load-plugins= - -# Use multiple processes to speed up Pylint. -# DO NOT CHANGE THIS VALUES >1 HIDE RESULTS!!!!! -jobs=1 - -# Allow loading of arbitrary C extensions. Extensions are imported into the -# active Python interpreter and may run arbitrary code. -unsafe-load-any-extension=no - -# A comma-separated list of package or module names from where C extensions may -# be loaded. Extensions are loading into the active Python interpreter and may -# run arbitrary code -extension-pkg-whitelist= - -# Allow optimization of some AST trees. This will activate a peephole AST -# optimizer, which will apply various small optimizations. For instance, it can -# be used to obtain the result of joining multiple strings with the addition -# operator. Joining a lot of strings can lead to a maximum recursion error in -# Pylint and this flag can prevent that. It has one side effect, the resulting -# AST will be different than the one from reality. -optimize-ast=no - - -[MESSAGES CONTROL] - -# Only show warnings with the listed confidence levels. Leave empty to show -# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED -confidence= - -# Enable the message, report, category or checker with the given id(s). You can -# either give multiple identifier separated by comma (,) or put this option -# multiple time. See also the "--disable" option for examples. -disable=all - -enable=import-error, - import-self, - reimported, - wildcard-import, - misplaced-future, - relative-import, - deprecated-module, - unpacking-non-sequence, - invalid-all-object, - undefined-all-variable, - used-before-assignment, - cell-var-from-loop, - global-variable-undefined, - redefined-builtin, - redefine-in-handler, - unused-import, - unused-wildcard-import, - global-variable-not-assigned, - undefined-loop-variable, - global-statement, - global-at-module-level, - bad-open-mode, - redundant-unittest-assert, - boolean-datetime, - undefined-variable, - redefined-outer-name, - no-name-in-module, - unused-argument, - trailing-whitespace, - trailing-newlines, - missing-final-newline, - unused-variable, - undefined-variable - -# Things we'd like to enable someday: -# redefined-outer-name (requires a bunch of work to clean up our code first) -# no-name-in-module (giving us spurious warnings https://github.com/PyCQA/pylint/issues/73) -# unused-argument (need to clean up or code a lot, e.g. prefix unused_?) - -# Things we'd like to try. -# Procedure: -# 1. Enable a bunch. -# 2. See if there's spurious ones; if so disable. -# 3. Record above. -# 4. Remove from this list. - # deprecated-method, - # anomalous-unicode-escape-in-string, - # anomalous-backslash-in-string, - # not-in-loop, - # function-redefined, - # continue-in-finally, - # abstract-class-instantiated, - # star-needs-assignment-target, - # duplicate-argument-name, - # return-in-init, - # too-many-star-expressions, - # nonlocal-and-global, - # return-outside-function, - # return-arg-in-generator, - # invalid-star-assignment-target, - # bad-reversed-sequence, - # nonexistent-operator, - # yield-outside-function, - # init-is-generator, - # nonlocal-without-binding, - # lost-exception, - # assert-on-tuple, - # dangerous-default-value, - # duplicate-key, - # useless-else-on-loop, - # expression-not-assigned, - # confusing-with-statement, - # unnecessary-lambda, - # pointless-statement, - # pointless-string-statement, - # unnecessary-pass, - # unreachable, - # eval-used, - # exec-used, - # bad-builtin, - # using-constant-test, - # deprecated-lambda, - # bad-super-call, - # missing-super-argument, - # slots-on-old-class, - # super-on-old-class, - # property-on-old-class, - # not-an-iterable, - # not-a-mapping, - # format-needs-mapping, - # truncated-format-string, - # missing-format-string-key, - # mixed-format-string, - # too-few-format-args, - # bad-str-strip-call, - # too-many-format-args, - # bad-format-character, - # format-combined-specification, - # bad-format-string-key, - # bad-format-string, - # missing-format-attribute, - # missing-format-argument-key, - # unused-format-string-argument, - # unused-format-string-key, - # invalid-format-index, - # bad-indentation, - # mixed-indentation, - # unnecessary-semicolon, - # lowercase-l-suffix, - # fixme, - # invalid-encoded-data, - # unpacking-in-except, - # import-star-module-level, - # parameter-unpacking, - # long-suffix, - # old-octal-literal, - # old-ne-operator, - # backtick, - # old-raise-syntax, - # print-statement, - # metaclass-assignment, - # next-method-called, - # dict-iter-method, - # dict-view-method, - # indexing-exception, - # raising-string, - # standarderror-builtin, - # using-cmp-argument, - # cmp-method, - # coerce-method, - # delslice-method, - # getslice-method, - # hex-method, - # nonzero-method, - # oct-method, - # setslice-method, - # apply-builtin, - # basestring-builtin, - # buffer-builtin, - # cmp-builtin, - # coerce-builtin, - # old-division, - # execfile-builtin, - # file-builtin, - # filter-builtin-not-iterating, - # no-absolute-import, - # input-builtin, - # intern-builtin, - # long-builtin, - # map-builtin-not-iterating, - # range-builtin-not-iterating, - # raw_input-builtin, - # reduce-builtin, - # reload-builtin, - # round-builtin, - # unichr-builtin, - # unicode-builtin, - # xrange-builtin, - # zip-builtin-not-iterating, - # logging-format-truncated, - # logging-too-few-args, - # logging-too-many-args, - # logging-unsupported-format, - # logging-not-lazy, - # logging-format-interpolation, - # invalid-unary-operand-type, - # unsupported-binary-operation, - # no-member, - # not-callable, - # redundant-keyword-arg, - # assignment-from-no-return, - # assignment-from-none, - # not-context-manager, - # repeated-keyword, - # missing-kwoa, - # no-value-for-parameter, - # invalid-sequence-index, - # invalid-slice-index, - # too-many-function-args, - # unexpected-keyword-arg, - # unsupported-membership-test, - # unsubscriptable-object, - # access-member-before-definition, - # method-hidden, - # assigning-non-slot, - # duplicate-bases, - # inconsistent-mro, - # inherit-non-class, - # invalid-slots, - # invalid-slots-object, - # no-method-argument, - # no-self-argument, - # unexpected-special-method-signature, - # non-iterator-returned, - # protected-access, - # arguments-differ, - # attribute-defined-outside-init, - # no-init, - # abstract-method, - # signature-differs, - # bad-staticmethod-argument, - # non-parent-init-called, - # super-init-not-called, - # bad-except-order, - # catching-non-exception, - # bad-exception-context, - # notimplemented-raised, - # raising-bad-type, - # raising-non-exception, - # misplaced-bare-raise, - # duplicate-except, - # broad-except, - # nonstandard-exception, - # binary-op-exception, - # bare-except, - # not-async-context-manager, - # yield-inside-async-function, - -# ... -[REPORTS] - -# Set the output format. Available formats are text, parseable, colorized, msvs -# (visual studio) and html. You can also give a reporter class, eg -# mypackage.mymodule.MyReporterClass. -output-format=parseable - -# Put messages in a separate file for each module / package specified on the -# command line instead of printing them on stdout. Reports (if any) will be -# written in a file name "pylint_global.[txt|html]". -files-output=no - -# Tells whether to display a full report or only the messages -reports=no - -# Python expression which should return a note less than 10 (10 is the highest -# note). You have access to the variables errors warning, statement which -# respectively contain the number of errors / warnings messages and the total -# number of statements analyzed. This is used by the global evaluation report -# (RP0004). -evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) - -# Template used to display messages. This is a python new-style format string -# used to format the message information. See doc for all details -#msg-template= - - -[LOGGING] - -# Logging modules to check that the string format arguments are in logging -# function parameter format -logging-modules=logging - - -[FORMAT] - -# Maximum number of characters on a single line. -max-line-length=100 - -# Regexp for a line that is allowed to be longer than the limit. -ignore-long-lines=^\s*(# )??$ - -# Allow the body of an if to be on the same line as the test if there is no -# else. -single-line-if-stmt=no - -# List of optional constructs for which whitespace checking is disabled. `dict- -# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}. -# `trailing-comma` allows a space between comma and closing bracket: (a, ). -# `empty-line` allows space-only lines. -no-space-check=trailing-comma,dict-separator - -# Maximum number of lines in a module -max-module-lines=1000 - -# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 -# tab). -indent-string=' ' - -# Number of spaces of indent required inside a hanging or continued line. -indent-after-paren=4 - -# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. -expected-line-ending-format= - - -[TYPECHECK] - -# Tells whether missing members accessed in mixin class should be ignored. A -# mixin class is detected if its name ends with "mixin" (case insensitive). -ignore-mixin-members=yes - -# List of module names for which member attributes should not be checked -# (useful for modules/projects where namespaces are manipulated during runtime -# and thus existing member attributes cannot be deduced by static analysis. It -# supports qualified module names, as well as Unix pattern matching. -ignored-modules= - -# List of classes names for which member attributes should not be checked -# (useful for classes with attributes dynamically set). This supports can work -# with qualified names. -ignored-classes= - -# List of members which are set dynamically and missed by pylint inference -# system, and so shouldn't trigger E1101 when accessed. Python regular -# expressions are accepted. -generated-members= - - -[VARIABLES] - -# Tells whether we should check for unused import in __init__ files. -init-import=no - -# A regular expression matching the name of dummy variables (i.e. expectedly -# not used). -dummy-variables-rgx=_$|dummy - -# List of additional names supposed to be defined in builtins. Remember that -# you should avoid to define new builtins when possible. -additional-builtins= - -# List of strings which can identify a callback function by name. A callback -# name must start or end with one of those strings. -callbacks=cb_,_cb - - -[SIMILARITIES] - -# Minimum lines number of a similarity. -min-similarity-lines=4 - -# Ignore comments when computing similarities. -ignore-comments=yes - -# Ignore docstrings when computing similarities. -ignore-docstrings=yes - -# Ignore imports when computing similarities. -ignore-imports=no - - -[SPELLING] - -# Spelling dictionary name. Available dictionaries: none. To make it working -# install python-enchant package. -spelling-dict= - -# List of comma separated words that should not be checked. -spelling-ignore-words= - -# A path to a file that contains private dictionary; one word per line. -spelling-private-dict-file= - -# Tells whether to store unknown words to indicated private dictionary in -# --spelling-private-dict-file option instead of raising a message. -spelling-store-unknown-words=no - - -[MISCELLANEOUS] - -# List of note tags to take in consideration, separated by a comma. -notes=FIXME,XXX,TODO - - -[BASIC] - -# List of builtins function names that should not be used, separated by a comma -bad-functions=map,filter,input - -# Good variable names which should always be accepted, separated by a comma -good-names=i,j,k,ex,Run,_ - -# Bad variable names which should always be refused, separated by a comma -bad-names=foo,bar,baz,toto,tutu,tata - -# Colon-delimited sets of names that determine each other's naming style when -# the name regexes allow several styles. -name-group= - -# Include a hint for the correct naming format with invalid-name -include-naming-hint=no - -# Regular expression matching correct function names -function-rgx=[a-z_][a-z0-9_]{2,30}$ - -# Naming hint for function names -function-name-hint=[a-z_][a-z0-9_]{2,30}$ - -# Regular expression matching correct variable names -variable-rgx=[a-z_][a-z0-9_]{2,30}$ - -# Naming hint for variable names -variable-name-hint=[a-z_][a-z0-9_]{2,30}$ - -# Regular expression matching correct constant names -const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ - -# Naming hint for constant names -const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$ - -# Regular expression matching correct attribute names -attr-rgx=[a-z_][a-z0-9_]{2,30}$ - -# Naming hint for attribute names -attr-name-hint=[a-z_][a-z0-9_]{2,30}$ - -# Regular expression matching correct argument names -argument-rgx=[a-z_][a-z0-9_]{2,30}$ - -# Naming hint for argument names -argument-name-hint=[a-z_][a-z0-9_]{2,30}$ - -# Regular expression matching correct class attribute names -class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ - -# Naming hint for class attribute names -class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ - -# Regular expression matching correct inline iteration names -inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ - -# Naming hint for inline iteration names -inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$ - -# Regular expression matching correct class names -class-rgx=[A-Z_][a-zA-Z0-9]+$ - -# Naming hint for class names -class-name-hint=[A-Z_][a-zA-Z0-9]+$ - -# Regular expression matching correct module names -module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ - -# Naming hint for module names -module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ - -# Regular expression matching correct method names -method-rgx=[a-z_][a-z0-9_]{2,30}$ - -# Naming hint for method names -method-name-hint=[a-z_][a-z0-9_]{2,30}$ - -# Regular expression which should only match function or class names that do -# not require a docstring. -no-docstring-rgx=^_ - -# Minimum line length for functions/classes that require docstrings, shorter -# ones are exempt. -docstring-min-length=-1 - - -[ELIF] - -# Maximum number of nested blocks for function / method body -max-nested-blocks=5 - - -[IMPORTS] - -# Deprecated modules which should not be used, separated by a comma -deprecated-modules=regsub,TERMIOS,Bastion,rexec - -# Create a graph of every (i.e. internal and external) dependencies in the -# given file (report RP0402 must not be disabled) -import-graph= - -# Create a graph of external dependencies in the given file (report RP0402 must -# not be disabled) -ext-import-graph= - -# Create a graph of internal dependencies in the given file (report RP0402 must -# not be disabled) -int-import-graph= - - -[DESIGN] - -# Maximum number of arguments for function / method -max-args=5 - -# Argument names that match this expression will be ignored. Default to name -# with leading underscore -ignored-argument-names=_.* - -# Maximum number of locals for function / method body -max-locals=15 - -# Maximum number of return / yield for function / method body -max-returns=6 - -# Maximum number of branch for function / method body -max-branches=12 - -# Maximum number of statements in function / method body -max-statements=50 - -# Maximum number of parents for a class (see R0901). -max-parents=7 - -# Maximum number of attributes for a class (see R0902). -max-attributes=7 - -# Minimum number of public methods for a class (see R0903). -min-public-methods=2 - -# Maximum number of public methods for a class (see R0904). -max-public-methods=20 - -# Maximum number of boolean expressions in a if statement -max-bool-expr=5 - - -[CLASSES] - -# List of method names used to declare (i.e. assign) instance attributes. -defining-attr-methods=__init__,__new__,setUp - -# List of valid names for the first argument in a class method. -valid-classmethod-first-arg=cls - -# List of valid names for the first argument in a metaclass class method. -valid-metaclass-classmethod-first-arg=mcs - -# List of member names, which should be excluded from the protected access -# warning. -exclude-protected=_asdict,_fields,_replace,_source,_make - - -[EXCEPTIONS] - -# Exceptions that will emit a warning when being caught. Defaults to -# "Exception" -overgeneral-exceptions=Exception diff --git a/.readthedocs.yml b/.readthedocs.yml index edd59acf8..909c2c81b 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -1,7 +1,7 @@ version: 2 # required formats: [pdf] conda: - environment: requirements_docs.yml + environment: requirements/docs.yml build: os: ubuntu-22.04 # required tools: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 16ed6350a..84e357535 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -63,7 +63,7 @@ Please try to write clear commit messages. One-line messages are fine for small We have existing test coverage for the key functionality of Calliope. -All tests are in the ``calliope/test`` directory and use [pytest](https://docs.pytest.org/en/latest/). +All tests are in the ``tests`` directory and use [pytest](https://docs.pytest.org/en/latest/). Our test coverage is not perfect and an easy way to contribute code is to work on better tests. diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 050c1cf4c..000000000 --- a/MANIFEST.in +++ /dev/null @@ -1 +0,0 @@ -include requirements.txt README.md LICENSE CITATION changelog.rst diff --git a/README.md b/README.md index 8a8e0a25c..10dcda68f 100644 --- a/README.md +++ b/README.md @@ -37,9 +37,9 @@ Calliope comes with several built-in analysis and visualisation tools. Having so ## Quick start -Calliope can run on Windows, macOS and Linux. Installing it is quickest with the `conda` package manager by running a single command: `conda create -c conda-forge -n calliope calliope`. +Calliope can run on Windows, macOS and Linux. Installing it is quickest with the `mamba` package manager by running a single command: `mamba create -c conda-forge -n calliope calliope`. -See the documentation for more [information on installing](https://calliope.readthedocs.io/en/stable/user/installation.html), including what to do if you are having issues with `conda`. +See the documentation for more [information on installing](https://calliope.readthedocs.io/en/stable/user/installation.html). Several easy to understand example models are [included with Calliope](calliope/example_models) and accessible through the `calliope.examples` submodule. @@ -51,8 +51,8 @@ More fully-featured examples that have been used in peer-reviewed scientific pub Documentation is available on Read the Docs: -* [Read the documentation online (recommended)](https://calliope.readthedocs.io/en/stable/) -* [Download all documentation in a single PDF file](https://readthedocs.org/projects/calliope/downloads/pdf/stable/) +- [Read the documentation online (recommended)](https://calliope.readthedocs.io/en/stable/) +- [Download all documentation in a single PDF file](https://readthedocs.org/projects/calliope/downloads/pdf/stable/) ## Contributing diff --git a/calliope/test/common/__init__.py b/calliope/test/common/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/calliope/test/model_conversion/national_scale/model_config/data/csp_r.csv b/calliope/test/model_conversion/national_scale/model_config/data/csp_r.csv deleted file mode 100644 index 29ee4ccc3..000000000 --- a/calliope/test/model_conversion/national_scale/model_config/data/csp_r.csv +++ /dev/null @@ -1,49 +0,0 @@ -,region1-1,region1-2,region1-3 -0,0.0,0.0,0.0 -1,0.0,0.0,0.0 -2,0.0,0.0,0.0 -3,0.0,0.0,0.0 -4,0.0,0.0,0.0 -5,0.0,0.0,0.0 -6,0.0,0.0,0.0 -7,0.02106,0.009056000000000002,0.0 -8,0.263805,0.096755,0.0 -9,0.43403699999999995,0.24535099999999999,0.026837 -10,0.5182769999999999,0.120591,0.171912 -11,0.531398,0.044248,0.27008499999999996 -12,0.5199640000000001,0.020565,0.295433 -13,0.451715,0.0,0.24085299999999998 -14,0.304444,0.0,0.106809 -15,0.062078999999999995,0.0,0.0 -16,0.0,0.0,0.0 -17,0.0,0.0,0.0 -18,0.0,0.0,0.0 -19,0.0,0.0,0.0 -20,0.0,0.0,0.0 -21,0.0,0.0,0.0 -22,0.0,0.0,0.0 -23,0.0,0.0,0.0 -24,0.0,0.0,0.0 -25,0.0,0.0,0.0 -26,0.0,0.0,0.0 -27,0.0,0.0,0.0 -28,0.0,0.0,0.0 -29,0.0,0.0,0.0 -30,0.0,0.0,0.0 -31,0.018765999999999998,0.096031,0.0 -32,0.257264,0.144047,0.0 -33,0.425005,0.098728,0.0 -34,0.510026,0.0,0.12358799999999999 -35,0.520726,0.001851,0.286832 -36,0.5140790000000001,0.0,0.285821 -37,0.44711,0.0,0.21121099999999998 -38,0.298619,0.0,0.113541 -39,0.06490399999999999,0.0,0.0 -40,0.0,0.0,0.0 -41,0.0,0.0,0.0 -42,0.0,0.0,0.0 -43,0.0,0.0,0.0 -44,0.0,0.0,0.0 -45,0.0,0.0,0.0 -46,0.0,0.0,0.0 -47,0.0,0.0,0.0 diff --git a/calliope/test/model_conversion/national_scale/model_config/data/demand-1.csv b/calliope/test/model_conversion/national_scale/model_config/data/demand-1.csv deleted file mode 100644 index d36096995..000000000 --- a/calliope/test/model_conversion/national_scale/model_config/data/demand-1.csv +++ /dev/null @@ -1,49 +0,0 @@ -,region1 -0,-1580280 -1,-1524215 -2,-1483166 -3,-1445190 -4,-1444975 -5,-1480205 -6,-1522795 -7,-1578123 -8,-1630638 -9,-1679404 -10,-1693540 -11,-1687598 -12,-1693571 -13,-1714887 -14,-1788937 -15,-1885392 -16,-1975820 -17,-1997830 -18,-1946237 -19,-1889341 -20,-1822851 -21,-1719294 -22,-1625102 -23,-1565667 -24,-1524446 -25,-1508993 -26,-1514860 -27,-1552608 -28,-1677047 -29,-1830850 -30,-1941396 -31,-2012018 -32,-2060581 -33,-2097656 -34,-2095969 -35,-2084733 -36,-2077134 -37,-2095375 -38,-2154679 -39,-2235576 -40,-2301214 -41,-2302376 -42,-2208150 -43,-2111953 -44,-2012825 -45,-1877927 -46,-1765100 -47,-1692912 diff --git a/calliope/test/model_conversion/national_scale/model_config/data/demand-2.csv b/calliope/test/model_conversion/national_scale/model_config/data/demand-2.csv deleted file mode 100644 index e151a1e75..000000000 --- a/calliope/test/model_conversion/national_scale/model_config/data/demand-2.csv +++ /dev/null @@ -1,49 +0,0 @@ -,region2 -0,-1127049 -1,-1065574 -2,-1045082 -3,-1065574 -4,-1086066 -5,-1086066 -6,-1106557 -7,-1147541 -8,-1229508 -9,-1229508 -10,-1209016 -11,-1209016 -12,-1188525 -13,-1168033 -14,-1147541 -15,-1229508 -16,-1454918 -17,-1434426 -18,-1393443 -19,-1372951 -20,-1311475 -21,-1229508 -22,-1127049 -23,-1147541 -24,-1127049 -25,-1065574 -26,-1045082 -27,-1065574 -28,-1086066 -29,-1086066 -30,-1106557 -31,-1147541 -32,-1229508 -33,-1229508 -34,-1209016 -35,-1209016 -36,-1188525 -37,-1168033 -38,-1147541 -39,-1229508 -40,-1454918 -41,-1434426 -42,-1393443 -43,-1372951 -44,-1311475 -45,-1229508 -46,-1127049 -47,-1147541 diff --git a/calliope/test/model_conversion/national_scale/model_config/data/set_t.csv b/calliope/test/model_conversion/national_scale/model_config/data/set_t.csv deleted file mode 100644 index 7725762dc..000000000 --- a/calliope/test/model_conversion/national_scale/model_config/data/set_t.csv +++ /dev/null @@ -1,48 +0,0 @@ -0,2005-01-01 00:00:00 -1,2005-01-01 01:00:00 -2,2005-01-01 02:00:00 -3,2005-01-01 03:00:00 -4,2005-01-01 04:00:00 -5,2005-01-01 05:00:00 -6,2005-01-01 06:00:00 -7,2005-01-01 07:00:00 -8,2005-01-01 08:00:00 -9,2005-01-01 09:00:00 -10,2005-01-01 10:00:00 -11,2005-01-01 11:00:00 -12,2005-01-01 12:00:00 -13,2005-01-01 13:00:00 -14,2005-01-01 14:00:00 -15,2005-01-01 15:00:00 -16,2005-01-01 16:00:00 -17,2005-01-01 17:00:00 -18,2005-01-01 18:00:00 -19,2005-01-01 19:00:00 -20,2005-01-01 20:00:00 -21,2005-01-01 21:00:00 -22,2005-01-01 22:00:00 -23,2005-01-01 23:00:00 -24,2005-01-02 00:00:00 -25,2005-01-02 01:00:00 -26,2005-01-02 02:00:00 -27,2005-01-02 03:00:00 -28,2005-01-02 04:00:00 -29,2005-01-02 05:00:00 -30,2005-01-02 06:00:00 -31,2005-01-02 07:00:00 -32,2005-01-02 08:00:00 -33,2005-01-02 09:00:00 -34,2005-01-02 10:00:00 -35,2005-01-02 11:00:00 -36,2005-01-02 12:00:00 -37,2005-01-02 13:00:00 -38,2005-01-02 14:00:00 -39,2005-01-02 15:00:00 -40,2005-01-02 16:00:00 -41,2005-01-02 17:00:00 -42,2005-01-02 18:00:00 -43,2005-01-02 19:00:00 -44,2005-01-02 20:00:00 -45,2005-01-02 21:00:00 -46,2005-01-02 22:00:00 -47,2005-01-02 23:00:00 diff --git a/calliope/test/model_conversion/national_scale/model_config/locations.yaml b/calliope/test/model_conversion/national_scale/model_config/locations.yaml deleted file mode 100644 index 46762c1da..000000000 --- a/calliope/test/model_conversion/national_scale/model_config/locations.yaml +++ /dev/null @@ -1,64 +0,0 @@ -## -# nodes -## - -nodes: - region1: - techs: ["demand_power", "unmet_demand_power", "ccgt"] - override: - demand_power: - x_map: "region1: demand" - constraints: - r: file=demand-1.csv - r_scale: 30 - ccgt: - constraints: - e_cap.max: 30000 # increased to ensure no unmet_demand in first timestep - - region2: - techs: - ["demand_power", "unmet_demand_power", "battery", "dummy_demand_power"] - override: - demand_power: - x_map: "region2: demand" - constraints: - r: file=demand-2.csv - r_scale: 220 - dummy_demand_power: - constraints: - r_scale_to_peak: -5000 - - region1-1,region1-2,region1-3: - within: region1 - techs: ["csp"] - -## -# TRANSMISSION CAPACITIES -## - -links: - region1,region2: - ac_transmission: - constraints: - e_cap.max: 10000 - -## -# METADATA -## - -metadata: - # map boundary defined by the lower left and upper right of the square - map_boundary: - lower_left: - lat: 35 - lon: -10 - upper_right: - lat: 45 - lon: 5 - - node_coordinates: # lat, lon coordinates in a dictionary - region1: { lat: 40, lon: -2 } - region2: { lat: 40, lon: -8 } - region1-1: { lat: 41, lon: -2 } - region1-2: { lat: 39, lon: -1 } - region1-3: { lat: 39, lon: -2 } diff --git a/calliope/test/model_conversion/national_scale/model_config/model.yaml b/calliope/test/model_conversion/national_scale/model_config/model.yaml deleted file mode 100644 index 5cbece328..000000000 --- a/calliope/test/model_conversion/national_scale/model_config/model.yaml +++ /dev/null @@ -1,45 +0,0 @@ -## -# IMPORT OTHER FILES -## - -# Can either be paths relative to this file, or absolute paths - -import: - - "techs.yaml" - - "locations.yaml" - -## -# MODEL NAME -## - -name: "Test model" - -## -# DATASET PATH -## - -# Can either be a path relative to this file, or an absolute path - -data_path: "data" - -## -# OBJECTIVE FUNCTION -## - -# 'constraints.objective.objective_cost_minimization' is used by default -# objective: - -## -# ADDITIONAL CONSTRAINTS -## - -constraints: - - constraints.optional.ramping_rate - -## -# OTHER MODEL-WIDE OPTIONS -## - -system_margin: - power: 0 - heat: 0 diff --git a/calliope/test/model_conversion/national_scale/model_config/techs.yaml b/calliope/test/model_conversion/national_scale/model_config/techs.yaml deleted file mode 100644 index 1bf8a85b9..000000000 --- a/calliope/test/model_conversion/national_scale/model_config/techs.yaml +++ /dev/null @@ -1,98 +0,0 @@ -## -# TECHNOLOGY DEFINITIONS -## - -techs: - renewable_supply_plus: - name: "Renewable supply" - parent: supply_plus - carrier_out: "power" - - ## - # Supply - ## - ccgt: - name: "Combined cycle gas turbine" - color: "#FDC97D" - stack_weight: 200 - parent: supply - carrier_out: power - constraints: - r: inf - e_eff: 0.5 - e_cap.max: 40000 # kW - costs: - monetary: - e_cap: 750 # USD per kW - om_fuel: 0.02 # USD per kWh - csp: - name: "Concentrating solar power" - color: "#99CB48" - stack_weight: 100 - parent: renewable_supply_plus - constraints: - use_s_time: true - s_time.max: 24 - s_loss: 0.002 - r: file # Will look for `csp_r.csv` in data directory - e_eff: 0.4 - p_eff: 0.9 - r_area.max: inf - e_cap.max: 10000 - costs: - monetary: - s_cap: 50 - r_area: 200 - r_cap: 200 - e_cap: 1000 - om_var: 0.002 - depreciation: - monetary: - interest: 0.12 - - ## - # Storage - ## - battery: - name: "Battery storage" - color: "#DC5CE5" - parent: storage - carrier: power - constraints: - e_cap.max: 1000 # kW - s_cap.max: inf - c_rate: 4 - e_eff: 0.95 # 0.95 * 0.95 = 0.9025 round trip efficiency - s_loss: 0 # No loss over time assumed - costs: - monetary: - s_cap: 200 # USD per kWh storage capacity - ## - # Demand - ## - demand_power: - name: "Power demand" - parent: demand - carrier: power - dummy_demand_power: - name: "DUMMY power demand" - parent: demand - carrier: power - unmet_demand_power: - name: "Unmet power demand" - parent: unmet_demand - carrier: power - - ## - # Transmission - ## - ac_transmission: - name: "AC power transmission" - parent: transmission - carrier: power - constraints: - e_eff: 0.85 - costs: - monetary: - e_cap: 200 - om_var: 0.002 diff --git a/calliope/test/model_conversion/national_scale/run.yaml b/calliope/test/model_conversion/national_scale/run.yaml deleted file mode 100644 index 848babbb7..000000000 --- a/calliope/test/model_conversion/national_scale/run.yaml +++ /dev/null @@ -1,73 +0,0 @@ -## -# RUN SETTINGS -## - -name: "Test run" # Run name -- distinct from model name! - -model: "model_config/model.yaml" - -output: # Only used if run via the 'calliope run' command-line tool - format: csv # Choices: netcdf, csv - path: "Output" # Will be created if it doesn't exist - -mode: plan # Choices: plan, operate - -solver: cbc - -## -# PARALLEL RUN SETTINGS -## - -# Ignored unless run via the 'calliope generate' tool - -parallel: - name: example-model-national - environment: bsub # Choices: bsub, qsub - pre_run: # Commands to run before executing model - post_run: # Commands to run after executing model - iterations: - - subset_t: ["2005-01-01", "2005-01-31"] - override.nodes.r1.techs: ["demand", "unmet_demand", "ccgt"] - - subset_t: ["2005-02-01", "2005-02-31"] - override.nodes.r1.techs: ["demand", "unmet_demand"] - resources: # Request resources on a computing cluster - threads: # Non-default number of threads - wall_time: # Run time (minutes) - memory: # Working memory (MB) - -## -# TIME RESOLUTION ADJUSTMENT -## - -# time: -# resolution: 6 # Reduce rest of data to 6-hourly timesteps -# masks: # Look for week where CSP output is minimal -# - function: mask_extreme_week -# options: {what: min, tech: csp} -# - -## -# SUBSETS -## - -# Leave any of these empty to disable subsetting - -subset_y: [] # Subset of technologies -subset_x: [] # Subset of nodes -subset_t: ["2005-01-01", "2005-01-02"] # Subset of timesteps - -## -# MODEL SETTINGS OVERRIDE -## - -# Override anything in the model configuration - -override: - -## -# DEBUG OPTIONS -## - -debug: - keep_temp_files: false # Keep temporary files - symbolic_solver_labels: false # Use human-readable component labels? (slower) diff --git a/doc/_static/notebooks/calliope_model_object.ipynb b/doc/_static/notebooks/calliope_model_object.ipynb index 2a3f7bbd7..b76253ad8 100644 --- a/doc/_static/notebooks/calliope_model_object.ipynb +++ b/doc/_static/notebooks/calliope_model_object.ipynb @@ -6,9 +6,8 @@ "metadata": {}, "outputs": [], "source": [ - "import pandas as pd\n", - "\n", "import calliope\n", + "import pandas as pd\n", "\n", "calliope.set_log_verbosity(\"INFO\", include_solver_output=False)" ] @@ -125,7 +124,7 @@ "source": [ "# All locations now hold all information about a technology at that location\n", "\n", - "m._model_run[\"locations\"][\"X2\"][\"techs\"][\"pv\"]" + "m._model_run[\"nodes\"][\"X2\"][\"techs\"][\"pv\"]" ] }, { @@ -160,124 +159,7 @@ "source": [ "# This includes location-specific overrides, such as energy_cap_max of 50 for the pv technology at location X3\n", "\n", - "m._model_run[\"locations\"][\"X3\"][\"techs\"][\"pv\"]" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "['X3::power_lines:X1',\n", - " 'X1::supply_gas',\n", - " 'X3::boiler',\n", - " 'X3::pv',\n", - " 'X2::pv',\n", - " 'X1::supply_grid_power',\n", - " 'X1::chp',\n", - " 'X2::power_lines:X1',\n", - " 'X1::power_lines:X2',\n", - " 'X3::demand_heat',\n", - " 'X2::heat_pipes:N1',\n", - " 'X3::heat_pipes:N1',\n", - " 'X1::pv',\n", - " 'X1::power_lines:X3',\n", - " 'X1::demand_heat',\n", - " 'N1::heat_pipes:X3',\n", - " 'X2::supply_gas',\n", - " 'X2::demand_electricity',\n", - " 'N1::heat_pipes:X2',\n", - " 'X2::demand_heat',\n", - " 'X1::demand_electricity',\n", - " 'N1::heat_pipes:X1',\n", - " 'X2::boiler',\n", - " 'X1::heat_pipes:N1',\n", - " 'X3::supply_gas',\n", - " 'X3::demand_electricity']" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# All sets have also been collated.\n", - "# locations and technologies are concatenated into loc::tech sets,\n", - "# to create a dense matrix and smaller overall model size\n", - "\n", - "m._model_run[\"sets\"][\"loc_techs\"]" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "['X3::power_lines:X1',\n", - " 'X1::supply_gas',\n", - " 'X3::boiler',\n", - " 'X3::pv',\n", - " 'X2::pv',\n", - " 'X1::supply_grid_power',\n", - " 'X1::chp',\n", - " 'X2::power_lines:X1',\n", - " 'X1::power_lines:X2',\n", - " 'X3::demand_heat',\n", - " 'X2::heat_pipes:N1',\n", - " 'X3::heat_pipes:N1',\n", - " 'X1::pv',\n", - " 'X1::power_lines:X3',\n", - " 'X1::demand_heat',\n", - " 'N1::heat_pipes:X3',\n", - " 'X2::supply_gas',\n", - " 'X2::demand_electricity',\n", - " 'N1::heat_pipes:X2',\n", - " 'X2::demand_heat',\n", - " 'X1::demand_electricity',\n", - " 'N1::heat_pipes:X1',\n", - " 'X2::boiler',\n", - " 'X1::heat_pipes:N1',\n", - " 'X3::supply_gas',\n", - " 'X3::demand_electricity']" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# For every constraint, a set of loc_techs (or loc_tech_carriers) is prepared,\n", - "# so we only build the constraint over that set\n", - "\n", - "m._model_run[\"constraint_sets\"][\"loc_techs_energy_capacity_constraint\"]" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "['X2::pv', 'X3::pv', 'X1::pv']" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m._model_run[\"constraint_sets\"][\"loc_techs_resource_area_constraint\"]" + "m._model_run[\"nodes\"][\"X3\"][\"techs\"][\"pv\"]" ] }, { @@ -3701,440 +3583,6 @@ "m._model_data.energy_cap_max.loc[{\"loc_techs\": \"X3::pv\"}]" ] }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
<xarray.DataArray 'loc_techs_energy_capacity_constraint' (\n",
-       "                                                          loc_techs_energy_capacity_constraint: 26)>\n",
-       "array(['X3::power_lines:X1', 'X1::supply_gas', 'X3::boiler', 'X3::pv',\n",
-       "       'X2::pv', 'X1::supply_grid_power', 'X1::chp', 'X2::power_lines:X1',\n",
-       "       'X1::power_lines:X2', 'X3::demand_heat', 'X2::heat_pipes:N1',\n",
-       "       'X3::heat_pipes:N1', 'X1::pv', 'X1::power_lines:X3', 'X1::demand_heat',\n",
-       "       'N1::heat_pipes:X3', 'X2::supply_gas', 'X2::demand_electricity',\n",
-       "       'N1::heat_pipes:X2', 'X2::demand_heat', 'X1::demand_electricity',\n",
-       "       'N1::heat_pipes:X1', 'X2::boiler', 'X1::heat_pipes:N1',\n",
-       "       'X3::supply_gas', 'X3::demand_electricity'], dtype='<U22')\n",
-       "Coordinates:\n",
-       "  * loc_techs_energy_capacity_constraint  (loc_techs_energy_capacity_constraint) <U22 ...
" - ], - "text/plain": [ - "\n", - "array(['X3::power_lines:X1', 'X1::supply_gas', 'X3::boiler', 'X3::pv',\n", - " 'X2::pv', 'X1::supply_grid_power', 'X1::chp', 'X2::power_lines:X1',\n", - " 'X1::power_lines:X2', 'X3::demand_heat', 'X2::heat_pipes:N1',\n", - " 'X3::heat_pipes:N1', 'X1::pv', 'X1::power_lines:X3', 'X1::demand_heat',\n", - " 'N1::heat_pipes:X3', 'X2::supply_gas', 'X2::demand_electricity',\n", - " 'N1::heat_pipes:X2', 'X2::demand_heat', 'X1::demand_electricity',\n", - " 'N1::heat_pipes:X1', 'X2::boiler', 'X1::heat_pipes:N1',\n", - " 'X3::supply_gas', 'X3::demand_electricity'], dtype=' 2\u001b[0m m\u001b[39m.\u001b[39;49minputs\u001b[39m.\u001b[39;49mloc_techs_energy_capacity_constraint\n", - "File \u001b[0;32m~/miniconda3/envs/calliope_dev/lib/python3.9/site-packages/xarray/core/common.py:239\u001b[0m, in \u001b[0;36mAttrAccessMixin.__getattr__\u001b[0;34m(self, name)\u001b[0m\n\u001b[1;32m 237\u001b[0m \u001b[39mwith\u001b[39;00m suppress(\u001b[39mKeyError\u001b[39;00m):\n\u001b[1;32m 238\u001b[0m \u001b[39mreturn\u001b[39;00m source[name]\n\u001b[0;32m--> 239\u001b[0m \u001b[39mraise\u001b[39;00m \u001b[39mAttributeError\u001b[39;00m(\n\u001b[1;32m 240\u001b[0m \u001b[39mf\u001b[39m\u001b[39m\"\u001b[39m\u001b[39m{\u001b[39;00m\u001b[39mtype\u001b[39m(\u001b[39mself\u001b[39m)\u001b[39m.\u001b[39m\u001b[39m__name__\u001b[39m\u001b[39m!r}\u001b[39;00m\u001b[39m object has no attribute \u001b[39m\u001b[39m{\u001b[39;00mname\u001b[39m!r}\u001b[39;00m\u001b[39m\"\u001b[39m\n\u001b[1;32m 241\u001b[0m )\n", - "\u001b[0;31mAttributeError\u001b[0m: 'Dataset' object has no attribute 'loc_techs_energy_capacity_constraint'" - ] - } - ], - "source": [ - "# It is these constraint sets that we cannot see in m.inputs\n", - "m.inputs.loc_techs_energy_capacity_constraint" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -5865,9 +5313,7 @@ "source": [ "# >2 dimensions cannot be easily viewed in a pandas dataframe, unless a MultiIndex is used.\n", "# To view a 4-dimensional result, we can use `to_series()`\n", - "m.get_formatted_array(\n", - " \"carrier_prod\"\n", - ").to_series().dropna() # drop_na() removes all NaN values" + "m.results(\"carrier_prod\").to_series().dropna() # drop_na() removes all NaN values" ] }, { diff --git a/doc/_static/notebooks/milp.ipynb b/doc/_static/notebooks/milp.ipynb index ce1dd0c07..5c177e662 100644 --- a/doc/_static/notebooks/milp.ipynb +++ b/doc/_static/notebooks/milp.ipynb @@ -912,9 +912,9 @@ } ], "source": [ - "# Individual data variables can be accessed easily, `to_pandas()` reformats the data to look nicer\n", + "# Individual data variables can be accessed easily, `to_series()` reformats the data to look nicer\n", "# Here we look at one of the MILP overrides that we have added, the fixed `purchase` cost\n", - "model.inputs.cost_purchase.to_pandas().dropna(axis=1)" + "model.inputs.cost_purchase.to_series().dropna()" ] }, { @@ -2084,7 +2084,7 @@ ], "source": [ "# We can sum operating units of CHP over all locations and turn the result into a pandas DataFrame\n", - "df_units = model.get_formatted_array(\"operating_units\").sum(\"locs\").to_pandas().T\n", + "df_units = model.get_formatted_array(\"operating_units\").sum(\"nodes\").to_series()\n", "\n", "# The information about the dataframe tells us about the amount of data it holds in the index and in each column\n", "df_units.info()" diff --git a/doc/_static/notebooks/national_scale.ipynb b/doc/_static/notebooks/national_scale.ipynb index 6593b71a7..cfdd1bb98 100644 --- a/doc/_static/notebooks/national_scale.ipynb +++ b/doc/_static/notebooks/national_scale.ipynb @@ -1097,8 +1097,8 @@ } ], "source": [ - "# Individual data variables can be accessed easily, `to_pandas()` reformats the data to look nicer\n", - "model.inputs.resource.to_pandas()" + "# Individual data variables can be accessed easily, `to_series()` reformats the data to look nicer\n", + "model.inputs.resource.to_series().dropna()" ] }, { @@ -1275,7 +1275,7 @@ "source": [ "# To reformat the array, deconcatenating loc_techs / loc_tech_carriers, you can use model.get_formatted_array()\n", "# You can then apply loc/tech/carrier only operations, like summing information over locations:\n", - "model.get_formatted_array(\"resource\").sum(\"locs\").to_pandas()" + "model.get_formatted_array(\"resource\").sum(\"nodes\").to_series().unstack(\"techs\")" ] }, { @@ -2369,9 +2369,8 @@ "df_power = (\n", " model.get_formatted_array(\"carrier_prod\")\n", " .loc[{\"carriers\": \"power\"}]\n", - " .sum(\"locs\")\n", - " .to_pandas()\n", - " .T\n", + " .sum(\"nodes\")\n", + " .to_series()\n", ")\n", "\n", "# The information about the dataframe tells us about the amount of data it holds in the index and in each column\n", @@ -8311,7 +8310,9 @@ "# notice all the NaN values which appear when seperating loc::techs to locs and techs.\n", "# Any NaN value means we never considered that combination of `loc` and `tech` for the variable\n", "\n", - "costs = model.get_formatted_array(\"cost\").loc[{\"costs\": \"monetary\"}].to_pandas()\n", + "costs = (\n", + " model.get_formatted_array(\"cost\").loc[{\"costs\": \"monetary\"}].to_series().dropna()\n", + ")\n", "costs" ] }, @@ -8349,7 +8350,7 @@ "\n", "lcoes = model.results.systemwide_levelised_cost.loc[\n", " {\"carriers\": \"power\", \"costs\": \"monetary\"}\n", - "].to_pandas()\n", + "].to_series()\n", "lcoes" ] }, diff --git a/doc/api/api.rst b/doc/api/api.rst index 318157f59..91aed705b 100644 --- a/doc/api/api.rst +++ b/doc/api/api.rst @@ -11,6 +11,14 @@ Model class .. autoclass:: calliope.Model :members: +.. _api_backend_interface: + +Optimisation backend interface +============================== + +.. automodule:: calliope.backend.backends + :members: BackendModel + .. _api_time_masks: Time series diff --git a/doc/conf.py b/doc/conf.py index 999dd7273..56ce8d7a6 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -11,7 +11,7 @@ # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. -sys.path.insert(0, os.path.abspath("..")) +sys.path.insert(0, os.path.abspath("../src")) sys.path.insert(0, os.path.abspath(".")) sys.path.append(os.path.abspath("_themes")) @@ -37,7 +37,7 @@ __version__ = "" # Sets the __version__ variable -exec(open("../calliope/_version.py").read()) +exec(open("../src/calliope/_version.py").read()) # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the diff --git a/doc/helpers/generate_math.py b/doc/helpers/generate_math.py index 0d076931b..d2de084fa 100644 --- a/doc/helpers/generate_math.py +++ b/doc/helpers/generate_math.py @@ -10,9 +10,8 @@ """ from pathlib import Path -import pandas as pd - import calliope +import pandas as pd BASEPATH = Path(__file__).resolve().parent STATICPATH = BASEPATH / ".." / "_static" @@ -73,7 +72,7 @@ def generate_model_config() -> dict[str, dict]: Parameters that can be defined over a timeseries are forced to be defined over a timeseries. Accordingly, the parameters will have "timesteps" in their dimensions in the formulation. """ defaults = calliope.AttrDict.from_yaml( - BASEPATH / ".." / ".." / "calliope" / "config" / "defaults.yaml" + BASEPATH / ".." / ".." / "src" / "calliope" / "config" / "defaults.yaml" ) allowed_: dict[str, dict] = {i: {"all": set()} for i in ["costs", "constraints"]} diff --git a/doc/helpers/generate_readable_schema.py b/doc/helpers/generate_readable_schema.py index 6bfdc751e..f5df87583 100644 --- a/doc/helpers/generate_readable_schema.py +++ b/doc/helpers/generate_readable_schema.py @@ -50,6 +50,6 @@ def customise_markdown(lines: list[str]) -> list[str]: def process(): - math_schema = Path("../calliope/config/math_schema.yaml") + math_schema = Path("../src/calliope/config/math_schema.yaml") assert math_schema.is_file() schema_to_md(math_schema, "./user/includes/math_schema.md") diff --git a/doc/helpers/generate_tables.py b/doc/helpers/generate_tables.py index 85adda12a..56f0cbbc5 100644 --- a/doc/helpers/generate_tables.py +++ b/doc/helpers/generate_tables.py @@ -43,7 +43,7 @@ def write_csv(filename, iterable): def process(): - with open("../calliope/config/defaults.yaml", "r") as f: + with open("../src/calliope/config/defaults.yaml", "r") as f: defaults = yaml.round_trip_load(f) write_csv( diff --git a/doc/user/advanced_constraints.rst b/doc/user/advanced_constraints.rst index ec015d2dd..9fd1cbccd 100644 --- a/doc/user/advanced_constraints.rst +++ b/doc/user/advanced_constraints.rst @@ -338,7 +338,7 @@ The ``asynchronous_prod_con`` binary constraint ensures that only one of ``carri This constraint can be applied to storage or transmission technologies. This example shows use with a heat transmission technology: -.. literalinclude:: ../../calliope/example_models/urban_scale/scenarios.yaml +.. literalinclude:: ../../src/calliope/example_models/urban_scale/scenarios.yaml :language: yaml :dedent: 4 :start-after: # heat_pipes-start diff --git a/doc/user/develop.rst b/doc/user/develop.rst index d1a22bce1..f78be1bd6 100644 --- a/doc/user/develop.rst +++ b/doc/user/develop.rst @@ -16,7 +16,7 @@ Also see the list of `open issues `. +.. Note:: Most of our tests depend on having the CBC solver also installed, as we have found it to be more stable than GPLK. If you are running on a Unix system, then you can run ``mamba install coincbc`` to also install the CBC solver. To install solvers other than CBC, and for Windows systems, see our :ref:`solver installation instructions `. We use the code formatter `black `_ and before you contribute any code, you should ensure that you have run it through black. If you don't have a process for doing this already, you can install our configured `pre-commit `_ hook which will automatically run black on each commit: @@ -157,21 +155,14 @@ When making a change you may need to run your tests multiple times until you hav Since the whole test suite takes ~25 minutes to run, you can do some things to speed up the process: #. parallelise tests - If you have installed the calliope development environment, it includes the `pytest-xdist `_ package, which allows you to run tests in parallel. - To do so with calliope with the maximum available threads on your device, run: - - .. code-block:: fishshell - - $ pytest -n=auto --dist=loadscope - - `--dist=loadscope` ensures that _within_ test classes, the tests run in series, since some might depend on changes made to `fixtures `_ by previous tests. + If you have installed the calliope development environment, it includes the `pytest-xdist `_ package and will run tests in parallel on as many cores as possible by default. #. run specific tests. E.g., for `test_function_name` inside `test_filename.py` and under the class name `TestClassName`, you would run: .. code-block:: fishshell - $ pytest calliope/test/test_filename.py::TestClassName::test_function_name + $ pytest tests/test_filename.py::TestClassName::test_function_name You can also run only those tests that previously failed with `--lf`: @@ -179,6 +170,12 @@ Since the whole test suite takes ~25 minutes to run, you can do some things to s $ pytest --lf + You can also avoid running the tests on the example notebooks by pointing only to the test directory: + + .. code-block:: fishshell + + $ pytest tests/ + #. Avoid time intensive tests. You can run most of the test suite but avoid running the more time intensive tests (which are mostly concerned with timeseries clustering) by activating the following pytest marker: diff --git a/doc/user/installation.rst b/doc/user/installation.rst index 741038b1a..727c760b0 100644 --- a/doc/user/installation.rst +++ b/doc/user/installation.rst @@ -19,15 +19,15 @@ Running Calliope requires four things: Recommended installation method =============================== -The easiest way to get a working Calliope installation is to use the free ``conda`` package manager, which can install all of the four things described above in a single step. +The easiest way to get a working Calliope installation is to use the free ``mamba`` package manager, which can install all of the four things described above in a single step. -To get ``conda``, `download and install the "Miniconda" distribution for your operating system `_ (using the version for Python 3). +To get ``mamba``, `download and install the "Mambaforge" distribution for your operating system `_ (using the version for Python 3). -With Miniconda installed, you can create a new environment called ``"calliope"`` with all the necessary modules, including the free and open source GLPK solver, by running the following command in a terminal or command-line window +With mamba installed, you can create a new environment called ``calliope`` with all the necessary modules, including the free and open source GLPK solver, by running the following command in a terminal or command-line window .. code-block:: fishshell - $ conda create -c conda-forge -n calliope calliope + $ mamba create -c conda-forge -n calliope calliope This will install calliope with Python version 3.11. @@ -35,15 +35,11 @@ To use Calliope, you need to activate the ``calliope`` environment each time .. code-block:: fishshell - $ conda activate calliope + $ mamba activate calliope -You are now ready to use Calliope together with the free and open source GLPK solver. However, we recommend to not use this solver where possible, since it performs relatively poorly (both in solution time and stability of result). Indeed, our example models use the free and open source CBC solver instead, but installing it on Windows requires an extra step. Read the next section for more information on installing alternative solvers. - -.. note:: - - Windows users may have trouble with the recommended installation method, due to conda not solving the environment successfully. - If this occurs, we recommend using the more efficient reimplementation of ``conda``: `Mamba `_. - First install mamba in your base conda environment (``conda install -c conda-forge -n base mamba``), then proceed with the installation as before, simply using ``mamba`` in place of ``conda`` (``mamba create -c conda-forge -n calliope calliope``). +You are now ready to use Calliope together with the free and open source GLPK solver. +However, we recommend to not use this solver where possible, since it performs relatively poorly (both in solution time and stability of result). +Indeed, our example models use the free and open source CBC solver instead, but installing it on Windows requires an extra step. Read the next section for more information on installing alternative solvers. .. warning:: @@ -53,11 +49,11 @@ You are now ready to use Calliope together with the free and open source GLPK so Updating an existing installation ================================= -If following the recommended installation method above, the following command, assuming the conda environment is active, will update Calliope to the newest version +If following the recommended installation method above, the following command, assuming the mamba environment is active, will update Calliope to the newest version .. code-block:: fishshell - $ conda update -c conda-forge calliope + $ mamba update -c conda-forge calliope .. _install_solvers: @@ -69,7 +65,7 @@ You need at least one of the solvers supported by Pyomo installed. CBC (open-sou CBC --- -`CBC `_ is our recommended option if you want a free and open-source solver. CBC can be installed via conda on Linux and macOS by running ```conda install -c conda-forge coincbc```. Windows binary packages are somewhat more difficult to install, due to limited information on `the CBC website `_, but can be found within their `binary archive `_ and are included in their `package releases on GitHub `_. The GitHub releases are more up-to-date. We recommend you download the relevant binary for `CBC 2.10.8 `_ and add `cbc.exe` to a directory known to PATH (e.g. an Anaconda environment 'bin' directory). +`CBC `_ is our recommended option if you want a free and open-source solver. CBC can be installed via conda on Linux and macOS by running ```mamba install -c conda-forge coincbc```. Windows binary packages are somewhat more difficult to install, due to limited information on `the CBC website `_, but can be found within their `binary archive `_ and are included in their `package releases on GitHub `_. The GitHub releases are more up-to-date. We recommend you download the relevant binary for `CBC 2.10.8 `_ and add `cbc.exe` to a directory known to PATH (e.g. an Anaconda environment 'bin' directory). GLPK ---- @@ -81,7 +77,7 @@ Gurobi `Gurobi `_ is commercial but significantly faster than CBC and GLPK, which is relevant for larger problems. It needs a license to work, which can be obtained for free for academic use by creating an account on gurobi.com. -While Gurobi can be installed via conda (:sh:`conda install -c gurobi gurobi`) we recommend downloading and installing the installer from the `Gurobi website `_, as the conda package has repeatedly shown various issues. +While Gurobi can be installed via conda (:sh:`mamba install -c gurobi gurobi`) we recommend downloading and installing the installer from the `Gurobi website `_, as the conda package has repeatedly shown various issues. After installing, log on to the `Gurobi website `_ and obtain a (free academic or paid commercial) license, then activate it on your system via the instructions given online (using the ``grbgetkey`` command). diff --git a/doc/user/ref_example_models.rst b/doc/user/ref_example_models.rst index c89bda9a7..02ea67706 100644 --- a/doc/user/ref_example_models.rst +++ b/doc/user/ref_example_models.rst @@ -43,22 +43,22 @@ The layout of the model directory is as follows (``+`` denotes directories, ``-` ``model.yaml``: -.. literalinclude:: ../../calliope/example_models/national_scale/model.yaml +.. literalinclude:: ../../src/calliope/example_models/national_scale/model.yaml :language: yaml ``scenarios.yaml``: -.. literalinclude:: ../../calliope/example_models/national_scale/scenarios.yaml +.. literalinclude:: ../../src/calliope/example_models/national_scale/scenarios.yaml :language: yaml ``techs.yaml``: -.. literalinclude:: ../../calliope/example_models/national_scale/model_config/techs.yaml +.. literalinclude:: ../../src/calliope/example_models/national_scale/model_config/techs.yaml :language: yaml ``locations.yaml``: -.. literalinclude:: ../../calliope/example_models/national_scale/model_config/locations.yaml +.. literalinclude:: ../../src/calliope/example_models/national_scale/model_config/locations.yaml :language: yaml Urban-scale example @@ -73,20 +73,20 @@ Model settings ``model.yaml``: -.. literalinclude:: ../../calliope/example_models/urban_scale/model.yaml +.. literalinclude:: ../../src/calliope/example_models/urban_scale/model.yaml :language: yaml ``scenarios.yaml``: -.. literalinclude:: ../../calliope/example_models/urban_scale/scenarios.yaml +.. literalinclude:: ../../src/calliope/example_models/urban_scale/scenarios.yaml :language: yaml ``techs.yaml``: -.. literalinclude:: ../../calliope/example_models/urban_scale/model_config/techs.yaml +.. literalinclude:: ../../src/calliope/example_models/urban_scale/model_config/techs.yaml :language: yaml ``locations.yaml``: -.. literalinclude:: ../../calliope/example_models/urban_scale/model_config/locations.yaml +.. literalinclude:: ../../src/calliope/example_models/urban_scale/model_config/locations.yaml :language: yaml diff --git a/doc/user/tutorials_01_national.rst b/doc/user/tutorials_01_national.rst index 7eaca2079..337cf4c99 100644 --- a/doc/user/tutorials_01_national.rst +++ b/doc/user/tutorials_01_national.rst @@ -25,7 +25,7 @@ The first is ``ccgt`` (combined-cycle gas turbine), which serves as an example o The definition of this technology in the example model's configuration looks as follows: -.. literalinclude:: ../../calliope/example_models/national_scale/model_config/techs.yaml +.. literalinclude:: ../../src/calliope/example_models/national_scale/model_config/techs.yaml :language: yaml :dedent: 2 :start-after: # ccgt-start @@ -48,7 +48,7 @@ The second technology is ``csp`` (concentrating solar power), and serves as an e This definition in the example model's configuration is more verbose: -.. literalinclude:: ../../calliope/example_models/national_scale/model_config/techs.yaml +.. literalinclude:: ../../src/calliope/example_models/national_scale/model_config/techs.yaml :language: yaml :dedent: 2 :start-after: # csp-start @@ -68,7 +68,7 @@ The second location allows a limited amount of battery storage to be deployed to A storage node with an :math:`energy_{eff}` and :math:`storage_{loss}`. -.. literalinclude:: ../../calliope/example_models/national_scale/model_config/techs.yaml +.. literalinclude:: ../../src/calliope/example_models/national_scale/model_config/techs.yaml :language: yaml :dedent: 2 :start-after: # battery-start @@ -86,7 +86,7 @@ Three more technologies are needed for a simple model. First, a definition of po A simple demand node. -.. literalinclude:: ../../calliope/example_models/national_scale/model_config/techs.yaml +.. literalinclude:: ../../src/calliope/example_models/national_scale/model_config/techs.yaml :language: yaml :dedent: 2 :start-after: # demand-start @@ -101,7 +101,7 @@ What remains to set up is a simple transmission technology. Transmission technol A simple transmission node with an :math:`energy_{eff}`. -.. literalinclude:: ../../calliope/example_models/national_scale/model_config/techs.yaml +.. literalinclude:: ../../src/calliope/example_models/national_scale/model_config/techs.yaml :language: yaml :dedent: 2 :start-after: # transmission-start @@ -125,7 +125,7 @@ The technologies are set up in these locations as follows: Let's now look at the first location definition: -.. literalinclude:: ../../calliope/example_models/national_scale/model_config/locations.yaml +.. literalinclude:: ../../src/calliope/example_models/national_scale/model_config/locations.yaml :language: yaml :dedent: 2 :start-after: # region-1-start @@ -139,7 +139,7 @@ There are several things to note here: The remaining location definitions look like this: -.. literalinclude:: ../../calliope/example_models/national_scale/model_config/locations.yaml +.. literalinclude:: ../../src/calliope/example_models/national_scale/model_config/locations.yaml :language: yaml :dedent: 2 :start-after: # other-locs-start @@ -149,7 +149,7 @@ The remaining location definitions look like this: For transmission technologies, the model also needs to know which locations can be linked, and this is set up in the model configuration as follows: -.. literalinclude:: ../../calliope/example_models/national_scale/model_config/locations.yaml +.. literalinclude:: ../../src/calliope/example_models/national_scale/model_config/locations.yaml :language: yaml :dedent: 2 :start-after: # links-start diff --git a/doc/user/tutorials_02_urban.rst b/doc/user/tutorials_02_urban.rst index 5b154a61b..acd16e1b5 100644 --- a/doc/user/tutorials_02_urban.rst +++ b/doc/user/tutorials_02_urban.rst @@ -25,7 +25,7 @@ The first two are ``supply_gas`` and ``supply_grid_power``, referring to the sup The definition of these technologies in the example model's configuration looks as follows: -.. literalinclude:: ../../calliope/example_models/urban_scale/model_config/techs.yaml +.. literalinclude:: ../../src/calliope/example_models/urban_scale/model_config/techs.yaml :language: yaml :dedent: 2 :start-after: # supply-start @@ -39,7 +39,7 @@ In most cases, domestic PV panels are able to export excess energy to the nation The definition of this technology in the example model's configuration looks as follows: -.. literalinclude:: ../../calliope/example_models/urban_scale/model_config/techs.yaml +.. literalinclude:: ../../src/calliope/example_models/urban_scale/model_config/techs.yaml :language: yaml :dedent: 2 :start-after: # pv-start @@ -47,7 +47,7 @@ The definition of this technology in the example model's configuration looks as Finally, the parent of the PV technology is not ``supply_plus``, but rather ``supply_power_plus``. We use this to show the possibility of an intermediate technology group, which provides the information on the energy carrier (``electricity``) and the ultimate abstract base technology (``supply_plus``): -.. literalinclude:: ../../calliope/example_models/urban_scale/model_config/techs.yaml +.. literalinclude:: ../../src/calliope/example_models/urban_scale/model_config/techs.yaml :language: yaml :start-after: # supply_power_plus-start :end-before: # supply_power_plus-end @@ -68,7 +68,7 @@ The first is ``boiler`` (natural gas boiler), which serves as an example of a si The definition of this technology in the example model's configuration looks as follows: -.. literalinclude:: ../../calliope/example_models/urban_scale/model_config/techs.yaml +.. literalinclude:: ../../src/calliope/example_models/urban_scale/model_config/techs.yaml :language: yaml :dedent: 2 :start-after: # boiler-start @@ -86,7 +86,7 @@ The second technology is ``chp`` (combined heat and power), and serves as an exa This definition in the example model's configuration is more verbose: -.. literalinclude:: ../../calliope/example_models/urban_scale/model_config/techs.yaml +.. literalinclude:: ../../src/calliope/example_models/urban_scale/model_config/techs.yaml :language: yaml :dedent: 2 :start-after: # chp-start @@ -103,7 +103,7 @@ Demand technologies Electricity and heat demand are defined here: -.. literalinclude:: ../../calliope/example_models/urban_scale/model_config/techs.yaml +.. literalinclude:: ../../src/calliope/example_models/urban_scale/model_config/techs.yaml :language: yaml :dedent: 2 :start-after: # demand-start @@ -121,7 +121,7 @@ In this district, electricity and heat can be distributed between locations. Gas A simple transmission node with an :math:`energy_{eff}`. -.. literalinclude:: ../../calliope/example_models/urban_scale/model_config/techs.yaml +.. literalinclude:: ../../src/calliope/example_models/urban_scale/model_config/techs.yaml :language: yaml :dedent: 2 :start-after: # transmission-start @@ -144,7 +144,7 @@ The technologies are set up in these locations as follows: Let's now look at the first location definition: -.. literalinclude:: ../../calliope/example_models/urban_scale/model_config/locations.yaml +.. literalinclude:: ../../src/calliope/example_models/urban_scale/model_config/locations.yaml :language: yaml :dedent: 2 :start-after: # X1-start @@ -159,7 +159,7 @@ There are several things to note here: The remaining location definitions look like this: -.. literalinclude:: ../../calliope/example_models/urban_scale/model_config/locations.yaml +.. literalinclude:: ../../src/calliope/example_models/urban_scale/model_config/locations.yaml :language: yaml :dedent: 2 :start-after: # other-locs-start @@ -169,7 +169,7 @@ The remaining location definitions look like this: ``N1`` differs to the others by virtue of containing no technologies. It acts as a branching station for the heat network, allowing connections to one or both of ``X2`` and ``X3`` without double counting the pipeline from ``X1`` to ``N1``. Its definition look like this: -.. literalinclude:: ../../calliope/example_models/urban_scale/model_config/locations.yaml +.. literalinclude:: ../../src/calliope/example_models/urban_scale/model_config/locations.yaml :language: yaml :dedent: 2 :start-after: # N1-start @@ -177,7 +177,7 @@ The remaining location definitions look like this: For transmission technologies, the model also needs to know which locations can be linked, and this is set up in the model configuration as follows: -.. literalinclude:: ../../calliope/example_models/urban_scale/model_config/locations.yaml +.. literalinclude:: ../../src/calliope/example_models/urban_scale/model_config/locations.yaml :language: yaml :dedent: 2 :start-after: # links-start diff --git a/doc/user/tutorials_03_milp.rst b/doc/user/tutorials_03_milp.rst index 52773b920..046061086 100644 --- a/doc/user/tutorials_03_milp.rst +++ b/doc/user/tutorials_03_milp.rst @@ -10,7 +10,7 @@ Units The capacity of a technology is usually a continuous decision variable, which can be within the range of 0 and ``energy_cap_max`` (the maximum capacity of a technology). In this model, we introduce a unit limit on the CHP instead: -.. literalinclude:: ../../calliope/example_models/urban_scale/scenarios.yaml +.. literalinclude:: ../../src/calliope/example_models/urban_scale/scenarios.yaml :language: yaml :dedent: 4 :start-after: # chp-start @@ -23,7 +23,7 @@ Purchase cost The boiler does not have a unit limit, it still utilises the continuous variable for its capacity. However, we have introduced a ``purchase`` cost: -.. literalinclude:: ../../calliope/example_models/urban_scale/scenarios.yaml +.. literalinclude:: ../../src/calliope/example_models/urban_scale/scenarios.yaml :language: yaml :dedent: 4 :start-after: # boiler-start @@ -39,7 +39,7 @@ Asynchronous energy production/consumption The heat pipes which distribute thermal energy in the network may be prone to dissipating heat in an unphysical way. I.e. given that they have distribution losses associated with them, in any given timestep, a link could produce and consume energy in the same timestep, losing energy to the atmosphere in both instances, but having a net energy transmission of zero. This allows e.g. a CHP facility to overproduce heat to produce more cheap electricity, and have some way of dumping that heat. The ``asynchronous_prod_con`` binary constraint ensures this phenomenon is avoided: -.. literalinclude:: ../../calliope/example_models/urban_scale/scenarios.yaml +.. literalinclude:: ../../src/calliope/example_models/urban_scale/scenarios.yaml :language: yaml :dedent: 4 :start-after: # heat_pipes-start diff --git a/paper/codemeta.json b/paper/codemeta.json deleted file mode 100644 index abf27a669..000000000 --- a/paper/codemeta.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "@context": "https://raw.githubusercontent.com/codemeta/codemeta/master/codemeta.jsonld", - "@type": "Code", - "author": [ - { - "@id": "https://orcid.org/0000-0002-8420-9498", - "@type": "Person", - "name": "Stefan Pfenninger", - "affiliation": "ETH Zürich" - }, - { - "@id": "https://orcid.org/0000-0003-4044-6587", - "@type": "Person", - "name": "Bryn Pickering", - "affiliation": "University of Cambridge" - } - ], - "identifier": "https://doi.org/10.5281/zenodo.593292", - "codeRepository": "https://github.com/calliope-project/calliope", - "datePublished": "2018-06-04", - "dateModified": "2018-06-04", - "dateCreated": "2018-06-04", - "description": "A multi-scale energy systems modelling framework", - "keywords": "python, energy, optimisation, energy-system", - "license": "Apache 2.0", - "title": "Calliope", - "version": "0.6.2" -} diff --git a/paper/paper.bib b/paper/paper.bib deleted file mode 100644 index be42bce1f..000000000 --- a/paper/paper.bib +++ /dev/null @@ -1,78 +0,0 @@ -@inproceedings{Heussen2010, - title = {Energy storage in power system operation: The power nodes modeling framework}, - shorttitle = {Energy storage in power system operation}, - doi = {10.1109/ISGTEUROPE.2010.5638865}, - booktitle = {Innovative Smart Grid Technologies Conference {Europe} ({ISGT} {Europe}), 2010 {IEEE} {PES}}, - author = {Heussen, Kai and Koch, Stephan and Ulbig, Andreas and Andersson, Göran}, - year = {2010}, - pages = {1--8} -} - -@article{Pfenninger2015_1, - title = {Renewables, nuclear, or fossil fuels? Scenarios for {Great Britain}'s power system considering costs, emissions and import dependency}, - volume = {152}, - doi = {10.1016/j.apenergy.2015.04.102}, - journal = {Applied Energy}, - author = {Pfenninger, Stefan and Keirstead, James}, - year = {2015}, - pages = {83--93} -} - -@article{Pfenninger2015_2, - title = {Comparing concentrating solar and nuclear power as baseload providers using the example of {South Africa}}, - volume = {87}, - issn = {0360-5442}, - doi = {10.1016/j.energy.2015.04.077}, - urldate = {2015-06-13}, - journal = {Energy}, - author = {Pfenninger, Stefan and Keirstead, James}, - year = {2015}, - pages = {303--314} -} - -@inproceedings{Pickering2017, - title = {Applying Piecewise Linear Characteristic Curves in District Energy Optimisation}, - booktitle = {Proceedings of the 30th {ECOS} Conference, {San Diego}, {CA}, 2-6 July 2017}, - author = {Pickering, Bryn and Choudhary, Ruchi}, - year = {2017}, - howpublished = {\url{https://www.researchgate.net/publication/319334427_Applying_Piecewise_Linear_Characteristic_Curves_in_District_Energy_Optimisation}} -} - -@online{xarray, - author = {xarray}, - title = {xarray: N-D labeled arrays and datasets in {Python}}, - year = 2018, - url = {https://xarray.pydata.org/en/stable/}, - urldate = {2018-04-27} -} - -@online{pyomo, - author = {Pyomo}, - title = {Pyomo - Flexible modeling of optimization problems in {Python}}, - year = 2018, - url = {https://www.pyomo.org/}, - urldate = {2018-04-27} -} - -@online{plotly, - author = {Plotly}, - title = {Plotly - Modern Visualization for the Data Era}, - year = 2018, - url = {https://plot.ly/}, - urldate = {2018-04-27} -} - -@online{CalliopeGitHub, - author = {Pfenninger, Stefan and Pickering, Bryn}, - title = {Calliope}, - year = 2018, - url = {https://github.com/calliope-project/calliope}, - urldate = {2018-04-27} -} - -@misc{CalliopeZenodo, - author = {Pfenninger, Stefan and Pickering, Bryn}, - title = {Calliope}, - doi = {10.5281/zenodo.593292}, - howpublished = {\url{https://doi.org/10.5281/zenodo.593292}} -} diff --git a/paper/paper.md b/paper/paper.md deleted file mode 100644 index 3da7d05fe..000000000 --- a/paper/paper.md +++ /dev/null @@ -1,41 +0,0 @@ ---- -title: 'Calliope: a multi-scale energy systems modelling framework' -tags: - - energy - - optimisation - - python -authors: - - name: Stefan Pfenninger - orcid: 0000-0002-8420-9498 - affiliation: 1 - - name: Bryn Pickering - orcid: 0000-0003-4044-6587 - affiliation: 2 -affiliations: - - name: Department of Environmental Systems Science, ETH Zürich - index: 1 - - name: Department of Engineering, University of Cambridge - index: 2 -date: 30 April 2018 -bibliography: paper.bib ---- - -# Summary - -Energy system models create coherent quantitative descriptions of how energy is converted, transported, and consumed, at scales ranging from urban districts to entire continents. Formulating such models as optimisation problems allows a modeller to asses the effect of constraints, such as limited land availability for wind power deployment, the cost of battery electricity storage, or the elimination of fossil fuels from a country or a city, on the feasibility or cost of the modelled system. These models are particularly important in planning and policy-making for the transformation of the global energy system to address climate change. - -Calliope is a framework to build energy system models, designed to analyse systems with arbitrarily high spatial and temporal resolution, with a scale-agnostic mathematical formulation permitting analyses ranging from single urban districts to countries and continents. Its formulation of energy system components was influenced by the power nodes modelling framework by Heussen et al. [@Heussen2010], but generalised to consider energy carriers other than electricity. Calliope's key features include the ability to handle high spatial and temporal resolution and to easily run on high-performance computing systems. Its design cleanly separates the general framework (code) from the problem-specific model (data). It provides both a command-line interface and an API for programmatic use, to be useful both for users experienced with Python and those with no Python knowledge. - -A Calliope model consists of a collection of ``YAML`` and ``CSV`` files that define technologies, locations, links between locations, resource potentials, and other constraints. Calliope takes these files, constructs an optimisation problem, solves it, and reports results in the form of ``xarray`` [@xarray] Datasets, which can easily be saved to NetCDF files for further processing. It uses Pyomo [@pyomo] as a backend to interface with both open and commercial solvers, currently handling linear and mixed-integer problems, although nonlinear components could be implemented if necessary for new kinds of problems. Calliope's built-in tools allow interactive exploration of results using Plotly [@plotly], as shown in Figure 1. - -![Example time series visualisation of aggregated generation decisions at hourly time scale from a national-scale model of the UK power system, created with the Plotly-based visualisation tools in Calliope.](timeseries.pdf) - -Calliope has been used in various studies, for example, analyses of the national-scale power systems in Britain [@Pfenninger2015_1] and South Africa [@Pfenninger2015_2], and in methodological development for piecewise linearisation of characteristic technology performance curves for district-scale energy system analysis [@Pickering2017]. Ongoing research projects using Calliope include the effect of increased resilience to uncertain future demand and the interaction between local and national actors in the clean energy transition. - -Calliope is developed in the open on GitHub [@CalliopeGitHub] and each release is archived on Zenodo [@CalliopeZenodo]. - -# Acknowledgements - -The authors acknowledge funding via the European Research Council (grant StG 2012-313553), the Grantham Institute for Climate Change at Imperial College London, and the Engineering and Physical Sciences Research Council (ref EP/L016095/1). - -# References diff --git a/paper/timeseries.pdf b/paper/timeseries.pdf deleted file mode 100644 index 1f7abec43a89b1e8d482fe3fc4e6024fdea60ef1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 31307 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%0A4T(DN%6lF&Hu=d|34Mv|E-Mv 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

lsHo({}h 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 diff --git a/pyproject.toml b/pyproject.toml index fa2fecef2..f59cef5ab 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,39 @@ +[tool.pytest.ini_options] +minversion = "6.0" +# opts: +# `--dist=loadscope ` - run tests within classes in series +# `--strict-markers` - Raise error on unexpected pytest markers being used (add new markers to `markers` config) +# `-nauto` - parallelise over as many threads as possible (uses pytest-xdist). If debugging (`--pdb`), this will default to one thread. +# `--nbmake --nbmake-kernel=calliope` - test example notebooks using the "calliope" notebook kernel (uses nbmake) +# `--cov --cov-report=xml --cov-config=pyproject.toml` - generate coverage report for tests (uses pytest-cov; call `--no-cov` in CLI to switch off; `--cov-config` include to avoid bug) +addopts = "-rav --dist=loadscope --strict-markers -nauto --nbmake --nbmake-kernel=calliope --cov --cov-report=xml --cov-config=pyproject.toml" +# TODO: add testpath once notebooks are fixed: "doc/_static/notebooks" +testpaths = ["tests"] + +# to mark a test, decorate it with `@pytest.mark.[marker-name]` +markers = ["serial", "time_intensive"] +filterwarnings = [ + # https://github.com/pytest-dev/pytest-xdist/issues/825 + "ignore:The --rsyncdir command line argument and rsyncdirs config variable are deprecated.:DeprecationWarning", + "ignore:.*`group_share` constraints will be removed in v0.7.0.*:FutureWarning:", + "ignore:.*Plotting will no longer be available as a method.*:FutureWarning:", + "ignore:.*There will be no default cost class for the objective function in v0.7.0.*:FutureWarning:", + "ignore:.*`charge_rate` is renamed to `energy_cap_per_storage_cap_max` and will be removed in v0.7.0.*:FutureWarning:", + "ignore:.*Deprecated, pass a TempConstr or use Model.addLConstr.*:DeprecationWarning:pyomo", + "ignore:.*distutils Version classes are deprecated.*:DeprecationWarning:", + "ignore:.*`np.float` is a deprecated alias.*:DeprecationWarning:", +] + +[tool.coverage.run] +branch = true +source = ["src/"] + +[tool.coverage.html] +directory = "reports/coverage" + +[tool.coverage.xml] +output = "reports/coverage/coverage.xml" + [tool.black] line-length = 88 target-version = ['py37', 'py38'] @@ -46,3 +82,56 @@ convention = "google" [tool.ruff.pycodestyle] max-doc-length = 200 ignore-overlong-task-comments = true + +[tool.setuptools.packages.find] +where = ["src"] +include = ["calliope*"] + +[tool.setuptools.package-data] +calliope = ["config/*", "math/*", "example_models/**/*"] + +[tool.setuptools] +license-files = ["LICENSE", "CITATION"] + +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" + +[project] +name = "calliope" +authors = [ + { name = "Calliope contributors listed in AUTHORS", email = "stefan@pfenninger.org" }, +] +maintainers = [ + { name = "Stefan Pfenninger", email = "stefan@pfenninger.org" }, + { name = "Bryn Pickering", email = "17178478+brynpickering@users.noreply.github.com" }, +] +description = "A multi-scale energy systems modelling framework." +readme = "README.md" +requires-python = ">=3.9" +keywords = ["energy systems", "optimisation", "mathematical programming"] +license = { text = "Apache 2.0" } +classifiers = [ + "Intended Audience :: Science/Research", + "License :: OSI Approved :: Apache Software License", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3 :: Only", +] +dynamic = ["version", "dependencies", "optional-dependencies"] + +[tool.setuptools.dynamic] +dependencies = { file = ["requirements/base.txt"] } +version = { attr = "calliope._version.__version__" } + +[project.scripts] +calliope = "calliope.cli:cli" + +[tool.setuptools.dynamic.optional-dependencies] +dev = { file = ["requirements/dev.txt"] } + +[project.urls] +website = "https://www.callio.pe/" +repository = "https://github.com/calliope-project/calliope" +documentation = "https://calliope.readthedocs.io" +changelog = "https://github.com/calliope-project/calliope/changelog.rst" diff --git a/pytest b/pytest deleted file mode 100644 index e69de29bb..000000000 diff --git a/pytest.ini b/pytest.ini deleted file mode 100644 index a829721e8..000000000 --- a/pytest.ini +++ /dev/null @@ -1,12 +0,0 @@ -[pytest] -filterwarnings = - ignore:.*`group_share` constraints will be removed in v0.7.0.*:FutureWarning: - ignore:.*Plotting will no longer be available as a method.*:FutureWarning: - ignore:.*There will be no default cost class for the objective function in v0.7.0.*:FutureWarning: - ignore:.*`charge_rate` is renamed to `energy_cap_per_storage_cap_max` and will be removed in v0.7.0.*:FutureWarning: - ignore:.*Deprecated, pass a TempConstr or use Model.addLConstr.*:DeprecationWarning:pyomo - ignore:.*distutils Version classes are deprecated.*:DeprecationWarning: - ignore:.*`np.float` is a deprecated alias.*:DeprecationWarning: -markers = - serial - time_intensive \ No newline at end of file diff --git a/requirements.yml b/requirements.yml deleted file mode 100644 index 1854d3fc6..000000000 --- a/requirements.yml +++ /dev/null @@ -1,16 +0,0 @@ -name: calliope - -channels: - - conda-forge - -dependencies: - - bottleneck < 2 - - coverage >= 4.4 - - codecov < 3 - - glpk = 5.0 - - hdf5 < 2 - - libnetcdf < 5 - - pre-commit < 4 - - pytest-cov < 5 - - pytest-xdist < 4 # pytest distributed testing plugin - - pytest < 8 diff --git a/requirements.txt b/requirements/base.txt similarity index 93% rename from requirements.txt rename to requirements/base.txt index a11945da0..639f9448e 100644 --- a/requirements.txt +++ b/requirements/base.txt @@ -1,5 +1,5 @@ click >= 8, < 9 -ipython >= 8, < 9 +ipykernel < 7 ipdb >= 0.13, < 0.14 jinja2 >= 3, < 4 jsonschema >= 4.17, < 4.19 diff --git a/requirements/dev.txt b/requirements/dev.txt new file mode 100644 index 000000000..1c3a8be25 --- /dev/null +++ b/requirements/dev.txt @@ -0,0 +1,11 @@ +bottleneck < 2 +coverage >= 4.4 +codecov < 3 +glpk == 5.0 +hdf5 < 2 +libnetcdf < 5 +pre-commit < 4 +pytest-cov < 5 +pytest-xdist < 4 # pytest distributed testing plugin +pytest < 8 +nbmake < 2 \ No newline at end of file diff --git a/requirements_docs.yml b/requirements/docs.yml similarity index 100% rename from requirements_docs.yml rename to requirements/docs.yml diff --git a/setup.py b/setup.py deleted file mode 100644 index 80545c2b9..000000000 --- a/setup.py +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/env python - -from pathlib import Path - -from setuptools import find_packages, setup - -exec(Path("calliope/_version.py").read_text()) # Sets the __version__ variable - -requirements = Path("requirements.txt").read_text().strip().split("\n") -long_description = Path("README.md").read_text() - - -def get_subdirs(path, glob_string): - return [ - i.relative_to(str(path) + "/") for i in path.glob(glob_string) if i.is_dir() - ] - - -def find_calliope_package_data(): - """Returns a list of found directories with package data files""" - path = Path("./calliope") - package_data = ["config/*.yaml", "config/*.html", "test/common/*.yaml"] - for subdir_level in ["*", "*/*", "*/*/*"]: - for example_dir in get_subdirs(path, "example_models/" + subdir_level): - package_data.append(str(example_dir) + "/*.csv") - package_data.append(str(example_dir) + "/*.yaml") - package_data.append(str(example_dir) + "/*.rst") - for test_case_dir in get_subdirs(path, "test/common/*"): - package_data.append(str(test_case_dir) + "/*.csv") - print(package_data) - return package_data - - -setup( - name="calliope", - version=__version__, # noqa: F821 - author="Calliope contributors listed in AUTHORS", - author_email="stefan@pfenninger.org", - description="A multi-scale energy systems modelling framework", - long_description=long_description, - long_description_content_type="text/markdown", - license="Apache 2.0", - url="https://www.callio.pe/", - download_url="https://github.com/calliope-project/calliope/releases", - packages=find_packages(), - package_data={"calliope": find_calliope_package_data()}, - install_requires=requirements, - entry_points={"console_scripts": ["calliope = calliope.cli:cli"]}, - classifiers=[ - "Intended Audience :: Science/Research", - "License :: OSI Approved :: Apache Software License", - "Programming Language :: Python", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3 :: Only", - ], - keywords=["energy systems", "optimisation", "mathematical programming"], -) diff --git a/calliope/__init__.py b/src/calliope/__init__.py similarity index 100% rename from calliope/__init__.py rename to src/calliope/__init__.py diff --git a/calliope/_version.py b/src/calliope/_version.py similarity index 100% rename from calliope/_version.py rename to src/calliope/_version.py diff --git a/calliope/backend/__init__.py b/src/calliope/backend/__init__.py similarity index 100% rename from calliope/backend/__init__.py rename to src/calliope/backend/__init__.py diff --git a/calliope/backend/backends.py b/src/calliope/backend/backends.py similarity index 100% rename from calliope/backend/backends.py rename to src/calliope/backend/backends.py diff --git a/calliope/backend/expression_parser.py b/src/calliope/backend/expression_parser.py similarity index 100% rename from calliope/backend/expression_parser.py rename to src/calliope/backend/expression_parser.py diff --git a/calliope/backend/helper_functions.py b/src/calliope/backend/helper_functions.py similarity index 100% rename from calliope/backend/helper_functions.py rename to src/calliope/backend/helper_functions.py diff --git a/calliope/backend/latex_backend.py b/src/calliope/backend/latex_backend.py similarity index 100% rename from calliope/backend/latex_backend.py rename to src/calliope/backend/latex_backend.py diff --git a/calliope/backend/parsing.py b/src/calliope/backend/parsing.py similarity index 100% rename from calliope/backend/parsing.py rename to src/calliope/backend/parsing.py diff --git a/calliope/backend/where_parser.py b/src/calliope/backend/where_parser.py similarity index 100% rename from calliope/backend/where_parser.py rename to src/calliope/backend/where_parser.py diff --git a/calliope/cli.py b/src/calliope/cli.py similarity index 100% rename from calliope/cli.py rename to src/calliope/cli.py diff --git a/calliope/config/defaults.yaml b/src/calliope/config/defaults.yaml similarity index 100% rename from calliope/config/defaults.yaml rename to src/calliope/config/defaults.yaml diff --git a/calliope/config/math_schema.yaml b/src/calliope/config/math_schema.yaml similarity index 100% rename from calliope/config/math_schema.yaml rename to src/calliope/config/math_schema.yaml diff --git a/calliope/config/model_data_lookup.yaml b/src/calliope/config/model_data_lookup.yaml similarity index 100% rename from calliope/config/model_data_lookup.yaml rename to src/calliope/config/model_data_lookup.yaml diff --git a/calliope/core/__init__.py b/src/calliope/core/__init__.py similarity index 100% rename from calliope/core/__init__.py rename to src/calliope/core/__init__.py diff --git a/calliope/core/attrdict.py b/src/calliope/core/attrdict.py similarity index 100% rename from calliope/core/attrdict.py rename to src/calliope/core/attrdict.py diff --git a/calliope/core/io.py b/src/calliope/core/io.py similarity index 100% rename from calliope/core/io.py rename to src/calliope/core/io.py diff --git a/calliope/core/model.py b/src/calliope/core/model.py similarity index 100% rename from calliope/core/model.py rename to src/calliope/core/model.py diff --git a/calliope/core/util/__init__.py b/src/calliope/core/util/__init__.py similarity index 100% rename from calliope/core/util/__init__.py rename to src/calliope/core/util/__init__.py diff --git a/calliope/core/util/generate_runs.py b/src/calliope/core/util/generate_runs.py similarity index 100% rename from calliope/core/util/generate_runs.py rename to src/calliope/core/util/generate_runs.py diff --git a/calliope/core/util/logging.py b/src/calliope/core/util/logging.py similarity index 100% rename from calliope/core/util/logging.py rename to src/calliope/core/util/logging.py diff --git a/calliope/core/util/tools.py b/src/calliope/core/util/tools.py similarity index 100% rename from calliope/core/util/tools.py rename to src/calliope/core/util/tools.py diff --git a/calliope/example_models/national_scale/model.yaml b/src/calliope/example_models/national_scale/model.yaml similarity index 100% rename from calliope/example_models/national_scale/model.yaml rename to src/calliope/example_models/national_scale/model.yaml diff --git a/calliope/example_models/national_scale/model_config/locations.yaml b/src/calliope/example_models/national_scale/model_config/locations.yaml similarity index 100% rename from calliope/example_models/national_scale/model_config/locations.yaml rename to src/calliope/example_models/national_scale/model_config/locations.yaml diff --git a/calliope/example_models/national_scale/model_config/techs.yaml b/src/calliope/example_models/national_scale/model_config/techs.yaml similarity index 100% rename from calliope/example_models/national_scale/model_config/techs.yaml rename to src/calliope/example_models/national_scale/model_config/techs.yaml diff --git a/calliope/example_models/national_scale/scenarios.yaml b/src/calliope/example_models/national_scale/scenarios.yaml similarity index 100% rename from calliope/example_models/national_scale/scenarios.yaml rename to src/calliope/example_models/national_scale/scenarios.yaml diff --git a/calliope/example_models/national_scale/timeseries_data/README.rst b/src/calliope/example_models/national_scale/timeseries_data/README.rst similarity index 100% rename from calliope/example_models/national_scale/timeseries_data/README.rst rename to src/calliope/example_models/national_scale/timeseries_data/README.rst diff --git a/calliope/example_models/national_scale/timeseries_data/csp_resource.csv b/src/calliope/example_models/national_scale/timeseries_data/csp_resource.csv similarity index 100% rename from calliope/example_models/national_scale/timeseries_data/csp_resource.csv rename to src/calliope/example_models/national_scale/timeseries_data/csp_resource.csv diff --git a/calliope/example_models/national_scale/timeseries_data/demand-1.csv b/src/calliope/example_models/national_scale/timeseries_data/demand-1.csv similarity index 100% rename from calliope/example_models/national_scale/timeseries_data/demand-1.csv rename to src/calliope/example_models/national_scale/timeseries_data/demand-1.csv diff --git a/calliope/example_models/national_scale/timeseries_data/demand-2.csv b/src/calliope/example_models/national_scale/timeseries_data/demand-2.csv similarity index 100% rename from calliope/example_models/national_scale/timeseries_data/demand-2.csv rename to src/calliope/example_models/national_scale/timeseries_data/demand-2.csv diff --git a/calliope/example_models/urban_scale/model.yaml b/src/calliope/example_models/urban_scale/model.yaml similarity index 100% rename from calliope/example_models/urban_scale/model.yaml rename to src/calliope/example_models/urban_scale/model.yaml diff --git a/calliope/example_models/urban_scale/model_config/locations.yaml b/src/calliope/example_models/urban_scale/model_config/locations.yaml similarity index 100% rename from calliope/example_models/urban_scale/model_config/locations.yaml rename to src/calliope/example_models/urban_scale/model_config/locations.yaml diff --git a/calliope/example_models/urban_scale/model_config/techs.yaml b/src/calliope/example_models/urban_scale/model_config/techs.yaml similarity index 100% rename from calliope/example_models/urban_scale/model_config/techs.yaml rename to src/calliope/example_models/urban_scale/model_config/techs.yaml diff --git a/calliope/example_models/urban_scale/scenarios.yaml b/src/calliope/example_models/urban_scale/scenarios.yaml similarity index 100% rename from calliope/example_models/urban_scale/scenarios.yaml rename to src/calliope/example_models/urban_scale/scenarios.yaml diff --git a/calliope/example_models/urban_scale/timeseries_data/demand_heat.csv b/src/calliope/example_models/urban_scale/timeseries_data/demand_heat.csv similarity index 100% rename from calliope/example_models/urban_scale/timeseries_data/demand_heat.csv rename to src/calliope/example_models/urban_scale/timeseries_data/demand_heat.csv diff --git a/calliope/example_models/urban_scale/timeseries_data/demand_power.csv b/src/calliope/example_models/urban_scale/timeseries_data/demand_power.csv similarity index 100% rename from calliope/example_models/urban_scale/timeseries_data/demand_power.csv rename to src/calliope/example_models/urban_scale/timeseries_data/demand_power.csv diff --git a/calliope/example_models/urban_scale/timeseries_data/export_power.csv b/src/calliope/example_models/urban_scale/timeseries_data/export_power.csv similarity index 100% rename from calliope/example_models/urban_scale/timeseries_data/export_power.csv rename to src/calliope/example_models/urban_scale/timeseries_data/export_power.csv diff --git a/calliope/example_models/urban_scale/timeseries_data/pv_resource.csv b/src/calliope/example_models/urban_scale/timeseries_data/pv_resource.csv similarity index 100% rename from calliope/example_models/urban_scale/timeseries_data/pv_resource.csv rename to src/calliope/example_models/urban_scale/timeseries_data/pv_resource.csv diff --git a/calliope/examples.py b/src/calliope/examples.py similarity index 100% rename from calliope/examples.py rename to src/calliope/examples.py diff --git a/calliope/exceptions.py b/src/calliope/exceptions.py similarity index 100% rename from calliope/exceptions.py rename to src/calliope/exceptions.py diff --git a/calliope/math/base.yaml b/src/calliope/math/base.yaml similarity index 100% rename from calliope/math/base.yaml rename to src/calliope/math/base.yaml diff --git a/calliope/math/operate.yaml b/src/calliope/math/operate.yaml similarity index 100% rename from calliope/math/operate.yaml rename to src/calliope/math/operate.yaml diff --git a/calliope/math/spores.yaml b/src/calliope/math/spores.yaml similarity index 100% rename from calliope/math/spores.yaml rename to src/calliope/math/spores.yaml diff --git a/calliope/math/storage_inter_cluster.yaml b/src/calliope/math/storage_inter_cluster.yaml similarity index 100% rename from calliope/math/storage_inter_cluster.yaml rename to src/calliope/math/storage_inter_cluster.yaml diff --git a/calliope/postprocess/__init__.py b/src/calliope/postprocess/__init__.py similarity index 100% rename from calliope/postprocess/__init__.py rename to src/calliope/postprocess/__init__.py diff --git a/calliope/postprocess/results.py b/src/calliope/postprocess/results.py similarity index 100% rename from calliope/postprocess/results.py rename to src/calliope/postprocess/results.py diff --git a/calliope/postprocess/util.py b/src/calliope/postprocess/util.py similarity index 100% rename from calliope/postprocess/util.py rename to src/calliope/postprocess/util.py diff --git a/calliope/preprocess/__init__.py b/src/calliope/preprocess/__init__.py similarity index 100% rename from calliope/preprocess/__init__.py rename to src/calliope/preprocess/__init__.py diff --git a/calliope/preprocess/checks.py b/src/calliope/preprocess/checks.py similarity index 100% rename from calliope/preprocess/checks.py rename to src/calliope/preprocess/checks.py diff --git a/calliope/preprocess/model_data.py b/src/calliope/preprocess/model_data.py similarity index 100% rename from calliope/preprocess/model_data.py rename to src/calliope/preprocess/model_data.py diff --git a/calliope/preprocess/model_run.py b/src/calliope/preprocess/model_run.py similarity index 100% rename from calliope/preprocess/model_run.py rename to src/calliope/preprocess/model_run.py diff --git a/calliope/preprocess/nodes.py b/src/calliope/preprocess/nodes.py similarity index 100% rename from calliope/preprocess/nodes.py rename to src/calliope/preprocess/nodes.py diff --git a/calliope/preprocess/time.py b/src/calliope/preprocess/time.py similarity index 100% rename from calliope/preprocess/time.py rename to src/calliope/preprocess/time.py diff --git a/calliope/preprocess/util.py b/src/calliope/preprocess/util.py similarity index 100% rename from calliope/preprocess/util.py rename to src/calliope/preprocess/util.py diff --git a/calliope/time/__init__.py b/src/calliope/time/__init__.py similarity index 100% rename from calliope/time/__init__.py rename to src/calliope/time/__init__.py diff --git a/calliope/time/clustering.py b/src/calliope/time/clustering.py similarity index 100% rename from calliope/time/clustering.py rename to src/calliope/time/clustering.py diff --git a/calliope/time/funcs.py b/src/calliope/time/funcs.py similarity index 100% rename from calliope/time/funcs.py rename to src/calliope/time/funcs.py diff --git a/calliope/time/masks.py b/src/calliope/time/masks.py similarity index 100% rename from calliope/time/masks.py rename to src/calliope/time/masks.py diff --git a/calliope/test/__init__.py b/tests/__init__.py similarity index 100% rename from calliope/test/__init__.py rename to tests/__init__.py diff --git a/calliope/test/common/constraint_sets.yaml b/tests/common/constraint_sets.yaml similarity index 100% rename from calliope/test/common/constraint_sets.yaml rename to tests/common/constraint_sets.yaml diff --git a/calliope/test/common/html_strings.yaml b/tests/common/html_strings.yaml similarity index 100% rename from calliope/test/common/html_strings.yaml rename to tests/common/html_strings.yaml diff --git a/calliope/test/common/lp_files/balance_conversion.lp b/tests/common/lp_files/balance_conversion.lp similarity index 100% rename from calliope/test/common/lp_files/balance_conversion.lp rename to tests/common/lp_files/balance_conversion.lp diff --git a/calliope/test/common/lp_files/carrier_production_max.lp b/tests/common/lp_files/carrier_production_max.lp similarity index 100% rename from calliope/test/common/lp_files/carrier_production_max.lp rename to tests/common/lp_files/carrier_production_max.lp diff --git a/calliope/test/common/lp_files/energy_cap.lp b/tests/common/lp_files/energy_cap.lp similarity index 100% rename from calliope/test/common/lp_files/energy_cap.lp rename to tests/common/lp_files/energy_cap.lp diff --git a/calliope/test/common/lp_files/resource_max.lp b/tests/common/lp_files/resource_max.lp similarity index 100% rename from calliope/test/common/lp_files/resource_max.lp rename to tests/common/lp_files/resource_max.lp diff --git a/calliope/test/common/lp_files/storage_max.lp b/tests/common/lp_files/storage_max.lp similarity index 100% rename from calliope/test/common/lp_files/storage_max.lp rename to tests/common/lp_files/storage_max.lp diff --git a/calliope/test/common/test_model/energy_cap_per_storage_cap.yaml b/tests/common/test_model/energy_cap_per_storage_cap.yaml similarity index 100% rename from calliope/test/common/test_model/energy_cap_per_storage_cap.yaml rename to tests/common/test_model/energy_cap_per_storage_cap.yaml diff --git a/calliope/test/common/test_model/model.yaml b/tests/common/test_model/model.yaml similarity index 100% rename from calliope/test/common/test_model/model.yaml rename to tests/common/test_model/model.yaml diff --git a/calliope/test/common/test_model/model_minimal.yaml b/tests/common/test_model/model_minimal.yaml similarity index 100% rename from calliope/test/common/test_model/model_minimal.yaml rename to tests/common/test_model/model_minimal.yaml diff --git a/calliope/test/common/test_model/scenarios.yaml b/tests/common/test_model/scenarios.yaml similarity index 100% rename from calliope/test/common/test_model/scenarios.yaml rename to tests/common/test_model/scenarios.yaml diff --git a/calliope/test/common/test_model/timeseries_data/alternating_cost.csv b/tests/common/test_model/timeseries_data/alternating_cost.csv similarity index 100% rename from calliope/test/common/test_model/timeseries_data/alternating_cost.csv rename to tests/common/test_model/timeseries_data/alternating_cost.csv diff --git a/calliope/test/common/test_model/timeseries_data/binary_one_day.csv b/tests/common/test_model/timeseries_data/binary_one_day.csv similarity index 100% rename from calliope/test/common/test_model/timeseries_data/binary_one_day.csv rename to tests/common/test_model/timeseries_data/binary_one_day.csv diff --git a/calliope/test/common/test_model/timeseries_data/carrier_ratio.csv b/tests/common/test_model/timeseries_data/carrier_ratio.csv similarity index 100% rename from calliope/test/common/test_model/timeseries_data/carrier_ratio.csv rename to tests/common/test_model/timeseries_data/carrier_ratio.csv diff --git a/calliope/test/common/test_model/timeseries_data/cluster_days.csv b/tests/common/test_model/timeseries_data/cluster_days.csv similarity index 100% rename from calliope/test/common/test_model/timeseries_data/cluster_days.csv rename to tests/common/test_model/timeseries_data/cluster_days.csv diff --git a/calliope/test/common/test_model/timeseries_data/clusters.csv b/tests/common/test_model/timeseries_data/clusters.csv similarity index 100% rename from calliope/test/common/test_model/timeseries_data/clusters.csv rename to tests/common/test_model/timeseries_data/clusters.csv diff --git a/calliope/test/common/test_model/timeseries_data/cost.csv b/tests/common/test_model/timeseries_data/cost.csv similarity index 100% rename from calliope/test/common/test_model/timeseries_data/cost.csv rename to tests/common/test_model/timeseries_data/cost.csv diff --git a/calliope/test/common/test_model/timeseries_data/demand_elec.csv b/tests/common/test_model/timeseries_data/demand_elec.csv similarity index 100% rename from calliope/test/common/test_model/timeseries_data/demand_elec.csv rename to tests/common/test_model/timeseries_data/demand_elec.csv diff --git a/calliope/test/common/test_model/timeseries_data/demand_elec_15T_to_2h.csv b/tests/common/test_model/timeseries_data/demand_elec_15T_to_2h.csv similarity index 100% rename from calliope/test/common/test_model/timeseries_data/demand_elec_15T_to_2h.csv rename to tests/common/test_model/timeseries_data/demand_elec_15T_to_2h.csv diff --git a/calliope/test/common/test_model/timeseries_data/demand_elec_15mins.csv b/tests/common/test_model/timeseries_data/demand_elec_15mins.csv similarity index 100% rename from calliope/test/common/test_model/timeseries_data/demand_elec_15mins.csv rename to tests/common/test_model/timeseries_data/demand_elec_15mins.csv diff --git a/calliope/test/common/test_model/timeseries_data/demand_elec_positive.csv b/tests/common/test_model/timeseries_data/demand_elec_positive.csv similarity index 100% rename from calliope/test/common/test_model/timeseries_data/demand_elec_positive.csv rename to tests/common/test_model/timeseries_data/demand_elec_positive.csv diff --git a/calliope/test/common/test_model/timeseries_data/demand_heat.csv b/tests/common/test_model/timeseries_data/demand_heat.csv similarity index 100% rename from calliope/test/common/test_model/timeseries_data/demand_heat.csv rename to tests/common/test_model/timeseries_data/demand_heat.csv diff --git a/calliope/test/common/test_model/timeseries_data/demand_heat_diff_dateformat.csv b/tests/common/test_model/timeseries_data/demand_heat_diff_dateformat.csv similarity index 100% rename from calliope/test/common/test_model/timeseries_data/demand_heat_diff_dateformat.csv rename to tests/common/test_model/timeseries_data/demand_heat_diff_dateformat.csv diff --git a/calliope/test/common/test_model/timeseries_data/demand_heat_wrong_dateformat.csv b/tests/common/test_model/timeseries_data/demand_heat_wrong_dateformat.csv similarity index 100% rename from calliope/test/common/test_model/timeseries_data/demand_heat_wrong_dateformat.csv rename to tests/common/test_model/timeseries_data/demand_heat_wrong_dateformat.csv diff --git a/calliope/test/common/test_model/timeseries_data/demand_heat_wrong_length.csv b/tests/common/test_model/timeseries_data/demand_heat_wrong_length.csv similarity index 100% rename from calliope/test/common/test_model/timeseries_data/demand_heat_wrong_length.csv rename to tests/common/test_model/timeseries_data/demand_heat_wrong_length.csv diff --git a/calliope/test/common/test_model/timeseries_data/demand_simple.csv b/tests/common/test_model/timeseries_data/demand_simple.csv similarity index 100% rename from calliope/test/common/test_model/timeseries_data/demand_simple.csv rename to tests/common/test_model/timeseries_data/demand_simple.csv diff --git a/calliope/test/common/test_model/timeseries_data/supply_plus_resource.csv b/tests/common/test_model/timeseries_data/supply_plus_resource.csv similarity index 100% rename from calliope/test/common/test_model/timeseries_data/supply_plus_resource.csv rename to tests/common/test_model/timeseries_data/supply_plus_resource.csv diff --git a/calliope/test/common/test_model/timeseries_data/supply_plus_resource_inf.csv b/tests/common/test_model/timeseries_data/supply_plus_resource_inf.csv similarity index 100% rename from calliope/test/common/test_model/timeseries_data/supply_plus_resource_inf.csv rename to tests/common/test_model/timeseries_data/supply_plus_resource_inf.csv diff --git a/calliope/test/common/test_model/timeseries_data/supply_simple.csv b/tests/common/test_model/timeseries_data/supply_simple.csv similarity index 100% rename from calliope/test/common/test_model/timeseries_data/supply_simple.csv rename to tests/common/test_model/timeseries_data/supply_simple.csv diff --git a/calliope/test/common/test_model/weighted_obj_func.yaml b/tests/common/test_model/weighted_obj_func.yaml similarity index 100% rename from calliope/test/common/test_model/weighted_obj_func.yaml rename to tests/common/test_model/weighted_obj_func.yaml diff --git a/calliope/test/common/util.py b/tests/common/util.py similarity index 99% rename from calliope/test/common/util.py rename to tests/common/util.py index 9bdf4258c..eefce6e5c 100644 --- a/calliope/test/common/util.py +++ b/tests/common/util.py @@ -4,10 +4,9 @@ from pathlib import Path from typing import Literal, Optional, Union +import calliope import pytest import xarray as xr - -import calliope from calliope import AttrDict constraint_sets = { diff --git a/calliope/test/common/yaml_file.yaml b/tests/common/yaml_file.yaml similarity index 100% rename from calliope/test/common/yaml_file.yaml rename to tests/common/yaml_file.yaml diff --git a/calliope/test/conftest.py b/tests/conftest.py similarity index 99% rename from calliope/test/conftest.py rename to tests/conftest.py index 7c5360e26..aa9092abd 100644 --- a/calliope/test/conftest.py +++ b/tests/conftest.py @@ -3,10 +3,10 @@ import numpy as np import pytest import xarray as xr - from calliope import AttrDict from calliope.backend import backends, latex_backend -from calliope.test.common.util import build_test_model as build_model + +from .common.util import build_test_model as build_model ALL_DIMS = {"nodes", "techs", "carriers", "costs", "timesteps", "carrier_tiers"} diff --git a/calliope/test/test_backend_expression_parser.py b/tests/test_backend_expression_parser.py similarity index 99% rename from calliope/test/test_backend_expression_parser.py rename to tests/test_backend_expression_parser.py index 7e939a984..16dd52b06 100644 --- a/calliope/test/test_backend_expression_parser.py +++ b/tests/test_backend_expression_parser.py @@ -4,10 +4,10 @@ import numpy as np import pyparsing as pp import pytest - from calliope import exceptions from calliope.backend import expression_parser, helper_functions -from calliope.test.common.util import check_error_or_warning + +from .common.util import check_error_or_warning SUB_EXPRESSION_CLASSIFIER = expression_parser.SUB_EXPRESSION_CLASSIFIER diff --git a/calliope/test/test_backend_helper_functions.py b/tests/test_backend_helper_functions.py similarity index 99% rename from calliope/test/test_backend_helper_functions.py rename to tests/test_backend_helper_functions.py index 1e91b767b..25d7c7c38 100644 --- a/calliope/test/test_backend_helper_functions.py +++ b/tests/test_backend_helper_functions.py @@ -1,10 +1,10 @@ import numpy as np import pytest import xarray as xr - from calliope import exceptions from calliope.backend import helper_functions -from calliope.test.common.util import check_error_or_warning + +from .common.util import check_error_or_warning @pytest.fixture(scope="module") diff --git a/calliope/test/test_backend_latex_backend.py b/tests/test_backend_latex_backend.py similarity index 99% rename from calliope/test/test_backend_latex_backend.py rename to tests/test_backend_latex_backend.py index 183b45e51..0f87cd6dd 100644 --- a/calliope/test/test_backend_latex_backend.py +++ b/tests/test_backend_latex_backend.py @@ -3,10 +3,10 @@ import pytest import xarray as xr - from calliope import exceptions from calliope.backend import latex_backend -from calliope.test.common.util import build_test_model, check_error_or_warning + +from .common.util import build_test_model, check_error_or_warning class TestMathDocumentation: diff --git a/calliope/test/test_backend_parsing.py b/tests/test_backend_parsing.py similarity index 99% rename from calliope/test/test_backend_parsing.py rename to tests/test_backend_parsing.py index 0fccdaee8..7f87040a5 100644 --- a/calliope/test/test_backend_parsing.py +++ b/tests/test_backend_parsing.py @@ -1,13 +1,13 @@ from io import StringIO from unittest.mock import patch +import calliope import pyparsing as pp import pytest import ruamel.yaml as yaml - -import calliope from calliope.backend import backends, expression_parser, parsing, where_parser -from calliope.test.common.util import check_error_or_warning + +from .common.util import check_error_or_warning BASE_DIMS = {"carriers", "carrier_tiers", "nodes", "techs"} diff --git a/calliope/test/test_backend_pyomo.py b/tests/test_backend_pyomo.py similarity index 99% rename from calliope/test/test_backend_pyomo.py rename to tests/test_backend_pyomo.py index a6a135e4c..84707afc2 100755 --- a/calliope/test/test_backend_pyomo.py +++ b/tests/test_backend_pyomo.py @@ -1,14 +1,14 @@ import logging from itertools import product +import calliope.exceptions as exceptions import numpy as np import pyomo.kernel as pmo import pytest # noqa: F401 import xarray as xr -import calliope.exceptions as exceptions -from calliope.test.common.util import build_test_model as build_model -from calliope.test.common.util import check_error_or_warning, check_variable_exists +from .common.util import build_test_model as build_model +from .common.util import check_error_or_warning, check_variable_exists @pytest.mark.xfail(reason="Not expecting operate mode to work at the moment") diff --git a/calliope/test/test_backend_pyomo_constraints_conversion_plus.py b/tests/test_backend_pyomo_constraints_conversion_plus.py similarity index 98% rename from calliope/test/test_backend_pyomo_constraints_conversion_plus.py rename to tests/test_backend_pyomo_constraints_conversion_plus.py index e10d7987e..dbb0e3aa0 100644 --- a/calliope/test/test_backend_pyomo_constraints_conversion_plus.py +++ b/tests/test_backend_pyomo_constraints_conversion_plus.py @@ -1,7 +1,7 @@ import pytest # noqa: F401 -from calliope.test.common.util import build_test_model as build_model -from calliope.test.common.util import check_variable_exists +from .common.util import build_test_model as build_model +from .common.util import check_variable_exists @pytest.mark.skip(reason="to be reimplemented by comparison to LP files") diff --git a/calliope/test/test_backend_pyomo_objective.py b/tests/test_backend_pyomo_objective.py similarity index 98% rename from calliope/test/test_backend_pyomo_objective.py rename to tests/test_backend_pyomo_objective.py index 6ee640f89..31412580f 100644 --- a/calliope/test/test_backend_pyomo_objective.py +++ b/tests/test_backend_pyomo_objective.py @@ -1,9 +1,9 @@ +import calliope import pyomo.core as po import pytest from pytest import approx -import calliope -from calliope.test.common.util import build_test_model as build_model +from .common.util import build_test_model as build_model @pytest.mark.skip(reason="to be reimplemented by comparison to LP files") diff --git a/calliope/test/test_backend_where_parser.py b/tests/test_backend_where_parser.py similarity index 99% rename from calliope/test/test_backend_where_parser.py rename to tests/test_backend_where_parser.py index 1e0941e3f..bfb4a2060 100644 --- a/calliope/test/test_backend_where_parser.py +++ b/tests/test_backend_where_parser.py @@ -2,11 +2,11 @@ import pyparsing import pytest import xarray as xr - from calliope.backend import expression_parser, helper_functions, where_parser from calliope.core.attrdict import AttrDict from calliope.exceptions import BackendError -from calliope.test.common.util import check_error_or_warning + +from .common.util import check_error_or_warning SUB_EXPRESSION_CLASSIFIER = expression_parser.SUB_EXPRESSION_CLASSIFIER diff --git a/calliope/test/test_cli.py b/tests/test_cli.py similarity index 96% rename from calliope/test/test_cli.py rename to tests/test_cli.py index fdc0b604d..59833a8c0 100644 --- a/calliope/test/test_cli.py +++ b/tests/test_cli.py @@ -2,19 +2,22 @@ import tempfile from pathlib import Path +import calliope +import importlib_resources import pytest # noqa: F401 +from calliope import AttrDict, cli from click.testing import CliRunner -import calliope -from calliope import AttrDict, cli +_MODEL_NATIONAL = ( + importlib_resources.files("calliope") + / "example_models" + / "national_scale" + / "model.yaml" +).as_posix() -_THIS_DIR = os.path.dirname(__file__) -_MODEL_NATIONAL = os.path.join( - _THIS_DIR, "..", "example_models", "national_scale", "model.yaml" -) -_MINIMAL_TEST_MODEL = os.path.join( - _THIS_DIR, "common", "test_model", "model_minimal.yaml" -) +_MINIMAL_TEST_MODEL = ( + Path(__file__).parent / "common" / "test_model" / "model_minimal.yaml" +).as_posix() class TestCLI: diff --git a/calliope/test/test_constraint_results.py b/tests/test_constraint_results.py similarity index 99% rename from calliope/test/test_constraint_results.py rename to tests/test_constraint_results.py index 003d9dc0b..6b2bf0f83 100644 --- a/calliope/test/test_constraint_results.py +++ b/tests/test_constraint_results.py @@ -1,8 +1,8 @@ +import calliope import pytest from pytest import approx -import calliope -from calliope.test.common.util import build_test_model as build_model +from .common.util import build_test_model as build_model @pytest.mark.skip(reason="to be reimplemented by comparison to LP files") diff --git a/calliope/test/test_core_attrdict.py b/tests/test_core_attrdict.py similarity index 99% rename from calliope/test/test_core_attrdict.py rename to tests/test_core_attrdict.py index 9aa8d8593..c2029e90b 100644 --- a/calliope/test/test_core_attrdict.py +++ b/tests/test_core_attrdict.py @@ -5,9 +5,9 @@ import numpy as np import pytest import ruamel.yaml as ruamel_yaml - from calliope.core.attrdict import _MISSING, AttrDict -from calliope.test.common.util import check_error_or_warning + +from .common.util import check_error_or_warning class TestAttrDict: diff --git a/calliope/test/test_core_future_warnings.py b/tests/test_core_future_warnings.py similarity index 89% rename from calliope/test/test_core_future_warnings.py rename to tests/test_core_future_warnings.py index b19d2445e..dc1b3de05 100644 --- a/calliope/test/test_core_future_warnings.py +++ b/tests/test_core_future_warnings.py @@ -1,7 +1,7 @@ import pytest -from calliope.test.common.util import build_test_model as build_model -from calliope.test.common.util import check_error_or_warning +from .common.util import build_test_model as build_model +from .common.util import check_error_or_warning class TestDeprecationWarnings: diff --git a/calliope/test/test_core_model.py b/tests/test_core_model.py similarity index 99% rename from calliope/test/test_core_model.py rename to tests/test_core_model.py index 0eced0588..1f011d692 100644 --- a/calliope/test/test_core_model.py +++ b/tests/test_core_model.py @@ -2,12 +2,12 @@ import os from pathlib import Path +import calliope import numpy as np import pytest -import calliope -from calliope.test.common.util import build_test_model as build_model -from calliope.test.common.util import check_error_or_warning +from .common.util import build_test_model as build_model +from .common.util import check_error_or_warning LOGGER = "calliope.core.model" diff --git a/calliope/test/test_core_preprocess.py b/tests/test_core_preprocess.py similarity index 99% rename from calliope/test/test_core_preprocess.py rename to tests/test_core_preprocess.py index 58e3c5435..31d65bd64 100644 --- a/calliope/test/test_core_preprocess.py +++ b/tests/test_core_preprocess.py @@ -1,16 +1,16 @@ import os +import calliope +import calliope.exceptions as exceptions import numpy as np import pandas as pd import pytest -from pytest import approx - -import calliope -import calliope.exceptions as exceptions from calliope.core.attrdict import AttrDict from calliope.preprocess import time -from calliope.test.common.util import build_test_model as build_model -from calliope.test.common.util import check_error_or_warning, defaults +from pytest import approx + +from .common.util import build_test_model as build_model +from .common.util import check_error_or_warning, defaults class TestModelRun: diff --git a/calliope/test/test_core_time.py b/tests/test_core_time.py similarity index 99% rename from calliope/test/test_core_time.py rename to tests/test_core_time.py index 36f47a4d3..c6c78b86f 100644 --- a/calliope/test/test_core_time.py +++ b/tests/test_core_time.py @@ -1,12 +1,12 @@ +import calliope import numpy as np import pandas as pd import pytest # noqa: F401 - -import calliope from calliope import exceptions -from calliope.test.common.util import build_test_model, check_error_or_warning from calliope.time import funcs, masks +from .common.util import build_test_model, check_error_or_warning + class TestClustering: @pytest.fixture diff --git a/calliope/test/test_core_util.py b/tests/test_core_util.py similarity index 95% rename from calliope/test/test_core_util.py rename to tests/test_core_util.py index 475589618..57fe8420e 100644 --- a/calliope/test/test_core_util.py +++ b/tests/test_core_util.py @@ -1,13 +1,12 @@ import datetime import glob import logging -import os from pathlib import Path +import calliope +import importlib_resources import jsonschema import pytest - -import calliope from calliope.core.util.generate_runs import generate_runs from calliope.core.util.logging import log_time from calliope.core.util.tools import ( @@ -17,15 +16,12 @@ validate_dict, ) from calliope.exceptions import ModelError -from calliope.test.common.util import check_error_or_warning, python36_or_higher -_MODEL_NATIONAL = os.path.join( - os.path.dirname(__file__), "..", "example_models", "national_scale", "model.yaml" -) +from .common.util import check_error_or_warning, python36_or_higher -_MODEL_URBAN = os.path.join( - os.path.dirname(__file__), "..", "example_models", "urban_scale", "model.yaml" -) +_EXAMPLES_DIR = importlib_resources.files("calliope") / "example_models" +_MODEL_NATIONAL = (_EXAMPLES_DIR / "national_scale" / "model.yaml").as_posix() +_MODEL_URBAN = (_EXAMPLES_DIR / "urban_scale" / "model.yaml").as_posix() class TestMemoization: diff --git a/calliope/test/test_example_models.py b/tests/test_example_models.py similarity index 99% rename from calliope/test/test_example_models.py rename to tests/test_example_models.py index 7d73bf052..69aa33df0 100755 --- a/calliope/test/test_example_models.py +++ b/tests/test_example_models.py @@ -1,13 +1,13 @@ import shutil +import calliope import numpy as np import pandas as pd import pytest +from calliope import exceptions from pytest import approx -import calliope -from calliope import exceptions -from calliope.test.common.util import check_error_or_warning +from .common.util import check_error_or_warning class TestModelPreproccessing: diff --git a/calliope/test/test_io.py b/tests/test_io.py similarity index 99% rename from calliope/test/test_io.py rename to tests/test_io.py index cf2662711..13b453c6c 100644 --- a/calliope/test/test_io.py +++ b/tests/test_io.py @@ -1,10 +1,9 @@ import os import tempfile +import calliope import pytest # noqa: F401 import xarray as xr - -import calliope from calliope import exceptions diff --git a/calliope/test/test_math.py b/tests/test_math.py similarity index 95% rename from calliope/test/test_math.py rename to tests/test_math.py index bb45860d2..0b2887bcc 100644 --- a/calliope/test/test_math.py +++ b/tests/test_math.py @@ -1,12 +1,12 @@ from pathlib import Path +import calliope import numpy as np import pytest +from calliope import AttrDict from pyomo.repn.tests import lp_diff -import calliope -from calliope import AttrDict -from calliope.test.common.util import build_lp, build_test_model +from .common.util import build_lp, build_test_model @pytest.fixture(scope="class") @@ -15,9 +15,7 @@ def _compare_lps(model, custom_math, filename): lp_file = filename + ".lp" generated_file = Path(tmpdir_factory.mktemp("lp_files")) / lp_file build_lp(model, generated_file, custom_math) - expected_file = ( - Path(calliope.__file__).parent / "test" / "common" / "lp_files" / lp_file - ) + expected_file = Path(__file__).parent / "common" / "lp_files" / lp_file diff = lp_diff.load_and_compare_lp_baseline( generated_file.as_posix(), expected_file.as_posix() ) diff --git a/calliope/test/test_model_data.py b/tests/test_model_data.py similarity index 98% rename from calliope/test/test_model_data.py rename to tests/test_model_data.py index 3ba42559a..8451aa919 100644 --- a/calliope/test/test_model_data.py +++ b/tests/test_model_data.py @@ -1,29 +1,22 @@ import logging -import os +from pathlib import Path +import calliope.exceptions as exceptions import numpy as np import pandas as pd import pytest - -import calliope -import calliope.exceptions as exceptions from calliope._version import __version__ from calliope.core.attrdict import AttrDict from calliope.preprocess import model_run_from_yaml from calliope.preprocess.model_data import ModelDataFactory -from calliope.test.common.util import check_error_or_warning + +from .common.util import check_error_or_warning @pytest.fixture(scope="module") def model_run(): - filepath = os.path.join( - os.path.dirname(calliope.__file__), - "test", - "common", - "test_model", - "model.yaml", - ) - return model_run_from_yaml(filepath, scenario="simple_supply")[0] + filepath = Path(__file__).parent / "common" / "test_model" / "model.yaml" + return model_run_from_yaml(filepath.as_posix(), scenario="simple_supply")[0] class TestModelData: diff --git a/calliope/test/test_model_manipulation.py b/tests/test_model_manipulation.py similarity index 95% rename from calliope/test/test_model_manipulation.py rename to tests/test_model_manipulation.py index 1e66a23a2..a1bf08166 100644 --- a/calliope/test/test_model_manipulation.py +++ b/tests/test_model_manipulation.py @@ -1,8 +1,8 @@ import pytest # noqa: F401 - from calliope import exceptions -from calliope.test.common.util import build_test_model as build_model -from calliope.test.common.util import check_error_or_warning + +from .common.util import build_test_model as build_model +from .common.util import check_error_or_warning class TestExistsFalse: