diff --git a/README.md b/README.md index 113ec9bc..44e45de8 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,10 @@ -# Integrated Energy System Optimization (IESopt.jl) +# IESopt: Integrated Energy System Optimization [![License](https://img.shields.io/github/license/ait-energy/IESopt.jl)](LICENSE) -[![Stable](https://img.shields.io/badge/docs-stable-blue.svg)](https://ait-energy.github.io/IESopt.jl/stable/) [![Dev](https://img.shields.io/badge/docs-dev-blue.svg)](https://ait-energy.github.io/IESopt.jl/dev/) + [![Build Status](https://github.com/ait-energy/IESopt.jl/actions/workflows/CI.yml/badge.svg?branch=main)](https://github.com/ait-energy/IESopt.jl/actions/workflows/CI.yml?query=branch%3Amain) [![Coverage](https://codecov.io/gh/ait-energy/IESopt.jl/branch/main/graph/badge.svg)](https://codecov.io/gh/ait-energy/IESopt.jl) @@ -25,30 +27,105 @@ systems. ## Background -TODO +IESopt has been in development at AIT since 2021, and was moved to GitHub in June, 2024, based on a cleaned version with +slightly more than 1000 commits. Check out the [references](https://ait-energy.github.io/IESopt.jl/dev/pages/references/publications/) +for a more detailed overview about publications and projects, where IESopt has been used. ## Install -TODO: Document how to install the package. +Make sure to check out the detailed [installation guides](https://ait-energy.github.io/IESopt.jl/dev/pages/tutorials/setup/) +in the documentation, both for Python and Julia. + +### Quick setup for Julia + +In an open REPL, type `]` to enter the package mode, make sure that your environment is +activated (e.g., do `activate .`), then add the package with the following command: + +```bash +(your-env) pkg> add IESopt +``` + +### Quick setup for Python + +Head over to [iesopt-py](https://github.com/ait-energy/iesopt-py) and follow the instructions there, or - if you already +have a working Python environment - install the package, e.g., via `poetry`: + +```bash +poetry add iesopt-py +``` ## Usage -TODO: Document how to use the package. +IESopt requires a configured model to run. You can start with the extensive [first model tutorial](https://ait-energy.github.io/IESopt.jl/dev/pages/tutorials/first_model/), or checkout [IESoptLib](https://github.com/ait-energy/IESoptLib.jl) which +includes many more examples. + +### Basic usage + +The basic workflow to get results from a model, defined by a top-level configuration file `config.iesopt.yaml`, is as +follows: + +1. Parse, generate, and build the model from `config.iesopt.yaml`. +2. Optimize the model (the chose solver is specified in `config.iesopt.yaml`). +3. Get the results from the model. + +Steps 1. and 2. can be combined in a single call, which the convenience function `run(...)` provides. + +#### Using Julia + +```julia +using IESopt + +model = IESopt.run("config.iesopt.yaml") +results = model.ext[:iesopt].results +``` + +#### Using Python + +```python +import iesopt + +model = iesopt.run("config.iesopt.yaml") +df_results = model.results.to_pandas() +``` ## API -TODO: Document the API of the package. +Check out the full [API reference](https://ait-energy.github.io/IESopt.jl/dev/pages/manual/api/) in the +documentation. + +### Basic API + +A short overview is given below. + +#### Julia API + +```julia +"""Builds and returns a model using the IESopt framework.""" +IESopt.generate!(filename::String) + +"""Optimize the given model, optionally saving model results to disk.""" +IESopt.optimize!(model::JuMP.Model; save_results::Bool=true, kwargs...) + +"""Build, optimize, and return a model, in a single call.""" +IESopt.run(filename::String; verbosity=nothing, kwargs...) + +"""Get the component with the name `component_name` from the `model`.""" +IESopt.component(model::JuMP.Model, component_name::String) + +"""Compute the Irreducible Infeasible Set (IIS) of the model.""" +IESopt.compute_IIS(model::JuMP.Model; filename::String = "") +``` -### Python +### Python API -### Julia +To be added. ## Contributing [![Code Style](https://img.shields.io/badge/code_style-custom-blue?style=flat&logo=julia&logoColor=white)](.JuliaFormatter.toml) [![Readme Style](https://img.shields.io/badge/readme_style-standard-lime?style=flat&logo=julia&logoColor=white)](https://github.com/RichardLitt/standard-readme) -PRs accepted. +PRs accepted. Checkout the [developer documentation](https://ait-energy.github.io/IESopt.jl/dev/pages/dev_docs/). ## License diff --git a/RELEASING.md b/RELEASING.md new file mode 100644 index 00000000..9424c7de --- /dev/null +++ b/RELEASING.md @@ -0,0 +1,111 @@ +# Releasing + +This documents the steps necessary to release a new version of the IESopt.jl package. Follow these step-by-step, and fix +any issues that might arise, before proceeding to the next step: + +1. [Check tests locally](#check-tests-locally) +2. [Check formatting](#check-formatting) +3. [Update the changelog](#update-the-changelog) +4. [Update the version number](#update-the-version-number) +5. [Trigger a new release](#trigger-a-new-release) + +## Check tests locally + +After entering "package mode" (press `]`), make sure that the `IESopt` environment is activated, which shows as +`(IESopt) pkg>` (if not execute `activate .`), and then run the tests by executing the `test` command: + +```shell +(IESopt) pkg> test +``` + +## Check formatting + +The following assumes that you have installed the `JuliaFormatter.jl` package. + +
+Expand: How to install JuliaFormatter + +> It is advised to add that package to your "base" environment (it comes at little overhead, and is then available in +> all environments). To install the package, run the following command in the Julia REPL, after switching to "package +> mode" (press `]`): +> +> ```shell +> (......) pkg> activate +> (@v1.10) pkg> add JuliaFormatter +> ``` +> +> The first "empty" activate command is necessary to switch to the "base" environment (it acts like `conda deactivate`). +> The second command then installs the `JuliaFormatter.jl` package (note that `(@v1.10)` is just an example, it could be +> different for you). + +
+ +To check/fix the formatting of the package, run the following command in the Julia REPL: + +```julia +using JuliaFormatter +format("src") +``` + +This automatically formats all files in the `src` directory. This returns `true` if all files were already formatted +correctly. + +## Update the changelog + +Check out [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) for guidance on how to write a changelog. You can use +the template below, replace all placeholders, and remove the parts that are not applicable. Add the new entry as topmost +entry of the [CHANGELOG.md](CHANGELOG.md) file. + +
+Expand: Changelog template + +```markdown +## [X.Y.Z] - YYYY-MM-DD + +{{Give a (really) short description of the release here, ideally one sentence.}} + +### Added + +- {{document new features here}} + +### Changed + +- {{document changed features here}} + +### Deprecated + +- {{document deprecated features here}} + +### Removed + +- {{document removed features here}} + +### Fixed + +- {{document fixed bugs here}} +``` + +
+ +## Update the version number + +Update the version number in the [Project.toml](Project.toml) file. The version number should be in the format `X.Y.Z`. +Check the [Semantic Versioning](https://semver.org/spec/v2.0.0.html) specification for guidance on how to update the +version number. Make sure to name your commit as: + +```text +chore: prep for vX.Y.Z +``` + +## Trigger a new release + +Open the latest commit that was merged into the `main` branch (this should be a `chore: prep for vX.Y.Z` commit) and add +a comment with the following text: + +```text +@JuliaRegistrator register + +Release notes: + +{{>> directly add you new changelog entry here <<}} +``` diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 00000000..76436934 --- /dev/null +++ b/codecov.yml @@ -0,0 +1,15 @@ +coverage: + status: + project: + default: + target: auto + threshold: 0% + base: auto + +comment: + layout: "diff, flags, files" + behavior: default + require_changes: false + require_base: false + require_head: true + hide_project_coverage: false diff --git a/docs/changelog.jl b/docs/changelog.jl index 32dbb3d4..17f743d5 100644 --- a/docs/changelog.jl +++ b/docs/changelog.jl @@ -7,7 +7,7 @@ function create_changelog() # Write the changelog. open(joinpath(PATH_DOCS, "src", "pages", "changelog.md"), "w") do f - write(f, changelog) + return write(f, changelog) end end diff --git a/docs/generate.jl b/docs/generate.jl index 6ce0f6d9..f477d187 100644 --- a/docs/generate.jl +++ b/docs/generate.jl @@ -3,15 +3,8 @@ _canonify_string(str::String) = lowercase(replace(str, r"[^a-zA-Z0-9]" => "_")) function _build_page_paths(entry; parent::String) isa(entry, String) && return joinpath(parent, "$(_canonify_string(entry)).md") isa(entry, AbstractVector) && return [_build_page_paths(subentry; parent=parent) for subentry in entry] - isa(entry, Pair) || error("Invalid type of entry in page structure") - - isa(entry.second, String) && return entry.first => "$(_canonify_string(entry.second)).md" - - if isa(entry.second, AbstractVector) && length(entry.second) == 1 - return joinpath(parent, "$(_canonify_string(entry.second[1])).md") - end - + isa(entry.second, String) && return entry.first => joinpath(parent, "$(_canonify_string(entry.second)).md") return entry.first => _build_page_paths(entry.second; parent=joinpath(parent, _canonify_string(entry.first))) end @@ -21,22 +14,26 @@ examples_files = [ file in readdir(normpath(@__DIR__, "src", "pages", "user_guide", "examples")) if endswith(file, ".md") ] -_PAGES = _build_page_paths( - [ - "Home" => "index", - "Tutorials" => ["setup", "first_model", "next_steps", "results"], - "User Guide" => [ - "general", - "Sectors" => ["electricity", "heat", "gas"], - "solvers", - "Custom Functionality" => ["templates", "addons"], - "Examples" => [], # TODO: examples_files, - ], - "Manual" => ["yaml", "core_components", "templates", "api"], - "Developer Documentation" => ["dev_docs"], - "Changelog" => ["changelog"], - ]; - parent="pages", +_PAGES = Pair["Home" => "index.md"] +append!( + _PAGES, + _build_page_paths( + [ + "Tutorials" => ["setup", "first_model", "next_steps", "results"], + "User Guide" => [ + "general", + "Sectors" => ["electricity", "heat", "gas"], + "solvers", + "Custom Functionality" => ["templates", "addons"], + "Examples" => [], # TODO: examples_files, + ], + "Manual" => ["yaml", "core_components", "templates", "api"], + "References" => "references", + "Developer Documentation" => "dev_docs", + "Changelog" => "changelog", + ]; + parent="pages", + ), ) # Create `changelog.md` from `CHANGELOG.md`. diff --git a/docs/liveserver.jl b/docs/liveserver.jl index b2b6e7e2..fc3253d8 100644 --- a/docs/liveserver.jl +++ b/docs/liveserver.jl @@ -3,8 +3,8 @@ # julia --project=. -e 'include("docs/liveserver.jl")' # ``` -const PATH_ROOT = dirname(@__DIR__) -const PATH_DOCS = joinpath(PATH_ROOT, "docs") +const LS_PATH_ROOT = dirname(@__DIR__) +const LS_PATH_DOCS = joinpath(LS_PATH_ROOT, "docs") # Make sure `docs` environment is set up properly. import Pkg @@ -17,17 +17,17 @@ push!(ARGS, "running_local_liveserver") # Serve documentation now. import LiveServer LiveServer.servedocs(; - include_dirs = [ - joinpath(PATH_ROOT, "src"), # watch `src/` for changes (to update docstrings) + include_dirs=[ + joinpath(LS_PATH_ROOT, "src"), # watch `src/` for changes (to update docstrings) ], - include_files = [ - joinpath(PATH_DOCS, "generate.jl"), # watch `generate.jl` for changes (to regenerate docs) - joinpath(PATH_DOCS, "changelog.jl"), # watch `changelog.jl` for changes (to regenerate changelog) - joinpath(PATH_ROOT, "CHANGELOG.md"), # watch `CHANGELOG.md` for changes (to regenerate changelog) + include_files=[ + joinpath(LS_PATH_DOCS, "generate.jl"), # watch `generate.jl` for changes (to regenerate docs) + joinpath(LS_PATH_DOCS, "changelog.jl"), # watch `changelog.jl` for changes (to regenerate changelog) + joinpath(LS_PATH_ROOT, "CHANGELOG.md"), # watch `CHANGELOG.md` for changes (to regenerate changelog) ], - skip_files = [ - joinpath(PATH_DOCS, "src", "pages", "changelog.md"), # don't watch this, because it's generated by `generate.jl` + skip_files=[ + joinpath(LS_PATH_DOCS, "src", "pages", "changelog.md"), # don't watch this, because it's generated by `generate.jl` ], - launch_browser = true, - verbose = true, + launch_browser=true, + verbose=true, ) diff --git a/docs/make.jl b/docs/make.jl index dd6a84af..59556ee5 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -1,5 +1,7 @@ const is_local_draft = "running_local_liveserver" in ARGS const running_in_ci = haskey(ENV, "CI") || haskey(ENV, "GITHUB_ACTIONS") +const PATH_DOCS_SRC = normpath(@__DIR__, "src") +const PATH_DOCS_PAGES = normpath(PATH_DOCS_SRC, "pages") if is_local_draft try @@ -27,17 +29,16 @@ makedocs(; collapselevel=2, mathengine=Documenter.MathJax2(), highlights=["yaml", "python"], - assets=[ - asset("assets/base_template.css"; class=:css, islocal=true), - ], + assets=[asset("assets/base_template.css"; class=:css, islocal=true)], size_threshold=300_000, size_threshold_warn=200_000, ), + # modules=[IESopt], pages=_PAGES, - doctest = false, - pagesonly = true, - warnonly = true, - draft = is_local_draft, + doctest=false, + pagesonly=true, + warnonly=true, + draft=is_local_draft, ) # Deploy documentation, if we are not running locally. @@ -45,12 +46,12 @@ if !is_local_draft deploydocs(; repo="github.com/ait-energy/IESopt.jl", push_preview=true, # previews for PRs (not from forks) - versions = [ + versions=[ "stable" => "v^", # "stable" => latest version "v#.#", # include all minor versions "dev" => "dev", # "v#.#.#", # use this to include all released versions # "v1.1.6", # use this to include a specific version - ] + ], ) end diff --git a/docs/src/pages/references.md b/docs/src/pages/references.md new file mode 100644 index 00000000..91fdcaa9 --- /dev/null +++ b/docs/src/pages/references.md @@ -0,0 +1,129 @@ +# Overview + +This maintains a list of publications (journals, conferences, ...) where IESopt was applied as part of the modeling +approach. Entries are in alphabetical order. If you want to contribute a new publication or project, please follow the +instructions in the [Contributing](#contributing) section. + +## Publications + +```@eval +using IESopt, Markdown +path = abspath(dirname(pathof(IESopt)), "..", "docs", "src", "pages", "references", "publications") + +ref_str = "" +items = [] +for file in readdir(path; join=true) + endswith(file, ".md") || continue + raw_content = read(file, String) + + fulltitle = "" + header = "" + content = "" + for line in eachline(IOBuffer(raw_content)) + if startswith(line, "# ") + fulltitle = line[3:end] + if length(fulltitle) > 92 + header = "$(fulltitle[1:88]) ..." + else + header = fulltitle + end + else + content = "$(content)\n$(line)" + end + end + + push!(items, """ + !!! details "$(header)" + _**$(fulltitle)**_ + $(replace(content, "\n" => "\n ")) + """) +end + +Markdown.parse(join(items, "\n")) +``` + +## Projects + +```@eval +using IESopt, Markdown +path = abspath(dirname(pathof(IESopt)), "..", "docs", "src", "pages", "references", "projects") + +ref_str = "" +items = [] +for file in readdir(path; join=true) + endswith(file, ".md") || continue + raw_content = read(file, String) + + fulltitle = "" + header = "" + content = "" + for line in eachline(IOBuffer(raw_content)) + if startswith(line, "# ") + fulltitle = line[3:end] + if length(fulltitle) > 92 + header = "$(fulltitle[1:88]) ..." + else + header = fulltitle + end + else + content = "$(content)\n$(line)" + end + end + + push!(items, """ + !!! details "$(header)" + _**$(fulltitle)**_ + $(replace(content, "\n" => "\n ")) + """) +end + +Markdown.parse(join(items, "\n")) +``` + +## Contributing + +To contribute a new reference, either + +- fork the [IESopt](https://github.com/ait-energy/IESopt.jl) repository, and directly add to the above list, or +- open an issue with the reference details. + +See the template below for the structure of a reference. + +### Publication Template + +Please stick to APA format here, and always include a link as badge (if possible a DOI, if not other links are okay +too). + +```markdown +# Title of the Publication + +[![CITATION](url-of-your-badge)](link-to-doi-or-pure-or-other) + +> _**Abstract --**_ Put your abstract text here. + +> _**Keywords --**_ Put some, Keywords, In this, List + +!!! details "Expand: Show citation" + > Add your (APA styled!) citation here + +``` + +### Project Template + +To be added. + +### Creating citation badges + +You can use [shields.io](https://shields.io/badges) to create badges, or use standardized ones that you already have +(e.g., from Zenodo), otherwhise stick to the ones provided below. + +> **Pure:** +> _(publications.ait.ac.at)_ +> ```markdown +> [![CITATION](https://img.shields.io/badge/PURE-publications.ait.ac.at-none?style=social)](ADDYOURLINKHERE) +> ``` + +> **DOI:** +> ```markdown +> [![CITATION](https://img.shields.io/badge/DOI-10.XXXX%2Fname.YYYY.ZZZZZZ-none?style=social)](https://doi.org/10.XXXX/name.YYYY.ZZZZZZ) +> ``` diff --git a/docs/src/pages/references/projects/.gitkeep b/docs/src/pages/references/projects/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/docs/src/pages/references/publications/heat_highway_-_heat_transmission_network_design_optimization_and_robustness_analysis_for_a_case_study_in_tyrol_-_methodology.md b/docs/src/pages/references/publications/heat_highway_-_heat_transmission_network_design_optimization_and_robustness_analysis_for_a_case_study_in_tyrol_-_methodology.md new file mode 100644 index 00000000..30766c83 --- /dev/null +++ b/docs/src/pages/references/publications/heat_highway_-_heat_transmission_network_design_optimization_and_robustness_analysis_for_a_case_study_in_tyrol_-_methodology.md @@ -0,0 +1,10 @@ +# Heat Highway - Heat Transmission Network Design Optimization and Robustness Analysis for a Case Study in Tyrol - Methodology + +[![CITATION](https://img.shields.io/badge/PURE-publications.ait.ac.at-blue?style=social)](https://publications.ait.ac.at/en/publications/heat-highway-heat-transmission-network-design-optimization-and-ro) + +> _**Abstract --**_ The majority of district heating (DH) networks today are fueled by combustion processes based on fossil or biogenic fuels. For the decarbonization of DH networks various uncertainties regarding the future development of key factors, such as energy prices, need to be considered. Within the project “HeatHighway” a hypothetical inter-regional heat transfer network (HTN) in the region of the Inn valley in Tyrol, Austria was investigated. + +> _**Keywords --**_ Future district heating, Waste heat sources, 4th generation DH, Heat transmission networks, Deterministic optimization, Monte Carlo simulation + +!!! details "Expand: Show citation" + > Marx, N. O., Schmidt, R. R., Blakcori, R., Maggauer, K., Strömer, S., & Forster, T. (2023, September). Heat Highway - Heat Transmission Network Design Optimization and Robustness Analysis for a Case Study in Tyrol - Methodology. In _9th International Conference on Smart Energy Systems_ (pp. 103-104).``` diff --git a/docs/src/pages/references/publications/optimizing_the_domestic_production_and_infrastructure_for_green_hydrogen_in_austria_for_2030.md b/docs/src/pages/references/publications/optimizing_the_domestic_production_and_infrastructure_for_green_hydrogen_in_austria_for_2030.md new file mode 100644 index 00000000..0ff029f7 --- /dev/null +++ b/docs/src/pages/references/publications/optimizing_the_domestic_production_and_infrastructure_for_green_hydrogen_in_austria_for_2030.md @@ -0,0 +1,10 @@ +# Optimizing the Domestic Production and Infrastructure for Green Hydrogen in Austria for 2030 + +[![CITATION](https://img.shields.io/badge/PURE-publications.ait.ac.at-blue?style=social)](https://publications.ait.ac.at/en/publications/optimizing-the-domestic-production-and-infrastructure-for-green-h) + +> _**Abstract --**_ The decarbonisation of the Austrian energy system is expected to be facilitated by the uptake of hydrogen-based technologies, which requires the establishment of a hydrogen infrastructure to meet the rising demand. While large quantities of hydrogen are expected to be imported in the future, current developments in the energy market suggest that domestic production of hydrogen should not be ignored to ensure the security of supply. As domestic production ramps up, locating electrolysers to ensure optimal system integration is still an open question. To address this challenge, the "HyTechonomy" project developed an optimisation model that identifies the most promising domestic locations for green hydrogen production and optimal means of hydrogen transport for the year 2030. + +> _**Keywords --**_ Hydrogen infrastructure, Energy system modelling, centralised electrolysis, decentralised electrolysis + +!!! details "Expand: Show citation" + > Reuter, S., Strömer, S., Traninger, M., & Beck, A. (2023, September). Optimizing the Domestic Production and Infrastructure for Green Hydrogen in Austria for 2030. In _Book of Abstracts: 9th International Conference on Smart Energy Systems_ (pp. 278-279).