Skip to content

Commit

Permalink
Add support for EnergyModelsInvestments as extension (#34)
Browse files Browse the repository at this point in the history
* Moved EMB specifics to EMB:
  - AbstractInvestmentModel is now introduced in EMB
  - InvestmentData is now introduced in EMB
  - Moved legacy constructors to EMB extension
  - Implement EMI.has_investment in extension (do not define new function)

* Lower bound julia to 1.9 due to weak dependencies

* Removal of nightly due to issues in Mocking.jl

* Documentation
  - Provide consistent labels to all headings
  - Updated the documentation for EMI through Investments section
  - Included DocumenterInterLinks

* Several minor fixes

---------

Co-authored-by: Julian Straus <[email protected]>
  • Loading branch information
hellemo and JulStraus authored Aug 20, 2024
1 parent 0b397cb commit f275047
Show file tree
Hide file tree
Showing 52 changed files with 2,590 additions and 1,436 deletions.
14 changes: 14 additions & 0 deletions .JuliaFormatter.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Configuration file for JuliaFormatter.jl
# For more information, see: https://domluna.github.io/JuliaFormatter.jl/stable/config/

always_for_in = true
for_in_replacement = ""
always_use_return = false
margin = 92
remove_extra_newlines = true
short_to_long_function_def = false
align_assignment = true
align_struct_field = false
align_conditional = true
align_pair_arrow = true
join_lines_based_on_source = true
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ jobs:
- version: '1.9' # 1.9
os: ubuntu-latest
arch: x86
- version: 'nightly'
os: ubuntu-latest
arch: x64
# - version: 'nightly'
# os: ubuntu-latest
# arch: x64
steps:
- uses: actions/checkout@v3
- uses: julia-actions/setup-julia@v1
Expand Down
10 changes: 9 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
# Release notes

## Unversioned
## Version 0.8.0 (2024-08-20)

### Introduced `EnergyModelsInvestments` as extension

* `EnergyModelsInvestments` was switched to be an independent package in [PR #28](https://github.com/EnergyModelsX/EnergyModelsInvestments.jl/pull/28).
* This approach required `EnergyModelsBase` to include all functions and type declarations internally.
* An extension was introduced to handle these problems.

### Minor updates

* Updated minor issues in the documentation (docstrings, indices, and quick start).
* Use dev version of EMB for examples when running as part of tests, solving [Issue #17](https://github.com/EnergyModelsX/EnergyModelsBase.jl/issues/17).
Expand Down
15 changes: 12 additions & 3 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
name = "EnergyModelsBase"
uuid = "5d7e687e-f956-46f3-9045-6f5a5fd49f50"
authors = ["Lars Hellemo <[email protected]>, Julian Straus <[email protected]>"]
version = "0.7.0"
version = "0.8.0"

[deps]
JuMP = "4076af6c-e467-56ae-b986-b466b2749572"
SparseVariables = "2749762c-80ed-4b14-8f33-f0736679b02b"
TimeStruct = "f9ed5ce0-9f41-4eaa-96da-f38ab8df101c"

[weakdeps]
EnergyModelsInvestments = "fca3f8eb-b383-437d-8e7b-aac76bb2004f"

[extensions]
EMIExt = "EnergyModelsInvestments"

[compat]
JuMP = "^0.23, 1"
julia = "^1.6"
EnergyModelsInvestments = "0.7"
JuMP = "1"
SparseVariables = "0.7.3"
TimeStruct = "^0.8"
julia = "1.9"
2 changes: 2 additions & 0 deletions docs/Project.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
[deps]
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
DocumenterInterLinks = "d12716ef-a0f6-4df4-a9f1-a5a34e75c656"
EnergyModelsBase = "5d7e687e-f956-46f3-9045-6f5a5fd49f50"
EnergyModelsInvestments = "fca3f8eb-b383-437d-8e7b-aac76bb2004f"
JuMP = "4076af6c-e467-56ae-b986-b466b2749572"
TimeStruct = "f9ed5ce0-9f41-4eaa-96da-f38ab8df101c"
70 changes: 43 additions & 27 deletions docs/make.jl
Original file line number Diff line number Diff line change
@@ -1,52 +1,68 @@
using Documenter
using DocumenterInterLinks

using EnergyModelsBase
using EnergyModelsInvestments
using TimeStruct
const EMB = EnergyModelsBase

# Copy the NEWS.md file
news = "docs/src/manual/NEWS.md"
if isfile(news)
rm(news)
end
cp("NEWS.md", news)
cp("NEWS.md", "docs/src/manual/NEWS.md"; force=true)

links = InterLinks(
"TimeStruct" => "https://sintefore.github.io/TimeStruct.jl/stable/",
"EnergyModelsInvestments" => "https://energymodelsx.github.io/EnergyModelsInvestments.jl/stable/",
)


DocMeta.setdocmeta!(EnergyModelsBase, :DocTestSetup, :(using EnergyModelsBase); recursive=true)
DocMeta.setdocmeta!(
EnergyModelsBase,
:DocTestSetup,
:(using EnergyModelsBase);
recursive = true,
)

makedocs(
sitename = "EnergyModelsBase",
format = Documenter.HTML(;
prettyurls=get(ENV, "CI", "false") == "true",
edit_link="main",
assets=String[],
prettyurls = get(ENV, "CI", "false") == "true",
edit_link = "main",
assets = String[],
ansicolor = true,
),
modules = [EnergyModelsBase],
modules = [
EMB,
isdefined(Base, :get_extension) ?
Base.get_extension(EMB, :EMIExt) :
EMB.EMIExt
],
pages = [
"Home" => "index.md",
"Manual" => Any[
"Quick Start" => "manual/quick-start.md",
"Philosophy" => "manual/philosophy.md",
"Optimization variables" => "manual/optimization-variables.md",
"Constraint functions" => "manual/constraint-functions.md",
"Data functions" => "manual/data-functions.md",
"Example" => "manual/simple-example.md",
"Release notes" => "manual/NEWS.md",
"Quick Start"=>"manual/quick-start.md",
"Philosophy"=>"manual/philosophy.md",
"Optimization variables"=>"manual/optimization-variables.md",
"Constraint functions"=>"manual/constraint-functions.md",
"Data functions"=>"manual/data-functions.md",
"Example"=>"manual/simple-example.md",
"Investment options"=>"manual/investments.md",
"Release notes"=>"manual/NEWS.md",
],
"How to" => Any[
"Create a new node" => "how-to/create-new-node.md",
"Utilize TimeStruct" => "how-to/utilize-timestruct.md",
"Update models" => "how-to/update-models.md",
"Contribute to EnergyModelsBase" => "how-to/contribute.md",
"Create a new node"=>"how-to/create-new-node.md",
"Utilize TimeStruct"=>"how-to/utilize-timestruct.md",
"Update models"=>"how-to/update-models.md",
"Contribute to EnergyModelsBase"=>"how-to/contribute.md",
],
"Library" => Any[
"Public" => "library/public.md",
"Internals" => Any[
"Reference" => "library/internals/reference.md",
]
]
]
"Public"=>"library/public.md",
"Internals"=>Any[
"Reference"=>"library/internals/reference.md",
"Reference EMIExt"=>"library/internals/reference_EMIExt.md",
],
],
],
plugins=[links],
)

deploydocs(;
Expand Down
28 changes: 14 additions & 14 deletions docs/src/how-to/contribute.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
# Contribute to EnergyModelsBase
# [Contribute to EnergyModelsBase](@id how_to-con)

Contributing to `EnergyModelsBase` can be achieved in several different ways.

## Create new extensions
## [Create new extensions](@id how_to-con-ext)

The main focus of `EnergyModelsBase` is to provide an easily extensible energy system optimization modelling framework.
Hence, a first approach to contributing to `EnergyModelsBase` is to create a new package with, _e.g._, the introduction of new node descriptions.

This is explained in [_How to create a new node_](@ref create_new_node).
This is explained in [_How to create a new node_](@ref how_to-create_node).

!!! tip
If you are uncertain how you could incorporate new nodal descriptions, take a look at [`EnergyModelsRenewableProducers`](https://github.com/EnergyModelsX/EnergyModelsRenewableProducers.jl).
The package is maintained by the developers of `EnergyModelsBase`.
Hence, it provides you with ideas on how we think it is best to develop new node descriptions.

## File a bug report
## [File a bug report](@id how_to-con-bug_rep)

Another approach to contributing to `EnergyModelsBase` is through filing a bug report as an _[issue](https://github.com/EnergyModelsX/EnergyModelsBase.jl/issues/new)_ when unexpected behaviour is occuring.

Expand All @@ -35,7 +35,7 @@ When filing a bug report, please follow the following guidelines:

In order to improve the code, we welcome any reports of potential method ambiguities to help us improving the structure of the framework.

## Feature requests
## [Feature requests](@id how_to-feat_req)

Although `EnergyModelsBase` was designed with the aim of flexibility, it sometimes still requires additional features to account for potential extensions.
Feature requests can be achieved through two approaches:
Expand All @@ -50,9 +50,9 @@ Feature requests can be achieved through two approaches:
Hence, feature requests should only include basic requirements for the core structure, and not, _e.g._, the description of new technologies.
These should be developed outside of `EnergyModelsBase`.

### [Create an Issue](@id create_issue)
### [Create an Issue](@id how_to-feat_req-issue)

Creating a new _[issue](https://github.com/EnergyModelsX/EnergyModelsBase.jl/issues/new)_ for a feature request is our standard approach for extending `EnergyModelsBase`.
Creating a new _[issue](https://github.com/EnergyModelsX/EnergyModelsBase.jl/issues/new) for a feature request is our standard approach for extending `EnergyModelsBase`.
Due to the extendibility of `EnergyModelsBase`, it is not necessarily straight forward to understand how to best incorporate required features into the framework without breaking other packages.

When creating a new issue as feature request, please follow the the following guidelines.
Expand All @@ -61,7 +61,7 @@ When creating a new issue as feature request, please follow the the following gu
2. **Required outcome**: What should be the outcome when including the feature and what should be the minimum requirements of the outcome?
3. **Potential solutions**: Describe alternatives you consider. This step is not necessarily required, but can be helpful for identifying potential solutions.

### Incorporating the feature requests through a fork
### [Incorporating the feature requests through a fork](@id how_to-feat_req-fork)

!!! note
The approach used for providing code is based on the excellent description of the [JuMP](https://jump.dev/JuMP.jl/stable/developers/contributing/#Contribute-code-to-JuMP) package.
Expand All @@ -70,23 +70,23 @@ When creating a new issue as feature request, please follow the the following gu
If you would like to work directly in `EnergyModelsBase`, you can also incorporate your changes directly.
In this case, it is beneficial to follow the outlined steps:

#### Step 1: Create an issue
#### [Step 1: Create an issue](@id how_to-feat_req-fork-step_1)

Even if you plan to incorporate the code directly, we advise you to first follow the steps outlined in _[Create an Issue](@ref create_issue)_.
Even if you plan to incorporate the code directly, we advise you to first follow the steps outlined in *[Create an Issue](@ref how_to-feat_req-issue)*.
This way, it is possible for us to comment on the solution approach(es) and assess potential problems with the other core packages of the `EnergyModelsX` framework.

Through creating an issue first, it is possible for us to comment directly on the proposed changes and assess, whether we consider the proposed changes to follow the philosophy of the framework.

#### Step 2: Create a fork of `EnergyModelsBase`
#### [Step 2: Create a fork of `EnergyModelsBase`](@id how_to-feat_req-fork-step_2)

Contributiing code to `EnergyModelsBase` should follow the standard approach by creating a fork of the repository.
All work on the code should occur within the fork.

#### Step 3: Checkout a new branch in your local fork
#### [Step 3: Checkout a new branch in your local fork](@id how_to-feat_req-fork-step_3)

It is in general preferable to work on a separate branch when developing new components.

#### Step 4: Make changes to the code base
#### [Step 4: Make changes to the code base](@id how_to-feat_req-fork-step_4)

Incorporate your changes in your new branch.
The changes should be commented to understand the thought process behind them.
Expand All @@ -110,7 +110,7 @@ It is however a requirement to update the [`NEWS.md`](https://github.com/EnergyM
`@constraint` macros are not following the style guide, as we personally consider the design more difficult to read.
Please follow in that respect the used style within the package.

#### Step 5: Create a pull request
#### [Step 5: Create a pull request](@id how_to-feat_req-fork-step_5)

Once you are satisified with your changes, create a pull request towards the main branch of the `EnergyModelsBase` repository.
We will internally assign the relevant person to the pull request.
Expand Down
53 changes: 29 additions & 24 deletions docs/src/how-to/create-new-node.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
# [Create a new node](@id create_new_node)
# [Create a new node](@id how_to-create_node)

The energy system model is based on the *[JuMP](https://jump.dev/JuMP.jl/stable/)* optimization framework, so some basic knowledge on this Julia package is needed to implement a new technology node.

> **To create a new technology node named `NewTechNode`, we need to**
> 1. Implement a new `struct` (composite type), that is a subtypes of `Node`,
> `Source`, `Sink`, etc. Here, a central choice is to decide on [*what abstract node type to subtype to*](@ref howto_create_node_subtype).
> 2. Optional: implement the method
> ```julia
> variables_node(m, 𝒩ˢᵘᵇ::Vector{<:NewTechNode}, 𝒯, modeltype::EnergyModel)
> ```
> Implement this method if you want to create additional optimization variables for the new node. See *[how to create JuMP variables](https://jump.dev/JuMP.jl/stable/manual/variables/)* in the JuMP documentation.
> 3. Implement the method
> ```julia
> create_node(m, n::NewTechNode, 𝒯, 𝒫, modeltype::EnergyModel)
> ```
> In this method the constraints for the new node are created. See *[how to create JuMP constraints](https://jump.dev/JuMP.jl/stable/manual/constraints/)* in the JuMP documentation.
>
> 1. Implement a new `struct` (composite type), that is a subtypes of `Node`, `Source`, `Sink`, etc.
> Here, a central choice is to decide on [*what abstract node type to subtype to*](@ref how_to-create_node-subtype).
> 2. Optional: implement the method
>
> ```julia
> variables_node(m, 𝒩ˢᵘᵇ::Vector{<:NewTechNode}, 𝒯, modeltype::EnergyModel)
> ```
>
> Implement this method if you want to create additional optimization variables for the new node. See *[how to create JuMP variables](https://jump.dev/JuMP.jl/stable/manual/variables/)* in the JuMP documentation.
> 3. Implement the method
>
> ```julia
> create_node(m, n::NewTechNode, 𝒯, 𝒫, modeltype::EnergyModel)
> ```
>
> In this method the constraints for the new node are created. See *[how to create JuMP constraints](https://jump.dev/JuMP.jl/stable/manual/constraints/)* in the JuMP documentation.
While step 1 is always required, it is possible to omit step 2 if no new variables are required.
It is also possible to create unregistered variables for each instance of the node.
Expand All @@ -23,32 +28,32 @@ This is however only advised if you do not need to access the value of the varia
!!! warning
When creating a new node type, you are free to change the field names to whatever name you desire. However, if you change the field names, there are several things to consider:
1. Certain functions are used within the core structure of the code for accessing the fields. These functions can be found in the *[Public Interface](@ref functions_fields_node)*.
1. Certain functions are used within the core structure of the code for accessing the fields. These functions can be found in the *[Public Interface](@ref lib-pub-nodes-fun_field)*.
2. The function [`EMB.check_node`](@ref) conducts some checks on the individual node data. If the fields and structure from the reference nodes are not present, you also have to create a new function for your node.
## Additional tips for creating new nodes
## [Additional tips for creating new nodes](@id how_to-create_node-tips)
1. If the `NewNodeType` should be able to include investments, it is necessary to i) call the function [`constraints_capacity_installed`](@ref).
and ii) have the field `data`.
The function is used for dispatching on the constraints for investments while the field `data` is used for providing the `InvestmentData`.
2. Emissions can be included in any way.
It is however beneficial to reutilize the [`EmissionsData`](@ref) type to improve usability with other packages.
This requries again the inclusion of the field `data` in `NewNodeType`.
It is possible to also create new subtypes for `EmissionsData` as well as dispatch on the function [`constraints_data(m, n::Node, 𝒯, 𝒫, modeltype, data::Data)`](@ref data_functions).
It is possible to also create new subtypes for `EmissionsData` as well as dispatch on the function [`constraints_data(m, n::Node, 𝒯, 𝒫, modeltype, data::Data)`](@ref man-data_fun).
3. It is in a first stage not important to include functions for handling all possible `TimeStructure`s, that is, *e.g.*, `RepresentativePeriods`.
Instead, and error can be provided if an unsupported `TimeStructure` is chosen.
4. The existing reference nodes and their respectvve *[constraint functions](@ref constraint_functions)* can serve as idea generators.
4. The existing reference nodes and their respective *[constraint functions](@ref man-con)* can serve as idea generators.
5. It is possible to include constraints that are coupled to another `Node` by introduing a field with the `Node` as type in the `NewNodeType`, *e.g.*, a field `node::Storage` when you plan to include additional constraints including a `Storage` node.
6. `EnergyModelsBase` utilize functions for accessing the fields of the individual nodes.
These functions can be found in *[Functions for accessing fields of `Node` types](@ref functions_fields_node)*.
These functions can be found in *[Functions for accessing fields of `Node` types](@ref lib-pub-nodes-fun_field)*.
In general, these functions dispatch on `abstract type`s.
7. It is beneficial to include the fields `input` and `output` for the `NewTechNode`.
This is not strictly required, but otherwise one has to provide new methods for the functions [`inputs()`](@ref) and [`outputs()`](@ref).
## Advanced creation of new nodes
## [Advanced creation of new nodes](@id how_to-create_node-adv)
Step 3 in the procedure is not necessarily required.
It is also possible to use the available *[constraint functions](@ref constraint_functions)* for the new node type.
It is also possible to use the available *[constraint functions](@ref man-con)* for the new node type.
In this case, we have to first obtain an overview over the constraint functions called in
```julia
Expand All @@ -64,7 +69,7 @@ This *constraint function* has to dispatch on the created `NewTechNode` type.
The advantage here is that the user requires less understanding of the individual constraint functions.
This may lead to repetetive code, but is the safer choice.

## [What abstract node type should you subtype to?](@id howto_create_node_subtype)
## [What abstract node type should you subtype to?](@id how_to-create_node-subtype)

The choice of node supertype depends on what optimization variables you need for the constraints describing the functionality of the new node.

Expand Down Expand Up @@ -108,10 +113,10 @@ Node

The leaf nodes of the above type hierarchy tree are `composite type`s, while the inner vertices are `abstract type`s.
The chosen parent `type` of the `NewNodeType` node decides what optimization variables are created for use by default.
You can find the created default optimization variables in *[Optimization Variables](@ref optimization_variables)* and *[Node types and respective variables](@ref var_node)*.
You can find the created default optimization variables in *[Optimization Variables](@ref man-opt_var)* and *[Node types and respective variables](@ref man-opt_var-node)*.
The main difference between the individual parent types is whether they have only an energy/mass output (`Source`), input and output (`NetworkNode`), or input (`Sink`).
A more detailed explanation of the different `abstract type`s can be found in *[Description of Technologies](@ref sec_des_nodes)*
A more detailed explanation of the different `abstract type`s can be found in *[Description of Technologies](@ref man-phil-nodes)*

## Example
## [Example](@id how_to-create_node-example)

As an example, you can check out how [`EnergyModelsRenewableProducers`](https://energymodelsx.github.io/EnergyModelsRenewableProducers.jl/) introduces two new technology types, a `Source` and a `Storage`.
Loading

0 comments on commit f275047

Please sign in to comment.