var documenterSearchIndex = {"docs":
[{"location":"api/#API-Reference","page":"API Reference","title":"API Reference","text":"","category":"section"},{"location":"api/#Read-data,-build-model-and-optimize","page":"API Reference","title":"Read data, build model & optimize","text":"","category":"section"},{"location":"api/","page":"API Reference","title":"API Reference","text":"UnitCommitment.read\nUnitCommitment.read_benchmark\nUnitCommitment.build_model\nUnitCommitment.optimize!\nUnitCommitment.solution\nUnitCommitment.validate\nUnitCommitment.write","category":"page"},{"location":"api/#UnitCommitment.read","page":"API Reference","title":"UnitCommitment.read","text":"read(path::AbstractString)::UnitCommitmentInstance\n\nRead a deterministic test case from the given file. The file may be gzipped.\n\nExample\n\ninstance = UnitCommitment.read(\"s1.json.gz\")\n\n\n\n\n\nread(path::Vector{String})::UnitCommitmentInstance\n\nRead a stochastic unit commitment instance from the given files. Each file describes a scenario. The files may be gzipped.\n\nExample\n\ninstance = UnitCommitment.read([\"s1.json.gz\", \"s2.json.gz\"])\n\n\n\n\n\n","category":"function"},{"location":"api/#UnitCommitment.read_benchmark","page":"API Reference","title":"UnitCommitment.read_benchmark","text":"read_benchmark(name::AbstractString)::UnitCommitmentInstance\n\nRead one of the benchmark instances included in the package. See Instances for the entire list of benchmark instances available.\n\nExample\n\ninstance = UnitCommitment.read_benchmark(\"matpower/case3375wp/2017-02-01\")\n\n\n\n\n\n","category":"function"},{"location":"api/#UnitCommitment.build_model","page":"API Reference","title":"UnitCommitment.build_model","text":"function build_model(;\n instance::UnitCommitmentInstance,\n optimizer = nothing,\n formulation = Formulation(),\n variable_names::Bool = false,\n)::JuMP.Model\n\nBuild the JuMP model corresponding to the given unit commitment instance.\n\nArguments\n\ninstance: the instance.\noptimizer: the optimizer factory that should be attached to this model (e.g. Cbc.Optimizer). If not provided, no optimizer will be attached.\nformulation: the MIP formulation to use. By default, uses a formulation that combines modeling components from different publications that provides good performance across a wide variety of instances. An alternative formulation may also be provided.\nvariable_names: if true, set variable and constraint names. Important if the model is going to be exported to an MPS file. For large models, this can take significant time, so it's disabled by default.\n\nExamples\n\n# Read benchmark instance\ninstance = UnitCommitment.read_benchmark(\"matpower/case118/2017-02-01\")\n\n# Construct model (using state-of-the-art defaults)\nmodel = UnitCommitment.build_model(\n instance = instance,\n optimizer = Cbc.Optimizer,\n)\n\n# Construct model (using customized formulation)\nmodel = UnitCommitment.build_model(\n instance = instance,\n optimizer = Cbc.Optimizer,\n formulation = Formulation(\n pwl_costs = KnuOstWat2018.PwlCosts(),\n ramping = MorLatRam2013.Ramping(),\n startup_costs = MorLatRam2013.StartupCosts(),\n transmission = ShiftFactorsFormulation(\n isf_cutoff = 0.005,\n lodf_cutoff = 0.001,\n ),\n ),\n)\n\n\n\n\n\n","category":"function"},{"location":"api/#UnitCommitment.optimize!","page":"API Reference","title":"UnitCommitment.optimize!","text":"optimize!(model::JuMP.Model)::Nothing\n\nSolve the given unit commitment model. Unlike JuMP.optimize!, this uses more advanced methods to accelerate the solution process and to enforce transmission and N-1 security constraints.\n\n\n\n\n\n","category":"function"},{"location":"api/#UnitCommitment.solution","page":"API Reference","title":"UnitCommitment.solution","text":"solution(model::JuMP.Model)::OrderedDict\n\nExtracts the optimal solution from the UC.jl model. The model must be solved beforehand.\n\nExample\n\nUnitCommitment.optimize!(model)\nsolution = UnitCommitment.solution(model)\n\n\n\n\n\n","category":"function"},{"location":"api/#UnitCommitment.validate","page":"API Reference","title":"UnitCommitment.validate","text":"validate(instance, solution)::Bool\n\nVerifies that the given solution is feasible for the problem. If feasible, silently returns true. In infeasible, returns false and prints the validation errors to the screen.\n\nThis function is implemented independently from the optimization model in model.jl, and therefore can be used to verify that the model is indeed producing valid solutions. It can also be used to verify the solutions produced by other optimization packages.\n\n\n\n\n\n","category":"function"},{"location":"api/#UnitCommitment.write","page":"API Reference","title":"UnitCommitment.write","text":"write(filename::AbstractString, solution::AbstractDict)::Nothing\n\nWrite the given solution to a JSON file.\n\nExample\n\nsolution = UnitCommitment.solution(model)\nUnitCommitment.write(\"/tmp/output.json\", solution)\n\n\n\n\n\n","category":"function"},{"location":"api/#Locational-Marginal-Prices","page":"API Reference","title":"Locational Marginal Prices","text":"","category":"section"},{"location":"api/#Conventional-LMPs","page":"API Reference","title":"Conventional LMPs","text":"","category":"section"},{"location":"api/","page":"API Reference","title":"API Reference","text":"UnitCommitment.compute_lmp(::JuMP.Model,::UnitCommitment.ConventionalLMP)","category":"page"},{"location":"api/#UnitCommitment.compute_lmp-Tuple{Model, UnitCommitment.ConventionalLMP}","page":"API Reference","title":"UnitCommitment.compute_lmp","text":"function compute_lmp(\n model::JuMP.Model,\n method::ConventionalLMP;\n optimizer,\n)::OrderedDict{Tuple{String,String,Int},Float64}\n\nCalculates conventional locational marginal prices of the given unit commitment instance. Returns a dictionary mapping (bus_name, time) to the marginal price.\n\nArguments\n\nmodel: the UnitCommitment model, must be solved before calling this function.\nmethod: the LMP method.\noptimizer: the optimizer for solving the LP problem.\n\nExamples\n\nusing UnitCommitment\nusing HiGHS\n\nimport UnitCommitment: ConventionalLMP\n\n# Read benchmark instance\ninstance = UnitCommitment.read_benchmark(\"matpower/case118/2018-01-01\")\n\n# Build the model\nmodel = UnitCommitment.build_model(\n instance = instance,\n optimizer = HiGHS.Optimizer,\n)\n\n# Optimize the model\nUnitCommitment.optimize!(model)\n\n# Compute the LMPs using the conventional method\nlmp = UnitCommitment.compute_lmp(\n model,\n ConventionalLMP(),\n optimizer = HiGHS.Optimizer,\n)\n\n# Access the LMPs\n# Example: \"s1\" is the scenario name, \"b1\" is the bus name, 1 is the first time slot\n@show lmp[\"s1\", \"b1\", 1]\n\n\n\n\n\n","category":"method"},{"location":"api/#Approximated-Extended-LMPs","page":"API Reference","title":"Approximated Extended LMPs","text":"","category":"section"},{"location":"api/","page":"API Reference","title":"API Reference","text":"UnitCommitment.AELMP\nUnitCommitment.compute_lmp(::JuMP.Model,::UnitCommitment.AELMP)","category":"page"},{"location":"api/#UnitCommitment.AELMP","page":"API Reference","title":"UnitCommitment.AELMP","text":"struct AELMP <: PricingMethod \n allow_offline_participation::Bool = true\n consider_startup_costs::Bool = true\nend\n\nApproximate Extended LMPs.\n\nArguments\n\nallow_offline_participation: If true, offline assets are allowed to participate in pricing.\nconsider_startup_costs: If true, the start-up costs are averaged over each unit production; otherwise the production costs stay the same.\n\n\n\n\n\n","category":"type"},{"location":"api/#UnitCommitment.compute_lmp-Tuple{Model, UnitCommitment.AELMP}","page":"API Reference","title":"UnitCommitment.compute_lmp","text":"function compute_lmp(\n model::JuMP.Model,\n method::AELMP;\n optimizer,\n)::OrderedDict{Tuple{String,Int},Float64}\n\nCalculates the approximate extended locational marginal prices of the given unit commitment instance.\n\nThe AELPM does the following three things:\n\n1. It sets the minimum power output of each generator to zero\n2. It averages the start-up cost over the offer blocks for each generator\n3. It relaxes all integrality constraints\n\nReturns a dictionary mapping (bus_name, time) to the marginal price.\n\nWARNING: This approximation method is not fully developed. The implementation is based on MISO Phase I only.\n\nIt only supports Fast Start resources. More specifically, the minimum up/down time has to be zero.\nThe method does NOT support time-varying start-up costs.\nAn asset is considered offline if it is never on throughout all time periods. \nThe method does NOT support multiple scenarios.\n\nArguments\n\nmodel: the UnitCommitment model, must be solved before calling this function if offline participation is not allowed.\nmethod: the AELMP method.\noptimizer: the optimizer for solving the LP problem.\n\nExamples\n\nusing UnitCommitment\nusing HiGHS\n\nimport UnitCommitment: AELMP\n\n# Read benchmark instance\ninstance = UnitCommitment.read_benchmark(\"matpower/case118/2017-02-01\")\n\n# Build the model\nmodel = UnitCommitment.build_model(\n instance = instance,\n optimizer = HiGHS.Optimizer,\n)\n\n# Optimize the model\nUnitCommitment.optimize!(model)\n\n# Compute the AELMPs\naelmp = UnitCommitment.compute_lmp(\n model,\n AELMP(\n allow_offline_participation = false,\n consider_startup_costs = true\n ),\n optimizer = HiGHS.Optimizer\n)\n\n# Access the AELMPs\n# Example: \"s1\" is the scenario name, \"b1\" is the bus name, 1 is the first time slot\n# Note: although scenario is supported, the query still keeps the scenario keys for consistency.\n@show aelmp[\"s1\", \"b1\", 1]\n\n\n\n\n\n","category":"method"},{"location":"api/#Modify-instance","page":"API Reference","title":"Modify instance","text":"","category":"section"},{"location":"api/","page":"API Reference","title":"API Reference","text":"UnitCommitment.slice\nUnitCommitment.randomize!(::UnitCommitment.UnitCommitmentInstance)\nUnitCommitment.generate_initial_conditions!","category":"page"},{"location":"api/#UnitCommitment.slice","page":"API Reference","title":"UnitCommitment.slice","text":"slice(instance, range)\n\nCreates a new instance, with only a subset of the time periods. This function does not modify the provided instance. The initial conditions are also not modified.\n\nExample\n\n# Build a 2-hour UC instance\ninstance = UnitCommitment.read_benchmark(\"matpower/case118/2017-02-01\")\nmodified = UnitCommitment.slice(instance, 1:2)\n\n\n\n\n\n","category":"function"},{"location":"api/#UnitCommitment.randomize!-Tuple{UnitCommitmentInstance}","page":"API Reference","title":"UnitCommitment.randomize!","text":"function randomize!(\n instance::UnitCommitmentInstance;\n method = UnitCommitment.XavQiuAhm2021.Randomization();\n rng = MersenneTwister(),\n)::Nothing\n\nRandomizes instance parameters according to the provided randomization method.\n\nExample\n\ninstance = UnitCommitment.read_benchmark(\"matpower/case118/2017-02-01\")\nUnitCommitment.randomize!(instance)\nmodel = UnitCommitment.build_model(; instance)\n\n\n\n\n\n","category":"method"},{"location":"api/#UnitCommitment.generate_initial_conditions!","page":"API Reference","title":"UnitCommitment.generate_initial_conditions!","text":"generate_initial_conditions!(instance, optimizer)\n\nGenerates feasible initial conditions for the given instance, by constructing and solving a single-period mixed-integer optimization problem, using the given optimizer. The instance is modified in-place.\n\n\n\n\n\n","category":"function"},{"location":"api/#Formulations","page":"API Reference","title":"Formulations","text":"","category":"section"},{"location":"api/","page":"API Reference","title":"API Reference","text":"UnitCommitment.Formulation\nUnitCommitment.ShiftFactorsFormulation\nUnitCommitment.ArrCon2000\nUnitCommitment.CarArr2006\nUnitCommitment.DamKucRajAta2016\nUnitCommitment.Gar1962\nUnitCommitment.KnuOstWat2018\nUnitCommitment.MorLatRam2013\nUnitCommitment.PanGua2016\nUnitCommitment.WanHob2016","category":"page"},{"location":"api/#UnitCommitment.Formulation","page":"API Reference","title":"UnitCommitment.Formulation","text":"struct Formulation\n prod_vars::ProductionVarsFormulation\n pwl_costs::PiecewiseLinearCostsFormulation\n ramping::RampingFormulation\n startup_costs::StartupCostsFormulation\n status_vars::StatusVarsFormulation\n transmission::TransmissionFormulation\nend\n\nStruct provided to build_model that holds various formulation components.\n\nFields\n\nprod_vars: Formulation for the production decision variables\npwl_costs: Formulation for the piecewise linear costs\nramping: Formulation for ramping constraints\nstartup_costs: Formulation for time-dependent start-up costs\nstatus_vars: Formulation for the status variables (e.g. is_on, is_off)\ntransmission: Formulation for transmission and N-1 security constraints\n\n\n\n\n\n","category":"type"},{"location":"api/#UnitCommitment.ShiftFactorsFormulation","page":"API Reference","title":"UnitCommitment.ShiftFactorsFormulation","text":"struct ShiftFactorsFormulation <: TransmissionFormulation\n isf_cutoff::Float64 = 0.005\n lodf_cutoff::Float64 = 0.001\n precomputed_isf=nothing\n precomputed_lodf=nothing\nend\n\nTransmission formulation based on Injection Shift Factors (ISF) and Line Outage Distribution Factors (LODF). Constraints are enforced in a lazy way.\n\nArguments\n\nprecomputed_isf: the injection shift factors matrix. If not provided, it will be computed.\nprecomputed_lodf: the line outage distribution factors matrix. If not provided, it will be computed.\nisf_cutoff: the cutoff that should be applied to the ISF matrix. Entries with magnitude smaller than this value will be set to zero.\nlodf_cutoff: the cutoff that should be applied to the LODF matrix. Entries with magnitude smaller than this value will be set to zero.\n\n\n\n\n\n","category":"type"},{"location":"api/#UnitCommitment.ArrCon2000","page":"API Reference","title":"UnitCommitment.ArrCon2000","text":"Formulation described in:\n\nArroyo, J. M., & Conejo, A. J. (2000). Optimal response of a thermal unit\nto an electricity spot market. IEEE Transactions on power systems, 15(3), \n1098-1104. DOI: https://doi.org/10.1109/59.871739\n\n\n\n\n\n","category":"module"},{"location":"api/#UnitCommitment.CarArr2006","page":"API Reference","title":"UnitCommitment.CarArr2006","text":"Formulation described in:\n\nCarrión, M., & Arroyo, J. M. (2006). A computationally efficient\nmixed-integer linear formulation for the thermal unit commitment problem.\nIEEE Transactions on power systems, 21(3), 1371-1378.\nDOI: https://doi.org/10.1109/TPWRS.2006.876672\n\n\n\n\n\n","category":"module"},{"location":"api/#UnitCommitment.DamKucRajAta2016","page":"API Reference","title":"UnitCommitment.DamKucRajAta2016","text":"Formulation described in:\n\nDamcı-Kurt, P., Küçükyavuz, S., Rajan, D., & Atamtürk, A. (2016). A polyhedral\nstudy of production ramping. Mathematical Programming, 158(1), 175-205.\nDOI: https://doi.org/10.1007/s10107-015-0919-9\n\n\n\n\n\n","category":"module"},{"location":"api/#UnitCommitment.Gar1962","page":"API Reference","title":"UnitCommitment.Gar1962","text":"Formulation described in:\n\nGarver, L. L. (1962). Power generation scheduling by integer\nprogramming-development of theory. Transactions of the American Institute\nof Electrical Engineers. Part III: Power Apparatus and Systems, 81(3), 730-734.\nDOI: https://doi.org/10.1109/AIEEPAS.1962.4501405\n\n\n\n\n\n","category":"module"},{"location":"api/#UnitCommitment.KnuOstWat2018","page":"API Reference","title":"UnitCommitment.KnuOstWat2018","text":"Formulation described in:\n\nKnueven, B., Ostrowski, J., & Watson, J. P. (2018). Exploiting identical\ngenerators in unit commitment. IEEE Transactions on Power Systems, 33(4),\n4496-4507. DOI: https://doi.org/10.1109/TPWRS.2017.2783850\n\n\n\n\n\n","category":"module"},{"location":"api/#UnitCommitment.MorLatRam2013","page":"API Reference","title":"UnitCommitment.MorLatRam2013","text":"Formulation described in:\n\nMorales-España, G., Latorre, J. M., & Ramos, A. (2013). Tight and compact\nMILP formulation for the thermal unit commitment problem. IEEE Transactions\non Power Systems, 28(4), 4897-4908. DOI: https://doi.org/10.1109/TPWRS.2013.2251373\n\n\n\n\n\n","category":"module"},{"location":"api/#UnitCommitment.PanGua2016","page":"API Reference","title":"UnitCommitment.PanGua2016","text":"Formulation described in:\n\nPan, K., & Guan, Y. (2016). Strong formulations for multistage stochastic\nself-scheduling unit commitment. Operations Research, 64(6), 1482-1498.\nDOI: https://doi.org/10.1287/opre.2016.1520\n\n\n\n\n\n","category":"module"},{"location":"api/#UnitCommitment.WanHob2016","page":"API Reference","title":"UnitCommitment.WanHob2016","text":"Formulation described in:\n\nB. Wang and B. F. Hobbs, \"Real-Time Markets for Flexiramp: A Stochastic \nUnit Commitment-Based Analysis,\" in IEEE Transactions on Power Systems, \nvol. 31, no. 2, pp. 846-860, March 2016, doi: 10.1109/TPWRS.2015.2411268.\n\n\n\n\n\n","category":"module"},{"location":"api/#Solution-Methods","page":"API Reference","title":"Solution Methods","text":"","category":"section"},{"location":"api/","page":"API Reference","title":"API Reference","text":"UnitCommitment.XavQiuWanThi2019.Method","category":"page"},{"location":"api/#UnitCommitment.XavQiuWanThi2019.Method","page":"API Reference","title":"UnitCommitment.XavQiuWanThi2019.Method","text":"mutable struct Method\n time_limit::Float64\n gap_limit::Float64\n two_phase_gap::Bool\n max_violations_per_line::Int\n max_violations_per_period::Int\nend\n\nLazy constraint solution method described in:\n\nXavier, A. S., Qiu, F., Wang, F., & Thimmapuram, P. R. (2019). Transmission\nconstraint filtering in large-scale security-constrained unit commitment. \nIEEE Transactions on Power Systems, 34(3), 2457-2460.\nDOI: https://doi.org/10.1109/TPWRS.2019.2892620\n\nFields\n\ntime_limit: the time limit over the entire optimization procedure.\ngap_limit: the desired relative optimality gap. Only used when two_phase_gap=true.\ntwo_phase_gap: if true, solve the problem with large gap tolerance first, then reduce the gap tolerance when no further violated constraints are found.\nmax_violations_per_line: maximum number of violated transmission constraints to add to the formulation per transmission line.\nmax_violations_per_period: maximum number of violated transmission constraints to add to the formulation per time period.\n\n\n\n\n\n","category":"type"},{"location":"api/#Randomization-Methods","page":"API Reference","title":"Randomization Methods","text":"","category":"section"},{"location":"api/","page":"API Reference","title":"API Reference","text":"UnitCommitment.XavQiuAhm2021.Randomization","category":"page"},{"location":"api/#UnitCommitment.XavQiuAhm2021.Randomization","page":"API Reference","title":"UnitCommitment.XavQiuAhm2021.Randomization","text":"struct Randomization\n cost = Uniform(0.95, 1.05)\n load_profile_mu = [...]\n load_profile_sigma = [...]\n load_share = Uniform(0.90, 1.10)\n peak_load = Uniform(0.6 * 0.925, 0.6 * 1.075)\n randomize_costs = true\n randomize_load_profile = true\n randomize_load_share = true\nend\n\nRandomization method that changes: (1) production and startup costs, (2) share of load coming from each bus, (3) peak system load, and (4) temporal load profile, as follows:\n\nProduction and startup costs: For each unit u, the vectors u.min_power_cost and u.cost_segments are multiplied by a constant α[u] sampled from the provided cost distribution. If randomize_costs is false, skips this step.\nLoad share: For each bus b and time t, the value b.load[t] is multiplied by (β[b] * b.load[t]) / sum(β[b2] * b2.load[t] for b2 in buses), where β[b] is sampled from the provided load_share distribution. If randomize_load_share is false, skips this step.\nPeak system load and temporal load profile: Sets the peak load to ρ * C, where ρ is sampled from peak_load and C is the maximum system capacity, at any time. Also scales the loads of all buses, so that system_load[t+1] becomes equal to system_load[t] * γ[t], where γ[t] is sampled from Normal(load_profile_mu[t], load_profile_sigma[t]).\nThe system load for the first time period is set so that the peak load matches ρ * C. If load_profile_sigma and load_profile_mu have fewer elements than instance.time, wraps around. If randomize_load_profile is false, skips this step.\n\nThe default parameters were obtained based on an analysis of publicly available bid and hourly data from PJM, corresponding to the month of January, 2017. For more details, see Section 4.2 of the paper.\n\nReferences\n\nXavier, Álinson S., Feng Qiu, and Shabbir Ahmed. \"Learning to solve large-scale security-constrained unit commitment problems.\" INFORMS Journal on Computing 33.2 (2021): 739-756. DOI: 10.1287/ijoc.2020.0976\n\n\n\n\n\n","category":"type"},{"location":"guides/format/#JSON-data-format","page":"JSON data format","title":"JSON data format","text":"","category":"section"},{"location":"guides/format/","page":"JSON data format","title":"JSON data format","text":"An instance of the stochastic security-constrained unit commitment (SCUC) problem is composed multiple scenarios. Each scenario should be described in an individual JSON file containing the main section belows. For deterministic instances, a single scenario file, following the same format below, may also be provided. Fields that are allowed to differ among scenarios are marked as \"uncertain\". Fields that are allowed to be time-dependent are marked as \"time series\".","category":"page"},{"location":"guides/format/","page":"JSON data format","title":"JSON data format","text":"Parameters\nBuses\nGenerators\nStorage units\nPrice-sensitive loads\nTransmission lines\nReserves\nContingencies","category":"page"},{"location":"guides/format/","page":"JSON data format","title":"JSON data format","text":"Each section is described in detail below. See case118/2017-01-01.json.gz for a complete example.","category":"page"},{"location":"guides/format/#Parameters","page":"JSON data format","title":"Parameters","text":"","category":"section"},{"location":"guides/format/","page":"JSON data format","title":"JSON data format","text":"This section describes system-wide parameters, such as power balance penalty, and optimization parameters, such as the length of the planning horizon and the time.","category":"page"},{"location":"guides/format/","page":"JSON data format","title":"JSON data format","text":"Key Description Default Time series? Uncertain?\nVersion Version of UnitCommitment.jl this file was written for. Required to ensure that the file remains readable in future versions of the package. If you are following this page to construct the file, this field should equal 0.4. Required No No\nTime horizon (min) or Time horizon (h) Length of the planning horizon (in minutes or hours). Either Time horizon (min) or Time horizon (h) is required, but not both. Required No No\nTime step (min) Length of each time step (in minutes). Must be a divisor of 60 (e.g. 60, 30, 20, 15, etc). 60 No No\nPower balance penalty ($/MW) Penalty for system-wide shortage or surplus in production (in /MW). This is charged per time step. For example, if there is a shortage of 1 MW for three time steps, three times this amount will be charged. 1000.0 No Yes\nScenario name Name of the scenario. \"s1\" No –-\nScenario weight Weight of the scenario. The scenario weight can be any positive real number, that is, it does not have to be between zero and one. The package normalizes the weights to ensure that the probability of all scenarios sum up to one. 1.0 No –-","category":"page"},{"location":"guides/format/#Example","page":"JSON data format","title":"Example","text":"","category":"section"},{"location":"guides/format/","page":"JSON data format","title":"JSON data format","text":"{\n \"Parameters\": {\n \"Version\": \"0.3\",\n \"Time horizon (h)\": 4,\n \"Power balance penalty ($/MW)\": 1000.0,\n \"Scenario name\": \"s1\",\n \"Scenario weight\": 0.5\n }\n}","category":"page"},{"location":"guides/format/#Buses","page":"JSON data format","title":"Buses","text":"","category":"section"},{"location":"guides/format/","page":"JSON data format","title":"JSON data format","text":"This section describes the characteristics of each bus in the system.","category":"page"},{"location":"guides/format/","page":"JSON data format","title":"JSON data format","text":"Key Description Default Time series? Uncertain?\nLoad (MW) Fixed load connected to the bus (in MW). Required Yes Yes","category":"page"},{"location":"guides/format/#Example-2","page":"JSON data format","title":"Example","text":"","category":"section"},{"location":"guides/format/","page":"JSON data format","title":"JSON data format","text":"{\n \"Buses\": {\n \"b1\": {\n \"Load (MW)\": 0.0\n },\n \"b2\": {\n \"Load (MW)\": [26.01527, 24.46212, 23.29725, 22.90897]\n }\n }\n}","category":"page"},{"location":"guides/format/#Generators","page":"JSON data format","title":"Generators","text":"","category":"section"},{"location":"guides/format/","page":"JSON data format","title":"JSON data format","text":"This section describes all generators in the system. Two types of units can be specified:","category":"page"},{"location":"guides/format/","page":"JSON data format","title":"JSON data format","text":"Thermal units: Units that produce power by converting heat into electrical energy, such as coal and oil power plants. These units use a more complex model, with binary decision variables, and various constraints to enforce ramp rates and minimum up/down time.\nProfiled units: Simplified model for units that do not require the constraints mentioned above, only a maximum and minimum power output for each time period. Typically used for renewables and hydro.","category":"page"},{"location":"guides/format/#Thermal-Units","page":"JSON data format","title":"Thermal Units","text":"","category":"section"},{"location":"guides/format/","page":"JSON data format","title":"JSON data format","text":"Key Description Default Time series? Uncertain?\nBus Identifier of the bus where this generator is located (string). Required No Yes\nType Type of the generator (string). For thermal generators, this must be Thermal. Required No No\nProduction cost curve (MW) and Production cost curve ($) Parameters describing the piecewise-linear production costs. See below for more details. Required Yes Yes\nStartup costs ($) and Startup delays (h) Parameters describing how much it costs to start the generator after it has been shut down for a certain amount of time. If Startup costs ($) and Startup delays (h) are set to [300.0, 400.0] and [1, 4], for example, and the generator is shut down at time 00:00 (h:min), then it costs $300 to start up the generator at any time between 01:00 and 03:59, and $400 to start the generator at time 04:00 or any time after that. The number of startup cost points is unlimited, and may be different for each generator. Startup delays must be strictly increasing and the first entry must equal Minimum downtime (h). [0.0] and [1] No Yes\nMinimum uptime (h) Minimum amount of time the generator must stay operational after starting up (in hours). For example, if the generator starts up at time 00:00 (h:min) and Minimum uptime (h) is set to 4, then the generator can only shut down at time 04:00. 1 No Yes\nMinimum downtime (h) Minimum amount of time the generator must stay offline after shutting down (in hours). For example, if the generator shuts down at time 00:00 (h:min) and Minimum downtime (h) is set to 4, then the generator can only start producing power again at time 04:00. 1 No Yes\nRamp up limit (MW) Maximum increase in production from one time step to the next (in MW). For example, if the generator is producing 100 MW at time step 1 and if this parameter is set to 40 MW, then the generator will produce at most 140 MW at time step 2. +inf No Yes\nRamp down limit (MW) Maximum decrease in production from one time step to the next (in MW). For example, if the generator is producing 100 MW at time step 1 and this parameter is set to 40 MW, then the generator will produce at least 60 MW at time step 2. +inf No Yes\nStartup limit (MW) Maximum amount of power a generator can produce immediately after starting up (in MW). For example, if Startup limit (MW) is set to 100 MW and the unit is off at time step 1, then it may produce at most 100 MW at time step 2. +inf No Yes\nShutdown limit (MW) Maximum amount of power a generator can produce immediately before shutting down (in MW). Specifically, the generator can only shut down at time step t+1 if its production at time step t is below this limit. +inf No Yes\nInitial status (h) If set to a positive number, indicates the amount of time (in hours) the generator has been on at the beginning of the simulation, and if set to a negative number, the amount of time the generator has been off. For example, if Initial status (h) is -2, this means that the generator was off since -02:00 (h:min). The simulation starts at time 00:00. If Initial status (h) is 3, this means that the generator was on since -03:00. A value of zero is not acceptable. Required No No\nInitial power (MW) Amount of power the generator at time step -1, immediately before the planning horizon starts. Required No No\nMust run? If true, the generator should be committed, even if that is not economical (Boolean). false Yes Yes\nReserve eligibility List of reserve products this generator is eligibe to provide. By default, the generator is not eligible to provide any reserves. [] No Yes\nCommitment status List of commitment status over the time horizon. At time t, if true, the generator must be commited at that time period; if false, the generator must not be commited at that time period. If null at time t, the generator's commitment status is then decided by the model. By default, the status is a list of null values. null Yes Yes","category":"page"},{"location":"guides/format/#Profiled-Units","page":"JSON data format","title":"Profiled Units","text":"","category":"section"},{"location":"guides/format/","page":"JSON data format","title":"JSON data format","text":"Key Description Default Time series? Uncertain?\nBus Identifier of the bus where this generator is located (string). Required No Yes\nType Type of the generator (string). For profiled generators, this must be Profiled. Required No No\nCost ($/MW) Cost incurred for serving each MW of power by this generator. Required Yes Yes\nMinimum power (MW) Minimum amount of power this generator may supply. 0.0 Yes Yes\nMaximum power (MW) Maximum amount of power this generator may supply. Required Yes Yes","category":"page"},{"location":"guides/format/#Production-costs-and-limits","page":"JSON data format","title":"Production costs and limits","text":"","category":"section"},{"location":"guides/format/","page":"JSON data format","title":"JSON data format","text":"Production costs are represented as piecewise-linear curves. Figure 1 shows an example cost curve with three segments, where it costs $1400, $1600, $2200 and $2400 to generate, respectively, 100, 110, 130 and 135 MW of power. To model this generator, Production cost curve (MW) should be set to [100, 110, 130, 135], and Production cost curve ($) should be set to [1400, 1600, 2200, 2400]. Note that this curve also specifies the production limits. Specifically, the first point identifies the minimum power output when the unit is operational, while the last point identifies the maximum power output.","category":"page"},{"location":"guides/format/","page":"JSON data format","title":"JSON data format","text":"
\n
\n Figure 1. Piecewise-linear production cost curve.
\n
\n","category":"page"},{"location":"guides/format/#Additional-remarks:","page":"JSON data format","title":"Additional remarks:","text":"","category":"section"},{"location":"guides/format/","page":"JSON data format","title":"JSON data format","text":"For time-dependent production limits or time-dependent production costs, the usage of nested arrays is allowed. For example, if Production cost curve (MW) is set to [5.0, [10.0, 12.0, 15.0, 20.0]], then the unit may generate at most 10, 12, 15 and 20 MW of power during time steps 1, 2, 3 and 4, respectively. The minimum output for all time periods is fixed to at 5 MW.\nThere is no limit to the number of piecewise-linear segments, and different generators may have a different number of segments.\nIf Production cost curve (MW) and Production cost curve ($) both contain a single element, then the generator must produce exactly that amount of power when operational. To specify that the generator may produce any amount of power up to a certain limit P, the parameter Production cost curve (MW) should be set to [0, P].\nProduction cost curves must be convex.","category":"page"},{"location":"guides/format/#Example-3","page":"JSON data format","title":"Example","text":"","category":"section"},{"location":"guides/format/","page":"JSON data format","title":"JSON data format","text":"{\n \"Generators\": {\n \"gen1\": {\n \"Bus\": \"b1\",\n \"Type\": \"Thermal\",\n \"Production cost curve (MW)\": [100.0, 110.0, 130.0, 135.0],\n \"Production cost curve ($)\": [1400.0, 1600.0, 2200.0, 2400.0],\n \"Startup costs ($)\": [300.0, 400.0],\n \"Startup delays (h)\": [1, 4],\n \"Ramp up limit (MW)\": 232.68,\n \"Ramp down limit (MW)\": 232.68,\n \"Startup limit (MW)\": 232.68,\n \"Shutdown limit (MW)\": 232.68,\n \"Minimum downtime (h)\": 4,\n \"Minimum uptime (h)\": 4,\n \"Initial status (h)\": 12,\n \"Initial power (MW)\": 115,\n \"Must run?\": false,\n \"Reserve eligibility\": [\"r1\"]\n },\n \"gen2\": {\n \"Bus\": \"b5\",\n \"Type\": \"Thermal\",\n \"Production cost curve (MW)\": [0.0, [10.0, 8.0, 0.0, 3.0]],\n \"Production cost curve ($)\": [0.0, 0.0],\n \"Initial status (h)\": -100,\n \"Initial power (MW)\": 0,\n \"Reserve eligibility\": [\"r1\", \"r2\"],\n \"Commitment status\": [true, false, null, true]\n },\n \"gen3\": {\n \"Bus\": \"b6\",\n \"Type\": \"Profiled\",\n \"Minimum power (MW)\": 10.0,\n \"Maximum power (MW)\": 120.0,\n \"Cost ($/MW)\": 100.0\n }\n }\n}","category":"page"},{"location":"guides/format/#Storage-units","page":"JSON data format","title":"Storage units","text":"","category":"section"},{"location":"guides/format/","page":"JSON data format","title":"JSON data format","text":"This section describes energy storage units in the system which charge and discharge power. The storage units consume power while charging, and generate power while discharging.","category":"page"},{"location":"guides/format/","page":"JSON data format","title":"JSON data format","text":"Key Description Default Time series? Uncertain?\nBus Bus where the storage unit is located. Multiple storage units may be placed at the same bus. Required No Yes\nMinimum level (MWh) Minimum of energy level this storage unit may contain. 0.0 Yes Yes\nMaximum level (MWh) Maximum of energy level this storage unit may contain. Required Yes Yes\nAllow simultaneous charging and discharging If false, the storage unit is not allowed to charge and discharge at the same time (Boolean). true Yes Yes\nCharge cost ($/MW) Cost incurred for charging each MW of power into this storage unit. Required Yes Yes\nDischarge cost ($/MW) Cost incurred for discharging each MW of power from this storage unit. Required Yes Yes\nCharge efficiency Efficiency rate to charge power into this storage unit. This value must be greater than or equal to 0.0, and less than or equal to 1.0. 1.0 Yes Yes\nDischarge efficiency Efficiency rate to discharge power from this storage unit. This value must be greater than or equal to 0.0, and less than or equal to 1.0. 1.0 Yes Yes\nLoss factor The energy dissipation rate of this storage unit. This value must be greater than or equal to 0.0, and less than or equal to 1.0. 0.0 Yes Yes\nMinimum charge rate (MW) Minimum amount of power rate this storage unit may charge. 0.0 Yes Yes\nMaximum charge rate (MW) Maximum amount of power rate this storage unit may charge. Required Yes Yes\nMinimum discharge rate (MW) Minimum amount of power rate this storage unit may discharge. 0.0 Yes Yes\nMaximum discharge rate (MW) Maximum amount of power rate this storage unit may discharge. Required Yes Yes\nInitial level (MWh) Amount of energy this storage unit at time step -1, immediately before the planning horizon starts. 0.0 No Yes\nLast period minimum level (MWh) Minimum of energy level this storage unit may contain in the last time step. By default, this value is the same as the last value of Minimum level (MWh). Minimum level (MWh) No Yes\nLast period maximum level (MWh) Maximum of energy level this storage unit may contain in the last time step. By default, this value is the same as the last value of Maximum level (MWh). Maximum level (MWh) No Yes","category":"page"},{"location":"guides/format/#Example-4","page":"JSON data format","title":"Example","text":"","category":"section"},{"location":"guides/format/","page":"JSON data format","title":"JSON data format","text":"{\n \"Storage units\": {\n \"su1\": {\n \"Bus\": \"b2\",\n \"Maximum level (MWh)\": 100.0,\n \"Charge cost ($/MW)\": 2.0,\n \"Discharge cost ($/MW)\": 2.5,\n \"Maximum charge rate (MW)\": 10.0,\n \"Maximum discharge rate (MW)\": 8.0\n },\n \"su2\": {\n \"Bus\": \"b2\",\n \"Minimum level (MWh)\": 10.0,\n \"Maximum level (MWh)\": 100.0,\n \"Allow simultaneous charging and discharging\": false,\n \"Charge cost ($/MW)\": 3.0,\n \"Discharge cost ($/MW)\": 3.5,\n \"Charge efficiency\": 0.8,\n \"Discharge efficiency\": 0.85,\n \"Loss factor\": 0.01,\n \"Minimum charge rate (MW)\": 5.0,\n \"Maximum charge rate (MW)\": 10.0,\n \"Minimum discharge rate (MW)\": 2.0,\n \"Maximum discharge rate (MW)\": 10.0,\n \"Initial level (MWh)\": 70.0,\n \"Last period minimum level (MWh)\": 80.0,\n \"Last period maximum level (MWh)\": 85.0\n },\n \"su3\": {\n \"Bus\": \"b9\",\n \"Minimum level (MWh)\": [10.0, 11.0, 12.0, 13.0],\n \"Maximum level (MWh)\": [100.0, 110.0, 120.0, 130.0],\n \"Allow simultaneous charging and discharging\": [false, false, true, true],\n \"Charge cost ($/MW)\": [2.0, 2.1, 2.2, 2.3],\n \"Discharge cost ($/MW)\": [1.0, 1.1, 1.2, 1.3],\n \"Charge efficiency\": [0.8, 0.81, 0.82, 0.82],\n \"Discharge efficiency\": [0.85, 0.86, 0.87, 0.88],\n \"Loss factor\": [0.01, 0.01, 0.02, 0.02],\n \"Minimum charge rate (MW)\": [5.0, 5.1, 5.2, 5.3],\n \"Maximum charge rate (MW)\": [10.0, 10.1, 10.2, 10.3],\n \"Minimum discharge rate (MW)\": [4.0, 4.1, 4.2, 4.3],\n \"Maximum discharge rate (MW)\": [8.0, 8.1, 8.2, 8.3],\n \"Initial level (MWh)\": 20.0,\n \"Last period minimum level (MWh)\": 21.0,\n \"Last period maximum level (MWh)\": 22.0\n }\n }\n}","category":"page"},{"location":"guides/format/#Price-sensitive-loads","page":"JSON data format","title":"Price-sensitive loads","text":"","category":"section"},{"location":"guides/format/","page":"JSON data format","title":"JSON data format","text":"This section describes components in the system which may increase or reduce their energy consumption according to the energy prices. Fixed loads (as described in the buses section) are always served, regardless of the price, unless there is significant congestion in the system or insufficient production capacity. Price-sensitive loads, on the other hand, are only served if it is economical to do so.","category":"page"},{"location":"guides/format/","page":"JSON data format","title":"JSON data format","text":"Key Description Default Time series? Uncertain?\nBus Bus where the load is located. Multiple price-sensitive loads may be placed at the same bus. Required No Yes\nRevenue ($/MW) Revenue obtained for serving each MW of power to this load. Required Yes Yes\nDemand (MW) Maximum amount of power required by this load. Any amount lower than this may be served. Required Yes Yes","category":"page"},{"location":"guides/format/#Example-5","page":"JSON data format","title":"Example","text":"","category":"section"},{"location":"guides/format/","page":"JSON data format","title":"JSON data format","text":"{\n \"Price-sensitive loads\": {\n \"p1\": {\n \"Bus\": \"b3\",\n \"Revenue ($/MW)\": 23.0,\n \"Demand (MW)\": 50.0\n }\n }\n}","category":"page"},{"location":"guides/format/#Transmission-lines","page":"JSON data format","title":"Transmission lines","text":"","category":"section"},{"location":"guides/format/","page":"JSON data format","title":"JSON data format","text":"This section describes the characteristics of transmission system, such as its topology and the susceptance of each transmission line.","category":"page"},{"location":"guides/format/","page":"JSON data format","title":"JSON data format","text":"Key Description Default Time series? Uncertain?\nSource bus Identifier of the bus where the transmission line originates. Required No Yes\nTarget bus Identifier of the bus where the transmission line reaches. Required No Yes\nSusceptance (S) Susceptance of the transmission line (in siemens). Required No Yes\nNormal flow limit (MW) Maximum amount of power (in MW) allowed to flow through the line when the system is in its regular, fully-operational state. +inf Yes Yes\nEmergency flow limit (MW) Maximum amount of power (in MW) allowed to flow through the line when the system is in degraded state (for example, after the failure of another transmission line). +inf Y Yes\nFlow limit penalty ($/MW) Penalty for violating the flow limits of the transmission line (in /MW). This is charged per time step. For example, if there is a thermal violation of 1 MW for three time steps, then three times this amount will be charged. 5000.0 Yes Yes","category":"page"},{"location":"guides/format/#Example-6","page":"JSON data format","title":"Example","text":"","category":"section"},{"location":"guides/format/","page":"JSON data format","title":"JSON data format","text":"{\n \"Transmission lines\": {\n \"l1\": {\n \"Source bus\": \"b1\",\n \"Target bus\": \"b2\",\n \"Susceptance (S)\": 29.49686,\n \"Normal flow limit (MW)\": 15000.0,\n \"Emergency flow limit (MW)\": 20000.0,\n \"Flow limit penalty ($/MW)\": 5000.0\n }\n }\n}","category":"page"},{"location":"guides/format/#Reserves","page":"JSON data format","title":"Reserves","text":"","category":"section"},{"location":"guides/format/","page":"JSON data format","title":"JSON data format","text":"This section describes the hourly amount of reserves required.","category":"page"},{"location":"guides/format/","page":"JSON data format","title":"JSON data format","text":"Key Description Default Time series? Uncertain?\nType Type of reserve product. Must be either \"spinning\" or \"flexiramp\". Required No No\nAmount (MW) Amount of reserves required. Required Yes Yes\nShortfall penalty ($/MW) Penalty for shortage in meeting the reserve requirements (in /MW). This is charged per time step. Negative value implies reserve constraints must always be satisfied. -1 Yes Yes","category":"page"},{"location":"guides/format/#Example-1","page":"JSON data format","title":"Example 1","text":"","category":"section"},{"location":"guides/format/","page":"JSON data format","title":"JSON data format","text":"{\n \"Reserves\": {\n \"r1\": {\n \"Type\": \"spinning\",\n \"Amount (MW)\": [57.30552, 53.88429, 51.31838, 50.46307],\n \"Shortfall penalty ($/MW)\": 5.0\n },\n \"r2\": {\n \"Type\": \"flexiramp\",\n \"Amount (MW)\": [20.31042, 23.65273, 27.41784, 25.34057]\n }\n }\n}","category":"page"},{"location":"guides/format/#Contingencies","page":"JSON data format","title":"Contingencies","text":"","category":"section"},{"location":"guides/format/","page":"JSON data format","title":"JSON data format","text":"This section describes credible contingency scenarios in the optimization, such as the loss of a transmission line or generator.","category":"page"},{"location":"guides/format/","page":"JSON data format","title":"JSON data format","text":"Key Description Default Uncertain?\nAffected generators List of generators affected by this contingency. May be omitted if no generators are affected. [] Yes\nAffected lines List of transmission lines affected by this contingency. May be omitted if no lines are affected. [] Yes","category":"page"},{"location":"guides/format/#Example-7","page":"JSON data format","title":"Example","text":"","category":"section"},{"location":"guides/format/","page":"JSON data format","title":"JSON data format","text":"{\n \"Contingencies\": {\n \"c1\": {\n \"Affected lines\": [\"l1\", \"l2\", \"l3\"],\n \"Affected generators\": [\"g1\"]\n },\n \"c2\": {\n \"Affected lines\": [\"l4\"]\n }\n }\n}","category":"page"},{"location":"guides/format/#Additional-remarks","page":"JSON data format","title":"Additional remarks","text":"","category":"section"},{"location":"guides/format/#Time-series-parameters","page":"JSON data format","title":"Time series parameters","text":"","category":"section"},{"location":"guides/format/","page":"JSON data format","title":"JSON data format","text":"Many numerical properties in the JSON file can be specified either as a single floating point number if they are time-independent, or as an array containing exactly T elements, if they are time-dependent, where T is the number of time steps in the planning horizon. For example, both formats below are valid when T=3:","category":"page"},{"location":"guides/format/","page":"JSON data format","title":"JSON data format","text":"{\n \"Load (MW)\": 800.0,\n \"Load (MW)\": [800.0, 850.0, 730.0]\n}","category":"page"},{"location":"guides/format/","page":"JSON data format","title":"JSON data format","text":"The value T depends on both Time horizon (h) and Time step (min), as the table below illustrates.","category":"page"},{"location":"guides/format/","page":"JSON data format","title":"JSON data format","text":"Time horizon (h) Time step (min) T\n24 60 24\n24 15 96\n24 5 288\n36 60 36\n36 15 144\n36 5 432","category":"page"},{"location":"guides/format/#Current-limitations","page":"JSON data format","title":"Current limitations","text":"","category":"section"},{"location":"guides/format/","page":"JSON data format","title":"JSON data format","text":"Network topology must remain the same for all time periods.\nOnly N-1 transmission contingencies are supported. Generator contingencies are not currently supported.\nTime-varying minimum production amounts are not currently compatible with ramp/startup/shutdown limits.\nFlexible ramping products can only be acquired under the WanHob2016 formulation, which does not support spinning reserves.\nThe set of generators must be the same in all scenarios.","category":"page"},{"location":"guides/instances/#Benchmark-instances","page":"Benchmark instances","title":"Benchmark instances","text":"","category":"section"},{"location":"guides/instances/","page":"Benchmark instances","title":"Benchmark instances","text":"UnitCommitment.jl provides a large collection of benchmark instances collected from the literature and converted to a common data format. In some cases, as indicated below, the original instances have been extended, with realistic parameters, using data-driven methods. If you use these instances in your research, we request that you cite UnitCommitment.jl, as well as the original sources, as listed below. Benchmark instances can be loaded with UnitCommitment.read_benchmark(name), as explained in the tutorials. Instance files can also be directly downloaded from our website.","category":"page"},{"location":"guides/instances/","page":"Benchmark instances","title":"Benchmark instances","text":"warning: Warning\nThe instances included in UC.jl are still under development and may change in the future. If you use these instances in your research, for reproducibility, you should specify what version of UC.jl they came from.","category":"page"},{"location":"guides/instances/#MATPOWER","page":"Benchmark instances","title":"MATPOWER","text":"","category":"section"},{"location":"guides/instances/","page":"Benchmark instances","title":"Benchmark instances","text":"MATPOWER is an open-source package for solving power flow problems in MATLAB and Octave. It contains a number of power flow test cases, which have been widely used in the power systems literature.","category":"page"},{"location":"guides/instances/","page":"Benchmark instances","title":"Benchmark instances","text":"Because most MATPOWER test cases were originally designed for power flow studies, they lack a number of important unit commitment parameters, such as time-varying loads, production cost curves, ramp limits, reserves and initial conditions. The test cases included in UnitCommitment.jl are extended versions of the original MATPOWER test cases, modified as following:","category":"page"},{"location":"guides/instances/","page":"Benchmark instances","title":"Benchmark instances","text":"Production cost curves were generated using a data-driven approach, based on publicly available data. More specifically, machine learning models were trained to predict typical production cost curves, for each day of the year, based on a generator's maximum and minimum power output.\nLoad profiles were generated using a similar data-driven approach.\nRamp-up, ramp-down, startup and shutdown rates were set to a fixed proportion of the generator's maximum output.\nMinimum reserves were set to a fixed proportion of the total demand.\nContingencies were set to include all N-1 transmission line contingencies that do not generate islands or isolated buses. More specifically, there is one contingency for each transmission line, as long as that transmission line is not a bridge in the network graph.","category":"page"},{"location":"guides/instances/","page":"Benchmark instances","title":"Benchmark instances","text":"For each MATPOWER test case, UC.jl provides 365 variations (2017-01-01 to 2017-12-31) corresponding different days of the year.","category":"page"},{"location":"guides/instances/#MATPOWER/UW-PSTCA","page":"Benchmark instances","title":"MATPOWER/UW-PSTCA","text":"","category":"section"},{"location":"guides/instances/","page":"Benchmark instances","title":"Benchmark instances","text":"A variety of smaller IEEE test cases, compiled by University of Washington, corresponding mostly to small portions of the American Electric Power System in the 1960s.","category":"page"},{"location":"guides/instances/","page":"Benchmark instances","title":"Benchmark instances","text":"Name Buses Generators Lines Contingencies References\nmatpower/case14/2017-01-01 14 5 20 19 [MTPWR, PSTCA]\nmatpower/case30/2017-01-01 30 6 41 38 [MTPWR, PSTCA]\nmatpower/case57/2017-01-01 57 7 80 79 [MTPWR, PSTCA]\nmatpower/case118/2017-01-01 118 54 186 177 [MTPWR, PSTCA]\nmatpower/case300/2017-01-01 300 69 411 320 [MTPWR, PSTCA]","category":"page"},{"location":"guides/instances/#MATPOWER/Polish","page":"Benchmark instances","title":"MATPOWER/Polish","text":"","category":"section"},{"location":"guides/instances/","page":"Benchmark instances","title":"Benchmark instances","text":"Test cases based on the Polish 400, 220 and 110 kV networks, originally provided by Roman Korab (Politechnika Śląska) and corrected by the MATPOWER team.","category":"page"},{"location":"guides/instances/","page":"Benchmark instances","title":"Benchmark instances","text":"Name Buses Generators Lines Contingencies References\nmatpower/case2383wp/2017-01-01 2383 323 2896 2240 [MTPWR]\nmatpower/case2736sp/2017-01-01 2736 289 3504 3159 [MTPWR]\nmatpower/case2737sop/2017-01-01 2737 267 3506 3161 [MTPWR]\nmatpower/case2746wop/2017-01-01 2746 443 3514 3155 [MTPWR]\nmatpower/case2746wp/2017-01-01 2746 457 3514 3156 [MTPWR]\nmatpower/case3012wp/2017-01-01 3012 496 3572 2854 [MTPWR]\nmatpower/case3120sp/2017-01-01 3120 483 3693 2950 [MTPWR]\nmatpower/case3375wp/2017-01-01 3374 590 4161 3245 [MTPWR]","category":"page"},{"location":"guides/instances/#MATPOWER/PEGASE","page":"Benchmark instances","title":"MATPOWER/PEGASE","text":"","category":"section"},{"location":"guides/instances/","page":"Benchmark instances","title":"Benchmark instances","text":"Test cases from the Pan European Grid Advanced Simulation and State Estimation (PEGASE) project, describing part of the European high voltage transmission network.","category":"page"},{"location":"guides/instances/","page":"Benchmark instances","title":"Benchmark instances","text":"Name Buses Generators Lines Contingencies References\nmatpower/case89pegase/2017-01-01 89 12 210 192 [JoFlMa16, FlPaCa13, MTPWR]\nmatpower/case1354pegase/2017-01-01 1354 260 1991 1288 [JoFlMa16, FlPaCa13, MTPWR]\nmatpower/case2869pegase/2017-01-01 2869 510 4582 3579 [JoFlMa16, FlPaCa13, MTPWR]\nmatpower/case9241pegase/2017-01-01 9241 1445 16049 13932 [JoFlMa16, FlPaCa13, MTPWR]\nmatpower/case13659pegase/2017-01-01 13659 4092 20467 13932 [JoFlMa16, FlPaCa13, MTPWR]","category":"page"},{"location":"guides/instances/#MATPOWER/RTE","page":"Benchmark instances","title":"MATPOWER/RTE","text":"","category":"section"},{"location":"guides/instances/","page":"Benchmark instances","title":"Benchmark instances","text":"Test cases from the R&D Division at Reseau de Transport d'Electricite representing the size and complexity of the French very high voltage transmission network.","category":"page"},{"location":"guides/instances/","page":"Benchmark instances","title":"Benchmark instances","text":"Name Buses Generators Lines Contingencies References\nmatpower/case1888rte/2017-01-01 1888 296 2531 1484 [MTPWR, JoFlMa16]\nmatpower/case1951rte/2017-01-01 1951 390 2596 1497 [MTPWR, JoFlMa16]\nmatpower/case2848rte/2017-01-01 2848 544 3776 2242 [MTPWR, JoFlMa16]\nmatpower/case2868rte/2017-01-01 2868 596 3808 2260 [MTPWR, JoFlMa16]\nmatpower/case6468rte/2017-01-01 6468 1262 9000 6094 [MTPWR, JoFlMa16]\nmatpower/case6470rte/2017-01-01 6470 1306 9005 6085 [MTPWR, JoFlMa16]\nmatpower/case6495rte/2017-01-01 6495 1352 9019 6060 [MTPWR, JoFlMa16]\nmatpower/case6515rte/2017-01-01 6515 1368 9037 6063 [MTPWR, JoFlMa16]","category":"page"},{"location":"guides/instances/#PGLIB-UC-Instances","page":"Benchmark instances","title":"PGLIB-UC Instances","text":"","category":"section"},{"location":"guides/instances/","page":"Benchmark instances","title":"Benchmark instances","text":"PGLIB-UC is a benchmark library curated and maintained by the IEEE PES Task Force on Benchmarks for Validation of Emerging Power System Algorithms. These test cases have been used in [KnOsWa20].","category":"page"},{"location":"guides/instances/#PGLIB-UC/California","page":"Benchmark instances","title":"PGLIB-UC/California","text":"","category":"section"},{"location":"guides/instances/","page":"Benchmark instances","title":"Benchmark instances","text":"Test cases based on publicly available data from the California ISO. For more details, see PGLIB-UC case file overview.","category":"page"},{"location":"guides/instances/","page":"Benchmark instances","title":"Benchmark instances","text":"Name Buses Generators Lines Contingencies References\npglib-uc/ca/2014-09-01_reserves_0 1 610 0 0 [KnOsWa20]\npglib-uc/ca/2014-09-01_reserves_1 1 610 0 0 [KnOsWa20]\npglib-uc/ca/2014-09-01_reserves_3 1 610 0 0 [KnOsWa20]\npglib-uc/ca/2014-09-01_reserves_5 1 610 0 0 [KnOsWa20]\npglib-uc/ca/2014-12-01_reserves_0 1 610 0 0 [KnOsWa20]\npglib-uc/ca/2014-12-01_reserves_1 1 610 0 0 [KnOsWa20]\npglib-uc/ca/2014-12-01_reserves_3 1 610 0 0 [KnOsWa20]\npglib-uc/ca/2014-12-01_reserves_5 1 610 0 0 [KnOsWa20]\npglib-uc/ca/2015-03-01_reserves_0 1 610 0 0 [KnOsWa20]\npglib-uc/ca/2015-03-01_reserves_1 1 610 0 0 [KnOsWa20]\npglib-uc/ca/2015-03-01_reserves_3 1 610 0 0 [KnOsWa20]\npglib-uc/ca/2015-03-01_reserves_5 1 610 0 0 [KnOsWa20]\npglib-uc/ca/2015-06-01_reserves_0 1 610 0 0 [KnOsWa20]\npglib-uc/ca/2015-06-01_reserves_1 1 610 0 0 [KnOsWa20]\npglib-uc/ca/2015-06-01_reserves_3 1 610 0 0 [KnOsWa20]\npglib-uc/ca/2015-06-01_reserves_5 1 610 0 0 [KnOsWa20]\npglib-uc/ca/Scenario400_reserves_0 1 611 0 0 [KnOsWa20]\npglib-uc/ca/Scenario400_reserves_1 1 611 0 0 [KnOsWa20]\npglib-uc/ca/Scenario400_reserves_3 1 611 0 0 [KnOsWa20]\npglib-uc/ca/Scenario400_reserves_5 1 611 0 0 [KnOsWa20]","category":"page"},{"location":"guides/instances/#PGLIB-UC/FERC","page":"Benchmark instances","title":"PGLIB-UC/FERC","text":"","category":"section"},{"location":"guides/instances/","page":"Benchmark instances","title":"Benchmark instances","text":"Test cases based on a publicly available unit commitment test case produced by the Federal Energy Regulatory Commission. For more details, see PGLIB-UC case file overview.","category":"page"},{"location":"guides/instances/","page":"Benchmark instances","title":"Benchmark instances","text":"Name Buses Generators Lines Contingencies References\npglib-uc/ferc/2015-01-01_hw 1 935 0 0 [KnOsWa20, KrHiOn12]\npglib-uc/ferc/2015-01-01_lw 1 935 0 0 [KnOsWa20, KrHiOn12]\npglib-uc/ferc/2015-02-01_hw 1 935 0 0 [KnOsWa20, KrHiOn12]\npglib-uc/ferc/2015-02-01_lw 1 935 0 0 [KnOsWa20, KrHiOn12]\npglib-uc/ferc/2015-03-01_hw 1 935 0 0 [KnOsWa20, KrHiOn12]\npglib-uc/ferc/2015-03-01_lw 1 935 0 0 [KnOsWa20, KrHiOn12]\npglib-uc/ferc/2015-04-01_hw 1 979 0 0 [KnOsWa20, KrHiOn12]\npglib-uc/ferc/2015-04-01_lw 1 979 0 0 [KnOsWa20, KrHiOn12]\npglib-uc/ferc/2015-05-01_hw 1 979 0 0 [KnOsWa20, KrHiOn12]\npglib-uc/ferc/2015-05-01_lw 1 979 0 0 [KnOsWa20, KrHiOn12]\npglib-uc/ferc/2015-06-01_hw 1 979 0 0 [KnOsWa20, KrHiOn12]\npglib-uc/ferc/2015-06-01_lw 1 979 0 0 [KnOsWa20, KrHiOn12]\npglib-uc/ferc/2015-07-01_hw 1 979 0 0 [KnOsWa20, KrHiOn12]\npglib-uc/ferc/2015-07-01_lw 1 979 0 0 [KnOsWa20, KrHiOn12]\npglib-uc/ferc/2015-08-01_hw 1 979 0 0 [KnOsWa20, KrHiOn12]\npglib-uc/ferc/2015-08-01_lw 1 979 0 0 [KnOsWa20, KrHiOn12]\npglib-uc/ferc/2015-09-01_hw 1 979 0 0 [KnOsWa20, KrHiOn12]\npglib-uc/ferc/2015-09-01_lw 1 979 0 0 [KnOsWa20, KrHiOn12]\npglib-uc/ferc/2015-10-01_hw 1 935 0 0 [KnOsWa20, KrHiOn12]\npglib-uc/ferc/2015-10-01_lw 1 935 0 0 [KnOsWa20, KrHiOn12]\npglib-uc/ferc/2015-11-02_hw 1 935 0 0 [KnOsWa20, KrHiOn12]\npglib-uc/ferc/2015-11-02_lw 1 935 0 0 [KnOsWa20, KrHiOn12]\npglib-uc/ferc/2015-12-01_hw 1 935 0 0 [KnOsWa20, KrHiOn12]\npglib-uc/ferc/2015-12-01_lw 1 935 0 0 [KnOsWa20, KrHiOn12]","category":"page"},{"location":"guides/instances/#PGLIB-UC/RTS-GMLC","page":"Benchmark instances","title":"PGLIB-UC/RTS-GMLC","text":"","category":"section"},{"location":"guides/instances/","page":"Benchmark instances","title":"Benchmark instances","text":"RTS-GMLC is an updated version of the RTS-96 test system produced by the United States Department of Energy's Grid Modernization Laboratory Consortium. The PGLIB-UC/RTS-GMLC instances are modified versions of the original RTS-GMLC instances, with modified ramp-rates and without a transmission network. For more details, see PGLIB-UC case file overview.","category":"page"},{"location":"guides/instances/","page":"Benchmark instances","title":"Benchmark instances","text":"Name Buses Generators Lines Contingencies References\npglib-uc/rts_gmlc/2020-01-27 1 154 0 0 [BaBlEh19]\npglib-uc/rts_gmlc/2020-02-09 1 154 0 0 [BaBlEh19]\npglib-uc/rts_gmlc/2020-03-05 1 154 0 0 [BaBlEh19]\npglib-uc/rts_gmlc/2020-04-03 1 154 0 0 [BaBlEh19]\npglib-uc/rts_gmlc/2020-05-05 1 154 0 0 [BaBlEh19]\npglib-uc/rts_gmlc/2020-06-09 1 154 0 0 [BaBlEh19]\npglib-uc/rts_gmlc/2020-07-06 1 154 0 0 [BaBlEh19]\npglib-uc/rts_gmlc/2020-08-12 1 154 0 0 [BaBlEh19]\npglib-uc/rts_gmlc/2020-09-20 1 154 0 0 [BaBlEh19]\npglib-uc/rts_gmlc/2020-10-27 1 154 0 0 [BaBlEh19]\npglib-uc/rts_gmlc/2020-11-25 1 154 0 0 [BaBlEh19]\npglib-uc/rts_gmlc/2020-12-23 1 154 0 0 [BaBlEh19]","category":"page"},{"location":"guides/instances/#OR-LIB/UC","page":"Benchmark instances","title":"OR-LIB/UC","text":"","category":"section"},{"location":"guides/instances/","page":"Benchmark instances","title":"Benchmark instances","text":"OR-LIB is a collection of test data sets for a variety of operations research problems, including unit commitment. The UC instances in OR-LIB are synthetic instances generated by a random problem generator developed by the Operations Research Group at University of Pisa. These test cases have been used in [FrGe06] and many other publications.","category":"page"},{"location":"guides/instances/","page":"Benchmark instances","title":"Benchmark instances","text":"Name Hours Buses Generators Lines Contingencies References\nor-lib/10_0_1_w 24 1 10 0 0 [ORLIB, FrGe06]\nor-lib/10_0_2_w 24 1 10 0 0 [ORLIB, FrGe06]\nor-lib/10_0_3_w 24 1 10 0 0 [ORLIB, FrGe06]\nor-lib/10_0_4_w 24 1 10 0 0 [ORLIB, FrGe06]\nor-lib/10_0_5_w 24 1 10 0 0 [ORLIB, FrGe06]\nor-lib/20_0_1_w 24 1 20 0 0 [ORLIB, FrGe06]\nor-lib/20_0_2_w 24 1 20 0 0 [ORLIB, FrGe06]\nor-lib/20_0_3_w 24 1 20 0 0 [ORLIB, FrGe06]\nor-lib/20_0_4_w 24 1 20 0 0 [ORLIB, FrGe06]\nor-lib/20_0_5_w 24 1 20 0 0 [ORLIB, FrGe06]\nor-lib/50_0_1_w 24 1 50 0 0 [ORLIB, FrGe06]\nor-lib/50_0_2_w 24 1 50 0 0 [ORLIB, FrGe06]\nor-lib/50_0_3_w 24 1 50 0 0 [ORLIB, FrGe06]\nor-lib/50_0_4_w 24 1 50 0 0 [ORLIB, FrGe06]\nor-lib/50_0_5_w 24 1 50 0 0 [ORLIB, FrGe06]\nor-lib/75_0_1_w 24 1 75 0 0 [ORLIB, FrGe06]\nor-lib/75_0_2_w 24 1 75 0 0 [ORLIB, FrGe06]\nor-lib/75_0_3_w 24 1 75 0 0 [ORLIB, FrGe06]\nor-lib/75_0_4_w 24 1 75 0 0 [ORLIB, FrGe06]\nor-lib/75_0_5_w 24 1 75 0 0 [ORLIB, FrGe06]\nor-lib/100_0_1_w 24 1 100 0 0 [ORLIB, FrGe06]\nor-lib/100_0_2_w 24 1 100 0 0 [ORLIB, FrGe06]\nor-lib/100_0_3_w 24 1 100 0 0 [ORLIB, FrGe06]\nor-lib/100_0_4_w 24 1 100 0 0 [ORLIB, FrGe06]\nor-lib/100_0_5_w 24 1 100 0 0 [ORLIB, FrGe06]\nor-lib/150_0_1_w 24 1 150 0 0 [ORLIB, FrGe06]\nor-lib/150_0_2_w 24 1 150 0 0 [ORLIB, FrGe06]\nor-lib/150_0_3_w 24 1 150 0 0 [ORLIB, FrGe06]\nor-lib/150_0_4_w 24 1 150 0 0 [ORLIB, FrGe06]\nor-lib/150_0_5_w 24 1 150 0 0 [ORLIB, FrGe06]\nor-lib/200_0_10_w 24 1 200 0 0 [ORLIB, FrGe06]\nor-lib/200_0_11_w 24 1 200 0 0 [ORLIB, FrGe06]\nor-lib/200_0_12_w 24 1 200 0 0 [ORLIB, FrGe06]\nor-lib/200_0_1_w 24 1 200 0 0 [ORLIB, FrGe06]\nor-lib/200_0_2_w 24 1 200 0 0 [ORLIB, FrGe06]\nor-lib/200_0_3_w 24 1 200 0 0 [ORLIB, FrGe06]\nor-lib/200_0_4_w 24 1 200 0 0 [ORLIB, FrGe06]\nor-lib/200_0_5_w 24 1 200 0 0 [ORLIB, FrGe06]\nor-lib/200_0_6_w 24 1 200 0 0 [ORLIB, FrGe06]\nor-lib/200_0_7_w 24 1 200 0 0 [ORLIB, FrGe06]\nor-lib/200_0_8_w 24 1 200 0 0 [ORLIB, FrGe06]\nor-lib/200_0_9_w 24 1 200 0 0 [ORLIB, FrGe06]","category":"page"},{"location":"guides/instances/#Tejada19","page":"Benchmark instances","title":"Tejada19","text":"","category":"section"},{"location":"guides/instances/","page":"Benchmark instances","title":"Benchmark instances","text":"Test cases used in [TeLuSa19]. These instances are similar to OR-LIB/UC, in the sense that they use the same random problem generator, but are much larger.","category":"page"},{"location":"guides/instances/","page":"Benchmark instances","title":"Benchmark instances","text":"Name Hours Buses Generators Lines Contingencies References\ntejada19/UC_24h_214g 24 1 214 0 0 [TeLuSa19]\ntejada19/UC_24h_250g 24 1 250 0 0 [TeLuSa19]\ntejada19/UC_24h_290g 24 1 290 0 0 [TeLuSa19]\ntejada19/UC_24h_480g 24 1 480 0 0 [TeLuSa19]\ntejada19/UC_24h_505g 24 1 505 0 0 [TeLuSa19]\ntejada19/UC_24h_623g 24 1 623 0 0 [TeLuSa19]\ntejada19/UC_24h_647g 24 1 647 0 0 [TeLuSa19]\ntejada19/UC_24h_836g 24 1 836 0 0 [TeLuSa19]\ntejada19/UC_24h_850g 24 1 850 0 0 [TeLuSa19]\ntejada19/UC_24h_918g 24 1 918 0 0 [TeLuSa19]\ntejada19/UC_24h_931g 24 1 931 0 0 [TeLuSa19]\ntejada19/UC_24h_940g 24 1 940 0 0 [TeLuSa19]\ntejada19/UC_24h_957g 24 1 957 0 0 [TeLuSa19]\ntejada19/UC_24h_959g 24 1 959 0 0 [TeLuSa19]\ntejada19/UC_24h_1069g 24 1 1069 0 0 [TeLuSa19]\ntejada19/UC_24h_1130g 24 1 1130 0 0 [TeLuSa19]\ntejada19/UC_24h_1376g 24 1 1376 0 0 [TeLuSa19]\ntejada19/UC_24h_1393g 24 1 1393 0 0 [TeLuSa19]\ntejada19/UC_24h_1577g 24 1 1577 0 0 [TeLuSa19]\ntejada19/UC_24h_1615g 24 1 1615 0 0 [TeLuSa19]\ntejada19/UC_24h_1632g 24 1 1632 0 0 [TeLuSa19]\ntejada19/UC_24h_1768g 24 1 1768 0 0 [TeLuSa19]\ntejada19/UC_24h_1804g 24 1 1804 0 0 [TeLuSa19]\ntejada19/UC_24h_1820g 24 1 1820 0 0 [TeLuSa19]\ntejada19/UC_24h_1823g 24 1 1823 0 0 [TeLuSa19]\ntejada19/UC_24h_1888g 24 1 1888 0 0 [TeLuSa19]\ntejada19/UC_168h_36g 168 1 36 0 0 [TeLuSa19]\ntejada19/UC_168h_38g 168 1 38 0 0 [TeLuSa19]\ntejada19/UC_168h_40g 168 1 40 0 0 [TeLuSa19]\ntejada19/UC_168h_53g 168 1 53 0 0 [TeLuSa19]\ntejada19/UC_168h_58g 168 1 58 0 0 [TeLuSa19]\ntejada19/UC_168h_59g 168 1 59 0 0 [TeLuSa19]\ntejada19/UC_168h_72g 168 1 72 0 0 [TeLuSa19]\ntejada19/UC_168h_84g 168 1 84 0 0 [TeLuSa19]\ntejada19/UC_168h_86g 168 1 86 0 0 [TeLuSa19]\ntejada19/UC_168h_88g 168 1 88 0 0 [TeLuSa19]\ntejada19/UC_168h_93g 168 1 93 0 0 [TeLuSa19]\ntejada19/UC_168h_105g 168 1 105 0 0 [TeLuSa19]\ntejada19/UC_168h_110g 168 1 110 0 0 [TeLuSa19]\ntejada19/UC_168h_125g 168 1 125 0 0 [TeLuSa19]\ntejada19/UC_168h_130g 168 1 130 0 0 [TeLuSa19]\ntejada19/UC_168h_131g 168 1 131 0 0 [TeLuSa19]\ntejada19/UC_168h_140g 168 1 140 0 0 [TeLuSa19]\ntejada19/UC_168h_165g 168 1 165 0 0 [TeLuSa19]\ntejada19/UC_168h_175g 168 1 175 0 0 [TeLuSa19]\ntejada19/UC_168h_179g 168 1 179 0 0 [TeLuSa19]\ntejada19/UC_168h_188g 168 1 188 0 0 [TeLuSa19]\ntejada19/UC_168h_192g 168 1 192 0 0 [TeLuSa19]\ntejada19/UC_168h_199g 168 1 199 0 0 [TeLuSa19]","category":"page"},{"location":"guides/instances/#References","page":"Benchmark instances","title":"References","text":"","category":"section"},{"location":"guides/instances/","page":"Benchmark instances","title":"Benchmark instances","text":"[UCJL] Alinson S. Xavier, Aleksandr M. Kazachkov, Ogün Yurdakul, Feng Qiu. \"UnitCommitment.jl: A Julia/JuMP Optimization Package for Security-Constrained Unit Commitment (Version 0.3)\". Zenodo (2022). DOI: 10.5281/zenodo.4269874\n[KnOsWa20] Bernard Knueven, James Ostrowski and Jean-Paul Watson. \"On Mixed-Integer Programming Formulations for the Unit Commitment Problem\". INFORMS Journal on Computing (2020). DOI: 10.1287/ijoc.2019.0944\n[KrHiOn12] Eric Krall, Michael Higgins and Richard P. O’Neill. \"RTO unit commitment test system.\" Federal Energy Regulatory Commission. Available at: https://www.ferc.gov/industries-data/electric/power-sales-and-markets/increasing-efficiency-through-improved-software-1 (Accessed: Nov 14, 2020)\n[BaBlEh19] Clayton Barrows, Aaron Bloom, Ali Ehlen, Jussi Ikaheimo, Jennie Jorgenson, Dheepak Krishnamurthy, Jessica Lau et al. \"The IEEE Reliability Test System: A Proposed 2019 Update.\" IEEE Transactions on Power Systems (2019). DOI: 10.1109/TPWRS.2019.2925557\n[JoFlMa16] C. Josz, S. Fliscounakis, J. Maeght, and P. Panciatici. \"AC Power Flow Data in MATPOWER and QCQP Format: iTesla, RTE Snapshots, and PEGASE\". ArXiv (2016).\n[FlPaCa13] S. Fliscounakis, P. Panciatici, F. Capitanescu, and L. Wehenkel. \"Contingency ranking with respect to overloads in very large power systems taking into account uncertainty, preventive and corrective actions\", Power Systems, IEEE Trans. on, (28)4:4909-4917, 2013. DOI: 10.1109/TPWRS.2013.2251015\n[MTPWR] D. Zimmerman, C. E. Murillo-Sandnchez and R. J. Thomas. \"Matpower: Steady-state operations, planning, and analysis tools forpower systems research and education\", IEEE Transactions on PowerSystems, vol. 26, no. 1, pp. 12 –19, Feb. 2011. DOI: 10.1109/TPWRS.2010.2051168\n[PSTCA] University of Washington, Dept. of Electrical Engineering. \"Power Systems Test Case Archive\". Available at: http://www.ee.washington.edu/research/pstca/ (Accessed: Nov 14, 2020)\n[ORLIB] J.E.Beasley. \"OR-Library: distributing test problems by electronic mail\", Journal of the Operational Research Society 41(11) (1990). DOI: 10.2307/2582903\n[FrGe06] A. Frangioni, C. Gentile. \"Solving nonlinear single-unit commitment problems with ramping constraints\" Operations Research 54(4), p. 767 - 775, 2006. DOI: 10.1287/opre.1060.0309\n[TeLuSa19] D. A. Tejada-Arango, S. Lumbreras, P. Sanchez-Martin and A. Ramos. \"Which Unit-Commitment Formulation is Best? A Systematic Comparison,\" in IEEE Transactions on Power Systems. DOI: 10.1109/TPWRS.2019.2962024.","category":"page"},{"location":"guides/problem/#Problem-definition","page":"Problem definition","title":"Problem definition","text":"","category":"section"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"The Security-Constrained Unit Commitment Problem (SCUC) is formulated in UC.jl as a two-stage stochastic mixed-integer linear optimization problem that aims to find the minimum-cost schedule for electricity generation while satisfying various physical, operational and economic constraints. In its most basic form, the problem is composed by:","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"A set of generators, which produce power, at a given cost;\nA set of loads, which consume power;\nA transmission network, which delivers power from generators to the loads.","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"In addition to the basic components above, SCUC also include a wide variety of additional components, such as energy storage devices, reserves and network interfaces, to name a few. On this page, we present a complete definition of the problem, as modeled in UC.jl. Please note that different sources in the literature may have significantly different definitions and assumptions.","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"note: Note\nUC.jl treats deterministic SCUC instances as a special case of the stochastic problem in which there is only one scenario, named \"s1\" by default. To access second-stage decisions, therefore, you must provide this scenario name as the value for s. For example, model[:prod_above][\"s1\", g, t].","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"warning: Warning\nThe problem definition presented in this page is mathematically equivalent to the one solved by UC.jl. However, some constraints (ramping, piecewise-linear costs and start-up costs) have been simplified in this page for clarity. The set of constraints actually enforced by UC.jl better describes the convex hull of the problem and leads to better computational performance, but it is much more complex to describe. For further details, we refer to the package's source code and associated references.","category":"page"},{"location":"guides/problem/#1.-General-modeling-assumptions","page":"Problem definition","title":"1. General modeling assumptions","text":"","category":"section"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Time discretization: SCUC is a multi-period problem, with decisions typically covering a 24-hour or 36-hour time window. UC.jl assumes that this time window is discretized into time steps of fixed length. The number of time steps, as well as the duration of each time step, are configurable. In the equations below, the set of time steps is denoted by T=12ldotsT.\nDecision under uncertainty: SCUC is a two-stage stochastic problem. In the first stage, we must decide the commitment status of all thermal generators. In the second stage, we determine the remaining decision variables, such power output of all generators, the operation of energy storage devices and load shedding. Stochasticity is modeled through a discrete number of scenarios s in S, each with given probability p(S). The goal is to minimize the minimum expected cost.","category":"page"},{"location":"guides/problem/#2.-Thermal-generators","page":"Problem definition","title":"2. Thermal generators","text":"","category":"section"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"A thermal generator is a power generation unit that converts thermal energy, typically from the combustion of coal, natural gas or oil, into electrical energy. Scheduling thermal generators is particularly complex due to their operational characteristics, including minimum up and down times, ramping rates, and start-up and shutdown limits.","category":"page"},{"location":"guides/problem/#Important-concepts","page":"Problem definition","title":"Important concepts","text":"","category":"section"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Commitment, power output and startup costs: Thermal generators can either be online (on) or offline (off). When a thermal generator is on, it can produce between a minimum and a maximum amount of power; when it is off, it cannot produce any power. Switching a generator on incurs a startup cost, which depends on how long the unit has been offline. More precisely, each thermal generator g has a number K^start_g of startup categories (e.g., cold, warm and hot). Each category k has a corresponding startup cost Z^textstart_gk, and is available only if the unit has spent at most M^textdelay_gk time steps offline.\nPiecewise-linear production cost curve: Besides startup costs, thermal generators also incur production costs based on their power output. The relationship between production cost and power output is not a linear, but a convex curve, which is simplified using a piecewise-linear approximation. For this purpose, each thermal generator g has a number K^textcost_g of piecewise-linear segments and its power output y^textprod-above_gts are broken down into sum_k=1^K^textcost_g y^textseg-prod_gtks, so that production costs can be more easily calculated.\nRamping, minimum up/down: Due to physical and operational limits, such as thermal inertia and mechanical stress, thermal generators cannot vary their power output too dramatically from one time period to the next. Similarly, thermal generators cannot switch on and off too frequently; after switching on or off, units must remain at that state for a minimum specified number of time steps.\nStartup and shutdown limit: A thermal generator cannot shut off if its output power level in the immediately preceding time step is very high (above a specified value); the unit must first ramp down, over potentially multiple time steps, and only then shut off. Similarly, the unit cannot produce a very large amount of power (above a specified limit) immediately after starting up; it must ramp up over potentially multiple time steps.\nInitial status: The optimization process finds optimal commitment status and power output level for all thermal generators starting at time period 1. Many constraints, however, require knowledge of previous time periods (0, -1, -2, ...) which are not part of the optimization model. For this reason, part of the input data is the initial power output M^textinit-power_g of unit g (that is, the output at time 0) and the initial status M^textinit-status_g of unit g (how many time steps has it been online/offline at time time 0). If M^textinit-status_g is positive, its magnitude indicates how many time periods has the unit been online; and if negative, how has it been offline.\nMust-run: Due to various factors, including reliability considerations, some units must remain operational regardless of whether it is economical for them to do so. Must-run constraints are used to enforce such requirements.","category":"page"},{"location":"guides/problem/#Sets-and-constants","page":"Problem definition","title":"Sets and constants","text":"","category":"section"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Symbol Unit Description\nK^cost_g Number of piecewise linear segments in the production cost curve.\nK^start_g Number of startup categories (e.g. cold, warm, hot).\nM^textdelay_gk Delay for startup category k.\nM^textinit-power_g MW Initial power output of unit g.\nM^textinit-status_g Initial status of unit g.\nM^textmin-up_g Minimum amount of time g must stay on after switching on.\nM^textmust-run_gt Binary One if unit g must be on at time t.\nM^textpmax_gt MW Maximum power output at time t.\nM^textpmin_gt MW Minimum power output at time t.\nM^textramp-down_g MW Ramp down limit.\nM^textramp-up_g MW Ramp up limit.\nM^textseg-pmax_gtks MW Maximum power output for piecewise-linear segment k at time t and scenario s.\nM^textshutdown-limit_g MW Maximum power unit g produces immediately before shutting down\nM^textstartup-limit_g MW Maximum power unit g produces immediately after starting up\nR_g Set of spinning reserves that may be served by g.\nZ^textpmin_gt $ Cost to keep g operational at time t generating at minimum power.\nZ^textpvar_gtks $/MW Cost for unit g to produce 1 MW of power under piecewise-linear segment k at time t.\nZ^textstart_gk $ Cost to start unit g at startup category k.\nG^texttherm Set of thermal generators.","category":"page"},{"location":"guides/problem/#Decision-variables","page":"Problem definition","title":"Decision variables","text":"","category":"section"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Symbol JuMP name Description Unit Stage\nx^textis-on_gt is_on[g,t] One if generator g is on at time t. Binary 1\nx^textswitch-on_gt switch_on[g,t] One if generator g switches on at time t. Binary 1\nx^textswitch-off_gt switch_off[g,t] One if generator g switches off at time t. Binary 1\nx^textstart_gtk startup[g,t,s] One if generator g starts up at time t under startup category k. Binary 1\ny^textprod-above_gts prod_above[s,g,t] Amount of power produced by g at time t in scenario s above the minimum power. MW 2\ny^textseg-prod_gtks segprod[s,g,t,k] Amount of power produced by g at time t in piecewise-linear segment k and scenario s. MW 2\ny^textres_grts reserve[s,r,g,t] Amount of spinning reserve r supplied by g at time t in scenario s. MW 2","category":"page"},{"location":"guides/problem/#Objective-function-terms","page":"Problem definition","title":"Objective function terms","text":"","category":"section"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Production costs:","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"sum_g in G^texttherm sum_t in T x^textis-on_gt Z^textpmin_gt\n+ sum_s in S p(s) left\n sum_g in G^texttherm sum_t in T sum_k=1^K^cost_g\n y^textseg-prod_gtks Z^textpvar_gtks\nright","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Start-up costs:","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"sum_g in G sum_t in T sum_k=1^K^start_g x^textstart_gtk Z^textstart_gk","category":"page"},{"location":"guides/problem/#Constraints","page":"Problem definition","title":"Constraints","text":"","category":"section"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Some units must remain on, even if it is not economical for them to do so:","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"x^textis-on_gt geq M^textmust-run_gt","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"After switching on, unit must remain on for some amount of time (eq_min_uptime[g,t]):","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"sum_i=max(1t-M^textmin-up_g+1)^t x^textswitch-on_gi leq x^textis-on_gt","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Same as above, but covering the initial time steps (eq_min_uptime[g,0]):","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"sum_i=1^min(TM^textmin-up_g-M^textinit-status_g) x^textswitch-off_gi = 0 text if M^textinit-status_g 0","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"After switching off, unit must remain offline for some amount of time (eq_min_downtime[g,t]):","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"sum_i=max(1t-M^textmin-down_g+1)^t x^textswitch-off_gi leq 1 - x^textis-on_gt","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Same as above, but covering the initial time steps (eq_min_downtime[g,0]):","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"sum_i=1^min(TM^textmin-down_g+M^textinit-status_g) x^textswitch-on_gi = 0 text if M^textinit-status_g 0","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"If the unit switches on, it must choose exactly one startup category (eq_startup_choose[g,t]):","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"x^textswitch-on_gt = sum_k=1^K^start_g x^textstart_gtk","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"If unit has not switched off in the last \"delay\" time periods, then startup category is forbidden (eq_startup_restrict[g,t,s]). The last startup category is always allowed. In the equation below, L^textstart_gtk=1 if category should be allowed based on initial status.","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"x^textstart_gtk leq L^textstart_gtk + sum_i=minleft(1t - M^textdelay_gk+1 + 1right)^t - M^textdelay_kg x^textswitch-off_gi","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Link the binary variables together (eq_binary_link[g,t]):","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"beginalign*\n x^textis-on_gt - x^textis-on_gt-1 = x^textswitch-on_gt - x^textswitch-off_gt forall t 1 \nendalign*","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Cannot switch on and off at the same time (eq_switch_on_off[g,t]):","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"x^textswitch-on_gt + x^textswitch-off_gt leq 1","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"If the unit is off, it cannot produce power or provide reserves. If it is on, it must to so within the specified production limits (eq_prod_limit[s,g,t]):","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"y^textprod-above_gts + sum_r in R_g y^textres_grts leq\n(M^textpmax_gt - M^textpmin_gt) x^textis-on_gt","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Break down the \"production above\" variable into smaller \"segment production\" variables, to simplify the objective function (eq_prod_above_def[s,g,t]):","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"y^textprod-above_gts = sum_k=1^K^cost_g y^textseg-prod_gtks","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Impose upper limit on segment production variables (eq_segprod_limit[s,g,t,k]):","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"0 leq y^textseg-prod_gtks leq M^textseg-pmax_gtks","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Unit cannot increase its production too quickly (eq_ramp_up[s,g,t]):","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"y^textprod-above_gts + sum_r in R_g y^textres_grts leq\ny^textprod-above_gt-1s + M^textramp-up_g","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Same as above, for initial time (eq_ramp_up[s,g,1]):","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"y^textprod-above_g1s + sum_r in R_g y^textres_gr1s leq\nleft(M^textinit-power_g - M^textpmin_gtright) + M^textramp-up_g","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Unit cannot decrease its production too quickly (eq_ramp_down[s,g,t]):","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"y^textprod-above_gts geq\ny^textprod-above_gt-1s - M^textramp-down_g","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Same as above, for initial time (eq_ramp_down[s,g,1]):","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"y^textprod-above_g1s geq\nleft(M^textinit-power_g - M^textpmin_gtright) - M^textramp-down_g","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Unit cannot produce excessive amount of power immediately after starting up (eq_startup_limit[s,g,t]):","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"y^textprod-above_gts + sum_r in R_g y^textres_grts leq\n(M^textpmax_gt - M^textpmin_gt) x^textis-on_gt -\nmaxleft0M^textpmax_gt - M^textstartup-limit_gright\nx^textswitch-on_gt","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Unit cannot shutoff it it's producing too much power (eq_shutdown_limit[s,g,t]):","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"y^textprod-above_gts leq\n(M^textpmax_gt - M^textpmin_gt) x^textis-on_gt -\nmaxleft0M^textpmax_gt - M^textshutdown-limit_gright\nx^textswitch-off_gt+1","category":"page"},{"location":"guides/problem/#3.-Profiled-generators","page":"Problem definition","title":"3. Profiled generators","text":"","category":"section"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"A profiled generator is a simplified generator model that can be used to represent renewable energy resources, including wind, solar and hydro. Unlike thermal generators, which can be either on or off, profiled generators do not have status variables; the only optimization decision is on their power output level, which must remain between minimum and maximum time-varying amounts. Production cost curves for profiled generators are linear, making them again much simpler than thermal units.","category":"page"},{"location":"guides/problem/#Constants","page":"Problem definition","title":"Constants","text":"","category":"section"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Symbol Unit Description\nM^textpmax_sgt MW Maximum power output at time t and scenario s.\nM^textpmin_sgt MW Minimum power output at time t and scenario s.\nZ^textpvar_sgt $/MW Generation cost at time t and scenario s.","category":"page"},{"location":"guides/problem/#Decision-variables-2","page":"Problem definition","title":"Decision variables","text":"","category":"section"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Symbol JuMP name Unit Description Stage\ny^textprod_sgt prod_profiled[s,g,t] MW Amount of power produced by g in time t and scenario s. 2","category":"page"},{"location":"guides/problem/#Objective-function-terms-2","page":"Problem definition","title":"Objective function terms","text":"","category":"section"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Production cost:","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"sum_s in S p(s) left\n sum_t in T y^textprod_sgt Z^textpvar_sgt\nright","category":"page"},{"location":"guides/problem/#Constraints-2","page":"Problem definition","title":"Constraints","text":"","category":"section"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Variable bounds:","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"M^textpmin_sgt leq y^textprod_sgt leq M^textpmax_sgt","category":"page"},{"location":"guides/problem/#4.-Conventional-loads","page":"Problem definition","title":"4. Conventional loads","text":"","category":"section"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Loads represent the demand for electrical power by consumers and devices connected to the system. This section describes conventional (or inelastic) loads, which are not sensitive to changes in electricity prices, and must always be served. Each bus in the transmission network has exactly one load; multiple loads in the same bus can be modelled by aggregating them. If there is not enough production or transmission capacity to serve all loads, some load can be curtailed, at a penalty.","category":"page"},{"location":"guides/problem/#Constants-2","page":"Problem definition","title":"Constants","text":"","category":"section"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Symbol Unit Description\nM^textload_sbt MW Conventional load on bus b at time s and scenario s.\nZ^textcurtail_st $/MW Load curtailment penalty at time t in scenario s.","category":"page"},{"location":"guides/problem/#Decision-variables-3","page":"Problem definition","title":"Decision variables","text":"","category":"section"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Symbol JuMP name Unit Description Stage\ny^textcurtail_sbt curtail[s,b,t] MW Amount of load curtailed at bus b in time t and scenario s 2","category":"page"},{"location":"guides/problem/#Objective-function-terms-3","page":"Problem definition","title":"Objective function terms","text":"","category":"section"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Load curtailment penalty:","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"sum_s in S p(s) left\n sum_b in B sum_t in T y^textcurtail_sbt Z^textcurtail_ts\nright","category":"page"},{"location":"guides/problem/#Constraints-3","page":"Problem definition","title":"Constraints","text":"","category":"section"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Variable bounds:","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"0 leq y^textcurtail_sbt leq M^textload_bts","category":"page"},{"location":"guides/problem/#5.-Price-sensitive-loads","page":"Problem definition","title":"5. Price-sensitive loads","text":"","category":"section"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Price-sensitive loads refer to components in the system which may increase or reduce their power consumption according to energy prices. Unlike conventional loads, described above, price-sensitive loads are only served if it is economical to do so. More specifically, there are no constraints forcing these loads to be served; instead, there is a term in the objective function rewarding each MW served. Unlike conventional loads, there may be multiple price-sensitive loads per bus.","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"note: Note\nSome unit commitment models allow price-sensitive loads to have a piecewise-linear convex revenue curves, similar to thermal generators. This can be achieved in UC.jl by adding multiple price-sensitive loads to the bus, one for each piecewise-linear segment.","category":"page"},{"location":"guides/problem/#Sets-and-constants-2","page":"Problem definition","title":"Sets and constants","text":"","category":"section"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Symbol Unit Description\nM^textpsl-demand_spt MW Demand of price-sensitive load p at time t and scenario s.\nZ^textpsl-revenue_spt $/MW Revenue from serving load p at t in scenario s.\ntextPSL Set of price-sensitive loads.","category":"page"},{"location":"guides/problem/#Decision-variables-4","page":"Problem definition","title":"Decision variables","text":"","category":"section"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Symbol JuMP name Unit Description Stage\ny^textpsl_spt loads[s,p,t] MW Amount served to p in time t and scenario s 2","category":"page"},{"location":"guides/problem/#Objective-function-terms-4","page":"Problem definition","title":"Objective function terms","text":"","category":"section"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Revenue from serving price-sensitive loads:","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":" - sum_s in S p(s) left\n sum_p in textPSL sum_t in T y^textpsl_spt Z^textpsl-revenue_spt\n right","category":"page"},{"location":"guides/problem/#Constraints-4","page":"Problem definition","title":"Constraints","text":"","category":"section"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Variable bounds:","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"0 leq y^textpsl_spt leq M^textpsl-demand_spt","category":"page"},{"location":"guides/problem/#6.-Energy-storage","page":"Problem definition","title":"6. Energy storage","text":"","category":"section"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Energy storage units are able to store energy during periods of low demand, then release energy back to the grid during periods of high demand. These devices include batteries, pumped hydroelectric storage, compressed air energy storage and flywheels. They are becoming increasingly important in the modern power grid, and can help to enhance grid reliability, efficiency and integration of renewable energy resources.","category":"page"},{"location":"guides/problem/#Concepts","page":"Problem definition","title":"Concepts","text":"","category":"section"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Min/max energy level and charge rate: Energy storage units can only store a limited amount of energy (in MWh). To maintain the operational safety and longevity of these devices, a minimum energy level may also be imposed. The rate (in MW) at which these units can charge and discharge is also limited, due to chemical, physical and operational considerations.\nOperational costs: Charging and discharging energy storage units may incur a cost/revenue. We assume that this cost/revenue is linear on the charge/discharte rate (/MW).\nEfficiency: Charging an energy storage unit for one hour with an input of 1 MW might not result in an increase of the energy level in the device by exactly 1 MWh, due to various inneficiencies in the charging process, including coversion losses and heat generation. For similar reasons, discharging a storage unit for one hour at 1 MW might reduce the energy level by more than 1 MWh. Furthermore, even when the unit is not charging or discharging, some energy level may be gradually lost over time, due to unwanted chemical reactions, thermal effects of mechanical losses.\nMyopic effect: Because the optimization process considers a fixed time window, there is an inherent bias towards exploiting energy storage units to their maximum within the window, completely ignoring their operation just beyond this horizon. For instance, without further constraints, the optimization algorithm will often ensure that all storage units are fully discharged at the end of the last time step, which may not be desirable. To mitigate this myopic effect, a minimum and maximum energy level may be imposed at the last time step.\nSimultaneous charging and discharging: Depending on charge and discharge costs/revenue, it may make sense mathematically to simultaneously charge and discharge the storage unit, thus keeping its energy level unchanged while potentially collecting revenue. Additional binary variables and constraints are required to prevent this incorrect model behavior.","category":"page"},{"location":"guides/problem/#Sets-and-constants-3","page":"Problem definition","title":"Sets and constants","text":"","category":"section"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Symbol Unit Description\ntextSU Set of storage units\nZ^textcharge_sut $/MW Linear charge cost/revenue for unit u at time t in scenario s.\nZ^textdischarge_sut $/MW Linear discharge cost/revenue for unit u at time t in scenario s.\nM^textdischarge-max_sut $/MW Maximum discharge rate for unit u at time t in scenario s.\nM^textdischarge-min_sut $/MW Minimum discharge rate for unit u at time t in scenario s.\nM^textcharge-max_sut $/MW Maximum charge rate for unit u at time t in scenario s.\nM^textcharge-min_sut $/MW Minimum charge rate for unit u at time t in scenario s.\nM^textmax-end-level_su MWh Maximum storage level of unit u at the last time step in scenario s\nM^textmin-end-level_su MWh Minimum storage level of unit u at the last time step in scenario s\ngamma^textloss_sut Self-discharge factor.\ngamma^textcharge-eff_sut Charging efficiency factor.\ngamma^textdischarge-eff_sut Discharging efficiency factor.\ngamma^texttime-step Length of a time step, in hours. Should be 1.0 for hourly time steps, 0.5 for 30-min half steps, etc.","category":"page"},{"location":"guides/problem/#Decision-variables-5","page":"Problem definition","title":"Decision variables","text":"","category":"section"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Symbol JuMP name Unit Description Stage\ny^textlevel_sut storage_level[s,u,t] MWh Storage level of unit u at time t in scenario s. 2\ny^textcharge_sut charge_rate[s,u,t] MW Charge rate of unit u at time t in scenario s. 2\ny^textdischarge_sut discharge_rate[s,u,t] MW Discharge rate of unit u at time t in scenario s. 2\nx^textis-charging_sut is_charging[s,u,t] Binary True if unit u is charging at time t in scenario s. 2\nx^textis-discharging_sut is_discharging[s,u,t] Binary True if unit u is discharging at time t in scenario s. 2","category":"page"},{"location":"guides/problem/#Objective-function-terms-5","page":"Problem definition","title":"Objective function terms","text":"","category":"section"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Charge and discharge cost/revenue:","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"sum_s in S p(s) left\n sum_u in textSU sum_t in T left(\n y^textcharge_sut Z^textcharge_sut +\n y^textdischarge_sut Z^textdischarge_sut\n right)\nright","category":"page"},{"location":"guides/problem/#Constraints-5","page":"Problem definition","title":"Constraints","text":"","category":"section"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Prevent simultaneous charge and discharge (eq_simultaneous_charge_and_discharge[s,u,t]):","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"x^textis-charging_sut + x^textis-discharging_sut leq 1","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Limit charge/discharge rate (eq_min_charge_rate[s,u,t], eq_max_charge_rate[s,u,t], eq_min_discharge_rate[s,u,t] and eq_max_discharge_rate[s,u,t]):","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"beginalign*\ny^textcharge_sut leq x^textis-charging_sut M^textcharge-max_sut \ny^textcharge_sut geq x^textis-charging_sut M^textcharge-min_sut \ny^textdischarge_sut leq x^textis-discharging_sut M^textdischarge-max_sut \ny^textdischarge_sut geq x^textis-discharging_sut M^textdischarge-min_sut \nendalign*","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Calculate current storage level (eq_storage_transition[s,u,t]):","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"y^textlevel_sut =\n(1 - gamma^textloss_sut) y^textlevel_sut-1 +\n gamma^texttime-step gamma^textcharge-eff_sut y^textcharge_sut -\nfracgamma^texttime-stepgamma^textdischarge-eff_sut y^textcharge_sut","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Enforce storage level at last time step (eq_ending_level[s,u]):","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"M^textmin-end-level_su leq y^textlevel_sut leq M^textmax-end-level_su","category":"page"},{"location":"guides/problem/#7.-Buses-and-transmission-lines","page":"Problem definition","title":"7. Buses and transmission lines","text":"","category":"section"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"So far, we have described generators, which produce power, loads, which consume power, and storage units, which store energy for later use. Another important element is the transmission network, which delivers the power produced by the generators to the loads and storage units. Mathematically, the network is represented as a graph (BL) where B is the set of buses and L is the set of transmission lines. Each generator, load and storage unit is located at a bus. The net injection at the bus is the sum of all power injected minus withdrawn at the bus. To balance production and consumption, we must enforce that the sum of all net injections over the entire network equal to zero.","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Besides the net balance equations, we must also enforce flow limits on the transmission lines. Unlike flows in other optimization problems, power flows are directly determined by net injections and transmission line parameters, and must follow physical laws. UC.jl uses the DC linearization of AC power flow equations. Under this linearization, the flow f_l in transmission line l is given by sum_b in B delta_bl n_b, where delta_bl is a constant known as injection shift factor (also commonly called power transfer distribution factor), computed from the line parameters, and n_b is the net injection at bus b.","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"warning: Warning\nTo improve computational performance, power flow variables and constraints are generated on-the-fly, during UnitCommitment.optimize!; they are not added by UnitCommitment.build_model.","category":"page"},{"location":"guides/problem/#Sets-and-constants-4","page":"Problem definition","title":"Sets and constants","text":"","category":"section"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Symbol Unit Description\nM^textlimit_slt MW Flow limit for line l at time t and scenario s.\nZ^textoverflow_slt $/MW Overflow penalty for line l at time t and scenario s.\nL Set of transmission lines.\nB Set of buses.","category":"page"},{"location":"guides/problem/#Decision-variables-6","page":"Problem definition","title":"Decision variables","text":"","category":"section"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Symbol JuMP name Unit Description Stage\ny^textflow_slt (added on-the-fly) MW Flow in line l at time t and scenario s. 2\ny^textinj_sbt net_injection[s,b,t] MW Total net injection at bus b, time t and scenario s. 2\ny^textoverflow_slt overflow[s,l,t] MW Amount of flow above limit for line l at time t and scenario s. 2","category":"page"},{"location":"guides/problem/#Objective-function-terms-6","page":"Problem definition","title":"Objective function terms","text":"","category":"section"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Penalty for exceeding line limits:","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":" sum_s in S p(s) left\n sum_l in L sum_t in T y^textoverflow_slt Z^textoverflow_slt\n right","category":"page"},{"location":"guides/problem/#Constraints-6","page":"Problem definition","title":"Constraints","text":"","category":"section"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Power produced equal power consumed (eq_power_balance[s,t]):","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"sum_b in B sum_t in T y^textinj_sbt = 0","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Definition of flow (enforced on-the-fly):","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"y^textflow_slt = sum_b in B delta_sbl y^textinj_sbt","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Flow limits (enforced on-the-fly):","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"beginalign*\n y^textflow_slt leq M^textlimit_slt + y^textoverflow_slt \n-y^textflow_slt leq M^textlimit_slt + y^textoverflow_slt\nendalign*","category":"page"},{"location":"guides/problem/#8.-Transmission-interfaces","page":"Problem definition","title":"8. Transmission interfaces","text":"","category":"section"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"In some applications, such as energy exchange studies, it is important to enforce flow limits not only on individual lines, but also on groups of transmission lines. These groups are known as interfaces. More precisely, an interface is composed by two sets of lines: the inbound and the outbound lines. The flow across the interface is defined as the sum of the flow in all inbound lines minus the sum of the flow in all outbound lines. An upper and a lower limit may be imposed on the flow across the interface, and a penalty is imposed if the limit is exceeded.","category":"page"},{"location":"guides/problem/#Sets-and-constants-5","page":"Problem definition","title":"Sets and constants","text":"","category":"section"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Symbol Unit Description\nL^textinbound_si Set of inbound lines for interface i in scenario s.\nL^textoutbound_si Set of outbound lines for interface i in scenario s.\nM^textlimit-down_sit MW Lower flow limit for interface i at time at time t and scenario s (negative number).\nM^textlimit-up_sit MW Upper flow limit for interface i at time at time t and scenario s (positive number).\nZ^textoverflow_sit $/MW Overflow penalty for interface l at time t and scenario s.\ntextIF Set of transmission interfaces.","category":"page"},{"location":"guides/problem/#Decision-variables-7","page":"Problem definition","title":"Decision variables","text":"","category":"section"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Symbol JuMP name Unit Description Stage\ny^texti-flow_sit interface_flow[s,i,t] MW Flow across interface i at time t and scenario s. 2\ny^texti-overflow_sit interface_overflow[s,i,t] MW Flow above limit for interface i at time t and scenario s. 2","category":"page"},{"location":"guides/problem/#Objective-function-terms-7","page":"Problem definition","title":"Objective function terms","text":"","category":"section"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Penalty for exceeding interface limits:","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":" sum_s in S p(s) left\n sum_i in textIF sum_t in T y^texti-overflow_sit Z^textoverflow_sit\n right","category":"page"},{"location":"guides/problem/#Constraints-7","page":"Problem definition","title":"Constraints","text":"","category":"section"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Definition of interface flow (eq_if_flow):","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"y^texti-flow_sit = sum_b in B y^textinj_sbt left\nsum_l in L^textoutbound_si delta_sbl -\nsum_l in L^textinbound_si delta_sbl\nright","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"Interface flow limits (eq_if_limit_up and eq_if_limit_up)","category":"page"},{"location":"guides/problem/","page":"Problem definition","title":"Problem definition","text":"beginalign*\n y^texti-flow_sit leq M^textlimit-up_sit + y^texti-overflow_sit \n-y^texti-flow_sit leq -M^textlimit-down_sit + y^texti-overflow_sit\nendalign*","category":"page"},{"location":"guides/problem/#9.-Contingencies","page":"Problem definition","title":"9. Contingencies","text":"","category":"section"},{"location":"guides/problem/#10.-Reserves","page":"Problem definition","title":"10. Reserves","text":"","category":"section"},{"location":"tutorials/market/#Market-clearing-and-LMPs","page":"Market clearing and LMPs","title":"Market clearing and LMPs","text":"","category":"section"},{"location":"tutorials/market/","page":"Market clearing and LMPs","title":"Market clearing and LMPs","text":"The UC.jl package offers a comprehensive set of functions for solving marketing problems. The primary function, solve_market, facilitates the solution of day-ahead (DA) markets, which can be either deterministic or stochastic in nature. Subsequently, it sequentially maps the commitment status obtained from the DA market to all the real-time (RT) markets, which are deterministic instances. It is essential to ensure that the time span of the DA market encompasses all the RT markets, and the file paths for the RT markets must be specified in chronological order. Each RT market should represent a single time slot, and it is recommended to include a few additional time slots to mitigate the closing window effect.","category":"page"},{"location":"tutorials/market/","page":"Market clearing and LMPs","title":"Market clearing and LMPs","text":"The solve_market function accepts several parameters, including the file path (or a list of file paths in the case of stochastic markets) for the DA market, a list of file paths for the RT markets, the market settings specified by the MarketSettings structure, and an optimizer. The MarketSettings structure itself requires three optional arguments: inner_method, lmp_method, and formulation. If the computation of Locational Marginal Prices (LMPs) is not desired, the lmp_method can be set to nothing. Additional optional parameters include a linear programming optimizer for solving LMPs (if a different optimizer than the required one is desired), callback functions after_build_da and after_optimize_da, which are invoked after the construction and optimization of the DA market, and callback functions after_build_rt and after_optimize_rt, which are invoked after the construction and optimization of each RT market. It is crucial to note that the after_build function requires its two arguments to consistently correspond to model and instance, while the after_optimize function requires its three arguments to consistently correspond to solution, model, and instance.","category":"page"},{"location":"tutorials/market/","page":"Market clearing and LMPs","title":"Market clearing and LMPs","text":"As an illustrative example, suppose the DA market predicts hourly data for a 24-hour period, while the RT markets represent 5-minute intervals. In this scenario, each RT market file corresponds to a specific 5-minute interval, with the first RT market representing the initial 5 minutes, the second RT market representing the subsequent 5 minutes, and so on. Consequently, there should be 12 RT market files for each hour. To mitigate the closing window effect, except for the last few RT markets, each RT market should contain three time slots, resulting in a total time span of 15 minutes. However, only the first time slot is considered in the final solution. The last two RT markets should only contain 2 and 1 time slot(s), respectively, to ensure that the total time covered by all RT markets does not exceed the time span of the DA market. The code snippet below demonstrates a simplified example of how to utilize the solve_market function. Please note that it only serves as a simplified example and may require further customization based on the specific requirements of your use case.","category":"page"},{"location":"tutorials/market/","page":"Market clearing and LMPs","title":"Market clearing and LMPs","text":"using UnitCommitment, Cbc, HiGHS\n\nimport UnitCommitment:\n MarketSettings,\n XavQiuWanThi2019,\n ConventionalLMP,\n Formulation\n\nsolution = UnitCommitment.solve_market(\n \"da_instance.json\",\n [\"rt_instance_1.json\", \"rt_instance_2.json\", \"rt_instance_3.json\"],\n MarketSettings(\n inner_method = XavQiuWanThi2019.Method(),\n lmp_method = ConventionalLMP(),\n formulation = Formulation(),\n ),\n optimizer = Cbc.Optimizer,\n lp_optimizer = HiGHS.Optimizer,\n)","category":"page"},{"location":"tutorials/market/#Computing-Locational-Marginal-Prices","page":"Market clearing and LMPs","title":"Computing Locational Marginal Prices","text":"","category":"section"},{"location":"tutorials/market/","page":"Market clearing and LMPs","title":"Market clearing and LMPs","text":"Locational marginal prices (LMPs) refer to the cost of supplying electricity at a particular location of the network. Multiple methods for computing LMPs have been proposed in the literature. UnitCommitment.jl implements two commonly-used methods: conventional LMPs and Approximated Extended LMPs (AELMPs). To compute LMPs for a given unit commitment instance, the compute_lmp function can be used, as shown in the examples below. The function accepts three arguments – a solved SCUC model, an LMP method, and a linear optimizer – and it returns a dictionary mapping (bus_name, time) to the marginal price.","category":"page"},{"location":"tutorials/market/","page":"Market clearing and LMPs","title":"Market clearing and LMPs","text":"warning: Warning\nMost mixed-integer linear optimizers, such as HiGHS, Gurobi and CPLEX can be used with compute_lmp, with the notable exception of Cbc, which does not support dual value evaluations. If using Cbc, please provide Clp as the linear optimizer.","category":"page"},{"location":"tutorials/market/#Conventional-LMPs","page":"Market clearing and LMPs","title":"Conventional LMPs","text":"","category":"section"},{"location":"tutorials/market/","page":"Market clearing and LMPs","title":"Market clearing and LMPs","text":"LMPs are conventionally computed by: (1) solving the SCUC model, (2) fixing all binary variables to their optimal values, and (3) re-solving the resulting linear programming model. In this approach, the LMPs are defined as the dual variables' values associated with the net injection constraints. The example below shows how to compute conventional LMPs for a given unit commitment instance. First, we build and optimize the SCUC model. Then, we call the compute_lmp function, providing as the second argument ConventionalLMP().","category":"page"},{"location":"tutorials/market/","page":"Market clearing and LMPs","title":"Market clearing and LMPs","text":"using UnitCommitment\nusing HiGHS\n\nimport UnitCommitment: ConventionalLMP\n\n# Read benchmark instance\ninstance = UnitCommitment.read_benchmark(\"matpower/case118/2018-01-01\")\n\n# Build the model\nmodel = UnitCommitment.build_model(\n instance = instance,\n optimizer = HiGHS.Optimizer,\n)\n\n# Optimize the model\nUnitCommitment.optimize!(model)\n\n# Compute the LMPs using the conventional method\nlmp = UnitCommitment.compute_lmp(\n model,\n ConventionalLMP(),\n optimizer = HiGHS.Optimizer,\n)\n\n# Access the LMPs\n# Example: \"s1\" is the scenario name, \"b1\" is the bus name, 1 is the first time slot\n@show lmp[\"s1\",\"b1\", 1]","category":"page"},{"location":"tutorials/market/#Approximate-Extended-LMPs","page":"Market clearing and LMPs","title":"Approximate Extended LMPs","text":"","category":"section"},{"location":"tutorials/market/","page":"Market clearing and LMPs","title":"Market clearing and LMPs","text":"Approximate Extended LMPs (AELMPs) are an alternative method to calculate locational marginal prices which attemps to minimize uplift payments. The method internally works by modifying the instance data in three ways: (1) it sets the minimum power output of each generator to zero, (2) it averages the start-up cost over the offer blocks for each generator, and (3) it relaxes all integrality constraints. To compute AELMPs, as shown in the example below, we call compute_lmp and provide AELMP() as the second argument.","category":"page"},{"location":"tutorials/market/","page":"Market clearing and LMPs","title":"Market clearing and LMPs","text":"This method has two configurable parameters: allow_offline_participation and consider_startup_costs. If allow_offline_participation = true, then offline generators are allowed to participate in the pricing. If instead allow_offline_participation = false, offline generators are not allowed and therefore are excluded from the system. A solved UC model is optional if offline participation is allowed, but is required if not allowed. The method forces offline participation to be allowed if the UC model supplied by the user is not solved. For the second field, If consider_startup_costs = true, then start-up costs are integrated and averaged over each unit production; otherwise the production costs stay the same. By default, both fields are set to true.","category":"page"},{"location":"tutorials/market/","page":"Market clearing and LMPs","title":"Market clearing and LMPs","text":"warning: Warning\nThis approximation method is still under active research, and has several limitations. The implementation provided in the package is based on MISO Phase I only. It only supports fast start resources. More specifically, the minimum up/down time of all generators must be 1, the initial power of all generators must be 0, and the initial status of all generators must be negative. The method does not support time-varying start-up costs. The method does not support multiple scenarios. If offline participation is not allowed, AELMPs treats an asset to be offline if it is never on throughout all time periods.","category":"page"},{"location":"tutorials/market/","page":"Market clearing and LMPs","title":"Market clearing and LMPs","text":"using UnitCommitment\nusing HiGHS\n\nimport UnitCommitment: AELMP\n\n# Read benchmark instance\ninstance = UnitCommitment.read_benchmark(\"matpower/case118/2017-02-01\")\n\n# Build the model\nmodel = UnitCommitment.build_model(\n instance = instance,\n optimizer = HiGHS.Optimizer,\n)\n\n# Optimize the model\nUnitCommitment.optimize!(model)\n\n# Compute the AELMPs\naelmp = UnitCommitment.compute_lmp(\n model,\n AELMP(\n allow_offline_participation = false,\n consider_startup_costs = true\n ),\n optimizer = HiGHS.Optimizer\n)\n\n# Access the AELMPs\n# Example: \"s1\" is the scenario name, \"b1\" is the bus name, 1 is the first time slot\n# Note: although scenario is supported, the query still keeps the scenario keys for consistency.\n@show aelmp[\"s1\", \"b1\", 1]","category":"page"},{"location":"tutorials/usage/","page":"Getting started","title":"Getting started","text":"EditURL = \"usage.jl\"","category":"page"},{"location":"tutorials/usage/#Getting-started","page":"Getting started","title":"Getting started","text":"","category":"section"},{"location":"tutorials/usage/#Installing-the-package","page":"Getting started","title":"Installing the package","text":"","category":"section"},{"location":"tutorials/usage/","page":"Getting started","title":"Getting started","text":"UnitCommitment.jl was tested and developed with Julia 1.10. To install Julia, please follow the installation guide on the official Julia website. To install UnitCommitment.jl, run the Julia interpreter, type ] to open the package manager, then type:","category":"page"},{"location":"tutorials/usage/","page":"Getting started","title":"Getting started","text":"pkg> add UnitCommitment@0.4","category":"page"},{"location":"tutorials/usage/","page":"Getting started","title":"Getting started","text":"To solve the optimization models, a mixed-integer linear programming (MILP) solver is also required. Please see the JuMP installation guide for more instructions on installing a solver. Typical open-source choices are HiGHS, Cbc and GLPK. In the instructions below, HiGHS will be used, but any other MILP solver listed in JuMP installation guide should also be compatible.","category":"page"},{"location":"tutorials/usage/#Solving-a-benchmark-instance","page":"Getting started","title":"Solving a benchmark instance","text":"","category":"section"},{"location":"tutorials/usage/","page":"Getting started","title":"Getting started","text":"We start this tutorial by illustrating how to use UnitCommitment.jl to solve one of the provided benchmark instances. The package contains a large number of deterministic benchmark instances collected from the literature and converted into a common data format, which can be used to evaluate the performance of different solution methods. See Instances for more details. The first step is to import UnitCommitment and HiGHS.","category":"page"},{"location":"tutorials/usage/","page":"Getting started","title":"Getting started","text":"using HiGHS\nusing UnitCommitment","category":"page"},{"location":"tutorials/usage/","page":"Getting started","title":"Getting started","text":"Next, we use the function read_benchmark to read the instance.","category":"page"},{"location":"tutorials/usage/","page":"Getting started","title":"Getting started","text":"instance = UnitCommitment.read_benchmark(\"matpower/case14/2017-01-01\");\nnothing #hide","category":"page"},{"location":"tutorials/usage/","page":"Getting started","title":"Getting started","text":"Now that we have the instance loaded in memory, we build the JuMP optimization model using UnitCommitment.build_model:","category":"page"},{"location":"tutorials/usage/","page":"Getting started","title":"Getting started","text":"model = UnitCommitment.build_model(\n instance=instance,\n optimizer=HiGHS.Optimizer,\n);\nnothing #hide","category":"page"},{"location":"tutorials/usage/","page":"Getting started","title":"Getting started","text":"Next, we run the optimization process, with UnitCommitment.optimize!:","category":"page"},{"location":"tutorials/usage/","page":"Getting started","title":"Getting started","text":"UnitCommitment.optimize!(model)","category":"page"},{"location":"tutorials/usage/","page":"Getting started","title":"Getting started","text":"Finally, we extract the optimal solution from the model:","category":"page"},{"location":"tutorials/usage/","page":"Getting started","title":"Getting started","text":"solution = UnitCommitment.solution(model)","category":"page"},{"location":"tutorials/usage/","page":"Getting started","title":"Getting started","text":"We can then explore the solution using Julia:","category":"page"},{"location":"tutorials/usage/","page":"Getting started","title":"Getting started","text":"@show solution[\"Thermal production (MW)\"][\"g1\"]","category":"page"},{"location":"tutorials/usage/","page":"Getting started","title":"Getting started","text":"Or export the entire solution to a JSON file:","category":"page"},{"location":"tutorials/usage/","page":"Getting started","title":"Getting started","text":"UnitCommitment.write(\"solution.json\", solution)","category":"page"},{"location":"tutorials/usage/#Solving-a-custom-deterministic-instance","page":"Getting started","title":"Solving a custom deterministic instance","text":"","category":"section"},{"location":"tutorials/usage/","page":"Getting started","title":"Getting started","text":"In the previous example, we solved a benchmark instance provided by the package. To solve a custom instance, the first step is to create an input file describing the list of elements (generators, loads and transmission lines) in the network. See Data Format for a complete description of the data format UC.jl expects. To keep this tutorial self-contained, we will create the input JSON file using Julia; however, this step can also be done with a simple text editor. First, we define the contents of the file:","category":"page"},{"location":"tutorials/usage/","page":"Getting started","title":"Getting started","text":"json_contents = \"\"\"\n{\n \"Parameters\": {\n \"Version\": \"0.4\",\n \"Time horizon (h)\": 4\n },\n \"Buses\": {\n \"b1\": {\n \"Load (MW)\": [100, 150, 200, 250]\n }\n },\n \"Generators\": {\n \"g1\": {\n \"Bus\": \"b1\",\n \"Type\": \"Thermal\",\n \"Production cost curve (MW)\": [0, 200],\n \"Production cost curve (\\$)\": [0, 1000],\n \"Initial status (h)\": -24,\n \"Initial power (MW)\": 0\n },\n \"g2\": {\n \"Bus\": \"b1\",\n \"Type\": \"Thermal\",\n \"Production cost curve (MW)\": [0, 300],\n \"Production cost curve (\\$)\": [0, 3000],\n \"Initial status (h)\": -24,\n \"Initial power (MW)\": 0\n }\n }\n}\n\"\"\";\nnothing #hide","category":"page"},{"location":"tutorials/usage/","page":"Getting started","title":"Getting started","text":"Next, we write it to example.json.","category":"page"},{"location":"tutorials/usage/","page":"Getting started","title":"Getting started","text":"open(\"example.json\", \"w\") do file\n write(file, json_contents)\nend;\nnothing #hide","category":"page"},{"location":"tutorials/usage/","page":"Getting started","title":"Getting started","text":"Now that we have the input file, we can proceed as before, but using UnitCommitment.read instead of UnitCommitment.read_benchmark:","category":"page"},{"location":"tutorials/usage/","page":"Getting started","title":"Getting started","text":"instance = UnitCommitment.read(\"example.json\");\nmodel = UnitCommitment.build_model(\n instance=instance,\n optimizer=HiGHS.Optimizer,\n);\nUnitCommitment.optimize!(model)","category":"page"},{"location":"tutorials/usage/","page":"Getting started","title":"Getting started","text":"Finally, we extract and display the solution:","category":"page"},{"location":"tutorials/usage/","page":"Getting started","title":"Getting started","text":"solution = UnitCommitment.solution(model)","category":"page"},{"location":"tutorials/usage/","page":"Getting started","title":"Getting started","text":"@show solution[\"Thermal production (MW)\"][\"g1\"]","category":"page"},{"location":"tutorials/usage/","page":"Getting started","title":"Getting started","text":"@show solution[\"Thermal production (MW)\"][\"g2\"]","category":"page"},{"location":"tutorials/usage/#Solving-a-custom-stochastic-instance","page":"Getting started","title":"Solving a custom stochastic instance","text":"","category":"section"},{"location":"tutorials/usage/","page":"Getting started","title":"Getting started","text":"In addition to deterministic test cases, UnitCommitment.jl can also solve two-stage stochastic instances of the problem. In this section, we demonstrate the most simple form, which builds a single (extensive form) model containing information for all scenarios. See Decomposition for more advanced methods.","category":"page"},{"location":"tutorials/usage/","page":"Getting started","title":"Getting started","text":"First, we need to create one JSON input file for each scenario. Parameters that are allowed to change across scenarios are marked as \"uncertain\" in the JSON data format page. It is also possible to specify the name and weight of each scenario, as shown below.","category":"page"},{"location":"tutorials/usage/","page":"Getting started","title":"Getting started","text":"We start by creating example_s1.json, the first scenario file:","category":"page"},{"location":"tutorials/usage/","page":"Getting started","title":"Getting started","text":"json_contents_s1 = \"\"\"\n{\n \"Parameters\": {\n \"Version\": \"0.4\",\n \"Time horizon (h)\": 4,\n \"Scenario name\": \"s1\",\n \"Scenario weight\": 3.0\n },\n \"Buses\": {\n \"b1\": {\n \"Load (MW)\": [100, 150, 200, 250]\n }\n },\n \"Generators\": {\n \"g1\": {\n \"Bus\": \"b1\",\n \"Type\": \"Thermal\",\n \"Production cost curve (MW)\": [0, 200],\n \"Production cost curve (\\$)\": [0, 1000],\n \"Initial status (h)\": -24,\n \"Initial power (MW)\": 0\n },\n \"g2\": {\n \"Bus\": \"b1\",\n \"Type\": \"Thermal\",\n \"Production cost curve (MW)\": [0, 300],\n \"Production cost curve (\\$)\": [0, 3000],\n \"Initial status (h)\": -24,\n \"Initial power (MW)\": 0\n }\n }\n}\n\"\"\"\nopen(\"example_s1.json\", \"w\") do file\n write(file, json_contents_s1)\nend;\nnothing #hide","category":"page"},{"location":"tutorials/usage/","page":"Getting started","title":"Getting started","text":"Next, we create example_s2.json, the second scenario file:","category":"page"},{"location":"tutorials/usage/","page":"Getting started","title":"Getting started","text":"json_contents_s2 = \"\"\"\n{\n \"Parameters\": {\n \"Version\": \"0.4\",\n \"Time horizon (h)\": 4,\n \"Scenario name\": \"s2\",\n \"Scenario weight\": 1.0\n },\n \"Buses\": {\n \"b1\": {\n \"Load (MW)\": [200, 300, 400, 500]\n }\n },\n \"Generators\": {\n \"g1\": {\n \"Bus\": \"b1\",\n \"Type\": \"Thermal\",\n \"Production cost curve (MW)\": [0, 200],\n \"Production cost curve (\\$)\": [0, 1000],\n \"Initial status (h)\": -24,\n \"Initial power (MW)\": 0\n },\n \"g2\": {\n \"Bus\": \"b1\",\n \"Type\": \"Thermal\",\n \"Production cost curve (MW)\": [0, 300],\n \"Production cost curve (\\$)\": [0, 3000],\n \"Initial status (h)\": -24,\n \"Initial power (MW)\": 0\n }\n }\n}\n\"\"\";\nopen(\"example_s2.json\", \"w\") do file\n write(file, json_contents_s2)\nend;\nnothing #hide","category":"page"},{"location":"tutorials/usage/","page":"Getting started","title":"Getting started","text":"Now that we have our two scenario files, we can read them using UnitCommitment.read. Note that, instead of a single file, we now provide a list.","category":"page"},{"location":"tutorials/usage/","page":"Getting started","title":"Getting started","text":"instance = UnitCommitment.read([\"example_s1.json\", \"example_s2.json\"])","category":"page"},{"location":"tutorials/usage/","page":"Getting started","title":"Getting started","text":"If we have a large number of scenario files, the Glob package can also be used to avoid having to list them individually:","category":"page"},{"location":"tutorials/usage/","page":"Getting started","title":"Getting started","text":"using Glob\ninstance = UnitCommitment.read(glob(\"example_s*.json\"))","category":"page"},{"location":"tutorials/usage/","page":"Getting started","title":"Getting started","text":"Finally, we build the model and optimize as before:","category":"page"},{"location":"tutorials/usage/","page":"Getting started","title":"Getting started","text":"model = UnitCommitment.build_model(\n instance=instance,\n optimizer=HiGHS.Optimizer,\n);\nUnitCommitment.optimize!(model)","category":"page"},{"location":"tutorials/usage/","page":"Getting started","title":"Getting started","text":"The solution to stochastic instances follows a slightly different format, as shown below:","category":"page"},{"location":"tutorials/usage/","page":"Getting started","title":"Getting started","text":"solution = UnitCommitment.solution(model)","category":"page"},{"location":"tutorials/usage/","page":"Getting started","title":"Getting started","text":"The solution for each scenario can be accessed through solution[scenario_name]. For conveniance, this includes both first- and second-stage optimal decisions:","category":"page"},{"location":"tutorials/usage/","page":"Getting started","title":"Getting started","text":"solution[\"s1\"]","category":"page"},{"location":"tutorials/customizing/","page":"Model customization","title":"Model customization","text":"EditURL = \"customizing.jl\"","category":"page"},{"location":"tutorials/customizing/#Model-customization","page":"Model customization","title":"Model customization","text":"","category":"section"},{"location":"tutorials/customizing/","page":"Model customization","title":"Model customization","text":"In the previous tutorial, we used UnitCommitment.jl to solve benchmark and user-provided instances using a default mathematical formulation for the problem. In this tutorial, we will explore how to customize this formulation.","category":"page"},{"location":"tutorials/customizing/","page":"Model customization","title":"Model customization","text":"warning: Warning\nThis tutorial is not required for using UnitCommitment.jl, unless you plan to make changes to the problem formulation. In this page, we assume familiarity with the JuMP modeling language. Please see JuMP's official documentation for resources on getting started with JuMP.","category":"page"},{"location":"tutorials/customizing/#Selecting-modeling-components","page":"Model customization","title":"Selecting modeling components","text":"","category":"section"},{"location":"tutorials/customizing/","page":"Model customization","title":"Model customization","text":"By default, UnitCommitment.build_model uses a formulation that combines modeling components from different publications, and that has been carefully tested, using our own benchmark scripts, to provide good performance across a wide variety of instances. This default formulation is expected to change over time, as new methods are proposed in the literature. You can, however, construct your own formulation, based on the modeling components that you choose, as shown in the next example.","category":"page"},{"location":"tutorials/customizing/","page":"Model customization","title":"Model customization","text":"We start by importing the necessary packages and reading a benchmark instance:","category":"page"},{"location":"tutorials/customizing/","page":"Model customization","title":"Model customization","text":"using HiGHS\nusing JuMP\nusing UnitCommitment\n\ninstance = UnitCommitment.read_benchmark(\"matpower/case14/2017-01-01\");\nnothing #hide","category":"page"},{"location":"tutorials/customizing/","page":"Model customization","title":"Model customization","text":"Next, instead of calling UnitCommitment.build_model with default arguments, we can provide a UnitCommitment.Formulation object, which describes what modeling components to use, and how should they be configured. For a complete list of modeling components available in UnitCommitment.jl, see the API docs.","category":"page"},{"location":"tutorials/customizing/","page":"Model customization","title":"Model customization","text":"In the example below, we switch to piecewise-linear cost modeling as defined in KnuOstWat2018, as well as ramping and startup costs formulation as defined in MorLatRam2013. In addition, we specify custom cutoffs for the shift factors formulation.","category":"page"},{"location":"tutorials/customizing/","page":"Model customization","title":"Model customization","text":"model = UnitCommitment.build_model(\n instance = instance,\n optimizer = HiGHS.Optimizer,\n formulation = UnitCommitment.Formulation(\n pwl_costs = UnitCommitment.KnuOstWat2018.PwlCosts(),\n ramping = UnitCommitment.MorLatRam2013.Ramping(),\n startup_costs = UnitCommitment.MorLatRam2013.StartupCosts(),\n transmission = UnitCommitment.ShiftFactorsFormulation(\n isf_cutoff = 0.008,\n lodf_cutoff = 0.003,\n ),\n ),\n);\nnothing #hide","category":"page"},{"location":"tutorials/customizing/#Accessing-decision-variables","page":"Model customization","title":"Accessing decision variables","text":"","category":"section"},{"location":"tutorials/customizing/","page":"Model customization","title":"Model customization","text":"In the previous tutorial, we saw how to access the optimal solution through UnitCommitment.solution. While this approach works well for basic usage, it is also possible to get a direct reference to the JuMP decision variables and query their values, as the next example illustrates.","category":"page"},{"location":"tutorials/customizing/","page":"Model customization","title":"Model customization","text":"First, we load a benchmark instance and solve it, as before.","category":"page"},{"location":"tutorials/customizing/","page":"Model customization","title":"Model customization","text":"instance = UnitCommitment.read_benchmark(\"matpower/case14/2017-01-01\");\nmodel = UnitCommitment.build_model(\n instance=instance,\n optimizer=HiGHS.Optimizer,\n);\nUnitCommitment.optimize!(model)","category":"page"},{"location":"tutorials/customizing/","page":"Model customization","title":"Model customization","text":"At this point, it is possible to obtain a reference to the decision variables by calling model[:varname][index]. For example, model[:is_on][\"g1\",1] returns a direct reference to the JuMP variable indicating whether generator named \"g1\" is on at time 1. For a complete list of decision variables available, and how are they indexed, see the problem definition.","category":"page"},{"location":"tutorials/customizing/","page":"Model customization","title":"Model customization","text":"@show JuMP.value(model[:is_on][\"g1\",1])","category":"page"},{"location":"tutorials/customizing/","page":"Model customization","title":"Model customization","text":"To access second-stage decisions, it is necessary to specify the scenario name. UnitCommitment.jl models deterministic instances as a particular case in which there is a single scenario named \"s1\", so we need to use this key.","category":"page"},{"location":"tutorials/customizing/","page":"Model customization","title":"Model customization","text":"@show JuMP.value(model[:prod_above][\"s1\", \"g1\", 1])","category":"page"},{"location":"tutorials/customizing/#Modifying-variables-and-constraints","page":"Model customization","title":"Modifying variables and constraints","text":"","category":"section"},{"location":"tutorials/customizing/","page":"Model customization","title":"Model customization","text":"When testing variations of the unit commitment problem, it is often necessary to modify the objective function, variables and constraints of the formulation. UnitCommitment.jl makes this process relatively easy. The first step is to construct the standard model using UnitCommitment.build_model:","category":"page"},{"location":"tutorials/customizing/","page":"Model customization","title":"Model customization","text":"instance = UnitCommitment.read_benchmark(\"matpower/case14/2017-01-01\");\nmodel = UnitCommitment.build_model(\n instance=instance,\n optimizer=HiGHS.Optimizer,\n);\nnothing #hide","category":"page"},{"location":"tutorials/customizing/","page":"Model customization","title":"Model customization","text":"Now, before calling UnitCommitment.optimize, we can make any desired changes to the formulation. In the previous section, we saw how to obtain a direct reference to the decision variables. It is possible to modify them by using standard JuMP methods. For example, to fix the commitment status of a particular generator, we can use JuMP.fix:","category":"page"},{"location":"tutorials/customizing/","page":"Model customization","title":"Model customization","text":"JuMP.fix(model[:is_on][\"g1\",1], 1.0, force=true)","category":"page"},{"location":"tutorials/customizing/","page":"Model customization","title":"Model customization","text":"To modify the cost coefficient of a particular variable, we can use JuMP.set_objective_coefficient:","category":"page"},{"location":"tutorials/customizing/","page":"Model customization","title":"Model customization","text":"JuMP.set_objective_coefficient(\n model,\n model[:switch_on][\"g1\",1],\n 1000.0,\n)","category":"page"},{"location":"tutorials/customizing/","page":"Model customization","title":"Model customization","text":"It is also possible to make changes to the set of constraints. For example, we can add a custom constraint, using the JuMP.@constraint macro:","category":"page"},{"location":"tutorials/customizing/","page":"Model customization","title":"Model customization","text":"@constraint(\n model,\n model[:is_on][\"g3\",1] + model[:is_on][\"g4\",1] <= 1,\n);\nnothing #hide","category":"page"},{"location":"tutorials/customizing/","page":"Model customization","title":"Model customization","text":"We can also remove an existing model constraint using JuMP.delete. See the problem definition for a list of constraint names and indices.","category":"page"},{"location":"tutorials/customizing/","page":"Model customization","title":"Model customization","text":"JuMP.delete(model, model[:eq_min_uptime][\"g1\",1])","category":"page"},{"location":"tutorials/customizing/","page":"Model customization","title":"Model customization","text":"After we are done with all changes, we can call UnitCommitment.optimize and extract the optimal solution:","category":"page"},{"location":"tutorials/customizing/","page":"Model customization","title":"Model customization","text":"UnitCommitment.optimize!(model)\n@show UnitCommitment.solution(model)","category":"page"},{"location":"tutorials/customizing/#Modeling-new-grid-components","page":"Model customization","title":"Modeling new grid components","text":"","category":"section"},{"location":"tutorials/customizing/","page":"Model customization","title":"Model customization","text":"In this section we demonstrate how to add a new grid component to a particular bus in the network. This is useful, for example, when developing formulations for a new type of generator, energy storage, or any other grid device. We start by reading the instance data and buliding a standard model:","category":"page"},{"location":"tutorials/customizing/","page":"Model customization","title":"Model customization","text":"instance = UnitCommitment.read_benchmark(\"matpower/case118/2017-02-01\")\nmodel = UnitCommitment.build_model(\n instance=instance,\n optimizer=HiGHS.Optimizer,\n);\nnothing #hide","category":"page"},{"location":"tutorials/customizing/","page":"Model customization","title":"Model customization","text":"Next, we create decision variables for the new grid component. In this example, we assume that the new component can inject up to 10 MW of power at each time step, so we create new continuous variables 0 leq x_t leq 10.","category":"page"},{"location":"tutorials/customizing/","page":"Model customization","title":"Model customization","text":"T = instance.time\n@variable(model, x[1:T], lower_bound=0.0, upper_bound=10.0);\nnothing #hide","category":"page"},{"location":"tutorials/customizing/","page":"Model customization","title":"Model customization","text":"Next, we add the production costs to the objective function. In this example, we assume a generation cost of $5/MW:","category":"page"},{"location":"tutorials/customizing/","page":"Model customization","title":"Model customization","text":"for t in 1:T\n set_objective_coefficient(model, x[t], 5.0)\nend","category":"page"},{"location":"tutorials/customizing/","page":"Model customization","title":"Model customization","text":"We then attach the new component to bus b1 by modifying the net injection constraint (eq_net_injection):","category":"page"},{"location":"tutorials/customizing/","page":"Model customization","title":"Model customization","text":"for t in 1:T\n set_normalized_coefficient(\n model[:eq_net_injection][\"s1\", \"b1\", t],\n x[t],\n 1.0,\n )\nend","category":"page"},{"location":"tutorials/customizing/","page":"Model customization","title":"Model customization","text":"Next, we solve the model:","category":"page"},{"location":"tutorials/customizing/","page":"Model customization","title":"Model customization","text":"UnitCommitment.optimize!(model)","category":"page"},{"location":"tutorials/customizing/","page":"Model customization","title":"Model customization","text":"We then finally extract the optimal value of the x variables:","category":"page"},{"location":"tutorials/customizing/","page":"Model customization","title":"Model customization","text":"@show value.(x)","category":"page"},{"location":"#UnitCommitment.jl","page":"Home","title":"UnitCommitment.jl","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"UnitCommitment.jl (UC.jl) is an optimization package for the Security-Constrained Unit Commitment Problem (SCUC), a fundamental optimization problem in power systems used, for example, to clear the day-ahead electricity markets. Both deterministic and two-stage stochastic versions of the problem are supported. The package provides benchmark instances for the problem, a flexible and well-documented data format for the problem, as well as Julia/JuMP implementations of state-of-the-art mixed-integer programming formulations and solution methods.","category":"page"},{"location":"#Package-Components","page":"Home","title":"Package Components","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"Data Format: The package proposes an extensible and fully-documented JSON-based data specification format for SCUC, developed in collaboration with Independent System Operators (ISOs), which describes the most important aspects of the problem. The format supports all the most common thermal generator characteristics (including ramping, piecewise-linear production cost curves and time-dependent startup costs), as well as profiled generators, reserves, price-sensitive loads, battery storage, transmission, and contingencies.\nBenchmark Instances: The package provides a diverse collection of large-scale benchmark instances collected from the literature, converted into a common data format, and extended using data-driven methods to make them more challenging and realistic.\nModel Implementation: The package provides a Julia/JuMP implementations of state-of-the-art formulations and solution methods for the deterministic and stochastic SCUC, including multiple ramping formulations (ArrCon2000, MorLatRam2013, DamKucRajAta2016, PanGua2016), piecewise-linear costs formulations (Gar1962, CarArr2006, KnuOstWat2018), contingency screening methods (XavQiuWanThi2019) and decomposition methods. Our goal is to keep these implementations up-to-date as new methods are proposed in the literature.\nBenchmark Tools: The package provides automated benchmark scripts to accurately evaluate the performance impact of proposed code changes.","category":"page"},{"location":"#Authors","page":"Home","title":"Authors","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"Alinson S. Xavier (Argonne National Laboratory)\nAleksandr M. Kazachkov (University of Florida)\nOgün Yurdakul (Technische Universität Berlin)\nJun He (Purdue University)\nFeng Qiu (Argonne National Laboratory)","category":"page"},{"location":"#Acknowledgments","page":"Home","title":"Acknowledgments","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"We would like to thank Yonghong Chen (Midcontinent Independent System Operator), Feng Pan (Pacific Northwest National Laboratory) for valuable feedback on early versions of this package.\nBased upon work supported by Laboratory Directed Research and Development (LDRD) funding from Argonne National Laboratory, provided by the Director, Office of Science, of the U.S. Department of Energy under Contract No. DE-AC02-06CH11357\nBased upon work supported by the U.S. Department of Energy Advanced Grid Modeling Program under Grant DE-OE0000875.","category":"page"},{"location":"#Citing","page":"Home","title":"Citing","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"If you use UnitCommitment.jl in your research (instances, models or algorithms), we kindly request that you cite the package as follows:","category":"page"},{"location":"","page":"Home","title":"Home","text":"Alinson S. Xavier, Aleksandr M. Kazachkov, Ogün Yurdakul, Jun He, Feng Qiu, \"UnitCommitment.jl: A Julia/JuMP Optimization Package for Security-Constrained Unit Commitment (Version 0.4)\". Zenodo (2023). DOI: 10.5281/zenodo.4269874.","category":"page"},{"location":"","page":"Home","title":"Home","text":"If you use the instances, we additionally request that you cite the original sources, as described in the instances page.","category":"page"},{"location":"#License","page":"Home","title":"License","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"UnitCommitment.jl: A Julia/JuMP Optimization Package for Security-Constrained Unit Commitment\nCopyright © 2020-2023, UChicago Argonne, LLC. All Rights Reserved.\n\nRedistribution and use in source and binary forms, with or without modification, are permitted\nprovided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this list of\n conditions and the following disclaimer.\n2. Redistributions in binary form must reproduce the above copyright notice, this list of\n conditions and the following disclaimer in the documentation and/or other materials provided\n with the distribution.\n3. Neither the name of the copyright holder nor the names of its contributors may be used to\n endorse or promote products derived from this software without specific prior written\n permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR\nIMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY\nAND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\nCONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\nCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\nOTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE.","category":"page"},{"location":"guides/model/#JuMP-Model","page":"JuMP Model","title":"JuMP Model","text":"","category":"section"},{"location":"guides/model/","page":"JuMP Model","title":"JuMP Model","text":"In this page, we describe the JuMP optimization model produced by the function build_model. A detailed understanding of this model is not necessary if you are just interested in using the package to solve some standard unit commitment cases, but it may be useful, for example, if you need to solve a slightly different problem, with additional variables and constraints. The notation in this page generally follows [KnOsWa20].","category":"page"},{"location":"guides/model/#Decision-variables","page":"JuMP Model","title":"Decision variables","text":"","category":"section"},{"location":"guides/model/","page":"JuMP Model","title":"JuMP Model","text":"UC.jl models the security-constrained unit commitment problem as a two-stage stochastic program. In this approach, some of the decision variables are first-stage decisions, which are taken before the uncertainty is realized and must therefore be the same across all scenarios, while the remaining variables are second-stage decisions, which can attain a different values in each scenario. In the current version of the package, all binary variables (which model commitment decisions of thermal units) are first-stage decisions and all continuous variables are second-stage decisions.","category":"page"},{"location":"guides/model/","page":"JuMP Model","title":"JuMP Model","text":"note: Note\nUC.jl treats deterministic SCUC instances as a special case of the stochastic problem in which there is only one scenario, named \"s1\" by default. To access second-stage decisions, therefore, you must provide this scenario name as the value for sn. For example, model[:prod_above][\"s1\", g, t]. ","category":"page"},{"location":"guides/model/#Generators","page":"JuMP Model","title":"Generators","text":"","category":"section"},{"location":"guides/model/","page":"JuMP Model","title":"JuMP Model","text":"In this section, we describe the decision variables associated with the generators, which include both thermal units (e.g., natural gas-fired power plant) and profiled units (e.g., wind turbine). ","category":"page"},{"location":"guides/model/#Thermal-Units","page":"JuMP Model","title":"Thermal Units","text":"","category":"section"},{"location":"guides/model/","page":"JuMP Model","title":"JuMP Model","text":"Name Description Unit Stage\nis_on[g,t] True if generator g is on at time t. Binary 1\nswitch_on[g,t] True is generator g switches on at time t. Binary 1\nswitch_off[g,t] True if generator g switches off at time t. Binary 1\nstartup[g,t,s] True if generator g switches on at time t incurring start-up costs from start-up category s. Binary 1\nprod_above[sn,g,t] Amount of power produced by generator g above its minimum power output at time t in scenario sn. For example, if the minimum power of generator g is 100 MW and g is producing 115 MW of power at time t in scenario sn, then prod_above[sn,g,t] equals 15.0. MW 2\nsegprod[sn,g,t,k] Amount of power from piecewise linear segment k produced by generator g at time t in scenario sn. For example, if cost curve for generator g is defined by the points (100, 1400), (110, 1600), (130, 2200) and (135, 2400), and if the generator is producing 115 MW of power at time t in scenario sn, then segprod[sn,g,t,:] equals [10.0, 5.0, 0.0]. MW 2\nreserve[sn,r,g,t] Amount of reserve r provided by unit g at time t in scenario sn. MW 2","category":"page"},{"location":"guides/model/","page":"JuMP Model","title":"JuMP Model","text":"warning: Warning\nThe first-stage decision variables of the JuMP model are is_on[g,t], switch_on[g,t], switch_off[g,t], and startup[g,t,s]. As such, the dictionaries corresponding to these variables do not include the scenario index in their keys. In contrast, all other variables of the created JuMP model are allowed to obtain a different value in each scenario and are thus modeled as second-stage decision variables. Accordingly, the dictionaries of all second-stage decision variables have the scenario index in their keys. This is true even if the model is created to solve the deterministic SCUC, in which case the default scenario index s1 is included in the dictionary key.","category":"page"},{"location":"guides/model/#Profiled-Units","page":"JuMP Model","title":"Profiled Units","text":"","category":"section"},{"location":"guides/model/","page":"JuMP Model","title":"JuMP Model","text":"Name Description Unit Stage\nprod_profiled[s,t] Amount of power produced by profiled unit g at time t. MW 2","category":"page"},{"location":"guides/model/#Buses","page":"JuMP Model","title":"Buses","text":"","category":"section"},{"location":"guides/model/","page":"JuMP Model","title":"JuMP Model","text":"Name Description Unit Stage\nnet_injection[sn,b,t] Net injection at bus b at time t in scenario sn. MW 2\ncurtail[sn,b,t] Amount of load curtailed at bus b at time t in scenario sn. MW 2","category":"page"},{"location":"guides/model/#Price-sensitive-loads","page":"JuMP Model","title":"Price-sensitive loads","text":"","category":"section"},{"location":"guides/model/","page":"JuMP Model","title":"JuMP Model","text":"Name Description Unit Stage\nloads[sn,s,t] Amount of power served to price-sensitive load s at time t in scenario sn. MW 2","category":"page"},{"location":"guides/model/#Transmission-lines","page":"JuMP Model","title":"Transmission lines","text":"","category":"section"},{"location":"guides/model/","page":"JuMP Model","title":"JuMP Model","text":"Name Description Unit Stage\nflow[sn,l,t] Power flow on line l at time t in scenario sn. MW 2\noverflow[sn,l,t] Amount of flow above the limit for line l at time t in scenario sn. MW 2","category":"page"},{"location":"guides/model/","page":"JuMP Model","title":"JuMP Model","text":"warning: Warning\nSince transmission and N-1 security constraints are enforced in a lazy way, most of the flow[l,t] variables are never added to the model. Accessing model[:flow][sn,l,t] without first checking that the variable exists will likely generate an error.","category":"page"},{"location":"guides/model/#Objective-function","page":"JuMP Model","title":"Objective function","text":"","category":"section"},{"location":"guides/model/","page":"JuMP Model","title":"JuMP Model","text":"TODO","category":"page"},{"location":"guides/model/#Constraints","page":"JuMP Model","title":"Constraints","text":"","category":"section"},{"location":"guides/model/","page":"JuMP Model","title":"JuMP Model","text":"TODO","category":"page"},{"location":"tutorials/decomposition/#Decomposition-methods","page":"Decomposition methods","title":"Decomposition methods","text":"","category":"section"},{"location":"tutorials/decomposition/#1.-Time-decomposition","page":"Decomposition methods","title":"1. Time decomposition","text":"","category":"section"},{"location":"tutorials/decomposition/","page":"Decomposition methods","title":"Decomposition methods","text":"Solving unit commitment instances that have long time horizons (for example, year-long 8760-hour instances) requires a substantial amount of computational power. To address this issue, UC.jl offers a time decomposition method, which breaks the instance down into multiple overlapping subproblems, solves them sequentially, then reassembles the solution.","category":"page"},{"location":"tutorials/decomposition/","page":"Decomposition methods","title":"Decomposition methods","text":"When solving a unit commitment instance with a dense time slot structure, computational complexity can become a significant challenge. For instance, if the instance contains hourly data for an entire year (8760 hours), solving such a model can require a substantial amount of computational power. To address this issue, UC.jl provides a time_decomposition method within the optimize! function. This method decomposes the problem into multiple sub-problems, solving them sequentially.","category":"page"},{"location":"tutorials/decomposition/","page":"Decomposition methods","title":"Decomposition methods","text":"The optimize! function takes 5 parameters: a unit commitment instance, a TimeDecomposition method, an optimizer, and two optional functions after_build and after_optimize. It returns a solution dictionary. The TimeDecomposition method itself requires four arguments: time_window, time_increment, inner_method (optional), and formulation (optional). These arguments define the time window for each sub-problem, the time increment to move to the next sub-problem, the method used to solve each sub-problem, and the formulation employed, respectively. The two functions, namely after_build and after_optimize, are invoked subsequent to the construction and optimization of each sub-model, respectively. It is imperative that the after_build function requires its two arguments to be consistently mapped to model and instance, while the after_optimize function necessitates its three arguments to be consistently mapped to solution, model, and instance.","category":"page"},{"location":"tutorials/decomposition/","page":"Decomposition methods","title":"Decomposition methods","text":"The code snippet below illustrates an example of solving an instance by decomposing the model into multiple 36-hour sub-problems using the XavQiuWanThi2019 method. Each sub-problem advances 24 hours at a time. The first sub-problem covers time steps 1 to 36, the second covers time steps 25 to 60, the third covers time steps 49 to 84, and so on. The initial power levels and statuses of the second and subsequent sub-problems are set based on the results of the first 24 hours from each of their immediate prior sub-problems. In essence, this approach addresses the complexity of solving a large problem by tackling it in 24-hour intervals, while incorporating an additional 12-hour buffer to mitigate the closing window effect for each sub-problem. Furthermore, the after_build function imposes the restriction that g3 and g4 cannot be activated simultaneously during the initial time slot of each sub-problem. On the other hand, the after_optimize function is invoked to calculate the conventional Locational Marginal Prices (LMPs) for each sub-problem, and subsequently appends the computed values to the lmps vector.","category":"page"},{"location":"tutorials/decomposition/","page":"Decomposition methods","title":"Decomposition methods","text":"Warning Specifying TimeDecomposition as the value of the inner_method field of another TimeDecomposition causes errors when calling the optimize! function due to the different argument structures between the two optimize! functions.","category":"page"},{"location":"tutorials/decomposition/","page":"Decomposition methods","title":"Decomposition methods","text":"using UnitCommitment, JuMP, Cbc, HiGHS\n\nimport UnitCommitment:\n TimeDecomposition,\n ConventionalLMP,\n XavQiuWanThi2019,\n Formulation\n\n# specifying the after_build and after_optimize functions\nfunction after_build(model, instance)\n @constraint(\n model,\n model[:is_on][\"g3\", 1] + model[:is_on][\"g4\", 1] <= 1,\n )\nend\n\nlmps = []\nfunction after_optimize(solution, model, instance)\n lmp = UnitCommitment.compute_lmp(\n model,\n ConventionalLMP(),\n optimizer = HiGHS.Optimizer,\n )\n return push!(lmps, lmp)\nend\n\n# assume the instance is given as a 120h problem\ninstance = UnitCommitment.read(\"instance.json\")\n\nsolution = UnitCommitment.optimize!(\n instance,\n TimeDecomposition(\n time_window = 36, # solve 36h problems\n time_increment = 24, # advance by 24h each time\n inner_method = XavQiuWanThi2019.Method(),\n formulation = Formulation(),\n ),\n optimizer = Cbc.Optimizer,\n after_build = after_build,\n after_optimize = after_optimize,\n)","category":"page"},{"location":"tutorials/decomposition/#2.-Scenario-decomposition-with-Progressive-Hedging","page":"Decomposition methods","title":"2. Scenario decomposition with Progressive Hedging","text":"","category":"section"},{"location":"tutorials/decomposition/","page":"Decomposition methods","title":"Decomposition methods","text":"By default, UC.jl uses the Extensive Form (EF) when solving stochastic instances. This approach involves constructing a single JuMP model that contains data and decision variables for all scenarios. Although EF has optimality guarantees and performs well with small test cases, it can become computationally intractable for large instances or substantial number of scenarios.","category":"page"},{"location":"tutorials/decomposition/","page":"Decomposition methods","title":"Decomposition methods","text":"Progressive Hedging (PH) is an alternative (heuristic) solution method provided by UC.jl in which the problem is decomposed into smaller scenario-based subproblems, which are then solved in parallel in separate Julia processes, potentially across multiple machines. Quadratic penalty terms are used to enforce convergence of first-stage decision variables. The method is closely related to the Alternative Direction Method of Multipliers (ADMM) and can handle larger instances, although it is not guaranteed to converge to the optimal solution. Our implementation of PH relies on Message Passing Interface (MPI) for communication. We refer to MPI.jl Documentation for more details on installing MPI.","category":"page"},{"location":"tutorials/decomposition/","page":"Decomposition methods","title":"Decomposition methods","text":"The following example shows how to solve SCUC instances using progressive hedging. The script should be saved in a file, say ph.jl, and executed using mpiexec -n julia ph.jl.","category":"page"},{"location":"tutorials/decomposition/","page":"Decomposition methods","title":"Decomposition methods","text":"using HiGHS\nusing MPI\nusing UnitCommitment\nusing Glob\n\n# 1. Initialize MPI\nMPI.Init()\n\n# 2. Configure progressive hedging method\nph = UnitCommitment.ProgressiveHedging()\n\n# 3. Read problem instance\ninstance = UnitCommitment.read([\"example/s1.json\", \"example/s2.json\"], ph)\n\n# 4. Build JuMP model\nmodel = UnitCommitment.build_model(\n instance = instance,\n optimizer = HiGHS.Optimizer,\n)\n\n# 5. Run the decentralized optimization algorithm\nUnitCommitment.optimize!(model, ph)\n\n# 6. Fetch the solution\nsolution = UnitCommitment.solution(model, ph)\n\n# 7. Close MPI\nMPI.Finalize()","category":"page"},{"location":"tutorials/decomposition/","page":"Decomposition methods","title":"Decomposition methods","text":"When using PH, the model can be customized as usual, with different formulations or additional user-provided constraints. Note that read, in this case, takes ph as an argument. This allows each Julia process to read only the instance files that are relevant to it. Similarly, the solution function gathers the optimal solution of each processes and returns a combined dictionary.","category":"page"},{"location":"tutorials/decomposition/","page":"Decomposition methods","title":"Decomposition methods","text":"Each process solves a sub-problem with fracsp scenarios, where s is the total number of scenarios and p is the number of MPI processes. For instance, if we have 15 scenario files and 5 processes, then each process will solve a JuMP model that contains data for 3 scenarios. If the total number of scenarios is not divisible by the number of processes, then an error will be thrown.","category":"page"},{"location":"tutorials/decomposition/","page":"Decomposition methods","title":"Decomposition methods","text":"warning: Warning\nCurrently, PH can handle only equiprobable scenarios. Further, solution(model, ph) can only handle cases where only one scenario is modeled in each process.","category":"page"}]
}