microgridspy 0.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (180) hide show
  1. microgridspy-0.4.0/.github/workflows/ci.yml +33 -0
  2. microgridspy-0.4.0/.github/workflows/draft-pdf.yml +30 -0
  3. microgridspy-0.4.0/.github/workflows/release.yml +35 -0
  4. microgridspy-0.4.0/.gitignore +41 -0
  5. microgridspy-0.4.0/.mailmap +39 -0
  6. microgridspy-0.4.0/.readthedocs.yaml +19 -0
  7. microgridspy-0.4.0/AUTHORS +68 -0
  8. microgridspy-0.4.0/CHANGELOG.md +110 -0
  9. microgridspy-0.4.0/CITATION.cff +107 -0
  10. microgridspy-0.4.0/CODE_OF_CONDUCT.md +133 -0
  11. microgridspy-0.4.0/CONTRIBUTING.md +48 -0
  12. microgridspy-0.4.0/LICENSE +287 -0
  13. microgridspy-0.4.0/PKG-INFO +615 -0
  14. microgridspy-0.4.0/README.md +274 -0
  15. microgridspy-0.4.0/docs/Mathematical_Formulation.pdf +0 -0
  16. microgridspy-0.4.0/docs/api/index.md +62 -0
  17. microgridspy-0.4.0/docs/api/models.md +26 -0
  18. microgridspy-0.4.0/docs/api/optimization.md +23 -0
  19. microgridspy-0.4.0/docs/api/project.md +49 -0
  20. microgridspy-0.4.0/docs/api/results.md +41 -0
  21. microgridspy-0.4.0/docs/assets/examples/ambient_temperature.png +0 -0
  22. microgridspy-0.4.0/docs/assets/examples/case1_cost.png +0 -0
  23. microgridspy-0.4.0/docs/assets/examples/case2_cost.png +0 -0
  24. microgridspy-0.4.0/docs/assets/examples/case3_degradation.png +0 -0
  25. microgridspy-0.4.0/docs/assets/examples/case4_cost.png +0 -0
  26. microgridspy-0.4.0/docs/assets/examples/case5_cost.png +0 -0
  27. microgridspy-0.4.0/docs/assets/examples/case5_expansion.png +0 -0
  28. microgridspy-0.4.0/docs/assets/examples/case6_dispatch.png +0 -0
  29. microgridspy-0.4.0/docs/assets/examples/case6_expected_cost.png +0 -0
  30. microgridspy-0.4.0/docs/assets/examples/case6_grid_availability.png +0 -0
  31. microgridspy-0.4.0/docs/assets/examples/case7_emissions.png +0 -0
  32. microgridspy-0.4.0/docs/assets/examples/demand_profile.png +0 -0
  33. microgridspy-0.4.0/docs/assets/examples/overview_capacity.png +0 -0
  34. microgridspy-0.4.0/docs/assets/examples/overview_npc_lcoe.png +0 -0
  35. microgridspy-0.4.0/docs/assets/examples/resource_solar_cf.png +0 -0
  36. microgridspy-0.4.0/docs/assets/gui/intro_interface.png +0 -0
  37. microgridspy-0.4.0/docs/assets/methodology/battery_degradation_coefficients.png +0 -0
  38. microgridspy-0.4.0/docs/assets/methodology/battery_loss_curve.png +0 -0
  39. microgridspy-0.4.0/docs/assets/methodology/battery_replacement_annuity.png +0 -0
  40. microgridspy-0.4.0/docs/assets/methodology/energy_system.png +0 -0
  41. microgridspy-0.4.0/docs/assets/methodology/grid_simulation.png +0 -0
  42. microgridspy-0.4.0/docs/assets/methodology/partial_load_curve.png +0 -0
  43. microgridspy-0.4.0/docs/data-reference/data-contract.md +153 -0
  44. microgridspy-0.4.0/docs/data-reference/overview.md +111 -0
  45. microgridspy-0.4.0/docs/developers/architecture.md +53 -0
  46. microgridspy-0.4.0/docs/developers/contributing.md +45 -0
  47. microgridspy-0.4.0/docs/examples/case-study.md +114 -0
  48. microgridspy-0.4.0/docs/examples/index.md +140 -0
  49. microgridspy-0.4.0/docs/examples/planning-for-growth.md +92 -0
  50. microgridspy-0.4.0/docs/examples/technology-choice.md +165 -0
  51. microgridspy-0.4.0/docs/examples/uncertainty.md +109 -0
  52. microgridspy-0.4.0/docs/getting-started/installation.md +70 -0
  53. microgridspy-0.4.0/docs/getting-started/quickstart.md +118 -0
  54. microgridspy-0.4.0/docs/gui/index.md +180 -0
  55. microgridspy-0.4.0/docs/index.md +192 -0
  56. microgridspy-0.4.0/docs/javascripts/mathjax.js +43 -0
  57. microgridspy-0.4.0/docs/methodology/battery.md +367 -0
  58. microgridspy-0.4.0/docs/methodology/constraints.md +119 -0
  59. microgridspy-0.4.0/docs/methodology/cost-accounting.md +140 -0
  60. microgridspy-0.4.0/docs/methodology/generator.md +136 -0
  61. microgridspy-0.4.0/docs/methodology/grid.md +115 -0
  62. microgridspy-0.4.0/docs/methodology/inverters.md +55 -0
  63. microgridspy-0.4.0/docs/methodology/objective-function.md +148 -0
  64. microgridspy-0.4.0/docs/methodology/overview.md +136 -0
  65. microgridspy-0.4.0/docs/methodology/planning-modes.md +114 -0
  66. microgridspy-0.4.0/docs/methodology/renewable.md +85 -0
  67. microgridspy-0.4.0/docs/stylesheets/extra.css +25 -0
  68. microgridspy-0.4.0/docs/tables/multi_year_input_reference.csv +15 -0
  69. microgridspy-0.4.0/docs/tables/multi_year_timeseries_reference.csv +9 -0
  70. microgridspy-0.4.0/docs/tables/typical_year_input_reference.csv +14 -0
  71. microgridspy-0.4.0/docs/tables/typical_year_timeseries_reference.csv +8 -0
  72. microgridspy-0.4.0/docs/tutorials/multi-year.md +77 -0
  73. microgridspy-0.4.0/docs/tutorials/typical-year.md +85 -0
  74. microgridspy-0.4.0/docs/user-guide/input-data.md +79 -0
  75. microgridspy-0.4.0/docs/user-guide/planning-modes.md +55 -0
  76. microgridspy-0.4.0/docs/user-guide/results.md +56 -0
  77. microgridspy-0.4.0/docs/user-guide/running.md +58 -0
  78. microgridspy-0.4.0/examples/run_demo_multi_year.py +45 -0
  79. microgridspy-0.4.0/examples/run_demo_typical_year.py +35 -0
  80. microgridspy-0.4.0/paper/paper.bib +195 -0
  81. microgridspy-0.4.0/paper/paper.md +92 -0
  82. microgridspy-0.4.0/pubs_list.md +59 -0
  83. microgridspy-0.4.0/pyproject.toml +93 -0
  84. microgridspy-0.4.0/src/microgridspy/__init__.py +102 -0
  85. microgridspy-0.4.0/src/microgridspy/api.py +248 -0
  86. microgridspy-0.4.0/src/microgridspy/app/Home.py +256 -0
  87. microgridspy-0.4.0/src/microgridspy/app/__init__.py +7 -0
  88. microgridspy-0.4.0/src/microgridspy/app/assets/distribution_tool_card.jpeg +0 -0
  89. microgridspy-0.4.0/src/microgridspy/app/assets/intro_interface.png +0 -0
  90. microgridspy-0.4.0/src/microgridspy/app/assets/planning_tool_card.png +0 -0
  91. microgridspy-0.4.0/src/microgridspy/app/assets/pvgis_tool_card.png +0 -0
  92. microgridspy-0.4.0/src/microgridspy/app/assets/ramp_tool_card.png +0 -0
  93. microgridspy-0.4.0/src/microgridspy/app/assets/simulation_tool_card.png +0 -0
  94. microgridspy-0.4.0/src/microgridspy/app/launcher.py +31 -0
  95. microgridspy-0.4.0/src/microgridspy/app/multi_year_results_page.py +1233 -0
  96. microgridspy-0.4.0/src/microgridspy/app/page_helpers.py +41 -0
  97. microgridspy-0.4.0/src/microgridspy/app/pages/0_Project_Setup.py +1585 -0
  98. microgridspy-0.4.0/src/microgridspy/app/pages/1_Data_Audit_and_Visualization.py +1654 -0
  99. microgridspy-0.4.0/src/microgridspy/app/pages/2_Optimization.py +1046 -0
  100. microgridspy-0.4.0/src/microgridspy/app/pages/3_Results.py +1083 -0
  101. microgridspy-0.4.0/src/microgridspy/app/session_results.py +76 -0
  102. microgridspy-0.4.0/src/microgridspy/app/typical_year_results_page.py +1014 -0
  103. microgridspy-0.4.0/src/microgridspy/cli.py +142 -0
  104. microgridspy-0.4.0/src/microgridspy/data_pipeline/__init__.py +1 -0
  105. microgridspy-0.4.0/src/microgridspy/data_pipeline/battery_degradation_coefficients.py +358 -0
  106. microgridspy-0.4.0/src/microgridspy/data_pipeline/battery_degradation_model.py +108 -0
  107. microgridspy-0.4.0/src/microgridspy/data_pipeline/battery_loss_model.py +336 -0
  108. microgridspy-0.4.0/src/microgridspy/data_pipeline/generator_partial_load_model.py +82 -0
  109. microgridspy-0.4.0/src/microgridspy/data_pipeline/layer1_liion_coefficients.json +366 -0
  110. microgridspy-0.4.0/src/microgridspy/data_pipeline/loader.py +76 -0
  111. microgridspy-0.4.0/src/microgridspy/data_pipeline/multi_year_loader.py +75 -0
  112. microgridspy-0.4.0/src/microgridspy/data_pipeline/typical_year_loader.py +475 -0
  113. microgridspy-0.4.0/src/microgridspy/data_pipeline/typical_year_parsing.py +1295 -0
  114. microgridspy-0.4.0/src/microgridspy/data_pipeline/utils.py +176 -0
  115. microgridspy-0.4.0/src/microgridspy/errors.py +19 -0
  116. microgridspy-0.4.0/src/microgridspy/examples/demo_multi_year/inputs/README_inputs.md +49 -0
  117. microgridspy-0.4.0/src/microgridspy/examples/demo_multi_year/inputs/battery.yaml +105 -0
  118. microgridspy-0.4.0/src/microgridspy/examples/demo_multi_year/inputs/formulation.json +74 -0
  119. microgridspy-0.4.0/src/microgridspy/examples/demo_multi_year/inputs/generator.yaml +114 -0
  120. microgridspy-0.4.0/src/microgridspy/examples/demo_multi_year/inputs/load_demand.csv +8762 -0
  121. microgridspy-0.4.0/src/microgridspy/examples/demo_multi_year/inputs/renewables.yaml +88 -0
  122. microgridspy-0.4.0/src/microgridspy/examples/demo_multi_year/inputs/resource_availability.csv +8763 -0
  123. microgridspy-0.4.0/src/microgridspy/examples/demo_typical_year/inputs/README_inputs.md +51 -0
  124. microgridspy-0.4.0/src/microgridspy/examples/demo_typical_year/inputs/battery.yaml +102 -0
  125. microgridspy-0.4.0/src/microgridspy/examples/demo_typical_year/inputs/formulation.json +74 -0
  126. microgridspy-0.4.0/src/microgridspy/examples/demo_typical_year/inputs/generator.yaml +89 -0
  127. microgridspy-0.4.0/src/microgridspy/examples/demo_typical_year/inputs/load_demand.csv +8762 -0
  128. microgridspy-0.4.0/src/microgridspy/examples/demo_typical_year/inputs/renewables.yaml +87 -0
  129. microgridspy-0.4.0/src/microgridspy/examples/demo_typical_year/inputs/resource_availability.csv +8763 -0
  130. microgridspy-0.4.0/src/microgridspy/export/__init__.py +1 -0
  131. microgridspy-0.4.0/src/microgridspy/export/common.py +139 -0
  132. microgridspy-0.4.0/src/microgridspy/export/multi_year_results.py +2426 -0
  133. microgridspy-0.4.0/src/microgridspy/export/results_bundle.py +73 -0
  134. microgridspy-0.4.0/src/microgridspy/export/results_page_helpers.py +234 -0
  135. microgridspy-0.4.0/src/microgridspy/export/typical_year_reporting.py +914 -0
  136. microgridspy-0.4.0/src/microgridspy/export/typical_year_results.py +880 -0
  137. microgridspy-0.4.0/src/microgridspy/finance.py +51 -0
  138. microgridspy-0.4.0/src/microgridspy/io/__init__.py +0 -0
  139. microgridspy-0.4.0/src/microgridspy/io/csv_format.py +100 -0
  140. microgridspy-0.4.0/src/microgridspy/io/examples.py +93 -0
  141. microgridspy-0.4.0/src/microgridspy/io/formulation.py +19 -0
  142. microgridspy-0.4.0/src/microgridspy/io/input_labels.py +29 -0
  143. microgridspy-0.4.0/src/microgridspy/io/jsonio.py +58 -0
  144. microgridspy-0.4.0/src/microgridspy/io/paths.py +25 -0
  145. microgridspy-0.4.0/src/microgridspy/io/project_setup.py +384 -0
  146. microgridspy-0.4.0/src/microgridspy/io/templates.py +1644 -0
  147. microgridspy-0.4.0/src/microgridspy/io/utils.py +363 -0
  148. microgridspy-0.4.0/src/microgridspy/io/vintage_labels.py +114 -0
  149. microgridspy-0.4.0/src/microgridspy/multi_year_model/__init__.py +0 -0
  150. microgridspy-0.4.0/src/microgridspy/multi_year_model/constraints.py +848 -0
  151. microgridspy-0.4.0/src/microgridspy/multi_year_model/data.py +2235 -0
  152. microgridspy-0.4.0/src/microgridspy/multi_year_model/lifecycle.py +186 -0
  153. microgridspy-0.4.0/src/microgridspy/multi_year_model/model.py +402 -0
  154. microgridspy-0.4.0/src/microgridspy/multi_year_model/objective.py +389 -0
  155. microgridspy-0.4.0/src/microgridspy/multi_year_model/params.py +186 -0
  156. microgridspy-0.4.0/src/microgridspy/multi_year_model/sets.py +183 -0
  157. microgridspy-0.4.0/src/microgridspy/multi_year_model/variables.py +286 -0
  158. microgridspy-0.4.0/src/microgridspy/py.typed +0 -0
  159. microgridspy-0.4.0/src/microgridspy/typical_year_model/__init__.py +0 -0
  160. microgridspy-0.4.0/src/microgridspy/typical_year_model/constraints.py +547 -0
  161. microgridspy-0.4.0/src/microgridspy/typical_year_model/data.py +9 -0
  162. microgridspy-0.4.0/src/microgridspy/typical_year_model/model.py +379 -0
  163. microgridspy-0.4.0/src/microgridspy/typical_year_model/objective.py +355 -0
  164. microgridspy-0.4.0/src/microgridspy/typical_year_model/params.py +180 -0
  165. microgridspy-0.4.0/src/microgridspy/typical_year_model/sets.py +77 -0
  166. microgridspy-0.4.0/src/microgridspy/typical_year_model/variables.py +254 -0
  167. microgridspy-0.4.0/src/microgridspy/visualization/__init__.py +0 -0
  168. microgridspy-0.4.0/src/microgridspy/visualization/input_plots.py +93 -0
  169. microgridspy-0.4.0/src/microgridspy/visualization/plots.py +48 -0
  170. microgridspy-0.4.0/tests/test_battery_degradation.py +519 -0
  171. microgridspy-0.4.0/tests/test_battery_degradation_coefficients.py +372 -0
  172. microgridspy-0.4.0/tests/test_battery_loss_curve.py +153 -0
  173. microgridspy-0.4.0/tests/test_cli.py +77 -0
  174. microgridspy-0.4.0/tests/test_formulation_naming.py +55 -0
  175. microgridspy-0.4.0/tests/test_generator_partial_load.py +121 -0
  176. microgridspy-0.4.0/tests/test_multi_year_inverters.py +721 -0
  177. microgridspy-0.4.0/tests/test_public_api.py +143 -0
  178. microgridspy-0.4.0/tests/test_typical_year_degradation.py +221 -0
  179. microgridspy-0.4.0/tests/test_typical_year_inverters.py +743 -0
  180. microgridspy-0.4.0/zensical.toml +134 -0
@@ -0,0 +1,33 @@
1
+ name: ci
2
+
3
+ on:
4
+ push:
5
+ branches: ["master", "main"]
6
+ pull_request:
7
+
8
+ jobs:
9
+ test:
10
+ runs-on: ubuntu-latest
11
+ strategy:
12
+ fail-fast: false
13
+ matrix:
14
+ python-version: ["3.10", "3.11", "3.12"]
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+ with:
18
+ fetch-depth: 0 # tags needed for hatch-vcs to derive the version
19
+ - uses: actions/setup-python@v5
20
+ with:
21
+ python-version: ${{ matrix.python-version }}
22
+ - name: Install (with dev + open-source solver)
23
+ run: |
24
+ python -m pip install --upgrade pip
25
+ pip install -e ".[dev,highs]"
26
+ - name: Lint
27
+ run: |
28
+ ruff check .
29
+ ruff format --check .
30
+ - name: Test (with coverage)
31
+ run: |
32
+ coverage run -m pytest -q
33
+ coverage report
@@ -0,0 +1,30 @@
1
+ name: draft-pdf
2
+
3
+ # Compiles the JOSS paper to a PDF on changes, so the draft can be previewed.
4
+ # The compiled PDF is uploaded as a build artifact (it is not committed).
5
+ on:
6
+ push:
7
+ paths:
8
+ - "paper/**"
9
+ - ".github/workflows/draft-pdf.yml"
10
+ workflow_dispatch:
11
+
12
+ jobs:
13
+ paper:
14
+ runs-on: ubuntu-latest
15
+ name: Paper Draft
16
+ steps:
17
+ - name: Checkout
18
+ uses: actions/checkout@v4
19
+
20
+ - name: Build draft PDF
21
+ uses: openjournals/openjournals-draft-action@master
22
+ with:
23
+ journal: joss
24
+ paper-path: paper/paper.md
25
+
26
+ - name: Upload
27
+ uses: actions/upload-artifact@v4
28
+ with:
29
+ name: paper
30
+ path: paper/paper.pdf
@@ -0,0 +1,35 @@
1
+ name: release
2
+
3
+ on:
4
+ push:
5
+ tags: ["v*"]
6
+
7
+ jobs:
8
+ build:
9
+ runs-on: ubuntu-latest
10
+ steps:
11
+ - uses: actions/checkout@v4
12
+ with:
13
+ fetch-depth: 0 # full history + tags for hatch-vcs
14
+ - uses: actions/setup-python@v5
15
+ with:
16
+ python-version: "3.12"
17
+ - run: python -m pip install --upgrade build
18
+ - run: python -m build
19
+ - uses: actions/upload-artifact@v4
20
+ with:
21
+ name: dist
22
+ path: dist/
23
+
24
+ publish:
25
+ needs: build
26
+ runs-on: ubuntu-latest
27
+ environment: pypi
28
+ permissions:
29
+ id-token: write # OIDC: Trusted Publishing, no API token stored
30
+ steps:
31
+ - uses: actions/download-artifact@v4
32
+ with:
33
+ name: dist
34
+ path: dist/
35
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,41 @@
1
+ # Byte-compiled / cache
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # Build / packaging artifacts
7
+ build/
8
+ dist/
9
+ *.egg-info/
10
+ .eggs/
11
+
12
+ # Test / lint caches
13
+ .pytest_cache/
14
+ .cache/
15
+ .ruff_cache/
16
+ .coverage
17
+ htmlcov/
18
+
19
+ # Docs build output
20
+ docs/_build/
21
+ site/
22
+
23
+ # Virtual environments
24
+ .venv/
25
+ venv/
26
+ env/
27
+
28
+ # Editors / IDE
29
+ .history/
30
+ .vscode/
31
+ .idea/
32
+
33
+ # OS cruft
34
+ .DS_Store
35
+ Thumbs.db
36
+
37
+ # The local workspace. `projects/` is created at runtime by create_project()/the GUI
38
+ # and holds whatever the user is working on, so none of it belongs in the repository.
39
+ # The two demo projects ship inside the package (src/microgridspy/examples/), and the
40
+ # Kalobeyei case studies are published as a separate archive - see docs/examples/.
41
+ projects/
@@ -0,0 +1,39 @@
1
+ # Canonical contributor identities.
2
+ #
3
+ # Git records whatever name/email was configured on the machine that made each
4
+ # commit, so one person can appear several times. This file maps those variants
5
+ # onto a single canonical identity; `git shortlog`, `git log` and most analysis
6
+ # tools honour it. No history is rewritten - only the display is corrected.
7
+ #
8
+ # Syntax: Canonical Name <canonical@email> Recorded Name <recorded@email>
9
+ # Canonical names/emails follow AUTHORS where the person is listed there.
10
+
11
+ # --- Universite de Liege: original authors ---
12
+ Sergio Balderrama <slbalderrama@doct.ulg.ac.be> Sergio Balderrama <sergiob44_47@hotmail.com>
13
+ Sergio Balderrama <slbalderrama@doct.ulg.ac.be> Sergio Balderra <sergiob44_47@hotmail.com>
14
+ Sergio Balderrama <slbalderrama@doct.ulg.ac.be> Slbalderrama <sergiob44_47@hotmail.com>
15
+ Sergio Balderrama <slbalderrama@doct.ulg.ac.be> slbalderrama <sergiob44_47@hotmail.com>
16
+ Sylvain Quoilin <squoilin@uliege.be> Sylvain Quoilin <squoilin@ulg.ac.be>
17
+ Sylvain Quoilin <squoilin@uliege.be> Sylvain Quoilin <sylvain.quoilin@ec.europa.eu>
18
+
19
+ # --- Politecnico di Milano ---
20
+ Alessandro Onori <alessandro.onori@polimi.it> AleOnori98 <onorialessandro1998@gmail.com>
21
+ Alessandro Onori <alessandro.onori@polimi.it> AleOnori98 <63561931+AleOnori98@users.noreply.github.com>
22
+ Alessandro Onori <alessandro.onori@polimi.it> Alessandro Onori <63561931+AleOnori98@users.noreply.github.com>
23
+ Nicolò Stevanato <nicolo.stevanato@polimi.it> Nicolò Stevanato <nicolo.stevanato@mail.polimi.it>
24
+ Gianluca Pellecchia <gianluca.pellecchia@polimi.it> Gianluca Pellecchia <gianluca.pellecchia@mail.polimi.it>
25
+ Gianluca Pellecchia <gianluca.pellecchia@polimi.it> gianlucapellecchia <gianluca.pellecchia@mail.polimi.it>
26
+ Lorenzo Rinaldi <lorenzo.rinaldi@polimi.it> LorenzoRinaldi <lorenzo.rinaldi1@gmail.com>
27
+ Lorenzo Rinaldi <lorenzo.rinaldi@polimi.it> LorenzoRinaldi <43796440+LorenzoRinaldi@users.noreply.github.com>
28
+ Giulia Guidicini <giulia.guidicini@polimi.it> Giulia Guidicini <43995656+gguidicini@users.noreply.github.com>
29
+ Ivan Sangiorgio <ivan.sangiorgio@polimi.it> Ivan Sangiorgio <73618037+ivansangiorgio@users.noreply.github.com>
30
+
31
+ # --- TU Delft ---
32
+ Francesco Lombardi <f.lombardi@tudelft.nl> Francesco Lombardi <francesco.lombardi@polimi.it>
33
+ Francesco Lombardi <f.lombardi@tudelft.nl> Francesco Lombardi <f.lombardi@outlook.com>
34
+ Francesco Lombardi <f.lombardi@tudelft.nl> FLomb <francesco.lombardi@polimi.it>
35
+ Francesco Lombardi <f.lombardi@tudelft.nl> FLomb <f.lombardi@outlook.com>
36
+
37
+ # --- Display-name normalisation only (canonical email not confirmed) ---
38
+ Giacomo Crevani <giacomo.crevani@mail.polimi.it> GiacomoCrevani <giacomo.crevani@mail.polimi.it>
39
+ Costanza Summaria <83756734+costisum@users.noreply.github.com> costanzasummaria <83756734+costisum@users.noreply.github.com>
@@ -0,0 +1,19 @@
1
+ # Read the Docs build configuration.
2
+ # RTD is the build/host layer only: it installs the tools, runs the Zensical
3
+ # build, and publishes the result. Zensical is the site generator; mkdocstrings
4
+ # produces the API reference. See https://docs.readthedocs.io/en/stable/config-file/
5
+ version: 2
6
+
7
+ build:
8
+ os: ubuntu-24.04
9
+ tools:
10
+ python: "3.12"
11
+ commands:
12
+ # Zensical (site generator) + mkdocstrings Python handler (API extraction).
13
+ # mkdocstrings reads the package statically from src/ (paths=["src"] in
14
+ # zensical.toml), so MicroGridsPy itself need not be installed.
15
+ - pip install zensical mkdocstrings-python
16
+ # Build the static site into ./site, then hand it to Read the Docs.
17
+ - zensical build
18
+ - mkdir -p "$READTHEDOCS_OUTPUT/html"
19
+ - cp -r site/. "$READTHEDOCS_OUTPUT/html/"
@@ -0,0 +1,68 @@
1
+ # Authors
2
+
3
+ MicroGridsPy is an open-source mini-grid sizing and dispatch model originally developed by
4
+ Sergio Balderrama and Sylvain Quoilin at the Université de Liège. It was subsequently extended
5
+ through research projects and publications involving the SESAM group at Politecnico di Milano and other collaborators.
6
+
7
+ The current version is a **major redevelopment** of the original model: it has been restructured
8
+ as an installable Python package based on Linopy, with a stable API and fully integrated GUI, and includes new consistent economic,
9
+ battery degradation, inverter sizing, expanded stochastic optimisation and multi-year capacity-expansion features.
10
+
11
+ ## Main developer and maintainer
12
+
13
+ - Alessandro Onori, Politecnico di Milano
14
+ <alessandro.onori@polimi.it> — ORCID: 0009-0009-1195-2078
15
+
16
+ ## Current contributors and Scientific advisory
17
+
18
+ - Nicolò Stevanato, Politecnico di Milano
19
+ <nicolo.stevanato@polimi.it> — ORCID: 0000-0002-3419-0389
20
+ - Riccardo Mereu, Politecnico di Milano
21
+ <riccardo.mereu@polimi.it> — ORCID: 0000-0003-0544-595X
22
+ - Emanuela Colombo, Politecnico di Milano
23
+ <emanuela.colombo@polimi.it> — ORCID: 0000-0002-9747-5699
24
+
25
+ ## Past contributors
26
+
27
+ The following contributors worked on **earlier versions** of MicroGridsPy, **up to the 2023 release line**:
28
+
29
+ - Francesco Lombardi, TU Delft
30
+ — El Espino (2019), PowerTech (2019), MYCE (2020)
31
+ - Giulia Guidicini, Politecnico di Milano
32
+ — MYCE (2020)
33
+ - Lorenzo Rinaldi, Politecnico di Milano
34
+ — MYCE (2020)
35
+ - Gianluca Pellecchia, Politecnico di Milano
36
+ — Third-generation minigrids (2023)
37
+ - Ivan Sangiorgio, Politecnico di Milano
38
+ — Third-generation minigrids (2023)
39
+
40
+ The original MicroGridsPy framework and **first open-source release (2019)** were developed at the Université de Liège:
41
+
42
+ - Sergio Balderrama, Université de Liège
43
+ - Sylvain Quoilin, Université de Liège
44
+
45
+ ## Development history
46
+
47
+ Key publications documenting the development of the model include:
48
+
49
+ - **El Espino (2019)** — S. Balderrama, F. Lombardi, F. Riva, W. Canedo, E. Colombo,
50
+ S. Quoilin. "A two-stage linear programming optimization framework for isolated hybrid
51
+ microgrids in a rural context: the case study of the 'El Espino' community." *Energy* 188
52
+ (2019) 116073. https://doi.org/10.1016/j.energy.2019.116073
53
+ - **PowerTech (2019)** — N. Stevanato, F. Lombardi, E. Colombo, S. Balderrama, S. Quoilin.
54
+ "Two-stage stochastic sizing of a rural micro-grid based on stochastic load generation."
55
+ *2019 IEEE Milan PowerTech*, pp. 1–6. https://doi.org/10.1109/PTC.2019.8810571
56
+ - **MYCE (2020)** — N. Stevanato, F. Lombardi, G. Guidicini, L. Rinaldi, S. L. Balderrama,
57
+ M. Pavičević, S. Quoilin, E. Colombo. "Long-term sizing of rural microgrids: accounting
58
+ for load evolution through multi-step investment plan and stochastic optimization."
59
+ *Energy for Sustainable Development* 58 (2020) 16–29.
60
+ https://doi.org/10.1016/j.esd.2020.07.002
61
+ - **Third-generation minigrids (2023)** — N. Stevanato, G. Pellecchia, I. Sangiorgio,
62
+ D. Shendrikova, C. A. Soares, R. Mereu, E. Colombo. "Planning third generation minigrids:
63
+ multi-objective optimization and brownfield investment approaches in modelling
64
+ village-scale on-grid and off-grid energy systems." *Renewable and Sustainable Energy
65
+ Transition* 3 (2023) 100053. https://doi.org/10.1016/j.rset.2023.100053
66
+ - **Financing schemes, ECOS (2023)** — G. Crevani, C. Soares, E. Colombo. "Modelling
67
+ financing schemes for energy system planning: a mini-grid case study." *Proceedings of
68
+ ECOS 2023*, pp. 1958–1969.
@@ -0,0 +1,110 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. The format is based on
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project
5
+ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [0.4.0] - 2026-09-25
10
+
11
+ ### Fixed
12
+ - **Multi-year battery energy balance closes at the end of the horizon.** `soc_balance`
13
+ linked `soc[t] -> soc[t+1]` only up to the second-to-last period, and `soc_year_link_*`
14
+ only carried state *between* years, so the state implied after the final period of the
15
+ final year was unbounded: the battery could discharge energy it had never stored in that
16
+ last step. New `soc_terminal_upper` / `soc_terminal_lower` constraints apply the same
17
+ bounds to that state. The typical-year formulation was never affected — its `soc_cyclic`
18
+ constraint already closed the loop.
19
+ The leak only bound when the battery would otherwise be empty at the horizon end, so
20
+ long hourly runs are unlikely to change: on `demo_multi_year` the final-hour discharge
21
+ (18.9 kWh) was already covered by stored energy (664.2 kWh). Short or reduced-resolution
22
+ horizons could be affected materially.
23
+
24
+ ### Changed
25
+ - **BREAKING — the two formulations are now named `typical_year` and `multi_year`
26
+ everywhere**: in `formulation.json`, in `create_project(formulation=...)`, in the CLI
27
+ `--formulation` choices and in the model class names. Previously the same two concepts
28
+ were spelled three ways (`steady_state`/`dynamic` in data and the API, `typical_year`/
29
+ `multi_year` in module names and docs, `SteadyStateModel`/`MultiYearModel` in code).
30
+ Projects created by earlier releases must set `core_formulation` to the new name; the
31
+ old spellings now raise `InputValidationError` instead of being translated.
32
+ - **BREAKING — `SteadyStateModel` was removed.** Use `TypicalYearModel`.
33
+ - **One exception type.** `InputValidationError` was defined separately in 20 modules, so
34
+ `except microgridspy.InputValidationError` did not catch errors raised by most of the
35
+ package. It now lives in `microgridspy.errors` and every layer raises that one class.
36
+ - **One capital-recovery factor.** `_crf` was implemented five times, with three different
37
+ zero-rate tolerances and three different answers for a non-positive lifetime, so the
38
+ annuity used in the objective could differ from the annuity shown in the results. It now
39
+ lives in `microgridspy.finance.crf`. For a non-positive lifetime it returns `nan`
40
+ (previously `0.0`, `nan` or `inf` depending on which copy ran).
41
+
42
+ ### Removed
43
+ - Dead code: `export/csv_reader.py`, `export/manifest.py`, `export/yaml_reader.py`,
44
+ `app/typical_year_file_results_page.py` and 17 unreferenced functions.
45
+ - The `error_cls` parameter threaded through the IO and coercion helpers, which existed
46
+ only to select between the duplicate exception classes.
47
+ - The duplicated session state on the Optimization page: a solved run was stored four ways
48
+ (`gp_sets`/`gp_data`/`gp_vars`, the results bundle and the two typed results objects).
49
+ Only the bundle and the typed results remain.
50
+ - `pre-commit` from the `dev` extra — the project has no pre-commit configuration.
51
+
52
+ ## [0.2.0] - 2026-08-24
53
+
54
+ ### Added
55
+ - Project management: `delete_project`, `copy_project`, `rename_project`.
56
+ - `load_inputs()` — assemble a project's input dataset without solving.
57
+ - `list_input_timeseries()` and `plot_input_timeseries()` — input time-series
58
+ plots returned as matplotlib figures.
59
+ - `to_excel()` method on `TypicalYearResults` / `MultiYearResults`.
60
+ - `microgridspy` command-line interface (`list` / `create` / `validate` / `solve`).
61
+
62
+ ### Changed
63
+ - Removed outdated files (broken `requirements.txt`, `environment_nobuilds.yml`,
64
+ documentation PDFs); README rewritten for `pip install` and the Python API.
65
+ - Home page: the PDF previews were replaced with a documentation-link placeholder.
66
+ - The `formulation.json` builder is shared between the GUI and the library.
67
+ - Whole codebase formatted and linted with ruff.
68
+ - Added a package-level test suite (`tests/test_public_api.py`); `ruff check`,
69
+ `ruff format --check`, and `pytest` all pass.
70
+
71
+ ### Fixed
72
+ - `results_summary()` now reads the objective from `model.objective.value`, so the
73
+ headline objective value is populated instead of `None`.
74
+ - Restored 3 multi-year inverter tests whose fixture was missing the
75
+ `year_inv_step` mapping.
76
+
77
+ ## [0.1.0] - 2026-08-24
78
+
79
+ First pip-installable release.
80
+
81
+ ### Added
82
+ - `pyproject.toml` (Hatchling + hatch-vcs): git-tag-driven versioning, the
83
+ `microgridspy-gui` console entry point, and optional extras `gui`, `highs`,
84
+ `gurobi`, `dev`.
85
+ - `src/` layout; the package is importable as `microgridspy`.
86
+ - Public API:
87
+ - `SteadyStateModel`, `MultiYearModel` with `solve_single_objective()`,
88
+ `results()` and `results_summary()`.
89
+ - `solve()`, `load_results()`, `export_results()` convenience functions.
90
+ - `create_project()`, `validate_project()` for headless project scaffolding.
91
+ - `set_workspace()`, `list_projects()`, `project_paths()`, `project_exists()`.
92
+ - `TypicalYearResults`, `MultiYearResults`, `InputValidationError`.
93
+ - `MICROGRIDSPY_WORKSPACE` environment variable to locate the projects folder.
94
+
95
+ ### Changed
96
+ - Renamed the importable package from `core` to `microgridspy`.
97
+ - Moved the Streamlit GUI into the `microgridspy.app` subpackage; installing the
98
+ core no longer requires Streamlit (it is gated behind the `gui` extra).
99
+ - The GUI's project-creation writes `formulation.json` via the shared
100
+ `microgridspy.io.project_setup.build_formulation_payload`, so the app and the
101
+ library stay in lock-step.
102
+
103
+ ### Fixed
104
+ - Optimal HiGHS solves were reported as "no feasible solution" because the
105
+ result gate grepped the solver log for a Gurobi-specific marker. Detection now
106
+ uses the in-memory linopy solution, so HiGHS and Gurobi both work.
107
+
108
+ [Unreleased]: https://github.com/MicroGridsPy/MicroGridsPy/compare/v0.2.0...HEAD
109
+ [0.2.0]: https://github.com/MicroGridsPy/MicroGridsPy/compare/v0.1.0...v0.2.0
110
+ [0.1.0]: https://github.com/MicroGridsPy/MicroGridsPy/releases/tag/v0.1.0
@@ -0,0 +1,107 @@
1
+ # Citation metadata for MicroGridsPy.
2
+ #
3
+ # Author order follows AUTHORS: the maintainer of the current redevelopment first,
4
+ # then current contributors and scientific advisory, then contributors to earlier
5
+ # versions, then the original authors of the model at the Universite de Liege.
6
+ #
7
+ # When the JOSS paper is published, add a `preferred-citation:` block here pointing
8
+ # to it; GitHub and citation tools will then offer the paper instead of the software.
9
+ cff-version: 1.2.0
10
+ message: "If you use MicroGridsPy in your research, please cite it as below."
11
+ title: "MicroGridsPy: bottom-up optimization of mini-grids for rural electrification"
12
+ abstract: >-
13
+ MicroGridsPy is an open-source Python package for the techno-economic planning of
14
+ mini-grid energy systems in remote and underserved areas. It sizes and dispatches
15
+ renewable generation, battery storage, backup generators and optional grid connection
16
+ by linear and mixed-integer optimization, supporting typical-year and multi-year
17
+ capacity-expansion formulations, single- and multi-scenario studies, and both
18
+ continuous and discrete sizing. It is built on Linopy and ships with a command-line
19
+ interface, a documented Python API and an optional Streamlit graphical interface.
20
+ type: software
21
+ version: "0.4.0"
22
+ date-released: "2026-09-25"
23
+ license: EUPL-1.2
24
+ repository-code: "https://github.com/MicroGridsPy/MicroGridsPy"
25
+ url: "https://microgridspy-package-docs.readthedocs.io/"
26
+ keywords:
27
+ - energy
28
+ - mini-grid
29
+ - rural electrification
30
+ - energy access
31
+ - optimization
32
+ - linopy
33
+ - capacity expansion
34
+ authors:
35
+ # Main developer and maintainer of the current version.
36
+ - family-names: Onori
37
+ given-names: Alessandro
38
+ affiliation: "Politecnico di Milano"
39
+ email: alessandro.onori@polimi.it
40
+ orcid: "https://orcid.org/0009-0009-1195-2078"
41
+ # Current contributors and scientific advisory.
42
+ - family-names: Stevanato
43
+ given-names: "Nicolo"
44
+ affiliation: "Politecnico di Milano"
45
+ email: nicolo.stevanato@polimi.it
46
+ orcid: "https://orcid.org/0000-0002-3419-0389"
47
+ - family-names: Colombo
48
+ given-names: Emanuela
49
+ affiliation: "Politecnico di Milano"
50
+ email: emanuela.colombo@polimi.it
51
+ orcid: "https://orcid.org/0000-0002-9747-5699"
52
+ - family-names: Mereu
53
+ given-names: Riccardo
54
+ affiliation: "Politecnico di Milano"
55
+ email: riccardo.mereu@polimi.it
56
+ orcid: "https://orcid.org/0000-0003-0544-595X"
57
+ # Contributors to earlier versions.
58
+ - family-names: Lombardi
59
+ given-names: Francesco
60
+ affiliation: "Delft University of Technology"
61
+ email: f.lombardi@tudelft.nl
62
+ - family-names: Guidicini
63
+ given-names: Giulia
64
+ affiliation: "Politecnico di Milano"
65
+ email: giulia.guidicini@polimi.it
66
+ - family-names: Rinaldi
67
+ given-names: Lorenzo
68
+ affiliation: "Politecnico di Milano"
69
+ email: lorenzo.rinaldi@polimi.it
70
+ - family-names: Pellecchia
71
+ given-names: Gianluca
72
+ affiliation: "Politecnico di Milano"
73
+ email: gianluca.pellecchia@polimi.it
74
+ - family-names: Sangiorgio
75
+ given-names: Ivan
76
+ affiliation: "Politecnico di Milano"
77
+ email: ivan.sangiorgio@polimi.it
78
+ # Original authors of the model (Universite de Liege, first release 2019).
79
+ - family-names: Balderrama
80
+ given-names: Sergio
81
+ affiliation: "Universidad Mayor de San Simon / Universite de Liege"
82
+ email: slbalderrama@doct.ulg.ac.be
83
+ orcid: "https://orcid.org/0000-0003-0656-3544"
84
+ - family-names: Quoilin
85
+ given-names: Sylvain
86
+ affiliation: "KU Leuven"
87
+ email: squoilin@uliege.be
88
+ orcid: "https://orcid.org/0000-0002-2064-209X"
89
+ references:
90
+ - type: dataset
91
+ title: "Kalobeyei case-study dataset for MicroGridsPy: seven mini-grid planning scenarios"
92
+ doi: 10.5281/zenodo.22958510
93
+ notes: "Inputs, results and solver logs for the seven scenarios documented in the Examples section."
94
+ authors:
95
+ - family-names: Onori
96
+ given-names: Alessandro
97
+ - type: software
98
+ title: "MicroGridsPy-Pyomo: archived Pyomo implementation of the MicroGridsPy mini-grid planning model"
99
+ doi: 10.5281/zenodo.22900498
100
+ version: "2.1"
101
+ year: 2026
102
+ notes: "The archived Pyomo implementation superseded by this package."
103
+ authors:
104
+ - family-names: Balderrama
105
+ given-names: Sergio
106
+ - family-names: Quoilin
107
+ given-names: Sylvain
@@ -0,0 +1,133 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ We as members, contributors, and leaders pledge to make participation in our
6
+ community a harassment-free experience for everyone, regardless of age, body
7
+ size, visible or invisible disability, ethnicity, sex characteristics, gender
8
+ identity and expression, level of experience, education, socio-economic status,
9
+ nationality, personal appearance, race, caste, color, religion, or sexual
10
+ identity and orientation.
11
+
12
+ We pledge to act and interact in ways that contribute to an open, welcoming,
13
+ diverse, inclusive, and healthy community.
14
+
15
+ ## Our Standards
16
+
17
+ Examples of behavior that contributes to a positive environment for our
18
+ community include:
19
+
20
+ - Demonstrating empathy and kindness toward other people
21
+ - Being respectful of differing opinions, viewpoints, and experiences
22
+ - Giving and gracefully accepting constructive feedback
23
+ - Accepting responsibility and apologizing to those affected by our mistakes,
24
+ and learning from the experience
25
+ - Focusing on what is best not just for us as individuals, but for the overall
26
+ community
27
+
28
+ Examples of unacceptable behavior include:
29
+
30
+ - The use of sexualized language or imagery, and sexual attention or advances of
31
+ any kind
32
+ - Trolling, insulting or derogatory comments, and personal or political attacks
33
+ - Public or private harassment
34
+ - Publishing others' private information, such as a physical or email address,
35
+ without their explicit permission
36
+ - Other conduct which could reasonably be considered inappropriate in a
37
+ professional setting
38
+
39
+ ## Enforcement Responsibilities
40
+
41
+ Community leaders are responsible for clarifying and enforcing our standards of
42
+ acceptable behavior and will take appropriate and fair corrective action in
43
+ response to any behavior that they deem inappropriate, threatening, offensive,
44
+ or harmful.
45
+
46
+ Community leaders have the right and responsibility to remove, edit, or reject
47
+ comments, commits, code, wiki edits, issues, and other contributions that are
48
+ not aligned to this Code of Conduct, and will communicate reasons for moderation
49
+ decisions when appropriate.
50
+
51
+ ## Scope
52
+
53
+ This Code of Conduct applies within all community spaces, and also applies when
54
+ an individual is officially representing the community in public spaces.
55
+ Examples of representing our community include using an official email address,
56
+ posting via an official social media account, or acting as an appointed
57
+ representative at an online or offline event.
58
+
59
+ ## Enforcement
60
+
61
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
62
+ reported to the community leaders responsible for enforcement at
63
+ **alessandro.onori@polimi.it**.
64
+ <!-- TODO: replace with a dedicated conduct-reporting address if the project adopts one. -->
65
+ All complaints will be reviewed and investigated promptly and fairly.
66
+
67
+ All community leaders are obligated to respect the privacy and security of the
68
+ reporter of any incident.
69
+
70
+ ## Enforcement Guidelines
71
+
72
+ Community leaders will follow these Community Impact Guidelines in determining
73
+ the consequences for any action they deem in violation of this Code of Conduct:
74
+
75
+ ### 1. Correction
76
+
77
+ **Community Impact**: Use of inappropriate language or other behavior deemed
78
+ unprofessional or unwelcome in the community.
79
+
80
+ **Consequence**: A private, written warning from community leaders, providing
81
+ clarity around the nature of the violation and an explanation of why the
82
+ behavior was inappropriate. A public apology may be requested.
83
+
84
+ ### 2. Warning
85
+
86
+ **Community Impact**: A violation through a single incident or series of
87
+ actions.
88
+
89
+ **Consequence**: A warning with consequences for continued behavior. No
90
+ interaction with the people involved, including unsolicited interaction with
91
+ those enforcing the Code of Conduct, for a specified period of time. This
92
+ includes avoiding interactions in community spaces as well as external channels
93
+ like social media. Violating these terms may lead to a temporary or permanent
94
+ ban.
95
+
96
+ ### 3. Temporary Ban
97
+
98
+ **Community Impact**: A serious violation of community standards, including
99
+ sustained inappropriate behavior.
100
+
101
+ **Consequence**: A temporary ban from any sort of interaction or public
102
+ communication with the community for a specified period of time. No public or
103
+ private interaction with the people involved, including unsolicited interaction
104
+ with those enforcing the Code of Conduct, is allowed during this period.
105
+ Violating these terms may lead to a permanent ban.
106
+
107
+ ### 4. Permanent Ban
108
+
109
+ **Community Impact**: Demonstrating a pattern of violation of community
110
+ standards, including sustained inappropriate behavior, harassment of an
111
+ individual, or aggression toward or disparagement of classes of individuals.
112
+
113
+ **Consequence**: A permanent ban from any sort of public interaction within the
114
+ community.
115
+
116
+ ## Attribution
117
+
118
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
119
+ version 2.1, available at
120
+ [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
121
+
122
+ Community Impact Guidelines were inspired by
123
+ [Mozilla's code of conduct enforcement ladder][mozilla coc].
124
+
125
+ For answers to common questions about this code of conduct, see the FAQ at
126
+ [https://www.contributor-covenant.org/faq][faq]. Translations are available at
127
+ [https://www.contributor-covenant.org/translations][translations].
128
+
129
+ [homepage]: https://www.contributor-covenant.org
130
+ [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
131
+ [mozilla coc]: https://github.com/mozilla/diversity
132
+ [faq]: https://www.contributor-covenant.org/faq
133
+ [translations]: https://www.contributor-covenant.org/translations
@@ -0,0 +1,48 @@
1
+ # Contributing to MicroGridsPy
2
+
3
+ Thanks for your interest in improving MicroGridsPy! Contributions of all kinds are
4
+ welcome — bug reports, feature requests, documentation, and code. For
5
+ documentation-specific conventions, see
6
+ [`docs/developers/contributing.md`](docs/developers/contributing.md).
7
+
8
+ ## Reporting issues
9
+
10
+ Please open an issue on the
11
+ [issue tracker](https://github.com/MicroGridsPy/MicroGridsPy/issues) and include, where
12
+ relevant: what you expected, what happened, a minimal example (or project inputs) that
13
+ reproduces the problem, your OS, Python version, and MicroGridsPy version
14
+ (`python -c "import microgridspy; print(microgridspy.__version__)"`).
15
+
16
+ ## Development setup
17
+
18
+ ```bash
19
+ git clone https://github.com/MicroGridsPy/MicroGridsPy.git
20
+ cd MicroGridsPy
21
+ pip install -e ".[highs,dev]"
22
+ ```
23
+
24
+ ## Before opening a pull request
25
+
26
+ - Keep changes focused and describe the motivation in the PR.
27
+ - Run the linters and tests locally:
28
+
29
+ ```bash
30
+ ruff check .
31
+ ruff format --check .
32
+ pytest
33
+ ```
34
+
35
+ - Update [`CHANGELOG.md`](CHANGELOG.md) when behavior changes.
36
+ - Add or update tests for new behavior, and update the docs when relevant
37
+ (keep API details in docstrings — the API reference is generated from them).
38
+ - If you build the docs, verify they build cleanly (`zensical build`).
39
+
40
+ ## Code style
41
+
42
+ The project uses [Ruff](https://docs.astral.sh/ruff/) for linting and formatting
43
+ (configured in `pyproject.toml`).
44
+
45
+ ## License
46
+
47
+ By contributing, you agree that your contributions will be licensed under the project's
48
+ [EUPL-1.2 license](LICENSE).