diff --git a/.github/actions/before-script/action.yml b/.github/actions/before-script/action.yml index 3be9c2b..ea412e0 100644 --- a/.github/actions/before-script/action.yml +++ b/.github/actions/before-script/action.yml @@ -7,9 +7,7 @@ runs: if: runner.os == 'Linux' run: | sudo apt-get update -qq - sudo apt-get install -y git glpk-utils g++ cmake wget curl python3-pip - pip install conan - conan profile detect + sudo apt-get install -y git g++ cmake wget curl python3-pip wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh bash Miniconda3-latest-Linux-x86_64.sh -b -p $HOME/miniconda echo "$HOME/miniconda/bin" >> $GITHUB_PATH @@ -17,7 +15,8 @@ runs: conda create --name testenv python=3.11 -y conda activate testenv - conda install -c conda-forge poetry -y + conda install -c conda-forge -y poetry highs highspy conan + conan profile detect cd "$GITHUB_WORKSPACE/test/python_module" poetry install @@ -41,3 +40,49 @@ runs: cmake --build . --config Release cd "$GITHUB_WORKSPACE" shell: bash + - name: Install Windows dependencies + Miniconda + python/cpp modules + if: runner.os == 'Windows' + run: | + # Download & install Miniconda into %USERPROFILE%\miniconda + $installer = Join-Path $env:RUNNER_TEMP "Miniconda3-latest-Windows-x86_64.exe" + Invoke-WebRequest -Uri "https://repo.anaconda.com/miniconda/Miniconda3-latest-Windows-x86_64.exe" -OutFile $installer + + $target = Join-Path $env:USERPROFILE "miniconda" + Start-Process -FilePath $installer -ArgumentList "/InstallationType=JustMe", "/S", "/D=$target" -Wait + + # Initialize conda for this PowerShell session + $conda = Join-Path $target "Scripts\conda.exe" + & $conda "shell.powershell" "hook" | Out-String | Invoke-Expression + + conda create --name testenv python=3.11 -y + conda activate testenv + $env:PATH = "$env:CONDA_PREFIX\Scripts;$env:CONDA_PREFIX;$env:PATH" + python -m pip install --upgrade pip + conda install -c conda-forge -y poetry highs highspy conan + conan profile detect + + # Check highs installation + where.exe highs + highs --version + + # Poetry installs + Set-Location (Join-Path $env:GITHUB_WORKSPACE "test\python_module") + poetry install + Set-Location (Join-Path $env:GITHUB_WORKSPACE "submodules\wind_power_timeseries") + poetry install + Set-Location (Join-Path $env:GITHUB_WORKSPACE "submodules\Tecnalia_Solar-Energy-Model") + poetry install + Set-Location (Join-Path $env:GITHUB_WORKSPACE "submodules\Tecnalia_Building-Stock-Energy-Model") + poetry install + + Set-Location (Join-Path $env:GITHUB_WORKSPACE "submodules\CHP_modelling") + New-Item -ItemType Directory -Force -Path "build" | Out-Null + Set-Location "build" + + conan install .. --output-folder=. --build=missing -s compiler.cppstd=17 -s arch=x86_64 + + cmake .. -DCMAKE_TOOLCHAIN_FILE="$PWD\conan_toolchain.cmake" -DCMAKE_BUILD_TYPE=Release + cmake --build . --config Release + + Set-Location $env:GITHUB_WORKSPACE + shell: pwsh \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 97a135d..30785bc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,11 +20,23 @@ jobs: - version: 'lts' # The long term stable version (Linux) os: ubuntu-latest arch: x64 + - version: '1' + os: windows-latest + arch: x64 + - version: 'lts' + os: windows-latest + arch: x64 steps: - uses: actions/checkout@v4 with: - submodules: true # Fetch the submodules - fetch-depth: 0 # full clone + submodules: true + fetch-depth: 0 + + # Recommended: ensure MSVC environment for conan/cmake on Windows + - name: Setup MSVC Dev Cmd + if: runner.os == 'Windows' + uses: ilammy/msvc-dev-cmd@v1 + - uses: ./.github/actions/before-script - uses: julia-actions/setup-julia@v2 with: @@ -41,7 +53,8 @@ jobs: ${{ runner.os }}-test- ${{ runner.os }}- - uses: julia-actions/julia-buildpkg@v1 - - name: Run Julia tests inside the testenv-enviornment in Miniconda + - name: Run Julia tests inside the testenv-enviornment in Miniconda (Linux) + if: runner.os == 'Linux' run: | source "$HOME/miniconda/etc/profile.d/conda.sh" conda init bash @@ -53,3 +66,13 @@ jobs: Pkg.test(; coverage=true) ' shell: bash + - name: Run Julia tests inside the testenv-environment in Miniconda (Windows) + if: runner.os == 'Windows' + run: | + $conda = Join-Path $env:USERPROFILE "miniconda\Scripts\conda.exe" + & $conda "shell.powershell" "hook" | Out-String | Invoke-Expression + conda activate testenv + $env:PATH = "$env:CONDA_PREFIX;$env:CONDA_PREFIX\Scripts;$env:PATH" + + julia --project=. -e 'using Pkg; ENV["PYTHON"] = joinpath(ENV["USERPROFILE"], "miniconda", "envs", "testenv", "python.exe"); Pkg.build("PyCall"); Pkg.test(; coverage=true)' + shell: pwsh diff --git a/NEWS.md b/NEWS.md index 58aa221..9a24435 100644 --- a/NEWS.md +++ b/NEWS.md @@ -2,6 +2,11 @@ ## Version 0.1.0 (2025-04-xx) +### Improve documentation (2026-01-06) + +* Added documentation for the node and a `how-to` section for the sampling constructors of these nodes. +* Added CI test runs for windows + ### Adjust for updates in submodules and update descriptive names for the EMGUI extension (2025-10-17) * Adjust for updates in submodules diff --git a/docs/Project.toml b/docs/Project.toml index bc5e1c2..00c5d09 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -1,7 +1,9 @@ [deps] +Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" DocumenterInterLinks = "d12716ef-a0f6-4df4-a9f1-a5a34e75c656" EnergyModelsBase = "5d7e687e-f956-46f3-9045-6f5a5fd49f50" +EnergyModelsHeat = "ad1b8b27-e232-4da9-b498-bea9c19a30d7" EnergyModelsLanguageInterfaces = "672bb132-9406-42d0-9ef4-9203b0a61e9a" EnergyModelsRenewableProducers = "b007c34f-ba52-4995-ba37-fffe79fbde35" HiGHS = "87dc4568-4c63-4d18-b0c0-bb2238e4078b" diff --git a/docs/make.jl b/docs/make.jl index fb807c4..ce09908 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -2,8 +2,10 @@ using Documenter using DocumenterInterLinks using EnergyModelsBase using EnergyModelsRenewableProducers +using EnergyModelsHeat using EnergyModelsLanguageInterfaces using TimeStruct +using Dates using Literate const EMB = EnergyModelsBase @@ -20,6 +22,7 @@ Literate.markdown(inputfile, joinpath(@__DIR__, "src", "examples")) links = InterLinks( "TimeStruct" => "https://sintefore.github.io/TimeStruct.jl/stable/", "EnergyModelsBase" => "https://energymodelsx.github.io/EnergyModelsBase.jl/stable/", + "EnergyModelsRenewableProducers" => "https://energymodelsx.github.io/EnergyModelsRenewableProducers.jl/stable/", ) makedocs( @@ -37,7 +40,13 @@ makedocs( "Quick Start"=>"manual/quick-start.md", "Release notes"=>"manual/NEWS.md", ], - "Types for EMX elements" => Any["Reference"=>"types/reference.md"], + "Nodes" => Any[ + "BioCHP"=>"nodes/biochp.md", + "WindPower"=>"nodes/windpower.md", + "PVandCSP"=>"nodes/pvandcsp.md", + "MultipleBuildingTypes"=>"nodes/multiplebuildingtypes.md", + ], + "Resources" => Any["ResourceBio"=>"resources/resourcebio.md"], "Utility functions" => Any["Reference"=>"util-fun/reference.md"], "How-to" => Any["Contribute"=>"how-to/contribute.md", "Utilize"=>"how-to/utilize.md"], diff --git a/docs/src/how-to/utilize.md b/docs/src/how-to/utilize.md index 8947096..157f4b7 100644 --- a/docs/src/how-to/utilize.md +++ b/docs/src/how-to/utilize.md @@ -18,6 +18,7 @@ output = EMLI.call_python_function("my_python_package", "my_func"; input) a local package you must create a conda environment (using a conda installation), or an other environment management system (not tested yet), and install required packages there. E.g., + ```bash conda create --name testenv python=3.10 conda activate testenv @@ -25,13 +26,16 @@ output = EMLI.call_python_function("my_python_package", "my_func"; input) cd path_to_your_python_project poetry install ``` + You must then (in Julia) set (it is here assumed you use miniconda on Windows) + ```julia using Pkg Pkg.add("PyCall") ENV["PYTHON"] = joinpath(homedir(), "AppData", "Local", "miniconda3", "envs", "testenv", "python.exe") Pkg.build("PyCall") ``` + and restart Julia. ### [Call C/C++ functions](@id how_to-utilize-ext_fun-Cpp) @@ -96,7 +100,7 @@ CxxWrap.prefix_path() which should return `"/home/user/.julia/dev/libcxxwrap_julia_jll/override"`. !!! note - If this instead returns `"/home/user/.julia/artifacts/5016ccec96368c99a5a678ab3319d1da7bb9a2c7"`, create a n`Overrides.toml` file at `/home/user/.julia/artifacts` with the following content + If this instead returns `"/home/user/.julia/artifacts/5016ccec96368c99a5a678ab3319d1da7bb9a2c7"`, create an `Overrides.toml` file at `/home/user/.julia/artifacts` with the following content ```toml [3eaa8342-bff7-56a5-9981-c04077f7cee7] @@ -110,3 +114,204 @@ which should return `"/home/user/.julia/dev/libcxxwrap_julia_jll/override"`. You can try to clone `CxxWrap`, change the toml file to `libcxxwrap_julia_jll = "0.13.4"` (instead of `0.14.0` which is not available yet), and `develop` `CxxWrap` in your environment. An example is given by the *[trippling_module example](https://github.com/EnergyModelsX/EnergyModelsLanguageInterfaces.jl/tree/main/test/trippling_module/)*. + +## [Use implemented nodes](@id how_to-utilize-use_nodes) + +The nodes [`WindPower`](@ref WindPower), [`CSPandPV`](@ref CSPandPV) and [`MultipleBuildingTypes`](@ref MultipleBuildingTypes) have [constructors](@ref lib-pub-sampling_constructors) that samples [`wind_power_timeseries`](https://gitlab.sintef.no/harald.svendsen/wind_power_timeseries), [`Tecnalia_Solar-Energy-Model`](https://github.com/iDesignRES/Tecnalia_Solar-Energy-Model) and [`Tecnalia_Building-Stock-Energy-Model`](https://github.com/iDesignRES/Tecnalia_Building-Stock-Energy-Model), respectively. These modules are python based and the usage of these [constructors](@ref lib-pub-sampling_constructors) requires installation of these as documented [below](@ref how_to-utilize-use_nodes-python_modules). + +Additionally, the node [`BioCHP`](@ref BioCHP) have a [constructor](@ref lib-pub-sampling_constructors) that samples the [CHP_modelling](https://github.com/iDesignRES/CHP_modelling) module. This module is `C++` based and the [constructor](@ref lib-pub-sampling_constructors) then requires compilation and build before usage as described further [below](@ref how_to-utilize-use_nodes-cpp_modules). + +The following installation guides will show how to install the modules to enable usage of these [constructors](@ref lib-pub-sampling_constructors) for both Windows and Linux. + +### [Clone repositories](@id how_to-utilize-use_nodes-clone_repos) + +Navigate to a folder in which you want to download required repositories and run + +```PowerShell +git clone --recurse-submodules git@github.com:EnergyModelsX/EnergyModelsLanguageInterfaces.jl.git +``` + +You should now be enabled to enter the main folder in which the other modules are located (under the submodules folder) + +```PowerShell +cd EnergyModelsLanguageInterfaces.jl +``` + +!!! note "Install git" + If you do not have git available in your PowerShell, make sure to [download](https://git-scm.com/install/windows) and install it properly (make sure to enable adjustment of the PATH environment). + + +### [Install python modules](@id how_to-utilize-use_nodes-python_modules) + +The following installs the modules using [`poetry`](https://pypi.org/project/poetry/) in a PowerShell in [VS code](https://code.visualstudio.com/). + +!!! note "Python installation" + You must have a python installation available in the terminal in VS code. + Python can be downloaded from [here](https://www.python.org/downloads/windows/) and installed by launching the downloaded installer (remember to "Add Python to PATH"). You must restart VS Code (and possibly any other open PowerShell windows) to have python available in the embedded VS code terminal. Check that you have python installed correctly with + + ```PowerShell + python --version + ``` + + which should return something like `Python 3.11.9`. + +Start by installing `poetry` using `pip` (which should be included in the python installation) + +```PowerShell +pip install poetry +``` + +Navigate to the submodule you want to install and run `poetry install`. If you want all python modules installed run the following + +```PowerShell +cd submodules/wind_power_timeseries +poetry install +cd ../.. +cd submodules/Tecnalia_Solar-Energy-Model +poetry install +cd ../.. +cd submodules/Tecnalia_Building-Stock-Energy-Model +poetry install +cd ../.. +``` + +If you want to be able to run the tests of the main repository later (see [Test modules](@ref how_to-utilize-use_nodes-test)), make sure to install the `python_module` (located in the `test/python_module` folder) + +```PowerShell +pip install highspy +cd test/python_module +poetry install +cd ../.. +``` + +!!! note "Environments" + If you are a developer, you probably want to install the python modules in a separate environment which can be done with, e.g., [miniconda](https://www.anaconda.com/docs/getting-started/miniconda/install). + +Enable these by starting a julia session in the main folder + +```PowerShell +julia --project=. +``` + +and run the following + +```julia +using Pkg +Pkg.instantiate() +ENV["PYTHON"] = joinpath(homedir(), "AppData", "Local", "Programs", "Python", "Python311", "python.exe") +Pkg.build("PyCall") +``` + +followed by restarting Julia. + +!!! note "Path to Python executable" + The path in the previous commands must be adjusted to the path of your python executable which can be found with + + ```PowerShell + (Get-Command python).Source + ``` + +### [Install C++ modules](@id how_to-utilize-use_nodes-cpp_modules) + +Start by installing [`conan`](https://pypi.org/project/conan/) and create a default profile + +```PowerShell +pip install conan +conan profile detect +``` + +Navigate to the `CHP_modelling` folder, build and install the module with the following + +```PowerShell +cd submodules/CHP_modelling +mkdir build +cd build +conan install .. --output-folder=. --build=missing -s compiler.cppstd=17 -s arch=x86_64 +cmake .. -DCMAKE_TOOLCHAIN_FILE="${PWD}/conan_toolchain.cmake" -DCMAKE_BUILD_TYPE=Release +cmake --build . --config Release +cd ../../.. +``` + +### [Install modules on linux](@id how_to-utilize-use_nodes-linux) + +To perform the same installation above on linux you can navigate to a folder in which you want to download required repositories and run + +```bash +sudo apt-get update -qq +sudo apt-get install -y git glpk-utils g++ cmake wget curl python3-pip +pip install conan +conan profile detect +wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh +bash Miniconda3-latest-Linux-x86_64.sh -b -p $HOME/miniconda +echo "$HOME/miniconda/bin" >> $GITHUB_PATH +source "$HOME/miniconda/etc/profile.d/conda.sh" + +conda create --name testenv python=3.11 -y +conda activate testenv +conda install -c conda-forge poetry -y + +git clone --recurse-submodules git@github.com:EnergyModelsX/EnergyModelsLanguageInterfaces.jl.git +cd "test/python_module" +poetry install +cd "../.." + +cd "submodules/wind_power_timeseries" +poetry install +cd "../.." + +cd "submodules/Tecnalia_Solar-Energy-Model" +poetry install +cd "../.." +cd "submodules/Tecnalia_Building-Stock-Energy-Model" +poetry install +cd "../.." + +cd "submodules/CHP_modelling" +mkdir build +cd build +conan install .. --output-folder=. --build=missing -s compiler.cppstd=17 -s arch=x86_64 +cmake .. -DCMAKE_TOOLCHAIN_FILE="${PWD}/conan_toolchain.cmake" -DCMAKE_BUILD_TYPE=Release +cmake --build . --config Release +cd "../../.." +``` + +Enable the python modules by starting a julia session in the main folder + +```PowerShell +julia --project=. +``` + +and run the following + +```julia +using Pkg; +Pkg.instantiate() +ENV["PYTHON"] = joinpath(ENV["HOME"], "miniconda", "envs", "testenv", "bin", "python"); +Pkg.build("PyCall"); +``` + +followed by restarting Julia. + +### [Test modules](@id how_to-utilize-use_nodes-test) + +All the mentioned [constructors](@ref lib-pub-sampling_constructors) have been included in the tests of the repository and you may therefore check if everyting is properly setup by running these in julia. + +!!! note "Requirements" + The tests assumes that all modules listed in the [Install python modules](@ref how_to-utilize-use_nodes-python_modules) section and the [Install C++ modules](@ref how_to-utilize-use_nodes-cpp_modules) section has been installed. + +Start a new Julia session with + +```PowerShell +julia --project=. +``` + +and run the tests + +```julia +using Pkg +Pkg.test() +``` + +### [Utilize constructors](@id how_to-utilize-constructors) + +For detailed information on how to use the [constructors](@ref lib-pub-sampling_constructors), refer to the [test/utils.jl](https://github.com/EnergyModelsX/EnergyModelsLanguageInterfaces.jl/blob/main/test/utils.jl) file, which contains minimum working examples for both sampling the models and using saved sampled data. \ No newline at end of file diff --git a/docs/src/library/public.md b/docs/src/library/public.md index 7424c8a..c1b6b5d 100644 --- a/docs/src/library/public.md +++ b/docs/src/library/public.md @@ -1,15 +1,69 @@ # [Public interface](@id lib-pub) -## [New nodal types](@id lib-pub-types) +## [New resource types](@id lib-pub-resource_types) + +```@docs +EnergyModelsLanguageInterfaces.ResourceBio +``` + +## [New nodal types](@id lib-pub-nodal_types) ```@docs EnergyModelsLanguageInterfaces.WindPower EnergyModelsLanguageInterfaces.CSPandPV EnergyModelsLanguageInterfaces.MultipleBuildingTypes -EnergyModelsLanguageInterfaces.ResourceBio EnergyModelsLanguageInterfaces.BioCHP ``` +## [Sampling constructors](@id lib-pub-sampling_constructors) + +```@docs +EnergyModelsLanguageInterfaces.WindPower( + ::Any, + ::TimeStruct.TimeProfile, + ::Dict, + ::String, + ::String, + ::TimeStruct.TimeProfile, + ::TimeStruct.TimeProfile, + ::Dict{<:EnergyModelsBase.Resource,<:Real}, +) +EnergyModelsLanguageInterfaces.CSPandPV( + ::Any, + ::Dict, + ::DateTime, + ::DateTime, + ::Dict{String,<:EnergyModelsBase.Resource}; + data::Vector{<:Data} = Data[], + method::String = "Ninja", + data_path::String = "", + source::String = "NORA3", +) +EnergyModelsLanguageInterfaces.MultipleBuildingTypes( + ::Any, + ::Dict, + ::DateTime, + ::DateTime, + ::Vector{String}, + ::Dict{String,<:EnergyModelsBase.Resource}, + ::TimeStruct.TimeStructure, + ::Dict{<:EnergyModelsBase.Resource,<:TimeStruct.TimeProfile}, + ::Dict{<:EnergyModelsBase.Resource,<:TimeStruct.TimeProfile}; + data::Vector{<:EnergyModelsBase.Data} = EnergyModelsBase.Data[], + data_location::String = joinpath(tempdir(), "buildings"), + overwrite_saved_data::Bool = false, +) +EnergyModelsLanguageInterfaces.BioCHP( + ::Any, + ::TimeStruct.TimeProfile, + ::Dict{<:EnergyModelsLanguageInterfaces.ResourceBio,<:Real}, + ::Dict{<:EnergyModelsHeat.ResourceHeat,<:Real}, + ::EnergyModelsBase.Resource; + data::Vector{<:EnergyModelsBase.Data} = EnergyModelsBase.Data[], + libpath::String = joinpath(@__DIR__, "..", "..", "CHP_modelling", "build", "lib", "libbioCHP_wrapper.so"), +) +``` + ## [Utility functions](@id lib-pub-util_fun) ```@docs diff --git a/docs/src/nodes/biochp.md b/docs/src/nodes/biochp.md new file mode 100644 index 0000000..1d78b98 --- /dev/null +++ b/docs/src/nodes/biochp.md @@ -0,0 +1,166 @@ +# [BioCHP](@id nodes-BioCHP) + +The [`BioCHP`](@ref) node represents a biomass-fired combined heat and power (CHP) plant. + +!!! note "Sampling CHP_modelling module" + To use the [constructor](@ref lib-pub-sampling_constructors) that samples the [CHP_modelling](https://github.com/iDesignRES/CHP_modelling) module, follow the installation in the [Use nodes](@ref how_to-utilize-use_nodes) section. + +The `BioCHP` utilizes linear, time-independent conversion rates from the `input` [`Resource`](@extref EnergyModelsBase.Resource)s to the `output` [`Resource`](@extref EnergyModelsBase.Resource)s, subject to the available capacity. +The capacity is normalized such that a conversion value of 1 corresponds to the nominal capacity in the fields `input` and `output`. + +Compared to a standard [`NetworkNode`](@extref EnergyModelsBase.NetworkNode), `BioCHP` differs in its outlet-flow constraints: +the produced heat does not have to be used (e.g., heat outputs are allowed to be zero), while electric output is enforced according to the given conversion factor. + +## [Introduced types and their fields](@id nodes-BioCHP-fields) + +The [`BioCHP`](@ref) is a subtype of the [`NetworkNode`](@extref EnergyModelsBase.NetworkNode). +It uses the standard `NetworkNode` functions from `EnergyModelsBase`. + +### [Standard fields](@id nodes-BioCHP-fields-stand) + +- **`id`**:\ + The field `id` is only used for providing a name to the node. + This is similar to the approach utilized in `EnergyModelsBase`. + +- **`cap::TimeProfile`**:\ + Specifies the installed capacity, that is the heat the heat pump can deliver.\ + If the node should contain investments through the application of [`EnergyModelsInvestments`](https://energymodelsx.github.io/EnergyModelsInvestments.jl/stable/), it is important to note that you can only use `FixedProfile` or `StrategicProfile` for the capacity, but not `RepresentativeProfile` or `OperationalProfile`.\ + In addition, all values have to be non-negative. + +- **`opex_var::TimeProfile`**:\ + The variable operational expenses are based on the capacity utilization through the variable [`:cap_use`](@extref EnergyModelsBase man-opt_var-cap). + Hence, it is directly related to the specified `output` ratios. + The variable operating expenses can be provided as `OperationalProfile` as well. + +- **`opex_fixed::TimeProfile`**:\ + The fixed operating expenses are relative to the installed capacity (through the field `cap`) and the chosen duration of a strategic period as outlined on *[Utilize `TimeStruct`](@extref EnergyModelsBase how_to-utilize_TS)*.\ + It is important to note that you can only use `FixedProfile` or `StrategicProfile` for the fixed OPEX, but not `RepresentativeProfile` or `OperationalProfile`. + In addition, all values have to be non-negative. + +- **`output::Dict{<:Resource, <:Real}`**:\ + The field `output` includes the output [`Resource`](@extref EnergyModelsBase.Resource)s with their corresponding conversion factors as dictionaries. + It is also possible to include other resources which are produced with a given correlation with the heat.\ + All values have to be non-negative. + +- **`data::Vector{<:ExtensionData}`**:\ + An entry for providing additional data to the model. + In the current version, it is only relevant for additional investment data when [`EnergyModelsInvestments`](https://energymodelsx.github.io/EnergyModelsInvestments.jl/) is used or for additional emission data through [`EmissionsProcess`](@extref EnergyModelsBase.EmissionsProcess). + The latter would correspond to uncaptured CO₂ that should be included in the analyses. + !!! note + The field `data` is not required as we include a constructor when the value is excluded. + +### [New fields](@id nodes-BioCHP-fields-new) + +- **`electricity_resource::Resource`**:\ + The electric power resource produced by the CHP plant. + This field is used to distinguish electricity from (potential) heat outputs in the outlet-flow constraints. + +- **`input::Dict{<:ResourceBio, <:Real}`**:\ + The biomass input resources (of type [`ResourceBio`](@ref)) and their conversion factors. + These conversion factors are normalized to the capacity definition of the node. + +!!! note "Default `data` constructor" + The provided constructor assigns `data = [EmissionsEnergy()]` by default. + This means the node includes energy-based emission accounting unless overwritten by explicitly constructing `BioCHP` with a custom `data` vector. + +## [Mathematical description](@id nodes-BioCHP-math) + +In the following mathematical equations, we use the names for variables and functions used in the model. +Variables are in general represented as + +``\texttt{var\_example}[index_1, index_2]`` + +with square brackets, while functions are represented as + +``func\_example(index_1, index_2)`` + +with paranthesis. + +### [Variables](@id nodes-BioCHP-math-var) + +The [`BioCHP`](@ref) node uses standard `NetworkNode` variables, as described on the page *[Optimization variables](@extref EnergyModelsBase man-opt_var)*. +The variables include: + +- [``\texttt{opex\_var}``](@extref EnergyModelsBase man-opt_var-opex) +- [``\texttt{opex\_fixed}``](@extref EnergyModelsBase man-opt_var-opex) +- [``\texttt{cap\_use}``](@extref EnergyModelsBase man-opt_var-cap) +- [``\texttt{cap\_inst}``](@extref EnergyModelsBase man-opt_var-cap) +- [``\texttt{flow\_in}``](@extref EnergyModelsBase man-opt_var-flow) +- [``\texttt{flow\_out}``](@extref EnergyModelsBase man-opt_var-flow) + +### [Constraints](@id nodes-BioCHP-math-con) + +The following sections omit the direct inclusion of the vector of heat pump nodes. +Instead, it is implicitly assumed that the constraints are valid ``\forall n ∈ N^{BioCHP}`` for all [`BioCHP`](@ref) types if not stated differently. +In addition, all constraints are valid ``\forall t \in T`` (that is in all operational periods) or ``\forall t_{inv} \in T^{Inv}`` (that is in all strategic periods). + +#### [Standard constraints](@id nodes-BioCHP-math-con-stand) + +`BioCHP` nodes utilize in general the standard constraints described on +*[Constraint functions](@extref EnergyModelsBase man-con)* for `NetworkNode`s. +These standard constraints are: + +- `constraints_capacity`: + + ```math + \texttt{cap\_use}[n, t] \leq \texttt{cap\_inst}[n, t] + ``` + +- `constraints_capacity_installed`: + + ```math + \texttt{cap\_inst}[n, t] = capacity(n, t) + ``` + + !!! tip "Using investments" + The function `constraints_capacity_installed` is also used in [`EnergyModelsInvestments`](https://energymodelsx.github.io/EnergyModelsInvestments.jl/) to incorporate the potential for investment. + Nodes with investments are then no longer constrained by the parameter capacity. + +- `constraints_flow_out`: + + ```math + \texttt{flow\_out}[n, t, p] = + outputs(n, p) \times \texttt{cap\_use}[n, t] + \qquad \forall p \in outputs(n) \setminus \{\text{CO}_2\} + ``` + +- `constraints_opex_fixed`: + + ```math + \texttt{opex\_fixed}[n, t_{inv}] = opex\_fixed(n, t_{inv}) \times \texttt{cap\_inst}[n, first(t_{inv})] + ``` + + !!! tip "Why do we use `first()`" + The variable ``\texttt{cap\_inst}`` is declared over all operational periods (see the section on *[Capacity variables](@extref EnergyModelsBase man-opt_var-cap)* for further explanations). + Hence, we use the function ``first(t_{inv})`` to retrieve the installed capacity in the first operational period of a given strategic period ``t_{inv}`` in the function `constraints_opex_fixed`. + +- `constraints_opex_var`: + + ```math + \texttt{opex\_var}[n, t_{inv}] = \sum_{t \in t_{inv}} opex\_var(n, t) \times \texttt{cap\_use}[n, t] \times scale\_op\_sp(t_{inv}, t) + ``` + + !!! tip "The function `scale_op_sp`" + The function [``scale\_op\_sp(t_{inv}, t)``](@extref EnergyModelsBase.scale_op_sp) calculates the scaling factor between operational and strategic periods. + It also takes into account potential operational scenarios and their probability as well as representative periods. + +- `constraints_ext_data`:\ + This function is only called for specified data of the storage node, see above. + +The function `constraints_flow_out` is extended with a new method for BioCHP nodes such that the outputs are flexible with respect to output resources not being the `electricity_resource`. + +Let ``\mathcal{P}^{out}(n)`` denote the set of output resources of node ``n`` excluding CO₂ and `electricity_resource`. The implemented constraint is + +```math +\texttt{flow\_out}[n, t, p] = outputs(n, p) \times \texttt{cap\_use}[n, t] \qquad \forall p \in \mathcal{P}^{out}(n) +``` + +For the `electricity_resource` we still have + +```math +\texttt{flow\_out}[n, t, electricity_resource(n)] = outputs(n, electricity_resource(n)) \times \texttt{cap\_use}[n, t] +``` + +#### [Additional constraints](@id nodes-BioCHP-math-con-add) + +[`BioCHP`](@ref) nodes do not add additional constraint functions or constraints in the `create_node` function. diff --git a/docs/src/nodes/multiplebuildingtypes.md b/docs/src/nodes/multiplebuildingtypes.md new file mode 100644 index 0000000..e7af9b2 --- /dev/null +++ b/docs/src/nodes/multiplebuildingtypes.md @@ -0,0 +1,153 @@ +# [Multiple building types sink node](@id nodes-MultipleBuildingTypes) + +The [`MultipleBuildingTypes`](@ref) node creates sinks for all demand resources with penalties for both surplus and deficit. +The implementation uses `Dict` structures for the fields `cap`, `penalty_surplus`, and `penalty_deficit` to facilitate multiple [Resource](@extref EnergyModelsBase.Resource)s. +This approach allows modeling building demands with flexible penalty mechanisms for over- and under-supply. +The type is also used to enable specialized constructors that samples the [`Tecnalia_Building-Stock-Energy-Model`](https://github.com/iDesignRES/Tecnalia_Building-Stock-Energy-Model) module. + +!!! note "Sampling Tecnalia_Building-Stock-Energy-Model module" + To use the [constructor](@ref lib-pub-sampling_constructors) for [`MultipleBuildingTypes`](@ref) that samples the [`Tecnalia_Building-Stock-Energy-Model`](https://github.com/iDesignRES/Tecnalia_Building-Stock-Energy-Model) module, follow the installation in the [Use nodes](@ref how_to-utilize-use_nodes) section. + +!!! danger + Investments are currently not available for this node. + +## [Introduced type and its field](@id nodes-MultipleBuildingTypes-fields) + +The [`MultipleBuildingTypes`](@ref) is a subtype of [`Sink`](@extref EnergyModelsBase.Sink) and is implemented as a specialized sink node. +Hence, it utilizes the same functions declared in `EnergyModelsBase`. + +### [Standard fields](@id nodes-MultipleBuildingTypes-fields-stand) + +Standard fields of a [`MultipleBuildingTypes`](@ref) node are given as: + +- **`id`**:\ + The field `id` is only used for providing a name to the node. + This is similar to the approach utilized in `EnergyModelsBase`. +- **`input::Dict{<:Resource, <:Real}`**:\ + The field `input` includes [`Resource`](@extref EnergyModelsBase.Resource)s with their corresponding conversion factors as dictionaries. + All values have to be non-negative. +- **`data::Vector{Data}`**:\ + An entry for providing additional data to the model. + In the current version, it is not applicable. We intend to change this in future releases to enable investments. + + !!! note "Constructor for `MultipleBuildingTypes`" + The field `data` is not required as we include a constructor when the value is excluded. + + !!! danger "Using `CaptureData`" + As a `Sink` node does not have any output, it is not possible to utilize `CaptureData`. + If you still plan to specify it, you will receive an error in the model building. + +### [Additional fields](@id nodes-MultipleBuildingTypes-fields-new) + +[`MultipleBuildingTypes`](@ref) nodes introduce additional fields for demand and penalty specifications: + +- **`cap::Dict{<:Resource,<:TimeProfile}`**:\ + The demand capacity for each of the input resources. + All values have to be non-negative. +- **`penalty_surplus::Dict{<:Resource,<:TimeProfile}`**:\ + The penalties applied for surplus (over-supply) for each of the input resources. + These penalties affect the variable operational expenses. + All values have to be non-negative. +- **`penalty_deficit::Dict{<:Resource,<:TimeProfile}`**:\ + The penalties applied for deficit (under-supply) for each of the input resources. + These penalties affect the variable operational expenses. + All values have to be non-negative. + +## [Mathematical description](@id nodes-MultipleBuildingTypes-math) + +In the following mathematical equations, we use the name for variables and functions used in the model. +Variables are in general represented as + +``\texttt{var\_example}[index_1, index_2]`` + +with square brackets, while functions are represented as + +``func\_example(index_1, index_2)`` + +with paranthesis. + +### [Variables](@id nodes-MultipleBuildingTypes-math-var) + +#### [Standard variables](@id nodes-MultipleBuildingTypes-math-var-stand) + +The [`MultipleBuildingTypes`](@ref) node type utilizes standard variables from the [`Sink`](@extref EnergyModelsBase.Sink) node type and includes: + +- [``\texttt{opex\_var}``](@extref EnergyModelsBase man-opt_var-opex) +- [``\texttt{opex\_fixed}``](@extref EnergyModelsBase man-opt_var-opex) +- [``\texttt{flow\_in}``](@extref EnergyModelsBase man-opt_var-flow) +- [``\texttt{sink\_surplus}``](@extref EnergyModelsBase man-opt_var-sink) +- [``\texttt{sink\_deficit}``](@extref EnergyModelsBase man-opt_var-sink) +- [``\texttt{emissions\_node}``](@extref EnergyModelsBase man-opt_var-emissions) if `EmissionsData` is added to the field `data` + +!!! note "cap\_use" + The standard variable [``\texttt{cap\_use}``](@extref EnergyModelsBase man-opt_var-opex) is not used. A MultipleBuildingTypes has capacity for all its resources but not in a EnergyModelsBase sense. + +#### [Additional variables](@id nodes-MultipleBuildingTypes-math-add) + +[`MultipleBuildingTypes`](@ref) introduces the following variables: + +- ``\texttt{buildings\_surplus}[n, t, p]``: Surplus (over-supply) for node ``n`` in operational period ``t`` for resource ``p``. +- ``\texttt{buildings\_deficit}[n, t, p]``: Deficit (under-supply) for node ``n`` in operational period ``t`` for resource ``p``. +- ``\texttt{sink\_surplus}[n, t]``: Total surplus aggregated across all resources. +- ``\texttt{sink\_deficit}[n, t]``: Total deficit aggregated across all resources. + +### [Constraints](@id nodes-MultipleBuildingTypes-math-con) + +The following sections omit the direct inclusion of the vector of [`MultipleBuildingTypes`](@ref) nodes. +Instead, it is implicitly assumed that the constraints are valid ``\forall n ∈ N^{\text{MultipleBuildingTypes}}`` if not stated differently. +In addition, all constraints are valid ``\forall t \in T`` (that is in all operational periods) or ``\forall t_{inv} \in T^{Inv}`` (that is in all strategic periods). +Finally, all constraints are valid ``\forall p \in inputs(n)`` (that is in all input resources). + +#### [Standard constraints](@id nodes-MultipleBuildingTypes-math-con-stand) + +[`MultipleBuildingTypes`](@ref) nodes utilize the following constraint functions: + +- `constraints_capacity`: + + ```math + \frac{\texttt{flow\_in}[n, t, p]}{inputs(n, p)} + \texttt{buildings\_deficit}[n, t, p] = + capacity(n, t, p) + \texttt{buildings\_surplus}[n, t, p] + \qquad \forall p \in inputs(n) + ``` + + ```math + \texttt{sink\_deficit}[n, t] = \sum_{p \in inputs(n)} \texttt{buildings\_deficit}[n, t, p] + ``` + + ```math + \texttt{sink\_surplus}[n, t] = \sum_{p \in inputs(n)} \texttt{buildings\_surplus}[n, t, p] + ``` + + !!! note "constraints_capacity_installed" + The function `constraints_capacity_installed` is not used and the node thus currently does not support investments. + +- `constraints_flow_in`:\ + This function is not used; inlet flow constraints are implemented directly in `constraints_capacity`. + +- `constraints_opex_fixed`:\ + The current implementation fixes the fixed operating expenses of a sink to 0. + + ```math + \texttt{opex\_fixed}[n, t_{inv}] = 0 + ``` + +- `constraints_opex_var`: + + ```math + \texttt{opex\_var}[n, t_{inv}] = \sum_{t \in t_{inv},\, p \in inputs(n)} + \left( + \texttt{buildings\_surplus}[n, t, p] \times penalty\_surplus(n, t, p) + + \texttt{buildings\_deficit}[n, t, p] \times penalty\_deficit(n, t, p) + \right) \times scale\_op\_sp(t_{inv}, t) + ``` + + !!! tip "The function `scale_op_sp`" + The function [``scale\_op\_sp(t_{inv}, t)``](@extref EnergyModelsBase.scale_op_sp) calculates the scaling factor between operational and strategic periods. + It also takes into account potential operational scenarios and their probability as well as representative periods. + +- `constraints_ext_data`:\ + This function is only called for specified additional data, see above. + +#### [Additional constraints](@id nodes-MultipleBuildingTypes-math-con-add) + +[`MultipleBuildingTypes`](@ref) nodes do not add additional constraints. diff --git a/docs/src/nodes/pvandcsp.md b/docs/src/nodes/pvandcsp.md new file mode 100644 index 0000000..2b976d7 --- /dev/null +++ b/docs/src/nodes/pvandcsp.md @@ -0,0 +1,154 @@ +# [PV and CSV source node](@id nodes-CSPandPV) + +PV and CSP source generate, respectively, electricity and heat from solar power. +The implementation of the node is similar to that of [NonDisRES](@extref EnergyModelsRenewableProducers nodes-nondisres) but uses `Dict` structures for the fields `cap`, `profile`, `opex_var` and `opex_fixed` to facilitate multiple [Resource](@extref EnergyModelsBase.Resource)s (both electricity and heat outputs). +The type is also used to enable specialized constructors that samples the [Tecnalia_Solar-Energy-Model](https://github.com/iDesignRES/Tecnalia_Solar-Energy-Model) module. + +!!! note "Sampling Tecnalia_Solar-Energy-Model module" + To use the [constructor](@ref lib-pub-sampling_constructors) for [`CSPandPV`](@ref) that samples the [Tecnalia_Solar-Energy-Model](https://github.com/iDesignRES/Tecnalia_Solar-Energy-Model) module, follow the installation in the [Use nodes](@ref how_to-utilize-use_nodes) section. + +!!! danger + Investments are currently not available for this node. + +## [Introduced type and its field](@id nodes-CSPandPV-fields) + +The [`CSPandPV`](@ref) is a subtype of [`AbstractNonDisRES`](@extref EnergyModelsRenewableProducers.AbstractNonDisRES) (the same is the case for [NonDisRES](@extref EnergyModelsRenewableProducers nodes-nondisres)) and is thus implemented as equivalent to a [`RefSource`](@extref EnergyModelsBase.RefSource). +Hence, it utilizes the same functions declared in `EnergyModelsBase`. + +### [Standard fields](@id nodes-CSPandPV-fields-stand) + +Standard fields (of a [`AbstractNonDisRES`](@extref EnergyModelsRenewableProducers.AbstractNonDisRES)) being reused are given as: + +- **`id`**:\ + The field `id` is only used for providing a name to the node. + This is similar to the approach utilized in `EnergyModelsBase`. +- **`output::Dict{<:Resource, <:Real}`**:\ + The field `output` includes [`Resource`](@extref EnergyModelsBase.Resource)s with their corresponding conversion factors as dictionaries. + In the case of a PV and CSP energy source, `output` should always include your *electricity* resource and a *heat* resource. In practice, you should use a value of 1.\ + All values have to be non-negative. +- **`data::Vector{Data}`**:\ + An entry for providing additional data to the model. + In the current version, it is not applicable. We intend to change this in future releases to enable investments. + + !!! note "Constructor for `CSPandPV`" + The field `data` is not required as we include a constructor when the value is excluded. + +### [Additional fields](@id nodes-CSPandPV-fields-new) + +[`CSPandPV`](@ref) nodes alter the types of some fields compared to a [`AbstractNonDisRES`](@extref EnergyModelsRenewableProducers.AbstractNonDisRES): + +- **`cap::Dict{<:Resource,<:TimeProfile}`**:\ + The installed capacity corresponds to the nominal capacity of the node for each of the produced resources.\ + If the node should contain investments through the application of [`EnergyModelsInvestments`](https://energymodelsx.github.io/EnergyModelsInvestments.jl/stable/), it is important to note that you can only use `FixedProfile` or `StrategicProfile` for the capacity, but not `RepresentativeProfile` or `OperationalProfile`. + In addition, all values have to be non-negative. +- **`profile::Dict{<:Resource,<:TimeProfile}`**:\ + The profiles are used as a multiplier to the installed capacity to represent the maximum actual capacity in each operational period for each of the produced resources. + The profiles should be provided as `OperationalProfile` or at least as `RepresentativeProfile`. + In addition, all values should be in the range ``[0, 1]``. +- **`opex_var::Dict{<:Resource,<:TimeProfile}`**:\ + The variable operational expenses are based on the capacity utilization through the variable [`:cap_use`](@extref EnergyModelsBase man-opt_var-cap) for each of the produced resources. + Hence, it is directly related to the specified `output` ratios. + The variable operating expenses can be provided as `OperationalProfile` as well. +- **`opex_fixed::Dict{<:Resource,<:TimeProfile}`**:\ + The fixed operating expenses are relative to the installed capacity (through the field `cap`) for each of the produced resources and the chosen duration of a strategic period as outlined on *[Utilize `TimeStruct`](@extref EnergyModelsBase how_to-utilize_TS)*.\ + It is important to note that you can only use `FixedProfile` or `StrategicProfile` for the fixed OPEX, but not `RepresentativeProfile` or `OperationalProfile`. + In addition, all values have to be non-negative. + +## [Mathematical description](@id nodes-CSPandPV-math) + +In the following mathematical equations, we use the name for variables and functions used in the model. +Variables are in general represented as + +``\texttt{var\_example}[index_1, index_2]`` + +with square brackets, while functions are represented as + +``func\_example(index_1, index_2)`` + +with paranthesis. + +### [Variables](@id nodes-CSPandPV-math-var) + +#### [Standard variables](@id nodes-CSPandPV-math-var-stand) + +The PV and CSP source node types utilize all standard variables from the [`AbstractNonDisRES`](@extref EnergyModelsRenewableProducers.AbstractNonDisRES) node type. +The variables include: + +- [``\texttt{opex\_var}``](@extref EnergyModelsBase man-opt_var-opex) +- [``\texttt{opex\_fixed}``](@extref EnergyModelsBase man-opt_var-opex) +- [``\texttt{cap\_inst}``](@extref EnergyModelsBase man-opt_var-cap) +- [``\texttt{flow\_out}``](@extref EnergyModelsBase man-opt_var-flow) +- [``\texttt{emissions\_node}``](@extref EnergyModelsBase man-opt_var-emissions) if `EmissionsData` is added to the field `data`. +- [``\texttt{curtailment}[n, t]``](@extref EnergyModelsRenewableProducers nodes-nondisres-math-add): For [`CSPandPV`](@ref), this variable is the sum of curtailed capacity of source ``n`` in operational period ``t``.\ + +!!! note + Non-dispatchable renewable energy source nodes are not compatible with `CaptureData`. + Hence, you can only provide [`EmissionsProcess`](@extref EnergyModelsBase.EmissionsProcess) to the node. + It is our aim to include the potential for construction emissions in a latter stage + +#### [Additional variables](@id nodes-CSPandPV-math-add) + +[`CSPandPV`](@ref) replaces the variables [``\texttt{cap\_use}``](@extref EnergyModelsBase man-opt_var-cap) and [``\texttt{curtailment}``](@extref EnergyModelsRenewableProducers nodes-nondisres-math-add) variables with the following variables + +- ``\texttt{solar\_cap\_use}[n, t, p]``: The capacity usage of source ``n`` in operational period ``t`` for resource ``p``. +- ``\texttt{solar\_curtailment}[n, t, p]``: Curtailed capacity of source ``n`` in operational period ``t`` for resource ``p`` with a typical unit of MW.\ + The curtailed resources specifies the unused generation capacity of sources. + It is currently only used in the calculation, but not with a cost. + +### [Constraints](@id nodes-CSPandPV-math-con) + +The following sections omit the direct inclusion of the vector of PV and CSP source nodes. +Instead, it is implicitly assumed that the constraints are valid ``\forall n ∈ N^{\text{CSPandPV}\_source}`` for all [`CSPandPV`](@ref) types if not stated differently. +In addition, all constraints are valid ``\forall t \in T`` (that is in all operational periods) or ``\forall t_{inv} \in T^{Inv}`` (that is in all strategic periods). +Finally, all constraints are valid ``\forall p \in outputs(n)`` (that is in all output resources). + +#### [Standard constraints](@id nodes-CSPandPV-math-con-stand) + +[`CSPandPV`](@ref) nodes utilize specialized constraint functions that extend the standard approach to accommodate multiple resources with per-resource tracking. +These constraints are: + +- `constraints_capacity`: + + ```math + \texttt{solar\_cap\_use}[n, t, p] \leq capacity(n, t, p) + ``` + + ```math + \texttt{solar\_cap\_use}[n, t, p] + \texttt{solar\_curtailment}[n, t, p] = + profile(n, t, p) \times capacity(n, t, p) + \qquad \forall p \in outputs(n) + ``` + + ```math + \sum_{p \in outputs(n)} \texttt{solar\_curtailment}[n, t, p] = \texttt{curtailment}[n, t] + ``` + + !!! note "constraints_capacity_installed" + The function `constraints_capacity_installed` is not used and the node thus currently does not support investments. + +- `constraints_flow_out`: + + ```math + \texttt{flow\_out}[n, t, p] = + \texttt{solar\_cap\_use}[n, t, p] \times outputs(n, p) + \qquad \forall p \in outputs(n) \setminus \{\text{CO}_2\} + ``` + +- `constraints_opex_fixed`: + + ```math + \texttt{opex\_fixed}[n, t_{inv}] = \sum_{p \in outputs(n)} opex\_fixed(n, t_{inv}, p) \times capacity(n, first(t_{inv}), p) + ``` + +- `constraints_opex_var`: + + ```math + \texttt{opex\_var}[n, t_{inv}] = \sum_{t \in t_{inv},\, p \in outputs(n)} \texttt{solar\_cap\_use}[n, t, p] \times opex\_var(n, t, p) \times scale\_op\_sp(t_{inv}, t) + ``` + +- `constraints_data`:\ + This function is only called for specified data of the node, see above. + +#### [Additional constraints](@id nodes-CSPandPV-math-con-add) + +[`CSPandPV`](@ref) nodes do not add additional constraints. \ No newline at end of file diff --git a/docs/src/nodes/windpower.md b/docs/src/nodes/windpower.md new file mode 100644 index 0000000..81493dc --- /dev/null +++ b/docs/src/nodes/windpower.md @@ -0,0 +1,161 @@ +# [Wind power source node](@id nodes-WindPower) + +Wind power source generate electricity from wind sources. +The implementation of the node is identical to that of [NonDisRES](@extref EnergyModelsRenewableProducers nodes-nondisres) and is here used to enable specialized constructors that samples the [`wind_power_timeseries`](https://gitlab.sintef.no/harald.svendsen/wind_power_timeseries) module. + +!!! note "Sampling wind\_power\_timeseries module" + To use the [constructor](@ref lib-pub-sampling_constructors) for [`WindPower`](@ref) that samples the [`wind_power_timeseries`](https://gitlab.sintef.no/harald.svendsen/wind_power_timeseries) module, follow the installation in the [Use nodes](@ref how_to-utilize-use_nodes) section. + +## [Introduced type and its field](@id nodes-WindPower-fields) + +The [`WindPower`](@ref) is a subtype of [`AbstractNonDisRES`](@extref EnergyModelsRenewableProducers.AbstractNonDisRES) (the same is the case for [NonDisRES](@extref EnergyModelsRenewableProducers nodes-nondisres)) and is thus implemented as equivalent to a [`RefSource`](@extref EnergyModelsBase.RefSource). +Hence, it utilizes the same functions declared in `EnergyModelsBase`. + +### [Standard fields](@id nodes-WindPower-fields-stand) + +The standard fields (of a [`AbstractNonDisRES`](@extref EnergyModelsRenewableProducers.AbstractNonDisRES)) are given as: + +- **`id`**:\ + The field `id` is only used for providing a name to the node. + This is similar to the approach utilized in `EnergyModelsBase`. +- **`cap::TimeProfile`**:\ + The installed capacity corresponds to the nominal capacity of the node.\ + If the node should contain investments through the application of [`EnergyModelsInvestments`](https://energymodelsx.github.io/EnergyModelsInvestments.jl/stable/), it is important to note that you can only use `FixedProfile` or `StrategicProfile` for the capacity, but not `RepresentativeProfile` or `OperationalProfile`. + In addition, all values have to be non-negative. +- **`profile::TimeProfile`**:\ + The profile is used as a multiplier to the installed capacity to represent the maximum actual capacity in each operational period. + The profile should be provided as `OperationalProfile` or at least as `RepresentativeProfile`. + In addition, all values should be in the range ``[0, 1]``. +- **`opex_var::TimeProfile`**:\ + The variable operational expenses are based on the capacity utilization through the variable [`:cap_use`](@extref EnergyModelsBase man-opt_var-cap). + Hence, it is directly related to the specified `output` ratios. + The variable operating expenses can be provided as `OperationalProfile` as well. +- **`opex_fixed::TimeProfile`**:\ + The fixed operating expenses are relative to the installed capacity (through the field `cap`) and the chosen duration of a strategic period as outlined on *[Utilize `TimeStruct`](@extref EnergyModelsBase how_to-utilize_TS)*.\ + It is important to note that you can only use `FixedProfile` or `StrategicProfile` for the fixed OPEX, but not `RepresentativeProfile` or `OperationalProfile`. + In addition, all values have to be non-negative. +- **`output::Dict{<:Resource, <:Real}`**:\ + The field `output` includes [`Resource`](@extref EnergyModelsBase.Resource)s with their corresponding conversion factors as dictionaries. + In the case of a non-dispatchable renewable energy source, `output` should always include your *electricity* resource.In practice, you should use a value of 1.\ + All values have to be non-negative. +- **`data::Vector{Data}`**:\ + An entry for providing additional data to the model. + In the current version, it is only relevant for additional investment data when [`EnergyModelsInvestments`](https://energymodelsx.github.io/EnergyModelsInvestments.jl/stable/) is used. + + !!! note "Constructor for `WindPower`" + The field `data` is not required as we include a constructor when the value is excluded. + +### [Additional fields](@id nodes-WindPower-fields-new) + +[`WindPower`](@ref) adds no additional fields to that of [`AbstractNonDisRES`](@extref EnergyModelsRenewableProducers.AbstractNonDisRES). + +## [Mathematical description](@id nodes-WindPower-math) + +In the following mathematical equations, we use the name for variables and functions used in the model. +Variables are in general represented as + +``\texttt{var\_example}[index_1, index_2]`` + +with square brackets, while functions are represented as + +``func\_example(index_1, index_2)`` + +with paranthesis. + +### [Variables](@id nodes-WindPower-math-var) + +#### [Standard variables](@id nodes-WindPower-math-var-stand) + +The wind power source node types utilize all standard variables from the [`AbstractNonDisRES`](@extref EnergyModelsRenewableProducers.AbstractNonDisRES) node type. +The variables include: + +- [``\texttt{opex\_var}``](@extref EnergyModelsBase man-opt_var-opex) +- [``\texttt{opex\_fixed}``](@extref EnergyModelsBase man-opt_var-opex) +- [``\texttt{cap\_use}``](@extref EnergyModelsBase man-opt_var-cap) +- [``\texttt{cap\_inst}``](@extref EnergyModelsBase man-opt_var-cap) +- [``\texttt{flow\_out}``](@extref EnergyModelsBase man-opt_var-flow) +- [``\texttt{emissions\_node}``](@extref EnergyModelsBase man-opt_var-emissions) if `EmissionsData` is added to the field `data`. +- [``\texttt{curtailment}[n, t]``](@extref EnergyModelsRenewableProducers nodes-nondisres-math-add): Curtailed capacity of source ``n`` in operational period ``t`` with a typical unit of MW.\ + The curtailed electricity specifies the unused generation capacity of the wind power source. + It is currently only used in the calculation, but not with a cost. + +!!! note + Non-dispatchable renewable energy source nodes are not compatible with `CaptureData`. + Hence, you can only provide [`EmissionsProcess`](@extref EnergyModelsBase.EmissionsProcess) to the node. + It is our aim to include the potential for construction emissions in a latter stage + +#### [Additional variables](@id nodes-WindPower-math-add) + +[`WindPower`](@ref) adds no additional variables to that of [`AbstractNonDisRES`](@extref EnergyModelsRenewableProducers.AbstractNonDisRES). + +### [Constraints](@id nodes-WindPower-math-con) + +The following sections omit the direct inclusion of the vector of wind power nodes. +Instead, it is implicitly assumed that the constraints are valid ``\forall n ∈ N^{\text{WindPower}\_source}`` for all [`WindPower`](@ref) types if not stated differently. +In addition, all constraints are valid ``\forall t \in T`` (that is in all operational periods) or ``\forall t_{inv} \in T^{Inv}`` (that is in all strategic periods). + +#### [Standard constraints](@id nodes-WindPower-math-con-stand) + +Wind power source nodes utilize in general the standard constraints described on *[Constraint functions](@extref EnergyModelsRenewableProducers nodes-nondisres-math-con)*. +These standard constraints are: + +- `constraints_capacity_installed`: + + ```math + \texttt{cap\_inst}[n, t] = capacity(n, t) + ``` + + !!! tip "Using investments" + The function `constraints_capacity_installed` is also used in [`EnergyModelsInvestments`](https://energymodelsx.github.io/EnergyModelsInvestments.jl/stable/) to incorporate the potential for investment. + Nodes with investments are then no longer constrained by the parameter capacity. + +- `constraints_flow_out`: + + ```math + \texttt{flow\_out}[n, t, p] = + outputs(n, p) \times \texttt{cap\_use}[n, t] + \qquad \forall p \in outputs(n) \setminus \{\text{CO}_2\} + ``` + +- `constraints_opex_fixed`: + + ```math + \texttt{opex\_fixed}[n, t_{inv}] = opex\_fixed(n, t_{inv}) \times \texttt{cap\_inst}[n, first(t_{inv})] + ``` + + !!! tip "Why do we use `first()`" + The variables ``\texttt{cap\_inst}`` are declared over all operational periods (see the section on *[Capacity variables](@extref EnergyModelsBase man-opt_var-cap)* for further explanations). + Hence, we use the function ``first(t_{inv})`` to retrieve the installed capacities in the first operational period of a given strategic period ``t_{inv}`` in the function `constraints_opex_fixed`. + +- `constraints_opex_var`: + + ```math + \texttt{opex\_var}[n, t_{inv}] = \sum_{t \in t_{inv}} opex\_var(n, t) \times \texttt{cap\_use}[n, t] \times scale\_op\_sp(t_{inv}, t) + ``` + + !!! tip "The function `scale_op_sp`" + The function [``scale\_op\_sp(t_{inv}, t)``](@extref EnergyModelsBase.scale_op_sp) calculates the scaling factor between operational and strategic periods. + It also takes into account potential operational scenarios and their probability as well as representative periods. + +- `constraints_data`:\ + This function is only called for specified data of the non-dispatchable renewable energy source, see above. + +The function `constraints_capacity` is extended by [`AbstractNonDisRES`](@extref EnergyModelsRenewableProducers.AbstractNonDisRES) with a method for non-dispatchable renewable energy source nodes to allow the inclusion of the production profile and the variable ``\texttt{curtailment}[n, t]``. +It includes two individual constraints: + +```math +\texttt{cap\_use}[n, t] \leq \texttt{cap\_inst}[n, t] +``` + +and + +```math +\texttt{cap\_use}[n, t] + \texttt{curtailment}[n, t] = +profile(n, t) \times \texttt{cap\_inst}[n, t] +``` + +This function still calls the subfunction `constraints_capacity_installed` to limit the variable ``\texttt{cap\_inst}[n, t]`` or provide capacity investment options. + +#### [Additional constraints](@id nodes-WindPower-math-con-add) + +[`WindPower`](@ref) nodes do not add additional constraints. \ No newline at end of file diff --git a/docs/src/resources/resourcebio.md b/docs/src/resources/resourcebio.md new file mode 100644 index 0000000..af2d99a --- /dev/null +++ b/docs/src/resources/resourcebio.md @@ -0,0 +1,28 @@ +# [ResourceBio](@id resources-ResourceBio) + +Biomass fuels have characteristics that go beyond a pure energy carrier, such as the specific fuel type and the moisture content of the material. +[`ResourceBio`](@ref), which is a [`Resource`](@extref EnergyModelsBase.Resource) for transporting and converting biomass fuels, is introduced to enable consistent modeling of biomass-based energy technologies in [EnergyModelsX](https://github.com/EnergyModelsX). + +Compared to a [`ResourceCarrier`](@extref EnergyModelsBase.ResourceCarrier), [`ResourceBio`](@ref) includes additional information on the biomass fuel definition and its moisture content. +Resources of type [`ResourceBio`](@ref) are intended to be *consumed* by technologies (e.g. biomass boilers or CHP plants). + +## [Introduced type and its fields](@id resources-ResourceBio-fields) + +[`ResourceBio`](@ref) extends the abstract type +[`Resource`](https://github.com/EnergyModelsX/EnergyModelsBase.jl/blob/main/src/structures/resource.jl) +from [EnergyModelsBase](https://github.com/EnergyModelsX/EnergyModelsBase.jl/tree/main), +with additional fields describing biomass-specific properties. + +- **`id`** :\ + The field `id` is only used for providing a name to the resource. + +- **`bio_type::String`** :\ + The type of biomass fuel, e.g. `"spruce_stem"`, `"spruce_bark"`, `"spruce_T&B"`, or `"birch_stem"`. + +- **`moisture::Float64`** :\ + Moisture content of the biomass resource as a mass fraction. + Typical values range from around 0.1 for dry pellets to more than 0.5 for wet wood chips. + +- **`co2_int::T`** :\ + CO₂ intensity of the biomass resource (with `T <: Real`), e.g. in t/MWh. + This value can be used by emissions-accounting extensions when biomass is converted or consumed. \ No newline at end of file diff --git a/docs/src/types/reference.md b/docs/src/types/reference.md deleted file mode 100644 index f74c562..0000000 --- a/docs/src/types/reference.md +++ /dev/null @@ -1 +0,0 @@ -# [Reference](@id types-ref) diff --git a/src/datastructures.jl b/src/datastructures.jl index 3229d32..4ccadd2 100644 --- a/src/datastructures.jl +++ b/src/datastructures.jl @@ -47,7 +47,8 @@ end output::Dict{<:Resource,<:Real}; data::Vector{<:Data} = Data[], method::String = "Ninja", - data_path::String = "" + data_path::String = "", + source::String = "NORA3", ) Constructs a [`WindPower`](@ref) instance where the power production profile is sampled from @@ -86,6 +87,10 @@ a Python function. an empty datapath. - **`source`** is the data source for wind data. The user can choose between the strings "NORA3" and "ERA5". The default value is "NORA3". + +!!! note "Usage of the ERA5 data source in wind_power_timeseries" + For use of the "ERA5" data source, the user needs to register and obtain a CDS API key. + - Perform step 1: https://cds.climate.copernicus.eu/how-to-api """ function WindPower( id::Any, @@ -510,7 +515,7 @@ function MultipleBuildingTypes( if time_start <= date && date <= time_end for (res, res_val) ∈ v if !(res ∈ ["Datetime", "Variable cost [€]", "Emissions [KgCO2]"]) - push!(temp[res], res_val/1e6) # Scale power_outputs to MW + push!(temp[res], res_val) end end end @@ -715,8 +720,11 @@ library file located at `libpath`. The BioCHP has electricity production of the - **`data::Vector{<:Data}`** is the additional data (*e.g.*, for investments). - **`libpath`** is the absolute path of the `CHP_modelling` library file. -!!! note ""EmissionsEnergy" +!!! note "EmissionsEnergy" If `EmissionsEnergy` is not included in the `data` field, it is automatically added. + +!!! note "Running on windows" + Adjust the `libpath` to point to the correct `.dll` file when running on Windows. """ function BioCHP( id::Any, diff --git a/test/python_module/src/test_python_sampling/optimization_module.py b/test/python_module/src/test_python_sampling/optimization_module.py index 8b770a1..7ce0d56 100644 --- a/test/python_module/src/test_python_sampling/optimization_module.py +++ b/test/python_module/src/test_python_sampling/optimization_module.py @@ -1,3 +1,4 @@ +import platform import pyomo.environ as pyo def solve_optimization_problem(input_data): @@ -20,7 +21,7 @@ def solve_optimization_problem(input_data): # Define constraints model.constraint = pyo.Constraint(expr=model.x + 2 * model.y + model.z <= 1) # Solve the optimization problem - solver = pyo.SolverFactory("glpk") + solver = pyo.SolverFactory("appsi_highs") solver.solve(model, tee=False) # Extract results x_value = model.x.value diff --git a/test/test_buildings.jl b/test/test_buildings.jl index 2f8ec37..dcf2a9f 100644 --- a/test/test_buildings.jl +++ b/test/test_buildings.jl @@ -24,7 +24,7 @@ value.(m[:buildings_deficit][buildings, t, p]) == 0.0 for t ∈ 𝒯, p ∈ building_res ) - @test all(value.(m[:emissions_total][t, CO2]) > 0.001 for t ∈ 𝒯) + @test all(value.(m[:emissions_total][t, CO2]) > 1e3 for t ∈ 𝒯) # Test that the EMB function has_capacity is false for the MultipleBuildingTypes node. @test !EMB.has_capacity(buildings) diff --git a/test/utils.jl b/test/utils.jl index b7c60b1..c2f1c7c 100644 --- a/test/utils.jl +++ b/test/utils.jl @@ -170,7 +170,7 @@ function simple_graph_buildings(; cap_p = nothing, sources = [ RefSource( "Source for " * resource.id, - FixedProfile(150), + FixedProfile(150e6), FixedProfile(120), FixedProfile(0), Dict(resource => 1.0), @@ -212,7 +212,7 @@ function simple_graph_buildings(; cap_p = nothing, case = Case(T, products, [nodes, links], [[get_nodes, get_links]]) - em_limits = Dict(CO2 => FixedProfile(1e4)) # Emission cap for CO₂ in t/year + em_limits = Dict(CO2 => FixedProfile(1e10)) # Emission cap for CO₂ in t/year em_cost = Dict(CO2 => FixedProfile(71.0)) # Emission price for CO₂ in €/t modeltype = OperationalModel(em_limits, em_cost, CO2) return case, modeltype, create_model(case, modeltype) @@ -324,14 +324,25 @@ function simple_graph_biochp(; output = nothing) BioBirchStem => 0.3, BioSpruceTB => 0.4, ) - libpath = joinpath( - pkgdir(EMLI), - "submodules", - "CHP_modelling", - "build", - "lib", - "libbioCHP_wrapper.so", - ) + libpath::String = if Sys.iswindows() + joinpath( + pkgdir(EMLI), + "submodules", + "CHP_modelling", + "build", + "Release", + "bioCHP_wrapper.dll", + ) + else + joinpath( + pkgdir(EMLI), + "submodules", + "CHP_modelling", + "build", + "lib", + "libbioCHP_wrapper.so", + ) + end if isnothing(output) bio_chp = BioCHP(