diff --git a/docs/make.jl b/docs/make.jl index df5bc13..f09693c 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -43,7 +43,7 @@ makedocs( "Philosophy"=>"manual/philosophy.md", "Optimization variables"=>"manual/optimization-variables.md", "Constraint functions"=>"manual/constraint-functions.md", - "Data functions"=>"manual/data-functions.md", + "ExtensionData functions"=>"manual/data-functions.md", "Example"=>"manual/simple-example.md", "Investment options"=>"manual/investments.md", "Release notes"=>"manual/NEWS.md", @@ -65,7 +65,7 @@ makedocs( "Library" => Any[ "Public"=>Any[ "Resources"=>"library/public/resources.md", - "Modeltype and Data"=>"library/public/model_data.md", + "Modeltype and ExtensionData"=>"library/public/model_data.md", "Nodes"=>"library/public/nodes.md", "Links"=>"library/public/links.md", "Case"=>"library/public/case_element.md", diff --git a/docs/src/how-to/create-new-node.md b/docs/src/how-to/create-new-node.md index 382ef6a..8e3f612 100644 --- a/docs/src/how-to/create-new-node.md +++ b/docs/src/how-to/create-new-node.md @@ -47,7 +47,7 @@ This is however only advised if you do not need to access the value of the varia 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 man-data_fun). + It is possible to also create new subtypes for `EmissionsData` as well as dispatch on the function [`constraints_data(m, n::Node, š’Æ, š’«, modeltype, data::ExtensionData)`](@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 respective *[constraint functions](@ref man-con)* can serve as idea generators. diff --git a/docs/src/library/internals/functions.md b/docs/src/library/internals/functions.md index d1bf6d6..a200844 100644 --- a/docs/src/library/internals/functions.md +++ b/docs/src/library/internals/functions.md @@ -16,6 +16,7 @@ CurrentModule = EnergyModelsBase create_element create_link variables_element +variables_data(m, _::Type{<:ExtensionData}, š’³::Vector{<:AbstractElement}, š’Æ, š’«, modeltype::EnergyModel) objective(m, š’³įµ›įµ‰į¶œ, š’«, š’Æ, modeltype::EnergyModel) objective_operational emissions_operational @@ -39,9 +40,10 @@ constraints_level_bounds variables_capacity variables_flow variables_opex -variables_capex(m, š’©::Vector{<:Node}, š’³įµ›įµ‰į¶œ, š’Æ, modeltype::EnergyModel) +variables_capex variables_emission variables_elements +variables_element_data ``` ## [Check functions](@id lib-int-fun-check) @@ -55,7 +57,7 @@ check_node check_link check_node_default check_node_data(n::Node, data::EmissionsData, š’Æ, modeltype::EnergyModel, check_timeprofiles::Bool) -check_link_data(n::Link, data::Data, š’Æ, modeltype::EnergyModel, check_timeprofiles::Bool) +check_link_data(n::Link, data::ExtensionData, š’Æ, modeltype::EnergyModel, check_timeprofiles::Bool) check_fixed_opex check_time_structure check_profile diff --git a/docs/src/library/internals/reference_EMIExt.md b/docs/src/library/internals/reference_EMIExt.md index 6f26719..641137c 100644 --- a/docs/src/library/internals/reference_EMIExt.md +++ b/docs/src/library/internals/reference_EMIExt.md @@ -32,7 +32,7 @@ check_inv_data ### [Methods](@id lib-int-EMIext-met) ```@docs -EMB.variables_capex(m, š’©::Vector{<:EMB.Node}, š’³įµ›įµ‰į¶œ, š’Æ, modeltype::AbstractInvestmentModel) +EMB.variables_data(m, _::Type{SingleInvData}, š’©į“µāæįµ›::Vector{<:EMB.Node}, š’Æ, š’«, modeltype::AbstractInvestmentModel) EMB.objective_invest(m, š’©::Vector{<:EMB.Node}, š’Æį“µāæįµ›::TS.AbstractStratPers, modeltype::AbstractInvestmentModel) EMB.constraints_capacity_installed(m, n::EMB.Node, š’Æ::TimeStructure, modeltype::AbstractInvestmentModel) EMB.check_node_data(n::EMB.Node, data::InvestmentData, š’Æ, modeltype::AbstractInvestmentModel, check_timeprofiles::Bool) diff --git a/docs/src/library/public/case_element.md b/docs/src/library/public/case_element.md index 02ff354..65e075e 100644 --- a/docs/src/library/public/case_element.md +++ b/docs/src/library/public/case_element.md @@ -23,6 +23,12 @@ The connections are incorporated through `Link`s which transport resources betwe AbstractElement ``` +`EnergyModelsBase` allows for the potential of extension data which can be extracted through + +```@docs +element_data +``` + ## [Case type](@id lib-pub-case-case) The case type is used as input to `EnergyModelsBase` models. diff --git a/docs/src/library/public/emi_extension.md b/docs/src/library/public/emi_extension.md index 6107f56..ef94e07 100644 --- a/docs/src/library/public/emi_extension.md +++ b/docs/src/library/public/emi_extension.md @@ -34,7 +34,7 @@ discount_rate ### [`InvestmentData` types](@id lib-pub-emi_ext-inv_data-types) -`InvestmentData` subtypes are used to provide technologies introduced in `EnergyModelsX` (nodes and transmission modes) a subtype of `Data` that can be used for dispatching. +`InvestmentData` subtypes are used to provide technologies introduced in `EnergyModelsX` (nodes and transmission modes) a subtype of `ExtensionData` that can be used for dispatching. Two different types are directly introduced, `SingleInvData` and `StorageInvData`. `SingleInvData` is providing a composite type with a single field. diff --git a/docs/src/library/public/functions.md b/docs/src/library/public/functions.md index 357ae9a..02c3b29 100644 --- a/docs/src/library/public/functions.md +++ b/docs/src/library/public/functions.md @@ -42,7 +42,7 @@ CurrentModule = EMB ``` The following functions can be used in newly developed nodes to include constraints. -See the pages *[Constraint functions](@ref man-con)* and *[Data functions](@ref man-data_fun)* for a detailed explanation on their usage. +See the pages *[Constraint functions](@ref man-con)* and *[ExtensionData functions](@ref man-data_fun)* for a detailed explanation on their usage. !!! warning The function `constraints_capacity_installed` should not be changed. diff --git a/docs/src/library/public/model_data.md b/docs/src/library/public/model_data.md index 016060a..75f0381 100644 --- a/docs/src/library/public/model_data.md +++ b/docs/src/library/public/model_data.md @@ -30,16 +30,16 @@ co2_instance ## [Additional data](@id lib-pub-mod_data-data) Emission data are used to provide the individual nodes with potential emissions. -The approach is also explained on the page *[Data functions](@ref man-data_fun)*. +The approach is also explained on the page *[ExtensionData functions](@ref man-data_fun)*. -### [`Data` and `Emission` types](@id lib-pub-mod_data-data-types) +### [`ExtensionData` and `Emission` types](@id lib-pub-mod_data-data-types) -`Data` types are introduced for introducing additional parameters, variables, and constraints to the `Node`s. -The approach of using the `data` field of `Node`s is explained on the page *[Data functions](@ref man-data_fun)*. +`ExtensionData` types are introduced for introducing additional parameters, variables, and constraints to the `Node`s. +The approach of using the `data` field of `Node`s is explained on the page *[ExtensionData functions](@ref man-data_fun)*. `EmptyData` is no longer relevant for the modelling, but it is retained for avoiding any problems with existing models. ```@docs -Data +ExtensionData EmptyData ``` diff --git a/docs/src/manual/data-functions.md b/docs/src/manual/data-functions.md index 9090b78..651493f 100644 --- a/docs/src/manual/data-functions.md +++ b/docs/src/manual/data-functions.md @@ -1,7 +1,7 @@ -# [Data functions](@id man-data_fun) +# [ExtensionData functions](@id man-data_fun) -The package provides the wildcard [`Data`](@ref) type as outlined in the *[Extensions to the model](@ref man-phil-ext)* section of the philosophy page. -`Data` can be utilized to extend the functionality of the model through dispatching on its type. +The package provides the wildcard [`ExtensionData`](@ref) type as outlined in the *[Extensions to the model](@ref man-phil-ext)* section of the philosophy page. +`ExtensionData` can be utilized to extend the functionality of the model through dispatching on its type. The following function is included in all reference `create_node` functions, except for `Storage` types ```julia @@ -11,10 +11,10 @@ for data ∈ node_data(n) end ``` -There is always a fallback option if a `Data` is specified, but no functions are provided: +There is always a fallback option if a `ExtensionData` is specified, but no functions are provided: ```julia -constraints_data(m, n::Node, š’Æ, š’«, modeltype::EnergyModel, data::Data) = nothing +constraints_data(m, n::Node, š’Æ, š’«, modeltype::EnergyModel, data::ExtensionData) = nothing ``` Its application is best explained by the implemented functionality for emissions. diff --git a/docs/src/manual/philosophy.md b/docs/src/manual/philosophy.md index bdd2d2d..7fb3a23 100644 --- a/docs/src/manual/philosophy.md +++ b/docs/src/manual/philosophy.md @@ -73,12 +73,12 @@ This is done in the package [`EnergyModelsInvestments`](https://energymodelsx.gi It can be problematic when one also wants to use investments. In addition, care has to be taken with respect to method amibiguity when dispatching on the type `EnergyModel`. -The `Array{Data}` field provides us with flexibility with respect to providing additional data to the existing nodes. +The `Array{ExtensionData}` field provides us with flexibility with respect to providing additional data to the existing nodes. It is implemented in `EnergyModelsBase` for including emissions (both process and energy usage related). In that case, it allows for flexibility through either saying whether process (or energy related emissions) are present, or not. In addition, it allows for capturing the COā‚‚ from either the individual COā‚‚ sources (process and energy usage related), alternatively from both sources, or not at all. -The individual data types are explained in the Section *[Additional data](@ref lib-pub-mod_data-data)* in the public library as well as on *[Data functions](@ref man-data_fun)*. -In addition, it is already used in the package [`EnergyModelsInvestments`](https://energymodelsx.github.io/EnergyModelsInvestments.jl/) through the introduction of the `abstract type` `InvestmentData` as subtype of `Data`. +The individual data types are explained in the Section *[Additional data](@ref lib-pub-mod_data-data)* in the public library as well as on *[ExtensionData functions](@ref man-data_fun)*. +In addition, it is already used in the package [`EnergyModelsInvestments`](https://energymodelsx.github.io/EnergyModelsInvestments.jl/) through the introduction of the `abstract type` `InvestmentData` as subtype of `ExtensionData`. The introduction of `InvestmentData` allows providing additional parameters to individual technologies. -However, the implementation in `EnergyModelsInvestments` does not utilize the extension through the *[Data functions](@ref man-data_fun)*. +However, the implementation in `EnergyModelsInvestments` does not utilize the extension through the *[ExtensionData functions](@ref man-data_fun)*. Instead, as outlined above, it dispatches on the type `EnergyModel`. diff --git a/docs/src/nodes/availability.md b/docs/src/nodes/availability.md index da1912a..02a4d57 100644 --- a/docs/src/nodes/availability.md +++ b/docs/src/nodes/availability.md @@ -66,7 +66,7 @@ The variables of [`Availability`](@ref) nodes include: ### [Constraints](@id nodes-availability-math-con) -Availability nodes do not add by default any constraints, except for the constraints introduced in the function `create_node`(@ref). +Availability nodes do not add by default any constraints, except for the constraints introduced in the function [`create_node`](@ref). This constraint is given by: ```math diff --git a/docs/src/nodes/networknode.md b/docs/src/nodes/networknode.md index b72f501..252a5c8 100644 --- a/docs/src/nodes/networknode.md +++ b/docs/src/nodes/networknode.md @@ -28,7 +28,7 @@ The fields of a [`RefNetworkNode`](@ref) are given as: COā‚‚ cannot be directly specified, *i.e.*, you cannot specify a ratio. If you use [`CaptureData`](@ref), it is however necessary to specify COā‚‚ as output, although the ratio is not important.\ All values have to be non-negative. -- **`data::Vector{Data}`**:\ +- **`data::Vector{ExtensionData}`**:\ An entry for providing additional data to the model. In the current version, it is used for both providing `EmissionsData` and additional investment data when [`EnergyModelsInvestments`](https://energymodelsx.github.io/EnergyModelsInvestments.jl/) is used. !!! note "Constructor for RefNetworkNode" diff --git a/docs/src/nodes/sink.md b/docs/src/nodes/sink.md index c52d945..cee3aa1 100644 --- a/docs/src/nodes/sink.md +++ b/docs/src/nodes/sink.md @@ -23,7 +23,7 @@ The fields of a [`RefSink`](@ref) node are given as: - **`input::Dict{<:Resource,<:Real}`**:\ The field `input` includes [`Resource`](@ref Resource)s with their corresponding conversion factors as dictionaries.\ All values have to be non-negative. -- **`data::Vector{Data}`**:\ +- **`data::Vector{ExtensionData}`**:\ An entry for providing additional data to the model. In the current version, it is used for both providing `EmissionsData` and additional investment data when [`EnergyModelsInvestments`](https://energymodelsx.github.io/EnergyModelsInvestments.jl/) is used. !!! note "Constructor for `RefSink`" diff --git a/docs/src/nodes/source.md b/docs/src/nodes/source.md index 835b2b9..2bcb2f4 100644 --- a/docs/src/nodes/source.md +++ b/docs/src/nodes/source.md @@ -29,7 +29,7 @@ The fields of a [`RefSource`](@ref) node are given as: If you would like to use a `Source` node with COā‚‚ as output with a given ratio, it is necessary to utilize the package [`EnergyModelsCO2`](https://energymodelsx.github.io/EnergyModelsCO2.jl/). If you use [`CaptureData`](@ref), it is however necessary to specify COā‚‚ as output, although the ratio is not important.\ All values have to be non-negative. -- **`data::Vector{Data}`**:\ +- **`data::Vector{ExtensionData}`**:\ An entry for providing additional data to the model. In the current version, it is used for both providing `EmissionsData` and additional investment data when [`EnergyModelsInvestments`](https://energymodelsx.github.io/EnergyModelsInvestments.jl/) is used. When using `EmissionsData`, only process emissions can be considered, that is the types [`EmissionsProcess`](@ref) and that is the types [`EmissionsProcess`](@ref) and [`CaptureProcessEmissions`](@ref). diff --git a/docs/src/nodes/storage.md b/docs/src/nodes/storage.md index c613f07..fbda055 100644 --- a/docs/src/nodes/storage.md +++ b/docs/src/nodes/storage.md @@ -81,7 +81,7 @@ The fields of a [`RefStorage`](@ref) are given as: In the current implementation, we do not consider `output` conversion factors for the outflow from the [`RefStorage`](@ref) node. Similarly, we do not consider the `input` conversion factor of the stored resource. Instead, it is assumed that there is no loss of the stored resource in the storage. -- **`data::Vector{Data}`**:\ +- **`data::Vector{ExtensionData}`**:\ An entry for providing additional data to the model. In the current version, it is used for both providing `EmissionsData` and additional investment data when [`EnergyModelsInvestments`](https://energymodelsx.github.io/EnergyModelsInvestments.jl/) is used. !!! note "Constructor for `RefStorage`" diff --git a/ext/EMIExt/variables_capex.jl b/ext/EMIExt/variables_capex.jl index ffc8d7f..2bfbc27 100644 --- a/ext/EMIExt/variables_capex.jl +++ b/ext/EMIExt/variables_capex.jl @@ -1,6 +1,7 @@ """ - EMB.variables_capex(m, š’©::Vector{<:EMB.Node}, š’³įµ›įµ‰į¶œ, š’Æ, modeltype::AbstractInvestmentModel) - EMB.variables_capex(m, ā„’::Vector{<:Link}, š’³įµ›įµ‰į¶œ, š’Æ, modeltype::AbstractInvestmentModel) + EMB.variables_data(m, _::Type{SingleInvData}, š’©į“µāæįµ›::Vector{<:EMB.Node}, š’Æ, š’«, modeltype::AbstractInvestmentModel) + EMB.variables_data(m, _::Type{StorageInvData}, š’©į“µāæįµ›::Vector{<:EMB.Node}, š’Æ, š’«, modeltype::AbstractInvestmentModel) + EMB.variables_data(m, _::Type{SingleInvData}, š’©į“µāæįµ›::Vector{<:Link}, š’Æ, š’«, modeltype::AbstractInvestmentModel) Declaration of different capital expenditures (CAPEX) variables for the element types introduced in `EnergyModelsBase`. CAPEX variables are only introduced for elements that have @@ -37,23 +38,22 @@ user with two individual methods for both `š’©::Vector{<:EMB.Node}` and š’©::V - `**prefix**_remove_b` is an auxiliary variable used in some investment modes for the reduction of capacities. """ -function EMB.variables_capex(m, š’©::Vector{<:EMB.Node}, š’³įµ›įµ‰į¶œ, š’Æ, modeltype::AbstractInvestmentModel) - š’©į“µāæįµ› = filter(has_investment, filter(!EMB.is_storage, š’©)) - š’©Ė¢įµ—įµ’Ź³ = filter(EMB.is_storage, š’©) - š’©Ė”įµ‰įµ›įµ‰Ė” = filter(n -> has_investment(n, :level), š’©Ė¢įµ—įµ’Ź³) - š’©į¶œŹ°įµƒŹ³įµįµ‰ = filter(n -> has_investment(n, :charge), š’©Ė¢įµ—įµ’Ź³) - š’©įµˆā±Ė¢į¶œŹ°įµƒŹ³įµįµ‰ = filter(n -> has_investment(n, :discharge), š’©Ė¢įµ—įµ’Ź³) +function EMB.variables_data(m, _::Type{SingleInvData}, š’©į“µāæįµ›::Vector{<:EMB.Node}, š’Æ, š’«, modeltype::AbstractInvestmentModel) š’Æį“µāæįµ› = strategic_periods(š’Æ) - # Add investment variables for reference nodes for each strategic period: + # Add investment variables for nodes for each strategic period @variable(m, cap_capex[š’©į“µāæįµ›, š’Æį“µāæįµ›] ≄ 0) @variable(m, cap_current[š’©į“µāæįµ›, š’Æį“µāæįµ›] ≄ 0) @variable(m, cap_add[š’©į“µāæįµ›, š’Æį“µāæįµ›] ≄ 0) @variable(m, cap_rem[š’©į“µāæįµ›, š’Æį“µāæįµ›] ≄ 0) @variable(m, cap_invest_b[š’©į“µāæįµ›, š’Æį“µāæįµ›] ≄ 0; container = IndexedVarArray) @variable(m, cap_remove_b[š’©į“µāæįµ›, š’Æį“µāæįµ›] ≄ 0; container = IndexedVarArray) +end +function EMB.variables_data(m, _::Type{StorageInvData}, š’©Ė¢įµ—įµ’Ź³::Vector{<:EMB.Node}, š’Æ, š’«, modeltype::EnergyModel) + š’Æį“µāæįµ› = strategic_periods(š’Æ) - # Add storage specific investment variables for each strategic period: + # Add investment variables for storage nodes for each strategic period + š’©Ė”įµ‰įµ›įµ‰Ė” = filter(n -> has_investment(n, :level), š’©Ė¢įµ—įµ’Ź³) @variable(m, stor_level_capex[š’©Ė”įµ‰įµ›įµ‰Ė”, š’Æį“µāæįµ›] ≄ 0) @variable(m, stor_level_current[š’©Ė”įµ‰įµ›įµ‰Ė”, š’Æį“µāæįµ›] ≄ 0) @variable(m, stor_level_add[š’©Ė”įµ‰įµ›įµ‰Ė”, š’Æį“µāæįµ›] ≄ 0) @@ -61,6 +61,7 @@ function EMB.variables_capex(m, š’©::Vector{<:EMB.Node}, š’³įµ›įµ‰į¶œ, š’Æ, m @variable(m, stor_level_invest_b[š’©Ė”įµ‰įµ›įµ‰Ė”, š’Æį“µāæįµ›] ≄ 0; container = IndexedVarArray) @variable(m, stor_level_remove_b[š’©Ė”įµ‰įµ›įµ‰Ė”, š’Æį“µāæįµ›] ≄ 0; container = IndexedVarArray) + š’©į¶œŹ°įµƒŹ³įµįµ‰ = filter(n -> has_investment(n, :charge), š’©Ė¢įµ—įµ’Ź³) @variable(m, stor_charge_capex[š’©į¶œŹ°įµƒŹ³įµįµ‰, š’Æį“µāæįµ›] ≄ 0) @variable(m, stor_charge_current[š’©į¶œŹ°įµƒŹ³įµįµ‰, š’Æį“µāæįµ›] ≄ 0) @variable(m, stor_charge_add[š’©į¶œŹ°įµƒŹ³įµįµ‰, š’Æį“µāæįµ›] ≄ 0) @@ -68,6 +69,7 @@ function EMB.variables_capex(m, š’©::Vector{<:EMB.Node}, š’³įµ›įµ‰į¶œ, š’Æ, m @variable(m, stor_charge_invest_b[š’©į¶œŹ°įµƒŹ³įµįµ‰, š’Æį“µāæįµ›] ≄ 0; container = IndexedVarArray) @variable(m, stor_charge_remove_b[š’©į¶œŹ°įµƒŹ³įµįµ‰, š’Æį“µāæįµ›] ≄ 0; container = IndexedVarArray) + š’©įµˆā±Ė¢į¶œŹ°įµƒŹ³įµįµ‰ = filter(n -> has_investment(n, :discharge), š’©Ė¢įµ—įµ’Ź³) @variable(m, stor_discharge_capex[š’©įµˆā±Ė¢į¶œŹ°įµƒŹ³įµįµ‰, š’Æį“µāæįµ›] ≄ 0) @variable(m, stor_discharge_current[š’©įµˆā±Ė¢į¶œŹ°įµƒŹ³įµįµ‰, š’Æį“µāæįµ›] ≄ 0) @variable(m, stor_discharge_add[š’©įµˆā±Ė¢į¶œŹ°įµƒŹ³įµįµ‰, š’Æį“µāæįµ›] ≄ 0) @@ -83,11 +85,10 @@ function EMB.variables_capex(m, š’©::Vector{<:EMB.Node}, š’³įµ›įµ‰į¶œ, š’Æ, m container = IndexedVarArray ) end -function EMB.variables_capex(m, ā„’::Vector{<:Link}, š’³įµ›įµ‰į¶œ, š’Æ, modeltype::AbstractInvestmentModel) - ℒᓵⁿᵛ = filter(has_investment, ā„’) +function EMB.variables_data(m, _::Type{SingleInvData}, ℒᓵⁿᵛ::Vector{<:Link}, š’Æ, š’«, modeltype::EnergyModel) š’Æį“µāæįµ› = strategic_periods(š’Æ) - # Add investment variables for reference nodes for each strategic period: + # Add investment variables for links for each strategic period @variable(m, link_cap_capex[ℒᓵⁿᵛ, š’Æį“µāæįµ›] ≄ 0) @variable(m, link_cap_current[ℒᓵⁿᵛ, š’Æį“µāæįµ›] ≄ 0) @variable(m, link_cap_add[ℒᓵⁿᵛ, š’Æį“µāæįµ›] ≄ 0) diff --git a/src/EnergyModelsBase.jl b/src/EnergyModelsBase.jl index 8434746..6f53ebe 100644 --- a/src/EnergyModelsBase.jl +++ b/src/EnergyModelsBase.jl @@ -6,7 +6,7 @@ In addition, all required functions for creaeting and running the model are expo You can find the exported types and functions below or on the pages *[Constraint functions](@ref man-con)* and -*[Data functions](@ref man-data_fun)*. +*[ExtensionData functions](@ref man-data_fun)*. """ module EnergyModelsBase @@ -41,7 +41,7 @@ export get_time_struct, get_products, get_elements_vec, get_nodes, get_links, ge # Export the general classes export EnergyModel, OperationalModel export Resource, ResourceCarrier, ResourceEmit -export AbstractElement +export AbstractElement, element_data # Export the different node types export Source, NetworkNode, Sink, Storage, Availability @@ -58,7 +58,7 @@ export Cyclic, CyclicRepresentative, CyclicStrategic export StorCapOpex, StorCap, StorCapOpexVar, StorCapOpexFixed, StorOpexVar # Export the data types -export Data, EmptyData, EmissionsData, CaptureData +export Data, ExtensionData, EmptyData, EmissionsData, CaptureData export CaptureProcessEnergyEmissions, CaptureProcessEmissions, CaptureEnergyEmissions export EmissionsProcess, EmissionsEnergy diff --git a/src/checks.jl b/src/checks.jl index b2a1808..8607588 100644 --- a/src/checks.jl +++ b/src/checks.jl @@ -170,7 +170,7 @@ and Vector{<:Link}. !!! note "Node methods" All nodes are checked through the functions - [`check_node`](@ref) to identify problematic input, - - [`check_node_data`](@ref EnergyModelsBase.check_node_data(n::Node, data::Data, š’Æ, modeltype::EnergyModel, check_timeprofiles::Bool)) + - [`check_node_data`](@ref EnergyModelsBase.check_node_data(n::Node, data::ExtensionData, š’Æ, modeltype::EnergyModel, check_timeprofiles::Bool)) issues in the provided additional data, and - [`check_time_structure`](@ref) to identify time profiles at the highest level that are not equivalent to the provided timestructure. @@ -178,7 +178,7 @@ and Vector{<:Link}. !!! note "Links methods" All links are checked through the functions - [`check_link`](@ref) to identify problematic input, - - [`check_link_data`](@ref EnergyModelsBase.check_link_data(l::Link, data::Data, š’Æ, modeltype::EnergyModel, check_timeprofiles::Bool)) + - [`check_link_data`](@ref EnergyModelsBase.check_link_data(l::Link, data::ExtensionData, š’Æ, modeltype::EnergyModel, check_timeprofiles::Bool)) to identify issues in the provided additional data, and - [`check_time_structure`](@ref) to identify time profiles at the highest level that are not equivalent to the provided timestructure. @@ -910,10 +910,10 @@ function check_fixed_opex(n, š’Æį“µāæįµ›, check_timeprofiles::Bool) end """ - check_node_data(n::Node, data::Data, š’Æ, modeltype::EnergyModel, check_timeprofiles::Bool) + check_node_data(n::Node, data::ExtensionData, š’Æ, modeltype::EnergyModel, check_timeprofiles::Bool) check_node_data(n::Node, data::EmissionsData, š’Æ, modeltype::EnergyModel, check_timeprofiles::Bool) -Check that the included `Data` types of a `Node` correspond to required structure. +Check that the included `ExtensionData` types of a `Node` correspond to required structure. ## Checks `EmissionsData` - Each node can only have a single `EmissionsData`. @@ -921,7 +921,7 @@ Check that the included `Data` types of a `Node` correspond to required structur - The value of the field `co2_capture` is required to be in the range ``[0, 1]``, if [`CaptureData`](@ref) is used. """ -check_node_data(n::Node, data::Data, š’Æ, modeltype::EnergyModel, check_timeprofiles::Bool) = +check_node_data(n::Node, data::ExtensionData, š’Æ, modeltype::EnergyModel, check_timeprofiles::Bool) = nothing function check_node_data( n::Node, @@ -988,9 +988,9 @@ functionality does not check anthing, aside from the checks performed in [`check check_link(n::Link, š’Æ, modeltype::EnergyModel, check_timeprofiles::Bool) = nothing """ - check_link_data(l::Link, data::Data, š’Æ, modeltype::EnergyModel, check_timeprofiles::Bool) + check_link_data(l::Link, data::ExtensionData, š’Æ, modeltype::EnergyModel, check_timeprofiles::Bool) -Check that the included `Data` types of a `Link` correspond to required structure. +Check that the included `ExtensionData` types of a `Link` correspond to required structure. """ -check_link_data(l::Link, data::Data, š’Æ, modeltype::EnergyModel, check_timeprofiles::Bool) = +check_link_data(l::Link, data::ExtensionData, š’Æ, modeltype::EnergyModel, check_timeprofiles::Bool) = nothing diff --git a/src/data_functions.jl b/src/data_functions.jl index 21ab1dc..358f218 100644 --- a/src/data_functions.jl +++ b/src/data_functions.jl @@ -162,10 +162,10 @@ function constraints_data( end """ - constraints_data(m, n::Node, š’Æ, š’«, modeltype::EnergyModel, data::Data) + constraints_data(m, n::Node, š’Æ, š’«, modeltype::EnergyModel, data::ExtensionData) Fallback option when data is specified, but it is not desired to add the constraints through this function. This is, *e.g.*, the case for `EnergyModelsInvestments` as the capacity constraint has to be replaced. """ -constraints_data(m, n::Node, š’Æ, š’«, modeltype::EnergyModel, data::Data) = nothing +constraints_data(m, n::Node, š’Æ, š’«, modeltype::EnergyModel, data::ExtensionData) = nothing diff --git a/src/legacy_constructor.jl b/src/legacy_constructor.jl index e48c4ba..09861a9 100644 --- a/src/legacy_constructor.jl +++ b/src/legacy_constructor.jl @@ -86,7 +86,7 @@ function RefStorage( stor_res, input, output, - Data[], + ExtensionData[], ) return tmp end @@ -181,7 +181,7 @@ function RefStorage( stor_res, input, output, - Data[], + ExtensionData[], ) return tmp end diff --git a/src/model.jl b/src/model.jl index e5701bc..849db70 100644 --- a/src/model.jl +++ b/src/model.jl @@ -51,7 +51,7 @@ function create_model( ) end - # WIP Data structure + # Extract the information from the `Case` š’Æ = get_time_struct(case) š’« = get_products(case) š’³įµ›įµ‰į¶œ = get_elements_vec(case) @@ -65,6 +65,7 @@ function create_model( variables_capex(m, š’³, š’³įµ›įµ‰į¶œ, š’Æ, modeltype) variables_emission(m, š’³, š’³įµ›įµ‰į¶œ, š’«, š’Æ, modeltype) variables_elements(m, š’³, š’³įµ›įµ‰į¶œ, š’Æ, modeltype) + variables_element_data(m, š’³, š’³įµ›įµ‰į¶œ, š’Æ, š’«, modeltype) constraints_elements(m, š’³, š’³įµ›įµ‰į¶œ, š’«, š’Æ, modeltype) end @@ -424,6 +425,58 @@ function variables_elements(m, š’³::Vector{<:AbstractElement}, š’³įµ›įµ‰į¶œ, end end +""" + variables_element_data(m, š’³::Vector{<:AbstractElement}, š’³įµ›įµ‰į¶œ, š’Æ, š’«,modeltype::EnergyModel) + +Loop through all data subtypes and create variables specific to each subtype. It starts +at the top level and subsequently move through the branches until it reaches a leave. + +The function subsequently calls the subroutine [`variables_data`](@ref) for creating the +variables for the nodes that have the corresponding data types. +""" +function variables_element_data( + m, + š’³::Vector{<:AbstractElement}, + š’³įµ›įµ‰į¶œ, + š’Æ, + š’«, + modeltype::EnergyModel +) + # Extract all ExtensionData types within all elements + š’Ÿ = reduce(vcat, [element_data(x) for x ∈ š’³]) + + # Skip if no data is added to the individual elements + isempty(š’Ÿ) && return + + # Vector of the unique data types in š’Ÿ. + data_composite_types = unique(typeof.(š’Ÿ)) + # Get all `ExtensionData`-types in the type-hierarchy that the nodes š’Ÿ represents. + data_types = collect_types(data_composite_types) + # Sort the `ExtensionData`-types such that a supertype will always come before its subtypes. + data_types = sort_types(data_types) + + for data_type ∈ data_types + # All elements with the given data sub type. + š’³įµˆįµƒįµ— = filter(x -> any(isa.(element_data(x), data_type)), š’³) + try + variables_data(m, data_type, š’³įµˆįµƒįµ—, š’Æ, š’«, modeltype) + catch e + # Parts of the exception message we are looking for + pre1 = "An object of name" + pre2 = "is already attached to this model." + if isa(e, ErrorException) + if occursin(pre1, e.msg) && occursin(pre2, e.msg) + # data_type was already registered by a call to a supertype, so just continue. + continue + end + end + # If we make it to this point, this means some other error occured. + # This should not be ignored. + throw(e) + end + end +end + """ variables_element(m, š’©Ė¢įµ˜įµ‡::Vector{<:Node}, š’Æ, modeltype::EnergyModel) variables_element(m, ā„’Ė¢įµ˜įµ‡::Vector{<:Link}, š’Æ, modeltype::EnergyModel) @@ -443,6 +496,20 @@ variables_element(m, š’©Ė¢įµ˜įµ‡::Vector{<:Node}, š’Æ, modeltype::EnergyModel) variables_element(m, ā„’Ė¢įµ˜įµ‡::Vector{<:Link}, š’Æ, modeltype::EnergyModel) = variables_link(m, ā„’Ė¢įµ˜įµ‡, š’Æ, modeltype) +""" + variables_data(m, _::Type{<:ExtensionData}, š’³::Vector{<:AbstractElement}, š’Æ, š’«, modeltype::EnergyModel) + +Default fallback method for the variables creation for a data type of a `Vector{<:AbstractElement}` +`š’³` if no other method is defined. The default method does not specify any variables. + +!!! warning + The function is called for each individual subtype of [`AbstractElement`](@ref). As a + consequence, methods, and hence, variables for [`Node`](@ref)s and [`Link`](@ref)s must + be specified specifically. +""" +function variables_data(m, _::Type{<:ExtensionData}, š’³::Vector{<:AbstractElement}, š’Æ, š’«, modeltype::EnergyModel) +end + """ variables_node(m, š’©Ė¢įµ˜įµ‡::Vector{<:Node}, š’Æ, modeltype::EnergyModel) diff --git a/src/structures/data.jl b/src/structures/data.jl index 7370bc0..e69fd38 100644 --- a/src/structures/data.jl +++ b/src/structures/data.jl @@ -1,11 +1,17 @@ -""" Abstract type used to define concrete struct containing the package specific elements -to add to the composite type defined in this package.""" -abstract type Data end -""" Empty composite type for `Data`""" -struct EmptyData <: Data end +""" + abstract type ExtensionData + +Abstract type used to define concrete struct containing the package specific elements +to add to the composite type defined in this package. +""" +abstract type ExtensionData end +Data = ExtensionData + +""" Empty composite type for `ExtensionData`""" +struct EmptyData <: ExtensionData end """ - EmissionsData{T<:Union{TimeProfile,Float64}} <: Data + EmissionsData{T<:Union{TimeProfile,Float64}} <: ExtensionData Abstract type for `EmissionsData` can be used to dispatch on different types of capture configurations. @@ -27,7 +33,7 @@ In general, the different types require the following input: - **[`EmissionsEnergy`](@ref)**: No capture and no process emissions. Does not require `co2_capture` or `emissions` as input, but will ignore them, if provided. """ -abstract type EmissionsData{T<:Union{TimeProfile,Float64}} <: Data end +abstract type EmissionsData{T<:Union{TimeProfile,Float64}} <: ExtensionData end """ CaptureData{T} <: EmissionsData{T} @@ -166,11 +172,11 @@ process_emissions(data::EmissionsEnergy{T}, p::ResourceEmit, t) where {T} = the function `process_emissions`.") """ - InvestmentData <: Data + InvestmentData <: ExtensionData Abstract type for the extra data for investing in technologies. """ -abstract type InvestmentData <: Data end +abstract type InvestmentData <: ExtensionData end """ StorageInvData <: InvestmentData diff --git a/src/structures/element.jl b/src/structures/element.jl index 4849440..36a7b79 100644 --- a/src/structures/element.jl +++ b/src/structures/element.jl @@ -14,3 +14,16 @@ an energy system. and constraints. """ abstract type AbstractElement end + + +""" + element_data(x::AbstractElement) + +Returns the [`ExtensionData`](@ref) array of [`AbstractElement`](@ref) `x`. The function requires the +specification of a new method for each `AbstractElement`. + +It is implemented in `EnergyModelsBase` for +- [`Node`](@ref) calling the subfunction [`node_data`](@ref) and +- [`Link`](@ref) calling the subfunction [`link_data`](@ref). +""" +element_data(x::AbstractElement) = ExtensionData[] diff --git a/src/structures/link.jl b/src/structures/link.jl index 778b644..2e92591 100644 --- a/src/structures/link.jl +++ b/src/structures/link.jl @@ -124,8 +124,9 @@ formulation(l::Link) = l.formulation """ link_data(l::Link) -Returns the [`Data`](@ref) array of link `l`. +Returns the [`ExtensionData`](@ref) array of link `l`. -The default options returns an empty `Data` vector. +The default options returns an empty `ExtensionData` vector. """ -link_data(l::Link) = Data[] +link_data(l::Link) = ExtensionData[] +element_data(l::Link) = link_data(l) diff --git a/src/structures/node.jl b/src/structures/node.jl index 50821f2..c76a5ca 100644 --- a/src/structures/node.jl +++ b/src/structures/node.jl @@ -97,7 +97,8 @@ end struct StorCap <: AbstractStorageParameters A storage parameter type for including only a capacity. This implies that neither the usage -of the [`Storage`](@ref), nor the installed capacity have a direct impact on the objective function. +of the [`Storage`](@ref), nor the installed capacity have a direct impact on the objective +function. # Fields - **`capacity::TimeProfile`** is the installed capacity. @@ -225,8 +226,8 @@ or `StrategicProfile`. through the variable `:cap_inst`. - **`output::Dict{<:Resource,<:Real}`** are the generated [`Resource`](@ref)s with conversion value `Real`. -- **`data::Vector{<:Data}`** is the additional data (*e.g.*, for investments). The field `data` - is conditional through usage of a constructor. +- **`data::Vector{<:ExtensionData}`** is the additional data (*e.g.*, for investments). + The field `data` is conditional through usage of a constructor. """ struct RefSource <: Source id::Any @@ -234,7 +235,7 @@ struct RefSource <: Source opex_var::TimeProfile opex_fixed::TimeProfile output::Dict{<:Resource,<:Real} - data::Vector{<:Data} + data::Vector{<:ExtensionData} end function RefSource( id, @@ -243,7 +244,7 @@ function RefSource( opex_fixed::TimeProfile, output::Dict{<:Resource,<:Real}, ) - return RefSource(id, cap, opex_var, opex_fixed, output, Data[]) + return RefSource(id, cap, opex_var, opex_fixed, output, ExtensionData[]) end """ @@ -266,8 +267,8 @@ The capacity is hereby normalized to a conversion value of 1 in the fields `inpu value `Real`. - **`output::Dict{<:Resource,<:Real}`** are the generated [`Resource`](@ref)s with conversion value `Real`. -- **`data::Vector{Data}`** is the additional data (*e.g.*, for investments). The field `data` - is conditional through usage of a constructor. +- **`data::Vector{ExtensionData}`** is the additional data (*e.g.*, for investments). + The field `data` is conditional through usage of a constructor. """ struct RefNetworkNode <: NetworkNode id::Any @@ -276,7 +277,7 @@ struct RefNetworkNode <: NetworkNode opex_fixed::TimeProfile input::Dict{<:Resource,<:Real} output::Dict{<:Resource,<:Real} - data::Vector{<:Data} + data::Vector{<:ExtensionData} end function RefNetworkNode( id, @@ -286,7 +287,7 @@ function RefNetworkNode( input::Dict{<:Resource,<:Real}, output::Dict{<:Resource,<:Real}, ) - return RefNetworkNode(id, cap, opex_var, opex_fixed, input, output, Data[]) + return RefNetworkNode(id, cap, opex_var, opex_fixed, input, output, ExtensionData[]) end """ @@ -338,8 +339,8 @@ The current implemented cyclic behaviours are [`CyclicRepresentative`](@ref), - **`output::Dict{<:Resource,<:Real}`** are the generated [`Resource`](@ref)s with conversion value `Real`. Only relevant for linking and the stored [`Resource`](@ref) as the output value is not utilized in the calculations. -- **`data::Vector{<:Data}`** is the additional data (*e.g.*, for investments). The field `data` - is conditional through usage of a constructor. +- **`data::Vector{<:ExtensionData}`** is the additional data (*e.g.*, for investments). + The field `data` is conditional through usage of a constructor. """ struct RefStorage{T} <: Storage{T} id::Any @@ -348,7 +349,7 @@ struct RefStorage{T} <: Storage{T} stor_res::Resource input::Dict{<:Resource,<:Real} output::Dict{<:Resource,<:Real} - data::Vector{<:Data} + data::Vector{<:ExtensionData} end function RefStorage{T}( @@ -359,7 +360,7 @@ function RefStorage{T}( input::Dict{<:Resource,<:Real}, output::Dict{<:Resource,<:Real}, ) where {T<:StorageBehavior} - return RefStorage{T}(id, charge, level, stor_res, input, output, Data[]) + return RefStorage{T}(id, charge, level, stor_res, input, output, ExtensionData[]) end """ @@ -376,15 +377,15 @@ and deficit. dictionary requires the fields `:surplus` and `:deficit`. - **`input::Dict{<:Resource,<:Real}`** are the input [`Resource`](@ref)s with conversion value `Real`. -- **`data::Vector{<:Data}`** is the additional data (*e.g.*, for investments). The field `data` - is conditional through usage of a constructor. +- **`data::Vector{<:ExtensionData}`** is the additional data (*e.g.*, for investments). + The field `data` is conditional through usage of a constructor. """ struct RefSink <: Sink id::Any cap::TimeProfile penalty::Dict{Symbol,<:TimeProfile} input::Dict{<:Resource,<:Real} - data::Vector{<:Data} + data::Vector{<:ExtensionData} end function RefSink( id, @@ -392,7 +393,7 @@ function RefSink( penalty::Dict{<:Any,<:TimeProfile}, input::Dict{<:Resource,<:Real}, ) - return RefSink(id, cap, penalty, input, Data[]) + return RefSink(id, cap, penalty, input, ExtensionData[]) end """ @@ -681,10 +682,11 @@ outputs(n::Sink, p::Resource) = nothing """ node_data(n::Node) -Returns the [`Data`](@ref) array of node `n`. +Returns the [`ExtensionData`](@ref) array of node `n`. """ node_data(n::Node) = n.data -node_data(n::Availability) = [] +node_data(n::Availability) = ExtensionData[] +element_data(n::Node) = node_data(n) """ storage_resource(n::Storage) diff --git a/test/runtests.jl b/test/runtests.jl index 680188e..e259ebf 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -15,6 +15,10 @@ ENV["EMB_TEST"] = true # Set flag for example scripts to check if they are run a include("test_general.jl") end + @testset "Base | ExtensionData" begin + include("test_data.jl") + end + @testset "Base | Node" begin include("test_nodes.jl") end diff --git a/test/test_data.jl b/test/test_data.jl new file mode 100644 index 0000000..78e6baf --- /dev/null +++ b/test/test_data.jl @@ -0,0 +1,160 @@ +@testset "Variable creation" begin + # New data type including 2 subtypes + abstract type ExampleData <: ExtensionData end + struct ExampleDataA <: ExampleData + end + struct ExampleDataB <: ExampleData + end + + # Creation of a data link type with associated OPEX + struct DataDirect <: Link + id::Any + from::EMB.Node + to::EMB.Node + formulation::EMB.Formulation + data::Vector{<:ExtensionData} + end + + EMB.element_data(l::DataDirect) = l.data + + # Subfunctions for the nodes + function EMB.variables_data(m, _::Type{<:ExampleData}, š’³įµˆįµƒįµ—::Vector{<:EMB.Node}, š’Æ, š’«, modeltype::EnergyModel) + @variable(m, node_example[š’³įµˆįµƒįµ—, š’Æ] ≄ 0) + end + function EMB.variables_data(m, _::Type{ExampleDataB}, š’³įµˆįµƒįµ—::Vector{<:EMB.Node}, š’Æ, š’«, modeltype::EnergyModel) + @variable(m, node_example_b[š’³įµˆįµƒįµ—, š’Æ] ≄ 0) + end + + # Subfunctions for the link + function EMB.variables_data(m, _::Type{<:ExampleDataA}, š’³įµˆįµƒįµ—::Vector{<:Link}, š’Æ, š’«, modeltype::EnergyModel) + @variable(m, link_example_a[š’³įµˆįµƒįµ—, š’Æ] ≄ 0) + end + function EMB.variables_data(m, _::Type{<:ExampleDataB}, š’³įµˆįµƒįµ—::Vector{<:Link}, š’Æ, š’«, modeltype::EnergyModel) + @variable(m, link_example_b[š’³įµˆįµƒįµ—, š’Æ] ≄ 0) + end + function EMB.create_link(m, l::DataDirect, š’Æ, š’«, modeltype::EnergyModel) + # Generic link in which each output corresponds to the input + @constraint(m, [t ∈ š’Æ, p ∈ EMB.link_res(l)], + m[:link_out][l, t, p] == m[:link_in][l, t, p] + ) + end + + # Resources used in the analysis + NG = ResourceEmit("NG", 0.2) + Coal = ResourceCarrier("Coal", 0.35) + Power = ResourceCarrier("Power", 0.0) + CO2 = ResourceEmit("CO2", 1.0) + + # Function for setting up the system + function simple_graph() + # Define the different resources + NG = ResourceEmit("NG", 0.2) + Coal = ResourceCarrier("Coal", 0.35) + Power = ResourceCarrier("Power", 0.0) + CO2 = ResourceEmit("CO2", 1.0) + products = [NG, Coal, Power, CO2] + + # Creation of the emission data for the individual nodes. + capture_data = CaptureEnergyEmissions(0.9) + emission_data = EmissionsEnergy() + + # Create the individual test nodes, corresponding to a system with an electricity demand/sink, + # coal and nautral gas sources, coal and natural gas (with CCS) power plants and CO2 storage. + nodes = [ + GenAvailability(1, products), + RefSource(2, FixedProfile(1e12), FixedProfile(30), FixedProfile(0), Dict(NG => 1), ExtensionData[ExampleDataA()]), + RefSource(3, FixedProfile(1e12), FixedProfile(9), FixedProfile(0), Dict(Coal => 1), ExtensionData[ExampleDataB()]), + RefNetworkNode( + 4, + FixedProfile(25), + FixedProfile(5.5), + FixedProfile(5), + Dict(NG => 2), + Dict(Power => 1, CO2 => 1), + [capture_data, ExampleDataA()], + ), + RefNetworkNode( + 5, + FixedProfile(25), + FixedProfile(6), + FixedProfile(10), + Dict(Coal => 2.5), + Dict(Power => 1), + [emission_data, ExampleDataB()], + ), + RefStorage{AccumulatingEmissions}( + 6, + StorCapOpex(FixedProfile(60), FixedProfile(9.1), FixedProfile(0)), + StorCap(FixedProfile(600)), + CO2, + Dict(CO2 => 1, Power => 0.02), + Dict(CO2 => 1), + ExtensionData[ExampleDataB()], + ), + RefSink( + 7, + OperationalProfile([20, 30, 40, 30]), + Dict(:surplus => FixedProfile(0), :deficit => FixedProfile(1e6)), + Dict(Power => 1), + ), + ] + + # Connect all nodes with the availability node for the overall energy/mass balance + links = [ + DataDirect(14, nodes[1], nodes[4], Linear(), ExtensionData[ExampleDataA()]) + Direct(15, nodes[1], nodes[5], Linear()) + Direct(16, nodes[1], nodes[6], Linear()) + Direct(17, nodes[1], nodes[7], Linear()) + Direct(21, nodes[2], nodes[1], Linear()) + DataDirect(31, nodes[3], nodes[1], Linear(), ExtensionData[ExampleDataB()]) + Direct(41, nodes[4], nodes[1], Linear()) + Direct(51, nodes[5], nodes[1], Linear()) + Direct(61, nodes[6], nodes[1], Linear()) + ] + + # Creation of the time structure and global data + T = TwoLevel(4, 2, SimpleTimes(4, 2), op_per_strat = 8) + model = OperationalModel( + Dict(CO2 => StrategicProfile([160, 140, 120, 100]), NG => FixedProfile(1e6)), + Dict(CO2 => FixedProfile(0)), + CO2, + ) + + # Input data structure + case = Case(T, products, [nodes, links], [[get_nodes, get_links]]) + return case, model + end + + # Create the case and the model + case, model = simple_graph() + m = create_model(case, model) + + # Extract data from the case + š’© = get_nodes(case) + ā„’ = get_links(case) + š’Æ = get_time_struct(case) + + @testset "Node data" begin + # Test that the variables_data function for the abstract type is included for all subtypes + @test haskey(m, :node_example) + @test sum(nt[1] == š’©[2] for nt ∈ keys(m[:node_example])) == length(š’Æ) + @test sum(nt[1] == š’©[3] for nt ∈ keys(m[:node_example])) == length(š’Æ) + @test sum(nt[1] == š’©[4] for nt ∈ keys(m[:node_example])) == length(š’Æ) + @test sum(nt[1] == š’©[6] for nt ∈ keys(m[:node_example])) == length(š’Æ) + + # Test that the variables_data for the concrete type is included + @test haskey(m, :node_example_b) + @test sum(nt[1] == š’©[3] for nt ∈ keys(m[:node_example_b])) == length(š’Æ) + @test sum(nt[1] == š’©[5] for nt ∈ keys(m[:node_example_b])) == length(š’Æ) + @test sum(nt[1] == š’©[6] for nt ∈ keys(m[:node_example_b])) == length(š’Æ) + end + + + @testset "Link data" begin + @test haskey(m, :link_example_a) + @test sum(nt[1] == ā„’[1] for nt ∈ keys(m[:link_example_a])) == length(š’Æ) + + @test haskey(m, :link_example_b) + @test sum(nt[1] == ā„’[6] for nt ∈ keys(m[:link_example_b])) == length(š’Æ) + end +end diff --git a/test/test_investments.jl b/test/test_investments.jl index f951399..39b0259 100644 --- a/test/test_investments.jl +++ b/test/test_investments.jl @@ -260,7 +260,7 @@ end from::EMB.Node to::EMB.Node formulation::EMB.Formulation - data::Vector{<:Data} + data::Vector{<:ExtensionData} end function EMB.create_link(m, š’Æ, š’«, l::InvDirect, modeltype::EnergyModel, formulation::EMB.Formulation) @@ -305,7 +305,7 @@ end Dict(Power => 1), ) - data_link = Data[ + data_link = ExtensionData[ SingleInvData( FixedProfile(10), FixedProfile(10), diff --git a/test/test_links.jl b/test/test_links.jl index ce5fcc6..c450008 100644 --- a/test/test_links.jl +++ b/test/test_links.jl @@ -22,7 +22,7 @@ FixedProfile(0), Dict(NG => 2), Dict(Power => 1), - Data[EmissionsEnergy()], + ExtensionData[EmissionsEnergy()], ) sink = RefSink( diff --git a/test/test_nodes.jl b/test/test_nodes.jl index 25fefb2..e67a070 100644 --- a/test/test_nodes.jl +++ b/test/test_nodes.jl @@ -398,8 +398,8 @@ end data_source = [EmissionsProcess(Dict(CO2 => 0.5))] else output = Dict(Power => 1) - data_net = Vector{Data}([]) - data_source = Vector{Data}([]) + data_net = Vector{ExtensionData}([]) + data_source = Vector{ExtensionData}([]) end # Used source, network, and sink