From ca0d250dfaf540bf137117aac7d635434cf0ce65 Mon Sep 17 00:00:00 2001 From: Alinson S Xavier Date: Wed, 19 Jan 2022 10:03:22 -0600 Subject: [PATCH] Parse new reserves --- instances/test/case14-sub-hourly.json.gz | Bin 1802 -> 1786 bytes instances/test/case14.json.gz | Bin 1795 -> 1834 bytes src/instance/read.jl | 24 +++++++++++++++++++++++ src/instance/structs.jl | 9 +++++++++ test/instance/read_test.jl | 9 +++++++++ 5 files changed, 42 insertions(+) diff --git a/instances/test/case14-sub-hourly.json.gz b/instances/test/case14-sub-hourly.json.gz index b788e4ddf9dd2052b34a74d47d2caad531a1467a..eb35ed32baeb713fc55403f67ab0fe22795a76c0 100644 GIT binary patch literal 1786 zcmVu;)MIlEjn)jz9xc6|92?b;WE?Y1kgX2;8_ z?sq|Nc0b-29sN?)Wm9ykq2CL$_3zEv_v_y1=*%3w*xq>6tj^c-t|AEYRol(x>*ifK zJ3jfNf8d{6w*ALw{UTp9+#;}xerxS78Jg!KU>u7kaI4m`tK?xPpwq5sy7krUyj&F5 z?WecIAYokROCWkwfADtv%vx*3o!ay3c4NQu!N1m3R}~A&wW3?!p7CY&rtj>oR`1K^ zHbw4Te|(U;7j`@a?ITl=Ii!pE8agIOZg(X1OFuTtd{A7Xxd@qWp0vAMcOr);Rb4IDOG4T8dV3RF zH)7O#++|k$ePdQsi|bjh&KKAHqc_I&da>AP-}Xmqc}t$6=@A5lae~6qGy;30hMM53JHz!G9n#7(0nO9VU@5W>u?~KW9Ds)%Zw$w8KZm6hwIpJC$m4#w z1*1YV?01MT4m?OgWAxsyQL9J_!Cebzdam~jB2*z*$5d5RUK?jbNGBvUN9ssYf@ZP` z6cSEuJ^C298z&XeA&Ow`t>7dyhNOmRLsW{vu^W^U+%hpGc@fI}#hU~=IhLbdSyDYl zpbb?Zguo;O?O0E>NrZK8?KV**Qd{Ol(kUVa&tdfnk<^miiJ-@^ZuJ6hnxbx(RonJm z%c81>jlqJ+;?vc-nU}M(vAg9rMRQShcl+7J-|MoNcSTJuj#rn<_LDSuG*RDwhLhLn zx}BF-pT2gwxiqJ8iXjCZBM?9IuudQSzG{}#6TMxm-fz#4kWa%$KP_pNE9?0+WA7OI zpYN@%%DPx|GzUKa`o`XDkJS&eW5LjE&v<%KJgo)o9>mj5#*>oJdg2Uv03uFE`~esy z4i1pL@WBDHizfB}1|!Bv&`Bi|j72iG!5D`;Xoiw|f_5^{F~D@BQ6)^Iln7`7TC_Z9 zrm@-+v@BH&^<2X{#T+zMOAXO`4M4S8$KZL?OrJGCoxT49Lv8es@hobqsp$rXE<_J8 z@Ti%VYk)dKbx^Fevu0Y_oS{h}pbqF`0_!6Wn(6oU1RZ5sqR|+<|43*_5~70-^lQ** z#~*-cJoh{RiVolj#dL-P&25Q5yO4CB>R}}8Tn{>coh8Enc6I^B$K6}KU)+O2>mg{3 zG}c)dQA4gZ9ULG7I5>dGs?>;xCln-0jE=^5>wA7uZ#IH@x^zyWmh~b8Bu$f)+FffY zON{TEMo)ns!986uCvgi)CiRfhIYM(SU?g2}ftsfNKO#qPPZ!NhJ_fk68@I8dY5XK? z>~DJdd`hI`ejN35)to{t(-dPQO)53xDNt7xEfra?!Hp&NblJ>c4UZI5_xB|N8}wv-npJy zMkg)ve=uETeC3)`nSU8$xh7KPU&dLkZIbzy@rvtjWd3E$;yMwTe;K#9jzQ*M#xAb3 z%lymu#noV0K^f=QR;hf|RP*v>Th?vWRqx8#VpW_EO6FC&<1dt%w&Yz|ugk4l)$A7b c$8uTJcQ@;P>(=!K-m{PY0)@sfo{ud601mWty8r+H literal 1802 zcmV+l2leHo zo5v;}&l3Ecze=lglQmgYpMR5l+&$Ypf0J*r^kz&-eRHr$D*xTkG97KIyBtY|^S}x5+A7r+4+e58f&i zUL-Ik+#Oawo+G6c-AQ);Q}2Gqtc+nZx6WEp?vg*Nl`FQZB z#S`!9aqsGR-bJ9sFOp~wxEXlmsAG5jv`)yK4gdkD$V0ROBHO)&4TRjP{7_6vK7g2%yJ;Ji!k2lGZ`uu_Y&uHq?KdMroyKEg>7RSC zG+*B(9RaWJx}$f(MY~=fm9IO~YFd(x(QrIMhaq#Dud+I+w|P5Qi6~qDM87Rlpq9Ow&=*JEk?qEWQ^i5W+3)2GsgXQ8Dqv7$RCzM4S0rnXVpH3ED|lL<9A7-`j(w z?xV5KQC9oKaK#AYw9>>12pzq)#EKSChUgC#-qBEr8h0G3Qm7rYgWpTS~2xX&D)PmGtGzTU@=ZV)3!f3Clx37i6hMmBJD^eRWER+ZuV&FjaCz3IoxG&Ci z4d7_v9QCGfdePQIf~uf|^NQSqgfU=&;~FJrzeXuMW(XqOa77tw2}Dsir;Vc)tW-v^ zkWQr3AyR`W#YrNnKt#kzJ@?i-g7P3-G%>PZ&d%VNXcVTJ;i*mp?+m$sAwfMxrUc7E zIX`)0f)0k{s1+Ks9+99GR-g!u2nbx!7Hbm=>+IaEya#h@7=S9CUSQAlvS+>=`h4;XMNeHwvTyD*EUrK?f0(Q#zusc1oE@gC;0B6SU!h_70{! z9Yu%%Gi8LRT+~t1pozw6CTL!$DD1hyBxtOb61=q%0Bg1M&eEufKC6d%@cvJ9wUT|t zlc=@CrW;H&&Rg(~MoqL_J=6nKC;3_$t)^3(Q8+2MC|$HZfVQ3nP4s&+L3>^bF+m4^un~k8JE}fI8 zdA$e%3DYFSc2{eR5@oxl(W2u=a8FmvN!-kmi9O_WjNn`g(PLgQ4x6U#-v+>?zJO=Txx$L^-5i>H8@+>WE3u9{P*c{xQXPLqnwcyQQNd5uLDv@>JDJzX{j zu=+tFc@-%1M>MLpmICvj516?Txm07BaJpCn}zFj9Ba zbmbg+^VAHeyJcx7(lATAV`(SSB}=Bv1dzbmj4tYEF6jd5oo+NS=NkXQ{S{r=Q0ws=wjs=P`@w zM0omn+@d-Lo_-#?sM5~U&*K+WgLwsIoL>i}@>P{Dvln$%)OnNNX34rtSG|(Ct&jX? sMxrgb&5AZVxK$n8!v2_T(&F)E-5%V!?%{P`XP?gg20bW!61XV<0Pogyi~s-t diff --git a/instances/test/case14.json.gz b/instances/test/case14.json.gz index 9876d5906b0608deb325304c32564ad3c7c54e4d..e4d49b8dc58b35c39d0d90ee180b9d33512ecdb4 100644 GIT binary patch literal 1834 zcmV+_2i5o=iwFqoGU#Cd17l%xWid1^YIARH0PR{!kJ~m7zVELvj2u!RVMz|3y%gya z1)3trF3>~KgVw9v6(CE79!a-B{(DFJwm7oJPB!hKPA*GQqmRS+zL}x@;b?)M<(sU@ z)_IpV?ed$&hwHKH@snbmFD~n*_`9wa&o95iS#v%6@x{%9Kj&56WL-Ue@Ir0)(g>{js%n_$Vn~q=SkY1ai=Bjs3|( z^K1f)A<;N$RBLh+E$jqz++|JIZx&~HnO(KF$3P$=gnP+JedCY;!z0d=@8VP7=pwmjZep-A)I7( zdt$%vBcseZK?R!e00Ib@9-i5;`$~(xj>n{6_W$<-T73+SDD7!&#Z*_KJ(O_}cvh1&$Wm!>PEe3VIxEfx4y}0Vj za_9PX*jh`kq$wI$1ReW2Z}TCl^Rl=oPK&bWuE=9wHfp(jxHQvYn(6TQnGTSSIY%&k zM%O=?=}IXO-Vzc3E(%F79YR#X@)&sl)6=2wgy}|4jKhJV;1g?8qCl)9MS)sJiUP6l zb&ny@^wqaG-8FsA(G11YjAYpt)(rPw&%;%9zsK+t zu6Ix8`p@iAd9C7KrfWEQ+I~_l%U;xO0*!4pG&u`v2<5f6A`10 zFitC?rPCmE^qLAkEusw3GxYG3sG)X4RSKh!g6*n<*ya7JoFhJ_MALkt|K{y;K@1D}igx(2YDc8)qJY{0cO zk)SFl;k+WBLBbfYz;TU|dmp0|9uB6w%W2@DBp7?~0*3+4XejRGAE$x$mb zsvaTG3NugyM+5}UXp6atg>`T3R$c^DTjC&b7d|>mVYMPgR7-NkgPg{?RSTRnS=FwK zwjHXLvZ%&|K}kgMaosnod~rH;+kKKX7kPI-pIk-0&9haPRcPXQeYtLLrO8I+<-=#( z!X5YRD&O2bc04?zF`Y&iob(=$A99?hm%r7`8f&8SvVOnaj6&L0FMnKPQ|x7S^m@-qlLT!;V(E=cGT%b2V zFmbeje?f$vr_E9%%1i-qTTp7*HuAMCGE6 zng&f2R(pcxg^I$OYkbR@g2rqq!CNZ)cww?w})O&k^_B<_-QK|Uw;m{H#L^|v6 zzlug0dILn^x#tEVYXcTh%ttt2-xd(GaX}8D?k3z$)u1ETNid9HCl_$E->sJW`Q3@A zEjTG7wsjgN)Q~DoM;k~0jy9l@EHxqGAu@u+dxLGfwgW%0Hk&{_pE_qz^J)r_EW^yljsk##aXu5hZ#)U#6%I3llJb(dpRX z3R+@WrIC;T`qA&Dw!7o+>#8fNp)D-Njq!@ep|8%*^HrCh-8a(2mv<%W%exhk>sZz` z%Q}&fSk{4MoyZ$3>xN~W(07(~%d$?$Fw44QStsO@W!J+0&pwY^RK>uv&tn&r z+IjYQ{GxI&FQH8HYb#a0X^K_;vdycu=!$pwqO7yCQOex3JAN}wlqK)-s?WD>Rg+uT zAM$lp-QTR+ty|YEc(*^UX}4)Q{FEj^baJ)H2S~@8qN*_akAb~f*L`(=H%y^AzO0+> YJS)rjtKl1vM<0*=0UC%}#;7g;0NAF7&j0`b literal 1795 zcmV+e2mJUSiwFn_LHl3;17l%xWid1^YIARH0Nq+kZ`(!?KF7a;FmiAKWxKnx&t8hY zQJ^V;I6x0U4zxtu1SC=*DW`7W|K6cwD;7BvheBEuRRS62&dz=_oNpeRd^$_;bN(i+ z(pA=ERekU?&%@TMvkn|YHX zpm|w0$$ZlSx!4{09#5SmiBkBjVEbi1@D#kS^9ZpvKRVXb`yRdF7~MxBj$F$gK_l0jS7Bv;rdAy@usmc=WA# z^69~rx9Mt~;Fe{+%9|(4V!#cA+@kzgj7mO%7?r!-G%SU$^CDkuR*14``M2jCDb#8_ zCYJuW6HD{uebN%}=Dt08D_m@r%cJsjYg$c9(lHv2M`%A}?(#)eC-pinioCc@qhO4z~Z?(<-l zgh^>eKmG(hCA{QPf{-LBLCKMnAOv4;(2>=q7zhiJF^b2Sp4h+4828_0j2UK(o5q+^ z>2i!K|3ImP_MFqOFMpRY3{o6}blqW55E(HA+r?jZ%2b5Jb4)iZa#`h@x;#8%Hfz zsf=PF9Z9Kuqy|%plSEX3h=`MV?yYwOi|Q=JIj8FB$bf_jWh z36_O&dh*5u9Sq4)D>P<3B0(#xKoJ}f5V)c()+QF#$+=s35ir{lFA}Zr(OC+s6)|GA zBv(AhVXOzez`H6f>Q!FXZ6~tKi*94EB%=7T+*I={xf;5LdY4u=S+ig7U8KCt(s`2> zsN$l$UDc1N$wuYn=TCR^xZKq9Z2h?HvfZPxoJJR%^d68OvRkLme=n;Q_C(jq^5fwU z1+qUy{j|biCM)LmguEf-fBr0W?0)Z=uXp|==r+-xmgP^aL7Hd&)T92yAk-E)6DQ z5S5EMY8o`rSWN`Y3l)VuR~QA2)l!1DRsvwHmfl$!HPL5vQ1{;diLO?%%XkvCme_QI ziN<*g-qEOumaBuhhw3C>OQY3zYBLHa1sA1@)(6nm)1ZldZz5>V%Ox@@6+eGCw8Ru5 zoptzEMI#Mu0MU3(G$67Ju!v$j!U5;DfS`>FvJG`N;C8A9?ZEB@LkD*6iiq~R)pDBO zorv0klQQC1hvUY80pmrz2e4y+>Q$+MBpxCoSiCnl#%tU16MM4()Z?Xd6g96GK_FqA zq}c9ijZva(+ca8q`~dFpiaCm#Su(MQ9FGy4Yax2fE5>2d)c!lu0PgXk*-IZC+`W6U zp`xkmDD2qY^tAC5Fq7M1)Z^mLWniU4>jvB9=eQ%zc z0ks_GWW?8kBRg2H9sU^#lJR=k&u}NEk{B61A!cq+As`!-#`$X?O7wWW?4vp@Ouz)j zq+{DFXo+o=MnVE;c$P~JrsE&VqRESPEX=!u@tmlk-(6p4^CnyD2kHK(-wxCV59v#U zIZ^9a+BHi%QIS~Mfu)_O8!YXHrJcy{EbW%1ok+th?T)3LNS7?_o~4~gYAo%6rJcw< zEbWn{o$9H1bdo&%C)1V3SE@PX>E|()Y9e|1d7P!%CZ2vCuc-cpr=Q0xsuSVq=W&bb z7$-#2ew{s>{S6#=qu9+U007gLdTRgx diff --git a/src/instance/read.jl b/src/instance/read.jl index 7f89838..a7c9359 100644 --- a/src/instance/read.jl +++ b/src/instance/read.jl @@ -66,6 +66,7 @@ function _from_json(json; repair = true) contingencies = Contingency[] lines = TransmissionLine[] loads = PriceSensitiveLoad[] + reserves2 = Reserve[] function scalar(x; default = nothing) x !== nothing || return default @@ -86,6 +87,7 @@ function _from_json(json; repair = true) name_to_bus = Dict{String,Bus}() name_to_line = Dict{String,TransmissionLine}() name_to_unit = Dict{String,Unit}() + name_to_reserve = Dict{String,Reserve}() function timeseries(x; default = nothing) x !== nothing || return default @@ -116,6 +118,19 @@ function _from_json(json; repair = true) push!(buses, bus) end + # Read reserves + if "Reserves2" in keys(json) + for (reserve_name, dict) in json["Reserves2"] + reserve = Reserve( + name = reserve_name, + type = lowercase(dict["Type"]), + amount = timeseries(dict["Amount (MW)"]), + ) + name_to_reserve[reserve_name] = reserve + push!(reserves2, reserve) + end + end + # Read units for (unit_name, dict) in json["Generators"] bus = name_to_bus[dict["Bus"]] @@ -153,6 +168,12 @@ function _from_json(json; repair = true) ) end + # Read reserves + unit_reserves = Reserve[] + if "Reserve eligibility" in keys(dict) + unit_reserves = [name_to_reserve[n] for n in dict["Reserve eligibility"]] + end + # Read and validate initial conditions initial_power = scalar(dict["Initial power (MW)"], default = nothing) initial_status = scalar(dict["Initial status (h)"], default = nothing) @@ -191,6 +212,7 @@ function _from_json(json; repair = true) default = [true for t in 1:T], ), startup_categories, + unit_reserves, ) push!(bus.units, unit) name_to_unit[unit_name] = unit @@ -276,6 +298,8 @@ function _from_json(json; repair = true) price_sensitive_loads_by_name = Dict(ps.name => ps for ps in loads), price_sensitive_loads = loads, reserves = reserves, + reserves2 = reserves2, + reserves_by_name = name_to_reserve, shortfall_penalty = shortfall_penalty, time = T, units_by_name = Dict(g.name => g for g in units), diff --git a/src/instance/structs.jl b/src/instance/structs.jl index 1e4cd5c..8b92777 100644 --- a/src/instance/structs.jl +++ b/src/instance/structs.jl @@ -20,6 +20,12 @@ mutable struct StartupCategory cost::Float64 end +Base.@kwdef mutable struct Reserve + name::String + type::String + amount::Vector{Float64} +end + mutable struct Unit name::String bus::Bus @@ -38,6 +44,7 @@ mutable struct Unit initial_power::Union{Float64,Nothing} provides_spinning_reserves::Vector{Bool} startup_categories::Vector{StartupCategory} + reserves::Vector{Reserve} end mutable struct TransmissionLine @@ -80,6 +87,8 @@ Base.@kwdef mutable struct UnitCommitmentInstance price_sensitive_loads_by_name::Dict{AbstractString,PriceSensitiveLoad} price_sensitive_loads::Vector{PriceSensitiveLoad} reserves::Reserves + reserves2::Vector{Reserve} + reserves_by_name::Dict{AbstractString,Reserve} shortfall_penalty::Vector{Float64} time::Int units_by_name::Dict{AbstractString,Unit} diff --git a/test/instance/read_test.jl b/test/instance/read_test.jl index 676a808..6984435 100644 --- a/test/instance/read_test.jl +++ b/test/instance/read_test.jl @@ -12,6 +12,7 @@ using UnitCommitment, LinearAlgebra, Cbc, JuMP, JSON, GZip @test length(instance.units) == 6 @test length(instance.contingencies) == 19 @test length(instance.price_sensitive_loads) == 1 + @test length(instance.reserves2) == 1 @test instance.time == 4 @test instance.lines[5].name == "l5" @@ -37,6 +38,11 @@ using UnitCommitment, LinearAlgebra, Cbc, JuMP, JSON, GZip @test instance.buses[9].load == [35.36638, 33.25495, 31.67138, 31.14353] @test instance.buses_by_name["b9"].name == "b9" + @test instance.reserves2[1].name == "r1" + @test instance.reserves2[1].type == "spinning" + @test instance.reserves2[1].amount == [100.0, 100.0, 100.0, 100.0] + @test instance.reserves_by_name["r1"].name == "r1" + unit = instance.units[1] @test unit.name == "g1" @test unit.bus.name == "b1" @@ -64,11 +70,13 @@ using UnitCommitment, LinearAlgebra, Cbc, JuMP, JSON, GZip @test unit.startup_categories[1].cost == 1000.0 @test unit.startup_categories[2].cost == 1500.0 @test unit.startup_categories[3].cost == 2000.0 + @test length(unit.reserves) == 0 @test instance.units_by_name["g1"].name == "g1" unit = instance.units[2] @test unit.name == "g2" @test unit.must_run == [false for t in 1:4] + @test length(unit.reserves) == 1 unit = instance.units[3] @test unit.name == "g3" @@ -90,6 +98,7 @@ using UnitCommitment, LinearAlgebra, Cbc, JuMP, JSON, GZip @test unit.cost_segments[2].cost[t] ≈ 38.04 @test unit.cost_segments[3].cost[t] ≈ 44.77853 end + @test length(unit.reserves) == 1 @test instance.reserves.spinning == zeros(4)