diff --git a/docs/Project.toml b/docs/Project.toml index 47a02ccab4..0b2f5ebc2d 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -2,4 +2,3 @@ DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" GenX = "5d317b1e-30ec-4ed6-a8ce-8d2d88d7cfac" -Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" diff --git a/docs/make.jl b/docs/make.jl index de4e671283..8d7bf83088 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -8,10 +8,10 @@ genx_docpath = joinpath(pwd(), "docs/src") push!(LOAD_PATH, genx_docpath) pages = OrderedDict( "Welcome Page" => [ - "GenX: Introduction" => "Welcome_Page/index.md", - "Installation Guide" => "Welcome_Page/installation.md", - "Limitation of GenX" => "Welcome_Page/limitations_genx.md", - "Third Party Extensions" => "Welcome_Page/third_party_genx.md" + "GenX: Introduction" => "index.md", + "Installation Guide" => "installation.md", + "Limitation of GenX" => "limitations_genx.md", + "Third Party Extensions" => "third_party_genx.md" ], "Getting Started" => [ "Running GenX" => "Getting_Started/examples_casestudies.md", @@ -67,7 +67,7 @@ pages = OrderedDict( ], "Hydrogen Electrolyzers" => "Model_Reference/Resources/electrolyzers.md", "Retrofit" => "Model_Reference/Resources/retrofit.md", - "Resources API" => "Model_Reference/Resources/resources.md", + # "Resources API" => "Model_Reference/Resources/resources.md", "Scheduled maintenance for various resources" => "Model_Reference/Resources/maintenance.md", "Resource types" => "Model_Reference/Resources/resource.md" ], @@ -103,7 +103,7 @@ makedocs(; collapselevel=1 ), pages=[p for p in pages], - warnonly=true + # warnonly=true ) # deploydocs(; diff --git a/docs/src/Model_Concept_Overview/model_introduction.md b/docs/src/Model_Concept_Overview/model_introduction.md index 896b22ff65..3e415399d8 100644 --- a/docs/src/Model_Concept_Overview/model_introduction.md +++ b/docs/src/Model_Concept_Overview/model_introduction.md @@ -29,7 +29,7 @@ Finally, the model is usually configured to consider a full year of operating de With appropriate configuration of the model, GenX thus allows the user to tractably consider several interlinking decision layers in a single, monolithic optimization problem that would otherwise have been necessary to solve in different separated stages or models. The following figure reflects the range of configurations currently possible along the three key dimensions of chronological detail, operational detail, and network detail. -![Range of configurations currently implemented in GenX along three key dimensions of model resolution](assets/Dimensions_graphic3_background.png) +![Range of configurations currently implemented in GenX along three key dimensions of model resolution](../assets/Dimensions_graphic3_background.png) *Figure. Range of configurations currently implemented in GenX along three key dimensions of model resolution* The model can be configured to consider a single future planning year or multiple planning stages (or investment periods) in sequence. diff --git a/docs/src/Model_Reference/Resources/resources.md b/docs/src/Model_Reference/Resources/resources.md deleted file mode 100644 index 921c36134e..0000000000 --- a/docs/src/Model_Reference/Resources/resources.md +++ /dev/null @@ -1,9 +0,0 @@ -# Resources API -_Added in v0.4_ - -```@docs -GenX.check_resource_type_flags -GenX.check_longdurationstorage_applicability -GenX.check_maintenance_applicability -GenX.check_resource -``` \ No newline at end of file diff --git a/docs/src/Model_Reference/Resources/thermal.md b/docs/src/Model_Reference/Resources/thermal.md index 9e47c297f5..0910d6d100 100644 --- a/docs/src/Model_Reference/Resources/thermal.md +++ b/docs/src/Model_Reference/Resources/thermal.md @@ -1,5 +1,5 @@ # Thermal ```@autodocs Modules = [GenX] -Pages = ["thermal.jl"] +Pages = ["thermal.jl", "effective_capacity.jl"] ``` \ No newline at end of file diff --git a/docs/src/Public_API/write_outputs.md b/docs/src/Public_API/write_outputs.md index 06f9789514..84a5d24411 100644 --- a/docs/src/Public_API/write_outputs.md +++ b/docs/src/Public_API/write_outputs.md @@ -38,6 +38,12 @@ Modules = [GenX] Pages = ["write_capacity.jl"] ``` +## Write Capacity Value # TODO: add it +```@autodocs +Modules = [GenX] +Pages = ["write_capacity_value.jl"] +``` + ## Write Capacity Factors ```@autodocs Modules = [GenX] diff --git a/docs/src/User_Guide/model_input.md b/docs/src/User_Guide/model_input.md index b34d4ae77b..c833735d59 100644 --- a/docs/src/User_Guide/model_input.md +++ b/docs/src/User_Guide/model_input.md @@ -720,13 +720,13 @@ This file contains the settings parameters required to run the Method of Morris |policy| Name of the policy| !!! note "Notes" -1. Upper and lower bounds are specified in terms of percentage deviation from the nominal value. -2. Percentage variation for uncertain parameters in a given group is identical. For example, if solar cluster 1 and solar cluster 2 both belong to the ‘solar’ group, their Lower_bound and Upper_bound must be identical -3. P\_steps should at least be = 1\%, i.e., Upper\_bound – Lower\_bound $<$ p\_steps -4. P\_steps for parameters in one group must be identical -5. Total\_num\_trajectory should be around 3 to 4 times the total number of uncertain parameters -6. num\_trajectory should be approximately equal to the total number of uncertain parameters -7. len\_design_mat should be 1.5 to 2 times the total number of uncertain parameters -8. Higher number of num\_trajectory and len_design_mat would lead to higher accuracy -9. Upper and lower bounds should be specified for all the resources included in the resource `.csv` file (inside the `Resource`). If a parameter related to a particular resource is not uncertain, specify upper bound = lower bound = 0. + 1. Upper and lower bounds are specified in terms of percentage deviation from the nominal value. + 2. Percentage variation for uncertain parameters in a given group is identical. For example, if solar cluster 1 and solar cluster 2 both belong to the ‘solar’ group, their Lower_bound and Upper_bound must be identical + 3. P\_steps should at least be = 1\%, i.e., Upper\_bound – Lower\_bound $<$ p\_steps + 4. P\_steps for parameters in one group must be identical + 5. Total\_num\_trajectory should be around 3 to 4 times the total number of uncertain parameters + 6. num\_trajectory should be approximately equal to the total number of uncertain parameters + 7. len\_design_mat should be 1.5 to 2 times the total number of uncertain parameters + 8. Higher number of num\_trajectory and len_design_mat would lead to higher accuracy + 9. Upper and lower bounds should be specified for all the resources included in the resource `.csv` file (inside the `Resource`). If a parameter related to a particular resource is not uncertain, specify upper bound = lower bound = 0. diff --git a/docs/src/User_Guide/workflow.md b/docs/src/User_Guide/workflow.md index decb46bf13..96844500c1 100644 --- a/docs/src/User_Guide/workflow.md +++ b/docs/src/User_Guide/workflow.md @@ -29,63 +29,63 @@ The next sections in this guide provide more details on how to perform all the s ## Details of running a GenX case This section details as to what happens in the process of running a GenX case. As a first step, the GenX package and the desired solver (is it's anyting other than the default solver, HiGHS; for instance, Gurobi) are loaded -```@example pcm +```julia using GenX using Gurobi optimizer=Gurobi.Optimizer ``` The next command the user needs to run is the following: -```@example pcm +```julia run_genx_case!("", optimizer) ``` Contingent upon whether a single stage model or a multi-stage model is intended to be run, the above function, inturn makes calls to either of these two functions: For single-stage case: -```@example pcm +```julia run_genx_case_simple!(case, mysetup, optimizer) ``` From within this function, if time-domain reduction (TDR) is needed, GenX first checks whether there already is time domain clustered data (in order to avoid duplication of efforts) by running -```@example pcm +```julia prevent_doubled_timedomainreduction(case) ``` and if the function -```@example pcm +```julia !time_domain_reduced_files_exist(TDRpath) ``` returns true value, it then runs -```@example pcm +```julia cluster_inputs(case, settings_path, mysetup) ``` to generate the time-domain clustered data for the time-series. -OR- For multi-stage case: -```@example pcm +```julia run_genx_case_multistage!(case, mysetup, optimizer) ``` In this case also, the TDR clustering is done in a similar way, exxcept for the fact that if TDRSettingsDict["MultiStageConcatenate"] is set to 0, the TDR clustering is done individually for each stage. Otherwise, the clustering is done for all the stages together. The next step is configuring the solver, which is done by -```@example pcm +```julia OPTIMIZER = configure_solver(settings_path, optimizer) ``` The call to configure_solver first gets the particular solver that is being used to solve the particular case at hand, which then calls a function specific to that solver in order to use either the default values of the solver settings parameter or, any other set of values, specified in the settings YAML file for that particular solver. The configuration of solver is followed by loading the input files by running the following function: -```@example pcm +```julia myinputs = load_inputs(mysetup, case) ``` The above function in its turn calls separate functions to load different resources, demand data, fuels data etc. and returns the dictionary myinputs populated by the input data. The next function call is to generate the model -```@example pcm +```julia time_elapsed = @elapsed EP = generate_model(mysetup, myinputs, OPTIMIZER) println("Time elapsed for model building is") println(time_elapsed) ``` The above function call instantiates the different decision variables, constraints, and objective function expressions from the input data. It can be seen that we also keep track of the time required to build the model. Follwoing this, the solve_model function makes the call to the solver and return the results as well as the solve time. -```@example pcm +```julia EP, solve_time = solve_model(EP, mysetup) myinputs["solve_time"] = solve_time # Store the model solve time in myinputs ``` For writing the results, we invoke the following function: -```@example pcm +```julia outputs_path = get_default_output_folder(case) elapsed_time = @elapsed outputs_path = write_outputs(EP, outputs_path, mysetup, myinputs) ``` diff --git a/docs/src/assets/genx_logo.svg b/docs/src/assets/genx_logo.svg new file mode 100644 index 0000000000..2414c19cff --- /dev/null +++ b/docs/src/assets/genx_logo.svg @@ -0,0 +1,309 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/src/developer_guide.md b/docs/src/developer_guide.md index 4472f9d0cf..0be3dc62e8 100644 --- a/docs/src/developer_guide.md +++ b/docs/src/developer_guide.md @@ -79,7 +79,7 @@ For example, let's assume that `thermal_gen` is the vector of the three `Thermal ```@meta DocTestSetup = quote - using GenX: Thermal, resource_name, existing_cap_mw, inv_cost_per_mwyr, ids_with, ids_with_positive, ids_with_nonneg, ids_with_policy, resource_id, esr, has + using GenX: AbstractResource, Thermal, resource_name, existing_cap_mw, inv_cost_per_mwyr, ids_with, ids_with_positive, ids_with_nonneg, ids_with_policy, resource_id, esr, haskey end ``` @@ -130,7 +130,7 @@ julia> thermal_gen[1].existing_cap_mw Moreover, inside the `resources.jl` file, there is a set of utility functions to work with all the resources and that can be used as building blocks to create more complex functions: -- [`Base.get(r::AbstractResource, sym::Symbol, default)`](@ref): Returns the value of the attribute `sym` of the resource `r`. If the attribute is not defined for the resource, it returns the `default` value of that attribute. +- [`Base.get`](@ref): Returns the value of the attribute `sym` of the resource `r`. If the attribute is not defined for the resource, it returns the `default` value of that attribute. Example: ```jldoctest example_thermal @@ -140,7 +140,7 @@ julia> get(thermal_gen[1], :new_build, 0) 0 ``` -- [`GenX.haskey(r::AbstractResource, sym::Symbol)`](@ref): Returns `true` if the resource `r` has the attribute `sym`, and `false` otherwise. +- [`Base.haskey`](@ref): Returns `true` if the resource `r` has the attribute `sym`, and `false` otherwise. Example: ```jldoctest example_thermal @@ -150,7 +150,7 @@ julia> haskey(thermal_gen[1], :new_build) false ``` -- [`Base.findall(f::Function, rs::Vector{<:AbstractResource})`](@ref): Returns the indices of the resources in `rs` for which the function `f` returns `true`. +- [`Base.findall`](@ref): Returns the indices of the resources in `rs` for which the function `f` returns `true`. Example: ```jldoctest example_thermal @@ -166,7 +166,7 @@ julia> findall(r -> get(r, :new_build, 0) == 1, thermal_gen) # returns the indic 1-element Vector{Int64}: 25 ``` -- [`GenX.ids_with(rs::Vector{T}, f::Function, default=default_zero) where T <: AbstractResource`](@ref): Returns the indices of the resources in the vector `rs` for which the function `f` is different from `default`. +- [`GenX.ids_with`](@ref): Returns the indices of the resources in the vector `rs` for which the function `f` is different from `default`. Example: ```jldoctest example_thermal @@ -183,7 +183,7 @@ julia> ids_with(thermal_gen, :inv_cost_per_mwyr) 25 ``` -- [`GenX.ids_with_policy(rs::Vector{T}, name::Symbol; tag::Int64) where T <: AbstractResource`](@ref): Returns the indices of the resources in the vector `rs` that have a policy with the name `name` and the tag `tag`. +- [`GenX.ids_with_policy`](@ref): Returns the indices of the resources in the vector `rs` that have a policy with the name `name` and the tag `tag`. Example: ```jldoctest example_thermal @@ -192,7 +192,7 @@ julia> ids_with_policy(thermal_gen, esr, tag=1) 23 ``` -- [`GenX.ids_with_positive(rs::Vector{T}, f::Function) where T <: AbstractResource`](@ref): Returns the indices of the resources in the vector `rs` for which the getter function `f` returns a positive value. +- [`GenX.ids_with_positive`](@ref): Returns the indices of the resources in the vector `rs` for which the getter function `f` returns a positive value. Example: ```jldoctest example_thermal @@ -209,10 +209,10 @@ julia> ids_with_positive(thermal_gen, :inv_cost_per_mwyr) 25 ``` -- [`GenX.ids_with_nonneg(rs::Vector{T}, f::Function) where T <: AbstractResource`](@ref): Returns the indices of the resources in `rs` for which the getter function `f` returns a non-negative value. +- [`GenX.ids_with_nonneg`](@ref): Returns the indices of the resources in `rs` for which the getter function `f` returns a non-negative value. Other useful functions available in GenX are: -- [`GenX.resource_id(r::AbstractResource)`](@ref): Returns the `id` of the resource `r`. +- `GenX.resource_id`: Returns the `id` of the resource `r`. Example: ```jldoctest example_thermal julia> resource_id(thermal_gen[1]) @@ -223,7 +223,7 @@ julia> resource_id.(thermal_gen) 24 25 ``` -- [`GenX.resource_name(r::AbstractResource)`](@ref): Returns the `name` of the resource `r`. +- `GenX.resource_name`: Returns the `name` of the resource `r`. Example: ```jldoctest example_thermal julia> resource_name(thermal_gen[1]) @@ -241,7 +241,7 @@ julia> resource_name.(thermal_gen) GenX is designed to be modular and highly flexible to comply with the rapidly changing electricity landscape. For this reason, adding a new resource to GenX is relatively straightforward. This guide will walk you through the steps to do it. !!! tip - Before you start, ensure you have read the section of the documentation about [2.1.4 Resources input files](@ref). This will help you understand the data format that GenX expects for each resource and where to place the input data files. + Before you start, ensure you have read the section of the documentation about [1.4 Resources input files](@ref). This will help you understand the data format that GenX expects for each resource and where to place the input data files. ### Step 1: Define the new resource data type @@ -344,4 +344,10 @@ Once the new resource type has been defined and added to GenX, you can work with ```@meta DocTestSetup = nothing +``` + +# Utility functions to work with JuMP expressions in GenX +```@autodocs +Modules = [GenX] +Pages = ["model/expression_manipulation.jl"] ``` \ No newline at end of file diff --git a/docs/src/Welcome_Page/index.md b/docs/src/index.md similarity index 96% rename from docs/src/Welcome_Page/index.md rename to docs/src/index.md index 828ed7fb83..873a2a5874 100644 --- a/docs/src/Welcome_Page/index.md +++ b/docs/src/index.md @@ -1,5 +1,8 @@ -# GenX Documentation -Welcome to the GenX documentation! +```@raw html + +``` + +### Welcome to the GenX documentation! ## What is GenX? diff --git a/docs/src/Welcome_Page/installation.md b/docs/src/installation.md similarity index 100% rename from docs/src/Welcome_Page/installation.md rename to docs/src/installation.md diff --git a/docs/src/Welcome_Page/limitations_genx.md b/docs/src/limitations_genx.md similarity index 100% rename from docs/src/Welcome_Page/limitations_genx.md rename to docs/src/limitations_genx.md diff --git a/docs/src/Welcome_Page/third_party_genx.md b/docs/src/third_party_genx.md similarity index 100% rename from docs/src/Welcome_Page/third_party_genx.md rename to docs/src/third_party_genx.md diff --git a/src/model/resources/hydro/hydro_inter_period_linkage.jl b/src/model/resources/hydro/hydro_inter_period_linkage.jl index 2c6cc00427..550dd13403 100644 --- a/src/model/resources/hydro/hydro_inter_period_linkage.jl +++ b/src/model/resources/hydro/hydro_inter_period_linkage.jl @@ -12,7 +12,7 @@ The constraints in this section are used to approximate the behavior of long-dur By definition $\mathcal{T}^{start}=\{\left(m-1\right) \times \tau^{period}+1 | m \in \mathcal{M}\}$, which implies that this constraint is defined for all values of $t \in T^{start}$. **Storage inventory change input periods** We need additional variables and constraints to approximate energy exchange between representative periods, while accounting for their chronological occurence in the original input time series data and the possibility that two representative periods may not be adjacent to each other (see Figure below). To implement this, we introduce a new variable $Q_{o,z, n}$ that models inventory of storage technology $o \in O$ in zone $z$ in each input period $n \in \mathcal{N}$. Additionally we define a function mapping, $f: n \rightarrow m$, that uniquely maps each input period $n$ to its corresponding representative period $m$. This mapping is available as an output of the process used to identify representative periods (E.g. k-means clustering [Mallapragada et al., 2018](https://www.sciencedirect.com/science/article/pii/S0360544218315238?casa_token=I-6GVNMtAVIAAAAA:G8LFXFqXxRGrXHtrzmiIGm02BusIUmm83zKh8xf1BXY81-dTnA9p2YI1NnGuzlYBXsxK12by)). -![Modeling inter-period energy exchange via long-duration storage when using representative period temporal resolution to approximate annual grid operations](assets/LDES_approach.png) +![Modeling inter-period energy exchange via long-duration storage when using representative period temporal resolution to approximate annual grid operations](../../assets/LDES_approach.png) *Figure. Modeling inter-period energy exchange via long-duration storage when using representative period temporal resolution to approximate annual grid operations* The following two equations define the storage inventory at the beginning of each input period $n+1$ as the sum of storage inventory at begining of previous input period $n$ plus change in storage inventory for that period. The latter is approximated by the change in storage inventory in the corresponding representative period, identified per the mapping $f(n)$. The second constraint relates the storage level of the last input period, $|N|$, with the storage level at the beginning of the first input period. Finally, if the input period is also a representative period, then a third constraint enforces that initial storage level estimated by the intra-period storage balance constraint should equal the initial storage level estimated from the inter-period storage balance constraints. Note that $|N|$ refers to the last modeled period. ```math diff --git a/src/model/resources/resources.jl b/src/model/resources/resources.jl index 7d4f06a5d2..74203925c3 100644 --- a/src/model/resources/resources.jl +++ b/src/model/resources/resources.jl @@ -84,7 +84,7 @@ Check if an `AbstractResource` object has a specific attribute. It returns a boo Base.haskey(r::AbstractResource, sym::Symbol) = haskey(parent(r), sym) """ - get(r::AbstractResource, sym::Symbol, default) + Base.get(r::AbstractResource, sym::Symbol, default) Retrieves the value of a specific attribute from an `AbstractResource` object. If the attribute exists, its value is returned; otherwise, the default value is returned. diff --git a/src/model/resources/storage/long_duration_storage.jl b/src/model/resources/storage/long_duration_storage.jl index 9eb904c8b8..c9814e42c0 100644 --- a/src/model/resources/storage/long_duration_storage.jl +++ b/src/model/resources/storage/long_duration_storage.jl @@ -20,7 +20,7 @@ By definition $\mathcal{T}^{start}=\{\left(m-1\right) \times \tau^{period}+1 | m We need additional variables and constraints to approximate energy exchange between representative periods, while accounting for their chronological occurence in the original input time series data and the possibility that two representative periods may not be adjacent to each other (see Figure below). To implement this, we introduce a new variable $Q_{o,z, n}$ that models inventory of storage technology $o \in O$ in zone $z$ in each input period $n \in \mathcal{N}$. Additionally we define a function mapping, $f: n \rightarrow m$, that uniquely maps each input period $n$ to its corresponding representative period $m$. This mapping is available as an output of the process used to identify representative periods (E.g. k-means clustering [Mallapragada et al., 2018](https://www.sciencedirect.com/science/article/pii/S0360544218315238?casa_token=I-6GVNMtAVIAAAAA:G8LFXFqXxRGrXHtrzmiIGm02BusIUmm83zKh8xf1BXY81-dTnA9p2YI1NnGuzlYBXsxK12by)). -![Modeling inter-period energy exchange via long-duration storage when using representative period temporal resolution to approximate annual grid operations](assets/LDES_approach.png) +![Modeling inter-period energy exchange via long-duration storage when using representative period temporal resolution to approximate annual grid operations](../../assets/LDES_approach.png) *Figure. Modeling inter-period energy exchange via long-duration storage when using representative period temporal resolution to approximate annual grid operations* The following two equations define the storage inventory at the beginning of each input period $n+1$ as diff --git a/src/model/resources/vre_stor/vre_stor.jl b/src/model/resources/vre_stor/vre_stor.jl index 09d9d0aa74..918ae42c99 100644 --- a/src/model/resources/vre_stor/vre_stor.jl +++ b/src/model/resources/vre_stor/vre_stor.jl @@ -1,19 +1,3 @@ -""" -GenX: An Configurable Capacity Expansion Model -Copyright (C) 2021, Massachusetts Institute of Technology -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. -A complete copy of the GNU General Public License v2 (GPLv2) is available -in LICENSE.txt. Users uncompressing this from an archive may not have -received this license file. If not, see . -""" - @doc raw""" vre_stor(EP::Model, inputs::Dict, setup::Dict) @@ -30,7 +14,7 @@ that each resource must have. If the configured resource has either solar PV and storage capabilities, an inverter decision variable is also created. The full module with the decision variables and interactions can be found below. -![Configurable Co-located VRE and Storage Module Interactions and Decision Variables](assets/vre_stor_module.png) +![Configurable Co-located VRE and Storage Module Interactions and Decision Variables](../../assets/vre_stor_module.png) *Figure. Configurable Co-located VRE and Storage Module Interactions and Decision Variables* This module is split such that functions are called for each configurable component of a co-located resource: