From b2e5a5e1b8c878be0dec3c0db7750a1fc83f8cce Mon Sep 17 00:00:00 2001 From: Chintala Date: Mon, 22 Jul 2019 18:01:02 -0600 Subject: [PATCH 01/76] NFP Lithium ion battery performance and life time model --- .../Simple_vs_SAM.png | Bin 0 -> 182046 bytes .../battery_temp_degradation.png | Bin 0 -> 114222 bytes design/FY2019/NFP Li_ion battery model.md | 132 ++++++++++++++++++ 3 files changed, 132 insertions(+) create mode 100644 design/FY2019/Li_ion_battery_model_images/Simple_vs_SAM.png create mode 100644 design/FY2019/Li_ion_battery_model_images/battery_temp_degradation.png create mode 100644 design/FY2019/NFP Li_ion battery model.md diff --git a/design/FY2019/Li_ion_battery_model_images/Simple_vs_SAM.png b/design/FY2019/Li_ion_battery_model_images/Simple_vs_SAM.png new file mode 100644 index 0000000000000000000000000000000000000000..3e3d267d4604cf4f26ea76c3384ceaabaa6dbea0 GIT binary patch literal 182046 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�$-J zD6U&RL`6lBA?nDZ7@=(dkR#R(I{>2vULdT(E!;m!T^%hx-ITH0gCo!l}G z;C?ri`OKBKJo?d+G;%GkK{_BH|Ax5X!`5jag3=%kBylt?q`L9-ULuWG zKwm(tvPUO<5}Pj2>HK_4eeCd}07TEzlfhXeB?+>}N*Lw50PjC%!E!-v%E*#L{gp18 zwjNmOG#!Av=m`pv)01r(c-+5NhXWy0H!I&KLHTgO&dZxIz4#ieC3s^2=vzQTg~P#z zx7_<0Q0F1lwxH_6*)MVjTLUSev3KuY*l*6qFMvPY?8d(Br0`)=wb=W1 zkUG0_^X9icn+!LSJ#Y+??3BQK`K$-TwO`Y?5ge`Y>)HHQ4kl$JAc^d{#pmU zb4QLG+2jfCXyuWCRw>23Du#&3fE5?zogCV-$dKGGUwjmg`Cmt=2H<%VfB&8|-++SNh^(W>Zz*nY{RtHFLKI~9 zb%SfWwuG7d16&LzuS%g)r#wifojZ3b&ZA`2abrg{uHZ^8@Dy`FLA3g}{D{BpJFxbe zd*fO4)AH+dmqB-mo`F%bn| zBUo3m!|^Y8d3i5gB2AZ>2s5!VwpiCRJi>(Y`78e|Tz7=?V*RgwOc^#}p7Q&!?~_x* zXAiNc%PGf>IaGe(VO^UI-!x|2SI4L5R%sC{V8#%6fSyfM8J?ohHUvj>qdZR0T_Mu{ zo;ui(pMgiH_lZt71z>IlH-_szapJ_g=jAHG!ou?MV;Bes0+96RfYeYK@Anh~}%8k4#(%85XodomQ z$9d{z06i}@+>CRsn%lSEB_6u}eTt;9Xb+fm&U@uoW=e~CM4|A@dO3f%b?B9PA->Gx zjn!^uo*g3LYQBbzfOa3T&{|T%M=tb&kn;^nyGf*#A?CW21tn4c_?X3ijb4D8{_VrR zXzlXH^(A?kvd(cd03F`iOHvkS?A(H2fj(;?MQ!ZX0mO-I+wK96BI@vRaeYFkB8g8} ztIwW21EG=xOxU%4HPe{HOYA~09XD`ZMZzZU2M-<$K`%s|f|>*hO;Oi+?WU$CrZun1 z(NY`eXa*gZ%!`}bxt5Bo@Vdc(>h{~Gha0F?MAtN6>A@3h6f5P4JRexwKqO?E+qgw6eR*G%%?Vxpl~>brj&+jGHcbYROt74mxjOxczh1Jat6iK*}l{3M6jLNs{01ybsh6Ii#Ih|R-5tL1A$I> z=@*TtxS!C7R_7h_eVp2J?>9D*nle&~mQK?wZbUpGhBovg)Hd<-_4l_!OCo;iH%*Cz z?ZNBl4L*S^^C;W$2RgJEcnqWKJiWL?`RmOUD;~8ca}?{Y@LD%K9r~8mKev2(M;q#f zxjMG_6RpFcZ4mX))FD=>hW4&8pkFjUXfecV1VnZr`k>7p8yb%2bVz<~kJRk!?2uc9 zFb9#Rd2EoG*&r=6{UMLYC+fd@FSAUrLr^dnJUKjS=U58ncT3NsB4F|A*Mi%6}&)3ojW=X;?@K=m2nDb>0DA8N7MnU$Jn|b zTuQ*iyA6c&R~U6F$#e2?`g`MlHkAql+t2Ttfj%cnKKg-NS7nouvWNyCARVPpAGN&1 z5NWL+oK^H4v9Yqcf}F!|n7rP*x1zw@!)tn?0WlI3lvIFHQ%@za9N^oL=^SbZ*$y;= z@{z9|BuDhbLB9hg2tb<0h-70Doo?0@zMID$aeSfLf$7+_;@)%1S4rzZ5eMV_=I%Tk zYKR4~detgqZPImCBhY4umq(gvkyMeVqqYJxS%f)tZvW3W@tddM;Xgvmg$ z(xyF=Lh<_N&{9mZymHQ-7BAcBrR;OX%WKwb=9X!Din92hf1I~$p>}Rd-QC8MibqT- zL7_+qjHeek#mI=a7G&hFZw4yq{Lh;io*NKw?qJlwr?)+FSkrU!Fazp^QOaxS5a&)? z02=j%|GrBZaFO54JEFxFu^$RO6A9Y(378N(-7_-F7S3~Xbf0o9czE@DxFLf7_6gjv zjN`4pywf-Hy?d{#ETjZlH(}C9;5RXAD^v+CIvVT^y@nA|rR*^z`!St6CST%1!y+HsgYf}`$ z9xTbeaNz>z`VC<1;hsIvcu7}BC+cr(2W?1_v!!>bI#p5~O0*9S&0A=2@V7g_-(K$q z9iY+zIzS|Io%I4d;eWt%-iH9OkXPwR+U``7e24Lg31G`_Am-d~my?x`x_VzF9^#lZ za_pRro*!1&(I!ebW}lX4=b(Ki@~EP)sg%X*m#<#+HD1nc8^9^C?bvJ3SGr1lcQ=rP zt(aFl^^pGiWjV2sFd(L`dylhc!D3BqYyvubcJ&RTCfX+7J+s=CtoE2v5Y$ z!1$ggOV+p}^Mjl60^La3$^mEIcjONst&s0bJz(-kP;lGRJGHl?^w<4&3FkIGw@m0u zIcAZqXWh~-h;QVHc9*iSC*%`^Pf)ZFD50u&KsLftjd90X<=gEZBQuom;vQq)DQ&B9 zz3a(;mJFc_Ha6B1aEx;D2SP7BRIb2>3wVl}taV}@SLF4_`3KwNU7mHJ;H&p z;spFT+sRw%)LCs&wcdNyoSQwg6(&Qonx&h2?1G56#$GB76PHz}L`AaywtzX6eMr;F$pp zDxljBZ-mUk0g#B1G^XkubOUXHb7e8N7+?nVLIH&ENi0xudtQvzE-n%hRtau z5OwcwpBxbcjWcnCTDWn}80|<3iw+m~#2zNy=vYBGBC;E1G-OpA6?TNkwhVEh)b)y( z<({N@-U6Z;`jkGQqJ%UKW5ao@3Y+6i*Q9OsJ%0_O(Mm-XpBGDbuDAa7i}>3oq5o!! zW!JJyur}k*B$|}gF+}z6w6%F7jiV@0#JMeqE}#645Rj7h4#b8#Bs#2V^p=bQ_>nUJ z{ryYh*(eoD?CZ@tmdMo5(~7~LI1NpYc@?*@S~@Nw$N#F(0!OPMfVqRY&7dYTaT?N1 zfHfSfND4nlQ(`a@#1}k;W_QD*pBfMlprTTaO|)a%HVAZE$;wpx??RETvf6dvw*B8+ z_df!<#?$n$!6o3v$Gu=Fpr9a)&VXm+kh4!?W6>@0T6%h6p`nCLfezROaEfvG@teG* zNlC~?p)%gAAaZaT+z5oK(GidxDa$jEsyM zTGb#v(Ocw6EsBzElgFD~83s}T0Y5<9Slsf^#GQ<6DB0j0TkwwReC(JT^5pNIlKJzR z6~=WDql=p$)CJ1AN8_Ol4GjSa5WWGM)!N!R@#GxH?ORG`&Rh(uf{q%)pQNX!Cv@;>uY=0SqPI6+$yK=lG=dg(BKIG zK0rtzlp`QLm@q3ZA3Yfkc zr#6lvdKaw{ar*ETMc5*~&0YA;DYA%&A7txz4n)TnM8w1xqR&te1ooPzhY6SR7+ zUg7`5O2>=XF8wupWOF-5jBgt^_U%q|? z$1w&I;%$uUh`(u$Y#ns`IA(5fuUuK?^{xXv39KqK5<{eI{xd_;IxN6@>jnppu~>#alm?!Cl0C&KYF#YxDM{ zoL8NnO_dS9{TzSDiI9Wwe;qJ+887CFUt2fk7zIbC(%~^j_+3bq4?7T~1hY~f{f71- z3@qc`>|a!Ar2sGh@iY$JsNPdQF8^0nm;;yg-vrP+!kU2r9lJ^;gnJGA? z2ndjF*={>3-I6P`cQ5DkCs)k{naEJ7ZQwB}wdo@EE+5XEJNFLHi2#@lE}M~$31zys z1ff_DF9V1N0=WrjTZZ_ac}t}w$$eZfmnTNf@QU33-hwSDcBYoVwfPBbl)zFg>rg`- z9UXWDKrW%K=Lh+Usu-AQ2jcXD2jVU$`Szsfa4XKCsNy9s1LZgAkVNu-t~_OXWBw=a z?c3M=g(^WwZ$jE)`C@U}HBeGO!JBX(4d`b)Zv$K_`7ZIqrp*_<*QHEfqYB3%eK)x; z&~fi(mFfK1OaKHIm-iUEGr;mBt9vGFjRYjl(T_^S1 zD+8_927kn?S(@-igcXy;u@p;jWMsqvjzZ|hKB)ac>w)kj3Js}l&O(Y_CDh(k3N(8E z_4Lh3IdH|-A|ALr1W<82IKi|OTdx3&?zcranJ5)bhIglpV?Q8 zyB}G(sgMv}mN;$)*#!0~=r4$_#vlu@GD!{Gf5Z3RpdaRrx(V17{OviMV2qnb)8uy? zAwoPs)z#H#3adpn!Y8l{nrd?&i&~pPH$8l_c$Iwklciu%#Hb!Fb^}p#k|k>~QuGo` zV8pv~Vt%bYrGP*vgj!usEcz%HiQNl|c!>L7)U@9G4E@hvU~Oczh1jgX>+m|;0RUit zfikvog<_}W7rvH66_Ooa zN_98~s$T{gQ8Do0oLRGc4=` z5G~O3A6SQu9Xm$msbO?S&o1W`=!-^@maNP|pFlEGY|6(KIQalfO>>`LSqF)rmwuY7 zIMq?CY`b|orKc~eWD*ee>U8#0lo&5vfsp*6Bd2-9JQ@CJD+oL-l6`xGnL-L zyf}ywLid~b8I-q(hA_d^w0e8+^!Xys;$zfk_vqPk+qlI@`y;X_djS1V{VHHW4N?P+ zcFS~9$@*Ct!$Sxoy$dR1D0svvjey`AVLvm&X^sQSB-9|KV6=+$wfM^}K@kzWDL+i! z1Y7F3n2%2dqRgpNb8Cu;w-#~@gY`!PL)R|r^7jW%f8xYCG1LimP9L;J(dP)Hpd>C% z_#nLb>xk~8@QRnpf`JxT7gzTc>C3+5H5ocJRSEI$tZtawiu(86`+cJba#J7Pb+{Su zp_)MknwpxVsS%+d>AXo6{apQVu_4Orxu#rl8QnCaUppvq327El283s1+ z9WDeJjG%3I`CG2t;5Xl3B7{-4MOk2AAOs4;4*{o28prTph>h@5y))VU6g3*ip*V*MMVPYOV=DQZ z3~=F+XJ7w(qe^Gc|4`9`_~H!V4Mee6yAEE0+SaYg%F03qY;e`!T8n*0Q*303Aq=2% zjlcoV{^nk2znoOGK|E?}GgOoJ7<{7tzkQ#PE4xX0?XHC7$RFP;VQj1}Mj?c^a2aJc zt`f^mIz$e+UI!@$l2re@cTypNrD1$dt^&*_dpgHjgarhgD=Vo#YyH0a4c5G8eNOBj>JMYZYi46B80rg@x#$cstrhOG^uH3uLoU>PDYotJ9o9f<=pu z9w5(E^^%R;t?@4!P8m6C^9fJse**Tuh)r0Yz@om;&B-C0XwfS4k9{VLOuZar1zMdj z#Y|IiX3zFXyW<&i7d$TdmKRiCGN>_r`iA#=iz%k1qH;MxYT}MX?5=_cnw0x6ZX?oU zpxV*agVg;QQtn|NAC05&5T`JB0@iLkh@)sG;&fvov_XWC5ZHqNUEuOuy7KYxCRSNB z!dstlS#~|3h|344es0D0Yt8)qCs8{c#T*-GUQ7X9810d}xp;VpC_M1v=^w6KxX#hq zhOw4;^6zukjPjwf!>6Ljr$)MJSWAo|N)DKUGfgWf7Hp(J8g+Y+r%cy^y1RE@fdUt^ zyj|MELsTe2w`)8`EslOqJ&JM#L`FQ%`rj}yXJRK?9EpgtTQ-h>B<#Z)6e3B0?E!+G;&hnSezDc_~l zbADZmku_cnK-YOIVNp>Hanr>t@cW&!4lz_OJ$~f*kMD-!vam$L{*6zdS!BZFMmDy` z?T7GB#uBVfs{~UuwL92hn~^ec8wd&7VJ7u>*nsey6vGFzPq>=I6<#(FUHt^kj=h$z zRpfxj9$wR5y&J_IK7+Que66K6G1g=+V6ttF-zNw5G;IAm+u9}UtRM=xUhu*=svOLc zn8hAu2*(Fmej1**42Urr|9gcXfDKjJge7$n__0MdR}t@VEVd|?umZN2t831ucNQ?$ zHNM!fBAzbezhGW-k<#g)zpiinuytxr?y&xtAmP(7;|kUWNk4S)wQF5*f*hw~8{!*G z>e?FXK}Z1(YP+sYYFtg@KdB6|E=eNMu=`=CL1(fP7%;CpXJFEj@^ispDh<|nJQy~nXeRJ?V z6{qoS6DLKVC?j^|CNGU%ALw9_OdS|Jl30J3zv{$Ehr#zU^0_kB5*`b7k+z2{oH8_!l zDIAuJi}K8(4dPl3KkpB!B}h_j+XtPUo#?y^66TiQjh_Q)tsQhcK_$RKT$V^F__(3F zAnPda6kSvohL>hiL=82>N(2py%%}{O4*W549hn-agpvq*6huT|{8isC>AOy5|1bJd zD5iv9#xg(H8l{zillofk-rX7$3j$-e_?*rX?`+zB@}wb&;G=lw(R16i8hM%;r&wL2 z=mk79wuGFNdJwA^i~nGAk|wGosP{P_^a+l}`&?`(vP(ram@Ra1|%ZjN*tx zjbuhi$>EcH#6Uzw%J)JZg<+)lwrtCo7I{*1AYOpG7hZpa^97)2B`mV}DFc3@B)u@Yml;bZXD%d_(aw_3?@@4mFHewLOV>5*SL$ zR`_P4oh1fv!jFt>fGLOLBeiSRSl(7b-$2;rFtf&hp$XG-4WE-PixGw}EE|cZv9FqXmDkao>Ku`KTT1M_$;S zz3o10=cd3(N5oEW=nSjZ_@4G3Rl9prGe%?$f?{#4w@Nm-etU>UQLrJJIfW2@NI_7X zPrEk${yMB4@Vi#iOtbN{m}@po0i2R%rA>O3c=3Ug_P=-2Bztmw$UYots=9ea4SH_fYs42DDaW5l(VDHoO2CcC;R}W&x_S4 zR!@3I%TK1TcGDd8Mc(u0MRo|oYx-3YZl=J=(``yCt2WQiG{5by2zmm98kC@eD8-QB zVd%Q~{CRJ8w?1S6^l85DD&9RFi1O{4d5Jv!Yr1vbCvUO4ZP!G<{;PSpp2|C+SI;GB zv@3nEX7Ck?H0|DHXqcvpyW+UcLMGuaU@pL`5OX2<71R*o9z$%m`cO;+dQHkP z3MlOM6nvP^KCc<=8*L@`?-K=qG6;)78*Z3bQjq*6#>ev=+eh#ylyN>SOhP>#^1xnX zd_B+&wh9{7fH2H+k1Fy)RqyUzK2c(H>EFVsY8-Gygu(6YJs~+1i_LcOh^<#1xV$tO zDk}09FJ9m)(F9Wr$`=?7P$viWq>%z>SP;qJ9Dzf30+I5v?`v*fzWFGP5{Sc?tUFNd za_PHSyKh^z;ZjuuTi4(}&`?WnUb1f8Iut->W*!!WR0Jv(ZPI%HRTnKzJu7+@+qg+(2}%FK6GqMN<%t=UkI_ z)(iVN^vg#u0~ySGB%PUTT1ur-VR%e{J-fZ`XP;Z818IGW6w($URP2G zBhLB+#&-{0YWYz;UuTE!j?Vtgdn!ib-GDcdv$?Z8AV5clH5(jy6en-ijdJZ& z7Dnm`=JESfj^;ZIst=puWpU?^uqH@z5P0qQlQKb%bJ*7Z&pFt00poKK$rTli#jA!< zl{066ttM6;ygUFA(rk#b(gfg)6m^GQZYvIXhjU~nNz&JFfebKJ509LCxU29Af11

m4#lNnswUnn){2lo8Az@6fvH}UqL~2!h4ephA#E9~ z+f=;UAY~z>9ZfiuZQHiNZ%71JjQq!@DK6=IXt5Vl1kS3TLzPpsK~m>mAV+7zylvyO zx+e#hX2VsS*6jX9+G1fd>UB_R8fy`n65hPAV};&8CEd|S3fnd2W?Tjn%wrq!Is-2O zLp|MzxfvuJ^k&Q{)Cc9j5d);BAYl6^{X* zo(!i)Ls$!OWx(kH+6<}r8Q?x#dBk>$0$X2~oXW-HbmOboh13~ZA+Z7+ZWW>jJUD?9Mu6RGsw++G!AS%^J> zTj;gm+GHI~VUsGfKJ1tX6QsqcVG<4)Tg37IVs5uN-;Di*dcK-2atF+qQnIc z1A+=8O!bCrUgO_0OEg?pqP~b=>UenM;ew#PpfUo45?>nC{o^_A{O7{^8}Qfn(3DSf z_ba?TS;8CL$8wm=|2D%m6x3x7SaKWntpPDI{^vr8WIgo}@jxO61qe{x20j&U3S|;5 zVd%rFD&mPkMQ2{*Dj=O`cxyM63cWO`R2$U@(2C#=^J9gDg|z*-aoBhBiKWI|$pIiu2DCY3~u+jBJAk74gC%e)= zqTH3(6Q%))3?&Y_wt5^feo_4-UlsBiYySj>j(+wgSyMPAxzTguY5ZcbbSk9rLx&C_ znw_^&0p5VvdB6O}H>t|m8b+<=_nizylqqjxIWBqEAwe%gg% z0HFm?Si1f6_}8yMwy1~N9re*85JlUMsdn5U^4qp=+jbVEH5gYQYR89Hj$OWN3E~ZP z9o@J*R(B!aX6#V7ztA*?&x>3%B$n5RNsa_{0CWa_y zj&MjurGoJgNK?lMc_>6EqQnAJBtAzRX2DTPj|<+3>COG;f*o-z(Is@JDf>No-nz8a zJsQO=7Kq@5_FJAAv;u^NXP1-@3tq5)oX((ykpYI942zSC9vHBCCHEts-4~J{kVP2M1t|DzQtE>o%ijN=c>l3NeLCjsU#zL~vi%@Uqe-*UJLc)6v)tlJ8 zxm|6sa!pITGSh~d603mjbl20lkva#TGY$-IWpj1IGO)nyfhhpCNI;A44%zPh{&5t} z5DZd)^0~izzT-#20yAwXbb%X=a+i(=Cslid4 zR<7*}MCHbt9c8jQ20PBL>^r7jMp)%zV|$^82Ia5YYsmlL-`31xN zGpfjAHNmY+pn(MAULaG!)WR#TtN zvFu9Mjv#YzDCq>tN`fU7TeV6ph^?n{zBeyOK&rHXS~}J&g0X&(?CG;-{n2G4ltk2L zNF;&?tUOgepQu5ruCeh=#}6Z)KR15m<6&cCLp8sqvIf4-oA5?OC+Nrh@XdqTfPWoB zPsf@@;Sup-E!&)hU4<@}XUY=88`&gJoIx^jJI^YBbPgz|>8dnExd*NspU4Qkbg-gS z0nckGp4VOT?*mrwa1&%JlyqS2GVB+D%8jUmFm|BZdZL7kmIC%cnbl*8CT#TU8^~nt z{)6Ir4d_T7K%e`n-Ozg~kCKn;!z)|hjJWe?{yKh}j448yQPPUmZ0A+Dhci z5{RD3G(EBB7WjR9!soKH*IX^nnDT)9G`fPl03;U|ks+;m##vwYN-HT%f>q&+KZ}LZ zyNdq|8CQU=_@KvVVsU7Hp8V!%Ng*vP3MUao9V`Y(Gjj#}7eaTxOZSEfim=cCg)+8J z&f)$0c^oztVEkNXAb%&5gJMKr%%@za)4+ix{N9NJ(d^LG4{~U}ZP3C*FUgl_6-Q z7^YZn=X?ZOP&M&Qc6E+|rZ5bU!%cSV$VTfbehYaLr_klZ*G9TE;#@7BO*ZT@G>V)8rB7Ylvb~yz|y|Y(ahNnaRRKi zP*UH+rBg)S!hJ+>!Ne-ecXPp|G_2_}DP4@o9}UCLXD>#C#!)e)!8($-3@8qSl!|9B zvj_m`guSahJJ4VAZjcaD!5|gM{>5B?RLpje$4xtTHlol!(5m7E@&kF9 zT`vXI5P>RI`+K)?@`|imcL?rXLS#6;hV&oJoX5PmI5q<0Uahi>;ni)Y@y9ha)+i|{ zk^Se18v3e#9>?d)F3|k2ps>^MF$=D|G6wgW$wwtte|g~f+9seHY#KE+HNm7pyoWly zr|5kJss`Ro>(N;(Y2->e@cl>6l^oWyTuM>kT7ddtmqB(6c?gzA$9vIpD`;~Sb^xUB zek>pKUOo?rx`kP`;pSd`SW-}#qODYzmTlp3NxsmXKJ9{64wzS5V8?Znd~r}{K?#sY z)Wk)ie?A`y!ErWEj-&4o!#LG7sxM)|!AoSR<_8Hdf;p~pVeOXmkMKX(=*F}me<;IR z%dw^ue~JY*P9T(`y|#|Gdo@m*$iyPi)Oe5mlz&uW1TyT$!S+#@4wPG;)6CE;0{eFnJWC6a!$a<)o5T3etr8_B@v?q+0|dm#(54 zHk9h@pdbR=Q{BO^;IzgaK__6v!l^zlAmWwdPr@J5mT5}1wOGIki73DK&&rq|K!7#G zt=AsEYxJz@&dCKU$XPp@Ie+)=Je03jv=z=5&w zdG;h1gT^O-7;#Bbsq6K6?I&lJQ`{<0@({RNse?xk@MaFva7`+tvj~{9U5$=jeDH)q4tfr5-Jqgy{0aQ-+(x7mpPggaAaCumRdYe9PahFVR8K z^AXC3cC|48p&tPRM!-K%kuO)B<;HVAh)7rBVB!is zdX07-qaT`{{OtCinCYXdSq$~!7%|gmxM0^np@^WLM)rgc>>YSqbPA4Nl)171RIC=9 z%L~v$V_)(pZs6fRcd=@oKFy!pVu45m2vq3UPR)(2uGT1V?D2%J18-21r9VTw6m=0w zb+ZdK#1l@|^29cV`2~y7tye3J*P%J-G_CmGvCFE&oC^xj-3eVpCp)rI(=GOB$avh=P0MZH(p|H`ONA1llFMnjvJYbwT zlj3#FcTpbMQ}8oX|V~RaUdH6VMs6wqwaC8EnEtp4_0q7sz?n6#4CHM;scCET(u`1 z=2q?A>*Ul;L{j)fHFJd_`@bbe=2c4%DefHqv4WG6nxyepjR|TB&>_ZyQ^ldQpxmR^ zr(HpvZ(OOD9fR>?FV4Vxpxp#Z04ja$91JgPghM`L!3tsYz$>F(Sn>|6NXV(PXYVxmtQP!y70-butE!-w*{l3!M7uVpj`jBLX+!z4pL+O71igqi1F%w6=T>0&rG3Ypr@o?# z24UQ?K-USd0G@O2n^&TiD-h*LKt&ZJW%`LM6G}sk-28^A2BVa_5XqG8hyjoxhF=1B z3O@S?*%Bg)q|_on<#~~Jv^K6}Goe)LL%#!o15}dCyaa))z^+LxC>9$0nYi;>VV~Ti62Izh!&{>lUM-UgxHgzjdJq36?Chk=wn?A@7{KcZwWS}h2)<)7kO^}V-eA0_IOu#7b5VVnaQ~4GdlciaWk6M&KzxD!b@r@T z#?GD28HN_VLh`Gz>SGSuy&M?W1mj?@3H-{$frt082hJwMbLI)r1M|7Wlgz>{U%u=% z$@k++6#~)c!FJ4j_=1NX`)nn-x)+nVEwBLolLMKs$xMwK_v7MztW+pP?8f$Y$FV2ldf&p6{XieR8R->xldwY4?v}W&IC`k5AZcw z+aWnb{pAOJr1x1vJ-Bq-(Q5Uxkhve=lm*u}4+VPFV9d1Mw=b&J7$k$+WM<(rXq%Tx zS-Y=d`@gmuef^(?ubvrtsFYx-7-xwfOF21n5j-%=Ddc!3nD@-ZOH#aiXHeXl5w;~5 zu^feC&16U5kg4F25Dz5QuVe2fIu2$78H?S$y+#5)+kP^8icaDVRk>$qXtPxXg*^>D z8K{S->|^`ek9**uA^~aVn8S~UWeQ#avIc>$uFIwUx?v4K;p~Ts8_hQGS(DBPctpks z0xUX|IO2tbi#p5)JQ^e0bj_MY{F=*UPJuzrZ(gs{hkxr}W#(l4)+huDC! z$;?*?$B{*iXksR;#CvNM<^c?T9*5P`4CMvvgTO{xxVy!77P)mZ*>;_QhJseSx1aoa z@1W_&ZTQ6&-<@Q!szyt0xS)j$!dxfWHb;zhjn3k~DHVFK;C?HSTZ`ipSiLjVE8;T{ z$H64l37^F9${`GFjf745qP@Gr#kDE30?qU@P1a)*n-=J#JISOX00pP9xS1 z=DL?JUnXhoflQZ1{y$2f^2}N7rT2=_&~dgamK4e(SEdxpSPbB;a9fgAgP@Ij5SmdP zfXx?EkZ2BU2;}aN9`XFkL`I2^arpNv|JorHxjT2CE?E=3yt;GtBCq)zQ5!d5FXDAK zYOW=Dh*g-h6alM%*Wv5egOphVq#<vOxL5}z6H9{mCyprB^C9vNr4lxd_tcGi#l6yDsD-XPp zO?FX^t1*=W1nLjWu8edH1--ZsGycrRrEFK1S(GCI^-7o(8!1LPfCvPvj-n^SXRv@< zX4~lP7DU@U-`AAGuoB59A|o>bIyIWEHU9imluM}GoLIELw0x4%mh7K4 zXO4D)F1~)_(aEBjvSd$!aS>7oLDm#g*&vt{htdVWPUr%n;7$ly`~r`O+Y7g)m80L9 zpoj1=GBzf^Qiq%}3KAAWYDtod5{&@y*)~nm+`yQaUqOr(nfjlz-p1Hs-#@>La zm*lu@lmoI|{1S!1#*&`B7n7x12?Ad-`4m7xUd5?nPX7}2I$b^bQO9KyBJk9Y2 z9EhXxA}3@&KPb9)V&_G9se$j(XaSMN89<1kkP;A54R2@l1fPI2#QV*|Zp0BRBaCR~ z9>$FMPdI-m>Bw7-)DQ2_V|4k)Wa`Wn2`T}%!8;m%^d=aNdEos7ohrIWUC)R(Dd7GR zVr|{#!#E#2Nee8FRDI|XrD&N32#mdMD_H+$g~9COI8opMnNUFhohonYjr-b%9)IYO zwcR$f7r8g9=I|eZ60%Zz_mx$sp3JAvCva42T>ICD5fKp}VUD0EO4YsS_4T8@Vw^Ve z?MjSu7uch!8VE8l_#*~bKgY}+_B8nP5Vls41QMPH+Y=cMWnfC^#zhRAj*TSE86SDx z@(W5KsSN?LAI8Qm;W%^{L63rN!lOZz{27>a6Apw&g#d!up|*AXc`O{8g5;aY7*i(t zdiz)^rnZ>!*(P}VuB|!D$WK7i)%-Qs^SZf6mUm7 zAGh@Np?B}f2r-FSTG^JC3zNlRvqYly!8|a;#~Oi5%*>4J{%#J^3i5e5+`TBDx?nD))*A%sj_!JW}{%e{rG;w)=s$cD8{WxFt}?QS%nwHk#n&P zc~Y2BWX3~G0sNL%U@kXPx4U*rKmQZqr}~;ejS$DR+H1T6Suku!?QoltA;K^vW6XUo z9Lc?TtDj=$p(&q}ipH1&3K?R$kRblvsU#rq7-=6w{08L~Juq6D9*_80h5p z2GxTUr`@1|!VL3Fp81dJ))aKYQ3-36;00fB4j>r~ai~^JECyJPfRX7))?QkZ2Ae&A zqvw76ci6l-KAD*I0YLJ4vDhvueX>X+SK*Wm7qCs;Y#OsNwl@%b>sA z8|H_fJ=+D{Z6?XoHGV%fxT6$CK#%FQAP1db-<_vNz!!yKOk35`(HaS9uNX)u@@A61 zw!^d90n`s6wEdtF$8biUmQOs?NHQkLZA~_Ioza*nOFoXeaj93n=?o&)C)63R!{iz; zUF$GP3BMFs4-c2AVl#{6qlB}@N;#UeE9q*?Wv!-wf5>VIv={h$KuW8_}dwos(t{YKmB> ztpx7s-64l-L%$E=g0Kj9C5EsE-v!wAU>d@7o~Q0-kSyX$hu~aPe2k7*=_#SL4s+)* zR2A&)=h4xNi1aoq%(3?>0%s7m+EL)HQ#>p7R9OE~WdH3;t`@QT@CRk-pNj=gtpDgY zyO8pt6vzyo%?UtAV|h=bek2Dnpb5Jgvjx|Ku|^qKd)g6pyX(Eq8Yl*Cr0hunmL(=; zx;SE@q@+%eIYZjK!|gp86sY-00o21$n?3K*-MmMf86*u5Iom-q zVzUWV)l*cR+c-)r-YdioJ=K*Hz-ZQ_tolwjzED&5xcKkcin( zYj#L^K>f!0nqti<*OwqT=f1Z0*qC1)Dg^75>Sh{t#2jkJ8)%5s;!|jQ(3n+}i~B`Y z+4{d}=e|Y=N)j=jUcP*!FKxB&GvD%pqg(#S(jKRJ+f@xBX5v7?5@2zV23r@}Q&V(e zQ9_1s%ch{y%B|W9`b)fw?U`U2_R0;nH7P7uzo4MrBKA?n z8YT8L#G!gfZ|Xtkt|lfTS4s#xM%8!t`=l@XeuFHtcGS)6X;35%Fb!!R^Wm<|TmcE~px0BDte16v{QmKwg%^%)*)csJwvQZw_Hq{Zz49SR-lKCZpGM}0GRf_C`od2;nJ@V8f86AuqCG-g-<&z3Z|(cc1E>oc>3=0Iui>1n}M z{*ES0P8sk1W+8&f4(8ue=sd9^N@ces$FjAm;+jvkO%fS}PN$JYvz%TLdg zDjTLbeKYq{o=Sc!nBXdx*i=xK&c@b$c{#=GEF2DmQER*$fGC8uu8Zk1(2H8}SkS# z-Qd+7ouG$u#i{A)iJ7{n>{l^jAv0>(J{YkA-a=3is#IrwPM{g=x^0^z(}Ka}X>u%w zMH+V4Wh4hy?4et1+ZGI7Xl9kDQH~W1OH)zVYGq4s;n~*tM@n&K#}Tyj22Ng|I=|q> zyeC)ITHdfP%4n0lw|(~D_pPgyx-b|%?O3VPuvNaNydgS19YI@TsbHgbfjmRB>j~yU zJKH#pBGbsx1Jy0%9n=9K1J6jvXfGfX35ay&-Mg>gb0J-llL}Bah~YVy29h5q?Oq9{ zMSuSI@go9<7g_)X5A{$o(!YZu(Z#8{XycChc~_1&xs z*B~k?(Mm5Q7$Qss)6fNMM@)3GK+c%Plp9QgVcj*;ydQ=&YqXmY*Tw~~u)Vp$Ufq3t zF=KzvuHHOl45$|2nBBQVZo^Wp`!C7xfkVX0ib`nd-SC3R)fnn?;hx`Fw+I3F+OwoV z*5e^zIv}RB;Qfbx%(Hn@^8PmH3Hq=CZ~%JNCRg*dc6Lr6L33VDRBC{Wl5BmqbUK~> z;)NA^xb>0L7QpOpr0x?I);cOWFkc0)11BhpbpL}Ug*Pm1`$4Q}X?))u%xy}FXV4w6 z+(|4Fvb*ZfP7W^Rq>7c7^Y%a82&XFa5uv2q!I?KLPAXf+=KFAoQF|gD)M6C_)HQO- zVT;ug_ehcnavWa1&;^pmDI)i#tQWg@Hv21xii!faBf4l|{f5sAC~rGT6d1PS8>%r` z1yz_}_aP)`$9DN8b`#%inXd>Rz$%J0G&LivRKOtI94s>?Bn>wXge|6}5!VZ2!1dDn zAJ85|7_snKA=ZAmX@)*n&SY1xDGw02|z%7t0bH2STNmtS|Q*y;E z8MB0MB&}+l2Y}OJBohN>uMb*nr(A3FWXNYj7@#UHuEjk@&`y|1CIB9BZ$MASiNaBz z?jU2}QxRES?vxRm+B7v2f|5kuc6^wwM4TwwQ`W@h@oiWV$B!Qe9ZD>>AEb(55 zuaN9(HXe#&>^*KQuW}f~e=?JbDNnSp1HRqlx&kGEE-`np5NNKW?65bYflN@ANq)N9 z!`fOR5HoXbVCa{YJ`8cNVxnVBSwTSoR1bU{Ky~j>KD) z0stj7xsV8WRO6u&z2fmbcgWmSMj7d+5MN>Ip5Q65>0V@H3It7ymj2krb2{|Aye$cyR{R#2yyvS?;l{H|WTFb189K0}Jt z2nNlRb0iCWFo>?2AW;4}>jP@ngnQuaCvZ?BsaSlF_0VDfdP|dWnz*?vZ<_@jhv;f3 zUV;V>y7*)KX4C*YFcA`u2R@Nl{URv7`wnp~rw!KUhNJ@lQEkOQdWi3E^FEL;^(w6=VGurIq%beO;5^Vb+Bl4ZVu4q*7^jIHmK21?#dZd*9^3pDH2&&( z72u@k3FGZMc2qrhpyfm6QB#YB4-~ngsDLfK_eZXq6g62KlM-lYGF|-=7w1P9jlYm} z{O}gSZR5gWw3#wRShq3tm(;)h9lHW0?R6<0yp7hxA3dN!071vV8wvJtp_kJRCNCr< zAvRUL8}?lp93FS?B+aHMqyl1NMM$8F6bdHXkbw7(iR6KrH}zdAz6H6RK_@Ms#x4#? zN`h&1a(Goc#!#cGZ;p<|jzPqu1$~2g=AoNP2A-o9!vP@R~)H~Jq#=6Ns_u-$0 z+o{14*j#olAE;d@+A*;M1Lx2@8_(lr3-$%z{SzvFSaEb=U{@5v7&0q*$8vO4!ucAl zmwKLAhl)Nam(Sb#Gg7wZ+Vl6bwt=>Idc!&-m7*^7}hZkCkiH^Jp`Uc zg@U8D+~Fwi{V?$9D`YLSwxJids4XQ~H>z8@a}QhKXszoU-Z}4rOyRpsyN(sQFRc#6 zOFmk^IP=`Ry%%wCL|GwZE2DjgVWon~`e;&{=(=?uz|qiOye@!$V#kss;yIvYNw%#i zMIxcb)_m{a18*J8JZpO(ZloSvS^@%lywu%cmN0PMlHz{?4IsoD$FfCF-B5MtuQrCg zdnN6_)L3zC%JYex9P4x;bB`5VU%(;RLzf^XZon=G@QkW8Ar$^9jG@_ku0j>mVa58= z;XCuGv83$@rIFy1My#qNEz%=~!{6BZ;WWW9^62CzHZX=V&}OuF8B|^^TNOLP6ZxyF;_Ty7qgrpp`Kk}x1HHh{W@1u`KB6*k`L)|yxPXvw zGS&xFf{0d;xyWr4VIQlf<|@W_di>4%L>HPNw!6QPQN5naKI z=&7Y+)ICe)KMzi`RyR1RQJQfAO*Z$csbtTXj6=$#nS^7#3E2cXCQ$JTqmQ{DgX zc1u=C$cRM9N<>M<|9TyF z_x<_*e!uhhJig<;KhAi+#`Ah!&+BT^nGuJ#Q^1j9Uk{}hNh7EOZH0e8 zg6`tp(cAJkT{lhagV+(yVRcI@#6@b;H(Y~})z`qox`T1%zlk4;oD4K1f5dgTWC%yB z!cEAF3g_8ZS)>;_mft$PETP=i^cG=~Hg+Nt;n3b;zj%7Ns;)Ht@Z{c*qlv=I?=YlL!c48bD;) za61g@4#gWoi-j%~Oy8QQcwU6IOuHj{1O!+MvQW3k@t1KE#BDHZ?7?7YM`*J<+ z62%IozP7@ArVmm5t55xIT7_7EPk+j^j_~r-Xs8`;>Gm3)c_NtYNs^RXF?1Ll4Ko_X zFrYLFI-gP%uqUJfeN}Y7spn<|G`4qc*~HFQjF)7~|~i zJ%jH?qAJ)RsLt{+mql(?G(5ufueml{P5J;JD8`m&Z%^ayy(8s#4+(sz2!g;2sIG?o zF{l>SK+eZDqf&x55)@F*yt%!NxQD{8=*aLWH9ja_4p@ zGR5iho5#SP7<3z8qVK6c?UD0wMO8}+TAJRl*BXO?h4|H97hlnH_~mN;MkOSF*wYyA zf+feX-=MFs4iQfLYb#XeCcCAb8J0fUl%o);*ZjIqSOxrJ1 zeA>-iXJ^Qfb&mw}c=<7^-3l425)j}COe290J?mZD2 z9!|~@2IAx(MMpFJGaP1~Sy1p=I8bG_i|p7j;y6oL+j#6w9Bf*UA7PE|e3qHAA&Y}& zN6hok*m|->KW_%HsVmlmpN|h`kLcv^zNv5pM2j|zv(8CJT?P0SL1K=8g4iCW1Xy(U zE>$kl^zDvm>L^Xu3UR9tm1&lSJg+ID zB^9}~l(@d)%&KRIJAF~J+#$phG13Gf+osY*7}!BBI;NB*uxWJaInibFHe*cKZf4>` zF)%C4(lIr6wo1SG42})T1Ief&;qu1MBCjV>etQNPUg*1qDl9ljonP)wYorrYmu-4b>FK9&THq4(8z)(4!OpGc(mb+(jL?++4faZ3QLx0u#!!Oy z_!TIIHqG$aZC{D~sA%6P&e98q)J#MW=lPuZ(RhdzCpP!P6UL+%)Kf0tWE4B=fqJxy(Sfmy5!X@n2+8M|Q#SlGV?)Y*E1)9N!=KRIZE(Am+1 zqmB#_E?Lkx#S@wdsuJ8pBX^-{c#orx_hwro9*^sG&YU^WE7_ni%qb3ZF@`RHYPwX%ZzkGF;LN3z8I3y1 zOxe`?J+S54{#K3`dz!Uiv{sXJ6~tc6$jCt3jL^~G(37OsAATVEzMNf^#^)Lt^8Gwg zbHbI+UInw9!_xeWr`;}tqjR$Q@EXR>e$X|P{zeaO=Flht zweVni4)14NR8S@N0C}Nq=L&Bb-1c1wxKdAJEic2-4E` z2p^G(P!$H0TY#Co!-p$wP%&GHVqlP{7J{y#cP%Z(nHMoUuZs<_l2GyJc7s!11dq}s z!U!9U*8qu*gXM)HEDP5SW}FQ`&x9Ov(~!+EC{M`m^B+ZGikwEEG>|v^BAu+ko-imX1Y##GV<;;C69`?7^}+28?F0sKz_lt41h!Vt+}&>$Eq#1UTnm-F zFG~Pwk(N)8grz)s``YWcc}!7@gABgS%^DpYB&)-P0CwV|;ED=)NX+?5pMfRY8m0Dq zbkya@;)B3NfcY4+4HUhJmzTfs04Ob8j_?yjICAVGu}6v>x>877V6P3p?gpPFF>VWP z_29u8)PFFtFcmoE_xN~Sn#p+-T5&l#8EkKBYa@+w5=r5)G{l;!SZSTT?uwJ&l|ZKB zlu37O7mE8ZN{=}G3ON>nf#J8&gD{Z`_hWz9fZ8%^i@>UiUw~rolX1^O9Mu)Z260T@ znJ&(QMZDqteR#l^3Qt`70DU-V$zkkpH6#g+ja8)fwON9SY{62z5sw2m0qo{pnu*(= zR};h!gfM9a35l>$E|5W`tVJTEey}9b!j+2FcIaH`(72vKPbYCUoO>Rf57+b%5*|PY8(`dWpHE zFje>A;dd}fhr}JJ1R=uk@sJik1@VYcAX zM1S-a)j1n~G0mr^+&O$zqyUz~f&g_eFaquz$e-K;$?Q^YnH?~$E9aC(?Q+E65z}@? zJlzJ>!L842mcX`fO!Q@vwZUCv^(S!*J&wr*uhm685Q@mq1%Vc`0e|KBv{zk zOfxOi!3**mYo9AY!&Q=AN~A^0d?qGxk>DUlJglD;j0nv>(W?LkR!^!_@jwxOB+Xy3 zf)SFoxCllajjfv?^g!R5)9b+E;u+k<{D}}IlLqjgF9S+P$0 z3-p}~r!$7`R_7lsLZ?MZk<-1G!rJ&NgH$6|+zdo0gp(EUaxk;Jva%nV-)n(^fmg4R zE>q|oY~aC_S7GL`cxlwcqwsAR66_d#E03z{wSa&>?S4x$i#_#mVvFE|f=5M6x7aL? zqv%787BtMXfa;e|O3O^e?hLH5#2``hoq|z_nxzV-J2EiUz3aR9R=1@eRkVB(_1W*- zLl`!dnu%{YnnbK?l_b|nIgm1t_PQ>?PkV3?k{sD06@FJqN1lvm-+p<<)X*AwK8Vz^ z+AcDh1>(n{)4n{V`19Mmw2FzT8L10T_^U%S_+ri{S_L^>$ouvB<5gbgFB(%aLi2Ur zACa!Dx)?)`?%03*%gyscw|zNdTH;o${5mryt#hV?GuBy(>&=A^KRzd<{qkfx(bluR z=i`SdDCK>F5X>BLEg^df75Rm@iExE~`m62y0U;%5VDpL78VjE6fmv3BDtk zzUs0v{vF|vEK?{gS#|*ias~z;5Jrei9-apYx%gk?F8y-Dyd7LerbRhqiR*DHaQmb1 zOXdevQcAYr8HVuX%&S_{KncFoh3SI;okdVMpb%7xJ|@jwmk8p)yOAD&8WmWm2K9=Jp-7vKf{M=X-Zzt?}Qqlf9*M0LtJVldB6gA~s~?BSU0=K1;g zm=SJ;suno%170b5SXq<=aH1kD5)9y{i=wm}Hqn>BPc&gbtv)4BoH)c)4uq)tF^PB1 zL$zJE;2aLPP0`}ztpKMzrU-kHIeW_HjWKLLJMVP5pARWwOY za4sFaz0p7msMdsoxq*~<Izf-cutJc-RIYx zAWdWjH}(vc;~_kS!ddXwNAws>J^FQ9$gSzZs1@=Y!i&Y{VBJxK)X12h)1U0!w(Pn} z!p|-IYcc_JPPr>mkOa(-t{k7y>#iJR!7j6Z`b3+yoA2!%wapxSF(qT+r|_8P7f^q= z>8E__hkMs5!O$-~J(+Hg>UK*!sv&*Ig&A3is%gwn$4yEa{#`aQdg;uBT1 zp;+_of8IJ#kg`Q56>D-r0jn!nkDAxM1i1Wp{KoCT9#}IYXe4j-PY7Y1Ge`gD*>mR^ zGr7%{!nJSrwfELX=FX$-XD4O!+1FPicH z8yg=spM`aaXih#dIYr9_r>SYZh4D5&cSBv3_{4`I7@GLge`=CEyV;k_iRAeXu2N}bjJo+NHAd_pZ`>h|35r6gI8tg6bDg@Y1S1+ywxUUhqS#8ckv})GZ}vK(s(W}x z{a%pKJM!zSVZmWr{AuGHOmqs)gmc9vbuX{L6XbxA*Y4vJg;YR8e9^C;o=8_4;ZhIL z5Ju1KKX2uy(n)>dU>_B=YVTgDqcG3&DI_zV1Yb{1i(b^ZGy5(WW;Fz=i)xeiw0X>6 z|I~tbG3qH;L#nt_Nzui%|bM(LEV5wH9KEaM7?P~d|Z(Hx5&$>CP4&HZ{rlB;%T3v8T)njA{N%{f%u%LfJ*o+rxqV6u?J!Jr%yb;UE(bqMC`2d3E?5(b*-um?A zbQb#A{+^g1Up&%`N3$p9dXxOW@0^XSyt^{$fG^tyWAAcPbXd||lJfPJ?)K$Drq>E| z#*~W6+pK}l?rSV$wJ_l7o^qY(&dpmEfV$s;-Q*)OpXso;|A(8~Pzn0ywE|6f!gO|_ zL-$^wHo?#L9Aq^R=>`lXHY`J8LzB3N%$C|KF12 zU7wa7Jvq7N8M(O_uPh84QG`f>ogHYu0Vsk0uqD)4xKwsDeu{ud5i(7UnjiQVxFt<6 zeIYXlaA5XK>|Ru3ePq$<+{|KOKL4yR@Xb=2NX^%ZaY)pZa z2t}l81)*`aI7;lYNJo6MSGjx9 z@9uT8cXmdO4`uNi<+RF{mcRI^jO_cyOU=%bVa@7RiVTjKJabJ@ev_p4)$9d+Ccd2_ zXe8*=5Mj_x-C6jnEd@GF)OJCzeS#<&(U*h?VCInpDoKjOh{4|<07oE#2Y?n6w!>y+ zNcI&UKD@*@qk!@87e9$5X-NnuSeGs{{oiYNYbN-0U{!UsZ79W{71ZB8&oEvY%}7R3+7RWL zkNE5jh{Mjht)T;%?jx|FvmvN4h+M@P5mP2SJh9;f>PwS-S-xt`n)BCII=h|Edi-~u z)@~;}Bo8zSNjrTBw&z7g#>U1rJ&^U5Z`}wuHL#kRHHQEbDTkr~=dV8)g-;dcZ6MhPhKAyhKu3qO_Njm`1-D=-CMFhb z;g8>j9NP%<7r;O8G0G@rvUBE$wmwxqx%~9$sG5VMb$}AfLL$=Ewb%1HkERq_p1Juq z%w^m~iy{|R6`fup;2*UzgVEg!?LqvhL>yI#@*m zj2orojEASmY_L9npF=)uG2_GL%%SpK{qL!(vB2l11pp8A95|ayLRsBY8TGchT3d8G zA7UzE#8J?(;BZlv`P|3@IY?nREy&ca67U%^ele909H4hhd-TcNC!)c9km=*j zH2b@{^!S2=7OmV8jEQ^(23|ajuqP#YUEs{5s4%VrwzjUG%>=*iFH2K213NK|PE~fy z!P@5kZ)866{J?ec&OSTDHf}VWGEq=qCm$R*@S!6I=m|f-750drS%6scV32kM9kDj$ z?1G_nIVt~2GfEas)}iMaBOZVJyGSHHoZumQ&i$v|@W_W#ZYrv(LyeD~!`2jpAL8uw zxP_EA{9CK|#ShxPpPZD!{ONyQ<pcWCECgU_hH$! z3U(peFMl5yKDJQo?_Y;rj9bfCR+|Ww6)m$6r!;?Zl8;o6mt^P!d;ou)SQ~;&Veb4z zY8Z_DF7?(*^|jko{{0PR++MbfODItt=LF&0n6IcfAnXPfJ8|0?+hKRy^|~^|^__fy zOJH1QUnQr;>5QB!_~-b<)A2u=Czo&75LHvtC`!KF?4M3g=IP30V*E7z^alCi|G&ks z{ks^NjLo}a?NyH99|5!Y$0qc)QGtY275Px5gSj=;{WzRZdte0JzUrX zYApkG9raHf&FL=0(Te;ze0;Bx48;liWm7PtI9XZ$^a8LR$z=u)yrkFLi2N|BDvPWH7LjpfFs_5fx>SrnkRk!9-+%7U}FKcR;MgXoF>KrbCkS9y}3UksiD=lLY!2Y7PJ zWIg!KZH$OS1&q)=B`PqsMlH&X#Rw$-!J!2IY<|pAhRTb5fCj{Ypd3Y!qU5L@jV*|4 zM#U!>7=Vm5M9}OjMsd~EHRltHyS;Fs2=lRBzy;_V3}RBEx=4aveTxyF!aR3Jv-DA8 z9tXS4XHD-(Go8Z{^g^L>)6XKE`C_uc3d1_QvCI3(9Gs1icJ0fLz_>YrfW|-m1I*`?q7?N+}MG zwLZ`B-){v$gIqzRX)iSBAgJQ&2X~|wj9k+-0(}{a#tNoJH8j|wsLp2%=}9Ic5_@eV zBI=2XaCP58RBbHq+}J4##KA^@F;~x+4;d2j@#H0WXq9e+z59KctE0JV{98#Mu;(Ve zHMM!pCtSH%BwfL`kiO`eFs}v;eBDC_^nDw^o5P!NYiUU13Bwm{XOr747u1S)+4{df z#t_CQ9>9%(Qk(IM7TKQ*cQBgr);`}w>sGt?WB2)U=P+L=$$Mrx)DogCgvT>lhHB74HUdNeZ*g%8#BFYXV2SMmZYNh2G%cWpMUX z3otEk1JeJQLB{%DGSC~2 zBZA(8N`4G|lFO^Qg7^7^Xa`~l^~Ss995C~KyqLm)6`qNH{#NWK7gExj;)uQ|i4uxA zG^_`;Df|RZh_@{$yPMJfL!8xMF-k;G5-dK;58RPMavOlJ1IipLB@+025(Yl#ZwU+&-6*1O_3SjdkzMZ4tdA3`9154ZNAdARbi=Is zAD6V3kWrIa57qJY&?2A=@)&xICGV>XAye*~AelGo?gQurK{CYGc%@k~>~G}r@&6y# ziLJ2@Uo!Co$>a`^N1w3@+747ES!9qqI6=Gl3B8=){!C3xCF+BLm{AsPM-B%i(iXks za4qdE8#lIN53p-hBy0wLa^f_z8=kr*XaOTlr(HhtQean8l_@X75wHsZ zk0ggJXkJ~2^S>4+hKX|Np=qI!kTLuW-{M0>{ss*S_y3vFE@OOK%}BM7#55Bc?&D9h z#y|plRFMjx!-dh=*F8KoChsxsfJejEeS9T zL@#M=HM!rnkd;-=d%A#WW2?>vPLKl+4OgsM#n01Z-y;4uZB|={$g==8c;WwH9-k<{ zF+G8t@=glnM^fwQ?Y|1^-$6HSKtk$jxum0O6#-^=Q_A^}4U^Oxav*f@ z%ElgNV2FQtr;TmGxOL*fDY2!PTn|5tj($}7v}2{V6;iLO& zv{wgp9;|q|BluiI8>9H$bISDrCRLDhfXdxuXa_Gu*7B~6Fo5jGJcvDZfbckeVZph0 zT5=FDv%6$`xawkwN*U@sVe$1?K~Phg8Tu%?V6x8%79+IDOt>uw;^-XRJ#Nf+8$^HVBYp6yUibiV+mbKm>XyGpYuBz_ zyI72%qCr&>WQ~n7GFNos^Xw@@&O@79D?gQ+g7yBgG-cI_6~thO#StP%;*X^H&nHq6 zx3@kuba06lC6IGAr88Se_$Z1J#-!MHfkUVE;+DRwTONkwiZIeOj;M#y@o{R{fVA4- zukU#2J}&7fjw05E#$y`_(I4i3Q~-ahcIElM2t8Qg;>DM2ZI<14Ew3Uw4`LW8-TcnL zJ^Yjt;utLpCDQm)Y)sT=1JjQw%?8C=xo(dFKn41kAHO>%@#z7D-xlZ_WG6%$m;q;& z@&tu$*a(EiBZY<}#(?FgE40S=d_>K!APi8@B$5?88Ysa?yaahq*p{>twb)Yi*U6MS z*jBio0g~b{=Oa(t_tYtYz6o@X=s0SDvQgBHTrfSTYU}EJY5qwHD8QrYHJ?|Wzm0^j z5xff|X;Aj0bYH;yMzD}4DkD>m$F6kO)0t}3-H?r-fbr$@o|HTG1m>wegkZ+$(Yd+@ zR`?^pu3FFDIvrB5oEQklG@i7mQ+SUD_yz3QD6wFwwg*eOnZxZ&ny>JtJL1Cp3DB!qb8TiTexoHc2oi!pM!V>% z3Y%kt?WJ=JX{V0(VlqqqA5eJCT@_={DZS=P1?j`*TqC~Ij(+h6N=fy#dW8eF4b&S) z3J3bG>u2fXoY&vmdC~ODSUK^2R!KOt{g!)v{mPx1DR0ALN=J8<;CtM=^N=YOZ%dMF z--}ciFU_mk5}pH|4;Go8q4;E(&7!O&s89Kwwb{Wg(lIn7VHHS_X736h%`QdCeoKUx zmpQs3I>&Tu-&wy=JbgM(q5bt?YYP1o$gs?=R3+{3fUrSW-VrSe%;4UkAPw0p0;4Co zpopbP!1dP&CvdYlMf0HD%SoPeww7Bu0v+MV>)qSOa_-V4AoE{P@uRnP`c*KVo__5* z52dK5%Ml|1zRNf8DbIwUqJK~{AmLOputc9#7aMDNoZ<{@2+349Z}VJ)GLut#FS`dh zJ>stuhEzronZ^h39j9Jj!IIEVxQu^4_FGeynw~3n#s5o3UA*GFq&!{G_tYUZAd)YS z)`lQ30P-Du;;?60;M~BEQ&0-2-N}kH+V|QL7d?tzDGN594Xc5!OWL(hcdWKt@A|>F z$I(A=Uok@i#~wDgU8g&k=FcymS4(|+Nc26?WgfZTiMno7Kq_o7&gF@S@j&x2B!+%eAVG?SQvGN9Fk3_JFI|N}G{eMJ%3=gu<=iMLQ z{lN8^SG6$jPD5+{*{->(SGx}3`35LPnh0=?fL9_m&ybi9gDiC!QPYBP@Ue*G)3}o* z%9pwF!oQ4Axo9@Api;jqx9e3HLC-P$mQjY;g{Owm7Ox2=Jod~Vs?wAXlIYU9-~0|= zr2c#}Vj~8cAWTQwzCg*NZo4~VQb<^cWk7UHQ2Dxan(Vw-h^>$g+NKe^P0P^b;9$Tb zN5&WvnK%M{wC$?%MYl#`b4^TOi|xTW1d~?_#-8L>r?_8E1_Ui zm)Bu&w3i(Xizz22kZoV#w?uy#uC;T&{F)rOhY-;MwcOaCD5{f6i|nyotSa)hzQag> z^ImRv-RvHjDp<>wxyaad@R9zQV+^PjDzTN01mWHR3viS+`hMiR3ejfxSi5gqL8lVdf_sRsc zTo$36b^Q+&WbuY!u`6Mf3Ccjnw*lNMw(gcvrwi^qPOq`qkX-XiT}9TdPK!Vb24hMM zC&r8&M2Y~l80p>4AaC{jHhk6yz4uX`5mp+S zcCk2N8njg_S6aA+{X_&$ycQ;?BQVwSxETV8x=HCX1BZXKtUfw{Jxn?#iO)#pMWhTJ zQ9Zx|kF_+e#pKuJ)?k2eygt7~xsmPkz)Y41Y9t2qsth~?q#Mw?hs8R*7o77kPhXq zhm1RI{dD%mqRMvZ^5q3gOyht4RPrr82}cev-N_LCwnDp^l>58$fw2XWyjHEWg0T&G z*MO0LPhsYot&1wlnQtErCFpl+!*M?VZ>ZN0hr;LtZxDHd5M*R@)b#9QMx$C>G$;AE1fs$t1A&fhuD6l()AAMwj1lXGC^l!Di!6krp3$3M&pX^xgoXd-1C z+%D|db?dEBTLVAO)8vHzqXJhj@-F_eLyou%*|Uq#zlUw1SwlTvYWtK)bDy$u7jVuy zDLKK>cVxCivDXxzb+qZL81+KWzOktIoj3|OH0o;Cj9{iGDU~Cn^1@CCTIbss4#Xh6n0AB$yTKB}ubIjD+c~`;aq2 zkP1Qy2l)?TcKssd%!bNT+4lpA#r)1;RazdFQBZ))X?zb%0ZU@BIT_0syyL+LiyHCUvHysKMRAoFmGMXTM_l5CZ zn>HK^m!)TMFkA2>`5R3zhzF2@uTc}SA)IL+75bIRskYVx|fd|CVPld=oiE$SXB06vv(2aN+9p{bSxWjbi2oj<ZLqVjeRPSo@e5Rgj9Uw9|_ZA3n6dUe&kW#Kc5t{gH~^UOB&Se`!;73ff$R-3iEX`go6;{3TqO zDcp1P6p{QvmOcrQZSi=(C@hme;YqVo1E*8C-@Y>{K={2oQ}n{w*|`#gNX(qj0ij1p z=>mFf+I}Lq+Qw{Qk6_V>H#^}l8HYtrDRg3S2Tq|P^TeJ5MMHo42BoGYqI2q)%PX&k zxiK3T)CF{7Lhl|;ZI&fVBFtEF7NmYt_Khr+%>ANymm?jkfH~0l1R`>&RzHFWyiRdd z5Yfs_K;WdsYLdh;U@K-^=x5uM()I#%u?;dVuSfSDHkm;J!p{20ecMf;8~Tp^7hfS@ z;b@%d$SWRxwGQbPHBM@5Inv;6aMXb&hN13|YIfP)4I-ak9DJP}XJUP4B-v62VGL|DFn^o(_?W|RfOxN7=BzttO|U;^KpYgtPmdCEMf`(sWzh3D7gz{i1U6{t|3CXqnym& zSO+zHV&-a&lY(WFJOzy`msdQR+6ygC;)Yz~k665jEr*^R&I%^u+#s5#FSS8hWl3G6 z=@nq$(f=Cr6FL$)y1Vb+Azn7nFp_bUJJDv|4P_sGdkiT4()~+w4o(1YO;7zgTJCr& zr!OR_S`J=}QM)p62JrcKZ;5G{tHdCSYjzM@dwSaXEoClbr6KQAkfS@cK zmgS-Z4R^P)QL|_I8xBCj-w9r{to>f|lvqzGmi5vZC(kPsrAxRXXnQO>g@oXpk`b*n`ym z*1FTfh}daH%c2i+6z%}=iqmq$w*kMjt_-7RpzG3&+t}*qtUUN=8c?b4erSQJx##K) z9^WraUpa;fG4Tau%Ie+qfYZ)gvnbqpm^yUdNHyskHM0Rf4mba%Qa;zkxPk~G;OoaN zqXI_q)=oRC4CyZjQ?}+*c|kw#lu2BJ$kBu2%bvb8vz0gEuV1|u#${1P$G@hT9<2!5 z{FY2oMMplVNUu~qX|)w57D!39jn7xc-UnRRSQ=bsq{6QgDq=bjw{PrC^5&G{v|XtP zleo*Gmi>y6LmcR8{?x}I=66HU6tqFTR+?zNcfv08?7#tOU#gv0^e2=1XV|abexz1y z*4HMim&_;q2GR$(X~j$SAmiZ;3slQ|DV)>2D`i*t)@KH1=)O_hC7KYlc#eFzYGjzS zBn$e?Xxq@I&6TZsdMP=n_pTw9qV25%w}frV0PgcX=Faql+^^QdzV(M0bGG-ZCP1H5 zDZ|6_i0~|wjmrtIMDJWa*bdBx5P|O>Cp~4t%rDc|1%QU8M)4mDH}~vx`FgN*T9mIB z-Hy~buNY;0qW3t=2c;Ie2SUwW!@Z`iO%p$$3ubiaP7s${snZ^RcX~ z2WbUlj3mACu#4>I>jMc`k7!9`*-*g@uW+TGNNxF452ClGriPRcPyu* z65=92*b)Ie*$A681$qz4E(bCQ2@ay;9e(L}ew)U&K$Qj#iJFDUVmF!%oXKcHknwKt z8{8T8;y@i#oKraLn&Rb-ZPoBDX+4z!^nv51KPU{DDXH>R*Mf`FJ0MwPqLY?LQ&Ay=UcNEP}aME)czA_lir7--uDfFQ9iHGapJY8qu_rWgD{|EU2;mR8;t_ zZ;TjZB#)5>8TOp1Ew)qjpr~An@dLxvW!TosS-S@&WIug%Xx%DX8v&jmqXxS6R+jE_ zAR~w&zzZ7;ov+;0YHNGwA#7hxocVTVu4Hn}wTWn1L#1EsyRodANX|y*n>CDZ7l+{lu66XSanXc+= zh7a4WfF72#YtYKnhi5amK)#Lp@!=SYMKo;Xmk6^~&4&vu^r1PlLR8M4j3Fy@Tw(s* z3>rQ35OHyt;3&W~qz`wV7gAj;Z~;&&NFXx&Qi!|nGnr;Jx;W{S2PEmF4a)v16fzc- zk=nkI?()@g{4=C`?7)uXP{4+jM7G)}XM2a0jjb))Cd_DrI0WpzFqZ)5X*FwNNd&lB zw{CM&BG3hDxhB3rz}^L1Bd>S3s`h!pJLic7ci+3@6PrspxPHI8Ke|^*Ue)im5F(s@ z)}vB|o~XKJTPzXty30hsWgZu^qu|w{%576;D`LBH)4*8rt(8nhJfrgaHJ6;nRma3_ zYi@%^8Te2{*zZH>1!}2r*z9REpe5xyWIpQR_fVvy_J05Q6V`+oURh~rIAAHtI;7xi z97OiqN%|@s5PCRd#O4YU3ZfZBq}`eGnVz`x3*;yl6q@W+VvH-_otbD9V1TQGbb9k} zdQA?i(%Hf6C#KiW>ypX9O+?I;=T<4Ha#e-Y9qXCdKyK29gckpCiwm3^yi#bAlg(&` zd$sPg+qrYDQ0U-hMZ0mNom3$1yy)#)G_Vk33og3RQ6D4Tj7*&%$WMOPWouZ{6obSR z-6GYa%YTSfLxP|>R5^~CN;SHpdBcnFnr5Y2N;d9|DANUFAvtRdwhvXScLnsYVpf#avA+(Z;W(jm9El3O$9KRv`|7p z1-wwt-S?e;j4k=>3k*PaqSo~(d7C8x7xWev+$Uz)#VPwzGjP+9jq&qc^Rc_f92OFP za5TKAsZ|ht66S;L>4$?4h@0E~{uQ^7PFL`x*g9DCkm+1| z%COA!ukQFKt`yR>MvgUMeh#THa@*zXtcZbciIuZ8f-s|%}6j^fLHyB?TEb^mZ~?XukfS4ux)){8qKE~`Cjkt-uXG} zAhCsdBT?eTu}|7La@(9oAGk3q-o?J#DL>bA6CT4!jQ(cI0!wLv+hSPL@)D@2{$g#f z{jw72Mt!6&7bN12EKc4w00LU=wqwtj=vCc)ea*ycS0+?i?);{p-`0Z}HP9aS;}>Im z!j?nFaoMm}#ox&(?O(@LD5Ra{=tBC)JuUcNoI~yTxBNYv2R6uEmZ=t>s9MC3|H{-U z4T95P`r+p8zSiEBtol_k6Ef@}A_zNg6-=IdISH_|x?GU9L$P=cWxxg$IRp;jBsNfd zuKQnniGfbDJbUQ(b(Z*tB^vaaj(Sk$@TFoY{|QMxofVRjz*64LvG0(ZYQMWN7PlRB?v2qnl%D8#1NqjwA=>snZYB6|=c0Q8o9Z@-uf2nx!yB-G z$T~FCDo7HqM?91yBx8aV{FE;AZdehQ2$cjB3P*g;q0C*2OM=A+nHSwcoW!i=Y^Lp` zY=~XWo(dh>oPTcvv5(6LB=K~BI6Pm z;bVop#GY-7Yzr`+CGw#6mWUu?D;QdRY(pwH$6DsgFIX2Ye2q+%=?5lHJVs@OJ)3p? zyxZL$q-^{5de?~fwVq;zovHv_;rGT`1g)nNxfPU(IogB^#aj;Llq$SJcc^+q4Mxa~ z#SyQ7ZDug|?>;0pKq!El*U8nKijdK07Pp&WmRo9*CXKVIo-nxPS z;#_0NGPZWDz56!pnX8yW-+>4p8N4#*$Ce0EjoxY-;O}Ca9M>x!^uwJqT%(Neo*MAW zQxj3-x5hQndQJH_E@KfH<2i(WURQg1G{+AN267(xZexfRGcMLt={JEbhB60GZ&?oubwIV!-0cdQN0to%b@-JG51I zB`2peY>?oaWSXhuI7hQ)7!7%^<@s-XhAniyc+SE7=PPEzBVH!Ox9kePIKy@6B_rzZ84x z)-5KHoTk(7=DfG9+>V@v{UObC5Z9kZ#y*JN#ult>25+ESZuR{>L;co8JQ5V`P_)&I zFs1*lxyD)2?&B(;!g{9hY!>JMYP9N%C^QQqeN}aqFTdr%=5qSp^TxA_uO=<+C;e=t1`aN1NoE&3aGG84^KXz~aYt(&4 z^Ls~I(PoV_J$zZ&(=++|c3dj*%t$(>usmlzF*Rf{BAPI;&ir4+$L|~Ox@8HMtb3oA zH9ea{X{>gG0H^l>}kU?cZj!m==)(JRCDB2C2fRZv$S z3f@pGkKIrck3+c@eb#~8ooIDS^FA1*vvBcZyZ862!Hn@g*o>?*&wVVJi5pjPjs>)dDXl0vmQ7c(va<71@Rf&MBCwHXwh2MbZyW1j^3qnEEdqG zNvOr#oGZFATTj0BpyOg7t`@M>y;|=gW7vrl^K1I(k~@dCET6iNLHe5YB)*Cr$^w&! zq=H3%n_I20pL6*1z8vZn^r{jLHcE*;8Tc7-2l))?9tX#Yc=!eKe+);+ zfLBkRRtnS-^mig|1{dXMF=u7T<4P@&iEe4 zjrq_tE^Si2re>+iu|y&AO6k0B*9R{hu4uoxu3T;;9~Dok4c+kN8}p)6El%vR5ZR1_ zVCra@{xofYpx>t&lJzu&eoW#@nc!V)*t#^{0>(2)BH61NQVhiCE~Lmu<-8k7o7n8D zp2|~zF3-{YCgi6DkoyB1{RF{+@F6hah1k$aWF&%H5sguFAdWN^WmYY!c9$<+DjmDx zrSoVBt$t^a!qmIRpkIGY{&r?j;jEO1h&(G>E zci=#?XNP7f7dD1GSH4Hj)xO@@-XM5fr+26!c{zQ9(lO5G(#FG3zqqBeV= zoAT+Y5B~_gYQPUUPg!LVgBM~bc}@aA0<~hEpjEp%KoOv7&f=&5<41lK4sGTQzma03 zDx4xytWlK=jYl@L)vqV@;1H~3XC=PW8HXQk6X`eHzoQ_Y&y+$8hXLLoBYJ4~9+v1V zx#r*N^#^i4(BHNzjr{mw{4jTLYobEnge)%m^lja_U6XuDmbuJa6vjRHh>~4Q}Gj*N596Y?B3=Wm2l!u3c9{YbymVLJT!< zsvrfzm~FFVtNV9~+@r`48Qi1giT+S1{lsEvWN^C{_pKu22&rS5q(p=~+VcnkH!@m) zg~jmcn(P?u^{Jsoi?3r%H_N=g?!E@Fhn?z^#n9v2=dcD?EXo5{Sq;>5?|13wt6Bgb zOdl0taYVb%AM6nIn!Ck&>LHO}$O5fVAnKz+6uy8>%gP&E&M#u&#$sgq?)KM~3@lEh zppJ^KzQk&609mbUo2Q`X5ehVGLi&E(@{ClTtzunpQ9e0<8Bn^uY&kbh+w&G9C|>ol zdvCpC{-Tw^X0L%d>lUFvViaaH(YZ2s;cTJnuJsNieGQ+NNgyhv45Nt{Ed)djOfKS@ zWXQC8vrZX*=%5ioi6H^QAT-iXQF=%obpVixh?YUuu7#?*FIp|iwRWx09^vY2H|Q!3 z6b=#n>ca?x5^U#l#tK)cu%HC}wq;L03Zmb0+{Hw49$9Clmh4`w#C?%Du`Q&0cVFJHV%oRO0@^a) zi=@#Rr79M(0m;-|CTLtDtfJ4My*zy$B6np?w@?d1>u0C(DEwzHbB8KT5Rjqi<&I> z;LH9}5Eiy%9P{&EY5s#FJqn{$XUNH~at&zQlQc_WXHu zudx2W$Bqc68~W<07cWgGr{c;&-8RC^E+`{VL*NHK5J?iGN2Ys8nSB~18TQey-VKnG z>1JCWVv*TuJ4{{t6bDtKMnYaGM*UD|fRPfs36&$lyP`-@9mM zV@KD*AL~R+ZPuU*APwg0W{d=C;@8mW@8QD3qxsM3?p$ns8fNwaU=@e;Jd2};hX?Do zv3cF*3>}vgTgspO{{gHeR8mMX`0c&u4*+;#?XlM3ZQW~7yU~@|(QrN4P7GqK#j8ah z>O6P@(ph`-EJ##u%v4~ny@zMe_v@@6vhSRG(8t4@OIJn+qnK9J7T%VniC+&(r%<@| zKn(~#;$MK-pg{lp`P0Aa^b1Vc_@ihpPsz1>oZx!0vbD9fZ(5WeP?_2bo|>*(&S1nM zMu;nt-qSCAF&(nc*#4X%4#`44)^IJ6MUN-dkVXQX;ih+PM}~>2l|G8(P2>=!bbnWg zeGRX;kgsa*qnMYj-x|>b;QJln4kY{p@+O^1GI$HTeKIIFr~wu(S~P)5X!XF&%o}x{ z*=G)0e@$0qm0a1R;cndd_3`jSjGzVZVjm@n=wvCdsF~$0#~cnzn%{EfC`Ui4t`WX_ zh(Hw%DjR(Yz_hrNrh8Mu9tiD5b8>&n%;X4EHppy@y`9I9wLw6CnU?u$`yY6PM}(Wh19MjD2_(D z5)E`jkj1IU7n-93E2pAb&HM}{hUAgJP@`Wk5a4i+b-wPnj%wU^a&$6%QN&kX_$?tPBWFKxRX& z^yNXVEcLiGT>F~6b|IuEW{OR1dx9HcJr~zj9-gVN0*p3mQeUUDVwar+&m zHu={txiC?9jAL7tQXqq?__|bs7-?u)euUANKt$y9fkOP=pPfPHv*)Y zu(GDSC#?IgFN4{JGcpD0#olny(M%4%J9F#0-(xpU4FAjp6ebl(5~0*>!rfz--<}|r zm84-kqXtQNVlCll=)vDmb-QTeemQh5r5#fRA-X*x%_4)U)d9Mhj^NpwPR-T|dkS{^ zIJMSe6Y0jP5SmC>6^%F8f9ljJ#N*to^+-l>x3OoFUg3x^VOU7txT|vzY8Wjc-lFl2 z0Hh`U7cZ(y-oR7{D661@puMw3L_vCeFmK~UX*@Im^3Xnm9T?9?MC)BTnZ{?kOmD+3 zIK!}%{~!`?OS_46o2}R$L#AVri*cg4_lh?ke{(|>i3GAFKv`j?lN&B#10T?QY9wWAT!H$`^>-nY-?Fy2ykmatlT*#Kv`@z;_cX+`1@#pw;+@&|=caE20bmpHYrR@#8(kL!{3hNnddLBx|l)wCO;~&UetJ z@ZAi@Z$T!2l+zAp9>lrcX`;kNus@25RQ{L^*_aA`OLr6*!$eJ^XFLSb$k|qISdLmz%5<#$BYqj8d;mzx5#f+Z9j1 zUaHe}LW)KYtp(tucYqkv6(Y~v=g0rHPo7}LQ}?;u)a$l->XXUn+rpE^6RJz43<3;5 ze-IiN`Z0na1!yK9BK}~h`T2Gr@uoj?YA=~XchOBdVkne&8r_yRyE|9pm$6ZNRzdIn z4m2@D#z=agr?kcoN6I1j#4}V2xUU*!7fh)rZZw^+V15u*^(`DoN`v-XVBH|8dTEqF z#$dE-zC(jwcqAS>nO7sk&3yT&WSo(Vx@8`?0!M|Bc5t!AP9e+@W*#WKa-eXDVvs- z2BCjcJg@QsilZqWOgX2f2;!d*H_BY$LY!#%-WU-CEMzPs6+vzmE^orRQVqM1PEid> zeICI*Dn94<%SH5#B+sWLx4#0)wE?!hEH=Jgvcbm(3M7#SFeaq6-3)*|S8SJ4(R}!F34!{679%O7f z0Jq>b%O$C$8eq7mBB&Ka=?7 za8yT4_QsffU$<&X%(P<)bB&nanvt=$r09qnIJ7#fYTL)q+2{Xu1fuYSFM)f{z^HPC z_Z@`~QaGd9brxedP_Qf0ywW0vS*h3jrHFc_f`e7kfAdpS;enRN2ZXpM$`VorsZ&`; zFT#4(GA}7<%l69~%`v>yOn5@Xlyq_FzUqw|6N5Snsz_gTTaifX)V0>#baa~GMHl+7 z|6VZ)(}W2{_$Nyz01a?WiM6%z6k&c0$J3xifS{vu)nfmFteXL;qp^P%+br_J>X=7SLVbuV^&&3zP)h#)0vOuQHMaqP`W=-luI4_3EfI67h2BCONKZLM7cl z)4b$*@mz|JAuC(OQ)G_#k9r38)G<1aJl71@0{YALOZTEj-!`V2+8WTerx2}DaPv_vBP!c}fl&LIKNjKOSz1d?}r{yaP<~XEdesmEML{zl2J*KF*eP|lO zDB_DnuuZXDb5ooe4bzn&&SWq$WQhdjdP!ICdEWZeB@7OcXl^d+M*ab_v>n4GQM>|* zCBYY|SvkUKSEdv$s!kN-V6wtuBo?(^;~w*&vuDpvT__HHj#_N-W<}{CCpo{NnCbDf zzTPtL&G$9UTj#JjvgSr|J}0nGV01y&PUoJz-Yy-e^{GXK?>j*i&w4&f=3RUCY}RPT z4*ZHYmSwk4rcOZAwE74mb)a4G9^++*bE_q{k>Jb@QoWeeE9{^(*)PNmI6eb8U)AYvwS?k; z?~hA=!ys(XBv{@Eii`jB5a~86=B5N|G4I-g!$g`gSaLJ4P&sq9?n%KTr|x-+O_$no zuLaw3dXB}!5^;Tul*N67mSesMJxpvRgM~2y=^>I#+jT9^pFjWb!Jzo+T*)Xah+QkU zsXWf37bRliHG1Nj$kFE^wte4XWuS|pylaBIr9rsK!;onFIdE2?cTCx8K-Ob@nIh|R}@HrfsZo^IKeW}EypU9eH2qCW9l%eAVH?5l11-C%u%Sm z7Ma5cxmO5kk_Th3(=bkQCxwkg%YiOOl-}uM1UJIQkqFwl$LYZ){7hIhS|;;QIKCptH*rA6Ga{PX`FyjNuk$`@KgCF($@w%i0in4A)(8W*MM? zapA;;LU&YEFZ5FVtP>9nyVo?`7o;*t!8Qgw`B|tGBHAeNQ0{YY$U&x=S@oa>_6@h8 zQaaBYWRJWiLuDkvf3dF?G5(Yk*Hso)5Qzp`&ZP7b zR4NLEeuwOTX=Ad`X8+h8-DHB=QT>C!tSPGpC{sYqpJ?B7#ve44PVqB4MV{AZ+yg~z z(#ZP-zopRwkxFhOYeNYWLwLTmtq{_((xWu9FzeJ}IQEsDRmzH;|NcJY@|LdCe>1$n4gjC4v-8^Tn|RClC3^BA=0LksZm!-h!TB^ zeHKg!{m^z*(z_6q$|^yDR8d|sHRI6N$TxRY4Z$j-3u**d>zG2=u4R2@%BHaT{*aoC z^SNm94Kapj6|VnYv(sK1ddDc0HZq`$$9=V508;RLN||!>&e%bOYpvir?asWT2hB+x zRGbkTytZwFA_|yRPQ(btG*}vZpBvso7TTTIKC9!iCThgPDKd5pZZz2Mq&2?KqztHC zuJ}Cie&UA7tnMXks@&&2Zr(s&-_s>Rb4w=hDtl-`Vii-c9^hlpp^XDGJ!ugXj&_4# zCHdXn%zF)BVNYLMXzS2h3VUU0&E24?d1O6CfLCe~z-`h@$_yn$S2w$=(P}IdVqE8WTGgtVV zPQTFJDHmDJRzlNee4k=H3yO zvh!z-WPbsDovGt=$8=bj&bNIpiML-DzKv^|dJURG3Zz=u*I!>WHO6uvd>8KuCh~)y zZTwM>riLj#=jC<|bG|x2uPZPURY$ByvKY1SIu!_z@?>;VmKD~N)zq9g6Qfqw*=+7- zuD++Nlb}HEAE6>8dKlD-@nL>bg>JEAM=ssMR(deHHA3A2QhtT$c&1s`Zgq#6A5yO0 zF80#fB{W8Z_P<^CvS1=9G)0S_REcmg)Icn1uSmsi5gq=Dk=OGu(wGc! zV>G!ZvHXs{qZ7!0QAoH66#_BG`c?EFkrh=}S4+zST?dg>IW$hoqel}tuz@Y^Os-z> z`j43S#S>e|NKmRaxo#6civF2c6N~&XvSgdwV_uIMoPzW5b=Iy=dX0UcctONMBMc2G zLM{~CzRpz^s}lAz@C5Ccj+cCJh7|&w7(wJd!}T5s9Hj_+wy8lo(-GB9SQsG?H8GoC z-8XzGsH{6@U7Ug0NX2+9v3*}xH@$G}CsIEuPrIbIVBd?)uWtw^s_l>v_O*>+yg8%v z98djbsE*Mn$_tGW4n^?7hVCl*eU#hVlfIL8ujNt~*>Nv96B-k@+Ss**kYJQUy_buw zF;Osg+gx-mDC?7rVJE<(0ZM4>6~D?2PZT2{RtSc>$PA;7QZIV_**a_0zFu|-eeCQq zxUmD0OVuZ4Q`K;O9aLR8k@+pLaziquF-=-}dQ1UIJ$HyRRC?{EaVptTX`-p$sYO15 zfn%~AVMlSN)%xs24C?fJ`#JxSb?ZH1nhU?Y?Di-z>ja^ty}iAhhsb<*vYUz>E2#V- zGkBiKH%k?F^kZ8Yhxej8)283R+4duS1BU#v9Zc9UOa^dw? zSbXJ2qWW29Xl7A(Jr-#sFR$}UN`ysDsaGz)fzOVM{64AbV~kGfpzJ+FP03GSdcd|r zL1iAUksN?lw42Hbm9mWtnHFQ+ublkmdRw{Sw>s)0%CjTESw-`joJGX?UzRwH%p)lU zG913(vOkCtWtMcHfi_!D2Ardgv{-3$T!l*m@`|L3>1*H2kyWMb&%vu2CweONf|GE(w8rfabX8jyJFSe7HTjO+$@$zz0Nc zy9ZLS_>g+UybB(Z#<>=lf6EUUW6I?8sGLy^5WQ*ETj9H`FH!C#By;ukqET1AvuI;n%~F!e_RMZ2s$j>CHzoprH_75=y-gm zKBe62$b*!_hY!moQIZ=X4W9ca|I!-uhaW1kii!aoF8{?}^8(?L**-l_n~QluECtD~ zsb+7mAMX1CiAr(q#t92WGxOlN)4Ni~A2QR-5Jb6j(bAz#w|aR$l@&d^3A@Juo`5ii z^_|YxRcm(@Q|!)+M*Cg+Kff~hG#u@g)av4_*);hd%-Y^$xjkLE>Fbvpb-(HOZ)x+g zzo3e8C~{QK8$W;k94xwmzDlybp4Yxo^`i5ICc43ERxae`x`(UYOkR6@Lr89iVY;u4 z!BJl=I$O~>uNKde>*$n=V#fE=VF7)IElmmor9@T1%5`$i3uj5gf9i_g=)d-=>=^u} z_h(8rxyfr!GW<+y)Jo1J$VY8kS#I}q%{+Pxl;_?*d~gzCOrUVD;?@h>G|a}Q^TnH?WyfghF)KX%>r73HSBr8*xzlIft3N&-pSjJ(Q}hcw+p>Oz%WexO z{`X?%sKj zRaZAvo=D75>_waPh_8LehiSF3{CrnKaw#9*6mt6TfWoCF=?C4@g&L>R3OAbVyQT(r znQ`IzUB#1T=3PsRqxbeYJKy}nVLNRUv-N^EW|r*h<&3v?7x{LhQ@|0YUDQB(*(Qal znNQOES{kR?`}>0H%kLh^!b+8{*W+kDi<;OfHQ0^NCrp3nz#pwRNBU*F-Ej7^t6|z( z13lVSy}v#hB>K}p7;{2DLP(vQ5I&0wZKrgYj^mt>a>LKZwY-%nZALq#iMrtAw3A=5 z%@=a~B!8|lxxFyMJS~J774ZZFavvdD#xUOl;N=;{g{HPW|wqHjA zY0Sm&97Ru%i-7f)>4I1;m_F@5&GjHO*^N9*jMo|My_Rp)Zl^`Kgo{y6dEwfJUTrQM zG*wefP>u<+0ZW_H{xrwU@XgMLu18K}S`f9@4)gV$TIVdPW&^4$w39hj3&bE`y1!H> zZe72Qq$5<{uMy)YhI`Y3@d(;3^c2vDVH7v&=Hgwzi5MB*G|2DQSOC9z?Te>--*0!P z&e?Jj1Qoo>QdwC^o)r*=eL_6bJVw+x%!ZtNma=%8Lvvx?Vqgbm{`oQW`moa*XW1@y z2@DQeRM^IrY(iPt1K5)w0zHmoqLIq`a}vJ-3CGzt3FkX_?n*pM{q{LAcwkY@Snr@5 zVMWE2Av&f;&V=tYL%l-{J?5SHvsK^cpU^x4uV}@Sl<5iGVnvdDr1e=*Fg3c=oQQoS zP>4&O#8eE!80E7`C0^>+@Aw_TUrBu4XG-}#MxVUU96^qL zm`wI5whSmxRu7L*Ug;9ioB1V22(X2qEGUGS3&EDt926~BApPo{u7G~+I8frv(Xq%p z4camG>+1!|D`gB!NQS=9K|EbY8E*R!>z1ur?KzvgC*io}z2fa3%VM7 zI0&e1Iv<`>c&P7Ky~lqL;D4iv-mC9qGxLk4qMU?E#rn&Y&k(FhU*FDs-$C|9+wT0V zmT$E z7vx%E{3T-AFP+{`+3Bh+>Ab?o$cR&+(l@-*LtScDdrW5XdC?{d$;Cw=-g-Rr0?xZ- zV#@m492&#A`iNc^PGLVtf|)-avf>X;=GSlEO!E=F>ArSXrEf{KP1BH8z}B-qm=QIr z*lwbzX)s)(Y0%YH*Cieo;#ZzHw($9HnU=C@F8ZZxbOMnQUoMu6<=}a5I?76t;{#?l zpPEkpBiVI%Va$~lGby{Ct@l60A+V>y0{Y_9_&wEZ_%hbPB6DG{6@R*~Sp#A6_tv(n z*RHLDd|OwC_FEQeY=VPKhe7Hs4f=gXdJZiH)F#YTzWkfY+IQ}ZDle|m97$0z6jdlD zh{FbgYCT!?@g!VTV88K2p$pY+)2rP`Tq(x$oKXQ3`3xtjD0Xc$Y%lsr))TR)*qV-a zTHN+{=1M?9$pl@7N({Yg>o|*Q3!NnkSIiRBVH3y0-d zZYe55k8!By1GzOs$JI22S*Llqv8aSCYL;tHLR*PjBFgiVU`WNa`K*h|yUS}^Qd!H`*Vc9v$){SB_>esj~P4CBBHA6XQ(uJacX zLkt6InX;AKg!tP;J0{sU3RY$<=88%B{rW1=COPRKks(_H9k!55VCfG)gw z-);51-fhB*l4IcSZh=G7Uq|O7H|tjD;BdOw$d<^1%7lm~^=Z}2ahM>B#E7X|-R7R0 zSHl8&_R|pJL_oxrYqqal+AfjS<_5(PJB&xr%Im3VedZMfI%!mXy_9VoUkZN)Y3>~5 z@h(mCHQGB;PJHP#7U)#M0H)14(RfO%HqA}oFz1qt!RQKoPjpu@j(fZo9Vnd7N^Z#a z5K2jv>!OcaPtvemE%t=TN8Z$Ez~UGea8voi@iJ7!3(=-D&2TbawLCI>L_h*)E)8}Q zH_eAyJ~91m8%49=9GWukIv0LNoW^tClEc`UdG*$oeGgH_jX&@$gU_QHGUCUg~&Tan~0t$JkDwO{IJ6 z;i)FJ7d_*xWZ}+E)o3dkZ-`1{Wf?~{M?+U5`OvD@#&%Nmmj0!${%6)p!_mCy8}P=W zeVRv~_NVLCNz>=D1(fWzaWBW;oD&40M~reLA@Q8>cC0-H@BUL!E$6)NAJgv)TmYh* zLisbqCsy9KhN^0&M+h<>_78Ngr>0FIHWx?jpqW#6bnTiomSaoE5v{snGQ1guRu|%s zqS#A*_mc}H-%7srF4{O+_in)PaP#y(TzcO>ZmyIZ$V|=<`kBM)L1TeoL^FDi?-Wo=L`c#*t3977^Dws71~q!^PE zm?9iC#`Q1S75~V{@MBmWxPjK5At4D5blaSZ>fpKam=1)6y59PPlKbc0eynPh=uJjL z{ojp@;?+4D(QM=+1eE@Fl8tC$HE=&3e~lX2{g;minw^|Ud;Nksb$3=ysTrq#cVX@J zhNZv!BX0N7%>FB0IohlvvKNpbo)9f6Ke>XcVWF#u(ROmW;Y^m2wfRYfHAFe@1Bk-} z0GKm#z_O^>sb`*crMH)RF6Y5`U-yD&V>t`76Mp|MUBqQBl3#nNCCmEyYF*E3l+{&1 zn)d8@SmJbnfj^3krQj|SJXUyHU?6oVG0|-Iz^OnLWQFtTcoDJD&AZDiZivR6i-y$D zMsN7ELe`A{LZ~5#8UnVeGW`bUfaLamdod-COV)$_!GtoI!W~HU9VXotJQku2mvEEY z%6!{}{l)AG(P6)x(~=O)wi|Nf}mKL?p61frsc66n{{EW(3D&0 z7}8;Kq3K69FwVQ0V8LbQ(Xb5^u4{7Bzf5%?FNd70@o!ow$sPU)Y+eij{*-Ol8VdQUtfN6wxvOzy)Pbpo6$Y(t;~d`?;oHI znErVW+z_gS(aU(;QfS_ho(11iD|4-BCo5YaTI3X5jx>&NH>0wVV1D$E)(WHrrXC@y za~9rpIxyFM_Z6KsucsAVoz%)eZ>bX!Pv5A49BPa*!x$}Nv@4T}sNfQj{;i9HisPxC zKg7mL$u{6dmxA@v%{m)qpzD!)2IX(=#qPRrsr4Q-y?e>a-%?i&+ISKWR7Pg7a%@KK zix)qY#B5{)TKpvIgj!-&vCfMZrG;__jB8>D z6OBvX*P=E5`Ze08C`VbXHhR6|MfY9OX;}SBpQd?RYA6T_QI0#-DA?o#=&;no8MUSF zU<}O)+$bQ{bdnL#%krC>ILkCf5SuFZC2k;-SC@_skm*0$Sx0M2d)vn^y30-S6RRH? zIyuQJYw)~NFKKq!NcKanN*XR979rQS>^gqjIIct({+M#fiGf%)YMT&_JtHNFxtI@%}GC zalywzaX+ZEBfvfZ(n-L9BE(gu!~o79PepuLp)7B>@n@ z2G0G~4G)H1pC7R?^=fu$FF_mG1>}ncP;I7(ge*t#8(rbS|24-Wkal<(UG26A#aBS^ z6ju|b61A9aa&qomV^ADQoRy$$agVspoC+a;iJ%MW7{5=}$ZR1Q{SN3<&I2uI2aQ30 zRl2;iT%1+D=G34OGs~}3*z)QAQ-D}5;&iYbXvke6rlkF#_WgTZ80vN_4wH2n#R#3k z-^=a}%?9#`DG=>(ne(Ok<@sf$rI0nBQsV2!Tn8$F7@Hy<1?Zbt`s62{S0>`UWWH5C z(EN0Wma?C%-2Q7yZVY;Klh{7S1iW>c#h3s#N8&+$smU+dU3;l*S?2QDzN$^pzy3GO&!y`{3|!F^#BoJSWe{F@-eBmwBJ~0vc;I+V51k6W7joOE43r!W#zJDvm95MFTS=r{=ix(=&Q>5su5Bw1<4qBEk<)o>4N=zU>ZdhwI_$T%Ily`r)s%#*4X7V zxsvUE;=Ge}Ygir#T0fAt+QT==T$cQE>x+MgaQdGW3=^~$NFIm@g%wG1lhd8|3bSRQ zLaM)3vSKM8z*Pl_S%u#gGHyh2;qa?CP(natx$;%+VzkL|&bLKo=H4+E{0|-4e(qeM z_)-rr9E$FOsUg&mGozUh&k1sUdY)N6!bvz9nVIcq%-n*x|ISFo3H9YlH*N4-%jxH8 z-otFv$e#iJF4kYx8x3bMpADMky!x%3xF|ivRK>hWqH#f{tV^$6V}G_(>L!lnR|Rt4 zb{5Ax1!oaK9XOF)YArcdB6^-Z`^UpA54X~T{5VS#CsVpAD5P^i=|d{P$^l-lA5;E7 z%&v1#&SrzTLZsK?4ZYo)696hRMidT&eD_4tDi;*5Vi8q?!RPzs{b95FUC{moX(kCx zuX|wIXY!L$Oe*3psjVm5&7Y4+H3=I6S8aJ+FU-rUH*X?Hg2fo3ksiGwg*c&1#kL~L zzO=yMPwgA^oFo)&FazG~NAQ7c!Q_UbEi3*o($K(POyWbv{_g=m(IY)wv1mYf?AnLA zI!&7J3B9gfx$>%Iw0WDEUq0U%TP>=Irw)L`nEk`C+pM5_b@8(5pr;1+%OXgt7-yu4zVLGVxy&!wSzhnkHWi2cQR`5$%qUof6`Y z5^P^zX*rkFkM5^myLAI7&=;KveRjTP6M>pp0v-BRq&-&AbGZx%Gn{C>eCpJx9ZB{{ zr-Kh8^NmN)QrPuRz*k)~-3yRT$KzM~^2jV(uCx{h5(rYV@bL zPX>MVd*h`Y^#lJl)V^#KJCf8z^yyu81cd#8Hi_)cyJ7k{=eysiprs<@0GAvbcXtBQSADRn z&8PLZef>j z0QMs{B#9#H@98d>BQY?G)4JEMpP!D&8`HBoC&<{J7>$vHl=su^FTjXF3kali4M@< zC3~CfK8ey>7O0aqdzr5FgkhHS=5nv z{e3P6k?1ywiRI4lb|UOsA{MYBk5``-C~wW0WAT{}brg#)t~q^(oKr7iBc)L>o(8Y% z74l#U;7(O08WIqwn(cl0?w!`-|I`%-#z32kX@#8@%$v8jbv9kT$sARw2>QzoEnC_# ztF36DbOK@j1I+pfkBE4}uG3v6E);#5`&?3(bj(=o%!d!pfk~56dAxcd7gp9 z*l)Y58bm`drSXr9|GU9kpZ<{3woRLrh{$g8CLoSqIsNwL;I+q>F0AOX?Nr|p*|kou zR^l2`xDs)Re5Q|sC4lnK%5{W3M+9A1{lQGV2ldB8Nbf+#lwn^$;n11?n*b-~|} z)%0Rx9#mnr3YUSkc2zY)cFN~0(JwHOsJ*UyW& z!%5}NG0a+4&m>%nwjT#mBNH%moSo)GLo^~u$+Ry5s&mX{XPVQYq8Q z`%~X6Q*|PDE+Hn|540Le!viY0T0?E8Ot}Vs3pT{8BU1tZ0vT)eMcCWk!LB@XLx&OP4Pf0KvW6WMbeIgf^kfN*;;GF6I=jrmlbcr_HmDq z4Vb6puQUcp1uI#VCSCn|L~3GQ^u%2m8BGlJ?(pegdi3k#_;&<>{vzxit}gNqIFGYh z%9|PZcRRMWN<+%Z5&N`yBaT`CFq=KJX>I29|!@&P{$x%e6D5424V7|~Zx2`n{>9R9ZNj2Lk(GEY4F2U7)HX`iS!X^O>-kL<=#WsHPEZ(je zm=16&9SCp`^<;3p`M1|jm@t8`maalO?iETecS)Ie%4t)k+^G8~K+UFDC0)e3kUe2M zj+l7X{PVIKVVY9+Vo_hxPyoT@BO+V3Pj+HmzxUHz&e zqLO*a(#dX-X+mbRBB)ieS9%DqLAwsdu?`PG44nv(3K;6u@DEJ)T8)ChrAwDMkYerk z?rT-w{}*^Z)8aNG+d5rh@rY!POQoI}EpCOQg}Ag04Jwxh>>HE7w@Y2P^r73*Ic~pr zP>(`p9_|MHr<%ULDCEM#)K-RP)|AbVczm&0*V<8DTRV}U*);#~un)1}AwA{g>B{dT zYs0bN)Etw>+kq3S_Rm`vbU-?3Xz4qWHUquVKgG7d@gP3{+peZM@7MJ0P>lYeDTG^a zByb%#;V|P52WdvsPjnx&d)-dk^BObe;+ zlD@^uA-KfVZyso(6$on$Jy8z4FNWRGqJA|MD~Siewul%u5#2}zhIU%(fZ3I^$ipq8 zH>y1#aQ!9X3!zsdb-xnL|Jx51y>!MsVk8PBEG2Wtj}gmk-n^Mu;Cf@jq@gcJJbtvw zy}gl}yBzqP8i}X~gNQ6~u_%06T2}TM))rRuolpRhtX|;cJ2C&?(*-jz-==Y!X<*hD zXl%tTKmb1T)Pjl7>5#UX9V|$GenU@-pq$opVaxpskKJYX=Z`ym=drlw zx(?gJ6F7}C_6}W0@ryds7s7r=7n_IptM=>3&oz1ux=IkKHaa}$^r73ghKXrb-4)2f zL$_BYP~X5lS!zGz@(84xSejtPi8$JK)_G2o)6L)*LK~M0`;St|KKwcXcSk~^)|mI# zmn&C zsc?_N&;|a|Ya!9>e_1;G_1fokZaM-pi_%@U{UNu3Q0Ng14RmPPlABij)ya|Iu71J1 z7Opr;hmZh}@J74=kqU#^ynyugH$slSgz`siTj_Yez1Mp?{Cv*U0|oKjB%1|_HVMa8 z(6UP8YU-#tckbNZN4t}CNZvC2&Iwn~X$>w}ax-{~!&YH{vKh1aPiGIqj>TuHHLFwT z1(1x=oI+w-PlzM%Rf#ckG(~*f`trV=|5sB&?b(HW_e-<99fA_dwRFJ7PgqIh9Ha=E zjO`eX2W;Psx956#GB3^Gf&~o=Qxqn^A|U>kD>#G|=1Wi;qK2A+<=m7^z3J@Y>`t;a zq6LnIgx25o6Dn~ul$`~{%S{jawT#Ok^-(2&fI{yu$V95!+P@>v%lIYD<0$h#$BQCaPmwb?$ZYrCF-4G;Po-+A!3o$~f~lbRnt zTIbT4vwbhA|56Z&vJy-(8ZmJYK#(Rzeh4rTF!h&;>%E~>H`4|qExP+#$MZ(9IdgAQ zUw&H7tB-okr?CL^j_kDq z3}fR5Ika|$hd-p^g~c`A-m{>?g}FOrJM2)X8*3aX)25>1Q6Y{?a5rR^E!#y8 z#`10emfNh${<6z#F@YPkhFO~ead7}nhMSV1){S;8(vh_xW!DvY`5V4+*#QEFOcVeN zL3?=ARqJUrwI4s8q>ixB^%AU!xX=UQhFxyay7hVK5Ke}iUp?0>iFLU*Eh@<48fP7AOQ>PHEnI%&0ySHYY_=7x#`WN&E&Xs0$fJRu6@rDpHtC8<&c> zu+wrLkz?20p#yDF&WJDaP#Z=$=5)h%m~IbWJMSI~b@}jK@4aCY6c05IPJQ|I%bgLW zsAxXqP*cGeNkYvQf@R#aT3(uWC<8;mDc6{HD$1;7fm$cKp|6E}%k9i*T2foXx_6Ww zPU=n$H1kf16x<0&T9fKOP|5eL$?7TRfq$GBx8xDlAMI!5a**UDcn0O@Q*1JPPg;Qu zgG*k~^GOvOd_Fw#*XBd2uz5?WhjfX6OjPfLp%GM>NoaBBF%nCE71YJB#dn&`zO%JW4N zZpm^O2w6C^E1PAB1Yh^v7(FvG;z88PXSXVAZPNBir?v9c{WV`kSoEKt>f3N3F)?wo zE-^A7dB*0COQEDu9uJQSrG7zTZ*24j^A#}6#`&k&37{!sBV$%cVA-uTY1PGtm<+x4 z|8q|Jk8D;;X&xdX9ad^EYgRsLU&?!{DBf%5Ib2WNa9wbAg)GvL5E^I+yIQnr15rtZ zz+-rKqeR`+nNbX*&+E$hoYiyHDrvVL@1UzK_C117YaCselOm~od>}Op54y7hI8utg z0|$71EH`Jm)XA*nBw0cxdULlmFl7KGl=}>O8-MP(MecWKFvg>{G2B1zfZpONs|CfSwRE>mm^g~sco=ji_0Cx zuA@!m-;s3e2vS2y()y3(HE3nZRu~^ydCn`KO~#oqP)re=zKJJ*dd0X2ap*4x z{tpdE=JlG89*OXOM!6K03my?!83+pIU$v)rehF_Y>Eb8B(kU z7z$#v92|;W(=xhK)CTsm!-(6>_R1(WF5!8tfx@`Y{*$4hh zyi4H*?HOLmC%xpBf}z8N+JE|9hKf1~77h&>4cQeu(ONOG=PDuhcGku>$)x4 zcwi;d7UzUNEY8yM^%bM&#m{O_Jfm(hCPg~vcs4H@GkhQ)M}Otby~9cdC#DVD6HM#! zNL}4|n_3|cdm^*vdt4>ZdhmjHDo#85jknnp#?8S(GeUvP8^_kKOP2v-W^kbqj1N+KEE?qKX5)nL`lnZSDb56+y?_(c8j<$q(=#t4KZB zPO8uVow-PP+Bv0AX^5nSn|hT13@As!wZz6Rdb`A3reNHNj5*D^gwnUn?s9OP`{3)e zEWxfBE2yygM*Y@~b-x&xIZupQJ{N8B2hqB5j1soP;;|LH0w#$F6ECz0k4t;Y42G+S z8u=lqy}vx_ZBcQIXtrPi@*_4Fk0PpYAU)n*UN;<_F2e92t>`<_MPM|HHuXA%%y#M{dKAA2*-ys2+Jc|~7u|{&U5%^YQFL-5 znLO#~Dn*;6D-}5(9myC%NZlcW$1&JVLqWZ;n0i%9i3hFbr3$(9LQZa+aG0?1#z;9a zmfTK?JHKezYW_x_n3O-ytwUO_d5){h&2ZYrFJLdJ%cW9#XEU93_Ty#*>ZElR*ZKwD zPw`tQCIUvB=$l5Tzg?UD9UrG!w!8O5S|*V`R&;OZ6XNPbT~&28Z8P&I5bF%2c>o8y z=JsB`YR~q%8(I9NK|OEzR-bwH7dQXmK1*~SEm$0QpRJ<#grm}tkOu&OB$&tm&aPJK ztrc`2Wq`|aqZrILV2@1n0A`i%eO)E`n45nL`jC+SBJmLXy0|5}%w)CF!v!!5`e}^1K zeT5iVXyB_|#dRbQQUKAMejJH-0^N*LryezG?VNUG>i35ElO{!rGV}u5A30HkD5L88 z`4(RbfX2I>K2m0Qr=|*SS<9EV=sE1tty?#Tb1wHyd|DU3@nAykr@_A~YucNIixiNb zpa<`#tG_HHv8%(%o2+g__D4*;`(-aI(_e|7M;Nm`qO_K&!3`A6K2arrpF){wMJ!QO zo3S}>adEA1ydgnXnw|9zJvN%06&P)dEo~`=atGL^c|7B`5VT|aQ&ImkGx?MGD!qpk z*$@9@2wnkJ*ZUygM%&|61ci@Ll~{%Jf1v9Zair+|+c-`gK#u}#VLFnkRp|W_rEW=ED5!KOFfB?xML?qKbq&)(_iQ2t28H1uUWE&c)q$Nsq+qBR=dHPN!qpt{-kQ=sHU; zLlx~aOw^z#QD?(@7@wNOtmLuPX=2{5^>V;fAe_*b$EkKuGaEz?s>0YXA#y6&yjC1> z`QH)~QwJ5!xR#y$v!w4LWX%Tk&3YqJwrM-#h<9)eV0S`Q@v+n%pTPuSgA4(w zMN2|=f1S)*+6uiC<;5zCpJ-!Z7r4WFqPlnKa$10QJqXnyOHie(`s=R&Vrl%(-gRyk zEExO`;q}pPzo&RHqoa{&tJeDN;(>gbI zSAKQ*j{J$NH@G80B7z`#&oZ8|Vf=q$1g6#q%BO|^yptzQ;wmK*oKsb(Janm(zh!$- zZP3^M$IKQSgm`KcQ^EmhU<`ut-ZGZa!KW^irZ*ZPlHd8y5)UB|n;6^C5>1MIa(zq) zXSuEIEHbj*a5_n1fx)!k*(D}cgF%RqLaDdpxD!n;ni|i6lt6j#0TrUU7t&rPdd&ZB z_;@1km3*Oc`MmCilcaM1=`IuKIl@8@6IIEHDFS}9Ygu`-Z!HGE9c$WI7wl03M#@J|8-xuPQ` zA^-TffS}|CA(Fi83K1sdQ7-*!4{xLyVe&kOmlJ&QC=ijD=D6SwEYPPB*B&W}L^DW^ zo(C~jJx!yFpWjc>kw=H-+olQ4E3!Ns9x5UifOl#C5VYpf;igOOM5Yp@f-9oMe+8F8 zYQK+QHMN6*o;WYE|M=#hHXLTrG$NB4e@TfK3|33O?O|7?WMm zq6y=ejT+An|Lv}`4uCz(@qP5<+sX7FFWVvH@1=`g$iqwem0hg9boSk~-2s$bhh6$} z+qNR49d_-SN$fm1vPr%UBLGDo)&mCN{yjX|caAVIXczq&VgV9vvTf1$>BY_X5)c5A z94*=e#Utys+Nt{EDs+0DC7a9z^|x9|#}l2A(Px671A=sQme)PS%Mwzb!PTiE)#C0GPy{SAX1S>+FHuLIL z%G09ZFp={-o&`N&e;)|zVchKHK@?Bvh%E>c4|2Kp|A)GsOyK3yHfbck zpEBDjq9NPxqcQ@kg++NaTxPYKYzGh7_Irw2U+*Zqi}<-*u|rY+616`8cAhN3&{SEQ58b!_5 z{rYN;-{*@jrb(mpRO_Q^B%)IEhpFSd$!+{`XQLq&(*1A z2i2;ka}fP%_Z%Ac<>l|iJOK;XBjJUbv$7<{x`|f;+ zhK9xwofSaOyKCKVk9@fCjqQsfw`_%@qbp5%@ zm2c@_hl+=ZFGf9CL0fG;HAC(Qm-^KWrCpI!4_F7H@klDL)Fd@0jByxr(5tw(e%z-= zi)*@QE(6a9IFy(IndZ77kKK0oT9+fo)!g^2C|Z~51EVu(di>}bz1Mpe=j7xN%&&&~ z(HV;o71h6=%#G>GmTkVCn%zO1Jej1PJ?&O!l19qKw19=7R~ETO3x{3q-JAJpGkt6K zWcSntFU?NDJz4mG|bKadj1$zsAqD)wG&ZMFXK)m^clLq zz{CGo#Msf3N~Z1HCVfJgBu8?;0{}T8^>5FY1TsTU05vE$yd}H5e*d;*!&-`fA8F%t zSYHw2CTU?P?>0r5qc*Dlfje(6=Hwn7W$fnmTFlps(p;WynI<#JGH~WhUE}7Er)W#{ z#zmUjm^wZUoyYZ2l8V6={>+w3ZdjBw` z57;H=60PAyHoSEaqRf4vgTOC%56zozJEHGvD4~F_qldm z00^UIN8by$a%J4-`6?;_y+;h>P*mOManNhN$K9#oO%OHh;qxI4x~7==xNqsf-U{Vv zCZuE!;9^~j)1YVXU{h05p3ppdpo@d zJ#^*_@xC#PiNOXO|1YQnB@wKt%8iRrB62H!^ipB?N6%gV^Q=!UU1 z4a}a=Mfm=8?1Zc{)}8#YDnU!2bsRNUH?w?vw^$;i0AAoe*=?5Z}hO^06jF}Y!>qaEjm z+qoM@52-sij)Xhkj(_mi{FoT?i0JdWYedIK{&Uyg=9XI;@U5j6?BcH((_;g+8Ey(AqUc|LI!4o+=k<@{q@&J~wxYo{z+=u{fI^`DcG zFnf?a`Rf-5u?jJPB(UiWUq!#M6y8y>#ZkTudY=cri%R4BU{kGt6KlU$t@5*_@4j1< zLQc(hx7g-doxzj27$tR6LP4eEj!#xzbdByqMzvk+>_!vQ5oJE1ExLM`Gj zo(T|Btp3L#M5Pr6=eaq#T;1`@q>mmo|MIX)*t8l`BR!8IFTreQ!{+#d zd8$Si>fabjh7qn98H^qF-)5#Hg(94hHNi^&_eb1el2x^lDI8fN9^QMO?ywI^oh4RB zj$9GuPw{a&=FDqHMaylea@i`?Viq<#5(u(^G|!)^yNr0eYe=?HJXwsS4Ogm?6) zmn_`2kQn$)VnOz+9k_!#wds>=Y$3Vzm1APCG@tb#W0?|HbD(Zs zAGwOEW!Hg@sf?IVay6$1Vs(0=hPVe}HQX(2{;xUL3t*9xw|L*5W9uqD%{^_y&a&as z&x-PSOgsVot$WOM649pG@Qf*s-L)>1A2G6KD*Pj8tLX_uE*>2$V^vjW>=0gpt=n*f zmmA>{6F%^QXH_4`b<)Lw$vZBfFp}89Ik%wVKRea5?u`3UflSgC*D`ttLBPal%_Uq@ z#t%;n8L~9eZJILHO}<-q6%&(zqm4B}AB#fY0n5SD)5P(YT&J3@l)QtY#?-jeI8eiu zMQH^EKP+|jhpUQ>LoLGM;^NjPo(trXFiK*Ki7Q6dPJHaNn0xzt=6ZVWU;fUKCx+A;qZ545L|%I@7THz(pA1UV|()|Cn<522#QyS4DoAt<4}F! zO@dnda@r4eyI_K!iA#g4j9OS)+U)%u9Rt)Yh4+^}Kd4ks$@NvfA0mu2OX!N&VYT?- z{B=89CwY&VaBsKC)aLIf3YWTmSEd8hDD4_27n2;hzET3#8(?8;nsJg#>Cxd|m-2aA zzEPaM=x8ns=rxl=`LF4nPQN>ot7Xog_8Gd?Wl{098`Fc$R5di-!eI2@!J?sV zI4#GWIj)8-E3@h}^*I~8WXpg3CuBE7n0`&Po`}m!6q|HSwtH74KNO=+2!f|1mWaTK zL!a+|gqq=omu1SKIpVWrMlFj8m`na9VtlocbWk*yYNzX%d`K-nvYnikQwffJ4!A(g z;E6OOP2C_EV64J&;9Rw3Uv>rw)RCwMlCwg(_3Sxw4z7J*O&%`jDRyxs1*Y0eM@uLoEO3tl0RX zso{m2WP)Ko?^gkX4)zkqCGh91?>$1!^4Js(<)i32ReRur=S~r>N0y|%J(HVozIdBj zL|K`B(^oikeN{}cy`A*GzgIJe2%ll-JmnwraZc?8Um<{@f()%Em#y>DspZ*AUk@JZv>N*5+4_lGB!e_onC6Z<)z zY%IsgT;k%oWy==UJ+Nhxw`tfE=g6gc z(vuaXv=4R>)u*Gcgr8Yo8anqKN--#ZHXc73*k}BDkIJslZbZ&mm(^Z7?LC1RLR=NN z>XJ3???V$e#?&vDKI75jYUUPlsdy#mU`~QsKPz$00k7Gxeda{h4*?&7$s}S!GO*RR zhGh!~6KZmW$9mei?{^l;4Le6aKYpq9jYHFVUQgsWb%wO9eg)>3yV2L@9XnxUupx*; z5jkjV^V9#n59-w6t^N8qnx21urM<}0)%b6c|FMQzcOpfQo&V>9gI=z*k!5^)R((Y0 zE!RkJ=E!1;=%-M0yVixp(bCY+`~LpwE})*u!AQlIkj*^EKRy3($n%kTH< zvvRXZ&TsK__0^6dMkha9{qk}K$~mzIJZ(IpK0ib8%cd{c`dGXk3eNiOW3HUAY5)CZb1;{rNhW&_^sMPx*O>x6Bu{W#dzQ*= z3Fwb#A{Dv9@16A261YNzvHvK@_#o{sOH{%7Z!Re~%*II9ec#g7>S8ASh%j*cwkBQl|q-;Ocos~0_ho&COC zCG!5r0Y1+xB=U_|FT&TT2^AhrFJ{~KOE%uN9mBv&=-dp8^l}}}6Nuaq#z(}OBM(WA zFuDz|_RNG&I$Wzo)vUl+uhjHr`|L4_Lj3tx!KSb89JolA0$4X!mr=dGSO%Di`S?Vk zWI!TDYm%?X*0A(gyu50b^1fozem!40Y^kY^yKp7o?zrh!3=J~`aqLZI*Jm^4D#aYtv-)>v~*}`>- zR#$DqA34s_2Uwx`o{t^*kTjNxhJZ%FSwfx?tGyRv0H*i#5%Fp54J8c7OK!^eg;zE+ zDfnac3;hXQ37y-PmJ)3A3%*H4nw4eFgYJ)xH%lAEMb0go@Hy2~E0wqC#}uhX(xO8c zVR1PyDKHDX>zd}2A;oa1etq3hzV|Bzdjgb_%DioPWZQPC_JQx4O)KwfbEQxcaO8;a z&rY4H-9NkV<*QtM6{+5?h*Z3>4gz7{bQZ^2!l2M1JtbO zQRdLXHA`emWs+a{8|hC}?|&JM8Onq>xq!g9OV-*40T2LQs?1a0-uTjMo%*)l@SpT_m=e(&Ns5K6_>ms_B} z!g$bSb}o+yv7xwESZU0*vRYF9%K<9qtT^)ofBYCcCv%kIm&V46uJ5?PuWz3iGsu4F zLGRa`#V?4LOv`%=bY>~BGWK2Cua&|i?wrb=EZZ=K!16x)UMOM>(~H-afm7qum(F{NpF+5OL$z`QApVBfe>^vggd%SdHKi zQ&z*o%$+l5+KUcEH;IiF=Kgn-!vn&V1S47c<3G+Ua_`sOTLs7~MR}6WJMHyS0CL*B z|0aAFMcHzBfqAVgJl^ap#J}P$gIAV*=@c{b?{#Z8YF+V2!Y`4`E>qcZ=#e z?~L-KlBcLN{rI`@40HS=xWBcx3(cfaF|H4;iH1g6k6lCBtia9yai+tE2jhIs3slea ztG~yyWbmu(s~tg>$Fj5OY6gZPsWJDe~hzUGCi`_Jc>shn-I ze@uobM*KwGoE0KQ*6hFge!w;1XcciM2Rw_^*DCHI3 z{zsSZf)Ih*Y;Wyhx29~GbL73eX5Y!_{Uap2xquWJs&dRM01tI)DsN^3{Udq^sFq{2 z>IJGS0CmLUY-rD4%A?%JWextB;qxFt@ku)7R^3vKG0>NCt73sqHMQ~r0JrWFwjEs} z<`GA$)?ev)=~v09uG;1A-S>HUcj9@Qe~v%I=mvCE8f`p$-|^$`pDS}jrr%go`~xe5 zLdq-~wdtcNY8hGM@cPQ~1pBN4s;2u#s`RB8(t$VAR67&r$6~1Rj zNGV1wu(ijOn3#W|R#EAF0j#Mi%p6}=Ncf#j+yf?D!{-`UM*mNa>)gIJ(hD1DxckgU z9Ds%WrO)ZrQ*+Lc<8uU)mKbloKBj|$^r7^2AbNoqnh@0&<2O4KV$q&-(6eY+4dN6A zD|2$2eQi$8k6guBi4TXKr)3ew8yk5`)(x0b?Y7Wh>+XNwAm@j`(vbQTW3DgUs?b9~ zOKty^#l9O&h>$eVdqx_Hk-w_vI?WKn7yGH_QUpkPlD`kgdav#<_dUvc0=BjLCh9ypb6C&n+BgA{)ml`?MtDuk4$D=y|9L_D zKdqz>Y4@3puixybewc!;gcoa2zGT}rITe-N5kK?MqLZ%)bdG7wul$;|*K1?hy+8qU>~ z=~oxCWgHv-`u{o1`A+-1TG-wao*?{hT;L*4;Qd=IE%X9}nq|0b+3WAp5Z5PsohS`e zZ3^glD(jWkwz)semUFd$V$^dJsni(pc*#H4NFb0hRokV1KfI<^nbXIQhcd-KFtj5_ z772)u-?;n@!_00_?6Xo+Y|7%(?kKW3<}PC?xrv;8ap0KO#E#72s6T66taRpD zt9TXPIeg;mpG!o+c<*o(fGUHrXYP{*%AZ!ZhcrOFc$mpf+}Vq@59gcjeX~6XR8?uq}TTqy*{ovRMz0&7ae>0&g{Vcd+L>)%%m=)vT|r%$fPol%wKxmiX1b- zWCOaq0;5*TpK@tw3mKi+-rheKygBH19y`u*e|unY+i7|Vhus7a$WMOecYzj)EqYQY z`C5H3M+$5Bd)~U%{?YK-u|~}o&AB?|ndcKxtorYT4n2N+we~Vz*=K}UvH!|@ltG2x z3D1cYD*q^;i@_NiruFQ(^o}4kI#*MM)a;)fyZEVfvrp8E6MlkxVh8`V$D;oek16=G z|G&KYF9WTR$MNz3D2EWKPwt!lH6)x9E!_Xsb=`X!^2N%R0C;6kf6T@??g^mFb`%>U;hQPrIDBWc25j!Dan08;Z0TylbVS9g)6h_R_| zFAC`c`6q*P=7`QSQHLzm_8Vie6Pcjvtkl0vm8x zKeEfBw10)KKf?U-N1U$*|2Cj9o)RS?JW!M}{aeEKm9q0Kf`t+b54=@;dYt^BMB|?j z8Glw~F0E3;ew+Ak_MEUE*Ldlve_dk%)|eOl9-mTFDe%#jRgYl<2`yjsU9g{M#ENj= zU~VI|^GZ&)RtHJL)cmMVjb`fkE<&>%i>d(bV!_R=7?`B`;;fAS47i!MhS`ZDT&-Xd zbA)4};J?&l&F(Vpqeam-Mc1x_oaWdck{r1*QMA{|82q00pVozMV62Fmw6s)@oR9cV z0q1uvd;}tjQvkx5Unr40G-+&e#FV!0Ik>gF|zqn2N{HgX*`ZhJP7s zaNM4-R)v^xdBA@7kt@x|9W>v|ws13Y%&TY?LHT!K4^4o$tF3@GY1 zlKjdes{k}Vr=g~%i^zhEV?mubDBHGI2~hSz5&Hrthl(p(a*VUT4W#4gMfEUGF|_>-e9cUyv({A~3#! zVET_U@cL@}S*yPb$GCmzzFk%oU#zaZOZuH8bRd;eT?(N#oTqjn@A+t<0I2a^3Ig)% zpg1Az)Tz}FgtqTmZk1!sDa$`Dy+gj$|ItuCEe!PWEcR!7YGg4qkLEC-|C9g6+M9q= zo%jF4r@CjFsk@pKt2$Hp*JrimbC$5{;ZRl*m#clr`C!NeYQ% zDT>KbIzq@E=Xt%q2hB{+^}qht^*pZs^}Bw*`+vtd-|uI6zhB$?|9_$w*Zlc^7st$Z zku2)^I^0s0IVM?m`Isj2fErJ6*KIJgf``fjtBHWkZ!QQM?%44I>Q<1Q2f#-Yc(*ID z>9Egm9lFeDJPrkI9V|RlNTHA3WncOo)x(Ypc+A=aan=6y$JmP=t(oQh{%5UpIDYpb zyb`yrf4vI;r=8eUkful194(f(rjC!JB4|?16^%71Y9lykjAV&Kbe}Cafd{x0`wXb| z)VY>ZVu82Ou0`9QK)s0zeKCNtC#e`A^p4$faW}x;k-TL>Y zcx@==l*X(^-^W*|*(DUKw9CEaJlgsl+||J=bcvM+->Dq_{Mh*mnhxjAol|Fs0T#~+ zhuXQnVJ|9HXf3Hj;Y4G$f?Re215eavPdyQSi+x<^E0Lu$<`ooS<9fv9kc@#s`V(k-c~8!IDLBR+S?|fPasn zLT%mluafv-I9|6fae6xA=evChx?U}Xyq@q*@Sk{F$76&MZ*zv8<>t?yrIRK7?T?o` z1RDV|hcgCL3kI1M@&{G=<^Y9bls5#>TPhi*JWR zB*+#8r5M8(C&b6om)11?cS9Yy70-U&g{H+`^ufXwj z|DQeVN74pviNA%Y4K1nYj+*3QJGyuOfzS@G$6KTG(rGDxfNa1!Vi;)Q?2bEj^zV26jqnl3 z(0ohj9sT3q8*(_a;|if*C7wpS)B(%{snfZ_svlp?62k+B2$6T7J^RH|0$2+CAi zM{)C8;?0}jX91onahxTSIv4x|BL_kqd;=j}WWPB&O^K;c4z-9+9x8&B_m>a6b;mC{WcZzH0bQEicv>>b{xa1u4CJ($cgGbtJaR#d((?szDlAnQ>itIb3cfL`tZ1hJT1uXXJyyp@UG*08N1DSAuqd6ML!E_n&kEkV@@H9h|C ze5jqA@hxf7AC)B0rc;i7&$T&Y-A&}&-?5sk88YLHfY*8-ngJG=C|b5~AF#YU5Egjq z?U0Y1UDtRD&h+_n=Mvtix!Bd9_dIIbF7OC;tr`8>0XOm6N>+H8&uV0eJ?b z#JU3O@ZpbE2zjM2Pq^L2U=&;ZuQIv&&g` z14};PAC13S;QxuXqEgnnrsD0#ey}D?Pi?mC;3YST&}&C?53}k`+%C$}lS;pTFnmC{ zO3+R}EW=ZUBKkQPB{GUjE4=(S7sXN=PE#6AI(M$%%t8WYti8g$8qXA68c5F?H<-vVK-n`dp52f>3QrjJ)8xg=qGZ}iV!&QN|E6TH@|8obm^rRi(% zJH?n|I4f`e8~us)+kPk!8R??Aif61PLe?KP>PQtRwB^ z0;vb9_7~E6%$c(xf>=YV4Lc%`C`WQz)mOjJa6|HHg2~fVWiKY%Hz<8C{&2%mSxYTQ z6dHwiPjTm_1fEU?Q0O0O+^``|-N!h*O&9(JhK2rE?eRFLZ`zDz?~cAFb}z*;&z+iavwJsNwl8ZLnoWTzm0==EvIBm|zBeOPe^gj4bz zUc9&o)t8V|tkqsj4h_II(1R0XGJW^J|K?ch)Rs_V``X1P^7OQ+?o5@X`&wg}Z((VK zDvfjYZoP66kZcpj3q$dofDQXV&E1aK*}H5#&`iB2r3s*Ck`d#-gM-`|s##g^AzHDda!Q*_Cyvg?bVFPSSL?lMNb9tFglFvDnH?YQSh#Te zhAwsP>fNK=7sRUG+(>7Vmer9$-*5AV0N}z_4d_u96C<1w+ahCRnvMsxP{kANk{pAX|FU z(Afr7Yy&xdfrPzm+e_#ogM>k9qI>*dnRWo_aVCd}U+^+cf4%Omps?{RfGVm7B4^E_ z8qya;FC8Hz&Y8UBD1&)WqLnngPr5^jHP~HglN1H6aqC;vl*4oUfTyH*(<40o*tjyWB|>sQFnYFe5<(CE)LeMx#Q!hu~;93o+2 zjq338vUndE^l7~^==~cT8v#5&xaWEUep4(QbD-cZs9_*0qsr04Y2qS?EG6wMuEj-h zg{YFK0Ex{){iw_dfO$;A_AZK-xp9T`e6aPlOfpqlHD*moN^)7K$QMy%@g>o7Y}g-EDYu}l0oO>$+UlX0`tdlFLXuJ^aX@U*njDp!(;inzcC1aVfn6xRf|7YLgC2KHZ#b(-IPbz(OOT?Lb^V z?qh?I^}LGM(fPL#l;wGUt}!W%An-Y*V`AYm(t9FL7G5sJfAXJd*-!9c;U3%)Pce;J zQjsJWW}1m0VIWE9js%+B)6^$Sw1~~GAXY?)Iy!fG$=53{9l_Ek>Gts{Gx4G6qV7$~ z0n(n~5-2k$9}MaKrRb;z* zZ+_t1xmJPii#Lx^tG-8LAo_L9L@HPB>B`AG@2*{irmmf>8IVnDsp&U&ACF*g4T1n^ zet|cRge^s~h??XNoaLYDHX&Ud)iXsLLqk{avKlt-NR~a0Lq6J)ZXh4rhFgmMz!+Y- zF*S-fsP}NrYffTW&th<}mKGQ&#5^!fa_ZSBFK}H4nN|Rcg@EX1 zaT7gMlUlm+NVCyO--taFgytkZPCtPkApJL5)A#5NtPWZl22EI8rz$5W;nWidmgDv! zdmbWxl8XCYYH{20aRQCAj;Ee7DCNI`dW9X=iv}7Q!fT`egvwd zEjCd&rq**D^x%uAy$yw~fIX09uISoyl!WL}`+{u2{QLM-PG*cm3PXMEi{kcn=Je>r z2(Pdp3C#bRE;XXZ!q0D+$duSp%rP*S6ZaNYlQd9MSb3M5+DFy`yIDkZZ)_nB!1Mhj z>5Si_76s4zuR-H7zO9d=r3o?LvyJ8vveB1-MP(1*fdx5SZg6ldwh z!+FT)f>($q{nYpMzVVL{ftGqdYDIR+yL|p=P=7pyU##cAn+}S?fOvcZA4jgN9M2BNl{Uv90$1V15r&JK>hl-vv@O|&9NLd^*EiT zHjP!t0*1zRjdqBEGk@i4T)QIpt=r8+@@NCLzzCq znIxt#8N~^rVY`ypT`dzFNtvjm>Cl?;FL<(b4@^6*(03jNCJS~MQe%u(U9wyT|7RU8 zUf#=N$WHZue3s24gB3io7SOr2nrz6QHCSZTcz#^Q78%E&xF$#Od9(&`+34i%Zl-Fl zatX~}uiyUwN$Emg!{_)3ZsMF1m-GjGrKVYNTqxO=P~jNmBq(UnHRwXvfjZJrVk$Mq zc#Zg<9=lOVImQJdaZiQgK#o>i+8bd>JKk@8x#46^i!51_@Uu)6H688mb5^j`2d&+l z+y94sh23qlYLq-AClWWo3 z1?3rp*rd=yv)Y2b{QYm6XDX3g8HX^TlqeC8=Vo3lF&gn>RLQlYsH!yL%dp@w$xbo} zAJ?zu)3JH(#0rZ#`&8YS(sIIXO@xOQ)&+umCc74i_--HByQ>(pJ$_pX`7@Bmj7xF) zigshBNtmVD{fyJm63}78Hhl!`%TXXCTjKU(83gf2K>8R~dvP@(B_lsr5ajNOSqA%N4&KC5>B<@cd5~p2hp}7LHz8wSl|Ib9JbA|4hHJE0mY)O`-|I- z$S$kn)}4yecRs$hSZF)FzPqojo65M8)2@^39JzS7)FDcv&XntE$bV}(a?qZ;8l?uW z!fN^p)erjdJ_}`XKXAa4!(84C9h}sz+c$AyElDV&{*sP)sBHc6mRtIi2}6C1>RYkp z1!-2R8s0^rING5c4p9$mU!*%0k~=`=2;~-;#&aJ`qpcD z(dgy#OB>$8=cPlc9u{G6icA}p8GG8Hopr($(kys=LZDS?Yt zM%a5c7&_3puq8zeYz7HqWgeU@D78FMq+kl*hc+nx;fQ`9;{1qC3jA3p-@D-oI5n%d z8`6u^A^oT{A-+fSQ+tHK2Bf(Q4=Lm12+Ft)bXEmpq60b8BKbq9*bA8nNq2bY z7$TsJ-ZXXboLN&Yes@8xML$k}lS9UfOBXLD+5hzEJh;t8oF0A$c&i9v%|Q{Hd+qFJk1~ zL13lC1T?L3nf&~LaK;}~aP!N(DN#&3AjYuc}k)$zK7`0m%vcR~dJ4X6@h8y_aaFYR# z#*C>5akIxzrDKK3XcTRtq%eQ~1RqWGVrO&`rH4JLp@)YuGE3r3(ojSN@9ba z*A^|Wfu@B)OC4aQOGRrJC$8jyF$es9qkR@H?X>E`+`Nj>a-qG+MIQlcoIwq0SVD#2 z9Kc_&Ps%Rel>M}@;r7icqi==59nrUC7_eIC)5&>H(z~I9aqAf$IPli!%5_MDAP;P; zF6@E+g7>+-hWVa3rY(T@nhqiL1Vj5 zU`82ES}4c3(3BO-BqE;et`OHvb?W$~W)Ebq6~bZF++TVC6CGXK8G}TcGYStEnqv zHa+l0zseItzhg->;GT=Ff%VJ%vCtT~X5>{>xt0D89 zS>>|Do-KVlZMy43YF;W=~SGBS>wHV!1z1Xlm$-i5u({h$G>UE3FpLK+}D8*gbhc6fR!YZsSgM5 z8We267Z(N9QedunJcjtV2CbzLX<}9q1M1wPjXzD7UVsvrOV>AbwR6D729KrQoFCWN zu&S5`Q6guwLZAdtTOu50N___wW-}_)C`EIM%mm4sg90Pt&4ks zSO%rorhQ*;hc+0wl)`S4jgXT!fpD5vVNl%s`Rv zJbEF&_%WI)R=EM)q$vJiKLnmlWhvI14m@~rWgCQIGeAeEa_Y(nLrEu|sN%r&e({^f z&)%~grqmRAHAUSp7#@Ccd(AYKn#EN;-8pkL4xRfX?77RY5dEJrE}TF zQYY1{LXZusF}QMC+QH9xu|F8LYO7!NHw>hGF+oaIe_Glvh-A&_@P2y`&>Y~b*|C8b zo012rj;+#FzIm2chjWB~g)jUAG^bBH1YcXzb_$fn?P7jE_;#HY!9lj9bVkQ_$)WaGOTWyCiDVPC+>9Z#&te&;$E!k9_LwrV`~^h#N&Yf< z>$F9mpmjm+ou-W|iV>!8swVR=^%!i^ofkJo-b|Bs{_n`a`0HBo?>Q8B%~DIMeTS=7 z2ma4LuNCSbvkkYzQSOO(FEuLbPpiGE-Fp3ihqg9VU)1|_W+_sN2mP&f-`de#KsX28!mdp zaVF^HAZ*i-7y}#g6&6y2uTwW<3{$d~&UTWn3l@}Jm*|f4IDI)qk)dsZjeYlZkLWip ztLWn*TP(`65zUnd3Jvz#BA9`@O^4PV$Kw_g~9#5B}eF17BLP9`Q)Ll!{myHCxY6IV%xb}vUJ|z8iXqDZkhe6h z5RA}*IEQCgyJA-E_=62NFU8$)8ySmQJ;(oU=F&hjM1jBIP<{ug0(0x)8NVSLGPNM6 zz6MT}zQ^0qh)*P-3Iec_0zb$Yk<^g*8_~b4hitGQm$4h+XIHn`3B(0e3pgm^5=Tp~ z4JF*)u9kWSdNsu!3tyK7kUTPXHtw&hh!{4H5yoRPj|rhAr=<{Pb*S<4Xz z%1F!I9mSTI)k4hui3zy{%@hLPVL4P8S{ctjL4z6DYwuyzE{My3p$`%@YpB7*R~3uA zI)AdUQQb`W3nY5_9*qRI&hO`s_-MxC-X|~v8cTQ7%g}Kmfc7Ifv`}4mMh!BNUBOR0 z;b;srJCwD2TDS$k%Kqho#y%{*BPSk(1E-|5qUC9FR7Sd=ac}Z_qFK(hU`P8^0xU{Q z=&uh%Kp+ANgiX!hB~q+7;D-86%nC6Y4rKWLf)zOl#jXIm9ZRFZlSFU=LCtiF$F&39 zB>5fKW?2aQh(1iJcn!A_r3XxFUOR>~SP!eXMj51sEIHqDrM{)ghu`m0v+=`fO;V)L zWgokx_wYyb)qWMSAP+0h7mJ&a?-(`vmZB20Hp4*gHHw(-91jmA4H*Fy?{UY?I; zad3w$jmtpo(+1^?|Nn*^alRs+O-cKjBCL*BTdLCnCX_7A*U83VYXHZY?Lwv)5r*>V zY~=wF*GjhQ$%7E!jevd-iS;8JvU;&BNF$2;REgwNl z1z03@3Ou-nQE?F^{2@dUEHmFr0dqzL4Rz*??(R#M>tK0i?-Bu)$#^w;LOGGYihx0* zW`w&PT+a+*(#Q-o42VW!uwcBu(2l+gwoQNgMup;)2wWHdX`^lDjf)xpIQZyW;`xf}6g4)h4xMcmc+!e zf|+C2RDd(>^i;nGv4AWIb<)YoPM%)w3j@A|9)u>_!#`$hMN9M;y%YE!6MX2wu}#Zx zoW2K$Ph)6}Jiu%kQ5$cgJ_*FB1Z|Vl@q?5vxB<5gJLQr~#a2?)R=j0IhT|oqz8Crq zJY%S3t$FWO9s~9RQyiMmoiS@)lbGC~4swP|CB>B44?4OZ$5d#m2{?+gzyPJSXI=(7 z(OGlt%I;U!E;$uTP#eK9>z$7ffur2A6im1$KM}&?p4cUf-bXI7A__bNmy(zNQ*sS! zkF)(PzncDwP9=&Nk$B>lU?D@Mi6ic}UA%4dHyA}#2({ZtPe!9aKh|q-%Lj5>Kt`OY zyg@`aDyfZ3KoS#2Qu{mVh3qRrg+v{qve|EhH{e97 z4}Q**RAOdv(Z`Lp=Kyd;{00t?SA?Q_e;mNJy&qc}h}Wig>TurlHJb0*Y z%6vIB?-Mf@BN_+Lbs4?=(l;Q)&vIis%IdG~LT~^9Rh&AQX!PSM(OnMVjetk)is``{ha{`)uAV62})77k*ZQ{A}OP|>kAaA08l7g4=NX9%o}^#2oD`; zQM_V@hH#D%H0uK@@ZypoF2)a#m= zfZEQERid+w!5&+}?2`N{SMS|^6t97D@96Qs*KD{uF3)1b+H==p z1Uuda`TF9QIjjNhzi2IM3lJBzD7eL{NRO;u=M0SueF8TWI?**xAikv#6?E`{_1_Y( z*wVXLHyzD<1a=AgI{c2zw`Ex$1$d#8JJpaZOid5YVl$tu=*GHd6 zrx}6=ZIjA;QBhvp=0pC>h{1lIBp}}N#uf{$bk+eRAQ@`x-m3hd|Gl7Pz@-rZO6u=&6Dbx<+b|_~tK}lu#{NeltsJZDb{1Dhm zhbJjjErA$3fb@UKufj?l*%KC|as#-cBhYF9m;*>byYR_HYv6Zu9*|_9)%68xy`b6* zEcs#Z1`D7@`;dcvxZyS!0SG9f4u6M1!yl1xN+nzCAP>Qeh?H={*+m*{=}D~bWlNHn zgv1FmwOS9UBk+3>k_4fZ=o9Y`yehk5t_1p%rFEl;(-if44?DwngOd*hCHcz!H)AZY zfhFaDmR7axMru^0W0j$CJCG;{OuZm$Au0)E{rxF35cSo9L(vUymEc^0yy0uWCVL4} zO;nmYy$$+8iHE%;&jwWEQuVwyLva^yyC<1xaDN!`ms+F9bMGuAw%l#|kq?)kS?>+{y;@94|q$ubkHY$C?KsJrtco@fh`v7(D!j-b=LQbI<^K*xcfl zMUJ1yr-%3O$rZr{i}zA+QXc5rr7#MSjL@L>5om;tR$gb*;4t)?!~xN1w!il| z#0W__-NoYV>IhOw@VQ7m0pTJfyGvS26+N}q*e;X`bD{PGLR2kqAy(yIKxvVVkPOG( z)DO7Bhx$j+KZCZ)9mMDroz)$fbe%D*;b!O|P*7B9+eAUq{T8jA2aXxYF_vBsrlD3^?Ygp| zt0g2TDg)cDAIqu-+e91QZmM0t4MJf@vf81}SE!ejaQ*CnoI-zDXW3df2sz_*%g8=sD(MQ;}qVju0plAgR7SnrO)1NcAaQ zBw!ZrYi2s2Hd2CyhL!=)M~qd@9O|DvCFQ<<0(~PKw8Z-WJ~kN%>QaJ>2bIT!=c~Aw zL>6lPwz(^BBRGbMztRrCLlB+q@aVgfBHeKM?}ff|>Qc`myLkUWt>X}EGY+RYhk|KA7+sWnCe99N3?IX72xQZ`>@!A^WonvGfA1Z1Y4o|HDxcwm0>>Uz zzV^}Ojl%n$M9TSFZwhDJ9#4BJZF(08pyfUaHbQm+l|6ji1wF6Lj8>dNj+6WDZms!OnQWNe-z@ zgq7pC447FeHC(lk5RfW3zmaM=5x`fTLoEPgfB2Egt*hkd92hK~#?7Hx03WL0cS)3n@=07$(gSg6gu4I;Cxu|u zUW}-qoL$njf>ChC=}Mbn@irL7jqVTTUbHIwF9UmL#6UN*$&7MjR4KkZ4!fVW{!rLlDrXRkdpFx}V z9l-BidlaV722bMYbE!nBK^%0k`?g~fri^4rOi?on9^qYv@VDH_$#bfXIWcS1Xr0QV z$OkVZvsP#7?{2w>A0)p8cQv*cS=O-PwN?@UjX$qh zl!9gi8fTSh0mV>(j3+NxW8K6H*=6I#XuLJ=CY~L^m++th1PIjeD*)!W^lOOL#Qqrz z&Z-T>ehGLHMe2$HSG5pgj3HNIb5{cta=IY>B22nq4>IRqr?{I0CfbCfGcSL1zbBi>x9 z1o-z6y>G*53AS})$76m>d}&8^ZJ5aRJ4-i=g-)t1GVYX;rPL-M*!Ez08Pspg_Q`VK z`pploLHi?Cbrh8Pmd4Zx%v$*bKGkZto*cH3m$1c6rxE!;W5#sfwGRvY^=xrK_SQQ% z0+m(y%Xdmt`L-7$0`A#bMj9-KmI>*+@t&l<|Mz>66_QbogFG$CA{XocNC}nMN=&%W zgaGv74ZG6=msWSF$w9?b3R=VhRUr_ne54S12d*aTC`@!2zc9lDRIRK+nHZ$V0J*NH z;2{w9!f_c8=&qQpgq&I0XcV7D^;oWx9B!0>OTv&xXm6 zEM!TjCE#9}NUM=Ne;Sr;mP06>*AsMiOJTSXHvtrvf|h#AcT>p%{z|Z}DtogVMx;3x zjp2x=`)v{{()F_dEZ?K|3j7~i;~1kAeXfPNQuRZWcXO5cKscA}0NZS&>N<_Yx7PTs zrc72c+=Y4nt3eNS1N*lMk1xZ!*C1AM!WesY?Pcode%~MHHyO`Z{NLtt zwc)>qj0j|`E(pH9F{H|EyB;5}3}soA{nxnn;`;wuvGyr-7Z_lp88<<8c<@FPjI(hj z`gePHUw0iVPd**0nRyiz)ORm>l_f_{D)MCXf2H%@1TSpuV5&*}b6+p0bqXP{bLGZG~bf}{*Zc(f&=@I87rvr`NV4QDJ?mM;z& zPcxB^=v&uy2hbV3I}2mCKx9A@6L>y)QJH(&4>cOHgR-__qv03Ib%V3`fi!zDL-;iS z_cjTR2Z*f1w4G`2GEk9hFHz}Da$WdDPF%f%^`|&vVx7{VgQJ|buAc-7dH!C&3wXwvxOfeO@jpm}N$QDZNG$dc>gWnRWx{TM0C;vcc% zOMv5oct>4<_8O+sv7f|PMl)>U-g0F;UwqDzU3ktKy9P|%aF^Mlu zh|18KGhdUzVyvYdnnO9Pfo*hY>v7DYUin#q(%EsUqOpi~0QP2kY;~+8b%S+JZ z51>`nuz|FliB>6c0xmj2=uyS%^dMDA-0bI!^Id8>xZYXqzoJ-pFQJt8CdOj?Otd~m zg`{+saqEAm?gn*Eq@4O=(tq}(F|`3bxr^Ko4A{_K!JxUVf8jN%Gn&x!Uf_+hmCRDU z7hL=JuXBn;P^?~O_B{zP^5hv`D?1`DIL6DbGnWGnG!%TDXr@0L4+i9 zFi`T2OBequ-H?)=L*wm=jv1~HoKC5Dr7p@NTMmsP+%eB+KYV}a?A$PQ87A66)RrIZ zP(MTAcMO09CUC!t{COtXPiaJkDulAS@Dt z6cRy>d9Prxx<5;(^L>05m#-z+?^DoRFA1_H>x9^N$8?|{BKvpvo74)BE#vs%_fuJF zW}ih$vszuYcC+NivIdfIS;M&V}y1LmU^(B zvV?X5(otJ0mdot{4`;?^KY>os12`7i5Kv6^c+wYDzO0Q#FmxHtCjBLt?~R$6Yg?)f zOv9dT9hy5gG`fd5r^3w5+^){Cwjw!&VqRB(cp_%r>_JP~i;Jx01i^oGXGCmN|kKhtjrJdJ~^I2owXh>O?5tE%6<3 z#`aT2#w=DAjXxP5P+~m~rdb2Kj%*^K01+ATV`#=7Fm(rPnD?Pq^-6sjT4>x3>w5J< zbRgA9<{rRIi4}(bEl>wjl&l)ZH<$bc3e}E}zIpRKP8|0}zm$-Hzm@ZeUo8OG-MSWQMx~J94FpcnMf_QlA0GqAr|0v9IA`%_$0fic|5~QgnPK1(hfRVVKv>>kq{UH!M@}C9}ZQUyH)9n!wO6E5Z%mt`Y zW0G(Pf_s=<8fgNj;cAWpaTzdS3CA-0^H2eFMSzb=#a+peOy*#ikiN++Bq0NqDE>&L zpbm0wK)#e<{sT)*K`7bu5TsI&5{ON^x$x2zffG;O9|DoJoDe{$2WdfY9%#%rpA%Pz zJ-R4v5{2IOgA5c`AYHN+ezTFqWdTJxJ|K&AcLfl?RpR1qDkU;LgC%Z}Dqv#C@#+KD z8KTpi``$foX=yp@9i@z7{taHs@MwQN_0Tloa%JT;3iriniYw(A1Vj|~i=LiD)*Gs? zV;i1_J!=y0VOKpAA7haEGZ89~V^&ktaLf=T*9Y0Y0I(V)d=#qz8DF>9Dr^gjJZNL+ zY5cD2nmRVGg7ueAdcB0jMmy?h2A`buo?~pc2tqOwljn5A;-NTeKY5uzZO%IhSQ)|U|@jUlpA?yj7$ zHc+CG4iYI?mC4W@T%_Qn<-H>-M`2^7i}WMBd^9<0SMesA--ZK*MnU0Jbd=D+iAB1N z*ew8qA**)*3UA<3O-Q@39c9}hA~}lX-sLI6EW+~DjJXO{vVpT&GwK*V#0_1Qr~;1+ z;4#}NrMy(J0ikl`S$|6d7DR}%81&nl(! z#i@|xlHAypeZ-;8-cd(!!^r7iK8UA)bA(@=m=vXM$Iq;WX>`j<;8--AaX9sU5)rB zz&5pJ43pw7t`L%m*>6)}e^seiN!Jr3#;L0qc^zh>z%MHuNG+K>1^3hLrKF@vVw%vE z&9+K~vn)2}alk$@8<3b83Ide53wvKKe~sPd_5Cs(X`y6;v9x@()H)nGVhZp0L;0f+ zupo*ep_Z%}S`j+|c>}.R2`=%D8uqqUdQ<( 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 v+s!%=pt`)|sjV>E(`R=~}NVf2< literal 0 HcmV?d00001 diff --git a/design/FY2019/Li_ion_battery_model_images/battery_temp_degradation.png b/design/FY2019/Li_ion_battery_model_images/battery_temp_degradation.png new file mode 100644 index 0000000000000000000000000000000000000000..6e97043b20781add445d0a5a8250f3cf6623f722 GIT binary patch literal 114222 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

m@FJDL3e7vd% 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

V+j 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�R}KOGxMpoe+9eQ)o(rl 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�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 literal 0 HcmV?d00001 diff --git a/design/FY2019/NFP Li_ion battery model.md b/design/FY2019/NFP Li_ion battery model.md new file mode 100644 index 00000000000..669aba2b265 --- /dev/null +++ b/design/FY2019/NFP Li_ion battery model.md @@ -0,0 +1,132 @@ +# Addition of Lithium-ion Battery Chemistry to the Energy Storage Module +**Rohit Chintala** +**Ben Polly** +**Noel Merket** +**Xin Jin** +- Original Date: July 2019 + +# Introduction + +The increasing need for decarbonization has resulted in a proliferation of buildings that have incorporated decentralized power production such as photovoltaic (PV) systems to meet their energy needs. Energy storage is a crucial element to consider for such buildings as storage makes it possible to balance energy generation and consumption, in addition to improving the interaction with the electricity grid. An accurate energy storage model thus becomes essential for several research and development activities pertaining to these buildings such as battery design and capacity, sizing of PV systems, building operation control strategies, load flexibility analysis, etc. [1]. EnergyPlus can serve as a valuable tool in this regard. However, there are key limitations in the current electrical storage model which need to be addressed. This document proposes a new feature that would enhance the capabilities of the storage model by improving its accuracy, and furthermore would make it applicable to a wider range of battery chemistries. + +# Justification for New Feature Proposal +From among the battery chemistries, Lithium-ion is becoming increasingly popular for use in storing renewable energy. Although, the initial costs are higher, lithium-ion batteries outperform competing technologies such as lead (Pb)-acid in terms of energy delivered and specific power. Furthermore, lithium-ion batteries may be more economical in the long run as they have longer cycle life and lower life cycle costs [2]. EnergyPlus doesn't have a storage model that can accurately simulate Li-ion battery chemistry. Having accurate models that predict various aggregate properties of the battery state allows energy modelers to make more informed decisions about selecting the right storage size and chemistry for the building under consideration. A brief summary of the limitation that exist in the current energy storage model and a description of the proposed model developed by SAM [3] is provided below. + +#### Constant Charging and Discharging Efficiencies +The electrical storage module in EnergyPlus currently has two models – a Simple Energy Balance model and a Kinetic Battery model. The simple energy model treats the battery as a black-box and counts the energy that is added or removed from it using constant charging and discharging efficiencies. The state of charge $$(Q_{stor})$$ at time step $$t+\Delta t$$ can be written as follows: +$$Q_{stor}^{t+\Delta t} = Q_{stor}^t+P_{chg}\cdot \epsilon_{chg} \cdot \Delta t$$ +where $$P_{chg}$$ is the charging power, and $$\epsilon_{chg}$$ is the charging efficiency. In a more accurate model of a Li-ion battery, however, the charging efficiency is not constant but is dependent on its current state of charge and terminal voltage. Not accurately modeling the battery states or efficiencies results in discrepancies while computing the battery charging and discharging power. A comparison of the charging power required to charge the battery at a constant rate as computed by the simple energy balance model, and the proposed SAM model is shown in Figure 1. +![](Li_ion_battery_model_images/Simple_vs_SAM.png) +Figure 1: Charging power comparison between Simple Energy Model and SAM at constant C-rate. + + +#### Kinetic Battery Model is not Suited for Li-ion +There are certain characteristics that are exhibited by batteries with Pb-acid chemistries that make them significantly different than others. One such property which makes them unique is the fact that a fraction of the total charge remains chemically bounded at any time. The bound charge must become available before it can be used [3]. The kinetic battery model which is employed by the EnergyPlus storage module assumes that the charge stored in the battery is divided into two tanks, an available charge tank and a bound-charge tank. Not all the charge that is currently stored in the battery is directly available to the load. The portion of the charge that is present in the bound-charge tank can supply electrons only to the available charge tank. +The kinetic battery model described above is more suitable for battery chemistries such as Pb-acid with slow chemical kinetics. Li-ion have batteries have much faster dynamics enabling them to be charged and discharged much more rapidly. The proposed model treats the battery as a single tank of charge, thereby representing Li-ion chemistry more accurately. + +#### Battery Thermal Model + +The electrical storage module in EnergyPlus doesn't model the battery temperature. The thermal model captures the impact of the ambient conditions not only on the battery temperature, but also the amount of heat dissipated by the battery to the surroundings. Furthermore, battery temperature has a big impact on the charge capacity and the calendar degradation. The lifecylce of a battery can be maximized by maintaining the battery temperature at room temperature. There is a significant reduction in the battery lifetime when the temperature instead is much higher or lower than the room temperature. For example, Figure 2 below shows how the capacity degradation of a typical Li-ion cell under different ambient temperatures. The figures were generated using the Li-ion capacity degradation model developed by Smith et al. in [4]. In order to determine the best dispatch strategy that also maximizes the battery's lifespan, an accurate model of both the capacity and cycle degradation is required. But as is evident from the figure, not modeling the thermal effects causes significant discrepancies in the estimation of these battery states. +![](Li_ion_battery_model_images/battery_temp_degradation.png) +Figure 2: Charge degradation at various ambient temperatures. + +#### Calendar and Cycle Degradation +There are two main mechanisms by which the battery capacity is reduced over its lifetime as listed below. +* Loss in cyclable Lithium due to the development of a solid-electrolyte interface (SEI) with time +* Mechanical damage to the negative electrode due to cycling + +The actual battery capacity can be modeled as the limiting value of these competing mechanisms [5] as shown in the equation below +$$Q_{max} = min(Q_{max}^{Li},Q_{max}^{neg})$$ +where $$Q_{max}$$ is the modeled battery capacity, and $$Q_{max}^{Li}$$ and $$Q_{max}^{neg}$$ are the capacities modeled due to the two mechanisms listed above. Each of the two mechanisms depend on several factors such as Depth of Discharge (DoD), number of cycles, battery temperature, calendar time, State of Charge (SoC) etc. The current cycle life model in EnergyPlus, however, does not take into consideration the different mechanisms by which the battery capacity fades. + +# Method and Approach +This section briefly describes the theory of the proposed battery model, and the programming approach that can be used to implement it in EnergyPlus. +#### Battery Performance and Lifetime Model +The battery performance model is used to describe its aggregate properties which include terminal voltage, state of charge, and temperature at every time step of the simulation. The parameters of the model can be extracted from battery data-sheets. The terminal voltage $V_{term}$ is expressed as shown in the equation below. +$$V_{term} = V_0 - I_{bat}\cdot R - K(Q_{max}/Q - \int I_{bat}\cdot dt ) +a\cdot e^{-BI_{bat}dt}$$ +A description of the variables, and the constants and their values corresponding to a Li-ion cell in the equation above are shown in Tables 1 and 2. + +Table 1: Description of variables in the terminal voltage equation. +| Parameter (symbol) | Value | +| ------ | ------ | +| $$V_{term} (V)$$ | Terminal Voltage | +| $$Q_{max} (Ah)$$ | Battery Capacity | +| $$Q (Ah)$$ | Battery Charge| +| $$I_{bat}(A)$$ | Battery current | +| $$dt (hr)$$ | Time Step | + +Table 2: Parameters of the terminal voltage equation. +| Parameter (symbol) | Description |Value| +| ------ | ------ |------ | +| $$V_0$$ |Open Circuit Voltage |3.7348| +| $$R(\omega)$$ | Internal Resistance |0.09| +| $$K(V)$$ | Polarization Voltage|0.00876| +| $$a(V)$$ | Exponential Zone Amplitude |0.468| +| $$B(Ah)^{-1}$$ | Exponential Zone Time Constant Inverse |3.5294| + +The state of charge of the battery $Q_{bat}$ at time step $$k$$ is updated using the equation below +$$Q_{bat}(k) = Q_{bat}(k-1) + \left((I_{bat}\cdot V_{term})\cdot (1/1000)/E_{max} \right)$$ +where $$E_{max}$$ is the maximum capacity of the battery in $$kWh$$. + +The thermal model is generated by using an energy balance which takes into consideration the heat generated due to the internal resistance, the heat transferred to and from the surrounding, and the thermal storage of the battery and the casing. The output of interest is the battery temperature $$T_{bat}$$ and the equation governing its evolution with time is expressed in the equation below +$$dT_{bat}/dt = (hA(T_{out} - T_{bat}) + I_{bat}^2R)/(m\cdot C_p)$$ +where $$T_{out}$$ is the ambient temperature, and $m$ and $C_p$ are the mass and specific heat capacity of the battery. + +The lifetime model is adopted from the paper by Smith et.al [4]. The model predicts the battery capacity degradation with time and use. The maximum capacity is computed by taking into consideration two mechanisms as was described in the previous section, the loss of cyclable Lithium due to formation of SEI $$(Q_{max}^{Li}$$, and the mechanical damage of the negative electrode due to the charge/discharge cycles $$(Q_{max}^{neg})$$. The battery capacity due to each of the mechanisms is shown in the equations below. +$$Q_{max}^{Li} = d_0 \left[b_0 - b_1t^{1/2} - b_2N - b_3(1-exp(-t/\tau_{b_3})\right]$$ + +$$Q_{max}^{neg} = d_0 \left[c_0^2 - 2c_2c_0N\right]^{1/2}$$ +The parameters $d_0,b_1, b_2, b_3, c_0, c_2$ depend on several factors such as depth of discharge, state of charge, number of cycles etc. These relationships were determined by Smith et.al in [4]. The capacity at any point in time is the limiting value of the estimates from the two mechanisms as shown in the equation below. +$$Q_{max} = min(Q_{max}^{Li}, Q_{max}^{neg})$$ + +#### Programming Approach +The System Advisor Model (SAM) already has a battery module based on the models described in the previous section. In order to incorporate this module in EnergyPlus, the battery model in SAM and all its dependencies can be imported into the third party liabrary in EnergyPlus. The battery model and its dependencies are contained in two folders of the SAM repository, the 'ssc' folder and the 'shared' folder. The link to the github repository of the SAM model is below. + +https://github.com/nrel/ssc + +The electrical storage model in EnergyPlus is present in the file ElectricPowerServiceManager.cc. The storage model in this file currently has just two cases corresponding to the simple battery model (simpleBucketStorage) and the Kinetic Battery Model (kiBaMBattery). A third case needs to be added to model Li-ion batteries (LiIonBattery) by importing the relevant libraries from the 'third\_party' folder. + +# Inputs and Outputs +The inputs and outputs that would be required to incorporate the Li-ion battery performance and lifetime degradation models are shown below. +#### Inputs +* Field: Name +* Availability schedule name +* Zone name +* Mass +* Effective specific heat capacity +* Effective conduction coefficient +* Number of battery modules in series +* Number of battery modules in parallel +* Initial fractional state of charge +* Module cut-off voltage +* Battery nominal capacity +* Battery usable capacity +* Real power max continuous +* Real power peak charging +* Real power peak discharging +* Nominal voltage + +#### Outputs +* Electric storage charge state +* Electric storage charge fraction +* Electric storage charge power +* Electric storage charge energy +* Electric storage discharge power +* Electric storage discharge energy +* Electric storage total current +* Electric storage total voltage +* Electric storage thermal loss rate +* Electric storage Thermal loss energy +* Electric storage temperature +* Electric storage degradation fraction +* Electric storage charge capacity +* Electric storage internal resistance + +# References + +[1] Berrueta, Alberto, et al. "A comprehensive model for lithium-ion batteries: From the physical principles to an electrical model." Energy 144 (2018): 286-300. +[2] Diouf, Boucar, and Ramchandra Pode. "Potential of lithium-ion batteries in renewable energy." Renewable Energy 76 (2015): 375-380 +[3] DiOrio, Nicholas, et al. Technoeconomic modeling of battery energy storage in SAM. No. NREL/TP-6A20-64641. National Renewable Energy Lab.(NREL), Golden, CO (United States), 2015. +[4] Smith, Kandler, et al. "Life prediction model for grid-connected Li-ion battery energy storage system." 2017 American Control Conference (ACC). IEEE, 2017 +[5] Santhanagopalan, Shriram, et al. Design and analysis of large lithium-ion battery systems. Artech House, 2014. + From 07a2bed15d16c502da26862c562587500d980775 Mon Sep 17 00:00:00 2001 From: rchintala13 <46604512+rchintala13@users.noreply.github.com> Date: Tue, 25 Aug 2020 14:22:32 -0600 Subject: [PATCH 02/76] Update NFP Li_ion battery model.md --- design/FY2019/NFP Li_ion battery model.md | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/design/FY2019/NFP Li_ion battery model.md b/design/FY2019/NFP Li_ion battery model.md index 669aba2b265..49b39c46736 100644 --- a/design/FY2019/NFP Li_ion battery model.md +++ b/design/FY2019/NFP Li_ion battery model.md @@ -2,7 +2,6 @@ **Rohit Chintala** **Ben Polly** **Noel Merket** -**Xin Jin** - Original Date: July 2019 # Introduction @@ -84,7 +83,25 @@ The System Advisor Model (SAM) already has a battery module based on the models https://github.com/nrel/ssc -The electrical storage model in EnergyPlus is present in the file ElectricPowerServiceManager.cc. The storage model in this file currently has just two cases corresponding to the simple battery model (simpleBucketStorage) and the Kinetic Battery Model (kiBaMBattery). A third case needs to be added to model Li-ion batteries (LiIonBattery) by importing the relevant libraries from the 'third\_party' folder. +The following liabraries from the SAM repository would be imported into EnergyPlus. +1. cmod_battery.h +2. common.h +3. core.h +4. lib_battery.h +5. lib_battery_dispatch.h +6. lib_battery_powerflow.h +7. lib_power_electronics.h +8. lib_resilience.h +9. lib_shared_inverter.h +10. lib_time.h +11. lib_util.h +12. lib_utility_rate.h +13. lib_weatherfile.h +14. 6par_newton.h + +A new class lifetime_calendar_t::runLithiumIonLifetimeModel has been programmed in the lib_battery module of SAM to model the capacity degradation of a lithium-ion battery based on the model described above by Smith et.al. [4]. The model outputs the updated capacity of the battery at every timestep taking into consideration the cycling history, state of charge, depth of discharge, and the ambient temperature to which the battery is exposed. + +The electrical storage model in EnergyPlus is present in the file ElectricPowerServiceManager.cc. The storage model in this file currently has just two cases corresponding to the simple battery model (simpleBucketStorage) and the Kinetic Battery Model (kiBaMBattery). By importing the aforementioned liabraries from SAM, a more detailed and accurate capacity degaradation model for Lithium ion can be incorporated into EnergyPlus. # Inputs and Outputs The inputs and outputs that would be required to incorporate the Li-ion battery performance and lifetime degradation models are shown below. From 9765127ea68327d3d4094556b0c19525a6d148d4 Mon Sep 17 00:00:00 2001 From: Noel Merket Date: Wed, 26 Aug 2020 09:22:44 -0600 Subject: [PATCH 03/76] fix tyops --- design/FY2019/NFP Li_ion battery model.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/design/FY2019/NFP Li_ion battery model.md b/design/FY2019/NFP Li_ion battery model.md index 49b39c46736..84d09679a76 100644 --- a/design/FY2019/NFP Li_ion battery model.md +++ b/design/FY2019/NFP Li_ion battery model.md @@ -79,11 +79,11 @@ The parameters $d_0,b_1, b_2, b_3, c_0, c_2$ depend on several factors such as d $$Q_{max} = min(Q_{max}^{Li}, Q_{max}^{neg})$$ #### Programming Approach -The System Advisor Model (SAM) already has a battery module based on the models described in the previous section. In order to incorporate this module in EnergyPlus, the battery model in SAM and all its dependencies can be imported into the third party liabrary in EnergyPlus. The battery model and its dependencies are contained in two folders of the SAM repository, the 'ssc' folder and the 'shared' folder. The link to the github repository of the SAM model is below. +The System Advisor Model (SAM) already has a battery module based on the models described in the previous section. In order to incorporate this module in EnergyPlus, the battery model in SAM and all its dependencies can be imported into the third party library in EnergyPlus. The battery model and its dependencies are contained in two folders of the SAM repository, the 'ssc' folder and the 'shared' folder. The link to the github repository of the SAM model is below. https://github.com/nrel/ssc -The following liabraries from the SAM repository would be imported into EnergyPlus. +The following libraries from the SAM repository would be imported into EnergyPlus. 1. cmod_battery.h 2. common.h 3. core.h @@ -101,7 +101,7 @@ The following liabraries from the SAM repository would be imported into EnergyPl A new class lifetime_calendar_t::runLithiumIonLifetimeModel has been programmed in the lib_battery module of SAM to model the capacity degradation of a lithium-ion battery based on the model described above by Smith et.al. [4]. The model outputs the updated capacity of the battery at every timestep taking into consideration the cycling history, state of charge, depth of discharge, and the ambient temperature to which the battery is exposed. -The electrical storage model in EnergyPlus is present in the file ElectricPowerServiceManager.cc. The storage model in this file currently has just two cases corresponding to the simple battery model (simpleBucketStorage) and the Kinetic Battery Model (kiBaMBattery). By importing the aforementioned liabraries from SAM, a more detailed and accurate capacity degaradation model for Lithium ion can be incorporated into EnergyPlus. +The electrical storage model in EnergyPlus is present in the file ElectricPowerServiceManager.cc. The storage model in this file currently has just two cases corresponding to the simple battery model (simpleBucketStorage) and the Kinetic Battery Model (kiBaMBattery). By importing the aforementioned libraries from SAM, a more detailed and accurate capacity degaradation model for Lithium ion can be incorporated into EnergyPlus. # Inputs and Outputs The inputs and outputs that would be required to incorporate the Li-ion battery performance and lifetime degradation models are shown below. From a6494213c2aeb7e411439b4454d5d494217e7d69 Mon Sep 17 00:00:00 2001 From: Noel Merket Date: Wed, 26 Aug 2020 09:28:42 -0600 Subject: [PATCH 04/76] formatting changes --- design/FY2019/NFP Li_ion battery model.md | 50 +++++++++++++---------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/design/FY2019/NFP Li_ion battery model.md b/design/FY2019/NFP Li_ion battery model.md index 84d09679a76..32a428354f4 100644 --- a/design/FY2019/NFP Li_ion battery model.md +++ b/design/FY2019/NFP Li_ion battery model.md @@ -1,17 +1,20 @@ # Addition of Lithium-ion Battery Chemistry to the Energy Storage Module -**Rohit Chintala** -**Ben Polly** + +**Rohit Chintala**
+**Ben Polly**
**Noel Merket** -- Original Date: July 2019 -# Introduction +Original Date: July 2019
+Updated: August 2020 + +## Introduction The increasing need for decarbonization has resulted in a proliferation of buildings that have incorporated decentralized power production such as photovoltaic (PV) systems to meet their energy needs. Energy storage is a crucial element to consider for such buildings as storage makes it possible to balance energy generation and consumption, in addition to improving the interaction with the electricity grid. An accurate energy storage model thus becomes essential for several research and development activities pertaining to these buildings such as battery design and capacity, sizing of PV systems, building operation control strategies, load flexibility analysis, etc. [1]. EnergyPlus can serve as a valuable tool in this regard. However, there are key limitations in the current electrical storage model which need to be addressed. This document proposes a new feature that would enhance the capabilities of the storage model by improving its accuracy, and furthermore would make it applicable to a wider range of battery chemistries. -# Justification for New Feature Proposal +## Justification for New Feature Proposal From among the battery chemistries, Lithium-ion is becoming increasingly popular for use in storing renewable energy. Although, the initial costs are higher, lithium-ion batteries outperform competing technologies such as lead (Pb)-acid in terms of energy delivered and specific power. Furthermore, lithium-ion batteries may be more economical in the long run as they have longer cycle life and lower life cycle costs [2]. EnergyPlus doesn't have a storage model that can accurately simulate Li-ion battery chemistry. Having accurate models that predict various aggregate properties of the battery state allows energy modelers to make more informed decisions about selecting the right storage size and chemistry for the building under consideration. A brief summary of the limitation that exist in the current energy storage model and a description of the proposed model developed by SAM [3] is provided below. -#### Constant Charging and Discharging Efficiencies +### Constant Charging and Discharging Efficiencies The electrical storage module in EnergyPlus currently has two models – a Simple Energy Balance model and a Kinetic Battery model. The simple energy model treats the battery as a black-box and counts the energy that is added or removed from it using constant charging and discharging efficiencies. The state of charge $$(Q_{stor})$$ at time step $$t+\Delta t$$ can be written as follows: $$Q_{stor}^{t+\Delta t} = Q_{stor}^t+P_{chg}\cdot \epsilon_{chg} \cdot \Delta t$$ where $$P_{chg}$$ is the charging power, and $$\epsilon_{chg}$$ is the charging efficiency. In a more accurate model of a Li-ion battery, however, the charging efficiency is not constant but is dependent on its current state of charge and terminal voltage. Not accurately modeling the battery states or efficiencies results in discrepancies while computing the battery charging and discharging power. A comparison of the charging power required to charge the battery at a constant rate as computed by the simple energy balance model, and the proposed SAM model is shown in Figure 1. @@ -19,17 +22,17 @@ where $$P_{chg}$$ is the charging power, and $$\epsilon_{chg}$$ is the charging Figure 1: Charging power comparison between Simple Energy Model and SAM at constant C-rate. -#### Kinetic Battery Model is not Suited for Li-ion +### Kinetic Battery Model is not Suited for Li-ion There are certain characteristics that are exhibited by batteries with Pb-acid chemistries that make them significantly different than others. One such property which makes them unique is the fact that a fraction of the total charge remains chemically bounded at any time. The bound charge must become available before it can be used [3]. The kinetic battery model which is employed by the EnergyPlus storage module assumes that the charge stored in the battery is divided into two tanks, an available charge tank and a bound-charge tank. Not all the charge that is currently stored in the battery is directly available to the load. The portion of the charge that is present in the bound-charge tank can supply electrons only to the available charge tank. The kinetic battery model described above is more suitable for battery chemistries such as Pb-acid with slow chemical kinetics. Li-ion have batteries have much faster dynamics enabling them to be charged and discharged much more rapidly. The proposed model treats the battery as a single tank of charge, thereby representing Li-ion chemistry more accurately. -#### Battery Thermal Model +### Battery Thermal Model The electrical storage module in EnergyPlus doesn't model the battery temperature. The thermal model captures the impact of the ambient conditions not only on the battery temperature, but also the amount of heat dissipated by the battery to the surroundings. Furthermore, battery temperature has a big impact on the charge capacity and the calendar degradation. The lifecylce of a battery can be maximized by maintaining the battery temperature at room temperature. There is a significant reduction in the battery lifetime when the temperature instead is much higher or lower than the room temperature. For example, Figure 2 below shows how the capacity degradation of a typical Li-ion cell under different ambient temperatures. The figures were generated using the Li-ion capacity degradation model developed by Smith et al. in [4]. In order to determine the best dispatch strategy that also maximizes the battery's lifespan, an accurate model of both the capacity and cycle degradation is required. But as is evident from the figure, not modeling the thermal effects causes significant discrepancies in the estimation of these battery states. ![](Li_ion_battery_model_images/battery_temp_degradation.png) Figure 2: Charge degradation at various ambient temperatures. -#### Calendar and Cycle Degradation +### Calendar and Cycle Degradation There are two main mechanisms by which the battery capacity is reduced over its lifetime as listed below. * Loss in cyclable Lithium due to the development of a solid-electrolyte interface (SEI) with time * Mechanical damage to the negative electrode due to cycling @@ -38,9 +41,11 @@ The actual battery capacity can be modeled as the limiting value of these compet $$Q_{max} = min(Q_{max}^{Li},Q_{max}^{neg})$$ where $$Q_{max}$$ is the modeled battery capacity, and $$Q_{max}^{Li}$$ and $$Q_{max}^{neg}$$ are the capacities modeled due to the two mechanisms listed above. Each of the two mechanisms depend on several factors such as Depth of Discharge (DoD), number of cycles, battery temperature, calendar time, State of Charge (SoC) etc. The current cycle life model in EnergyPlus, however, does not take into consideration the different mechanisms by which the battery capacity fades. -# Method and Approach +## Method and Approach + This section briefly describes the theory of the proposed battery model, and the programming approach that can be used to implement it in EnergyPlus. -#### Battery Performance and Lifetime Model + +### Battery Performance and Lifetime Model The battery performance model is used to describe its aggregate properties which include terminal voltage, state of charge, and temperature at every time step of the simulation. The parameters of the model can be extracted from battery data-sheets. The terminal voltage $V_{term}$ is expressed as shown in the equation below. $$V_{term} = V_0 - I_{bat}\cdot R - K(Q_{max}/Q - \int I_{bat}\cdot dt ) +a\cdot e^{-BI_{bat}dt}$$ A description of the variables, and the constants and their values corresponding to a Li-ion cell in the equation above are shown in Tables 1 and 2. @@ -78,7 +83,7 @@ $$Q_{max}^{neg} = d_0 \left[c_0^2 - 2c_2c_0N\right]^{1/2}$$ The parameters $d_0,b_1, b_2, b_3, c_0, c_2$ depend on several factors such as depth of discharge, state of charge, number of cycles etc. These relationships were determined by Smith et.al in [4]. The capacity at any point in time is the limiting value of the estimates from the two mechanisms as shown in the equation below. $$Q_{max} = min(Q_{max}^{Li}, Q_{max}^{neg})$$ -#### Programming Approach +### Programming Approach The System Advisor Model (SAM) already has a battery module based on the models described in the previous section. In order to incorporate this module in EnergyPlus, the battery model in SAM and all its dependencies can be imported into the third party library in EnergyPlus. The battery model and its dependencies are contained in two folders of the SAM repository, the 'ssc' folder and the 'shared' folder. The link to the github repository of the SAM model is below. https://github.com/nrel/ssc @@ -103,9 +108,11 @@ A new class lifetime_calendar_t::runLithiumIonLifetimeModel has been programmed The electrical storage model in EnergyPlus is present in the file ElectricPowerServiceManager.cc. The storage model in this file currently has just two cases corresponding to the simple battery model (simpleBucketStorage) and the Kinetic Battery Model (kiBaMBattery). By importing the aforementioned libraries from SAM, a more detailed and accurate capacity degaradation model for Lithium ion can be incorporated into EnergyPlus. -# Inputs and Outputs +## Inputs and Outputs The inputs and outputs that would be required to incorporate the Li-ion battery performance and lifetime degradation models are shown below. -#### Inputs + +### Inputs + * Field: Name * Availability schedule name * Zone name @@ -123,7 +130,8 @@ The inputs and outputs that would be required to incorporate the Li-ion battery * Real power peak discharging * Nominal voltage -#### Outputs +### Outputs + * Electric storage charge state * Electric storage charge fraction * Electric storage charge power @@ -139,11 +147,11 @@ The inputs and outputs that would be required to incorporate the Li-ion battery * Electric storage charge capacity * Electric storage internal resistance -# References +## References -[1] Berrueta, Alberto, et al. "A comprehensive model for lithium-ion batteries: From the physical principles to an electrical model." Energy 144 (2018): 286-300. -[2] Diouf, Boucar, and Ramchandra Pode. "Potential of lithium-ion batteries in renewable energy." Renewable Energy 76 (2015): 375-380 -[3] DiOrio, Nicholas, et al. Technoeconomic modeling of battery energy storage in SAM. No. NREL/TP-6A20-64641. National Renewable Energy Lab.(NREL), Golden, CO (United States), 2015. -[4] Smith, Kandler, et al. "Life prediction model for grid-connected Li-ion battery energy storage system." 2017 American Control Conference (ACC). IEEE, 2017 -[5] Santhanagopalan, Shriram, et al. Design and analysis of large lithium-ion battery systems. Artech House, 2014. +- [1] Berrueta, Alberto, et al. "A comprehensive model for lithium-ion batteries: From the physical principles to an electrical model." Energy 144 (2018): 286-300. +- [2] Diouf, Boucar, and Ramchandra Pode. "Potential of lithium-ion batteries in renewable energy." Renewable Energy 76 (2015): 375-380 +- [3] DiOrio, Nicholas, et al. Technoeconomic modeling of battery energy storage in SAM. No. NREL/TP-6A20-64641. National Renewable Energy Lab.(NREL), Golden, CO (United States), 2015. +- [4] Smith, Kandler, et al. "Life prediction model for grid-connected Li-ion battery energy storage system." 2017 American Control Conference (ACC). IEEE, 2017 +- [5] Santhanagopalan, Shriram, et al. Design and analysis of large lithium-ion battery systems. Artech House, 2014. From c5b1d2faf2dd838198554c028d357d26445f8c9a Mon Sep 17 00:00:00 2001 From: Noel Merket Date: Wed, 26 Aug 2020 09:40:07 -0600 Subject: [PATCH 05/76] moving li-ion battery model nfp to fy2020 folder --- design/{FY2019 => FY2020}/NFP Li_ion battery model.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename design/{FY2019 => FY2020}/NFP Li_ion battery model.md (100%) diff --git a/design/FY2019/NFP Li_ion battery model.md b/design/FY2020/NFP Li_ion battery model.md similarity index 100% rename from design/FY2019/NFP Li_ion battery model.md rename to design/FY2020/NFP Li_ion battery model.md From bb83a27800395ca220b2a0a913eb92b28f5a5248 Mon Sep 17 00:00:00 2001 From: xuanluo113 Date: Wed, 9 Dec 2020 17:53:04 -0800 Subject: [PATCH 06/76] first commit --- src/EnergyPlus/ChilledCeilingPanelSimple.cc | 7 +- src/EnergyPlus/ConvectionCoefficients.cc | 4 +- src/EnergyPlus/DataSurfaces.cc | 25 +- src/EnergyPlus/DataSurfaces.hh | 37 +- src/EnergyPlus/DaylightingManager.cc | 58 +-- src/EnergyPlus/ElectricBaseboardRadiator.cc | 6 +- src/EnergyPlus/HWBaseboardRadiator.cc | 6 +- src/EnergyPlus/HeatBalanceIntRadExchange.cc | 18 +- src/EnergyPlus/HeatBalanceSurfaceManager.cc | 148 +++---- src/EnergyPlus/HighTempRadiantSystem.cc | 6 +- src/EnergyPlus/LowTempRadiantSystem.cc | 6 +- src/EnergyPlus/RoomAirModelAirflowNetwork.cc | 8 +- src/EnergyPlus/SolarShading.cc | 417 +++++++++--------- src/EnergyPlus/SteamBaseboardRadiator.cc | 6 +- src/EnergyPlus/SurfaceGeometry.cc | 6 +- src/EnergyPlus/SwimmingPool.cc | 8 +- src/EnergyPlus/UFADManager.cc | 2 +- src/EnergyPlus/VentilatedSlab.cc | 6 +- src/EnergyPlus/WindowComplexManager.cc | 18 +- src/EnergyPlus/WindowManager.cc | 170 +++---- .../WindowManagerExteriorThermal.cc | 30 +- src/EnergyPlus/ZoneTempPredictorCorrector.cc | 14 +- .../unit/DaylightingManager.unit.cc | 11 +- tst/EnergyPlus/unit/EMSManager.unit.cc | 2 +- .../unit/HeatBalanceSurfaceManager.unit.cc | 2 +- 25 files changed, 497 insertions(+), 524 deletions(-) diff --git a/src/EnergyPlus/ChilledCeilingPanelSimple.cc b/src/EnergyPlus/ChilledCeilingPanelSimple.cc index 765f85cb54d..48715e128db 100644 --- a/src/EnergyPlus/ChilledCeilingPanelSimple.cc +++ b/src/EnergyPlus/ChilledCeilingPanelSimple.cc @@ -1705,8 +1705,7 @@ namespace CoolingPanelSimple { using DataHeatBalance::HConvIn; using DataHeatBalance::Zone; using DataHeatBalSurface::TempSurfInTmp; - using DataSurfaces::IntBlindOn; - using DataSurfaces::IntShadeOn; + using DataSurfaces::WinShadingFlag; using DataSurfaces::Surface; using DataSurfaces::SurfWinShadingFlag; using DataSurfaces::SurfWinFrameArea; @@ -1736,7 +1735,7 @@ namespace CoolingPanelSimple { if (ThisSurf.Class == DataSurfaces::SurfaceClass::Window) { - if (SurfWinShadingFlag(SurfNum) == IntShadeOn || SurfWinShadingFlag(SurfNum) == IntBlindOn) { + if (SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntShadeOn || SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntBlindOn) { // The area is the shade or blind area = the sum of the glazing area and the divider area (which is zero if no divider) Area += DataSurfaces::SurfWinDividerArea(SurfNum); } @@ -1746,7 +1745,7 @@ namespace CoolingPanelSimple { SumHATsurf += HConvIn(SurfNum) * SurfWinFrameArea(SurfNum) * (1.0 + SurfWinProjCorrFrIn(SurfNum)) * SurfWinFrameTempSurfIn(SurfNum); } - if (SurfWinDividerArea(SurfNum) > 0.0 && SurfWinShadingFlag(SurfNum) != IntShadeOn && SurfWinShadingFlag(SurfNum) != IntBlindOn) { + if (SurfWinDividerArea(SurfNum) > 0.0 && SurfWinShadingFlag(SurfNum) != WinShadingFlag::IntShadeOn && SurfWinShadingFlag(SurfNum) != WinShadingFlag::IntBlindOn) { // Window divider contribution (only from shade or blind for window with divider and interior shade or blind) SumHATsurf += HConvIn(SurfNum) * SurfWinDividerArea(SurfNum) * (1.0 + 2.0 * SurfWinProjCorrDivIn(SurfNum)) * SurfWinDividerTempSurfIn(SurfNum); diff --git a/src/EnergyPlus/ConvectionCoefficients.cc b/src/EnergyPlus/ConvectionCoefficients.cc index bc942c13227..f951b8842bd 100644 --- a/src/EnergyPlus/ConvectionCoefficients.cc +++ b/src/EnergyPlus/ConvectionCoefficients.cc @@ -400,7 +400,7 @@ namespace ConvectionCoefficients { if (!Surface(SurfNum).ExtWind) { SurfWindSpeed = 0.0; // No wind exposure - } else if (Surface(SurfNum).Class == SurfaceClass::Window && SurfWinShadingFlag(SurfNum) == ExtShadeOn) { + } else if (Surface(SurfNum).Class == SurfaceClass::Window && SurfWinShadingFlag(SurfNum) == WinShadingFlag::ExtShadeOn) { SurfWindSpeed = 0.0; // Assume zero wind speed at outside glass surface of window with exterior shade } else { SurfWindSpeed = Surface(SurfNum).WindSpeed; @@ -4736,7 +4736,7 @@ namespace ConvectionCoefficients { if (!Surface(SurfNum).ExtWind) { SurfWindSpeed = 0.0; // No wind exposure - } else if (Surface(SurfNum).Class == SurfaceClass::Window && SurfWinShadingFlag(SurfNum) == ExtShadeOn) { + } else if (Surface(SurfNum).Class == SurfaceClass::Window && SurfWinShadingFlag(SurfNum) == WinShadingFlag::ExtShadeOn) { SurfWindSpeed = 0.0; // Assume zero wind speed at outside glass surface of window with exterior shade } else { SurfWindSpeed = Surface(SurfNum).WindSpeed; diff --git a/src/EnergyPlus/DataSurfaces.cc b/src/EnergyPlus/DataSurfaces.cc index f2fcad1c635..66557a26038 100644 --- a/src/EnergyPlus/DataSurfaces.cc +++ b/src/EnergyPlus/DataSurfaces.cc @@ -237,23 +237,6 @@ namespace DataSurfaces { int const InConvWinLoc_WindowBelowThis(4); // this is a wall with window below it int const InConvWinLoc_LargePartOfExteriorWall(5); // this is a big window taking up most of wall - // Parameters for window shade status - int const NoShade(-1); - int const ShadeOff(0); - int const IntShadeOn(1); // Interior shade on - int const SwitchableGlazing(2); - int const ExtShadeOn(3); // Exterior shade on - int const ExtScreenOn(4); // Exterior screen on - int const IntBlindOn(6); // Interior blind on - int const ExtBlindOn(7); // Exterior blind on - int const BGShadeOn(8); // Between-glass shade on - int const BGBlindOn(9); // Between-glass blind on - int const IntShadeConditionallyOff(10); - int const GlassConditionallyLightened(20); - int const ExtShadeConditionallyOff(30); - int const IntBlindConditionallyOff(60); - int const ExtBlindConditionallyOff(70); - // WindowShadingControl Shading Types int const WSC_ST_NoShade(0); int const WSC_ST_InteriorShade(1); @@ -511,13 +494,15 @@ namespace DataSurfaces { Array1D SurfWinProfileAngHor; // Horizontal beam solar profile angle (degrees) Array1D SurfWinProfileAngVert; // Vertical beam solar profile angle (degrees) - Array1D SurfWinShadingFlag; // -1: window has no shading device + Array1D SurfWinShadingFlag; // -1: window has no shading device + Array1D SurfWinShaded; // Window shading flag is not shadeoff or noshade Array1D SurfWinShadingFlagEMSOn; // EMS control flag, true if EMS is controlling ShadingFlag with ShadingFlagEMSValue Array1D SurfWinShadingFlagEMSValue; // EMS control value for Shading Flag + Array1D SurfWinGlareControlIsActive; // True if glare control is active Array1D SurfWinStormWinFlag; // -1: Storm window not applicable; 0: Window has storm window but it is off 1: Window has storm window and it is on Array1D SurfWinStormWinFlagPrevDay; // Previous time step value of StormWinFlag Array1D SurfWinFracTimeShadingDeviceOn; // For a single time step, = 0.0 if no shading device or shading device is off = 1.0 if shading device is on; For time intervals longer than a time step, = fraction of time that shading device is on. - Array1D SurfWinExtIntShadePrevTS; // 1 if exterior or interior blind or shade in place previous time step;0 otherwise + Array1D SurfWinExtIntShadePrevTS; // 1 if exterior or interior blind or shade in place previous time step;0 otherwise Array1D SurfWinHasShadeOrBlindLayer; // mark as true if the window construction has a shade or a blind layer Array1D SurfWinSurfDayLightInit; // surface has been initialized for following 5 arrays Array1D SurfWinDaylFacPoint; // Pointer to daylight factors for the window @@ -1325,8 +1310,10 @@ namespace DataSurfaces { SurfWinProfileAngVert.clear(); SurfWinShadingFlag.clear(); + SurfWinShaded.clear(); SurfWinShadingFlagEMSOn.clear(); SurfWinShadingFlagEMSValue.clear(); + SurfWinGlareControlIsActive.clear(); SurfWinStormWinFlag.clear(); SurfWinStormWinFlagPrevDay.clear(); SurfWinFracTimeShadingDeviceOn.clear(); diff --git a/src/EnergyPlus/DataSurfaces.hh b/src/EnergyPlus/DataSurfaces.hh index 3cbf9f2c631..1829693e762 100644 --- a/src/EnergyPlus/DataSurfaces.hh +++ b/src/EnergyPlus/DataSurfaces.hh @@ -120,6 +120,20 @@ namespace DataSurfaces { Count // The counter representing the total number of surface class, always stays at the bottom }; + enum class WinShadingFlag : int { + NoShade = -1, + ShadeOff = 0, + IntShadeOn = 1, + SwitchableGlazing = 2, + ExtShadeOn = 3, + ExtScreenOn = 4, + IntBlindOn = 5, + ExtBlindOn = 6, + BGShadeOn = 7, + GlassDoor = 8, + BGBlindOn = 9 + }; + // Parameters to indicate exterior boundary conditions for use with // the Surface derived type (see below): // Note: Positive values correspond to an interzone adjacent surface @@ -239,23 +253,6 @@ namespace DataSurfaces { extern int const InConvWinLoc_WindowBelowThis; // this is a wall with window below it extern int const InConvWinLoc_LargePartOfExteriorWall; // this is a big window taking up most of wall - // Parameters for window shade status - extern int const NoShade; - extern int const ShadeOff; - extern int const IntShadeOn; // Interior shade on - extern int const SwitchableGlazing; - extern int const ExtShadeOn; // Exterior shade on - extern int const ExtScreenOn; // Exterior screen on - extern int const IntBlindOn; // Interior blind on - extern int const ExtBlindOn; // Exterior blind on - extern int const BGShadeOn; // Between-glass shade on - extern int const BGBlindOn; // Between-glass blind on - extern int const IntShadeConditionallyOff; - extern int const GlassConditionallyLightened; - extern int const ExtShadeConditionallyOff; - extern int const IntBlindConditionallyOff; - extern int const ExtBlindConditionallyOff; - // WindowShadingControl Shading Types extern int const WSC_ST_NoShade; extern int const WSC_ST_InteriorShade; @@ -518,13 +515,15 @@ namespace DataSurfaces { extern Array1D SurfWinProfileAngHor; // Horizontal beam solar profile angle (degrees) extern Array1D SurfWinProfileAngVert; // Vertical beam solar profile angle (degrees) - extern Array1D SurfWinShadingFlag; // -1: window has no shading device + extern Array1D SurfWinShadingFlag; // -1: window has no shading device + extern Array1D SurfWinShaded; // Window shading flag is not shadeoff or noshade extern Array1D SurfWinShadingFlagEMSOn; // EMS control flag, true if EMS is controlling ShadingFlag with ShadingFlagEMSValue extern Array1D SurfWinShadingFlagEMSValue; // EMS control value for Shading Flag + extern Array1D SurfWinGlareControlIsActive; // True if glare control is active extern Array1D SurfWinStormWinFlag; // -1: Storm window not applicable; 0: Window has storm window but it is off 1: Window has storm window and it is on extern Array1D SurfWinStormWinFlagPrevDay; // Previous time step value of StormWinFlag extern Array1D SurfWinFracTimeShadingDeviceOn; // For a single time step, = 0.0 if no shading device or shading device is off = 1.0 if shading device is on; For time intervals longer than a time step, = fraction of time that shading device is on. - extern Array1D SurfWinExtIntShadePrevTS; // 1 if exterior or interior blind or shade in place previous time step;0 otherwise + extern Array1D SurfWinExtIntShadePrevTS; // 1 if exterior or interior blind or shade in place previous time step;0 otherwise extern Array1D SurfWinHasShadeOrBlindLayer; // mark as true if the window construction has a shade or a blind layer extern Array1D SurfWinSurfDayLightInit; // surface has been initialized for following 5 arrays extern Array1D SurfWinDaylFacPoint; // Pointer to daylight factors for the window diff --git a/src/EnergyPlus/DaylightingManager.cc b/src/EnergyPlus/DaylightingManager.cc index 1a63e147379..92d7a816ef5 100644 --- a/src/EnergyPlus/DaylightingManager.cc +++ b/src/EnergyPlus/DaylightingManager.cc @@ -5652,7 +5652,7 @@ namespace EnergyPlus::DaylightingManager { IWin = state.dataDaylightingData->ZoneDaylight(ZoneNum).DayltgExtWinSurfNums(loop); IS = 1; if ((SurfWinWindowModelType(IWin) != WindowBSDFModel) && - ((SurfWinShadingFlag(IWin) >= 1 && SurfWinShadingFlag(IWin) <= 9) || SurfWinSolarDiffusing(IWin))) + ((SurfWinShaded(IWin) && !SurfWinGlareControlIsActive(IWin)) || SurfWinSolarDiffusing(IWin))) IS = 2; // Conversion from ft-L to cd/m2, with cd/m2 = 0.2936 ft-L, gives the 0.4794 factor // below, which is (0.2936)**0.6 @@ -5730,7 +5730,7 @@ namespace EnergyPlus::DaylightingManager { IWin = state.dataDaylightingData->ZoneDaylight(ZoneNum).DayltgExtWinSurfNums(loop); IS = 1; if ((SurfWinWindowModelType(IWin) != WindowBSDFModel) && - ((SurfWinShadingFlag(IWin) >= 1 && SurfWinShadingFlag(IWin) <= 9) || SurfWinSolarDiffusing(IWin))) + ((SurfWinShaded(IWin) && !SurfWinGlareControlIsActive(IWin)) || SurfWinSolarDiffusing(IWin))) IS = 2; // Conversion from ft-L to cd/m2, with cd/m2 = 0.2936 ft-L, gives the 0.4794 factor // below, which is (0.2936)**0.6 @@ -6339,7 +6339,7 @@ namespace EnergyPlus::DaylightingManager { state.dataDaylightingData->ZoneDaylight(ZoneNum).DaylSourceFacSunDisk(state.dataGlobal->PreviousHour, 1, IL, loop))); if ((SurfWinWindowModelType(IWin) != WindowBSDFModel) && - (SurfWinShadingFlag(IWin) >= 1 || SurfWinSolarDiffusing(IWin))) { + (SurfWinShaded(IWin) || SurfWinSolarDiffusing(IWin))) { // ===Shaded window or window with diffusing glass=== if (!SurfWinMovableSlats(IWin)) { @@ -6511,7 +6511,7 @@ namespace EnergyPlus::DaylightingManager { for (IS = 1; IS <= 2; ++IS) { if (IS == 2 && (SurfWinWindowModelType(IWin) == WindowBSDFModel)) break; - if (IS == 2 && SurfWinShadingFlag(IWin) <= 0 && !SurfWinSolarDiffusing(IWin)) break; + if (IS == 2 && !SurfWinShaded(IWin) && !SurfWinSolarDiffusing(IWin)) break; state.dataDaylightingData->ZoneDaylight(ZoneNum).IllumFromWinAtRefPt(loop, IS, IL) = DFSUHR(IS) * state.dataEnvrn->HISUNF + @@ -6552,7 +6552,7 @@ namespace EnergyPlus::DaylightingManager { ICtrl = Surface(IWin).activeWindowShadingControl; if (Surface(IWin).HasShadeControl && ISWFLG == 0) { if (WindowShadingControl(ICtrl).ShadingControlType == WSCT_MeetDaylIlumSetp && - SurfWinShadingFlag(IWin) == GlassConditionallyLightened) + SurfWinShadingFlag(IWin) == WinShadingFlag::SwitchableGlazing && SurfWinGlareControlIsActive(IWin)) ISWFLG = 1; } @@ -6563,7 +6563,7 @@ namespace EnergyPlus::DaylightingManager { // For other windows with glare control, the shading flag is initialized at >10, to be determined IS = 1; if ((SurfWinWindowModelType(IWin) != WindowBSDFModel) && - ((SurfWinShadingFlag(IWin) >= 1 && SurfWinShadingFlag(IWin) <= 9) || SurfWinSolarDiffusing(IWin))) + ((SurfWinShaded(IWin) && !SurfWinGlareControlIsActive(IWin)) || SurfWinSolarDiffusing(IWin))) IS = 2; for (IL = 1; IL <= NREFPT; ++IL) { @@ -6608,10 +6608,10 @@ namespace EnergyPlus::DaylightingManager { ICtrl = Surface(IWin).activeWindowShadingControl; IS = 1; if ((SurfWinWindowModelType(IWin) != WindowBSDFModel) && - ((SurfWinShadingFlag(IWin) >= 1 && SurfWinShadingFlag(IWin) <= 9) || SurfWinSolarDiffusing(IWin))) + ((SurfWinShaded(IWin) && !SurfWinGlareControlIsActive(IWin))|| SurfWinSolarDiffusing(IWin))) IS = 2; if (Surface(IWin).HasShadeControl) { - if (SurfWinShadingFlag(IWin) == GlassConditionallyLightened && + if (SurfWinShadingFlag(IWin) == WinShadingFlag::SwitchableGlazing && SurfWinGlareControlIsActive(IWin) && WindowShadingControl(ICtrl).ShadingControlType == WSCT_MeetDaylIlumSetp && !previously_shaded(loop)) { DILLSW(igroup) += state.dataDaylightingData->ZoneDaylight(ZoneNum).IllumFromWinAtRefPt(loop, IS, 1); previously_shaded(loop) = true; @@ -6656,7 +6656,7 @@ namespace EnergyPlus::DaylightingManager { continueOuterLoop = true; continue; } - if (SurfWinShadingFlag(IWin) != GlassConditionallyLightened || + if (!(SurfWinShadingFlag(IWin) == WinShadingFlag::SwitchableGlazing && SurfWinGlareControlIsActive(IWin)) || WindowShadingControl(ICtrl).ShadingControlType != WSCT_MeetDaylIlumSetp) { continueOuterLoop = true; continue; @@ -6672,7 +6672,7 @@ namespace EnergyPlus::DaylightingManager { TVIS2(igroup) = POLYF(1.0, state.dataConstruction->Construct(IConstShaded).TransVisBeamCoef) * SurfWinGlazedFrac(IWin); // Reset shading flag to indicate that window is shaded by being partially or fully switched - SurfWinShadingFlag(IWin) = SwitchableGlazing; + SurfWinShadingFlag(IWin) = WinShadingFlag::SwitchableGlazing; // ASETIL < 0 means illuminance from non-daylight-switchable windows exceeds setpoint, // so completely switch all daylight-switchable windows to minimize solar gain @@ -6701,7 +6701,7 @@ namespace EnergyPlus::DaylightingManager { state.dataDaylightingData->ZoneDaylight(ZoneNum).BacLum(IL) += (VTRAT - 1.0) * state.dataDaylightingData->ZoneDaylight(ZoneNum).BackLumFromWinAtRefPt(loop, IS, IL); // Adjust illum, background illum and source luminance for this window in intermediate switched state - // for later use in the DayltgGlare calc because SurfaceWindow(IWin)%ShadingFlag = SwitchableGlazing = 2 + // for later use in the DayltgGlare calc because SurfaceWindow(IWin)%ShadingFlag = WinShadingFlag::SwitchableGlazing = 2 IS = 2; VTRAT = SurfWinVisTransSelected(IWin) / (TVIS2(igroup) + 0.000001); state.dataDaylightingData->ZoneDaylight(ZoneNum).IllumFromWinAtRefPt(loop, IS, IL) = VTRAT * tmpIllumFromWinAtRefPt(loop, IS, IL); @@ -6773,7 +6773,7 @@ namespace EnergyPlus::DaylightingManager { // Check if window is eligible for glare control // TH 1/21/2010. Switchable glazings already in partially switched state // should be allowed to further dim to control glare - if (SurfWinShadingFlag(IWin) < 10 && SurfWinShadingFlag(IWin) != SwitchableGlazing) { + if (!SurfWinGlareControlIsActive(IWin) && SurfWinShadingFlag(IWin) != WinShadingFlag::SwitchableGlazing) { continueOuterLoop = false; continue; } @@ -6798,9 +6798,9 @@ namespace EnergyPlus::DaylightingManager { // Recalculate illuminance and glare with shading on this window. // For switchable glazings, this is the fully switched (dark) state for (IL = 1; IL <= NREFPT; ++IL) { - if (SurfWinShadingFlag(IWin) != SwitchableGlazing) { + if (SurfWinShadingFlag(IWin) != WinShadingFlag::SwitchableGlazing) { // for non switchable glazings or switchable glazings not switched yet (still in clear state) - // SurfaceWindow(IWin)%ShadingFlag = GlassConditionallyLightened + // SurfaceWindow(IWin)%ShadingFlag = WinShadingFlag::GlassConditionallyLightened RDAYIL(IL, igroup) = state.dataDaylightingManager->DaylIllum(IL) - WDAYIL(1, IL, igroup) + WDAYIL(2, IL, igroup); RBACLU(IL, igroup) = state.dataDaylightingData->ZoneDaylight(ZoneNum).BacLum(IL) - WBACLU(1, IL, igroup) + WBACLU(2, IL, igroup); } else { @@ -6810,11 +6810,11 @@ namespace EnergyPlus::DaylightingManager { } } - if (SurfWinShadingFlag(IWin) != SwitchableGlazing) SurfWinShadingFlag(IWin) /= 10; + if (SurfWinShadingFlag(IWin) != WinShadingFlag::SwitchableGlazing) SurfWinGlareControlIsActive = false; // For switchable glazings, it is switched to fully dark state, // update ZoneDaylight(ZoneNum)%SourceLumFromWinAtRefPt(IL,2,loop) for use in DayltgGlare - if (SurfWinShadingFlag(IWin) == SwitchableGlazing) { + if (SurfWinShadingFlag(IWin) == WinShadingFlag::SwitchableGlazing) { for (IL = 1; IL <= NREFPT; ++IL) { state.dataDaylightingData->ZoneDaylight(ZoneNum).SourceLumFromWinAtRefPt(loop, 2, IL) = tmpSourceLumFromWinAtRefPt(loop, 2, IL); state.dataDaylightingData->ZoneDaylight(ZoneNum).IllumFromWinAtRefPt(loop, 2, IL) = tmpIllumFromWinAtRefPt(loop, 2, IL); @@ -6884,7 +6884,7 @@ namespace EnergyPlus::DaylightingManager { ++count; // need to map back to the original order of the "loop" to not change all the other data structures loop = state.dataDaylightingData->ZoneDaylight(ZoneNum).MapShdOrdToLoopNum(count); - if (SurfWinShadingFlag(IWin) < 10 && SurfWinShadingFlag(IWin) != SwitchableGlazing) continue; + if (!SurfWinGlareControlIsActive(IWin) && SurfWinShadingFlag(IWin) != WinShadingFlag::SwitchableGlazing) continue; ICtrl = Surface(IWin).activeWindowShadingControl; if (!Surface(IWin).HasShadeControl) continue; @@ -6894,7 +6894,7 @@ namespace EnergyPlus::DaylightingManager { // Reset shading flag to no shading condition, go to next window. if (blnCycle) { // for switchable glazings, reset properties to clear state or partial switched state? - if (SurfWinShadingFlag(IWin) == SwitchableGlazing) { + if (SurfWinShadingFlag(IWin) == WinShadingFlag::SwitchableGlazing) { SurfWinSwitchingFactor(IWin) = 0.0; SurfWinVisTransSelected(IWin) = TVIS1(igroup); @@ -6906,7 +6906,7 @@ namespace EnergyPlus::DaylightingManager { } } - SurfWinShadingFlag(IWin) = ShadeOff; + SurfWinShadingFlag(IWin) = WinShadingFlag::ShadeOff; continue; } @@ -6927,7 +6927,7 @@ namespace EnergyPlus::DaylightingManager { // This was addressed in CR 7984 for E+ 5.0. 1/19/2010 // If switchable glazing, set switching factor to 1: fully switched. - if (SurfWinShadingFlag(IWin) == SwitchableGlazing) { + if (SurfWinShadingFlag(IWin) == WinShadingFlag::SwitchableGlazing) { // tmpSWFactor0 = SurfaceWindow( IWin ).SwitchingFactor; // save original // switching factor ////Unused Set but never used @@ -6954,7 +6954,7 @@ namespace EnergyPlus::DaylightingManager { } if (GlareOK) { - if (SurfWinShadingFlag(IWin) == SwitchableGlazing && + if (SurfWinShadingFlag(IWin) == WinShadingFlag::SwitchableGlazing && WindowShadingControl(ICtrl).ShadingControlType == WSCT_MeetDaylIlumSetp) { // Added TH 1/14/2010 // Only for switchable glazings with MeetDaylightIlluminanceSetpoint control @@ -7066,7 +7066,7 @@ namespace EnergyPlus::DaylightingManager { for (IWin = Zone(ZoneNum).SurfaceFirst; IWin <= Zone(ZoneNum).SurfaceLast; ++IWin) { if (Surface(IWin).Class != SurfaceClass::Window) continue; if (Surface(IWin).ExtBoundCond != ExternalEnvironment) continue; - if (SurfWinShadingFlag(IWin) >= 10) SurfWinShadingFlag(IWin) = ShadeOff; + if (SurfWinGlareControlIsActive(IWin)) SurfWinShadingFlag(IWin) = WinShadingFlag::ShadeOff; } // Variables for reporting @@ -7094,7 +7094,7 @@ namespace EnergyPlus::DaylightingManager { for (loop = 1; loop <= state.dataDaylightingData->ZoneDaylight(ZoneNum).NumOfDayltgExtWins; ++loop) { IWin = state.dataDaylightingData->ZoneDaylight(ZoneNum).DayltgExtWinSurfNums(loop); IS = 1; - if (SurfWinShadingFlag(IWin) > 0 || SurfWinSolarDiffusing(IWin)) IS = 2; + if (SurfWinShaded(IWin) || SurfWinSolarDiffusing(IWin)) IS = 2; if (state.dataDaylightingData->ZoneDaylight(ZoneNum).DaylightMethod == DataDaylighting::iDaylightingMethod::SplitFluxDaylighting) { int refPtCount = 0; for (int const enclZoneNum : DataViewFactorInformation::ZoneSolarInfo(Zone(ZoneNum).SolarEnclosureNum).ZoneNums) { @@ -9536,7 +9536,7 @@ namespace EnergyPlus::DaylightingManager { } if ((SurfWinWindowModelType(IWin) != WindowBSDFModel) && - (SurfWinShadingFlag(IWin) >= 1 || SurfWinSolarDiffusing(IWin))) { + (SurfWinShaded(IWin) || SurfWinSolarDiffusing(IWin))) { // ===Shaded window=== if (!SurfWinMovableSlats(IWin)) { @@ -9717,7 +9717,7 @@ namespace EnergyPlus::DaylightingManager { HorIllSkyFac = state.dataEnvrn->HISKF / ((1.0 - SkyWeight) * HorIllSky(ISky2) + SkyWeight * HorIllSky(ISky1)); for (IS = 1; IS <= 2; ++IS) { - if (IS == 2 && SurfWinShadingFlag(IWin) <= 0 && !SurfWinSolarDiffusing(IWin)) break; + if (IS == 2 && !SurfWinShaded(IWin) && !SurfWinSolarDiffusing(IWin)) break; state.dataDaylightingData->IllumMapCalc(MapNum).IllumFromWinAtMapPt(loop, IS, ILB) = DFSUHR(IS) * state.dataEnvrn->HISUNF + HorIllSkyFac * (DFSKHR(IS, ISky1) * SkyWeight * HorIllSky(ISky1) + @@ -9746,7 +9746,7 @@ namespace EnergyPlus::DaylightingManager { IS = 1; if ((SurfWinWindowModelType(IWin) != WindowBSDFModel) && - ((SurfWinShadingFlag(IWin) >= 1 && SurfWinShadingFlag(IWin) <= 9) || SurfWinSolarDiffusing(IWin))) + ((SurfWinShaded(IWin) && !SurfWinGlareControlIsActive(IWin)) || SurfWinSolarDiffusing(IWin))) IS = 2; // CR 8057. 3/17/2010. @@ -9756,7 +9756,7 @@ namespace EnergyPlus::DaylightingManager { ICtrl = Surface(IWin).activeWindowShadingControl; if (Surface(IWin).HasShadeControl) { if (WindowShadingControl(ICtrl).ShadingControlType == WSCT_MeetDaylIlumSetp && - SurfWinShadingFlag(IWin) == SwitchableGlazing) { + SurfWinShadingFlag(IWin) == WinShadingFlag::SwitchableGlazing) { // switchable windows in partial or fully switched state, // get its intermediate VT calculated in DayltgInteriorIllum IConstShaded = Surface(IWin).activeShadedConstruction; @@ -9784,7 +9784,7 @@ namespace EnergyPlus::DaylightingManager { IWin = state.dataDaylightingData->ZoneDaylight(ZoneNum).DayltgExtWinSurfNums(loop); IS = 1; if ((SurfWinWindowModelType(IWin) != WindowBSDFModel) && - ((SurfWinShadingFlag(IWin) >= 1 && SurfWinShadingFlag(IWin) <= 9) || SurfWinSolarDiffusing(IWin))) + ((SurfWinShaded(IWin) && !SurfWinGlareControlIsActive(IWin)) || SurfWinSolarDiffusing(IWin))) IS = 2; // CR 8057. 3/17/2010 @@ -9793,7 +9793,7 @@ namespace EnergyPlus::DaylightingManager { ICtrl = Surface(IWin).activeWindowShadingControl; if (Surface(IWin).HasShadeControl) { if (WindowShadingControl(ICtrl).ShadingControlType == WSCT_MeetDaylIlumSetp && - SurfWinShadingFlag(IWin) == SwitchableGlazing) { + SurfWinShadingFlag(IWin) == WinShadingFlag::SwitchableGlazing) { // switchable windows in partial or fully switched state, // get its intermediate VT calculated in DayltgInteriorIllum IConstShaded = Surface(IWin).activeShadedConstruction; diff --git a/src/EnergyPlus/ElectricBaseboardRadiator.cc b/src/EnergyPlus/ElectricBaseboardRadiator.cc index 7b266f42ab9..1f2819fe4ce 100644 --- a/src/EnergyPlus/ElectricBaseboardRadiator.cc +++ b/src/EnergyPlus/ElectricBaseboardRadiator.cc @@ -1154,7 +1154,7 @@ namespace ElectricBaseboardRadiator { Area = Surface(SurfNum).Area; if (Surface(SurfNum).Class == SurfaceClass::Window) { - if (SurfWinShadingFlag(SurfNum) == IntShadeOn || SurfWinShadingFlag(SurfNum) == IntBlindOn) { + if (SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntShadeOn || SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntBlindOn) { // The area is the shade or blind area = the sum of the glazing area and the divider area (which is zero if no divider) Area += SurfWinDividerArea(SurfNum); } @@ -1165,8 +1165,8 @@ namespace ElectricBaseboardRadiator { SurfWinFrameTempSurfIn(SurfNum); } - if (SurfWinDividerArea(SurfNum) > 0.0 && SurfWinShadingFlag(SurfNum) != IntShadeOn && - SurfWinShadingFlag(SurfNum) != IntBlindOn) { + if (SurfWinDividerArea(SurfNum) > 0.0 && SurfWinShadingFlag(SurfNum) != WinShadingFlag::IntShadeOn && + SurfWinShadingFlag(SurfNum) != WinShadingFlag::IntBlindOn) { // Window divider contribution (only from shade or blind for window with divider and interior shade or blind) SumHATsurf += HConvIn(SurfNum) * SurfWinDividerArea(SurfNum) * (1.0 + 2.0 * SurfWinProjCorrDivIn(SurfNum)) * SurfWinDividerTempSurfIn(SurfNum); diff --git a/src/EnergyPlus/HWBaseboardRadiator.cc b/src/EnergyPlus/HWBaseboardRadiator.cc index 808e707350d..a687bb907f5 100644 --- a/src/EnergyPlus/HWBaseboardRadiator.cc +++ b/src/EnergyPlus/HWBaseboardRadiator.cc @@ -1742,7 +1742,7 @@ namespace HWBaseboardRadiator { Area = Surface(SurfNum).Area; if (Surface(SurfNum).Class == SurfaceClass::Window) { - if (SurfWinShadingFlag(SurfNum) == IntShadeOn || SurfWinShadingFlag(SurfNum) == IntBlindOn) { + if (SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntShadeOn || SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntBlindOn) { // The area is the shade or blind area = the sum of the glazing area and the divider area (which is zero if no divider) Area += SurfWinDividerArea(SurfNum); } @@ -1753,8 +1753,8 @@ namespace HWBaseboardRadiator { SurfWinFrameTempSurfIn(SurfNum); } - if (SurfWinDividerArea(SurfNum) > 0.0 && SurfWinShadingFlag(SurfNum) != IntShadeOn && - SurfWinShadingFlag(SurfNum) != IntBlindOn) { + if (SurfWinDividerArea(SurfNum) > 0.0 && SurfWinShadingFlag(SurfNum) != WinShadingFlag::IntShadeOn && + SurfWinShadingFlag(SurfNum) != WinShadingFlag::IntBlindOn) { // Window divider contribution (only from shade or blind for window with divider and interior shade or blind) SumHATsurf += HConvIn(SurfNum) * SurfWinDividerArea(SurfNum) * (1.0 + 2.0 * SurfWinProjCorrDivIn(SurfNum)) * SurfWinDividerTempSurfIn(SurfNum); diff --git a/src/EnergyPlus/HeatBalanceIntRadExchange.cc b/src/EnergyPlus/HeatBalanceIntRadExchange.cc index 6d31b779f64..684cc5b56a5 100644 --- a/src/EnergyPlus/HeatBalanceIntRadExchange.cc +++ b/src/EnergyPlus/HeatBalanceIntRadExchange.cc @@ -172,8 +172,8 @@ namespace HeatBalanceIntRadExchange { bool IntShadeOrBlindStatusChanged; // True if status of interior shade or blind on at least // one window in a zone has changed from previous time step - int ShadeFlag; // Window shading status current time step - int ShadeFlagPrev; // Window shading status previous time step + WinShadingFlag ShadeFlag; // Window shading status current time step + WinShadingFlag ShadeFlagPrev; // Window shading status previous time step // variables added as part of strategy to reduce calculation time - Glazer 2011-04-22 static Array1D SurfaceTempRad; @@ -272,9 +272,9 @@ namespace HeatBalanceIntRadExchange { if (state.dataConstruction->Construct(Surface(SurfNum).Construction).TypeIsWindow) { ShadeFlag = SurfWinShadingFlag(SurfNum); ShadeFlagPrev = SurfWinExtIntShadePrevTS(SurfNum); - if ((ShadeFlagPrev != IntShadeOn && ShadeFlag == IntShadeOn) || - (ShadeFlagPrev != IntBlindOn && ShadeFlag == IntBlindOn) || - (ShadeFlagPrev == IntShadeOn && ShadeFlag != IntShadeOn) || (ShadeFlagPrev == IntBlindOn && ShadeFlag != IntBlindOn)) + if ((ShadeFlagPrev != WinShadingFlag::IntShadeOn && ShadeFlag == WinShadingFlag::IntShadeOn) || + (ShadeFlagPrev != WinShadingFlag::IntBlindOn && ShadeFlag == WinShadingFlag::IntBlindOn) || + (ShadeFlagPrev == WinShadingFlag::IntShadeOn && ShadeFlag != WinShadingFlag::IntShadeOn) || (ShadeFlagPrev == WinShadingFlag::IntBlindOn && ShadeFlag != WinShadingFlag::IntBlindOn)) IntShadeOrBlindStatusChanged = true; if (SurfWinWindowModelType(SurfNum) == WindowEQLModel && DataWindowEquivalentLayer::CFS(state.dataConstruction->Construct(Surface(SurfNum).Construction).EQLConsPtr).ISControlled) { @@ -293,7 +293,7 @@ namespace HeatBalanceIntRadExchange { zone_info.Emissivity(ZoneSurfNum) = state.dataConstruction->Construct(ConstrNum).InsideAbsorpThermal; auto const &surface_window(SurfaceWindow(SurfNum)); if (state.dataConstruction->Construct(ConstrNum).TypeIsWindow && - (SurfWinShadingFlag(SurfNum) == IntShadeOn || SurfWinShadingFlag(SurfNum) == IntBlindOn)) { + (SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntShadeOn || SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntBlindOn)) { zone_info.Emissivity(ZoneSurfNum) = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), surface_window.EffShBlindEmiss) + InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), surface_window.EffGlassEmiss); @@ -332,14 +332,14 @@ namespace HeatBalanceIntRadExchange { if (construct.WindowTypeEQL) { SurfaceTempRad[ZoneSurfNum] = SurfWinEffInsSurfTemp(SurfNum); SurfaceEmiss[ZoneSurfNum] = EQLWindowInsideEffectiveEmiss(state, ConstrNum); - } else if (construct.WindowTypeBSDF && SurfWinShadingFlag(SurfNum) == IntShadeOn) { + } else if (construct.WindowTypeBSDF && SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntShadeOn) { SurfaceTempRad[ZoneSurfNum] = SurfWinEffInsSurfTemp(SurfNum); SurfaceEmiss[ZoneSurfNum] = surface_window.EffShBlindEmiss[0] + surface_window.EffGlassEmiss[0]; } else if (construct.WindowTypeBSDF) { SurfaceTempRad[ZoneSurfNum] = SurfWinEffInsSurfTemp(SurfNum); SurfaceEmiss[ZoneSurfNum] = construct.InsideAbsorpThermal; } else if (construct.TypeIsWindow && SurfWinOriginalClass(SurfNum) != SurfaceClass::TDD_Diffuser) { - if (SurfIterations == 0 && SurfWinShadingFlag(SurfNum) <= 0) { + if (SurfIterations == 0 && (SurfWinShadingFlag(SurfNum) == WinShadingFlag::NoShade || SurfWinShadingFlag(SurfNum) == WinShadingFlag::ShadeOff)) { // If the window is bare this TS and it is the first time through we use the previous TS glass // temperature whether or not the window was shaded in the previous TS. If the window was shaded // the previous time step this temperature is a better starting value than the shade temperature. @@ -347,7 +347,7 @@ namespace HeatBalanceIntRadExchange { SurfaceEmiss[ZoneSurfNum] = construct.InsideAbsorpThermal; // For windows with an interior shade or blind an effective inside surface temp // and emiss is used here that is a weighted combination of shade/blind and glass temp and emiss. - } else if (SurfWinShadingFlag(SurfNum) == IntShadeOn || SurfWinShadingFlag(SurfNum) == IntBlindOn) { + } else if (SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntShadeOn || SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntBlindOn) { SurfaceTempRad[ZoneSurfNum] = SurfWinEffInsSurfTemp(SurfNum); SurfaceEmiss[ZoneSurfNum] = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), surface_window.EffShBlindEmiss) + InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), surface_window.EffGlassEmiss); diff --git a/src/EnergyPlus/HeatBalanceSurfaceManager.cc b/src/EnergyPlus/HeatBalanceSurfaceManager.cc index fc1d89717c9..0a4508bcd4f 100644 --- a/src/EnergyPlus/HeatBalanceSurfaceManager.cc +++ b/src/EnergyPlus/HeatBalanceSurfaceManager.cc @@ -689,7 +689,7 @@ namespace HeatBalanceSurfaceManager { if (firstSurfWin == -1) continue; for (int SurfNum = firstSurfWin; SurfNum <= lastSurfWin; ++SurfNum) { SurfWinFracTimeShadingDeviceOn(SurfNum) = 0.0; - if (SurfWinShadingFlag(SurfNum) > 0) { + if (SurfWinShaded(SurfNum)) { SurfWinFracTimeShadingDeviceOn(SurfNum) = 1.0; } else { SurfWinFracTimeShadingDeviceOn(SurfNum) = 0.0; @@ -2216,8 +2216,8 @@ namespace HeatBalanceSurfaceManager { SurfWinDividerTempSurfOut(SurfNum) = 23.0; // Initialize previous-timestep shading indicators - SurfWinExtIntShadePrevTS(SurfNum) = 0; - SurfWinShadingFlag(SurfNum) = NoShade; + SurfWinExtIntShadePrevTS(SurfNum) = WinShadingFlag::NoShade; + SurfWinShadingFlag(SurfNum) = WinShadingFlag::NoShade; } // end of Zone Surf } } // end of Zone @@ -2909,7 +2909,7 @@ namespace HeatBalanceSurfaceManager { Real64 SkySolarInc = currSkySolarInc(SurfNum); // Sky diffuse solar incident on a surface Real64 GndSolarInc = currGndSolarInc(SurfNum); // Ground diffuse solar incident on a surface - int ShadeFlag = SurfWinShadingFlag(SurfNum); + WinShadingFlag ShadeFlag = SurfWinShadingFlag(SurfNum); if (SurfWinWindowModelType(SurfNum) != WindowBSDFModel && SurfWinWindowModelType(SurfNum) != WindowEQLModel && @@ -2919,13 +2919,13 @@ namespace HeatBalanceSurfaceManager { AbsDiffWin(Lay) = state.dataConstruction->Construct(ConstrNum).AbsDiff(Lay); } - if (ShadeFlag > 0) { // Shaded window + if (SurfWinShaded(SurfNum)) { // Shaded window int ConstrNumSh = Surface(SurfNum).activeShadedConstruction; // Shaded window construction if (SurfWinStormWinFlag(SurfNum) == 1) ConstrNumSh = Surface(SurfNum).activeStormWinShadedConstruction; - if (ShadeFlag == IntShadeOn || ShadeFlag == ExtShadeOn || ShadeFlag == BGShadeOn || - ShadeFlag == ExtScreenOn) { // Shade/screen on + if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::BGShadeOn || + ShadeFlag == WinShadingFlag::ExtScreenOn) { // Shade/screen on for (int Lay = 1; Lay <= TotGlassLay; ++Lay) { AbsDiffWin(Lay) = state.dataConstruction->Construct(ConstrNumSh).AbsDiff(Lay); } @@ -2935,8 +2935,8 @@ namespace HeatBalanceSurfaceManager { } - if (ShadeFlag == IntBlindOn || ShadeFlag == ExtBlindOn || - ShadeFlag == BGBlindOn) { // Blind on + if (ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn || + ShadeFlag == WinShadingFlag::BGBlindOn) { // Blind on for (int Lay = 1; Lay <= TotGlassLay; ++Lay) { AbsDiffWin(Lay) = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), @@ -2976,11 +2976,11 @@ namespace HeatBalanceSurfaceManager { // Correct for shadowing of divider onto interior shading device (note that dividers are // not allowed in windows with between-glass shade/blind) - if ((ShadeFlag == IntShadeOn || ShadeFlag == IntBlindOn) && + if ((ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn) && SurfWinDividerArea(SurfNum) > 0.0) SurfWinExtDiffAbsByShade(SurfNum) *= SurfWinGlazedFrac(SurfNum); - if (ShadeFlag == SwitchableGlazing) { // Switchable glazing + if (ShadeFlag == WinShadingFlag::SwitchableGlazing) { // Switchable glazing Real64 SwitchFac = SurfWinSwitchingFactor( SurfNum); // Switching factor for switchable glazing for (int Lay = 1; Lay <= TotGlassLay; ++Lay) { @@ -2997,8 +2997,8 @@ namespace HeatBalanceSurfaceManager { SurfWinQRadSWwinAbs(Lay, SurfNum) = AbsDiffWin(Lay) * (SkySolarInc + GndSolarInc) + SurfWinA(Lay, SurfNum) * BeamSolar; // SurfWinA is from InteriorSolarDistribution - if (ShadeFlag == IntBlindOn || ShadeFlag == ExtBlindOn || - ShadeFlag == BGBlindOn) { + if (ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn || + ShadeFlag == WinShadingFlag::BGBlindOn) { int ConstrNumSh = Surface(SurfNum).activeShadedConstruction; if (Blind(SurfWinBlindNumber(SurfNum)).SlatOrientation == Horizontal) { // AbsDiffGlassLayGnd - System glass layer ground diffuse solar absorptance with blind on @@ -3202,7 +3202,7 @@ namespace HeatBalanceSurfaceManager { Real64 TransGl = POLYF(CosInc, state.dataConstruction->Construct( ConstrNum).TransSolBeamCoef); TransDiffGl = state.dataConstruction->Construct(ConstrNum).TransDiff; - if (ShadeFlag == SwitchableGlazing) { // Switchable glazing + if (ShadeFlag == WinShadingFlag::SwitchableGlazing) { // Switchable glazing Real64 SwitchFac = SurfWinSwitchingFactor(SurfNum); int ConstrNumSh = Surface(SurfNum).activeShadedConstruction; Real64 TransGlSh = POLYF(CosInc, state.dataConstruction->Construct( @@ -3256,7 +3256,7 @@ namespace HeatBalanceSurfaceManager { Real64 AbsGl = 1.0 - TransGl - ReflGl; Real64 SwitchFac = SurfWinSwitchingFactor(SurfNum); int ConstrNumSh = Surface(SurfNum).activeShadedConstruction; - if (ShadeFlag == SwitchableGlazing) { // Switchable glazing + if (ShadeFlag == WinShadingFlag::SwitchableGlazing) { // Switchable glazing Real64 MatNumGlSh = state.dataConstruction->Construct( ConstrNumSh).LayerPoint(1); Real64 TransGlSh = dataMaterial.Material(MatNumGlSh).Trans; @@ -3276,8 +3276,8 @@ namespace HeatBalanceSurfaceManager { Real64 BeamDivHorFaceInc = 0.0; // Beam solar on divider's horizontal outside projection faces (W/m2) Real64 BeamDivVertFaceInc = 0.0; // Beam solar on divider's vertical outside projection faces (W/m2) // Beam incident on horizontal and vertical projection faces of divider if no exterior shading - if (DivProjOut > 0.0 && ShadeFlag != ExtShadeOn && - ShadeFlag != ExtBlindOn && ShadeFlag != ExtScreenOn) { + if (DivProjOut > 0.0 && ShadeFlag != WinShadingFlag::ExtShadeOn && + ShadeFlag != WinShadingFlag::ExtBlindOn && ShadeFlag != WinShadingFlag::ExtScreenOn) { BeamDivHorFaceInc = state.dataEnvrn->BeamSolarRad * CosIncAngHorProj * FrameDivider(FrDivNum).HorDividers * DivProjOut * (Surface(SurfNum).Width - @@ -3293,9 +3293,9 @@ namespace HeatBalanceSurfaceManager { Real64 DivIncSolarOutDif = 0.0; // Diffuse solar incident on outside of divider including diffuse on divider projection (W/m2) Real64 DivIncSolarInBm = 0.0; // Diffuse solar incident on inside of divider including beam on divider projection (W/m2) Real64 DivIncSolarInDif = 0.0; // Diffuse solar incident on inside of divider including diffuse on divider projection (W/m2) - if (ShadeFlag != ExtShadeOn && ShadeFlag != ExtBlindOn && - ShadeFlag != BGShadeOn && ShadeFlag != BGBlindOn && - ShadeFlag != ExtScreenOn) { // No exterior or between-glass shading + if (ShadeFlag != WinShadingFlag::ExtShadeOn && ShadeFlag != WinShadingFlag::ExtBlindOn && + ShadeFlag != WinShadingFlag::BGShadeOn && ShadeFlag != WinShadingFlag::BGBlindOn && + ShadeFlag != WinShadingFlag::ExtScreenOn) { // No exterior or between-glass shading DivIncSolarOutBm = BeamFaceInc + BeamDivHorFaceInc + BeamDivVertFaceInc; DivIncSolarOutDif = DifSolarFaceInc * (1.0 + SurfWinProjCorrDivOut(SurfNum)); @@ -3304,7 +3304,7 @@ namespace HeatBalanceSurfaceManager { ConstrNum).TransSolBeamCoef); Real64 TransDiffGl = state.dataConstruction->Construct( ConstrNum).TransDiff; // Diffuse solar transmittance - if (ShadeFlag == SwitchableGlazing) { // Switchable glazing + if (ShadeFlag == WinShadingFlag::SwitchableGlazing) { // Switchable glazing Real64 SwitchFac = SurfWinSwitchingFactor(SurfNum); int ConstrNumSh = Surface(SurfNum).activeShadedConstruction; Real64 TransGlSh = POLYF(CosInc, state.dataConstruction->Construct( @@ -3348,15 +3348,15 @@ namespace HeatBalanceSurfaceManager { DivIncSolarInDif = DifSolarFaceInc * SurfWinProjCorrDivIn(SurfNum) * state.dataConstruction->Construct(ConstrNum).TransDiff; } - if (ShadeFlag != ExtShadeOn && ShadeFlag != ExtBlindOn && - ShadeFlag != ExtScreenOn && ShadeFlag != BGShadeOn && ShadeFlag != BGBlindOn) { + if (ShadeFlag != WinShadingFlag::ExtShadeOn && ShadeFlag != WinShadingFlag::ExtBlindOn && + ShadeFlag != WinShadingFlag::ExtScreenOn && ShadeFlag != WinShadingFlag::BGShadeOn && ShadeFlag != WinShadingFlag::BGBlindOn) { // No exterior or between-glass shade, screen or blind SurfWinDividerQRadOutAbs(SurfNum) = DividerAbs * (DivIncSolarOutBm + DivIncSolarOutDif); SurfWinDividerQRadInAbs(SurfNum) = DividerAbs * (DivIncSolarInBm + DivIncSolarInDif); // Exterior shade, screen or blind - } else if (ShadeFlag == ExtBlindOn) { // Exterior blind + } else if (ShadeFlag == WinShadingFlag::ExtBlindOn) { // Exterior blind int BlNum = SurfWinBlindNumber(SurfNum); Real64 ProfAng; // Solar profile angle (rad) ProfileAngle(SurfNum, state.dataEnvrn->SOLCOS, Blind(BlNum).SlatOrientation, ProfAng); @@ -3379,7 +3379,7 @@ namespace HeatBalanceSurfaceManager { DivIncSolarInDif * InterpSlatAng(SlatAng, SurfWinMovableSlats(SurfNum), Blind(BlNum).SolFrontDiffDiffTrans)); - } else if (ShadeFlag == ExtShadeOn) { // Exterior shade + } else if (ShadeFlag == WinShadingFlag::ExtShadeOn) { // Exterior shade int ConstrNumSh = Surface(SurfNum).activeShadedConstruction; SurfWinDividerQRadOutAbs(SurfNum) = DividerAbs * dataMaterial.Material(state.dataConstruction->Construct(ConstrNumSh).LayerPoint(1)).Trans * @@ -3388,7 +3388,7 @@ namespace HeatBalanceSurfaceManager { DividerAbs * dataMaterial.Material(state.dataConstruction->Construct(ConstrNumSh).LayerPoint(1)).Trans * (DivIncSolarInBm +DivIncSolarInDif); - } else if (ShadeFlag == ExtScreenOn) { // Exterior screen + } else if (ShadeFlag == WinShadingFlag::ExtScreenOn) { // Exterior screen SurfWinDividerQRadOutAbs(SurfNum) = DividerAbs * (SurfaceScreens( SurfWinScreenNumber(SurfNum)).BmBmTrans + SurfaceScreens( SurfWinScreenNumber(SurfNum)).BmDifTrans) * @@ -3605,7 +3605,7 @@ namespace HeatBalanceSurfaceManager { ConstrNumSh = Surface(SurfNum).activeStormWinShadedConstruction; } int TotGlassLayers = state.dataConstruction->Construct(ConstrNum).TotGlassLayers; - int ShadeFlag = SurfWinShadingFlag(SurfNum); + WinShadingFlag ShadeFlag = SurfWinShadingFlag(SurfNum); // These calculations are repeated from InitInternalHeatGains for the Zone Component Loads Report Real64 pulseMultipler = 0.01; // use to create a pulse for the load component report computations, the W/sqft pulse for the zone @@ -3623,49 +3623,49 @@ namespace HeatBalanceSurfaceManager { SurfQRadThermInAbs(SurfNum) = adjQL * TMULT(radEnclosureNum) * ITABSF(SurfNum); } - if (ShadeFlag <= 0) { // No window shading + if (!SurfWinShaded(SurfNum)) { // No window shading for (int IGlass = 1; IGlass <= TotGlassLayers; ++IGlass) { SurfWinQRadSWwinAbs(IGlass, SurfNum) += QS(solEnclosureNum) * state.dataConstruction->Construct(ConstrNum).AbsDiffBack(IGlass); } - } else if (ConstrNumSh != 0 && (ShadeFlag == IntShadeOn || ShadeFlag >= 3)) { + } else if (ConstrNumSh != 0 && ShadeFlag != WinShadingFlag::SwitchableGlazing) { // Interior, exterior or between-glass shade, screen or blind in place for (int IGlass = 1; IGlass <= state.dataConstruction->Construct(ConstrNumSh).TotGlassLayers; ++IGlass) { - if (ShadeFlag == IntShadeOn || ShadeFlag == ExtShadeOn || ShadeFlag == BGShadeOn || - ShadeFlag == ExtScreenOn) + if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::BGShadeOn || + ShadeFlag == WinShadingFlag::ExtScreenOn) SurfWinQRadSWwinAbs(IGlass, SurfNum) += QS(solEnclosureNum) * state.dataConstruction->Construct(ConstrNumSh).AbsDiffBack( IGlass); - if (ShadeFlag == IntBlindOn || ShadeFlag == ExtBlindOn) { + if (ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn) { Real64 BlAbsDiffBk = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), state.dataConstruction->Construct(ConstrNumSh).BlAbsDiffBack(_, IGlass)); // Glass layer back diffuse solar absorptance when blind in place SurfWinQRadSWwinAbs(IGlass, SurfNum) += QS(solEnclosureNum) * BlAbsDiffBk; } } - if (ShadeFlag == IntShadeOn) + if (ShadeFlag == WinShadingFlag::IntShadeOn) SurfWinIntLWAbsByShade(SurfNum) = QL(radEnclosureNum) * state.dataConstruction->Construct(ConstrNumSh).ShadeAbsorpThermal * TMULT(radEnclosureNum); - if (ShadeFlag == IntBlindOn) { + if (ShadeFlag == WinShadingFlag::IntBlindOn) { Real64 EffBlEmiss = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), SurfaceWindow(SurfNum).EffShBlindEmiss); // Blind emissivity (thermal absorptance) as part of glazing system SurfWinIntLWAbsByShade(SurfNum) = QL(radEnclosureNum) * EffBlEmiss * TMULT(radEnclosureNum); } - if (ShadeFlag == IntShadeOn || ShadeFlag == ExtShadeOn || ShadeFlag == BGShadeOn || - ShadeFlag == ExtScreenOn) + if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::BGShadeOn || + ShadeFlag == WinShadingFlag::ExtScreenOn) SurfWinIntSWAbsByShade(SurfNum) = QS(solEnclosureNum) * state.dataConstruction->Construct(ConstrNumSh).AbsDiffBackShade; - if (ShadeFlag == IntBlindOn || ShadeFlag == ExtBlindOn || ShadeFlag == BGBlindOn) { + if (ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::BGBlindOn) { Real64 AbsDiffBkBl = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), state.dataConstruction->Construct(ConstrNumSh).AbsDiffBackBlind); // Blind diffuse back solar absorptance as part of glazing system SurfWinIntSWAbsByShade(SurfNum) = QS(solEnclosureNum) * AbsDiffBkBl; } // Correct for divider shadowing - if (ShadeFlag == ExtShadeOn || ShadeFlag == ExtBlindOn || ShadeFlag == ExtScreenOn) + if (ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::ExtScreenOn) SurfWinIntSWAbsByShade(SurfNum) *= SurfWinGlazedFrac(SurfNum); - } else if (ShadeFlag == SwitchableGlazing) { // Switchable glazing + } else if (ShadeFlag == WinShadingFlag::SwitchableGlazing) { // Switchable glazing for (int IGlass = 1; IGlass <= TotGlassLayers; ++IGlass) { SurfWinQRadSWwinAbs(IGlass, SurfNum) += QS(solEnclosureNum) * @@ -3701,12 +3701,12 @@ namespace HeatBalanceSurfaceManager { DividerThermAbs = dataMaterial.Material(MatNumGl).AbsorpThermalBack; } // Correct for interior shade transmittance - if (ShadeFlag == IntShadeOn) { + if (ShadeFlag == WinShadingFlag::IntShadeOn) { int MatNumSh = state.dataConstruction->Construct(ConstrNumSh).LayerPoint( state.dataConstruction->Construct(ConstrNumSh).TotLayers); // Shade layer material number DividerSolAbs *= dataMaterial.Material(MatNumSh).Trans; DividerThermAbs *= dataMaterial.Material(MatNumSh).TransThermal; - } else if (ShadeFlag == IntBlindOn) { + } else if (ShadeFlag == WinShadingFlag::IntBlindOn) { int BlNum = SurfWinBlindNumber(SurfNum); DividerSolAbs *= InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), Blind(BlNum).SolBackDiffDiffTrans); @@ -3783,26 +3783,26 @@ namespace HeatBalanceSurfaceManager { ConstrNumSh = Surface(SurfNum).activeStormWinShadedConstruction; } int TotGlassLayers = state.dataConstruction->Construct(ConstrNum).TotGlassLayers; - int ShadeFlag = SurfWinShadingFlag(SurfNum); - if (ShadeFlag <= 0) { // No window shading + WinShadingFlag ShadeFlag = SurfWinShadingFlag(SurfNum); + if (!SurfWinShaded(SurfNum)) { // No window shading for (int IGlass = 1; IGlass <= TotGlassLayers; ++IGlass) { SurfWinQRadSWwinAbs(IGlass, SurfNum) += SurfWinInitialDifSolwinAbs(IGlass, SurfNum); } - } else if (ShadeFlag == IntShadeOn || ShadeFlag >= 3) { + } else if (ShadeFlag == WinShadingFlag::SwitchableGlazing) { // Switchable glazing + for (int IGlass = 1; IGlass <= TotGlassLayers; ++IGlass) { + SurfWinQRadSWwinAbs(IGlass, SurfNum) += SurfWinInitialDifSolwinAbs(IGlass, SurfNum); + } + } else { // Interior, exterior or between-glass shade, screen or blind in place for (int IGlass = 1; IGlass <= state.dataConstruction->Construct(ConstrNumSh).TotGlassLayers; ++IGlass) { SurfWinQRadSWwinAbs(IGlass, SurfNum) += SurfWinInitialDifSolwinAbs(IGlass, SurfNum); } - if (ShadeFlag == IntShadeOn || ShadeFlag == ExtShadeOn || ShadeFlag == BGShadeOn || - ShadeFlag == ExtScreenOn) + if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::BGShadeOn || + ShadeFlag == WinShadingFlag::ExtScreenOn) SurfWinIntSWAbsByShade(SurfNum) += SurfWinInitialDifSolAbsByShade(SurfNum); - if (ShadeFlag == IntBlindOn || ShadeFlag == ExtBlindOn || ShadeFlag == BGBlindOn) { + if (ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::BGBlindOn) { SurfWinIntSWAbsByShade(SurfNum) += SurfWinInitialDifSolAbsByShade(SurfNum); } - } else if (ShadeFlag == SwitchableGlazing) { // Switchable glazing - for (int IGlass = 1; IGlass <= TotGlassLayers; ++IGlass) { - SurfWinQRadSWwinAbs(IGlass, SurfNum) += SurfWinInitialDifSolwinAbs(IGlass, SurfNum); - } } // End of shading flag check } else if (SurfWinWindowModelType(SurfNum) == WindowBSDFModel) { int TotGlassLayers = state.dataConstruction->Construct(ConstrNum).TotGlassLayers; @@ -3837,8 +3837,8 @@ namespace HeatBalanceSurfaceManager { } else { TotGlassLayers = state.dataConstruction->Construct(ConstrNum).TotGlassLayers; } - int ShadeFlag = SurfWinShadingFlag(SurfNum); - if (ShadeFlag <= 0 || SurfWinWindowModelType(SurfNum) == WindowBSDFModel) { // No window shading + WinShadingFlag ShadeFlag = SurfWinShadingFlag(SurfNum); + if (!SurfWinShaded(SurfNum) || SurfWinWindowModelType(SurfNum) == WindowBSDFModel) { // No window shading for (int IGlass = 1; IGlass <= TotGlassLayers; ++IGlass) { // Initial Transmitted Diffuse Solar Absorbed on Inside of Surface[W] SurfInitialDifSolInAbsReport(SurfNum) += @@ -3848,9 +3848,8 @@ namespace HeatBalanceSurfaceManager { // Total Shortwave Absorbed:All Glass Layers[W] SurfWinSWwinAbsTotalReport(SurfNum) += SurfWinQRadSWwinAbs(IGlass, SurfNum) * Surface(SurfNum).Area; } - } else if (ShadeFlag == IntShadeOn || ShadeFlag >= 3) { - // Interior, exterior or between-glass shade, screen or blind in place - for (int IGlass = 1; IGlass <= state.dataConstruction->Construct(ConstrNumSh).TotGlassLayers; ++IGlass) { + } else if (ShadeFlag == WinShadingFlag::SwitchableGlazing) { // Switchable glazing + for (int IGlass = 1; IGlass <= TotGlassLayers; ++IGlass) { // Initial Transmitted Diffuse Solar Absorbed on Inside of Surface[W] SurfInitialDifSolInAbsReport(SurfNum) += SurfWinInitialDifSolwinAbs(IGlass, SurfNum) * Surface(SurfNum).Area; @@ -3859,8 +3858,9 @@ namespace HeatBalanceSurfaceManager { // Total Shortwave Absorbed:All Glass Layers[W] SurfWinSWwinAbsTotalReport(SurfNum) += SurfWinQRadSWwinAbs(IGlass, SurfNum) * Surface(SurfNum).Area; } - } else if (ShadeFlag == SwitchableGlazing) { // Switchable glazing - for (int IGlass = 1; IGlass <= TotGlassLayers; ++IGlass) { + } else { + // Interior, exterior or between-glass shade, screen or blind in place + for (int IGlass = 1; IGlass <= state.dataConstruction->Construct(ConstrNumSh).TotGlassLayers; ++IGlass) { // Initial Transmitted Diffuse Solar Absorbed on Inside of Surface[W] SurfInitialDifSolInAbsReport(SurfNum) += SurfWinInitialDifSolwinAbs(IGlass, SurfNum) * Surface(SurfNum).Area; @@ -3940,8 +3940,8 @@ namespace HeatBalanceSurfaceManager { if (firstSurfWin == -1) continue; for (int SurfNum = firstSurfWin; SurfNum <= lastSurfWin; ++SurfNum) { // For window with an interior shade or blind, emissivity is a combination of glass and shade/blind emissivity - int ShadeFlag = SurfWinShadingFlag(SurfNum); - if (ShadeFlag == IntShadeOn || ShadeFlag == IntBlindOn) + WinShadingFlag ShadeFlag = SurfWinShadingFlag(SurfNum); + if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn) ITABSF(SurfNum) = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), SurfaceWindow(SurfNum).EffShBlindEmiss) + InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), @@ -3959,8 +3959,8 @@ namespace HeatBalanceSurfaceManager { if (!Surface(SurfNum).HeatTransSurf) continue; int ConstrNum = Surface(SurfNum).Construction; - int ShadeFlag = SurfWinShadingFlag(SurfNum); - if (ShadeFlag != SwitchableGlazing) { + WinShadingFlag ShadeFlag = SurfWinShadingFlag(SurfNum); + if (ShadeFlag != WinShadingFlag::SwitchableGlazing) { SUM1 += Surface(SurfNum).Area * ITABSF(SurfNum); } else { // Switchable glazing SUM1 += Surface(SurfNum).Area * InterpSw(SurfWinSwitchingFactor(SurfNum), @@ -3975,7 +3975,7 @@ namespace HeatBalanceSurfaceManager { Real64 DividerThermAbs = SurfWinDividerEmis(SurfNum); // Window divider thermal absorptance // Suspended (between-glass) divider; relevant emissivity is inner glass emissivity if (SurfWinDividerType(SurfNum) == Suspended) DividerThermAbs = state.dataConstruction->Construct(ConstrNum).InsideAbsorpThermal; - if (ShadeFlag == IntShadeOn || ShadeFlag == IntBlindOn) { + if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn) { // Interior shade or blind in place int ConstrNumSh = Surface(SurfNum).activeShadedConstruction; if (SurfWinHasShadeOrBlindLayer(SurfNum)) { @@ -3985,7 +3985,7 @@ namespace HeatBalanceSurfaceManager { Real64 TauShIR = dataMaterial.Material(MatNumSh).TransThermal; // Effective emissivity of shade or blind Real64 EffShDevEmiss = SurfaceWindow(SurfNum).EffShBlindEmiss(1); - if (ShadeFlag == IntBlindOn) { + if (ShadeFlag == WinShadingFlag::IntBlindOn) { TauShIR = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), Blind(SurfWinBlindNumber(SurfNum)).IRBackTrans); @@ -4078,7 +4078,7 @@ namespace HeatBalanceSurfaceManager { // Window if (!state.dataConstruction->Construct(Surface(SurfNum).Construction).WindowTypeEQL) { - int ShadeFlag = SurfWinShadingFlag(SurfNum); + WinShadingFlag ShadeFlag = SurfWinShadingFlag(SurfNum); Real64 AbsDiffTotWin = 0.0; // Sum of window layer short-wave absorptances int ConstrNumSh = Surface(SurfNum).activeShadedConstruction; if (SurfWinStormWinFlag(SurfNum) == 1) { @@ -4093,9 +4093,9 @@ namespace HeatBalanceSurfaceManager { // Window with shade, screen or blind if (ConstrNumSh != 0) { - if (ShadeFlag == IntShadeOn || ShadeFlag == ExtShadeOn || ShadeFlag == BGShadeOn || ShadeFlag == ExtScreenOn) { + if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::BGShadeOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { AbsDiffLayWin = state.dataConstruction->Construct(ConstrNumSh).AbsDiffBack(Lay); - } else if (ShadeFlag == IntBlindOn || ShadeFlag == ExtBlindOn || ShadeFlag == BGBlindOn) { + } else if (ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::BGBlindOn) { AbsDiffLayWin = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), state.dataConstruction->Construct(ConstrNumSh).BlAbsDiffBack(_, Lay)); @@ -4103,7 +4103,7 @@ namespace HeatBalanceSurfaceManager { } // Switchable glazing - if (ShadeFlag == SwitchableGlazing) + if (ShadeFlag == WinShadingFlag::SwitchableGlazing) AbsDiffLayWin = InterpSw(SwitchFac, AbsDiffLayWin, state.dataConstruction->Construct(ConstrNumSh).AbsDiffBack(Lay)); AbsDiffTotWin += AbsDiffLayWin; @@ -4115,10 +4115,10 @@ namespace HeatBalanceSurfaceManager { // Window with shade, screen or blind if (ConstrNumSh != 0) { - if (ShadeFlag == IntShadeOn || ShadeFlag == ExtShadeOn || ShadeFlag == BGShadeOn || ShadeFlag == ExtScreenOn) { + if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::BGShadeOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { TransDiffWin = state.dataConstruction->Construct(ConstrNumSh).TransDiff; DiffAbsShade = state.dataConstruction->Construct(ConstrNumSh).AbsDiffBackShade; - } else if (ShadeFlag == IntBlindOn || ShadeFlag == ExtBlindOn || ShadeFlag == BGBlindOn) { + } else if (ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::BGBlindOn) { TransDiffWin = InterpSlatAng( SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), state.dataConstruction->Construct(ConstrNumSh).BlTransDiff); DiffAbsShade = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), @@ -4129,7 +4129,7 @@ namespace HeatBalanceSurfaceManager { // Switchable glazing - if (ShadeFlag == SwitchableGlazing) + if (ShadeFlag == WinShadingFlag::SwitchableGlazing) TransDiffWin = InterpSw(SwitchFac, TransDiffWin, state.dataConstruction->Construct(ConstrNumSh).TransDiff); SUM1 += Surface(SurfNum).Area * (TransDiffWin + AbsDiffTotWin + DiffAbsShade); @@ -4150,7 +4150,7 @@ namespace HeatBalanceSurfaceManager { Real64 DividerRefl = 1.0 - DividerAbs; // Window divider short-wave reflectance DividerAbs = AbsGl + TransGl * (DividerAbs + DividerRefl * AbsGl) / (1.0 - DividerRefl * ReflGl); } - if (ShadeFlag == IntShadeOn || ShadeFlag == IntBlindOn) { + if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn) { SUM1 += SurfWinDividerArea(SurfNum) * (DividerAbs + DiffAbsShade); } else { SUM1 += SurfWinDividerArea(SurfNum) * (1.0 + SurfWinProjCorrDivIn(SurfNum)) * DividerAbs; @@ -6833,7 +6833,7 @@ namespace HeatBalanceSurfaceManager { int RoughSurf = dataMaterial.Material(construct.LayerPoint(1)).Roughness; // Outside surface roughness Real64 EmisOut = dataMaterial.Material(construct.LayerPoint(1)).AbsorpThermalFront; // Glass outside surface emissivity auto const shading_flag(SurfWinShadingFlag(SurfNum)); - if (shading_flag == ExtShadeOn || shading_flag == ExtBlindOn || shading_flag == ExtScreenOn) { + if (shading_flag == WinShadingFlag::ExtShadeOn || shading_flag == WinShadingFlag::ExtBlindOn || shading_flag == WinShadingFlag::ExtScreenOn) { // Exterior shade in place int ConstrNumSh = Surface(SurfNum).activeShadedConstruction; if (ConstrNumSh != 0) { @@ -7543,7 +7543,7 @@ namespace HeatBalanceSurfaceManager { Real64 EmisOut = dataMaterial.Material(construct.LayerPoint(1)).AbsorpThermalFront; // Glass outside surface emissivity auto const shading_flag(SurfWinShadingFlag(surfNum)); - if (shading_flag == ExtShadeOn || shading_flag == ExtBlindOn || shading_flag == ExtScreenOn) { + if (shading_flag == WinShadingFlag::ExtShadeOn || shading_flag == WinShadingFlag::ExtBlindOn || shading_flag == WinShadingFlag::ExtScreenOn) { // Exterior shade in place int ConstrNumSh = Surface(surfNum).activeShadedConstruction; if (ConstrNumSh != 0) { diff --git a/src/EnergyPlus/HighTempRadiantSystem.cc b/src/EnergyPlus/HighTempRadiantSystem.cc index e468c668b6f..a81904d4105 100644 --- a/src/EnergyPlus/HighTempRadiantSystem.cc +++ b/src/EnergyPlus/HighTempRadiantSystem.cc @@ -1511,7 +1511,7 @@ namespace HighTempRadiantSystem { Area = Surface(SurfNum).Area; if (Surface(SurfNum).Class == SurfaceClass::Window) { - if (SurfWinShadingFlag(SurfNum) == IntShadeOn || SurfWinShadingFlag(SurfNum) == IntBlindOn) { + if (SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntShadeOn || SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntBlindOn) { // The area is the shade or blind area = the sum of the glazing area and the divider area (which is zero if no divider) Area += SurfWinDividerArea(SurfNum); } @@ -1522,8 +1522,8 @@ namespace HighTempRadiantSystem { SurfWinFrameTempSurfIn(SurfNum); } - if (SurfWinDividerArea(SurfNum) > 0.0 && SurfWinShadingFlag(SurfNum) != IntShadeOn && - SurfWinShadingFlag(SurfNum) != IntBlindOn) { + if (SurfWinDividerArea(SurfNum) > 0.0 && SurfWinShadingFlag(SurfNum) != WinShadingFlag::IntShadeOn && + SurfWinShadingFlag(SurfNum) != WinShadingFlag::IntBlindOn) { // Window divider contribution (only from shade or blind for window with divider and interior shade or blind) SumHATsurf += HConvIn(SurfNum) * SurfWinDividerArea(SurfNum) * (1.0 + 2.0 * SurfWinProjCorrDivIn(SurfNum)) * SurfWinDividerTempSurfIn(SurfNum); diff --git a/src/EnergyPlus/LowTempRadiantSystem.cc b/src/EnergyPlus/LowTempRadiantSystem.cc index aecc562ca05..96ebb7c8345 100644 --- a/src/EnergyPlus/LowTempRadiantSystem.cc +++ b/src/EnergyPlus/LowTempRadiantSystem.cc @@ -5577,7 +5577,7 @@ namespace LowTempRadiantSystem { Real64 Area = Surface(surfNum).Area; if (Surface(surfNum).Class == SurfaceClass::Window) { - if (SurfWinShadingFlag(surfNum) == IntShadeOn || SurfWinShadingFlag(surfNum) == IntBlindOn) { + if (SurfWinShadingFlag(surfNum) == WinShadingFlag::IntShadeOn || SurfWinShadingFlag(surfNum) == WinShadingFlag::IntBlindOn) { // The area is the shade or blind are = sum of the glazing area and the divider area (which is zero if no divider) Area += SurfWinDividerArea(surfNum); } @@ -5588,8 +5588,8 @@ namespace LowTempRadiantSystem { SurfWinFrameTempSurfIn(surfNum); } - if (SurfWinDividerArea(surfNum) > 0.0 && SurfWinShadingFlag(surfNum) != IntShadeOn && - SurfWinShadingFlag(surfNum) != IntBlindOn) { + if (SurfWinDividerArea(surfNum) > 0.0 && SurfWinShadingFlag(surfNum) != WinShadingFlag::IntShadeOn && + SurfWinShadingFlag(surfNum) != WinShadingFlag::IntBlindOn) { // Window divider contribution (only from shade or blind for window with divider and interior shade or blind) sumHATsurf += HConvIn(surfNum) * SurfWinDividerArea(surfNum) * (1.0 + 2.0 * SurfWinProjCorrDivIn(surfNum)) * SurfWinDividerTempSurfIn(surfNum); diff --git a/src/EnergyPlus/RoomAirModelAirflowNetwork.cc b/src/EnergyPlus/RoomAirModelAirflowNetwork.cc index ffd748b7bcc..78886647d42 100644 --- a/src/EnergyPlus/RoomAirModelAirflowNetwork.cc +++ b/src/EnergyPlus/RoomAirModelAirflowNetwork.cc @@ -1059,14 +1059,14 @@ namespace RoomAirModelAirflowNetwork { if (Surface(SurfNum).Class == DataSurfaces::SurfaceClass::Window) { // Add to the convective internal gains - if (SurfWinShadingFlag(SurfNum) == IntShadeOn || SurfWinShadingFlag(SurfNum) == IntBlindOn) { + if (SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntShadeOn || SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntBlindOn) { // The shade area covers the area of the glazing plus the area of the dividers. Area += SurfWinDividerArea(SurfNum); SumIntGain += SurfWinDividerHeatGain(SurfNum); } // Convective heat gain from natural convection in gap between glass and interior shade or blind - if (SurfWinShadingFlag(SurfNum) == IntShadeOn || SurfWinShadingFlag(SurfNum) == IntBlindOn) + if (SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntShadeOn || SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntBlindOn) SumIntGain += SurfWinConvHeatFlowNatural(SurfNum); // Convective heat gain from airflow window @@ -1096,8 +1096,8 @@ namespace RoomAirModelAirflowNetwork { HA += HConvIn(SurfNum) * SurfWinFrameArea(SurfNum) * (1.0 + SurfWinProjCorrFrIn(SurfNum)); } - if (SurfWinDividerArea(SurfNum) > 0.0 && SurfWinShadingFlag(SurfNum) != IntShadeOn && - SurfWinShadingFlag(SurfNum) != IntBlindOn) { + if (SurfWinDividerArea(SurfNum) > 0.0 && SurfWinShadingFlag(SurfNum) != WinShadingFlag::IntShadeOn && + SurfWinShadingFlag(SurfNum) != WinShadingFlag::IntBlindOn) { // Window divider contribution(only from shade or blind for window with divider and interior shade or blind) SumHATsurf += HConvIn(SurfNum) * SurfWinDividerArea(SurfNum) * (1.0 + 2.0 * SurfWinProjCorrDivIn(SurfNum)) * SurfWinDividerTempSurfIn(SurfNum); diff --git a/src/EnergyPlus/SolarShading.cc b/src/EnergyPlus/SolarShading.cc index f1f13028b08..1cb71fea6fd 100644 --- a/src/EnergyPlus/SolarShading.cc +++ b/src/EnergyPlus/SolarShading.cc @@ -1350,7 +1350,7 @@ namespace SolarShading { // CurrentModuleObject='Switchable Windows' if (Surface(SurfLoop).HasShadeControl) { if (WindowShadingControl(Surface(SurfLoop).activeWindowShadingControl).ShadingType == WSC_ST_SwitchableGlazing) { - // IF (SurfaceWindow(SurfLoop)%ShadingFlag == SwitchableGlazing) THEN !ShadingFlag is not set to SwitchableGlazing yet! + // IF (SurfaceWindow(SurfLoop)%ShadingFlag == WinShadingFlag::SwitchableGlazing) THEN !ShadingFlag is not set to WinShadingFlag::SwitchableGlazing yet! SetupOutputVariable(state, "Surface Window Switchable Glazing Switching Factor", OutputProcessor::Unit::None, SurfWinSwitchingFactor(SurfLoop), @@ -6068,7 +6068,7 @@ namespace SolarShading { } int BlNum = SurfWinBlindNumber(SurfNum); int ScNum = SurfWinScreenNumber(SurfNum); - int ShadeFlag = SurfWinShadingFlag(SurfNum); // Set in subr. WindowShadingManager + WinShadingFlag ShadeFlag = SurfWinShadingFlag(SurfNum); // Set in subr. WindowShadingManager Real64 ProfAng = 0.0; // Window solar profile angle (radians) @@ -6107,7 +6107,7 @@ namespace SolarShading { AbWin(Lay) = POLYF(CosInc, state.dataConstruction->Construct(ConstrNum).AbsBeamCoef({1, 6}, Lay)) * CosInc * SunLitFract * SurfaceWindow(SurfNum).OutProjSLFracMult(state.dataGlobal->HourOfDay); } - if (ShadeFlag <= 0 || ShadeFlag >= 10) { + if (!SurfWinShaded(SurfNum) || SurfWinGlareControlIsActive(SurfNum)) { // Bare window (ShadeFlag = -1 or 0 or shading device of off) for (int Lay = 1; Lay <= NGlass; ++Lay) { // Add contribution of beam reflected from outside and inside reveal @@ -6120,30 +6120,30 @@ namespace SolarShading { Real64 InOutProjSLFracMult = SurfaceWindow(SurfNum).InOutProjSLFracMult(state.dataGlobal->HourOfDay); Array1D AbWinSh(NGlass); // Like AbWin, but for shaded window Array1D ADiffWinSh(NGlass); // Diffuse solar absorptance of glass layer, window with shading device - if (ShadeFlag == ExtShadeOn || ShadeFlag == ExtBlindOn || ShadeFlag == ExtScreenOn) FracSunLit = SunLitFract; + if (ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::ExtScreenOn) FracSunLit = SunLitFract; - if (ShadeFlag == IntShadeOn || ShadeFlag == ExtShadeOn || ShadeFlag == BGShadeOn || ShadeFlag == SwitchableGlazing) { + if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::BGShadeOn || ShadeFlag == WinShadingFlag::SwitchableGlazing) { // Shade or switchable glazing on for (int Lay = 1; Lay <= NGlass; ++Lay) { AbWinSh(Lay) = POLYF(CosInc, state.dataConstruction->Construct(ConstrNumSh).AbsBeamCoef({1, 6}, Lay)) * CosInc * FracSunLit; ADiffWinSh(Lay) = state.dataConstruction->Construct(ConstrNumSh).AbsDiff(Lay); } - if (ShadeFlag == IntShadeOn) { // Exterior beam absorbed by INTERIOR SHADE + if (ShadeFlag == WinShadingFlag::IntShadeOn) { // Exterior beam absorbed by INTERIOR SHADE // Note that AbsBeamShadeCoef includes effect of shade/glazing inter-reflection Real64 AbsShade = POLYF(CosInc, state.dataConstruction->Construct(ConstrNumSh).AbsBeamShadeCoef); // Interior shade or blind beam solar absorptance ExtBeamAbsByShadFac(SurfNum) = (AbsShade * CosInc * SunLitFract * InOutProjSLFracMult + SurfWinOutsRevealDiffOntoGlazing(SurfNum) * state.dataConstruction->Construct(ConstrNumSh).AbsDiffShade) * SurfWinGlazedFrac(SurfNum); // In the above, GlazedFrac corrects for shadowing of divider onto interior shade - } else if (ShadeFlag == ExtShadeOn) { // Exterior beam absorbed by EXTERIOR SHADE + } else if (ShadeFlag == WinShadingFlag::ExtShadeOn) { // Exterior beam absorbed by EXTERIOR SHADE ExtBeamAbsByShadFac(SurfNum) = state.dataConstruction->Construct(ConstrNumSh).AbsDiffShade * CosInc * SunLitFract; - } else if (ShadeFlag == BGShadeOn) { // Exterior beam absorbed by BETWEEN-GLASS SHADE + } else if (ShadeFlag == WinShadingFlag::BGShadeOn) { // Exterior beam absorbed by BETWEEN-GLASS SHADE Real64 AbsShade = POLYF(CosInc, state.dataConstruction->Construct(ConstrNumSh).AbsBeamShadeCoef); ExtBeamAbsByShadFac(SurfNum) = AbsShade * CosInc * SunLitFract + SurfWinOutsRevealDiffOntoGlazing(SurfNum) * state.dataConstruction->Construct(ConstrNumSh).AbsDiffShade; } } else { // Blind or screen on - if (ShadeFlag != ExtScreenOn) ProfileAngle(SurfNum, state.dataEnvrn->SOLCOS, Blind(BlNum).SlatOrientation, ProfAng); - if (ShadeFlag == IntBlindOn) { + if (ShadeFlag != WinShadingFlag::ExtScreenOn) ProfileAngle(SurfNum, state.dataEnvrn->SOLCOS, Blind(BlNum).SlatOrientation, ProfAng); + if (ShadeFlag == WinShadingFlag::IntBlindOn) { // Interior blind on Real64 TGlBm = POLYF(CosInc,state.dataConstruction->Construct(ConstrNum).TransSolBeamCoef); // Glazing system front solar beam transmittance Real64 RGlDiffBack = state.dataConstruction->Construct(ConstrNum).ReflectSolDiffBack; // Glazing system back diffuse solar reflectance @@ -6167,7 +6167,7 @@ namespace SolarShading { SurfWinOutsRevealDiffOntoGlazing(SurfNum) * AbsShadeDiff) * SurfWinGlazedFrac(SurfNum); // In the above, GlazedFrac corrects for shadowing of divider onto interior blind - } else if (ShadeFlag == ExtBlindOn) { + } else if (ShadeFlag == WinShadingFlag::ExtBlindOn) { // Exterior blind on Real64 TBlBmBm = BlindBeamBeamTrans(ProfAng, SlatAng, Blind(BlNum).SlatWidth, Blind(BlNum).SlatSeparation, Blind(BlNum).SlatThickness); // Blind solar front beam-beam transmittance Real64 TBlDifDif = InterpSlatAng(SlatAng, VarSlats, Blind(BlNum).SolFrontDiffDiffTrans); // Diffuse-diffuse solar transmittance of blind @@ -6192,7 +6192,7 @@ namespace SolarShading { Real64 AbsBlDiffBack = InterpSlatAng(SlatAng, VarSlats, Blind(BlNum).SolBackDiffAbs); // Blind solar back diffuse absorptance Real64 AbsShade = AbsBlFront + AbsBlBack * RGlFront * TBlBmBm + (AbsBlDiffBack * RGlDiffFront / (1.0 - RhoBlDiffBack * RGlDiffFront)) * (RGlFront * TBlBmBm * RhoBlBack + TBlBmDiff); ExtBeamAbsByShadFac(SurfNum) = AbsShade * CosInc * SunLitFract * InOutProjSLFracMult; - } else if (ShadeFlag == ExtScreenOn) { + } else if (ShadeFlag == WinShadingFlag::ExtScreenOn) { // Exterior screen on Real64 TScBmBm = SurfaceScreens(ScNum).BmBmTrans; // Screen solar front beam-beam transmittance Real64 TScBmDiff = SurfaceScreens(ScNum).BmDifTrans; // Screen solar front beam-diffuse transmittance @@ -6214,7 +6214,7 @@ namespace SolarShading { Real64 AbsScDiffBack = SurfaceScreens(ScNum).DifScreenAbsorp; // Screen solar back diffuse absorptance Real64 AbsScreen = AbsScBeam * (1.0 + TScBmBm * RGlFront) + (AbsScDiffBack * TScBmBm * RGlFront * RGlDiffFront * RScBack / (1.0 - RScDifBack * RGlDiffFront)); // Exterior screen beam solar absorptance ExtBeamAbsByShadFac(SurfNum) = AbsScreen * CosInc * SunLitFract * InOutProjSLFracMult; - } else if (ShadeFlag == BGBlindOn) { + } else if (ShadeFlag == WinShadingFlag::BGBlindOn) { // Between-glass blind o // Isolated glass and blind properties at current incidence angle, profile angle and slat angle Real64 t1 = POLYF(CosInc, state.dataConstruction->Construct(ConstrNum).tBareSolCoef({1, 6}, 1)); // Bare-glass beam solar transmittance for glass layers 1,2 and 3 @@ -6277,12 +6277,12 @@ namespace SolarShading { } // End of check if blind is interior, exterior or between-glass } // End of check if a blind is on - if (ShadeFlag != SwitchableGlazing) { + if (ShadeFlag != WinShadingFlag::SwitchableGlazing) { // Interior or between glass shade or blind on for (int Lay = 1; Lay <= NGlass; ++Lay) { SurfWinA(Lay, SurfNum) = AbWinSh(Lay); // Add contribution of diffuse from beam on outside reveal - if (ShadeFlag == IntShadeOn || ShadeFlag == IntBlindOn || ShadeFlag == BGShadeOn || ShadeFlag == BGBlindOn) + if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::BGShadeOn || ShadeFlag == WinShadingFlag::BGBlindOn) SurfWinA(Lay, SurfNum) += ADiffWinSh(Lay) * SurfWinOutsRevealDiffOntoGlazing(SurfNum); } } else { @@ -6398,10 +6398,10 @@ namespace SolarShading { } if (SurfWinWindowModelType(SurfNum) != WindowBSDFModel && SurfWinWindowModelType(SurfNum) != WindowEQLModel) { - if (ShadeFlag > 0 && ShadeFlag < 10) { - if (ShadeFlag != SwitchableGlazing) { + if (SurfWinShaded(SurfNum) && !SurfWinGlareControlIsActive(SurfNum)) { + if (ShadeFlag != WinShadingFlag::SwitchableGlazing) { // Shade or blind - if (ShadeFlag == IntShadeOn || ShadeFlag == ExtShadeOn || ShadeFlag == BGShadeOn || ShadeFlag == ExtScreenOn) { + if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::BGShadeOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { // Shade or screen DiffTrans = state.dataConstruction->Construct(ConstrNumSh).TransDiff; } else { @@ -6487,10 +6487,10 @@ namespace SolarShading { } else { DiffTrans = state.dataConstruction->Construct(ConstrNum).TransDiff; } - if (ShadeFlag > 0 && ShadeFlag < 10) { - if (ShadeFlag != SwitchableGlazing) { + if (SurfWinShaded(SurfNum) && !SurfWinGlareControlIsActive(SurfNum)) { + if (ShadeFlag != WinShadingFlag::SwitchableGlazing) { // Shade or blind - if (ShadeFlag == IntShadeOn || ShadeFlag == ExtShadeOn || ShadeFlag == BGShadeOn || ShadeFlag == ExtScreenOn) { + if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::BGShadeOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { // Shade or screen DiffTrans = state.dataConstruction->Construct(ConstrNumSh).TransDiff; } else { @@ -6544,10 +6544,10 @@ namespace SolarShading { if (SurfWinWindowModelType(SurfNum) != WindowEQLModel) { SurfWinBlGlSysTsolDifDif(SurfNum) = DiffTrans; SurfWinScGlSysTsolDifDif(SurfNum) = DiffTrans; - if (ShadeFlag == IntBlindOn || ShadeFlag == ExtBlindOn || ShadeFlag == BGBlindOn || ShadeFlag == ExtScreenOn) { + if (ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::BGBlindOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { SurfWinBlGlSysTsolDifDif(SurfNum) = DiffTrans; SurfWinScGlSysTsolDifDif(SurfNum) = DiffTrans; - if (ShadeFlag == ExtScreenOn) { + if (ShadeFlag == WinShadingFlag::ExtScreenOn) { SurfWinScTsolDifDif(SurfNum) = SurfaceScreens(ScNum).DifDifTrans; } else { SurfWinBlTsolDifDif(SurfNum) = InterpSlatAng(SlatAng, VarSlats, Blind(BlNum).SolFrontDiffDiffTrans); @@ -6560,10 +6560,10 @@ namespace SolarShading { //----------------------------------------------------------------- if (ConstrNumSh != 0 && SunLitFract > 0.0) { if (SurfWinWindowModelType(SurfNum) != WindowEQLModel) { - if (ShadeFlag > 0 && ShadeFlag < 10) { + if (SurfWinShaded(SurfNum) && !SurfWinGlareControlIsActive(SurfNum)) { // Shade or screen or blind on, or switchable glazing // (note in the following that diffusing glass is not allowed in a window with shade, blind or switchable glazing) - if (ShadeFlag != IntBlindOn && ShadeFlag != ExtBlindOn && ShadeFlag != BGBlindOn && ShadeFlag != ExtScreenOn) { + if (ShadeFlag != WinShadingFlag::IntBlindOn && ShadeFlag != WinShadingFlag::ExtBlindOn && ShadeFlag != WinShadingFlag::BGBlindOn && ShadeFlag != WinShadingFlag::ExtScreenOn) { // Shade on or switchable glazing TBmAllShBlSc = POLYF(CosInc, state.dataConstruction->Construct(ConstrNumSh).TransSolBeamCoef); } else { @@ -6573,7 +6573,7 @@ namespace SolarShading { Real64 TBlDifDif; // Diffuse-diffuse solar transmittance of blind Real64 TScBmBm; Real64 TBlBmBm; - if (ShadeFlag == ExtScreenOn) {// Exterior screen + if (ShadeFlag == WinShadingFlag::ExtScreenOn) {// Exterior screen Real64 RScBack = SurfaceScreens(ScNum).ReflectSolBeamFront; Real64 RScDifDifBk = SurfaceScreens(ScNum).DifReflect; // Diffuse-diffuse back refectance of screen Real64 RGlBmFr = POLYF(CosInc, state.dataConstruction->Construct(ConstrNum).ReflSolBeamFrontCoef); // Beam front reflectance of glass @@ -6593,7 +6593,7 @@ namespace SolarShading { } else { TBlBmBm = BlindBeamBeamTrans(ProfAng, SlatAng, Blind(BlNum).SlatWidth, Blind(BlNum).SlatSeparation, Blind(BlNum).SlatThickness); TBlBmDif = InterpProfSlatAng(ProfAng, SlatAng, VarSlats, Blind(BlNum).SolFrontBeamDiffTrans); - if (ShadeFlag == IntBlindOn) { + if (ShadeFlag == WinShadingFlag::IntBlindOn) { Real64 RhoBlBmDifFr = InterpProfSlatAng(ProfAng, SlatAng, VarSlats, Blind(BlNum).SolFrontBeamDiffRefl); // Beam-diffuse front reflectance of blind Real64 RGlDifBk = state.dataConstruction->Construct(ConstrNum).ReflectSolDiffBack; // Diffuse front reflectance of glass Real64 RhoBlDifDifFr = InterpSlatAng(SlatAng, VarSlats, Blind(BlNum).SolFrontDiffDiffRefl); // Diffuse-diffuse front refectance of blind @@ -6604,7 +6604,7 @@ namespace SolarShading { TBmBmShBlSc = TBmBmBl; // TBmBm * TBlBmBm TBmDifShBlSc = TBmAllShBlSc - TBmBmShBlSc; if (TBmDifShBlSc < 0.0) TBmDifShBlSc = 0.0; - } else if (ShadeFlag == ExtBlindOn) { + } else if (ShadeFlag == WinShadingFlag::ExtBlindOn) { Real64 RhoBlBmDifBk = InterpProfSlatAng(ProfAng, SlatAng, VarSlats, Blind(BlNum).SolBackBeamDiffRefl); // Beam-diffuse back reflectance of blind Real64 RhoBlDifDifBk = InterpSlatAng(SlatAng, VarSlats, Blind(BlNum).SolBackDiffDiffRefl); // Diffuse-diffuse back refectance of blind Real64 RGlBmFr = POLYF(CosInc, state.dataConstruction->Construct(ConstrNum).ReflSolBeamFrontCoef); @@ -6658,7 +6658,7 @@ namespace SolarShading { } // end of checking if sunlitfract > 0 // TODO: Why this is updated after reporting - if (ShadeFlag == SwitchableGlazing) { + if (ShadeFlag == WinShadingFlag::SwitchableGlazing) { // Switchable glazing Real64 SwitchFac = SurfWinSwitchingFactor(SurfNum); if (!SurfWinSolarDiffusing(SurfNum)) { @@ -6688,7 +6688,7 @@ namespace SolarShading { Real64 InOutProjSLFracMult = SurfaceWindow(SurfNum).InOutProjSLFracMult(state.dataGlobal->HourOfDay); if (SurfWinWindowModelType(SurfNum) != WindowEQLModel) { WinTransDifSolar(SurfNum) = DiffTrans * Surface(SurfNum).Area; - if (ShadeFlag == IntBlindOn || ShadeFlag == ExtBlindOn || ShadeFlag == BGBlindOn) { + if (ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::BGBlindOn) { if (Blind(SurfWinBlindNumber(SurfNum)).SlatOrientation == Horizontal) { WinTransDifSolarGnd(SurfNum) = DiffTransGnd * Surface(SurfNum).Area; WinTransDifSolarSky(SurfNum) = DiffTransSky * Surface(SurfNum).Area; @@ -6703,7 +6703,7 @@ namespace SolarShading { WinTransDifSolarSky(SurfNum) = DiffTrans * Surface(SurfNum).Area; } - if (ShadeFlag < 1 || ShadeFlag == SwitchableGlazing || ShadeFlag >= 10) { // Unshaded or switchable glazing + if (!SurfWinShaded(SurfNum) || SurfWinGlareControlIsActive(SurfNum) || ShadeFlag == WinShadingFlag::SwitchableGlazing) { // Unshaded or switchable glazing // Note: with previous defs of TBmBm & TBmDif, these come out right for Complex Fenestration // WinTransBmSolar uses the directional-hemispherical transmittance WinTransBmSolar(SurfNum) = (TBmBm + TBmDif) * SunLitFract * CosInc * Surface(SurfNum).Area * InOutProjSLFracMult; @@ -6743,8 +6743,8 @@ namespace SolarShading { if (WindowScheduledSolarAbs(SurfNum, ConstrNum) == 0) { Real64 TBmAll; // Window beam-to-(beam+diffuse) transmittance if (SurfWinWindowModelType(SurfNum) != WindowBSDFModel && - (ShadeFlag == IntShadeOn || ShadeFlag == ExtShadeOn || ShadeFlag == IntBlindOn || ShadeFlag == ExtBlindOn || - ShadeFlag == BGShadeOn || ShadeFlag == BGBlindOn || ShadeFlag == ExtScreenOn)) { + (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn || + ShadeFlag == WinShadingFlag::BGShadeOn || ShadeFlag == WinShadingFlag::BGBlindOn || ShadeFlag == WinShadingFlag::ExtScreenOn)) { TBmAll = TBmAllShBlSc; } else { TBmAll = TBmBm + TBmDif; @@ -6787,7 +6787,7 @@ namespace SolarShading { // assumed to be zero. if (SurfWinWindowModelType(SurfNum) != WindowBSDFModel) - if (ShadeFlag == IntShadeOn || ShadeFlag == ExtShadeOn || ShadeFlag == BGShadeOn || SurfWinSolarDiffusing(SurfNum) || + if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::BGShadeOn || SurfWinSolarDiffusing(SurfNum) || SurfWinOriginalClass(SurfNum) == SurfaceClass::TDD_Diffuser || Surface(SurfNum).Class == SurfaceClass::TDD_Dome) continue; if (SunLitFract > 0.0) { @@ -6811,9 +6811,9 @@ namespace SolarShading { if (ShelfNum > 0) { // Daylighting shelf InShelfSurf = state.dataDaylightingDevicesData->Shelf(ShelfNum).InSurf; } - if (ShadeFlag == IntBlindOn || ShadeFlag == ExtBlindOn || ShadeFlag == BGBlindOn) { + if (ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::BGBlindOn) { TBm = TBmBmBl; // Interior, exterior or between-glass blind on - } else if (ShadeFlag == ExtScreenOn) { + } else if (ShadeFlag == WinShadingFlag::ExtScreenOn) { TBm = TBmBmSc; // Exterior screen on } else { TBm = TBmBm; // Bare glass or switchable glazing @@ -6881,7 +6881,7 @@ namespace SolarShading { // are assumed to be bare, i.e., they have no shading device and are non-switchable. // The layer order for interior windows is "outside" to "inside," where "outside" refers to // the adjacent zone and "inside" refers to the current zone. - int ShadeFlagBack = SurfWinShadingFlag(BackSurfNum); + WinShadingFlag ShadeFlagBack = SurfWinShadingFlag(BackSurfNum); int ConstrNum = Surface(SurfNum).Construction; int ConstrNumSh = Surface(SurfNum).activeShadedConstruction; if (SurfWinStormWinFlag(SurfNum) == 1) { @@ -6911,7 +6911,7 @@ namespace SolarShading { TransBeamWin = 1.0; AbsBeamWinEQL = 0.0; AbsBeamTotWin = 0.0; - } else if (ShadeFlagBack <= 0) { + } else if (SurfWinShaded(SurfNum)) { for (int Lay = 1; Lay <= NBackGlass; ++Lay) { AbsBeamWin(Lay) = POLYF(CosIncBack, state.dataConstruction->Construct(ConstrNumBack).AbsBeamBackCoef({1, 6}, Lay)); } @@ -6920,7 +6920,7 @@ namespace SolarShading { // Interior beam absorptance of glass layers and beam transmittance // of back exterior window with SHADE - if (ShadeFlagBack == IntShadeOn || ShadeFlagBack == ExtShadeOn || ShadeFlagBack == BGShadeOn) { + if (ShadeFlagBack == WinShadingFlag::IntShadeOn || ShadeFlagBack == WinShadingFlag::ExtShadeOn || ShadeFlagBack == WinShadingFlag::BGShadeOn) { for (int Lay = 1; Lay <= state.dataConstruction->Construct(ConstrNumBackSh).TotGlassLayers; ++Lay) { AbsBeamWin(Lay) = POLYF(CosIncBack, state.dataConstruction->Construct(ConstrNumBackSh).AbsBeamBackCoef({1, 6}, Lay)); } @@ -6929,7 +6929,7 @@ namespace SolarShading { // Interior beam absorbed by INTERIOR SHADE of back exterior window - if (ShadeFlagBack == IntShadeOn) { + if (ShadeFlagBack == WinShadingFlag::IntShadeOn) { IntBeamAbsByShadFac(BackSurfNum) = BOverlap * state.dataConstruction->Construct(ConstrNumBackSh).AbsDiffBackShade / (Surface(BackSurfNum).Area + SurfWinDividerArea(BackSurfNum)); BABSZone += BOverlap * state.dataConstruction->Construct(ConstrNumBackSh).AbsDiffBackShade; @@ -6937,7 +6937,7 @@ namespace SolarShading { // Interior beam absorbed by EXTERIOR SHADE of back exterior window - if (ShadeFlagBack == ExtShadeOn) { + if (ShadeFlagBack == WinShadingFlag::ExtShadeOn) { Real64 RGlFront = state.dataConstruction->Construct(ConstrNumBack).ReflectSolDiffFront; Real64 AbsSh = dataMaterial.Material(state.dataConstruction->Construct(ConstrNumBackSh).LayerPoint(1)).AbsorpSolar; Real64 RhoSh = 1.0 - AbsSh - dataMaterial.Material(state.dataConstruction->Construct(ConstrNumBackSh).LayerPoint(1)).Trans; @@ -6949,7 +6949,7 @@ namespace SolarShading { // Interior beam absorbed by BETWEEN-GLASS SHADE of back exterior window - if (ShadeFlagBack == BGShadeOn) { + if (ShadeFlagBack == WinShadingFlag::BGShadeOn) { Real64 rbd1k = state.dataConstruction->Construct(ConstrNumBack).rbBareSolDiff(1); Real64 rfd2k = state.dataConstruction->Construct(ConstrNumBack).rfBareSolDiff(2); Real64 AShBack; // System shade absorptance for interior beam solar @@ -6975,7 +6975,7 @@ namespace SolarShading { // Interior beam absorptance of glass layers and beam absorbed in blind // of back exterior window with BLIND - if (ShadeFlagBack == IntBlindOn || ShadeFlagBack == ExtBlindOn || ShadeFlagBack == BGBlindOn) { + if (ShadeFlagBack == WinShadingFlag::IntBlindOn || ShadeFlagBack == WinShadingFlag::ExtBlindOn || ShadeFlagBack == WinShadingFlag::BGBlindOn) { int BlNumBack = SurfWinBlindNumber(BackSurfNum); // Back surface blind number Real64 ProfAngBack; // Back window solar profile angle (radians) ProfileAngle(BackSurfNum, state.dataEnvrn->SOLCOS, Blind(BlNumBack).SlatOrientation, ProfAngBack); @@ -6988,7 +6988,7 @@ namespace SolarShading { Real64 TBlBmDiffBack = InterpProfSlatAng(ProfAngBack, SlatAngBack, VarSlatsBack, Blind(BlNumBack).SolBackBeamDiffTrans); // Blind solar back beam-diffuse transmittance - if (ShadeFlagBack == IntBlindOn) { + if (ShadeFlagBack == WinShadingFlag::IntBlindOn) { // Interior beam absorptance of GLASS LAYERS of exterior back window with INTERIOR BLIND // Blind solar front beam reflectance @@ -7032,7 +7032,7 @@ namespace SolarShading { BABSZone += BOverlap * ABlBack; } - if (ShadeFlagBack == ExtBlindOn) { + if (ShadeFlagBack == WinShadingFlag::ExtBlindOn) { // Interior beam absorptance of GLASS LAYERS of exterior back window with EXTERIOR BLIND // Glazing system front diffuse solar reflectance @@ -7069,7 +7069,7 @@ namespace SolarShading { BOverlap * ABlBack / (Surface(BackSurfNum).Area + SurfWinDividerArea(BackSurfNum)); } // End of check if exterior blind on back window - if (ShadeFlagBack == BGBlindOn) { + if (ShadeFlagBack == WinShadingFlag::BGBlindOn) { Real64 t1k = POLYF(CosIncBack, state.dataConstruction->Construct(ConstrNumBack).tBareSolCoef({1, 6}, 1)); Real64 t2k = POLYF(CosIncBack, state.dataConstruction->Construct(ConstrNumBack).tBareSolCoef({1, 6}, 2)); @@ -7134,7 +7134,7 @@ namespace SolarShading { } // End of check if blind is on back window - if (ShadeFlagBack == ExtScreenOn) { + if (ShadeFlagBack == WinShadingFlag::ExtScreenOn) { // Interior beam absorptance of GLASS LAYERS of exterior back window with EXTERIOR SCREEN int ScNumBack = SurfWinScreenNumber(BackSurfNum); // Back surface screen number @@ -7170,7 +7170,7 @@ namespace SolarShading { // Interior beam absorptance of glass layers of back exterior window with SWITCHABLE GLAZING - if (ShadeFlagBack == SwitchableGlazing && Surface(BackSurfNum).ExtBoundCond == 0) { + if (ShadeFlagBack == WinShadingFlag::SwitchableGlazing && Surface(BackSurfNum).ExtBoundCond == 0) { Real64 SwitchFac = SurfWinSwitchingFactor(SurfNum); // Switching factor for a window Real64 AbsBeamWinSh; // Glass layer beam solar absorptance of a shaded window for (int Lay = 1; Lay <= NBackGlass; ++Lay) { @@ -7578,7 +7578,7 @@ namespace SolarShading { if ((Surface(SurfNum).ExtBoundCond == ExternalEnvironment) || (Surface(SurfNum).ExtBoundCond == OtherSideCondModeledExt)) { - int ShadeFlag = SurfWinShadingFlag(SurfNum); + WinShadingFlag ShadeFlag = SurfWinShadingFlag(SurfNum); int ShelfNum = Surface(SurfNum).Shelf; int OutShelfSurf = 0; if (ShelfNum > 0) { // Outside daylighting shelf @@ -7641,7 +7641,7 @@ namespace SolarShading { SurfWinDifSolar(SurfNum) = DifSolarInc * WinTransDifSolar(SurfNum); SurfWinBmSolarEnergy(SurfNum) = SurfWinBmSolar(SurfNum) * state.dataGlobal->TimeStepZoneSec; SurfWinDifSolarEnergy(SurfNum) = SurfWinDifSolar(SurfNum) * state.dataGlobal->TimeStepZoneSec; - if (ShadeFlag == IntBlindOn || ShadeFlag == ExtBlindOn || ShadeFlag == BGBlindOn) { + if (ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::BGBlindOn) { if (Blind(SurfWinBlindNumber(SurfNum)).SlatOrientation == Horizontal) { SurfWinDifSolar(SurfNum) = SkySolarInc * WinTransDifSolarSky(SurfNum) + GndSolarInc * WinTransDifSolarGnd(SurfNum); SurfWinDifSolarEnergy(SurfNum) = SurfWinDifSolar(SurfNum) * state.dataGlobal->TimeStepZoneSec; @@ -8686,7 +8686,7 @@ namespace SolarShading { for (int ISurf = firstSurfWin; ISurf <= lastSurfWin; ++ISurf) { SurfWinExtIntShadePrevTS(ISurf) = SurfWinShadingFlag(ISurf); - SurfWinShadingFlag(ISurf) = NoShade; + SurfWinShadingFlag(ISurf) = WinShadingFlag::NoShade; SurfWinFracTimeShadingDeviceOn(ISurf) = 0.0; if (SurfWinWindowModelType(ISurf) == WindowEQLModel) { int EQLNum = state.dataConstruction->Construct(Surface(ISurf).Construction).EQLConsPtr; @@ -8708,10 +8708,10 @@ namespace SolarShading { const int LayPtr = construction.LayerPoint(Lay); auto &material(dataMaterial.Material(LayPtr)); const bool isShading = material.Group == ComplexWindowShade; - if (isShading && Lay == 1) SurfWinShadingFlag(ISurf) = ExtShadeOn; - if (isShading && Lay == TotLayers) SurfWinShadingFlag(ISurf) = IntShadeOn; + if (isShading && Lay == 1) SurfWinShadingFlag(ISurf) = WinShadingFlag::ExtShadeOn; + if (isShading && Lay == TotLayers) SurfWinShadingFlag(ISurf) = WinShadingFlag::IntShadeOn; } - if (SurfWinShadingFlag(ISurf) == IntShadeOn) { + if (SurfWinShadingFlag(ISurf) == WinShadingFlag::IntShadeOn) { auto &construction(state.dataConstruction->Construct(Surface(ISurf).Construction)); const int TotLay = construction.TotLayers; int ShadingLayerPtr = construction.LayerPoint(TotLay); @@ -8761,7 +8761,7 @@ namespace SolarShading { int IShadingCtrl = Surface(ISurf).activeWindowShadingControl; int ShadingType = WindowShadingControl(IShadingCtrl).ShadingType; // Type of shading (interior shade, interior blind, etc.) - SurfWinShadingFlag(ISurf) = ShadeOff; // Initialize shading flag to off + SurfWinShadingFlag(ISurf) = WinShadingFlag::ShadeOff; // Initialize shading flag to off int IZone = Surface(ISurf).Zone; // Setpoint for shading @@ -8771,7 +8771,7 @@ namespace SolarShading { // ShType = NoShade ! =-1 (see DataHeatBalance) // ShType = ShadeOff ! =0 - int ShType; + WinShadingFlag ShType; // 1 = interior shade is on, // 2 = glass is switched to dark state, // 3 = exterior shade is on, @@ -8781,14 +8781,14 @@ namespace SolarShading { // 8 = between-glass shade is on, // 9 = between-glass blind is on. // CHARACTER(len=32) :: ShadingType ! Type of shading (interior shade, interior blind, etc.) - if (ShadingType == WSC_ST_InteriorShade) ShType = IntShadeOn; // =1 - if (ShadingType == WSC_ST_SwitchableGlazing) ShType = SwitchableGlazing; // =2 - if (ShadingType == WSC_ST_ExteriorShade) ShType = ExtShadeOn; // =3 - if (ShadingType == WSC_ST_ExteriorScreen) ShType = ExtScreenOn; // =4 - if (ShadingType == WSC_ST_InteriorBlind) ShType = IntBlindOn; // =6 - if (ShadingType == WSC_ST_ExteriorBlind) ShType = ExtBlindOn; // =7 - if (ShadingType == WSC_ST_BetweenGlassShade) ShType = BGShadeOn; // =8 - if (ShadingType == WSC_ST_BetweenGlassBlind) ShType = BGBlindOn; // =9 + if (ShadingType == WSC_ST_InteriorShade) ShType = WinShadingFlag::IntShadeOn; // =1 + if (ShadingType == WSC_ST_SwitchableGlazing) ShType = WinShadingFlag::SwitchableGlazing; // =2 + if (ShadingType == WSC_ST_ExteriorShade) ShType = WinShadingFlag::ExtShadeOn; // =3 + if (ShadingType == WSC_ST_ExteriorScreen) ShType = WinShadingFlag::ExtScreenOn; // =4 + if (ShadingType == WSC_ST_InteriorBlind) ShType = WinShadingFlag::IntBlindOn; // =6 + if (ShadingType == WSC_ST_ExteriorBlind) ShType = WinShadingFlag::ExtBlindOn; // =7 + if (ShadingType == WSC_ST_BetweenGlassShade) ShType = WinShadingFlag::BGShadeOn; // =8 + if (ShadingType == WSC_ST_BetweenGlassBlind) ShType = WinShadingFlag::BGBlindOn; // =9 bool SchedAllowsControl = true; // True if control schedule is not specified or is specified and schedule value = 1 int SchedulePtr = WindowShadingControl(IShadingCtrl).Schedule; @@ -8815,6 +8815,7 @@ namespace SolarShading { // Determine whether to deploy shading depending on type of control + SurfWinGlareControlIsActive(ISurf) = false; auto const SELECT_CASE_var(WindowShadingControl(IShadingCtrl).ShadingControlType); @@ -8822,7 +8823,7 @@ namespace SolarShading { SurfWinShadingFlag(ISurf) = ShType; } else if (SELECT_CASE_var == WSCT_AlwaysOff) { // 'ALWAYSOFF' - SurfWinShadingFlag(ISurf) = ShadeOff; + SurfWinShadingFlag(ISurf) = WinShadingFlag::ShadeOff; } else if (SELECT_CASE_var == WSCT_OnIfScheduled) { // 'ONIFSCHEDULEALLOWS' if (SchedAllowsControl) SurfWinShadingFlag(ISurf) = ShType; @@ -8832,8 +8833,6 @@ namespace SolarShading { if (state.dataEnvrn->SunIsUp) { if (SolarOnWindow > SetPoint && SchedAllowsControl) { SurfWinShadingFlag(ISurf) = ShType; - } else if (GlareControlIsActive) { - SurfWinShadingFlag(ISurf) = 10 * ShType; } } @@ -8842,24 +8841,18 @@ namespace SolarShading { if (state.dataEnvrn->SunIsUp) { if (HorizSolar > SetPoint && SchedAllowsControl) { SurfWinShadingFlag(ISurf) = ShType; - } else if (GlareControlIsActive) { - SurfWinShadingFlag(ISurf) = 10 * ShType; } } } else if (SELECT_CASE_var == WSCT_HiOutAirTemp) { // 'OnIfHighOutdoorAirTemperature' if (Surface(ISurf).OutDryBulbTemp > SetPoint && SchedAllowsControl) { SurfWinShadingFlag(ISurf) = ShType; - } else if (GlareControlIsActive) { - SurfWinShadingFlag(ISurf) = 10 * ShType; } } else if (SELECT_CASE_var == WSCT_HiZoneAirTemp) { // 'OnIfHighZoneAirTemperature' ! Previous time step zone air temperature if (MAT(IZone) > SetPoint && SchedAllowsControl) { SurfWinShadingFlag(ISurf) = ShType; - } else if (GlareControlIsActive) { - SurfWinShadingFlag(ISurf) = 10 * ShType; } } else if (SELECT_CASE_var == WSCT_OnHiOutTemp_HiSolarWindow) { @@ -8868,8 +8861,6 @@ namespace SolarShading { if (Surface(ISurf).OutDryBulbTemp > SetPoint && SolarOnWindow > SetPoint2 && SchedAllowsControl) { SurfWinShadingFlag(ISurf) = ShType; - } else if (GlareControlIsActive) { - SurfWinShadingFlag(ISurf) = 10 * ShType; } } @@ -8879,8 +8870,6 @@ namespace SolarShading { if (Surface(ISurf).OutDryBulbTemp > SetPoint && HorizSolar > SetPoint2 && SchedAllowsControl) { SurfWinShadingFlag(ISurf) = ShType; - } else if (GlareControlIsActive) { - SurfWinShadingFlag(ISurf) = 10 * ShType; } } @@ -8889,8 +8878,6 @@ namespace SolarShading { if (state.dataEnvrn->SunIsUp) { if (MAT(IZone) > SetPoint && SolarOnWindow > SetPoint2 && SchedAllowsControl) { SurfWinShadingFlag(ISurf) = ShType; - } else if (GlareControlIsActive) { - SurfWinShadingFlag(ISurf) = 10 * ShType; } } @@ -8899,8 +8886,6 @@ namespace SolarShading { if (state.dataEnvrn->SunIsUp) { if (MAT(IZone) > SetPoint && HorizSolar > SetPoint2 && SchedAllowsControl) { SurfWinShadingFlag(ISurf) = ShType; - } else if (GlareControlIsActive) { - SurfWinShadingFlag(ISurf) = 10 * ShType; } } @@ -8911,8 +8896,6 @@ namespace SolarShading { if (!state.dataGlobal->BeginSimFlag) { if (SNLoadCoolRate(IZone) > SetPoint && SchedAllowsControl) { SurfWinShadingFlag(ISurf) = ShType; - } else if (GlareControlIsActive) { - SurfWinShadingFlag(ISurf) = 10 * ShType; } } @@ -8920,33 +8903,35 @@ namespace SolarShading { // 'ONIFHIGHGLARE' ! Daylight glare index at first reference point in the zone. // This type of shading control is done in DayltgInteriorIllum. Glare control is not affected // by control schedule. - if (state.dataEnvrn->SunIsUp) SurfWinShadingFlag(ISurf) = 10 * ShType; + if (state.dataEnvrn->SunIsUp) { + SurfWinShadingFlag(ISurf) = ShType; + SurfWinGlareControlIsActive(ISurf) = true; + } + } else if (SELECT_CASE_var == WSCT_MeetDaylIlumSetp) { // 'MEETDAYLIGHTILLUMINANCESETPOINT') ! Daylight illuminance test is done in DayltgInteriorIllum // Only switchable glazing does daylight illuminance control - if (state.dataEnvrn->SunIsUp && SchedAllowsControl) SurfWinShadingFlag(ISurf) = GlassConditionallyLightened; + if (state.dataEnvrn->SunIsUp && SchedAllowsControl) { + SurfWinShadingFlag(ISurf) = ShType; + SurfWinGlareControlIsActive(ISurf) = true; +// SurfWinShadingFlag(ISurf) = WinShadingFlag::GlassConditionallyLightened; + } } else if (SELECT_CASE_var == WSCT_OnNightLoOutTemp_OffDay) { // 'OnNightIfLowOutdoorTempAndOffDay' if (!state.dataEnvrn->SunIsUp && Surface(ISurf).OutDryBulbTemp < SetPoint && SchedAllowsControl) { SurfWinShadingFlag(ISurf) = ShType; - } else if (GlareControlIsActive) { - SurfWinShadingFlag(ISurf) = 10 * ShType; } } else if (SELECT_CASE_var == WSCT_OnNightLoInTemp_OffDay) { // 'OnNightIfLowInsideTempAndOffDay') if (!state.dataEnvrn->SunIsUp && MAT(IZone) < SetPoint && SchedAllowsControl) { SurfWinShadingFlag(ISurf) = ShType; - } else if (GlareControlIsActive) { - SurfWinShadingFlag(ISurf) = 10 * ShType; } } else if (SELECT_CASE_var == WSCT_OnNightIfHeating_OffDay) { // 'OnNightIfHeatingAndOffDay' if (!state.dataGlobal->BeginSimFlag) { if (!state.dataEnvrn->SunIsUp && SNLoadHeatRate(IZone) > SetPoint && SchedAllowsControl) { SurfWinShadingFlag(ISurf) = ShType; - } else if (GlareControlIsActive) { - SurfWinShadingFlag(ISurf) = 10 * ShType; } } @@ -8959,8 +8944,6 @@ namespace SolarShading { } else { // Day if (SNLoadCoolRate(IZone) > 0.0 && SchedAllowsControl) { SurfWinShadingFlag(ISurf) = ShType; - } else if (GlareControlIsActive) { - SurfWinShadingFlag(ISurf) = 10 * ShType; } } } @@ -8974,8 +8957,6 @@ namespace SolarShading { } else { // Day if (SNLoadCoolRate(IZone) > 0.0 && SchedAllowsControl) { SurfWinShadingFlag(ISurf) = ShType; - } else if (GlareControlIsActive) { - SurfWinShadingFlag(ISurf) = 10 * ShType; } } } @@ -8985,8 +8966,6 @@ namespace SolarShading { if (!state.dataGlobal->BeginSimFlag) { if (state.dataEnvrn->SunIsUp && SNLoadCoolRate(IZone) > 0.0 && SchedAllowsControl) { if (SolarOnWindow > SetPoint) SurfWinShadingFlag(ISurf) = ShType; - } else if (GlareControlIsActive) { - SurfWinShadingFlag(ISurf) = 10 * ShType; } } @@ -8997,14 +8976,16 @@ namespace SolarShading { if (SolarOnWindow > SetPoint) SurfWinShadingFlag(ISurf) = ShType; } else if (!state.dataEnvrn->SunIsUp && SchedAllowsControl) { SurfWinShadingFlag(ISurf) = ShType; - } else if (GlareControlIsActive) { - SurfWinShadingFlag(ISurf) = 10 * ShType; } } } + if (GlareControlIsActive) { + SurfWinGlareControlIsActive(ISurf) = true; + } + // Set switching factor to fully switched if ShadingFlag = 2 - if (SurfWinShadingFlag(ISurf) == SwitchableGlazing) { + if (SurfWinShadingFlag(ISurf) == WinShadingFlag::SwitchableGlazing) { SurfWinSwitchingFactor(ISurf) = 1.0; // Added TH 1/20/2010 @@ -9019,9 +9000,9 @@ namespace SolarShading { SurfWinSlatAngThisTS(ISurf) = 0.0; SurfWinSlatAngThisTSDeg(ISurf) = 0.0; SurfWinSlatsBlockBeam(ISurf) = false; - if (SurfWinShadingFlag(ISurf) == IntBlindOn || SurfWinShadingFlag(ISurf) == 10 * IntBlindOn || - SurfWinShadingFlag(ISurf) == ExtBlindOn || SurfWinShadingFlag(ISurf) == 10 * ExtBlindOn || - SurfWinShadingFlag(ISurf) == BGBlindOn || SurfWinShadingFlag(ISurf) == 10 * BGBlindOn) { + if (SurfWinShadingFlag(ISurf) == WinShadingFlag::IntBlindOn || + SurfWinShadingFlag(ISurf) == WinShadingFlag::ExtBlindOn || + SurfWinShadingFlag(ISurf) == WinShadingFlag::BGBlindOn) { // Blind in place or may be in place due to glare control int BlNum = SurfWinBlindNumber(ISurf); if (BlNum > 0) { @@ -9152,15 +9133,17 @@ namespace SolarShading { } // End of check if interior or exterior blind in place // CALL CalcScreenTransmittance to intialized all screens prior to HB calc's - if (SurfWinShadingFlag(ISurf) == ExtScreenOn && state.dataEnvrn->SunIsUp) { + if (SurfWinShadingFlag(ISurf) == WinShadingFlag::ExtScreenOn && state.dataEnvrn->SunIsUp) { CalcScreenTransmittance(state, ISurf); } // EMS Actuator Point: override setting if ems flag on if (SurfWinShadingFlagEMSOn(ISurf)) { - SurfWinShadingFlag(ISurf) = SurfWinShadingFlagEMSValue(ISurf); + SurfWinShadingFlag(ISurf) = WinShadingFlag(SurfWinShadingFlagEMSValue(ISurf)); + } + if (SurfWinShadingFlag(ISurf) != WinShadingFlag::NoShade && SurfWinShadingFlag(ISurf) != WinShadingFlag::ShadeOff) { + SurfWinShaded(ISurf) = true; } - } // End of surface loop } } @@ -9882,7 +9865,7 @@ namespace SolarShading { // outside reveal surface (m2) Real64 BmSolRefldInsReveal; // Multiplied by beam solar gives beam solar reflected by horiz or vertical // inside reveal surface (m2) - int ShadeFlag; // Shading flag + WinShadingFlag ShadeFlag; // Shading flag int FrameDivNum; // Frame/Divider number Real64 FrameWidth; // Frame width (m) Real64 P1; // Frame outside/inside projection plus half of glazing thickness (m) @@ -9936,7 +9919,7 @@ namespace SolarShading { if (SurfWinInsideSillDepth(SurfNum) < SurfWinInsideReveal(SurfNum)) continue; ShadeFlag = SurfWinShadingFlag(SurfNum); - if (ShadeFlag == ExtShadeOn || ShadeFlag == ExtBlindOn) continue; + if (ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::ExtBlindOn) continue; if (CosIncAng(state.dataGlobal->TimeStep, state.dataGlobal->HourOfDay, SurfNum) <= 0.0) continue; @@ -10191,12 +10174,12 @@ namespace SolarShading { // Quantities related to inside reveal; inside reveal reflection/absorption is assumed // to occur only if an interior shade or blind is not in place. - if (ShadeFlag <= 0 || ShadeFlag == SwitchableGlazing) { + if (!SurfWinShaded(SurfNum) || ShadeFlag == WinShadingFlag::SwitchableGlazing) { if (A2ill > 1.0e-6) { DiffReflGlass = state.dataConstruction->Construct(ConstrNum).ReflectSolDiffBack; - if (ShadeFlag == SwitchableGlazing) { + if (ShadeFlag == WinShadingFlag::SwitchableGlazing) { SolTransGlassSh = POLYF(CosIncAng(state.dataGlobal->TimeStep, state.dataGlobal->HourOfDay, SurfNum), state.dataConstruction->Construct(ConstrNumSh).TransSolBeamCoef); SolTransGlass = InterpSw(SurfWinSwitchingFactor(SurfNum), SolTransGlass, @@ -10779,10 +10762,10 @@ namespace SolarShading { ConstrNumSh = Surface(HeatTransSurfNum).activeStormWinShadedConstruction; } int TotGlassLayers = state.dataConstruction->Construct(ConstrNum).TotGlassLayers; - int ShadeFlag = SurfWinShadingFlag(HeatTransSurfNum); + WinShadingFlag ShadeFlag = SurfWinShadingFlag(HeatTransSurfNum); if (SurfWinWindowModelType(HeatTransSurfNum) != WindowEQLModel) { - if (ShadeFlag <= 0) { // No window shading + if (!SurfWinShaded(HeatTransSurfNum)) { // No window shading // Init accumulator for transmittance calc below DifSolarAbsW = 0.0; @@ -10873,7 +10856,52 @@ namespace SolarShading { // Accumulate transmitted diffuse solar for reporting SurfWinInitialDifSolInTrans(HeatTransSurfNum) += DifSolarTransW * per_HTSurfaceArea; - } else if (ConstrNumSh != 0 && (ShadeFlag == IntShadeOn || ShadeFlag >= 3)) { + } else if (ShadeFlag == WinShadingFlag::SwitchableGlazing) { // Switchable glazing + // Init accumulator for transmittance calc below + DifSolarAbsW = 0.0; + + auto const &construct(state.dataConstruction->Construct(ConstrNum)); + auto const &construct_AbsDiffBack(construct.AbsDiffBack); + auto const &construct_sh(state.dataConstruction->Construct(ConstrNumSh)); + auto const &construct_sh_AbsDiffBack(construct_sh.AbsDiffBack); + for (int IGlass = 1; IGlass <= TotGlassLayers; ++IGlass) { + // Calc diffuse solar absorbed in each window glass layer + WinDifSolLayAbsW = WinDifSolarTrans_Factor * + InterpSw(win_SwitchingFactor, construct_AbsDiffBack(IGlass), construct_sh_AbsDiffBack(IGlass)); + + // Accumulate distributed diffuse solar absorbed [W] by overall window for transmittance calc below + DifSolarAbsW += WinDifSolLayAbsW; + + // Accumulate Window and Zone total distributed diffuse solar to check for conservation of energy + WinDifSolarDistAbsorbedTotl += WinDifSolLayAbsW; // debug + ZoneDifSolarDistAbsorbedTotl += WinDifSolLayAbsW; // debug + + // Accumulate diffuse solar absorbed from the inside by each window glass layer [W/m2] for heat balance calcs + SurfWinInitialDifSolwinAbs(IGlass, HeatTransSurfNum) += WinDifSolLayAbsW * per_HTSurfaceArea; + } + + // Calc diffuse solar reflected back to zone + DifSolarReflW = WinDifSolarTrans_Factor * + InterpSw(win_SwitchingFactor, construct.ReflectSolDiffBack, construct_sh.ReflectSolDiffBack); + + // Accumulate total reflected distributed diffuse solar for each zone for subsequent interreflection calcs + InitialZoneDifSolReflW(enclosureNum) += DifSolarReflW; // [W] + + // Accumulate Window and Zone total distributed diffuse solar to check for conservation of energy + WinDifSolarDistReflectedTotl += DifSolarReflW; // debug + ZoneDifSolarDistReflectedTotl += DifSolarReflW; // debug + + // Accumulate transmitted Window and Zone total distributed diffuse solar to check for conservation of energy + // This is not very effective since it assigns whatever distributed diffuse solar has not been + // absorbed or reflected to transmitted. + DifSolarTransW = WinDifSolarTrans_Factor - DifSolarAbsW - DifSolarReflW; + WinDifSolarDistTransmittedTotl += DifSolarTransW; // debug [W] + ZoneDifSolarDistTransmittedTotl += DifSolarTransW; // debug [W] + + // Accumulate transmitted diffuse solar for reporting + SurfWinInitialDifSolInTrans(HeatTransSurfNum) += DifSolarTransW * per_HTSurfaceArea; + + } else if (ConstrNumSh != 0) { // Interior, exterior or between-glass shade, screen or blind in place // Init accumulator for transmittance calc below @@ -10885,12 +10913,12 @@ namespace SolarShading { auto const &construct_sh_AbsDiffBack(construct_sh.AbsDiffBack); auto const &construct_sh_BlAbsDiffBack(construct_sh.BlAbsDiffBack); for (int IGlass = 1; IGlass <= construct_sh.TotGlassLayers; ++IGlass) { - if (ShadeFlag == IntShadeOn || ShadeFlag == ExtShadeOn || ShadeFlag == BGShadeOn || ShadeFlag == ExtScreenOn) { + if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::BGShadeOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { // Calc diffuse solar absorbed in each window glass layer and shade WinDifSolLayAbsW = WinDifSolarTrans_Factor * construct_sh_AbsDiffBack(IGlass); } - if (ShadeFlag == IntBlindOn || ShadeFlag == ExtBlindOn || ShadeFlag == BGBlindOn) { + if (ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::BGBlindOn) { BlAbsDiffBk = InterpSlatAng(HTsurf_slat_ang, HTsurf_movable_slats, construct_sh_BlAbsDiffBack(_, IGlass)); // Calc diffuse solar absorbed in each window glass layer and shade WinDifSolLayAbsW = WinDifSolarTrans_Factor * BlAbsDiffBk; @@ -10910,7 +10938,7 @@ namespace SolarShading { // Next calc diffuse solar reflected back to zone from window with shade or blind on // Diffuse back solar reflectance, bare glass or shade on InsideDifReflectance = state.dataConstruction->Construct(ConstrNum).ReflectSolDiffBack; - if (ShadeFlag == IntBlindOn || ShadeFlag == ExtBlindOn) { + if (ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn) { // Diffuse back solar reflectance, blind present, vs. slat angle InsideDifReflectance = InterpSlatAng(HTsurf_slat_ang, HTsurf_movable_slats, state.dataConstruction->Construct(ConstrNum).BlReflectSolDiffBack); @@ -10926,17 +10954,17 @@ namespace SolarShading { // Now calc diffuse solar absorbed by shade/blind itself BlNum = SurfWinBlindNumber(HeatTransSurfNum); - if (ShadeFlag == IntShadeOn || ShadeFlag == ExtShadeOn || ShadeFlag == BGShadeOn || ShadeFlag == ExtScreenOn) { + if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::BGShadeOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { // Calc diffuse solar absorbed by shade or screen [W] ShBlDifSolarAbsW = WinDifSolarTrans_Factor * construct_sh.AbsDiffBackShade; } - if (ShadeFlag == IntBlindOn || ShadeFlag == ExtBlindOn || ShadeFlag == BGBlindOn) { + if (ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::BGBlindOn) { // Calc diffuse solar absorbed by blind [W] AbsDiffBkBl = InterpSlatAng(HTsurf_slat_ang, HTsurf_movable_slats, construct_sh.AbsDiffBackBlind); ShBlDifSolarAbsW = WinDifSolarTrans_Factor * AbsDiffBkBl; } // Correct for divider shadowing - if (ShadeFlag == ExtShadeOn || ShadeFlag == ExtBlindOn || ShadeFlag == ExtScreenOn) + if (ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::ExtScreenOn) ShBlDifSolarAbsW *= SurfWinGlazedFrac(HeatTransSurfNum); // Accumulate diffuse solar absorbed by shade or screen [W/m2] for heat balance calcs @@ -10959,51 +10987,6 @@ namespace SolarShading { // Accumulate transmitted diffuse solar for reporting SurfWinInitialDifSolInTrans(HeatTransSurfNum) += DifSolarTransW * per_HTSurfaceArea; - } else if (ShadeFlag == SwitchableGlazing) { // Switchable glazing - // Init accumulator for transmittance calc below - DifSolarAbsW = 0.0; - - auto const &construct(state.dataConstruction->Construct(ConstrNum)); - auto const &construct_AbsDiffBack(construct.AbsDiffBack); - auto const &construct_sh(state.dataConstruction->Construct(ConstrNumSh)); - auto const &construct_sh_AbsDiffBack(construct_sh.AbsDiffBack); - for (int IGlass = 1; IGlass <= TotGlassLayers; ++IGlass) { - // Calc diffuse solar absorbed in each window glass layer - WinDifSolLayAbsW = WinDifSolarTrans_Factor * - InterpSw(win_SwitchingFactor, construct_AbsDiffBack(IGlass), construct_sh_AbsDiffBack(IGlass)); - - // Accumulate distributed diffuse solar absorbed [W] by overall window for transmittance calc below - DifSolarAbsW += WinDifSolLayAbsW; - - // Accumulate Window and Zone total distributed diffuse solar to check for conservation of energy - WinDifSolarDistAbsorbedTotl += WinDifSolLayAbsW; // debug - ZoneDifSolarDistAbsorbedTotl += WinDifSolLayAbsW; // debug - - // Accumulate diffuse solar absorbed from the inside by each window glass layer [W/m2] for heat balance calcs - SurfWinInitialDifSolwinAbs(IGlass, HeatTransSurfNum) += WinDifSolLayAbsW * per_HTSurfaceArea; - } - - // Calc diffuse solar reflected back to zone - DifSolarReflW = WinDifSolarTrans_Factor * - InterpSw(win_SwitchingFactor, construct.ReflectSolDiffBack, construct_sh.ReflectSolDiffBack); - - // Accumulate total reflected distributed diffuse solar for each zone for subsequent interreflection calcs - InitialZoneDifSolReflW(enclosureNum) += DifSolarReflW; // [W] - - // Accumulate Window and Zone total distributed diffuse solar to check for conservation of energy - WinDifSolarDistReflectedTotl += DifSolarReflW; // debug - ZoneDifSolarDistReflectedTotl += DifSolarReflW; // debug - - // Accumulate transmitted Window and Zone total distributed diffuse solar to check for conservation of energy - // This is not very effective since it assigns whatever distributed diffuse solar has not been - // absorbed or reflected to transmitted. - DifSolarTransW = WinDifSolarTrans_Factor - DifSolarAbsW - DifSolarReflW; - WinDifSolarDistTransmittedTotl += DifSolarTransW; // debug [W] - ZoneDifSolarDistTransmittedTotl += DifSolarTransW; // debug [W] - - // Accumulate transmitted diffuse solar for reporting - SurfWinInitialDifSolInTrans(HeatTransSurfNum) += DifSolarTransW * per_HTSurfaceArea; - } // End of shading flag check } else { @@ -11112,7 +11095,7 @@ namespace SolarShading { // IF(ShadeFlag == IntShadeOn) THEN // MatNumSh = Construct(ConstrNumSh)%LayerPoint(Construct(ConstrNumSh)%TotLayers) // DividerSolAbs = DividerSolAbs * dataMaterial.Material(MatNumSh)%Trans - // ELSE IF(ShadeFlag == IntBlindOn) THEN + // ELSE IF(ShadeFlag == WinShadingFlag::IntBlindOn) THEN // DividerSolAbs = DividerSolAbs * InterpSlatAng(SurfaceWindow(HeatTransSurfNum)%SlatAngThisTS, & // SurfaceWindow(HeatTransSurfNum)%MovableSlats,Blind(BlNum)%SolBackDiffDiffTrans) // END IF @@ -11191,7 +11174,7 @@ namespace SolarShading { int ConstrNumSh; // Shaded construction number int IGlass; // Glass layer counter int TotGlassLayers; // Number of glass layers in a window construction - int ShadeFlag; // Shading flag + WinShadingFlag ShadeFlag; // Shading flag Real64 AbsInt; // Tmp var for Inside surface short-wave absorptance Real64 MovInsulSchedVal; // Value of the movable insulation schedule for current time Real64 HMovInsul; // Conductance of movable insulation @@ -11323,7 +11306,7 @@ namespace SolarShading { TotGlassLayers = state.dataConstruction->Construct(ConstrNum).TotGlassLayers; ShadeFlag = SurfWinShadingFlag(HeatTransSurfNum); - if (ShadeFlag <= 0) { // No window shading + if (!SurfWinShaded(HeatTransSurfNum)) { // No window shading // Init accumulator for transmittance calc below DifSolarAbsW = 0.0; @@ -11393,7 +11376,49 @@ namespace SolarShading { InitialZoneDifSolReflW(Surface(AdjSurfNum).SolarEnclIndex) += DifSolarTransW; // [W] } - } else if (ShadeFlag == IntShadeOn || ShadeFlag >= 3) { + } else if (ShadeFlag == WinShadingFlag::SwitchableGlazing) { // Switchable glazing + // Init accumulator for transmittance calc below + DifSolarAbsW = 0.0; + + for (IGlass = 1; IGlass <= TotGlassLayers; ++IGlass) { + // Calc diffuse solar absorbed in each window glass layer + WinDifSolLayAbsW = SolarTrans_ViewFactor * InterpSw(SurfWinSwitchingFactor(HeatTransSurfNum), + state.dataConstruction->Construct(ConstrNum).AbsDiffBack(IGlass), + state.dataConstruction->Construct(ConstrNumSh).AbsDiffBack(IGlass)); + + // Accumulate distributed diffuse solar absorbed [W] by overall window for transmittance calc below + DifSolarAbsW += WinDifSolLayAbsW; + + // Accumulate diffuse solar absorbed from the inside by each window glass layer [W/m2] for heat balance calcs + SurfWinInitialDifSolwinAbs(IGlass, HeatTransSurfNum) += (WinDifSolLayAbsW / Surface(HeatTransSurfNum).Area); + } + // Accumulate Window and Zone total distributed diffuse solar to check for conservation of energy + // WinDifSolarDistAbsorbedTotl += DifSolarAbsW; // debug + // ZoneDifSolarDistAbsorbedTotl += DifSolarAbsW; // debug + + // Calc diffuse solar reflected back to zone + DifSolarReflW = SolarTrans_ViewFactor * InterpSw(SurfWinSwitchingFactor(HeatTransSurfNum), + state.dataConstruction->Construct(ConstrNum).ReflectSolDiffBack, + state.dataConstruction->Construct(ConstrNumSh).ReflectSolDiffBack); + + // Accumulate total reflected distributed diffuse solar for each zone for subsequent interreflection calcs + InitialZoneDifSolReflW_zone += DifSolarReflW; // [W] + + // Accumulate Window and Zone total distributed diffuse solar to check for conservation of energy + // WinDifSolarDistReflectedTotl += DifSolarReflW; // debug + // ZoneDifSolarDistReflectedTotl += DifSolarReflW; // debug + + // Accumulate transmitted Window and Zone total distributed diffuse solar to check for conservation of energy + // This is not very effective since it assigns whatever distributed diffuse solar has not been + // absorbed or reflected to transmitted. + DifSolarTransW = SolarTrans_ViewFactor - DifSolarAbsW - DifSolarReflW; + // WinDifSolarDistTransmittedTotl += DifSolarTransW; // debug [W] + // ZoneDifSolarDistTransmittedTotl += DifSolarTransW; // debug [W] + + // Accumulate transmitted diffuse solar for reporting + SurfWinInitialDifSolInTrans(HeatTransSurfNum) += (DifSolarTransW / Surface(HeatTransSurfNum).Area); + + } else { // Interior, exterior or between-glass shade, screen or blind in place // Init accumulator for transmittance calc below @@ -11402,12 +11427,12 @@ namespace SolarShading { // First calc diffuse solar absorbed by each glass layer in this window with shade/blind in place for (IGlass = 1; IGlass <= state.dataConstruction->Construct(ConstrNumSh).TotGlassLayers; ++IGlass) { - if (ShadeFlag == IntShadeOn || ShadeFlag == ExtShadeOn || ShadeFlag == BGShadeOn || ShadeFlag == ExtScreenOn) { + if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::BGShadeOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { // Calc diffuse solar absorbed in each window glass layer and shade WinDifSolLayAbsW = SolarTrans_ViewFactor * state.dataConstruction->Construct(ConstrNumSh).AbsDiffBack(IGlass); } - if (ShadeFlag == IntBlindOn || ShadeFlag == ExtBlindOn || ShadeFlag == BGBlindOn) { + if (ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::BGBlindOn) { BlAbsDiffBk = InterpSlatAng(SurfWinSlatAngThisTS(HeatTransSurfNum), SurfWinMovableSlats(HeatTransSurfNum), state.dataConstruction->Construct(ConstrNumSh).BlAbsDiffBack(_, IGlass)); @@ -11428,7 +11453,7 @@ namespace SolarShading { // Next calc diffuse solar reflected back to zone from window with shade or blind on // Diffuse back solar reflectance, bare glass or shade on InsideDifReflectance = state.dataConstruction->Construct(ConstrNum).ReflectSolDiffBack; - if (ShadeFlag == IntBlindOn || ShadeFlag == ExtBlindOn) { + if (ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn) { // Diffuse back solar reflectance, blind present, vs. slat angle InsideDifReflectance = InterpSlatAng(SurfWinSlatAngThisTS(HeatTransSurfNum), SurfWinMovableSlats(HeatTransSurfNum), @@ -11445,11 +11470,11 @@ namespace SolarShading { // Now calc diffuse solar absorbed by shade/blind itself BlNum = SurfWinBlindNumber(HeatTransSurfNum); - if (ShadeFlag == IntShadeOn || ShadeFlag == ExtShadeOn || ShadeFlag == BGShadeOn || ShadeFlag == ExtScreenOn) { + if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::BGShadeOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { // Calc diffuse solar absorbed by shade or screen [W] ShBlDifSolarAbsW = SolarTrans_ViewFactor * state.dataConstruction->Construct(ConstrNumSh).AbsDiffBackShade; } - if (ShadeFlag == IntBlindOn || ShadeFlag == ExtBlindOn || ShadeFlag == BGBlindOn) { + if (ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::BGBlindOn) { // Calc diffuse solar absorbed by blind [W] AbsDiffBkBl = InterpSlatAng(SurfWinSlatAngThisTS(HeatTransSurfNum), SurfWinMovableSlats(HeatTransSurfNum), @@ -11457,7 +11482,7 @@ namespace SolarShading { ShBlDifSolarAbsW = SolarTrans_ViewFactor * AbsDiffBkBl; } // Correct for divider shadowing - if (ShadeFlag == ExtShadeOn || ShadeFlag == ExtBlindOn || ShadeFlag == ExtScreenOn) + if (ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::ExtScreenOn) ShBlDifSolarAbsW *= SurfWinGlazedFrac(HeatTransSurfNum); // Accumulate diffuse solar absorbed by shade or screen [W/m2] for heat balance calcs @@ -11480,48 +11505,6 @@ namespace SolarShading { // Accumulate transmitted diffuse solar for reporting SurfWinInitialDifSolInTrans(HeatTransSurfNum) += (DifSolarTransW / Surface(HeatTransSurfNum).Area); - } else if (ShadeFlag == SwitchableGlazing) { // Switchable glazing - // Init accumulator for transmittance calc below - DifSolarAbsW = 0.0; - - for (IGlass = 1; IGlass <= TotGlassLayers; ++IGlass) { - // Calc diffuse solar absorbed in each window glass layer - WinDifSolLayAbsW = SolarTrans_ViewFactor * InterpSw(SurfWinSwitchingFactor(HeatTransSurfNum), - state.dataConstruction->Construct(ConstrNum).AbsDiffBack(IGlass), - state.dataConstruction->Construct(ConstrNumSh).AbsDiffBack(IGlass)); - - // Accumulate distributed diffuse solar absorbed [W] by overall window for transmittance calc below - DifSolarAbsW += WinDifSolLayAbsW; - - // Accumulate diffuse solar absorbed from the inside by each window glass layer [W/m2] for heat balance calcs - SurfWinInitialDifSolwinAbs(IGlass, HeatTransSurfNum) += (WinDifSolLayAbsW / Surface(HeatTransSurfNum).Area); - } - // Accumulate Window and Zone total distributed diffuse solar to check for conservation of energy - // WinDifSolarDistAbsorbedTotl += DifSolarAbsW; // debug - // ZoneDifSolarDistAbsorbedTotl += DifSolarAbsW; // debug - - // Calc diffuse solar reflected back to zone - DifSolarReflW = SolarTrans_ViewFactor * InterpSw(SurfWinSwitchingFactor(HeatTransSurfNum), - state.dataConstruction->Construct(ConstrNum).ReflectSolDiffBack, - state.dataConstruction->Construct(ConstrNumSh).ReflectSolDiffBack); - - // Accumulate total reflected distributed diffuse solar for each zone for subsequent interreflection calcs - InitialZoneDifSolReflW_zone += DifSolarReflW; // [W] - - // Accumulate Window and Zone total distributed diffuse solar to check for conservation of energy - // WinDifSolarDistReflectedTotl += DifSolarReflW; // debug - // ZoneDifSolarDistReflectedTotl += DifSolarReflW; // debug - - // Accumulate transmitted Window and Zone total distributed diffuse solar to check for conservation of energy - // This is not very effective since it assigns whatever distributed diffuse solar has not been - // absorbed or reflected to transmitted. - DifSolarTransW = SolarTrans_ViewFactor - DifSolarAbsW - DifSolarReflW; - // WinDifSolarDistTransmittedTotl += DifSolarTransW; // debug [W] - // ZoneDifSolarDistTransmittedTotl += DifSolarTransW; // debug [W] - - // Accumulate transmitted diffuse solar for reporting - SurfWinInitialDifSolInTrans(HeatTransSurfNum) += (DifSolarTransW / Surface(HeatTransSurfNum).Area); - } // End of shading flag check // HERE 8/14/07 Ignore absorptance and reflectance of Frames and Dividers for now. @@ -11546,7 +11529,7 @@ namespace SolarShading { // IF(ShadeFlag == IntShadeOn) THEN // MatNumSh = Construct(ConstrNumSh)%LayerPoint(Construct(ConstrNumSh)%TotLayers) // DividerSolAbs = DividerSolAbs * dataMaterial.Material(MatNumSh)%Trans - // ELSE IF(ShadeFlag == IntBlindOn) THEN + // ELSE IF(ShadeFlag == WinShadingFlag::IntBlindOn) THEN // DividerSolAbs = DividerSolAbs * InterpSlatAng(SurfaceWindow(HeatTransSurfNum)%SlatAngThisTS, & // SurfaceWindow(HeatTransSurfNum)%MovableSlats,Blind(BlNum)%SolBackDiffDiffTrans) // END IF diff --git a/src/EnergyPlus/SteamBaseboardRadiator.cc b/src/EnergyPlus/SteamBaseboardRadiator.cc index a7a7e0d4072..ba5eb4e15b6 100644 --- a/src/EnergyPlus/SteamBaseboardRadiator.cc +++ b/src/EnergyPlus/SteamBaseboardRadiator.cc @@ -1389,7 +1389,7 @@ namespace SteamBaseboardRadiator { Area = Surface(SurfNum).Area; if (Surface(SurfNum).Class == SurfaceClass::Window) { - if (SurfWinShadingFlag(SurfNum) == IntShadeOn || SurfWinShadingFlag(SurfNum) == IntBlindOn) { + if (SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntShadeOn || SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntBlindOn) { // The area is the shade or blind area = the sum of the glazing area and the divider area (which is zero if no divider) Area += SurfWinDividerArea(SurfNum); } @@ -1400,8 +1400,8 @@ namespace SteamBaseboardRadiator { SurfWinFrameTempSurfIn(SurfNum); } - if (SurfWinDividerArea(SurfNum) > 0.0 && SurfWinShadingFlag(SurfNum) != IntShadeOn && - SurfWinShadingFlag(SurfNum) != IntBlindOn) { + if (SurfWinDividerArea(SurfNum) > 0.0 && SurfWinShadingFlag(SurfNum) != WinShadingFlag::IntShadeOn && + SurfWinShadingFlag(SurfNum) != WinShadingFlag::IntBlindOn) { // Window divider contribution (only from shade or blind for window with divider and interior shade or blind) SumHATsurf += HConvIn(SurfNum) * SurfWinDividerArea(SurfNum) * (1.0 + 2.0 * SurfWinProjCorrDivIn(SurfNum)) * SurfWinDividerTempSurfIn(SurfNum); diff --git a/src/EnergyPlus/SurfaceGeometry.cc b/src/EnergyPlus/SurfaceGeometry.cc index 194711e4938..e5776c99602 100644 --- a/src/EnergyPlus/SurfaceGeometry.cc +++ b/src/EnergyPlus/SurfaceGeometry.cc @@ -159,13 +159,15 @@ namespace SurfaceGeometry { SurfWinProfileAngHor.dimension(NumSurfaces, 0); SurfWinProfileAngVert.dimension(NumSurfaces, 0); - SurfWinShadingFlag.dimension(NumSurfaces, 0); + SurfWinShadingFlag.dimension(NumSurfaces, WinShadingFlag::ShadeOff); + SurfWinShaded.dimension(NumSurfaces, false); SurfWinShadingFlagEMSOn.dimension(NumSurfaces, 0); SurfWinShadingFlagEMSValue.dimension(NumSurfaces, 0); + SurfWinGlareControlIsActive.dimension(NumSurfaces, false); SurfWinStormWinFlag.dimension(NumSurfaces, 0); SurfWinStormWinFlagPrevDay.dimension(NumSurfaces, 0); SurfWinFracTimeShadingDeviceOn.dimension(NumSurfaces, 0); - SurfWinExtIntShadePrevTS.dimension(NumSurfaces, 0); + SurfWinExtIntShadePrevTS.dimension(NumSurfaces, WinShadingFlag::ShadeOff); SurfWinHasShadeOrBlindLayer.dimension(NumSurfaces, 0); SurfWinSurfDayLightInit.dimension(NumSurfaces, 0); SurfWinDaylFacPoint.dimension(NumSurfaces, 0); diff --git a/src/EnergyPlus/SwimmingPool.cc b/src/EnergyPlus/SwimmingPool.cc index cb60733b7e1..3d42836a270 100644 --- a/src/EnergyPlus/SwimmingPool.cc +++ b/src/EnergyPlus/SwimmingPool.cc @@ -1028,8 +1028,8 @@ namespace SwimmingPool { Real64 Area = DataSurfaces::Surface(SurfNum).Area; // Effective surface area if (DataSurfaces::Surface(SurfNum).Class == DataSurfaces::SurfaceClass::Window) { - if (DataSurfaces::SurfWinShadingFlag(SurfNum) == DataSurfaces::IntShadeOn || - DataSurfaces::SurfWinShadingFlag(SurfNum) == DataSurfaces::IntBlindOn) { + if (DataSurfaces::SurfWinShadingFlag(SurfNum) == DataSurfaces::WinShadingFlag::IntShadeOn || + DataSurfaces::SurfWinShadingFlag(SurfNum) == DataSurfaces::WinShadingFlag::IntBlindOn) { // The area is the shade or blind are = sum of the glazing area and the divider area (which is zero if no divider) Area += DataSurfaces::SurfWinDividerArea(SurfNum); } @@ -1041,8 +1041,8 @@ namespace SwimmingPool { } if (DataSurfaces::SurfWinDividerArea(SurfNum) > 0.0 && - DataSurfaces::SurfWinShadingFlag(SurfNum) != DataSurfaces::IntShadeOn && - DataSurfaces::SurfWinShadingFlag(SurfNum) != DataSurfaces::IntBlindOn) { + DataSurfaces::SurfWinShadingFlag(SurfNum) != DataSurfaces::WinShadingFlag::IntShadeOn && + DataSurfaces::SurfWinShadingFlag(SurfNum) != DataSurfaces::WinShadingFlag::IntBlindOn) { // Window divider contribution (only from shade or blind for window with divider and interior shade or blind) SumHATsurf += DataHeatBalance::HConvIn(SurfNum) * DataSurfaces::SurfWinDividerArea(SurfNum) * (1.0 + 2.0 * DataSurfaces::SurfWinProjCorrDivIn(SurfNum)) * diff --git a/src/EnergyPlus/UFADManager.cc b/src/EnergyPlus/UFADManager.cc index c3f8f0ac822..d1a1ba3e596 100644 --- a/src/EnergyPlus/UFADManager.cc +++ b/src/EnergyPlus/UFADManager.cc @@ -216,7 +216,7 @@ namespace UFADManager { if (SurfNum == 0) continue; if (Surface(SurfNum).ExtBoundCond == ExternalEnvironment || Surface(SurfNum).ExtBoundCond == OtherSideCoefNoCalcExt || Surface(SurfNum).ExtBoundCond == OtherSideCoefCalcExt || Surface(SurfNum).ExtBoundCond == OtherSideCondModeledExt) { - if (SurfWinShadingFlag(SurfNum) == IntShadeOn || SurfWinShadingFlag(SurfNum) == IntBlindOn) { + if (SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntShadeOn || SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntBlindOn) { ++NumShadesDown; } } diff --git a/src/EnergyPlus/VentilatedSlab.cc b/src/EnergyPlus/VentilatedSlab.cc index 25b154bf481..bad1549bb9e 100644 --- a/src/EnergyPlus/VentilatedSlab.cc +++ b/src/EnergyPlus/VentilatedSlab.cc @@ -4464,7 +4464,7 @@ namespace VentilatedSlab { Area = Surface(SurfNum).Area; if (Surface(SurfNum).Class == SurfaceClass::Window) { - if (SurfWinShadingFlag(SurfNum) == IntShadeOn || SurfWinShadingFlag(SurfNum) == IntBlindOn) { + if (SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntShadeOn || SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntBlindOn) { // The area is the shade or blind are = sum of the glazing area and the divider area (which is zero if no divider) Area += SurfWinDividerArea(SurfNum); } @@ -4475,8 +4475,8 @@ namespace VentilatedSlab { SurfWinFrameTempSurfIn(SurfNum); } - if (SurfWinDividerArea(SurfNum) > 0.0 && SurfWinShadingFlag(SurfNum) != IntShadeOn && - SurfWinShadingFlag(SurfNum) != IntBlindOn) { + if (SurfWinDividerArea(SurfNum) > 0.0 && SurfWinShadingFlag(SurfNum) != WinShadingFlag::IntShadeOn && + SurfWinShadingFlag(SurfNum) != WinShadingFlag::IntBlindOn) { // Window divider contribution (only from shade or blind for window with divider and interior shade or blind) SumHATsurf += HConvIn(SurfNum) * SurfWinDividerArea(SurfNum) * (1.0 + 2.0 * SurfWinProjCorrDivIn(SurfNum)) * SurfWinDividerTempSurfIn(SurfNum); diff --git a/src/EnergyPlus/WindowComplexManager.cc b/src/EnergyPlus/WindowComplexManager.cc index dc137586966..e80d170067a 100644 --- a/src/EnergyPlus/WindowComplexManager.cc +++ b/src/EnergyPlus/WindowComplexManager.cc @@ -2676,7 +2676,7 @@ namespace WindowComplexManager { int k; // Layer counter int SurfNumAdj; // An interzone surface's number in the adjacent zone int ZoneNumAdj; // An interzone surface's adjacent zone number - int ShadeFlag; // Flag indicating whether shade or blind is on, and shade/blind position + WinShadingFlag ShadeFlag; // Flag indicating whether shade or blind is on, and shade/blind position int IMix; Real64 IncidentSolar; // Solar incident on outside of window (W) @@ -2935,7 +2935,7 @@ namespace WindowComplexManager { // outdoor wind speed if (!Surface(SurfNum).ExtWind) { wso = 0.0; // No wind exposure - // ELSE IF (Surface(SurfNum)%Class == SurfaceClass::Window .AND. SurfaceWindow(SurfNum)%ShadingFlag == ExtShadeOn) THEN + // ELSE IF (Surface(SurfNum)%Class == SurfaceClass::Window .AND. SurfaceWindow(SurfNum)%ShadingFlag == WinShadingFlag::ExtShadeOn) THEN // wso = 0.0 ! Assume zero wind speed at outside glass surface of window with exterior shade } else { wso = Surface(SurfNum).WindSpeed; @@ -3332,7 +3332,7 @@ namespace WindowComplexManager { SurfOutsideEmiss = emis(1); IncidentSolar = Surface(SurfNum).Area * SurfQRadSWOutIncident(SurfNum); - if (ShadeFlag == IntShadeOn || ShadeFlag == IntBlindOn) { + if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn) { // Interior shade or blind ConvHeatFlowNatural = -qv(nlayer) * height * width; @@ -3378,7 +3378,7 @@ namespace WindowComplexManager { SurfWinGainConvGlazToZoneRep(SurfNum) = ConvHeatGainFrZoneSideOfGlass; SurfWinGainIRGlazToZoneRep(SurfNum) = NetIRHeatGainGlass; // need to report convective heat flow from the gap in case of exterior shade - if (ShadeFlag == ExtShadeOn) { + if (ShadeFlag == WinShadingFlag::ExtShadeOn) { ConvHeatFlowNatural = -qv(2) * height * width; // qv(1) is exterior environment SurfWinGapConvHtFlowRep(SurfNum) = ConvHeatFlowNatural; @@ -3438,9 +3438,9 @@ namespace WindowComplexManager { // TransDiff = Construct(ConstrNum).TransDiff; int IState = SurfaceWindow(SurfNum).ComplexFen.NumStates; Real64 TransDiff = SurfaceWindow(SurfNum).ComplexFen.State(IState).WinDiffTrans; - // ELSE IF(ShadeFlag==IntShadeOn .OR. ShadeFlag==ExtShadeOn) THEN + // ELSE IF(ShadeFlag==WinShadingFlag::IntShadeOn .OR. ShadeFlag==WinShadingFlag::ExtShadeOn) THEN // TransDiff = Construct(ConstrNum)%TransDiff - // ELSE IF(ShadeFlag==IntBlindOn .OR. ShadeFlag==ExtBlindOn .OR.ShadeFlag==BGBlindOn) THEN + // ELSE IF(ShadeFlag==WinShadingFlag::IntBlindOn .OR. ShadeFlag==WinShadingFlag::ExtBlindOn .OR.ShadeFlag==WinShadingFlag::BGBlindOn) THEN // TransDiff = InterpSlatAng(SurfaceWindow(SurfNum)%SlatAngThisTS,SurfaceWindow(SurfNum)%MovableSlats, & // Construct(ConstrNumSh)%BlTransDiff) // ELSE IF(ShadeFlag == SwitchableGlazing) THEN @@ -3451,7 +3451,7 @@ namespace WindowComplexManager { SurfWinHeatTransfer(SurfNum) -= QS(Surface(SurfNum).SolarEnclIndex) * Surface(SurfNum).Area * TransDiff; SurfWinLossSWZoneToOutWinRep(SurfNum) = QS(Surface(SurfNum).SolarEnclIndex) * Surface(SurfNum).Area * TransDiff; - if (ShadeFlag == IntShadeOn || ShadeFlag == ExtShadeOn) { + if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn) { SurfWinShadingAbsorbedSolar(SurfNum) = (SurfWinExtBeamAbsByShade(SurfNum) + SurfWinExtDiffAbsByShade(SurfNum)) * (Surface(SurfNum).Area + SurfWinDividerArea(SurfNum)); SurfWinShadingAbsorbedSolarEnergy(SurfNum) = SurfWinShadingAbsorbedSolar(SurfNum) * state.dataGlobal->TimeStepZoneSec; @@ -3469,9 +3469,9 @@ namespace WindowComplexManager { } // Save hcv for use in divider calc with interior or exterior shade (see CalcWinFrameAndDividerTemps) - if (ShadeFlag == IntShadeOn) SurfWinConvCoeffWithShade(SurfNum) = 0.0; + if (ShadeFlag == WinShadingFlag::IntShadeOn) SurfWinConvCoeffWithShade(SurfNum) = 0.0; - if (ShadeFlag == IntShadeOn) { + if (ShadeFlag == WinShadingFlag::IntShadeOn) { SurfInsideTemp = theta(2 * ngllayer + 2) - DataGlobalConstants::KelvinConv(); // // Get properties of inside shading layer diff --git a/src/EnergyPlus/WindowManager.cc b/src/EnergyPlus/WindowManager.cc index 3c4664bc745..e172bd8d22d 100644 --- a/src/EnergyPlus/WindowManager.cc +++ b/src/EnergyPlus/WindowManager.cc @@ -1639,7 +1639,7 @@ namespace WindowManager { if (!Surface(SurfNum).HasShadeControl) { SurfWinSolarDiffusing(SurfNum) = true; } else { // There is a shading control - if (WindowShadingControl(Surface(SurfNum).activeWindowShadingControl).ShadingType == SwitchableGlazing) { + if (WindowShadingControl(Surface(SurfNum).activeWindowShadingControl).ShadingType == WSC_ST_SwitchableGlazing) { SurfWinSolarDiffusing(SurfNum) = true; } else { SurfWinSolarDiffusing(SurfNum) = false; @@ -2088,7 +2088,7 @@ namespace WindowManager { int IGap; // Gap layer number (1,2,...) int IMix; // Gas number in a mixture of gases int ICoeff; // Gas property index (1,2,3) - int ShadeFlag; // Flag indicating whether shade or blind is on, and shade/blind position + WinShadingFlag ShadeFlag; // Flag indicating whether shade or blind is on, and shade/blind position int k; // Layer counter // REAL(r64) :: tsky ! Sky temperature [K] int ShadeLayPtr; // Material number corresponding to a shade layer @@ -2345,8 +2345,8 @@ namespace WindowManager { // blind/shade and glass 3. IConst = ConstrNum; - if (ShadeFlag == IntShadeOn || ShadeFlag == ExtShadeOn || ShadeFlag == IntBlindOn || ShadeFlag == ExtBlindOn || ShadeFlag == BGShadeOn || - ShadeFlag == BGBlindOn || ShadeFlag == ExtScreenOn) { + if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::BGShadeOn || + ShadeFlag == WinShadingFlag::BGBlindOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { IConst = surface.activeShadedConstruction; if (SurfWinStormWinFlag(SurfNum) > 0) IConst = surface.activeStormWinShadedConstruction; } @@ -2370,13 +2370,13 @@ namespace WindowManager { } if (dataMaterial.Material(LayPtr).Group == Shade || dataMaterial.Material(LayPtr).Group == WindowBlind || dataMaterial.Material(LayPtr).Group == Screen) { - if (ShadeFlag == IntShadeOn || ShadeFlag == IntBlindOn) ShadeLayPtr = state.dataConstruction->Construct(IConst).LayerPoint(state.dataConstruction->Construct(IConst).TotLayers); - if (ShadeFlag == ExtShadeOn || ShadeFlag == ExtBlindOn || ShadeFlag == ExtScreenOn) ShadeLayPtr = state.dataConstruction->Construct(IConst).LayerPoint(1); - if (ShadeFlag == BGShadeOn || ShadeFlag == BGBlindOn) { + if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn) ShadeLayPtr = state.dataConstruction->Construct(IConst).LayerPoint(state.dataConstruction->Construct(IConst).TotLayers); + if (ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::ExtScreenOn) ShadeLayPtr = state.dataConstruction->Construct(IConst).LayerPoint(1); + if (ShadeFlag == WinShadingFlag::BGShadeOn || ShadeFlag == WinShadingFlag::BGBlindOn) { ShadeLayPtr = state.dataConstruction->Construct(IConst).LayerPoint(3); if (TotGlassLay == 3) ShadeLayPtr = state.dataConstruction->Construct(IConst).LayerPoint(5); } - if (ShadeFlag == IntShadeOn || ShadeFlag == ExtShadeOn || ShadeFlag == BGShadeOn || ShadeFlag == ExtScreenOn) { + if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::BGShadeOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { // Shade or screen on if (state.dataGlobal->AnyEnergyManagementSystemInModel) { // check to make sure the user hasn't messed up the shade control values if (dataMaterial.Material(ShadeLayPtr).Group == WindowBlind) { @@ -2388,7 +2388,7 @@ namespace WindowManager { } state.dataWindowManager->thick(TotGlassLay + 1) = dataMaterial.Material(ShadeLayPtr).Thickness; state.dataWindowManager->scon(TotGlassLay + 1) = dataMaterial.Material(ShadeLayPtr).Conductivity / dataMaterial.Material(ShadeLayPtr).Thickness; - if (ShadeFlag == ExtScreenOn) { + if (ShadeFlag == WinShadingFlag::ExtScreenOn) { state.dataWindowManager->emis(state.dataWindowManager->nglface + 1) = dataMaterial.Material(ShadeLayPtr).AbsorpThermalFront; state.dataWindowManager->tir(state.dataWindowManager->nglface + 1) = SurfaceScreens(dataMaterial.Material(ShadeLayPtr).ScreenDataPtr).DifDifTrans; state.dataWindowManager->tir(state.dataWindowManager->nglface + 2) = SurfaceScreens(dataMaterial.Material(ShadeLayPtr).ScreenDataPtr).DifDifTrans; @@ -2436,12 +2436,12 @@ namespace WindowManager { } // End of loop over glass, gap and blind/shade layers in a window construction - if (ShadeFlag == IntShadeOn || ShadeFlag == ExtShadeOn || ShadeFlag == IntBlindOn || ShadeFlag == ExtBlindOn || - ShadeFlag == ExtScreenOn) { + if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn || + ShadeFlag == WinShadingFlag::ExtScreenOn) { // Interior or exterior blind, shade or screen is on. // Fill gap between blind/shade and adjacent glass with air properties. ++IGap; - if (ShadeFlag == IntShadeOn || ShadeFlag == ExtShadeOn || ShadeFlag == ExtScreenOn) { // Interior or exterior shade + if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { // Interior or exterior shade state.dataWindowManager->gap(IGap) = dataMaterial.Material(ShadeLayPtr).WinShadeToGlassDist; } else { // Interior or exterior blind state.dataWindowManager->gap(IGap) = Blind(SurfWinBlindNumber(SurfNum)).BlindToGlassDist; @@ -2588,7 +2588,7 @@ namespace WindowManager { dth3 = state.dataWindowManager->thetas(6) - state.dataWindowManager->thetas(5); dth4 = state.dataWindowManager->thetas(8) - state.dataWindowManager->thetas(7); - if (ShadeFlag == IntShadeOn || ShadeFlag == IntBlindOn) { + if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn) { SurfInsideTemp = state.dataWindowManager->thetas(2 * state.dataWindowManager->ngllayer + 2) - state.dataWindowManager->TKelvin; EffShBlEmiss = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), window.EffShBlindEmiss); EffGlEmiss = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), window.EffGlassEmiss); @@ -2596,7 +2596,7 @@ namespace WindowManager { } else { SurfInsideTemp = state.dataWindowManager->thetas(2 * state.dataWindowManager->ngllayer) - state.dataWindowManager->TKelvin; } - if (ShadeFlag == ExtShadeOn || ShadeFlag == ExtBlindOn || ShadeFlag == ExtScreenOn) { + if (ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { SurfOutsideTemp = state.dataWindowManager->thetas(2 * state.dataWindowManager->ngllayer + 1) - state.dataWindowManager->TKelvin; // this index looks suspicious (CR 8202) // SurfOutsideEmiss = emis(1) ! this index should be coordinated with previous line SurfOutsideEmiss = state.dataWindowManager->emis(2 * state.dataWindowManager->ngllayer + 1); // fix for CR 8202 @@ -2911,7 +2911,7 @@ namespace WindowManager { // 2=exterior shade/blind Real64 TauShIR; // Long-wave transmittance of isolated shade/blind Real64 sconsh; // shade/blind conductance (W/m2-K) - int ShadeFlag; // Shading flag + WinShadingFlag ShadeFlag; // Shading flag // Real64 ShadeAbsFac1; // Fractions for apportioning absorbed radiation to shade/blind faces // Real64 ShadeAbsFac2; static Array1D AbsRadShadeFace(2); // Solar radiation, short-wave radiation from lights, and long-wave //Tuned Made static @@ -2963,22 +2963,22 @@ namespace WindowManager { AbsRadShadeFace = 0.0; TGapNew = 0.0; - if (ShadeFlag == IntShadeOn || ShadeFlag == ExtShadeOn || ShadeFlag == IntBlindOn || ShadeFlag == ExtBlindOn || ShadeFlag == BGShadeOn || - ShadeFlag == BGBlindOn || ShadeFlag == ExtScreenOn) { + if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::BGShadeOn || + ShadeFlag == WinShadingFlag::BGBlindOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { state.dataWindowManager->nglfacep = state.dataWindowManager->nglface + 2; AbsRadShadeFace(1) = DataSurfaces::AbsFrontSide(SurfNum); AbsRadShadeFace(2) = DataSurfaces::AbsBackSide(SurfNum); - if (ShadeFlag == IntShadeOn || ShadeFlag == IntBlindOn) AbsRadShadeFace(2) += SurfWinIntLWAbsByShade(SurfNum); + if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn) AbsRadShadeFace(2) += SurfWinIntLWAbsByShade(SurfNum); sconsh = state.dataWindowManager->scon(state.dataWindowManager->ngllayer + 1); TauShIR = state.dataWindowManager->tir(state.dataWindowManager->nglface + 1); EpsShIR1 = state.dataWindowManager->emis(state.dataWindowManager->nglface + 1); EpsShIR2 = state.dataWindowManager->emis(state.dataWindowManager->nglface + 2); RhoShIR1 = max(0.0, 1.0 - TauShIR - EpsShIR1); RhoShIR2 = max(0.0, 1.0 - TauShIR - EpsShIR2); - if (ShadeFlag == IntShadeOn || ShadeFlag == IntBlindOn) { + if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn) { RhoGlIR2 = 1.0 - state.dataWindowManager->emis(2 * state.dataWindowManager->ngllayer); ShGlReflFacIR = 1.0 - RhoGlIR2 * RhoShIR1; - } else if (ShadeFlag == ExtShadeOn || ShadeFlag == ExtBlindOn || ShadeFlag == ExtScreenOn) { + } else if (ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { RhoGlIR1 = 1.0 - state.dataWindowManager->emis(1); ShGlReflFacIR = 1.0 - RhoGlIR1 * RhoShIR2; } @@ -3010,7 +3010,7 @@ namespace WindowManager { (Surface(SurfNum).IntConvCoeff == -2)) { // coef model is "detailed" and not prescribed by user // need to find inside face index, varies with shade/blind etc. - if (ShadeFlag == IntShadeOn || ShadeFlag == IntBlindOn) { + if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn) { InsideFaceIndex = state.dataWindowManager->nglfacep; } else { InsideFaceIndex = state.dataWindowManager->nglface; @@ -3026,8 +3026,8 @@ namespace WindowManager { // coefficient from glass and shade/blind to gap between glass and shade/blind, // effective gap air temperature, velocity of air in gap and gap outlet temperature. - if (ShadeFlag == IntShadeOn || ShadeFlag == ExtShadeOn || ShadeFlag == IntBlindOn || ShadeFlag == ExtBlindOn || - ShadeFlag == ExtScreenOn) { + if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn || + ShadeFlag == WinShadingFlag::ExtScreenOn) { ExtOrIntShadeNaturalFlow(state, SurfNum, iter, VGap, TGapNew, TGapOutlet, hcv, ConvHeatFlowNatural); if (iter >= 1) { hcv = 0.5 * (hcvPrev + hcv); @@ -3043,7 +3043,7 @@ namespace WindowManager { // get glass-to-air forced convection heat transfer coefficient, average gap air temperature, and // convective heat flow from gap. - if (ShadeFlag != BGShadeOn && ShadeFlag != BGBlindOn && SurfWinAirflowThisTS(SurfNum) > 0.0) { + if (ShadeFlag != WinShadingFlag::BGShadeOn && ShadeFlag != WinShadingFlag::BGBlindOn && SurfWinAirflowThisTS(SurfNum) > 0.0) { BetweenGlassForcedFlow(state, SurfNum, iter, VAirflowGap, TAirflowGapNew, TAirflowGapOutlet, hcvAirflowGap, ConvHeatFlowForced); } @@ -3052,7 +3052,7 @@ namespace WindowManager { // Also get average gas temperature in the two gaps, and, for airflow window, the sum of the // convective heat flows from the gaps. - if (ShadeFlag == BGShadeOn || ShadeFlag == BGBlindOn) { + if (ShadeFlag == WinShadingFlag::BGShadeOn || ShadeFlag == WinShadingFlag::BGBlindOn) { if (SurfWinAirflowThisTS(SurfNum) == 0.0) { // Natural convection in gaps BetweenGlassShadeNaturalFlow(state, SurfNum, iter, VGap, TGapNewBG, hcvBG); } else { // Forced convection in gaps @@ -3076,7 +3076,7 @@ namespace WindowManager { Aface(1, 2) = -state.dataWindowManager->scon(1); Aface(2, 2) = hr(2) + state.dataWindowManager->scon(1) + state.dataWindowManager->hcin; - if (ShadeFlag == IntShadeOn || ShadeFlag == IntBlindOn) { + if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn) { Bface(2) = state.dataWindowManager->Rmir * state.dataWindowManager->emis(2) * TauShIR / ShGlReflFacIR + hcv * TGapNew + state.dataWindowManager->AbsRadGlassFace(2); Bface(3) = state.dataWindowManager->Rmir * TauShIR * RhoGlIR2 * EpsShIR1 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(1); Bface(4) = state.dataWindowManager->Rmir * EpsShIR2 + state.dataWindowManager->hcin * state.dataWindowManager->tin + AbsRadShadeFace(2); @@ -3090,7 +3090,7 @@ namespace WindowManager { Aface(4, 4) = hr(4) + sconsh + state.dataWindowManager->hcin; } - if (ShadeFlag == ExtShadeOn || ShadeFlag == ExtBlindOn || ShadeFlag == ExtScreenOn) { + if (ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { Bface(1) = state.dataWindowManager->Outir * state.dataWindowManager->emis(1) * TauShIR / ShGlReflFacIR + hcv * TGapNew + state.dataWindowManager->AbsRadGlassFace(1); Bface(3) = state.dataWindowManager->Outir * EpsShIR1 + state.dataWindowManager->hcout * state.dataWindowManager->tout + AbsRadShadeFace(1); Bface(4) = state.dataWindowManager->Outir * TauShIR * RhoGlIR1 * EpsShIR2 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(2); @@ -3132,7 +3132,7 @@ namespace WindowManager { Aface(3, 4) = -state.dataWindowManager->scon(2); Aface(4, 4) = hr(4) + state.dataWindowManager->scon(2) + state.dataWindowManager->hcin; - if (ShadeFlag != BGShadeOn && ShadeFlag != BGBlindOn && SurfWinAirflowThisTS(SurfNum) > 0.0) { + if (ShadeFlag != WinShadingFlag::BGShadeOn && ShadeFlag != WinShadingFlag::BGBlindOn && SurfWinAirflowThisTS(SurfNum) > 0.0) { Bface(2) = state.dataWindowManager->AbsRadGlassFace(2) + hcvAirflowGap * TAirflowGapNew; Bface(3) = state.dataWindowManager->AbsRadGlassFace(3) + hcvAirflowGap * TAirflowGapNew; Aface(2, 2) = state.dataWindowManager->scon(1) + hcvAirflowGap - state.dataWindowManager->A23P * hr(2); @@ -3141,7 +3141,7 @@ namespace WindowManager { Aface(3, 3) = hcvAirflowGap + state.dataWindowManager->scon(2) + state.dataWindowManager->A32P * hr(3); } - if (ShadeFlag == IntShadeOn || ShadeFlag == IntBlindOn) { + if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn) { Bface(4) = state.dataWindowManager->Rmir * state.dataWindowManager->emis(4) * TauShIR / ShGlReflFacIR + hcv * TGapNew + state.dataWindowManager->AbsRadGlassFace(4); Bface(5) = state.dataWindowManager->Rmir * TauShIR * RhoGlIR2 * EpsShIR1 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(1); Bface(6) = state.dataWindowManager->Rmir * EpsShIR2 + state.dataWindowManager->hcin * state.dataWindowManager->tin + AbsRadShadeFace(2); @@ -3155,7 +3155,7 @@ namespace WindowManager { Aface(6, 6) = hr(6) + sconsh + state.dataWindowManager->hcin; } - if (ShadeFlag == ExtShadeOn || ShadeFlag == ExtBlindOn || ShadeFlag == ExtScreenOn) { + if (ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { Bface(1) = state.dataWindowManager->Outir * state.dataWindowManager->emis(1) * TauShIR / ShGlReflFacIR + hcv * TGapNew + state.dataWindowManager->AbsRadGlassFace(1); Bface(5) = state.dataWindowManager->Outir * EpsShIR1 + state.dataWindowManager->hcout * state.dataWindowManager->tout + AbsRadShadeFace(1); Bface(6) = state.dataWindowManager->Outir * TauShIR * RhoGlIR1 * EpsShIR2 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(2); @@ -3169,7 +3169,7 @@ namespace WindowManager { Aface(6, 6) = hr(6) * (1 - RhoGlIR1 * (EpsShIR2 + RhoShIR2)) / ShGlReflFacIR + sconsh + hcv; } - if (ShadeFlag == BGShadeOn || ShadeFlag == BGBlindOn) { + if (ShadeFlag == WinShadingFlag::BGShadeOn || ShadeFlag == WinShadingFlag::BGBlindOn) { for (i = 1; i <= 6; ++i) { RhoIR(i) = max(0.0, 1.0 - state.dataWindowManager->tir(i) - state.dataWindowManager->emis(i)); } @@ -3250,7 +3250,7 @@ namespace WindowManager { Aface(5, 6) = -state.dataWindowManager->scon(3); Aface(6, 6) = hr(6) + state.dataWindowManager->scon(3) + state.dataWindowManager->hcin; - if (ShadeFlag != BGShadeOn && ShadeFlag != BGBlindOn && SurfWinAirflowThisTS(SurfNum) > 0.0) { + if (ShadeFlag != WinShadingFlag::BGShadeOn && ShadeFlag != WinShadingFlag::BGBlindOn && SurfWinAirflowThisTS(SurfNum) > 0.0) { Bface(4) = state.dataWindowManager->AbsRadGlassFace(4) + hcvAirflowGap * TAirflowGapNew; Bface(5) = state.dataWindowManager->AbsRadGlassFace(5) + hcvAirflowGap * TAirflowGapNew; Aface(4, 4) = state.dataWindowManager->scon(2) + hcvAirflowGap - state.dataWindowManager->A45P * hr(4); @@ -3259,7 +3259,7 @@ namespace WindowManager { Aface(5, 5) = hcvAirflowGap + state.dataWindowManager->scon(3) + state.dataWindowManager->A54P * hr(5); } - if (ShadeFlag == IntShadeOn || ShadeFlag == IntBlindOn) { + if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn) { Bface(6) = state.dataWindowManager->Rmir * state.dataWindowManager->emis(6) * TauShIR / ShGlReflFacIR + hcv * TGapNew + state.dataWindowManager->AbsRadGlassFace(6); Bface(7) = state.dataWindowManager->Rmir * TauShIR * RhoGlIR2 * EpsShIR1 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(1); Bface(8) = state.dataWindowManager->Rmir * EpsShIR2 + state.dataWindowManager->hcin * state.dataWindowManager->tin + AbsRadShadeFace(2); @@ -3273,7 +3273,7 @@ namespace WindowManager { Aface(8, 8) = hr(8) + sconsh + state.dataWindowManager->hcin; } - if (ShadeFlag == ExtShadeOn || ShadeFlag == ExtBlindOn || ShadeFlag == ExtScreenOn) { + if (ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { Bface(1) = state.dataWindowManager->Outir * state.dataWindowManager->emis(1) * TauShIR / ShGlReflFacIR + hcv * TGapNew + state.dataWindowManager->AbsRadGlassFace(1); Bface(7) = state.dataWindowManager->Outir * EpsShIR1 + state.dataWindowManager->hcout * state.dataWindowManager->tout + AbsRadShadeFace(1); Bface(8) = state.dataWindowManager->Outir * TauShIR * RhoGlIR1 * EpsShIR2 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(2); @@ -3287,7 +3287,7 @@ namespace WindowManager { Aface(8, 8) = hr(8) * (1 - RhoGlIR1 * (EpsShIR2 + RhoShIR2)) / ShGlReflFacIR + sconsh + hcv; } - if (ShadeFlag == BGShadeOn || ShadeFlag == BGBlindOn) { + if (ShadeFlag == WinShadingFlag::BGShadeOn || ShadeFlag == WinShadingFlag::BGBlindOn) { for (i = 1; i <= 8; ++i) { RhoIR(i) = max(0.0, 1.0 - state.dataWindowManager->tir(i) - state.dataWindowManager->emis(i)); } @@ -3385,7 +3385,7 @@ namespace WindowManager { Aface(7, 8) = -state.dataWindowManager->scon(4); Aface(8, 8) = hr(8) + state.dataWindowManager->scon(4) + state.dataWindowManager->hcin; - if (ShadeFlag == IntShadeOn || ShadeFlag == IntBlindOn) { + if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn) { Bface(8) = state.dataWindowManager->Rmir * state.dataWindowManager->emis(8) * TauShIR / ShGlReflFacIR + hcv * TGapNew + state.dataWindowManager->AbsRadGlassFace(8); Bface(9) = state.dataWindowManager->Rmir * TauShIR * RhoGlIR2 * EpsShIR1 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(1); Bface(10) = state.dataWindowManager->Rmir * EpsShIR2 + state.dataWindowManager->hcin * state.dataWindowManager->tin + AbsRadShadeFace(2); @@ -3399,7 +3399,7 @@ namespace WindowManager { Aface(10, 10) = hr(10) + sconsh + state.dataWindowManager->hcin; } - if (ShadeFlag == ExtShadeOn || ShadeFlag == ExtBlindOn || ShadeFlag == ExtScreenOn) { + if (ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { Bface(1) = state.dataWindowManager->Outir * state.dataWindowManager->emis(1) * TauShIR / ShGlReflFacIR + hcv * TGapNew + state.dataWindowManager->AbsRadGlassFace(1); Bface(9) = state.dataWindowManager->Outir * EpsShIR1 + state.dataWindowManager->hcout * state.dataWindowManager->tout + AbsRadShadeFace(1); Bface(10) = state.dataWindowManager->Outir * TauShIR * RhoGlIR1 * EpsShIR2 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(2); @@ -3451,7 +3451,7 @@ namespace WindowManager { // For all cases, get total window heat gain for reporting. See CalcWinFrameAndDividerTemps for // contribution of frame and divider. IncidentSolar = Surface(SurfNum).Area * SurfQRadSWOutIncident(SurfNum); - if (ShadeFlag == IntShadeOn || ShadeFlag == IntBlindOn) { + if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn) { // Interior shade or blind SurfWinConvHeatFlowNatural(SurfNum) = ConvHeatFlowNatural; // Window heat gain from glazing and shade/blind to zone. Consists of transmitted solar, convection @@ -3532,14 +3532,14 @@ namespace WindowManager { } TransDiff = state.dataConstruction->Construct(ConstrNum).TransDiff; // Default value for TransDiff here - if (ShadeFlag <= 0) { + if (ShadeFlag == WinShadingFlag::NoShade || ShadeFlag == WinShadingFlag::ShadeOff) { TransDiff = state.dataConstruction->Construct(ConstrNum).TransDiff; - } else if (ShadeFlag == IntShadeOn || ShadeFlag == ExtShadeOn || ShadeFlag == BGShadeOn || ShadeFlag == ExtScreenOn) { + } else if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::BGShadeOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { TransDiff = state.dataConstruction->Construct(ConstrNumSh).TransDiff; - } else if (ShadeFlag == IntBlindOn || ShadeFlag == ExtBlindOn || ShadeFlag == BGBlindOn) { + } else if (ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::BGBlindOn) { TransDiff = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), state.dataConstruction->Construct(ConstrNumSh).BlTransDiff); - } else if (ShadeFlag == SwitchableGlazing) { + } else if (ShadeFlag == WinShadingFlag::SwitchableGlazing) { TransDiff = InterpSw(SurfWinSwitchingFactor(SurfNum), state.dataConstruction->Construct(ConstrNum).TransDiff, state.dataConstruction->Construct(ConstrNumSh).TransDiff); } SurfWinHeatGain(SurfNum) -= QS(Surface(SurfNum).SolarEnclIndex) * Surface(SurfNum).Area * TransDiff; @@ -3547,8 +3547,8 @@ namespace WindowManager { // shouldn't this be + outward flowing fraction of absorbed SW? -- do not know whose comment this is? LKL (9/2012) SurfWinLossSWZoneToOutWinRep(SurfNum) = QS(Surface(SurfNum).SolarEnclIndex) * Surface(SurfNum).Area * TransDiff; - if (ShadeFlag == IntShadeOn || ShadeFlag == ExtShadeOn || ShadeFlag == IntBlindOn || ShadeFlag == ExtBlindOn || ShadeFlag == BGShadeOn || - ShadeFlag == BGBlindOn || ShadeFlag == ExtScreenOn) { + if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::BGShadeOn || + ShadeFlag == WinShadingFlag::BGBlindOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { SurfWinShadingAbsorbedSolar(SurfNum) = (SurfWinExtBeamAbsByShade(SurfNum) + SurfWinExtDiffAbsByShade(SurfNum)) * (Surface(SurfNum).Area + SurfWinDividerArea(SurfNum)); SurfWinShadingAbsorbedSolarEnergy(SurfNum) = SurfWinShadingAbsorbedSolar(SurfNum) * state.dataGlobal->TimeStepZoneSec; @@ -3567,7 +3567,7 @@ namespace WindowManager { } // Save hcv for use in divider calc with interior or exterior shade (see CalcWinFrameAndDividerTemps) - if (ShadeFlag == IntShadeOn || ShadeFlag == ExtShadeOn || ShadeFlag == IntBlindOn || ShadeFlag == ExtBlindOn || ShadeFlag == ExtScreenOn) + if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::ExtScreenOn) SurfWinConvCoeffWithShade(SurfNum) = hcv; } else { // No convergence after MaxIterations even with relaxed error tolerance @@ -3662,7 +3662,7 @@ namespace WindowManager { Real64 gr; // glass-shade/blind gap Grashof number Real64 pr; // glass-shade/blind gap Prandtl number Real64 nu; // glass-shade/blind gap Nusselt number - int ShadeFlag; // Shading flag + WinShadingFlag ShadeFlag; // Shading flag int BlNum; // Blind number // Air properties @@ -3675,7 +3675,7 @@ namespace WindowManager { nglassfaces = 2 * state.dataConstruction->Construct(ConstrNumSh).TotGlassLayers; TotGaps = state.dataConstruction->Construct(ConstrNumSh).TotGlassLayers; - if (ShadeFlag == IntShadeOn || ShadeFlag == IntBlindOn) { // Interior shade or blind + if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn) { // Interior shade or blind MatNumSh = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(nglassfaces); TGapInlet = state.dataWindowManager->tin; TGlassFace = state.dataWindowManager->thetas(nglassfaces); @@ -3713,7 +3713,7 @@ namespace WindowManager { GapHeight = Surface(SurfNum).Height; - if (ShadeFlag == IntShadeOn || ShadeFlag == ExtShadeOn || ShadeFlag == ExtScreenOn) { + if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { // Shade or Screen on GapDepth = dataMaterial.Material(MatNumSh).WinShadeToGlassDist; AGap = GapDepth * Surface(SurfNum).Width; @@ -3777,7 +3777,7 @@ namespace WindowManager { TGapNew = TAve - (GapHeightChar / GapHeight) * (TGapOutlet - TGapInlet); // Convective heat flow from gap to room air for interior shade or blind - if (ShadeFlag == IntShadeOn || ShadeFlag == IntBlindOn) { + if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn) { RhoAir = state.dataWindowManager->AirProps(1) + state.dataWindowManager->AirProps(2) * (TGapNew - state.dataWindowManager->TKelvin); QConvGap = RhoAir * AGap * VGap * 1008.0 * (TGapOutlet - TGapInlet); // Exclude convection to gap due to divider, if present; divider convection handled @@ -3862,7 +3862,7 @@ namespace WindowManager { Real64 gr; // Gap gas Grashof number Real64 pr; // Gap gas Prandtl number Real64 nu; // Gap gas Nusselt number - int ShadeFlag; // Shading flag + WinShadingFlag ShadeFlag; // Shading flag int BlNum; // Blind number int IGap; // Gap counter; 1 = gap on outer side of shade/blind, 2 = gap on inner side. int IGapInc; // Gap increment (0 or 1) @@ -3916,7 +3916,7 @@ namespace WindowManager { GapDepth = state.dataWindowManager->gap(1 + IGapInc); AGap = GapDepth * Surface(SurfNum).Width; - if (ShadeFlag == BGShadeOn) { + if (ShadeFlag == WinShadingFlag::BGShadeOn) { // Shade on ATopGap = dataMaterial.Material(MatNumSh).WinShadeTopOpeningMult * AGap; ABotGap = dataMaterial.Material(MatNumSh).WinShadeBottomOpeningMult * AGap; @@ -4152,7 +4152,7 @@ namespace WindowManager { Real64 gr; // Gap air Grashof number Real64 pr; // Gap air Prandtl number Real64 nu; // Gap air Nusselt number - int ShadeFlag; // Shading flag + WinShadingFlag ShadeFlag; // Shading flag int IGap; // Gap counter; 1 = gap on outer side of shade/blind, 2 = gap on inner side. int IGapInc; // Gap increment; =0, double glass, =1, triple glass // REAL(r64) :: AirProps(8) ! Air properties @@ -4642,7 +4642,7 @@ namespace WindowManager { Real64 const resgap(0.21); // Typical gap resistance (m2-K/W) int i; // Face counter - int ShadeFlag; // Shading flag + WinShadingFlag ShadeFlag; // Shading flag static Array1D rguess(11); // Combined radiative/convective resistance (m2-K/W) of //Tuned Made static // inside or outside air film, or gap Real64 restot; // Total window resistance including outside @@ -4699,9 +4699,9 @@ namespace WindowManager { // Initialize face temperatures of shade or blind, if present ShadeFlag = SurfWinShadingFlag(SurfNum); - if (SurfWinExtIntShadePrevTS(SurfNum) == IntShadeOn || SurfWinExtIntShadePrevTS(SurfNum) == IntBlindOn || - SurfWinExtIntShadePrevTS(SurfNum) == ExtShadeOn || SurfWinExtIntShadePrevTS(SurfNum) == ExtBlindOn || - SurfWinExtIntShadePrevTS(SurfNum) == BGShadeOn || SurfWinExtIntShadePrevTS(SurfNum) == BGBlindOn) { + if (SurfWinExtIntShadePrevTS(SurfNum) == WinShadingFlag::IntShadeOn || SurfWinExtIntShadePrevTS(SurfNum) == WinShadingFlag::IntBlindOn || + SurfWinExtIntShadePrevTS(SurfNum) == WinShadingFlag::ExtShadeOn || SurfWinExtIntShadePrevTS(SurfNum) == WinShadingFlag::ExtBlindOn || + SurfWinExtIntShadePrevTS(SurfNum) == WinShadingFlag::BGShadeOn || SurfWinExtIntShadePrevTS(SurfNum) == WinShadingFlag::BGBlindOn) { // Shade or blind is on during the previous TS; use previous-TS values of shade/blind face temps. // Note that if shade or blind is NOT on in the current TS the following two // temperature values, although calculated here, are not used. The shade/blind face numbers @@ -4721,15 +4721,15 @@ namespace WindowManager { // equal to tout. For between-glass shade/blind it is assumed to be equal to the // average temperature of the adjacent glass faces. - if (ShadeFlag == IntShadeOn || ShadeFlag == IntBlindOn) { + if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn) { state.dataWindowManager->thetas(state.dataWindowManager->nglface + 1) = state.dataWindowManager->tin + (AbsRadShade(1) + AbsRadShade(2)) / (2 * (state.dataWindowManager->hcin + hrad)); state.dataWindowManager->thetas(state.dataWindowManager->nglface + 2) = state.dataWindowManager->thetas(state.dataWindowManager->nglface + 1); } - if (ShadeFlag == ExtShadeOn || ShadeFlag == ExtBlindOn) { + if (ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::ExtBlindOn) { state.dataWindowManager->thetas(state.dataWindowManager->nglface + 1) = state.dataWindowManager->tout + (AbsRadShade(1) + AbsRadShade(2)) / (2 * (state.dataWindowManager->hcout + hrad)); state.dataWindowManager->thetas(state.dataWindowManager->nglface + 2) = state.dataWindowManager->thetas(state.dataWindowManager->nglface + 1); } - if (ShadeFlag == BGShadeOn || ShadeFlag == BGBlindOn) { + if (ShadeFlag == WinShadingFlag::BGShadeOn || ShadeFlag == WinShadingFlag::BGBlindOn) { // Between-glass shade/blind allowed only for double and triple glazing. // The factor 16.0 below is based on a combined convective/radiative heat transfer // coefficient on either side of the shade/blind of 8.0 W/m2-K -- about 1.4 Btu/h-ft2-F. @@ -5762,7 +5762,7 @@ namespace WindowManager { Real64 TOutRad; // Outside radiative temperature (K) Real64 TOutRadFr; // Effective outside radiative temperature for frame (K) Real64 TOutRadDiv; // Effective outside radiative temperature for divider (K) - int ShadeFlag; // Window shading flag + WinShadingFlag ShadeFlag; // Window shading flag Real64 FrameCon; // Frame conductance (W/m2-K) Real64 Afac; // Intermediate calculation variables @@ -5886,7 +5886,7 @@ namespace WindowManager { if (FrameDivider(FrDivNum).DividerProjectionOut > 0.0) { HOutRad *= (1.0 + 2.0 * SurfWinProjCorrDivOut(SurfNum)); - if (SurfWinShadingFlag(SurfNum) == ExtShadeOn) HOutConvDiv = SurfWinConvCoeffWithShade(SurfNum); + if (SurfWinShadingFlag(SurfNum) == WinShadingFlag::ExtShadeOn) HOutConvDiv = SurfWinConvCoeffWithShade(SurfNum); HOutConvDiv *= (1.0 + 2.0 * SurfWinProjCorrDivOut(SurfNum)); // Add long-wave from outside window surface absorbed by divider outside projection SurfWinDividerQRadOutAbs(SurfNum) += SurfWinProjCorrDivOut(SurfNum) * FrameDivider(FrDivNum).DividerEmis * @@ -5897,7 +5897,7 @@ namespace WindowManager { if (FrameDivider(FrDivNum).DividerProjectionIn > 0.0) { HInRad *= (1.0 + 2.0 * SurfWinProjCorrDivIn(SurfNum)); - if (SurfWinShadingFlag(SurfNum) == IntShadeOn) HInConvDiv = SurfWinConvCoeffWithShade(SurfNum); + if (SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntShadeOn) HInConvDiv = SurfWinConvCoeffWithShade(SurfNum); HInConvDiv *= (1.0 + 2.0 * SurfWinProjCorrDivIn(SurfNum)); // Add long-wave from inside window surface absorbed by divider inside projection SurfWinDividerQRadInAbs(SurfNum) += SurfWinProjCorrDivIn(SurfNum) * FrameDivider(FrDivNum).DividerEmis * EmisGlassIn * @@ -5929,7 +5929,7 @@ namespace WindowManager { // from the inside surface of the divider goes directly into the zone air -- i.e., the IR radiative // interaction between divider and shade is ignored due to the difficulty of calculating this interaction // at the same time that the interaction between glass and shade is calculated. - if (SurfWinShadingFlag(SurfNum) == IntShadeOn || SurfWinShadingFlag(SurfNum) == IntBlindOn) + if (SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntShadeOn || SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntBlindOn) SurfWinDividerHeatGain(SurfNum) = DividerHeatGain; DivTempOut = SurfWinDividerTempSurfOut(SurfNum) + state.dataWindowManager->TKelvin; } // End of check if window has dividers @@ -6040,7 +6040,7 @@ namespace WindowManager { Array1D hgap(5); // Conductive gap conductance [W/m2-K] Array1D hGapTot(5); // Combined radiative and conductive gap conductance [W/m2-K] Real64 Rbare; // Nominal center-of-glass resistance without air films [m2-K/W] - int ShadeFlag; // Shading flag + WinShadingFlag ShadeFlag; // Shading flag Real64 ShadeRes; // Thermal resistance of shade int MatOutside; // Material number of outside layer of construction int MatInside; // Material number of inside layer of construction @@ -6141,42 +6141,42 @@ namespace WindowManager { state.dataWindowManager->Outir = state.dataWindowManager->sigma * pow_4(state.dataWindowManager->tout); // Determine whether construction has an exterior or interior shade or blind - ShadeFlag = NoShade; + ShadeFlag = WinShadingFlag::NoShade; ShadeRes = 0.0; MatOutside = state.dataConstruction->Construct(ConstrNum).LayerPoint(1); MatInside = state.dataConstruction->Construct(ConstrNum).LayerPoint(TotLay); if (dataMaterial.Material(MatOutside).Group == 2) { // Exterior shade present MatShade = MatOutside; - ShadeFlag = ExtShadeOn; + ShadeFlag = WinShadingFlag::ExtShadeOn; // Set glazing outside convection coefficient to Window 4 still-air value state.dataWindowManager->hcout = 12.25; } else if (dataMaterial.Material(MatOutside).Group == 7) { // Exterior screen present MatShade = MatOutside; ScNum = dataMaterial.Material(MatShade).ScreenDataPtr; // Orphaned constructs with exterior screen are ignored - if (ScNum > 0) ShadeFlag = ExtScreenOn; + if (ScNum > 0) ShadeFlag = WinShadingFlag::ExtScreenOn; state.dataWindowManager->hcout = 12.25; } else if (dataMaterial.Material(MatOutside).Group == 5) { // Exterior blind present MatShade = MatOutside; - ShadeFlag = ExtBlindOn; + ShadeFlag = WinShadingFlag::ExtBlindOn; BlNum = dataMaterial.Material(MatShade).BlindDataPtr; state.dataWindowManager->hcout = 12.25; } else if (dataMaterial.Material(MatInside).Group == 2) { // Interior shade present MatShade = MatInside; - ShadeFlag = IntShadeOn; + ShadeFlag = WinShadingFlag::IntShadeOn; } else if (dataMaterial.Material(MatInside).Group == 5) { // Interior blind present MatShade = MatInside; BlNum = dataMaterial.Material(MatShade).BlindDataPtr; - ShadeFlag = IntBlindOn; + ShadeFlag = WinShadingFlag::IntBlindOn; } else if (TotGlassLay == 2) { - if (dataMaterial.Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(3)).Group == 2) ShadeFlag = BGShadeOn; - if (dataMaterial.Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(3)).Group == 5) ShadeFlag = BGBlindOn; + if (dataMaterial.Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(3)).Group == 2) ShadeFlag = WinShadingFlag::BGShadeOn; + if (dataMaterial.Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(3)).Group == 5) ShadeFlag = WinShadingFlag::BGBlindOn; } else if (TotGlassLay == 3) { - if (dataMaterial.Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(5)).Group == 2) ShadeFlag = BGShadeOn; - if (dataMaterial.Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(5)).Group == 5) ShadeFlag = BGBlindOn; + if (dataMaterial.Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(5)).Group == 2) ShadeFlag = WinShadingFlag::BGShadeOn; + if (dataMaterial.Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(5)).Group == 5) ShadeFlag = WinShadingFlag::BGBlindOn; } - if (ShadeFlag == BGShadeOn || ShadeFlag == BGBlindOn) { + if (ShadeFlag == WinShadingFlag::BGShadeOn || ShadeFlag == WinShadingFlag::BGBlindOn) { errFlag = 2; return; } @@ -6184,10 +6184,10 @@ namespace WindowManager { TSolNorm = POLYF(1.0, state.dataConstruction->Construct(ConstrNum).TransSolBeamCoef); TVisNorm = POLYF(1.0, state.dataConstruction->Construct(ConstrNum).TransVisBeamCoef); AbsBeamShadeNorm = 0.0; - if (ShadeFlag == IntShadeOn || ShadeFlag == ExtShadeOn) { // Exterior or interior shade on + if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn) { // Exterior or interior shade on AbsBeamShadeNorm = POLYF(1.0, state.dataConstruction->Construct(ConstrNum).AbsBeamShadeCoef); // Exterior blind or screen or interior blind on - } else if (ShadeFlag == IntBlindOn || ShadeFlag == ExtBlindOn || ShadeFlag == ExtScreenOn) { + } else if (ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { // Find unshaded construction that goes with this construction w/blind or screen ConstrNumBare = 0; for (ConstrNum1 = 1; ConstrNum1 <= TotConstructs; ++ConstrNum1) { @@ -6199,7 +6199,7 @@ namespace WindowManager { ConstrNumBare = ConstrNum1; for (Lay = 1; Lay <= state.dataConstruction->Construct(ConstrNum1).TotLayers; ++Lay) { LayPtr = state.dataConstruction->Construct(ConstrNum1).LayerPoint(Lay); - if (ShadeFlag == IntBlindOn) { // The shaded construction has an interior blind + if (ShadeFlag == WinShadingFlag::IntBlindOn) { // The shaded construction has an interior blind LayPtrSh = state.dataConstruction->Construct(ConstrNum).LayerPoint(Lay); } else { // The shaded construction has an exterior blind or screen LayPtrSh = state.dataConstruction->Construct(ConstrNum).LayerPoint(Lay + 1); @@ -6217,7 +6217,7 @@ namespace WindowManager { TBmBm = POLYF(1.0, state.dataConstruction->Construct(ConstrNumBare).TransSolBeamCoef); TBmBmVis = POLYF(1.0, state.dataConstruction->Construct(ConstrNumBare).TransVisBeamCoef); - if (ShadeFlag == ExtScreenOn) { + if (ShadeFlag == WinShadingFlag::ExtScreenOn) { // Don't need to call subroutine, use normal incident properties (SUBROUTINE CalcNominalWindowCond) // Last call to CalcScreenTransmittance(ISurf) was done at direct normal angle (0,0) in CalcWindowScreenProperties TScBmBm = SurfaceScreens(ScNum).BmBmTrans; @@ -6249,7 +6249,7 @@ namespace WindowManager { TBlBmDifVis = InterpProfSlatAng(0.0, SlatAng, VarSlats, Blind(BlNum).VisFrontBeamDiffTrans); TDif = state.dataConstruction->Construct(ConstrNumBare).TransDiff; TDifVis = state.dataConstruction->Construct(ConstrNumBare).TransDiffVis; - if (ShadeFlag == IntBlindOn) { + if (ShadeFlag == WinShadingFlag::IntBlindOn) { RGlDiffBack = state.dataConstruction->Construct(ConstrNumBare).ReflectSolDiffBack; RGlDiffBackVis = state.dataConstruction->Construct(ConstrNumBare).ReflectVisDiffBack; RhoBlFront = InterpProfSlatAng(0.0, SlatAng, VarSlats, Blind(BlNum).SolFrontBeamDiffRefl); @@ -6266,7 +6266,7 @@ namespace WindowManager { TVisNorm = TBmBmVis * (TBlBmBm + TBlBmDifVis + TBlDifDifVis * RhoBlFrontVis * RGlDiffBackVis / (1.0 - RhoBlDiffFrontVis * RGlDiffBackVis)); } // (IntBlind) - if (ShadeFlag == ExtBlindOn) { + if (ShadeFlag == WinShadingFlag::ExtBlindOn) { TBlBmBm = BlindBeamBeamTrans(0.0, SlatAng, Blind(BlNum).SlatWidth, Blind(BlNum).SlatSeparation, Blind(BlNum).SlatThickness); RGlFront = POLYF(1.0, state.dataConstruction->Construct(ConstrNumBare).ReflSolBeamFrontCoef); RGlFrontVis = POLYF(1.0, state.dataConstruction->Construct(ConstrNumBare).ReflSolBeamFrontCoef); @@ -6317,16 +6317,16 @@ namespace WindowManager { state.dataWindowManager->tir(2 * IGlass - 1) = dataMaterial.Material(LayPtr).TransThermal; state.dataWindowManager->tir(2 * IGlass) = dataMaterial.Material(LayPtr).TransThermal; AbsBeamNorm(IGlass) = POLYF(1.0, state.dataConstruction->Construct(ConstrNum).AbsBeamCoef({1, 6}, IGlass)); - if (ShadeFlag == IntBlindOn) { // Interior blind on + if (ShadeFlag == WinShadingFlag::IntBlindOn) { // Interior blind on AbsBeamNorm(IGlass) = POLYF(1.0, state.dataConstruction->Construct(ConstrNumBare).AbsBeamCoef({1, 6}, IGlass)); AGlDiffBack = state.dataConstruction->Construct(ConstrNumBare).AbsDiffBack(IGlass); AbsBeamNorm(IGlass) += TBmBm * AGlDiffBack * RhoBlFront / (1.0 - RhoBlFront * RGlDiffBack); - } else if (ShadeFlag == ExtBlindOn) { // Exterior blind on + } else if (ShadeFlag == WinShadingFlag::ExtBlindOn) { // Exterior blind on AbsBeamNorm(IGlass) = POLYF(1.0, state.dataConstruction->Construct(ConstrNumBare).AbsBeamCoef({1, 6}, IGlass)); AbsBeamNorm(IGlass) = TBlBmBm * AbsBeamNorm(IGlass) + (TBlBmBm * RGlFront * RhoBlBack + TBlBmDif) * state.dataConstruction->Construct(ConstrNumBare).AbsDiff(IGlass) / (1.0 - RGlDiffFront * RhoBlDiffBack); - } else if (ShadeFlag == ExtScreenOn) { // Exterior screen on + } else if (ShadeFlag == WinShadingFlag::ExtScreenOn) { // Exterior screen on AbsBeamNorm(IGlass) = POLYF(1.0, state.dataConstruction->Construct(ConstrNumBare).AbsBeamCoef({1, 6}, IGlass)); AbsBeamNorm(IGlass) = TScBmBm * AbsBeamNorm(IGlass) + (TScBmBm * RGlFront * RScBack + TScBmDif) * state.dataConstruction->Construct(ConstrNumBare).AbsDiff(IGlass) / @@ -6387,7 +6387,7 @@ namespace WindowManager { hInRad = state.dataWindowManager->emis(state.dataWindowManager->nglface) * state.dataWindowManager->sigma * 0.5 * pow_3(state.dataWindowManager->tin + state.dataWindowManager->thetas(state.dataWindowManager->nglface)); rIn = 1.0 / (hInRad + state.dataWindowManager->hcin); - if (!(ShadeFlag == IntShadeOn || ShadeFlag == IntBlindOn)) AbsBeamShadeNorm = 0.0; + if (!(ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn)) AbsBeamShadeNorm = 0.0; { auto const SELECT_CASE_var(state.dataWindowManager->ngllayer); diff --git a/src/EnergyPlus/WindowManagerExteriorThermal.cc b/src/EnergyPlus/WindowManagerExteriorThermal.cc index 326cbb73c1d..bd49ee13b8f 100644 --- a/src/EnergyPlus/WindowManagerExteriorThermal.cc +++ b/src/EnergyPlus/WindowManagerExteriorThermal.cc @@ -109,9 +109,9 @@ namespace WindowManager { // Interior and exterior shading layers have gas between them and IGU but that gas // was not part of construction so it needs to be increased by one - if (SurfWinShadingFlag(SurfNum) == IntShadeOn || SurfWinShadingFlag(SurfNum) == ExtShadeOn || SurfWinShadingFlag(SurfNum) == IntBlindOn || - SurfWinShadingFlag(SurfNum) == ExtBlindOn || SurfWinShadingFlag(SurfNum) == ExtScreenOn || SurfWinShadingFlag(SurfNum) == BGShadeOn || - SurfWinShadingFlag(SurfNum) == BGBlindOn) { + if (SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntShadeOn || SurfWinShadingFlag(SurfNum) == WinShadingFlag::ExtShadeOn || SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntBlindOn || + SurfWinShadingFlag(SurfNum) == WinShadingFlag::ExtBlindOn || SurfWinShadingFlag(SurfNum) == WinShadingFlag::ExtScreenOn || SurfWinShadingFlag(SurfNum) == WinShadingFlag::BGShadeOn || + SurfWinShadingFlag(SurfNum) == WinShadingFlag::BGBlindOn) { ++totSolidLayers; } @@ -140,7 +140,7 @@ namespace WindowManager { ++i; } SurfInsideTemp = aTemp - DataGlobalConstants::KelvinConv(); - if (SurfWinShadingFlag(SurfNum) == IntShadeOn || SurfWinShadingFlag(SurfNum) == IntBlindOn) { + if (SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntShadeOn || SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntBlindOn) { auto EffShBlEmiss = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), window.EffShBlindEmiss); auto EffGlEmiss = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), window.EffGlassEmiss); SurfWinEffInsSurfTemp(SurfNum) = @@ -149,7 +149,7 @@ namespace WindowManager { } HConvIn(SurfNum) = aSystem->getHc(Environment::Indoor); - if (SurfWinShadingFlag(SurfNum) == IntShadeOn || SurfWinShadingFlag(SurfNum) == IntBlindOn || aFactory.isInteriorShade()) { + if (SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntShadeOn || SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntBlindOn || aFactory.isInteriorShade()) { // It is not clear why EnergyPlus keeps this interior calculations separately for interior shade. This does create different // solution from heat transfer from tarcog itself. Need to confirm with LBNL team about this approach. Note that heat flow // through shade (consider case when openings are zero) is different from heat flow obtained by these equations. Will keep @@ -247,23 +247,23 @@ namespace WindowManager { m_ConstructionNumber = m_Surface.Construction; m_ShadePosition = ShadePosition::NoShade; - if (ShadeFlag == IntShadeOn || ShadeFlag == ExtShadeOn || ShadeFlag == IntBlindOn || ShadeFlag == ExtBlindOn || ShadeFlag == BGShadeOn || - ShadeFlag == BGBlindOn || ShadeFlag == ExtScreenOn) { + if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::BGShadeOn || + ShadeFlag == WinShadingFlag::BGBlindOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { m_ConstructionNumber = m_Surface.activeShadedConstruction; if (SurfWinStormWinFlag(t_SurfNum) > 0) m_ConstructionNumber = m_Surface.activeStormWinShadedConstruction; } m_TotLay = getNumOfLayers(state); - if (ShadeFlag == IntShadeOn || ShadeFlag == IntBlindOn) { + if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn) { m_ShadePosition = ShadePosition::Interior; } - if (ShadeFlag == ExtShadeOn || ShadeFlag == ExtBlindOn || ShadeFlag == ExtScreenOn) { + if (ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { m_ShadePosition = ShadePosition::Exterior; } - if (ShadeFlag == BGShadeOn || ShadeFlag == BGBlindOn) { + if (ShadeFlag == WinShadingFlag::BGShadeOn || ShadeFlag == WinShadingFlag::BGBlindOn) { m_ShadePosition = ShadePosition::Between; } } @@ -302,9 +302,9 @@ namespace WindowManager { { auto ConstrNum = m_Surface.Construction; - if (SurfWinShadingFlag(m_SurfNum) == IntShadeOn || SurfWinShadingFlag(m_SurfNum) == ExtShadeOn || SurfWinShadingFlag(m_SurfNum) == IntBlindOn || - SurfWinShadingFlag(m_SurfNum) == ExtBlindOn || SurfWinShadingFlag(m_SurfNum) == BGShadeOn || SurfWinShadingFlag(m_SurfNum) == BGBlindOn || - SurfWinShadingFlag(m_SurfNum) == ExtScreenOn) { + if (SurfWinShadingFlag(m_SurfNum) == WinShadingFlag::IntShadeOn || SurfWinShadingFlag(m_SurfNum) == WinShadingFlag::ExtShadeOn || SurfWinShadingFlag(m_SurfNum) == WinShadingFlag::IntBlindOn || + SurfWinShadingFlag(m_SurfNum) == WinShadingFlag::ExtBlindOn || SurfWinShadingFlag(m_SurfNum) == WinShadingFlag::BGShadeOn || SurfWinShadingFlag(m_SurfNum) == WinShadingFlag::BGBlindOn || + SurfWinShadingFlag(m_SurfNum) == WinShadingFlag::ExtScreenOn) { ConstrNum = m_Surface.activeShadedConstruction; if (SurfWinStormWinFlag(m_SurfNum) > 0) ConstrNum = m_Surface.activeStormWinShadedConstruction; } @@ -498,10 +498,10 @@ namespace WindowManager { auto aGas = getAir(); auto thickness = 0.0; - if (SurfWinShadingFlag(m_SurfNum) == IntBlindOn || SurfWinShadingFlag(m_SurfNum) == ExtBlindOn) { + if (SurfWinShadingFlag(m_SurfNum) == WinShadingFlag::IntBlindOn || SurfWinShadingFlag(m_SurfNum) == WinShadingFlag::ExtBlindOn) { thickness = Blind(SurfWinBlindNumber(m_SurfNum)).BlindToGlassDist; } - if (SurfWinShadingFlag(m_SurfNum) == IntShadeOn || SurfWinShadingFlag(m_SurfNum) == ExtShadeOn || SurfWinShadingFlag(m_SurfNum) == ExtScreenOn) { + if (SurfWinShadingFlag(m_SurfNum) == WinShadingFlag::IntShadeOn || SurfWinShadingFlag(m_SurfNum) == WinShadingFlag::ExtShadeOn || SurfWinShadingFlag(m_SurfNum) == WinShadingFlag::ExtScreenOn) { auto material = getLayerMaterial(state, t_Index); thickness = material->WinShadeToGlassDist; } diff --git a/src/EnergyPlus/ZoneTempPredictorCorrector.cc b/src/EnergyPlus/ZoneTempPredictorCorrector.cc index 114215878a6..b93d0cf9280 100644 --- a/src/EnergyPlus/ZoneTempPredictorCorrector.cc +++ b/src/EnergyPlus/ZoneTempPredictorCorrector.cc @@ -6333,7 +6333,7 @@ namespace ZoneTempPredictorCorrector { auto const shading_flag(SurfWinShadingFlag(SurfNum)); // Add to the convective internal gains - if (shading_flag == IntShadeOn || shading_flag == IntBlindOn) { + if (shading_flag == WinShadingFlag::IntShadeOn || shading_flag == WinShadingFlag::IntBlindOn) { // The shade area covers the area of the glazing plus the area of the dividers. Area += SurfWinDividerArea(SurfNum); // If interior shade or blind is present it is assumed that both the convective and IR radiative gain @@ -6347,7 +6347,7 @@ namespace ZoneTempPredictorCorrector { if (state.dataConstruction->Construct(Surface(SurfNum).Construction).WindowTypeEQL) SumIntGain += SurfWinOtherConvHeatGain(SurfNum); // Convective heat gain from natural convection in gap between glass and interior shade or blind - if (shading_flag == IntShadeOn || shading_flag == IntBlindOn) SumIntGain += SurfWinConvHeatFlowNatural(SurfNum); + if (shading_flag == WinShadingFlag::IntShadeOn || shading_flag == WinShadingFlag::IntBlindOn) SumIntGain += SurfWinConvHeatFlowNatural(SurfNum); // Convective heat gain from airflow window if (SurfWinAirflowThisTS(SurfNum) > 0.0) { @@ -6375,7 +6375,7 @@ namespace ZoneTempPredictorCorrector { HA += HA_surf; } - if (SurfWinDividerArea(SurfNum) > 0.0 && shading_flag != IntShadeOn && shading_flag != IntBlindOn) { + if (SurfWinDividerArea(SurfNum) > 0.0 && shading_flag != WinShadingFlag::IntShadeOn && shading_flag != WinShadingFlag::IntBlindOn) { // Window divider contribution (only from shade or blind for window with divider and interior shade or blind) Real64 const HA_surf(HConvIn(SurfNum) * SurfWinDividerArea(SurfNum) * (1.0 + 2.0 * SurfWinProjCorrDivIn(SurfNum))); SumHATsurf += HA_surf * SurfWinDividerTempSurfIn(SurfNum); @@ -6665,7 +6665,7 @@ namespace ZoneTempPredictorCorrector { if (Surface(SurfNum).Class == SurfaceClass::Window) { // Add to the convective internal gains - if (SurfWinShadingFlag(SurfNum) == IntShadeOn || SurfWinShadingFlag(SurfNum) == IntBlindOn) { + if (SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntShadeOn || SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntBlindOn) { // The shade area covers the area of the glazing plus the area of the dividers. Area += SurfWinDividerArea(SurfNum); // If interior shade or blind is present it is assumed that both the convective and IR radiative gain @@ -6679,7 +6679,7 @@ namespace ZoneTempPredictorCorrector { if (state.dataConstruction->Construct(Surface(SurfNum).Construction).WindowTypeEQL) SumIntGains += SurfWinOtherConvHeatGain(SurfNum); // Convective heat gain from natural convection in gap between glass and interior shade or blind - if (SurfWinShadingFlag(SurfNum) == IntShadeOn || SurfWinShadingFlag(SurfNum) == IntBlindOn) + if (SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntShadeOn || SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntBlindOn) SumIntGains += SurfWinConvHeatFlowNatural(SurfNum); // Convective heat gain from airflow window @@ -6698,8 +6698,8 @@ namespace ZoneTempPredictorCorrector { (SurfWinFrameTempSurfIn(SurfNum) - RefAirTemp); } - if (SurfWinDividerArea(SurfNum) > 0.0 && SurfWinShadingFlag(SurfNum) != IntShadeOn && - SurfWinShadingFlag(SurfNum) != IntBlindOn) { + if (SurfWinDividerArea(SurfNum) > 0.0 && SurfWinShadingFlag(SurfNum) != WinShadingFlag::IntShadeOn && + SurfWinShadingFlag(SurfNum) != WinShadingFlag::IntBlindOn) { // Window divider contribution (only from shade or blind for window with divider and interior shade or blind) SumHADTsurfs += HConvIn(SurfNum) * SurfWinDividerArea(SurfNum) * (1.0 + 2.0 * SurfWinProjCorrDivIn(SurfNum)) * (SurfWinDividerTempSurfIn(SurfNum) - RefAirTemp); diff --git a/tst/EnergyPlus/unit/DaylightingManager.unit.cc b/tst/EnergyPlus/unit/DaylightingManager.unit.cc index a89aab7788e..94ddf32bbe5 100644 --- a/tst/EnergyPlus/unit/DaylightingManager.unit.cc +++ b/tst/EnergyPlus/unit/DaylightingManager.unit.cc @@ -1380,12 +1380,13 @@ TEST_F(EnergyPlusFixture, DaylightingManager_DayltgInteriorIllum_Test) // Window5 model - expect 100 for unshaded and 50 for shaded (10 and 5 for RefPt2) SurfWinWindowModelType(IWin) = Window5DetailedModel; - SurfWinShadingFlag(IWin) = DataSurfaces::NoShade; + SurfWinShadingFlag(IWin) = DataSurfaces::WinShadingFlag::NoShade; DaylightingManager::DayltgInteriorIllum(*state, ZoneNum); EXPECT_NEAR(state->dataDaylightingManager->DaylIllum(1), 100.0, 0.001); EXPECT_NEAR(state->dataDaylightingManager->DaylIllum(2), 10.0, 0.001); - SurfWinShadingFlag(IWin) = DataSurfaces::ExtBlindOn; + SurfWinShadingFlag(IWin) = DataSurfaces::WinShadingFlag::ExtBlindOn; + SurfWinShaded(IWin) = true; DaylightingManager::DayltgInteriorIllum(*state, ZoneNum); EXPECT_NEAR(state->dataDaylightingManager->DaylIllum(1), 50.0, 0.001); EXPECT_NEAR(state->dataDaylightingManager->DaylIllum(2), 5.0, 0.001); @@ -1393,12 +1394,14 @@ TEST_F(EnergyPlusFixture, DaylightingManager_DayltgInteriorIllum_Test) // BSDF model - expect 100 for unshaded and 100 for shaded (10 for RefPt2 // BSDF does shading differently, it's integrated in the base state SurfWinWindowModelType(IWin) = WindowBSDFModel; - SurfWinShadingFlag(IWin) = DataSurfaces::NoShade; + SurfWinShadingFlag(IWin) = DataSurfaces::WinShadingFlag::NoShade; + SurfWinShaded(IWin) = false; DaylightingManager::DayltgInteriorIllum(*state, ZoneNum); EXPECT_NEAR(state->dataDaylightingManager->DaylIllum(1), 100.0, 0.001); EXPECT_NEAR(state->dataDaylightingManager->DaylIllum(2), 10.0, 0.001); - SurfWinShadingFlag(IWin) = DataSurfaces::ExtBlindOn; + SurfWinShadingFlag(IWin) = DataSurfaces::WinShadingFlag::ExtBlindOn; + SurfWinShaded(IWin) = true; DaylightingManager::DayltgInteriorIllum(*state, ZoneNum); EXPECT_NEAR(state->dataDaylightingManager->DaylIllum(1), 100.0, 0.001); EXPECT_NEAR(state->dataDaylightingManager->DaylIllum(2), 10.0, 0.001); diff --git a/tst/EnergyPlus/unit/EMSManager.unit.cc b/tst/EnergyPlus/unit/EMSManager.unit.cc index 2aa750c049d..aa0108428a1 100644 --- a/tst/EnergyPlus/unit/EMSManager.unit.cc +++ b/tst/EnergyPlus/unit/EMSManager.unit.cc @@ -1630,7 +1630,7 @@ TEST_F(EnergyPlusFixture, EMSManager_TestWindowShadingControlExteriorScreenOptio DataSurfaces::SurfWinShadingFlagEMSOn(2) = true; DataSurfaces::SurfWinShadingFlagEMSValue(2) = 1.0; SolarShading::WindowShadingManager(*state); - EXPECT_EQ(DataSurfaces::SurfWinShadingFlag(2), DataSurfaces::SurfWinShadingFlagEMSValue(2)); + EXPECT_EQ(int(DataSurfaces::SurfWinShadingFlag(2)), DataSurfaces::SurfWinShadingFlagEMSValue(2)); } TEST_F(EnergyPlusFixture, EMS_WeatherDataActuators) diff --git a/tst/EnergyPlus/unit/HeatBalanceSurfaceManager.unit.cc b/tst/EnergyPlus/unit/HeatBalanceSurfaceManager.unit.cc index 7c47d43f0a2..6ae0e6e9953 100644 --- a/tst/EnergyPlus/unit/HeatBalanceSurfaceManager.unit.cc +++ b/tst/EnergyPlus/unit/HeatBalanceSurfaceManager.unit.cc @@ -280,7 +280,7 @@ TEST_F(EnergyPlusFixture, HeatBalanceSurfaceManager_ComputeIntThermalAbsorpFacto DataSurfaces::Surface(1).HeatTransSurf = true; DataSurfaces::Surface(1).Construction = 1; - DataSurfaces::SurfWinShadingFlag(1) = 0; + DataSurfaces::SurfWinShadingFlag(1) = DataSurfaces::WinShadingFlag::ShadeOff; state->dataConstruction->Construct(1).InsideAbsorpThermal = 0.9; state->dataConstruction->Construct(1).TransDiff = 0.0; DataSurfaces::Surface(1).MaterialMovInsulInt = 1; From d33eb73447326215daa30ddb9cbb78c3510d0e88 Mon Sep 17 00:00:00 2001 From: xuanluo113 Date: Thu, 10 Dec 2020 09:56:33 -0800 Subject: [PATCH 07/76] fix a bug --- src/EnergyPlus/SolarShading.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EnergyPlus/SolarShading.cc b/src/EnergyPlus/SolarShading.cc index 1cb71fea6fd..a81537e183b 100644 --- a/src/EnergyPlus/SolarShading.cc +++ b/src/EnergyPlus/SolarShading.cc @@ -6911,7 +6911,7 @@ namespace SolarShading { TransBeamWin = 1.0; AbsBeamWinEQL = 0.0; AbsBeamTotWin = 0.0; - } else if (SurfWinShaded(SurfNum)) { + } else if (!SurfWinShaded(SurfNum)) { for (int Lay = 1; Lay <= NBackGlass; ++Lay) { AbsBeamWin(Lay) = POLYF(CosIncBack, state.dataConstruction->Construct(ConstrNumBack).AbsBeamBackCoef({1, 6}, Lay)); } From 79aa3d87fa3d2e2b9e8395ca2741ec6ea5e8cc9d Mon Sep 17 00:00:00 2001 From: xuanluo113 Date: Thu, 10 Dec 2020 12:13:19 -0800 Subject: [PATCH 08/76] fix another --- src/EnergyPlus/SolarShading.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EnergyPlus/SolarShading.cc b/src/EnergyPlus/SolarShading.cc index a81537e183b..e015554a6ad 100644 --- a/src/EnergyPlus/SolarShading.cc +++ b/src/EnergyPlus/SolarShading.cc @@ -8762,6 +8762,7 @@ namespace SolarShading { int ShadingType = WindowShadingControl(IShadingCtrl).ShadingType; // Type of shading (interior shade, interior blind, etc.) SurfWinShadingFlag(ISurf) = WinShadingFlag::ShadeOff; // Initialize shading flag to off + SurfWinShaded(ISurf) = false; int IZone = Surface(ISurf).Zone; // Setpoint for shading @@ -8915,7 +8916,6 @@ namespace SolarShading { if (state.dataEnvrn->SunIsUp && SchedAllowsControl) { SurfWinShadingFlag(ISurf) = ShType; SurfWinGlareControlIsActive(ISurf) = true; -// SurfWinShadingFlag(ISurf) = WinShadingFlag::GlassConditionallyLightened; } } else if (SELECT_CASE_var == WSCT_OnNightLoOutTemp_OffDay) { // 'OnNightIfLowOutdoorTempAndOffDay' From 8664ca3c4b8a2c2d253bc6460f666d181a8f283e Mon Sep 17 00:00:00 2001 From: xuanluo113 Date: Fri, 11 Dec 2020 11:39:32 -0800 Subject: [PATCH 09/76] fix more --- src/EnergyPlus/DaylightingManager.cc | 2 +- src/EnergyPlus/SolarShading.cc | 36 ++++++++++++++++++++++++---- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/src/EnergyPlus/DaylightingManager.cc b/src/EnergyPlus/DaylightingManager.cc index 92d7a816ef5..bce6e47ba15 100644 --- a/src/EnergyPlus/DaylightingManager.cc +++ b/src/EnergyPlus/DaylightingManager.cc @@ -6798,7 +6798,7 @@ namespace EnergyPlus::DaylightingManager { // Recalculate illuminance and glare with shading on this window. // For switchable glazings, this is the fully switched (dark) state for (IL = 1; IL <= NREFPT; ++IL) { - if (SurfWinShadingFlag(IWin) != WinShadingFlag::SwitchableGlazing) { + if (SurfWinShadingFlag(IWin) != WinShadingFlag::SwitchableGlazing || SurfWinGlareControlIsActive(IWin)) { // for non switchable glazings or switchable glazings not switched yet (still in clear state) // SurfaceWindow(IWin)%ShadingFlag = WinShadingFlag::GlassConditionallyLightened RDAYIL(IL, igroup) = state.dataDaylightingManager->DaylIllum(IL) - WDAYIL(1, IL, igroup) + WDAYIL(2, IL, igroup); diff --git a/src/EnergyPlus/SolarShading.cc b/src/EnergyPlus/SolarShading.cc index e015554a6ad..d3d070f71e3 100644 --- a/src/EnergyPlus/SolarShading.cc +++ b/src/EnergyPlus/SolarShading.cc @@ -8834,6 +8834,8 @@ namespace SolarShading { if (state.dataEnvrn->SunIsUp) { if (SolarOnWindow > SetPoint && SchedAllowsControl) { SurfWinShadingFlag(ISurf) = ShType; + } else if (GlareControlIsActive) { + SurfWinGlareControlIsActive(ISurf) = true; } } @@ -8842,18 +8844,24 @@ namespace SolarShading { if (state.dataEnvrn->SunIsUp) { if (HorizSolar > SetPoint && SchedAllowsControl) { SurfWinShadingFlag(ISurf) = ShType; + } else if (GlareControlIsActive) { + SurfWinGlareControlIsActive(ISurf) = true; } } } else if (SELECT_CASE_var == WSCT_HiOutAirTemp) { // 'OnIfHighOutdoorAirTemperature' if (Surface(ISurf).OutDryBulbTemp > SetPoint && SchedAllowsControl) { SurfWinShadingFlag(ISurf) = ShType; + } else if (GlareControlIsActive) { + SurfWinGlareControlIsActive(ISurf) = true; } } else if (SELECT_CASE_var == WSCT_HiZoneAirTemp) { // 'OnIfHighZoneAirTemperature' ! Previous time step zone air temperature if (MAT(IZone) > SetPoint && SchedAllowsControl) { SurfWinShadingFlag(ISurf) = ShType; + } else if (GlareControlIsActive) { + SurfWinGlareControlIsActive(ISurf) = true; } } else if (SELECT_CASE_var == WSCT_OnHiOutTemp_HiSolarWindow) { @@ -8862,6 +8870,8 @@ namespace SolarShading { if (Surface(ISurf).OutDryBulbTemp > SetPoint && SolarOnWindow > SetPoint2 && SchedAllowsControl) { SurfWinShadingFlag(ISurf) = ShType; + } else if (GlareControlIsActive) { + SurfWinGlareControlIsActive(ISurf) = true; } } @@ -8871,6 +8881,8 @@ namespace SolarShading { if (Surface(ISurf).OutDryBulbTemp > SetPoint && HorizSolar > SetPoint2 && SchedAllowsControl) { SurfWinShadingFlag(ISurf) = ShType; + } else if (GlareControlIsActive) { + SurfWinGlareControlIsActive(ISurf) = true; } } @@ -8879,6 +8891,8 @@ namespace SolarShading { if (state.dataEnvrn->SunIsUp) { if (MAT(IZone) > SetPoint && SolarOnWindow > SetPoint2 && SchedAllowsControl) { SurfWinShadingFlag(ISurf) = ShType; + } else if (GlareControlIsActive) { + SurfWinGlareControlIsActive(ISurf) = true; } } @@ -8887,6 +8901,8 @@ namespace SolarShading { if (state.dataEnvrn->SunIsUp) { if (MAT(IZone) > SetPoint && HorizSolar > SetPoint2 && SchedAllowsControl) { SurfWinShadingFlag(ISurf) = ShType; + } else if (GlareControlIsActive) { + SurfWinGlareControlIsActive(ISurf) = true; } } @@ -8897,6 +8913,8 @@ namespace SolarShading { if (!state.dataGlobal->BeginSimFlag) { if (SNLoadCoolRate(IZone) > SetPoint && SchedAllowsControl) { SurfWinShadingFlag(ISurf) = ShType; + } else if (GlareControlIsActive) { + SurfWinGlareControlIsActive(ISurf) = true; } } @@ -8921,17 +8939,23 @@ namespace SolarShading { } else if (SELECT_CASE_var == WSCT_OnNightLoOutTemp_OffDay) { // 'OnNightIfLowOutdoorTempAndOffDay' if (!state.dataEnvrn->SunIsUp && Surface(ISurf).OutDryBulbTemp < SetPoint && SchedAllowsControl) { SurfWinShadingFlag(ISurf) = ShType; + } else if (GlareControlIsActive) { + SurfWinGlareControlIsActive(ISurf) = true; } } else if (SELECT_CASE_var == WSCT_OnNightLoInTemp_OffDay) { // 'OnNightIfLowInsideTempAndOffDay') if (!state.dataEnvrn->SunIsUp && MAT(IZone) < SetPoint && SchedAllowsControl) { SurfWinShadingFlag(ISurf) = ShType; + } else if (GlareControlIsActive) { + SurfWinGlareControlIsActive(ISurf) = true; } } else if (SELECT_CASE_var == WSCT_OnNightIfHeating_OffDay) { // 'OnNightIfHeatingAndOffDay' if (!state.dataGlobal->BeginSimFlag) { if (!state.dataEnvrn->SunIsUp && SNLoadHeatRate(IZone) > SetPoint && SchedAllowsControl) { SurfWinShadingFlag(ISurf) = ShType; + } else if (GlareControlIsActive) { + SurfWinGlareControlIsActive(ISurf) = true; } } @@ -8944,6 +8968,8 @@ namespace SolarShading { } else { // Day if (SNLoadCoolRate(IZone) > 0.0 && SchedAllowsControl) { SurfWinShadingFlag(ISurf) = ShType; + } else if (GlareControlIsActive) { + SurfWinGlareControlIsActive(ISurf) = true; } } } @@ -8957,6 +8983,8 @@ namespace SolarShading { } else { // Day if (SNLoadCoolRate(IZone) > 0.0 && SchedAllowsControl) { SurfWinShadingFlag(ISurf) = ShType; + } else if (GlareControlIsActive) { + SurfWinGlareControlIsActive(ISurf) = true; } } } @@ -8966,6 +8994,8 @@ namespace SolarShading { if (!state.dataGlobal->BeginSimFlag) { if (state.dataEnvrn->SunIsUp && SNLoadCoolRate(IZone) > 0.0 && SchedAllowsControl) { if (SolarOnWindow > SetPoint) SurfWinShadingFlag(ISurf) = ShType; + } else if (GlareControlIsActive) { + SurfWinGlareControlIsActive(ISurf) = true; } } @@ -8976,14 +9006,12 @@ namespace SolarShading { if (SolarOnWindow > SetPoint) SurfWinShadingFlag(ISurf) = ShType; } else if (!state.dataEnvrn->SunIsUp && SchedAllowsControl) { SurfWinShadingFlag(ISurf) = ShType; + } else if (GlareControlIsActive) { + SurfWinGlareControlIsActive(ISurf) = true; } } } - if (GlareControlIsActive) { - SurfWinGlareControlIsActive(ISurf) = true; - } - // Set switching factor to fully switched if ShadingFlag = 2 if (SurfWinShadingFlag(ISurf) == WinShadingFlag::SwitchableGlazing) { SurfWinSwitchingFactor(ISurf) = 1.0; From f455c3ee108c7488723be0336c4f571053500313 Mon Sep 17 00:00:00 2001 From: xuanluo113 Date: Fri, 11 Dec 2020 22:52:55 -0800 Subject: [PATCH 10/76] fix more --- src/EnergyPlus/DaylightingManager.cc | 9 +++++---- src/EnergyPlus/HeatBalanceSurfaceManager.cc | 2 +- src/EnergyPlus/SolarShading.cc | 10 ++++++++-- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/EnergyPlus/DaylightingManager.cc b/src/EnergyPlus/DaylightingManager.cc index bce6e47ba15..a965cc0920d 100644 --- a/src/EnergyPlus/DaylightingManager.cc +++ b/src/EnergyPlus/DaylightingManager.cc @@ -5651,9 +5651,9 @@ namespace EnergyPlus::DaylightingManager { for (loop = 1; loop <= state.dataDaylightingData->ZoneDaylight(ZoneNum).NumOfDayltgExtWins; ++loop) { IWin = state.dataDaylightingData->ZoneDaylight(ZoneNum).DayltgExtWinSurfNums(loop); IS = 1; - if ((SurfWinWindowModelType(IWin) != WindowBSDFModel) && - ((SurfWinShaded(IWin) && !SurfWinGlareControlIsActive(IWin)) || SurfWinSolarDiffusing(IWin))) + if ((SurfWinWindowModelType(IWin) != WindowBSDFModel) && ((SurfWinShaded(IWin) && !SurfWinGlareControlIsActive(IWin)) || SurfWinSolarDiffusing(IWin))) { IS = 2; + } // Conversion from ft-L to cd/m2, with cd/m2 = 0.2936 ft-L, gives the 0.4794 factor // below, which is (0.2936)**0.6 GTOT1 = 0.4794 * (std::pow(state.dataDaylightingData->ZoneDaylight(ZoneNum).SourceLumFromWinAtRefPt(loop, IS, IL), 1.6)) * @@ -6571,6 +6571,7 @@ namespace EnergyPlus::DaylightingManager { state.dataDaylightingData->ZoneDaylight(ZoneNum).BacLum(IL) += state.dataDaylightingData->ZoneDaylight(ZoneNum).BackLumFromWinAtRefPt(loop, IS, IL); } } // End of second window loop over exterior windows associated with this zone + std::cout << "Day " << state.dataGlobal->DayOfSim << " hour " << state.dataGlobal->HourOfDay << " DaylIllum " << state.dataDaylightingManager->DaylIllum(1) << "\n"; // Optical switching control (e.g. electrochromic glass) to adjust // window's vis trans downward so daylight level equals or is as @@ -6656,7 +6657,7 @@ namespace EnergyPlus::DaylightingManager { continueOuterLoop = true; continue; } - if (!(SurfWinShadingFlag(IWin) == WinShadingFlag::SwitchableGlazing && SurfWinGlareControlIsActive(IWin)) || + if ((SurfWinShadingFlag(IWin) != WinShadingFlag::SwitchableGlazing && !SurfWinGlareControlIsActive(IWin)) || WindowShadingControl(ICtrl).ShadingControlType != WSCT_MeetDaylIlumSetp) { continueOuterLoop = true; continue; @@ -6810,7 +6811,7 @@ namespace EnergyPlus::DaylightingManager { } } - if (SurfWinShadingFlag(IWin) != WinShadingFlag::SwitchableGlazing) SurfWinGlareControlIsActive = false; + if (SurfWinShadingFlag(IWin) != WinShadingFlag::SwitchableGlazing || SurfWinGlareControlIsActive(IWin) ) SurfWinGlareControlIsActive = false; // For switchable glazings, it is switched to fully dark state, // update ZoneDaylight(ZoneNum)%SourceLumFromWinAtRefPt(IL,2,loop) for use in DayltgGlare diff --git a/src/EnergyPlus/HeatBalanceSurfaceManager.cc b/src/EnergyPlus/HeatBalanceSurfaceManager.cc index 0a4508bcd4f..ac5bb0d3b0f 100644 --- a/src/EnergyPlus/HeatBalanceSurfaceManager.cc +++ b/src/EnergyPlus/HeatBalanceSurfaceManager.cc @@ -689,7 +689,7 @@ namespace HeatBalanceSurfaceManager { if (firstSurfWin == -1) continue; for (int SurfNum = firstSurfWin; SurfNum <= lastSurfWin; ++SurfNum) { SurfWinFracTimeShadingDeviceOn(SurfNum) = 0.0; - if (SurfWinShaded(SurfNum)) { + if (SurfWinShaded(SurfNum) || SurfWinGlareControlIsActive(SurfNum)) { SurfWinFracTimeShadingDeviceOn(SurfNum) = 1.0; } else { SurfWinFracTimeShadingDeviceOn(SurfNum) = 0.0; diff --git a/src/EnergyPlus/SolarShading.cc b/src/EnergyPlus/SolarShading.cc index d3d070f71e3..3589b2187be 100644 --- a/src/EnergyPlus/SolarShading.cc +++ b/src/EnergyPlus/SolarShading.cc @@ -8708,8 +8708,14 @@ namespace SolarShading { const int LayPtr = construction.LayerPoint(Lay); auto &material(dataMaterial.Material(LayPtr)); const bool isShading = material.Group == ComplexWindowShade; - if (isShading && Lay == 1) SurfWinShadingFlag(ISurf) = WinShadingFlag::ExtShadeOn; - if (isShading && Lay == TotLayers) SurfWinShadingFlag(ISurf) = WinShadingFlag::IntShadeOn; + if (isShading && Lay == 1) { + SurfWinShadingFlag(ISurf) = WinShadingFlag::ExtShadeOn; + SurfWinShaded(ISurf) = true; + } + if (isShading && Lay == TotLayers) { + SurfWinShadingFlag(ISurf) = WinShadingFlag::IntShadeOn; + SurfWinShaded(ISurf) = true; + } } if (SurfWinShadingFlag(ISurf) == WinShadingFlag::IntShadeOn) { auto &construction(state.dataConstruction->Construct(Surface(ISurf).Construction)); From 19591730a7f3d1e0067e6a628c22e2db8d5d92cf Mon Sep 17 00:00:00 2001 From: xuanluo113 Date: Fri, 18 Dec 2020 16:42:36 -0800 Subject: [PATCH 11/76] ems fix --- src/EnergyPlus/DataSurfaces.cc | 2 +- src/EnergyPlus/DataSurfaces.hh | 9 ++++----- src/EnergyPlus/EMSManager.cc | 4 ++-- src/EnergyPlus/SolarShading.cc | 2 +- src/EnergyPlus/SurfaceGeometry.cc | 2 +- 5 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/EnergyPlus/DataSurfaces.cc b/src/EnergyPlus/DataSurfaces.cc index 66557a26038..f9c3c4565f7 100644 --- a/src/EnergyPlus/DataSurfaces.cc +++ b/src/EnergyPlus/DataSurfaces.cc @@ -497,7 +497,7 @@ namespace DataSurfaces { Array1D SurfWinShadingFlag; // -1: window has no shading device Array1D SurfWinShaded; // Window shading flag is not shadeoff or noshade Array1D SurfWinShadingFlagEMSOn; // EMS control flag, true if EMS is controlling ShadingFlag with ShadingFlagEMSValue - Array1D SurfWinShadingFlagEMSValue; // EMS control value for Shading Flag + Array1D SurfWinShadingFlagEMSValue; // EMS control value for Shading Flag Array1D SurfWinGlareControlIsActive; // True if glare control is active Array1D SurfWinStormWinFlag; // -1: Storm window not applicable; 0: Window has storm window but it is off 1: Window has storm window and it is on Array1D SurfWinStormWinFlagPrevDay; // Previous time step value of StormWinFlag diff --git a/src/EnergyPlus/DataSurfaces.hh b/src/EnergyPlus/DataSurfaces.hh index 1829693e762..8bab4eab67d 100644 --- a/src/EnergyPlus/DataSurfaces.hh +++ b/src/EnergyPlus/DataSurfaces.hh @@ -127,10 +127,9 @@ namespace DataSurfaces { SwitchableGlazing = 2, ExtShadeOn = 3, ExtScreenOn = 4, - IntBlindOn = 5, - ExtBlindOn = 6, - BGShadeOn = 7, - GlassDoor = 8, + IntBlindOn = 6, + ExtBlindOn = 7, + BGShadeOn = 8, BGBlindOn = 9 }; @@ -518,7 +517,7 @@ namespace DataSurfaces { extern Array1D SurfWinShadingFlag; // -1: window has no shading device extern Array1D SurfWinShaded; // Window shading flag is not shadeoff or noshade extern Array1D SurfWinShadingFlagEMSOn; // EMS control flag, true if EMS is controlling ShadingFlag with ShadingFlagEMSValue - extern Array1D SurfWinShadingFlagEMSValue; // EMS control value for Shading Flag + extern Array1D SurfWinShadingFlagEMSValue; // EMS control value for Shading Flag extern Array1D SurfWinGlareControlIsActive; // True if glare control is active extern Array1D SurfWinStormWinFlag; // -1: Storm window not applicable; 0: Window has storm window but it is off 1: Window has storm window and it is on extern Array1D SurfWinStormWinFlagPrevDay; // Previous time step value of StormWinFlag diff --git a/src/EnergyPlus/EMSManager.cc b/src/EnergyPlus/EMSManager.cc index 388e80b9c52..3758c131083 100644 --- a/src/EnergyPlus/EMSManager.cc +++ b/src/EnergyPlus/EMSManager.cc @@ -1954,7 +1954,7 @@ namespace EMSManager { "Control Status", "[ShadeStatus]", DataSurfaces::SurfWinShadingFlagEMSOn(loopSurfNum), - DataSurfaces::SurfWinShadingFlagEMSValue(loopSurfNum)); + (int &)DataSurfaces::SurfWinShadingFlagEMSValue(loopSurfNum)); if (DataSurfaces::SurfWinMovableSlats(loopSurfNum)) { SetupEMSActuator("Window Shading Control", Surface(loopSurfNum).Name, @@ -1969,7 +1969,7 @@ namespace EMSManager { "Control Status", "[ShadeStatus]", DataSurfaces::SurfWinShadingFlagEMSOn(loopSurfNum), - DataSurfaces::SurfWinShadingFlagEMSValue(loopSurfNum)); + (int &)DataSurfaces::SurfWinShadingFlagEMSValue(loopSurfNum)); } else { if (WindowShadingControl(Surface(loopSurfNum).activeWindowShadingControl).ShadingType != WSC_ST_SwitchableGlazing) { ShowSevereError(state, "Missing shade or blind layer in window construction name = '" + diff --git a/src/EnergyPlus/SolarShading.cc b/src/EnergyPlus/SolarShading.cc index 3589b2187be..a9cb704f3d6 100644 --- a/src/EnergyPlus/SolarShading.cc +++ b/src/EnergyPlus/SolarShading.cc @@ -9173,7 +9173,7 @@ namespace SolarShading { // EMS Actuator Point: override setting if ems flag on if (SurfWinShadingFlagEMSOn(ISurf)) { - SurfWinShadingFlag(ISurf) = WinShadingFlag(SurfWinShadingFlagEMSValue(ISurf)); + SurfWinShadingFlag(ISurf) = SurfWinShadingFlagEMSValue(ISurf); } if (SurfWinShadingFlag(ISurf) != WinShadingFlag::NoShade && SurfWinShadingFlag(ISurf) != WinShadingFlag::ShadeOff) { SurfWinShaded(ISurf) = true; diff --git a/src/EnergyPlus/SurfaceGeometry.cc b/src/EnergyPlus/SurfaceGeometry.cc index e5776c99602..e10001f0319 100644 --- a/src/EnergyPlus/SurfaceGeometry.cc +++ b/src/EnergyPlus/SurfaceGeometry.cc @@ -162,7 +162,7 @@ namespace SurfaceGeometry { SurfWinShadingFlag.dimension(NumSurfaces, WinShadingFlag::ShadeOff); SurfWinShaded.dimension(NumSurfaces, false); SurfWinShadingFlagEMSOn.dimension(NumSurfaces, 0); - SurfWinShadingFlagEMSValue.dimension(NumSurfaces, 0); + SurfWinShadingFlagEMSValue.dimension(NumSurfaces, WinShadingFlag::ShadeOff); SurfWinGlareControlIsActive.dimension(NumSurfaces, false); SurfWinStormWinFlag.dimension(NumSurfaces, 0); SurfWinStormWinFlagPrevDay.dimension(NumSurfaces, 0); From 4dcba6ee768abfa9a985448e7dffbef52aeaadc8 Mon Sep 17 00:00:00 2001 From: xuanluo113 Date: Fri, 18 Dec 2020 17:35:31 -0800 Subject: [PATCH 12/76] fix ems type in unit test --- tst/EnergyPlus/unit/EMSManager.unit.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tst/EnergyPlus/unit/EMSManager.unit.cc b/tst/EnergyPlus/unit/EMSManager.unit.cc index afd4024ae7d..b2a739d1821 100644 --- a/tst/EnergyPlus/unit/EMSManager.unit.cc +++ b/tst/EnergyPlus/unit/EMSManager.unit.cc @@ -1621,16 +1621,16 @@ TEST_F(EnergyPlusFixture, EMSManager_TestWindowShadingControlExteriorScreenOptio SetupWindowShadingControlActuators(*state); EXPECT_FALSE(DataSurfaces::SurfWinShadingFlagEMSOn(2)); - EXPECT_EQ(DataSurfaces::SurfWinShadingFlagEMSValue(2), 0); + EXPECT_EQ(DataSurfaces::SurfWinShadingFlagEMSValue(2), DataSurfaces::WinShadingFlag::ShadeOff); DataHeatBalance::Zone.allocate(1); DataHeatBalance::Zone(1).WindowSurfaceFirst = 1; DataHeatBalance::Zone(1).WindowSurfaceLast = 2; state->dataGlobal->NumOfZones = 1; DataSurfaces::SurfWinShadingFlagEMSOn(2) = true; - DataSurfaces::SurfWinShadingFlagEMSValue(2) = 1.0; + DataSurfaces::SurfWinShadingFlagEMSValue(2) = DataSurfaces::WinShadingFlag::IntShadeOn; SolarShading::WindowShadingManager(*state); - EXPECT_EQ(int(DataSurfaces::SurfWinShadingFlag(2)), DataSurfaces::SurfWinShadingFlagEMSValue(2)); + EXPECT_EQ(DataSurfaces::SurfWinShadingFlag(2), DataSurfaces::SurfWinShadingFlagEMSValue(2)); } TEST_F(EnergyPlusFixture, EMS_WeatherDataActuators) From 91e062814177561235f1cc6c7401b8235382123a Mon Sep 17 00:00:00 2001 From: xuanluo113 Date: Wed, 13 Jan 2021 14:02:05 -0800 Subject: [PATCH 13/76] bug fixing --- src/EnergyPlus/DaylightingManager.cc | 6 ++++-- src/EnergyPlus/SolarShading.cc | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/EnergyPlus/DaylightingManager.cc b/src/EnergyPlus/DaylightingManager.cc index a71f51660e1..2faba00c02f 100644 --- a/src/EnergyPlus/DaylightingManager.cc +++ b/src/EnergyPlus/DaylightingManager.cc @@ -6571,7 +6571,6 @@ namespace EnergyPlus::DaylightingManager { state.dataDaylightingData->ZoneDaylight(ZoneNum).BacLum(IL) += state.dataDaylightingData->ZoneDaylight(ZoneNum).BackLumFromWinAtRefPt(loop, IS, IL); } } // End of second window loop over exterior windows associated with this zone - std::cout << "Day " << state.dataGlobal->DayOfSim << " hour " << state.dataGlobal->HourOfDay << " DaylIllum " << state.dataDaylightingManager->DaylIllum(1) << "\n"; // Optical switching control (e.g. electrochromic glass) to adjust // window's vis trans downward so daylight level equals or is as @@ -7067,7 +7066,10 @@ namespace EnergyPlus::DaylightingManager { for (IWin = Zone(ZoneNum).SurfaceFirst; IWin <= Zone(ZoneNum).SurfaceLast; ++IWin) { if (Surface(IWin).Class != SurfaceClass::Window) continue; if (Surface(IWin).ExtBoundCond != ExternalEnvironment) continue; - if (SurfWinGlareControlIsActive(IWin)) SurfWinShadingFlag(IWin) = WinShadingFlag::ShadeOff; + if (SurfWinGlareControlIsActive(IWin)) { + SurfWinShadingFlag(IWin) = WinShadingFlag::ShadeOff; + SurfWinGlareControlIsActive(IWin) = false; + } } // Variables for reporting diff --git a/src/EnergyPlus/SolarShading.cc b/src/EnergyPlus/SolarShading.cc index 91659e8a0f1..1abd9d060b9 100644 --- a/src/EnergyPlus/SolarShading.cc +++ b/src/EnergyPlus/SolarShading.cc @@ -9012,7 +9012,7 @@ namespace SolarShading { } // Set switching factor to fully switched if ShadingFlag = 2 - if (SurfWinShadingFlag(ISurf) == WinShadingFlag::SwitchableGlazing) { + if (SurfWinShadingFlag(ISurf) == WinShadingFlag::SwitchableGlazing && !SurfWinGlareControlIsActive(ISurf)) { SurfWinSwitchingFactor(ISurf) = 1.0; // Added TH 1/20/2010 From bc631d88803edf5b7dd697a9beccf38e1b69aaf9 Mon Sep 17 00:00:00 2001 From: xuanluo113 Date: Fri, 15 Jan 2021 09:31:06 -0800 Subject: [PATCH 14/76] fix --- src/EnergyPlus/DataSurfaces.hh | 9 ++++++++- src/EnergyPlus/DaylightingManager.cc | 5 ++++- src/EnergyPlus/HeatBalanceSurfaceManager.cc | 2 +- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/EnergyPlus/DataSurfaces.hh b/src/EnergyPlus/DataSurfaces.hh index 17a0fa7ac0a..5fd62d5f0bc 100644 --- a/src/EnergyPlus/DataSurfaces.hh +++ b/src/EnergyPlus/DataSurfaces.hh @@ -65,6 +65,13 @@ #include #include + +#define BITF(B) (1 << (int(B))) +#define BITF_TEST_ANY(V, B) (((V) & (B)) != 0) + +#define IS_SHADED(SHADE_FLAG) BITF_TEST_ANY(BITF(SHADE_FLAG), BITF(WinShadingFlag::NoShade) | BITF(WinShadingFlag::ShadeOff)) + + namespace EnergyPlus { // Forward declarations @@ -122,7 +129,7 @@ namespace DataSurfaces { }; enum class WinShadingFlag : int { - NoShade = -1, + NoShade = 10, ShadeOff = 0, IntShadeOn = 1, SwitchableGlazing = 2, diff --git a/src/EnergyPlus/DaylightingManager.cc b/src/EnergyPlus/DaylightingManager.cc index 2faba00c02f..4ad41111014 100644 --- a/src/EnergyPlus/DaylightingManager.cc +++ b/src/EnergyPlus/DaylightingManager.cc @@ -6810,7 +6810,9 @@ namespace EnergyPlus::DaylightingManager { } } - if (SurfWinShadingFlag(IWin) != WinShadingFlag::SwitchableGlazing || SurfWinGlareControlIsActive(IWin) ) SurfWinGlareControlIsActive = false; + if (SurfWinShadingFlag(IWin) != WinShadingFlag::SwitchableGlazing || SurfWinGlareControlIsActive(IWin)) { + SurfWinGlareControlIsActive(IWin) = false; + } // For switchable glazings, it is switched to fully dark state, // update ZoneDaylight(ZoneNum)%SourceLumFromWinAtRefPt(IL,2,loop) for use in DayltgGlare @@ -7069,6 +7071,7 @@ namespace EnergyPlus::DaylightingManager { if (SurfWinGlareControlIsActive(IWin)) { SurfWinShadingFlag(IWin) = WinShadingFlag::ShadeOff; SurfWinGlareControlIsActive(IWin) = false; + SurfWinShaded(IWin) = false; } } diff --git a/src/EnergyPlus/HeatBalanceSurfaceManager.cc b/src/EnergyPlus/HeatBalanceSurfaceManager.cc index 8bb7faf9068..e11d6d9207d 100644 --- a/src/EnergyPlus/HeatBalanceSurfaceManager.cc +++ b/src/EnergyPlus/HeatBalanceSurfaceManager.cc @@ -667,7 +667,7 @@ namespace HeatBalanceSurfaceManager { if (firstSurfWin == -1) continue; for (int SurfNum = firstSurfWin; SurfNum <= lastSurfWin; ++SurfNum) { SurfWinFracTimeShadingDeviceOn(SurfNum) = 0.0; - if (SurfWinShaded(SurfNum) || SurfWinGlareControlIsActive(SurfNum)) { + if (!IS_SHADED(SurfWinShadingFlag(SurfNum)) || SurfWinGlareControlIsActive(SurfNum)) { SurfWinFracTimeShadingDeviceOn(SurfNum) = 1.0; } else { SurfWinFracTimeShadingDeviceOn(SurfNum) = 0.0; From 88347f667244d8320755ea39816bf760440463eb Mon Sep 17 00:00:00 2001 From: xuanluo113 Date: Fri, 15 Jan 2021 14:32:10 -0800 Subject: [PATCH 15/76] remove shaded --- src/EnergyPlus/DataSurfaces.cc | 2 - src/EnergyPlus/DataSurfaces.hh | 3 +- src/EnergyPlus/DaylightingManager.cc | 166 +++++++----------- src/EnergyPlus/DaylightingManager.hh | 2 + src/EnergyPlus/HeatBalanceSurfaceManager.cc | 10 +- src/EnergyPlus/SolarShading.cc | 24 +-- src/EnergyPlus/SurfaceGeometry.cc | 1 - .../unit/DaylightingManager.unit.cc | 3 - 8 files changed, 84 insertions(+), 127 deletions(-) diff --git a/src/EnergyPlus/DataSurfaces.cc b/src/EnergyPlus/DataSurfaces.cc index 30ab402bbc4..9cd54050211 100644 --- a/src/EnergyPlus/DataSurfaces.cc +++ b/src/EnergyPlus/DataSurfaces.cc @@ -495,7 +495,6 @@ namespace DataSurfaces { Array1D SurfWinProfileAngVert; // Vertical beam solar profile angle (degrees) Array1D SurfWinShadingFlag; // -1: window has no shading device - Array1D SurfWinShaded; // Window shading flag is not shadeoff or noshade Array1D SurfWinShadingFlagEMSOn; // EMS control flag, true if EMS is controlling ShadingFlag with ShadingFlagEMSValue Array1D SurfWinShadingFlagEMSValue; // EMS control value for Shading Flag Array1D SurfWinGlareControlIsActive; // True if glare control is active @@ -1310,7 +1309,6 @@ namespace DataSurfaces { SurfWinProfileAngVert.clear(); SurfWinShadingFlag.clear(); - SurfWinShaded.clear(); SurfWinShadingFlagEMSOn.clear(); SurfWinShadingFlagEMSValue.clear(); SurfWinGlareControlIsActive.clear(); diff --git a/src/EnergyPlus/DataSurfaces.hh b/src/EnergyPlus/DataSurfaces.hh index 83b72686786..764e705dfec 100644 --- a/src/EnergyPlus/DataSurfaces.hh +++ b/src/EnergyPlus/DataSurfaces.hh @@ -69,7 +69,7 @@ #define BITF(B) (1 << (int(B))) #define BITF_TEST_ANY(V, B) (((V) & (B)) != 0) -#define IS_SHADED(SHADE_FLAG) BITF_TEST_ANY(BITF(SHADE_FLAG), BITF(WinShadingFlag::NoShade) | BITF(WinShadingFlag::ShadeOff)) +#define IS_SHADED(SHADE_FLAG) !BITF_TEST_ANY(BITF(SHADE_FLAG), BITF(WinShadingFlag::NoShade) | BITF(WinShadingFlag::ShadeOff)) namespace EnergyPlus { @@ -523,7 +523,6 @@ namespace DataSurfaces { extern Array1D SurfWinProfileAngVert; // Vertical beam solar profile angle (degrees) extern Array1D SurfWinShadingFlag; // -1: window has no shading device - extern Array1D SurfWinShaded; // Window shading flag is not shadeoff or noshade extern Array1D SurfWinShadingFlagEMSOn; // EMS control flag, true if EMS is controlling ShadingFlag with ShadingFlagEMSValue extern Array1D SurfWinShadingFlagEMSValue; // EMS control value for Shading Flag extern Array1D SurfWinGlareControlIsActive; // True if glare control is active diff --git a/src/EnergyPlus/DaylightingManager.cc b/src/EnergyPlus/DaylightingManager.cc index 06e33e99696..24608ea5bd5 100644 --- a/src/EnergyPlus/DaylightingManager.cc +++ b/src/EnergyPlus/DaylightingManager.cc @@ -5591,6 +5591,17 @@ namespace EnergyPlus::DaylightingManager { } // End of loop over light well objects } + int findWinShadingIndex(int const IWin) { + int WinShadingIndex = 1; // 1=unshaded, 2=shaded + bool WinShadedNoGlareControl = IS_SHADED(SurfWinShadingFlag(IWin)) && !SurfWinGlareControlIsActive(IWin); + if ((SurfWinWindowModelType(IWin) != WindowBSDFModel) && + (WinShadedNoGlareControl || SurfWinSolarDiffusing(IWin))) { + WinShadingIndex = 2; + } + return WinShadingIndex; + } + + void DayltgGlare(EnergyPlusData &state, int &IL, // Reference point index: 1=first ref pt, 2=second ref pt Real64 &BLUM, // Window background (surround) luminance (cd/m2) @@ -5636,30 +5647,18 @@ namespace EnergyPlus::DaylightingManager { // na // SUBROUTINE LOCAL VARIABLE DECLARATIONS: - Real64 GTOT; // Glare constant - Real64 GTOT1; // Portion of glare constant - Real64 GTOT2; // Portion of glare constant - int IWin; // Window counter - int IS; // Window shading index: 1=unshaded, 2=shaded - int loop; // Loop index - - // FLOW: - // Initialize glare constant - GTOT = 0.0; + Real64 GTOT = 0.0; // Glare constant // Loop over exterior windows associated with zone - for (loop = 1; loop <= state.dataDaylightingData->ZoneDaylight(ZoneNum).NumOfDayltgExtWins; ++loop) { - IWin = state.dataDaylightingData->ZoneDaylight(ZoneNum).DayltgExtWinSurfNums(loop); - IS = 1; - if ((SurfWinWindowModelType(IWin) != WindowBSDFModel) && ((SurfWinShaded(IWin) && !SurfWinGlareControlIsActive(IWin)) || SurfWinSolarDiffusing(IWin))) { - IS = 2; - } + for (int loop = 1; loop <= state.dataDaylightingData->ZoneDaylight(ZoneNum).NumOfDayltgExtWins; ++loop) { + int IWin = state.dataDaylightingData->ZoneDaylight(ZoneNum).DayltgExtWinSurfNums(loop); + bool WinShadingIndex = findWinShadingIndex(IWin); // Conversion from ft-L to cd/m2, with cd/m2 = 0.2936 ft-L, gives the 0.4794 factor // below, which is (0.2936)**0.6 - GTOT1 = 0.4794 * (std::pow(state.dataDaylightingData->ZoneDaylight(ZoneNum).SourceLumFromWinAtRefPt(loop, IS, IL), 1.6)) * + Real64 GTOT1 = 0.4794 * (std::pow(state.dataDaylightingData->ZoneDaylight(ZoneNum).SourceLumFromWinAtRefPt(loop, WinShadingIndex, IL), 1.6)) * std::pow(state.dataDaylightingData->ZoneDaylight(ZoneNum).SolidAngAtRefPtWtd(loop, IL), 0.8); - GTOT2 = BLUM + - 0.07 * (std::sqrt(state.dataDaylightingData->ZoneDaylight(ZoneNum).SolidAngAtRefPt(loop, IL))) * state.dataDaylightingData->ZoneDaylight(ZoneNum).SourceLumFromWinAtRefPt(loop, IS, IL); + Real64 GTOT2 = BLUM + + 0.07 * (std::sqrt(state.dataDaylightingData->ZoneDaylight(ZoneNum).SolidAngAtRefPt(loop, IL))) * state.dataDaylightingData->ZoneDaylight(ZoneNum).SourceLumFromWinAtRefPt(loop, WinShadingIndex, IL); GTOT += GTOT1 / (GTOT2 + 0.000001); } @@ -5702,42 +5701,26 @@ namespace EnergyPlus::DaylightingManager { // INTERFACE BLOCK SPECIFICATIONS: na // DERIVED TYPE DEFINITIONS: na - // SUBROUTINE LOCAL VARIABLE DECLARATIONS: - int IL; // Reference point index: 1=first ref pt, 2=second ref pt - Real64 GTOT; // Glare constant - Real64 GTOT1; // Portion of glare constant - Real64 GTOT2; // Portion of glare constant - int IWin; // Window counter - int IS; // Window shading index: 1=unshaded, 2=shaded - Real64 BacLum; // Background luminance (cd/m2) - int loop; // Loop index - int RefPoints; // Number of daylighting reference points in zone - // FLOW: - // Initialize glare constant - - GTOT = 0.0; + Real64 GTOT = 0.0;; // Glare constant // Calculate background luminance including effect of inter-reflected illuminance from light // entering zone through its interior windows - RefPoints = state.dataDaylightingData->ZoneDaylight(ZoneNum).TotalDaylRefPoints; - for (IL = 1; IL <= RefPoints; ++IL) { - BacLum = state.dataDaylightingData->ZoneDaylight(ZoneNum).BacLum(IL) + state.dataDaylightingData->ZoneDaylight(ZoneNum).InterReflIllFrIntWins * state.dataDaylightingData->ZoneDaylight(ZoneNum).AveVisDiffReflect / DataGlobalConstants::Pi; - BacLum = max(state.dataDaylightingData->ZoneDaylight(ZoneNum).IllumSetPoint(IL) * state.dataDaylightingData->ZoneDaylight(ZoneNum).AveVisDiffReflect / DataGlobalConstants::Pi, BacLum); + int RefPoints = state.dataDaylightingData->ZoneDaylight(ZoneNum).TotalDaylRefPoints; // Number of daylighting reference points in zone + for (int IL = 1; IL <= RefPoints; ++IL) { + Real64 BackgroundLum = state.dataDaylightingData->ZoneDaylight(ZoneNum).BacLum(IL) + state.dataDaylightingData->ZoneDaylight(ZoneNum).InterReflIllFrIntWins * state.dataDaylightingData->ZoneDaylight(ZoneNum).AveVisDiffReflect / DataGlobalConstants::Pi; + BackgroundLum = max(state.dataDaylightingData->ZoneDaylight(ZoneNum).IllumSetPoint(IL) * state.dataDaylightingData->ZoneDaylight(ZoneNum).AveVisDiffReflect / DataGlobalConstants::Pi, BackgroundLum); // Loop over exterior windows associated with zone - for (loop = 1; loop <= state.dataDaylightingData->ZoneDaylight(ZoneNum).NumOfDayltgExtWins; ++loop) { - IWin = state.dataDaylightingData->ZoneDaylight(ZoneNum).DayltgExtWinSurfNums(loop); - IS = 1; - if ((SurfWinWindowModelType(IWin) != WindowBSDFModel) && - ((SurfWinShaded(IWin) && !SurfWinGlareControlIsActive(IWin)) || SurfWinSolarDiffusing(IWin))) - IS = 2; + for (int loop = 1; loop <= state.dataDaylightingData->ZoneDaylight(ZoneNum).NumOfDayltgExtWins; ++loop) { + int IWin = state.dataDaylightingData->ZoneDaylight(ZoneNum).DayltgExtWinSurfNums(loop); + bool WinShadingIndex = findWinShadingIndex(IWin); // Conversion from ft-L to cd/m2, with cd/m2 = 0.2936 ft-L, gives the 0.4794 factor // below, which is (0.2936)**0.6 - GTOT1 = 0.4794 * (std::pow(state.dataDaylightingData->ZoneDaylight(ZoneNum).SourceLumFromWinAtRefPt(loop, IS, IL), 1.6)) * + Real64 GTOT1 = 0.4794 * (std::pow(state.dataDaylightingData->ZoneDaylight(ZoneNum).SourceLumFromWinAtRefPt(loop, WinShadingIndex, IL), 1.6)) * std::pow(state.dataDaylightingData->ZoneDaylight(ZoneNum).SolidAngAtRefPtWtd(loop, IL), 0.8); - GTOT2 = BacLum + 0.07 * (std::sqrt(state.dataDaylightingData->ZoneDaylight(ZoneNum).SolidAngAtRefPt(loop, IL))) * - state.dataDaylightingData->ZoneDaylight(ZoneNum).SourceLumFromWinAtRefPt(loop, IS, IL); + Real64 GTOT2 = BackgroundLum + 0.07 * (std::sqrt(state.dataDaylightingData->ZoneDaylight(ZoneNum).SolidAngAtRefPt(loop, IL))) * + state.dataDaylightingData->ZoneDaylight(ZoneNum).SourceLumFromWinAtRefPt(loop, WinShadingIndex, IL); GTOT += GTOT1 / (GTOT2 + 0.000001); } @@ -6193,9 +6176,6 @@ namespace EnergyPlus::DaylightingManager { static Vector2 SFSUHR; // Sun source luminance factor for bare/shaded window static Array1D GLRNDX; // Glare index at reference point static Array1D GLRNEW; // New glare index at reference point - int IL; // Reference point index - int IWin; // Window index - int IS; // IS=1 for unshaded window, =2 for shaded window int ISWFLG; // Switchable glazing flag: =1 if one or more windows in a zone // has switchable glazing that adjusts visible transmittance to just meet // daylighting setpoint; =0 otherwise. @@ -6262,7 +6242,7 @@ namespace EnergyPlus::DaylightingManager { // FLOW: // Initialize reference point illuminance and window background luminance - for (IL = 1; IL <= NREFPT; ++IL) { + for (int IL = 1; IL <= NREFPT; ++IL) { SetPnt(IL) = state.dataDaylightingData->ZoneDaylight(ZoneNum).IllumSetPoint(IL); state.dataDaylightingManager->DaylIllum(IL) = 0.0; state.dataDaylightingData->ZoneDaylight(ZoneNum).BacLum(IL) = 0.0; @@ -6287,7 +6267,7 @@ namespace EnergyPlus::DaylightingManager { // Find contribution of each window to the daylight illum and to the glare numerator at each reference point. // Use shading flags set in WindowShadingManager. for (loop = 1; loop <= state.dataDaylightingData->ZoneDaylight(ZoneNum).NumOfDayltgExtWins; ++loop) { - IWin = state.dataDaylightingData->ZoneDaylight(ZoneNum).DayltgExtWinSurfNums(loop); + int IWin = state.dataDaylightingData->ZoneDaylight(ZoneNum).DayltgExtWinSurfNums(loop); // Added TH 6/29/2009 for thermochromic windows VTRatio = 1.0; @@ -6304,8 +6284,11 @@ namespace EnergyPlus::DaylightingManager { } } + bool ShadedOrDiffuseGlassWin = (SurfWinWindowModelType(IWin) != WindowBSDFModel) && + (IS_SHADED(SurfWinShadingFlag(IWin)) || SurfWinSolarDiffusing(IWin)); + // Loop over reference points - for (IL = 1; IL <= NREFPT; ++IL) { + for (int IL = 1; IL <= NREFPT; ++IL) { // Daylight factors for current sun position for (ISky = 1; ISky <= 4; ++ISky) { @@ -6338,8 +6321,7 @@ namespace EnergyPlus::DaylightingManager { state.dataGlobal->WeightPreviousHour * (state.dataDaylightingData->ZoneDaylight(ZoneNum).DaylSourceFacSun(state.dataGlobal->PreviousHour, 1, IL, loop) + state.dataDaylightingData->ZoneDaylight(ZoneNum).DaylSourceFacSunDisk(state.dataGlobal->PreviousHour, 1, IL, loop))); - if ((SurfWinWindowModelType(IWin) != WindowBSDFModel) && - (SurfWinShaded(IWin) || SurfWinSolarDiffusing(IWin))) { + if (ShadedOrDiffuseGlassWin) { // ===Shaded window or window with diffusing glass=== if (!SurfWinMovableSlats(IWin)) { @@ -6509,9 +6491,8 @@ namespace EnergyPlus::DaylightingManager { HorIllSkyFac = state.dataEnvrn->HISKF / ((1 - SkyWeight) * HorIllSky(ISky2) + SkyWeight * HorIllSky(ISky1)); - for (IS = 1; IS <= 2; ++IS) { - if (IS == 2 && (SurfWinWindowModelType(IWin) == WindowBSDFModel)) break; - if (IS == 2 && !SurfWinShaded(IWin) && !SurfWinSolarDiffusing(IWin)) break; + for (int IS = 1; IS <= 2; ++IS) { + if (IS == 2 && !ShadedOrDiffuseGlassWin) break; state.dataDaylightingData->ZoneDaylight(ZoneNum).IllumFromWinAtRefPt(loop, IS, IL) = DFSUHR(IS) * state.dataEnvrn->HISUNF + @@ -6548,7 +6529,7 @@ namespace EnergyPlus::DaylightingManager { // entering the zone through interior windows (which is calculated in DayltgInterReflIllFrIntWins. for (loop = 1; loop <= state.dataDaylightingData->ZoneDaylight(ZoneNum).NumOfDayltgExtWins; ++loop) { - IWin = state.dataDaylightingData->ZoneDaylight(ZoneNum).DayltgExtWinSurfNums(loop); + int IWin = state.dataDaylightingData->ZoneDaylight(ZoneNum).DayltgExtWinSurfNums(loop); ICtrl = Surface(IWin).activeWindowShadingControl; if (Surface(IWin).HasShadeControl && ISWFLG == 0) { if (WindowShadingControl(ICtrl).ShadingControlType == WSCT_MeetDaylIlumSetp && @@ -6561,12 +6542,9 @@ namespace EnergyPlus::DaylightingManager { // the shading flag is initialized at GlassConditionallyLightened (20), and // the window is initialized at clear state: IS = 1 // For other windows with glare control, the shading flag is initialized at >10, to be determined - IS = 1; - if ((SurfWinWindowModelType(IWin) != WindowBSDFModel) && - ((SurfWinShaded(IWin) && !SurfWinGlareControlIsActive(IWin)) || SurfWinSolarDiffusing(IWin))) - IS = 2; + int IS = findWinShadingIndex(IWin); - for (IL = 1; IL <= NREFPT; ++IL) { + for (int IL = 1; IL <= NREFPT; ++IL) { state.dataDaylightingManager->DaylIllum(IL) += state.dataDaylightingData->ZoneDaylight(ZoneNum).IllumFromWinAtRefPt(loop, IS, IL); state.dataDaylightingData->ZoneDaylight(ZoneNum).BacLum(IL) += state.dataDaylightingData->ZoneDaylight(ZoneNum).BackLumFromWinAtRefPt(loop, IS, IL); } @@ -6606,10 +6584,7 @@ namespace EnergyPlus::DaylightingManager { loop = state.dataDaylightingData->ZoneDaylight(ZoneNum).MapShdOrdToLoopNum(count); ICtrl = Surface(IWin).activeWindowShadingControl; - IS = 1; - if ((SurfWinWindowModelType(IWin) != WindowBSDFModel) && - ((SurfWinShaded(IWin) && !SurfWinGlareControlIsActive(IWin))|| SurfWinSolarDiffusing(IWin))) - IS = 2; + bool IS = findWinShadingIndex(IWin); if (Surface(IWin).HasShadeControl) { if (SurfWinShadingFlag(IWin) == WinShadingFlag::SwitchableGlazing && SurfWinGlareControlIsActive(IWin) && WindowShadingControl(ICtrl).ShadingControlType == WSCT_MeetDaylIlumSetp && !previously_shaded(loop)) { @@ -6692,10 +6667,10 @@ namespace EnergyPlus::DaylightingManager { } // Adjust daylight quantities based on ratio between switched and unswitched visible transmittance - for (IL = 1; IL <= NREFPT; ++IL) { + for (int IL = 1; IL <= NREFPT; ++IL) { // DaylIllum(IL) and BacLum(IL) were calculated at the clear state: IS = 1, // and need to adjusted for intermediate switched state at VisTransSelected: IS = 2 - IS = 1; + int IS = 1; VTRAT = SurfWinVisTransSelected(IWin) / (TVIS1(igroup) + 0.000001); state.dataDaylightingManager->DaylIllum(IL) += (VTRAT - 1.0) * state.dataDaylightingData->ZoneDaylight(ZoneNum).IllumFromWinAtRefPt(loop, IS, IL); state.dataDaylightingData->ZoneDaylight(ZoneNum).BacLum(IL) += (VTRAT - 1.0) * state.dataDaylightingData->ZoneDaylight(ZoneNum).BackLumFromWinAtRefPt(loop, IS, IL); @@ -6723,7 +6698,7 @@ namespace EnergyPlus::DaylightingManager { // Calculate glare index at each reference point assuming the daylight illuminance setpoint is // met at both reference points, either by daylight or electric lights - for (IL = 1; IL <= NREFPT; ++IL) { + for (int IL = 1; IL <= NREFPT; ++IL) { BACL = max(SetPnt(IL) * state.dataDaylightingData->ZoneDaylight(ZoneNum).AveVisDiffReflect / DataGlobalConstants::Pi, state.dataDaylightingData->ZoneDaylight(ZoneNum).BacLum(IL)); // DayltgGlare uses ZoneDaylight(ZoneNum)%SourceLumFromWinAtRefPt(IL,1,loop) for unshaded windows, and // ZoneDaylight(ZoneNum)%SourceLumFromWinAtRefPt(IL,2,loop) for shaded windows @@ -6734,7 +6709,7 @@ namespace EnergyPlus::DaylightingManager { // is exceeded at either ref pt, attempt to reduce glare to acceptable level by closing // shading device on windows that have shades that have not already been closed. GlareFlag = false; - for (IL = 1; IL <= NREFPT; ++IL) { + for (int IL = 1; IL <= NREFPT; ++IL) { if (GLRNDX(IL) > state.dataDaylightingData->ZoneDaylight(ZoneNum).MaxGlareallowed) { GlareFlag = true; break; @@ -6788,8 +6763,8 @@ namespace EnergyPlus::DaylightingManager { // Illuminance (WDAYIL) and background luminance (WBACLU) contribution from this // window without shading (IS=1) and with shading (IS=2) for each ref pt // For switchable windows, this may be partially switched rather than fully dark - for (IL = 1; IL <= NREFPT; ++IL) { - for (IS = 1; IS <= 2; ++IS) { + for (int IL = 1; IL <= NREFPT; ++IL) { + for (int IS = 1; IS <= 2; ++IS) { WDAYIL(IS, IL, igroup) = state.dataDaylightingData->ZoneDaylight(ZoneNum).IllumFromWinAtRefPt(loop, IS, IL); WBACLU(IS, IL, igroup) = state.dataDaylightingData->ZoneDaylight(ZoneNum).BackLumFromWinAtRefPt(loop, IS, IL); } @@ -6797,7 +6772,7 @@ namespace EnergyPlus::DaylightingManager { // Recalculate illuminance and glare with shading on this window. // For switchable glazings, this is the fully switched (dark) state - for (IL = 1; IL <= NREFPT; ++IL) { + for (int IL = 1; IL <= NREFPT; ++IL) { if (SurfWinShadingFlag(IWin) != WinShadingFlag::SwitchableGlazing || SurfWinGlareControlIsActive(IWin)) { // for non switchable glazings or switchable glazings not switched yet (still in clear state) // SurfaceWindow(IWin)%ShadingFlag = WinShadingFlag::GlassConditionallyLightened @@ -6817,7 +6792,7 @@ namespace EnergyPlus::DaylightingManager { // For switchable glazings, it is switched to fully dark state, // update ZoneDaylight(ZoneNum)%SourceLumFromWinAtRefPt(IL,2,loop) for use in DayltgGlare if (SurfWinShadingFlag(IWin) == WinShadingFlag::SwitchableGlazing) { - for (IL = 1; IL <= NREFPT; ++IL) { + for (int IL = 1; IL <= NREFPT; ++IL) { state.dataDaylightingData->ZoneDaylight(ZoneNum).SourceLumFromWinAtRefPt(loop, 2, IL) = tmpSourceLumFromWinAtRefPt(loop, 2, IL); state.dataDaylightingData->ZoneDaylight(ZoneNum).IllumFromWinAtRefPt(loop, 2, IL) = tmpIllumFromWinAtRefPt(loop, 2, IL); state.dataDaylightingData->ZoneDaylight(ZoneNum).BackLumFromWinAtRefPt(loop, 2, IL) = tmpBackLumFromWinAtRefPt(loop, 2, IL); @@ -6838,7 +6813,7 @@ namespace EnergyPlus::DaylightingManager { if (atLeastOneGlareControlIsActive) { // Re-calc daylight and glare at shaded state. For switchable glazings, it is the fully dark state. - for (IL = 1; IL <= NREFPT; ++IL) { + for (int IL = 1; IL <= NREFPT; ++IL) { BACL = max(SetPnt(IL) * state.dataDaylightingData->ZoneDaylight(ZoneNum).AveVisDiffReflect / DataGlobalConstants::Pi, RBACLU(IL, igroup)); // DayltgGlare uses ZoneDaylight(ZoneNum)%SourceLumFromWinAtRefPt(IL,2,loop) for shaded state DayltgGlare(state, IL, BACL, GLRNEW(IL), ZoneNum); @@ -6869,7 +6844,7 @@ namespace EnergyPlus::DaylightingManager { // covers all the reference points. int numRefPtOldAboveMaxNewBelowOld = 0; int numRefPtOldBelowMaxNewBelowMax = 0; - for (IL = 1; IL <= NREFPT; ++IL) { + for (int IL = 1; IL <= NREFPT; ++IL) { if (GLRNDX(IL) > state.dataDaylightingData->ZoneDaylight(ZoneNum).MaxGlareallowed && GLRNEW(IL) <= GLRNDX(IL)) ++numRefPtOldAboveMaxNewBelowOld; if (GLRNDX(IL) <= state.dataDaylightingData->ZoneDaylight(ZoneNum).MaxGlareallowed && GLRNEW(IL) <= state.dataDaylightingData->ZoneDaylight(ZoneNum).MaxGlareallowed) ++numRefPtOldBelowMaxNewBelowMax; @@ -6901,7 +6876,7 @@ namespace EnergyPlus::DaylightingManager { SurfWinVisTransSelected(IWin) = TVIS1(igroup); // RESET properties for fully dark state - for (IL = 1; IL <= NREFPT; ++IL) { + for (int IL = 1; IL <= NREFPT; ++IL) { state.dataDaylightingData->ZoneDaylight(ZoneNum).IllumFromWinAtRefPt(loop, 2, IL) = tmpIllumFromWinAtRefPt(loop, 2, IL); state.dataDaylightingData->ZoneDaylight(ZoneNum).BackLumFromWinAtRefPt(loop, 2, IL) = tmpBackLumFromWinAtRefPt(loop, 2, IL); state.dataDaylightingData->ZoneDaylight(ZoneNum).SourceLumFromWinAtRefPt(loop, 2, IL) = tmpSourceLumFromWinAtRefPt(loop, 2, IL); @@ -6915,7 +6890,7 @@ namespace EnergyPlus::DaylightingManager { // Shading this window has improved the glare situation. // Reset background luminance, glare index, and daylight illuminance at each ref pt. // For switchable glazings, this is fully switched, dark state - for (IL = 1; IL <= NREFPT; ++IL) { + for (int IL = 1; IL <= NREFPT; ++IL) { state.dataDaylightingData->ZoneDaylight(ZoneNum).BacLum(IL) = RBACLU(IL, igroup); GLRNDX(IL) = GLRNEW(IL); state.dataDaylightingManager->DaylIllum(IL) = RDAYIL(IL, igroup); @@ -6937,7 +6912,7 @@ namespace EnergyPlus::DaylightingManager { SurfWinVisTransSelected(IWin) = TVIS2(igroup); // restore fully dark values - for (IL = 1; IL <= NREFPT; ++IL) { + for (int IL = 1; IL <= NREFPT; ++IL) { WDAYIL(2, IL, igroup) = tmpIllumFromWinAtRefPt(loop, 2, IL); WBACLU(2, IL, igroup) = tmpBackLumFromWinAtRefPt(loop, 2, IL); state.dataDaylightingData->ZoneDaylight(ZoneNum).IllumFromWinAtRefPt(loop, 2, IL) = tmpIllumFromWinAtRefPt(loop, 2, IL); @@ -6972,7 +6947,7 @@ namespace EnergyPlus::DaylightingManager { tmpSWFactor = 1.0 - tmpSWIterStep; while (tmpSWFactor > 0) { // calc new glare at new switching state - for (IL = 1; IL <= NREFPT; ++IL) { + for (int IL = 1; IL <= NREFPT; ++IL) { RDAYIL(IL, igroup) = state.dataDaylightingManager->DaylIllum(IL) + (WDAYIL(1, IL, igroup) - WDAYIL(2, IL, igroup)) * (1.0 - tmpSWFactor); RBACLU(IL, igroup) = state.dataDaylightingData->ZoneDaylight(ZoneNum).BacLum(IL) + (WBACLU(1, IL, igroup) - WBACLU(2, IL, igroup)) * (1.0 - tmpSWFactor); @@ -7018,7 +6993,7 @@ namespace EnergyPlus::DaylightingManager { // Final re-calculation if needed if (!GlareOK) { // Glare too high, use previous state and re-calc - for (IL = 1; IL <= NREFPT; ++IL) { + for (int IL = 1; IL <= NREFPT; ++IL) { RDAYIL(IL, igroup) = state.dataDaylightingManager->DaylIllum(IL) + (WDAYIL(1, IL, igroup) - WDAYIL(2, IL, igroup)) * (1.0 - tmpSWFactor); RBACLU(IL, igroup) = state.dataDaylightingData->ZoneDaylight(ZoneNum).BacLum(IL) + (WBACLU(1, IL, igroup) - WBACLU(2, IL, igroup)) * (1.0 - tmpSWFactor); @@ -7036,7 +7011,7 @@ namespace EnergyPlus::DaylightingManager { } // Update final results - for (IL = 1; IL <= NREFPT; ++IL) { + for (int IL = 1; IL <= NREFPT; ++IL) { state.dataDaylightingData->ZoneDaylight(ZoneNum).BacLum(IL) = RBACLU(IL, igroup); GLRNDX(IL) = GLRNEW(IL); state.dataDaylightingManager->DaylIllum(IL) = RDAYIL(IL, igroup); @@ -7065,18 +7040,17 @@ namespace EnergyPlus::DaylightingManager { // Loop again over windows and reset remaining shading flags that // are 10 or higher (i.e., conditionally off) to off - for (IWin = Zone(ZoneNum).SurfaceFirst; IWin <= Zone(ZoneNum).SurfaceLast; ++IWin) { + for (int IWin = Zone(ZoneNum).SurfaceFirst; IWin <= Zone(ZoneNum).SurfaceLast; ++IWin) { if (Surface(IWin).Class != SurfaceClass::Window) continue; if (Surface(IWin).ExtBoundCond != ExternalEnvironment) continue; if (SurfWinGlareControlIsActive(IWin)) { SurfWinShadingFlag(IWin) = WinShadingFlag::ShadeOff; SurfWinGlareControlIsActive(IWin) = false; - SurfWinShaded(IWin) = false; } } // Variables for reporting - for (IL = 1; IL <= NREFPT; ++IL) { + for (int IL = 1; IL <= NREFPT; ++IL) { state.dataDaylightingData->ZoneDaylight(ZoneNum).DaylIllumAtRefPt(IL) = state.dataDaylightingManager->DaylIllum(IL); state.dataDaylightingData->ZoneDaylight(ZoneNum).GlareIndexAtRefPt(IL) = GLRNDX(IL); @@ -7098,9 +7072,9 @@ namespace EnergyPlus::DaylightingManager { // The following report variables are valid only for daylit zones without interior windows if (!Zone(ZoneNum).HasInterZoneWindow) { for (loop = 1; loop <= state.dataDaylightingData->ZoneDaylight(ZoneNum).NumOfDayltgExtWins; ++loop) { - IWin = state.dataDaylightingData->ZoneDaylight(ZoneNum).DayltgExtWinSurfNums(loop); - IS = 1; - if (SurfWinShaded(IWin) || SurfWinSolarDiffusing(IWin)) IS = 2; + int IWin = state.dataDaylightingData->ZoneDaylight(ZoneNum).DayltgExtWinSurfNums(loop); + int IS = 1; + if (IS_SHADED(SurfWinShadingFlag(IWin)) || SurfWinSolarDiffusing(IWin)) IS = 2; if (state.dataDaylightingData->ZoneDaylight(ZoneNum).DaylightMethod == DataDaylighting::iDaylightingMethod::SplitFluxDaylighting) { int refPtCount = 0; for (int const enclZoneNum : DataViewFactorInformation::ZoneSolarInfo(Zone(ZoneNum).SolarEnclosureNum).ZoneNums) { @@ -9542,7 +9516,7 @@ namespace EnergyPlus::DaylightingManager { } if ((SurfWinWindowModelType(IWin) != WindowBSDFModel) && - (SurfWinShaded(IWin) || SurfWinSolarDiffusing(IWin))) { + (IS_SHADED(SurfWinShadingFlag(IWin)) || SurfWinSolarDiffusing(IWin))) { // ===Shaded window=== if (!SurfWinMovableSlats(IWin)) { @@ -9723,7 +9697,7 @@ namespace EnergyPlus::DaylightingManager { HorIllSkyFac = state.dataEnvrn->HISKF / ((1.0 - SkyWeight) * HorIllSky(ISky2) + SkyWeight * HorIllSky(ISky1)); for (IS = 1; IS <= 2; ++IS) { - if (IS == 2 && !SurfWinShaded(IWin) && !SurfWinSolarDiffusing(IWin)) break; + if (IS == 2 && !IS_SHADED(SurfWinShadingFlag(IWin)) && !SurfWinSolarDiffusing(IWin)) break; state.dataDaylightingData->IllumMapCalc(MapNum).IllumFromWinAtMapPt(loop, IS, ILB) = DFSUHR(IS) * state.dataEnvrn->HISUNF + HorIllSkyFac * (DFSKHR(IS, ISky1) * SkyWeight * HorIllSky(ISky1) + @@ -9750,10 +9724,7 @@ namespace EnergyPlus::DaylightingManager { for (loop = 1; loop <= state.dataDaylightingData->ZoneDaylight(ZoneNum).NumOfDayltgExtWins; ++loop) { IWin = state.dataDaylightingData->ZoneDaylight(ZoneNum).DayltgExtWinSurfNums(loop); - IS = 1; - if ((SurfWinWindowModelType(IWin) != WindowBSDFModel) && - ((SurfWinShaded(IWin) && !SurfWinGlareControlIsActive(IWin)) || SurfWinSolarDiffusing(IWin))) - IS = 2; + IS = findWinShadingIndex(IWin); // CR 8057. 3/17/2010. // Switchable windows may be in partially switched state rather than fully dark state @@ -9788,10 +9759,7 @@ namespace EnergyPlus::DaylightingManager { // Loop over exterior windows associated with zone for (loop = 1; loop <= state.dataDaylightingData->ZoneDaylight(ZoneNum).NumOfDayltgExtWins; ++loop) { IWin = state.dataDaylightingData->ZoneDaylight(ZoneNum).DayltgExtWinSurfNums(loop); - IS = 1; - if ((SurfWinWindowModelType(IWin) != WindowBSDFModel) && - ((SurfWinShaded(IWin) && !SurfWinGlareControlIsActive(IWin)) || SurfWinSolarDiffusing(IWin))) - IS = 2; + IS = findWinShadingIndex(IWin); // CR 8057. 3/17/2010 VTMULT = 1.0; diff --git a/src/EnergyPlus/DaylightingManager.hh b/src/EnergyPlus/DaylightingManager.hh index e0826dae1ce..a92efb46ab3 100644 --- a/src/EnergyPlus/DaylightingManager.hh +++ b/src/EnergyPlus/DaylightingManager.hh @@ -317,6 +317,8 @@ namespace DaylightingManager { void GetLightWellData(EnergyPlusData &state, bool &ErrorsFound); // If errors found in input + int findWinShadingIndex(int const IWin); + void DayltgGlare(EnergyPlusData &state, int &IL, // Reference point index: 1=first ref pt, 2=second ref pt Real64 &BLUM, // Window background (surround) luminance (cd/m2) diff --git a/src/EnergyPlus/HeatBalanceSurfaceManager.cc b/src/EnergyPlus/HeatBalanceSurfaceManager.cc index f03090757fe..d2e5e915b24 100644 --- a/src/EnergyPlus/HeatBalanceSurfaceManager.cc +++ b/src/EnergyPlus/HeatBalanceSurfaceManager.cc @@ -667,7 +667,7 @@ namespace HeatBalanceSurfaceManager { if (firstSurfWin == -1) continue; for (int SurfNum = firstSurfWin; SurfNum <= lastSurfWin; ++SurfNum) { SurfWinFracTimeShadingDeviceOn(SurfNum) = 0.0; - if (!IS_SHADED(SurfWinShadingFlag(SurfNum)) || SurfWinGlareControlIsActive(SurfNum)) { + if (IS_SHADED(SurfWinShadingFlag(SurfNum)) || SurfWinGlareControlIsActive(SurfNum)) { SurfWinFracTimeShadingDeviceOn(SurfNum) = 1.0; } else { SurfWinFracTimeShadingDeviceOn(SurfNum) = 0.0; @@ -2883,7 +2883,7 @@ namespace HeatBalanceSurfaceManager { AbsDiffWin(Lay) = state.dataConstruction->Construct(ConstrNum).AbsDiff(Lay); } - if (SurfWinShaded(SurfNum)) { // Shaded window + if (IS_SHADED(SurfWinShadingFlag(SurfNum))) { // Shaded window int ConstrNumSh = Surface(SurfNum).activeShadedConstruction; // Shaded window construction if (SurfWinStormWinFlag(SurfNum) == 1) ConstrNumSh = Surface(SurfNum).activeStormWinShadedConstruction; @@ -3580,7 +3580,7 @@ namespace HeatBalanceSurfaceManager { SurfQRadThermInAbs(SurfNum) = adjQL * TMULT(radEnclosureNum) * ITABSF(SurfNum); } - if (!SurfWinShaded(SurfNum)) { // No window shading + if (!IS_SHADED(SurfWinShadingFlag(SurfNum))) { // No window shading for (int IGlass = 1; IGlass <= TotGlassLayers; ++IGlass) { SurfWinQRadSWwinAbs(IGlass, SurfNum) += QS(solEnclosureNum) * state.dataConstruction->Construct(ConstrNum).AbsDiffBack(IGlass); @@ -3741,7 +3741,7 @@ namespace HeatBalanceSurfaceManager { } int TotGlassLayers = state.dataConstruction->Construct(ConstrNum).TotGlassLayers; WinShadingFlag ShadeFlag = SurfWinShadingFlag(SurfNum); - if (!SurfWinShaded(SurfNum)) { // No window shading + if (!IS_SHADED(SurfWinShadingFlag(SurfNum))) { // No window shading for (int IGlass = 1; IGlass <= TotGlassLayers; ++IGlass) { SurfWinQRadSWwinAbs(IGlass, SurfNum) += SurfWinInitialDifSolwinAbs(IGlass, SurfNum); } @@ -3795,7 +3795,7 @@ namespace HeatBalanceSurfaceManager { TotGlassLayers = state.dataConstruction->Construct(ConstrNum).TotGlassLayers; } WinShadingFlag ShadeFlag = SurfWinShadingFlag(SurfNum); - if (!SurfWinShaded(SurfNum) || SurfWinWindowModelType(SurfNum) == WindowBSDFModel) { // No window shading + if (!IS_SHADED(SurfWinShadingFlag(SurfNum)) || SurfWinWindowModelType(SurfNum) == WindowBSDFModel) { // No window shading for (int IGlass = 1; IGlass <= TotGlassLayers; ++IGlass) { // Initial Transmitted Diffuse Solar Absorbed on Inside of Surface[W] SurfInitialDifSolInAbsReport(SurfNum) += diff --git a/src/EnergyPlus/SolarShading.cc b/src/EnergyPlus/SolarShading.cc index 361488ce1c6..7de320c471e 100644 --- a/src/EnergyPlus/SolarShading.cc +++ b/src/EnergyPlus/SolarShading.cc @@ -6111,7 +6111,7 @@ namespace SolarShading { AbWin(Lay) = POLYF(CosInc, state.dataConstruction->Construct(ConstrNum).AbsBeamCoef({1, 6}, Lay)) * CosInc * SunLitFract * SurfaceWindow(SurfNum).OutProjSLFracMult(state.dataGlobal->HourOfDay); } - if (!SurfWinShaded(SurfNum) || SurfWinGlareControlIsActive(SurfNum)) { + if (!IS_SHADED(SurfWinShadingFlag(SurfNum)) || SurfWinGlareControlIsActive(SurfNum)) { // Bare window (ShadeFlag = -1 or 0 or shading device of off) for (int Lay = 1; Lay <= NGlass; ++Lay) { // Add contribution of beam reflected from outside and inside reveal @@ -6401,7 +6401,7 @@ namespace SolarShading { } if (SurfWinWindowModelType(SurfNum) == Window5DetailedModel) { - if (SurfWinShaded(SurfNum) && !SurfWinGlareControlIsActive(SurfNum)) { + if (IS_SHADED(SurfWinShadingFlag(SurfNum)) && !SurfWinGlareControlIsActive(SurfNum)) { if (ShadeFlag != WinShadingFlag::SwitchableGlazing) { // Shade or blind if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::BGShadeOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { @@ -6489,7 +6489,7 @@ namespace SolarShading { } else { DiffTrans = state.dataConstruction->Construct(ConstrNum).TransDiff; } - if (SurfWinShaded(SurfNum) && !SurfWinGlareControlIsActive(SurfNum)) { + if (IS_SHADED(SurfWinShadingFlag(SurfNum)) && !SurfWinGlareControlIsActive(SurfNum)) { if (ShadeFlag != WinShadingFlag::SwitchableGlazing) { // Shade or blind if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::BGShadeOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { @@ -6562,7 +6562,7 @@ namespace SolarShading { //----------------------------------------------------------------- if (ConstrNumSh != 0 && SunLitFract > 0.0) { if (SurfWinWindowModelType(SurfNum) != WindowEQLModel) { - if (SurfWinShaded(SurfNum) && !SurfWinGlareControlIsActive(SurfNum)) { + if (IS_SHADED(SurfWinShadingFlag(SurfNum)) && !SurfWinGlareControlIsActive(SurfNum)) { // Shade or screen or blind on, or switchable glazing // (note in the following that diffusing glass is not allowed in a window with shade, blind or switchable glazing) if (ShadeFlag != WinShadingFlag::IntBlindOn && ShadeFlag != WinShadingFlag::ExtBlindOn && ShadeFlag != WinShadingFlag::BGBlindOn && ShadeFlag != WinShadingFlag::ExtScreenOn) { @@ -6705,7 +6705,7 @@ namespace SolarShading { WinTransDifSolarSky(SurfNum) = DiffTrans * Surface(SurfNum).Area; } - if (!SurfWinShaded(SurfNum) || SurfWinGlareControlIsActive(SurfNum) || ShadeFlag == WinShadingFlag::SwitchableGlazing) { // Unshaded or switchable glazing + if (!IS_SHADED(SurfWinShadingFlag(SurfNum)) || SurfWinGlareControlIsActive(SurfNum) || ShadeFlag == WinShadingFlag::SwitchableGlazing) { // Unshaded or switchable glazing // Note: with previous defs of TBmBm & TBmDif, these come out right for Complex Fenestration // WinTransBmSolar uses the directional-hemispherical transmittance WinTransBmSolar(SurfNum) = (TBmBm + TBmDif) * SunLitFract * CosInc * Surface(SurfNum).Area * InOutProjSLFracMult; @@ -6909,7 +6909,7 @@ namespace SolarShading { // Interior beam absorptance of glass layers and beam transmittance of back exterior & // or interior window WITHOUT SHADING this timestep - if (!SurfWinShaded(BackSurfNum)) { + if (!IS_SHADED(SurfWinShadingFlag(BackSurfNum))) { for (int Lay = 1; Lay <= NBackGlass; ++Lay) { AbsBeamWin(Lay) = POLYF(CosIncBack, state.dataConstruction->Construct(ConstrNumBack).AbsBeamBackCoef({1, 6}, Lay)); } @@ -8703,11 +8703,9 @@ namespace SolarShading { const bool isShading = material.Group == ComplexWindowShade; if (isShading && Lay == 1) { SurfWinShadingFlag(ISurf) = WinShadingFlag::ExtShadeOn; - SurfWinShaded(ISurf) = true; } if (isShading && Lay == TotLayers) { SurfWinShadingFlag(ISurf) = WinShadingFlag::IntShadeOn; - SurfWinShaded(ISurf) = true; } } if (SurfWinShadingFlag(ISurf) == WinShadingFlag::IntShadeOn) { @@ -8761,7 +8759,6 @@ namespace SolarShading { int ShadingType = WindowShadingControl(IShadingCtrl).ShadingType; // Type of shading (interior shade, interior blind, etc.) SurfWinShadingFlag(ISurf) = WinShadingFlag::ShadeOff; // Initialize shading flag to off - SurfWinShaded(ISurf) = false; int IZone = Surface(ISurf).Zone; // Setpoint for shading @@ -9168,9 +9165,6 @@ namespace SolarShading { if (SurfWinShadingFlagEMSOn(ISurf)) { SurfWinShadingFlag(ISurf) = SurfWinShadingFlagEMSValue(ISurf); } - if (SurfWinShadingFlag(ISurf) != WinShadingFlag::NoShade && SurfWinShadingFlag(ISurf) != WinShadingFlag::ShadeOff) { - SurfWinShaded(ISurf) = true; - } } // End of surface loop } } @@ -10201,7 +10195,7 @@ namespace SolarShading { // Quantities related to inside reveal; inside reveal reflection/absorption is assumed // to occur only if an interior shade or blind is not in place. - if (!SurfWinShaded(SurfNum) || ShadeFlag == WinShadingFlag::SwitchableGlazing) { + if (!IS_SHADED(SurfWinShadingFlag(SurfNum)) || ShadeFlag == WinShadingFlag::SwitchableGlazing) { if (A2ill > 1.0e-6) { @@ -10792,7 +10786,7 @@ namespace SolarShading { WinShadingFlag ShadeFlag = SurfWinShadingFlag(HeatTransSurfNum); if (SurfWinWindowModelType(HeatTransSurfNum) != WindowEQLModel) { - if (!SurfWinShaded(HeatTransSurfNum)) { // No window shading + if (!IS_SHADED(ShadeFlag)) { // No window shading // Init accumulator for transmittance calc below DifSolarAbsW = 0.0; @@ -11332,7 +11326,7 @@ namespace SolarShading { TotGlassLayers = state.dataConstruction->Construct(ConstrNum).TotGlassLayers; ShadeFlag = SurfWinShadingFlag(HeatTransSurfNum); - if (!SurfWinShaded(HeatTransSurfNum)) { // No window shading + if (!IS_SHADED(ShadeFlag)) { // No window shading // Init accumulator for transmittance calc below DifSolarAbsW = 0.0; diff --git a/src/EnergyPlus/SurfaceGeometry.cc b/src/EnergyPlus/SurfaceGeometry.cc index 9d821440a46..41a082ff83a 100644 --- a/src/EnergyPlus/SurfaceGeometry.cc +++ b/src/EnergyPlus/SurfaceGeometry.cc @@ -160,7 +160,6 @@ namespace SurfaceGeometry { SurfWinProfileAngVert.dimension(NumSurfaces, 0); SurfWinShadingFlag.dimension(NumSurfaces, WinShadingFlag::ShadeOff); - SurfWinShaded.dimension(NumSurfaces, false); SurfWinShadingFlagEMSOn.dimension(NumSurfaces, 0); SurfWinShadingFlagEMSValue.dimension(NumSurfaces, WinShadingFlag::ShadeOff); SurfWinGlareControlIsActive.dimension(NumSurfaces, false); diff --git a/tst/EnergyPlus/unit/DaylightingManager.unit.cc b/tst/EnergyPlus/unit/DaylightingManager.unit.cc index 437176b08fe..1affe15f984 100644 --- a/tst/EnergyPlus/unit/DaylightingManager.unit.cc +++ b/tst/EnergyPlus/unit/DaylightingManager.unit.cc @@ -1386,7 +1386,6 @@ TEST_F(EnergyPlusFixture, DaylightingManager_DayltgInteriorIllum_Test) EXPECT_NEAR(state->dataDaylightingManager->DaylIllum(2), 10.0, 0.001); SurfWinShadingFlag(IWin) = DataSurfaces::WinShadingFlag::ExtBlindOn; - SurfWinShaded(IWin) = true; DaylightingManager::DayltgInteriorIllum(*state, ZoneNum); EXPECT_NEAR(state->dataDaylightingManager->DaylIllum(1), 50.0, 0.001); EXPECT_NEAR(state->dataDaylightingManager->DaylIllum(2), 5.0, 0.001); @@ -1395,13 +1394,11 @@ TEST_F(EnergyPlusFixture, DaylightingManager_DayltgInteriorIllum_Test) // BSDF does shading differently, it's integrated in the base state SurfWinWindowModelType(IWin) = WindowBSDFModel; SurfWinShadingFlag(IWin) = DataSurfaces::WinShadingFlag::NoShade; - SurfWinShaded(IWin) = false; DaylightingManager::DayltgInteriorIllum(*state, ZoneNum); EXPECT_NEAR(state->dataDaylightingManager->DaylIllum(1), 100.0, 0.001); EXPECT_NEAR(state->dataDaylightingManager->DaylIllum(2), 10.0, 0.001); SurfWinShadingFlag(IWin) = DataSurfaces::WinShadingFlag::ExtBlindOn; - SurfWinShaded(IWin) = true; DaylightingManager::DayltgInteriorIllum(*state, ZoneNum); EXPECT_NEAR(state->dataDaylightingManager->DaylIllum(1), 100.0, 0.001); EXPECT_NEAR(state->dataDaylightingManager->DaylIllum(2), 10.0, 0.001); From 6aabfc7f5e960b09023b2793a57a23ff3f9e533b Mon Sep 17 00:00:00 2001 From: xuanluo113 Date: Sun, 17 Jan 2021 19:02:23 -0800 Subject: [PATCH 16/76] fix index --- src/EnergyPlus/DaylightingManager.cc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/EnergyPlus/DaylightingManager.cc b/src/EnergyPlus/DaylightingManager.cc index 24608ea5bd5..7aa4dfcdef6 100644 --- a/src/EnergyPlus/DaylightingManager.cc +++ b/src/EnergyPlus/DaylightingManager.cc @@ -5652,7 +5652,7 @@ namespace EnergyPlus::DaylightingManager { // Loop over exterior windows associated with zone for (int loop = 1; loop <= state.dataDaylightingData->ZoneDaylight(ZoneNum).NumOfDayltgExtWins; ++loop) { int IWin = state.dataDaylightingData->ZoneDaylight(ZoneNum).DayltgExtWinSurfNums(loop); - bool WinShadingIndex = findWinShadingIndex(IWin); + int WinShadingIndex = findWinShadingIndex(IWin); // Conversion from ft-L to cd/m2, with cd/m2 = 0.2936 ft-L, gives the 0.4794 factor // below, which is (0.2936)**0.6 Real64 GTOT1 = 0.4794 * (std::pow(state.dataDaylightingData->ZoneDaylight(ZoneNum).SourceLumFromWinAtRefPt(loop, WinShadingIndex, IL), 1.6)) * @@ -5714,7 +5714,7 @@ namespace EnergyPlus::DaylightingManager { // Loop over exterior windows associated with zone for (int loop = 1; loop <= state.dataDaylightingData->ZoneDaylight(ZoneNum).NumOfDayltgExtWins; ++loop) { int IWin = state.dataDaylightingData->ZoneDaylight(ZoneNum).DayltgExtWinSurfNums(loop); - bool WinShadingIndex = findWinShadingIndex(IWin); + int WinShadingIndex = findWinShadingIndex(IWin); // Conversion from ft-L to cd/m2, with cd/m2 = 0.2936 ft-L, gives the 0.4794 factor // below, which is (0.2936)**0.6 Real64 GTOT1 = 0.4794 * (std::pow(state.dataDaylightingData->ZoneDaylight(ZoneNum).SourceLumFromWinAtRefPt(loop, WinShadingIndex, IL), 1.6)) * @@ -6584,7 +6584,7 @@ namespace EnergyPlus::DaylightingManager { loop = state.dataDaylightingData->ZoneDaylight(ZoneNum).MapShdOrdToLoopNum(count); ICtrl = Surface(IWin).activeWindowShadingControl; - bool IS = findWinShadingIndex(IWin); + int IS = findWinShadingIndex(IWin); if (Surface(IWin).HasShadeControl) { if (SurfWinShadingFlag(IWin) == WinShadingFlag::SwitchableGlazing && SurfWinGlareControlIsActive(IWin) && WindowShadingControl(ICtrl).ShadingControlType == WSCT_MeetDaylIlumSetp && !previously_shaded(loop)) { @@ -6859,9 +6859,10 @@ namespace EnergyPlus::DaylightingManager { for (const auto IWin : listOfExtWin) { ++count; + // need to map back to the original order of the "loop" to not change all the other data structures loop = state.dataDaylightingData->ZoneDaylight(ZoneNum).MapShdOrdToLoopNum(count); - if (!SurfWinGlareControlIsActive(IWin) && SurfWinShadingFlag(IWin) != WinShadingFlag::SwitchableGlazing) continue; + if (SurfWinShadingFlag(IWin) != WinShadingFlag::SwitchableGlazing) continue; ICtrl = Surface(IWin).activeWindowShadingControl; if (!Surface(IWin).HasShadeControl) continue; @@ -6884,6 +6885,7 @@ namespace EnergyPlus::DaylightingManager { } SurfWinShadingFlag(IWin) = WinShadingFlag::ShadeOff; + SurfWinGlareControlIsActive(IWin) = false; continue; } From cdf9ff71a051efd6be04c3c1ae7c894a7f70346b Mon Sep 17 00:00:00 2001 From: xuanluo113 Date: Tue, 19 Jan 2021 09:15:01 -0800 Subject: [PATCH 17/76] macros --- src/EnergyPlus/DataSurfaces.hh | 7 + src/EnergyPlus/HeatBalanceSurfaceManager.cc | 115 ++++++-------- src/EnergyPlus/SolarShading.cc | 159 +++++++++----------- 3 files changed, 124 insertions(+), 157 deletions(-) diff --git a/src/EnergyPlus/DataSurfaces.hh b/src/EnergyPlus/DataSurfaces.hh index 764e705dfec..e838efd20ee 100644 --- a/src/EnergyPlus/DataSurfaces.hh +++ b/src/EnergyPlus/DataSurfaces.hh @@ -67,9 +67,16 @@ #define BITF(B) (1 << (int(B))) +#define BITF_TEST(V, B) (((V) & (B)) == (B)) #define BITF_TEST_ANY(V, B) (((V) & (B)) != 0) #define IS_SHADED(SHADE_FLAG) !BITF_TEST_ANY(BITF(SHADE_FLAG), BITF(WinShadingFlag::NoShade) | BITF(WinShadingFlag::ShadeOff)) +#define IS_SHADE_ON(SHADE_FLAG) BITF_TEST_ANY(BITF(SHADE_FLAG), BITF(WinShadingFlag::IntShadeOn) | BITF(WinShadingFlag::ExtShadeOn) | BITF(WinShadingFlag::BGShadeOn)) +#define IS_SHADE_SCREEN_ON(SHADE_FLAG) BITF_TEST_ANY(BITF(SHADE_FLAG), BITF(WinShadingFlag::IntShadeOn) | BITF(WinShadingFlag::ExtShadeOn) | BITF(WinShadingFlag::BGShadeOn) | BITF(WinShadingFlag::ExtScreenOn)) +#define IS_BLIND_ON(SHADE_FLAG) BITF_TEST_ANY(BITF(SHADE_FLAG), BITF(WinShadingFlag::IntBlindOn) | BITF(WinShadingFlag::ExtBlindOn) | BITF(WinShadingFlag::BGBlindOn)) +#define IS_INT_SHADED(SHADE_FLAG) BITF_TEST_ANY(BITF(SHADE_FLAG), BITF(WinShadingFlag::IntShadeOn) | BITF(WinShadingFlag::IntBlindOn)) +#define IS_EXT_SHADED(SHADE_FLAG) BITF_TEST_ANY(BITF(SHADE_FLAG), BITF(WinShadingFlag::ExtShadeOn) | BITF(WinShadingFlag::ExtBlindOn) | BITF(WinShadingFlag::ExtScreenOn)) +#define IS_BG_SHADED(SHADE_FLAG) BITF_TEST_ANY(BITF(SHADE_FLAG), BITF(WinShadingFlag::BGShadeOn) | BITF(WinShadingFlag::BGBlindOn)) namespace EnergyPlus { diff --git a/src/EnergyPlus/HeatBalanceSurfaceManager.cc b/src/EnergyPlus/HeatBalanceSurfaceManager.cc index d2e5e915b24..0f6f6e1f781 100644 --- a/src/EnergyPlus/HeatBalanceSurfaceManager.cc +++ b/src/EnergyPlus/HeatBalanceSurfaceManager.cc @@ -2883,23 +2883,19 @@ namespace HeatBalanceSurfaceManager { AbsDiffWin(Lay) = state.dataConstruction->Construct(ConstrNum).AbsDiff(Lay); } - if (IS_SHADED(SurfWinShadingFlag(SurfNum))) { // Shaded window + if (IS_SHADED(ShadeFlag)) { // Shaded window int ConstrNumSh = Surface(SurfNum).activeShadedConstruction; // Shaded window construction if (SurfWinStormWinFlag(SurfNum) == 1) ConstrNumSh = Surface(SurfNum).activeStormWinShadedConstruction; - if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::BGShadeOn || - ShadeFlag == WinShadingFlag::ExtScreenOn) { // Shade/screen on + if (IS_SHADE_SCREEN_ON(ShadeFlag)) { // Shade/screen on for (int Lay = 1; Lay <= TotGlassLay; ++Lay) { AbsDiffWin(Lay) = state.dataConstruction->Construct(ConstrNumSh).AbsDiff(Lay); } SurfWinExtDiffAbsByShade(SurfNum) = state.dataConstruction->Construct(ConstrNumSh).AbsDiffShade * (SkySolarInc + GndSolarInc); - } - - if (ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn || - ShadeFlag == WinShadingFlag::BGBlindOn) { // Blind on + } else if (IS_BLIND_ON(ShadeFlag)) { // Blind on for (int Lay = 1; Lay <= TotGlassLay; ++Lay) { AbsDiffWin(Lay) = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), @@ -2939,11 +2935,10 @@ namespace HeatBalanceSurfaceManager { // Correct for shadowing of divider onto interior shading device (note that dividers are // not allowed in windows with between-glass shade/blind) - if ((ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn) && - SurfWinDividerArea(SurfNum) > 0.0) + if (IS_INT_SHADED(ShadeFlag) && SurfWinDividerArea(SurfNum) > 0.0) SurfWinExtDiffAbsByShade(SurfNum) *= SurfWinGlazedFrac(SurfNum); - if (ShadeFlag == WinShadingFlag::SwitchableGlazing) { // Switchable glazing + if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::SwitchableGlazing))) { // Switchable glazing Real64 SwitchFac = SurfWinSwitchingFactor( SurfNum); // Switching factor for switchable glazing for (int Lay = 1; Lay <= TotGlassLay; ++Lay) { @@ -2960,8 +2955,7 @@ namespace HeatBalanceSurfaceManager { SurfWinQRadSWwinAbs(Lay, SurfNum) = AbsDiffWin(Lay) * (SkySolarInc + GndSolarInc) + SurfWinA(Lay, SurfNum) * BeamSolar; // SurfWinA is from InteriorSolarDistribution - if (ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn || - ShadeFlag == WinShadingFlag::BGBlindOn) { + if (IS_BLIND_ON(ShadeFlag)) { int ConstrNumSh = Surface(SurfNum).activeShadedConstruction; if (Blind(SurfWinBlindNumber(SurfNum)).SlatOrientation == Horizontal) { // AbsDiffGlassLayGnd - System glass layer ground diffuse solar absorptance with blind on @@ -3162,7 +3156,7 @@ namespace HeatBalanceSurfaceManager { Real64 TransGl = POLYF(CosInc, state.dataConstruction->Construct( ConstrNum).TransSolBeamCoef); TransDiffGl = state.dataConstruction->Construct(ConstrNum).TransDiff; - if (ShadeFlag == WinShadingFlag::SwitchableGlazing) { // Switchable glazing + if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::SwitchableGlazing))) { // Switchable glazing Real64 SwitchFac = SurfWinSwitchingFactor(SurfNum); int ConstrNumSh = Surface(SurfNum).activeShadedConstruction; Real64 TransGlSh = POLYF(CosInc, state.dataConstruction->Construct( @@ -3216,7 +3210,7 @@ namespace HeatBalanceSurfaceManager { Real64 AbsGl = 1.0 - TransGl - ReflGl; Real64 SwitchFac = SurfWinSwitchingFactor(SurfNum); int ConstrNumSh = Surface(SurfNum).activeShadedConstruction; - if (ShadeFlag == WinShadingFlag::SwitchableGlazing) { // Switchable glazing + if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::SwitchableGlazing))) { // Switchable glazing Real64 MatNumGlSh = state.dataConstruction->Construct( ConstrNumSh).LayerPoint(1); Real64 TransGlSh = state.dataMaterial->Material(MatNumGlSh).Trans; @@ -3236,8 +3230,7 @@ namespace HeatBalanceSurfaceManager { Real64 BeamDivHorFaceInc = 0.0; // Beam solar on divider's horizontal outside projection faces (W/m2) Real64 BeamDivVertFaceInc = 0.0; // Beam solar on divider's vertical outside projection faces (W/m2) // Beam incident on horizontal and vertical projection faces of divider if no exterior shading - if (DivProjOut > 0.0 && ShadeFlag != WinShadingFlag::ExtShadeOn && - ShadeFlag != WinShadingFlag::ExtBlindOn && ShadeFlag != WinShadingFlag::ExtScreenOn) { + if (DivProjOut > 0.0 && !IS_EXT_SHADED(ShadeFlag)) { BeamDivHorFaceInc = state.dataEnvrn->BeamSolarRad * CosIncAngHorProj * FrameDivider(FrDivNum).HorDividers * DivProjOut * (Surface(SurfNum).Width - @@ -3253,9 +3246,7 @@ namespace HeatBalanceSurfaceManager { Real64 DivIncSolarOutDif = 0.0; // Diffuse solar incident on outside of divider including diffuse on divider projection (W/m2) Real64 DivIncSolarInBm = 0.0; // Diffuse solar incident on inside of divider including beam on divider projection (W/m2) Real64 DivIncSolarInDif = 0.0; // Diffuse solar incident on inside of divider including diffuse on divider projection (W/m2) - if (ShadeFlag != WinShadingFlag::ExtShadeOn && ShadeFlag != WinShadingFlag::ExtBlindOn && - ShadeFlag != WinShadingFlag::BGShadeOn && ShadeFlag != WinShadingFlag::BGBlindOn && - ShadeFlag != WinShadingFlag::ExtScreenOn) { // No exterior or between-glass shading + if (!IS_EXT_SHADED(ShadeFlag) && !IS_BG_SHADED(ShadeFlag)) { // No exterior or between-glass shading DivIncSolarOutBm = BeamFaceInc + BeamDivHorFaceInc + BeamDivVertFaceInc; DivIncSolarOutDif = DifSolarFaceInc * (1.0 + SurfWinProjCorrDivOut(SurfNum)); @@ -3264,7 +3255,7 @@ namespace HeatBalanceSurfaceManager { ConstrNum).TransSolBeamCoef); Real64 TransDiffGl = state.dataConstruction->Construct( ConstrNum).TransDiff; // Diffuse solar transmittance - if (ShadeFlag == WinShadingFlag::SwitchableGlazing) { // Switchable glazing + if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::SwitchableGlazing))) { // Switchable glazing Real64 SwitchFac = SurfWinSwitchingFactor(SurfNum); int ConstrNumSh = Surface(SurfNum).activeShadedConstruction; Real64 TransGlSh = POLYF(CosInc, state.dataConstruction->Construct( @@ -3308,15 +3299,14 @@ namespace HeatBalanceSurfaceManager { DivIncSolarInDif = DifSolarFaceInc * SurfWinProjCorrDivIn(SurfNum) * state.dataConstruction->Construct(ConstrNum).TransDiff; } - if (ShadeFlag != WinShadingFlag::ExtShadeOn && ShadeFlag != WinShadingFlag::ExtBlindOn && - ShadeFlag != WinShadingFlag::ExtScreenOn && ShadeFlag != WinShadingFlag::BGShadeOn && ShadeFlag != WinShadingFlag::BGBlindOn) { + if (!IS_EXT_SHADED(ShadeFlag) && !IS_BG_SHADED(ShadeFlag)) { // No exterior or between-glass shade, screen or blind SurfWinDividerQRadOutAbs(SurfNum) = DividerAbs * (DivIncSolarOutBm + DivIncSolarOutDif); SurfWinDividerQRadInAbs(SurfNum) = DividerAbs * (DivIncSolarInBm + DivIncSolarInDif); // Exterior shade, screen or blind - } else if (ShadeFlag == WinShadingFlag::ExtBlindOn) { // Exterior blind + } else if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::ExtBlindOn))) { // Exterior blind int BlNum = SurfWinBlindNumber(SurfNum); Real64 ProfAng; // Solar profile angle (rad) ProfileAngle(SurfNum, state.dataEnvrn->SOLCOS, Blind(BlNum).SlatOrientation, ProfAng); @@ -3339,7 +3329,7 @@ namespace HeatBalanceSurfaceManager { DivIncSolarInDif * InterpSlatAng(SlatAng, SurfWinMovableSlats(SurfNum), Blind(BlNum).SolFrontDiffDiffTrans)); - } else if (ShadeFlag == WinShadingFlag::ExtShadeOn) { // Exterior shade + } else if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::ExtShadeOn))) { // Exterior shade int ConstrNumSh = Surface(SurfNum).activeShadedConstruction; SurfWinDividerQRadOutAbs(SurfNum) = DividerAbs * state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNumSh).LayerPoint(1)).Trans * @@ -3348,7 +3338,7 @@ namespace HeatBalanceSurfaceManager { DividerAbs * state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNumSh).LayerPoint(1)).Trans * (DivIncSolarInBm +DivIncSolarInDif); - } else if (ShadeFlag == WinShadingFlag::ExtScreenOn) { // Exterior screen + } else if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::ExtScreenOn))) { // Exterior screen SurfWinDividerQRadOutAbs(SurfNum) = DividerAbs * (SurfaceScreens( SurfWinScreenNumber(SurfNum)).BmBmTrans + SurfaceScreens( SurfWinScreenNumber(SurfNum)).BmDifTrans) * @@ -3580,49 +3570,43 @@ namespace HeatBalanceSurfaceManager { SurfQRadThermInAbs(SurfNum) = adjQL * TMULT(radEnclosureNum) * ITABSF(SurfNum); } - if (!IS_SHADED(SurfWinShadingFlag(SurfNum))) { // No window shading + if (!IS_SHADED(ShadeFlag)) { // No window shading for (int IGlass = 1; IGlass <= TotGlassLayers; ++IGlass) { SurfWinQRadSWwinAbs(IGlass, SurfNum) += QS(solEnclosureNum) * state.dataConstruction->Construct(ConstrNum).AbsDiffBack(IGlass); } - } else if (ConstrNumSh != 0 && ShadeFlag != WinShadingFlag::SwitchableGlazing) { + } else if (ConstrNumSh != 0 && !BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::SwitchableGlazing))) { // Interior, exterior or between-glass shade, screen or blind in place for (int IGlass = 1; IGlass <= state.dataConstruction->Construct(ConstrNumSh).TotGlassLayers; ++IGlass) { - if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::BGShadeOn || - ShadeFlag == WinShadingFlag::ExtScreenOn) - SurfWinQRadSWwinAbs(IGlass, SurfNum) += QS(solEnclosureNum) * - state.dataConstruction->Construct(ConstrNumSh).AbsDiffBack( - IGlass); - if (ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn) { + if (IS_SHADE_SCREEN_ON(ShadeFlag)) { + SurfWinQRadSWwinAbs(IGlass, SurfNum) += QS(solEnclosureNum) * state.dataConstruction->Construct(ConstrNumSh).AbsDiffBack(IGlass); + } else if (BITF_TEST_ANY(BITF(ShadeFlag), BITF(WinShadingFlag::IntBlindOn) | BITF(WinShadingFlag::ExtBlindOn))) { Real64 BlAbsDiffBk = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), state.dataConstruction->Construct(ConstrNumSh).BlAbsDiffBack(_, IGlass)); // Glass layer back diffuse solar absorptance when blind in place SurfWinQRadSWwinAbs(IGlass, SurfNum) += QS(solEnclosureNum) * BlAbsDiffBk; } } - if (ShadeFlag == WinShadingFlag::IntShadeOn) - SurfWinIntLWAbsByShade(SurfNum) = - QL(radEnclosureNum) * state.dataConstruction->Construct(ConstrNumSh).ShadeAbsorpThermal * - TMULT(radEnclosureNum); - if (ShadeFlag == WinShadingFlag::IntBlindOn) { + if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::IntShadeOn))) { + SurfWinIntLWAbsByShade(SurfNum) = QL(radEnclosureNum) * state.dataConstruction->Construct(ConstrNumSh).ShadeAbsorpThermal * TMULT(radEnclosureNum); + } else if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::IntBlindOn))) { Real64 EffBlEmiss = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), SurfaceWindow(SurfNum).EffShBlindEmiss); // Blind emissivity (thermal absorptance) as part of glazing system SurfWinIntLWAbsByShade(SurfNum) = QL(radEnclosureNum) * EffBlEmiss * TMULT(radEnclosureNum); } - if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::BGShadeOn || - ShadeFlag == WinShadingFlag::ExtScreenOn) - SurfWinIntSWAbsByShade(SurfNum) = - QS(solEnclosureNum) * state.dataConstruction->Construct(ConstrNumSh).AbsDiffBackShade; - if (ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::BGBlindOn) { + if (IS_SHADE_SCREEN_ON(ShadeFlag)){ + SurfWinIntSWAbsByShade(SurfNum) = QS(solEnclosureNum) * state.dataConstruction->Construct(ConstrNumSh).AbsDiffBackShade; + } else if (IS_BLIND_ON(ShadeFlag)) { Real64 AbsDiffBkBl = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), state.dataConstruction->Construct(ConstrNumSh).AbsDiffBackBlind); // Blind diffuse back solar absorptance as part of glazing system SurfWinIntSWAbsByShade(SurfNum) = QS(solEnclosureNum) * AbsDiffBkBl; } // Correct for divider shadowing - if (ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::ExtScreenOn) + if (IS_EXT_SHADED(ShadeFlag)) { SurfWinIntSWAbsByShade(SurfNum) *= SurfWinGlazedFrac(SurfNum); + } - } else if (ShadeFlag == WinShadingFlag::SwitchableGlazing) { // Switchable glazing + } else if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::SwitchableGlazing))) { // Switchable glazing for (int IGlass = 1; IGlass <= TotGlassLayers; ++IGlass) { SurfWinQRadSWwinAbs(IGlass, SurfNum) += QS(solEnclosureNum) * @@ -3658,12 +3642,12 @@ namespace HeatBalanceSurfaceManager { DividerThermAbs = state.dataMaterial->Material(MatNumGl).AbsorpThermalBack; } // Correct for interior shade transmittance - if (ShadeFlag == WinShadingFlag::IntShadeOn) { + if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::IntShadeOn))) { int MatNumSh = state.dataConstruction->Construct(ConstrNumSh).LayerPoint( state.dataConstruction->Construct(ConstrNumSh).TotLayers); // Shade layer material number DividerSolAbs *= state.dataMaterial->Material(MatNumSh).Trans; DividerThermAbs *= state.dataMaterial->Material(MatNumSh).TransThermal; - } else if (ShadeFlag == WinShadingFlag::IntBlindOn) { + } else if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::IntBlindOn))) { int BlNum = SurfWinBlindNumber(SurfNum); DividerSolAbs *= InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), Blind(BlNum).SolBackDiffDiffTrans); @@ -3741,11 +3725,11 @@ namespace HeatBalanceSurfaceManager { } int TotGlassLayers = state.dataConstruction->Construct(ConstrNum).TotGlassLayers; WinShadingFlag ShadeFlag = SurfWinShadingFlag(SurfNum); - if (!IS_SHADED(SurfWinShadingFlag(SurfNum))) { // No window shading + if (!IS_SHADED(ShadeFlag)) { // No window shading for (int IGlass = 1; IGlass <= TotGlassLayers; ++IGlass) { SurfWinQRadSWwinAbs(IGlass, SurfNum) += SurfWinInitialDifSolwinAbs(IGlass, SurfNum); } - } else if (ShadeFlag == WinShadingFlag::SwitchableGlazing) { // Switchable glazing + } else if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::SwitchableGlazing))) { // Switchable glazing for (int IGlass = 1; IGlass <= TotGlassLayers; ++IGlass) { SurfWinQRadSWwinAbs(IGlass, SurfNum) += SurfWinInitialDifSolwinAbs(IGlass, SurfNum); } @@ -3754,10 +3738,9 @@ namespace HeatBalanceSurfaceManager { for (int IGlass = 1; IGlass <= state.dataConstruction->Construct(ConstrNumSh).TotGlassLayers; ++IGlass) { SurfWinQRadSWwinAbs(IGlass, SurfNum) += SurfWinInitialDifSolwinAbs(IGlass, SurfNum); } - if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::BGShadeOn || - ShadeFlag == WinShadingFlag::ExtScreenOn) + if (IS_SHADE_SCREEN_ON(ShadeFlag)) { SurfWinIntSWAbsByShade(SurfNum) += SurfWinInitialDifSolAbsByShade(SurfNum); - if (ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::BGBlindOn) { + } else if (IS_BLIND_ON(ShadeFlag)) { SurfWinIntSWAbsByShade(SurfNum) += SurfWinInitialDifSolAbsByShade(SurfNum); } } // End of shading flag check @@ -3795,7 +3778,7 @@ namespace HeatBalanceSurfaceManager { TotGlassLayers = state.dataConstruction->Construct(ConstrNum).TotGlassLayers; } WinShadingFlag ShadeFlag = SurfWinShadingFlag(SurfNum); - if (!IS_SHADED(SurfWinShadingFlag(SurfNum)) || SurfWinWindowModelType(SurfNum) == WindowBSDFModel) { // No window shading + if (!IS_SHADED(ShadeFlag) || SurfWinWindowModelType(SurfNum) == WindowBSDFModel) { // No window shading for (int IGlass = 1; IGlass <= TotGlassLayers; ++IGlass) { // Initial Transmitted Diffuse Solar Absorbed on Inside of Surface[W] SurfInitialDifSolInAbsReport(SurfNum) += @@ -3805,7 +3788,7 @@ namespace HeatBalanceSurfaceManager { // Total Shortwave Absorbed:All Glass Layers[W] SurfWinSWwinAbsTotalReport(SurfNum) += SurfWinQRadSWwinAbs(IGlass, SurfNum) * Surface(SurfNum).Area; } - } else if (ShadeFlag == WinShadingFlag::SwitchableGlazing) { // Switchable glazing + } else if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::SwitchableGlazing))) { // Switchable glazing for (int IGlass = 1; IGlass <= TotGlassLayers; ++IGlass) { // Initial Transmitted Diffuse Solar Absorbed on Inside of Surface[W] SurfInitialDifSolInAbsReport(SurfNum) += @@ -3915,7 +3898,7 @@ namespace HeatBalanceSurfaceManager { if (!Surface(SurfNum).HeatTransSurf) continue; int ConstrNum = Surface(SurfNum).Construction; WinShadingFlag ShadeFlag = SurfWinShadingFlag(SurfNum); - if (ShadeFlag != WinShadingFlag::SwitchableGlazing) { + if (!BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::SwitchableGlazing))) { SUM1 += Surface(SurfNum).Area * ITABSF(SurfNum); } else { // Switchable glazing SUM1 += Surface(SurfNum).Area * InterpSw(SurfWinSwitchingFactor(SurfNum), @@ -3930,7 +3913,7 @@ namespace HeatBalanceSurfaceManager { Real64 DividerThermAbs = SurfWinDividerEmis(SurfNum); // Window divider thermal absorptance // Suspended (between-glass) divider; relevant emissivity is inner glass emissivity if (SurfWinDividerType(SurfNum) == Suspended) DividerThermAbs = state.dataConstruction->Construct(ConstrNum).InsideAbsorpThermal; - if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn) { + if (IS_INT_SHADED(ShadeFlag)) { // Interior shade or blind in place int ConstrNumSh = Surface(SurfNum).activeShadedConstruction; if (SurfWinHasShadeOrBlindLayer(SurfNum)) { @@ -3940,7 +3923,7 @@ namespace HeatBalanceSurfaceManager { Real64 TauShIR = state.dataMaterial->Material(MatNumSh).TransThermal; // Effective emissivity of shade or blind Real64 EffShDevEmiss = SurfaceWindow(SurfNum).EffShBlindEmiss(1); - if (ShadeFlag == WinShadingFlag::IntBlindOn) { + if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::IntBlindOn))) { TauShIR = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), Blind(SurfWinBlindNumber(SurfNum)).IRBackTrans); @@ -4048,9 +4031,9 @@ namespace HeatBalanceSurfaceManager { // Window with shade, screen or blind if (ConstrNumSh != 0) { - if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::BGShadeOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { + if (IS_SHADE_SCREEN_ON(ShadeFlag)) { AbsDiffLayWin = state.dataConstruction->Construct(ConstrNumSh).AbsDiffBack(Lay); - } else if (ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::BGBlindOn) { + } else if (IS_BLIND_ON(ShadeFlag)) { AbsDiffLayWin = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), state.dataConstruction->Construct(ConstrNumSh).BlAbsDiffBack(_, Lay)); @@ -4058,7 +4041,7 @@ namespace HeatBalanceSurfaceManager { } // Switchable glazing - if (ShadeFlag == WinShadingFlag::SwitchableGlazing) + if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::SwitchableGlazing))) AbsDiffLayWin = InterpSw(SwitchFac, AbsDiffLayWin, state.dataConstruction->Construct(ConstrNumSh).AbsDiffBack(Lay)); AbsDiffTotWin += AbsDiffLayWin; @@ -4070,10 +4053,10 @@ namespace HeatBalanceSurfaceManager { // Window with shade, screen or blind if (ConstrNumSh != 0) { - if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::BGShadeOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { + if (IS_SHADE_SCREEN_ON(ShadeFlag)) { TransDiffWin = state.dataConstruction->Construct(ConstrNumSh).TransDiff; DiffAbsShade = state.dataConstruction->Construct(ConstrNumSh).AbsDiffBackShade; - } else if (ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::BGBlindOn) { + } else if (IS_BLIND_ON(ShadeFlag)) { TransDiffWin = InterpSlatAng( SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), state.dataConstruction->Construct(ConstrNumSh).BlTransDiff); DiffAbsShade = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), @@ -4084,7 +4067,7 @@ namespace HeatBalanceSurfaceManager { // Switchable glazing - if (ShadeFlag == WinShadingFlag::SwitchableGlazing) + if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::SwitchableGlazing))) TransDiffWin = InterpSw(SwitchFac, TransDiffWin, state.dataConstruction->Construct(ConstrNumSh).TransDiff); SUM1 += Surface(SurfNum).Area * (TransDiffWin + AbsDiffTotWin + DiffAbsShade); @@ -4105,7 +4088,7 @@ namespace HeatBalanceSurfaceManager { Real64 DividerRefl = 1.0 - DividerAbs; // Window divider short-wave reflectance DividerAbs = AbsGl + TransGl * (DividerAbs + DividerRefl * AbsGl) / (1.0 - DividerRefl * ReflGl); } - if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn) { + if (IS_INT_SHADED(ShadeFlag)) { SUM1 += SurfWinDividerArea(SurfNum) * (DividerAbs + DiffAbsShade); } else { SUM1 += SurfWinDividerArea(SurfNum) * (1.0 + SurfWinProjCorrDivIn(SurfNum)) * DividerAbs; @@ -6782,7 +6765,7 @@ namespace HeatBalanceSurfaceManager { int RoughSurf = state.dataMaterial->Material(construct.LayerPoint(1)).Roughness; // Outside surface roughness Real64 EmisOut = state.dataMaterial->Material(construct.LayerPoint(1)).AbsorpThermalFront; // Glass outside surface emissivity auto const shading_flag(SurfWinShadingFlag(SurfNum)); - if (shading_flag == WinShadingFlag::ExtShadeOn || shading_flag == WinShadingFlag::ExtBlindOn || shading_flag == WinShadingFlag::ExtScreenOn) { + if (IS_EXT_SHADED(shading_flag)) { // Exterior shade in place int ConstrNumSh = Surface(SurfNum).activeShadedConstruction; if (ConstrNumSh != 0) { @@ -7484,7 +7467,7 @@ namespace HeatBalanceSurfaceManager { Real64 EmisOut = state.dataMaterial->Material(construct.LayerPoint(1)).AbsorpThermalFront; // Glass outside surface emissivity auto const shading_flag(SurfWinShadingFlag(surfNum)); - if (shading_flag == WinShadingFlag::ExtShadeOn || shading_flag == WinShadingFlag::ExtBlindOn || shading_flag == WinShadingFlag::ExtScreenOn) { + if (IS_EXT_SHADED(shading_flag)) { // Exterior shade in place int ConstrNumSh = Surface(surfNum).activeShadedConstruction; if (ConstrNumSh != 0) { diff --git a/src/EnergyPlus/SolarShading.cc b/src/EnergyPlus/SolarShading.cc index 7de320c471e..f28277c7d8f 100644 --- a/src/EnergyPlus/SolarShading.cc +++ b/src/EnergyPlus/SolarShading.cc @@ -6111,7 +6111,7 @@ namespace SolarShading { AbWin(Lay) = POLYF(CosInc, state.dataConstruction->Construct(ConstrNum).AbsBeamCoef({1, 6}, Lay)) * CosInc * SunLitFract * SurfaceWindow(SurfNum).OutProjSLFracMult(state.dataGlobal->HourOfDay); } - if (!IS_SHADED(SurfWinShadingFlag(SurfNum)) || SurfWinGlareControlIsActive(SurfNum)) { + if (!IS_SHADED(ShadeFlag) || SurfWinGlareControlIsActive(SurfNum)) { // Bare window (ShadeFlag = -1 or 0 or shading device of off) for (int Lay = 1; Lay <= NGlass; ++Lay) { // Add contribution of beam reflected from outside and inside reveal @@ -6124,30 +6124,30 @@ namespace SolarShading { Real64 InOutProjSLFracMult = SurfaceWindow(SurfNum).InOutProjSLFracMult(state.dataGlobal->HourOfDay); Array1D AbWinSh(NGlass); // Like AbWin, but for shaded window Array1D ADiffWinSh(NGlass); // Diffuse solar absorptance of glass layer, window with shading device - if (ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::ExtScreenOn) FracSunLit = SunLitFract; + if (IS_EXT_SHADED(ShadeFlag)) FracSunLit = SunLitFract; - if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::BGShadeOn || ShadeFlag == WinShadingFlag::SwitchableGlazing) { + if (IS_SHADE_ON(ShadeFlag) || BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::SwitchableGlazing))) { // Shade or switchable glazing on for (int Lay = 1; Lay <= NGlass; ++Lay) { AbWinSh(Lay) = POLYF(CosInc, state.dataConstruction->Construct(ConstrNumSh).AbsBeamCoef({1, 6}, Lay)) * CosInc * FracSunLit; ADiffWinSh(Lay) = state.dataConstruction->Construct(ConstrNumSh).AbsDiff(Lay); } - if (ShadeFlag == WinShadingFlag::IntShadeOn) { // Exterior beam absorbed by INTERIOR SHADE + if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::IntShadeOn))) { // Exterior beam absorbed by INTERIOR SHADE // Note that AbsBeamShadeCoef includes effect of shade/glazing inter-reflection Real64 AbsShade = POLYF(CosInc, state.dataConstruction->Construct(ConstrNumSh).AbsBeamShadeCoef); // Interior shade or blind beam solar absorptance ExtBeamAbsByShadFac(SurfNum) = (AbsShade * CosInc * SunLitFract * InOutProjSLFracMult + SurfWinOutsRevealDiffOntoGlazing(SurfNum) * state.dataConstruction->Construct(ConstrNumSh).AbsDiffShade) * SurfWinGlazedFrac(SurfNum); // In the above, GlazedFrac corrects for shadowing of divider onto interior shade - } else if (ShadeFlag == WinShadingFlag::ExtShadeOn) { // Exterior beam absorbed by EXTERIOR SHADE + } else if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::ExtShadeOn))) { // Exterior beam absorbed by EXTERIOR SHADE ExtBeamAbsByShadFac(SurfNum) = state.dataConstruction->Construct(ConstrNumSh).AbsDiffShade * CosInc * SunLitFract; - } else if (ShadeFlag == WinShadingFlag::BGShadeOn) { // Exterior beam absorbed by BETWEEN-GLASS SHADE + } else if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::BGShadeOn))) { // Exterior beam absorbed by BETWEEN-GLASS SHADE Real64 AbsShade = POLYF(CosInc, state.dataConstruction->Construct(ConstrNumSh).AbsBeamShadeCoef); ExtBeamAbsByShadFac(SurfNum) = AbsShade * CosInc * SunLitFract + SurfWinOutsRevealDiffOntoGlazing(SurfNum) * state.dataConstruction->Construct(ConstrNumSh).AbsDiffShade; } } else { // Blind or screen on - if (ShadeFlag != WinShadingFlag::ExtScreenOn) ProfileAngle(SurfNum, state.dataEnvrn->SOLCOS, Blind(BlNum).SlatOrientation, ProfAng); - if (ShadeFlag == WinShadingFlag::IntBlindOn) { + if (!BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::ExtScreenOn))) ProfileAngle(SurfNum, state.dataEnvrn->SOLCOS, Blind(BlNum).SlatOrientation, ProfAng); + if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::IntBlindOn))) { // Interior blind on Real64 TGlBm = POLYF(CosInc,state.dataConstruction->Construct(ConstrNum).TransSolBeamCoef); // Glazing system front solar beam transmittance Real64 RGlDiffBack = state.dataConstruction->Construct(ConstrNum).ReflectSolDiffBack; // Glazing system back diffuse solar reflectance @@ -6171,7 +6171,7 @@ namespace SolarShading { SurfWinOutsRevealDiffOntoGlazing(SurfNum) * AbsShadeDiff) * SurfWinGlazedFrac(SurfNum); // In the above, GlazedFrac corrects for shadowing of divider onto interior blind - } else if (ShadeFlag == WinShadingFlag::ExtBlindOn) { + } else if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::ExtBlindOn))) { // Exterior blind on Real64 TBlBmBm = BlindBeamBeamTrans(ProfAng, SlatAng, Blind(BlNum).SlatWidth, Blind(BlNum).SlatSeparation, Blind(BlNum).SlatThickness); // Blind solar front beam-beam transmittance Real64 TBlDifDif = InterpSlatAng(SlatAng, VarSlats, Blind(BlNum).SolFrontDiffDiffTrans); // Diffuse-diffuse solar transmittance of blind @@ -6196,7 +6196,7 @@ namespace SolarShading { Real64 AbsBlDiffBack = InterpSlatAng(SlatAng, VarSlats, Blind(BlNum).SolBackDiffAbs); // Blind solar back diffuse absorptance Real64 AbsShade = AbsBlFront + AbsBlBack * RGlFront * TBlBmBm + (AbsBlDiffBack * RGlDiffFront / (1.0 - RhoBlDiffBack * RGlDiffFront)) * (RGlFront * TBlBmBm * RhoBlBack + TBlBmDiff); ExtBeamAbsByShadFac(SurfNum) = AbsShade * CosInc * SunLitFract * InOutProjSLFracMult; - } else if (ShadeFlag == WinShadingFlag::ExtScreenOn) { + } else if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::ExtScreenOn))) { // Exterior screen on Real64 TScBmBm = SurfaceScreens(ScNum).BmBmTrans; // Screen solar front beam-beam transmittance Real64 TScBmDiff = SurfaceScreens(ScNum).BmDifTrans; // Screen solar front beam-diffuse transmittance @@ -6218,7 +6218,7 @@ namespace SolarShading { Real64 AbsScDiffBack = SurfaceScreens(ScNum).DifScreenAbsorp; // Screen solar back diffuse absorptance Real64 AbsScreen = AbsScBeam * (1.0 + TScBmBm * RGlFront) + (AbsScDiffBack * TScBmBm * RGlFront * RGlDiffFront * RScBack / (1.0 - RScDifBack * RGlDiffFront)); // Exterior screen beam solar absorptance ExtBeamAbsByShadFac(SurfNum) = AbsScreen * CosInc * SunLitFract * InOutProjSLFracMult; - } else if (ShadeFlag == WinShadingFlag::BGBlindOn) { + } else if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::BGBlindOn))) { // Between-glass blind o // Isolated glass and blind properties at current incidence angle, profile angle and slat angle Real64 t1 = POLYF(CosInc, state.dataConstruction->Construct(ConstrNum).tBareSolCoef({1, 6}, 1)); // Bare-glass beam solar transmittance for glass layers 1,2 and 3 @@ -6281,12 +6281,12 @@ namespace SolarShading { } // End of check if blind is interior, exterior or between-glass } // End of check if a blind is on - if (ShadeFlag != WinShadingFlag::SwitchableGlazing) { + if (!BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::SwitchableGlazing))) { // Interior or between glass shade or blind on for (int Lay = 1; Lay <= NGlass; ++Lay) { SurfWinA(Lay, SurfNum) = AbWinSh(Lay); // Add contribution of diffuse from beam on outside reveal - if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::BGShadeOn || ShadeFlag == WinShadingFlag::BGBlindOn) + if (IS_INT_SHADED(ShadeFlag) || IS_BG_SHADED(ShadeFlag)) SurfWinA(Lay, SurfNum) += ADiffWinSh(Lay) * SurfWinOutsRevealDiffOntoGlazing(SurfNum); } } else { @@ -6402,9 +6402,9 @@ namespace SolarShading { if (SurfWinWindowModelType(SurfNum) == Window5DetailedModel) { if (IS_SHADED(SurfWinShadingFlag(SurfNum)) && !SurfWinGlareControlIsActive(SurfNum)) { - if (ShadeFlag != WinShadingFlag::SwitchableGlazing) { + if (!BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::SwitchableGlazing))) { // Shade or blind - if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::BGShadeOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { + if (IS_SHADE_SCREEN_ON(ShadeFlag)) { // Shade or screen DiffTrans = state.dataConstruction->Construct(ConstrNumSh).TransDiff; } else { @@ -6489,10 +6489,10 @@ namespace SolarShading { } else { DiffTrans = state.dataConstruction->Construct(ConstrNum).TransDiff; } - if (IS_SHADED(SurfWinShadingFlag(SurfNum)) && !SurfWinGlareControlIsActive(SurfNum)) { - if (ShadeFlag != WinShadingFlag::SwitchableGlazing) { + if (IS_SHADED(ShadeFlag) && !SurfWinGlareControlIsActive(SurfNum)) { + if (!BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::SwitchableGlazing))) { // Shade or blind - if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::BGShadeOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { + if (IS_SHADE_SCREEN_ON(ShadeFlag)) { // Shade or screen DiffTrans = state.dataConstruction->Construct(ConstrNumSh).TransDiff; } else { @@ -6546,10 +6546,10 @@ namespace SolarShading { if (SurfWinWindowModelType(SurfNum) != WindowEQLModel) { SurfWinBlGlSysTsolDifDif(SurfNum) = DiffTrans; SurfWinScGlSysTsolDifDif(SurfNum) = DiffTrans; - if (ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::BGBlindOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { + if (IS_BLIND_ON(ShadeFlag)|| BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::ExtScreenOn))) { SurfWinBlGlSysTsolDifDif(SurfNum) = DiffTrans; SurfWinScGlSysTsolDifDif(SurfNum) = DiffTrans; - if (ShadeFlag == WinShadingFlag::ExtScreenOn) { + if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::ExtScreenOn))) { SurfWinScTsolDifDif(SurfNum) = SurfaceScreens(ScNum).DifDifTrans; } else { SurfWinBlTsolDifDif(SurfNum) = InterpSlatAng(SlatAng, VarSlats, Blind(BlNum).SolFrontDiffDiffTrans); @@ -6562,10 +6562,10 @@ namespace SolarShading { //----------------------------------------------------------------- if (ConstrNumSh != 0 && SunLitFract > 0.0) { if (SurfWinWindowModelType(SurfNum) != WindowEQLModel) { - if (IS_SHADED(SurfWinShadingFlag(SurfNum)) && !SurfWinGlareControlIsActive(SurfNum)) { + if (IS_SHADED(ShadeFlag) && !SurfWinGlareControlIsActive(SurfNum)) { // Shade or screen or blind on, or switchable glazing // (note in the following that diffusing glass is not allowed in a window with shade, blind or switchable glazing) - if (ShadeFlag != WinShadingFlag::IntBlindOn && ShadeFlag != WinShadingFlag::ExtBlindOn && ShadeFlag != WinShadingFlag::BGBlindOn && ShadeFlag != WinShadingFlag::ExtScreenOn) { + if (IS_SHADE_ON(ShadeFlag) || BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::SwitchableGlazing))) { // Shade on or switchable glazing TBmAllShBlSc = POLYF(CosInc, state.dataConstruction->Construct(ConstrNumSh).TransSolBeamCoef); } else { @@ -6575,7 +6575,7 @@ namespace SolarShading { Real64 TBlDifDif; // Diffuse-diffuse solar transmittance of blind Real64 TScBmBm; Real64 TBlBmBm; - if (ShadeFlag == WinShadingFlag::ExtScreenOn) {// Exterior screen + if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::ExtScreenOn))) {// Exterior screen Real64 RScBack = SurfaceScreens(ScNum).ReflectSolBeamFront; Real64 RScDifDifBk = SurfaceScreens(ScNum).DifReflect; // Diffuse-diffuse back refectance of screen Real64 RGlBmFr = POLYF(CosInc, state.dataConstruction->Construct(ConstrNum).ReflSolBeamFrontCoef); // Beam front reflectance of glass @@ -6595,7 +6595,7 @@ namespace SolarShading { } else { TBlBmBm = BlindBeamBeamTrans(ProfAng, SlatAng, Blind(BlNum).SlatWidth, Blind(BlNum).SlatSeparation, Blind(BlNum).SlatThickness); TBlBmDif = InterpProfSlatAng(ProfAng, SlatAng, VarSlats, Blind(BlNum).SolFrontBeamDiffTrans); - if (ShadeFlag == WinShadingFlag::IntBlindOn) { + if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::IntBlindOn))) { Real64 RhoBlBmDifFr = InterpProfSlatAng(ProfAng, SlatAng, VarSlats, Blind(BlNum).SolFrontBeamDiffRefl); // Beam-diffuse front reflectance of blind Real64 RGlDifBk = state.dataConstruction->Construct(ConstrNum).ReflectSolDiffBack; // Diffuse front reflectance of glass Real64 RhoBlDifDifFr = InterpSlatAng(SlatAng, VarSlats, Blind(BlNum).SolFrontDiffDiffRefl); // Diffuse-diffuse front refectance of blind @@ -6606,7 +6606,7 @@ namespace SolarShading { TBmBmShBlSc = TBmBmBl; // TBmBm * TBlBmBm TBmDifShBlSc = TBmAllShBlSc - TBmBmShBlSc; if (TBmDifShBlSc < 0.0) TBmDifShBlSc = 0.0; - } else if (ShadeFlag == WinShadingFlag::ExtBlindOn) { + } else if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::ExtBlindOn))) { Real64 RhoBlBmDifBk = InterpProfSlatAng(ProfAng, SlatAng, VarSlats, Blind(BlNum).SolBackBeamDiffRefl); // Beam-diffuse back reflectance of blind Real64 RhoBlDifDifBk = InterpSlatAng(SlatAng, VarSlats, Blind(BlNum).SolBackDiffDiffRefl); // Diffuse-diffuse back refectance of blind Real64 RGlBmFr = POLYF(CosInc, state.dataConstruction->Construct(ConstrNum).ReflSolBeamFrontCoef); @@ -6659,8 +6659,7 @@ namespace SolarShading { } // end of checking if not eql window model } // end of checking if sunlitfract > 0 - // TODO: Why this is updated after reporting - if (ShadeFlag == WinShadingFlag::SwitchableGlazing) { + if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::SwitchableGlazing))) { // Switchable glazing Real64 SwitchFac = SurfWinSwitchingFactor(SurfNum); if (!SurfWinSolarDiffusing(SurfNum)) { @@ -6690,7 +6689,7 @@ namespace SolarShading { Real64 InOutProjSLFracMult = SurfaceWindow(SurfNum).InOutProjSLFracMult(state.dataGlobal->HourOfDay); if (SurfWinWindowModelType(SurfNum) != WindowEQLModel) { WinTransDifSolar(SurfNum) = DiffTrans * Surface(SurfNum).Area; - if (ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::BGBlindOn) { + if (IS_BLIND_ON(ShadeFlag)) { if (Blind(SurfWinBlindNumber(SurfNum)).SlatOrientation == Horizontal) { WinTransDifSolarGnd(SurfNum) = DiffTransGnd * Surface(SurfNum).Area; WinTransDifSolarSky(SurfNum) = DiffTransSky * Surface(SurfNum).Area; @@ -6705,7 +6704,7 @@ namespace SolarShading { WinTransDifSolarSky(SurfNum) = DiffTrans * Surface(SurfNum).Area; } - if (!IS_SHADED(SurfWinShadingFlag(SurfNum)) || SurfWinGlareControlIsActive(SurfNum) || ShadeFlag == WinShadingFlag::SwitchableGlazing) { // Unshaded or switchable glazing + if (!IS_SHADED(ShadeFlag) || SurfWinGlareControlIsActive(SurfNum) || BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::SwitchableGlazing))) { // Unshaded or switchable glazing // Note: with previous defs of TBmBm & TBmDif, these come out right for Complex Fenestration // WinTransBmSolar uses the directional-hemispherical transmittance WinTransBmSolar(SurfNum) = (TBmBm + TBmDif) * SunLitFract * CosInc * Surface(SurfNum).Area * InOutProjSLFracMult; @@ -6744,9 +6743,7 @@ namespace SolarShading { // Window is schedule surface gained. Do not make addition to what enters into zone since that information is not available if (FenSolAbsPtr == 0) { Real64 TBmAll; // Window beam-to-(beam+diffuse) transmittance - if (SurfWinWindowModelType(SurfNum) != WindowBSDFModel && - (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn || - ShadeFlag == WinShadingFlag::BGShadeOn || ShadeFlag == WinShadingFlag::BGBlindOn || ShadeFlag == WinShadingFlag::ExtScreenOn)) { + if (SurfWinWindowModelType(SurfNum) != WindowBSDFModel && (IS_BLIND_ON(ShadeFlag) || IS_SHADE_SCREEN_ON(ShadeFlag))) { TBmAll = TBmAllShBlSc; } else { TBmAll = TBmBm + TBmDif; @@ -6790,7 +6787,7 @@ namespace SolarShading { if (SunLitFract > 0.0) { if (SurfWinWindowModelType(SurfNum) != WindowBSDFModel) - if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::BGShadeOn || SurfWinSolarDiffusing(SurfNum) || + if (IS_SHADE_ON(ShadeFlag) || SurfWinSolarDiffusing(SurfNum) || SurfWinOriginalClass(SurfNum) == SurfaceClass::TDD_Diffuser || Surface(SurfNum).Class == SurfaceClass::TDD_Dome) continue; @@ -6813,9 +6810,9 @@ namespace SolarShading { if (ShelfNum > 0) { // Daylighting shelf InShelfSurf = state.dataDaylightingDevicesData->Shelf(ShelfNum).InSurf; } - if (ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::BGBlindOn) { + if (IS_BLIND_ON(ShadeFlag)) { TBm = TBmBmBl; // Interior, exterior or between-glass blind on - } else if (ShadeFlag == WinShadingFlag::ExtScreenOn) { + } else if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::ExtScreenOn))) { TBm = TBmBmSc; // Exterior screen on } else { TBm = TBmBm; // Bare glass or switchable glazing @@ -6909,7 +6906,7 @@ namespace SolarShading { // Interior beam absorptance of glass layers and beam transmittance of back exterior & // or interior window WITHOUT SHADING this timestep - if (!IS_SHADED(SurfWinShadingFlag(BackSurfNum))) { + if (!IS_SHADED(ShadeFlagBack)) { for (int Lay = 1; Lay <= NBackGlass; ++Lay) { AbsBeamWin(Lay) = POLYF(CosIncBack, state.dataConstruction->Construct(ConstrNumBack).AbsBeamBackCoef({1, 6}, Lay)); } @@ -6918,7 +6915,7 @@ namespace SolarShading { // Interior beam absorptance of glass layers and beam transmittance // of back exterior window with SHADE - if (ShadeFlagBack == WinShadingFlag::IntShadeOn || ShadeFlagBack == WinShadingFlag::ExtShadeOn || ShadeFlagBack == WinShadingFlag::BGShadeOn) { + if (IS_SHADE_ON(ShadeFlagBack)) { for (int Lay = 1; Lay <= state.dataConstruction->Construct(ConstrNumBackSh).TotGlassLayers; ++Lay) { AbsBeamWin(Lay) = POLYF(CosIncBack, state.dataConstruction->Construct(ConstrNumBackSh).AbsBeamBackCoef({1, 6}, Lay)); } @@ -6927,15 +6924,11 @@ namespace SolarShading { // Interior beam absorbed by INTERIOR SHADE of back exterior window - if (ShadeFlagBack == WinShadingFlag::IntShadeOn) { + if (BITF_TEST(BITF(ShadeFlagBack), BITF(WinShadingFlag::IntShadeOn))) { IntBeamAbsByShadFac(BackSurfNum) = BOverlap * state.dataConstruction->Construct(ConstrNumBackSh).AbsDiffBackShade / (Surface(BackSurfNum).Area + SurfWinDividerArea(BackSurfNum)); BABSZone += BOverlap * state.dataConstruction->Construct(ConstrNumBackSh).AbsDiffBackShade; - } - - // Interior beam absorbed by EXTERIOR SHADE of back exterior window - - if (ShadeFlagBack == WinShadingFlag::ExtShadeOn) { + } else if (BITF_TEST(BITF(ShadeFlagBack), BITF(WinShadingFlag::ExtShadeOn))) { // Interior beam absorbed by EXTERIOR SHADE of back exterior window Real64 RGlFront = state.dataConstruction->Construct(ConstrNumBack).ReflectSolDiffFront; Real64 AbsSh = state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNumBackSh).LayerPoint(1)).AbsorpSolar; Real64 RhoSh = 1.0 - AbsSh - state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNumBackSh).LayerPoint(1)).Trans; @@ -6943,11 +6936,7 @@ namespace SolarShading { BABSZone += BOverlap * AShBack; IntBeamAbsByShadFac(BackSurfNum) = BOverlap * AShBack / (Surface(BackSurfNum).Area + SurfWinDividerArea(BackSurfNum)); - } - - // Interior beam absorbed by BETWEEN-GLASS SHADE of back exterior window - - if (ShadeFlagBack == WinShadingFlag::BGShadeOn) { + } else if (BITF_TEST(BITF(ShadeFlagBack), BITF(WinShadingFlag::BGShadeOn))) { // Interior beam absorbed by BETWEEN-GLASS SHADE of back exterior window Real64 rbd1k = state.dataConstruction->Construct(ConstrNumBack).rbBareSolDiff(1); Real64 rfd2k = state.dataConstruction->Construct(ConstrNumBack).rfBareSolDiff(2); Real64 AShBack; // System shade absorptance for interior beam solar @@ -6973,7 +6962,7 @@ namespace SolarShading { // Interior beam absorptance of glass layers and beam absorbed in blind // of back exterior window with BLIND - if (ShadeFlagBack == WinShadingFlag::IntBlindOn || ShadeFlagBack == WinShadingFlag::ExtBlindOn || ShadeFlagBack == WinShadingFlag::BGBlindOn) { + if (IS_BLIND_ON(ShadeFlagBack)) { int BlNumBack = SurfWinBlindNumber(BackSurfNum); // Back surface blind number Real64 ProfAngBack; // Back window solar profile angle (radians) ProfileAngle(BackSurfNum, state.dataEnvrn->SOLCOS, Blind(BlNumBack).SlatOrientation, ProfAngBack); @@ -6986,7 +6975,7 @@ namespace SolarShading { Real64 TBlBmDiffBack = InterpProfSlatAng(ProfAngBack, SlatAngBack, VarSlatsBack, Blind(BlNumBack).SolBackBeamDiffTrans); // Blind solar back beam-diffuse transmittance - if (ShadeFlagBack == WinShadingFlag::IntBlindOn) { + if (BITF_TEST(BITF(ShadeFlagBack), BITF(WinShadingFlag::IntBlindOn))) { // Interior beam absorptance of GLASS LAYERS of exterior back window with INTERIOR BLIND // Blind solar front beam reflectance @@ -7028,9 +7017,7 @@ namespace SolarShading { IntBeamAbsByShadFac(BackSurfNum) = BOverlap * ABlBack / (Surface(BackSurfNum).Area + SurfWinDividerArea(BackSurfNum)); BABSZone += BOverlap * ABlBack; - } - - if (ShadeFlagBack == WinShadingFlag::ExtBlindOn) { + } else if (BITF_TEST(BITF(ShadeFlagBack), BITF(WinShadingFlag::ExtBlindOn))) { // Interior beam absorptance of GLASS LAYERS of exterior back window with EXTERIOR BLIND // Glazing system front diffuse solar reflectance @@ -7065,9 +7052,7 @@ namespace SolarShading { BABSZone += BOverlap * ABlBack; IntBeamAbsByShadFac(BackSurfNum) = BOverlap * ABlBack / (Surface(BackSurfNum).Area + SurfWinDividerArea(BackSurfNum)); - } // End of check if exterior blind on back window - - if (ShadeFlagBack == WinShadingFlag::BGBlindOn) { + } else { Real64 t1k = POLYF(CosIncBack, state.dataConstruction->Construct(ConstrNumBack).tBareSolCoef({1, 6}, 1)); Real64 t2k = POLYF(CosIncBack, state.dataConstruction->Construct(ConstrNumBack).tBareSolCoef({1, 6}, 2)); @@ -7129,10 +7114,8 @@ namespace SolarShading { IntBeamAbsByShadFac(BackSurfNum) = BOverlap * ABlBack / Surface(BackSurfNum).Area; } // End of check if between-glass blind is on back window - - } // End of check if blind is on back window - - if (ShadeFlagBack == WinShadingFlag::ExtScreenOn) { + // End of check if blind is on back window + } else if (BITF_TEST(BITF(ShadeFlagBack), BITF(WinShadingFlag::ExtScreenOn))) { // Interior beam absorptance of GLASS LAYERS of exterior back window with EXTERIOR SCREEN int ScNumBack = SurfWinScreenNumber(BackSurfNum); // Back surface screen number @@ -7168,7 +7151,7 @@ namespace SolarShading { // Interior beam absorptance of glass layers of back exterior window with SWITCHABLE GLAZING - if (ShadeFlagBack == WinShadingFlag::SwitchableGlazing && Surface(BackSurfNum).ExtBoundCond == 0) { + if (BITF_TEST(BITF(ShadeFlagBack), BITF(WinShadingFlag::SwitchableGlazing)) && Surface(BackSurfNum).ExtBoundCond == 0) { Real64 SwitchFac = SurfWinSwitchingFactor(SurfNum); // Switching factor for a window Real64 AbsBeamWinSh; // Glass layer beam solar absorptance of a shaded window for (int Lay = 1; Lay <= NBackGlass; ++Lay) { @@ -7634,7 +7617,7 @@ namespace SolarShading { SurfWinDifSolar(SurfNum) = DifSolarInc * WinTransDifSolar(SurfNum); SurfWinBmSolarEnergy(SurfNum) = SurfWinBmSolar(SurfNum) * state.dataGlobal->TimeStepZoneSec; SurfWinDifSolarEnergy(SurfNum) = SurfWinDifSolar(SurfNum) * state.dataGlobal->TimeStepZoneSec; - if (ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::BGBlindOn) { + if (IS_BLIND_ON(ShadeFlag)) { if (Blind(SurfWinBlindNumber(SurfNum)).SlatOrientation == Horizontal) { SurfWinDifSolar(SurfNum) = SkySolarInc * WinTransDifSolarSky(SurfNum) + GndSolarInc * WinTransDifSolarGnd(SurfNum); SurfWinDifSolarEnergy(SurfNum) = SurfWinDifSolar(SurfNum) * state.dataGlobal->TimeStepZoneSec; @@ -8708,7 +8691,7 @@ namespace SolarShading { SurfWinShadingFlag(ISurf) = WinShadingFlag::IntShadeOn; } } - if (SurfWinShadingFlag(ISurf) == WinShadingFlag::IntShadeOn) { + if (BITF_TEST(BITF(SurfWinShadingFlag(ISurf)), BITF(WinShadingFlag::IntShadeOn))) { auto &construction(state.dataConstruction->Construct(Surface(ISurf).Construction)); const int TotLay = construction.TotLayers; int ShadingLayerPtr = construction.LayerPoint(TotLay); @@ -9009,7 +8992,7 @@ namespace SolarShading { } // Set switching factor to fully switched if ShadingFlag = 2 - if (SurfWinShadingFlag(ISurf) == WinShadingFlag::SwitchableGlazing && !SurfWinGlareControlIsActive(ISurf)) { + if (BITF_TEST(BITF(SurfWinShadingFlag(ISurf)), BITF(WinShadingFlag::SwitchableGlazing)) && !SurfWinGlareControlIsActive(ISurf)) { SurfWinSwitchingFactor(ISurf) = 1.0; // Added TH 1/20/2010 @@ -9024,9 +9007,7 @@ namespace SolarShading { SurfWinSlatAngThisTS(ISurf) = 0.0; SurfWinSlatAngThisTSDeg(ISurf) = 0.0; SurfWinSlatsBlockBeam(ISurf) = false; - if (SurfWinShadingFlag(ISurf) == WinShadingFlag::IntBlindOn || - SurfWinShadingFlag(ISurf) == WinShadingFlag::ExtBlindOn || - SurfWinShadingFlag(ISurf) == WinShadingFlag::BGBlindOn) { + if (IS_BLIND_ON(SurfWinShadingFlag(ISurf))) { // Blind in place or may be in place due to glare control int BlNum = SurfWinBlindNumber(ISurf); if (BlNum > 0) { @@ -9157,7 +9138,7 @@ namespace SolarShading { } // End of check if interior or exterior blind in place // CALL CalcScreenTransmittance to intialized all screens prior to HB calc's - if (SurfWinShadingFlag(ISurf) == WinShadingFlag::ExtScreenOn && state.dataEnvrn->SunIsUp) { + if ((BITF_TEST(BITF(SurfWinShadingFlag(ISurf)), BITF(WinShadingFlag::ExtScreenOn)) && state.dataEnvrn->SunIsUp)) { CalcScreenTransmittance(state, ISurf); } @@ -9940,7 +9921,7 @@ namespace SolarShading { if (SurfWinInsideSillDepth(SurfNum) < SurfWinInsideReveal(SurfNum)) continue; ShadeFlag = SurfWinShadingFlag(SurfNum); - if (ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::ExtBlindOn) continue; + if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::ExtShadeOn) | BITF(WinShadingFlag::ExtBlindOn))) continue; if (CosIncAng(state.dataGlobal->TimeStep, state.dataGlobal->HourOfDay, SurfNum) <= 0.0) continue; @@ -10195,12 +10176,12 @@ namespace SolarShading { // Quantities related to inside reveal; inside reveal reflection/absorption is assumed // to occur only if an interior shade or blind is not in place. - if (!IS_SHADED(SurfWinShadingFlag(SurfNum)) || ShadeFlag == WinShadingFlag::SwitchableGlazing) { + if (!IS_SHADED(ShadeFlag) || BITF_TEST_ANY(BITF(ShadeFlag), BITF(WinShadingFlag::SwitchableGlazing))) { if (A2ill > 1.0e-6) { DiffReflGlass = state.dataConstruction->Construct(ConstrNum).ReflectSolDiffBack; - if (ShadeFlag == WinShadingFlag::SwitchableGlazing) { + if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::SwitchableGlazing))) { SolTransGlassSh = POLYF(CosIncAng(state.dataGlobal->TimeStep, state.dataGlobal->HourOfDay, SurfNum), state.dataConstruction->Construct(ConstrNumSh).TransSolBeamCoef); SolTransGlass = InterpSw(SurfWinSwitchingFactor(SurfNum), SolTransGlass, @@ -10877,7 +10858,7 @@ namespace SolarShading { // Accumulate transmitted diffuse solar for reporting SurfWinInitialDifSolInTrans(HeatTransSurfNum) += DifSolarTransW * per_HTSurfaceArea; - } else if (ShadeFlag == WinShadingFlag::SwitchableGlazing) { // Switchable glazing + } else if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::SwitchableGlazing))) { // Switchable glazing // Init accumulator for transmittance calc below DifSolarAbsW = 0.0; @@ -10934,12 +10915,10 @@ namespace SolarShading { auto const &construct_sh_AbsDiffBack(construct_sh.AbsDiffBack); auto const &construct_sh_BlAbsDiffBack(construct_sh.BlAbsDiffBack); for (int IGlass = 1; IGlass <= construct_sh.TotGlassLayers; ++IGlass) { - if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::BGShadeOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { + if (IS_SHADE_SCREEN_ON(ShadeFlag)) { // Calc diffuse solar absorbed in each window glass layer and shade WinDifSolLayAbsW = WinDifSolarTrans_Factor * construct_sh_AbsDiffBack(IGlass); - } - - if (ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::BGBlindOn) { + } else if (IS_BLIND_ON(ShadeFlag)) { BlAbsDiffBk = InterpSlatAng(HTsurf_slat_ang, HTsurf_movable_slats, construct_sh_BlAbsDiffBack(_, IGlass)); // Calc diffuse solar absorbed in each window glass layer and shade WinDifSolLayAbsW = WinDifSolarTrans_Factor * BlAbsDiffBk; @@ -10959,7 +10938,7 @@ namespace SolarShading { // Next calc diffuse solar reflected back to zone from window with shade or blind on // Diffuse back solar reflectance, bare glass or shade on InsideDifReflectance = state.dataConstruction->Construct(ConstrNum).ReflectSolDiffBack; - if (ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn) { + if (BITF_TEST_ANY(BITF(ShadeFlag), BITF(WinShadingFlag::IntBlindOn) | BITF(WinShadingFlag::ExtBlindOn))) { // Diffuse back solar reflectance, blind present, vs. slat angle InsideDifReflectance = InterpSlatAng(HTsurf_slat_ang, HTsurf_movable_slats, state.dataConstruction->Construct(ConstrNum).BlReflectSolDiffBack); @@ -10975,18 +10954,18 @@ namespace SolarShading { // Now calc diffuse solar absorbed by shade/blind itself BlNum = SurfWinBlindNumber(HeatTransSurfNum); - if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::BGShadeOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { + if (IS_SHADE_SCREEN_ON(ShadeFlag)) { // Calc diffuse solar absorbed by shade or screen [W] ShBlDifSolarAbsW = WinDifSolarTrans_Factor * construct_sh.AbsDiffBackShade; - } - if (ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::BGBlindOn) { + } else if (IS_BLIND_ON(ShadeFlag)) { // Calc diffuse solar absorbed by blind [W] AbsDiffBkBl = InterpSlatAng(HTsurf_slat_ang, HTsurf_movable_slats, construct_sh.AbsDiffBackBlind); ShBlDifSolarAbsW = WinDifSolarTrans_Factor * AbsDiffBkBl; } // Correct for divider shadowing - if (ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::ExtScreenOn) + if (IS_EXT_SHADED(ShadeFlag)) { ShBlDifSolarAbsW *= SurfWinGlazedFrac(HeatTransSurfNum); + } // Accumulate diffuse solar absorbed by shade or screen [W/m2] for heat balance calcs SurfWinInitialDifSolAbsByShade(HeatTransSurfNum) += ShBlDifSolarAbsW * per_HTSurfaceArea; @@ -11396,7 +11375,7 @@ namespace SolarShading { InitialZoneDifSolReflW(Surface(AdjSurfNum).SolarEnclIndex) += DifSolarTransW; // [W] } - } else if (ShadeFlag == WinShadingFlag::SwitchableGlazing) { // Switchable glazing + } else if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::SwitchableGlazing))) { // Switchable glazing // Init accumulator for transmittance calc below DifSolarAbsW = 0.0; @@ -11447,12 +11426,10 @@ namespace SolarShading { // First calc diffuse solar absorbed by each glass layer in this window with shade/blind in place for (IGlass = 1; IGlass <= state.dataConstruction->Construct(ConstrNumSh).TotGlassLayers; ++IGlass) { - if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::BGShadeOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { + if (IS_SHADE_SCREEN_ON(ShadeFlag)) { // Calc diffuse solar absorbed in each window glass layer and shade WinDifSolLayAbsW = SolarTrans_ViewFactor * state.dataConstruction->Construct(ConstrNumSh).AbsDiffBack(IGlass); - } - - if (ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::BGBlindOn) { + } else if (IS_BLIND_ON(ShadeFlag)) { BlAbsDiffBk = InterpSlatAng(SurfWinSlatAngThisTS(HeatTransSurfNum), SurfWinMovableSlats(HeatTransSurfNum), state.dataConstruction->Construct(ConstrNumSh).BlAbsDiffBack(_, IGlass)); @@ -11473,7 +11450,7 @@ namespace SolarShading { // Next calc diffuse solar reflected back to zone from window with shade or blind on // Diffuse back solar reflectance, bare glass or shade on InsideDifReflectance = state.dataConstruction->Construct(ConstrNum).ReflectSolDiffBack; - if (ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn) { + if (BITF_TEST_ANY(BITF(ShadeFlag), BITF(WinShadingFlag::IntBlindOn) | BITF(WinShadingFlag::ExtBlindOn))) { // Diffuse back solar reflectance, blind present, vs. slat angle InsideDifReflectance = InterpSlatAng(SurfWinSlatAngThisTS(HeatTransSurfNum), SurfWinMovableSlats(HeatTransSurfNum), @@ -11490,11 +11467,10 @@ namespace SolarShading { // Now calc diffuse solar absorbed by shade/blind itself BlNum = SurfWinBlindNumber(HeatTransSurfNum); - if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::BGShadeOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { + if (IS_SHADE_SCREEN_ON(ShadeFlag)) { // Calc diffuse solar absorbed by shade or screen [W] ShBlDifSolarAbsW = SolarTrans_ViewFactor * state.dataConstruction->Construct(ConstrNumSh).AbsDiffBackShade; - } - if (ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::BGBlindOn) { + } else if (IS_BLIND_ON(ShadeFlag)) { // Calc diffuse solar absorbed by blind [W] AbsDiffBkBl = InterpSlatAng(SurfWinSlatAngThisTS(HeatTransSurfNum), SurfWinMovableSlats(HeatTransSurfNum), @@ -11502,8 +11478,9 @@ namespace SolarShading { ShBlDifSolarAbsW = SolarTrans_ViewFactor * AbsDiffBkBl; } // Correct for divider shadowing - if (ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::ExtScreenOn) + if (IS_EXT_SHADED(ShadeFlag)) { ShBlDifSolarAbsW *= SurfWinGlazedFrac(HeatTransSurfNum); + } // Accumulate diffuse solar absorbed by shade or screen [W/m2] for heat balance calcs SurfWinInitialDifSolAbsByShade(HeatTransSurfNum) += (ShBlDifSolarAbsW / Surface(HeatTransSurfNum).Area); From daf5a74ba598ee62b8b2abf334e694cfbbaf89d5 Mon Sep 17 00:00:00 2001 From: xuanluo113 Date: Tue, 19 Jan 2021 14:15:34 -0800 Subject: [PATCH 18/76] more macros --- src/EnergyPlus/ChilledCeilingPanelSimple.cc | 4 +- src/EnergyPlus/DataSurfaces.hh | 1 - src/EnergyPlus/ElectricBaseboardRadiator.cc | 5 +- src/EnergyPlus/HeatBalanceSurfaceManager.cc | 38 +++++------ src/EnergyPlus/RoomAirModelAirflowNetwork.cc | 4 +- src/EnergyPlus/SolarShading.cc | 72 ++++++++++---------- 6 files changed, 61 insertions(+), 63 deletions(-) diff --git a/src/EnergyPlus/ChilledCeilingPanelSimple.cc b/src/EnergyPlus/ChilledCeilingPanelSimple.cc index 7b825b865cb..3fe28f6b087 100644 --- a/src/EnergyPlus/ChilledCeilingPanelSimple.cc +++ b/src/EnergyPlus/ChilledCeilingPanelSimple.cc @@ -1731,7 +1731,7 @@ namespace CoolingPanelSimple { if (ThisSurf.Class == DataSurfaces::SurfaceClass::Window) { - if (SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntShadeOn || SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntBlindOn) { + if (IS_INT_SHADED(SurfWinShadingFlag(SurfNum))) { // The area is the shade or blind area = the sum of the glazing area and the divider area (which is zero if no divider) Area += DataSurfaces::SurfWinDividerArea(SurfNum); } @@ -1741,7 +1741,7 @@ namespace CoolingPanelSimple { SumHATsurf += HConvIn(SurfNum) * SurfWinFrameArea(SurfNum) * (1.0 + SurfWinProjCorrFrIn(SurfNum)) * SurfWinFrameTempSurfIn(SurfNum); } - if (SurfWinDividerArea(SurfNum) > 0.0 && SurfWinShadingFlag(SurfNum) != WinShadingFlag::IntShadeOn && SurfWinShadingFlag(SurfNum) != WinShadingFlag::IntBlindOn) { + if (SurfWinDividerArea(SurfNum) > 0.0 && !IS_INT_SHADED(SurfWinShadingFlag(SurfNum))) { // Window divider contribution (only from shade or blind for window with divider and interior shade or blind) SumHATsurf += HConvIn(SurfNum) * SurfWinDividerArea(SurfNum) * (1.0 + 2.0 * SurfWinProjCorrDivIn(SurfNum)) * SurfWinDividerTempSurfIn(SurfNum); diff --git a/src/EnergyPlus/DataSurfaces.hh b/src/EnergyPlus/DataSurfaces.hh index e838efd20ee..6345166feb1 100644 --- a/src/EnergyPlus/DataSurfaces.hh +++ b/src/EnergyPlus/DataSurfaces.hh @@ -67,7 +67,6 @@ #define BITF(B) (1 << (int(B))) -#define BITF_TEST(V, B) (((V) & (B)) == (B)) #define BITF_TEST_ANY(V, B) (((V) & (B)) != 0) #define IS_SHADED(SHADE_FLAG) !BITF_TEST_ANY(BITF(SHADE_FLAG), BITF(WinShadingFlag::NoShade) | BITF(WinShadingFlag::ShadeOff)) diff --git a/src/EnergyPlus/ElectricBaseboardRadiator.cc b/src/EnergyPlus/ElectricBaseboardRadiator.cc index 96bcb869470..f4534ce1121 100644 --- a/src/EnergyPlus/ElectricBaseboardRadiator.cc +++ b/src/EnergyPlus/ElectricBaseboardRadiator.cc @@ -1153,7 +1153,7 @@ namespace ElectricBaseboardRadiator { Area = Surface(SurfNum).Area; if (Surface(SurfNum).Class == SurfaceClass::Window) { - if (SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntShadeOn || SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntBlindOn) { + if (IS_INT_SHADED(SurfWinShadingFlag(SurfNum))) { // The area is the shade or blind area = the sum of the glazing area and the divider area (which is zero if no divider) Area += SurfWinDividerArea(SurfNum); } @@ -1164,8 +1164,7 @@ namespace ElectricBaseboardRadiator { SurfWinFrameTempSurfIn(SurfNum); } - if (SurfWinDividerArea(SurfNum) > 0.0 && SurfWinShadingFlag(SurfNum) != WinShadingFlag::IntShadeOn && - SurfWinShadingFlag(SurfNum) != WinShadingFlag::IntBlindOn) { + if (SurfWinDividerArea(SurfNum) > 0.0 && !IS_INT_SHADED(SurfWinShadingFlag(SurfNum))) { // Window divider contribution (only from shade or blind for window with divider and interior shade or blind) SumHATsurf += HConvIn(SurfNum) * SurfWinDividerArea(SurfNum) * (1.0 + 2.0 * SurfWinProjCorrDivIn(SurfNum)) * SurfWinDividerTempSurfIn(SurfNum); diff --git a/src/EnergyPlus/HeatBalanceSurfaceManager.cc b/src/EnergyPlus/HeatBalanceSurfaceManager.cc index 0f6f6e1f781..c20033ad00e 100644 --- a/src/EnergyPlus/HeatBalanceSurfaceManager.cc +++ b/src/EnergyPlus/HeatBalanceSurfaceManager.cc @@ -2938,7 +2938,7 @@ namespace HeatBalanceSurfaceManager { if (IS_INT_SHADED(ShadeFlag) && SurfWinDividerArea(SurfNum) > 0.0) SurfWinExtDiffAbsByShade(SurfNum) *= SurfWinGlazedFrac(SurfNum); - if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::SwitchableGlazing))) { // Switchable glazing + if (ShadeFlag == WinShadingFlag::SwitchableGlazing) { // Switchable glazing Real64 SwitchFac = SurfWinSwitchingFactor( SurfNum); // Switching factor for switchable glazing for (int Lay = 1; Lay <= TotGlassLay; ++Lay) { @@ -3156,7 +3156,7 @@ namespace HeatBalanceSurfaceManager { Real64 TransGl = POLYF(CosInc, state.dataConstruction->Construct( ConstrNum).TransSolBeamCoef); TransDiffGl = state.dataConstruction->Construct(ConstrNum).TransDiff; - if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::SwitchableGlazing))) { // Switchable glazing + if (ShadeFlag == WinShadingFlag::SwitchableGlazing) { // Switchable glazing Real64 SwitchFac = SurfWinSwitchingFactor(SurfNum); int ConstrNumSh = Surface(SurfNum).activeShadedConstruction; Real64 TransGlSh = POLYF(CosInc, state.dataConstruction->Construct( @@ -3210,7 +3210,7 @@ namespace HeatBalanceSurfaceManager { Real64 AbsGl = 1.0 - TransGl - ReflGl; Real64 SwitchFac = SurfWinSwitchingFactor(SurfNum); int ConstrNumSh = Surface(SurfNum).activeShadedConstruction; - if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::SwitchableGlazing))) { // Switchable glazing + if (ShadeFlag == WinShadingFlag::SwitchableGlazing) { // Switchable glazing Real64 MatNumGlSh = state.dataConstruction->Construct( ConstrNumSh).LayerPoint(1); Real64 TransGlSh = state.dataMaterial->Material(MatNumGlSh).Trans; @@ -3255,7 +3255,7 @@ namespace HeatBalanceSurfaceManager { ConstrNum).TransSolBeamCoef); Real64 TransDiffGl = state.dataConstruction->Construct( ConstrNum).TransDiff; // Diffuse solar transmittance - if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::SwitchableGlazing))) { // Switchable glazing + if (ShadeFlag == WinShadingFlag::SwitchableGlazing) { // Switchable glazing Real64 SwitchFac = SurfWinSwitchingFactor(SurfNum); int ConstrNumSh = Surface(SurfNum).activeShadedConstruction; Real64 TransGlSh = POLYF(CosInc, state.dataConstruction->Construct( @@ -3306,7 +3306,7 @@ namespace HeatBalanceSurfaceManager { SurfWinDividerQRadInAbs(SurfNum) = DividerAbs * (DivIncSolarInBm + DivIncSolarInDif); // Exterior shade, screen or blind - } else if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::ExtBlindOn))) { // Exterior blind + } else if (ShadeFlag == WinShadingFlag::ExtBlindOn) { // Exterior blind int BlNum = SurfWinBlindNumber(SurfNum); Real64 ProfAng; // Solar profile angle (rad) ProfileAngle(SurfNum, state.dataEnvrn->SOLCOS, Blind(BlNum).SlatOrientation, ProfAng); @@ -3329,7 +3329,7 @@ namespace HeatBalanceSurfaceManager { DivIncSolarInDif * InterpSlatAng(SlatAng, SurfWinMovableSlats(SurfNum), Blind(BlNum).SolFrontDiffDiffTrans)); - } else if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::ExtShadeOn))) { // Exterior shade + } else if (ShadeFlag == WinShadingFlag::ExtShadeOn) { // Exterior shade int ConstrNumSh = Surface(SurfNum).activeShadedConstruction; SurfWinDividerQRadOutAbs(SurfNum) = DividerAbs * state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNumSh).LayerPoint(1)).Trans * @@ -3338,7 +3338,7 @@ namespace HeatBalanceSurfaceManager { DividerAbs * state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNumSh).LayerPoint(1)).Trans * (DivIncSolarInBm +DivIncSolarInDif); - } else if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::ExtScreenOn))) { // Exterior screen + } else if (ShadeFlag == WinShadingFlag::ExtScreenOn) { // Exterior screen SurfWinDividerQRadOutAbs(SurfNum) = DividerAbs * (SurfaceScreens( SurfWinScreenNumber(SurfNum)).BmBmTrans + SurfaceScreens( SurfWinScreenNumber(SurfNum)).BmDifTrans) * @@ -3575,7 +3575,7 @@ namespace HeatBalanceSurfaceManager { SurfWinQRadSWwinAbs(IGlass, SurfNum) += QS(solEnclosureNum) * state.dataConstruction->Construct(ConstrNum).AbsDiffBack(IGlass); } - } else if (ConstrNumSh != 0 && !BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::SwitchableGlazing))) { + } else if (ConstrNumSh != 0 && ShadeFlag != WinShadingFlag::SwitchableGlazing) { // Interior, exterior or between-glass shade, screen or blind in place for (int IGlass = 1; IGlass <= state.dataConstruction->Construct(ConstrNumSh).TotGlassLayers; ++IGlass) { if (IS_SHADE_SCREEN_ON(ShadeFlag)) { @@ -3586,9 +3586,9 @@ namespace HeatBalanceSurfaceManager { SurfWinQRadSWwinAbs(IGlass, SurfNum) += QS(solEnclosureNum) * BlAbsDiffBk; } } - if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::IntShadeOn))) { + if (ShadeFlag == WinShadingFlag::IntShadeOn) { SurfWinIntLWAbsByShade(SurfNum) = QL(radEnclosureNum) * state.dataConstruction->Construct(ConstrNumSh).ShadeAbsorpThermal * TMULT(radEnclosureNum); - } else if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::IntBlindOn))) { + } else if (ShadeFlag == WinShadingFlag::IntBlindOn) { Real64 EffBlEmiss = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), SurfaceWindow(SurfNum).EffShBlindEmiss); // Blind emissivity (thermal absorptance) as part of glazing system SurfWinIntLWAbsByShade(SurfNum) = QL(radEnclosureNum) * EffBlEmiss * TMULT(radEnclosureNum); @@ -3606,7 +3606,7 @@ namespace HeatBalanceSurfaceManager { SurfWinIntSWAbsByShade(SurfNum) *= SurfWinGlazedFrac(SurfNum); } - } else if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::SwitchableGlazing))) { // Switchable glazing + } else if (ShadeFlag == WinShadingFlag::SwitchableGlazing) { // Switchable glazing for (int IGlass = 1; IGlass <= TotGlassLayers; ++IGlass) { SurfWinQRadSWwinAbs(IGlass, SurfNum) += QS(solEnclosureNum) * @@ -3642,12 +3642,12 @@ namespace HeatBalanceSurfaceManager { DividerThermAbs = state.dataMaterial->Material(MatNumGl).AbsorpThermalBack; } // Correct for interior shade transmittance - if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::IntShadeOn))) { + if (ShadeFlag == WinShadingFlag::IntShadeOn) { int MatNumSh = state.dataConstruction->Construct(ConstrNumSh).LayerPoint( state.dataConstruction->Construct(ConstrNumSh).TotLayers); // Shade layer material number DividerSolAbs *= state.dataMaterial->Material(MatNumSh).Trans; DividerThermAbs *= state.dataMaterial->Material(MatNumSh).TransThermal; - } else if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::IntBlindOn))) { + } else if (ShadeFlag == WinShadingFlag::IntBlindOn) { int BlNum = SurfWinBlindNumber(SurfNum); DividerSolAbs *= InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), Blind(BlNum).SolBackDiffDiffTrans); @@ -3729,7 +3729,7 @@ namespace HeatBalanceSurfaceManager { for (int IGlass = 1; IGlass <= TotGlassLayers; ++IGlass) { SurfWinQRadSWwinAbs(IGlass, SurfNum) += SurfWinInitialDifSolwinAbs(IGlass, SurfNum); } - } else if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::SwitchableGlazing))) { // Switchable glazing + } else if (ShadeFlag == WinShadingFlag::SwitchableGlazing) { // Switchable glazing for (int IGlass = 1; IGlass <= TotGlassLayers; ++IGlass) { SurfWinQRadSWwinAbs(IGlass, SurfNum) += SurfWinInitialDifSolwinAbs(IGlass, SurfNum); } @@ -3788,7 +3788,7 @@ namespace HeatBalanceSurfaceManager { // Total Shortwave Absorbed:All Glass Layers[W] SurfWinSWwinAbsTotalReport(SurfNum) += SurfWinQRadSWwinAbs(IGlass, SurfNum) * Surface(SurfNum).Area; } - } else if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::SwitchableGlazing))) { // Switchable glazing + } else if (ShadeFlag == WinShadingFlag::SwitchableGlazing) { // Switchable glazing for (int IGlass = 1; IGlass <= TotGlassLayers; ++IGlass) { // Initial Transmitted Diffuse Solar Absorbed on Inside of Surface[W] SurfInitialDifSolInAbsReport(SurfNum) += @@ -3898,7 +3898,7 @@ namespace HeatBalanceSurfaceManager { if (!Surface(SurfNum).HeatTransSurf) continue; int ConstrNum = Surface(SurfNum).Construction; WinShadingFlag ShadeFlag = SurfWinShadingFlag(SurfNum); - if (!BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::SwitchableGlazing))) { + if (ShadeFlag != WinShadingFlag::SwitchableGlazing) { SUM1 += Surface(SurfNum).Area * ITABSF(SurfNum); } else { // Switchable glazing SUM1 += Surface(SurfNum).Area * InterpSw(SurfWinSwitchingFactor(SurfNum), @@ -3923,7 +3923,7 @@ namespace HeatBalanceSurfaceManager { Real64 TauShIR = state.dataMaterial->Material(MatNumSh).TransThermal; // Effective emissivity of shade or blind Real64 EffShDevEmiss = SurfaceWindow(SurfNum).EffShBlindEmiss(1); - if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::IntBlindOn))) { + if (ShadeFlag == WinShadingFlag::IntBlindOn) { TauShIR = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), Blind(SurfWinBlindNumber(SurfNum)).IRBackTrans); @@ -4041,7 +4041,7 @@ namespace HeatBalanceSurfaceManager { } // Switchable glazing - if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::SwitchableGlazing))) + if (ShadeFlag == WinShadingFlag::SwitchableGlazing) AbsDiffLayWin = InterpSw(SwitchFac, AbsDiffLayWin, state.dataConstruction->Construct(ConstrNumSh).AbsDiffBack(Lay)); AbsDiffTotWin += AbsDiffLayWin; @@ -4067,7 +4067,7 @@ namespace HeatBalanceSurfaceManager { // Switchable glazing - if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::SwitchableGlazing))) + if (ShadeFlag == WinShadingFlag::SwitchableGlazing) TransDiffWin = InterpSw(SwitchFac, TransDiffWin, state.dataConstruction->Construct(ConstrNumSh).TransDiff); SUM1 += Surface(SurfNum).Area * (TransDiffWin + AbsDiffTotWin + DiffAbsShade); diff --git a/src/EnergyPlus/RoomAirModelAirflowNetwork.cc b/src/EnergyPlus/RoomAirModelAirflowNetwork.cc index 4aeedd7803f..12137e6d1f4 100644 --- a/src/EnergyPlus/RoomAirModelAirflowNetwork.cc +++ b/src/EnergyPlus/RoomAirModelAirflowNetwork.cc @@ -1056,14 +1056,14 @@ namespace RoomAirModelAirflowNetwork { if (Surface(SurfNum).Class == DataSurfaces::SurfaceClass::Window) { // Add to the convective internal gains - if (SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntShadeOn || SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntBlindOn) { + if (IS_INT_SHADED(SurfWinShadingFlag(SurfNum))) { // The shade area covers the area of the glazing plus the area of the dividers. Area += SurfWinDividerArea(SurfNum); SumIntGain += SurfWinDividerHeatGain(SurfNum); } // Convective heat gain from natural convection in gap between glass and interior shade or blind - if (SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntShadeOn || SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntBlindOn) + if (IS_INT_SHADED(SurfWinShadingFlag(SurfNum))) SumIntGain += SurfWinConvHeatFlowNatural(SurfNum); // Convective heat gain from airflow window diff --git a/src/EnergyPlus/SolarShading.cc b/src/EnergyPlus/SolarShading.cc index f28277c7d8f..ceac5037235 100644 --- a/src/EnergyPlus/SolarShading.cc +++ b/src/EnergyPlus/SolarShading.cc @@ -6126,28 +6126,28 @@ namespace SolarShading { Array1D ADiffWinSh(NGlass); // Diffuse solar absorptance of glass layer, window with shading device if (IS_EXT_SHADED(ShadeFlag)) FracSunLit = SunLitFract; - if (IS_SHADE_ON(ShadeFlag) || BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::SwitchableGlazing))) { + if (IS_SHADE_ON(ShadeFlag) || ShadeFlag == WinShadingFlag::SwitchableGlazing) { // Shade or switchable glazing on for (int Lay = 1; Lay <= NGlass; ++Lay) { AbWinSh(Lay) = POLYF(CosInc, state.dataConstruction->Construct(ConstrNumSh).AbsBeamCoef({1, 6}, Lay)) * CosInc * FracSunLit; ADiffWinSh(Lay) = state.dataConstruction->Construct(ConstrNumSh).AbsDiff(Lay); } - if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::IntShadeOn))) { // Exterior beam absorbed by INTERIOR SHADE + if (ShadeFlag == WinShadingFlag::IntShadeOn) { // Exterior beam absorbed by INTERIOR SHADE // Note that AbsBeamShadeCoef includes effect of shade/glazing inter-reflection Real64 AbsShade = POLYF(CosInc, state.dataConstruction->Construct(ConstrNumSh).AbsBeamShadeCoef); // Interior shade or blind beam solar absorptance ExtBeamAbsByShadFac(SurfNum) = (AbsShade * CosInc * SunLitFract * InOutProjSLFracMult + SurfWinOutsRevealDiffOntoGlazing(SurfNum) * state.dataConstruction->Construct(ConstrNumSh).AbsDiffShade) * SurfWinGlazedFrac(SurfNum); // In the above, GlazedFrac corrects for shadowing of divider onto interior shade - } else if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::ExtShadeOn))) { // Exterior beam absorbed by EXTERIOR SHADE + } else if (ShadeFlag == WinShadingFlag::ExtShadeOn) { // Exterior beam absorbed by EXTERIOR SHADE ExtBeamAbsByShadFac(SurfNum) = state.dataConstruction->Construct(ConstrNumSh).AbsDiffShade * CosInc * SunLitFract; - } else if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::BGShadeOn))) { // Exterior beam absorbed by BETWEEN-GLASS SHADE + } else if (ShadeFlag == WinShadingFlag::BGShadeOn) { // Exterior beam absorbed by BETWEEN-GLASS SHADE Real64 AbsShade = POLYF(CosInc, state.dataConstruction->Construct(ConstrNumSh).AbsBeamShadeCoef); ExtBeamAbsByShadFac(SurfNum) = AbsShade * CosInc * SunLitFract + SurfWinOutsRevealDiffOntoGlazing(SurfNum) * state.dataConstruction->Construct(ConstrNumSh).AbsDiffShade; } } else { // Blind or screen on - if (!BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::ExtScreenOn))) ProfileAngle(SurfNum, state.dataEnvrn->SOLCOS, Blind(BlNum).SlatOrientation, ProfAng); - if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::IntBlindOn))) { + if (ShadeFlag != WinShadingFlag::ExtScreenOn) ProfileAngle(SurfNum, state.dataEnvrn->SOLCOS, Blind(BlNum).SlatOrientation, ProfAng); + if (ShadeFlag == WinShadingFlag::IntBlindOn) { // Interior blind on Real64 TGlBm = POLYF(CosInc,state.dataConstruction->Construct(ConstrNum).TransSolBeamCoef); // Glazing system front solar beam transmittance Real64 RGlDiffBack = state.dataConstruction->Construct(ConstrNum).ReflectSolDiffBack; // Glazing system back diffuse solar reflectance @@ -6171,7 +6171,7 @@ namespace SolarShading { SurfWinOutsRevealDiffOntoGlazing(SurfNum) * AbsShadeDiff) * SurfWinGlazedFrac(SurfNum); // In the above, GlazedFrac corrects for shadowing of divider onto interior blind - } else if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::ExtBlindOn))) { + } else if (ShadeFlag == WinShadingFlag::ExtBlindOn) { // Exterior blind on Real64 TBlBmBm = BlindBeamBeamTrans(ProfAng, SlatAng, Blind(BlNum).SlatWidth, Blind(BlNum).SlatSeparation, Blind(BlNum).SlatThickness); // Blind solar front beam-beam transmittance Real64 TBlDifDif = InterpSlatAng(SlatAng, VarSlats, Blind(BlNum).SolFrontDiffDiffTrans); // Diffuse-diffuse solar transmittance of blind @@ -6196,7 +6196,7 @@ namespace SolarShading { Real64 AbsBlDiffBack = InterpSlatAng(SlatAng, VarSlats, Blind(BlNum).SolBackDiffAbs); // Blind solar back diffuse absorptance Real64 AbsShade = AbsBlFront + AbsBlBack * RGlFront * TBlBmBm + (AbsBlDiffBack * RGlDiffFront / (1.0 - RhoBlDiffBack * RGlDiffFront)) * (RGlFront * TBlBmBm * RhoBlBack + TBlBmDiff); ExtBeamAbsByShadFac(SurfNum) = AbsShade * CosInc * SunLitFract * InOutProjSLFracMult; - } else if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::ExtScreenOn))) { + } else if (ShadeFlag == WinShadingFlag::ExtScreenOn) { // Exterior screen on Real64 TScBmBm = SurfaceScreens(ScNum).BmBmTrans; // Screen solar front beam-beam transmittance Real64 TScBmDiff = SurfaceScreens(ScNum).BmDifTrans; // Screen solar front beam-diffuse transmittance @@ -6218,7 +6218,7 @@ namespace SolarShading { Real64 AbsScDiffBack = SurfaceScreens(ScNum).DifScreenAbsorp; // Screen solar back diffuse absorptance Real64 AbsScreen = AbsScBeam * (1.0 + TScBmBm * RGlFront) + (AbsScDiffBack * TScBmBm * RGlFront * RGlDiffFront * RScBack / (1.0 - RScDifBack * RGlDiffFront)); // Exterior screen beam solar absorptance ExtBeamAbsByShadFac(SurfNum) = AbsScreen * CosInc * SunLitFract * InOutProjSLFracMult; - } else if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::BGBlindOn))) { + } else if (ShadeFlag == WinShadingFlag::BGBlindOn) { // Between-glass blind o // Isolated glass and blind properties at current incidence angle, profile angle and slat angle Real64 t1 = POLYF(CosInc, state.dataConstruction->Construct(ConstrNum).tBareSolCoef({1, 6}, 1)); // Bare-glass beam solar transmittance for glass layers 1,2 and 3 @@ -6281,7 +6281,7 @@ namespace SolarShading { } // End of check if blind is interior, exterior or between-glass } // End of check if a blind is on - if (!BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::SwitchableGlazing))) { + if (ShadeFlag != WinShadingFlag::SwitchableGlazing) { // Interior or between glass shade or blind on for (int Lay = 1; Lay <= NGlass; ++Lay) { SurfWinA(Lay, SurfNum) = AbWinSh(Lay); @@ -6402,7 +6402,7 @@ namespace SolarShading { if (SurfWinWindowModelType(SurfNum) == Window5DetailedModel) { if (IS_SHADED(SurfWinShadingFlag(SurfNum)) && !SurfWinGlareControlIsActive(SurfNum)) { - if (!BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::SwitchableGlazing))) { + if (ShadeFlag != WinShadingFlag::SwitchableGlazing) { // Shade or blind if (IS_SHADE_SCREEN_ON(ShadeFlag)) { // Shade or screen @@ -6490,7 +6490,7 @@ namespace SolarShading { DiffTrans = state.dataConstruction->Construct(ConstrNum).TransDiff; } if (IS_SHADED(ShadeFlag) && !SurfWinGlareControlIsActive(SurfNum)) { - if (!BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::SwitchableGlazing))) { + if (ShadeFlag != WinShadingFlag::SwitchableGlazing) { // Shade or blind if (IS_SHADE_SCREEN_ON(ShadeFlag)) { // Shade or screen @@ -6546,10 +6546,10 @@ namespace SolarShading { if (SurfWinWindowModelType(SurfNum) != WindowEQLModel) { SurfWinBlGlSysTsolDifDif(SurfNum) = DiffTrans; SurfWinScGlSysTsolDifDif(SurfNum) = DiffTrans; - if (IS_BLIND_ON(ShadeFlag)|| BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::ExtScreenOn))) { + if (IS_BLIND_ON(ShadeFlag)|| ShadeFlag == WinShadingFlag::ExtScreenOn) { SurfWinBlGlSysTsolDifDif(SurfNum) = DiffTrans; SurfWinScGlSysTsolDifDif(SurfNum) = DiffTrans; - if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::ExtScreenOn))) { + if (ShadeFlag == WinShadingFlag::ExtScreenOn) { SurfWinScTsolDifDif(SurfNum) = SurfaceScreens(ScNum).DifDifTrans; } else { SurfWinBlTsolDifDif(SurfNum) = InterpSlatAng(SlatAng, VarSlats, Blind(BlNum).SolFrontDiffDiffTrans); @@ -6565,7 +6565,7 @@ namespace SolarShading { if (IS_SHADED(ShadeFlag) && !SurfWinGlareControlIsActive(SurfNum)) { // Shade or screen or blind on, or switchable glazing // (note in the following that diffusing glass is not allowed in a window with shade, blind or switchable glazing) - if (IS_SHADE_ON(ShadeFlag) || BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::SwitchableGlazing))) { + if (IS_SHADE_ON(ShadeFlag) || ShadeFlag == WinShadingFlag::SwitchableGlazing) { // Shade on or switchable glazing TBmAllShBlSc = POLYF(CosInc, state.dataConstruction->Construct(ConstrNumSh).TransSolBeamCoef); } else { @@ -6575,7 +6575,7 @@ namespace SolarShading { Real64 TBlDifDif; // Diffuse-diffuse solar transmittance of blind Real64 TScBmBm; Real64 TBlBmBm; - if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::ExtScreenOn))) {// Exterior screen + if (ShadeFlag == WinShadingFlag::ExtScreenOn) {// Exterior screen Real64 RScBack = SurfaceScreens(ScNum).ReflectSolBeamFront; Real64 RScDifDifBk = SurfaceScreens(ScNum).DifReflect; // Diffuse-diffuse back refectance of screen Real64 RGlBmFr = POLYF(CosInc, state.dataConstruction->Construct(ConstrNum).ReflSolBeamFrontCoef); // Beam front reflectance of glass @@ -6595,7 +6595,7 @@ namespace SolarShading { } else { TBlBmBm = BlindBeamBeamTrans(ProfAng, SlatAng, Blind(BlNum).SlatWidth, Blind(BlNum).SlatSeparation, Blind(BlNum).SlatThickness); TBlBmDif = InterpProfSlatAng(ProfAng, SlatAng, VarSlats, Blind(BlNum).SolFrontBeamDiffTrans); - if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::IntBlindOn))) { + if (ShadeFlag == WinShadingFlag::IntBlindOn) { Real64 RhoBlBmDifFr = InterpProfSlatAng(ProfAng, SlatAng, VarSlats, Blind(BlNum).SolFrontBeamDiffRefl); // Beam-diffuse front reflectance of blind Real64 RGlDifBk = state.dataConstruction->Construct(ConstrNum).ReflectSolDiffBack; // Diffuse front reflectance of glass Real64 RhoBlDifDifFr = InterpSlatAng(SlatAng, VarSlats, Blind(BlNum).SolFrontDiffDiffRefl); // Diffuse-diffuse front refectance of blind @@ -6606,7 +6606,7 @@ namespace SolarShading { TBmBmShBlSc = TBmBmBl; // TBmBm * TBlBmBm TBmDifShBlSc = TBmAllShBlSc - TBmBmShBlSc; if (TBmDifShBlSc < 0.0) TBmDifShBlSc = 0.0; - } else if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::ExtBlindOn))) { + } else if (ShadeFlag == WinShadingFlag::ExtBlindOn) { Real64 RhoBlBmDifBk = InterpProfSlatAng(ProfAng, SlatAng, VarSlats, Blind(BlNum).SolBackBeamDiffRefl); // Beam-diffuse back reflectance of blind Real64 RhoBlDifDifBk = InterpSlatAng(SlatAng, VarSlats, Blind(BlNum).SolBackDiffDiffRefl); // Diffuse-diffuse back refectance of blind Real64 RGlBmFr = POLYF(CosInc, state.dataConstruction->Construct(ConstrNum).ReflSolBeamFrontCoef); @@ -6659,7 +6659,7 @@ namespace SolarShading { } // end of checking if not eql window model } // end of checking if sunlitfract > 0 - if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::SwitchableGlazing))) { + if (ShadeFlag == WinShadingFlag::SwitchableGlazing) { // Switchable glazing Real64 SwitchFac = SurfWinSwitchingFactor(SurfNum); if (!SurfWinSolarDiffusing(SurfNum)) { @@ -6704,7 +6704,7 @@ namespace SolarShading { WinTransDifSolarSky(SurfNum) = DiffTrans * Surface(SurfNum).Area; } - if (!IS_SHADED(ShadeFlag) || SurfWinGlareControlIsActive(SurfNum) || BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::SwitchableGlazing))) { // Unshaded or switchable glazing + if (!IS_SHADED(ShadeFlag) || SurfWinGlareControlIsActive(SurfNum) || ShadeFlag == WinShadingFlag::SwitchableGlazing) { // Unshaded or switchable glazing // Note: with previous defs of TBmBm & TBmDif, these come out right for Complex Fenestration // WinTransBmSolar uses the directional-hemispherical transmittance WinTransBmSolar(SurfNum) = (TBmBm + TBmDif) * SunLitFract * CosInc * Surface(SurfNum).Area * InOutProjSLFracMult; @@ -6812,7 +6812,7 @@ namespace SolarShading { } if (IS_BLIND_ON(ShadeFlag)) { TBm = TBmBmBl; // Interior, exterior or between-glass blind on - } else if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::ExtScreenOn))) { + } else if (ShadeFlag == WinShadingFlag::ExtScreenOn) { TBm = TBmBmSc; // Exterior screen on } else { TBm = TBmBm; // Bare glass or switchable glazing @@ -6924,11 +6924,11 @@ namespace SolarShading { // Interior beam absorbed by INTERIOR SHADE of back exterior window - if (BITF_TEST(BITF(ShadeFlagBack), BITF(WinShadingFlag::IntShadeOn))) { + if (ShadeFlagBack == WinShadingFlag::IntShadeOn) { IntBeamAbsByShadFac(BackSurfNum) = BOverlap * state.dataConstruction->Construct(ConstrNumBackSh).AbsDiffBackShade / (Surface(BackSurfNum).Area + SurfWinDividerArea(BackSurfNum)); BABSZone += BOverlap * state.dataConstruction->Construct(ConstrNumBackSh).AbsDiffBackShade; - } else if (BITF_TEST(BITF(ShadeFlagBack), BITF(WinShadingFlag::ExtShadeOn))) { // Interior beam absorbed by EXTERIOR SHADE of back exterior window + } else if (ShadeFlagBack == WinShadingFlag::ExtShadeOn) { // Interior beam absorbed by EXTERIOR SHADE of back exterior window Real64 RGlFront = state.dataConstruction->Construct(ConstrNumBack).ReflectSolDiffFront; Real64 AbsSh = state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNumBackSh).LayerPoint(1)).AbsorpSolar; Real64 RhoSh = 1.0 - AbsSh - state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNumBackSh).LayerPoint(1)).Trans; @@ -6936,7 +6936,7 @@ namespace SolarShading { BABSZone += BOverlap * AShBack; IntBeamAbsByShadFac(BackSurfNum) = BOverlap * AShBack / (Surface(BackSurfNum).Area + SurfWinDividerArea(BackSurfNum)); - } else if (BITF_TEST(BITF(ShadeFlagBack), BITF(WinShadingFlag::BGShadeOn))) { // Interior beam absorbed by BETWEEN-GLASS SHADE of back exterior window + } else if (ShadeFlagBack == WinShadingFlag::BGShadeOn) { // Interior beam absorbed by BETWEEN-GLASS SHADE of back exterior window Real64 rbd1k = state.dataConstruction->Construct(ConstrNumBack).rbBareSolDiff(1); Real64 rfd2k = state.dataConstruction->Construct(ConstrNumBack).rfBareSolDiff(2); Real64 AShBack; // System shade absorptance for interior beam solar @@ -6975,7 +6975,7 @@ namespace SolarShading { Real64 TBlBmDiffBack = InterpProfSlatAng(ProfAngBack, SlatAngBack, VarSlatsBack, Blind(BlNumBack).SolBackBeamDiffTrans); // Blind solar back beam-diffuse transmittance - if (BITF_TEST(BITF(ShadeFlagBack), BITF(WinShadingFlag::IntBlindOn))) { + if (ShadeFlagBack == WinShadingFlag::IntBlindOn) { // Interior beam absorptance of GLASS LAYERS of exterior back window with INTERIOR BLIND // Blind solar front beam reflectance @@ -7017,7 +7017,7 @@ namespace SolarShading { IntBeamAbsByShadFac(BackSurfNum) = BOverlap * ABlBack / (Surface(BackSurfNum).Area + SurfWinDividerArea(BackSurfNum)); BABSZone += BOverlap * ABlBack; - } else if (BITF_TEST(BITF(ShadeFlagBack), BITF(WinShadingFlag::ExtBlindOn))) { + } else if (ShadeFlagBack == WinShadingFlag::ExtBlindOn) { // Interior beam absorptance of GLASS LAYERS of exterior back window with EXTERIOR BLIND // Glazing system front diffuse solar reflectance @@ -7115,7 +7115,7 @@ namespace SolarShading { } // End of check if between-glass blind is on back window // End of check if blind is on back window - } else if (BITF_TEST(BITF(ShadeFlagBack), BITF(WinShadingFlag::ExtScreenOn))) { + } else if (ShadeFlagBack == WinShadingFlag::ExtScreenOn) { // Interior beam absorptance of GLASS LAYERS of exterior back window with EXTERIOR SCREEN int ScNumBack = SurfWinScreenNumber(BackSurfNum); // Back surface screen number @@ -7151,7 +7151,7 @@ namespace SolarShading { // Interior beam absorptance of glass layers of back exterior window with SWITCHABLE GLAZING - if (BITF_TEST(BITF(ShadeFlagBack), BITF(WinShadingFlag::SwitchableGlazing)) && Surface(BackSurfNum).ExtBoundCond == 0) { + if (ShadeFlagBack == WinShadingFlag::SwitchableGlazing && Surface(BackSurfNum).ExtBoundCond == 0) { Real64 SwitchFac = SurfWinSwitchingFactor(SurfNum); // Switching factor for a window Real64 AbsBeamWinSh; // Glass layer beam solar absorptance of a shaded window for (int Lay = 1; Lay <= NBackGlass; ++Lay) { @@ -8691,7 +8691,7 @@ namespace SolarShading { SurfWinShadingFlag(ISurf) = WinShadingFlag::IntShadeOn; } } - if (BITF_TEST(BITF(SurfWinShadingFlag(ISurf)), BITF(WinShadingFlag::IntShadeOn))) { + if (SurfWinShadingFlag(ISurf) == WinShadingFlag::IntShadeOn) { auto &construction(state.dataConstruction->Construct(Surface(ISurf).Construction)); const int TotLay = construction.TotLayers; int ShadingLayerPtr = construction.LayerPoint(TotLay); @@ -8992,7 +8992,7 @@ namespace SolarShading { } // Set switching factor to fully switched if ShadingFlag = 2 - if (BITF_TEST(BITF(SurfWinShadingFlag(ISurf)), BITF(WinShadingFlag::SwitchableGlazing)) && !SurfWinGlareControlIsActive(ISurf)) { + if (SurfWinShadingFlag(ISurf) == WinShadingFlag::SwitchableGlazing && !SurfWinGlareControlIsActive(ISurf)) { SurfWinSwitchingFactor(ISurf) = 1.0; // Added TH 1/20/2010 @@ -9138,7 +9138,7 @@ namespace SolarShading { } // End of check if interior or exterior blind in place // CALL CalcScreenTransmittance to intialized all screens prior to HB calc's - if ((BITF_TEST(BITF(SurfWinShadingFlag(ISurf)), BITF(WinShadingFlag::ExtScreenOn)) && state.dataEnvrn->SunIsUp)) { + if (SurfWinShadingFlag(ISurf) == WinShadingFlag::ExtScreenOn && state.dataEnvrn->SunIsUp) { CalcScreenTransmittance(state, ISurf); } @@ -9921,7 +9921,7 @@ namespace SolarShading { if (SurfWinInsideSillDepth(SurfNum) < SurfWinInsideReveal(SurfNum)) continue; ShadeFlag = SurfWinShadingFlag(SurfNum); - if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::ExtShadeOn) | BITF(WinShadingFlag::ExtBlindOn))) continue; + if (BITF_TEST_ANY(BITF(ShadeFlag), BITF(WinShadingFlag::ExtShadeOn) | BITF(WinShadingFlag::ExtBlindOn))) continue; if (CosIncAng(state.dataGlobal->TimeStep, state.dataGlobal->HourOfDay, SurfNum) <= 0.0) continue; @@ -10176,12 +10176,12 @@ namespace SolarShading { // Quantities related to inside reveal; inside reveal reflection/absorption is assumed // to occur only if an interior shade or blind is not in place. - if (!IS_SHADED(ShadeFlag) || BITF_TEST_ANY(BITF(ShadeFlag), BITF(WinShadingFlag::SwitchableGlazing))) { + if (!IS_SHADED(ShadeFlag) || ShadeFlag == WinShadingFlag::SwitchableGlazing) { if (A2ill > 1.0e-6) { DiffReflGlass = state.dataConstruction->Construct(ConstrNum).ReflectSolDiffBack; - if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::SwitchableGlazing))) { + if (ShadeFlag == WinShadingFlag::SwitchableGlazing) { SolTransGlassSh = POLYF(CosIncAng(state.dataGlobal->TimeStep, state.dataGlobal->HourOfDay, SurfNum), state.dataConstruction->Construct(ConstrNumSh).TransSolBeamCoef); SolTransGlass = InterpSw(SurfWinSwitchingFactor(SurfNum), SolTransGlass, @@ -10858,7 +10858,7 @@ namespace SolarShading { // Accumulate transmitted diffuse solar for reporting SurfWinInitialDifSolInTrans(HeatTransSurfNum) += DifSolarTransW * per_HTSurfaceArea; - } else if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::SwitchableGlazing))) { // Switchable glazing + } else if (ShadeFlag == WinShadingFlag::SwitchableGlazing) { // Switchable glazing // Init accumulator for transmittance calc below DifSolarAbsW = 0.0; @@ -11375,7 +11375,7 @@ namespace SolarShading { InitialZoneDifSolReflW(Surface(AdjSurfNum).SolarEnclIndex) += DifSolarTransW; // [W] } - } else if (BITF_TEST(BITF(ShadeFlag), BITF(WinShadingFlag::SwitchableGlazing))) { // Switchable glazing + } else if (ShadeFlag == WinShadingFlag::SwitchableGlazing) { // Switchable glazing // Init accumulator for transmittance calc below DifSolarAbsW = 0.0; From 6bcbe0934a0a1462dee135217bf8312cc2652470 Mon Sep 17 00:00:00 2001 From: xuanluo113 Date: Tue, 19 Jan 2021 16:41:19 -0800 Subject: [PATCH 19/76] window control type --- src/EnergyPlus/DataSurfaces.cc | 11 --- src/EnergyPlus/DataSurfaces.hh | 21 +--- src/EnergyPlus/DaylightingManager.cc | 59 ++++++------ src/EnergyPlus/DaylightingManager.hh | 4 +- src/EnergyPlus/EMSManager.cc | 7 +- src/EnergyPlus/HeatBalanceSurfaceManager.cc | 18 ++-- src/EnergyPlus/SolarShading.cc | 47 ++++----- src/EnergyPlus/SurfaceGeometry.cc | 100 ++++++++++---------- src/EnergyPlus/WindowManager.cc | 12 +-- tst/EnergyPlus/unit/EMSManager.unit.cc | 4 +- tst/EnergyPlus/unit/SurfaceGeometry.unit.cc | 6 +- 11 files changed, 125 insertions(+), 164 deletions(-) diff --git a/src/EnergyPlus/DataSurfaces.cc b/src/EnergyPlus/DataSurfaces.cc index 9cd54050211..49b2f6712b9 100644 --- a/src/EnergyPlus/DataSurfaces.cc +++ b/src/EnergyPlus/DataSurfaces.cc @@ -237,17 +237,6 @@ namespace DataSurfaces { int const InConvWinLoc_WindowBelowThis(4); // this is a wall with window below it int const InConvWinLoc_LargePartOfExteriorWall(5); // this is a big window taking up most of wall - // WindowShadingControl Shading Types - int const WSC_ST_NoShade(0); - int const WSC_ST_InteriorShade(1); - int const WSC_ST_SwitchableGlazing(2); - int const WSC_ST_ExteriorShade(3); - int const WSC_ST_InteriorBlind(4); - int const WSC_ST_ExteriorBlind(5); - int const WSC_ST_BetweenGlassShade(6); - int const WSC_ST_BetweenGlassBlind(7); - int const WSC_ST_ExteriorScreen(8); - // WindowShadingControl Control Types int const WSCT_AlwaysOn(1); // AlwaysOn int const WSCT_AlwaysOff(2); // AlwaysOff diff --git a/src/EnergyPlus/DataSurfaces.hh b/src/EnergyPlus/DataSurfaces.hh index 6345166feb1..cb523e2b6c1 100644 --- a/src/EnergyPlus/DataSurfaces.hh +++ b/src/EnergyPlus/DataSurfaces.hh @@ -135,8 +135,7 @@ namespace DataSurfaces { }; enum class WinShadingFlag : int { - NoShade = 10, - ShadeOff = 0, + NoShade = 0, IntShadeOn = 1, SwitchableGlazing = 2, ExtShadeOn = 3, @@ -144,7 +143,8 @@ namespace DataSurfaces { IntBlindOn = 6, ExtBlindOn = 7, BGShadeOn = 8, - BGBlindOn = 9 + BGBlindOn = 9, + ShadeOff = 10 }; // Parameters to indicate exterior boundary conditions for use with @@ -266,17 +266,6 @@ namespace DataSurfaces { extern int const InConvWinLoc_WindowBelowThis; // this is a wall with window below it extern int const InConvWinLoc_LargePartOfExteriorWall; // this is a big window taking up most of wall - // WindowShadingControl Shading Types - extern int const WSC_ST_NoShade; - extern int const WSC_ST_InteriorShade; - extern int const WSC_ST_SwitchableGlazing; - extern int const WSC_ST_ExteriorShade; - extern int const WSC_ST_InteriorBlind; - extern int const WSC_ST_ExteriorBlind; - extern int const WSC_ST_BetweenGlassShade; - extern int const WSC_ST_BetweenGlassBlind; - extern int const WSC_ST_ExteriorScreen; - // WindowShadingControl Control Types extern int const WSCT_AlwaysOn; // AlwaysOn extern int const WSCT_AlwaysOff; // AlwaysOff @@ -1113,7 +1102,7 @@ namespace DataSurfaces { std::string Name; // User supplied name of this set of shading control data int ZoneIndex; // number of the zone referenced int SequenceNumber; // Shading control sequence number - int ShadingType; // Shading type (InteriorShade, SwitchableGlazing, + WinShadingFlag ShadingType; // Shading type (InteriorShade, SwitchableGlazing, // CHARACTER(len=32) :: ShadingType = ' ' ! Shading type (InteriorShade, SwitchableGlazing, // ExteriorShade,InteriorBlind,ExteriorBlind,BetweenGlassShade, // BetweenGlassBlind, or ExteriorScreen) @@ -1199,7 +1188,7 @@ namespace DataSurfaces { // Default Constructor WindowShadingControlData() - : ZoneIndex(0), SequenceNumber(0), ShadingType(WSC_ST_NoShade), getInputShadedConstruction(0), ShadingDevice(0), ShadingControlType(0), + : ZoneIndex(0), SequenceNumber(0), ShadingType(WinShadingFlag::NoShade), getInputShadedConstruction(0), ShadingDevice(0), ShadingControlType(0), Schedule(0), SetPoint(0.0), SetPoint2(0.0), ShadingControlIsScheduled(false), GlareControlIsActive(false), SlatAngleSchedule(0), SlatAngleControlForBlinds(0), DaylightControlIndex(0), MultiSurfaceCtrlIsGroup(false), FenestrationCount(0) { diff --git a/src/EnergyPlus/DaylightingManager.cc b/src/EnergyPlus/DaylightingManager.cc index 7aa4dfcdef6..02d64fb3d44 100644 --- a/src/EnergyPlus/DaylightingManager.cc +++ b/src/EnergyPlus/DaylightingManager.cc @@ -863,7 +863,7 @@ namespace EnergyPlus::DaylightingManager { int IWin; // Window counter int IWin2; // Secondary window counter (for TDD:DOME object, if exists) int InShelfSurf; // Inside daylighting shelf surface number - int ShType; // Window shading type + WinShadingFlag ShType; // Window shading type int BlNum; // Window Blind Number int LSHCAL; // Interior shade calculation flag: 0=not yet // calculated, 1=already calculated @@ -1262,7 +1262,7 @@ namespace EnergyPlus::DaylightingManager { int IWin; // Window counter int IWin2; // Secondary window counter (for TDD:DOME object, if exists) int InShelfSurf; // Inside daylighting shelf surface number - int ShType; // Window shading type + WinShadingFlag ShType; // Window shading type int BlNum; // Window Blind Number int LSHCAL; // Interior shade calculation flag: 0=not yet // calculated, 1=already calculated @@ -1612,7 +1612,7 @@ namespace EnergyPlus::DaylightingManager { int &LSHCAL, // Interior shade calculation flag: 0=not yet calculated, 1=already calculated int &InShelfSurf, // Inside daylighting shelf surface number int &ICtrl, // Window control counter - int &ShType, // Window shading type + WinShadingFlag &ShType, // Window shading type int &BlNum, // Window blind number Vector3 &WNORM2, // Unit vector normal to window DataDaylighting::iExtWinType &ExtWinType, // Exterior window type (InZoneExtWin, AdjZoneExtWin, NotInOrAdjZoneExtWin) @@ -1740,7 +1740,7 @@ namespace EnergyPlus::DaylightingManager { } ICtrl = Surface(IWin).activeWindowShadingControl; - ShType = WSC_ST_NoShade; // 'NOSHADE' + ShType = WinShadingFlag::NoShade; // 'NOSHADE' BlNum = 0; // ScNum = 0; //Unused Set but never used if (Surface(IWin).HasShadeControl) ShType = WindowShadingControl(ICtrl).ShadingType; @@ -1781,7 +1781,7 @@ namespace EnergyPlus::DaylightingManager { // incidence for fully switched (dark) state to that of unswitched state SurfWinVisTransRatio(IWin) = 1.0; if (ICtrl > 0) { - if (ShType == WSC_ST_SwitchableGlazing) { + if (ShType == WinShadingFlag::SwitchableGlazing) { IConstShaded = Surface(IWin).activeShadedConstruction; SurfWinVisTransRatio(IWin) = SafeDivide(POLYF(1.0, state.dataConstruction->Construct(IConstShaded).TransVisBeamCoef), POLYF(1.0, state.dataConstruction->Construct(IConst).TransVisBeamCoef)); @@ -3246,7 +3246,7 @@ namespace EnergyPlus::DaylightingManager { Real64 const TVISB, // Visible transmittance of window for COSB angle of incidence (times light well efficiency, if appropriate) Real64 const DOMEGA, // Solid angle subtended by window element wrt reference point (steradians) int const ICtrl, // Window control counter - int const ShType, // Window shading type + WinShadingFlag const ShType, // Window shading type int const BlNum, // Window blind number Real64 const THRAY, // Azimuth of ray from reference point to window element (radians) Vector3 const &WNORM2, // Unit vector normal to window @@ -3675,7 +3675,7 @@ namespace EnergyPlus::DaylightingManager { state.dataDaylightingManager->EDIRSUdisk(iHour, 1) = RAYCOS(3) * TVISS * ObTransDisk; // Bare window TransBmBmMult = 0.0; - if (ShType == WSC_ST_ExteriorBlind || ShType == WSC_ST_InteriorBlind || ShType == WSC_ST_BetweenGlassBlind) { + if (ShType == WinShadingFlag::ExtBlindOn || ShType == WinShadingFlag::IntBlindOn || ShType == WinShadingFlag::BGBlindOn) { ProfileAngle(IWin, RAYCOS, Blind(BlNum).SlatOrientation, ProfAng); // Contribution of beam passing through slats and reaching reference point for (JB = 1; JB <= MaxSlatAngs; ++JB) { @@ -3692,7 +3692,7 @@ namespace EnergyPlus::DaylightingManager { // do this only once for fixed slat blinds if (!SurfWinMovableSlats(IWin)) break; } - } else if (ShType == WSC_ST_ExteriorScreen) { + } else if (ShType == WinShadingFlag::ExtScreenOn) { // pass angle from sun to window normal here using PHSUN and THSUN from above and surface angles // SunAltitudeToWindowNormalAngle = PHSUN - SurfaceWindow(IWin)%Phi // SunAzimuthToWindowNormalAngle = THSUN - SurfaceWindow(IWin)%Theta @@ -3729,13 +3729,13 @@ namespace EnergyPlus::DaylightingManager { XAVWL = 14700.0 * std::sqrt(0.000068 * POSFAC) * double(NWX * NWY) / std::pow(WindowSolidAngleDaylightPoint, 0.8); state.dataDaylightingManager->AVWLSUdisk(iHour, 1) = XAVWL * TVISS * ObTransDisk; // Bare window - if (ShType == WSC_ST_ExteriorBlind || ShType == WSC_ST_InteriorBlind || ShType == WSC_ST_BetweenGlassBlind) { + if (ShType == WinShadingFlag::ExtBlindOn || ShType == WinShadingFlag::IntBlindOn || ShType == WinShadingFlag::BGBlindOn) { for (JB = 1; JB <= MaxSlatAngs; ++JB) { // IF (.NOT. SurfaceWindow(IWin)%MovableSlats .AND. JB > 1) EXIT state.dataDaylightingManager->AVWLSUdisk(iHour, JB + 1) = XAVWL * TVISS * TransBmBmMult(JB) * ObTransDisk; if (!SurfWinMovableSlats(IWin)) break; } - } else if (ShType == WSC_ST_ExteriorScreen) { + } else if (ShType == WinShadingFlag::ExtScreenOn) { state.dataDaylightingManager->AVWLSUdisk(iHour, 2) = XAVWL * TVISS * TransBmBmMult(1) * ObTransDisk; } } // Position Factor @@ -3842,7 +3842,7 @@ namespace EnergyPlus::DaylightingManager { state.dataDaylightingManager->EDIRSUdisk(iHour, 1) += SunVecMir(3) * SpecReflectance * TVisRefl; // Bare window TransBmBmMultRefl = 0.0; - if (ShType == WSC_ST_ExteriorBlind || ShType == WSC_ST_InteriorBlind || ShType == WSC_ST_BetweenGlassBlind) { + if (ShType == WinShadingFlag::ExtBlindOn || ShType == WinShadingFlag::IntBlindOn || ShType == WinShadingFlag::BGBlindOn) { ProfileAngle(IWin, SunVecMir, Blind(BlNum).SlatOrientation, ProfAng); // Contribution of reflected beam passing through slats and reaching reference point Real64 const Pi_SlatAng_fac(DataGlobalConstants::Pi / (MaxSlatAngs - 1)); @@ -3859,7 +3859,7 @@ namespace EnergyPlus::DaylightingManager { if (!SurfWinMovableSlats(IWin)) break; } - } else if (ShType == WSC_ST_ExteriorScreen) { + } else if (ShType == WinShadingFlag::ExtScreenOn) { // pass angle from sun to window normal here using PHSUN and THSUN from above and // surface angles SunAltitudeToWindowNormalAngle = PHSUN - SurfaceWindow(IWin)%Phi // SunAzimuthToWindowNormalAngle = THSUN - SurfaceWindow(IWin)%Theta @@ -3879,13 +3879,13 @@ namespace EnergyPlus::DaylightingManager { XAVWL = 14700.0 * std::sqrt(0.000068 * POSFAC) * double(NWX * NWY) / std::pow(SurfaceWindow(IWin).SolidAngAtRefPtWtd(iRefPoint), 0.8); state.dataDaylightingManager->AVWLSUdisk(iHour, 1) += XAVWL * TVisRefl * SpecReflectance; // Bare window - if (ShType == WSC_ST_ExteriorBlind || ShType == WSC_ST_InteriorBlind || ShType == WSC_ST_BetweenGlassBlind) { + if (ShType == WinShadingFlag::ExtBlindOn || ShType == WinShadingFlag::IntBlindOn || ShType == WinShadingFlag::BGBlindOn) { for (JB = 1; JB <= MaxSlatAngs; ++JB) { // IF(.NOT. SurfaceWindow(IWin)%MovableSlats .AND. JB > 1) EXIT state.dataDaylightingManager->AVWLSUdisk(iHour, JB + 1) += XAVWL * TVisRefl * SpecReflectance * TransBmBmMultRefl(JB); if (!SurfWinMovableSlats(IWin)) break; } - } else if (ShType == WSC_ST_ExteriorScreen) { + } else if (ShType == WinShadingFlag::ExtScreenOn) { state.dataDaylightingManager->AVWLSUdisk(iHour, 2) += XAVWL * TVisRefl * SpecReflectance * TransBmBmMultRefl(1); } } @@ -3898,9 +3898,9 @@ namespace EnergyPlus::DaylightingManager { } // Last pass - if ((ICtrl > 0 && (ShType == WSC_ST_InteriorShade || ShType == WSC_ST_ExteriorShade || ShType == WSC_ST_BetweenGlassShade || - ShType == WSC_ST_InteriorBlind || ShType == WSC_ST_ExteriorBlind || ShType == WSC_ST_BetweenGlassBlind || - ShType == WSC_ST_ExteriorScreen)) || + if ((ICtrl > 0 && (ShType == WinShadingFlag::IntShadeOn || ShType == WinShadingFlag::ExtShadeOn || ShType == WinShadingFlag::BGShadeOn || + ShType == WinShadingFlag::IntBlindOn || ShType == WinShadingFlag::ExtBlindOn || ShType == WinShadingFlag::BGBlindOn || + ShType == WinShadingFlag::ExtScreenOn)) || SurfWinSolarDiffusing(IWin)) { // ----- CASE II -- WINDOW WITH SCREEN, SHADE, BLIND, OR DIFFUSING WINDOW @@ -4051,7 +4051,7 @@ namespace EnergyPlus::DaylightingManager { // For switchable glazing put daylighting factors for switched (dark) state in IS=2 location if (ICtrl > 0) { - if (WindowShadingControl(ICtrl).ShadingType == WSC_ST_SwitchableGlazing) { + if (WindowShadingControl(ICtrl).ShadingType == WinShadingFlag::SwitchableGlazing) { VTR = SurfWinVisTransRatio(IWin); state.dataDaylightingData->ZoneDaylight(ZoneNum).DaylIllFacSky(iHour, 2, ISky, iRefPoint, loopwin) = state.dataDaylightingData->ZoneDaylight(ZoneNum).DaylIllFacSky(iHour, 1, ISky, iRefPoint, loopwin) * VTR; @@ -4197,7 +4197,7 @@ namespace EnergyPlus::DaylightingManager { // For switchable glazing put daylighting factors for switched (dark) state in IS=2 location if (ICtrl > 0) { - if (WindowShadingControl(ICtrl).ShadingType == WSC_ST_SwitchableGlazing) { + if (WindowShadingControl(ICtrl).ShadingType == WinShadingFlag::SwitchableGlazing) { VTR = SurfWinVisTransRatio(IWin); state.dataDaylightingData->IllumMapCalc(MapNum).DaylIllFacSky(iHour, 2, ISky, iMapPoint, loopwin) = state.dataDaylightingData->IllumMapCalc(MapNum).DaylIllFacSky(iHour, 1, ISky, iMapPoint, loopwin) * VTR; @@ -7544,7 +7544,6 @@ namespace EnergyPlus::DaylightingManager { // (times light well efficiency, if appropriate) Real64 ZSU1; // Transmitted direct normal illuminance (lux) // CHARACTER(len=32) :: ShType ! Window shading device type - int ShType; // Window shading device type bool ShadeOn; // True if exterior or interior window shade present bool BlindOn; // True if exterior or interior window blind present bool ScreenOn; // True if exterior window screen present @@ -7618,6 +7617,8 @@ namespace EnergyPlus::DaylightingManager { int IntWinNum; // window index for interior windows associated with exterior windows Real64 COSBintWin; + WinShadingFlag ShType; + ZoneNumThisWin = Surface(Surface(IWin).BaseSurf).Zone; // The inside surface area, ZoneDaylight(ZoneNum)%TotInsSurfArea was calculated in subr DayltgAveInteriorReflectance @@ -7939,9 +7940,9 @@ namespace EnergyPlus::DaylightingManager { BlNum = SurfWinBlindNumber(IWin); // ScNum = SurfaceWindow( IWin ).ScreenNumber; //Unused Set but never used - ShadeOn = (ShType == WSC_ST_InteriorShade || ShType == WSC_ST_ExteriorShade || ShType == WSC_ST_BetweenGlassShade); - BlindOn = (ShType == WSC_ST_InteriorBlind || ShType == WSC_ST_ExteriorBlind || ShType == WSC_ST_BetweenGlassBlind); - ScreenOn = (ShType == WSC_ST_ExteriorScreen); + ShadeOn = (ShType == WinShadingFlag::IntShadeOn || ShType == WinShadingFlag::ExtShadeOn || ShType == WinShadingFlag::BGShadeOn); + BlindOn = (ShType == WinShadingFlag::IntBlindOn || ShType == WinShadingFlag::ExtBlindOn || ShType == WinShadingFlag::BGBlindOn); + ScreenOn = (ShType == WinShadingFlag::ExtScreenOn); } if (ShadeOn || BlindOn || ScreenOn || SurfWinSolarDiffusing(IWin)) { @@ -8003,7 +8004,7 @@ namespace EnergyPlus::DaylightingManager { TransBlBmDiffFront = InterpProfAng(ProfAng, Blind(BlNum).VisFrontBeamDiffTrans(JB, {1, 37})); - if (ShType == WSC_ST_InteriorBlind) { // Interior blind + if (ShType == WinShadingFlag::IntBlindOn) { // Interior blind ReflGlDiffDiffBack = state.dataConstruction->Construct(IConst).ReflectVisDiffBack; ReflBlBmDiffFront = InterpProfAng(ProfAng, Blind(BlNum).VisFrontBeamDiffRefl(JB, {1, 37})); ReflBlDiffDiffFront = Blind(BlNum).VisFrontDiffDiffRefl(JB); @@ -8011,7 +8012,7 @@ namespace EnergyPlus::DaylightingManager { TransMult(JB) = TVISBR * (TransBlBmDiffFront + ReflBlBmDiffFront * ReflGlDiffDiffBack * TransBlDiffDiffFront / (1.0 - ReflBlDiffDiffFront * ReflGlDiffDiffBack)); - } else if (ShType == WSC_ST_ExteriorBlind) { // Exterior blind + } else if (ShType == WinShadingFlag::ExtBlindOn) { // Exterior blind ReflGlDiffDiffFront = state.dataConstruction->Construct(IConst).ReflectVisDiffFront; ReflBlDiffDiffBack = Blind(BlNum).VisBackDiffDiffRefl(JB); TransMult(JB) = TransBlBmDiffFront * SurfWinGlazedFrac(IWin) * state.dataConstruction->Construct(IConst).TransDiffVis / @@ -8210,7 +8211,7 @@ namespace EnergyPlus::DaylightingManager { TransBlBmDiffFront = InterpProfAng(ProfAng, Blind(BlNum).VisFrontBeamDiffTrans(JB, {1, 37})); - if (ShType == WSC_ST_InteriorBlind) { // Interior blind + if (ShType == WinShadingFlag::IntBlindOn) { // Interior blind // TH CR 8121, 7/7/2010 // ReflBlBmDiffFront = InterpProfAng(ProfAng,Blind(BlNum)%VisFrontBeamDiffRefl) ReflBlBmDiffFront = InterpProfAng(ProfAng, Blind(BlNum).VisFrontBeamDiffRefl(JB, {1, 37})); @@ -8222,7 +8223,7 @@ namespace EnergyPlus::DaylightingManager { TransMult(JB) = TVISBSun * (TransBlBmDiffFront + ReflBlBmDiffFront * ReflGlDiffDiffBack * TransBlDiffDiffFront / (1.0 - ReflBlDiffDiffFront * ReflGlDiffDiffBack)); - } else if (ShType == WSC_ST_ExteriorBlind) { // Exterior blind + } else if (ShType == WinShadingFlag::ExtBlindOn) { // Exterior blind TransMult(JB) = TransBlBmDiffFront * (state.dataConstruction->Construct(IConst).TransDiffVis / (1.0 - ReflGlDiffDiffFront * Blind(BlNum).VisBackDiffDiffRefl(JB))) * @@ -8312,13 +8313,13 @@ namespace EnergyPlus::DaylightingManager { } else { // Blind on TransBlDiffDiffFront = Blind(BlNum).VisFrontDiffDiffTrans(JB); - if (ShType == WSC_ST_InteriorBlind) { // Interior blind + if (ShType == WinShadingFlag::IntBlindOn) { // Interior blind ReflBlDiffDiffFront = Blind(BlNum).VisFrontDiffDiffRefl(JB); TransMult(JB) = TVisSunRefl * (TransBlDiffDiffFront + ReflBlDiffDiffFront * ReflGlDiffDiffBack * TransBlDiffDiffFront / (1.0 - ReflBlDiffDiffFront * ReflGlDiffDiffBack)); - } else if (ShType == WSC_ST_ExteriorBlind) { // Exterior blind + } else if (ShType == WinShadingFlag::ExtBlindOn) { // Exterior blind TransMult(JB) = TransBlDiffDiffFront * (state.dataConstruction->Construct(IConst).TransDiffVis / (1.0 - ReflGlDiffDiffFront * Blind(BlNum).VisBackDiffDiffRefl(JB))) * diff --git a/src/EnergyPlus/DaylightingManager.hh b/src/EnergyPlus/DaylightingManager.hh index a92efb46ab3..b4955b77a22 100644 --- a/src/EnergyPlus/DaylightingManager.hh +++ b/src/EnergyPlus/DaylightingManager.hh @@ -110,7 +110,7 @@ namespace DaylightingManager { int &LSHCAL, // Interior shade calculation flag: 0=not yet calculated, 1=already calculated int &InShelfSurf, // Inside daylighting shelf surface number int &ICtrl, // Window control counter - int &ShType, // Window shading type + DataSurfaces::WinShadingFlag &ShType, // Window shading type int &BlNum, // Window blind number Vector3 &WNORM2, // Unit vector normal to window DataDaylighting::iExtWinType &ExtWinType, // Exterior window type (InZoneExtWin, AdjZoneExtWin, NotInOrAdjZoneExtWin) @@ -257,7 +257,7 @@ namespace DaylightingManager { Real64 const TVISB, // Visible transmittance of window for COSB angle of incidence (times light well efficiency, if appropriate) Real64 const DOMEGA, // Solid angle subtended by window element wrt reference point (steradians) int const ICtrl, // Window control counter - int const ShType, // Window shading type + DataSurfaces::WinShadingFlag const ShType, // Window shading type int const BlNum, // Window blind number Real64 const THRAY, // Azimuth of ray from reference point to window element (radians) Vector3 const &WNORM2, // Unit vector normal to window diff --git a/src/EnergyPlus/EMSManager.cc b/src/EnergyPlus/EMSManager.cc index 1c6bbf28933..72f72fd3ece 100644 --- a/src/EnergyPlus/EMSManager.cc +++ b/src/EnergyPlus/EMSManager.cc @@ -1862,8 +1862,7 @@ namespace EMSManager { using DataSurfaces::Surface; using DataSurfaces::TotSurfaces; using DataSurfaces::WindowShadingControl; - using DataSurfaces::WSC_ST_SwitchableGlazing; - using DataSurfaces::WSC_ST_ExteriorScreen; + using DataSurfaces::WinShadingFlag; // Locals // SUBROUTINE ARGUMENT DEFINITIONS: @@ -1902,7 +1901,7 @@ namespace EMSManager { DataSurfaces::SurfWinSlatAngThisTSDegEMSon(loopSurfNum), DataSurfaces::SurfWinSlatAngThisTSDegEMSValue(loopSurfNum)); } - } else if (WindowShadingControl(Surface(loopSurfNum).activeWindowShadingControl).ShadingType == WSC_ST_ExteriorScreen) { + } else if (WindowShadingControl(Surface(loopSurfNum).activeWindowShadingControl).ShadingType == WinShadingFlag::ExtScreenOn) { SetupEMSActuator(state, "Window Shading Control", Surface(loopSurfNum).Name, "Control Status", @@ -1910,7 +1909,7 @@ namespace EMSManager { DataSurfaces::SurfWinShadingFlagEMSOn(loopSurfNum), (int &)DataSurfaces::SurfWinShadingFlagEMSValue(loopSurfNum)); } else { - if (WindowShadingControl(Surface(loopSurfNum).activeWindowShadingControl).ShadingType != WSC_ST_SwitchableGlazing) { + if (WindowShadingControl(Surface(loopSurfNum).activeWindowShadingControl).ShadingType != WinShadingFlag::SwitchableGlazing) { ShowSevereError(state, "Missing shade or blind layer in window construction name = '" + state.dataConstruction->Construct(Surface(loopSurfNum).activeShadedConstruction).Name + "', surface name = '" + Surface(loopSurfNum).Name + "'."); diff --git a/src/EnergyPlus/HeatBalanceSurfaceManager.cc b/src/EnergyPlus/HeatBalanceSurfaceManager.cc index c20033ad00e..be47cd035df 100644 --- a/src/EnergyPlus/HeatBalanceSurfaceManager.cc +++ b/src/EnergyPlus/HeatBalanceSurfaceManager.cc @@ -1052,23 +1052,23 @@ namespace HeatBalanceSurfaceManager { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscName, surfName, WindowShadingControl(curWSC).Name); { auto const SELECT_CASE_var1(WindowShadingControl(curWSC).ShadingType); - if (SELECT_CASE_var1 == WSC_ST_NoShade) { + if (SELECT_CASE_var1 == WinShadingFlag::NoShade) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscShading, surfName, "No Shade"); - } else if (SELECT_CASE_var1 == WSC_ST_InteriorShade) { + } else if (SELECT_CASE_var1 == WinShadingFlag::IntShadeOn) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscShading, surfName, "Interior Shade"); - } else if (SELECT_CASE_var1 == WSC_ST_SwitchableGlazing) { + } else if (SELECT_CASE_var1 == WinShadingFlag::SwitchableGlazing) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscShading, surfName, "Switchable Glazing"); - } else if (SELECT_CASE_var1 == WSC_ST_ExteriorShade) { + } else if (SELECT_CASE_var1 == WinShadingFlag::ExtShadeOn) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscShading, surfName, "Exterior Shade"); - } else if (SELECT_CASE_var1 == WSC_ST_InteriorBlind) { + } else if (SELECT_CASE_var1 == WinShadingFlag::IntBlindOn) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscShading, surfName, "Interior Blind"); - } else if (SELECT_CASE_var1 == WSC_ST_ExteriorBlind) { + } else if (SELECT_CASE_var1 == WinShadingFlag::ExtBlindOn) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscShading, surfName, "Exterior Blind"); - } else if (SELECT_CASE_var1 == WSC_ST_BetweenGlassShade) { + } else if (SELECT_CASE_var1 == WinShadingFlag::BGShadeOn) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscShading, surfName, "Between Glass Shade"); - } else if (SELECT_CASE_var1 == WSC_ST_BetweenGlassBlind) { + } else if (SELECT_CASE_var1 == WinShadingFlag::BGBlindOn) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscShading, surfName, "Between Glass Blind"); - } else if (SELECT_CASE_var1 == WSC_ST_ExteriorScreen) { + } else if (SELECT_CASE_var1 == WinShadingFlag::ExtScreenOn) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscShading, surfName, "Exterior Screen"); } } diff --git a/src/EnergyPlus/SolarShading.cc b/src/EnergyPlus/SolarShading.cc index ceac5037235..8cdbd4f4c50 100644 --- a/src/EnergyPlus/SolarShading.cc +++ b/src/EnergyPlus/SolarShading.cc @@ -1347,7 +1347,7 @@ namespace SolarShading { // Added TH 5/26/2009 for switchable windows to report switching factor (tinted level) // CurrentModuleObject='Switchable Windows' if (Surface(SurfLoop).HasShadeControl) { - if (WindowShadingControl(Surface(SurfLoop).activeWindowShadingControl).ShadingType == WSC_ST_SwitchableGlazing) { + if (WindowShadingControl(Surface(SurfLoop).activeWindowShadingControl).ShadingType == WinShadingFlag::SwitchableGlazing) { // IF (SurfaceWindow(SurfLoop)%ShadingFlag == WinShadingFlag::SwitchableGlazing) THEN !ShadingFlag is not set to WinShadingFlag::SwitchableGlazing yet! SetupOutputVariable(state, "Surface Window Switchable Glazing Switching Factor", OutputProcessor::Unit::None, @@ -8740,35 +8740,19 @@ namespace SolarShading { } int IShadingCtrl = Surface(ISurf).activeWindowShadingControl; - int ShadingType = WindowShadingControl(IShadingCtrl).ShadingType; // Type of shading (interior shade, interior blind, etc.) - SurfWinShadingFlag(ISurf) = WinShadingFlag::ShadeOff; // Initialize shading flag to off +// int ShadingType = WindowShadingControl(IShadingCtrl).ShadingType; // Type of shading (interior shade, interior blind, etc.) + int IZone = Surface(ISurf).Zone; // Setpoint for shading Real64 SetPoint = WindowShadingControl(IShadingCtrl).SetPoint; // Control setpoint Real64 SetPoint2 = WindowShadingControl(IShadingCtrl).SetPoint2; // Second control setpoint + WinShadingFlag ShType; // Type of shading (interior shade, interior blind, etc.) - // ShType = NoShade ! =-1 (see DataHeatBalance) - // ShType = ShadeOff ! =0 - WinShadingFlag ShType; - // 1 = interior shade is on, - // 2 = glass is switched to dark state, - // 3 = exterior shade is on, - // 4 = exterior screen is on, - // 6 = interior blind is on, - // 7 = exterior blind is on, - // 8 = between-glass shade is on, - // 9 = between-glass blind is on. - // CHARACTER(len=32) :: ShadingType ! Type of shading (interior shade, interior blind, etc.) - if (ShadingType == WSC_ST_InteriorShade) ShType = WinShadingFlag::IntShadeOn; // =1 - if (ShadingType == WSC_ST_SwitchableGlazing) ShType = WinShadingFlag::SwitchableGlazing; // =2 - if (ShadingType == WSC_ST_ExteriorShade) ShType = WinShadingFlag::ExtShadeOn; // =3 - if (ShadingType == WSC_ST_ExteriorScreen) ShType = WinShadingFlag::ExtScreenOn; // =4 - if (ShadingType == WSC_ST_InteriorBlind) ShType = WinShadingFlag::IntBlindOn; // =6 - if (ShadingType == WSC_ST_ExteriorBlind) ShType = WinShadingFlag::ExtBlindOn; // =7 - if (ShadingType == WSC_ST_BetweenGlassShade) ShType = WinShadingFlag::BGShadeOn; // =8 - if (ShadingType == WSC_ST_BetweenGlassBlind) ShType = WinShadingFlag::BGBlindOn; // =9 + if (IS_SHADED(WindowShadingControl(IShadingCtrl).ShadingType)) { + ShType = WindowShadingControl(IShadingCtrl).ShadingType; + } bool SchedAllowsControl = true; // True if control schedule is not specified or is specified and schedule value = 1 int SchedulePtr = WindowShadingControl(IShadingCtrl).Schedule; @@ -8796,6 +8780,7 @@ namespace SolarShading { // Determine whether to deploy shading depending on type of control SurfWinGlareControlIsActive(ISurf) = false; + SurfWinShadingFlag(ISurf) = WinShadingFlag::ShadeOff; // Initialize shading flag to off auto const SELECT_CASE_var(WindowShadingControl(IShadingCtrl).ShadingControlType); @@ -8806,7 +8791,9 @@ namespace SolarShading { SurfWinShadingFlag(ISurf) = WinShadingFlag::ShadeOff; } else if (SELECT_CASE_var == WSCT_OnIfScheduled) { // 'ONIFSCHEDULEALLOWS' - if (SchedAllowsControl) SurfWinShadingFlag(ISurf) = ShType; + if (SchedAllowsControl) { + SurfWinShadingFlag(ISurf) = ShType; + } } else if (SELECT_CASE_var == WSCT_HiSolar) { // 'ONIFHIGHSOLARONWINDOW' ! Direct plus diffuse solar intensity on window @@ -10516,18 +10503,18 @@ namespace SolarShading { Real64 AbsorpEff = 0.0; // Effective absorptance of isolated shade layer (fraction of // of incident radiation remaining after reflected portion is // removed that is absorbed - if (WindowShadingControl(WinShadeCtrlNum).ShadingType == WSC_ST_InteriorShade || - WindowShadingControl(WinShadeCtrlNum).ShadingType == WSC_ST_ExteriorShade || - WindowShadingControl(WinShadeCtrlNum).ShadingType == WSC_ST_BetweenGlassShade) { + if (WindowShadingControl(WinShadeCtrlNum).ShadingType == WinShadingFlag::IntShadeOn || + WindowShadingControl(WinShadeCtrlNum).ShadingType == WinShadingFlag::ExtShadeOn || + WindowShadingControl(WinShadeCtrlNum).ShadingType == WinShadingFlag::BGShadeOn) { int ConstrNumSh = Surface(SurfNum).activeShadedConstruction; // Window construction number with shade int TotLay = state.dataConstruction->Construct(ConstrNumSh).TotLayers; // Total layers in a construction - if (WindowShadingControl(WinShadeCtrlNum).ShadingType == WSC_ST_InteriorShade) { + if (WindowShadingControl(WinShadeCtrlNum).ShadingType == WinShadingFlag::IntShadeOn) { MatNumSh = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(TotLay); // Interior shade - } else if (WindowShadingControl(WinShadeCtrlNum).ShadingType == WSC_ST_ExteriorShade) { + } else if (WindowShadingControl(WinShadeCtrlNum).ShadingType == WinShadingFlag::ExtShadeOn) { MatNumSh = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(1); // Exterior shade - } else if (WindowShadingControl(WinShadeCtrlNum).ShadingType == WSC_ST_BetweenGlassShade) { + } else if (WindowShadingControl(WinShadeCtrlNum).ShadingType == WinShadingFlag::BGShadeOn) { if (state.dataConstruction->Construct(ConstrNumSh).TotGlassLayers == 2) { // Double pane with between-glass shade MatNumSh = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(3); diff --git a/src/EnergyPlus/SurfaceGeometry.cc b/src/EnergyPlus/SurfaceGeometry.cc index 41a082ff83a..4429b4ee753 100644 --- a/src/EnergyPlus/SurfaceGeometry.cc +++ b/src/EnergyPlus/SurfaceGeometry.cc @@ -1005,7 +1005,6 @@ namespace SurfaceGeometry { // unused INTEGER :: SchID int BlNumNew; int WinShadingControlPtr(0); - int ShadingType; int ErrCount; Real64 diffp; bool izConstDiff; // differences in construction for IZ surfaces @@ -2036,10 +2035,10 @@ namespace SurfaceGeometry { ConstrNumSh = Surface(SurfNum).activeShadedConstruction; if (ConstrNumSh <= 0) continue; - ShadingType = WindowShadingControl(WinShadingControlPtr).ShadingType; + WinShadingFlag ShadingType = WindowShadingControl(WinShadingControlPtr).ShadingType; // only for blinds - if (ShadingType == WSC_ST_ExteriorBlind || ShadingType == WSC_ST_InteriorBlind || ShadingType == WSC_ST_BetweenGlassBlind) { + if (ShadingType == WinShadingFlag::ExtBlindOn || ShadingType == WinShadingFlag::IntBlindOn || ShadingType == WinShadingFlag::BGBlindOn) { // TH 1/7/2010. CR 7930 // The old code did not consider between-glass blind. Also there should not be two blinds - both interior and exterior @@ -4771,11 +4770,11 @@ namespace SurfaceGeometry { if (ConstrNumSh > 0) { state.dataSurfaceGeometry->SurfaceTmp(SurfNum).activeShadedConstruction = ConstrNumSh; } else { - if (WindowShadingControl(WSCPtr).ShadingType == WSC_ST_InteriorShade || - WindowShadingControl(WSCPtr).ShadingType == WSC_ST_InteriorBlind || - WindowShadingControl(WSCPtr).ShadingType == WSC_ST_ExteriorShade || - WindowShadingControl(WSCPtr).ShadingType == WSC_ST_ExteriorScreen || - WindowShadingControl(WSCPtr).ShadingType == WSC_ST_ExteriorBlind) { + if (WindowShadingControl(WSCPtr).ShadingType == WinShadingFlag::IntShadeOn || + WindowShadingControl(WSCPtr).ShadingType == WinShadingFlag::IntBlindOn || + WindowShadingControl(WSCPtr).ShadingType == WinShadingFlag::ExtShadeOn || + WindowShadingControl(WSCPtr).ShadingType == WinShadingFlag::ExtScreenOn || + WindowShadingControl(WSCPtr).ShadingType == WinShadingFlag::ExtBlindOn) { ShDevNum = WindowShadingControl(WSCPtr).ShadingDevice; if (ShDevNum > 0) { CreateShadedWindowConstruction(state, SurfNum, WSCPtr, ShDevNum, shadeControlIndex); @@ -4790,8 +4789,8 @@ namespace SurfaceGeometry { ConstrNum = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction; if (!ErrorsFound && WSCPtr > 0 && ConstrNum > 0 && ConstrNumSh > 0) { - if (WindowShadingControl(WSCPtr).ShadingType == WSC_ST_InteriorShade || - WindowShadingControl(WSCPtr).ShadingType == WSC_ST_InteriorBlind) { + if (WindowShadingControl(WSCPtr).ShadingType == WinShadingFlag::IntShadeOn || + WindowShadingControl(WSCPtr).ShadingType == WinShadingFlag::IntBlindOn) { TotLayers = state.dataConstruction->Construct(ConstrNum).TotLayers; TotShLayers = state.dataConstruction->Construct(ConstrNumSh).TotLayers; if (TotShLayers - 1 != TotLayers) { @@ -4814,9 +4813,9 @@ namespace SurfaceGeometry { } } - if (WindowShadingControl(WSCPtr).ShadingType == WSC_ST_ExteriorShade || - WindowShadingControl(WSCPtr).ShadingType == WSC_ST_ExteriorScreen || - WindowShadingControl(WSCPtr).ShadingType == WSC_ST_ExteriorBlind) { + if (WindowShadingControl(WSCPtr).ShadingType == WinShadingFlag::ExtShadeOn || + WindowShadingControl(WSCPtr).ShadingType == WinShadingFlag::ExtScreenOn || + WindowShadingControl(WSCPtr).ShadingType == WinShadingFlag::ExtBlindOn) { TotLayers = state.dataConstruction->Construct(ConstrNum).TotLayers; TotShLayers = state.dataConstruction->Construct(ConstrNumSh).TotLayers; if (TotShLayers - 1 != TotLayers) { @@ -4839,8 +4838,8 @@ namespace SurfaceGeometry { } } - if (WindowShadingControl(WSCPtr).ShadingType == WSC_ST_BetweenGlassShade || - WindowShadingControl(WSCPtr).ShadingType == WSC_ST_BetweenGlassBlind) { + if (WindowShadingControl(WSCPtr).ShadingType == WinShadingFlag::BGShadeOn || + WindowShadingControl(WSCPtr).ShadingType == WinShadingFlag::BGBlindOn) { // Divider not allowed with between-glass shade or blind if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).FrameDivider > 0) { if (FrameDivider(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).FrameDivider).DividerWidth > 0.0) { @@ -4883,7 +4882,7 @@ namespace SurfaceGeometry { MatGap1 = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(2 * TotGlassLayers - 2); MatGap2 = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(2 * TotGlassLayers); MatSh = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(2 * TotGlassLayers - 1); - if (WindowShadingControl(WSCPtr).ShadingType == WSC_ST_BetweenGlassBlind) { + if (WindowShadingControl(WSCPtr).ShadingType == WinShadingFlag::BGBlindOn) { MatGapCalc = std::abs(state.dataMaterial->Material(MatGap).Thickness - (state.dataMaterial->Material(MatGap1).Thickness + state.dataMaterial->Material(MatGap2).Thickness)); if (MatGapCalc > 0.001) { ShowSevereError(state, cRoutineName + ": The gap width(s) for the unshaded window construction " + state.dataConstruction->Construct(ConstrNum).Name); @@ -4971,8 +4970,8 @@ namespace SurfaceGeometry { // Divider not allowed with between-glass shade or blind for (int WSCPtr : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).windowShadingControlList) { if (!ErrorsFound && WSCPtr > 0 && ConstrNumSh > 0) { - if (WindowShadingControl(WSCPtr).ShadingType == WSC_ST_BetweenGlassShade || - WindowShadingControl(WSCPtr).ShadingType == WSC_ST_BetweenGlassBlind) { + if (WindowShadingControl(WSCPtr).ShadingType == WinShadingFlag::BGShadeOn || + WindowShadingControl(WSCPtr).ShadingType == WinShadingFlag::BGBlindOn) { if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).FrameDivider > 0) { if (FrameDivider(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).FrameDivider).DividerWidth > 0.0) { ShowSevereError(state, cCurrentModuleObject + "=\"" + state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name + "\", invalid " + @@ -8177,15 +8176,15 @@ namespace SurfaceGeometry { "BETWEENGLASSSHADE", "BETWEENGLASSBLIND", "SWITCHABLEGLAZING"}); - static Array1D_int const ValidShadingTypes(NumValidShadingTypes, - {WSC_ST_InteriorShade, - WSC_ST_ExteriorShade, - WSC_ST_ExteriorScreen, - WSC_ST_InteriorBlind, - WSC_ST_ExteriorBlind, - WSC_ST_BetweenGlassShade, - WSC_ST_BetweenGlassBlind, - WSC_ST_SwitchableGlazing}); + static Array1D const ValidShadingTypes(NumValidShadingTypes, + {WinShadingFlag::IntShadeOn, + WinShadingFlag::ExtShadeOn, + WinShadingFlag::ExtScreenOn, + WinShadingFlag::IntBlindOn, + WinShadingFlag::ExtBlindOn, + WinShadingFlag::BGShadeOn, + WinShadingFlag::BGBlindOn, + WinShadingFlag::SwitchableGlazing}); int const NumValidWindowShadingControlTypes(21); static Array1D_string const cValidWindowShadingControlTypes(NumValidWindowShadingControlTypes, @@ -8258,7 +8257,6 @@ namespace SurfaceGeometry { bool ErrorInName; bool IsBlank; int Loop; - int ShTyp; // Shading type std::string ControlType; // Shading control type bool BGShadeBlindError; // True if problem with construction that is supposed to have between-glass // shade or blind @@ -8484,13 +8482,13 @@ namespace SurfaceGeometry { if (cAlphaArgs(3) == "INTERIORNONINSULATINGSHADE" || cAlphaArgs(3) == "INTERIORINSULATINGSHADE") { ShowWarningError(state, cCurrentModuleObject + "=\"" + WindowShadingControl(ControlNum).Name + "\" is using obsolete " + cAlphaFieldNames(3) + "=\"" + cAlphaArgs(3) + "\", changing to \"InteriorShade\""); - WindowShadingControl(ControlNum).ShadingType = WSC_ST_InteriorShade; + WindowShadingControl(ControlNum).ShadingType = WinShadingFlag::IntShadeOn; cAlphaArgs(3) = "INTERIORSHADE"; } if (cAlphaArgs(3) == "EXTERIORNONINSULATINGSHADE" || cAlphaArgs(3) == "EXTERIORINSULATINGSHADE") { ShowWarningError(state, cCurrentModuleObject + "=\"" + WindowShadingControl(ControlNum).Name + "\" is using obsolete " + cAlphaFieldNames(3) + "=\"" + cAlphaArgs(3) + "\", changing to \"ExteriorShade\""); - WindowShadingControl(ControlNum).ShadingType = WSC_ST_ExteriorShade; + WindowShadingControl(ControlNum).ShadingType = WinShadingFlag::ExtShadeOn; cAlphaArgs(3) = "EXTERIORSHADE"; } @@ -8512,7 +8510,7 @@ namespace SurfaceGeometry { WindowShadingControl(ControlNum).ShadingType = ValidShadingTypes(Found); } - ShTyp = WindowShadingControl(ControlNum).ShadingType; + WinShadingFlag ShTyp = WindowShadingControl(ControlNum).ShadingType; IShadedConst = WindowShadingControl(ControlNum).getInputShadedConstruction; IShadingDevice = WindowShadingControl(ControlNum).ShadingDevice; @@ -8521,30 +8519,30 @@ namespace SurfaceGeometry { "\" has no matching shaded construction or shading device."); ErrorsFound = true; } else if (IShadedConst == 0 && IShadingDevice > 0) { - if (ShTyp == WSC_ST_SwitchableGlazing) { + if (ShTyp == WinShadingFlag::SwitchableGlazing) { ShowSevereError(state, cCurrentModuleObject + "=\"" + WindowShadingControl(ControlNum).Name + "\" has " + cAlphaArgs(3) + "= SwitchableGlazing but no matching shaded construction"); ErrorsFound = true; } - if ((ShTyp == WSC_ST_InteriorShade || ShTyp == WSC_ST_ExteriorShade) && state.dataMaterial->Material(IShadingDevice).Group != Shade) { + if ((ShTyp == WinShadingFlag::IntShadeOn || ShTyp == WinShadingFlag::ExtShadeOn) && state.dataMaterial->Material(IShadingDevice).Group != Shade) { ShowSevereError(state, cCurrentModuleObject + "=\"" + WindowShadingControl(ControlNum).Name + "\" has " + cAlphaArgs(3) + "= InteriorShade or ExteriorShade but matching shading device is not a window shade"); ShowContinueError(state, cAlphaFieldNames(8) + " in error=\"" + state.dataMaterial->Material(IShadingDevice).Name + "\"."); ErrorsFound = true; } - if ((ShTyp == WSC_ST_ExteriorScreen) && state.dataMaterial->Material(IShadingDevice).Group != Screen) { + if ((ShTyp == WinShadingFlag::ExtScreenOn) && state.dataMaterial->Material(IShadingDevice).Group != Screen) { ShowSevereError(state, cCurrentModuleObject + "=\"" + WindowShadingControl(ControlNum).Name + "\" has " + cAlphaArgs(3) + "= ExteriorScreen but matching shading device is not a window screen"); ShowContinueError(state, cAlphaFieldNames(8) + " in error=\"" + state.dataMaterial->Material(IShadingDevice).Name + "\"."); ErrorsFound = true; } - if ((ShTyp == WSC_ST_InteriorBlind || ShTyp == WSC_ST_ExteriorBlind) && state.dataMaterial->Material(IShadingDevice).Group != WindowBlind) { + if ((ShTyp == WinShadingFlag::IntBlindOn || ShTyp == WinShadingFlag::ExtBlindOn) && state.dataMaterial->Material(IShadingDevice).Group != WindowBlind) { ShowSevereError(state, cCurrentModuleObject + "=\"" + WindowShadingControl(ControlNum).Name + "\" has " + cAlphaArgs(3) + "= InteriorBlind or ExteriorBlind but matching shading device is not a window blind"); ShowContinueError(state, cAlphaFieldNames(8) + " in error=\"" + state.dataMaterial->Material(IShadingDevice).Name + "\"."); ErrorsFound = true; } - if (ShTyp == WSC_ST_BetweenGlassShade || ShTyp == WSC_ST_BetweenGlassBlind) { + if (ShTyp == WinShadingFlag::BGShadeOn || ShTyp == WinShadingFlag::BGBlindOn) { ShowSevereError(state, cCurrentModuleObject + "=\"" + WindowShadingControl(ControlNum).Name + "\" has " + cAlphaArgs(3) + "= BetweenGlassShade or BetweenGlassBlind and"); ShowContinueError(state, cAlphaFieldNames(8) + " is specified. This is illegal. Specify shaded construction instead."); @@ -8565,7 +8563,7 @@ namespace SurfaceGeometry { BGShadeBlindError = false; IShadingDevice = 0; if (state.dataConstruction->Construct(IShadedConst).LayerPoint(NLayers) != 0) { - if (WindowShadingControl(ControlNum).ShadingType == WSC_ST_InteriorShade) { + if (WindowShadingControl(ControlNum).ShadingType == WinShadingFlag::IntShadeOn) { IShadingDevice = state.dataConstruction->Construct(IShadedConst).LayerPoint(NLayers); if (state.dataMaterial->Material(state.dataConstruction->Construct(IShadedConst).LayerPoint(NLayers)).Group != Shade) { ErrorsFound = true; @@ -8574,7 +8572,7 @@ namespace SurfaceGeometry { ShowContinueError(state, "of " + cAlphaFieldNames(3) + "=\"" + cAlphaArgs(3) + "\" should have a shade layer on the inside of the window."); } - } else if (WindowShadingControl(ControlNum).ShadingType == WSC_ST_ExteriorShade) { + } else if (WindowShadingControl(ControlNum).ShadingType == WinShadingFlag::ExtShadeOn) { IShadingDevice = state.dataConstruction->Construct(IShadedConst).LayerPoint(1); if (state.dataMaterial->Material(state.dataConstruction->Construct(IShadedConst).LayerPoint(1)).Group != Shade) { ErrorsFound = true; @@ -8583,7 +8581,7 @@ namespace SurfaceGeometry { ShowContinueError(state, "of " + cAlphaFieldNames(3) + "=\"" + cAlphaArgs(3) + "\" should have a shade layer on the outside of the window."); } - } else if (WindowShadingControl(ControlNum).ShadingType == WSC_ST_ExteriorScreen) { + } else if (WindowShadingControl(ControlNum).ShadingType == WinShadingFlag::ExtScreenOn) { IShadingDevice = state.dataConstruction->Construct(IShadedConst).LayerPoint(1); if (state.dataMaterial->Material(state.dataConstruction->Construct(IShadedConst).LayerPoint(1)).Group != Screen) { ErrorsFound = true; @@ -8592,7 +8590,7 @@ namespace SurfaceGeometry { ShowContinueError(state, "of " + cAlphaFieldNames(3) + "=\"" + cAlphaArgs(3) + "\" should have a screen layer on the outside of the window."); } - } else if (WindowShadingControl(ControlNum).ShadingType == WSC_ST_InteriorBlind) { + } else if (WindowShadingControl(ControlNum).ShadingType == WinShadingFlag::IntBlindOn) { IShadingDevice = state.dataConstruction->Construct(IShadedConst).LayerPoint(NLayers); if (state.dataMaterial->Material(state.dataConstruction->Construct(IShadedConst).LayerPoint(NLayers)).Group != WindowBlind) { ErrorsFound = true; @@ -8601,7 +8599,7 @@ namespace SurfaceGeometry { ShowContinueError(state, "of " + cAlphaFieldNames(3) + "=\"" + cAlphaArgs(3) + "\" should have a blind layer on the inside of the window."); } - } else if (WindowShadingControl(ControlNum).ShadingType == WSC_ST_ExteriorBlind) { + } else if (WindowShadingControl(ControlNum).ShadingType == WinShadingFlag::ExtBlindOn) { IShadingDevice = state.dataConstruction->Construct(IShadedConst).LayerPoint(1); if (state.dataMaterial->Material(state.dataConstruction->Construct(IShadedConst).LayerPoint(1)).Group != WindowBlind) { ErrorsFound = true; @@ -8610,7 +8608,7 @@ namespace SurfaceGeometry { ShowContinueError(state, "of " + cAlphaFieldNames(3) + "=\"" + cAlphaArgs(3) + "\" should have a blind layer on the outside of the window."); } - } else if (WindowShadingControl(ControlNum).ShadingType == WSC_ST_BetweenGlassShade) { + } else if (WindowShadingControl(ControlNum).ShadingType == WinShadingFlag::BGShadeOn) { if (NLayers != 5 && NLayers != 7) BGShadeBlindError = true; if (NLayers == 5) { if (state.dataMaterial->Material(state.dataConstruction->Construct(IShadedConst).LayerPoint(3)).Group != Shade) BGShadeBlindError = true; @@ -8626,7 +8624,7 @@ namespace SurfaceGeometry { "\" should have two or three glass layers and a"); ShowContinueError(state, "between-glass shade layer with a gas layer on each side."); } - } else if (WindowShadingControl(ControlNum).ShadingType == WSC_ST_BetweenGlassBlind) { + } else if (WindowShadingControl(ControlNum).ShadingType == WinShadingFlag::BGBlindOn) { if (NLayers != 5 && NLayers != 7) BGShadeBlindError = true; if (NLayers == 5) { if (state.dataMaterial->Material(state.dataConstruction->Construct(IShadedConst).LayerPoint(3)).Group != WindowBlind) BGShadeBlindError = true; @@ -8644,19 +8642,19 @@ namespace SurfaceGeometry { } } if (IShadingDevice > 0) { - if ((ShTyp == WSC_ST_InteriorShade || ShTyp == WSC_ST_ExteriorShade) && state.dataMaterial->Material(IShadingDevice).Group != Shade) { + if ((ShTyp == WinShadingFlag::IntShadeOn || ShTyp == WinShadingFlag::ExtShadeOn) && state.dataMaterial->Material(IShadingDevice).Group != Shade) { ShowSevereError(state, cCurrentModuleObject + "=\"" + WindowShadingControl(ControlNum).Name + "\" has " + cAlphaFieldNames(3) + "= InteriorShade or ExteriorShade but matching shading device is not a window shade"); ShowContinueError(state, "Shading Device in error=\"" + state.dataMaterial->Material(IShadingDevice).Name + "\"."); ErrorsFound = true; } - if ((ShTyp == WSC_ST_ExteriorScreen) && state.dataMaterial->Material(IShadingDevice).Group != Screen) { + if ((ShTyp == WinShadingFlag::ExtScreenOn) && state.dataMaterial->Material(IShadingDevice).Group != Screen) { ShowSevereError(state, cCurrentModuleObject + "=\"" + WindowShadingControl(ControlNum).Name + "\" has " + cAlphaFieldNames(3) + "= ExteriorScreen but matching shading device is not an exterior window screen."); ShowContinueError(state, "Shading Device in error=\"" + state.dataMaterial->Material(IShadingDevice).Name + "\"."); ErrorsFound = true; } - if ((ShTyp == WSC_ST_InteriorBlind || ShTyp == WSC_ST_ExteriorBlind) && state.dataMaterial->Material(IShadingDevice).Group != WindowBlind) { + if ((ShTyp == WinShadingFlag::IntBlindOn || ShTyp == WinShadingFlag::ExtBlindOn) && state.dataMaterial->Material(IShadingDevice).Group != WindowBlind) { ShowSevereError(state, cCurrentModuleObject + "=\"" + WindowShadingControl(ControlNum).Name + "\" has " + cAlphaFieldNames(3) + "= InteriorBlind or ExteriorBlind but matching shading device is not a window blind."); ShowContinueError(state, "Shading Device in error=\"" + state.dataMaterial->Material(IShadingDevice).Name + "\"."); @@ -9177,8 +9175,8 @@ namespace SurfaceGeometry { if (Surface(SurfNum).HasShadeControl) { for (std::size_t listIndex = 0; listIndex < Surface(SurfNum).windowShadingControlList.size(); ++listIndex) { int WSCPtr = Surface(SurfNum).windowShadingControlList[listIndex]; - if (WindowShadingControl(WSCPtr).ShadingType == WSC_ST_BetweenGlassShade || - WindowShadingControl(WSCPtr).ShadingType == WSC_ST_BetweenGlassBlind) { + if (WindowShadingControl(WSCPtr).ShadingType == WinShadingFlag::BGShadeOn || + WindowShadingControl(WSCPtr).ShadingType == WinShadingFlag::BGBlindOn) { ConstrNumSh = Surface(SurfNum).shadedConstructionList[listIndex]; if (state.dataConstruction->Construct(ConstrNum).TotGlassLayers == 2) { MatGapFlow1 = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(2); @@ -11690,7 +11688,7 @@ namespace SurfaceGeometry { ShDevName = state.dataMaterial->Material(ShDevNum).Name; ConstrNum = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction; ConstrName = state.dataConstruction->Construct(ConstrNum).Name; - if (WindowShadingControl(WSCPtr).ShadingType == WSC_ST_InteriorShade || WindowShadingControl(WSCPtr).ShadingType == WSC_ST_InteriorBlind) { + if (WindowShadingControl(WSCPtr).ShadingType == WinShadingFlag::IntShadeOn || WindowShadingControl(WSCPtr).ShadingType == WinShadingFlag::IntBlindOn) { ConstrNameSh = ConstrName + ':' + ShDevName + ":INT"; } else { ConstrNameSh = ConstrName + ':' + ShDevName + ":EXT"; @@ -11722,8 +11720,8 @@ namespace SurfaceGeometry { state.dataConstruction->Construct(ConstrNewSh).LayerPoint = 0; - if (WindowShadingControl(WSCPtr).ShadingType == WSC_ST_InteriorShade || - WindowShadingControl(WSCPtr).ShadingType == WSC_ST_InteriorBlind) { + if (WindowShadingControl(WSCPtr).ShadingType == WinShadingFlag::IntShadeOn || + WindowShadingControl(WSCPtr).ShadingType == WinShadingFlag::IntBlindOn) { // Interior shading device state.dataConstruction->Construct(ConstrNewSh).LayerPoint({1, TotLayersOld}) = state.dataConstruction->Construct(ConstrNum).LayerPoint({1, TotLayersOld}); state.dataConstruction->Construct(ConstrNewSh).LayerPoint(TotLayersNew) = ShDevNum; diff --git a/src/EnergyPlus/WindowManager.cc b/src/EnergyPlus/WindowManager.cc index e311225337b..cd40eb17b29 100644 --- a/src/EnergyPlus/WindowManager.cc +++ b/src/EnergyPlus/WindowManager.cc @@ -1512,7 +1512,6 @@ namespace WindowManager { int NumHorDividers; // Number of horizontal divider elements int NumVertDividers; // Number of vertical divider elements int BaseSurfNum; // Base surface number - int ShadingType; // Window shading type int MatNum; // Material number int DifOverrideCount; // Count the number of SolarDiffusing material overrides @@ -1545,8 +1544,8 @@ namespace WindowManager { if (Surface(SurfNum).HasShadeControl) { for (int winShadCtrl : Surface(SurfNum).windowShadingControlList) { - ShadingType = WindowShadingControl(winShadCtrl).ShadingType; - if (ShadingType == WSC_ST_ExteriorScreen) { + WinShadingFlag ShadingType = WindowShadingControl(winShadCtrl).ShadingType; + if (ShadingType == WinShadingFlag::ExtScreenOn) { // Count number of exterior window screens, initialize in InitGlassOpticalCalculations after returning // from this subroutine. The blind structure is initialized first and then the screen structure is initialized. ++NumSurfaceScreens; @@ -1616,7 +1615,7 @@ namespace WindowManager { if (!Surface(SurfNum).HasShadeControl) { SurfWinSolarDiffusing(SurfNum) = true; } else { // There is a shading control - if (WindowShadingControl(Surface(SurfNum).activeWindowShadingControl).ShadingType == WSC_ST_SwitchableGlazing) { + if (WindowShadingControl(Surface(SurfNum).activeWindowShadingControl).ShadingType == WinShadingFlag::SwitchableGlazing) { SurfWinSolarDiffusing(SurfNum) = true; } else { SurfWinSolarDiffusing(SurfNum) = false; @@ -7458,7 +7457,6 @@ namespace WindowManager { Real64 SumReflect; // Integration variable for reflectance Real64 SumReflectVis; // Integration variable for visible reflectance Real64 SumArea; // Integration variable for area of quarter hemisphere - int ShadingType; // Type of shading device bool FoundMaterial; // Flag to avoid printing screen transmittance data multiple times when Material:WindowScreen // is used on multiple surfaces bool PrintTransMap; // Flag used to print transmittance map @@ -7510,8 +7508,8 @@ namespace WindowManager { if (Surface(SurfNum).HasShadeControl) { ConstrNumSh = Surface(SurfNum).activeShadedConstruction; MatNum = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(1); - ShadingType = WindowShadingControl(Surface(SurfNum).activeWindowShadingControl).ShadingType; - if (ShadingType == WSC_ST_ExteriorScreen) { + WinShadingFlag ShadingType = WindowShadingControl(Surface(SurfNum).activeWindowShadingControl).ShadingType; + if (ShadingType == WinShadingFlag::ExtScreenOn) { if (state.dataMaterial->Material(MatNum).ScreenMapResolution > 0) PrintTransMap = true; ++ScreenNum; diff --git a/tst/EnergyPlus/unit/EMSManager.unit.cc b/tst/EnergyPlus/unit/EMSManager.unit.cc index cf6c48ff8e1..8021a01f836 100644 --- a/tst/EnergyPlus/unit/EMSManager.unit.cc +++ b/tst/EnergyPlus/unit/EMSManager.unit.cc @@ -1610,8 +1610,8 @@ TEST_F(EnergyPlusFixture, EMSManager_TestWindowShadingControlExteriorScreenOptio state->dataConstruction->Construct(1).Name = "Construction1"; - DataSurfaces::WindowShadingControl(1).ShadingType = 0; - DataSurfaces::WindowShadingControl(2).ShadingType = DataSurfaces::WSC_ST_ExteriorScreen; + DataSurfaces::WindowShadingControl(1).ShadingType = DataSurfaces::WinShadingFlag::NoShade; + DataSurfaces::WindowShadingControl(2).ShadingType = DataSurfaces::WinShadingFlag::ExtScreenOn; DataSurfaces::TotSurfaces = 2; diff --git a/tst/EnergyPlus/unit/SurfaceGeometry.unit.cc b/tst/EnergyPlus/unit/SurfaceGeometry.unit.cc index c97cd19a63a..ca3aca89f2d 100644 --- a/tst/EnergyPlus/unit/SurfaceGeometry.unit.cc +++ b/tst/EnergyPlus/unit/SurfaceGeometry.unit.cc @@ -3474,7 +3474,7 @@ TEST_F(EnergyPlusFixture, SurfaceGeometry_isWindowShadingControlSimilar_Test) WindowShadingControl(1).Name = "TheShadingControl"; WindowShadingControl(1).ZoneIndex = 57; WindowShadingControl(1).SequenceNumber = 3; - WindowShadingControl(1).ShadingType = WSC_ST_ExteriorShade; + WindowShadingControl(1).ShadingType = WinShadingFlag::ExtShadeOn; WindowShadingControl(1).ShadingDevice = 17; WindowShadingControl(1).ShadingControlType = WSCT_OnIfScheduled; WindowShadingControl(1).Schedule = 83; @@ -3546,7 +3546,7 @@ TEST_F(EnergyPlusFixture, SurfaceGeometry_isWindowShadingControlSimilar_Test) EXPECT_FALSE(isWindowShadingControlSimilar(1, 2)); WindowShadingControl(2) = WindowShadingControl(1); - WindowShadingControl(2).ShadingType = WSC_ST_BetweenGlassBlind; + WindowShadingControl(2).ShadingType = WinShadingFlag::BGBlindOn; EXPECT_FALSE(isWindowShadingControlSimilar(1, 2)); WindowShadingControl(2) = WindowShadingControl(1); @@ -3601,7 +3601,7 @@ TEST_F(EnergyPlusFixture, SurfaceGeometry_CheckWindowShadingControlSimilarForWin WindowShadingControl(1).Name = "TheShadingControl"; WindowShadingControl(1).ZoneIndex = 57; WindowShadingControl(1).SequenceNumber = 3; - WindowShadingControl(1).ShadingType = WSC_ST_ExteriorShade; + WindowShadingControl(1).ShadingType = WinShadingFlag::ExtShadeOn; WindowShadingControl(1).ShadingDevice = 17; WindowShadingControl(1).ShadingControlType = WSCT_OnIfScheduled; WindowShadingControl(1).Schedule = 83; From 256e6e0fab426aeb1bf07c72d3f752960519492e Mon Sep 17 00:00:00 2001 From: Noel Merket Date: Wed, 20 Jan 2021 11:31:53 -0700 Subject: [PATCH 20/76] Squashed 'third_party/ssc/' changes from 41e46913b1..707dc0792d 707dc0792d Add lithium ion nmc option in batt calendar choice ff3d63f22a update lib_battery to add nmc model 5cf42876c2 adding lifetime_cycle_t object in lifetime_calendar_t 66046db775 building the Li_ion_nmc calendar degradation function 4247518fa0 Creating lifetime_t constructor for li_ion_nmc git-subtree-dir: third_party/ssc git-subtree-split: 707dc0792d0b81225d85714eec39076e5ef7265f --- shared/lib_battery.cpp | 5 +- shared/lib_battery.h | 4 +- shared/lib_battery_lifetime.cpp | 59 ++++++++++++++++++- shared/lib_battery_lifetime.h | 37 +++++++++++- ssc/cmod_battery.cpp | 3 + .../shared_test/lib_battery_lifetime_test.cpp | 35 +++++++---- 6 files changed, 127 insertions(+), 16 deletions(-) diff --git a/shared/lib_battery.cpp b/shared/lib_battery.cpp index fff5126ee05..7f32a07a7ad 100644 --- a/shared/lib_battery.cpp +++ b/shared/lib_battery.cpp @@ -383,9 +383,12 @@ void battery_t::initialize() { if (params->voltage->voltage_choice == voltage_params::TABLE || params->chem == battery_params::IRON_FLOW) { voltage = std::unique_ptr(new voltage_table_t(params->voltage)); } - else if (params->chem == battery_params::LEAD_ACID || params->chem == battery_params::LITHIUM_ION) { + //Rohit Add lithium_ION_NMC + else if (params->chem == battery_params::LEAD_ACID || params->chem == battery_params::LITHIUM_ION + || params->chem == battery_params::LITHIUM_ION_NMC) { voltage = std::unique_ptr(new voltage_dynamic_t(params->voltage)); } + else if (params->chem == battery_params::VANADIUM_REDOX) { voltage = std::unique_ptr(new voltage_vanadium_redox_t(params->voltage)); } diff --git a/shared/lib_battery.h b/shared/lib_battery.h index 55228dce1b9..5e55277ab0e 100644 --- a/shared/lib_battery.h +++ b/shared/lib_battery.h @@ -257,8 +257,10 @@ struct battery_state { }; struct battery_params { + + //Rohit - Add Lithium_ion_nmc enum CHEM { - LEAD_ACID, LITHIUM_ION, VANADIUM_REDOX, IRON_FLOW + LEAD_ACID, LITHIUM_ION, VANADIUM_REDOX, IRON_FLOW, LITHIUM_ION_NMC }; int chem; double dt_hour; diff --git a/shared/lib_battery_lifetime.cpp b/shared/lib_battery_lifetime.cpp index 15cbc09575c..95a2b288197 100644 --- a/shared/lib_battery_lifetime.cpp +++ b/shared/lib_battery_lifetime.cpp @@ -348,6 +348,8 @@ bool calendar_state::operator==(const calendar_state &p) { void lifetime_calendar_t::initialize() { state = std::make_shared(); + // Rohit - initialize cycle model object in lifetime_calendar_t + cycle_model = std::unique_ptr(new lifetime_cycle_t(params)); state->day_age_of_battery = 0; state->q_relative_calendar = 100; state->dq_relative_calendar_old = 0; @@ -411,13 +413,16 @@ double lifetime_calendar_t::capacity_percent() { return state->q_relative_calend calendar_state lifetime_calendar_t::get_state() { return *state; } -double lifetime_calendar_t::runLifetimeCalendarModel(size_t lifetimeIndex, double T, double SOC) { +double lifetime_calendar_t::runLifetimeCalendarModel(size_t lifetimeIndex, double T, double SOC, bool charge_changed) { state->day_age_of_battery = (int)(lifetimeIndex / (util::hours_per_day / params->dt_hour)); if (params->calendar_choice == lifetime_params::CALENDAR_CHOICE::MODEL) runLithiumIonModel(T, SOC); else if (params->calendar_choice == lifetime_params::CALENDAR_CHOICE::TABLE) runTableModel(); + //Rohit - run LiionNMCModel + else if (params->calendar_choice == lifetime_params::CALENDAR_CHOICE::NMC_MODEL) + runLithiumIonNMCModel(T, SOC, charge_changed); else state->q_relative_calendar = 100; @@ -438,6 +443,45 @@ void lifetime_calendar_t::runLithiumIonModel(double temp, double SOC) { state->q_relative_calendar = (params->calendar_q0 - (dq_new)) * 100; } +// Rohit - define Q_li model for Li-ion +void lifetime_calendar_t::runLithiumIonNMCModel(double temp, double SOC, bool charge_changed) { + temp += 273.15; + SOC *= 0.01; + // write function to find DOD_max, U_neg, and V_oc + double DOD_max = 0.8; + double U_neg = 0.1726; + double V_oc = 3.6912; + //calendar component + double b1 = b1_ref * exp(-(Ea_b_1 / Rug) * (1. / temp - 1. / T_ref)) + * exp((alpha_a_b1 * F / Rug) * (U_neg / temp - U_ref / T_ref)) + * exp(gamma * pow(DOD_max, beta_b1)); + + double b2 = b2_ref * exp(-(Ea_b_2 / Rug) * (1. / temp - 1. / T_ref)); + + double b3 = b3_ref * exp(-(Ea_b_3 / Rug) * (1. / temp - 1. / T_ref)) + * exp((alpha_a_b3 * F / Rug) * (V_oc / temp - V_ref / T_ref)) + * (1+theta*DOD_max); + + if (charge_changed) + cycle_model->rainflow(100. - SOC); + + double dn_cycles = cycle_model->get_state().n_cycles; + + double k_cal = 0; + if (state->day_age_of_battery > 0) + k_cal = (0.5 * b1) / (sqrt(state->day_age_of_battery)) + (b3/tau_b3)*exp(-(state->day_age_of_battery/tau_b3)); + else + k_cal = 0; + + double dq_new; + if (state->dq_relative_calendar_old == 0) + dq_new = k_cal * dt_day + b2*dn_cycles; + else + dq_new = k_cal * dt_day + state->dq_relative_calendar_old; + state->dq_relative_calendar_old = dq_new; + state->q_relative_calendar = (params->calendar_q0 - (dq_new)) * 100; +} + void lifetime_calendar_t::runTableModel() { size_t n_rows = params->calendar_matrix.nrows(); size_t n = n_rows - 1; @@ -537,6 +581,16 @@ lifetime_t::lifetime_t(const util::matrix_t &batt_lifetime_matrix, doubl initialize(); } +//Rohit Add lifetime_t constructor for NMC_MODEL +lifetime_t::lifetime_t(double dt_hour) { + params = std::make_shared(); + params->dt_hour = dt_hour; + params->calendar_choice = lifetime_params::CALENDAR_CHOICE::NMC_MODEL; + params->calendar_q0 = 1.07; + + initialize(); +} + lifetime_t::lifetime_t(const util::matrix_t &batt_lifetime_matrix, double dt_hour) { params = std::make_shared(); params->dt_hour = dt_hour; @@ -591,7 +645,8 @@ void lifetime_t::runLifetimeModels(size_t lifetimeIndex, bool charge_changed, do else if (lifetimeIndex == 0) q_cycle = cycle_model->runCycleLifetime(DOD); - q_calendar = calendar_model->runLifetimeCalendarModel(lifetimeIndex, T_battery, 100. - DOD); + // Rohit - add parameter charge_changed + q_calendar = calendar_model->runLifetimeCalendarModel(lifetimeIndex, T_battery, 100. - DOD, charge_changed); // total capacity is min of cycle (Q_neg) and calendar (Q_li) capacity state->q_relative = fmin(q_cycle, q_calendar); diff --git a/shared/lib_battery_lifetime.h b/shared/lib_battery_lifetime.h index 76e199032df..348a4cb4f7b 100644 --- a/shared/lib_battery_lifetime.h +++ b/shared/lib_battery_lifetime.h @@ -39,8 +39,9 @@ struct lifetime_params { }; // calendar + //Rohit adding MODEL_NMC option enum CALENDAR_CHOICE { - NONE, MODEL, TABLE + NONE, MODEL, TABLE, NMC_MODEL }; int calendar_choice; double dt_hour; @@ -170,7 +171,8 @@ class lifetime_calendar_t { lifetime_calendar_t *clone(); /// Given the index of the simulation, the tempertature and SOC, return the effective capacity percent - double runLifetimeCalendarModel(size_t lifetimeIndex, double T, double SOC); + /// Rohit - Add parameter charge_changed + double runLifetimeCalendarModel(size_t lifetimeIndex, double T, double SOC, bool charge_changed); /// Reset or augment the capacity void replaceBattery(double replacement_percent); @@ -183,6 +185,9 @@ class lifetime_calendar_t { protected: void runLithiumIonModel(double temp_C, double SOC); + // Rohit - add Q_li for Li_ion model + void runLithiumIonNMCModel(double temp_C, double SOC, bool charge_changed); + void runTableModel(); double dt_day; @@ -190,9 +195,34 @@ class lifetime_calendar_t { std::shared_ptr state; std::shared_ptr params; + //Rohit - Add cycle_model object in lifetime_calendar_t + std::unique_ptr cycle_model; + private: void initialize(); + /// Rohit - Add Li-ion NMC Kandler Smith parameters + double Ea_d0_1 = 4126.0; + double b1_ref = 0.003503; + double Ea_b_1 = 35392.; + double Rug = 8.314; + double T_ref = 298.15; + double alpha_a_b1 = -1; + double F = 96485; + double U_ref = 0.08; + double gamma = 2.472; + double beta_b1 = 2.157; + + double b2_ref = 0.00001541; + double Ea_b_2 = -42800.; + + double b3_ref = 0.003503; + double Ea_b_3 = 42800.; + double alpha_a_b3 = 0.0066; + double V_ref = 3.7; + double theta = 0.135; + double tau_b3 = 5; + friend class lifetime_t; }; @@ -225,6 +255,9 @@ class lifetime_t { lifetime_t(const util::matrix_t &batt_lifetime_matrix, double dt_hour, double q0, double a, double b, double c); + /// Rohit NMC model constructor + lifetime_t(double dt_hour); + /// Cycle with no Calendar lifetime_t(const util::matrix_t &batt_lifetime_matrix, double dt_hour); diff --git a/ssc/cmod_battery.cpp b/ssc/cmod_battery.cpp index 13aec760b6b..47d9e31941e 100644 --- a/ssc/cmod_battery.cpp +++ b/ssc/cmod_battery.cpp @@ -111,6 +111,7 @@ var_info vtab_battery_inputs[] = { { SSC_INPUT, SSC_NUMBER, "batt_minimum_modetime", "Minimum time at charge state", "min", "", "BatteryCell", "", "", "" }, // lifetime inputs + //TODO: Rohit- Add batt_calendar_choice corresponding to lithium_ion_nmc { SSC_INPUT, SSC_MATRIX, "batt_lifetime_matrix", "Cycles vs capacity at different depths-of-discharge", "", "", "BatteryCell", "", "", "" }, { SSC_INPUT, SSC_NUMBER, "batt_calendar_choice", "Calendar life degradation input option", "0/1/2", "0=NoCalendarDegradation,1=LithiomIonModel,2=InputLossTable", "BatteryCell", "", "", "" }, { SSC_INPUT, SSC_MATRIX, "batt_calendar_lifetime_matrix", "Days vs capacity", "", "", "BatteryCell", "", "", "" }, @@ -803,6 +804,8 @@ battstor::battstor(var_table& vt, bool setup_model, size_t nrec, double dt_hr, c batt_vars->batt_voltage_matrix, batt_vars->batt_resistance, dt_hr); + //Rohit- TODO add option of lifetime_t constructor corresponding lithium_ion_nmc + if (batt_vars->batt_calendar_choice == lifetime_params::CALENDAR_CHOICE::MODEL) { lifetime_model = new lifetime_t(batt_vars->batt_lifetime_matrix, dt_hr, batt_vars->batt_calendar_q0, batt_vars->batt_calendar_a, batt_vars->batt_calendar_b, batt_vars->batt_calendar_c); diff --git a/test/shared_test/lib_battery_lifetime_test.cpp b/test/shared_test/lib_battery_lifetime_test.cpp index 7bd62ab428b..dbdfbac5883 100644 --- a/test/shared_test/lib_battery_lifetime_test.cpp +++ b/test/shared_test/lib_battery_lifetime_test.cpp @@ -161,11 +161,13 @@ TEST_F(lib_battery_lifetime_cycle_test, replaceBatteryTest) { TEST_F(lib_battery_lifetime_calendar_matrix_test, runCalendarMatrixTest) { double T = 278, SOC = 20; // not used but required for function int idx = 0; + //Rohit - add charge_changed to CalendarModel + bool charge_changed = true; while (idx < 500){ if (idx % 2 != 0){ SOC = 90; } - cal_model->runLifetimeCalendarModel(idx, T, SOC); + cal_model->runLifetimeCalendarModel(idx, T, SOC, charge_changed); idx++; } calendar_state s = cal_model->get_state(); @@ -177,7 +179,7 @@ TEST_F(lib_battery_lifetime_calendar_matrix_test, runCalendarMatrixTest) { if (idx % 2 != 0){ SOC = 90; } - cal_model->runLifetimeCalendarModel(idx, T, SOC); + cal_model->runLifetimeCalendarModel(idx, T, SOC, charge_changed); idx++; } s = cal_model->get_state(); @@ -189,11 +191,13 @@ TEST_F(lib_battery_lifetime_calendar_matrix_test, runCalendarMatrixTest) { TEST_F(lib_battery_lifetime_calendar_matrix_test, replaceBatteryTest) { double T = 4.85, SOC = 20; int idx = 0; + // Rohit - add charge_changed to Calendar Model + bool charge_changed = true; while (idx < 200000){ if (idx % 2 != 0){ SOC = 90; } - cal_model->runLifetimeCalendarModel(idx, T, SOC); + cal_model->runLifetimeCalendarModel(idx, T, SOC,charge_changed); idx++; } calendar_state s = cal_model->get_state(); @@ -216,11 +220,13 @@ TEST_F(lib_battery_lifetime_calendar_model_test, SetUpTest) { TEST_F(lib_battery_lifetime_calendar_model_test, runCalendarModelTest) { double T = 4.85, SOC = 20; // not used but required for function int idx = 0; + // Add charge_changed to calendar model + bool charge_changed = true; while (idx < 500){ if (idx % 2 != 0){ SOC = 90; } - cal_model->runLifetimeCalendarModel(idx, T, SOC); + cal_model->runLifetimeCalendarModel(idx, T, SOC,charge_changed); idx++; } calendar_state s = cal_model->get_state(); @@ -232,7 +238,7 @@ TEST_F(lib_battery_lifetime_calendar_model_test, runCalendarModelTest) { if (idx % 2 != 0){ SOC = 90; } - cal_model->runLifetimeCalendarModel(idx, T, SOC); + cal_model->runLifetimeCalendarModel(idx, T, SOC,charge_changed); idx++; } s = cal_model->get_state(); @@ -244,11 +250,13 @@ TEST_F(lib_battery_lifetime_calendar_model_test, runCalendarModelTest) { TEST_F(lib_battery_lifetime_calendar_model_test, replaceBatteryTest) { double T = 4.85, SOC = 20; int idx = 0; + //Rohit - add charge_changed to CalendarModel + bool charge_changed = true; while (idx < 200000){ if (idx % 2 != 0){ SOC = 90; } - cal_model->runLifetimeCalendarModel(idx, T, SOC); + cal_model->runLifetimeCalendarModel(idx, T, SOC,charge_changed); idx++; } calendar_state s = cal_model->get_state(); @@ -269,11 +277,13 @@ TEST_F(lib_battery_lifetime_calendar_matrix_test, TestLifetimeDegradation) { util::matrix_t lifetime_matrix; lifetime_matrix.assign(vals, 2, 2); + //Rohit - add charge_changed to Calendar model + bool charge_changed = true; double dt_hour = 1; lifetime_calendar_t hourly_lifetime(dt_hour, lifetime_matrix); for (int idx = 0; idx < 8760; idx++) { - hourly_lifetime.runLifetimeCalendarModel(idx, 20, 80); + hourly_lifetime.runLifetimeCalendarModel(idx, 20, 80,charge_changed); } EXPECT_NEAR(hourly_lifetime.capacity_percent(), 50, 1); @@ -282,7 +292,7 @@ TEST_F(lib_battery_lifetime_calendar_matrix_test, TestLifetimeDegradation) { lifetime_calendar_t subhourly_lifetime(dt_hour, lifetime_matrix); for (int idx = 0; idx < 8760 * 12; idx++) { - subhourly_lifetime.runLifetimeCalendarModel(idx, 20, 80); + subhourly_lifetime.runLifetimeCalendarModel(idx, 20, 80,charge_changed); } EXPECT_NEAR(subhourly_lifetime.capacity_percent(), 50, 1); @@ -291,8 +301,11 @@ TEST_F(lib_battery_lifetime_calendar_matrix_test, TestLifetimeDegradation) { TEST_F(lib_battery_lifetime_calendar_model_test, TestLifetimeDegradation) { + //Rohit - add charge_changed to CalendarModel + bool charge_changed = true; + for (int idx = 0; idx < 8760; idx++) { - cal_model->runLifetimeCalendarModel(idx, 20, 80); + cal_model->runLifetimeCalendarModel(idx, 20, 80,charge_changed); } EXPECT_NEAR(cal_model->capacity_percent(), 99.812, 1); @@ -301,7 +314,7 @@ TEST_F(lib_battery_lifetime_calendar_model_test, TestLifetimeDegradation) { lifetime_calendar_t subhourly_lifetime(dt_hour); for (int idx = 0; idx < 8760 * 12; idx++) { - subhourly_lifetime.runLifetimeCalendarModel(idx, 20, 80); + subhourly_lifetime.runLifetimeCalendarModel(idx, 20, 80,charge_changed); } EXPECT_NEAR(subhourly_lifetime.capacity_percent(), 99.812, 1); @@ -347,6 +360,8 @@ TEST_F(lib_battery_lifetime_test, runCycleLifetimeTestWithRestPeriod) { EXPECT_NEAR(s.range, 90, tol); EXPECT_NEAR(s.average_range, 90, tol); EXPECT_NEAR(s.n_cycles, 2, tol); + //Rohit + EXPECT_GT(s.n_cycles, 0, tol); } From 12eb3951e6092c341390d6fbdf829f6cac3adeae Mon Sep 17 00:00:00 2001 From: Noel Merket Date: Fri, 22 Jan 2021 10:39:10 -0700 Subject: [PATCH 21/76] Squashed 'third_party/ssc/' changes from 707dc0792d..6edbeab044 6edbeab044 added cmod option for liion nmc. Updated Q_neg git-subtree-dir: third_party/ssc git-subtree-split: 6edbeab044f96f83e0ec6ffb9ae7c63674f08104 --- shared/lib_battery_lifetime.cpp | 66 ++++++++++++++++++++++++++++----- shared/lib_battery_lifetime.h | 20 ++++++++++ ssc/cmod_battery.cpp | 7 +++- 3 files changed, 82 insertions(+), 11 deletions(-) diff --git a/shared/lib_battery_lifetime.cpp b/shared/lib_battery_lifetime.cpp index 95a2b288197..188d87be223 100644 --- a/shared/lib_battery_lifetime.cpp +++ b/shared/lib_battery_lifetime.cpp @@ -45,6 +45,7 @@ void lifetime_cycle_t::initialize() { state = std::make_shared(); state->n_cycles = 0; state->q_relative_cycle = bilinear(0., 0); + state->dq_relative_cycle_old = 0; state->range = 0; state->average_range = 0; state->rainflow_jlt = 0; @@ -90,6 +91,27 @@ double lifetime_cycle_t::estimateCycleDamage() { return (bilinear(DOD, state->n_cycles + 1) - bilinear(DOD, state->n_cycles + 2)); } +// Rohit - function to compute Q_neg for Lithium ion NMC +double lifetime_cycle_t::runCycleLifetimeNMC(double T, double DOD) { + int n_cycles_old = state->n_cycles; + rainflow(DOD); + int dn_cycles = state->n_cycles - n_cycles_old; + + double c2 = c2_ref * exp(-(Ea_c_2 / Rug) * (1. / T - 1. / T_ref)) + * pow(DOD, beta_c2); + + double dq_new; + if (state->dq_relative_cycle_old == 0) + dq_new = 1 - sqrt(1 - 2 * (c2 / c0_ref) * dn_cycles); + else + dq_new = 1 - sqrt(1 - 2 * (c2 / c0_ref) * dn_cycles) + state->dq_relative_cycle_old; + + state->dq_relative_cycle_old = dq_new; + + state->q_relative_cycle = (1- (dq_new)) * 100; + return state->q_relative_cycle; +} + double lifetime_cycle_t::runCycleLifetime(double DOD) { rainflow(DOD); @@ -353,7 +375,7 @@ void lifetime_calendar_t::initialize() { state->day_age_of_battery = 0; state->q_relative_calendar = 100; state->dq_relative_calendar_old = 0; - if (params->calendar_choice == lifetime_params::CALENDAR_CHOICE::MODEL) { + if (params->calendar_choice == lifetime_params::CALENDAR_CHOICE::MODEL || params->calendar_choice == lifetime_params::CALENDAR_CHOICE::NMC_MODEL) { dt_day = params->dt_hour / util::hours_per_day; state->q_relative_calendar = params->calendar_q0 * 100; } @@ -409,6 +431,28 @@ lifetime_calendar_t *lifetime_calendar_t::clone() { return new lifetime_calendar_t(*this); } +// Rohit - Define negative electrode voltage function +double lifetime_calendar_t::Uneg_computation(double SOC) { + double Uneg = 0.1; + if (SOC <= 0.1) + Uneg = ((0.2420 - 1.2868) / 0.1) * SOC + 1.268; + else + Uneg = ((0.0859 - 0.2420) / 0.9) * (SOC - 0.1) + 0.2420; + return Uneg; +} + +// Rohit - Define open circuit voltage function +double lifetime_calendar_t::Voc_computation(double SOC) { + double Voc = 0.1; + if (SOC <= 0.1) + Voc = ((0.4679) / 0.1) * SOC + 3; + else if (SOC <= 0.6) + Voc = ((3.747 - 3.4679) / 0.5) * (SOC - 0.1) + 3.4679; + else + Voc = ((4.1934 - 3.7469) / 0.4) * (SOC - 0.6) + 3.7469; + return Voc; +} + double lifetime_calendar_t::capacity_percent() { return state->q_relative_calendar; } calendar_state lifetime_calendar_t::get_state() { return *state; } @@ -449,8 +493,8 @@ void lifetime_calendar_t::runLithiumIonNMCModel(double temp, double SOC, bool ch SOC *= 0.01; // write function to find DOD_max, U_neg, and V_oc double DOD_max = 0.8; - double U_neg = 0.1726; - double V_oc = 3.6912; + double U_neg = Uneg_computation(SOC); + double V_oc = Voc_computation(SOC); //calendar component double b1 = b1_ref * exp(-(Ea_b_1 / Rug) * (1. / temp - 1. / T_ref)) * exp((alpha_a_b1 * F / Rug) * (U_neg / temp - U_ref / T_ref)) @@ -462,10 +506,14 @@ void lifetime_calendar_t::runLithiumIonNMCModel(double temp, double SOC, bool ch * exp((alpha_a_b3 * F / Rug) * (V_oc / temp - V_ref / T_ref)) * (1+theta*DOD_max); - if (charge_changed) + int n_cycles_old = cycle_model->get_state().n_cycles; + + if (charge_changed) { cycle_model->rainflow(100. - SOC); + } + - double dn_cycles = cycle_model->get_state().n_cycles; + int dn_cycles = cycle_model->get_state().n_cycles - n_cycles_old; double k_cal = 0; if (state->day_age_of_battery > 0) @@ -477,7 +525,7 @@ void lifetime_calendar_t::runLithiumIonNMCModel(double temp, double SOC, bool ch if (state->dq_relative_calendar_old == 0) dq_new = k_cal * dt_day + b2*dn_cycles; else - dq_new = k_cal * dt_day + state->dq_relative_calendar_old; + dq_new = k_cal * dt_day + b2*dn_cycles + state->dq_relative_calendar_old; state->dq_relative_calendar_old = dq_new; state->q_relative_calendar = (params->calendar_q0 - (dq_new)) * 100; } @@ -640,10 +688,10 @@ void lifetime_t::runLifetimeModels(size_t lifetimeIndex, bool charge_changed, do double q_cycle = cycle_model->capacity_percent(); double q_calendar; - if (charge_changed) + if (charge_changed && params->calendar_choice != lifetime_params::CALENDAR_CHOICE::NMC_MODEL) q_cycle = cycle_model->runCycleLifetime(prev_DOD); - else if (lifetimeIndex == 0) - q_cycle = cycle_model->runCycleLifetime(DOD); + else if (lifetimeIndex == 0 != lifetime_params::CALENDAR_CHOICE::NMC_MODEL) + q_cycle = cycle_model->runCycleLifetimeNMC(T_battery, DOD); // Rohit - add parameter charge_changed q_calendar = calendar_model->runLifetimeCalendarModel(lifetimeIndex, T_battery, 100. - DOD, charge_changed); diff --git a/shared/lib_battery_lifetime.h b/shared/lib_battery_lifetime.h index 348a4cb4f7b..a50c306a781 100644 --- a/shared/lib_battery_lifetime.h +++ b/shared/lib_battery_lifetime.h @@ -63,6 +63,8 @@ struct lifetime_params { struct cycle_state { double q_relative_cycle; // % + //Rohit - Keep track of cycle degradation for Liion NMC + double dq_relative_cycle_old; int n_cycles; double range; double average_range; @@ -97,6 +99,9 @@ class lifetime_cycle_t { /// return q, the effective capacity percent double runCycleLifetime(double DOD); + /// Rohit - return q, the effective capacity percent for Lithium Ion NMC + double runCycleLifetimeNMC(double T, double DOD); + /// return hypothetical dq the average cycle double estimateCycleDamage(); @@ -137,6 +142,15 @@ class lifetime_cycle_t { private: void initialize(); + /// Rohit - constants for Q_neg of LiionNMC + double c0_ref = 75.1; + double c2_ref = 0.0039193; + double Ea_c_2 = -48260; + double Rug = 8.314; + double T_ref = 298.15; + double beta_c2 = 4.54; + + friend class lifetime_t; }; @@ -180,6 +194,12 @@ class lifetime_calendar_t { /// Return the relative capacity percentage of nominal (%) double capacity_percent(); + /// Calculate negative electrode voltage from SOC + double Uneg_computation(double SOC); + + /// Calculate open circuit voltage from SOC + double Voc_computation(double SOC); + calendar_state get_state(); protected: diff --git a/ssc/cmod_battery.cpp b/ssc/cmod_battery.cpp index 47d9e31941e..1cba9571906 100644 --- a/ssc/cmod_battery.cpp +++ b/ssc/cmod_battery.cpp @@ -113,7 +113,7 @@ var_info vtab_battery_inputs[] = { // lifetime inputs //TODO: Rohit- Add batt_calendar_choice corresponding to lithium_ion_nmc { SSC_INPUT, SSC_MATRIX, "batt_lifetime_matrix", "Cycles vs capacity at different depths-of-discharge", "", "", "BatteryCell", "", "", "" }, - { SSC_INPUT, SSC_NUMBER, "batt_calendar_choice", "Calendar life degradation input option", "0/1/2", "0=NoCalendarDegradation,1=LithiomIonModel,2=InputLossTable", "BatteryCell", "", "", "" }, + { SSC_INPUT, SSC_NUMBER, "batt_calendar_choice", "Calendar life degradation input option", "0/1/2/3", "0=NoCalendarDegradation,1=LithiomIonModel,2=InputLossTable,3=LithiumIonNMCModel", "BatteryCell", "", "", "" }, { SSC_INPUT, SSC_MATRIX, "batt_calendar_lifetime_matrix", "Days vs capacity", "", "", "BatteryCell", "", "", "" }, { SSC_INPUT, SSC_NUMBER, "batt_calendar_q0", "Calendar life model initial capacity cofficient", "", "", "BatteryCell", "", "", "" }, { SSC_INPUT, SSC_NUMBER, "batt_calendar_a", "Calendar life model coefficient", "1/sqrt(day)","", "BatteryCell", "", "", "" }, @@ -804,7 +804,7 @@ battstor::battstor(var_table& vt, bool setup_model, size_t nrec, double dt_hr, c batt_vars->batt_voltage_matrix, batt_vars->batt_resistance, dt_hr); - //Rohit- TODO add option of lifetime_t constructor corresponding lithium_ion_nmc + //Rohit- add option of lifetime_t constructor corresponding lithium_ion_nmc if (batt_vars->batt_calendar_choice == lifetime_params::CALENDAR_CHOICE::MODEL) { lifetime_model = new lifetime_t(batt_vars->batt_lifetime_matrix, dt_hr, @@ -813,6 +813,9 @@ battstor::battstor(var_table& vt, bool setup_model, size_t nrec, double dt_hr, c else if (batt_vars->batt_calendar_choice == lifetime_params::CALENDAR_CHOICE::TABLE) { lifetime_model = new lifetime_t(batt_vars->batt_lifetime_matrix, dt_hr, batt_vars->batt_calendar_lifetime_matrix); } + else if (batt_vars->batt_calendar_choice == lifetime_params::CALENDAR_CHOICE::NMC_MODEL) { + lifetime_model = new lifetime_t(dt_hr); + } else { lifetime_model = new lifetime_t(batt_vars->batt_lifetime_matrix, dt_hr); } From 6cc1bf4cb0d08002531ede98b031fee0e63dc1e1 Mon Sep 17 00:00:00 2001 From: xuanluo113 Date: Sun, 24 Jan 2021 11:51:24 -0800 Subject: [PATCH 22/76] naming --- src/EnergyPlus/ChilledCeilingPanelSimple.cc | 2 +- src/EnergyPlus/ConvectionCoefficients.cc | 4 +- src/EnergyPlus/DataSurfaces.cc | 6 +- src/EnergyPlus/DataSurfaces.hh | 40 ++-- src/EnergyPlus/DaylightingManager.cc | 92 ++++----- src/EnergyPlus/DaylightingManager.hh | 4 +- src/EnergyPlus/EMSManager.cc | 6 +- src/EnergyPlus/HWBaseboardRadiator.cc | 6 +- src/EnergyPlus/HeatBalanceIntRadExchange.cc | 18 +- src/EnergyPlus/HeatBalanceSurfaceManager.cc | 78 ++++---- src/EnergyPlus/HighTempRadiantSystem.cc | 6 +- src/EnergyPlus/LowTempRadiantSystem.cc | 6 +- src/EnergyPlus/RoomAirModelAirflowNetwork.cc | 4 +- src/EnergyPlus/SolarShading.cc | 120 ++++++------ src/EnergyPlus/SteamBaseboardRadiator.cc | 6 +- src/EnergyPlus/SurfaceGeometry.cc | 104 +++++----- src/EnergyPlus/SwimmingPool.cc | 8 +- src/EnergyPlus/UFADManager.cc | 2 +- src/EnergyPlus/VentilatedSlab.cc | 6 +- src/EnergyPlus/WindowComplexManager.cc | 18 +- src/EnergyPlus/WindowManager.cc | 178 +++++++++--------- .../WindowManagerExteriorThermal.cc | 30 +-- src/EnergyPlus/ZoneTempPredictorCorrector.cc | 14 +- .../unit/DaylightingManager.unit.cc | 8 +- tst/EnergyPlus/unit/EMSManager.unit.cc | 8 +- .../unit/HeatBalanceSurfaceManager.unit.cc | 2 +- tst/EnergyPlus/unit/SurfaceGeometry.unit.cc | 6 +- 27 files changed, 391 insertions(+), 391 deletions(-) diff --git a/src/EnergyPlus/ChilledCeilingPanelSimple.cc b/src/EnergyPlus/ChilledCeilingPanelSimple.cc index 66aa2134cb0..36d6193fe23 100644 --- a/src/EnergyPlus/ChilledCeilingPanelSimple.cc +++ b/src/EnergyPlus/ChilledCeilingPanelSimple.cc @@ -1696,7 +1696,7 @@ namespace CoolingPanelSimple { using DataHeatBalance::HConvIn; using DataHeatBalance::Zone; using DataHeatBalSurface::TempSurfInTmp; - using DataSurfaces::WinShadingFlag; + using DataSurfaces::WinShadingType; using DataSurfaces::Surface; using DataSurfaces::SurfWinShadingFlag; using DataSurfaces::SurfWinFrameArea; diff --git a/src/EnergyPlus/ConvectionCoefficients.cc b/src/EnergyPlus/ConvectionCoefficients.cc index cfa00767983..055fc8dd492 100644 --- a/src/EnergyPlus/ConvectionCoefficients.cc +++ b/src/EnergyPlus/ConvectionCoefficients.cc @@ -398,7 +398,7 @@ namespace ConvectionCoefficients { if (!Surface(SurfNum).ExtWind) { SurfWindSpeed = 0.0; // No wind exposure - } else if (Surface(SurfNum).Class == SurfaceClass::Window && SurfWinShadingFlag(SurfNum) == WinShadingFlag::ExtShadeOn) { + } else if (Surface(SurfNum).Class == SurfaceClass::Window && SurfWinShadingFlag(SurfNum) == WinShadingType::ExtShade) { SurfWindSpeed = 0.0; // Assume zero wind speed at outside glass surface of window with exterior shade } else { SurfWindSpeed = Surface(SurfNum).WindSpeed; @@ -4709,7 +4709,7 @@ namespace ConvectionCoefficients { if (!Surface(SurfNum).ExtWind) { SurfWindSpeed = 0.0; // No wind exposure - } else if (Surface(SurfNum).Class == SurfaceClass::Window && SurfWinShadingFlag(SurfNum) == WinShadingFlag::ExtShadeOn) { + } else if (Surface(SurfNum).Class == SurfaceClass::Window && SurfWinShadingFlag(SurfNum) == WinShadingType::ExtShade) { SurfWindSpeed = 0.0; // Assume zero wind speed at outside glass surface of window with exterior shade } else { SurfWindSpeed = Surface(SurfNum).WindSpeed; diff --git a/src/EnergyPlus/DataSurfaces.cc b/src/EnergyPlus/DataSurfaces.cc index 044bcb7677e..22a75c3caf5 100644 --- a/src/EnergyPlus/DataSurfaces.cc +++ b/src/EnergyPlus/DataSurfaces.cc @@ -483,14 +483,14 @@ namespace DataSurfaces { Array1D SurfWinProfileAngHor; // Horizontal beam solar profile angle (degrees) Array1D SurfWinProfileAngVert; // Vertical beam solar profile angle (degrees) - Array1D SurfWinShadingFlag; // -1: window has no shading device + Array1D SurfWinShadingFlag; // -1: window has no shading device Array1D SurfWinShadingFlagEMSOn; // EMS control flag, true if EMS is controlling ShadingFlag with ShadingFlagEMSValue - Array1D SurfWinShadingFlagEMSValue; // EMS control value for Shading Flag + Array1D SurfWinShadingFlagEMSValue; // EMS control value for Shading Flag Array1D SurfWinGlareControlIsActive; // True if glare control is active Array1D SurfWinStormWinFlag; // -1: Storm window not applicable; 0: Window has storm window but it is off 1: Window has storm window and it is on Array1D SurfWinStormWinFlagPrevDay; // Previous time step value of StormWinFlag Array1D SurfWinFracTimeShadingDeviceOn; // For a single time step, = 0.0 if no shading device or shading device is off = 1.0 if shading device is on; For time intervals longer than a time step, = fraction of time that shading device is on. - Array1D SurfWinExtIntShadePrevTS; // 1 if exterior or interior blind or shade in place previous time step;0 otherwise + Array1D SurfWinExtIntShadePrevTS; // 1 if exterior or interior blind or shade in place previous time step;0 otherwise Array1D SurfWinHasShadeOrBlindLayer; // mark as true if the window construction has a shade or a blind layer Array1D SurfWinSurfDayLightInit; // surface has been initialized for following 5 arrays Array1D SurfWinDaylFacPoint; // Pointer to daylight factors for the window diff --git a/src/EnergyPlus/DataSurfaces.hh b/src/EnergyPlus/DataSurfaces.hh index cb523e2b6c1..532cb33d7ea 100644 --- a/src/EnergyPlus/DataSurfaces.hh +++ b/src/EnergyPlus/DataSurfaces.hh @@ -69,13 +69,13 @@ #define BITF(B) (1 << (int(B))) #define BITF_TEST_ANY(V, B) (((V) & (B)) != 0) -#define IS_SHADED(SHADE_FLAG) !BITF_TEST_ANY(BITF(SHADE_FLAG), BITF(WinShadingFlag::NoShade) | BITF(WinShadingFlag::ShadeOff)) -#define IS_SHADE_ON(SHADE_FLAG) BITF_TEST_ANY(BITF(SHADE_FLAG), BITF(WinShadingFlag::IntShadeOn) | BITF(WinShadingFlag::ExtShadeOn) | BITF(WinShadingFlag::BGShadeOn)) -#define IS_SHADE_SCREEN_ON(SHADE_FLAG) BITF_TEST_ANY(BITF(SHADE_FLAG), BITF(WinShadingFlag::IntShadeOn) | BITF(WinShadingFlag::ExtShadeOn) | BITF(WinShadingFlag::BGShadeOn) | BITF(WinShadingFlag::ExtScreenOn)) -#define IS_BLIND_ON(SHADE_FLAG) BITF_TEST_ANY(BITF(SHADE_FLAG), BITF(WinShadingFlag::IntBlindOn) | BITF(WinShadingFlag::ExtBlindOn) | BITF(WinShadingFlag::BGBlindOn)) -#define IS_INT_SHADED(SHADE_FLAG) BITF_TEST_ANY(BITF(SHADE_FLAG), BITF(WinShadingFlag::IntShadeOn) | BITF(WinShadingFlag::IntBlindOn)) -#define IS_EXT_SHADED(SHADE_FLAG) BITF_TEST_ANY(BITF(SHADE_FLAG), BITF(WinShadingFlag::ExtShadeOn) | BITF(WinShadingFlag::ExtBlindOn) | BITF(WinShadingFlag::ExtScreenOn)) -#define IS_BG_SHADED(SHADE_FLAG) BITF_TEST_ANY(BITF(SHADE_FLAG), BITF(WinShadingFlag::BGShadeOn) | BITF(WinShadingFlag::BGBlindOn)) +#define IS_SHADED(SHADE_FLAG) !BITF_TEST_ANY(BITF(SHADE_FLAG), BITF(WinShadingType::NoShade) | BITF(WinShadingType::ShadeOff)) +#define IS_SHADE_ON(SHADE_FLAG) BITF_TEST_ANY(BITF(SHADE_FLAG), BITF(WinShadingType::IntShade) | BITF(WinShadingType::ExtShade) | BITF(WinShadingType::BGShade)) +#define IS_SHADE_SCREEN_ON(SHADE_FLAG) BITF_TEST_ANY(BITF(SHADE_FLAG), BITF(WinShadingType::IntShade) | BITF(WinShadingType::ExtShade) | BITF(WinShadingType::BGShade) | BITF(WinShadingType::ExtScreen)) +#define IS_BLIND_ON(SHADE_FLAG) BITF_TEST_ANY(BITF(SHADE_FLAG), BITF(WinShadingType::IntBlind) | BITF(WinShadingType::ExtBlind) | BITF(WinShadingType::BGBlind)) +#define IS_INT_SHADED(SHADE_FLAG) BITF_TEST_ANY(BITF(SHADE_FLAG), BITF(WinShadingType::IntShade) | BITF(WinShadingType::IntBlind)) +#define IS_EXT_SHADED(SHADE_FLAG) BITF_TEST_ANY(BITF(SHADE_FLAG), BITF(WinShadingType::ExtShade) | BITF(WinShadingType::ExtBlind) | BITF(WinShadingType::ExtScreen)) +#define IS_BG_SHADED(SHADE_FLAG) BITF_TEST_ANY(BITF(SHADE_FLAG), BITF(WinShadingType::BGShade) | BITF(WinShadingType::BGBlind)) namespace EnergyPlus { @@ -134,16 +134,16 @@ namespace DataSurfaces { Count // The counter representing the total number of surface class, always stays at the bottom }; - enum class WinShadingFlag : int { + enum class WinShadingType : int { NoShade = 0, - IntShadeOn = 1, + IntShade = 1, SwitchableGlazing = 2, - ExtShadeOn = 3, - ExtScreenOn = 4, - IntBlindOn = 6, - ExtBlindOn = 7, - BGShadeOn = 8, - BGBlindOn = 9, + ExtShade = 3, + ExtScreen = 4, + IntBlind = 6, + ExtBlind = 7, + BGShade = 8, + BGBlind = 9, ShadeOff = 10 }; @@ -517,14 +517,14 @@ namespace DataSurfaces { extern Array1D SurfWinProfileAngHor; // Horizontal beam solar profile angle (degrees) extern Array1D SurfWinProfileAngVert; // Vertical beam solar profile angle (degrees) - extern Array1D SurfWinShadingFlag; // -1: window has no shading device + extern Array1D SurfWinShadingFlag; // -1: window has no shading device extern Array1D SurfWinShadingFlagEMSOn; // EMS control flag, true if EMS is controlling ShadingFlag with ShadingFlagEMSValue - extern Array1D SurfWinShadingFlagEMSValue; // EMS control value for Shading Flag + extern Array1D SurfWinShadingFlagEMSValue; // EMS control value for Shading Flag extern Array1D SurfWinGlareControlIsActive; // True if glare control is active extern Array1D SurfWinStormWinFlag; // -1: Storm window not applicable; 0: Window has storm window but it is off 1: Window has storm window and it is on extern Array1D SurfWinStormWinFlagPrevDay; // Previous time step value of StormWinFlag extern Array1D SurfWinFracTimeShadingDeviceOn; // For a single time step, = 0.0 if no shading device or shading device is off = 1.0 if shading device is on; For time intervals longer than a time step, = fraction of time that shading device is on. - extern Array1D SurfWinExtIntShadePrevTS; // 1 if exterior or interior blind or shade in place previous time step;0 otherwise + extern Array1D SurfWinExtIntShadePrevTS; // 1 if exterior or interior blind or shade in place previous time step;0 otherwise extern Array1D SurfWinHasShadeOrBlindLayer; // mark as true if the window construction has a shade or a blind layer extern Array1D SurfWinSurfDayLightInit; // surface has been initialized for following 5 arrays extern Array1D SurfWinDaylFacPoint; // Pointer to daylight factors for the window @@ -1102,7 +1102,7 @@ namespace DataSurfaces { std::string Name; // User supplied name of this set of shading control data int ZoneIndex; // number of the zone referenced int SequenceNumber; // Shading control sequence number - WinShadingFlag ShadingType; // Shading type (InteriorShade, SwitchableGlazing, + WinShadingType ShadingType; // Shading type (InteriorShade, SwitchableGlazing, // CHARACTER(len=32) :: ShadingType = ' ' ! Shading type (InteriorShade, SwitchableGlazing, // ExteriorShade,InteriorBlind,ExteriorBlind,BetweenGlassShade, // BetweenGlassBlind, or ExteriorScreen) @@ -1188,7 +1188,7 @@ namespace DataSurfaces { // Default Constructor WindowShadingControlData() - : ZoneIndex(0), SequenceNumber(0), ShadingType(WinShadingFlag::NoShade), getInputShadedConstruction(0), ShadingDevice(0), ShadingControlType(0), + : ZoneIndex(0), SequenceNumber(0), ShadingType(WinShadingType::NoShade), getInputShadedConstruction(0), ShadingDevice(0), ShadingControlType(0), Schedule(0), SetPoint(0.0), SetPoint2(0.0), ShadingControlIsScheduled(false), GlareControlIsActive(false), SlatAngleSchedule(0), SlatAngleControlForBlinds(0), DaylightControlIndex(0), MultiSurfaceCtrlIsGroup(false), FenestrationCount(0) { diff --git a/src/EnergyPlus/DaylightingManager.cc b/src/EnergyPlus/DaylightingManager.cc index 02d64fb3d44..909c4a2647a 100644 --- a/src/EnergyPlus/DaylightingManager.cc +++ b/src/EnergyPlus/DaylightingManager.cc @@ -863,7 +863,7 @@ namespace EnergyPlus::DaylightingManager { int IWin; // Window counter int IWin2; // Secondary window counter (for TDD:DOME object, if exists) int InShelfSurf; // Inside daylighting shelf surface number - WinShadingFlag ShType; // Window shading type + WinShadingType ShType; // Window shading type int BlNum; // Window Blind Number int LSHCAL; // Interior shade calculation flag: 0=not yet // calculated, 1=already calculated @@ -1262,7 +1262,7 @@ namespace EnergyPlus::DaylightingManager { int IWin; // Window counter int IWin2; // Secondary window counter (for TDD:DOME object, if exists) int InShelfSurf; // Inside daylighting shelf surface number - WinShadingFlag ShType; // Window shading type + WinShadingType ShType; // Window shading type int BlNum; // Window Blind Number int LSHCAL; // Interior shade calculation flag: 0=not yet // calculated, 1=already calculated @@ -1612,7 +1612,7 @@ namespace EnergyPlus::DaylightingManager { int &LSHCAL, // Interior shade calculation flag: 0=not yet calculated, 1=already calculated int &InShelfSurf, // Inside daylighting shelf surface number int &ICtrl, // Window control counter - WinShadingFlag &ShType, // Window shading type + WinShadingType &ShType, // Window shading type int &BlNum, // Window blind number Vector3 &WNORM2, // Unit vector normal to window DataDaylighting::iExtWinType &ExtWinType, // Exterior window type (InZoneExtWin, AdjZoneExtWin, NotInOrAdjZoneExtWin) @@ -1740,7 +1740,7 @@ namespace EnergyPlus::DaylightingManager { } ICtrl = Surface(IWin).activeWindowShadingControl; - ShType = WinShadingFlag::NoShade; // 'NOSHADE' + ShType = WinShadingType::NoShade; // 'NOSHADE' BlNum = 0; // ScNum = 0; //Unused Set but never used if (Surface(IWin).HasShadeControl) ShType = WindowShadingControl(ICtrl).ShadingType; @@ -1781,7 +1781,7 @@ namespace EnergyPlus::DaylightingManager { // incidence for fully switched (dark) state to that of unswitched state SurfWinVisTransRatio(IWin) = 1.0; if (ICtrl > 0) { - if (ShType == WinShadingFlag::SwitchableGlazing) { + if (ShType == WinShadingType::SwitchableGlazing) { IConstShaded = Surface(IWin).activeShadedConstruction; SurfWinVisTransRatio(IWin) = SafeDivide(POLYF(1.0, state.dataConstruction->Construct(IConstShaded).TransVisBeamCoef), POLYF(1.0, state.dataConstruction->Construct(IConst).TransVisBeamCoef)); @@ -3246,7 +3246,7 @@ namespace EnergyPlus::DaylightingManager { Real64 const TVISB, // Visible transmittance of window for COSB angle of incidence (times light well efficiency, if appropriate) Real64 const DOMEGA, // Solid angle subtended by window element wrt reference point (steradians) int const ICtrl, // Window control counter - WinShadingFlag const ShType, // Window shading type + WinShadingType const ShType, // Window shading type int const BlNum, // Window blind number Real64 const THRAY, // Azimuth of ray from reference point to window element (radians) Vector3 const &WNORM2, // Unit vector normal to window @@ -3675,7 +3675,7 @@ namespace EnergyPlus::DaylightingManager { state.dataDaylightingManager->EDIRSUdisk(iHour, 1) = RAYCOS(3) * TVISS * ObTransDisk; // Bare window TransBmBmMult = 0.0; - if (ShType == WinShadingFlag::ExtBlindOn || ShType == WinShadingFlag::IntBlindOn || ShType == WinShadingFlag::BGBlindOn) { + if (ShType == WinShadingType::ExtBlind || ShType == WinShadingType::IntBlind || ShType == WinShadingType::BGBlind) { ProfileAngle(IWin, RAYCOS, Blind(BlNum).SlatOrientation, ProfAng); // Contribution of beam passing through slats and reaching reference point for (JB = 1; JB <= MaxSlatAngs; ++JB) { @@ -3692,7 +3692,7 @@ namespace EnergyPlus::DaylightingManager { // do this only once for fixed slat blinds if (!SurfWinMovableSlats(IWin)) break; } - } else if (ShType == WinShadingFlag::ExtScreenOn) { + } else if (ShType == WinShadingType::ExtScreen) { // pass angle from sun to window normal here using PHSUN and THSUN from above and surface angles // SunAltitudeToWindowNormalAngle = PHSUN - SurfaceWindow(IWin)%Phi // SunAzimuthToWindowNormalAngle = THSUN - SurfaceWindow(IWin)%Theta @@ -3729,13 +3729,13 @@ namespace EnergyPlus::DaylightingManager { XAVWL = 14700.0 * std::sqrt(0.000068 * POSFAC) * double(NWX * NWY) / std::pow(WindowSolidAngleDaylightPoint, 0.8); state.dataDaylightingManager->AVWLSUdisk(iHour, 1) = XAVWL * TVISS * ObTransDisk; // Bare window - if (ShType == WinShadingFlag::ExtBlindOn || ShType == WinShadingFlag::IntBlindOn || ShType == WinShadingFlag::BGBlindOn) { + if (ShType == WinShadingType::ExtBlind || ShType == WinShadingType::IntBlind || ShType == WinShadingType::BGBlind) { for (JB = 1; JB <= MaxSlatAngs; ++JB) { // IF (.NOT. SurfaceWindow(IWin)%MovableSlats .AND. JB > 1) EXIT state.dataDaylightingManager->AVWLSUdisk(iHour, JB + 1) = XAVWL * TVISS * TransBmBmMult(JB) * ObTransDisk; if (!SurfWinMovableSlats(IWin)) break; } - } else if (ShType == WinShadingFlag::ExtScreenOn) { + } else if (ShType == WinShadingType::ExtScreen) { state.dataDaylightingManager->AVWLSUdisk(iHour, 2) = XAVWL * TVISS * TransBmBmMult(1) * ObTransDisk; } } // Position Factor @@ -3842,7 +3842,7 @@ namespace EnergyPlus::DaylightingManager { state.dataDaylightingManager->EDIRSUdisk(iHour, 1) += SunVecMir(3) * SpecReflectance * TVisRefl; // Bare window TransBmBmMultRefl = 0.0; - if (ShType == WinShadingFlag::ExtBlindOn || ShType == WinShadingFlag::IntBlindOn || ShType == WinShadingFlag::BGBlindOn) { + if (ShType == WinShadingType::ExtBlind || ShType == WinShadingType::IntBlind || ShType == WinShadingType::BGBlind) { ProfileAngle(IWin, SunVecMir, Blind(BlNum).SlatOrientation, ProfAng); // Contribution of reflected beam passing through slats and reaching reference point Real64 const Pi_SlatAng_fac(DataGlobalConstants::Pi / (MaxSlatAngs - 1)); @@ -3859,7 +3859,7 @@ namespace EnergyPlus::DaylightingManager { if (!SurfWinMovableSlats(IWin)) break; } - } else if (ShType == WinShadingFlag::ExtScreenOn) { + } else if (ShType == WinShadingType::ExtScreen) { // pass angle from sun to window normal here using PHSUN and THSUN from above and // surface angles SunAltitudeToWindowNormalAngle = PHSUN - SurfaceWindow(IWin)%Phi // SunAzimuthToWindowNormalAngle = THSUN - SurfaceWindow(IWin)%Theta @@ -3879,13 +3879,13 @@ namespace EnergyPlus::DaylightingManager { XAVWL = 14700.0 * std::sqrt(0.000068 * POSFAC) * double(NWX * NWY) / std::pow(SurfaceWindow(IWin).SolidAngAtRefPtWtd(iRefPoint), 0.8); state.dataDaylightingManager->AVWLSUdisk(iHour, 1) += XAVWL * TVisRefl * SpecReflectance; // Bare window - if (ShType == WinShadingFlag::ExtBlindOn || ShType == WinShadingFlag::IntBlindOn || ShType == WinShadingFlag::BGBlindOn) { + if (ShType == WinShadingType::ExtBlind || ShType == WinShadingType::IntBlind || ShType == WinShadingType::BGBlind) { for (JB = 1; JB <= MaxSlatAngs; ++JB) { // IF(.NOT. SurfaceWindow(IWin)%MovableSlats .AND. JB > 1) EXIT state.dataDaylightingManager->AVWLSUdisk(iHour, JB + 1) += XAVWL * TVisRefl * SpecReflectance * TransBmBmMultRefl(JB); if (!SurfWinMovableSlats(IWin)) break; } - } else if (ShType == WinShadingFlag::ExtScreenOn) { + } else if (ShType == WinShadingType::ExtScreen) { state.dataDaylightingManager->AVWLSUdisk(iHour, 2) += XAVWL * TVisRefl * SpecReflectance * TransBmBmMultRefl(1); } } @@ -3898,9 +3898,9 @@ namespace EnergyPlus::DaylightingManager { } // Last pass - if ((ICtrl > 0 && (ShType == WinShadingFlag::IntShadeOn || ShType == WinShadingFlag::ExtShadeOn || ShType == WinShadingFlag::BGShadeOn || - ShType == WinShadingFlag::IntBlindOn || ShType == WinShadingFlag::ExtBlindOn || ShType == WinShadingFlag::BGBlindOn || - ShType == WinShadingFlag::ExtScreenOn)) || + if ((ICtrl > 0 && (ShType == WinShadingType::IntShade || ShType == WinShadingType::ExtShade || ShType == WinShadingType::BGShade || + ShType == WinShadingType::IntBlind || ShType == WinShadingType::ExtBlind || ShType == WinShadingType::BGBlind || + ShType == WinShadingType::ExtScreen)) || SurfWinSolarDiffusing(IWin)) { // ----- CASE II -- WINDOW WITH SCREEN, SHADE, BLIND, OR DIFFUSING WINDOW @@ -4051,7 +4051,7 @@ namespace EnergyPlus::DaylightingManager { // For switchable glazing put daylighting factors for switched (dark) state in IS=2 location if (ICtrl > 0) { - if (WindowShadingControl(ICtrl).ShadingType == WinShadingFlag::SwitchableGlazing) { + if (WindowShadingControl(ICtrl).ShadingType == WinShadingType::SwitchableGlazing) { VTR = SurfWinVisTransRatio(IWin); state.dataDaylightingData->ZoneDaylight(ZoneNum).DaylIllFacSky(iHour, 2, ISky, iRefPoint, loopwin) = state.dataDaylightingData->ZoneDaylight(ZoneNum).DaylIllFacSky(iHour, 1, ISky, iRefPoint, loopwin) * VTR; @@ -4197,7 +4197,7 @@ namespace EnergyPlus::DaylightingManager { // For switchable glazing put daylighting factors for switched (dark) state in IS=2 location if (ICtrl > 0) { - if (WindowShadingControl(ICtrl).ShadingType == WinShadingFlag::SwitchableGlazing) { + if (WindowShadingControl(ICtrl).ShadingType == WinShadingType::SwitchableGlazing) { VTR = SurfWinVisTransRatio(IWin); state.dataDaylightingData->IllumMapCalc(MapNum).DaylIllFacSky(iHour, 2, ISky, iMapPoint, loopwin) = state.dataDaylightingData->IllumMapCalc(MapNum).DaylIllFacSky(iHour, 1, ISky, iMapPoint, loopwin) * VTR; @@ -6533,7 +6533,7 @@ namespace EnergyPlus::DaylightingManager { ICtrl = Surface(IWin).activeWindowShadingControl; if (Surface(IWin).HasShadeControl && ISWFLG == 0) { if (WindowShadingControl(ICtrl).ShadingControlType == WSCT_MeetDaylIlumSetp && - SurfWinShadingFlag(IWin) == WinShadingFlag::SwitchableGlazing && SurfWinGlareControlIsActive(IWin)) + SurfWinShadingFlag(IWin) == WinShadingType::SwitchableGlazing && SurfWinGlareControlIsActive(IWin)) ISWFLG = 1; } @@ -6586,7 +6586,7 @@ namespace EnergyPlus::DaylightingManager { ICtrl = Surface(IWin).activeWindowShadingControl; int IS = findWinShadingIndex(IWin); if (Surface(IWin).HasShadeControl) { - if (SurfWinShadingFlag(IWin) == WinShadingFlag::SwitchableGlazing && SurfWinGlareControlIsActive(IWin) && + if (SurfWinShadingFlag(IWin) == WinShadingType::SwitchableGlazing && SurfWinGlareControlIsActive(IWin) && WindowShadingControl(ICtrl).ShadingControlType == WSCT_MeetDaylIlumSetp && !previously_shaded(loop)) { DILLSW(igroup) += state.dataDaylightingData->ZoneDaylight(ZoneNum).IllumFromWinAtRefPt(loop, IS, 1); previously_shaded(loop) = true; @@ -6631,7 +6631,7 @@ namespace EnergyPlus::DaylightingManager { continueOuterLoop = true; continue; } - if ((SurfWinShadingFlag(IWin) != WinShadingFlag::SwitchableGlazing && !SurfWinGlareControlIsActive(IWin)) || + if ((SurfWinShadingFlag(IWin) != WinShadingType::SwitchableGlazing && !SurfWinGlareControlIsActive(IWin)) || WindowShadingControl(ICtrl).ShadingControlType != WSCT_MeetDaylIlumSetp) { continueOuterLoop = true; continue; @@ -6647,7 +6647,7 @@ namespace EnergyPlus::DaylightingManager { TVIS2(igroup) = POLYF(1.0, state.dataConstruction->Construct(IConstShaded).TransVisBeamCoef) * SurfWinGlazedFrac(IWin); // Reset shading flag to indicate that window is shaded by being partially or fully switched - SurfWinShadingFlag(IWin) = WinShadingFlag::SwitchableGlazing; + SurfWinShadingFlag(IWin) = WinShadingType::SwitchableGlazing; // ASETIL < 0 means illuminance from non-daylight-switchable windows exceeds setpoint, // so completely switch all daylight-switchable windows to minimize solar gain @@ -6676,7 +6676,7 @@ namespace EnergyPlus::DaylightingManager { state.dataDaylightingData->ZoneDaylight(ZoneNum).BacLum(IL) += (VTRAT - 1.0) * state.dataDaylightingData->ZoneDaylight(ZoneNum).BackLumFromWinAtRefPt(loop, IS, IL); // Adjust illum, background illum and source luminance for this window in intermediate switched state - // for later use in the DayltgGlare calc because SurfaceWindow(IWin)%ShadingFlag = WinShadingFlag::SwitchableGlazing = 2 + // for later use in the DayltgGlare calc because SurfaceWindow(IWin)%ShadingFlag = WinShadingType::SwitchableGlazing = 2 IS = 2; VTRAT = SurfWinVisTransSelected(IWin) / (TVIS2(igroup) + 0.000001); state.dataDaylightingData->ZoneDaylight(ZoneNum).IllumFromWinAtRefPt(loop, IS, IL) = VTRAT * tmpIllumFromWinAtRefPt(loop, IS, IL); @@ -6748,7 +6748,7 @@ namespace EnergyPlus::DaylightingManager { // Check if window is eligible for glare control // TH 1/21/2010. Switchable glazings already in partially switched state // should be allowed to further dim to control glare - if (!SurfWinGlareControlIsActive(IWin) && SurfWinShadingFlag(IWin) != WinShadingFlag::SwitchableGlazing) { + if (!SurfWinGlareControlIsActive(IWin) && SurfWinShadingFlag(IWin) != WinShadingType::SwitchableGlazing) { continueOuterLoop = false; continue; } @@ -6773,7 +6773,7 @@ namespace EnergyPlus::DaylightingManager { // Recalculate illuminance and glare with shading on this window. // For switchable glazings, this is the fully switched (dark) state for (int IL = 1; IL <= NREFPT; ++IL) { - if (SurfWinShadingFlag(IWin) != WinShadingFlag::SwitchableGlazing || SurfWinGlareControlIsActive(IWin)) { + if (SurfWinShadingFlag(IWin) != WinShadingType::SwitchableGlazing || SurfWinGlareControlIsActive(IWin)) { // for non switchable glazings or switchable glazings not switched yet (still in clear state) // SurfaceWindow(IWin)%ShadingFlag = WinShadingFlag::GlassConditionallyLightened RDAYIL(IL, igroup) = state.dataDaylightingManager->DaylIllum(IL) - WDAYIL(1, IL, igroup) + WDAYIL(2, IL, igroup); @@ -6785,13 +6785,13 @@ namespace EnergyPlus::DaylightingManager { } } - if (SurfWinShadingFlag(IWin) != WinShadingFlag::SwitchableGlazing || SurfWinGlareControlIsActive(IWin)) { + if (SurfWinShadingFlag(IWin) != WinShadingType::SwitchableGlazing || SurfWinGlareControlIsActive(IWin)) { SurfWinGlareControlIsActive(IWin) = false; } // For switchable glazings, it is switched to fully dark state, // update ZoneDaylight(ZoneNum)%SourceLumFromWinAtRefPt(IL,2,loop) for use in DayltgGlare - if (SurfWinShadingFlag(IWin) == WinShadingFlag::SwitchableGlazing) { + if (SurfWinShadingFlag(IWin) == WinShadingType::SwitchableGlazing) { for (int IL = 1; IL <= NREFPT; ++IL) { state.dataDaylightingData->ZoneDaylight(ZoneNum).SourceLumFromWinAtRefPt(loop, 2, IL) = tmpSourceLumFromWinAtRefPt(loop, 2, IL); state.dataDaylightingData->ZoneDaylight(ZoneNum).IllumFromWinAtRefPt(loop, 2, IL) = tmpIllumFromWinAtRefPt(loop, 2, IL); @@ -6862,7 +6862,7 @@ namespace EnergyPlus::DaylightingManager { // need to map back to the original order of the "loop" to not change all the other data structures loop = state.dataDaylightingData->ZoneDaylight(ZoneNum).MapShdOrdToLoopNum(count); - if (SurfWinShadingFlag(IWin) != WinShadingFlag::SwitchableGlazing) continue; + if (SurfWinShadingFlag(IWin) != WinShadingType::SwitchableGlazing) continue; ICtrl = Surface(IWin).activeWindowShadingControl; if (!Surface(IWin).HasShadeControl) continue; @@ -6872,7 +6872,7 @@ namespace EnergyPlus::DaylightingManager { // Reset shading flag to no shading condition, go to next window. if (blnCycle) { // for switchable glazings, reset properties to clear state or partial switched state? - if (SurfWinShadingFlag(IWin) == WinShadingFlag::SwitchableGlazing) { + if (SurfWinShadingFlag(IWin) == WinShadingType::SwitchableGlazing) { SurfWinSwitchingFactor(IWin) = 0.0; SurfWinVisTransSelected(IWin) = TVIS1(igroup); @@ -6884,7 +6884,7 @@ namespace EnergyPlus::DaylightingManager { } } - SurfWinShadingFlag(IWin) = WinShadingFlag::ShadeOff; + SurfWinShadingFlag(IWin) = WinShadingType::ShadeOff; SurfWinGlareControlIsActive(IWin) = false; continue; } @@ -6906,7 +6906,7 @@ namespace EnergyPlus::DaylightingManager { // This was addressed in CR 7984 for E+ 5.0. 1/19/2010 // If switchable glazing, set switching factor to 1: fully switched. - if (SurfWinShadingFlag(IWin) == WinShadingFlag::SwitchableGlazing) { + if (SurfWinShadingFlag(IWin) == WinShadingType::SwitchableGlazing) { // tmpSWFactor0 = SurfaceWindow( IWin ).SwitchingFactor; // save original // switching factor ////Unused Set but never used @@ -6933,7 +6933,7 @@ namespace EnergyPlus::DaylightingManager { } if (GlareOK) { - if (SurfWinShadingFlag(IWin) == WinShadingFlag::SwitchableGlazing && + if (SurfWinShadingFlag(IWin) == WinShadingType::SwitchableGlazing && WindowShadingControl(ICtrl).ShadingControlType == WSCT_MeetDaylIlumSetp) { // Added TH 1/14/2010 // Only for switchable glazings with MeetDaylightIlluminanceSetpoint control @@ -7046,7 +7046,7 @@ namespace EnergyPlus::DaylightingManager { if (Surface(IWin).Class != SurfaceClass::Window) continue; if (Surface(IWin).ExtBoundCond != ExternalEnvironment) continue; if (SurfWinGlareControlIsActive(IWin)) { - SurfWinShadingFlag(IWin) = WinShadingFlag::ShadeOff; + SurfWinShadingFlag(IWin) = WinShadingType::ShadeOff; SurfWinGlareControlIsActive(IWin) = false; } } @@ -7617,7 +7617,7 @@ namespace EnergyPlus::DaylightingManager { int IntWinNum; // window index for interior windows associated with exterior windows Real64 COSBintWin; - WinShadingFlag ShType; + WinShadingType ShType; ZoneNumThisWin = Surface(Surface(IWin).BaseSurf).Zone; // The inside surface area, ZoneDaylight(ZoneNum)%TotInsSurfArea was calculated in subr DayltgAveInteriorReflectance @@ -7940,9 +7940,9 @@ namespace EnergyPlus::DaylightingManager { BlNum = SurfWinBlindNumber(IWin); // ScNum = SurfaceWindow( IWin ).ScreenNumber; //Unused Set but never used - ShadeOn = (ShType == WinShadingFlag::IntShadeOn || ShType == WinShadingFlag::ExtShadeOn || ShType == WinShadingFlag::BGShadeOn); - BlindOn = (ShType == WinShadingFlag::IntBlindOn || ShType == WinShadingFlag::ExtBlindOn || ShType == WinShadingFlag::BGBlindOn); - ScreenOn = (ShType == WinShadingFlag::ExtScreenOn); + ShadeOn = (ShType == WinShadingType::IntShade || ShType == WinShadingType::ExtShade || ShType == WinShadingType::BGShade); + BlindOn = (ShType == WinShadingType::IntBlind || ShType == WinShadingType::ExtBlind || ShType == WinShadingType::BGBlind); + ScreenOn = (ShType == WinShadingType::ExtScreen); } if (ShadeOn || BlindOn || ScreenOn || SurfWinSolarDiffusing(IWin)) { @@ -8004,7 +8004,7 @@ namespace EnergyPlus::DaylightingManager { TransBlBmDiffFront = InterpProfAng(ProfAng, Blind(BlNum).VisFrontBeamDiffTrans(JB, {1, 37})); - if (ShType == WinShadingFlag::IntBlindOn) { // Interior blind + if (ShType == WinShadingType::IntBlind) { // Interior blind ReflGlDiffDiffBack = state.dataConstruction->Construct(IConst).ReflectVisDiffBack; ReflBlBmDiffFront = InterpProfAng(ProfAng, Blind(BlNum).VisFrontBeamDiffRefl(JB, {1, 37})); ReflBlDiffDiffFront = Blind(BlNum).VisFrontDiffDiffRefl(JB); @@ -8012,7 +8012,7 @@ namespace EnergyPlus::DaylightingManager { TransMult(JB) = TVISBR * (TransBlBmDiffFront + ReflBlBmDiffFront * ReflGlDiffDiffBack * TransBlDiffDiffFront / (1.0 - ReflBlDiffDiffFront * ReflGlDiffDiffBack)); - } else if (ShType == WinShadingFlag::ExtBlindOn) { // Exterior blind + } else if (ShType == WinShadingType::ExtBlind) { // Exterior blind ReflGlDiffDiffFront = state.dataConstruction->Construct(IConst).ReflectVisDiffFront; ReflBlDiffDiffBack = Blind(BlNum).VisBackDiffDiffRefl(JB); TransMult(JB) = TransBlBmDiffFront * SurfWinGlazedFrac(IWin) * state.dataConstruction->Construct(IConst).TransDiffVis / @@ -8211,7 +8211,7 @@ namespace EnergyPlus::DaylightingManager { TransBlBmDiffFront = InterpProfAng(ProfAng, Blind(BlNum).VisFrontBeamDiffTrans(JB, {1, 37})); - if (ShType == WinShadingFlag::IntBlindOn) { // Interior blind + if (ShType == WinShadingType::IntBlind) { // Interior blind // TH CR 8121, 7/7/2010 // ReflBlBmDiffFront = InterpProfAng(ProfAng,Blind(BlNum)%VisFrontBeamDiffRefl) ReflBlBmDiffFront = InterpProfAng(ProfAng, Blind(BlNum).VisFrontBeamDiffRefl(JB, {1, 37})); @@ -8223,7 +8223,7 @@ namespace EnergyPlus::DaylightingManager { TransMult(JB) = TVISBSun * (TransBlBmDiffFront + ReflBlBmDiffFront * ReflGlDiffDiffBack * TransBlDiffDiffFront / (1.0 - ReflBlDiffDiffFront * ReflGlDiffDiffBack)); - } else if (ShType == WinShadingFlag::ExtBlindOn) { // Exterior blind + } else if (ShType == WinShadingType::ExtBlind) { // Exterior blind TransMult(JB) = TransBlBmDiffFront * (state.dataConstruction->Construct(IConst).TransDiffVis / (1.0 - ReflGlDiffDiffFront * Blind(BlNum).VisBackDiffDiffRefl(JB))) * @@ -8313,13 +8313,13 @@ namespace EnergyPlus::DaylightingManager { } else { // Blind on TransBlDiffDiffFront = Blind(BlNum).VisFrontDiffDiffTrans(JB); - if (ShType == WinShadingFlag::IntBlindOn) { // Interior blind + if (ShType == WinShadingType::IntBlind) { // Interior blind ReflBlDiffDiffFront = Blind(BlNum).VisFrontDiffDiffRefl(JB); TransMult(JB) = TVisSunRefl * (TransBlDiffDiffFront + ReflBlDiffDiffFront * ReflGlDiffDiffBack * TransBlDiffDiffFront / (1.0 - ReflBlDiffDiffFront * ReflGlDiffDiffBack)); - } else if (ShType == WinShadingFlag::ExtBlindOn) { // Exterior blind + } else if (ShType == WinShadingType::ExtBlind) { // Exterior blind TransMult(JB) = TransBlDiffDiffFront * (state.dataConstruction->Construct(IConst).TransDiffVis / (1.0 - ReflGlDiffDiffFront * Blind(BlNum).VisBackDiffDiffRefl(JB))) * @@ -9736,7 +9736,7 @@ namespace EnergyPlus::DaylightingManager { ICtrl = Surface(IWin).activeWindowShadingControl; if (Surface(IWin).HasShadeControl) { if (WindowShadingControl(ICtrl).ShadingControlType == WSCT_MeetDaylIlumSetp && - SurfWinShadingFlag(IWin) == WinShadingFlag::SwitchableGlazing) { + SurfWinShadingFlag(IWin) == WinShadingType::SwitchableGlazing) { // switchable windows in partial or fully switched state, // get its intermediate VT calculated in DayltgInteriorIllum IConstShaded = Surface(IWin).activeShadedConstruction; @@ -9770,7 +9770,7 @@ namespace EnergyPlus::DaylightingManager { ICtrl = Surface(IWin).activeWindowShadingControl; if (Surface(IWin).HasShadeControl) { if (WindowShadingControl(ICtrl).ShadingControlType == WSCT_MeetDaylIlumSetp && - SurfWinShadingFlag(IWin) == WinShadingFlag::SwitchableGlazing) { + SurfWinShadingFlag(IWin) == WinShadingType::SwitchableGlazing) { // switchable windows in partial or fully switched state, // get its intermediate VT calculated in DayltgInteriorIllum IConstShaded = Surface(IWin).activeShadedConstruction; diff --git a/src/EnergyPlus/DaylightingManager.hh b/src/EnergyPlus/DaylightingManager.hh index b4955b77a22..0235d158240 100644 --- a/src/EnergyPlus/DaylightingManager.hh +++ b/src/EnergyPlus/DaylightingManager.hh @@ -110,7 +110,7 @@ namespace DaylightingManager { int &LSHCAL, // Interior shade calculation flag: 0=not yet calculated, 1=already calculated int &InShelfSurf, // Inside daylighting shelf surface number int &ICtrl, // Window control counter - DataSurfaces::WinShadingFlag &ShType, // Window shading type + DataSurfaces::WinShadingType &ShType, // Window shading type int &BlNum, // Window blind number Vector3 &WNORM2, // Unit vector normal to window DataDaylighting::iExtWinType &ExtWinType, // Exterior window type (InZoneExtWin, AdjZoneExtWin, NotInOrAdjZoneExtWin) @@ -257,7 +257,7 @@ namespace DaylightingManager { Real64 const TVISB, // Visible transmittance of window for COSB angle of incidence (times light well efficiency, if appropriate) Real64 const DOMEGA, // Solid angle subtended by window element wrt reference point (steradians) int const ICtrl, // Window control counter - DataSurfaces::WinShadingFlag const ShType, // Window shading type + DataSurfaces::WinShadingType const ShType, // Window shading type int const BlNum, // Window blind number Real64 const THRAY, // Azimuth of ray from reference point to window element (radians) Vector3 const &WNORM2, // Unit vector normal to window diff --git a/src/EnergyPlus/EMSManager.cc b/src/EnergyPlus/EMSManager.cc index 8d3047b7a3e..2ca54ac3eb9 100644 --- a/src/EnergyPlus/EMSManager.cc +++ b/src/EnergyPlus/EMSManager.cc @@ -1861,7 +1861,7 @@ namespace EMSManager { using DataSurfaces::Surface; using DataSurfaces::TotSurfaces; using DataSurfaces::WindowShadingControl; - using DataSurfaces::WinShadingFlag; + using DataSurfaces::WinShadingType; // Locals // SUBROUTINE ARGUMENT DEFINITIONS: @@ -1900,7 +1900,7 @@ namespace EMSManager { DataSurfaces::SurfWinSlatAngThisTSDegEMSon(loopSurfNum), DataSurfaces::SurfWinSlatAngThisTSDegEMSValue(loopSurfNum)); } - } else if (WindowShadingControl(Surface(loopSurfNum).activeWindowShadingControl).ShadingType == WinShadingFlag::ExtScreenOn) { + } else if (WindowShadingControl(Surface(loopSurfNum).activeWindowShadingControl).ShadingType == WinShadingType::ExtScreen) { SetupEMSActuator(state, "Window Shading Control", Surface(loopSurfNum).Name, "Control Status", @@ -1908,7 +1908,7 @@ namespace EMSManager { DataSurfaces::SurfWinShadingFlagEMSOn(loopSurfNum), (int &)DataSurfaces::SurfWinShadingFlagEMSValue(loopSurfNum)); } else { - if (WindowShadingControl(Surface(loopSurfNum).activeWindowShadingControl).ShadingType != WinShadingFlag::SwitchableGlazing) { + if (WindowShadingControl(Surface(loopSurfNum).activeWindowShadingControl).ShadingType != WinShadingType::SwitchableGlazing) { ShowSevereError(state, "Missing shade or blind layer in window construction name = '" + state.dataConstruction->Construct(Surface(loopSurfNum).activeShadedConstruction).Name + "', surface name = '" + Surface(loopSurfNum).Name + "'."); diff --git a/src/EnergyPlus/HWBaseboardRadiator.cc b/src/EnergyPlus/HWBaseboardRadiator.cc index 9fcb283ce2c..50aacbd9610 100644 --- a/src/EnergyPlus/HWBaseboardRadiator.cc +++ b/src/EnergyPlus/HWBaseboardRadiator.cc @@ -1735,7 +1735,7 @@ namespace HWBaseboardRadiator { Area = Surface(SurfNum).Area; if (Surface(SurfNum).Class == SurfaceClass::Window) { - if (SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntShadeOn || SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntBlindOn) { + if (SurfWinShadingFlag(SurfNum) == WinShadingType::IntShade || SurfWinShadingFlag(SurfNum) == WinShadingType::IntBlind) { // The area is the shade or blind area = the sum of the glazing area and the divider area (which is zero if no divider) Area += SurfWinDividerArea(SurfNum); } @@ -1746,8 +1746,8 @@ namespace HWBaseboardRadiator { SurfWinFrameTempSurfIn(SurfNum); } - if (SurfWinDividerArea(SurfNum) > 0.0 && SurfWinShadingFlag(SurfNum) != WinShadingFlag::IntShadeOn && - SurfWinShadingFlag(SurfNum) != WinShadingFlag::IntBlindOn) { + if (SurfWinDividerArea(SurfNum) > 0.0 && SurfWinShadingFlag(SurfNum) != WinShadingType::IntShade && + SurfWinShadingFlag(SurfNum) != WinShadingType::IntBlind) { // Window divider contribution (only from shade or blind for window with divider and interior shade or blind) SumHATsurf += HConvIn(SurfNum) * SurfWinDividerArea(SurfNum) * (1.0 + 2.0 * SurfWinProjCorrDivIn(SurfNum)) * SurfWinDividerTempSurfIn(SurfNum); diff --git a/src/EnergyPlus/HeatBalanceIntRadExchange.cc b/src/EnergyPlus/HeatBalanceIntRadExchange.cc index 14f9511ccd0..185b878215b 100644 --- a/src/EnergyPlus/HeatBalanceIntRadExchange.cc +++ b/src/EnergyPlus/HeatBalanceIntRadExchange.cc @@ -171,8 +171,8 @@ namespace HeatBalanceIntRadExchange { bool IntShadeOrBlindStatusChanged; // True if status of interior shade or blind on at least // one window in a zone has changed from previous time step - WinShadingFlag ShadeFlag; // Window shading status current time step - WinShadingFlag ShadeFlagPrev; // Window shading status previous time step + WinShadingType ShadeFlag; // Window shading status current time step + WinShadingType ShadeFlagPrev; // Window shading status previous time step // variables added as part of strategy to reduce calculation time - Glazer 2011-04-22 static Array1D SurfaceTempRad; @@ -271,9 +271,9 @@ namespace HeatBalanceIntRadExchange { if (state.dataConstruction->Construct(Surface(SurfNum).Construction).TypeIsWindow) { ShadeFlag = SurfWinShadingFlag(SurfNum); ShadeFlagPrev = SurfWinExtIntShadePrevTS(SurfNum); - if ((ShadeFlagPrev != WinShadingFlag::IntShadeOn && ShadeFlag == WinShadingFlag::IntShadeOn) || - (ShadeFlagPrev != WinShadingFlag::IntBlindOn && ShadeFlag == WinShadingFlag::IntBlindOn) || - (ShadeFlagPrev == WinShadingFlag::IntShadeOn && ShadeFlag != WinShadingFlag::IntShadeOn) || (ShadeFlagPrev == WinShadingFlag::IntBlindOn && ShadeFlag != WinShadingFlag::IntBlindOn)) + if ((ShadeFlagPrev != WinShadingType::IntShade && ShadeFlag == WinShadingType::IntShade) || + (ShadeFlagPrev != WinShadingType::IntBlind && ShadeFlag == WinShadingType::IntBlind) || + (ShadeFlagPrev == WinShadingType::IntShade && ShadeFlag != WinShadingType::IntShade) || (ShadeFlagPrev == WinShadingType::IntBlind && ShadeFlag != WinShadingType::IntBlind)) IntShadeOrBlindStatusChanged = true; if (SurfWinWindowModelType(SurfNum) == WindowEQLModel && DataWindowEquivalentLayer::CFS(state.dataConstruction->Construct(Surface(SurfNum).Construction).EQLConsPtr).ISControlled) { @@ -292,7 +292,7 @@ namespace HeatBalanceIntRadExchange { zone_info.Emissivity(ZoneSurfNum) = state.dataConstruction->Construct(ConstrNum).InsideAbsorpThermal; auto const &surface_window(SurfaceWindow(SurfNum)); if (state.dataConstruction->Construct(ConstrNum).TypeIsWindow && - (SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntShadeOn || SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntBlindOn)) { + (SurfWinShadingFlag(SurfNum) == WinShadingType::IntShade || SurfWinShadingFlag(SurfNum) == WinShadingType::IntBlind)) { zone_info.Emissivity(ZoneSurfNum) = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), surface_window.EffShBlindEmiss) + InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), surface_window.EffGlassEmiss); @@ -331,14 +331,14 @@ namespace HeatBalanceIntRadExchange { if (construct.WindowTypeEQL) { SurfaceTempRad[ZoneSurfNum] = SurfWinEffInsSurfTemp(SurfNum); SurfaceEmiss[ZoneSurfNum] = EQLWindowInsideEffectiveEmiss(state, ConstrNum); - } else if (construct.WindowTypeBSDF && SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntShadeOn) { + } else if (construct.WindowTypeBSDF && SurfWinShadingFlag(SurfNum) == WinShadingType::IntShade) { SurfaceTempRad[ZoneSurfNum] = SurfWinEffInsSurfTemp(SurfNum); SurfaceEmiss[ZoneSurfNum] = surface_window.EffShBlindEmiss[0] + surface_window.EffGlassEmiss[0]; } else if (construct.WindowTypeBSDF) { SurfaceTempRad[ZoneSurfNum] = SurfWinEffInsSurfTemp(SurfNum); SurfaceEmiss[ZoneSurfNum] = construct.InsideAbsorpThermal; } else if (construct.TypeIsWindow && SurfWinOriginalClass(SurfNum) != SurfaceClass::TDD_Diffuser) { - if (SurfIterations == 0 && (SurfWinShadingFlag(SurfNum) == WinShadingFlag::NoShade || SurfWinShadingFlag(SurfNum) == WinShadingFlag::ShadeOff)) { + if (SurfIterations == 0 && (SurfWinShadingFlag(SurfNum) == WinShadingType::NoShade || SurfWinShadingFlag(SurfNum) == WinShadingType::ShadeOff)) { // If the window is bare this TS and it is the first time through we use the previous TS glass // temperature whether or not the window was shaded in the previous TS. If the window was shaded // the previous time step this temperature is a better starting value than the shade temperature. @@ -346,7 +346,7 @@ namespace HeatBalanceIntRadExchange { SurfaceEmiss[ZoneSurfNum] = construct.InsideAbsorpThermal; // For windows with an interior shade or blind an effective inside surface temp // and emiss is used here that is a weighted combination of shade/blind and glass temp and emiss. - } else if (SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntShadeOn || SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntBlindOn) { + } else if (SurfWinShadingFlag(SurfNum) == WinShadingType::IntShade || SurfWinShadingFlag(SurfNum) == WinShadingType::IntBlind) { SurfaceTempRad[ZoneSurfNum] = SurfWinEffInsSurfTemp(SurfNum); SurfaceEmiss[ZoneSurfNum] = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), surface_window.EffShBlindEmiss) + InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), surface_window.EffGlassEmiss); diff --git a/src/EnergyPlus/HeatBalanceSurfaceManager.cc b/src/EnergyPlus/HeatBalanceSurfaceManager.cc index 152ccae756e..403af6d915a 100644 --- a/src/EnergyPlus/HeatBalanceSurfaceManager.cc +++ b/src/EnergyPlus/HeatBalanceSurfaceManager.cc @@ -1052,23 +1052,23 @@ namespace HeatBalanceSurfaceManager { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscName, surfName, WindowShadingControl(curWSC).Name); { auto const SELECT_CASE_var1(WindowShadingControl(curWSC).ShadingType); - if (SELECT_CASE_var1 == WinShadingFlag::NoShade) { + if (SELECT_CASE_var1 == WinShadingType::NoShade) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscShading, surfName, "No Shade"); - } else if (SELECT_CASE_var1 == WinShadingFlag::IntShadeOn) { + } else if (SELECT_CASE_var1 == WinShadingType::IntShade) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscShading, surfName, "Interior Shade"); - } else if (SELECT_CASE_var1 == WinShadingFlag::SwitchableGlazing) { + } else if (SELECT_CASE_var1 == WinShadingType::SwitchableGlazing) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscShading, surfName, "Switchable Glazing"); - } else if (SELECT_CASE_var1 == WinShadingFlag::ExtShadeOn) { + } else if (SELECT_CASE_var1 == WinShadingType::ExtShade) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscShading, surfName, "Exterior Shade"); - } else if (SELECT_CASE_var1 == WinShadingFlag::IntBlindOn) { + } else if (SELECT_CASE_var1 == WinShadingType::IntBlind) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscShading, surfName, "Interior Blind"); - } else if (SELECT_CASE_var1 == WinShadingFlag::ExtBlindOn) { + } else if (SELECT_CASE_var1 == WinShadingType::ExtBlind) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscShading, surfName, "Exterior Blind"); - } else if (SELECT_CASE_var1 == WinShadingFlag::BGShadeOn) { + } else if (SELECT_CASE_var1 == WinShadingType::BGShade) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscShading, surfName, "Between Glass Shade"); - } else if (SELECT_CASE_var1 == WinShadingFlag::BGBlindOn) { + } else if (SELECT_CASE_var1 == WinShadingType::BGBlind) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscShading, surfName, "Between Glass Blind"); - } else if (SELECT_CASE_var1 == WinShadingFlag::ExtScreenOn) { + } else if (SELECT_CASE_var1 == WinShadingType::ExtScreen) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscShading, surfName, "Exterior Screen"); } } @@ -2192,8 +2192,8 @@ namespace HeatBalanceSurfaceManager { SurfWinDividerTempSurfOut(SurfNum) = 23.0; // Initialize previous-timestep shading indicators - SurfWinExtIntShadePrevTS(SurfNum) = WinShadingFlag::NoShade; - SurfWinShadingFlag(SurfNum) = WinShadingFlag::NoShade; + SurfWinExtIntShadePrevTS(SurfNum) = WinShadingType::NoShade; + SurfWinShadingFlag(SurfNum) = WinShadingType::NoShade; } // end of Zone Surf } } // end of Zone @@ -2875,7 +2875,7 @@ namespace HeatBalanceSurfaceManager { Real64 SkySolarInc = currSkySolarInc(SurfNum); // Sky diffuse solar incident on a surface Real64 GndSolarInc = currGndSolarInc(SurfNum); // Ground diffuse solar incident on a surface - WinShadingFlag ShadeFlag = SurfWinShadingFlag(SurfNum); + WinShadingType ShadeFlag = SurfWinShadingFlag(SurfNum); if (SurfWinWindowModelType(SurfNum) == Window5DetailedModel && !state.dataWindowManager->inExtWindowModel->isExternalLibraryModel()) { int TotGlassLay = state.dataConstruction->Construct(ConstrNum).TotGlassLayers; // Number of glass layers @@ -2938,7 +2938,7 @@ namespace HeatBalanceSurfaceManager { if (IS_INT_SHADED(ShadeFlag) && SurfWinDividerArea(SurfNum) > 0.0) SurfWinExtDiffAbsByShade(SurfNum) *= SurfWinGlazedFrac(SurfNum); - if (ShadeFlag == WinShadingFlag::SwitchableGlazing) { // Switchable glazing + if (ShadeFlag == WinShadingType::SwitchableGlazing) { // Switchable glazing Real64 SwitchFac = SurfWinSwitchingFactor( SurfNum); // Switching factor for switchable glazing for (int Lay = 1; Lay <= TotGlassLay; ++Lay) { @@ -3156,7 +3156,7 @@ namespace HeatBalanceSurfaceManager { Real64 TransGl = POLYF(CosInc, state.dataConstruction->Construct( ConstrNum).TransSolBeamCoef); TransDiffGl = state.dataConstruction->Construct(ConstrNum).TransDiff; - if (ShadeFlag == WinShadingFlag::SwitchableGlazing) { // Switchable glazing + if (ShadeFlag == WinShadingType::SwitchableGlazing) { // Switchable glazing Real64 SwitchFac = SurfWinSwitchingFactor(SurfNum); int ConstrNumSh = Surface(SurfNum).activeShadedConstruction; Real64 TransGlSh = POLYF(CosInc, state.dataConstruction->Construct( @@ -3210,7 +3210,7 @@ namespace HeatBalanceSurfaceManager { Real64 AbsGl = 1.0 - TransGl - ReflGl; Real64 SwitchFac = SurfWinSwitchingFactor(SurfNum); int ConstrNumSh = Surface(SurfNum).activeShadedConstruction; - if (ShadeFlag == WinShadingFlag::SwitchableGlazing) { // Switchable glazing + if (ShadeFlag == WinShadingType::SwitchableGlazing) { // Switchable glazing Real64 MatNumGlSh = state.dataConstruction->Construct( ConstrNumSh).LayerPoint(1); Real64 TransGlSh = state.dataMaterial->Material(MatNumGlSh).Trans; @@ -3255,7 +3255,7 @@ namespace HeatBalanceSurfaceManager { ConstrNum).TransSolBeamCoef); Real64 TransDiffGl = state.dataConstruction->Construct( ConstrNum).TransDiff; // Diffuse solar transmittance - if (ShadeFlag == WinShadingFlag::SwitchableGlazing) { // Switchable glazing + if (ShadeFlag == WinShadingType::SwitchableGlazing) { // Switchable glazing Real64 SwitchFac = SurfWinSwitchingFactor(SurfNum); int ConstrNumSh = Surface(SurfNum).activeShadedConstruction; Real64 TransGlSh = POLYF(CosInc, state.dataConstruction->Construct( @@ -3306,7 +3306,7 @@ namespace HeatBalanceSurfaceManager { SurfWinDividerQRadInAbs(SurfNum) = DividerAbs * (DivIncSolarInBm + DivIncSolarInDif); // Exterior shade, screen or blind - } else if (ShadeFlag == WinShadingFlag::ExtBlindOn) { // Exterior blind + } else if (ShadeFlag == WinShadingType::ExtBlind) { // Exterior blind int BlNum = SurfWinBlindNumber(SurfNum); Real64 ProfAng; // Solar profile angle (rad) ProfileAngle(SurfNum, state.dataEnvrn->SOLCOS, Blind(BlNum).SlatOrientation, ProfAng); @@ -3329,7 +3329,7 @@ namespace HeatBalanceSurfaceManager { DivIncSolarInDif * InterpSlatAng(SlatAng, SurfWinMovableSlats(SurfNum), Blind(BlNum).SolFrontDiffDiffTrans)); - } else if (ShadeFlag == WinShadingFlag::ExtShadeOn) { // Exterior shade + } else if (ShadeFlag == WinShadingType::ExtShade) { // Exterior shade int ConstrNumSh = Surface(SurfNum).activeShadedConstruction; SurfWinDividerQRadOutAbs(SurfNum) = DividerAbs * state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNumSh).LayerPoint(1)).Trans * @@ -3338,7 +3338,7 @@ namespace HeatBalanceSurfaceManager { DividerAbs * state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNumSh).LayerPoint(1)).Trans * (DivIncSolarInBm +DivIncSolarInDif); - } else if (ShadeFlag == WinShadingFlag::ExtScreenOn) { // Exterior screen + } else if (ShadeFlag == WinShadingType::ExtScreen) { // Exterior screen SurfWinDividerQRadOutAbs(SurfNum) = DividerAbs * (SurfaceScreens( SurfWinScreenNumber(SurfNum)).BmBmTrans + SurfaceScreens( SurfWinScreenNumber(SurfNum)).BmDifTrans) * @@ -3552,7 +3552,7 @@ namespace HeatBalanceSurfaceManager { ConstrNumSh = Surface(SurfNum).activeStormWinShadedConstruction; } int TotGlassLayers = state.dataConstruction->Construct(ConstrNum).TotGlassLayers; - WinShadingFlag ShadeFlag = SurfWinShadingFlag(SurfNum); + WinShadingType ShadeFlag = SurfWinShadingFlag(SurfNum); // These calculations are repeated from InitInternalHeatGains for the Zone Component Loads Report Real64 pulseMultipler = 0.01; // use to create a pulse for the load component report computations, the W/sqft pulse for the zone @@ -3575,20 +3575,20 @@ namespace HeatBalanceSurfaceManager { SurfWinQRadSWwinAbs(IGlass, SurfNum) += QS(solEnclosureNum) * state.dataConstruction->Construct(ConstrNum).AbsDiffBack(IGlass); } - } else if (ConstrNumSh != 0 && ShadeFlag != WinShadingFlag::SwitchableGlazing) { + } else if (ConstrNumSh != 0 && ShadeFlag != WinShadingType::SwitchableGlazing) { // Interior, exterior or between-glass shade, screen or blind in place for (int IGlass = 1; IGlass <= state.dataConstruction->Construct(ConstrNumSh).TotGlassLayers; ++IGlass) { if (IS_SHADE_SCREEN_ON(ShadeFlag)) { SurfWinQRadSWwinAbs(IGlass, SurfNum) += QS(solEnclosureNum) * state.dataConstruction->Construct(ConstrNumSh).AbsDiffBack(IGlass); - } else if (BITF_TEST_ANY(BITF(ShadeFlag), BITF(WinShadingFlag::IntBlindOn) | BITF(WinShadingFlag::ExtBlindOn))) { + } else if (BITF_TEST_ANY(BITF(ShadeFlag), BITF(WinShadingType::IntBlind) | BITF(WinShadingType::ExtBlind))) { Real64 BlAbsDiffBk = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), state.dataConstruction->Construct(ConstrNumSh).BlAbsDiffBack(_, IGlass)); // Glass layer back diffuse solar absorptance when blind in place SurfWinQRadSWwinAbs(IGlass, SurfNum) += QS(solEnclosureNum) * BlAbsDiffBk; } } - if (ShadeFlag == WinShadingFlag::IntShadeOn) { + if (ShadeFlag == WinShadingType::IntShade) { SurfWinIntLWAbsByShade(SurfNum) = QL(radEnclosureNum) * state.dataConstruction->Construct(ConstrNumSh).ShadeAbsorpThermal * TMULT(radEnclosureNum); - } else if (ShadeFlag == WinShadingFlag::IntBlindOn) { + } else if (ShadeFlag == WinShadingType::IntBlind) { Real64 EffBlEmiss = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), SurfaceWindow(SurfNum).EffShBlindEmiss); // Blind emissivity (thermal absorptance) as part of glazing system SurfWinIntLWAbsByShade(SurfNum) = QL(radEnclosureNum) * EffBlEmiss * TMULT(radEnclosureNum); @@ -3606,7 +3606,7 @@ namespace HeatBalanceSurfaceManager { SurfWinIntSWAbsByShade(SurfNum) *= SurfWinGlazedFrac(SurfNum); } - } else if (ShadeFlag == WinShadingFlag::SwitchableGlazing) { // Switchable glazing + } else if (ShadeFlag == WinShadingType::SwitchableGlazing) { // Switchable glazing for (int IGlass = 1; IGlass <= TotGlassLayers; ++IGlass) { SurfWinQRadSWwinAbs(IGlass, SurfNum) += QS(solEnclosureNum) * @@ -3642,12 +3642,12 @@ namespace HeatBalanceSurfaceManager { DividerThermAbs = state.dataMaterial->Material(MatNumGl).AbsorpThermalBack; } // Correct for interior shade transmittance - if (ShadeFlag == WinShadingFlag::IntShadeOn) { + if (ShadeFlag == WinShadingType::IntShade) { int MatNumSh = state.dataConstruction->Construct(ConstrNumSh).LayerPoint( state.dataConstruction->Construct(ConstrNumSh).TotLayers); // Shade layer material number DividerSolAbs *= state.dataMaterial->Material(MatNumSh).Trans; DividerThermAbs *= state.dataMaterial->Material(MatNumSh).TransThermal; - } else if (ShadeFlag == WinShadingFlag::IntBlindOn) { + } else if (ShadeFlag == WinShadingType::IntBlind) { int BlNum = SurfWinBlindNumber(SurfNum); DividerSolAbs *= InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), Blind(BlNum).SolBackDiffDiffTrans); @@ -3724,12 +3724,12 @@ namespace HeatBalanceSurfaceManager { ConstrNumSh = Surface(SurfNum).activeStormWinShadedConstruction; } int TotGlassLayers = state.dataConstruction->Construct(ConstrNum).TotGlassLayers; - WinShadingFlag ShadeFlag = SurfWinShadingFlag(SurfNum); + WinShadingType ShadeFlag = SurfWinShadingFlag(SurfNum); if (!IS_SHADED(ShadeFlag)) { // No window shading for (int IGlass = 1; IGlass <= TotGlassLayers; ++IGlass) { SurfWinQRadSWwinAbs(IGlass, SurfNum) += SurfWinInitialDifSolwinAbs(IGlass, SurfNum); } - } else if (ShadeFlag == WinShadingFlag::SwitchableGlazing) { // Switchable glazing + } else if (ShadeFlag == WinShadingType::SwitchableGlazing) { // Switchable glazing for (int IGlass = 1; IGlass <= TotGlassLayers; ++IGlass) { SurfWinQRadSWwinAbs(IGlass, SurfNum) += SurfWinInitialDifSolwinAbs(IGlass, SurfNum); } @@ -3777,7 +3777,7 @@ namespace HeatBalanceSurfaceManager { } else { TotGlassLayers = state.dataConstruction->Construct(ConstrNum).TotGlassLayers; } - WinShadingFlag ShadeFlag = SurfWinShadingFlag(SurfNum); + WinShadingType ShadeFlag = SurfWinShadingFlag(SurfNum); if (!IS_SHADED(ShadeFlag) || SurfWinWindowModelType(SurfNum) == WindowBSDFModel) { // No window shading for (int IGlass = 1; IGlass <= TotGlassLayers; ++IGlass) { // Initial Transmitted Diffuse Solar Absorbed on Inside of Surface[W] @@ -3788,7 +3788,7 @@ namespace HeatBalanceSurfaceManager { // Total Shortwave Absorbed:All Glass Layers[W] SurfWinSWwinAbsTotalReport(SurfNum) += SurfWinQRadSWwinAbs(IGlass, SurfNum) * Surface(SurfNum).Area; } - } else if (ShadeFlag == WinShadingFlag::SwitchableGlazing) { // Switchable glazing + } else if (ShadeFlag == WinShadingType::SwitchableGlazing) { // Switchable glazing for (int IGlass = 1; IGlass <= TotGlassLayers; ++IGlass) { // Initial Transmitted Diffuse Solar Absorbed on Inside of Surface[W] SurfInitialDifSolInAbsReport(SurfNum) += @@ -3878,8 +3878,8 @@ namespace HeatBalanceSurfaceManager { if (firstSurfWin == -1) continue; for (int SurfNum = firstSurfWin; SurfNum <= lastSurfWin; ++SurfNum) { // For window with an interior shade or blind, emissivity is a combination of glass and shade/blind emissivity - WinShadingFlag ShadeFlag = SurfWinShadingFlag(SurfNum); - if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn) + WinShadingType ShadeFlag = SurfWinShadingFlag(SurfNum); + if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::IntBlind) ITABSF(SurfNum) = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), SurfaceWindow(SurfNum).EffShBlindEmiss) + InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), @@ -3897,8 +3897,8 @@ namespace HeatBalanceSurfaceManager { if (!Surface(SurfNum).HeatTransSurf) continue; int ConstrNum = Surface(SurfNum).Construction; - WinShadingFlag ShadeFlag = SurfWinShadingFlag(SurfNum); - if (ShadeFlag != WinShadingFlag::SwitchableGlazing) { + WinShadingType ShadeFlag = SurfWinShadingFlag(SurfNum); + if (ShadeFlag != WinShadingType::SwitchableGlazing) { SUM1 += Surface(SurfNum).Area * ITABSF(SurfNum); } else { // Switchable glazing SUM1 += Surface(SurfNum).Area * InterpSw(SurfWinSwitchingFactor(SurfNum), @@ -3923,7 +3923,7 @@ namespace HeatBalanceSurfaceManager { Real64 TauShIR = state.dataMaterial->Material(MatNumSh).TransThermal; // Effective emissivity of shade or blind Real64 EffShDevEmiss = SurfaceWindow(SurfNum).EffShBlindEmiss(1); - if (ShadeFlag == WinShadingFlag::IntBlindOn) { + if (ShadeFlag == WinShadingType::IntBlind) { TauShIR = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), Blind(SurfWinBlindNumber(SurfNum)).IRBackTrans); @@ -4016,7 +4016,7 @@ namespace HeatBalanceSurfaceManager { // Window if (!state.dataConstruction->Construct(Surface(SurfNum).Construction).WindowTypeEQL) { - WinShadingFlag ShadeFlag = SurfWinShadingFlag(SurfNum); + WinShadingType ShadeFlag = SurfWinShadingFlag(SurfNum); Real64 AbsDiffTotWin = 0.0; // Sum of window layer short-wave absorptances int ConstrNumSh = Surface(SurfNum).activeShadedConstruction; if (SurfWinStormWinFlag(SurfNum) == 1) { @@ -4041,7 +4041,7 @@ namespace HeatBalanceSurfaceManager { } // Switchable glazing - if (ShadeFlag == WinShadingFlag::SwitchableGlazing) + if (ShadeFlag == WinShadingType::SwitchableGlazing) AbsDiffLayWin = InterpSw(SwitchFac, AbsDiffLayWin, state.dataConstruction->Construct(ConstrNumSh).AbsDiffBack(Lay)); AbsDiffTotWin += AbsDiffLayWin; @@ -4067,7 +4067,7 @@ namespace HeatBalanceSurfaceManager { // Switchable glazing - if (ShadeFlag == WinShadingFlag::SwitchableGlazing) + if (ShadeFlag == WinShadingType::SwitchableGlazing) TransDiffWin = InterpSw(SwitchFac, TransDiffWin, state.dataConstruction->Construct(ConstrNumSh).TransDiff); SUM1 += Surface(SurfNum).Area * (TransDiffWin + AbsDiffTotWin + DiffAbsShade); diff --git a/src/EnergyPlus/HighTempRadiantSystem.cc b/src/EnergyPlus/HighTempRadiantSystem.cc index 8e6bf48e6c0..b89eeffffc6 100644 --- a/src/EnergyPlus/HighTempRadiantSystem.cc +++ b/src/EnergyPlus/HighTempRadiantSystem.cc @@ -1491,7 +1491,7 @@ namespace HighTempRadiantSystem { Area = Surface(SurfNum).Area; if (Surface(SurfNum).Class == SurfaceClass::Window) { - if (SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntShadeOn || SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntBlindOn) { + if (SurfWinShadingFlag(SurfNum) == WinShadingType::IntShade || SurfWinShadingFlag(SurfNum) == WinShadingType::IntBlind) { // The area is the shade or blind area = the sum of the glazing area and the divider area (which is zero if no divider) Area += SurfWinDividerArea(SurfNum); } @@ -1502,8 +1502,8 @@ namespace HighTempRadiantSystem { SurfWinFrameTempSurfIn(SurfNum); } - if (SurfWinDividerArea(SurfNum) > 0.0 && SurfWinShadingFlag(SurfNum) != WinShadingFlag::IntShadeOn && - SurfWinShadingFlag(SurfNum) != WinShadingFlag::IntBlindOn) { + if (SurfWinDividerArea(SurfNum) > 0.0 && SurfWinShadingFlag(SurfNum) != WinShadingType::IntShade && + SurfWinShadingFlag(SurfNum) != WinShadingType::IntBlind) { // Window divider contribution (only from shade or blind for window with divider and interior shade or blind) SumHATsurf += HConvIn(SurfNum) * SurfWinDividerArea(SurfNum) * (1.0 + 2.0 * SurfWinProjCorrDivIn(SurfNum)) * SurfWinDividerTempSurfIn(SurfNum); diff --git a/src/EnergyPlus/LowTempRadiantSystem.cc b/src/EnergyPlus/LowTempRadiantSystem.cc index a400f04a177..2d7909ee1e8 100644 --- a/src/EnergyPlus/LowTempRadiantSystem.cc +++ b/src/EnergyPlus/LowTempRadiantSystem.cc @@ -5570,7 +5570,7 @@ namespace LowTempRadiantSystem { Real64 Area = Surface(surfNum).Area; if (Surface(surfNum).Class == SurfaceClass::Window) { - if (SurfWinShadingFlag(surfNum) == WinShadingFlag::IntShadeOn || SurfWinShadingFlag(surfNum) == WinShadingFlag::IntBlindOn) { + if (SurfWinShadingFlag(surfNum) == WinShadingType::IntShade || SurfWinShadingFlag(surfNum) == WinShadingType::IntBlind) { // The area is the shade or blind are = sum of the glazing area and the divider area (which is zero if no divider) Area += SurfWinDividerArea(surfNum); } @@ -5581,8 +5581,8 @@ namespace LowTempRadiantSystem { SurfWinFrameTempSurfIn(surfNum); } - if (SurfWinDividerArea(surfNum) > 0.0 && SurfWinShadingFlag(surfNum) != WinShadingFlag::IntShadeOn && - SurfWinShadingFlag(surfNum) != WinShadingFlag::IntBlindOn) { + if (SurfWinDividerArea(surfNum) > 0.0 && SurfWinShadingFlag(surfNum) != WinShadingType::IntShade && + SurfWinShadingFlag(surfNum) != WinShadingType::IntBlind) { // Window divider contribution (only from shade or blind for window with divider and interior shade or blind) sumHATsurf += HConvIn(surfNum) * SurfWinDividerArea(surfNum) * (1.0 + 2.0 * SurfWinProjCorrDivIn(surfNum)) * SurfWinDividerTempSurfIn(surfNum); diff --git a/src/EnergyPlus/RoomAirModelAirflowNetwork.cc b/src/EnergyPlus/RoomAirModelAirflowNetwork.cc index 46adba8a228..772be99daa4 100644 --- a/src/EnergyPlus/RoomAirModelAirflowNetwork.cc +++ b/src/EnergyPlus/RoomAirModelAirflowNetwork.cc @@ -1088,8 +1088,8 @@ namespace RoomAirModelAirflowNetwork { HA += HConvIn(SurfNum) * SurfWinFrameArea(SurfNum) * (1.0 + SurfWinProjCorrFrIn(SurfNum)); } - if (SurfWinDividerArea(SurfNum) > 0.0 && SurfWinShadingFlag(SurfNum) != WinShadingFlag::IntShadeOn && - SurfWinShadingFlag(SurfNum) != WinShadingFlag::IntBlindOn) { + if (SurfWinDividerArea(SurfNum) > 0.0 && SurfWinShadingFlag(SurfNum) != WinShadingType::IntShade && + SurfWinShadingFlag(SurfNum) != WinShadingType::IntBlind) { // Window divider contribution(only from shade or blind for window with divider and interior shade or blind) SumHATsurf += HConvIn(SurfNum) * SurfWinDividerArea(SurfNum) * (1.0 + 2.0 * SurfWinProjCorrDivIn(SurfNum)) * SurfWinDividerTempSurfIn(SurfNum); diff --git a/src/EnergyPlus/SolarShading.cc b/src/EnergyPlus/SolarShading.cc index 8cdbd4f4c50..f51b7c75ff9 100644 --- a/src/EnergyPlus/SolarShading.cc +++ b/src/EnergyPlus/SolarShading.cc @@ -1347,8 +1347,8 @@ namespace SolarShading { // Added TH 5/26/2009 for switchable windows to report switching factor (tinted level) // CurrentModuleObject='Switchable Windows' if (Surface(SurfLoop).HasShadeControl) { - if (WindowShadingControl(Surface(SurfLoop).activeWindowShadingControl).ShadingType == WinShadingFlag::SwitchableGlazing) { - // IF (SurfaceWindow(SurfLoop)%ShadingFlag == WinShadingFlag::SwitchableGlazing) THEN !ShadingFlag is not set to WinShadingFlag::SwitchableGlazing yet! + if (WindowShadingControl(Surface(SurfLoop).activeWindowShadingControl).ShadingType == WinShadingType::SwitchableGlazing) { + // IF (SurfaceWindow(SurfLoop)%ShadingFlag == WinShadingType::SwitchableGlazing) THEN !ShadingFlag is not set to WinShadingType::SwitchableGlazing yet! SetupOutputVariable(state, "Surface Window Switchable Glazing Switching Factor", OutputProcessor::Unit::None, SurfWinSwitchingFactor(SurfLoop), @@ -6068,7 +6068,7 @@ namespace SolarShading { } int BlNum = SurfWinBlindNumber(SurfNum); int ScNum = SurfWinScreenNumber(SurfNum); - WinShadingFlag ShadeFlag = SurfWinShadingFlag(SurfNum); // Set in subr. WindowShadingManager + WinShadingType ShadeFlag = SurfWinShadingFlag(SurfNum); // Set in subr. WindowShadingManager Real64 ProfAng = 0.0; // Window solar profile angle (radians) @@ -6126,28 +6126,28 @@ namespace SolarShading { Array1D ADiffWinSh(NGlass); // Diffuse solar absorptance of glass layer, window with shading device if (IS_EXT_SHADED(ShadeFlag)) FracSunLit = SunLitFract; - if (IS_SHADE_ON(ShadeFlag) || ShadeFlag == WinShadingFlag::SwitchableGlazing) { + if (IS_SHADE_ON(ShadeFlag) || ShadeFlag == WinShadingType::SwitchableGlazing) { // Shade or switchable glazing on for (int Lay = 1; Lay <= NGlass; ++Lay) { AbWinSh(Lay) = POLYF(CosInc, state.dataConstruction->Construct(ConstrNumSh).AbsBeamCoef({1, 6}, Lay)) * CosInc * FracSunLit; ADiffWinSh(Lay) = state.dataConstruction->Construct(ConstrNumSh).AbsDiff(Lay); } - if (ShadeFlag == WinShadingFlag::IntShadeOn) { // Exterior beam absorbed by INTERIOR SHADE + if (ShadeFlag == WinShadingType::IntShade) { // Exterior beam absorbed by INTERIOR SHADE // Note that AbsBeamShadeCoef includes effect of shade/glazing inter-reflection Real64 AbsShade = POLYF(CosInc, state.dataConstruction->Construct(ConstrNumSh).AbsBeamShadeCoef); // Interior shade or blind beam solar absorptance ExtBeamAbsByShadFac(SurfNum) = (AbsShade * CosInc * SunLitFract * InOutProjSLFracMult + SurfWinOutsRevealDiffOntoGlazing(SurfNum) * state.dataConstruction->Construct(ConstrNumSh).AbsDiffShade) * SurfWinGlazedFrac(SurfNum); // In the above, GlazedFrac corrects for shadowing of divider onto interior shade - } else if (ShadeFlag == WinShadingFlag::ExtShadeOn) { // Exterior beam absorbed by EXTERIOR SHADE + } else if (ShadeFlag == WinShadingType::ExtShade) { // Exterior beam absorbed by EXTERIOR SHADE ExtBeamAbsByShadFac(SurfNum) = state.dataConstruction->Construct(ConstrNumSh).AbsDiffShade * CosInc * SunLitFract; - } else if (ShadeFlag == WinShadingFlag::BGShadeOn) { // Exterior beam absorbed by BETWEEN-GLASS SHADE + } else if (ShadeFlag == WinShadingType::BGShade) { // Exterior beam absorbed by BETWEEN-GLASS SHADE Real64 AbsShade = POLYF(CosInc, state.dataConstruction->Construct(ConstrNumSh).AbsBeamShadeCoef); ExtBeamAbsByShadFac(SurfNum) = AbsShade * CosInc * SunLitFract + SurfWinOutsRevealDiffOntoGlazing(SurfNum) * state.dataConstruction->Construct(ConstrNumSh).AbsDiffShade; } } else { // Blind or screen on - if (ShadeFlag != WinShadingFlag::ExtScreenOn) ProfileAngle(SurfNum, state.dataEnvrn->SOLCOS, Blind(BlNum).SlatOrientation, ProfAng); - if (ShadeFlag == WinShadingFlag::IntBlindOn) { + if (ShadeFlag != WinShadingType::ExtScreen) ProfileAngle(SurfNum, state.dataEnvrn->SOLCOS, Blind(BlNum).SlatOrientation, ProfAng); + if (ShadeFlag == WinShadingType::IntBlind) { // Interior blind on Real64 TGlBm = POLYF(CosInc,state.dataConstruction->Construct(ConstrNum).TransSolBeamCoef); // Glazing system front solar beam transmittance Real64 RGlDiffBack = state.dataConstruction->Construct(ConstrNum).ReflectSolDiffBack; // Glazing system back diffuse solar reflectance @@ -6171,7 +6171,7 @@ namespace SolarShading { SurfWinOutsRevealDiffOntoGlazing(SurfNum) * AbsShadeDiff) * SurfWinGlazedFrac(SurfNum); // In the above, GlazedFrac corrects for shadowing of divider onto interior blind - } else if (ShadeFlag == WinShadingFlag::ExtBlindOn) { + } else if (ShadeFlag == WinShadingType::ExtBlind) { // Exterior blind on Real64 TBlBmBm = BlindBeamBeamTrans(ProfAng, SlatAng, Blind(BlNum).SlatWidth, Blind(BlNum).SlatSeparation, Blind(BlNum).SlatThickness); // Blind solar front beam-beam transmittance Real64 TBlDifDif = InterpSlatAng(SlatAng, VarSlats, Blind(BlNum).SolFrontDiffDiffTrans); // Diffuse-diffuse solar transmittance of blind @@ -6196,7 +6196,7 @@ namespace SolarShading { Real64 AbsBlDiffBack = InterpSlatAng(SlatAng, VarSlats, Blind(BlNum).SolBackDiffAbs); // Blind solar back diffuse absorptance Real64 AbsShade = AbsBlFront + AbsBlBack * RGlFront * TBlBmBm + (AbsBlDiffBack * RGlDiffFront / (1.0 - RhoBlDiffBack * RGlDiffFront)) * (RGlFront * TBlBmBm * RhoBlBack + TBlBmDiff); ExtBeamAbsByShadFac(SurfNum) = AbsShade * CosInc * SunLitFract * InOutProjSLFracMult; - } else if (ShadeFlag == WinShadingFlag::ExtScreenOn) { + } else if (ShadeFlag == WinShadingType::ExtScreen) { // Exterior screen on Real64 TScBmBm = SurfaceScreens(ScNum).BmBmTrans; // Screen solar front beam-beam transmittance Real64 TScBmDiff = SurfaceScreens(ScNum).BmDifTrans; // Screen solar front beam-diffuse transmittance @@ -6218,7 +6218,7 @@ namespace SolarShading { Real64 AbsScDiffBack = SurfaceScreens(ScNum).DifScreenAbsorp; // Screen solar back diffuse absorptance Real64 AbsScreen = AbsScBeam * (1.0 + TScBmBm * RGlFront) + (AbsScDiffBack * TScBmBm * RGlFront * RGlDiffFront * RScBack / (1.0 - RScDifBack * RGlDiffFront)); // Exterior screen beam solar absorptance ExtBeamAbsByShadFac(SurfNum) = AbsScreen * CosInc * SunLitFract * InOutProjSLFracMult; - } else if (ShadeFlag == WinShadingFlag::BGBlindOn) { + } else if (ShadeFlag == WinShadingType::BGBlind) { // Between-glass blind o // Isolated glass and blind properties at current incidence angle, profile angle and slat angle Real64 t1 = POLYF(CosInc, state.dataConstruction->Construct(ConstrNum).tBareSolCoef({1, 6}, 1)); // Bare-glass beam solar transmittance for glass layers 1,2 and 3 @@ -6281,7 +6281,7 @@ namespace SolarShading { } // End of check if blind is interior, exterior or between-glass } // End of check if a blind is on - if (ShadeFlag != WinShadingFlag::SwitchableGlazing) { + if (ShadeFlag != WinShadingType::SwitchableGlazing) { // Interior or between glass shade or blind on for (int Lay = 1; Lay <= NGlass; ++Lay) { SurfWinA(Lay, SurfNum) = AbWinSh(Lay); @@ -6402,7 +6402,7 @@ namespace SolarShading { if (SurfWinWindowModelType(SurfNum) == Window5DetailedModel) { if (IS_SHADED(SurfWinShadingFlag(SurfNum)) && !SurfWinGlareControlIsActive(SurfNum)) { - if (ShadeFlag != WinShadingFlag::SwitchableGlazing) { + if (ShadeFlag != WinShadingType::SwitchableGlazing) { // Shade or blind if (IS_SHADE_SCREEN_ON(ShadeFlag)) { // Shade or screen @@ -6490,7 +6490,7 @@ namespace SolarShading { DiffTrans = state.dataConstruction->Construct(ConstrNum).TransDiff; } if (IS_SHADED(ShadeFlag) && !SurfWinGlareControlIsActive(SurfNum)) { - if (ShadeFlag != WinShadingFlag::SwitchableGlazing) { + if (ShadeFlag != WinShadingType::SwitchableGlazing) { // Shade or blind if (IS_SHADE_SCREEN_ON(ShadeFlag)) { // Shade or screen @@ -6546,10 +6546,10 @@ namespace SolarShading { if (SurfWinWindowModelType(SurfNum) != WindowEQLModel) { SurfWinBlGlSysTsolDifDif(SurfNum) = DiffTrans; SurfWinScGlSysTsolDifDif(SurfNum) = DiffTrans; - if (IS_BLIND_ON(ShadeFlag)|| ShadeFlag == WinShadingFlag::ExtScreenOn) { + if (IS_BLIND_ON(ShadeFlag)|| ShadeFlag == WinShadingType::ExtScreen) { SurfWinBlGlSysTsolDifDif(SurfNum) = DiffTrans; SurfWinScGlSysTsolDifDif(SurfNum) = DiffTrans; - if (ShadeFlag == WinShadingFlag::ExtScreenOn) { + if (ShadeFlag == WinShadingType::ExtScreen) { SurfWinScTsolDifDif(SurfNum) = SurfaceScreens(ScNum).DifDifTrans; } else { SurfWinBlTsolDifDif(SurfNum) = InterpSlatAng(SlatAng, VarSlats, Blind(BlNum).SolFrontDiffDiffTrans); @@ -6565,7 +6565,7 @@ namespace SolarShading { if (IS_SHADED(ShadeFlag) && !SurfWinGlareControlIsActive(SurfNum)) { // Shade or screen or blind on, or switchable glazing // (note in the following that diffusing glass is not allowed in a window with shade, blind or switchable glazing) - if (IS_SHADE_ON(ShadeFlag) || ShadeFlag == WinShadingFlag::SwitchableGlazing) { + if (IS_SHADE_ON(ShadeFlag) || ShadeFlag == WinShadingType::SwitchableGlazing) { // Shade on or switchable glazing TBmAllShBlSc = POLYF(CosInc, state.dataConstruction->Construct(ConstrNumSh).TransSolBeamCoef); } else { @@ -6575,7 +6575,7 @@ namespace SolarShading { Real64 TBlDifDif; // Diffuse-diffuse solar transmittance of blind Real64 TScBmBm; Real64 TBlBmBm; - if (ShadeFlag == WinShadingFlag::ExtScreenOn) {// Exterior screen + if (ShadeFlag == WinShadingType::ExtScreen) {// Exterior screen Real64 RScBack = SurfaceScreens(ScNum).ReflectSolBeamFront; Real64 RScDifDifBk = SurfaceScreens(ScNum).DifReflect; // Diffuse-diffuse back refectance of screen Real64 RGlBmFr = POLYF(CosInc, state.dataConstruction->Construct(ConstrNum).ReflSolBeamFrontCoef); // Beam front reflectance of glass @@ -6595,7 +6595,7 @@ namespace SolarShading { } else { TBlBmBm = BlindBeamBeamTrans(ProfAng, SlatAng, Blind(BlNum).SlatWidth, Blind(BlNum).SlatSeparation, Blind(BlNum).SlatThickness); TBlBmDif = InterpProfSlatAng(ProfAng, SlatAng, VarSlats, Blind(BlNum).SolFrontBeamDiffTrans); - if (ShadeFlag == WinShadingFlag::IntBlindOn) { + if (ShadeFlag == WinShadingType::IntBlind) { Real64 RhoBlBmDifFr = InterpProfSlatAng(ProfAng, SlatAng, VarSlats, Blind(BlNum).SolFrontBeamDiffRefl); // Beam-diffuse front reflectance of blind Real64 RGlDifBk = state.dataConstruction->Construct(ConstrNum).ReflectSolDiffBack; // Diffuse front reflectance of glass Real64 RhoBlDifDifFr = InterpSlatAng(SlatAng, VarSlats, Blind(BlNum).SolFrontDiffDiffRefl); // Diffuse-diffuse front refectance of blind @@ -6606,7 +6606,7 @@ namespace SolarShading { TBmBmShBlSc = TBmBmBl; // TBmBm * TBlBmBm TBmDifShBlSc = TBmAllShBlSc - TBmBmShBlSc; if (TBmDifShBlSc < 0.0) TBmDifShBlSc = 0.0; - } else if (ShadeFlag == WinShadingFlag::ExtBlindOn) { + } else if (ShadeFlag == WinShadingType::ExtBlind) { Real64 RhoBlBmDifBk = InterpProfSlatAng(ProfAng, SlatAng, VarSlats, Blind(BlNum).SolBackBeamDiffRefl); // Beam-diffuse back reflectance of blind Real64 RhoBlDifDifBk = InterpSlatAng(SlatAng, VarSlats, Blind(BlNum).SolBackDiffDiffRefl); // Diffuse-diffuse back refectance of blind Real64 RGlBmFr = POLYF(CosInc, state.dataConstruction->Construct(ConstrNum).ReflSolBeamFrontCoef); @@ -6659,7 +6659,7 @@ namespace SolarShading { } // end of checking if not eql window model } // end of checking if sunlitfract > 0 - if (ShadeFlag == WinShadingFlag::SwitchableGlazing) { + if (ShadeFlag == WinShadingType::SwitchableGlazing) { // Switchable glazing Real64 SwitchFac = SurfWinSwitchingFactor(SurfNum); if (!SurfWinSolarDiffusing(SurfNum)) { @@ -6704,7 +6704,7 @@ namespace SolarShading { WinTransDifSolarSky(SurfNum) = DiffTrans * Surface(SurfNum).Area; } - if (!IS_SHADED(ShadeFlag) || SurfWinGlareControlIsActive(SurfNum) || ShadeFlag == WinShadingFlag::SwitchableGlazing) { // Unshaded or switchable glazing + if (!IS_SHADED(ShadeFlag) || SurfWinGlareControlIsActive(SurfNum) || ShadeFlag == WinShadingType::SwitchableGlazing) { // Unshaded or switchable glazing // Note: with previous defs of TBmBm & TBmDif, these come out right for Complex Fenestration // WinTransBmSolar uses the directional-hemispherical transmittance WinTransBmSolar(SurfNum) = (TBmBm + TBmDif) * SunLitFract * CosInc * Surface(SurfNum).Area * InOutProjSLFracMult; @@ -6812,7 +6812,7 @@ namespace SolarShading { } if (IS_BLIND_ON(ShadeFlag)) { TBm = TBmBmBl; // Interior, exterior or between-glass blind on - } else if (ShadeFlag == WinShadingFlag::ExtScreenOn) { + } else if (ShadeFlag == WinShadingType::ExtScreen) { TBm = TBmBmSc; // Exterior screen on } else { TBm = TBmBm; // Bare glass or switchable glazing @@ -6880,7 +6880,7 @@ namespace SolarShading { // are assumed to be bare, i.e., they have no shading device and are non-switchable. // The layer order for interior windows is "outside" to "inside," where "outside" refers to // the adjacent zone and "inside" refers to the current zone. - WinShadingFlag ShadeFlagBack = SurfWinShadingFlag(BackSurfNum); + WinShadingType ShadeFlagBack = SurfWinShadingFlag(BackSurfNum); int ConstrNum = Surface(SurfNum).Construction; int ConstrNumSh = Surface(SurfNum).activeShadedConstruction; if (SurfWinStormWinFlag(SurfNum) == 1) { @@ -6924,11 +6924,11 @@ namespace SolarShading { // Interior beam absorbed by INTERIOR SHADE of back exterior window - if (ShadeFlagBack == WinShadingFlag::IntShadeOn) { + if (ShadeFlagBack == WinShadingType::IntShade) { IntBeamAbsByShadFac(BackSurfNum) = BOverlap * state.dataConstruction->Construct(ConstrNumBackSh).AbsDiffBackShade / (Surface(BackSurfNum).Area + SurfWinDividerArea(BackSurfNum)); BABSZone += BOverlap * state.dataConstruction->Construct(ConstrNumBackSh).AbsDiffBackShade; - } else if (ShadeFlagBack == WinShadingFlag::ExtShadeOn) { // Interior beam absorbed by EXTERIOR SHADE of back exterior window + } else if (ShadeFlagBack == WinShadingType::ExtShade) { // Interior beam absorbed by EXTERIOR SHADE of back exterior window Real64 RGlFront = state.dataConstruction->Construct(ConstrNumBack).ReflectSolDiffFront; Real64 AbsSh = state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNumBackSh).LayerPoint(1)).AbsorpSolar; Real64 RhoSh = 1.0 - AbsSh - state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNumBackSh).LayerPoint(1)).Trans; @@ -6936,7 +6936,7 @@ namespace SolarShading { BABSZone += BOverlap * AShBack; IntBeamAbsByShadFac(BackSurfNum) = BOverlap * AShBack / (Surface(BackSurfNum).Area + SurfWinDividerArea(BackSurfNum)); - } else if (ShadeFlagBack == WinShadingFlag::BGShadeOn) { // Interior beam absorbed by BETWEEN-GLASS SHADE of back exterior window + } else if (ShadeFlagBack == WinShadingType::BGShade) { // Interior beam absorbed by BETWEEN-GLASS SHADE of back exterior window Real64 rbd1k = state.dataConstruction->Construct(ConstrNumBack).rbBareSolDiff(1); Real64 rfd2k = state.dataConstruction->Construct(ConstrNumBack).rfBareSolDiff(2); Real64 AShBack; // System shade absorptance for interior beam solar @@ -6975,7 +6975,7 @@ namespace SolarShading { Real64 TBlBmDiffBack = InterpProfSlatAng(ProfAngBack, SlatAngBack, VarSlatsBack, Blind(BlNumBack).SolBackBeamDiffTrans); // Blind solar back beam-diffuse transmittance - if (ShadeFlagBack == WinShadingFlag::IntBlindOn) { + if (ShadeFlagBack == WinShadingType::IntBlind) { // Interior beam absorptance of GLASS LAYERS of exterior back window with INTERIOR BLIND // Blind solar front beam reflectance @@ -7017,7 +7017,7 @@ namespace SolarShading { IntBeamAbsByShadFac(BackSurfNum) = BOverlap * ABlBack / (Surface(BackSurfNum).Area + SurfWinDividerArea(BackSurfNum)); BABSZone += BOverlap * ABlBack; - } else if (ShadeFlagBack == WinShadingFlag::ExtBlindOn) { + } else if (ShadeFlagBack == WinShadingType::ExtBlind) { // Interior beam absorptance of GLASS LAYERS of exterior back window with EXTERIOR BLIND // Glazing system front diffuse solar reflectance @@ -7115,7 +7115,7 @@ namespace SolarShading { } // End of check if between-glass blind is on back window // End of check if blind is on back window - } else if (ShadeFlagBack == WinShadingFlag::ExtScreenOn) { + } else if (ShadeFlagBack == WinShadingType::ExtScreen) { // Interior beam absorptance of GLASS LAYERS of exterior back window with EXTERIOR SCREEN int ScNumBack = SurfWinScreenNumber(BackSurfNum); // Back surface screen number @@ -7151,7 +7151,7 @@ namespace SolarShading { // Interior beam absorptance of glass layers of back exterior window with SWITCHABLE GLAZING - if (ShadeFlagBack == WinShadingFlag::SwitchableGlazing && Surface(BackSurfNum).ExtBoundCond == 0) { + if (ShadeFlagBack == WinShadingType::SwitchableGlazing && Surface(BackSurfNum).ExtBoundCond == 0) { Real64 SwitchFac = SurfWinSwitchingFactor(SurfNum); // Switching factor for a window Real64 AbsBeamWinSh; // Glass layer beam solar absorptance of a shaded window for (int Lay = 1; Lay <= NBackGlass; ++Lay) { @@ -7554,7 +7554,7 @@ namespace SolarShading { if ((Surface(SurfNum).ExtBoundCond == ExternalEnvironment) || (Surface(SurfNum).ExtBoundCond == OtherSideCondModeledExt)) { - WinShadingFlag ShadeFlag = SurfWinShadingFlag(SurfNum); + WinShadingType ShadeFlag = SurfWinShadingFlag(SurfNum); int ShelfNum = Surface(SurfNum).Shelf; int OutShelfSurf = 0; if (ShelfNum > 0) { // Outside daylighting shelf @@ -8662,7 +8662,7 @@ namespace SolarShading { for (int ISurf = firstSurfWin; ISurf <= lastSurfWin; ++ISurf) { SurfWinExtIntShadePrevTS(ISurf) = SurfWinShadingFlag(ISurf); - SurfWinShadingFlag(ISurf) = WinShadingFlag::NoShade; + SurfWinShadingFlag(ISurf) = WinShadingType::NoShade; SurfWinFracTimeShadingDeviceOn(ISurf) = 0.0; if (SurfWinWindowModelType(ISurf) == WindowEQLModel) { int EQLNum = state.dataConstruction->Construct(Surface(ISurf).Construction).EQLConsPtr; @@ -8685,13 +8685,13 @@ namespace SolarShading { auto &material(state.dataMaterial->Material(LayPtr)); const bool isShading = material.Group == ComplexWindowShade; if (isShading && Lay == 1) { - SurfWinShadingFlag(ISurf) = WinShadingFlag::ExtShadeOn; + SurfWinShadingFlag(ISurf) = WinShadingType::ExtShade; } if (isShading && Lay == TotLayers) { - SurfWinShadingFlag(ISurf) = WinShadingFlag::IntShadeOn; + SurfWinShadingFlag(ISurf) = WinShadingType::IntShade; } } - if (SurfWinShadingFlag(ISurf) == WinShadingFlag::IntShadeOn) { + if (SurfWinShadingFlag(ISurf) == WinShadingType::IntShade) { auto &construction(state.dataConstruction->Construct(Surface(ISurf).Construction)); const int TotLay = construction.TotLayers; int ShadingLayerPtr = construction.LayerPoint(TotLay); @@ -8748,7 +8748,7 @@ namespace SolarShading { Real64 SetPoint = WindowShadingControl(IShadingCtrl).SetPoint; // Control setpoint Real64 SetPoint2 = WindowShadingControl(IShadingCtrl).SetPoint2; // Second control setpoint - WinShadingFlag ShType; // Type of shading (interior shade, interior blind, etc.) + WinShadingType ShType; // Type of shading (interior shade, interior blind, etc.) if (IS_SHADED(WindowShadingControl(IShadingCtrl).ShadingType)) { ShType = WindowShadingControl(IShadingCtrl).ShadingType; @@ -8780,7 +8780,7 @@ namespace SolarShading { // Determine whether to deploy shading depending on type of control SurfWinGlareControlIsActive(ISurf) = false; - SurfWinShadingFlag(ISurf) = WinShadingFlag::ShadeOff; // Initialize shading flag to off + SurfWinShadingFlag(ISurf) = WinShadingType::ShadeOff; // Initialize shading flag to off auto const SELECT_CASE_var(WindowShadingControl(IShadingCtrl).ShadingControlType); @@ -8788,7 +8788,7 @@ namespace SolarShading { SurfWinShadingFlag(ISurf) = ShType; } else if (SELECT_CASE_var == WSCT_AlwaysOff) { // 'ALWAYSOFF' - SurfWinShadingFlag(ISurf) = WinShadingFlag::ShadeOff; + SurfWinShadingFlag(ISurf) = WinShadingType::ShadeOff; } else if (SELECT_CASE_var == WSCT_OnIfScheduled) { // 'ONIFSCHEDULEALLOWS' if (SchedAllowsControl) { @@ -8979,7 +8979,7 @@ namespace SolarShading { } // Set switching factor to fully switched if ShadingFlag = 2 - if (SurfWinShadingFlag(ISurf) == WinShadingFlag::SwitchableGlazing && !SurfWinGlareControlIsActive(ISurf)) { + if (SurfWinShadingFlag(ISurf) == WinShadingType::SwitchableGlazing && !SurfWinGlareControlIsActive(ISurf)) { SurfWinSwitchingFactor(ISurf) = 1.0; // Added TH 1/20/2010 @@ -9125,7 +9125,7 @@ namespace SolarShading { } // End of check if interior or exterior blind in place // CALL CalcScreenTransmittance to intialized all screens prior to HB calc's - if (SurfWinShadingFlag(ISurf) == WinShadingFlag::ExtScreenOn && state.dataEnvrn->SunIsUp) { + if (SurfWinShadingFlag(ISurf) == WinShadingType::ExtScreen && state.dataEnvrn->SunIsUp) { CalcScreenTransmittance(state, ISurf); } @@ -9854,7 +9854,7 @@ namespace SolarShading { // outside reveal surface (m2) Real64 BmSolRefldInsReveal; // Multiplied by beam solar gives beam solar reflected by horiz or vertical // inside reveal surface (m2) - WinShadingFlag ShadeFlag; // Shading flag + WinShadingType ShadeFlag; // Shading flag int FrameDivNum; // Frame/Divider number Real64 FrameWidth; // Frame width (m) Real64 P1; // Frame outside/inside projection plus half of glazing thickness (m) @@ -9908,7 +9908,7 @@ namespace SolarShading { if (SurfWinInsideSillDepth(SurfNum) < SurfWinInsideReveal(SurfNum)) continue; ShadeFlag = SurfWinShadingFlag(SurfNum); - if (BITF_TEST_ANY(BITF(ShadeFlag), BITF(WinShadingFlag::ExtShadeOn) | BITF(WinShadingFlag::ExtBlindOn))) continue; + if (BITF_TEST_ANY(BITF(ShadeFlag), BITF(WinShadingType::ExtShade) | BITF(WinShadingType::ExtBlind))) continue; if (CosIncAng(state.dataGlobal->TimeStep, state.dataGlobal->HourOfDay, SurfNum) <= 0.0) continue; @@ -10163,12 +10163,12 @@ namespace SolarShading { // Quantities related to inside reveal; inside reveal reflection/absorption is assumed // to occur only if an interior shade or blind is not in place. - if (!IS_SHADED(ShadeFlag) || ShadeFlag == WinShadingFlag::SwitchableGlazing) { + if (!IS_SHADED(ShadeFlag) || ShadeFlag == WinShadingType::SwitchableGlazing) { if (A2ill > 1.0e-6) { DiffReflGlass = state.dataConstruction->Construct(ConstrNum).ReflectSolDiffBack; - if (ShadeFlag == WinShadingFlag::SwitchableGlazing) { + if (ShadeFlag == WinShadingType::SwitchableGlazing) { SolTransGlassSh = POLYF(CosIncAng(state.dataGlobal->TimeStep, state.dataGlobal->HourOfDay, SurfNum), state.dataConstruction->Construct(ConstrNumSh).TransSolBeamCoef); SolTransGlass = InterpSw(SurfWinSwitchingFactor(SurfNum), SolTransGlass, @@ -10503,18 +10503,18 @@ namespace SolarShading { Real64 AbsorpEff = 0.0; // Effective absorptance of isolated shade layer (fraction of // of incident radiation remaining after reflected portion is // removed that is absorbed - if (WindowShadingControl(WinShadeCtrlNum).ShadingType == WinShadingFlag::IntShadeOn || - WindowShadingControl(WinShadeCtrlNum).ShadingType == WinShadingFlag::ExtShadeOn || - WindowShadingControl(WinShadeCtrlNum).ShadingType == WinShadingFlag::BGShadeOn) { + if (WindowShadingControl(WinShadeCtrlNum).ShadingType == WinShadingType::IntShade || + WindowShadingControl(WinShadeCtrlNum).ShadingType == WinShadingType::ExtShade || + WindowShadingControl(WinShadeCtrlNum).ShadingType == WinShadingType::BGShade) { int ConstrNumSh = Surface(SurfNum).activeShadedConstruction; // Window construction number with shade int TotLay = state.dataConstruction->Construct(ConstrNumSh).TotLayers; // Total layers in a construction - if (WindowShadingControl(WinShadeCtrlNum).ShadingType == WinShadingFlag::IntShadeOn) { + if (WindowShadingControl(WinShadeCtrlNum).ShadingType == WinShadingType::IntShade) { MatNumSh = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(TotLay); // Interior shade - } else if (WindowShadingControl(WinShadeCtrlNum).ShadingType == WinShadingFlag::ExtShadeOn) { + } else if (WindowShadingControl(WinShadeCtrlNum).ShadingType == WinShadingType::ExtShade) { MatNumSh = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(1); // Exterior shade - } else if (WindowShadingControl(WinShadeCtrlNum).ShadingType == WinShadingFlag::BGShadeOn) { + } else if (WindowShadingControl(WinShadeCtrlNum).ShadingType == WinShadingType::BGShade) { if (state.dataConstruction->Construct(ConstrNumSh).TotGlassLayers == 2) { // Double pane with between-glass shade MatNumSh = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(3); @@ -10751,7 +10751,7 @@ namespace SolarShading { ConstrNumSh = Surface(HeatTransSurfNum).activeStormWinShadedConstruction; } int TotGlassLayers = state.dataConstruction->Construct(ConstrNum).TotGlassLayers; - WinShadingFlag ShadeFlag = SurfWinShadingFlag(HeatTransSurfNum); + WinShadingType ShadeFlag = SurfWinShadingFlag(HeatTransSurfNum); if (SurfWinWindowModelType(HeatTransSurfNum) != WindowEQLModel) { if (!IS_SHADED(ShadeFlag)) { // No window shading @@ -10845,7 +10845,7 @@ namespace SolarShading { // Accumulate transmitted diffuse solar for reporting SurfWinInitialDifSolInTrans(HeatTransSurfNum) += DifSolarTransW * per_HTSurfaceArea; - } else if (ShadeFlag == WinShadingFlag::SwitchableGlazing) { // Switchable glazing + } else if (ShadeFlag == WinShadingType::SwitchableGlazing) { // Switchable glazing // Init accumulator for transmittance calc below DifSolarAbsW = 0.0; @@ -10925,7 +10925,7 @@ namespace SolarShading { // Next calc diffuse solar reflected back to zone from window with shade or blind on // Diffuse back solar reflectance, bare glass or shade on InsideDifReflectance = state.dataConstruction->Construct(ConstrNum).ReflectSolDiffBack; - if (BITF_TEST_ANY(BITF(ShadeFlag), BITF(WinShadingFlag::IntBlindOn) | BITF(WinShadingFlag::ExtBlindOn))) { + if (BITF_TEST_ANY(BITF(ShadeFlag), BITF(WinShadingType::IntBlind) | BITF(WinShadingType::ExtBlind))) { // Diffuse back solar reflectance, blind present, vs. slat angle InsideDifReflectance = InterpSlatAng(HTsurf_slat_ang, HTsurf_movable_slats, state.dataConstruction->Construct(ConstrNum).BlReflectSolDiffBack); @@ -11081,7 +11081,7 @@ namespace SolarShading { // IF(ShadeFlag == IntShadeOn) THEN // MatNumSh = Construct(ConstrNumSh)%LayerPoint(Construct(ConstrNumSh)%TotLayers) // DividerSolAbs = DividerSolAbs * dataMaterial.Material(MatNumSh)%Trans - // ELSE IF(ShadeFlag == WinShadingFlag::IntBlindOn) THEN + // ELSE IF(ShadeFlag == WinShadingType::IntBlind) THEN // DividerSolAbs = DividerSolAbs * InterpSlatAng(SurfaceWindow(HeatTransSurfNum)%SlatAngThisTS, & // SurfaceWindow(HeatTransSurfNum)%MovableSlats,Blind(BlNum)%SolBackDiffDiffTrans) // END IF @@ -11160,7 +11160,7 @@ namespace SolarShading { int ConstrNumSh; // Shaded construction number int IGlass; // Glass layer counter int TotGlassLayers; // Number of glass layers in a window construction - WinShadingFlag ShadeFlag; // Shading flag + WinShadingType ShadeFlag; // Shading flag Real64 AbsInt; // Tmp var for Inside surface short-wave absorptance Real64 MovInsulSchedVal; // Value of the movable insulation schedule for current time Real64 HMovInsul; // Conductance of movable insulation @@ -11362,7 +11362,7 @@ namespace SolarShading { InitialZoneDifSolReflW(Surface(AdjSurfNum).SolarEnclIndex) += DifSolarTransW; // [W] } - } else if (ShadeFlag == WinShadingFlag::SwitchableGlazing) { // Switchable glazing + } else if (ShadeFlag == WinShadingType::SwitchableGlazing) { // Switchable glazing // Init accumulator for transmittance calc below DifSolarAbsW = 0.0; @@ -11437,7 +11437,7 @@ namespace SolarShading { // Next calc diffuse solar reflected back to zone from window with shade or blind on // Diffuse back solar reflectance, bare glass or shade on InsideDifReflectance = state.dataConstruction->Construct(ConstrNum).ReflectSolDiffBack; - if (BITF_TEST_ANY(BITF(ShadeFlag), BITF(WinShadingFlag::IntBlindOn) | BITF(WinShadingFlag::ExtBlindOn))) { + if (BITF_TEST_ANY(BITF(ShadeFlag), BITF(WinShadingType::IntBlind) | BITF(WinShadingType::ExtBlind))) { // Diffuse back solar reflectance, blind present, vs. slat angle InsideDifReflectance = InterpSlatAng(SurfWinSlatAngThisTS(HeatTransSurfNum), SurfWinMovableSlats(HeatTransSurfNum), @@ -11513,7 +11513,7 @@ namespace SolarShading { // IF(ShadeFlag == IntShadeOn) THEN // MatNumSh = Construct(ConstrNumSh)%LayerPoint(Construct(ConstrNumSh)%TotLayers) // DividerSolAbs = DividerSolAbs * dataMaterial.Material(MatNumSh)%Trans - // ELSE IF(ShadeFlag == WinShadingFlag::IntBlindOn) THEN + // ELSE IF(ShadeFlag == WinShadingType::IntBlind) THEN // DividerSolAbs = DividerSolAbs * InterpSlatAng(SurfaceWindow(HeatTransSurfNum)%SlatAngThisTS, & // SurfaceWindow(HeatTransSurfNum)%MovableSlats,Blind(BlNum)%SolBackDiffDiffTrans) // END IF diff --git a/src/EnergyPlus/SteamBaseboardRadiator.cc b/src/EnergyPlus/SteamBaseboardRadiator.cc index 717995ff09b..7baa5edd2e2 100644 --- a/src/EnergyPlus/SteamBaseboardRadiator.cc +++ b/src/EnergyPlus/SteamBaseboardRadiator.cc @@ -1380,7 +1380,7 @@ namespace SteamBaseboardRadiator { Area = Surface(SurfNum).Area; if (Surface(SurfNum).Class == SurfaceClass::Window) { - if (SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntShadeOn || SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntBlindOn) { + if (SurfWinShadingFlag(SurfNum) == WinShadingType::IntShade || SurfWinShadingFlag(SurfNum) == WinShadingType::IntBlind) { // The area is the shade or blind area = the sum of the glazing area and the divider area (which is zero if no divider) Area += SurfWinDividerArea(SurfNum); } @@ -1391,8 +1391,8 @@ namespace SteamBaseboardRadiator { SurfWinFrameTempSurfIn(SurfNum); } - if (SurfWinDividerArea(SurfNum) > 0.0 && SurfWinShadingFlag(SurfNum) != WinShadingFlag::IntShadeOn && - SurfWinShadingFlag(SurfNum) != WinShadingFlag::IntBlindOn) { + if (SurfWinDividerArea(SurfNum) > 0.0 && SurfWinShadingFlag(SurfNum) != WinShadingType::IntShade && + SurfWinShadingFlag(SurfNum) != WinShadingType::IntBlind) { // Window divider contribution (only from shade or blind for window with divider and interior shade or blind) SumHATsurf += HConvIn(SurfNum) * SurfWinDividerArea(SurfNum) * (1.0 + 2.0 * SurfWinProjCorrDivIn(SurfNum)) * SurfWinDividerTempSurfIn(SurfNum); diff --git a/src/EnergyPlus/SurfaceGeometry.cc b/src/EnergyPlus/SurfaceGeometry.cc index f19cb135691..4a60a35cbcd 100644 --- a/src/EnergyPlus/SurfaceGeometry.cc +++ b/src/EnergyPlus/SurfaceGeometry.cc @@ -159,14 +159,14 @@ namespace SurfaceGeometry { SurfWinProfileAngHor.dimension(NumSurfaces, 0); SurfWinProfileAngVert.dimension(NumSurfaces, 0); - SurfWinShadingFlag.dimension(NumSurfaces, WinShadingFlag::ShadeOff); + SurfWinShadingFlag.dimension(NumSurfaces, WinShadingType::ShadeOff); SurfWinShadingFlagEMSOn.dimension(NumSurfaces, 0); - SurfWinShadingFlagEMSValue.dimension(NumSurfaces, WinShadingFlag::ShadeOff); + SurfWinShadingFlagEMSValue.dimension(NumSurfaces, WinShadingType::ShadeOff); SurfWinGlareControlIsActive.dimension(NumSurfaces, false); SurfWinStormWinFlag.dimension(NumSurfaces, 0); SurfWinStormWinFlagPrevDay.dimension(NumSurfaces, 0); SurfWinFracTimeShadingDeviceOn.dimension(NumSurfaces, 0); - SurfWinExtIntShadePrevTS.dimension(NumSurfaces, WinShadingFlag::ShadeOff); + SurfWinExtIntShadePrevTS.dimension(NumSurfaces, WinShadingType::ShadeOff); SurfWinHasShadeOrBlindLayer.dimension(NumSurfaces, 0); SurfWinSurfDayLightInit.dimension(NumSurfaces, 0); SurfWinDaylFacPoint.dimension(NumSurfaces, 0); @@ -2035,10 +2035,10 @@ namespace SurfaceGeometry { ConstrNumSh = Surface(SurfNum).activeShadedConstruction; if (ConstrNumSh <= 0) continue; - WinShadingFlag ShadingType = WindowShadingControl(WinShadingControlPtr).ShadingType; + WinShadingType ShadingType = WindowShadingControl(WinShadingControlPtr).ShadingType; // only for blinds - if (ShadingType == WinShadingFlag::ExtBlindOn || ShadingType == WinShadingFlag::IntBlindOn || ShadingType == WinShadingFlag::BGBlindOn) { + if (ShadingType == WinShadingType::ExtBlind || ShadingType == WinShadingType::IntBlind || ShadingType == WinShadingType::BGBlind) { // TH 1/7/2010. CR 7930 // The old code did not consider between-glass blind. Also there should not be two blinds - both interior and exterior @@ -4770,11 +4770,11 @@ namespace SurfaceGeometry { if (ConstrNumSh > 0) { state.dataSurfaceGeometry->SurfaceTmp(SurfNum).activeShadedConstruction = ConstrNumSh; } else { - if (WindowShadingControl(WSCPtr).ShadingType == WinShadingFlag::IntShadeOn || - WindowShadingControl(WSCPtr).ShadingType == WinShadingFlag::IntBlindOn || - WindowShadingControl(WSCPtr).ShadingType == WinShadingFlag::ExtShadeOn || - WindowShadingControl(WSCPtr).ShadingType == WinShadingFlag::ExtScreenOn || - WindowShadingControl(WSCPtr).ShadingType == WinShadingFlag::ExtBlindOn) { + if (WindowShadingControl(WSCPtr).ShadingType == WinShadingType::IntShade || + WindowShadingControl(WSCPtr).ShadingType == WinShadingType::IntBlind || + WindowShadingControl(WSCPtr).ShadingType == WinShadingType::ExtShade || + WindowShadingControl(WSCPtr).ShadingType == WinShadingType::ExtScreen || + WindowShadingControl(WSCPtr).ShadingType == WinShadingType::ExtBlind) { ShDevNum = WindowShadingControl(WSCPtr).ShadingDevice; if (ShDevNum > 0) { CreateShadedWindowConstruction(state, SurfNum, WSCPtr, ShDevNum, shadeControlIndex); @@ -4789,8 +4789,8 @@ namespace SurfaceGeometry { ConstrNum = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction; if (!ErrorsFound && WSCPtr > 0 && ConstrNum > 0 && ConstrNumSh > 0) { - if (WindowShadingControl(WSCPtr).ShadingType == WinShadingFlag::IntShadeOn || - WindowShadingControl(WSCPtr).ShadingType == WinShadingFlag::IntBlindOn) { + if (WindowShadingControl(WSCPtr).ShadingType == WinShadingType::IntShade || + WindowShadingControl(WSCPtr).ShadingType == WinShadingType::IntBlind) { TotLayers = state.dataConstruction->Construct(ConstrNum).TotLayers; TotShLayers = state.dataConstruction->Construct(ConstrNumSh).TotLayers; if (TotShLayers - 1 != TotLayers) { @@ -4813,9 +4813,9 @@ namespace SurfaceGeometry { } } - if (WindowShadingControl(WSCPtr).ShadingType == WinShadingFlag::ExtShadeOn || - WindowShadingControl(WSCPtr).ShadingType == WinShadingFlag::ExtScreenOn || - WindowShadingControl(WSCPtr).ShadingType == WinShadingFlag::ExtBlindOn) { + if (WindowShadingControl(WSCPtr).ShadingType == WinShadingType::ExtShade || + WindowShadingControl(WSCPtr).ShadingType == WinShadingType::ExtScreen || + WindowShadingControl(WSCPtr).ShadingType == WinShadingType::ExtBlind) { TotLayers = state.dataConstruction->Construct(ConstrNum).TotLayers; TotShLayers = state.dataConstruction->Construct(ConstrNumSh).TotLayers; if (TotShLayers - 1 != TotLayers) { @@ -4838,8 +4838,8 @@ namespace SurfaceGeometry { } } - if (WindowShadingControl(WSCPtr).ShadingType == WinShadingFlag::BGShadeOn || - WindowShadingControl(WSCPtr).ShadingType == WinShadingFlag::BGBlindOn) { + if (WindowShadingControl(WSCPtr).ShadingType == WinShadingType::BGShade || + WindowShadingControl(WSCPtr).ShadingType == WinShadingType::BGBlind) { // Divider not allowed with between-glass shade or blind if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).FrameDivider > 0) { if (FrameDivider(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).FrameDivider).DividerWidth > 0.0) { @@ -4882,7 +4882,7 @@ namespace SurfaceGeometry { MatGap1 = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(2 * TotGlassLayers - 2); MatGap2 = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(2 * TotGlassLayers); MatSh = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(2 * TotGlassLayers - 1); - if (WindowShadingControl(WSCPtr).ShadingType == WinShadingFlag::BGBlindOn) { + if (WindowShadingControl(WSCPtr).ShadingType == WinShadingType::BGBlind) { MatGapCalc = std::abs(state.dataMaterial->Material(MatGap).Thickness - (state.dataMaterial->Material(MatGap1).Thickness + state.dataMaterial->Material(MatGap2).Thickness)); if (MatGapCalc > 0.001) { ShowSevereError(state, cRoutineName + ": The gap width(s) for the unshaded window construction " + state.dataConstruction->Construct(ConstrNum).Name); @@ -4970,8 +4970,8 @@ namespace SurfaceGeometry { // Divider not allowed with between-glass shade or blind for (int WSCPtr : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).windowShadingControlList) { if (!ErrorsFound && WSCPtr > 0 && ConstrNumSh > 0) { - if (WindowShadingControl(WSCPtr).ShadingType == WinShadingFlag::BGShadeOn || - WindowShadingControl(WSCPtr).ShadingType == WinShadingFlag::BGBlindOn) { + if (WindowShadingControl(WSCPtr).ShadingType == WinShadingType::BGShade || + WindowShadingControl(WSCPtr).ShadingType == WinShadingType::BGBlind) { if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).FrameDivider > 0) { if (FrameDivider(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).FrameDivider).DividerWidth > 0.0) { ShowSevereError(state, cCurrentModuleObject + "=\"" + state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name + "\", invalid " + @@ -8176,15 +8176,15 @@ namespace SurfaceGeometry { "BETWEENGLASSSHADE", "BETWEENGLASSBLIND", "SWITCHABLEGLAZING"}); - static Array1D const ValidShadingTypes(NumValidShadingTypes, - {WinShadingFlag::IntShadeOn, - WinShadingFlag::ExtShadeOn, - WinShadingFlag::ExtScreenOn, - WinShadingFlag::IntBlindOn, - WinShadingFlag::ExtBlindOn, - WinShadingFlag::BGShadeOn, - WinShadingFlag::BGBlindOn, - WinShadingFlag::SwitchableGlazing}); + static Array1D const ValidShadingTypes(NumValidShadingTypes, + {WinShadingType::IntShade, + WinShadingType::ExtShade, + WinShadingType::ExtScreen, + WinShadingType::IntBlind, + WinShadingType::ExtBlind, + WinShadingType::BGShade, + WinShadingType::BGBlind, + WinShadingType::SwitchableGlazing}); int const NumValidWindowShadingControlTypes(21); static Array1D_string const cValidWindowShadingControlTypes(NumValidWindowShadingControlTypes, @@ -8482,13 +8482,13 @@ namespace SurfaceGeometry { if (cAlphaArgs(3) == "INTERIORNONINSULATINGSHADE" || cAlphaArgs(3) == "INTERIORINSULATINGSHADE") { ShowWarningError(state, cCurrentModuleObject + "=\"" + WindowShadingControl(ControlNum).Name + "\" is using obsolete " + cAlphaFieldNames(3) + "=\"" + cAlphaArgs(3) + "\", changing to \"InteriorShade\""); - WindowShadingControl(ControlNum).ShadingType = WinShadingFlag::IntShadeOn; + WindowShadingControl(ControlNum).ShadingType = WinShadingType::IntShade; cAlphaArgs(3) = "INTERIORSHADE"; } if (cAlphaArgs(3) == "EXTERIORNONINSULATINGSHADE" || cAlphaArgs(3) == "EXTERIORINSULATINGSHADE") { ShowWarningError(state, cCurrentModuleObject + "=\"" + WindowShadingControl(ControlNum).Name + "\" is using obsolete " + cAlphaFieldNames(3) + "=\"" + cAlphaArgs(3) + "\", changing to \"ExteriorShade\""); - WindowShadingControl(ControlNum).ShadingType = WinShadingFlag::ExtShadeOn; + WindowShadingControl(ControlNum).ShadingType = WinShadingType::ExtShade; cAlphaArgs(3) = "EXTERIORSHADE"; } @@ -8510,7 +8510,7 @@ namespace SurfaceGeometry { WindowShadingControl(ControlNum).ShadingType = ValidShadingTypes(Found); } - WinShadingFlag ShTyp = WindowShadingControl(ControlNum).ShadingType; + WinShadingType ShTyp = WindowShadingControl(ControlNum).ShadingType; IShadedConst = WindowShadingControl(ControlNum).getInputShadedConstruction; IShadingDevice = WindowShadingControl(ControlNum).ShadingDevice; @@ -8519,30 +8519,30 @@ namespace SurfaceGeometry { "\" has no matching shaded construction or shading device."); ErrorsFound = true; } else if (IShadedConst == 0 && IShadingDevice > 0) { - if (ShTyp == WinShadingFlag::SwitchableGlazing) { + if (ShTyp == WinShadingType::SwitchableGlazing) { ShowSevereError(state, cCurrentModuleObject + "=\"" + WindowShadingControl(ControlNum).Name + "\" has " + cAlphaArgs(3) + "= SwitchableGlazing but no matching shaded construction"); ErrorsFound = true; } - if ((ShTyp == WinShadingFlag::IntShadeOn || ShTyp == WinShadingFlag::ExtShadeOn) && state.dataMaterial->Material(IShadingDevice).Group != Shade) { + if ((ShTyp == WinShadingType::IntShade || ShTyp == WinShadingType::ExtShade) && state.dataMaterial->Material(IShadingDevice).Group != Shade) { ShowSevereError(state, cCurrentModuleObject + "=\"" + WindowShadingControl(ControlNum).Name + "\" has " + cAlphaArgs(3) + "= InteriorShade or ExteriorShade but matching shading device is not a window shade"); ShowContinueError(state, cAlphaFieldNames(8) + " in error=\"" + state.dataMaterial->Material(IShadingDevice).Name + "\"."); ErrorsFound = true; } - if ((ShTyp == WinShadingFlag::ExtScreenOn) && state.dataMaterial->Material(IShadingDevice).Group != Screen) { + if ((ShTyp == WinShadingType::ExtScreen) && state.dataMaterial->Material(IShadingDevice).Group != Screen) { ShowSevereError(state, cCurrentModuleObject + "=\"" + WindowShadingControl(ControlNum).Name + "\" has " + cAlphaArgs(3) + "= ExteriorScreen but matching shading device is not a window screen"); ShowContinueError(state, cAlphaFieldNames(8) + " in error=\"" + state.dataMaterial->Material(IShadingDevice).Name + "\"."); ErrorsFound = true; } - if ((ShTyp == WinShadingFlag::IntBlindOn || ShTyp == WinShadingFlag::ExtBlindOn) && state.dataMaterial->Material(IShadingDevice).Group != WindowBlind) { + if ((ShTyp == WinShadingType::IntBlind || ShTyp == WinShadingType::ExtBlind) && state.dataMaterial->Material(IShadingDevice).Group != WindowBlind) { ShowSevereError(state, cCurrentModuleObject + "=\"" + WindowShadingControl(ControlNum).Name + "\" has " + cAlphaArgs(3) + "= InteriorBlind or ExteriorBlind but matching shading device is not a window blind"); ShowContinueError(state, cAlphaFieldNames(8) + " in error=\"" + state.dataMaterial->Material(IShadingDevice).Name + "\"."); ErrorsFound = true; } - if (ShTyp == WinShadingFlag::BGShadeOn || ShTyp == WinShadingFlag::BGBlindOn) { + if (ShTyp == WinShadingType::BGShade || ShTyp == WinShadingType::BGBlind) { ShowSevereError(state, cCurrentModuleObject + "=\"" + WindowShadingControl(ControlNum).Name + "\" has " + cAlphaArgs(3) + "= BetweenGlassShade or BetweenGlassBlind and"); ShowContinueError(state, cAlphaFieldNames(8) + " is specified. This is illegal. Specify shaded construction instead."); @@ -8563,7 +8563,7 @@ namespace SurfaceGeometry { BGShadeBlindError = false; IShadingDevice = 0; if (state.dataConstruction->Construct(IShadedConst).LayerPoint(NLayers) != 0) { - if (WindowShadingControl(ControlNum).ShadingType == WinShadingFlag::IntShadeOn) { + if (WindowShadingControl(ControlNum).ShadingType == WinShadingType::IntShade) { IShadingDevice = state.dataConstruction->Construct(IShadedConst).LayerPoint(NLayers); if (state.dataMaterial->Material(state.dataConstruction->Construct(IShadedConst).LayerPoint(NLayers)).Group != Shade) { ErrorsFound = true; @@ -8572,7 +8572,7 @@ namespace SurfaceGeometry { ShowContinueError(state, "of " + cAlphaFieldNames(3) + "=\"" + cAlphaArgs(3) + "\" should have a shade layer on the inside of the window."); } - } else if (WindowShadingControl(ControlNum).ShadingType == WinShadingFlag::ExtShadeOn) { + } else if (WindowShadingControl(ControlNum).ShadingType == WinShadingType::ExtShade) { IShadingDevice = state.dataConstruction->Construct(IShadedConst).LayerPoint(1); if (state.dataMaterial->Material(state.dataConstruction->Construct(IShadedConst).LayerPoint(1)).Group != Shade) { ErrorsFound = true; @@ -8581,7 +8581,7 @@ namespace SurfaceGeometry { ShowContinueError(state, "of " + cAlphaFieldNames(3) + "=\"" + cAlphaArgs(3) + "\" should have a shade layer on the outside of the window."); } - } else if (WindowShadingControl(ControlNum).ShadingType == WinShadingFlag::ExtScreenOn) { + } else if (WindowShadingControl(ControlNum).ShadingType == WinShadingType::ExtScreen) { IShadingDevice = state.dataConstruction->Construct(IShadedConst).LayerPoint(1); if (state.dataMaterial->Material(state.dataConstruction->Construct(IShadedConst).LayerPoint(1)).Group != Screen) { ErrorsFound = true; @@ -8590,7 +8590,7 @@ namespace SurfaceGeometry { ShowContinueError(state, "of " + cAlphaFieldNames(3) + "=\"" + cAlphaArgs(3) + "\" should have a screen layer on the outside of the window."); } - } else if (WindowShadingControl(ControlNum).ShadingType == WinShadingFlag::IntBlindOn) { + } else if (WindowShadingControl(ControlNum).ShadingType == WinShadingType::IntBlind) { IShadingDevice = state.dataConstruction->Construct(IShadedConst).LayerPoint(NLayers); if (state.dataMaterial->Material(state.dataConstruction->Construct(IShadedConst).LayerPoint(NLayers)).Group != WindowBlind) { ErrorsFound = true; @@ -8599,7 +8599,7 @@ namespace SurfaceGeometry { ShowContinueError(state, "of " + cAlphaFieldNames(3) + "=\"" + cAlphaArgs(3) + "\" should have a blind layer on the inside of the window."); } - } else if (WindowShadingControl(ControlNum).ShadingType == WinShadingFlag::ExtBlindOn) { + } else if (WindowShadingControl(ControlNum).ShadingType == WinShadingType::ExtBlind) { IShadingDevice = state.dataConstruction->Construct(IShadedConst).LayerPoint(1); if (state.dataMaterial->Material(state.dataConstruction->Construct(IShadedConst).LayerPoint(1)).Group != WindowBlind) { ErrorsFound = true; @@ -8608,7 +8608,7 @@ namespace SurfaceGeometry { ShowContinueError(state, "of " + cAlphaFieldNames(3) + "=\"" + cAlphaArgs(3) + "\" should have a blind layer on the outside of the window."); } - } else if (WindowShadingControl(ControlNum).ShadingType == WinShadingFlag::BGShadeOn) { + } else if (WindowShadingControl(ControlNum).ShadingType == WinShadingType::BGShade) { if (NLayers != 5 && NLayers != 7) BGShadeBlindError = true; if (NLayers == 5) { if (state.dataMaterial->Material(state.dataConstruction->Construct(IShadedConst).LayerPoint(3)).Group != Shade) BGShadeBlindError = true; @@ -8624,7 +8624,7 @@ namespace SurfaceGeometry { "\" should have two or three glass layers and a"); ShowContinueError(state, "between-glass shade layer with a gas layer on each side."); } - } else if (WindowShadingControl(ControlNum).ShadingType == WinShadingFlag::BGBlindOn) { + } else if (WindowShadingControl(ControlNum).ShadingType == WinShadingType::BGBlind) { if (NLayers != 5 && NLayers != 7) BGShadeBlindError = true; if (NLayers == 5) { if (state.dataMaterial->Material(state.dataConstruction->Construct(IShadedConst).LayerPoint(3)).Group != WindowBlind) BGShadeBlindError = true; @@ -8642,19 +8642,19 @@ namespace SurfaceGeometry { } } if (IShadingDevice > 0) { - if ((ShTyp == WinShadingFlag::IntShadeOn || ShTyp == WinShadingFlag::ExtShadeOn) && state.dataMaterial->Material(IShadingDevice).Group != Shade) { + if ((ShTyp == WinShadingType::IntShade || ShTyp == WinShadingType::ExtShade) && state.dataMaterial->Material(IShadingDevice).Group != Shade) { ShowSevereError(state, cCurrentModuleObject + "=\"" + WindowShadingControl(ControlNum).Name + "\" has " + cAlphaFieldNames(3) + "= InteriorShade or ExteriorShade but matching shading device is not a window shade"); ShowContinueError(state, "Shading Device in error=\"" + state.dataMaterial->Material(IShadingDevice).Name + "\"."); ErrorsFound = true; } - if ((ShTyp == WinShadingFlag::ExtScreenOn) && state.dataMaterial->Material(IShadingDevice).Group != Screen) { + if ((ShTyp == WinShadingType::ExtScreen) && state.dataMaterial->Material(IShadingDevice).Group != Screen) { ShowSevereError(state, cCurrentModuleObject + "=\"" + WindowShadingControl(ControlNum).Name + "\" has " + cAlphaFieldNames(3) + "= ExteriorScreen but matching shading device is not an exterior window screen."); ShowContinueError(state, "Shading Device in error=\"" + state.dataMaterial->Material(IShadingDevice).Name + "\"."); ErrorsFound = true; } - if ((ShTyp == WinShadingFlag::IntBlindOn || ShTyp == WinShadingFlag::ExtBlindOn) && state.dataMaterial->Material(IShadingDevice).Group != WindowBlind) { + if ((ShTyp == WinShadingType::IntBlind || ShTyp == WinShadingType::ExtBlind) && state.dataMaterial->Material(IShadingDevice).Group != WindowBlind) { ShowSevereError(state, cCurrentModuleObject + "=\"" + WindowShadingControl(ControlNum).Name + "\" has " + cAlphaFieldNames(3) + "= InteriorBlind or ExteriorBlind but matching shading device is not a window blind."); ShowContinueError(state, "Shading Device in error=\"" + state.dataMaterial->Material(IShadingDevice).Name + "\"."); @@ -9175,8 +9175,8 @@ namespace SurfaceGeometry { if (Surface(SurfNum).HasShadeControl) { for (std::size_t listIndex = 0; listIndex < Surface(SurfNum).windowShadingControlList.size(); ++listIndex) { int WSCPtr = Surface(SurfNum).windowShadingControlList[listIndex]; - if (WindowShadingControl(WSCPtr).ShadingType == WinShadingFlag::BGShadeOn || - WindowShadingControl(WSCPtr).ShadingType == WinShadingFlag::BGBlindOn) { + if (WindowShadingControl(WSCPtr).ShadingType == WinShadingType::BGShade || + WindowShadingControl(WSCPtr).ShadingType == WinShadingType::BGBlind) { ConstrNumSh = Surface(SurfNum).shadedConstructionList[listIndex]; if (state.dataConstruction->Construct(ConstrNum).TotGlassLayers == 2) { MatGapFlow1 = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(2); @@ -11688,7 +11688,7 @@ namespace SurfaceGeometry { ShDevName = state.dataMaterial->Material(ShDevNum).Name; ConstrNum = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction; ConstrName = state.dataConstruction->Construct(ConstrNum).Name; - if (WindowShadingControl(WSCPtr).ShadingType == WinShadingFlag::IntShadeOn || WindowShadingControl(WSCPtr).ShadingType == WinShadingFlag::IntBlindOn) { + if (WindowShadingControl(WSCPtr).ShadingType == WinShadingType::IntShade || WindowShadingControl(WSCPtr).ShadingType == WinShadingType::IntBlind) { ConstrNameSh = ConstrName + ':' + ShDevName + ":INT"; } else { ConstrNameSh = ConstrName + ':' + ShDevName + ":EXT"; @@ -11720,8 +11720,8 @@ namespace SurfaceGeometry { state.dataConstruction->Construct(ConstrNewSh).LayerPoint = 0; - if (WindowShadingControl(WSCPtr).ShadingType == WinShadingFlag::IntShadeOn || - WindowShadingControl(WSCPtr).ShadingType == WinShadingFlag::IntBlindOn) { + if (WindowShadingControl(WSCPtr).ShadingType == WinShadingType::IntShade || + WindowShadingControl(WSCPtr).ShadingType == WinShadingType::IntBlind) { // Interior shading device state.dataConstruction->Construct(ConstrNewSh).LayerPoint({1, TotLayersOld}) = state.dataConstruction->Construct(ConstrNum).LayerPoint({1, TotLayersOld}); state.dataConstruction->Construct(ConstrNewSh).LayerPoint(TotLayersNew) = ShDevNum; diff --git a/src/EnergyPlus/SwimmingPool.cc b/src/EnergyPlus/SwimmingPool.cc index 987230df85d..a40ac90cb36 100644 --- a/src/EnergyPlus/SwimmingPool.cc +++ b/src/EnergyPlus/SwimmingPool.cc @@ -1025,8 +1025,8 @@ namespace SwimmingPool { Real64 Area = DataSurfaces::Surface(SurfNum).Area; // Effective surface area if (DataSurfaces::Surface(SurfNum).Class == DataSurfaces::SurfaceClass::Window) { - if (DataSurfaces::SurfWinShadingFlag(SurfNum) == DataSurfaces::WinShadingFlag::IntShadeOn || - DataSurfaces::SurfWinShadingFlag(SurfNum) == DataSurfaces::WinShadingFlag::IntBlindOn) { + if (DataSurfaces::SurfWinShadingFlag(SurfNum) == DataSurfaces::WinShadingType::IntShade || + DataSurfaces::SurfWinShadingFlag(SurfNum) == DataSurfaces::WinShadingType::IntBlind) { // The area is the shade or blind are = sum of the glazing area and the divider area (which is zero if no divider) Area += DataSurfaces::SurfWinDividerArea(SurfNum); } @@ -1038,8 +1038,8 @@ namespace SwimmingPool { } if (DataSurfaces::SurfWinDividerArea(SurfNum) > 0.0 && - DataSurfaces::SurfWinShadingFlag(SurfNum) != DataSurfaces::WinShadingFlag::IntShadeOn && - DataSurfaces::SurfWinShadingFlag(SurfNum) != DataSurfaces::WinShadingFlag::IntBlindOn) { + DataSurfaces::SurfWinShadingFlag(SurfNum) != DataSurfaces::WinShadingType::IntShade && + DataSurfaces::SurfWinShadingFlag(SurfNum) != DataSurfaces::WinShadingType::IntBlind) { // Window divider contribution (only from shade or blind for window with divider and interior shade or blind) SumHATsurf += DataHeatBalance::HConvIn(SurfNum) * DataSurfaces::SurfWinDividerArea(SurfNum) * (1.0 + 2.0 * DataSurfaces::SurfWinProjCorrDivIn(SurfNum)) * diff --git a/src/EnergyPlus/UFADManager.cc b/src/EnergyPlus/UFADManager.cc index 660216af401..3f115278cd6 100644 --- a/src/EnergyPlus/UFADManager.cc +++ b/src/EnergyPlus/UFADManager.cc @@ -212,7 +212,7 @@ namespace UFADManager { if (SurfNum == 0) continue; if (Surface(SurfNum).ExtBoundCond == ExternalEnvironment || Surface(SurfNum).ExtBoundCond == OtherSideCoefNoCalcExt || Surface(SurfNum).ExtBoundCond == OtherSideCoefCalcExt || Surface(SurfNum).ExtBoundCond == OtherSideCondModeledExt) { - if (SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntShadeOn || SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntBlindOn) { + if (SurfWinShadingFlag(SurfNum) == WinShadingType::IntShade || SurfWinShadingFlag(SurfNum) == WinShadingType::IntBlind) { ++NumShadesDown; } } diff --git a/src/EnergyPlus/VentilatedSlab.cc b/src/EnergyPlus/VentilatedSlab.cc index 3dfc314c88d..0c52fda9a81 100644 --- a/src/EnergyPlus/VentilatedSlab.cc +++ b/src/EnergyPlus/VentilatedSlab.cc @@ -4459,7 +4459,7 @@ namespace VentilatedSlab { Area = Surface(SurfNum).Area; if (Surface(SurfNum).Class == SurfaceClass::Window) { - if (SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntShadeOn || SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntBlindOn) { + if (SurfWinShadingFlag(SurfNum) == WinShadingType::IntShade || SurfWinShadingFlag(SurfNum) == WinShadingType::IntBlind) { // The area is the shade or blind are = sum of the glazing area and the divider area (which is zero if no divider) Area += SurfWinDividerArea(SurfNum); } @@ -4470,8 +4470,8 @@ namespace VentilatedSlab { SurfWinFrameTempSurfIn(SurfNum); } - if (SurfWinDividerArea(SurfNum) > 0.0 && SurfWinShadingFlag(SurfNum) != WinShadingFlag::IntShadeOn && - SurfWinShadingFlag(SurfNum) != WinShadingFlag::IntBlindOn) { + if (SurfWinDividerArea(SurfNum) > 0.0 && SurfWinShadingFlag(SurfNum) != WinShadingType::IntShade && + SurfWinShadingFlag(SurfNum) != WinShadingType::IntBlind) { // Window divider contribution (only from shade or blind for window with divider and interior shade or blind) SumHATsurf += HConvIn(SurfNum) * SurfWinDividerArea(SurfNum) * (1.0 + 2.0 * SurfWinProjCorrDivIn(SurfNum)) * SurfWinDividerTempSurfIn(SurfNum); diff --git a/src/EnergyPlus/WindowComplexManager.cc b/src/EnergyPlus/WindowComplexManager.cc index 4bcaaa70bb7..9c09350f7b8 100644 --- a/src/EnergyPlus/WindowComplexManager.cc +++ b/src/EnergyPlus/WindowComplexManager.cc @@ -2642,7 +2642,7 @@ namespace WindowComplexManager { int k; // Layer counter int SurfNumAdj; // An interzone surface's number in the adjacent zone int ZoneNumAdj; // An interzone surface's adjacent zone number - WinShadingFlag ShadeFlag; // Flag indicating whether shade or blind is on, and shade/blind position + WinShadingType ShadeFlag; // Flag indicating whether shade or blind is on, and shade/blind position int IMix; Real64 IncidentSolar; // Solar incident on outside of window (W) @@ -2901,7 +2901,7 @@ namespace WindowComplexManager { // outdoor wind speed if (!Surface(SurfNum).ExtWind) { wso = 0.0; // No wind exposure - // ELSE IF (Surface(SurfNum)%Class == SurfaceClass::Window .AND. SurfaceWindow(SurfNum)%ShadingFlag == WinShadingFlag::ExtShadeOn) THEN + // ELSE IF (Surface(SurfNum)%Class == SurfaceClass::Window .AND. SurfaceWindow(SurfNum)%ShadingFlag == WinShadingType::ExtShade) THEN // wso = 0.0 ! Assume zero wind speed at outside glass surface of window with exterior shade } else { wso = Surface(SurfNum).WindSpeed; @@ -3298,7 +3298,7 @@ namespace WindowComplexManager { SurfOutsideEmiss = emis(1); IncidentSolar = Surface(SurfNum).Area * SurfQRadSWOutIncident(SurfNum); - if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn) { + if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::IntBlind) { // Interior shade or blind ConvHeatFlowNatural = -qv(nlayer) * height * width; @@ -3344,7 +3344,7 @@ namespace WindowComplexManager { SurfWinGainConvGlazToZoneRep(SurfNum) = ConvHeatGainFrZoneSideOfGlass; SurfWinGainIRGlazToZoneRep(SurfNum) = NetIRHeatGainGlass; // need to report convective heat flow from the gap in case of exterior shade - if (ShadeFlag == WinShadingFlag::ExtShadeOn) { + if (ShadeFlag == WinShadingType::ExtShade) { ConvHeatFlowNatural = -qv(2) * height * width; // qv(1) is exterior environment SurfWinGapConvHtFlowRep(SurfNum) = ConvHeatFlowNatural; @@ -3404,9 +3404,9 @@ namespace WindowComplexManager { // TransDiff = Construct(ConstrNum).TransDiff; int IState = SurfaceWindow(SurfNum).ComplexFen.NumStates; Real64 TransDiff = SurfaceWindow(SurfNum).ComplexFen.State(IState).WinDiffTrans; - // ELSE IF(ShadeFlag==WinShadingFlag::IntShadeOn .OR. ShadeFlag==WinShadingFlag::ExtShadeOn) THEN + // ELSE IF(ShadeFlag==WinShadingType::IntShade .OR. ShadeFlag==WinShadingType::ExtShade) THEN // TransDiff = Construct(ConstrNum)%TransDiff - // ELSE IF(ShadeFlag==WinShadingFlag::IntBlindOn .OR. ShadeFlag==WinShadingFlag::ExtBlindOn .OR.ShadeFlag==WinShadingFlag::BGBlindOn) THEN + // ELSE IF(ShadeFlag==WinShadingType::IntBlind .OR. ShadeFlag==WinShadingType::ExtBlind .OR.ShadeFlag==WinShadingType::BGBlind) THEN // TransDiff = InterpSlatAng(SurfaceWindow(SurfNum)%SlatAngThisTS,SurfaceWindow(SurfNum)%MovableSlats, & // Construct(ConstrNumSh)%BlTransDiff) // ELSE IF(ShadeFlag == SwitchableGlazing) THEN @@ -3417,7 +3417,7 @@ namespace WindowComplexManager { SurfWinHeatTransfer(SurfNum) -= QS(Surface(SurfNum).SolarEnclIndex) * Surface(SurfNum).Area * TransDiff; SurfWinLossSWZoneToOutWinRep(SurfNum) = QS(Surface(SurfNum).SolarEnclIndex) * Surface(SurfNum).Area * TransDiff; - if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn) { + if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::ExtShade) { SurfWinShadingAbsorbedSolar(SurfNum) = (SurfWinExtBeamAbsByShade(SurfNum) + SurfWinExtDiffAbsByShade(SurfNum)) * (Surface(SurfNum).Area + SurfWinDividerArea(SurfNum)); SurfWinShadingAbsorbedSolarEnergy(SurfNum) = SurfWinShadingAbsorbedSolar(SurfNum) * state.dataGlobal->TimeStepZoneSec; @@ -3435,9 +3435,9 @@ namespace WindowComplexManager { } // Save hcv for use in divider calc with interior or exterior shade (see CalcWinFrameAndDividerTemps) - if (ShadeFlag == WinShadingFlag::IntShadeOn) SurfWinConvCoeffWithShade(SurfNum) = 0.0; + if (ShadeFlag == WinShadingType::IntShade) SurfWinConvCoeffWithShade(SurfNum) = 0.0; - if (ShadeFlag == WinShadingFlag::IntShadeOn) { + if (ShadeFlag == WinShadingType::IntShade) { SurfInsideTemp = theta(2 * ngllayer + 2) - DataGlobalConstants::KelvinConv; // // Get properties of inside shading layer diff --git a/src/EnergyPlus/WindowManager.cc b/src/EnergyPlus/WindowManager.cc index 99ff475737f..0f650963840 100644 --- a/src/EnergyPlus/WindowManager.cc +++ b/src/EnergyPlus/WindowManager.cc @@ -1544,8 +1544,8 @@ namespace WindowManager { if (Surface(SurfNum).HasShadeControl) { for (int winShadCtrl : Surface(SurfNum).windowShadingControlList) { - WinShadingFlag ShadingType = WindowShadingControl(winShadCtrl).ShadingType; - if (ShadingType == WinShadingFlag::ExtScreenOn) { + WinShadingType ShadingType = WindowShadingControl(winShadCtrl).ShadingType; + if (ShadingType == WinShadingType::ExtScreen) { // Count number of exterior window screens, initialize in InitGlassOpticalCalculations after returning // from this subroutine. The blind structure is initialized first and then the screen structure is initialized. ++NumSurfaceScreens; @@ -1615,7 +1615,7 @@ namespace WindowManager { if (!Surface(SurfNum).HasShadeControl) { SurfWinSolarDiffusing(SurfNum) = true; } else { // There is a shading control - if (WindowShadingControl(Surface(SurfNum).activeWindowShadingControl).ShadingType == WinShadingFlag::SwitchableGlazing) { + if (WindowShadingControl(Surface(SurfNum).activeWindowShadingControl).ShadingType == WinShadingType::SwitchableGlazing) { SurfWinSolarDiffusing(SurfNum) = true; } else { SurfWinSolarDiffusing(SurfNum) = false; @@ -2063,7 +2063,7 @@ namespace WindowManager { int IGap; // Gap layer number (1,2,...) int IMix; // Gas number in a mixture of gases int ICoeff; // Gas property index (1,2,3) - WinShadingFlag ShadeFlag; // Flag indicating whether shade or blind is on, and shade/blind position + WinShadingType ShadeFlag; // Flag indicating whether shade or blind is on, and shade/blind position int k; // Layer counter // REAL(r64) :: tsky ! Sky temperature [K] int ShadeLayPtr; // Material number corresponding to a shade layer @@ -2320,8 +2320,8 @@ namespace WindowManager { // blind/shade and glass 3. IConst = ConstrNum; - if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::BGShadeOn || - ShadeFlag == WinShadingFlag::BGBlindOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { + if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::ExtShade || ShadeFlag == WinShadingType::IntBlind || ShadeFlag == WinShadingType::ExtBlind || ShadeFlag == WinShadingType::BGShade || + ShadeFlag == WinShadingType::BGBlind || ShadeFlag == WinShadingType::ExtScreen) { IConst = surface.activeShadedConstruction; if (SurfWinStormWinFlag(SurfNum) > 0) IConst = surface.activeStormWinShadedConstruction; } @@ -2345,13 +2345,13 @@ namespace WindowManager { } if (state.dataMaterial->Material(LayPtr).Group == Shade || state.dataMaterial->Material(LayPtr).Group == WindowBlind || state.dataMaterial->Material(LayPtr).Group == Screen) { - if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn) ShadeLayPtr = state.dataConstruction->Construct(IConst).LayerPoint(state.dataConstruction->Construct(IConst).TotLayers); - if (ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::ExtScreenOn) ShadeLayPtr = state.dataConstruction->Construct(IConst).LayerPoint(1); - if (ShadeFlag == WinShadingFlag::BGShadeOn || ShadeFlag == WinShadingFlag::BGBlindOn) { + if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::IntBlind) ShadeLayPtr = state.dataConstruction->Construct(IConst).LayerPoint(state.dataConstruction->Construct(IConst).TotLayers); + if (ShadeFlag == WinShadingType::ExtShade || ShadeFlag == WinShadingType::ExtBlind || ShadeFlag == WinShadingType::ExtScreen) ShadeLayPtr = state.dataConstruction->Construct(IConst).LayerPoint(1); + if (ShadeFlag == WinShadingType::BGShade || ShadeFlag == WinShadingType::BGBlind) { ShadeLayPtr = state.dataConstruction->Construct(IConst).LayerPoint(3); if (TotGlassLay == 3) ShadeLayPtr = state.dataConstruction->Construct(IConst).LayerPoint(5); } - if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::BGShadeOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { + if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::ExtShade || ShadeFlag == WinShadingType::BGShade || ShadeFlag == WinShadingType::ExtScreen) { // Shade or screen on if (state.dataGlobal->AnyEnergyManagementSystemInModel) { // check to make sure the user hasn't messed up the shade control values if (state.dataMaterial->Material(ShadeLayPtr).Group == WindowBlind) { @@ -2363,7 +2363,7 @@ namespace WindowManager { } state.dataWindowManager->thick(TotGlassLay + 1) = state.dataMaterial->Material(ShadeLayPtr).Thickness; state.dataWindowManager->scon(TotGlassLay + 1) = state.dataMaterial->Material(ShadeLayPtr).Conductivity / state.dataMaterial->Material(ShadeLayPtr).Thickness; - if (ShadeFlag == WinShadingFlag::ExtScreenOn) { + if (ShadeFlag == WinShadingType::ExtScreen) { state.dataWindowManager->emis(state.dataWindowManager->nglface + 1) = state.dataMaterial->Material(ShadeLayPtr).AbsorpThermalFront; state.dataWindowManager->tir(state.dataWindowManager->nglface + 1) = SurfaceScreens(state.dataMaterial->Material(ShadeLayPtr).ScreenDataPtr).DifDifTrans; state.dataWindowManager->tir(state.dataWindowManager->nglface + 2) = SurfaceScreens(state.dataMaterial->Material(ShadeLayPtr).ScreenDataPtr).DifDifTrans; @@ -2411,12 +2411,12 @@ namespace WindowManager { } // End of loop over glass, gap and blind/shade layers in a window construction - if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn || - ShadeFlag == WinShadingFlag::ExtScreenOn) { + if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::ExtShade || ShadeFlag == WinShadingType::IntBlind || ShadeFlag == WinShadingType::ExtBlind || + ShadeFlag == WinShadingType::ExtScreen) { // Interior or exterior blind, shade or screen is on. // Fill gap between blind/shade and adjacent glass with air properties. ++IGap; - if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { // Interior or exterior shade + if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::ExtShade || ShadeFlag == WinShadingType::ExtScreen) { // Interior or exterior shade state.dataWindowManager->gap(IGap) = state.dataMaterial->Material(ShadeLayPtr).WinShadeToGlassDist; } else { // Interior or exterior blind state.dataWindowManager->gap(IGap) = Blind(SurfWinBlindNumber(SurfNum)).BlindToGlassDist; @@ -2563,7 +2563,7 @@ namespace WindowManager { dth3 = state.dataWindowManager->thetas(6) - state.dataWindowManager->thetas(5); dth4 = state.dataWindowManager->thetas(8) - state.dataWindowManager->thetas(7); - if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn) { + if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::IntBlind) { SurfInsideTemp = state.dataWindowManager->thetas(2 * state.dataWindowManager->ngllayer + 2) - state.dataWindowManager->TKelvin; EffShBlEmiss = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), window.EffShBlindEmiss); EffGlEmiss = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), window.EffGlassEmiss); @@ -2571,7 +2571,7 @@ namespace WindowManager { } else { SurfInsideTemp = state.dataWindowManager->thetas(2 * state.dataWindowManager->ngllayer) - state.dataWindowManager->TKelvin; } - if (ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { + if (ShadeFlag == WinShadingType::ExtShade || ShadeFlag == WinShadingType::ExtBlind || ShadeFlag == WinShadingType::ExtScreen) { SurfOutsideTemp = state.dataWindowManager->thetas(2 * state.dataWindowManager->ngllayer + 1) - state.dataWindowManager->TKelvin; // this index looks suspicious (CR 8202) // SurfOutsideEmiss = emis(1) ! this index should be coordinated with previous line SurfOutsideEmiss = state.dataWindowManager->emis(2 * state.dataWindowManager->ngllayer + 1); // fix for CR 8202 @@ -2886,7 +2886,7 @@ namespace WindowManager { // 2=exterior shade/blind Real64 TauShIR; // Long-wave transmittance of isolated shade/blind Real64 sconsh; // shade/blind conductance (W/m2-K) - WinShadingFlag ShadeFlag; // Shading flag + WinShadingType ShadeFlag; // Shading flag // Real64 ShadeAbsFac1; // Fractions for apportioning absorbed radiation to shade/blind faces // Real64 ShadeAbsFac2; static Array1D AbsRadShadeFace(2); // Solar radiation, short-wave radiation from lights, and long-wave //Tuned Made static @@ -2938,22 +2938,22 @@ namespace WindowManager { AbsRadShadeFace = 0.0; TGapNew = 0.0; - if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::BGShadeOn || - ShadeFlag == WinShadingFlag::BGBlindOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { + if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::ExtShade || ShadeFlag == WinShadingType::IntBlind || ShadeFlag == WinShadingType::ExtBlind || ShadeFlag == WinShadingType::BGShade || + ShadeFlag == WinShadingType::BGBlind || ShadeFlag == WinShadingType::ExtScreen) { state.dataWindowManager->nglfacep = state.dataWindowManager->nglface + 2; AbsRadShadeFace(1) = DataSurfaces::AbsFrontSide(SurfNum); AbsRadShadeFace(2) = DataSurfaces::AbsBackSide(SurfNum); - if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn) AbsRadShadeFace(2) += SurfWinIntLWAbsByShade(SurfNum); + if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::IntBlind) AbsRadShadeFace(2) += SurfWinIntLWAbsByShade(SurfNum); sconsh = state.dataWindowManager->scon(state.dataWindowManager->ngllayer + 1); TauShIR = state.dataWindowManager->tir(state.dataWindowManager->nglface + 1); EpsShIR1 = state.dataWindowManager->emis(state.dataWindowManager->nglface + 1); EpsShIR2 = state.dataWindowManager->emis(state.dataWindowManager->nglface + 2); RhoShIR1 = max(0.0, 1.0 - TauShIR - EpsShIR1); RhoShIR2 = max(0.0, 1.0 - TauShIR - EpsShIR2); - if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn) { + if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::IntBlind) { RhoGlIR2 = 1.0 - state.dataWindowManager->emis(2 * state.dataWindowManager->ngllayer); ShGlReflFacIR = 1.0 - RhoGlIR2 * RhoShIR1; - } else if (ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { + } else if (ShadeFlag == WinShadingType::ExtShade || ShadeFlag == WinShadingType::ExtBlind || ShadeFlag == WinShadingType::ExtScreen) { RhoGlIR1 = 1.0 - state.dataWindowManager->emis(1); ShGlReflFacIR = 1.0 - RhoGlIR1 * RhoShIR2; } @@ -2985,7 +2985,7 @@ namespace WindowManager { (Surface(SurfNum).IntConvCoeff == -2)) { // coef model is "detailed" and not prescribed by user // need to find inside face index, varies with shade/blind etc. - if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn) { + if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::IntBlind) { InsideFaceIndex = state.dataWindowManager->nglfacep; } else { InsideFaceIndex = state.dataWindowManager->nglface; @@ -3001,8 +3001,8 @@ namespace WindowManager { // coefficient from glass and shade/blind to gap between glass and shade/blind, // effective gap air temperature, velocity of air in gap and gap outlet temperature. - if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn || - ShadeFlag == WinShadingFlag::ExtScreenOn) { + if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::ExtShade || ShadeFlag == WinShadingType::IntBlind || ShadeFlag == WinShadingType::ExtBlind || + ShadeFlag == WinShadingType::ExtScreen) { ExtOrIntShadeNaturalFlow(state, SurfNum, iter, VGap, TGapNew, TGapOutlet, hcv, ConvHeatFlowNatural); if (iter >= 1) { hcv = 0.5 * (hcvPrev + hcv); @@ -3018,7 +3018,7 @@ namespace WindowManager { // get glass-to-air forced convection heat transfer coefficient, average gap air temperature, and // convective heat flow from gap. - if (ShadeFlag != WinShadingFlag::BGShadeOn && ShadeFlag != WinShadingFlag::BGBlindOn && SurfWinAirflowThisTS(SurfNum) > 0.0) { + if (ShadeFlag != WinShadingType::BGShade && ShadeFlag != WinShadingType::BGBlind && SurfWinAirflowThisTS(SurfNum) > 0.0) { BetweenGlassForcedFlow(state, SurfNum, iter, VAirflowGap, TAirflowGapNew, TAirflowGapOutlet, hcvAirflowGap, ConvHeatFlowForced); } @@ -3027,7 +3027,7 @@ namespace WindowManager { // Also get average gas temperature in the two gaps, and, for airflow window, the sum of the // convective heat flows from the gaps. - if (ShadeFlag == WinShadingFlag::BGShadeOn || ShadeFlag == WinShadingFlag::BGBlindOn) { + if (ShadeFlag == WinShadingType::BGShade || ShadeFlag == WinShadingType::BGBlind) { if (SurfWinAirflowThisTS(SurfNum) == 0.0) { // Natural convection in gaps BetweenGlassShadeNaturalFlow(state, SurfNum, iter, VGap, TGapNewBG, hcvBG); } else { // Forced convection in gaps @@ -3051,7 +3051,7 @@ namespace WindowManager { Aface(1, 2) = -state.dataWindowManager->scon(1); Aface(2, 2) = hr(2) + state.dataWindowManager->scon(1) + state.dataWindowManager->hcin; - if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn) { + if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::IntBlind) { Bface(2) = state.dataWindowManager->Rmir * state.dataWindowManager->emis(2) * TauShIR / ShGlReflFacIR + hcv * TGapNew + state.dataWindowManager->AbsRadGlassFace(2); Bface(3) = state.dataWindowManager->Rmir * TauShIR * RhoGlIR2 * EpsShIR1 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(1); Bface(4) = state.dataWindowManager->Rmir * EpsShIR2 + state.dataWindowManager->hcin * state.dataWindowManager->tin + AbsRadShadeFace(2); @@ -3065,7 +3065,7 @@ namespace WindowManager { Aface(4, 4) = hr(4) + sconsh + state.dataWindowManager->hcin; } - if (ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { + if (ShadeFlag == WinShadingType::ExtShade || ShadeFlag == WinShadingType::ExtBlind || ShadeFlag == WinShadingType::ExtScreen) { Bface(1) = state.dataWindowManager->Outir * state.dataWindowManager->emis(1) * TauShIR / ShGlReflFacIR + hcv * TGapNew + state.dataWindowManager->AbsRadGlassFace(1); Bface(3) = state.dataWindowManager->Outir * EpsShIR1 + state.dataWindowManager->hcout * state.dataWindowManager->tout + AbsRadShadeFace(1); Bface(4) = state.dataWindowManager->Outir * TauShIR * RhoGlIR1 * EpsShIR2 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(2); @@ -3107,7 +3107,7 @@ namespace WindowManager { Aface(3, 4) = -state.dataWindowManager->scon(2); Aface(4, 4) = hr(4) + state.dataWindowManager->scon(2) + state.dataWindowManager->hcin; - if (ShadeFlag != WinShadingFlag::BGShadeOn && ShadeFlag != WinShadingFlag::BGBlindOn && SurfWinAirflowThisTS(SurfNum) > 0.0) { + if (ShadeFlag != WinShadingType::BGShade && ShadeFlag != WinShadingType::BGBlind && SurfWinAirflowThisTS(SurfNum) > 0.0) { Bface(2) = state.dataWindowManager->AbsRadGlassFace(2) + hcvAirflowGap * TAirflowGapNew; Bface(3) = state.dataWindowManager->AbsRadGlassFace(3) + hcvAirflowGap * TAirflowGapNew; Aface(2, 2) = state.dataWindowManager->scon(1) + hcvAirflowGap - state.dataWindowManager->A23P * hr(2); @@ -3116,7 +3116,7 @@ namespace WindowManager { Aface(3, 3) = hcvAirflowGap + state.dataWindowManager->scon(2) + state.dataWindowManager->A32P * hr(3); } - if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn) { + if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::IntBlind) { Bface(4) = state.dataWindowManager->Rmir * state.dataWindowManager->emis(4) * TauShIR / ShGlReflFacIR + hcv * TGapNew + state.dataWindowManager->AbsRadGlassFace(4); Bface(5) = state.dataWindowManager->Rmir * TauShIR * RhoGlIR2 * EpsShIR1 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(1); Bface(6) = state.dataWindowManager->Rmir * EpsShIR2 + state.dataWindowManager->hcin * state.dataWindowManager->tin + AbsRadShadeFace(2); @@ -3130,7 +3130,7 @@ namespace WindowManager { Aface(6, 6) = hr(6) + sconsh + state.dataWindowManager->hcin; } - if (ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { + if (ShadeFlag == WinShadingType::ExtShade || ShadeFlag == WinShadingType::ExtBlind || ShadeFlag == WinShadingType::ExtScreen) { Bface(1) = state.dataWindowManager->Outir * state.dataWindowManager->emis(1) * TauShIR / ShGlReflFacIR + hcv * TGapNew + state.dataWindowManager->AbsRadGlassFace(1); Bface(5) = state.dataWindowManager->Outir * EpsShIR1 + state.dataWindowManager->hcout * state.dataWindowManager->tout + AbsRadShadeFace(1); Bface(6) = state.dataWindowManager->Outir * TauShIR * RhoGlIR1 * EpsShIR2 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(2); @@ -3144,7 +3144,7 @@ namespace WindowManager { Aface(6, 6) = hr(6) * (1 - RhoGlIR1 * (EpsShIR2 + RhoShIR2)) / ShGlReflFacIR + sconsh + hcv; } - if (ShadeFlag == WinShadingFlag::BGShadeOn || ShadeFlag == WinShadingFlag::BGBlindOn) { + if (ShadeFlag == WinShadingType::BGShade || ShadeFlag == WinShadingType::BGBlind) { for (i = 1; i <= 6; ++i) { RhoIR(i) = max(0.0, 1.0 - state.dataWindowManager->tir(i) - state.dataWindowManager->emis(i)); } @@ -3225,7 +3225,7 @@ namespace WindowManager { Aface(5, 6) = -state.dataWindowManager->scon(3); Aface(6, 6) = hr(6) + state.dataWindowManager->scon(3) + state.dataWindowManager->hcin; - if (ShadeFlag != WinShadingFlag::BGShadeOn && ShadeFlag != WinShadingFlag::BGBlindOn && SurfWinAirflowThisTS(SurfNum) > 0.0) { + if (ShadeFlag != WinShadingType::BGShade && ShadeFlag != WinShadingType::BGBlind && SurfWinAirflowThisTS(SurfNum) > 0.0) { Bface(4) = state.dataWindowManager->AbsRadGlassFace(4) + hcvAirflowGap * TAirflowGapNew; Bface(5) = state.dataWindowManager->AbsRadGlassFace(5) + hcvAirflowGap * TAirflowGapNew; Aface(4, 4) = state.dataWindowManager->scon(2) + hcvAirflowGap - state.dataWindowManager->A45P * hr(4); @@ -3234,7 +3234,7 @@ namespace WindowManager { Aface(5, 5) = hcvAirflowGap + state.dataWindowManager->scon(3) + state.dataWindowManager->A54P * hr(5); } - if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn) { + if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::IntBlind) { Bface(6) = state.dataWindowManager->Rmir * state.dataWindowManager->emis(6) * TauShIR / ShGlReflFacIR + hcv * TGapNew + state.dataWindowManager->AbsRadGlassFace(6); Bface(7) = state.dataWindowManager->Rmir * TauShIR * RhoGlIR2 * EpsShIR1 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(1); Bface(8) = state.dataWindowManager->Rmir * EpsShIR2 + state.dataWindowManager->hcin * state.dataWindowManager->tin + AbsRadShadeFace(2); @@ -3248,7 +3248,7 @@ namespace WindowManager { Aface(8, 8) = hr(8) + sconsh + state.dataWindowManager->hcin; } - if (ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { + if (ShadeFlag == WinShadingType::ExtShade || ShadeFlag == WinShadingType::ExtBlind || ShadeFlag == WinShadingType::ExtScreen) { Bface(1) = state.dataWindowManager->Outir * state.dataWindowManager->emis(1) * TauShIR / ShGlReflFacIR + hcv * TGapNew + state.dataWindowManager->AbsRadGlassFace(1); Bface(7) = state.dataWindowManager->Outir * EpsShIR1 + state.dataWindowManager->hcout * state.dataWindowManager->tout + AbsRadShadeFace(1); Bface(8) = state.dataWindowManager->Outir * TauShIR * RhoGlIR1 * EpsShIR2 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(2); @@ -3262,7 +3262,7 @@ namespace WindowManager { Aface(8, 8) = hr(8) * (1 - RhoGlIR1 * (EpsShIR2 + RhoShIR2)) / ShGlReflFacIR + sconsh + hcv; } - if (ShadeFlag == WinShadingFlag::BGShadeOn || ShadeFlag == WinShadingFlag::BGBlindOn) { + if (ShadeFlag == WinShadingType::BGShade || ShadeFlag == WinShadingType::BGBlind) { for (i = 1; i <= 8; ++i) { RhoIR(i) = max(0.0, 1.0 - state.dataWindowManager->tir(i) - state.dataWindowManager->emis(i)); } @@ -3360,7 +3360,7 @@ namespace WindowManager { Aface(7, 8) = -state.dataWindowManager->scon(4); Aface(8, 8) = hr(8) + state.dataWindowManager->scon(4) + state.dataWindowManager->hcin; - if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn) { + if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::IntBlind) { Bface(8) = state.dataWindowManager->Rmir * state.dataWindowManager->emis(8) * TauShIR / ShGlReflFacIR + hcv * TGapNew + state.dataWindowManager->AbsRadGlassFace(8); Bface(9) = state.dataWindowManager->Rmir * TauShIR * RhoGlIR2 * EpsShIR1 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(1); Bface(10) = state.dataWindowManager->Rmir * EpsShIR2 + state.dataWindowManager->hcin * state.dataWindowManager->tin + AbsRadShadeFace(2); @@ -3374,7 +3374,7 @@ namespace WindowManager { Aface(10, 10) = hr(10) + sconsh + state.dataWindowManager->hcin; } - if (ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { + if (ShadeFlag == WinShadingType::ExtShade || ShadeFlag == WinShadingType::ExtBlind || ShadeFlag == WinShadingType::ExtScreen) { Bface(1) = state.dataWindowManager->Outir * state.dataWindowManager->emis(1) * TauShIR / ShGlReflFacIR + hcv * TGapNew + state.dataWindowManager->AbsRadGlassFace(1); Bface(9) = state.dataWindowManager->Outir * EpsShIR1 + state.dataWindowManager->hcout * state.dataWindowManager->tout + AbsRadShadeFace(1); Bface(10) = state.dataWindowManager->Outir * TauShIR * RhoGlIR1 * EpsShIR2 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(2); @@ -3426,7 +3426,7 @@ namespace WindowManager { // For all cases, get total window heat gain for reporting. See CalcWinFrameAndDividerTemps for // contribution of frame and divider. IncidentSolar = Surface(SurfNum).Area * SurfQRadSWOutIncident(SurfNum); - if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn) { + if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::IntBlind) { // Interior shade or blind SurfWinConvHeatFlowNatural(SurfNum) = ConvHeatFlowNatural; // Window heat gain from glazing and shade/blind to zone. Consists of transmitted solar, convection @@ -3507,14 +3507,14 @@ namespace WindowManager { } TransDiff = state.dataConstruction->Construct(ConstrNum).TransDiff; // Default value for TransDiff here - if (ShadeFlag == WinShadingFlag::NoShade || ShadeFlag == WinShadingFlag::ShadeOff) { + if (ShadeFlag == WinShadingType::NoShade || ShadeFlag == WinShadingType::ShadeOff) { TransDiff = state.dataConstruction->Construct(ConstrNum).TransDiff; - } else if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::BGShadeOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { + } else if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::ExtShade || ShadeFlag == WinShadingType::BGShade || ShadeFlag == WinShadingType::ExtScreen) { TransDiff = state.dataConstruction->Construct(ConstrNumSh).TransDiff; - } else if (ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::BGBlindOn) { + } else if (ShadeFlag == WinShadingType::IntBlind || ShadeFlag == WinShadingType::ExtBlind || ShadeFlag == WinShadingType::BGBlind) { TransDiff = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), state.dataConstruction->Construct(ConstrNumSh).BlTransDiff); - } else if (ShadeFlag == WinShadingFlag::SwitchableGlazing) { + } else if (ShadeFlag == WinShadingType::SwitchableGlazing) { TransDiff = InterpSw(SurfWinSwitchingFactor(SurfNum), state.dataConstruction->Construct(ConstrNum).TransDiff, state.dataConstruction->Construct(ConstrNumSh).TransDiff); } SurfWinHeatGain(SurfNum) -= QS(Surface(SurfNum).SolarEnclIndex) * Surface(SurfNum).Area * TransDiff; @@ -3522,8 +3522,8 @@ namespace WindowManager { // shouldn't this be + outward flowing fraction of absorbed SW? -- do not know whose comment this is? LKL (9/2012) SurfWinLossSWZoneToOutWinRep(SurfNum) = QS(Surface(SurfNum).SolarEnclIndex) * Surface(SurfNum).Area * TransDiff; - if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::BGShadeOn || - ShadeFlag == WinShadingFlag::BGBlindOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { + if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::ExtShade || ShadeFlag == WinShadingType::IntBlind || ShadeFlag == WinShadingType::ExtBlind || ShadeFlag == WinShadingType::BGShade || + ShadeFlag == WinShadingType::BGBlind || ShadeFlag == WinShadingType::ExtScreen) { SurfWinShadingAbsorbedSolar(SurfNum) = (SurfWinExtBeamAbsByShade(SurfNum) + SurfWinExtDiffAbsByShade(SurfNum)) * (Surface(SurfNum).Area + SurfWinDividerArea(SurfNum)); SurfWinShadingAbsorbedSolarEnergy(SurfNum) = SurfWinShadingAbsorbedSolar(SurfNum) * state.dataGlobal->TimeStepZoneSec; @@ -3542,7 +3542,7 @@ namespace WindowManager { } // Save hcv for use in divider calc with interior or exterior shade (see CalcWinFrameAndDividerTemps) - if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::ExtScreenOn) + if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::ExtShade || ShadeFlag == WinShadingType::IntBlind || ShadeFlag == WinShadingType::ExtBlind || ShadeFlag == WinShadingType::ExtScreen) SurfWinConvCoeffWithShade(SurfNum) = hcv; } else { // No convergence after MaxIterations even with relaxed error tolerance @@ -3637,7 +3637,7 @@ namespace WindowManager { Real64 gr; // glass-shade/blind gap Grashof number Real64 pr; // glass-shade/blind gap Prandtl number Real64 nu; // glass-shade/blind gap Nusselt number - WinShadingFlag ShadeFlag; // Shading flag + WinShadingType ShadeFlag; // Shading flag int BlNum; // Blind number // Air properties @@ -3650,7 +3650,7 @@ namespace WindowManager { nglassfaces = 2 * state.dataConstruction->Construct(ConstrNumSh).TotGlassLayers; TotGaps = state.dataConstruction->Construct(ConstrNumSh).TotGlassLayers; - if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn) { // Interior shade or blind + if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::IntBlind) { // Interior shade or blind MatNumSh = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(nglassfaces); TGapInlet = state.dataWindowManager->tin; TGlassFace = state.dataWindowManager->thetas(nglassfaces); @@ -3688,7 +3688,7 @@ namespace WindowManager { GapHeight = Surface(SurfNum).Height; - if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { + if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::ExtShade || ShadeFlag == WinShadingType::ExtScreen) { // Shade or Screen on GapDepth = state.dataMaterial->Material(MatNumSh).WinShadeToGlassDist; AGap = GapDepth * Surface(SurfNum).Width; @@ -3752,7 +3752,7 @@ namespace WindowManager { TGapNew = TAve - (GapHeightChar / GapHeight) * (TGapOutlet - TGapInlet); // Convective heat flow from gap to room air for interior shade or blind - if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn) { + if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::IntBlind) { RhoAir = state.dataWindowManager->AirProps(1) + state.dataWindowManager->AirProps(2) * (TGapNew - state.dataWindowManager->TKelvin); QConvGap = RhoAir * AGap * VGap * 1008.0 * (TGapOutlet - TGapInlet); // Exclude convection to gap due to divider, if present; divider convection handled @@ -3837,7 +3837,7 @@ namespace WindowManager { Real64 gr; // Gap gas Grashof number Real64 pr; // Gap gas Prandtl number Real64 nu; // Gap gas Nusselt number - WinShadingFlag ShadeFlag; // Shading flag + WinShadingType ShadeFlag; // Shading flag int BlNum; // Blind number int IGap; // Gap counter; 1 = gap on outer side of shade/blind, 2 = gap on inner side. int IGapInc; // Gap increment (0 or 1) @@ -3891,7 +3891,7 @@ namespace WindowManager { GapDepth = state.dataWindowManager->gap(1 + IGapInc); AGap = GapDepth * Surface(SurfNum).Width; - if (ShadeFlag == WinShadingFlag::BGShadeOn) { + if (ShadeFlag == WinShadingType::BGShade) { // Shade on ATopGap = state.dataMaterial->Material(MatNumSh).WinShadeTopOpeningMult * AGap; ABotGap = state.dataMaterial->Material(MatNumSh).WinShadeBottomOpeningMult * AGap; @@ -4127,7 +4127,7 @@ namespace WindowManager { Real64 gr; // Gap air Grashof number Real64 pr; // Gap air Prandtl number Real64 nu; // Gap air Nusselt number - WinShadingFlag ShadeFlag; // Shading flag + WinShadingType ShadeFlag; // Shading flag int IGap; // Gap counter; 1 = gap on outer side of shade/blind, 2 = gap on inner side. int IGapInc; // Gap increment; =0, double glass, =1, triple glass // REAL(r64) :: AirProps(8) ! Air properties @@ -4617,7 +4617,7 @@ namespace WindowManager { Real64 const resgap(0.21); // Typical gap resistance (m2-K/W) int i; // Face counter - WinShadingFlag ShadeFlag; // Shading flag + WinShadingType ShadeFlag; // Shading flag static Array1D rguess(11); // Combined radiative/convective resistance (m2-K/W) of //Tuned Made static // inside or outside air film, or gap Real64 restot; // Total window resistance including outside @@ -4674,9 +4674,9 @@ namespace WindowManager { // Initialize face temperatures of shade or blind, if present ShadeFlag = SurfWinShadingFlag(SurfNum); - if (SurfWinExtIntShadePrevTS(SurfNum) == WinShadingFlag::IntShadeOn || SurfWinExtIntShadePrevTS(SurfNum) == WinShadingFlag::IntBlindOn || - SurfWinExtIntShadePrevTS(SurfNum) == WinShadingFlag::ExtShadeOn || SurfWinExtIntShadePrevTS(SurfNum) == WinShadingFlag::ExtBlindOn || - SurfWinExtIntShadePrevTS(SurfNum) == WinShadingFlag::BGShadeOn || SurfWinExtIntShadePrevTS(SurfNum) == WinShadingFlag::BGBlindOn) { + if (SurfWinExtIntShadePrevTS(SurfNum) == WinShadingType::IntShade || SurfWinExtIntShadePrevTS(SurfNum) == WinShadingType::IntBlind || + SurfWinExtIntShadePrevTS(SurfNum) == WinShadingType::ExtShade || SurfWinExtIntShadePrevTS(SurfNum) == WinShadingType::ExtBlind || + SurfWinExtIntShadePrevTS(SurfNum) == WinShadingType::BGShade || SurfWinExtIntShadePrevTS(SurfNum) == WinShadingType::BGBlind) { // Shade or blind is on during the previous TS; use previous-TS values of shade/blind face temps. // Note that if shade or blind is NOT on in the current TS the following two // temperature values, although calculated here, are not used. The shade/blind face numbers @@ -4696,15 +4696,15 @@ namespace WindowManager { // equal to tout. For between-glass shade/blind it is assumed to be equal to the // average temperature of the adjacent glass faces. - if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn) { + if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::IntBlind) { state.dataWindowManager->thetas(state.dataWindowManager->nglface + 1) = state.dataWindowManager->tin + (AbsRadShade(1) + AbsRadShade(2)) / (2 * (state.dataWindowManager->hcin + hrad)); state.dataWindowManager->thetas(state.dataWindowManager->nglface + 2) = state.dataWindowManager->thetas(state.dataWindowManager->nglface + 1); } - if (ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::ExtBlindOn) { + if (ShadeFlag == WinShadingType::ExtShade || ShadeFlag == WinShadingType::ExtBlind) { state.dataWindowManager->thetas(state.dataWindowManager->nglface + 1) = state.dataWindowManager->tout + (AbsRadShade(1) + AbsRadShade(2)) / (2 * (state.dataWindowManager->hcout + hrad)); state.dataWindowManager->thetas(state.dataWindowManager->nglface + 2) = state.dataWindowManager->thetas(state.dataWindowManager->nglface + 1); } - if (ShadeFlag == WinShadingFlag::BGShadeOn || ShadeFlag == WinShadingFlag::BGBlindOn) { + if (ShadeFlag == WinShadingType::BGShade || ShadeFlag == WinShadingType::BGBlind) { // Between-glass shade/blind allowed only for double and triple glazing. // The factor 16.0 below is based on a combined convective/radiative heat transfer // coefficient on either side of the shade/blind of 8.0 W/m2-K -- about 1.4 Btu/h-ft2-F. @@ -5737,7 +5737,7 @@ namespace WindowManager { Real64 TOutRad; // Outside radiative temperature (K) Real64 TOutRadFr; // Effective outside radiative temperature for frame (K) Real64 TOutRadDiv; // Effective outside radiative temperature for divider (K) - WinShadingFlag ShadeFlag; // Window shading flag + WinShadingType ShadeFlag; // Window shading flag Real64 FrameCon; // Frame conductance (W/m2-K) Real64 Afac; // Intermediate calculation variables @@ -5861,7 +5861,7 @@ namespace WindowManager { if (FrameDivider(FrDivNum).DividerProjectionOut > 0.0) { HOutRad *= (1.0 + 2.0 * SurfWinProjCorrDivOut(SurfNum)); - if (SurfWinShadingFlag(SurfNum) == WinShadingFlag::ExtShadeOn) HOutConvDiv = SurfWinConvCoeffWithShade(SurfNum); + if (SurfWinShadingFlag(SurfNum) == WinShadingType::ExtShade) HOutConvDiv = SurfWinConvCoeffWithShade(SurfNum); HOutConvDiv *= (1.0 + 2.0 * SurfWinProjCorrDivOut(SurfNum)); // Add long-wave from outside window surface absorbed by divider outside projection SurfWinDividerQRadOutAbs(SurfNum) += SurfWinProjCorrDivOut(SurfNum) * FrameDivider(FrDivNum).DividerEmis * @@ -5872,7 +5872,7 @@ namespace WindowManager { if (FrameDivider(FrDivNum).DividerProjectionIn > 0.0) { HInRad *= (1.0 + 2.0 * SurfWinProjCorrDivIn(SurfNum)); - if (SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntShadeOn) HInConvDiv = SurfWinConvCoeffWithShade(SurfNum); + if (SurfWinShadingFlag(SurfNum) == WinShadingType::IntShade) HInConvDiv = SurfWinConvCoeffWithShade(SurfNum); HInConvDiv *= (1.0 + 2.0 * SurfWinProjCorrDivIn(SurfNum)); // Add long-wave from inside window surface absorbed by divider inside projection SurfWinDividerQRadInAbs(SurfNum) += SurfWinProjCorrDivIn(SurfNum) * FrameDivider(FrDivNum).DividerEmis * EmisGlassIn * @@ -5904,7 +5904,7 @@ namespace WindowManager { // from the inside surface of the divider goes directly into the zone air -- i.e., the IR radiative // interaction between divider and shade is ignored due to the difficulty of calculating this interaction // at the same time that the interaction between glass and shade is calculated. - if (SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntShadeOn || SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntBlindOn) + if (SurfWinShadingFlag(SurfNum) == WinShadingType::IntShade || SurfWinShadingFlag(SurfNum) == WinShadingType::IntBlind) SurfWinDividerHeatGain(SurfNum) = DividerHeatGain; DivTempOut = SurfWinDividerTempSurfOut(SurfNum) + state.dataWindowManager->TKelvin; } // End of check if window has dividers @@ -6015,7 +6015,7 @@ namespace WindowManager { Array1D hgap(5); // Conductive gap conductance [W/m2-K] Array1D hGapTot(5); // Combined radiative and conductive gap conductance [W/m2-K] Real64 Rbare; // Nominal center-of-glass resistance without air films [m2-K/W] - WinShadingFlag ShadeFlag; // Shading flag + WinShadingType ShadeFlag; // Shading flag Real64 ShadeRes; // Thermal resistance of shade int MatOutside; // Material number of outside layer of construction int MatInside; // Material number of inside layer of construction @@ -6116,42 +6116,42 @@ namespace WindowManager { state.dataWindowManager->Outir = state.dataWindowManager->sigma * pow_4(state.dataWindowManager->tout); // Determine whether construction has an exterior or interior shade or blind - ShadeFlag = WinShadingFlag::NoShade; + ShadeFlag = WinShadingType::NoShade; ShadeRes = 0.0; MatOutside = state.dataConstruction->Construct(ConstrNum).LayerPoint(1); MatInside = state.dataConstruction->Construct(ConstrNum).LayerPoint(TotLay); if (state.dataMaterial->Material(MatOutside).Group == 2) { // Exterior shade present MatShade = MatOutside; - ShadeFlag = WinShadingFlag::ExtShadeOn; + ShadeFlag = WinShadingType::ExtShade; // Set glazing outside convection coefficient to Window 4 still-air value state.dataWindowManager->hcout = 12.25; } else if (state.dataMaterial->Material(MatOutside).Group == 7) { // Exterior screen present MatShade = MatOutside; ScNum = state.dataMaterial->Material(MatShade).ScreenDataPtr; // Orphaned constructs with exterior screen are ignored - if (ScNum > 0) ShadeFlag = WinShadingFlag::ExtScreenOn; + if (ScNum > 0) ShadeFlag = WinShadingType::ExtScreen; state.dataWindowManager->hcout = 12.25; } else if (state.dataMaterial->Material(MatOutside).Group == 5) { // Exterior blind present MatShade = MatOutside; - ShadeFlag = WinShadingFlag::ExtBlindOn; + ShadeFlag = WinShadingType::ExtBlind; BlNum = state.dataMaterial->Material(MatShade).BlindDataPtr; state.dataWindowManager->hcout = 12.25; } else if (state.dataMaterial->Material(MatInside).Group == 2) { // Interior shade present MatShade = MatInside; - ShadeFlag = WinShadingFlag::IntShadeOn; + ShadeFlag = WinShadingType::IntShade; } else if (state.dataMaterial->Material(MatInside).Group == 5) { // Interior blind present MatShade = MatInside; BlNum = state.dataMaterial->Material(MatShade).BlindDataPtr; - ShadeFlag = WinShadingFlag::IntBlindOn; + ShadeFlag = WinShadingType::IntBlind; } else if (TotGlassLay == 2) { - if (state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(3)).Group == 2) ShadeFlag = WinShadingFlag::BGShadeOn; - if (state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(3)).Group == 5) ShadeFlag = WinShadingFlag::BGBlindOn; + if (state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(3)).Group == 2) ShadeFlag = WinShadingType::BGShade; + if (state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(3)).Group == 5) ShadeFlag = WinShadingType::BGBlind; } else if (TotGlassLay == 3) { - if (state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(5)).Group == 2) ShadeFlag = WinShadingFlag::BGShadeOn; - if (state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(5)).Group == 5) ShadeFlag = WinShadingFlag::BGBlindOn; + if (state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(5)).Group == 2) ShadeFlag = WinShadingType::BGShade; + if (state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(5)).Group == 5) ShadeFlag = WinShadingType::BGBlind; } - if (ShadeFlag == WinShadingFlag::BGShadeOn || ShadeFlag == WinShadingFlag::BGBlindOn) { + if (ShadeFlag == WinShadingType::BGShade || ShadeFlag == WinShadingType::BGBlind) { errFlag = 2; return; } @@ -6159,10 +6159,10 @@ namespace WindowManager { TSolNorm = POLYF(1.0, state.dataConstruction->Construct(ConstrNum).TransSolBeamCoef); TVisNorm = POLYF(1.0, state.dataConstruction->Construct(ConstrNum).TransVisBeamCoef); AbsBeamShadeNorm = 0.0; - if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn) { // Exterior or interior shade on + if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::ExtShade) { // Exterior or interior shade on AbsBeamShadeNorm = POLYF(1.0, state.dataConstruction->Construct(ConstrNum).AbsBeamShadeCoef); // Exterior blind or screen or interior blind on - } else if (ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { + } else if (ShadeFlag == WinShadingType::IntBlind || ShadeFlag == WinShadingType::ExtBlind || ShadeFlag == WinShadingType::ExtScreen) { // Find unshaded construction that goes with this construction w/blind or screen ConstrNumBare = 0; for (ConstrNum1 = 1; ConstrNum1 <= TotConstructs; ++ConstrNum1) { @@ -6174,7 +6174,7 @@ namespace WindowManager { ConstrNumBare = ConstrNum1; for (Lay = 1; Lay <= state.dataConstruction->Construct(ConstrNum1).TotLayers; ++Lay) { LayPtr = state.dataConstruction->Construct(ConstrNum1).LayerPoint(Lay); - if (ShadeFlag == WinShadingFlag::IntBlindOn) { // The shaded construction has an interior blind + if (ShadeFlag == WinShadingType::IntBlind) { // The shaded construction has an interior blind LayPtrSh = state.dataConstruction->Construct(ConstrNum).LayerPoint(Lay); } else { // The shaded construction has an exterior blind or screen LayPtrSh = state.dataConstruction->Construct(ConstrNum).LayerPoint(Lay + 1); @@ -6192,7 +6192,7 @@ namespace WindowManager { TBmBm = POLYF(1.0, state.dataConstruction->Construct(ConstrNumBare).TransSolBeamCoef); TBmBmVis = POLYF(1.0, state.dataConstruction->Construct(ConstrNumBare).TransVisBeamCoef); - if (ShadeFlag == WinShadingFlag::ExtScreenOn) { + if (ShadeFlag == WinShadingType::ExtScreen) { // Don't need to call subroutine, use normal incident properties (SUBROUTINE CalcNominalWindowCond) // Last call to CalcScreenTransmittance(ISurf) was done at direct normal angle (0,0) in CalcWindowScreenProperties TScBmBm = SurfaceScreens(ScNum).BmBmTrans; @@ -6224,7 +6224,7 @@ namespace WindowManager { TBlBmDifVis = InterpProfSlatAng(0.0, SlatAng, VarSlats, Blind(BlNum).VisFrontBeamDiffTrans); TDif = state.dataConstruction->Construct(ConstrNumBare).TransDiff; TDifVis = state.dataConstruction->Construct(ConstrNumBare).TransDiffVis; - if (ShadeFlag == WinShadingFlag::IntBlindOn) { + if (ShadeFlag == WinShadingType::IntBlind) { RGlDiffBack = state.dataConstruction->Construct(ConstrNumBare).ReflectSolDiffBack; RGlDiffBackVis = state.dataConstruction->Construct(ConstrNumBare).ReflectVisDiffBack; RhoBlFront = InterpProfSlatAng(0.0, SlatAng, VarSlats, Blind(BlNum).SolFrontBeamDiffRefl); @@ -6241,7 +6241,7 @@ namespace WindowManager { TVisNorm = TBmBmVis * (TBlBmBm + TBlBmDifVis + TBlDifDifVis * RhoBlFrontVis * RGlDiffBackVis / (1.0 - RhoBlDiffFrontVis * RGlDiffBackVis)); } // (IntBlind) - if (ShadeFlag == WinShadingFlag::ExtBlindOn) { + if (ShadeFlag == WinShadingType::ExtBlind) { TBlBmBm = BlindBeamBeamTrans(0.0, SlatAng, Blind(BlNum).SlatWidth, Blind(BlNum).SlatSeparation, Blind(BlNum).SlatThickness); RGlFront = POLYF(1.0, state.dataConstruction->Construct(ConstrNumBare).ReflSolBeamFrontCoef); RGlFrontVis = POLYF(1.0, state.dataConstruction->Construct(ConstrNumBare).ReflSolBeamFrontCoef); @@ -6292,16 +6292,16 @@ namespace WindowManager { state.dataWindowManager->tir(2 * IGlass - 1) = state.dataMaterial->Material(LayPtr).TransThermal; state.dataWindowManager->tir(2 * IGlass) = state.dataMaterial->Material(LayPtr).TransThermal; AbsBeamNorm(IGlass) = POLYF(1.0, state.dataConstruction->Construct(ConstrNum).AbsBeamCoef({1, 6}, IGlass)); - if (ShadeFlag == WinShadingFlag::IntBlindOn) { // Interior blind on + if (ShadeFlag == WinShadingType::IntBlind) { // Interior blind on AbsBeamNorm(IGlass) = POLYF(1.0, state.dataConstruction->Construct(ConstrNumBare).AbsBeamCoef({1, 6}, IGlass)); AGlDiffBack = state.dataConstruction->Construct(ConstrNumBare).AbsDiffBack(IGlass); AbsBeamNorm(IGlass) += TBmBm * AGlDiffBack * RhoBlFront / (1.0 - RhoBlFront * RGlDiffBack); - } else if (ShadeFlag == WinShadingFlag::ExtBlindOn) { // Exterior blind on + } else if (ShadeFlag == WinShadingType::ExtBlind) { // Exterior blind on AbsBeamNorm(IGlass) = POLYF(1.0, state.dataConstruction->Construct(ConstrNumBare).AbsBeamCoef({1, 6}, IGlass)); AbsBeamNorm(IGlass) = TBlBmBm * AbsBeamNorm(IGlass) + (TBlBmBm * RGlFront * RhoBlBack + TBlBmDif) * state.dataConstruction->Construct(ConstrNumBare).AbsDiff(IGlass) / (1.0 - RGlDiffFront * RhoBlDiffBack); - } else if (ShadeFlag == WinShadingFlag::ExtScreenOn) { // Exterior screen on + } else if (ShadeFlag == WinShadingType::ExtScreen) { // Exterior screen on AbsBeamNorm(IGlass) = POLYF(1.0, state.dataConstruction->Construct(ConstrNumBare).AbsBeamCoef({1, 6}, IGlass)); AbsBeamNorm(IGlass) = TScBmBm * AbsBeamNorm(IGlass) + (TScBmBm * RGlFront * RScBack + TScBmDif) * state.dataConstruction->Construct(ConstrNumBare).AbsDiff(IGlass) / @@ -6362,7 +6362,7 @@ namespace WindowManager { hInRad = state.dataWindowManager->emis(state.dataWindowManager->nglface) * state.dataWindowManager->sigma * 0.5 * pow_3(state.dataWindowManager->tin + state.dataWindowManager->thetas(state.dataWindowManager->nglface)); rIn = 1.0 / (hInRad + state.dataWindowManager->hcin); - if (!(ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn)) AbsBeamShadeNorm = 0.0; + if (!(ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::IntBlind)) AbsBeamShadeNorm = 0.0; { auto const SELECT_CASE_var(state.dataWindowManager->ngllayer); @@ -7507,8 +7507,8 @@ namespace WindowManager { if (Surface(SurfNum).HasShadeControl) { ConstrNumSh = Surface(SurfNum).activeShadedConstruction; MatNum = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(1); - WinShadingFlag ShadingType = WindowShadingControl(Surface(SurfNum).activeWindowShadingControl).ShadingType; - if (ShadingType == WinShadingFlag::ExtScreenOn) { + WinShadingType ShadingType = WindowShadingControl(Surface(SurfNum).activeWindowShadingControl).ShadingType; + if (ShadingType == WinShadingType::ExtScreen) { if (state.dataMaterial->Material(MatNum).ScreenMapResolution > 0) PrintTransMap = true; ++ScreenNum; diff --git a/src/EnergyPlus/WindowManagerExteriorThermal.cc b/src/EnergyPlus/WindowManagerExteriorThermal.cc index 960ea00f970..d69efe759a2 100644 --- a/src/EnergyPlus/WindowManagerExteriorThermal.cc +++ b/src/EnergyPlus/WindowManagerExteriorThermal.cc @@ -110,9 +110,9 @@ namespace WindowManager { // Interior and exterior shading layers have gas between them and IGU but that gas // was not part of construction so it needs to be increased by one - if (SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntShadeOn || SurfWinShadingFlag(SurfNum) == WinShadingFlag::ExtShadeOn || SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntBlindOn || - SurfWinShadingFlag(SurfNum) == WinShadingFlag::ExtBlindOn || SurfWinShadingFlag(SurfNum) == WinShadingFlag::ExtScreenOn || SurfWinShadingFlag(SurfNum) == WinShadingFlag::BGShadeOn || - SurfWinShadingFlag(SurfNum) == WinShadingFlag::BGBlindOn) { + if (SurfWinShadingFlag(SurfNum) == WinShadingType::IntShade || SurfWinShadingFlag(SurfNum) == WinShadingType::ExtShade || SurfWinShadingFlag(SurfNum) == WinShadingType::IntBlind || + SurfWinShadingFlag(SurfNum) == WinShadingType::ExtBlind || SurfWinShadingFlag(SurfNum) == WinShadingType::ExtScreen || SurfWinShadingFlag(SurfNum) == WinShadingType::BGShade || + SurfWinShadingFlag(SurfNum) == WinShadingType::BGBlind) { ++totSolidLayers; } @@ -141,7 +141,7 @@ namespace WindowManager { ++i; } SurfInsideTemp = aTemp - DataGlobalConstants::KelvinConv; - if (SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntShadeOn || SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntBlindOn) { + if (SurfWinShadingFlag(SurfNum) == WinShadingType::IntShade || SurfWinShadingFlag(SurfNum) == WinShadingType::IntBlind) { auto EffShBlEmiss = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), window.EffShBlindEmiss); auto EffGlEmiss = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), window.EffGlassEmiss); SurfWinEffInsSurfTemp(SurfNum) = @@ -150,7 +150,7 @@ namespace WindowManager { } HConvIn(SurfNum) = aSystem->getHc(Environment::Indoor); - if (SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntShadeOn || SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntBlindOn || aFactory.isInteriorShade()) { + if (SurfWinShadingFlag(SurfNum) == WinShadingType::IntShade || SurfWinShadingFlag(SurfNum) == WinShadingType::IntBlind || aFactory.isInteriorShade()) { // It is not clear why EnergyPlus keeps this interior calculations separately for interior shade. This does create different // solution from heat transfer from tarcog itself. Need to confirm with LBNL team about this approach. Note that heat flow // through shade (consider case when openings are zero) is different from heat flow obtained by these equations. Will keep @@ -248,23 +248,23 @@ namespace WindowManager { m_ConstructionNumber = m_Surface.Construction; m_ShadePosition = ShadePosition::NoShade; - if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::BGShadeOn || - ShadeFlag == WinShadingFlag::BGBlindOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { + if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::ExtShade || ShadeFlag == WinShadingType::IntBlind || ShadeFlag == WinShadingType::ExtBlind || ShadeFlag == WinShadingType::BGShade || + ShadeFlag == WinShadingType::BGBlind || ShadeFlag == WinShadingType::ExtScreen) { m_ConstructionNumber = m_Surface.activeShadedConstruction; if (SurfWinStormWinFlag(t_SurfNum) > 0) m_ConstructionNumber = m_Surface.activeStormWinShadedConstruction; } m_TotLay = getNumOfLayers(state); - if (ShadeFlag == WinShadingFlag::IntShadeOn || ShadeFlag == WinShadingFlag::IntBlindOn) { + if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::IntBlind) { m_ShadePosition = ShadePosition::Interior; } - if (ShadeFlag == WinShadingFlag::ExtShadeOn || ShadeFlag == WinShadingFlag::ExtBlindOn || ShadeFlag == WinShadingFlag::ExtScreenOn) { + if (ShadeFlag == WinShadingType::ExtShade || ShadeFlag == WinShadingType::ExtBlind || ShadeFlag == WinShadingType::ExtScreen) { m_ShadePosition = ShadePosition::Exterior; } - if (ShadeFlag == WinShadingFlag::BGShadeOn || ShadeFlag == WinShadingFlag::BGBlindOn) { + if (ShadeFlag == WinShadingType::BGShade || ShadeFlag == WinShadingType::BGBlind) { m_ShadePosition = ShadePosition::Between; } } @@ -303,9 +303,9 @@ namespace WindowManager { { auto ConstrNum = m_Surface.Construction; - if (SurfWinShadingFlag(m_SurfNum) == WinShadingFlag::IntShadeOn || SurfWinShadingFlag(m_SurfNum) == WinShadingFlag::ExtShadeOn || SurfWinShadingFlag(m_SurfNum) == WinShadingFlag::IntBlindOn || - SurfWinShadingFlag(m_SurfNum) == WinShadingFlag::ExtBlindOn || SurfWinShadingFlag(m_SurfNum) == WinShadingFlag::BGShadeOn || SurfWinShadingFlag(m_SurfNum) == WinShadingFlag::BGBlindOn || - SurfWinShadingFlag(m_SurfNum) == WinShadingFlag::ExtScreenOn) { + if (SurfWinShadingFlag(m_SurfNum) == WinShadingType::IntShade || SurfWinShadingFlag(m_SurfNum) == WinShadingType::ExtShade || SurfWinShadingFlag(m_SurfNum) == WinShadingType::IntBlind || + SurfWinShadingFlag(m_SurfNum) == WinShadingType::ExtBlind || SurfWinShadingFlag(m_SurfNum) == WinShadingType::BGShade || SurfWinShadingFlag(m_SurfNum) == WinShadingType::BGBlind || + SurfWinShadingFlag(m_SurfNum) == WinShadingType::ExtScreen) { ConstrNum = m_Surface.activeShadedConstruction; if (SurfWinStormWinFlag(m_SurfNum) > 0) ConstrNum = m_Surface.activeStormWinShadedConstruction; } @@ -499,10 +499,10 @@ namespace WindowManager { auto aGas = getAir(); auto thickness = 0.0; - if (SurfWinShadingFlag(m_SurfNum) == WinShadingFlag::IntBlindOn || SurfWinShadingFlag(m_SurfNum) == WinShadingFlag::ExtBlindOn) { + if (SurfWinShadingFlag(m_SurfNum) == WinShadingType::IntBlind || SurfWinShadingFlag(m_SurfNum) == WinShadingType::ExtBlind) { thickness = Blind(SurfWinBlindNumber(m_SurfNum)).BlindToGlassDist; } - if (SurfWinShadingFlag(m_SurfNum) == WinShadingFlag::IntShadeOn || SurfWinShadingFlag(m_SurfNum) == WinShadingFlag::ExtShadeOn || SurfWinShadingFlag(m_SurfNum) == WinShadingFlag::ExtScreenOn) { + if (SurfWinShadingFlag(m_SurfNum) == WinShadingType::IntShade || SurfWinShadingFlag(m_SurfNum) == WinShadingType::ExtShade || SurfWinShadingFlag(m_SurfNum) == WinShadingType::ExtScreen) { auto material = getLayerMaterial(state, t_Index); thickness = material->WinShadeToGlassDist; } diff --git a/src/EnergyPlus/ZoneTempPredictorCorrector.cc b/src/EnergyPlus/ZoneTempPredictorCorrector.cc index 4cee0fd93fa..48bbbde7c5a 100644 --- a/src/EnergyPlus/ZoneTempPredictorCorrector.cc +++ b/src/EnergyPlus/ZoneTempPredictorCorrector.cc @@ -6257,7 +6257,7 @@ namespace ZoneTempPredictorCorrector { auto const shading_flag(SurfWinShadingFlag(SurfNum)); // Add to the convective internal gains - if (shading_flag == WinShadingFlag::IntShadeOn || shading_flag == WinShadingFlag::IntBlindOn) { + if (shading_flag == WinShadingType::IntShade || shading_flag == WinShadingType::IntBlind) { // The shade area covers the area of the glazing plus the area of the dividers. Area += SurfWinDividerArea(SurfNum); // If interior shade or blind is present it is assumed that both the convective and IR radiative gain @@ -6271,7 +6271,7 @@ namespace ZoneTempPredictorCorrector { if (state.dataConstruction->Construct(Surface(SurfNum).Construction).WindowTypeEQL) SumIntGain += SurfWinOtherConvHeatGain(SurfNum); // Convective heat gain from natural convection in gap between glass and interior shade or blind - if (shading_flag == WinShadingFlag::IntShadeOn || shading_flag == WinShadingFlag::IntBlindOn) SumIntGain += SurfWinConvHeatFlowNatural(SurfNum); + if (shading_flag == WinShadingType::IntShade || shading_flag == WinShadingType::IntBlind) SumIntGain += SurfWinConvHeatFlowNatural(SurfNum); // Convective heat gain from airflow window if (SurfWinAirflowThisTS(SurfNum) > 0.0) { @@ -6299,7 +6299,7 @@ namespace ZoneTempPredictorCorrector { HA += HA_surf; } - if (SurfWinDividerArea(SurfNum) > 0.0 && shading_flag != WinShadingFlag::IntShadeOn && shading_flag != WinShadingFlag::IntBlindOn) { + if (SurfWinDividerArea(SurfNum) > 0.0 && shading_flag != WinShadingType::IntShade && shading_flag != WinShadingType::IntBlind) { // Window divider contribution (only from shade or blind for window with divider and interior shade or blind) Real64 const HA_surf(HConvIn(SurfNum) * SurfWinDividerArea(SurfNum) * (1.0 + 2.0 * SurfWinProjCorrDivIn(SurfNum))); SumHATsurf += HA_surf * SurfWinDividerTempSurfIn(SurfNum); @@ -6588,7 +6588,7 @@ namespace ZoneTempPredictorCorrector { if (Surface(SurfNum).Class == SurfaceClass::Window) { // Add to the convective internal gains - if (SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntShadeOn || SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntBlindOn) { + if (SurfWinShadingFlag(SurfNum) == WinShadingType::IntShade || SurfWinShadingFlag(SurfNum) == WinShadingType::IntBlind) { // The shade area covers the area of the glazing plus the area of the dividers. Area += SurfWinDividerArea(SurfNum); // If interior shade or blind is present it is assumed that both the convective and IR radiative gain @@ -6602,7 +6602,7 @@ namespace ZoneTempPredictorCorrector { if (state.dataConstruction->Construct(Surface(SurfNum).Construction).WindowTypeEQL) SumIntGains += SurfWinOtherConvHeatGain(SurfNum); // Convective heat gain from natural convection in gap between glass and interior shade or blind - if (SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntShadeOn || SurfWinShadingFlag(SurfNum) == WinShadingFlag::IntBlindOn) + if (SurfWinShadingFlag(SurfNum) == WinShadingType::IntShade || SurfWinShadingFlag(SurfNum) == WinShadingType::IntBlind) SumIntGains += SurfWinConvHeatFlowNatural(SurfNum); // Convective heat gain from airflow window @@ -6621,8 +6621,8 @@ namespace ZoneTempPredictorCorrector { (SurfWinFrameTempSurfIn(SurfNum) - RefAirTemp); } - if (SurfWinDividerArea(SurfNum) > 0.0 && SurfWinShadingFlag(SurfNum) != WinShadingFlag::IntShadeOn && - SurfWinShadingFlag(SurfNum) != WinShadingFlag::IntBlindOn) { + if (SurfWinDividerArea(SurfNum) > 0.0 && SurfWinShadingFlag(SurfNum) != WinShadingType::IntShade && + SurfWinShadingFlag(SurfNum) != WinShadingType::IntBlind) { // Window divider contribution (only from shade or blind for window with divider and interior shade or blind) SumHADTsurfs += HConvIn(SurfNum) * SurfWinDividerArea(SurfNum) * (1.0 + 2.0 * SurfWinProjCorrDivIn(SurfNum)) * (SurfWinDividerTempSurfIn(SurfNum) - RefAirTemp); diff --git a/tst/EnergyPlus/unit/DaylightingManager.unit.cc b/tst/EnergyPlus/unit/DaylightingManager.unit.cc index 1affe15f984..a239865639d 100644 --- a/tst/EnergyPlus/unit/DaylightingManager.unit.cc +++ b/tst/EnergyPlus/unit/DaylightingManager.unit.cc @@ -1380,12 +1380,12 @@ TEST_F(EnergyPlusFixture, DaylightingManager_DayltgInteriorIllum_Test) // Window5 model - expect 100 for unshaded and 50 for shaded (10 and 5 for RefPt2) SurfWinWindowModelType(IWin) = Window5DetailedModel; - SurfWinShadingFlag(IWin) = DataSurfaces::WinShadingFlag::NoShade; + SurfWinShadingFlag(IWin) = DataSurfaces::WinShadingType::NoShade; DaylightingManager::DayltgInteriorIllum(*state, ZoneNum); EXPECT_NEAR(state->dataDaylightingManager->DaylIllum(1), 100.0, 0.001); EXPECT_NEAR(state->dataDaylightingManager->DaylIllum(2), 10.0, 0.001); - SurfWinShadingFlag(IWin) = DataSurfaces::WinShadingFlag::ExtBlindOn; + SurfWinShadingFlag(IWin) = DataSurfaces::WinShadingType::ExtBlind; DaylightingManager::DayltgInteriorIllum(*state, ZoneNum); EXPECT_NEAR(state->dataDaylightingManager->DaylIllum(1), 50.0, 0.001); EXPECT_NEAR(state->dataDaylightingManager->DaylIllum(2), 5.0, 0.001); @@ -1393,12 +1393,12 @@ TEST_F(EnergyPlusFixture, DaylightingManager_DayltgInteriorIllum_Test) // BSDF model - expect 100 for unshaded and 100 for shaded (10 for RefPt2 // BSDF does shading differently, it's integrated in the base state SurfWinWindowModelType(IWin) = WindowBSDFModel; - SurfWinShadingFlag(IWin) = DataSurfaces::WinShadingFlag::NoShade; + SurfWinShadingFlag(IWin) = DataSurfaces::WinShadingType::NoShade; DaylightingManager::DayltgInteriorIllum(*state, ZoneNum); EXPECT_NEAR(state->dataDaylightingManager->DaylIllum(1), 100.0, 0.001); EXPECT_NEAR(state->dataDaylightingManager->DaylIllum(2), 10.0, 0.001); - SurfWinShadingFlag(IWin) = DataSurfaces::WinShadingFlag::ExtBlindOn; + SurfWinShadingFlag(IWin) = DataSurfaces::WinShadingType::ExtBlind; DaylightingManager::DayltgInteriorIllum(*state, ZoneNum); EXPECT_NEAR(state->dataDaylightingManager->DaylIllum(1), 100.0, 0.001); EXPECT_NEAR(state->dataDaylightingManager->DaylIllum(2), 10.0, 0.001); diff --git a/tst/EnergyPlus/unit/EMSManager.unit.cc b/tst/EnergyPlus/unit/EMSManager.unit.cc index 8021a01f836..129fa7c0a58 100644 --- a/tst/EnergyPlus/unit/EMSManager.unit.cc +++ b/tst/EnergyPlus/unit/EMSManager.unit.cc @@ -1610,8 +1610,8 @@ TEST_F(EnergyPlusFixture, EMSManager_TestWindowShadingControlExteriorScreenOptio state->dataConstruction->Construct(1).Name = "Construction1"; - DataSurfaces::WindowShadingControl(1).ShadingType = DataSurfaces::WinShadingFlag::NoShade; - DataSurfaces::WindowShadingControl(2).ShadingType = DataSurfaces::WinShadingFlag::ExtScreenOn; + DataSurfaces::WindowShadingControl(1).ShadingType = DataSurfaces::WinShadingType::NoShade; + DataSurfaces::WindowShadingControl(2).ShadingType = DataSurfaces::WinShadingType::ExtScreen; DataSurfaces::TotSurfaces = 2; @@ -1621,14 +1621,14 @@ TEST_F(EnergyPlusFixture, EMSManager_TestWindowShadingControlExteriorScreenOptio SetupWindowShadingControlActuators(*state); EXPECT_FALSE(DataSurfaces::SurfWinShadingFlagEMSOn(2)); - EXPECT_EQ(DataSurfaces::SurfWinShadingFlagEMSValue(2), DataSurfaces::WinShadingFlag::ShadeOff); + EXPECT_EQ(DataSurfaces::SurfWinShadingFlagEMSValue(2), DataSurfaces::WinShadingType::ShadeOff); DataHeatBalance::Zone.allocate(1); DataHeatBalance::Zone(1).WindowSurfaceFirst = 1; DataHeatBalance::Zone(1).WindowSurfaceLast = 2; state->dataGlobal->NumOfZones = 1; DataSurfaces::SurfWinShadingFlagEMSOn(2) = true; - DataSurfaces::SurfWinShadingFlagEMSValue(2) = DataSurfaces::WinShadingFlag::IntShadeOn; + DataSurfaces::SurfWinShadingFlagEMSValue(2) = DataSurfaces::WinShadingType::IntShade; SolarShading::WindowShadingManager(*state); EXPECT_EQ(DataSurfaces::SurfWinShadingFlag(2), DataSurfaces::SurfWinShadingFlagEMSValue(2)); diff --git a/tst/EnergyPlus/unit/HeatBalanceSurfaceManager.unit.cc b/tst/EnergyPlus/unit/HeatBalanceSurfaceManager.unit.cc index 2c2d07a86a7..b29cd92ce1e 100644 --- a/tst/EnergyPlus/unit/HeatBalanceSurfaceManager.unit.cc +++ b/tst/EnergyPlus/unit/HeatBalanceSurfaceManager.unit.cc @@ -280,7 +280,7 @@ TEST_F(EnergyPlusFixture, HeatBalanceSurfaceManager_ComputeIntThermalAbsorpFacto DataSurfaces::Surface(1).HeatTransSurf = true; DataSurfaces::Surface(1).Construction = 1; - DataSurfaces::SurfWinShadingFlag(1) = DataSurfaces::WinShadingFlag::ShadeOff; + DataSurfaces::SurfWinShadingFlag(1) = DataSurfaces::WinShadingType::ShadeOff; state->dataConstruction->Construct(1).InsideAbsorpThermal = 0.9; state->dataConstruction->Construct(1).TransDiff = 0.0; DataSurfaces::Surface(1).MaterialMovInsulInt = 1; diff --git a/tst/EnergyPlus/unit/SurfaceGeometry.unit.cc b/tst/EnergyPlus/unit/SurfaceGeometry.unit.cc index ca3aca89f2d..1339623ce6a 100644 --- a/tst/EnergyPlus/unit/SurfaceGeometry.unit.cc +++ b/tst/EnergyPlus/unit/SurfaceGeometry.unit.cc @@ -3474,7 +3474,7 @@ TEST_F(EnergyPlusFixture, SurfaceGeometry_isWindowShadingControlSimilar_Test) WindowShadingControl(1).Name = "TheShadingControl"; WindowShadingControl(1).ZoneIndex = 57; WindowShadingControl(1).SequenceNumber = 3; - WindowShadingControl(1).ShadingType = WinShadingFlag::ExtShadeOn; + WindowShadingControl(1).ShadingType = WinShadingType::ExtShade; WindowShadingControl(1).ShadingDevice = 17; WindowShadingControl(1).ShadingControlType = WSCT_OnIfScheduled; WindowShadingControl(1).Schedule = 83; @@ -3546,7 +3546,7 @@ TEST_F(EnergyPlusFixture, SurfaceGeometry_isWindowShadingControlSimilar_Test) EXPECT_FALSE(isWindowShadingControlSimilar(1, 2)); WindowShadingControl(2) = WindowShadingControl(1); - WindowShadingControl(2).ShadingType = WinShadingFlag::BGBlindOn; + WindowShadingControl(2).ShadingType = WinShadingType::BGBlind; EXPECT_FALSE(isWindowShadingControlSimilar(1, 2)); WindowShadingControl(2) = WindowShadingControl(1); @@ -3601,7 +3601,7 @@ TEST_F(EnergyPlusFixture, SurfaceGeometry_CheckWindowShadingControlSimilarForWin WindowShadingControl(1).Name = "TheShadingControl"; WindowShadingControl(1).ZoneIndex = 57; WindowShadingControl(1).SequenceNumber = 3; - WindowShadingControl(1).ShadingType = WinShadingFlag::ExtShadeOn; + WindowShadingControl(1).ShadingType = WinShadingType::ExtShade; WindowShadingControl(1).ShadingDevice = 17; WindowShadingControl(1).ShadingControlType = WSCT_OnIfScheduled; WindowShadingControl(1).Schedule = 83; From e7af4ec93032a373433db4623056961cfe9a9e42 Mon Sep 17 00:00:00 2001 From: xuanluo113 Date: Sun, 24 Jan 2021 15:31:39 -0800 Subject: [PATCH 23/76] replace first part --- src/EnergyPlus/DaylightingManager.cc | 17 ++--- src/EnergyPlus/HWBaseboardRadiator.cc | 5 +- src/EnergyPlus/HeatBalanceIntRadExchange.cc | 9 +-- src/EnergyPlus/HeatBalanceSurfaceManager.cc | 2 +- src/EnergyPlus/HighTempRadiantSystem.cc | 5 +- src/EnergyPlus/LowTempRadiantSystem.cc | 5 +- src/EnergyPlus/RoomAirModelAirflowNetwork.cc | 3 +- src/EnergyPlus/SolarShading.cc | 4 +- src/EnergyPlus/SteamBaseboardRadiator.cc | 5 +- src/EnergyPlus/SurfaceGeometry.cc | 15 +--- src/EnergyPlus/UFADManager.cc | 2 +- src/EnergyPlus/VentilatedSlab.cc | 5 +- src/EnergyPlus/WindowComplexManager.cc | 4 +- src/EnergyPlus/WindowManager.cc | 77 +++++++++----------- 14 files changed, 66 insertions(+), 92 deletions(-) diff --git a/src/EnergyPlus/DaylightingManager.cc b/src/EnergyPlus/DaylightingManager.cc index 909c4a2647a..84cf87ce51e 100644 --- a/src/EnergyPlus/DaylightingManager.cc +++ b/src/EnergyPlus/DaylightingManager.cc @@ -3675,7 +3675,7 @@ namespace EnergyPlus::DaylightingManager { state.dataDaylightingManager->EDIRSUdisk(iHour, 1) = RAYCOS(3) * TVISS * ObTransDisk; // Bare window TransBmBmMult = 0.0; - if (ShType == WinShadingType::ExtBlind || ShType == WinShadingType::IntBlind || ShType == WinShadingType::BGBlind) { + if (IS_BLIND_ON(ShType)) { ProfileAngle(IWin, RAYCOS, Blind(BlNum).SlatOrientation, ProfAng); // Contribution of beam passing through slats and reaching reference point for (JB = 1; JB <= MaxSlatAngs; ++JB) { @@ -3729,7 +3729,7 @@ namespace EnergyPlus::DaylightingManager { XAVWL = 14700.0 * std::sqrt(0.000068 * POSFAC) * double(NWX * NWY) / std::pow(WindowSolidAngleDaylightPoint, 0.8); state.dataDaylightingManager->AVWLSUdisk(iHour, 1) = XAVWL * TVISS * ObTransDisk; // Bare window - if (ShType == WinShadingType::ExtBlind || ShType == WinShadingType::IntBlind || ShType == WinShadingType::BGBlind) { + if (IS_BLIND_ON(ShType)) { for (JB = 1; JB <= MaxSlatAngs; ++JB) { // IF (.NOT. SurfaceWindow(IWin)%MovableSlats .AND. JB > 1) EXIT state.dataDaylightingManager->AVWLSUdisk(iHour, JB + 1) = XAVWL * TVISS * TransBmBmMult(JB) * ObTransDisk; @@ -3842,7 +3842,7 @@ namespace EnergyPlus::DaylightingManager { state.dataDaylightingManager->EDIRSUdisk(iHour, 1) += SunVecMir(3) * SpecReflectance * TVisRefl; // Bare window TransBmBmMultRefl = 0.0; - if (ShType == WinShadingType::ExtBlind || ShType == WinShadingType::IntBlind || ShType == WinShadingType::BGBlind) { + if (IS_BLIND_ON(ShType)) { ProfileAngle(IWin, SunVecMir, Blind(BlNum).SlatOrientation, ProfAng); // Contribution of reflected beam passing through slats and reaching reference point Real64 const Pi_SlatAng_fac(DataGlobalConstants::Pi / (MaxSlatAngs - 1)); @@ -3879,7 +3879,7 @@ namespace EnergyPlus::DaylightingManager { XAVWL = 14700.0 * std::sqrt(0.000068 * POSFAC) * double(NWX * NWY) / std::pow(SurfaceWindow(IWin).SolidAngAtRefPtWtd(iRefPoint), 0.8); state.dataDaylightingManager->AVWLSUdisk(iHour, 1) += XAVWL * TVisRefl * SpecReflectance; // Bare window - if (ShType == WinShadingType::ExtBlind || ShType == WinShadingType::IntBlind || ShType == WinShadingType::BGBlind) { + if (IS_BLIND_ON(ShType)) { for (JB = 1; JB <= MaxSlatAngs; ++JB) { // IF(.NOT. SurfaceWindow(IWin)%MovableSlats .AND. JB > 1) EXIT state.dataDaylightingManager->AVWLSUdisk(iHour, JB + 1) += XAVWL * TVisRefl * SpecReflectance * TransBmBmMultRefl(JB); @@ -3898,10 +3898,7 @@ namespace EnergyPlus::DaylightingManager { } // Last pass - if ((ICtrl > 0 && (ShType == WinShadingType::IntShade || ShType == WinShadingType::ExtShade || ShType == WinShadingType::BGShade || - ShType == WinShadingType::IntBlind || ShType == WinShadingType::ExtBlind || ShType == WinShadingType::BGBlind || - ShType == WinShadingType::ExtScreen)) || - SurfWinSolarDiffusing(IWin)) { + if ((ICtrl > 0 && (IS_BLIND_ON(ShType) || IS_SHADE_SCREEN_ON(ShType))) || SurfWinSolarDiffusing(IWin)) { // ----- CASE II -- WINDOW WITH SCREEN, SHADE, BLIND, OR DIFFUSING WINDOW @@ -7940,8 +7937,8 @@ namespace EnergyPlus::DaylightingManager { BlNum = SurfWinBlindNumber(IWin); // ScNum = SurfaceWindow( IWin ).ScreenNumber; //Unused Set but never used - ShadeOn = (ShType == WinShadingType::IntShade || ShType == WinShadingType::ExtShade || ShType == WinShadingType::BGShade); - BlindOn = (ShType == WinShadingType::IntBlind || ShType == WinShadingType::ExtBlind || ShType == WinShadingType::BGBlind); + ShadeOn = IS_SHADE_ON(ShType); + BlindOn = IS_BLIND_ON(ShType); ScreenOn = (ShType == WinShadingType::ExtScreen); } diff --git a/src/EnergyPlus/HWBaseboardRadiator.cc b/src/EnergyPlus/HWBaseboardRadiator.cc index 50aacbd9610..222fe17c5c0 100644 --- a/src/EnergyPlus/HWBaseboardRadiator.cc +++ b/src/EnergyPlus/HWBaseboardRadiator.cc @@ -1735,7 +1735,7 @@ namespace HWBaseboardRadiator { Area = Surface(SurfNum).Area; if (Surface(SurfNum).Class == SurfaceClass::Window) { - if (SurfWinShadingFlag(SurfNum) == WinShadingType::IntShade || SurfWinShadingFlag(SurfNum) == WinShadingType::IntBlind) { + if (IS_INT_SHADED(SurfWinShadingFlag(SurfNum))) { // The area is the shade or blind area = the sum of the glazing area and the divider area (which is zero if no divider) Area += SurfWinDividerArea(SurfNum); } @@ -1746,8 +1746,7 @@ namespace HWBaseboardRadiator { SurfWinFrameTempSurfIn(SurfNum); } - if (SurfWinDividerArea(SurfNum) > 0.0 && SurfWinShadingFlag(SurfNum) != WinShadingType::IntShade && - SurfWinShadingFlag(SurfNum) != WinShadingType::IntBlind) { + if (SurfWinDividerArea(SurfNum) > 0.0 && !IS_INT_SHADED(SurfWinShadingFlag(SurfNum))) { // Window divider contribution (only from shade or blind for window with divider and interior shade or blind) SumHATsurf += HConvIn(SurfNum) * SurfWinDividerArea(SurfNum) * (1.0 + 2.0 * SurfWinProjCorrDivIn(SurfNum)) * SurfWinDividerTempSurfIn(SurfNum); diff --git a/src/EnergyPlus/HeatBalanceIntRadExchange.cc b/src/EnergyPlus/HeatBalanceIntRadExchange.cc index 185b878215b..09c5ea7db10 100644 --- a/src/EnergyPlus/HeatBalanceIntRadExchange.cc +++ b/src/EnergyPlus/HeatBalanceIntRadExchange.cc @@ -271,9 +271,7 @@ namespace HeatBalanceIntRadExchange { if (state.dataConstruction->Construct(Surface(SurfNum).Construction).TypeIsWindow) { ShadeFlag = SurfWinShadingFlag(SurfNum); ShadeFlagPrev = SurfWinExtIntShadePrevTS(SurfNum); - if ((ShadeFlagPrev != WinShadingType::IntShade && ShadeFlag == WinShadingType::IntShade) || - (ShadeFlagPrev != WinShadingType::IntBlind && ShadeFlag == WinShadingType::IntBlind) || - (ShadeFlagPrev == WinShadingType::IntShade && ShadeFlag != WinShadingType::IntShade) || (ShadeFlagPrev == WinShadingType::IntBlind && ShadeFlag != WinShadingType::IntBlind)) + if (ShadeFlagPrev != ShadeFlag && (IS_INT_SHADED(ShadeFlagPrev) || IS_INT_SHADED(ShadeFlag))) IntShadeOrBlindStatusChanged = true; if (SurfWinWindowModelType(SurfNum) == WindowEQLModel && DataWindowEquivalentLayer::CFS(state.dataConstruction->Construct(Surface(SurfNum).Construction).EQLConsPtr).ISControlled) { @@ -291,8 +289,7 @@ namespace HeatBalanceIntRadExchange { int const ConstrNum = Surface(SurfNum).Construction; zone_info.Emissivity(ZoneSurfNum) = state.dataConstruction->Construct(ConstrNum).InsideAbsorpThermal; auto const &surface_window(SurfaceWindow(SurfNum)); - if (state.dataConstruction->Construct(ConstrNum).TypeIsWindow && - (SurfWinShadingFlag(SurfNum) == WinShadingType::IntShade || SurfWinShadingFlag(SurfNum) == WinShadingType::IntBlind)) { + if (state.dataConstruction->Construct(ConstrNum).TypeIsWindow && IS_INT_SHADED(SurfWinShadingFlag(SurfNum))) { zone_info.Emissivity(ZoneSurfNum) = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), surface_window.EffShBlindEmiss) + InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), surface_window.EffGlassEmiss); @@ -346,7 +343,7 @@ namespace HeatBalanceIntRadExchange { SurfaceEmiss[ZoneSurfNum] = construct.InsideAbsorpThermal; // For windows with an interior shade or blind an effective inside surface temp // and emiss is used here that is a weighted combination of shade/blind and glass temp and emiss. - } else if (SurfWinShadingFlag(SurfNum) == WinShadingType::IntShade || SurfWinShadingFlag(SurfNum) == WinShadingType::IntBlind) { + } else if (IS_INT_SHADED(SurfWinShadingFlag(SurfNum))) { SurfaceTempRad[ZoneSurfNum] = SurfWinEffInsSurfTemp(SurfNum); SurfaceEmiss[ZoneSurfNum] = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), surface_window.EffShBlindEmiss) + InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), surface_window.EffGlassEmiss); diff --git a/src/EnergyPlus/HeatBalanceSurfaceManager.cc b/src/EnergyPlus/HeatBalanceSurfaceManager.cc index 403af6d915a..eb1af6a5db1 100644 --- a/src/EnergyPlus/HeatBalanceSurfaceManager.cc +++ b/src/EnergyPlus/HeatBalanceSurfaceManager.cc @@ -3879,7 +3879,7 @@ namespace HeatBalanceSurfaceManager { for (int SurfNum = firstSurfWin; SurfNum <= lastSurfWin; ++SurfNum) { // For window with an interior shade or blind, emissivity is a combination of glass and shade/blind emissivity WinShadingType ShadeFlag = SurfWinShadingFlag(SurfNum); - if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::IntBlind) + if (IS_INT_SHADED(ShadeFlag)) ITABSF(SurfNum) = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), SurfaceWindow(SurfNum).EffShBlindEmiss) + InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), diff --git a/src/EnergyPlus/HighTempRadiantSystem.cc b/src/EnergyPlus/HighTempRadiantSystem.cc index b89eeffffc6..dcd33cfdc65 100644 --- a/src/EnergyPlus/HighTempRadiantSystem.cc +++ b/src/EnergyPlus/HighTempRadiantSystem.cc @@ -1491,7 +1491,7 @@ namespace HighTempRadiantSystem { Area = Surface(SurfNum).Area; if (Surface(SurfNum).Class == SurfaceClass::Window) { - if (SurfWinShadingFlag(SurfNum) == WinShadingType::IntShade || SurfWinShadingFlag(SurfNum) == WinShadingType::IntBlind) { + if (IS_INT_SHADED(SurfWinShadingFlag(SurfNum))) { // The area is the shade or blind area = the sum of the glazing area and the divider area (which is zero if no divider) Area += SurfWinDividerArea(SurfNum); } @@ -1502,8 +1502,7 @@ namespace HighTempRadiantSystem { SurfWinFrameTempSurfIn(SurfNum); } - if (SurfWinDividerArea(SurfNum) > 0.0 && SurfWinShadingFlag(SurfNum) != WinShadingType::IntShade && - SurfWinShadingFlag(SurfNum) != WinShadingType::IntBlind) { + if (SurfWinDividerArea(SurfNum) > 0.0 && !IS_INT_SHADED(SurfWinShadingFlag(SurfNum))) { // Window divider contribution (only from shade or blind for window with divider and interior shade or blind) SumHATsurf += HConvIn(SurfNum) * SurfWinDividerArea(SurfNum) * (1.0 + 2.0 * SurfWinProjCorrDivIn(SurfNum)) * SurfWinDividerTempSurfIn(SurfNum); diff --git a/src/EnergyPlus/LowTempRadiantSystem.cc b/src/EnergyPlus/LowTempRadiantSystem.cc index 2d7909ee1e8..fec62976001 100644 --- a/src/EnergyPlus/LowTempRadiantSystem.cc +++ b/src/EnergyPlus/LowTempRadiantSystem.cc @@ -5570,7 +5570,7 @@ namespace LowTempRadiantSystem { Real64 Area = Surface(surfNum).Area; if (Surface(surfNum).Class == SurfaceClass::Window) { - if (SurfWinShadingFlag(surfNum) == WinShadingType::IntShade || SurfWinShadingFlag(surfNum) == WinShadingType::IntBlind) { + if (IS_INT_SHADED(SurfWinShadingFlag(surfNum))) { // The area is the shade or blind are = sum of the glazing area and the divider area (which is zero if no divider) Area += SurfWinDividerArea(surfNum); } @@ -5581,8 +5581,7 @@ namespace LowTempRadiantSystem { SurfWinFrameTempSurfIn(surfNum); } - if (SurfWinDividerArea(surfNum) > 0.0 && SurfWinShadingFlag(surfNum) != WinShadingType::IntShade && - SurfWinShadingFlag(surfNum) != WinShadingType::IntBlind) { + if (SurfWinDividerArea(surfNum) > 0.0 && !IS_INT_SHADED(SurfWinShadingFlag(surfNum))) { // Window divider contribution (only from shade or blind for window with divider and interior shade or blind) sumHATsurf += HConvIn(surfNum) * SurfWinDividerArea(surfNum) * (1.0 + 2.0 * SurfWinProjCorrDivIn(surfNum)) * SurfWinDividerTempSurfIn(surfNum); diff --git a/src/EnergyPlus/RoomAirModelAirflowNetwork.cc b/src/EnergyPlus/RoomAirModelAirflowNetwork.cc index 772be99daa4..0f67b0fdab2 100644 --- a/src/EnergyPlus/RoomAirModelAirflowNetwork.cc +++ b/src/EnergyPlus/RoomAirModelAirflowNetwork.cc @@ -1088,8 +1088,7 @@ namespace RoomAirModelAirflowNetwork { HA += HConvIn(SurfNum) * SurfWinFrameArea(SurfNum) * (1.0 + SurfWinProjCorrFrIn(SurfNum)); } - if (SurfWinDividerArea(SurfNum) > 0.0 && SurfWinShadingFlag(SurfNum) != WinShadingType::IntShade && - SurfWinShadingFlag(SurfNum) != WinShadingType::IntBlind) { + if (SurfWinDividerArea(SurfNum) > 0.0 && !IS_INT_SHADED(SurfWinShadingFlag(SurfNum))) { // Window divider contribution(only from shade or blind for window with divider and interior shade or blind) SumHATsurf += HConvIn(SurfNum) * SurfWinDividerArea(SurfNum) * (1.0 + 2.0 * SurfWinProjCorrDivIn(SurfNum)) * SurfWinDividerTempSurfIn(SurfNum); diff --git a/src/EnergyPlus/SolarShading.cc b/src/EnergyPlus/SolarShading.cc index f51b7c75ff9..2440b31bd6d 100644 --- a/src/EnergyPlus/SolarShading.cc +++ b/src/EnergyPlus/SolarShading.cc @@ -10503,9 +10503,7 @@ namespace SolarShading { Real64 AbsorpEff = 0.0; // Effective absorptance of isolated shade layer (fraction of // of incident radiation remaining after reflected portion is // removed that is absorbed - if (WindowShadingControl(WinShadeCtrlNum).ShadingType == WinShadingType::IntShade || - WindowShadingControl(WinShadeCtrlNum).ShadingType == WinShadingType::ExtShade || - WindowShadingControl(WinShadeCtrlNum).ShadingType == WinShadingType::BGShade) { + if (IS_SHADE_ON(WindowShadingControl(WinShadeCtrlNum).ShadingType)) { int ConstrNumSh = Surface(SurfNum).activeShadedConstruction; // Window construction number with shade int TotLay = state.dataConstruction->Construct(ConstrNumSh).TotLayers; // Total layers in a construction diff --git a/src/EnergyPlus/SteamBaseboardRadiator.cc b/src/EnergyPlus/SteamBaseboardRadiator.cc index 7baa5edd2e2..cd9f43b34de 100644 --- a/src/EnergyPlus/SteamBaseboardRadiator.cc +++ b/src/EnergyPlus/SteamBaseboardRadiator.cc @@ -1380,7 +1380,7 @@ namespace SteamBaseboardRadiator { Area = Surface(SurfNum).Area; if (Surface(SurfNum).Class == SurfaceClass::Window) { - if (SurfWinShadingFlag(SurfNum) == WinShadingType::IntShade || SurfWinShadingFlag(SurfNum) == WinShadingType::IntBlind) { + if (IS_INT_SHADED(SurfWinShadingFlag(SurfNum))) { // The area is the shade or blind area = the sum of the glazing area and the divider area (which is zero if no divider) Area += SurfWinDividerArea(SurfNum); } @@ -1391,8 +1391,7 @@ namespace SteamBaseboardRadiator { SurfWinFrameTempSurfIn(SurfNum); } - if (SurfWinDividerArea(SurfNum) > 0.0 && SurfWinShadingFlag(SurfNum) != WinShadingType::IntShade && - SurfWinShadingFlag(SurfNum) != WinShadingType::IntBlind) { + if (SurfWinDividerArea(SurfNum) > 0.0 && !IS_INT_SHADED(SurfWinShadingFlag(SurfNum))) { // Window divider contribution (only from shade or blind for window with divider and interior shade or blind) SumHATsurf += HConvIn(SurfNum) * SurfWinDividerArea(SurfNum) * (1.0 + 2.0 * SurfWinProjCorrDivIn(SurfNum)) * SurfWinDividerTempSurfIn(SurfNum); diff --git a/src/EnergyPlus/SurfaceGeometry.cc b/src/EnergyPlus/SurfaceGeometry.cc index 4a60a35cbcd..3fa22a22893 100644 --- a/src/EnergyPlus/SurfaceGeometry.cc +++ b/src/EnergyPlus/SurfaceGeometry.cc @@ -4770,11 +4770,7 @@ namespace SurfaceGeometry { if (ConstrNumSh > 0) { state.dataSurfaceGeometry->SurfaceTmp(SurfNum).activeShadedConstruction = ConstrNumSh; } else { - if (WindowShadingControl(WSCPtr).ShadingType == WinShadingType::IntShade || - WindowShadingControl(WSCPtr).ShadingType == WinShadingType::IntBlind || - WindowShadingControl(WSCPtr).ShadingType == WinShadingType::ExtShade || - WindowShadingControl(WSCPtr).ShadingType == WinShadingType::ExtScreen || - WindowShadingControl(WSCPtr).ShadingType == WinShadingType::ExtBlind) { + if (IS_INT_SHADED(WindowShadingControl(WSCPtr).ShadingType) || IS_EXT_SHADED(WindowShadingControl(WSCPtr).ShadingType)) { ShDevNum = WindowShadingControl(WSCPtr).ShadingDevice; if (ShDevNum > 0) { CreateShadedWindowConstruction(state, SurfNum, WSCPtr, ShDevNum, shadeControlIndex); @@ -4789,8 +4785,7 @@ namespace SurfaceGeometry { ConstrNum = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction; if (!ErrorsFound && WSCPtr > 0 && ConstrNum > 0 && ConstrNumSh > 0) { - if (WindowShadingControl(WSCPtr).ShadingType == WinShadingType::IntShade || - WindowShadingControl(WSCPtr).ShadingType == WinShadingType::IntBlind) { + if (IS_INT_SHADED(WindowShadingControl(WSCPtr).ShadingType)) { TotLayers = state.dataConstruction->Construct(ConstrNum).TotLayers; TotShLayers = state.dataConstruction->Construct(ConstrNumSh).TotLayers; if (TotShLayers - 1 != TotLayers) { @@ -4813,9 +4808,7 @@ namespace SurfaceGeometry { } } - if (WindowShadingControl(WSCPtr).ShadingType == WinShadingType::ExtShade || - WindowShadingControl(WSCPtr).ShadingType == WinShadingType::ExtScreen || - WindowShadingControl(WSCPtr).ShadingType == WinShadingType::ExtBlind) { + if (IS_EXT_SHADED(WindowShadingControl(WSCPtr).ShadingType)) { TotLayers = state.dataConstruction->Construct(ConstrNum).TotLayers; TotShLayers = state.dataConstruction->Construct(ConstrNumSh).TotLayers; if (TotShLayers - 1 != TotLayers) { @@ -11688,7 +11681,7 @@ namespace SurfaceGeometry { ShDevName = state.dataMaterial->Material(ShDevNum).Name; ConstrNum = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction; ConstrName = state.dataConstruction->Construct(ConstrNum).Name; - if (WindowShadingControl(WSCPtr).ShadingType == WinShadingType::IntShade || WindowShadingControl(WSCPtr).ShadingType == WinShadingType::IntBlind) { + if (IS_INT_SHADED(WindowShadingControl(WSCPtr).ShadingType)) { ConstrNameSh = ConstrName + ':' + ShDevName + ":INT"; } else { ConstrNameSh = ConstrName + ':' + ShDevName + ":EXT"; diff --git a/src/EnergyPlus/UFADManager.cc b/src/EnergyPlus/UFADManager.cc index 3f115278cd6..86b5cfbdb22 100644 --- a/src/EnergyPlus/UFADManager.cc +++ b/src/EnergyPlus/UFADManager.cc @@ -212,7 +212,7 @@ namespace UFADManager { if (SurfNum == 0) continue; if (Surface(SurfNum).ExtBoundCond == ExternalEnvironment || Surface(SurfNum).ExtBoundCond == OtherSideCoefNoCalcExt || Surface(SurfNum).ExtBoundCond == OtherSideCoefCalcExt || Surface(SurfNum).ExtBoundCond == OtherSideCondModeledExt) { - if (SurfWinShadingFlag(SurfNum) == WinShadingType::IntShade || SurfWinShadingFlag(SurfNum) == WinShadingType::IntBlind) { + if (IS_INT_SHADED(SurfWinShadingFlag(SurfNum))) { ++NumShadesDown; } } diff --git a/src/EnergyPlus/VentilatedSlab.cc b/src/EnergyPlus/VentilatedSlab.cc index 0c52fda9a81..7dbb14b961a 100644 --- a/src/EnergyPlus/VentilatedSlab.cc +++ b/src/EnergyPlus/VentilatedSlab.cc @@ -4459,7 +4459,7 @@ namespace VentilatedSlab { Area = Surface(SurfNum).Area; if (Surface(SurfNum).Class == SurfaceClass::Window) { - if (SurfWinShadingFlag(SurfNum) == WinShadingType::IntShade || SurfWinShadingFlag(SurfNum) == WinShadingType::IntBlind) { + if (IS_INT_SHADED(SurfWinShadingFlag(SurfNum))) { // The area is the shade or blind are = sum of the glazing area and the divider area (which is zero if no divider) Area += SurfWinDividerArea(SurfNum); } @@ -4470,8 +4470,7 @@ namespace VentilatedSlab { SurfWinFrameTempSurfIn(SurfNum); } - if (SurfWinDividerArea(SurfNum) > 0.0 && SurfWinShadingFlag(SurfNum) != WinShadingType::IntShade && - SurfWinShadingFlag(SurfNum) != WinShadingType::IntBlind) { + if (SurfWinDividerArea(SurfNum) > 0.0 && !IS_INT_SHADED(SurfWinShadingFlag(SurfNum))) { // Window divider contribution (only from shade or blind for window with divider and interior shade or blind) SumHATsurf += HConvIn(SurfNum) * SurfWinDividerArea(SurfNum) * (1.0 + 2.0 * SurfWinProjCorrDivIn(SurfNum)) * SurfWinDividerTempSurfIn(SurfNum); diff --git a/src/EnergyPlus/WindowComplexManager.cc b/src/EnergyPlus/WindowComplexManager.cc index 9c09350f7b8..0666f2291ce 100644 --- a/src/EnergyPlus/WindowComplexManager.cc +++ b/src/EnergyPlus/WindowComplexManager.cc @@ -3298,7 +3298,7 @@ namespace WindowComplexManager { SurfOutsideEmiss = emis(1); IncidentSolar = Surface(SurfNum).Area * SurfQRadSWOutIncident(SurfNum); - if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::IntBlind) { + if (IS_INT_SHADED(ShadeFlag)) { // Interior shade or blind ConvHeatFlowNatural = -qv(nlayer) * height * width; @@ -3417,7 +3417,7 @@ namespace WindowComplexManager { SurfWinHeatTransfer(SurfNum) -= QS(Surface(SurfNum).SolarEnclIndex) * Surface(SurfNum).Area * TransDiff; SurfWinLossSWZoneToOutWinRep(SurfNum) = QS(Surface(SurfNum).SolarEnclIndex) * Surface(SurfNum).Area * TransDiff; - if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::ExtShade) { + if (IS_INT_SHADED(ShadeFlag)) { SurfWinShadingAbsorbedSolar(SurfNum) = (SurfWinExtBeamAbsByShade(SurfNum) + SurfWinExtDiffAbsByShade(SurfNum)) * (Surface(SurfNum).Area + SurfWinDividerArea(SurfNum)); SurfWinShadingAbsorbedSolarEnergy(SurfNum) = SurfWinShadingAbsorbedSolar(SurfNum) * state.dataGlobal->TimeStepZoneSec; diff --git a/src/EnergyPlus/WindowManager.cc b/src/EnergyPlus/WindowManager.cc index 0f650963840..fbbddb68e17 100644 --- a/src/EnergyPlus/WindowManager.cc +++ b/src/EnergyPlus/WindowManager.cc @@ -2345,13 +2345,13 @@ namespace WindowManager { } if (state.dataMaterial->Material(LayPtr).Group == Shade || state.dataMaterial->Material(LayPtr).Group == WindowBlind || state.dataMaterial->Material(LayPtr).Group == Screen) { - if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::IntBlind) ShadeLayPtr = state.dataConstruction->Construct(IConst).LayerPoint(state.dataConstruction->Construct(IConst).TotLayers); - if (ShadeFlag == WinShadingType::ExtShade || ShadeFlag == WinShadingType::ExtBlind || ShadeFlag == WinShadingType::ExtScreen) ShadeLayPtr = state.dataConstruction->Construct(IConst).LayerPoint(1); - if (ShadeFlag == WinShadingType::BGShade || ShadeFlag == WinShadingType::BGBlind) { + if (IS_INT_SHADED(ShadeFlag)) ShadeLayPtr = state.dataConstruction->Construct(IConst).LayerPoint(state.dataConstruction->Construct(IConst).TotLayers); + if (IS_EXT_SHADED(ShadeFlag)) ShadeLayPtr = state.dataConstruction->Construct(IConst).LayerPoint(1); + if (IS_BG_SHADED(ShadeFlag)) { ShadeLayPtr = state.dataConstruction->Construct(IConst).LayerPoint(3); if (TotGlassLay == 3) ShadeLayPtr = state.dataConstruction->Construct(IConst).LayerPoint(5); } - if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::ExtShade || ShadeFlag == WinShadingType::BGShade || ShadeFlag == WinShadingType::ExtScreen) { + if (IS_SHADE_SCREEN_ON(ShadeFlag)) { // Shade or screen on if (state.dataGlobal->AnyEnergyManagementSystemInModel) { // check to make sure the user hasn't messed up the shade control values if (state.dataMaterial->Material(ShadeLayPtr).Group == WindowBlind) { @@ -2411,12 +2411,11 @@ namespace WindowManager { } // End of loop over glass, gap and blind/shade layers in a window construction - if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::ExtShade || ShadeFlag == WinShadingType::IntBlind || ShadeFlag == WinShadingType::ExtBlind || - ShadeFlag == WinShadingType::ExtScreen) { + if (IS_INT_SHADED(ShadeFlag) || IS_EXT_SHADED(ShadeFlag)) { // Interior or exterior blind, shade or screen is on. // Fill gap between blind/shade and adjacent glass with air properties. ++IGap; - if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::ExtShade || ShadeFlag == WinShadingType::ExtScreen) { // Interior or exterior shade + if (IS_SHADE_ON(ShadeFlag)) { // Interior or exterior shade state.dataWindowManager->gap(IGap) = state.dataMaterial->Material(ShadeLayPtr).WinShadeToGlassDist; } else { // Interior or exterior blind state.dataWindowManager->gap(IGap) = Blind(SurfWinBlindNumber(SurfNum)).BlindToGlassDist; @@ -2563,7 +2562,7 @@ namespace WindowManager { dth3 = state.dataWindowManager->thetas(6) - state.dataWindowManager->thetas(5); dth4 = state.dataWindowManager->thetas(8) - state.dataWindowManager->thetas(7); - if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::IntBlind) { + if (IS_INT_SHADED(ShadeFlag)) { SurfInsideTemp = state.dataWindowManager->thetas(2 * state.dataWindowManager->ngllayer + 2) - state.dataWindowManager->TKelvin; EffShBlEmiss = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), window.EffShBlindEmiss); EffGlEmiss = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), window.EffGlassEmiss); @@ -2571,7 +2570,7 @@ namespace WindowManager { } else { SurfInsideTemp = state.dataWindowManager->thetas(2 * state.dataWindowManager->ngllayer) - state.dataWindowManager->TKelvin; } - if (ShadeFlag == WinShadingType::ExtShade || ShadeFlag == WinShadingType::ExtBlind || ShadeFlag == WinShadingType::ExtScreen) { + if (IS_EXT_SHADED(ShadeFlag)) { SurfOutsideTemp = state.dataWindowManager->thetas(2 * state.dataWindowManager->ngllayer + 1) - state.dataWindowManager->TKelvin; // this index looks suspicious (CR 8202) // SurfOutsideEmiss = emis(1) ! this index should be coordinated with previous line SurfOutsideEmiss = state.dataWindowManager->emis(2 * state.dataWindowManager->ngllayer + 1); // fix for CR 8202 @@ -2938,22 +2937,21 @@ namespace WindowManager { AbsRadShadeFace = 0.0; TGapNew = 0.0; - if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::ExtShade || ShadeFlag == WinShadingType::IntBlind || ShadeFlag == WinShadingType::ExtBlind || ShadeFlag == WinShadingType::BGShade || - ShadeFlag == WinShadingType::BGBlind || ShadeFlag == WinShadingType::ExtScreen) { + if (IS_SHADE_SCREEN_ON(ShadeFlag) || IS_BLIND_ON(ShadeFlag)) { state.dataWindowManager->nglfacep = state.dataWindowManager->nglface + 2; AbsRadShadeFace(1) = DataSurfaces::AbsFrontSide(SurfNum); AbsRadShadeFace(2) = DataSurfaces::AbsBackSide(SurfNum); - if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::IntBlind) AbsRadShadeFace(2) += SurfWinIntLWAbsByShade(SurfNum); + if (IS_INT_SHADED(ShadeFlag)) AbsRadShadeFace(2) += SurfWinIntLWAbsByShade(SurfNum); sconsh = state.dataWindowManager->scon(state.dataWindowManager->ngllayer + 1); TauShIR = state.dataWindowManager->tir(state.dataWindowManager->nglface + 1); EpsShIR1 = state.dataWindowManager->emis(state.dataWindowManager->nglface + 1); EpsShIR2 = state.dataWindowManager->emis(state.dataWindowManager->nglface + 2); RhoShIR1 = max(0.0, 1.0 - TauShIR - EpsShIR1); RhoShIR2 = max(0.0, 1.0 - TauShIR - EpsShIR2); - if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::IntBlind) { + if (IS_INT_SHADED(ShadeFlag)) { RhoGlIR2 = 1.0 - state.dataWindowManager->emis(2 * state.dataWindowManager->ngllayer); ShGlReflFacIR = 1.0 - RhoGlIR2 * RhoShIR1; - } else if (ShadeFlag == WinShadingType::ExtShade || ShadeFlag == WinShadingType::ExtBlind || ShadeFlag == WinShadingType::ExtScreen) { + } else if (IS_EXT_SHADED(ShadeFlag)) { RhoGlIR1 = 1.0 - state.dataWindowManager->emis(1); ShGlReflFacIR = 1.0 - RhoGlIR1 * RhoShIR2; } @@ -2985,7 +2983,7 @@ namespace WindowManager { (Surface(SurfNum).IntConvCoeff == -2)) { // coef model is "detailed" and not prescribed by user // need to find inside face index, varies with shade/blind etc. - if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::IntBlind) { + if (IS_EXT_SHADED(ShadeFlag)) { InsideFaceIndex = state.dataWindowManager->nglfacep; } else { InsideFaceIndex = state.dataWindowManager->nglface; @@ -3001,8 +2999,7 @@ namespace WindowManager { // coefficient from glass and shade/blind to gap between glass and shade/blind, // effective gap air temperature, velocity of air in gap and gap outlet temperature. - if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::ExtShade || ShadeFlag == WinShadingType::IntBlind || ShadeFlag == WinShadingType::ExtBlind || - ShadeFlag == WinShadingType::ExtScreen) { + if (IS_EXT_SHADED(ShadeFlag) || IS_INT_SHADED(ShadeFlag)) { ExtOrIntShadeNaturalFlow(state, SurfNum, iter, VGap, TGapNew, TGapOutlet, hcv, ConvHeatFlowNatural); if (iter >= 1) { hcv = 0.5 * (hcvPrev + hcv); @@ -3018,7 +3015,7 @@ namespace WindowManager { // get glass-to-air forced convection heat transfer coefficient, average gap air temperature, and // convective heat flow from gap. - if (ShadeFlag != WinShadingType::BGShade && ShadeFlag != WinShadingType::BGBlind && SurfWinAirflowThisTS(SurfNum) > 0.0) { + if (!IS_BG_SHADED(ShadeFlag) && SurfWinAirflowThisTS(SurfNum) > 0.0) { BetweenGlassForcedFlow(state, SurfNum, iter, VAirflowGap, TAirflowGapNew, TAirflowGapOutlet, hcvAirflowGap, ConvHeatFlowForced); } @@ -3027,7 +3024,7 @@ namespace WindowManager { // Also get average gas temperature in the two gaps, and, for airflow window, the sum of the // convective heat flows from the gaps. - if (ShadeFlag == WinShadingType::BGShade || ShadeFlag == WinShadingType::BGBlind) { + if (IS_BG_SHADED(ShadeFlag)) { if (SurfWinAirflowThisTS(SurfNum) == 0.0) { // Natural convection in gaps BetweenGlassShadeNaturalFlow(state, SurfNum, iter, VGap, TGapNewBG, hcvBG); } else { // Forced convection in gaps @@ -3051,7 +3048,7 @@ namespace WindowManager { Aface(1, 2) = -state.dataWindowManager->scon(1); Aface(2, 2) = hr(2) + state.dataWindowManager->scon(1) + state.dataWindowManager->hcin; - if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::IntBlind) { + if (IS_INT_SHADED(ShadeFlag)) { Bface(2) = state.dataWindowManager->Rmir * state.dataWindowManager->emis(2) * TauShIR / ShGlReflFacIR + hcv * TGapNew + state.dataWindowManager->AbsRadGlassFace(2); Bface(3) = state.dataWindowManager->Rmir * TauShIR * RhoGlIR2 * EpsShIR1 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(1); Bface(4) = state.dataWindowManager->Rmir * EpsShIR2 + state.dataWindowManager->hcin * state.dataWindowManager->tin + AbsRadShadeFace(2); @@ -3107,7 +3104,7 @@ namespace WindowManager { Aface(3, 4) = -state.dataWindowManager->scon(2); Aface(4, 4) = hr(4) + state.dataWindowManager->scon(2) + state.dataWindowManager->hcin; - if (ShadeFlag != WinShadingType::BGShade && ShadeFlag != WinShadingType::BGBlind && SurfWinAirflowThisTS(SurfNum) > 0.0) { + if (!IS_BG_SHADED(ShadeFlag) && SurfWinAirflowThisTS(SurfNum) > 0.0) { Bface(2) = state.dataWindowManager->AbsRadGlassFace(2) + hcvAirflowGap * TAirflowGapNew; Bface(3) = state.dataWindowManager->AbsRadGlassFace(3) + hcvAirflowGap * TAirflowGapNew; Aface(2, 2) = state.dataWindowManager->scon(1) + hcvAirflowGap - state.dataWindowManager->A23P * hr(2); @@ -3116,7 +3113,7 @@ namespace WindowManager { Aface(3, 3) = hcvAirflowGap + state.dataWindowManager->scon(2) + state.dataWindowManager->A32P * hr(3); } - if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::IntBlind) { + if (IS_INT_SHADED(ShadeFlag)) { Bface(4) = state.dataWindowManager->Rmir * state.dataWindowManager->emis(4) * TauShIR / ShGlReflFacIR + hcv * TGapNew + state.dataWindowManager->AbsRadGlassFace(4); Bface(5) = state.dataWindowManager->Rmir * TauShIR * RhoGlIR2 * EpsShIR1 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(1); Bface(6) = state.dataWindowManager->Rmir * EpsShIR2 + state.dataWindowManager->hcin * state.dataWindowManager->tin + AbsRadShadeFace(2); @@ -3130,7 +3127,7 @@ namespace WindowManager { Aface(6, 6) = hr(6) + sconsh + state.dataWindowManager->hcin; } - if (ShadeFlag == WinShadingType::ExtShade || ShadeFlag == WinShadingType::ExtBlind || ShadeFlag == WinShadingType::ExtScreen) { + if (IS_EXT_SHADED(ShadeFlag)) { Bface(1) = state.dataWindowManager->Outir * state.dataWindowManager->emis(1) * TauShIR / ShGlReflFacIR + hcv * TGapNew + state.dataWindowManager->AbsRadGlassFace(1); Bface(5) = state.dataWindowManager->Outir * EpsShIR1 + state.dataWindowManager->hcout * state.dataWindowManager->tout + AbsRadShadeFace(1); Bface(6) = state.dataWindowManager->Outir * TauShIR * RhoGlIR1 * EpsShIR2 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(2); @@ -3144,7 +3141,7 @@ namespace WindowManager { Aface(6, 6) = hr(6) * (1 - RhoGlIR1 * (EpsShIR2 + RhoShIR2)) / ShGlReflFacIR + sconsh + hcv; } - if (ShadeFlag == WinShadingType::BGShade || ShadeFlag == WinShadingType::BGBlind) { + if (IS_BG_SHADED(ShadeFlag)) { for (i = 1; i <= 6; ++i) { RhoIR(i) = max(0.0, 1.0 - state.dataWindowManager->tir(i) - state.dataWindowManager->emis(i)); } @@ -3234,7 +3231,7 @@ namespace WindowManager { Aface(5, 5) = hcvAirflowGap + state.dataWindowManager->scon(3) + state.dataWindowManager->A54P * hr(5); } - if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::IntBlind) { + if (IS_INT_SHADED(ShadeFlag)) { Bface(6) = state.dataWindowManager->Rmir * state.dataWindowManager->emis(6) * TauShIR / ShGlReflFacIR + hcv * TGapNew + state.dataWindowManager->AbsRadGlassFace(6); Bface(7) = state.dataWindowManager->Rmir * TauShIR * RhoGlIR2 * EpsShIR1 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(1); Bface(8) = state.dataWindowManager->Rmir * EpsShIR2 + state.dataWindowManager->hcin * state.dataWindowManager->tin + AbsRadShadeFace(2); @@ -3360,7 +3357,7 @@ namespace WindowManager { Aface(7, 8) = -state.dataWindowManager->scon(4); Aface(8, 8) = hr(8) + state.dataWindowManager->scon(4) + state.dataWindowManager->hcin; - if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::IntBlind) { + if (IS_INT_SHADED(ShadeFlag)) { Bface(8) = state.dataWindowManager->Rmir * state.dataWindowManager->emis(8) * TauShIR / ShGlReflFacIR + hcv * TGapNew + state.dataWindowManager->AbsRadGlassFace(8); Bface(9) = state.dataWindowManager->Rmir * TauShIR * RhoGlIR2 * EpsShIR1 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(1); Bface(10) = state.dataWindowManager->Rmir * EpsShIR2 + state.dataWindowManager->hcin * state.dataWindowManager->tin + AbsRadShadeFace(2); @@ -3426,7 +3423,7 @@ namespace WindowManager { // For all cases, get total window heat gain for reporting. See CalcWinFrameAndDividerTemps for // contribution of frame and divider. IncidentSolar = Surface(SurfNum).Area * SurfQRadSWOutIncident(SurfNum); - if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::IntBlind) { + if (IS_INT_SHADED(ShadeFlag)) { // Interior shade or blind SurfWinConvHeatFlowNatural(SurfNum) = ConvHeatFlowNatural; // Window heat gain from glazing and shade/blind to zone. Consists of transmitted solar, convection @@ -3507,11 +3504,11 @@ namespace WindowManager { } TransDiff = state.dataConstruction->Construct(ConstrNum).TransDiff; // Default value for TransDiff here - if (ShadeFlag == WinShadingType::NoShade || ShadeFlag == WinShadingType::ShadeOff) { + if (!IS_SHADED(ShadeFlag)) { TransDiff = state.dataConstruction->Construct(ConstrNum).TransDiff; - } else if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::ExtShade || ShadeFlag == WinShadingType::BGShade || ShadeFlag == WinShadingType::ExtScreen) { + } else if (IS_SHADE_SCREEN_ON(ShadeFlag)) { TransDiff = state.dataConstruction->Construct(ConstrNumSh).TransDiff; - } else if (ShadeFlag == WinShadingType::IntBlind || ShadeFlag == WinShadingType::ExtBlind || ShadeFlag == WinShadingType::BGBlind) { + } else if (IS_BLIND_ON(ShadeFlag)) { TransDiff = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), state.dataConstruction->Construct(ConstrNumSh).BlTransDiff); } else if (ShadeFlag == WinShadingType::SwitchableGlazing) { @@ -3650,7 +3647,7 @@ namespace WindowManager { nglassfaces = 2 * state.dataConstruction->Construct(ConstrNumSh).TotGlassLayers; TotGaps = state.dataConstruction->Construct(ConstrNumSh).TotGlassLayers; - if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::IntBlind) { // Interior shade or blind + if (IS_INT_SHADED(ShadeFlag)) { // Interior shade or blind MatNumSh = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(nglassfaces); TGapInlet = state.dataWindowManager->tin; TGlassFace = state.dataWindowManager->thetas(nglassfaces); @@ -3752,7 +3749,7 @@ namespace WindowManager { TGapNew = TAve - (GapHeightChar / GapHeight) * (TGapOutlet - TGapInlet); // Convective heat flow from gap to room air for interior shade or blind - if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::IntBlind) { + if (IS_INT_SHADED(ShadeFlag)) { RhoAir = state.dataWindowManager->AirProps(1) + state.dataWindowManager->AirProps(2) * (TGapNew - state.dataWindowManager->TKelvin); QConvGap = RhoAir * AGap * VGap * 1008.0 * (TGapOutlet - TGapInlet); // Exclude convection to gap due to divider, if present; divider convection handled @@ -4674,9 +4671,9 @@ namespace WindowManager { // Initialize face temperatures of shade or blind, if present ShadeFlag = SurfWinShadingFlag(SurfNum); - if (SurfWinExtIntShadePrevTS(SurfNum) == WinShadingType::IntShade || SurfWinExtIntShadePrevTS(SurfNum) == WinShadingType::IntBlind || + if (IS_INT_SHADED(SurfWinExtIntShadePrevTS(SurfNum)) || SurfWinExtIntShadePrevTS(SurfNum) == WinShadingType::ExtShade || SurfWinExtIntShadePrevTS(SurfNum) == WinShadingType::ExtBlind || - SurfWinExtIntShadePrevTS(SurfNum) == WinShadingType::BGShade || SurfWinExtIntShadePrevTS(SurfNum) == WinShadingType::BGBlind) { + IS_BG_SHADED(SurfWinExtIntShadePrevTS(SurfNum))) { // Shade or blind is on during the previous TS; use previous-TS values of shade/blind face temps. // Note that if shade or blind is NOT on in the current TS the following two // temperature values, although calculated here, are not used. The shade/blind face numbers @@ -4696,15 +4693,13 @@ namespace WindowManager { // equal to tout. For between-glass shade/blind it is assumed to be equal to the // average temperature of the adjacent glass faces. - if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::IntBlind) { + if (IS_INT_SHADED(ShadeFlag)) { state.dataWindowManager->thetas(state.dataWindowManager->nglface + 1) = state.dataWindowManager->tin + (AbsRadShade(1) + AbsRadShade(2)) / (2 * (state.dataWindowManager->hcin + hrad)); state.dataWindowManager->thetas(state.dataWindowManager->nglface + 2) = state.dataWindowManager->thetas(state.dataWindowManager->nglface + 1); - } - if (ShadeFlag == WinShadingType::ExtShade || ShadeFlag == WinShadingType::ExtBlind) { + } else if (ShadeFlag == WinShadingType::ExtShade || ShadeFlag == WinShadingType::ExtBlind) { state.dataWindowManager->thetas(state.dataWindowManager->nglface + 1) = state.dataWindowManager->tout + (AbsRadShade(1) + AbsRadShade(2)) / (2 * (state.dataWindowManager->hcout + hrad)); state.dataWindowManager->thetas(state.dataWindowManager->nglface + 2) = state.dataWindowManager->thetas(state.dataWindowManager->nglface + 1); - } - if (ShadeFlag == WinShadingType::BGShade || ShadeFlag == WinShadingType::BGBlind) { + } else if (IS_BG_SHADED(ShadeFlag)) { // Between-glass shade/blind allowed only for double and triple glazing. // The factor 16.0 below is based on a combined convective/radiative heat transfer // coefficient on either side of the shade/blind of 8.0 W/m2-K -- about 1.4 Btu/h-ft2-F. @@ -5904,7 +5899,7 @@ namespace WindowManager { // from the inside surface of the divider goes directly into the zone air -- i.e., the IR radiative // interaction between divider and shade is ignored due to the difficulty of calculating this interaction // at the same time that the interaction between glass and shade is calculated. - if (SurfWinShadingFlag(SurfNum) == WinShadingType::IntShade || SurfWinShadingFlag(SurfNum) == WinShadingType::IntBlind) + if (IS_INT_SHADED(SurfWinShadingFlag(SurfNum))) SurfWinDividerHeatGain(SurfNum) = DividerHeatGain; DivTempOut = SurfWinDividerTempSurfOut(SurfNum) + state.dataWindowManager->TKelvin; } // End of check if window has dividers @@ -6362,7 +6357,7 @@ namespace WindowManager { hInRad = state.dataWindowManager->emis(state.dataWindowManager->nglface) * state.dataWindowManager->sigma * 0.5 * pow_3(state.dataWindowManager->tin + state.dataWindowManager->thetas(state.dataWindowManager->nglface)); rIn = 1.0 / (hInRad + state.dataWindowManager->hcin); - if (!(ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::IntBlind)) AbsBeamShadeNorm = 0.0; + if (!IS_INT_SHADED(ShadeFlag)) AbsBeamShadeNorm = 0.0; { auto const SELECT_CASE_var(state.dataWindowManager->ngllayer); From 1cff5a5f0f5b14a66ea78ce611c2ff95ee1fd154 Mon Sep 17 00:00:00 2001 From: xuanluo113 Date: Mon, 25 Jan 2021 16:12:18 -0800 Subject: [PATCH 24/76] window control type enum --- src/EnergyPlus/DataSurfaces.cc | 23 -- src/EnergyPlus/DataSurfaces.hh | 53 ++-- src/EnergyPlus/DaylightingManager.cc | 14 +- src/EnergyPlus/HeatBalanceSurfaceManager.cc | 44 +-- src/EnergyPlus/SolarShading.cc | 302 ++++++++++---------- src/EnergyPlus/SurfaceGeometry.cc | 68 ++--- src/EnergyPlus/WindowComplexManager.cc | 2 +- src/EnergyPlus/WindowManager.cc | 4 +- src/EnergyPlus/api/EnergyPlusPgm.cc | 1 - tst/EnergyPlus/unit/SurfaceGeometry.unit.cc | 6 +- 10 files changed, 252 insertions(+), 265 deletions(-) diff --git a/src/EnergyPlus/DataSurfaces.cc b/src/EnergyPlus/DataSurfaces.cc index 22a75c3caf5..f3fe27023b9 100644 --- a/src/EnergyPlus/DataSurfaces.cc +++ b/src/EnergyPlus/DataSurfaces.cc @@ -237,29 +237,6 @@ namespace DataSurfaces { int const InConvWinLoc_WindowBelowThis(4); // this is a wall with window below it int const InConvWinLoc_LargePartOfExteriorWall(5); // this is a big window taking up most of wall - // WindowShadingControl Control Types - int const WSCT_AlwaysOn(1); // AlwaysOn - int const WSCT_AlwaysOff(2); // AlwaysOff - int const WSCT_OnIfScheduled(3); // OnIfScheduleAllows - int const WSCT_HiSolar(4); // OnIfHighSolarOnWindow - int const WSCT_HiHorzSolar(5); // OnIfHighHorizontalSolar - int const WSCT_HiOutAirTemp(6); // OnIfHighOutsideAirTemp - int const WSCT_HiZoneAirTemp(7); // OnIfHighZoneAirTemp - int const WSCT_HiZoneCooling(8); // OnIfHighZoneCooling - int const WSCT_HiGlare(9); // OnIfHighGlare - int const WSCT_MeetDaylIlumSetp(10); // MeetDaylightIlluminanceSetpoint - int const WSCT_OnNightLoOutTemp_OffDay(11); // OnNightIfLowOutsideTemp/OffDay - int const WSCT_OnNightLoInTemp_OffDay(12); // OnNightIfLowInsideTemp/OffDay - int const WSCT_OnNightIfHeating_OffDay(13); // OnNightIfHeating/OffDay - int const WSCT_OnNightLoOutTemp_OnDayCooling(14); // OnNightIfLowOutsideTemp/OnDayIfCooling - int const WSCT_OnNightIfHeating_OnDayCooling(15); // OnNightIfHeating/OnDayIfCooling - int const WSCT_OffNight_OnDay_HiSolarWindow(16); // OffNight/OnDayIfCoolingAndHighSolarOnWindow - int const WSCT_OnNight_OnDay_HiSolarWindow(17); // OnNight/OnDayIfCoolingAndHighSolarOnWindow - int const WSCT_OnHiOutTemp_HiSolarWindow(18); // OnIfHighOutsideAirTempAndHighSolarOnWindow - int const WSCT_OnHiOutTemp_HiHorzSolar(19); // OnIfHighOutsideAirTempAndHighHorizontalSolar - int const WSCT_OnHiZoneTemp_HiSolarWindow(20); // OnIfHighZoneAirTempAndHighSolarOnWindow - int const WSCT_OnHiZoneTemp_HiHorzSolar(21); // OnIfHighZoneAirTempAndHighHorizontalSolar - // WindowShadingControl Slat Angle Control for Blinds int const WSC_SAC_FixedSlatAngle(1); int const WSC_SAC_ScheduledSlatAngle(2); diff --git a/src/EnergyPlus/DataSurfaces.hh b/src/EnergyPlus/DataSurfaces.hh index 532cb33d7ea..2a96e6983c6 100644 --- a/src/EnergyPlus/DataSurfaces.hh +++ b/src/EnergyPlus/DataSurfaces.hh @@ -147,6 +147,32 @@ namespace DataSurfaces { ShadeOff = 10 }; + enum WindowShadingControlType { + UnControlled = 0, + AlwaysOn = 1, + AlwaysOff = 2, + OnIfScheduled = 3, + HiSolar = 4, + HiHorzSolar = 5, + HiOutAirTemp = 6, + HiZoneAirTemp = 7, + HiZoneCooling = 8, + HiGlare = 9, + MeetDaylIlumSetp = 10, + OnNightLoOutTemp_OffDay = 11, + OnNightLoInTemp_OffDay = 12, + OnNightIfHeating_OffDay = 13, + OnNightLoOutTemp_OnDayCooling = 14, + OnNightIfHeating_OnDayCooling = 15, + OffNight_OnDay_HiSolarWindow = 16, + OnNight_OnDay_HiSolarWindow = 17, + OnHiOutTemp_HiSolarWindow = 18, + OnHiOutTemp_HiHorzSolar = 19, + OnHiZoneTemp_HiSolarWindow = 20, + OnHiZoneTemp_HiHorzSolar = 21 + + }; + // Parameters to indicate exterior boundary conditions for use with // the Surface derived type (see below): // Note: Positive values correspond to an interzone adjacent surface @@ -266,29 +292,6 @@ namespace DataSurfaces { extern int const InConvWinLoc_WindowBelowThis; // this is a wall with window below it extern int const InConvWinLoc_LargePartOfExteriorWall; // this is a big window taking up most of wall - // WindowShadingControl Control Types - extern int const WSCT_AlwaysOn; // AlwaysOn - extern int const WSCT_AlwaysOff; // AlwaysOff - extern int const WSCT_OnIfScheduled; // OnIfScheduleAllows - extern int const WSCT_HiSolar; // OnIfHighSolarOnWindow - extern int const WSCT_HiHorzSolar; // OnIfHighHorizontalSolar - extern int const WSCT_HiOutAirTemp; // OnIfHighOutsideAirTemp - extern int const WSCT_HiZoneAirTemp; // OnIfHighZoneAirTemp - extern int const WSCT_HiZoneCooling; // OnIfHighZoneCooling - extern int const WSCT_HiGlare; // OnIfHighGlare - extern int const WSCT_MeetDaylIlumSetp; // MeetDaylightIlluminanceSetpoint - extern int const WSCT_OnNightLoOutTemp_OffDay; // OnNightIfLowOutsideTemp/OffDay - extern int const WSCT_OnNightLoInTemp_OffDay; // OnNightIfLowInsideTemp/OffDay - extern int const WSCT_OnNightIfHeating_OffDay; // OnNightIfHeating/OffDay - extern int const WSCT_OnNightLoOutTemp_OnDayCooling; // OnNightIfLowOutsideTemp/OnDayIfCooling - extern int const WSCT_OnNightIfHeating_OnDayCooling; // OnNightIfHeating/OnDayIfCooling - extern int const WSCT_OffNight_OnDay_HiSolarWindow; // OffNight/OnDayIfCoolingAndHighSolarOnWindow - extern int const WSCT_OnNight_OnDay_HiSolarWindow; // OnNight/OnDayIfCoolingAndHighSolarOnWindow - extern int const WSCT_OnHiOutTemp_HiSolarWindow; // OnIfHighOutsideAirTempAndHighSolarOnWindow - extern int const WSCT_OnHiOutTemp_HiHorzSolar; // OnIfHighOutsideAirTempAndHighHorizontalSolar - extern int const WSCT_OnHiZoneTemp_HiSolarWindow; // OnIfHighZoneAirTempAndHighSolarOnWindow - extern int const WSCT_OnHiZoneTemp_HiHorzSolar; // OnIfHighZoneAirTempAndHighHorizontalSolar - // WindowShadingControl Slat Angle Control for Blinds extern int const WSC_SAC_FixedSlatAngle; extern int const WSC_SAC_ScheduledSlatAngle; @@ -1114,7 +1117,7 @@ namespace DataSurfaces { // ExteriorShade,BetweenGlassShade,InteriorBlind,ExteriorBlind,BetweenGlassBlind, // ExteriorScreen; // this must be a Material:WindowShade, Material:WindowScreen, or Material:WindowBlind - int ShadingControlType; // Takes one of the following values that specifies type of shading control + WindowShadingControlType ShadingControlType; // Takes one of the following values that specifies type of shading control // CHARACTER(len=60) :: ShadingControlType =' ' ! Takes one of the following values that specifies type of shading control // (control is active only when schedule value = 1; if no schedule // specified, schedule value defaults to 1) @@ -1188,7 +1191,7 @@ namespace DataSurfaces { // Default Constructor WindowShadingControlData() - : ZoneIndex(0), SequenceNumber(0), ShadingType(WinShadingType::NoShade), getInputShadedConstruction(0), ShadingDevice(0), ShadingControlType(0), + : ZoneIndex(0), SequenceNumber(0), ShadingType(WinShadingType::NoShade), getInputShadedConstruction(0), ShadingDevice(0), ShadingControlType(UnControlled), Schedule(0), SetPoint(0.0), SetPoint2(0.0), ShadingControlIsScheduled(false), GlareControlIsActive(false), SlatAngleSchedule(0), SlatAngleControlForBlinds(0), DaylightControlIndex(0), MultiSurfaceCtrlIsGroup(false), FenestrationCount(0) { diff --git a/src/EnergyPlus/DaylightingManager.cc b/src/EnergyPlus/DaylightingManager.cc index 84cf87ce51e..b1828549ee8 100644 --- a/src/EnergyPlus/DaylightingManager.cc +++ b/src/EnergyPlus/DaylightingManager.cc @@ -4357,7 +4357,7 @@ namespace EnergyPlus::DaylightingManager { } } - if (WindowShadingControl(Surface(SurfNum).activeWindowShadingControl).ShadingControlType == WSCT_MeetDaylIlumSetp) { + if (WindowShadingControl(Surface(SurfNum).activeWindowShadingControl).ShadingControlType == MeetDaylIlumSetp) { // Error if window has ShadingControlType = MeetDaylightingIlluminanceSetpoint & // but is not in a Daylighting:Detailed zone if (thisSurfEnclosure.TotalEnclosureDaylRefPoints == 0) { @@ -6529,7 +6529,7 @@ namespace EnergyPlus::DaylightingManager { int IWin = state.dataDaylightingData->ZoneDaylight(ZoneNum).DayltgExtWinSurfNums(loop); ICtrl = Surface(IWin).activeWindowShadingControl; if (Surface(IWin).HasShadeControl && ISWFLG == 0) { - if (WindowShadingControl(ICtrl).ShadingControlType == WSCT_MeetDaylIlumSetp && + if (WindowShadingControl(ICtrl).ShadingControlType == MeetDaylIlumSetp && SurfWinShadingFlag(IWin) == WinShadingType::SwitchableGlazing && SurfWinGlareControlIsActive(IWin)) ISWFLG = 1; } @@ -6584,7 +6584,7 @@ namespace EnergyPlus::DaylightingManager { int IS = findWinShadingIndex(IWin); if (Surface(IWin).HasShadeControl) { if (SurfWinShadingFlag(IWin) == WinShadingType::SwitchableGlazing && SurfWinGlareControlIsActive(IWin) && - WindowShadingControl(ICtrl).ShadingControlType == WSCT_MeetDaylIlumSetp && !previously_shaded(loop)) { + WindowShadingControl(ICtrl).ShadingControlType == MeetDaylIlumSetp && !previously_shaded(loop)) { DILLSW(igroup) += state.dataDaylightingData->ZoneDaylight(ZoneNum).IllumFromWinAtRefPt(loop, IS, 1); previously_shaded(loop) = true; } else { @@ -6629,7 +6629,7 @@ namespace EnergyPlus::DaylightingManager { continue; } if ((SurfWinShadingFlag(IWin) != WinShadingType::SwitchableGlazing && !SurfWinGlareControlIsActive(IWin)) || - WindowShadingControl(ICtrl).ShadingControlType != WSCT_MeetDaylIlumSetp) { + WindowShadingControl(ICtrl).ShadingControlType != MeetDaylIlumSetp) { continueOuterLoop = true; continue; } @@ -6931,7 +6931,7 @@ namespace EnergyPlus::DaylightingManager { if (GlareOK) { if (SurfWinShadingFlag(IWin) == WinShadingType::SwitchableGlazing && - WindowShadingControl(ICtrl).ShadingControlType == WSCT_MeetDaylIlumSetp) { + WindowShadingControl(ICtrl).ShadingControlType == MeetDaylIlumSetp) { // Added TH 1/14/2010 // Only for switchable glazings with MeetDaylightIlluminanceSetpoint control // The glazing is in fully dark state, it might lighten a bit to provide more daylight @@ -9732,7 +9732,7 @@ namespace EnergyPlus::DaylightingManager { ICtrl = Surface(IWin).activeWindowShadingControl; if (Surface(IWin).HasShadeControl) { - if (WindowShadingControl(ICtrl).ShadingControlType == WSCT_MeetDaylIlumSetp && + if (WindowShadingControl(ICtrl).ShadingControlType == MeetDaylIlumSetp && SurfWinShadingFlag(IWin) == WinShadingType::SwitchableGlazing) { // switchable windows in partial or fully switched state, // get its intermediate VT calculated in DayltgInteriorIllum @@ -9766,7 +9766,7 @@ namespace EnergyPlus::DaylightingManager { ICtrl = Surface(IWin).activeWindowShadingControl; if (Surface(IWin).HasShadeControl) { - if (WindowShadingControl(ICtrl).ShadingControlType == WSCT_MeetDaylIlumSetp && + if (WindowShadingControl(ICtrl).ShadingControlType == MeetDaylIlumSetp && SurfWinShadingFlag(IWin) == WinShadingType::SwitchableGlazing) { // switchable windows in partial or fully switched state, // get its intermediate VT calculated in DayltgInteriorIllum diff --git a/src/EnergyPlus/HeatBalanceSurfaceManager.cc b/src/EnergyPlus/HeatBalanceSurfaceManager.cc index eb1af6a5db1..987c3df15de 100644 --- a/src/EnergyPlus/HeatBalanceSurfaceManager.cc +++ b/src/EnergyPlus/HeatBalanceSurfaceManager.cc @@ -1074,47 +1074,47 @@ namespace HeatBalanceSurfaceManager { } { auto const SELECT_CASE_var1(WindowShadingControl(curWSC).ShadingControlType); - if (SELECT_CASE_var1 == WSCT_AlwaysOn) { + if (SELECT_CASE_var1 == AlwaysOn) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "AlwaysOn"); - } else if (SELECT_CASE_var1 == WSCT_AlwaysOff) { + } else if (SELECT_CASE_var1 == AlwaysOff) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "AlwaysOff"); - } else if (SELECT_CASE_var1 == WSCT_OnIfScheduled) { + } else if (SELECT_CASE_var1 == OnIfScheduled) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OnIfScheduleAllows"); - } else if (SELECT_CASE_var1 == WSCT_HiSolar) { + } else if (SELECT_CASE_var1 == HiSolar) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OnIfHighSolarOnWindow"); - } else if (SELECT_CASE_var1 == WSCT_HiHorzSolar) { + } else if (SELECT_CASE_var1 == HiHorzSolar) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OnIfHighHorizontalSolar"); - } else if (SELECT_CASE_var1 == WSCT_HiOutAirTemp) { + } else if (SELECT_CASE_var1 == HiOutAirTemp) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OnIfHighOutdoorAirTemperature"); - } else if (SELECT_CASE_var1 == WSCT_HiZoneAirTemp) { + } else if (SELECT_CASE_var1 == HiZoneAirTemp) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OnIfHighZoneAirTemperature"); - } else if (SELECT_CASE_var1 == WSCT_HiZoneCooling) { + } else if (SELECT_CASE_var1 == HiZoneCooling) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OnIfHighZoneCooling"); - } else if (SELECT_CASE_var1 == WSCT_HiGlare) { + } else if (SELECT_CASE_var1 == HiGlare) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OnIfHighGlare"); - } else if (SELECT_CASE_var1 == WSCT_MeetDaylIlumSetp) { + } else if (SELECT_CASE_var1 == MeetDaylIlumSetp) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "MeetDaylightIlluminanceSetpoint"); - } else if (SELECT_CASE_var1 == WSCT_OnNightLoOutTemp_OffDay) { + } else if (SELECT_CASE_var1 == OnNightLoOutTemp_OffDay) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OnNightIfLowOutdoorTempAndOffDay"); - } else if (SELECT_CASE_var1 == WSCT_OnNightLoInTemp_OffDay) { + } else if (SELECT_CASE_var1 == OnNightLoInTemp_OffDay) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OnNightIfLowInsideTempAndOffDay"); - } else if (SELECT_CASE_var1 == WSCT_OnNightIfHeating_OffDay) { + } else if (SELECT_CASE_var1 == OnNightIfHeating_OffDay) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OnNightIfHeatingAndOffDay"); - } else if (SELECT_CASE_var1 == WSCT_OnNightLoOutTemp_OnDayCooling) { + } else if (SELECT_CASE_var1 == OnNightLoOutTemp_OnDayCooling) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OnNightIfLowOutdoorTempAndOnDayIfCooling"); - } else if (SELECT_CASE_var1 == WSCT_OnNightIfHeating_OnDayCooling) { + } else if (SELECT_CASE_var1 == OnNightIfHeating_OnDayCooling) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OnNightIfHeatingAndOnDayIfCooling"); - } else if (SELECT_CASE_var1 == WSCT_OffNight_OnDay_HiSolarWindow) { + } else if (SELECT_CASE_var1 == OffNight_OnDay_HiSolarWindow) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OffNightAndOnDayIfCoolingAndHighSolarOnWindow"); - } else if (SELECT_CASE_var1 == WSCT_OnNight_OnDay_HiSolarWindow) { + } else if (SELECT_CASE_var1 == OnNight_OnDay_HiSolarWindow) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OnNightAndOnDayIfCoolingAndHighSolarOnWindow"); - } else if (SELECT_CASE_var1 == WSCT_OnHiOutTemp_HiSolarWindow) { + } else if (SELECT_CASE_var1 == OnHiOutTemp_HiSolarWindow) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OnIfHighOutdoorAirTempAndHighSolarOnWindow"); - } else if (SELECT_CASE_var1 == WSCT_OnHiOutTemp_HiHorzSolar) { + } else if (SELECT_CASE_var1 == OnHiOutTemp_HiHorzSolar) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OnIfHighOutdoorAirTempAndHighHorizontalSolar"); - } else if (SELECT_CASE_var1 == WSCT_OnHiZoneTemp_HiSolarWindow) { + } else if (SELECT_CASE_var1 == OnHiZoneTemp_HiSolarWindow) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OnIfHighZoneAirTempAndHighSolarOnWindow"); - } else if (SELECT_CASE_var1 == WSCT_OnHiZoneTemp_HiHorzSolar) { + } else if (SELECT_CASE_var1 == OnHiZoneTemp_HiHorzSolar) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OnIfHighZoneAirTempAndHighHorizontalSolar"); } } @@ -2858,7 +2858,7 @@ namespace HeatBalanceSurfaceManager { } int const firstSurfWin = Zone(zoneNum).WindowSurfaceFirst; int const lastSurfWin = Zone(zoneNum).WindowSurfaceLast; - for (int SurfNum = firstSurfWin; SurfNum <= lastSurfWin; ++SurfNum) { + for (int SurfNum = firstSurfWin; SurfNum <= lastSurfWin; ++SurfNum) { if (Surface(SurfNum).ExtSolar || SurfWinOriginalClass(SurfNum) == SurfaceClass::TDD_Diffuser) { // Exclude special shading surfaces which required QRadSWOut calculations above int RoughIndexMovInsul = 0; // Roughness index of movable insulation diff --git a/src/EnergyPlus/SolarShading.cc b/src/EnergyPlus/SolarShading.cc index 2440b31bd6d..6dc3c9847e3 100644 --- a/src/EnergyPlus/SolarShading.cc +++ b/src/EnergyPlus/SolarShading.cc @@ -49,7 +49,7 @@ #include #include #include - +#include // ObjexxFCL Headers #include #include @@ -8649,6 +8649,7 @@ namespace SolarShading { using DataWindowEquivalentLayer::CFS; using General::POLYF; using ScheduleManager::GetCurrentScheduleValue; + using namespace std::chrono; static Real64 ThetaBig(0.0); // Larger of ThetaBlock1 and ThetaBlock2 //Autodesk Used uninitialized in some runs static Real64 ThetaSmall(0.0); // Smaller of ThetaBlock1 and ThetaBlock2 //Autodesk Used uninitialized in some runs @@ -8782,200 +8783,207 @@ namespace SolarShading { SurfWinGlareControlIsActive(ISurf) = false; SurfWinShadingFlag(ISurf) = WinShadingType::ShadeOff; // Initialize shading flag to off - auto const SELECT_CASE_var(WindowShadingControl(IShadingCtrl).ShadingControlType); - - if (SELECT_CASE_var == WSCT_AlwaysOn) { // 'ALWAYSON' - SurfWinShadingFlag(ISurf) = ShType; - - } else if (SELECT_CASE_var == WSCT_AlwaysOff) { // 'ALWAYSOFF' - SurfWinShadingFlag(ISurf) = WinShadingType::ShadeOff; - - } else if (SELECT_CASE_var == WSCT_OnIfScheduled) { // 'ONIFSCHEDULEALLOWS' - if (SchedAllowsControl) { + switch (WindowShadingControl(IShadingCtrl).ShadingControlType) { + case AlwaysOn: // 'ALWAYSON' SurfWinShadingFlag(ISurf) = ShType; - } + break; + case AlwaysOff: // 'ALWAYSOFF' + SurfWinShadingFlag(ISurf) = WinShadingType::ShadeOff; + break; + case OnIfScheduled: // 'ONIFSCHEDULEALLOWS' + if (SchedAllowsControl) SurfWinShadingFlag(ISurf) = ShType; + break; + case HiSolar: // 'ONIFHIGHSOLARONWINDOW' + // ! Direct plus diffuse solar intensity on window + if (state.dataEnvrn->SunIsUp) { + if (SolarOnWindow > SetPoint && SchedAllowsControl) { + SurfWinShadingFlag(ISurf) = ShType; + } else if (GlareControlIsActive) { + SurfWinGlareControlIsActive(ISurf) = true; + } + } + break; - } else if (SELECT_CASE_var == WSCT_HiSolar) { - // 'ONIFHIGHSOLARONWINDOW' ! Direct plus diffuse solar intensity on window - if (state.dataEnvrn->SunIsUp) { - if (SolarOnWindow > SetPoint && SchedAllowsControl) { + case HiHorzSolar: // 'ONIFHIGHHORIZONTALSOLAR' ! Direct plus diffuse exterior horizontal solar intensity + if (state.dataEnvrn->SunIsUp) { + if (HorizSolar > SetPoint && SchedAllowsControl) { + SurfWinShadingFlag(ISurf) = ShType; + } else if (GlareControlIsActive) { + SurfWinGlareControlIsActive(ISurf) = true; + } + } + break; + + case HiOutAirTemp: // 'OnIfHighOutdoorAirTemperature' + if (Surface(ISurf).OutDryBulbTemp > SetPoint && SchedAllowsControl) { SurfWinShadingFlag(ISurf) = ShType; } else if (GlareControlIsActive) { SurfWinGlareControlIsActive(ISurf) = true; } - } + break; - } else if (SELECT_CASE_var == WSCT_HiHorzSolar) { - // 'ONIFHIGHHORIZONTALSOLAR' ! Direct plus diffuse exterior horizontal solar intensity - if (state.dataEnvrn->SunIsUp) { - if (HorizSolar > SetPoint && SchedAllowsControl) { + case HiZoneAirTemp: // 'OnIfHighZoneAirTemperature' ! Previous time step zone air temperature + if (MAT(IZone) > SetPoint && SchedAllowsControl) { SurfWinShadingFlag(ISurf) = ShType; } else if (GlareControlIsActive) { SurfWinGlareControlIsActive(ISurf) = true; } - } + break; - } else if (SELECT_CASE_var == WSCT_HiOutAirTemp) { // 'OnIfHighOutdoorAirTemperature' - if (Surface(ISurf).OutDryBulbTemp > SetPoint && SchedAllowsControl) { - SurfWinShadingFlag(ISurf) = ShType; - } else if (GlareControlIsActive) { - SurfWinGlareControlIsActive(ISurf) = true; - } + case OnHiOutTemp_HiSolarWindow: // 'OnIfHighOutdoorAirTempAndHighSolarOnWindow' ! Outside air temp and solar on window + if (state.dataEnvrn->SunIsUp) { + if (Surface(ISurf).OutDryBulbTemp > SetPoint && SolarOnWindow > SetPoint2 && + SchedAllowsControl) { + SurfWinShadingFlag(ISurf) = ShType; + } else if (GlareControlIsActive) { + SurfWinGlareControlIsActive(ISurf) = true; + } + } + break; - } else if (SELECT_CASE_var == WSCT_HiZoneAirTemp) { - // 'OnIfHighZoneAirTemperature' ! Previous time step zone air temperature - if (MAT(IZone) > SetPoint && SchedAllowsControl) { - SurfWinShadingFlag(ISurf) = ShType; - } else if (GlareControlIsActive) { - SurfWinGlareControlIsActive(ISurf) = true; - } + case OnHiOutTemp_HiHorzSolar: // 'OnIfHighOutdoorAirTempAndHighHorizontalSolar' ! Outside air temp and horizontal solar + if (state.dataEnvrn->SunIsUp) { + if (Surface(ISurf).OutDryBulbTemp > SetPoint && HorizSolar > SetPoint2 && + SchedAllowsControl) { + SurfWinShadingFlag(ISurf) = ShType; + } else if (GlareControlIsActive) { + SurfWinGlareControlIsActive(ISurf) = true; + } + } + break; - } else if (SELECT_CASE_var == WSCT_OnHiOutTemp_HiSolarWindow) { - // 'OnIfHighOutdoorAirTempAndHighSolarOnWindow' ! Outside air temp and solar on window - if (state.dataEnvrn->SunIsUp) { - if (Surface(ISurf).OutDryBulbTemp > SetPoint && SolarOnWindow > SetPoint2 && - SchedAllowsControl) { - SurfWinShadingFlag(ISurf) = ShType; - } else if (GlareControlIsActive) { - SurfWinGlareControlIsActive(ISurf) = true; + case OnHiZoneTemp_HiSolarWindow: // 'ONIFHIGHZONEAIRTEMPANDHIGHSOLARONWINDOW' ! Zone air temp and solar on window + if (state.dataEnvrn->SunIsUp) { + if (MAT(IZone) > SetPoint && SolarOnWindow > SetPoint2 && SchedAllowsControl) { + SurfWinShadingFlag(ISurf) = ShType; + } else if (GlareControlIsActive) { + SurfWinGlareControlIsActive(ISurf) = true; + } } - } + break; - } else if (SELECT_CASE_var == WSCT_OnHiOutTemp_HiHorzSolar) { - // 'OnIfHighOutdoorAirTempAndHighHorizontalSolar' ! Outside air temp and horizontal solar - if (state.dataEnvrn->SunIsUp) { - if (Surface(ISurf).OutDryBulbTemp > SetPoint && HorizSolar > SetPoint2 && - SchedAllowsControl) { - SurfWinShadingFlag(ISurf) = ShType; - } else if (GlareControlIsActive) { - SurfWinGlareControlIsActive(ISurf) = true; + case OnHiZoneTemp_HiHorzSolar: // 'ONIFHIGHZONEAIRTEMPANDHIGHHORIZONTALSOLAR' ! Zone air temp and horizontal solar + if (state.dataEnvrn->SunIsUp) { + if (MAT(IZone) > SetPoint && HorizSolar > SetPoint2 && SchedAllowsControl) { + SurfWinShadingFlag(ISurf) = ShType; + } else if (GlareControlIsActive) { + SurfWinGlareControlIsActive(ISurf) = true; + } } - } + break; - } else if (SELECT_CASE_var == WSCT_OnHiZoneTemp_HiSolarWindow) { - // 'ONIFHIGHZONEAIRTEMPANDHIGHSOLARONWINDOW' ! Zone air temp and solar on window - if (state.dataEnvrn->SunIsUp) { - if (MAT(IZone) > SetPoint && SolarOnWindow > SetPoint2 && SchedAllowsControl) { + case HiZoneCooling: [[unlikely]] + // 'ONIFHIGHZONECOOLING' ! Previous time step zone sensible cooling rate [W] + // In the following, the check on BeginSimFlag is needed since SNLoadCoolRate (and SNLoadHeatRate, + // used in other CASEs) are not allocated at this point for the first time step of the simulation. + if (!state.dataGlobal->BeginSimFlag) { + if (SNLoadCoolRate(IZone) > SetPoint && SchedAllowsControl) { + SurfWinShadingFlag(ISurf) = ShType; + } else if (GlareControlIsActive) { + SurfWinGlareControlIsActive(ISurf) = true; + } + } + break; + + case HiGlare: [[unlikely]] + // 'ONIFHIGHGLARE' ! Daylight glare index at first reference point in the zone. + // This type of shading control is done in DayltgInteriorIllum. Glare control is not affected + // by control schedule. + if (state.dataEnvrn->SunIsUp) { SurfWinShadingFlag(ISurf) = ShType; - } else if (GlareControlIsActive) { SurfWinGlareControlIsActive(ISurf) = true; } - } + break; - } else if (SELECT_CASE_var == WSCT_OnHiZoneTemp_HiHorzSolar) { - // 'ONIFHIGHZONEAIRTEMPANDHIGHHORIZONTALSOLAR' ! Zone air temp and horizontal solar - if (state.dataEnvrn->SunIsUp) { - if (MAT(IZone) > SetPoint && HorizSolar > SetPoint2 && SchedAllowsControl) { + case MeetDaylIlumSetp: [[unlikely]] + // 'MEETDAYLIGHTILLUMINANCESETPOINT') ! Daylight illuminance test is done in DayltgInteriorIllum + // Only switchable glazing does daylight illuminance control + if (state.dataEnvrn->SunIsUp && SchedAllowsControl) { SurfWinShadingFlag(ISurf) = ShType; - } else if (GlareControlIsActive) { SurfWinGlareControlIsActive(ISurf) = true; } - } + break; - } else if (SELECT_CASE_var == WSCT_HiZoneCooling) { - // 'ONIFHIGHZONECOOLING' ! Previous time step zone sensible cooling rate [W] - // In the following, the check on BeginSimFlag is needed since SNLoadCoolRate (and SNLoadHeatRate, - // used in other CASEs) are not allocated at this point for the first time step of the simulation. - if (!state.dataGlobal->BeginSimFlag) { - if (SNLoadCoolRate(IZone) > SetPoint && SchedAllowsControl) { + case OnNightLoOutTemp_OffDay: [[unlikely]]// 'OnNightIfLowOutdoorTempAndOffDay' + if (!state.dataEnvrn->SunIsUp && Surface(ISurf).OutDryBulbTemp < SetPoint && SchedAllowsControl) { SurfWinShadingFlag(ISurf) = ShType; } else if (GlareControlIsActive) { SurfWinGlareControlIsActive(ISurf) = true; } - } - - } else if (SELECT_CASE_var == WSCT_HiGlare) { - // 'ONIFHIGHGLARE' ! Daylight glare index at first reference point in the zone. - // This type of shading control is done in DayltgInteriorIllum. Glare control is not affected - // by control schedule. - if (state.dataEnvrn->SunIsUp) { - SurfWinShadingFlag(ISurf) = ShType; - SurfWinGlareControlIsActive(ISurf) = true; - } - - - } else if (SELECT_CASE_var == WSCT_MeetDaylIlumSetp) { - // 'MEETDAYLIGHTILLUMINANCESETPOINT') ! Daylight illuminance test is done in DayltgInteriorIllum - // Only switchable glazing does daylight illuminance control - if (state.dataEnvrn->SunIsUp && SchedAllowsControl) { - SurfWinShadingFlag(ISurf) = ShType; - SurfWinGlareControlIsActive(ISurf) = true; - } - - } else if (SELECT_CASE_var == WSCT_OnNightLoOutTemp_OffDay) { // 'OnNightIfLowOutdoorTempAndOffDay' - if (!state.dataEnvrn->SunIsUp && Surface(ISurf).OutDryBulbTemp < SetPoint && SchedAllowsControl) { - SurfWinShadingFlag(ISurf) = ShType; - } else if (GlareControlIsActive) { - SurfWinGlareControlIsActive(ISurf) = true; - } - - } else if (SELECT_CASE_var == WSCT_OnNightLoInTemp_OffDay) { // 'OnNightIfLowInsideTempAndOffDay') - if (!state.dataEnvrn->SunIsUp && MAT(IZone) < SetPoint && SchedAllowsControl) { - SurfWinShadingFlag(ISurf) = ShType; - } else if (GlareControlIsActive) { - SurfWinGlareControlIsActive(ISurf) = true; - } + break; - } else if (SELECT_CASE_var == WSCT_OnNightIfHeating_OffDay) { // 'OnNightIfHeatingAndOffDay' - if (!state.dataGlobal->BeginSimFlag) { - if (!state.dataEnvrn->SunIsUp && SNLoadHeatRate(IZone) > SetPoint && SchedAllowsControl) { + case OnNightLoInTemp_OffDay: [[unlikely]]// 'OnNightIfLowInsideTempAndOffDay') + if (!state.dataEnvrn->SunIsUp && MAT(IZone) < SetPoint && SchedAllowsControl) { SurfWinShadingFlag(ISurf) = ShType; } else if (GlareControlIsActive) { SurfWinGlareControlIsActive(ISurf) = true; } - } + break; - } else if (SELECT_CASE_var == WSCT_OnNightLoOutTemp_OnDayCooling) { - // 'OnNightIfLowOutdoorTempAndOnDayIfCooling' - if (!state.dataGlobal->BeginSimFlag) { - if (!state.dataEnvrn->SunIsUp) { // Night - if (Surface(ISurf).OutDryBulbTemp < SetPoint && SchedAllowsControl) - SurfWinShadingFlag(ISurf) = ShType; - } else { // Day - if (SNLoadCoolRate(IZone) > 0.0 && SchedAllowsControl) { + case OnNightIfHeating_OffDay: [[unlikely]]// 'OnNightIfHeatingAndOffDay' + if (!state.dataGlobal->BeginSimFlag) { + if (!state.dataEnvrn->SunIsUp && SNLoadHeatRate(IZone) > SetPoint && SchedAllowsControl) { SurfWinShadingFlag(ISurf) = ShType; } else if (GlareControlIsActive) { SurfWinGlareControlIsActive(ISurf) = true; } } - } + break; - } else if (SELECT_CASE_var == - WSCT_OnNightIfHeating_OnDayCooling) { // 'OnNightIfHeatingAndOnDayIfCooling' - if (!state.dataGlobal->BeginSimFlag) { - if (!state.dataEnvrn->SunIsUp) { // Night - if (SNLoadHeatRate(IZone) > SetPoint && SchedAllowsControl) - SurfWinShadingFlag(ISurf) = ShType; - } else { // Day - if (SNLoadCoolRate(IZone) > 0.0 && SchedAllowsControl) { - SurfWinShadingFlag(ISurf) = ShType; - } else if (GlareControlIsActive) { - SurfWinGlareControlIsActive(ISurf) = true; + case OnNightLoOutTemp_OnDayCooling: [[unlikely]]// 'OnNightIfLowOutdoorTempAndOnDayIfCooling' + if (!state.dataGlobal->BeginSimFlag) { + if (!state.dataEnvrn->SunIsUp) { // Night + if (Surface(ISurf).OutDryBulbTemp < SetPoint && SchedAllowsControl) + SurfWinShadingFlag(ISurf) = ShType; + } else { // Day + if (SNLoadCoolRate(IZone) > 0.0 && SchedAllowsControl) { + SurfWinShadingFlag(ISurf) = ShType; + } else if (GlareControlIsActive) { + SurfWinGlareControlIsActive(ISurf) = true; + } } } - } + break; - } else if (SELECT_CASE_var == - WSCT_OffNight_OnDay_HiSolarWindow) { // 'OffNightAndOnDayIfCoolingAndHighSolarOnWindow' - if (!state.dataGlobal->BeginSimFlag) { - if (state.dataEnvrn->SunIsUp && SNLoadCoolRate(IZone) > 0.0 && SchedAllowsControl) { - if (SolarOnWindow > SetPoint) SurfWinShadingFlag(ISurf) = ShType; - } else if (GlareControlIsActive) { - SurfWinGlareControlIsActive(ISurf) = true; + case OnNightIfHeating_OnDayCooling: [[unlikely]]// 'OnNightIfHeatingAndOnDayIfCooling' + if (!state.dataGlobal->BeginSimFlag) { + if (!state.dataEnvrn->SunIsUp) { // Night + if (SNLoadHeatRate(IZone) > SetPoint && SchedAllowsControl) + SurfWinShadingFlag(ISurf) = ShType; + } else { // Day + if (SNLoadCoolRate(IZone) > 0.0 && SchedAllowsControl) { + SurfWinShadingFlag(ISurf) = ShType; + } else if (GlareControlIsActive) { + SurfWinGlareControlIsActive(ISurf) = true; + } + } } - } + break; - } else if (SELECT_CASE_var == - WSCT_OnNight_OnDay_HiSolarWindow) { // 'OnNightAndOnDayIfCoolingAndHighSolarOnWindow' - if (!state.dataGlobal->BeginSimFlag) { - if (state.dataEnvrn->SunIsUp && SNLoadCoolRate(IZone) > 0.0 && SchedAllowsControl) { - if (SolarOnWindow > SetPoint) SurfWinShadingFlag(ISurf) = ShType; - } else if (!state.dataEnvrn->SunIsUp && SchedAllowsControl) { - SurfWinShadingFlag(ISurf) = ShType; - } else if (GlareControlIsActive) { - SurfWinGlareControlIsActive(ISurf) = true; + case OffNight_OnDay_HiSolarWindow: [[unlikely]]// 'OffNightAndOnDayIfCoolingAndHighSolarOnWindow' + if (!state.dataGlobal->BeginSimFlag) { + if (state.dataEnvrn->SunIsUp && SNLoadCoolRate(IZone) > 0.0 && SchedAllowsControl) { + if (SolarOnWindow > SetPoint) SurfWinShadingFlag(ISurf) = ShType; + } else if (GlareControlIsActive) { + SurfWinGlareControlIsActive(ISurf) = true; + } } - } + break; + + case OnNight_OnDay_HiSolarWindow: [[unlikely]]// 'OnNightAndOnDayIfCoolingAndHighSolarOnWindow' + if (!state.dataGlobal->BeginSimFlag) { + if (state.dataEnvrn->SunIsUp && SNLoadCoolRate(IZone) > 0.0 && SchedAllowsControl) { + if (SolarOnWindow > SetPoint) SurfWinShadingFlag(ISurf) = ShType; + } else if (!state.dataEnvrn->SunIsUp && SchedAllowsControl) { + SurfWinShadingFlag(ISurf) = ShType; + } else if (GlareControlIsActive) { + SurfWinGlareControlIsActive(ISurf) = true; + } + } + break; + default: [[unlikely]] + std::cout << "Invalid Selection\n"; + break; } // Set switching factor to fully switched if ShadingFlag = 2 diff --git a/src/EnergyPlus/SurfaceGeometry.cc b/src/EnergyPlus/SurfaceGeometry.cc index 3fa22a22893..467d7e6c28a 100644 --- a/src/EnergyPlus/SurfaceGeometry.cc +++ b/src/EnergyPlus/SurfaceGeometry.cc @@ -8203,40 +8203,40 @@ namespace SurfaceGeometry { "ONIFHIGHZONEAIRTEMPANDHIGHSOLARONWINDOW", "ONIFHIGHZONEAIRTEMPANDHIGHHORIZONTALSOLAR"}); - static Array1D_int const ValidWindowShadingControlTypes( + static Array1D const ValidWindowShadingControlTypes( NumValidWindowShadingControlTypes, - {WSCT_AlwaysOn, - WSCT_AlwaysOff, - WSCT_OnIfScheduled, - WSCT_HiSolar, - WSCT_HiHorzSolar, - WSCT_HiOutAirTemp, - WSCT_HiZoneAirTemp, - WSCT_HiZoneCooling, - WSCT_HiGlare, - WSCT_MeetDaylIlumSetp, - WSCT_OnNightLoOutTemp_OffDay, - WSCT_OnNightLoInTemp_OffDay, - WSCT_OnNightIfHeating_OffDay, - WSCT_OnNightLoOutTemp_OnDayCooling, - WSCT_OnNightIfHeating_OnDayCooling, - WSCT_OffNight_OnDay_HiSolarWindow, - WSCT_OnNight_OnDay_HiSolarWindow, - WSCT_OnHiOutTemp_HiSolarWindow, - WSCT_OnHiOutTemp_HiHorzSolar, - WSCT_OnHiZoneTemp_HiSolarWindow, - WSCT_OnHiZoneTemp_HiHorzSolar}); // 'ALWAYSON ', & | 'ALWAYSOFF ', & - // | 'ONIFSCHEDULEALLOWS ', & | 'ONIFHIGHSOLARONWINDOW ', - // & | 'ONIFHIGHHORIZONTALSOLAR ', & | 'ONIFHIGHOUTDOORAIRTEMPERATURE - // ', & | 'ONIFHIGHZONEAIRTEMPERATURE ', & | 'ONIFHIGHZONECOOLING - // ', & | 'ONIFHIGHGLARE ', & | 'MEETDAYLIGHTILLUMINANCESETPOINT - // ', & | 'ONNIGHTIFLOWOUTDOORTEMPANDOFFDAY ', & | 'ONNIGHTIFLOWINSIDETEMPANDOFFDAY - // ', & | 'ONNIGHTIFHEATINGANDOFFDAY ', & | - // 'ONNIGHTIFLOWOUTDOORTEMPANDONDAYIFCOOLING ', & | 'ONNIGHTIFHEATINGANDONDAYIFCOOLING - // ', & | 'OFFNIGHTANDONDAYIFCOOLINGANDHIGHSOLARONWINDOW ', & | - // 'ONNIGHTANDONDAYIFCOOLINGANDHIGHSOLARONWINDOW ', & | 'ONIFHIGHOUTDOORAIRTEMPANDHIGHSOLARONWINDOW ', - // & | 'ONIFHIGHOUTDOORAIRTEMPANDHIGHHORIZONTALSOLAR', & | 'ONIFHIGHZONEAIRTEMPANDHIGHSOLARONWINDOW - // ', & | 'ONIFHIGHZONEAIRTEMPANDHIGHHORIZONTALSOLAR '/) + {AlwaysOn, + AlwaysOff, + OnIfScheduled, + HiSolar, + HiHorzSolar, + HiOutAirTemp, + HiZoneAirTemp, + HiZoneCooling, + HiGlare, + MeetDaylIlumSetp, + OnNightLoOutTemp_OffDay, + OnNightLoInTemp_OffDay, + OnNightIfHeating_OffDay, + OnNightLoOutTemp_OnDayCooling, + OnNightIfHeating_OnDayCooling, + OffNight_OnDay_HiSolarWindow, + OnNight_OnDay_HiSolarWindow, + OnHiOutTemp_HiSolarWindow, + OnHiOutTemp_HiHorzSolar, + OnHiZoneTemp_HiSolarWindow, + OnHiZoneTemp_HiHorzSolar}); // 'ALWAYSON ', & | 'ALWAYSOFF ', & + // | 'ONIFSCHEDULEALLOWS ', & | 'ONIFHIGHSOLARONWINDOW ', + // & | 'ONIFHIGHHORIZONTALSOLAR ', & | 'ONIFHIGHOUTDOORAIRTEMPERATURE + // ', & | 'ONIFHIGHZONEAIRTEMPERATURE ', & | 'ONIFHIGHZONECOOLING + // ', & | 'ONIFHIGHGLARE ', & | 'MEETDAYLIGHTILLUMINANCESETPOINT + // ', & | 'ONNIGHTIFLOWOUTDOORTEMPANDOFFDAY ', & | 'ONNIGHTIFLOWINSIDETEMPANDOFFDAY + // ', & | 'ONNIGHTIFHEATINGANDOFFDAY ', & | + // 'ONNIGHTIFLOWOUTDOORTEMPANDONDAYIFCOOLING ', & | 'ONNIGHTIFHEATINGANDONDAYIFCOOLING + // ', & | 'OFFNIGHTANDONDAYIFCOOLINGANDHIGHSOLARONWINDOW ', & | + // 'ONNIGHTANDONDAYIFCOOLINGANDHIGHSOLARONWINDOW ', & | 'ONIFHIGHOUTDOORAIRTEMPANDHIGHSOLARONWINDOW ', + // & | 'ONIFHIGHOUTDOORAIRTEMPANDHIGHHORIZONTALSOLAR', & | 'ONIFHIGHZONEAIRTEMPANDHIGHSOLARONWINDOW + // ', & | 'ONIFHIGHZONEAIRTEMPANDHIGHHORIZONTALSOLAR '/) // SUBROUTINE LOCAL VARIABLE DECLARATIONS: @@ -8451,7 +8451,7 @@ namespace SurfaceGeometry { cAlphaArgs(8) + "\"."); } - if ((WindowShadingControl(ControlNum).ShadingControlType == WSCT_OnIfScheduled) && + if ((WindowShadingControl(ControlNum).ShadingControlType == OnIfScheduled) && (!WindowShadingControl(ControlNum).ShadingControlIsScheduled)) { // CR 7709 BG ErrorsFound = true; ShowSevereError(state, cCurrentModuleObject + " = \"" + WindowShadingControl(ControlNum).Name + "\" invalid, " + cAlphaFieldNames(7) + diff --git a/src/EnergyPlus/WindowComplexManager.cc b/src/EnergyPlus/WindowComplexManager.cc index 0666f2291ce..0bd6f8b526b 100644 --- a/src/EnergyPlus/WindowComplexManager.cc +++ b/src/EnergyPlus/WindowComplexManager.cc @@ -3417,7 +3417,7 @@ namespace WindowComplexManager { SurfWinHeatTransfer(SurfNum) -= QS(Surface(SurfNum).SolarEnclIndex) * Surface(SurfNum).Area * TransDiff; SurfWinLossSWZoneToOutWinRep(SurfNum) = QS(Surface(SurfNum).SolarEnclIndex) * Surface(SurfNum).Area * TransDiff; - if (IS_INT_SHADED(ShadeFlag)) { + if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::ExtShade) { SurfWinShadingAbsorbedSolar(SurfNum) = (SurfWinExtBeamAbsByShade(SurfNum) + SurfWinExtDiffAbsByShade(SurfNum)) * (Surface(SurfNum).Area + SurfWinDividerArea(SurfNum)); SurfWinShadingAbsorbedSolarEnergy(SurfNum) = SurfWinShadingAbsorbedSolar(SurfNum) * state.dataGlobal->TimeStepZoneSec; diff --git a/src/EnergyPlus/WindowManager.cc b/src/EnergyPlus/WindowManager.cc index fbbddb68e17..b791e67a517 100644 --- a/src/EnergyPlus/WindowManager.cc +++ b/src/EnergyPlus/WindowManager.cc @@ -2415,7 +2415,7 @@ namespace WindowManager { // Interior or exterior blind, shade or screen is on. // Fill gap between blind/shade and adjacent glass with air properties. ++IGap; - if (IS_SHADE_ON(ShadeFlag)) { // Interior or exterior shade + if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::ExtShade || ShadeFlag == WinShadingType::ExtScreen) { // Interior or exterior shade state.dataWindowManager->gap(IGap) = state.dataMaterial->Material(ShadeLayPtr).WinShadeToGlassDist; } else { // Interior or exterior blind state.dataWindowManager->gap(IGap) = Blind(SurfWinBlindNumber(SurfNum)).BlindToGlassDist; @@ -2983,7 +2983,7 @@ namespace WindowManager { (Surface(SurfNum).IntConvCoeff == -2)) { // coef model is "detailed" and not prescribed by user // need to find inside face index, varies with shade/blind etc. - if (IS_EXT_SHADED(ShadeFlag)) { + if (IS_INT_SHADED(ShadeFlag)) { InsideFaceIndex = state.dataWindowManager->nglfacep; } else { InsideFaceIndex = state.dataWindowManager->nglface; diff --git a/src/EnergyPlus/api/EnergyPlusPgm.cc b/src/EnergyPlus/api/EnergyPlusPgm.cc index 4c3425c7e01..fdcaa508e7d 100644 --- a/src/EnergyPlus/api/EnergyPlusPgm.cc +++ b/src/EnergyPlus/api/EnergyPlusPgm.cc @@ -393,7 +393,6 @@ int RunEnergyPlus(EnergyPlus::EnergyPlusData &state, std::string const & filepat // METHODOLOGY EMPLOYED: // The method used in EnergyPlus is to simplify the main program as much // as possible and contain all "simulation" code in other modules and files. - int status = initializeEnergyPlus(state, filepath); if (status || state.dataGlobal->outputEpJSONConversionOnly) return status; try { diff --git a/tst/EnergyPlus/unit/SurfaceGeometry.unit.cc b/tst/EnergyPlus/unit/SurfaceGeometry.unit.cc index 1339623ce6a..17f7983cbf2 100644 --- a/tst/EnergyPlus/unit/SurfaceGeometry.unit.cc +++ b/tst/EnergyPlus/unit/SurfaceGeometry.unit.cc @@ -3476,7 +3476,7 @@ TEST_F(EnergyPlusFixture, SurfaceGeometry_isWindowShadingControlSimilar_Test) WindowShadingControl(1).SequenceNumber = 3; WindowShadingControl(1).ShadingType = WinShadingType::ExtShade; WindowShadingControl(1).ShadingDevice = 17; - WindowShadingControl(1).ShadingControlType = WSCT_OnIfScheduled; + WindowShadingControl(1).ShadingControlType = OnIfScheduled; WindowShadingControl(1).Schedule = 83; WindowShadingControl(1).SetPoint = 200; WindowShadingControl(1).SetPoint2 = 170; @@ -3550,7 +3550,7 @@ TEST_F(EnergyPlusFixture, SurfaceGeometry_isWindowShadingControlSimilar_Test) EXPECT_FALSE(isWindowShadingControlSimilar(1, 2)); WindowShadingControl(2) = WindowShadingControl(1); - WindowShadingControl(2).ShadingControlType = WSCT_OffNight_OnDay_HiSolarWindow; + WindowShadingControl(2).ShadingControlType = OffNight_OnDay_HiSolarWindow; EXPECT_FALSE(isWindowShadingControlSimilar(1, 2)); WindowShadingControl(2) = WindowShadingControl(1); @@ -3603,7 +3603,7 @@ TEST_F(EnergyPlusFixture, SurfaceGeometry_CheckWindowShadingControlSimilarForWin WindowShadingControl(1).SequenceNumber = 3; WindowShadingControl(1).ShadingType = WinShadingType::ExtShade; WindowShadingControl(1).ShadingDevice = 17; - WindowShadingControl(1).ShadingControlType = WSCT_OnIfScheduled; + WindowShadingControl(1).ShadingControlType = OnIfScheduled; WindowShadingControl(1).Schedule = 83; WindowShadingControl(1).SetPoint = 200; WindowShadingControl(1).SetPoint2 = 170; From d58aed0994d7fc7dcf0b7eda4b473418b21c3ff5 Mon Sep 17 00:00:00 2001 From: xuanluo113 Date: Mon, 25 Jan 2021 23:20:53 -0800 Subject: [PATCH 25/76] remove attributes --- src/EnergyPlus/DataSurfaces.hh | 4 +- src/EnergyPlus/DaylightingManager.cc | 29 +++++----- src/EnergyPlus/HeatBalanceIntRadExchange.cc | 2 +- src/EnergyPlus/HeatBalanceSurfaceManager.cc | 52 ++++++++--------- src/EnergyPlus/SolarShading.cc | 63 +++++++++------------ src/EnergyPlus/SurfaceGeometry.cc | 44 +++++++------- src/EnergyPlus/WindowManager.cc | 9 ++- src/EnergyPlus/api/EnergyPlusPgm.cc | 1 + tst/EnergyPlus/unit/SurfaceGeometry.unit.cc | 6 +- 9 files changed, 98 insertions(+), 112 deletions(-) diff --git a/src/EnergyPlus/DataSurfaces.hh b/src/EnergyPlus/DataSurfaces.hh index 2a96e6983c6..774013ee033 100644 --- a/src/EnergyPlus/DataSurfaces.hh +++ b/src/EnergyPlus/DataSurfaces.hh @@ -147,7 +147,7 @@ namespace DataSurfaces { ShadeOff = 10 }; - enum WindowShadingControlType { + enum class WindowShadingControlType : int{ UnControlled = 0, AlwaysOn = 1, AlwaysOff = 2, @@ -1191,7 +1191,7 @@ namespace DataSurfaces { // Default Constructor WindowShadingControlData() - : ZoneIndex(0), SequenceNumber(0), ShadingType(WinShadingType::NoShade), getInputShadedConstruction(0), ShadingDevice(0), ShadingControlType(UnControlled), + : ZoneIndex(0), SequenceNumber(0), ShadingType(WinShadingType::NoShade), getInputShadedConstruction(0), ShadingDevice(0), ShadingControlType(WindowShadingControlType::UnControlled), Schedule(0), SetPoint(0.0), SetPoint2(0.0), ShadingControlIsScheduled(false), GlareControlIsActive(false), SlatAngleSchedule(0), SlatAngleControlForBlinds(0), DaylightControlIndex(0), MultiSurfaceCtrlIsGroup(false), FenestrationCount(0) { diff --git a/src/EnergyPlus/DaylightingManager.cc b/src/EnergyPlus/DaylightingManager.cc index b1828549ee8..5873bf7f284 100644 --- a/src/EnergyPlus/DaylightingManager.cc +++ b/src/EnergyPlus/DaylightingManager.cc @@ -4357,7 +4357,7 @@ namespace EnergyPlus::DaylightingManager { } } - if (WindowShadingControl(Surface(SurfNum).activeWindowShadingControl).ShadingControlType == MeetDaylIlumSetp) { + if (WindowShadingControl(Surface(SurfNum).activeWindowShadingControl).ShadingControlType == WindowShadingControlType::MeetDaylIlumSetp) { // Error if window has ShadingControlType = MeetDaylightingIlluminanceSetpoint & // but is not in a Daylighting:Detailed zone if (thisSurfEnclosure.TotalEnclosureDaylRefPoints == 0) { @@ -6281,8 +6281,8 @@ namespace EnergyPlus::DaylightingManager { } } - bool ShadedOrDiffuseGlassWin = (SurfWinWindowModelType(IWin) != WindowBSDFModel) && - (IS_SHADED(SurfWinShadingFlag(IWin)) || SurfWinSolarDiffusing(IWin)); + bool ShadedOrDiffusingGlassWin = (SurfWinWindowModelType(IWin) != WindowBSDFModel) && + (IS_SHADED(SurfWinShadingFlag(IWin)) || SurfWinSolarDiffusing(IWin)); // Loop over reference points for (int IL = 1; IL <= NREFPT; ++IL) { @@ -6318,7 +6318,7 @@ namespace EnergyPlus::DaylightingManager { state.dataGlobal->WeightPreviousHour * (state.dataDaylightingData->ZoneDaylight(ZoneNum).DaylSourceFacSun(state.dataGlobal->PreviousHour, 1, IL, loop) + state.dataDaylightingData->ZoneDaylight(ZoneNum).DaylSourceFacSunDisk(state.dataGlobal->PreviousHour, 1, IL, loop))); - if (ShadedOrDiffuseGlassWin) { + if (ShadedOrDiffusingGlassWin) { // ===Shaded window or window with diffusing glass=== if (!SurfWinMovableSlats(IWin)) { @@ -6489,7 +6489,7 @@ namespace EnergyPlus::DaylightingManager { HorIllSkyFac = state.dataEnvrn->HISKF / ((1 - SkyWeight) * HorIllSky(ISky2) + SkyWeight * HorIllSky(ISky1)); for (int IS = 1; IS <= 2; ++IS) { - if (IS == 2 && !ShadedOrDiffuseGlassWin) break; + if (IS == 2 && !ShadedOrDiffusingGlassWin) break; state.dataDaylightingData->ZoneDaylight(ZoneNum).IllumFromWinAtRefPt(loop, IS, IL) = DFSUHR(IS) * state.dataEnvrn->HISUNF + @@ -6529,7 +6529,7 @@ namespace EnergyPlus::DaylightingManager { int IWin = state.dataDaylightingData->ZoneDaylight(ZoneNum).DayltgExtWinSurfNums(loop); ICtrl = Surface(IWin).activeWindowShadingControl; if (Surface(IWin).HasShadeControl && ISWFLG == 0) { - if (WindowShadingControl(ICtrl).ShadingControlType == MeetDaylIlumSetp && + if (WindowShadingControl(ICtrl).ShadingControlType == WindowShadingControlType::MeetDaylIlumSetp && SurfWinShadingFlag(IWin) == WinShadingType::SwitchableGlazing && SurfWinGlareControlIsActive(IWin)) ISWFLG = 1; } @@ -6584,7 +6584,7 @@ namespace EnergyPlus::DaylightingManager { int IS = findWinShadingIndex(IWin); if (Surface(IWin).HasShadeControl) { if (SurfWinShadingFlag(IWin) == WinShadingType::SwitchableGlazing && SurfWinGlareControlIsActive(IWin) && - WindowShadingControl(ICtrl).ShadingControlType == MeetDaylIlumSetp && !previously_shaded(loop)) { + WindowShadingControl(ICtrl).ShadingControlType == WindowShadingControlType::MeetDaylIlumSetp && !previously_shaded(loop)) { DILLSW(igroup) += state.dataDaylightingData->ZoneDaylight(ZoneNum).IllumFromWinAtRefPt(loop, IS, 1); previously_shaded(loop) = true; } else { @@ -6629,7 +6629,7 @@ namespace EnergyPlus::DaylightingManager { continue; } if ((SurfWinShadingFlag(IWin) != WinShadingType::SwitchableGlazing && !SurfWinGlareControlIsActive(IWin)) || - WindowShadingControl(ICtrl).ShadingControlType != MeetDaylIlumSetp) { + WindowShadingControl(ICtrl).ShadingControlType != WindowShadingControlType::MeetDaylIlumSetp) { continueOuterLoop = true; continue; } @@ -6856,10 +6856,9 @@ namespace EnergyPlus::DaylightingManager { for (const auto IWin : listOfExtWin) { ++count; - // need to map back to the original order of the "loop" to not change all the other data structures loop = state.dataDaylightingData->ZoneDaylight(ZoneNum).MapShdOrdToLoopNum(count); - if (SurfWinShadingFlag(IWin) != WinShadingType::SwitchableGlazing) continue; + if (!SurfWinGlareControlIsActive(IWin) && SurfWinShadingFlag(IWin) != WinShadingType::SwitchableGlazing) continue; ICtrl = Surface(IWin).activeWindowShadingControl; if (!Surface(IWin).HasShadeControl) continue; @@ -6931,7 +6930,7 @@ namespace EnergyPlus::DaylightingManager { if (GlareOK) { if (SurfWinShadingFlag(IWin) == WinShadingType::SwitchableGlazing && - WindowShadingControl(ICtrl).ShadingControlType == MeetDaylIlumSetp) { + WindowShadingControl(ICtrl).ShadingControlType == WindowShadingControlType::MeetDaylIlumSetp) { // Added TH 1/14/2010 // Only for switchable glazings with MeetDaylightIlluminanceSetpoint control // The glazing is in fully dark state, it might lighten a bit to provide more daylight @@ -6992,7 +6991,7 @@ namespace EnergyPlus::DaylightingManager { // Final re-calculation if needed if (!GlareOK) { // Glare too high, use previous state and re-calc - for (int IL = 1; IL <= NREFPT; ++IL) { + for (int IL = 1; IL <= NREFPT; ++IL) { RDAYIL(IL, igroup) = state.dataDaylightingManager->DaylIllum(IL) + (WDAYIL(1, IL, igroup) - WDAYIL(2, IL, igroup)) * (1.0 - tmpSWFactor); RBACLU(IL, igroup) = state.dataDaylightingData->ZoneDaylight(ZoneNum).BacLum(IL) + (WBACLU(1, IL, igroup) - WBACLU(2, IL, igroup)) * (1.0 - tmpSWFactor); @@ -7010,7 +7009,7 @@ namespace EnergyPlus::DaylightingManager { } // Update final results - for (int IL = 1; IL <= NREFPT; ++IL) { + for (int IL = 1; IL <= NREFPT; ++IL) { state.dataDaylightingData->ZoneDaylight(ZoneNum).BacLum(IL) = RBACLU(IL, igroup); GLRNDX(IL) = GLRNEW(IL); state.dataDaylightingManager->DaylIllum(IL) = RDAYIL(IL, igroup); @@ -9732,7 +9731,7 @@ namespace EnergyPlus::DaylightingManager { ICtrl = Surface(IWin).activeWindowShadingControl; if (Surface(IWin).HasShadeControl) { - if (WindowShadingControl(ICtrl).ShadingControlType == MeetDaylIlumSetp && + if (WindowShadingControl(ICtrl).ShadingControlType == WindowShadingControlType::MeetDaylIlumSetp && SurfWinShadingFlag(IWin) == WinShadingType::SwitchableGlazing) { // switchable windows in partial or fully switched state, // get its intermediate VT calculated in DayltgInteriorIllum @@ -9766,7 +9765,7 @@ namespace EnergyPlus::DaylightingManager { ICtrl = Surface(IWin).activeWindowShadingControl; if (Surface(IWin).HasShadeControl) { - if (WindowShadingControl(ICtrl).ShadingControlType == MeetDaylIlumSetp && + if (WindowShadingControl(ICtrl).ShadingControlType == WindowShadingControlType::MeetDaylIlumSetp && SurfWinShadingFlag(IWin) == WinShadingType::SwitchableGlazing) { // switchable windows in partial or fully switched state, // get its intermediate VT calculated in DayltgInteriorIllum diff --git a/src/EnergyPlus/HeatBalanceIntRadExchange.cc b/src/EnergyPlus/HeatBalanceIntRadExchange.cc index 09c5ea7db10..89116f222a0 100644 --- a/src/EnergyPlus/HeatBalanceIntRadExchange.cc +++ b/src/EnergyPlus/HeatBalanceIntRadExchange.cc @@ -335,7 +335,7 @@ namespace HeatBalanceIntRadExchange { SurfaceTempRad[ZoneSurfNum] = SurfWinEffInsSurfTemp(SurfNum); SurfaceEmiss[ZoneSurfNum] = construct.InsideAbsorpThermal; } else if (construct.TypeIsWindow && SurfWinOriginalClass(SurfNum) != SurfaceClass::TDD_Diffuser) { - if (SurfIterations == 0 && (SurfWinShadingFlag(SurfNum) == WinShadingType::NoShade || SurfWinShadingFlag(SurfNum) == WinShadingType::ShadeOff)) { + if (SurfIterations == 0 && !IS_SHADED(SurfWinShadingFlag(SurfNum))) { // If the window is bare this TS and it is the first time through we use the previous TS glass // temperature whether or not the window was shaded in the previous TS. If the window was shaded // the previous time step this temperature is a better starting value than the shade temperature. diff --git a/src/EnergyPlus/HeatBalanceSurfaceManager.cc b/src/EnergyPlus/HeatBalanceSurfaceManager.cc index 987c3df15de..8d55d74941a 100644 --- a/src/EnergyPlus/HeatBalanceSurfaceManager.cc +++ b/src/EnergyPlus/HeatBalanceSurfaceManager.cc @@ -1074,47 +1074,47 @@ namespace HeatBalanceSurfaceManager { } { auto const SELECT_CASE_var1(WindowShadingControl(curWSC).ShadingControlType); - if (SELECT_CASE_var1 == AlwaysOn) { + if (SELECT_CASE_var1 == WindowShadingControlType::AlwaysOn) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "AlwaysOn"); - } else if (SELECT_CASE_var1 == AlwaysOff) { + } else if (SELECT_CASE_var1 == WindowShadingControlType::AlwaysOff) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "AlwaysOff"); - } else if (SELECT_CASE_var1 == OnIfScheduled) { + } else if (SELECT_CASE_var1 == WindowShadingControlType::OnIfScheduled) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OnIfScheduleAllows"); - } else if (SELECT_CASE_var1 == HiSolar) { + } else if (SELECT_CASE_var1 == WindowShadingControlType::HiSolar) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OnIfHighSolarOnWindow"); - } else if (SELECT_CASE_var1 == HiHorzSolar) { + } else if (SELECT_CASE_var1 == WindowShadingControlType::HiHorzSolar) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OnIfHighHorizontalSolar"); - } else if (SELECT_CASE_var1 == HiOutAirTemp) { + } else if (SELECT_CASE_var1 == WindowShadingControlType::HiOutAirTemp) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OnIfHighOutdoorAirTemperature"); - } else if (SELECT_CASE_var1 == HiZoneAirTemp) { + } else if (SELECT_CASE_var1 == WindowShadingControlType::HiZoneAirTemp) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OnIfHighZoneAirTemperature"); - } else if (SELECT_CASE_var1 == HiZoneCooling) { + } else if (SELECT_CASE_var1 == WindowShadingControlType::HiZoneCooling) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OnIfHighZoneCooling"); - } else if (SELECT_CASE_var1 == HiGlare) { + } else if (SELECT_CASE_var1 == WindowShadingControlType::HiGlare) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OnIfHighGlare"); - } else if (SELECT_CASE_var1 == MeetDaylIlumSetp) { + } else if (SELECT_CASE_var1 == WindowShadingControlType::MeetDaylIlumSetp) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "MeetDaylightIlluminanceSetpoint"); - } else if (SELECT_CASE_var1 == OnNightLoOutTemp_OffDay) { + } else if (SELECT_CASE_var1 == WindowShadingControlType::OnNightLoOutTemp_OffDay) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OnNightIfLowOutdoorTempAndOffDay"); - } else if (SELECT_CASE_var1 == OnNightLoInTemp_OffDay) { + } else if (SELECT_CASE_var1 == WindowShadingControlType::OnNightLoInTemp_OffDay) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OnNightIfLowInsideTempAndOffDay"); - } else if (SELECT_CASE_var1 == OnNightIfHeating_OffDay) { + } else if (SELECT_CASE_var1 == WindowShadingControlType::OnNightIfHeating_OffDay) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OnNightIfHeatingAndOffDay"); - } else if (SELECT_CASE_var1 == OnNightLoOutTemp_OnDayCooling) { + } else if (SELECT_CASE_var1 == WindowShadingControlType::OnNightLoOutTemp_OnDayCooling) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OnNightIfLowOutdoorTempAndOnDayIfCooling"); - } else if (SELECT_CASE_var1 == OnNightIfHeating_OnDayCooling) { + } else if (SELECT_CASE_var1 == WindowShadingControlType::OnNightIfHeating_OnDayCooling) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OnNightIfHeatingAndOnDayIfCooling"); - } else if (SELECT_CASE_var1 == OffNight_OnDay_HiSolarWindow) { + } else if (SELECT_CASE_var1 == WindowShadingControlType::OffNight_OnDay_HiSolarWindow) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OffNightAndOnDayIfCoolingAndHighSolarOnWindow"); - } else if (SELECT_CASE_var1 == OnNight_OnDay_HiSolarWindow) { + } else if (SELECT_CASE_var1 == WindowShadingControlType::OnNight_OnDay_HiSolarWindow) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OnNightAndOnDayIfCoolingAndHighSolarOnWindow"); - } else if (SELECT_CASE_var1 == OnHiOutTemp_HiSolarWindow) { + } else if (SELECT_CASE_var1 == WindowShadingControlType::OnHiOutTemp_HiSolarWindow) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OnIfHighOutdoorAirTempAndHighSolarOnWindow"); - } else if (SELECT_CASE_var1 == OnHiOutTemp_HiHorzSolar) { + } else if (SELECT_CASE_var1 == WindowShadingControlType::OnHiOutTemp_HiHorzSolar) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OnIfHighOutdoorAirTempAndHighHorizontalSolar"); - } else if (SELECT_CASE_var1 == OnHiZoneTemp_HiSolarWindow) { + } else if (SELECT_CASE_var1 == WindowShadingControlType::OnHiZoneTemp_HiSolarWindow) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OnIfHighZoneAirTempAndHighSolarOnWindow"); - } else if (SELECT_CASE_var1 == OnHiZoneTemp_HiHorzSolar) { + } else if (SELECT_CASE_var1 == WindowShadingControlType::OnHiZoneTemp_HiHorzSolar) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OnIfHighZoneAirTempAndHighHorizontalSolar"); } } @@ -2858,7 +2858,7 @@ namespace HeatBalanceSurfaceManager { } int const firstSurfWin = Zone(zoneNum).WindowSurfaceFirst; int const lastSurfWin = Zone(zoneNum).WindowSurfaceLast; - for (int SurfNum = firstSurfWin; SurfNum <= lastSurfWin; ++SurfNum) { + for (int SurfNum = firstSurfWin; SurfNum <= lastSurfWin; ++SurfNum) { if (Surface(SurfNum).ExtSolar || SurfWinOriginalClass(SurfNum) == SurfaceClass::TDD_Diffuser) { // Exclude special shading surfaces which required QRadSWOut calculations above int RoughIndexMovInsul = 0; // Roughness index of movable insulation @@ -2867,6 +2867,7 @@ namespace HeatBalanceSurfaceManager { if (Surface(SurfNum).MaterialMovInsulExt > 0) EvalOutsideMovableInsulation(state, SurfNum, HMovInsul, RoughIndexMovInsul, AbsExt); + int ConstrNum = Surface(SurfNum).Construction; if (SurfWinStormWinFlag(SurfNum) == 1) ConstrNum = Surface(SurfNum).StormWinConstruction; if (RoughIndexMovInsul <= 0) { // No movable insulation present @@ -2939,12 +2940,9 @@ namespace HeatBalanceSurfaceManager { SurfWinExtDiffAbsByShade(SurfNum) *= SurfWinGlazedFrac(SurfNum); if (ShadeFlag == WinShadingType::SwitchableGlazing) { // Switchable glazing - Real64 SwitchFac = SurfWinSwitchingFactor( - SurfNum); // Switching factor for switchable glazing + Real64 SwitchFac = SurfWinSwitchingFactor( SurfNum); // Switching factor for switchable glazing for (int Lay = 1; Lay <= TotGlassLay; ++Lay) { - AbsDiffWin(Lay) = InterpSw(SwitchFac, AbsDiffWin(Lay), - state.dataConstruction->Construct( - ConstrNumSh).AbsDiff(Lay)); + AbsDiffWin(Lay) = InterpSw(SwitchFac, AbsDiffWin(Lay), state.dataConstruction->Construct(ConstrNumSh).AbsDiff(Lay)); } } diff --git a/src/EnergyPlus/SolarShading.cc b/src/EnergyPlus/SolarShading.cc index 6dc3c9847e3..1c2c4581eb7 100644 --- a/src/EnergyPlus/SolarShading.cc +++ b/src/EnergyPlus/SolarShading.cc @@ -49,7 +49,7 @@ #include #include #include -#include + // ObjexxFCL Headers #include #include @@ -6881,12 +6881,6 @@ namespace SolarShading { // The layer order for interior windows is "outside" to "inside," where "outside" refers to // the adjacent zone and "inside" refers to the current zone. WinShadingType ShadeFlagBack = SurfWinShadingFlag(BackSurfNum); - int ConstrNum = Surface(SurfNum).Construction; - int ConstrNumSh = Surface(SurfNum).activeShadedConstruction; - if (SurfWinStormWinFlag(SurfNum) == 1) { - ConstrNum = Surface(SurfNum).StormWinConstruction; - ConstrNumSh = Surface(SurfNum).activeStormWinShadedConstruction; - } bool VarSlatsBack = SurfWinMovableSlats(BackSurfNum); Real64 SlatAngBack = SurfWinSlatAngThisTS(BackSurfNum); Real64 CosIncBack = std::abs(CosIncAng(state.dataGlobal->TimeStep, state.dataGlobal->HourOfDay, BackSurfNum)); @@ -7053,7 +7047,7 @@ namespace SolarShading { IntBeamAbsByShadFac(BackSurfNum) = BOverlap * ABlBack / (Surface(BackSurfNum).Area + SurfWinDividerArea(BackSurfNum)); } else { - + // ShadeFlagBack == BGBlindOn Real64 t1k = POLYF(CosIncBack, state.dataConstruction->Construct(ConstrNumBack).tBareSolCoef({1, 6}, 1)); Real64 t2k = POLYF(CosIncBack, state.dataConstruction->Construct(ConstrNumBack).tBareSolCoef({1, 6}, 2)); Real64 af2k = POLYF(CosIncBack, state.dataConstruction->Construct(ConstrNumBack).afBareSolCoef({1, 6}, 2)); @@ -8649,7 +8643,6 @@ namespace SolarShading { using DataWindowEquivalentLayer::CFS; using General::POLYF; using ScheduleManager::GetCurrentScheduleValue; - using namespace std::chrono; static Real64 ThetaBig(0.0); // Larger of ThetaBlock1 and ThetaBlock2 //Autodesk Used uninitialized in some runs static Real64 ThetaSmall(0.0); // Smaller of ThetaBlock1 and ThetaBlock2 //Autodesk Used uninitialized in some runs @@ -8740,10 +8733,6 @@ namespace SolarShading { Surface(ISurf).activeStormWinShadedConstruction = Surface(ISurf).shadedStormWinConstructionList[indexWindowShadingControl]; } int IShadingCtrl = Surface(ISurf).activeWindowShadingControl; - -// int ShadingType = WindowShadingControl(IShadingCtrl).ShadingType; // Type of shading (interior shade, interior blind, etc.) - - int IZone = Surface(ISurf).Zone; // Setpoint for shading Real64 SetPoint = WindowShadingControl(IShadingCtrl).SetPoint; // Control setpoint @@ -8784,16 +8773,16 @@ namespace SolarShading { SurfWinShadingFlag(ISurf) = WinShadingType::ShadeOff; // Initialize shading flag to off switch (WindowShadingControl(IShadingCtrl).ShadingControlType) { - case AlwaysOn: // 'ALWAYSON' + case WindowShadingControlType::AlwaysOn: // 'ALWAYSON' SurfWinShadingFlag(ISurf) = ShType; break; - case AlwaysOff: // 'ALWAYSOFF' + case WindowShadingControlType::AlwaysOff: // 'ALWAYSOFF' SurfWinShadingFlag(ISurf) = WinShadingType::ShadeOff; break; - case OnIfScheduled: // 'ONIFSCHEDULEALLOWS' + case WindowShadingControlType::OnIfScheduled: // 'ONIFSCHEDULEALLOWS' if (SchedAllowsControl) SurfWinShadingFlag(ISurf) = ShType; break; - case HiSolar: // 'ONIFHIGHSOLARONWINDOW' + case WindowShadingControlType::HiSolar: // 'ONIFHIGHSOLARONWINDOW' // ! Direct plus diffuse solar intensity on window if (state.dataEnvrn->SunIsUp) { if (SolarOnWindow > SetPoint && SchedAllowsControl) { @@ -8804,7 +8793,7 @@ namespace SolarShading { } break; - case HiHorzSolar: // 'ONIFHIGHHORIZONTALSOLAR' ! Direct plus diffuse exterior horizontal solar intensity + case WindowShadingControlType::HiHorzSolar: // 'ONIFHIGHHORIZONTALSOLAR' ! Direct plus diffuse exterior horizontal solar intensity if (state.dataEnvrn->SunIsUp) { if (HorizSolar > SetPoint && SchedAllowsControl) { SurfWinShadingFlag(ISurf) = ShType; @@ -8814,7 +8803,7 @@ namespace SolarShading { } break; - case HiOutAirTemp: // 'OnIfHighOutdoorAirTemperature' + case WindowShadingControlType::HiOutAirTemp: // 'OnIfHighOutdoorAirTemperature' if (Surface(ISurf).OutDryBulbTemp > SetPoint && SchedAllowsControl) { SurfWinShadingFlag(ISurf) = ShType; } else if (GlareControlIsActive) { @@ -8822,7 +8811,7 @@ namespace SolarShading { } break; - case HiZoneAirTemp: // 'OnIfHighZoneAirTemperature' ! Previous time step zone air temperature + case WindowShadingControlType::HiZoneAirTemp: // 'OnIfHighZoneAirTemperature' ! Previous time step zone air temperature if (MAT(IZone) > SetPoint && SchedAllowsControl) { SurfWinShadingFlag(ISurf) = ShType; } else if (GlareControlIsActive) { @@ -8830,7 +8819,7 @@ namespace SolarShading { } break; - case OnHiOutTemp_HiSolarWindow: // 'OnIfHighOutdoorAirTempAndHighSolarOnWindow' ! Outside air temp and solar on window + case WindowShadingControlType::OnHiOutTemp_HiSolarWindow: // 'OnIfHighOutdoorAirTempAndHighSolarOnWindow' ! Outside air temp and solar on window if (state.dataEnvrn->SunIsUp) { if (Surface(ISurf).OutDryBulbTemp > SetPoint && SolarOnWindow > SetPoint2 && SchedAllowsControl) { @@ -8841,7 +8830,7 @@ namespace SolarShading { } break; - case OnHiOutTemp_HiHorzSolar: // 'OnIfHighOutdoorAirTempAndHighHorizontalSolar' ! Outside air temp and horizontal solar + case WindowShadingControlType::OnHiOutTemp_HiHorzSolar: // 'OnIfHighOutdoorAirTempAndHighHorizontalSolar' ! Outside air temp and horizontal solar if (state.dataEnvrn->SunIsUp) { if (Surface(ISurf).OutDryBulbTemp > SetPoint && HorizSolar > SetPoint2 && SchedAllowsControl) { @@ -8852,7 +8841,7 @@ namespace SolarShading { } break; - case OnHiZoneTemp_HiSolarWindow: // 'ONIFHIGHZONEAIRTEMPANDHIGHSOLARONWINDOW' ! Zone air temp and solar on window + case WindowShadingControlType::OnHiZoneTemp_HiSolarWindow: // 'ONIFHIGHZONEAIRTEMPANDHIGHSOLARONWINDOW' ! Zone air temp and solar on window if (state.dataEnvrn->SunIsUp) { if (MAT(IZone) > SetPoint && SolarOnWindow > SetPoint2 && SchedAllowsControl) { SurfWinShadingFlag(ISurf) = ShType; @@ -8862,7 +8851,7 @@ namespace SolarShading { } break; - case OnHiZoneTemp_HiHorzSolar: // 'ONIFHIGHZONEAIRTEMPANDHIGHHORIZONTALSOLAR' ! Zone air temp and horizontal solar + case WindowShadingControlType::OnHiZoneTemp_HiHorzSolar: // 'ONIFHIGHZONEAIRTEMPANDHIGHHORIZONTALSOLAR' ! Zone air temp and horizontal solar if (state.dataEnvrn->SunIsUp) { if (MAT(IZone) > SetPoint && HorizSolar > SetPoint2 && SchedAllowsControl) { SurfWinShadingFlag(ISurf) = ShType; @@ -8872,7 +8861,7 @@ namespace SolarShading { } break; - case HiZoneCooling: [[unlikely]] + case WindowShadingControlType::HiZoneCooling: // 'ONIFHIGHZONECOOLING' ! Previous time step zone sensible cooling rate [W] // In the following, the check on BeginSimFlag is needed since SNLoadCoolRate (and SNLoadHeatRate, // used in other CASEs) are not allocated at this point for the first time step of the simulation. @@ -8885,7 +8874,7 @@ namespace SolarShading { } break; - case HiGlare: [[unlikely]] + case WindowShadingControlType::HiGlare: // 'ONIFHIGHGLARE' ! Daylight glare index at first reference point in the zone. // This type of shading control is done in DayltgInteriorIllum. Glare control is not affected // by control schedule. @@ -8895,7 +8884,7 @@ namespace SolarShading { } break; - case MeetDaylIlumSetp: [[unlikely]] + case WindowShadingControlType::MeetDaylIlumSetp: // 'MEETDAYLIGHTILLUMINANCESETPOINT') ! Daylight illuminance test is done in DayltgInteriorIllum // Only switchable glazing does daylight illuminance control if (state.dataEnvrn->SunIsUp && SchedAllowsControl) { @@ -8904,7 +8893,7 @@ namespace SolarShading { } break; - case OnNightLoOutTemp_OffDay: [[unlikely]]// 'OnNightIfLowOutdoorTempAndOffDay' + case WindowShadingControlType::OnNightLoOutTemp_OffDay: // 'OnNightIfLowOutdoorTempAndOffDay' if (!state.dataEnvrn->SunIsUp && Surface(ISurf).OutDryBulbTemp < SetPoint && SchedAllowsControl) { SurfWinShadingFlag(ISurf) = ShType; } else if (GlareControlIsActive) { @@ -8912,7 +8901,7 @@ namespace SolarShading { } break; - case OnNightLoInTemp_OffDay: [[unlikely]]// 'OnNightIfLowInsideTempAndOffDay') + case WindowShadingControlType::OnNightLoInTemp_OffDay: // 'OnNightIfLowInsideTempAndOffDay') if (!state.dataEnvrn->SunIsUp && MAT(IZone) < SetPoint && SchedAllowsControl) { SurfWinShadingFlag(ISurf) = ShType; } else if (GlareControlIsActive) { @@ -8920,7 +8909,7 @@ namespace SolarShading { } break; - case OnNightIfHeating_OffDay: [[unlikely]]// 'OnNightIfHeatingAndOffDay' + case WindowShadingControlType::OnNightIfHeating_OffDay: // 'OnNightIfHeatingAndOffDay' if (!state.dataGlobal->BeginSimFlag) { if (!state.dataEnvrn->SunIsUp && SNLoadHeatRate(IZone) > SetPoint && SchedAllowsControl) { SurfWinShadingFlag(ISurf) = ShType; @@ -8930,7 +8919,7 @@ namespace SolarShading { } break; - case OnNightLoOutTemp_OnDayCooling: [[unlikely]]// 'OnNightIfLowOutdoorTempAndOnDayIfCooling' + case WindowShadingControlType::OnNightLoOutTemp_OnDayCooling: // 'OnNightIfLowOutdoorTempAndOnDayIfCooling' if (!state.dataGlobal->BeginSimFlag) { if (!state.dataEnvrn->SunIsUp) { // Night if (Surface(ISurf).OutDryBulbTemp < SetPoint && SchedAllowsControl) @@ -8945,7 +8934,7 @@ namespace SolarShading { } break; - case OnNightIfHeating_OnDayCooling: [[unlikely]]// 'OnNightIfHeatingAndOnDayIfCooling' + case WindowShadingControlType::OnNightIfHeating_OnDayCooling: // 'OnNightIfHeatingAndOnDayIfCooling' if (!state.dataGlobal->BeginSimFlag) { if (!state.dataEnvrn->SunIsUp) { // Night if (SNLoadHeatRate(IZone) > SetPoint && SchedAllowsControl) @@ -8960,7 +8949,7 @@ namespace SolarShading { } break; - case OffNight_OnDay_HiSolarWindow: [[unlikely]]// 'OffNightAndOnDayIfCoolingAndHighSolarOnWindow' + case WindowShadingControlType::OffNight_OnDay_HiSolarWindow: // 'OffNightAndOnDayIfCoolingAndHighSolarOnWindow' if (!state.dataGlobal->BeginSimFlag) { if (state.dataEnvrn->SunIsUp && SNLoadCoolRate(IZone) > 0.0 && SchedAllowsControl) { if (SolarOnWindow > SetPoint) SurfWinShadingFlag(ISurf) = ShType; @@ -8970,7 +8959,7 @@ namespace SolarShading { } break; - case OnNight_OnDay_HiSolarWindow: [[unlikely]]// 'OnNightAndOnDayIfCoolingAndHighSolarOnWindow' + case WindowShadingControlType::OnNight_OnDay_HiSolarWindow: // 'OnNightAndOnDayIfCoolingAndHighSolarOnWindow' if (!state.dataGlobal->BeginSimFlag) { if (state.dataEnvrn->SunIsUp && SNLoadCoolRate(IZone) > 0.0 && SchedAllowsControl) { if (SolarOnWindow > SetPoint) SurfWinShadingFlag(ISurf) = ShType; @@ -8981,9 +8970,9 @@ namespace SolarShading { } } break; - default: [[unlikely]] - std::cout << "Invalid Selection\n"; - break; + default: + ShowWarningError(state, "Invalid Selection of Window Shading Control Type for Surface " + + Surface(ISurf).Name); } // Set switching factor to fully switched if ShadingFlag = 2 diff --git a/src/EnergyPlus/SurfaceGeometry.cc b/src/EnergyPlus/SurfaceGeometry.cc index 467d7e6c28a..d4eb0b2281e 100644 --- a/src/EnergyPlus/SurfaceGeometry.cc +++ b/src/EnergyPlus/SurfaceGeometry.cc @@ -8205,27 +8205,27 @@ namespace SurfaceGeometry { static Array1D const ValidWindowShadingControlTypes( NumValidWindowShadingControlTypes, - {AlwaysOn, - AlwaysOff, - OnIfScheduled, - HiSolar, - HiHorzSolar, - HiOutAirTemp, - HiZoneAirTemp, - HiZoneCooling, - HiGlare, - MeetDaylIlumSetp, - OnNightLoOutTemp_OffDay, - OnNightLoInTemp_OffDay, - OnNightIfHeating_OffDay, - OnNightLoOutTemp_OnDayCooling, - OnNightIfHeating_OnDayCooling, - OffNight_OnDay_HiSolarWindow, - OnNight_OnDay_HiSolarWindow, - OnHiOutTemp_HiSolarWindow, - OnHiOutTemp_HiHorzSolar, - OnHiZoneTemp_HiSolarWindow, - OnHiZoneTemp_HiHorzSolar}); // 'ALWAYSON ', & | 'ALWAYSOFF ', & + {WindowShadingControlType::AlwaysOn, + WindowShadingControlType::AlwaysOff, + WindowShadingControlType::OnIfScheduled, + WindowShadingControlType::HiSolar, + WindowShadingControlType::HiHorzSolar, + WindowShadingControlType::HiOutAirTemp, + WindowShadingControlType::HiZoneAirTemp, + WindowShadingControlType::HiZoneCooling, + WindowShadingControlType::HiGlare, + WindowShadingControlType::MeetDaylIlumSetp, + WindowShadingControlType::OnNightLoOutTemp_OffDay, + WindowShadingControlType::OnNightLoInTemp_OffDay, + WindowShadingControlType::OnNightIfHeating_OffDay, + WindowShadingControlType::OnNightLoOutTemp_OnDayCooling, + WindowShadingControlType::OnNightIfHeating_OnDayCooling, + WindowShadingControlType::OffNight_OnDay_HiSolarWindow, + WindowShadingControlType::OnNight_OnDay_HiSolarWindow, + WindowShadingControlType::OnHiOutTemp_HiSolarWindow, + WindowShadingControlType::OnHiOutTemp_HiHorzSolar, + WindowShadingControlType::OnHiZoneTemp_HiSolarWindow, + WindowShadingControlType::OnHiZoneTemp_HiHorzSolar}); // 'ALWAYSON ', & | 'ALWAYSOFF ', & // | 'ONIFSCHEDULEALLOWS ', & | 'ONIFHIGHSOLARONWINDOW ', // & | 'ONIFHIGHHORIZONTALSOLAR ', & | 'ONIFHIGHOUTDOORAIRTEMPERATURE // ', & | 'ONIFHIGHZONEAIRTEMPERATURE ', & | 'ONIFHIGHZONECOOLING @@ -8451,7 +8451,7 @@ namespace SurfaceGeometry { cAlphaArgs(8) + "\"."); } - if ((WindowShadingControl(ControlNum).ShadingControlType == OnIfScheduled) && + if ((WindowShadingControl(ControlNum).ShadingControlType == WindowShadingControlType::OnIfScheduled) && (!WindowShadingControl(ControlNum).ShadingControlIsScheduled)) { // CR 7709 BG ErrorsFound = true; ShowSevereError(state, cCurrentModuleObject + " = \"" + WindowShadingControl(ControlNum).Name + "\" invalid, " + cAlphaFieldNames(7) + diff --git a/src/EnergyPlus/WindowManager.cc b/src/EnergyPlus/WindowManager.cc index b791e67a517..f2d425c16b6 100644 --- a/src/EnergyPlus/WindowManager.cc +++ b/src/EnergyPlus/WindowManager.cc @@ -3062,7 +3062,7 @@ namespace WindowManager { Aface(4, 4) = hr(4) + sconsh + state.dataWindowManager->hcin; } - if (ShadeFlag == WinShadingType::ExtShade || ShadeFlag == WinShadingType::ExtBlind || ShadeFlag == WinShadingType::ExtScreen) { + if (IS_EXT_SHADED(ShadeFlag)) { Bface(1) = state.dataWindowManager->Outir * state.dataWindowManager->emis(1) * TauShIR / ShGlReflFacIR + hcv * TGapNew + state.dataWindowManager->AbsRadGlassFace(1); Bface(3) = state.dataWindowManager->Outir * EpsShIR1 + state.dataWindowManager->hcout * state.dataWindowManager->tout + AbsRadShadeFace(1); Bface(4) = state.dataWindowManager->Outir * TauShIR * RhoGlIR1 * EpsShIR2 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(2); @@ -3245,7 +3245,7 @@ namespace WindowManager { Aface(8, 8) = hr(8) + sconsh + state.dataWindowManager->hcin; } - if (ShadeFlag == WinShadingType::ExtShade || ShadeFlag == WinShadingType::ExtBlind || ShadeFlag == WinShadingType::ExtScreen) { + if (IS_EXT_SHADED(ShadeFlag)) { Bface(1) = state.dataWindowManager->Outir * state.dataWindowManager->emis(1) * TauShIR / ShGlReflFacIR + hcv * TGapNew + state.dataWindowManager->AbsRadGlassFace(1); Bface(7) = state.dataWindowManager->Outir * EpsShIR1 + state.dataWindowManager->hcout * state.dataWindowManager->tout + AbsRadShadeFace(1); Bface(8) = state.dataWindowManager->Outir * TauShIR * RhoGlIR1 * EpsShIR2 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(2); @@ -3371,7 +3371,7 @@ namespace WindowManager { Aface(10, 10) = hr(10) + sconsh + state.dataWindowManager->hcin; } - if (ShadeFlag == WinShadingType::ExtShade || ShadeFlag == WinShadingType::ExtBlind || ShadeFlag == WinShadingType::ExtScreen) { + if (IS_EXT_SHADED(ShadeFlag)) { Bface(1) = state.dataWindowManager->Outir * state.dataWindowManager->emis(1) * TauShIR / ShGlReflFacIR + hcv * TGapNew + state.dataWindowManager->AbsRadGlassFace(1); Bface(9) = state.dataWindowManager->Outir * EpsShIR1 + state.dataWindowManager->hcout * state.dataWindowManager->tout + AbsRadShadeFace(1); Bface(10) = state.dataWindowManager->Outir * TauShIR * RhoGlIR1 * EpsShIR2 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(2); @@ -3519,8 +3519,7 @@ namespace WindowManager { // shouldn't this be + outward flowing fraction of absorbed SW? -- do not know whose comment this is? LKL (9/2012) SurfWinLossSWZoneToOutWinRep(SurfNum) = QS(Surface(SurfNum).SolarEnclIndex) * Surface(SurfNum).Area * TransDiff; - if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::ExtShade || ShadeFlag == WinShadingType::IntBlind || ShadeFlag == WinShadingType::ExtBlind || ShadeFlag == WinShadingType::BGShade || - ShadeFlag == WinShadingType::BGBlind || ShadeFlag == WinShadingType::ExtScreen) { + if (IS_SHADE_SCREEN_ON(ShadeFlag) || IS_BLIND_ON(ShadeFlag)) { SurfWinShadingAbsorbedSolar(SurfNum) = (SurfWinExtBeamAbsByShade(SurfNum) + SurfWinExtDiffAbsByShade(SurfNum)) * (Surface(SurfNum).Area + SurfWinDividerArea(SurfNum)); SurfWinShadingAbsorbedSolarEnergy(SurfNum) = SurfWinShadingAbsorbedSolar(SurfNum) * state.dataGlobal->TimeStepZoneSec; diff --git a/src/EnergyPlus/api/EnergyPlusPgm.cc b/src/EnergyPlus/api/EnergyPlusPgm.cc index fdcaa508e7d..4c3425c7e01 100644 --- a/src/EnergyPlus/api/EnergyPlusPgm.cc +++ b/src/EnergyPlus/api/EnergyPlusPgm.cc @@ -393,6 +393,7 @@ int RunEnergyPlus(EnergyPlus::EnergyPlusData &state, std::string const & filepat // METHODOLOGY EMPLOYED: // The method used in EnergyPlus is to simplify the main program as much // as possible and contain all "simulation" code in other modules and files. + int status = initializeEnergyPlus(state, filepath); if (status || state.dataGlobal->outputEpJSONConversionOnly) return status; try { diff --git a/tst/EnergyPlus/unit/SurfaceGeometry.unit.cc b/tst/EnergyPlus/unit/SurfaceGeometry.unit.cc index 17f7983cbf2..ea8e30901cf 100644 --- a/tst/EnergyPlus/unit/SurfaceGeometry.unit.cc +++ b/tst/EnergyPlus/unit/SurfaceGeometry.unit.cc @@ -3476,7 +3476,7 @@ TEST_F(EnergyPlusFixture, SurfaceGeometry_isWindowShadingControlSimilar_Test) WindowShadingControl(1).SequenceNumber = 3; WindowShadingControl(1).ShadingType = WinShadingType::ExtShade; WindowShadingControl(1).ShadingDevice = 17; - WindowShadingControl(1).ShadingControlType = OnIfScheduled; + WindowShadingControl(1).ShadingControlType = WindowShadingControlType::OnIfScheduled; WindowShadingControl(1).Schedule = 83; WindowShadingControl(1).SetPoint = 200; WindowShadingControl(1).SetPoint2 = 170; @@ -3550,7 +3550,7 @@ TEST_F(EnergyPlusFixture, SurfaceGeometry_isWindowShadingControlSimilar_Test) EXPECT_FALSE(isWindowShadingControlSimilar(1, 2)); WindowShadingControl(2) = WindowShadingControl(1); - WindowShadingControl(2).ShadingControlType = OffNight_OnDay_HiSolarWindow; + WindowShadingControl(2).ShadingControlType = WindowShadingControlType::OffNight_OnDay_HiSolarWindow; EXPECT_FALSE(isWindowShadingControlSimilar(1, 2)); WindowShadingControl(2) = WindowShadingControl(1); @@ -3603,7 +3603,7 @@ TEST_F(EnergyPlusFixture, SurfaceGeometry_CheckWindowShadingControlSimilarForWin WindowShadingControl(1).SequenceNumber = 3; WindowShadingControl(1).ShadingType = WinShadingType::ExtShade; WindowShadingControl(1).ShadingDevice = 17; - WindowShadingControl(1).ShadingControlType = OnIfScheduled; + WindowShadingControl(1).ShadingControlType = WindowShadingControlType::OnIfScheduled; WindowShadingControl(1).Schedule = 83; WindowShadingControl(1).SetPoint = 200; WindowShadingControl(1).SetPoint2 = 170; From b68ec4e7a1c74cf65612760df614d478dff46c04 Mon Sep 17 00:00:00 2001 From: Noel Merket Date: Tue, 26 Jan 2021 11:55:56 -0700 Subject: [PATCH 26/76] ElectricLoadCenter:Storage:LiIonNMCBattery idd object and input processing --- idd/Energy+.idd.in | 133 ++++++++++++++++++ src/EnergyPlus/ElectricPowerServiceManager.cc | 95 ++++++++++--- src/EnergyPlus/ElectricPowerServiceManager.hh | 25 +++- .../unit/ElectricPowerServiceManager.unit.cc | 59 ++++++++ 4 files changed, 290 insertions(+), 22 deletions(-) diff --git a/idd/Energy+.idd.in b/idd/Energy+.idd.in index 7379fddb7d3..dccbd3fe74f 100644 --- a/idd/Energy+.idd.in +++ b/idd/Energy+.idd.in @@ -88754,6 +88754,139 @@ ElectricLoadCenter:Storage:Battery, \note Determines the number of cycles to failure in relation to cycle range. \note Only required when battery life calculation is activated. +ElectricLoadCenter:Storage:LiIonNMCBattery, + \memo Uses Lithium Ion NMC model to simulate rechargeable battery banks in an + \memo electrical load center. The battery bank is a collection of one or more individual + \memo battery modules. Given the surplus or deficit power from the electrical system and + \memo the state of charge from the previous time step, this object can model the voltage, + \memo current, and energy losses with charging and discharging during each time step. + \memo The cumulative battery damage can be also modeled and reported at the end of + \memo each simulation run. + A1, \field Name + \required-field + \type alpha + \reference ElecStorageList + A2, \field Availability Schedule Name + \note Availability schedule name for this system. Schedule value > 0 means the system is available. + \note If this field is blank, the system is always available. + \type object-list + \object-list ScheduleNames + A3, \field Zone Name + \type object-list + \object-list ZoneNames + \note Enter name of zone to receive electrical storage losses as heat + \note if blank then electrical storage losses are dissipated to outdoors + N1, \field Radiative Fraction + \type real + \minimum 0 + \maximum 1.0 + \default 0 + A4, \field Lifetime Model + \type choice + \key None + \key KandlerSmith + \default KandlerSmith + N2, \field Number of Cells in Series + \type integer + \minimum 1 + \default 3 + \note Each cell in a Li-ion battery is 3.6V + \note with a capacity of 3.2 A-h. + N3, \field Number of Strings in Parallel + \type integer + \minimum 1 + \default 1 + \note TODO + N4, \field Minimum Available State of Charge + \type real + \minimum 0 + \maximum< 1.0 + \default 0.15 + \note A model parameter usually derived from test data by curve fitting. + N5, \field Maximum Available State of Charge + \type real + \minimum> 0 + \maximum 1.0 + \default 0.95 + \note A model parameter usually derived from test data by curve fitting. + N6, \field Initial Fractional State of Charge + \type real + \minimum 0 + \maximum 1.0 + \default 0.5 + \note The state of charge is evaluated based on the + \note maximum capacity defined in the next field. + N7, \field DC to DC Charging Efficiency + \type real + \minimum> 0 + \maximum 1 + \default 0.95 + N8, \field Battery Mass + \type real + \minimum> 0 + \units kg + \default 95.1255 + N9, \field Battery Surface Area + \type real + \minimum> 0 + \units m2 + \default 0.5 + N10, \field Battery Specific Heat Capacity + \type real + \minimum> 0 + \units J/kg-K + \default 1500 + N11, \field Heat Transfer Coefficient Between Battery and Ambient + \type real + \minimum> 0 + \units W/m2-K + \default 7.5 + N12, \field Fully Charged Cell Voltage + \type real + \minimum> 0 + \units V + \default 4.2 + N13, \field Cell Voltage at End of Exponential Zone + \type real + \minimum> 0 + \units V + \default 3.53 + N14, \field Cell Voltage at End of Nominal Zone + \type real + \minimum> 0 + \units V + \default 3.342 + N15, \field Default Nominal Cell Voltage + \type real + \minimum> 0 + \units V + \default 3.342 + N16, \field Fully Charged Cell Capacity + \type real + \minimum> 0 + \units A-h + \default 1 + N17, \field Cell Capacity at End of Exponential Zone + \type real + \minimum> 0 + \units A-h + \default 0.1925 + N18, \field Cell Capacity at End of Nominal Zone + \type real + \minimum> 0 + \units A-h + \default 0.0231 + N19, \field Rate at Which Voltage vs Capacity Curve Input + \type real + \minimum> 0 + \default 1 + N20; \field Battery Cell Internal Electrical Resistance + \type real + \minimum 0 + \units ohms + \default 0.09 + \note for a single cell + ElectricLoadCenter:Transformer, \memo a list of meters that can be reported are available after a run on \memo the meter dictionary file (.mdd) if the Output:VariableDictionary has been requested. diff --git a/src/EnergyPlus/ElectricPowerServiceManager.cc b/src/EnergyPlus/ElectricPowerServiceManager.cc index 35985318a31..552002fa472 100644 --- a/src/EnergyPlus/ElectricPowerServiceManager.cc +++ b/src/EnergyPlus/ElectricPowerServiceManager.cc @@ -80,6 +80,9 @@ #include #include +// SSC Headers +#include <../third_party/ssc/shared/lib_battery.h> + namespace EnergyPlus { std::unique_ptr facilityElectricServiceObj; @@ -2941,13 +2944,15 @@ ElectricStorage::ElectricStorage( // main constructor maxRainflowArrayInc_(100), myWarmUpFlag_(false), storageModelMode_(StorageModelType::storageTypeNotSet), availSchedPtr_(0), heatLossesDestination_(ThermalLossDestination::heatLossNotDetermined), zoneNum_(0), zoneRadFract_(0.0), startingEnergyStored_(0.0), energeticEfficCharge_(0.0), energeticEfficDischarge_(0.0), maxPowerDraw_(0.0), maxPowerStore_(0.0), maxEnergyCapacity_(0.0), parallelNum_(0), - seriesNum_(0), numBattery_(0), chargeCurveNum_(0), dischargeCurveNum_(0), cycleBinNum_(0), startingSOC_(0.0), maxAhCapacity_(0.0), - availableFrac_(0.0), chargeConversionRate_(0.0), chargedOCV_(0.0), dischargedOCV_(0.0), internalR_(0.0), maxDischargeI_(0.0), cutoffV_(0.0), + seriesNum_(0), numBattery_(0), chargeCurveNum_(0), dischargeCurveNum_(0), cycleBinNum_(0), startingSOC_(0.0), maxAhCapacity_(0.0), maxSOC_(0.0), + chargeConversionRate_(0.0), chargedOCV_(0.0), dischargedOCV_(0.0), internalR_(0.0), maxDischargeI_(0.0), cutoffV_(0.0), maxChargeRate_(0.0), lifeCalculation_(BatteyDegredationModelType::degredationNotSet), lifeCurveNum_(0), thisTimeStepStateOfCharge_(0.0), lastTimeStepStateOfCharge_(0.0), pelNeedFromStorage_(0.0), pelFromStorage_(0.0), pelIntoStorage_(0.0), qdotConvZone_(0.0), qdotRadZone_(0.0), timeElapsed_(0.0), thisTimeStepAvailable_(0.0), thisTimeStepBound_(0.0), lastTimeStepAvailable_(0.0), lastTimeStepBound_(0.0), lastTwoTimeStepAvailable_(0.0), lastTwoTimeStepBound_(0.0), count0_(0), electEnergyinStorage_(0.0), thermLossRate_(0.0), thermLossEnergy_(0.0), - storageMode_(0), absoluteSOC_(0.0), fractionSOC_(0.0), batteryCurrent_(0.0), batteryVoltage_(0.0), batteryDamage_(0.0) + storageMode_(0), absoluteSOC_(0.0), fractionSOC_(0.0), batteryCurrent_(0.0), batteryVoltage_(0.0), batteryDamage_(0.0), + liIon_dcToDcChargingEff_(0.0), liIon_mass_(0.0), liIon_surfaceArea_(0.0), liIon_Cp_(0.0), liIon_heatTransferCoef_(0.0), liIon_Vfull_(0.0), + liIon_Vexp_(0.0), liIon_Vnom_(0.0), liIon_Vnom_default_(0.0), liIon_Qfull_(0.0), liIon_Qexp_(0.0), liIon_Qnom_(0.0), liIon_C_rate_(0.0) { std::string const routineName = "ElectricStorage constructor "; @@ -2976,6 +2981,14 @@ ElectricStorage::ElectricStorage( // main constructor storageModelMode_ = StorageModelType::kiBaMBattery; } + testStorageIndex = inputProcessor->getObjectItemNum(state, "ElectricLoadCenter:Storage:LiIonNMCBattery", objectName); + if (testStorageIndex > 0) { + foundStorage = true; + storageIDFObjectNum = testStorageIndex; + DataIPShortCuts::cCurrentModuleObject = "ElectricLoadCenter:Storage:LiIonNMCBattery"; + storageModelMode_ = StorageModelType::liIonNmcBattery; + } + if (foundStorage) { inputProcessor->getObjectItem(state, DataIPShortCuts::cCurrentModuleObject, @@ -3125,7 +3138,7 @@ ElectricStorage::ElectricStorage( // main constructor numBattery_ = parallelNum_ * seriesNum_; maxAhCapacity_ = DataIPShortCuts::rNumericArgs(4); startingSOC_ = DataIPShortCuts::rNumericArgs(5); - availableFrac_ = DataIPShortCuts::rNumericArgs(6); + maxSOC_ = DataIPShortCuts::rNumericArgs(6); chargeConversionRate_ = DataIPShortCuts::rNumericArgs(7); chargedOCV_ = DataIPShortCuts::rNumericArgs(8); dischargedOCV_ = DataIPShortCuts::rNumericArgs(9); @@ -3150,6 +3163,54 @@ ElectricStorage::ElectricStorage( // main constructor } break; } + case StorageModelType::liIonNmcBattery: { + if (UtilityRoutines::SameString(DataIPShortCuts::cAlphaArgs(4), "KandlerSmith") or DataIPShortCuts::lAlphaFieldBlanks(4)) { + lifeCalculation_ = BatteyDegredationModelType::lifeCalculationYes; + } else { + lifeCalculation_ = BatteyDegredationModelType::lifeCalculationNo; + } + seriesNum_ = DataIPShortCuts::lNumericFieldBlanks(2) ? 3 : static_cast(DataIPShortCuts::rNumericArgs(2)); + parallelNum_ = DataIPShortCuts::lNumericFieldBlanks(3) ? 1 : static_cast(DataIPShortCuts::rNumericArgs(3)); + minSOC_ = DataIPShortCuts::lNumericFieldBlanks(4) ? 0.15 : DataIPShortCuts::rNumericArgs(4); + maxSOC_ = DataIPShortCuts::lNumericFieldBlanks(5) ? 0.95 : DataIPShortCuts::rNumericArgs(5); + if (minSOC_ >= maxSOC_) { + ShowSevereError(state, routineName + DataIPShortCuts::cCurrentModuleObject + "=\"" + DataIPShortCuts::cAlphaArgs(1) + "\", invalid entry."); + ShowContinueError(state, DataIPShortCuts::cNumericFieldNames(4) + " should be less than " + DataIPShortCuts::cNumericFieldNames(5)); + ShowContinueError(state, format("{} = {:.3R}.", DataIPShortCuts::cNumericFieldNames(4), DataIPShortCuts::rNumericArgs(4))); + ShowContinueError(state, format("{} = {:.3R}.", DataIPShortCuts::cNumericFieldNames(5), DataIPShortCuts::rNumericArgs(5))); + errorsFound = true; + } + startingSOC_ = DataIPShortCuts::lNumericFieldBlanks(6) ? 0.5 : DataIPShortCuts::rNumericArgs(6); + if (startingSOC_ > maxSOC_) { + ShowSevereError(state, routineName + DataIPShortCuts::cCurrentModuleObject + "=\"" + DataIPShortCuts::cAlphaArgs(1) + "\", invalid entry."); + ShowContinueError(state, DataIPShortCuts::cNumericFieldNames(6) + " should be less than or equal to " + DataIPShortCuts::cNumericFieldNames(5)); + ShowContinueError(state, format("{} = {:.3R}.", DataIPShortCuts::cNumericFieldNames(6), DataIPShortCuts::rNumericArgs(6))); + ShowContinueError(state, format("{} = {:.3R}.", DataIPShortCuts::cNumericFieldNames(5), DataIPShortCuts::rNumericArgs(5))); + errorsFound = true; + } + if (startingSOC_ < minSOC_) { + ShowSevereError(state, routineName + DataIPShortCuts::cCurrentModuleObject + "=\"" + DataIPShortCuts::cAlphaArgs(1) + "\", invalid entry."); + ShowContinueError(state, DataIPShortCuts::cNumericFieldNames(6) + " should be greater than or equal to " + DataIPShortCuts::cNumericFieldNames(4)); + ShowContinueError(state, format("{} = {:.3R}.", DataIPShortCuts::cNumericFieldNames(6), DataIPShortCuts::rNumericArgs(6))); + ShowContinueError(state, format("{} = {:.3R}.", DataIPShortCuts::cNumericFieldNames(4), DataIPShortCuts::rNumericArgs(4))); + errorsFound = true; + } + liIon_dcToDcChargingEff_ = DataIPShortCuts::lNumericFieldBlanks(7) ? 0.95 : DataIPShortCuts::rNumericArgs(7); + liIon_mass_ = DataIPShortCuts::lNumericFieldBlanks(8) ? 95.1255 : DataIPShortCuts::rNumericArgs(8); + liIon_surfaceArea_ = DataIPShortCuts::lNumericFieldBlanks(9) ? 0.5 : DataIPShortCuts::rNumericArgs(9); + liIon_Cp_ = DataIPShortCuts::lNumericFieldBlanks(10) ? 1500.0 : DataIPShortCuts::rNumericArgs(10); + liIon_heatTransferCoef_ = DataIPShortCuts::lNumericFieldBlanks(11) ? 7.5 : DataIPShortCuts::rNumericArgs(11); + liIon_Vfull_ = DataIPShortCuts::lNumericFieldBlanks(12) ? 4.2 : DataIPShortCuts::rNumericArgs(12); + liIon_Vexp_ = DataIPShortCuts::lNumericFieldBlanks(13) ? 3.53 : DataIPShortCuts::rNumericArgs(13); + liIon_Vnom_ = DataIPShortCuts::lNumericFieldBlanks(14) ? 3.342 : DataIPShortCuts::rNumericArgs(14); + liIon_Vnom_default_ = DataIPShortCuts::lNumericFieldBlanks(15) ? 3.342 : DataIPShortCuts::rNumericArgs(15); + liIon_Qfull_ = DataIPShortCuts::lNumericFieldBlanks(16) ? 1.0 : DataIPShortCuts::rNumericArgs(16); + liIon_Qexp_ = DataIPShortCuts::lNumericFieldBlanks(17) ? 0.1925 : DataIPShortCuts::rNumericArgs(17); + liIon_Qnom_ = DataIPShortCuts::lNumericFieldBlanks(18) ? 0.0231 : DataIPShortCuts::rNumericArgs(18); + liIon_C_rate_ = DataIPShortCuts::lNumericFieldBlanks(19) ? 1.0 : DataIPShortCuts::rNumericArgs(19); + internalR_ = DataIPShortCuts::lNumericFieldBlanks(20) ? 0.09 : DataIPShortCuts::rNumericArgs(20); + break; + } case StorageModelType::storageTypeNotSet: { // do nothing break; @@ -3251,12 +3312,12 @@ void ElectricStorage::reinitAtBeginEnvironment() if (storageModelMode_ == StorageModelType::kiBaMBattery) { Real64 initialCharge = maxAhCapacity_ * startingSOC_; - lastTwoTimeStepAvailable_ = initialCharge * availableFrac_; - lastTwoTimeStepBound_ = initialCharge * (1.0 - availableFrac_); - lastTimeStepAvailable_ = initialCharge * availableFrac_; - lastTimeStepBound_ = initialCharge * (1.0 - availableFrac_); - thisTimeStepAvailable_ = initialCharge * availableFrac_; - thisTimeStepBound_ = initialCharge * (1.0 - availableFrac_); + lastTwoTimeStepAvailable_ = initialCharge * maxSOC_; + lastTwoTimeStepBound_ = initialCharge * (1.0 - maxSOC_); + lastTimeStepAvailable_ = initialCharge * maxSOC_; + lastTimeStepBound_ = initialCharge * (1.0 - maxSOC_); + thisTimeStepAvailable_ = initialCharge * maxSOC_; + thisTimeStepBound_ = initialCharge * (1.0 - maxSOC_); if (lifeCalculation_ == BatteyDegredationModelType::lifeCalculationYes) { count0_ = 1; // Index 0 is for initial SOC, so new input starts from index 1. b10_[0] = startingSOC_; // the initial fractional SOC is stored as the reference @@ -3288,12 +3349,12 @@ void ElectricStorage::reinitAtEndWarmup() thisTimeStepStateOfCharge_ = startingEnergyStored_; if (storageModelMode_ == StorageModelType::kiBaMBattery) { Real64 initialCharge = maxAhCapacity_ * startingSOC_; - lastTwoTimeStepAvailable_ = initialCharge * availableFrac_; - lastTwoTimeStepBound_ = initialCharge * (1.0 - availableFrac_); - lastTimeStepAvailable_ = initialCharge * availableFrac_; - lastTimeStepBound_ = initialCharge * (1.0 - availableFrac_); - thisTimeStepAvailable_ = initialCharge * availableFrac_; - thisTimeStepBound_ = initialCharge * (1.0 - availableFrac_); + lastTwoTimeStepAvailable_ = initialCharge * maxSOC_; + lastTwoTimeStepBound_ = initialCharge * (1.0 - maxSOC_); + lastTimeStepAvailable_ = initialCharge * maxSOC_; + lastTimeStepBound_ = initialCharge * (1.0 - maxSOC_); + thisTimeStepAvailable_ = initialCharge * maxSOC_; + thisTimeStepBound_ = initialCharge * (1.0 - maxSOC_); if (lifeCalculation_ == BatteyDegredationModelType::lifeCalculationYes) { count0_ = 1; // Index 0 is for initial SOC, so new input starts from index 1. b10_[0] = startingSOC_; // the initial fractional SOC is stored as the reference @@ -3511,7 +3572,7 @@ void ElectricStorage::simulateKineticBatteryModel(EnergyPlusData &state, E0c = chargedOCV_; E0d = dischargedOCV_; k = chargeConversionRate_; - c = availableFrac_; + c = maxSOC_; if (charging) { diff --git a/src/EnergyPlus/ElectricPowerServiceManager.hh b/src/EnergyPlus/ElectricPowerServiceManager.hh index 8a968b6d9d0..775d6f84bb6 100644 --- a/src/EnergyPlus/ElectricPowerServiceManager.hh +++ b/src/EnergyPlus/ElectricPowerServiceManager.hh @@ -318,7 +318,8 @@ private: // data { storageTypeNotSet = 0, simpleBucketStorage, - kiBaMBattery + kiBaMBattery, + liIonNmcBattery, }; enum class BatteyDegredationModelType : int @@ -356,16 +357,30 @@ private: // data int cycleBinNum_; // [ ] number of cycle bins Real64 startingSOC_; // [ ] initial fractional state of charge Real64 maxAhCapacity_; // [Ah]maximum capacity - Real64 availableFrac_; // [ ] fraction of available charge capacity + Real64 maxSOC_; // [ ] maximum fraction of available charge capacity + Real64 minSOC_; // [ ] minimum fraction of available charge capacity Real64 chargeConversionRate_; // [1/h]change rate from bound charge energy to available charge Real64 chargedOCV_; // [V] fully charged open circuit voltage Real64 dischargedOCV_; // [V] fully discharged open circuit voltage Real64 internalR_; // [ohm]internal electric resistance Real64 maxDischargeI_; // [A] maximum discharging current Real64 cutoffV_; // [V] cut-off voltage - Real64 maxChargeRate_; // [1/h]charge rate limit - BatteyDegredationModelType lifeCalculation_; // [ ]battery life calculation: Yes or No - int lifeCurveNum_; // [ ]battery life curve name index number + Real64 maxChargeRate_; // [1/h] charge rate limit + BatteyDegredationModelType lifeCalculation_; // [ ] battery life calculation: Yes or No + int lifeCurveNum_; // [ ] battery life curve name index number + Real64 liIon_dcToDcChargingEff_; // [ ] DC to DC Charging Efficiency (Li-ion NMC model) + Real64 liIon_mass_; // [kg] mass of battery (Li-ion NMC model) + Real64 liIon_surfaceArea_; // [m2] battery surface area (Li-ion NMC model) + Real64 liIon_Cp_; // [J/kg-K] battery specific heat capacity (Li-ion NMC model) + Real64 liIon_heatTransferCoef_; // [W/m2-K] Heat Transfer Coefficient Between Battery and Ambient (Li-ion NMC model) + Real64 liIon_Vfull_; // [V] Fully charged cell voltage (Li-ion NMC model) + Real64 liIon_Vexp_; // [V] Cell Voltage at End of Exponential Zone (Li-ion NMC model) + Real64 liIon_Vnom_; // [V] Cell voltage at end of nominal zone (Li-ion NMC model) + Real64 liIon_Vnom_default_; // [V] Default nominal cell voltage (Li-ion NMC model) + Real64 liIon_Qfull_; // [A-h] Fully charged cell capacity (Li-ion NMC model) + Real64 liIon_Qexp_; // [A-h] Cell capacity at end of exponential zone (Li-ion NMC model) + Real64 liIon_Qnom_; // [A-h] Cell capacity at end of nominal zone (Li-ion NMC model) + Real64 liIon_C_rate_; // [ ] Rate at which voltage vs capacity curve input (Li-ion NMC model) // calculated and from elsewhere vars Real64 thisTimeStepStateOfCharge_; // [J] Real64 lastTimeStepStateOfCharge_; // [J] diff --git a/tst/EnergyPlus/unit/ElectricPowerServiceManager.unit.cc b/tst/EnergyPlus/unit/ElectricPowerServiceManager.unit.cc index 0d681313592..85f20d83040 100644 --- a/tst/EnergyPlus/unit/ElectricPowerServiceManager.unit.cc +++ b/tst/EnergyPlus/unit/ElectricPowerServiceManager.unit.cc @@ -1023,3 +1023,62 @@ TEST_F(EnergyPlusFixture, ElectricLoadCenter_WarnAvailabilitySchedule_PVWatts) EXPECT_TRUE(compare_err_stream(error_string, true)); } + +TEST_F(EnergyPlusFixture, Battery_LiIonNmc_Constructor) +{ + std::string const idf_objects = delimited_string({ + "ElectricLoadCenter:Storage:LiIonNMCBattery,", + " Battery1, !- Name", + " , !- Availability Schedule Name", + " , !- Zone Name", + " , !- Radiative Fraction", + " KandlerSmith, !- Lifetime Model", + " 5, !- Number of Cells in Series", + " 3, !- Number of Strings in Parallel", + " 0.1, !- Minimum Available State of Charge", + " 0.95, !- Maximum Availabls State of Charge", + " 0.95, !- Initial Fractional State of Charge", + " , !- DC to DC Charging Efficiency", + " 100, !- Battery Mass", + " 0.75, !- Battery Surface Area", + " 1500, !- Battery Specific Heat Capacity", + " 8.1; !- Heat Transfer Coefficient Between Battery and Ambient", + + "ElectricLoadCenter:Storage:LiIonNMCBattery,", + " Battery2, !- Name", + " , !- Availability Schedule Name", + " , !- Zone Name", + " , !- Radiative Fraction", + " None, !- Lifetime Model", + " , !- Number of Cells in Series", + " 3, !- Number of Strings in Parallel", + " 0.9, !- Minimum Available State of Charge", + " 0.1, !- Maximum Availabls State of Charge", + " 0.5; !- Initial Fractional State of Charge", + }); + + ASSERT_TRUE(process_idf(idf_objects)); + ElectricStorage battery1{*state, "Battery1"}; + ASSERT_TRUE(UtilityRoutines::SameString(battery1.name(), "Battery1")); + + ASSERT_THROW(ElectricStorage battery2(*state, "Battery2"), EnergyPlus::FatalError); + std::string const error_string = delimited_string({ + " ** Severe ** ElectricStorage constructor ElectricLoadCenter:Storage:LiIonNMCBattery=\"BATTERY2\", invalid entry.", + " ** ~~~ ** Minimum Available State of Charge should be less than Maximum Available State of Charge", + " ** ~~~ ** Minimum Available State of Charge = 0.900.", + " ** ~~~ ** Maximum Available State of Charge = 0.100.", + " ** Severe ** ElectricStorage constructor ElectricLoadCenter:Storage:LiIonNMCBattery=\"BATTERY2\", invalid entry.", + " ** ~~~ ** Initial Fractional State of Charge should be less than or equal to Maximum Available State of Charge", + " ** ~~~ ** Initial Fractional State of Charge = 0.500.", + " ** ~~~ ** Maximum Available State of Charge = 0.100.", + " ** Severe ** ElectricStorage constructor ElectricLoadCenter:Storage:LiIonNMCBattery=\"BATTERY2\", invalid entry.", + " ** ~~~ ** Initial Fractional State of Charge should be greater than or equal to Minimum Available State of Charge", + " ** ~~~ ** Initial Fractional State of Charge = 0.500.", + " ** ~~~ ** Minimum Available State of Charge = 0.900.", + " ** Fatal ** ElectricStorage constructor Preceding errors terminate program.", + " ...Summary of Errors that led to program termination:", + " ..... Reference severe error count=3", + " ..... Last severe error=ElectricStorage constructor ElectricLoadCenter:Storage:LiIonNMCBattery=\"BATTERY2\", invalid entry." + }); + EXPECT_TRUE(compare_err_stream(error_string, true)); +} \ No newline at end of file From 6d55d05dc697bc6d83a1f55cce4e1a71610f6c53 Mon Sep 17 00:00:00 2001 From: Noel Merket Date: Tue, 26 Jan 2021 11:58:36 -0700 Subject: [PATCH 27/76] Squashed 'third_party/ssc/' changes from 6edbeab044..3ee02f1578 3ee02f1578 Add analytical thermal capacity model, fix runLithiumIonNMC git-subtree-dir: third_party/ssc git-subtree-split: 3ee02f157843dc6e661332fdcbed7e96e4646837 --- shared/lib_battery.cpp | 25 ++++++++++++++++++++++++- shared/lib_battery.h | 11 +++++++++++ shared/lib_battery_lifetime.cpp | 2 +- test/shared_test/lib_battery_test.cpp | 3 +++ 4 files changed, 39 insertions(+), 2 deletions(-) diff --git a/shared/lib_battery.cpp b/shared/lib_battery.cpp index 7f32a07a7ad..79063bcfca4 100644 --- a/shared/lib_battery.cpp +++ b/shared/lib_battery.cpp @@ -55,6 +55,8 @@ thermal_t::thermal_t(double dt_hour, double mass, double surface_area, double R, const util::matrix_t &c_vs_t, std::vector T_room_C) { params = std::shared_ptr(new thermal_params({dt_hour, mass, surface_area, Cp, h, R, c_vs_t})); params->option = thermal_params::SCHEDULE; + //Rohit intialize analytical_model + params->analytical_model = false; params->T_room_schedule = std::move(T_room_C); initialize(); state->T_room = params->T_room_schedule[0]; @@ -64,6 +66,21 @@ thermal_t::thermal_t(double dt_hour, double mass, double surface_area, double R, const util::matrix_t &c_vs_t, double T_room_C) { params = std::shared_ptr(new thermal_params({dt_hour, mass, surface_area, Cp, h, R, c_vs_t})); params->option = thermal_params::VALUE; + //Rohit initialize analytical_model + params->analytical_model = false; + params->T_room_init = T_room_C; + initialize(); +} + +thermal_t::thermal_t(double dt_hour, double mass, double surface_area, double R, double Cp, double h, + double T_room_C) { + util::matrix_t c_vs_t; + double vals3[] = { -10, 60, 0, 80, 25, 100, 40, 100 }; + c_vs_t.assign(vals3, 4, 2); + params = std::shared_ptr(new thermal_params({ dt_hour, mass, surface_area, Cp, h, R, c_vs_t })); + params->option = thermal_params::VALUE; + //Rohit initialize analytical_model + params->analytical_model = true; params->T_room_init = T_room_C; initialize(); } @@ -101,7 +118,13 @@ void thermal_t::replace_battery(size_t lifetimeIndex) { } void thermal_t::calc_capacity() { - double percent = util::linterp_col(params->cap_vs_temp, 0, state->T_batt, 1); + + double percent; + if (params->analytical_model) + percent = 100 * exp(-(Ea_d0_1 / Rug) * (1 / state->T_batt - 1 / T_ref) - + (Ea_d0_2 / Rug) * pow((1 / state->T_batt - 1 / T_ref), 2)); + else + percent = util::linterp_col(params->cap_vs_temp, 0, state->T_batt, 1); if (std::isnan(percent) || percent < 0 || percent > 100) { percent = 100; diff --git a/shared/lib_battery.h b/shared/lib_battery.h index 5e55277ab0e..23dac40fbad 100644 --- a/shared/lib_battery.h +++ b/shared/lib_battery.h @@ -61,6 +61,8 @@ struct thermal_params { double h; // [W/m2/K] - general heat transfer coefficient double resistance; // [Ohm] - internal resistance util::matrix_t cap_vs_temp; + //Rohit add analytical model for updating capacity + bool analytical_model; enum OPTIONS { VALUE, SCHEDULE @@ -80,6 +82,10 @@ class thermal_t { thermal_t(double dt_hour, double mass, double surface_area, double R, double Cp, double h, const util::matrix_t &c_vs_t, double T_room_C); + //Rohit - add constructor for analytical model + thermal_t(double dt_hour, double mass, double surface_area, double R, double Cp, double h, + double T_room_C); + explicit thermal_t(std::shared_ptr p); thermal_t(const thermal_t &rhs); @@ -108,6 +114,11 @@ class thermal_t { std::shared_ptr params; std::shared_ptr state; + double Ea_d0_1 = 4126.0; + double Ea_d0_2 = 9752000; + double Rug = 8.314; + double T_ref = 298.15; + private: void initialize(); diff --git a/shared/lib_battery_lifetime.cpp b/shared/lib_battery_lifetime.cpp index 188d87be223..12783090856 100644 --- a/shared/lib_battery_lifetime.cpp +++ b/shared/lib_battery_lifetime.cpp @@ -690,7 +690,7 @@ void lifetime_t::runLifetimeModels(size_t lifetimeIndex, bool charge_changed, do if (charge_changed && params->calendar_choice != lifetime_params::CALENDAR_CHOICE::NMC_MODEL) q_cycle = cycle_model->runCycleLifetime(prev_DOD); - else if (lifetimeIndex == 0 != lifetime_params::CALENDAR_CHOICE::NMC_MODEL) + else if (charge_changed && params->calendar_choice == lifetime_params::CALENDAR_CHOICE::NMC_MODEL) q_cycle = cycle_model->runCycleLifetimeNMC(T_battery, DOD); // Rohit - add parameter charge_changed diff --git a/test/shared_test/lib_battery_test.cpp b/test/shared_test/lib_battery_test.cpp index dfc38ece157..a163bb799f3 100644 --- a/test/shared_test/lib_battery_test.cpp +++ b/test/shared_test/lib_battery_test.cpp @@ -205,6 +205,7 @@ TEST_F(lib_battery_test, SetUpTest){ ASSERT_TRUE(1); } +/* TEST_F(lib_battery_test, runTestCycleAt1C){ size_t idx = 0; double capacity_passed = 0.; @@ -264,6 +265,7 @@ TEST_F(lib_battery_test, runTestCycleAt1C){ EXPECT_NEAR(qmax/q, .93, 0.01) << "capacity relative to max capacity"; } + TEST_F(lib_battery_test, runTestCycleAt3C){ size_t idx = 0; double capacity_passed = 0.; @@ -323,6 +325,7 @@ TEST_F(lib_battery_test, runTestCycleAt3C){ double qmax = fmax(s.capacity.qmax_lifetime, s.capacity.qmax_thermal); EXPECT_NEAR(qmax/q, 0.9209, 0.01) << "capacity relative to max capacity"; } +*/ TEST_F(lib_battery_test, runDuplicates) { // get initial state From db38fd05eafa35249e3bff959082a5d7f30423b1 Mon Sep 17 00:00:00 2001 From: Noel Merket Date: Tue, 26 Jan 2021 14:24:46 -0700 Subject: [PATCH 28/76] simplifying item lookup for batteries --- src/EnergyPlus/ElectricPowerServiceManager.cc | 37 ++++++++----------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/src/EnergyPlus/ElectricPowerServiceManager.cc b/src/EnergyPlus/ElectricPowerServiceManager.cc index 552002fa472..9ef1dc38b28 100644 --- a/src/EnergyPlus/ElectricPowerServiceManager.cc +++ b/src/EnergyPlus/ElectricPowerServiceManager.cc @@ -2965,28 +2965,21 @@ ElectricStorage::ElectricStorage( // main constructor int testStorageIndex = 0; int storageIDFObjectNum = 0; - testStorageIndex = inputProcessor->getObjectItemNum(state, "ElectricLoadCenter:Storage:Simple", objectName); - if (testStorageIndex > 0) { - foundStorage = true; - storageIDFObjectNum = testStorageIndex; - DataIPShortCuts::cCurrentModuleObject = "ElectricLoadCenter:Storage:Simple"; - storageModelMode_ = StorageModelType::simpleBucketStorage; - } - - testStorageIndex = inputProcessor->getObjectItemNum(state, "ElectricLoadCenter:Storage:Battery", objectName); - if (testStorageIndex > 0) { - foundStorage = true; - storageIDFObjectNum = testStorageIndex; - DataIPShortCuts::cCurrentModuleObject = "ElectricLoadCenter:Storage:Battery"; - storageModelMode_ = StorageModelType::kiBaMBattery; - } - - testStorageIndex = inputProcessor->getObjectItemNum(state, "ElectricLoadCenter:Storage:LiIonNMCBattery", objectName); - if (testStorageIndex > 0) { - foundStorage = true; - storageIDFObjectNum = testStorageIndex; - DataIPShortCuts::cCurrentModuleObject = "ElectricLoadCenter:Storage:LiIonNMCBattery"; - storageModelMode_ = StorageModelType::liIonNmcBattery; + const std::array, 3> storageTypes{{ + {"ElectricLoadCenter:Storage:Simple", StorageModelType::simpleBucketStorage}, + {"ElectricLoadCenter:Storage:Battery", StorageModelType::kiBaMBattery}, + {"ElectricLoadCenter:Storage:LiIonNMCBattery", StorageModelType::liIonNmcBattery} + }}; + + for (auto &item : storageTypes) { + testStorageIndex = inputProcessor->getObjectItemNum(state, item.first, objectName); + if (testStorageIndex > 0) { + foundStorage = true; + storageIDFObjectNum = testStorageIndex; + DataIPShortCuts::cCurrentModuleObject = item.first; + storageModelMode_ = item.second; + break; + } } if (foundStorage) { From 9801007958e4235f056290f8bbd2713a2c90be52 Mon Sep 17 00:00:00 2001 From: Noel Merket Date: Tue, 26 Jan 2021 14:36:28 -0700 Subject: [PATCH 29/76] hooking up zone internal gains --- src/EnergyPlus/DataHeatBalance.cc | 65 ++++++++++--------- src/EnergyPlus/DataHeatBalance.hh | 1 + src/EnergyPlus/ElectricPowerServiceManager.cc | 10 +++ 3 files changed, 44 insertions(+), 32 deletions(-) diff --git a/src/EnergyPlus/DataHeatBalance.cc b/src/EnergyPlus/DataHeatBalance.cc index 4fd4acd5ffe..b77401db467 100644 --- a/src/EnergyPlus/DataHeatBalance.cc +++ b/src/EnergyPlus/DataHeatBalance.cc @@ -394,38 +394,39 @@ namespace DataHeatBalance { int const IntGainTypeOf_ElectricLoadCenterInverterSimple(19); int const IntGainTypeOf_ElectricLoadCenterInverterFunctionOfPower(20); int const IntGainTypeOf_ElectricLoadCenterInverterLookUpTable(21); - int const IntGainTypeOf_ElectricLoadCenterStorageBattery(22); - int const IntGainTypeOf_ElectricLoadCenterStorageSimple(23); - int const IntGainTypeOf_PipeIndoor(24); - int const IntGainTypeOf_RefrigerationCase(25); - int const IntGainTypeOf_RefrigerationCompressorRack(26); - int const IntGainTypeOf_RefrigerationSystemAirCooledCondenser(27); - int const IntGainTypeOf_RefrigerationTransSysAirCooledGasCooler(28); - int const IntGainTypeOf_RefrigerationSystemSuctionPipe(29); - int const IntGainTypeOf_RefrigerationTransSysSuctionPipeMT(30); - int const IntGainTypeOf_RefrigerationTransSysSuctionPipeLT(31); - int const IntGainTypeOf_RefrigerationSecondaryReceiver(32); - int const IntGainTypeOf_RefrigerationSecondaryPipe(33); - int const IntGainTypeOf_RefrigerationWalkIn(34); - int const IntGainTypeOf_Pump_VarSpeed(35); - int const IntGainTypeOf_Pump_ConSpeed(36); - int const IntGainTypeOf_Pump_Cond(37); - int const IntGainTypeOf_PumpBank_VarSpeed(38); - int const IntGainTypeOf_PumpBank_ConSpeed(39); - int const IntGainTypeOf_ZoneContaminantSourceAndSinkGenericContam(40); - int const IntGainTypeOf_PlantComponentUserDefined(41); - int const IntGainTypeOf_CoilUserDefined(42); - int const IntGainTypeOf_ZoneHVACForcedAirUserDefined(43); - int const IntGainTypeOf_AirTerminalUserDefined(44); - int const IntGainTypeOf_PackagedTESCoilTank(45); - int const IntGainTypeOf_ElectricEquipmentITEAirCooled(46); - int const IntGainTypeOf_SecCoolingDXCoilSingleSpeed(47); - int const IntGainTypeOf_SecHeatingDXCoilSingleSpeed(48); - int const IntGainTypeOf_SecCoolingDXCoilTwoSpeed(49); - int const IntGainTypeOf_SecCoolingDXCoilMultiSpeed(50); - int const IntGainTypeOf_SecHeatingDXCoilMultiSpeed(51); - int const IntGainTypeOf_ElectricLoadCenterConverter(52); - int const IntGainTypeOf_FanSystemModel(53); + int const IntGainTypeOf_ElectricLoadCenterStorageLiIonNmcBattery(22); + int const IntGainTypeOf_ElectricLoadCenterStorageBattery(23); + int const IntGainTypeOf_ElectricLoadCenterStorageSimple(24); + int const IntGainTypeOf_PipeIndoor(25); + int const IntGainTypeOf_RefrigerationCase(26); + int const IntGainTypeOf_RefrigerationCompressorRack(27); + int const IntGainTypeOf_RefrigerationSystemAirCooledCondenser(28); + int const IntGainTypeOf_RefrigerationTransSysAirCooledGasCooler(29); + int const IntGainTypeOf_RefrigerationSystemSuctionPipe(30); + int const IntGainTypeOf_RefrigerationTransSysSuctionPipeMT(31); + int const IntGainTypeOf_RefrigerationTransSysSuctionPipeLT(32); + int const IntGainTypeOf_RefrigerationSecondaryReceiver(33); + int const IntGainTypeOf_RefrigerationSecondaryPipe(34); + int const IntGainTypeOf_RefrigerationWalkIn(35); + int const IntGainTypeOf_Pump_VarSpeed(36); + int const IntGainTypeOf_Pump_ConSpeed(37); + int const IntGainTypeOf_Pump_Cond(38); + int const IntGainTypeOf_PumpBank_VarSpeed(39); + int const IntGainTypeOf_PumpBank_ConSpeed(40); + int const IntGainTypeOf_ZoneContaminantSourceAndSinkGenericContam(41); + int const IntGainTypeOf_PlantComponentUserDefined(42); + int const IntGainTypeOf_CoilUserDefined(43); + int const IntGainTypeOf_ZoneHVACForcedAirUserDefined(44); + int const IntGainTypeOf_AirTerminalUserDefined(45); + int const IntGainTypeOf_PackagedTESCoilTank(46); + int const IntGainTypeOf_ElectricEquipmentITEAirCooled(47); + int const IntGainTypeOf_SecCoolingDXCoilSingleSpeed(48); + int const IntGainTypeOf_SecHeatingDXCoilSingleSpeed(49); + int const IntGainTypeOf_SecCoolingDXCoilTwoSpeed(50); + int const IntGainTypeOf_SecCoolingDXCoilMultiSpeed(51); + int const IntGainTypeOf_SecHeatingDXCoilMultiSpeed(52); + int const IntGainTypeOf_ElectricLoadCenterConverter(53); + int const IntGainTypeOf_FanSystemModel(54); // Parameters for checking surface heat transfer models Real64 const HighDiffusivityThreshold(1.e-5); // used to check if Material properties are out of line. diff --git a/src/EnergyPlus/DataHeatBalance.hh b/src/EnergyPlus/DataHeatBalance.hh index 372038e2fb7..312eea3e26a 100644 --- a/src/EnergyPlus/DataHeatBalance.hh +++ b/src/EnergyPlus/DataHeatBalance.hh @@ -244,6 +244,7 @@ namespace DataHeatBalance { extern int const IntGainTypeOf_ElectricLoadCenterInverterSimple; extern int const IntGainTypeOf_ElectricLoadCenterInverterFunctionOfPower; extern int const IntGainTypeOf_ElectricLoadCenterInverterLookUpTable; + extern int const IntGainTypeOf_ElectricLoadCenterStorageLiIonNmcBattery; extern int const IntGainTypeOf_ElectricLoadCenterStorageBattery; extern int const IntGainTypeOf_ElectricLoadCenterStorageSimple; extern int const IntGainTypeOf_ElectricLoadCenterConverter; diff --git a/src/EnergyPlus/ElectricPowerServiceManager.cc b/src/EnergyPlus/ElectricPowerServiceManager.cc index 9ef1dc38b28..e09ef4b74cd 100644 --- a/src/EnergyPlus/ElectricPowerServiceManager.cc +++ b/src/EnergyPlus/ElectricPowerServiceManager.cc @@ -3268,6 +3268,16 @@ ElectricStorage::ElectricStorage( // main constructor &qdotRadZone_); break; } + case StorageModelType::liIonNmcBattery: { + SetupZoneInternalGain(state, zoneNum_, + "ElectricLoadCenter:Storage:LiIonNMCBattery", + name_, + DataHeatBalance::IntGainTypeOf_ElectricLoadCenterStorageLiIonNmcBattery, + &qdotConvZone_, + nullptr, + &qdotRadZone_); + break; + } case StorageModelType::storageTypeNotSet: { // do nothing break; From af671a5fe9cd29ece1c0d26f623ee92613dad318 Mon Sep 17 00:00:00 2001 From: xuanluo113 Date: Tue, 26 Jan 2021 14:48:03 -0800 Subject: [PATCH 30/76] address comments --- src/EnergyPlus/ChilledCeilingPanelSimple.cc | 4 +- src/EnergyPlus/DataSurfaces.cc | 3 + src/EnergyPlus/DataSurfaces.hh | 13 +- src/EnergyPlus/DaylightingManager.cc | 14 +- src/EnergyPlus/ElectricBaseboardRadiator.cc | 4 +- src/EnergyPlus/HWBaseboardRadiator.cc | 4 +- src/EnergyPlus/HeatBalanceIntRadExchange.cc | 6 +- src/EnergyPlus/HeatBalanceSurfaceManager.cc | 128 +++++------------ src/EnergyPlus/HighTempRadiantSystem.cc | 4 +- src/EnergyPlus/LowTempRadiantSystem.cc | 4 +- src/EnergyPlus/RoomAirModelAirflowNetwork.cc | 6 +- src/EnergyPlus/SolarShading.cc | 52 +++---- src/EnergyPlus/SteamBaseboardRadiator.cc | 4 +- src/EnergyPlus/SurfaceGeometry.cc | 141 +++++++------------ src/EnergyPlus/UFADManager.cc | 2 +- src/EnergyPlus/VentilatedSlab.cc | 4 +- src/EnergyPlus/WindowComplexManager.cc | 2 +- src/EnergyPlus/WindowManager.cc | 74 +++++----- 18 files changed, 193 insertions(+), 276 deletions(-) diff --git a/src/EnergyPlus/ChilledCeilingPanelSimple.cc b/src/EnergyPlus/ChilledCeilingPanelSimple.cc index 36d6193fe23..f345ef5e3b4 100644 --- a/src/EnergyPlus/ChilledCeilingPanelSimple.cc +++ b/src/EnergyPlus/ChilledCeilingPanelSimple.cc @@ -1726,7 +1726,7 @@ namespace CoolingPanelSimple { if (ThisSurf.Class == DataSurfaces::SurfaceClass::Window) { - if (IS_INT_SHADED(SurfWinShadingFlag(SurfNum))) { + if (ANY_INTERIOR_SHADE_BLIND(SurfWinShadingFlag(SurfNum))) { // The area is the shade or blind area = the sum of the glazing area and the divider area (which is zero if no divider) Area += DataSurfaces::SurfWinDividerArea(SurfNum); } @@ -1736,7 +1736,7 @@ namespace CoolingPanelSimple { SumHATsurf += HConvIn(SurfNum) * SurfWinFrameArea(SurfNum) * (1.0 + SurfWinProjCorrFrIn(SurfNum)) * SurfWinFrameTempSurfIn(SurfNum); } - if (SurfWinDividerArea(SurfNum) > 0.0 && !IS_INT_SHADED(SurfWinShadingFlag(SurfNum))) { + if (SurfWinDividerArea(SurfNum) > 0.0 && !ANY_INTERIOR_SHADE_BLIND(SurfWinShadingFlag(SurfNum))) { // Window divider contribution (only from shade or blind for window with divider and interior shade or blind) SumHATsurf += HConvIn(SurfNum) * SurfWinDividerArea(SurfNum) * (1.0 + 2.0 * SurfWinProjCorrDivIn(SurfNum)) * SurfWinDividerTempSurfIn(SurfNum); diff --git a/src/EnergyPlus/DataSurfaces.cc b/src/EnergyPlus/DataSurfaces.cc index f3fe27023b9..4d25b38b8b4 100644 --- a/src/EnergyPlus/DataSurfaces.cc +++ b/src/EnergyPlus/DataSurfaces.cc @@ -558,6 +558,9 @@ namespace DataSurfaces { bool AnyHeatBalanceInsideSourceTerm(false); // True if any SurfaceProperty:HeatBalanceSourceTerm inside face used bool AnyHeatBalanceOutsideSourceTerm(false); // True if any SurfaceProperty:HeatBalanceSourceTerm outside face used + // String to item maps. + std::map WindowShadingControlTypeToStr; + // SUBROUTINE SPECIFICATIONS FOR MODULE DataSurfaces: // Object Data diff --git a/src/EnergyPlus/DataSurfaces.hh b/src/EnergyPlus/DataSurfaces.hh index 774013ee033..f1b088a0bd1 100644 --- a/src/EnergyPlus/DataSurfaces.hh +++ b/src/EnergyPlus/DataSurfaces.hh @@ -70,12 +70,12 @@ #define BITF_TEST_ANY(V, B) (((V) & (B)) != 0) #define IS_SHADED(SHADE_FLAG) !BITF_TEST_ANY(BITF(SHADE_FLAG), BITF(WinShadingType::NoShade) | BITF(WinShadingType::ShadeOff)) -#define IS_SHADE_ON(SHADE_FLAG) BITF_TEST_ANY(BITF(SHADE_FLAG), BITF(WinShadingType::IntShade) | BITF(WinShadingType::ExtShade) | BITF(WinShadingType::BGShade)) -#define IS_SHADE_SCREEN_ON(SHADE_FLAG) BITF_TEST_ANY(BITF(SHADE_FLAG), BITF(WinShadingType::IntShade) | BITF(WinShadingType::ExtShade) | BITF(WinShadingType::BGShade) | BITF(WinShadingType::ExtScreen)) -#define IS_BLIND_ON(SHADE_FLAG) BITF_TEST_ANY(BITF(SHADE_FLAG), BITF(WinShadingType::IntBlind) | BITF(WinShadingType::ExtBlind) | BITF(WinShadingType::BGBlind)) -#define IS_INT_SHADED(SHADE_FLAG) BITF_TEST_ANY(BITF(SHADE_FLAG), BITF(WinShadingType::IntShade) | BITF(WinShadingType::IntBlind)) -#define IS_EXT_SHADED(SHADE_FLAG) BITF_TEST_ANY(BITF(SHADE_FLAG), BITF(WinShadingType::ExtShade) | BITF(WinShadingType::ExtBlind) | BITF(WinShadingType::ExtScreen)) -#define IS_BG_SHADED(SHADE_FLAG) BITF_TEST_ANY(BITF(SHADE_FLAG), BITF(WinShadingType::BGShade) | BITF(WinShadingType::BGBlind)) +#define ANY_SHADE(SHADE_FLAG) BITF_TEST_ANY(BITF(SHADE_FLAG), BITF(WinShadingType::IntShade) | BITF(WinShadingType::ExtShade) | BITF(WinShadingType::BGShade)) +#define ANY_SHADE_SCREEN(SHADE_FLAG) BITF_TEST_ANY(BITF(SHADE_FLAG), BITF(WinShadingType::IntShade) | BITF(WinShadingType::ExtShade) | BITF(WinShadingType::BGShade) | BITF(WinShadingType::ExtScreen)) +#define ANY_BLIND(SHADE_FLAG) BITF_TEST_ANY(BITF(SHADE_FLAG), BITF(WinShadingType::IntBlind) | BITF(WinShadingType::ExtBlind) | BITF(WinShadingType::BGBlind)) +#define ANY_INTERIOR_SHADE_BLIND(SHADE_FLAG) BITF_TEST_ANY(BITF(SHADE_FLAG), BITF(WinShadingType::IntShade) | BITF(WinShadingType::IntBlind)) +#define ANY_EXTERIOR_SHADE_BLIND_SCREEN(SHADE_FLAG) BITF_TEST_ANY(BITF(SHADE_FLAG), BITF(WinShadingType::ExtShade) | BITF(WinShadingType::ExtBlind) | BITF(WinShadingType::ExtScreen)) +#define ANY_BETWEENGLASS_SHADE_BLIND(SHADE_FLAG) BITF_TEST_ANY(BITF(SHADE_FLAG), BITF(WinShadingType::BGShade) | BITF(WinShadingType::BGBlind)) namespace EnergyPlus { @@ -172,6 +172,7 @@ namespace DataSurfaces { OnHiZoneTemp_HiHorzSolar = 21 }; + extern std::map WindowShadingControlTypeToStr; // Parameters to indicate exterior boundary conditions for use with // the Surface derived type (see below): diff --git a/src/EnergyPlus/DaylightingManager.cc b/src/EnergyPlus/DaylightingManager.cc index 5873bf7f284..4c5dc6bed0b 100644 --- a/src/EnergyPlus/DaylightingManager.cc +++ b/src/EnergyPlus/DaylightingManager.cc @@ -3675,7 +3675,7 @@ namespace EnergyPlus::DaylightingManager { state.dataDaylightingManager->EDIRSUdisk(iHour, 1) = RAYCOS(3) * TVISS * ObTransDisk; // Bare window TransBmBmMult = 0.0; - if (IS_BLIND_ON(ShType)) { + if (ANY_BLIND(ShType)) { ProfileAngle(IWin, RAYCOS, Blind(BlNum).SlatOrientation, ProfAng); // Contribution of beam passing through slats and reaching reference point for (JB = 1; JB <= MaxSlatAngs; ++JB) { @@ -3729,7 +3729,7 @@ namespace EnergyPlus::DaylightingManager { XAVWL = 14700.0 * std::sqrt(0.000068 * POSFAC) * double(NWX * NWY) / std::pow(WindowSolidAngleDaylightPoint, 0.8); state.dataDaylightingManager->AVWLSUdisk(iHour, 1) = XAVWL * TVISS * ObTransDisk; // Bare window - if (IS_BLIND_ON(ShType)) { + if (ANY_BLIND(ShType)) { for (JB = 1; JB <= MaxSlatAngs; ++JB) { // IF (.NOT. SurfaceWindow(IWin)%MovableSlats .AND. JB > 1) EXIT state.dataDaylightingManager->AVWLSUdisk(iHour, JB + 1) = XAVWL * TVISS * TransBmBmMult(JB) * ObTransDisk; @@ -3842,7 +3842,7 @@ namespace EnergyPlus::DaylightingManager { state.dataDaylightingManager->EDIRSUdisk(iHour, 1) += SunVecMir(3) * SpecReflectance * TVisRefl; // Bare window TransBmBmMultRefl = 0.0; - if (IS_BLIND_ON(ShType)) { + if (ANY_BLIND(ShType)) { ProfileAngle(IWin, SunVecMir, Blind(BlNum).SlatOrientation, ProfAng); // Contribution of reflected beam passing through slats and reaching reference point Real64 const Pi_SlatAng_fac(DataGlobalConstants::Pi / (MaxSlatAngs - 1)); @@ -3879,7 +3879,7 @@ namespace EnergyPlus::DaylightingManager { XAVWL = 14700.0 * std::sqrt(0.000068 * POSFAC) * double(NWX * NWY) / std::pow(SurfaceWindow(IWin).SolidAngAtRefPtWtd(iRefPoint), 0.8); state.dataDaylightingManager->AVWLSUdisk(iHour, 1) += XAVWL * TVisRefl * SpecReflectance; // Bare window - if (IS_BLIND_ON(ShType)) { + if (ANY_BLIND(ShType)) { for (JB = 1; JB <= MaxSlatAngs; ++JB) { // IF(.NOT. SurfaceWindow(IWin)%MovableSlats .AND. JB > 1) EXIT state.dataDaylightingManager->AVWLSUdisk(iHour, JB + 1) += XAVWL * TVisRefl * SpecReflectance * TransBmBmMultRefl(JB); @@ -3898,7 +3898,7 @@ namespace EnergyPlus::DaylightingManager { } // Last pass - if ((ICtrl > 0 && (IS_BLIND_ON(ShType) || IS_SHADE_SCREEN_ON(ShType))) || SurfWinSolarDiffusing(IWin)) { + if ((ICtrl > 0 && (ANY_BLIND(ShType) || ANY_SHADE_SCREEN(ShType))) || SurfWinSolarDiffusing(IWin)) { // ----- CASE II -- WINDOW WITH SCREEN, SHADE, BLIND, OR DIFFUSING WINDOW @@ -7936,8 +7936,8 @@ namespace EnergyPlus::DaylightingManager { BlNum = SurfWinBlindNumber(IWin); // ScNum = SurfaceWindow( IWin ).ScreenNumber; //Unused Set but never used - ShadeOn = IS_SHADE_ON(ShType); - BlindOn = IS_BLIND_ON(ShType); + ShadeOn = ANY_SHADE(ShType); + BlindOn = ANY_BLIND(ShType); ScreenOn = (ShType == WinShadingType::ExtScreen); } diff --git a/src/EnergyPlus/ElectricBaseboardRadiator.cc b/src/EnergyPlus/ElectricBaseboardRadiator.cc index 57af2828119..2de4e2f7e6a 100644 --- a/src/EnergyPlus/ElectricBaseboardRadiator.cc +++ b/src/EnergyPlus/ElectricBaseboardRadiator.cc @@ -1147,7 +1147,7 @@ namespace ElectricBaseboardRadiator { Area = Surface(SurfNum).Area; if (Surface(SurfNum).Class == SurfaceClass::Window) { - if (IS_INT_SHADED(SurfWinShadingFlag(SurfNum))) { + if (ANY_INTERIOR_SHADE_BLIND(SurfWinShadingFlag(SurfNum))) { // The area is the shade or blind area = the sum of the glazing area and the divider area (which is zero if no divider) Area += SurfWinDividerArea(SurfNum); } @@ -1158,7 +1158,7 @@ namespace ElectricBaseboardRadiator { SurfWinFrameTempSurfIn(SurfNum); } - if (SurfWinDividerArea(SurfNum) > 0.0 && !IS_INT_SHADED(SurfWinShadingFlag(SurfNum))) { + if (SurfWinDividerArea(SurfNum) > 0.0 && !ANY_INTERIOR_SHADE_BLIND(SurfWinShadingFlag(SurfNum))) { // Window divider contribution (only from shade or blind for window with divider and interior shade or blind) SumHATsurf += HConvIn(SurfNum) * SurfWinDividerArea(SurfNum) * (1.0 + 2.0 * SurfWinProjCorrDivIn(SurfNum)) * SurfWinDividerTempSurfIn(SurfNum); diff --git a/src/EnergyPlus/HWBaseboardRadiator.cc b/src/EnergyPlus/HWBaseboardRadiator.cc index 222fe17c5c0..edecad62d76 100644 --- a/src/EnergyPlus/HWBaseboardRadiator.cc +++ b/src/EnergyPlus/HWBaseboardRadiator.cc @@ -1735,7 +1735,7 @@ namespace HWBaseboardRadiator { Area = Surface(SurfNum).Area; if (Surface(SurfNum).Class == SurfaceClass::Window) { - if (IS_INT_SHADED(SurfWinShadingFlag(SurfNum))) { + if (ANY_INTERIOR_SHADE_BLIND(SurfWinShadingFlag(SurfNum))) { // The area is the shade or blind area = the sum of the glazing area and the divider area (which is zero if no divider) Area += SurfWinDividerArea(SurfNum); } @@ -1746,7 +1746,7 @@ namespace HWBaseboardRadiator { SurfWinFrameTempSurfIn(SurfNum); } - if (SurfWinDividerArea(SurfNum) > 0.0 && !IS_INT_SHADED(SurfWinShadingFlag(SurfNum))) { + if (SurfWinDividerArea(SurfNum) > 0.0 && !ANY_INTERIOR_SHADE_BLIND(SurfWinShadingFlag(SurfNum))) { // Window divider contribution (only from shade or blind for window with divider and interior shade or blind) SumHATsurf += HConvIn(SurfNum) * SurfWinDividerArea(SurfNum) * (1.0 + 2.0 * SurfWinProjCorrDivIn(SurfNum)) * SurfWinDividerTempSurfIn(SurfNum); diff --git a/src/EnergyPlus/HeatBalanceIntRadExchange.cc b/src/EnergyPlus/HeatBalanceIntRadExchange.cc index 89116f222a0..4b93c6396f3 100644 --- a/src/EnergyPlus/HeatBalanceIntRadExchange.cc +++ b/src/EnergyPlus/HeatBalanceIntRadExchange.cc @@ -271,7 +271,7 @@ namespace HeatBalanceIntRadExchange { if (state.dataConstruction->Construct(Surface(SurfNum).Construction).TypeIsWindow) { ShadeFlag = SurfWinShadingFlag(SurfNum); ShadeFlagPrev = SurfWinExtIntShadePrevTS(SurfNum); - if (ShadeFlagPrev != ShadeFlag && (IS_INT_SHADED(ShadeFlagPrev) || IS_INT_SHADED(ShadeFlag))) + if (ShadeFlagPrev != ShadeFlag && (ANY_INTERIOR_SHADE_BLIND(ShadeFlagPrev) || ANY_INTERIOR_SHADE_BLIND(ShadeFlag))) IntShadeOrBlindStatusChanged = true; if (SurfWinWindowModelType(SurfNum) == WindowEQLModel && DataWindowEquivalentLayer::CFS(state.dataConstruction->Construct(Surface(SurfNum).Construction).EQLConsPtr).ISControlled) { @@ -289,7 +289,7 @@ namespace HeatBalanceIntRadExchange { int const ConstrNum = Surface(SurfNum).Construction; zone_info.Emissivity(ZoneSurfNum) = state.dataConstruction->Construct(ConstrNum).InsideAbsorpThermal; auto const &surface_window(SurfaceWindow(SurfNum)); - if (state.dataConstruction->Construct(ConstrNum).TypeIsWindow && IS_INT_SHADED(SurfWinShadingFlag(SurfNum))) { + if (state.dataConstruction->Construct(ConstrNum).TypeIsWindow && ANY_INTERIOR_SHADE_BLIND(SurfWinShadingFlag(SurfNum))) { zone_info.Emissivity(ZoneSurfNum) = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), surface_window.EffShBlindEmiss) + InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), surface_window.EffGlassEmiss); @@ -343,7 +343,7 @@ namespace HeatBalanceIntRadExchange { SurfaceEmiss[ZoneSurfNum] = construct.InsideAbsorpThermal; // For windows with an interior shade or blind an effective inside surface temp // and emiss is used here that is a weighted combination of shade/blind and glass temp and emiss. - } else if (IS_INT_SHADED(SurfWinShadingFlag(SurfNum))) { + } else if (ANY_INTERIOR_SHADE_BLIND(SurfWinShadingFlag(SurfNum))) { SurfaceTempRad[ZoneSurfNum] = SurfWinEffInsSurfTemp(SurfNum); SurfaceEmiss[ZoneSurfNum] = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), surface_window.EffShBlindEmiss) + InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), surface_window.EffGlassEmiss); diff --git a/src/EnergyPlus/HeatBalanceSurfaceManager.cc b/src/EnergyPlus/HeatBalanceSurfaceManager.cc index 8d55d74941a..cebebc5ddb5 100644 --- a/src/EnergyPlus/HeatBalanceSurfaceManager.cc +++ b/src/EnergyPlus/HeatBalanceSurfaceManager.cc @@ -1048,76 +1048,22 @@ namespace HeatBalanceSurfaceManager { // shading if (Surface(iSurf).HasShadeControl) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchFenSwitchable, surfName, "Yes"); - // shading report PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscName, surfName, WindowShadingControl(curWSC).Name); - { - auto const SELECT_CASE_var1(WindowShadingControl(curWSC).ShadingType); - if (SELECT_CASE_var1 == WinShadingType::NoShade) { - PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscShading, surfName, "No Shade"); - } else if (SELECT_CASE_var1 == WinShadingType::IntShade) { - PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscShading, surfName, "Interior Shade"); - } else if (SELECT_CASE_var1 == WinShadingType::SwitchableGlazing) { - PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscShading, surfName, "Switchable Glazing"); - } else if (SELECT_CASE_var1 == WinShadingType::ExtShade) { - PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscShading, surfName, "Exterior Shade"); - } else if (SELECT_CASE_var1 == WinShadingType::IntBlind) { - PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscShading, surfName, "Interior Blind"); - } else if (SELECT_CASE_var1 == WinShadingType::ExtBlind) { - PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscShading, surfName, "Exterior Blind"); - } else if (SELECT_CASE_var1 == WinShadingType::BGShade) { - PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscShading, surfName, "Between Glass Shade"); - } else if (SELECT_CASE_var1 == WinShadingType::BGBlind) { - PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscShading, surfName, "Between Glass Blind"); - } else if (SELECT_CASE_var1 == WinShadingType::ExtScreen) { - PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscShading, surfName, "Exterior Screen"); - } - } - { - auto const SELECT_CASE_var1(WindowShadingControl(curWSC).ShadingControlType); - if (SELECT_CASE_var1 == WindowShadingControlType::AlwaysOn) { - PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "AlwaysOn"); - } else if (SELECT_CASE_var1 == WindowShadingControlType::AlwaysOff) { - PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "AlwaysOff"); - } else if (SELECT_CASE_var1 == WindowShadingControlType::OnIfScheduled) { - PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OnIfScheduleAllows"); - } else if (SELECT_CASE_var1 == WindowShadingControlType::HiSolar) { - PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OnIfHighSolarOnWindow"); - } else if (SELECT_CASE_var1 == WindowShadingControlType::HiHorzSolar) { - PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OnIfHighHorizontalSolar"); - } else if (SELECT_CASE_var1 == WindowShadingControlType::HiOutAirTemp) { - PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OnIfHighOutdoorAirTemperature"); - } else if (SELECT_CASE_var1 == WindowShadingControlType::HiZoneAirTemp) { - PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OnIfHighZoneAirTemperature"); - } else if (SELECT_CASE_var1 == WindowShadingControlType::HiZoneCooling) { - PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OnIfHighZoneCooling"); - } else if (SELECT_CASE_var1 == WindowShadingControlType::HiGlare) { - PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OnIfHighGlare"); - } else if (SELECT_CASE_var1 == WindowShadingControlType::MeetDaylIlumSetp) { - PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "MeetDaylightIlluminanceSetpoint"); - } else if (SELECT_CASE_var1 == WindowShadingControlType::OnNightLoOutTemp_OffDay) { - PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OnNightIfLowOutdoorTempAndOffDay"); - } else if (SELECT_CASE_var1 == WindowShadingControlType::OnNightLoInTemp_OffDay) { - PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OnNightIfLowInsideTempAndOffDay"); - } else if (SELECT_CASE_var1 == WindowShadingControlType::OnNightIfHeating_OffDay) { - PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OnNightIfHeatingAndOffDay"); - } else if (SELECT_CASE_var1 == WindowShadingControlType::OnNightLoOutTemp_OnDayCooling) { - PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OnNightIfLowOutdoorTempAndOnDayIfCooling"); - } else if (SELECT_CASE_var1 == WindowShadingControlType::OnNightIfHeating_OnDayCooling) { - PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OnNightIfHeatingAndOnDayIfCooling"); - } else if (SELECT_CASE_var1 == WindowShadingControlType::OffNight_OnDay_HiSolarWindow) { - PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OffNightAndOnDayIfCoolingAndHighSolarOnWindow"); - } else if (SELECT_CASE_var1 == WindowShadingControlType::OnNight_OnDay_HiSolarWindow) { - PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OnNightAndOnDayIfCoolingAndHighSolarOnWindow"); - } else if (SELECT_CASE_var1 == WindowShadingControlType::OnHiOutTemp_HiSolarWindow) { - PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OnIfHighOutdoorAirTempAndHighSolarOnWindow"); - } else if (SELECT_CASE_var1 == WindowShadingControlType::OnHiOutTemp_HiHorzSolar) { - PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OnIfHighOutdoorAirTempAndHighHorizontalSolar"); - } else if (SELECT_CASE_var1 == WindowShadingControlType::OnHiZoneTemp_HiSolarWindow) { - PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OnIfHighZoneAirTempAndHighSolarOnWindow"); - } else if (SELECT_CASE_var1 == WindowShadingControlType::OnHiZoneTemp_HiHorzSolar) { - PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, "OnIfHighZoneAirTempAndHighHorizontalSolar"); - } - } + // shading report + std::map WindowShadingTypeToStr = { + {WinShadingType::IntShade, "No Shade"}, + {WinShadingType::IntShade, "Interior Shade"}, + {WinShadingType::ExtShade, "Exterior Shade"}, + {WinShadingType::ExtScreen, "Exterior Screen"}, + {WinShadingType::IntBlind, "Interior Blind"}, + {WinShadingType::ExtBlind, "Exterior Blind"}, + {WinShadingType::BGShade, "Between Glass Shade"}, + {WinShadingType::BGBlind, "Between Glass Blind"}, + {WinShadingType::SwitchableGlazing, "Switchable Glazing"} + }; + PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscShading, surfName, WindowShadingTypeToStr[WindowShadingControl(curWSC).ShadingType]); + PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, + DataSurfaces::WindowShadingControlTypeToStr[WindowShadingControl(curWSC).ShadingControlType]); // output list of all possible shading contructions for shaded windows including those with storms std::string names = ""; @@ -2889,14 +2835,14 @@ namespace HeatBalanceSurfaceManager { int ConstrNumSh = Surface(SurfNum).activeShadedConstruction; // Shaded window construction if (SurfWinStormWinFlag(SurfNum) == 1) ConstrNumSh = Surface(SurfNum).activeStormWinShadedConstruction; - if (IS_SHADE_SCREEN_ON(ShadeFlag)) { // Shade/screen on + if (ANY_SHADE_SCREEN(ShadeFlag)) { // Shade/screen on for (int Lay = 1; Lay <= TotGlassLay; ++Lay) { AbsDiffWin(Lay) = state.dataConstruction->Construct(ConstrNumSh).AbsDiff(Lay); } SurfWinExtDiffAbsByShade(SurfNum) = state.dataConstruction->Construct(ConstrNumSh).AbsDiffShade * (SkySolarInc + GndSolarInc); - } else if (IS_BLIND_ON(ShadeFlag)) { // Blind on + } else if (ANY_BLIND(ShadeFlag)) { // Blind on for (int Lay = 1; Lay <= TotGlassLay; ++Lay) { AbsDiffWin(Lay) = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), @@ -2936,7 +2882,7 @@ namespace HeatBalanceSurfaceManager { // Correct for shadowing of divider onto interior shading device (note that dividers are // not allowed in windows with between-glass shade/blind) - if (IS_INT_SHADED(ShadeFlag) && SurfWinDividerArea(SurfNum) > 0.0) + if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag) && SurfWinDividerArea(SurfNum) > 0.0) SurfWinExtDiffAbsByShade(SurfNum) *= SurfWinGlazedFrac(SurfNum); if (ShadeFlag == WinShadingType::SwitchableGlazing) { // Switchable glazing @@ -2953,7 +2899,7 @@ namespace HeatBalanceSurfaceManager { SurfWinQRadSWwinAbs(Lay, SurfNum) = AbsDiffWin(Lay) * (SkySolarInc + GndSolarInc) + SurfWinA(Lay, SurfNum) * BeamSolar; // SurfWinA is from InteriorSolarDistribution - if (IS_BLIND_ON(ShadeFlag)) { + if (ANY_BLIND(ShadeFlag)) { int ConstrNumSh = Surface(SurfNum).activeShadedConstruction; if (Blind(SurfWinBlindNumber(SurfNum)).SlatOrientation == Horizontal) { // AbsDiffGlassLayGnd - System glass layer ground diffuse solar absorptance with blind on @@ -3228,7 +3174,7 @@ namespace HeatBalanceSurfaceManager { Real64 BeamDivHorFaceInc = 0.0; // Beam solar on divider's horizontal outside projection faces (W/m2) Real64 BeamDivVertFaceInc = 0.0; // Beam solar on divider's vertical outside projection faces (W/m2) // Beam incident on horizontal and vertical projection faces of divider if no exterior shading - if (DivProjOut > 0.0 && !IS_EXT_SHADED(ShadeFlag)) { + if (DivProjOut > 0.0 && !ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) { BeamDivHorFaceInc = state.dataEnvrn->BeamSolarRad * CosIncAngHorProj * FrameDivider(FrDivNum).HorDividers * DivProjOut * (Surface(SurfNum).Width - @@ -3244,7 +3190,7 @@ namespace HeatBalanceSurfaceManager { Real64 DivIncSolarOutDif = 0.0; // Diffuse solar incident on outside of divider including diffuse on divider projection (W/m2) Real64 DivIncSolarInBm = 0.0; // Diffuse solar incident on inside of divider including beam on divider projection (W/m2) Real64 DivIncSolarInDif = 0.0; // Diffuse solar incident on inside of divider including diffuse on divider projection (W/m2) - if (!IS_EXT_SHADED(ShadeFlag) && !IS_BG_SHADED(ShadeFlag)) { // No exterior or between-glass shading + if (!ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag) && !ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag)) { // No exterior or between-glass shading DivIncSolarOutBm = BeamFaceInc + BeamDivHorFaceInc + BeamDivVertFaceInc; DivIncSolarOutDif = DifSolarFaceInc * (1.0 + SurfWinProjCorrDivOut(SurfNum)); @@ -3297,7 +3243,7 @@ namespace HeatBalanceSurfaceManager { DivIncSolarInDif = DifSolarFaceInc * SurfWinProjCorrDivIn(SurfNum) * state.dataConstruction->Construct(ConstrNum).TransDiff; } - if (!IS_EXT_SHADED(ShadeFlag) && !IS_BG_SHADED(ShadeFlag)) { + if (!ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag) && !ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag)) { // No exterior or between-glass shade, screen or blind SurfWinDividerQRadOutAbs(SurfNum) = DividerAbs * (DivIncSolarOutBm + DivIncSolarOutDif); @@ -3576,7 +3522,7 @@ namespace HeatBalanceSurfaceManager { } else if (ConstrNumSh != 0 && ShadeFlag != WinShadingType::SwitchableGlazing) { // Interior, exterior or between-glass shade, screen or blind in place for (int IGlass = 1; IGlass <= state.dataConstruction->Construct(ConstrNumSh).TotGlassLayers; ++IGlass) { - if (IS_SHADE_SCREEN_ON(ShadeFlag)) { + if (ANY_SHADE_SCREEN(ShadeFlag)) { SurfWinQRadSWwinAbs(IGlass, SurfNum) += QS(solEnclosureNum) * state.dataConstruction->Construct(ConstrNumSh).AbsDiffBack(IGlass); } else if (BITF_TEST_ANY(BITF(ShadeFlag), BITF(WinShadingType::IntBlind) | BITF(WinShadingType::ExtBlind))) { Real64 BlAbsDiffBk = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), @@ -3591,16 +3537,16 @@ namespace HeatBalanceSurfaceManager { SurfaceWindow(SurfNum).EffShBlindEmiss); // Blind emissivity (thermal absorptance) as part of glazing system SurfWinIntLWAbsByShade(SurfNum) = QL(radEnclosureNum) * EffBlEmiss * TMULT(radEnclosureNum); } - if (IS_SHADE_SCREEN_ON(ShadeFlag)){ + if (ANY_SHADE_SCREEN(ShadeFlag)){ SurfWinIntSWAbsByShade(SurfNum) = QS(solEnclosureNum) * state.dataConstruction->Construct(ConstrNumSh).AbsDiffBackShade; - } else if (IS_BLIND_ON(ShadeFlag)) { + } else if (ANY_BLIND(ShadeFlag)) { Real64 AbsDiffBkBl = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), state.dataConstruction->Construct(ConstrNumSh).AbsDiffBackBlind); // Blind diffuse back solar absorptance as part of glazing system SurfWinIntSWAbsByShade(SurfNum) = QS(solEnclosureNum) * AbsDiffBkBl; } // Correct for divider shadowing - if (IS_EXT_SHADED(ShadeFlag)) { + if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) { SurfWinIntSWAbsByShade(SurfNum) *= SurfWinGlazedFrac(SurfNum); } @@ -3736,9 +3682,9 @@ namespace HeatBalanceSurfaceManager { for (int IGlass = 1; IGlass <= state.dataConstruction->Construct(ConstrNumSh).TotGlassLayers; ++IGlass) { SurfWinQRadSWwinAbs(IGlass, SurfNum) += SurfWinInitialDifSolwinAbs(IGlass, SurfNum); } - if (IS_SHADE_SCREEN_ON(ShadeFlag)) { + if (ANY_SHADE_SCREEN(ShadeFlag)) { SurfWinIntSWAbsByShade(SurfNum) += SurfWinInitialDifSolAbsByShade(SurfNum); - } else if (IS_BLIND_ON(ShadeFlag)) { + } else if (ANY_BLIND(ShadeFlag)) { SurfWinIntSWAbsByShade(SurfNum) += SurfWinInitialDifSolAbsByShade(SurfNum); } } // End of shading flag check @@ -3877,7 +3823,7 @@ namespace HeatBalanceSurfaceManager { for (int SurfNum = firstSurfWin; SurfNum <= lastSurfWin; ++SurfNum) { // For window with an interior shade or blind, emissivity is a combination of glass and shade/blind emissivity WinShadingType ShadeFlag = SurfWinShadingFlag(SurfNum); - if (IS_INT_SHADED(ShadeFlag)) + if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) ITABSF(SurfNum) = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), SurfaceWindow(SurfNum).EffShBlindEmiss) + InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), @@ -3911,7 +3857,7 @@ namespace HeatBalanceSurfaceManager { Real64 DividerThermAbs = SurfWinDividerEmis(SurfNum); // Window divider thermal absorptance // Suspended (between-glass) divider; relevant emissivity is inner glass emissivity if (SurfWinDividerType(SurfNum) == Suspended) DividerThermAbs = state.dataConstruction->Construct(ConstrNum).InsideAbsorpThermal; - if (IS_INT_SHADED(ShadeFlag)) { + if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) { // Interior shade or blind in place int ConstrNumSh = Surface(SurfNum).activeShadedConstruction; if (SurfWinHasShadeOrBlindLayer(SurfNum)) { @@ -4029,9 +3975,9 @@ namespace HeatBalanceSurfaceManager { // Window with shade, screen or blind if (ConstrNumSh != 0) { - if (IS_SHADE_SCREEN_ON(ShadeFlag)) { + if (ANY_SHADE_SCREEN(ShadeFlag)) { AbsDiffLayWin = state.dataConstruction->Construct(ConstrNumSh).AbsDiffBack(Lay); - } else if (IS_BLIND_ON(ShadeFlag)) { + } else if (ANY_BLIND(ShadeFlag)) { AbsDiffLayWin = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), state.dataConstruction->Construct(ConstrNumSh).BlAbsDiffBack(_, Lay)); @@ -4051,10 +3997,10 @@ namespace HeatBalanceSurfaceManager { // Window with shade, screen or blind if (ConstrNumSh != 0) { - if (IS_SHADE_SCREEN_ON(ShadeFlag)) { + if (ANY_SHADE_SCREEN(ShadeFlag)) { TransDiffWin = state.dataConstruction->Construct(ConstrNumSh).TransDiff; DiffAbsShade = state.dataConstruction->Construct(ConstrNumSh).AbsDiffBackShade; - } else if (IS_BLIND_ON(ShadeFlag)) { + } else if (ANY_BLIND(ShadeFlag)) { TransDiffWin = InterpSlatAng( SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), state.dataConstruction->Construct(ConstrNumSh).BlTransDiff); DiffAbsShade = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), @@ -4086,7 +4032,7 @@ namespace HeatBalanceSurfaceManager { Real64 DividerRefl = 1.0 - DividerAbs; // Window divider short-wave reflectance DividerAbs = AbsGl + TransGl * (DividerAbs + DividerRefl * AbsGl) / (1.0 - DividerRefl * ReflGl); } - if (IS_INT_SHADED(ShadeFlag)) { + if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) { SUM1 += SurfWinDividerArea(SurfNum) * (DividerAbs + DiffAbsShade); } else { SUM1 += SurfWinDividerArea(SurfNum) * (1.0 + SurfWinProjCorrDivIn(SurfNum)) * DividerAbs; @@ -6763,7 +6709,7 @@ namespace HeatBalanceSurfaceManager { int RoughSurf = state.dataMaterial->Material(construct.LayerPoint(1)).Roughness; // Outside surface roughness Real64 EmisOut = state.dataMaterial->Material(construct.LayerPoint(1)).AbsorpThermalFront; // Glass outside surface emissivity auto const shading_flag(SurfWinShadingFlag(SurfNum)); - if (IS_EXT_SHADED(shading_flag)) { + if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(shading_flag)) { // Exterior shade in place int ConstrNumSh = Surface(SurfNum).activeShadedConstruction; if (ConstrNumSh != 0) { @@ -7465,7 +7411,7 @@ namespace HeatBalanceSurfaceManager { Real64 EmisOut = state.dataMaterial->Material(construct.LayerPoint(1)).AbsorpThermalFront; // Glass outside surface emissivity auto const shading_flag(SurfWinShadingFlag(surfNum)); - if (IS_EXT_SHADED(shading_flag)) { + if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(shading_flag)) { // Exterior shade in place int ConstrNumSh = Surface(surfNum).activeShadedConstruction; if (ConstrNumSh != 0) { diff --git a/src/EnergyPlus/HighTempRadiantSystem.cc b/src/EnergyPlus/HighTempRadiantSystem.cc index dcd33cfdc65..f7854cc41d0 100644 --- a/src/EnergyPlus/HighTempRadiantSystem.cc +++ b/src/EnergyPlus/HighTempRadiantSystem.cc @@ -1491,7 +1491,7 @@ namespace HighTempRadiantSystem { Area = Surface(SurfNum).Area; if (Surface(SurfNum).Class == SurfaceClass::Window) { - if (IS_INT_SHADED(SurfWinShadingFlag(SurfNum))) { + if (ANY_INTERIOR_SHADE_BLIND(SurfWinShadingFlag(SurfNum))) { // The area is the shade or blind area = the sum of the glazing area and the divider area (which is zero if no divider) Area += SurfWinDividerArea(SurfNum); } @@ -1502,7 +1502,7 @@ namespace HighTempRadiantSystem { SurfWinFrameTempSurfIn(SurfNum); } - if (SurfWinDividerArea(SurfNum) > 0.0 && !IS_INT_SHADED(SurfWinShadingFlag(SurfNum))) { + if (SurfWinDividerArea(SurfNum) > 0.0 && !ANY_INTERIOR_SHADE_BLIND(SurfWinShadingFlag(SurfNum))) { // Window divider contribution (only from shade or blind for window with divider and interior shade or blind) SumHATsurf += HConvIn(SurfNum) * SurfWinDividerArea(SurfNum) * (1.0 + 2.0 * SurfWinProjCorrDivIn(SurfNum)) * SurfWinDividerTempSurfIn(SurfNum); diff --git a/src/EnergyPlus/LowTempRadiantSystem.cc b/src/EnergyPlus/LowTempRadiantSystem.cc index fec62976001..cc5a5458fb5 100644 --- a/src/EnergyPlus/LowTempRadiantSystem.cc +++ b/src/EnergyPlus/LowTempRadiantSystem.cc @@ -5570,7 +5570,7 @@ namespace LowTempRadiantSystem { Real64 Area = Surface(surfNum).Area; if (Surface(surfNum).Class == SurfaceClass::Window) { - if (IS_INT_SHADED(SurfWinShadingFlag(surfNum))) { + if (ANY_INTERIOR_SHADE_BLIND(SurfWinShadingFlag(surfNum))) { // The area is the shade or blind are = sum of the glazing area and the divider area (which is zero if no divider) Area += SurfWinDividerArea(surfNum); } @@ -5581,7 +5581,7 @@ namespace LowTempRadiantSystem { SurfWinFrameTempSurfIn(surfNum); } - if (SurfWinDividerArea(surfNum) > 0.0 && !IS_INT_SHADED(SurfWinShadingFlag(surfNum))) { + if (SurfWinDividerArea(surfNum) > 0.0 && !ANY_INTERIOR_SHADE_BLIND(SurfWinShadingFlag(surfNum))) { // Window divider contribution (only from shade or blind for window with divider and interior shade or blind) sumHATsurf += HConvIn(surfNum) * SurfWinDividerArea(surfNum) * (1.0 + 2.0 * SurfWinProjCorrDivIn(surfNum)) * SurfWinDividerTempSurfIn(surfNum); diff --git a/src/EnergyPlus/RoomAirModelAirflowNetwork.cc b/src/EnergyPlus/RoomAirModelAirflowNetwork.cc index 0f67b0fdab2..31dd7bbf8a4 100644 --- a/src/EnergyPlus/RoomAirModelAirflowNetwork.cc +++ b/src/EnergyPlus/RoomAirModelAirflowNetwork.cc @@ -1051,14 +1051,14 @@ namespace RoomAirModelAirflowNetwork { if (Surface(SurfNum).Class == DataSurfaces::SurfaceClass::Window) { // Add to the convective internal gains - if (IS_INT_SHADED(SurfWinShadingFlag(SurfNum))) { + if (ANY_INTERIOR_SHADE_BLIND(SurfWinShadingFlag(SurfNum))) { // The shade area covers the area of the glazing plus the area of the dividers. Area += SurfWinDividerArea(SurfNum); SumIntGain += SurfWinDividerHeatGain(SurfNum); } // Convective heat gain from natural convection in gap between glass and interior shade or blind - if (IS_INT_SHADED(SurfWinShadingFlag(SurfNum))) + if (ANY_INTERIOR_SHADE_BLIND(SurfWinShadingFlag(SurfNum))) SumIntGain += SurfWinConvHeatFlowNatural(SurfNum); // Convective heat gain from airflow window @@ -1088,7 +1088,7 @@ namespace RoomAirModelAirflowNetwork { HA += HConvIn(SurfNum) * SurfWinFrameArea(SurfNum) * (1.0 + SurfWinProjCorrFrIn(SurfNum)); } - if (SurfWinDividerArea(SurfNum) > 0.0 && !IS_INT_SHADED(SurfWinShadingFlag(SurfNum))) { + if (SurfWinDividerArea(SurfNum) > 0.0 && !ANY_INTERIOR_SHADE_BLIND(SurfWinShadingFlag(SurfNum))) { // Window divider contribution(only from shade or blind for window with divider and interior shade or blind) SumHATsurf += HConvIn(SurfNum) * SurfWinDividerArea(SurfNum) * (1.0 + 2.0 * SurfWinProjCorrDivIn(SurfNum)) * SurfWinDividerTempSurfIn(SurfNum); diff --git a/src/EnergyPlus/SolarShading.cc b/src/EnergyPlus/SolarShading.cc index 1c2c4581eb7..f467d8311ba 100644 --- a/src/EnergyPlus/SolarShading.cc +++ b/src/EnergyPlus/SolarShading.cc @@ -6124,9 +6124,9 @@ namespace SolarShading { Real64 InOutProjSLFracMult = SurfaceWindow(SurfNum).InOutProjSLFracMult(state.dataGlobal->HourOfDay); Array1D AbWinSh(NGlass); // Like AbWin, but for shaded window Array1D ADiffWinSh(NGlass); // Diffuse solar absorptance of glass layer, window with shading device - if (IS_EXT_SHADED(ShadeFlag)) FracSunLit = SunLitFract; + if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) FracSunLit = SunLitFract; - if (IS_SHADE_ON(ShadeFlag) || ShadeFlag == WinShadingType::SwitchableGlazing) { + if (ANY_SHADE(ShadeFlag) || ShadeFlag == WinShadingType::SwitchableGlazing) { // Shade or switchable glazing on for (int Lay = 1; Lay <= NGlass; ++Lay) { AbWinSh(Lay) = POLYF(CosInc, state.dataConstruction->Construct(ConstrNumSh).AbsBeamCoef({1, 6}, Lay)) * CosInc * FracSunLit; @@ -6286,7 +6286,7 @@ namespace SolarShading { for (int Lay = 1; Lay <= NGlass; ++Lay) { SurfWinA(Lay, SurfNum) = AbWinSh(Lay); // Add contribution of diffuse from beam on outside reveal - if (IS_INT_SHADED(ShadeFlag) || IS_BG_SHADED(ShadeFlag)) + if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag) || ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag)) SurfWinA(Lay, SurfNum) += ADiffWinSh(Lay) * SurfWinOutsRevealDiffOntoGlazing(SurfNum); } } else { @@ -6404,7 +6404,7 @@ namespace SolarShading { if (IS_SHADED(SurfWinShadingFlag(SurfNum)) && !SurfWinGlareControlIsActive(SurfNum)) { if (ShadeFlag != WinShadingType::SwitchableGlazing) { // Shade or blind - if (IS_SHADE_SCREEN_ON(ShadeFlag)) { + if (ANY_SHADE_SCREEN(ShadeFlag)) { // Shade or screen DiffTrans = state.dataConstruction->Construct(ConstrNumSh).TransDiff; } else { @@ -6492,7 +6492,7 @@ namespace SolarShading { if (IS_SHADED(ShadeFlag) && !SurfWinGlareControlIsActive(SurfNum)) { if (ShadeFlag != WinShadingType::SwitchableGlazing) { // Shade or blind - if (IS_SHADE_SCREEN_ON(ShadeFlag)) { + if (ANY_SHADE_SCREEN(ShadeFlag)) { // Shade or screen DiffTrans = state.dataConstruction->Construct(ConstrNumSh).TransDiff; } else { @@ -6546,7 +6546,7 @@ namespace SolarShading { if (SurfWinWindowModelType(SurfNum) != WindowEQLModel) { SurfWinBlGlSysTsolDifDif(SurfNum) = DiffTrans; SurfWinScGlSysTsolDifDif(SurfNum) = DiffTrans; - if (IS_BLIND_ON(ShadeFlag)|| ShadeFlag == WinShadingType::ExtScreen) { + if (ANY_BLIND(ShadeFlag)|| ShadeFlag == WinShadingType::ExtScreen) { SurfWinBlGlSysTsolDifDif(SurfNum) = DiffTrans; SurfWinScGlSysTsolDifDif(SurfNum) = DiffTrans; if (ShadeFlag == WinShadingType::ExtScreen) { @@ -6565,7 +6565,7 @@ namespace SolarShading { if (IS_SHADED(ShadeFlag) && !SurfWinGlareControlIsActive(SurfNum)) { // Shade or screen or blind on, or switchable glazing // (note in the following that diffusing glass is not allowed in a window with shade, blind or switchable glazing) - if (IS_SHADE_ON(ShadeFlag) || ShadeFlag == WinShadingType::SwitchableGlazing) { + if (ANY_SHADE(ShadeFlag) || ShadeFlag == WinShadingType::SwitchableGlazing) { // Shade on or switchable glazing TBmAllShBlSc = POLYF(CosInc, state.dataConstruction->Construct(ConstrNumSh).TransSolBeamCoef); } else { @@ -6689,7 +6689,7 @@ namespace SolarShading { Real64 InOutProjSLFracMult = SurfaceWindow(SurfNum).InOutProjSLFracMult(state.dataGlobal->HourOfDay); if (SurfWinWindowModelType(SurfNum) != WindowEQLModel) { WinTransDifSolar(SurfNum) = DiffTrans * Surface(SurfNum).Area; - if (IS_BLIND_ON(ShadeFlag)) { + if (ANY_BLIND(ShadeFlag)) { if (Blind(SurfWinBlindNumber(SurfNum)).SlatOrientation == Horizontal) { WinTransDifSolarGnd(SurfNum) = DiffTransGnd * Surface(SurfNum).Area; WinTransDifSolarSky(SurfNum) = DiffTransSky * Surface(SurfNum).Area; @@ -6743,7 +6743,7 @@ namespace SolarShading { // Window is schedule surface gained. Do not make addition to what enters into zone since that information is not available if (FenSolAbsPtr == 0) { Real64 TBmAll; // Window beam-to-(beam+diffuse) transmittance - if (SurfWinWindowModelType(SurfNum) != WindowBSDFModel && (IS_BLIND_ON(ShadeFlag) || IS_SHADE_SCREEN_ON(ShadeFlag))) { + if (SurfWinWindowModelType(SurfNum) != WindowBSDFModel && (ANY_BLIND(ShadeFlag) || ANY_SHADE_SCREEN(ShadeFlag))) { TBmAll = TBmAllShBlSc; } else { TBmAll = TBmBm + TBmDif; @@ -6787,7 +6787,7 @@ namespace SolarShading { if (SunLitFract > 0.0) { if (SurfWinWindowModelType(SurfNum) != WindowBSDFModel) - if (IS_SHADE_ON(ShadeFlag) || SurfWinSolarDiffusing(SurfNum) || + if (ANY_SHADE(ShadeFlag) || SurfWinSolarDiffusing(SurfNum) || SurfWinOriginalClass(SurfNum) == SurfaceClass::TDD_Diffuser || Surface(SurfNum).Class == SurfaceClass::TDD_Dome) continue; @@ -6810,7 +6810,7 @@ namespace SolarShading { if (ShelfNum > 0) { // Daylighting shelf InShelfSurf = state.dataDaylightingDevicesData->Shelf(ShelfNum).InSurf; } - if (IS_BLIND_ON(ShadeFlag)) { + if (ANY_BLIND(ShadeFlag)) { TBm = TBmBmBl; // Interior, exterior or between-glass blind on } else if (ShadeFlag == WinShadingType::ExtScreen) { TBm = TBmBmSc; // Exterior screen on @@ -6909,7 +6909,7 @@ namespace SolarShading { // Interior beam absorptance of glass layers and beam transmittance // of back exterior window with SHADE - if (IS_SHADE_ON(ShadeFlagBack)) { + if (ANY_SHADE(ShadeFlagBack)) { for (int Lay = 1; Lay <= state.dataConstruction->Construct(ConstrNumBackSh).TotGlassLayers; ++Lay) { AbsBeamWin(Lay) = POLYF(CosIncBack, state.dataConstruction->Construct(ConstrNumBackSh).AbsBeamBackCoef({1, 6}, Lay)); } @@ -6956,7 +6956,7 @@ namespace SolarShading { // Interior beam absorptance of glass layers and beam absorbed in blind // of back exterior window with BLIND - if (IS_BLIND_ON(ShadeFlagBack)) { + if (ANY_BLIND(ShadeFlagBack)) { int BlNumBack = SurfWinBlindNumber(BackSurfNum); // Back surface blind number Real64 ProfAngBack; // Back window solar profile angle (radians) ProfileAngle(BackSurfNum, state.dataEnvrn->SOLCOS, Blind(BlNumBack).SlatOrientation, ProfAngBack); @@ -7611,7 +7611,7 @@ namespace SolarShading { SurfWinDifSolar(SurfNum) = DifSolarInc * WinTransDifSolar(SurfNum); SurfWinBmSolarEnergy(SurfNum) = SurfWinBmSolar(SurfNum) * state.dataGlobal->TimeStepZoneSec; SurfWinDifSolarEnergy(SurfNum) = SurfWinDifSolar(SurfNum) * state.dataGlobal->TimeStepZoneSec; - if (IS_BLIND_ON(ShadeFlag)) { + if (ANY_BLIND(ShadeFlag)) { if (Blind(SurfWinBlindNumber(SurfNum)).SlatOrientation == Horizontal) { SurfWinDifSolar(SurfNum) = SkySolarInc * WinTransDifSolarSky(SurfNum) + GndSolarInc * WinTransDifSolarGnd(SurfNum); SurfWinDifSolarEnergy(SurfNum) = SurfWinDifSolar(SurfNum) * state.dataGlobal->TimeStepZoneSec; @@ -8991,7 +8991,7 @@ namespace SolarShading { SurfWinSlatAngThisTS(ISurf) = 0.0; SurfWinSlatAngThisTSDeg(ISurf) = 0.0; SurfWinSlatsBlockBeam(ISurf) = false; - if (IS_BLIND_ON(SurfWinShadingFlag(ISurf))) { + if (ANY_BLIND(SurfWinShadingFlag(ISurf))) { // Blind in place or may be in place due to glare control int BlNum = SurfWinBlindNumber(ISurf); if (BlNum > 0) { @@ -10500,7 +10500,7 @@ namespace SolarShading { Real64 AbsorpEff = 0.0; // Effective absorptance of isolated shade layer (fraction of // of incident radiation remaining after reflected portion is // removed that is absorbed - if (IS_SHADE_ON(WindowShadingControl(WinShadeCtrlNum).ShadingType)) { + if (ANY_SHADE(WindowShadingControl(WinShadeCtrlNum).ShadingType)) { int ConstrNumSh = Surface(SurfNum).activeShadedConstruction; // Window construction number with shade int TotLay = state.dataConstruction->Construct(ConstrNumSh).TotLayers; // Total layers in a construction @@ -10897,10 +10897,10 @@ namespace SolarShading { auto const &construct_sh_AbsDiffBack(construct_sh.AbsDiffBack); auto const &construct_sh_BlAbsDiffBack(construct_sh.BlAbsDiffBack); for (int IGlass = 1; IGlass <= construct_sh.TotGlassLayers; ++IGlass) { - if (IS_SHADE_SCREEN_ON(ShadeFlag)) { + if (ANY_SHADE_SCREEN(ShadeFlag)) { // Calc diffuse solar absorbed in each window glass layer and shade WinDifSolLayAbsW = WinDifSolarTrans_Factor * construct_sh_AbsDiffBack(IGlass); - } else if (IS_BLIND_ON(ShadeFlag)) { + } else if (ANY_BLIND(ShadeFlag)) { BlAbsDiffBk = InterpSlatAng(HTsurf_slat_ang, HTsurf_movable_slats, construct_sh_BlAbsDiffBack(_, IGlass)); // Calc diffuse solar absorbed in each window glass layer and shade WinDifSolLayAbsW = WinDifSolarTrans_Factor * BlAbsDiffBk; @@ -10936,16 +10936,16 @@ namespace SolarShading { // Now calc diffuse solar absorbed by shade/blind itself BlNum = SurfWinBlindNumber(HeatTransSurfNum); - if (IS_SHADE_SCREEN_ON(ShadeFlag)) { + if (ANY_SHADE_SCREEN(ShadeFlag)) { // Calc diffuse solar absorbed by shade or screen [W] ShBlDifSolarAbsW = WinDifSolarTrans_Factor * construct_sh.AbsDiffBackShade; - } else if (IS_BLIND_ON(ShadeFlag)) { + } else if (ANY_BLIND(ShadeFlag)) { // Calc diffuse solar absorbed by blind [W] AbsDiffBkBl = InterpSlatAng(HTsurf_slat_ang, HTsurf_movable_slats, construct_sh.AbsDiffBackBlind); ShBlDifSolarAbsW = WinDifSolarTrans_Factor * AbsDiffBkBl; } // Correct for divider shadowing - if (IS_EXT_SHADED(ShadeFlag)) { + if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) { ShBlDifSolarAbsW *= SurfWinGlazedFrac(HeatTransSurfNum); } @@ -11408,10 +11408,10 @@ namespace SolarShading { // First calc diffuse solar absorbed by each glass layer in this window with shade/blind in place for (IGlass = 1; IGlass <= state.dataConstruction->Construct(ConstrNumSh).TotGlassLayers; ++IGlass) { - if (IS_SHADE_SCREEN_ON(ShadeFlag)) { + if (ANY_SHADE_SCREEN(ShadeFlag)) { // Calc diffuse solar absorbed in each window glass layer and shade WinDifSolLayAbsW = SolarTrans_ViewFactor * state.dataConstruction->Construct(ConstrNumSh).AbsDiffBack(IGlass); - } else if (IS_BLIND_ON(ShadeFlag)) { + } else if (ANY_BLIND(ShadeFlag)) { BlAbsDiffBk = InterpSlatAng(SurfWinSlatAngThisTS(HeatTransSurfNum), SurfWinMovableSlats(HeatTransSurfNum), state.dataConstruction->Construct(ConstrNumSh).BlAbsDiffBack(_, IGlass)); @@ -11449,10 +11449,10 @@ namespace SolarShading { // Now calc diffuse solar absorbed by shade/blind itself BlNum = SurfWinBlindNumber(HeatTransSurfNum); - if (IS_SHADE_SCREEN_ON(ShadeFlag)) { + if (ANY_SHADE_SCREEN(ShadeFlag)) { // Calc diffuse solar absorbed by shade or screen [W] ShBlDifSolarAbsW = SolarTrans_ViewFactor * state.dataConstruction->Construct(ConstrNumSh).AbsDiffBackShade; - } else if (IS_BLIND_ON(ShadeFlag)) { + } else if (ANY_BLIND(ShadeFlag)) { // Calc diffuse solar absorbed by blind [W] AbsDiffBkBl = InterpSlatAng(SurfWinSlatAngThisTS(HeatTransSurfNum), SurfWinMovableSlats(HeatTransSurfNum), @@ -11460,7 +11460,7 @@ namespace SolarShading { ShBlDifSolarAbsW = SolarTrans_ViewFactor * AbsDiffBkBl; } // Correct for divider shadowing - if (IS_EXT_SHADED(ShadeFlag)) { + if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) { ShBlDifSolarAbsW *= SurfWinGlazedFrac(HeatTransSurfNum); } diff --git a/src/EnergyPlus/SteamBaseboardRadiator.cc b/src/EnergyPlus/SteamBaseboardRadiator.cc index cd9f43b34de..b39fbdcc5d7 100644 --- a/src/EnergyPlus/SteamBaseboardRadiator.cc +++ b/src/EnergyPlus/SteamBaseboardRadiator.cc @@ -1380,7 +1380,7 @@ namespace SteamBaseboardRadiator { Area = Surface(SurfNum).Area; if (Surface(SurfNum).Class == SurfaceClass::Window) { - if (IS_INT_SHADED(SurfWinShadingFlag(SurfNum))) { + if (ANY_INTERIOR_SHADE_BLIND(SurfWinShadingFlag(SurfNum))) { // The area is the shade or blind area = the sum of the glazing area and the divider area (which is zero if no divider) Area += SurfWinDividerArea(SurfNum); } @@ -1391,7 +1391,7 @@ namespace SteamBaseboardRadiator { SurfWinFrameTempSurfIn(SurfNum); } - if (SurfWinDividerArea(SurfNum) > 0.0 && !IS_INT_SHADED(SurfWinShadingFlag(SurfNum))) { + if (SurfWinDividerArea(SurfNum) > 0.0 && !ANY_INTERIOR_SHADE_BLIND(SurfWinShadingFlag(SurfNum))) { // Window divider contribution (only from shade or blind for window with divider and interior shade or blind) SumHATsurf += HConvIn(SurfNum) * SurfWinDividerArea(SurfNum) * (1.0 + 2.0 * SurfWinProjCorrDivIn(SurfNum)) * SurfWinDividerTempSurfIn(SurfNum); diff --git a/src/EnergyPlus/SurfaceGeometry.cc b/src/EnergyPlus/SurfaceGeometry.cc index d4eb0b2281e..f0a7357ba8a 100644 --- a/src/EnergyPlus/SurfaceGeometry.cc +++ b/src/EnergyPlus/SurfaceGeometry.cc @@ -4770,7 +4770,7 @@ namespace SurfaceGeometry { if (ConstrNumSh > 0) { state.dataSurfaceGeometry->SurfaceTmp(SurfNum).activeShadedConstruction = ConstrNumSh; } else { - if (IS_INT_SHADED(WindowShadingControl(WSCPtr).ShadingType) || IS_EXT_SHADED(WindowShadingControl(WSCPtr).ShadingType)) { + if (ANY_INTERIOR_SHADE_BLIND(WindowShadingControl(WSCPtr).ShadingType) || ANY_EXTERIOR_SHADE_BLIND_SCREEN(WindowShadingControl(WSCPtr).ShadingType)) { ShDevNum = WindowShadingControl(WSCPtr).ShadingDevice; if (ShDevNum > 0) { CreateShadedWindowConstruction(state, SurfNum, WSCPtr, ShDevNum, shadeControlIndex); @@ -4785,7 +4785,7 @@ namespace SurfaceGeometry { ConstrNum = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction; if (!ErrorsFound && WSCPtr > 0 && ConstrNum > 0 && ConstrNumSh > 0) { - if (IS_INT_SHADED(WindowShadingControl(WSCPtr).ShadingType)) { + if (ANY_INTERIOR_SHADE_BLIND(WindowShadingControl(WSCPtr).ShadingType)) { TotLayers = state.dataConstruction->Construct(ConstrNum).TotLayers; TotShLayers = state.dataConstruction->Construct(ConstrNumSh).TotLayers; if (TotShLayers - 1 != TotLayers) { @@ -4808,7 +4808,7 @@ namespace SurfaceGeometry { } } - if (IS_EXT_SHADED(WindowShadingControl(WSCPtr).ShadingType)) { + if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(WindowShadingControl(WSCPtr).ShadingType)) { TotLayers = state.dataConstruction->Construct(ConstrNum).TotLayers; TotShLayers = state.dataConstruction->Construct(ConstrNumSh).TotLayers; if (TotShLayers - 1 != TotLayers) { @@ -8159,87 +8159,54 @@ namespace SurfaceGeometry { using ScheduleManager::GetScheduleIndex; // SUBROUTINE PARAMETER DEFINITIONS: - int const NumValidShadingTypes(8); - static Array1D_string const cValidShadingTypes(NumValidShadingTypes, - {"INTERIORSHADE", - "EXTERIORSHADE", - "EXTERIORSCREEN", - "INTERIORBLIND", - "EXTERIORBLIND", - "BETWEENGLASSSHADE", - "BETWEENGLASSBLIND", - "SWITCHABLEGLAZING"}); - static Array1D const ValidShadingTypes(NumValidShadingTypes, - {WinShadingType::IntShade, - WinShadingType::ExtShade, - WinShadingType::ExtScreen, - WinShadingType::IntBlind, - WinShadingType::ExtBlind, - WinShadingType::BGShade, - WinShadingType::BGBlind, - WinShadingType::SwitchableGlazing}); - - int const NumValidWindowShadingControlTypes(21); - static Array1D_string const cValidWindowShadingControlTypes(NumValidWindowShadingControlTypes, - {"ALWAYSON", - "ALWAYSOFF", - "ONIFSCHEDULEALLOWS", - "ONIFHIGHSOLARONWINDOW", - "ONIFHIGHHORIZONTALSOLAR", - "ONIFHIGHOUTDOORAIRTEMPERATURE", - "ONIFHIGHZONEAIRTEMPERATURE", - "ONIFHIGHZONECOOLING", - "ONIFHIGHGLARE", - "MEETDAYLIGHTILLUMINANCESETPOINT", - "ONNIGHTIFLOWOUTDOORTEMPANDOFFDAY", - "ONNIGHTIFLOWINSIDETEMPANDOFFDAY", - "ONNIGHTIFHEATINGANDOFFDAY", - "ONNIGHTIFLOWOUTDOORTEMPANDONDAYIFCOOLING", - "ONNIGHTIFHEATINGANDONDAYIFCOOLING", - "OFFNIGHTANDONDAYIFCOOLINGANDHIGHSOLARONWINDOW", - "ONNIGHTANDONDAYIFCOOLINGANDHIGHSOLARONWINDOW", - "ONIFHIGHOUTDOORAIRTEMPANDHIGHSOLARONWINDOW", - "ONIFHIGHOUTDOORAIRTEMPANDHIGHHORIZONTALSOLAR", - "ONIFHIGHZONEAIRTEMPANDHIGHSOLARONWINDOW", - "ONIFHIGHZONEAIRTEMPANDHIGHHORIZONTALSOLAR"}); - - static Array1D const ValidWindowShadingControlTypes( - NumValidWindowShadingControlTypes, - {WindowShadingControlType::AlwaysOn, - WindowShadingControlType::AlwaysOff, - WindowShadingControlType::OnIfScheduled, - WindowShadingControlType::HiSolar, - WindowShadingControlType::HiHorzSolar, - WindowShadingControlType::HiOutAirTemp, - WindowShadingControlType::HiZoneAirTemp, - WindowShadingControlType::HiZoneCooling, - WindowShadingControlType::HiGlare, - WindowShadingControlType::MeetDaylIlumSetp, - WindowShadingControlType::OnNightLoOutTemp_OffDay, - WindowShadingControlType::OnNightLoInTemp_OffDay, - WindowShadingControlType::OnNightIfHeating_OffDay, - WindowShadingControlType::OnNightLoOutTemp_OnDayCooling, - WindowShadingControlType::OnNightIfHeating_OnDayCooling, - WindowShadingControlType::OffNight_OnDay_HiSolarWindow, - WindowShadingControlType::OnNight_OnDay_HiSolarWindow, - WindowShadingControlType::OnHiOutTemp_HiSolarWindow, - WindowShadingControlType::OnHiOutTemp_HiHorzSolar, - WindowShadingControlType::OnHiZoneTemp_HiSolarWindow, - WindowShadingControlType::OnHiZoneTemp_HiHorzSolar}); // 'ALWAYSON ', & | 'ALWAYSOFF ', & - // | 'ONIFSCHEDULEALLOWS ', & | 'ONIFHIGHSOLARONWINDOW ', - // & | 'ONIFHIGHHORIZONTALSOLAR ', & | 'ONIFHIGHOUTDOORAIRTEMPERATURE - // ', & | 'ONIFHIGHZONEAIRTEMPERATURE ', & | 'ONIFHIGHZONECOOLING - // ', & | 'ONIFHIGHGLARE ', & | 'MEETDAYLIGHTILLUMINANCESETPOINT - // ', & | 'ONNIGHTIFLOWOUTDOORTEMPANDOFFDAY ', & | 'ONNIGHTIFLOWINSIDETEMPANDOFFDAY - // ', & | 'ONNIGHTIFHEATINGANDOFFDAY ', & | - // 'ONNIGHTIFLOWOUTDOORTEMPANDONDAYIFCOOLING ', & | 'ONNIGHTIFHEATINGANDONDAYIFCOOLING - // ', & | 'OFFNIGHTANDONDAYIFCOOLINGANDHIGHSOLARONWINDOW ', & | - // 'ONNIGHTANDONDAYIFCOOLINGANDHIGHSOLARONWINDOW ', & | 'ONIFHIGHOUTDOORAIRTEMPANDHIGHSOLARONWINDOW ', - // & | 'ONIFHIGHOUTDOORAIRTEMPANDHIGHHORIZONTALSOLAR', & | 'ONIFHIGHZONEAIRTEMPANDHIGHSOLARONWINDOW - // ', & | 'ONIFHIGHZONEAIRTEMPANDHIGHHORIZONTALSOLAR '/) - // SUBROUTINE LOCAL VARIABLE DECLARATIONS: + std::map WindowShadingStrToType = { + {"INTERIORSHADE",WinShadingType::IntShade}, + {"EXTERIORSHADE", WinShadingType::ExtShade}, + {"EXTERIORSCREEN", WinShadingType::ExtScreen}, + {"INTERIORBLIND", WinShadingType::IntBlind}, + {"EXTERIORBLIND", WinShadingType::ExtBlind}, + {"BETWEENGLASSSHADE", WinShadingType::BGShade, }, + {"BETWEENGLASSBLIND", WinShadingType::BGBlind, }, + {"SWITCHABLEGLAZING", WinShadingType::SwitchableGlazing, } + }; + + WindowShadingControlTypeToStr = { + {WindowShadingControlType::UnControlled, "Uncontrolled"}, + {WindowShadingControlType::AlwaysOn, "AlwaysOn"}, + {WindowShadingControlType::AlwaysOff, "AlwaysOff"}, + {WindowShadingControlType::OnIfScheduled, "OnIfScheduleAllows"}, + {WindowShadingControlType::HiSolar, "OnIfHighSolarOnWindow"}, + {WindowShadingControlType::HiHorzSolar, "OnIfHighHorizontalSolar"}, + {WindowShadingControlType::HiOutAirTemp, "OnIfHighOutdoorAirTemperature"}, + {WindowShadingControlType::HiZoneAirTemp, "OnIfHighZoneAirTemperature"}, + {WindowShadingControlType::HiZoneCooling, "OnIfHighZoneCooling"}, + {WindowShadingControlType::HiGlare, "OnIfHighGlare"}, + {WindowShadingControlType::MeetDaylIlumSetp, "MeetDaylightIlluminanceSetpoint"}, + {WindowShadingControlType::OnNightLoOutTemp_OffDay, "OnNightIfLowOutdoorTempAndOffDay"}, + {WindowShadingControlType::OnNightLoInTemp_OffDay, "OnNightIfLowInsideTempAndOffDay"}, + {WindowShadingControlType::OnNightIfHeating_OffDay, "OnNightIfHeatingAndOffDay"}, + {WindowShadingControlType::OnNightLoOutTemp_OnDayCooling, "OnNightIfLowOutdoorTempAndOnDayIfCooling"}, + {WindowShadingControlType::OnNightIfHeating_OnDayCooling, "OnNightIfHeatingAndOnDayIfCooling"}, + {WindowShadingControlType::OffNight_OnDay_HiSolarWindow, "OffNightAndOnDayIfCoolingAndHighSolarOnWindow"}, + {WindowShadingControlType::OnNight_OnDay_HiSolarWindow, "OnNightAndOnDayIfCoolingAndHighSolarOnWindow"}, + {WindowShadingControlType::OnHiOutTemp_HiSolarWindow, "OnIfHighOutdoorAirTempAndHighSolarOnWindow"}, + {WindowShadingControlType::OnHiOutTemp_HiHorzSolar, "OnIfHighOutdoorAirTempAndHighHorizontalSolar"}, + {WindowShadingControlType::OnHiZoneTemp_HiSolarWindow, "OnIfHighZoneAirTempAndHighSolarOnWindow"}, + {WindowShadingControlType::OnHiZoneTemp_HiHorzSolar, "OnIfHighZoneAirTempAndHighHorizontalSolar"} + }; + std::map WindowShadingControlStrToType; + for (auto &type: WindowShadingControlTypeToStr) { + std::string str_type = type.second; + std::transform(str_type.begin(), str_type.end(), str_type.begin(), ::toupper); + WindowShadingControlStrToType.insert({str_type, type.first}); + } + + std::string str = "Hello World"; + boost::to_upper(str); + + // SUBROUTINE LOCAL VARIABLE DECLARATIONS: int IOStat; // IO Status when calling get input subroutine int ControlNumAlpha; // Number of control alpha names being passed int ControlNumProp; // Number of control properties being passed @@ -8430,13 +8397,13 @@ namespace SurfaceGeometry { } // Error if illegal control type - Found = UtilityRoutines::FindItemInList(ControlType, cValidWindowShadingControlTypes, NumValidWindowShadingControlTypes); + Found = WindowShadingControlStrToType.count(ControlType); if (Found == 0) { ErrorsFound = true; ShowSevereError(state, cCurrentModuleObject + "=\"" + WindowShadingControl(ControlNum).Name + "\" invalid " + cAlphaFieldNames(5) + "=\"" + cAlphaArgs(5) + "\"."); } else { - WindowShadingControl(ControlNum).ShadingControlType = ValidWindowShadingControlTypes(Found); + WindowShadingControl(ControlNum).ShadingControlType = WindowShadingControlStrToType[ControlType]; } // Error checks @@ -8494,13 +8461,13 @@ namespace SurfaceGeometry { } // Check for illegal shading type name - Found = UtilityRoutines::FindItemInList(cAlphaArgs(3), cValidShadingTypes, NumValidShadingTypes); + Found = WindowShadingStrToType.count(cAlphaArgs(3)); if (Found == 0) { ErrorsFound = true; ShowSevereError(state, cCurrentModuleObject + "=\"" + WindowShadingControl(ControlNum).Name + "\" invalid " + cAlphaFieldNames(3) + "=\"" + cAlphaArgs(3) + "\"."); } else { - WindowShadingControl(ControlNum).ShadingType = ValidShadingTypes(Found); + WindowShadingControl(ControlNum).ShadingType = WindowShadingStrToType[cAlphaArgs(3)]; } WinShadingType ShTyp = WindowShadingControl(ControlNum).ShadingType; @@ -11681,7 +11648,7 @@ namespace SurfaceGeometry { ShDevName = state.dataMaterial->Material(ShDevNum).Name; ConstrNum = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction; ConstrName = state.dataConstruction->Construct(ConstrNum).Name; - if (IS_INT_SHADED(WindowShadingControl(WSCPtr).ShadingType)) { + if (ANY_INTERIOR_SHADE_BLIND(WindowShadingControl(WSCPtr).ShadingType)) { ConstrNameSh = ConstrName + ':' + ShDevName + ":INT"; } else { ConstrNameSh = ConstrName + ':' + ShDevName + ":EXT"; diff --git a/src/EnergyPlus/UFADManager.cc b/src/EnergyPlus/UFADManager.cc index 86b5cfbdb22..a735e0841e9 100644 --- a/src/EnergyPlus/UFADManager.cc +++ b/src/EnergyPlus/UFADManager.cc @@ -212,7 +212,7 @@ namespace UFADManager { if (SurfNum == 0) continue; if (Surface(SurfNum).ExtBoundCond == ExternalEnvironment || Surface(SurfNum).ExtBoundCond == OtherSideCoefNoCalcExt || Surface(SurfNum).ExtBoundCond == OtherSideCoefCalcExt || Surface(SurfNum).ExtBoundCond == OtherSideCondModeledExt) { - if (IS_INT_SHADED(SurfWinShadingFlag(SurfNum))) { + if (ANY_INTERIOR_SHADE_BLIND(SurfWinShadingFlag(SurfNum))) { ++NumShadesDown; } } diff --git a/src/EnergyPlus/VentilatedSlab.cc b/src/EnergyPlus/VentilatedSlab.cc index 7dbb14b961a..5cadb774b62 100644 --- a/src/EnergyPlus/VentilatedSlab.cc +++ b/src/EnergyPlus/VentilatedSlab.cc @@ -4459,7 +4459,7 @@ namespace VentilatedSlab { Area = Surface(SurfNum).Area; if (Surface(SurfNum).Class == SurfaceClass::Window) { - if (IS_INT_SHADED(SurfWinShadingFlag(SurfNum))) { + if (ANY_INTERIOR_SHADE_BLIND(SurfWinShadingFlag(SurfNum))) { // The area is the shade or blind are = sum of the glazing area and the divider area (which is zero if no divider) Area += SurfWinDividerArea(SurfNum); } @@ -4470,7 +4470,7 @@ namespace VentilatedSlab { SurfWinFrameTempSurfIn(SurfNum); } - if (SurfWinDividerArea(SurfNum) > 0.0 && !IS_INT_SHADED(SurfWinShadingFlag(SurfNum))) { + if (SurfWinDividerArea(SurfNum) > 0.0 && !ANY_INTERIOR_SHADE_BLIND(SurfWinShadingFlag(SurfNum))) { // Window divider contribution (only from shade or blind for window with divider and interior shade or blind) SumHATsurf += HConvIn(SurfNum) * SurfWinDividerArea(SurfNum) * (1.0 + 2.0 * SurfWinProjCorrDivIn(SurfNum)) * SurfWinDividerTempSurfIn(SurfNum); diff --git a/src/EnergyPlus/WindowComplexManager.cc b/src/EnergyPlus/WindowComplexManager.cc index 0bd6f8b526b..e48b997ea0c 100644 --- a/src/EnergyPlus/WindowComplexManager.cc +++ b/src/EnergyPlus/WindowComplexManager.cc @@ -3298,7 +3298,7 @@ namespace WindowComplexManager { SurfOutsideEmiss = emis(1); IncidentSolar = Surface(SurfNum).Area * SurfQRadSWOutIncident(SurfNum); - if (IS_INT_SHADED(ShadeFlag)) { + if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) { // Interior shade or blind ConvHeatFlowNatural = -qv(nlayer) * height * width; diff --git a/src/EnergyPlus/WindowManager.cc b/src/EnergyPlus/WindowManager.cc index f2d425c16b6..a3af326f806 100644 --- a/src/EnergyPlus/WindowManager.cc +++ b/src/EnergyPlus/WindowManager.cc @@ -2345,13 +2345,13 @@ namespace WindowManager { } if (state.dataMaterial->Material(LayPtr).Group == Shade || state.dataMaterial->Material(LayPtr).Group == WindowBlind || state.dataMaterial->Material(LayPtr).Group == Screen) { - if (IS_INT_SHADED(ShadeFlag)) ShadeLayPtr = state.dataConstruction->Construct(IConst).LayerPoint(state.dataConstruction->Construct(IConst).TotLayers); - if (IS_EXT_SHADED(ShadeFlag)) ShadeLayPtr = state.dataConstruction->Construct(IConst).LayerPoint(1); - if (IS_BG_SHADED(ShadeFlag)) { + if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) ShadeLayPtr = state.dataConstruction->Construct(IConst).LayerPoint(state.dataConstruction->Construct(IConst).TotLayers); + if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) ShadeLayPtr = state.dataConstruction->Construct(IConst).LayerPoint(1); + if (ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag)) { ShadeLayPtr = state.dataConstruction->Construct(IConst).LayerPoint(3); if (TotGlassLay == 3) ShadeLayPtr = state.dataConstruction->Construct(IConst).LayerPoint(5); } - if (IS_SHADE_SCREEN_ON(ShadeFlag)) { + if (ANY_SHADE_SCREEN(ShadeFlag)) { // Shade or screen on if (state.dataGlobal->AnyEnergyManagementSystemInModel) { // check to make sure the user hasn't messed up the shade control values if (state.dataMaterial->Material(ShadeLayPtr).Group == WindowBlind) { @@ -2411,7 +2411,7 @@ namespace WindowManager { } // End of loop over glass, gap and blind/shade layers in a window construction - if (IS_INT_SHADED(ShadeFlag) || IS_EXT_SHADED(ShadeFlag)) { + if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag) || ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) { // Interior or exterior blind, shade or screen is on. // Fill gap between blind/shade and adjacent glass with air properties. ++IGap; @@ -2562,7 +2562,7 @@ namespace WindowManager { dth3 = state.dataWindowManager->thetas(6) - state.dataWindowManager->thetas(5); dth4 = state.dataWindowManager->thetas(8) - state.dataWindowManager->thetas(7); - if (IS_INT_SHADED(ShadeFlag)) { + if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) { SurfInsideTemp = state.dataWindowManager->thetas(2 * state.dataWindowManager->ngllayer + 2) - state.dataWindowManager->TKelvin; EffShBlEmiss = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), window.EffShBlindEmiss); EffGlEmiss = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), window.EffGlassEmiss); @@ -2570,7 +2570,7 @@ namespace WindowManager { } else { SurfInsideTemp = state.dataWindowManager->thetas(2 * state.dataWindowManager->ngllayer) - state.dataWindowManager->TKelvin; } - if (IS_EXT_SHADED(ShadeFlag)) { + if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) { SurfOutsideTemp = state.dataWindowManager->thetas(2 * state.dataWindowManager->ngllayer + 1) - state.dataWindowManager->TKelvin; // this index looks suspicious (CR 8202) // SurfOutsideEmiss = emis(1) ! this index should be coordinated with previous line SurfOutsideEmiss = state.dataWindowManager->emis(2 * state.dataWindowManager->ngllayer + 1); // fix for CR 8202 @@ -2937,21 +2937,21 @@ namespace WindowManager { AbsRadShadeFace = 0.0; TGapNew = 0.0; - if (IS_SHADE_SCREEN_ON(ShadeFlag) || IS_BLIND_ON(ShadeFlag)) { + if (ANY_SHADE_SCREEN(ShadeFlag) || ANY_BLIND(ShadeFlag)) { state.dataWindowManager->nglfacep = state.dataWindowManager->nglface + 2; AbsRadShadeFace(1) = DataSurfaces::AbsFrontSide(SurfNum); AbsRadShadeFace(2) = DataSurfaces::AbsBackSide(SurfNum); - if (IS_INT_SHADED(ShadeFlag)) AbsRadShadeFace(2) += SurfWinIntLWAbsByShade(SurfNum); + if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) AbsRadShadeFace(2) += SurfWinIntLWAbsByShade(SurfNum); sconsh = state.dataWindowManager->scon(state.dataWindowManager->ngllayer + 1); TauShIR = state.dataWindowManager->tir(state.dataWindowManager->nglface + 1); EpsShIR1 = state.dataWindowManager->emis(state.dataWindowManager->nglface + 1); EpsShIR2 = state.dataWindowManager->emis(state.dataWindowManager->nglface + 2); RhoShIR1 = max(0.0, 1.0 - TauShIR - EpsShIR1); RhoShIR2 = max(0.0, 1.0 - TauShIR - EpsShIR2); - if (IS_INT_SHADED(ShadeFlag)) { + if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) { RhoGlIR2 = 1.0 - state.dataWindowManager->emis(2 * state.dataWindowManager->ngllayer); ShGlReflFacIR = 1.0 - RhoGlIR2 * RhoShIR1; - } else if (IS_EXT_SHADED(ShadeFlag)) { + } else if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) { RhoGlIR1 = 1.0 - state.dataWindowManager->emis(1); ShGlReflFacIR = 1.0 - RhoGlIR1 * RhoShIR2; } @@ -2983,7 +2983,7 @@ namespace WindowManager { (Surface(SurfNum).IntConvCoeff == -2)) { // coef model is "detailed" and not prescribed by user // need to find inside face index, varies with shade/blind etc. - if (IS_INT_SHADED(ShadeFlag)) { + if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) { InsideFaceIndex = state.dataWindowManager->nglfacep; } else { InsideFaceIndex = state.dataWindowManager->nglface; @@ -2999,7 +2999,7 @@ namespace WindowManager { // coefficient from glass and shade/blind to gap between glass and shade/blind, // effective gap air temperature, velocity of air in gap and gap outlet temperature. - if (IS_EXT_SHADED(ShadeFlag) || IS_INT_SHADED(ShadeFlag)) { + if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag) || ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) { ExtOrIntShadeNaturalFlow(state, SurfNum, iter, VGap, TGapNew, TGapOutlet, hcv, ConvHeatFlowNatural); if (iter >= 1) { hcv = 0.5 * (hcvPrev + hcv); @@ -3015,7 +3015,7 @@ namespace WindowManager { // get glass-to-air forced convection heat transfer coefficient, average gap air temperature, and // convective heat flow from gap. - if (!IS_BG_SHADED(ShadeFlag) && SurfWinAirflowThisTS(SurfNum) > 0.0) { + if (!ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag) && SurfWinAirflowThisTS(SurfNum) > 0.0) { BetweenGlassForcedFlow(state, SurfNum, iter, VAirflowGap, TAirflowGapNew, TAirflowGapOutlet, hcvAirflowGap, ConvHeatFlowForced); } @@ -3024,7 +3024,7 @@ namespace WindowManager { // Also get average gas temperature in the two gaps, and, for airflow window, the sum of the // convective heat flows from the gaps. - if (IS_BG_SHADED(ShadeFlag)) { + if (ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag)) { if (SurfWinAirflowThisTS(SurfNum) == 0.0) { // Natural convection in gaps BetweenGlassShadeNaturalFlow(state, SurfNum, iter, VGap, TGapNewBG, hcvBG); } else { // Forced convection in gaps @@ -3048,7 +3048,7 @@ namespace WindowManager { Aface(1, 2) = -state.dataWindowManager->scon(1); Aface(2, 2) = hr(2) + state.dataWindowManager->scon(1) + state.dataWindowManager->hcin; - if (IS_INT_SHADED(ShadeFlag)) { + if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) { Bface(2) = state.dataWindowManager->Rmir * state.dataWindowManager->emis(2) * TauShIR / ShGlReflFacIR + hcv * TGapNew + state.dataWindowManager->AbsRadGlassFace(2); Bface(3) = state.dataWindowManager->Rmir * TauShIR * RhoGlIR2 * EpsShIR1 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(1); Bface(4) = state.dataWindowManager->Rmir * EpsShIR2 + state.dataWindowManager->hcin * state.dataWindowManager->tin + AbsRadShadeFace(2); @@ -3062,7 +3062,7 @@ namespace WindowManager { Aface(4, 4) = hr(4) + sconsh + state.dataWindowManager->hcin; } - if (IS_EXT_SHADED(ShadeFlag)) { + if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) { Bface(1) = state.dataWindowManager->Outir * state.dataWindowManager->emis(1) * TauShIR / ShGlReflFacIR + hcv * TGapNew + state.dataWindowManager->AbsRadGlassFace(1); Bface(3) = state.dataWindowManager->Outir * EpsShIR1 + state.dataWindowManager->hcout * state.dataWindowManager->tout + AbsRadShadeFace(1); Bface(4) = state.dataWindowManager->Outir * TauShIR * RhoGlIR1 * EpsShIR2 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(2); @@ -3104,7 +3104,7 @@ namespace WindowManager { Aface(3, 4) = -state.dataWindowManager->scon(2); Aface(4, 4) = hr(4) + state.dataWindowManager->scon(2) + state.dataWindowManager->hcin; - if (!IS_BG_SHADED(ShadeFlag) && SurfWinAirflowThisTS(SurfNum) > 0.0) { + if (!ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag) && SurfWinAirflowThisTS(SurfNum) > 0.0) { Bface(2) = state.dataWindowManager->AbsRadGlassFace(2) + hcvAirflowGap * TAirflowGapNew; Bface(3) = state.dataWindowManager->AbsRadGlassFace(3) + hcvAirflowGap * TAirflowGapNew; Aface(2, 2) = state.dataWindowManager->scon(1) + hcvAirflowGap - state.dataWindowManager->A23P * hr(2); @@ -3113,7 +3113,7 @@ namespace WindowManager { Aface(3, 3) = hcvAirflowGap + state.dataWindowManager->scon(2) + state.dataWindowManager->A32P * hr(3); } - if (IS_INT_SHADED(ShadeFlag)) { + if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) { Bface(4) = state.dataWindowManager->Rmir * state.dataWindowManager->emis(4) * TauShIR / ShGlReflFacIR + hcv * TGapNew + state.dataWindowManager->AbsRadGlassFace(4); Bface(5) = state.dataWindowManager->Rmir * TauShIR * RhoGlIR2 * EpsShIR1 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(1); Bface(6) = state.dataWindowManager->Rmir * EpsShIR2 + state.dataWindowManager->hcin * state.dataWindowManager->tin + AbsRadShadeFace(2); @@ -3127,7 +3127,7 @@ namespace WindowManager { Aface(6, 6) = hr(6) + sconsh + state.dataWindowManager->hcin; } - if (IS_EXT_SHADED(ShadeFlag)) { + if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) { Bface(1) = state.dataWindowManager->Outir * state.dataWindowManager->emis(1) * TauShIR / ShGlReflFacIR + hcv * TGapNew + state.dataWindowManager->AbsRadGlassFace(1); Bface(5) = state.dataWindowManager->Outir * EpsShIR1 + state.dataWindowManager->hcout * state.dataWindowManager->tout + AbsRadShadeFace(1); Bface(6) = state.dataWindowManager->Outir * TauShIR * RhoGlIR1 * EpsShIR2 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(2); @@ -3141,7 +3141,7 @@ namespace WindowManager { Aface(6, 6) = hr(6) * (1 - RhoGlIR1 * (EpsShIR2 + RhoShIR2)) / ShGlReflFacIR + sconsh + hcv; } - if (IS_BG_SHADED(ShadeFlag)) { + if (ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag)) { for (i = 1; i <= 6; ++i) { RhoIR(i) = max(0.0, 1.0 - state.dataWindowManager->tir(i) - state.dataWindowManager->emis(i)); } @@ -3231,7 +3231,7 @@ namespace WindowManager { Aface(5, 5) = hcvAirflowGap + state.dataWindowManager->scon(3) + state.dataWindowManager->A54P * hr(5); } - if (IS_INT_SHADED(ShadeFlag)) { + if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) { Bface(6) = state.dataWindowManager->Rmir * state.dataWindowManager->emis(6) * TauShIR / ShGlReflFacIR + hcv * TGapNew + state.dataWindowManager->AbsRadGlassFace(6); Bface(7) = state.dataWindowManager->Rmir * TauShIR * RhoGlIR2 * EpsShIR1 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(1); Bface(8) = state.dataWindowManager->Rmir * EpsShIR2 + state.dataWindowManager->hcin * state.dataWindowManager->tin + AbsRadShadeFace(2); @@ -3245,7 +3245,7 @@ namespace WindowManager { Aface(8, 8) = hr(8) + sconsh + state.dataWindowManager->hcin; } - if (IS_EXT_SHADED(ShadeFlag)) { + if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) { Bface(1) = state.dataWindowManager->Outir * state.dataWindowManager->emis(1) * TauShIR / ShGlReflFacIR + hcv * TGapNew + state.dataWindowManager->AbsRadGlassFace(1); Bface(7) = state.dataWindowManager->Outir * EpsShIR1 + state.dataWindowManager->hcout * state.dataWindowManager->tout + AbsRadShadeFace(1); Bface(8) = state.dataWindowManager->Outir * TauShIR * RhoGlIR1 * EpsShIR2 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(2); @@ -3357,7 +3357,7 @@ namespace WindowManager { Aface(7, 8) = -state.dataWindowManager->scon(4); Aface(8, 8) = hr(8) + state.dataWindowManager->scon(4) + state.dataWindowManager->hcin; - if (IS_INT_SHADED(ShadeFlag)) { + if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) { Bface(8) = state.dataWindowManager->Rmir * state.dataWindowManager->emis(8) * TauShIR / ShGlReflFacIR + hcv * TGapNew + state.dataWindowManager->AbsRadGlassFace(8); Bface(9) = state.dataWindowManager->Rmir * TauShIR * RhoGlIR2 * EpsShIR1 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(1); Bface(10) = state.dataWindowManager->Rmir * EpsShIR2 + state.dataWindowManager->hcin * state.dataWindowManager->tin + AbsRadShadeFace(2); @@ -3371,7 +3371,7 @@ namespace WindowManager { Aface(10, 10) = hr(10) + sconsh + state.dataWindowManager->hcin; } - if (IS_EXT_SHADED(ShadeFlag)) { + if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) { Bface(1) = state.dataWindowManager->Outir * state.dataWindowManager->emis(1) * TauShIR / ShGlReflFacIR + hcv * TGapNew + state.dataWindowManager->AbsRadGlassFace(1); Bface(9) = state.dataWindowManager->Outir * EpsShIR1 + state.dataWindowManager->hcout * state.dataWindowManager->tout + AbsRadShadeFace(1); Bface(10) = state.dataWindowManager->Outir * TauShIR * RhoGlIR1 * EpsShIR2 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(2); @@ -3423,7 +3423,7 @@ namespace WindowManager { // For all cases, get total window heat gain for reporting. See CalcWinFrameAndDividerTemps for // contribution of frame and divider. IncidentSolar = Surface(SurfNum).Area * SurfQRadSWOutIncident(SurfNum); - if (IS_INT_SHADED(ShadeFlag)) { + if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) { // Interior shade or blind SurfWinConvHeatFlowNatural(SurfNum) = ConvHeatFlowNatural; // Window heat gain from glazing and shade/blind to zone. Consists of transmitted solar, convection @@ -3506,9 +3506,9 @@ namespace WindowManager { TransDiff = state.dataConstruction->Construct(ConstrNum).TransDiff; // Default value for TransDiff here if (!IS_SHADED(ShadeFlag)) { TransDiff = state.dataConstruction->Construct(ConstrNum).TransDiff; - } else if (IS_SHADE_SCREEN_ON(ShadeFlag)) { + } else if (ANY_SHADE_SCREEN(ShadeFlag)) { TransDiff = state.dataConstruction->Construct(ConstrNumSh).TransDiff; - } else if (IS_BLIND_ON(ShadeFlag)) { + } else if (ANY_BLIND(ShadeFlag)) { TransDiff = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), state.dataConstruction->Construct(ConstrNumSh).BlTransDiff); } else if (ShadeFlag == WinShadingType::SwitchableGlazing) { @@ -3519,7 +3519,7 @@ namespace WindowManager { // shouldn't this be + outward flowing fraction of absorbed SW? -- do not know whose comment this is? LKL (9/2012) SurfWinLossSWZoneToOutWinRep(SurfNum) = QS(Surface(SurfNum).SolarEnclIndex) * Surface(SurfNum).Area * TransDiff; - if (IS_SHADE_SCREEN_ON(ShadeFlag) || IS_BLIND_ON(ShadeFlag)) { + if (ANY_SHADE_SCREEN(ShadeFlag) || ANY_BLIND(ShadeFlag)) { SurfWinShadingAbsorbedSolar(SurfNum) = (SurfWinExtBeamAbsByShade(SurfNum) + SurfWinExtDiffAbsByShade(SurfNum)) * (Surface(SurfNum).Area + SurfWinDividerArea(SurfNum)); SurfWinShadingAbsorbedSolarEnergy(SurfNum) = SurfWinShadingAbsorbedSolar(SurfNum) * state.dataGlobal->TimeStepZoneSec; @@ -3646,7 +3646,7 @@ namespace WindowManager { nglassfaces = 2 * state.dataConstruction->Construct(ConstrNumSh).TotGlassLayers; TotGaps = state.dataConstruction->Construct(ConstrNumSh).TotGlassLayers; - if (IS_INT_SHADED(ShadeFlag)) { // Interior shade or blind + if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) { // Interior shade or blind MatNumSh = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(nglassfaces); TGapInlet = state.dataWindowManager->tin; TGlassFace = state.dataWindowManager->thetas(nglassfaces); @@ -3748,7 +3748,7 @@ namespace WindowManager { TGapNew = TAve - (GapHeightChar / GapHeight) * (TGapOutlet - TGapInlet); // Convective heat flow from gap to room air for interior shade or blind - if (IS_INT_SHADED(ShadeFlag)) { + if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) { RhoAir = state.dataWindowManager->AirProps(1) + state.dataWindowManager->AirProps(2) * (TGapNew - state.dataWindowManager->TKelvin); QConvGap = RhoAir * AGap * VGap * 1008.0 * (TGapOutlet - TGapInlet); // Exclude convection to gap due to divider, if present; divider convection handled @@ -4670,9 +4670,9 @@ namespace WindowManager { // Initialize face temperatures of shade or blind, if present ShadeFlag = SurfWinShadingFlag(SurfNum); - if (IS_INT_SHADED(SurfWinExtIntShadePrevTS(SurfNum)) || + if (ANY_INTERIOR_SHADE_BLIND(SurfWinExtIntShadePrevTS(SurfNum)) || SurfWinExtIntShadePrevTS(SurfNum) == WinShadingType::ExtShade || SurfWinExtIntShadePrevTS(SurfNum) == WinShadingType::ExtBlind || - IS_BG_SHADED(SurfWinExtIntShadePrevTS(SurfNum))) { + ANY_BETWEENGLASS_SHADE_BLIND(SurfWinExtIntShadePrevTS(SurfNum))) { // Shade or blind is on during the previous TS; use previous-TS values of shade/blind face temps. // Note that if shade or blind is NOT on in the current TS the following two // temperature values, although calculated here, are not used. The shade/blind face numbers @@ -4692,13 +4692,13 @@ namespace WindowManager { // equal to tout. For between-glass shade/blind it is assumed to be equal to the // average temperature of the adjacent glass faces. - if (IS_INT_SHADED(ShadeFlag)) { + if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) { state.dataWindowManager->thetas(state.dataWindowManager->nglface + 1) = state.dataWindowManager->tin + (AbsRadShade(1) + AbsRadShade(2)) / (2 * (state.dataWindowManager->hcin + hrad)); state.dataWindowManager->thetas(state.dataWindowManager->nglface + 2) = state.dataWindowManager->thetas(state.dataWindowManager->nglface + 1); } else if (ShadeFlag == WinShadingType::ExtShade || ShadeFlag == WinShadingType::ExtBlind) { state.dataWindowManager->thetas(state.dataWindowManager->nglface + 1) = state.dataWindowManager->tout + (AbsRadShade(1) + AbsRadShade(2)) / (2 * (state.dataWindowManager->hcout + hrad)); state.dataWindowManager->thetas(state.dataWindowManager->nglface + 2) = state.dataWindowManager->thetas(state.dataWindowManager->nglface + 1); - } else if (IS_BG_SHADED(ShadeFlag)) { + } else if (ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag)) { // Between-glass shade/blind allowed only for double and triple glazing. // The factor 16.0 below is based on a combined convective/radiative heat transfer // coefficient on either side of the shade/blind of 8.0 W/m2-K -- about 1.4 Btu/h-ft2-F. @@ -5898,7 +5898,7 @@ namespace WindowManager { // from the inside surface of the divider goes directly into the zone air -- i.e., the IR radiative // interaction between divider and shade is ignored due to the difficulty of calculating this interaction // at the same time that the interaction between glass and shade is calculated. - if (IS_INT_SHADED(SurfWinShadingFlag(SurfNum))) + if (ANY_INTERIOR_SHADE_BLIND(SurfWinShadingFlag(SurfNum))) SurfWinDividerHeatGain(SurfNum) = DividerHeatGain; DivTempOut = SurfWinDividerTempSurfOut(SurfNum) + state.dataWindowManager->TKelvin; } // End of check if window has dividers @@ -6356,7 +6356,7 @@ namespace WindowManager { hInRad = state.dataWindowManager->emis(state.dataWindowManager->nglface) * state.dataWindowManager->sigma * 0.5 * pow_3(state.dataWindowManager->tin + state.dataWindowManager->thetas(state.dataWindowManager->nglface)); rIn = 1.0 / (hInRad + state.dataWindowManager->hcin); - if (!IS_INT_SHADED(ShadeFlag)) AbsBeamShadeNorm = 0.0; + if (!ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) AbsBeamShadeNorm = 0.0; { auto const SELECT_CASE_var(state.dataWindowManager->ngllayer); From 5bfefa392932e1861c33e579342ed31c2103bdde Mon Sep 17 00:00:00 2001 From: xuanluo113 Date: Wed, 27 Jan 2021 22:21:33 -0800 Subject: [PATCH 31/76] temporary fix --- src/EnergyPlus/DataSurfaces.cc | 2 - src/EnergyPlus/DataSurfaces.hh | 10 +- src/EnergyPlus/DaylightingManager.cc | 8 +- src/EnergyPlus/HeatBalanceSurfaceManager.cc | 51 +++++++--- src/EnergyPlus/SolarShading.cc | 2 +- src/EnergyPlus/SurfaceGeometry.cc | 99 ++++++++----------- src/EnergyPlus/WindowManager.cc | 17 ++-- .../WindowManagerExteriorThermal.cc | 23 ++--- src/EnergyPlus/ZoneTempPredictorCorrector.cc | 13 ++- 9 files changed, 110 insertions(+), 115 deletions(-) diff --git a/src/EnergyPlus/DataSurfaces.cc b/src/EnergyPlus/DataSurfaces.cc index 4d25b38b8b4..e13bdceeba7 100644 --- a/src/EnergyPlus/DataSurfaces.cc +++ b/src/EnergyPlus/DataSurfaces.cc @@ -558,8 +558,6 @@ namespace DataSurfaces { bool AnyHeatBalanceInsideSourceTerm(false); // True if any SurfaceProperty:HeatBalanceSourceTerm inside face used bool AnyHeatBalanceOutsideSourceTerm(false); // True if any SurfaceProperty:HeatBalanceSourceTerm outside face used - // String to item maps. - std::map WindowShadingControlTypeToStr; // SUBROUTINE SPECIFICATIONS FOR MODULE DataSurfaces: diff --git a/src/EnergyPlus/DataSurfaces.hh b/src/EnergyPlus/DataSurfaces.hh index f1b088a0bd1..1794b0a1b54 100644 --- a/src/EnergyPlus/DataSurfaces.hh +++ b/src/EnergyPlus/DataSurfaces.hh @@ -140,10 +140,10 @@ namespace DataSurfaces { SwitchableGlazing = 2, ExtShade = 3, ExtScreen = 4, - IntBlind = 6, - ExtBlind = 7, - BGShade = 8, - BGBlind = 9, + IntBlind = 5, + ExtBlind = 6, + BGShade = 7, + BGBlind = 8, ShadeOff = 10 }; @@ -170,9 +170,7 @@ namespace DataSurfaces { OnHiOutTemp_HiHorzSolar = 19, OnHiZoneTemp_HiSolarWindow = 20, OnHiZoneTemp_HiHorzSolar = 21 - }; - extern std::map WindowShadingControlTypeToStr; // Parameters to indicate exterior boundary conditions for use with // the Surface derived type (see below): diff --git a/src/EnergyPlus/DaylightingManager.cc b/src/EnergyPlus/DaylightingManager.cc index 4c5dc6bed0b..f10e3dab59c 100644 --- a/src/EnergyPlus/DaylightingManager.cc +++ b/src/EnergyPlus/DaylightingManager.cc @@ -5588,7 +5588,7 @@ namespace EnergyPlus::DaylightingManager { } // End of loop over light well objects } - int findWinShadingIndex(int const IWin) { + inline int findWinShadingIndex(int const IWin) { int WinShadingIndex = 1; // 1=unshaded, 2=shaded bool WinShadedNoGlareControl = IS_SHADED(SurfWinShadingFlag(IWin)) && !SurfWinGlareControlIsActive(IWin); if ((SurfWinWindowModelType(IWin) != WindowBSDFModel) && @@ -6281,7 +6281,7 @@ namespace EnergyPlus::DaylightingManager { } } - bool ShadedOrDiffusingGlassWin = (SurfWinWindowModelType(IWin) != WindowBSDFModel) && + bool ShadedOrDiffusingGlassWin = SurfWinWindowModelType(IWin) != WindowBSDFModel && (IS_SHADED(SurfWinShadingFlag(IWin)) || SurfWinSolarDiffusing(IWin)); // Loop over reference points @@ -6645,6 +6645,7 @@ namespace EnergyPlus::DaylightingManager { // Reset shading flag to indicate that window is shaded by being partially or fully switched SurfWinShadingFlag(IWin) = WinShadingType::SwitchableGlazing; + SurfWinGlareControlIsActive(IWin) = false; // ASETIL < 0 means illuminance from non-daylight-switchable windows exceeds setpoint, // so completely switch all daylight-switchable windows to minimize solar gain @@ -6724,7 +6725,6 @@ namespace EnergyPlus::DaylightingManager { Array2D RBACLU( NREFPT, state.dataDaylightingData->ZoneDaylight(ZoneNum).ShadeDeployOrderExtWins.size()); // Background illuminance from window at reference point after closing shade - if (GlareFlag) { // Glare is too high at a ref pt. Loop through windows. int count = 0; @@ -7034,7 +7034,7 @@ namespace EnergyPlus::DaylightingManager { } // end of for(auto IWin : listOfExtWin) if (breakOuterLoop) break; } // for group - } // GlareFlag + } // GlareFlag // Loop again over windows and reset remaining shading flags that // are 10 or higher (i.e., conditionally off) to off diff --git a/src/EnergyPlus/HeatBalanceSurfaceManager.cc b/src/EnergyPlus/HeatBalanceSurfaceManager.cc index cebebc5ddb5..14acb2ad047 100644 --- a/src/EnergyPlus/HeatBalanceSurfaceManager.cc +++ b/src/EnergyPlus/HeatBalanceSurfaceManager.cc @@ -1050,20 +1050,43 @@ namespace HeatBalanceSurfaceManager { PreDefTableEntry(state, state.dataOutRptPredefined->pdchFenSwitchable, surfName, "Yes"); PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscName, surfName, WindowShadingControl(curWSC).Name); // shading report - std::map WindowShadingTypeToStr = { - {WinShadingType::IntShade, "No Shade"}, - {WinShadingType::IntShade, "Interior Shade"}, - {WinShadingType::ExtShade, "Exterior Shade"}, - {WinShadingType::ExtScreen, "Exterior Screen"}, - {WinShadingType::IntBlind, "Interior Blind"}, - {WinShadingType::ExtBlind, "Exterior Blind"}, - {WinShadingType::BGShade, "Between Glass Shade"}, - {WinShadingType::BGBlind, "Between Glass Blind"}, - {WinShadingType::SwitchableGlazing, "Switchable Glazing"} + std::vector WindowShadingTypeStr = { + "No Shade", // WinShadingType::NoShade + "Interior Shade", // WinShadingType::IntShade + "Switchable Glazing", + "Exterior Shade", + "Exterior Screen", + "Interior Blind", + "Exterior Blind", + "Between Glass Shade", + "Between Glass Blind", }; - PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscShading, surfName, WindowShadingTypeToStr[WindowShadingControl(curWSC).ShadingType]); - PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, - DataSurfaces::WindowShadingControlTypeToStr[WindowShadingControl(curWSC).ShadingControlType]); + std::vector WindowShadingControlTypeStr = { + "Uncontrolled", + "AlwaysOn", + "AlwaysOff", + "OnIfScheduleAllows", + "OnIfHighSolarOnWindow", + "OnIfHighHorizontalSolar", + "OnIfHighOutdoorAirTemperature", + "OnIfHighZoneAirTemperature", + "OnIfHighZoneCooling", + "OnIfHighGlare", + "MeetDaylightIlluminanceSetpoint", + "OnNightIfLowOutdoorTempAndOffDay", + "OnNightIfLowInsideTempAndOffDay", + "OnNightIfHeatingAndOffDay", + "OnNightIfLowOutdoorTempAndOnDayIfCooling", + "OnNightIfHeatingAndOnDayIfCooling", + "OffNightAndOnDayIfCoolingAndHighSolarOnWindow", + "OnNightAndOnDayIfCoolingAndHighSolarOnWindow", + "OnIfHighOutdoorAirTempAndHighSolarOnWindow", + "OnIfHighOutdoorAirTempAndHighHorizontalSolar", + "OnIfHighZoneAirTempAndHighSolarOnWindow", + "OnIfHighZoneAirTempAndHighHorizontalSolar" + }; + PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscShading, surfName, WindowShadingTypeStr[int(WindowShadingControl(curWSC).ShadingType)]); + PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscControl, surfName, WindowShadingControlTypeStr[int(WindowShadingControl(curWSC).ShadingControlType)]); // output list of all possible shading contructions for shaded windows including those with storms std::string names = ""; @@ -2886,7 +2909,7 @@ namespace HeatBalanceSurfaceManager { SurfWinExtDiffAbsByShade(SurfNum) *= SurfWinGlazedFrac(SurfNum); if (ShadeFlag == WinShadingType::SwitchableGlazing) { // Switchable glazing - Real64 SwitchFac = SurfWinSwitchingFactor( SurfNum); // Switching factor for switchable glazing + Real64 SwitchFac = SurfWinSwitchingFactor(SurfNum); // Switching factor for switchable glazing for (int Lay = 1; Lay <= TotGlassLay; ++Lay) { AbsDiffWin(Lay) = InterpSw(SwitchFac, AbsDiffWin(Lay), state.dataConstruction->Construct(ConstrNumSh).AbsDiff(Lay)); } diff --git a/src/EnergyPlus/SolarShading.cc b/src/EnergyPlus/SolarShading.cc index f467d8311ba..694a1264c78 100644 --- a/src/EnergyPlus/SolarShading.cc +++ b/src/EnergyPlus/SolarShading.cc @@ -6112,7 +6112,7 @@ namespace SolarShading { CosInc * SunLitFract * SurfaceWindow(SurfNum).OutProjSLFracMult(state.dataGlobal->HourOfDay); } if (!IS_SHADED(ShadeFlag) || SurfWinGlareControlIsActive(SurfNum)) { - // Bare window (ShadeFlag = -1 or 0 or shading device of off) + // (ShadeFlag <= 0 || ShadeFlag >= 10) - Bare window (ShadeFlag = -1 or 0 or shading device of off) for (int Lay = 1; Lay <= NGlass; ++Lay) { // Add contribution of beam reflected from outside and inside reveal SurfWinA(Lay, SurfNum) = AbWin(Lay) + SurfWinOutsRevealDiffOntoGlazing(SurfNum) * state.dataConstruction->Construct(ConstrNum).AbsDiff(Lay) + diff --git a/src/EnergyPlus/SurfaceGeometry.cc b/src/EnergyPlus/SurfaceGeometry.cc index f0a7357ba8a..575697c8120 100644 --- a/src/EnergyPlus/SurfaceGeometry.cc +++ b/src/EnergyPlus/SurfaceGeometry.cc @@ -2038,7 +2038,7 @@ namespace SurfaceGeometry { WinShadingType ShadingType = WindowShadingControl(WinShadingControlPtr).ShadingType; // only for blinds - if (ShadingType == WinShadingType::ExtBlind || ShadingType == WinShadingType::IntBlind || ShadingType == WinShadingType::BGBlind) { + if (ANY_BLIND(ShadingType)) { // TH 1/7/2010. CR 7930 // The old code did not consider between-glass blind. Also there should not be two blinds - both interior and exterior @@ -4831,8 +4831,7 @@ namespace SurfaceGeometry { } } - if (WindowShadingControl(WSCPtr).ShadingType == WinShadingType::BGShade || - WindowShadingControl(WSCPtr).ShadingType == WinShadingType::BGBlind) { + if (ANY_BETWEENGLASS_SHADE_BLIND(WindowShadingControl(WSCPtr).ShadingType)) { // Divider not allowed with between-glass shade or blind if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).FrameDivider > 0) { if (FrameDivider(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).FrameDivider).DividerWidth > 0.0) { @@ -4963,8 +4962,7 @@ namespace SurfaceGeometry { // Divider not allowed with between-glass shade or blind for (int WSCPtr : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).windowShadingControlList) { if (!ErrorsFound && WSCPtr > 0 && ConstrNumSh > 0) { - if (WindowShadingControl(WSCPtr).ShadingType == WinShadingType::BGShade || - WindowShadingControl(WSCPtr).ShadingType == WinShadingType::BGBlind) { + if (ANY_BETWEENGLASS_SHADE_BLIND(WindowShadingControl(WSCPtr).ShadingType)) { if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).FrameDivider > 0) { if (FrameDivider(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).FrameDivider).DividerWidth > 0.0) { ShowSevereError(state, cCurrentModuleObject + "=\"" + state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name + "\", invalid " + @@ -8160,51 +8158,41 @@ namespace SurfaceGeometry { // SUBROUTINE PARAMETER DEFINITIONS: - std::map WindowShadingStrToType = { - {"INTERIORSHADE",WinShadingType::IntShade}, - {"EXTERIORSHADE", WinShadingType::ExtShade}, - {"EXTERIORSCREEN", WinShadingType::ExtScreen}, - {"INTERIORBLIND", WinShadingType::IntBlind}, - {"EXTERIORBLIND", WinShadingType::ExtBlind}, - {"BETWEENGLASSSHADE", WinShadingType::BGShade, }, - {"BETWEENGLASSBLIND", WinShadingType::BGBlind, }, - {"SWITCHABLEGLAZING", WinShadingType::SwitchableGlazing, } - }; - - WindowShadingControlTypeToStr = { - {WindowShadingControlType::UnControlled, "Uncontrolled"}, - {WindowShadingControlType::AlwaysOn, "AlwaysOn"}, - {WindowShadingControlType::AlwaysOff, "AlwaysOff"}, - {WindowShadingControlType::OnIfScheduled, "OnIfScheduleAllows"}, - {WindowShadingControlType::HiSolar, "OnIfHighSolarOnWindow"}, - {WindowShadingControlType::HiHorzSolar, "OnIfHighHorizontalSolar"}, - {WindowShadingControlType::HiOutAirTemp, "OnIfHighOutdoorAirTemperature"}, - {WindowShadingControlType::HiZoneAirTemp, "OnIfHighZoneAirTemperature"}, - {WindowShadingControlType::HiZoneCooling, "OnIfHighZoneCooling"}, - {WindowShadingControlType::HiGlare, "OnIfHighGlare"}, - {WindowShadingControlType::MeetDaylIlumSetp, "MeetDaylightIlluminanceSetpoint"}, - {WindowShadingControlType::OnNightLoOutTemp_OffDay, "OnNightIfLowOutdoorTempAndOffDay"}, - {WindowShadingControlType::OnNightLoInTemp_OffDay, "OnNightIfLowInsideTempAndOffDay"}, - {WindowShadingControlType::OnNightIfHeating_OffDay, "OnNightIfHeatingAndOffDay"}, - {WindowShadingControlType::OnNightLoOutTemp_OnDayCooling, "OnNightIfLowOutdoorTempAndOnDayIfCooling"}, - {WindowShadingControlType::OnNightIfHeating_OnDayCooling, "OnNightIfHeatingAndOnDayIfCooling"}, - {WindowShadingControlType::OffNight_OnDay_HiSolarWindow, "OffNightAndOnDayIfCoolingAndHighSolarOnWindow"}, - {WindowShadingControlType::OnNight_OnDay_HiSolarWindow, "OnNightAndOnDayIfCoolingAndHighSolarOnWindow"}, - {WindowShadingControlType::OnHiOutTemp_HiSolarWindow, "OnIfHighOutdoorAirTempAndHighSolarOnWindow"}, - {WindowShadingControlType::OnHiOutTemp_HiHorzSolar, "OnIfHighOutdoorAirTempAndHighHorizontalSolar"}, - {WindowShadingControlType::OnHiZoneTemp_HiSolarWindow, "OnIfHighZoneAirTempAndHighSolarOnWindow"}, - {WindowShadingControlType::OnHiZoneTemp_HiHorzSolar, "OnIfHighZoneAirTempAndHighHorizontalSolar"} - }; - std::map WindowShadingControlStrToType; - for (auto &type: WindowShadingControlTypeToStr) { - std::string str_type = type.second; - std::transform(str_type.begin(), str_type.end(), str_type.begin(), ::toupper); - WindowShadingControlStrToType.insert({str_type, type.first}); - } - - std::string str = "Hello World"; - - boost::to_upper(str); + int const NumValidShadingTypes(8); + static Array1D_string const cValidShadingTypes(NumValidShadingTypes, + {"INTERIORSHADE", // 1 + "SWITCHABLEGLAZING", // 2 + "EXTERIORSHADE", // 3 + "EXTERIORSCREEN", // 4 + "INTERIORBLIND", // 5 + "EXTERIORBLIND", // 6 + "BETWEENGLASSSHADE", // 7 + "BETWEENGLASSBLIND" // 8 + }); + + int const NumValidWindowShadingControlTypes(21); + static Array1D_string const cValidWindowShadingControlTypes(NumValidWindowShadingControlTypes, + {"ALWAYSON", + "ALWAYSOFF", + "ONIFSCHEDULEALLOWS", + "ONIFHIGHSOLARONWINDOW", + "ONIFHIGHHORIZONTALSOLAR", + "ONIFHIGHOUTDOORAIRTEMPERATURE", + "ONIFHIGHZONEAIRTEMPERATURE", + "ONIFHIGHZONECOOLING", + "ONIFHIGHGLARE", + "MEETDAYLIGHTILLUMINANCESETPOINT", + "ONNIGHTIFLOWOUTDOORTEMPANDOFFDAY", + "ONNIGHTIFLOWINSIDETEMPANDOFFDAY", + "ONNIGHTIFHEATINGANDOFFDAY", + "ONNIGHTIFLOWOUTDOORTEMPANDONDAYIFCOOLING", + "ONNIGHTIFHEATINGANDONDAYIFCOOLING", + "OFFNIGHTANDONDAYIFCOOLINGANDHIGHSOLARONWINDOW", + "ONNIGHTANDONDAYIFCOOLINGANDHIGHSOLARONWINDOW", + "ONIFHIGHOUTDOORAIRTEMPANDHIGHSOLARONWINDOW", + "ONIFHIGHOUTDOORAIRTEMPANDHIGHHORIZONTALSOLAR", + "ONIFHIGHZONEAIRTEMPANDHIGHSOLARONWINDOW", + "ONIFHIGHZONEAIRTEMPANDHIGHHORIZONTALSOLAR"}); // SUBROUTINE LOCAL VARIABLE DECLARATIONS: int IOStat; // IO Status when calling get input subroutine @@ -8397,13 +8385,13 @@ namespace SurfaceGeometry { } // Error if illegal control type - Found = WindowShadingControlStrToType.count(ControlType); + Found = UtilityRoutines::FindItemInList(ControlType, cValidWindowShadingControlTypes, NumValidWindowShadingControlTypes); if (Found == 0) { ErrorsFound = true; ShowSevereError(state, cCurrentModuleObject + "=\"" + WindowShadingControl(ControlNum).Name + "\" invalid " + cAlphaFieldNames(5) + "=\"" + cAlphaArgs(5) + "\"."); } else { - WindowShadingControl(ControlNum).ShadingControlType = WindowShadingControlStrToType[ControlType]; + WindowShadingControl(ControlNum).ShadingControlType = WindowShadingControlType(Found); } // Error checks @@ -8461,13 +8449,13 @@ namespace SurfaceGeometry { } // Check for illegal shading type name - Found = WindowShadingStrToType.count(cAlphaArgs(3)); + Found = UtilityRoutines::FindItemInList(cAlphaArgs(3), cValidShadingTypes, NumValidShadingTypes); if (Found == 0) { ErrorsFound = true; ShowSevereError(state, cCurrentModuleObject + "=\"" + WindowShadingControl(ControlNum).Name + "\" invalid " + cAlphaFieldNames(3) + "=\"" + cAlphaArgs(3) + "\"."); } else { - WindowShadingControl(ControlNum).ShadingType = WindowShadingStrToType[cAlphaArgs(3)]; + WindowShadingControl(ControlNum).ShadingType = WinShadingType(Found); } WinShadingType ShTyp = WindowShadingControl(ControlNum).ShadingType; @@ -9135,8 +9123,7 @@ namespace SurfaceGeometry { if (Surface(SurfNum).HasShadeControl) { for (std::size_t listIndex = 0; listIndex < Surface(SurfNum).windowShadingControlList.size(); ++listIndex) { int WSCPtr = Surface(SurfNum).windowShadingControlList[listIndex]; - if (WindowShadingControl(WSCPtr).ShadingType == WinShadingType::BGShade || - WindowShadingControl(WSCPtr).ShadingType == WinShadingType::BGBlind) { + if (ANY_BETWEENGLASS_SHADE_BLIND(WindowShadingControl(WSCPtr).ShadingType)) { ConstrNumSh = Surface(SurfNum).shadedConstructionList[listIndex]; if (state.dataConstruction->Construct(ConstrNum).TotGlassLayers == 2) { MatGapFlow1 = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(2); diff --git a/src/EnergyPlus/WindowManager.cc b/src/EnergyPlus/WindowManager.cc index a3af326f806..c5c8d7b4a31 100644 --- a/src/EnergyPlus/WindowManager.cc +++ b/src/EnergyPlus/WindowManager.cc @@ -2320,8 +2320,7 @@ namespace WindowManager { // blind/shade and glass 3. IConst = ConstrNum; - if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::ExtShade || ShadeFlag == WinShadingType::IntBlind || ShadeFlag == WinShadingType::ExtBlind || ShadeFlag == WinShadingType::BGShade || - ShadeFlag == WinShadingType::BGBlind || ShadeFlag == WinShadingType::ExtScreen) { + if (ANY_SHADE_SCREEN(ShadeFlag) || ANY_BLIND(ShadeFlag)) { IConst = surface.activeShadedConstruction; if (SurfWinStormWinFlag(SurfNum) > 0) IConst = surface.activeStormWinShadedConstruction; } @@ -3222,7 +3221,7 @@ namespace WindowManager { Aface(5, 6) = -state.dataWindowManager->scon(3); Aface(6, 6) = hr(6) + state.dataWindowManager->scon(3) + state.dataWindowManager->hcin; - if (ShadeFlag != WinShadingType::BGShade && ShadeFlag != WinShadingType::BGBlind && SurfWinAirflowThisTS(SurfNum) > 0.0) { + if (!ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag) && SurfWinAirflowThisTS(SurfNum) > 0.0) { Bface(4) = state.dataWindowManager->AbsRadGlassFace(4) + hcvAirflowGap * TAirflowGapNew; Bface(5) = state.dataWindowManager->AbsRadGlassFace(5) + hcvAirflowGap * TAirflowGapNew; Aface(4, 4) = state.dataWindowManager->scon(2) + hcvAirflowGap - state.dataWindowManager->A45P * hr(4); @@ -3243,9 +3242,7 @@ namespace WindowManager { Aface(8, 7) = -sconsh; Aface(7, 8) = -sconsh; Aface(8, 8) = hr(8) + sconsh + state.dataWindowManager->hcin; - } - - if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) { + } else if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) { Bface(1) = state.dataWindowManager->Outir * state.dataWindowManager->emis(1) * TauShIR / ShGlReflFacIR + hcv * TGapNew + state.dataWindowManager->AbsRadGlassFace(1); Bface(7) = state.dataWindowManager->Outir * EpsShIR1 + state.dataWindowManager->hcout * state.dataWindowManager->tout + AbsRadShadeFace(1); Bface(8) = state.dataWindowManager->Outir * TauShIR * RhoGlIR1 * EpsShIR2 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(2); @@ -3257,9 +3254,7 @@ namespace WindowManager { Aface(1, 8) = -hr(1) * EpsShIR2 / ShGlReflFacIR; Aface(7, 8) = -sconsh; Aface(8, 8) = hr(8) * (1 - RhoGlIR1 * (EpsShIR2 + RhoShIR2)) / ShGlReflFacIR + sconsh + hcv; - } - - if (ShadeFlag == WinShadingType::BGShade || ShadeFlag == WinShadingType::BGBlind) { + } else if (ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag)) { for (i = 1; i <= 8; ++i) { RhoIR(i) = max(0.0, 1.0 - state.dataWindowManager->tir(i) - state.dataWindowManager->emis(i)); } @@ -3538,7 +3533,7 @@ namespace WindowManager { } // Save hcv for use in divider calc with interior or exterior shade (see CalcWinFrameAndDividerTemps) - if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::ExtShade || ShadeFlag == WinShadingType::IntBlind || ShadeFlag == WinShadingType::ExtBlind || ShadeFlag == WinShadingType::ExtScreen) + if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag) || ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) SurfWinConvCoeffWithShade(SurfNum) = hcv; } else { // No convergence after MaxIterations even with relaxed error tolerance @@ -6145,7 +6140,7 @@ namespace WindowManager { if (state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(5)).Group == 5) ShadeFlag = WinShadingType::BGBlind; } - if (ShadeFlag == WinShadingType::BGShade || ShadeFlag == WinShadingType::BGBlind) { + if (ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag)) { errFlag = 2; return; } diff --git a/src/EnergyPlus/WindowManagerExteriorThermal.cc b/src/EnergyPlus/WindowManagerExteriorThermal.cc index d69efe759a2..a233dd830ff 100644 --- a/src/EnergyPlus/WindowManagerExteriorThermal.cc +++ b/src/EnergyPlus/WindowManagerExteriorThermal.cc @@ -110,9 +110,7 @@ namespace WindowManager { // Interior and exterior shading layers have gas between them and IGU but that gas // was not part of construction so it needs to be increased by one - if (SurfWinShadingFlag(SurfNum) == WinShadingType::IntShade || SurfWinShadingFlag(SurfNum) == WinShadingType::ExtShade || SurfWinShadingFlag(SurfNum) == WinShadingType::IntBlind || - SurfWinShadingFlag(SurfNum) == WinShadingType::ExtBlind || SurfWinShadingFlag(SurfNum) == WinShadingType::ExtScreen || SurfWinShadingFlag(SurfNum) == WinShadingType::BGShade || - SurfWinShadingFlag(SurfNum) == WinShadingType::BGBlind) { + if (ANY_SHADE_SCREEN(SurfWinShadingFlag(SurfNum)) || ANY_BLIND(SurfWinShadingFlag(SurfNum))) { ++totSolidLayers; } @@ -141,7 +139,7 @@ namespace WindowManager { ++i; } SurfInsideTemp = aTemp - DataGlobalConstants::KelvinConv; - if (SurfWinShadingFlag(SurfNum) == WinShadingType::IntShade || SurfWinShadingFlag(SurfNum) == WinShadingType::IntBlind) { + if (ANY_INTERIOR_SHADE_BLIND(SurfWinShadingFlag(SurfNum))) { auto EffShBlEmiss = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), window.EffShBlindEmiss); auto EffGlEmiss = InterpSlatAng(SurfWinSlatAngThisTS(SurfNum), SurfWinMovableSlats(SurfNum), window.EffGlassEmiss); SurfWinEffInsSurfTemp(SurfNum) = @@ -150,7 +148,7 @@ namespace WindowManager { } HConvIn(SurfNum) = aSystem->getHc(Environment::Indoor); - if (SurfWinShadingFlag(SurfNum) == WinShadingType::IntShade || SurfWinShadingFlag(SurfNum) == WinShadingType::IntBlind || aFactory.isInteriorShade()) { + if (ANY_INTERIOR_SHADE_BLIND(SurfWinShadingFlag(SurfNum))|| aFactory.isInteriorShade()) { // It is not clear why EnergyPlus keeps this interior calculations separately for interior shade. This does create different // solution from heat transfer from tarcog itself. Need to confirm with LBNL team about this approach. Note that heat flow // through shade (consider case when openings are zero) is different from heat flow obtained by these equations. Will keep @@ -248,23 +246,22 @@ namespace WindowManager { m_ConstructionNumber = m_Surface.Construction; m_ShadePosition = ShadePosition::NoShade; - if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::ExtShade || ShadeFlag == WinShadingType::IntBlind || ShadeFlag == WinShadingType::ExtBlind || ShadeFlag == WinShadingType::BGShade || - ShadeFlag == WinShadingType::BGBlind || ShadeFlag == WinShadingType::ExtScreen) { + if (ANY_SHADE_SCREEN(ShadeFlag) || ANY_BLIND(ShadeFlag)) { m_ConstructionNumber = m_Surface.activeShadedConstruction; if (SurfWinStormWinFlag(t_SurfNum) > 0) m_ConstructionNumber = m_Surface.activeStormWinShadedConstruction; } m_TotLay = getNumOfLayers(state); - if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::IntBlind) { + if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) { m_ShadePosition = ShadePosition::Interior; } - if (ShadeFlag == WinShadingType::ExtShade || ShadeFlag == WinShadingType::ExtBlind || ShadeFlag == WinShadingType::ExtScreen) { + if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) { m_ShadePosition = ShadePosition::Exterior; } - if (ShadeFlag == WinShadingType::BGShade || ShadeFlag == WinShadingType::BGBlind) { + if (ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag)) { m_ShadePosition = ShadePosition::Between; } } @@ -303,9 +300,7 @@ namespace WindowManager { { auto ConstrNum = m_Surface.Construction; - if (SurfWinShadingFlag(m_SurfNum) == WinShadingType::IntShade || SurfWinShadingFlag(m_SurfNum) == WinShadingType::ExtShade || SurfWinShadingFlag(m_SurfNum) == WinShadingType::IntBlind || - SurfWinShadingFlag(m_SurfNum) == WinShadingType::ExtBlind || SurfWinShadingFlag(m_SurfNum) == WinShadingType::BGShade || SurfWinShadingFlag(m_SurfNum) == WinShadingType::BGBlind || - SurfWinShadingFlag(m_SurfNum) == WinShadingType::ExtScreen) { + if (ANY_SHADE_SCREEN(SurfWinShadingFlag(m_SurfNum)) || ANY_BLIND(SurfWinShadingFlag(m_SurfNum))) { ConstrNum = m_Surface.activeShadedConstruction; if (SurfWinStormWinFlag(m_SurfNum) > 0) ConstrNum = m_Surface.activeStormWinShadedConstruction; } @@ -499,7 +494,7 @@ namespace WindowManager { auto aGas = getAir(); auto thickness = 0.0; - if (SurfWinShadingFlag(m_SurfNum) == WinShadingType::IntBlind || SurfWinShadingFlag(m_SurfNum) == WinShadingType::ExtBlind) { + if (ANY_INTERIOR_SHADE_BLIND(SurfWinShadingFlag(m_SurfNum))) { thickness = Blind(SurfWinBlindNumber(m_SurfNum)).BlindToGlassDist; } if (SurfWinShadingFlag(m_SurfNum) == WinShadingType::IntShade || SurfWinShadingFlag(m_SurfNum) == WinShadingType::ExtShade || SurfWinShadingFlag(m_SurfNum) == WinShadingType::ExtScreen) { diff --git a/src/EnergyPlus/ZoneTempPredictorCorrector.cc b/src/EnergyPlus/ZoneTempPredictorCorrector.cc index 48bbbde7c5a..3acc3ce46ef 100644 --- a/src/EnergyPlus/ZoneTempPredictorCorrector.cc +++ b/src/EnergyPlus/ZoneTempPredictorCorrector.cc @@ -6257,7 +6257,7 @@ namespace ZoneTempPredictorCorrector { auto const shading_flag(SurfWinShadingFlag(SurfNum)); // Add to the convective internal gains - if (shading_flag == WinShadingType::IntShade || shading_flag == WinShadingType::IntBlind) { + if (ANY_INTERIOR_SHADE_BLIND(shading_flag)) { // The shade area covers the area of the glazing plus the area of the dividers. Area += SurfWinDividerArea(SurfNum); // If interior shade or blind is present it is assumed that both the convective and IR radiative gain @@ -6271,7 +6271,7 @@ namespace ZoneTempPredictorCorrector { if (state.dataConstruction->Construct(Surface(SurfNum).Construction).WindowTypeEQL) SumIntGain += SurfWinOtherConvHeatGain(SurfNum); // Convective heat gain from natural convection in gap between glass and interior shade or blind - if (shading_flag == WinShadingType::IntShade || shading_flag == WinShadingType::IntBlind) SumIntGain += SurfWinConvHeatFlowNatural(SurfNum); + if (ANY_INTERIOR_SHADE_BLIND(shading_flag)) SumIntGain += SurfWinConvHeatFlowNatural(SurfNum); // Convective heat gain from airflow window if (SurfWinAirflowThisTS(SurfNum) > 0.0) { @@ -6299,7 +6299,7 @@ namespace ZoneTempPredictorCorrector { HA += HA_surf; } - if (SurfWinDividerArea(SurfNum) > 0.0 && shading_flag != WinShadingType::IntShade && shading_flag != WinShadingType::IntBlind) { + if (SurfWinDividerArea(SurfNum) > 0.0 && !ANY_INTERIOR_SHADE_BLIND(shading_flag)) { // Window divider contribution (only from shade or blind for window with divider and interior shade or blind) Real64 const HA_surf(HConvIn(SurfNum) * SurfWinDividerArea(SurfNum) * (1.0 + 2.0 * SurfWinProjCorrDivIn(SurfNum))); SumHATsurf += HA_surf * SurfWinDividerTempSurfIn(SurfNum); @@ -6588,7 +6588,7 @@ namespace ZoneTempPredictorCorrector { if (Surface(SurfNum).Class == SurfaceClass::Window) { // Add to the convective internal gains - if (SurfWinShadingFlag(SurfNum) == WinShadingType::IntShade || SurfWinShadingFlag(SurfNum) == WinShadingType::IntBlind) { + if (ANY_INTERIOR_SHADE_BLIND(SurfWinShadingFlag(SurfNum))) { // The shade area covers the area of the glazing plus the area of the dividers. Area += SurfWinDividerArea(SurfNum); // If interior shade or blind is present it is assumed that both the convective and IR radiative gain @@ -6602,7 +6602,7 @@ namespace ZoneTempPredictorCorrector { if (state.dataConstruction->Construct(Surface(SurfNum).Construction).WindowTypeEQL) SumIntGains += SurfWinOtherConvHeatGain(SurfNum); // Convective heat gain from natural convection in gap between glass and interior shade or blind - if (SurfWinShadingFlag(SurfNum) == WinShadingType::IntShade || SurfWinShadingFlag(SurfNum) == WinShadingType::IntBlind) + if (ANY_INTERIOR_SHADE_BLIND(SurfWinShadingFlag(SurfNum))) SumIntGains += SurfWinConvHeatFlowNatural(SurfNum); // Convective heat gain from airflow window @@ -6621,8 +6621,7 @@ namespace ZoneTempPredictorCorrector { (SurfWinFrameTempSurfIn(SurfNum) - RefAirTemp); } - if (SurfWinDividerArea(SurfNum) > 0.0 && SurfWinShadingFlag(SurfNum) != WinShadingType::IntShade && - SurfWinShadingFlag(SurfNum) != WinShadingType::IntBlind) { + if (SurfWinDividerArea(SurfNum) > 0.0 && !ANY_INTERIOR_SHADE_BLIND(SurfWinShadingFlag(SurfNum))) { // Window divider contribution (only from shade or blind for window with divider and interior shade or blind) SumHADTsurfs += HConvIn(SurfNum) * SurfWinDividerArea(SurfNum) * (1.0 + 2.0 * SurfWinProjCorrDivIn(SurfNum)) * (SurfWinDividerTempSurfIn(SurfNum) - RefAirTemp); From 45edddf06a583f2e460cb113e8c4bbe79d839870 Mon Sep 17 00:00:00 2001 From: xuanluo113 Date: Fri, 29 Jan 2021 13:28:04 -0800 Subject: [PATCH 32/76] EMS value --- src/EnergyPlus/DataSurfaces.cc | 2 +- src/EnergyPlus/DataSurfaces.hh | 21 ++++----- src/EnergyPlus/EMSManager.cc | 4 +- src/EnergyPlus/HeatBalanceSurfaceManager.cc | 5 ++- src/EnergyPlus/SolarShading.cc | 45 ++++++++++++++++++- src/EnergyPlus/SolarShading.hh | 2 + src/EnergyPlus/SurfaceGeometry.cc | 23 +++++----- .../WindowManagerExteriorThermal.cc | 2 +- testfiles/EMSConstantVolumePurchasedAir.idf | 2 +- tst/EnergyPlus/unit/EMSManager.unit.cc | 6 +-- 10 files changed, 80 insertions(+), 32 deletions(-) diff --git a/src/EnergyPlus/DataSurfaces.cc b/src/EnergyPlus/DataSurfaces.cc index e13bdceeba7..83cbd79a371 100644 --- a/src/EnergyPlus/DataSurfaces.cc +++ b/src/EnergyPlus/DataSurfaces.cc @@ -462,7 +462,7 @@ namespace DataSurfaces { Array1D SurfWinShadingFlag; // -1: window has no shading device Array1D SurfWinShadingFlagEMSOn; // EMS control flag, true if EMS is controlling ShadingFlag with ShadingFlagEMSValue - Array1D SurfWinShadingFlagEMSValue; // EMS control value for Shading Flag + Array1D SurfWinShadingFlagEMSValue; // EMS control value for Shading Flag Array1D SurfWinGlareControlIsActive; // True if glare control is active Array1D SurfWinStormWinFlag; // -1: Storm window not applicable; 0: Window has storm window but it is off 1: Window has storm window and it is on Array1D SurfWinStormWinFlagPrevDay; // Previous time step value of StormWinFlag diff --git a/src/EnergyPlus/DataSurfaces.hh b/src/EnergyPlus/DataSurfaces.hh index 1794b0a1b54..bc40a9b8376 100644 --- a/src/EnergyPlus/DataSurfaces.hh +++ b/src/EnergyPlus/DataSurfaces.hh @@ -135,16 +135,17 @@ namespace DataSurfaces { }; enum class WinShadingType : int { + INVALID = -1, NoShade = 0, - IntShade = 1, - SwitchableGlazing = 2, - ExtShade = 3, - ExtScreen = 4, - IntBlind = 5, - ExtBlind = 6, - BGShade = 7, - BGBlind = 8, - ShadeOff = 10 + ShadeOff = 1, + IntShade = 2, + SwitchableGlazing = 3, + ExtShade = 4, + ExtScreen = 5, + IntBlind = 6, + ExtBlind = 7, + BGShade = 8, + BGBlind = 9 }; enum class WindowShadingControlType : int{ @@ -521,7 +522,7 @@ namespace DataSurfaces { extern Array1D SurfWinShadingFlag; // -1: window has no shading device extern Array1D SurfWinShadingFlagEMSOn; // EMS control flag, true if EMS is controlling ShadingFlag with ShadingFlagEMSValue - extern Array1D SurfWinShadingFlagEMSValue; // EMS control value for Shading Flag + extern Array1D SurfWinShadingFlagEMSValue; // EMS control value for Shading Flag extern Array1D SurfWinGlareControlIsActive; // True if glare control is active extern Array1D SurfWinStormWinFlag; // -1: Storm window not applicable; 0: Window has storm window but it is off 1: Window has storm window and it is on extern Array1D SurfWinStormWinFlagPrevDay; // Previous time step value of StormWinFlag diff --git a/src/EnergyPlus/EMSManager.cc b/src/EnergyPlus/EMSManager.cc index 2ca54ac3eb9..13901a57f09 100644 --- a/src/EnergyPlus/EMSManager.cc +++ b/src/EnergyPlus/EMSManager.cc @@ -1891,7 +1891,7 @@ namespace EMSManager { "Control Status", "[ShadeStatus]", DataSurfaces::SurfWinShadingFlagEMSOn(loopSurfNum), - (int &)DataSurfaces::SurfWinShadingFlagEMSValue(loopSurfNum)); + DataSurfaces::SurfWinShadingFlagEMSValue(loopSurfNum)); if (DataSurfaces::SurfWinMovableSlats(loopSurfNum)) { SetupEMSActuator(state, "Window Shading Control", Surface(loopSurfNum).Name, @@ -1906,7 +1906,7 @@ namespace EMSManager { "Control Status", "[ShadeStatus]", DataSurfaces::SurfWinShadingFlagEMSOn(loopSurfNum), - (int &)DataSurfaces::SurfWinShadingFlagEMSValue(loopSurfNum)); + DataSurfaces::SurfWinShadingFlagEMSValue(loopSurfNum)); } else { if (WindowShadingControl(Surface(loopSurfNum).activeWindowShadingControl).ShadingType != WinShadingType::SwitchableGlazing) { ShowSevereError(state, "Missing shade or blind layer in window construction name = '" + diff --git a/src/EnergyPlus/HeatBalanceSurfaceManager.cc b/src/EnergyPlus/HeatBalanceSurfaceManager.cc index 14acb2ad047..052d7fb753c 100644 --- a/src/EnergyPlus/HeatBalanceSurfaceManager.cc +++ b/src/EnergyPlus/HeatBalanceSurfaceManager.cc @@ -1051,8 +1051,9 @@ namespace HeatBalanceSurfaceManager { PreDefTableEntry(state, state.dataOutRptPredefined->pdchWscName, surfName, WindowShadingControl(curWSC).Name); // shading report std::vector WindowShadingTypeStr = { - "No Shade", // WinShadingType::NoShade - "Interior Shade", // WinShadingType::IntShade + "No Shade", // 0 + "Shade Off", // 1 + "Interior Shade", "Switchable Glazing", "Exterior Shade", "Exterior Screen", diff --git a/src/EnergyPlus/SolarShading.cc b/src/EnergyPlus/SolarShading.cc index 694a1264c78..065f9a950b4 100644 --- a/src/EnergyPlus/SolarShading.cc +++ b/src/EnergyPlus/SolarShading.cc @@ -9128,12 +9128,55 @@ namespace SolarShading { // EMS Actuator Point: override setting if ems flag on if (SurfWinShadingFlagEMSOn(ISurf)) { - SurfWinShadingFlag(ISurf) = SurfWinShadingFlagEMSValue(ISurf); + WinShadingType SurfWinShadingFlagEMS = findValueInEnumeration(SurfWinShadingFlagEMSValue(ISurf)); + if (SurfWinShadingFlagEMS != WinShadingType::INVALID) { + SurfWinShadingFlag(ISurf) = SurfWinShadingFlagEMS; + } else { + ShowWarningError(state, "Invalid EMS value of Window Shading Control Type for Surface " + + Surface(ISurf).Name); + } } } // End of surface loop } } + DataSurfaces::WinShadingType findValueInEnumeration(Real64 controlValue) { + // This is a workaround to translate EMS Shading control numerical values + // EMS control of window shading devices involves setting the control values for shading control actuators with + // one of these values. The variable names can be used or replaced, it is the whole number values that trigger + // changes in the modeling. + // Shades and Blinds are either fully on or fully off, partial positions require multiple windows. + // the window shading control flag values follow + // -1: if window has no shading device + // 0: if shading device is off + // 1: if interior shade is on + // 2: if glazing is switched to darker state + // 3: if exterior shade is on + // 4: if exterior screen is on + // 6: if interior blind is on + // 7: if exterior blind is on + // 8: if between-glass shade is on + // 9: if between-glass blind is on + // 10: window has interior shade that is off but may be triggered on later to control daylight glare + // 20: window has switchable glazing that is unswitched but may be switched later to control daylight glare or daylight illuminance + // 30: window has exterior shade that is off but may be triggered on later to control daylight glare or daylight illuminance + // 60: window has interior blind that is off but may be triggered on later to control daylight glare or daylight illuminance + // 70: window has exterior blind that is off but may be triggered on later to control daylight glare or daylight illuminance + // 80: window has between-glass shade that is off but may be triggered on later to control daylight glare or daylight illuminance + // 90: window has between-glass blind that is off but may be triggered on later to control daylight glare or daylight illuminance + if (controlValue == -1.0) return WinShadingType::NoShade; + if (controlValue == 0.0) return WinShadingType::ShadeOff; + if (controlValue == 1.0) return WinShadingType::IntShade; + if (controlValue == 2.0) return WinShadingType::SwitchableGlazing; + if (controlValue == 3.0) return WinShadingType::ExtShade; + if (controlValue == 4.0) return WinShadingType::ExtScreen; + if (controlValue == 6.0) return WinShadingType::IntBlind; + if (controlValue == 7.0) return WinShadingType::ExtBlind; + if (controlValue == 8.0) return WinShadingType::BGShade; + if (controlValue == 9.0) return WinShadingType::BGBlind; + return WinShadingType::INVALID; + } + int selectActiveWindowShadingControlIndex(EnergyPlusData &state, int curSurface) { // For a given surface, determine based on the schedules which index to the window shading control list vector should be active diff --git a/src/EnergyPlus/SolarShading.hh b/src/EnergyPlus/SolarShading.hh index 2949c3cb6eb..12ea05acb1c 100644 --- a/src/EnergyPlus/SolarShading.hh +++ b/src/EnergyPlus/SolarShading.hh @@ -273,6 +273,8 @@ namespace SolarShading { void WindowShadingManager(EnergyPlusData &state); + DataSurfaces::WinShadingType findValueInEnumeration(Real64 controlValue); + int selectActiveWindowShadingControlIndex(EnergyPlusData &state, int curSurface); void WindowGapAirflowControl(EnergyPlusData &state); diff --git a/src/EnergyPlus/SurfaceGeometry.cc b/src/EnergyPlus/SurfaceGeometry.cc index 575697c8120..d797090751e 100644 --- a/src/EnergyPlus/SurfaceGeometry.cc +++ b/src/EnergyPlus/SurfaceGeometry.cc @@ -161,7 +161,7 @@ namespace SurfaceGeometry { SurfWinShadingFlag.dimension(NumSurfaces, WinShadingType::ShadeOff); SurfWinShadingFlagEMSOn.dimension(NumSurfaces, 0); - SurfWinShadingFlagEMSValue.dimension(NumSurfaces, WinShadingType::ShadeOff); + SurfWinShadingFlagEMSValue.dimension(NumSurfaces, 0.0); SurfWinGlareControlIsActive.dimension(NumSurfaces, false); SurfWinStormWinFlag.dimension(NumSurfaces, 0); SurfWinStormWinFlagPrevDay.dimension(NumSurfaces, 0); @@ -8158,16 +8158,17 @@ namespace SurfaceGeometry { // SUBROUTINE PARAMETER DEFINITIONS: - int const NumValidShadingTypes(8); + int const NumValidShadingTypes(9); static Array1D_string const cValidShadingTypes(NumValidShadingTypes, - {"INTERIORSHADE", // 1 - "SWITCHABLEGLAZING", // 2 - "EXTERIORSHADE", // 3 - "EXTERIORSCREEN", // 4 - "INTERIORBLIND", // 5 - "EXTERIORBLIND", // 6 - "BETWEENGLASSSHADE", // 7 - "BETWEENGLASSBLIND" // 8 + {"SHADEOFF", // 1 + "INTERIORSHADE", // 2 + "SWITCHABLEGLAZING", // 3 + "EXTERIORSHADE", // 4 + "EXTERIORSCREEN", // 5 + "INTERIORBLIND", // 6 + "EXTERIORBLIND", // 7 + "BETWEENGLASSSHADE", // 8 + "BETWEENGLASSBLIND" // 9 }); int const NumValidWindowShadingControlTypes(21); @@ -8450,7 +8451,7 @@ namespace SurfaceGeometry { // Check for illegal shading type name Found = UtilityRoutines::FindItemInList(cAlphaArgs(3), cValidShadingTypes, NumValidShadingTypes); - if (Found == 0) { + if (Found > 1) { ErrorsFound = true; ShowSevereError(state, cCurrentModuleObject + "=\"" + WindowShadingControl(ControlNum).Name + "\" invalid " + cAlphaFieldNames(3) + "=\"" + cAlphaArgs(3) + "\"."); diff --git a/src/EnergyPlus/WindowManagerExteriorThermal.cc b/src/EnergyPlus/WindowManagerExteriorThermal.cc index a233dd830ff..c566d4420d8 100644 --- a/src/EnergyPlus/WindowManagerExteriorThermal.cc +++ b/src/EnergyPlus/WindowManagerExteriorThermal.cc @@ -494,7 +494,7 @@ namespace WindowManager { auto aGas = getAir(); auto thickness = 0.0; - if (ANY_INTERIOR_SHADE_BLIND(SurfWinShadingFlag(m_SurfNum))) { + if (SurfWinShadingFlag(m_SurfNum) == WinShadingType::IntBlind || SurfWinShadingFlag(m_SurfNum) == WinShadingType::ExtBlind) { thickness = Blind(SurfWinBlindNumber(m_SurfNum)).BlindToGlassDist; } if (SurfWinShadingFlag(m_SurfNum) == WinShadingType::IntShade || SurfWinShadingFlag(m_SurfNum) == WinShadingType::ExtShade || SurfWinShadingFlag(m_SurfNum) == WinShadingType::ExtScreen) { diff --git a/testfiles/EMSConstantVolumePurchasedAir.idf b/testfiles/EMSConstantVolumePurchasedAir.idf index 180e2a14452..e7766d90524 100644 --- a/testfiles/EMSConstantVolumePurchasedAir.idf +++ b/testfiles/EMSConstantVolumePurchasedAir.idf @@ -1515,7 +1515,7 @@ , !- EMS Program or Subroutine Name ; !- Units - EnergyManagementSystem:OutputVariable, +1.0 EnergyManagementSystem:OutputVariable, Erl Zn001:Wall001:Win001 Incident Angle, !- Name IncidentAngle, !- EMS Variable Name Averaged, !- Type of Data in Variable diff --git a/tst/EnergyPlus/unit/EMSManager.unit.cc b/tst/EnergyPlus/unit/EMSManager.unit.cc index 129fa7c0a58..b8b886e3d6f 100644 --- a/tst/EnergyPlus/unit/EMSManager.unit.cc +++ b/tst/EnergyPlus/unit/EMSManager.unit.cc @@ -1621,16 +1621,16 @@ TEST_F(EnergyPlusFixture, EMSManager_TestWindowShadingControlExteriorScreenOptio SetupWindowShadingControlActuators(*state); EXPECT_FALSE(DataSurfaces::SurfWinShadingFlagEMSOn(2)); - EXPECT_EQ(DataSurfaces::SurfWinShadingFlagEMSValue(2), DataSurfaces::WinShadingType::ShadeOff); + EXPECT_EQ(DataSurfaces::SurfWinShadingFlagEMSValue(2), 0.0); DataHeatBalance::Zone.allocate(1); DataHeatBalance::Zone(1).WindowSurfaceFirst = 1; DataHeatBalance::Zone(1).WindowSurfaceLast = 2; state->dataGlobal->NumOfZones = 1; DataSurfaces::SurfWinShadingFlagEMSOn(2) = true; - DataSurfaces::SurfWinShadingFlagEMSValue(2) = DataSurfaces::WinShadingType::IntShade; + DataSurfaces::SurfWinShadingFlagEMSValue(2) = 1.0; // WinShadingType::IntShade SolarShading::WindowShadingManager(*state); - EXPECT_EQ(DataSurfaces::SurfWinShadingFlag(2), DataSurfaces::SurfWinShadingFlagEMSValue(2)); + EXPECT_EQ(DataSurfaces::SurfWinShadingFlag(2), DataSurfaces::WinShadingType::IntShade); } TEST_F(EnergyPlusFixture, EMS_WeatherDataActuators) From e99c7feb140d66a5601a6d4cb8e35905a0480c93 Mon Sep 17 00:00:00 2001 From: xuanluo113 Date: Fri, 29 Jan 2021 15:12:33 -0800 Subject: [PATCH 33/76] EMS value --- src/EnergyPlus/SurfaceGeometry.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EnergyPlus/SurfaceGeometry.cc b/src/EnergyPlus/SurfaceGeometry.cc index d797090751e..5c74d3eae25 100644 --- a/src/EnergyPlus/SurfaceGeometry.cc +++ b/src/EnergyPlus/SurfaceGeometry.cc @@ -8451,7 +8451,7 @@ namespace SurfaceGeometry { // Check for illegal shading type name Found = UtilityRoutines::FindItemInList(cAlphaArgs(3), cValidShadingTypes, NumValidShadingTypes); - if (Found > 1) { + if (Found <= 1) { ErrorsFound = true; ShowSevereError(state, cCurrentModuleObject + "=\"" + WindowShadingControl(ControlNum).Name + "\" invalid " + cAlphaFieldNames(3) + "=\"" + cAlphaArgs(3) + "\"."); From 6bb6ae4397bcb9e045451e685c0db533b968a263 Mon Sep 17 00:00:00 2001 From: xuanluo113 Date: Fri, 29 Jan 2021 18:05:23 -0800 Subject: [PATCH 34/76] fix glare control logic --- src/EnergyPlus/DataSurfaces.cc | 4 +- src/EnergyPlus/DataSurfaces.hh | 30 ++++- src/EnergyPlus/DaylightingManager.cc | 32 +++-- src/EnergyPlus/HeatBalanceIntRadExchange.cc | 2 +- src/EnergyPlus/HeatBalanceSurfaceManager.cc | 8 +- src/EnergyPlus/SolarShading.cc | 134 ++++++++++---------- src/EnergyPlus/SurfaceGeometry.cc | 1 - src/EnergyPlus/WindowManager.cc | 2 +- testfiles/EMSConstantVolumePurchasedAir.idf | 2 +- 9 files changed, 120 insertions(+), 95 deletions(-) diff --git a/src/EnergyPlus/DataSurfaces.cc b/src/EnergyPlus/DataSurfaces.cc index 83cbd79a371..b905c74d5dd 100644 --- a/src/EnergyPlus/DataSurfaces.cc +++ b/src/EnergyPlus/DataSurfaces.cc @@ -462,8 +462,7 @@ namespace DataSurfaces { Array1D SurfWinShadingFlag; // -1: window has no shading device Array1D SurfWinShadingFlagEMSOn; // EMS control flag, true if EMS is controlling ShadingFlag with ShadingFlagEMSValue - Array1D SurfWinShadingFlagEMSValue; // EMS control value for Shading Flag - Array1D SurfWinGlareControlIsActive; // True if glare control is active + Array1D SurfWinShadingFlagEMSValue; // EMS control value for Shading Flag Array1D SurfWinStormWinFlag; // -1: Storm window not applicable; 0: Window has storm window but it is off 1: Window has storm window and it is on Array1D SurfWinStormWinFlagPrevDay; // Previous time step value of StormWinFlag Array1D SurfWinFracTimeShadingDeviceOn; // For a single time step, = 0.0 if no shading device or shading device is off = 1.0 if shading device is on; For time intervals longer than a time step, = fraction of time that shading device is on. @@ -1278,7 +1277,6 @@ namespace DataSurfaces { SurfWinShadingFlag.clear(); SurfWinShadingFlagEMSOn.clear(); SurfWinShadingFlagEMSValue.clear(); - SurfWinGlareControlIsActive.clear(); SurfWinStormWinFlag.clear(); SurfWinStormWinFlagPrevDay.clear(); SurfWinFracTimeShadingDeviceOn.clear(); diff --git a/src/EnergyPlus/DataSurfaces.hh b/src/EnergyPlus/DataSurfaces.hh index bc40a9b8376..f5bc5729a29 100644 --- a/src/EnergyPlus/DataSurfaces.hh +++ b/src/EnergyPlus/DataSurfaces.hh @@ -69,7 +69,21 @@ #define BITF(B) (1 << (int(B))) #define BITF_TEST_ANY(V, B) (((V) & (B)) != 0) -#define IS_SHADED(SHADE_FLAG) !BITF_TEST_ANY(BITF(SHADE_FLAG), BITF(WinShadingType::NoShade) | BITF(WinShadingType::ShadeOff)) +// IS_SHADED is the flag to indicate window has no shading device or shading device is off, and no daylight glare control +// original expression: SHADE_FLAG == ShadeOff || SHADE_FLAG == ShadeOff +#define NOT_SHADED(SHADE_FLAG) BITF_TEST_ANY(BITF(SHADE_FLAG), BITF(WinShadingType::NoShade) | BITF(WinShadingType::ShadeOff)) + +// IS_SHADED is the flag to indicate window has shade on or temporarily off but may be triggered on later to control daylight glare +// original expression: SHADE_FLAG > ShadeOff +#define IS_SHADED(SHADE_FLAG) !NOT_SHADED(SHADE_FLAG) + +// IS_SHADED_NO_GLARE is the flag to indicate window has shade and no daylight glare control +// original expression: IntShade <= SHADE_FLAG <= BGBlind +#define IS_SHADED_NO_GLARE_CTRL(SHADE_FLAG) BITF_TEST_ANY(BITF(SHADE_FLAG), \ + BITF(WinShadingType::IntShade) | BITF(WinShadingType::SwitchableGlazing) | BITF(WinShadingType::ExtShade) | BITF(WinShadingType::ExtScreen) |\ + BITF(WinShadingType::IntBlind) | BITF(WinShadingType::ExtBlind) | BITF(WinShadingType::BGShade) | BITF(WinShadingType::BGBlind)) + +// ANY_SHADE: if SHADE_FLAG is any of the shading types including interior, exterior or between glass shades #define ANY_SHADE(SHADE_FLAG) BITF_TEST_ANY(BITF(SHADE_FLAG), BITF(WinShadingType::IntShade) | BITF(WinShadingType::ExtShade) | BITF(WinShadingType::BGShade)) #define ANY_SHADE_SCREEN(SHADE_FLAG) BITF_TEST_ANY(BITF(SHADE_FLAG), BITF(WinShadingType::IntShade) | BITF(WinShadingType::ExtShade) | BITF(WinShadingType::BGShade) | BITF(WinShadingType::ExtScreen)) #define ANY_BLIND(SHADE_FLAG) BITF_TEST_ANY(BITF(SHADE_FLAG), BITF(WinShadingType::IntBlind) | BITF(WinShadingType::ExtBlind) | BITF(WinShadingType::BGBlind)) @@ -145,7 +159,12 @@ namespace DataSurfaces { IntBlind = 6, ExtBlind = 7, BGShade = 8, - BGBlind = 9 + BGBlind = 9, + IntShadeConditionallyOff = 10, + GlassConditionallyLightened = 11, + ExtShadeConditionallyOff = 12, + IntBlindConditionallyOff = 13, + ExtBlindConditionallyOff = 14 }; enum class WindowShadingControlType : int{ @@ -520,14 +539,13 @@ namespace DataSurfaces { extern Array1D SurfWinProfileAngHor; // Horizontal beam solar profile angle (degrees) extern Array1D SurfWinProfileAngVert; // Vertical beam solar profile angle (degrees) - extern Array1D SurfWinShadingFlag; // -1: window has no shading device + extern Array1D SurfWinShadingFlag; // -1: window has no shading device extern Array1D SurfWinShadingFlagEMSOn; // EMS control flag, true if EMS is controlling ShadingFlag with ShadingFlagEMSValue - extern Array1D SurfWinShadingFlagEMSValue; // EMS control value for Shading Flag - extern Array1D SurfWinGlareControlIsActive; // True if glare control is active + extern Array1D SurfWinShadingFlagEMSValue; // EMS control value for Shading Flag extern Array1D SurfWinStormWinFlag; // -1: Storm window not applicable; 0: Window has storm window but it is off 1: Window has storm window and it is on extern Array1D SurfWinStormWinFlagPrevDay; // Previous time step value of StormWinFlag extern Array1D SurfWinFracTimeShadingDeviceOn; // For a single time step, = 0.0 if no shading device or shading device is off = 1.0 if shading device is on; For time intervals longer than a time step, = fraction of time that shading device is on. - extern Array1D SurfWinExtIntShadePrevTS; // 1 if exterior or interior blind or shade in place previous time step;0 otherwise + extern Array1D SurfWinExtIntShadePrevTS; // 1 if exterior or interior blind or shade in place previous time step;0 otherwise extern Array1D SurfWinHasShadeOrBlindLayer; // mark as true if the window construction has a shade or a blind layer extern Array1D SurfWinSurfDayLightInit; // surface has been initialized for following 5 arrays extern Array1D SurfWinDaylFacPoint; // Pointer to daylight factors for the window diff --git a/src/EnergyPlus/DaylightingManager.cc b/src/EnergyPlus/DaylightingManager.cc index f10e3dab59c..e25ea4a7227 100644 --- a/src/EnergyPlus/DaylightingManager.cc +++ b/src/EnergyPlus/DaylightingManager.cc @@ -5590,7 +5590,7 @@ namespace EnergyPlus::DaylightingManager { inline int findWinShadingIndex(int const IWin) { int WinShadingIndex = 1; // 1=unshaded, 2=shaded - bool WinShadedNoGlareControl = IS_SHADED(SurfWinShadingFlag(IWin)) && !SurfWinGlareControlIsActive(IWin); + bool WinShadedNoGlareControl = IS_SHADED_NO_GLARE_CTRL(SurfWinShadingFlag(IWin)); if ((SurfWinWindowModelType(IWin) != WindowBSDFModel) && (WinShadedNoGlareControl || SurfWinSolarDiffusing(IWin))) { WinShadingIndex = 2; @@ -6530,7 +6530,7 @@ namespace EnergyPlus::DaylightingManager { ICtrl = Surface(IWin).activeWindowShadingControl; if (Surface(IWin).HasShadeControl && ISWFLG == 0) { if (WindowShadingControl(ICtrl).ShadingControlType == WindowShadingControlType::MeetDaylIlumSetp && - SurfWinShadingFlag(IWin) == WinShadingType::SwitchableGlazing && SurfWinGlareControlIsActive(IWin)) + SurfWinShadingFlag(IWin) == WinShadingType::GlassConditionallyLightened) ISWFLG = 1; } @@ -6583,7 +6583,7 @@ namespace EnergyPlus::DaylightingManager { ICtrl = Surface(IWin).activeWindowShadingControl; int IS = findWinShadingIndex(IWin); if (Surface(IWin).HasShadeControl) { - if (SurfWinShadingFlag(IWin) == WinShadingType::SwitchableGlazing && SurfWinGlareControlIsActive(IWin) && + if (SurfWinShadingFlag(IWin) == WinShadingType::GlassConditionallyLightened && WindowShadingControl(ICtrl).ShadingControlType == WindowShadingControlType::MeetDaylIlumSetp && !previously_shaded(loop)) { DILLSW(igroup) += state.dataDaylightingData->ZoneDaylight(ZoneNum).IllumFromWinAtRefPt(loop, IS, 1); previously_shaded(loop) = true; @@ -6628,7 +6628,7 @@ namespace EnergyPlus::DaylightingManager { continueOuterLoop = true; continue; } - if ((SurfWinShadingFlag(IWin) != WinShadingType::SwitchableGlazing && !SurfWinGlareControlIsActive(IWin)) || + if (SurfWinShadingFlag(IWin) != WinShadingType::GlassConditionallyLightened || WindowShadingControl(ICtrl).ShadingControlType != WindowShadingControlType::MeetDaylIlumSetp) { continueOuterLoop = true; continue; @@ -6645,7 +6645,6 @@ namespace EnergyPlus::DaylightingManager { // Reset shading flag to indicate that window is shaded by being partially or fully switched SurfWinShadingFlag(IWin) = WinShadingType::SwitchableGlazing; - SurfWinGlareControlIsActive(IWin) = false; // ASETIL < 0 means illuminance from non-daylight-switchable windows exceeds setpoint, // so completely switch all daylight-switchable windows to minimize solar gain @@ -6745,7 +6744,8 @@ namespace EnergyPlus::DaylightingManager { // Check if window is eligible for glare control // TH 1/21/2010. Switchable glazings already in partially switched state // should be allowed to further dim to control glare - if (!SurfWinGlareControlIsActive(IWin) && SurfWinShadingFlag(IWin) != WinShadingType::SwitchableGlazing) { + // if (SurfWinShadingFlag(IWin) <= BGBlind && SurfWinShadingFlag(IWin) != SwitchableGlazing) { + if (NOT_SHADED(IWin) || ANY_SHADE_SCREEN(IWin) || ANY_BLIND(IWin)) { continueOuterLoop = false; continue; } @@ -6770,7 +6770,7 @@ namespace EnergyPlus::DaylightingManager { // Recalculate illuminance and glare with shading on this window. // For switchable glazings, this is the fully switched (dark) state for (int IL = 1; IL <= NREFPT; ++IL) { - if (SurfWinShadingFlag(IWin) != WinShadingType::SwitchableGlazing || SurfWinGlareControlIsActive(IWin)) { + if (SurfWinShadingFlag(IWin) != WinShadingType::SwitchableGlazing) { // for non switchable glazings or switchable glazings not switched yet (still in clear state) // SurfaceWindow(IWin)%ShadingFlag = WinShadingFlag::GlassConditionallyLightened RDAYIL(IL, igroup) = state.dataDaylightingManager->DaylIllum(IL) - WDAYIL(1, IL, igroup) + WDAYIL(2, IL, igroup); @@ -6782,8 +6782,11 @@ namespace EnergyPlus::DaylightingManager { } } - if (SurfWinShadingFlag(IWin) != WinShadingType::SwitchableGlazing || SurfWinGlareControlIsActive(IWin)) { - SurfWinGlareControlIsActive(IWin) = false; + if (SurfWinShadingFlag(IWin) != WinShadingType::SwitchableGlazing) { + if (SurfWinShadingFlag(IWin) == WinShadingType::IntShadeConditionallyOff) SurfWinShadingFlag(IWin) == WinShadingType::IntShade; + else if (SurfWinShadingFlag(IWin) == WinShadingType::ExtShadeConditionallyOff) SurfWinShadingFlag(IWin) == WinShadingType::ExtShade; + else if (SurfWinShadingFlag(IWin) == WinShadingType::IntBlindConditionallyOff) SurfWinShadingFlag(IWin) == WinShadingType::IntBlind; + else if (SurfWinShadingFlag(IWin) == WinShadingType::ExtBlindConditionallyOff) SurfWinShadingFlag(IWin) == WinShadingType::ExtBlind; } // For switchable glazings, it is switched to fully dark state, @@ -6858,7 +6861,8 @@ namespace EnergyPlus::DaylightingManager { ++count; // need to map back to the original order of the "loop" to not change all the other data structures loop = state.dataDaylightingData->ZoneDaylight(ZoneNum).MapShdOrdToLoopNum(count); - if (!SurfWinGlareControlIsActive(IWin) && SurfWinShadingFlag(IWin) != WinShadingType::SwitchableGlazing) continue; + // if (SurfWinShadingFlag(IWin) <= BGBlind && SurfWinShadingFlag(IWin) != SwitchableGlazing) { + if (NOT_SHADED(IWin) || ANY_SHADE_SCREEN(IWin) || ANY_BLIND(IWin)) continue; ICtrl = Surface(IWin).activeWindowShadingControl; if (!Surface(IWin).HasShadeControl) continue; @@ -6881,7 +6885,6 @@ namespace EnergyPlus::DaylightingManager { } SurfWinShadingFlag(IWin) = WinShadingType::ShadeOff; - SurfWinGlareControlIsActive(IWin) = false; continue; } @@ -7041,9 +7044,10 @@ namespace EnergyPlus::DaylightingManager { for (int IWin = Zone(ZoneNum).SurfaceFirst; IWin <= Zone(ZoneNum).SurfaceLast; ++IWin) { if (Surface(IWin).Class != SurfaceClass::Window) continue; if (Surface(IWin).ExtBoundCond != ExternalEnvironment) continue; - if (SurfWinGlareControlIsActive(IWin)) { + bool anyGlareControl = BITF_TEST_ANY(BITF(SurfWinShadingFlag(IWin)), BITF(WinShadingType::IntShadeConditionallyOff) | BITF(WinShadingType::GlassConditionallyLightened) |\ + BITF(WinShadingType::ExtShadeConditionallyOff) | BITF(WinShadingType::IntBlindConditionallyOff) | BITF(WinShadingType::ExtBlindConditionallyOff)); + if (anyGlareControl) { SurfWinShadingFlag(IWin) = WinShadingType::ShadeOff; - SurfWinGlareControlIsActive(IWin) = false; } } @@ -9696,7 +9700,7 @@ namespace EnergyPlus::DaylightingManager { HorIllSkyFac = state.dataEnvrn->HISKF / ((1.0 - SkyWeight) * HorIllSky(ISky2) + SkyWeight * HorIllSky(ISky1)); for (IS = 1; IS <= 2; ++IS) { - if (IS == 2 && !IS_SHADED(SurfWinShadingFlag(IWin)) && !SurfWinSolarDiffusing(IWin)) break; + if (IS == 2 && NOT_SHADED(SurfWinShadingFlag(IWin)) && !SurfWinSolarDiffusing(IWin)) break; state.dataDaylightingData->IllumMapCalc(MapNum).IllumFromWinAtMapPt(loop, IS, ILB) = DFSUHR(IS) * state.dataEnvrn->HISUNF + HorIllSkyFac * (DFSKHR(IS, ISky1) * SkyWeight * HorIllSky(ISky1) + diff --git a/src/EnergyPlus/HeatBalanceIntRadExchange.cc b/src/EnergyPlus/HeatBalanceIntRadExchange.cc index 4b93c6396f3..2a5ac1ff9e0 100644 --- a/src/EnergyPlus/HeatBalanceIntRadExchange.cc +++ b/src/EnergyPlus/HeatBalanceIntRadExchange.cc @@ -335,7 +335,7 @@ namespace HeatBalanceIntRadExchange { SurfaceTempRad[ZoneSurfNum] = SurfWinEffInsSurfTemp(SurfNum); SurfaceEmiss[ZoneSurfNum] = construct.InsideAbsorpThermal; } else if (construct.TypeIsWindow && SurfWinOriginalClass(SurfNum) != SurfaceClass::TDD_Diffuser) { - if (SurfIterations == 0 && !IS_SHADED(SurfWinShadingFlag(SurfNum))) { + if (SurfIterations == 0 && NOT_SHADED(SurfWinShadingFlag(SurfNum))) { // If the window is bare this TS and it is the first time through we use the previous TS glass // temperature whether or not the window was shaded in the previous TS. If the window was shaded // the previous time step this temperature is a better starting value than the shade temperature. diff --git a/src/EnergyPlus/HeatBalanceSurfaceManager.cc b/src/EnergyPlus/HeatBalanceSurfaceManager.cc index 052d7fb753c..5bebe27b08d 100644 --- a/src/EnergyPlus/HeatBalanceSurfaceManager.cc +++ b/src/EnergyPlus/HeatBalanceSurfaceManager.cc @@ -667,7 +667,7 @@ namespace HeatBalanceSurfaceManager { if (firstSurfWin == -1) continue; for (int SurfNum = firstSurfWin; SurfNum <= lastSurfWin; ++SurfNum) { SurfWinFracTimeShadingDeviceOn(SurfNum) = 0.0; - if (IS_SHADED(SurfWinShadingFlag(SurfNum)) || SurfWinGlareControlIsActive(SurfNum)) { + if (IS_SHADED(SurfWinShadingFlag(SurfNum))) { SurfWinFracTimeShadingDeviceOn(SurfNum) = 1.0; } else { SurfWinFracTimeShadingDeviceOn(SurfNum) = 0.0; @@ -3538,7 +3538,7 @@ namespace HeatBalanceSurfaceManager { SurfQRadThermInAbs(SurfNum) = adjQL * TMULT(radEnclosureNum) * ITABSF(SurfNum); } - if (!IS_SHADED(ShadeFlag)) { // No window shading + if (NOT_SHADED(ShadeFlag)) { // No window shading for (int IGlass = 1; IGlass <= TotGlassLayers; ++IGlass) { SurfWinQRadSWwinAbs(IGlass, SurfNum) += QS(solEnclosureNum) * state.dataConstruction->Construct(ConstrNum).AbsDiffBack(IGlass); @@ -3693,7 +3693,7 @@ namespace HeatBalanceSurfaceManager { } int TotGlassLayers = state.dataConstruction->Construct(ConstrNum).TotGlassLayers; WinShadingType ShadeFlag = SurfWinShadingFlag(SurfNum); - if (!IS_SHADED(ShadeFlag)) { // No window shading + if (NOT_SHADED(ShadeFlag)) { // No window shading for (int IGlass = 1; IGlass <= TotGlassLayers; ++IGlass) { SurfWinQRadSWwinAbs(IGlass, SurfNum) += SurfWinInitialDifSolwinAbs(IGlass, SurfNum); } @@ -3746,7 +3746,7 @@ namespace HeatBalanceSurfaceManager { TotGlassLayers = state.dataConstruction->Construct(ConstrNum).TotGlassLayers; } WinShadingType ShadeFlag = SurfWinShadingFlag(SurfNum); - if (!IS_SHADED(ShadeFlag) || SurfWinWindowModelType(SurfNum) == WindowBSDFModel) { // No window shading + if (NOT_SHADED(ShadeFlag) || SurfWinWindowModelType(SurfNum) == WindowBSDFModel) { // No window shading for (int IGlass = 1; IGlass <= TotGlassLayers; ++IGlass) { // Initial Transmitted Diffuse Solar Absorbed on Inside of Surface[W] SurfInitialDifSolInAbsReport(SurfNum) += diff --git a/src/EnergyPlus/SolarShading.cc b/src/EnergyPlus/SolarShading.cc index 065f9a950b4..31eaa043586 100644 --- a/src/EnergyPlus/SolarShading.cc +++ b/src/EnergyPlus/SolarShading.cc @@ -6111,7 +6111,7 @@ namespace SolarShading { AbWin(Lay) = POLYF(CosInc, state.dataConstruction->Construct(ConstrNum).AbsBeamCoef({1, 6}, Lay)) * CosInc * SunLitFract * SurfaceWindow(SurfNum).OutProjSLFracMult(state.dataGlobal->HourOfDay); } - if (!IS_SHADED(ShadeFlag) || SurfWinGlareControlIsActive(SurfNum)) { + if (!IS_SHADED_NO_GLARE_CTRL(ShadeFlag)) { // (ShadeFlag <= 0 || ShadeFlag >= 10) - Bare window (ShadeFlag = -1 or 0 or shading device of off) for (int Lay = 1; Lay <= NGlass; ++Lay) { // Add contribution of beam reflected from outside and inside reveal @@ -6401,7 +6401,7 @@ namespace SolarShading { } if (SurfWinWindowModelType(SurfNum) == Window5DetailedModel) { - if (IS_SHADED(SurfWinShadingFlag(SurfNum)) && !SurfWinGlareControlIsActive(SurfNum)) { + if (IS_SHADED_NO_GLARE_CTRL(SurfWinShadingFlag(SurfNum))) { if (ShadeFlag != WinShadingType::SwitchableGlazing) { // Shade or blind if (ANY_SHADE_SCREEN(ShadeFlag)) { @@ -6489,7 +6489,7 @@ namespace SolarShading { } else { DiffTrans = state.dataConstruction->Construct(ConstrNum).TransDiff; } - if (IS_SHADED(ShadeFlag) && !SurfWinGlareControlIsActive(SurfNum)) { + if (IS_SHADED_NO_GLARE_CTRL(ShadeFlag)) { if (ShadeFlag != WinShadingType::SwitchableGlazing) { // Shade or blind if (ANY_SHADE_SCREEN(ShadeFlag)) { @@ -6562,7 +6562,7 @@ namespace SolarShading { //----------------------------------------------------------------- if (ConstrNumSh != 0 && SunLitFract > 0.0) { if (SurfWinWindowModelType(SurfNum) != WindowEQLModel) { - if (IS_SHADED(ShadeFlag) && !SurfWinGlareControlIsActive(SurfNum)) { + if (IS_SHADED_NO_GLARE_CTRL(ShadeFlag)) { // Shade or screen or blind on, or switchable glazing // (note in the following that diffusing glass is not allowed in a window with shade, blind or switchable glazing) if (ANY_SHADE(ShadeFlag) || ShadeFlag == WinShadingType::SwitchableGlazing) { @@ -6704,7 +6704,8 @@ namespace SolarShading { WinTransDifSolarSky(SurfNum) = DiffTrans * Surface(SurfNum).Area; } - if (!IS_SHADED(ShadeFlag) || SurfWinGlareControlIsActive(SurfNum) || ShadeFlag == WinShadingType::SwitchableGlazing) { // Unshaded or switchable glazing + if (!IS_SHADED_NO_GLARE_CTRL(ShadeFlag) || ShadeFlag == WinShadingType::SwitchableGlazing) { + // Unshaded or switchable glazing // Note: with previous defs of TBmBm & TBmDif, these come out right for Complex Fenestration // WinTransBmSolar uses the directional-hemispherical transmittance WinTransBmSolar(SurfNum) = (TBmBm + TBmDif) * SunLitFract * CosInc * Surface(SurfNum).Area * InOutProjSLFracMult; @@ -6900,7 +6901,7 @@ namespace SolarShading { // Interior beam absorptance of glass layers and beam transmittance of back exterior & // or interior window WITHOUT SHADING this timestep - if (!IS_SHADED(ShadeFlagBack)) { + if (NOT_SHADED(ShadeFlagBack)) { for (int Lay = 1; Lay <= NBackGlass; ++Lay) { AbsBeamWin(Lay) = POLYF(CosIncBack, state.dataConstruction->Construct(ConstrNumBack).AbsBeamBackCoef({1, 6}, Lay)); } @@ -8738,12 +8739,6 @@ namespace SolarShading { Real64 SetPoint = WindowShadingControl(IShadingCtrl).SetPoint; // Control setpoint Real64 SetPoint2 = WindowShadingControl(IShadingCtrl).SetPoint2; // Second control setpoint - WinShadingType ShType; // Type of shading (interior shade, interior blind, etc.) - - if (IS_SHADED(WindowShadingControl(IShadingCtrl).ShadingType)) { - ShType = WindowShadingControl(IShadingCtrl).ShadingType; - } - bool SchedAllowsControl = true; // True if control schedule is not specified or is specified and schedule value = 1 int SchedulePtr = WindowShadingControl(IShadingCtrl).Schedule; if (SchedulePtr != 0) { @@ -8769,26 +8764,25 @@ namespace SolarShading { // Determine whether to deploy shading depending on type of control - SurfWinGlareControlIsActive(ISurf) = false; - SurfWinShadingFlag(ISurf) = WinShadingType::ShadeOff; // Initialize shading flag to off + bool shadingOn = false; + bool shadingOffButGlareControlOn = false; switch (WindowShadingControl(IShadingCtrl).ShadingControlType) { case WindowShadingControlType::AlwaysOn: // 'ALWAYSON' - SurfWinShadingFlag(ISurf) = ShType; + shadingOn = true; break; case WindowShadingControlType::AlwaysOff: // 'ALWAYSOFF' - SurfWinShadingFlag(ISurf) = WinShadingType::ShadeOff; break; case WindowShadingControlType::OnIfScheduled: // 'ONIFSCHEDULEALLOWS' - if (SchedAllowsControl) SurfWinShadingFlag(ISurf) = ShType; + if (SchedAllowsControl) shadingOn = true; break; case WindowShadingControlType::HiSolar: // 'ONIFHIGHSOLARONWINDOW' // ! Direct plus diffuse solar intensity on window if (state.dataEnvrn->SunIsUp) { if (SolarOnWindow > SetPoint && SchedAllowsControl) { - SurfWinShadingFlag(ISurf) = ShType; + shadingOn = true; } else if (GlareControlIsActive) { - SurfWinGlareControlIsActive(ISurf) = true; + shadingOffButGlareControlOn = true; } } break; @@ -8796,47 +8790,45 @@ namespace SolarShading { case WindowShadingControlType::HiHorzSolar: // 'ONIFHIGHHORIZONTALSOLAR' ! Direct plus diffuse exterior horizontal solar intensity if (state.dataEnvrn->SunIsUp) { if (HorizSolar > SetPoint && SchedAllowsControl) { - SurfWinShadingFlag(ISurf) = ShType; + shadingOn = true; } else if (GlareControlIsActive) { - SurfWinGlareControlIsActive(ISurf) = true; + shadingOffButGlareControlOn = true; } } break; case WindowShadingControlType::HiOutAirTemp: // 'OnIfHighOutdoorAirTemperature' if (Surface(ISurf).OutDryBulbTemp > SetPoint && SchedAllowsControl) { - SurfWinShadingFlag(ISurf) = ShType; + shadingOn = true; } else if (GlareControlIsActive) { - SurfWinGlareControlIsActive(ISurf) = true; + shadingOffButGlareControlOn = true; } break; case WindowShadingControlType::HiZoneAirTemp: // 'OnIfHighZoneAirTemperature' ! Previous time step zone air temperature if (MAT(IZone) > SetPoint && SchedAllowsControl) { - SurfWinShadingFlag(ISurf) = ShType; + shadingOn = true; } else if (GlareControlIsActive) { - SurfWinGlareControlIsActive(ISurf) = true; + shadingOffButGlareControlOn = true; } break; case WindowShadingControlType::OnHiOutTemp_HiSolarWindow: // 'OnIfHighOutdoorAirTempAndHighSolarOnWindow' ! Outside air temp and solar on window if (state.dataEnvrn->SunIsUp) { - if (Surface(ISurf).OutDryBulbTemp > SetPoint && SolarOnWindow > SetPoint2 && - SchedAllowsControl) { - SurfWinShadingFlag(ISurf) = ShType; + if (Surface(ISurf).OutDryBulbTemp > SetPoint && SolarOnWindow > SetPoint2 && SchedAllowsControl) { + shadingOn = true; } else if (GlareControlIsActive) { - SurfWinGlareControlIsActive(ISurf) = true; + shadingOffButGlareControlOn = true; } } break; case WindowShadingControlType::OnHiOutTemp_HiHorzSolar: // 'OnIfHighOutdoorAirTempAndHighHorizontalSolar' ! Outside air temp and horizontal solar if (state.dataEnvrn->SunIsUp) { - if (Surface(ISurf).OutDryBulbTemp > SetPoint && HorizSolar > SetPoint2 && - SchedAllowsControl) { - SurfWinShadingFlag(ISurf) = ShType; + if (Surface(ISurf).OutDryBulbTemp > SetPoint && HorizSolar > SetPoint2 && SchedAllowsControl) { + shadingOn = true; } else if (GlareControlIsActive) { - SurfWinGlareControlIsActive(ISurf) = true; + shadingOffButGlareControlOn = true; } } break; @@ -8844,9 +8836,9 @@ namespace SolarShading { case WindowShadingControlType::OnHiZoneTemp_HiSolarWindow: // 'ONIFHIGHZONEAIRTEMPANDHIGHSOLARONWINDOW' ! Zone air temp and solar on window if (state.dataEnvrn->SunIsUp) { if (MAT(IZone) > SetPoint && SolarOnWindow > SetPoint2 && SchedAllowsControl) { - SurfWinShadingFlag(ISurf) = ShType; + shadingOn = true; } else if (GlareControlIsActive) { - SurfWinGlareControlIsActive(ISurf) = true; + shadingOffButGlareControlOn = true; } } break; @@ -8854,9 +8846,9 @@ namespace SolarShading { case WindowShadingControlType::OnHiZoneTemp_HiHorzSolar: // 'ONIFHIGHZONEAIRTEMPANDHIGHHORIZONTALSOLAR' ! Zone air temp and horizontal solar if (state.dataEnvrn->SunIsUp) { if (MAT(IZone) > SetPoint && HorizSolar > SetPoint2 && SchedAllowsControl) { - SurfWinShadingFlag(ISurf) = ShType; + shadingOn = true; } else if (GlareControlIsActive) { - SurfWinGlareControlIsActive(ISurf) = true; + shadingOffButGlareControlOn = true; } } break; @@ -8867,9 +8859,9 @@ namespace SolarShading { // used in other CASEs) are not allocated at this point for the first time step of the simulation. if (!state.dataGlobal->BeginSimFlag) { if (SNLoadCoolRate(IZone) > SetPoint && SchedAllowsControl) { - SurfWinShadingFlag(ISurf) = ShType; + shadingOn = true; } else if (GlareControlIsActive) { - SurfWinGlareControlIsActive(ISurf) = true; + shadingOffButGlareControlOn = true; } } break; @@ -8879,8 +8871,7 @@ namespace SolarShading { // This type of shading control is done in DayltgInteriorIllum. Glare control is not affected // by control schedule. if (state.dataEnvrn->SunIsUp) { - SurfWinShadingFlag(ISurf) = ShType; - SurfWinGlareControlIsActive(ISurf) = true; + shadingOffButGlareControlOn = true; } break; @@ -8888,33 +8879,32 @@ namespace SolarShading { // 'MEETDAYLIGHTILLUMINANCESETPOINT') ! Daylight illuminance test is done in DayltgInteriorIllum // Only switchable glazing does daylight illuminance control if (state.dataEnvrn->SunIsUp && SchedAllowsControl) { - SurfWinShadingFlag(ISurf) = ShType; - SurfWinGlareControlIsActive(ISurf) = true; + shadingOffButGlareControlOn = true; } break; case WindowShadingControlType::OnNightLoOutTemp_OffDay: // 'OnNightIfLowOutdoorTempAndOffDay' if (!state.dataEnvrn->SunIsUp && Surface(ISurf).OutDryBulbTemp < SetPoint && SchedAllowsControl) { - SurfWinShadingFlag(ISurf) = ShType; + shadingOn = true; } else if (GlareControlIsActive) { - SurfWinGlareControlIsActive(ISurf) = true; + shadingOffButGlareControlOn = true; } break; case WindowShadingControlType::OnNightLoInTemp_OffDay: // 'OnNightIfLowInsideTempAndOffDay') if (!state.dataEnvrn->SunIsUp && MAT(IZone) < SetPoint && SchedAllowsControl) { - SurfWinShadingFlag(ISurf) = ShType; + shadingOn = true; } else if (GlareControlIsActive) { - SurfWinGlareControlIsActive(ISurf) = true; + shadingOffButGlareControlOn = true; } break; case WindowShadingControlType::OnNightIfHeating_OffDay: // 'OnNightIfHeatingAndOffDay' if (!state.dataGlobal->BeginSimFlag) { if (!state.dataEnvrn->SunIsUp && SNLoadHeatRate(IZone) > SetPoint && SchedAllowsControl) { - SurfWinShadingFlag(ISurf) = ShType; + shadingOn = true; } else if (GlareControlIsActive) { - SurfWinGlareControlIsActive(ISurf) = true; + shadingOffButGlareControlOn = true; } } break; @@ -8923,12 +8913,12 @@ namespace SolarShading { if (!state.dataGlobal->BeginSimFlag) { if (!state.dataEnvrn->SunIsUp) { // Night if (Surface(ISurf).OutDryBulbTemp < SetPoint && SchedAllowsControl) - SurfWinShadingFlag(ISurf) = ShType; + shadingOn = true; } else { // Day if (SNLoadCoolRate(IZone) > 0.0 && SchedAllowsControl) { - SurfWinShadingFlag(ISurf) = ShType; + shadingOn = true; } else if (GlareControlIsActive) { - SurfWinGlareControlIsActive(ISurf) = true; + shadingOffButGlareControlOn = true; } } } @@ -8938,12 +8928,12 @@ namespace SolarShading { if (!state.dataGlobal->BeginSimFlag) { if (!state.dataEnvrn->SunIsUp) { // Night if (SNLoadHeatRate(IZone) > SetPoint && SchedAllowsControl) - SurfWinShadingFlag(ISurf) = ShType; + shadingOn = true; } else { // Day if (SNLoadCoolRate(IZone) > 0.0 && SchedAllowsControl) { - SurfWinShadingFlag(ISurf) = ShType; + shadingOn = true; } else if (GlareControlIsActive) { - SurfWinGlareControlIsActive(ISurf) = true; + shadingOffButGlareControlOn = true; } } } @@ -8952,9 +8942,9 @@ namespace SolarShading { case WindowShadingControlType::OffNight_OnDay_HiSolarWindow: // 'OffNightAndOnDayIfCoolingAndHighSolarOnWindow' if (!state.dataGlobal->BeginSimFlag) { if (state.dataEnvrn->SunIsUp && SNLoadCoolRate(IZone) > 0.0 && SchedAllowsControl) { - if (SolarOnWindow > SetPoint) SurfWinShadingFlag(ISurf) = ShType; + if (SolarOnWindow > SetPoint) shadingOn = true; } else if (GlareControlIsActive) { - SurfWinGlareControlIsActive(ISurf) = true; + shadingOffButGlareControlOn = true; } } break; @@ -8962,11 +8952,11 @@ namespace SolarShading { case WindowShadingControlType::OnNight_OnDay_HiSolarWindow: // 'OnNightAndOnDayIfCoolingAndHighSolarOnWindow' if (!state.dataGlobal->BeginSimFlag) { if (state.dataEnvrn->SunIsUp && SNLoadCoolRate(IZone) > 0.0 && SchedAllowsControl) { - if (SolarOnWindow > SetPoint) SurfWinShadingFlag(ISurf) = ShType; + if (SolarOnWindow > SetPoint) shadingOn = true; } else if (!state.dataEnvrn->SunIsUp && SchedAllowsControl) { - SurfWinShadingFlag(ISurf) = ShType; + shadingOn = true; } else if (GlareControlIsActive) { - SurfWinGlareControlIsActive(ISurf) = true; + shadingOffButGlareControlOn = true; } } break; @@ -8975,8 +8965,24 @@ namespace SolarShading { Surface(ISurf).Name); } + WinShadingType ShType = WindowShadingControl(IShadingCtrl).ShadingType; + + SurfWinShadingFlag(ISurf) = WinShadingType::ShadeOff; // Initialize shading flag to off + + if (IS_SHADED(ShType)) { + if (shadingOn) { + SurfWinShadingFlag(ISurf) = ShType; + } else if (shadingOffButGlareControlOn) { + if (ShType == WinShadingType::SwitchableGlazing) SurfWinShadingFlag(ISurf) = WinShadingType::GlassConditionallyLightened; + else if (ShType == WinShadingType::IntShade) SurfWinShadingFlag(ISurf) = WinShadingType::IntShadeConditionallyOff; + else if (ShType == WinShadingType::ExtShade) SurfWinShadingFlag(ISurf) = WinShadingType::ExtShadeConditionallyOff; + else if (ShType == WinShadingType::IntBlind) SurfWinShadingFlag(ISurf) = WinShadingType::IntBlindConditionallyOff; + else if (ShType == WinShadingType::ExtBlind) SurfWinShadingFlag(ISurf) = WinShadingType::ExtBlindConditionallyOff; + } + } + // Set switching factor to fully switched if ShadingFlag = 2 - if (SurfWinShadingFlag(ISurf) == WinShadingType::SwitchableGlazing && !SurfWinGlareControlIsActive(ISurf)) { + if (SurfWinShadingFlag(ISurf) == WinShadingType::SwitchableGlazing) { SurfWinSwitchingFactor(ISurf) = 1.0; // Added TH 1/20/2010 @@ -10203,7 +10209,7 @@ namespace SolarShading { // Quantities related to inside reveal; inside reveal reflection/absorption is assumed // to occur only if an interior shade or blind is not in place. - if (!IS_SHADED(ShadeFlag) || ShadeFlag == WinShadingType::SwitchableGlazing) { + if (NOT_SHADED(ShadeFlag) || ShadeFlag == WinShadingType::SwitchableGlazing) { if (A2ill > 1.0e-6) { @@ -10792,7 +10798,7 @@ namespace SolarShading { WinShadingType ShadeFlag = SurfWinShadingFlag(HeatTransSurfNum); if (SurfWinWindowModelType(HeatTransSurfNum) != WindowEQLModel) { - if (!IS_SHADED(ShadeFlag)) { // No window shading + if (NOT_SHADED(ShadeFlag)) { // No window shading // Init accumulator for transmittance calc below DifSolarAbsW = 0.0; @@ -11330,7 +11336,7 @@ namespace SolarShading { TotGlassLayers = state.dataConstruction->Construct(ConstrNum).TotGlassLayers; ShadeFlag = SurfWinShadingFlag(HeatTransSurfNum); - if (!IS_SHADED(ShadeFlag)) { // No window shading + if (NOT_SHADED(ShadeFlag)) { // No window shading // Init accumulator for transmittance calc below DifSolarAbsW = 0.0; diff --git a/src/EnergyPlus/SurfaceGeometry.cc b/src/EnergyPlus/SurfaceGeometry.cc index 5c74d3eae25..e4937f5c4d2 100644 --- a/src/EnergyPlus/SurfaceGeometry.cc +++ b/src/EnergyPlus/SurfaceGeometry.cc @@ -162,7 +162,6 @@ namespace SurfaceGeometry { SurfWinShadingFlag.dimension(NumSurfaces, WinShadingType::ShadeOff); SurfWinShadingFlagEMSOn.dimension(NumSurfaces, 0); SurfWinShadingFlagEMSValue.dimension(NumSurfaces, 0.0); - SurfWinGlareControlIsActive.dimension(NumSurfaces, false); SurfWinStormWinFlag.dimension(NumSurfaces, 0); SurfWinStormWinFlagPrevDay.dimension(NumSurfaces, 0); SurfWinFracTimeShadingDeviceOn.dimension(NumSurfaces, 0); diff --git a/src/EnergyPlus/WindowManager.cc b/src/EnergyPlus/WindowManager.cc index c5c8d7b4a31..92a890b7bd5 100644 --- a/src/EnergyPlus/WindowManager.cc +++ b/src/EnergyPlus/WindowManager.cc @@ -3499,7 +3499,7 @@ namespace WindowManager { } TransDiff = state.dataConstruction->Construct(ConstrNum).TransDiff; // Default value for TransDiff here - if (!IS_SHADED(ShadeFlag)) { + if (NOT_SHADED(ShadeFlag)) { TransDiff = state.dataConstruction->Construct(ConstrNum).TransDiff; } else if (ANY_SHADE_SCREEN(ShadeFlag)) { TransDiff = state.dataConstruction->Construct(ConstrNumSh).TransDiff; diff --git a/testfiles/EMSConstantVolumePurchasedAir.idf b/testfiles/EMSConstantVolumePurchasedAir.idf index e7766d90524..180e2a14452 100644 --- a/testfiles/EMSConstantVolumePurchasedAir.idf +++ b/testfiles/EMSConstantVolumePurchasedAir.idf @@ -1515,7 +1515,7 @@ , !- EMS Program or Subroutine Name ; !- Units -1.0 EnergyManagementSystem:OutputVariable, + EnergyManagementSystem:OutputVariable, Erl Zn001:Wall001:Win001 Incident Angle, !- Name IncidentAngle, !- EMS Variable Name Averaged, !- Type of Data in Variable From f9582dcaa74109a5f9cd0491b385d7ca33ade28e Mon Sep 17 00:00:00 2001 From: xuanluo113 Date: Fri, 29 Jan 2021 23:49:01 -0800 Subject: [PATCH 35/76] bug fix --- src/EnergyPlus/DataSurfaces.hh | 4 +++- src/EnergyPlus/DaylightingManager.cc | 17 +++++++++-------- src/EnergyPlus/SolarShading.cc | 14 +++++++++++++- 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/src/EnergyPlus/DataSurfaces.hh b/src/EnergyPlus/DataSurfaces.hh index f5bc5729a29..686e5cbdafd 100644 --- a/src/EnergyPlus/DataSurfaces.hh +++ b/src/EnergyPlus/DataSurfaces.hh @@ -164,7 +164,9 @@ namespace DataSurfaces { GlassConditionallyLightened = 11, ExtShadeConditionallyOff = 12, IntBlindConditionallyOff = 13, - ExtBlindConditionallyOff = 14 + ExtBlindConditionallyOff = 14, + BGShadeConditionallyOff = 15, + BGBlindConditionallyOff = 16 }; enum class WindowShadingControlType : int{ diff --git a/src/EnergyPlus/DaylightingManager.cc b/src/EnergyPlus/DaylightingManager.cc index e25ea4a7227..5dd35fea4a0 100644 --- a/src/EnergyPlus/DaylightingManager.cc +++ b/src/EnergyPlus/DaylightingManager.cc @@ -6745,7 +6745,7 @@ namespace EnergyPlus::DaylightingManager { // TH 1/21/2010. Switchable glazings already in partially switched state // should be allowed to further dim to control glare // if (SurfWinShadingFlag(IWin) <= BGBlind && SurfWinShadingFlag(IWin) != SwitchableGlazing) { - if (NOT_SHADED(IWin) || ANY_SHADE_SCREEN(IWin) || ANY_BLIND(IWin)) { + if (NOT_SHADED(SurfWinShadingFlag(IWin)) || ANY_SHADE_SCREEN(SurfWinShadingFlag(IWin)) || ANY_BLIND(SurfWinShadingFlag(IWin))) { continueOuterLoop = false; continue; } @@ -6782,12 +6782,13 @@ namespace EnergyPlus::DaylightingManager { } } - if (SurfWinShadingFlag(IWin) != WinShadingType::SwitchableGlazing) { - if (SurfWinShadingFlag(IWin) == WinShadingType::IntShadeConditionallyOff) SurfWinShadingFlag(IWin) == WinShadingType::IntShade; - else if (SurfWinShadingFlag(IWin) == WinShadingType::ExtShadeConditionallyOff) SurfWinShadingFlag(IWin) == WinShadingType::ExtShade; - else if (SurfWinShadingFlag(IWin) == WinShadingType::IntBlindConditionallyOff) SurfWinShadingFlag(IWin) == WinShadingType::IntBlind; - else if (SurfWinShadingFlag(IWin) == WinShadingType::ExtBlindConditionallyOff) SurfWinShadingFlag(IWin) == WinShadingType::ExtBlind; - } + if (SurfWinShadingFlag(IWin) == WinShadingType::GlassConditionallyLightened) SurfWinShadingFlag(IWin) = WinShadingType::SwitchableGlazing; + else if (SurfWinShadingFlag(IWin) == WinShadingType::IntShadeConditionallyOff) SurfWinShadingFlag(IWin) = WinShadingType::IntShade; + else if (SurfWinShadingFlag(IWin) == WinShadingType::ExtShadeConditionallyOff) SurfWinShadingFlag(IWin) = WinShadingType::ExtShade; + else if (SurfWinShadingFlag(IWin) == WinShadingType::IntBlindConditionallyOff) SurfWinShadingFlag(IWin) = WinShadingType::IntBlind; + else if (SurfWinShadingFlag(IWin) == WinShadingType::ExtBlindConditionallyOff) SurfWinShadingFlag(IWin) = WinShadingType::ExtBlind; + else if (SurfWinShadingFlag(IWin) == WinShadingType::BGShadeConditionallyOff) SurfWinShadingFlag(IWin) = WinShadingType::BGShade; + else if (SurfWinShadingFlag(IWin) == WinShadingType::BGBlindConditionallyOff) SurfWinShadingFlag(IWin) = WinShadingType::BGBlind; // For switchable glazings, it is switched to fully dark state, // update ZoneDaylight(ZoneNum)%SourceLumFromWinAtRefPt(IL,2,loop) for use in DayltgGlare @@ -6862,7 +6863,7 @@ namespace EnergyPlus::DaylightingManager { // need to map back to the original order of the "loop" to not change all the other data structures loop = state.dataDaylightingData->ZoneDaylight(ZoneNum).MapShdOrdToLoopNum(count); // if (SurfWinShadingFlag(IWin) <= BGBlind && SurfWinShadingFlag(IWin) != SwitchableGlazing) { - if (NOT_SHADED(IWin) || ANY_SHADE_SCREEN(IWin) || ANY_BLIND(IWin)) continue; + if (NOT_SHADED(SurfWinShadingFlag(IWin)) || ANY_SHADE_SCREEN(SurfWinShadingFlag(IWin)) || ANY_BLIND(SurfWinShadingFlag(IWin))) continue; ICtrl = Surface(IWin).activeWindowShadingControl; if (!Surface(IWin).HasShadeControl) continue; diff --git a/src/EnergyPlus/SolarShading.cc b/src/EnergyPlus/SolarShading.cc index 31eaa043586..c69b2e9426d 100644 --- a/src/EnergyPlus/SolarShading.cc +++ b/src/EnergyPlus/SolarShading.cc @@ -8978,6 +8978,8 @@ namespace SolarShading { else if (ShType == WinShadingType::ExtShade) SurfWinShadingFlag(ISurf) = WinShadingType::ExtShadeConditionallyOff; else if (ShType == WinShadingType::IntBlind) SurfWinShadingFlag(ISurf) = WinShadingType::IntBlindConditionallyOff; else if (ShType == WinShadingType::ExtBlind) SurfWinShadingFlag(ISurf) = WinShadingType::ExtBlindConditionallyOff; + else if (ShType == WinShadingType::BGShade) SurfWinShadingFlag(ISurf) = WinShadingType::BGShadeConditionallyOff; + else if (ShType == WinShadingType::BGBlind) SurfWinShadingFlag(ISurf) = WinShadingType::BGBlindConditionallyOff; } } @@ -8997,7 +8999,10 @@ namespace SolarShading { SurfWinSlatAngThisTS(ISurf) = 0.0; SurfWinSlatAngThisTSDeg(ISurf) = 0.0; SurfWinSlatsBlockBeam(ISurf) = false; - if (ANY_BLIND(SurfWinShadingFlag(ISurf))) { + if (ANY_BLIND(SurfWinShadingFlag(ISurf)) || + SurfWinShadingFlag(ISurf) == WinShadingType::IntBlindConditionallyOff || + SurfWinShadingFlag(ISurf) == WinShadingType::ExtBlindConditionallyOff || + SurfWinShadingFlag(ISurf) == WinShadingType::BGBlindConditionallyOff) { // Blind in place or may be in place due to glare control int BlNum = SurfWinBlindNumber(ISurf); if (BlNum > 0) { @@ -9180,6 +9185,13 @@ namespace SolarShading { if (controlValue == 7.0) return WinShadingType::ExtBlind; if (controlValue == 8.0) return WinShadingType::BGShade; if (controlValue == 9.0) return WinShadingType::BGBlind; + if (controlValue == 10.0) return WinShadingType::IntShadeConditionallyOff; + if (controlValue == 20.0) return WinShadingType::GlassConditionallyLightened; + if (controlValue == 30.0) return WinShadingType::ExtShadeConditionallyOff; + if (controlValue == 60.0) return WinShadingType::IntBlindConditionallyOff; + if (controlValue == 70.0) return WinShadingType::ExtBlindConditionallyOff; + if (controlValue == 80.0) return WinShadingType::BGShadeConditionallyOff; + if (controlValue == 90.0) return WinShadingType::BGBlindConditionallyOff; return WinShadingType::INVALID; } From 4568a3b2c20315bf59e1e8e3b7131de019407065 Mon Sep 17 00:00:00 2001 From: Noel Merket Date: Mon, 1 Feb 2021 10:18:20 -0700 Subject: [PATCH 36/76] Squashed 'third_party/ssc/' changes from 3ee02f1578..3ce30afc9e 3ce30afc9e use temperature in Kelvin to compute thermal capcity update 3f49b568f2 Accept temperture schedule for analytical model of temperature capacity 885330dd22 Added analytical thermal model da8a007b77 added lifetime nmc model 3ae0580195 merge with batt_life_new, add day_age_of_battery_float f182552d6b Fix merging conflict with batt_life_new ebc4e52edd add lifetime_nmc_states, run state initialization tests 03e5a6758d Merge branch 'adaptive_timestep' into batt_life_new 5ec146d17e static_cast for battery control mode ENUM fe43ff7bf7 BatteryStateful can change dt_hr between executions 7e1b9cb14b battery_stateful dt_hr initialization 78e01d1491 Merge branch 'adaptive_timestep' into batt_life_new b63e9028e5 add battery_t ChangeTimestep fx & rename all "dt_hour" vars to "dt_hr" 70609a5925 add "day_of_age_battery" incrementing to lifetime_nmc_t 9f11b13f60 add cycle counter to battery_lifetime_nmc c337886624 increase ResidentialDCBatteryModelPriceSignalDispatch err tol for platform differences ef07e46683 stub out unit tests for lifetime_nmc 3651dcd21c fix cloning of lifetime_state cfb4720840 Merge branch 'patch' into batt_life_new b233a750f4 add some test expectations to DCBatteryModelPriceSignalDispatch 7dda110a77 fix some more tests 0535b88e4b add more stubbed fxns c124d4a9c6 pass lifetime_params instead of calendar_cycle_params 09fda3dc3e start stubbing out lifetime_nmc class in the cmods a1a4f40692 fix some more battery lifetime calendar cycle issues 72f95f3aff fix pvsamm batt tests 9ba9b3d8d7 fix stateful tests 00cb47a629 Merge branch 'patch' into batt_life_new c8dd39dda8 add additional parameters to batterystateful test e13237f545 fixing some tests 5bf6b59f2a initial refactoring of Test 48ba00c9fa initial refactoring of lifetime model 303f22f56e add entry points for new battery life model ec94a8d8a7 fix some warnings 228747c456 remove unused battery loss choice "VALUE" d1348165f2 Merge branch 'develop' into patch 596403ea2a Revert "Revert "Merge branch 'develop' of https://github.com/NREL/ssc into develop"" 7f40da4dda Revert "Merge branch 'develop' of https://github.com/NREL/ssc into develop" 204b5443de Merge branch 'develop' of https://github.com/NREL/ssc into develop c2f52e52b3 Merge branch 'develop' of https://github.com/NREL/ssc into develop REVERT: 3ee02f1578 Add analytical thermal capacity model, fix runLithiumIonNMC REVERT: 6edbeab044 added cmod option for liion nmc. Updated Q_neg REVERT: 707dc0792d Add lithium ion nmc option in batt calendar choice REVERT: ff3d63f22a update lib_battery to add nmc model REVERT: 5cf42876c2 adding lifetime_cycle_t object in lifetime_calendar_t REVERT: 66046db775 building the Li_ion_nmc calendar degradation function REVERT: 4247518fa0 Creating lifetime_t constructor for li_ion_nmc git-subtree-dir: third_party/ssc git-subtree-split: 3ce30afc9e375d90ee3e947766203f649eb0467e --- shared/CMakeLists.txt | 4 + shared/lib_battery.cpp | 87 ++- shared/lib_battery.h | 34 +- shared/lib_battery_dispatch.cpp | 4 +- shared/lib_battery_dispatch_automatic_btm.h | 2 +- shared/lib_battery_lifetime.cpp | 721 ++---------------- shared/lib_battery_lifetime.h | 306 +------- .../lib_battery_lifetime_calendar_cycle.cpp | 590 ++++++++++++++ shared/lib_battery_lifetime_calendar_cycle.h | 249 ++++++ shared/lib_battery_lifetime_nmc.cpp | 187 +++++ shared/lib_battery_lifetime_nmc.h | 97 +++ shared/logger.cpp | 51 +- ssc/cmod_battery.cpp | 89 ++- ssc/cmod_battery.h | 1 + ssc/cmod_battery_stateful.cpp | 155 ++-- ssc/cmod_battery_stateful.h | 2 +- ssc/cmod_battwatts.cpp | 2 +- ssc/cmod_fuelcell.cpp | 20 +- ssc/cmod_pvsamv1.cpp | 1 - ssc/cmod_pvwattsv5.cpp | 2 +- test/input_cases/battery_common_data.h | 3 +- test/input_cases/generic_common_data.h | 4 +- .../input_cases/pvsamv1_battery_common_data.h | 4 +- test/input_cases/pvsamv1_common_data.cpp | 1 + .../lib_battery_dispatch_automatic_btm_test.h | 6 +- .../lib_battery_dispatch_automatic_fom_test.h | 6 +- .../lib_battery_dispatch_manual_test.h | 6 +- .../shared_test/lib_battery_lifetime_test.cpp | 184 +++-- test/shared_test/lib_battery_lifetime_test.h | 18 +- test/shared_test/lib_battery_properties.h | 2 +- test/shared_test/lib_battery_test.cpp | 187 ++++- test/shared_test/lib_battery_test.h | 24 +- test/ssc_test/cmod_battery_pvsamv1_test.cpp | 10 +- test/ssc_test/cmod_battery_stateful_test.cpp | 136 +++- test/ssc_test/cmod_battery_stateful_test.h | 4 +- test/ssc_test/cmod_windpower_test.cpp | 2 - 36 files changed, 1904 insertions(+), 1297 deletions(-) create mode 100644 shared/lib_battery_lifetime_calendar_cycle.cpp create mode 100644 shared/lib_battery_lifetime_calendar_cycle.h create mode 100644 shared/lib_battery_lifetime_nmc.cpp create mode 100644 shared/lib_battery_lifetime_nmc.h diff --git a/shared/CMakeLists.txt b/shared/CMakeLists.txt index dc1d6d5db14..722e5e4c9db 100644 --- a/shared/CMakeLists.txt +++ b/shared/CMakeLists.txt @@ -31,6 +31,10 @@ set(SHARED_SRC lib_battery_dispatch_manual.h lib_battery_lifetime.cpp lib_battery_lifetime.h + lib_battery_lifetime_calendar_cycle.cpp + lib_battery_lifetime_calendar_cycle.h + lib_battery_lifetime_nmc.cpp + lib_battery_lifetime_nmc.h lib_battery_powerflow.cpp lib_battery_powerflow.h lib_battery_voltage.cpp diff --git a/shared/lib_battery.cpp b/shared/lib_battery.cpp index 79063bcfca4..9f8716840dd 100644 --- a/shared/lib_battery.cpp +++ b/shared/lib_battery.cpp @@ -48,15 +48,13 @@ void thermal_t::initialize() { state->T_batt_prev = state->T_room; state->heat_dissipated = 0; state->q_relative_thermal = 100; - dt_sec = params->dt_hour * 3600; + dt_sec = params->dt_hr * 3600; } thermal_t::thermal_t(double dt_hour, double mass, double surface_area, double R, double Cp, double h, const util::matrix_t &c_vs_t, std::vector T_room_C) { params = std::shared_ptr(new thermal_params({dt_hour, mass, surface_area, Cp, h, R, c_vs_t})); params->option = thermal_params::SCHEDULE; - //Rohit intialize analytical_model - params->analytical_model = false; params->T_room_schedule = std::move(T_room_C); initialize(); state->T_room = params->T_room_schedule[0]; @@ -66,9 +64,8 @@ thermal_t::thermal_t(double dt_hour, double mass, double surface_area, double R, const util::matrix_t &c_vs_t, double T_room_C) { params = std::shared_ptr(new thermal_params({dt_hour, mass, surface_area, Cp, h, R, c_vs_t})); params->option = thermal_params::VALUE; - //Rohit initialize analytical_model - params->analytical_model = false; params->T_room_init = T_room_C; + params->analytical_model = false; initialize(); } @@ -77,14 +74,26 @@ thermal_t::thermal_t(double dt_hour, double mass, double surface_area, double R, util::matrix_t c_vs_t; double vals3[] = { -10, 60, 0, 80, 25, 100, 40, 100 }; c_vs_t.assign(vals3, 4, 2); - params = std::shared_ptr(new thermal_params({ dt_hour, mass, surface_area, Cp, h, R, c_vs_t })); + params = std::shared_ptr(new thermal_params({dt_hour, mass, surface_area, Cp, h, R, c_vs_t })); params->option = thermal_params::VALUE; - //Rohit initialize analytical_model - params->analytical_model = true; params->T_room_init = T_room_C; + params->analytical_model = true; initialize(); } +thermal_t::thermal_t(double dt_hour, double mass, double surface_area, double R, double Cp, double h, + std::vector T_room_C) { + util::matrix_t c_vs_t; + double vals3[] = { -10, 60, 0, 80, 25, 100, 40, 100 }; + c_vs_t.assign(vals3, 4, 2); + params = std::shared_ptr(new thermal_params({ dt_hour, mass, surface_area, Cp, h, R, c_vs_t })); + params->option = thermal_params::SCHEDULE; + params->T_room_schedule = std::move(T_room_C); + params->analytical_model = true; + initialize(); + state->T_room = params->T_room_schedule[0]; +} + thermal_t::thermal_t(std::shared_ptr p) { params = std::move(p); initialize(); @@ -118,13 +127,17 @@ void thermal_t::replace_battery(size_t lifetimeIndex) { } void thermal_t::calc_capacity() { - - double percent; - if (params->analytical_model) - percent = 100 * exp(-(Ea_d0_1 / Rug) * (1 / state->T_batt - 1 / T_ref) - - (Ea_d0_2 / Rug) * pow((1 / state->T_batt - 1 / T_ref), 2)); + double percent; + if (params->analytical_model) { + percent = 100 * exp(-(Ea_d0_1 / Rug) * (1 /( state->T_batt+273) - 1 / T_ref) - + (Ea_d0_2 / Rug) * pow((1 / (state->T_batt+273) - 1 / T_ref), 2)); + } else + { percent = util::linterp_col(params->cap_vs_temp, 0, state->T_batt, 1); + } + + if (std::isnan(percent) || percent < 0 || percent > 100) { percent = 100; @@ -190,7 +203,7 @@ void losses_t::initialize() { fail: throw std::runtime_error("losses_t error: loss arrays length must be 1 or 12 for monthly input mode"); } - else if (params->loss_choice == losses_params::SCHEDULE) { + else { if (params->schedule_loss.empty()) { throw std::runtime_error("losses_t error: loss length must be greater than 0 for schedule mode"); } @@ -345,7 +358,7 @@ battery_params::battery_params(const std::shared_ptr &cap, cons const std::shared_ptr &life, const std::shared_ptr &loss) { chem = -1; - dt_hour = 0.; + dt_hr = 0.; nominal_energy = 0; nominal_voltage = 0; capacity = cap; @@ -363,7 +376,7 @@ battery_params::battery_params(const battery_params& rhs) { battery_params &battery_params::operator=(const battery_params &rhs) { if (this != &rhs) { chem = rhs.chem; - dt_hour = rhs.dt_hour; + dt_hr = rhs.dt_hr; nominal_voltage = rhs.nominal_voltage; nominal_energy = rhs.nominal_energy; if (capacity) @@ -406,18 +419,18 @@ void battery_t::initialize() { if (params->voltage->voltage_choice == voltage_params::TABLE || params->chem == battery_params::IRON_FLOW) { voltage = std::unique_ptr(new voltage_table_t(params->voltage)); } - //Rohit Add lithium_ION_NMC - else if (params->chem == battery_params::LEAD_ACID || params->chem == battery_params::LITHIUM_ION - || params->chem == battery_params::LITHIUM_ION_NMC) { + else if (params->chem == battery_params::LEAD_ACID || params->chem == battery_params::LITHIUM_ION) { voltage = std::unique_ptr(new voltage_dynamic_t(params->voltage)); } - else if (params->chem == battery_params::VANADIUM_REDOX) { voltage = std::unique_ptr(new voltage_vanadium_redox_t(params->voltage)); } // lifetime - lifetime = std::unique_ptr(new lifetime_t(params->lifetime)); + if (params->lifetime->model_choice == lifetime_params::CALCYC) + lifetime = std::unique_ptr(new lifetime_calendar_cycle_t(params->lifetime)); + else + lifetime = std::unique_ptr(new lifetime_nmc_t(params->lifetime)); // thermal thermal = std::unique_ptr(new thermal_t(params->thermal)); @@ -438,7 +451,7 @@ battery_t::battery_t(double dt_hr, int chem, capacity_t *capacity_model, voltage state = std::make_shared(capacity->state, voltage->state, thermal->state, lifetime->state, losses->state); params = std::make_shared(capacity->params, voltage->params, thermal->params, lifetime->params, losses->params); - params->dt_hour = dt_hr; + params->dt_hr = dt_hr; params->chem = chem; params->nominal_voltage = params->voltage->Vnom_default * params->voltage->num_cells_series; params->nominal_energy = params->nominal_voltage * params->voltage->num_strings * params->voltage->dynamic.Qfull * 1e-3; @@ -466,7 +479,7 @@ battery_t &battery_t::operator=(const battery_t& rhs) { capacity = std::unique_ptr(rhs.capacity->clone()); voltage = std::unique_ptr(rhs.voltage->clone()); thermal = std::unique_ptr(new thermal_t(*rhs.thermal)); - lifetime = std::unique_ptr(new lifetime_t(*rhs.lifetime)); + lifetime = std::unique_ptr(rhs.lifetime->clone()); losses = std::unique_ptr(new losses_t(*rhs.losses)); state = std::make_shared(capacity->state, voltage->state, thermal->state, lifetime->state, losses->state); *state->replacement = *rhs.state->replacement; @@ -562,6 +575,18 @@ double battery_t::calculate_max_discharge_kw(double *max_current_A) { return power_W / 1000.; } +void battery_t::ChangeTimestep(double dt_hr) { + if (dt_hr <= 0) + throw std::runtime_error("battery_t timestep must be greater than 0 hour"); + if (dt_hr > 1) + throw std::runtime_error("battery_t timestep must be less than or equal to 1 hour"); + params->dt_hr = dt_hr; + params->capacity->dt_hr = dt_hr; + params->voltage->dt_hr = dt_hr; + params->thermal->dt_hr = dt_hr; + params->lifetime->dt_hr = dt_hr; +} + double battery_t::run(size_t lifetimeIndex, double &I) { // Temperature affects capacity, but capacity model can reduce current, which reduces temperature, need to iterate double I_initial = I; @@ -614,11 +639,11 @@ void battery_t::runCapacityModel(double &I) { // Need to first update capacity model to ensure temperature accounted for capacity->updateCapacityForThermal(thermal->capacity_percent()); } - capacity->updateCapacity(I, params->dt_hour); + capacity->updateCapacity(I, params->dt_hr); } void battery_t::runVoltageModel() { - voltage->updateVoltage(capacity->q0(), capacity->qmax(), capacity->I(), thermal->T_battery(), params->dt_hour); + voltage->updateVoltage(capacity->q0(), capacity->qmax(), capacity->I(), thermal->T_battery(), params->dt_hr); } void battery_t::runLifetimeModel(size_t lifetimeIndex) { @@ -630,7 +655,7 @@ void battery_t::runLifetimeModel(size_t lifetimeIndex) { void battery_t::runLossesModel(size_t idx) { if (idx > state->last_idx || idx == 0) { - losses->run_losses(idx, params->dt_hour, capacity->charge_operation()); + losses->run_losses(idx, params->dt_hr, capacity->charge_operation()); state->last_idx = idx; } } @@ -660,7 +685,7 @@ void battery_t::runReplacement(size_t year, size_t hour, size_t step) { if (replace) { state->replacement->n_replacements++; - state->replacement->indices_replaced.push_back(util::lifetimeIndex(year, hour, step, (size_t) (1 / params->dt_hour))); + state->replacement->indices_replaced.push_back(util::lifetimeIndex(year, hour, step, (size_t) (1 / params->dt_hr))); lifetime->replaceBattery(percent); capacity->replace_battery(percent); thermal->replace_battery(year); @@ -717,7 +742,7 @@ double battery_t::energy_available(double SOC_min) { double battery_t::power_to_fill(double SOC_max) { // in one time step - return (this->energy_to_fill(SOC_max) / params->dt_hour); + return (this->energy_to_fill(SOC_max) / params->dt_hr); } double battery_t::charge_total() { return capacity->q0(); } @@ -737,8 +762,8 @@ double battery_t::SOC() { return capacity->SOC(); } double battery_t::I() { return capacity->I(); } double battery_t::calculate_loss(double power, size_t lifetimeIndex) { - size_t indexYearOne = util::yearOneIndex(params->dt_hour, lifetimeIndex); - auto hourOfYear = (size_t)std::floor(indexYearOne * params->dt_hour); + size_t indexYearOne = util::yearOneIndex(params->dt_hr, lifetimeIndex); + auto hourOfYear = (size_t)std::floor(indexYearOne * params->dt_hr); size_t monthIndex = (size_t) util::month_of((double)(hourOfYear)) - 1; if (params->losses->loss_choice == losses_params::MONTHLY) { @@ -753,7 +778,7 @@ double battery_t::calculate_loss(double power, size_t lifetimeIndex) { } } - else if (params->losses->loss_choice == losses_params::SCHEDULE) { + else { return params->losses->schedule_loss[lifetimeIndex % params->losses->schedule_loss.size()]; } } diff --git a/shared/lib_battery.h b/shared/lib_battery.h index 23dac40fbad..e019f0282e6 100644 --- a/shared/lib_battery.h +++ b/shared/lib_battery.h @@ -33,7 +33,8 @@ OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "lib_util.h" #include "lib_battery_capacity.h" #include "lib_battery_voltage.h" -#include "lib_battery_lifetime.h" +#include "lib_battery_lifetime_calendar_cycle.h" +#include "lib_battery_lifetime_nmc.h" /** * \class thermal_t @@ -54,14 +55,13 @@ struct thermal_state { }; struct thermal_params { - double dt_hour; + double dt_hr; double mass; // [kg] double surface_area; // [m2] - exposed surface area double Cp; // [J/KgK] - battery specific heat capacity double h; // [W/m2/K] - general heat transfer coefficient double resistance; // [Ohm] - internal resistance util::matrix_t cap_vs_temp; - //Rohit add analytical model for updating capacity bool analytical_model; enum OPTIONS { @@ -82,9 +82,12 @@ class thermal_t { thermal_t(double dt_hour, double mass, double surface_area, double R, double Cp, double h, const util::matrix_t &c_vs_t, double T_room_C); - //Rohit - add constructor for analytical model + // constructor for analytical model to update capacity thermal_t(double dt_hour, double mass, double surface_area, double R, double Cp, double h, - double T_room_C); + double T_room_C); + + thermal_t(double dt_hour, double mass, double surface_area, double R, double Cp, double h, + std::vector T_room_C); explicit thermal_t(std::shared_ptr p); @@ -144,7 +147,7 @@ struct losses_state { struct losses_params { enum OPTIONS { - MONTHLY, SCHEDULE, VALUE + MONTHLY, SCHEDULE }; int loss_choice; @@ -268,13 +271,11 @@ struct battery_state { }; struct battery_params { - - //Rohit - Add Lithium_ion_nmc enum CHEM { - LEAD_ACID, LITHIUM_ION, VANADIUM_REDOX, IRON_FLOW, LITHIUM_ION_NMC + LEAD_ACID, LITHIUM_ION, VANADIUM_REDOX, IRON_FLOW }; int chem; - double dt_hour; + double dt_hr; double nominal_energy; double nominal_voltage; std::shared_ptr capacity; @@ -300,11 +301,11 @@ struct battery_params { class battery_t { public: battery_t(double dt_hr, int chem, - capacity_t* capacity_model, - voltage_t* voltage_model, - lifetime_t* lifetime_model, - thermal_t* thermal_model, - losses_t* losses_model); + capacity_t* capacity_model, + voltage_t* voltage_model, + lifetime_t* lifetime_model, + thermal_t* thermal_model, + losses_t* losses_model); explicit battery_t(std::shared_ptr p); @@ -327,6 +328,9 @@ class battery_t { // Returns the % replacement if on a capacity schedule. Returns 0 for "none" or "calendar" double getReplacementPercent(); + // Change the timestep of the battery and its component models + void ChangeTimestep(double dt_hr); + // Run all for single time step, updating all component model states and return the dispatched power [kW] double run(size_t lifetimeIndex, double &I); diff --git a/shared/lib_battery_dispatch.cpp b/shared/lib_battery_dispatch.cpp index b1c71d9ed7f..2aa8bd739f1 100644 --- a/shared/lib_battery_dispatch.cpp +++ b/shared/lib_battery_dispatch.cpp @@ -840,7 +840,7 @@ bool byCost::operator() (grid_point const& a, grid_point const& b) bool byLowestMarginalCost::operator() (grid_point const& a, grid_point const& b) { - + if (fabs(a.MarginalCost() - b.MarginalCost()) < 1e-7) { if (fabs(a.Grid()) < 1e-7 || fabs(b.Grid()) < 1e-7) @@ -855,5 +855,5 @@ bool byLowestMarginalCost::operator() (grid_point const& a, grid_point const& b) } return a.MarginalCost() < b.MarginalCost(); - + } diff --git a/shared/lib_battery_dispatch_automatic_btm.h b/shared/lib_battery_dispatch_automatic_btm.h index 649496aa7e7..3e6693c24ac 100644 --- a/shared/lib_battery_dispatch_automatic_btm.h +++ b/shared/lib_battery_dispatch_automatic_btm.h @@ -108,7 +108,7 @@ class dispatch_automatic_behind_the_meter_t : public dispatch_automatic_t double power_grid_target() override; /*! Return the calculated cost to cycle for battery outputs */ - double cost_to_cycle_per_kwh(); + double cost_to_cycle_per_kwh() override; enum BTM_TARGET_MODES {TARGET_SINGLE_MONTHLY, TARGET_TIME_SERIES}; diff --git a/shared/lib_battery_lifetime.cpp b/shared/lib_battery_lifetime.cpp index 12783090856..18bb5c6463f 100644 --- a/shared/lib_battery_lifetime.cpp +++ b/shared/lib_battery_lifetime.cpp @@ -1,719 +1,88 @@ -/** -BSD-3-Clause -Copyright 2019 Alliance for Sustainable Energy, LLC -Redistribution and use in source and binary forms, with or without modification, are permitted provided -that the following conditions are met : -1. Redistributions of source code must retain the above copyright notice, this list of conditions -and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions -and the following disclaimer in the documentation and/or other materials provided with the distribution. -3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse -or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDER, CONTRIBUTORS, UNITED STATES GOVERNMENT OR UNITED STATES -DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, -OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#include - #include "lib_battery_lifetime.h" +#include "lib_battery_lifetime_calendar_cycle.h" +#include "lib_battery_lifetime_nmc.h" -extern double tolerance; -extern double low_tolerance; - -bool cycle_state::operator==(const cycle_state &p) { - bool equal = (q_relative_cycle == p.q_relative_cycle); - equal &= (n_cycles == p.n_cycles); - equal &= (range == p.range); - equal &= (average_range == p.average_range); - equal &= (rainflow_Xlt == p.rainflow_Xlt); - equal &= (rainflow_Ylt == p.rainflow_Ylt); - equal &= (rainflow_jlt == p.rainflow_jlt); - equal &= (rainflow_peaks == p.rainflow_peaks); - return equal; -} - -void lifetime_cycle_t::initialize() { - if (params->cycling_matrix.nrows() < 3 || params->cycling_matrix.ncols() != 3) - throw std::runtime_error("lifetime_cycle_t error: Battery lifetime matrix must have three columns and at least three rows"); - state = std::make_shared(); - state->n_cycles = 0; - state->q_relative_cycle = bilinear(0., 0); - state->dq_relative_cycle_old = 0; - state->range = 0; - state->average_range = 0; - state->rainflow_jlt = 0; - state->rainflow_Xlt = 0; - state->rainflow_Ylt = 0; - state->rainflow_peaks.clear(); +lifetime_params::lifetime_params() { + model_choice = CALCYC; + cal_cyc = std::make_shared(); } -lifetime_cycle_t::lifetime_cycle_t(const util::matrix_t &batt_lifetime_matrix) { - params = std::make_shared(); - params->cycling_matrix = batt_lifetime_matrix; - initialize(); -} - -lifetime_cycle_t::lifetime_cycle_t(std::shared_ptr params_ptr) : - params(std::move(params_ptr)) { - initialize(); -} - -lifetime_cycle_t::lifetime_cycle_t(const lifetime_cycle_t &rhs) { - state = std::make_shared(*rhs.state); - operator=(rhs); -} - -lifetime_cycle_t &lifetime_cycle_t::operator=(const lifetime_cycle_t &rhs) { +lifetime_params &lifetime_params::operator=(const lifetime_params &rhs) { if (this != &rhs) { - *state = *rhs.state; - *params = *rhs.params; + model_choice = rhs.model_choice; + *cal_cyc = *rhs.cal_cyc; } return *this; } -lifetime_cycle_t *lifetime_cycle_t::clone() { - return new lifetime_cycle_t(*this); -} - -double lifetime_cycle_t::estimateCycleDamage() { - // Initialize assuming 50% DOD - double DOD = 50; - if (state->average_range > 0) { - DOD = state->average_range; - } - return (bilinear(DOD, state->n_cycles + 1) - bilinear(DOD, state->n_cycles + 2)); -} - -// Rohit - function to compute Q_neg for Lithium ion NMC -double lifetime_cycle_t::runCycleLifetimeNMC(double T, double DOD) { - int n_cycles_old = state->n_cycles; - rainflow(DOD); - int dn_cycles = state->n_cycles - n_cycles_old; - - double c2 = c2_ref * exp(-(Ea_c_2 / Rug) * (1. / T - 1. / T_ref)) - * pow(DOD, beta_c2); - - double dq_new; - if (state->dq_relative_cycle_old == 0) - dq_new = 1 - sqrt(1 - 2 * (c2 / c0_ref) * dn_cycles); - else - dq_new = 1 - sqrt(1 - 2 * (c2 / c0_ref) * dn_cycles) + state->dq_relative_cycle_old; - - state->dq_relative_cycle_old = dq_new; - - state->q_relative_cycle = (1- (dq_new)) * 100; - return state->q_relative_cycle; -} - -double lifetime_cycle_t::runCycleLifetime(double DOD) { - rainflow(DOD); - - // return the effective capacity (Q_neg) - return state->q_relative_cycle; -} - -void lifetime_cycle_t::rainflow(double DOD) { - // initialize return code - int retCode = cycle_state::LT_GET_DATA; - - // Begin algorithm - state->rainflow_peaks.push_back(DOD); - bool atStepTwo = true; - - // Loop until break - while (atStepTwo) { - // Rainflow: Step 2: Form ranges X,Y - if (state->rainflow_jlt >= 2) - rainflow_ranges(); - else { - // Get more data (Step 1) - retCode = cycle_state::LT_GET_DATA; - break; - } - - // Rainflow: Step 3: Compare ranges - retCode = rainflow_compareRanges(); - - // We break to get more data, or if we are done with step 5 - if (retCode == cycle_state::LT_GET_DATA) - break; - } - - if (retCode == cycle_state::LT_GET_DATA) - state->rainflow_jlt++; -} - -void lifetime_cycle_t::rainflow_ranges() { - state->rainflow_Ylt = fabs(state->rainflow_peaks[state->rainflow_jlt - (size_t) 1] - state->rainflow_peaks[state->rainflow_jlt - (size_t) 2]); - state->rainflow_Xlt = fabs(state->rainflow_peaks[state->rainflow_jlt] - state->rainflow_peaks[state->rainflow_jlt - (size_t) 1]); -} - -void lifetime_cycle_t::rainflow_ranges_circular(int index) { - size_t end = state->rainflow_peaks.size() - 1; - if (index == 0) { - state->rainflow_Xlt = fabs(state->rainflow_peaks[0] - state->rainflow_peaks[end]); - state->rainflow_Ylt = fabs(state->rainflow_peaks[end] - state->rainflow_peaks[end - 1]); - } else if (index == 1) { - state->rainflow_Xlt = fabs(state->rainflow_peaks[1] - state->rainflow_peaks[0]); - state->rainflow_Ylt = fabs(state->rainflow_peaks[0] - state->rainflow_peaks[end]); - } else - rainflow_ranges(); -} - -int lifetime_cycle_t::rainflow_compareRanges() { - int retCode = cycle_state::LT_SUCCESS; - bool contained = true; - - // modified to disregard some of algorithm which doesn't work well - if (state->rainflow_Xlt < state->rainflow_Ylt) - retCode = cycle_state::LT_GET_DATA; - else if (state->rainflow_Xlt >= state->rainflow_Ylt) - contained = false; - - // Step 5: Count range Y, discard peak & valley of Y, go to Step 2 - if (!contained) { - state->range = state->rainflow_Ylt; - state->average_range = (state->average_range * state->n_cycles + state->range) / (state->n_cycles + (size_t) 1); - state->n_cycles++; - - // the capacity percent cannot increase - double dq = - bilinear(state->average_range, state->n_cycles) - bilinear(state->average_range, state->n_cycles + 1); - if (dq > 0) - state->q_relative_cycle -= dq; - - if (state->q_relative_cycle < 0) - state->q_relative_cycle = 0.; - - // discard peak & valley of Y - double save = state->rainflow_peaks[state->rainflow_jlt]; - state->rainflow_peaks.pop_back(); - state->rainflow_peaks.pop_back(); - state->rainflow_peaks.pop_back(); - state->rainflow_peaks.push_back(save); - state->rainflow_jlt -= 2; - // stay in while loop - retCode = cycle_state::LT_RERANGE; - } - - return retCode; -} - -void lifetime_cycle_t::replaceBattery(double replacement_percent) { - state->q_relative_cycle += replacement_percent; - state->q_relative_cycle = fmin(bilinear(0., 0), state->q_relative_cycle); - - // More work to figure out degradation of multiple-aged battery units - if (replacement_percent == 100) { - state->n_cycles = 0; - } - - state->rainflow_jlt = 0; - state->rainflow_Xlt = 0; - state->rainflow_Ylt = 0; - state->range = 0; - state->rainflow_peaks.clear(); -} - -int lifetime_cycle_t::cycles_elapsed() { return state->n_cycles; } - -double lifetime_cycle_t::cycle_range() { return state->range; } - -double lifetime_cycle_t::average_range() { return state->average_range; } - -double lifetime_cycle_t::capacity_percent() { return state->q_relative_cycle; } - -cycle_state lifetime_cycle_t::get_state() { return *state; } - -double lifetime_cycle_t::bilinear(double DOD, int cycle_number) { - /* - Work could be done to make this simpler - Current idea is to interpolate first along the C = f(n) curves for each DOD to get C_DOD_, C_DOD_+ - Then interpolate C_, C+ to get C at the DOD of interest - */ - - std::vector D_unique_vect; - std::vector C_n_low_vect; - std::vector D_high_vect; - std::vector C_n_high_vect; - std::vector low_indices; - std::vector high_indices; - double D = 0.; - size_t n = 0; - double C = 100; - size_t n_rows = params->cycling_matrix.nrows(); - - // get unique values of D - D_unique_vect.push_back(params->cycling_matrix.at(0, lifetime_params::DOD)); - for (size_t i = 0; i < n_rows; i++) { - bool contained = false; - for (int j = 0; j < (int) D_unique_vect.size(); j++) { - if (params->cycling_matrix.at(i, lifetime_params::DOD) == D_unique_vect[j]) { - contained = true; - break; - } - } - if (!contained) { - D_unique_vect.push_back(params->cycling_matrix.at(i, lifetime_params::DOD)); - } - } - n = D_unique_vect.size(); - - if (n > 1) { - // get where DOD is bracketed [D_lo, DOD, D_hi] - double D_lo = 0; - double D_hi = 100; - - for (size_t i = 0; i < n_rows; i++) { - D = params->cycling_matrix.at(i, lifetime_params::DOD); - if (D < DOD && D > D_lo) - D_lo = D; - else if (D >= DOD && D < D_hi) - D_hi = D; - } - - // Separate table into bins - double D_min = 100.; - double D_max = 0.; - - for (size_t i = 0; i < n_rows; i++) { - D = params->cycling_matrix.at(i, lifetime_params::DOD); - if (D == D_lo) - low_indices.push_back(i); - else if (D == D_hi) - high_indices.push_back(i); - - if (D < D_min) { D_min = D; } - else if (D > D_max) { D_max = D; } - } - - // if we're out of the bounds, just make the upper bound equal to the highest input - if (high_indices.empty()) { - for (size_t i = 0; i != n_rows; i++) { - if (params->cycling_matrix.at(i, lifetime_params::DOD) == D_max) - high_indices.push_back(i); - } - } - - size_t n_rows_lo = low_indices.size(); - size_t n_rows_hi = high_indices.size(); - size_t n_cols = 2; - - // If we aren't bounded, fill in values - if (n_rows_lo == 0) { - // Assumes 0% DOD - for (double i = 0; i < n_rows_hi; i++) { - C_n_low_vect.push_back(0. + i * 500); // cycles - C_n_low_vect.push_back(100.); // 100 % capacity - } - } - - if (n_rows_lo != 0) { - for (int i = 0; i < (int) n_rows_lo; i++) { - C_n_low_vect.push_back(params->cycling_matrix.at(low_indices[i], lifetime_params::CYCLE)); - C_n_low_vect.push_back(params->cycling_matrix.at(low_indices[i], lifetime_params::CAPACITY_CYCLE)); - } - } - if (n_rows_hi != 0) { - for (int i = 0; i < (int) n_rows_hi; i++) { - C_n_high_vect.push_back(params->cycling_matrix.at(high_indices[i], lifetime_params::CYCLE)); - C_n_high_vect.push_back(params->cycling_matrix.at(high_indices[i], lifetime_params::CAPACITY_CYCLE)); - } - } - n_rows_lo = C_n_low_vect.size() / n_cols; - n_rows_hi = C_n_high_vect.size() / n_cols; - - if (n_rows_lo == 0 || n_rows_hi == 0) { - // need a safeguard here - } - - util::matrix_t C_n_low(n_rows_lo, n_cols, &C_n_low_vect); - util::matrix_t C_n_high(n_rows_lo, n_cols, &C_n_high_vect); - - // Compute C(D_lo, n), C(D_hi, n) - double C_Dlo = util::linterp_col(C_n_low, 0, cycle_number, 1); - double C_Dhi = util::linterp_col(C_n_high, 0, cycle_number, 1); - - if (C_Dlo < 0.) - C_Dlo = 0.; - if (C_Dhi > 100.) - C_Dhi = 100.; - - // Interpolate to get C(D, n) - C = util::interpolate(D_lo, C_Dlo, D_hi, C_Dhi, DOD); - } - // just have one row, single level interpolation - else { - C = util::linterp_col(params->cycling_matrix, 1, cycle_number, 2); - } - - return C; -} - -/* -Lifetime Calendar Model -*/ - -bool calendar_state::operator==(const calendar_state &p) { - bool equal = (q_relative_calendar == p.q_relative_calendar); - equal &= (day_age_of_battery == p.day_age_of_battery); - equal &= (dq_relative_calendar_old == p.dq_relative_calendar_old); - return equal; -} - -void lifetime_calendar_t::initialize() { - state = std::make_shared(); - // Rohit - initialize cycle model object in lifetime_calendar_t - cycle_model = std::unique_ptr(new lifetime_cycle_t(params)); - state->day_age_of_battery = 0; - state->q_relative_calendar = 100; - state->dq_relative_calendar_old = 0; - if (params->calendar_choice == lifetime_params::CALENDAR_CHOICE::MODEL || params->calendar_choice == lifetime_params::CALENDAR_CHOICE::NMC_MODEL) { - dt_day = params->dt_hour / util::hours_per_day; - state->q_relative_calendar = params->calendar_q0 * 100; - } - else if (params->calendar_choice == lifetime_params::CALENDAR_CHOICE::TABLE) { - if (params->calendar_matrix.nrows() < 2 || params->calendar_matrix.ncols() != 2) - throw std::runtime_error("lifetime_calendar_t error: Battery calendar lifetime matrix must have 2 columns and at least 2 rows"); - } -} - -lifetime_calendar_t::lifetime_calendar_t(double dt_hour, const util::matrix_t& calendar_matrix) { - params = std::make_shared(); - params->dt_hour = dt_hour; - params->calendar_choice = lifetime_params::CALENDAR_CHOICE::TABLE; - params->calendar_matrix = calendar_matrix; - - initialize(); -} - - -lifetime_calendar_t::lifetime_calendar_t(double dt_hour, double q0, double a, double b, double c) { - params = std::make_shared(); - params->dt_hour = dt_hour; - params->calendar_choice = lifetime_params::CALENDAR_CHOICE::MODEL; - params->calendar_q0 = q0; - params->calendar_a = a; - params->calendar_b = b; - params->calendar_c = c; - - initialize(); -} - -lifetime_calendar_t::lifetime_calendar_t(std::shared_ptr params_ptr) : - params(std::move(params_ptr)) { - initialize(); -} - -lifetime_calendar_t::lifetime_calendar_t(const lifetime_calendar_t &rhs) { - state = std::make_shared(*rhs.state); - params = std::make_shared(*rhs.params); - dt_day = rhs.dt_day; -} - -lifetime_calendar_t &lifetime_calendar_t::operator=(const lifetime_calendar_t &rhs) { - if (this != &rhs) { - *params = *rhs.params; - *state = *rhs.state; - dt_day = rhs.dt_day; - } - return *this; -} - -lifetime_calendar_t *lifetime_calendar_t::clone() { - return new lifetime_calendar_t(*this); -} - -// Rohit - Define negative electrode voltage function -double lifetime_calendar_t::Uneg_computation(double SOC) { - double Uneg = 0.1; - if (SOC <= 0.1) - Uneg = ((0.2420 - 1.2868) / 0.1) * SOC + 1.268; - else - Uneg = ((0.0859 - 0.2420) / 0.9) * (SOC - 0.1) + 0.2420; - return Uneg; -} - -// Rohit - Define open circuit voltage function -double lifetime_calendar_t::Voc_computation(double SOC) { - double Voc = 0.1; - if (SOC <= 0.1) - Voc = ((0.4679) / 0.1) * SOC + 3; - else if (SOC <= 0.6) - Voc = ((3.747 - 3.4679) / 0.5) * (SOC - 0.1) + 3.4679; - else - Voc = ((4.1934 - 3.7469) / 0.4) * (SOC - 0.6) + 3.7469; - return Voc; -} - -double lifetime_calendar_t::capacity_percent() { return state->q_relative_calendar; } - -calendar_state lifetime_calendar_t::get_state() { return *state; } - -double lifetime_calendar_t::runLifetimeCalendarModel(size_t lifetimeIndex, double T, double SOC, bool charge_changed) { - state->day_age_of_battery = (int)(lifetimeIndex / (util::hours_per_day / params->dt_hour)); - - if (params->calendar_choice == lifetime_params::CALENDAR_CHOICE::MODEL) - runLithiumIonModel(T, SOC); - else if (params->calendar_choice == lifetime_params::CALENDAR_CHOICE::TABLE) - runTableModel(); - //Rohit - run LiionNMCModel - else if (params->calendar_choice == lifetime_params::CALENDAR_CHOICE::NMC_MODEL) - runLithiumIonNMCModel(T, SOC, charge_changed); - else - state->q_relative_calendar = 100; - - return state->q_relative_calendar; -} - -void lifetime_calendar_t::runLithiumIonModel(double temp, double SOC) { - temp += 273.15; - SOC *= 0.01; - double k_cal = params->calendar_a * exp(params->calendar_b * (1. / temp - 1. / 296)) - * exp(params->calendar_c * (SOC / temp - 1. / 296)); - double dq_new; - if (state->dq_relative_calendar_old == 0) - dq_new = k_cal * sqrt(dt_day); - else - dq_new = (0.5 * pow(k_cal, 2) / state->dq_relative_calendar_old) * dt_day + state->dq_relative_calendar_old; - state->dq_relative_calendar_old = dq_new; - state->q_relative_calendar = (params->calendar_q0 - (dq_new)) * 100; -} - -// Rohit - define Q_li model for Li-ion -void lifetime_calendar_t::runLithiumIonNMCModel(double temp, double SOC, bool charge_changed) { - temp += 273.15; - SOC *= 0.01; - // write function to find DOD_max, U_neg, and V_oc - double DOD_max = 0.8; - double U_neg = Uneg_computation(SOC); - double V_oc = Voc_computation(SOC); - //calendar component - double b1 = b1_ref * exp(-(Ea_b_1 / Rug) * (1. / temp - 1. / T_ref)) - * exp((alpha_a_b1 * F / Rug) * (U_neg / temp - U_ref / T_ref)) - * exp(gamma * pow(DOD_max, beta_b1)); - - double b2 = b2_ref * exp(-(Ea_b_2 / Rug) * (1. / temp - 1. / T_ref)); - - double b3 = b3_ref * exp(-(Ea_b_3 / Rug) * (1. / temp - 1. / T_ref)) - * exp((alpha_a_b3 * F / Rug) * (V_oc / temp - V_ref / T_ref)) - * (1+theta*DOD_max); - - int n_cycles_old = cycle_model->get_state().n_cycles; - - if (charge_changed) { - cycle_model->rainflow(100. - SOC); - } - - - int dn_cycles = cycle_model->get_state().n_cycles - n_cycles_old; - - double k_cal = 0; - if (state->day_age_of_battery > 0) - k_cal = (0.5 * b1) / (sqrt(state->day_age_of_battery)) + (b3/tau_b3)*exp(-(state->day_age_of_battery/tau_b3)); - else - k_cal = 0; - - double dq_new; - if (state->dq_relative_calendar_old == 0) - dq_new = k_cal * dt_day + b2*dn_cycles; - else - dq_new = k_cal * dt_day + b2*dn_cycles + state->dq_relative_calendar_old; - state->dq_relative_calendar_old = dq_new; - state->q_relative_calendar = (params->calendar_q0 - (dq_new)) * 100; -} - -void lifetime_calendar_t::runTableModel() { - size_t n_rows = params->calendar_matrix.nrows(); - size_t n = n_rows - 1; - size_t day_lo = 0; - size_t day_hi = (size_t) params->calendar_matrix.at(n, lifetime_params::DAYS); - double capacity_lo = 100; - double capacity_hi = 0; - - // interpolation mode - for (size_t i = 0; i != n_rows; i++) { - int day = (int)params->calendar_matrix.at(i, lifetime_params::DAYS); - double capacity = (int) params->calendar_matrix.at(i, lifetime_params::CAPACITY_CAL); - if (day <= state->day_age_of_battery) { - day_lo = day; - capacity_lo = capacity; - } - if (day > state->day_age_of_battery) { - day_hi = day; - capacity_hi = capacity; - break; - } - } - if (day_lo == day_hi) { - day_lo = (int) params->calendar_matrix.at(n - 1, lifetime_params::DAYS); - day_hi = (int) params->calendar_matrix.at(n, lifetime_params::DAYS); - capacity_lo = (int) params->calendar_matrix.at(n - 1, lifetime_params::CAPACITY_CAL); - capacity_hi = (int) params->calendar_matrix.at(n, lifetime_params::CAPACITY_CAL); - } - - state->q_relative_calendar = util::interpolate((double) day_lo, capacity_lo, (double) day_hi, capacity_hi, (double) state->day_age_of_battery); -} - -void lifetime_calendar_t::replaceBattery(double replacement_percent) { - state->day_age_of_battery = 0; - state->dq_relative_calendar_old = 0; - state->q_relative_calendar += replacement_percent; - if (params->calendar_choice == lifetime_params::CALENDAR_CHOICE::MODEL) - state->q_relative_calendar = fmin(params->calendar_q0 * 100, state->q_relative_calendar); - if (params->calendar_choice == lifetime_params::CALENDAR_CHOICE::TABLE) - state->q_relative_calendar = fmin(100, state->q_relative_calendar); -} - -/* -Define Lifetime Model -*/ - lifetime_state::lifetime_state(){ q_relative = 0; + n_cycles = 0; + range = 0; + average_range = 0; + day_age_of_battery = 0; cycle = std::make_shared(); calendar = std::make_shared(); + nmc_state = std::make_shared(); +} + +lifetime_state::lifetime_state(const lifetime_state &rhs) : + lifetime_state() { + operator=(rhs); } lifetime_state::lifetime_state(const std::shared_ptr& cyc, const std::shared_ptr& cal) { + q_relative = 0; + n_cycles = 0; + range = 0; + average_range = 0; + day_age_of_battery = 0; cycle = cyc; calendar = cal; q_relative = fmin(cycle->q_relative_cycle, calendar->q_relative_calendar); } +//Rohit - define constructor for lifetime_state with lifetime_nmc_state as parameter +lifetime_state::lifetime_state(const std::shared_ptr& nmc) { + q_relative = 0; + n_cycles = 0; + range = 0; + average_range = 0; + day_age_of_battery = 0; + nmc_state = nmc; + q_relative = fmin(nmc_state->q_relative_li, nmc_state->q_relative_neg); +} + + lifetime_state &lifetime_state::operator=(const lifetime_state &rhs) { if (this != &rhs) { q_relative = rhs.q_relative; + n_cycles = rhs.n_cycles; + range = rhs.range; + average_range = rhs.average_range; + day_age_of_battery = rhs.day_age_of_battery; *cycle = *rhs.cycle; *calendar = *rhs.calendar; + *nmc_state = *rhs.nmc_state; } return *this; } -void lifetime_t::initialize() { - cycle_model = std::unique_ptr(new lifetime_cycle_t(params)); - calendar_model = std::unique_ptr(new lifetime_calendar_t(params)); - state = std::make_shared(cycle_model->state, calendar_model->state); - state->q_relative = fmin(state->cycle->q_relative_cycle, state->calendar->q_relative_calendar); -} - -lifetime_t::lifetime_t(const util::matrix_t &batt_lifetime_matrix, double dt_hour, - const util::matrix_t &calendar_matrix) { - params = std::make_shared(); - params->dt_hour = dt_hour; - params->cycling_matrix = batt_lifetime_matrix; - params->calendar_choice = lifetime_params::CALENDAR_CHOICE::TABLE; - params->calendar_matrix = calendar_matrix; - - initialize(); -} - -lifetime_t::lifetime_t(const util::matrix_t &batt_lifetime_matrix, double dt_hour, double q0, double a, double b, - double c) { - params = std::make_shared(); - params->dt_hour = dt_hour; - params->cycling_matrix = batt_lifetime_matrix; - params->calendar_choice = lifetime_params::CALENDAR_CHOICE::MODEL; - params->calendar_q0 = q0; - params->calendar_a = a; - params->calendar_b = b; - params->calendar_c = c; - - initialize(); -} - -//Rohit Add lifetime_t constructor for NMC_MODEL -lifetime_t::lifetime_t(double dt_hour) { - params = std::make_shared(); - params->dt_hour = dt_hour; - params->calendar_choice = lifetime_params::CALENDAR_CHOICE::NMC_MODEL; - params->calendar_q0 = 1.07; - - initialize(); -} - -lifetime_t::lifetime_t(const util::matrix_t &batt_lifetime_matrix, double dt_hour) { - params = std::make_shared(); - params->dt_hour = dt_hour; - params->cycling_matrix = batt_lifetime_matrix; - params->calendar_choice = lifetime_params::CALENDAR_CHOICE::NONE; - - initialize(); -} - -lifetime_t::lifetime_t(std::shared_ptr params_ptr): - params(std::move(params_ptr)) { - initialize(); -} - -lifetime_t::lifetime_t(const lifetime_t& rhs) { - state = std::make_shared(); - params = std::make_shared(); - operator=(rhs); +lifetime_t::lifetime_t(const lifetime_t &rhs) { + state = std::make_shared(*rhs.state); + params = std::make_shared(*rhs.params); } -lifetime_t& lifetime_t::operator=(const lifetime_t& rhs) { +lifetime_t &lifetime_t::operator=(const lifetime_t &rhs) { if (this != &rhs) { *params = *rhs.params; - calendar_model = std::unique_ptr(new lifetime_calendar_t(params)); - cycle_model = std::unique_ptr(new lifetime_cycle_t(params)); - state->q_relative = rhs.state->q_relative; - state->calendar = calendar_model->state; - state->cycle = cycle_model->state; + *state = *rhs.state; } return *this; } -lifetime_t *lifetime_t::clone() { - return new lifetime_t(*this); -} - double lifetime_t::capacity_percent() { return state->q_relative; } -double lifetime_t::capacity_percent_cycle() { return cycle_model->capacity_percent(); } - -double lifetime_t::capacity_percent_calendar() { return calendar_model->capacity_percent(); } - -void lifetime_t::runLifetimeModels(size_t lifetimeIndex, bool charge_changed, double prev_DOD, double DOD, double T_battery) { - double q_last = state->q_relative; - - if (q_last > 0) { - double q_cycle = cycle_model->capacity_percent(); - double q_calendar; - - if (charge_changed && params->calendar_choice != lifetime_params::CALENDAR_CHOICE::NMC_MODEL) - q_cycle = cycle_model->runCycleLifetime(prev_DOD); - else if (charge_changed && params->calendar_choice == lifetime_params::CALENDAR_CHOICE::NMC_MODEL) - q_cycle = cycle_model->runCycleLifetimeNMC(T_battery, DOD); - - // Rohit - add parameter charge_changed - q_calendar = calendar_model->runLifetimeCalendarModel(lifetimeIndex, T_battery, 100. - DOD, charge_changed); - - // total capacity is min of cycle (Q_neg) and calendar (Q_li) capacity - state->q_relative = fmin(q_cycle, q_calendar); - } - state->q_relative = fmax(state->q_relative, 0); - - // capacity cannot increase - state->q_relative = fmin(state->q_relative, q_last); -} - -double lifetime_t::estimateCycleDamage() { - return cycle_model->estimateCycleDamage(); -} - -void lifetime_t::replaceBattery(double percent_to_replace) { - cycle_model->replaceBattery(percent_to_replace); - calendar_model->replaceBattery(percent_to_replace); - state->q_relative = fmin(cycle_model->capacity_percent(), calendar_model->capacity_percent()); -} lifetime_params lifetime_t::get_params() { return *params; } diff --git a/shared/lib_battery_lifetime.h b/shared/lib_battery_lifetime.h index a50c306a781..2c225b4b873 100644 --- a/shared/lib_battery_lifetime.h +++ b/shared/lib_battery_lifetime.h @@ -1,265 +1,55 @@ -/** -BSD-3-Clause -Copyright 2019 Alliance for Sustainable Energy, LLC -Redistribution and use in source and binary forms, with or without modification, are permitted provided -that the following conditions are met : -1. Redistributions of source code must retain the above copyright notice, this list of conditions -and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions -and the following disclaimer in the documentation and/or other materials provided with the distribution. -3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse -or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDER, CONTRIBUTORS, UNITED STATES GOVERNMENT OR UNITED STATES -DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, -OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - #ifndef SAM_SIMULATION_CORE_LIB_BATTERY_LIFETIME_H #define SAM_SIMULATION_CORE_LIB_BATTERY_LIFETIME_H #include -#include "lib_util.h" -/* -Lifetime cycling class. -*/ +struct calendar_cycle_params; struct lifetime_params { - // cycling - util::matrix_t cycling_matrix; - enum CYCLING_COLUMNS { - DOD, CYCLE, CAPACITY_CYCLE - }; - - // calendar - //Rohit adding MODEL_NMC option - enum CALENDAR_CHOICE { - NONE, MODEL, TABLE, NMC_MODEL - }; - int calendar_choice; - double dt_hour; - - // K. Smith: Life Prediction model coefficients - double calendar_q0; // unitless - double calendar_a; // 1/sqrt(day) - double calendar_b; // K - double calendar_c; // K - - // table entries - util::matrix_t calendar_matrix; - enum CALENDAR_COLUMNS { - DAYS, CAPACITY_CAL - }; - - friend std::ostream &operator<<(std::ostream &os, const lifetime_params &p); -}; - -struct cycle_state { - double q_relative_cycle; // % - //Rohit - Keep track of cycle degradation for Liion NMC - double dq_relative_cycle_old; - int n_cycles; - double range; - double average_range; - enum RAINFLOW_CODES { - LT_SUCCESS, LT_GET_DATA, LT_RERANGE - }; - double rainflow_Xlt; - double rainflow_Ylt; - int rainflow_jlt; // last index in Peaks, i.e, if Peaks = [0,1], then jlt = 1 - std::vector rainflow_peaks; - - friend std::ostream &operator<<(std::ostream &os, const cycle_state &p); - - bool operator==(const cycle_state &p); -}; + double dt_hr; -class lifetime_cycle_t { + enum MODEL_CHOICE { + CALCYC, + NMCNREL // K. Smith: Life Prediction model coefficients + } model_choice; -public: - /// Constructor for independent model, owning its state and params - lifetime_cycle_t(const util::matrix_t &batt_lifetime_matrix); - - /// Constructor as lifetime_t component - explicit lifetime_cycle_t(std::shared_ptr params_ptr); - - lifetime_cycle_t(const lifetime_cycle_t &rhs); - - lifetime_cycle_t &operator=(const lifetime_cycle_t &rhs); - - lifetime_cycle_t *clone(); - - /// return q, the effective capacity percent - double runCycleLifetime(double DOD); - - /// Rohit - return q, the effective capacity percent for Lithium Ion NMC - double runCycleLifetimeNMC(double T, double DOD); - - /// return hypothetical dq the average cycle - double estimateCycleDamage(); - - /// Return the relative capacity percentage of nominal (%) - double capacity_percent(); + std::shared_ptr cal_cyc; - /// Run the rainflow counting algorithm at the current depth-of-discharge to determine cycle - void rainflow(double DOD); - - /// Replace or partially replace a batteyr - void replaceBattery(double replacement_percent); - - /// Return the total cycles elapse - int cycles_elapsed(); - - /// Return the range of the last cycle - double cycle_range(); - - /// Return the average cycle range - double average_range(); - - cycle_state get_state(); - -protected: - - void rainflow_ranges(); - - void rainflow_ranges_circular(int index); - - int rainflow_compareRanges(); - - /// Bilinear interpolation, given the depth-of-discharge and cycle number, return the capacity percent - double bilinear(double DOD, int cycle_number); - - std::shared_ptr state; - std::shared_ptr params; - -private: - void initialize(); - - /// Rohit - constants for Q_neg of LiionNMC - double c0_ref = 75.1; - double c2_ref = 0.0039193; - double Ea_c_2 = -48260; - double Rug = 8.314; - double T_ref = 298.15; - double beta_c2 = 4.54; - - - friend class lifetime_t; -}; - -/* -Lifetime calendar model -*/ - -struct calendar_state { - double q_relative_calendar; // % - int day_age_of_battery; - double dq_relative_calendar_old; // (0 - 1) + lifetime_params(); - friend std::ostream &operator<<(std::ostream &os, const calendar_state &p); + lifetime_params &operator=(const lifetime_params &rhs); - bool operator==(const calendar_state &p); -}; - -class lifetime_calendar_t { -public: - /// Constructors for independent models, owning its state and params - lifetime_calendar_t(double dt_hour, const util::matrix_t& calendar_matrix); - - explicit lifetime_calendar_t(double dt_hour, double q0= 1.02, double a= 2.66e-3, double b= -7280, double c= 930); - - /// Constructor as lifetime_t component - explicit lifetime_calendar_t(std::shared_ptr params_ptr); - - lifetime_calendar_t(const lifetime_calendar_t &rhs); - - lifetime_calendar_t &operator=(const lifetime_calendar_t &rhs); - - lifetime_calendar_t *clone(); - - /// Given the index of the simulation, the tempertature and SOC, return the effective capacity percent - /// Rohit - Add parameter charge_changed - double runLifetimeCalendarModel(size_t lifetimeIndex, double T, double SOC, bool charge_changed); - - /// Reset or augment the capacity - void replaceBattery(double replacement_percent); - - /// Return the relative capacity percentage of nominal (%) - double capacity_percent(); - - /// Calculate negative electrode voltage from SOC - double Uneg_computation(double SOC); - - /// Calculate open circuit voltage from SOC - double Voc_computation(double SOC); - - calendar_state get_state(); - -protected: - void runLithiumIonModel(double temp_C, double SOC); - - // Rohit - add Q_li for Li_ion model - void runLithiumIonNMCModel(double temp_C, double SOC, bool charge_changed); - - void runTableModel(); - - double dt_day; - - std::shared_ptr state; - std::shared_ptr params; - - //Rohit - Add cycle_model object in lifetime_calendar_t - std::unique_ptr cycle_model; - -private: - void initialize(); - - /// Rohit - Add Li-ion NMC Kandler Smith parameters - double Ea_d0_1 = 4126.0; - double b1_ref = 0.003503; - double Ea_b_1 = 35392.; - double Rug = 8.314; - double T_ref = 298.15; - double alpha_a_b1 = -1; - double F = 96485; - double U_ref = 0.08; - double gamma = 2.472; - double beta_b1 = 2.157; - - double b2_ref = 0.00001541; - double Ea_b_2 = -42800.; - - double b3_ref = 0.003503; - double Ea_b_3 = 42800.; - double alpha_a_b3 = 0.0066; - double V_ref = 3.7; - double theta = 0.135; - double tau_b3 = 5; - - friend class lifetime_t; + friend std::ostream &operator<<(std::ostream &os, const lifetime_params &p); }; -/* -Class to encapsulate multiple lifetime models, and linearly combined the associated degradation and handle replacements -*/ +struct cycle_state; +struct calendar_state; +// Rohit -add states for lifetime_nmc +struct lifetime_nmc_state; struct lifetime_state { double q_relative; // total lifetime relative capacity % + int n_cycles; + double range; + double average_range; + int day_age_of_battery; - std::shared_ptr cycle; + // CALCYC model state std::shared_ptr calendar; + std::shared_ptr cycle; + std::shared_ptr nmc_state; lifetime_state(); + lifetime_state(const lifetime_state &rhs); + lifetime_state(const std::shared_ptr& cyc, const std::shared_ptr& cal); + // Rohit - define lifetime_state constructor with lifetime_nmc_state as parameter + + lifetime_state(const std::shared_ptr& nmc); + lifetime_state &operator=(const lifetime_state &rhs); friend std::ostream &operator<<(std::ostream &os, const lifetime_state &p); @@ -267,45 +57,25 @@ struct lifetime_state { class lifetime_t { public: - /// Cycle with Calendar table - lifetime_t(const util::matrix_t &batt_lifetime_matrix, - double dt_hour, const util::matrix_t& calendar_matrix); - - /// Cycle with Calendar model - lifetime_t(const util::matrix_t &batt_lifetime_matrix, - double dt_hour, double q0, double a, double b, double c); - - /// Rohit NMC model constructor - lifetime_t(double dt_hour); - - /// Cycle with no Calendar - lifetime_t(const util::matrix_t &batt_lifetime_matrix, double dt_hour); + lifetime_t() = default; - explicit lifetime_t(std::shared_ptr params_ptr); + lifetime_t(const lifetime_t &rhs); - lifetime_t(const lifetime_t& rhs); + virtual lifetime_t &operator=(const lifetime_t &rhs); - lifetime_t &operator=(const lifetime_t& rhs); + virtual lifetime_t *clone() = 0; - virtual ~lifetime_t() {}; - - lifetime_t *clone(); + virtual ~lifetime_t() = default; /// Execute the lifetime models given the current lifetime run index, capacity model, and temperature - void runLifetimeModels(size_t lifetimeIndex, bool charge_changed, double prev_DOD, double DOD, double T_battery); - - double estimateCycleDamage(); - - void replaceBattery(double percent_to_replace); + virtual void runLifetimeModels(size_t lifetimeIndex, bool charge_changed, double prev_DOD, double DOD, double T_battery) = 0; /// Return the relative capacity percentage of nominal (%) double capacity_percent(); - /// Return the relative capacity percentage of nominal caused by cycle damage (%) - double capacity_percent_cycle(); + virtual double estimateCycleDamage() = 0; - /// Return the relative capacity percentage of nominal caused by calendar fade (%) - double capacity_percent_calendar(); + virtual void replaceBattery(double percent_to_replace) = 0; lifetime_params get_params(); @@ -316,12 +86,6 @@ class lifetime_t { std::shared_ptr state; std::shared_ptr params; - std::unique_ptr calendar_model; - std::unique_ptr cycle_model; - -private: - void initialize(); - friend class battery_t; }; diff --git a/shared/lib_battery_lifetime_calendar_cycle.cpp b/shared/lib_battery_lifetime_calendar_cycle.cpp new file mode 100644 index 00000000000..6b37a1dc475 --- /dev/null +++ b/shared/lib_battery_lifetime_calendar_cycle.cpp @@ -0,0 +1,590 @@ +/** +BSD-3-Clause +Copyright 2019 Alliance for Sustainable Energy, LLC +Redistribution and use in source and binary forms, with or without modification, are permitted provided +that the following conditions are met : +1. Redistributions of source code must retain the above copyright notice, this list of conditions +and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions +and the following disclaimer in the documentation and/or other materials provided with the distribution. +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse +or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDER, CONTRIBUTORS, UNITED STATES GOVERNMENT OR UNITED STATES +DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, +OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include + +#include "lib_battery_lifetime.h" +#include "lib_battery_lifetime_nmc.h" +#include "lib_battery_lifetime_calendar_cycle.h" + +extern double tolerance; +extern double low_tolerance; + +void lifetime_cycle_t::initialize() { + state->n_cycles = 0; + state->range = 0; + state->average_range = 0; + state->cycle->q_relative_cycle = bilinear(0., 0); + state->cycle->rainflow_jlt = 0; + state->cycle->rainflow_Xlt = 0; + state->cycle->rainflow_Ylt = 0; + state->cycle->rainflow_peaks.clear(); +} + +lifetime_cycle_t::lifetime_cycle_t(const util::matrix_t &batt_lifetime_matrix) { + params = std::make_shared(); + params->cal_cyc->cycling_matrix = batt_lifetime_matrix; + state = std::make_shared(); + initialize(); +} + +lifetime_cycle_t::lifetime_cycle_t(std::shared_ptr params_ptr) : + params(std::move(params_ptr)) { + state = std::make_shared(); + initialize(); +} + +lifetime_cycle_t::lifetime_cycle_t(std::shared_ptr params_ptr, std::shared_ptr state_ptr) : + params(std::move(params_ptr)), + state(std::move(state_ptr)){ + initialize(); +} + +lifetime_cycle_t::lifetime_cycle_t(const lifetime_cycle_t &rhs) { + state = std::make_shared(*rhs.state); + operator=(rhs); +} + +lifetime_cycle_t &lifetime_cycle_t::operator=(const lifetime_cycle_t &rhs) { + if (this != &rhs) { + *state = *rhs.state; + *params = *rhs.params; + } + return *this; +} + +lifetime_cycle_t *lifetime_cycle_t::clone() { + return new lifetime_cycle_t(*this); +} + +double lifetime_cycle_t::estimateCycleDamage() { + // Initialize assuming 50% DOD + double DOD = 50; + if (state->average_range > 0) { + DOD = state->average_range; + } + return (bilinear(DOD, state->n_cycles + 1) - bilinear(DOD, state->n_cycles + 2)); +} + +double lifetime_cycle_t::runCycleLifetime(double DOD) { + rainflow(DOD); + + // return the effective capacity (Q_neg) + return state->cycle->q_relative_cycle; +} + +void lifetime_cycle_t::rainflow(double DOD) { + // initialize return code + int retCode = cycle_state::LT_GET_DATA; + + // Begin algorithm + state->cycle->rainflow_peaks.push_back(DOD); + bool atStepTwo = true; + + // Loop until break + while (atStepTwo) { + // Rainflow: Step 2: Form ranges X,Y + if (state->cycle->rainflow_jlt >= 2) + rainflow_ranges(); + else { + // Get more data (Step 1) + retCode = cycle_state::LT_GET_DATA; + break; + } + + // Rainflow: Step 3: Compare ranges + retCode = rainflow_compareRanges(); + + // We break to get more data, or if we are done with step 5 + if (retCode == cycle_state::LT_GET_DATA) + break; + } + + if (retCode == cycle_state::LT_GET_DATA) + state->cycle->rainflow_jlt++; +} + +void lifetime_cycle_t::rainflow_ranges() { + state->cycle->rainflow_Ylt = fabs(state->cycle->rainflow_peaks[state->cycle->rainflow_jlt - (size_t) 1] - state->cycle->rainflow_peaks[state->cycle->rainflow_jlt - (size_t) 2]); + state->cycle->rainflow_Xlt = fabs(state->cycle->rainflow_peaks[state->cycle->rainflow_jlt] - state->cycle->rainflow_peaks[state->cycle->rainflow_jlt - (size_t) 1]); +} + +void lifetime_cycle_t::rainflow_ranges_circular(int index) { + size_t end = state->cycle->rainflow_peaks.size() - 1; + if (index == 0) { + state->cycle->rainflow_Xlt = fabs(state->cycle->rainflow_peaks[0] - state->cycle->rainflow_peaks[end]); + state->cycle->rainflow_Ylt = fabs(state->cycle->rainflow_peaks[end] - state->cycle->rainflow_peaks[end - 1]); + } else if (index == 1) { + state->cycle->rainflow_Xlt = fabs(state->cycle->rainflow_peaks[1] - state->cycle->rainflow_peaks[0]); + state->cycle->rainflow_Ylt = fabs(state->cycle->rainflow_peaks[0] - state->cycle->rainflow_peaks[end]); + } else + rainflow_ranges(); +} + +int lifetime_cycle_t::rainflow_compareRanges() { + int retCode = cycle_state::LT_SUCCESS; + bool contained = true; + + // modified to disregard some of algorithm which doesn't work well + if (state->cycle->rainflow_Xlt < state->cycle->rainflow_Ylt) + retCode = cycle_state::LT_GET_DATA; + else if (state->cycle->rainflow_Xlt >= state->cycle->rainflow_Ylt) + contained = false; + + // Step 5: Count range Y, discard peak & valley of Y, go to Step 2 + if (!contained) { + state->range = state->cycle->rainflow_Ylt; + state->average_range = (state->average_range * state->n_cycles + state->range) / (double)(state->n_cycles + (size_t) 1); + state->n_cycles++; + + // the capacity percent cannot increase + double dq = + bilinear(state->average_range, state->n_cycles) - bilinear(state->average_range, state->n_cycles + 1); + if (dq > 0) + state->cycle->q_relative_cycle -= dq; + + if (state->cycle->q_relative_cycle < 0) + state->cycle->q_relative_cycle = 0.; + + // discard peak & valley of Y + double save = state->cycle->rainflow_peaks[state->cycle->rainflow_jlt]; + state->cycle->rainflow_peaks.pop_back(); + state->cycle->rainflow_peaks.pop_back(); + state->cycle->rainflow_peaks.pop_back(); + state->cycle->rainflow_peaks.push_back(save); + state->cycle->rainflow_jlt -= 2; + // stay in while loop + retCode = cycle_state::LT_RERANGE; + } + + return retCode; +} + +void lifetime_cycle_t::replaceBattery(double replacement_percent) { + state->cycle->q_relative_cycle += replacement_percent; + state->cycle->q_relative_cycle = fmin(bilinear(0., 0), state->cycle->q_relative_cycle); + + // More work to figure out degradation of multiple-aged battery units + if (replacement_percent == 100) { + state->n_cycles = 0; + } + + state->cycle->rainflow_jlt = 0; + state->cycle->rainflow_Xlt = 0; + state->cycle->rainflow_Ylt = 0; + state->range = 0; + state->cycle->rainflow_peaks.clear(); +} + +int lifetime_cycle_t::cycles_elapsed() { return state->n_cycles; } + +double lifetime_cycle_t::cycle_range() { return state->range; } + +double lifetime_cycle_t::average_range() { return state->average_range; } + +double lifetime_cycle_t::capacity_percent() { return state->cycle->q_relative_cycle; } + +lifetime_state lifetime_cycle_t::get_state() { return *state; } + +double lifetime_cycle_t::bilinear(double DOD, int cycle_number) { + /* + Work could be done to make this simpler + Current idea is to interpolate first along the C = f(n) curves for each DOD to get C_DOD_, C_DOD_+ + Then interpolate C_, C+ to get C at the DOD of interest + */ + + std::vector D_unique_vect; + std::vector C_n_low_vect; + std::vector D_high_vect; + std::vector C_n_high_vect; + std::vector low_indices; + std::vector high_indices; + double D = 0.; + size_t n = 0; + double C = 100; + size_t n_rows = params->cal_cyc->cycling_matrix.nrows(); + + // get unique values of D + D_unique_vect.push_back(params->cal_cyc->cycling_matrix.at(0, calendar_cycle_params::DOD)); + for (size_t i = 0; i < n_rows; i++) { + bool contained = false; + for (double j : D_unique_vect) { + if (params->cal_cyc->cycling_matrix.at(i, calendar_cycle_params::DOD) == j) { + contained = true; + break; + } + } + if (!contained) { + D_unique_vect.push_back(params->cal_cyc->cycling_matrix.at(i, calendar_cycle_params::DOD)); + } + } + n = D_unique_vect.size(); + + if (n > 1) { + // get where DOD is bracketed [D_lo, DOD, D_hi] + double D_lo = 0; + double D_hi = 100; + + for (size_t i = 0; i < n_rows; i++) { + D = params->cal_cyc->cycling_matrix.at(i, calendar_cycle_params::DOD); + if (D < DOD && D > D_lo) + D_lo = D; + else if (D >= DOD && D < D_hi) + D_hi = D; + } + + // Separate table into bins + double D_min = 100.; + double D_max = 0.; + + for (size_t i = 0; i < n_rows; i++) { + D = params->cal_cyc->cycling_matrix.at(i, calendar_cycle_params::DOD); + if (D == D_lo) + low_indices.push_back(i); + else if (D == D_hi) + high_indices.push_back(i); + + if (D < D_min) { D_min = D; } + else if (D > D_max) { D_max = D; } + } + + // if we're out of the bounds, just make the upper bound equal to the highest input + if (high_indices.empty()) { + for (size_t i = 0; i != n_rows; i++) { + if (params->cal_cyc->cycling_matrix.at(i, calendar_cycle_params::DOD) == D_max) + high_indices.push_back(i); + } + } + + size_t n_rows_lo = low_indices.size(); + size_t n_rows_hi = high_indices.size(); + size_t n_cols = 2; + + // If we aren't bounded, fill in values + if (n_rows_lo == 0) { + // Assumes 0% DOD + for (int i = 0; i < n_rows_hi; i++) { + C_n_low_vect.push_back(0. + (double)i * 500); // cycles + C_n_low_vect.push_back(100.); // 100 % capacity + } + } + + if (n_rows_lo != 0) { + for (int i = 0; i < (int) n_rows_lo; i++) { + C_n_low_vect.push_back(params->cal_cyc->cycling_matrix.at(low_indices[i], calendar_cycle_params::CYCLE)); + C_n_low_vect.push_back(params->cal_cyc->cycling_matrix.at(low_indices[i], calendar_cycle_params::CAPACITY_CYCLE)); + } + } + if (n_rows_hi != 0) { + for (int i = 0; i < (int) n_rows_hi; i++) { + C_n_high_vect.push_back(params->cal_cyc->cycling_matrix.at(high_indices[i], calendar_cycle_params::CYCLE)); + C_n_high_vect.push_back(params->cal_cyc->cycling_matrix.at(high_indices[i], calendar_cycle_params::CAPACITY_CYCLE)); + } + } + n_rows_lo = C_n_low_vect.size() / n_cols; + n_rows_hi = C_n_high_vect.size() / n_cols; + + if (n_rows_lo == 0 || n_rows_hi == 0) { + // need a safeguard here + } + + util::matrix_t C_n_low(n_rows_lo, n_cols, &C_n_low_vect); + util::matrix_t C_n_high(n_rows_lo, n_cols, &C_n_high_vect); + + // Compute C(D_lo, n), C(D_hi, n) + double C_Dlo = util::linterp_col(C_n_low, 0, cycle_number, 1); + double C_Dhi = util::linterp_col(C_n_high, 0, cycle_number, 1); + + if (C_Dlo < 0.) + C_Dlo = 0.; + if (C_Dhi > 100.) + C_Dhi = 100.; + + // Interpolate to get C(D, n) + C = util::interpolate(D_lo, C_Dlo, D_hi, C_Dhi, DOD); + } + // just have one row, single level interpolation + else { + C = util::linterp_col(params->cal_cyc->cycling_matrix, 1, cycle_number, 2); + } + + return C; +} + +/* +Lifetime Calendar Model +*/ + +bool calendar_state::operator==(const calendar_state &p) const { + bool equal = (q_relative_calendar == p.q_relative_calendar); +// equal &= (day_age_of_battery == p.day_age_of_battery); + equal &= (dq_relative_calendar_old == p.dq_relative_calendar_old); + return equal; +} + +void lifetime_calendar_t::initialize() { + state->day_age_of_battery = 0; + state->calendar->q_relative_calendar = 100; + state->calendar->dq_relative_calendar_old = 0; + if (params->cal_cyc->calendar_choice == calendar_cycle_params::CALENDAR_CHOICE::MODEL) { + dt_day = params->dt_hr / util::hours_per_day; + state->calendar->q_relative_calendar = params->cal_cyc->calendar_q0 * 100; + } + else if (params->cal_cyc->calendar_choice == calendar_cycle_params::CALENDAR_CHOICE::TABLE) { + if (params->cal_cyc->calendar_matrix.nrows() < 2 || params->cal_cyc->calendar_matrix.ncols() != 2) + throw std::runtime_error("lifetime_calendar_t error: Battery calendar lifetime matrix must have 2 columns and at least 2 rows"); + } +} + +lifetime_calendar_t::lifetime_calendar_t(double dt_hour, const util::matrix_t& calendar_matrix) { + params = std::make_shared(); + params->dt_hr = dt_hour; + params->cal_cyc->calendar_choice = calendar_cycle_params::CALENDAR_CHOICE::TABLE; + params->cal_cyc->calendar_matrix = calendar_matrix; + state = std::make_shared(); + initialize(); +} + + +lifetime_calendar_t::lifetime_calendar_t(double dt_hour, double q0, double a, double b, double c) { + params = std::make_shared(); + params->dt_hr = dt_hour; + params->cal_cyc->calendar_choice = calendar_cycle_params::CALENDAR_CHOICE::MODEL; + params->cal_cyc->calendar_q0 = q0; + params->cal_cyc->calendar_a = a; + params->cal_cyc->calendar_b = b; + params->cal_cyc->calendar_c = c; + state = std::make_shared(); + initialize(); +} + +lifetime_calendar_t::lifetime_calendar_t(std::shared_ptr params_ptr, std::shared_ptr state_ptr) : + params(std::move(params_ptr)), + state(std::move(state_ptr)) +{ + initialize(); +} + +lifetime_calendar_t::lifetime_calendar_t(const lifetime_calendar_t &rhs) { + state = std::make_shared(*rhs.state); + params = std::make_shared(*rhs.params); + dt_day = rhs.dt_day; +} + +lifetime_calendar_t &lifetime_calendar_t::operator=(const lifetime_calendar_t &rhs) { + if (this != &rhs) { + *params = *rhs.params; + *state = *rhs.state; + dt_day = rhs.dt_day; + } + return *this; +} + +lifetime_calendar_t *lifetime_calendar_t::clone() { + return new lifetime_calendar_t(*this); +} + +double lifetime_calendar_t::capacity_percent() { return state->calendar->q_relative_calendar; } + +lifetime_state lifetime_calendar_t::get_state() { return *state; } + +double lifetime_calendar_t::runLifetimeCalendarModel(size_t lifetimeIndex, double T, double SOC) { + state->day_age_of_battery = (int)(lifetimeIndex / (util::hours_per_day / params->dt_hr)); + + if (params->cal_cyc->calendar_choice == calendar_cycle_params::CALENDAR_CHOICE::MODEL) + runLithiumIonModel(T, SOC); + else if (params->cal_cyc->calendar_choice == calendar_cycle_params::CALENDAR_CHOICE::TABLE) + runTableModel(); + else + state->calendar->q_relative_calendar = 100; + + return state->calendar->q_relative_calendar; +} + +void lifetime_calendar_t::runLithiumIonModel(double temp, double SOC) { + temp += 273.15; + SOC *= 0.01; + double k_cal = params->cal_cyc->calendar_a * exp(params->cal_cyc->calendar_b * (1. / temp - 1. / 296)) + * exp(params->cal_cyc->calendar_c * (SOC / temp - 1. / 296)); + double dq_new; + if (state->calendar->dq_relative_calendar_old == 0) + dq_new = k_cal * sqrt(dt_day); + else + dq_new = (0.5 * pow(k_cal, 2) / state->calendar->dq_relative_calendar_old) * dt_day + state->calendar->dq_relative_calendar_old; + state->calendar->dq_relative_calendar_old = dq_new; + state->calendar->q_relative_calendar = (params->cal_cyc->calendar_q0 - (dq_new)) * 100; +} + +void lifetime_calendar_t::runTableModel() { + size_t n_rows = params->cal_cyc->calendar_matrix.nrows(); + size_t n = n_rows - 1; + size_t day_lo = 0; + auto day_hi = (size_t) params->cal_cyc->calendar_matrix.at(n, calendar_cycle_params::DAYS); + double capacity_lo = 100; + double capacity_hi = 0; + + // interpolation mode + for (size_t i = 0; i != n_rows; i++) { + int day = (int)params->cal_cyc->calendar_matrix.at(i, calendar_cycle_params::DAYS); + double capacity = (int) params->cal_cyc->calendar_matrix.at(i, calendar_cycle_params::CAPACITY_CAL); + if (day <= state->day_age_of_battery) { + day_lo = day; + capacity_lo = capacity; + } + if (day > state->day_age_of_battery) { + day_hi = day; + capacity_hi = capacity; + break; + } + } + if (day_lo == day_hi) { + day_lo = (int) params->cal_cyc->calendar_matrix.at(n - 1, calendar_cycle_params::DAYS); + day_hi = (int) params->cal_cyc->calendar_matrix.at(n, calendar_cycle_params::DAYS); + capacity_lo = (int) params->cal_cyc->calendar_matrix.at(n - 1, calendar_cycle_params::CAPACITY_CAL); + capacity_hi = (int) params->cal_cyc->calendar_matrix.at(n, calendar_cycle_params::CAPACITY_CAL); + } + + state->calendar->q_relative_calendar = util::interpolate((double) day_lo, capacity_lo, (double) day_hi, capacity_hi, (double) state->day_age_of_battery); +} + +void lifetime_calendar_t::replaceBattery(double replacement_percent) { + state->day_age_of_battery = 0; + state->calendar->dq_relative_calendar_old = 0; + state->calendar->q_relative_calendar += replacement_percent; + if (params->cal_cyc->calendar_choice == calendar_cycle_params::MODEL) + state->calendar->q_relative_calendar = fmin(params->cal_cyc->calendar_q0 * 100, state->calendar->q_relative_calendar); + if (params->cal_cyc->calendar_choice == calendar_cycle_params::TABLE) + state->calendar->q_relative_calendar = fmin(100, state->calendar->q_relative_calendar); +} + +/* +Define Lifetime Model +*/ + +void lifetime_calendar_cycle_t::initialize() { + state = std::make_shared(); + if (params->cal_cyc->cycling_matrix.nrows() < 3 || params->cal_cyc->cycling_matrix.ncols() != 3) + throw std::runtime_error("lifetime_cycle_t error: Battery lifetime matrix must have three columns and at least three rows"); + cycle_model = std::unique_ptr(new lifetime_cycle_t(params, state)); + calendar_model = std::unique_ptr(new lifetime_calendar_t(params, state)); + state->q_relative = fmin(state->cycle->q_relative_cycle, state->calendar->q_relative_calendar); +} + +lifetime_calendar_cycle_t::lifetime_calendar_cycle_t(const util::matrix_t &batt_lifetime_matrix, double dt_hour, + const util::matrix_t &calendar_matrix) { + params = std::make_shared(); + params->model_choice = lifetime_params::CALCYC; + params->dt_hr = dt_hour; + params->cal_cyc->cycling_matrix = batt_lifetime_matrix; + params->cal_cyc->calendar_choice = calendar_cycle_params::CALENDAR_CHOICE::TABLE; + params->cal_cyc->calendar_matrix = calendar_matrix; + + initialize(); +} + +lifetime_calendar_cycle_t::lifetime_calendar_cycle_t(const util::matrix_t &batt_lifetime_matrix, double dt_hour, double q0, double a, double b, + double c) { + params = std::make_shared(); + params->model_choice = lifetime_params::CALCYC; + params->dt_hr = dt_hour; + params->cal_cyc->cycling_matrix = batt_lifetime_matrix; + params->cal_cyc->calendar_choice = calendar_cycle_params::CALENDAR_CHOICE::MODEL; + params->cal_cyc->calendar_q0 = q0; + params->cal_cyc->calendar_a = a; + params->cal_cyc->calendar_b = b; + params->cal_cyc->calendar_c = c; + + initialize(); +} + +lifetime_calendar_cycle_t::lifetime_calendar_cycle_t(const util::matrix_t &batt_lifetime_matrix, double dt_hour) { + params = std::make_shared(); + params->model_choice = lifetime_params::CALCYC;\ + params->dt_hr = dt_hour; + params->cal_cyc->cycling_matrix = batt_lifetime_matrix; + params->cal_cyc->calendar_choice = calendar_cycle_params::CALENDAR_CHOICE::NONE; + + initialize(); +} + +lifetime_calendar_cycle_t::lifetime_calendar_cycle_t(std::shared_ptr params_ptr) { + params = std::move(params_ptr); + initialize(); +} + +lifetime_calendar_cycle_t::lifetime_calendar_cycle_t(const lifetime_calendar_cycle_t& rhs) : + lifetime_t(rhs){ + operator=(rhs); +} + +lifetime_calendar_cycle_t& lifetime_calendar_cycle_t::operator=(const lifetime_calendar_cycle_t& rhs) { + if (this != &rhs) { + *params = *rhs.params; + *state = *rhs.state; + calendar_model = std::unique_ptr(new lifetime_calendar_t(params, state)); + cycle_model = std::unique_ptr(new lifetime_cycle_t(params, state)); + } + return *this; +} + +lifetime_calendar_cycle_t *lifetime_calendar_cycle_t::clone() { + return new lifetime_calendar_cycle_t(*this); +} + +double lifetime_calendar_cycle_t::capacity_percent_cycle() { return cycle_model->capacity_percent(); } + +double lifetime_calendar_cycle_t::capacity_percent_calendar() { return calendar_model->capacity_percent(); } + +void lifetime_calendar_cycle_t::runLifetimeModels(size_t lifetimeIndex, bool charge_changed, double prev_DOD, double DOD, double T_battery) { + double q_last = state->q_relative; + + if (q_last > 0) { + double q_cycle = cycle_model->capacity_percent(); + double q_calendar; + + if (charge_changed) + q_cycle = cycle_model->runCycleLifetime(prev_DOD); + else if (lifetimeIndex == 0) + q_cycle = cycle_model->runCycleLifetime(DOD); + + q_calendar = calendar_model->runLifetimeCalendarModel(lifetimeIndex, T_battery, 100. - DOD); + + // total capacity is min of cycle (Q_neg) and calendar (Q_li) capacity + state->q_relative = fmin(q_cycle, q_calendar); + } + state->q_relative = fmax(state->q_relative, 0); + + // capacity cannot increase + state->q_relative = fmin(state->q_relative, q_last); +} + +double lifetime_calendar_cycle_t::estimateCycleDamage() { + return cycle_model->estimateCycleDamage(); +} + +void lifetime_calendar_cycle_t::replaceBattery(double percent_to_replace) { + cycle_model->replaceBattery(percent_to_replace); + calendar_model->replaceBattery(percent_to_replace); + state->q_relative = fmin(cycle_model->capacity_percent(), calendar_model->capacity_percent()); +} + diff --git a/shared/lib_battery_lifetime_calendar_cycle.h b/shared/lib_battery_lifetime_calendar_cycle.h new file mode 100644 index 00000000000..2b2fe7630ff --- /dev/null +++ b/shared/lib_battery_lifetime_calendar_cycle.h @@ -0,0 +1,249 @@ +/** +BSD-3-Clause +Copyright 2019 Alliance for Sustainable Energy, LLC +Redistribution and use in source and binary forms, with or without modification, are permitted provided +that the following conditions are met : +1. Redistributions of source code must retain the above copyright notice, this list of conditions +and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions +and the following disclaimer in the documentation and/or other materials provided with the distribution. +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse +or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDER, CONTRIBUTORS, UNITED STATES GOVERNMENT OR UNITED STATES +DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, +OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef SAM_SIMULATION_CORE_LIB_BATTERY_LIFETIME_CALENDAR_CYCLE_H +#define SAM_SIMULATION_CORE_LIB_BATTERY_LIFETIME_CALENDAR_CYCLE_H + +#include + +#include "lib_util.h" +#include "lib_battery_lifetime.h" + + +/* +Lifetime cycling class. +*/ + +struct calendar_cycle_params { + // cycling + util::matrix_t cycling_matrix; + enum CYCLING_COLUMNS { + DOD, CYCLE, CAPACITY_CYCLE + }; + + // calendar + enum CALENDAR_CHOICE { + NONE, MODEL, TABLE + }; + int calendar_choice; + + double calendar_q0; // unitless + double calendar_a; // 1/sqrt(day) + double calendar_b; // K + double calendar_c; // K + + // table entries + util::matrix_t calendar_matrix; + enum CALENDAR_COLUMNS { + DAYS, CAPACITY_CAL + }; + + friend std::ostream &operator<<(std::ostream &os, const calendar_cycle_params &p); +}; + +struct cycle_state { + double q_relative_cycle; // % + enum RAINFLOW_CODES { + LT_SUCCESS, LT_GET_DATA, LT_RERANGE + }; + double rainflow_Xlt; + double rainflow_Ylt; + int rainflow_jlt; // last index in Peaks, i.e, if Peaks = [0,1], then jlt = 1 + std::vector rainflow_peaks; + + friend std::ostream &operator<<(std::ostream &os, const cycle_state &p); +}; + +class lifetime_cycle_t { + +public: + /// Constructor for independent model, owning its state and params + lifetime_cycle_t(const util::matrix_t &batt_lifetime_matrix); + + /// Constructor as lifetime_calendar_cycle_t component + explicit lifetime_cycle_t(std::shared_ptr params_ptr); + + lifetime_cycle_t(std::shared_ptr params_ptr, std::shared_ptr state_ptr); + + lifetime_cycle_t(const lifetime_cycle_t &rhs); + + lifetime_cycle_t &operator=(const lifetime_cycle_t &rhs); + + lifetime_cycle_t *clone(); + + /// return q, the effective capacity percent + double runCycleLifetime(double DOD); + + /// return hypothetical dq the average cycle + double estimateCycleDamage(); + + /// Return the relative capacity percentage of nominal (%) + double capacity_percent(); + + /// Run the rainflow counting algorithm at the current depth-of-discharge to determine cycle + void rainflow(double DOD); + + /// Replace or partially replace a batteyr + void replaceBattery(double replacement_percent); + + /// Return the total cycles elapse + int cycles_elapsed(); + + /// Return the range of the last cycle + double cycle_range(); + + /// Return the average cycle range + double average_range(); + + lifetime_state get_state(); + +protected: + + void rainflow_ranges(); + + void rainflow_ranges_circular(int index); + + int rainflow_compareRanges(); + + /// Bilinear interpolation, given the depth-of-discharge and cycle number, return the capacity percent + double bilinear(double DOD, int cycle_number); + + std::shared_ptr params; + + std::shared_ptr state; + +private: + void initialize(); + + friend class lifetime_t; +}; + +/* +Lifetime calendar model +*/ + +struct calendar_state { + double q_relative_calendar; // % + double dq_relative_calendar_old; // (0 - 1) +// int day_age_of_battery; + + friend std::ostream &operator<<(std::ostream &os, const calendar_state &p); + + bool operator==(const calendar_state &p) const; +}; + +class lifetime_calendar_t { +public: + /// Constructors for independent models, owning its state and params + lifetime_calendar_t(double dt_hour, const util::matrix_t& calendar_matrix); + + explicit lifetime_calendar_t(double dt_hour, double q0= 1.02, double a= 2.66e-3, double b= -7280, double c= 930); + + lifetime_calendar_t(std::shared_ptr params_ptr, std::shared_ptr state_ptr); + + lifetime_calendar_t(const lifetime_calendar_t &rhs); + + lifetime_calendar_t &operator=(const lifetime_calendar_t &rhs); + + lifetime_calendar_t *clone(); + + /// Given the index of the simulation, the tempertature and SOC, return the effective capacity percent + double runLifetimeCalendarModel(size_t lifetimeIndex, double T, double SOC); + + /// Reset or augment the capacity + void replaceBattery(double replacement_percent); + + /// Return the relative capacity percentage of nominal (%) + double capacity_percent(); + + lifetime_state get_state(); + +protected: + void runLithiumIonModel(double temp_C, double SOC); + + void runTableModel(); + + double dt_day; + + std::shared_ptr params; + + std::shared_ptr state; + +private: + void initialize(); + + friend class lifetime_calendar_cycle_t; +}; + +/* +Class to encapsulate multiple lifetime models, and linearly combined the associated degradation and handle replacements +*/ + +class lifetime_calendar_cycle_t : public lifetime_t { +public: + /// Cycle with Calendar table + lifetime_calendar_cycle_t(const util::matrix_t &batt_lifetime_matrix, + double dt_hour, const util::matrix_t& calendar_matrix); + + /// Cycle with Calendar model + lifetime_calendar_cycle_t(const util::matrix_t &batt_lifetime_matrix, + double dt_hour, double q0, double a, double b, double c); + + /// Cycle with no Calendar + lifetime_calendar_cycle_t(const util::matrix_t &batt_lifetime_matrix, double dt_hour); + + lifetime_calendar_cycle_t(std::shared_ptr params_ptr); + + lifetime_calendar_cycle_t(const lifetime_calendar_cycle_t& rhs); + + lifetime_calendar_cycle_t &operator=(const lifetime_calendar_cycle_t& rhs); + + lifetime_calendar_cycle_t *clone() override; + + ~lifetime_calendar_cycle_t() override = default; + + /// Execute the lifetime models given the current lifetime run index, capacity model, and temperature + void runLifetimeModels(size_t lifetimeIndex, bool charge_changed, double prev_DOD, double DOD, double T_battery) override; + + double estimateCycleDamage() override; + + void replaceBattery(double percent_to_replace) override; + + /// Return the relative capacity percentage of nominal caused by cycle damage (%) + double capacity_percent_cycle(); + + /// Return the relative capacity percentage of nominal caused by calendar fade (%) + double capacity_percent_calendar(); + +protected: + + std::unique_ptr calendar_model; + std::unique_ptr cycle_model; + +private: + void initialize(); + + friend class battery_t; +}; + + +#endif //SAM_SIMULATION_CORE_LIB_BATTERY_LIFETIME_CALENDAR_CYCLE_H diff --git a/shared/lib_battery_lifetime_nmc.cpp b/shared/lib_battery_lifetime_nmc.cpp new file mode 100644 index 00000000000..2fd15875b83 --- /dev/null +++ b/shared/lib_battery_lifetime_nmc.cpp @@ -0,0 +1,187 @@ +#include "lib_battery_lifetime_calendar_cycle.h" +#include "lib_battery_lifetime_nmc.h" +#include "lib_battery_lifetime.h" +#include + +void lifetime_nmc_t::initialize() { + + // cycle model for counting cycles only, no cycle-only degradation + cycle_model = std::unique_ptr(new lifetime_cycle_t(params, state)); + // do any state initialization here + state->nmc_state->q_relative_li = 100; + state->nmc_state->q_relative_neg = 100; + state->nmc_state->dq_relative_li_old = 0; + state->nmc_state->dq_relative_neg_old = 0; + state->nmc_state->day_age_of_battery_float = 0; + state->nmc_state->DOD_max = 50; + state->nmc_state->n_cycles_prev_day = 0; + state->nmc_state->b1_dt.clear(); + state->nmc_state->b2_dt.clear(); + state->nmc_state->b3_dt.clear(); + state->nmc_state->c2_dt.clear(); +} + +lifetime_nmc_t::lifetime_nmc_t(double dt_hr) { + params = std::make_shared(); + params->model_choice = lifetime_params::NMCNREL; + params->dt_hr = dt_hr; + state = std::make_shared(); + initialize(); +} + +lifetime_nmc_t::lifetime_nmc_t(std::shared_ptr params_pt) { + params = std::move(params_pt); + initialize(); +} + +lifetime_nmc_t::lifetime_nmc_t(const lifetime_nmc_t &rhs) : + lifetime_t(rhs){ + operator=(rhs); +} + +lifetime_nmc_t& lifetime_nmc_t::operator=(const lifetime_nmc_t& rhs) { + if (this != &rhs) { + *params = *rhs.params; + *state = *rhs.state; + } + return *this; +} + +lifetime_t * lifetime_nmc_t::clone() { + return new lifetime_nmc_t(*this); +} + +// Rohit - Define negative electrode voltage function +double lifetime_nmc_t::Uneg_computation(double SOC) { + double Uneg = 0.1; + if (SOC <= 0.1) + Uneg = ((0.2420 - 1.2868) / 0.1) * SOC + 1.2868; + else + Uneg = ((0.0859 - 0.2420) / 0.9) * (SOC - 0.1) + 0.2420; + return Uneg; +} + +// Rohit - Define open circuit voltage function +double lifetime_nmc_t::Voc_computation(double SOC) { + double Voc = 0.1; + if (SOC <= 0.1) + Voc = ((0.4679) / 0.1) * SOC + 3; + else if (SOC <= 0.6) + Voc = ((3.747 - 3.4679) / 0.5) * (SOC - 0.1) + 3.4679; + else + Voc = ((4.1934 - 3.7469) / 0.4) * (SOC - 0.6) + 3.7469; + return Voc; +} + +double lifetime_nmc_t::runLifetimeNMC_Qli() { + double dt_day = 1; + int dn_cycles = state->n_cycles - state->nmc_state->n_cycles_prev_day; + double k_cal = 0; + double b1 = std::accumulate(state->nmc_state->b1_dt.begin(), state->nmc_state->b1_dt.end(), 0); + double b2 = std::accumulate(state->nmc_state->b2_dt.begin(), state->nmc_state->b1_dt.end(), 0); + double b3 = std::accumulate(state->nmc_state->b3_dt.begin(), state->nmc_state->b1_dt.end(), 0); + + if (state->day_age_of_battery > 0) + k_cal = (0.5 * b1) / (sqrt(state->day_age_of_battery)) + (b3 / tau_b3) * exp(-(state->day_age_of_battery / tau_b3)); + else + k_cal = 0; + + double dq_new; + if (state->nmc_state->dq_relative_li_old == 0) + dq_new = k_cal * dt_day + b2 * dn_cycles; + else + dq_new = k_cal * dt_day + b2 * dn_cycles + state->nmc_state->dq_relative_li_old; + state->nmc_state->dq_relative_li_old = dq_new; + state->nmc_state->q_relative_li = (1 - (dq_new)) * 100; + return state->nmc_state->q_relative_li; +} + +double lifetime_nmc_t::runLifetimeNMC_Qneg(double T_battery, double SOC) { + double DOD = 1 - SOC; + int dn_cycles = state->n_cycles - state->nmc_state->n_cycles_prev_day; + + double c2 = std::accumulate(state->nmc_state->c2_dt.begin(), state->nmc_state->c2_dt.end(), 0);; + + double dq_new; + if (state->nmc_state->dq_relative_neg_old == 0) + dq_new = 1 - sqrt(1 - 2 * (c2 / c0_ref) * dn_cycles); + else + dq_new = 1 - sqrt(1 - 2 * (c2 / c0_ref) * dn_cycles) + state->nmc_state->dq_relative_neg_old; + + state->nmc_state->dq_relative_neg_old = dq_new; + + state->nmc_state->q_relative_neg = (1 - (dq_new)) * 100; + return state->nmc_state->q_relative_neg; +} + +void lifetime_nmc_t::runLifetimeModels(size_t lifetimeIndex, bool charge_changed, double prev_DOD, double DOD, + double T_battery) { + double q_last = state->q_relative; + // update day age of battery + int day_age_of_battery_old = (int)(state->nmc_state->day_age_of_battery_float); + state->nmc_state->day_age_of_battery_float = state->nmc_state->day_age_of_battery_float + + float(util::hours_per_day / params->dt_hr); + state->day_age_of_battery = (int)(state->nmc_state->day_age_of_battery_float); + + // convert battery temperature to Kelvin + T_battery += 273; + if (charge_changed) + cycle_model->rainflow(prev_DOD); + + // update DOD_max if DOD > old DOD_max + if (DOD > state->nmc_state->DOD_max) + state->nmc_state->DOD_max = DOD; + + //compute open circuit and negative electrode voltage as function of SOC + double SOC = 0.01 * (100 - DOD); + double U_neg = Uneg_computation(SOC); + double V_oc = Voc_computation(SOC); + + // compute lifetime degradation coefficients for current time step, + //multiply by timestep in days and populate corresponding vectors + double dt_day = (1 / 24) * params->dt_hr; + double b1_dt_el = b1_ref * exp(-(Ea_b_1 / Rug) * (1. / T_battery - 1. / T_ref)) + * exp((alpha_a_b1 * F / Rug) * (U_neg / T_battery - U_ref / T_ref)) + * exp(gamma * pow(state->nmc_state->DOD_max, beta_b1)) * dt_day; + double b2_dt_el = b2_ref * exp(-(Ea_b_2 / Rug) * (1. / T_battery - 1. / T_ref)) * dt_day; + double b3_dt_el = b3_ref * exp(-(Ea_b_3 / Rug) * (1. / T_battery - 1. / T_ref)) + * exp((alpha_a_b3 * F / Rug) * (V_oc / T_battery - V_ref / T_ref)) + * (1 + theta * state->nmc_state->DOD_max); + state->nmc_state->b1_dt.push_back(b1_dt_el); + state->nmc_state->b2_dt.push_back(b2_dt_el); + state->nmc_state->b3_dt.push_back(b3_dt_el); + + //computations for q_neg + double c2_dt_el = c2_ref * exp(-(Ea_c_2 / Rug) * (1. / T_battery - 1. / T_ref)) + * pow(DOD, beta_c2); + state->nmc_state->c2_dt.push_back(c2_dt_el); + + //Run capacity degradation model after every 24 hours + if (state->day_age_of_battery - day_age_of_battery_old == 1) { + state->nmc_state->q_relative_li = runLifetimeNMC_Qli(); + state->nmc_state->q_relative_neg = runLifetimeNMC_Qneg(T_battery, SOC); + state->q_relative = fmin(state->nmc_state->q_relative_li, state->nmc_state->q_relative_neg); + state->nmc_state->b1_dt.clear(); + state->nmc_state->b2_dt.clear(); + state->nmc_state->b3_dt.clear(); + state->nmc_state->n_cycles_prev_day = state->n_cycles; + } + + state->q_relative = fmin(state->q_relative, q_last); +} + +double lifetime_nmc_t::estimateCycleDamage() { + return 0; +} + +void lifetime_nmc_t::replaceBattery(double percent_to_replace) { + state->day_age_of_battery = 0; + state->nmc_state->day_age_of_battery_float = 0; + state->nmc_state->dq_relative_li_old = 0; + state->nmc_state->dq_relative_neg_old = 0; + state->nmc_state->q_relative_li += percent_to_replace; + state->nmc_state->q_relative_neg += percent_to_replace; + state->nmc_state->q_relative_li = fmin(100, state->nmc_state->q_relative_li); + state->nmc_state->q_relative_neg = fmin(100, state->nmc_state->q_relative_neg); + state->q_relative = fmin(state->nmc_state->q_relative_li, state->nmc_state->q_relative_neg); +} diff --git a/shared/lib_battery_lifetime_nmc.h b/shared/lib_battery_lifetime_nmc.h new file mode 100644 index 00000000000..47ada6ebb03 --- /dev/null +++ b/shared/lib_battery_lifetime_nmc.h @@ -0,0 +1,97 @@ +#ifndef SAM_SIMULATION_CORE_LIB_BATTERY_LIFETIME_NMC_H +#define SAM_SIMULATION_CORE_LIB_BATTERY_LIFETIME_NMC_H + +#include + +#include "lib_util.h" +#include "lib_battery_lifetime_calendar_cycle.h" + +// Rohit - add struct for lithiumIonnmc states, SEI degradation (q_relative_li) and cycle degradation (q_relative_neg) + +struct lifetime_nmc_state { + double q_relative_li; // % + double q_relative_neg; + double dq_relative_li_old; + double dq_relative_neg_old; + double DOD_max; + int n_cycles_prev_day; + + float day_age_of_battery_float; // keep track of age of battery with changing timestep + + // for complex cycling of battery, b1 = summagion of b1_dt * dt_day over a day + // lifetime capacity updated after 24 hours elapse. + + std::vector b1_dt; + std::vector b2_dt; + std::vector b3_dt; + std::vector c2_dt; + + friend std::ostream& operator<<(std::ostream& os, const lifetime_nmc_state& p); +}; + +class lifetime_nmc_t : public lifetime_t { +public: + lifetime_nmc_t(double dt_hr); + + lifetime_nmc_t(std::shared_ptr params_pt); + + lifetime_nmc_t(const lifetime_nmc_t& rhs); + + lifetime_nmc_t &operator=(const lifetime_nmc_t& rhs); + + lifetime_t *clone() override; + + /// Execute the lifetime models given the current lifetime run index, capacity model, and temperature + void runLifetimeModels(size_t lifetimeIndex, bool charge_changed, double prev_DOD, double DOD, double T_battery) override; + + double estimateCycleDamage() override; + + void replaceBattery(double percent_to_replace) override; + + /// Calculate negative electrode voltage from SOC + double Uneg_computation(double SOC); + + /// Calculate open circuit voltage from SOC + double Voc_computation(double SOC); + + // Capacity degradation due to SEI + double runLifetimeNMC_Qli(); + + // Capacity degradation due to cycles + double runLifetimeNMC_Qneg(double T_battery, double SOC); + +protected: + std::unique_ptr cycle_model; + + void initialize(); + + /// Rohit - Add Li-ion NMC Kandler Smith parameters + double Ea_d0_1 = 4126.0; + double b1_ref = 0.003503; + double Ea_b_1 = 35392.; + double Rug = 8.314; + double T_ref = 298.15; + double alpha_a_b1 = -1; + double F = 96485; + double U_ref = 0.08; + double gamma = 2.472; + double beta_b1 = 2.157; + + double b2_ref = 0.00001541; + double Ea_b_2 = -42800.; + + double b3_ref = 0.003503; + double Ea_b_3 = 42800.; + double alpha_a_b3 = 0.0066; + double V_ref = 3.7; + double theta = 0.135; + double tau_b3 = 5; + + double c0_ref = 75.1; + double c2_ref = 0.0039193; + double Ea_c_2 = -48260; + double beta_c2 = 4.54; +}; + + +#endif //SAM_SIMULATION_CORE_LIB_BATTERY_LIFETIME_NMC_H diff --git a/shared/logger.cpp b/shared/logger.cpp index 07f3079b1d6..e0c6df24c35 100644 --- a/shared/logger.cpp +++ b/shared/logger.cpp @@ -3,7 +3,7 @@ #include "lib_util.h" #include "lib_battery_capacity.h" #include "lib_battery_voltage.h" -#include "lib_battery_lifetime.h" +#include "lib_battery_lifetime_calendar_cycle.h" #include "lib_battery.h" /** @@ -88,9 +88,9 @@ std::ostream &operator<<(std::ostream &os, const capacity_params &p) { std::ostream &operator<<(std::ostream &os, const cycle_state &p) { char buf[1024]; - sprintf(buf, "\"cycle_state\": { \"q_relative_cycle\": %.3f, \"n_cycles\": %d, \"range\": %.3f, \"average_range\": %.3f, " + sprintf(buf, "\"cycle_state\": { \"q_relative_cycle\": %.3f, " "\"rainflow_Xlt\": %.3f, \"rainflow_Ylt\": %.3f, \"rainflow_jlt\": %d, \"rainflow_peaks\": ", - p.q_relative_cycle, p.n_cycles, p.range, p.average_range, + p.q_relative_cycle, p.rainflow_Xlt, p.rainflow_Ylt, p.rainflow_jlt); os << buf << p.rainflow_peaks << " }"; return os; @@ -98,32 +98,53 @@ std::ostream &operator<<(std::ostream &os, const cycle_state &p) { std::ostream &operator<<(std::ostream &os, const calendar_state &p) { char buf[1024]; - sprintf(buf, "\"calendar_state\": { \"q_relative_calendar\": %.3f, \"day_age_of_battery\": %d, " + sprintf(buf, "\"calendar_state\": { \"q_relative_calendar\": %.3f, " "\"dq_relative_calendar_old\": %.3f }", - p.q_relative_calendar, p.day_age_of_battery, p.dq_relative_calendar_old); + p.q_relative_calendar, p.dq_relative_calendar_old); os << buf; return os; } +//Rohit +std::ostream& operator<<(std::ostream& os, const lifetime_nmc_state& p) { + char buf[1024]; + sprintf(buf, "\"lifetime_nmc_state\": { \"q_relative_li\": %.3f, " + "\"q_relative_neg\": %.3f } ", + p.q_relative_li, p.q_relative_neg); + os << buf ; + return os; +} + std::ostream &operator<<(std::ostream &os, const lifetime_state &p) { os.precision(3); - os << R"("lifetime_state" : { "q_relative": )" << p.q_relative << ", " << *p.cycle << ", " << *p.calendar << " }"; + char buf[1024]; + sprintf(buf, R"("lifetime_state": { "q_relative": %f, "n_cycles": %d, "range": %.3f, "average_range": %.3f, )", + p.q_relative, p.n_cycles, p.range, p.average_range); + os << buf << *p.cycle << ", " << *p.calendar << " }"; return os; } -std::ostream &operator<<(std::ostream &os, const lifetime_params &p) { - os << R"("lifetime_params": { "cycling_matrix": )" << p.cycling_matrix; +std::ostream &operator<<(std::ostream &os, const calendar_cycle_params &p) { + os << R"("calendar_cycle_params": { "cycling_matrix": )" << p.cycling_matrix; char buf[1024]; - sprintf(buf, ", \"calendar_choice\": %d, \"dt_hour\": %.3f, \"calendar_q0\": %.3f, " + sprintf(buf, ", \"calendar_choice\": %d, \"calendar_q0\": %.3f, " "\"calendar_a\": %.3f, \"calendar_b\": %.3f, " - "\"calendar_c\": %.3f, ", p.calendar_choice, p.dt_hour, p.calendar_q0, + "\"calendar_c\": %.3f, ", p.calendar_choice, p.calendar_q0, p.calendar_a, p.calendar_b, p.calendar_c); os << buf; os << R"("calendar_matrix": )" << p.calendar_matrix << " }"; return os; } +std::ostream &operator<<(std::ostream &os, const lifetime_params &p) { + os.precision(3); + char buf[1024]; + sprintf(buf, R"("lifetime_params": { "dt_hr": %.3f, "model_choice": %d, )", p.dt_hr, p.model_choice); + os << *p.cal_cyc << " }"; + return os; +} + std::ostream &operator<<(std::ostream &os, const replacement_state &p) { char buf[256]; sprintf(buf, R"("replacement_state": { "n_replacements": %d, "indices_replaced": )", p.n_replacements); @@ -150,10 +171,10 @@ std::ostream &operator<<(std::ostream &os, const thermal_state &p) { std::ostream &operator<<(std::ostream &os, const thermal_params &p) { char buf[1024]; - sprintf(buf, "\"thermal_params\": { \"dt_hour\": %.3f, \"mass\": %.3f, \"surface_area\": %.3f, " + sprintf(buf, "\"thermal_params\": { \"dt_hr\": %.3f, \"mass\": %.3f, \"surface_area\": %.3f, " "\"Cp\": %.3f, \"h\": %.3f, \"resistance\": %.3e, \"cap_vs_temp\": ", - p.dt_hour, p.mass, p.surface_area, - p.Cp, p.h, p.resistance); + p.dt_hr, p.mass, p.surface_area, + p.Cp, p.h, p.resistance); os << buf << p.cap_vs_temp; os.precision(3); os << R"(, "option": )" << p.option; @@ -198,8 +219,8 @@ std::ostream &operator<<(std::ostream &os, const battery_state &p) { std::ostream &operator<<(std::ostream &os, const battery_params &p) { char buf[1024]; - sprintf(buf, R"("battery_params": { "chem": %u, "dt_hour": %.3f, "nominal_voltage": %.3f, "nominal_energy": %.3f)", - p.chem, p.dt_hour, p.nominal_voltage, p.nominal_energy); + sprintf(buf, R"("battery_params": { "chem": %u, "dt_hr": %.3f, "nominal_voltage": %.3f, "nominal_energy": %.3f)", + p.chem, p.dt_hr, p.nominal_voltage, p.nominal_energy); os << buf << ", "; os << *p.capacity << ", "; os << *p.voltage << ", "; diff --git a/ssc/cmod_battery.cpp b/ssc/cmod_battery.cpp index 1cba9571906..2e29bdf6466 100644 --- a/ssc/cmod_battery.cpp +++ b/ssc/cmod_battery.cpp @@ -111,14 +111,14 @@ var_info vtab_battery_inputs[] = { { SSC_INPUT, SSC_NUMBER, "batt_minimum_modetime", "Minimum time at charge state", "min", "", "BatteryCell", "", "", "" }, // lifetime inputs - //TODO: Rohit- Add batt_calendar_choice corresponding to lithium_ion_nmc - { SSC_INPUT, SSC_MATRIX, "batt_lifetime_matrix", "Cycles vs capacity at different depths-of-discharge", "", "", "BatteryCell", "", "", "" }, - { SSC_INPUT, SSC_NUMBER, "batt_calendar_choice", "Calendar life degradation input option", "0/1/2/3", "0=NoCalendarDegradation,1=LithiomIonModel,2=InputLossTable,3=LithiumIonNMCModel", "BatteryCell", "", "", "" }, - { SSC_INPUT, SSC_MATRIX, "batt_calendar_lifetime_matrix", "Days vs capacity", "", "", "BatteryCell", "", "", "" }, - { SSC_INPUT, SSC_NUMBER, "batt_calendar_q0", "Calendar life model initial capacity cofficient", "", "", "BatteryCell", "", "", "" }, - { SSC_INPUT, SSC_NUMBER, "batt_calendar_a", "Calendar life model coefficient", "1/sqrt(day)","", "BatteryCell", "", "", "" }, - { SSC_INPUT, SSC_NUMBER, "batt_calendar_b", "Calendar life model coefficient", "K", "", "BatteryCell", "", "", "" }, - { SSC_INPUT, SSC_NUMBER, "batt_calendar_c", "Calendar life model coefficient", "K", "", "BatteryCell", "", "", "" }, + { SSC_INPUT, SSC_NUMBER, "batt_life_model", "Battery life model specifier", "0/1", "0=calendar/cycle,1=NMC", "BatteryCell", "en_batt=1", "", "" }, + { SSC_INPUT, SSC_MATRIX, "batt_lifetime_matrix", "Cycles vs capacity at different depths-of-discharge", "", "", "BatteryCell", "batt_life_model=0", "", "" }, + { SSC_INPUT, SSC_NUMBER, "batt_calendar_choice", "Calendar life degradation input option", "0/1/2", "0=NoCalendarDegradation,1=LithiomIonModel,2=InputLossTable", "BatteryCell", "batt_life_model=0", "", "" }, + { SSC_INPUT, SSC_MATRIX, "batt_calendar_lifetime_matrix", "Days vs capacity", "", "", "BatteryCell", "batt_life_model=0&batt_calendar_choice=2", "", "" }, + { SSC_INPUT, SSC_NUMBER, "batt_calendar_q0", "Calendar life model initial capacity cofficient", "", "", "BatteryCell", "batt_life_model=0&batt_calendar_choice=1", "", "" }, + { SSC_INPUT, SSC_NUMBER, "batt_calendar_a", "Calendar life model coefficient", "1/sqrt(day)","", "BatteryCell", "batt_life_model=0&batt_calendar_choice=1", "", "" }, + { SSC_INPUT, SSC_NUMBER, "batt_calendar_b", "Calendar life model coefficient", "K", "", "BatteryCell", "batt_life_model=0&batt_calendar_choice=1", "", "" }, + { SSC_INPUT, SSC_NUMBER, "batt_calendar_c", "Calendar life model coefficient", "K", "", "BatteryCell", "batt_life_model=0&batt_calendar_choice=1", "", "" }, // replacement inputs { SSC_INPUT, SSC_NUMBER, "batt_replacement_capacity", "Capacity degradation at which to replace battery", "%", "", "BatterySystem", "", "", "" }, @@ -391,7 +391,7 @@ battstor::battstor(var_table& vt, bool setup_model, size_t nrec, double dt_hr, c } batt_vars->batt_cycle_cost = cycle_cost; - + // Battery bank replacement if (vt.is_assigned("om_replacement_cost1")) { @@ -468,7 +468,7 @@ battstor::battstor(var_table& vt, bool setup_model, size_t nrec, double dt_hr, c if (vt.is_assigned("ur_ec_tou_mat")) { // Some tests don't have this assigned, ensure it is before setting up forecast rate batt_vars->ec_rate_defined = true; } - + if (batt_vars->batt_dispatch == dispatch_t::MAINTAIN_TARGET) { @@ -553,14 +553,17 @@ battstor::battstor(var_table& vt, bool setup_model, size_t nrec, double dt_hr, c } // Battery lifetime - batt_vars->batt_calendar_choice = vt.as_integer("batt_calendar_choice"); - batt_vars->batt_lifetime_matrix = vt.as_matrix("batt_lifetime_matrix"); - batt_vars->batt_calendar_lifetime_matrix = vt.as_matrix("batt_calendar_lifetime_matrix"); - batt_vars->batt_voltage_matrix = vt.as_matrix("batt_voltage_matrix"); - batt_vars->batt_calendar_q0 = vt.as_double("batt_calendar_q0"); - batt_vars->batt_calendar_a = vt.as_double("batt_calendar_a"); - batt_vars->batt_calendar_b = vt.as_double("batt_calendar_b"); - batt_vars->batt_calendar_c = vt.as_double("batt_calendar_c"); + batt_vars->batt_life_model = vt.as_integer("batt_life_model"); + if (batt_vars->batt_life_model == 0) { + batt_vars->batt_calendar_choice = vt.as_integer("batt_calendar_choice"); + batt_vars->batt_lifetime_matrix = vt.as_matrix("batt_lifetime_matrix"); + batt_vars->batt_calendar_lifetime_matrix = vt.as_matrix("batt_calendar_lifetime_matrix"); + batt_vars->batt_voltage_matrix = vt.as_matrix("batt_voltage_matrix"); + batt_vars->batt_calendar_q0 = vt.as_double("batt_calendar_q0"); + batt_vars->batt_calendar_a = vt.as_double("batt_calendar_a"); + batt_vars->batt_calendar_b = vt.as_double("batt_calendar_b"); + batt_vars->batt_calendar_c = vt.as_double("batt_calendar_c"); + } // Thermal behavior batt_vars->batt_surface_area = vt.as_double("batt_surface_area"); @@ -804,27 +807,43 @@ battstor::battstor(var_table& vt, bool setup_model, size_t nrec, double dt_hr, c batt_vars->batt_voltage_matrix, batt_vars->batt_resistance, dt_hr); - //Rohit- add option of lifetime_t constructor corresponding lithium_ion_nmc - - if (batt_vars->batt_calendar_choice == lifetime_params::CALENDAR_CHOICE::MODEL) { - lifetime_model = new lifetime_t(batt_vars->batt_lifetime_matrix, dt_hr, - batt_vars->batt_calendar_q0, batt_vars->batt_calendar_a, batt_vars->batt_calendar_b, batt_vars->batt_calendar_c); - } - else if (batt_vars->batt_calendar_choice == lifetime_params::CALENDAR_CHOICE::TABLE) { - lifetime_model = new lifetime_t(batt_vars->batt_lifetime_matrix, dt_hr, batt_vars->batt_calendar_lifetime_matrix); + if (batt_vars->batt_life_model == 0) { + if (batt_vars->batt_calendar_choice == calendar_cycle_params::CALENDAR_CHOICE::MODEL) { + lifetime_model = new lifetime_calendar_cycle_t(batt_vars->batt_lifetime_matrix, dt_hr, + batt_vars->batt_calendar_q0, batt_vars->batt_calendar_a, batt_vars->batt_calendar_b, batt_vars->batt_calendar_c); + } + else if (batt_vars->batt_calendar_choice == calendar_cycle_params::CALENDAR_CHOICE::TABLE) { + lifetime_model = new lifetime_calendar_cycle_t(batt_vars->batt_lifetime_matrix, dt_hr, batt_vars->batt_calendar_lifetime_matrix); + } + else { + lifetime_model = new lifetime_calendar_cycle_t(batt_vars->batt_lifetime_matrix, dt_hr); + } } - else if (batt_vars->batt_calendar_choice == lifetime_params::CALENDAR_CHOICE::NMC_MODEL) { - lifetime_model = new lifetime_t(dt_hr); + else if (batt_vars->batt_life_model == 1) { + lifetime_model = new lifetime_nmc_t(dt_hr); } else { - lifetime_model = new lifetime_t(batt_vars->batt_lifetime_matrix, dt_hr); + throw exec_error("battery", "Unrecognized `batt_life_model` option. Valid options are 0 for separate calendar & cycle models; " + "1 for NREL NMC life model."); } if (batt_vars->T_room.size() != nrec) { throw exec_error("battery", "Environment temperature input length must equal number of weather file records"); } - thermal_model = new thermal_t( + if (batt_vars->batt_life_model == 1) { + thermal_model = new thermal_t( + dt_hr, + batt_vars->batt_mass, // [kg] + batt_vars->batt_surface_area, // [m] + batt_vars->batt_resistance, // [J/kgK] + batt_vars->batt_Cp, + batt_vars->batt_h_to_ambient, + batt_vars->T_room + ); + } + else { + thermal_model = new thermal_t( dt_hr, batt_vars->batt_mass, // [kg] batt_vars->batt_surface_area, // [m] @@ -833,7 +852,9 @@ battstor::battstor(var_table& vt, bool setup_model, size_t nrec, double dt_hr, c batt_vars->batt_h_to_ambient, batt_vars->cap_vs_temp, batt_vars->T_room - ); + ); + } + if (chem == battery_params::LEAD_ACID) { @@ -1397,10 +1418,10 @@ void battstor::outputs_fixed() outCurrent[index] = (ssc_number_t)(state.capacity->cell_current); outBatteryVoltage[index] = (ssc_number_t)(battery_model->V()); - outCycles[index] = (ssc_number_t)(state.lifetime->cycle->n_cycles); + outCycles[index] = (ssc_number_t)(state.lifetime->n_cycles); outSOC[index] = (ssc_number_t)(state.capacity->SOC); - outDOD[index] = (ssc_number_t)(state.lifetime->cycle->range); - outDODCycleAverage[index] = (ssc_number_t)(state.lifetime->cycle->average_range); + outDOD[index] = (ssc_number_t)(state.lifetime->range); + outDODCycleAverage[index] = (ssc_number_t)(state.lifetime->average_range); outCapacityPercent[index] = (ssc_number_t)(state.lifetime->q_relative); outCapacityPercentCycle[index] = (ssc_number_t)(state.lifetime->cycle->q_relative_cycle); outCapacityPercentCalendar[index] = (ssc_number_t)(state.lifetime->calendar->q_relative_calendar); diff --git a/ssc/cmod_battery.h b/ssc/cmod_battery.h index 0c64897e5be..2da30b9586d 100644 --- a/ssc/cmod_battery.h +++ b/ssc/cmod_battery.h @@ -53,6 +53,7 @@ struct batt_variables int batt_meter_position; int batt_target_choice; int batt_loss_choice; + int batt_life_model; int batt_calendar_choice; ssc_number_t *pcharge = 0; diff --git a/ssc/cmod_battery_stateful.cpp b/ssc/cmod_battery_stateful.cpp index 8a7a1f18777..6725ba6cb7d 100644 --- a/ssc/cmod_battery_stateful.cpp +++ b/ssc/cmod_battery_stateful.cpp @@ -69,13 +69,14 @@ var_info vtab_battery_stateful_inputs[] = { { SSC_INPUT, SSC_MATRIX, "cap_vs_temp", "Table with Temperature and Capacity % as columns", "[[C,%]]", "", "ParamsPack", "*", "", "" }, // lifetime inputs - { SSC_INPUT, SSC_MATRIX, "cycling_matrix", "Table with DOD %, Cycle #, and Capacity % columns", "[[%, #, %]]","", "ParamsCell", "*", "", "" }, - { SSC_INPUT, SSC_NUMBER, "calendar_choice", "Calendar life degradation input option", "0/1/2", "0=None,1=LithiomIonModel,2=InputLossTable", "ParamsCell", "*", "", "" }, - { SSC_INPUT, SSC_MATRIX, "calendar_matrix", "Table with Day # and Capacity % columns", "[[#, %]]", "", "ParamsCell", "calendar_choice=2", "", "" }, - { SSC_INPUT, SSC_NUMBER, "calendar_q0", "Calendar life model initial capacity cofficient", "", "", "ParamsCell", "calendar_choice=1", "", "" }, - { SSC_INPUT, SSC_NUMBER, "calendar_a", "Calendar life model coefficient", "1/sqrt(day)","", "ParamsCell", "calendar_choice=1", "", "" }, - { SSC_INPUT, SSC_NUMBER, "calendar_b", "Calendar life model coefficient", "K", "", "ParamsCell", "calendar_choice=1", "", "" }, - { SSC_INPUT, SSC_NUMBER, "calendar_c", "Calendar life model coefficient", "K", "", "ParamsCell", "calendar_choice=1", "", "" }, + { SSC_INPUT, SSC_NUMBER, "life_model", "Battery life model specifier", "0/1", "0=calendar/cycle,1=NMC", "ParamsCell", "*", "", "" }, + { SSC_INPUT, SSC_MATRIX, "cycling_matrix", "Table with DOD %, Cycle #, and Capacity % columns", "[[%, #, %]]","", "ParamsCell", "life_model=0", "", "" }, + { SSC_INPUT, SSC_NUMBER, "calendar_choice", "Calendar life degradation input option", "0/1/2", "0=None,1=LithiomIonModel,2=InputLossTable", "ParamsCell", "life_model=0", "", "" }, + { SSC_INPUT, SSC_MATRIX, "calendar_matrix", "Table with Day # and Capacity % columns", "[[#, %]]", "", "ParamsCell", "life_model=0&calendar_choice=2", "", "" }, + { SSC_INPUT, SSC_NUMBER, "calendar_q0", "Calendar life model initial capacity cofficient", "", "", "ParamsCell", "life_model=0&calendar_choice=1", "", "" }, + { SSC_INPUT, SSC_NUMBER, "calendar_a", "Calendar life model coefficient", "1/sqrt(day)","", "ParamsCell", "life_model=0&calendar_choice=1", "", "" }, + { SSC_INPUT, SSC_NUMBER, "calendar_b", "Calendar life model coefficient", "K", "", "ParamsCell", "life_model=0&calendar_choice=1", "", "" }, + { SSC_INPUT, SSC_NUMBER, "calendar_c", "Calendar life model coefficient", "K", "", "ParamsCell", "life_model=0&calendar_choice=1", "", "" }, // losses { SSC_INPUT, SSC_NUMBER, "loss_choice", "Loss power input option", "0/1", "0=Monthly,1=TimeSeries", "ParamsPack", "?=0", "", "" }, @@ -176,10 +177,15 @@ void write_battery_state(const battery_state& state, var_table* vt) { vt->assign_match_case("charge_mode", cap->charge_mode); vt->assign_match_case("prev_charge", cap->prev_charge); vt->assign_match_case("chargeChange", cap->chargeChange); - vt->assign_match_case("q1_0", cap->leadacid.q1_0); - vt->assign_match_case("q2_0", cap->leadacid.q2_0); - vt->assign_match_case("qn", cap->leadacid.q1); - vt->assign_match_case("q2", cap->leadacid.q2); + + int choice; + vt_get_int(vt, "chem", &choice); + if (choice == battery_params::CHEM::LEAD_ACID) { + vt->assign_match_case("q1_0", cap->leadacid.q1_0); + vt->assign_match_case("q2_0", cap->leadacid.q2_0); + vt->assign_match_case("qn", cap->leadacid.q1); + vt->assign_match_case("q2", cap->leadacid.q2); + } vt->assign_match_case("cell_voltage", state.voltage->cell_voltage); @@ -192,19 +198,26 @@ void write_battery_state(const battery_state& state, var_table* vt) { auto lifetime = state.lifetime; vt->assign_match_case("q_relative", lifetime->q_relative); - vt->assign_match_case("q_relative_cycle", lifetime->cycle->q_relative_cycle); - vt->assign_match_case("n_cycles", lifetime->cycle->n_cycles); - vt->assign_match_case("range", lifetime->cycle->range); - vt->assign_match_case("average_range", lifetime->cycle->average_range); - vt->assign_match_case("rainflow_Xlt", lifetime->cycle->rainflow_Xlt); - vt->assign_match_case("rainflow_Ylt", lifetime->cycle->rainflow_Ylt); - vt->assign_match_case("rainflow_jlt", lifetime->cycle->rainflow_jlt); - if (!lifetime->cycle->rainflow_peaks.empty()) { - vt->assign_match_case("rainflow_peaks", lifetime->cycle->rainflow_peaks); + vt->assign_match_case("n_cycles", lifetime->n_cycles); + vt->assign_match_case("range", lifetime->range); + vt->assign_match_case("average_range", lifetime->average_range); + vt->assign_match_case("day_age_of_battery", lifetime->day_age_of_battery); + + vt_get_int(vt, "life_model", &choice); + if (choice == lifetime_params::CALCYC) { + vt->assign_match_case("q_relative_cycle", lifetime->cycle->q_relative_cycle); + vt->assign_match_case("rainflow_Xlt", lifetime->cycle->rainflow_Xlt); + vt->assign_match_case("rainflow_Ylt", lifetime->cycle->rainflow_Ylt); + vt->assign_match_case("rainflow_jlt", lifetime->cycle->rainflow_jlt); + if (!lifetime->cycle->rainflow_peaks.empty()) { + vt->assign_match_case("rainflow_peaks", lifetime->cycle->rainflow_peaks); + } + vt->assign_match_case("q_relative_calendar", lifetime->calendar->q_relative_calendar); + vt->assign_match_case("dq_relative_calendar_old", lifetime->calendar->dq_relative_calendar_old); + } + else { + } - vt->assign_match_case("q_relative_calendar", lifetime->calendar->q_relative_calendar); - vt->assign_match_case("day_age_of_battery", lifetime->calendar->day_age_of_battery); - vt->assign_match_case("dq_relative_calendar_old", lifetime->calendar->dq_relative_calendar_old); vt->assign_match_case("loss_kw", state.losses->loss_kw); @@ -235,10 +248,15 @@ void read_battery_state(battery_state& state, var_table* vt) { vt_get_int(vt, "charge_mode", &cap->charge_mode); vt_get_int(vt, "prev_charge", &cap->prev_charge); vt_get_bool(vt, "chargeChange", &cap->chargeChange); - vt_get_number(vt, "q1_0", &cap->leadacid.q1_0); - vt_get_number(vt, "q2_0", &cap->leadacid.q2_0); - vt_get_number(vt, "qn", &cap->leadacid.q1); - vt_get_number(vt, "q2", &cap->leadacid.q2); + + int choice; + vt_get_int(vt, "chem", &choice); + if (choice == battery_params::CHEM::LEAD_ACID) { + vt_get_number(vt, "q1_0", &cap->leadacid.q1_0); + vt_get_number(vt, "q2_0", &cap->leadacid.q2_0); + vt_get_number(vt, "qn", &cap->leadacid.q1); + vt_get_number(vt, "q2", &cap->leadacid.q2); + } vt_get_number(vt, "cell_voltage", &state.voltage->cell_voltage); @@ -252,20 +270,27 @@ void read_battery_state(battery_state& state, var_table* vt) { auto lifetime = state.lifetime; vt_get_number(vt, "q_relative", &lifetime->q_relative); vt_get_number(vt, "q_relative_cycle", &lifetime->cycle->q_relative_cycle); - vt_get_int(vt, "n_cycles", &lifetime->cycle->n_cycles); - vt_get_number(vt, "range", &lifetime->cycle->range); - vt_get_number(vt, "average_range", &lifetime->cycle->average_range); - vt_get_number(vt, "rainflow_Xlt", &lifetime->cycle->rainflow_Xlt); - vt_get_number(vt, "rainflow_Ylt", &lifetime->cycle->rainflow_Ylt); - vt_get_int(vt, "rainflow_jlt", &lifetime->cycle->rainflow_jlt); - if (vt->is_assigned("rainflow_peaks")) - { - vt_get_array_vec(vt, "rainflow_peaks", lifetime->cycle->rainflow_peaks); - // If not assigned, leave empty + vt_get_int(vt, "n_cycles", &lifetime->n_cycles); + vt_get_number(vt, "range", &lifetime->range); + vt_get_number(vt, "average_range", &lifetime->average_range); + vt_get_int(vt, "day_age_of_battery", &lifetime->day_age_of_battery); + + vt_get_int(vt, "life_model", &choice); + if (choice == lifetime_params::CALCYC) { + vt_get_number(vt, "rainflow_Xlt", &lifetime->cycle->rainflow_Xlt); + vt_get_number(vt, "rainflow_Ylt", &lifetime->cycle->rainflow_Ylt); + vt_get_int(vt, "rainflow_jlt", &lifetime->cycle->rainflow_jlt); + if (vt->is_assigned("rainflow_peaks")) + { + vt_get_array_vec(vt, "rainflow_peaks", lifetime->cycle->rainflow_peaks); + // If not assigned, leave empty + } + vt_get_number(vt, "q_relative_calendar", &lifetime->calendar->q_relative_calendar); + vt_get_number(vt, "dq_relative_calendar_old", &lifetime->calendar->dq_relative_calendar_old); + } + else { + } - vt_get_number(vt, "q_relative_calendar", &lifetime->calendar->q_relative_calendar); - vt_get_int(vt, "day_age_of_battery", &lifetime->calendar->day_age_of_battery); - vt_get_number(vt, "dq_relative_calendar_old", &lifetime->calendar->dq_relative_calendar_old); vt_get_number(vt, "loss_kw", &state.losses->loss_kw); @@ -278,6 +303,7 @@ std::shared_ptr create_battery_params(var_table *vt, double dt_h int chem; vt_get_int(vt, "chem", &chem); params->chem = static_cast(chem); + params->dt_hr = dt_hr; // voltage auto voltage = params->voltage; @@ -317,7 +343,7 @@ std::shared_ptr create_battery_params(var_table *vt, double dt_h vt_get_number(vt, "initial_SOC", &capacity->initial_SOC); vt_get_number(vt, "maximum_soc", &capacity->maximum_SOC); vt_get_number(vt, "minimum_soc", &capacity->minimum_SOC); - params->dt_hour = dt_hr; + capacity->dt_hr = dt_hr; if (params->chem == battery_params::LEAD_ACID) { vt_get_number(vt, "leadacid_tn", &capacity->leadacid.tn); vt_get_number(vt, "leadacid_qn", &capacity->leadacid.qn); @@ -335,23 +361,27 @@ std::shared_ptr create_battery_params(var_table *vt, double dt_h // lifetime auto lifetime = params->lifetime; - vt_get_int(vt, "calendar_choice", &choice); - lifetime->calendar_choice = static_cast(choice); - lifetime->dt_hour = dt_hr; - vt_get_matrix(vt, "cycling_matrix", lifetime->cycling_matrix); - if (lifetime->calendar_choice == lifetime_params::CALENDAR_CHOICE::MODEL) { - vt_get_number(vt, "calendar_q0", &lifetime->calendar_q0); - vt_get_number(vt, "calendar_a", &lifetime->calendar_a); - vt_get_number(vt, "calendar_b", &lifetime->calendar_b); - vt_get_number(vt, "calendar_c", &lifetime->calendar_c); - } - else if (lifetime->calendar_choice == lifetime_params::CALENDAR_CHOICE::TABLE) { - vt_get_matrix(vt, "calendar_matrix", lifetime->calendar_matrix); + vt_get_int(vt, "life_model", &choice); + lifetime->model_choice = static_cast(choice); + if (lifetime->model_choice == lifetime_params::CALCYC) { + vt_get_int(vt, "calendar_choice", &choice); + lifetime->cal_cyc->calendar_choice = static_cast(choice); + lifetime->dt_hr = dt_hr; + vt_get_matrix(vt, "cycling_matrix", lifetime->cal_cyc->cycling_matrix); + if (lifetime->cal_cyc->calendar_choice == calendar_cycle_params::CALENDAR_CHOICE::MODEL) { + vt_get_number(vt, "calendar_q0", &lifetime->cal_cyc->calendar_q0); + vt_get_number(vt, "calendar_a", &lifetime->cal_cyc->calendar_a); + vt_get_number(vt, "calendar_b", &lifetime->cal_cyc->calendar_b); + vt_get_number(vt, "calendar_c", &lifetime->cal_cyc->calendar_c); + } + else if (lifetime->cal_cyc->calendar_choice == calendar_cycle_params::CALENDAR_CHOICE::TABLE) { + vt_get_matrix(vt, "calendar_matrix", lifetime->cal_cyc->calendar_matrix); + } } // thermal auto thermal = params->thermal; - thermal->dt_hour = dt_hr; + thermal->dt_hr = dt_hr; thermal->option = thermal_params::VALUE; thermal->resistance = params->voltage->resistance; vt_get_number(vt, "mass", &thermal->mass); @@ -389,7 +419,7 @@ std::shared_ptr create_battery_params(var_table *vt, double dt_h } cm_battery_stateful::cm_battery_stateful(): - dt_hour(0), + dt_hr(0), control_mode(0){ add_var_info(vtab_battery_stateful_inputs); add_var_info(vtab_battery_state); @@ -401,9 +431,9 @@ cm_battery_stateful::cm_battery_stateful(var_table* vt) : try { if (!compute_module::verify("precheck input", SSC_INPUT)) throw exec_error("battery_stateful", log(0)->text); - dt_hour = as_number("dt_hr"); + dt_hr = as_number("dt_hr"); control_mode = as_integer("control_mode"); - params = create_battery_params(m_vartab, dt_hour); + params = create_battery_params(m_vartab, dt_hr); battery = std::unique_ptr(new battery_t(params)); write_battery_state(battery->get_state(), m_vartab); } @@ -416,6 +446,7 @@ void cm_battery_stateful::exec() { if (!battery) throw exec_error("battery_stateful", "Battery model must be initialized first."); + // Update state battery_state state; try { read_battery_state(state, m_vartab); @@ -427,6 +458,15 @@ void cm_battery_stateful::exec() { throw runtime_error(err); } + // Update controls + control_mode = static_cast(as_integer("control_mode")); + double control_dt_hr = as_float("dt_hr"); + if (fabs(control_dt_hr - dt_hr) > 1e-7) { + dt_hr = control_dt_hr; + battery->ChangeTimestep(dt_hr); + } + + // Simulate if (static_cast(as_integer("control_mode")) == MODE::CURRENT) { double I = as_number("input_current"); battery->runCurrent(I); @@ -435,6 +475,7 @@ void cm_battery_stateful::exec() { double P = as_number("input_power"); battery->runPower(P); } + write_battery_state(battery->get_state(), m_vartab); } diff --git a/ssc/cmod_battery_stateful.h b/ssc/cmod_battery_stateful.h index e13f70509e8..c2ad5f6608e 100644 --- a/ssc/cmod_battery_stateful.h +++ b/ssc/cmod_battery_stateful.h @@ -36,7 +36,7 @@ void read_battery_state(const battery_state& state, var_table* vt); class cm_battery_stateful : public compute_module { public: - double dt_hour; + double dt_hr; enum MODE { CURRENT, POWER }; diff --git a/ssc/cmod_battwatts.cpp b/ssc/cmod_battwatts.cpp index 72e0d21a938..338c92537e5 100644 --- a/ssc/cmod_battwatts.cpp +++ b/ssc/cmod_battwatts.cpp @@ -228,7 +228,7 @@ battwatts_create(size_t n_recs, size_t n_years, int chem, int meter_pos, double batt_vars->batt_replacement_capacity = 0.; // Battery lifetime - batt_vars->batt_calendar_choice = lifetime_params::CALENDAR_CHOICE::NONE; + batt_vars->batt_calendar_choice = calendar_cycle_params::CALENDAR_CHOICE::NONE; batt_vars->batt_calendar_lifetime_matrix = util::matrix_t(); batt_vars->batt_calendar_q0 = 1.0; diff --git a/ssc/cmod_fuelcell.cpp b/ssc/cmod_fuelcell.cpp index 4714c786e2c..2fb598d476b 100644 --- a/ssc/cmod_fuelcell.cpp +++ b/ssc/cmod_fuelcell.cpp @@ -46,7 +46,7 @@ var_info vtab_fuelcell_input[] = { { SSC_INPUT, SSC_NUMBER, "fuelcell_degradation_restart_schedule","Fuel cell enable scheduled restarts", "0/1", "", "Fuel Cell", "", "", "" }, { SSC_INPUT, SSC_NUMBER, "fuelcell_degradation_restarts_per_year","Fuel cell scheduled restarts per year","", "", "Fuel Cell", "", "", "" }, { SSC_INPUT, SSC_NUMBER, "fuelcell_fixed_pct", "Fuel cell fixed operation percent", "%", "", "Fuel Cell", "", "", "" }, - { SSC_INPUT, SSC_NUMBER, "fuelcell_dynamic_response_up", "Fuel cell ramp rate limit up", "kW/h", "", "Fuel Cell", "", "", "" }, + { SSC_INPUT, SSC_NUMBER, "fuelcell_dynamic_response_up", "Fuel cell ramp rate limit up", "kW/h", "", "Fuel Cell", "", "", "" }, { SSC_INPUT, SSC_NUMBER, "fuelcell_dynamic_response_down", "Fuel cell ramp rate limit down", "kW/h", "", "Fuel Cell", "", "", "" }, { SSC_INPUT, SSC_MATRIX, "fuelcell_efficiency", "Fuel cell efficiency table ", "", "", "Fuel Cell", "", "", "" }, { SSC_INPUT, SSC_NUMBER, "fuelcell_efficiency_choice", "Fuel cell efficiency definition choice ","0/1", "0=OriginalNameplate,1=DegradedNameplate", "Fuel Cell", "", "", "" }, @@ -106,7 +106,7 @@ cm_fuelcell::cm_fuelcell() add_var_info(vtab_fuelcell_output); add_var_info(vtab_technology_outputs); } - + // Have to add this since compute module isn't actually fully constructed until compute is called with // a vartable. void cm_fuelcell::construct() @@ -116,8 +116,8 @@ void cm_fuelcell::construct() std::unique_ptr tmp2(new FuelCell(fcVars->unitPowerMax_kW, fcVars->unitPowerMin_kW, fcVars->startup_hours, fcVars->is_started, fcVars->shutdown_hours, - fcVars->dynamicResponseUp_kWperHour, fcVars->dynamicResponseDown_kWperHour, - fcVars->degradation_kWperHour, fcVars->degradationRestart_kW, + fcVars->dynamicResponseUp_kWperHour, fcVars->dynamicResponseDown_kWperHour, + fcVars->degradation_kWperHour, fcVars->degradationRestart_kW, fcVars->replacementOption, fcVars->replacement_percent, fcVars->replacementSchedule, fcVars->shutdownTable, fcVars->efficiencyChoice, fcVars->efficiencyTable, fcVars->lowerHeatingValue_BtuPerFt3, fcVars->higherHeatingValue_BtuPerFt3, fcVars->availableFuel_MCf, @@ -126,7 +126,7 @@ void cm_fuelcell::construct() std::unique_ptr tmp3(new FuelCellDispatch(fuelCell.get(), fcVars->numberOfUnits, fcVars->dispatchOption, fcVars->shutdownOption, fcVars->dt_hour, fcVars->fixed_percent, fcVars->dispatch_kW, - fcVars->canCharge, fcVars->canDischarge, fcVars->discharge_percentByPeriod, fcVars->discharge_unitsByPeriod, + fcVars->canCharge, fcVars->canDischarge, fcVars->discharge_percentByPeriod, fcVars->discharge_unitsByPeriod, fcVars->scheduleWeekday,fcVars->scheduleWeekend)); fuelCellDispatch = std::move(tmp3); @@ -138,7 +138,7 @@ void cm_fuelcell::exec() double annual_energy = 0.0; double annual_fuel = 0.0; // float percent_complete = 0.0; - float percent = 0.0; +// float percent = 0.0; // size_t nStatusUpdates = 50; /* @@ -150,7 +150,7 @@ void cm_fuelcell::exec() construct(); size_t idx = 0; for (size_t y = 0; y < fcVars->numberOfYears; y++) { - + size_t idx_year = 0; size_t annual_index; fcVars->numberOfYears > 1 ? annual_index = y + 1 : annual_index = 0; @@ -161,7 +161,7 @@ void cm_fuelcell::exec() if (h % (8760 / nStatusUpdates) == 0) { // assume that anyone using this module is chaining with two techs - float techs = 3; + float techs = 3; percent = percent_complete + 100.0f * ((float)idx + 1) / ((float)fcVars->numberOfLifetimeRecords) / techs; if (!update("", percent, (float)h)) { throw exec_error("fuelcell", "simulation canceled at hour " + util::to_string(h + 1.0)); @@ -184,7 +184,7 @@ void cm_fuelcell::exec() if (y == 0) { annual_energy += p_gen_kW[idx] * fcVars->dt_hour; } - + idx++; idx_year++; } @@ -197,7 +197,7 @@ void cm_fuelcell::exec() p_fuelCellReplacements[annual_index] = (ssc_number_t)(fuelCell->getTotalReplacements()); fuelCell->resetReplacements(); } - + // capacity factor update double capacity_factor_in, annual_energy_in, nameplate_in; capacity_factor_in = annual_energy_in = nameplate_in = 0; diff --git a/ssc/cmod_pvsamv1.cpp b/ssc/cmod_pvsamv1.cpp index 2bd58204930..38f5e7a6a68 100644 --- a/ssc/cmod_pvsamv1.cpp +++ b/ssc/cmod_pvsamv1.cpp @@ -2134,7 +2134,6 @@ void cm_pvsamv1::exec() dcPowerNetPerMppt_kW[m] = PVSystem->p_dcPowerNetPerMppt[m][idx] * util::watt_to_kilowatt; } - double power_before_battery = 0.0; //run AC power calculation if (en_batt && (batt_topology == ChargeController::DC_CONNECTED)) // DC-connected battery { diff --git a/ssc/cmod_pvwattsv5.cpp b/ssc/cmod_pvwattsv5.cpp index 9982ba048b5..28f3607ba66 100644 --- a/ssc/cmod_pvwattsv5.cpp +++ b/ssc/cmod_pvwattsv5.cpp @@ -674,7 +674,7 @@ class cm_pvwattsv5_1ts : public cm_pvwattsv5_base double tamb = as_double("tamb"); double wspd = as_double("wspd"); double alb = as_double("alb"); - double elev, tdry, pres; + double elev, pres; if (!is_assigned("elevation")) { elev = 0; //assume 0 meter elevation if none is provided } diff --git a/test/input_cases/battery_common_data.h b/test/input_cases/battery_common_data.h index a07a8c82fed..6af3b02d0c3 100644 --- a/test/input_cases/battery_common_data.h +++ b/test/input_cases/battery_common_data.h @@ -73,7 +73,8 @@ namespace { ssc_data_set_number(data, "batt_minimum_SOC", 15); ssc_data_set_number(data, "batt_maximum_SOC", 95); ssc_data_set_number(data, "batt_minimum_modetime", 10); - ssc_number_t p_batt_lifetime_matrix[18] = { 20, 0, 100, 20, 5000, 80, 20, 10000, 60, 80, 0, 100, 80, 1000, 80, 80, 2000, 60 }; + ssc_data_set_number(data, "batt_life_model", 0); + ssc_number_t p_batt_lifetime_matrix[18] = { 20, 0, 100, 20, 5000, 80, 20, 10000, 60, 80, 0, 100, 80, 1000, 80, 80, 2000, 60 }; ssc_data_set_matrix(data, "batt_lifetime_matrix", p_batt_lifetime_matrix, 6, 3); ssc_data_set_number(data, "batt_calendar_choice", 1); ssc_number_t p_batt_calendar_lifetime_matrix[6] = { 0, 100, 3650, 80, 7300, 50 }; diff --git a/test/input_cases/generic_common_data.h b/test/input_cases/generic_common_data.h index 0426b656d83..c8924c27ff6 100644 --- a/test/input_cases/generic_common_data.h +++ b/test/input_cases/generic_common_data.h @@ -96,7 +96,8 @@ void generic_singleowner_battery_60min(ssc_data_t &data) ssc_data_set_number( data, "batt_minimum_SOC", 15 ); ssc_data_set_number( data, "batt_maximum_SOC", 95 ); ssc_data_set_number( data, "batt_minimum_modetime", 10 ); - ssc_number_t p_batt_lifetime_matrix[18] ={ 20, 0, 100, 20, 2500, 98, 20, 5000, 95, 80, 0, 100, 80, 500, 98, 80, 1000, 95 }; + ssc_data_set_number(data, "batt_life_model", 0); + ssc_number_t p_batt_lifetime_matrix[18] ={ 20, 0, 100, 20, 2500, 98, 20, 5000, 95, 80, 0, 100, 80, 500, 98, 80, 1000, 95 }; ssc_data_set_matrix( data, "batt_lifetime_matrix", p_batt_lifetime_matrix, 6, 3 ); ssc_data_set_number( data, "batt_calendar_choice", 1 ); ssc_number_t p_batt_calendar_lifetime_matrix[6] ={ 0, 100, 3650, 80, 7300, 50 }; @@ -466,6 +467,7 @@ void generic_commerical_battery_60min(ssc_data_t &data) ssc_data_set_number(data, "batt_minimum_SOC", 15); ssc_data_set_number(data, "batt_maximum_SOC", 95); ssc_data_set_number(data, "batt_minimum_modetime", 10); + ssc_data_set_number(data, "batt_life_model", 0); ssc_number_t p_batt_lifetime_matrix[18] = { 20, 0, 100, 20, 5000, 80, 20, 10000, 60, 80, 0, 100, 80, 1000, 80, 80, 2000, 60 }; ssc_data_set_matrix(data, "batt_lifetime_matrix", p_batt_lifetime_matrix, 6, 3); ssc_data_set_number(data, "batt_calendar_choice", 0); diff --git a/test/input_cases/pvsamv1_battery_common_data.h b/test/input_cases/pvsamv1_battery_common_data.h index b5d384fe2f0..fcc649c860e 100644 --- a/test/input_cases/pvsamv1_battery_common_data.h +++ b/test/input_cases/pvsamv1_battery_common_data.h @@ -415,7 +415,8 @@ void pvsamv1_battery_defaults(ssc_data_t& data) { ssc_data_set_number(data, "batt_minimum_SOC", 15); ssc_data_set_number(data, "batt_maximum_SOC", 95); ssc_data_set_number(data, "batt_minimum_modetime", 10); - ssc_number_t p_batt_lifetime_matrix[18] = { 20, 0, 100, 20, 5000, 80, 20, 10000, 60, 80, 0, 100, 80, 1000, 80, 80, 2000, 60 }; + ssc_data_set_number(data, "batt_life_model", 0); + ssc_number_t p_batt_lifetime_matrix[18] = { 20, 0, 100, 20, 5000, 80, 20, 10000, 60, 80, 0, 100, 80, 1000, 80, 80, 2000, 60 }; ssc_data_set_matrix(data, "batt_lifetime_matrix", p_batt_lifetime_matrix, 6, 3); ssc_data_set_number(data, "batt_calendar_choice", 0); ssc_number_t p_batt_calendar_lifetime_matrix[6] = { 0, 100, 3650, 80, 7300, 50 }; @@ -1131,6 +1132,7 @@ void commercial_multiarray_default(ssc_data_t& data) { ssc_data_set_number(data, "batt_minimum_SOC", 15); ssc_data_set_number(data, "batt_maximum_SOC", 95); ssc_data_set_number(data, "batt_minimum_modetime", 10); + ssc_data_set_number(data, "batt_life_model", 0 ); ssc_number_t p_batt_lifetime_matrix[18] = { 20, 0, 100, 20, 5000, 80, 20, 10000, 60, 80, 0, 100, 80, 1000, 80, 80, 2000, 60 }; ssc_data_set_matrix(data, "batt_lifetime_matrix", p_batt_lifetime_matrix, 6, 3); ssc_data_set_number(data, "batt_calendar_choice", 0); diff --git a/test/input_cases/pvsamv1_common_data.cpp b/test/input_cases/pvsamv1_common_data.cpp index 77b6384c6ae..b31f00bfb33 100644 --- a/test/input_cases/pvsamv1_common_data.cpp +++ b/test/input_cases/pvsamv1_common_data.cpp @@ -436,6 +436,7 @@ void battery_data_default(ssc_data_t& data) { ssc_data_set_number(data, "batt_minimum_SOC", 15); ssc_data_set_number(data, "batt_maximum_SOC", 95); ssc_data_set_number(data, "batt_minimum_modetime", 10); + ssc_data_set_number(data, "batt_life_model", 0); ssc_number_t p_batt_lifetime_matrix[18] = { 20, 0, 100, 20, 5000, 80, 20, 10000, 60, 80, 0, 100, 80, 1000, 80, 80, 2000, 60 }; ssc_data_set_matrix(data, "batt_lifetime_matrix", p_batt_lifetime_matrix, 6, 3); ssc_data_set_number(data, "batt_replacement_capacity", 50); diff --git a/test/shared_test/lib_battery_dispatch_automatic_btm_test.h b/test/shared_test/lib_battery_dispatch_automatic_btm_test.h index b8fb90adaff..0b6938b8d0b 100644 --- a/test/shared_test/lib_battery_dispatch_automatic_btm_test.h +++ b/test/shared_test/lib_battery_dispatch_automatic_btm_test.h @@ -18,7 +18,7 @@ class AutoBTMTest_lib_battery_dispatch : public BatteryProperties , public Dispa capacity_lithium_ion_t * capacityModel; voltage_dynamic_t * voltageModel; thermal_t * thermalModel; - lifetime_t * lifetimeModel; + lifetime_calendar_cycle_t * lifetimeModel; losses_t * lossModel; battery_t * batteryModel; BatteryPower * batteryPower; @@ -52,7 +52,7 @@ class AutoBTMTest_lib_battery_dispatch : public BatteryProperties , public Dispa capacityModel = new capacity_lithium_ion_t(q * n_strings, SOC_init, SOC_max, SOC_min, dtHour); voltageModel = new voltage_dynamic_t(n_series, n_strings, Vnom_default, Vfull, Vexp, Vnom, Qfull, Qexp, Qnom, C_rate, resistance, dtHour); - lifetimeModel = new lifetime_t(cycleLifeMatrix, dtHour, calendar_q0, calendar_a, calendar_b, calendar_c); + lifetimeModel = new lifetime_calendar_cycle_t(cycleLifeMatrix, dtHour, calendar_q0, calendar_a, calendar_b, calendar_c); thermalModel = new thermal_t(1.0, mass, surface_area, resistance, Cp, h, capacityVsTemperature, T_room); lossModel = new losses_t(); batteryModel = new battery_t(dtHour, chemistry, capacityModel, voltageModel, lifetimeModel, thermalModel, lossModel); @@ -80,7 +80,7 @@ class AutoBTMTest_lib_battery_dispatch : public BatteryProperties , public Dispa capacityModel = new capacity_lithium_ion_t(q * n_strings, SOC_init, SOC_max, SOC_min, dtHour); voltageModel = new voltage_dynamic_t(n_series, n_strings, Vnom_default, Vfull, Vexp, Vnom, Qfull, Qexp, Qnom, C_rate, resistance, dtHour); - lifetimeModel = new lifetime_t(cycleLifeMatrix, dtHour, calendar_q0, calendar_a, calendar_b, calendar_c); + lifetimeModel = new lifetime_calendar_cycle_t(cycleLifeMatrix, dtHour, calendar_q0, calendar_a, calendar_b, calendar_c); thermalModel = new thermal_t(1.0, mass, surface_area, resistance, Cp, h, capacityVsTemperature, T_room); std::vector charging_losses(12, 1); // Monthly losses diff --git a/test/shared_test/lib_battery_dispatch_automatic_fom_test.h b/test/shared_test/lib_battery_dispatch_automatic_fom_test.h index c8eaec284c9..9c2bf7a5e3d 100644 --- a/test/shared_test/lib_battery_dispatch_automatic_fom_test.h +++ b/test/shared_test/lib_battery_dispatch_automatic_fom_test.h @@ -16,7 +16,7 @@ class AutoFOM_lib_battery_dispatch : public BatteryProperties , public DispatchP { protected: thermal_t * thermalModel; - lifetime_t * lifetimeModel; + lifetime_calendar_cycle_t * lifetimeModel; BatteryPower * batteryPower; capacity_lithium_ion_t * capacityModel; @@ -46,7 +46,7 @@ class AutoFOM_lib_battery_dispatch : public BatteryProperties , public DispatchP capacityModel = new capacity_lithium_ion_t(2.25 * 133227, 50, 100, 10, dtHour); voltageModel = new voltage_dynamic_t(139, 133227, 3.6, 4.10, 4.05, 3.4, 2.25, 0.04, 2.00, 0.2, 0.2, dtHour); - lifetimeModel = new lifetime_t(cycleLifeMatrix, dtHour, calendar_q0, calendar_a, calendar_b, calendar_c); + lifetimeModel = new lifetime_calendar_cycle_t(cycleLifeMatrix, dtHour, calendar_q0, calendar_a, calendar_b, calendar_c); thermalModel = new thermal_t(1.0, mass, surface_area, resistance, Cp, h, capacityVsTemperature, T_room); lossModel = new losses_t(); batteryModel = new battery_t(dtHour, chemistry, capacityModel, voltageModel, lifetimeModel, thermalModel, lossModel); @@ -62,7 +62,7 @@ class AutoFOM_lib_battery_dispatch : public BatteryProperties , public DispatchP capacityModel = new capacity_lithium_ion_t(2.25 * 133227, 50, 100, 10, dtHour); voltageModel = new voltage_dynamic_t(139, 133227, 3.6, 4.10, 4.05, 3.4, 2.25, 0.04, 2.00, 0.2, 0.2, dtHour); - lifetimeModel = new lifetime_t(cycleLifeMatrix, dtHour, calendar_q0, calendar_a, calendar_b, calendar_c); + lifetimeModel = new lifetime_calendar_cycle_t(cycleLifeMatrix, dtHour, calendar_q0, calendar_a, calendar_b, calendar_c); thermalModel = new thermal_t(1.0, mass, surface_area, resistance, Cp, h, capacityVsTemperature, T_room); std::vector charging_losses(12, 10); // Monthly losses diff --git a/test/shared_test/lib_battery_dispatch_manual_test.h b/test/shared_test/lib_battery_dispatch_manual_test.h index cee87eed40d..04110572591 100644 --- a/test/shared_test/lib_battery_dispatch_manual_test.h +++ b/test/shared_test/lib_battery_dispatch_manual_test.h @@ -19,7 +19,7 @@ class ManualTest_lib_battery_dispatch : public BatteryProperties, public Dispatc capacity_lithium_ion_t* capacityModel; voltage_dynamic_t* voltageModel; thermal_t* thermalModel; - lifetime_t* lifetimeModel; + lifetime_calendar_cycle_t* lifetimeModel; losses_t* lossModel; battery_t* batteryModel; BatteryPower* batteryPower; @@ -53,7 +53,7 @@ class ManualTest_lib_battery_dispatch : public BatteryProperties, public Dispatc capacityModel = new capacity_lithium_ion_t(q * n_strings, SOC_init, SOC_max, SOC_min, 1.0); voltageModel = new voltage_dynamic_t(n_series, n_strings, Vnom_default, Vfull, Vexp, Vnom, Qfull, Qexp, Qnom, C_rate, resistance, dtHour); - lifetimeModel = new lifetime_t(cycleLifeMatrix, dtHour, calendar_q0, calendar_a, calendar_b, calendar_c); + lifetimeModel = new lifetime_calendar_cycle_t(cycleLifeMatrix, dtHour, calendar_q0, calendar_a, calendar_b, calendar_c); thermalModel = new thermal_t(1.0, mass, surface_area, resistance, Cp, h, capacityVsTemperature, T_room); lossModel = new losses_t(); batteryModel = new battery_t(dtHour, chemistry, capacityModel, voltageModel, lifetimeModel, thermalModel, lossModel); @@ -83,7 +83,7 @@ class ManualTest_lib_battery_dispatch_losses : public ManualTest_lib_battery_dis capacityModel = new capacity_lithium_ion_t(q * n_strings, SOC_init, SOC_max, SOC_min, 1.0); voltageModel = new voltage_dynamic_t(n_series, n_strings, Vnom_default, Vfull, Vexp, Vnom, Qfull, Qexp, Qnom, C_rate, resistance, dtHour); - lifetimeModel = new lifetime_t(cycleLifeMatrix, dtHour, calendar_q0, calendar_a, calendar_b, calendar_c); + lifetimeModel = new lifetime_calendar_cycle_t(cycleLifeMatrix, dtHour, calendar_q0, calendar_a, calendar_b, calendar_c); thermalModel = new thermal_t(1.0, mass, surface_area, resistance, Cp, h, capacityVsTemperature, T_room); std::vector charging_losses(12, 1); // Monthly losses diff --git a/test/shared_test/lib_battery_lifetime_test.cpp b/test/shared_test/lib_battery_lifetime_test.cpp index dbdfbac5883..c129ff5a760 100644 --- a/test/shared_test/lib_battery_lifetime_test.cpp +++ b/test/shared_test/lib_battery_lifetime_test.cpp @@ -33,11 +33,11 @@ TEST_F(lib_battery_lifetime_cycle_test, runCycleLifetimeTest) { cycle_model->runCycleLifetime(DOD); idx++; } - cycle_state s = cycle_model->get_state(); - EXPECT_NEAR(s.q_relative_cycle, 95.02, tol); - EXPECT_NEAR(s.rainflow_Xlt, 90, tol); - EXPECT_NEAR(s.rainflow_Ylt, 90, tol); - EXPECT_NEAR(s.rainflow_jlt, 2, tol); + lifetime_state s = cycle_model->get_state(); + EXPECT_NEAR(s.cycle->q_relative_cycle, 95.02, tol); + EXPECT_NEAR(s.cycle->rainflow_Xlt, 90, tol); + EXPECT_NEAR(s.cycle->rainflow_Ylt, 90, tol); + EXPECT_NEAR(s.cycle->rainflow_jlt, 2, tol); EXPECT_NEAR(s.range, 90, tol); EXPECT_NEAR(s.average_range, 90, tol); EXPECT_NEAR(s.n_cycles, 249, tol); @@ -50,10 +50,10 @@ TEST_F(lib_battery_lifetime_cycle_test, runCycleLifetimeTest) { idx++; } s = cycle_model->get_state(); - EXPECT_NEAR(s.q_relative_cycle, 91.244, tol); - EXPECT_NEAR(s.rainflow_Xlt, 0, tol); - EXPECT_NEAR(s.rainflow_Ylt, 0, tol); - EXPECT_NEAR(s.rainflow_jlt, 2, tol); + EXPECT_NEAR(s.cycle->q_relative_cycle, 91.244, tol); + EXPECT_NEAR(s.cycle->rainflow_Xlt, 0, tol); + EXPECT_NEAR(s.cycle->rainflow_Ylt, 0, tol); + EXPECT_NEAR(s.cycle->rainflow_jlt, 2, tol); EXPECT_NEAR(s.range, 0, tol); EXPECT_NEAR(s.average_range, 44.9098, tol); EXPECT_NEAR(s.n_cycles, 499, tol); @@ -66,11 +66,11 @@ TEST_F(lib_battery_lifetime_cycle_test, runCycleLifetimeTestJaggedProfile) { cycle_model->runCycleLifetime(DOD[idx]); idx++; } - cycle_state s = cycle_model->get_state(); - EXPECT_NEAR(s.q_relative_cycle, 99.95, tol); - EXPECT_NEAR(s.rainflow_Xlt, 90, tol); - EXPECT_NEAR(s.rainflow_Ylt, 90, tol); - EXPECT_NEAR(s.rainflow_jlt, 1, tol); + lifetime_state s = cycle_model->get_state(); + EXPECT_NEAR(s.cycle->q_relative_cycle, 99.95, tol); + EXPECT_NEAR(s.cycle->rainflow_Xlt, 90, tol); + EXPECT_NEAR(s.cycle->rainflow_Ylt, 90, tol); + EXPECT_NEAR(s.cycle->rainflow_jlt, 1, tol); EXPECT_NEAR(s.range, 90, tol); EXPECT_NEAR(s.average_range, 63.75, tol); EXPECT_NEAR(s.n_cycles, 4, tol); @@ -84,11 +84,11 @@ TEST_F(lib_battery_lifetime_cycle_test, runCycleLifetimeTestKokamProfile) { cycle_model->runCycleLifetime((1-DOD[idx]) * 100.0); idx++; } - cycle_state s = cycle_model->get_state(); - EXPECT_NEAR(s.q_relative_cycle, 99.79, tol); - EXPECT_NEAR(s.rainflow_Xlt, 75.09, tol); - EXPECT_NEAR(s.rainflow_Ylt, 75.27, tol); - EXPECT_NEAR(s.rainflow_jlt, 5, tol); + lifetime_state s = cycle_model->get_state(); + EXPECT_NEAR(s.cycle->q_relative_cycle, 99.79, tol); + EXPECT_NEAR(s.cycle->rainflow_Xlt, 75.09, tol); + EXPECT_NEAR(s.cycle->rainflow_Ylt, 75.27, tol); + EXPECT_NEAR(s.cycle->rainflow_jlt, 5, tol); EXPECT_NEAR(s.range, 75.07, tol); EXPECT_NEAR(s.average_range, 72.03, tol); EXPECT_NEAR(s.n_cycles, 13, tol); @@ -97,7 +97,7 @@ TEST_F(lib_battery_lifetime_cycle_test, runCycleLifetimeTestKokamProfile) { TEST_F(lib_battery_lifetime_cycle_test, runCycleLifetimeTestWithNoise) { int seed = 100; - double tol_high = 1.0; // Randomness will generate different results on different platforms + double tol_high = 1.6; // Randomness will generate different results on different platforms // Initialize a default_random_engine with the seed std::default_random_engine randomEngine(seed); @@ -117,9 +117,9 @@ TEST_F(lib_battery_lifetime_cycle_test, runCycleLifetimeTestWithNoise) { cycle_model->runCycleLifetime(DOD); idx++; } - cycle_state s = cycle_model->get_state(); - EXPECT_NEAR(s.q_relative_cycle, 95.06, tol_high); - EXPECT_NEAR(s.range, 89.06, tol_high); + lifetime_state s = cycle_model->get_state(); + EXPECT_NEAR(s.cycle->q_relative_cycle, 95.06, tol_high); + EXPECT_NEAR(s.range, 90.6, tol_high); EXPECT_NEAR(s.average_range, 90.02, tol_high); } @@ -137,11 +137,11 @@ TEST_F(lib_battery_lifetime_cycle_test, replaceBatteryTest) { idx++; } auto st = cycle_lifetime_state({85.02,90,90,90,90, 749, 2}); - cycle_state s = cycle_model->get_state(); - EXPECT_NEAR(s.q_relative_cycle, 85.02, tol); - EXPECT_NEAR(s.rainflow_Xlt, 90, tol); - EXPECT_NEAR(s.rainflow_Ylt, 90, tol); - EXPECT_NEAR(s.rainflow_jlt, 2, tol); + lifetime_state s = cycle_model->get_state(); + EXPECT_NEAR(s.cycle->q_relative_cycle, 85.02, tol); + EXPECT_NEAR(s.cycle->rainflow_Xlt, 90, tol); + EXPECT_NEAR(s.cycle->rainflow_Ylt, 90, tol); + EXPECT_NEAR(s.cycle->rainflow_jlt, 2, tol); EXPECT_NEAR(s.range, 90, tol); EXPECT_NEAR(s.average_range, 90, tol); EXPECT_NEAR(s.n_cycles, 749, tol); @@ -149,10 +149,10 @@ TEST_F(lib_battery_lifetime_cycle_test, replaceBatteryTest) { cycle_model->replaceBattery(5); s = cycle_model->get_state(); - EXPECT_NEAR(s.q_relative_cycle, 90.019, tol); - EXPECT_NEAR(s.rainflow_Xlt, 0, tol); - EXPECT_NEAR(s.rainflow_Ylt, 0, tol); - EXPECT_NEAR(s.rainflow_jlt, 0, tol); + EXPECT_NEAR(s.cycle->q_relative_cycle, 90.019, tol); + EXPECT_NEAR(s.cycle->rainflow_Xlt, 0, tol); + EXPECT_NEAR(s.cycle->rainflow_Ylt, 0, tol); + EXPECT_NEAR(s.cycle->rainflow_jlt, 0, tol); EXPECT_NEAR(s.range, 0, tol); EXPECT_NEAR(s.average_range, 90, tol); EXPECT_NEAR(s.n_cycles, 749, tol); @@ -161,56 +161,52 @@ TEST_F(lib_battery_lifetime_cycle_test, replaceBatteryTest) { TEST_F(lib_battery_lifetime_calendar_matrix_test, runCalendarMatrixTest) { double T = 278, SOC = 20; // not used but required for function int idx = 0; - //Rohit - add charge_changed to CalendarModel - bool charge_changed = true; while (idx < 500){ if (idx % 2 != 0){ SOC = 90; } - cal_model->runLifetimeCalendarModel(idx, T, SOC, charge_changed); + cal_model->runLifetimeCalendarModel(idx, T, SOC); idx++; } - calendar_state s = cal_model->get_state(); + lifetime_state s = cal_model->get_state(); EXPECT_NEAR(s.day_age_of_battery, 20, tol); - EXPECT_NEAR(s.q_relative_calendar, 99.89, tol); - EXPECT_NEAR(s.dq_relative_calendar_old, 0, tol); + EXPECT_NEAR(s.calendar->q_relative_calendar, 99.89, tol); + EXPECT_NEAR(s.calendar->dq_relative_calendar_old, 0, tol); while (idx < 1000){ if (idx % 2 != 0){ SOC = 90; } - cal_model->runLifetimeCalendarModel(idx, T, SOC, charge_changed); + cal_model->runLifetimeCalendarModel(idx, T, SOC); idx++; } s = cal_model->get_state(); EXPECT_NEAR(s.day_age_of_battery, 41, tol); - EXPECT_NEAR(s.q_relative_calendar, 99.775, tol); - EXPECT_NEAR(s.dq_relative_calendar_old, 0, tol); + EXPECT_NEAR(s.calendar->q_relative_calendar, 99.775, tol); + EXPECT_NEAR(s.calendar->dq_relative_calendar_old, 0, tol); } TEST_F(lib_battery_lifetime_calendar_matrix_test, replaceBatteryTest) { double T = 4.85, SOC = 20; int idx = 0; - // Rohit - add charge_changed to Calendar Model - bool charge_changed = true; while (idx < 200000){ if (idx % 2 != 0){ SOC = 90; } - cal_model->runLifetimeCalendarModel(idx, T, SOC,charge_changed); + cal_model->runLifetimeCalendarModel(idx, T, SOC); idx++; } - calendar_state s = cal_model->get_state(); + lifetime_state s = cal_model->get_state(); EXPECT_NEAR(s.day_age_of_battery, 8333, tol); - EXPECT_NEAR(s.q_relative_calendar, 41.51, tol); - EXPECT_NEAR(s.dq_relative_calendar_old, 0, tol); + EXPECT_NEAR(s.calendar->q_relative_calendar, 41.51, tol); + EXPECT_NEAR(s.calendar->dq_relative_calendar_old, 0, tol); cal_model->replaceBattery(5); s = cal_model->get_state(); EXPECT_NEAR(s.day_age_of_battery, 0, tol); - EXPECT_NEAR(s.q_relative_calendar, 46.51, tol); - EXPECT_NEAR(s.dq_relative_calendar_old, 0, tol); + EXPECT_NEAR(s.calendar->q_relative_calendar, 46.51, tol); + EXPECT_NEAR(s.calendar->dq_relative_calendar_old, 0, tol); } TEST_F(lib_battery_lifetime_calendar_model_test, SetUpTest) { @@ -220,56 +216,52 @@ TEST_F(lib_battery_lifetime_calendar_model_test, SetUpTest) { TEST_F(lib_battery_lifetime_calendar_model_test, runCalendarModelTest) { double T = 4.85, SOC = 20; // not used but required for function int idx = 0; - // Add charge_changed to calendar model - bool charge_changed = true; while (idx < 500){ if (idx % 2 != 0){ SOC = 90; } - cal_model->runLifetimeCalendarModel(idx, T, SOC,charge_changed); + cal_model->runLifetimeCalendarModel(idx, T, SOC); idx++; } - calendar_state s = cal_model->get_state(); + lifetime_state s = cal_model->get_state(); EXPECT_NEAR(s.day_age_of_battery, 20, tol); - EXPECT_NEAR(s.q_relative_calendar, 101.78, tol); - EXPECT_NEAR(s.dq_relative_calendar_old, 0.00217, tol); + EXPECT_NEAR(s.calendar->q_relative_calendar, 101.78, tol); + EXPECT_NEAR(s.calendar->dq_relative_calendar_old, 0.00217, tol); while (idx < 1000){ if (idx % 2 != 0){ SOC = 90; } - cal_model->runLifetimeCalendarModel(idx, T, SOC,charge_changed); + cal_model->runLifetimeCalendarModel(idx, T, SOC); idx++; } s = cal_model->get_state(); EXPECT_NEAR(s.day_age_of_battery, 41, tol); - EXPECT_NEAR(s.q_relative_calendar, 101.69, tol); - EXPECT_NEAR(s.dq_relative_calendar_old, 0.00306, tol); + EXPECT_NEAR(s.calendar->q_relative_calendar, 101.69, tol); + EXPECT_NEAR(s.calendar->dq_relative_calendar_old, 0.00306, tol); } TEST_F(lib_battery_lifetime_calendar_model_test, replaceBatteryTest) { double T = 4.85, SOC = 20; int idx = 0; - //Rohit - add charge_changed to CalendarModel - bool charge_changed = true; while (idx < 200000){ if (idx % 2 != 0){ SOC = 90; } - cal_model->runLifetimeCalendarModel(idx, T, SOC,charge_changed); + cal_model->runLifetimeCalendarModel(idx, T, SOC); idx++; } - calendar_state s = cal_model->get_state(); + lifetime_state s = cal_model->get_state(); EXPECT_NEAR(s.day_age_of_battery, 8333, tol); - EXPECT_NEAR(s.q_relative_calendar, 97.67, tol); - EXPECT_NEAR(s.dq_relative_calendar_old, 0.043, tol); + EXPECT_NEAR(s.calendar->q_relative_calendar, 97.67, tol); + EXPECT_NEAR(s.calendar->dq_relative_calendar_old, 0.043, tol); cal_model->replaceBattery(5); s = cal_model->get_state(); EXPECT_NEAR(s.day_age_of_battery, 0, tol); - EXPECT_NEAR(s.q_relative_calendar, 102, tol); - EXPECT_NEAR(s.dq_relative_calendar_old, 0.0, tol); + EXPECT_NEAR(s.calendar->q_relative_calendar, 102, tol); + EXPECT_NEAR(s.calendar->dq_relative_calendar_old, 0.0, tol); } TEST_F(lib_battery_lifetime_calendar_matrix_test, TestLifetimeDegradation) { @@ -277,13 +269,11 @@ TEST_F(lib_battery_lifetime_calendar_matrix_test, TestLifetimeDegradation) { util::matrix_t lifetime_matrix; lifetime_matrix.assign(vals, 2, 2); - //Rohit - add charge_changed to Calendar model - bool charge_changed = true; double dt_hour = 1; lifetime_calendar_t hourly_lifetime(dt_hour, lifetime_matrix); for (int idx = 0; idx < 8760; idx++) { - hourly_lifetime.runLifetimeCalendarModel(idx, 20, 80,charge_changed); + hourly_lifetime.runLifetimeCalendarModel(idx, 20, 80); } EXPECT_NEAR(hourly_lifetime.capacity_percent(), 50, 1); @@ -292,7 +282,7 @@ TEST_F(lib_battery_lifetime_calendar_matrix_test, TestLifetimeDegradation) { lifetime_calendar_t subhourly_lifetime(dt_hour, lifetime_matrix); for (int idx = 0; idx < 8760 * 12; idx++) { - subhourly_lifetime.runLifetimeCalendarModel(idx, 20, 80,charge_changed); + subhourly_lifetime.runLifetimeCalendarModel(idx, 20, 80); } EXPECT_NEAR(subhourly_lifetime.capacity_percent(), 50, 1); @@ -301,11 +291,8 @@ TEST_F(lib_battery_lifetime_calendar_matrix_test, TestLifetimeDegradation) { TEST_F(lib_battery_lifetime_calendar_model_test, TestLifetimeDegradation) { - //Rohit - add charge_changed to CalendarModel - bool charge_changed = true; - for (int idx = 0; idx < 8760; idx++) { - cal_model->runLifetimeCalendarModel(idx, 20, 80,charge_changed); + cal_model->runLifetimeCalendarModel(idx, 20, 80); } EXPECT_NEAR(cal_model->capacity_percent(), 99.812, 1); @@ -314,7 +301,7 @@ TEST_F(lib_battery_lifetime_calendar_model_test, TestLifetimeDegradation) { lifetime_calendar_t subhourly_lifetime(dt_hour); for (int idx = 0; idx < 8760 * 12; idx++) { - subhourly_lifetime.runLifetimeCalendarModel(idx, 20, 80,charge_changed); + subhourly_lifetime.runLifetimeCalendarModel(idx, 20, 80); } EXPECT_NEAR(subhourly_lifetime.capacity_percent(), 99.812, 1); @@ -332,7 +319,6 @@ TEST_F(lib_battery_lifetime_test, updateCapacityTest) { idx ++; } - } TEST_F(lib_battery_lifetime_test, runCycleLifetimeTestWithRestPeriod) { @@ -351,17 +337,47 @@ TEST_F(lib_battery_lifetime_test, runCycleLifetimeTestWithRestPeriod) { idx++; } - - cycle_state s = *model->get_state().cycle; - EXPECT_NEAR(s.q_relative_cycle, 99.96, tol); - EXPECT_NEAR(s.rainflow_Xlt, 90, tol); - EXPECT_NEAR(s.rainflow_Ylt, 90, tol); - EXPECT_NEAR(s.rainflow_jlt, 2, tol); + + lifetime_state s = model->get_state(); + EXPECT_NEAR(s.cycle->q_relative_cycle, 99.96, tol); + EXPECT_NEAR(s.cycle->rainflow_Xlt, 90, tol); + EXPECT_NEAR(s.cycle->rainflow_Ylt, 90, tol); + EXPECT_NEAR(s.cycle->rainflow_jlt, 2, tol); EXPECT_NEAR(s.range, 90, tol); EXPECT_NEAR(s.average_range, 90, tol); EXPECT_NEAR(s.n_cycles, 2, tol); - //Rohit - EXPECT_GT(s.n_cycles, 0, tol); } +TEST_F(lib_battery_lifetime_nmc_test, updateCapacityTest) { + size_t idx = 0; + double tol = 0.01; + //check lifetime_nmc_state_initialization + ASSERT_EQ(model->get_state().nmc_state->q_relative_neg, 100); + ASSERT_EQ(model->get_state().nmc_state->q_relative_li, 100); + ASSERT_EQ(model->get_state().nmc_state->b1_dt.size(), 0); + ASSERT_EQ(model->get_state().nmc_state->b2_dt.size(), 0); + ASSERT_EQ(model->get_state().nmc_state->b3_dt.size(), 0); + ASSERT_EQ(model->get_state().nmc_state->day_age_of_battery_float, 0); + + //check U_neg, and Voc functions (SOC as a fractional input) + ASSERT_NEAR(model->Uneg_computation(0.1), 0.242, tol); + ASSERT_NEAR(model->Voc_computation(0.1), 3.4679, tol); + ASSERT_NEAR(model->Uneg_computation(0.5), 0.1726, tol); + ASSERT_NEAR(model->Voc_computation(0.5), 3.6912, tol); + ASSERT_NEAR(model->Uneg_computation(0.9), 0.1032, tol); + ASSERT_NEAR(model->Voc_computation(0.9), 4.0818, tol); + + // check number of cycles + while (idx < 876){ + model->runLifetimeModels(idx, true, 5,95, 25); + model->runLifetimeModels(idx, true, 95, 5, 25); + + auto state = model->get_state(); + + idx ++; + } + + ASSERT_EQ(model->get_state().n_cycles, 875); + +} diff --git a/test/shared_test/lib_battery_lifetime_test.h b/test/shared_test/lib_battery_lifetime_test.h index 32d092a8f23..f043165f753 100644 --- a/test/shared_test/lib_battery_lifetime_test.h +++ b/test/shared_test/lib_battery_lifetime_test.h @@ -4,7 +4,7 @@ #include #include "lib_util.h" -//#include "lib_battery_lifetime.h" +//#include "lifetime_t.h" #include "lib_battery.h" class lib_battery_lifetime_cycle_test : public ::testing::Test @@ -85,7 +85,7 @@ class lib_battery_lifetime_calendar_model_test : public ::testing::Test class lib_battery_lifetime_test : public ::testing::Test{ protected: - std::unique_ptr model; + std::unique_ptr model; util::matrix_t cycles_vs_DOD; @@ -94,7 +94,19 @@ class lib_battery_lifetime_test : public ::testing::Test{ void SetUp() override { double table_vals[18] = {20, 0, 100, 20, 5000, 80, 20, 10000, 60, 80, 0, 100, 80, 1000, 80, 80, 2000, 60}; cycles_vs_DOD.assign(table_vals, 6, 3); - model = std::unique_ptr(new lifetime_t(cycles_vs_DOD, dt_hour,1.02, 2.66e-3, -7280, 930)); + model = std::unique_ptr(new lifetime_calendar_cycle_t(cycles_vs_DOD, dt_hour, 1.02, 2.66e-3, -7280, 930)); } }; + +class lib_battery_lifetime_nmc_test : public ::testing::Test{ +protected: + std::unique_ptr model; + + double dt_hour = 1; +public: + void SetUp() override { + model = std::unique_ptr(new lifetime_nmc_t(dt_hour)); + } +}; + #endif //SAM_SIMULATION_CORE_LIB_BATTERY_LIFETIME_TEST_H diff --git a/test/shared_test/lib_battery_properties.h b/test/shared_test/lib_battery_properties.h index 4ef6697e722..3736516fd9a 100644 --- a/test/shared_test/lib_battery_properties.h +++ b/test/shared_test/lib_battery_properties.h @@ -81,7 +81,7 @@ class BatteryProperties : public ::testing::Test double vals2[] = { 0, 100, 3650, 80, 7300, 50 }; calendarLifeMatrix.assign(vals2, 3, 2); - calendarChoice = lifetime_params::CALENDAR_CHOICE::MODEL; + calendarChoice = calendar_cycle_params::CALENDAR_CHOICE::MODEL; // thermal mass = 507; diff --git a/test/shared_test/lib_battery_test.cpp b/test/shared_test/lib_battery_test.cpp index a163bb799f3..23d29df03b4 100644 --- a/test/shared_test/lib_battery_test.cpp +++ b/test/shared_test/lib_battery_test.cpp @@ -205,7 +205,6 @@ TEST_F(lib_battery_test, SetUpTest){ ASSERT_TRUE(1); } -/* TEST_F(lib_battery_test, runTestCycleAt1C){ size_t idx = 0; double capacity_passed = 0.; @@ -214,12 +213,14 @@ TEST_F(lib_battery_test, runTestCycleAt1C){ capacity_passed += batteryModel->I() * batteryModel->V() / 1000.; // std::cerr << "\n" << idx << ": " << capacity_passed << "\n"; - auto s = battery_state_test({{479.75, 1000, 960.01, 20.25, 0, 49.97, 52.09, 2}, // cap - 550.65, // voltage - 100, {100, 0, 0, 0, 0, 0, 1, std::vector()}, // cycle - {102, 0, 0}, // calendar - {96.00, 20.00, 20}, // thermal - 0}); + auto s = battery_state_test(); + s.capacity = {479.75, 1000, 960.01, 20.25, 0, 49.97, 52.09, 2}; + s.batt_voltage = 550.65; + s.lifetime.calendar->q_relative_calendar = 102; + s.lifetime.cycle->q_relative_cycle = 100; + s.lifetime.cycle->rainflow_jlt = 1; + s.lifetime.q_relative = 100; + s.thermal = {96.00, 20.00, 20}; compareState(batteryModel, s, "runTestCycleAt1C: 1"); while (batteryModel->SOC() > SOC_min + 1){ @@ -228,12 +229,13 @@ TEST_F(lib_battery_test, runTestCycleAt1C){ } // std::cerr << idx << ": soc " << batteryModel->SOC() << ", cap " << capacity_passed << "\n"; // the SOC isn't at 5 so it means the controller is not able to calculate a current/voltage at which to discharge to 5 - s = battery_state_test({{54.5, 1000, 960.01, 20.25, 0, 5.67, 7.79, 2}, // cap - 366.96, // voltage - 100, {100, 0, 0, 0, 0, 0, 1, std::vector()}, // cycle - {101.976, 0, 0.0002}, // calendar - {96.01, 20.01, 20}, // thermal - 0}); + s.capacity = {54.5, 1000, 960.01, 20.25, 0, 5.67, 7.79, 2}; + s.batt_voltage = 366.96; + s.lifetime.q_relative = 100; + s.lifetime.cycle->q_relative_cycle = 100; + s.lifetime.calendar->q_relative_calendar = 101.976; + s.lifetime.calendar->dq_relative_calendar_old = 0.0002; + s.thermal = {96.01, 20.01, 20}; compareState(batteryModel, s, "runTestCycleAt1C: 2"); size_t n_cycles = 400; @@ -252,12 +254,22 @@ TEST_F(lib_battery_test, runTestCycleAt1C){ } // std::cerr << idx << ": soc " << batteryModel->SOC() << ", cap " << capacity_passed << "\n"; // the SOC isn't at 5 so it means the controller is not able to calculate a current/voltage at which to discharge to 5 - s = battery_state_test({{50.64, 920.75, 883.93, 8.917, 0, 5.73, 6.74, 2}, // cap - 368.90, // voltage - 93.08, {92.07, 397, 88.74, 88.72, 88.79, 89.30, 7, std::vector()}, // cycle - {98.0, 2739, 0.039}, // calendar - {96.0, 20.00, 20}, // thermal - 32991}); + s.capacity = {50.64, 920.75, 883.93, 8.917, 0, 5.73, 6.74, 2}; + s.batt_voltage = 368.90; + s.lifetime.q_relative = 93.08; + s.lifetime.cycle->q_relative_cycle = 92.07; + s.lifetime.n_cycles = 397; + s.lifetime.range = 88.74; + s.lifetime.average_range = 88.72; + s.lifetime.cycle->rainflow_Xlt = 88.79; + s.lifetime.cycle->rainflow_Ylt = 89.30; + s.lifetime.cycle->rainflow_jlt = 7; + s.lifetime.day_age_of_battery = 2739; + s.lifetime.calendar->q_relative_calendar = 98.0; + s.lifetime.calendar->dq_relative_calendar_old = 0.039; + s.thermal = {96.0, 20.00, 20}; + s.last_idx = 32991; + compareState(batteryModel, s, "runTestCycleAt1C: 3"); EXPECT_NEAR(capacity_passed, 352736, 1000) << "Current passing through cell"; @@ -265,7 +277,6 @@ TEST_F(lib_battery_test, runTestCycleAt1C){ EXPECT_NEAR(qmax/q, .93, 0.01) << "capacity relative to max capacity"; } - TEST_F(lib_battery_test, runTestCycleAt3C){ size_t idx = 0; double capacity_passed = 0.; @@ -274,12 +285,15 @@ TEST_F(lib_battery_test, runTestCycleAt3C){ capacity_passed += batteryModel->I() * batteryModel->V() / 1000.; // std::cerr << "\n" << idx << ": " << capacity_passed << "\n"; - auto s = battery_state_test({{439.25, 1000, 960.02, 60.75, 0, 45.75, 52.08, 2}, // cap - 548.35, // voltage - 100, {100, 0, 0, 0, 0, 0, 1, std::vector()}, // cycle - {102, 0}, // calendar - {96.01, 20.01, 20}, // thermal - 0}); + auto s = battery_state_test(); + s.capacity = {439.25, 1000, 960.02, 60.75, 0, 45.75, 52.08, 2}; + s.batt_voltage = 548.35; + s.lifetime.q_relative = 100; + s.lifetime.cycle->q_relative_cycle = 100; + s.lifetime.cycle->rainflow_jlt = 1; + s.lifetime.calendar->q_relative_calendar = 102; + s.thermal = {96.01, 20.01, 20}; + s.last_idx = 0; compareState(batteryModel, s, "runTest: 1"); while (batteryModel->SOC() > SOC_min + 1){ @@ -288,12 +302,11 @@ TEST_F(lib_battery_test, runTestCycleAt3C){ } // std::cerr << idx << ": soc " << batteryModel->SOC() << ", cap " << capacity_passed << "\n"; // the SOC isn't at 5 so it means the controller is not able to calculate a current/voltage at which to discharge to 5 - s = battery_state_test({{48.01, 1000, 960.11, 26.74, 0, 5.00, 7.78, 2}, // cap - 338.91, // voltage - 101.98, {100, 0, 0, 0, 0, 0, 1, std::vector()}, // cycle - {101.98, 0}, // calendar - {96.01, 20.01, 20}, // thermal - 0}); + s.capacity = {48.01, 1000, 960.11, 26.74, 0, 5.00, 7.78, 2}; + s.batt_voltage = 338.91; + s.lifetime.q_relative = 101.98; + s.lifetime.calendar->q_relative_calendar = 101.98; + s.last_idx = 0; compareState(batteryModel, s, "runTest: 2"); size_t n_cycles = 400; @@ -312,20 +325,28 @@ TEST_F(lib_battery_test, runTestCycleAt3C){ } // std::cerr << idx << ": soc " << batteryModel->SOC() << ", cap " << capacity_passed << "\n"; // the SOC isn't at 5 so it means the controller is not able to calculate a current/voltage at which to discharge to 5 - s = battery_state_test({{49.06, 920.77, 883.94, 8.89, 0, 5.55, 6.55, 2}, // cap - 362.25, // voltage - 93.08, {92.08, 397, 88.51, 89.14, 88.53, 89.45, 7, std::vector()}, // cycle - {98.11, 2613, 0.0393}, // calendar - {96.01, 20, 20}, // thermal - 32991}); + s.capacity = {49.06, 920.77, 883.94, 8.89, 0, 5.55, 6.55, 2}; + s.batt_voltage = 362.25; + s.lifetime.q_relative = 93.08; + s.lifetime.day_age_of_battery = 2613; + s.lifetime.cycle->q_relative_cycle = 92.08; + s.lifetime.n_cycles = 397; + s.lifetime.range = 88.51; + s.lifetime.average_range = 89.14; + s.lifetime.cycle->rainflow_Xlt = 88.53; + s.lifetime.cycle->rainflow_Ylt = 89.45; + s.lifetime.cycle->rainflow_jlt = 7; + s.lifetime.cycle->q_relative_cycle = 92.08; + s.lifetime.calendar->q_relative_calendar = 98.11; + s.lifetime.calendar->dq_relative_calendar_old = 0.0393; + s.thermal = {96.01, 20, 20}; + s.last_idx = 32991; compareState(batteryModel, s, "runTest: 3"); - EXPECT_NEAR(capacity_passed, 353328, 100) << "Current passing through cell"; double qmax = fmax(s.capacity.qmax_lifetime, s.capacity.qmax_thermal); EXPECT_NEAR(qmax/q, 0.9209, 0.01) << "capacity relative to max capacity"; } -*/ TEST_F(lib_battery_test, runDuplicates) { // get initial state @@ -358,10 +379,12 @@ TEST_F(lib_battery_test, createFromParams) { double current = 10; double P_orig = batteryModel->run(0, current); - current = 10; + double P_new = bat.run(0, current); EXPECT_EQ(P_orig, P_new); + EXPECT_EQ(batteryModel->I(), bat.I()); + EXPECT_EQ(batteryModel->charge_maximum(), bat.charge_maximum()); } TEST_F(lib_battery_test,logging) { @@ -573,6 +596,88 @@ TEST_F(lib_battery_test, HourlyVsSubHourly) } } +TEST_F(lib_battery_test, AdaptiveTimestep) { + size_t steps_per_hour = 4; + auto batt_subhourly = new battery_t(*batteryModel); + batt_subhourly->ChangeTimestep(1. / (double)steps_per_hour); + auto batt_adaptive = new battery_t(*batt_subhourly); + + EXPECT_EQ(batt_adaptive->charge_total(), batteryModel->charge_total()); + EXPECT_EQ(batt_adaptive->charge_maximum(), batteryModel->charge_maximum()); + EXPECT_EQ(batt_adaptive->V(), batteryModel->V()); + EXPECT_EQ(batt_adaptive->I(), batteryModel->I()); + + double kw_hourly = 100.; + size_t count = 0; + while (count < 2000){ + double hourly_E = 0; + double subhourly_E = 0; + double adaptive_E = 0; + while (batteryModel->SOC() > 15) { + // run hourly + batteryModel->runPower(kw_hourly); + hourly_E += batteryModel->get_state().P; + + // run subhourly + for (size_t i = 0; i < steps_per_hour; i++) { + batt_subhourly->runPower(kw_hourly); + subhourly_E += batt_subhourly->get_state().P / (double)steps_per_hour; + } + + // run adaptive + if (count % 2 == 0) { + batt_adaptive->ChangeTimestep(1); + batt_adaptive->runPower(kw_hourly); + adaptive_E += batt_adaptive->get_state().P; + } + else { + batt_adaptive->ChangeTimestep(1. / (double)steps_per_hour); + for (size_t i = 0; i < steps_per_hour; i++) { + batt_adaptive->runPower(kw_hourly); + adaptive_E += batt_adaptive->get_state().P / (double)steps_per_hour; + } + } + } + while (batteryModel->SOC() < 85) { + batteryModel->runPower(-kw_hourly); + hourly_E -= batteryModel->get_state().P; + + for (size_t i = 0; i < steps_per_hour; i++) { + batt_subhourly->runPower(-kw_hourly); + subhourly_E -= batt_subhourly->get_state().P / (double)steps_per_hour; + } + if (count % 2 == 0) { + batt_adaptive->ChangeTimestep(1); + batt_adaptive->runPower(-kw_hourly); + adaptive_E -= batt_adaptive->get_state().P; + } + else { + batt_adaptive->ChangeTimestep(1. / (double)steps_per_hour); + for (size_t i = 0; i < steps_per_hour; i++) { + batt_adaptive->runPower(-kw_hourly); + adaptive_E -= batt_adaptive->get_state().P / (double)steps_per_hour; + } + } + } + count++; + + // max energy throughput error is about 10% from hourly runs and 15% from 15 min runs + EXPECT_NEAR(hourly_E, adaptive_E, hourly_E * 0.10) << "At count " << count; + EXPECT_NEAR(subhourly_E, adaptive_E, subhourly_E * 0.15) << "At count " << count; + + // max lifetime degradation error is about 15, out of charge max of ~600 -> 20 / 600 = 3.3 % error + EXPECT_NEAR(batteryModel->charge_maximum(), batt_adaptive->charge_maximum(), 20) << "At count " << count; + EXPECT_NEAR(batt_subhourly->charge_maximum(), batt_adaptive->charge_maximum(), 20) << "At count " << count; + } + EXPECT_NEAR(batteryModel->charge_maximum(), 577.09, 1e-2); + EXPECT_NEAR(batt_subhourly->charge_maximum(), 582.22, 1e-2); + EXPECT_NEAR(batt_adaptive->charge_maximum(), 577.27, 1e-2); + + EXPECT_NEAR(batteryModel->SOC(), 94.97, 1e-2); + EXPECT_NEAR(batt_subhourly->SOC(), 88.14, 1e-2); + EXPECT_NEAR(batt_adaptive->SOC(), 88.67, 1e-2); +} + TEST_F(lib_battery_test, AugmentCapacity) { std::vector augmentation_percent = {50, 40, 30}; batteryModel->setupReplacements(augmentation_percent); diff --git a/test/shared_test/lib_battery_test.h b/test/shared_test/lib_battery_test.h index b8e2e5a5bed..ec4bc08bf2f 100644 --- a/test/shared_test/lib_battery_test.h +++ b/test/shared_test/lib_battery_test.h @@ -109,9 +109,7 @@ class lib_battery_losses_test : public ::testing::Test struct battery_state_test{ capacity_state capacity; double batt_voltage; - double q_lifetime; - cycle_state cycle; - calendar_state cal; + lifetime_state lifetime; thermal_state thermal; size_t last_idx; @@ -125,18 +123,20 @@ static void compareState(std::unique_ptr&model, const battery_state_t double tol = 0.01; auto lifetime_tested = tested_state.lifetime; - auto cal_expected = expected_state.cal; - EXPECT_NEAR(lifetime_tested->calendar->day_age_of_battery, cal_expected.day_age_of_battery, tol) << msg; + auto lifetime_expected = expected_state.lifetime; + EXPECT_NEAR(lifetime_tested->day_age_of_battery, lifetime_expected.day_age_of_battery, tol) << msg; + EXPECT_NEAR(lifetime_tested->range, lifetime_expected.range, tol) << msg; + EXPECT_NEAR(lifetime_tested->average_range, lifetime_expected.average_range, tol) << msg; + EXPECT_NEAR(lifetime_tested->n_cycles, lifetime_expected.n_cycles, tol) << msg; + + auto cal_expected = *lifetime_expected.calendar; EXPECT_NEAR(lifetime_tested->calendar->q_relative_calendar, cal_expected.q_relative_calendar, tol) << msg; EXPECT_NEAR(lifetime_tested->calendar->dq_relative_calendar_old, cal_expected.dq_relative_calendar_old, tol) << msg; - auto cyc_expected = expected_state.cycle; + auto cyc_expected = *lifetime_expected.cycle; EXPECT_NEAR(lifetime_tested->cycle->q_relative_cycle, cyc_expected.q_relative_cycle, tol) << msg; EXPECT_NEAR(lifetime_tested->cycle->rainflow_Xlt, cyc_expected.rainflow_Xlt, tol) << msg; EXPECT_NEAR(lifetime_tested->cycle->rainflow_Ylt, cyc_expected.rainflow_Ylt, tol) << msg; - EXPECT_NEAR(lifetime_tested->cycle->range, cyc_expected.range, tol) << msg; - EXPECT_NEAR(lifetime_tested->cycle->average_range, cyc_expected.average_range, tol) << msg; - EXPECT_NEAR(lifetime_tested->cycle->n_cycles, cyc_expected.n_cycles, tol) << msg; EXPECT_NEAR(lifetime_tested->cycle->rainflow_jlt, cyc_expected.rainflow_jlt, tol) << msg; compareState(*tested_state.thermal, expected_state.thermal, msg); @@ -197,7 +197,7 @@ class lib_battery_test : public ::testing::Test capacity_lithium_ion_t * capacityModel; voltage_t * voltageModel; thermal_t * thermalModel; - lifetime_t * lifetimeModel; + lifetime_calendar_cycle_t * lifetimeModel; losses_t * lossModel; std::unique_ptr batteryModel; @@ -259,13 +259,13 @@ class lib_battery_test : public ::testing::Test capacityModel = new capacity_lithium_ion_t(q, SOC_init, SOC_max, SOC_min, dtHour); voltageModel = new voltage_dynamic_t(n_series, n_strings, Vnom_default, Vfull, Vexp, Vnom, Qfull, Qexp, Qnom, C_rate, resistance, dtHour); - lifetimeModel = new lifetime_t(cycleLifeMatrix, dtHour, 1.02, 2.66e-3, -7280, 930); + lifetimeModel = new lifetime_calendar_cycle_t(cycleLifeMatrix, dtHour, 1.02, 2.66e-3, -7280, 930); thermalModel = new thermal_t(1.0, mass, surface_area, resistance, Cp, h, capacityVsTemperature, T_room); lossModel = new losses_t(monthlyLosses, monthlyLosses, monthlyLosses); batteryModel = std::unique_ptr(new battery_t(dtHour, chemistry, capacityModel, voltageModel, lifetimeModel, thermalModel, lossModel)); } - void TearDown(){ + void TearDown() override { // batteryModel takes ownership of component models } diff --git a/test/ssc_test/cmod_battery_pvsamv1_test.cpp b/test/ssc_test/cmod_battery_pvsamv1_test.cpp index 5469811a25c..fd88098f684 100644 --- a/test/ssc_test/cmod_battery_pvsamv1_test.cpp +++ b/test/ssc_test/cmod_battery_pvsamv1_test.cpp @@ -779,7 +779,7 @@ TEST_F(CMPvsamv1BatteryIntegration_cmod_pvsamv1, ResidentialDCBatteryModelPriceS ssc_number_t peakKwCharge = -3.914; ssc_number_t peakKwDischarge = 1.99; ssc_number_t peakCycles = 2; - ssc_number_t avgCycles = 0.4136; + ssc_number_t avgCycles = 0.41; pairs["batt_dispatch_choice"] = 5; @@ -805,7 +805,11 @@ TEST_F(CMPvsamv1BatteryIntegration_cmod_pvsamv1, ResidentialDCBatteryModelPriceS EXPECT_NEAR(batt_stats.peakKwCharge, peakKwCharge, m_error_tolerance_lo); EXPECT_NEAR(batt_stats.peakKwDischarge, peakKwDischarge, m_error_tolerance_lo); EXPECT_NEAR(batt_stats.peakCycles, peakCycles, m_error_tolerance_lo); - EXPECT_NEAR(batt_stats.avgCycles, avgCycles, 0.01); // As of 8-26-20 Linux cycles 2 more times in a year than Windows, this changes the NPV by $2 over 25 years - } + EXPECT_NEAR(batt_stats.avgCycles, avgCycles, 0.1); // As of 8-26-20 Linux cycles 2 more times in a year than Windows, this changes the NPV by $2 over 25 years + auto batt_q_rel = data_vtab->as_vector_ssc_number_t("batt_capacity_percent"); + auto batt_cyc_avg = data_vtab->as_vector_ssc_number_t("batt_DOD_cycle_average"); + EXPECT_NEAR(batt_q_rel.back(), 97.836, 1e-2); + EXPECT_NEAR(batt_cyc_avg.back(), 22.62, 0.5); + } } diff --git a/test/ssc_test/cmod_battery_stateful_test.cpp b/test/ssc_test/cmod_battery_stateful_test.cpp index 725247703c8..14c6086c83e 100644 --- a/test/ssc_test/cmod_battery_stateful_test.cpp +++ b/test/ssc_test/cmod_battery_stateful_test.cpp @@ -6,18 +6,28 @@ typedef std::chrono::high_resolution_clock Clock; TEST_F(CMBatteryStatefulIntegration_cmod_battery_stateful, TestStep) { CreateModel(1); - double last_idx, current, SOC, V, P; + double last_idx, I, SOC, V, P, Q, I_d, I_c, P_d, P_c; ssc_module_exec(mod, data); ssc_data_get_number(data, "last_idx", &last_idx); - ssc_data_get_number(data, "I", ¤t); - ssc_data_get_number(data, "P", &P); ssc_data_get_number(data, "V", &V); + ssc_data_get_number(data, "P", &P); + ssc_data_get_number(data, "Q", &Q); + ssc_data_get_number(data, "I", &I); + ssc_data_get_number(data, "I_dischargeable", &I_d); + ssc_data_get_number(data, "I_chargeable", &I_c); + ssc_data_get_number(data, "P_dischargeable", &P_d); + ssc_data_get_number(data, "P_chargeable", &P_c); ssc_data_get_number(data, "SOC", &SOC); EXPECT_EQ(last_idx, 1); - EXPECT_NEAR(current, 1, 1e-2); - EXPECT_NEAR(P, 0.549, 1e-2); EXPECT_NEAR(V, 549.18, 1e-2); + EXPECT_NEAR(P, 0.549, 1e-2); + EXPECT_NEAR(Q, 9.125, 1e-2); + EXPECT_NEAR(I, 1, 1e-2); + EXPECT_NEAR(I_d, 7.30, 1e-2); + EXPECT_NEAR(I_c, -9.34, 1e-2); + EXPECT_NEAR(P_d, 3.36, 1e-2); + EXPECT_NEAR(P_c, -5.32, 1e-2); EXPECT_NEAR(SOC, 46.94, 1e-2); // make a copy @@ -26,27 +36,47 @@ TEST_F(CMBatteryStatefulIntegration_cmod_battery_stateful, TestStep) { ssc_module_exec(mod, data); ssc_data_get_number(data, "last_idx", &last_idx); - ssc_data_get_number(data, "I", ¤t); - ssc_data_get_number(data, "P", &P); ssc_data_get_number(data, "V", &V); + ssc_data_get_number(data, "P", &P); + ssc_data_get_number(data, "Q", &Q); + ssc_data_get_number(data, "I", &I); + ssc_data_get_number(data, "I_dischargeable", &I_d); + ssc_data_get_number(data, "I_chargeable", &I_c); + ssc_data_get_number(data, "P_dischargeable", &P_d); + ssc_data_get_number(data, "P_chargeable", &P_c); ssc_data_get_number(data, "SOC", &SOC); EXPECT_EQ(last_idx, 2); - EXPECT_NEAR(current, 1, 1e-2); - EXPECT_NEAR(P, 0.546, 1e-2); EXPECT_NEAR(V, 546.09, 1e-2); + EXPECT_NEAR(P, 0.546, 1e-2); + EXPECT_NEAR(Q, 8.125, 1e-2); + EXPECT_NEAR(I, 1, 1e-2); + EXPECT_NEAR(I_d, 6.5, 1e-2); + EXPECT_NEAR(I_c, -10.34, 1e-2); + EXPECT_NEAR(P_d, 2.90, 1e-2); + EXPECT_NEAR(P_c, -5.89, 1e-2); EXPECT_NEAR(SOC, 41.79, 1e-2); // run the copy, should end up in same place ssc_module_exec(mod, copy); - ssc_data_get_number(data, "last_idx", &last_idx); - ssc_data_get_number(data, "I", ¤t); - ssc_data_get_number(data, "P", &P); - ssc_data_get_number(data, "V", &V); - ssc_data_get_number(data, "SOC", &SOC); + ssc_data_get_number(copy, "last_idx", &last_idx); + ssc_data_get_number(copy, "V", &V); + ssc_data_get_number(copy, "P", &P); + ssc_data_get_number(copy, "Q", &Q); + ssc_data_get_number(copy, "I", &I); + ssc_data_get_number(copy, "I_dischargeable", &I_d); + ssc_data_get_number(copy, "I_chargeable", &I_c); + ssc_data_get_number(copy, "P_dischargeable", &P_d); + ssc_data_get_number(copy, "P_chargeable", &P_c); + ssc_data_get_number(copy, "SOC", &SOC); EXPECT_EQ(last_idx, 2); - EXPECT_NEAR(current, 1, 1e-2); - EXPECT_NEAR(P, 0.546, 1e-2); EXPECT_NEAR(V, 546.09, 1e-2); + EXPECT_NEAR(P, 0.546, 1e-2); + EXPECT_NEAR(Q, 8.125, 1e-2); + EXPECT_NEAR(I, 1, 1e-2); + EXPECT_NEAR(I_d, 6.5, 1e-2); + EXPECT_NEAR(I_c, -10.34, 1e-2); + EXPECT_NEAR(P_d, 2.90, 1e-2); + EXPECT_NEAR(P_c, -5.89, 1e-2); EXPECT_NEAR(SOC, 41.79, 1e-2); } @@ -98,7 +128,7 @@ TEST_F(CMBatteryStatefulIntegration_cmod_battery_stateful, SubMinute) { TEST_F(CMBatteryStatefulIntegration_cmod_battery_stateful, ReadJson) { CreateModel(1./60.); - std::string js = "{\"control_mode\": 1.0, \"dt_hr\": 0.016666666666666666, \"input_power\": -1608.9696000000001, \"run_sequentially\": 1.0, \"C_rate\": 0.2, \"Qexp\": 0.04, \"Qfull\": 2.25, \"Qnom\": 2.0, \"Vexp\": 4.05, \"Vfull\": 4.1, \"Vnom\": 3.4, \"Vnom_default\": 3.6, \"calendar_a\": 0.003, \"calendar_b\": -7280.0, \"calendar_c\": 930.0, \"calendar_choice\": 1.0, \"calendar_matrix\": [[-3.1e+231]], \"calendar_q0\": 1.02, \"chem\": 1.0, \"cycling_matrix\": [[20.0, 0.0, 100.0], [20.0, 5000.0, 80.0], [20.0, 10000.0, 60.0], [80.0, 0.0, 100.0], [80.0, 1000.0, 80.0], [80.0, 2000.0, 60.0]], \"initial_SOC\": 50.0, \"maximum_SOC\": 90.0, \"minimum_SOC\": 10.0, \"resistance\": 0.0002, \"voltage_choice\": 0.0, \"Cp\": 1500.0, \"T_room_init\": 20.0, \"cap_vs_temp\": [[-10.0, 60.0], [0.0, 80.0], [25.0, 100.0], [40.0, 100.0]], \"h\": 7.5, \"loss_choice\": 0.0, \"mass\": 98980.0, \"monthly_charge_loss\": [0.0], \"monthly_discharge_loss\": [0.0], \"monthly_idle_loss\": [0.0], \"nominal_energy\": 10000.0, \"nominal_voltage\": 500.0, \"replacement_capacity\": 0.0, \"replacement_option\": 0.0, \"replacement_schedule\": [-1.4916681462400413e-154], \"replacement_schedule_percent\": [-1.4916681462400413e-154], \"schedule_loss\": [0.0], \"surface_area\": 2071.0, \"I\": 0.0, \"I_chargeable\": -939699.5036648216, \"I_dischargeable\": 0.0, \"P\": 0.0, \"P_chargeable\": -538310.3372051578, \"P_dischargeable\": 0.0, \"Q\": 1957.713280026735, \"Q_max\": 19577.07963826714, \"SOC\": 10.000027155224982, \"T_batt\": 54.667972372468775, \"T_room\": 16.5319492435796, \"V\": 0.0, \"heat_dissipated\": 592184.2210545398, \"indices_replaced\": [0.0], \"last_idx\": 1261.0, \"loss_kw\": 0.0, \"n_replacements\": 0.0, \"I_loss\": 0.0, \"SOC_prev\": 10.000026847325115, \"T_batt_prev\": 54.54844020525578, \"average_range\": 0.0, \"cell_current\": 0.0, \"cell_voltage\": 0.0, \"chargeChange\": 0.0, \"charge_mode\": 1.0, \"n_cycles\": 0.0, \"prev_charge\": 2.0, \"q0\": 1957.713280026735, \"q1_0\": 0.0, \"q2\": 0.0, \"q2_0\": 0.0, \"q_relative\": 97.96131821295074, \"q_relative_calendar\": 97.96131821295074, \"q_relative_cycle\": 100.0, \"q_relative_thermal\": 100.0, \"qmax_lifetime\": 19577.07963826714, \"qmax_thermal\": 19577.13280026734, \"qn\": 0.0, \"rainflow_Xlt\": 0.0, \"rainflow_Ylt\": 0.040386817870492635, \"rainflow_jlt\": 2.0, \"rainflow_peaks\": [0.0, 47.9929307855364, 10.000000000000014], \"range\": 0.0, \"day_age_of_battery\" : 3, \"dq_relative_calendar_old\" : 0.001}"; + std::string js = "{\"control_mode\": 1.0, \"dt_hr\": 0.016666666666666666, \"input_power\": -1608.9696000000001, \"run_sequentially\": 1.0, \"C_rate\": 0.2, \"Qexp\": 0.04, \"Qfull\": 2.25, \"Qnom\": 2.0, \"Vexp\": 4.05, \"Vfull\": 4.1, \"Vnom\": 3.4, \"Vnom_default\": 3.6, \"life_model\": 0, \"calendar_a\": 0.003, \"calendar_b\": -7280.0, \"calendar_c\": 930.0, \"calendar_choice\": 1.0, \"calendar_matrix\": [[-3.1e+231]], \"calendar_q0\": 1.02, \"chem\": 1.0, \"cycling_matrix\": [[20.0, 0.0, 100.0], [20.0, 5000.0, 80.0], [20.0, 10000.0, 60.0], [80.0, 0.0, 100.0], [80.0, 1000.0, 80.0], [80.0, 2000.0, 60.0]], \"initial_SOC\": 50.0, \"maximum_SOC\": 90.0, \"minimum_SOC\": 10.0, \"resistance\": 0.0002, \"voltage_choice\": 0.0, \"Cp\": 1500.0, \"T_room_init\": 20.0, \"cap_vs_temp\": [[-10.0, 60.0], [0.0, 80.0], [25.0, 100.0], [40.0, 100.0]], \"h\": 7.5, \"loss_choice\": 0.0, \"mass\": 98980.0, \"monthly_charge_loss\": [0.0], \"monthly_discharge_loss\": [0.0], \"monthly_idle_loss\": [0.0], \"nominal_energy\": 10000.0, \"nominal_voltage\": 500.0, \"replacement_capacity\": 0.0, \"replacement_option\": 0.0, \"replacement_schedule\": [-1.4916681462400413e-154], \"replacement_schedule_percent\": [-1.4916681462400413e-154], \"schedule_loss\": [0.0], \"surface_area\": 2071.0, \"I\": 0.0, \"I_chargeable\": -939699.5036648216, \"I_dischargeable\": 0.0, \"P\": 0.0, \"P_chargeable\": -538310.3372051578, \"P_dischargeable\": 0.0, \"Q\": 1957.713280026735, \"Q_max\": 19577.07963826714, \"SOC\": 10.000027155224982, \"T_batt\": 54.667972372468775, \"T_room\": 16.5319492435796, \"V\": 0.0, \"heat_dissipated\": 592184.2210545398, \"indices_replaced\": [0.0], \"last_idx\": 1261.0, \"loss_kw\": 0.0, \"n_replacements\": 0.0, \"I_loss\": 0.0, \"SOC_prev\": 10.000026847325115, \"T_batt_prev\": 54.54844020525578, \"average_range\": 0.0, \"cell_current\": 0.0, \"cell_voltage\": 0.0, \"chargeChange\": 0.0, \"charge_mode\": 1.0, \"n_cycles\": 0.0, \"prev_charge\": 2.0, \"q0\": 1957.713280026735, \"q1_0\": 0.0, \"q2\": 0.0, \"q2_0\": 0.0, \"q_relative\": 97.96131821295074, \"q_relative_calendar\": 97.96131821295074, \"q_relative_cycle\": 100.0, \"q_relative_thermal\": 100.0, \"qmax_lifetime\": 19577.07963826714, \"qmax_thermal\": 19577.13280026734, \"qn\": 0.0, \"rainflow_Xlt\": 0.0, \"rainflow_Ylt\": 0.040386817870492635, \"rainflow_jlt\": 2.0, \"rainflow_peaks\": [0.0, 47.9929307855364, 10.000000000000014], \"range\": 0.0, \"day_age_of_battery\" : 3, \"dq_relative_calendar_old\" : 0.001}"; auto copy = json_to_ssc_data(js.c_str()); double P, V, SOC; @@ -117,7 +147,7 @@ TEST_F(CMBatteryStatefulIntegration_cmod_battery_stateful, ReadJson) { TEST_F(CMBatteryStatefulIntegration_cmod_battery_stateful, RunCurrentControl) { CreateKokamModel(); - double range, avg_range, n_cycles; + double range, avg_range, n_cycles, q_max, q_rel; std::vector currents = getCurrentData(); @@ -130,11 +160,75 @@ TEST_F(CMBatteryStatefulIntegration_cmod_battery_stateful, RunCurrentControl) { ssc_module_exec(mod, data); } + ssc_data_get_number(data, "range", &range); ssc_data_get_number(data, "average_range", &avg_range); ssc_data_get_number(data, "n_cycles", &n_cycles); + ssc_data_get_number(data, "Q_max", &q_max); + ssc_data_get_number(data, "q_relative", &q_rel); + + + EXPECT_NEAR(range, 75.34, 0.01); + EXPECT_NEAR(avg_range, 61.54, 0.01); + EXPECT_NEAR(n_cycles, 3.0, 0.01); + EXPECT_NEAR(q_max, 75.55, 0.01); + EXPECT_NEAR(q_rel, 99.99, 0.01); +} + +TEST_F(CMBatteryStatefulIntegration_cmod_battery_stateful, AdaptiveTimestep) { + CreateModel(1.); + + double power = 1; + ssc_data_set_number(data, "control_mode", 1); + ssc_data_set_number(data, "input_power", power); + + // create adaptive + var_table data_copy; + data_copy = *static_cast(data); + ssc_data_set_number(&data_copy, "input_power", power); + auto adaptive_batt = ssc_stateful_module_create("battery_stateful", &data_copy); + + double P, hourly_E = 0, adaptive_E = 0; + + // run both at hourly + ssc_module_exec(mod, data); + ssc_data_get_number(data, "P", &P); + hourly_E += P; + + ssc_module_exec(adaptive_batt, &data_copy); + ssc_data_get_number(&data_copy, "P", &P); + adaptive_E += P; + + // run at hourly and adaptive at 15 min + ssc_module_exec(mod, data); + ssc_data_get_number(data, "P", &P); + hourly_E += P; + + size_t steps_per_hour = 4; + ssc_data_set_number(&data_copy, "dt_hr", 1. / (double)steps_per_hour); + for (size_t i = 0; i < steps_per_hour; i++) { + ssc_module_exec(adaptive_batt, &data_copy); + ssc_data_get_number(&data_copy, "P", &P); + adaptive_E += P / (double)steps_per_hour; + } + + // run both at hourly + ssc_module_exec(mod, data); + ssc_data_get_number(data, "P", &P); + hourly_E += P; + + ssc_data_set_number(&data_copy, "dt_hr", 1.); + ssc_module_exec(adaptive_batt, &data_copy); + ssc_data_get_number(&data_copy, "P", &P); + adaptive_E += P; + + double hourly_SOC, adaptive_SOC; + ssc_data_get_number(data, "SOC", &hourly_SOC); + ssc_data_get_number(&data_copy, "SOC", &adaptive_SOC); + + EXPECT_NEAR(hourly_E, 2.994, 1e-3); + EXPECT_NEAR(adaptive_E, 2.994, 1e-3); + EXPECT_NEAR(hourly_SOC, 23.370, 1e-3); + EXPECT_NEAR(adaptive_SOC, 23.428, 1e-3); - EXPECT_NEAR(range, 75.0, 0.5); - EXPECT_NEAR(avg_range, 61.5, 0.1); - EXPECT_NEAR(n_cycles, 3.0, 0.1); } diff --git a/test/ssc_test/cmod_battery_stateful_test.h b/test/ssc_test/cmod_battery_stateful_test.h index 3e2cf640214..dd216be7807 100644 --- a/test/ssc_test/cmod_battery_stateful_test.h +++ b/test/ssc_test/cmod_battery_stateful_test.h @@ -17,7 +17,7 @@ class CMBatteryStatefulIntegration_cmod_battery_stateful : public ::testing::Tes double m_error_tolerance_lo = 0.1; void CreateModel(double dt_hour = 1.) { - params_str = R"({ "control_mode": 0, "input_current": 1, "chem": 1, "nominal_energy": 10, "nominal_voltage": 500, "qmax_init": 1000.000, "initial_SOC": 50.000, "maximum_SOC": 95.000, "minimum_SOC": 5.000, "dt_hr": 1.000, "leadacid_tn": 0.000, "leadacid_qn": 0.000, "leadacid_q10": 0.000, "leadacid_q20": 0.000, "voltage_choice": 0, "Vnom_default": 3.600, "resistance": 0.000, "Vfull": 4.100, "Vexp": 4.050, "Vnom": 3.400, "Qfull": 2.250, "Qexp": 0.040, "Qnom": 2.000, "C_rate": 0.200, "mass": 507.000, "surface_area": 2.018, "Cp": 1004.000, "h": 20.000, "cap_vs_temp": [ [ -10, 60 ], [ 0, 80 ], [ 25, 1E+2 ], [ 40, 1E+2 ] ], "option": 1, "T_room_init": 20, "cycling_matrix": [ [ 20, 0, 1E+2 ], [ 20, 5E+3, 80 ], [ 20, 1E+4, 60 ], [ 80, 0, 1E+2 ], [ 80, 1E+3, 80 ], [ 80, 2E+3, 60 ] ], "calendar_choice": 1, "calendar_q0": 1.020, "calendar_a": 0.003, "calendar_b": -7280.000, "calendar_c": 930.000, "calendar_matrix": [ [ -3.1E+231 ] ], "loss_choice": 0, "monthly_charge_loss": [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ], "monthly_discharge_loss": [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ], "monthly_idle_loss": [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ], "schedule_loss": [], "replacement_option": 0, "replacement_capacity": 0.000, "replacement_schedule": [], "replacement_schedule_percent": [], "analysis_period": 1, "load_escalation": [0]})"; + params_str = R"({ "control_mode": 0, "input_current": 1, "chem": 1, "nominal_energy": 10, "nominal_voltage": 500, "qmax_init": 1000.000, "initial_SOC": 50.000, "maximum_SOC": 95.000, "minimum_SOC": 5.000, "dt_hr": 1.000, "leadacid_tn": 0.000, "leadacid_qn": 0.000, "leadacid_q10": 0.000, "leadacid_q20": 0.000, "voltage_choice": 0, "Vnom_default": 3.600, "resistance": 0.000, "Vfull": 4.100, "Vexp": 4.050, "Vnom": 3.400, "Qfull": 2.250, "Qexp": 0.040, "Qnom": 2.000, "C_rate": 0.200, "mass": 507.000, "surface_area": 2.018, "Cp": 1004.000, "h": 20.000, "cap_vs_temp": [ [ -10, 60 ], [ 0, 80 ], [ 25, 1E+2 ], [ 40, 1E+2 ] ], "option": 1, "T_room_init": 20, "life_model": 0, "cycling_matrix": [ [ 20, 0, 1E+2 ], [ 20, 5E+3, 80 ], [ 20, 1E+4, 60 ], [ 80, 0, 1E+2 ], [ 80, 1E+3, 80 ], [ 80, 2E+3, 60 ] ], "calendar_choice": 1, "calendar_q0": 1.020, "calendar_a": 0.003, "calendar_b": -7280.000, "calendar_c": 930.000, "calendar_matrix": [ [ -3.1E+231 ] ], "loss_choice": 0, "monthly_charge_loss": [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ], "monthly_discharge_loss": [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ], "monthly_idle_loss": [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ], "schedule_loss": [], "replacement_option": 0, "replacement_capacity": 0.000, "replacement_schedule": [], "replacement_schedule_percent": [], "analysis_period": 1, "load_escalation": [0]})"; data = json_to_ssc_data(params_str.c_str()); ssc_data_set_number(data, "dt_hr", dt_hour); mod = ssc_stateful_module_create("battery_stateful", data); @@ -33,7 +33,7 @@ class CMBatteryStatefulIntegration_cmod_battery_stateful : public ::testing::Tes "\"Vnom_default\" : 3.6, \"resistance\" : 0.001155, \"Vfull\" : 4.200, \"Vexp\" : 3.529, \"Vnom\" : 3.35, \"Qfull\" : 75.56," "\"Qexp\" : 60.75, \"Qnom\" : 73.58, \"C_rate\" : 0.200, \"mass\" : 1.55417, \"surface_area\" : 0.1548, \"Cp\" : 980," "\"h\" : 8.066, \"cap_vs_temp\" : [[ 0, 80.200000000000003 ],[23, 100],[30, 103.09999999999999],[45, 105.40000000000001]], \"T_room_init\" : 23," - "\"cycling_matrix\" : [[ 20, 0, 107 ],[20, 1000, 101],[20, 2000, 98.5],[20, 3000, 96.3]," + "\"life_model\": 0, \"cycling_matrix\" : [[ 20, 0, 107 ],[20, 1000, 101],[20, 2000, 98.5],[20, 3000, 96.3]," "[80, 0, 107],[80, 1000, 95.6],[80, 2000, 91.1],[80, 3000, 87.3]," "[100, 0, 107],[100, 1000, 85.1],[100, 2000, 76.3],[100, 3000, 69.1]]," "\"calendar_choice\" : 1, \"calendar_q0\" : 1.03127097 , \"calendar_a\" : 1.35973301e-03," diff --git a/test/ssc_test/cmod_windpower_test.cpp b/test/ssc_test/cmod_windpower_test.cpp index 723aee57fa0..b12b2c6b87d 100644 --- a/test/ssc_test/cmod_windpower_test.cpp +++ b/test/ssc_test/cmod_windpower_test.cpp @@ -145,7 +145,6 @@ TEST_F(CMWindPowerIntegration, UsingInterpolatedSubhourly_cmod_windpower) { EXPECT_TRUE(success) << "Computation 3 should succeed"; - check_annual_energy; ssc_data_get_number(data, "annual_energy", &check_annual_energy); EXPECT_NEAR(check_annual_energy, hourly_annual_energy, 0.005 * check_annual_energy); @@ -188,7 +187,6 @@ TEST_F(CMWindPowerIntegration, UsingDataArray_cmod_windpower) { compute(); - annual_energy; ssc_data_get_number(data, "annual_energy", &annual_energy); EXPECT_NEAR(annual_energy, expectedAnnualEnergy, relErr); From 0529fdc55d4eebeb3e1379929753f18858d1a635 Mon Sep 17 00:00:00 2001 From: Noel Merket Date: Mon, 1 Feb 2021 11:54:48 -0700 Subject: [PATCH 37/76] first crack at creating a battery_t --- src/EnergyPlus/ElectricPowerServiceManager.cc | 41 +++++++++++++++++++ src/EnergyPlus/ElectricPowerServiceManager.hh | 5 +++ 2 files changed, 46 insertions(+) diff --git a/src/EnergyPlus/ElectricPowerServiceManager.cc b/src/EnergyPlus/ElectricPowerServiceManager.cc index e09ef4b74cd..761a9919509 100644 --- a/src/EnergyPlus/ElectricPowerServiceManager.cc +++ b/src/EnergyPlus/ElectricPowerServiceManager.cc @@ -3202,6 +3202,47 @@ ElectricStorage::ElectricStorage( // main constructor liIon_Qnom_ = DataIPShortCuts::lNumericFieldBlanks(18) ? 0.0231 : DataIPShortCuts::rNumericArgs(18); liIon_C_rate_ = DataIPShortCuts::lNumericFieldBlanks(19) ? 1.0 : DataIPShortCuts::rNumericArgs(19); internalR_ = DataIPShortCuts::lNumericFieldBlanks(20) ? 0.09 : DataIPShortCuts::rNumericArgs(20); + + ssc_battery_ = std::unique_ptr( + new battery_t( + DataHVACGlobals::TimeStepSys, + battery_params::CHEM::LITHIUM_ION, + new capacity_lithium_ion_t( + liIon_Qfull_ * seriesNum_ * parallelNum_, // Capacity of the whole battery + startingSOC_, + maxSOC_, + minSOC_, + DataHVACGlobals::TimeStepSys + ), + new voltage_dynamic_t( + seriesNum_, + parallelNum_, + liIon_Vnom_default_, + liIon_Vfull_, + liIon_Vexp_, + liIon_Vnom_, + liIon_Qfull_, // Capacity of one cell + liIon_Qexp_, + liIon_Qnom_, + liIon_C_rate_, + internalR_, + DataHVACGlobals::TimeStepSys + ), + new lifetime_nmc_t( + DataHVACGlobals::TimeStepSys + ), + new thermal_t( + DataHVACGlobals::TimeStepSys, + liIon_mass_, + liIon_surfaceArea_, + internalR_ * seriesNum_, // Electric resistance of the whole battery + liIon_Cp_, + liIon_heatTransferCoef_, + 20.0 // Picking a temperature for now, will reset before each run. + ), + new losses_t() + ) + ); break; } case StorageModelType::storageTypeNotSet: { diff --git a/src/EnergyPlus/ElectricPowerServiceManager.hh b/src/EnergyPlus/ElectricPowerServiceManager.hh index 775d6f84bb6..b05c28f647c 100644 --- a/src/EnergyPlus/ElectricPowerServiceManager.hh +++ b/src/EnergyPlus/ElectricPowerServiceManager.hh @@ -62,6 +62,9 @@ #include #include +// SSC Headers +#include <../third_party/ssc/shared/lib_battery.h> + namespace EnergyPlus { enum class ThermalLossDestination : int @@ -396,6 +399,8 @@ private: // data Real64 lastTimeStepBound_; // [Ah] bound charge at the previous timestep Real64 lastTwoTimeStepAvailable_; // [Ah] available charge at the previous two timesteps Real64 lastTwoTimeStepBound_; // [Ah] bound charge at the previous two timesteps + // Li-ion NMC battery object from SAM Simulation Core lib_battery + std::unique_ptr ssc_battery_; // battery life calculation variables int count0_; std::vector b10_; From 9b55c2177f48738ad0d17f83cf7a86bf676c1515 Mon Sep 17 00:00:00 2001 From: Noel Merket Date: Mon, 1 Feb 2021 13:49:38 -0700 Subject: [PATCH 38/76] fixing A-h -> Ah in idd --- idd/Energy+.idd.in | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/idd/Energy+.idd.in b/idd/Energy+.idd.in index dccbd3fe74f..80e4c23234f 100644 --- a/idd/Energy+.idd.in +++ b/idd/Energy+.idd.in @@ -88791,7 +88791,7 @@ ElectricLoadCenter:Storage:LiIonNMCBattery, \minimum 1 \default 3 \note Each cell in a Li-ion battery is 3.6V - \note with a capacity of 3.2 A-h. + \note with a capacity of 3.2 Ah. N3, \field Number of Strings in Parallel \type integer \minimum 1 @@ -88864,17 +88864,17 @@ ElectricLoadCenter:Storage:LiIonNMCBattery, N16, \field Fully Charged Cell Capacity \type real \minimum> 0 - \units A-h + \units Ah \default 1 N17, \field Cell Capacity at End of Exponential Zone \type real \minimum> 0 - \units A-h + \units Ah \default 0.1925 N18, \field Cell Capacity at End of Nominal Zone \type real \minimum> 0 - \units A-h + \units Ah \default 0.0231 N19, \field Rate at Which Voltage vs Capacity Curve Input \type real From bb03e317158bab7ef102783b8a9d62ea937d87b6 Mon Sep 17 00:00:00 2001 From: Noel Merket Date: Thu, 4 Feb 2021 14:05:35 -0700 Subject: [PATCH 39/76] hooking up output variables and zone heat gains --- src/EnergyPlus/ElectricPowerServiceManager.cc | 122 +++++++++++++++--- src/EnergyPlus/ElectricPowerServiceManager.hh | 11 +- 2 files changed, 114 insertions(+), 19 deletions(-) diff --git a/src/EnergyPlus/ElectricPowerServiceManager.cc b/src/EnergyPlus/ElectricPowerServiceManager.cc index 761a9919509..1abad29b415 100644 --- a/src/EnergyPlus/ElectricPowerServiceManager.cc +++ b/src/EnergyPlus/ElectricPowerServiceManager.cc @@ -56,9 +56,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -3140,20 +3142,6 @@ ElectricStorage::ElectricStorage( // main constructor cutoffV_ = DataIPShortCuts::rNumericArgs(12); maxChargeRate_ = DataIPShortCuts::rNumericArgs(13); - SetupOutputVariable(state, "Electric Storage Operating Mode Index", OutputProcessor::Unit::None, storageMode_, "System", "Average", name_); - SetupOutputVariable(state, "Electric Storage Battery Charge State", - OutputProcessor::Unit::Ah, - absoluteSOC_, - "System", - "Average", - name_); // issue #4921 - SetupOutputVariable(state, "Electric Storage Charge Fraction", OutputProcessor::Unit::None, fractionSOC_, "System", "Average", name_); - SetupOutputVariable(state, "Electric Storage Total Current", OutputProcessor::Unit::A, batteryCurrent_, "System", "Average", name_); - SetupOutputVariable(state, "Electric Storage Total Voltage", OutputProcessor::Unit::V, batteryVoltage_, "System", "Average", name_); - - if (lifeCalculation_ == BatteyDegredationModelType::lifeCalculationYes) { - SetupOutputVariable(state, "Electric Storage Degradation Fraction", OutputProcessor::Unit::None, batteryDamage_, "System", "Average", name_); - } break; } case StorageModelType::liIonNmcBattery: { @@ -3203,12 +3191,15 @@ ElectricStorage::ElectricStorage( // main constructor liIon_C_rate_ = DataIPShortCuts::lNumericFieldBlanks(19) ? 1.0 : DataIPShortCuts::rNumericArgs(19); internalR_ = DataIPShortCuts::lNumericFieldBlanks(20) ? 0.09 : DataIPShortCuts::rNumericArgs(20); + maxAhCapacity_ = liIon_Qfull_ * seriesNum_ * parallelNum_; + + std::vector batt_losses{0}; // using double because SSC expects a double ssc_battery_ = std::unique_ptr( new battery_t( DataHVACGlobals::TimeStepSys, battery_params::CHEM::LITHIUM_ION, new capacity_lithium_ion_t( - liIon_Qfull_ * seriesNum_ * parallelNum_, // Capacity of the whole battery + maxAhCapacity_, // Capacity of the whole battery startingSOC_, maxSOC_, minSOC_, @@ -3235,14 +3226,15 @@ ElectricStorage::ElectricStorage( // main constructor DataHVACGlobals::TimeStepSys, liIon_mass_, liIon_surfaceArea_, - internalR_ * seriesNum_, // Electric resistance of the whole battery + internalR_ * seriesNum_ / parallelNum_, // Electric resistance of the whole battery liIon_Cp_, liIon_heatTransferCoef_, 20.0 // Picking a temperature for now, will reset before each run. ), - new losses_t() + new losses_t(batt_losses) ) ); + *ssc_lastBatteryState_ = ssc_battery_->get_state(); break; } case StorageModelType::storageTypeNotSet: { @@ -3252,6 +3244,23 @@ ElectricStorage::ElectricStorage( // main constructor } // switch storage model type + if (storageModelMode_ == StorageModelType::kiBaMBattery or storageModelMode_ == StorageModelType::liIonNmcBattery) { + SetupOutputVariable(state, "Electric Storage Operating Mode Index", OutputProcessor::Unit::None, storageMode_, "System", "Average", name_); + SetupOutputVariable(state, "Electric Storage Battery Charge State", + OutputProcessor::Unit::Ah, + absoluteSOC_, + "System", + "Average", + name_); // issue #4921 + SetupOutputVariable(state, "Electric Storage Charge Fraction", OutputProcessor::Unit::None, fractionSOC_, "System", "Average", name_); + SetupOutputVariable(state, "Electric Storage Total Current", OutputProcessor::Unit::A, batteryCurrent_, "System", "Average", name_); + SetupOutputVariable(state, "Electric Storage Total Voltage", OutputProcessor::Unit::V, batteryVoltage_, "System", "Average", name_); + + if (lifeCalculation_ == BatteyDegredationModelType::lifeCalculationYes) { + SetupOutputVariable(state, "Electric Storage Degradation Fraction", OutputProcessor::Unit::None, batteryDamage_, "System", "Average", name_); + } + } + SetupOutputVariable(state, "Electric Storage Charge Power", OutputProcessor::Unit::W, storedPower_, "System", "Average", name_); SetupOutputVariable(state, "Electric Storage Charge Energy", OutputProcessor::Unit::J, storedEnergy_, "System", "Sum", name_); SetupOutputVariable(state, "Electric Storage Production Decrement Energy", @@ -3285,6 +3294,7 @@ ElectricStorage::ElectricStorage( // main constructor } else if (storageModelMode_ == StorageModelType::kiBaMBattery) { SetupEMSInternalVariable(state, "Electrical Storage Battery Maximum Capacity", name_, "[Ah]", maxAhCapacity_); } + // FIXME: Add EMS Variable for Li-ion battery } if (zoneNum_ > 0) { @@ -3389,6 +3399,7 @@ void ElectricStorage::reinitZoneGainsAtBeginEnvironment() void ElectricStorage::reinitAtEndWarmup() { // need to reset initial state of charge at beginning of environment but after warm up is complete + // FIXME: get this reset for li-ion batteries lastTimeStepStateOfCharge_ = startingEnergyStored_; thisTimeStepStateOfCharge_ = startingEnergyStored_; if (storageModelMode_ == StorageModelType::kiBaMBattery) { @@ -3466,6 +3477,8 @@ void ElectricStorage::timeCheckAndUpdate(EnergyPlusData &state) batteryDamage_ += oneNmb0_[binNum] / CurveManager::CurveValue(state, lifeCurveNum_, (double(binNum) / double(cycleBinNum_))); } } + } else if ( storageModelMode_ == StorageModelType::liIonNmcBattery ) { + *ssc_lastBatteryState_ = ssc_battery_->get_state(); } lastTimeStepStateOfCharge_ = thisTimeStepStateOfCharge_; @@ -3497,7 +3510,9 @@ void ElectricStorage::simulate(EnergyPlusData &state, if (storageModelMode_ == StorageModelType::simpleBucketStorage) { simulateSimpleBucketModel(powerCharge, powerDischarge, charging, discharging, controlSOCMaxFracLimit, controlSOCMinFracLimit); } else if (storageModelMode_ == StorageModelType::kiBaMBattery) { - simulateKineticBatteryModel(state,powerCharge, powerDischarge, charging, discharging, controlSOCMaxFracLimit, controlSOCMinFracLimit); + simulateKineticBatteryModel(state, powerCharge, powerDischarge, charging, discharging, controlSOCMaxFracLimit, controlSOCMinFracLimit); + } else if (storageModelMode_ == StorageModelType::liIonNmcBattery) { + simulateLiIonNmcBatteryModel(state, powerCharge, powerDischarge, charging, discharging, controlSOCMaxFracLimit, controlSOCMinFracLimit); } } @@ -3810,6 +3825,77 @@ void ElectricStorage::simulateKineticBatteryModel(EnergyPlusData &state, powerDischarge = drawnPower_; } +void ElectricStorage::simulateLiIonNmcBatteryModel(EnergyPlusData &state, + Real64 &powerCharge, + Real64 &powerDischarge, + bool &charging, + bool &discharging, + Real64 const controlSOCMaxFracLimit, + Real64 const controlSOCMinFracLimit) +{ + // Copy the battery state from the end of last timestep + battery_state battState = *ssc_lastBatteryState_; + + // Set the temperature the battery sees + if (zoneNum_ > 0) { + // If in a zone, use the zone temperature + battState.thermal->T_room = DataHeatBalFanSys::ZT(zoneNum_); + } else { + // If outside, use outdoor temperature + battState.thermal->T_room = state.dataEnvrn->OutDryBulbTemp; + } + ssc_battery_->set_state(battState); + + // Set the current timestep length + ssc_battery_->ChangeTimestep(DataHVACGlobals::TimeStepSys); + + // Run the battery + // SAM uses negative values for charging, positive for discharging + double power{0.0}; // Using double instead of Real64 because SSC is expecting a double + if (charging) { + power = - powerCharge; + } else if (discharging) { + power = powerDischarge; + } + power *= 0.001; // Convert to kW + ssc_battery_->runPower(power); + + // Store outputs + const battery_state battState2 = ssc_battery_->get_state(); + if (battState2.P < 0.0) { // negative for charging + storageMode_ = 2; + } else if (battState2.P > 0.0) { // positive for discharging + storageMode_ = 1; + } else { + storageMode_ = 0; + } + absoluteSOC_ = ssc_battery_->charge_total(); + fractionSOC_ = ssc_battery_->SOC() * 0.01; // % -> fraction + batteryCurrent_ = ssc_battery_->I(); + batteryVoltage_ = ssc_battery_->V(); + batteryDamage_ = 1.0 - (ssc_battery_->charge_maximum_lifetime() / maxAhCapacity_); + if (battState2.P < 0.0) { // negative for charging + storedPower_ = - battState2.P * 1000.0; // kW -> W + drawnPower_ = 0.0; + } else { // positive for discharging + storedPower_ = 0.0; + drawnPower_ = battState2.P * 1000.0; // kW -> W + } + storedEnergy_ = storedPower_ * DataHVACGlobals::TimeStepSys * DataGlobalConstants::SecInHour; + decrementedEnergyStored_ = - storedEnergy_; + thermLossRate_ = battState2.thermal->heat_dissipated * 1000.0; // kW -> W + thermLossEnergy_ = thermLossRate_ * DataHVACGlobals::TimeStepSys * DataGlobalConstants::SecInHour; + + // Zone Heat Gains + if (zoneNum_ > 0) { // set values for zone heat gains + qdotConvZone_ = (1.0 - zoneRadFract_) * thermLossRate_; + qdotRadZone_ = (zoneRadFract_) * thermLossRate_; + } + + + +} + Real64 ElectricStorage::drawnPower() const { return drawnPower_; diff --git a/src/EnergyPlus/ElectricPowerServiceManager.hh b/src/EnergyPlus/ElectricPowerServiceManager.hh index b05c28f647c..d010a132d3d 100644 --- a/src/EnergyPlus/ElectricPowerServiceManager.hh +++ b/src/EnergyPlus/ElectricPowerServiceManager.hh @@ -302,6 +302,14 @@ private: // methods Real64 const controlSOCMaxFracLimit, Real64 const controlSOCMinFracLimit); + void simulateLiIonNmcBatteryModel(EnergyPlusData &state, + Real64 &powerCharge, + Real64 &powerDischarge, + bool &charging, + bool &discharging, + Real64 const controlSOCMaxFracLimit, + Real64 const controlSOCMinFracLimit); + void rainflow(int const numbin, // numbin = constant value Real64 const input, // input = input value from other object (battery model) std::vector &B1, // stores values of points, calculated here - stored for next timestep @@ -399,8 +407,9 @@ private: // data Real64 lastTimeStepBound_; // [Ah] bound charge at the previous timestep Real64 lastTwoTimeStepAvailable_; // [Ah] available charge at the previous two timesteps Real64 lastTwoTimeStepBound_; // [Ah] bound charge at the previous two timesteps - // Li-ion NMC battery object from SAM Simulation Core lib_battery + // Li-ion NMC battery objects from SAM Simulation Core lib_battery std::unique_ptr ssc_battery_; + std::unique_ptr ssc_lastBatteryState_; // battery life calculation variables int count0_; std::vector b10_; From a31fdce0aee680011d300a92a95c7315c7b6305f Mon Sep 17 00:00:00 2001 From: Noel Merket Date: Thu, 4 Feb 2021 14:08:38 -0700 Subject: [PATCH 40/76] Squashed 'third_party/ssc/' changes from 3ce30afc9e..a016268145 a016268145 added nocycling tests for NMC, fixed DOD_max in equation 94a36aed6e Merge remote-tracking branch 'upstream/patch' into batt_life_new_Jan_2021 a98e27221b Merge pull request #522 from NREL/ssc_520 70d7eb03f2 Added comment reflecting units of updateVoltage in dynamic voltage model f1dcfb6e2c Updated test results 26b1a642c3 Merge branch 'patch' into ssc_520 5d66a82941 Adaptive battery timesteps (#524) f33a06f291 Set initial SOC for voltage with battery capacity rather than cell capacity 9aafbf2da5 Fix #364 error messaging for PV one-axis tracking and bifacial 819127dc67 Merge pull request #519 from NREL/dynamic_voltage_error_message a14d655adf Revise battery error messages. 98c7a74e7a Added error message for bad voltage model inputs 450a84366e fix battery capacity in lib_battery_dispatch_automatic_btm_test.h (#518) 8987e0db43 Merge branch 'price_signals_dispatch_improved_demand' of https://github.com/NREL/ssc into patch f9dec3e64a Merge pull request #516 from NREL/SAM_485 2243c8b3e9 Addresses SAM issue #485 57219e6c3f update comments and variable names about peak vs average load to clarify new conventions cfd13b8088 Fix for SSC issue #505 (#506) a5d3bec827 Merge pull request #509 from dangerski/dangerski-refraction-correction-fix eb1dafa5a9 check for divide by zero and replace with nan e57e0d1285 Reverted precision on unaffected tests a1e72a202a Added test catching atmospheric refraction behavior aa1e15ebd7 Merge pull request #507 from NREL/496_update_required_vars 408e3a07d7 fix tests based on changes in ea8da11 c409acf968 Merge branch 'patch' of https://github.com/NREL/ssc into price_signals_dispatch_improved_demand 9b0d5819a0 set default for batt_cycle_cost_choice if missing ea8da118e0 make the calculation of value of remaining energy more consistent between dispatch lengths 4d1cbd0442 update variable names to reflect new usage bf9fdcfba5 fix (hopefully all) tests for dispatch algorithm update 1d529cf465 first cut of changes to improve price signals dispatch response to demand charges. need to fix tests and rename vars 856543733a Fixed bug in atmospheric_refraction_correction 47c1f98ebc remove re-initialized variables that were preventing cnt and ts_br from being communicated to setup_time_series 39d709d18b update cmod battery to only require battery cycle costs when the input cost option is selected 24758912f7 changing cmake to 3.10 (#504) 146fc135ad increase ResidentialDCBatteryModelPriceSignalDispatch err tol for platform differences a4c86168ac Merge branch 'improve_tests' into develop 537dc1a05c Simplify tower shared with ui equation tests 466e12fd16 Reorganize more csp tests 3e7ca9fdbf Reorganize some csp tests a03f7d3699 Move defaults files to the inputs directory 50cdf53360 Refactor fresnel molten salt tests 73a8d049fd Refactor direct steam tower tests a34c689d6e Refactor empirical trough tests f95c859b68 Refactor heat trough tests 024795eeda Refactor trough physical tests 415bbe62b1 Refactor tcsmolten_salt tests 6d46752293 Merge branch 'develop' into improve_tests 77de932edb Refactor csp tes tests into new file and rename other csp tests dd41275027 Refactor trough tests into factories d3e909ede1 Add rest of flat plate tests to solar_thermal namespace 79bd7dde37 Move one test to a VS namespace a3f2b187af Add support for VS Test Explorer namespaces ca506ff475 Change raw pointers to unique_ptrs or values in csp tests 7f4bb2b0d2 Refactor csp function tests into an abstract factory pattern git-subtree-dir: third_party/ssc git-subtree-split: a016268145d86feb02e409b3d081903ffb102cc5 --- CMakeLists.txt | 9 +- shared/lib_battery_dispatch_automatic_btm.cpp | 42 +- shared/lib_battery_lifetime.cpp | 1 + shared/lib_battery_lifetime_nmc.cpp | 58 +- shared/lib_battery_lifetime_nmc.h | 8 +- shared/lib_battery_voltage.cpp | 2 +- shared/lib_battery_voltage.h | 5 +- shared/lib_irradproc.cpp | 2 +- shared/lib_pvshade.cpp | 5 +- shared/lib_utility_rate.cpp | 40 +- shared/lib_utility_rate.h | 5 +- ssc/cmod_battery.cpp | 77 +- ssc/cmod_merchantplant.cpp | 32 +- ssc/cmod_pvsamv1.cpp | 8 +- ssc/cmod_utilityrate5.cpp | 2 - ssc/cmod_windpower.cpp | 4 +- test/input_cases/battery_common_data.h | 2 - test/input_cases/csp_financial_defaults.cpp | 260 +++ .../tcsdirect_steam_defaults.h} | 20 +- .../tcsfresnel_molten_salt_defaults.h} | 14 +- .../tcsmolten_salt_defaults.h} | 247 +-- .../tcstrough_empirical_defaults.h} | 14 +- .../trough_physical_defaults.h} | 268 +-- .../trough_physical_iph_defaults.h} | 30 +- .../csp_solver_core_test.cpp | 0 ...ib_battery_dispatch_automatic_btm_test.cpp | 31 +- .../lib_battery_dispatch_automatic_btm_test.h | 4 +- .../lib_battery_dispatch_manual_test.cpp | 2 +- .../lib_battery_dispatch_manual_test.h | 4 +- .../shared_test/lib_battery_lifetime_test.cpp | 38 +- test/shared_test/lib_csp_tes_test.cpp | 148 ++ test/shared_test/lib_csp_tes_test.h | 74 + test/shared_test/lib_csp_test.cpp | 230 --- test/shared_test/lib_csp_test.h | 125 -- .../lib_csp_tower_shared_with_ui_test.cpp | 533 ++++++ test/shared_test/lib_csp_trough_test.cpp | 726 ++++++++ test/shared_test/lib_csp_trough_test.h | 186 ++ test/shared_test/lib_irradproc_test.cpp | 25 +- test/shared_test/lib_solar_thermal_test.cpp | 175 ++ test/shared_test/lib_solar_thermal_test.h | 53 + test/shared_test/lib_utility_rate_test.cpp | 147 +- .../vs_google_test_explorer_namespace.h | 48 + test/ssc_test/cmod_battery_pvsamv1_test.cpp | 7 +- test/ssc_test/cmod_singleowner_test.cpp | 95 - test/ssc_test/cmod_tcsdirect_steam_test.cpp | 602 +++---- test/ssc_test/cmod_tcsdirect_steam_test.h | 54 - .../cmod_tcsfresnel_molten_salt_test.cpp | 691 +++----- .../cmod_tcsfresnel_molten_salt_test.h | 53 - test/ssc_test/cmod_tcsmolten_salt_test.cpp | 1559 ++++------------- test/ssc_test/cmod_tcsmolten_salt_test.h | 54 - .../cmod_tcstrough_empirical_test.cpp | 614 +++---- test/ssc_test/cmod_tcstrough_empirical_test.h | 53 - .../cmod_trough_physical_iph_test.cpp | 140 +- test/ssc_test/cmod_trough_physical_iph_test.h | 53 - test/ssc_test/cmod_trough_physical_test.cpp | 141 +- test/ssc_test/cmod_trough_physical_test.h | 54 - test/ssc_test/csp_common_test.h | 56 + test/tcs_test/lib_trough_properties.h | 506 ------ test/tcs_test/lib_trough_test.cpp | 174 -- test/tcs_test/lib_trough_test.h | 193 -- test/tcs_test/tcsdirect_steam_cases.h | 168 -- test/tcs_test/tcsfresnel_molten_salt_cases.h | 177 -- test/tcs_test/tcsmolten_salt_cases.h | 385 ---- test/tcs_test/tcstrough_empirical_cases.h | 241 --- test/tcs_test/trough_physical_cases.h | 28 - test/tcs_test/trough_physical_iph_cases.h | 28 - 66 files changed, 3698 insertions(+), 6132 deletions(-) create mode 100644 test/input_cases/csp_financial_defaults.cpp rename test/{tcs_test/tcsdirect_steam_common_data.h => input_cases/tcsdirect_steam_defaults.h} (98%) rename test/{tcs_test/tcsfresnel_molten_salt_common_data.h => input_cases/tcsfresnel_molten_salt_defaults.h} (98%) rename test/{tcs_test/tcsmolten_salt_common_data.h => input_cases/tcsmolten_salt_defaults.h} (61%) rename test/{tcs_test/tcstrough_empirical_common_data.h => input_cases/tcstrough_empirical_defaults.h} (97%) rename test/{tcs_test/trough_physical_common_data.h => input_cases/trough_physical_defaults.h} (65%) rename test/{tcs_test/trough_physical_iph_common_data.h => input_cases/trough_physical_iph_defaults.h} (97%) rename test/{tcs_test => shared_test}/csp_solver_core_test.cpp (100%) create mode 100644 test/shared_test/lib_csp_tes_test.cpp create mode 100644 test/shared_test/lib_csp_tes_test.h delete mode 100644 test/shared_test/lib_csp_test.cpp delete mode 100644 test/shared_test/lib_csp_test.h create mode 100644 test/shared_test/lib_csp_tower_shared_with_ui_test.cpp create mode 100644 test/shared_test/lib_csp_trough_test.cpp create mode 100644 test/shared_test/lib_csp_trough_test.h create mode 100644 test/shared_test/lib_solar_thermal_test.cpp create mode 100644 test/shared_test/lib_solar_thermal_test.h create mode 100644 test/shared_test/vs_google_test_explorer_namespace.h delete mode 100644 test/ssc_test/cmod_tcsdirect_steam_test.h delete mode 100644 test/ssc_test/cmod_tcsfresnel_molten_salt_test.h delete mode 100644 test/ssc_test/cmod_tcsmolten_salt_test.h delete mode 100644 test/ssc_test/cmod_tcstrough_empirical_test.h delete mode 100644 test/ssc_test/cmod_trough_physical_iph_test.h delete mode 100644 test/ssc_test/cmod_trough_physical_test.h create mode 100644 test/ssc_test/csp_common_test.h delete mode 100644 test/tcs_test/lib_trough_properties.h delete mode 100644 test/tcs_test/lib_trough_test.cpp delete mode 100644 test/tcs_test/lib_trough_test.h delete mode 100644 test/tcs_test/tcsdirect_steam_cases.h delete mode 100644 test/tcs_test/tcsfresnel_molten_salt_cases.h delete mode 100644 test/tcs_test/tcsmolten_salt_cases.h delete mode 100644 test/tcs_test/tcstrough_empirical_cases.h delete mode 100644 test/tcs_test/trough_physical_cases.h delete mode 100644 test/tcs_test/trough_physical_iph_cases.h diff --git a/CMakeLists.txt b/CMakeLists.txt index d96c75cbfbb..7dd726ae1a9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ # ##################################################################################################################### -cmake_minimum_required(VERSION 3.11) +cmake_minimum_required(VERSION 3.10) if(POLICY CMP0077) cmake_policy(SET CMP0077 NEW) @@ -140,12 +140,7 @@ endfunction() # turn off examples, tests and install for jsoncpp set(JSONCPP_WITH_EXAMPLE 0) set(JSONCPP_WITH_TESTS 0) -macro (install) -endmacro () -add_subdirectory(jsoncpp) -macro (install) - _install(${ARGV}) -endmacro(install) +add_subdirectory(jsoncpp EXCLUDE_FROM_ALL) add_subdirectory(splinter) add_subdirectory(shared) diff --git a/shared/lib_battery_dispatch_automatic_btm.cpp b/shared/lib_battery_dispatch_automatic_btm.cpp index 2ac57f61741..681e090ecd8 100644 --- a/shared/lib_battery_dispatch_automatic_btm.cpp +++ b/shared/lib_battery_dispatch_automatic_btm.cpp @@ -140,23 +140,22 @@ void dispatch_automatic_behind_the_meter_t::setup_rate_forecast() { // Process load and pv forecasts to get _monthly_ expected gen, load, and peak // Do we need new member variables, or can these just be passed off to UtilityRateForecast? - std::vector monthly_peaks; + std::vector monthly_gross_load; std::vector monthly_gen; - std::vector monthly_load; + std::vector monthly_net_load; // Load here is every step for the full analysis period. Load escalation has already been applied (TODO in compute modules) size_t num_recs = util::hours_per_year * _steps_per_hour * _nyears; size_t step = 0; size_t hour_of_year = 0; int curr_month = 1; - double load_during_month = 0.0; double gen_during_month = 0.0; double peak_during_month = 0.0; + double load_during_month = 0.0; double gen_during_month = 0.0; double gross_load_during_month = 0.0; size_t array_size = std::min(_P_pv_ac.size(), _P_load_ac.size()); // Cover smaller arrays to make testing easier for (size_t idx = 0; idx < num_recs && idx < array_size; idx++) { double grid_power = _P_pv_ac[idx] - _P_load_ac[idx]; - if (grid_power < peak_during_month) - { - peak_during_month = grid_power; - } + + gross_load_during_month += _P_load_ac[idx] * _dt_hour; + if (grid_power < 0) { @@ -180,16 +179,16 @@ void dispatch_automatic_behind_the_meter_t::setup_rate_forecast() { // Push back vectors // Note: this is a net-billing approach. To be accurate for net metering, we'd have to invoke tou periods here, this overestimates costs for NM - monthly_peaks.push_back(-1.0 * peak_during_month); - monthly_load.push_back(-1.0 * load_during_month); + monthly_gross_load.push_back(gross_load_during_month / util::hours_in_month(curr_month)); + monthly_net_load.push_back(-1.0 * load_during_month); monthly_gen.push_back(gen_during_month); - peak_during_month = 0.0; load_during_month = 0.0; gen_during_month = 0.0; + gross_load_during_month = 0.0; load_during_month = 0.0; gen_during_month = 0.0; curr_month < 12 ? curr_month++ : curr_month = 1; } } - rate_forecast = std::shared_ptr(new UtilityRateForecast(rate.get(), _steps_per_hour, monthly_load, monthly_gen, monthly_peaks, _nyears)); + rate_forecast = std::shared_ptr(new UtilityRateForecast(rate.get(), _steps_per_hour, monthly_net_load, monthly_gen, monthly_gross_load, _nyears)); rate_forecast->initializeMonth(0, 0); rate_forecast->copyTOUForecast(); } @@ -604,6 +603,7 @@ void dispatch_automatic_behind_the_meter_t::plan_dispatch_for_cost(dispatch_plan } } double remainingEnergy = E_max; + double powerAtMaxCost = 0; plan.lowestMarginalCost = sorted_grid[0].MarginalCost(); for (i = 0; i < (plan.dispatch_hours * _steps_per_hour) && (i < sorted_grid.size()); i++) { @@ -612,10 +612,17 @@ void dispatch_automatic_behind_the_meter_t::plan_dispatch_for_cost(dispatch_plan { double costPercent = costAtStep / costDuringDispatchHours; double desiredPower = remainingEnergy * costPercent / _dt_hour; + + // Prevent the wierd signals from demand charges from reducing dispatch (maybe fix this upstream in the future) + if (desiredPower < powerAtMaxCost && sorted_grid[i].Grid() >= powerAtMaxCost) { + desiredPower = powerAtMaxCost; + } + if (desiredPower > sorted_grid[i].Grid()) { desiredPower = sorted_grid[i].Grid(); } + // Account for discharging constraints assuming voltage is constant over forecast period check_power_restrictions(desiredPower); @@ -627,11 +634,24 @@ void dispatch_automatic_behind_the_meter_t::plan_dispatch_for_cost(dispatch_plan index = sorted_grid[i].Hour() * _steps_per_hour + sorted_grid[i].Step(); // Assumes we're always running this function on the hour plan.plannedDispatch[index] = desiredPower; + if (powerAtMaxCost == 0) { + powerAtMaxCost = desiredPower; + } + } + } + + for (i = 0; i < _steps_per_hour && (i < sorted_grid.size()); i++) + { + if (sorted_grid[i].Cost() > 0) + { if (sorted_grid[i].MarginalCost() < plan.lowestMarginalCost) { plan.lowestMarginalCost = sorted_grid[i].MarginalCost(); } } + else { + break; + } } // Aim to keep the battery at 50% diff --git a/shared/lib_battery_lifetime.cpp b/shared/lib_battery_lifetime.cpp index 18bb5c6463f..cb30938a1cb 100644 --- a/shared/lib_battery_lifetime.cpp +++ b/shared/lib_battery_lifetime.cpp @@ -1,6 +1,7 @@ #include "lib_battery_lifetime.h" #include "lib_battery_lifetime_calendar_cycle.h" #include "lib_battery_lifetime_nmc.h" +#include lifetime_params::lifetime_params() { model_choice = CALCYC; diff --git a/shared/lib_battery_lifetime_nmc.cpp b/shared/lib_battery_lifetime_nmc.cpp index 2fd15875b83..c7f5eea0042 100644 --- a/shared/lib_battery_lifetime_nmc.cpp +++ b/shared/lib_battery_lifetime_nmc.cpp @@ -2,12 +2,14 @@ #include "lib_battery_lifetime_nmc.h" #include "lib_battery_lifetime.h" #include +#include void lifetime_nmc_t::initialize() { // cycle model for counting cycles only, no cycle-only degradation cycle_model = std::unique_ptr(new lifetime_cycle_t(params, state)); // do any state initialization here + state->q_relative = 100; state->nmc_state->q_relative_li = 100; state->nmc_state->q_relative_neg = 100; state->nmc_state->dq_relative_li_old = 0; @@ -15,10 +17,10 @@ void lifetime_nmc_t::initialize() { state->nmc_state->day_age_of_battery_float = 0; state->nmc_state->DOD_max = 50; state->nmc_state->n_cycles_prev_day = 0; - state->nmc_state->b1_dt.clear(); - state->nmc_state->b2_dt.clear(); - state->nmc_state->b3_dt.clear(); - state->nmc_state->c2_dt.clear(); + state->nmc_state->b1_dt = 0; + state->nmc_state->b2_dt = 0; + state->nmc_state->b3_dt = 0; + state->nmc_state->c2_dt = 0; } lifetime_nmc_t::lifetime_nmc_t(double dt_hr) { @@ -77,9 +79,14 @@ double lifetime_nmc_t::runLifetimeNMC_Qli() { double dt_day = 1; int dn_cycles = state->n_cycles - state->nmc_state->n_cycles_prev_day; double k_cal = 0; - double b1 = std::accumulate(state->nmc_state->b1_dt.begin(), state->nmc_state->b1_dt.end(), 0); - double b2 = std::accumulate(state->nmc_state->b2_dt.begin(), state->nmc_state->b1_dt.end(), 0); - double b3 = std::accumulate(state->nmc_state->b3_dt.begin(), state->nmc_state->b1_dt.end(), 0); + //double b1 = std::accumulate(state->nmc_state->b1_dt.begin(), state->nmc_state->b1_dt.end(), 0); + double b1 = state->nmc_state->b1_dt; + double b2 = state->nmc_state->b2_dt; + double b3 = state->nmc_state->b3_dt; + + state->nmc_state->b1_dt = 0; + state->nmc_state->b2_dt = 0; + state->nmc_state->b3_dt = 0; if (state->day_age_of_battery > 0) k_cal = (0.5 * b1) / (sqrt(state->day_age_of_battery)) + (b3 / tau_b3) * exp(-(state->day_age_of_battery / tau_b3)); @@ -92,15 +99,17 @@ double lifetime_nmc_t::runLifetimeNMC_Qli() { else dq_new = k_cal * dt_day + b2 * dn_cycles + state->nmc_state->dq_relative_li_old; state->nmc_state->dq_relative_li_old = dq_new; - state->nmc_state->q_relative_li = (1 - (dq_new)) * 100; + state->nmc_state->q_relative_li = (1.07 - (dq_new)) * 100; return state->nmc_state->q_relative_li; } double lifetime_nmc_t::runLifetimeNMC_Qneg(double T_battery, double SOC) { + double DOD = 1 - SOC; int dn_cycles = state->n_cycles - state->nmc_state->n_cycles_prev_day; - double c2 = std::accumulate(state->nmc_state->c2_dt.begin(), state->nmc_state->c2_dt.end(), 0);; + double c2 = state->nmc_state->c2_dt; + state->nmc_state->c2_dt = 0; double dq_new; if (state->nmc_state->dq_relative_neg_old == 0) @@ -111,18 +120,22 @@ double lifetime_nmc_t::runLifetimeNMC_Qneg(double T_battery, double SOC) { state->nmc_state->dq_relative_neg_old = dq_new; state->nmc_state->q_relative_neg = (1 - (dq_new)) * 100; - return state->nmc_state->q_relative_neg; + + //return state->nmc_state->q_relative_neg; + return 100; } void lifetime_nmc_t::runLifetimeModels(size_t lifetimeIndex, bool charge_changed, double prev_DOD, double DOD, double T_battery) { double q_last = state->q_relative; + // update day age of battery int day_age_of_battery_old = (int)(state->nmc_state->day_age_of_battery_float); state->nmc_state->day_age_of_battery_float = state->nmc_state->day_age_of_battery_float + - float(util::hours_per_day / params->dt_hr); + float( params->dt_hr/ util::hours_per_day); state->day_age_of_battery = (int)(state->nmc_state->day_age_of_battery_float); - + + // convert battery temperature to Kelvin T_battery += 273; if (charge_changed) @@ -134,40 +147,39 @@ void lifetime_nmc_t::runLifetimeModels(size_t lifetimeIndex, bool charge_changed //compute open circuit and negative electrode voltage as function of SOC double SOC = 0.01 * (100 - DOD); + double DOD_max = state->nmc_state->DOD_max * 0.01; double U_neg = Uneg_computation(SOC); double V_oc = Voc_computation(SOC); // compute lifetime degradation coefficients for current time step, //multiply by timestep in days and populate corresponding vectors - double dt_day = (1 / 24) * params->dt_hr; + double dt_day = (1. / 24) * params->dt_hr; double b1_dt_el = b1_ref * exp(-(Ea_b_1 / Rug) * (1. / T_battery - 1. / T_ref)) * exp((alpha_a_b1 * F / Rug) * (U_neg / T_battery - U_ref / T_ref)) - * exp(gamma * pow(state->nmc_state->DOD_max, beta_b1)) * dt_day; + * exp(gamma * pow(DOD_max, beta_b1)) * dt_day; double b2_dt_el = b2_ref * exp(-(Ea_b_2 / Rug) * (1. / T_battery - 1. / T_ref)) * dt_day; double b3_dt_el = b3_ref * exp(-(Ea_b_3 / Rug) * (1. / T_battery - 1. / T_ref)) * exp((alpha_a_b3 * F / Rug) * (V_oc / T_battery - V_ref / T_ref)) - * (1 + theta * state->nmc_state->DOD_max); - state->nmc_state->b1_dt.push_back(b1_dt_el); - state->nmc_state->b2_dt.push_back(b2_dt_el); - state->nmc_state->b3_dt.push_back(b3_dt_el); + * (1 + theta * DOD_max); + state->nmc_state->b1_dt += b1_dt_el; + state->nmc_state->b2_dt += b2_dt_el; + state->nmc_state->b3_dt += b3_dt_el; //computations for q_neg double c2_dt_el = c2_ref * exp(-(Ea_c_2 / Rug) * (1. / T_battery - 1. / T_ref)) - * pow(DOD, beta_c2); - state->nmc_state->c2_dt.push_back(c2_dt_el); + * pow(0.01 * DOD, beta_c2); + state->nmc_state->c2_dt += c2_dt_el; //Run capacity degradation model after every 24 hours if (state->day_age_of_battery - day_age_of_battery_old == 1) { state->nmc_state->q_relative_li = runLifetimeNMC_Qli(); state->nmc_state->q_relative_neg = runLifetimeNMC_Qneg(T_battery, SOC); state->q_relative = fmin(state->nmc_state->q_relative_li, state->nmc_state->q_relative_neg); - state->nmc_state->b1_dt.clear(); - state->nmc_state->b2_dt.clear(); - state->nmc_state->b3_dt.clear(); state->nmc_state->n_cycles_prev_day = state->n_cycles; } state->q_relative = fmin(state->q_relative, q_last); + } double lifetime_nmc_t::estimateCycleDamage() { diff --git a/shared/lib_battery_lifetime_nmc.h b/shared/lib_battery_lifetime_nmc.h index 47ada6ebb03..c0867cd31d1 100644 --- a/shared/lib_battery_lifetime_nmc.h +++ b/shared/lib_battery_lifetime_nmc.h @@ -21,10 +21,10 @@ struct lifetime_nmc_state { // for complex cycling of battery, b1 = summagion of b1_dt * dt_day over a day // lifetime capacity updated after 24 hours elapse. - std::vector b1_dt; - std::vector b2_dt; - std::vector b3_dt; - std::vector c2_dt; + double b1_dt; + double b2_dt; + double b3_dt; + double c2_dt; friend std::ostream& operator<<(std::ostream& os, const lifetime_nmc_state& p); }; diff --git a/shared/lib_battery_voltage.cpp b/shared/lib_battery_voltage.cpp index cff0e1dbde5..44fb7ed8f58 100644 --- a/shared/lib_battery_voltage.cpp +++ b/shared/lib_battery_voltage.cpp @@ -342,7 +342,7 @@ void voltage_dynamic_t::parameter_compute() { } void voltage_dynamic_t::set_initial_SOC(double init_soc) { - updateVoltage(init_soc * 0.01 * params->dynamic.Qfull, params->dynamic.Qfull, 0, 25, params->dt_hr); + updateVoltage(init_soc * 0.01 * params->dynamic.Qfull * params->num_strings, params->dynamic.Qfull * params->num_strings, 0, 25, params->dt_hr); } // everything in here is on a per-cell basis diff --git a/shared/lib_battery_voltage.h b/shared/lib_battery_voltage.h index a13308ceb71..a91db3084dd 100644 --- a/shared/lib_battery_voltage.h +++ b/shared/lib_battery_voltage.h @@ -188,8 +188,9 @@ class voltage_dynamic_t : public voltage_t { double calculate_voltage_for_current(double I, double q, double qmax, double T_k) override; - void updateVoltage(double q, double qmax, double I, double temp, double dt) override; - + + void updateVoltage(double q, double qmax, double I, double temp, double dt) override; //updates battery voltage based on system capacity (Ah), system maximum capacity (Ah), current (A), temperature (C), and time step (hr) + protected: double _A; diff --git a/shared/lib_irradproc.cpp b/shared/lib_irradproc.cpp index 52768a77041..52c687c77b6 100644 --- a/shared/lib_irradproc.cpp +++ b/shared/lib_irradproc.cpp @@ -995,7 +995,7 @@ double atmospheric_refraction_correction(double pressure, double temperature, double atmos_refract, double e0) //atmospheric refraction correction (degrees) { double del_e = 0; - int SUN_RADIUS = 0.26667; + double SUN_RADIUS = 0.26667; if (e0 >= -1 * (SUN_RADIUS + atmos_refract)) del_e = (pressure / 1010.0) * (283.0 / (273.0 + temperature)) * 1.02 / (60.0 * tan(DTOR * (e0 + 10.3 / (e0 + 5.11)))); diff --git a/shared/lib_pvshade.cpp b/shared/lib_pvshade.cpp index 4bc6c0f6718..6c9b8367afd 100644 --- a/shared/lib_pvshade.cpp +++ b/shared/lib_pvshade.cpp @@ -302,7 +302,10 @@ double sssky_diffuse_table::compute(double surface_tilt) { double Asky_shade[1000]; for (int n = 0; n < 1000; n++) { - arg[n] = (1 / tand_stilt) - (1 / (gcr * sind_stilt * (1 - n * step))); + if (surface_tilt != 0) + arg[n] = (1 / tand_stilt) - (1 / (gcr * sind_stilt * (1 - n * step))); + else + arg[n] = std::numeric_limits::quiet_NaN(); gamma[n] = (-M_PI / 2) + atan(arg[n]); tan_tilt_gamma[n] = tan(surface_tilt * DTOR + gamma[n]); Asky_shade[n] = M_PI + M_PI / pow((1 + tan_tilt_gamma[n] * tan_tilt_gamma[n]), 0.5); diff --git a/shared/lib_utility_rate.cpp b/shared/lib_utility_rate.cpp index 845059252a7..daf0abc85a2 100644 --- a/shared/lib_utility_rate.cpp +++ b/shared/lib_utility_rate.cpp @@ -130,7 +130,7 @@ size_t UtilityRateCalculator::getEnergyPeriod(size_t hourOfYear) return period; } -UtilityRateForecast::UtilityRateForecast(rate_data* util_rate, size_t stepsPerHour, const std::vector& monthly_load_forecast, const std::vector& monthly_gen_forecast, const std::vector& monthly_peak_forecast, size_t analysis_period) : +UtilityRateForecast::UtilityRateForecast(rate_data* util_rate, size_t stepsPerHour, const std::vector& monthly_load_forecast, const std::vector& monthly_gen_forecast, const std::vector& monthly_avg_load_forecast, size_t analysis_period) : current_composite_buy_rates(), current_composite_sell_rates(), next_composite_buy_rates(), @@ -143,7 +143,7 @@ UtilityRateForecast::UtilityRateForecast(rate_data* util_rate, size_t stepsPerHo rate = std::shared_ptr(new rate_data(*util_rate)); m_monthly_load_forecast = monthly_load_forecast; m_monthly_gen_forecast = monthly_gen_forecast; - m_monthly_peak_forecast = monthly_peak_forecast; + m_monthly_avg_load_forecast = monthly_avg_load_forecast; nyears = analysis_period; } @@ -153,7 +153,7 @@ UtilityRateForecast::UtilityRateForecast(UtilityRateForecast& tmp) : last_step(tmp.last_step), m_monthly_load_forecast(tmp.m_monthly_load_forecast), m_monthly_gen_forecast(tmp.m_monthly_gen_forecast), - m_monthly_peak_forecast(tmp.m_monthly_peak_forecast), + m_monthly_avg_load_forecast(tmp.m_monthly_avg_load_forecast), current_composite_buy_rates(tmp.current_composite_buy_rates), current_composite_sell_rates(tmp.current_composite_sell_rates), next_composite_buy_rates(tmp.next_composite_buy_rates), @@ -198,10 +198,7 @@ double UtilityRateForecast::forecastCost(std::vector& predicted_loads, s if (crossing_month) { initializeMonth(month_at_end, year_at_end); - if (n > 1) - { - previousDemandCharge += rate->get_demand_charge(month_at_end, year_at_end); - } + previousDemandCharge += rate->get_demand_charge(month_at_end, year_at_end); } double newEnergyCharge = 0; @@ -248,9 +245,20 @@ double UtilityRateForecast::forecastCost(std::vector& predicted_loads, s } } - // Compute new peak cost - may need to run two months - double newDemandCharge = rate->get_demand_charge(month, year); - if (crossing_month && n > 1) + // Compute new peak cost - may need to run two months + double newDemandCharge = rate->get_demand_charge(month, year); + // If forecast length is 1, restartMonth won't be triggered on the next forecast. Trigger it now + if (crossing_month && n == 1) + { + if (rate->enable_nm) + { + newEnergyCharge += getEnergyChargeNetMetering(month, current_composite_buy_rates, current_composite_sell_rates); + } + restartMonth(month, month_at_end, year_at_end); + copyTOUForecast(); + } + + if (crossing_month) { newDemandCharge += rate->get_demand_charge(month_at_end, year_at_end); if (rate->enable_nm) @@ -263,13 +271,6 @@ double UtilityRateForecast::forecastCost(std::vector& predicted_loads, s newEnergyCharge += getEnergyChargeNetMetering(month, current_composite_buy_rates, current_composite_sell_rates); } - // If forecast length is 1, restartMonth won't be triggered on the next forecast. Trigger it now - if (crossing_month && n == 1) - { - restartMonth(month, month_at_end, year_at_end); - copyTOUForecast(); - } - cost += newDemandCharge + newEnergyCharge - previousDemandCharge - previousEnergyCharge; return cost; @@ -381,7 +382,8 @@ void UtilityRateForecast::initializeMonth(int month, size_t year) rate->init_dc_peak_vectors(month); compute_next_composite_tou(month, year); - double avg_load = m_monthly_load_forecast[year * 12 + month] / util::hours_in_month(month + (int) 1); + // Ignore any peak charges lower than the average gross load - this prevents the price signal from showing demand charges on the first hour of each month when the load is not really a peak + double avg_load = m_monthly_avg_load_forecast[year * 12 + month]; ur_month& curr_month = rate->m_month[month]; curr_month.dc_flat_peak = avg_load; @@ -405,7 +407,6 @@ void UtilityRateForecast::restartMonth(int prevMonth, int currentMonth, size_t y { ur_month& prev_month = rate->m_month[prevMonth]; ur_month& curr_month = rate->m_month[currentMonth]; - curr_month.reset(); rate->compute_surplus(prev_month); bool skip_rollover = (currentMonth == 0 && year == 0) || (currentMonth == rate->net_metering_credit_month + 1) || (currentMonth == 0 && rate->net_metering_credit_month == 11); @@ -413,6 +414,7 @@ void UtilityRateForecast::restartMonth(int prevMonth, int currentMonth, size_t y { rate->transfer_surplus(curr_month, prev_month); } + prev_month.reset(); } double UtilityRateForecast::getEnergyChargeNetMetering(int month, std::vector& buy_rates, std::vector& sell_rates) diff --git a/shared/lib_utility_rate.h b/shared/lib_utility_rate.h index 7ba78d078de..bd4f021826a 100644 --- a/shared/lib_utility_rate.h +++ b/shared/lib_utility_rate.h @@ -156,9 +156,12 @@ class UtilityRateForecast int last_month_init; size_t nyears; + // Load: total net energy from the grid over the month std::vector m_monthly_load_forecast; // Length is 12 * analysis period + // gen: total net energy to the grid (generation) over the month std::vector m_monthly_gen_forecast; // Length is 12 * analysis period - std::vector m_monthly_peak_forecast; // Length is 12 * analysis period + // Avg load: the average gross load (no gen) over the month. Used to establish a floor for peak shaving costs + std::vector m_monthly_avg_load_forecast; // Length is 12 * analysis period }; diff --git a/ssc/cmod_battery.cpp b/ssc/cmod_battery.cpp index 2e29bdf6466..1f49b916e39 100644 --- a/ssc/cmod_battery.cpp +++ b/ssc/cmod_battery.cpp @@ -161,8 +161,8 @@ var_info vtab_battery_inputs[] = { { SSC_INPUT, SSC_ARRAY, "batt_pv_ac_forecast", "PV ac power forecast", "kW", "", "BatteryDispatch", "", "", "" }, // cycle cost inputs - { SSC_INPUT, SSC_NUMBER, "batt_cycle_cost_choice", "Use SAM cost model for degradaton penalty or input custom via batt_cycle_cost", "0/1", "0=UseCostModel,1=InputCost", "BatterySystem", "", "", "" }, - { SSC_INPUT, SSC_ARRAY, "batt_cycle_cost", "Input battery cycle degradaton penalty per year", "$/cycle-kWh","length 1 or analysis_period, length 1 will be extended using inflation", "BatterySystem", "", "", "" }, + { SSC_INPUT, SSC_NUMBER, "batt_cycle_cost_choice", "Use SAM cost model for degradaton penalty or input custom via batt_cycle_cost", "0/1", "0=UseCostModel,1=InputCost", "BatterySystem", "?=0", "", "" }, + { SSC_INPUT, SSC_ARRAY, "batt_cycle_cost", "Input battery cycle degradaton penalty per year", "$/cycle-kWh","length 1 or analysis_period, length 1 will be extended using inflation", "BatterySystem", "batt_cycle_cost_choice=1", "", "" }, { SSC_INPUT, SSC_NUMBER, "inflation_rate", "Inflation rate", "%", "", "Lifetime", "?=0", "MIN=-99", "" }, { SSC_INPUT, SSC_ARRAY, "load_escalation", "Annual load escalation", "%/year", "", "Load", "?=0", "", "" }, @@ -320,6 +320,12 @@ battstor::battstor(var_table& vt, bool setup_model, size_t nrec, double dt_hr, c batt_vars->batt_Vfull = vt.as_double("batt_Vfull"); batt_vars->batt_Vexp = vt.as_double("batt_Vexp"); batt_vars->batt_Vnom = vt.as_double("batt_Vnom"); + //Voltage error checking + if (batt_vars->batt_voltage_choice==0 && + ((batt_vars->batt_Vfull < batt_vars->batt_Vexp) || + batt_vars->batt_Vexp < batt_vars->batt_Vnom)) { + throw exec_error("battery", "For the electrochemical battery voltage model, voltage inputs must meet the requirement Vfull > Vexp > Vnom."); + } batt_vars->batt_Qfull_flow = vt.as_double("batt_Qfull_flow"); batt_vars->batt_Qfull = vt.as_double("batt_Qfull"); batt_vars->batt_Qexp = vt.as_double("batt_Qexp"); @@ -374,20 +380,23 @@ battstor::battstor(var_table& vt, bool setup_model, size_t nrec, double dt_hr, c // compute utility rate out-years escalation multipliers std::vector cycle_cost(nyears); - ssc_number_t* parr = vt.as_array("batt_cycle_cost", &cnt); - if (cnt == 1) - { - for (i = 0; i < nyears; i++) - cycle_cost[i] = parr[0] * (ssc_number_t)pow((double)(inflation_rate + 1), (double)i); - } - else if (cnt < nyears) - { - throw exec_error("battery", "invalid number for batt_cycle_cost, must be 1 or equal to analysis_period"); - } - else + if (batt_vars->batt_cycle_cost_choice == 1) { - for (i = 0; i < nyears; i++) - cycle_cost[i] = parr[i]; + ssc_number_t* parr = vt.as_array("batt_cycle_cost", &cnt); + if (cnt == 1) + { + for (i = 0; i < nyears; i++) + cycle_cost[i] = parr[0] * (ssc_number_t)pow((double)(inflation_rate + 1), (double)i); + } + else if (cnt < nyears) + { + throw exec_error("battery", "Invalid number for batt_cycle_cost, must be 1 or equal to analysis_period."); + } + else + { + for (i = 0; i < nyears; i++) + cycle_cost[i] = parr[i]; + } } batt_vars->batt_cycle_cost = cycle_cost; @@ -396,7 +405,7 @@ battstor::battstor(var_table& vt, bool setup_model, size_t nrec, double dt_hr, c if (vt.is_assigned("om_replacement_cost1")) { std::vector replacement_cost(nyears); - parr = vt.as_array("om_replacement_cost1", &cnt); + ssc_number_t* parr = vt.as_array("om_replacement_cost1", &cnt); if (cnt == 1) { for (i = 0; i < nyears; i++) @@ -404,7 +413,7 @@ battstor::battstor(var_table& vt, bool setup_model, size_t nrec, double dt_hr, c } else if (cnt < nyears) { - throw exec_error("battery", "invalid number for om_replacement_cost1, must be 1 or equal to analysis_period"); + throw exec_error("battery", "Invalid number for om_replacement_cost1, must be 1 or equal to analysis_period."); } else { for (i = 0; i < nyears; i++) @@ -496,7 +505,7 @@ battstor::battstor(var_table& vt, bool setup_model, size_t nrec, double dt_hr, c target_power = batt_vars->target_power; if (target_power.size() != nrec) - throw exec_error("battery", "invalid number of target powers, must be equal to number of records in weather file"); + throw exec_error("battery", "Invalid number of target powers, must be equal to number of records in weather file."); // extend target power to lifetime internally for (size_t y = 1; y < nyears; y++) { @@ -681,7 +690,7 @@ battstor::battstor(var_table& vt, bool setup_model, size_t nrec, double dt_hr, c if (!batt_vars->system_use_lifetime_output){ if (batt_vars->batt_replacement_option > 0) - throw exec_error("battery", "Replacements are enabled without running lifetime simulation, please run over lifetime to consider battery replacements"); + throw exec_error("battery", "Battery replacements are enabled with single year simulation. You must enable lifetime simulations to model battery replacements."); } total_steps = nyears * 8760 * step_per_hour; chem = batt_vars->batt_chem; @@ -828,7 +837,7 @@ battstor::battstor(var_table& vt, bool setup_model, size_t nrec, double dt_hr, c } if (batt_vars->T_room.size() != nrec) { - throw exec_error("battery", "Environment temperature input length must equal number of weather file records"); + throw exec_error("battery", "Environment temperature input length must equal number of weather file records."); } if (batt_vars->batt_life_model == 1) { @@ -885,7 +894,7 @@ battstor::battstor(var_table& vt, bool setup_model, size_t nrec, double dt_hr, c } else if (batt_vars->batt_loss_choice == losses_params::SCHEDULE) { if (!(batt_vars->batt_losses.size() == 1 || batt_vars->batt_losses.size() == nrec)) { - throw exec_error("battery", "system loss input length must be 1 or equal to weather file length for time series input mode"); + throw exec_error("battery", "System loss input length must be 1 or equal to weather file length for time series input mode."); } losses_model = new losses_t(batt_vars->batt_losses); } @@ -910,28 +919,28 @@ battstor::battstor(var_table& vt, bool setup_model, size_t nrec, double dt_hr, c { /*! Generic manual dispatch model inputs */ if (batt_vars->batt_can_charge.size() != 6 || batt_vars->batt_can_discharge.size() != 6 || batt_vars->batt_can_gridcharge.size() != 6) - throw exec_error("battery", "invalid manual dispatch control vector lengths, must be length 6"); + throw exec_error("battery", "Invalid manual dispatch control vector length, must be length 6."); if (batt_vars->batt_discharge_schedule_weekday.nrows() != 12 || batt_vars->batt_discharge_schedule_weekday.ncols() != 24) - throw exec_error("battery", "invalid manual dispatch schedule matrix dimensions, must be 12 x 24"); + throw exec_error("battery", "Invalid manual dispatch schedule matrix dimensions, must be 12 x 24."); size_t max_period = 6; size_t* discharge_schedule_vec = batt_vars->batt_discharge_schedule_weekday.data(); size_t* period_num = std::find_if(discharge_schedule_vec, discharge_schedule_vec + batt_vars->batt_discharge_schedule_weekday.ncells() - 1, [max_period](double element) { return (max_period < element); }); if (*period_num > max_period) - throw exec_error("battery", "invalid manual dispatch period in weekday schedule. Period numbers must be less than or equal to 6"); + throw exec_error("battery", "Invalid manual dispatch period in weekday schedule. Period numbers must be less than or equal to 6."); if (batt_vars->batt_discharge_schedule_weekend.nrows() != 12 || batt_vars->batt_discharge_schedule_weekend.ncols() != 24) - throw exec_error("battery", "invalid weekend manual dispatch schedule matrix dimensions, must be 12 x 24"); + throw exec_error("battery", "Invalid weekend manual dispatch schedule matrix dimensions, must be 12 x 24."); discharge_schedule_vec = batt_vars->batt_discharge_schedule_weekend.data(); period_num = std::find_if(discharge_schedule_vec, discharge_schedule_vec + batt_vars->batt_discharge_schedule_weekend.ncells() - 1, [max_period](double element) { return (max_period < element); }); if (*period_num > max_period) - throw exec_error("battery", "invalid manual dispatch period in weekend schedule. Period numbers must be less than or equal to 6"); + throw exec_error("battery", "Invalid manual dispatch period in weekend schedule. Period numbers must be less than or equal to 6."); if (batt_vars->en_fuelcell) { if (batt_vars->batt_can_fuelcellcharge.size() != 6) - throw exec_error("fuelcell", "invalid manual dispatch control vector lengths, must be length 6"); + throw exec_error("fuelcell", "Invalid manual dispatch control vector lengths, must be length 6."); } @@ -996,7 +1005,7 @@ battstor::battstor(var_table& vt, bool setup_model, size_t nrec, double dt_hr, c if (dispatch_automatic_front_of_meter_t * dispatch_fom = dynamic_cast(dispatch_model)) { if (batt_vars->batt_custom_dispatch.size() != 8760 * step_per_hour) { - throw exec_error("battery", "invalid custom dispatch, must be 8760 * steps_per_hour"); + throw exec_error("battery", "Invalid custom dispatch length, must be 8760 * steps_per_hour."); } dispatch_fom->set_custom_dispatch(batt_vars->batt_custom_dispatch); } @@ -1026,7 +1035,7 @@ battstor::battstor(var_table& vt, bool setup_model, size_t nrec, double dt_hr, c if (dispatch_automatic_behind_the_meter_t * dispatch_btm = dynamic_cast(dispatch_model)) { if (batt_vars->batt_custom_dispatch.size() != 8760 * step_per_hour) { - throw exec_error("battery", "invalid custom dispatch, must be 8760 * steps_per_hour"); + throw exec_error("battery", "Invalid custom dispatch, must be 8760 * steps_per_hour."); } dispatch_btm->set_custom_dispatch(batt_vars->batt_custom_dispatch); } @@ -1600,7 +1609,7 @@ class cm_battery : public compute_module size_t analysis_period = (size_t)as_integer("analysis_period"); if (use_lifetime && (double)(util::hours_per_year * analysis_period) / n_rec_lifetime > 1) - throw exec_error("battery", "`gen` input must be lifetime when system_use_lifetime_output=1."); + throw exec_error("battery", "Input gen must be from lifetime simulation when system_use_lifetime_output=1."); size_t n_rec_single_year; double dt_hour_gen; @@ -1630,10 +1639,10 @@ class cm_battery : public compute_module batt->initialize_automated_dispatch(power_input_lifetime, load_lifetime); if (load_lifetime.size() != n_rec_lifetime) { - throw exec_error("battery", "Load length does not match system generation length"); + throw exec_error("battery", "Load length does not match system generation length."); } if (batt->batt_vars->batt_topology == ChargeController::DC_CONNECTED) { - throw exec_error("battery", "Generic System must be AC connected to battery"); + throw exec_error("battery", "Generic System must be AC connected to battery."); } // resilience metrics for battery @@ -1643,7 +1652,7 @@ class cm_battery : public compute_module p_crit_load = as_vector_ssc_number_t("crit_load"); size_t nload = p_crit_load.size(); if (nload != n_rec_single_year) - throw exec_error("battery", "electric load profile must have same number of values as weather file, or 8760"); + throw exec_error("battery", "Electric load profile must have same number of values as weather file, or 8760."); if (!p_crit_load.empty() && *std::max_element(p_crit_load.begin(), p_crit_load.end()) > 0){ resilience = std::unique_ptr(new resilience_runner(batt)); auto logs = resilience->get_logs(); @@ -1689,7 +1698,7 @@ class cm_battery : public compute_module float techs = 3; percent = percent_complete + 100.0f * ((float)lifetime_idx + 1) / ((float)n_rec_lifetime) / techs; if (!update("", percent, (float)hour)) { - throw exec_error("battery", "simulation canceled at hour " + util::to_string(hour + 1.0)); + throw exec_error("battery", "Simulation canceled at hour " + util::to_string(hour + 1.0)); } } diff --git a/ssc/cmod_merchantplant.cpp b/ssc/cmod_merchantplant.cpp index fb5719c18f7..2353519034a 100644 --- a/ssc/cmod_merchantplant.cpp +++ b/ssc/cmod_merchantplant.cpp @@ -566,25 +566,25 @@ static var_info _cm_vtab_merchantplant[] = { { SSC_OUTPUT, SSC_NUMBER, "npv_thermal_value", "Present value of thermal value", "$", "", "Metrics", "*", "", "" }, // Additional lifetime outputs for data tables and plotting. // calculated revenue - { SSC_OUTPUT, SSC_ARRAY, "mp_energy_market_generated_revenue", "Energy market generated revenue", "$", "", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "mp_ancillary_services1_generated_revenue", "Ancillary services 1 generated revenue", "$", "", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "mp_ancillary_services2_generated_revenue", "Ancillary services 2 generated revenue", "$", "", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "mp_ancillary_services3_generated_revenue", "Ancillary services 3 generated revenue", "$", "", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "mp_ancillary_services4_generated_revenue", "Ancillary services 4 generated revenue", "$", "", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "mp_energy_market_generated_revenue", "Energy market generated revenue", "$", "", "", "*", "", "GROUP=LIFETIME_MP" }, + { SSC_OUTPUT, SSC_ARRAY, "mp_ancillary_services1_generated_revenue", "Ancillary services 1 generated revenue", "$", "", "", "*", "", "GROUP=LIFETIME_MP" }, + { SSC_OUTPUT, SSC_ARRAY, "mp_ancillary_services2_generated_revenue", "Ancillary services 2 generated revenue", "$", "", "", "*", "", "GROUP=LIFETIME_MP" }, + { SSC_OUTPUT, SSC_ARRAY, "mp_ancillary_services3_generated_revenue", "Ancillary services 3 generated revenue", "$", "", "", "*", "", "GROUP=LIFETIME_MP" }, + { SSC_OUTPUT, SSC_ARRAY, "mp_ancillary_services4_generated_revenue", "Ancillary services 4 generated revenue", "$", "", "", "*", "", "GROUP=LIFETIME_MP" }, // cleared capacity user input - { SSC_OUTPUT, SSC_ARRAY, "mp_energy_market_cleared_capacity", "Energy market cleared capacity", "MW", "", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "mp_ancillary_services1_cleared_capacity", "Ancillary services 1 cleared capacity", "MW", "", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "mp_ancillary_services2_cleared_capacity", "Ancillary services 2 cleared capacity", "MW", "", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "mp_ancillary_services3_cleared_capacity", "Ancillary services 3 cleared capacity", "MW", "", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "mp_ancillary_services4_cleared_capacity", "Ancillary services 4 cleared capacity", "MW", "", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "mp_energy_market_cleared_capacity", "Energy market cleared capacity", "MW", "", "", "*", "", "GROUP=LIFETIME_MP" }, + { SSC_OUTPUT, SSC_ARRAY, "mp_ancillary_services1_cleared_capacity", "Ancillary services 1 cleared capacity", "MW", "", "", "*", "", "GROUP=LIFETIME_MP" }, + { SSC_OUTPUT, SSC_ARRAY, "mp_ancillary_services2_cleared_capacity", "Ancillary services 2 cleared capacity", "MW", "", "", "*", "", "GROUP=LIFETIME_MP" }, + { SSC_OUTPUT, SSC_ARRAY, "mp_ancillary_services3_cleared_capacity", "Ancillary services 3 cleared capacity", "MW", "", "", "*", "", "GROUP=LIFETIME_MP" }, + { SSC_OUTPUT, SSC_ARRAY, "mp_ancillary_services4_cleared_capacity", "Ancillary services 4 cleared capacity", "MW", "", "", "*", "", "GROUP=LIFETIME_MP" }, // price user input - { SSC_OUTPUT, SSC_ARRAY, "mp_energy_market_price", "Energy market price", "$/MWh", "", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "mp_ancillary_services1_price", "Ancillary services 1 generated price", "$/MWh", "", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "mp_ancillary_services2_price", "Ancillary services 2 generated price", "$/MWh", "", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "mp_ancillary_services3_price", "Ancillary services 3 generated price", "$/MWh", "", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "mp_ancillary_services4_price", "Ancillary services 4 generated price", "$/MWh", "", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "mp_energy_market_price", "Energy market price", "$/MWh", "", "", "*", "", "GROUP=LIFETIME_MP" }, + { SSC_OUTPUT, SSC_ARRAY, "mp_ancillary_services1_price", "Ancillary services 1 generated price", "$/MWh", "", "", "*", "", "GROUP=LIFETIME_MP" }, + { SSC_OUTPUT, SSC_ARRAY, "mp_ancillary_services2_price", "Ancillary services 2 generated price", "$/MWh", "", "", "*", "", "GROUP=LIFETIME_MP" }, + { SSC_OUTPUT, SSC_ARRAY, "mp_ancillary_services3_price", "Ancillary services 3 generated price", "$/MWh", "", "", "*", "", "GROUP=LIFETIME_MP" }, + { SSC_OUTPUT, SSC_ARRAY, "mp_ancillary_services4_price", "Ancillary services 4 generated price", "$/MWh", "", "", "*", "", "GROUP=LIFETIME_MP" }, // sum of all cleared capacities - { SSC_OUTPUT, SSC_ARRAY, "mp_total_cleared_capacity", "Total cleared capacity", "MW", "", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "mp_total_cleared_capacity", "Total cleared capacity", "MW", "", "", "*", "", "GROUP=LIFETIME_MP" }, diff --git a/ssc/cmod_pvsamv1.cpp b/ssc/cmod_pvsamv1.cpp index 38f5e7a6a68..f81c3227cf6 100644 --- a/ssc/cmod_pvsamv1.cpp +++ b/ssc/cmod_pvsamv1.cpp @@ -969,10 +969,10 @@ void cm_pvsamv1::exec() { if (Subarrays[nn]->tiltEqualLatitude) Subarrays[nn]->tiltDegrees = fabs(Irradiance->weatherHeader.lat); - if (Subarrays[nn]->trackMode == irrad::SINGLE_AXIS && Subarrays[nn]->tiltDegrees > 0) - log(util::format("Subarray %d has one-axis tracking with a tilt angle of %f degrees. Large one-axis tracking arrays typically have a tilt angle of zero.", nn + 1, Subarrays[nn]->tiltDegrees), SSC_WARNING); - if (Subarrays[nn]->Module->isBifacial && (Subarrays[nn]->trackMode != irrad::FIXED_TILT)) - log(util::format("Subarray %d uses tracking with bifacial modules. The bifacial model is designed for fixed arrays and may not produce reliable results for tracking arrays.", nn + 1), SSC_WARNING); + if (Subarrays[nn]->trackMode == irrad::SINGLE_AXIS && Subarrays[nn]->tiltDegrees > 0 && !Subarrays[nn]->Module->isBifacial) + log(util::format("Subarray %d has one-axis tracking with a tilt angle of %f degrees. SAM can simulate one-axis tracking with non-zero tilt angles, but large one-axis tracking arrays typically have a tilt angle of zero. This message is a reminder in case you forgot to set the tilt angle to zero.", nn + 1, Subarrays[nn]->tiltDegrees), SSC_WARNING); + if (Subarrays[nn]->Module->isBifacial && Subarrays[nn]->trackMode == irrad::SINGLE_AXIS && Subarrays[nn]->tiltDegrees > 0) + log(util::format("Subarray %d uses bifacial modules with one-axis tracking and a tilt angle of %f degrees. The bifacial model is designed for one-axis tracking with a tilt angle of zero and may not produce reliable results for non-zero tilt angles.", nn + 1, Subarrays[nn]->tiltDegrees), SSC_WARNING); } // check for snow model with non-annual simulations: because snow model coefficients need to know the timestep, and we don't know timestep if non-annual diff --git a/ssc/cmod_utilityrate5.cpp b/ssc/cmod_utilityrate5.cpp index c2ba7215c9f..bb613875b81 100644 --- a/ssc/cmod_utilityrate5.cpp +++ b/ssc/cmod_utilityrate5.cpp @@ -292,8 +292,6 @@ void rate_setup::setup(var_table* vt, int num_recs_yearly, int nyears, rate_data } else { // hourly or sub hourly loads for single year - size_t cnt; - ssc_number_t* ts_br; ts_br = vt->as_array("ur_ts_buy_rate", &cnt); size_t ts_step_per_hour = cnt / 8760; if (ts_step_per_hour < 1 || ts_step_per_hour > 60 || ts_step_per_hour * 8760 != cnt) diff --git a/ssc/cmod_windpower.cpp b/ssc/cmod_windpower.cpp index 2d173dc3f60..b14a016c36b 100644 --- a/ssc/cmod_windpower.cpp +++ b/ssc/cmod_windpower.cpp @@ -40,8 +40,8 @@ static var_info _cm_vtab_windpower[] = { { SSC_INPUT , SSC_NUMBER , "wind_resource_shear" , "Shear exponent" , "" ,"" , "Turbine" , "*" , "MIN=0" , "" } , { SSC_INPUT , SSC_NUMBER , "wind_turbine_rotor_diameter" , "Rotor diameter" , "m" ,"" , "Turbine" , "*" , "POSITIVE" , "" } , - { SSC_INOUT , SSC_ARRAY , "wind_turbine_powercurve_windspeeds" , "Power curve wind speed array" , "m/s" ,"" , "Turbine" , "*" , "" , "" } , - { SSC_INOUT , SSC_ARRAY , "wind_turbine_powercurve_powerout" , "Power curve turbine output array" , "kW" ,"" , "Turbine" , "*" , "LENGTH_EQUAL=wind_turbine_powercurve_windspeeds" , "" } , + { SSC_INOUT , SSC_ARRAY , "wind_turbine_powercurve_windspeeds" , "Power curve wind speed array" , "m/s" ,"" , "Turbine" , "*" , "" , "GROUP=WTPCD" } , + { SSC_INOUT , SSC_ARRAY , "wind_turbine_powercurve_powerout" , "Power curve turbine output array" , "kW" ,"" , "Turbine" , "*" , "LENGTH_EQUAL=wind_turbine_powercurve_windspeeds" , "GROUP=WTPCD" } , { SSC_INPUT , SSC_NUMBER , "wind_turbine_hub_ht" , "Hub height" , "m" ,"" , "Turbine" , "*" , "POSITIVE" , "" } , { SSC_INPUT , SSC_NUMBER , "wind_turbine_max_cp" , "Max Coefficient of Power" , "" ,"" , "Turbine" , "wind_resource_model_choice=1" , "MIN=0" , "" } , diff --git a/test/input_cases/battery_common_data.h b/test/input_cases/battery_common_data.h index 6af3b02d0c3..baf0e74b3a5 100644 --- a/test/input_cases/battery_common_data.h +++ b/test/input_cases/battery_common_data.h @@ -124,8 +124,6 @@ namespace { ssc_number_t p_ur_ec_tou_mat[24] = { 1, 1, 200, 1, 0.21174600720405579, 0.028000000864267349, 1, 2, 400, 1, 0.057693801820278168, 0.028000000864267349, 1, 3, 600, 1, 0.052770901471376419, 0.028000000864267349, 1, 4, 10000, 1, 0.049003798514604568, 0.028000000864267349 }; ssc_data_set_matrix(data, "ur_ec_tou_mat", p_ur_ec_tou_mat, 4, 6); ssc_data_set_number(data, "batt_cycle_cost_choice", 0); - ssc_number_t p_batt_cycle_cost[1] = { 0.1 }; - ssc_data_set_array(data, "batt_cycle_cost", p_batt_cycle_cost, 1); } } #endif diff --git a/test/input_cases/csp_financial_defaults.cpp b/test/input_cases/csp_financial_defaults.cpp new file mode 100644 index 00000000000..260f41244c2 --- /dev/null +++ b/test/input_cases/csp_financial_defaults.cpp @@ -0,0 +1,260 @@ +#include "../input_cases/code_generator_utilities.h" + +/** +* Default parameters for the PPA singleowner (utility) financial model +*/ +ssc_data_t singleowner_defaults() +{ + ssc_data_t data = ssc_data_create(); + + ssc_data_set_number(data, "analysis_period", 25); + ssc_number_t p_federal_tax_rate[1] = { 21 }; + ssc_data_set_array(data, "federal_tax_rate", p_federal_tax_rate, 1); + ssc_number_t p_state_tax_rate[1] = { 7 }; + ssc_data_set_array(data, "state_tax_rate", p_state_tax_rate, 1); + ssc_data_set_number(data, "property_tax_rate", 0); + ssc_data_set_number(data, "prop_tax_cost_assessed_percent", 100); + ssc_data_set_number(data, "prop_tax_assessed_decline", 0); + ssc_data_set_number(data, "real_discount_rate", 6.4000000953674316); + ssc_data_set_number(data, "inflation_rate", 2.5); + ssc_data_set_number(data, "insurance_rate", 0.5); + ssc_data_set_number(data, "system_capacity", 99899.9921875); + ssc_number_t p_om_fixed[1] = { 0 }; + ssc_data_set_array(data, "om_fixed", p_om_fixed, 1); + ssc_data_set_number(data, "om_fixed_escal", 0); + ssc_number_t p_om_production[1] = { 4 }; + ssc_data_set_array(data, "om_production", p_om_production, 1); + ssc_data_set_number(data, "om_production_escal", 0); + ssc_number_t p_om_capacity[1] = { 66 }; + ssc_data_set_array(data, "om_capacity", p_om_capacity, 1); + ssc_data_set_number(data, "om_capacity_escal", 0); + ssc_number_t p_om_fuel_cost[1] = { 0 }; + ssc_data_set_array(data, "om_fuel_cost", p_om_fuel_cost, 1); + ssc_data_set_number(data, "om_fuel_cost_escal", 0); + ssc_number_t p_om_replacement_cost1[1] = { 0 }; + ssc_data_set_array(data, "om_replacement_cost1", p_om_replacement_cost1, 1); + ssc_data_set_number(data, "om_replacement_cost_escal", 0); + ssc_data_set_number(data, "itc_fed_amount", 0); + ssc_data_set_number(data, "itc_fed_amount_deprbas_fed", 1); + ssc_data_set_number(data, "itc_fed_amount_deprbas_sta", 1); + ssc_data_set_number(data, "itc_sta_amount", 0); + ssc_data_set_number(data, "itc_sta_amount_deprbas_fed", 0); + ssc_data_set_number(data, "itc_sta_amount_deprbas_sta", 0); + ssc_data_set_number(data, "itc_fed_percent", 30); + ssc_data_set_number(data, "itc_fed_percent_maxvalue", 9.9999996802856925e+37); + ssc_data_set_number(data, "itc_fed_percent_deprbas_fed", 1); + ssc_data_set_number(data, "itc_fed_percent_deprbas_sta", 1); + ssc_data_set_number(data, "itc_sta_percent", 0); + ssc_data_set_number(data, "itc_sta_percent_maxvalue", 9.9999996802856925e+37); + ssc_data_set_number(data, "itc_sta_percent_deprbas_fed", 0); + ssc_data_set_number(data, "itc_sta_percent_deprbas_sta", 0); + ssc_number_t p_ptc_fed_amount[1] = { 0 }; + ssc_data_set_array(data, "ptc_fed_amount", p_ptc_fed_amount, 1); + ssc_data_set_number(data, "ptc_fed_term", 10); + ssc_data_set_number(data, "ptc_fed_escal", 0); + ssc_number_t p_ptc_sta_amount[1] = { 0 }; + ssc_data_set_array(data, "ptc_sta_amount", p_ptc_sta_amount, 1); + ssc_data_set_number(data, "ptc_sta_term", 10); + ssc_data_set_number(data, "ptc_sta_escal", 0); + ssc_data_set_number(data, "ibi_fed_amount", 0); + ssc_data_set_number(data, "ibi_fed_amount_tax_fed", 1); + ssc_data_set_number(data, "ibi_fed_amount_tax_sta", 1); + ssc_data_set_number(data, "ibi_fed_amount_deprbas_fed", 0); + ssc_data_set_number(data, "ibi_fed_amount_deprbas_sta", 0); + ssc_data_set_number(data, "ibi_sta_amount", 0); + ssc_data_set_number(data, "ibi_sta_amount_tax_fed", 1); + ssc_data_set_number(data, "ibi_sta_amount_tax_sta", 1); + ssc_data_set_number(data, "ibi_sta_amount_deprbas_fed", 0); + ssc_data_set_number(data, "ibi_sta_amount_deprbas_sta", 0); + ssc_data_set_number(data, "ibi_uti_amount", 0); + ssc_data_set_number(data, "ibi_uti_amount_tax_fed", 1); + ssc_data_set_number(data, "ibi_uti_amount_tax_sta", 1); + ssc_data_set_number(data, "ibi_uti_amount_deprbas_fed", 0); + ssc_data_set_number(data, "ibi_uti_amount_deprbas_sta", 0); + ssc_data_set_number(data, "ibi_oth_amount", 0); + ssc_data_set_number(data, "ibi_oth_amount_tax_fed", 1); + ssc_data_set_number(data, "ibi_oth_amount_tax_sta", 1); + ssc_data_set_number(data, "ibi_oth_amount_deprbas_fed", 0); + ssc_data_set_number(data, "ibi_oth_amount_deprbas_sta", 0); + ssc_data_set_number(data, "ibi_fed_percent", 0); + ssc_data_set_number(data, "ibi_fed_percent_maxvalue", 9.9999996802856925e+37); + ssc_data_set_number(data, "ibi_fed_percent_tax_fed", 1); + ssc_data_set_number(data, "ibi_fed_percent_tax_sta", 1); + ssc_data_set_number(data, "ibi_fed_percent_deprbas_fed", 0); + ssc_data_set_number(data, "ibi_fed_percent_deprbas_sta", 0); + ssc_data_set_number(data, "ibi_sta_percent", 0); + ssc_data_set_number(data, "ibi_sta_percent_maxvalue", 9.9999996802856925e+37); + ssc_data_set_number(data, "ibi_sta_percent_tax_fed", 1); + ssc_data_set_number(data, "ibi_sta_percent_tax_sta", 1); + ssc_data_set_number(data, "ibi_sta_percent_deprbas_fed", 0); + ssc_data_set_number(data, "ibi_sta_percent_deprbas_sta", 0); + ssc_data_set_number(data, "ibi_uti_percent", 0); + ssc_data_set_number(data, "ibi_uti_percent_maxvalue", 9.9999996802856925e+37); + ssc_data_set_number(data, "ibi_uti_percent_tax_fed", 1); + ssc_data_set_number(data, "ibi_uti_percent_tax_sta", 1); + ssc_data_set_number(data, "ibi_uti_percent_deprbas_fed", 0); + ssc_data_set_number(data, "ibi_uti_percent_deprbas_sta", 0); + ssc_data_set_number(data, "ibi_oth_percent", 0); + ssc_data_set_number(data, "ibi_oth_percent_maxvalue", 9.9999996802856925e+37); + ssc_data_set_number(data, "ibi_oth_percent_tax_fed", 1); + ssc_data_set_number(data, "ibi_oth_percent_tax_sta", 1); + ssc_data_set_number(data, "ibi_oth_percent_deprbas_fed", 0); + ssc_data_set_number(data, "ibi_oth_percent_deprbas_sta", 0); + ssc_data_set_number(data, "cbi_fed_amount", 0); + ssc_data_set_number(data, "cbi_fed_maxvalue", 9.9999996802856925e+37); + ssc_data_set_number(data, "cbi_fed_tax_fed", 1); + ssc_data_set_number(data, "cbi_fed_tax_sta", 1); + ssc_data_set_number(data, "cbi_fed_deprbas_fed", 0); + ssc_data_set_number(data, "cbi_fed_deprbas_sta", 0); + ssc_data_set_number(data, "cbi_sta_amount", 0); + ssc_data_set_number(data, "cbi_sta_maxvalue", 9.9999996802856925e+37); + ssc_data_set_number(data, "cbi_sta_tax_fed", 1); + ssc_data_set_number(data, "cbi_sta_tax_sta", 1); + ssc_data_set_number(data, "cbi_sta_deprbas_fed", 0); + ssc_data_set_number(data, "cbi_sta_deprbas_sta", 0); + ssc_data_set_number(data, "cbi_uti_amount", 0); + ssc_data_set_number(data, "cbi_uti_maxvalue", 9.9999996802856925e+37); + ssc_data_set_number(data, "cbi_uti_tax_fed", 1); + ssc_data_set_number(data, "cbi_uti_tax_sta", 1); + ssc_data_set_number(data, "cbi_uti_deprbas_fed", 0); + ssc_data_set_number(data, "cbi_uti_deprbas_sta", 0); + ssc_data_set_number(data, "cbi_oth_amount", 0); + ssc_data_set_number(data, "cbi_oth_maxvalue", 9.9999996802856925e+37); + ssc_data_set_number(data, "cbi_oth_tax_fed", 1); + ssc_data_set_number(data, "cbi_oth_tax_sta", 1); + ssc_data_set_number(data, "cbi_oth_deprbas_fed", 0); + ssc_data_set_number(data, "cbi_oth_deprbas_sta", 0); + ssc_number_t p_pbi_fed_amount[1] = { 0 }; + ssc_data_set_array(data, "pbi_fed_amount", p_pbi_fed_amount, 1); + ssc_data_set_number(data, "pbi_fed_term", 0); + ssc_data_set_number(data, "pbi_fed_escal", 0); + ssc_data_set_number(data, "pbi_fed_tax_fed", 1); + ssc_data_set_number(data, "pbi_fed_tax_sta", 1); + ssc_number_t p_pbi_sta_amount[1] = { 0 }; + ssc_data_set_array(data, "pbi_sta_amount", p_pbi_sta_amount, 1); + ssc_data_set_number(data, "pbi_sta_term", 0); + ssc_data_set_number(data, "pbi_sta_escal", 0); + ssc_data_set_number(data, "pbi_sta_tax_fed", 1); + ssc_data_set_number(data, "pbi_sta_tax_sta", 1); + ssc_number_t p_pbi_uti_amount[1] = { 0 }; + ssc_data_set_array(data, "pbi_uti_amount", p_pbi_uti_amount, 1); + ssc_data_set_number(data, "pbi_uti_term", 0); + ssc_data_set_number(data, "pbi_uti_escal", 0); + ssc_data_set_number(data, "pbi_uti_tax_fed", 1); + ssc_data_set_number(data, "pbi_uti_tax_sta", 1); + ssc_number_t p_pbi_oth_amount[1] = { 0 }; + ssc_data_set_array(data, "pbi_oth_amount", p_pbi_oth_amount, 1); + ssc_data_set_number(data, "pbi_oth_term", 0); + ssc_data_set_number(data, "pbi_oth_escal", 0); + ssc_data_set_number(data, "pbi_oth_tax_fed", 1); + ssc_data_set_number(data, "pbi_oth_tax_sta", 1); + ssc_number_t p_degradation[1] = { 0 }; + ssc_data_set_array(data, "degradation", p_degradation, 1); + ssc_number_t p_roe_input[1] = { 0 }; + ssc_data_set_array(data, "roe_input", p_roe_input, 1); + ssc_data_set_number(data, "loan_moratorium", 0); + ssc_data_set_number(data, "system_use_recapitalization", 0); + ssc_data_set_number(data, "system_use_lifetime_output", 0); + ssc_data_set_number(data, "total_installed_cost", 562201472); + ssc_data_set_number(data, "reserves_interest", 1.75); + ssc_data_set_number(data, "equip1_reserve_cost", 0); + ssc_data_set_number(data, "equip1_reserve_freq", 12); + ssc_data_set_number(data, "equip2_reserve_cost", 0); + ssc_data_set_number(data, "equip2_reserve_freq", 15); + ssc_data_set_number(data, "equip3_reserve_cost", 0); + ssc_data_set_number(data, "equip3_reserve_freq", 3); + ssc_data_set_number(data, "equip_reserve_depr_sta", 0); + ssc_data_set_number(data, "equip_reserve_depr_fed", 0); + ssc_data_set_number(data, "salvage_percentage", 0); + ssc_data_set_number(data, "ppa_soln_mode", 0); + ssc_number_t p_ppa_price_input[1] = { 0.13 }; + ssc_data_set_array(data, "ppa_price_input", p_ppa_price_input, 1); + ssc_data_set_number(data, "cp_capacity_payment_esc", 0); + ssc_data_set_number(data, "cp_capacity_payment_type", 0); + ssc_data_set_number(data, "cp_system_nameplate", 0); + ssc_data_set_number(data, "cp_battery_nameplate", 0); + ssc_data_set_array(data, "cp_capacity_credit_percent", p_ppa_price_input, 1); + ssc_data_set_array(data, "cp_capacity_payment_amount", p_ppa_price_input, 1); + ssc_data_set_number(data, "ppa_escalation", 1); + ssc_data_set_number(data, "construction_financing_cost", 28110074); + ssc_data_set_number(data, "term_tenor", 18); + ssc_data_set_number(data, "term_int_rate", 7); + ssc_data_set_number(data, "dscr", 1.2999999523162842); + ssc_data_set_number(data, "dscr_reserve_months", 6); + ssc_data_set_number(data, "debt_percent", 50); + ssc_data_set_number(data, "debt_option", 1); + ssc_data_set_number(data, "payment_option", 0); + ssc_data_set_number(data, "cost_debt_closing", 450000); + ssc_data_set_number(data, "cost_debt_fee", 2.75); + ssc_data_set_number(data, "months_working_reserve", 6); + ssc_data_set_number(data, "months_receivables_reserve", 0); + ssc_data_set_number(data, "cost_other_financing", 0); + ssc_data_set_number(data, "flip_target_percent", 11); + ssc_data_set_number(data, "flip_target_year", 20); + ssc_data_set_number(data, "depr_alloc_macrs_5_percent", 90); + ssc_data_set_number(data, "depr_alloc_macrs_15_percent", 1.5); + ssc_data_set_number(data, "depr_alloc_sl_5_percent", 0); + ssc_data_set_number(data, "depr_alloc_sl_15_percent", 2.5); + ssc_data_set_number(data, "depr_alloc_sl_20_percent", 3); + ssc_data_set_number(data, "depr_alloc_sl_39_percent", 0); + ssc_data_set_number(data, "depr_alloc_custom_percent", 0); + ssc_number_t p_depr_custom_schedule[1] = { 0 }; + ssc_data_set_array(data, "depr_custom_schedule", p_depr_custom_schedule, 1); + ssc_data_set_number(data, "depr_bonus_sta", 0); + ssc_data_set_number(data, "depr_bonus_sta_macrs_5", 1); + ssc_data_set_number(data, "depr_bonus_sta_macrs_15", 1); + ssc_data_set_number(data, "depr_bonus_sta_sl_5", 0); + ssc_data_set_number(data, "depr_bonus_sta_sl_15", 0); + ssc_data_set_number(data, "depr_bonus_sta_sl_20", 0); + ssc_data_set_number(data, "depr_bonus_sta_sl_39", 0); + ssc_data_set_number(data, "depr_bonus_sta_custom", 0); + ssc_data_set_number(data, "depr_bonus_fed", 0); + ssc_data_set_number(data, "depr_bonus_fed_macrs_5", 1); + ssc_data_set_number(data, "depr_bonus_fed_macrs_15", 1); + ssc_data_set_number(data, "depr_bonus_fed_sl_5", 0); + ssc_data_set_number(data, "depr_bonus_fed_sl_15", 0); + ssc_data_set_number(data, "depr_bonus_fed_sl_20", 0); + ssc_data_set_number(data, "depr_bonus_fed_sl_39", 0); + ssc_data_set_number(data, "depr_bonus_fed_custom", 0); + ssc_data_set_number(data, "depr_itc_sta_macrs_5", 1); + ssc_data_set_number(data, "depr_itc_sta_macrs_15", 0); + ssc_data_set_number(data, "depr_itc_sta_sl_5", 0); + ssc_data_set_number(data, "depr_itc_sta_sl_15", 0); + ssc_data_set_number(data, "depr_itc_sta_sl_20", 0); + ssc_data_set_number(data, "depr_itc_sta_sl_39", 0); + ssc_data_set_number(data, "depr_itc_sta_custom", 0); + ssc_data_set_number(data, "depr_itc_fed_macrs_5", 1); + ssc_data_set_number(data, "depr_itc_fed_macrs_15", 0); + ssc_data_set_number(data, "depr_itc_fed_sl_5", 0); + ssc_data_set_number(data, "depr_itc_fed_sl_15", 0); + ssc_data_set_number(data, "depr_itc_fed_sl_20", 0); + ssc_data_set_number(data, "depr_itc_fed_sl_39", 0); + ssc_data_set_number(data, "depr_itc_fed_custom", 0); + ssc_data_set_number(data, "pbi_fed_for_ds", 0); + ssc_data_set_number(data, "pbi_sta_for_ds", 0); + ssc_data_set_number(data, "pbi_uti_for_ds", 0); + ssc_data_set_number(data, "pbi_oth_for_ds", 0); + ssc_data_set_number(data, "depr_stabas_method", 1); + ssc_data_set_number(data, "depr_fedbas_method", 1); + + return data; +} + +/** +* Default data for iph_to_lcoefcr +*/ +void convert_and_adjust_fixed_charge(ssc_data_t& data) +{ + ssc_data_set_number(data, "electricity_rate", 0.059999998658895493); + ssc_data_set_number(data, "fixed_operating_cost", 103758.203125); +} + +/** +* Default data for lcoefcr +*/ +void fixed_charge_rate_default(ssc_data_t& data) +{ + ssc_data_set_number(data, "capital_cost", 7263074); + ssc_data_set_number(data, "variable_operating_cost", 0.0010000000474974513); + ssc_data_set_number(data, "fixed_charge_rate", 0.10807877779006958); +} diff --git a/test/tcs_test/tcsdirect_steam_common_data.h b/test/input_cases/tcsdirect_steam_defaults.h similarity index 98% rename from test/tcs_test/tcsdirect_steam_common_data.h rename to test/input_cases/tcsdirect_steam_defaults.h index 5314b99df57..3fb3fba1b0e 100644 --- a/test/tcs_test/tcsdirect_steam_common_data.h +++ b/test/input_cases/tcsdirect_steam_defaults.h @@ -1,8 +1,7 @@ -#ifndef _TCSDIRECT_STEAM_COMMON_DATA_H_ -#define _TCSDIRECT_STEAM_COMMON_DATA_H_ +#ifndef _TCSDIRECT_STEAM_DEFAULTS_H_ +#define _TCSDIRECT_STEAM_DEFAULTS_H_ #include - #include "../input_cases/code_generator_utilities.h" //const char * SSCDIR = std::getenv("SSCDIR"); @@ -10,22 +9,20 @@ char ndspt_dispatch_factors_path[512]; char ndspt_helio_positions_path[512]; - - int ndspt1 = sprintf(ndspt_dispatch_factors_path, "%s/test/input_cases/directsteam_data/dispatch_factors_ts.csv", std::getenv("SSCDIR")); int ndspt2 = sprintf(ndspt_helio_positions_path, "%s/test/input_cases/directsteam_data/helio_positions.csv", std::getenv("SSCDIR")); /** -* Default data for tcsdirect_steam run that can be further modified +* Default data for tcsdirect_steam technology model */ -void tcsdirect_steam_default(ssc_data_t &data) +ssc_data_t tcsdirect_steam_defaults() { + ssc_data_t data = ssc_data_create(); + char solar_resource_path_default[512]; int n1 = sprintf(solar_resource_path_default, "%s/test/input_cases/directsteam_data/daggett_ca_34.865371_-116.783023_psmv3_60_tmy.csv", std::getenv("SSCDIR")); ssc_data_set_string(data, "solar_resource_file", solar_resource_path_default); - - ssc_data_set_number(data, "system_capacity", 100125); ssc_number_t p_weekday_schedule[288] = { 6, 6, 6, 6, 6, 6, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 6, 6, 6, 6, 6, 6, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 6, 6, 6, 6, 6, 6, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 6, 6, 6, 6, 6, 6, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 6, 6, 6, 6, 6, 6, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 6, 6, 6, 6, 6, 6, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 6, 6, 6, 6, 6, 6, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 6, 6, 6, 6, 6, 6, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5 }; ssc_data_set_matrix(data, "weekday_schedule", p_weekday_schedule, 12, 24); @@ -191,9 +188,8 @@ void tcsdirect_steam_default(ssc_data_t &data) ssc_data_set_number(data, "bop_par_2", 0); ssc_data_set_number(data, "adjust:constant", 4); ssc_data_set_number(data, "sf_adjust:constant", 0); -} - - + return data; +} #endif diff --git a/test/tcs_test/tcsfresnel_molten_salt_common_data.h b/test/input_cases/tcsfresnel_molten_salt_defaults.h similarity index 98% rename from test/tcs_test/tcsfresnel_molten_salt_common_data.h rename to test/input_cases/tcsfresnel_molten_salt_defaults.h index 8cbeb293129..251554d1e52 100644 --- a/test/tcs_test/tcsfresnel_molten_salt_common_data.h +++ b/test/input_cases/tcsfresnel_molten_salt_defaults.h @@ -1,23 +1,22 @@ -#ifndef _TCSFRESNEL_MOLTEN_SALT_COMMON_DATA_H_ -#define _TCSFRESNEL_MOLTEN_SALT_COMMON_DATA_H_ +#ifndef _TCSFRESNEL_MOLTEN_SALT_DEFAULTS_H_ +#define _TCSFRESNEL_MOLTEN_SALT_DEFAULTS_H_ #include - #include "../input_cases/code_generator_utilities.h" //const char * SSCDIR = std::getenv("SSCDIR"); //const char * SAMNTDIR = std::getenv("SAMNTDIR"); char nlfms_ud_ind_od_path[512]; - - int nlfms1 = sprintf(nlfms_ud_ind_od_path, "%s/test/input_cases/linearfresnel_molten_salt_data/ud_ind_od.csv", std::getenv("SSCDIR")); /** -* Default data for tcsfresnel_molten_salt run that can be further modified +* Default data for tcsfresnel_molten_salt technology model */ -void tcsfresnel_molten_salt_default(ssc_data_t &data) +ssc_data_t tcsfresnel_molten_salt_defaults() { + ssc_data_t data = ssc_data_create(); + char solar_resource_path[512]; // This is a copy of the actual weather file used, which has been copied to the ssc repo so it can be found by Travis CI for its tests. // The actual weather file used by SAM could change and thus change the UI output values (different input (i.e., weather file) -> different outputs) @@ -253,6 +252,7 @@ void tcsfresnel_molten_salt_default(ssc_data_t &data) ssc_data_set_number(data, "T_htf_cold_ref", 293); ssc_data_set_number(data, "adjust:constant", 4); + return data; } #endif diff --git a/test/tcs_test/tcsmolten_salt_common_data.h b/test/input_cases/tcsmolten_salt_defaults.h similarity index 61% rename from test/tcs_test/tcsmolten_salt_common_data.h rename to test/input_cases/tcsmolten_salt_defaults.h index f1e5fee32c3..52384ec461a 100644 --- a/test/tcs_test/tcsmolten_salt_common_data.h +++ b/test/input_cases/tcsmolten_salt_defaults.h @@ -1,8 +1,7 @@ -#ifndef _TCSMOLTEN_SALT_COMMON_DATA_H_ -#define _TCSMOLTEN_SALT_COMMON_DATA_H_ +#ifndef _TCSMOLTEN_SALT_DEFAULTS_H_ +#define _TCSMOLTEN_SALT_DEFAULTS_H_ #include - #include "../input_cases/code_generator_utilities.h" //const char * SSCDIR = std::getenv("SSCDIR"); @@ -12,18 +11,18 @@ char dispatch_factors_path[512]; char ud_ind_od_path[512]; char wlim_series_path[512]; char helio_positions_path[512]; - - int nmspt1 = sprintf(dispatch_factors_path, "%s/test/input_cases/moltensalt_data/dispatch_factors_ts.csv", std::getenv("SSCDIR")); int nmspt2 = sprintf(ud_ind_od_path, "%s/test/input_cases/moltensalt_data/ud_ind_od.csv", std::getenv("SSCDIR")); int nmspt3 = sprintf(wlim_series_path, "%s/test/input_cases/moltensalt_data/wlim_series.csv", std::getenv("SSCDIR")); int nmspt4 = sprintf(helio_positions_path, "%s/test/input_cases/moltensalt_data/helio_positions.csv", std::getenv("SSCDIR")); /** -* Default data for tcsmolten_salt run that can be further modified +* Default parameters for tcsmolten_salt technology model */ -void tcsmolten_salt_default(ssc_data_t &data) +ssc_data_t tcsmolten_salt_defaults() { + ssc_data_t data = ssc_data_create(); + char solar_resource_path[512]; // This is a copy of the actual weather file used, which has been copied to the ssc repo so it can be found by Travis CI for its tests. // The actual weather file used by SAM could change and thus change the UI output values (different input (i.e., weather file) -> different outputs) @@ -312,239 +311,7 @@ void tcsmolten_salt_default(ssc_data_t &data) ssc_data_set_number(data, "adjust:constant", 4); ssc_data_set_number(data, "sf_adjust:constant", 0); -} - -/** -* Default data for the PPA single owner (utility) run that can be further modified -*/ -void single_owner_default(ssc_data_t &data) -{ - ssc_data_set_number(data, "analysis_period", 25); - ssc_number_t p_federal_tax_rate[1] = { 21 }; - ssc_data_set_array(data, "federal_tax_rate", p_federal_tax_rate, 1); - ssc_number_t p_state_tax_rate[1] = { 7 }; - ssc_data_set_array(data, "state_tax_rate", p_state_tax_rate, 1); - ssc_data_set_number(data, "property_tax_rate", 0); - ssc_data_set_number(data, "prop_tax_cost_assessed_percent", 100); - ssc_data_set_number(data, "prop_tax_assessed_decline", 0); - ssc_data_set_number(data, "real_discount_rate", 6.4); - ssc_data_set_number(data, "inflation_rate", 2.5); - ssc_data_set_number(data, "insurance_rate", 0.5); - ssc_data_set_number(data, "system_capacity", 103500); - ssc_number_t p_om_fixed[1] = { 0 }; - ssc_data_set_array(data, "om_fixed", p_om_fixed, 1); - ssc_data_set_number(data, "om_fixed_escal", 0); - ssc_number_t p_om_production[1] = { 3.5 }; - ssc_data_set_array(data, "om_production", p_om_production, 1); - ssc_data_set_number(data, "om_production_escal", 0); - ssc_number_t p_om_capacity[1] = { 66 }; - ssc_data_set_array(data, "om_capacity", p_om_capacity, 1); - ssc_data_set_number(data, "om_capacity_escal", 0); - ssc_number_t p_om_fuel_cost[1] = { 0 }; - ssc_data_set_array(data, "om_fuel_cost", p_om_fuel_cost, 1); - ssc_data_set_number(data, "om_fuel_cost_escal", 0); - ssc_data_set_number(data, "itc_fed_amount", 0); - ssc_data_set_number(data, "itc_fed_amount_deprbas_fed", 1); - ssc_data_set_number(data, "itc_fed_amount_deprbas_sta", 1); - ssc_data_set_number(data, "itc_sta_amount", 0); - ssc_data_set_number(data, "itc_sta_amount_deprbas_fed", 0); - ssc_data_set_number(data, "itc_sta_amount_deprbas_sta", 0); - ssc_data_set_number(data, "itc_fed_percent", 30); - ssc_data_set_number(data, "itc_fed_percent_maxvalue", 10e+37); - ssc_data_set_number(data, "itc_fed_percent_deprbas_fed", 1); - ssc_data_set_number(data, "itc_fed_percent_deprbas_sta", 1); - ssc_data_set_number(data, "itc_sta_percent", 0); - ssc_data_set_number(data, "itc_sta_percent_maxvalue", 10e+37); - ssc_data_set_number(data, "itc_sta_percent_deprbas_fed", 0); - ssc_data_set_number(data, "itc_sta_percent_deprbas_sta", 0); - ssc_number_t p_ptc_fed_amount[1] = { 0 }; - ssc_data_set_array(data, "ptc_fed_amount", p_ptc_fed_amount, 1); - ssc_data_set_number(data, "ptc_fed_term", 10); - ssc_data_set_number(data, "ptc_fed_escal", 0); - ssc_number_t p_ptc_sta_amount[1] = { 0 }; - ssc_data_set_array(data, "ptc_sta_amount", p_ptc_sta_amount, 1); - ssc_data_set_number(data, "ptc_sta_term", 10); - ssc_data_set_number(data, "ptc_sta_escal", 0); - ssc_data_set_number(data, "ibi_fed_amount", 0); - ssc_data_set_number(data, "ibi_fed_amount_tax_fed", 1); - ssc_data_set_number(data, "ibi_fed_amount_tax_sta", 1); - ssc_data_set_number(data, "ibi_fed_amount_deprbas_fed", 0); - ssc_data_set_number(data, "ibi_fed_amount_deprbas_sta", 0); - ssc_data_set_number(data, "ibi_sta_amount", 0); - ssc_data_set_number(data, "ibi_sta_amount_tax_fed", 1); - ssc_data_set_number(data, "ibi_sta_amount_tax_sta", 1); - ssc_data_set_number(data, "ibi_sta_amount_deprbas_fed", 0); - ssc_data_set_number(data, "ibi_sta_amount_deprbas_sta", 0); - ssc_data_set_number(data, "ibi_uti_amount", 0); - ssc_data_set_number(data, "ibi_uti_amount_tax_fed", 1); - ssc_data_set_number(data, "ibi_uti_amount_tax_sta", 1); - ssc_data_set_number(data, "ibi_uti_amount_deprbas_fed", 0); - ssc_data_set_number(data, "ibi_uti_amount_deprbas_sta", 0); - ssc_data_set_number(data, "ibi_oth_amount", 0); - ssc_data_set_number(data, "ibi_oth_amount_tax_fed", 1); - ssc_data_set_number(data, "ibi_oth_amount_tax_sta", 1); - ssc_data_set_number(data, "ibi_oth_amount_deprbas_fed", 0); - ssc_data_set_number(data, "ibi_oth_amount_deprbas_sta", 0); - ssc_data_set_number(data, "ibi_fed_percent", 0); - ssc_data_set_number(data, "ibi_fed_percent_maxvalue", 10e+37); - ssc_data_set_number(data, "ibi_fed_percent_tax_fed", 1); - ssc_data_set_number(data, "ibi_fed_percent_tax_sta", 1); - ssc_data_set_number(data, "ibi_fed_percent_deprbas_fed", 0); - ssc_data_set_number(data, "ibi_fed_percent_deprbas_sta", 0); - ssc_data_set_number(data, "ibi_sta_percent", 0); - ssc_data_set_number(data, "ibi_sta_percent_maxvalue", 10e+37); - ssc_data_set_number(data, "ibi_sta_percent_tax_fed", 1); - ssc_data_set_number(data, "ibi_sta_percent_tax_sta", 1); - ssc_data_set_number(data, "ibi_sta_percent_deprbas_fed", 0); - ssc_data_set_number(data, "ibi_sta_percent_deprbas_sta", 0); - ssc_data_set_number(data, "ibi_uti_percent", 0); - ssc_data_set_number(data, "ibi_uti_percent_maxvalue", 10e+37); - ssc_data_set_number(data, "ibi_uti_percent_tax_fed", 1); - ssc_data_set_number(data, "ibi_uti_percent_tax_sta", 1); - ssc_data_set_number(data, "ibi_uti_percent_deprbas_fed", 0); - ssc_data_set_number(data, "ibi_uti_percent_deprbas_sta", 0); - ssc_data_set_number(data, "ibi_oth_percent", 0); - ssc_data_set_number(data, "ibi_oth_percent_maxvalue", 10e+37); - ssc_data_set_number(data, "ibi_oth_percent_tax_fed", 1); - ssc_data_set_number(data, "ibi_oth_percent_tax_sta", 1); - ssc_data_set_number(data, "ibi_oth_percent_deprbas_fed", 0); - ssc_data_set_number(data, "ibi_oth_percent_deprbas_sta", 0); - ssc_data_set_number(data, "cbi_fed_amount", 0); - ssc_data_set_number(data, "cbi_fed_maxvalue", 10e+37); - ssc_data_set_number(data, "cbi_fed_tax_fed", 1); - ssc_data_set_number(data, "cbi_fed_tax_sta", 1); - ssc_data_set_number(data, "cbi_fed_deprbas_fed", 0); - ssc_data_set_number(data, "cbi_fed_deprbas_sta", 0); - ssc_data_set_number(data, "cbi_sta_amount", 0); - ssc_data_set_number(data, "cbi_sta_maxvalue", 10e+37); - ssc_data_set_number(data, "cbi_sta_tax_fed", 1); - ssc_data_set_number(data, "cbi_sta_tax_sta", 1); - ssc_data_set_number(data, "cbi_sta_deprbas_fed", 0); - ssc_data_set_number(data, "cbi_sta_deprbas_sta", 0); - ssc_data_set_number(data, "cbi_uti_amount", 0); - ssc_data_set_number(data, "cbi_uti_maxvalue", 10e+37); - ssc_data_set_number(data, "cbi_uti_tax_fed", 1); - ssc_data_set_number(data, "cbi_uti_tax_sta", 1); - ssc_data_set_number(data, "cbi_uti_deprbas_fed", 0); - ssc_data_set_number(data, "cbi_uti_deprbas_sta", 0); - ssc_data_set_number(data, "cbi_oth_amount", 0); - ssc_data_set_number(data, "cbi_oth_maxvalue", 10e+37); - ssc_data_set_number(data, "cbi_oth_tax_fed", 1); - ssc_data_set_number(data, "cbi_oth_tax_sta", 1); - ssc_data_set_number(data, "cbi_oth_deprbas_fed", 0); - ssc_data_set_number(data, "cbi_oth_deprbas_sta", 0); - ssc_number_t p_pbi_fed_amount[1] = { 0 }; - ssc_data_set_array(data, "pbi_fed_amount", p_pbi_fed_amount, 1); - ssc_data_set_number(data, "pbi_fed_term", 0); - ssc_data_set_number(data, "pbi_fed_escal", 0); - ssc_data_set_number(data, "pbi_fed_tax_fed", 1); - ssc_data_set_number(data, "pbi_fed_tax_sta", 1); - ssc_number_t p_pbi_sta_amount[1] = { 0 }; - ssc_data_set_array(data, "pbi_sta_amount", p_pbi_sta_amount, 1); - ssc_data_set_number(data, "pbi_sta_term", 0); - ssc_data_set_number(data, "pbi_sta_escal", 0); - ssc_data_set_number(data, "pbi_sta_tax_fed", 1); - ssc_data_set_number(data, "pbi_sta_tax_sta", 1); - ssc_number_t p_pbi_uti_amount[1] = { 0 }; - ssc_data_set_array(data, "pbi_uti_amount", p_pbi_uti_amount, 1); - ssc_data_set_number(data, "pbi_uti_term", 0); - ssc_data_set_number(data, "pbi_uti_escal", 0); - ssc_data_set_number(data, "pbi_uti_tax_fed", 1); - ssc_data_set_number(data, "pbi_uti_tax_sta", 1); - ssc_number_t p_pbi_oth_amount[1] = { 0 }; - ssc_data_set_array(data, "pbi_oth_amount", p_pbi_oth_amount, 1); - ssc_data_set_number(data, "pbi_oth_term", 0); - ssc_data_set_number(data, "pbi_oth_escal", 0); - ssc_data_set_number(data, "pbi_oth_tax_fed", 1); - ssc_data_set_number(data, "pbi_oth_tax_sta", 1); - ssc_number_t p_degradation[1] = { 0 }; - ssc_data_set_array(data, "degradation", p_degradation, 1); - ssc_number_t p_roe_input[1] = { 0 }; - ssc_data_set_array(data, "roe_input", p_roe_input, 1); - ssc_data_set_number(data, "loan_moratorium", 0); - ssc_data_set_number(data, "system_use_recapitalization", 0); - ssc_data_set_number(data, "system_use_lifetime_output", 0); - ssc_data_set_number(data, "total_installed_cost", 673465536); - ssc_data_set_number(data, "reserves_interest", 1.75); - ssc_data_set_number(data, "equip1_reserve_cost", 0); - ssc_data_set_number(data, "equip1_reserve_freq", 12); - ssc_data_set_number(data, "equip2_reserve_cost", 0); - ssc_data_set_number(data, "equip2_reserve_freq", 15); - ssc_data_set_number(data, "equip3_reserve_cost", 0); - ssc_data_set_number(data, "equip3_reserve_freq", 3); - ssc_data_set_number(data, "equip_reserve_depr_sta", 0); - ssc_data_set_number(data, "equip_reserve_depr_fed", 0); - ssc_data_set_number(data, "salvage_percentage", 0); - ssc_data_set_number(data, "ppa_soln_mode", 0); - ssc_number_t p_ppa_price_input[1] = { 0.13 }; - ssc_data_set_array(data, "ppa_price_input", p_ppa_price_input, 1); - ssc_data_set_number(data, "cp_capacity_payment_esc", 0); - ssc_data_set_number(data, "cp_capacity_payment_type", 0); - ssc_data_set_number(data, "cp_system_nameplate", 0); - ssc_data_set_number(data, "cp_battery_nameplate", 0); - ssc_data_set_array(data, "cp_capacity_credit_percent", p_ppa_price_input, 1); - ssc_data_set_array(data, "cp_capacity_payment_amount", p_ppa_price_input, 1); - ssc_data_set_number(data, "ppa_escalation", 1); - ssc_data_set_number(data, "construction_financing_cost", 33673276); - ssc_data_set_number(data, "term_tenor", 18); - ssc_data_set_number(data, "term_int_rate", 7); - ssc_data_set_number(data, "dscr", 1.3); - ssc_data_set_number(data, "dscr_reserve_months", 6); - ssc_data_set_number(data, "debt_percent", 50); - ssc_data_set_number(data, "debt_option", 1); - ssc_data_set_number(data, "payment_option", 0); - ssc_data_set_number(data, "cost_debt_closing", 450000); - ssc_data_set_number(data, "cost_debt_fee", 2.75); - ssc_data_set_number(data, "months_working_reserve", 6); - ssc_data_set_number(data, "months_receivables_reserve", 0); - ssc_data_set_number(data, "cost_other_financing", 0); - ssc_data_set_number(data, "flip_target_percent", 11); - ssc_data_set_number(data, "flip_target_year", 20); - ssc_data_set_number(data, "depr_alloc_macrs_5_percent", 90); - ssc_data_set_number(data, "depr_alloc_macrs_15_percent", 1.5); - ssc_data_set_number(data, "depr_alloc_sl_5_percent", 0); - ssc_data_set_number(data, "depr_alloc_sl_15_percent", 2.5); - ssc_data_set_number(data, "depr_alloc_sl_20_percent", 3); - ssc_data_set_number(data, "depr_alloc_sl_39_percent", 0); - ssc_data_set_number(data, "depr_alloc_custom_percent", 0); - ssc_number_t p_depr_custom_schedule[1] = { 0 }; - ssc_data_set_array(data, "depr_custom_schedule", p_depr_custom_schedule, 1); - ssc_data_set_number(data, "depr_bonus_sta", 0); - ssc_data_set_number(data, "depr_bonus_sta_macrs_5", 1); - ssc_data_set_number(data, "depr_bonus_sta_macrs_15", 1); - ssc_data_set_number(data, "depr_bonus_sta_sl_5", 0); - ssc_data_set_number(data, "depr_bonus_sta_sl_15", 0); - ssc_data_set_number(data, "depr_bonus_sta_sl_20", 0); - ssc_data_set_number(data, "depr_bonus_sta_sl_39", 0); - ssc_data_set_number(data, "depr_bonus_sta_custom", 0); - ssc_data_set_number(data, "depr_bonus_fed", 0); - ssc_data_set_number(data, "depr_bonus_fed_macrs_5", 1); - ssc_data_set_number(data, "depr_bonus_fed_macrs_15", 1); - ssc_data_set_number(data, "depr_bonus_fed_sl_5", 0); - ssc_data_set_number(data, "depr_bonus_fed_sl_15", 0); - ssc_data_set_number(data, "depr_bonus_fed_sl_20", 0); - ssc_data_set_number(data, "depr_bonus_fed_sl_39", 0); - ssc_data_set_number(data, "depr_bonus_fed_custom", 0); - ssc_data_set_number(data, "depr_itc_sta_macrs_5", 1); - ssc_data_set_number(data, "depr_itc_sta_macrs_15", 0); - ssc_data_set_number(data, "depr_itc_sta_sl_5", 0); - ssc_data_set_number(data, "depr_itc_sta_sl_15", 0); - ssc_data_set_number(data, "depr_itc_sta_sl_20", 0); - ssc_data_set_number(data, "depr_itc_sta_sl_39", 0); - ssc_data_set_number(data, "depr_itc_sta_custom", 0); - ssc_data_set_number(data, "depr_itc_fed_macrs_5", 1); - ssc_data_set_number(data, "depr_itc_fed_macrs_15", 0); - ssc_data_set_number(data, "depr_itc_fed_sl_5", 0); - ssc_data_set_number(data, "depr_itc_fed_sl_15", 0); - ssc_data_set_number(data, "depr_itc_fed_sl_20", 0); - ssc_data_set_number(data, "depr_itc_fed_sl_39", 0); - ssc_data_set_number(data, "depr_itc_fed_custom", 0); - ssc_data_set_number(data, "pbi_fed_for_ds", 0); - ssc_data_set_number(data, "pbi_sta_for_ds", 0); - ssc_data_set_number(data, "pbi_uti_for_ds", 0); - ssc_data_set_number(data, "pbi_oth_for_ds", 0); - ssc_data_set_number(data, "depr_stabas_method", 1); - ssc_data_set_number(data, "depr_fedbas_method", 1); + return data; } #endif diff --git a/test/tcs_test/tcstrough_empirical_common_data.h b/test/input_cases/tcstrough_empirical_defaults.h similarity index 97% rename from test/tcs_test/tcstrough_empirical_common_data.h rename to test/input_cases/tcstrough_empirical_defaults.h index e7f2669c9ce..3887bbc828c 100644 --- a/test/tcs_test/tcstrough_empirical_common_data.h +++ b/test/input_cases/tcstrough_empirical_defaults.h @@ -1,16 +1,16 @@ -#ifndef _TCSTROUGH_EMPIRICAL_COMMON_DATA_H -#define _TCSTROUGH_EMPIRICAL_COMMON_DATA_H +#ifndef _TCSTROUGH_EMPIRICAL_DEFAULTS_H +#define _TCSTROUGH_EMPIRICAL_DEFAULTS_H #include - #include "../input_cases/code_generator_utilities.h" - /** -* Default data for tcstrough_empirical run that can be further modified +* Default data for tcstrough_empirical technology model */ -void tcstrough_empirical_default(ssc_data_t &data) +ssc_data_t tcstrough_empirical_defaults() { + ssc_data_t data = ssc_data_create(); + char solar_resource_path[512]; int n1 = sprintf(solar_resource_path, "%s/test/input_cases/trough_empirical_data/tucson_az_32.116521_-110.933042_psmv3_60_tmy.csv", std::getenv("SSCDIR")); @@ -153,6 +153,8 @@ void tcstrough_empirical_default(ssc_data_t &data) ssc_data_set_number(data, "HhtfParF2", 0.79400000000000004); ssc_data_set_number(data, "PbFixPar", 0.61049997806549072); ssc_data_set_number(data, "adjust:constant", 4); + + return data; } #endif diff --git a/test/tcs_test/trough_physical_common_data.h b/test/input_cases/trough_physical_defaults.h similarity index 65% rename from test/tcs_test/trough_physical_common_data.h rename to test/input_cases/trough_physical_defaults.h index f5dcc8ad360..0b67d0d2026 100644 --- a/test/tcs_test/trough_physical_common_data.h +++ b/test/input_cases/trough_physical_defaults.h @@ -1,8 +1,7 @@ -#ifndef _TROUGH_PHYSICAL_COMMON_DATA_H_ -#define _TROUGH_PHYSICAL_COMMON_DATA_H_ +#ifndef _TROUGH_PHYSICAL_DEFAULTS_H_ +#define _TROUGH_PHYSICAL_DEFAULTS_H_ #include - #include "../input_cases/code_generator_utilities.h" //const char * SSCDIR = std::getenv("SSCDIR"); @@ -11,17 +10,17 @@ char dispatch_factors_path_tp[512]; char ud_ind_od_path_tp[512]; char wlim_series_path_tp[512]; - - int ntp1 = sprintf(dispatch_factors_path_tp, "%s/test/input_cases/moltensalt_data/dispatch_factors_ts.csv", std::getenv("SSCDIR")); int ntp2 = sprintf(ud_ind_od_path_tp, "%s/test/input_cases/moltensalt_data/ud_ind_od.csv", std::getenv("SSCDIR")); int ntp3 = sprintf(wlim_series_path_tp, "%s/test/input_cases/moltensalt_data/wlim_series.csv", std::getenv("SSCDIR")); /** -* Default data for trough_physical run that can be further modified +* Default data for trough_physical technology model */ -void trough_physical_default(ssc_data_t &data) +ssc_data_t trough_physical_defaults() { + ssc_data_t data = ssc_data_create(); + char solar_resource_path[512]; int n1 = sprintf(solar_resource_path, "%s/test/input_cases/tcstrough_data/tucson_az_32.116521_-110.933042_psmv3_60_tmy.csv", std::getenv("SSCDIR")); @@ -293,261 +292,8 @@ void trough_physical_default(ssc_data_t &data) ssc_data_set_matrix(data, "tes_lengths", p_tes_lengths, 1, 11); ssc_data_set_number(data, "DP_SGS", 0); ssc_data_set_number(data, "adjust:constant", 4); -} -/** -* Default data for the PPA single owner (utility) run that can be further modified -*/ -void trough_physical_single_owner_default(ssc_data_t &data) -{ - ssc_data_set_number(data, "analysis_period", 25); - ssc_number_t p_federal_tax_rate[1] = { 21 }; - ssc_data_set_array(data, "federal_tax_rate", p_federal_tax_rate, 1); - ssc_number_t p_state_tax_rate[1] = { 7 }; - ssc_data_set_array(data, "state_tax_rate", p_state_tax_rate, 1); - ssc_data_set_number(data, "property_tax_rate", 0); - ssc_data_set_number(data, "prop_tax_cost_assessed_percent", 100); - ssc_data_set_number(data, "prop_tax_assessed_decline", 0); - ssc_data_set_number(data, "real_discount_rate", 6.4000000953674316); - ssc_data_set_number(data, "inflation_rate", 2.5); - ssc_data_set_number(data, "insurance_rate", 0.5); - ssc_data_set_number(data, "system_capacity", 99899.9921875); - ssc_number_t p_om_fixed[1] = { 0 }; - ssc_data_set_array(data, "om_fixed", p_om_fixed, 1); - ssc_data_set_number(data, "om_fixed_escal", 0); - ssc_number_t p_om_production[1] = { 4 }; - ssc_data_set_array(data, "om_production", p_om_production, 1); - ssc_data_set_number(data, "om_production_escal", 0); - ssc_number_t p_om_capacity[1] = { 66 }; - ssc_data_set_array(data, "om_capacity", p_om_capacity, 1); - ssc_data_set_number(data, "om_capacity_escal", 0); - ssc_number_t p_om_fuel_cost[1] = { 0 }; - ssc_data_set_array(data, "om_fuel_cost", p_om_fuel_cost, 1); - ssc_data_set_number(data, "om_fuel_cost_escal", 0); - ssc_number_t p_om_replacement_cost1[1] = { 0 }; - ssc_data_set_array(data, "om_replacement_cost1", p_om_replacement_cost1, 1); - ssc_data_set_number(data, "om_replacement_cost_escal", 0); - ssc_data_set_number(data, "itc_fed_amount", 0); - ssc_data_set_number(data, "itc_fed_amount_deprbas_fed", 1); - ssc_data_set_number(data, "itc_fed_amount_deprbas_sta", 1); - ssc_data_set_number(data, "itc_sta_amount", 0); - ssc_data_set_number(data, "itc_sta_amount_deprbas_fed", 0); - ssc_data_set_number(data, "itc_sta_amount_deprbas_sta", 0); - ssc_data_set_number(data, "itc_fed_percent", 30); - ssc_data_set_number(data, "itc_fed_percent_maxvalue", 9.9999996802856925e+37); - ssc_data_set_number(data, "itc_fed_percent_deprbas_fed", 1); - ssc_data_set_number(data, "itc_fed_percent_deprbas_sta", 1); - ssc_data_set_number(data, "itc_sta_percent", 0); - ssc_data_set_number(data, "itc_sta_percent_maxvalue", 9.9999996802856925e+37); - ssc_data_set_number(data, "itc_sta_percent_deprbas_fed", 0); - ssc_data_set_number(data, "itc_sta_percent_deprbas_sta", 0); - ssc_number_t p_ptc_fed_amount[1] = { 0 }; - ssc_data_set_array(data, "ptc_fed_amount", p_ptc_fed_amount, 1); - ssc_data_set_number(data, "ptc_fed_term", 10); - ssc_data_set_number(data, "ptc_fed_escal", 0); - ssc_number_t p_ptc_sta_amount[1] = { 0 }; - ssc_data_set_array(data, "ptc_sta_amount", p_ptc_sta_amount, 1); - ssc_data_set_number(data, "ptc_sta_term", 10); - ssc_data_set_number(data, "ptc_sta_escal", 0); - ssc_data_set_number(data, "ibi_fed_amount", 0); - ssc_data_set_number(data, "ibi_fed_amount_tax_fed", 1); - ssc_data_set_number(data, "ibi_fed_amount_tax_sta", 1); - ssc_data_set_number(data, "ibi_fed_amount_deprbas_fed", 0); - ssc_data_set_number(data, "ibi_fed_amount_deprbas_sta", 0); - ssc_data_set_number(data, "ibi_sta_amount", 0); - ssc_data_set_number(data, "ibi_sta_amount_tax_fed", 1); - ssc_data_set_number(data, "ibi_sta_amount_tax_sta", 1); - ssc_data_set_number(data, "ibi_sta_amount_deprbas_fed", 0); - ssc_data_set_number(data, "ibi_sta_amount_deprbas_sta", 0); - ssc_data_set_number(data, "ibi_uti_amount", 0); - ssc_data_set_number(data, "ibi_uti_amount_tax_fed", 1); - ssc_data_set_number(data, "ibi_uti_amount_tax_sta", 1); - ssc_data_set_number(data, "ibi_uti_amount_deprbas_fed", 0); - ssc_data_set_number(data, "ibi_uti_amount_deprbas_sta", 0); - ssc_data_set_number(data, "ibi_oth_amount", 0); - ssc_data_set_number(data, "ibi_oth_amount_tax_fed", 1); - ssc_data_set_number(data, "ibi_oth_amount_tax_sta", 1); - ssc_data_set_number(data, "ibi_oth_amount_deprbas_fed", 0); - ssc_data_set_number(data, "ibi_oth_amount_deprbas_sta", 0); - ssc_data_set_number(data, "ibi_fed_percent", 0); - ssc_data_set_number(data, "ibi_fed_percent_maxvalue", 9.9999996802856925e+37); - ssc_data_set_number(data, "ibi_fed_percent_tax_fed", 1); - ssc_data_set_number(data, "ibi_fed_percent_tax_sta", 1); - ssc_data_set_number(data, "ibi_fed_percent_deprbas_fed", 0); - ssc_data_set_number(data, "ibi_fed_percent_deprbas_sta", 0); - ssc_data_set_number(data, "ibi_sta_percent", 0); - ssc_data_set_number(data, "ibi_sta_percent_maxvalue", 9.9999996802856925e+37); - ssc_data_set_number(data, "ibi_sta_percent_tax_fed", 1); - ssc_data_set_number(data, "ibi_sta_percent_tax_sta", 1); - ssc_data_set_number(data, "ibi_sta_percent_deprbas_fed", 0); - ssc_data_set_number(data, "ibi_sta_percent_deprbas_sta", 0); - ssc_data_set_number(data, "ibi_uti_percent", 0); - ssc_data_set_number(data, "ibi_uti_percent_maxvalue", 9.9999996802856925e+37); - ssc_data_set_number(data, "ibi_uti_percent_tax_fed", 1); - ssc_data_set_number(data, "ibi_uti_percent_tax_sta", 1); - ssc_data_set_number(data, "ibi_uti_percent_deprbas_fed", 0); - ssc_data_set_number(data, "ibi_uti_percent_deprbas_sta", 0); - ssc_data_set_number(data, "ibi_oth_percent", 0); - ssc_data_set_number(data, "ibi_oth_percent_maxvalue", 9.9999996802856925e+37); - ssc_data_set_number(data, "ibi_oth_percent_tax_fed", 1); - ssc_data_set_number(data, "ibi_oth_percent_tax_sta", 1); - ssc_data_set_number(data, "ibi_oth_percent_deprbas_fed", 0); - ssc_data_set_number(data, "ibi_oth_percent_deprbas_sta", 0); - ssc_data_set_number(data, "cbi_fed_amount", 0); - ssc_data_set_number(data, "cbi_fed_maxvalue", 9.9999996802856925e+37); - ssc_data_set_number(data, "cbi_fed_tax_fed", 1); - ssc_data_set_number(data, "cbi_fed_tax_sta", 1); - ssc_data_set_number(data, "cbi_fed_deprbas_fed", 0); - ssc_data_set_number(data, "cbi_fed_deprbas_sta", 0); - ssc_data_set_number(data, "cbi_sta_amount", 0); - ssc_data_set_number(data, "cbi_sta_maxvalue", 9.9999996802856925e+37); - ssc_data_set_number(data, "cbi_sta_tax_fed", 1); - ssc_data_set_number(data, "cbi_sta_tax_sta", 1); - ssc_data_set_number(data, "cbi_sta_deprbas_fed", 0); - ssc_data_set_number(data, "cbi_sta_deprbas_sta", 0); - ssc_data_set_number(data, "cbi_uti_amount", 0); - ssc_data_set_number(data, "cbi_uti_maxvalue", 9.9999996802856925e+37); - ssc_data_set_number(data, "cbi_uti_tax_fed", 1); - ssc_data_set_number(data, "cbi_uti_tax_sta", 1); - ssc_data_set_number(data, "cbi_uti_deprbas_fed", 0); - ssc_data_set_number(data, "cbi_uti_deprbas_sta", 0); - ssc_data_set_number(data, "cbi_oth_amount", 0); - ssc_data_set_number(data, "cbi_oth_maxvalue", 9.9999996802856925e+37); - ssc_data_set_number(data, "cbi_oth_tax_fed", 1); - ssc_data_set_number(data, "cbi_oth_tax_sta", 1); - ssc_data_set_number(data, "cbi_oth_deprbas_fed", 0); - ssc_data_set_number(data, "cbi_oth_deprbas_sta", 0); - ssc_number_t p_pbi_fed_amount[1] = { 0 }; - ssc_data_set_array(data, "pbi_fed_amount", p_pbi_fed_amount, 1); - ssc_data_set_number(data, "pbi_fed_term", 0); - ssc_data_set_number(data, "pbi_fed_escal", 0); - ssc_data_set_number(data, "pbi_fed_tax_fed", 1); - ssc_data_set_number(data, "pbi_fed_tax_sta", 1); - ssc_number_t p_pbi_sta_amount[1] = { 0 }; - ssc_data_set_array(data, "pbi_sta_amount", p_pbi_sta_amount, 1); - ssc_data_set_number(data, "pbi_sta_term", 0); - ssc_data_set_number(data, "pbi_sta_escal", 0); - ssc_data_set_number(data, "pbi_sta_tax_fed", 1); - ssc_data_set_number(data, "pbi_sta_tax_sta", 1); - ssc_number_t p_pbi_uti_amount[1] = { 0 }; - ssc_data_set_array(data, "pbi_uti_amount", p_pbi_uti_amount, 1); - ssc_data_set_number(data, "pbi_uti_term", 0); - ssc_data_set_number(data, "pbi_uti_escal", 0); - ssc_data_set_number(data, "pbi_uti_tax_fed", 1); - ssc_data_set_number(data, "pbi_uti_tax_sta", 1); - ssc_number_t p_pbi_oth_amount[1] = { 0 }; - ssc_data_set_array(data, "pbi_oth_amount", p_pbi_oth_amount, 1); - ssc_data_set_number(data, "pbi_oth_term", 0); - ssc_data_set_number(data, "pbi_oth_escal", 0); - ssc_data_set_number(data, "pbi_oth_tax_fed", 1); - ssc_data_set_number(data, "pbi_oth_tax_sta", 1); - ssc_number_t p_degradation[1] = { 0 }; - ssc_data_set_array(data, "degradation", p_degradation, 1); - ssc_number_t p_roe_input[1] = { 0 }; - ssc_data_set_array(data, "roe_input", p_roe_input, 1); - ssc_data_set_number(data, "loan_moratorium", 0); - ssc_data_set_number(data, "system_use_recapitalization", 0); - ssc_data_set_number(data, "system_use_lifetime_output", 0); - ssc_data_set_number(data, "total_installed_cost", 562201472); - ssc_data_set_number(data, "reserves_interest", 1.75); - ssc_data_set_number(data, "equip1_reserve_cost", 0); - ssc_data_set_number(data, "equip1_reserve_freq", 12); - ssc_data_set_number(data, "equip2_reserve_cost", 0); - ssc_data_set_number(data, "equip2_reserve_freq", 15); - ssc_data_set_number(data, "equip3_reserve_cost", 0); - ssc_data_set_number(data, "equip3_reserve_freq", 3); - ssc_data_set_number(data, "equip_reserve_depr_sta", 0); - ssc_data_set_number(data, "equip_reserve_depr_fed", 0); - ssc_data_set_number(data, "salvage_percentage", 0); - ssc_data_set_number(data, "ppa_soln_mode", 0); - ssc_number_t p_ppa_price_input[1] = { 0.13 }; - ssc_data_set_array(data, "ppa_price_input", p_ppa_price_input, 1); - ssc_data_set_number(data, "cp_capacity_payment_esc", 0); - ssc_data_set_number(data, "cp_capacity_payment_type", 0); - ssc_data_set_number(data, "cp_system_nameplate", 0); - ssc_data_set_number(data, "cp_battery_nameplate", 0); - ssc_data_set_array(data, "cp_capacity_credit_percent", p_ppa_price_input, 1); - ssc_data_set_array(data, "cp_capacity_payment_amount", p_ppa_price_input, 1); - ssc_data_set_number(data, "ppa_escalation", 1); - ssc_data_set_number(data, "construction_financing_cost", 28110074); - ssc_data_set_number(data, "term_tenor", 18); - ssc_data_set_number(data, "term_int_rate", 7); - ssc_data_set_number(data, "dscr", 1.2999999523162842); - ssc_data_set_number(data, "dscr_reserve_months", 6); - ssc_data_set_number(data, "debt_percent", 50); - ssc_data_set_number(data, "debt_option", 1); - ssc_data_set_number(data, "payment_option", 0); - ssc_data_set_number(data, "cost_debt_closing", 450000); - ssc_data_set_number(data, "cost_debt_fee", 2.75); - ssc_data_set_number(data, "months_working_reserve", 6); - ssc_data_set_number(data, "months_receivables_reserve", 0); - ssc_data_set_number(data, "cost_other_financing", 0); - ssc_data_set_number(data, "flip_target_percent", 11); - ssc_data_set_number(data, "flip_target_year", 20); - ssc_data_set_number(data, "depr_alloc_macrs_5_percent", 90); - ssc_data_set_number(data, "depr_alloc_macrs_15_percent", 1.5); - ssc_data_set_number(data, "depr_alloc_sl_5_percent", 0); - ssc_data_set_number(data, "depr_alloc_sl_15_percent", 2.5); - ssc_data_set_number(data, "depr_alloc_sl_20_percent", 3); - ssc_data_set_number(data, "depr_alloc_sl_39_percent", 0); - ssc_data_set_number(data, "depr_alloc_custom_percent", 0); - ssc_number_t p_depr_custom_schedule[1] = { 0 }; - ssc_data_set_array(data, "depr_custom_schedule", p_depr_custom_schedule, 1); - ssc_data_set_number(data, "depr_bonus_sta", 0); - ssc_data_set_number(data, "depr_bonus_sta_macrs_5", 1); - ssc_data_set_number(data, "depr_bonus_sta_macrs_15", 1); - ssc_data_set_number(data, "depr_bonus_sta_sl_5", 0); - ssc_data_set_number(data, "depr_bonus_sta_sl_15", 0); - ssc_data_set_number(data, "depr_bonus_sta_sl_20", 0); - ssc_data_set_number(data, "depr_bonus_sta_sl_39", 0); - ssc_data_set_number(data, "depr_bonus_sta_custom", 0); - ssc_data_set_number(data, "depr_bonus_fed", 0); - ssc_data_set_number(data, "depr_bonus_fed_macrs_5", 1); - ssc_data_set_number(data, "depr_bonus_fed_macrs_15", 1); - ssc_data_set_number(data, "depr_bonus_fed_sl_5", 0); - ssc_data_set_number(data, "depr_bonus_fed_sl_15", 0); - ssc_data_set_number(data, "depr_bonus_fed_sl_20", 0); - ssc_data_set_number(data, "depr_bonus_fed_sl_39", 0); - ssc_data_set_number(data, "depr_bonus_fed_custom", 0); - ssc_data_set_number(data, "depr_itc_sta_macrs_5", 1); - ssc_data_set_number(data, "depr_itc_sta_macrs_15", 0); - ssc_data_set_number(data, "depr_itc_sta_sl_5", 0); - ssc_data_set_number(data, "depr_itc_sta_sl_15", 0); - ssc_data_set_number(data, "depr_itc_sta_sl_20", 0); - ssc_data_set_number(data, "depr_itc_sta_sl_39", 0); - ssc_data_set_number(data, "depr_itc_sta_custom", 0); - ssc_data_set_number(data, "depr_itc_fed_macrs_5", 1); - ssc_data_set_number(data, "depr_itc_fed_macrs_15", 0); - ssc_data_set_number(data, "depr_itc_fed_sl_5", 0); - ssc_data_set_number(data, "depr_itc_fed_sl_15", 0); - ssc_data_set_number(data, "depr_itc_fed_sl_20", 0); - ssc_data_set_number(data, "depr_itc_fed_sl_39", 0); - ssc_data_set_number(data, "depr_itc_fed_custom", 0); - ssc_data_set_number(data, "pbi_fed_for_ds", 0); - ssc_data_set_number(data, "pbi_sta_for_ds", 0); - ssc_data_set_number(data, "pbi_uti_for_ds", 0); - ssc_data_set_number(data, "pbi_oth_for_ds", 0); - ssc_data_set_number(data, "depr_stabas_method", 1); - ssc_data_set_number(data, "depr_fedbas_method", 1); + return data; } -///** -//* Default data for iph_to_lcoefcr run that can be further modified -//*/ -//void convert_and_adjust_fixed_charge(ssc_data_t &data) -//{ -// ssc_data_set_number(data, "electricity_rate", 0.059999998658895493); -// ssc_data_set_number(data, "fixed_operating_cost", 103758.203125); -//} -// -///** -//* Default data for lcoefcr run that can be further modified -//*/ -//void fixed_charge_rate_default(ssc_data_t &data) -//{ -// ssc_data_set_number(data, "capital_cost", 7263074); -// ssc_data_set_number(data, "variable_operating_cost", 0.0010000000474974513); -// ssc_data_set_number(data, "fixed_charge_rate", 0.10807877779006958); -//} - #endif diff --git a/test/tcs_test/trough_physical_iph_common_data.h b/test/input_cases/trough_physical_iph_defaults.h similarity index 97% rename from test/tcs_test/trough_physical_iph_common_data.h rename to test/input_cases/trough_physical_iph_defaults.h index 5e68fcad0c1..d23509fe42e 100644 --- a/test/tcs_test/trough_physical_iph_common_data.h +++ b/test/input_cases/trough_physical_iph_defaults.h @@ -2,24 +2,21 @@ #define _TROUGH_PHYSICAL_IPH_COMMON_DATA_H_ #include - #include "../input_cases/code_generator_utilities.h" char wlim_series_path2[512]; - int ntpiph1 = sprintf(wlim_series_path2, "%s/test/input_cases/tcstrough_data/wlim_series.csv", std::getenv("SSCDIR")); /** * Default data for trough_physical_process_heat run that can be further modified */ -void trough_physical_iph_default(ssc_data_t &data) +ssc_data_t trough_physical_iph_defaults() { - const char * SSCDIR = std::getenv("SSCDIR"); + ssc_data_t data = ssc_data_create(); - char solar_resource_path[512]; + const char * SSCDIR = std::getenv("SSCDIR"); + char solar_resource_path[512]; //char load_profile_path[512]; - - int n1 = sprintf(solar_resource_path, "%s/test/input_cases/tcstrough_data/tucson_az_32.116521_-110.933042_psmv3_60_tmy.csv", SSCDIR); //int n2 = sprintf(load_profile_path, "%s/test/input_cases/pvsamv1_data/pvsamv1_residential_load.csv", SSCDIR); @@ -238,25 +235,8 @@ void trough_physical_iph_default(ssc_data_t &data) ssc_number_t p_sf_hdr_lengths[1] = { -1 }; ssc_data_set_matrix(data, "sf_hdr_lengths", p_sf_hdr_lengths, 1, 1); ssc_data_set_number(data, "adjust:constant", 4); -} -/** -* Default data for iph_to_lcoefcr run that can be further modified -*/ -void convert_and_adjust_fixed_charge(ssc_data_t &data) -{ - ssc_data_set_number(data, "electricity_rate", 0.059999998658895493); - ssc_data_set_number(data, "fixed_operating_cost", 103758.203125); -} - -/** -* Default data for lcoefcr run that can be further modified -*/ -void fixed_charge_rate_default(ssc_data_t &data) -{ - ssc_data_set_number(data, "capital_cost", 7263074); - ssc_data_set_number(data, "variable_operating_cost", 0.0010000000474974513); - ssc_data_set_number(data, "fixed_charge_rate", 0.10807877779006958); + return data; } #endif diff --git a/test/tcs_test/csp_solver_core_test.cpp b/test/shared_test/csp_solver_core_test.cpp similarity index 100% rename from test/tcs_test/csp_solver_core_test.cpp rename to test/shared_test/csp_solver_core_test.cpp diff --git a/test/shared_test/lib_battery_dispatch_automatic_btm_test.cpp b/test/shared_test/lib_battery_dispatch_automatic_btm_test.cpp index c6879fb34f1..b064c214632 100644 --- a/test/shared_test/lib_battery_dispatch_automatic_btm_test.cpp +++ b/test/shared_test/lib_battery_dispatch_automatic_btm_test.cpp @@ -80,7 +80,7 @@ TEST_F(AutoBTMTest_lib_battery_dispatch, DispatchAutoBTMPVCharging) { batteryPower->connectionMode = ChargeController::AC_CONNECTED; // Load never peaks above average load, so battery never discharges - std::vector expectedPower = {0, 0, 0, 0, 0, 0, 0, -50, -50, -50, -50, -50, -1.63, 0, 0, 0, 0, 0, 0, 0, 0, 0, + std::vector expectedPower = {0, 0, 0, 0, 0, 0, 0, -50, -50, -50, -50, -50, -1.94, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; for (size_t h = 0; h < 24; h++) { if (h > 6 && h < 18) { @@ -178,7 +178,7 @@ TEST_F(AutoBTMTest_lib_battery_dispatch, DispatchAutoBTMPVChargeAndDischargeSubh 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, -50.00, -50.00, -50.00, -50.00, -50.00, -50.00, -50.00, -50.00, -50.00, -50.00, -50.00, -50.00, -50.00, -50.00, -50.00, -50.00, -50.00, -50.00, - -50.00, -50.00, -5.19, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, + -50.00, -50.00, -6.40, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 50.00, 50.00, 50.00, 50.00, 50.00, 50.00, 50.00, 50.00, 50.00, 50.00, 50.00, 50.00, 50.00, 50.00, 50.00, 50.00, 50.00, 50.00, @@ -247,7 +247,7 @@ TEST_F(AutoBTMTest_lib_battery_dispatch, DispatchAutoBTMDCClipCharge) { batteryPower->setSharedInverter(m_sharedInverter); // Battery will charge when PV is available, then discharge when load increases at 7 pm - std::vector expectedPower = {0, 0, 0, 0, 0, 0, 0, -47.93, -47.92, -47.92, -47.91, -48.0, -11.99, + std::vector expectedPower = {0, 0, 0, 0, 0, 0, 0, -47.93, -47.92, -47.92, -47.91, -48.0, -12.295, 0, 0, 0, 0, 0, 0, 50, 50, 50, 50, 50.25}; for (size_t h = 0; h < 24; h++) { batteryPower->powerLoad = 500; @@ -300,7 +300,7 @@ TEST_F(AutoBTMTest_lib_battery_dispatch, TestBasicForecast) { batteryPower->connectionMode = ChargeController::AC_CONNECTED; // Discharge first 4 hours to avoid peak demand charges. Charge while there's solar, then discharge again at 6 pm since this is a high TOU rate - std::vector expectedPower = { 50, 50, 50, 34.79, 0, 0, 0, -47.84, -47.84, -47.84, -47.84, -47.84, -47.84, -47.84, -47.84, -47.91, -10.0, 0, 50, 50, 50, + std::vector expectedPower = { 50, 50, 50, 34.79, 0, 0, 0, -47.84, -47.84, -47.84, -47.84, -47.84, -47.84, -47.84, -47.84, -47.91, -10.538, 0, 50, 50, 50, 50, 50, 50, 50, 50, 50 }; for (size_t h = 0; h < 24; h++) { batteryPower->powerLoad = 500; @@ -332,7 +332,7 @@ TEST_F(AutoBTMTest_lib_battery_dispatch, TestSummerPeak) { 1.34971, 1.65378, 1.80832, 1.89189, 2.15165, 2.83263, 2.98228, 3.22567, 3.50516, 3.83516, 3.92251, 4.05548, 4.13676, 4.13277, 4.0915, 4.19724, 4.00006, 3.34509, 2.68845, 2.08509, 1.7126, }; pv_prediction = { -0.00116655, - 0.00116655, - 0.00116655, - 0.00116655, - 0.00116655, - 0.00116655, - 0.00116655, 0.129814, 0.75348, 1.47006, 2.45093, 2.9696, 3.30167, 3.47537, 3.42799, 3.14281, 2.59477, 1.83033, 0.857618, 0.176968, - 0.00116655, - 0.00116655, - 0.00116655 - - 0.00116655, - 0.00116655, - 0.00116655, - 0.00116655, - 0.00116655, - 0.00116655, - 0.00116655, - 0.00116655, 0.078559, 0.420793, 1.35006, 2.03824, 2.47638, 2.70446, 3.22802, 2.74022, 2.81986, 2.39299, 1.68699, 0.881843, + - 0.00116655, - 0.00116655, - 0.00116655, - 0.00116655, - 0.00116655, - 0.00116655, - 0.00116655, - 0.00116655, 0.078559, 0.420793, 1.35006, 2.03824, 2.47638, 2.70446, 3.22802, 2.74022, 2.81986, 2.39299, 1.68699, 0.881843, 0.169532, - 0.00116655, - 0.00116655, - 0.00116655, - 0.00116655 }; dispatchAutoBTM->update_load_data(load_prediction); @@ -342,8 +342,8 @@ TEST_F(AutoBTMTest_lib_battery_dispatch, TestSummerPeak) { batteryPower = dispatchAutoBTM->getBatteryPower(); batteryPower->connectionMode = ChargeController::AC_CONNECTED; - std::vector expectedPower = { 0.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.058, -0.0054, 0, 0, 0.0, 0.0, 2.3757, 0.0, - 4.122, 0.0, 0, 0, 0, 0 }; + std::vector expectedPower = { 0.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.058, -0.0054, 0, 0, 0.0, 1.564, 2.3757, + 3.368, 4.122, 0.0, 0, 0, 0, 0 }; for (size_t h = 0; h < 24; h++) { batteryPower->powerSystem = pv_prediction[h]; // Match the predicted PV batteryPower->powerLoad = load_prediction[h]; // Match the predicted load @@ -379,8 +379,8 @@ TEST_F(AutoBTMTest_lib_battery_dispatch, TestSummerPeakNetMeteringCredits) { batteryPower = dispatchAutoBTM->getBatteryPower(); batteryPower->connectionMode = ChargeController::AC_CONNECTED; - std::vector expectedPower = { 0.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.058, -0.0054, 0, 0, 0.0, 0.0, 2.3757, 0.0, - 4.122, 0.0, 0, 0, 0, 0 }; + std::vector expectedPower = { 0.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.058, -0.0054, 0, 0, 0.0, 1.564, 2.3757, + 3.368, 4.122, 0.0, 0, 0, 0, 0 }; for (size_t h = 0; h < 24; h++) { batteryPower->powerSystem = pv_prediction[h]; // Match the predicted PV batteryPower->powerLoad = load_prediction[h]; // Match the predicted load @@ -416,7 +416,8 @@ TEST_F(AutoBTMTest_lib_battery_dispatch, TestSummerPeakGridCharging) { batteryPower = dispatchAutoBTM->getBatteryPower(); batteryPower->connectionMode = ChargeController::AC_CONNECTED; - std::vector expectedPower = { -0.648, -0.813, -0.912, -0.984, -0.949, -0.695, -0.523, -0.124, -0.723, -1.093, -1.874, -2.092, -2.092, -1.872, -1.598, -1.21, -0.592, 2.3757, 3.3688, + std::vector expectedPower = { -0.648, -0.813, -0.912, -0.984, -0.949, -0.695, -0.523, -0.124, -0.723, + -1.093, -1.874, -2.092, -2.092, -1.872, -1.598, -1.21, -0.592, 0, 3.3688, 4.122, 0.0, 0.0, 0.0, -0.317}; for (size_t h = 0; h < 24; h++) { batteryPower->powerSystem = pv_prediction[h]; // Match the predicted PV @@ -465,7 +466,7 @@ TEST_F(AutoBTMTest_lib_battery_dispatch, TestSummerPeakGridChargingSubhourly) { batteryPower = dispatchAutoBTM->getBatteryPower(); batteryPower->connectionMode = ChargeController::AC_CONNECTED; - std::vector expectedPower = { -0.648, -0.813, -0.912, -0.984, -0.949, -0.695, -0.523, -0.124, -0.723, -1.093, -1.874, -2.092, -2.092, -1.872, -1.598, -1.21, 1.564, 2.3757, 3.3688, + std::vector expectedPower = { -0.648, -0.813, -0.912, -0.984, -0.949, -0.695, -0.523, -0.124, -0.723, -1.093, -1.874, -2.092, -2.092, -1.872, -1.598, 0.885, 1.564, 2.3757, 3.3688, 4.122, 0.0, 0.0, 0.0, -0.317 }; for (size_t h = 0; h < 24; h++) { batteryPower->powerSystem = pv_prediction[h]; // Match the predicted PV @@ -491,7 +492,7 @@ TEST_F(AutoBTMTest_lib_battery_dispatch, TestCommercialPeakForecasting) { true, true, false, util_rate, replacementCost, cyclingChoice, cyclingCost); load_prediction = { 49.9898, 42.4037, 42.1935, 43.3778, 39.4545, 59.3723, 84.6907, 180.423, 180.836, 186.225, 197.275, 205.302, 231.362, - 240.712, 249.681, 263.722, 249.91, 188.621, 173.452, 134.803, 121.631, 56.1207, 57.5053, 50.6343, 49.1768, 44.4999, 44.3999, + 240.712, 249.681, 263.722, 249.91, 188.621, 173.452, 134.803, 121.631, 56.1207, 57.5053, 50.6343, 49.1768, 44.4999, 44.3999, 44.3927, 42.8778, 61.4139, 86.7599, 186.891, 190.837, 198.747, 207.645, 211.838, 241.774, 262.163, 268.742, 274.231, 262.211, 199.747, 178.862, 145.017, 122.382, 55.8128, 58.1977, 51.3724, 48.2751, 42.5604, 39.8775, 38.8493, 38.2728, 62.2958, 66.9385, 99.3759, 111.364, 120.912, 129.247, 133.878, 135.635, 106.555, 114.328, 119.437, 104.461, 50.5622, 47.9985, 60.8511, 54.6621, @@ -511,8 +512,8 @@ TEST_F(AutoBTMTest_lib_battery_dispatch, TestCommercialPeakForecasting) { batteryPower = dispatchAutoBTM->getBatteryPower(); batteryPower->connectionMode = ChargeController::AC_CONNECTED; - std::vector expectedPower = { 50.02, 44.22, 44.00, 0, -46.0, 0, 0, 50.08, 41.45, 0, 0, -46.0, -46.0, 0, 0, 50.08, 38.49, 0, 0, - 0, 0, -46.0, -42.58, -46.0 }; + std::vector expectedPower = { 50.02, 44.22, 44.0, 45.24, 1.34, 0, 0, 0, 0, 0.0, 0, -46.0, -46.0, -45.39, -30.26, 50.08, 50.06, 50.15, 13.25, + 0, 0, -46.0, -46.0, -46.0 }; for (size_t h = 0; h < 24; h++) { batteryPower->powerSystem = pv_prediction[h]; // Match the predicted PV batteryPower->powerLoad = load_prediction[h]; // Match the predicted load @@ -635,7 +636,7 @@ TEST_F(AutoBTMTest_lib_battery_dispatch, DispatchAutoBTMCustomDispatch) { std::vector expectedPower = { 0, 0, 0, 0, 0, 0, 0, -50, -50, -50, -50, -50, -1.63, 0, 0, 0, 0, 0, 0, 9.479, 9.479, 9.479, 9.479, 9.479, 9.479, 9.479, 9.479 }; dispatchAutoBTM->set_custom_dispatch(expectedPower); - + batteryPower = dispatchAutoBTM->getBatteryPower(); batteryPower->connectionMode = ChargeController::AC_CONNECTED; diff --git a/test/shared_test/lib_battery_dispatch_automatic_btm_test.h b/test/shared_test/lib_battery_dispatch_automatic_btm_test.h index 0b6938b8d0b..9d968c267f4 100644 --- a/test/shared_test/lib_battery_dispatch_automatic_btm_test.h +++ b/test/shared_test/lib_battery_dispatch_automatic_btm_test.h @@ -47,9 +47,9 @@ class AutoBTMTest_lib_battery_dispatch : public BatteryProperties , public Dispa { // For Manual Dispatch Test BatteryProperties::SetUp(); - q = 1000. / 89.; + n_strings = 445; - capacityModel = new capacity_lithium_ion_t(q * n_strings, SOC_init, SOC_max, SOC_min, dtHour); + capacityModel = new capacity_lithium_ion_t(Qfull * n_strings, SOC_init, SOC_max, SOC_min, dtHour); voltageModel = new voltage_dynamic_t(n_series, n_strings, Vnom_default, Vfull, Vexp, Vnom, Qfull, Qexp, Qnom, C_rate, resistance, dtHour); lifetimeModel = new lifetime_calendar_cycle_t(cycleLifeMatrix, dtHour, calendar_q0, calendar_a, calendar_b, calendar_c); diff --git a/test/shared_test/lib_battery_dispatch_manual_test.cpp b/test/shared_test/lib_battery_dispatch_manual_test.cpp index ffdd840634d..f5e5b7f5dfb 100644 --- a/test/shared_test/lib_battery_dispatch_manual_test.cpp +++ b/test/shared_test/lib_battery_dispatch_manual_test.cpp @@ -468,7 +468,7 @@ TEST_F(ManualTest_lib_battery_dispatch, InverterEfficiencyCutoffDC) // Test discharge constraints. First constraint does not hit backoff batteryPower->powerSystem = 0; batteryPower->voltageSystem = 600; batteryPower->powerGridToBattery = 0; batteryPower->powerLoad = 7; dispatchManual->dispatch(year, 0, step_of_hour); - EXPECT_NEAR(batteryPower->sharedInverter->efficiencyAC, 36.05, 0.1); // Not enforced becasue no PV + EXPECT_NEAR(batteryPower->sharedInverter->efficiencyAC, 35.82, 0.1); // Not enforced becasue no PV EXPECT_NEAR(batteryPower->powerBatteryDC, 4.43, 0.1); batteryPower->powerSystem = 770; batteryPower->voltageSystem = 600; batteryPower->powerGridToBattery = 0; batteryPower->powerLoad = 1000; diff --git a/test/shared_test/lib_battery_dispatch_manual_test.h b/test/shared_test/lib_battery_dispatch_manual_test.h index 04110572591..585c0f88f85 100644 --- a/test/shared_test/lib_battery_dispatch_manual_test.h +++ b/test/shared_test/lib_battery_dispatch_manual_test.h @@ -48,9 +48,9 @@ class ManualTest_lib_battery_dispatch : public BatteryProperties, public Dispatc { // For Manual Dispatch Test BatteryProperties::SetUp(); - q = 1000. / 89.; + n_strings = 445; - capacityModel = new capacity_lithium_ion_t(q * n_strings, SOC_init, SOC_max, SOC_min, 1.0); + capacityModel = new capacity_lithium_ion_t(Qfull * n_strings, SOC_init, SOC_max, SOC_min, 1.0); voltageModel = new voltage_dynamic_t(n_series, n_strings, Vnom_default, Vfull, Vexp, Vnom, Qfull, Qexp, Qnom, C_rate, resistance, dtHour); lifetimeModel = new lifetime_calendar_cycle_t(cycleLifeMatrix, dtHour, calendar_q0, calendar_a, calendar_b, calendar_c); diff --git a/test/shared_test/lib_battery_lifetime_test.cpp b/test/shared_test/lib_battery_lifetime_test.cpp index c129ff5a760..6c50a700553 100644 --- a/test/shared_test/lib_battery_lifetime_test.cpp +++ b/test/shared_test/lib_battery_lifetime_test.cpp @@ -355,9 +355,9 @@ TEST_F(lib_battery_lifetime_nmc_test, updateCapacityTest) { //check lifetime_nmc_state_initialization ASSERT_EQ(model->get_state().nmc_state->q_relative_neg, 100); ASSERT_EQ(model->get_state().nmc_state->q_relative_li, 100); - ASSERT_EQ(model->get_state().nmc_state->b1_dt.size(), 0); - ASSERT_EQ(model->get_state().nmc_state->b2_dt.size(), 0); - ASSERT_EQ(model->get_state().nmc_state->b3_dt.size(), 0); + ASSERT_EQ(model->get_state().nmc_state->b1_dt, 0); + ASSERT_EQ(model->get_state().nmc_state->b2_dt, 0); + ASSERT_EQ(model->get_state().nmc_state->b3_dt, 0); ASSERT_EQ(model->get_state().nmc_state->day_age_of_battery_float, 0); //check U_neg, and Voc functions (SOC as a fractional input) @@ -381,3 +381,35 @@ TEST_F(lib_battery_lifetime_nmc_test, updateCapacityTest) { ASSERT_EQ(model->get_state().n_cycles, 875); } + +TEST_F(lib_battery_lifetime_nmc_test, NoCyclingCapacityTest) { + size_t idx = 0; + double tol = 0.1; + + // check capacity degradation with no cycling + while (idx < 2400) { + model->runLifetimeModels(idx, false, 50, 50, 25); + + auto state = model->get_state(); + + idx++; + } + //Values compared to MATLAB model + ASSERT_EQ(model->get_state().n_cycles, 0); + ASSERT_NEAR(model->get_state().q_relative, 98.8258,tol); + + model = std::unique_ptr(new lifetime_nmc_t(dt_hour)); + idx = 0; + + // simulate at battery temperature 35 C for 300 days + while (idx < 7200) { + model->runLifetimeModels(idx, false, 50, 50, 35); + + auto state = model->get_state(); + + idx++; + } + ASSERT_EQ(model->get_state().n_cycles, 0); + ASSERT_NEAR(model->get_state().nmc_state->q_relative_li, 92.8315, tol); + +} diff --git a/test/shared_test/lib_csp_tes_test.cpp b/test/shared_test/lib_csp_tes_test.cpp new file mode 100644 index 00000000000..494c6563255 --- /dev/null +++ b/test/shared_test/lib_csp_tes_test.cpp @@ -0,0 +1,148 @@ +#include + +#include "lib_csp_tes_test.h" +#include "vs_google_test_explorer_namespace.h" + +using namespace csp_common; + +//========Tests=================================================================================== +//=== Using factory patterns to create the different physical and non-physical components========= + +// Test draining storage tank +NAMESPACE_TEST(csp_common, StorageTank, DrainingTank) +{ + bool is_hot_tank = false; + double dt = 3600.; + + DefaultTankFactory default_tank_factory = DefaultTankFactory(); + std::unique_ptr tank_specifications = default_tank_factory.MakeSpecifications(); + std::unique_ptr tank = default_tank_factory.MakeTank(tank_specifications.get()); + TankState tank_state = default_tank_factory.MakeTankState(); + TankExternalConditions external_conditions = default_tank_factory.MakeExternalConditions(); + + double T_ave, vol_ave, q_loss, T_fin, vol_fin, m_fin, q_heater; // outputs + + tank->mixed_tank( + is_hot_tank, dt, + tank_state.m_prev, tank_state.T_prev, + external_conditions.m_dot_in, external_conditions.m_dot_out, + external_conditions.T_in, external_conditions.T_amb, + T_ave, vol_ave, q_loss, T_fin, vol_fin, m_fin, q_heater); + + EXPECT_NEAR(T_ave, 563.7, 563.7 * kErrorToleranceLo); + EXPECT_NEAR(vol_ave, 892.30, 892.30 * kErrorToleranceLo); + EXPECT_NEAR(q_loss, 0.331, 0.331 * kErrorToleranceLo); + EXPECT_NEAR(T_fin, 558.9, 558.9 * kErrorToleranceLo); + EXPECT_NEAR(vol_fin, 0., 0. * kErrorToleranceLo); + EXPECT_NEAR(m_fin, 0., 0. * kErrorToleranceLo); + EXPECT_NEAR(q_heater, 0., 0. * kErrorToleranceLo); +} + +// Test an initially drained storage tank +NAMESPACE_TEST(csp_common, StorageTank, InitiallyDrainedTank) +{ + bool is_hot_tank = false; + double dt = 3600.; + + DefaultTankFactory default_tank_factory = DefaultTankFactory(); + std::unique_ptr tank_specifications = default_tank_factory.MakeSpecifications(); + std::unique_ptr tank = default_tank_factory.MakeTank(tank_specifications.get()); + TankState tank_state = default_tank_factory.MakeTankState(); + TankExternalConditions external_conditions = default_tank_factory.MakeExternalConditions(); + + tank_state.m_prev = 0.; + + double T_ave, vol_ave, q_loss, T_fin, vol_fin, m_fin, q_heater; // outputs + + tank->mixed_tank( + is_hot_tank, dt, + tank_state.m_prev, tank_state.T_prev, + external_conditions.m_dot_in, external_conditions.m_dot_out, + external_conditions.T_in, external_conditions.T_amb, + T_ave, vol_ave, q_loss, T_fin, vol_fin, m_fin, q_heater); + + EXPECT_NEAR(T_ave, 563.97, 563.97 * kErrorToleranceLo); + EXPECT_NEAR(vol_ave, 0., 0. * kErrorToleranceLo); + EXPECT_NEAR(q_loss, 0., 0. * kErrorToleranceLo); + EXPECT_NEAR(T_fin, 563.97, 563.97 * kErrorToleranceLo); + EXPECT_NEAR(vol_fin, 0., 0. * kErrorToleranceLo); + EXPECT_NEAR(m_fin, 0., 0. * kErrorToleranceLo); + EXPECT_NEAR(q_heater, 0., 0. * kErrorToleranceLo); +} + +//========/Tests================================================================================== + +//========TankFactory (super class)=============================================================== +//========/TankFactory (super class)============================================================== + +//========DefaultTankFactory (subclass)=========================================================== +std::unique_ptr DefaultTankFactory::MakeTank(TankSpecifications* tank_specifications) const +{ + auto tank = std::unique_ptr(new Tank); + + tank->define_storage( + tank_specifications->fluid_field, + tank_specifications->fluid_store, + tank_specifications->is_direct, + tank_specifications->config, + tank_specifications->duty_des, + tank_specifications->vol_des, + tank_specifications->h_des, + tank_specifications->u_des, + tank_specifications->tank_pairs_des, + tank_specifications->hot_htr_set_point_des, + tank_specifications->cold_htr_set_point_des, + tank_specifications->max_q_htr_cold, + tank_specifications->max_q_htr_hot, + tank_specifications->dt_hot_des, + tank_specifications->dt_cold_des, + tank_specifications->T_h_in_des, + tank_specifications->T_h_out_des); + + return tank; +} + +std::unique_ptr DefaultTankFactory::MakeSpecifications() const +{ + auto tank_specifications = std::unique_ptr(new TankSpecifications()); + tank_specifications->field_fluid = 18; + tank_specifications->store_fluid = 18; + tank_specifications->fluid_field.SetFluid(tank_specifications->field_fluid); + tank_specifications->fluid_store.SetFluid(tank_specifications->store_fluid); + tank_specifications->is_direct = true; + tank_specifications->config = 2; + tank_specifications->duty_des = 623595520.; + tank_specifications->vol_des = 17558.4; + tank_specifications->h_des = 12.; + tank_specifications->u_des = 0.4; + tank_specifications->tank_pairs_des = 1.; + tank_specifications->hot_htr_set_point_des = 638.15; + tank_specifications->cold_htr_set_point_des = 523.15; + tank_specifications->max_q_htr_cold = 25.; + tank_specifications->max_q_htr_hot = 25.; + tank_specifications->dt_hot_des = 5.; + tank_specifications->dt_cold_des = 5.; + tank_specifications->T_h_in_des = 703.15; + tank_specifications->T_h_out_des = 566.15; + + return tank_specifications; +} + +TankState DefaultTankFactory::MakeTankState() const +{ + TankState tank_state; + tank_state.m_prev = 3399727.; + tank_state.T_prev = 563.97; + return tank_state; +} + +TankExternalConditions DefaultTankFactory::MakeExternalConditions() const +{ + TankExternalConditions external_conditions; + external_conditions.m_dot_in = 0.; + external_conditions.m_dot_out = 1239.16; // this will more than drain the tank + external_conditions.T_in = 566.15; + external_conditions.T_amb = 296.15; + return external_conditions; +} +//========/DefaultTankFactory (subclass)========================================================== diff --git a/test/shared_test/lib_csp_tes_test.h b/test/shared_test/lib_csp_tes_test.h new file mode 100644 index 00000000000..f4fc24a4c5a --- /dev/null +++ b/test/shared_test/lib_csp_tes_test.h @@ -0,0 +1,74 @@ +#ifndef __LIB_CSP_TES_TEST_H__ +#define __LIB_CSP_TES_TEST_H__ + +#include +#include "../tcs/storage_hx.h" + +using Tank = Storage_HX; + +namespace csp_common +{ + struct TankSpecifications; // forward declaration + struct TankState; + struct TankExternalConditions; + + const double kErrorToleranceLo = 0.001; // 0.1% + const double kErrorToleranceHi = 0.01; // 1.0% + + class TankFactory { + public: + TankFactory() {}; + virtual std::unique_ptr MakeTank(TankSpecifications* tank_specifications) const = 0; + virtual std::unique_ptr MakeSpecifications() const = 0; + virtual TankState MakeTankState() const = 0; + virtual TankExternalConditions MakeExternalConditions() const = 0; + }; + + class DefaultTankFactory : public TankFactory { + public: + DefaultTankFactory() {}; + virtual std::unique_ptr MakeTank(TankSpecifications* tank_specifications) const; + virtual std::unique_ptr MakeSpecifications() const; + virtual TankState MakeTankState() const; + virtual TankExternalConditions MakeExternalConditions() const; + }; + + struct TankSpecifications + { + int field_fluid; + int store_fluid; + HTFProperties fluid_field; + HTFProperties fluid_store; + bool is_direct; + int config; + double duty_des; + double vol_des; + double h_des; + double u_des; + double tank_pairs_des; + double hot_htr_set_point_des; + double cold_htr_set_point_des; + double max_q_htr_cold; + double max_q_htr_hot; + double dt_hot_des; + double dt_cold_des; + double T_h_in_des; + double T_h_out_des; + }; + + struct TankState + { + double m_prev; + double T_prev; + }; + + struct TankExternalConditions + { + double m_dot_in; + double m_dot_out; + double T_in; + double T_amb; + }; +} + +#endif diff --git a/test/shared_test/lib_csp_test.cpp b/test/shared_test/lib_csp_test.cpp deleted file mode 100644 index 9623deab171..00000000000 --- a/test/shared_test/lib_csp_test.cpp +++ /dev/null @@ -1,230 +0,0 @@ -#include - -#include "lib_csp_test.h" - - -CollectorTestSpecifications default_collector_test_specifications() -{ - CollectorTestSpecifications collector_test_specifications; - collector_test_specifications.FRta = 0.689; - collector_test_specifications.FRUL = 3.85; - collector_test_specifications.iam = 0.2; - collector_test_specifications.area_coll = 2.98; - collector_test_specifications.m_dot = 0.045528; // kg/s - collector_test_specifications.heat_capacity = 4.182; // kJ/kg-K - - return collector_test_specifications; -} - -FlatPlateCollector* default_flat_plate_collector() -{ - CollectorTestSpecifications collector_test_specifications = default_collector_test_specifications(); - - return new FlatPlateCollector(collector_test_specifications); -} - -tm default_time() -{ - tm time; - // TODO - The timestamp should be generated from a string so all attributes are valid - time.tm_year = 2012 - 1900; // years since 1900 - time.tm_mon = 1 - 1; // months since Jan. (Jan. = 0) - time.tm_mday = 1; - time.tm_hour = 12; - time.tm_min = 30; - time.tm_sec = 0; - - return time; -} - -CollectorLocation default_location() -{ - CollectorLocation collector_location; - collector_location.latitude = 33.45000; - collector_location.longitude = -111.98000; - collector_location.timezone = -7; - - return collector_location; -} - -CollectorOrientation default_orientation() -{ - CollectorOrientation collector_orientation; - collector_orientation.tilt = 30.; - collector_orientation.azimuth = 180.; - - return collector_orientation; -} - -ArrayDimensions default_dimensions() -{ - ArrayDimensions array_dimensions; - array_dimensions.num_in_parallel = 1; - array_dimensions.num_in_series = 1; - - return array_dimensions; -} - -TimeAndPosition default_time_and_position() -{ - TimeAndPosition time_and_position; - time_and_position.timestamp = default_time(); - time_and_position.collector_location = default_location(); - time_and_position.collector_orientation = default_orientation(); - - return time_and_position; -} - -ExternalConditions default_external_conditions() -{ - ExternalConditions external_conditions; - external_conditions.weather.ambient_temp = 25.; - external_conditions.weather.dni = 935.; - external_conditions.weather.dhi = 84.; - external_conditions.weather.ghi = std::numeric_limits::quiet_NaN(); - external_conditions.weather.wind_speed = std::numeric_limits::quiet_NaN(); - external_conditions.weather.wind_direction = std::numeric_limits::quiet_NaN(); - external_conditions.inlet_fluid_flow.m_dot = 0.091056; // kg/s - external_conditions.inlet_fluid_flow.specific_heat = 4.182; // kJ/kg-K - external_conditions.inlet_fluid_flow.temp = 45.9; // from previous timestep - external_conditions.albedo = 0.2; - - return external_conditions; -} - -Pipe* default_pipe() -{ - double inner_diameter = 0.019; - double insulation_conductivity = 0.03; - double insulation_thickness = 0.006; - double length = 5; - - return new Pipe(inner_diameter, insulation_conductivity, insulation_thickness, length); -} - -void FlatPlateCollectorTest::SetUp() -{ - // Too much in the Setup; can't change the configuration in the tests - flat_plate_collector_ = default_flat_plate_collector(); -} - -TEST_F(FlatPlateCollectorTest, TestFlatPlateCollectorNominalOperation) -{ - TimeAndPosition time_and_position = default_time_and_position(); - ExternalConditions external_conditions = default_external_conditions(); - - double useful_power_gain = flat_plate_collector_->UsefulPowerGain(time_and_position, external_conditions); // [W] - double T_out = flat_plate_collector_->T_out(time_and_position, external_conditions); // [C] - - EXPECT_NEAR(useful_power_gain, 1.659e3, 1.659e3 * m_error_tolerance_hi); - EXPECT_NEAR(T_out, 50.26, 50.26 * m_error_tolerance_hi); -} - -void FlatPlateArrayTest::SetUp() -{ - // Too much in the Setup; can't change the configuration in the tests - flat_plate_collector_ = default_flat_plate_collector(); - collector_location_ = default_location(); - collector_orientation_ = default_orientation(); - array_dimensions_ = default_dimensions(); - - inlet_pipe_ = default_pipe(); - outlet_pipe_ = default_pipe(); - - flat_plate_array_ = new FlatPlateArray(*flat_plate_collector_, collector_location_, - collector_orientation_, array_dimensions_, *inlet_pipe_, *outlet_pipe_); -} - -TEST_F(FlatPlateArrayTest, TestFlatPlateArrayOfOneNominalOperation) -{ - tm timestamp = default_time(); - ExternalConditions external_conditions = default_external_conditions(); - external_conditions.inlet_fluid_flow.temp = 44.86; - - double useful_power_gain = flat_plate_array_->UsefulPowerGain(timestamp, external_conditions); // [W] - double T_out = flat_plate_array_->T_out(timestamp, external_conditions); // [C] - - EXPECT_NEAR(useful_power_gain, 1.587e3, 1.587e3 * m_error_tolerance_hi); - EXPECT_NEAR(T_out, 49.03, 49.03 * m_error_tolerance_hi); -} - - - -void StorageTankTest::SetUp() -{ - m_storage = new Storage_HX(); - - m_field_fluid = 18; - m_store_fluid = 18; - m_fluid_field; - m_fluid_store; - m_is_direct = true; - m_config = 2; - m_duty_des = 623595520.; - m_vol_des = 17558.4; - m_h_des = 12.; - m_u_des = 0.4; - m_tank_pairs_des = 1.; - m_hot_htr_set_point_des = 638.15; - m_cold_htr_set_point_des = 523.15; - m_max_q_htr_cold = 25.; - m_max_q_htr_hot = 25.; - m_dt_hot_des = 5.; - m_dt_cold_des = 5.; - m_T_h_in_des = 703.15; - m_T_h_out_des = 566.15; - - m_fluid_field.SetFluid(m_field_fluid); - m_fluid_store.SetFluid(m_store_fluid); - - m_storage->define_storage(m_fluid_field, m_fluid_store, m_is_direct, - m_config, m_duty_des, m_vol_des, m_h_des, - m_u_des, m_tank_pairs_des, m_hot_htr_set_point_des, m_cold_htr_set_point_des, - m_max_q_htr_cold, m_max_q_htr_hot, m_dt_hot_des, m_dt_cold_des, m_T_h_in_des, m_T_h_out_des); -} - -TEST_F(StorageTankTest, TestDrainingTank_storage_hx) -{ - m_is_hot_tank = false; - m_dt = 3600; - m_m_prev = 3399727.; - m_T_prev = 563.97; - m_m_dot_in = 0.; - m_m_dot_out = 1239.16; // this will more than drain the tank - m_T_in = 566.15; - m_T_amb = 296.15; - - m_storage->mixed_tank(m_is_hot_tank, m_dt, m_m_prev, m_T_prev, m_m_dot_in, m_m_dot_out, m_T_in, m_T_amb, - m_T_ave, m_vol_ave, m_q_loss, m_T_fin, m_vol_fin, m_m_fin, m_q_heater); - - EXPECT_NEAR(m_T_ave, 563.7, 563.7 * m_error_tolerance_lo); - EXPECT_NEAR(m_vol_ave, 892.30, 892.30 * m_error_tolerance_lo); - EXPECT_NEAR(m_q_loss, 0.331, 0.331 * m_error_tolerance_lo); - EXPECT_NEAR(m_T_fin, 558.9, 558.9 * m_error_tolerance_lo); - EXPECT_NEAR(m_vol_fin, 0., 0. * m_error_tolerance_lo); - EXPECT_NEAR(m_m_fin, 0., 0. * m_error_tolerance_lo); - EXPECT_NEAR(m_q_heater, 0., 0. * m_error_tolerance_lo); -} - -TEST_F(StorageTankTest, TestDrainedTank_storage_hx) -{ - m_is_hot_tank = false; - m_dt = 3600; - m_m_prev = 0.; - m_T_prev = 563.97; - m_m_dot_in = 0.; - m_m_dot_out = 1239.16; - m_T_in = 566.15; - m_T_amb = 296.15; - - m_storage->mixed_tank(m_is_hot_tank, m_dt, m_m_prev, m_T_prev, m_m_dot_in, m_m_dot_out, m_T_in, m_T_amb, - m_T_ave, m_vol_ave, m_q_loss, m_T_fin, m_vol_fin, m_m_fin, m_q_heater); - - EXPECT_NEAR(m_T_ave, 563.97, 563.97 * m_error_tolerance_lo); - EXPECT_NEAR(m_vol_ave, 0., 0. * m_error_tolerance_lo); - EXPECT_NEAR(m_q_loss, 0., 0. * m_error_tolerance_lo); - EXPECT_NEAR(m_T_fin, 563.97, 563.97 * m_error_tolerance_lo); - EXPECT_NEAR(m_vol_fin, 0., 0. * m_error_tolerance_lo); - EXPECT_NEAR(m_m_fin, 0., 0. * m_error_tolerance_lo); - EXPECT_NEAR(m_q_heater, 0., 0. * m_error_tolerance_lo); -} \ No newline at end of file diff --git a/test/shared_test/lib_csp_test.h b/test/shared_test/lib_csp_test.h deleted file mode 100644 index ec702281a10..00000000000 --- a/test/shared_test/lib_csp_test.h +++ /dev/null @@ -1,125 +0,0 @@ -#ifndef __LIB_CSP_TEST_H__ -#define __LIB_CSP_TEST_H__ - -#include -#include "../tcs/storage_hx.h" -#include "../tcs/flat_plate_solar_collector.h" - -class FlatPlateCollectorTest : public ::testing::Test -{ -public: - const double m_error_tolerance_lo = 0.001; // 0.1% - const double m_error_tolerance_hi = 0.01; // 1.0% - - void SetUp(); - - void TearDown() - { - if (flat_plate_collector_) { - delete flat_plate_collector_; - flat_plate_collector_ = nullptr; - } - } -protected: - FlatPlateCollector *flat_plate_collector_; - - // inputs - - // outputs - - // parameters for initialization - -}; - -class FlatPlateArrayTest : public ::testing::Test -{ -public: - const double m_error_tolerance_lo = 0.001; // 0.1% - const double m_error_tolerance_hi = 0.01; // 1.0% - - void SetUp(); - - void TearDown() - { - if (flat_plate_array_) { - delete flat_plate_array_; - flat_plate_array_ = nullptr; - } - } -protected: - FlatPlateArray *flat_plate_array_; - - // inputs - - // outputs - - // parameters for initialization - FlatPlateCollector *flat_plate_collector_; - CollectorLocation collector_location_; - CollectorOrientation collector_orientation_; - ArrayDimensions array_dimensions_; - Pipe *inlet_pipe_; - Pipe *outlet_pipe_; -}; - -class StorageTankTest : public ::testing::Test -{ -protected: - Storage_HX *m_storage; - - // inputs - bool m_is_hot_tank; - double m_dt; - double m_m_prev; - double m_T_prev; - double m_m_dot_in; - double m_m_dot_out; - double m_T_in; - double m_T_amb; - - //outputs - double m_T_ave; - double m_vol_ave; - double m_q_loss; - double m_T_fin; - double m_vol_fin; - double m_m_fin; - double m_q_heater; - - // parameters for initialization - int m_field_fluid; - int m_store_fluid; - HTFProperties m_fluid_field; - HTFProperties m_fluid_store; - bool m_is_direct; - int m_config; - double m_duty_des; - double m_vol_des; - double m_h_des; - double m_u_des; - double m_tank_pairs_des; - double m_hot_htr_set_point_des; - double m_cold_htr_set_point_des; - double m_max_q_htr_cold; - double m_max_q_htr_hot; - double m_dt_hot_des; - double m_dt_cold_des; - double m_T_h_in_des; - double m_T_h_out_des; - -public: - double m_error_tolerance_lo = 0.001; // 0.1% - double m_error_tolerance_hi = 0.01; // 1.0% - - void SetUp(); - - void TearDown() - { - if (m_storage) { - delete m_storage; - m_storage = nullptr; - } - } -}; - -#endif \ No newline at end of file diff --git a/test/shared_test/lib_csp_tower_shared_with_ui_test.cpp b/test/shared_test/lib_csp_tower_shared_with_ui_test.cpp new file mode 100644 index 00000000000..8b5b3a9cd3d --- /dev/null +++ b/test/shared_test/lib_csp_tower_shared_with_ui_test.cpp @@ -0,0 +1,533 @@ +#include +#include "cmod_csp_tower_eqns.h" +#include "cmod_financial_eqns.h" +#include "csp_common_test.h" +#include "vs_google_test_explorer_namespace.h" + +namespace csp_common {} +using namespace csp_common; + +double GetNum(var_table* vd, std::string name) { + return vd->lookup(name.c_str())->num; +} +double GetNum(ssc_data_t data, std::string name) { + auto data_vtab = static_cast(data); + return data_vtab->as_number(name.c_str()); +} + +//=======Testing Molten Salt Power Tower UI Equations============================================= +NAMESPACE_TEST(csp_common, TowerSharedWithUi, SystemDesign) { + double error_tolerance = 0.01; + var_table* vd = new var_table; + vd->assign("design_eff", 0.412); + vd->assign("gross_net_conversion_factor", 0.9); + vd->assign("P_ref", 115.); + vd->assign("solarm", 2.4); + vd->assign("tshours", 10.); + + MSPT_System_Design_Equations(vd); + + ASSERT_NEAR_FRAC(GetNum(vd, "nameplate"), 103.5, kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "q_pb_design"), 279., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "q_rec_des"), 670., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "tshours_sf"), 4.16667, kErrorToleranceHi); +} + +NAMESPACE_TEST(csp_common, TowerSharedWithUi, SolarPilotField) { + double error_tolerance = 0.01; + var_table* vd = new var_table; + vd->assign("c_atm_0", 0.006789); + vd->assign("c_atm_1", 0.1046); + vd->assign("c_atm_2", -0.017); + vd->assign("c_atm_3", 0.002845); + vd->assign("csp_pt_sf_fixed_land_area", 45.); + vd->assign("csp_pt_sf_land_overhead_factor", 1.); + vd->assign("dens_mirror", 0.97); + vd->assign("dni_des", 950.); + vd->assign("h_tower", 193.458); + vd->assign("helio_height", 12.2); + vd->assign("helio_optical_error_mrad", 1.53); + util::matrix_t helio_positions(8790, 2, 1.e3); + vd->assign("helio_positions", helio_positions); + vd->assign("helio_width", 12.2); + vd->assign("land_area_base", 1847.04); + vd->assign("land_max", 9.5); + vd->assign("land_min", 0.75); + vd->assign("override_layout", 0); + vd->assign("override_opt", 0); + vd->assign("q_rec_des", 670.); + + Tower_SolarPilot_Solar_Field_Equations(vd); + + ASSERT_NEAR_FRAC(GetNum(vd, "a_sf_ui"), 1269055., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "c_atm_info"), 12.97, kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_sf_heliostat_area"), 144.375, kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_sf_total_land_area"), 1892., kErrorToleranceHi); + //ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_sf_total_reflective_area"), 1269056.25, kErrorToleranceHi); // This one is not being read in the UI + ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_sf_tower_height"), 193.458, kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "dni_des_calc"), 950., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "error_equiv"), 4.32749, kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "field_model_type"), 2., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "helio_area_tot"), 1269055., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "is_optimize"), 0., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "land_max_calc"), 1837.85, kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "land_min_calc"), 145.094, kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "n_hel"), 8790., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "opt_algorithm"), 1., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "opt_flux_penalty"), 0.25, kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "q_design"), 670., kErrorToleranceHi); +} + +NAMESPACE_TEST(csp_common, TowerSharedWithUi, SolarPilotFieldWithPeriodUse) { + // Testing period use in variable names + double error_tolerance = 0.01; + var_table* vd = new var_table; + vd->assign("c_atm_0", 0.006789); + vd->assign("c_atm_1", 0.1046); + vd->assign("c_atm_2", -0.017); + vd->assign("c_atm_3", 0.002845); + vd->assign("csp.pt.sf.fixed_land_area", 45.); + vd->assign("csp.pt.sf.land_overhead_factor", 1.); + vd->assign("dens_mirror", 0.97); + vd->assign("dni_des", 950.); + vd->assign("h_tower", 193.458); + vd->assign("helio_height", 12.2); + vd->assign("helio_optical_error_mrad", 1.53); + util::matrix_t helio_positions(8790, 2, 1.e3); + vd->assign("helio_positions", helio_positions); + vd->assign("helio_width", 12.2); + vd->assign("land_area_base", 1847.04); + vd->assign("land_max", 9.5); + vd->assign("land_min", 0.75); + vd->assign("override_layout", 0); + vd->assign("override_opt", 0); + vd->assign("q_rec_des", 670.); + + Tower_SolarPilot_Solar_Field_Equations(vd); + + ASSERT_NEAR_FRAC(GetNum(vd, "a_sf_ui"), 1269055., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "c_atm_info"), 12.97, kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_sf_heliostat_area"), 144.375, kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_sf_total_land_area"), 1892., kErrorToleranceHi); + //ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_sf_total_reflective_area"), 1269056.25, kErrorToleranceHi); // This one is not being read in the UI + ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_sf_tower_height"), 193.458, kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "dni_des_calc"), 950., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "error_equiv"), 4.32749, kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "field_model_type"), 2., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "helio_area_tot"), 1269055., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "is_optimize"), 0., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "land_max_calc"), 1837.85, kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "land_min_calc"), 145.094, kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "n_hel"), 8790., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "opt_algorithm"), 1., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "opt_flux_penalty"), 0.25, kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "q_design"), 670., kErrorToleranceHi); +} + +NAMESPACE_TEST(csp_common, TowerSharedWithUi, Receiver) { + double error_tolerance = 0.01; + var_table* vd = new var_table; + vd->assign("t_htf_cold_des", 290.); + vd->assign("t_htf_hot_des", 574.); + vd->assign("rec_htf", 17); + vd->assign("csp_pt_rec_max_oper_frac", 1.2); + vd->assign("q_rec_des", 660.9); + vd->assign("rec_d_spec", 15.); + vd->assign("csp_pt_rec_cav_ap_hw_ratio", 1.2); + vd->assign("d_rec", 17.65); + vd->assign("rec_height", 23.8084); + vd->assign("h_tower", 193.458); + vd->assign("piping_length_mult", 2.6); + vd->assign("piping_length_const", 0.); + vd->assign("piping_loss", 10200.); + std::vector field_fluid_properties{ 1, 7, 0, 0, 0, 0, 0, 0, 0 }; + util::matrix_t field_fl_props(1, 9, &field_fluid_properties); + vd->assign("field_fl_props", field_fl_props); + + MSPT_Receiver_Equations(vd); + + ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_rec_htf_t_avg"), 432., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_rec_htf_c_avg"), 1.5066, kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_rec_max_flow_to_rec"), 1853.5, kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_rec_cav_ap_height"), 18., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "rec_aspect"), 1.349, kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "piping_length"), 502.991, kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "piping_loss_tot"), 5130.51, kErrorToleranceHi); +} + +NAMESPACE_TEST(csp_common, TowerSharedWithUi, ReceiverWithPeriodUse) { + double error_tolerance = 0.01; + var_table* vd = new var_table; + vd->assign("t_htf_cold_des", 290.); + vd->assign("t_htf_hot_des", 574.); + vd->assign("rec_htf", 17); + vd->assign("csp.pt.rec.max_oper_frac", 1.2); + vd->assign("q_rec_des", 660.9); + vd->assign("rec_d_spec", 15.); + vd->assign("csp.pt.rec.cav_ap_hw_ratio", 1.2); + vd->assign("d_rec", 17.65); + vd->assign("rec_height", 23.8084); + vd->assign("h_tower", 193.458); + vd->assign("piping_length_mult", 2.6); + vd->assign("piping_length_const", 0.); + vd->assign("piping_loss", 10200.); + std::vector field_fluid_properties{ 1, 7, 0, 0, 0, 0, 0, 0, 0 }; + util::matrix_t field_fl_props(1, 9, &field_fluid_properties); + vd->assign("field_fl_props", field_fl_props); + + MSPT_Receiver_Equations(vd); + + ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_rec_htf_t_avg"), 432., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_rec_htf_c_avg"), 1.5066, kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_rec_max_flow_to_rec"), 1853.5, kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_rec_cav_ap_height"), 18., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "rec_aspect"), 1.349, kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "piping_length"), 502.991, kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "piping_loss_tot"), 5130.51, kErrorToleranceHi); +} + +NAMESPACE_TEST(csp_common, TowerSharedWithUi, Tes) { + double error_tolerance = 0.01; + ssc_data_t data = ssc_data_create(); + auto data_vtab = static_cast(data); + + data_vtab->assign("P_ref", 115.); + data_vtab->assign("design_eff", 0.412); + data_vtab->assign("tshours", 10.); + data_vtab->assign("T_htf_hot_des", 574.); + data_vtab->assign("T_htf_cold_des", 290.); + data_vtab->assign("rec_htf", 17); + std::vector field_fluid_properties{ 1, 7, 0, 0, 0, 0, 0, 0, 0 }; + util::matrix_t field_fl_props(1, 9, &field_fluid_properties); + data_vtab->assign("field_fl_props", field_fl_props); + data_vtab->assign("h_tank_min", 1.); + data_vtab->assign("h_tank", 12.); + data_vtab->assign("tank_pairs", 1.); + data_vtab->assign("u_tank", 0.4); + + int errors = run_module(data, "ui_tes_calcs"); + EXPECT_FALSE(errors); + + ASSERT_NEAR_FRAC(GetNum(data, "q_tes"), 2791.3, kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(data, "tes_avail_vol"), 12986., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(data, "vol_tank"), 14166., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(data, "csp_pt_tes_tank_diameter"), 38.8, kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(data, "q_dot_tes_est"), 0.73, kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(data, "csp_pt_tes_htf_density"), 1808.48, kErrorToleranceHi); +} + +NAMESPACE_TEST(csp_common, TowerSharedWithUi, TesWithPeriodUse) { + double error_tolerance = 0.01; + ssc_data_t data = ssc_data_create(); + auto data_vtab = static_cast(data); + + data_vtab->assign("P_ref", 115.); + data_vtab->assign("design_eff", 0.412); + data_vtab->assign("tshours", 10.); + data_vtab->assign("T_htf_hot_des", 574.); + data_vtab->assign("T_htf_cold_des", 290.); + data_vtab->assign("rec_htf", 17); + std::vector field_fluid_properties{ 1, 7, 0, 0, 0, 0, 0, 0, 0 }; + util::matrix_t field_fl_props(1, 9, &field_fluid_properties); + data_vtab->assign("field_fl_props", field_fl_props); + data_vtab->assign("h_tank_min", 1.); + data_vtab->assign("h_tank", 12.); + data_vtab->assign("tank_pairs", 1.); + data_vtab->assign("u_tank", 0.4); + + int errors = run_module(data, "ui_tes_calcs"); + EXPECT_FALSE(errors); + + ASSERT_NEAR_FRAC(GetNum(data, "q_tes"), 2791.3, kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(data, "tes_avail_vol"), 12986., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(data, "vol_tank"), 14166., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(data, "csp_pt_tes_tank_diameter"), 38.8, kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(data, "q_dot_tes_est"), 0.73, kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(data, "csp_pt_tes_htf_density"), 1808.48, kErrorToleranceHi); +} + +NAMESPACE_TEST(csp_common, TowerSharedWithUi, SystemControl) { + double error_tolerance = 0.01; + var_table* vd = new var_table; + vd->assign("bop_par", 0.); + vd->assign("bop_par_f", 1.); + vd->assign("bop_par_0", 0.); + vd->assign("bop_par_1", 0.483); + vd->assign("bop_par_2", 0.); + vd->assign("p_ref", 115.); + vd->assign("aux_par", 0.023); + vd->assign("aux_par_f", 1.); + vd->assign("aux_par_0", 0.483); + vd->assign("aux_par_1", 0.571); + vd->assign("aux_par_2", 0.); + vd->assign("disp_wlim_maxspec", 1.); + vd->assign("constant", 4.); + + MSPT_System_Control_Equations(vd); + + util::matrix_t wlim_series = vd->lookup("wlim_series")->num; + ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_par_calc_bop"), 0., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_par_calc_aux"), 2.78783, kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "disp_wlim_max"), 0.96, kErrorToleranceHi); + ASSERT_NEAR_FRAC(wlim_series.ncells(), 8760, 0.); + ASSERT_NEAR_FRAC(wlim_series.at(0, 0), 960., kErrorToleranceHi); +} + +NAMESPACE_TEST(csp_common, TowerSharedWithUi, SystemControlWithPeriods) { + double error_tolerance = 0.01; + var_table* vd = new var_table; + vd->assign("bop_par", 0.); + vd->assign("bop_par_f", 1.); + vd->assign("bop_par_0", 0.); + vd->assign("bop_par_1", 0.483); + vd->assign("bop_par_2", 0.); + vd->assign("p_ref", 115.); + vd->assign("aux_par", 0.023); + vd->assign("aux_par_f", 1.); + vd->assign("aux_par_0", 0.483); + vd->assign("aux_par_1", 0.571); + vd->assign("aux_par_2", 0.); + vd->assign("disp_wlim_maxspec", 1.); + vd->assign("constant", 4.); + + MSPT_System_Control_Equations(vd); + + util::matrix_t wlim_series = vd->lookup("wlim_series")->num; + ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_par_calc_bop"), 0., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_par_calc_aux"), 2.78783, kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "disp_wlim_max"), 0.96, kErrorToleranceHi); + ASSERT_NEAR_FRAC(wlim_series.ncells(), 8760, 0.); + ASSERT_NEAR_FRAC(wlim_series.at(0, 0), 960., kErrorToleranceHi); +} + +NAMESPACE_TEST(csp_common, TowerSharedWithUi, CapitalCosts) { + double error_tolerance = 0.01; + var_table* vd = new var_table; + vd->assign("d_rec", 17.65); + vd->assign("rec_height", 21.60); + vd->assign("receiver_type", 0); + vd->assign("rec_d_spec", 15.); + vd->assign("csp_pt_rec_cav_ap_height", 18.); + vd->assign("p_ref", 115.); + vd->assign("design_eff", 0.412); + vd->assign("tshours", 10.); + vd->assign("demand_var", 0); + vd->assign("a_sf_ui", 1269055.); + vd->assign("site_spec_cost", 16.); + vd->assign("heliostat_spec_cost", 140.); + vd->assign("cost_sf_fixed", 0.); + vd->assign("h_tower", 193.458); + vd->assign("rec_height", 21.6029); + vd->assign("helio_height", 12.2); + vd->assign("tower_fixed_cost", 3000000.); + vd->assign("tower_exp", 0.0113); + vd->assign("csp_pt_cost_receiver_area", 1269055.); + vd->assign("rec_ref_cost", 103000000.); + vd->assign("rec_ref_area", 1571.); + vd->assign("rec_cost_exp", 0.7); + vd->assign("csp_pt_cost_storage_mwht", 2791.26); + vd->assign("tes_spec_cost", 22.); + vd->assign("csp_pt_cost_power_block_mwe", 115.); + vd->assign("plant_spec_cost", 1040.); + vd->assign("bop_spec_cost", 290.); + vd->assign("fossil_spec_cost", 0.); + vd->assign("contingency_rate", 7.); + vd->assign("csp_pt_sf_total_land_area", 1892.); + vd->assign("nameplate", 104.); + vd->assign("csp_pt_cost_epc_per_acre", 0.); + vd->assign("csp_pt_cost_epc_percent", 13.); + vd->assign("csp_pt_cost_epc_per_watt", 0.); + vd->assign("csp_pt_cost_epc_fixed", 0.); + vd->assign("land_spec_cost", 10000.); + vd->assign("csp_pt_cost_plm_percent", 0.); + vd->assign("csp_pt_cost_plm_per_watt", 0.); + vd->assign("csp_pt_cost_plm_fixed", 0.); + vd->assign("sales_tax_frac", 80.); + vd->assign("sales_tax_rate", 5.); + + Tower_SolarPilot_Capital_Costs_MSPT_Equations(vd); + + ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_cost_receiver_area"), 1197.86, kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_cost_storage_mwht"), 2791.26, kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_cost_power_block_mwe"), 115., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_cost_site_improvements"), 20304872., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_cost_heliostats"), 177667632., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_cost_tower"), 25319156., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_cost_receiver"), 85191944., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_cost_storage"), 61407768., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_cost_power_block"), 119600000., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_cost_bop"), 33350000., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_cost_fossil"), 0., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "ui_direct_subtotal"), 522841376., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_cost_contingency"), 36598896., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "total_direct_cost"), 559440256., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_cost_epc_total"), 72727232., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_cost_plm_total"), 18920378., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_cost_sales_tax_total"), 22377610., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "total_indirect_cost"), 114025224., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "total_installed_cost"), 673465472., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_cost_installed_per_capacity"), 6506.91, kErrorToleranceHi); +} + +NAMESPACE_TEST(csp_common, TowerSharedWithUi, CapitalCostsWithPeriods) { + double error_tolerance = 0.01; + var_table* vd = new var_table; + vd->assign("d_rec", 17.65); + vd->assign("rec_height", 21.60); + vd->assign("receiver_type", 0); + vd->assign("rec_d_spec", 15.); + vd->assign("csp.pt.rec.cav_ap_height", 18.); + vd->assign("p_ref", 115.); + vd->assign("design_eff", 0.412); + vd->assign("tshours", 10.); + vd->assign("demand_var", 0); + vd->assign("a_sf_ui", 1269055.); + vd->assign("site_spec_cost", 16.); + vd->assign("heliostat_spec_cost", 140.); + vd->assign("cost_sf_fixed", 0.); + vd->assign("h_tower", 193.458); + vd->assign("rec_height", 21.6029); + vd->assign("helio_height", 12.2); + vd->assign("tower_fixed_cost", 3000000.); + vd->assign("tower_exp", 0.0113); + vd->assign("csp.pt.cost.receiver.area", 1269055.); + vd->assign("rec_ref_cost", 103000000.); + vd->assign("rec_ref_area", 1571.); + vd->assign("rec_cost_exp", 0.7); + vd->assign("csp.pt.cost.storage_mwht", 2791.26); + vd->assign("tes_spec_cost", 22.); + vd->assign("csp.pt.cost.power_block_mwe", 115.); + vd->assign("plant_spec_cost", 1040.); + vd->assign("bop_spec_cost", 290.); + vd->assign("fossil_spec_cost", 0.); + vd->assign("contingency_rate", 7.); + vd->assign("csp.pt.sf.total_land_area", 1892.); + vd->assign("nameplate", 104.); + vd->assign("csp.pt.cost.epc.per_acre", 0.); + vd->assign("csp.pt.cost.epc.percent", 13.); + vd->assign("csp.pt.cost.epc.per_watt", 0.); + vd->assign("csp.pt.cost.epc.fixed", 0.); + vd->assign("land_spec_cost", 10000.); + vd->assign("csp.pt.cost.plm.percent", 0.); + vd->assign("csp.pt.cost.plm.per_watt", 0.); + vd->assign("csp.pt.cost.plm.fixed", 0.); + vd->assign("sales_tax_frac", 80.); + vd->assign("sales_tax_rate", 5.); + + Tower_SolarPilot_Capital_Costs_MSPT_Equations(vd); + + ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_cost_receiver_area"), 1197.86, kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_cost_storage_mwht"), 2791.26, kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_cost_power_block_mwe"), 115., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_cost_site_improvements"), 20304872., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_cost_heliostats"), 177667632., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_cost_tower"), 25319156., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_cost_receiver"), 85191944., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_cost_storage"), 61407768., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_cost_power_block"), 119600000., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_cost_bop"), 33350000., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_cost_fossil"), 0., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "ui_direct_subtotal"), 522841376., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_cost_contingency"), 36598896., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "total_direct_cost"), 559440256., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_cost_epc_total"), 72727232., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_cost_plm_total"), 18920378., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_cost_sales_tax_total"), 22377610., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "total_indirect_cost"), 114025224., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "total_installed_cost"), 673465472., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "csp_pt_cost_installed_per_capacity"), 6506.91, kErrorToleranceHi); +} + +//======Financial Equations======================================================================= +NAMESPACE_TEST(csp_common, TowerSharedWithUi, FinancialCase1) { + double error_tolerance = 0.01; + var_table* vd = new var_table; + vd->assign("total_installed_cost", 673465536.); + + vd->assign("const_per_percent1", 100.); + vd->assign("const_per_upfront_rate1", 1.); + vd->assign("const_per_months1", 24.); + vd->assign("const_per_interest_rate1", 4.); + + vd->assign("const_per_percent2", 0.); + vd->assign("const_per_upfront_rate2", 0.); + vd->assign("const_per_months2", 0.); + vd->assign("const_per_interest_rate2", 0.); + + vd->assign("const_per_percent3", 0.); + vd->assign("const_per_upfront_rate3", 0.); + vd->assign("const_per_months3", 0.); + vd->assign("const_per_interest_rate3", 0.); + + vd->assign("const_per_percent4", 0.); + vd->assign("const_per_upfront_rate4", 0.); + vd->assign("const_per_months4", 0.); + vd->assign("const_per_interest_rate4", 0.); + + vd->assign("const_per_percent5", 0.); + vd->assign("const_per_upfront_rate5", 0.); + vd->assign("const_per_months5", 0.); + vd->assign("const_per_interest_rate5", 0.); + + Financial_Construction_Financing_Equations(vd); + + ASSERT_NEAR_FRAC(GetNum(vd, "const_per_principal1"), 673465472., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "const_per_interest1"), 26938618., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "const_per_total1"), 33673272., kErrorToleranceHi); + + ASSERT_NEAR_FRAC(GetNum(vd, "const_per_principal2"), 0., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "const_per_interest2"), 0., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "const_per_total2"), 0., kErrorToleranceHi); + + ASSERT_NEAR_FRAC(GetNum(vd, "const_per_principal3"), 0., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "const_per_interest3"), 0., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "const_per_total3"), 0., kErrorToleranceHi); + + ASSERT_NEAR_FRAC(GetNum(vd, "const_per_principal4"), 0., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "const_per_interest4"), 0., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "const_per_total4"), 0., kErrorToleranceHi); + + ASSERT_NEAR_FRAC(GetNum(vd, "const_per_principal5"), 0., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "const_per_interest5"), 0., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "const_per_total5"), 0., kErrorToleranceHi); + + ASSERT_NEAR_FRAC(GetNum(vd, "const_per_percent_total"), 100., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "const_per_principal_total"), 673465472., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "const_per_interest_total"), 26938618., kErrorToleranceHi); + ASSERT_NEAR_FRAC(GetNum(vd, "construction_financing_cost"), 33673272., kErrorToleranceHi); +} + +NAMESPACE_TEST(csp_common, TowerSharedWithUi, FinancialCase2) { + double error_tolerance = 0.01; + var_table* vd = new var_table; + vd->assign("system_capacity", 103500.); + + Financial_Capacity_Payments_Equations(vd); + + //double cp_system_nameplate = vd->lookup("cp_system_nameplate")->num; + ASSERT_NEAR_FRAC(GetNum(vd, "cp_system_nameplate"), 103.5, kErrorToleranceHi); +} + +//======/Testing Molten Salt Power Tower UI Equations============================================= + + +//TEST(Mspt_cmod_csp_tower_eqns, NoData) { +// ASSERT_THROW(MSPT_System_Design_Equations(nullptr), std::runtime_error); +// ASSERT_THROW(Tower_SolarPilot_Solar_Field_Equations(nullptr), std::runtime_error); +// //ASSERT_THROW(MSPT_Receiver_Equations(nullptr), std::runtime_error); +// //ASSERT_THROW(MSPT_System_Control_Equations(nullptr), std::runtime_error); +// //ASSERT_THROW(Tower_SolarPilot_Capital_Costs_MSPT_Equations(nullptr), std::runtime_error); +// //ASSERT_THROW(Tower_SolarPilot_Capital_Costs_DSPT_Equations(nullptr), std::runtime_error); +// //ASSERT_THROW(Tower_SolarPilot_Capital_Costs_ISCC_Equations(nullptr), std::runtime_error); +//} + +//TEST(Mspt_cmod_csp_tower_eqns, MissingVariables) { +// var_table* vd = new var_table; +// ASSERT_THROW(MSPT_System_Design_Equations(vd), std::runtime_error); +// ASSERT_THROW(Tower_SolarPilot_Solar_Field_Equations(vd), std::runtime_error); +// //ASSERT_THROW(MSPT_Receiver_Equations(vd), std::runtime_error); +// //ASSERT_THROW(MSPT_System_Control_Equations(vd), std::runtime_error); +// //ASSERT_THROW(Tower_SolarPilot_Capital_Costs_MSPT_Equations(vd), std::runtime_error); +// //ASSERT_THROW(Tower_SolarPilot_Capital_Costs_DSPT_Equations(vd), std::runtime_error); +// //ASSERT_THROW(Tower_SolarPilot_Capital_Costs_ISCC_Equations(vd), std::runtime_error); +//} diff --git a/test/shared_test/lib_csp_trough_test.cpp b/test/shared_test/lib_csp_trough_test.cpp new file mode 100644 index 00000000000..eb3f6598d57 --- /dev/null +++ b/test/shared_test/lib_csp_trough_test.cpp @@ -0,0 +1,726 @@ +#include + +#define private public // for setting private data members +#include "lib_csp_trough_test.h" +#include "vs_google_test_explorer_namespace.h" + +using namespace csp_trough; + +//========Tests=================================================================================== +//=== Using factory patterns to create the different physical and non-physical components========= + +// Test a standard trough loop at a single point in time +NAMESPACE_TEST(csp_trough, TroughLoop, DefaultTest) +{ + DefaultTroughFactory default_trough_factory = DefaultTroughFactory(); + Location location = default_trough_factory.MakeLocation(); + std::unique_ptr trough = default_trough_factory.MakeTrough(location); + std::unique_ptr trough_state = default_trough_factory.MakeTroughState(); + TroughFactory::SetTroughState(trough.get(), trough_state.get()); + + std::unique_ptr time_and_weather = default_trough_factory.MakeTimeLocationWeather(location); + FluidInletState fluid_inlet_state = default_trough_factory.MakeInletState(); + double defocus = default_trough_factory.MakeDefocus(); + TroughOutputs trough_outputs; + TimestepAndTou timestep_and_tou = default_trough_factory.MakeTimestepAndTou(); + + trough->on(*time_and_weather, fluid_inlet_state, defocus, trough_outputs, timestep_and_tou); + + EXPECT_NEAR(trough_outputs.m_T_salt_hot, 391.17, 391.17 * kErrorToleranceLo); + EXPECT_NEAR(trough_outputs.m_m_dot_salt_tot, 6568369, 6568369 * kErrorToleranceLo); +} + +// Test a standard trough loop from a homogenous initial condition to steady-state +NAMESPACE_TEST(csp_trough, TroughLoop, SteadyStateTest) +{ + DefaultTroughFactory default_trough_factory = DefaultTroughFactory(); + Location location = default_trough_factory.MakeLocation(); + std::unique_ptr trough = default_trough_factory.MakeTrough(location); + std::unique_ptr trough_state = default_trough_factory.MakeTroughState(); + TroughFactory::SetTroughState(trough.get(), trough_state.get()); + + std::unique_ptr time_and_weather = default_trough_factory.MakeTimeLocationWeather(location); + FluidInletState fluid_inlet_state = default_trough_factory.MakeInletState(); + double defocus = default_trough_factory.MakeDefocus(); + TroughOutputs trough_outputs; + TimestepAndTou timestep_and_tou = default_trough_factory.MakeTimestepAndTou(); + + trough->m_accept_mode = 1; // flag so solar zenith from weather is used instead of calc'd + trough->m_accept_init = false; // running at steady-state but keeping false to avoid side effects + trough->m_accept_loc = 1; // don't just model a single loop + trough->m_is_using_input_gen = false; // use parameter values set below instead + + // Design DNI and normal incidence angle + time_and_weather->m_beam = trough->m_I_bn_des; + time_and_weather->m_solazi = trough->m_ColAz; + time_and_weather->m_solzen = trough->m_ColTilt; + + // 5-minute timesteps + timestep_and_tou.ms_ts.m_step = 5. * 60.; + timestep_and_tou.ms_ts.m_time = timestep_and_tou.ms_ts.m_time_start + timestep_and_tou.ms_ts.m_step; + + // Initially set all fluid to design temperature + fluid_inlet_state.m_temp = trough->m_T_loop_in_des - 273.15; + trough->m_T_sys_c_t_end_converged = trough->m_T_loop_in_des; + trough->m_T_sys_h_t_end_converged = trough->m_T_loop_in_des; + trough->m_T_htf_out_t_end_converged.assign(trough->m_nSCA, trough->m_T_loop_in_des); + + // Values for checking whether steady-state + double ss_diff = std::numeric_limits::quiet_NaN(); + const double tol = 0.05; + std::vector T_htf_in_t_int_prev = trough->m_T_htf_in_t_int; + std::vector T_htf_out_t_int_prev = trough->m_T_htf_out_t_int; + double minutes2SS = 0.; + + do + { + trough->on(*time_and_weather, fluid_inlet_state, defocus, trough_outputs, timestep_and_tou); + + // Calculate metric for deciding whether steady-state is reached + ss_diff = 0.; + for (int i = 0; i < trough->m_nSCA; i++) { + ss_diff += fabs(trough->m_T_htf_in_t_int[i] - T_htf_in_t_int_prev[i]) + + fabs(trough->m_T_htf_out_t_int[i] - T_htf_out_t_int_prev[i]); + } + + // Set converged values so reset_last_temps() propagates the temps in time + trough->m_T_sys_c_t_end_converged = trough->m_T_sys_c_t_end; + trough->m_T_sys_h_t_end_converged = trough->m_T_sys_h_t_end; + // SCA temperatures - these set the values of m_T_htf_out_t_end_last[i] + trough->m_T_htf_out_t_end_converged = trough->m_T_htf_out_t_end; + + // Update 'last' values + T_htf_in_t_int_prev = trough->m_T_htf_in_t_int; + T_htf_out_t_int_prev = trough->m_T_htf_out_t_int; + + minutes2SS += timestep_and_tou.ms_ts.m_step / 60.; + + } while (ss_diff / 200. > tol); + + EXPECT_NEAR(trough->m_T_sys_h_t_end, 656.1, 656.1 * kErrorToleranceLo); // final loop outlet temperature + EXPECT_NEAR(minutes2SS, 35., 35. * kErrorToleranceLo); // time to steady-state +} +//========/Tests================================================================================== + +//========Factories:============================================================================== +//========TroughFactory (super class)============================================================= +std::unique_ptr TroughFactory::MakeTrough(TroughSpecifications* trough_specifications, + Location location) const +{ + auto trough = std::unique_ptr(new Trough); + + trough->m_nSCA = trough_specifications->nSCA; + trough->m_nHCEt = trough_specifications->nHCEt; + trough->m_nColt = trough_specifications->nColt; + trough->m_nHCEVar = trough_specifications->nHCEVar; + trough->m_nLoops = trough_specifications->nLoops; + trough->m_FieldConfig = trough_specifications->FieldConfig; + trough->m_L_power_block_piping = trough_specifications->L_power_block_piping; + trough->m_include_fixed_power_block_runner = trough_specifications->include_fixed_power_block_runner; + trough->m_eta_pump = trough_specifications->eta_pump; + trough->m_Fluid = trough_specifications->Fluid; + //trough->m_fthrok = trough_specifications->fthrok; + trough->m_fthrctrl = trough_specifications->fthrctrl; + trough->m_accept_loc = trough_specifications->accept_loc; + trough->m_HDR_rough = trough_specifications->HDR_rough; + trough->m_theta_stow = trough_specifications->theta_stow; + trough->m_theta_dep = trough_specifications->theta_dep; + trough->m_Row_Distance = trough_specifications->Row_Distance; + + trough->m_T_loop_in_des = trough_specifications->T_loop_in_des; + trough->m_T_loop_out_des = trough_specifications->T_loop_out_des; + trough->m_T_startup = trough_specifications->T_startup; + trough->m_m_dot_htfmin = trough_specifications->m_dot_htfmin; + trough->m_m_dot_htfmax = trough_specifications->m_dot_htfmax; + trough->m_field_fl_props = trough_specifications->field_fl_props; + trough->m_T_fp = trough_specifications->T_fp; + trough->m_I_bn_des = trough_specifications->I_bn_des; + trough->m_V_hdr_cold_max = trough_specifications->V_hdr_cold_max; + trough->m_V_hdr_cold_min = trough_specifications->V_hdr_cold_min; + trough->m_V_hdr_hot_max = trough_specifications->V_hdr_hot_max; + trough->m_V_hdr_hot_min = trough_specifications->V_hdr_hot_min; + trough->m_V_hdr_max = trough_specifications->V_hdr_max; + trough->m_V_hdr_min = trough_specifications->V_hdr_min; + trough->m_Pipe_hl_coef = trough_specifications->Pipe_hl_coef; + trough->m_SCA_drives_elec = trough_specifications->SCA_drives_elec; + trough->m_ColTilt = trough_specifications->ColTilt; + trough->m_ColAz = trough_specifications->ColAz; + trough->m_wind_stow_speed = trough_specifications->wind_stow_speed; + trough->m_accept_mode = trough_specifications->accept_mode; + trough->m_accept_init = trough_specifications->accept_init; + trough->m_solar_mult = trough_specifications->solar_mult; + trough->m_mc_bal_hot_per_MW = trough_specifications->mc_bal_hot_per_MW; + trough->m_mc_bal_cold_per_MW = trough_specifications->mc_bal_cold_per_MW; + trough->m_mc_bal_sca = trough_specifications->mc_bal_sca; + + trough->m_W_aperture = trough_specifications->W_aperture; + trough->m_A_aperture = trough_specifications->A_aperture; + trough->m_TrackingError = trough_specifications->TrackingError; + trough->m_GeomEffects = trough_specifications->GeomEffects; + trough->m_Rho_mirror_clean = trough_specifications->Rho_mirror_clean; + trough->m_Dirt_mirror = trough_specifications->Dirt_mirror; + trough->m_Error = trough_specifications->Error; + trough->m_Ave_Focal_Length = trough_specifications->Ave_Focal_Length; + trough->m_L_SCA = trough_specifications->L_SCA; + trough->m_L_aperture = trough_specifications->L_aperture; + trough->m_ColperSCA = trough_specifications->ColperSCA; + trough->m_Distance_SCA = trough_specifications->Distance_SCA; + + trough->m_IAM_matrix = trough_specifications->IAM_matrix; + trough->m_HCE_FieldFrac = trough_specifications->HCE_FieldFrac; + trough->m_D_2 = trough_specifications->D_2; + trough->m_D_3 = trough_specifications->D_3; + trough->m_D_4 = trough_specifications->D_4; + trough->m_D_5 = trough_specifications->D_5; + trough->m_D_p = trough_specifications->D_p; + trough->m_Flow_type = trough_specifications->Flow_type; + trough->m_Rough = trough_specifications->Rough; + trough->m_alpha_env = trough_specifications->alpha_env; + + trough->m_epsilon_3_11 = trough_specifications->epsilon_3_11; + trough->m_epsilon_3_12 = trough_specifications->epsilon_3_12; + trough->m_epsilon_3_13 = trough_specifications->epsilon_3_13; + trough->m_epsilon_3_14 = trough_specifications->epsilon_3_14; + trough->m_epsilon_3_21 = trough_specifications->epsilon_3_21; + trough->m_epsilon_3_22 = trough_specifications->epsilon_3_22; + trough->m_epsilon_3_23 = trough_specifications->epsilon_3_23; + trough->m_epsilon_3_24 = trough_specifications->epsilon_3_24; + trough->m_epsilon_3_31 = trough_specifications->epsilon_3_31; + trough->m_epsilon_3_32 = trough_specifications->epsilon_3_32; + trough->m_epsilon_3_33 = trough_specifications->epsilon_3_33; + trough->m_epsilon_3_34 = trough_specifications->epsilon_3_34; + trough->m_epsilon_3_41 = trough_specifications->epsilon_3_41; + trough->m_epsilon_3_42 = trough_specifications->epsilon_3_42; + trough->m_epsilon_3_43 = trough_specifications->epsilon_3_43; + trough->m_epsilon_3_44 = trough_specifications->epsilon_3_44; + + trough->m_alpha_abs = trough_specifications->alpha_abs; + trough->m_Tau_envelope = trough_specifications->Tau_envelope; + trough->m_EPSILON_4 = trough_specifications->EPSILON_4; + trough->m_EPSILON_5 = trough_specifications->EPSILON_5; + trough->m_GlazingIntact = trough_specifications->GlazingIntact; + trough->m_P_a = trough_specifications->P_a; + trough->m_AnnulusGas = trough_specifications->AnnulusGas; + trough->m_AbsorberMaterial = trough_specifications->AbsorberMaterial; + trough->m_Shadowing = trough_specifications->Shadowing; + trough->m_Dirt_HCE = trough_specifications->Dirt_HCE; + trough->m_Design_loss = trough_specifications->Design_loss; + trough->m_SCAInfoArray = trough_specifications->SCAInfoArray; + + trough->m_calc_design_pipe_vals = trough_specifications->calc_design_pipe_vals; + trough->m_L_rnr_pb = trough_specifications->L_rnr_pb; + trough->m_N_max_hdr_diams = trough_specifications->N_max_hdr_diams; + trough->m_L_rnr_per_xpan = trough_specifications->L_rnr_per_xpan; + trough->m_L_xpan_hdr = trough_specifications->L_xpan_hdr; + trough->m_L_xpan_rnr = trough_specifications->L_xpan_rnr; + trough->m_Min_rnr_xpans = trough_specifications->Min_rnr_xpans; + trough->m_northsouth_field_sep = trough_specifications->northsouth_field_sep; + trough->m_N_hdr_per_xpan = trough_specifications->N_hdr_per_xpan; + trough->m_K_cpnt = trough_specifications->K_cpnt; + trough->m_D_cpnt = trough_specifications->D_cpnt; + trough->m_L_cpnt = trough_specifications->L_cpnt; + trough->m_Type_cpnt = trough_specifications->Type_cpnt; + trough->m_custom_sf_pipe_sizes = trough_specifications->custom_sf_pipe_sizes; + trough->m_sf_rnr_diams = trough_specifications->sf_rnr_diams; + trough->m_sf_rnr_wallthicks = trough_specifications->sf_rnr_wallthicks; + trough->m_sf_rnr_lengths = trough_specifications->sf_rnr_lengths; + trough->m_sf_hdr_diams = trough_specifications->sf_hdr_diams; + trough->m_sf_hdr_wallthicks = trough_specifications->sf_hdr_wallthicks; + trough->m_sf_hdr_lengths = trough_specifications->sf_hdr_lengths; + + TroughSolvedParams trough_solved_params; + trough->init(location, trough_solved_params); + + return trough; +} + +// Set state by assigning previous (converged) trough HTF temperatures +void TroughFactory::SetTroughState(Trough* trough, TroughState* trough_state) +{ + std::size_t N_scas_trough = trough->m_T_htf_out_t_end_converged.size(); + std::size_t N_scas_state = trough_state->T_out_SCAs_prev.size(); + if (N_scas_trough != N_scas_state) { + throw "Incorrect trough state array length."; + } + + trough->m_T_sys_c_t_end_converged = trough_state->T_in_loop_prev; // this ends up setting m_T_sys_c_t_end_last + trough->m_T_sys_h_t_end_converged = trough_state->T_out_loop_prev; // this ends up setting m_T_sys_h_t_end_last + + // SCA temperatures - these end up setting m_T_htf_out_t_end_last[i] + for (std::vector::size_type i = 0; i != trough_state->T_out_SCAs_prev.size(); i++) { + trough->m_T_htf_out_t_end_converged[i] = trough_state->T_out_SCAs_prev[i]; + } +} +//========/TroughFactory========================================================================== + +//========DefaultTroughFactory (subclass)========================================================= +std::unique_ptr DefaultTroughFactory::MakeTrough(Location location) const +{ + std::unique_ptr trough_specifications = this->MakeSpecifications(); + std::unique_ptr trough = TroughFactory::MakeTrough(trough_specifications.get(), + location); + return trough; +} + +std::unique_ptr DefaultTroughFactory::MakeSpecifications() const +{ + auto trough_specifications = std::unique_ptr(new TroughSpecifications); + trough_specifications->nSCA = 8; + trough_specifications->nHCEt = 4; + trough_specifications->nColt = 4; + trough_specifications->nHCEVar = 4; + trough_specifications->nLoops = 181; + trough_specifications->FieldConfig = 2; + trough_specifications->L_power_block_piping = 50.; + trough_specifications->include_fixed_power_block_runner = true; + trough_specifications->eta_pump = 0.85; + trough_specifications->Fluid = 21; + trough_specifications->fthrctrl = 2; + trough_specifications->accept_loc = 1; + trough_specifications->HDR_rough = 4.57e-5; + trough_specifications->theta_stow = 170.; + trough_specifications->theta_dep = 10.; + trough_specifications->Row_Distance = 15.; + + trough_specifications->T_loop_in_des = 293.; + trough_specifications->T_loop_out_des = 391.; + trough_specifications->T_startup = 0.67 * trough_specifications->T_loop_in_des + 0.33 * trough_specifications->T_loop_out_des; //[C] + trough_specifications->m_dot_htfmin = 1.; + trough_specifications->m_dot_htfmax = 12.; + double vals[] = { 0 }; + trough_specifications->field_fl_props.assign(vals, 1, 1); + trough_specifications->T_fp = 150.; + trough_specifications->I_bn_des = 950.; + trough_specifications->V_hdr_cold_max = 3.; + trough_specifications->V_hdr_cold_min = 2.; + trough_specifications->V_hdr_hot_max = 3.; + trough_specifications->V_hdr_hot_min = 2.; + trough_specifications->V_hdr_max = std::min(trough_specifications->V_hdr_cold_max, trough_specifications->V_hdr_hot_max); + trough_specifications->V_hdr_min = std::max(trough_specifications->V_hdr_cold_min, trough_specifications->V_hdr_hot_min); + trough_specifications->Pipe_hl_coef = 0.45; + trough_specifications->SCA_drives_elec = 125.; + trough_specifications->ColTilt = 0.; + trough_specifications->ColAz = 0.; + trough_specifications->wind_stow_speed = 25.; + trough_specifications->accept_mode = 0; + trough_specifications->accept_init = false; + trough_specifications->solar_mult = 2.; + trough_specifications->mc_bal_hot_per_MW = 0.2; + trough_specifications->mc_bal_cold_per_MW = 0.2; + trough_specifications->mc_bal_sca = 4.5; + + trough_specifications->W_aperture = { 6, 6, 6, 6 }; + trough_specifications->A_aperture = { 656, 656, 656, 656 }; + trough_specifications->TrackingError = { 0.988, 0.988, 0.988, 0.988 }; + trough_specifications->GeomEffects = { 0.952, 0.952, 0.952, 0.952 }; + trough_specifications->Rho_mirror_clean = { 0.93, 0.93, 0.93, 0.93 }; + trough_specifications->Dirt_mirror = { 0.97, 0.97, 0.97, 0.97 }; + trough_specifications->Error = { 1., 1., 1., 1. }; + trough_specifications->Ave_Focal_Length = { 2.15, 2.15, 2.15, 2.15 }; + trough_specifications->L_SCA = { 115., 115., 115., 115. }; + trough_specifications->L_aperture = { 14.375, 14.375, 14.375, 14.375 }; + trough_specifications->ColperSCA = { 8., 8., 8., 8. }; + trough_specifications->Distance_SCA = { 1., 1., 1., 1. }; + + double vals2[] = { + 1, 0.0327, -0.1351, + 1, 0.0327, -0.1351, + 1, 0.0327, -0.1351, + 1, 0.0327, -0.1351 }; + trough_specifications->IAM_matrix.assign(vals2, 4, 3); + + double vals3[] = { + 0.985, 0.01, 0.005, 0., + 1., 0., 0., 0., + 1., 0., 0., 0., + 1., 0., 0., 0. }; + trough_specifications->HCE_FieldFrac.assign(vals3, 4, 4); + + double vals4[] = { + 0.076, 0.076, 0.076, 0.076, + 0.076, 0.076, 0.076, 0.076, + 0.076, 0.076, 0.076, 0.076, + 0.076, 0.076, 0.076, 0.076 }; + trough_specifications->D_2.assign(vals4, 4, 4); + + double vals5[] = { + 0.08, 0.08, 0.08, 0.08, + 0.08, 0.08, 0.08, 0.08, + 0.08, 0.08, 0.08, 0.08, + 0.08, 0.08, 0.08, 0.08 }; + trough_specifications->D_3.assign(vals5, 4, 4); + + double vals6[] = { + 0.115, 0.115, 0.115, 0.115, + 0.115, 0.115, 0.115, 0.115, + 0.115, 0.115, 0.115, 0.115, + 0.115, 0.115, 0.115, 0.115 }; + trough_specifications->D_4.assign(vals6, 4, 4); + + double vals7[] = { + 0.12, 0.12, 0.12, 0.12, + 0.12, 0.12, 0.12, 0.12, + 0.12, 0.12, 0.12, 0.12, + 0.12, 0.12, 0.12, 0.12 }; + trough_specifications->D_5.assign(vals7, 4, 4); + + double vals8[] = { + 0., 0., 0., 0., + 0., 0., 0., 0., + 0., 0., 0., 0., + 0., 0., 0., 0. }; + trough_specifications->D_p.assign(vals8, 4, 4); + + double vals9[] = { + 1., 1., 1., 1., + 1., 1., 1., 1., + 1., 1., 1., 1., + 1., 1., 1., 1. }; + trough_specifications->Flow_type.assign(vals9, 4, 4); + + double vals10[] = { + 4.5e-5, 4.5e-5, 4.5e-5, 4.5e-5, + 4.5e-5, 4.5e-5, 4.5e-5, 4.5e-5, + 4.5e-5, 4.5e-5, 4.5e-5, 4.5e-5, + 4.5e-5, 4.5e-5, 4.5e-5, 4.5e-5 }; + trough_specifications->Rough.assign(vals10, 4, 4); + + double vals11[] = { + 0.02, 0.02, 0., 0., + 0.02, 0.02, 0., 0., + 0.02, 0.02, 0., 0., + 0.02, 0.02, 0., 0. }; + trough_specifications->alpha_env.assign(vals11, 4, 4); + + double vals12[] = { + 100., 150., 200., 250., 300., 350., 400., 450., 500., + 0.064, 0.0665, 0.07, 0.0745, 0.08, 0.0865, 0.094, 0.1025, 0.112 }; + trough_specifications->epsilon_3_11.assign(vals12, 2, 9); + + double vals13[] = { 0.65 }; + trough_specifications->epsilon_3_12.assign(vals13, 1, 1); + + double vals14[] = { 0.65 }; + trough_specifications->epsilon_3_13.assign(vals14, 1, 1); + + double vals15[] = { 0. }; + trough_specifications->epsilon_3_14.assign(vals15, 0, 0); + + double vals16[] = { + 100., 150., 200., 250., 300., 350., 400., 450., 500., + 0.064, 0.0665, 0.07, 0.0745, 0.08, 0.0865, 0.094, 0.1025, 0.112 }; + trough_specifications->epsilon_3_21.assign(vals16, 2, 9); + + double vals17[] = { 0.65 }; + trough_specifications->epsilon_3_22.assign(vals17, 1, 1); + + double vals18[] = { 0.65 }; + trough_specifications->epsilon_3_23.assign(vals18, 1, 1); + + double vals19[] = { 0. }; + trough_specifications->epsilon_3_24.assign(vals19, 1, 1); + + double vals20[] = { + 100., 150., 200., 250., 300., 350., 400., 450., 500., + 0.064, 0.0665, 0.07, 0.0745, 0.08, 0.0865, 0.094, 0.1025, 0.112 }; + trough_specifications->epsilon_3_31.assign(vals20, 2, 9); + + double vals21[] = { 0.65 }; + trough_specifications->epsilon_3_32.assign(vals21, 1, 1); + + double vals22[] = { 0.65 }; + trough_specifications->epsilon_3_33.assign(vals22, 1, 1); + + double vals23[] = { 0. }; + trough_specifications->epsilon_3_34.assign(vals23, 1, 1); + + double vals24[] = { + 100., 150., 200., 250., 300., 350., 400., 450., 500., + 0.064, 0.0665, 0.07, 0.0745, 0.08, 0.0865, 0.094, 0.1025, 0.112 }; + trough_specifications->epsilon_3_41.assign(vals24, 2, 9); + + double vals25[] = { 0.65 }; + trough_specifications->epsilon_3_42.assign(vals25, 1, 1); + + double vals26[] = { 0.65 }; + trough_specifications->epsilon_3_43.assign(vals26, 1, 1); + + double vals27[] = { 0. }; + trough_specifications->epsilon_3_44.assign(vals27, 1, 1); + + double vals28[] = { + 0.963, 0.963, 0.8, 0., + 0.963, 0.963, 0.8, 0., + 0.963, 0.963, 0.8, 0., + 0.963, 0.963, 0.8, 0. }; + trough_specifications->alpha_abs.assign(vals28, 4, 4); + + double vals29[] = { + 0.964, 0.964, 1., 0., + 0.964, 0.964, 1., 0., + 0.964, 0.964, 1., 0., + 0.964, 0.964, 1., 0. }; + trough_specifications->Tau_envelope.assign(vals29, 4, 4); + + double vals30[] = { + 0.86, 0.86, 1., 0., + 0.86, 0.86, 1., 0., + 0.86, 0.86, 1., 0., + 0.86, 0.86, 1., 0. }; + trough_specifications->EPSILON_4.assign(vals30, 4, 4); + + double vals31[] = { + 0.86, 0.86, 1., 0., + 0.86, 0.86, 1., 0., + 0.86, 0.86, 1., 0., + 0.86, 0.86, 1., 0. }; + trough_specifications->EPSILON_5.assign(vals31, 4, 4); + + double vals32[] = { + 1., 1., 0., 1., + 1., 1., 0., 1., + 1., 1., 0., 1., + 1., 1., 0., 1. }; + + trough_specifications->GlazingIntact_dbl.assign(vals32, 4, 4); + // convert to + int n_gl_row = (int)trough_specifications->GlazingIntact_dbl.nrows(); + int n_gl_col = (int)trough_specifications->GlazingIntact_dbl.ncols(); + trough_specifications->GlazingIntact.resize(n_gl_row, n_gl_col); + for (int i = 0; i < n_gl_row; i++) { + for (int j = 0; j < n_gl_col; j++) { + trough_specifications->GlazingIntact(i, j) = (trough_specifications->GlazingIntact_dbl(i, j) > 0); + } + } + + double vals33[] = { + 1.e-4, 750., 750., 0., + 1.e-4, 750., 750., 0., + 1.e-4, 750., 750., 0., + 1.e-4, 750., 750., 0., }; + trough_specifications->P_a.assign(vals33, 4, 4); + + double vals34[] = { + 27., 1., 1., 27., + 27., 1., 1., 27., + 27., 1., 1., 27., + 27., 1., 1., 27., }; + trough_specifications->AnnulusGas.assign(vals34, 4, 4); + + double vals35[] = { + 1., 1., 1., 1., + 1., 1., 1., 1., + 1., 1., 1., 1., + 1., 1., 1., 1., }; + trough_specifications->AbsorberMaterial.assign(vals35, 4, 4); + + double vals36[] = { + 0.935, 0.935, 0.935, 0.963, + 0.935, 0.935, 0.935, 0.963, + 0.935, 0.935, 0.935, 0.963, + 0.935, 0.935, 0.935, 0.963 }; + trough_specifications->Shadowing.assign(vals36, 4, 4); + + double vals37[] = { + 0.98, 0.98, 1., 0.98, + 0.98, 0.98, 1., 0.98, + 0.98, 0.98, 1., 0.98, + 0.98, 0.98, 1., 0.98, }; + trough_specifications->Dirt_HCE.assign(vals37, 4, 4); + + double vals38[] = { + 190., 1270., 1500., 0., + 190., 1270., 1500., 0., + 190., 1270., 1500., 0., + 190., 1270., 1500., 0. }; + trough_specifications->Design_loss.assign(vals38, 4, 4); + + double vals39[] = { + 1., 1., + 1., 1., + 1., 1., + 1., 1., + 1., 1., + 1., 1., + 1., 1., + 1., 1. }; + trough_specifications->SCAInfoArray.assign(vals39, 8, 2); + + trough_specifications->calc_design_pipe_vals = true; + trough_specifications->L_rnr_pb = 25.; + trough_specifications->N_max_hdr_diams = 10.; + trough_specifications->L_rnr_per_xpan = 70.; + trough_specifications->L_xpan_hdr = 20.; + trough_specifications->L_xpan_rnr = 20.; + trough_specifications->Min_rnr_xpans = 1.; + trough_specifications->northsouth_field_sep = 20.; + trough_specifications->N_hdr_per_xpan = 2.; + + double vals40[] = { + 0.9, 0., 0.19, 0., 0.9, -1., -1., -1., -1., -1., -1., + 0., 0.6, 0.05, 0., 0.6, 0., 0.6, 0., 0.42, 0., 0.15, + 0.05, 0., 0.42, 0., 0.6, 0., 0.6, 0., 0.42, 0., 0.15, + 0.05, 0., 0.42, 0., 0.6, 0., 0.6, 0., 0.42, 0., 0.15, + 0.05, 0., 0.42, 0., 0.6, 0., 0.6, 0., 0.42, 0., 0.15, + 0.05, 0., 0.42, 0., 0.6, 0., 0.6, 0., 0.42, 0., 0.15, + 0.05, 0., 0.42, 0., 0.6, 0., 0.6, 0., 0.42, 0., 0.15, + 0.05, 0., 0.42, 0., 0.6, 0., 0.6, 0., 0.42, 0., 0.15, + 0.05, 0., 0.42, 0., 0.6, 0., 0.6, 0., 0.42, 0., 0.15, + 0.05, 0., 0.42, 0., 0.6, 0., 0.6, 0., 0.15, 0.6, 0., + 0.9, 0., 0.19, 0., 0.9, -1., -1., -1., -1., -1., -1. }; + trough_specifications->K_cpnt.assign(vals40, 11, 11); + + double vals41[] = { + 0.085, 0.0635, 0.085, 0.0635, 0.085, -1., -1., -1., -1., -1., -1., + 0.085, 0.085, 0.085, 0.0635, 0.0635, 0.0635,0.0635, 0.0635, 0.0635, 0.0635, 0.085, + 0.085, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.085, + 0.085, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.085, + 0.085, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.085, + 0.085, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.085, + 0.085, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.085, + 0.085, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.085, + 0.085, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.085, + 0.085, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635,0.0635, 0.0635, 0.085, 0.085, 0.085, + 0.085, 0.0635, 0.085, 0.0635, 0.085, -1., -1., -1., -1., -1., -1. }; + trough_specifications->D_cpnt.assign(vals41, 11, 11); + + double vals42[] = { + 0., 0., 0., 0., 0., -1., -1., -1., -1., -1., -1., + 0., 0., 0., 1., 0., 0., 0., 1., 0., 1., 0., + 0., 1., 0., 1., 0., 0., 0., 1., 0., 1., 0., + 0., 1., 0., 1., 0., 0., 0., 1., 0., 1., 0., + 0., 1., 0., 1., 0., 0., 0., 1., 0., 1., 0., + 0., 1., 0., 1., 0., 0., 0., 1., 0., 1., 0., + 0., 1., 0., 1., 0., 0., 0., 1., 0., 1., 0., + 0., 1., 0., 1., 0., 0., 0., 1., 0., 1., 0., + 0., 1., 0., 1., 0., 0., 0., 1., 0., 1., 0., + 0., 1., 0., 1., 0., 0., 0., 1., 0., 0., 0., + 0., 0., 0., 0., 0., -1., -1., -1., -1., -1., -1. }; + trough_specifications->L_cpnt.assign(vals42, 11, 11); + + double vals43[] = { + 0., 1., 0., 1., 0., -1., -1., -1., -1., -1., -1., + 1., 0., 0., 2., 0., 1., 0., 2., 0., 2., 0., + 0., 2., 0., 2., 0., 1., 0., 2., 0., 2., 0., + 0., 2., 0., 2., 0., 1., 0., 2., 0., 2., 0., + 0., 2., 0., 2., 0., 1., 0., 2., 0., 2., 0., + 0., 2., 0., 2., 0., 1., 0., 2., 0., 2., 0., + 0., 2., 0., 2., 0., 1., 0., 2., 0., 2., 0., + 0., 2., 0., 2., 0., 1., 0., 2., 0., 2., 0., + 0., 2., 0., 2., 0., 1., 0., 2., 0., 2., 0., + 0., 2., 0., 2., 0., 1., 0., 2., 0., 0., 1., + 0., 1., 0., 1., 0., -1., -1., -1., -1., -1., -1. }; + trough_specifications->Type_cpnt.assign(vals43, 11, 11); + + trough_specifications->custom_sf_pipe_sizes = false; + + double vals44[] = { -1. }; + trough_specifications->sf_rnr_diams.assign(vals44, 1, 1); + + double vals45[] = { -1 }; + trough_specifications->sf_rnr_wallthicks.assign(vals45, 1, 1); + + double vals46[] = { -1 }; + trough_specifications->sf_rnr_lengths.assign(vals46, 1, 1); + + double vals47[] = { -1 }; + trough_specifications->sf_hdr_diams.assign(vals47, 1, 1); + + double vals48[] = { -1 }; + trough_specifications->sf_hdr_wallthicks.assign(vals48, 1, 1); + + double vals49[] = { -1 }; + trough_specifications->sf_hdr_lengths.assign(vals49, 1, 1); + + return trough_specifications; +} + +std::unique_ptr DefaultTroughFactory::MakeTroughState() const +{ + auto trough_state = std::unique_ptr(new TroughState); + trough_state->T_in_loop_prev = 574.6; + trough_state->T_out_loop_prev = 664.5; + trough_state->T_out_SCAs_prev.push_back(586.5); + trough_state->T_out_SCAs_prev.push_back(598.4); + trough_state->T_out_SCAs_prev.push_back(610.0); + trough_state->T_out_SCAs_prev.push_back(621.4); + trough_state->T_out_SCAs_prev.push_back(632.5); + trough_state->T_out_SCAs_prev.push_back(643.4); + trough_state->T_out_SCAs_prev.push_back(654.1); + trough_state->T_out_SCAs_prev.push_back(664.5); + + return trough_state; +} + +std::unique_ptr DefaultTroughFactory::MakeTimeLocationWeather(Location location) const +{ + auto time_and_weather = std::unique_ptr(new TimeAndWeather); + time_and_weather->m_year = 2009; + time_and_weather->m_month = 2; + time_and_weather->m_day = 14; + time_and_weather->m_hour = 12; + time_and_weather->m_minute = 0; + time_and_weather->m_beam = 1016.0; + time_and_weather->m_tdry = 16.0; + time_and_weather->m_tdew = -14.0; + time_and_weather->m_wspd = 1.2; + time_and_weather->m_pres = 920.0; + time_and_weather->m_solazi = 167.06; + time_and_weather->m_solzen = 45.79; + time_and_weather->m_lat = location.m_latitude; + time_and_weather->m_lon = location.m_longitude; + time_and_weather->m_tz = location.m_tz; + time_and_weather->m_shift = location.m_shift; + time_and_weather->m_elev = location.m_elev; + time_and_weather->m_global = std::numeric_limits::quiet_NaN(); + time_and_weather->m_hor_beam = std::numeric_limits::quiet_NaN(); // 433.1 + time_and_weather->m_diffuse = std::numeric_limits::quiet_NaN(); // 282 + time_and_weather->m_twet = std::numeric_limits::quiet_NaN(); + time_and_weather->m_wdir = std::numeric_limits::quiet_NaN(); // 88 + time_and_weather->m_rhum = std::numeric_limits::quiet_NaN(); + time_and_weather->m_snow = std::numeric_limits::quiet_NaN(); + time_and_weather->m_albedo = std::numeric_limits::quiet_NaN(); // 0.213 + time_and_weather->m_aod = std::numeric_limits::quiet_NaN(); + time_and_weather->m_poa = std::numeric_limits::quiet_NaN(); // 715.1 + time_and_weather->m_time_rise = std::numeric_limits::quiet_NaN(); // 7.486443134 + time_and_weather->m_time_set = std::numeric_limits::quiet_NaN(); // 17.46109472 + + return time_and_weather; +} + +TimestepAndTou DefaultTroughFactory::MakeTimestepAndTou() const +{ + TimestepAndTou timestep_and_tou; + timestep_and_tou.ms_ts.m_time_start = 3844800.; + timestep_and_tou.ms_ts.m_step = 3600.; + timestep_and_tou.ms_ts.m_time = timestep_and_tou.ms_ts.m_time_start + timestep_and_tou.ms_ts.m_step; + timestep_and_tou.m_tou = 1.; + return timestep_and_tou; +} + +FluidInletState DefaultTroughFactory::MakeInletState() const +{ + FluidInletState fluid_inlet_state; + fluid_inlet_state.m_temp = 296.5; + fluid_inlet_state.m_pres = std::numeric_limits::quiet_NaN(); + fluid_inlet_state.m_qual = -1.; + fluid_inlet_state.m_m_dot = std::numeric_limits::quiet_NaN(); + return fluid_inlet_state; +} + +double DefaultTroughFactory::MakeDefocus() const +{ + return 1.; +} + +Location DefaultTroughFactory::MakeLocation() const +{ + Location location; + location.m_latitude = 32.13000107; + location.m_longitude = -110.9400024; + location.m_tz = -7; + location.m_shift = -5.940002441; + location.m_elev = -773; + return location; +} +//========/DefaultTroughFactory=================================================================== diff --git a/test/shared_test/lib_csp_trough_test.h b/test/shared_test/lib_csp_trough_test.h new file mode 100644 index 00000000000..515e2a550d5 --- /dev/null +++ b/test/shared_test/lib_csp_trough_test.h @@ -0,0 +1,186 @@ +#ifndef __LIB_TROUGH_TEST_H__ +#define __LIB_TROUGH_TEST_H__ + +#include +#include "csp_solver_trough_collector_receiver.h" + +// Aliases (e.g., typedef) +using Trough = C_csp_trough_collector_receiver; +using Location = C_csp_collector_receiver::S_csp_cr_init_inputs; +using TroughSolvedParams = C_csp_collector_receiver::S_csp_cr_solved_params; +using TimeAndWeather = C_csp_weatherreader::S_outputs; +using FluidInletState = C_csp_solver_htf_1state; +using TimestepAndTou = C_csp_solver_sim_info; +using TroughOutputs = C_csp_collector_receiver::S_csp_cr_out_solver; + +namespace csp_trough +{ + struct TroughSpecifications; // forward declaration + struct TroughState; + + const double kErrorToleranceLo = 0.001; // 0.1% + const double kErrorToleranceHi = 0.01; // 1.0% + + class TroughFactory { + public: + TroughFactory() {}; + + virtual std::unique_ptr MakeTrough(Location location) const = 0; + std::unique_ptr MakeTrough(TroughSpecifications* trough_specifications, + Location location) const; + virtual std::unique_ptr MakeSpecifications() const = 0; + virtual std::unique_ptr MakeTroughState() const = 0; + virtual std::unique_ptr MakeTimeLocationWeather(Location location) const = 0; + virtual TimestepAndTou MakeTimestepAndTou() const = 0; + virtual FluidInletState MakeInletState() const = 0; + virtual double MakeDefocus() const = 0; + virtual Location MakeLocation() const = 0; + + static void SetTroughState(Trough* trough, TroughState* trough_state); + }; + + class DefaultTroughFactory : public TroughFactory { + public: + DefaultTroughFactory() {}; + + virtual std::unique_ptr MakeTrough(Location location) const; + virtual std::unique_ptr MakeSpecifications() const; + virtual std::unique_ptr MakeTroughState() const; + virtual std::unique_ptr MakeTimeLocationWeather(Location location) const; + virtual TimestepAndTou MakeTimestepAndTou() const; + virtual FluidInletState MakeInletState() const; + virtual double MakeDefocus() const; + virtual Location MakeLocation() const; + }; + + struct TroughSpecifications + { + int nSCA; //[-] Number of SCA's in a loop + int nHCEt; //[-] Number of HCE types + int nColt; //[-] Number of collector types + int nHCEVar; //[-] Number of HCE variants per t + int nLoops; //[-] Number of loops in the field + int FieldConfig; //[-] Number of subfield headers + double L_power_block_piping; //[m] Length of piping (full mass flow) through power block (if applicable) + bool include_fixed_power_block_runner; //[-] Should model consider piping through power block (is_model_power_block_piping)? + double eta_pump; //[-] HTF pump efficiency + int Fluid; //[-] Field HTF fluid number + //int fthrok; //[-] Flag to allow partial defocusing of the collectors + int fthrctrl; //[-] Defocusing strategy; hardcode2 for now + int accept_loc; //[-] In acceptance testing mode - temperature sensor location (1=hx,2=loop) + double HDR_rough; //[m] Header pipe roughness + double theta_stow; //[deg] stow angle + double theta_dep; //[deg] deploy angle + double Row_Distance; //[m] Spacing between rows (centerline to centerline) + + double T_loop_in_des; //[C] Design loop inlet temperature, converted to K in init + double T_loop_out_des; //[C] Target loop outlet temperature, converted to K in init + double T_startup; //[C] The required temperature (converted to K in init) of the system before the power block can be switched on + double m_dot_htfmin; //[kg/s] Minimum loop HTF flow rate + double m_dot_htfmax; //[kg/s] Maximum loop HTF flow rate + util::matrix_t field_fl_props; //[-] User-defined field HTF properties + double T_fp; //[C] Freeze protection temperature (heat trace activation temperature), convert to K in init + double I_bn_des; //[W/m^2] Solar irradiation at design + double V_hdr_cold_max; //[m/s] Maximum HTF velocity in the cold header at design + double V_hdr_cold_min; //[m/s] Minimum HTF velocity in the cold header at design + double V_hdr_hot_max; //[m/s] Maximum HTF velocity in the hot header at design + double V_hdr_hot_min; //[m/s] Minimum HTF velocity in the hot header at design + double V_hdr_max; //[m/s] Maximum HTF velocity in the header at design, for backwards compatibility, marked for removal + double V_hdr_min; //[m/s] Minimum HTF velocity in the header at design, for backwards compatibility, marked for removal + double Pipe_hl_coef; //[W/m2-K] Loss coefficient from the header, runner pipe, and non-HCE piping + double SCA_drives_elec; //[W/SCA] Tracking power, in Watts per SCA drive + double ColTilt; //[deg] Collector tilt angle (0 is horizontal, 90deg is vertical) ("tilt") + double ColAz; //[deg] Collector azimuth angle ("azimuth") + double wind_stow_speed; //[m/s] Wind speed at and above which the collectors will be stowed + int accept_mode; //[-] Acceptance testing mode? (1=yes, 0=no) + bool accept_init; //[-] In acceptance testing mode - require steady-state startup + double solar_mult; //[-] Solar Multiple + double mc_bal_hot_per_MW; //[kWht/K-MWt] The heat capacity of the balance of plant on the hot side ("mc_bal_hot") + double mc_bal_cold_per_MW; //[kWht/K-MWt] The heat capacity of the balance of plant on the cold side ("mc_bal_cold") + double mc_bal_sca; //[Wht/K-m] Non-HTF heat capacity associated with each SCA - per meter basis + + std::vector W_aperture; //[m] The collector aperture width (Total structural area.. used for shadowing) + std::vector A_aperture; //[m^2] Reflective aperture area of the collector + std::vector TrackingError; //[-] Tracking error derate + std::vector GeomEffects; //[-] Geometry effects derate + std::vector Rho_mirror_clean; //[-] Clean mirror reflectivity + std::vector Dirt_mirror; //[-] Dirt on mirror derate + std::vector Error; //[-] General optical error derate + std::vector Ave_Focal_Length; //[m] The average focal length of the collector + std::vector L_SCA; //[m] The length of the SCA + std::vector L_aperture; //[m] The length of a single mirror/HCE unit + std::vector ColperSCA; //[-] The number of individual collector sections in an SCA + std::vector Distance_SCA; //[m] Piping distance between SCA's in the field + + util::matrix_t IAM_matrix; //[-] IAM coefficients, matrix for 4 collectors + util::matrix_t HCE_FieldFrac; //[-] Fraction of the field occupied by this HCE type + util::matrix_t D_2; //[m] Inner absorber tube diameter + util::matrix_t D_3; //[m] Outer absorber tube diameter + util::matrix_t D_4; //[m] Inner glass envelope diameter + util::matrix_t D_5; //[m] Outer glass envelope diameter + util::matrix_t D_p; //[m] Diameter of the absorber flow plug (optional) + util::matrix_t Flow_type; //[-] Flow type through the absorber + util::matrix_t Rough; //[m] Roughness of the internal surface + util::matrix_t alpha_env; //[-] Envelope absorptance + + util::matrix_t epsilon_3_11; //[-] Absorber emittance for receiver type 1 variation 1 + util::matrix_t epsilon_3_12; //[-] Absorber emittance for receiver type 1 variation 2 + util::matrix_t epsilon_3_13; //[-] Absorber emittance for receiver type 1 variation 3 + util::matrix_t epsilon_3_14; //[-] Absorber emittance for receiver type 1 variation 4 + util::matrix_t epsilon_3_21; //[-] Absorber emittance for receiver type 2 variation 1 + util::matrix_t epsilon_3_22; //[-] Absorber emittance for receiver type 2 variation 2 + util::matrix_t epsilon_3_23; //[-] Absorber emittance for receiver type 2 variation 3 + util::matrix_t epsilon_3_24; //[-] Absorber emittance for receiver type 2 variation 4 + util::matrix_t epsilon_3_31; //[-] Absorber emittance for receiver type 3 variation 1 + util::matrix_t epsilon_3_32; //[-] Absorber emittance for receiver type 3 variation 2 + util::matrix_t epsilon_3_33; //[-] Absorber emittance for receiver type 3 variation 3 + util::matrix_t epsilon_3_34; //[-] Absorber emittance for receiver type 3 variation 4 + util::matrix_t epsilon_3_41; //[-] Absorber emittance for receiver type 4 variation 1 + util::matrix_t epsilon_3_42; //[-] Absorber emittance for receiver type 4 variation 2 + util::matrix_t epsilon_3_43; //[-] Absorber emittance for receiver type 4 variation 3 + util::matrix_t epsilon_3_44; //[-] Absorber emittance for receiver type 4 variation 4 + + util::matrix_t alpha_abs; //[-] Absorber absorptance + util::matrix_t Tau_envelope; //[-] Envelope transmittance + util::matrix_t EPSILON_4; //[-] Inner glass envelope emissivities + util::matrix_t EPSILON_5; //[-] Outer glass envelope emissivities + util::matrix_t GlazingIntact_dbl; //[-] Glazing intact (broken glass) flag {1=true, else=false}, as double + util::matrix_t GlazingIntact; //[-] Glazing intact (broken glass) flag {1=true, else=false} + util::matrix_t P_a; //[torr] Annulus gas pressure + util::matrix_t AnnulusGas; //[-] Annulus gas type (1=air, 26=Ar, 27=H2) + util::matrix_t AbsorberMaterial; //[-] Absorber material type + util::matrix_t Shadowing; //[-] Receiver bellows shadowing loss factor + util::matrix_t Dirt_HCE; //[-] Loss due to dirt on the receiver envelope + util::matrix_t Design_loss; //[-] Receiver heat loss at design + util::matrix_t SCAInfoArray; //[-] Receiver (,1) and collector (,2) type for each assembly in loop + + bool calc_design_pipe_vals; //[-] Should the HTF state be calculated at design conditions + double L_rnr_pb; //[m] Length of hot or cold runner pipe around the power block + double N_max_hdr_diams; //[-] Maximum number of allowed diameters in each of the hot and cold headers + double L_rnr_per_xpan; //[m] Threshold length of straight runner pipe without an expansion loop + double L_xpan_hdr; //[m] Combined length in meters of the two perpendicular segments of a header expansion loop + double L_xpan_rnr; //[m] Combined length in meters of the two perpendicular segments of a runner expansion loop + double Min_rnr_xpans; //[-] Minimum number of expansion loops per single-diameter runner section + double northsouth_field_sep; //[m] Shortest north/south distance between SCAs in different subfields + double N_hdr_per_xpan; //[-] Number of collector loops per header expansion loops. 1expansion loop between every collector loop + util::matrix_t K_cpnt; //[-] Minor loss coefficients of the components in each loop interconnect + util::matrix_t D_cpnt; //[m] Inner diameters of the components in each loop interconnect + util::matrix_t L_cpnt; //[m] Lengths of the components in each loop interconnect + util::matrix_t Type_cpnt; //[-] Type of component in each loop interconnect [0=fitting | 1=pipe | 2=flex_hose] + bool custom_sf_pipe_sizes; //[-] Should the field pipe diameters, wall thickness and lengths be imported instead of calculated + util::matrix_t sf_rnr_diams; //[m] Imported runner diameters, used if custom_sf_pipe_sizes is true + util::matrix_t sf_rnr_wallthicks; //[m] Imported runner wall thicknesses, used if custom_sf_pipe_sizes is true + util::matrix_t sf_rnr_lengths; //[m] Imported runner lengths, used if custom_sf_pipe_sizes is true + util::matrix_t sf_hdr_diams; //[m] Imported header diameters, used if custom_sf_pipe_sizes is true + util::matrix_t sf_hdr_wallthicks; //[m] Imported header wall thicknesses, used if custom_sf_pipe_sizes is true + util::matrix_t sf_hdr_lengths; //[m] Imported header lengths, used if custom_sf_pipe_sizes is true + }; + + struct TroughState + { + double T_in_loop_prev; // corresponds to m_T_sys_c_t_end_converged + double T_out_loop_prev; // corresponds to m_T_sys_h_t_end_converged + std::vector T_out_SCAs_prev; // corresponds to m_T_htf_out_t_end_converged; + }; +} +#endif diff --git a/test/shared_test/lib_irradproc_test.cpp b/test/shared_test/lib_irradproc_test.cpp index e135bb25a27..4bdd6e0f4a6 100644 --- a/test/shared_test/lib_irradproc_test.cpp +++ b/test/shared_test/lib_irradproc_test.cpp @@ -15,7 +15,7 @@ TEST_F(NightCaseIrradProc, solarposTest_lib_irradproc) { double sun[9]; vector sunrise_times; vector sunset_times; - + e = 0.0001; /* Just before sunrise test case */ solarpos(year, month, day, 4, 30, lat, lon, tz, sun); vector solution = { 0.95662, 1.79457, -0.223771, 0.363938, 5.70882, 19.5183, 0.968276, 3.88646, 0 }; @@ -141,6 +141,21 @@ TEST_F(IrradTest, sunriseAndSunsetAlaskaTest_spa_lib_irradproc) { EXPECT_NEAR((double)sun_results[5], sunset_time, e) << "sunrise time for lat " << latitude << " long " << longitude << " failed\n"; } +TEST_F(IrradTest, atmos_refractionTest_spa_lib_irradproc) { + //Test to check for atmospheric refraction correction occuring only if sun is above horizon + double latitude = 31.6430; + double longitude = 74.8723; + double time_zone = 5.5; + double elevation_angle = -.00175; //topocentric elevation angle corrected for atmospheric refraction (radians) + //double sunset_time = 17.514; + int month = 7; + int day = 19; + double sun_results[9]; + double alt = 0; + solarpos_spa(2017, month, day, 5, 39, 0, latitude, longitude, time_zone, 0, 234, 1013.25, 15, latitude, 180, sun_results); + EXPECT_NEAR((double)sun_results[2], elevation_angle, e) << "elevation angle for lat " << latitude << " long " << longitude << " failed\n"; +} + TEST_F(DayCaseIrradProc, solarposTest_lib_irradproc) { double sun[9]; @@ -200,7 +215,7 @@ TEST_F(NightCaseIrradProc, solarpos_spaTest_lib_irradproc) { double needed[13]; vector sunrise_times; vector sunset_times; - + e = 0.0001; /* Just before sunrise test case */ solarpos_spa(year, month, day, 4, 30, 0, lat, lon, tz, 0, 0, 1016, 15, lat, 180, sun); vector solution = { 0.95668, 1.80432, -0.233522, 0.363905, 5.636927, 19.584888, 0.968276, 3.88691, 0 }; @@ -239,7 +254,7 @@ TEST_F(SunriseCaseIrradProc, solarpos_spaTest_lib_irradproc) { double needed[13]; vector sunrise_times; vector sunset_times; - + e = 0.0001; solarpos_spa(year, month, day, 5, 30, 0, lat, lon, tz, 0, 234, 1016, 15, lat, 180, sun); vector solution = { 1.11053, 1.61284, -0.0420474, 0.363777, 5.636927, 19.584888, 0.968281, 4.88686, 0 }; sunrise_times.push_back(solution[4]); @@ -286,7 +301,7 @@ TEST_F(SunsetCaseIrradProc, solarpos_spaTest_lib_irradproc) { double needed[13]; vector sunrise_times; vector sunset_times; - + e = 0.0001; solarpos_spa(year, month, day, 19, 30, 0, lat, lon, tz, 0, 234, 1016, 15, lat, 180, sun); vector solution = { 5.13951, 1.56025, 0.010544, 0.361913, 5.636927, 19.584888, 0.968356, 18.88622, 13.98903 }; sunrise_times.push_back(solution[4]); @@ -794,3 +809,5 @@ TEST(SingleAxisTrackingTest, SunBelowTiltedArray) { double bt = backtrack(tt, 0.4); ASSERT_NEAR(bt, 16.15566, 1e-4); } + + diff --git a/test/shared_test/lib_solar_thermal_test.cpp b/test/shared_test/lib_solar_thermal_test.cpp new file mode 100644 index 00000000000..72bb3140e8a --- /dev/null +++ b/test/shared_test/lib_solar_thermal_test.cpp @@ -0,0 +1,175 @@ +#include + +#include "lib_solar_thermal_test.h" +#include "vs_google_test_explorer_namespace.h" + +using namespace solar_thermal; + +//========Tests=================================================================================== +//=== Using factory patterns to create the different physical and non-physical components========= + +// Basic test of expected power gain and outlet temperature of a single flat plate collector +NAMESPACE_TEST(solar_thermal, FlatPlateCollectorTest, TestFlatPlateCollectorNominalOperation) +{ + DefaultFpcFactory default_fpc_factory = DefaultFpcFactory(); + std::unique_ptr flat_plate_collector = default_fpc_factory.MakeCollector(); + std::unique_ptr time_and_position = default_fpc_factory.MakeTimeAndPosition(); + std::unique_ptr external_conditions = default_fpc_factory.MakeExternalConditions(); + + double useful_power_gain = flat_plate_collector->UsefulPowerGain(*time_and_position, *external_conditions); // [W] + double T_out = flat_plate_collector->T_out(*time_and_position, *external_conditions); // [C] + + EXPECT_NEAR(useful_power_gain, 1.659e3, 1.659e3 * kErrorToleranceHi); + EXPECT_NEAR(T_out, 50.26, 50.26 * kErrorToleranceHi); +} + +// Basic test of expected power gain and outlet temperature of a flat plate collector array +// Uses a factory (abstract factory pattern) to create the different physical and non-physical components +NAMESPACE_TEST(solar_thermal, FlatPlateArrayTest, TestFlatPlateArrayOfOneNominalOperation) +{ + DefaultFpcFactory default_fpc_factory = DefaultFpcFactory(); + std::unique_ptr flat_plate_array = default_fpc_factory.MakeFpcArray(); + tm timestamp = default_fpc_factory.MakeTime(); + std::unique_ptr external_conditions = default_fpc_factory.MakeExternalConditions(); + external_conditions->inlet_fluid_flow.temp = 44.86; + + double useful_power_gain = flat_plate_array->UsefulPowerGain(timestamp, *external_conditions); // [W] + double T_out = flat_plate_array->T_out(timestamp, *external_conditions); // [C] + + EXPECT_NEAR(useful_power_gain, 1.587e3, 1.587e3 * kErrorToleranceHi); + EXPECT_NEAR(T_out, 49.03, 49.03 * kErrorToleranceHi); +} +//========/Tests================================================================================== + +//========Factories:============================================================================== +//========FpcFactory (super class)================================================================ +std::unique_ptr FpcFactory::MakeFpcArray(FlatPlateCollector* flat_plate_collector, + CollectorLocation* collector_location, + CollectorOrientation* collector_orientation, + ArrayDimensions* array_dimensions, + Pipe* inlet_pipe, + Pipe* outlet_pipe) const +{ + return std::unique_ptr(new FlatPlateArray(*flat_plate_collector, *collector_location, + *collector_orientation, *array_dimensions, *inlet_pipe, *outlet_pipe)); +} + +std::unique_ptr FpcFactory::MakeCollector(CollectorTestSpecifications* collector_test_specifications) const +{ + return std::unique_ptr(new FlatPlateCollector(*collector_test_specifications)); +} + +std::unique_ptr FpcFactory::MakeTimeAndPosition() const +{ + auto time_and_position = std::unique_ptr(new TimeAndPosition); + time_and_position->timestamp = this->MakeTime(); + time_and_position->collector_location = this->MakeLocation(); + time_and_position->collector_orientation = this->MakeOrientation(); + + return time_and_position; +} +//========/FpcFactory============================================================================ + +//========DefaultFPCFactory (subclass)=========================================================== +std::unique_ptr DefaultFpcFactory::MakeFpcArray() const +{ + std::unique_ptr flat_plate_collector = this->MakeCollector(); + CollectorLocation collector_location = this->MakeLocation(); + CollectorOrientation collector_orientation = this->MakeOrientation(); + ArrayDimensions array_dimensions = this->MakeArrayDimensions(); + + std::unique_ptr inlet_pipe = this->MakePipe(); + std::unique_ptr outlet_pipe = this->MakePipe(); + + return std::unique_ptr(new FlatPlateArray(*flat_plate_collector, collector_location, + collector_orientation, array_dimensions, *inlet_pipe, *outlet_pipe)); +} + +std::unique_ptr DefaultFpcFactory::MakeCollector() const +{ + std::unique_ptr collector_test_specifications = this->MakeTestSpecifications(); + return std::unique_ptr(new FlatPlateCollector(*collector_test_specifications)); +} + +std::unique_ptr DefaultFpcFactory::MakeTestSpecifications() const +{ + auto collector_test_specifications = std::unique_ptr(new CollectorTestSpecifications()); + collector_test_specifications->FRta = 0.689; + collector_test_specifications->FRUL = 3.85; + collector_test_specifications->iam = 0.2; + collector_test_specifications->area_coll = 2.98; + collector_test_specifications->m_dot = 0.045528; // kg/s + collector_test_specifications->heat_capacity = 4.182; // kJ/kg-K + + return collector_test_specifications; +} + +CollectorLocation DefaultFpcFactory::MakeLocation() const +{ + CollectorLocation collector_location; + collector_location.latitude = 33.45000; + collector_location.longitude = -111.98000; + collector_location.timezone = -7; + + return collector_location; +} + +CollectorOrientation DefaultFpcFactory::MakeOrientation() const +{ + CollectorOrientation collector_orientation; + collector_orientation.tilt = 30.; + collector_orientation.azimuth = 180.; + + return collector_orientation; +} + +std::unique_ptr DefaultFpcFactory::MakePipe() const +{ + double inner_diameter = 0.019; + double insulation_conductivity = 0.03; + double insulation_thickness = 0.006; + double length = 5; + + return std::unique_ptr(new Pipe(inner_diameter, insulation_conductivity, insulation_thickness, length)); +} + +std::unique_ptr DefaultFpcFactory::MakeExternalConditions() const +{ + auto external_conditions = std::unique_ptr(new ExternalConditions); + external_conditions->weather.ambient_temp = 25.; + external_conditions->weather.dni = 935.; + external_conditions->weather.dhi = 84.; + external_conditions->weather.ghi = std::numeric_limits::quiet_NaN(); + external_conditions->weather.wind_speed = std::numeric_limits::quiet_NaN(); + external_conditions->weather.wind_direction = std::numeric_limits::quiet_NaN(); + external_conditions->inlet_fluid_flow.m_dot = 0.091056; // kg/s + external_conditions->inlet_fluid_flow.specific_heat = 4.182; // kJ/kg-K + external_conditions->inlet_fluid_flow.temp = 45.9; // from previous timestep + external_conditions->albedo = 0.2; + + return external_conditions; +} + +tm DefaultFpcFactory::MakeTime() const +{ + tm time; + // TODO - The timestamp should be generated from a string so all attributes are valid + time.tm_year = 2012 - 1900; // years since 1900 + time.tm_mon = 1 - 1; // months since Jan. (Jan. = 0) + time.tm_mday = 1; + time.tm_hour = 12; + time.tm_min = 30; + time.tm_sec = 0; + + return time; +} + +ArrayDimensions DefaultFpcFactory::MakeArrayDimensions() const +{ + ArrayDimensions array_dimensions; + array_dimensions.num_in_parallel = 1; + array_dimensions.num_in_series = 1; + + return array_dimensions; +} +//========/DefaultFpcFactory====================================================================== diff --git a/test/shared_test/lib_solar_thermal_test.h b/test/shared_test/lib_solar_thermal_test.h new file mode 100644 index 00000000000..aa15759719b --- /dev/null +++ b/test/shared_test/lib_solar_thermal_test.h @@ -0,0 +1,53 @@ +#ifndef __LIB_CSP_TEST_H__ +#define __LIB_CSP_TEST_H__ + +#include +#include "../tcs/flat_plate_solar_collector.h" + +namespace solar_thermal +{ + const double kErrorToleranceLo = 0.001; // 0.1% + const double kErrorToleranceHi = 0.01; // 1.0% + + class FpcFactory { + public: + FpcFactory() {}; + + virtual std::unique_ptr MakeFpcArray() const = 0; + std::unique_ptr MakeFpcArray(FlatPlateCollector* flat_plate_collector, + CollectorLocation* collector_location, + CollectorOrientation* collector_orientation, + ArrayDimensions* array_dimensions, + Pipe* inlet_pipe, + Pipe* outlet_pipe) const; + virtual std::unique_ptr MakeCollector() const = 0; + std::unique_ptr MakeCollector(CollectorTestSpecifications* collector_test_specifications) const; + std::unique_ptr MakeTimeAndPosition() const; + + virtual std::unique_ptr MakeTestSpecifications() const = 0; + virtual CollectorLocation MakeLocation() const = 0; + virtual CollectorOrientation MakeOrientation() const = 0; + virtual std::unique_ptr MakePipe() const = 0; + virtual std::unique_ptr MakeExternalConditions() const = 0; + virtual tm MakeTime() const = 0; + virtual ArrayDimensions MakeArrayDimensions() const = 0; + }; + + class DefaultFpcFactory : public FpcFactory { + public: + DefaultFpcFactory() {}; + + virtual std::unique_ptr MakeFpcArray() const; + virtual std::unique_ptr MakeCollector() const; + + virtual std::unique_ptr MakeTestSpecifications() const; + virtual CollectorLocation MakeLocation() const; + virtual CollectorOrientation MakeOrientation() const; + virtual std::unique_ptr MakePipe() const; + virtual std::unique_ptr MakeExternalConditions() const; + virtual tm MakeTime() const; + virtual ArrayDimensions MakeArrayDimensions() const; + }; +} + +#endif diff --git a/test/shared_test/lib_utility_rate_test.cpp b/test/shared_test/lib_utility_rate_test.cpp index e84e5d74197..66761a3abf7 100644 --- a/test/shared_test/lib_utility_rate_test.cpp +++ b/test/shared_test/lib_utility_rate_test.cpp @@ -24,8 +24,8 @@ TEST(lib_utility_rate_test, test_copy) int steps_per_hour = 1; std::vector monthly_load_forecast = { 25, 25, 25, 25, 25, 25 }; std::vector monthly_gen_forecast = { 0, 0, 0, 0, 0, 0, }; - std::vector monthly_peak_forecast = { 25, 25, 25, 25, 25, 25 }; - UtilityRateForecast rate_forecast_1(&data, steps_per_hour, monthly_load_forecast, monthly_gen_forecast, monthly_peak_forecast, 2); + std::vector monthly_avg_gross_load = { 25, 25, 25, 25, 25, 25 }; + UtilityRateForecast rate_forecast_1(&data, steps_per_hour, monthly_load_forecast, monthly_gen_forecast, monthly_avg_gross_load, 2); UtilityRateForecast rate_forecast_2(rate_forecast_1); @@ -72,10 +72,10 @@ TEST(lib_utility_rate_test, test_tiered_tou_cost_estimates) monthly_load_forecast.push_back(25); // Rates above are kWh/day, but don't want to test that just yet std::vector monthly_gen_forecast; monthly_gen_forecast.push_back(0); - std::vector monthly_peak_forecast; - monthly_peak_forecast.push_back(7); + std::vector monthly_avg_gross_load; + monthly_avg_gross_load.push_back(7); - UtilityRateForecast rate_forecast(&data, steps_per_hour, monthly_load_forecast, monthly_gen_forecast, monthly_peak_forecast, 2); + UtilityRateForecast rate_forecast(&data, steps_per_hour, monthly_load_forecast, monthly_gen_forecast, monthly_avg_gross_load, 2); rate_forecast.compute_next_composite_tou(0, 0); @@ -117,10 +117,10 @@ TEST(lib_utility_rate_test, test_tiered_sell_rates) monthly_load_forecast.push_back(0); // Rates above are kWh/day, but don't want to test that just yet std::vector monthly_gen_forecast; monthly_gen_forecast.push_back(10); - std::vector monthly_peak_forecast; - monthly_peak_forecast.push_back(7); + std::vector monthly_avg_gross_load; + monthly_avg_gross_load.push_back(7); - UtilityRateForecast rate_forecast(&data, steps_per_hour, monthly_load_forecast, monthly_gen_forecast, monthly_peak_forecast, 2); + UtilityRateForecast rate_forecast(&data, steps_per_hour, monthly_load_forecast, monthly_gen_forecast, monthly_avg_gross_load, 2); rate_forecast.compute_next_composite_tou(0, 0); @@ -143,9 +143,9 @@ TEST(lib_utility_rate_test, test_simple_demand_charges) int steps_per_hour = 1; std::vector monthly_load_forecast = { 31 * 24, 28 * 24 }; // Average load is 1 kW std::vector monthly_gen_forecast = { 0, 0 }; - std::vector monthly_peak_forecast = { 1, 1 }; + std::vector monthly_avg_gross_load = { 1, 1 }; - UtilityRateForecast rate_forecast(&data, steps_per_hour, monthly_load_forecast, monthly_gen_forecast, monthly_peak_forecast, 2); + UtilityRateForecast rate_forecast(&data, steps_per_hour, monthly_load_forecast, monthly_gen_forecast, monthly_avg_gross_load, 2); // - is load std::vector forecast = { -1, -1, 0, -2 }; // Demand charge increases by 1 kW from average @@ -171,9 +171,9 @@ TEST(lib_utility_rate_test, test_demand_charges_crossing_months) int steps_per_hour = 1; std::vector monthly_load_forecast = { 150, 75 }; std::vector monthly_gen_forecast = { 0, 0 }; - std::vector monthly_peak_forecast = { 100, 50 }; + std::vector monthly_avg_gross_load = { 100, 50 }; - UtilityRateForecast rate_forecast(&data, steps_per_hour, monthly_load_forecast, monthly_gen_forecast, monthly_peak_forecast, 2); + UtilityRateForecast rate_forecast(&data, steps_per_hour, monthly_load_forecast, monthly_gen_forecast, monthly_avg_gross_load, 2); // - is load std::vector forecast = {-100, -50, -50, -25}; @@ -183,8 +183,33 @@ TEST(lib_utility_rate_test, test_demand_charges_crossing_months) int hour_of_year = 742; // 10 pm on Jan 31st double cost = rate_forecast.forecastCost(forecast, 0, hour_of_year, 0); - // Total cost for the months would be $1511.25, but this subtracts off the peaks predicted by average load ($3.12) - ASSERT_NEAR(1508.11, cost, 0.02); + // Total cost for the months would be $1511.25, but this subtracts off the peaks predicted by average gross load ($1500) + ASSERT_NEAR(11.25, cost, 0.02); +} + +// Test imperfect peak forecast +TEST(lib_utility_rate_test, test_demand_charges_inaccurate_forecast) +{ + rate_data data; + set_up_default_commercial_rate_data(data); // Net billing + + int steps_per_hour = 1; + std::vector monthly_load_forecast = { 150, 75 }; + std::vector monthly_gen_forecast = { 0, 0 }; + std::vector monthly_avg_gross_load = { 50, 0 }; + + UtilityRateForecast rate_forecast(&data, steps_per_hour, monthly_load_forecast, monthly_gen_forecast, monthly_avg_gross_load, 2); + + // - is load + std::vector forecast = { -100, -50, -50, -25 }; + rate_forecast.initializeMonth(0, 0); + rate_forecast.copyTOUForecast(); + + int hour_of_year = 742; // 10 pm on Jan 31st + double cost = rate_forecast.forecastCost(forecast, 0, hour_of_year, 0); + + // Total cost for the months would be $1511.25, but this subtracts off the peaks predicted ($500) + ASSERT_NEAR(1011.25, cost, 0.02); } // Excel implementation of these results is available at https://github.com/NREL/SAM-documentation/blob/master/Unit%20Testing/Utility%20Rates/UtilityRateForecast/lib_utility_rate_test_cross_checks.xlsx @@ -196,9 +221,9 @@ TEST(lib_utility_rate_test, test_changing_rates_crossing_months) int steps_per_hour = 1; std::vector monthly_load_forecast = { 0, 0, 0, 150, 75 }; std::vector monthly_gen_forecast = { 0, 0, 0, 0, 0 }; - std::vector monthly_peak_forecast = { 0, 0, 0, 100, 50 }; + std::vector monthly_avg_gross_load = { 0, 0, 0, 100, 50 }; - UtilityRateForecast rate_forecast(&data, steps_per_hour, monthly_load_forecast, monthly_gen_forecast, monthly_peak_forecast, 2); + UtilityRateForecast rate_forecast(&data, steps_per_hour, monthly_load_forecast, monthly_gen_forecast, monthly_avg_gross_load, 2); // - is load std::vector forecast = { -100, -50, -50, -25 }; @@ -208,8 +233,8 @@ TEST(lib_utility_rate_test, test_changing_rates_crossing_months) int hour_of_year = 2878; // 10 pm on Apr 30th double cost = rate_forecast.forecastCost(forecast, 0, hour_of_year, 0); - // Total cost for the months would be $1513.13, but this subtracts off the peaks predicted by average load ($3.09) - ASSERT_NEAR(1510.03, cost, 0.02); + // Total cost for the months would be $1513.13, but this subtracts off the peaks predicted by average gross load forecast ($1500) + ASSERT_NEAR(13.125, cost, 0.02); } TEST(lib_utility_rate_test, test_demand_charges_crossing_year) @@ -220,9 +245,9 @@ TEST(lib_utility_rate_test, test_demand_charges_crossing_year) int steps_per_hour = 1; std::vector monthly_load_forecast = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 150, 75 }; std::vector monthly_gen_forecast = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - std::vector monthly_peak_forecast = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 50 }; + std::vector monthly_avg_gross_load = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 50 }; - UtilityRateForecast rate_forecast(&data, steps_per_hour, monthly_load_forecast, monthly_gen_forecast, monthly_peak_forecast, 2); + UtilityRateForecast rate_forecast(&data, steps_per_hour, monthly_load_forecast, monthly_gen_forecast, monthly_avg_gross_load, 2); // - is load std::vector forecast = { -100, -50, -50, -25 }; @@ -232,7 +257,7 @@ TEST(lib_utility_rate_test, test_demand_charges_crossing_year) int hour_of_year = 8758; // 10 pm on Dec 31st double cost = rate_forecast.forecastCost(forecast, 0, hour_of_year, 0); - ASSERT_NEAR(1520.79, cost, 0.02); + ASSERT_NEAR(11.34, cost, 0.02); } // Net billing with a sell rate @@ -277,9 +302,9 @@ TEST(lib_utility_rate_test, test_sell_rates) int steps_per_hour = 1; std::vector monthly_load_forecast = { 150, 75 }; std::vector monthly_gen_forecast = { 0, 100 }; - std::vector monthly_peak_forecast = { 100, 50 }; + std::vector monthly_avg_gross_load = { 100, 50 }; - UtilityRateForecast rate_forecast(&data, steps_per_hour, monthly_load_forecast, monthly_gen_forecast, monthly_peak_forecast, 2); + UtilityRateForecast rate_forecast(&data, steps_per_hour, monthly_load_forecast, monthly_gen_forecast, monthly_avg_gross_load, 2); // - is load std::vector forecast = { -100, -50, -50, -25, 25, 50, 25 }; @@ -290,7 +315,7 @@ TEST(lib_utility_rate_test, test_sell_rates) double cost = rate_forecast.forecastCost(forecast, 0, hour_of_year, 0); - ASSERT_NEAR(1506.11, cost, 0.02); + ASSERT_NEAR(9.25, cost, 0.02); } TEST(lib_utility_rate_test, test_net_metering_one_tou_period) @@ -301,9 +326,9 @@ TEST(lib_utility_rate_test, test_net_metering_one_tou_period) int steps_per_hour = 1; std::vector monthly_load_forecast = { 150, 75 }; std::vector monthly_gen_forecast = { 0, 0 }; - std::vector monthly_peak_forecast = { 100, 50 }; + std::vector monthly_avg_gross_load = { 100, 50 }; - UtilityRateForecast rate_forecast(&data, steps_per_hour, monthly_load_forecast, monthly_gen_forecast, monthly_peak_forecast, 2); + UtilityRateForecast rate_forecast(&data, steps_per_hour, monthly_load_forecast, monthly_gen_forecast, monthly_avg_gross_load, 2); // - is load std::vector forecast = { -100, -50, 50, 100 }; // Net zero load @@ -331,9 +356,9 @@ TEST(lib_utility_rate_test, test_net_metering_multiple_tou_periods) int steps_per_hour = 1; std::vector monthly_load_forecast = { 150, 75 }; std::vector monthly_gen_forecast = { 0, 0 }; // Test unexpected generation as well - std::vector monthly_peak_forecast = { 100, 50 }; + std::vector monthly_avg_gross_load = { 100, 50 }; - UtilityRateForecast rate_forecast(&data, steps_per_hour, monthly_load_forecast, monthly_gen_forecast, monthly_peak_forecast, 2); + UtilityRateForecast rate_forecast(&data, steps_per_hour, monthly_load_forecast, monthly_gen_forecast, monthly_avg_gross_load, 2); // - is load std::vector forecast = { -100, -50, 50, 100 }; // Net zero load @@ -361,9 +386,9 @@ TEST(lib_utility_rate_test, test_net_metering_end_of_month_carryover) int steps_per_hour = 1; std::vector monthly_load_forecast = { 0, 150 }; std::vector monthly_gen_forecast = { 150, 0 }; - std::vector monthly_peak_forecast = { 0, 100 }; + std::vector monthly_avg_gross_load = { 0, 100 }; - UtilityRateForecast rate_forecast(&data, steps_per_hour, monthly_load_forecast, monthly_gen_forecast, monthly_peak_forecast, 2); + UtilityRateForecast rate_forecast(&data, steps_per_hour, monthly_load_forecast, monthly_gen_forecast, monthly_avg_gross_load, 2); // - is load std::vector forecast = { 100, 50, -50, -100 }; // Net zero load @@ -385,9 +410,9 @@ TEST(lib_utility_rate_test, test_net_metering_dollar_credits) int steps_per_hour = 1; std::vector monthly_load_forecast = { 0, 150 }; std::vector monthly_gen_forecast = { 150, 0 }; - std::vector monthly_peak_forecast = { 0, 100 }; + std::vector monthly_avg_gross_load = { 0, 100 }; - UtilityRateForecast rate_forecast(&data, steps_per_hour, monthly_load_forecast, monthly_gen_forecast, monthly_peak_forecast, 2); + UtilityRateForecast rate_forecast(&data, steps_per_hour, monthly_load_forecast, monthly_gen_forecast, monthly_avg_gross_load, 2); // - is load std::vector forecast = { 100, 50, -50, -100 }; // Net zero load, but credits expire with zero sell rate @@ -409,9 +434,9 @@ TEST(lib_utility_rate_test, test_net_metering_end_of_month_cashout) int steps_per_hour = 1; std::vector monthly_load_forecast = { 0, 150 }; std::vector monthly_gen_forecast = { 150, 0 }; - std::vector monthly_peak_forecast = { 0, 100 }; + std::vector monthly_avg_gross_load = { 0, 100 }; - UtilityRateForecast rate_forecast(&data, steps_per_hour, monthly_load_forecast, monthly_gen_forecast, monthly_peak_forecast, 2); + UtilityRateForecast rate_forecast(&data, steps_per_hour, monthly_load_forecast, monthly_gen_forecast, monthly_avg_gross_load, 2); // - is load std::vector forecast = { 100, 50, -50, -100 }; // Net zero load @@ -432,9 +457,9 @@ TEST(lib_utility_rate_test, test_net_metering_end_of_month_charges) int steps_per_hour = 1; std::vector monthly_load_forecast = { 150, 0 }; std::vector monthly_gen_forecast = { 0, 150 }; - std::vector monthly_peak_forecast = { 100, 0 }; + std::vector monthly_avg_gross_load = { 100, 0 }; - UtilityRateForecast rate_forecast(&data, steps_per_hour, monthly_load_forecast, monthly_gen_forecast, monthly_peak_forecast, 2); + UtilityRateForecast rate_forecast(&data, steps_per_hour, monthly_load_forecast, monthly_gen_forecast, monthly_avg_gross_load, 2); // - is load std::vector forecast = { -100, -50, 50, 100 }; // Net zero load, but charged at end of Jan @@ -455,9 +480,9 @@ TEST(lib_utility_rate_test, test_net_metering_end_of_month_charges_subhourly) int steps_per_hour = 2; std::vector monthly_load_forecast = { 150, 0 }; std::vector monthly_gen_forecast = { 0, 150 }; - std::vector monthly_peak_forecast = { 100, 0 }; + std::vector monthly_avg_gross_load = { 100, 0 }; - UtilityRateForecast rate_forecast(&data, steps_per_hour, monthly_load_forecast, monthly_gen_forecast, monthly_peak_forecast, 2); + UtilityRateForecast rate_forecast(&data, steps_per_hour, monthly_load_forecast, monthly_gen_forecast, monthly_avg_gross_load, 2); // - is load std::vector forecast = { -100, -100, -50, -50, 50, 50, 100, 100 }; // Net zero load, but charged at end of Jan @@ -478,9 +503,9 @@ TEST(lib_utility_rate_test, test_net_metering_charges_crossing_year) int steps_per_hour = 1; std::vector monthly_load_forecast = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 25 }; std::vector monthly_gen_forecast = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 75, 0 }; - std::vector monthly_peak_forecast = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 50 }; + std::vector monthly_avg_gross_load = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 50 }; - UtilityRateForecast rate_forecast(&data, steps_per_hour, monthly_load_forecast, monthly_gen_forecast, monthly_peak_forecast, 2); + UtilityRateForecast rate_forecast(&data, steps_per_hour, monthly_load_forecast, monthly_gen_forecast, monthly_avg_gross_load, 2); // - is load std::vector forecast = { -25, 25, 50, -25, -25 }; // Get charged for Jan at escalated rate (inflation) @@ -502,9 +527,9 @@ TEST(lib_utility_rate_test, test_net_metering_charges_crossing_year_other_cash_o int steps_per_hour = 1; std::vector monthly_load_forecast = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 25 }; std::vector monthly_gen_forecast = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 75, 0 }; - std::vector monthly_peak_forecast = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 50 }; + std::vector monthly_avg_gross_load = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 50 }; - UtilityRateForecast rate_forecast(&data, steps_per_hour, monthly_load_forecast, monthly_gen_forecast, monthly_peak_forecast, 2); + UtilityRateForecast rate_forecast(&data, steps_per_hour, monthly_load_forecast, monthly_gen_forecast, monthly_avg_gross_load, 2); // - is load std::vector forecast = { -25, 25, 50, -25, -25 }; @@ -525,9 +550,9 @@ TEST(lib_utility_rate_test, test_multiple_forecast_calls) int steps_per_hour = 1; std::vector monthly_load_forecast = { 100, 75 }; std::vector monthly_gen_forecast = { 175, 0 }; - std::vector monthly_peak_forecast = { 100, 50 }; + std::vector monthly_avg_gross_load = { 100, 50 }; - UtilityRateForecast rate_forecast(&data, steps_per_hour, monthly_load_forecast, monthly_gen_forecast, monthly_peak_forecast, 2); + UtilityRateForecast rate_forecast(&data, steps_per_hour, monthly_load_forecast, monthly_gen_forecast, monthly_avg_gross_load, 2); // - is load std::vector forecast = { 25, 25, 25, 25 }; @@ -555,9 +580,9 @@ TEST(lib_utility_rate_test, test_one_at_a_time_vs_full_vector) int steps_per_hour = 1; std::vector monthly_load_forecast = { 150, 75 }; std::vector monthly_gen_forecast = { 50, 175 }; - std::vector monthly_peak_forecast = { 100, 50 }; + std::vector monthly_avg_gross_load = { 100, 50 }; - UtilityRateForecast rate_forecast(&data, steps_per_hour, monthly_load_forecast, monthly_gen_forecast, monthly_peak_forecast, 2); + UtilityRateForecast rate_forecast(&data, steps_per_hour, monthly_load_forecast, monthly_gen_forecast, monthly_avg_gross_load, 2); // - is load std::vector forecast = { 50, -100, -50, -50, -25, 25, 50, 100 }; @@ -569,8 +594,8 @@ TEST(lib_utility_rate_test, test_one_at_a_time_vs_full_vector) int hour_of_year = 741; // 9 pm on Jan 31st double cost = rate_forecast.forecastCost(forecast, 0, hour_of_year, 0); - // Total cost for the months would be $1511.25, but this subtracts off the peaks predicted by average load ($3.12) - ASSERT_NEAR(1508.11, cost, 0.02); + // Total cost for the months would be $1511.25, but this subtracts off the peaks predicted by average gross load load ($3.12) + ASSERT_NEAR(11.25, cost, 0.02); cost = 0; for (int i = 0; i < forecast.size(); i++) @@ -579,7 +604,7 @@ TEST(lib_utility_rate_test, test_one_at_a_time_vs_full_vector) cost += forecast_copy.forecastCost(single_forecast, 0, hour_of_year + i, 0); } - ASSERT_NEAR(1508.11, cost, 0.02); + ASSERT_NEAR(11.25, cost, 0.02); } TEST(lib_utility_rate_test, test_one_at_a_time_vs_full_vector_nm_credits) @@ -590,9 +615,9 @@ TEST(lib_utility_rate_test, test_one_at_a_time_vs_full_vector_nm_credits) int steps_per_hour = 1; std::vector monthly_load_forecast = { 150, 75 }; std::vector monthly_gen_forecast = { 50, 175 }; - std::vector monthly_peak_forecast = { 100, 50 }; + std::vector monthly_avg_gross_load = { 100, 50 }; - UtilityRateForecast rate_forecast(&data, steps_per_hour, monthly_load_forecast, monthly_gen_forecast, monthly_peak_forecast, 2); + UtilityRateForecast rate_forecast(&data, steps_per_hour, monthly_load_forecast, monthly_gen_forecast, monthly_avg_gross_load, 2); // - is load std::vector forecast = { 50, -100, -50, -50, -25, 25, 50, 100 }; @@ -624,9 +649,9 @@ TEST(lib_utility_rate_test, test_one_at_a_time_vs_full_vector_nm_credits_subhour int steps_per_hour = 2; std::vector monthly_load_forecast = { 150, 75 }; std::vector monthly_gen_forecast = { 50, 175 }; - std::vector monthly_peak_forecast = { 100, 50 }; + std::vector monthly_avg_gross_load = { 100, 50 }; - UtilityRateForecast rate_forecast(&data, steps_per_hour, monthly_load_forecast, monthly_gen_forecast, monthly_peak_forecast, 2); + UtilityRateForecast rate_forecast(&data, steps_per_hour, monthly_load_forecast, monthly_gen_forecast, monthly_avg_gross_load, 2); // - is load std::vector forecast = { 50, 50, -100, -100, -50, -50, -50, -50, -25, -25, 25, 25, 50, 50, 100, 100 }; @@ -663,9 +688,9 @@ TEST(lib_utility_rate_test, test_end_of_analyis_period) int steps_per_hour = 1; std::vector monthly_load_forecast = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25 }; std::vector monthly_gen_forecast = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 75 }; - std::vector monthly_peak_forecast = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50 }; + std::vector monthly_avg_gross_load = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50 }; - UtilityRateForecast rate_forecast(&data, steps_per_hour, monthly_load_forecast, monthly_gen_forecast, monthly_peak_forecast, 1); + UtilityRateForecast rate_forecast(&data, steps_per_hour, monthly_load_forecast, monthly_gen_forecast, monthly_avg_gross_load, 1); // - is load std::vector forecast = { -25, -25, 50 }; @@ -686,9 +711,9 @@ TEST(lib_utility_rate_test, test_one_at_a_time_vs_full_vector_buy_and_sell_rates int steps_per_hour = 1; std::vector monthly_load_forecast = { 150, 75 }; std::vector monthly_gen_forecast = { 50, 175 }; - std::vector monthly_peak_forecast = { 100, 50 }; + std::vector monthly_avg_gross_load = { 100, 50 }; - UtilityRateForecast rate_forecast(&data, steps_per_hour, monthly_load_forecast, monthly_gen_forecast, monthly_peak_forecast, 2); + UtilityRateForecast rate_forecast(&data, steps_per_hour, monthly_load_forecast, monthly_gen_forecast, monthly_avg_gross_load, 2); // - is load std::vector forecast = { 50, -100, -50, -50, -25, 25, 50, 100 }; @@ -721,9 +746,9 @@ TEST(lib_utility_rate_test, test_ts_buy_only) int steps_per_hour = 1; std::vector monthly_load_forecast = { 150, 75 }; std::vector monthly_gen_forecast = { 50, 175 }; - std::vector monthly_peak_forecast = { 100, 50 }; + std::vector monthly_avg_gross_load = { 100, 50 }; - UtilityRateForecast rate_forecast(&data, steps_per_hour, monthly_load_forecast, monthly_gen_forecast, monthly_peak_forecast, 2); + UtilityRateForecast rate_forecast(&data, steps_per_hour, monthly_load_forecast, monthly_gen_forecast, monthly_avg_gross_load, 2); // - is load std::vector forecast = { 50, -100, -50, -50, -25, 25, 50, 100 }; @@ -747,9 +772,9 @@ TEST(lib_utility_rate_test, test_ts_sell_only) int steps_per_hour = 1; std::vector monthly_load_forecast = { 150, 75 }; std::vector monthly_gen_forecast = { 50, 175 }; - std::vector monthly_peak_forecast = { 100, 50 }; + std::vector monthly_avg_gross_load = { 100, 50 }; - UtilityRateForecast rate_forecast(&data, steps_per_hour, monthly_load_forecast, monthly_gen_forecast, monthly_peak_forecast, 2); + UtilityRateForecast rate_forecast(&data, steps_per_hour, monthly_load_forecast, monthly_gen_forecast, monthly_avg_gross_load, 2); // - is load std::vector forecast = { 50, -100, -50, -50, -25, 25, 50, 100 }; diff --git a/test/shared_test/vs_google_test_explorer_namespace.h b/test/shared_test/vs_google_test_explorer_namespace.h new file mode 100644 index 00000000000..6eb408bc863 --- /dev/null +++ b/test/shared_test/vs_google_test_explorer_namespace.h @@ -0,0 +1,48 @@ +// vs_google_test_explorer_namespace.h +// +// This is an example of a file/macro that could be used to trick the Google Test Adapter into +// sorting tests into namespaces in C++ +// + +#ifndef NAMESPACE_GTEST_INCLUDE_GTEST_GTEST_H_ +#define NAMESPACE_GTEST_INCLUDE_GTEST_GTEST_H_ + +#include + +// A copy of GTEST_TEST_CLASS_NAME_, but with handling for namespace name. + +#define NAMESPACE_GTEST_TEST_CLASS_NAME_(namespace_name, test_case_name, test_name) \ + namespace_name##_##test_case_name##_##test_name##_Test + +// A copy of GTEST_TEST_, but with handling for namespace name. + +#define NAMESPACE_GTEST_TEST_(namespace_name, test_case_name, test_name, parent_class, parent_id)\ +class NAMESPACE_GTEST_TEST_CLASS_NAME_(namespace_name, test_case_name, test_name) : public parent_class {\ + public:\ + NAMESPACE_GTEST_TEST_CLASS_NAME_(namespace_name, test_case_name, test_name)() {}\ + private:\ + virtual void TestBody();\ + static ::testing::TestInfo* const test_info_ GTEST_ATTRIBUTE_UNUSED_;\ + GTEST_DISALLOW_COPY_AND_ASSIGN_(\ + NAMESPACE_GTEST_TEST_CLASS_NAME_(namespace_name, test_case_name, test_name));\ +};\ +\ +::testing::TestInfo* const NAMESPACE_GTEST_TEST_CLASS_NAME_(namespace_name, test_case_name, test_name)\ + ::test_info_ =\ + ::testing::internal::MakeAndRegisterTestInfo(\ + #namespace_name "." #test_case_name, #test_name, NULL, NULL, /* <-- Defines the test as "Namespace.Classname" */ \ + ::testing::internal::CodeLocation(__FILE__, __LINE__), \ + (parent_id), \ + parent_class::SetUpTestCase, \ + parent_class::TearDownTestCase, \ + new ::testing::internal::TestFactoryImpl<\ + NAMESPACE_GTEST_TEST_CLASS_NAME_(namespace_name, test_case_name, test_name)>);\ +void NAMESPACE_GTEST_TEST_CLASS_NAME_(namespace_name, test_case_name, test_name)::TestBody() + +// Simple macro + +#define NAMESPACE_TEST(namespace_name, test_case_name, test_name) \ + NAMESPACE_GTEST_TEST_(namespace_name, test_case_name, test_name,\ + ::testing::Test, ::testing::internal::GetTestTypeId()) + +#endif // NAMESPACE_GTEST_INCLUDE_GTEST_GTEST_H_ diff --git a/test/ssc_test/cmod_battery_pvsamv1_test.cpp b/test/ssc_test/cmod_battery_pvsamv1_test.cpp index fd88098f684..ee4239a1200 100644 --- a/test/ssc_test/cmod_battery_pvsamv1_test.cpp +++ b/test/ssc_test/cmod_battery_pvsamv1_test.cpp @@ -398,12 +398,12 @@ TEST_F(CMPvsamv1BatteryIntegration_cmod_pvsamv1, PPA_ManualDispatchBatteryModelI grid_and_rate_defaults(data); singleowner_defaults(data); - ssc_number_t expectedEnergy = 37176158; + ssc_number_t expectedEnergy = 37175792; ssc_number_t expectedBatteryChargeEnergy = 1297985; - ssc_number_t expectedBatteryDischargeEnergy = 1166100; + ssc_number_t expectedBatteryDischargeEnergy = 1165634; ssc_number_t peakKwCharge = -1052.0; - ssc_number_t peakKwDischarge = 857.2; + ssc_number_t peakKwDischarge = 846.8; ssc_number_t peakCycles = 1; ssc_number_t avgCycles = 1; @@ -811,5 +811,6 @@ TEST_F(CMPvsamv1BatteryIntegration_cmod_pvsamv1, ResidentialDCBatteryModelPriceS auto batt_cyc_avg = data_vtab->as_vector_ssc_number_t("batt_DOD_cycle_average"); EXPECT_NEAR(batt_q_rel.back(), 97.836, 1e-2); EXPECT_NEAR(batt_cyc_avg.back(), 22.62, 0.5); + //EXPECT_NEAR(batt_cyc_avg.back(), 24.72, 0.5); // from patch } } diff --git a/test/ssc_test/cmod_singleowner_test.cpp b/test/ssc_test/cmod_singleowner_test.cpp index 66f6c790a41..7d2f88b5740 100644 --- a/test/ssc_test/cmod_singleowner_test.cpp +++ b/test/ssc_test/cmod_singleowner_test.cpp @@ -1,6 +1,5 @@ #include "cmod_singleowner_test.h" -#include "cmod_financial_eqns.h" #include "gtest/gtest.h" @@ -14,97 +13,3 @@ TEST_F(CMSingleOwner, ResidentialDefault_cmod_swh) { EXPECT_NEAR(npv, -647727751.2, 0.1); } - -TEST(Mspt_cmod_financial_eqns, Case1) { - double error_tolerance = 0.01; - var_table* vd = new var_table; - vd->assign("total_installed_cost", 673465536.); - - vd->assign("const_per_percent1", 100.); - vd->assign("const_per_upfront_rate1", 1.); - vd->assign("const_per_months1", 24.); - vd->assign("const_per_interest_rate1", 4.); - - vd->assign("const_per_percent2", 0.); - vd->assign("const_per_upfront_rate2", 0.); - vd->assign("const_per_months2", 0.); - vd->assign("const_per_interest_rate2", 0.); - - vd->assign("const_per_percent3", 0.); - vd->assign("const_per_upfront_rate3", 0.); - vd->assign("const_per_months3", 0.); - vd->assign("const_per_interest_rate3", 0.); - - vd->assign("const_per_percent4", 0.); - vd->assign("const_per_upfront_rate4", 0.); - vd->assign("const_per_months4", 0.); - vd->assign("const_per_interest_rate4", 0.); - - vd->assign("const_per_percent5", 0.); - vd->assign("const_per_upfront_rate5", 0.); - vd->assign("const_per_months5", 0.); - vd->assign("const_per_interest_rate5", 0.); - - Financial_Construction_Financing_Equations(vd); - - double const_per_principal1 = vd->lookup("const_per_principal1")->num; - double const_per_interest1 = vd->lookup("const_per_interest1")->num; - double const_per_total1 = vd->lookup("const_per_total1")->num; - - double const_per_principal2 = vd->lookup("const_per_principal2")->num; - double const_per_interest2 = vd->lookup("const_per_interest2")->num; - double const_per_total2 = vd->lookup("const_per_total2")->num; - - double const_per_principal3 = vd->lookup("const_per_principal3")->num; - double const_per_interest3 = vd->lookup("const_per_interest3")->num; - double const_per_total3 = vd->lookup("const_per_total3")->num; - - double const_per_principal4 = vd->lookup("const_per_principal4")->num; - double const_per_interest4 = vd->lookup("const_per_interest4")->num; - double const_per_total4 = vd->lookup("const_per_total4")->num; - - double const_per_principal5 = vd->lookup("const_per_principal5")->num; - double const_per_interest5 = vd->lookup("const_per_interest5")->num; - double const_per_total5 = vd->lookup("const_per_total5")->num; - - double const_per_principal_total = vd->lookup("const_per_principal_total")->num; - double const_per_percent_total = vd->lookup("const_per_percent_total")->num; - double construction_financing_cost = vd->lookup("construction_financing_cost")->num; - double const_per_interest_total = vd->lookup("const_per_interest_total")->num; - - ASSERT_NEAR(const_per_principal1, 673465472., 673465472. * error_tolerance); - ASSERT_NEAR(const_per_interest1, 26938618., 26938618. * error_tolerance); - ASSERT_NEAR(const_per_total1, 33673272., 33673272. * error_tolerance); - - ASSERT_NEAR(const_per_principal2, 0., 0. * error_tolerance); - ASSERT_NEAR(const_per_interest2, 0., 0. * error_tolerance); - ASSERT_NEAR(const_per_total2, 0., 0. * error_tolerance); - - ASSERT_NEAR(const_per_principal3, 0., 0. * error_tolerance); - ASSERT_NEAR(const_per_interest3, 0., 0. * error_tolerance); - ASSERT_NEAR(const_per_total3, 0., 0. * error_tolerance); - - ASSERT_NEAR(const_per_principal4, 0., 0. * error_tolerance); - ASSERT_NEAR(const_per_interest4, 0., 0. * error_tolerance); - ASSERT_NEAR(const_per_total4, 0., 0. * error_tolerance); - - ASSERT_NEAR(const_per_principal5, 0., 0. * error_tolerance); - ASSERT_NEAR(const_per_interest5, 0., 0. * error_tolerance); - ASSERT_NEAR(const_per_total5, 0., 0. * error_tolerance); - - ASSERT_NEAR(const_per_percent_total, 100., 100. * error_tolerance); - ASSERT_NEAR(const_per_principal_total, 673465472., 673465472. * error_tolerance); - ASSERT_NEAR(const_per_interest_total, 26938618., 26938618. * error_tolerance); - ASSERT_NEAR(construction_financing_cost, 33673272., 33673272. * error_tolerance); -} - -TEST(Mspt_cmod_financial_eqns, Case2) { - double error_tolerance = 0.01; - var_table* vd = new var_table; - vd->assign("system_capacity", 103500.); - - Financial_Capacity_Payments_Equations(vd); - - double cp_system_nameplate = vd->lookup("cp_system_nameplate")->num; - ASSERT_NEAR(cp_system_nameplate, 103.5, 103.5 * error_tolerance); -} diff --git a/test/ssc_test/cmod_tcsdirect_steam_test.cpp b/test/ssc_test/cmod_tcsdirect_steam_test.cpp index 343e36beeda..d5e9b97f326 100644 --- a/test/ssc_test/cmod_tcsdirect_steam_test.cpp +++ b/test/ssc_test/cmod_tcsdirect_steam_test.cpp @@ -1,419 +1,221 @@ #include - -#include "cmod_tcsdirect_steam_test.h" -#include "../tcs_test/tcsdirect_steam_cases.h" -#include "../input_cases/weather_inputs.h" - -/// Test tcsdirect_steam with all defaults and the single owner financial model -TEST_F(CMTcsDirectSteam, DirectSteam_Default_SingleOwner_cmod_tcsdirect_steam) { - - ssc_data_t data = ssc_data_create(); - int test_errors = tcsdirect_steam_daggett_default(data); - - EXPECT_FALSE(test_errors); - if (!test_errors) - { - ssc_number_t annual_energy; - ssc_data_get_number(data, "annual_energy", &annual_energy); - EXPECT_NEAR(annual_energy, 263818768.982372, 263818768.982372 * m_error_tolerance_hi) << "Annual Energy"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t annual_fuel_usage; - ssc_data_get_number(data, "annual_fuel_usage", &annual_fuel_usage); - EXPECT_NEAR(annual_fuel_usage, 0, 0 * m_error_tolerance_hi) << "Annual fuel usage"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t capacity_factor; - ssc_data_get_number(data, "capacity_factor", &capacity_factor); - EXPECT_NEAR(capacity_factor, 30.078699, 30.078699 * m_error_tolerance_hi) << "Capacity Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t annual_W_cycle_gross; - ssc_data_get_number(data, "annual_W_cycle_gross", &annual_W_cycle_gross); - EXPECT_NEAR(annual_W_cycle_gross, 296640437.816735, 296640437.816735 * m_error_tolerance_hi) << "Annual W_cycle Gross"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t kwh_per_kw; - ssc_data_get_number(data, "kwh_per_kw", &kwh_per_kw); - EXPECT_NEAR(kwh_per_kw, 2634.894072, 2634.894072 * m_error_tolerance_hi) << "kwh per kw"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t conversion_factor; - ssc_data_get_number(data, "conversion_factor", &conversion_factor); - EXPECT_NEAR(conversion_factor, 92.641187, 92.641187 * m_error_tolerance_hi) << "Conversion Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t system_heat_rate; - ssc_data_get_number(data, "system_heat_rate", &system_heat_rate); - EXPECT_NEAR(system_heat_rate, 3.413000, 3.413000 * m_error_tolerance_hi) << "System heat rate"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t annual_total_water_use; - ssc_data_get_number(data, "annual_total_water_use", &annual_total_water_use); - EXPECT_NEAR(annual_total_water_use, 55716.172107, 55716.172107 * m_error_tolerance_hi) << "Annual Total Water Use"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - } +#include "tcsdirect_steam_defaults.h" +#include "csp_common_test.h" +#include "vs_google_test_explorer_namespace.h" + + +namespace csp_tower {} +using namespace csp_tower; + +//========Tests=================================================================================== +NAMESPACE_TEST(csp_tower, SteamTowerCmod, Default_NoFinancial) +{ + ssc_data_t defaults = tcsdirect_steam_defaults(); + CmodUnderTest steam_tower = CmodUnderTest("tcsdirect_steam", defaults); + int errors = steam_tower.RunModule(); + EXPECT_FALSE(errors); + if (!errors) { + EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_energy"), 263809742, kErrorToleranceLo); + EXPECT_NEAR(steam_tower.GetOutput("annual_fuel_usage"), 0., kErrorToleranceLo); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("capacity_factor"), 30.08, kErrorToleranceLo); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_W_cycle_gross"), 296630582, kErrorToleranceLo); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("kwh_per_kw"), 2635, kErrorToleranceLo); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("conversion_factor"), 92.64, kErrorToleranceLo); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("system_heat_rate"), 3.413, kErrorToleranceLo); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_total_water_use"), 55716, kErrorToleranceLo); + } } -/// Test tcsdirect_steam with alternative condenser type: Evaporative -/// Rest default configurations with respect to the single owner financial model -TEST_F(CMTcsDirectSteam, DirectSteam_Evap_Condenser_SingleOwner_cmod_tcsdirect_steam) { - - ssc_data_t data = ssc_data_create(); - int test_errors = tcsdirect_steam_daggett_evap_condenser(data); - - EXPECT_FALSE(test_errors); - if (!test_errors) - { - ssc_number_t annual_energy; - ssc_data_get_number(data, "annual_energy", &annual_energy); - EXPECT_NEAR(annual_energy, 280986033.690457, 280986033.690457 * m_error_tolerance_hi) << "Annual Energy"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t annual_fuel_usage; - ssc_data_get_number(data, "annual_fuel_usage", &annual_fuel_usage); - EXPECT_NEAR(annual_fuel_usage, 0, 0 * m_error_tolerance_hi) << "Annual fuel usage"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t capacity_factor; - ssc_data_get_number(data, "capacity_factor", &capacity_factor); - EXPECT_NEAR(capacity_factor, 32.035986, 32.035986 * m_error_tolerance_hi) << "Capacity Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t annual_W_cycle_gross; - ssc_data_get_number(data, "annual_W_cycle_gross", &annual_W_cycle_gross); - EXPECT_NEAR(annual_W_cycle_gross, 307636143.733944, 307636143.733944 * m_error_tolerance_hi) << "Annual W_cycle Gross"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t kwh_per_kw; - ssc_data_get_number(data, "kwh_per_kw", &kwh_per_kw); - EXPECT_NEAR(kwh_per_kw, 2806.352396, 2806.352396 * m_error_tolerance_hi) << "kwh per kw"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t conversion_factor; - ssc_data_get_number(data, "conversion_factor", &conversion_factor); - EXPECT_NEAR(conversion_factor, 95.142849, 95.142849 * m_error_tolerance_hi) << "Conversion Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t system_heat_rate; - ssc_data_get_number(data, "system_heat_rate", &system_heat_rate); - EXPECT_NEAR(system_heat_rate, 3.413000, 3.413000 * m_error_tolerance_hi) << "System heat rate"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t annual_total_water_use; - ssc_data_get_number(data, "annual_total_water_use", &annual_total_water_use); - EXPECT_NEAR(annual_total_water_use, 893438.592909, 893438.592909 * m_error_tolerance_hi) << "Annual Total Water Use"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - - } +// Alternative condenser type : Evaporative +NAMESPACE_TEST(csp_tower, SteamTowerCmod, EvaporativeCondenser_NoFinancial) +{ + ssc_data_t defaults = tcsdirect_steam_defaults(); + CmodUnderTest steam_tower = CmodUnderTest("tcsdirect_steam", defaults); + steam_tower.SetInput("ct", 1); + steam_tower.SetInput("eta_ref", 0.404); + steam_tower.SetInput("startup_frac", 0.5); + steam_tower.SetInput("P_cond_min", 2); + + int errors = steam_tower.RunModule(); + EXPECT_FALSE(errors); + if (!errors) { + EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_energy"), 280975356, kErrorToleranceLo); + EXPECT_NEAR(steam_tower.GetOutput("annual_fuel_usage"), 0., kErrorToleranceLo); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("capacity_factor"), 32.03, kErrorToleranceLo); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_W_cycle_gross"), 307624737, kErrorToleranceLo); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("kwh_per_kw"), 2806, kErrorToleranceLo); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("conversion_factor"), 95.14, kErrorToleranceLo); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("system_heat_rate"), 3.413, kErrorToleranceLo); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_total_water_use"), 893431, kErrorToleranceLo); + } } -/// Test tcsdirect_steam with alternative condenser type: Hybrid -/// Rest default configurations with respect to the single owner financial model -TEST_F(CMTcsDirectSteam, DirectSteam_Hybrid_Condenser_SingleOwner_cmod_tcsdirect_steam) { - - ssc_data_t data = ssc_data_create(); - int test_errors = tcsdirect_steam_daggett_hybrid_condenser(data); - - EXPECT_FALSE(test_errors); - if (!test_errors) - { - ssc_number_t annual_energy; - ssc_data_get_number(data, "annual_energy", &annual_energy); - EXPECT_NEAR(annual_energy, 268125210.231106, 268125210.231106 * m_error_tolerance_hi) << "Annual Energy"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t annual_fuel_usage; - ssc_data_get_number(data, "annual_fuel_usage", &annual_fuel_usage); - EXPECT_NEAR(annual_fuel_usage, 0, 0 * m_error_tolerance_hi) << "Annual fuel usage"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t capacity_factor; - ssc_data_get_number(data, "capacity_factor", &capacity_factor); - EXPECT_NEAR(capacity_factor, 30.569689, 30.569689 * m_error_tolerance_hi) << "Capacity Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t annual_W_cycle_gross; - ssc_data_get_number(data, "annual_W_cycle_gross", &annual_W_cycle_gross); - EXPECT_NEAR(annual_W_cycle_gross, 304076894.573157, 304076894.573157 * m_error_tolerance_hi) << "Annual W_cycle Gross"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t kwh_per_kw; - ssc_data_get_number(data, "kwh_per_kw", &kwh_per_kw); - EXPECT_NEAR(kwh_per_kw, 2677.904721, 2677.904721 * m_error_tolerance_hi) << "kwh per kw"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t conversion_factor; - ssc_data_get_number(data, "conversion_factor", &conversion_factor); - EXPECT_NEAR(conversion_factor, 91.850813, 91.850813 * m_error_tolerance_hi) << "Conversion Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t system_heat_rate; - ssc_data_get_number(data, "system_heat_rate", &system_heat_rate); - EXPECT_NEAR(system_heat_rate, 3.413000, 3.413000 * m_error_tolerance_hi) << "System heat rate"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t annual_total_water_use; - ssc_data_get_number(data, "annual_total_water_use", &annual_total_water_use); - EXPECT_NEAR(annual_total_water_use, 55716.584942, 55716.584942 * m_error_tolerance_hi) << "Annual Total Water Use"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - - } +// Alternative condenser type : Hybrid +NAMESPACE_TEST(csp_tower, SteamTowerCmod, HybridCondenser_NoFinancial) +{ + ssc_data_t defaults = tcsdirect_steam_defaults(); + CmodUnderTest steam_tower = CmodUnderTest("tcsdirect_steam", defaults); + steam_tower.SetInput("ct", 3); + steam_tower.SetInput("eta_ref", 0.404); + steam_tower.SetInput("startup_frac", 0.5); + steam_tower.SetInput("P_cond_min", 2); + + int errors = steam_tower.RunModule(); + EXPECT_FALSE(errors); + if (!errors) { + EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_energy"), 268116066, kErrorToleranceLo); + EXPECT_NEAR(steam_tower.GetOutput("annual_fuel_usage"), 0., kErrorToleranceLo); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("capacity_factor"), 30.57, kErrorToleranceLo); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_W_cycle_gross"), 304066728, kErrorToleranceLo); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("kwh_per_kw"), 2678, kErrorToleranceLo); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("conversion_factor"), 91.85, kErrorToleranceLo); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("system_heat_rate"), 3.413, kErrorToleranceLo); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_total_water_use"), 55716, kErrorToleranceLo); + } } -/// Test tcsdirect_steam with alternative fossil dispatch mode: Supplemental mode -/// Rest default configurations with respect to the single owner financial model -//TEST_F(CMTcsDirectSteam, DirectSteam_Fossil_Supplemental_SingleOwner_cmod_tcsdirect_steam) { -// -// ssc_data_t data = ssc_data_create(); -// int test_errors = tcsdirect_steam_daggett_fossil_dispatch_supplemental(data); -// -// EXPECT_FALSE(test_errors); -// if (!test_errors) -// { -// ssc_number_t annual_energy; -// ssc_data_get_number(data, "annual_energy", &annual_energy); -// EXPECT_NEAR(annual_energy, 268125210.231106, 268125210.231106 * m_error_tolerance_hi) << "Annual Energy"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_fuel_usage; -// ssc_data_get_number(data, "annual_fuel_usage", &annual_fuel_usage); -// EXPECT_NEAR(annual_fuel_usage, 0, 0 * m_error_tolerance_hi) << "Annual fuel usage"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t capacity_factor; -// ssc_data_get_number(data, "capacity_factor", &capacity_factor); -// EXPECT_NEAR(capacity_factor, 30.569689, 30.569689 * m_error_tolerance_hi) << "Capacity Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_W_cycle_gross; -// ssc_data_get_number(data, "annual_W_cycle_gross", &annual_W_cycle_gross); -// EXPECT_NEAR(annual_W_cycle_gross, 304076894.573157, 304076894.573157 * m_error_tolerance_hi) << "Annual W_cycle Gross"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t kwh_per_kw; -// ssc_data_get_number(data, "kwh_per_kw", &kwh_per_kw); -// EXPECT_NEAR(kwh_per_kw, 2677.904721, 2677.904721 * m_error_tolerance_hi) << "kwh per kw"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t conversion_factor; -// ssc_data_get_number(data, "conversion_factor", &conversion_factor); -// EXPECT_NEAR(conversion_factor, 91.850813, 91.850813 * m_error_tolerance_hi) << "Conversion Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t system_heat_rate; -// ssc_data_get_number(data, "system_heat_rate", &system_heat_rate); -// EXPECT_NEAR(system_heat_rate, 3.413000, 3.413000 * m_error_tolerance_hi) << "System heat rate"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_total_water_use; -// ssc_data_get_number(data, "annual_total_water_use", &annual_total_water_use); -// EXPECT_NEAR(annual_total_water_use, 55716.584942, 55716.584942 * m_error_tolerance_hi) << "Annual Total Water Use"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// -// } +//// Fossil dispatch +//NAMESPACE_TEST(csp_tower, SteamTowerCmod, FossilDispatch_NoFinancial) +//{ +// ssc_data_t defaults = tcsdirect_steam_defaults(); +// CmodUnderTest steam_tower = CmodUnderTest("tcsdirect_steam", defaults); +// steam_tower.SetInput("fossil_mode", 2); +// steam_tower.SetInput("eta_ref", 0.404); +// steam_tower.SetInput("startup_frac", 0.5); +// steam_tower.SetInput("P_cond_min", 2); +// +// int errors = steam_tower.RunModule(); +// EXPECT_FALSE(errors); +// if (!errors) { +// EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_energy"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_fuel_usage"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(steam_tower.GetOutput("capacity_factor"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_W_cycle_gross"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(steam_tower.GetOutput("kwh_per_kw"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(steam_tower.GetOutput("conversion_factor"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(steam_tower.GetOutput("system_heat_rate"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_total_water_use"), 571408807, kErrorToleranceLo); +// } //} - -/// Test tcsdirect_steam with alternative Direct Steam Receiver material: T91 Steel -/// Rest default configurations with respect to the single owner financial model -//TEST_F(CMTcsDirectSteam, DirectSteam_Direct_Steam_Receiver_SingleOwner_cmod_tcsdirect_steam) { -// -// ssc_data_t data = ssc_data_create(); -// int test_errors = tcsdirect_steam_daggett_direct_steam_receiver(data); -// -// EXPECT_FALSE(test_errors); -// if (!test_errors) -// { -// ssc_number_t annual_energy; -// ssc_data_get_number(data, "annual_energy", &annual_energy); -// EXPECT_NEAR(annual_energy, 2.68312e8, 2.68312e8 * m_error_tolerance_hi) << "Annual Energy"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_fuel_usage; -// ssc_data_get_number(data, "annual_fuel_usage", &annual_fuel_usage); -// EXPECT_NEAR(annual_fuel_usage, 0, 0 * m_error_tolerance_hi) << "Annual fuel usage"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t capacity_factor; -// ssc_data_get_number(data, "capacity_factor", &capacity_factor); -// EXPECT_NEAR(capacity_factor, 30.591, 30.591 * m_error_tolerance_hi) << "Capacity Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_W_cycle_gross; -// ssc_data_get_number(data, "annual_W_cycle_gross", &annual_W_cycle_gross); -// EXPECT_NEAR(annual_W_cycle_gross, 3.01568e8, 3.01568e8 * m_error_tolerance_hi) << "Annual W_cycle Gross"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t kwh_per_kw; -// ssc_data_get_number(data, "kwh_per_kw", &kwh_per_kw); -// EXPECT_NEAR(kwh_per_kw, 2679.77, 2679.77 * m_error_tolerance_hi) << "kwh per kw"; // choose either m_error_tolerance_lo or m_error_tolerance_hi // -// ssc_number_t conversion_factor; -// ssc_data_get_number(data, "conversion_factor", &conversion_factor); -// EXPECT_NEAR(conversion_factor, 92.6794, 92.6794 * m_error_tolerance_hi) << "Conversion Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t system_heat_rate; -// ssc_data_get_number(data, "system_heat_rate", &system_heat_rate); -// EXPECT_NEAR(system_heat_rate, 3.413, 3.413 * m_error_tolerance_hi) << "System heat rate"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_total_water_use; -// ssc_data_get_number(data, "annual_total_water_use", &annual_total_water_use); -// EXPECT_NEAR(annual_total_water_use, 55574.5, 55574.5 * m_error_tolerance_hi) << "Annual Total Water Use"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// -// } +//// Receiver material : T91 Steel +//NAMESPACE_TEST(csp_tower, SteamTowerCmod, ReceiverT91Steel_NoFinancial) +//{ +// ssc_data_t defaults = tcsdirect_steam_defaults(); +// CmodUnderTest steam_tower = CmodUnderTest("tcsdirect_steam", defaults); +// steam_tower.SetInput("mat_boiler", 28); +// steam_tower.SetInput("mat_sh", 28); +// steam_tower.SetInput("mat_rh", 28); +// steam_tower.SetInput("eta_ref", 0.404); +// steam_tower.SetInput("startup_frac", 0.5); +// steam_tower.SetInput("P_cond_min", 2); +// +// int errors = steam_tower.RunModule(); +// EXPECT_FALSE(errors); +// if (!errors) { +// EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_energy"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_fuel_usage"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(steam_tower.GetOutput("capacity_factor"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_W_cycle_gross"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(steam_tower.GetOutput("kwh_per_kw"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(steam_tower.GetOutput("conversion_factor"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(steam_tower.GetOutput("system_heat_rate"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_total_water_use"), 571408807, kErrorToleranceLo); +// } //} - -/// Test tcsdirect_steam with alternative flow pattern: 1 -/// Rest default configurations with respect to the single owner financial model -//TEST_F(CMTcsDirectSteam, DirectSteam_Flow_Pattern_SingleOwner_cmod_tcsdirect_steam) { -// -// ssc_data_t data = ssc_data_create(); -// int test_errors = tcsdirect_steam_daggett_flow_pattern(data); -// -// EXPECT_FALSE(test_errors); -// if (!test_errors) -// { -// ssc_number_t annual_energy; -// ssc_data_get_number(data, "annual_energy", &annual_energy); -// EXPECT_NEAR(annual_energy, 2.67815e8, 2.67815e8 * m_error_tolerance_hi) << "Annual Energy"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_fuel_usage; -// ssc_data_get_number(data, "annual_fuel_usage", &annual_fuel_usage); -// EXPECT_NEAR(annual_fuel_usage, 0, 0 * m_error_tolerance_hi) << "Annual fuel usage"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t capacity_factor; -// ssc_data_get_number(data, "capacity_factor", &capacity_factor); -// EXPECT_NEAR(capacity_factor, 30.5343, 30.5343 * m_error_tolerance_hi) << "Capacity Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_W_cycle_gross; -// ssc_data_get_number(data, "annual_W_cycle_gross", &annual_W_cycle_gross); -// EXPECT_NEAR(annual_W_cycle_gross, 3.01038e8, 3.01038e8 * m_error_tolerance_hi) << "Annual W_cycle Gross"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t kwh_per_kw; -// ssc_data_get_number(data, "kwh_per_kw", &kwh_per_kw); -// EXPECT_NEAR(kwh_per_kw, 2674.81, 2674.81 * m_error_tolerance_hi) << "kwh per kw"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t conversion_factor; -// ssc_data_get_number(data, "conversion_factor", &conversion_factor); -// EXPECT_NEAR(conversion_factor, 92.6707, 92.6707 * m_error_tolerance_hi) << "Conversion Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t system_heat_rate; -// ssc_data_get_number(data, "system_heat_rate", &system_heat_rate); -// EXPECT_NEAR(system_heat_rate, 3.413, 3.413 * m_error_tolerance_hi) << "System heat rate"; // choose either m_error_tolerance_lo or m_error_tolerance_hi // -// ssc_number_t annual_total_water_use; -// ssc_data_get_number(data, "annual_total_water_use", &annual_total_water_use); -// EXPECT_NEAR(annual_total_water_use, 55540.2, 55540.2 * m_error_tolerance_hi) << "Annual Total Water Use"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// -// } +//// Alternative receiver flow pattern +//NAMESPACE_TEST(csp_tower, SteamTowerCmod, FlowPattern1_NoFinancial) +//{ +// ssc_data_t defaults = tcsdirect_steam_defaults(); +// CmodUnderTest steam_tower = CmodUnderTest("tcsdirect_steam", defaults); +// steam_tower.SetInput("flowtype", 1); +// steam_tower.SetInput("eta_ref", 0.404); +// steam_tower.SetInput("startup_frac", 0.5); +// steam_tower.SetInput("P_cond_min", 2); +// +// int errors = steam_tower.RunModule(); +// EXPECT_FALSE(errors); +// if (!errors) { +// EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_energy"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_fuel_usage"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(steam_tower.GetOutput("capacity_factor"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_W_cycle_gross"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(steam_tower.GetOutput("kwh_per_kw"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(steam_tower.GetOutput("conversion_factor"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(steam_tower.GetOutput("system_heat_rate"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_total_water_use"), 571408807, kErrorToleranceLo); +// } //} - -/// Test tcsdirect_steam with alternative Heliostat focusing method: Flat -/// Rest default configurations with respect to the single owner financial model -//TEST_F(CMTcsDirectSteam, DirectSteam_Heliostat_Focusing_SingleOwner_cmod_tcsdirect_steam) { -// -// ssc_data_t data = ssc_data_create(); -// int test_errors = tcsdirect_steam_daggett_focusing_method(data); -// -// EXPECT_FALSE(test_errors); -// if (!test_errors) -// { -// ssc_number_t annual_energy; -// ssc_data_get_number(data, "annual_energy", &annual_energy); -// EXPECT_NEAR(annual_energy, 2.68027e8, 2.68027e8 * m_error_tolerance_hi) << "Annual Energy"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_fuel_usage; -// ssc_data_get_number(data, "annual_fuel_usage", &annual_fuel_usage); -// EXPECT_NEAR(annual_fuel_usage, 0, 0 * m_error_tolerance_hi) << "Annual fuel usage"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t capacity_factor; -// ssc_data_get_number(data, "capacity_factor", &capacity_factor); -// EXPECT_NEAR(capacity_factor, 30.5585, 30.5585 * m_error_tolerance_hi) << "Capacity Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_W_cycle_gross; -// ssc_data_get_number(data, "annual_W_cycle_gross", &annual_W_cycle_gross); -// EXPECT_NEAR(annual_W_cycle_gross, 3.01252e8, 3.01252e8 * m_error_tolerance_hi) << "Annual W_cycle Gross"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t kwh_per_kw; -// ssc_data_get_number(data, "kwh_per_kw", &kwh_per_kw); -// EXPECT_NEAR(kwh_per_kw, 2676.92, 2676.92 * m_error_tolerance_hi) << "kwh per kw"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t conversion_factor; -// ssc_data_get_number(data, "conversion_factor", &conversion_factor); -// EXPECT_NEAR(conversion_factor, 92.678, 92.678 * m_error_tolerance_hi) << "Conversion Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t system_heat_rate; -// ssc_data_get_number(data, "system_heat_rate", &system_heat_rate); -// EXPECT_NEAR(system_heat_rate, 3.413, 3.413 * m_error_tolerance_hi) << "System heat rate"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_total_water_use; -// ssc_data_get_number(data, "annual_total_water_use", &annual_total_water_use); -// EXPECT_NEAR(annual_total_water_use, 55547.3, 55547.3 * m_error_tolerance_hi) << "Annual Total Water Use"; // choose either m_error_tolerance_lo or m_error_tolerance_hi // -// -// } +//// Alternative heliostat focusing method: Flat +//NAMESPACE_TEST(csp_tower, SteamTowerCmod, HeliostatFlatFocusing_NoFinancial) +//{ +// ssc_data_t defaults = tcsdirect_steam_defaults(); +// CmodUnderTest steam_tower = CmodUnderTest("tcsdirect_steam", defaults); +// steam_tower.SetInput("focus_type", 0); +// steam_tower.SetInput("eta_ref", 0.404); +// steam_tower.SetInput("startup_frac", 0.5); +// steam_tower.SetInput("P_cond_min", 2); +// +// int errors = steam_tower.RunModule(); +// EXPECT_FALSE(errors); +// if (!errors) { +// EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_energy"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_fuel_usage"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(steam_tower.GetOutput("capacity_factor"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_W_cycle_gross"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(steam_tower.GetOutput("kwh_per_kw"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(steam_tower.GetOutput("conversion_factor"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(steam_tower.GetOutput("system_heat_rate"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_total_water_use"), 571408807, kErrorToleranceLo); +// } //} - -/// Test tcsdirect_steam with alternative Heliostat canting method: Equinox -/// Rest default configurations with respect to the single owner financial model -//TEST_F(CMTcsDirectSteam, DirectSteam_Heliostat_Canting_SingleOwner_cmod_tcsdirect_steam) { -// -// ssc_data_t data = ssc_data_create(); -// int test_errors = tcsdirect_steam_daggett_canting_method(data); -// -// EXPECT_FALSE(test_errors); -// if (!test_errors) -// { -// ssc_number_t annual_energy; -// ssc_data_get_number(data, "annual_energy", &annual_energy); -// EXPECT_NEAR(annual_energy, 2.68848e8, 2.68848e8 * m_error_tolerance_hi) << "Annual Energy"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_fuel_usage; -// ssc_data_get_number(data, "annual_fuel_usage", &annual_fuel_usage); -// EXPECT_NEAR(annual_fuel_usage, 0, 0 * m_error_tolerance_hi) << "Annual fuel usage"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t capacity_factor; -// ssc_data_get_number(data, "capacity_factor", &capacity_factor); -// EXPECT_NEAR(capacity_factor, 30.6521, 30.6521 * m_error_tolerance_hi) << "Capacity Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi // -// ssc_number_t annual_W_cycle_gross; -// ssc_data_get_number(data, "annual_W_cycle_gross", &annual_W_cycle_gross); -// EXPECT_NEAR(annual_W_cycle_gross, 3.02142e8, 3.02142e8 * m_error_tolerance_hi) << "Annual W_cycle Gross"; // choose either m_error_tolerance_lo or m_error_tolerance_hi // -// ssc_number_t kwh_per_kw; -// ssc_data_get_number(data, "kwh_per_kw", &kwh_per_kw); -// EXPECT_NEAR(kwh_per_kw, 2685.12, 2685.12 * m_error_tolerance_hi) << "kwh per kw"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t conversion_factor; -// ssc_data_get_number(data, "conversion_factor", &conversion_factor); -// EXPECT_NEAR(conversion_factor, 92.6883, 92.6883 * m_error_tolerance_hi) << "Conversion Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t system_heat_rate; -// ssc_data_get_number(data, "system_heat_rate", &system_heat_rate); -// EXPECT_NEAR(system_heat_rate, 3.413, 3.413 * m_error_tolerance_hi) << "System heat rate"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_total_water_use; -// ssc_data_get_number(data, "annual_total_water_use", &annual_total_water_use); -// EXPECT_NEAR(annual_total_water_use, 55606.8, 55606.8 * m_error_tolerance_hi) << "Annual Total Water Use"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// -// } +//// Alternative heliostat canting method: Equinox +//NAMESPACE_TEST(csp_tower, SteamTowerCmod, HeliostatEquinoxCanting_NoFinancial) +//{ +// ssc_data_t defaults = tcsdirect_steam_defaults(); +// CmodUnderTest steam_tower = CmodUnderTest("tcsdirect_steam", defaults); +// steam_tower.SetInput("cant_type", 2); +// steam_tower.SetInput("eta_ref", 0.404); +// steam_tower.SetInput("startup_frac", 0.5); +// steam_tower.SetInput("P_cond_min", 2); +// +// int errors = steam_tower.RunModule(); +// EXPECT_FALSE(errors); +// if (!errors) { +// EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_energy"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_fuel_usage"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(steam_tower.GetOutput("capacity_factor"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_W_cycle_gross"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(steam_tower.GetOutput("kwh_per_kw"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(steam_tower.GetOutput("conversion_factor"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(steam_tower.GetOutput("system_heat_rate"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_total_water_use"), 571408807, kErrorToleranceLo); +// } //} - -/// Test tcsdirect_steam with alternative location: Tucson, AZ -/// Rest default configurations with respect to the single owner financial model -//TEST_F(CMTcsDirectSteam, DirectSteam_Location_Tucson_AZ_SingleOwner_cmod_tcsdirect_steam) { // -// ssc_data_t data = ssc_data_create(); -// int test_errors = tcsdirect_steam_daggett_tucson_AZ(data); -// -// EXPECT_FALSE(test_errors); -// if (!test_errors) -// { -// ssc_number_t annual_energy; -// ssc_data_get_number(data, "annual_energy", &annual_energy); -// EXPECT_NEAR(annual_energy, 2.55075e8, 2.55075e8 * m_error_tolerance_hi) << "Annual Energy"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_fuel_usage; -// ssc_data_get_number(data, "annual_fuel_usage", &annual_fuel_usage); -// EXPECT_NEAR(annual_fuel_usage, 0, 0 * m_error_tolerance_hi) << "Annual fuel usage"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t capacity_factor; -// ssc_data_get_number(data, "capacity_factor", &capacity_factor); -// EXPECT_NEAR(capacity_factor, 29.0817, 29.0817 * m_error_tolerance_hi) << "Capacity Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_W_cycle_gross; -// ssc_data_get_number(data, "annual_W_cycle_gross", &annual_W_cycle_gross); -// EXPECT_NEAR(annual_W_cycle_gross, 2.87524e8, 2.87524e8 * m_error_tolerance_hi) << "Annual W_cycle Gross"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t kwh_per_kw; -// ssc_data_get_number(data, "kwh_per_kw", &kwh_per_kw); -// EXPECT_NEAR(kwh_per_kw, 2547.56, 2547.56 * m_error_tolerance_hi) << "kwh per kw"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t conversion_factor; -// ssc_data_get_number(data, "conversion_factor", &conversion_factor); -// EXPECT_NEAR(conversion_factor, 92.4107, 92.4107 * m_error_tolerance_hi) << "Conversion Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t system_heat_rate; -// ssc_data_get_number(data, "system_heat_rate", &system_heat_rate); -// EXPECT_NEAR(system_heat_rate, 3.413, 3.413 * m_error_tolerance_hi) << "System heat rate"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_total_water_use; -// ssc_data_get_number(data, "annual_total_water_use", &annual_total_water_use); -// EXPECT_NEAR(annual_total_water_use, 54685.3, 54685.3 * m_error_tolerance_hi) << "Annual Total Water Use"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// -// } +//// Phoenix, AZ +//NAMESPACE_TEST(csp_tower, SteamTowerCmod, Phoeniz_NoFinancial) +//{ +// ssc_data_t defaults = tcsdirect_steam_defaults(); +// CmodUnderTest steam_tower = CmodUnderTest("tcsdirect_steam", defaults); +// char solar_resource_path_tucson[512]; +// int n2 = sprintf(solar_resource_path_tucson, "%s/test/input_cases/directsteam_data/tucson_az_32.116521_-110.933042_psmv3_60_tmy.csv", std::getenv("SSCDIR")); +// steam_tower.SetInput("solar_resource_file", solar_resource_path_tucson); +// +// int errors = steam_tower.RunModule(); +// EXPECT_FALSE(errors); +// if (!errors) { +// EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_energy"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_fuel_usage"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(steam_tower.GetOutput("capacity_factor"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_W_cycle_gross"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(steam_tower.GetOutput("kwh_per_kw"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(steam_tower.GetOutput("conversion_factor"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(steam_tower.GetOutput("system_heat_rate"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_total_water_use"), 571408807, kErrorToleranceLo); +// } //} - - diff --git a/test/ssc_test/cmod_tcsdirect_steam_test.h b/test/ssc_test/cmod_tcsdirect_steam_test.h deleted file mode 100644 index 6d62233aa75..00000000000 --- a/test/ssc_test/cmod_tcsdirect_steam_test.h +++ /dev/null @@ -1,54 +0,0 @@ -#include - -#include "core.h" -#ifndef _CMOD_TCSDIRECT_STEAM_TEST_H_ -#define _CMOD_TCSDIRECT_STEAM_TEST_H_ - -#include "vartab.h" -#include "../ssc/common.h" -#include "../tcs_test/tcsdirect_steam_cases.h" - -/** - * CMtcsDirectSteam tests the cmod_tcsdirect_steam using the SAM code generator to generate data - * Eventually a method can be written to write this data to a vartable so that lower-level methods of - * tcsdirect_steam can be tested - * For now, this uses the SSCAPI interfaces to run the compute module and compare results - */ -class CMTcsDirectSteam : public ::testing::Test { - -public: - - ssc_data_t data; - ssc_number_t calculated_value; - ssc_number_t * calculated_array; - double m_error_tolerance_hi = 0.01; // 1.0% - double m_error_tolerance_lo = 0.001; // 0.1% - - void SetUp() - { - data = ssc_data_create(); - tcsdirect_steam_default(data); - calculated_array = new ssc_number_t[8760]; - } - void TearDown() { - if (data) { - ssc_data_free(data); - data = nullptr; - } - if (calculated_array) { - delete[] calculated_array; - } - } - void SetCalculated(std::string name) - { - ssc_data_get_number(data, const_cast(name.c_str()), &calculated_value); - } - void SetCalculatedArray(std::string name) - { - int n; - calculated_array = ssc_data_get_array(data, const_cast(name.c_str()), &n); - } -}; - -#endif // !_CMOD_TCSDIRECT_STEAM_TEST_H_ - diff --git a/test/ssc_test/cmod_tcsfresnel_molten_salt_test.cpp b/test/ssc_test/cmod_tcsfresnel_molten_salt_test.cpp index afd79eea8b2..036165f1da7 100644 --- a/test/ssc_test/cmod_tcsfresnel_molten_salt_test.cpp +++ b/test/ssc_test/cmod_tcsfresnel_molten_salt_test.cpp @@ -1,489 +1,244 @@ #include - -#include "cmod_tcsfresnel_molten_salt_test.h" -#include "../tcs_test/tcsfresnel_molten_salt_cases.h" -#include "../input_cases/weather_inputs.h" - - -/// Test tcsfresnel_molten_salt with all default configurations with respect to the No Finanical model -TEST_F(CMTcsFresnelMoltenSalt, Rankine_Default_No_Financial_cmod_tcsfresnel_molten_salt) { - - ssc_data_t data = ssc_data_create(); - int test_errors = tcsfresnel_molten_salt_tucson_default(data); - - EXPECT_FALSE(test_errors); - if (!test_errors) - { - ssc_number_t annual_energy; - ssc_data_get_number(data, "annual_energy", &annual_energy); - EXPECT_NEAR(annual_energy, 337260930.158212, 337260930.158212 * m_error_tolerance_hi) << "Annual Energy"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t annual_fuel_usage; - ssc_data_get_number(data, "annual_fuel_usage", &annual_fuel_usage); - EXPECT_NEAR(annual_fuel_usage, 0, 0 * m_error_tolerance_hi) << "Annual fuel usage"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t capacity_factor; - ssc_data_get_number(data, "capacity_factor", &capacity_factor); - EXPECT_NEAR(capacity_factor, 38.500145, 38.500145 * m_error_tolerance_hi) << "Capacity Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t annual_W_cycle_gross; - ssc_data_get_number(data, "annual_W_cycle_gross", &annual_W_cycle_gross); - EXPECT_NEAR(annual_W_cycle_gross, 372651034.745992, 372651034.745992 * m_error_tolerance_hi) << "Annual W_cycle Gross"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t kwh_per_kw; - ssc_data_get_number(data, "kwh_per_kw", &kwh_per_kw); - EXPECT_NEAR(kwh_per_kw, 3372.612727, 3372.612727 * m_error_tolerance_hi) << "kwh per kw"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t conversion_factor; - ssc_data_get_number(data, "conversion_factor", &conversion_factor); - EXPECT_NEAR(conversion_factor, 94.274118, 94.274118 * m_error_tolerance_hi) << "Conversion Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t system_heat_rate; - ssc_data_get_number(data, "system_heat_rate", &system_heat_rate); - EXPECT_NEAR(system_heat_rate, 3.413000, 3.413000 * m_error_tolerance_hi) << "System heat rate"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t annual_total_water_use; - ssc_data_get_number(data, "annual_total_water_use", &annual_total_water_use); - EXPECT_NEAR(annual_total_water_use, 30058.992530, 30058.992530 * m_error_tolerance_hi) << "Annual Total Water Use"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - } +#include "tcsfresnel_molten_salt_defaults.h" +#include "csp_common_test.h" +#include "vs_google_test_explorer_namespace.h" + +namespace csp_tower {} +using namespace csp_tower; + +//========Tests=================================================================================== +NAMESPACE_TEST(csp_fresnel, PowerFresnelCmod, Default_NoFinancial) +{ + ssc_data_t defaults = tcsfresnel_molten_salt_defaults(); + CmodUnderTest power_fresnel = CmodUnderTest("tcsmslf", defaults); + int errors = power_fresnel.RunModule(); + EXPECT_FALSE(errors); + if (!errors) { + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_energy"), 337249089, kErrorToleranceLo); + EXPECT_NEAR(power_fresnel.GetOutput("annual_fuel_usage"), 0, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("capacity_factor"), 38.50, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_W_cycle_gross"), 372639466, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("kwh_per_kw"), 3372, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("conversion_factor"), 94.27, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("system_heat_rate"), 3.413, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_total_water_use"), 30058, kErrorToleranceLo); + } } -/// Test tcsfresnel_molten_salt with alternative defocusing strategy: Sequenced -/// Rest default configurations with respect to the No Financial model -TEST_F(CMTcsFresnelMoltenSalt, Rankine_Defocusing_Strategy_No_Financial_cmod_tcsfresnel_molten_salt) { - - ssc_data_t data = ssc_data_create(); - int test_errors = tcsfresnel_molten_salt_tucson_defocusing_strategy(data); - - EXPECT_FALSE(test_errors); - if (!test_errors) - { - ssc_number_t annual_energy; - ssc_data_get_number(data, "annual_energy", &annual_energy); - EXPECT_NEAR(annual_energy, 337260930.158212, 337260930.158212 * m_error_tolerance_hi) << "Annual Energy"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t annual_fuel_usage; - ssc_data_get_number(data, "annual_fuel_usage", &annual_fuel_usage); - EXPECT_NEAR(annual_fuel_usage, 0, 0 * m_error_tolerance_hi) << "Annual fuel usage"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t capacity_factor; - ssc_data_get_number(data, "capacity_factor", &capacity_factor); - EXPECT_NEAR(capacity_factor, 38.500145, 38.500145 * m_error_tolerance_hi) << "Capacity Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t annual_W_cycle_gross; - ssc_data_get_number(data, "annual_W_cycle_gross", &annual_W_cycle_gross); - EXPECT_NEAR(annual_W_cycle_gross, 372651034.745992, 372651034.745992 * m_error_tolerance_hi) << "Annual W_cycle Gross"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t kwh_per_kw; - ssc_data_get_number(data, "kwh_per_kw", &kwh_per_kw); - EXPECT_NEAR(kwh_per_kw, 3372.612727, 3372.612727 * m_error_tolerance_hi) << "kwh per kw"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t conversion_factor; - ssc_data_get_number(data, "conversion_factor", &conversion_factor); - EXPECT_NEAR(conversion_factor, 94.274118, 94.274118 * m_error_tolerance_hi) << "Conversion Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t system_heat_rate; - ssc_data_get_number(data, "system_heat_rate", &system_heat_rate); - EXPECT_NEAR(system_heat_rate, 3.413000, 3.413000 * m_error_tolerance_hi) << "System heat rate"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t annual_total_water_use; - ssc_data_get_number(data, "annual_total_water_use", &annual_total_water_use); - EXPECT_NEAR(annual_total_water_use, 30058.992530, 30058.992530 * m_error_tolerance_hi) << "Annual Total Water Use"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - } +// Defocusing strategy: Sequenced +NAMESPACE_TEST(csp_fresnel, PowerFresnelCmod, SequencedDefocusing_NoFinancial) +{ + ssc_data_t defaults = tcsfresnel_molten_salt_defaults(); + CmodUnderTest power_fresnel = CmodUnderTest("tcsmslf", defaults); + power_fresnel.SetInput("fthrctrl", 1); + + int errors = power_fresnel.RunModule(); + EXPECT_FALSE(errors); + if (!errors) { + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_energy"), 337249089, kErrorToleranceLo); + EXPECT_NEAR(power_fresnel.GetOutput("annual_fuel_usage"), 0, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("capacity_factor"), 38.50, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_W_cycle_gross"), 372639466, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("kwh_per_kw"), 3372, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("conversion_factor"), 94.27, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("system_heat_rate"), 3.413, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_total_water_use"), 30058, kErrorToleranceLo); + } } -/// Test tcsfresnel_molten_salt with alternative Field HTF: Therminol VP-1 -/// Rest default configurations with respect to the No Financial model -TEST_F(CMTcsFresnelMoltenSalt, Rankine_Field_HTF_No_Financial_cmod_tcsfresnel_molten_salt) { - - ssc_data_t data = ssc_data_create(); - int test_errors = tcsfresnel_molten_salt_tucson_field_HTF(data); - - EXPECT_FALSE(test_errors); - if (!test_errors) - { - ssc_number_t annual_energy; - ssc_data_get_number(data, "annual_energy", &annual_energy); - EXPECT_NEAR(annual_energy, 336220223.708381, 336220223.708381 * m_error_tolerance_hi) << "Annual Energy"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t annual_fuel_usage; - ssc_data_get_number(data, "annual_fuel_usage", &annual_fuel_usage); - EXPECT_NEAR(annual_fuel_usage, 0, 0 * m_error_tolerance_hi) << "Annual fuel usage"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t capacity_factor; - ssc_data_get_number(data, "capacity_factor", &capacity_factor); - EXPECT_NEAR(capacity_factor, 38.381343, 38.381343 * m_error_tolerance_hi) << "Capacity Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t annual_W_cycle_gross; - ssc_data_get_number(data, "annual_W_cycle_gross", &annual_W_cycle_gross); - EXPECT_NEAR(annual_W_cycle_gross, 371358844.515444, 371358844.515444 * m_error_tolerance_hi) << "Annual W_cycle Gross"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t kwh_per_kw; - ssc_data_get_number(data, "kwh_per_kw", &kwh_per_kw); - EXPECT_NEAR(kwh_per_kw, 3362.205652, 3362.205652 * m_error_tolerance_hi) << "kwh per kw"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t conversion_factor; - ssc_data_get_number(data, "conversion_factor", &conversion_factor); - EXPECT_NEAR(conversion_factor, 94.310237, 94.310237 * m_error_tolerance_hi) << "Conversion Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t system_heat_rate; - ssc_data_get_number(data, "system_heat_rate", &system_heat_rate); - EXPECT_NEAR(system_heat_rate, 3.413000, 3.413000 * m_error_tolerance_hi) << "System heat rate"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t annual_total_water_use; - ssc_data_get_number(data, "annual_total_water_use", &annual_total_water_use); - EXPECT_NEAR(annual_total_water_use, 29948.205347, 29948.205347 * m_error_tolerance_hi) << "Annual Total Water Use"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - } +// Field HTF: Therminol VP-1 +NAMESPACE_TEST(csp_fresnel, PowerFresnelCmod, TherminolVp1Htf_NoFinancial) +{ + ssc_data_t defaults = tcsfresnel_molten_salt_defaults(); + CmodUnderTest power_fresnel = CmodUnderTest("tcsmslf", defaults); + power_fresnel.SetInput("Fluid", 21); + power_fresnel.SetInput("field_fluid", 21); + power_fresnel.SetInput("is_hx", 1); + power_fresnel.SetInput("V_tank_hot_ini", 1290.5642); + power_fresnel.SetInput("vol_tank", 6452.821); + + int errors = power_fresnel.RunModule(); + EXPECT_FALSE(errors); + if (!errors) { + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_energy"), 336171001, kErrorToleranceLo); + EXPECT_NEAR(power_fresnel.GetOutput("annual_fuel_usage"), 0, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("capacity_factor"), 38.38, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_W_cycle_gross"), 371306661, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("kwh_per_kw"), 3362, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("conversion_factor"), 94.31, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("system_heat_rate"), 3.413, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_total_water_use"), 29944, kErrorToleranceLo); + } } -/// Test tcsfresnel_molten_salt with alternative optical characterization method: Solar position -/// Rest default configurations with respect to the No Financial model -TEST_F(CMTcsFresnelMoltenSalt, Rankine_Optical_Char_No_Financial_cmod_tcsfresnel_molten_salt) { - - ssc_data_t data = ssc_data_create(); - int test_errors = tcsfresnel_molten_salt_tucson_optical_char_solar(data); - - EXPECT_FALSE(test_errors); - if (!test_errors) - { - ssc_number_t annual_energy; - ssc_data_get_number(data, "annual_energy", &annual_energy); - EXPECT_NEAR(annual_energy, 228402762.335069, 228402762.335069 * m_error_tolerance_hi) << "Annual Energy"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t annual_fuel_usage; - ssc_data_get_number(data, "annual_fuel_usage", &annual_fuel_usage); - EXPECT_NEAR(annual_fuel_usage, 0, 0 * m_error_tolerance_hi) << "Annual fuel usage"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t capacity_factor; - ssc_data_get_number(data, "capacity_factor", &capacity_factor); - EXPECT_NEAR(capacity_factor, 26.073401, 26.073401 * m_error_tolerance_hi) << "Capacity Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t annual_W_cycle_gross; - ssc_data_get_number(data, "annual_W_cycle_gross", &annual_W_cycle_gross); - EXPECT_NEAR(annual_W_cycle_gross, 255099173.098881, 255099173.098881 * m_error_tolerance_hi) << "Annual W_cycle Gross"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t kwh_per_kw; - ssc_data_get_number(data, "kwh_per_kw", &kwh_per_kw); - EXPECT_NEAR(kwh_per_kw, 2284.029943, 2284.029943 * m_error_tolerance_hi) << "kwh per kw"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t conversion_factor; - ssc_data_get_number(data, "conversion_factor", &conversion_factor); - EXPECT_NEAR(conversion_factor, 93.265512, 93.265512 * m_error_tolerance_hi) << "Conversion Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t system_heat_rate; - ssc_data_get_number(data, "system_heat_rate", &system_heat_rate); - EXPECT_NEAR(system_heat_rate, 3.413000, 3.413000 * m_error_tolerance_hi) << "System heat rate"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t annual_total_water_use; - ssc_data_get_number(data, "annual_total_water_use", &annual_total_water_use); - EXPECT_NEAR(annual_total_water_use, 21782.647609, 21782.647609 * m_error_tolerance_hi) << "Annual Total Water Use"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - } +// Optical characterization method: Solar position +NAMESPACE_TEST(csp_fresnel, PowerFresnelCmod, SolarPositioinOpticalChar_NoFinancial) +{ + ssc_data_t defaults = tcsfresnel_molten_salt_defaults(); + CmodUnderTest power_fresnel = CmodUnderTest("tcsmslf", defaults); + power_fresnel.SetInput("opt_model", 1); + + int errors = power_fresnel.RunModule(); + EXPECT_FALSE(errors); + if (!errors) { + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_energy"), 228344862, kErrorToleranceLo); + EXPECT_NEAR(power_fresnel.GetOutput("annual_fuel_usage"), 0, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("capacity_factor"), 26.07, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_W_cycle_gross"), 255036717, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("kwh_per_kw"), 2283, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("conversion_factor"), 93.26, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("system_heat_rate"), 3.413, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_total_water_use"), 21776, kErrorToleranceLo); + } } -/// Test tcsfresnel_molten_salt with alternative receiver model type: Polynomial Heat Loss model -/// Rest default configurations with respect to the No Financial model -//TEST_F(CMTcsFresnelMoltenSalt, Rankine_Polynomial_Heat_Loss_No_Financial_cmod_tcsfresnel_molten_salt) { -// -// ssc_data_t data = ssc_data_create(); -// int test_errors = tcsfresnel_molten_salt_tucson_polynomial_heat_loss_model(data); -// -// EXPECT_FALSE(test_errors); -// if (!test_errors) -// { -// ssc_number_t annual_energy; -// ssc_data_get_number(data, "annual_energy", &annual_energy); -// EXPECT_NEAR(annual_energy, 3.3431e8, 3.3431e8 * m_error_tolerance_hi) << "Annual Energy"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_fuel_usage; -// ssc_data_get_number(data, "annual_fuel_usage", &annual_fuel_usage); -// EXPECT_NEAR(annual_fuel_usage, 0, 0 * m_error_tolerance_hi) << "Annual fuel usage"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t capacity_factor; -// ssc_data_get_number(data, "capacity_factor", &capacity_factor); -// EXPECT_NEAR(capacity_factor, 38.1633, 38.1633 * m_error_tolerance_hi) << "Capacity Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_W_cycle_gross; -// ssc_data_get_number(data, "annual_W_cycle_gross", &annual_W_cycle_gross); -// EXPECT_NEAR(annual_W_cycle_gross, 3.70549e8, 3.70549e8 * m_error_tolerance_hi) << "Annual W_cycle Gross"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t kwh_per_kw; -// ssc_data_get_number(data, "kwh_per_kw", &kwh_per_kw); -// EXPECT_NEAR(kwh_per_kw, 3343.1, 3343.1 * m_error_tolerance_hi) << "kwh per kw"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t conversion_factor; -// ssc_data_get_number(data, "conversion_factor", &conversion_factor); -// EXPECT_NEAR(conversion_factor, 93.9793, 93.9793 * m_error_tolerance_hi) << "Conversion Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t system_heat_rate; -// ssc_data_get_number(data, "system_heat_rate", &system_heat_rate); -// EXPECT_NEAR(system_heat_rate, 3.413, 3.413 * m_error_tolerance_hi) << "System heat rate"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_total_water_use; -// ssc_data_get_number(data, "annual_total_water_use", &annual_total_water_use); -// EXPECT_NEAR(annual_total_water_use, 29823.1, 29823.1 * m_error_tolerance_hi) << "Annual Total Water Use"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// } +//// Receiver model type: Polynomial heat loss model +//NAMESPACE_TEST(csp_fresnel, PowerFresnelCmod, PolynomialHeatLoss_NoFinancial) +//{ +// ssc_data_t defaults = tcsfresnel_molten_salt_defaults(); +// CmodUnderTest power_fresnel = CmodUnderTest("tcsmslf", defaults); +// power_fresnel.SetInput("nLoops", 148); +// power_fresnel.SetInput("rec_model", 1); +// +// int errors = power_fresnel.RunModule(); +// EXPECT_FALSE(errors); +// if (!errors) { +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_energy"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_fuel_usage"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("capacity_factor"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_W_cycle_gross"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("kwh_per_kw"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("conversion_factor"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("system_heat_rate"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_total_water_use"), 571408807, kErrorToleranceLo); +// } //} - -/// Test tcsfresnel_molten_salt with alternative condenser type: Evaporative -/// Rest default configurations with respect to the No Financial model -//TEST_F(CMTcsFresnelMoltenSalt, Rankine_Evap_Condenser_No_Financial_cmod_tcsfresnel_molten_salt) { -// -// ssc_data_t data = ssc_data_create(); -// int test_errors = tcsfresnel_molten_salt_tucson_evap_condenser(data); -// -// EXPECT_FALSE(test_errors); -// if (!test_errors) -// { -// ssc_number_t annual_energy; -// ssc_data_get_number(data, "annual_energy", &annual_energy); -// EXPECT_NEAR(annual_energy, 3.54549e8, 3.54549e8 * m_error_tolerance_hi) << "Annual Energy"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_fuel_usage; -// ssc_data_get_number(data, "annual_fuel_usage", &annual_fuel_usage); -// EXPECT_NEAR(annual_fuel_usage, 0, 0 * m_error_tolerance_hi) << "Annual fuel usage"; // choose either m_error_tolerance_lo or m_error_tolerance_hi // -// ssc_number_t capacity_factor; -// ssc_data_get_number(data, "capacity_factor", &capacity_factor); -// EXPECT_NEAR(capacity_factor, 40.4736, 40.4736 * m_error_tolerance_hi) << "Capacity Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_W_cycle_gross; -// ssc_data_get_number(data, "annual_W_cycle_gross", &annual_W_cycle_gross); -// EXPECT_NEAR(annual_W_cycle_gross, 3.84127e8, 3.84127e8 * m_error_tolerance_hi) << "Annual W_cycle Gross"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t kwh_per_kw; -// ssc_data_get_number(data, "kwh_per_kw", &kwh_per_kw); -// EXPECT_NEAR(kwh_per_kw, 3545.49, 3545.49 * m_error_tolerance_hi) << "kwh per kw"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t conversion_factor; -// ssc_data_get_number(data, "conversion_factor", &conversion_factor); -// EXPECT_NEAR(conversion_factor, 96.1456, 96.1456 * m_error_tolerance_hi) << "Conversion Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t system_heat_rate; -// ssc_data_get_number(data, "system_heat_rate", &system_heat_rate); -// EXPECT_NEAR(system_heat_rate, 3.413, 3.413 * m_error_tolerance_hi) << "System heat rate"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_total_water_use; -// ssc_data_get_number(data, "annual_total_water_use", &annual_total_water_use); -// EXPECT_NEAR(annual_total_water_use, 998592, 998592 * m_error_tolerance_hi) << "Annual Total Water Use"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// } +//// Condenser type: Evaporative +//NAMESPACE_TEST(csp_fresnel, PowerFresnelCmod, EvaporativeCondenser_NoFinancial) +//{ +// ssc_data_t defaults = tcsfresnel_molten_salt_defaults(); +// CmodUnderTest power_fresnel = CmodUnderTest("tcsmslf", defaults); +// power_fresnel.SetInput("CT", 1); +// +// int errors = power_fresnel.RunModule(); +// EXPECT_FALSE(errors); +// if (!errors) { +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_energy"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_fuel_usage"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("capacity_factor"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_W_cycle_gross"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("kwh_per_kw"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("conversion_factor"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("system_heat_rate"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_total_water_use"), 571408807, kErrorToleranceLo); +// } //} - -/// Test tcsfresnel_molten_salt with alternative condenser type: Hybrid -/// Rest default configurations with respect to the No Financial model -//TEST_F(CMTcsFresnelMoltenSalt, Rankine_Hybrid_Condenser_No_Financial_cmod_tcsfresnel_molten_salt) { -// -// ssc_data_t data = ssc_data_create(); -// int test_errors = tcsfresnel_molten_salt_tucson_hybrid_condenser(data); -// -// EXPECT_FALSE(test_errors); -// if (!test_errors) -// { -// ssc_number_t annual_energy; -// ssc_data_get_number(data, "annual_energy", &annual_energy); -// EXPECT_NEAR(annual_energy, 3.30518e8, 3.30518e8 * m_error_tolerance_hi) << "Annual Energy"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_fuel_usage; -// ssc_data_get_number(data, "annual_fuel_usage", &annual_fuel_usage); -// EXPECT_NEAR(annual_fuel_usage, 0, 0 * m_error_tolerance_hi) << "Annual fuel usage"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t capacity_factor; -// ssc_data_get_number(data, "capacity_factor", &capacity_factor); -// EXPECT_NEAR(capacity_factor, 37.7304, 37.7304 * m_error_tolerance_hi) << "Capacity Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_W_cycle_gross; -// ssc_data_get_number(data, "annual_W_cycle_gross", &annual_W_cycle_gross); -// EXPECT_NEAR(annual_W_cycle_gross, 3.68433e8, 3.68433e8 * m_error_tolerance_hi) << "Annual W_cycle Gross"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t kwh_per_kw; -// ssc_data_get_number(data, "kwh_per_kw", &kwh_per_kw); -// EXPECT_NEAR(kwh_per_kw, 3305.18, 3305.18 * m_error_tolerance_hi) << "kwh per kw"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t conversion_factor; -// ssc_data_get_number(data, "conversion_factor", &conversion_factor); -// EXPECT_NEAR(conversion_factor, 93.447, 93.447 * m_error_tolerance_hi) << "Conversion Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi // -// ssc_number_t system_heat_rate; -// ssc_data_get_number(data, "system_heat_rate", &system_heat_rate); -// EXPECT_NEAR(system_heat_rate, 3.413, 3.413 * m_error_tolerance_hi) << "System heat rate"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_total_water_use; -// ssc_data_get_number(data, "annual_total_water_use", &annual_total_water_use); -// EXPECT_NEAR(annual_total_water_use, 29597.1, 29597.1 * m_error_tolerance_hi) << "Annual Total Water Use"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// } +//// Condenser type: Hybrid +//NAMESPACE_TEST(csp_fresnel, PowerFresnelCmod, HybridCondenser_NoFinancial) +//{ +// ssc_data_t defaults = tcsfresnel_molten_salt_defaults(); +// CmodUnderTest power_fresnel = CmodUnderTest("tcsmslf", defaults); +// power_fresnel.SetInput("CT", 3); +// +// int errors = power_fresnel.RunModule(); +// EXPECT_FALSE(errors); +// if (!errors) { +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_energy"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_fuel_usage"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("capacity_factor"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_W_cycle_gross"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("kwh_per_kw"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("conversion_factor"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("system_heat_rate"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_total_water_use"), 571408807, kErrorToleranceLo); +// } //} - -/// Test tcsfresnel_molten_salt with alternative turbine inlet pressure control: Sliding pressure -/// Rest default configurations with respect to the No Financial model -//TEST_F(CMTcsFresnelMoltenSalt, Rankine_Sliding_P_No_Financial_cmod_tcsfresnel_molten_salt) { -// -// ssc_data_t data = ssc_data_create(); -// int test_errors = tcsfresnel_molten_salt_tucson_sliding_p(data); -// -// EXPECT_FALSE(test_errors); -// if (!test_errors) -// { -// ssc_number_t annual_energy; -// ssc_data_get_number(data, "annual_energy", &annual_energy); -// EXPECT_NEAR(annual_energy, 3.14357e8, 3.14357e8 * m_error_tolerance_hi) << "Annual Energy"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_fuel_usage; -// ssc_data_get_number(data, "annual_fuel_usage", &annual_fuel_usage); -// EXPECT_NEAR(annual_fuel_usage, 0, 0 * m_error_tolerance_hi) << "Annual fuel usage"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t capacity_factor; -// ssc_data_get_number(data, "capacity_factor", &capacity_factor); -// EXPECT_NEAR(capacity_factor, 35.8856, 35.8856 * m_error_tolerance_hi) << "Capacity Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_W_cycle_gross; -// ssc_data_get_number(data, "annual_W_cycle_gross", &annual_W_cycle_gross); -// EXPECT_NEAR(annual_W_cycle_gross, 3.49548e8, 3.49548e8 * m_error_tolerance_hi) << "Annual W_cycle Gross"; // choose either m_error_tolerance_lo or m_error_tolerance_hi // -// ssc_number_t kwh_per_kw; -// ssc_data_get_number(data, "kwh_per_kw", &kwh_per_kw); -// EXPECT_NEAR(kwh_per_kw, 3143.58, 3143.58 * m_error_tolerance_hi) << "kwh per kw"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t conversion_factor; -// ssc_data_get_number(data, "conversion_factor", &conversion_factor); -// EXPECT_NEAR(conversion_factor, 93.6795, 93.6795 * m_error_tolerance_hi) << "Conversion Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t system_heat_rate; -// ssc_data_get_number(data, "system_heat_rate", &system_heat_rate); -// EXPECT_NEAR(system_heat_rate, 3.413, 3.413 * m_error_tolerance_hi) << "System heat rate"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_total_water_use; -// ssc_data_get_number(data, "annual_total_water_use", &annual_total_water_use); -// EXPECT_NEAR(annual_total_water_use, 28264.2, 28264.2 * m_error_tolerance_hi) << "Annual Total Water Use"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// } +//// Turbine inlet pressure control: Sliding pressure +//NAMESPACE_TEST(csp_fresnel, PowerFresnelCmod, TurbineSlidingPressure_NoFinancial) +//{ +// ssc_data_t defaults = tcsfresnel_molten_salt_defaults(); +// CmodUnderTest power_fresnel = CmodUnderTest("tcsmslf", defaults); +// power_fresnel.SetInput("tech_type", 3); +// +// int errors = power_fresnel.RunModule(); +// EXPECT_FALSE(errors); +// if (!errors) { +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_energy"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_fuel_usage"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("capacity_factor"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_W_cycle_gross"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("kwh_per_kw"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("conversion_factor"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("system_heat_rate"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_total_water_use"), 571408807, kErrorToleranceLo); +// } //} - -/// Test tcsfresnel_molten_salt with alternative HTF freeze protection mode: Electric heating -/// Rest default configurations with respect to the No Financial model -//TEST_F(CMTcsFresnelMoltenSalt, Rankine_HTF_Freeze_Protection_No_Financial_cmod_tcsfresnel_molten_salt) { -// -// ssc_data_t data = ssc_data_create(); -// int test_errors = tcsfresnel_molten_salt_tucson_HTF_freeze_protection(data); -// -// EXPECT_FALSE(test_errors); -// if (!test_errors) -// { -// ssc_number_t annual_energy; -// ssc_data_get_number(data, "annual_energy", &annual_energy); -// EXPECT_NEAR(annual_energy, 2.95735e8, 2.95735e8 * m_error_tolerance_hi) << "Annual Energy"; // choose either m_error_tolerance_lo or m_error_tolerance_hi // -// ssc_number_t annual_fuel_usage; -// ssc_data_get_number(data, "annual_fuel_usage", &annual_fuel_usage); -// EXPECT_NEAR(annual_fuel_usage, 0, 0 * m_error_tolerance_hi) << "Annual fuel usage"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t capacity_factor; -// ssc_data_get_number(data, "capacity_factor", &capacity_factor); -// EXPECT_NEAR(capacity_factor, 33.7597, 33.7597 * m_error_tolerance_hi) << "Capacity Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_W_cycle_gross; -// ssc_data_get_number(data, "annual_W_cycle_gross", &annual_W_cycle_gross); -// EXPECT_NEAR(annual_W_cycle_gross, 3.68433e8, 3.68433e8 * m_error_tolerance_hi) << "Annual W_cycle Gross"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t kwh_per_kw; -// ssc_data_get_number(data, "kwh_per_kw", &kwh_per_kw); -// EXPECT_NEAR(kwh_per_kw, 2957.35, 2957.35 * m_error_tolerance_hi) << "kwh per kw"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t conversion_factor; -// ssc_data_get_number(data, "conversion_factor", &conversion_factor); -// EXPECT_NEAR(conversion_factor, 83.6129, 83.6129 * m_error_tolerance_hi) << "Conversion Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t system_heat_rate; -// ssc_data_get_number(data, "system_heat_rate", &system_heat_rate); -// EXPECT_NEAR(system_heat_rate, 3.413, 3.413 * m_error_tolerance_hi) << "System heat rate"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_total_water_use; -// ssc_data_get_number(data, "annual_total_water_use", &annual_total_water_use); -// EXPECT_NEAR(annual_total_water_use, 29597.1, 29597.1 * m_error_tolerance_hi) << "Annual Total Water Use"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// } +//// HTF freeze protection mode: Electric heating +//NAMESPACE_TEST(csp_fresnel, PowerFresnelCmod, ElectricFreezeProtection_NoFinancial) +//{ +// ssc_data_t defaults = tcsfresnel_molten_salt_defaults(); +// CmodUnderTest power_fresnel = CmodUnderTest("tcsmslf", defaults); +// power_fresnel.SetInput("fp_mode", 1); +// +// int errors = power_fresnel.RunModule(); +// EXPECT_FALSE(errors); +// if (!errors) { +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_energy"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_fuel_usage"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("capacity_factor"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_W_cycle_gross"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("kwh_per_kw"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("conversion_factor"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("system_heat_rate"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_total_water_use"), 571408807, kErrorToleranceLo); +// } //} - -/// Test tcsfresnel_molten_salt with alternative storage HTF: Therminol VP-1 -/// Rest default configurations with respect to the No Financial model -//TEST_F(CMTcsFresnelMoltenSalt, Rankine_Storage_HTF_No_Financial_cmod_tcsfresnel_molten_salt) { -// -// ssc_data_t data = ssc_data_create(); -// int test_errors = tcsfresnel_molten_salt_tucson_storage_HTF(data); -// -// EXPECT_FALSE(test_errors); -// if (!test_errors) -// { -// ssc_number_t annual_energy; -// ssc_data_get_number(data, "annual_energy", &annual_energy); -// EXPECT_NEAR(annual_energy, 3.35099e8, 3.35099e8 * m_error_tolerance_hi) << "Annual Energy"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_fuel_usage; -// ssc_data_get_number(data, "annual_fuel_usage", &annual_fuel_usage); -// EXPECT_NEAR(annual_fuel_usage, 0, 0 * m_error_tolerance_hi) << "Annual fuel usage"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t capacity_factor; -// ssc_data_get_number(data, "capacity_factor", &capacity_factor); -// EXPECT_NEAR(capacity_factor, 38.2534, 38.2534 * m_error_tolerance_hi) << "Capacity Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_W_cycle_gross; -// ssc_data_get_number(data, "annual_W_cycle_gross", &annual_W_cycle_gross); -// EXPECT_NEAR(annual_W_cycle_gross, 3.72551e8, 3.72551e8 * m_error_tolerance_hi) << "Annual W_cycle Gross"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t kwh_per_kw; -// ssc_data_get_number(data, "kwh_per_kw", &kwh_per_kw); -// EXPECT_NEAR(kwh_per_kw, 3351, 3351 * m_error_tolerance_hi) << "kwh per kw"; // choose either m_error_tolerance_lo or m_error_tolerance_hi // -// ssc_number_t conversion_factor; -// ssc_data_get_number(data, "conversion_factor", &conversion_factor); -// EXPECT_NEAR(conversion_factor, 93.6951, 93.6951 * m_error_tolerance_hi) << "Conversion Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t system_heat_rate; -// ssc_data_get_number(data, "system_heat_rate", &system_heat_rate); -// EXPECT_NEAR(system_heat_rate, 3.413, 3.413 * m_error_tolerance_hi) << "System heat rate"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_total_water_use; -// ssc_data_get_number(data, "annual_total_water_use", &annual_total_water_use); -// EXPECT_NEAR(annual_total_water_use, 29869.8, 29869.8 * m_error_tolerance_hi) << "Annual Total Water Use"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// } +//// Storage HTF: Therminol VP-1 +//NAMESPACE_TEST(csp_fresnel, PowerFresnelCmod, TherminolVp1Storage_NoFinancial) +//{ +// ssc_data_t defaults = tcsfresnel_molten_salt_defaults(); +// CmodUnderTest power_fresnel = CmodUnderTest("tcsmslf", defaults); +// power_fresnel.SetInput("store_fluid", 21); +// power_fresnel.SetInput("is_hx", 1); +// power_fresnel.SetInput("V_tank_hot_ini", 1963.66443); +// power_fresnel.SetInput("vol_tank", 9818.3223); +// +// int errors = power_fresnel.RunModule(); +// EXPECT_FALSE(errors); +// if (!errors) { +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_energy"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_fuel_usage"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("capacity_factor"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_W_cycle_gross"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("kwh_per_kw"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("conversion_factor"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("system_heat_rate"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_total_water_use"), 571408807, kErrorToleranceLo); +// } //} - -/// Test tcsfresnel_molten_salt with alternative Power Cycle: User Defined -/// Rest default configurations with respect to the No Financial model -//TEST_F(CMTcsFresnelMoltenSalt, UserDefined_Default_No_Financial_cmod_tcsfresnel_molten_salt) { -// -// ssc_data_t data = ssc_data_create(); -// int test_errors = tcsfresnel_molten_salt_tucson_userdefined_default(data); -// -// EXPECT_FALSE(test_errors); -// if (!test_errors) -// { -// ssc_number_t annual_energy; -// ssc_data_get_number(data, "annual_energy", &annual_energy); -// EXPECT_NEAR(annual_energy, 3.29573e8, 3.29573e8 * m_error_tolerance_hi) << "Annual Energy"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_fuel_usage; -// ssc_data_get_number(data, "annual_fuel_usage", &annual_fuel_usage); -// EXPECT_NEAR(annual_fuel_usage, 0, 0 * m_error_tolerance_hi) << "Annual fuel usage"; // choose either m_error_tolerance_lo or m_error_tolerance_hi // -// ssc_number_t capacity_factor; -// ssc_data_get_number(data, "capacity_factor", &capacity_factor); -// EXPECT_NEAR(capacity_factor, 37.6225, 37.6225 * m_error_tolerance_hi) << "Capacity Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_W_cycle_gross; -// ssc_data_get_number(data, "annual_W_cycle_gross", &annual_W_cycle_gross); -// EXPECT_NEAR(annual_W_cycle_gross, 3.53789e8, 3.53789e8 * m_error_tolerance_hi) << "Annual W_cycle Gross"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t kwh_per_kw; -// ssc_data_get_number(data, "kwh_per_kw", &kwh_per_kw); -// EXPECT_NEAR(kwh_per_kw, 3295.73, 3295.73 * m_error_tolerance_hi) << "kwh per kw"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t conversion_factor; -// ssc_data_get_number(data, "conversion_factor", &conversion_factor); -// EXPECT_NEAR(conversion_factor, 97.0368, 97.0368 * m_error_tolerance_hi) << "Conversion Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t system_heat_rate; -// ssc_data_get_number(data, "system_heat_rate", &system_heat_rate); -// EXPECT_NEAR(system_heat_rate, 3.413, 3.413 * m_error_tolerance_hi) << "System heat rate"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_total_water_use; -// ssc_data_get_number(data, "annual_total_water_use", &annual_total_water_use); -// EXPECT_NEAR(annual_total_water_use, 2708.93, 2708.93 * m_error_tolerance_hi) << "Annual Total Water Use"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// } -//} \ No newline at end of file +//// Power Cycle: User Defined +//NAMESPACE_TEST(csp_fresnel, PowerFresnelCmod, UserDefinedPowerCycle_NoFinancial) +//{ +// ssc_data_t defaults = tcsfresnel_molten_salt_defaults(); +// CmodUnderTest power_fresnel = CmodUnderTest("tcsmslf", defaults); +// power_fresnel.SetInput("pc_config", 1); +// +// int errors = power_fresnel.RunModule(); +// EXPECT_FALSE(errors); +// if (!errors) { +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_energy"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_fuel_usage"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("capacity_factor"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_W_cycle_gross"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("kwh_per_kw"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("conversion_factor"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("system_heat_rate"), 571408807, kErrorToleranceLo); +// EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_total_water_use"), 571408807, kErrorToleranceLo); +// } +//} diff --git a/test/ssc_test/cmod_tcsfresnel_molten_salt_test.h b/test/ssc_test/cmod_tcsfresnel_molten_salt_test.h deleted file mode 100644 index 95cb1bf09fb..00000000000 --- a/test/ssc_test/cmod_tcsfresnel_molten_salt_test.h +++ /dev/null @@ -1,53 +0,0 @@ -#include - -#include "core.h" -#ifndef _CMOD_TCSFRESNEL_MOLTEN_SALT_TEST_H_ -#define _CMOD_TCSFRESNEL_MOLTEN_SALT_TEST_H_ - -#include "vartab.h" -#include "../ssc/common.h" -#include "../tcs_test/tcsfresnel_molten_salt_cases.h" - -/** - * CMTcsFresnelMoltenSalt tests the cmod_tcsfesnel_molten_salt using the SAM code generator to generate data - * Eventually a method can be written to write this data to a vartable so that lower-level methods of - * tcsfesnel_molten_salt can be tested - * For now, this uses the SSCAPI interfaces to run the compute module and compare results - */ -class CMTcsFresnelMoltenSalt : public ::testing::Test { - -public: - - ssc_data_t data; - ssc_number_t calculated_value; - ssc_number_t * calculated_array; - double m_error_tolerance_hi = 0.01; // 1.0% - double m_error_tolerance_lo = 0.001; // 0.1% - - void SetUp() - { - data = ssc_data_create(); - tcsfresnel_molten_salt_default(data); - calculated_array = new ssc_number_t[8760]; - } - void TearDown() { - if (data) { - ssc_data_free(data); - data = nullptr; - } - if (calculated_array) { - delete[] calculated_array; - } - } - void SetCalculated(std::string name) - { - ssc_data_get_number(data, const_cast(name.c_str()), &calculated_value); - } - void SetCalculatedArray(std::string name) - { - int n; - calculated_array = ssc_data_get_array(data, const_cast(name.c_str()), &n); - } -}; - -#endif // !_CMOD_TCSFRESNEL_MOLTEN_SALT_TEST_H_ diff --git a/test/ssc_test/cmod_tcsmolten_salt_test.cpp b/test/ssc_test/cmod_tcsmolten_salt_test.cpp index 25f1544fe87..48e00f90cf2 100644 --- a/test/ssc_test/cmod_tcsmolten_salt_test.cpp +++ b/test/ssc_test/cmod_tcsmolten_salt_test.cpp @@ -1,765 +1,92 @@ #include - -#include "cmod_tcsmolten_salt_test.h" -#include "../tcs_test/tcsmolten_salt_cases.h" -#include "../input_cases/weather_inputs.h" - -/// Test tcsmolten_salt with all defaults and the single owner financial model -TEST_F(CMTcsMoltenSalt, Rankine_Default_SingleOwner_cmod_tcsmolten_salt) { - - ssc_data_t data = ssc_data_create(); - int test_errors = tcsmolten_salt_daggett_default(data); - - EXPECT_FALSE(test_errors); - if (!test_errors) - { - ssc_number_t annual_energy; - ssc_data_get_number(data, "annual_energy", &annual_energy); - EXPECT_NEAR(annual_energy, 571408807.373179, 571408807.373179 * m_error_tolerance_hi) << "Annual Energy"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t land_area_base; - ssc_data_get_number(data, "land_area_base", &land_area_base); - EXPECT_NEAR(land_area_base, 1847.040000, 1847.040000 * m_error_tolerance_hi) << "Land Area Base"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t capacity_factor; - ssc_data_get_number(data, "capacity_factor", &capacity_factor); - EXPECT_NEAR(capacity_factor, 63.023494, 63.023494 * m_error_tolerance_hi) << "Capacity Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t annual_W_cycle_gross; - ssc_data_get_number(data, "annual_W_cycle_gross", &annual_W_cycle_gross); - EXPECT_NEAR(annual_W_cycle_gross, 642428580.492706, 642428580.492706 * m_error_tolerance_hi) << "Annual W_cycle Gross"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t kwh_per_kw; - ssc_data_get_number(data, "kwh_per_kw", &kwh_per_kw); - EXPECT_NEAR(kwh_per_kw, 5520.858042, 5520.858042 * m_error_tolerance_hi) << "kwh per kw"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t conversion_factor; - ssc_data_get_number(data, "conversion_factor", &conversion_factor); - EXPECT_NEAR(conversion_factor, 88.945110, 88.945110 * m_error_tolerance_hi) << "Conversion Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t N_hel; - ssc_data_get_number(data, "N_hel", &N_hel); - EXPECT_NEAR(N_hel, 8790, 8790 * m_error_tolerance_hi) << "Number of Heliostats"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t rec_height; - ssc_data_get_number(data, "rec_height", &rec_height); - EXPECT_NEAR(rec_height, 21.602900, 21.602900 * m_error_tolerance_hi) << "Rec Height"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t A_sf; - ssc_data_get_number(data, "A_sf", &A_sf); - EXPECT_NEAR(A_sf, 1269054.492000, 1269054.492000 * m_error_tolerance_hi) << "Solar Field Area"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t D_rec; - ssc_data_get_number(data, "D_rec", &D_rec); - EXPECT_NEAR(D_rec, 17.650000, 17.650000 * m_error_tolerance_hi) << "Receiver Outer Diameter"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t annual_total_water_use; - ssc_data_get_number(data, "annual_total_water_use", &annual_total_water_use); - EXPECT_NEAR(annual_total_water_use, 98221.126175, 98221.126175 * m_error_tolerance_hi) << "Annual Total Water Use"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t csp_pt_cost_total_land_area; - ssc_data_get_number(data, "csp.pt.cost.total_land_area", &csp_pt_cost_total_land_area); - EXPECT_NEAR(csp_pt_cost_total_land_area, 1892.040000, 1892.040000 * m_error_tolerance_hi) << "Total Land Area"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t h_tower; - ssc_data_get_number(data, "h_tower", &h_tower); - EXPECT_NEAR(h_tower, 193.458000, 193.458000 * m_error_tolerance_hi) << "Tower Height"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - //ssc_number_t VARIABLE; - //ssc_data_get_number(data, "VARIABLE", &VARIABLE); - //EXPECT_NEAR(VARIABLE, EXP_VAL, EXP_VAL * m_error_tolerance_hi) << "DESCRIPTION"; // choose either m_error_tolerance_lo or m_error_tolerance_hi +#include "tcsmolten_salt_defaults.h" +#include "cmod_csp_tower_eqns.h" +#include "csp_common_test.h" +#include "vs_google_test_explorer_namespace.h" + +namespace csp_tower {} +using namespace csp_tower; + +//========Tests=================================================================================== +NAMESPACE_TEST(csp_tower, PowerTowerCmod, Default_NoFinancial) +{ + ssc_data_t defaults = tcsmolten_salt_defaults(); + CmodUnderTest power_tower = CmodUnderTest("tcsmolten_salt", defaults); + int errors = power_tower.RunModule(); + EXPECT_FALSE(errors); + if (!errors) { + EXPECT_NEAR_FRAC(power_tower.GetOutput("annual_energy"), 571408807, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("land_area_base"), 1847, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("capacity_factor"), 63.02, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("annual_W_cycle_gross"), 638478912, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("kwh_per_kw"), 5521, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("conversion_factor"), 89.55, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("N_hel"), 8790, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("rec_height"), 21.60, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("A_sf"), 1269054, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("D_rec"), 17.65, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("annual_total_water_use"), 98402, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("csp.pt.cost.total_land_area"), 1892, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("h_tower"), 193.5, kErrorToleranceLo); } -} - -/// Test tcsmolten_salt with alternative turbine inlet pressure control: Sliding pressure -/// Rest default configurations with respect to the single owner financial model -TEST_F(CMTcsMoltenSalt, Rankine_Sliding_P_SingleOwner_cmod_tcsmolten_salt) { - - ssc_data_t data = ssc_data_create(); - int test_errors = tcsmolten_salt_daggett_sliding_pressure(data); - - EXPECT_FALSE(test_errors); - if (!test_errors) - { - ssc_number_t annual_energy; - ssc_data_get_number(data, "annual_energy", &annual_energy); - EXPECT_NEAR(annual_energy, 576302445.677569, 576302445.677569 * m_error_tolerance_hi) << "Annual Energy"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t land_area_base; - ssc_data_get_number(data, "land_area_base", &land_area_base); - EXPECT_NEAR(land_area_base, 1847.040000, 1847.040000 * m_error_tolerance_hi) << "Land Area Base"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t capacity_factor; - ssc_data_get_number(data, "capacity_factor", &capacity_factor); - EXPECT_NEAR(capacity_factor, 63.563237, 63.563237 * m_error_tolerance_hi) << "Capacity Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t annual_W_cycle_gross; - ssc_data_get_number(data, "annual_W_cycle_gross", &annual_W_cycle_gross); - EXPECT_NEAR(annual_W_cycle_gross, 647174668.052062, 647174668.052062 * m_error_tolerance_hi) << "Annual W_cycle Gross"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t kwh_per_kw; - ssc_data_get_number(data, "kwh_per_kw", &kwh_per_kw); - EXPECT_NEAR(kwh_per_kw, 5568.139572, 5568.139572 * m_error_tolerance_hi) << "kwh per kw"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t conversion_factor; - ssc_data_get_number(data, "conversion_factor", &conversion_factor); - EXPECT_NEAR(conversion_factor, 89.048981, 89.048981 * m_error_tolerance_hi) << "Conversion Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t N_hel; - ssc_data_get_number(data, "N_hel", &N_hel); - EXPECT_NEAR(N_hel, 8790, 8790 * m_error_tolerance_hi) << "Number of Heliostats"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t rec_height; - ssc_data_get_number(data, "rec_height", &rec_height); - EXPECT_NEAR(rec_height, 21.602900, 21.602900 * m_error_tolerance_hi) << "Rec Height"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t A_sf; - ssc_data_get_number(data, "A_sf", &A_sf); - EXPECT_NEAR(A_sf, 1269054.492000, 1269054.492000 * m_error_tolerance_hi) << "Solar Field Area"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t D_rec; - ssc_data_get_number(data, "D_rec", &D_rec); - EXPECT_NEAR(D_rec, 17.650000, 17.650000 * m_error_tolerance_hi) << "Receiver Outer Diameter"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t annual_total_water_use; - ssc_data_get_number(data, "annual_total_water_use", &annual_total_water_use); - EXPECT_NEAR(annual_total_water_use, 98238.031245, 98238.031245 * m_error_tolerance_hi) << "Annual Total Water Use"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t csp_pt_cost_total_land_area; - ssc_data_get_number(data, "csp.pt.cost.total_land_area", &csp_pt_cost_total_land_area); - EXPECT_NEAR(csp_pt_cost_total_land_area, 1892.040000, 1892.040000 * m_error_tolerance_hi) << "Total Land Area"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t h_tower; - ssc_data_get_number(data, "h_tower", &h_tower); - EXPECT_NEAR(h_tower, 193.458000, 193.458000 * m_error_tolerance_hi) << "Tower Height"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - //ssc_number_t VARIABLE; - //ssc_data_get_number(data, "VARIABLE", &VARIABLE); - //EXPECT_NEAR(VARIABLE, EXP_VAL, EXP_VAL * m_error_tolerance_hi) << "DESCRIPTION"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - } -} - -/// Test tcsmolten_salt with alternative flow pattern: Flow pattern 8 -/// Rest default configurations with respect to the single owner financial model -TEST_F(CMTcsMoltenSalt, Rankine_Flow_Pattern_SingleOwner_cmod_tcsmolten_salt) { - - ssc_data_t data = ssc_data_create(); - int test_errors = tcsmolten_salt_daggett_flow_pattern(data); - - EXPECT_FALSE(test_errors); - if (!test_errors) - { - ssc_number_t annual_energy; - ssc_data_get_number(data, "annual_energy", &annual_energy); - EXPECT_NEAR(annual_energy, 518055493.136035, 518055493.136035 * m_error_tolerance_hi) << "Annual Energy"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t land_area_base; - ssc_data_get_number(data, "land_area_base", &land_area_base); - EXPECT_NEAR(land_area_base, 1847.040000, 1847.040000 * m_error_tolerance_hi) << "Land Area Base"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t capacity_factor; - ssc_data_get_number(data, "capacity_factor", &capacity_factor); - EXPECT_NEAR(capacity_factor, 57.138894, 57.138894 * m_error_tolerance_hi) << "Capacity Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t annual_W_cycle_gross; - ssc_data_get_number(data, "annual_W_cycle_gross", &annual_W_cycle_gross); - EXPECT_NEAR(annual_W_cycle_gross, 646287965.853696, 646287965.853696 * m_error_tolerance_hi) << "Annual W_cycle Gross"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t kwh_per_kw; - ssc_data_get_number(data, "kwh_per_kw", &kwh_per_kw); - EXPECT_NEAR(kwh_per_kw, 5005.367083, 5005.367083 * m_error_tolerance_hi) << "kwh per kw"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t conversion_factor; - ssc_data_get_number(data, "conversion_factor", &conversion_factor); - EXPECT_NEAR(conversion_factor, 80.158617, 80.158617 * m_error_tolerance_hi) << "Conversion Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t N_hel; - ssc_data_get_number(data, "N_hel", &N_hel); - EXPECT_NEAR(N_hel, 8790, 8790 * m_error_tolerance_hi) << "Number of Heliostats"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t rec_height; - ssc_data_get_number(data, "rec_height", &rec_height); - EXPECT_NEAR(rec_height, 21.602900, 21.602900 * m_error_tolerance_hi) << "Rec Height"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t A_sf; - ssc_data_get_number(data, "A_sf", &A_sf); - EXPECT_NEAR(A_sf, 1269054.492000, 1269054.492000 * m_error_tolerance_hi) << "Solar Field Area"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t D_rec; - ssc_data_get_number(data, "D_rec", &D_rec); - EXPECT_NEAR(D_rec, 17.650000, 17.650000 * m_error_tolerance_hi) << "Receiver Outer Diameter"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t annual_total_water_use; - ssc_data_get_number(data, "annual_total_water_use", &annual_total_water_use); - EXPECT_NEAR(annual_total_water_use, 98470.230665, 98470.230665 * m_error_tolerance_hi) << "Annual Total Water Use"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t csp_pt_cost_total_land_area; - ssc_data_get_number(data, "csp.pt.cost.total_land_area", &csp_pt_cost_total_land_area); - EXPECT_NEAR(csp_pt_cost_total_land_area, 1892.040000, 1892.040000 * m_error_tolerance_hi) << "Total Land Area"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t h_tower; - ssc_data_get_number(data, "h_tower", &h_tower); - EXPECT_NEAR(h_tower, 193.458000, 193.458000 * m_error_tolerance_hi) << "Tower Height"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - //ssc_number_t VARIABLE; - //ssc_data_get_number(data, "VARIABLE", &VARIABLE); - //EXPECT_NEAR(VARIABLE, EXP_VAL, EXP_VAL * m_error_tolerance_hi) << "DESCRIPTION"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - } -} - -/// Testing Molten Salt Power Tower UI Equations - -TEST(Mspt_cmod_csp_tower_eqns, NoData) { - ASSERT_THROW(MSPT_System_Design_Equations(nullptr), std::runtime_error); - ASSERT_THROW(Tower_SolarPilot_Solar_Field_Equations(nullptr), std::runtime_error); - //ASSERT_THROW(MSPT_Receiver_Equations(nullptr), std::runtime_error); - //ASSERT_THROW(MSPT_System_Control_Equations(nullptr), std::runtime_error); - //ASSERT_THROW(Tower_SolarPilot_Capital_Costs_MSPT_Equations(nullptr), std::runtime_error); - //ASSERT_THROW(Tower_SolarPilot_Capital_Costs_DSPT_Equations(nullptr), std::runtime_error); - //ASSERT_THROW(Tower_SolarPilot_Capital_Costs_ISCC_Equations(nullptr), std::runtime_error); -} -//TEST(Mspt_cmod_csp_tower_eqns, MissingVariables) { -// var_table* vd = new var_table; -// ASSERT_THROW(MSPT_System_Design_Equations(vd), std::runtime_error); -// ASSERT_THROW(Tower_SolarPilot_Solar_Field_Equations(vd), std::runtime_error); -// //ASSERT_THROW(MSPT_Receiver_Equations(vd), std::runtime_error); -// //ASSERT_THROW(MSPT_System_Control_Equations(vd), std::runtime_error); -// //ASSERT_THROW(Tower_SolarPilot_Capital_Costs_MSPT_Equations(vd), std::runtime_error); -// //ASSERT_THROW(Tower_SolarPilot_Capital_Costs_DSPT_Equations(vd), std::runtime_error); -// //ASSERT_THROW(Tower_SolarPilot_Capital_Costs_ISCC_Equations(vd), std::runtime_error); -//} - -TEST(Mspt_cmod_csp_tower_eqns, Case1) { - double error_tolerance = 0.01; - var_table* vd = new var_table; - vd->assign("design_eff", 0.412); - vd->assign("gross_net_conversion_factor", 0.9); - vd->assign("P_ref", 115.); - vd->assign("solarm", 2.4); - vd->assign("tshours", 10.); - - MSPT_System_Design_Equations(vd); - - double nameplate = vd->lookup("nameplate")->num; - double q_pb_design = vd->lookup("q_pb_design")->num; - double q_rec_des = vd->lookup("q_rec_des")->num; - double tshours_sf = vd->lookup("tshours_sf")->num; - ASSERT_NEAR(nameplate, 103.5, 103.5 * error_tolerance); - ASSERT_NEAR(q_pb_design, 279., 279. * error_tolerance); - ASSERT_NEAR(q_rec_des, 670., 670. * error_tolerance); - ASSERT_NEAR(tshours_sf, 4.16667, 4.16667 * error_tolerance); -} - -TEST(Mspt_cmod_csp_tower_eqns, Case2) { - double error_tolerance = 0.01; - var_table* vd = new var_table; - vd->assign("c_atm_0", 0.006789); - vd->assign("c_atm_1", 0.1046); - vd->assign("c_atm_2", -0.017); - vd->assign("c_atm_3", 0.002845); - vd->assign("csp_pt_sf_fixed_land_area", 45.); - vd->assign("csp_pt_sf_land_overhead_factor", 1.); - vd->assign("dens_mirror", 0.97); - vd->assign("dni_des", 950.); - vd->assign("h_tower", 193.458); - vd->assign("helio_height", 12.2); - vd->assign("helio_optical_error_mrad", 1.53); - util::matrix_t helio_positions(8790, 2, 1.e3); - vd->assign("helio_positions", helio_positions); - vd->assign("helio_width", 12.2); - vd->assign("land_area_base", 1847.04); - vd->assign("land_max", 9.5); - vd->assign("land_min", 0.75); - vd->assign("override_layout", 0); - vd->assign("override_opt", 0); - vd->assign("q_rec_des", 670.); - - Tower_SolarPilot_Solar_Field_Equations(vd); - - double a_sf_ui = vd->lookup("a_sf_ui")->num; - double c_atm_info = vd->lookup("c_atm_info")->num; - double csp_pt_sf_heliostat_area = vd->lookup("csp_pt_sf_heliostat_area")->num; - double csp_pt_sf_total_land_area = vd->lookup("csp_pt_sf_total_land_area")->num; - //double csp_pt_sf_total_reflective_area = vd->lookup("csp_pt_sf_total_reflective_area")->num; // This one is not being read in the UI - double csp_pt_sf_tower_height = vd->lookup("csp_pt_sf_tower_height")->num; - double dni_des_calc = vd->lookup("dni_des_calc")->num; - double error_equiv = vd->lookup("error_equiv")->num; - double field_model_type = vd->lookup("field_model_type")->num; - double helio_area_tot = vd->lookup("helio_area_tot")->num; - double is_optimize = vd->lookup("is_optimize")->num; - double land_max_calc = vd->lookup("land_max_calc")->num; - double land_min_calc = vd->lookup("land_min_calc")->num; - double n_hel = vd->lookup("n_hel")->num; - double opt_algorithm = vd->lookup("opt_algorithm")->num; - double opt_flux_penalty = vd->lookup("opt_flux_penalty")->num; - double q_design = vd->lookup("q_design")->num; - ASSERT_NEAR(a_sf_ui, 1269055., 1269055. * error_tolerance); - ASSERT_NEAR(c_atm_info, 12.97, 12.97 * error_tolerance); - ASSERT_NEAR(csp_pt_sf_heliostat_area, 144.375, 144.375 * error_tolerance); - ASSERT_NEAR(csp_pt_sf_total_land_area, 1892., 1892. * error_tolerance); - //ASSERT_NEAR(csp_pt_sf_total_reflective_area, 1269056.25, 1269056.25 * error_tolerance); // This one is not being read in the UI - ASSERT_NEAR(csp_pt_sf_tower_height, 193.458, 193.458 * error_tolerance); - ASSERT_NEAR(dni_des_calc, 950., 950. * error_tolerance); - ASSERT_NEAR(error_equiv, 4.32749, 4.32749 * error_tolerance); - ASSERT_NEAR(field_model_type, 2., 2. * error_tolerance); - ASSERT_NEAR(helio_area_tot, 1269055., 1269055. * error_tolerance); - ASSERT_NEAR(is_optimize, 0., 0. * error_tolerance); - ASSERT_NEAR(land_max_calc, 1837.85, 1837.85 * error_tolerance); - ASSERT_NEAR(land_min_calc, 145.094, 145.094 * error_tolerance); - ASSERT_NEAR(n_hel, 8790., 8790. * error_tolerance); - ASSERT_NEAR(opt_algorithm, 1., 1. * error_tolerance); - ASSERT_NEAR(opt_flux_penalty, 0.25, 0.25 * error_tolerance); - ASSERT_NEAR(q_design, 670., 670. * error_tolerance); -} - -TEST(Mspt_cmod_csp_tower_eqns, Case2b) { - // Testing period use in variable names - double error_tolerance = 0.01; - var_table* vd = new var_table; - vd->assign("c_atm_0", 0.006789); - vd->assign("c_atm_1", 0.1046); - vd->assign("c_atm_2", -0.017); - vd->assign("c_atm_3", 0.002845); - vd->assign("csp.pt.sf.fixed_land_area", 45.); - vd->assign("csp.pt.sf.land_overhead_factor", 1.); - vd->assign("dens_mirror", 0.97); - vd->assign("dni_des", 950.); - vd->assign("h_tower", 193.458); - vd->assign("helio_height", 12.2); - vd->assign("helio_optical_error_mrad", 1.53); - util::matrix_t helio_positions(8790, 2, 1.e3); - vd->assign("helio_positions", helio_positions); - vd->assign("helio_width", 12.2); - vd->assign("land_area_base", 1847.04); - vd->assign("land_max", 9.5); - vd->assign("land_min", 0.75); - vd->assign("override_layout", 0); - vd->assign("override_opt", 0); - vd->assign("q_rec_des", 670.); - - Tower_SolarPilot_Solar_Field_Equations(vd); - - double a_sf_ui = vd->lookup("a_sf_ui")->num; - double c_atm_info = vd->lookup("c_atm_info")->num; - double csp_pt_sf_heliostat_area = vd->lookup("csp.pt.sf.heliostat_area")->num; - double csp_pt_sf_total_land_area = vd->lookup("csp.pt.sf.total_land_area")->num; - //double csp_pt_sf_total_reflective_area = vd->lookup("csp.pt.sf.total_reflective_area")->num; // This one is not being read in the UI - double csp_pt_sf_tower_height = vd->lookup("csp.pt.sf.tower_height")->num; - double dni_des_calc = vd->lookup("dni_des_calc")->num; - double error_equiv = vd->lookup("error_equiv")->num; - double field_model_type = vd->lookup("field_model_type")->num; - double helio_area_tot = vd->lookup("helio_area_tot")->num; - double is_optimize = vd->lookup("is_optimize")->num; - double land_max_calc = vd->lookup("land_max_calc")->num; - double land_min_calc = vd->lookup("land_min_calc")->num; - double n_hel = vd->lookup("n_hel")->num; - double opt_algorithm = vd->lookup("opt_algorithm")->num; - double opt_flux_penalty = vd->lookup("opt_flux_penalty")->num; - double q_design = vd->lookup("q_design")->num; - ASSERT_NEAR(a_sf_ui, 1269055., 1269055. * error_tolerance); - ASSERT_NEAR(c_atm_info, 12.97, 12.97 * error_tolerance); - ASSERT_NEAR(csp_pt_sf_heliostat_area, 144.375, 144.375 * error_tolerance); - ASSERT_NEAR(csp_pt_sf_total_land_area, 1892., 1892. * error_tolerance); - //ASSERT_NEAR(csp_pt_sf_total_reflective_area, 1269056.25, 1269056.25 * error_tolerance); // This one is not being read in the UI - ASSERT_NEAR(csp_pt_sf_tower_height, 193.458, 193.458 * error_tolerance); - ASSERT_NEAR(dni_des_calc, 950., 950. * error_tolerance); - ASSERT_NEAR(error_equiv, 4.32749, 4.32749 * error_tolerance); - ASSERT_NEAR(field_model_type, 2., 2. * error_tolerance); - ASSERT_NEAR(helio_area_tot, 1269055., 1269055. * error_tolerance); - ASSERT_NEAR(is_optimize, 0., 0. * error_tolerance); - ASSERT_NEAR(land_max_calc, 1837.85, 1837.85 * error_tolerance); - ASSERT_NEAR(land_min_calc, 145.094, 145.094 * error_tolerance); - ASSERT_NEAR(n_hel, 8790., 8790. * error_tolerance); - ASSERT_NEAR(opt_algorithm, 1., 1. * error_tolerance); - ASSERT_NEAR(opt_flux_penalty, 0.25, 0.25 * error_tolerance); - ASSERT_NEAR(q_design, 670., 670. * error_tolerance); -} - -TEST(Mspt_cmod_csp_tower_eqns, Case3) { - double error_tolerance = 0.01; - var_table* vd = new var_table; - vd->assign("t_htf_cold_des", 290.); - vd->assign("t_htf_hot_des", 574.); - vd->assign("rec_htf", 17); - vd->assign("csp_pt_rec_max_oper_frac", 1.2); - vd->assign("q_rec_des", 660.9); - vd->assign("rec_d_spec", 15.); - vd->assign("csp_pt_rec_cav_ap_hw_ratio", 1.2); - vd->assign("d_rec", 17.65); - vd->assign("rec_height", 23.8084); - vd->assign("h_tower", 193.458); - vd->assign("piping_length_mult", 2.6); - vd->assign("piping_length_const", 0.); - vd->assign("piping_loss", 10200.); - std::vector field_fluid_properties{ 1, 7, 0, 0, 0, 0, 0, 0, 0 }; - util::matrix_t field_fl_props(1, 9, &field_fluid_properties); - vd->assign("field_fl_props", field_fl_props); - - MSPT_Receiver_Equations(vd); - - double csp_pt_rec_htf_t_avg = vd->lookup("csp_pt_rec_htf_t_avg")->num; - double csp_pt_rec_htf_c_avg = vd->lookup("csp_pt_rec_htf_c_avg")->num; - double csp_pt_rec_max_flow_to_rec = vd->lookup("csp_pt_rec_max_flow_to_rec")->num; - double csp_pt_rec_cav_ap_height = vd->lookup("csp_pt_rec_cav_ap_height")->num; - double rec_aspect = vd->lookup("rec_aspect")->num; - double piping_length = vd->lookup("piping_length")->num; - double piping_loss_tot = vd->lookup("piping_loss_tot")->num; - ASSERT_NEAR(csp_pt_rec_htf_t_avg, 432., 432. * error_tolerance); - ASSERT_NEAR(csp_pt_rec_htf_c_avg, 1.5066, 1.5066 * error_tolerance); - ASSERT_NEAR(csp_pt_rec_max_flow_to_rec, 1853.5, 1853.5 * error_tolerance); - ASSERT_NEAR(csp_pt_rec_cav_ap_height, 18., 18. * error_tolerance); - ASSERT_NEAR(rec_aspect, 1.349, 1.349 * error_tolerance); - ASSERT_NEAR(piping_length, 502.991, 502.991 * error_tolerance); - ASSERT_NEAR(piping_loss_tot, 5130.51, 5130.51 * error_tolerance); -} - -TEST(Mspt_cmod_csp_tower_eqns, Case3b) { - double error_tolerance = 0.01; - var_table* vd = new var_table; - vd->assign("t_htf_cold_des", 290.); - vd->assign("t_htf_hot_des", 574.); - vd->assign("rec_htf", 17); - vd->assign("csp.pt.rec.max_oper_frac", 1.2); - vd->assign("q_rec_des", 660.9); - vd->assign("rec_d_spec", 15.); - vd->assign("csp.pt.rec.cav_ap_hw_ratio", 1.2); - vd->assign("d_rec", 17.65); - vd->assign("rec_height", 23.8084); - vd->assign("h_tower", 193.458); - vd->assign("piping_length_mult", 2.6); - vd->assign("piping_length_const", 0.); - vd->assign("piping_loss", 10200.); - std::vector field_fluid_properties{ 1, 7, 0, 0, 0, 0, 0, 0, 0 }; - util::matrix_t field_fl_props(1, 9, &field_fluid_properties); - vd->assign("field_fl_props", field_fl_props); - - MSPT_Receiver_Equations(vd); - - double csp_pt_rec_htf_t_avg = vd->lookup("csp.pt.rec.htf_t_avg")->num; - double csp_pt_rec_htf_c_avg = vd->lookup("csp.pt.rec.htf_c_avg")->num; - double csp_pt_rec_max_flow_to_rec = vd->lookup("csp.pt.rec.max_flow_to_rec")->num; - double csp_pt_rec_cav_ap_height = vd->lookup("csp.pt.rec.cav_ap_height")->num; - double rec_aspect = vd->lookup("rec_aspect")->num; - double piping_length = vd->lookup("piping_length")->num; - double piping_loss_tot = vd->lookup("piping_loss_tot")->num; - ASSERT_NEAR(csp_pt_rec_htf_t_avg, 432., 432. * error_tolerance); - ASSERT_NEAR(csp_pt_rec_htf_c_avg, 1.5066, 1.5066 * error_tolerance); - ASSERT_NEAR(csp_pt_rec_max_flow_to_rec, 1853.5, 1853.5 * error_tolerance); - ASSERT_NEAR(csp_pt_rec_cav_ap_height, 18., 18. * error_tolerance); - ASSERT_NEAR(rec_aspect, 1.349, 1.349 * error_tolerance); - ASSERT_NEAR(piping_length, 502.991, 502.991 * error_tolerance); - ASSERT_NEAR(piping_loss_tot, 5130.51, 5130.51 * error_tolerance); + //ssc_data_t defaults = singleowner_defaults(); + //CmodUnderTest singleowner = CmodUnderTest("singleowner", defaults); + //int errors = singleowner.RunModule(); + //EXPECT_FALSE(errors); + //if (!errors) { + // EXPECT_NEAR_FRAC(singleowner.GetOutput(""), , kErrorToleranceLo); + //} } -TEST(Mspt_cmod_csp_tower_eqns, Case4) { - double error_tolerance = 0.01; - ssc_data_t data = ssc_data_create(); - auto data_vtab = static_cast(data); - - data_vtab->assign("P_ref", 115.); - data_vtab->assign("design_eff", 0.412); - data_vtab->assign("tshours", 10.); - data_vtab->assign("T_htf_hot_des", 574.); - data_vtab->assign("T_htf_cold_des", 290.); - data_vtab->assign("rec_htf", 17); - std::vector field_fluid_properties{ 1, 7, 0, 0, 0, 0, 0, 0, 0 }; - util::matrix_t field_fl_props(1, 9, &field_fluid_properties); - data_vtab->assign("field_fl_props", field_fl_props); - data_vtab->assign("h_tank_min", 1.); - data_vtab->assign("h_tank", 12.); - data_vtab->assign("tank_pairs", 1.); - data_vtab->assign("u_tank", 0.4); - - int errors = run_module(data, "ui_tes_calcs"); - EXPECT_FALSE(errors); - - double q_tes = data_vtab->as_number("q_tes"); - double tes_avail_vol = data_vtab->as_number("tes_avail_vol"); - double vol_tank = data_vtab->as_number("vol_tank"); - double csp_pt_tes_tank_diameter = data_vtab->as_number("csp_pt_tes_tank_diameter"); - double q_dot_tes_est = data_vtab->as_number("q_dot_tes_est"); - double csp_pt_tes_htf_density = data_vtab->as_number("csp_pt_tes_htf_density"); - ASSERT_NEAR(q_tes, 2791.3, 2791.3 * error_tolerance); - ASSERT_NEAR(tes_avail_vol, 12986., 12986. * error_tolerance); - ASSERT_NEAR(vol_tank, 14166., 14166. * error_tolerance); - ASSERT_NEAR(csp_pt_tes_tank_diameter, 38.8, 38.8 * error_tolerance); - ASSERT_NEAR(q_dot_tes_est, 0.73, 0.73 * error_tolerance); - ASSERT_NEAR(csp_pt_tes_htf_density, 1808.48, 1808.48 * error_tolerance); -} - -TEST(Mspt_cmod_csp_tower_eqns, Case4b) { - double error_tolerance = 0.01; - ssc_data_t data = ssc_data_create(); - auto data_vtab = static_cast(data); - - data_vtab->assign("P_ref", 115.); - data_vtab->assign("design_eff", 0.412); - data_vtab->assign("tshours", 10.); - data_vtab->assign("T_htf_hot_des", 574.); - data_vtab->assign("T_htf_cold_des", 290.); - data_vtab->assign("rec_htf", 17); - std::vector field_fluid_properties{ 1, 7, 0, 0, 0, 0, 0, 0, 0 }; - util::matrix_t field_fl_props(1, 9, &field_fluid_properties); - data_vtab->assign("field_fl_props", field_fl_props); - data_vtab->assign("h_tank_min", 1.); - data_vtab->assign("h_tank", 12.); - data_vtab->assign("tank_pairs", 1.); - data_vtab->assign("u_tank", 0.4); - - int errors = run_module(data, "ui_tes_calcs"); +NAMESPACE_TEST(csp_tower, PowerTowerCmod, SlidingPressure_NoFinancial) +{ + ssc_data_t defaults = tcsmolten_salt_defaults(); + CmodUnderTest power_tower = CmodUnderTest("tcsmolten_salt", defaults); + power_tower.SetInput("tech_type", 3); // change to sliding pressure + int errors = power_tower.RunModule(); EXPECT_FALSE(errors); - - double q_tes = data_vtab->as_number("q_tes"); - double tes_avail_vol = data_vtab->as_number("tes_avail_vol"); - double vol_tank = data_vtab->as_number("vol_tank"); - double csp_pt_tes_tank_diameter = data_vtab->as_number("csp.pt.tes.tank_diameter"); - double q_dot_tes_est = data_vtab->as_number("q_dot_tes_est"); - double csp_pt_tes_htf_density = data_vtab->as_number("csp.pt.tes.htf_density"); - ASSERT_NEAR(q_tes, 2791.3, 2791.3 * error_tolerance); - ASSERT_NEAR(tes_avail_vol, 12986., 12986. * error_tolerance); - ASSERT_NEAR(vol_tank, 14166., 14166. * error_tolerance); - ASSERT_NEAR(csp_pt_tes_tank_diameter, 38.8, 38.8 * error_tolerance); - ASSERT_NEAR(q_dot_tes_est, 0.73, 0.73 * error_tolerance); - ASSERT_NEAR(csp_pt_tes_htf_density, 1808.48, 1808.48 * error_tolerance); -} - -TEST(Mspt_cmod_csp_tower_eqns, Case5) { - double error_tolerance = 0.01; - var_table* vd = new var_table; - vd->assign("bop_par", 0.); - vd->assign("bop_par_f", 1.); - vd->assign("bop_par_0", 0.); - vd->assign("bop_par_1", 0.483); - vd->assign("bop_par_2", 0.); - vd->assign("p_ref", 115.); - vd->assign("aux_par", 0.023); - vd->assign("aux_par_f", 1.); - vd->assign("aux_par_0", 0.483); - vd->assign("aux_par_1", 0.571); - vd->assign("aux_par_2", 0.); - vd->assign("disp_wlim_maxspec", 1.); - vd->assign("constant", 4.); - - MSPT_System_Control_Equations(vd); - - double csp_pt_par_calc_bop = vd->lookup("csp_pt_par_calc_bop")->num; - double csp_pt_par_calc_aux = vd->lookup("csp_pt_par_calc_aux")->num; - double disp_wlim_max = vd->lookup("disp_wlim_max")->num; - util::matrix_t wlim_series = vd->lookup("wlim_series")->num; - ASSERT_NEAR(csp_pt_par_calc_bop, 0., 0. * error_tolerance); - ASSERT_NEAR(csp_pt_par_calc_aux, 2.78783, 2.78783 * error_tolerance); - ASSERT_NEAR(disp_wlim_max, 0.96, 0.96 * error_tolerance); - ASSERT_NEAR(wlim_series.ncells(), 8760, 0.); - ASSERT_NEAR(wlim_series.at(0, 0), 960., 960. * error_tolerance); -} - -TEST(Mspt_cmod_csp_tower_eqns, Case5b) { - double error_tolerance = 0.01; - var_table* vd = new var_table; - vd->assign("bop_par", 0.); - vd->assign("bop_par_f", 1.); - vd->assign("bop_par_0", 0.); - vd->assign("bop_par_1", 0.483); - vd->assign("bop_par_2", 0.); - vd->assign("p_ref", 115.); - vd->assign("aux_par", 0.023); - vd->assign("aux_par_f", 1.); - vd->assign("aux_par_0", 0.483); - vd->assign("aux_par_1", 0.571); - vd->assign("aux_par_2", 0.); - vd->assign("disp_wlim_maxspec", 1.); - vd->assign("constant", 4.); - - MSPT_System_Control_Equations(vd); - - double csp_pt_par_calc_bop = vd->lookup("csp.pt.par.calc.bop")->num; - double csp_pt_par_calc_aux = vd->lookup("csp.pt.par.calc.aux")->num; - double disp_wlim_max = vd->lookup("disp_wlim_max")->num; - util::matrix_t wlim_series = vd->lookup("wlim_series")->num; - ASSERT_NEAR(csp_pt_par_calc_bop, 0., 0. * error_tolerance); - ASSERT_NEAR(csp_pt_par_calc_aux, 2.78783, 2.78783 * error_tolerance); - ASSERT_NEAR(disp_wlim_max, 0.96, 0.96 * error_tolerance); - ASSERT_NEAR(wlim_series.ncells(), 8760, 0.); - ASSERT_NEAR(wlim_series.at(0, 0), 960., 960. * error_tolerance); -} - -TEST(Mspt_cmod_csp_tower_eqns, Case6) { - double error_tolerance = 0.01; - var_table* vd = new var_table; - vd->assign("d_rec", 17.65); - vd->assign("rec_height", 21.60); - vd->assign("receiver_type", 0); - vd->assign("rec_d_spec", 15.); - vd->assign("csp_pt_rec_cav_ap_height", 18.); - vd->assign("p_ref", 115.); - vd->assign("design_eff", 0.412); - vd->assign("tshours", 10.); - vd->assign("demand_var", 0); - vd->assign("a_sf_ui", 1269055.); - vd->assign("site_spec_cost", 16.); - vd->assign("heliostat_spec_cost", 140.); - vd->assign("cost_sf_fixed", 0.); - vd->assign("h_tower", 193.458); - vd->assign("rec_height", 21.6029); - vd->assign("helio_height", 12.2); - vd->assign("tower_fixed_cost", 3000000.); - vd->assign("tower_exp", 0.0113); - vd->assign("csp_pt_cost_receiver_area", 1269055.); - vd->assign("rec_ref_cost", 103000000.); - vd->assign("rec_ref_area", 1571.); - vd->assign("rec_cost_exp", 0.7); - vd->assign("csp_pt_cost_storage_mwht", 2791.26); - vd->assign("tes_spec_cost", 22.); - vd->assign("csp_pt_cost_power_block_mwe", 115.); - vd->assign("plant_spec_cost", 1040.); - vd->assign("bop_spec_cost", 290.); - vd->assign("fossil_spec_cost", 0.); - vd->assign("contingency_rate", 7.); - vd->assign("csp_pt_sf_total_land_area", 1892.); - vd->assign("nameplate", 104.); - vd->assign("csp_pt_cost_epc_per_acre", 0.); - vd->assign("csp_pt_cost_epc_percent", 13.); - vd->assign("csp_pt_cost_epc_per_watt", 0.); - vd->assign("csp_pt_cost_epc_fixed", 0.); - vd->assign("land_spec_cost", 10000.); - vd->assign("csp_pt_cost_plm_percent", 0.); - vd->assign("csp_pt_cost_plm_per_watt", 0.); - vd->assign("csp_pt_cost_plm_fixed", 0.); - vd->assign("sales_tax_frac", 80.); - vd->assign("sales_tax_rate", 5.); - - Tower_SolarPilot_Capital_Costs_MSPT_Equations(vd); - - double csp_pt_cost_receiver_area = vd->lookup("csp_pt_cost_receiver_area")->num; - double csp_pt_cost_storage_mwht = vd->lookup("csp_pt_cost_storage_mwht")->num; - double csp_pt_cost_power_block_mwe = vd->lookup("csp_pt_cost_power_block_mwe")->num; - double csp_pt_cost_site_improvements = vd->lookup("csp_pt_cost_site_improvements")->num; - double csp_pt_cost_heliostats = vd->lookup("csp_pt_cost_heliostats")->num; - double csp_pt_cost_tower = vd->lookup("csp_pt_cost_tower")->num; - double csp_pt_cost_receiver = vd->lookup("csp_pt_cost_receiver")->num; - double csp_pt_cost_storage = vd->lookup("csp_pt_cost_storage")->num; - double csp_pt_cost_power_block = vd->lookup("csp_pt_cost_power_block")->num; - double csp_pt_cost_bop = vd->lookup("csp_pt_cost_bop")->num; - double csp_pt_cost_fossil = vd->lookup("csp_pt_cost_fossil")->num; - double ui_direct_subtotal = vd->lookup("ui_direct_subtotal")->num; - double csp_pt_cost_contingency = vd->lookup("csp_pt_cost_contingency")->num; - double total_direct_cost = vd->lookup("total_direct_cost")->num; - double csp_pt_cost_epc_total = vd->lookup("csp_pt_cost_epc_total")->num; - double csp_pt_cost_plm_total = vd->lookup("csp_pt_cost_plm_total")->num; - double csp_pt_cost_sales_tax_total = vd->lookup("csp_pt_cost_sales_tax_total")->num; - double total_indirect_cost = vd->lookup("total_indirect_cost")->num; - double total_installed_cost = vd->lookup("total_installed_cost")->num; - double csp_pt_cost_installed_per_capacity = vd->lookup("csp_pt_cost_installed_per_capacity")->num; - ASSERT_NEAR(csp_pt_cost_receiver_area, 1197.86, 1197.86 * error_tolerance); - ASSERT_NEAR(csp_pt_cost_storage_mwht, 2791.26, 2791.26 * error_tolerance); - ASSERT_NEAR(csp_pt_cost_power_block_mwe, 115., 115. * error_tolerance); - ASSERT_NEAR(csp_pt_cost_site_improvements, 20304872., 20304872. * error_tolerance); - ASSERT_NEAR(csp_pt_cost_heliostats, 177667632., 177667632. * error_tolerance); - ASSERT_NEAR(csp_pt_cost_tower, 25319156., 25319156. * error_tolerance); - ASSERT_NEAR(csp_pt_cost_receiver, 85191944., 85191944. * error_tolerance); - ASSERT_NEAR(csp_pt_cost_storage, 61407768., 61407768. * error_tolerance); - ASSERT_NEAR(csp_pt_cost_power_block, 119600000., 119600000. * error_tolerance); - ASSERT_NEAR(csp_pt_cost_bop, 33350000., 33350000. * error_tolerance); - ASSERT_NEAR(csp_pt_cost_fossil, 0., 0. * error_tolerance); - ASSERT_NEAR(ui_direct_subtotal, 522841376., 522841376. * error_tolerance); - ASSERT_NEAR(csp_pt_cost_contingency, 36598896., 36598896. * error_tolerance); - ASSERT_NEAR(total_direct_cost, 559440256., 559440256. * error_tolerance); - ASSERT_NEAR(csp_pt_cost_epc_total, 72727232., 72727232. * error_tolerance); - ASSERT_NEAR(csp_pt_cost_plm_total, 18920378., 18920378. * error_tolerance); - ASSERT_NEAR(csp_pt_cost_sales_tax_total, 22377610., 22377610. * error_tolerance); - ASSERT_NEAR(total_indirect_cost, 114025224., 114025224. * error_tolerance); - ASSERT_NEAR(total_installed_cost, 673465472., 673465472. * error_tolerance); - ASSERT_NEAR(csp_pt_cost_installed_per_capacity, 6506.91, 6506.91 * error_tolerance); + if (!errors) + { + EXPECT_NEAR_FRAC(power_tower.GetOutput("annual_energy"), 578111750, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("land_area_base"), 1847, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("capacity_factor"), 63.76, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("annual_W_cycle_gross"), 645396296, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("kwh_per_kw"), 5586, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("conversion_factor"), 89.57, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("N_hel"), 8790, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("rec_height"), 21.60, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("A_sf"), 1269054, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("D_rec"), 17.65, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("annual_total_water_use"), 98238, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("csp.pt.cost.total_land_area"), 1892, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("h_tower"), 193.5, kErrorToleranceLo); + } } -TEST(Mspt_cmod_csp_tower_eqns, Case6b) { - double error_tolerance = 0.01; - var_table* vd = new var_table; - vd->assign("d_rec", 17.65); - vd->assign("rec_height", 21.60); - vd->assign("receiver_type", 0); - vd->assign("rec_d_spec", 15.); - vd->assign("csp.pt.rec.cav_ap_height", 18.); - vd->assign("p_ref", 115.); - vd->assign("design_eff", 0.412); - vd->assign("tshours", 10.); - vd->assign("demand_var", 0); - vd->assign("a_sf_ui", 1269055.); - vd->assign("site_spec_cost", 16.); - vd->assign("heliostat_spec_cost", 140.); - vd->assign("cost_sf_fixed", 0.); - vd->assign("h_tower", 193.458); - vd->assign("rec_height", 21.6029); - vd->assign("helio_height", 12.2); - vd->assign("tower_fixed_cost", 3000000.); - vd->assign("tower_exp", 0.0113); - vd->assign("csp.pt.cost.receiver.area", 1269055.); - vd->assign("rec_ref_cost", 103000000.); - vd->assign("rec_ref_area", 1571.); - vd->assign("rec_cost_exp", 0.7); - vd->assign("csp.pt.cost.storage_mwht", 2791.26); - vd->assign("tes_spec_cost", 22.); - vd->assign("csp.pt.cost.power_block_mwe", 115.); - vd->assign("plant_spec_cost", 1040.); - vd->assign("bop_spec_cost", 290.); - vd->assign("fossil_spec_cost", 0.); - vd->assign("contingency_rate", 7.); - vd->assign("csp.pt.sf.total_land_area", 1892.); - vd->assign("nameplate", 104.); - vd->assign("csp.pt.cost.epc.per_acre", 0.); - vd->assign("csp.pt.cost.epc.percent", 13.); - vd->assign("csp.pt.cost.epc.per_watt", 0.); - vd->assign("csp.pt.cost.epc.fixed", 0.); - vd->assign("land_spec_cost", 10000.); - vd->assign("csp.pt.cost.plm.percent", 0.); - vd->assign("csp.pt.cost.plm.per_watt", 0.); - vd->assign("csp.pt.cost.plm.fixed", 0.); - vd->assign("sales_tax_frac", 80.); - vd->assign("sales_tax_rate", 5.); - - Tower_SolarPilot_Capital_Costs_MSPT_Equations(vd); - - double csp_pt_cost_receiver_area = vd->lookup("csp.pt.cost.receiver.area")->num; - double csp_pt_cost_storage_mwht = vd->lookup("csp.pt.cost.storage_mwht")->num; - double csp_pt_cost_power_block_mwe = vd->lookup("csp.pt.cost.power_block_mwe")->num; - double csp_pt_cost_site_improvements = vd->lookup("csp.pt.cost.site_improvements")->num; - double csp_pt_cost_heliostats = vd->lookup("csp.pt.cost.heliostats")->num; - double csp_pt_cost_tower = vd->lookup("csp.pt.cost.tower")->num; - double csp_pt_cost_receiver = vd->lookup("csp.pt.cost.receiver")->num; - double csp_pt_cost_storage = vd->lookup("csp.pt.cost.storage")->num; - double csp_pt_cost_power_block = vd->lookup("csp.pt.cost.power_block")->num; - double csp_pt_cost_bop = vd->lookup("csp.pt.cost.bop")->num; - double csp_pt_cost_fossil = vd->lookup("csp.pt.cost.fossil")->num; - double ui_direct_subtotal = vd->lookup("ui_direct_subtotal")->num; - double csp_pt_cost_contingency = vd->lookup("csp.pt.cost.contingency")->num; - double total_direct_cost = vd->lookup("total_direct_cost")->num; - double csp_pt_cost_epc_total = vd->lookup("csp.pt.cost.epc.total")->num; - double csp_pt_cost_plm_total = vd->lookup("csp.pt.cost.plm.total")->num; - double csp_pt_cost_sales_tax_total = vd->lookup("csp.pt.cost.sales_tax.total")->num; - double total_indirect_cost = vd->lookup("total_indirect_cost")->num; - double total_installed_cost = vd->lookup("total_installed_cost")->num; - double csp_pt_cost_installed_per_capacity = vd->lookup("csp.pt.cost.installed_per_capacity")->num; - ASSERT_NEAR(csp_pt_cost_receiver_area, 1197.86, 1197.86 * error_tolerance); - ASSERT_NEAR(csp_pt_cost_storage_mwht, 2791.26, 2791.26 * error_tolerance); - ASSERT_NEAR(csp_pt_cost_power_block_mwe, 115., 115. * error_tolerance); - ASSERT_NEAR(csp_pt_cost_site_improvements, 20304872., 20304872. * error_tolerance); - ASSERT_NEAR(csp_pt_cost_heliostats, 177667632., 177667632. * error_tolerance); - ASSERT_NEAR(csp_pt_cost_tower, 25319156., 25319156. * error_tolerance); - ASSERT_NEAR(csp_pt_cost_receiver, 85191944., 85191944. * error_tolerance); - ASSERT_NEAR(csp_pt_cost_storage, 61407768., 61407768. * error_tolerance); - ASSERT_NEAR(csp_pt_cost_power_block, 119600000., 119600000. * error_tolerance); - ASSERT_NEAR(csp_pt_cost_bop, 33350000., 33350000. * error_tolerance); - ASSERT_NEAR(csp_pt_cost_fossil, 0., 0. * error_tolerance); - ASSERT_NEAR(ui_direct_subtotal, 522841376., 522841376. * error_tolerance); - ASSERT_NEAR(csp_pt_cost_contingency, 36598896., 36598896. * error_tolerance); - ASSERT_NEAR(total_direct_cost, 559440256., 559440256. * error_tolerance); - ASSERT_NEAR(csp_pt_cost_epc_total, 72727232., 72727232. * error_tolerance); - ASSERT_NEAR(csp_pt_cost_plm_total, 18920378., 18920378. * error_tolerance); - ASSERT_NEAR(csp_pt_cost_sales_tax_total, 22377610., 22377610. * error_tolerance); - ASSERT_NEAR(total_indirect_cost, 114025224., 114025224. * error_tolerance); - ASSERT_NEAR(total_installed_cost, 673465472., 673465472. * error_tolerance); - ASSERT_NEAR(csp_pt_cost_installed_per_capacity, 6506.91, 6506.91 * error_tolerance); +NAMESPACE_TEST(csp_tower, PowerTowerCmod, FlowPattern_NoFinancial) +{ + ssc_data_t defaults = tcsmolten_salt_defaults(); + CmodUnderTest power_tower = CmodUnderTest("tcsmolten_salt", defaults); + power_tower.SetInput("Flow_type", 8); + int errors = power_tower.RunModule(); + EXPECT_FALSE(errors); + if (!errors) + { + EXPECT_NEAR_FRAC(power_tower.GetOutput("annual_energy"), 519995603, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("land_area_base"), 1847, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("capacity_factor"), 57.35, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("annual_W_cycle_gross"), 642716926, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("kwh_per_kw"), 5024, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("conversion_factor"), 80.90, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("N_hel"), 8790, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("rec_height"), 21.60, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("A_sf"), 1269054, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("D_rec"), 17.65, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("annual_total_water_use"), 98678, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("csp.pt.cost.total_land_area"), 1892, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("h_tower"), 193.5, kErrorToleranceLo); + } } void CopyVarTableAndGetValue(var_table* vartab, std::string var_name, double* var_value) { @@ -770,13 +97,12 @@ void CopyVarTableAndGetValue(var_table* vartab, std::string var_name, double* va return; } -TEST(Mspt_cmod_csp_tower_eqns, VarTableCopyAssignmentOperator) { +NAMESPACE_TEST(csp_tower, PowerTowerCmod, CopyingVarTable) { // Get an ssc_data_t with default input values for the molten salt tower model - ssc_data_t data = ssc_data_create(); - tcsmolten_salt_default(data); + ssc_data_t data = tcsmolten_salt_defaults(); // Verify var_tables can be copied by first converting the ssc_data_t to a var_table - var_table *vartab = static_cast(data); + var_table* vartab = static_cast(data); std::string test_variable_name = "tower_exp"; double test_value = vartab->as_double(test_variable_name); @@ -790,9 +116,8 @@ TEST(Mspt_cmod_csp_tower_eqns, VarTableCopyAssignmentOperator) { try { test_value_from_orig_table_after_copied_and_fun_returned = vartab->as_double(test_variable_name); // throws error - } - catch (std::exception& e) { + catch (...) { test_value_from_orig_table_after_copied_and_fun_returned = std::numeric_limits::quiet_NaN(); } @@ -805,404 +130,118 @@ TEST(Mspt_cmod_csp_tower_eqns, VarTableCopyAssignmentOperator) { //TEST_F(CMTcsMoltenSalt, Rankine_Evap_Condenser_SingleOwner_cmod_tcsmolten_salt) { // // ssc_data_t data = ssc_data_create(); -// int test_errors = tcsmolten_salt_daggett_evap_condenser(data); -// -// EXPECT_FALSE(test_errors); -// if (!test_errors) -// { -// ssc_number_t annual_energy; -// ssc_data_get_number(data, "annual_energy", &annual_energy); -// EXPECT_NEAR(annual_energy, 571408807.373179, 571408807.373179 * m_error_tolerance_hi) << "Annual Energy"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t land_area_base; -// ssc_data_get_number(data, "land_area_base", &land_area_base); -// EXPECT_NEAR(land_area_base, 1847.040000, 1847.040000 * m_error_tolerance_hi) << "Land Area Base"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t capacity_factor; -// ssc_data_get_number(data, "capacity_factor", &capacity_factor); -// EXPECT_NEAR(capacity_factor, 63.023494, 63.023494 * m_error_tolerance_hi) << "Capacity Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_W_cycle_gross; -// ssc_data_get_number(data, "annual_W_cycle_gross", &annual_W_cycle_gross); -// EXPECT_NEAR(annual_W_cycle_gross, 642428580.492706, 642428580.492706 * m_error_tolerance_hi) << "Annual W_cycle Gross"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t kwh_per_kw; -// ssc_data_get_number(data, "kwh_per_kw", &kwh_per_kw); -// EXPECT_NEAR(kwh_per_kw, 5520.858042, 5520.858042 * m_error_tolerance_hi) << "kwh per kw"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t conversion_factor; -// ssc_data_get_number(data, "conversion_factor", &conversion_factor); -// EXPECT_NEAR(conversion_factor, 88.945110, 88.945110 * m_error_tolerance_hi) << "Conversion Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t N_hel; -// ssc_data_get_number(data, "N_hel", &N_hel); -// EXPECT_NEAR(N_hel, 8790, 8790 * m_error_tolerance_hi) << "Number of Heliostats"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t rec_height; -// ssc_data_get_number(data, "rec_height", &rec_height); -// EXPECT_NEAR(rec_height, 21.602900, 21.602900 * m_error_tolerance_hi) << "Rec Height"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t A_sf; -// ssc_data_get_number(data, "A_sf", &A_sf); -// EXPECT_NEAR(A_sf, 1269054.492000, 1269054.492000 * m_error_tolerance_hi) << "Solar Field Area"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t D_rec; -// ssc_data_get_number(data, "D_rec", &D_rec); -// EXPECT_NEAR(D_rec, 17.650000, 17.650000 * m_error_tolerance_hi) << "Receiver Outer Diameter"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_total_water_use; -// ssc_data_get_number(data, "annual_total_water_use", &annual_total_water_use); -// EXPECT_NEAR(annual_total_water_use, 98221.126175, 98221.126175 * m_error_tolerance_hi) << "Annual Total Water Use"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t csp_pt_cost_total_land_area; -// ssc_data_get_number(data, "csp.pt.cost.total_land_area", &csp_pt_cost_total_land_area); -// EXPECT_NEAR(csp_pt_cost_total_land_area, 1892.040000, 1892.040000 * m_error_tolerance_hi) << "Total Land Area"; // choose either m_error_tolerance_lo or m_error_tolerance_hi +// ssc_data_set_number(data, "CT", 1); // -// ssc_number_t h_tower; -// ssc_data_get_number(data, "h_tower", &h_tower); -// EXPECT_NEAR(h_tower, 193.458000, 193.458000 * m_error_tolerance_hi) << "Tower Height"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// //ssc_number_t VARIABLE; -// //ssc_data_get_number(data, "VARIABLE", &VARIABLE); -// //EXPECT_NEAR(VARIABLE, EXP_VAL, EXP_VAL * m_error_tolerance_hi) << "DESCRIPTION"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// } -//} +// ... /// Test tcsmolten_salt with alternative condenser type: Hybrid /// Rest default configurations with respect to the single owner financial model //TEST_F(CMTcsMoltenSalt, Rankine_Hybrid_Condenser_SingleOwner_cmod_tcsmolten_salt) { // // ssc_data_t data = ssc_data_create(); -// int test_errors = tcsmolten_salt_daggett_hybrid_condenser(data); -// -// EXPECT_FALSE(test_errors); -// if (!test_errors) -// { -// ssc_number_t annual_energy; -// ssc_data_get_number(data, "annual_energy", &annual_energy); -// EXPECT_NEAR(annual_energy, 571408807.373179, 571408807.373179 * m_error_tolerance_hi) << "Annual Energy"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t land_area_base; -// ssc_data_get_number(data, "land_area_base", &land_area_base); -// EXPECT_NEAR(land_area_base, 1847.040000, 1847.040000 * m_error_tolerance_hi) << "Land Area Base"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t capacity_factor; -// ssc_data_get_number(data, "capacity_factor", &capacity_factor); -// EXPECT_NEAR(capacity_factor, 63.023494, 63.023494 * m_error_tolerance_hi) << "Capacity Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_W_cycle_gross; -// ssc_data_get_number(data, "annual_W_cycle_gross", &annual_W_cycle_gross); -// EXPECT_NEAR(annual_W_cycle_gross, 642428580.492706, 642428580.492706 * m_error_tolerance_hi) << "Annual W_cycle Gross"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t kwh_per_kw; -// ssc_data_get_number(data, "kwh_per_kw", &kwh_per_kw); -// EXPECT_NEAR(kwh_per_kw, 5520.858042, 5520.858042 * m_error_tolerance_hi) << "kwh per kw"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t conversion_factor; -// ssc_data_get_number(data, "conversion_factor", &conversion_factor); -// EXPECT_NEAR(conversion_factor, 88.945110, 88.945110 * m_error_tolerance_hi) << "Conversion Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t N_hel; -// ssc_data_get_number(data, "N_hel", &N_hel); -// EXPECT_NEAR(N_hel, 8790, 8790 * m_error_tolerance_hi) << "Number of Heliostats"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t rec_height; -// ssc_data_get_number(data, "rec_height", &rec_height); -// EXPECT_NEAR(rec_height, 21.602900, 21.602900 * m_error_tolerance_hi) << "Rec Height"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t A_sf; -// ssc_data_get_number(data, "A_sf", &A_sf); -// EXPECT_NEAR(A_sf, 1269054.492000, 1269054.492000 * m_error_tolerance_hi) << "Solar Field Area"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t D_rec; -// ssc_data_get_number(data, "D_rec", &D_rec); -// EXPECT_NEAR(D_rec, 17.650000, 17.650000 * m_error_tolerance_hi) << "Receiver Outer Diameter"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_total_water_use; -// ssc_data_get_number(data, "annual_total_water_use", &annual_total_water_use); -// EXPECT_NEAR(annual_total_water_use, 98221.126175, 98221.126175 * m_error_tolerance_hi) << "Annual Total Water Use"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t csp_pt_cost_total_land_area; -// ssc_data_get_number(data, "csp.pt.cost.total_land_area", &csp_pt_cost_total_land_area); -// EXPECT_NEAR(csp_pt_cost_total_land_area, 1892.040000, 1892.040000 * m_error_tolerance_hi) << "Total Land Area"; // choose either m_error_tolerance_lo or m_error_tolerance_hi +// ssc_data_set_number(data, "CT", 3); // -// ssc_number_t h_tower; -// ssc_data_get_number(data, "h_tower", &h_tower); -// EXPECT_NEAR(h_tower, 193.458000, 193.458000 * m_error_tolerance_hi) << "Tower Height"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// //ssc_number_t VARIABLE; -// //ssc_data_get_number(data, "VARIABLE", &VARIABLE); -// //EXPECT_NEAR(VARIABLE, EXP_VAL, EXP_VAL * m_error_tolerance_hi) << "DESCRIPTION"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// } -//} +// ... /// Test tcsmolten_salt with alternative condenser type: Radiative /// Rest default configurations with respect to the single owner financial model //TEST_F(CMTcsMoltenSalt, Rankine_Radiative_Condenser_SingleOwner_cmod_tcsmolten_salt) { // // ssc_data_t data = ssc_data_create(); -// int test_errors = tcsmolten_salt_daggett_radiative_condenser(data); -// -// EXPECT_FALSE(test_errors); -// if (!test_errors) -// { -// ssc_number_t annual_energy; -// ssc_data_get_number(data, "annual_energy", &annual_energy); -// EXPECT_NEAR(annual_energy, 6.11007e8, 6.11007e8 * m_error_tolerance_hi) << "Annual Energy"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t land_area_base; -// ssc_data_get_number(data, "land_area_base", &land_area_base); -// EXPECT_NEAR(land_area_base, 1847.04, 1847.04 * m_error_tolerance_hi) << "Land Area Base"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t capacity_factor; -// ssc_data_get_number(data, "capacity_factor", &capacity_factor); -// EXPECT_NEAR(capacity_factor, 67.391, 67.391 * m_error_tolerance_hi) << "Capacity Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_W_cycle_gross; -// ssc_data_get_number(data, "annual_W_cycle_gross", &annual_W_cycle_gross); -// EXPECT_NEAR(annual_W_cycle_gross, 6.68005e8, 6.68005e8 * m_error_tolerance_hi) << "Annual W_cycle Gross"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t kwh_per_kw; -// ssc_data_get_number(data, "kwh_per_kw", &kwh_per_kw); -// EXPECT_NEAR(kwh_per_kw, 5903.45, 5903.45 * m_error_tolerance_hi) << "kwh per kw"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t conversion_factor; -// ssc_data_get_number(data, "conversion_factor", &conversion_factor); -// EXPECT_NEAR(conversion_factor, 91.4676, 91.4676 * m_error_tolerance_hi) << "Conversion Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t N_hel; -// ssc_data_get_number(data, "N_hel", &N_hel); -// EXPECT_NEAR(N_hel, 8790, 8790 * m_error_tolerance_hi) << "Number of Heliostats"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t rec_height; -// ssc_data_get_number(data, "rec_height", &rec_height); -// EXPECT_NEAR(rec_height, 21.6029, 21.6029 * m_error_tolerance_hi) << "Rec Height"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t A_sf; -// ssc_data_get_number(data, "A_sf", &A_sf); -// EXPECT_NEAR(A_sf, 1.26905e6, 1.26905e6 * m_error_tolerance_hi) << "Solar Field Area"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t D_rec; -// ssc_data_get_number(data, "D_rec", &D_rec); -// EXPECT_NEAR(D_rec, 17.65, 17.65 * m_error_tolerance_hi) << "Receiver Outer Diameter"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_total_water_use; -// ssc_data_get_number(data, "annual_total_water_use", &annual_total_water_use); -// EXPECT_NEAR(annual_total_water_use, 97830.1, 97830.1 * m_error_tolerance_hi) << "Annual Total Water Use"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t csp_pt_cost_total_land_area; -// ssc_data_get_number(data, "csp.pt.cost.total_land_area", &csp_pt_cost_total_land_area); -// EXPECT_NEAR(csp_pt_cost_total_land_area, 2362.53, 2362.53 * m_error_tolerance_hi) << "Total Land Area"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t h_tower; -// ssc_data_get_number(data, "h_tower", &h_tower); -// EXPECT_NEAR(h_tower, 193.458, 193.458 * m_error_tolerance_hi) << "Tower Height"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// //ssc_number_t VARIABLE; -// //ssc_data_get_number(data, "VARIABLE", &VARIABLE); -// //EXPECT_NEAR(VARIABLE, EXP_VAL, EXP_VAL * m_error_tolerance_hi) << "DESCRIPTION"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// } -//} +// ssc_data_set_number(data, "h_ctes_tank_min", 1); +// ssc_data_set_number(data, "ctes_tshours", 15); +// ssc_data_set_number(data, "ctes_field_fl", 4); +// ssc_data_set_number(data, "h_ctes_tank", 30); +// ssc_data_set_number(data, "u_ctes_tank", 0.4); +// ssc_data_set_number(data, "ctes_tankpairs", 1); +// ssc_data_set_number(data, "T_ctes_cold_design", 5); +// ssc_data_set_number(data, "T_ctes_warm_design", 10); +// ssc_data_set_number(data, "T_ctes_warm_ini", 20); +// ssc_data_set_number(data, "T_ctes_cold_ini", 10); +// ssc_data_set_number(data, "f_ctes_warm_ini", 0); +// ssc_data_set_number(data, "rad_multiplier", 1.5); +// ssc_data_set_number(data, "m_dot_radpanel", 8); +// ssc_data_set_number(data, "n_rad_tubes", 100); +// ssc_data_set_number(data, "W_rad_tubes", 0.05); +// ssc_data_set_number(data, "L_rad", 100); +// ssc_data_set_number(data, "th_rad_panel", 0.002); +// ssc_data_set_number(data, "D_rad_tubes", 0.02); +// ssc_data_set_number(data, "k_panel", 235); +// ssc_data_set_number(data, "epsilon_radtop", 0.95); +// ssc_data_set_number(data, "epsilon_radbot", 0.07); +// ssc_data_set_number(data, "epsilon_radgrnd", 0.9); +// ssc_data_set_number(data, "L_rad_sections", 10); +// ssc_data_set_number(data, "epsilon_radHX", 0.8); +// ssc_data_set_number(data, "ctes_type", 0); +// ssc_data_set_number(data, "helio_area_tot", 1269054.5); +// ssc_data_set_number(data, "radiator_unitcost", 13); +// ssc_data_set_number(data, "radiator_installcost", 22); +// ssc_data_set_number(data, "radiator_fluidcost", 0.34); +// ssc_data_set_number(data, "radfluid_vol_ratio", 3); +// ssc_data_set_number(data, "ctes_cost", 0.7); +// ssc_data_set_number(data, "rad_pressuredrop", 75); +// ssc_data_set_number(data, "CT", 4); +// +// ... /// Test tcsmolten_salt with alternative Location: Tucson, Arizona /// Rest default configurations with respect to the single owner financial model //TEST_F(CMTcsMoltenSalt, Rankine_Location_SingleOwner_cmod_tcsmolten_salt) { // // ssc_data_t data = ssc_data_create(); -// int test_errors = tcsmolten_salt_Tucson_AZ(data); -// -// EXPECT_FALSE(test_errors); -// if (!test_errors) -// { -// ssc_number_t annual_energy; -// ssc_data_get_number(data, "annual_energy", &annual_energy); -// EXPECT_NEAR(annual_energy, 5.60538e8, 5.60538e8 * m_error_tolerance_hi) << "Annual Energy"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t land_area_base; -// ssc_data_get_number(data, "land_area_base", &land_area_base); -// EXPECT_NEAR(land_area_base, 1847.04, 1847.04 * m_error_tolerance_hi) << "Land Area Base"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t capacity_factor; -// ssc_data_get_number(data, "capacity_factor", &capacity_factor); -// EXPECT_NEAR(capacity_factor, 61.8245, 61.8245 * m_error_tolerance_hi) << "Capacity Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_W_cycle_gross; -// ssc_data_get_number(data, "annual_W_cycle_gross", &annual_W_cycle_gross); -// EXPECT_NEAR(annual_W_cycle_gross, 6.29388e8, 6.29388e8 * m_error_tolerance_hi) << "Annual W_cycle Gross"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t kwh_per_kw; -// ssc_data_get_number(data, "kwh_per_kw", &kwh_per_kw); -// EXPECT_NEAR(kwh_per_kw, 5415.83, 5415.83 * m_error_tolerance_hi) << "kwh per kw"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t conversion_factor; -// ssc_data_get_number(data, "conversion_factor", &conversion_factor); -// EXPECT_NEAR(conversion_factor, 89.0609, 89.0609 * m_error_tolerance_hi) << "Conversion Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t N_hel; -// ssc_data_get_number(data, "N_hel", &N_hel); -// EXPECT_NEAR(N_hel, 8790, 8790 * m_error_tolerance_hi) << "Number of Heliostats"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t rec_height; -// ssc_data_get_number(data, "rec_height", &rec_height); -// EXPECT_NEAR(rec_height, 21.6029, 21.6029 * m_error_tolerance_hi) << "Rec Height"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t A_sf; -// ssc_data_get_number(data, "A_sf", &A_sf); -// EXPECT_NEAR(A_sf, 1.26905e6, 1.26905e6 * m_error_tolerance_hi) << "Solar Field Area"; // choose either m_error_tolerance_lo or m_error_tolerance_hi +// char solar_resource_path_tucson[512]; +// int n = sprintf(solar_resource_path_tucson, "%s/test/input_cases/moltensalt_data/tucson_az_32.116521_-110.933042_psmv3_60_tmy.csv", std::getenv("SSCDIR")); +// ssc_data_set_string(data, "solar_resource_file", solar_resource_path_tucson); // -// ssc_number_t D_rec; -// ssc_data_get_number(data, "D_rec", &D_rec); -// EXPECT_NEAR(D_rec, 17.65, 17.65 * m_error_tolerance_hi) << "Receiver Outer Diameter"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_total_water_use; -// ssc_data_get_number(data, "annual_total_water_use", &annual_total_water_use); -// EXPECT_NEAR(annual_total_water_use, 96449.7, 96449.7 * m_error_tolerance_hi) << "Annual Total Water Use"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t csp_pt_cost_total_land_area; -// ssc_data_get_number(data, "csp.pt.cost.total_land_area", &csp_pt_cost_total_land_area); -// EXPECT_NEAR(csp_pt_cost_total_land_area, 1892.04, 1892.04 * m_error_tolerance_hi) << "Total Land Area"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t h_tower; -// ssc_data_get_number(data, "h_tower", &h_tower); -// EXPECT_NEAR(h_tower, 193.458, 193.458 * m_error_tolerance_hi) << "Tower Height"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// //ssc_number_t VARIABLE; -// //ssc_data_get_number(data, "VARIABLE", &VARIABLE); -// //EXPECT_NEAR(VARIABLE, EXP_VAL, EXP_VAL * m_error_tolerance_hi) << "DESCRIPTION"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// } -//} +// ... /// Test tcsmolten_salt with power cycle alternative: User Defined /// Rest default configurations with respect to the single owner financial model //TEST_F(CMTcsMoltenSalt, User_Defined_SingleOwner_cmod_tcsmolten_salt) { // // ssc_data_t data = ssc_data_create(); -// int test_errors = tcsmolten_salt_daggett_UD_default(data); -// -// EXPECT_FALSE(test_errors); -// if (!test_errors) -// { -// ssc_number_t annual_energy; -// ssc_data_get_number(data, "annual_energy", &annual_energy); -// EXPECT_NEAR(annual_energy, 5.9082e8, 5.9082e8 * m_error_tolerance_hi) << "Annual Energy"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t land_area_base; -// ssc_data_get_number(data, "land_area_base", &land_area_base); -// EXPECT_NEAR(land_area_base, 1847.04, 1847.04 * m_error_tolerance_hi) << "Land Area Base"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t capacity_factor; -// ssc_data_get_number(data, "capacity_factor", &capacity_factor); -// EXPECT_NEAR(capacity_factor, 65.1644, 65.1644 * m_error_tolerance_hi) << "Capacity Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_W_cycle_gross; -// ssc_data_get_number(data, "annual_W_cycle_gross", &annual_W_cycle_gross); -// EXPECT_NEAR(annual_W_cycle_gross, 6.4659e8, 6.4659e8 * m_error_tolerance_hi) << "Annual W_cycle Gross"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t kwh_per_kw; -// ssc_data_get_number(data, "kwh_per_kw", &kwh_per_kw); -// EXPECT_NEAR(kwh_per_kw, 5708.4, 5708.4 * m_error_tolerance_hi) << "kwh per kw"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t conversion_factor; -// ssc_data_get_number(data, "conversion_factor", &conversion_factor); -// EXPECT_NEAR(conversion_factor, 91.3747, 91.3747 * m_error_tolerance_hi) << "Conversion Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t N_hel; -// ssc_data_get_number(data, "N_hel", &N_hel); -// EXPECT_NEAR(N_hel, 8790, 8790 * m_error_tolerance_hi) << "Number of Heliostats"; // choose either m_error_tolerance_lo or m_error_tolerance_hi +// set_matrix(data, "ud_ind_od", ud_ind_od_path, 180, 7); +// ssc_data_set_number(data, "pc_config", 1); +// ssc_data_set_number(data, "ud_m_dot_htf_low", 0.3); +// ssc_data_set_number(data, "ud_m_dot_htf_high", 1.2); // -// ssc_number_t rec_height; -// ssc_data_get_number(data, "rec_height", &rec_height); -// EXPECT_NEAR(rec_height, 21.6029, 21.6029 * m_error_tolerance_hi) << "Rec Height"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t A_sf; -// ssc_data_get_number(data, "A_sf", &A_sf); -// EXPECT_NEAR(A_sf, 1.26905e6, 1.26905e6 * m_error_tolerance_hi) << "Solar Field Area"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t D_rec; -// ssc_data_get_number(data, "D_rec", &D_rec); -// EXPECT_NEAR(D_rec, 17.65, 17.65 * m_error_tolerance_hi) << "Receiver Outer Diameter"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_total_water_use; -// ssc_data_get_number(data, "annual_total_water_use", &annual_total_water_use); -// EXPECT_NEAR(annual_total_water_use, 55965.3, 55965.3 * m_error_tolerance_hi) << "Annual Total Water Use"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t csp_pt_cost_total_land_area; -// ssc_data_get_number(data, "csp.pt.cost.total_land_area", &csp_pt_cost_total_land_area); -// EXPECT_NEAR(csp_pt_cost_total_land_area, 1892.04, 1892.04 * m_error_tolerance_hi) << "Total Land Area"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t h_tower; -// ssc_data_get_number(data, "h_tower", &h_tower); -// EXPECT_NEAR(h_tower, 193.458, 193.458 * m_error_tolerance_hi) << "Tower Height"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// //ssc_number_t VARIABLE; -// //ssc_data_get_number(data, "VARIABLE", &VARIABLE); -// //EXPECT_NEAR(VARIABLE, EXP_VAL, EXP_VAL * m_error_tolerance_hi) << "DESCRIPTION"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// } -//} +// ... /// Test tcsmolten_salt with alternative power cycle: Super Critical CO2 /// Rest default configurations with respect to the single owner financial model //TEST_F(CMTcsMoltenSalt, SCO2_Default_SingleOwner_cmod_tcsmolten_salt) { // // ssc_data_t data = ssc_data_create(); -// int test_errors = tcsmolten_salt_daggett_SCO2_default(data); -// -// EXPECT_FALSE(test_errors); -// if (!test_errors) -// { -// ssc_number_t annual_energy; -// ssc_data_get_number(data, "annual_energy", &annual_energy); -// EXPECT_NEAR(annual_energy, 5.14776e8, 5.14776e8 * m_error_tolerance_hi) << "Annual Energy"; // choose m_error_tolerance_hi -// -// ssc_number_t land_area_base; -// ssc_data_get_number(data, "land_area_base", &land_area_base); -// EXPECT_NEAR(land_area_base, 1847.04, 1847.04 * m_error_tolerance_hi) << "Land Area Base"; -// -// ssc_number_t capacity_factor; -// ssc_data_get_number(data, "capacity_factor", &capacity_factor); -// EXPECT_NEAR(capacity_factor, 56.7772, 56.7772 * m_error_tolerance_hi) << "Capacity Factor"; // choose m_error_tolerance_hi -// -// ssc_number_t annual_W_cycle_gross; -// ssc_data_get_number(data, "annual_W_cycle_gross", &annual_W_cycle_gross); -// EXPECT_NEAR(annual_W_cycle_gross, 6.1858e8, 6.1858e8 * m_error_tolerance_hi) << "Annual W_cycle Gross"; // choose m_error_tolerance_hi -// -// ssc_number_t kwh_per_kw; -// ssc_data_get_number(data, "kwh_per_kw", &kwh_per_kw); -// EXPECT_NEAR(kwh_per_kw, 4973.68, 4973.68 * m_error_tolerance_hi) << "kwh per kw"; // choose m_error_tolerance_hi -// -// ssc_number_t conversion_factor; -// ssc_data_get_number(data, "conversion_factor", &conversion_factor); -// EXPECT_NEAR(conversion_factor, 83.219, 83.219 * m_error_tolerance_hi) << "Conversion Factor"; // choose m_error_tolerance_hi -// -// ssc_number_t N_hel; -// ssc_data_get_number(data, "N_hel", &N_hel); -// EXPECT_NEAR(N_hel, 8790, 8790 * m_error_tolerance_hi) << "Number of Heliostats"; -// -// ssc_number_t rec_height; -// ssc_data_get_number(data, "rec_height", &rec_height); -// EXPECT_NEAR(rec_height, 21.6029, 21.6029 * m_error_tolerance_hi) << "Rec Height"; -// -// ssc_number_t A_sf; -// ssc_data_get_number(data, "A_sf", &A_sf); -// EXPECT_NEAR(A_sf, 1.26905e6, 1.26905e6 * m_error_tolerance_hi) << "Solar Field Area"; -// -// ssc_number_t D_rec; -// ssc_data_get_number(data, "D_rec", &D_rec); -// EXPECT_NEAR(D_rec, 17.65, 17.65 * m_error_tolerance_hi) << "Receiver Outer Diameter"; -// -// ssc_number_t annual_total_water_use; -// ssc_data_get_number(data, "annual_total_water_use", &annual_total_water_use); -// EXPECT_NEAR(annual_total_water_use, 55965.3, 55965.3 * m_error_tolerance_hi) << "Annual Total Water Use"; -// -// ssc_number_t csp_pt_cost_total_land_area; -// ssc_data_get_number(data, "csp.pt.cost.total_land_area", &csp_pt_cost_total_land_area); -// EXPECT_NEAR(csp_pt_cost_total_land_area, 1892.04, 1892.04 * m_error_tolerance_hi) << "Total Land Area"; -// -// ssc_number_t h_tower; -// ssc_data_get_number(data, "h_tower", &h_tower); -// EXPECT_NEAR(h_tower, 193.458, 193.458 * m_error_tolerance_hi) << "Tower Height"; -// } -//} +// ssc_data_set_number(data, "is_sco2_preprocess", 1); +// +// ssc_data_set_number(data, "pc_config", 2); +// ssc_data_set_number(data, "cycle_cutoff_frac", 0.5); +// // Start of super critical CO2 metrics +// ssc_data_set_number(data, "sco2ud_T_htf_cold_calc", 406.04); +// ssc_data_set_number(data, "sco2ud_T_htf_low", 554); +// ssc_data_set_number(data, "sco2ud_T_htf_high", 589); +// ssc_data_set_number(data, "sco2ud_T_amb_high", 45); +// ssc_data_set_number(data, "sco2ud_m_dot_htf_low", 0.5); +// ssc_data_set_number(data, "sco2ud_m_dot_htf_high", 1.05); +// ssc_number_t p_sco2ud_T_htf_ind_od[65] = { 554, 0.50001432179685623, 0.96932004909372826, 0.97558944094670463, 0.56452945008574118, 0.99212119137385479, 0.9938261663184943, 0.071046760698792344, 1.0516901234966409, 1.0396677815546937, 1, 1, 1, 562.75, 0.50000677254611736, 0.98273822965810698, 0.98931005948737616, 0.55442312464765453, 0.99593839560635933, 0.99813862855158975, 0.060760248142716182, 1.0280675561194188, 1.0216094704370726, 1, 1, 1, 571.5, 0.49997035485832741, 0.99560036541912367, 1.0030665958141747, 0.54540906175814596, 0.99964495720997093, 1.0023929148428683, 0.052633463645261176, 1.0056543163255209, 1.0033307681195913, 1, 1, 1, 580.25, 0.50001678576431519, 0.99981330235493204, 1.0149012834308118, 0.53755371644427918, 0.99437061481748712, 1.0057187757624548, 0.046124783184180999, 0.93267305740289486, 0.97564080126247599, 1, 1, 1, 589, 0.49998766910986947, 0.99997642865903091, 1.0280965929880774, 0.53035396718324523, 0.98587808938966315, 1.0103635810622889, 0.040778740942652915, 0.84986379353651254, 0.96107738725047209, 1, 1, 1 }; +// ssc_data_set_matrix(data, "sco2ud_T_htf_ind_od", p_sco2ud_T_htf_ind_od, 5, 13); +// ssc_number_t p_sco2ud_T_amb_ind_od[130] = { 0, 0.99994012767121321, 0.99974326147411507, 0.99987485850649338, 0.970379288808072, 0.95027470619969945, 0.93683012616718919, 0.059164848919520591, 0.049933864673572616, 0.04548467867978704, 1, 1, 1, 5, 0.99994012767121321, 0.99974326147411507, 0.99987485850649338, 0.970379288808072, 0.95027470619969945, 0.93683012616718919, 0.097133136927079936, 0.082248959886362452, 0.075269394493921518, 1, 1, 1, 10, 0.99994012767121321, 0.99974326147411507, 0.99987485850649338, 0.970379288808072, 0.95027470619969945, 0.93683012616718919, 0.17314165365655804, 0.14726896648379706, 0.13576325670205261, 1, 1, 1, 15, 0.99994012767121321, 0.99974326147411507, 0.99987485850649338, 0.970379288808072, 0.95027470619969945, 0.93683012616718919, 0.3481506775773433, 0.29853487098289033, 0.27855988861884273, 1, 1, 1, 20, 0.99994012767121321, 0.99974326147411507, 0.99987485850649338, 0.970379288808072, 0.95027470619969945, 0.93683012616718919, 0.85719459330059711, 0.74767538224853725, 0.71410844002614948, 1, 1, 1, 25, 0.99998860165458137, 0.99998405506376475, 0.99994129487763628, 0.97834420606252215, 0.9592086954026382, 0.94639328546002388, 1.4397512132898596, 1.1099623611534934, 0.9289610766286478, 1, 1, 1, 30, 0.99997868773200105, 1.0000128744625323, 0.99987390166815182, 0.99986135777103136, 0.97846151925556812, 0.96428182700735732, 1.2885473732704416, 1.0097961360792755, 0.85212892165494525, 1, 1, 1, 35, 0.96932004909372826, 0.99995022500741981, 0.99997642865903091, 0.99212119137385479, 0.99999459906789145, 0.98587808938966315, 1.0516901234966409, 1.0033307681195913, 0.84986379353651254, 1, 1, 1, 40, 0.85681928090544024, 0.88648580427756085, 0.90755440545490784, 0.8967547597723905, 0.90655814175453875, 0.91360819421216066, 0.54638640488302492, 0.52332590711799631, 0.50841120332212841, 1, 1, 1, 45, 0.76192612755033284, 0.78992076166486025, 0.81009772614290565, 0.81887517513574226, 0.82799762047592962, 0.83504194672755783, 0.32667431104075889, 0.31463845368914112, 0.30664767313185981, 1, 1, 1 }; +// ssc_data_set_matrix(data, "sco2ud_T_amb_ind_od", p_sco2ud_T_amb_ind_od, 10, 13); +// ssc_number_t p_sco2ud_m_dot_htf_ind_od[130] = { 0.5, 0.50000238394483887, 0.50002030400496988, 0.5000072744279479, 0.49996830468452913, 0.54311461140321193, 0.58949291750771449, 0.0023965079935530688, 0.050651289208334289, 0.085268991630535099, 1, 1, 1, 0.56111111111111112, 0.56107350053341665, 0.56109752841228611, 0.56110469253490813, 0.55257347648896971, 0.59674948077268875, 0.64372698634700765, 0.0035623149303332731, 0.076089576895326735, 0.12158112224599875, 1, 1, 1, 0.62222222222222223, 0.62224697121064898, 0.62224996267725707, 0.62219761804463092, 0.60616131300962228, 0.65145619071565242, 0.69969734374588888, 0.0052256619247860641, 0.11370919032872756, 0.17234788816884622, 1, 1, 1, 0.68333333333333335, 0.68334763160686485, 0.68332772806833242, 0.68334268666386189, 0.66063755666452395, 0.70667012650879169, 0.75616720875118448, 0.0076071355040999147, 0.16722335929420953, 0.24228904960439612, 1, 1, 1, 0.74444444444444446, 0.74441099641078146, 0.74443754704645426, 0.73579757426674453, 0.7154614610083625, 0.76238207877819242, 0.80635338615523044, 0.010993657103543011, 0.24183918938496599, 0.28923568019902324, 1, 1, 1, 0.80555555555555558, 0.80548586203577432, 0.80556625128549619, 0.7607325689541361, 0.7709115279333274, 0.81874600280477805, 0.81846324371170665, 0.015863026451133713, 0.34650772248743805, 0.32712367869313513, 1, 1, 1, 0.8666666666666667, 0.86665068706416915, 0.86667726624963815, 0.77310372269008887, 0.82666048629288214, 0.87575544351530044, 0.82250334117333646, 0.022915833888653158, 0.49058181757621305, 0.32138671984149092, 1, 1, 1, 0.92777777777777781, 0.92781567340041837, 0.92781937609673271, 0.78228939831004085, 0.88241774237123771, 0.93313651551826904, 0.82559824503018264, 0.033028022568911568, 0.6869968410833619, 0.31804744512991351, 1, 1, 1, 0.98888888888888893, 0.98860321834099996, 0.98888850977399578, 0.78897052574490523, 0.93832104872570143, 0.99049121752897784, 0.82770087400040337, 0.049618846148749549, 0.94725737476210103, 0.31520682775233339, 1, 1, 1, 1.05, 1.0487348778724641, 1.0062218585376423, 0.79376542360284852, 1.0039295318936428, 1.0043865029637598, 0.82928412460314016, 0.049807927876335194, 0.99339517007581468, 0.31300940662606114, 1, 1, 1 }; +// ssc_data_set_matrix(data, "sco2ud_m_dot_htf_ind_od", p_sco2ud_m_dot_htf_ind_od, 10, 13); +// +// ssc_data_set_number(data, "_sco2_P_high_limit", 25); +// ssc_data_set_number(data, "_sco2_P_ref", 115); +// ssc_data_set_number(data, "_sco2_T_amb_des", 35); +// ssc_data_set_number(data, "_sco2_T_approach", 10); +// ssc_data_set_number(data, "_sco2_T_htf_hot_des", 574); +// ssc_data_set_number(data, "_sco2_deltaT_PHX", 20); +// ssc_data_set_number(data, "_sco2_design_eff", 0.41200000047683716); +// ssc_data_set_number(data, "_sco2_eta_c", 0.88999998569488525); +// ssc_data_set_number(data, "_sco2_eta_t", 0.89999997615814209); +// ssc_data_set_number(data, "_sco2_recup_eff_max", 0.95999997854232788); +// +// ... /// Test tcsmolten_salt with alternative power cycle: Super Critical CO2 /// Cycle Configuration alternative: Partial Cooling @@ -1210,64 +249,33 @@ TEST(Mspt_cmod_csp_tower_eqns, VarTableCopyAssignmentOperator) { //TEST_F(CMTcsMoltenSalt, SCO2_Partial_Cooling_SingleOwner_cmod_tcsmolten_salt) { // // ssc_data_t data = ssc_data_create(); -// int test_errors = tcsmolten_salt_daggett_SCO2_partial_cooling(data); -// -// EXPECT_FALSE(test_errors); -// if (!test_errors) -// { -// ssc_number_t annual_energy; -// ssc_data_get_number(data, "annual_energy", &annual_energy); -// EXPECT_NEAR(annual_energy, 5.43316e8, 5.43316e8 * m_error_tolerance_hi) << "Annual Energy"; // choose m_error_tolerance_hi -// -// ssc_number_t land_area_base; -// ssc_data_get_number(data, "land_area_base", &land_area_base); -// EXPECT_NEAR(land_area_base, 1847.04, 1847.04 * m_error_tolerance_hi) << "Land Area Base"; -// -// ssc_number_t capacity_factor; -// ssc_data_get_number(data, "capacity_factor", &capacity_factor); -// EXPECT_NEAR(capacity_factor, 59.925, 59.925 * m_error_tolerance_hi) << "Capacity Factor"; // choose m_error_tolerance_hi -// -// ssc_number_t annual_W_cycle_gross; -// ssc_data_get_number(data, "annual_W_cycle_gross", &annual_W_cycle_gross); -// EXPECT_NEAR(annual_W_cycle_gross, 6.15469e8, 6.15469e8 * m_error_tolerance_hi) << "Annual W_cycle Gross"; // choose m_error_tolerance_hi -// -// ssc_number_t kwh_per_kw; -// ssc_data_get_number(data, "kwh_per_kw", &kwh_per_kw); -// EXPECT_NEAR(kwh_per_kw, 5249.43, 5249.43 * m_error_tolerance_hi) << "kwh per kw"; // choose m_error_tolerance_hi -// -// ssc_number_t conversion_factor; -// ssc_data_get_number(data, "conversion_factor", &conversion_factor); -// EXPECT_NEAR(conversion_factor, 88.2767, 88.2767 * m_error_tolerance_hi) << "Conversion Factor"; // choose m_error_tolerance_hi -// -// ssc_number_t N_hel; -// ssc_data_get_number(data, "N_hel", &N_hel); -// EXPECT_NEAR(N_hel, 8790, 8790 * m_error_tolerance_hi) << "Number of Heliostats"; -// -// ssc_number_t rec_height; -// ssc_data_get_number(data, "rec_height", &rec_height); -// EXPECT_NEAR(rec_height, 21.6029, 21.6029 * m_error_tolerance_hi) << "Rec Height"; -// -// ssc_number_t A_sf; -// ssc_data_get_number(data, "A_sf", &A_sf); -// EXPECT_NEAR(A_sf, 1.26905e6, 1.26905e6 * m_error_tolerance_hi) << "Solar Field Area"; -// -// ssc_number_t D_rec; -// ssc_data_get_number(data, "D_rec", &D_rec); -// EXPECT_NEAR(D_rec, 17.65, 17.65 * m_error_tolerance_hi) << "Receiver Outer Diameter"; -// -// ssc_number_t annual_total_water_use; -// ssc_data_get_number(data, "annual_total_water_use", &annual_total_water_use); -// EXPECT_NEAR(annual_total_water_use, 55965.3, 55965.3 * m_error_tolerance_hi) << "Annual Total Water Use"; -// -// ssc_number_t csp_pt_cost_total_land_area; -// ssc_data_get_number(data, "csp.pt.cost.total_land_area", &csp_pt_cost_total_land_area); -// EXPECT_NEAR(csp_pt_cost_total_land_area, 1892.04, 1892.04 * m_error_tolerance_hi) << "Total Land Area"; -// -// ssc_number_t h_tower; -// ssc_data_get_number(data, "h_tower", &h_tower); -// EXPECT_NEAR(h_tower, 193.458, 193.458 * m_error_tolerance_hi) << "Tower Height"; -// } -//} +// ssc_data_set_number(data, "pc_config", 2); +// ssc_data_set_number(data, "cycle_cutoff_frac", 0.5); +// ssc_data_set_number(data, "sco2_cycle_config", 2); +// ssc_data_set_number(data, "sco2ud_T_htf_cold_calc", 354.84); +// ssc_data_set_number(data, "sco2ud_T_htf_low", 554); +// ssc_data_set_number(data, "sco2ud_T_htf_high", 589); +// ssc_data_set_number(data, "sco2ud_T_amb_high", 45); +// ssc_data_set_number(data, "sco2ud_m_dot_htf_low", 0.5); +// ssc_data_set_number(data, "sco2ud_m_dot_htf_high", 1.05); +// ssc_number_t p_sco2ud_T_htf_ind_od[65] = { 554, 0.49999352886459142, 0.96525561209463806, 0.97453395561145839, 0.62911366508823352, 0.98998074672002789, 0.99261217903413035, 0.20247797682275048, 1.0571168076843547, 1.0432895732028127, 1, 1, 1, 562.75, 0.49999364663999546, 0.98061760093183636, 0.98945608039614341, 0.59967747034505758, 0.99410410545590111, 0.99692477104310284, 0.17800016270512209, 1.0348516156853151, 1.0211725729287384, 1, 1, 1, 571.5, 0.49999395161728027, 0.99563145139446119, 1.0038535082905322, 0.58306031118146817, 0.99832427864796236, 1.001449148486844, 0.16124320857207705, 1.0092594720500885, 1.0025470111145369, 1, 1, 1, 580.25, 0.49999438710690025, 1.0000368631016281, 1.0187996347167014, 0.57310398959762909, 0.99215602847837348, 1.0059800813551822, 0.14338401700982784, 0.9341583009417217, 0.98266060214587514, 1, 1, 1, 589, 0.50001605482790912, 0.99999012779922869, 1.0325220180423378, 0.56534529941933243, 0.9816011558820481, 1.0098950333460388, 0.12932201013498895, 0.84387453074601659, 0.96199109269179472, 1, 1, 1 }; +// ssc_data_set_matrix(data, "sco2ud_T_htf_ind_od", p_sco2ud_T_htf_ind_od, 5, 13); +// ssc_number_t p_sco2ud_T_amb_ind_od[130] = { 0, 0.99997428799188914, 0.99999000874401356, 0.99999963664033542, 1.0096260890795448, 0.97647524655927898, 0.95539332954343525, 0.035964053686654389, 0.030460203665356428, 0.028191373083630726, 1, 1, 1, 5, 0.99997428799188914, 0.99999000874401356, 0.99999963664033542, 1.0096260890795448, 0.97647524655927898, 0.95539332954343525, 0.054169401117576316, 0.046164874738715223, 0.043090992060877832, 1, 1, 1, 10, 0.99997428799188914, 0.99999000874401356, 0.99999963664033542, 1.0096260890795448, 0.97647524655927898, 0.95539332954343525, 0.086054162974292386, 0.074011959990269383, 0.069988333857598825, 1, 1, 1, 15, 0.99997428799188914, 0.99999000874401356, 0.99999963664033542, 1.0096260890795448, 0.97647524655927898, 0.95539332954343525, 0.14717747411619553, 0.12834741606804084, 0.12359755317608473, 1, 1, 1, 20, 0.99997428799188914, 0.99999000874401356, 0.99999963664033542, 1.0096260890795448, 0.97647524655927898, 0.95539332954343525, 0.27882175950298732, 0.24810999613169693, 0.24587350287625651, 1, 1, 1, 25, 0.99998001476123333, 0.99998252902816598, 0.99991197104226259, 1.0098815301216097, 0.97647895095481074, 0.9554677877793778, 0.59120853683278496, 0.54403699709247888, 0.56813028411712974, 1, 1, 1, 30, 0.99998001476123333, 0.99998700539505325, 1.000003594937197, 1.0098815301216097, 0.97801555014110308, 0.95937811970467868, 1.6874663271788872, 1.1677785621376786, 0.92812586911858419, 1, 1, 1, 35, 0.96525561209463806, 0.99994365838368371, 0.99999012779922869, 0.98998074672002789, 1.0001162551906568, 0.9816011558820481, 1.0571168076843547, 1.0070553661423967, 0.84387453074601659, 1, 1, 1, 40, 0.88091956289263618, 0.91354408714037638, 0.93692898396657309, 0.92804590812890486, 0.93898338187710573, 0.94720156997882032, 0.77791598161892206, 0.7475571669584532, 0.72852820207159907, 1, 1, 1, 45, 0.80443081580069309, 0.83588054350931573, 0.85830802419616214, 0.87954062349121198, 0.89162501172294772, 0.90100255955577613, 0.71796263227634882, 0.69604875226586571, 0.68078331511457812, 1, 1, 1 }; +// ssc_data_set_matrix(data, "sco2ud_T_amb_ind_od", p_sco2ud_T_amb_ind_od, 10, 13); +// ssc_number_t p_sco2ud_m_dot_htf_ind_od[130] = { 0.5, 0.50001158587629013, 0.49999335234425468, 0.500009458086906, 0.52092523582781203, 0.580310601704488, 0.67277741730869234, 0.0066297710364970602, 0.15612995926951076, 0.42538208998154886, 1, 1, 1, 0.56111111111111112, 0.56112632572922161, 0.56109347634533013, 0.56112858298132773, 0.5676475361894191, 0.62646030027815847, 0.70338416085113653, 0.0079531402579119982, 0.18764587089730347, 0.43103981940440877, 1, 1, 1, 0.62222222222222223, 0.62221611814605471, 0.62221274231112988, 0.62222151074161314, 0.61455395777278332, 0.67446637440230506, 0.74670855688273574, 0.0093884633943930561, 0.22842611147672137, 0.48833317891759392, 1, 1, 1, 0.68333333333333335, 0.68329224890757501, 0.68333522189257412, 0.68331145370876678, 0.66231318458618582, 0.72371156880387011, 0.7949045334243946, 0.011139413945746518, 0.28028443088130395, 0.57482477745595617, 1, 1, 1, 0.74444444444444446, 0.74445060439362043, 0.74444232493970608, 0.74442697568885108, 0.71280359548337557, 0.77393932493368434, 0.84599994004797685, 0.01370986733027353, 0.34683195143613776, 0.69088300755849497, 1, 1, 1, 0.80555555555555558, 0.80554205452706595, 0.80553118613158747, 0.78568541702380978, 0.76617945177385471, 0.82545035439296532, 0.87282832981226932, 0.018334310087357693, 0.43577215265376867, 0.73125604358596707, 1, 1, 1, 0.8666666666666667, 0.86667780683097451, 0.86669111505864649, 0.80779790168115828, 0.82501645350095432, 0.8784837343548566, 0.88083521806059473, 0.031013715053052799, 0.55720344212317163, 0.71564348223866958, 1, 1, 1, 0.92777777777777781, 0.92778930075110044, 0.92781165563938151, 0.82346900197673678, 0.89420782417679856, 0.9332817335240674, 0.88681855363756823, 0.030225663571636099, 0.72555609695067691, 0.70381015654357315, 1, 1, 1, 0.98888888888888893, 0.98891033574992371, 0.98886027855958214, 0.8342986400696234, 0.96400610586573099, 0.98968856703989938, 0.89098743214344123, 0.030057676976388854, 0.95810218483069376, 0.69690700803894567, 1, 1, 1, 1.05, 1.0499204736064125, 1.0082881287098067, 0.84167433259869806, 1.0322051570968707, 1.002564506765949, 0.89389762859965882, 0.034640376520654041, 0.99538596406341329, 0.69252556580813951, 1, 1, 1 }; +// ssc_data_set_matrix(data, "sco2ud_m_dot_htf_ind_od", p_sco2ud_m_dot_htf_ind_od, 10, 13); +// ssc_data_set_number(data, "_sco2_P_high_limit", 25); +// ssc_data_set_number(data, "_sco2_P_ref", 115); +// ssc_data_set_number(data, "_sco2_T_amb_des", 35); +// ssc_data_set_number(data, "_sco2_T_approach", 10); +// ssc_data_set_number(data, "_sco2_T_htf_hot_des", 574); +// ssc_data_set_number(data, "_sco2_deltaT_PHX", 20); +// ssc_data_set_number(data, "_sco2_design_eff", 0.412); +// ssc_data_set_number(data, "_sco2_eta_c", 0.89); +// ssc_data_set_number(data, "_sco2_eta_t", 0.9); +// ssc_data_set_number(data, "_sco2_recup_eff_max", 0.96); +// +// ... /// Test tcsmolten_salt with alternative power cycle: Super Critical CO2 /// Materials and Flow alternative: Flow pattern 2 instead of 1 @@ -1275,68 +283,139 @@ TEST(Mspt_cmod_csp_tower_eqns, VarTableCopyAssignmentOperator) { //TEST_F(CMTcsMoltenSalt, SCO2_Flow_Pattern_Alternative_SingleOwner_cmod_tcsmolten_salt) { // // ssc_data_t data = ssc_data_create(); -// int test_errors = tcsmolten_salt_daggett_SCO2_flow_pattern_2(data); -// -// EXPECT_FALSE(test_errors); -// if (!test_errors) -// { -// ssc_number_t annual_energy; -// ssc_data_get_number(data, "annual_energy", &annual_energy); -// EXPECT_NEAR(annual_energy, 5.15291e8, 5.15291e8 * m_error_tolerance_hi) << "Annual Energy"; // choose m_error_tolerance_hi -// -// ssc_number_t land_area_base; -// ssc_data_get_number(data, "land_area_base", &land_area_base); -// EXPECT_NEAR(land_area_base, 1847.04, 1847.04 * m_error_tolerance_hi) << "Land Area Base"; -// -// ssc_number_t capacity_factor; -// ssc_data_get_number(data, "capacity_factor", &capacity_factor); -// EXPECT_NEAR(capacity_factor, 56.834, 56.834 * m_error_tolerance_hi) << "Capacity Factor"; // choose m_error_tolerance_hi -// -// ssc_number_t annual_W_cycle_gross; -// ssc_data_get_number(data, "annual_W_cycle_gross", &annual_W_cycle_gross); -// EXPECT_NEAR(annual_W_cycle_gross, 6.19302e8, 6.19302e8 * m_error_tolerance_hi) << "Annual W_cycle Gross"; // choose m_error_tolerance_hi -// -// ssc_number_t kwh_per_kw; -// ssc_data_get_number(data, "kwh_per_kw", &kwh_per_kw); -// EXPECT_NEAR(kwh_per_kw, 4978.66, 4978.66 * m_error_tolerance_hi) << "kwh per kw"; // choose m_error_tolerance_hi -// -// ssc_number_t conversion_factor; -// ssc_data_get_number(data, "conversion_factor", &conversion_factor); -// EXPECT_NEAR(conversion_factor, 83.7374, 83.7374 * m_error_tolerance_hi) << "Conversion Factor"; // choose m_error_tolerance_hi -// -// ssc_number_t N_hel; -// ssc_data_get_number(data, "N_hel", &N_hel); -// EXPECT_NEAR(N_hel, 8790, 8790 * m_error_tolerance_hi) << "Number of Heliostats"; -// -// ssc_number_t rec_height; -// ssc_data_get_number(data, "rec_height", &rec_height); -// EXPECT_NEAR(rec_height, 21.6029, 21.6029 * m_error_tolerance_hi) << "Rec Height"; -// -// ssc_number_t A_sf; -// ssc_data_get_number(data, "A_sf", &A_sf); -// EXPECT_NEAR(A_sf, 1.26905e6, 1.26905e6 * m_error_tolerance_hi) << "Solar Field Area"; -// -// ssc_number_t D_rec; -// ssc_data_get_number(data, "D_rec", &D_rec); -// EXPECT_NEAR(D_rec, 17.65, 17.65 * m_error_tolerance_hi) << "Receiver Outer Diameter"; -// -// ssc_number_t annual_total_water_use; -// ssc_data_get_number(data, "annual_total_water_use", &annual_total_water_use); -// EXPECT_NEAR(annual_total_water_use, 55965.3, 55965.3 * m_error_tolerance_hi) << "Annual Total Water Use"; -// -// ssc_number_t csp_pt_cost_total_land_area; -// ssc_data_get_number(data, "csp.pt.cost.total_land_area", &csp_pt_cost_total_land_area); -// EXPECT_NEAR(csp_pt_cost_total_land_area, 1892.04, 1892.04 * m_error_tolerance_hi) << "Total Land Area"; -// -// ssc_number_t h_tower; -// ssc_data_get_number(data, "h_tower", &h_tower); -// EXPECT_NEAR(h_tower, 193.458, 193.458 * m_error_tolerance_hi) << "Tower Height"; -// } -//} +// ssc_data_set_number(data, "Flow_type", 2); +// ssc_data_set_number(data, "pc_config", 2); +// ssc_data_set_number(data, "cycle_cutoff_frac", 0.5); +// +// // Start of super critical CO2 metrics +// ssc_data_set_number(data, "sco2ud_T_htf_cold_calc", 406.04); +// ssc_data_set_number(data, "sco2ud_T_htf_low", 554); +// ssc_data_set_number(data, "sco2ud_T_htf_high", 589); +// ssc_data_set_number(data, "sco2ud_T_amb_high", 45); +// ssc_data_set_number(data, "sco2ud_m_dot_htf_low", 0.5); +// ssc_data_set_number(data, "sco2ud_m_dot_htf_high", 1.05); +// ssc_number_t p_sco2ud_T_htf_ind_od[65] = { 554, 0.50001432179685623, 0.96932004909372826, 0.97558944094670463, 0.56452945008574118, 0.99212119137385479, 0.9938261663184943, 0.071046760698792344, 1.0516901234966409, 1.0396677815546937, 1, 1, 1, 562.75, 0.50000677254611736, 0.98273822965810698, 0.98931005948737616, 0.55442312464765453, 0.99593839560635933, 0.99813862855158975, 0.060760248142716182, 1.0280675561194188, 1.0216094704370726, 1, 1, 1, 571.5, 0.49997035485832741, 0.99560036541912367, 1.0030665958141747, 0.54540906175814596, 0.99964495720997093, 1.0023929148428683, 0.052633463645261176, 1.0056543163255209, 1.0033307681195913, 1, 1, 1, 580.25, 0.50001678576431519, 0.99981330235493204, 1.0149012834308118, 0.53755371644427918, 0.99437061481748712, 1.0057187757624548, 0.046124783184180999, 0.93267305740289486, 0.97564080126247599, 1, 1, 1, 589, 0.49998766910986947, 0.99997642865903091, 1.0280965929880774, 0.53035396718324523, 0.98587808938966315, 1.0103635810622889, 0.040778740942652915, 0.84986379353651254, 0.96107738725047209, 1, 1, 1 }; +// ssc_data_set_matrix(data, "sco2ud_T_htf_ind_od", p_sco2ud_T_htf_ind_od, 5, 13); +// ssc_number_t p_sco2ud_T_amb_ind_od[130] = { 0, 0.99994012767121321, 0.99974326147411507, 0.99987485850649338, 0.970379288808072, 0.95027470619969945, 0.93683012616718919, 0.059164848919520591, 0.049933864673572616, 0.04548467867978704, 1, 1, 1, 5, 0.99994012767121321, 0.99974326147411507, 0.99987485850649338, 0.970379288808072, 0.95027470619969945, 0.93683012616718919, 0.097133136927079936, 0.082248959886362452, 0.075269394493921518, 1, 1, 1, 10, 0.99994012767121321, 0.99974326147411507, 0.99987485850649338, 0.970379288808072, 0.95027470619969945, 0.93683012616718919, 0.17314165365655804, 0.14726896648379706, 0.13576325670205261, 1, 1, 1, 15, 0.99994012767121321, 0.99974326147411507, 0.99987485850649338, 0.970379288808072, 0.95027470619969945, 0.93683012616718919, 0.3481506775773433, 0.29853487098289033, 0.27855988861884273, 1, 1, 1, 20, 0.99994012767121321, 0.99974326147411507, 0.99987485850649338, 0.970379288808072, 0.95027470619969945, 0.93683012616718919, 0.85719459330059711, 0.74767538224853725, 0.71410844002614948, 1, 1, 1, 25, 0.99998860165458137, 0.99998405506376475, 0.99994129487763628, 0.97834420606252215, 0.9592086954026382, 0.94639328546002388, 1.4397512132898596, 1.1099623611534934, 0.9289610766286478, 1, 1, 1, 30, 0.99997868773200105, 1.0000128744625323, 0.99987390166815182, 0.99986135777103136, 0.97846151925556812, 0.96428182700735732, 1.2885473732704416, 1.0097961360792755, 0.85212892165494525, 1, 1, 1, 35, 0.96932004909372826, 0.99995022500741981, 0.99997642865903091, 0.99212119137385479, 0.99999459906789145, 0.98587808938966315, 1.0516901234966409, 1.0033307681195913, 0.84986379353651254, 1, 1, 1, 40, 0.85681928090544024, 0.88648580427756085, 0.90755440545490784, 0.8967547597723905, 0.90655814175453875, 0.91360819421216066, 0.54638640488302492, 0.52332590711799631, 0.50841120332212841, 1, 1, 1, 45, 0.76192612755033284, 0.78992076166486025, 0.81009772614290565, 0.81887517513574226, 0.82799762047592962, 0.83504194672755783, 0.32667431104075889, 0.31463845368914112, 0.30664767313185981, 1, 1, 1 }; +// ssc_data_set_matrix(data, "sco2ud_T_amb_ind_od", p_sco2ud_T_amb_ind_od, 10, 13); +// ssc_number_t p_sco2ud_m_dot_htf_ind_od[130] = { 0.5, 0.50000238394483887, 0.50002030400496988, 0.5000072744279479, 0.49996830468452913, 0.54311461140321193, 0.58949291750771449, 0.0023965079935530688, 0.050651289208334289, 0.085268991630535099, 1, 1, 1, 0.56111111111111112, 0.56107350053341665, 0.56109752841228611, 0.56110469253490813, 0.55257347648896971, 0.59674948077268875, 0.64372698634700765, 0.0035623149303332731, 0.076089576895326735, 0.12158112224599875, 1, 1, 1, 0.62222222222222223, 0.62224697121064898, 0.62224996267725707, 0.62219761804463092, 0.60616131300962228, 0.65145619071565242, 0.69969734374588888, 0.0052256619247860641, 0.11370919032872756, 0.17234788816884622, 1, 1, 1, 0.68333333333333335, 0.68334763160686485, 0.68332772806833242, 0.68334268666386189, 0.66063755666452395, 0.70667012650879169, 0.75616720875118448, 0.0076071355040999147, 0.16722335929420953, 0.24228904960439612, 1, 1, 1, 0.74444444444444446, 0.74441099641078146, 0.74443754704645426, 0.73579757426674453, 0.7154614610083625, 0.76238207877819242, 0.80635338615523044, 0.010993657103543011, 0.24183918938496599, 0.28923568019902324, 1, 1, 1, 0.80555555555555558, 0.80548586203577432, 0.80556625128549619, 0.7607325689541361, 0.7709115279333274, 0.81874600280477805, 0.81846324371170665, 0.015863026451133713, 0.34650772248743805, 0.32712367869313513, 1, 1, 1, 0.8666666666666667, 0.86665068706416915, 0.86667726624963815, 0.77310372269008887, 0.82666048629288214, 0.87575544351530044, 0.82250334117333646, 0.022915833888653158, 0.49058181757621305, 0.32138671984149092, 1, 1, 1, 0.92777777777777781, 0.92781567340041837, 0.92781937609673271, 0.78228939831004085, 0.88241774237123771, 0.93313651551826904, 0.82559824503018264, 0.033028022568911568, 0.6869968410833619, 0.31804744512991351, 1, 1, 1, 0.98888888888888893, 0.98860321834099996, 0.98888850977399578, 0.78897052574490523, 0.93832104872570143, 0.99049121752897784, 0.82770087400040337, 0.049618846148749549, 0.94725737476210103, 0.31520682775233339, 1, 1, 1, 1.05, 1.0487348778724641, 1.0062218585376423, 0.79376542360284852, 1.0039295318936428, 1.0043865029637598, 0.82928412460314016, 0.049807927876335194, 0.99339517007581468, 0.31300940662606114, 1, 1, 1 }; +// ssc_data_set_matrix(data, "sco2ud_m_dot_htf_ind_od", p_sco2ud_m_dot_htf_ind_od, 10, 13); +// +// ... /// Test series of Advanced Combinatorial Testing System (ACTS) runs //TEST_F(CMTcsMoltenSalt, ACTS_sCO2_recompression) { // +// Molten Salt power tower - Super-critical CO2 power cycle +// ACTS framework driven testing +//int ACTS_sCO2_testing(ssc_data_t &data, int test_case) +//{ +// tcsmolten_salt_default(data); +// +// //ssc_data_set_number(data, "T_htf_cold_des", 414.53549194335938); // Different values each run ... But have no effect on outputs +// +// ssc_data_set_number(data, "pc_config", 2); +// +// ssc_data_set_number(data, "cycle_cutoff_frac", 0.5); +// +// //ssc_data_set_number(data, "sco2ud_T_htf_cold_calc", 414.53549194335938); // Different values each run ... But have no effect on outputs +// ssc_data_set_number(data, "sco2ud_T_htf_low", 554); +// ssc_data_set_number(data, "sco2ud_T_htf_high", 589); +// +// ssc_data_set_number(data, "sco2ud_T_amb_high", 45); +// ssc_data_set_number(data, "sco2ud_m_dot_htf_low", 0.5); +// ssc_data_set_number(data, "sco2ud_m_dot_htf_high", 1.05); +// ssc_number_t p_sco2ud_T_htf_ind_od[65] = { 554, 0.50001432179685623, 0.96932004909372826, 0.97558944094670463, 0.56452945008574118, 0.99212119137385479, 0.9938261663184943, 0.071046760698792344, 1.0516901234966409, 1.0396677815546937, 1, 1, 1, 562.75, 0.50000677254611736, 0.98273822965810698, 0.98931005948737616, 0.55442312464765453, 0.99593839560635933, 0.99813862855158975, 0.060760248142716182, 1.0280675561194188, 1.0216094704370726, 1, 1, 1, 571.5, 0.49997035485832741, 0.99560036541912367, 1.0030665958141747, 0.54540906175814596, 0.99964495720997093, 1.0023929148428683, 0.052633463645261176, 1.0056543163255209, 1.0033307681195913, 1, 1, 1, 580.25, 0.50001678576431519, 0.99981330235493204, 1.0149012834308118, 0.53755371644427918, 0.99437061481748712, 1.0057187757624548, 0.046124783184180999, 0.93267305740289486, 0.97564080126247599, 1, 1, 1, 589, 0.49998766910986947, 0.99997642865903091, 1.0280965929880774, 0.53035396718324523, 0.98587808938966315, 1.0103635810622889, 0.040778740942652915, 0.84986379353651254, 0.96107738725047209, 1, 1, 1 }; +// ssc_data_set_matrix(data, "sco2ud_T_htf_ind_od", p_sco2ud_T_htf_ind_od, 5, 13); +// ssc_number_t p_sco2ud_T_amb_ind_od[130] = { 0, 0.99994012767121321, 0.99974326147411507, 0.99987485850649338, 0.970379288808072, 0.95027470619969945, 0.93683012616718919, 0.059164848919520591, 0.049933864673572616, 0.04548467867978704, 1, 1, 1, 5, 0.99994012767121321, 0.99974326147411507, 0.99987485850649338, 0.970379288808072, 0.95027470619969945, 0.93683012616718919, 0.097133136927079936, 0.082248959886362452, 0.075269394493921518, 1, 1, 1, 10, 0.99994012767121321, 0.99974326147411507, 0.99987485850649338, 0.970379288808072, 0.95027470619969945, 0.93683012616718919, 0.17314165365655804, 0.14726896648379706, 0.13576325670205261, 1, 1, 1, 15, 0.99994012767121321, 0.99974326147411507, 0.99987485850649338, 0.970379288808072, 0.95027470619969945, 0.93683012616718919, 0.3481506775773433, 0.29853487098289033, 0.27855988861884273, 1, 1, 1, 20, 0.99994012767121321, 0.99974326147411507, 0.99987485850649338, 0.970379288808072, 0.95027470619969945, 0.93683012616718919, 0.85719459330059711, 0.74767538224853725, 0.71410844002614948, 1, 1, 1, 25, 0.99998860165458137, 0.99998405506376475, 0.99994129487763628, 0.97834420606252215, 0.9592086954026382, 0.94639328546002388, 1.4397512132898596, 1.1099623611534934, 0.9289610766286478, 1, 1, 1, 30, 0.99997868773200105, 1.0000128744625323, 0.99987390166815182, 0.99986135777103136, 0.97846151925556812, 0.96428182700735732, 1.2885473732704416, 1.0097961360792755, 0.85212892165494525, 1, 1, 1, 35, 0.96932004909372826, 0.99995022500741981, 0.99997642865903091, 0.99212119137385479, 0.99999459906789145, 0.98587808938966315, 1.0516901234966409, 1.0033307681195913, 0.84986379353651254, 1, 1, 1, 40, 0.85681928090544024, 0.88648580427756085, 0.90755440545490784, 0.8967547597723905, 0.90655814175453875, 0.91360819421216066, 0.54638640488302492, 0.52332590711799631, 0.50841120332212841, 1, 1, 1, 45, 0.76192612755033284, 0.78992076166486025, 0.81009772614290565, 0.81887517513574226, 0.82799762047592962, 0.83504194672755783, 0.32667431104075889, 0.31463845368914112, 0.30664767313185981, 1, 1, 1 }; +// ssc_data_set_matrix(data, "sco2ud_T_amb_ind_od", p_sco2ud_T_amb_ind_od, 10, 13); +// ssc_number_t p_sco2ud_m_dot_htf_ind_od[130] = { 0.5, 0.50000238394483887, 0.50002030400496988, 0.5000072744279479, 0.49996830468452913, 0.54311461140321193, 0.58949291750771449, 0.0023965079935530688, 0.050651289208334289, 0.085268991630535099, 1, 1, 1, 0.56111111111111112, 0.56107350053341665, 0.56109752841228611, 0.56110469253490813, 0.55257347648896971, 0.59674948077268875, 0.64372698634700765, 0.0035623149303332731, 0.076089576895326735, 0.12158112224599875, 1, 1, 1, 0.62222222222222223, 0.62224697121064898, 0.62224996267725707, 0.62219761804463092, 0.60616131300962228, 0.65145619071565242, 0.69969734374588888, 0.0052256619247860641, 0.11370919032872756, 0.17234788816884622, 1, 1, 1, 0.68333333333333335, 0.68334763160686485, 0.68332772806833242, 0.68334268666386189, 0.66063755666452395, 0.70667012650879169, 0.75616720875118448, 0.0076071355040999147, 0.16722335929420953, 0.24228904960439612, 1, 1, 1, 0.74444444444444446, 0.74441099641078146, 0.74443754704645426, 0.73579757426674453, 0.7154614610083625, 0.76238207877819242, 0.80635338615523044, 0.010993657103543011, 0.24183918938496599, 0.28923568019902324, 1, 1, 1, 0.80555555555555558, 0.80548586203577432, 0.80556625128549619, 0.7607325689541361, 0.7709115279333274, 0.81874600280477805, 0.81846324371170665, 0.015863026451133713, 0.34650772248743805, 0.32712367869313513, 1, 1, 1, 0.8666666666666667, 0.86665068706416915, 0.86667726624963815, 0.77310372269008887, 0.82666048629288214, 0.87575544351530044, 0.82250334117333646, 0.022915833888653158, 0.49058181757621305, 0.32138671984149092, 1, 1, 1, 0.92777777777777781, 0.92781567340041837, 0.92781937609673271, 0.78228939831004085, 0.88241774237123771, 0.93313651551826904, 0.82559824503018264, 0.033028022568911568, 0.6869968410833619, 0.31804744512991351, 1, 1, 1, 0.98888888888888893, 0.98860321834099996, 0.98888850977399578, 0.78897052574490523, 0.93832104872570143, 0.99049121752897784, 0.82770087400040337, 0.049618846148749549, 0.94725737476210103, 0.31520682775233339, 1, 1, 1, 1.05, 1.0487348778724641, 1.0062218585376423, 0.79376542360284852, 1.0039295318936428, 1.0043865029637598, 0.82928412460314016, 0.049807927876335194, 0.99339517007581468, 0.31300940662606114, 1, 1, 1 }; +// ssc_data_set_matrix(data, "sco2ud_m_dot_htf_ind_od", p_sco2ud_m_dot_htf_ind_od, 10, 13); +// // sco2 default configuration preprocessing parameters +// ssc_data_set_number(data, "_sco2_P_high_limit", 25); +// ssc_data_set_number(data, "_sco2_P_ref", 115); +// ssc_data_set_number(data, "_sco2_T_amb_des", 35); +// ssc_data_set_number(data, "_sco2_T_approach", 10); +// ssc_data_set_number(data, "_sco2_T_htf_hot_des", 574); +// ssc_data_set_number(data, "_sco2_deltaT_PHX", 20); +// ssc_data_set_number(data, "_sco2_design_eff", 0.412); +// ssc_data_set_number(data, "_sco2_eta_c", 0.89); +// ssc_data_set_number(data, "_sco2_eta_t", 0.9); +// ssc_data_set_number(data, "_sco2_recup_eff_max", 0.96); +// +// // Testing level to vector index map +// std::unordered_map idx = +// { +// {-1, 0}, +// { 0, 1}, +// { 1, 2} +// }; +// +// // Parameter test range values +// std::vector sco2_T_amb_des_vals{ 20.98, 35, 60 }; // Ambient temperature at design // SAM SSC - "sco2_T_amb_des" +// std::vector sco2_T_approach_vals{ 1, 10, 30 }; // Air cooler aproach temperature // SAM SSC - "sco2_T_approach" +// std::vector deltaT_PHX_vals{ 1, 20, 50 }; // PHX approach temperature // SAM SSC - "deltaT_PHX" +// std::vector eta_c_vals{ 0.70, 0.89, 1.0 }; // Compressor(s) Isentropic efficiency // SAM SSC - "eta_c" +// std::vector eta_t_vals{ 0.70, 0.90, 1.0 }; // Turbine Isentropic efficiency // SAM SSC - "eta_t" +// std::vector fan_power_perc_net_vals{ 0.25, 1.5, 5 }; // Cooling fan electricity consumption // SAM SSC - "fan_power_perc_net" +// +// // Full ACTS sCO2 framework - 15 total tests, where 6/15 tests are actually able to simulate on the SAM UI +// +// // Test case pass/fail summary 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 +// // P = Pass & F = Fail in SAM UI F P F P P F P F F F F P F F P +// // std::vector sco2_T_amb_des_lvls{ -1, -1, -1, 0, 0, 0, 1, 1, 1, -1, 0, 1, 1, -1, 1 }; +// // std::vector sco2_T_approach_lvls{ -1, 0, 1, -1, 0, 1, -1, 0, 1, -1, 0, 0, 1, -1, 1 }; +// // std::vector deltaT_PHX_lvls{ 0, 1, -1, 1, -1, 0, -1, 0, 1, 0, 1, -1, 1, -1, 0 }; +// // std::vector eta_c_lvls{ 0, 1, -1, -1, 0, 1, 1, -1, 0, 0, 1, 1, -1, 1, 1 }; +// // std::vector eta_t_lvls{ 0, 1, -1, 0, 1, -1, 0, 1, -1, -1, -1, 0, 0, 1, 1 }; +// // std::vector fan_power_perc_net_lvls{ 0, 1, -1, 1, -1, 0, -1, 0, 1, -1, -1 , 0, 0, 1, 1 }; +// +// +// // Passing ACTS sco2 tests within the SAM UI +// // NOTE: +// // Certain tests are able to completely pass the unit tests +// // using high tolerances while some tests still are +// // unable to pass using the high tolerances when testing outputs +// +// // Unit test case pass/fall summary 2 4 5 7 12 15 +// // P = Pass & F = Fail for tested outputs F F P P P F +// // std::vector sco2_T_amb_des_lvls{ -1, 0, 0, 1, 1, 1 }; +// // std::vector sco2_T_approach_lvls{ 0, -1, 0, -1, 0, 1 }; +// // std::vector deltaT_PHX_lvls{ 1, 1, -1, -1, -1, 0 }; +// // std::vector eta_c_lvls{ 1, -1, 0, 1, 1, 1 }; +// // std::vector eta_t_lvls{ 1, 0, 1, 0, 0, 1 }; +// // std::vector fan_power_perc_net_lvls{ 1, 1, 1, -1, 0, 1 }; +// +// +// // Passing SAM UI configurations 5 7 12 +// // P = Pass & F = Fail for tested outputs P P P +// std::vector sco2_T_amb_des_lvls{ 0, 1, 1 }; +// std::vector sco2_T_approach_lvls{ 0, -1, 0 }; +// std::vector deltaT_PHX_lvls{ -1, -1, -1 }; +// std::vector eta_c_lvls{ 0, 1, 1 }; +// std::vector eta_t_lvls{ 1, 0, 0 }; +// std::vector fan_power_perc_net_lvls{ 1, -1, 0 }; +// +// // Get test case values from index +// double sco2_T_amb_des_ACTS = sco2_T_amb_des_vals.at(idx.find(sco2_T_amb_des_lvls.at(test_case))->second); +// double sco2_T_approach_ACTS = sco2_T_approach_vals.at(idx.find(sco2_T_approach_lvls.at(test_case))->second); +// double deltaT_PHX_ACTS = deltaT_PHX_vals.at(idx.find(deltaT_PHX_lvls.at(test_case))->second); +// double eta_c_ACTS = eta_c_vals.at(idx.find(eta_c_lvls.at(test_case))->second); +// double eta_t_ACTS = eta_t_vals.at(idx.find(eta_t_lvls.at(test_case))->second); +// double fan_power_perc_net_ACTS = fan_power_perc_net_vals.at(idx.find(fan_power_perc_net_lvls.at(test_case))->second); +// +// // Assigning values to variables +// ssc_data_set_number(data, "sco2_T_amb_des", sco2_T_amb_des_ACTS); +// ssc_data_set_number(data, "sco2_T_approach", sco2_T_approach_ACTS); +// ssc_data_set_number(data, "deltaT_PHX", deltaT_PHX_ACTS); +// ssc_data_set_number(data, "eta_c", eta_c_ACTS); +// ssc_data_set_number(data, "eta_t", eta_t_ACTS); +// ssc_data_set_number(data, "fan_power_perc_net", fan_power_perc_net_ACTS); +// +// int status = run_module(data, "tcsmolten_salt"); +// +// return status; +//} // // Outputs of 6/15 total ACTS tests for the sCO2 model // // The other 9 test case scenarios were unable to simulate properly // // on the SAM UI. diff --git a/test/ssc_test/cmod_tcsmolten_salt_test.h b/test/ssc_test/cmod_tcsmolten_salt_test.h deleted file mode 100644 index fd293c5dd2a..00000000000 --- a/test/ssc_test/cmod_tcsmolten_salt_test.h +++ /dev/null @@ -1,54 +0,0 @@ -#include - -#include "core.h" -#ifndef _CMOD_TCSMOLTEN_SALT_TEST_H_ -#define _CMOD_TCSMOLTEN_SALT_TEST_H_ - -#include "vartab.h" -#include "../ssc/common.h" -#include "../tcs_test/tcsmolten_salt_cases.h" -#include "cmod_csp_tower_eqns.h" - -/** - * CMtcsMoltenSalt tests the cmod_tcsmolten_salt using the SAM code generator to generate data - * Eventually a method can be written to write this data to a vartable so that lower-level methods of - * tcsmolten_salt can be tested - * For now, this uses the SSCAPI interfaces to run the compute module and compare results - */ -class CMTcsMoltenSalt : public ::testing::Test{ - -public: - - ssc_data_t data; - ssc_number_t calculated_value; - ssc_number_t * calculated_array; - double m_error_tolerance_hi = 0.01; // 1.0% - double m_error_tolerance_lo = 0.001; // 0.1% - - void SetUp() - { - data = ssc_data_create(); - tcsmolten_salt_default(data); - calculated_array = new ssc_number_t[8760]; - } - void TearDown() { - if (data) { - ssc_data_free(data); - data = nullptr; - } - if (calculated_array) { - delete[] calculated_array; - } - } - void SetCalculated(std::string name) - { - ssc_data_get_number(data, const_cast(name.c_str()), &calculated_value); - } - void SetCalculatedArray(std::string name) - { - int n; - calculated_array = ssc_data_get_array(data, const_cast(name.c_str()), &n); - } -}; - -#endif // !_CMOD_TCSMOLTEN_SALT_TEST_H_ diff --git a/test/ssc_test/cmod_tcstrough_empirical_test.cpp b/test/ssc_test/cmod_tcstrough_empirical_test.cpp index 21a877fd7ed..ba5e008d12a 100644 --- a/test/ssc_test/cmod_tcstrough_empirical_test.cpp +++ b/test/ssc_test/cmod_tcstrough_empirical_test.cpp @@ -1,373 +1,278 @@ #include - -#include "cmod_tcstrough_empirical_test.h" -#include "../tcs_test/tcstrough_empirical_cases.h" -#include "../input_cases/weather_inputs.h" - -/// Test tcstrough_empirical with all defaults with respect to the No Financial model -TEST_F(CMTcsTroughEmpirical, TroughEmpirical_Default_No_Financial_cmod_tcstrough_empirical) { - - ssc_data_t data = ssc_data_create(); - int test_errors = tcstrough_empirical_tucson_default(data); - - EXPECT_FALSE(test_errors); - if (!test_errors) - { - ssc_number_t annual_energy; - ssc_data_get_number(data, "annual_energy", &annual_energy); - EXPECT_NEAR(annual_energy, 3.44335e8, 3.44335e8 * m_error_tolerance_hi) << "Annual Energy"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t annual_fuel_usage; - ssc_data_get_number(data, "annual_fuel_usage", &annual_fuel_usage); - EXPECT_NEAR(annual_fuel_usage, 0, 0 * m_error_tolerance_hi) << "Annual fuel usage"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t capacity_factor; - ssc_data_get_number(data, "capacity_factor", &capacity_factor); - EXPECT_NEAR(capacity_factor, 39.347, 39.347 * m_error_tolerance_hi) << "Capacity Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t annual_W_cycle_gross; - ssc_data_get_number(data, "annual_W_cycle_gross", &annual_W_cycle_gross); - EXPECT_NEAR(annual_W_cycle_gross, 4.04116e8, 4.04116e8 * m_error_tolerance_hi) << "Annual W_cycle Gross"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t kwh_per_kw; - ssc_data_get_number(data, "kwh_per_kw", &kwh_per_kw); - EXPECT_NEAR(kwh_per_kw, 3446.8, 3446.8 * m_error_tolerance_hi) << "kwh per kw"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t conversion_factor; - ssc_data_get_number(data, "conversion_factor", &conversion_factor); - EXPECT_NEAR(conversion_factor, 88.7574, 88.7574 * m_error_tolerance_hi) << "Conversion Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t system_heat_rate; - ssc_data_get_number(data, "system_heat_rate", &system_heat_rate); - EXPECT_NEAR(system_heat_rate, 3.413, 3.413 * m_error_tolerance_hi) << "System heat rate"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t system_use_lifetime_output; - ssc_data_get_number(data, "system_use_lifetime_output", &system_use_lifetime_output); - EXPECT_NEAR(system_use_lifetime_output, 0, 0 * m_error_tolerance_hi) << "Use lifetime output"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - } +#include "tcstrough_empirical_defaults.h" +#include "csp_common_test.h" +#include "vs_google_test_explorer_namespace.h" + +namespace csp_trough {} +using namespace csp_trough; + +//========Tests=================================================================================== +NAMESPACE_TEST(csp_trough, EmpiricalTroughCmod, Default_NoFinancial) +{ + ssc_data_t defaults = tcstrough_empirical_defaults(); + CmodUnderTest empirical_trough = CmodUnderTest("tcstrough_empirical", defaults); + int errors = empirical_trough.RunModule(); + EXPECT_FALSE(errors); + if (!errors) { + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_energy"), 344049128, kErrorToleranceLo); + EXPECT_NEAR(empirical_trough.GetOutput("annual_fuel_usage"), 0., kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("capacity_factor"), 39.31, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_W_cycle_gross"), 403814011, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("kwh_per_kw"), 3444, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("conversion_factor"), 88.75, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("system_heat_rate"), 3.413, kErrorToleranceLo); + EXPECT_NEAR(empirical_trough.GetOutput("system_use_lifetime_output"), 0., kErrorToleranceLo); + } } -/// Test tcstrough_empirical with alternative Solar Field HTF type: Hitec Solar Salt -/// Rest default configurations with respect to the No Financial model -TEST_F(CMTcsTroughEmpirical, TroughEmpirical_Solar_Field_HTF_No_Financial_cmod_tcstrough_empirical) { - - ssc_data_t data = ssc_data_create(); - int test_errors = tcstrough_empirical_tucson_solar_field_HTF(data); - - EXPECT_FALSE(test_errors); - if (!test_errors) - { - ssc_number_t annual_energy; - ssc_data_get_number(data, "annual_energy", &annual_energy); - EXPECT_NEAR(annual_energy, 3.40714e8, 3.40714e8 * m_error_tolerance_hi) << "Annual Energy"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t annual_fuel_usage; - ssc_data_get_number(data, "annual_fuel_usage", &annual_fuel_usage); - EXPECT_NEAR(annual_fuel_usage, 0, 0 * m_error_tolerance_hi) << "Annual fuel usage"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t capacity_factor; - ssc_data_get_number(data, "capacity_factor", &capacity_factor); - EXPECT_NEAR(capacity_factor, 38.9332, 38.9332 * m_error_tolerance_hi) << "Capacity Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t annual_W_cycle_gross; - ssc_data_get_number(data, "annual_W_cycle_gross", &annual_W_cycle_gross); - EXPECT_NEAR(annual_W_cycle_gross, 3.9992e8, 3.9992e8 * m_error_tolerance_hi) << "Annual W_cycle Gross"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t kwh_per_kw; - ssc_data_get_number(data, "kwh_per_kw", &kwh_per_kw); - EXPECT_NEAR(kwh_per_kw, 3410.55, 3410.55 * m_error_tolerance_hi) << "kwh per kw"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t conversion_factor; - ssc_data_get_number(data, "conversion_factor", &conversion_factor); - EXPECT_NEAR(conversion_factor, 88.7454, 88.7454 * m_error_tolerance_hi) << "Conversion Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t system_heat_rate; - ssc_data_get_number(data, "system_heat_rate", &system_heat_rate); - EXPECT_NEAR(system_heat_rate, 3.413, 3.413 * m_error_tolerance_hi) << "System heat rate"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t system_use_lifetime_output; - ssc_data_get_number(data, "system_use_lifetime_output", &system_use_lifetime_output); - EXPECT_NEAR(system_use_lifetime_output, 0, 0 * m_error_tolerance_hi) << "Use lifetime output"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - } +// Alternative solar field HTF type: Hitec Solar Salt +NAMESPACE_TEST(csp_trough, EmpiricalTroughCmod, SolarSaltHtf_NoFinancial) +{ + ssc_data_t defaults = tcstrough_empirical_defaults(); + CmodUnderTest empirical_trough = CmodUnderTest("tcstrough_empirical", defaults); + empirical_trough.SetInput("HTFFluid", 18); + empirical_trough.SetInput("PTSmax", 676.471); + empirical_trough.SetInput("PFSmax", 342.699); + + int errors = empirical_trough.RunModule(); + EXPECT_FALSE(errors); + if (!errors) { + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_energy"), 340377809, kErrorToleranceLo); + EXPECT_NEAR(empirical_trough.GetOutput("annual_fuel_usage"), 0., kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("capacity_factor"), 38.89, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_W_cycle_gross"), 399556634, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("kwh_per_kw"), 3407, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("conversion_factor"), 88.74, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("system_heat_rate"), 3.413, kErrorToleranceLo); + EXPECT_NEAR(empirical_trough.GetOutput("system_use_lifetime_output"), 0., kErrorToleranceLo); + } } -/// Passed with m_error_tolerance_hi used for: -/// annual_W_cycle_gross & conversion_factor & kwh_per_kw - -/// Test tcstrough_empirical with alternative Solar Collector Assembly (SCA): EuroTrough ET150 -/// Rest default configurations with respect to the No Financial model -TEST_F(CMTcsTroughEmpirical, TroughEmpirical_SCA_No_Financial_cmod_tcstrough_empirical) { - - ssc_data_t data = ssc_data_create(); - int test_errors = tcstrough_empirical_tucson_SCA(data); - - EXPECT_FALSE(test_errors); - if (!test_errors) - { - ssc_number_t annual_energy; - ssc_data_get_number(data, "annual_energy", &annual_energy); - EXPECT_NEAR(annual_energy, 3.44114e8, 3.44114e8 * m_error_tolerance_hi) << "Annual Energy"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t annual_fuel_usage; - ssc_data_get_number(data, "annual_fuel_usage", &annual_fuel_usage); - EXPECT_NEAR(annual_fuel_usage, 0, 0 * m_error_tolerance_hi) << "Annual fuel usage"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t capacity_factor; - ssc_data_get_number(data, "capacity_factor", &capacity_factor); - EXPECT_NEAR(capacity_factor, 39.3217, 39.3217 * m_error_tolerance_hi) << "Capacity Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t annual_W_cycle_gross; - ssc_data_get_number(data, "annual_W_cycle_gross", &annual_W_cycle_gross); - EXPECT_NEAR(annual_W_cycle_gross, 4.03352e8, 4.03352e8 * m_error_tolerance_hi) << "Annual W_cycle Gross"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t kwh_per_kw; - ssc_data_get_number(data, "kwh_per_kw", &kwh_per_kw); - EXPECT_NEAR(kwh_per_kw, 3444.58, 3444.58 * m_error_tolerance_hi) << "kwh per kw"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t conversion_factor; - ssc_data_get_number(data, "conversion_factor", &conversion_factor); - EXPECT_NEAR(conversion_factor, 88.8683, 88.8683 * m_error_tolerance_hi) << "Conversion Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t system_heat_rate; - ssc_data_get_number(data, "system_heat_rate", &system_heat_rate); - EXPECT_NEAR(system_heat_rate, 3.413, 3.413 * m_error_tolerance_hi) << "System heat rate"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t system_use_lifetime_output; - ssc_data_get_number(data, "system_use_lifetime_output", &system_use_lifetime_output); - EXPECT_NEAR(system_use_lifetime_output, 0, 0 * m_error_tolerance_hi) << "Use lifetime output"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - } +// Alternative solar collector assembly (SCA): EuroTrough ET150 +NAMESPACE_TEST(csp_trough, EmpiricalTroughCmod, EuroTrough_NoFinancial) +{ + ssc_data_t defaults = tcstrough_empirical_defaults(); + CmodUnderTest empirical_trough = CmodUnderTest("tcstrough_empirical", defaults); + empirical_trough.SetInput("Solar_Field_Area", 856740); + empirical_trough.SetInput("Ave_Focal_Length", 2.1); + empirical_trough.SetInput("ScaLen", 150); + empirical_trough.SetInput("SCA_aper", 5.75); + empirical_trough.SetInput("TrkTwstErr", 0.99); + empirical_trough.SetInput("MirCln", 0.97); + empirical_trough.SetInput("HCEdust", { 0.98, 0.98, 0.98, 0.98 }); + empirical_trough.SetInput("RefMirrAper", { 5.75, 5.75, 5.75, 5.75 }); + empirical_trough.SetInput("SfPar", 0.228); + empirical_trough.SetInput("ChtfPar", 9.013); + empirical_trough.SetInput("AntiFrPar", 0.9013); + + int errors = empirical_trough.RunModule(); + EXPECT_FALSE(errors); + if (!errors) { + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_energy"), 343687390, kErrorToleranceLo); + EXPECT_NEAR(empirical_trough.GetOutput("annual_fuel_usage"), 0., kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("capacity_factor"), 39.27, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_W_cycle_gross"), 402926405, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("kwh_per_kw"), 3440, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("conversion_factor"), 88.85, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("system_heat_rate"), 3.413, kErrorToleranceLo); + EXPECT_NEAR(empirical_trough.GetOutput("system_use_lifetime_output"), 0., kErrorToleranceLo); + } } -/// Passed with m_error_tolerance_hi used for: -/// conversion_factor - -/// Test tcstrough_empirical with alternative Heat Collection Element (HCE): Luz Cermet Vacuum, Luz Cermet Hydrogren, and Luz Cermet Broken Glass -/// Rest default configurations with respect to the No Financial model -TEST_F(CMTcsTroughEmpirical, TroughEmpirical_HCE_No_Financial_cmod_tcstrough_empirical) { - - ssc_data_t data = ssc_data_create(); - int test_errors = tcstrough_empirical_tucson_HCE(data); - - EXPECT_FALSE(test_errors); - if (!test_errors) - { - ssc_number_t annual_energy; - ssc_data_get_number(data, "annual_energy", &annual_energy); - EXPECT_NEAR(annual_energy, 3.11168e8, 3.11168e8 * m_error_tolerance_hi) << "Annual Energy"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t annual_fuel_usage; - ssc_data_get_number(data, "annual_fuel_usage", &annual_fuel_usage); - EXPECT_NEAR(annual_fuel_usage, 0, 0 * m_error_tolerance_hi) << "Annual fuel usage"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t capacity_factor; - ssc_data_get_number(data, "capacity_factor", &capacity_factor); - EXPECT_NEAR(capacity_factor, 35.557, 35.557 * m_error_tolerance_hi) << "Capacity Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t annual_W_cycle_gross; - ssc_data_get_number(data, "annual_W_cycle_gross", &annual_W_cycle_gross); - EXPECT_NEAR(annual_W_cycle_gross, 3.69939e8, 3.69939e8 * m_error_tolerance_hi) << "Annual W_cycle Gross"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t kwh_per_kw; - ssc_data_get_number(data, "kwh_per_kw", &kwh_per_kw); - EXPECT_NEAR(kwh_per_kw, 3114.8, 3114.8 * m_error_tolerance_hi) << "kwh per kw"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t conversion_factor; - ssc_data_get_number(data, "conversion_factor", &conversion_factor); - EXPECT_NEAR(conversion_factor, 87.618, 87.618 * m_error_tolerance_hi) << "Conversion Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t system_heat_rate; - ssc_data_get_number(data, "system_heat_rate", &system_heat_rate); - EXPECT_NEAR(system_heat_rate, 3.413, 3.413 * m_error_tolerance_hi) << "System heat rate"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t system_use_lifetime_output; - ssc_data_get_number(data, "system_use_lifetime_output", &system_use_lifetime_output); - EXPECT_NEAR(system_use_lifetime_output, 0, 0 * m_error_tolerance_hi) << "Use lifetime output"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - } +// Alternative heat collection element (HCE): Luz Cermet Vacuum, Luz Cermet Hydrogren, and Luz Cermet Broken Glass +NAMESPACE_TEST(csp_trough, EmpiricalTroughCmod, LuzCermetHce_NoFinancial) +{ + ssc_data_t defaults = tcstrough_empirical_defaults(); + CmodUnderTest empirical_trough = CmodUnderTest("tcstrough_empirical", defaults); + empirical_trough.SetInput("Solar_Field_Area", 1015848); + empirical_trough.SetInput("HCEBelShad", { 0.971, 0.971, 0.971, 0 }); + empirical_trough.SetInput("HCEEnvTrans", { 0.935, 0.935, 1, 0 }); + empirical_trough.SetInput("HCEabs", { 0.925, 0.925, 0.8, 0 }); + empirical_trough.SetInput("PerfFac", { 1.25, 1.25, 1.25, 0 }); + empirical_trough.SetInput("HCE_A0", { 2.424, 7.0233, 100.05, 0 }); + empirical_trough.SetInput("HCE_A1", { 0.214, 1.275, -0.7351, 0 }); + empirical_trough.SetInput("HCE_A2", { -0.00047461, 0.0015105, -0.008635, 0 }); + empirical_trough.SetInput("HCE_A3", { 6.88e-06, 5.05e-06, 2.67e-05, 0 }); + empirical_trough.SetInput("HCE_A4", { 9.62e-08, 7.03e-08, 6.65e-07, 0 }); + empirical_trough.SetInput("HCE_A5", { -2.2423, -4.284, -99.043, 0 }); + empirical_trough.SetInput("HCE_A6", { 0.032325, 0.39685, 5.1672, 0 }); + empirical_trough.SetInput("SfPar", 0.270); + empirical_trough.SetInput("ChtfPar", 10.687); + empirical_trough.SetInput("AntiFrPar", 1.069); + + int errors = empirical_trough.RunModule(); + EXPECT_FALSE(errors); + if (!errors) { + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_energy"), 310891768, kErrorToleranceLo); + EXPECT_NEAR(empirical_trough.GetOutput("annual_fuel_usage"), 0., kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("capacity_factor"), 35.53, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_W_cycle_gross"), 369630914, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("kwh_per_kw"), 3112, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("conversion_factor"), 87.61, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("system_heat_rate"), 3.413, kErrorToleranceLo); + EXPECT_NEAR(empirical_trough.GetOutput("system_use_lifetime_output"), 0., kErrorToleranceLo); + } } -/// Test tcstrough_empirical with alternative Power Cycle: APS Ormat 1MWe 300C -/// Rest default configurations with respect to the No Financial model -TEST_F(CMTcsTroughEmpirical, TroughEmpirical_Power_Cycle_No_Financial_cmod_tcstrough_empirical) { - - ssc_data_t data = ssc_data_create(); - int test_errors = tcstrough_empirical_tucson_power_cycle(data); - - EXPECT_FALSE(test_errors); - if (!test_errors) - { - ssc_number_t annual_energy; - ssc_data_get_number(data, "annual_energy", &annual_energy); - EXPECT_NEAR(annual_energy, 3.5066e8, 3.5066e8 * m_error_tolerance_hi) << "Annual Energy"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t annual_fuel_usage; - ssc_data_get_number(data, "annual_fuel_usage", &annual_fuel_usage); - EXPECT_NEAR(annual_fuel_usage, 0, 0 * m_error_tolerance_hi) << "Annual fuel usage"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t capacity_factor; - ssc_data_get_number(data, "capacity_factor", &capacity_factor); - EXPECT_NEAR(capacity_factor, 40.0698, 40.0698 * m_error_tolerance_hi) << "Capacity Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t annual_W_cycle_gross; - ssc_data_get_number(data, "annual_W_cycle_gross", &annual_W_cycle_gross); - EXPECT_NEAR(annual_W_cycle_gross, 4.27665e8, 4.27665e8 * m_error_tolerance_hi) << "Annual W_cycle Gross"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t kwh_per_kw; - ssc_data_get_number(data, "kwh_per_kw", &kwh_per_kw); - EXPECT_NEAR(kwh_per_kw, 3510.11, 3510.11 * m_error_tolerance_hi) << "kwh per kw"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t conversion_factor; - ssc_data_get_number(data, "conversion_factor", &conversion_factor); - EXPECT_NEAR(conversion_factor, 85.4106, 85.4106 * m_error_tolerance_hi) << "Conversion Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t system_heat_rate; - ssc_data_get_number(data, "system_heat_rate", &system_heat_rate); - EXPECT_NEAR(system_heat_rate, 3.413, 3.413 * m_error_tolerance_hi) << "System heat rate"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t system_use_lifetime_output; - ssc_data_get_number(data, "system_use_lifetime_output", &system_use_lifetime_output); - EXPECT_NEAR(system_use_lifetime_output, 0, 0 * m_error_tolerance_hi) << "Use lifetime output"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - } +// Alternative power cycle: APS Ormat 1MWe 300C +NAMESPACE_TEST(csp_trough, EmpiricalTroughCmod, PowerCycle_NoFinancial) +{ + ssc_data_t defaults = tcstrough_empirical_defaults(); + CmodUnderTest empirical_trough = CmodUnderTest("tcstrough_empirical", defaults); + empirical_trough.SetInput("Solar_Field_Area", 1599020); + empirical_trough.SetInput("TurbEffG", 0.2071); + empirical_trough.SetInput("TurSUE", 0.05); + empirical_trough.SetInput("T2EPLF0", -0.1594); + empirical_trough.SetInput("T2EPLF1", 0.9262); + empirical_trough.SetInput("T2EPLF2", 1.1349); + empirical_trough.SetInput("T2EPLF3", -1.3606); + empirical_trough.SetInput("T2EPLF4", 0.4588); + empirical_trough.SetInput("E2TPLF0", 0.1492); + empirical_trough.SetInput("E2TPLF1", 0.8522); + empirical_trough.SetInput("E2TPLF2", -0.3247); + empirical_trough.SetInput("E2TPLF3", 0.44863); + empirical_trough.SetInput("E2TPLF4", -0.1256); + empirical_trough.SetInput("TempCorrF", 0); + empirical_trough.SetInput("TempCorr0", 1); + empirical_trough.SetInput("TempCorr1", 0); + empirical_trough.SetInput("TempCorr2", 0); + empirical_trough.SetInput("TempCorr3", 0); + empirical_trough.SetInput("TempCorr4", 0); + empirical_trough.SetInput("PTSmax", 535.973); + empirical_trough.SetInput("PFSmax", 543.0467); + empirical_trough.SetInput("SfPar", 0.42534); + empirical_trough.SetInput("ChtfPar", 16.8217); + empirical_trough.SetInput("AntiFrPar", 1.6822); + + int errors = empirical_trough.RunModule(); + EXPECT_FALSE(errors); + if (!errors) { + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_energy"), 350313341, kErrorToleranceLo); + EXPECT_NEAR(empirical_trough.GetOutput("annual_fuel_usage"), 0., kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("capacity_factor"), 40.03, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_W_cycle_gross"), 427283458, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("kwh_per_kw"), 3507, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("conversion_factor"), 85.40, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("system_heat_rate"), 3.413, kErrorToleranceLo); + EXPECT_NEAR(empirical_trough.GetOutput("system_use_lifetime_output"), 0., kErrorToleranceLo); + } } -/// Test tcstrough_empirical with alternative Thermal Storage Fluid Type: Therminol VP-1 -/// Rest default configurations with respect to the No Financial model -TEST_F(CMTcsTroughEmpirical, TroughEmpirical_Thermal_Storage_Fluid_No_Financial_cmod_tcstrough_empirical) { - - ssc_data_t data = ssc_data_create(); - int test_errors = tcstrough_empirical_tucson_thermal_storage(data); - - EXPECT_FALSE(test_errors); - if (!test_errors) - { - ssc_number_t annual_energy; - ssc_data_get_number(data, "annual_energy", &annual_energy); - EXPECT_NEAR(annual_energy, 3.4418e8, 3.4418e8 * m_error_tolerance_hi) << "Annual Energy"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t annual_fuel_usage; - ssc_data_get_number(data, "annual_fuel_usage", &annual_fuel_usage); - EXPECT_NEAR(annual_fuel_usage, 0, 0 * m_error_tolerance_hi) << "Annual fuel usage"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t capacity_factor; - ssc_data_get_number(data, "capacity_factor", &capacity_factor); - EXPECT_NEAR(capacity_factor, 39.3292, 39.3292 * m_error_tolerance_hi) << "Capacity Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t annual_W_cycle_gross; - ssc_data_get_number(data, "annual_W_cycle_gross", &annual_W_cycle_gross); - EXPECT_NEAR(annual_W_cycle_gross, 4.03784e8, 4.03784e8 * m_error_tolerance_hi) << "Annual W_cycle Gross"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t kwh_per_kw; - ssc_data_get_number(data, "kwh_per_kw", &kwh_per_kw); - EXPECT_NEAR(kwh_per_kw, 3445.24, 3445.24 * m_error_tolerance_hi) << "kwh per kw"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t conversion_factor; - ssc_data_get_number(data, "conversion_factor", &conversion_factor); - EXPECT_NEAR(conversion_factor, 88.7901, 88.7901 * m_error_tolerance_hi) << "Conversion Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t system_heat_rate; - ssc_data_get_number(data, "system_heat_rate", &system_heat_rate); - EXPECT_NEAR(system_heat_rate, 3.413, 3.413 * m_error_tolerance_hi) << "System heat rate"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t system_use_lifetime_output; - ssc_data_get_number(data, "system_use_lifetime_output", &system_use_lifetime_output); - EXPECT_NEAR(system_use_lifetime_output, 0, 0 * m_error_tolerance_hi) << "Use lifetime output"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - } +// Alternative thermal stoage fluid type: Therminol VP-1 +NAMESPACE_TEST(csp_trough, EmpiricalTroughCmod, TherminolHtf_NoFinancial) +{ + ssc_data_t defaults = tcstrough_empirical_defaults(); + CmodUnderTest empirical_trough = CmodUnderTest("tcstrough_empirical", defaults); + empirical_trough.SetInput("PTSmax", 676.4706); + empirical_trough.SetInput("PFSmax", 342.699); + + int errors = empirical_trough.RunModule(); + EXPECT_FALSE(errors); + if (!errors) { + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_energy"), 343856219, kErrorToleranceLo); + EXPECT_NEAR(empirical_trough.GetOutput("annual_fuel_usage"), 0., kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("capacity_factor"), 39.29, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_W_cycle_gross"), 403443026, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("kwh_per_kw"), 3444, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("conversion_factor"), 88.78, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("system_heat_rate"), 3.413, kErrorToleranceLo); + EXPECT_NEAR(empirical_trough.GetOutput("system_use_lifetime_output"), 0., kErrorToleranceLo); + } } -/// Test tcstrough_empirical with alternative Parasitic Electric Energy Use: 500C Molten Salt HTF -/// Rest default configurations with respect to the No Financial model -TEST_F(CMTcsTroughEmpirical, TroughEmpirical_Parasitic_No_Financial_cmod_tcstrough_empirical) { - - ssc_data_t data = ssc_data_create(); - int test_errors = tcstrough_empirical_tucson_parasitic(data); - - EXPECT_FALSE(test_errors); - if (!test_errors) - { - ssc_number_t annual_energy; - ssc_data_get_number(data, "annual_energy", &annual_energy); - EXPECT_NEAR(annual_energy, 3.58145e8, 3.58145e8 * m_error_tolerance_hi) << "Annual Energy"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t annual_fuel_usage; - ssc_data_get_number(data, "annual_fuel_usage", &annual_fuel_usage); - EXPECT_NEAR(annual_fuel_usage, 0, 0 * m_error_tolerance_hi) << "Annual fuel usage"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t capacity_factor; - ssc_data_get_number(data, "capacity_factor", &capacity_factor); - EXPECT_NEAR(capacity_factor, 40.9251, 40.9251 * m_error_tolerance_hi) << "Capacity Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t annual_W_cycle_gross; - ssc_data_get_number(data, "annual_W_cycle_gross", &annual_W_cycle_gross); - EXPECT_NEAR(annual_W_cycle_gross, 4.04116e8, 4.04116e8 * m_error_tolerance_hi) << "Annual W_cycle Gross"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t kwh_per_kw; - ssc_data_get_number(data, "kwh_per_kw", &kwh_per_kw); - EXPECT_NEAR(kwh_per_kw, 3585.04, 3585.04 * m_error_tolerance_hi) << "kwh per kw"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t conversion_factor; - ssc_data_get_number(data, "conversion_factor", &conversion_factor); - EXPECT_NEAR(conversion_factor, 92.3171, 92.3171 * m_error_tolerance_hi) << "Conversion Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t system_heat_rate; - ssc_data_get_number(data, "system_heat_rate", &system_heat_rate); - EXPECT_NEAR(system_heat_rate, 3.413, 3.413 * m_error_tolerance_hi) << "System heat rate"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t system_use_lifetime_output; - ssc_data_get_number(data, "system_use_lifetime_output", &system_use_lifetime_output); - EXPECT_NEAR(system_use_lifetime_output, 0, 0 * m_error_tolerance_hi) << "Use lifetime output"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - } +// Alternative parasitic electric energy use +NAMESPACE_TEST(csp_trough, EmpiricalTroughCmod, ParasiticElectric_NoFinancial) +{ + ssc_data_t defaults = tcstrough_empirical_defaults(); + CmodUnderTest empirical_trough = CmodUnderTest("tcstrough_empirical", defaults); + empirical_trough.SetInput("SfPar", 0.117); + empirical_trough.SetInput("SfParPF", 0.5); + empirical_trough.SetInput("ChtfPar", 3.231); + empirical_trough.SetInput("ChtfParPF", 0.35); + empirical_trough.SetInput("AntiFrPar", 0.323); + empirical_trough.SetInput("HhtfPar", 0.777); + empirical_trough.SetInput("HhtfParPF", 0.35); + + int errors = empirical_trough.RunModule(); + EXPECT_FALSE(errors); + if (!errors) { + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_energy"), 357850265, kErrorToleranceLo); + EXPECT_NEAR(empirical_trough.GetOutput("annual_fuel_usage"), 0., kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("capacity_factor"), 40.89, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_W_cycle_gross"), 403814011, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("kwh_per_kw"), 3582, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("conversion_factor"), 92.31, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("system_heat_rate"), 3.413, kErrorToleranceLo); + EXPECT_NEAR(empirical_trough.GetOutput("system_use_lifetime_output"), 0., kErrorToleranceLo); + } } -/// Test tcstrough_empirical with alternativelocation: Phoenix, AZ -/// Rest default configurations with respect to the No Financial model -TEST_F(CMTcsTroughEmpirical, TroughEmpirical_Location_No_Financial_cmod_tcstrough_empirical) { - - ssc_data_t data = ssc_data_create(); - int test_errors = tcstrough_empirical_phoenix(data); - - EXPECT_FALSE(test_errors); - if (!test_errors) - { - ssc_number_t annual_energy; - ssc_data_get_number(data, "annual_energy", &annual_energy); - EXPECT_NEAR(annual_energy, 3.3255e8, 3.3255e8 * m_error_tolerance_hi) << "Annual Energy"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t annual_fuel_usage; - ssc_data_get_number(data, "annual_fuel_usage", &annual_fuel_usage); - EXPECT_NEAR(annual_fuel_usage, 0, 0 * m_error_tolerance_hi) << "Annual fuel usage"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t capacity_factor; - ssc_data_get_number(data, "capacity_factor", &capacity_factor); - EXPECT_NEAR(capacity_factor, 38.0003, 38.0003 * m_error_tolerance_hi) << "Capacity Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t annual_W_cycle_gross; - ssc_data_get_number(data, "annual_W_cycle_gross", &annual_W_cycle_gross); - EXPECT_NEAR(annual_W_cycle_gross, 3.91116e8, 3.91116e8 * m_error_tolerance_hi) << "Annual W_cycle Gross"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t kwh_per_kw; - ssc_data_get_number(data, "kwh_per_kw", &kwh_per_kw); - EXPECT_NEAR(kwh_per_kw, 3328.83, 3328.83 * m_error_tolerance_hi) << "kwh per kw"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t conversion_factor; - ssc_data_get_number(data, "conversion_factor", &conversion_factor); - EXPECT_NEAR(conversion_factor, 88.5687, 88.5687 * m_error_tolerance_hi) << "Conversion Factor"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - - ssc_number_t system_heat_rate; - ssc_data_get_number(data, "system_heat_rate", &system_heat_rate); - EXPECT_NEAR(system_heat_rate, 3.413, 3.413 * m_error_tolerance_hi) << "System heat rate"; // choose either m_error_tolerance_lo or m_error_tolerance_hi +// Alternative location: Phoenix, AZ +NAMESPACE_TEST(csp_trough, EmpiricalTroughCmod, Phoenix_NoFinancial) +{ + ssc_data_t defaults = tcstrough_empirical_defaults(); + CmodUnderTest empirical_trough = CmodUnderTest("tcstrough_empirical", defaults); + char solar_resource_path_phoenix[512]; + int n = sprintf(solar_resource_path_phoenix, "%s/test/input_cases/trough_empirical_data/phoenix_az_33.450495_-111.983688_psmv3_60_tmy.csv", std::getenv("SSCDIR")); + empirical_trough.SetInput("file_name", solar_resource_path_phoenix); + + int errors = empirical_trough.RunModule(); + EXPECT_FALSE(errors); + if (!errors) { + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_energy"), 332549669, kErrorToleranceLo); + EXPECT_NEAR(empirical_trough.GetOutput("annual_fuel_usage"), 0., kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("capacity_factor"), 38.00, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_W_cycle_gross"), 391115710, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("kwh_per_kw"), 3329, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("conversion_factor"), 88.56, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("system_heat_rate"), 3.413, kErrorToleranceLo); + EXPECT_NEAR(empirical_trough.GetOutput("system_use_lifetime_output"), 0., kErrorToleranceLo); + } +} - ssc_number_t system_use_lifetime_output; - ssc_data_get_number(data, "system_use_lifetime_output", &system_use_lifetime_output); - EXPECT_NEAR(system_use_lifetime_output, 0, 0 * m_error_tolerance_hi) << "Use lifetime output"; // choose either m_error_tolerance_lo or m_error_tolerance_hi +// Test series of Advanced Combinatorial Testing System (ACTS) runs +// Parabolic trough (empirical) +//int ACTS_test_empirical(ssc_data_t &data, int test_case) +//{ +// tcstrough_empirical_default(data); +// +// // Testing level to vector index map +// std::unordered_map idx = +// { +// {-1, 0}, +// { 0, 1}, +// { 1, 2} +// }; +// +// // Parameter test range values +// std::vector Distance_SCA_vals{ 0.5, 1 , 2 }; // Distance Between SCAs in Row // SAM SSC - "Distance_SCA" +// std::vector NumScas_vals{ 1, 4, 8 }; // Number of SCAs per Row // SAM SSC - "NumScas" +// std::vector DepAngle_vals{ 5, 10, 20 }; // Deploy Angle // SAM SSC - "DepAngle" +// std::vector Stow_Angle_vals{ 160, 170, 175 }; // Stow Angle // SAM SSC - "Stow_Angle" +// +// // ACTS transposed covering array 1 2 3 4 5 6 7 8 9 +// std::vector Distance_SCA_lvls{ -1, -1, -1, 0, 0, 0, 1, 1, 1 }; +// std::vector NumScas_lvls{ -1, 0, 1, -1, 0, 1, -1, 0, 1 }; +// std::vector DepAngle_lvls{ 0, 1, -1, 1, -1, 0, -1, 0, 1 }; +// std::vector Stow_Angle_lvls{ 0, 1, -1, -1, 0, 1, 1, -1, 0 }; +// +// // Get test case values from index +// double Distance_SCA_ACTS = Distance_SCA_vals.at(idx.find(Distance_SCA_lvls.at(test_case))->second); +// double NumScas_ACTS = NumScas_vals.at(idx.find(NumScas_lvls.at(test_case))->second); +// double DepAngle_ACTS = DepAngle_vals.at(idx.find(DepAngle_lvls.at(test_case))->second); +// double Stow_Angle_ACTS = Stow_Angle_vals.at(idx.find(Stow_Angle_lvls.at(test_case))->second); +// +// // Assigning values to variables +// ssc_data_set_number(data, "Distance_SCA", Distance_SCA_ACTS); +// ssc_data_set_number(data, "NumScas", NumScas_ACTS); +// ssc_data_set_number(data, "DepAngle", DepAngle_ACTS); +// ssc_data_set_number(data, "Stow_Angle", Stow_Angle_ACTS); +// +// int status = run_module(data, "tcstrough_empirical"); +// +// return status; +//} - } -} /// Test series of Advanced Combinatorial Testing System (ACTS) runs //TEST_F(CMTcsTroughEmpirical, ACTS_Test_Empirical) { @@ -423,6 +328,3 @@ TEST_F(CMTcsTroughEmpirical, TroughEmpirical_Location_No_Financial_cmod_tcstroug // } // } //} - - - diff --git a/test/ssc_test/cmod_tcstrough_empirical_test.h b/test/ssc_test/cmod_tcstrough_empirical_test.h deleted file mode 100644 index 3b10d7e8301..00000000000 --- a/test/ssc_test/cmod_tcstrough_empirical_test.h +++ /dev/null @@ -1,53 +0,0 @@ -#include - -#include "core.h" -#ifndef _CMOD_TCSTROUGH_EMPIRICAL_TEST_H_ -#define _CMOD_TCSTROUGH_EMPIRICAL_TEST_H_ - -#include "vartab.h" -#include "../ssc/common.h" -#include "../tcs_test/tcstrough_empirical_cases.h" - -/** - * CMtcsTroughEmpirical tests the cmod_tcstrough_empirical using the SAM code generator to generate data - * Eventually a method can be written to write this data to a vartable so that lower-level methods of - * tcstrough_empirical can be tested - * For now, this uses the SSCAPI interfaces to run the compute module and compare results - */ -class CMTcsTroughEmpirical : public ::testing::Test { - -public: - - ssc_data_t data; - ssc_number_t calculated_value; - ssc_number_t * calculated_array; - double m_error_tolerance_hi = 0.01; // 1.0% - double m_error_tolerance_lo = 0.001; // 0.1% - - void SetUp() - { - data = ssc_data_create(); - tcstrough_empirical_default(data); - calculated_array = new ssc_number_t[8760]; - } - void TearDown() { - if (data) { - ssc_data_free(data); - data = nullptr; - } - if (calculated_array) { - delete[] calculated_array; - } - } - void SetCalculated(std::string name) - { - ssc_data_get_number(data, const_cast(name.c_str()), &calculated_value); - } - void SetCalculatedArray(std::string name) - { - int n; - calculated_array = ssc_data_get_array(data, const_cast(name.c_str()), &n); - } -}; - -#endif // !_CMOD_TCSTROUGH_EMPIRICAL_TEST_H diff --git a/test/ssc_test/cmod_trough_physical_iph_test.cpp b/test/ssc_test/cmod_trough_physical_iph_test.cpp index 2251ce11494..6ce20846cfc 100644 --- a/test/ssc_test/cmod_trough_physical_iph_test.cpp +++ b/test/ssc_test/cmod_trough_physical_iph_test.cpp @@ -1,119 +1,25 @@ #include - -#include "cmod_trough_physical_iph_test.h" -#include "../tcs_test/trough_physical_iph_cases.h" -#include "../input_cases/weather_inputs.h" - -/// Test trough_physical_iph with all defaults and no-financial model -TEST_F(CMTroughPhysicalIPH, DefaultNoFinancialModel_cmod_trough_physical_iph){ - - int test_errors = run_module(data, "trough_physical_process_heat"); - - EXPECT_FALSE(test_errors); - if (!test_errors) - { - ssc_number_t annual_gross_energy; - ssc_data_get_number(data, "annual_gross_energy", &annual_gross_energy); - EXPECT_NEAR(annual_gross_energy, 24480390.431956, 24480390.431956 * m_error_tolerance_hi) << "Annual Gross Energy"; - - ssc_number_t annual_energy; - ssc_data_get_number(data, "annual_energy", &annual_energy); - EXPECT_NEAR(annual_energy, 24480390.431956, 24480390.431956 * m_error_tolerance_hi) << "Annual Energy"; - - ssc_number_t annual_electricity_consumption; - ssc_data_get_number(data, "annual_electricity_consumption", &annual_electricity_consumption); - EXPECT_NEAR(annual_electricity_consumption, 93788., 93788. * m_error_tolerance_hi) << "Annual Electricity Consumption"; - - //ssc_number_t fixed_operating_cost; - //ssc_data_get_number(data, "fixed_operating_cost", &fixed_operating_cost); - //EXPECT_NEAR(fixed_operating_cost, 111118, 111118 * m_error_tolerance_hi) << "Fixed Operating Cost"; - - ssc_number_t annual_thermal_consumption; - ssc_data_get_number(data, "annual_thermal_consumption", &annual_thermal_consumption); - EXPECT_NEAR(annual_thermal_consumption, 247.65286, 247.65286 * m_error_tolerance_hi) << "Annual Thermal Consumption"; - - ssc_number_t annual_tes_freeze_protection; - ssc_data_get_number(data, "annual_tes_freeze_protection", &annual_tes_freeze_protection); - EXPECT_NEAR(annual_tes_freeze_protection, 247.65286, 247.65286 * m_error_tolerance_hi) << "Annual TES Freeze Protection"; - - ssc_number_t annual_field_freeze_protection; - ssc_data_get_number(data, "annual_field_freeze_protection", &annual_field_freeze_protection); - EXPECT_NEAR(annual_field_freeze_protection, 0., m_error_tolerance_hi) << "Annual Field Freeze Protection"; - - //ssc_number_t lcoe_fcr; - //ssc_data_get_number(data, "lcoe_fcr", &lcoe_fcr); - //EXPECT_NEAR(lcoe_fcr, 0.0375859, 0.0375859 * m_error_tolerance_hi) << "LCOE FCR"; - - ssc_number_t annual_total_water_use; - ssc_data_get_number(data, "annual_total_water_use", &annual_total_water_use); - EXPECT_NEAR(annual_total_water_use, 176.332800, 176.332800 * m_error_tolerance_hi) << "Annual Total Water Use"; - - //ssc_number_t VARIABLE; - //ssc_data_get_number(data, "VARIABLE", &VARIABLE); - //EXPECT_NEAR(VARIABLE, EXP_VAL, EXP_VAL * m_error_tolerance_hi) << "DESCRIPTION"; - } +#include "trough_physical_iph_defaults.h" +#include "csp_common_test.h" +#include "vs_google_test_explorer_namespace.h" + +namespace csp_trough {} +using namespace csp_trough; + +//========Tests=================================================================================== +NAMESPACE_TEST(csp_trough, HeatTroughCmod, Default_NoFinancial) +{ + ssc_data_t defaults = trough_physical_iph_defaults(); + CmodUnderTest heat_trough = CmodUnderTest("trough_physical_process_heat", defaults); + int errors = heat_trough.RunModule(); + EXPECT_FALSE(errors); + if (!errors) { + EXPECT_NEAR_FRAC(heat_trough.GetOutput("annual_gross_energy"), 24328026, kErrorToleranceLo); + EXPECT_NEAR_FRAC(heat_trough.GetOutput("annual_energy"), 24327778, kErrorToleranceLo); + EXPECT_NEAR_FRAC(heat_trough.GetOutput("annual_electricity_consumption"), 93310, kErrorToleranceLo); + EXPECT_NEAR_FRAC(heat_trough.GetOutput("annual_thermal_consumption"), 247.67, kErrorToleranceLo); + EXPECT_NEAR_FRAC(heat_trough.GetOutput("annual_tes_freeze_protection"), 247.67, kErrorToleranceLo); + EXPECT_NEAR(heat_trough.GetOutput("annual_field_freeze_protection"), 0., kErrorToleranceLo); + EXPECT_NEAR_FRAC(heat_trough.GetOutput("annual_total_water_use"), 176.3, kErrorToleranceLo); + } } - -/// Test trough_physical_iph with all defaults and the financial model in the LCOH Calculator -//TEST_F(CMTroughPhysicalIPH, DefaultLCOHFinancialModel_cmod_trough_physical_iph) { -// -// ssc_data_t data = ssc_data_create(); -// int test_errors = trough_physical_iph_tucson(data); -// -// EXPECT_FALSE(test_errors); -// if (!test_errors) -// { -// ssc_number_t annual_gross_energy; -// ssc_data_get_number(data, "annual_gross_energy", &annual_gross_energy); -// EXPECT_NEAR(annual_gross_energy, 2.44933e7, 2.44933e7 * m_error_tolerance_lo) << "Annual Gross Energy"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_energy; -// ssc_data_get_number(data, "annual_energy", &annual_energy); -// EXPECT_NEAR(annual_energy, 2.44931e7, 2.44931e7 * m_error_tolerance_lo) << "Annual Energy"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_electricity_consumption; -// ssc_data_get_number(data, "annual_electricity_consumption", &annual_electricity_consumption); -// EXPECT_NEAR(annual_electricity_consumption, 132796, 132796 * m_error_tolerance_lo) << "Annual Electricity Consumption"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t fixed_operating_cost; -// ssc_data_get_number(data, "fixed_operating_cost", &fixed_operating_cost); -// EXPECT_NEAR(fixed_operating_cost, 111726, 111726 * m_error_tolerance_lo) << "Fixed Operating Cost"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_thermal_consumption; -// ssc_data_get_number(data, "annual_thermal_consumption", &annual_thermal_consumption); -// EXPECT_NEAR(annual_thermal_consumption, 232.282, 232.282 * m_error_tolerance_lo) << "Annual Thermal Consumption"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_tes_freeze_protection; -// ssc_data_get_number(data, "annual_tes_freeze_protection", &annual_tes_freeze_protection); -// EXPECT_NEAR(annual_tes_freeze_protection, 232.282, 232.282 * m_error_tolerance_lo) << "Annual TES Freeze Protection"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_field_freeze_protection; -// ssc_data_get_number(data, "annual_field_freeze_protection", &annual_field_freeze_protection); -// EXPECT_NEAR(annual_field_freeze_protection, 0., m_error_tolerance_lo) << "Annual Field Freeze Protection"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t lcoe_fcr; -// ssc_data_get_number(data, "lcoe_fcr", &lcoe_fcr); -// EXPECT_NEAR(lcoe_fcr, 0.0376277, 0.0376277 * m_error_tolerance_lo) << "LCOE FCR"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_total_water_use; -// ssc_data_get_number(data, "annual_total_water_use", &annual_total_water_use); -// EXPECT_NEAR(annual_total_water_use, 176.333, 176.333 * m_error_tolerance_lo) << "Annual Total Water Use"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// //ssc_number_t VARIABLE; -// //ssc_data_get_number(data, "VARIABLE", &VARIABLE); -// //EXPECT_NEAR(VARIABLE, EXP_VAL, EXP_VAL * m_error_tolerance_lo) << "DESCRIPTION"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// } -//} - -//TestResult iphTroughLCOHDefaultResult[] = { -// /* SSC Var Name Test Type Test Result Error Bound % */ -// { "annual_gross_energy", NR, 2.44933e7, 0.1 }, // Annual Gross Thermal Energy Production w/ avail derate [kWt-hr] -// { "annual_energy", NR, 2.44931e7, 0.1 }, // Annual Net Thermal Energy Production w/ avail derate [kWt-hr] -// { "annual_electricity_consumption", NR, 122659, 0.1 }, // Annual electricity consumptoin w/ avail derate [kWe-hr] -// { "fixed_operating_cost", NR, 111118, 0.1 }, // Annual fixed operating cost [$/kW] -// { "annual_thermal_consumption", NR, 236.609, 0.1 }, // Annual thermal freeze protection required [kWt-hr] -// { "annual_tes_freeze_protection", NR, 236.609, 0.1 }, // Annual thermal power for TES freeze protection [kWt-hr] -// { "annual_field_freeze_protection", NR, 0., 0.1 }, // Annual thermal power for field freeze protection [kWt-hr] -// { "lcoe_fcr", NR, 0.0375859, 0.1 }, // Levelized cost of energy [$/kWh] -// { "annual_total_water_use", NR, 176.333, 0.1 }, // Total Annual Water Usage [m^3] -//}; diff --git a/test/ssc_test/cmod_trough_physical_iph_test.h b/test/ssc_test/cmod_trough_physical_iph_test.h deleted file mode 100644 index faaa108be6e..00000000000 --- a/test/ssc_test/cmod_trough_physical_iph_test.h +++ /dev/null @@ -1,53 +0,0 @@ -#include - -#include "core.h" -#ifndef _CMOD_TROUGH_PHYSICAL_IPH_TEST_H_ -#define _CMOD_TROUGH_PHYSICAL_IPH_TEST_H_ - -#include "vartab.h" -#include "../ssc/common.h" -#include "../tcs_test/trough_physical_iph_cases.h" - -/** - * CMTroughPhysicalIPH tests the cmod_trough_physical_iph using the SAM code generator to generate data - * Eventually a method can be written to write this data to a vartable so that lower-level methods of - * trough_physical_process_heat can be tested - * For now, this uses the SSCAPI interfaces to run the compute module and compare results - */ -class CMTroughPhysicalIPH : public ::testing::Test{ - -public: - - ssc_data_t data; - ssc_number_t calculated_value; - ssc_number_t * calculated_array; - double m_error_tolerance_hi = 0.01; // 1.0% - double m_error_tolerance_lo = 0.001; // 0.1% - - void SetUp() - { - data = ssc_data_create(); - trough_physical_iph_default(data); - calculated_array = new ssc_number_t[8760]; - } - void TearDown() { - if (data) { - ssc_data_free(data); - data = nullptr; - } - if (calculated_array) { - delete[] calculated_array; - } - } - void SetCalculated(std::string name) - { - ssc_data_get_number(data, const_cast(name.c_str()), &calculated_value); - } - void SetCalculatedArray(std::string name) - { - int n; - calculated_array = ssc_data_get_array(data, const_cast(name.c_str()), &n); - } -}; - -#endif // !_CMOD_TROUGH_PHYSICAL_IPH_TEST_H_ diff --git a/test/ssc_test/cmod_trough_physical_test.cpp b/test/ssc_test/cmod_trough_physical_test.cpp index adfd797571a..e5a11f7011a 100644 --- a/test/ssc_test/cmod_trough_physical_test.cpp +++ b/test/ssc_test/cmod_trough_physical_test.cpp @@ -1,110 +1,35 @@ #include - -#include "cmod_trough_physical_test.h" -#include "../tcs_test/trough_physical_cases.h" -#include "../input_cases/weather_inputs.h" - -/// Test trough_physical with all defaults and no-financial model -TEST_F(CMTroughPhysical, DefaultNoFinancialModel_cmod_trough_physical){ - - int test_errors = run_module(data, "trough_physical"); - - EXPECT_FALSE(test_errors); - if (!test_errors) - { - //ssc_number_t annual_gross_energy; - //ssc_data_get_number(data, "annual_gross_energy", &annual_gross_energy); - //EXPECT_NEAR(annual_gross_energy, 3.671e8, 3.671e8 * m_error_tolerance_lo) << "Annual Gross Thermal Energy Production"; - - ssc_number_t annual_energy; - ssc_data_get_number(data, "annual_energy", &annual_energy); - EXPECT_NEAR(annual_energy, 369175344., 369175344. * m_error_tolerance_hi) << "Annual Net Thermal Energy Production"; - - ssc_number_t annual_thermal_consumption; - ssc_data_get_number(data, "annual_thermal_consumption", &annual_thermal_consumption); - EXPECT_NEAR(annual_thermal_consumption, 599751.371423, 599751.371423 * m_error_tolerance_hi) << "Annual Thermal Freeze Protection"; - - ssc_number_t annual_tes_freeze_protection; - ssc_data_get_number(data, "annual_tes_freeze_protection", &annual_tes_freeze_protection); - EXPECT_NEAR(annual_tes_freeze_protection, 561717.769603, 561717.769603 * m_error_tolerance_hi) << "Annual TES Freeze Protection"; - - ssc_number_t annual_field_freeze_protection; - ssc_data_get_number(data, "annual_field_freeze_protection", &annual_field_freeze_protection); - EXPECT_NEAR(annual_field_freeze_protection, 38036.686198, 38036.686198 * m_error_tolerance_hi) << "Annual Field Freeze Protection"; - - ssc_number_t capacity_factor; - ssc_data_get_number(data, "capacity_factor", &capacity_factor); - EXPECT_NEAR(capacity_factor, 42.18, 42.18 * m_error_tolerance_hi) << "Capacity factor"; - - ssc_number_t annual_W_cycle_gross; - ssc_data_get_number(data, "annual_W_cycle_gross", &annual_W_cycle_gross); - EXPECT_NEAR(annual_W_cycle_gross, 424232748.142327, 424232748.142327 * m_error_tolerance_hi) << "Power cycle gross electrical output"; - - ssc_number_t kwh_per_kw; - ssc_data_get_number(data, "kwh_per_kw", &kwh_per_kw); - EXPECT_NEAR(kwh_per_kw, 3695., 3695. * m_error_tolerance_hi) << "First year kWh/kW"; - - ssc_number_t conversion_factor; - ssc_data_get_number(data, "conversion_factor", &conversion_factor); - EXPECT_NEAR(conversion_factor, 87.92, 87.92 * m_error_tolerance_hi) << "Gross to Net Conversion Factor"; - - ssc_number_t annual_total_water_use; - ssc_data_get_number(data, "annual_total_water_use", &annual_total_water_use); - EXPECT_NEAR(annual_total_water_use, 81059.873491, 81059.873491 * m_error_tolerance_hi) << "Annual Total Water Use"; - - //ssc_number_t VARIABLE; - //ssc_data_get_number(data, "VARIABLE", &VARIABLE); - //EXPECT_NEAR(VARIABLE, EXP_VAL, EXP_VAL * m_error_tolerance_lo) << "DESCRIPTION"; // choose either m_error_tolerance_lo or m_error_tolerance_hi - } +#include "trough_physical_defaults.h" +#include "csp_common_test.h" +#include "vs_google_test_explorer_namespace.h" + +namespace csp_trough {} +using namespace csp_trough; + +//========Tests=================================================================================== +NAMESPACE_TEST(csp_trough, PowerTroughCmod, Default_NoFinancial) +{ + ssc_data_t defaults = trough_physical_defaults(); + CmodUnderTest power_trough = CmodUnderTest("trough_physical", defaults); + int errors = power_trough.RunModule(); + EXPECT_FALSE(errors); + if (!errors) { + EXPECT_NEAR_FRAC(power_trough.GetOutput("annual_energy"), 369272759, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_trough.GetOutput("annual_thermal_consumption"), 596547, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_trough.GetOutput("annual_tes_freeze_protection"), 558505, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_trough.GetOutput("annual_field_freeze_protection"), 38042, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_trough.GetOutput("capacity_factor"), 42.20, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_trough.GetOutput("annual_W_cycle_gross"), 420379150, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_trough.GetOutput("kwh_per_kw"), 3696, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_trough.GetOutput("conversion_factor"), 87.84, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_trough.GetOutput("annual_total_water_use"), 80708, kErrorToleranceLo); + } + + //ssc_data_t defaults = singleowner_defaults(); + //CmodUnderTest singleowner = CmodUnderTest("singleowner", defaults); + //int errors = singleowner.RunModule(); + //EXPECT_FALSE(errors); + //if (!errors) { + // EXPECT_NEAR_FRAC(singleowner.GetOutput(""), , kErrorToleranceLo); + //} } - -/// Test trough_physical with all defaults and the financial model in the LCOH Calculator -//TEST_F(CMTroughPhysical, DefaultLCOHFinancialModel) { -// -// ssc_data_t data = ssc_data_create(); -// int test_errors = trough_physical_tucson(data); -// -// EXPECT_FALSE(test_errors); -// if (!test_errors) -// { -// ssc_number_t annual_gross_energy; -// ssc_data_get_number(data, "annual_gross_energy", &annual_gross_energy); -// EXPECT_NEAR(annual_gross_energy, 2.44933e7, 2.44933e7 * m_error_tolerance_lo) << "Annual Gross Energy"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_energy; -// ssc_data_get_number(data, "annual_energy", &annual_energy); -// EXPECT_NEAR(annual_energy, 2.44931e7, 2.44931e7 * m_error_tolerance_lo) << "Annual Energy"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_electricity_consumption; -// ssc_data_get_number(data, "annual_electricity_consumption", &annual_electricity_consumption); -// EXPECT_NEAR(annual_electricity_consumption, 122659, 122659 * m_error_tolerance_lo) << "Annual Electricity Consumption"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t fixed_operating_cost; -// ssc_data_get_number(data, "fixed_operating_cost", &fixed_operating_cost); -// EXPECT_NEAR(fixed_operating_cost, 111118, 111118 * m_error_tolerance_lo) << "Fixed Operating Cost"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_thermal_consumption; -// ssc_data_get_number(data, "annual_thermal_consumption", &annual_thermal_consumption); -// EXPECT_NEAR(annual_thermal_consumption, 236.609, 236.609 * m_error_tolerance_lo) << "Annual Thermal Consumption"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_tes_freeze_protection; -// ssc_data_get_number(data, "annual_tes_freeze_protection", &annual_tes_freeze_protection); -// EXPECT_NEAR(annual_tes_freeze_protection, 236.609, 236.609 * m_error_tolerance_lo) << "Annual TES Freeze Protection"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_field_freeze_protection; -// ssc_data_get_number(data, "annual_field_freeze_protection", &annual_field_freeze_protection); -// EXPECT_NEAR(annual_field_freeze_protection, 0., m_error_tolerance_lo) << "Annual Field Freeze Protection"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t lcoe_fcr; -// ssc_data_get_number(data, "lcoe_fcr", &lcoe_fcr); -// EXPECT_NEAR(lcoe_fcr, 0.0375859, 0.0375859 * m_error_tolerance_lo) << "LCOE FCR"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// ssc_number_t annual_total_water_use; -// ssc_data_get_number(data, "annual_total_water_use", &annual_total_water_use); -// EXPECT_NEAR(annual_total_water_use, 176.333, 176.333 * m_error_tolerance_lo) << "Annual Total Water Use"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// -// //ssc_number_t VARIABLE; -// //ssc_data_get_number(data, "VARIABLE", &VARIABLE); -// //EXPECT_NEAR(VARIABLE, EXP_VAL, EXP_VAL * m_error_tolerance_lo) << "DESCRIPTION"; // choose either m_error_tolerance_lo or m_error_tolerance_hi -// } -//} diff --git a/test/ssc_test/cmod_trough_physical_test.h b/test/ssc_test/cmod_trough_physical_test.h deleted file mode 100644 index 959097d6efb..00000000000 --- a/test/ssc_test/cmod_trough_physical_test.h +++ /dev/null @@ -1,54 +0,0 @@ -#include - -#include "core.h" -#ifndef _CMOD_TROUGH_PHYSICAL_TEST_H_ -#define _CMOD_TROUGH_PHYSICAL_TEST_H_ - -#include "vartab.h" -#include "../ssc/common.h" -#include "../tcs_test/trough_physical_cases.h" - -/** - * CMTroughPhysical tests the cmod_trough_physical using the SAM code generator to generate data - * Eventually a method can be written to write this data to a vartable so that lower-level methods of - * trough_physical can be tested - * For now, this uses the SSCAPI interfaces to run the compute module and compare results - */ -class CMTroughPhysical : public ::testing::Test{ - -public: - - ssc_data_t data; - ssc_number_t calculated_value; - ssc_number_t * calculated_array; - double m_error_tolerance_hi = 0.01; // 1.0% - double m_error_tolerance_lo = 0.001; // 0.1% - - void SetUp() - { - data = ssc_data_create(); - trough_physical_default(data); - calculated_array = new ssc_number_t[8760]; - } - void TearDown() { - if (data) { - ssc_data_free(data); - data = nullptr; - } - if (calculated_array) { - delete[] calculated_array; - calculated_array = nullptr; - } - } - void SetCalculated(std::string name) - { - ssc_data_get_number(data, const_cast(name.c_str()), &calculated_value); - } - void SetCalculatedArray(std::string name) - { - int n; - calculated_array = ssc_data_get_array(data, const_cast(name.c_str()), &n); - } -}; - -#endif // !_CMOD_TROUGH_PHYSICAL_TEST_H_ diff --git a/test/ssc_test/csp_common_test.h b/test/ssc_test/csp_common_test.h new file mode 100644 index 00000000000..d33711efad2 --- /dev/null +++ b/test/ssc_test/csp_common_test.h @@ -0,0 +1,56 @@ +#ifndef _CSP_COMMON_TEST_H_ +#define _CSP_COMMON_TEST_H_ + +#include +#include +#include "../ssc/common.h" +//#include "csp_financial_defaults.h" +#include "../input_cases/code_generator_utilities.h" + +#define EXPECT_NEAR_FRAC(val1, val2, frac_error) EXPECT_NEAR(val1, val2, val2 * frac_error) +#define ASSERT_NEAR_FRAC(val1, val2, frac_error) ASSERT_NEAR(val1, val2, val2 * frac_error) + +const double kErrorToleranceLo = 0.001; // 0.1% +const double kErrorToleranceHi = 0.01; // 1.0% + +class CmodUnderTest { +public: + CmodUnderTest(std::string module_name, ssc_data_t defaults) + : module_name_{ module_name }, data_{ defaults } {} + ~CmodUnderTest() { + if (data_) { + ssc_data_free(data_); + data_ = nullptr; + } + } + int RunModule() { + int errors = run_module(this->data_, this->module_name_); + return errors; + } + void SetInput(std::string name, ssc_number_t value) { + ssc_data_set_number(this->data_, name.c_str(), value); + } + void SetInput(std::string name, std::string value) { + ssc_data_set_string(this->data_, name.c_str(), value.c_str()); + } + void SetInput(std::string name, ssc_number_t values[], int size) { + // deprecated, replaced by the following that uses initializer_list + ssc_data_set_array(this->data_, name.c_str(), values, size); + } + void SetInput(std::string name, const std::initializer_list& values) { + ssc_data_set_array(this->data_, name.c_str(), (ssc_number_t*)(values.begin()), values.size()); + } + ssc_number_t GetOutput(std::string name) const { + ssc_number_t output; + ssc_data_get_number(this->data_, name.c_str(), &output); + return output; + } +private: + const std::string module_name_; + ssc_data_t data_; +}; + + +ssc_data_t singleowner_defaults(); + +#endif diff --git a/test/tcs_test/lib_trough_properties.h b/test/tcs_test/lib_trough_properties.h deleted file mode 100644 index f676456578a..00000000000 --- a/test/tcs_test/lib_trough_properties.h +++ /dev/null @@ -1,506 +0,0 @@ -#ifndef __LIB_TROUGH_PROPERTIES__ -#define __LIB_TROUGH_PROPERTIES__ - -#include -#include - - -// Generic physical trough for the csp solver to be re-used -class TroughProperties : public ::testing::Test -{ -public: - - int nSCA; //[-] Number of SCA's in a loop - int nHCEt; //[-] Number of HCE types - int nColt; //[-] Number of collector types - int nHCEVar; //[-] Number of HCE variants per t - int nLoops; //[-] Number of loops in the field - int FieldConfig; //[-] Number of subfield headers - double L_power_block_piping; //[m] Length of piping (full mass flow) through power block (if applicable) - bool include_fixed_power_block_runner; //[-] Should model consider piping through power block (is_model_power_block_piping)? - double eta_pump; //[-] HTF pump efficiency - int Fluid; //[-] Field HTF fluid number - //int fthrok; //[-] Flag to allow partial defocusing of the collectors - int fthrctrl; //[-] Defocusing strategy; hardcode2 for now - int accept_loc; //[-] In acceptance testing mode - temperature sensor location (1=hx,2=loop) - double HDR_rough; //[m] Header pipe roughness - double theta_stow; //[deg] stow angle - double theta_dep; //[deg] deploy angle - double Row_Distance; //[m] Spacing between rows (centerline to centerline) - - double T_loop_in_des; //[C] Design loop inlet temperature, converted to K in init - double T_loop_out_des; //[C] Target loop outlet temperature, converted to K in init - double T_startup; //[C] The required temperature (converted to K in init) of the system before the power block can be switched on - double m_dot_htfmin; //[kg/s] Minimum loop HTF flow rate - double m_dot_htfmax; //[kg/s] Maximum loop HTF flow rate - util::matrix_t field_fl_props; //[-] User-defined field HTF properties - double T_fp; //[C] Freeze protection temperature (heat trace activation temperature), convert to K in init - double I_bn_des; //[W/m^2] Solar irradiation at design - double V_hdr_cold_max; //[m/s] Maximum HTF velocity in the cold header at design - double V_hdr_cold_min; //[m/s] Minimum HTF velocity in the cold header at design - double V_hdr_hot_max; //[m/s] Maximum HTF velocity in the hot header at design - double V_hdr_hot_min; //[m/s] Minimum HTF velocity in the hot header at design - double V_hdr_max; //[m/s] Maximum HTF velocity in the header at design, for backwards compatibility, marked for removal - double V_hdr_min; //[m/s] Minimum HTF velocity in the header at design, for backwards compatibility, marked for removal - double Pipe_hl_coef; //[W/m2-K] Loss coefficient from the header, runner pipe, and non-HCE piping - double SCA_drives_elec; //[W/SCA] Tracking power, in Watts per SCA drive - double ColTilt; //[deg] Collector tilt angle (0 is horizontal, 90deg is vertical) ("tilt") - double ColAz; //[deg] Collector azimuth angle ("azimuth") - double wind_stow_speed; //[m/s] Wind speed at and above which the collectors will be stowed - int accept_mode; //[-] Acceptance testing mode? (1=yes, 0=no) - bool accept_init; //[-] In acceptance testing mode - require steady-state startup - double solar_mult; //[-] Solar Multiple - double mc_bal_hot_per_MW; //[kWht/K-MWt] The heat capacity of the balance of plant on the hot side ("mc_bal_hot") - double mc_bal_cold_per_MW; //[kWht/K-MWt] The heat capacity of the balance of plant on the cold side ("mc_bal_cold") - double mc_bal_sca; //[Wht/K-m] Non-HTF heat capacity associated with each SCA - per meter basis - - std::vector W_aperture; //[m] The collector aperture width (Total structural area.. used for shadowing) - std::vector A_aperture; //[m^2] Reflective aperture area of the collector - std::vector TrackingError; //[-] Tracking error derate - std::vector GeomEffects; //[-] Geometry effects derate - std::vector Rho_mirror_clean; //[-] Clean mirror reflectivity - std::vector Dirt_mirror; //[-] Dirt on mirror derate - std::vector Error; //[-] General optical error derate - std::vector Ave_Focal_Length; //[m] The average focal length of the collector - std::vector L_SCA; //[m] The length of the SCA - std::vector L_aperture; //[m] The length of a single mirror/HCE unit - std::vector ColperSCA; //[-] The number of individual collector sections in an SCA - std::vector Distance_SCA; //[m] Piping distance between SCA's in the field - - util::matrix_t IAM_matrix; //[-] IAM coefficients, matrix for 4 collectors - util::matrix_t HCE_FieldFrac; //[-] Fraction of the field occupied by this HCE type - util::matrix_t D_2; //[m] Inner absorber tube diameter - util::matrix_t D_3; //[m] Outer absorber tube diameter - util::matrix_t D_4; //[m] Inner glass envelope diameter - util::matrix_t D_5; //[m] Outer glass envelope diameter - util::matrix_t D_p; //[m] Diameter of the absorber flow plug (optional) - util::matrix_t Flow_type; //[-] Flow type through the absorber - util::matrix_t Rough; //[m] Roughness of the internal surface - util::matrix_t alpha_env; //[-] Envelope absorptance - - util::matrix_t epsilon_3_11; //[-] Absorber emittance for receiver type 1 variation 1 - util::matrix_t epsilon_3_12; //[-] Absorber emittance for receiver type 1 variation 2 - util::matrix_t epsilon_3_13; //[-] Absorber emittance for receiver type 1 variation 3 - util::matrix_t epsilon_3_14; //[-] Absorber emittance for receiver type 1 variation 4 - util::matrix_t epsilon_3_21; //[-] Absorber emittance for receiver type 2 variation 1 - util::matrix_t epsilon_3_22; //[-] Absorber emittance for receiver type 2 variation 2 - util::matrix_t epsilon_3_23; //[-] Absorber emittance for receiver type 2 variation 3 - util::matrix_t epsilon_3_24; //[-] Absorber emittance for receiver type 2 variation 4 - util::matrix_t epsilon_3_31; //[-] Absorber emittance for receiver type 3 variation 1 - util::matrix_t epsilon_3_32; //[-] Absorber emittance for receiver type 3 variation 2 - util::matrix_t epsilon_3_33; //[-] Absorber emittance for receiver type 3 variation 3 - util::matrix_t epsilon_3_34; //[-] Absorber emittance for receiver type 3 variation 4 - util::matrix_t epsilon_3_41; //[-] Absorber emittance for receiver type 4 variation 1 - util::matrix_t epsilon_3_42; //[-] Absorber emittance for receiver type 4 variation 2 - util::matrix_t epsilon_3_43; //[-] Absorber emittance for receiver type 4 variation 3 - util::matrix_t epsilon_3_44; //[-] Absorber emittance for receiver type 4 variation 4 - - util::matrix_t alpha_abs; //[-] Absorber absorptance - util::matrix_t Tau_envelope; //[-] Envelope transmittance - util::matrix_t EPSILON_4; //[-] Inner glass envelope emissivities - util::matrix_t EPSILON_5; //[-] Outer glass envelope emissivities - util::matrix_t GlazingIntact_dbl; //[-] Glazing intact (broken glass) flag {1=true, else=false}, as double - util::matrix_t GlazingIntact; //[-] Glazing intact (broken glass) flag {1=true, else=false} - util::matrix_t P_a; //[torr] Annulus gas pressure - util::matrix_t AnnulusGas; //[-] Annulus gas type (1=air, 26=Ar, 27=H2) - util::matrix_t AbsorberMaterial; //[-] Absorber material type - util::matrix_t Shadowing; //[-] Receiver bellows shadowing loss factor - util::matrix_t Dirt_HCE; //[-] Loss due to dirt on the receiver envelope - util::matrix_t Design_loss; //[-] Receiver heat loss at design - util::matrix_t SCAInfoArray; //[-] Receiver (,1) and collector (,2) type for each assembly in loop - - bool calc_design_pipe_vals; //[-] Should the HTF state be calculated at design conditions - double L_rnr_pb; //[m] Length of hot or cold runner pipe around the power block - double N_max_hdr_diams; //[-] Maximum number of allowed diameters in each of the hot and cold headers - double L_rnr_per_xpan; //[m] Threshold length of straight runner pipe without an expansion loop - double L_xpan_hdr; //[m] Combined length in meters of the two perpendicular segments of a header expansion loop - double L_xpan_rnr; //[m] Combined length in meters of the two perpendicular segments of a runner expansion loop - double Min_rnr_xpans; //[-] Minimum number of expansion loops per single-diameter runner section - double northsouth_field_sep; //[m] Shortest north/south distance between SCAs in different subfields - double N_hdr_per_xpan; //[-] Number of collector loops per header expansion loops. 1expansion loop between every collector loop - util::matrix_t K_cpnt; //[-] Minor loss coefficients of the components in each loop interconnect - util::matrix_t D_cpnt; //[m] Inner diameters of the components in each loop interconnect - util::matrix_t L_cpnt; //[m] Lengths of the components in each loop interconnect - util::matrix_t Type_cpnt; //[-] Type of component in each loop interconnect [0=fitting | 1=pipe | 2=flex_hose] - bool custom_sf_pipe_sizes; //[-] Should the field pipe diameters, wall thickness and lengths be imported instead of calculated - util::matrix_t sf_rnr_diams; //[m] Imported runner diameters, used if custom_sf_pipe_sizes is true - util::matrix_t sf_rnr_wallthicks; //[m] Imported runner wall thicknesses, used if custom_sf_pipe_sizes is true - util::matrix_t sf_rnr_lengths; //[m] Imported runner lengths, used if custom_sf_pipe_sizes is true - util::matrix_t sf_hdr_diams; //[m] Imported header diameters, used if custom_sf_pipe_sizes is true - util::matrix_t sf_hdr_wallthicks; //[m] Imported header wall thicknesses, used if custom_sf_pipe_sizes is true - util::matrix_t sf_hdr_lengths; //[m] Imported header lengths, used if custom_sf_pipe_sizes is true - - void SetUp() - { - nSCA = 8; - nHCEt = 4; - nColt = 4; - nHCEVar = 4; - nLoops = 181; - FieldConfig = 2; - L_power_block_piping = 50.; - include_fixed_power_block_runner = true; - eta_pump = 0.85; - Fluid = 21; - fthrctrl = 2; - accept_loc = 1; - HDR_rough = 4.57e-5; - theta_stow = 170.; - theta_dep = 10.; - Row_Distance = 15.; - - T_loop_in_des = 293.; - T_loop_out_des = 391.; - T_startup = 0.67*T_loop_in_des + 0.33*T_loop_out_des; //[C] - m_dot_htfmin = 1.; - m_dot_htfmax = 12.; - double vals[] = { 0 }; - field_fl_props.assign(vals, 1, 1); - T_fp = 150.; - I_bn_des = 950.; - V_hdr_cold_max = 3.; - V_hdr_cold_min = 2.; - V_hdr_hot_max = 3.; - V_hdr_hot_min = 2.; - V_hdr_max = std::min(V_hdr_cold_max, V_hdr_hot_max); - V_hdr_min = std::max(V_hdr_cold_min, V_hdr_hot_min); - Pipe_hl_coef = 0.45; - SCA_drives_elec = 125.; - ColTilt = 0.; - ColAz = 0.; - wind_stow_speed = 25.; - accept_mode = 0; - accept_init = false; - solar_mult = 2.; - mc_bal_hot_per_MW = 0.2; - mc_bal_cold_per_MW = 0.2; - mc_bal_sca = 4.5; - - W_aperture = { 6, 6, 6, 6 }; - A_aperture = { 656, 656, 656, 656 }; - TrackingError = { 0.988, 0.988, 0.988, 0.988 }; - GeomEffects = { 0.952, 0.952, 0.952, 0.952 }; - Rho_mirror_clean = { 0.93, 0.93, 0.93, 0.93 }; - Dirt_mirror = { 0.97, 0.97, 0.97, 0.97 }; - Error = { 1., 1., 1., 1. }; - Ave_Focal_Length = { 2.15, 2.15, 2.15, 2.15 }; - L_SCA = { 115., 115., 115., 115. }; - L_aperture = { 14.375, 14.375, 14.375, 14.375 }; - ColperSCA = { 8., 8., 8., 8. }; - Distance_SCA = { 1., 1., 1., 1. }; - - double vals2[] = { - 1, 0.0327, -0.1351, - 1, 0.0327, -0.1351, - 1, 0.0327, -0.1351, - 1, 0.0327, -0.1351 }; - IAM_matrix.assign(vals2, 4, 3); - - double vals3[] = { - 0.985, 0.01, 0.005, 0., - 1., 0., 0., 0., - 1., 0., 0., 0., - 1., 0., 0., 0. }; - HCE_FieldFrac.assign(vals3, 4, 4); - - double vals4[] = { - 0.076, 0.076, 0.076, 0.076, - 0.076, 0.076, 0.076, 0.076, - 0.076, 0.076, 0.076, 0.076, - 0.076, 0.076, 0.076, 0.076 }; - D_2.assign(vals4, 4, 4); - - double vals5[] = { - 0.08, 0.08, 0.08, 0.08, - 0.08, 0.08, 0.08, 0.08, - 0.08, 0.08, 0.08, 0.08, - 0.08, 0.08, 0.08, 0.08 }; - D_3.assign(vals5, 4, 4); - - double vals6[] = { - 0.115, 0.115, 0.115, 0.115, - 0.115, 0.115, 0.115, 0.115, - 0.115, 0.115, 0.115, 0.115, - 0.115, 0.115, 0.115, 0.115 }; - D_4.assign(vals6, 4, 4); - - double vals7[] = { - 0.12, 0.12, 0.12, 0.12, - 0.12, 0.12, 0.12, 0.12, - 0.12, 0.12, 0.12, 0.12, - 0.12, 0.12, 0.12, 0.12 }; - D_5.assign(vals7, 4, 4); - - double vals8[] = { - 0., 0., 0., 0., - 0., 0., 0., 0., - 0., 0., 0., 0., - 0., 0., 0., 0. }; - D_p.assign(vals8, 4, 4); - - double vals9[] = { - 1., 1., 1., 1., - 1., 1., 1., 1., - 1., 1., 1., 1., - 1., 1., 1., 1. }; - Flow_type.assign(vals9, 4, 4); - - double vals10[] = { - 4.5e-5, 4.5e-5, 4.5e-5, 4.5e-5, - 4.5e-5, 4.5e-5, 4.5e-5, 4.5e-5, - 4.5e-5, 4.5e-5, 4.5e-5, 4.5e-5, - 4.5e-5, 4.5e-5, 4.5e-5, 4.5e-5 }; - Rough.assign(vals10, 4, 4); - - double vals11[] = { - 0.02, 0.02, 0., 0., - 0.02, 0.02, 0., 0., - 0.02, 0.02, 0., 0., - 0.02, 0.02, 0., 0. }; - alpha_env.assign(vals11, 4, 4); - - double vals12[] = { - 100., 150., 200., 250., 300., 350., 400., 450., 500., - 0.064, 0.0665, 0.07, 0.0745, 0.08, 0.0865, 0.094, 0.1025, 0.112 }; - epsilon_3_11.assign(vals12, 2, 9); - - double vals13[] = { 0.65 }; - epsilon_3_12.assign(vals13, 1, 1); - - double vals14[] = { 0.65 }; - epsilon_3_13.assign(vals14, 1, 1); - - double vals15[] = { 0. }; - epsilon_3_14.assign(vals15, 0, 0); - - double vals16[] = { - 100., 150., 200., 250., 300., 350., 400., 450., 500., - 0.064, 0.0665, 0.07, 0.0745, 0.08, 0.0865, 0.094, 0.1025, 0.112 }; - epsilon_3_21.assign(vals16, 2, 9); - - double vals17[] = { 0.65 }; - epsilon_3_22.assign(vals17, 1, 1); - - double vals18[] = { 0.65 }; - epsilon_3_23.assign(vals18, 1, 1); - - double vals19[] = { 0. }; - epsilon_3_24.assign(vals19, 1, 1); - - double vals20[] = { - 100., 150., 200., 250., 300., 350., 400., 450., 500., - 0.064, 0.0665, 0.07, 0.0745, 0.08, 0.0865, 0.094, 0.1025, 0.112 }; - epsilon_3_31.assign(vals20, 2, 9); - - double vals21[] = { 0.65 }; - epsilon_3_32.assign(vals21, 1, 1); - - double vals22[] = { 0.65 }; - epsilon_3_33.assign(vals22, 1, 1); - - double vals23[] = { 0. }; - epsilon_3_34.assign(vals23, 1, 1); - - double vals24[] = { - 100., 150., 200., 250., 300., 350., 400., 450., 500., - 0.064, 0.0665, 0.07, 0.0745, 0.08, 0.0865, 0.094, 0.1025, 0.112 }; - epsilon_3_41.assign(vals24, 2, 9); - - double vals25[] = { 0.65 }; - epsilon_3_42.assign(vals25, 1, 1); - - double vals26[] = { 0.65 }; - epsilon_3_43.assign(vals26, 1, 1); - - double vals27[] = { 0. }; - epsilon_3_44.assign(vals27, 1, 1); - - double vals28[] = { - 0.963, 0.963, 0.8, 0., - 0.963, 0.963, 0.8, 0., - 0.963, 0.963, 0.8, 0., - 0.963, 0.963, 0.8, 0.}; - alpha_abs.assign(vals28, 4, 4); - - double vals29[] = { - 0.964, 0.964, 1., 0., - 0.964, 0.964, 1., 0., - 0.964, 0.964, 1., 0., - 0.964, 0.964, 1., 0.}; - Tau_envelope.assign(vals29, 4, 4); - - double vals30[] = { - 0.86, 0.86, 1., 0., - 0.86, 0.86, 1., 0., - 0.86, 0.86, 1., 0., - 0.86, 0.86, 1., 0.}; - EPSILON_4.assign(vals30, 4, 4); - - double vals31[] = { - 0.86, 0.86, 1., 0., - 0.86, 0.86, 1., 0., - 0.86, 0.86, 1., 0., - 0.86, 0.86, 1., 0. }; - EPSILON_5.assign(vals31, 4, 4); - - double vals32[] = { - 1., 1., 0., 1., - 1., 1., 0., 1., - 1., 1., 0., 1., - 1., 1., 0., 1.}; - GlazingIntact_dbl.assign(vals32, 4, 4); - // convert to - int n_gl_row = (int)GlazingIntact_dbl.nrows(); - int n_gl_col = (int)GlazingIntact_dbl.ncols(); - GlazingIntact.resize(n_gl_row, n_gl_col); - for (int i = 0; i < n_gl_row; i++) { - for (int j = 0; j < n_gl_col; j++) { - GlazingIntact(i, j) = (GlazingIntact_dbl(i, j) > 0); - } - } - - double vals33[] = { - 1.e-4, 750., 750., 0., - 1.e-4, 750., 750., 0., - 1.e-4, 750., 750., 0., - 1.e-4, 750., 750., 0., }; - P_a.assign(vals33, 4, 4); - - double vals34[] = { - 27., 1., 1., 27., - 27., 1., 1., 27., - 27., 1., 1., 27., - 27., 1., 1., 27., }; - AnnulusGas.assign(vals34, 4, 4); - - double vals35[] = { - 1., 1., 1., 1., - 1., 1., 1., 1., - 1., 1., 1., 1., - 1., 1., 1., 1., }; - AbsorberMaterial.assign(vals35, 4, 4); - - double vals36[] = { - 0.935, 0.935, 0.935, 0.963, - 0.935, 0.935, 0.935, 0.963, - 0.935, 0.935, 0.935, 0.963, - 0.935, 0.935, 0.935, 0.963}; - Shadowing.assign(vals36, 4, 4); - - double vals37[] = { - 0.98, 0.98, 1., 0.98, - 0.98, 0.98, 1., 0.98, - 0.98, 0.98, 1., 0.98, - 0.98, 0.98, 1., 0.98, }; - Dirt_HCE.assign(vals37, 4, 4); - - double vals38[] = { - 190., 1270., 1500., 0., - 190., 1270., 1500., 0., - 190., 1270., 1500., 0., - 190., 1270., 1500., 0.}; - Design_loss.assign(vals38, 4, 4); - - double vals39[] = { - 1., 1., - 1., 1., - 1., 1., - 1., 1., - 1., 1., - 1., 1., - 1., 1., - 1., 1.}; - SCAInfoArray.assign(vals39, 8, 2); - - calc_design_pipe_vals = true; - L_rnr_pb = 25.; - N_max_hdr_diams = 10.; - L_rnr_per_xpan = 70.; - L_xpan_hdr = 20.; - L_xpan_rnr = 20.; - Min_rnr_xpans = 1.; - northsouth_field_sep = 20.; - N_hdr_per_xpan = 2.; - - double vals40[] = { - 0.9, 0., 0.19, 0., 0.9, -1., -1., -1., -1., -1., -1., - 0., 0.6, 0.05, 0., 0.6, 0., 0.6, 0., 0.42, 0., 0.15, - 0.05, 0., 0.42, 0., 0.6, 0., 0.6, 0., 0.42, 0., 0.15, - 0.05, 0., 0.42, 0., 0.6, 0., 0.6, 0., 0.42, 0., 0.15, - 0.05, 0., 0.42, 0., 0.6, 0., 0.6, 0., 0.42, 0., 0.15, - 0.05, 0., 0.42, 0., 0.6, 0., 0.6, 0., 0.42, 0., 0.15, - 0.05, 0., 0.42, 0., 0.6, 0., 0.6, 0., 0.42, 0., 0.15, - 0.05, 0., 0.42, 0., 0.6, 0., 0.6, 0., 0.42, 0., 0.15, - 0.05, 0., 0.42, 0., 0.6, 0., 0.6, 0., 0.42, 0., 0.15, - 0.05, 0., 0.42, 0., 0.6, 0., 0.6, 0., 0.15, 0.6, 0., - 0.9, 0., 0.19, 0., 0.9, -1., -1., -1., -1., -1., -1.}; - K_cpnt.assign(vals40, 11, 11); - - double vals41[] = { - 0.085, 0.0635, 0.085, 0.0635, 0.085, -1., -1., -1., -1., -1., -1., - 0.085, 0.085, 0.085, 0.0635, 0.0635, 0.0635,0.0635, 0.0635, 0.0635, 0.0635, 0.085, - 0.085, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.085, - 0.085, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.085, - 0.085, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.085, - 0.085, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.085, - 0.085, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.085, - 0.085, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.085, - 0.085, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635, 0.085, - 0.085, 0.0635, 0.0635, 0.0635, 0.0635, 0.0635,0.0635, 0.0635, 0.085, 0.085, 0.085, - 0.085, 0.0635, 0.085, 0.0635, 0.085, -1., -1., -1., -1., -1., -1.}; - D_cpnt.assign(vals41, 11, 11); - - double vals42[] = { - 0., 0., 0., 0., 0., -1., -1., -1., -1., -1., -1., - 0., 0., 0., 1., 0., 0., 0., 1., 0., 1., 0., - 0., 1., 0., 1., 0., 0., 0., 1., 0., 1., 0., - 0., 1., 0., 1., 0., 0., 0., 1., 0., 1., 0., - 0., 1., 0., 1., 0., 0., 0., 1., 0., 1., 0., - 0., 1., 0., 1., 0., 0., 0., 1., 0., 1., 0., - 0., 1., 0., 1., 0., 0., 0., 1., 0., 1., 0., - 0., 1., 0., 1., 0., 0., 0., 1., 0., 1., 0., - 0., 1., 0., 1., 0., 0., 0., 1., 0., 1., 0., - 0., 1., 0., 1., 0., 0., 0., 1., 0., 0., 0., - 0., 0., 0., 0., 0., -1., -1., -1., -1., -1., -1.}; - L_cpnt.assign(vals42, 11, 11); - - double vals43[] = { - 0., 1., 0., 1., 0., -1., -1., -1., -1., -1., -1., - 1., 0., 0., 2., 0., 1., 0., 2., 0., 2., 0., - 0., 2., 0., 2., 0., 1., 0., 2., 0., 2., 0., - 0., 2., 0., 2., 0., 1., 0., 2., 0., 2., 0., - 0., 2., 0., 2., 0., 1., 0., 2., 0., 2., 0., - 0., 2., 0., 2., 0., 1., 0., 2., 0., 2., 0., - 0., 2., 0., 2., 0., 1., 0., 2., 0., 2., 0., - 0., 2., 0., 2., 0., 1., 0., 2., 0., 2., 0., - 0., 2., 0., 2., 0., 1., 0., 2., 0., 2., 0., - 0., 2., 0., 2., 0., 1., 0., 2., 0., 0., 1., - 0., 1., 0., 1., 0., -1., -1., -1., -1., -1., -1.}; - Type_cpnt.assign(vals43, 11, 11); - - custom_sf_pipe_sizes = false; - - double vals44[] = { -1. }; - sf_rnr_diams.assign(vals44, 1, 1); - - double vals45[] = { -1 }; - sf_rnr_wallthicks.assign(vals45, 1, 1); - - double vals46[] = { -1 }; - sf_rnr_lengths.assign(vals46, 1, 1); - - double vals47[] = { -1 }; - sf_hdr_diams.assign(vals47, 1, 1); - - double vals48[] = { -1 }; - sf_hdr_wallthicks.assign(vals48, 1, 1); - - double vals49[] = { -1 }; - sf_hdr_lengths.assign(vals49, 1, 1); - } - - //nothing to do - void TearDown(){} -}; - -#endif \ No newline at end of file diff --git a/test/tcs_test/lib_trough_test.cpp b/test/tcs_test/lib_trough_test.cpp deleted file mode 100644 index 48388afcfe5..00000000000 --- a/test/tcs_test/lib_trough_test.cpp +++ /dev/null @@ -1,174 +0,0 @@ -#include - -#define private public // for setting private data members -#include "lib_trough_test.h" -/* -TEST_F(TroughTest, DefocusTest_csp_solver_trough_collector_receiver) -{ - // at time 1476 (1477 end time listed in output) - weatherValues.m_year = 2009; - weatherValues.m_month = 3; - weatherValues.m_day = 3; - weatherValues.m_hour = 12; - weatherValues.m_minute = 0; - weatherValues.m_beam = 488; - weatherValues.m_tdry = 27; - weatherValues.m_tdew = -4; - weatherValues.m_wspd = 3; - weatherValues.m_pres = 920; - weatherValues.m_solazi = 166.04812459961; - weatherValues.m_solzen = 39.5823887774745; - - htfInletState.m_temp = 297.95980959101303; //297.95980959101303; - defocus = 0.77316; - - troughInfo.ms_ts.m_time_start = 5313600.; - troughInfo.ms_ts.m_time = 5317200.; - troughInfo.ms_ts.m_step = 3600.; - troughInfo.m_tou = 1.; - - // previous HTF temperatures [K] - troughModel->m_T_sys_c_t_end_converged = 571.979992782819; // this sets m_T_sys_c_t_end_last - troughModel->m_T_sys_h_t_end_converged = 663.79113603342; // this sets m_T_sys_h_t_end_last - // SCA temperatures - these set the values of m_T_htf_out_t_end_last[i] - troughModel->m_T_htf_out_t_end_converged[0] = 585.2012765; - troughModel->m_T_htf_out_t_end_converged[1] = 597.5706153; - troughModel->m_T_htf_out_t_end_converged[2] = 609.5327793; - troughModel->m_T_htf_out_t_end_converged[3] = 621.1103321; - troughModel->m_T_htf_out_t_end_converged[4] = 632.2659289; - troughModel->m_T_htf_out_t_end_converged[5] = 643.1282423; - troughModel->m_T_htf_out_t_end_converged[6] = 653.6533931; - troughModel->m_T_htf_out_t_end_converged[7] = 663.8068978; - - - troughModel->on(weatherValues, htfInletState, defocus, troughOutputs, troughInfo); - - EXPECT_NEAR(troughOutputs.m_T_salt_hot, 390.98, 390.98 * m_error_tolerance_lo); - EXPECT_NEAR(troughOutputs.m_m_dot_salt_tot, 2443500., 2443500. * m_error_tolerance_lo); - - - //// Change defocus, increase by 0.0013% - //defocus = 0.77317; - //troughModel->on(weatherValues, htfInletState, defocus, troughOutputs, troughInfo); - - //EXPECT_NEAR(troughOutputs.m_T_salt_hot, 390.39, 390.39 * m_error_tolerance_lo); - //EXPECT_NEAR(troughOutputs.m_m_dot_salt_tot, 2494962., 2494962. * m_error_tolerance_lo); - //// mass flow increases by 2.1% -} - -TEST_F(TroughTest, DefocusTest2_csp_solver_trough_collector_receiver) -{ - // at time 1068 (1069 end time listed in output) - weatherValues.m_year = 2009; - weatherValues.m_month = 2; - weatherValues.m_day = 14; - weatherValues.m_hour = 12; - weatherValues.m_minute = 0; - weatherValues.m_beam = 1016.0; - weatherValues.m_tdry = 16.0; - weatherValues.m_tdew = -14.0; - weatherValues.m_wspd = 1.2; - weatherValues.m_pres = 920.0; - weatherValues.m_solazi = 167.05961724080794; - weatherValues.m_solzen = 45.793932659900818; - - htfInletState.m_temp = 296.47387218057872; // 289.38622217774684; - defocus = 0.31113892655015696; - - troughInfo.ms_ts.m_time_start = 3844800.; - troughInfo.ms_ts.m_time = 3848400.; - troughInfo.ms_ts.m_step = 3600.; - troughInfo.m_tou = 1.; - - // previous HTF temperatures [K] - troughModel->m_T_sys_c_t_end_converged = 574.56624498543692; // this sets m_T_sys_c_t_end_last - troughModel->m_T_sys_h_t_end_converged = 664.49041436768960; // this sets m_T_sys_h_t_end_last - // SCA temperatures - these set the values of m_T_htf_out_t_end_last[i] - troughModel->m_T_htf_out_t_end_converged[0] = 586.54320898265996; - troughModel->m_T_htf_out_t_end_converged[1] = 598.40229621263472; - troughModel->m_T_htf_out_t_end_converged[2] = 610.02021991454296; - troughModel->m_T_htf_out_t_end_converged[3] = 621.40305775456318; - troughModel->m_T_htf_out_t_end_converged[4] = 632.53459357521194; - troughModel->m_T_htf_out_t_end_converged[5] = 643.46237590525539; - troughModel->m_T_htf_out_t_end_converged[6] = 654.17081551318063; - troughModel->m_T_htf_out_t_end_converged[7] = 664.58682197556709; - - - troughModel->on(weatherValues, htfInletState, defocus, troughOutputs, troughInfo); - - EXPECT_NEAR(troughOutputs.m_T_salt_hot, 390.96, 390.96 * m_error_tolerance_lo); - EXPECT_NEAR(troughOutputs.m_m_dot_salt_tot, 1705004.8, 1705004.8 * m_error_tolerance_lo); -} - -TEST_F(TroughTest, SteadyStateTest_csp_solver_trough_collector_receiver) -{ - troughModel->m_accept_mode = 1; // flag so solar zenith from weather is used instead of calc'd - troughModel->m_accept_init = false; // running at steady-state but keeping false to avoid side effects - troughModel->m_accept_loc = 1; // don't just model a single loop - troughModel->m_is_using_input_gen = false; // use parameter values set below instead - - // at time 1476 (1477 end time listed in output) - weatherValues.m_year = 2009; - weatherValues.m_month = 6; - weatherValues.m_day = 21; - weatherValues.m_hour = 12; - weatherValues.m_minute = 0; - weatherValues.m_beam = troughModel->m_I_bn_des; - weatherValues.m_tdry = 30; - weatherValues.m_tdew = 30 - 10; - weatherValues.m_wspd = 5; - weatherValues.m_pres = 1013; - weatherValues.m_solazi = troughModel->m_ColAz; - weatherValues.m_solzen = troughModel->m_ColTilt; - - //htfInletState.m_m_dot = troughModel->m_m_dot_design; - //htfInletState.m_pres = 101.3; - //htfInletState.m_qual = 0; - htfInletState.m_temp = troughModel->m_T_loop_in_des - 273.15; - defocus = 1.0; - - troughInfo.ms_ts.m_time_start = 14817600.; - troughInfo.ms_ts.m_step = 5.*60.; // 5-minute timesteps - troughInfo.ms_ts.m_time = troughInfo.ms_ts.m_time_start + troughInfo.ms_ts.m_step; - troughInfo.m_tou = 1.; - - troughModel->m_T_sys_c_t_end_converged = htfInletState.m_temp + 273.15; // this sets m_T_sys_c_t_end_last - troughModel->m_T_sys_h_t_end_converged = htfInletState.m_temp + 273.15; // this sets m_T_sys_h_t_end_last - troughModel->m_T_htf_out_t_end_converged.assign(troughModel->m_nSCA, htfInletState.m_temp + 273.15); - - // Values for checking whether steady-state - double ss_diff = std::numeric_limits::quiet_NaN(); - const double tol = 0.05; - std::vector T_htf_in_t_int_prev = troughModel->m_T_htf_in_t_int; - std::vector T_htf_out_t_int_prev = troughModel->m_T_htf_out_t_int; - double minutes2SS = 0.; - - do - { - troughModel->on(weatherValues, htfInletState, defocus, troughOutputs, troughInfo); - - // Calculate metric for deciding whether steady-state is reached - ss_diff = 0.; - for (int i = 0; i < troughModel->m_nSCA; i++) { - ss_diff += fabs(troughModel->m_T_htf_in_t_int[i] - T_htf_in_t_int_prev[i]) + - fabs(troughModel->m_T_htf_out_t_int[i] - T_htf_out_t_int_prev[i]); - } - - // Set converged values so reset_last_temps() propagates the temps in time - troughModel->m_T_sys_c_t_end_converged = troughModel->m_T_sys_c_t_end; - troughModel->m_T_sys_h_t_end_converged = troughModel->m_T_sys_h_t_end; - // SCA temperatures - these set the values of m_T_htf_out_t_end_last[i] - troughModel->m_T_htf_out_t_end_converged = troughModel->m_T_htf_out_t_end; - - // Update 'last' values - T_htf_in_t_int_prev = troughModel->m_T_htf_in_t_int; - T_htf_out_t_int_prev = troughModel->m_T_htf_out_t_int; - - minutes2SS += troughInfo.ms_ts.m_step / 60.; - - } while (ss_diff / 200. > tol); - - EXPECT_NEAR(troughModel->m_T_sys_h_t_end, 656.3, 656.3 * m_error_tolerance_lo); - EXPECT_NEAR(minutes2SS, 40., 40. * m_error_tolerance_hi); -} -*/ \ No newline at end of file diff --git a/test/tcs_test/lib_trough_test.h b/test/tcs_test/lib_trough_test.h deleted file mode 100644 index f93eb5f5f8a..00000000000 --- a/test/tcs_test/lib_trough_test.h +++ /dev/null @@ -1,193 +0,0 @@ -#ifndef __LIB_TROUGH_TEST_H__ -#define __LIB_TROUGH_TEST_H__ - -#include -#include "csp_solver_trough_collector_receiver.h" - -#include "lib_trough_properties.h" - -class TroughTest : public TroughProperties -{ -protected: - C_csp_trough_collector_receiver *troughModel; - C_csp_collector_receiver::S_csp_cr_init_inputs troughInitInputs; // for init() - C_csp_collector_receiver::S_csp_cr_solved_params troughSolvedParams; // for init() - - C_csp_weatherreader::S_outputs weatherValues; - C_csp_solver_htf_1state htfInletState; - double defocus; - C_csp_solver_sim_info troughInfo; - C_csp_collector_receiver::S_csp_cr_out_solver troughOutputs; - -public: - double m_error_tolerance_lo = 0.001; // 0.1% - double m_error_tolerance_hi = 0.01; // 1.0% - - void SetUp() { - TroughProperties::SetUp(); - troughModel = new C_csp_trough_collector_receiver(); - - troughModel->m_nSCA = nSCA; - troughModel->m_nHCEt = nHCEt; - troughModel->m_nColt = nColt; - troughModel->m_nHCEVar = nHCEVar; - troughModel->m_nLoops = nLoops; - troughModel->m_FieldConfig = FieldConfig; - troughModel->m_L_power_block_piping = L_power_block_piping; - troughModel->m_include_fixed_power_block_runner = include_fixed_power_block_runner; - troughModel->m_eta_pump = eta_pump; - troughModel->m_Fluid = Fluid; - //troughModel->m_fthrok = fthrok; - troughModel->m_fthrctrl = fthrctrl; - troughModel->m_accept_loc = accept_loc; - troughModel->m_HDR_rough = HDR_rough; - troughModel->m_theta_stow = theta_stow; - troughModel->m_theta_dep = theta_dep; - troughModel->m_Row_Distance = Row_Distance; - - troughModel->m_T_loop_in_des = T_loop_in_des; - troughModel->m_T_loop_out_des = T_loop_out_des; - troughModel->m_T_startup = T_startup; - troughModel->m_m_dot_htfmin = m_dot_htfmin; - troughModel->m_m_dot_htfmax = m_dot_htfmax; - troughModel->m_field_fl_props = field_fl_props; - troughModel->m_T_fp = T_fp; - troughModel->m_I_bn_des = I_bn_des; - troughModel->m_V_hdr_cold_max = V_hdr_cold_max; - troughModel->m_V_hdr_cold_min = V_hdr_cold_min; - troughModel->m_V_hdr_hot_max = V_hdr_hot_max; - troughModel->m_V_hdr_hot_min = V_hdr_hot_min; - troughModel->m_V_hdr_max = V_hdr_max; - troughModel->m_V_hdr_min = V_hdr_min; - troughModel->m_Pipe_hl_coef = Pipe_hl_coef; - troughModel->m_SCA_drives_elec = SCA_drives_elec; - troughModel->m_ColTilt = ColTilt; - troughModel->m_ColAz = ColAz; - troughModel->m_wind_stow_speed = wind_stow_speed; - troughModel->m_accept_mode = accept_mode; - troughModel->m_accept_init = accept_init; - troughModel->m_solar_mult = solar_mult; - troughModel->m_mc_bal_hot_per_MW = mc_bal_hot_per_MW; - troughModel->m_mc_bal_cold_per_MW = mc_bal_cold_per_MW; - troughModel->m_mc_bal_sca = mc_bal_sca; - - troughModel->m_W_aperture = W_aperture; - troughModel->m_A_aperture = A_aperture; - troughModel->m_TrackingError = TrackingError; - troughModel->m_GeomEffects = GeomEffects; - troughModel->m_Rho_mirror_clean = Rho_mirror_clean; - troughModel->m_Dirt_mirror = Dirt_mirror; - troughModel->m_Error = Error; - troughModel->m_Ave_Focal_Length = Ave_Focal_Length; - troughModel->m_L_SCA = L_SCA; - troughModel->m_L_aperture = L_aperture; - troughModel->m_ColperSCA = ColperSCA; - troughModel->m_Distance_SCA = Distance_SCA; - - troughModel->m_IAM_matrix = IAM_matrix; - troughModel->m_HCE_FieldFrac = HCE_FieldFrac; - troughModel->m_D_2 = D_2; - troughModel->m_D_3 = D_3; - troughModel->m_D_4 = D_4; - troughModel->m_D_5 = D_5; - troughModel->m_D_p = D_p; - troughModel->m_Flow_type = Flow_type; - troughModel->m_Rough = Rough; - troughModel->m_alpha_env = alpha_env; - - troughModel->m_epsilon_3_11 = epsilon_3_11; - troughModel->m_epsilon_3_12 = epsilon_3_12; - troughModel->m_epsilon_3_13 = epsilon_3_13; - troughModel->m_epsilon_3_14 = epsilon_3_14; - troughModel->m_epsilon_3_21 = epsilon_3_21; - troughModel->m_epsilon_3_22 = epsilon_3_22; - troughModel->m_epsilon_3_23 = epsilon_3_23; - troughModel->m_epsilon_3_24 = epsilon_3_24; - troughModel->m_epsilon_3_31 = epsilon_3_31; - troughModel->m_epsilon_3_32 = epsilon_3_32; - troughModel->m_epsilon_3_33 = epsilon_3_33; - troughModel->m_epsilon_3_34 = epsilon_3_34; - troughModel->m_epsilon_3_41 = epsilon_3_41; - troughModel->m_epsilon_3_42 = epsilon_3_42; - troughModel->m_epsilon_3_43 = epsilon_3_43; - troughModel->m_epsilon_3_44 = epsilon_3_44; - - troughModel->m_alpha_abs = alpha_abs; - troughModel->m_Tau_envelope = Tau_envelope; - troughModel->m_EPSILON_4 = EPSILON_4; - troughModel->m_EPSILON_5 = EPSILON_5; - troughModel->m_GlazingIntact = GlazingIntact; - troughModel->m_P_a = P_a; - troughModel->m_AnnulusGas = AnnulusGas; - troughModel->m_AbsorberMaterial = AbsorberMaterial; - troughModel->m_Shadowing = Shadowing; - troughModel->m_Dirt_HCE = Dirt_HCE; - troughModel->m_Design_loss = Design_loss; - troughModel->m_SCAInfoArray = SCAInfoArray; - - troughModel->m_calc_design_pipe_vals = calc_design_pipe_vals; - troughModel->m_L_rnr_pb = L_rnr_pb; - troughModel->m_N_max_hdr_diams = N_max_hdr_diams; - troughModel->m_L_rnr_per_xpan = L_rnr_per_xpan; - troughModel->m_L_xpan_hdr = L_xpan_hdr; - troughModel->m_L_xpan_rnr = L_xpan_rnr; - troughModel->m_Min_rnr_xpans = Min_rnr_xpans; - troughModel->m_northsouth_field_sep = northsouth_field_sep; - troughModel->m_N_hdr_per_xpan = N_hdr_per_xpan; - troughModel->m_K_cpnt = K_cpnt; - troughModel->m_D_cpnt = D_cpnt; - troughModel->m_L_cpnt = L_cpnt; - troughModel->m_Type_cpnt = Type_cpnt; - troughModel->m_custom_sf_pipe_sizes = custom_sf_pipe_sizes; - troughModel->m_sf_rnr_diams = sf_rnr_diams; - troughModel->m_sf_rnr_wallthicks = sf_rnr_wallthicks; - troughModel->m_sf_rnr_lengths = sf_rnr_lengths; - troughModel->m_sf_hdr_diams = sf_hdr_diams; - troughModel->m_sf_hdr_wallthicks = sf_hdr_wallthicks; - troughModel->m_sf_hdr_lengths = sf_hdr_lengths; - - // init inputs - troughInitInputs.m_latitude = 32.13000107; - troughInitInputs.m_longitude = -110.9400024; - troughInitInputs.m_tz = -7; - troughInitInputs.m_shift = -5.940002441; - troughInitInputs.m_elev = -773; - - troughModel->init(troughInitInputs, troughSolvedParams); - - // inputs, constant or unused - weatherValues.m_lat = 32.13000107; - weatherValues.m_lon = -110.9400024; - weatherValues.m_tz = -7; - weatherValues.m_shift = -5.940002441; - weatherValues.m_elev = 773; - weatherValues.m_global = std::numeric_limits::quiet_NaN(); - weatherValues.m_hor_beam = std::numeric_limits::quiet_NaN(); // 433.1 - weatherValues.m_diffuse = std::numeric_limits::quiet_NaN(); // 282 - weatherValues.m_twet = std::numeric_limits::quiet_NaN(); - weatherValues.m_wdir = std::numeric_limits::quiet_NaN(); // 88 - weatherValues.m_rhum = std::numeric_limits::quiet_NaN(); - weatherValues.m_snow = std::numeric_limits::quiet_NaN(); - weatherValues.m_albedo = std::numeric_limits::quiet_NaN(); // 0.213 - weatherValues.m_aod = std::numeric_limits::quiet_NaN(); - weatherValues.m_poa = std::numeric_limits::quiet_NaN(); // 715.1 - weatherValues.m_time_rise = std::numeric_limits::quiet_NaN(); // 7.486443134 - weatherValues.m_time_set = std::numeric_limits::quiet_NaN(); // 17.46109472 - - htfInletState.m_pres = std::numeric_limits::quiet_NaN(); - htfInletState.m_qual = -1.; - htfInletState.m_m_dot = std::numeric_limits::quiet_NaN(); - } - - void TearDown() - { - TroughProperties::TearDown(); - if (troughModel) { - delete troughModel; - troughModel = nullptr; - } - } - -}; - -#endif diff --git a/test/tcs_test/tcsdirect_steam_cases.h b/test/tcs_test/tcsdirect_steam_cases.h deleted file mode 100644 index 6786842b892..00000000000 --- a/test/tcs_test/tcsdirect_steam_cases.h +++ /dev/null @@ -1,168 +0,0 @@ -#ifndef _TCSDIRECT_STEAM_CASES_H_ -#define _TCSDIRECT_STEAM_CASES_H_ - -#include -#include "../input_cases/code_generator_utilities.h" -#include "tcsdirect_steam_common_data.h" - -/** -* Data for high-level integration tests that verifies whether results for a direct steam power tower -* plant in Tucson, AZ matches expected results. -* Data generated from code-generator (Shift+F5) within SAM UI. -* Test uses SSCAPI interfaces (similiar to SDK usage) to pass and receive data to tcsdirect_steam -*/ - -// Power Tower direct steam default congifuration -int tcsdirect_steam_daggett_default(ssc_data_t &data) -{ - tcsdirect_steam_default(data); - - int status = run_module(data, "tcsdirect_steam"); - - //single_owner_default(data); - //status += run_module(data, "singleowner"); - - return status; -} - -// Power Tower direct steam with alternative condenser type -// Condenser type: Evaporative -// Rest default configurations -int tcsdirect_steam_daggett_evap_condenser(ssc_data_t &data) -{ - tcsdirect_steam_default(data); - - ssc_data_set_number(data, "ct", 1); - ssc_data_set_number(data, "eta_ref", 0.404); - ssc_data_set_number(data, "startup_frac", 0.5); - ssc_data_set_number(data, "P_cond_min", 2); - - int status = run_module(data, "tcsdirect_steam"); - - return status; -} - -// Power Tower direct steam with alternative condenser type -// Condenser type: Hybrid -// Rest default configurations -int tcsdirect_steam_daggett_hybrid_condenser(ssc_data_t &data) -{ - tcsdirect_steam_default(data); - - ssc_data_set_number(data, "ct", 3); - ssc_data_set_number(data, "eta_ref", 0.404); - ssc_data_set_number(data, "startup_frac", 0.5); - ssc_data_set_number(data, "P_cond_min", 2); - - int status = run_module(data, "tcsdirect_steam"); - - return status; -} - -// Power Tower direct steam with alternative fossil dispatch mode -// Fossil dispatch mode: Supplemental operation -// Rest default configurations -//int tcsdirect_steam_daggett_fossil_dispatch_supplemental(ssc_data_t &data) -//{ -// tcsdirect_steam_default(data); -// -// ssc_data_set_number(data, "fossil_mode", 2); -// ssc_data_set_number(data, "eta_ref", 0.404); -// ssc_data_set_number(data, "startup_frac", 0.5); -// ssc_data_set_number(data, "P_cond_min", 2); -// -// int status = run_module(data, "tcsdirect_steam"); -// -// return status; -//} - -// Power Tower direct steam with alternative Direct Steam Receiver material -// Direct Steam Receiver material: T91 Steel -// Rest default configurations -//int tcsdirect_steam_daggett_direct_steam_receiver(ssc_data_t &data) -//{ -// tcsdirect_steam_default(data); -// -// ssc_data_set_number(data, "mat_boiler", 28); -// ssc_data_set_number(data, "mat_sh", 28); -// ssc_data_set_number(data, "mat_rh", 28); -// ssc_data_set_number(data, "eta_ref", 0.404); -// ssc_data_set_number(data, "startup_frac", 0.5); -// ssc_data_set_number(data, "P_cond_min", 2); -// -// int status = run_module(data, "tcsdirect_steam"); -// -// return status; -//} - -// Power Tower direct steam with alternative flow pattern -// Flow pattern: 1 -// Rest default configurations -//int tcsdirect_steam_daggett_flow_pattern(ssc_data_t &data) -//{ -// tcsdirect_steam_default(data); -// -// ssc_data_set_number(data, "flowtype", 1); -// ssc_data_set_number(data, "eta_ref", 0.404); -// ssc_data_set_number(data, "startup_frac", 0.5); -// ssc_data_set_number(data, "P_cond_min", 2); -// -// int status = run_module(data, "tcsdirect_steam"); -// -// return status; -//} - -// Power Tower direct steam with alternative Heliostat focusing method -// Heliostat focusing method: Flat -// Rest default configurations -//int tcsdirect_steam_daggett_focusing_method(ssc_data_t &data) -//{ -// tcsdirect_steam_default(data); -// -// ssc_data_set_number(data, "focus_type", 0); -// ssc_data_set_number(data, "eta_ref", 0.404); -// ssc_data_set_number(data, "startup_frac", 0.5); -// ssc_data_set_number(data, "P_cond_min", 2); -// -// int status = run_module(data, "tcsdirect_steam"); -// -// return status; -//} - -// Power Tower direct steam with alternative Heliostat canting method -// Heliostat canting method: Equinox -// Rest default configurations -//int tcsdirect_steam_daggett_canting_method(ssc_data_t &data) -//{ -// tcsdirect_steam_default(data); -// -// ssc_data_set_number(data, "cant_type", 2); -// ssc_data_set_number(data, "eta_ref", 0.404); -// ssc_data_set_number(data, "startup_frac", 0.5); -// ssc_data_set_number(data, "P_cond_min", 2); -// -// int status = run_module(data, "tcsdirect_steam"); -// -// return status; -//} - -// Power Tower direct steam with alternative location -// Location: Tucson, AZ -// Rest default configurations -//int tcsdirect_steam_daggett_tucson_AZ(ssc_data_t &data) -//{ -// tcsdirect_steam_default(data); -// -// char solar_resource_path_tucson[512]; -// int n2 = sprintf(solar_resource_path_tucson, "%s/test/input_cases/directsteam_data/tucson_az_32.116521_-110.933042_psmv3_60_tmy.csv", std::getenv("SSCDIR")); -// ssc_data_set_string(data, "solar_resource_file", solar_resource_path_tucson); -// -// int status = run_module(data, "tcsdirect_steam"); -// -// return status; -//} - - - - -#endif \ No newline at end of file diff --git a/test/tcs_test/tcsfresnel_molten_salt_cases.h b/test/tcs_test/tcsfresnel_molten_salt_cases.h deleted file mode 100644 index bf1a420d1a4..00000000000 --- a/test/tcs_test/tcsfresnel_molten_salt_cases.h +++ /dev/null @@ -1,177 +0,0 @@ -#ifndef _TCSFRESNEL_MOLTEN_SALT_CASES_H_ -#define _TCSFRESNEL_MOLTEN_SALT_CASES_H_ - -#include -#include "../input_cases/code_generator_utilities.h" -#include "tcsfresnel_molten_salt_common_data.h" - -/** -* Data for high-level integration tests that verifies whether results for a liner Fresnel molten -* salt plant in Tucson, AZ matches expected results. -* Data generated from code-generator (Shift+F5) within SAM UI. -* Test uses SSCAPI interfaces (similiar to SDK usage) to pass and receive data to tcsfresnel_molten_salt -*/ - - -// Linear Fresnel molten salt default congifuration -int tcsfresnel_molten_salt_tucson_default(ssc_data_t &data) -{ - tcsfresnel_molten_salt_default(data); - - int status = run_module(data, "tcsmslf"); - - //single_owner_default(data); - //status += run_module(data, "singleowner"); - - return status; -} - -// Linear Fresnel molten salt with alternative defocusing strategy -// Defocusing strategy: Sequenced -// Rest default configurations with respect to the No Finanical model -int tcsfresnel_molten_salt_tucson_defocusing_strategy(ssc_data_t &data) -{ - tcsfresnel_molten_salt_default(data); - - ssc_data_set_number( data, "fthrctrl", 1 ); - - int status = run_module(data, "tcsmslf"); - - return status; -} - -// Linear Fresnel molten salt with alternative Field HTF -// Field HTF: Therminol VP-1 -// Rest default configurations with respect to the No Finanical model -int tcsfresnel_molten_salt_tucson_field_HTF(ssc_data_t &data) -{ - tcsfresnel_molten_salt_default(data); - - ssc_data_set_number(data, "Fluid", 21); - ssc_data_set_number(data, "field_fluid", 21); - ssc_data_set_number(data, "is_hx", 1); - ssc_data_set_number(data, "V_tank_hot_ini", 1290.5642); - ssc_data_set_number(data, "vol_tank", 6452.821); - - int status = run_module(data, "tcsmslf"); - - return status; -} - -// Linear Fresnel molten salt with alternative optical characterization method -// Optical characterization method: Solar position -// Rest default configurations with respect to the No Finanical model -int tcsfresnel_molten_salt_tucson_optical_char_solar(ssc_data_t &data) -{ - tcsfresnel_molten_salt_default(data); - - ssc_data_set_number(data, "opt_model", 1); - - int status = run_module(data, "tcsmslf"); - - return status; -} - -// Linear Fresnel molten salt with alternative receiver model type -// Receiver model type: Polynomial heat loss model -// Rest default configurations with respect to the No Finanical model -//int tcsfresnel_molten_salt_tucson_polynomial_heat_loss_model(ssc_data_t &data) -//{ -// tcsfresnel_molten_salt_default(data); -// -// ssc_data_set_number(data, "nLoops", 148); -// ssc_data_set_number(data, "rec_model", 1); -// -// int status = run_module(data, "tcsmslf"); -// -// return status; -//} - -// Linear Fresnel molten salt with alternative condenser type -// Condenser type: Evaporative -// Rest default configurations with respect to the No Finanical model -//int tcsfresnel_molten_salt_tucson_evap_condenser(ssc_data_t &data) -//{ -// tcsfresnel_molten_salt_default(data); -// -// ssc_data_set_number(data, "CT", 1); -// -// int status = run_module(data, "tcsmslf"); -// -// return status; -//} - -// Linear Fresnel molten salt with alternative condenser type -// Condenser type: Hybrid -// Rest default configurations with respect to the No Finanical model -//int tcsfresnel_molten_salt_tucson_hybrid_condenser(ssc_data_t &data) -//{ -// tcsfresnel_molten_salt_default(data); -// -// ssc_data_set_number(data, "CT", 3); -// -// int status = run_module(data, "tcsmslf"); -// -// return status; -//} - -// Linear Fresnel molten salt with alternative turbine inlet pressure control -// Turbine inlet pressure control: Sliding pressure -// Rest default configurations with respect to the No Finanical model -//int tcsfresnel_molten_salt_tucson_sliding_p(ssc_data_t &data) -//{ -// tcsfresnel_molten_salt_default(data); -// -// ssc_data_set_number(data, "tech_type", 3); -// -// int status = run_module(data, "tcsmslf"); -// -// return status; -//} - -// Linear Fresnel molten salt with alternative HTF freeze protection mode -// HTF freeze protection mode: Electric heating -// Rest default configurations with respect to the No Finanical model -//int tcsfresnel_molten_salt_tucson_HTF_freeze_protection(ssc_data_t &data) -//{ -// tcsfresnel_molten_salt_default(data); -// -// ssc_data_set_number(data, "fp_mode", 1); -// -// int status = run_module(data, "tcsmslf"); -// -// return status; -//} - -// Linear Fresnel molten salt with alternative storage HTF -// Storage HTF: Therminol VP-1 -// Rest default configurations with respect to the No Finanical model -//int tcsfresnel_molten_salt_tucson_storage_HTF(ssc_data_t &data) -//{ -// tcsfresnel_molten_salt_default(data); -// -// ssc_data_set_number(data, "store_fluid", 21); -// ssc_data_set_number(data, "is_hx", 1); -// ssc_data_set_number(data, "V_tank_hot_ini", 1963.66443); -// ssc_data_set_number(data, "vol_tank", 9818.3223); -// -// int status = run_module(data, "tcsmslf"); -// -// return status; -//} - -// Linear Fresnel molten salt with alternative Power Cycle -// Power Cycle: User Defined -// Rest default configurations with respect to the No Finanical model -//int tcsfresnel_molten_salt_tucson_userdefined_default(ssc_data_t &data) -//{ -// tcsfresnel_molten_salt_default(data); -// -// ssc_data_set_number(data, "pc_config", 1); -// -// int status = run_module(data, "tcsmslf"); -// -// return status; -//} - -#endif diff --git a/test/tcs_test/tcsmolten_salt_cases.h b/test/tcs_test/tcsmolten_salt_cases.h deleted file mode 100644 index f7bb68c5eca..00000000000 --- a/test/tcs_test/tcsmolten_salt_cases.h +++ /dev/null @@ -1,385 +0,0 @@ -#ifndef _TCSMOLTEN_SALT_CASES_H_ -#define _TCSMOLTEN_SALT_CASES_H_ - -#include -#include "../input_cases/code_generator_utilities.h" -#include "tcsmolten_salt_common_data.h" - -/** -* Data for high-level integration tests that verifies whether results for a molten salt power tower -* plant in Daggett, CA matches expected results. -* Data generated from code-generator (Shift+F5) within SAM UI. -* Test uses SSCAPI interfaces (similiar to SDK usage) to pass and receive data to tcsmolten_salt -*/ - -// Power Tower molten salt default congifuration -int tcsmolten_salt_daggett_default(ssc_data_t &data) -{ - tcsmolten_salt_default(data); - - int status = run_module(data, "tcsmolten_salt"); - - //single_owner_default(data); - //status += run_module(data, "singleowner"); - - return status; -} - -// Power Tower molten salt with alternative turbine inlet pressure control -// Turbine inlet pressure control: Sliding pressure -// Rest default configurations -int tcsmolten_salt_daggett_sliding_pressure(ssc_data_t &data) -{ - tcsmolten_salt_default(data); - - ssc_data_set_number(data, "tech_type", 3); - - int status = run_module(data, "tcsmolten_salt"); - - return status; -} - -// Power tower molten salt with alternative condenser type -// Condenser type: Evaporative -// Rest default configurations -//int tcsmolten_salt_daggett_evap_condenser(ssc_data_t &data) -//{ -// tcsmolten_salt_default(data); -// -// ssc_data_set_number(data, "CT", 1); -// -// int status = run_module(data, "tcsmolten_salt"); -// -// return status; -//} - -// Power tower molten salt with alternative condenser type -// Condenser type: Hybrid -// Rest default configurations -//int tcsmolten_salt_daggett_hybrid_condenser(ssc_data_t &data) -//{ -// tcsmolten_salt_default(data); -// -// ssc_data_set_number(data, "CT", 3); -// -// int status = run_module(data, "tcsmolten_salt"); -// -// return status; -//} - -// Power tower molten salt with alternative condenser type -// Condenser type: Radiative -// Rest default configurations -//int tcsmolten_salt_daggett_radiative_condenser(ssc_data_t &data) -//{ -// tcsmolten_salt_default(data); -// -// // Start of radiative-cooling metrics -// ssc_data_set_number(data, "h_ctes_tank_min", 1); -// ssc_data_set_number(data, "ctes_tshours", 15); -// ssc_data_set_number(data, "ctes_field_fl", 4); -// ssc_data_set_number(data, "h_ctes_tank", 30); -// ssc_data_set_number(data, "u_ctes_tank", 0.4); -// ssc_data_set_number(data, "ctes_tankpairs", 1); -// ssc_data_set_number(data, "T_ctes_cold_design", 5); -// ssc_data_set_number(data, "T_ctes_warm_design", 10); -// ssc_data_set_number(data, "T_ctes_warm_ini", 20); -// ssc_data_set_number(data, "T_ctes_cold_ini", 10); -// ssc_data_set_number(data, "f_ctes_warm_ini", 0); -// ssc_data_set_number(data, "rad_multiplier", 1.5); -// ssc_data_set_number(data, "m_dot_radpanel", 8); -// ssc_data_set_number(data, "n_rad_tubes", 100); -// ssc_data_set_number(data, "W_rad_tubes", 0.05); -// ssc_data_set_number(data, "L_rad", 100); -// ssc_data_set_number(data, "th_rad_panel", 0.002); -// ssc_data_set_number(data, "D_rad_tubes", 0.02); -// ssc_data_set_number(data, "k_panel", 235); -// ssc_data_set_number(data, "epsilon_radtop", 0.95); -// ssc_data_set_number(data, "epsilon_radbot", 0.07); -// ssc_data_set_number(data, "epsilon_radgrnd", 0.9); -// ssc_data_set_number(data, "L_rad_sections", 10); -// ssc_data_set_number(data, "epsilon_radHX", 0.8); -// ssc_data_set_number(data, "ctes_type", 0); -// ssc_data_set_number(data, "helio_area_tot", 1269054.5); -// ssc_data_set_number(data, "radiator_unitcost", 13); -// ssc_data_set_number(data, "radiator_installcost", 22); -// ssc_data_set_number(data, "radiator_fluidcost", 0.34); -// ssc_data_set_number(data, "radfluid_vol_ratio", 3); -// ssc_data_set_number(data, "ctes_cost", 0.7); -// ssc_data_set_number(data, "rad_pressuredrop", 75); -// //End of radiative-cooling metrics -// ssc_data_set_number(data, "CT", 4); -// -// int status = run_module(data, "tcsmolten_salt"); -// -// return status; -//} - -// Power Tower molten salt with alternative flow pattern -// Flow pattern: 8 -// Rest default configurations -int tcsmolten_salt_daggett_flow_pattern(ssc_data_t &data) -{ - tcsmolten_salt_default(data); - - ssc_data_set_number(data, "Flow_type", 8); - - int status = run_module(data, "tcsmolten_salt"); - - return status; -} - -// Power Tower molten salt with alternative location -// Location: Tucson, Arizona -// Rest default configurations -//int tcsmolten_salt_Tucson_AZ(ssc_data_t &data) -//{ -// tcsmolten_salt_default(data); -// -// char solar_resource_path_tucson[512]; -// int n = sprintf(solar_resource_path_tucson, "%s/test/input_cases/moltensalt_data/tucson_az_32.116521_-110.933042_psmv3_60_tmy.csv", std::getenv("SSCDIR")); -// ssc_data_set_string(data, "solar_resource_file", solar_resource_path_tucson); -// -// int status = run_module(data, "tcsmolten_salt"); -// -// return status; -//} - -// Power Tower molten salt with alternative power cycle: User Defined -// Rest default configurations -//int tcsmolten_salt_daggett_UD_default(ssc_data_t &data) -//{ -// tcsmolten_salt_default(data); -// -// set_matrix(data, "ud_ind_od", ud_ind_od_path, 180, 7); -// ssc_data_set_number(data, "pc_config", 1); -// ssc_data_set_number(data, "ud_m_dot_htf_low", 0.3); -// ssc_data_set_number(data, "ud_m_dot_htf_high", 1.2); -// -// int status = run_module(data, "tcsmolten_salt"); -// -// return status; -//} - -// Power Tower molten salt with alternative power cycle: Super Critical CO2 -// Rest default configurations -//int tcsmolten_salt_daggett_SCO2_default(ssc_data_t &data) -//{ -// tcsmolten_salt_default(data); -// -// ssc_data_set_number(data, "is_sco2_preprocess", 1); -// -// ssc_data_set_number(data, "pc_config", 2); -// ssc_data_set_number(data, "cycle_cutoff_frac", 0.5); -// // Start of super critical CO2 metrics -// ssc_data_set_number(data, "sco2ud_T_htf_cold_calc", 406.04); -// ssc_data_set_number(data, "sco2ud_T_htf_low", 554); -// ssc_data_set_number(data, "sco2ud_T_htf_high", 589); -// ssc_data_set_number(data, "sco2ud_T_amb_high", 45); -// ssc_data_set_number(data, "sco2ud_m_dot_htf_low", 0.5); -// ssc_data_set_number(data, "sco2ud_m_dot_htf_high", 1.05); -// ssc_number_t p_sco2ud_T_htf_ind_od[65] = { 554, 0.50001432179685623, 0.96932004909372826, 0.97558944094670463, 0.56452945008574118, 0.99212119137385479, 0.9938261663184943, 0.071046760698792344, 1.0516901234966409, 1.0396677815546937, 1, 1, 1, 562.75, 0.50000677254611736, 0.98273822965810698, 0.98931005948737616, 0.55442312464765453, 0.99593839560635933, 0.99813862855158975, 0.060760248142716182, 1.0280675561194188, 1.0216094704370726, 1, 1, 1, 571.5, 0.49997035485832741, 0.99560036541912367, 1.0030665958141747, 0.54540906175814596, 0.99964495720997093, 1.0023929148428683, 0.052633463645261176, 1.0056543163255209, 1.0033307681195913, 1, 1, 1, 580.25, 0.50001678576431519, 0.99981330235493204, 1.0149012834308118, 0.53755371644427918, 0.99437061481748712, 1.0057187757624548, 0.046124783184180999, 0.93267305740289486, 0.97564080126247599, 1, 1, 1, 589, 0.49998766910986947, 0.99997642865903091, 1.0280965929880774, 0.53035396718324523, 0.98587808938966315, 1.0103635810622889, 0.040778740942652915, 0.84986379353651254, 0.96107738725047209, 1, 1, 1 }; -// ssc_data_set_matrix(data, "sco2ud_T_htf_ind_od", p_sco2ud_T_htf_ind_od, 5, 13); -// ssc_number_t p_sco2ud_T_amb_ind_od[130] = { 0, 0.99994012767121321, 0.99974326147411507, 0.99987485850649338, 0.970379288808072, 0.95027470619969945, 0.93683012616718919, 0.059164848919520591, 0.049933864673572616, 0.04548467867978704, 1, 1, 1, 5, 0.99994012767121321, 0.99974326147411507, 0.99987485850649338, 0.970379288808072, 0.95027470619969945, 0.93683012616718919, 0.097133136927079936, 0.082248959886362452, 0.075269394493921518, 1, 1, 1, 10, 0.99994012767121321, 0.99974326147411507, 0.99987485850649338, 0.970379288808072, 0.95027470619969945, 0.93683012616718919, 0.17314165365655804, 0.14726896648379706, 0.13576325670205261, 1, 1, 1, 15, 0.99994012767121321, 0.99974326147411507, 0.99987485850649338, 0.970379288808072, 0.95027470619969945, 0.93683012616718919, 0.3481506775773433, 0.29853487098289033, 0.27855988861884273, 1, 1, 1, 20, 0.99994012767121321, 0.99974326147411507, 0.99987485850649338, 0.970379288808072, 0.95027470619969945, 0.93683012616718919, 0.85719459330059711, 0.74767538224853725, 0.71410844002614948, 1, 1, 1, 25, 0.99998860165458137, 0.99998405506376475, 0.99994129487763628, 0.97834420606252215, 0.9592086954026382, 0.94639328546002388, 1.4397512132898596, 1.1099623611534934, 0.9289610766286478, 1, 1, 1, 30, 0.99997868773200105, 1.0000128744625323, 0.99987390166815182, 0.99986135777103136, 0.97846151925556812, 0.96428182700735732, 1.2885473732704416, 1.0097961360792755, 0.85212892165494525, 1, 1, 1, 35, 0.96932004909372826, 0.99995022500741981, 0.99997642865903091, 0.99212119137385479, 0.99999459906789145, 0.98587808938966315, 1.0516901234966409, 1.0033307681195913, 0.84986379353651254, 1, 1, 1, 40, 0.85681928090544024, 0.88648580427756085, 0.90755440545490784, 0.8967547597723905, 0.90655814175453875, 0.91360819421216066, 0.54638640488302492, 0.52332590711799631, 0.50841120332212841, 1, 1, 1, 45, 0.76192612755033284, 0.78992076166486025, 0.81009772614290565, 0.81887517513574226, 0.82799762047592962, 0.83504194672755783, 0.32667431104075889, 0.31463845368914112, 0.30664767313185981, 1, 1, 1 }; -// ssc_data_set_matrix(data, "sco2ud_T_amb_ind_od", p_sco2ud_T_amb_ind_od, 10, 13); -// ssc_number_t p_sco2ud_m_dot_htf_ind_od[130] = { 0.5, 0.50000238394483887, 0.50002030400496988, 0.5000072744279479, 0.49996830468452913, 0.54311461140321193, 0.58949291750771449, 0.0023965079935530688, 0.050651289208334289, 0.085268991630535099, 1, 1, 1, 0.56111111111111112, 0.56107350053341665, 0.56109752841228611, 0.56110469253490813, 0.55257347648896971, 0.59674948077268875, 0.64372698634700765, 0.0035623149303332731, 0.076089576895326735, 0.12158112224599875, 1, 1, 1, 0.62222222222222223, 0.62224697121064898, 0.62224996267725707, 0.62219761804463092, 0.60616131300962228, 0.65145619071565242, 0.69969734374588888, 0.0052256619247860641, 0.11370919032872756, 0.17234788816884622, 1, 1, 1, 0.68333333333333335, 0.68334763160686485, 0.68332772806833242, 0.68334268666386189, 0.66063755666452395, 0.70667012650879169, 0.75616720875118448, 0.0076071355040999147, 0.16722335929420953, 0.24228904960439612, 1, 1, 1, 0.74444444444444446, 0.74441099641078146, 0.74443754704645426, 0.73579757426674453, 0.7154614610083625, 0.76238207877819242, 0.80635338615523044, 0.010993657103543011, 0.24183918938496599, 0.28923568019902324, 1, 1, 1, 0.80555555555555558, 0.80548586203577432, 0.80556625128549619, 0.7607325689541361, 0.7709115279333274, 0.81874600280477805, 0.81846324371170665, 0.015863026451133713, 0.34650772248743805, 0.32712367869313513, 1, 1, 1, 0.8666666666666667, 0.86665068706416915, 0.86667726624963815, 0.77310372269008887, 0.82666048629288214, 0.87575544351530044, 0.82250334117333646, 0.022915833888653158, 0.49058181757621305, 0.32138671984149092, 1, 1, 1, 0.92777777777777781, 0.92781567340041837, 0.92781937609673271, 0.78228939831004085, 0.88241774237123771, 0.93313651551826904, 0.82559824503018264, 0.033028022568911568, 0.6869968410833619, 0.31804744512991351, 1, 1, 1, 0.98888888888888893, 0.98860321834099996, 0.98888850977399578, 0.78897052574490523, 0.93832104872570143, 0.99049121752897784, 0.82770087400040337, 0.049618846148749549, 0.94725737476210103, 0.31520682775233339, 1, 1, 1, 1.05, 1.0487348778724641, 1.0062218585376423, 0.79376542360284852, 1.0039295318936428, 1.0043865029637598, 0.82928412460314016, 0.049807927876335194, 0.99339517007581468, 0.31300940662606114, 1, 1, 1 }; -// ssc_data_set_matrix(data, "sco2ud_m_dot_htf_ind_od", p_sco2ud_m_dot_htf_ind_od, 10, 13); -// -// ssc_data_set_number(data, "_sco2_P_high_limit", 25); -// ssc_data_set_number(data, "_sco2_P_ref", 115); -// ssc_data_set_number(data, "_sco2_T_amb_des", 35); -// ssc_data_set_number(data, "_sco2_T_approach", 10); -// ssc_data_set_number(data, "_sco2_T_htf_hot_des", 574); -// ssc_data_set_number(data, "_sco2_deltaT_PHX", 20); -// ssc_data_set_number(data, "_sco2_design_eff", 0.41200000047683716); -// ssc_data_set_number(data, "_sco2_eta_c", 0.88999998569488525); -// ssc_data_set_number(data, "_sco2_eta_t", 0.89999997615814209); -// ssc_data_set_number(data, "_sco2_recup_eff_max", 0.95999997854232788); -// -// int status = run_module(data, "tcsmolten_salt"); -// -// return status; -//} - -// Power Tower molten salt with alternative power cycle: Super Critical CO2 -// Cycle Configuration alternative: Partial Cooling -// Rest default configurations -//int tcsmolten_salt_daggett_SCO2_partial_cooling(ssc_data_t &data) -//{ -// tcsmolten_salt_default(data); -// -// ssc_data_set_number(data, "pc_config", 2); -// ssc_data_set_number(data, "cycle_cutoff_frac", 0.5); -// // Start of super critical CO2 metrics -// ssc_data_set_number(data, "sco2_cycle_config", 2); -// ssc_data_set_number(data, "sco2ud_T_htf_cold_calc", 354.84); -// ssc_data_set_number(data, "sco2ud_T_htf_low", 554); -// ssc_data_set_number(data, "sco2ud_T_htf_high", 589); -// ssc_data_set_number(data, "sco2ud_T_amb_high", 45); -// ssc_data_set_number(data, "sco2ud_m_dot_htf_low", 0.5); -// ssc_data_set_number(data, "sco2ud_m_dot_htf_high", 1.05); -// ssc_number_t p_sco2ud_T_htf_ind_od[65] = { 554, 0.49999352886459142, 0.96525561209463806, 0.97453395561145839, 0.62911366508823352, 0.98998074672002789, 0.99261217903413035, 0.20247797682275048, 1.0571168076843547, 1.0432895732028127, 1, 1, 1, 562.75, 0.49999364663999546, 0.98061760093183636, 0.98945608039614341, 0.59967747034505758, 0.99410410545590111, 0.99692477104310284, 0.17800016270512209, 1.0348516156853151, 1.0211725729287384, 1, 1, 1, 571.5, 0.49999395161728027, 0.99563145139446119, 1.0038535082905322, 0.58306031118146817, 0.99832427864796236, 1.001449148486844, 0.16124320857207705, 1.0092594720500885, 1.0025470111145369, 1, 1, 1, 580.25, 0.49999438710690025, 1.0000368631016281, 1.0187996347167014, 0.57310398959762909, 0.99215602847837348, 1.0059800813551822, 0.14338401700982784, 0.9341583009417217, 0.98266060214587514, 1, 1, 1, 589, 0.50001605482790912, 0.99999012779922869, 1.0325220180423378, 0.56534529941933243, 0.9816011558820481, 1.0098950333460388, 0.12932201013498895, 0.84387453074601659, 0.96199109269179472, 1, 1, 1 }; -// ssc_data_set_matrix(data, "sco2ud_T_htf_ind_od", p_sco2ud_T_htf_ind_od, 5, 13); -// ssc_number_t p_sco2ud_T_amb_ind_od[130] = { 0, 0.99997428799188914, 0.99999000874401356, 0.99999963664033542, 1.0096260890795448, 0.97647524655927898, 0.95539332954343525, 0.035964053686654389, 0.030460203665356428, 0.028191373083630726, 1, 1, 1, 5, 0.99997428799188914, 0.99999000874401356, 0.99999963664033542, 1.0096260890795448, 0.97647524655927898, 0.95539332954343525, 0.054169401117576316, 0.046164874738715223, 0.043090992060877832, 1, 1, 1, 10, 0.99997428799188914, 0.99999000874401356, 0.99999963664033542, 1.0096260890795448, 0.97647524655927898, 0.95539332954343525, 0.086054162974292386, 0.074011959990269383, 0.069988333857598825, 1, 1, 1, 15, 0.99997428799188914, 0.99999000874401356, 0.99999963664033542, 1.0096260890795448, 0.97647524655927898, 0.95539332954343525, 0.14717747411619553, 0.12834741606804084, 0.12359755317608473, 1, 1, 1, 20, 0.99997428799188914, 0.99999000874401356, 0.99999963664033542, 1.0096260890795448, 0.97647524655927898, 0.95539332954343525, 0.27882175950298732, 0.24810999613169693, 0.24587350287625651, 1, 1, 1, 25, 0.99998001476123333, 0.99998252902816598, 0.99991197104226259, 1.0098815301216097, 0.97647895095481074, 0.9554677877793778, 0.59120853683278496, 0.54403699709247888, 0.56813028411712974, 1, 1, 1, 30, 0.99998001476123333, 0.99998700539505325, 1.000003594937197, 1.0098815301216097, 0.97801555014110308, 0.95937811970467868, 1.6874663271788872, 1.1677785621376786, 0.92812586911858419, 1, 1, 1, 35, 0.96525561209463806, 0.99994365838368371, 0.99999012779922869, 0.98998074672002789, 1.0001162551906568, 0.9816011558820481, 1.0571168076843547, 1.0070553661423967, 0.84387453074601659, 1, 1, 1, 40, 0.88091956289263618, 0.91354408714037638, 0.93692898396657309, 0.92804590812890486, 0.93898338187710573, 0.94720156997882032, 0.77791598161892206, 0.7475571669584532, 0.72852820207159907, 1, 1, 1, 45, 0.80443081580069309, 0.83588054350931573, 0.85830802419616214, 0.87954062349121198, 0.89162501172294772, 0.90100255955577613, 0.71796263227634882, 0.69604875226586571, 0.68078331511457812, 1, 1, 1 }; -// ssc_data_set_matrix(data, "sco2ud_T_amb_ind_od", p_sco2ud_T_amb_ind_od, 10, 13); -// ssc_number_t p_sco2ud_m_dot_htf_ind_od[130] = { 0.5, 0.50001158587629013, 0.49999335234425468, 0.500009458086906, 0.52092523582781203, 0.580310601704488, 0.67277741730869234, 0.0066297710364970602, 0.15612995926951076, 0.42538208998154886, 1, 1, 1, 0.56111111111111112, 0.56112632572922161, 0.56109347634533013, 0.56112858298132773, 0.5676475361894191, 0.62646030027815847, 0.70338416085113653, 0.0079531402579119982, 0.18764587089730347, 0.43103981940440877, 1, 1, 1, 0.62222222222222223, 0.62221611814605471, 0.62221274231112988, 0.62222151074161314, 0.61455395777278332, 0.67446637440230506, 0.74670855688273574, 0.0093884633943930561, 0.22842611147672137, 0.48833317891759392, 1, 1, 1, 0.68333333333333335, 0.68329224890757501, 0.68333522189257412, 0.68331145370876678, 0.66231318458618582, 0.72371156880387011, 0.7949045334243946, 0.011139413945746518, 0.28028443088130395, 0.57482477745595617, 1, 1, 1, 0.74444444444444446, 0.74445060439362043, 0.74444232493970608, 0.74442697568885108, 0.71280359548337557, 0.77393932493368434, 0.84599994004797685, 0.01370986733027353, 0.34683195143613776, 0.69088300755849497, 1, 1, 1, 0.80555555555555558, 0.80554205452706595, 0.80553118613158747, 0.78568541702380978, 0.76617945177385471, 0.82545035439296532, 0.87282832981226932, 0.018334310087357693, 0.43577215265376867, 0.73125604358596707, 1, 1, 1, 0.8666666666666667, 0.86667780683097451, 0.86669111505864649, 0.80779790168115828, 0.82501645350095432, 0.8784837343548566, 0.88083521806059473, 0.031013715053052799, 0.55720344212317163, 0.71564348223866958, 1, 1, 1, 0.92777777777777781, 0.92778930075110044, 0.92781165563938151, 0.82346900197673678, 0.89420782417679856, 0.9332817335240674, 0.88681855363756823, 0.030225663571636099, 0.72555609695067691, 0.70381015654357315, 1, 1, 1, 0.98888888888888893, 0.98891033574992371, 0.98886027855958214, 0.8342986400696234, 0.96400610586573099, 0.98968856703989938, 0.89098743214344123, 0.030057676976388854, 0.95810218483069376, 0.69690700803894567, 1, 1, 1, 1.05, 1.0499204736064125, 1.0082881287098067, 0.84167433259869806, 1.0322051570968707, 1.002564506765949, 0.89389762859965882, 0.034640376520654041, 0.99538596406341329, 0.69252556580813951, 1, 1, 1 }; -// ssc_data_set_matrix(data, "sco2ud_m_dot_htf_ind_od", p_sco2ud_m_dot_htf_ind_od, 10, 13); -// ssc_data_set_number(data, "_sco2_P_high_limit", 25); -// ssc_data_set_number(data, "_sco2_P_ref", 115); -// ssc_data_set_number(data, "_sco2_T_amb_des", 35); -// ssc_data_set_number(data, "_sco2_T_approach", 10); -// ssc_data_set_number(data, "_sco2_T_htf_hot_des", 574); -// ssc_data_set_number(data, "_sco2_deltaT_PHX", 20); -// ssc_data_set_number(data, "_sco2_design_eff", 0.412); -// ssc_data_set_number(data, "_sco2_eta_c", 0.89); -// ssc_data_set_number(data, "_sco2_eta_t", 0.9); -// ssc_data_set_number(data, "_sco2_recup_eff_max", 0.96); -// //End of super critical CO2 metrics -// -// int status = run_module(data, "tcsmolten_salt"); -// -// return status; -//} - -// Power Tower molten salt with alternative power cycle: Super Critical CO2 -// Materials and Flow alternative: Flow pattern 2 instead of 1 -// Rest default configurations -//int tcsmolten_salt_daggett_SCO2_flow_pattern_2(ssc_data_t &data) -//{ -// tcsmolten_salt_default(data); -// -// ssc_data_set_number(data, "Flow_type", 2); -// ssc_data_set_number(data, "pc_config", 2); -// ssc_data_set_number(data, "cycle_cutoff_frac", 0.5); -// -// // Start of super critical CO2 metrics -// ssc_data_set_number(data, "sco2ud_T_htf_cold_calc", 406.04); -// ssc_data_set_number(data, "sco2ud_T_htf_low", 554); -// ssc_data_set_number(data, "sco2ud_T_htf_high", 589); -// ssc_data_set_number(data, "sco2ud_T_amb_high", 45); -// ssc_data_set_number(data, "sco2ud_m_dot_htf_low", 0.5); -// ssc_data_set_number(data, "sco2ud_m_dot_htf_high", 1.05); -// ssc_number_t p_sco2ud_T_htf_ind_od[65] = { 554, 0.50001432179685623, 0.96932004909372826, 0.97558944094670463, 0.56452945008574118, 0.99212119137385479, 0.9938261663184943, 0.071046760698792344, 1.0516901234966409, 1.0396677815546937, 1, 1, 1, 562.75, 0.50000677254611736, 0.98273822965810698, 0.98931005948737616, 0.55442312464765453, 0.99593839560635933, 0.99813862855158975, 0.060760248142716182, 1.0280675561194188, 1.0216094704370726, 1, 1, 1, 571.5, 0.49997035485832741, 0.99560036541912367, 1.0030665958141747, 0.54540906175814596, 0.99964495720997093, 1.0023929148428683, 0.052633463645261176, 1.0056543163255209, 1.0033307681195913, 1, 1, 1, 580.25, 0.50001678576431519, 0.99981330235493204, 1.0149012834308118, 0.53755371644427918, 0.99437061481748712, 1.0057187757624548, 0.046124783184180999, 0.93267305740289486, 0.97564080126247599, 1, 1, 1, 589, 0.49998766910986947, 0.99997642865903091, 1.0280965929880774, 0.53035396718324523, 0.98587808938966315, 1.0103635810622889, 0.040778740942652915, 0.84986379353651254, 0.96107738725047209, 1, 1, 1 }; -// ssc_data_set_matrix(data, "sco2ud_T_htf_ind_od", p_sco2ud_T_htf_ind_od, 5, 13); -// ssc_number_t p_sco2ud_T_amb_ind_od[130] = { 0, 0.99994012767121321, 0.99974326147411507, 0.99987485850649338, 0.970379288808072, 0.95027470619969945, 0.93683012616718919, 0.059164848919520591, 0.049933864673572616, 0.04548467867978704, 1, 1, 1, 5, 0.99994012767121321, 0.99974326147411507, 0.99987485850649338, 0.970379288808072, 0.95027470619969945, 0.93683012616718919, 0.097133136927079936, 0.082248959886362452, 0.075269394493921518, 1, 1, 1, 10, 0.99994012767121321, 0.99974326147411507, 0.99987485850649338, 0.970379288808072, 0.95027470619969945, 0.93683012616718919, 0.17314165365655804, 0.14726896648379706, 0.13576325670205261, 1, 1, 1, 15, 0.99994012767121321, 0.99974326147411507, 0.99987485850649338, 0.970379288808072, 0.95027470619969945, 0.93683012616718919, 0.3481506775773433, 0.29853487098289033, 0.27855988861884273, 1, 1, 1, 20, 0.99994012767121321, 0.99974326147411507, 0.99987485850649338, 0.970379288808072, 0.95027470619969945, 0.93683012616718919, 0.85719459330059711, 0.74767538224853725, 0.71410844002614948, 1, 1, 1, 25, 0.99998860165458137, 0.99998405506376475, 0.99994129487763628, 0.97834420606252215, 0.9592086954026382, 0.94639328546002388, 1.4397512132898596, 1.1099623611534934, 0.9289610766286478, 1, 1, 1, 30, 0.99997868773200105, 1.0000128744625323, 0.99987390166815182, 0.99986135777103136, 0.97846151925556812, 0.96428182700735732, 1.2885473732704416, 1.0097961360792755, 0.85212892165494525, 1, 1, 1, 35, 0.96932004909372826, 0.99995022500741981, 0.99997642865903091, 0.99212119137385479, 0.99999459906789145, 0.98587808938966315, 1.0516901234966409, 1.0033307681195913, 0.84986379353651254, 1, 1, 1, 40, 0.85681928090544024, 0.88648580427756085, 0.90755440545490784, 0.8967547597723905, 0.90655814175453875, 0.91360819421216066, 0.54638640488302492, 0.52332590711799631, 0.50841120332212841, 1, 1, 1, 45, 0.76192612755033284, 0.78992076166486025, 0.81009772614290565, 0.81887517513574226, 0.82799762047592962, 0.83504194672755783, 0.32667431104075889, 0.31463845368914112, 0.30664767313185981, 1, 1, 1 }; -// ssc_data_set_matrix(data, "sco2ud_T_amb_ind_od", p_sco2ud_T_amb_ind_od, 10, 13); -// ssc_number_t p_sco2ud_m_dot_htf_ind_od[130] = { 0.5, 0.50000238394483887, 0.50002030400496988, 0.5000072744279479, 0.49996830468452913, 0.54311461140321193, 0.58949291750771449, 0.0023965079935530688, 0.050651289208334289, 0.085268991630535099, 1, 1, 1, 0.56111111111111112, 0.56107350053341665, 0.56109752841228611, 0.56110469253490813, 0.55257347648896971, 0.59674948077268875, 0.64372698634700765, 0.0035623149303332731, 0.076089576895326735, 0.12158112224599875, 1, 1, 1, 0.62222222222222223, 0.62224697121064898, 0.62224996267725707, 0.62219761804463092, 0.60616131300962228, 0.65145619071565242, 0.69969734374588888, 0.0052256619247860641, 0.11370919032872756, 0.17234788816884622, 1, 1, 1, 0.68333333333333335, 0.68334763160686485, 0.68332772806833242, 0.68334268666386189, 0.66063755666452395, 0.70667012650879169, 0.75616720875118448, 0.0076071355040999147, 0.16722335929420953, 0.24228904960439612, 1, 1, 1, 0.74444444444444446, 0.74441099641078146, 0.74443754704645426, 0.73579757426674453, 0.7154614610083625, 0.76238207877819242, 0.80635338615523044, 0.010993657103543011, 0.24183918938496599, 0.28923568019902324, 1, 1, 1, 0.80555555555555558, 0.80548586203577432, 0.80556625128549619, 0.7607325689541361, 0.7709115279333274, 0.81874600280477805, 0.81846324371170665, 0.015863026451133713, 0.34650772248743805, 0.32712367869313513, 1, 1, 1, 0.8666666666666667, 0.86665068706416915, 0.86667726624963815, 0.77310372269008887, 0.82666048629288214, 0.87575544351530044, 0.82250334117333646, 0.022915833888653158, 0.49058181757621305, 0.32138671984149092, 1, 1, 1, 0.92777777777777781, 0.92781567340041837, 0.92781937609673271, 0.78228939831004085, 0.88241774237123771, 0.93313651551826904, 0.82559824503018264, 0.033028022568911568, 0.6869968410833619, 0.31804744512991351, 1, 1, 1, 0.98888888888888893, 0.98860321834099996, 0.98888850977399578, 0.78897052574490523, 0.93832104872570143, 0.99049121752897784, 0.82770087400040337, 0.049618846148749549, 0.94725737476210103, 0.31520682775233339, 1, 1, 1, 1.05, 1.0487348778724641, 1.0062218585376423, 0.79376542360284852, 1.0039295318936428, 1.0043865029637598, 0.82928412460314016, 0.049807927876335194, 0.99339517007581468, 0.31300940662606114, 1, 1, 1 }; -// ssc_data_set_matrix(data, "sco2ud_m_dot_htf_ind_od", p_sco2ud_m_dot_htf_ind_od, 10, 13); -// -// int status = run_module(data, "tcsmolten_salt"); -// -// return status; -//} - -// Molten Salt power tower - Super-critical CO2 power cycle -// ACTS framework driven testing -//int ACTS_sCO2_testing(ssc_data_t &data, int test_case) -//{ -// tcsmolten_salt_default(data); -// -// //ssc_data_set_number(data, "T_htf_cold_des", 414.53549194335938); // Different values each run ... But have no effect on outputs -// -// ssc_data_set_number(data, "pc_config", 2); -// -// ssc_data_set_number(data, "cycle_cutoff_frac", 0.5); -// -// //ssc_data_set_number(data, "sco2ud_T_htf_cold_calc", 414.53549194335938); // Different values each run ... But have no effect on outputs -// ssc_data_set_number(data, "sco2ud_T_htf_low", 554); -// ssc_data_set_number(data, "sco2ud_T_htf_high", 589); -// -// ssc_data_set_number(data, "sco2ud_T_amb_high", 45); -// ssc_data_set_number(data, "sco2ud_m_dot_htf_low", 0.5); -// ssc_data_set_number(data, "sco2ud_m_dot_htf_high", 1.05); -// ssc_number_t p_sco2ud_T_htf_ind_od[65] = { 554, 0.50001432179685623, 0.96932004909372826, 0.97558944094670463, 0.56452945008574118, 0.99212119137385479, 0.9938261663184943, 0.071046760698792344, 1.0516901234966409, 1.0396677815546937, 1, 1, 1, 562.75, 0.50000677254611736, 0.98273822965810698, 0.98931005948737616, 0.55442312464765453, 0.99593839560635933, 0.99813862855158975, 0.060760248142716182, 1.0280675561194188, 1.0216094704370726, 1, 1, 1, 571.5, 0.49997035485832741, 0.99560036541912367, 1.0030665958141747, 0.54540906175814596, 0.99964495720997093, 1.0023929148428683, 0.052633463645261176, 1.0056543163255209, 1.0033307681195913, 1, 1, 1, 580.25, 0.50001678576431519, 0.99981330235493204, 1.0149012834308118, 0.53755371644427918, 0.99437061481748712, 1.0057187757624548, 0.046124783184180999, 0.93267305740289486, 0.97564080126247599, 1, 1, 1, 589, 0.49998766910986947, 0.99997642865903091, 1.0280965929880774, 0.53035396718324523, 0.98587808938966315, 1.0103635810622889, 0.040778740942652915, 0.84986379353651254, 0.96107738725047209, 1, 1, 1 }; -// ssc_data_set_matrix(data, "sco2ud_T_htf_ind_od", p_sco2ud_T_htf_ind_od, 5, 13); -// ssc_number_t p_sco2ud_T_amb_ind_od[130] = { 0, 0.99994012767121321, 0.99974326147411507, 0.99987485850649338, 0.970379288808072, 0.95027470619969945, 0.93683012616718919, 0.059164848919520591, 0.049933864673572616, 0.04548467867978704, 1, 1, 1, 5, 0.99994012767121321, 0.99974326147411507, 0.99987485850649338, 0.970379288808072, 0.95027470619969945, 0.93683012616718919, 0.097133136927079936, 0.082248959886362452, 0.075269394493921518, 1, 1, 1, 10, 0.99994012767121321, 0.99974326147411507, 0.99987485850649338, 0.970379288808072, 0.95027470619969945, 0.93683012616718919, 0.17314165365655804, 0.14726896648379706, 0.13576325670205261, 1, 1, 1, 15, 0.99994012767121321, 0.99974326147411507, 0.99987485850649338, 0.970379288808072, 0.95027470619969945, 0.93683012616718919, 0.3481506775773433, 0.29853487098289033, 0.27855988861884273, 1, 1, 1, 20, 0.99994012767121321, 0.99974326147411507, 0.99987485850649338, 0.970379288808072, 0.95027470619969945, 0.93683012616718919, 0.85719459330059711, 0.74767538224853725, 0.71410844002614948, 1, 1, 1, 25, 0.99998860165458137, 0.99998405506376475, 0.99994129487763628, 0.97834420606252215, 0.9592086954026382, 0.94639328546002388, 1.4397512132898596, 1.1099623611534934, 0.9289610766286478, 1, 1, 1, 30, 0.99997868773200105, 1.0000128744625323, 0.99987390166815182, 0.99986135777103136, 0.97846151925556812, 0.96428182700735732, 1.2885473732704416, 1.0097961360792755, 0.85212892165494525, 1, 1, 1, 35, 0.96932004909372826, 0.99995022500741981, 0.99997642865903091, 0.99212119137385479, 0.99999459906789145, 0.98587808938966315, 1.0516901234966409, 1.0033307681195913, 0.84986379353651254, 1, 1, 1, 40, 0.85681928090544024, 0.88648580427756085, 0.90755440545490784, 0.8967547597723905, 0.90655814175453875, 0.91360819421216066, 0.54638640488302492, 0.52332590711799631, 0.50841120332212841, 1, 1, 1, 45, 0.76192612755033284, 0.78992076166486025, 0.81009772614290565, 0.81887517513574226, 0.82799762047592962, 0.83504194672755783, 0.32667431104075889, 0.31463845368914112, 0.30664767313185981, 1, 1, 1 }; -// ssc_data_set_matrix(data, "sco2ud_T_amb_ind_od", p_sco2ud_T_amb_ind_od, 10, 13); -// ssc_number_t p_sco2ud_m_dot_htf_ind_od[130] = { 0.5, 0.50000238394483887, 0.50002030400496988, 0.5000072744279479, 0.49996830468452913, 0.54311461140321193, 0.58949291750771449, 0.0023965079935530688, 0.050651289208334289, 0.085268991630535099, 1, 1, 1, 0.56111111111111112, 0.56107350053341665, 0.56109752841228611, 0.56110469253490813, 0.55257347648896971, 0.59674948077268875, 0.64372698634700765, 0.0035623149303332731, 0.076089576895326735, 0.12158112224599875, 1, 1, 1, 0.62222222222222223, 0.62224697121064898, 0.62224996267725707, 0.62219761804463092, 0.60616131300962228, 0.65145619071565242, 0.69969734374588888, 0.0052256619247860641, 0.11370919032872756, 0.17234788816884622, 1, 1, 1, 0.68333333333333335, 0.68334763160686485, 0.68332772806833242, 0.68334268666386189, 0.66063755666452395, 0.70667012650879169, 0.75616720875118448, 0.0076071355040999147, 0.16722335929420953, 0.24228904960439612, 1, 1, 1, 0.74444444444444446, 0.74441099641078146, 0.74443754704645426, 0.73579757426674453, 0.7154614610083625, 0.76238207877819242, 0.80635338615523044, 0.010993657103543011, 0.24183918938496599, 0.28923568019902324, 1, 1, 1, 0.80555555555555558, 0.80548586203577432, 0.80556625128549619, 0.7607325689541361, 0.7709115279333274, 0.81874600280477805, 0.81846324371170665, 0.015863026451133713, 0.34650772248743805, 0.32712367869313513, 1, 1, 1, 0.8666666666666667, 0.86665068706416915, 0.86667726624963815, 0.77310372269008887, 0.82666048629288214, 0.87575544351530044, 0.82250334117333646, 0.022915833888653158, 0.49058181757621305, 0.32138671984149092, 1, 1, 1, 0.92777777777777781, 0.92781567340041837, 0.92781937609673271, 0.78228939831004085, 0.88241774237123771, 0.93313651551826904, 0.82559824503018264, 0.033028022568911568, 0.6869968410833619, 0.31804744512991351, 1, 1, 1, 0.98888888888888893, 0.98860321834099996, 0.98888850977399578, 0.78897052574490523, 0.93832104872570143, 0.99049121752897784, 0.82770087400040337, 0.049618846148749549, 0.94725737476210103, 0.31520682775233339, 1, 1, 1, 1.05, 1.0487348778724641, 1.0062218585376423, 0.79376542360284852, 1.0039295318936428, 1.0043865029637598, 0.82928412460314016, 0.049807927876335194, 0.99339517007581468, 0.31300940662606114, 1, 1, 1 }; -// ssc_data_set_matrix(data, "sco2ud_m_dot_htf_ind_od", p_sco2ud_m_dot_htf_ind_od, 10, 13); -// // sco2 default configuration preprocessing parameters -// ssc_data_set_number(data, "_sco2_P_high_limit", 25); -// ssc_data_set_number(data, "_sco2_P_ref", 115); -// ssc_data_set_number(data, "_sco2_T_amb_des", 35); -// ssc_data_set_number(data, "_sco2_T_approach", 10); -// ssc_data_set_number(data, "_sco2_T_htf_hot_des", 574); -// ssc_data_set_number(data, "_sco2_deltaT_PHX", 20); -// ssc_data_set_number(data, "_sco2_design_eff", 0.412); -// ssc_data_set_number(data, "_sco2_eta_c", 0.89); -// ssc_data_set_number(data, "_sco2_eta_t", 0.9); -// ssc_data_set_number(data, "_sco2_recup_eff_max", 0.96); -// -// // Testing level to vector index map -// std::unordered_map idx = -// { -// {-1, 0}, -// { 0, 1}, -// { 1, 2} -// }; -// -// // Parameter test range values -// std::vector sco2_T_amb_des_vals{ 20.98, 35, 60 }; // Ambient temperature at design // SAM SSC - "sco2_T_amb_des" -// std::vector sco2_T_approach_vals{ 1, 10, 30 }; // Air cooler aproach temperature // SAM SSC - "sco2_T_approach" -// std::vector deltaT_PHX_vals{ 1, 20, 50 }; // PHX approach temperature // SAM SSC - "deltaT_PHX" -// std::vector eta_c_vals{ 0.70, 0.89, 1.0 }; // Compressor(s) Isentropic efficiency // SAM SSC - "eta_c" -// std::vector eta_t_vals{ 0.70, 0.90, 1.0 }; // Turbine Isentropic efficiency // SAM SSC - "eta_t" -// std::vector fan_power_perc_net_vals{ 0.25, 1.5, 5 }; // Cooling fan electricity consumption // SAM SSC - "fan_power_perc_net" -// -// // Full ACTS sCO2 framework - 15 total tests, where 6/15 tests are actually able to simulate on the SAM UI -// -// // Test case pass/fail summary 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 -// // P = Pass & F = Fail in SAM UI F P F P P F P F F F F P F F P -// // std::vector sco2_T_amb_des_lvls{ -1, -1, -1, 0, 0, 0, 1, 1, 1, -1, 0, 1, 1, -1, 1 }; -// // std::vector sco2_T_approach_lvls{ -1, 0, 1, -1, 0, 1, -1, 0, 1, -1, 0, 0, 1, -1, 1 }; -// // std::vector deltaT_PHX_lvls{ 0, 1, -1, 1, -1, 0, -1, 0, 1, 0, 1, -1, 1, -1, 0 }; -// // std::vector eta_c_lvls{ 0, 1, -1, -1, 0, 1, 1, -1, 0, 0, 1, 1, -1, 1, 1 }; -// // std::vector eta_t_lvls{ 0, 1, -1, 0, 1, -1, 0, 1, -1, -1, -1, 0, 0, 1, 1 }; -// // std::vector fan_power_perc_net_lvls{ 0, 1, -1, 1, -1, 0, -1, 0, 1, -1, -1 , 0, 0, 1, 1 }; -// -// -// // Passing ACTS sco2 tests within the SAM UI -// // NOTE: -// // Certain tests are able to completely pass the unit tests -// // using high tolerances while some tests still are -// // unable to pass using the high tolerances when testing outputs -// -// // Unit test case pass/fall summary 2 4 5 7 12 15 -// // P = Pass & F = Fail for tested outputs F F P P P F -// // std::vector sco2_T_amb_des_lvls{ -1, 0, 0, 1, 1, 1 }; -// // std::vector sco2_T_approach_lvls{ 0, -1, 0, -1, 0, 1 }; -// // std::vector deltaT_PHX_lvls{ 1, 1, -1, -1, -1, 0 }; -// // std::vector eta_c_lvls{ 1, -1, 0, 1, 1, 1 }; -// // std::vector eta_t_lvls{ 1, 0, 1, 0, 0, 1 }; -// // std::vector fan_power_perc_net_lvls{ 1, 1, 1, -1, 0, 1 }; -// -// -// // Passing SAM UI configurations 5 7 12 -// // P = Pass & F = Fail for tested outputs P P P -// std::vector sco2_T_amb_des_lvls{ 0, 1, 1 }; -// std::vector sco2_T_approach_lvls{ 0, -1, 0 }; -// std::vector deltaT_PHX_lvls{ -1, -1, -1 }; -// std::vector eta_c_lvls{ 0, 1, 1 }; -// std::vector eta_t_lvls{ 1, 0, 0 }; -// std::vector fan_power_perc_net_lvls{ 1, -1, 0 }; -// -// // Get test case values from index -// double sco2_T_amb_des_ACTS = sco2_T_amb_des_vals.at(idx.find(sco2_T_amb_des_lvls.at(test_case))->second); -// double sco2_T_approach_ACTS = sco2_T_approach_vals.at(idx.find(sco2_T_approach_lvls.at(test_case))->second); -// double deltaT_PHX_ACTS = deltaT_PHX_vals.at(idx.find(deltaT_PHX_lvls.at(test_case))->second); -// double eta_c_ACTS = eta_c_vals.at(idx.find(eta_c_lvls.at(test_case))->second); -// double eta_t_ACTS = eta_t_vals.at(idx.find(eta_t_lvls.at(test_case))->second); -// double fan_power_perc_net_ACTS = fan_power_perc_net_vals.at(idx.find(fan_power_perc_net_lvls.at(test_case))->second); -// -// // Assigning values to variables -// ssc_data_set_number(data, "sco2_T_amb_des", sco2_T_amb_des_ACTS); -// ssc_data_set_number(data, "sco2_T_approach", sco2_T_approach_ACTS); -// ssc_data_set_number(data, "deltaT_PHX", deltaT_PHX_ACTS); -// ssc_data_set_number(data, "eta_c", eta_c_ACTS); -// ssc_data_set_number(data, "eta_t", eta_t_ACTS); -// ssc_data_set_number(data, "fan_power_perc_net", fan_power_perc_net_ACTS); -// -// int status = run_module(data, "tcsmolten_salt"); -// -// return status; -//} - -#endif diff --git a/test/tcs_test/tcstrough_empirical_cases.h b/test/tcs_test/tcstrough_empirical_cases.h deleted file mode 100644 index 7e535117408..00000000000 --- a/test/tcs_test/tcstrough_empirical_cases.h +++ /dev/null @@ -1,241 +0,0 @@ -#ifndef _TCSTROUGH_EMPIRICAL_CASES_H -#define _TCSTROUGH_EMPIRICAL_CASES_H - -#include -#include "../input_cases/code_generator_utilities.h" -#include "tcstrough_empirical_common_data.h" - -/** -* Data for high-level integration tests that verifies whether results for a parabolic trough (empirical) -* plant in Tucson, AZ matches expected results. -* Data generated from code-generator (Shift+F5) within SAM UI. -* Test uses SSCAPI interfaces (similiar to SDK usage) to pass and receive data to tcstrough_empirical -*/ - -// Parabolic trough (empirical) default configuration -int tcstrough_empirical_tucson_default(ssc_data_t &data) -{ - tcstrough_empirical_default(data); - - int status = run_module(data, "tcstrough_empirical"); - - //single_owner_default(data); - //status += run_module(data, "singleowner"); - - return status; -} - -// Parabolic trough (empirical) with alternative Solar Field HTF type -// Solar Field HTF type: Hitec Solar Salt -// Rest default configurations -int tcstrough_empirical_tucson_solar_field_HTF(ssc_data_t &data) -{ - tcstrough_empirical_default(data); - - ssc_data_set_number(data, "HTFFluid", 18); - ssc_data_set_number(data, "PTSmax", 676.471); - ssc_data_set_number(data, "PFSmax", 342.699); - - int status = run_module(data, "tcstrough_empirical"); - - return status; -} - -// Parabolic trough (empirical) with alternative Solar Collector Assembly (SCA) -// Solar collector assembly (SCA): EuroTrough ET150 -// Rest default configurations -int tcstrough_empirical_tucson_SCA(ssc_data_t &data) -{ - tcstrough_empirical_default(data); - - ssc_data_set_number(data, "Solar_Field_Area", 856740); - ssc_data_set_number(data, "Ave_Focal_Length", 2.1); - ssc_data_set_number(data, "ScaLen", 150); - ssc_data_set_number(data, "SCA_aper", 5.75); - ssc_data_set_number(data, "TrkTwstErr", 0.99); - ssc_data_set_number(data, "MirCln", 0.97); - ssc_number_t p_HCEdust[4] = { 0.98, 0.98, 0.98, 0.98 }; - ssc_data_set_array(data, "HCEdust", p_HCEdust, 4); - ssc_number_t p_RefMirrAper[4] = { 5.75, 5.75, 5.75, 5.75 }; - ssc_data_set_array(data, "RefMirrAper", p_RefMirrAper, 4); - ssc_data_set_number(data, "SfPar", 0.228); - ssc_data_set_number(data, "ChtfPar", 9.013); - ssc_data_set_number(data, "AntiFrPar", 0.9013); - - int status = run_module(data, "tcstrough_empirical"); - - return status; -} - -// Parabolic trough (empirical) with alternative Heat Collection Element (HCE) -// Heat Collection Element (HCE): Luz Cermet Vacuum, Luz Cermet Hydrogren, and Luz Cermet Broken Glass -// Rest default configurations -int tcstrough_empirical_tucson_HCE(ssc_data_t &data) -{ - tcstrough_empirical_default(data); - - ssc_data_set_number(data, "Solar_Field_Area", 1015848); - ssc_number_t p_HCEBelShad[4] = { 0.971, 0.971, 0.971, 0 }; - ssc_data_set_array(data, "HCEBelShad", p_HCEBelShad, 4); - ssc_number_t p_HCEEnvTrans[4] = { 0.935, 0.935, 1, 0 }; - ssc_data_set_array(data, "HCEEnvTrans", p_HCEEnvTrans, 4); - ssc_number_t p_HCEabs[4] = { 0.925, 0.925, 0.8, 0 }; - ssc_data_set_array(data, "HCEabs", p_HCEabs, 4); - ssc_number_t p_PerfFac[4] = { 1.25, 1.25, 1.25, 0 }; - ssc_data_set_array(data, "PerfFac", p_PerfFac, 4); - ssc_number_t p_HCE_A0[4] = { 2.424, 7.0233, 100.05, 0 }; - ssc_data_set_array(data, "HCE_A0", p_HCE_A0, 4); - ssc_number_t p_HCE_A1[4] = { 0.214, 1.275, -0.7351, 0 }; - ssc_data_set_array(data, "HCE_A1", p_HCE_A1, 4); - ssc_number_t p_HCE_A2[4] = { -0.00047461, 0.0015105, -0.008635, 0 }; - ssc_data_set_array(data, "HCE_A2", p_HCE_A2, 4); - ssc_number_t p_HCE_A3[4] = { 6.88e-06, 5.05e-06, 2.67e-05, 0 }; - ssc_data_set_array(data, "HCE_A3", p_HCE_A3, 4); - ssc_number_t p_HCE_A4[4] = { 9.62e-08, 7.03e-08, 6.65e-07, 0 }; - ssc_data_set_array(data, "HCE_A4", p_HCE_A4, 4); - ssc_number_t p_HCE_A5[4] = { -2.2423, -4.284, -99.043, 0 }; - ssc_data_set_array(data, "HCE_A5", p_HCE_A5, 4); - ssc_number_t p_HCE_A6[4] = { 0.032325, 0.39685, 5.1672, 0 }; - ssc_data_set_array(data, "HCE_A6", p_HCE_A6, 4); - ssc_data_set_number(data, "SfPar", 0.270); - ssc_data_set_number(data, "ChtfPar", 10.687); - ssc_data_set_number(data, "AntiFrPar", 1.069); - - - int status = run_module(data, "tcstrough_empirical"); - - return status; -} - -// Parabolic trough (empirical) with alternative Power Cycle -// Power Cycle: APS Ormat 1MWe 300C -// Rest default configurations -int tcstrough_empirical_tucson_power_cycle(ssc_data_t &data) -{ - tcstrough_empirical_default(data); - - ssc_data_set_number(data, "Solar_Field_Area", 1599020); - ssc_data_set_number(data, "TurbEffG", 0.2071); - ssc_data_set_number(data, "TurSUE", 0.05); - ssc_data_set_number(data, "T2EPLF0", -0.1594); - ssc_data_set_number(data, "T2EPLF1", 0.9262); - ssc_data_set_number(data, "T2EPLF2", 1.1349); - ssc_data_set_number(data, "T2EPLF3", -1.3606); - ssc_data_set_number(data, "T2EPLF4", 0.4588); - ssc_data_set_number(data, "E2TPLF0", 0.1492); - ssc_data_set_number(data, "E2TPLF1", 0.8522); - ssc_data_set_number(data, "E2TPLF2", -0.3247); - ssc_data_set_number(data, "E2TPLF3", 0.44863); - ssc_data_set_number(data, "E2TPLF4", -0.1256); - ssc_data_set_number(data, "TempCorrF", 0); - ssc_data_set_number(data, "TempCorr0", 1); - ssc_data_set_number(data, "TempCorr1", 0); - ssc_data_set_number(data, "TempCorr2", 0); - ssc_data_set_number(data, "TempCorr3", 0); - ssc_data_set_number(data, "TempCorr4", 0); - ssc_data_set_number(data, "PTSmax", 535.973); - ssc_data_set_number(data, "PFSmax", 543.0467); - ssc_data_set_number(data, "SfPar", 0.42534); - ssc_data_set_number(data, "ChtfPar", 16.8217); - ssc_data_set_number(data, "AntiFrPar", 1.6822); - - int status = run_module(data, "tcstrough_empirical"); - - return status; -} - -// Parabolic trough (empirical) with alternative Thermal Stoage Fluid Type -// Thermal Storage Fluid Type: Therminol VP-1 -// Rest default configurations -int tcstrough_empirical_tucson_thermal_storage(ssc_data_t &data) -{ - tcstrough_empirical_default(data); - - ssc_data_set_number(data, "PTSmax", 676.4706); - ssc_data_set_number(data, "PFSmax", 342.699); - - int status = run_module(data, "tcstrough_empirical"); - - return status; -} - -// Parabolic trough (empirical) with alternative Parasitic Electric Energy Use -// Parasitic Electric Energy Use: 500C Molten Salt HTF -// Rest default configurations -int tcstrough_empirical_tucson_parasitic(ssc_data_t &data) -{ - tcstrough_empirical_default(data); - - ssc_data_set_number(data, "SfPar", 0.117); - ssc_data_set_number(data, "SfParPF", 0.5); - ssc_data_set_number(data, "ChtfPar", 3.231); - ssc_data_set_number(data, "ChtfParPF", 0.35); - ssc_data_set_number(data, "AntiFrPar", 0.323); - ssc_data_set_number(data, "HhtfPar", 0.777); - ssc_data_set_number(data, "HhtfParPF", 0.35); - - int status = run_module(data, "tcstrough_empirical"); - - return status; -} - -// Parabolic trough (empirical) with alternative location -// Location: Phoenix, AZ -// Rest default configurations -int tcstrough_empirical_phoenix(ssc_data_t &data) -{ - tcstrough_empirical_default(data); - - char solar_resource_path_phoenix[512]; - int n = sprintf(solar_resource_path_phoenix, "%s/test/input_cases/trough_empirical_data/phoenix_az_33.450495_-111.983688_psmv3_60_tmy.csv", std::getenv("SSCDIR")); - ssc_data_set_string(data, "file_name", solar_resource_path_phoenix); - - int status = run_module(data, "tcstrough_empirical"); - - return status; -} - -// Test series of Advanced Combinatorial Testing System (ACTS) runs -// Parabolic trough (empirical) -//int ACTS_test_empirical(ssc_data_t &data, int test_case) -//{ -// tcstrough_empirical_default(data); -// -// // Testing level to vector index map -// std::unordered_map idx = -// { -// {-1, 0}, -// { 0, 1}, -// { 1, 2} -// }; -// -// // Parameter test range values -// std::vector Distance_SCA_vals{ 0.5, 1 , 2 }; // Distance Between SCAs in Row // SAM SSC - "Distance_SCA" -// std::vector NumScas_vals{ 1, 4, 8 }; // Number of SCAs per Row // SAM SSC - "NumScas" -// std::vector DepAngle_vals{ 5, 10, 20 }; // Deploy Angle // SAM SSC - "DepAngle" -// std::vector Stow_Angle_vals{ 160, 170, 175 }; // Stow Angle // SAM SSC - "Stow_Angle" -// -// // ACTS transposed covering array 1 2 3 4 5 6 7 8 9 -// std::vector Distance_SCA_lvls{ -1, -1, -1, 0, 0, 0, 1, 1, 1 }; -// std::vector NumScas_lvls{ -1, 0, 1, -1, 0, 1, -1, 0, 1 }; -// std::vector DepAngle_lvls{ 0, 1, -1, 1, -1, 0, -1, 0, 1 }; -// std::vector Stow_Angle_lvls{ 0, 1, -1, -1, 0, 1, 1, -1, 0 }; -// -// // Get test case values from index -// double Distance_SCA_ACTS = Distance_SCA_vals.at(idx.find(Distance_SCA_lvls.at(test_case))->second); -// double NumScas_ACTS = NumScas_vals.at(idx.find(NumScas_lvls.at(test_case))->second); -// double DepAngle_ACTS = DepAngle_vals.at(idx.find(DepAngle_lvls.at(test_case))->second); -// double Stow_Angle_ACTS = Stow_Angle_vals.at(idx.find(Stow_Angle_lvls.at(test_case))->second); -// -// // Assigning values to variables -// ssc_data_set_number(data, "Distance_SCA", Distance_SCA_ACTS); -// ssc_data_set_number(data, "NumScas", NumScas_ACTS); -// ssc_data_set_number(data, "DepAngle", DepAngle_ACTS); -// ssc_data_set_number(data, "Stow_Angle", Stow_Angle_ACTS); -// -// int status = run_module(data, "tcstrough_empirical"); -// -// return status; -//} - -#endif diff --git a/test/tcs_test/trough_physical_cases.h b/test/tcs_test/trough_physical_cases.h deleted file mode 100644 index db4195fb39b..00000000000 --- a/test/tcs_test/trough_physical_cases.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef _TROUGH_PHYSICAL_CASES_H_ -#define _TROUGH_PHYSICAL_CASES_H_ - -#include -#include "../input_cases/code_generator_utilities.h" -#include "trough_physical_common_data.h" - -/** -* Data for high-level integration tests that verifies whether results for a parabolic trough -* plant in Tucson matches expected results. -* Data generated from code-generator (Shift+F5) within SAM UI. -* Test uses SSCAPI interfaces (similiar to SDK usage) to pass and receive data to trough_physical -*/ -int trough_physical_tucson(ssc_data_t &data) -{ - trough_physical_default(data); - int status = run_module(data, "trough_physical"); - - //convert_and_adjust_fixed_charge(data); - //status += run_module(data, "iph_to_lcoefcr"); - - //fixed_charge_rate_default(data); - //status += run_module(data, "lcoefcr"); - - return status; -} - -#endif diff --git a/test/tcs_test/trough_physical_iph_cases.h b/test/tcs_test/trough_physical_iph_cases.h deleted file mode 100644 index 61acccbdd64..00000000000 --- a/test/tcs_test/trough_physical_iph_cases.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef _TROUGH_PHYSICAL_IPH_CASES_H_ -#define _TROUGH_PHYSICAL_IPH_CASES_H_ - -#include -#include "../input_cases/code_generator_utilities.h" -#include "trough_physical_iph_common_data.h" - -/** -* Data for high-level integration tests that verifies whether results for a parabolic trough -* industrial process heat (iph) plant in Tucson matches expected results. -* Data generated from code-generator (Shift+F5) within SAM UI. -* Test uses SSCAPI interfaces (similiar to SDK usage) to pass and receive data to trough_physical_iph -*/ -//int trough_physical_iph_tucson(ssc_data_t &data) -//{ -// trough_physical_iph_default(data); -// int status = run_module(data, "trough_physical_process_heat"); -// -// convert_and_adjust_fixed_charge(data); -// status += run_module(data, "iph_to_lcoefcr"); -// -// fixed_charge_rate_default(data); -// status += run_module(data, "lcoefcr"); -// -// return status; -//} - -#endif From e094dad26043ef2c3c629db365c8d35acd78bb62 Mon Sep 17 00:00:00 2001 From: Noel Merket Date: Fri, 5 Feb 2021 09:42:33 -0700 Subject: [PATCH 41/76] reiniting battery state, passing powerCharged/powerDischarged back --- src/EnergyPlus/ElectricPowerServiceManager.cc | 35 ++++++++++++++----- src/EnergyPlus/ElectricPowerServiceManager.hh | 1 + 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/src/EnergyPlus/ElectricPowerServiceManager.cc b/src/EnergyPlus/ElectricPowerServiceManager.cc index 1abad29b415..7c0aea2ce90 100644 --- a/src/EnergyPlus/ElectricPowerServiceManager.cc +++ b/src/EnergyPlus/ElectricPowerServiceManager.cc @@ -3193,6 +3193,7 @@ ElectricStorage::ElectricStorage( // main constructor maxAhCapacity_ = liIon_Qfull_ * seriesNum_ * parallelNum_; + // FIXME: Disable lifetime model when requested. std::vector batt_losses{0}; // using double because SSC expects a double ssc_battery_ = std::unique_ptr( new battery_t( @@ -3235,6 +3236,7 @@ ElectricStorage::ElectricStorage( // main constructor ) ); *ssc_lastBatteryState_ = ssc_battery_->get_state(); + *ssc_initBatteryState_ = ssc_battery_->get_state(); break; } case StorageModelType::storageTypeNotSet: { @@ -3386,6 +3388,9 @@ void ElectricStorage::reinitAtBeginEnvironment() } batteryDamage_ = 0.0; } + } else if (storageModelMode_ == StorageModelType::liIonNmcBattery) { + // Copy the initial battery state to the last battery state + *ssc_lastBatteryState_ = *ssc_initBatteryState_; } myWarmUpFlag_ = true; } @@ -3399,7 +3404,6 @@ void ElectricStorage::reinitZoneGainsAtBeginEnvironment() void ElectricStorage::reinitAtEndWarmup() { // need to reset initial state of charge at beginning of environment but after warm up is complete - // FIXME: get this reset for li-ion batteries lastTimeStepStateOfCharge_ = startingEnergyStored_; thisTimeStepStateOfCharge_ = startingEnergyStored_; if (storageModelMode_ == StorageModelType::kiBaMBattery) { @@ -3424,6 +3428,9 @@ void ElectricStorage::reinitAtEndWarmup() } batteryDamage_ = 0.0; } + } else if (storageModelMode_ == StorageModelType::liIonNmcBattery) { + // Copy the initial battery state to the last battery state + *ssc_lastBatteryState_ = *ssc_initBatteryState_; } myWarmUpFlag_ = false; } @@ -3851,6 +3858,7 @@ void ElectricStorage::simulateLiIonNmcBatteryModel(EnergyPlusData &state, // Run the battery // SAM uses negative values for charging, positive for discharging + // E+ power/energy outputs are positive double power{0.0}; // Using double instead of Real64 because SSC is expecting a double if (charging) { power = - powerCharge; @@ -3859,28 +3867,37 @@ void ElectricStorage::simulateLiIonNmcBatteryModel(EnergyPlusData &state, } power *= 0.001; // Convert to kW ssc_battery_->runPower(power); + // FIXME: Track down these controlSOCMax/MinFracLimit and figure out what to do with them. + // FIXME: Check other class members that store simulation state that are retrieved from getters and set accordingly. // Store outputs - const battery_state battState2 = ssc_battery_->get_state(); + const battery_state& battState2{ssc_battery_->get_state()}; if (battState2.P < 0.0) { // negative for charging storageMode_ = 2; + powerCharge = fabs(battState2.P) * 1000.0; // kW -> W + powerDischarge = 0.0; + charging = true; + discharging = false; } else if (battState2.P > 0.0) { // positive for discharging storageMode_ = 1; + powerCharge = 0.0; + powerDischarge = fabs(battState2.P) * 1000.0; // kW -> W + charging = false; + discharging = true; } else { storageMode_ = 0; + powerCharge = 0.0; + powerDischarge = 0.0; + charging = false; + discharging = false; } absoluteSOC_ = ssc_battery_->charge_total(); fractionSOC_ = ssc_battery_->SOC() * 0.01; // % -> fraction batteryCurrent_ = ssc_battery_->I(); batteryVoltage_ = ssc_battery_->V(); batteryDamage_ = 1.0 - (ssc_battery_->charge_maximum_lifetime() / maxAhCapacity_); - if (battState2.P < 0.0) { // negative for charging - storedPower_ = - battState2.P * 1000.0; // kW -> W - drawnPower_ = 0.0; - } else { // positive for discharging - storedPower_ = 0.0; - drawnPower_ = battState2.P * 1000.0; // kW -> W - } + storedPower_ = powerCharge; + drawnPower_ = powerDischarge; storedEnergy_ = storedPower_ * DataHVACGlobals::TimeStepSys * DataGlobalConstants::SecInHour; decrementedEnergyStored_ = - storedEnergy_; thermLossRate_ = battState2.thermal->heat_dissipated * 1000.0; // kW -> W diff --git a/src/EnergyPlus/ElectricPowerServiceManager.hh b/src/EnergyPlus/ElectricPowerServiceManager.hh index d010a132d3d..0c6db0c7810 100644 --- a/src/EnergyPlus/ElectricPowerServiceManager.hh +++ b/src/EnergyPlus/ElectricPowerServiceManager.hh @@ -410,6 +410,7 @@ private: // data // Li-ion NMC battery objects from SAM Simulation Core lib_battery std::unique_ptr ssc_battery_; std::unique_ptr ssc_lastBatteryState_; + std::unique_ptr ssc_initBatteryState_; // battery life calculation variables int count0_; std::vector b10_; From 3eda318b07c6e897456fb75f32bc34cf60a909ba Mon Sep 17 00:00:00 2001 From: Noel Merket Date: Fri, 5 Feb 2021 14:29:18 -0700 Subject: [PATCH 42/76] switch to using the min/max SOC from ElectricLoadCenter:Distribution --- idd/Energy+.idd.in | 42 +++------ src/EnergyPlus/ElectricPowerServiceManager.cc | 93 +++++++------------ src/EnergyPlus/ElectricPowerServiceManager.hh | 3 +- 3 files changed, 52 insertions(+), 86 deletions(-) diff --git a/idd/Energy+.idd.in b/idd/Energy+.idd.in index 80e4c23234f..7c106d52018 100644 --- a/idd/Energy+.idd.in +++ b/idd/Energy+.idd.in @@ -88797,90 +88797,78 @@ ElectricLoadCenter:Storage:LiIonNMCBattery, \minimum 1 \default 1 \note TODO - N4, \field Minimum Available State of Charge - \type real - \minimum 0 - \maximum< 1.0 - \default 0.15 - \note A model parameter usually derived from test data by curve fitting. - N5, \field Maximum Available State of Charge - \type real - \minimum> 0 - \maximum 1.0 - \default 0.95 - \note A model parameter usually derived from test data by curve fitting. - N6, \field Initial Fractional State of Charge + N4, \field Initial Fractional State of Charge \type real \minimum 0 \maximum 1.0 \default 0.5 \note The state of charge is evaluated based on the \note maximum capacity defined in the next field. - N7, \field DC to DC Charging Efficiency + N5, \field DC to DC Charging Efficiency \type real \minimum> 0 \maximum 1 \default 0.95 - N8, \field Battery Mass + N6, \field Battery Mass \type real \minimum> 0 \units kg \default 95.1255 - N9, \field Battery Surface Area + N7, \field Battery Surface Area \type real \minimum> 0 \units m2 \default 0.5 - N10, \field Battery Specific Heat Capacity + N8, \field Battery Specific Heat Capacity \type real \minimum> 0 \units J/kg-K \default 1500 - N11, \field Heat Transfer Coefficient Between Battery and Ambient + N9, \field Heat Transfer Coefficient Between Battery and Ambient \type real \minimum> 0 \units W/m2-K \default 7.5 - N12, \field Fully Charged Cell Voltage + N10, \field Fully Charged Cell Voltage \type real \minimum> 0 \units V \default 4.2 - N13, \field Cell Voltage at End of Exponential Zone + N11, \field Cell Voltage at End of Exponential Zone \type real \minimum> 0 \units V \default 3.53 - N14, \field Cell Voltage at End of Nominal Zone + N12, \field Cell Voltage at End of Nominal Zone \type real \minimum> 0 \units V \default 3.342 - N15, \field Default Nominal Cell Voltage + N13, \field Default Nominal Cell Voltage \type real \minimum> 0 \units V \default 3.342 - N16, \field Fully Charged Cell Capacity + N14, \field Fully Charged Cell Capacity \type real \minimum> 0 \units Ah \default 1 - N17, \field Cell Capacity at End of Exponential Zone + N15, \field Cell Capacity at End of Exponential Zone \type real \minimum> 0 \units Ah \default 0.1925 - N18, \field Cell Capacity at End of Nominal Zone + N16, \field Cell Capacity at End of Nominal Zone \type real \minimum> 0 \units Ah \default 0.0231 - N19, \field Rate at Which Voltage vs Capacity Curve Input + N17, \field Rate at Which Voltage vs Capacity Curve Input \type real \minimum> 0 \default 1 - N20; \field Battery Cell Internal Electrical Resistance + N18; \field Battery Cell Internal Electrical Resistance \type real \minimum 0 \units ohms diff --git a/src/EnergyPlus/ElectricPowerServiceManager.cc b/src/EnergyPlus/ElectricPowerServiceManager.cc index 7c0aea2ce90..4ae1d3af3f4 100644 --- a/src/EnergyPlus/ElectricPowerServiceManager.cc +++ b/src/EnergyPlus/ElectricPowerServiceManager.cc @@ -2946,8 +2946,8 @@ ElectricStorage::ElectricStorage( // main constructor maxRainflowArrayInc_(100), myWarmUpFlag_(false), storageModelMode_(StorageModelType::storageTypeNotSet), availSchedPtr_(0), heatLossesDestination_(ThermalLossDestination::heatLossNotDetermined), zoneNum_(0), zoneRadFract_(0.0), startingEnergyStored_(0.0), energeticEfficCharge_(0.0), energeticEfficDischarge_(0.0), maxPowerDraw_(0.0), maxPowerStore_(0.0), maxEnergyCapacity_(0.0), parallelNum_(0), - seriesNum_(0), numBattery_(0), chargeCurveNum_(0), dischargeCurveNum_(0), cycleBinNum_(0), startingSOC_(0.0), maxAhCapacity_(0.0), maxSOC_(0.0), - chargeConversionRate_(0.0), chargedOCV_(0.0), dischargedOCV_(0.0), internalR_(0.0), maxDischargeI_(0.0), cutoffV_(0.0), + seriesNum_(0), numBattery_(0), chargeCurveNum_(0), dischargeCurveNum_(0), cycleBinNum_(0), startingSOC_(0.0), maxAhCapacity_(0.0), + availableFrac_(0.0), chargeConversionRate_(0.0), chargedOCV_(0.0), dischargedOCV_(0.0), internalR_(0.0), maxDischargeI_(0.0), cutoffV_(0.0), maxChargeRate_(0.0), lifeCalculation_(BatteyDegredationModelType::degredationNotSet), lifeCurveNum_(0), thisTimeStepStateOfCharge_(0.0), lastTimeStepStateOfCharge_(0.0), pelNeedFromStorage_(0.0), pelFromStorage_(0.0), pelIntoStorage_(0.0), qdotConvZone_(0.0), qdotRadZone_(0.0), timeElapsed_(0.0), thisTimeStepAvailable_(0.0), thisTimeStepBound_(0.0), lastTimeStepAvailable_(0.0), lastTimeStepBound_(0.0), @@ -3133,7 +3133,7 @@ ElectricStorage::ElectricStorage( // main constructor numBattery_ = parallelNum_ * seriesNum_; maxAhCapacity_ = DataIPShortCuts::rNumericArgs(4); startingSOC_ = DataIPShortCuts::rNumericArgs(5); - maxSOC_ = DataIPShortCuts::rNumericArgs(6); + availableFrac_ = DataIPShortCuts::rNumericArgs(6); chargeConversionRate_ = DataIPShortCuts::rNumericArgs(7); chargedOCV_ = DataIPShortCuts::rNumericArgs(8); dischargedOCV_ = DataIPShortCuts::rNumericArgs(9); @@ -3152,44 +3152,21 @@ ElectricStorage::ElectricStorage( // main constructor } seriesNum_ = DataIPShortCuts::lNumericFieldBlanks(2) ? 3 : static_cast(DataIPShortCuts::rNumericArgs(2)); parallelNum_ = DataIPShortCuts::lNumericFieldBlanks(3) ? 1 : static_cast(DataIPShortCuts::rNumericArgs(3)); - minSOC_ = DataIPShortCuts::lNumericFieldBlanks(4) ? 0.15 : DataIPShortCuts::rNumericArgs(4); - maxSOC_ = DataIPShortCuts::lNumericFieldBlanks(5) ? 0.95 : DataIPShortCuts::rNumericArgs(5); - if (minSOC_ >= maxSOC_) { - ShowSevereError(state, routineName + DataIPShortCuts::cCurrentModuleObject + "=\"" + DataIPShortCuts::cAlphaArgs(1) + "\", invalid entry."); - ShowContinueError(state, DataIPShortCuts::cNumericFieldNames(4) + " should be less than " + DataIPShortCuts::cNumericFieldNames(5)); - ShowContinueError(state, format("{} = {:.3R}.", DataIPShortCuts::cNumericFieldNames(4), DataIPShortCuts::rNumericArgs(4))); - ShowContinueError(state, format("{} = {:.3R}.", DataIPShortCuts::cNumericFieldNames(5), DataIPShortCuts::rNumericArgs(5))); - errorsFound = true; - } - startingSOC_ = DataIPShortCuts::lNumericFieldBlanks(6) ? 0.5 : DataIPShortCuts::rNumericArgs(6); - if (startingSOC_ > maxSOC_) { - ShowSevereError(state, routineName + DataIPShortCuts::cCurrentModuleObject + "=\"" + DataIPShortCuts::cAlphaArgs(1) + "\", invalid entry."); - ShowContinueError(state, DataIPShortCuts::cNumericFieldNames(6) + " should be less than or equal to " + DataIPShortCuts::cNumericFieldNames(5)); - ShowContinueError(state, format("{} = {:.3R}.", DataIPShortCuts::cNumericFieldNames(6), DataIPShortCuts::rNumericArgs(6))); - ShowContinueError(state, format("{} = {:.3R}.", DataIPShortCuts::cNumericFieldNames(5), DataIPShortCuts::rNumericArgs(5))); - errorsFound = true; - } - if (startingSOC_ < minSOC_) { - ShowSevereError(state, routineName + DataIPShortCuts::cCurrentModuleObject + "=\"" + DataIPShortCuts::cAlphaArgs(1) + "\", invalid entry."); - ShowContinueError(state, DataIPShortCuts::cNumericFieldNames(6) + " should be greater than or equal to " + DataIPShortCuts::cNumericFieldNames(4)); - ShowContinueError(state, format("{} = {:.3R}.", DataIPShortCuts::cNumericFieldNames(6), DataIPShortCuts::rNumericArgs(6))); - ShowContinueError(state, format("{} = {:.3R}.", DataIPShortCuts::cNumericFieldNames(4), DataIPShortCuts::rNumericArgs(4))); - errorsFound = true; - } - liIon_dcToDcChargingEff_ = DataIPShortCuts::lNumericFieldBlanks(7) ? 0.95 : DataIPShortCuts::rNumericArgs(7); - liIon_mass_ = DataIPShortCuts::lNumericFieldBlanks(8) ? 95.1255 : DataIPShortCuts::rNumericArgs(8); - liIon_surfaceArea_ = DataIPShortCuts::lNumericFieldBlanks(9) ? 0.5 : DataIPShortCuts::rNumericArgs(9); - liIon_Cp_ = DataIPShortCuts::lNumericFieldBlanks(10) ? 1500.0 : DataIPShortCuts::rNumericArgs(10); - liIon_heatTransferCoef_ = DataIPShortCuts::lNumericFieldBlanks(11) ? 7.5 : DataIPShortCuts::rNumericArgs(11); - liIon_Vfull_ = DataIPShortCuts::lNumericFieldBlanks(12) ? 4.2 : DataIPShortCuts::rNumericArgs(12); - liIon_Vexp_ = DataIPShortCuts::lNumericFieldBlanks(13) ? 3.53 : DataIPShortCuts::rNumericArgs(13); - liIon_Vnom_ = DataIPShortCuts::lNumericFieldBlanks(14) ? 3.342 : DataIPShortCuts::rNumericArgs(14); - liIon_Vnom_default_ = DataIPShortCuts::lNumericFieldBlanks(15) ? 3.342 : DataIPShortCuts::rNumericArgs(15); - liIon_Qfull_ = DataIPShortCuts::lNumericFieldBlanks(16) ? 1.0 : DataIPShortCuts::rNumericArgs(16); - liIon_Qexp_ = DataIPShortCuts::lNumericFieldBlanks(17) ? 0.1925 : DataIPShortCuts::rNumericArgs(17); - liIon_Qnom_ = DataIPShortCuts::lNumericFieldBlanks(18) ? 0.0231 : DataIPShortCuts::rNumericArgs(18); - liIon_C_rate_ = DataIPShortCuts::lNumericFieldBlanks(19) ? 1.0 : DataIPShortCuts::rNumericArgs(19); - internalR_ = DataIPShortCuts::lNumericFieldBlanks(20) ? 0.09 : DataIPShortCuts::rNumericArgs(20); + startingSOC_ = DataIPShortCuts::lNumericFieldBlanks(4) ? 0.5 : DataIPShortCuts::rNumericArgs(4); + liIon_dcToDcChargingEff_ = DataIPShortCuts::lNumericFieldBlanks(5) ? 0.95 : DataIPShortCuts::rNumericArgs(5); + liIon_mass_ = DataIPShortCuts::lNumericFieldBlanks(6) ? 95.1255 : DataIPShortCuts::rNumericArgs(6); + liIon_surfaceArea_ = DataIPShortCuts::lNumericFieldBlanks(7) ? 0.5 : DataIPShortCuts::rNumericArgs(7); + liIon_Cp_ = DataIPShortCuts::lNumericFieldBlanks(8) ? 1500.0 : DataIPShortCuts::rNumericArgs(8); + liIon_heatTransferCoef_ = DataIPShortCuts::lNumericFieldBlanks(9) ? 7.5 : DataIPShortCuts::rNumericArgs(9); + liIon_Vfull_ = DataIPShortCuts::lNumericFieldBlanks(10) ? 4.2 : DataIPShortCuts::rNumericArgs(10); + liIon_Vexp_ = DataIPShortCuts::lNumericFieldBlanks(11) ? 3.53 : DataIPShortCuts::rNumericArgs(11); + liIon_Vnom_ = DataIPShortCuts::lNumericFieldBlanks(12) ? 3.342 : DataIPShortCuts::rNumericArgs(12); + liIon_Vnom_default_ = DataIPShortCuts::lNumericFieldBlanks(13) ? 3.342 : DataIPShortCuts::rNumericArgs(13); + liIon_Qfull_ = DataIPShortCuts::lNumericFieldBlanks(14) ? 1.0 : DataIPShortCuts::rNumericArgs(14); + liIon_Qexp_ = DataIPShortCuts::lNumericFieldBlanks(15) ? 0.1925 : DataIPShortCuts::rNumericArgs(15); + liIon_Qnom_ = DataIPShortCuts::lNumericFieldBlanks(16) ? 0.0231 : DataIPShortCuts::rNumericArgs(16); + liIon_C_rate_ = DataIPShortCuts::lNumericFieldBlanks(17) ? 1.0 : DataIPShortCuts::rNumericArgs(17); + internalR_ = DataIPShortCuts::lNumericFieldBlanks(18) ? 0.09 : DataIPShortCuts::rNumericArgs(18); maxAhCapacity_ = liIon_Qfull_ * seriesNum_ * parallelNum_; @@ -3202,8 +3179,8 @@ ElectricStorage::ElectricStorage( // main constructor new capacity_lithium_ion_t( maxAhCapacity_, // Capacity of the whole battery startingSOC_, - maxSOC_, - minSOC_, + 0.0, // Reset later + 1.0, // Reset later DataHVACGlobals::TimeStepSys ), new voltage_dynamic_t( @@ -3368,12 +3345,12 @@ void ElectricStorage::reinitAtBeginEnvironment() if (storageModelMode_ == StorageModelType::kiBaMBattery) { Real64 initialCharge = maxAhCapacity_ * startingSOC_; - lastTwoTimeStepAvailable_ = initialCharge * maxSOC_; - lastTwoTimeStepBound_ = initialCharge * (1.0 - maxSOC_); - lastTimeStepAvailable_ = initialCharge * maxSOC_; - lastTimeStepBound_ = initialCharge * (1.0 - maxSOC_); - thisTimeStepAvailable_ = initialCharge * maxSOC_; - thisTimeStepBound_ = initialCharge * (1.0 - maxSOC_); + lastTwoTimeStepAvailable_ = initialCharge * availableFrac_; + lastTwoTimeStepBound_ = initialCharge * (1.0 - availableFrac_); + lastTimeStepAvailable_ = initialCharge * availableFrac_; + lastTimeStepBound_ = initialCharge * (1.0 - availableFrac_); + thisTimeStepAvailable_ = initialCharge * availableFrac_; + thisTimeStepBound_ = initialCharge * (1.0 - availableFrac_); if (lifeCalculation_ == BatteyDegredationModelType::lifeCalculationYes) { count0_ = 1; // Index 0 is for initial SOC, so new input starts from index 1. b10_[0] = startingSOC_; // the initial fractional SOC is stored as the reference @@ -3408,12 +3385,12 @@ void ElectricStorage::reinitAtEndWarmup() thisTimeStepStateOfCharge_ = startingEnergyStored_; if (storageModelMode_ == StorageModelType::kiBaMBattery) { Real64 initialCharge = maxAhCapacity_ * startingSOC_; - lastTwoTimeStepAvailable_ = initialCharge * maxSOC_; - lastTwoTimeStepBound_ = initialCharge * (1.0 - maxSOC_); - lastTimeStepAvailable_ = initialCharge * maxSOC_; - lastTimeStepBound_ = initialCharge * (1.0 - maxSOC_); - thisTimeStepAvailable_ = initialCharge * maxSOC_; - thisTimeStepBound_ = initialCharge * (1.0 - maxSOC_); + lastTwoTimeStepAvailable_ = initialCharge * availableFrac_; + lastTwoTimeStepBound_ = initialCharge * (1.0 - availableFrac_); + lastTimeStepAvailable_ = initialCharge * availableFrac_; + lastTimeStepBound_ = initialCharge * (1.0 - availableFrac_); + thisTimeStepAvailable_ = initialCharge * availableFrac_; + thisTimeStepBound_ = initialCharge * (1.0 - availableFrac_); if (lifeCalculation_ == BatteyDegredationModelType::lifeCalculationYes) { count0_ = 1; // Index 0 is for initial SOC, so new input starts from index 1. b10_[0] = startingSOC_; // the initial fractional SOC is stored as the reference @@ -3638,7 +3615,7 @@ void ElectricStorage::simulateKineticBatteryModel(EnergyPlusData &state, E0c = chargedOCV_; E0d = dischargedOCV_; k = chargeConversionRate_; - c = maxSOC_; + c = availableFrac_; if (charging) { @@ -3853,6 +3830,9 @@ void ElectricStorage::simulateLiIonNmcBatteryModel(EnergyPlusData &state, } ssc_battery_->set_state(battState); + // Set the SOC limits + ssc_battery_->changeSOCLimits(controlSOCMinFracLimit * 100.0, controlSOCMaxFracLimit * 100.0); + // Set the current timestep length ssc_battery_->ChangeTimestep(DataHVACGlobals::TimeStepSys); @@ -3867,7 +3847,6 @@ void ElectricStorage::simulateLiIonNmcBatteryModel(EnergyPlusData &state, } power *= 0.001; // Convert to kW ssc_battery_->runPower(power); - // FIXME: Track down these controlSOCMax/MinFracLimit and figure out what to do with them. // FIXME: Check other class members that store simulation state that are retrieved from getters and set accordingly. // Store outputs diff --git a/src/EnergyPlus/ElectricPowerServiceManager.hh b/src/EnergyPlus/ElectricPowerServiceManager.hh index 0c6db0c7810..c0051cddb8d 100644 --- a/src/EnergyPlus/ElectricPowerServiceManager.hh +++ b/src/EnergyPlus/ElectricPowerServiceManager.hh @@ -368,8 +368,7 @@ private: // data int cycleBinNum_; // [ ] number of cycle bins Real64 startingSOC_; // [ ] initial fractional state of charge Real64 maxAhCapacity_; // [Ah]maximum capacity - Real64 maxSOC_; // [ ] maximum fraction of available charge capacity - Real64 minSOC_; // [ ] minimum fraction of available charge capacity + Real64 availableFrac_; // [ ] maximum fraction of available charge capacity Real64 chargeConversionRate_; // [1/h]change rate from bound charge energy to available charge Real64 chargedOCV_; // [V] fully charged open circuit voltage Real64 dischargedOCV_; // [V] fully discharged open circuit voltage From d34e19c848d8f05d4e5bdf3e72dd51bee38c9d9d Mon Sep 17 00:00:00 2001 From: Noel Merket Date: Fri, 5 Feb 2021 16:43:35 -0700 Subject: [PATCH 43/76] adding lifetime degradation switch --- src/EnergyPlus/ElectricPowerServiceManager.cc | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/EnergyPlus/ElectricPowerServiceManager.cc b/src/EnergyPlus/ElectricPowerServiceManager.cc index 4ae1d3af3f4..520405772b9 100644 --- a/src/EnergyPlus/ElectricPowerServiceManager.cc +++ b/src/EnergyPlus/ElectricPowerServiceManager.cc @@ -3170,8 +3170,23 @@ ElectricStorage::ElectricStorage( // main constructor maxAhCapacity_ = liIon_Qfull_ * seriesNum_ * parallelNum_; - // FIXME: Disable lifetime model when requested. + // Set the Lifetime model in SSC + // I'm using a raw pointer here because the the battery_t constructor expects it. + // The pointer is then passed into the battery_t where it is converted into a unique_ptr and persists along with that object. + // Therefore I am not deleting this pointer here because that will be handled by the battery_t class. + lifetime_t* battLifetime; + if (lifeCalculation_ == BatteyDegredationModelType::lifeCalculationYes) { + battLifetime = new lifetime_nmc_t(DataHVACGlobals::TimeStepSys); + } else { + // This sets a lifetime model where the capacity is always 100%. + std::vector tblVals{{20, 0, 100, 20, 5000, 100, 20, 10000, 100, 80, 0, 100, 80, 1000, 100, 80, 2000, 100}}; + util::matrix_t battLifetimeMatrix(6, 3, &tblVals); + battLifetime = new lifetime_calendar_cycle_t(battLifetimeMatrix, DataHVACGlobals::TimeStepSys); + } + std::vector batt_losses{0}; // using double because SSC expects a double + + // Create the SSC battery object ssc_battery_ = std::unique_ptr( new battery_t( DataHVACGlobals::TimeStepSys, @@ -3197,9 +3212,7 @@ ElectricStorage::ElectricStorage( // main constructor internalR_, DataHVACGlobals::TimeStepSys ), - new lifetime_nmc_t( - DataHVACGlobals::TimeStepSys - ), + battLifetime, new thermal_t( DataHVACGlobals::TimeStepSys, liIon_mass_, @@ -3847,7 +3860,6 @@ void ElectricStorage::simulateLiIonNmcBatteryModel(EnergyPlusData &state, } power *= 0.001; // Convert to kW ssc_battery_->runPower(power); - // FIXME: Check other class members that store simulation state that are retrieved from getters and set accordingly. // Store outputs const battery_state& battState2{ssc_battery_->get_state()}; @@ -3876,8 +3888,9 @@ void ElectricStorage::simulateLiIonNmcBatteryModel(EnergyPlusData &state, batteryVoltage_ = ssc_battery_->V(); batteryDamage_ = 1.0 - (ssc_battery_->charge_maximum_lifetime() / maxAhCapacity_); storedPower_ = powerCharge; - drawnPower_ = powerDischarge; storedEnergy_ = storedPower_ * DataHVACGlobals::TimeStepSys * DataGlobalConstants::SecInHour; + drawnPower_ = powerDischarge; + drawnEnergy_ = drawnPower_ * DataHVACGlobals::TimeStepSys * DataGlobalConstants::SecInHour; decrementedEnergyStored_ = - storedEnergy_; thermLossRate_ = battState2.thermal->heat_dissipated * 1000.0; // kW -> W thermLossEnergy_ = thermLossRate_ * DataHVACGlobals::TimeStepSys * DataGlobalConstants::SecInHour; From 8e4e905cc963973cb7f121a9e4911cd08d2d78d0 Mon Sep 17 00:00:00 2001 From: Noel Merket Date: Tue, 9 Feb 2021 11:17:30 -0700 Subject: [PATCH 44/76] halting progress and a new example file --- idd/Energy+.idd.in | 20 +- src/EnergyPlus/ElectricPowerServiceManager.cc | 44 +- src/EnergyPlus/ElectricPowerServiceManager.hh | 4 +- testfiles/CMakeLists.txt | 1 + testfiles/ShopWithPVandLiIonBattery.idf | 5299 +++++++++++++++++ 5 files changed, 5337 insertions(+), 31 deletions(-) create mode 100644 testfiles/ShopWithPVandLiIonBattery.idf diff --git a/idd/Energy+.idd.in b/idd/Energy+.idd.in index 7c106d52018..d5d1a26e9ea 100644 --- a/idd/Energy+.idd.in +++ b/idd/Energy+.idd.in @@ -88853,17 +88853,19 @@ ElectricLoadCenter:Storage:LiIonNMCBattery, \type real \minimum> 0 \units Ah - \default 1 - N15, \field Cell Capacity at End of Exponential Zone + \default 3.2 + \note move these 3 above Fully Charged Cell Voltage + N15, \field Cell Capacity at End of Exponential Zone as Fraction of Full Cell Capacity \type real - \minimum> 0 - \units Ah - \default 0.1925 - N16, \field Cell Capacity at End of Nominal Zone + \minimum> 0.0 + \maximum< 1.0 + \default 0.81925 + N16, \field Cell Capacity at End of Nominal Zone as Fraction of Full Cell Capacity \type real - \minimum> 0 - \units Ah - \default 0.0231 + \minimum> 0.0 + \maximum< 1.0 + \default 0.088231 + \note 8.8231% of Qfull N17, \field Rate at Which Voltage vs Capacity Curve Input \type real \minimum> 0 diff --git a/src/EnergyPlus/ElectricPowerServiceManager.cc b/src/EnergyPlus/ElectricPowerServiceManager.cc index 520405772b9..a13611c590f 100644 --- a/src/EnergyPlus/ElectricPowerServiceManager.cc +++ b/src/EnergyPlus/ElectricPowerServiceManager.cc @@ -2948,7 +2948,7 @@ ElectricStorage::ElectricStorage( // main constructor energeticEfficCharge_(0.0), energeticEfficDischarge_(0.0), maxPowerDraw_(0.0), maxPowerStore_(0.0), maxEnergyCapacity_(0.0), parallelNum_(0), seriesNum_(0), numBattery_(0), chargeCurveNum_(0), dischargeCurveNum_(0), cycleBinNum_(0), startingSOC_(0.0), maxAhCapacity_(0.0), availableFrac_(0.0), chargeConversionRate_(0.0), chargedOCV_(0.0), dischargedOCV_(0.0), internalR_(0.0), maxDischargeI_(0.0), cutoffV_(0.0), - maxChargeRate_(0.0), lifeCalculation_(BatteyDegredationModelType::degredationNotSet), lifeCurveNum_(0), thisTimeStepStateOfCharge_(0.0), + maxChargeRate_(0.0), lifeCalculation_(BatteryDegradationModelType::degredationNotSet), lifeCurveNum_(0), thisTimeStepStateOfCharge_(0.0), lastTimeStepStateOfCharge_(0.0), pelNeedFromStorage_(0.0), pelFromStorage_(0.0), pelIntoStorage_(0.0), qdotConvZone_(0.0), qdotRadZone_(0.0), timeElapsed_(0.0), thisTimeStepAvailable_(0.0), thisTimeStepBound_(0.0), lastTimeStepAvailable_(0.0), lastTimeStepBound_(0.0), lastTwoTimeStepAvailable_(0.0), lastTwoTimeStepBound_(0.0), count0_(0), electEnergyinStorage_(0.0), thermLossRate_(0.0), thermLossEnergy_(0.0), @@ -3084,17 +3084,17 @@ ElectricStorage::ElectricStorage( // main constructor } if (UtilityRoutines::SameString(DataIPShortCuts::cAlphaArgs(6), "Yes")) { - lifeCalculation_ = BatteyDegredationModelType::lifeCalculationYes; + lifeCalculation_ = BatteryDegradationModelType::lifeCalculationYes; } else if (UtilityRoutines::SameString(DataIPShortCuts::cAlphaArgs(6), "No")) { - lifeCalculation_ = BatteyDegredationModelType::lifeCalculationNo; + lifeCalculation_ = BatteryDegradationModelType::lifeCalculationNo; } else { ShowWarningError(state, routineName + DataIPShortCuts::cCurrentModuleObject + "=\"" + DataIPShortCuts::cAlphaArgs(1) + "\", invalid entry."); ShowContinueError(state, "Invalid " + DataIPShortCuts::cAlphaFieldNames(6) + " = " + DataIPShortCuts::cAlphaArgs(6)); ShowContinueError(state, "Yes or No should be selected. Default value No is used to continue simulation"); - lifeCalculation_ = BatteyDegredationModelType::lifeCalculationNo; + lifeCalculation_ = BatteryDegradationModelType::lifeCalculationNo; } - if (lifeCalculation_ == BatteyDegredationModelType::lifeCalculationYes) { + if (lifeCalculation_ == BatteryDegradationModelType::lifeCalculationYes) { lifeCurveNum_ = CurveManager::GetCurveIndex(state, DataIPShortCuts::cAlphaArgs(7)); // Battery life calculation if (lifeCurveNum_ == 0 && !DataIPShortCuts::lAlphaFieldBlanks(7)) { ShowSevereError(state, routineName + DataIPShortCuts::cCurrentModuleObject + "=\"" + DataIPShortCuts::cAlphaArgs(1) + @@ -3146,9 +3146,9 @@ ElectricStorage::ElectricStorage( // main constructor } case StorageModelType::liIonNmcBattery: { if (UtilityRoutines::SameString(DataIPShortCuts::cAlphaArgs(4), "KandlerSmith") or DataIPShortCuts::lAlphaFieldBlanks(4)) { - lifeCalculation_ = BatteyDegredationModelType::lifeCalculationYes; + lifeCalculation_ = BatteryDegradationModelType::lifeCalculationYes; } else { - lifeCalculation_ = BatteyDegredationModelType::lifeCalculationNo; + lifeCalculation_ = BatteryDegradationModelType::lifeCalculationNo; } seriesNum_ = DataIPShortCuts::lNumericFieldBlanks(2) ? 3 : static_cast(DataIPShortCuts::rNumericArgs(2)); parallelNum_ = DataIPShortCuts::lNumericFieldBlanks(3) ? 1 : static_cast(DataIPShortCuts::rNumericArgs(3)); @@ -3161,10 +3161,13 @@ ElectricStorage::ElectricStorage( // main constructor liIon_Vfull_ = DataIPShortCuts::lNumericFieldBlanks(10) ? 4.2 : DataIPShortCuts::rNumericArgs(10); liIon_Vexp_ = DataIPShortCuts::lNumericFieldBlanks(11) ? 3.53 : DataIPShortCuts::rNumericArgs(11); liIon_Vnom_ = DataIPShortCuts::lNumericFieldBlanks(12) ? 3.342 : DataIPShortCuts::rNumericArgs(12); + // FIXME: Validate Vnom < Vexp + // see lib_battery_voltage.cpp line 268 liIon_Vnom_default_ = DataIPShortCuts::lNumericFieldBlanks(13) ? 3.342 : DataIPShortCuts::rNumericArgs(13); - liIon_Qfull_ = DataIPShortCuts::lNumericFieldBlanks(14) ? 1.0 : DataIPShortCuts::rNumericArgs(14); - liIon_Qexp_ = DataIPShortCuts::lNumericFieldBlanks(15) ? 0.1925 : DataIPShortCuts::rNumericArgs(15); - liIon_Qnom_ = DataIPShortCuts::lNumericFieldBlanks(16) ? 0.0231 : DataIPShortCuts::rNumericArgs(16); + liIon_Qfull_ = DataIPShortCuts::lNumericFieldBlanks(14) ? 3.2 : DataIPShortCuts::rNumericArgs(14); + liIon_Qexp_ = DataIPShortCuts::lNumericFieldBlanks(15) ? 0.81925 * liIon_Qfull_ : DataIPShortCuts::rNumericArgs(15) * liIon_Qfull_; + liIon_Qnom_ = DataIPShortCuts::lNumericFieldBlanks(16) ? 0.088231 * liIon_Qfull_ : DataIPShortCuts::rNumericArgs(16) * liIon_Qfull_; + // FIXME: Validate Qexp and Qnom are less than Qfull, and Qnom > Qexp? liIon_C_rate_ = DataIPShortCuts::lNumericFieldBlanks(17) ? 1.0 : DataIPShortCuts::rNumericArgs(17); internalR_ = DataIPShortCuts::lNumericFieldBlanks(18) ? 0.09 : DataIPShortCuts::rNumericArgs(18); @@ -3175,7 +3178,7 @@ ElectricStorage::ElectricStorage( // main constructor // The pointer is then passed into the battery_t where it is converted into a unique_ptr and persists along with that object. // Therefore I am not deleting this pointer here because that will be handled by the battery_t class. lifetime_t* battLifetime; - if (lifeCalculation_ == BatteyDegredationModelType::lifeCalculationYes) { + if (lifeCalculation_ == BatteryDegradationModelType::lifeCalculationYes) { battLifetime = new lifetime_nmc_t(DataHVACGlobals::TimeStepSys); } else { // This sets a lifetime model where the capacity is always 100%. @@ -3225,8 +3228,9 @@ ElectricStorage::ElectricStorage( // main constructor new losses_t(batt_losses) ) ); - *ssc_lastBatteryState_ = ssc_battery_->get_state(); - *ssc_initBatteryState_ = ssc_battery_->get_state(); + ssc_lastBatteryState_ = std::unique_ptr(new battery_state(ssc_battery_->get_state())); + ssc_initBatteryState_ = std::unique_ptr(new battery_state(ssc_battery_->get_state())); + break; } case StorageModelType::storageTypeNotSet: { @@ -3248,7 +3252,7 @@ ElectricStorage::ElectricStorage( // main constructor SetupOutputVariable(state, "Electric Storage Total Current", OutputProcessor::Unit::A, batteryCurrent_, "System", "Average", name_); SetupOutputVariable(state, "Electric Storage Total Voltage", OutputProcessor::Unit::V, batteryVoltage_, "System", "Average", name_); - if (lifeCalculation_ == BatteyDegredationModelType::lifeCalculationYes) { + if (lifeCalculation_ == BatteryDegradationModelType::lifeCalculationYes) { SetupOutputVariable(state, "Electric Storage Degradation Fraction", OutputProcessor::Unit::None, batteryDamage_, "System", "Average", name_); } } @@ -3364,7 +3368,7 @@ void ElectricStorage::reinitAtBeginEnvironment() lastTimeStepBound_ = initialCharge * (1.0 - availableFrac_); thisTimeStepAvailable_ = initialCharge * availableFrac_; thisTimeStepBound_ = initialCharge * (1.0 - availableFrac_); - if (lifeCalculation_ == BatteyDegredationModelType::lifeCalculationYes) { + if (lifeCalculation_ == BatteryDegradationModelType::lifeCalculationYes) { count0_ = 1; // Index 0 is for initial SOC, so new input starts from index 1. b10_[0] = startingSOC_; // the initial fractional SOC is stored as the reference x0_[0] = 0.0; @@ -3404,7 +3408,7 @@ void ElectricStorage::reinitAtEndWarmup() lastTimeStepBound_ = initialCharge * (1.0 - availableFrac_); thisTimeStepAvailable_ = initialCharge * availableFrac_; thisTimeStepBound_ = initialCharge * (1.0 - availableFrac_); - if (lifeCalculation_ == BatteyDegredationModelType::lifeCalculationYes) { + if (lifeCalculation_ == BatteryDegradationModelType::lifeCalculationYes) { count0_ = 1; // Index 0 is for initial SOC, so new input starts from index 1. b10_[0] = startingSOC_; // the initial fractional SOC is stored as the reference x0_[0] = 0.0; @@ -3434,7 +3438,7 @@ void ElectricStorage::timeCheckAndUpdate(EnergyPlusData &state) Real64 timeElapsedLoc = state.dataGlobal->HourOfDay + state.dataGlobal->TimeStep * state.dataGlobal->TimeStepZone + DataHVACGlobals::SysTimeElapsed; if (timeElapsed_ != timeElapsedLoc) { // time changed, update last with "current" result from previous time - if (storageModelMode_ == StorageModelType::kiBaMBattery && lifeCalculation_ == BatteyDegredationModelType::lifeCalculationYes) { + if (storageModelMode_ == StorageModelType::kiBaMBattery && lifeCalculation_ == BatteryDegradationModelType::lifeCalculationYes) { // At this point, the current values, last time step values and last two time step values have not been updated, hence: // "ThisTimeStep*" actually points to the previous one time step // "LastTimeStep*" actually points to the previous two time steps @@ -3830,6 +3834,9 @@ void ElectricStorage::simulateLiIonNmcBatteryModel(EnergyPlusData &state, Real64 const controlSOCMaxFracLimit, Real64 const controlSOCMinFracLimit) { + + // FIXME: Do availability schedule check. + // Copy the battery state from the end of last timestep battery_state battState = *ssc_lastBatteryState_; @@ -3900,9 +3907,6 @@ void ElectricStorage::simulateLiIonNmcBatteryModel(EnergyPlusData &state, qdotConvZone_ = (1.0 - zoneRadFract_) * thermLossRate_; qdotRadZone_ = (zoneRadFract_) * thermLossRate_; } - - - } Real64 ElectricStorage::drawnPower() const diff --git a/src/EnergyPlus/ElectricPowerServiceManager.hh b/src/EnergyPlus/ElectricPowerServiceManager.hh index c0051cddb8d..cbd17d3af7a 100644 --- a/src/EnergyPlus/ElectricPowerServiceManager.hh +++ b/src/EnergyPlus/ElectricPowerServiceManager.hh @@ -333,7 +333,7 @@ private: // data liIonNmcBattery, }; - enum class BatteyDegredationModelType : int + enum class BatteryDegradationModelType : int { degredationNotSet = 0, lifeCalculationYes, @@ -376,7 +376,7 @@ private: // data Real64 maxDischargeI_; // [A] maximum discharging current Real64 cutoffV_; // [V] cut-off voltage Real64 maxChargeRate_; // [1/h] charge rate limit - BatteyDegredationModelType lifeCalculation_; // [ ] battery life calculation: Yes or No + BatteryDegradationModelType lifeCalculation_; // [ ] battery life calculation: Yes or No int lifeCurveNum_; // [ ] battery life curve name index number Real64 liIon_dcToDcChargingEff_; // [ ] DC to DC Charging Efficiency (Li-ion NMC model) Real64 liIon_mass_; // [kg] mass of battery (Li-ion NMC model) diff --git a/testfiles/CMakeLists.txt b/testfiles/CMakeLists.txt index 077c9056a78..5061397f02c 100644 --- a/testfiles/CMakeLists.txt +++ b/testfiles/CMakeLists.txt @@ -498,6 +498,7 @@ ADD_SIMULATION_TEST(IDF_FILE ReportHeatEmission_RefFSRestaurant.idf EPW_FILE USA ADD_SIMULATION_TEST(IDF_FILE RetailPackagedTESCoil.idf EPW_FILE USA_IL_Chicago-OHare.Intl.AP.725300_TMY3.epw) ADD_SIMULATION_TEST(IDF_FILE RoomAirflowNetwork.idf EPW_FILE USA_IL_Chicago-OHare.Intl.AP.725300_TMY3.epw) ADD_SIMULATION_TEST(IDF_FILE SeriesActiveBranch.idf EPW_FILE USA_IL_Chicago-OHare.Intl.AP.725300_TMY3.epw) +ADD_SIMULATION_TEST(IDF_FILE ShopWithPVandLiIonBattery.idf EPW_FILE USA_OK_Oklahoma.City-Will.Rogers.World.AP.723530_TMY3.epw) ADD_SIMULATION_TEST(IDF_FILE ShopWithPVandBattery.idf EPW_FILE USA_OK_Oklahoma.City-Will.Rogers.World.AP.723530_TMY3.epw) ADD_SIMULATION_TEST(IDF_FILE ShopWithPVandStorage.idf EPW_FILE USA_OK_Oklahoma.City-Will.Rogers.World.AP.723530_TMY3.epw) ADD_SIMULATION_TEST(IDF_FILE ShopWithSimplePVT.idf EPW_FILE USA_OK_Oklahoma.City-Will.Rogers.World.AP.723530_TMY3.epw) diff --git a/testfiles/ShopWithPVandLiIonBattery.idf b/testfiles/ShopWithPVandLiIonBattery.idf new file mode 100644 index 00000000000..401a5d13211 --- /dev/null +++ b/testfiles/ShopWithPVandLiIonBattery.idf @@ -0,0 +1,5299 @@ +!ShopWithPVandBattery.idf +! Basic file description: 1 story building divided into 4 exterior and one interior conditioned zones and return plenum. +! +! Highlights: low energy building with photovoltaic roof and electrical storage +! Demonstrate the used of battery model for electrical storage +! Demonstrates different inverters on different arrays. +! Fairly comprehensive model with full HVAC, service water heating, etc. +! +! Simulation Location/Run: OKLAHOMA_CITY_OK_USA TMY2-13967, 2 design days, 1 run period +! +! Location: Oklahoma City, OK +! +! Design Days: OKLAHOMA_CITY_OK_USA Heating 99.6% Conditions +! OKLAHOMA_CITY_OK_USA Cooling .4% Conditions WB=>MDB +! +! Run Period (Weather File): +! +! Run Control: Zone and System sizing with weather file run control (no design days run) +! +! Building: small service repair shop. open Mon-Fri, 45 hours a week, +! model developed from 2003CBECS PUBID8=2994 +! Envelope and equipment set to nominally meet ASHRAE Standard 90.1-2004 +! +! +! Floor Area: 390.19 m2 (4200 ft2) +! Number of Stories: 1 +! +! Zone Description Details: +! +! Internal gains description: lighting is 15 watts/m2, service equip is 8.3 watts/m2. There are 3 occupants. +! The infiltration is about 0.5 air changes per hour. +! +! +! Detached Shading: None +! Daylight: None +! Natural Ventilation: None +! Compact Schedules: Yes +! +! HVAC: Single zone, constant volume air systems. +! 5 seperate "packages" +! outside air system includes ideal PVT air preconditioners +! +! Zonal Equipment: Direct Air/Single Duct Uncontrolled. +! Central Air Handling Equipment: no ( but uses central-air-style air handlers for PSZ) +! System Equipment Autosize: Yes +! Coils: DX +! Pumps: Pump:VariableSpeed +! +! Results: +! Standard Reports: All Summary +! Timestep or Hourly Variables: Timestep +! Time bins Report: None +! HTML Report: Yes +! Environmental Emissions: Yes +! Utility Tariffs: Yes, circa 2004, Reliant , TX + + Version,9.4; + + Timestep,6; + + SimulationControl, + Yes, !- Do Zone Sizing Calculation + Yes, !- Do System Sizing Calculation + No, !- Do Plant Sizing Calculation + No, !- Run Simulation for Sizing Periods + Yes, !- Run Simulation for Weather File Run Periods + No, !- Do HVAC Sizing Simulation for Sizing Periods + 1; !- Maximum Number of HVAC Sizing Simulation Passes + + RunPeriod, + Run Period 1, !- Name + 7, !- Begin Month + 1, !- Begin Day of Month + , !- Begin Year + 7, !- End Month + 2, !- End Day of Month + , !- End Year + Sunday, !- Day of Week for Start Day + No, !- Use Weather File Holidays and Special Days + No, !- Use Weather File Daylight Saving Period + No, !- Apply Weekend Holiday Rule + Yes, !- Use Weather File Rain Indicators + Yes; !- Use Weather File Snow Indicators + + SurfaceConvectionAlgorithm:Inside,TARP; + + SurfaceConvectionAlgorithm:Outside,DOE-2; + + HeatBalanceAlgorithm,ConductionTransferFunction; + + Sizing:Parameters, + 1.2000, !- Heating Sizing Factor + 1.2000, !- Cooling Sizing Factor + ; !- Timesteps in Averaging Window + + ConvergenceLimits, + 5, !- Minimum System Timestep {minutes} + 10; !- Maximum HVAC Iterations + + ShadowCalculation, + PolygonClipping, !- Shading Calculation Method + Periodic, !- Shading Calculation Update Frequency Method + 30; !- Shading Calculation Update Frequency + + GlobalGeometryRules, + UpperLeftCorner, !- Starting Vertex Position + CounterClockWise, !- Vertex Entry Direction + Relative; !- Coordinate System + + Building, + AutoBuilt Model: All, !- Name + 203.0140, !- North Axis {deg} + City, !- Terrain + 0.0400, !- Loads Convergence Tolerance Value {W} + 0.2000, !- Temperature Convergence Tolerance Value {deltaC} + FullInteriorAndExterior, !- Solar Distribution + 25, !- Maximum Number of Warmup Days + 6; !- Minimum Number of Warmup Days + +! US National Holidays + + RunPeriodControl:SpecialDays, + New Years Day, !- Name + January 1, !- Start Date + 1, !- Duration {days} + Holiday; !- Special Day Type + + RunPeriodControl:SpecialDays, + Veterans Day, !- Name + November 11, !- Start Date + 1, !- Duration {days} + Holiday; !- Special Day Type + + RunPeriodControl:SpecialDays, + Christmas, !- Name + December 25, !- Start Date + 1, !- Duration {days} + Holiday; !- Special Day Type + + RunPeriodControl:SpecialDays, + Independence Day, !- Name + July 4, !- Start Date + 1, !- Duration {days} + Holiday; !- Special Day Type + + RunPeriodControl:SpecialDays, + MLK Day, !- Name + 3rd Monday in January, !- Start Date + 1, !- Duration {days} + Holiday; !- Special Day Type + + RunPeriodControl:SpecialDays, + Presidents Day, !- Name + 3rd Monday in February, !- Start Date + 1, !- Duration {days} + Holiday; !- Special Day Type + + RunPeriodControl:SpecialDays, + Memorial Day, !- Name + Last Monday in May, !- Start Date + 1, !- Duration {days} + Holiday; !- Special Day Type + + RunPeriodControl:SpecialDays, + Labor Day, !- Name + 1st Monday in September, !- Start Date + 1, !- Duration {days} + Holiday; !- Special Day Type + + RunPeriodControl:SpecialDays, + Columbus Day, !- Name + 2nd Monday in October, !- Start Date + 1, !- Duration {days} + Holiday; !- Special Day Type + + RunPeriodControl:SpecialDays, + Thanksgiving, !- Name + 4th Thursday in November,!- Start Date + 1, !- Duration {days} + Holiday; !- Special Day Type + +! Daylight Saving Period in US + + RunPeriodControl:DaylightSavingTime, + 1st Sunday in April, !- Start Date + Last Sunday in October; !- End Date + + Site:Location, + OKLAHOMA_CITY_OK_USA TMY2-13967, !- Name + 35.40000, !- Latitude {deg} + -97.60000, !- Longitude {deg} + -6.000000, !- Time Zone {hr} + 397.0000; !- Elevation {m} + +! OKLAHOMA_CITY_OK_USA Heating 99.6%, MaxDB= -12.60 Wind Speed= 6.90 Wind Dir= 360.00 + + SizingPeriod:DesignDay, + OKLAHOMA_CITY_OK_USA Heating 99.6% Conditions, !- Name + 1, !- Month + 21, !- Day of Month + WinterDesignDay, !- Day Type + -12.60000, !- Maximum Dry-Bulb Temperature {C} + 0.0000000E+00, !- Daily Dry-Bulb Temperature Range {deltaC} + , !- Dry-Bulb Temperature Range Modifier Type + , !- Dry-Bulb Temperature Range Modifier Day Schedule Name + Wetbulb, !- Humidity Condition Type + -12.60000, !- Wetbulb or DewPoint at Maximum Dry-Bulb {C} + , !- Humidity Condition Day Schedule Name + , !- Humidity Ratio at Maximum Dry-Bulb {kgWater/kgDryAir} + , !- Enthalpy at Maximum Dry-Bulb {J/kg} + , !- Daily Wet-Bulb Temperature Range {deltaC} + 96645.77, !- Barometric Pressure {Pa} + 6.900000, !- Wind Speed {m/s} + 360.0000, !- Wind Direction {deg} + No, !- Rain Indicator + No, !- Snow Indicator + No, !- Daylight Saving Time Indicator + ASHRAEClearSky, !- Solar Model Indicator + , !- Beam Solar Day Schedule Name + , !- Diffuse Solar Day Schedule Name + , !- ASHRAE Clear Sky Optical Depth for Beam Irradiance (taub) {dimensionless} + , !- ASHRAE Clear Sky Optical Depth for Diffuse Irradiance (taud) {dimensionless} + 0.0000000E+00; !- Sky Clearness + +! OKLAHOMA_CITY_OK_USA Cooling (WB=>MDB) .4%, MDB= 32.80 WB= 24.90 + + SizingPeriod:DesignDay, + OKLAHOMA_CITY_OK_USA Cooling .4% Conditions WB=>MDB, !- Name + 7, !- Month + 21, !- Day of Month + SummerDesignDay, !- Day Type + 32.80000, !- Maximum Dry-Bulb Temperature {C} + 11.70000, !- Daily Dry-Bulb Temperature Range {deltaC} + , !- Dry-Bulb Temperature Range Modifier Type + , !- Dry-Bulb Temperature Range Modifier Day Schedule Name + Wetbulb, !- Humidity Condition Type + 24.90000, !- Wetbulb or DewPoint at Maximum Dry-Bulb {C} + , !- Humidity Condition Day Schedule Name + , !- Humidity Ratio at Maximum Dry-Bulb {kgWater/kgDryAir} + , !- Enthalpy at Maximum Dry-Bulb {J/kg} + , !- Daily Wet-Bulb Temperature Range {deltaC} + 96645.77, !- Barometric Pressure {Pa} + 0.0000000E+00, !- Wind Speed {m/s} + 0.0000000E+00, !- Wind Direction {deg} + No, !- Rain Indicator + No, !- Snow Indicator + No, !- Daylight Saving Time Indicator + ASHRAEClearSky, !- Solar Model Indicator + , !- Beam Solar Day Schedule Name + , !- Diffuse Solar Day Schedule Name + , !- ASHRAE Clear Sky Optical Depth for Beam Irradiance (taub) {dimensionless} + , !- ASHRAE Clear Sky Optical Depth for Diffuse Irradiance (taud) {dimensionless} + 1.000000; !- Sky Clearness + + Site:GroundTemperature:BuildingSurface,20.03,20.05,20.08,20.10,20.18,20.23,20.22,20.19,20.26,20.25,20.23,20.20; + +! Daily Avg, -0.3, 3.3, 10.4, 14.8, 20.6, 23.7, 26.3, 27.9, 22.0, 16.9, 9.7, 5.1 + + Site:WaterMainsTemperature, + CORRELATION, !- Calculation Method + , !- Temperature Schedule Name + 15.03, !- Annual Average Outdoor Air Temperature {C} + 28.20; !- Maximum Difference In Monthly Average Outdoor Air Temperatures {deltaC} + + ScheduleTypeLimits, + Any Number; !- Name + + ScheduleTypeLimits, + Fraction, !- Name + 0.0, !- Lower Limit Value + 1.0, !- Upper Limit Value + CONTINUOUS; !- Numeric Type + + ScheduleTypeLimits, + Temperature, !- Name + -60, !- Lower Limit Value + 200, !- Upper Limit Value + CONTINUOUS, !- Numeric Type + Temperature; !- Unit Type + + ScheduleTypeLimits, + On/Off, !- Name + 0, !- Lower Limit Value + 1, !- Upper Limit Value + DISCRETE; !- Numeric Type + + ScheduleTypeLimits, + Control Type, !- Name + 0, !- Lower Limit Value + 4, !- Upper Limit Value + DISCRETE; !- Numeric Type + + ScheduleTypeLimits, + Humidity, !- Name + 10, !- Lower Limit Value + 90, !- Upper Limit Value + CONTINUOUS; !- Numeric Type + + ScheduleTypeLimits, + Number; !- Name + +! PBA: 26: Service +! PBA+: 45: Repair shop +! Weekly Hours: 45 +! Open 24 Hours: False +! Open Weekends: False +! Days Open: Open Mon-Fri +! Months Not Open: 0 +! Month Occupied (not always used): 0 +! Schedule valid for the following building IDs +! ID_2994 +!------------ ALWAYS_ON --------- + + Schedule:Compact, + ALWAYS_ON, !- Name + On/Off, !- Schedule Type Limits Name + Through: 12/31, !- Field 1 + For: AllDays, !- Field 2 + Until: 24:00,1; !- Field 3 + +!------------ WORK_EFF_SCH --------- + + Schedule:Compact, + WORK_EFF_SCH, !- Name + Fraction, !- Schedule Type Limits Name + Through: 12/31, !- Field 1 + For: AllDays, !- Field 2 + Until: 24:00,0; !- Field 3 + +!------------ AIR_VELO_SCH --------- + + Schedule:Compact, + AIR_VELO_SCH, !- Name + Any Number, !- Schedule Type Limits Name + Through: 12/31, !- Field 1 + For: AllDays, !- Field 2 + Until: 24:00,0.2; !- Field 3 + +!------------ CLOTHING_SCH --------- + + Schedule:Compact, + CLOTHING_SCH, !- Name + Any Number, !- Schedule Type Limits Name + Through: 04/30, !- Field 1 + For: AllDays, !- Field 2 + Until: 24:00,1.1, !- Field 3 + Through: 09/30, !- Field 5 + For: AllDays, !- Field 6 + Until: 24:00,0.6, !- Field 7 + Through: 12/31, !- Field 9 + For: AllDays, !- Field 10 + Until: 24:00,1.1; !- Field 11 + +!------------ PlantOnSched --------- + + Schedule:Compact, + PlantOnSched, !- Name + Any Number, !- Schedule Type Limits Name + Through: 12/31, !- Field 1 + For: AllDays, !- Field 2 + Until: 24:00,1; !- Field 3 + +!------------ Dual Zone Control Type Sched --------- + + Schedule:Compact, + Dual Zone Control Type Sched, !- Name + Control Type, !- Schedule Type Limits Name + Through: 12/31, !- Field 1 + For: AllDays, !- Field 2 + Until: 24:00,4; !- Field 3 + +!------------ Hours_of_operation --------- +! Schedule for hours of operation +! Assigned 45 hours + + Schedule:Compact, + Hours_of_operation, !- Name + On/Off, !- Schedule Type Limits Name + Through: 12/31, !- Field 1 + For: Weekdays SummerDesignDay, !- Field 2 + Until: 10:00,0, !- Field 3 + Until: 19:00,1, !- Field 5 + Until: 24:00,0, !- Field 7 + For: WeekEnds WinterDesignDay Holidays AllOtherDays, !- Field 9 + Until: 24:00,0; !- Field 10 + +!------------ HVACOperationSchd --------- +! Schedule for HVAC operation + + Schedule:Compact, + HVACOperationSchd, !- Name + On/Off, !- Schedule Type Limits Name + Through: 12/31, !- Field 1 + For: Weekdays SummerDesignDay, !- Field 2 + Until: 10:00,0, !- Field 3 + Until: 19:00,1, !- Field 5 + Until: 24:00,0, !- Field 7 + For: WeekEnds WinterDesignDay Holidays AllOtherDays, !- Field 9 + Until: 24:00,0; !- Field 10 + +!------------ HTGSETP_SCH --------- +! Heating Setpoint + + Schedule:Compact, + HTGSETP_SCH, !- Name + Temperature, !- Schedule Type Limits Name + Through: 12/31, !- Field 1 + For: SummerDesignDay, !- Field 2 + Until: 24:00,13, !- Field 3 + For: WinterDesignDay, !- Field 5 + Until: 24:00,21, !- Field 6 + For: Weekdays, !- Field 8 + Until: 10:00,13, !- Field 9 + Until: 19:00,21, !- Field 11 + Until: 24:00,13, !- Field 13 + For: WeekEnds Holidays AllOtherDays, !- Field 15 + Until: 24:00,13; !- Field 16 + +!------------ CLGSETP_SCH --------- +! Cooling Setpoint + + Schedule:Compact, + CLGSETP_SCH, !- Name + Temperature, !- Schedule Type Limits Name + Through: 12/31, !- Field 1 + For: SummerDesignDay, !- Field 2 + Until: 24:00,24, !- Field 3 + For: WinterDesignDay, !- Field 5 + Until: 24:00,33, !- Field 6 + For: WeekEnds, !- Field 8 + Until: 24:00,33, !- Field 9 + For: Weekdays Holidays AllOtherDays, !- Field 11 + Until: 10:00,33, !- Field 12 + Until: 19:00,24, !- Field 14 + Until: 24:00,33; !- Field 16 + +!------------ MinOA_Sched --------- +! Minimum outside air schedule +! Gravity Damper + + Schedule:Compact, + MinOA_Sched, !- Name + On/Off, !- Schedule Type Limits Name + Through: 12/31, !- Field 1 + For: AllDays, !- Field 2 + Until: 24:00,1; !- Field 3 + +!------------ BLDG_LIGHT_SCH --------- +! Lighting schedule +! Lighting Reduced: True +! Percent Lit When Closed: 0 +! Percent Lit When Open: 100 + + Schedule:Compact, + BLDG_LIGHT_SCH, !- Name + Fraction, !- Schedule Type Limits Name + Through: 12/31, !- Field 1 + For: Weekdays SummerDesignDay, !- Field 2 + Until: 10:00,0, !- Field 3 + Until: 19:00,0.943, !- Field 5 + Until: 24:00,0, !- Field 7 + For: WeekEnds WinterDesignDay Holidays AllOtherDays, !- Field 9 + Until: 24:00,0; !- Field 10 + +!------------ BLDG_EQUIP_SCH --------- +! Equipment Schedule +! Minimum Equipment Percent: 10 +! Maximum Equipment Percent: 95 +! Equipment turned off during off hours: Always + + Schedule:Compact, + BLDG_EQUIP_SCH, !- Name + Fraction, !- Schedule Type Limits Name + Through: 12/31, !- Field 1 + For: Weekdays SummerDesignDay, !- Field 2 + Until: 10:00,0.1, !- Field 3 + Until: 19:00,0.95, !- Field 5 + Until: 24:00,0.1, !- Field 7 + For: WeekEnds WinterDesignDay Holidays AllOtherDays, !- Field 9 + Until: 24:00,0.1; !- Field 10 + +!------------ BLDG_OCC_SCH --------- +! Occupancy Schedule +! Minimum Occupancy Percent: 0 +! Maximum Occupancy Percent: 95 + + Schedule:Compact, + BLDG_OCC_SCH, !- Name + Fraction, !- Schedule Type Limits Name + Through: 12/31, !- Field 1 + For: Weekdays SummerDesignDay, !- Field 2 + Until: 10:00,0, !- Field 3 + Until: 12:00,0.95, !- Field 5 + Until: 13:00,0.5, !- Field 7 + Until: 19:00,0.95, !- Field 9 + Until: 24:00,0, !- Field 11 + For: WeekEnds WinterDesignDay Holidays AllOtherDays, !- Field 13 + Until: 24:00,0; !- Field 14 + +!------------ INFIL_SCH --------- +! Infiltration Schedule +! Infiltration Percent w/o HVAC: 100 +! Infiltration Percent w/HVAC: 100 + + Schedule:Compact, + INFIL_SCH, !- Name + Fraction, !- Schedule Type Limits Name + Through: 12/31, !- Field 1 + For: AllDays, !- Field 2 + Until: 24:00,1; !- Field 3 + +!------------ ACTIVITY_SCH --------- +! Activity Schedule + + Schedule:Compact, + ACTIVITY_SCH, !- Name + Any Number, !- Schedule Type Limits Name + Through: 12/31, !- Field 1 + For: AllDays, !- Field 2 + Until: 24:00,140; !- Field 3 + + WindowMaterial:Glazing, + Theoretical Glass [23], !- Name + SpectralAverage, !- Optical Data Type + , !- Window Glass Spectral Data Set Name + 0.0030, !- Thickness {m} + 0.5531, !- Solar Transmittance at Normal Incidence + 0.3969, !- Front Side Solar Reflectance at Normal Incidence + 0.3969, !- Back Side Solar Reflectance at Normal Incidence + 0.6041, !- Visible Transmittance at Normal Incidence + 0.3459, !- Front Side Visible Reflectance at Normal Incidence + 0.3459, !- Back Side Visible Reflectance at Normal Incidence + 0.0000, !- Infrared Transmittance at Normal Incidence + 0.8500, !- Front Side Infrared Hemispherical Emissivity + 0.8500, !- Back Side Infrared Hemispherical Emissivity + 2.3904; !- Conductivity {W/m-K} + + WindowMaterial:Gas, + AIR 6MM, !- Name + Air, !- Gas Type + 0.0063; !- Thickness {m} + + WindowMaterial:Glazing, + Theoretical Glass [24], !- Name + SpectralAverage, !- Optical Data Type + , !- Window Glass Spectral Data Set Name + 0.0030, !- Thickness {m} + 0.6483, !- Solar Transmittance at Normal Incidence + 0.3017, !- Front Side Solar Reflectance at Normal Incidence + 0.3017, !- Back Side Solar Reflectance at Normal Incidence + 0.7094, !- Visible Transmittance at Normal Incidence + 0.2406, !- Front Side Visible Reflectance at Normal Incidence + 0.2406, !- Back Side Visible Reflectance at Normal Incidence + 0.0000, !- Infrared Transmittance at Normal Incidence + 0.8500, !- Front Side Infrared Hemispherical Emissivity + 0.8500, !- Back Side Infrared Hemispherical Emissivity + 2.4179; !- Conductivity {W/m-K} + + WindowMaterial:Glazing, + Theoretical Glass [8], !- Name + SpectralAverage, !- Optical Data Type + , !- Window Glass Spectral Data Set Name + 0.0030, !- Thickness {m} + 0.3480, !- Solar Transmittance at Normal Incidence + 0.6020, !- Front Side Solar Reflectance at Normal Incidence + 0.6020, !- Back Side Solar Reflectance at Normal Incidence + 0.3763, !- Visible Transmittance at Normal Incidence + 0.5737, !- Front Side Visible Reflectance at Normal Incidence + 0.5737, !- Back Side Visible Reflectance at Normal Incidence + 0.0000, !- Infrared Transmittance at Normal Incidence + 0.9990, !- Front Side Infrared Hemispherical Emissivity + 0.9990, !- Back Side Infrared Hemispherical Emissivity + 2.2444; !- Conductivity {W/m-K} + + Material, + Roof Membrane, !- Name + VeryRough, !- Roughness + 0.0095, !- Thickness {m} + 0.1600, !- Conductivity {W/m-K} + 1121.2900, !- Density {kg/m3} + 1460.0000, !- Specific Heat {J/kg-K} + 0.9000, !- Thermal Absorptance + 0.7000, !- Solar Absorptance + 0.7000; !- Visible Absorptance + + Material, + Roof Insulation, !- Name + MediumRough, !- Roughness + 0.1250, !- Thickness {m} + 0.0490, !- Conductivity {W/m-K} + 265.0000, !- Density {kg/m3} + 836.8000, !- Specific Heat {J/kg-K} + 0.9000, !- Thermal Absorptance + 0.7000, !- Solar Absorptance + 0.7000; !- Visible Absorptance + + Material, + Metal Decking, !- Name + MediumSmooth, !- Roughness + 0.0015, !- Thickness {m} + 45.0060, !- Conductivity {W/m-K} + 7680.0000, !- Density {kg/m3} + 418.4000, !- Specific Heat {J/kg-K} + 0.9000, !- Thermal Absorptance + 0.7000, !- Solar Absorptance + 0.3000; !- Visible Absorptance + + Material, + GP01 1/2 GYPSUM, !- Name + Smooth, !- Roughness + 0.0127, !- Thickness {m} + 0.1600, !- Conductivity {W/m-K} + 800.0000, !- Density {kg/m3} + 1090.0000, !- Specific Heat {J/kg-K} + 0.9000, !- Thermal Absorptance + 0.7000, !- Solar Absorptance + 0.5000; !- Visible Absorptance + + Material:NoMass, + MAT-SHEATH, !- Name + Rough, !- Roughness + 0.3626, !- Thermal Resistance {m2-K/W} + 0.9000, !- Thermal Absorptance + 0.7000, !- Solar Absorptance + 0.7000; !- Visible Absorptance + + Material, + Wall Insulation [2], !- Name + MediumRough, !- Roughness + 0.0376, !- Thickness {m} + 0.0450, !- Conductivity {W/m-K} + 265.0000, !- Density {kg/m3} + 836.8000, !- Specific Heat {J/kg-K} + 0.9000, !- Thermal Absorptance + 0.7000, !- Solar Absorptance + 0.7000; !- Visible Absorptance + + Material, + 1/2IN Gypsum, !- Name + Smooth, !- Roughness + 0.0127, !- Thickness {m} + 0.1600, !- Conductivity {W/m-K} + 784.9000, !- Density {kg/m3} + 830.0000, !- Specific Heat {J/kg-K} + 0.9000, !- Thermal Absorptance + 0.9200, !- Solar Absorptance + 0.9200; !- Visible Absorptance + + Material, + MAT-CC05 8 HW CONCRETE, !- Name + Rough, !- Roughness + 0.2032, !- Thickness {m} + 1.3110, !- Conductivity {W/m-K} + 2240.0000, !- Density {kg/m3} + 836.8000, !- Specific Heat {J/kg-K} + 0.9000, !- Thermal Absorptance + 0.7000, !- Solar Absorptance + 0.7000; !- Visible Absorptance + + Material:NoMass, + CP02 CARPET PAD, !- Name + VeryRough, !- Roughness + 0.2165, !- Thermal Resistance {m2-K/W} + 0.9000, !- Thermal Absorptance + 0.7000, !- Solar Absorptance + 0.8000; !- Visible Absorptance + + Material, + Floor Insulation [2], !- Name + MediumRough, !- Roughness + 0.0503, !- Thickness {m} + 0.0450, !- Conductivity {W/m-K} + 265.0000, !- Density {kg/m3} + 836.8000, !- Specific Heat {J/kg-K} + 0.9000, !- Thermal Absorptance + 0.7000, !- Solar Absorptance + 0.7000; !- Visible Absorptance + + Material, + 1/2IN Gypsum Top, !- Name + Smooth, !- Roughness + 0.0127, !- Thickness {m} + 0.1600, !- Conductivity {W/m-K} + 784.9000, !- Density {kg/m3} + 830.0000, !- Specific Heat {J/kg-K} + 0.9000, !- Thermal Absorptance + 0.9200, !- Solar Absorptance + 0.9200; !- Visible Absorptance + + Material, + AtticFloor Insulation, !- Name + MediumRough, !- Roughness + 0.2379, !- Thickness {m} + 0.0490, !- Conductivity {W/m-K} + 265.0000, !- Density {kg/m3} + 836.8000, !- Specific Heat {J/kg-K} + 0.9000, !- Thermal Absorptance + 0.7000, !- Solar Absorptance + 0.7000; !- Visible Absorptance + + Material, + 1/2IN Gypsum Bottom, !- Name + Smooth, !- Roughness + 0.0127, !- Thickness {m} + 0.1600, !- Conductivity {W/m-K} + 784.9000, !- Density {kg/m3} + 830.0000, !- Specific Heat {J/kg-K} + 0.9000, !- Thermal Absorptance + 0.9200, !- Solar Absorptance + 0.9200; !- Visible Absorptance + + Material, + Std Wood 6inch, !- Name + MediumSmooth, !- Roughness + 0.15, !- Thickness {m} + 0.12, !- Conductivity {W/m-K} + 540.0000, !- Density {kg/m3} + 1210, !- Specific Heat {J/kg-K} + 0.9000000, !- Thermal Absorptance + 0.7000000, !- Solar Absorptance + 0.7000000; !- Visible Absorptance + + Material, + Std 1.5 MW CONCRETE, !- Name + Rough, !- Roughness + 0.038, !- Thickness {m} + 0.858, !- Conductivity {W/m-K} + 1968, !- Density {kg/m3} + 836.8, !- Specific Heat {J/kg-K} + 0.9, !- Thermal Absorptance + 0.7, !- Solar Absorptance + 0.7; !- Visible Absorptance + + Material, + Std AC02, !- Name + MediumSmooth, !- Roughness + 1.2700000E-02, !- Thickness {m} + 5.7000000E-02, !- Conductivity {W/m-K} + 288.0000, !- Density {kg/m3} + 1339.000, !- Specific Heat {J/kg-K} + 0.9000000, !- Thermal Absorptance + 0.7000000, !- Solar Absorptance + 0.2000000; !- Visible Absorptance + + Material:NoMass, + Std CP02 CARPET PAD, !- Name + VeryRough, !- Roughness + 0.21648, !- Thermal Resistance {m2-K/W} + 0.9, !- Thermal Absorptance + 0.7, !- Solar Absorptance + 0.8; !- Visible Absorptance + + Material, + Std MAT-CC05 4 MW CONCRETE, !- Name + Rough, !- Roughness + 0.1000, !- Thickness {m} + 0.858, !- Conductivity {W/m-K} + 1968, !- Density {kg/m3} + 836.8, !- Specific Heat {J/kg-K} + 0.9, !- Thermal Absorptance + 0.7, !- Solar Absorptance + 0.2; !- Visible Absorptance + + Material, + Std Very High Reflectivity Surface, !- Name + Smooth, !- Roughness + 0.0005, !- Thickness {m} + 237, !- Conductivity {W/m-K} + 2702, !- Density {kg/m3} + 903, !- Specific Heat {J/kg-K} + 0.90, !- Thermal Absorptance + 0.05, !- Solar Absorptance + 0.05; !- Visible Absorptance + + WindowMaterial:Glazing, + Std Clear Acrylic Plastic, !- Name + SpectralAverage, !- Optical Data Type + , !- Window Glass Spectral Data Set Name + 0.003, !- Thickness {m} + 0.92, !- Solar Transmittance at Normal Incidence + 0.05, !- Front Side Solar Reflectance at Normal Incidence + 0.05, !- Back Side Solar Reflectance at Normal Incidence + 0.92, !- Visible Transmittance at Normal Incidence + 0.05, !- Front Side Visible Reflectance at Normal Incidence + 0.05, !- Back Side Visible Reflectance at Normal Incidence + 0.00, !- Infrared Transmittance at Normal Incidence + 0.90, !- Front Side Infrared Hemispherical Emissivity + 0.90, !- Back Side Infrared Hemispherical Emissivity + 0.90; !- Conductivity {W/m-K} + + WindowMaterial:Glazing, + Std Diffusing Acrylic Plastic, !- Name + SpectralAverage, !- Optical Data Type + , !- Window Glass Spectral Data Set Name + 0.0022, !- Thickness {m} + 0.90, !- Solar Transmittance at Normal Incidence + 0.08, !- Front Side Solar Reflectance at Normal Incidence + 0.08, !- Back Side Solar Reflectance at Normal Incidence + 0.90, !- Visible Transmittance at Normal Incidence + 0.08, !- Front Side Visible Reflectance at Normal Incidence + 0.08, !- Back Side Visible Reflectance at Normal Incidence + 0.00, !- Infrared Transmittance at Normal Incidence + 0.90, !- Front Side Infrared Hemispherical Emissivity + 0.90, !- Back Side Infrared Hemispherical Emissivity + 0.90; !- Conductivity {W/m-K} + + Material, + Std PW05, !- Name + MediumSmooth, !- Roughness + 1.9099999E-02, !- Thickness {m} + 0.1150000, !- Conductivity {W/m-K} + 545.0000, !- Density {kg/m3} + 1213.000, !- Specific Heat {J/kg-K} + 0.9000000, !- Thermal Absorptance + 0.7800000, !- Solar Absorptance + 0.7800000; !- Visible Absorptance + + Material, + Std Steel_Brown_Regular, !- Name + Smooth, !- Roughness + 1.5000000E-03, !- Thickness {m} + 44.96960, !- Conductivity {W/m-K} + 7689.000, !- Density {kg/m3} + 418.0000, !- Specific Heat {J/kg-K} + 0.9000000, !- Thermal Absorptance + 0.9200000, !- Solar Absorptance + 0.92000000; !- Visible Absorptance + + Material, + Std Steel_Brown_Cool, !- Name + Smooth, !- Roughness + 1.5000000E-03, !- Thickness {m} + 44.96960, !- Conductivity {W/m-K} + 7689.000, !- Density {kg/m3} + 418.0000, !- Specific Heat {J/kg-K} + 0.9000000, !- Thermal Absorptance + 0.7300000, !- Solar Absorptance + 0.73000000; !- Visible Absorptance + + Construction, + InteriorFurnishings, !- Name + Std Wood 6inch; !- Outside Layer + + ComponentCost:LineItem, + Interior Furnishings, !- Name + , !- Type + Construction, !- Line Item Type + InteriorFurnishings, !- Item Name + , !- Object End-Use Key + , !- Cost per Each {$} + 1, !- Cost per Area {$/m2} + , !- Cost per Unit of Output Capacity {$/kW} + , !- Cost per Unit of Output Capacity per COP {$/kW} + , !- Cost per Volume {$/m3} + , !- Cost per Volume Rate {$/(m3/s)} + ; !- Cost per Energy per Temperature Difference {$/(W/K)} + + Construction, + ASHRAE 90.1-2004_Sec 5.5-3ab_0_0.1_fixed_south_window, !- Name + Theoretical Glass [23], !- Outside Layer + AIR 6MM, !- Layer 2 + Theoretical Glass [23]; !- Layer 3 + + ComponentCost:LineItem, + south:ASHRAE 90.1-2004_Sec 5.5-3ab_0_0.1_fixed_south_window, !- Name + , !- Type + CONSTRUCTION, !- Line Item Type + ASHRAE 90.1-2004_Sec 5.5-3ab_0_0.1_fixed_south_window, !- Item Name + , !- Object End-Use Key + , !- Cost per Each {$} + 193.8100, !- Cost per Area {$/m2} + , !- Cost per Unit of Output Capacity {$/kW} + , !- Cost per Unit of Output Capacity per COP {$/kW} + , !- Cost per Volume {$/m3} + , !- Cost per Volume Rate {$/(m3/s)} + , !- Cost per Energy per Temperature Difference {$/(W/K)} + ; !- Quantity {dimensionless} + + Construction, + ASHRAE 90.1-2004_Sec 5.5-3ab_0_0.1_fixed_east_window, !- Name + Theoretical Glass [23], !- Outside Layer + AIR 6MM, !- Layer 2 + Theoretical Glass [23]; !- Layer 3 + + ComponentCost:LineItem, + east:ASHRAE 90.1-2004_Sec 5.5-3ab_0_0.1_fixed_east_window, !- Name + , !- Type + CONSTRUCTION, !- Line Item Type + ASHRAE 90.1-2004_Sec 5.5-3ab_0_0.1_fixed_east_window, !- Item Name + , !- Object End-Use Key + , !- Cost per Each {$} + 193.8100, !- Cost per Area {$/m2} + , !- Cost per Unit of Output Capacity {$/kW} + , !- Cost per Unit of Output Capacity per COP {$/kW} + , !- Cost per Volume {$/m3} + , !- Cost per Volume Rate {$/(m3/s)} + , !- Cost per Energy per Temperature Difference {$/(W/K)} + ; !- Quantity {dimensionless} + + Construction, + ASHRAE 90.1-2004_Sec 5.5-3ab_0_0.1_fixed_north_window, !- Name + Theoretical Glass [24], !- Outside Layer + AIR 6MM, !- Layer 2 + Theoretical Glass [24]; !- Layer 3 + + ComponentCost:LineItem, + north:ASHRAE 90.1-2004_Sec 5.5-3ab_0_0.1_fixed_north_window, !- Name + , !- Type + CONSTRUCTION, !- Line Item Type + ASHRAE 90.1-2004_Sec 5.5-3ab_0_0.1_fixed_north_window, !- Item Name + , !- Object End-Use Key + , !- Cost per Each {$} + 191.8100, !- Cost per Area {$/m2} + , !- Cost per Unit of Output Capacity {$/kW} + , !- Cost per Unit of Output Capacity per COP {$/kW} + , !- Cost per Volume {$/m3} + , !- Cost per Volume Rate {$/(m3/s)} + , !- Cost per Energy per Temperature Difference {$/(W/K)} + ; !- Quantity {dimensionless} + + Construction, + ASHRAE 90.1-2004_Sec 5.5-3ab_0_0.1_fixed_west_window, !- Name + Theoretical Glass [23], !- Outside Layer + AIR 6MM, !- Layer 2 + Theoretical Glass [23]; !- Layer 3 + + ComponentCost:LineItem, + west:ASHRAE 90.1-2004_Sec 5.5-3ab_0_0.1_fixed_west_window, !- Name + , !- Type + CONSTRUCTION, !- Line Item Type + ASHRAE 90.1-2004_Sec 5.5-3ab_0_0.1_fixed_west_window, !- Item Name + , !- Object End-Use Key + , !- Cost per Each {$} + 193.8100, !- Cost per Area {$/m2} + , !- Cost per Unit of Output Capacity {$/kW} + , !- Cost per Unit of Output Capacity per COP {$/kW} + , !- Cost per Volume {$/m3} + , !- Cost per Volume Rate {$/(m3/s)} + , !- Cost per Energy per Temperature Difference {$/(W/K)} + ; !- Quantity {dimensionless} + + Construction, + ASHRAE 90.1-2004_Sec 5.5-3ab_IEAD_Roof, !- Name + Roof Membrane, !- Outside Layer + Roof Insulation, !- Layer 2 + Metal Decking; !- Layer 3 + + ComponentCost:LineItem, + roofs:ASHRAE 90.1-2004_Sec 5.5-3ab_IEAD_Roof, !- Name + , !- Type + CONSTRUCTION, !- Line Item Type + ASHRAE 90.1-2004_Sec 5.5-3ab_IEAD_Roof, !- Item Name + , !- Object End-Use Key + , !- Cost per Each {$} + 26.5800, !- Cost per Area {$/m2} + , !- Cost per Unit of Output Capacity {$/kW} + , !- Cost per Unit of Output Capacity per COP {$/kW} + , !- Cost per Volume {$/m3} + , !- Cost per Volume Rate {$/(m3/s)} + , !- Cost per Energy per Temperature Difference {$/(W/K)} + ; !- Quantity {dimensionless} + + Construction, + ASHRAE 90.1-2004_Sec 5.5-3ab_Interior Wall_Int-Wall, !- Name + GP01 1/2 GYPSUM, !- Outside Layer + GP01 1/2 GYPSUM; !- Layer 2 + + ComponentCost:LineItem, + int-walls:ASHRAE 90.1-2004_Sec 5.5-3ab_Interior Wall_Int-Wall, !- Name + , !- Type + CONSTRUCTION, !- Line Item Type + ASHRAE 90.1-2004_Sec 5.5-3ab_Interior Wall_Int-Wall, !- Item Name + , !- Object End-Use Key + , !- Cost per Each {$} + 1.0000, !- Cost per Area {$/m2} + , !- Cost per Unit of Output Capacity {$/kW} + , !- Cost per Unit of Output Capacity per COP {$/kW} + , !- Cost per Volume {$/m3} + , !- Cost per Volume Rate {$/(m3/s)} + , !- Cost per Energy per Temperature Difference {$/(W/K)} + ; !- Quantity {dimensionless} + + Construction, + ASHRAE 90.1-2004_Sec 5.5-3ab_Steel-Framed_Ext-wall, !- Name + MAT-SHEATH, !- Outside Layer + Wall Insulation [2], !- Layer 2 + 1/2IN Gypsum; !- Layer 3 + + ComponentCost:LineItem, + ext-walls:ASHRAE 90.1-2004_Sec 5.5-3ab_Steel-Framed_Ext-wall, !- Name + , !- Type + CONSTRUCTION, !- Line Item Type + ASHRAE 90.1-2004_Sec 5.5-3ab_Steel-Framed_Ext-wall, !- Item Name + , !- Object End-Use Key + , !- Cost per Each {$} + 39.2600, !- Cost per Area {$/m2} + , !- Cost per Unit of Output Capacity {$/kW} + , !- Cost per Unit of Output Capacity per COP {$/kW} + , !- Cost per Volume {$/m3} + , !- Cost per Volume Rate {$/(m3/s)} + , !- Cost per Energy per Temperature Difference {$/(W/K)} + ; !- Quantity {dimensionless} + + Construction, + ASHRAE 90.1-2004_Sec 5.5-3ab_Unheated_Ext-slab, !- Name + MAT-CC05 8 HW CONCRETE, !- Outside Layer + CP02 CARPET PAD; !- Layer 2 + + ComponentCost:LineItem, + ext-slab:ASHRAE 90.1-2004_Sec 5.5-3ab_Unheated_Ext-slab, !- Name + , !- Type + CONSTRUCTION, !- Line Item Type + ASHRAE 90.1-2004_Sec 5.5-3ab_Unheated_Ext-slab, !- Item Name + , !- Object End-Use Key + , !- Cost per Each {$} + 24.8600, !- Cost per Area {$/m2} + , !- Cost per Unit of Output Capacity {$/kW} + , !- Cost per Unit of Output Capacity per COP {$/kW} + , !- Cost per Volume {$/m3} + , !- Cost per Volume Rate {$/(m3/s)} + , !- Cost per Energy per Temperature Difference {$/(W/K)} + ; !- Quantity {dimensionless} + + Zone, + ZN_1_FLR_1_SEC_1, !- Name + 0.0000, !- Direction of Relative North {deg} + 0.0000, !- X Origin {m} + 0.0000, !- Y Origin {m} + 0.0000, !- Z Origin {m} + 1, !- Type + 1.0000, !- Multiplier + 5.0088, !- Ceiling Height {m} + 393.3855, !- Volume {m3} + autocalculate, !- Floor Area {m2} + , !- Zone Inside Convection Algorithm + , !- Zone Outside Convection Algorithm + YES; !- Part of Total Floor Area + + BuildingSurface:Detailed, + ZN_1_FLR_1_SEC_1_Wall_1, !- Name + wall, !- Surface Type + ASHRAE 90.1-2004_Sec 5.5-3ab_Steel-Framed_Ext-wall, !- Construction Name + ZN_1_FLR_1_SEC_1, !- Zone Name + Outdoors, !- Outside Boundary Condition + , !- Outside Boundary Condition Object + SunExposed, !- Sun Exposure + WindExposed, !- Wind Exposure + 0.5000, !- View Factor to Ground + 4, !- Number of Vertices + 0.000,0.000,5.009, !- X,Y,Z ==> Vertex 1 {m} + 0.000,0.000,0.000, !- X,Y,Z ==> Vertex 2 {m} + 21.756,0.000,0.000, !- X,Y,Z ==> Vertex 3 {m} + 21.756,0.000,5.009; !- X,Y,Z ==> Vertex 4 {m} + + FenestrationSurface:Detailed, + ZN_1_FLR_1_SEC_1_Wall_1_window_1, !- Name + Window, !- Surface Type + ASHRAE 90.1-2004_Sec 5.5-3ab_0_0.1_fixed_north_window, !- Construction Name + ZN_1_FLR_1_SEC_1_Wall_1, !- Building Surface Name + , !- Outside Boundary Condition Object + 0.5000, !- View Factor to Ground + , !- Frame and Divider Name + 1, !- Multiplier + 4, !- Number of Vertices + 0.050,0.000,1.181, !- X,Y,Z ==> Vertex 1 {m} + 0.050,0.000,1.000, !- X,Y,Z ==> Vertex 2 {m} + 21.706,0.000,1.000, !- X,Y,Z ==> Vertex 3 {m} + 21.706,0.000,1.181; !- X,Y,Z ==> Vertex 4 {m} + + BuildingSurface:Detailed, + ZN_1_FLR_1_SEC_1_Wall_2, !- Name + wall, !- Surface Type + ASHRAE 90.1-2004_Sec 5.5-3ab_Interior Wall_Int-Wall, !- Construction Name + ZN_1_FLR_1_SEC_1, !- Zone Name + Surface, !- Outside Boundary Condition + ZN_1_FLR_1_SEC_2_Wall_4, !- Outside Boundary Condition Object + NoSun, !- Sun Exposure + NoWind, !- Wind Exposure + 0.0000, !- View Factor to Ground + 4, !- Number of Vertices + 21.756,0.000,5.009, !- X,Y,Z ==> Vertex 1 {m} + 21.756,0.000,0.000, !- X,Y,Z ==> Vertex 2 {m} + 17.186,4.570,0.000, !- X,Y,Z ==> Vertex 3 {m} + 17.186,4.570,5.009; !- X,Y,Z ==> Vertex 4 {m} + + BuildingSurface:Detailed, + ZN_1_FLR_1_SEC_1_Wall_3, !- Name + wall, !- Surface Type + ASHRAE 90.1-2004_Sec 5.5-3ab_Interior Wall_Int-Wall, !- Construction Name + ZN_1_FLR_1_SEC_1, !- Zone Name + Surface, !- Outside Boundary Condition + ZN_1_FLR_1_SEC_5_Wall_1, !- Outside Boundary Condition Object + NoSun, !- Sun Exposure + NoWind, !- Wind Exposure + 0.0000, !- View Factor to Ground + 4, !- Number of Vertices + 17.186,4.570,5.009, !- X,Y,Z ==> Vertex 1 {m} + 17.186,4.570,0.000, !- X,Y,Z ==> Vertex 2 {m} + 4.570,4.570,0.000, !- X,Y,Z ==> Vertex 3 {m} + 4.570,4.570,5.009; !- X,Y,Z ==> Vertex 4 {m} + + BuildingSurface:Detailed, + ZN_1_FLR_1_SEC_1_Wall_4, !- Name + wall, !- Surface Type + ASHRAE 90.1-2004_Sec 5.5-3ab_Interior Wall_Int-Wall, !- Construction Name + ZN_1_FLR_1_SEC_1, !- Zone Name + Surface, !- Outside Boundary Condition + ZN_1_FLR_1_SEC_4_Wall_1, !- Outside Boundary Condition Object + NoSun, !- Sun Exposure + NoWind, !- Wind Exposure + 0.0000, !- View Factor to Ground + 4, !- Number of Vertices + 4.570,4.570,5.009, !- X,Y,Z ==> Vertex 1 {m} + 4.570,4.570,0.000, !- X,Y,Z ==> Vertex 2 {m} + 0.000,0.000,0.000, !- X,Y,Z ==> Vertex 3 {m} + 0.000,0.000,5.009; !- X,Y,Z ==> Vertex 4 {m} + + BuildingSurface:Detailed, + ZN_1_FLR_1_SEC_1_Floor, !- Name + floor, !- Surface Type + ASHRAE 90.1-2004_Sec 5.5-3ab_Unheated_Ext-slab, !- Construction Name + ZN_1_FLR_1_SEC_1, !- Zone Name + Ground, !- Outside Boundary Condition + , !- Outside Boundary Condition Object + NoSun, !- Sun Exposure + NoWind, !- Wind Exposure + 0.0000, !- View Factor to Ground + 4, !- Number of Vertices + 4.570,4.570,0.000, !- X,Y,Z ==> Vertex 1 {m} + 17.186,4.570,0.000, !- X,Y,Z ==> Vertex 2 {m} + 21.756,0.000,0.000, !- X,Y,Z ==> Vertex 3 {m} + 0.000,0.000,0.000; !- X,Y,Z ==> Vertex 4 {m} + + BuildingSurface:Detailed, + ZN_1_FLR_1_SEC_1_Ceiling,!- Name + ceiling, !- Surface Type + ASHRAE 90.1-2004_Sec 5.5-3ab_IEAD_Roof, !- Construction Name + ZN_1_FLR_1_SEC_1, !- Zone Name + Outdoors, !- Outside Boundary Condition + , !- Outside Boundary Condition Object + SunExposed, !- Sun Exposure + WindExposed, !- Wind Exposure + 0.0000, !- View Factor to Ground + 4, !- Number of Vertices + 0.000,0.000,5.009, !- X,Y,Z ==> Vertex 1 {m} + 21.756,0.000,5.009, !- X,Y,Z ==> Vertex 2 {m} + 17.186,4.570,5.009, !- X,Y,Z ==> Vertex 3 {m} + 4.570,4.570,5.009; !- X,Y,Z ==> Vertex 4 {m} + + InternalMass, + ZN_1_FLR_1_SEC_1_InternalMass_1, !- Name + InteriorFurnishings, !- Construction Name + ZN_1_FLR_1_SEC_1, !- Zone or ZoneList Name + 157.0784; !- Surface Area {m2} + + ZoneInfiltration:DesignFlowRate, + ZN_1_FLR_1_SEC_1_Infiltration, !- Name + ZN_1_FLR_1_SEC_1, !- Zone or ZoneList Name + INFIL_SCH, !- Schedule Name + flow/zone, !- Design Flow Rate Calculation Method + 0.0542, !- Design Flow Rate {m3/s} + , !- Flow per Zone Floor Area {m3/s-m2} + , !- Flow per Exterior Surface Area {m3/s-m2} + , !- Air Changes per Hour {1/hr} + 1.0000, !- Constant Term Coefficient + 0.0000, !- Temperature Term Coefficient + 0.0000, !- Velocity Term Coefficient + 0.0000; !- Velocity Squared Term Coefficient + + People, + ZN_1_FLR_1_SEC_1, !- Name + ZN_1_FLR_1_SEC_1, !- Zone or ZoneList Name + BLDG_OCC_SCH, !- Number of People Schedule Name + people, !- Number of People Calculation Method + 0.6039, !- Number of People + , !- People per Zone Floor Area {person/m2} + , !- Zone Floor Area per Person {m2/person} + 0.3000, !- Fraction Radiant + , !- Sensible Heat Fraction + ACTIVITY_SCH, !- Activity Level Schedule Name + 3.82E-8, !- Carbon Dioxide Generation Rate {m3/s-W} + , !- Enable ASHRAE 55 Comfort Warnings + ZoneAveraged, !- Mean Radiant Temperature Calculation Type + , !- Surface Name/Angle Factor List Name + WORK_EFF_SCH, !- Work Efficiency Schedule Name + ClothingInsulationSchedule, !- Clothing Insulation Calculation Method + , !- Clothing Insulation Calculation Method Schedule Name + CLOTHING_SCH, !- Clothing Insulation Schedule Name + AIR_VELO_SCH, !- Air Velocity Schedule Name + FANGER; !- Thermal Comfort Model 1 Type + + Lights, + ZN_1_FLR_1_SEC_1_Lights, !- Name + ZN_1_FLR_1_SEC_1, !- Zone or ZoneList Name + BLDG_LIGHT_SCH, !- Schedule Name + LightingLevel, !- Design Level Calculation Method + 1178.0879, !- Lighting Level {W} + , !- Watts per Zone Floor Area {W/m2} + , !- Watts per Person {W/person} + 0.0000, !- Return Air Fraction + 0.2000, !- Fraction Radiant + 0.2000, !- Fraction Visible + 1.0000, !- Fraction Replaceable + General Lights; !- End-Use Subcategory + + ComponentCost:LineItem, + LIGHTING EQUIP:ZN_1_FLR_1_SEC_1, !- Name + , !- Type + LIGHTS, !- Line Item Type + ZN_1_FLR_1_SEC_1, !- Item Name + , !- Object End-Use Key + , !- Cost per Each {$} + , !- Cost per Area {$/m2} + 1.0000, !- Cost per Unit of Output Capacity {$/kW} + , !- Cost per Unit of Output Capacity per COP {$/kW} + , !- Cost per Volume {$/m3} + , !- Cost per Volume Rate {$/(m3/s)} + , !- Cost per Energy per Temperature Difference {$/(W/K)} + ; !- Quantity {dimensionless} + + ElectricEquipment, + ZN_1_FLR_1_SEC_1_MiscPlug_Equip, !- Name + ZN_1_FLR_1_SEC_1, !- Zone or ZoneList Name + BLDG_EQUIP_SCH, !- Schedule Name + EquipmentLevel, !- Design Level Calculation Method + 465.9534, !- Design Level {W} + , !- Watts per Zone Floor Area {W/m2} + , !- Watts per Person {W/person} + 0.0000, !- Fraction Latent + 0.5000, !- Fraction Radiant + 0.0000, !- Fraction Lost + GeneralEquipment; !- End-Use Subcategory + + GasEquipment, + ZN_1_FLR_1_SEC_1_MiscGas_Equip, !- Name + ZN_1_FLR_1_SEC_1, !- Zone or ZoneList Name + BLDG_EQUIP_SCH, !- Schedule Name + EquipmentLevel, !- Design Level Calculation Method + 184.1006, !- Design Level {W} + , !- Power per Zone Floor Area {W/m2} + , !- Power per Person {W/person} + 0.0000, !- Fraction Latent + 0.2000, !- Fraction Radiant + 0.0000, !- Fraction Lost + 0, !- Carbon Dioxide Generation Rate {m3/s-W} + GeneralEquipment; !- End-Use Subcategory + +!***** Space Conditioning For Zone: ZN_1_FLR_1_SEC_1 ***** + + Sizing:Zone, + ZN_1_FLR_1_SEC_1, !- Zone or ZoneList Name + SupplyAirTemperature, !- Zone Cooling Design Supply Air Temperature Input Method + 14.0, !- Zone Cooling Design Supply Air Temperature {C} + , !- Zone Cooling Design Supply Air Temperature Difference {deltaC} + SupplyAirTemperature, !- Zone Heating Design Supply Air Temperature Input Method + 50.0, !- Zone Heating Design Supply Air Temperature {C} + , !- Zone Heating Design Supply Air Temperature Difference {deltaC} + 0.0085, !- Zone Cooling Design Supply Air Humidity Ratio {kgWater/kgDryAir} + 0.008, !- Zone Heating Design Supply Air Humidity Ratio {kgWater/kgDryAir} + SZ DSOA ZN_1_FLR_1_SEC_1,!- Design Specification Outdoor Air Object Name + 0.0, !- Zone Heating Sizing Factor + 0.0, !- Zone Cooling Sizing Factor + DesignDay, !- Cooling Design Air Flow Method + 0.0, !- Cooling Design Air Flow Rate {m3/s} + , !- Cooling Minimum Air Flow per Zone Floor Area {m3/s-m2} + 0.0, !- Cooling Minimum Air Flow {m3/s} + 0.0, !- Cooling Minimum Air Flow Fraction + DesignDay, !- Heating Design Air Flow Method + 0.0, !- Heating Design Air Flow Rate {m3/s} + , !- Heating Maximum Air Flow per Zone Floor Area {m3/s-m2} + , !- Heating Maximum Air Flow {m3/s} + , !- Heating Maximum Air Flow Fraction + , !- Design Specification Zone Air Distribution Object Name + No, !- Account for Dedicated Outdoor Air System + NeutralSupplyAir, !- Dedicated Outdoor Air System Control Strategy + autosize, !- Dedicated Outdoor Air Low Setpoint Temperature for Design {C} + autosize; !- Dedicated Outdoor Air High Setpoint Temperature for Design {C} + + DesignSpecification:OutdoorAir, + SZ DSOA ZN_1_FLR_1_SEC_1,!- Name + FLOW/ZONE, !- Outdoor Air Method + , !- Outdoor Air Flow per Person {m3/s-person} + 0.0, !- Outdoor Air Flow per Zone Floor Area {m3/s-m2} + 0.073704617803385; !- Outdoor Air Flow per Zone {m3/s} + + ZoneControl:Thermostat, + ZN_1_FLR_1_SEC_1 Thermostat, !- Name + ZN_1_FLR_1_SEC_1, !- Zone or ZoneList Name + Dual Zone Control Type Sched, !- Control Type Schedule Name + ThermostatSetpoint:DualSetpoint, !- Control 1 Object Type + ZN_1_FLR_1_SEC_1 DualSPSched; !- Control 1 Name + + ThermostatSetpoint:DualSetpoint, + ZN_1_FLR_1_SEC_1 DualSPSched, !- Name + HtgSetP_Sch, !- Heating Setpoint Temperature Schedule Name + ClgSetP_Sch; !- Cooling Setpoint Temperature Schedule Name + + ZoneHVAC:EquipmentConnections, + ZN_1_FLR_1_SEC_1, !- Zone Name + ZN_1_FLR_1_SEC_1 Equipment, !- Zone Conditioning Equipment List Name + ZN_1_FLR_1_SEC_1 Inlet Nodes, !- Zone Air Inlet Node or NodeList Name + , !- Zone Air Exhaust Node or NodeList Name + ZN_1_FLR_1_SEC_1 Air Node, !- Zone Air Node Name + ZN_1_FLR_1_SEC_1 Return Air Node; !- Zone Return Air Node or NodeList Name + + NodeList, + ZN_1_FLR_1_SEC_1 Inlet Nodes, !- Name + ZN_1_FLR_1_SEC_1 Direct Air Inlet Node; !- Node 1 Name + + ZoneHVAC:EquipmentList, + ZN_1_FLR_1_SEC_1 Equipment, !- Name + SequentialLoad, !- Load Distribution Scheme + ZoneHVAC:AirDistributionUnit, !- Zone Equipment 1 Object Type + ZN_1_FLR_1_SEC_1 Direct Air ADU, !- Zone Equipment 1 Name + 1, !- Zone Equipment 1 Cooling Sequence + 1, !- Zone Equipment 1 Heating or No-Load Sequence + , !- Zone Equipment 1 Sequential Cooling Fraction Schedule Name + ; !- Zone Equipment 1 Sequential Heating Fraction Schedule Name + + AirTerminal:SingleDuct:ConstantVolume:NoReheat, + ZN_1_FLR_1_SEC_1 Direct Air, !- Name + ALWAYS_ON, !- Availability Schedule Name + ZN_1_FLR_1_SEC_1 Direct Air Inlet Node ATInlet, !- Air Inlet Node Name + ZN_1_FLR_1_SEC_1 Direct Air Inlet Node, !- Air Outlet Node Name + AUTOSIZE, !- Maximum Air Flow Rate {m3/s} + , !- Design Specification Outdoor Air Object Name + ; !- Per Person Ventilation Rate Mode + + ZoneHVAC:AirDistributionUnit, + ZN_1_FLR_1_SEC_1 Direct Air ADU, !- Name + ZN_1_FLR_1_SEC_1 Direct Air Inlet Node, !- Air Distribution Unit Outlet Node Name + AirTerminal:SingleDuct:ConstantVolume:NoReheat, !- Air Terminal Object Type + ZN_1_FLR_1_SEC_1 Direct Air, !- Air Terminal Name + , !- Nominal Upstream Leakage Fraction + , !- Constant Downstream Leakage Fraction + ; !- Design Specification Air Terminal Sizing Object Name + + SetpointManager:SingleZone:Reheat, + SupAirTemp MngrZN_1_FLR_1_SEC_1, !- Name + Temperature, !- Control Variable + 13.0, !- Minimum Supply Air Temperature {C} + 40.0, !- Maximum Supply Air Temperature {C} + ZN_1_FLR_1_SEC_1, !- Control Zone Name + ZN_1_FLR_1_SEC_1 Air Node, !- Zone Node Name + ZN_1_FLR_1_SEC_1 Direct Air Inlet Node, !- Zone Inlet Node Name + ZN_1_FLR_1_SEC_1:Sys Supply Equipment Outlet Node; !- Setpoint Node or NodeList Name + +!***** Process Loads For Zone: ZN_1_FLR_1_SEC_1 ***** + + WaterUse:Connections, + ZN_1_FLR_1_SEC_1SHW_DEFAULT, !- Name + ZN_1_FLR_1_SEC_1SHW_DEFAULT Water Inlet Node, !- Inlet Node Name + ZN_1_FLR_1_SEC_1SHW_DEFAULT Water Outlet Node, !- Outlet Node Name + , !- Supply Water Storage Tank Name + , !- Reclamation Water Storage Tank Name + , !- Hot Water Supply Temperature Schedule Name + , !- Cold Water Supply Temperature Schedule Name + , !- Drain Water Heat Exchanger Type + , !- Drain Water Heat Exchanger Destination + , !- Drain Water Heat Exchanger U-Factor Times Area {W/K} + ZN_1_FLR_1_SEC_1SHW_DEFAULT; !- Water Use Equipment 1 Name + + WaterUse:Equipment, + ZN_1_FLR_1_SEC_1SHW_DEFAULT, !- Name + SHW_DEFAULT, !- End-Use Subcategory + 2.21418604788511E-6, !- Peak Flow Rate {m3/s} + HOURS_OF_OPERATION, !- Flow Rate Fraction Schedule Name + ZN_1_FLR_1_SEC_1SHW_DEFAULT Temp Sched, !- Target Temperature Schedule Name + ZN_1_FLR_1_SEC_1SHW_DEFAULTHot Supply Temp Sched, !- Hot Water Supply Temperature Schedule Name + , !- Cold Water Supply Temperature Schedule Name + ZN_1_FLR_1_SEC_1, !- Zone Name + ZN_1_FLR_1_SEC_1SHW_DEFAULT Sensible fract sched, !- Sensible Fraction Schedule Name + ZN_1_FLR_1_SEC_1SHW_DEFAULT Latent fract sched; !- Latent Fraction Schedule Name + + Schedule:Compact, + ZN_1_FLR_1_SEC_1SHW_DEFAULT Latent fract sched, !- Name + Fraction, !- Schedule Type Limits Name + Through: 12/31, !- Field 1 + For: AllDays, !- Field 2 + Until: 24:00,0.05; !- Field 3 + + Schedule:Compact, + ZN_1_FLR_1_SEC_1SHW_DEFAULT Sensible fract sched, !- Name + Fraction, !- Schedule Type Limits Name + Through: 12/31, !- Field 1 + For: AllDays, !- Field 2 + Until: 24:00,0.2; !- Field 3 + + Schedule:Compact, + ZN_1_FLR_1_SEC_1SHW_DEFAULT Temp Sched, !- Name + Temperature, !- Schedule Type Limits Name + Through: 12/31, !- Field 1 + For: AllDays, !- Field 2 + Until: 24:00,40; !- Field 3 + + Schedule:Compact, + ZN_1_FLR_1_SEC_1SHW_DEFAULTHot Supply Temp Sched, !- Name + Temperature, !- Schedule Type Limits Name + Through: 12/31, !- Field 1 + For: AllDays, !- Field 2 + Until: 24:00,55; !- Field 3 + + Zone, + ZN_1_FLR_1_SEC_2, !- Name + 0.0000, !- Direction of Relative North {deg} + 21.7558, !- X Origin {m} + 0.0000, !- Y Origin {m} + 0.0000, !- Z Origin {m} + 1, !- Type + 1.0000, !- Multiplier + 5.0088, !- Ceiling Height {m} + 305.9154, !- Volume {m3} + autocalculate, !- Floor Area {m2} + , !- Zone Inside Convection Algorithm + , !- Zone Outside Convection Algorithm + YES; !- Part of Total Floor Area + + BuildingSurface:Detailed, + ZN_1_FLR_1_SEC_2_Wall_1, !- Name + wall, !- Surface Type + ASHRAE 90.1-2004_Sec 5.5-3ab_Steel-Framed_Ext-wall, !- Construction Name + ZN_1_FLR_1_SEC_2, !- Zone Name + Outdoors, !- Outside Boundary Condition + , !- Outside Boundary Condition Object + SunExposed, !- Sun Exposure + WindExposed, !- Wind Exposure + 0.5000, !- View Factor to Ground + 4, !- Number of Vertices + 0.000,0.000,5.009, !- X,Y,Z ==> Vertex 1 {m} + 0.000,0.000,0.000, !- X,Y,Z ==> Vertex 2 {m} + 0.000,17.935,0.000, !- X,Y,Z ==> Vertex 3 {m} + 0.000,17.935,5.009; !- X,Y,Z ==> Vertex 4 {m} + + FenestrationSurface:Detailed, + ZN_1_FLR_1_SEC_2_Wall_1_window_1, !- Name + Window, !- Surface Type + ASHRAE 90.1-2004_Sec 5.5-3ab_0_0.1_fixed_west_window, !- Construction Name + ZN_1_FLR_1_SEC_2_Wall_1, !- Building Surface Name + , !- Outside Boundary Condition Object + 0.5000, !- View Factor to Ground + , !- Frame and Divider Name + 1, !- Multiplier + 4, !- Number of Vertices + 0.000,0.050,1.363, !- X,Y,Z ==> Vertex 1 {m} + 0.000,0.050,1.000, !- X,Y,Z ==> Vertex 2 {m} + 0.000,17.885,1.000, !- X,Y,Z ==> Vertex 3 {m} + 0.000,17.885,1.363; !- X,Y,Z ==> Vertex 4 {m} + + BuildingSurface:Detailed, + ZN_1_FLR_1_SEC_2_Wall_2, !- Name + wall, !- Surface Type + ASHRAE 90.1-2004_Sec 5.5-3ab_Interior Wall_Int-Wall, !- Construction Name + ZN_1_FLR_1_SEC_2, !- Zone Name + Surface, !- Outside Boundary Condition + ZN_1_FLR_1_SEC_3_Wall_2, !- Outside Boundary Condition Object + NoSun, !- Sun Exposure + NoWind, !- Wind Exposure + 0.0000, !- View Factor to Ground + 4, !- Number of Vertices + 0.000,17.935,5.009, !- X,Y,Z ==> Vertex 1 {m} + 0.000,17.935,0.000, !- X,Y,Z ==> Vertex 2 {m} + -4.570,13.365,0.000, !- X,Y,Z ==> Vertex 3 {m} + -4.570,13.365,5.009; !- X,Y,Z ==> Vertex 4 {m} + + BuildingSurface:Detailed, + ZN_1_FLR_1_SEC_2_Wall_3, !- Name + wall, !- Surface Type + ASHRAE 90.1-2004_Sec 5.5-3ab_Interior Wall_Int-Wall, !- Construction Name + ZN_1_FLR_1_SEC_2, !- Zone Name + Surface, !- Outside Boundary Condition + ZN_1_FLR_1_SEC_5_Wall_2, !- Outside Boundary Condition Object + NoSun, !- Sun Exposure + NoWind, !- Wind Exposure + 0.0000, !- View Factor to Ground + 4, !- Number of Vertices + -4.570,13.365,5.009, !- X,Y,Z ==> Vertex 1 {m} + -4.570,13.365,0.000, !- X,Y,Z ==> Vertex 2 {m} + -4.570,4.570,0.000, !- X,Y,Z ==> Vertex 3 {m} + -4.570,4.570,5.009; !- X,Y,Z ==> Vertex 4 {m} + + BuildingSurface:Detailed, + ZN_1_FLR_1_SEC_2_Wall_4, !- Name + wall, !- Surface Type + ASHRAE 90.1-2004_Sec 5.5-3ab_Interior Wall_Int-Wall, !- Construction Name + ZN_1_FLR_1_SEC_2, !- Zone Name + Surface, !- Outside Boundary Condition + ZN_1_FLR_1_SEC_1_Wall_2, !- Outside Boundary Condition Object + NoSun, !- Sun Exposure + NoWind, !- Wind Exposure + 0.0000, !- View Factor to Ground + 4, !- Number of Vertices + -4.570,4.570,5.009, !- X,Y,Z ==> Vertex 1 {m} + -4.570,4.570,0.000, !- X,Y,Z ==> Vertex 2 {m} + 0.000,0.000,0.000, !- X,Y,Z ==> Vertex 3 {m} + 0.000,0.000,5.009; !- X,Y,Z ==> Vertex 4 {m} + + BuildingSurface:Detailed, + ZN_1_FLR_1_SEC_2_Floor, !- Name + floor, !- Surface Type + ASHRAE 90.1-2004_Sec 5.5-3ab_Unheated_Ext-slab, !- Construction Name + ZN_1_FLR_1_SEC_2, !- Zone Name + Ground, !- Outside Boundary Condition + , !- Outside Boundary Condition Object + NoSun, !- Sun Exposure + NoWind, !- Wind Exposure + 0.0000, !- View Factor to Ground + 4, !- Number of Vertices + -4.570,4.570,0.000, !- X,Y,Z ==> Vertex 1 {m} + -4.570,13.365,0.000, !- X,Y,Z ==> Vertex 2 {m} + 0.000,17.935,0.000, !- X,Y,Z ==> Vertex 3 {m} + 0.000,0.000,0.000; !- X,Y,Z ==> Vertex 4 {m} + + BuildingSurface:Detailed, + ZN_1_FLR_1_SEC_2_Ceiling,!- Name + ceiling, !- Surface Type + ASHRAE 90.1-2004_Sec 5.5-3ab_IEAD_Roof, !- Construction Name + ZN_1_FLR_1_SEC_2, !- Zone Name + Outdoors, !- Outside Boundary Condition + , !- Outside Boundary Condition Object + SunExposed, !- Sun Exposure + WindExposed, !- Wind Exposure + 0.0000, !- View Factor to Ground + 4, !- Number of Vertices + 0.000,0.000,5.009, !- X,Y,Z ==> Vertex 1 {m} + 0.000,17.935,5.009, !- X,Y,Z ==> Vertex 2 {m} + -4.570,13.365,5.009, !- X,Y,Z ==> Vertex 3 {m} + -4.570,4.570,5.009; !- X,Y,Z ==> Vertex 4 {m} + + InternalMass, + ZN_1_FLR_1_SEC_2_InternalMass_1, !- Name + InteriorFurnishings, !- Construction Name + ZN_1_FLR_1_SEC_2, !- Zone or ZoneList Name + 122.1516; !- Surface Area {m2} + + ZoneInfiltration:DesignFlowRate, + ZN_1_FLR_1_SEC_2_Infiltration, !- Name + ZN_1_FLR_1_SEC_2, !- Zone or ZoneList Name + INFIL_SCH, !- Schedule Name + flow/zone, !- Design Flow Rate Calculation Method + 0.0435, !- Design Flow Rate {m3/s} + , !- Flow per Zone Floor Area {m3/s-m2} + , !- Flow per Exterior Surface Area {m3/s-m2} + , !- Air Changes per Hour {1/hr} + 1.0000, !- Constant Term Coefficient + 0.0000, !- Temperature Term Coefficient + 0.0000, !- Velocity Term Coefficient + 0.0000; !- Velocity Squared Term Coefficient + + People, + ZN_1_FLR_1_SEC_2, !- Name + ZN_1_FLR_1_SEC_2, !- Zone or ZoneList Name + BLDG_OCC_SCH, !- Number of People Schedule Name + people, !- Number of People Calculation Method + 0.4696, !- Number of People + , !- People per Zone Floor Area {person/m2} + , !- Zone Floor Area per Person {m2/person} + 0.3000, !- Fraction Radiant + , !- Sensible Heat Fraction + ACTIVITY_SCH, !- Activity Level Schedule Name + 3.82E-8, !- Carbon Dioxide Generation Rate {m3/s-W} + , !- Enable ASHRAE 55 Comfort Warnings + ZoneAveraged, !- Mean Radiant Temperature Calculation Type + , !- Surface Name/Angle Factor List Name + WORK_EFF_SCH, !- Work Efficiency Schedule Name + ClothingInsulationSchedule, !- Clothing Insulation Calculation Method + , !- Clothing Insulation Calculation Method Schedule Name + CLOTHING_SCH, !- Clothing Insulation Schedule Name + AIR_VELO_SCH, !- Air Velocity Schedule Name + FANGER; !- Thermal Comfort Model 1 Type + + Lights, + ZN_1_FLR_1_SEC_2_Lights, !- Name + ZN_1_FLR_1_SEC_2, !- Zone or ZoneList Name + BLDG_LIGHT_SCH, !- Schedule Name + LightingLevel, !- Design Level Calculation Method + 916.1373, !- Lighting Level {W} + , !- Watts per Zone Floor Area {W/m2} + , !- Watts per Person {W/person} + 0.0000, !- Return Air Fraction + 0.2000, !- Fraction Radiant + 0.2000, !- Fraction Visible + 1.0000, !- Fraction Replaceable + General Lights; !- End-Use Subcategory + + ComponentCost:LineItem, + LIGHTING EQUIP:ZN_1_FLR_1_SEC_2, !- Name + , !- Type + LIGHTS, !- Line Item Type + ZN_1_FLR_1_SEC_2, !- Item Name + , !- Object End-Use Key + , !- Cost per Each {$} + , !- Cost per Area {$/m2} + 1.0000, !- Cost per Unit of Output Capacity {$/kW} + , !- Cost per Unit of Output Capacity per COP {$/kW} + , !- Cost per Volume {$/m3} + , !- Cost per Volume Rate {$/(m3/s)} + , !- Cost per Energy per Temperature Difference {$/(W/K)} + ; !- Quantity {dimensionless} + + ElectricEquipment, + ZN_1_FLR_1_SEC_2_MiscPlug_Equip, !- Name + ZN_1_FLR_1_SEC_2, !- Zone or ZoneList Name + BLDG_EQUIP_SCH, !- Schedule Name + EquipmentLevel, !- Design Level Calculation Method + 362.3476, !- Design Level {W} + , !- Watts per Zone Floor Area {W/m2} + , !- Watts per Person {W/person} + 0.0000, !- Fraction Latent + 0.5000, !- Fraction Radiant + 0.0000, !- Fraction Lost + GeneralEquipment; !- End-Use Subcategory + + GasEquipment, + ZN_1_FLR_1_SEC_2_MiscGas_Equip, !- Name + ZN_1_FLR_1_SEC_2, !- Zone or ZoneList Name + BLDG_EQUIP_SCH, !- Schedule Name + EquipmentLevel, !- Design Level Calculation Method + 143.1654, !- Design Level {W} + , !- Power per Zone Floor Area {W/m2} + , !- Power per Person {W/person} + 0.0000, !- Fraction Latent + 0.2000, !- Fraction Radiant + 0.0000, !- Fraction Lost + 0, !- Carbon Dioxide Generation Rate {m3/s-W} + GeneralEquipment; !- End-Use Subcategory + +!***** Space Conditioning For Zone: ZN_1_FLR_1_SEC_2 ***** + + Sizing:Zone, + ZN_1_FLR_1_SEC_2, !- Zone or ZoneList Name + SupplyAirTemperature, !- Zone Cooling Design Supply Air Temperature Input Method + 14.0, !- Zone Cooling Design Supply Air Temperature {C} + , !- Zone Cooling Design Supply Air Temperature Difference {deltaC} + SupplyAirTemperature, !- Zone Heating Design Supply Air Temperature Input Method + 50.0, !- Zone Heating Design Supply Air Temperature {C} + , !- Zone Heating Design Supply Air Temperature Difference {deltaC} + 0.0085, !- Zone Cooling Design Supply Air Humidity Ratio {kgWater/kgDryAir} + 0.008, !- Zone Heating Design Supply Air Humidity Ratio {kgWater/kgDryAir} + SZ DSOA ZN_1_FLR_1_SEC_2,!- Design Specification Outdoor Air Object Name + 0.0, !- Zone Heating Sizing Factor + 0.0, !- Zone Cooling Sizing Factor + DesignDay, !- Cooling Design Air Flow Method + 0.0, !- Cooling Design Air Flow Rate {m3/s} + , !- Cooling Minimum Air Flow per Zone Floor Area {m3/s-m2} + 0.0, !- Cooling Minimum Air Flow {m3/s} + 0.0, !- Cooling Minimum Air Flow Fraction + DesignDay, !- Heating Design Air Flow Method + 0.0, !- Heating Design Air Flow Rate {m3/s} + , !- Heating Maximum Air Flow per Zone Floor Area {m3/s-m2} + , !- Heating Maximum Air Flow {m3/s} + , !- Heating Maximum Air Flow Fraction + , !- Design Specification Zone Air Distribution Object Name + No, !- Account for Dedicated Outdoor Air System + NeutralSupplyAir, !- Dedicated Outdoor Air System Control Strategy + autosize, !- Dedicated Outdoor Air Low Setpoint Temperature for Design {C} + autosize; !- Dedicated Outdoor Air High Setpoint Temperature for Design {C} + + DesignSpecification:OutdoorAir, + SZ DSOA ZN_1_FLR_1_SEC_2,!- Name + FLOW/ZONE, !- Outdoor Air Method + , !- Outdoor Air Flow per Person {m3/s-person} + 0.0, !- Outdoor Air Flow per Zone Floor Area {m3/s-m2} + 0.057316225695446; !- Outdoor Air Flow per Zone {m3/s} + + ZoneControl:Thermostat, + ZN_1_FLR_1_SEC_2 Thermostat, !- Name + ZN_1_FLR_1_SEC_2, !- Zone or ZoneList Name + Dual Zone Control Type Sched, !- Control Type Schedule Name + ThermostatSetpoint:DualSetpoint, !- Control 1 Object Type + ZN_1_FLR_1_SEC_2 DualSPSched; !- Control 1 Name + + ThermostatSetpoint:DualSetpoint, + ZN_1_FLR_1_SEC_2 DualSPSched, !- Name + HtgSetP_Sch, !- Heating Setpoint Temperature Schedule Name + ClgSetP_Sch; !- Cooling Setpoint Temperature Schedule Name + + ZoneHVAC:EquipmentConnections, + ZN_1_FLR_1_SEC_2, !- Zone Name + ZN_1_FLR_1_SEC_2 Equipment, !- Zone Conditioning Equipment List Name + ZN_1_FLR_1_SEC_2 Inlet Nodes, !- Zone Air Inlet Node or NodeList Name + , !- Zone Air Exhaust Node or NodeList Name + ZN_1_FLR_1_SEC_2 Air Node, !- Zone Air Node Name + ZN_1_FLR_1_SEC_2 Return Air Node; !- Zone Return Air Node or NodeList Name + + NodeList, + ZN_1_FLR_1_SEC_2 Inlet Nodes, !- Name + ZN_1_FLR_1_SEC_2 Direct Air Inlet Node; !- Node 1 Name + + ZoneHVAC:EquipmentList, + ZN_1_FLR_1_SEC_2 Equipment, !- Name + SequentialLoad, !- Load Distribution Scheme + ZoneHVAC:AirDistributionUnit, !- Zone Equipment 1 Object Type + ZN_1_FLR_1_SEC_2 Direct Air ADU, !- Zone Equipment 1 Name + 1, !- Zone Equipment 1 Cooling Sequence + 1, !- Zone Equipment 1 Heating or No-Load Sequence + , !- Zone Equipment 1 Sequential Cooling Fraction Schedule Name + ; !- Zone Equipment 1 Sequential Heating Fraction Schedule Name + + AirTerminal:SingleDuct:ConstantVolume:NoReheat, + ZN_1_FLR_1_SEC_2 Direct Air, !- Name + ALWAYS_ON, !- Availability Schedule Name + ZN_1_FLR_1_SEC_2 Direct Air Inlet Node ATInlet, !- Air Inlet Node Name + ZN_1_FLR_1_SEC_2 Direct Air Inlet Node, !- Air Outlet Node Name + AUTOSIZE, !- Maximum Air Flow Rate {m3/s} + , !- Design Specification Outdoor Air Object Name + ; !- Per Person Ventilation Rate Mode + + ZoneHVAC:AirDistributionUnit, + ZN_1_FLR_1_SEC_2 Direct Air ADU, !- Name + ZN_1_FLR_1_SEC_2 Direct Air Inlet Node, !- Air Distribution Unit Outlet Node Name + AirTerminal:SingleDuct:ConstantVolume:NoReheat, !- Air Terminal Object Type + ZN_1_FLR_1_SEC_2 Direct Air, !- Air Terminal Name + , !- Nominal Upstream Leakage Fraction + , !- Constant Downstream Leakage Fraction + ; !- Design Specification Air Terminal Sizing Object Name + + SetpointManager:SingleZone:Reheat, + SupAirTemp MngrZN_1_FLR_1_SEC_2, !- Name + Temperature, !- Control Variable + 13.0, !- Minimum Supply Air Temperature {C} + 40.0, !- Maximum Supply Air Temperature {C} + ZN_1_FLR_1_SEC_2, !- Control Zone Name + ZN_1_FLR_1_SEC_2 Air Node, !- Zone Node Name + ZN_1_FLR_1_SEC_2 Direct Air Inlet Node, !- Zone Inlet Node Name + ZN_1_FLR_1_SEC_2:Sys Supply Equipment Outlet Node; !- Setpoint Node or NodeList Name + +!***** Process Loads For Zone: ZN_1_FLR_1_SEC_2 ***** + + WaterUse:Connections, + ZN_1_FLR_1_SEC_2SHW_DEFAULT, !- Name + ZN_1_FLR_1_SEC_2SHW_DEFAULT Water Inlet Node, !- Inlet Node Name + ZN_1_FLR_1_SEC_2SHW_DEFAULT Water Outlet Node, !- Outlet Node Name + , !- Supply Water Storage Tank Name + , !- Reclamation Water Storage Tank Name + , !- Hot Water Supply Temperature Schedule Name + , !- Cold Water Supply Temperature Schedule Name + , !- Drain Water Heat Exchanger Type + , !- Drain Water Heat Exchanger Destination + , !- Drain Water Heat Exchanger U-Factor Times Area {W/K} + ZN_1_FLR_1_SEC_2SHW_DEFAULT; !- Water Use Equipment 1 Name + + WaterUse:Equipment, + ZN_1_FLR_1_SEC_2SHW_DEFAULT, !- Name + SHW_DEFAULT, !- End-Use Subcategory + 1.72185666291403E-7, !- Peak Flow Rate {m3/s} + HOURS_OF_OPERATION, !- Flow Rate Fraction Schedule Name + ZN_1_FLR_1_SEC_2SHW_DEFAULT Temp Sched, !- Target Temperature Schedule Name + ZN_1_FLR_1_SEC_2SHW_DEFAULTHot Supply Temp Sched, !- Hot Water Supply Temperature Schedule Name + , !- Cold Water Supply Temperature Schedule Name + ZN_1_FLR_1_SEC_2, !- Zone Name + ZN_1_FLR_1_SEC_2SHW_DEFAULT Sensible fract sched, !- Sensible Fraction Schedule Name + ZN_1_FLR_1_SEC_2SHW_DEFAULT Latent fract sched; !- Latent Fraction Schedule Name + + Schedule:Compact, + ZN_1_FLR_1_SEC_2SHW_DEFAULT Latent fract sched, !- Name + Fraction, !- Schedule Type Limits Name + Through: 12/31, !- Field 1 + For: AllDays, !- Field 2 + Until: 24:00,0.05; !- Field 3 + + Schedule:Compact, + ZN_1_FLR_1_SEC_2SHW_DEFAULT Sensible fract sched, !- Name + Fraction, !- Schedule Type Limits Name + Through: 12/31, !- Field 1 + For: AllDays, !- Field 2 + Until: 24:00,0.2; !- Field 3 + + Schedule:Compact, + ZN_1_FLR_1_SEC_2SHW_DEFAULT Temp Sched, !- Name + Temperature, !- Schedule Type Limits Name + Through: 12/31, !- Field 1 + For: AllDays, !- Field 2 + Until: 24:00,40; !- Field 3 + + Schedule:Compact, + ZN_1_FLR_1_SEC_2SHW_DEFAULTHot Supply Temp Sched, !- Name + Temperature, !- Schedule Type Limits Name + Through: 12/31, !- Field 1 + For: AllDays, !- Field 2 + Until: 24:00,55; !- Field 3 + + Zone, + ZN_1_FLR_1_SEC_3, !- Name + 0.0000, !- Direction of Relative North {deg} + 4.5700, !- X Origin {m} + 13.3645, !- Y Origin {m} + 0.0000, !- Z Origin {m} + 1, !- Type + 1.0000, !- Multiplier + 5.0088, !- Ceiling Height {m} + 393.3855, !- Volume {m3} + autocalculate, !- Floor Area {m2} + , !- Zone Inside Convection Algorithm + , !- Zone Outside Convection Algorithm + YES; !- Part of Total Floor Area + + BuildingSurface:Detailed, + ZN_1_FLR_1_SEC_3_Wall_1, !- Name + wall, !- Surface Type + ASHRAE 90.1-2004_Sec 5.5-3ab_Interior Wall_Int-Wall, !- Construction Name + ZN_1_FLR_1_SEC_3, !- Zone Name + Surface, !- Outside Boundary Condition + ZN_1_FLR_1_SEC_5_Wall_3, !- Outside Boundary Condition Object + NoSun, !- Sun Exposure + NoWind, !- Wind Exposure + 0.0000, !- View Factor to Ground + 4, !- Number of Vertices + 0.000,0.000,5.009, !- X,Y,Z ==> Vertex 1 {m} + 0.000,0.000,0.000, !- X,Y,Z ==> Vertex 2 {m} + 12.616,0.000,0.000, !- X,Y,Z ==> Vertex 3 {m} + 12.616,0.000,5.009; !- X,Y,Z ==> Vertex 4 {m} + + BuildingSurface:Detailed, + ZN_1_FLR_1_SEC_3_Wall_2, !- Name + wall, !- Surface Type + ASHRAE 90.1-2004_Sec 5.5-3ab_Interior Wall_Int-Wall, !- Construction Name + ZN_1_FLR_1_SEC_3, !- Zone Name + Surface, !- Outside Boundary Condition + ZN_1_FLR_1_SEC_2_Wall_2, !- Outside Boundary Condition Object + NoSun, !- Sun Exposure + NoWind, !- Wind Exposure + 0.0000, !- View Factor to Ground + 4, !- Number of Vertices + 12.616,0.000,5.009, !- X,Y,Z ==> Vertex 1 {m} + 12.616,0.000,0.000, !- X,Y,Z ==> Vertex 2 {m} + 17.186,4.570,0.000, !- X,Y,Z ==> Vertex 3 {m} + 17.186,4.570,5.009; !- X,Y,Z ==> Vertex 4 {m} + + BuildingSurface:Detailed, + ZN_1_FLR_1_SEC_3_Wall_3, !- Name + wall, !- Surface Type + ASHRAE 90.1-2004_Sec 5.5-3ab_Steel-Framed_Ext-wall, !- Construction Name + ZN_1_FLR_1_SEC_3, !- Zone Name + Outdoors, !- Outside Boundary Condition + , !- Outside Boundary Condition Object + SunExposed, !- Sun Exposure + WindExposed, !- Wind Exposure + 0.5000, !- View Factor to Ground + 4, !- Number of Vertices + 17.186,4.570,5.009, !- X,Y,Z ==> Vertex 1 {m} + 17.186,4.570,0.000, !- X,Y,Z ==> Vertex 2 {m} + -4.570,4.570,0.000, !- X,Y,Z ==> Vertex 3 {m} + -4.570,4.570,5.009; !- X,Y,Z ==> Vertex 4 {m} + + FenestrationSurface:Detailed, + ZN_1_FLR_1_SEC_3_Wall_3_window_1, !- Name + Window, !- Surface Type + ASHRAE 90.1-2004_Sec 5.5-3ab_0_0.1_fixed_south_window, !- Construction Name + ZN_1_FLR_1_SEC_3_Wall_3, !- Building Surface Name + , !- Outside Boundary Condition Object + 0.5000, !- View Factor to Ground + , !- Frame and Divider Name + 1, !- Multiplier + 4, !- Number of Vertices + 17.136,4.570,1.362, !- X,Y,Z ==> Vertex 1 {m} + 17.136,4.570,1.000, !- X,Y,Z ==> Vertex 2 {m} + -4.520,4.570,1.000, !- X,Y,Z ==> Vertex 3 {m} + -4.520,4.570,1.362; !- X,Y,Z ==> Vertex 4 {m} + + BuildingSurface:Detailed, + ZN_1_FLR_1_SEC_3_Wall_4, !- Name + wall, !- Surface Type + ASHRAE 90.1-2004_Sec 5.5-3ab_Interior Wall_Int-Wall, !- Construction Name + ZN_1_FLR_1_SEC_3, !- Zone Name + Surface, !- Outside Boundary Condition + ZN_1_FLR_1_SEC_4_Wall_3, !- Outside Boundary Condition Object + NoSun, !- Sun Exposure + NoWind, !- Wind Exposure + 0.0000, !- View Factor to Ground + 4, !- Number of Vertices + -4.570,4.570,5.009, !- X,Y,Z ==> Vertex 1 {m} + -4.570,4.570,0.000, !- X,Y,Z ==> Vertex 2 {m} + 0.000,0.000,0.000, !- X,Y,Z ==> Vertex 3 {m} + 0.000,0.000,5.009; !- X,Y,Z ==> Vertex 4 {m} + + BuildingSurface:Detailed, + ZN_1_FLR_1_SEC_3_Floor, !- Name + floor, !- Surface Type + ASHRAE 90.1-2004_Sec 5.5-3ab_Unheated_Ext-slab, !- Construction Name + ZN_1_FLR_1_SEC_3, !- Zone Name + Ground, !- Outside Boundary Condition + , !- Outside Boundary Condition Object + NoSun, !- Sun Exposure + NoWind, !- Wind Exposure + 0.0000, !- View Factor to Ground + 4, !- Number of Vertices + -4.570,4.570,0.000, !- X,Y,Z ==> Vertex 1 {m} + 17.186,4.570,0.000, !- X,Y,Z ==> Vertex 2 {m} + 12.616,0.000,0.000, !- X,Y,Z ==> Vertex 3 {m} + 0.000,0.000,0.000; !- X,Y,Z ==> Vertex 4 {m} + + BuildingSurface:Detailed, + ZN_1_FLR_1_SEC_3_Ceiling,!- Name + ceiling, !- Surface Type + ASHRAE 90.1-2004_Sec 5.5-3ab_IEAD_Roof, !- Construction Name + ZN_1_FLR_1_SEC_3, !- Zone Name + Outdoors, !- Outside Boundary Condition + , !- Outside Boundary Condition Object + SunExposed, !- Sun Exposure + WindExposed, !- Wind Exposure + 0.0000, !- View Factor to Ground + 4, !- Number of Vertices + 0.000,0.000,5.009, !- X,Y,Z ==> Vertex 1 {m} + 12.616,0.000,5.009, !- X,Y,Z ==> Vertex 2 {m} + 17.186,4.570,5.009, !- X,Y,Z ==> Vertex 3 {m} + -4.570,4.570,5.009; !- X,Y,Z ==> Vertex 4 {m} + + InternalMass, + ZN_1_FLR_1_SEC_3_InternalMass_1, !- Name + InteriorFurnishings, !- Construction Name + ZN_1_FLR_1_SEC_3, !- Zone or ZoneList Name + 157.0784; !- Surface Area {m2} + + ZoneInfiltration:DesignFlowRate, + ZN_1_FLR_1_SEC_3_Infiltration, !- Name + ZN_1_FLR_1_SEC_3, !- Zone or ZoneList Name + INFIL_SCH, !- Schedule Name + flow/zone, !- Design Flow Rate Calculation Method + 0.0542, !- Design Flow Rate {m3/s} + , !- Flow per Zone Floor Area {m3/s-m2} + , !- Flow per Exterior Surface Area {m3/s-m2} + , !- Air Changes per Hour {1/hr} + 1.0000, !- Constant Term Coefficient + 0.0000, !- Temperature Term Coefficient + 0.0000, !- Velocity Term Coefficient + 0.0000; !- Velocity Squared Term Coefficient + + People, + ZN_1_FLR_1_SEC_3, !- Name + ZN_1_FLR_1_SEC_3, !- Zone or ZoneList Name + BLDG_OCC_SCH, !- Number of People Schedule Name + people, !- Number of People Calculation Method + 0.6039, !- Number of People + , !- People per Zone Floor Area {person/m2} + , !- Zone Floor Area per Person {m2/person} + 0.3000, !- Fraction Radiant + , !- Sensible Heat Fraction + ACTIVITY_SCH, !- Activity Level Schedule Name + 3.82E-8, !- Carbon Dioxide Generation Rate {m3/s-W} + , !- Enable ASHRAE 55 Comfort Warnings + ZoneAveraged, !- Mean Radiant Temperature Calculation Type + , !- Surface Name/Angle Factor List Name + WORK_EFF_SCH, !- Work Efficiency Schedule Name + ClothingInsulationSchedule, !- Clothing Insulation Calculation Method + , !- Clothing Insulation Calculation Method Schedule Name + CLOTHING_SCH, !- Clothing Insulation Schedule Name + AIR_VELO_SCH, !- Air Velocity Schedule Name + FANGER; !- Thermal Comfort Model 1 Type + + Lights, + ZN_1_FLR_1_SEC_3_Lights, !- Name + ZN_1_FLR_1_SEC_3, !- Zone or ZoneList Name + BLDG_LIGHT_SCH, !- Schedule Name + LightingLevel, !- Design Level Calculation Method + 1178.0879, !- Lighting Level {W} + , !- Watts per Zone Floor Area {W/m2} + , !- Watts per Person {W/person} + 0.0000, !- Return Air Fraction + 0.2000, !- Fraction Radiant + 0.2000, !- Fraction Visible + 1.0000, !- Fraction Replaceable + General Lights; !- End-Use Subcategory + + ComponentCost:LineItem, + LIGHTING EQUIP:ZN_1_FLR_1_SEC_3, !- Name + , !- Type + LIGHTS, !- Line Item Type + ZN_1_FLR_1_SEC_3, !- Item Name + , !- Object End-Use Key + , !- Cost per Each {$} + , !- Cost per Area {$/m2} + 1.0000, !- Cost per Unit of Output Capacity {$/kW} + , !- Cost per Unit of Output Capacity per COP {$/kW} + , !- Cost per Volume {$/m3} + , !- Cost per Volume Rate {$/(m3/s)} + , !- Cost per Energy per Temperature Difference {$/(W/K)} + ; !- Quantity {dimensionless} + + ElectricEquipment, + ZN_1_FLR_1_SEC_3_MiscPlug_Equip, !- Name + ZN_1_FLR_1_SEC_3, !- Zone or ZoneList Name + BLDG_EQUIP_SCH, !- Schedule Name + EquipmentLevel, !- Design Level Calculation Method + 465.9534, !- Design Level {W} + , !- Watts per Zone Floor Area {W/m2} + , !- Watts per Person {W/person} + 0.0000, !- Fraction Latent + 0.5000, !- Fraction Radiant + 0.0000, !- Fraction Lost + GeneralEquipment; !- End-Use Subcategory + + GasEquipment, + ZN_1_FLR_1_SEC_3_MiscGas_Equip, !- Name + ZN_1_FLR_1_SEC_3, !- Zone or ZoneList Name + BLDG_EQUIP_SCH, !- Schedule Name + EquipmentLevel, !- Design Level Calculation Method + 184.1006, !- Design Level {W} + , !- Power per Zone Floor Area {W/m2} + , !- Power per Person {W/person} + 0.0000, !- Fraction Latent + 0.2000, !- Fraction Radiant + 0.0000, !- Fraction Lost + 0, !- Carbon Dioxide Generation Rate {m3/s-W} + GeneralEquipment; !- End-Use Subcategory + +!***** Space Conditioning For Zone: ZN_1_FLR_1_SEC_3 ***** + + Sizing:Zone, + ZN_1_FLR_1_SEC_3, !- Zone or ZoneList Name + SupplyAirTemperature, !- Zone Cooling Design Supply Air Temperature Input Method + 14.0, !- Zone Cooling Design Supply Air Temperature {C} + , !- Zone Cooling Design Supply Air Temperature Difference {deltaC} + SupplyAirTemperature, !- Zone Heating Design Supply Air Temperature Input Method + 50.0, !- Zone Heating Design Supply Air Temperature {C} + , !- Zone Heating Design Supply Air Temperature Difference {deltaC} + 0.0085, !- Zone Cooling Design Supply Air Humidity Ratio {kgWater/kgDryAir} + 0.008, !- Zone Heating Design Supply Air Humidity Ratio {kgWater/kgDryAir} + SZ DSOA ZN_1_FLR_1_SEC_3,!- Design Specification Outdoor Air Object Name + 0.0, !- Zone Heating Sizing Factor + 0.0, !- Zone Cooling Sizing Factor + DesignDay, !- Cooling Design Air Flow Method + 0.0, !- Cooling Design Air Flow Rate {m3/s} + , !- Cooling Minimum Air Flow per Zone Floor Area {m3/s-m2} + 0.0, !- Cooling Minimum Air Flow {m3/s} + 0.0, !- Cooling Minimum Air Flow Fraction + DesignDay, !- Heating Design Air Flow Method + 0.0, !- Heating Design Air Flow Rate {m3/s} + , !- Heating Maximum Air Flow per Zone Floor Area {m3/s-m2} + , !- Heating Maximum Air Flow {m3/s} + , !- Heating Maximum Air Flow Fraction + , !- Design Specification Zone Air Distribution Object Name + No, !- Account for Dedicated Outdoor Air System + NeutralSupplyAir, !- Dedicated Outdoor Air System Control Strategy + autosize, !- Dedicated Outdoor Air Low Setpoint Temperature for Design {C} + autosize; !- Dedicated Outdoor Air High Setpoint Temperature for Design {C} + + DesignSpecification:OutdoorAir, + SZ DSOA ZN_1_FLR_1_SEC_3,!- Name + FLOW/ZONE, !- Outdoor Air Method + , !- Outdoor Air Flow per Person {m3/s-person} + 0.0, !- Outdoor Air Flow per Zone Floor Area {m3/s-m2} + 0.073704617803385; !- Outdoor Air Flow per Zone {m3/s} + + ZoneControl:Thermostat, + ZN_1_FLR_1_SEC_3 Thermostat, !- Name + ZN_1_FLR_1_SEC_3, !- Zone or ZoneList Name + Dual Zone Control Type Sched, !- Control Type Schedule Name + ThermostatSetpoint:DualSetpoint, !- Control 1 Object Type + ZN_1_FLR_1_SEC_3 DualSPSched; !- Control 1 Name + + ThermostatSetpoint:DualSetpoint, + ZN_1_FLR_1_SEC_3 DualSPSched, !- Name + HtgSetP_Sch, !- Heating Setpoint Temperature Schedule Name + ClgSetP_Sch; !- Cooling Setpoint Temperature Schedule Name + + ZoneHVAC:EquipmentConnections, + ZN_1_FLR_1_SEC_3, !- Zone Name + ZN_1_FLR_1_SEC_3 Equipment, !- Zone Conditioning Equipment List Name + ZN_1_FLR_1_SEC_3 Inlet Nodes, !- Zone Air Inlet Node or NodeList Name + , !- Zone Air Exhaust Node or NodeList Name + ZN_1_FLR_1_SEC_3 Air Node, !- Zone Air Node Name + ZN_1_FLR_1_SEC_3 Return Air Node; !- Zone Return Air Node or NodeList Name + + NodeList, + ZN_1_FLR_1_SEC_3 Inlet Nodes, !- Name + ZN_1_FLR_1_SEC_3 Direct Air Inlet Node; !- Node 1 Name + + ZoneHVAC:EquipmentList, + ZN_1_FLR_1_SEC_3 Equipment, !- Name + SequentialLoad, !- Load Distribution Scheme + ZoneHVAC:AirDistributionUnit, !- Zone Equipment 1 Object Type + ZN_1_FLR_1_SEC_3 Direct Air ADU, !- Zone Equipment 1 Name + 1, !- Zone Equipment 1 Cooling Sequence + 1, !- Zone Equipment 1 Heating or No-Load Sequence + , !- Zone Equipment 1 Sequential Cooling Fraction Schedule Name + ; !- Zone Equipment 1 Sequential Heating Fraction Schedule Name + + AirTerminal:SingleDuct:ConstantVolume:NoReheat, + ZN_1_FLR_1_SEC_3 Direct Air, !- Name + ALWAYS_ON, !- Availability Schedule Name + ZN_1_FLR_1_SEC_3 Direct Air Inlet Node ATInlet, !- Air Inlet Node Name + ZN_1_FLR_1_SEC_3 Direct Air Inlet Node, !- Air Outlet Node Name + AUTOSIZE, !- Maximum Air Flow Rate {m3/s} + , !- Design Specification Outdoor Air Object Name + ; !- Per Person Ventilation Rate Mode + + ZoneHVAC:AirDistributionUnit, + ZN_1_FLR_1_SEC_3 Direct Air ADU, !- Name + ZN_1_FLR_1_SEC_3 Direct Air Inlet Node, !- Air Distribution Unit Outlet Node Name + AirTerminal:SingleDuct:ConstantVolume:NoReheat, !- Air Terminal Object Type + ZN_1_FLR_1_SEC_3 Direct Air, !- Air Terminal Name + , !- Nominal Upstream Leakage Fraction + , !- Constant Downstream Leakage Fraction + ; !- Design Specification Air Terminal Sizing Object Name + + SetpointManager:SingleZone:Reheat, + SupAirTemp MngrZN_1_FLR_1_SEC_3, !- Name + Temperature, !- Control Variable + 13.0, !- Minimum Supply Air Temperature {C} + 40.0, !- Maximum Supply Air Temperature {C} + ZN_1_FLR_1_SEC_3, !- Control Zone Name + ZN_1_FLR_1_SEC_3 Air Node, !- Zone Node Name + ZN_1_FLR_1_SEC_3 Direct Air Inlet Node, !- Zone Inlet Node Name + ZN_1_FLR_1_SEC_3:Sys Supply Equipment Outlet Node; !- Setpoint Node or NodeList Name + +!***** Process Loads For Zone: ZN_1_FLR_1_SEC_3 ***** + + WaterUse:Connections, + ZN_1_FLR_1_SEC_3SHW_DEFAULT, !- Name + ZN_1_FLR_1_SEC_3SHW_DEFAULT Water Inlet Node, !- Inlet Node Name + ZN_1_FLR_1_SEC_3SHW_DEFAULT Water Outlet Node, !- Outlet Node Name + , !- Supply Water Storage Tank Name + , !- Reclamation Water Storage Tank Name + , !- Hot Water Supply Temperature Schedule Name + , !- Cold Water Supply Temperature Schedule Name + , !- Drain Water Heat Exchanger Type + , !- Drain Water Heat Exchanger Destination + , !- Drain Water Heat Exchanger U-Factor Times Area {W/K} + ZN_1_FLR_1_SEC_3SHW_DEFAULT; !- Water Use Equipment 1 Name + + WaterUse:Equipment, + ZN_1_FLR_1_SEC_3SHW_DEFAULT, !- Name + SHW_DEFAULT, !- End-Use Subcategory + 2.21418604788511E-6, !- Peak Flow Rate {m3/s} + HOURS_OF_OPERATION, !- Flow Rate Fraction Schedule Name + ZN_1_FLR_1_SEC_3SHW_DEFAULT Temp Sched, !- Target Temperature Schedule Name + ZN_1_FLR_1_SEC_3SHW_DEFAULTHot Supply Temp Sched, !- Hot Water Supply Temperature Schedule Name + , !- Cold Water Supply Temperature Schedule Name + ZN_1_FLR_1_SEC_3, !- Zone Name + ZN_1_FLR_1_SEC_3SHW_DEFAULT Sensible fract sched, !- Sensible Fraction Schedule Name + ZN_1_FLR_1_SEC_3SHW_DEFAULT Latent fract sched; !- Latent Fraction Schedule Name + + Schedule:Compact, + ZN_1_FLR_1_SEC_3SHW_DEFAULT Latent fract sched, !- Name + Fraction, !- Schedule Type Limits Name + Through: 12/31, !- Field 1 + For: AllDays, !- Field 2 + Until: 24:00,0.05; !- Field 3 + + Schedule:Compact, + ZN_1_FLR_1_SEC_3SHW_DEFAULT Sensible fract sched, !- Name + Fraction, !- Schedule Type Limits Name + Through: 12/31, !- Field 1 + For: AllDays, !- Field 2 + Until: 24:00,0.2; !- Field 3 + + Schedule:Compact, + ZN_1_FLR_1_SEC_3SHW_DEFAULT Temp Sched, !- Name + Temperature, !- Schedule Type Limits Name + Through: 12/31, !- Field 1 + For: AllDays, !- Field 2 + Until: 24:00,40; !- Field 3 + + Schedule:Compact, + ZN_1_FLR_1_SEC_3SHW_DEFAULTHot Supply Temp Sched, !- Name + Temperature, !- Schedule Type Limits Name + Through: 12/31, !- Field 1 + For: AllDays, !- Field 2 + Until: 24:00,55; !- Field 3 + + Zone, + ZN_1_FLR_1_SEC_4, !- Name + 0.0000, !- Direction of Relative North {deg} + 0.0000, !- X Origin {m} + 0.0000, !- Y Origin {m} + 0.0000, !- Z Origin {m} + 1, !- Type + 1.0000, !- Multiplier + 5.0088, !- Ceiling Height {m} + 305.9154, !- Volume {m3} + autocalculate, !- Floor Area {m2} + , !- Zone Inside Convection Algorithm + , !- Zone Outside Convection Algorithm + YES; !- Part of Total Floor Area + + BuildingSurface:Detailed, + ZN_1_FLR_1_SEC_4_Wall_1, !- Name + wall, !- Surface Type + ASHRAE 90.1-2004_Sec 5.5-3ab_Interior Wall_Int-Wall, !- Construction Name + ZN_1_FLR_1_SEC_4, !- Zone Name + Surface, !- Outside Boundary Condition + ZN_1_FLR_1_SEC_1_Wall_4, !- Outside Boundary Condition Object + NoSun, !- Sun Exposure + NoWind, !- Wind Exposure + 0.0000, !- View Factor to Ground + 4, !- Number of Vertices + 0.000,0.000,5.009, !- X,Y,Z ==> Vertex 1 {m} + 0.000,0.000,0.000, !- X,Y,Z ==> Vertex 2 {m} + 4.570,4.570,0.000, !- X,Y,Z ==> Vertex 3 {m} + 4.570,4.570,5.009; !- X,Y,Z ==> Vertex 4 {m} + + BuildingSurface:Detailed, + ZN_1_FLR_1_SEC_4_Wall_2, !- Name + wall, !- Surface Type + ASHRAE 90.1-2004_Sec 5.5-3ab_Interior Wall_Int-Wall, !- Construction Name + ZN_1_FLR_1_SEC_4, !- Zone Name + Surface, !- Outside Boundary Condition + ZN_1_FLR_1_SEC_5_Wall_4, !- Outside Boundary Condition Object + NoSun, !- Sun Exposure + NoWind, !- Wind Exposure + 0.0000, !- View Factor to Ground + 4, !- Number of Vertices + 4.570,4.570,5.009, !- X,Y,Z ==> Vertex 1 {m} + 4.570,4.570,0.000, !- X,Y,Z ==> Vertex 2 {m} + 4.570,13.365,0.000, !- X,Y,Z ==> Vertex 3 {m} + 4.570,13.365,5.009; !- X,Y,Z ==> Vertex 4 {m} + + BuildingSurface:Detailed, + ZN_1_FLR_1_SEC_4_Wall_3, !- Name + wall, !- Surface Type + ASHRAE 90.1-2004_Sec 5.5-3ab_Interior Wall_Int-Wall, !- Construction Name + ZN_1_FLR_1_SEC_4, !- Zone Name + Surface, !- Outside Boundary Condition + ZN_1_FLR_1_SEC_3_Wall_4, !- Outside Boundary Condition Object + NoSun, !- Sun Exposure + NoWind, !- Wind Exposure + 0.0000, !- View Factor to Ground + 4, !- Number of Vertices + 4.570,13.365,5.009, !- X,Y,Z ==> Vertex 1 {m} + 4.570,13.365,0.000, !- X,Y,Z ==> Vertex 2 {m} + 0.000,17.935,0.000, !- X,Y,Z ==> Vertex 3 {m} + 0.000,17.935,5.009; !- X,Y,Z ==> Vertex 4 {m} + + BuildingSurface:Detailed, + ZN_1_FLR_1_SEC_4_Wall_4, !- Name + wall, !- Surface Type + ASHRAE 90.1-2004_Sec 5.5-3ab_Steel-Framed_Ext-wall, !- Construction Name + ZN_1_FLR_1_SEC_4, !- Zone Name + Outdoors, !- Outside Boundary Condition + , !- Outside Boundary Condition Object + SunExposed, !- Sun Exposure + WindExposed, !- Wind Exposure + 0.5000, !- View Factor to Ground + 4, !- Number of Vertices + 0.000,17.935,5.009, !- X,Y,Z ==> Vertex 1 {m} + 0.000,17.935,0.000, !- X,Y,Z ==> Vertex 2 {m} + 0.000,0.000,0.000, !- X,Y,Z ==> Vertex 3 {m} + 0.000,0.000,5.009; !- X,Y,Z ==> Vertex 4 {m} + + FenestrationSurface:Detailed, + ZN_1_FLR_1_SEC_4_Wall_4_window_1, !- Name + Window, !- Surface Type + ASHRAE 90.1-2004_Sec 5.5-3ab_0_0.1_fixed_east_window, !- Construction Name + ZN_1_FLR_1_SEC_4_Wall_4, !- Building Surface Name + , !- Outside Boundary Condition Object + 0.5000, !- View Factor to Ground + , !- Frame and Divider Name + 1, !- Multiplier + 4, !- Number of Vertices + 0.000,17.885,1.363, !- X,Y,Z ==> Vertex 1 {m} + 0.000,17.885,1.000, !- X,Y,Z ==> Vertex 2 {m} + 0.000,0.050,1.000, !- X,Y,Z ==> Vertex 3 {m} + 0.000,0.050,1.363; !- X,Y,Z ==> Vertex 4 {m} + + BuildingSurface:Detailed, + ZN_1_FLR_1_SEC_4_Floor, !- Name + floor, !- Surface Type + ASHRAE 90.1-2004_Sec 5.5-3ab_Unheated_Ext-slab, !- Construction Name + ZN_1_FLR_1_SEC_4, !- Zone Name + Ground, !- Outside Boundary Condition + , !- Outside Boundary Condition Object + NoSun, !- Sun Exposure + NoWind, !- Wind Exposure + 0.0000, !- View Factor to Ground + 4, !- Number of Vertices + 0.000,17.935,0.000, !- X,Y,Z ==> Vertex 1 {m} + 4.570,13.365,0.000, !- X,Y,Z ==> Vertex 2 {m} + 4.570,4.570,0.000, !- X,Y,Z ==> Vertex 3 {m} + 0.000,0.000,0.000; !- X,Y,Z ==> Vertex 4 {m} + + BuildingSurface:Detailed, + ZN_1_FLR_1_SEC_4_Ceiling,!- Name + ceiling, !- Surface Type + ASHRAE 90.1-2004_Sec 5.5-3ab_IEAD_Roof, !- Construction Name + ZN_1_FLR_1_SEC_4, !- Zone Name + Outdoors, !- Outside Boundary Condition + , !- Outside Boundary Condition Object + SunExposed, !- Sun Exposure + WindExposed, !- Wind Exposure + 0.0000, !- View Factor to Ground + 4, !- Number of Vertices + 0.000,0.000,5.009, !- X,Y,Z ==> Vertex 1 {m} + 4.570,4.570,5.009, !- X,Y,Z ==> Vertex 2 {m} + 4.570,13.365,5.009, !- X,Y,Z ==> Vertex 3 {m} + 0.000,17.935,5.009; !- X,Y,Z ==> Vertex 4 {m} + + InternalMass, + ZN_1_FLR_1_SEC_4_InternalMass_1, !- Name + InteriorFurnishings, !- Construction Name + ZN_1_FLR_1_SEC_4, !- Zone or ZoneList Name + 122.1516; !- Surface Area {m2} + + ZoneInfiltration:DesignFlowRate, + ZN_1_FLR_1_SEC_4_Infiltration, !- Name + ZN_1_FLR_1_SEC_4, !- Zone or ZoneList Name + INFIL_SCH, !- Schedule Name + flow/zone, !- Design Flow Rate Calculation Method + 0.0435, !- Design Flow Rate {m3/s} + , !- Flow per Zone Floor Area {m3/s-m2} + , !- Flow per Exterior Surface Area {m3/s-m2} + , !- Air Changes per Hour {1/hr} + 1.0000, !- Constant Term Coefficient + 0.0000, !- Temperature Term Coefficient + 0.0000, !- Velocity Term Coefficient + 0.0000; !- Velocity Squared Term Coefficient + + People, + ZN_1_FLR_1_SEC_4, !- Name + ZN_1_FLR_1_SEC_4, !- Zone or ZoneList Name + BLDG_OCC_SCH, !- Number of People Schedule Name + people, !- Number of People Calculation Method + 0.4696, !- Number of People + , !- People per Zone Floor Area {person/m2} + , !- Zone Floor Area per Person {m2/person} + 0.3000, !- Fraction Radiant + , !- Sensible Heat Fraction + ACTIVITY_SCH, !- Activity Level Schedule Name + 3.82E-8, !- Carbon Dioxide Generation Rate {m3/s-W} + , !- Enable ASHRAE 55 Comfort Warnings + ZoneAveraged, !- Mean Radiant Temperature Calculation Type + , !- Surface Name/Angle Factor List Name + WORK_EFF_SCH, !- Work Efficiency Schedule Name + ClothingInsulationSchedule, !- Clothing Insulation Calculation Method + , !- Clothing Insulation Calculation Method Schedule Name + CLOTHING_SCH, !- Clothing Insulation Schedule Name + AIR_VELO_SCH, !- Air Velocity Schedule Name + FANGER; !- Thermal Comfort Model 1 Type + + Lights, + ZN_1_FLR_1_SEC_4_Lights, !- Name + ZN_1_FLR_1_SEC_4, !- Zone or ZoneList Name + BLDG_LIGHT_SCH, !- Schedule Name + LightingLevel, !- Design Level Calculation Method + 916.1373, !- Lighting Level {W} + , !- Watts per Zone Floor Area {W/m2} + , !- Watts per Person {W/person} + 0.0000, !- Return Air Fraction + 0.2000, !- Fraction Radiant + 0.2000, !- Fraction Visible + 1.0000, !- Fraction Replaceable + General Lights; !- End-Use Subcategory + + ComponentCost:LineItem, + LIGHTING EQUIP:ZN_1_FLR_1_SEC_4, !- Name + , !- Type + LIGHTS, !- Line Item Type + ZN_1_FLR_1_SEC_4, !- Item Name + , !- Object End-Use Key + , !- Cost per Each {$} + , !- Cost per Area {$/m2} + 1.0000, !- Cost per Unit of Output Capacity {$/kW} + , !- Cost per Unit of Output Capacity per COP {$/kW} + , !- Cost per Volume {$/m3} + , !- Cost per Volume Rate {$/(m3/s)} + , !- Cost per Energy per Temperature Difference {$/(W/K)} + ; !- Quantity {dimensionless} + + ElectricEquipment, + ZN_1_FLR_1_SEC_4_MiscPlug_Equip, !- Name + ZN_1_FLR_1_SEC_4, !- Zone or ZoneList Name + BLDG_EQUIP_SCH, !- Schedule Name + EquipmentLevel, !- Design Level Calculation Method + 362.3476, !- Design Level {W} + , !- Watts per Zone Floor Area {W/m2} + , !- Watts per Person {W/person} + 0.0000, !- Fraction Latent + 0.5000, !- Fraction Radiant + 0.0000, !- Fraction Lost + GeneralEquipment; !- End-Use Subcategory + + GasEquipment, + ZN_1_FLR_1_SEC_4_MiscGas_Equip, !- Name + ZN_1_FLR_1_SEC_4, !- Zone or ZoneList Name + BLDG_EQUIP_SCH, !- Schedule Name + EquipmentLevel, !- Design Level Calculation Method + 143.1654, !- Design Level {W} + , !- Power per Zone Floor Area {W/m2} + , !- Power per Person {W/person} + 0.0000, !- Fraction Latent + 0.2000, !- Fraction Radiant + 0.0000, !- Fraction Lost + 0, !- Carbon Dioxide Generation Rate {m3/s-W} + GeneralEquipment; !- End-Use Subcategory + +!***** Space Conditioning For Zone: ZN_1_FLR_1_SEC_4 ***** + + Sizing:Zone, + ZN_1_FLR_1_SEC_4, !- Zone or ZoneList Name + SupplyAirTemperature, !- Zone Cooling Design Supply Air Temperature Input Method + 14.0, !- Zone Cooling Design Supply Air Temperature {C} + , !- Zone Cooling Design Supply Air Temperature Difference {deltaC} + SupplyAirTemperature, !- Zone Heating Design Supply Air Temperature Input Method + 50.0, !- Zone Heating Design Supply Air Temperature {C} + , !- Zone Heating Design Supply Air Temperature Difference {deltaC} + 0.0085, !- Zone Cooling Design Supply Air Humidity Ratio {kgWater/kgDryAir} + 0.008, !- Zone Heating Design Supply Air Humidity Ratio {kgWater/kgDryAir} + SZ DSOA ZN_1_FLR_1_SEC_4,!- Design Specification Outdoor Air Object Name + 0.0, !- Zone Heating Sizing Factor + 0.0, !- Zone Cooling Sizing Factor + DesignDay, !- Cooling Design Air Flow Method + 0.0, !- Cooling Design Air Flow Rate {m3/s} + , !- Cooling Minimum Air Flow per Zone Floor Area {m3/s-m2} + 0.0, !- Cooling Minimum Air Flow {m3/s} + 0.0, !- Cooling Minimum Air Flow Fraction + DesignDay, !- Heating Design Air Flow Method + 0.0, !- Heating Design Air Flow Rate {m3/s} + , !- Heating Maximum Air Flow per Zone Floor Area {m3/s-m2} + , !- Heating Maximum Air Flow {m3/s} + , !- Heating Maximum Air Flow Fraction + , !- Design Specification Zone Air Distribution Object Name + No, !- Account for Dedicated Outdoor Air System + NeutralSupplyAir, !- Dedicated Outdoor Air System Control Strategy + autosize, !- Dedicated Outdoor Air Low Setpoint Temperature for Design {C} + autosize; !- Dedicated Outdoor Air High Setpoint Temperature for Design {C} + + DesignSpecification:OutdoorAir, + SZ DSOA ZN_1_FLR_1_SEC_4,!- Name + FLOW/ZONE, !- Outdoor Air Method + , !- Outdoor Air Flow per Person {m3/s-person} + 0.0, !- Outdoor Air Flow per Zone Floor Area {m3/s-m2} + 0.057316225695446; !- Outdoor Air Flow per Zone {m3/s} + + ZoneControl:Thermostat, + ZN_1_FLR_1_SEC_4 Thermostat, !- Name + ZN_1_FLR_1_SEC_4, !- Zone or ZoneList Name + Dual Zone Control Type Sched, !- Control Type Schedule Name + ThermostatSetpoint:DualSetpoint, !- Control 1 Object Type + ZN_1_FLR_1_SEC_4 DualSPSched; !- Control 1 Name + + ThermostatSetpoint:DualSetpoint, + ZN_1_FLR_1_SEC_4 DualSPSched, !- Name + HtgSetP_Sch, !- Heating Setpoint Temperature Schedule Name + ClgSetP_Sch; !- Cooling Setpoint Temperature Schedule Name + + ZoneHVAC:EquipmentConnections, + ZN_1_FLR_1_SEC_4, !- Zone Name + ZN_1_FLR_1_SEC_4 Equipment, !- Zone Conditioning Equipment List Name + ZN_1_FLR_1_SEC_4 Inlet Nodes, !- Zone Air Inlet Node or NodeList Name + , !- Zone Air Exhaust Node or NodeList Name + ZN_1_FLR_1_SEC_4 Air Node, !- Zone Air Node Name + ZN_1_FLR_1_SEC_4 Return Air Node; !- Zone Return Air Node or NodeList Name + + NodeList, + ZN_1_FLR_1_SEC_4 Inlet Nodes, !- Name + ZN_1_FLR_1_SEC_4 Direct Air Inlet Node; !- Node 1 Name + + ZoneHVAC:EquipmentList, + ZN_1_FLR_1_SEC_4 Equipment, !- Name + SequentialLoad, !- Load Distribution Scheme + ZoneHVAC:AirDistributionUnit, !- Zone Equipment 1 Object Type + ZN_1_FLR_1_SEC_4 Direct Air ADU, !- Zone Equipment 1 Name + 1, !- Zone Equipment 1 Cooling Sequence + 1, !- Zone Equipment 1 Heating or No-Load Sequence + , !- Zone Equipment 1 Sequential Cooling Fraction Schedule Name + ; !- Zone Equipment 1 Sequential Heating Fraction Schedule Name + + AirTerminal:SingleDuct:ConstantVolume:NoReheat, + ZN_1_FLR_1_SEC_4 Direct Air, !- Name + ALWAYS_ON, !- Availability Schedule Name + ZN_1_FLR_1_SEC_4 Direct Air Inlet Node ATInlet, !- Air Inlet Node Name + ZN_1_FLR_1_SEC_4 Direct Air Inlet Node, !- Air Outlet Node Name + AUTOSIZE, !- Maximum Air Flow Rate {m3/s} + , !- Design Specification Outdoor Air Object Name + ; !- Per Person Ventilation Rate Mode + + ZoneHVAC:AirDistributionUnit, + ZN_1_FLR_1_SEC_4 Direct Air ADU, !- Name + ZN_1_FLR_1_SEC_4 Direct Air Inlet Node, !- Air Distribution Unit Outlet Node Name + AirTerminal:SingleDuct:ConstantVolume:NoReheat, !- Air Terminal Object Type + ZN_1_FLR_1_SEC_4 Direct Air, !- Air Terminal Name + , !- Nominal Upstream Leakage Fraction + , !- Constant Downstream Leakage Fraction + ; !- Design Specification Air Terminal Sizing Object Name + + SetpointManager:SingleZone:Reheat, + SupAirTemp MngrZN_1_FLR_1_SEC_4, !- Name + Temperature, !- Control Variable + 13.0, !- Minimum Supply Air Temperature {C} + 40.0, !- Maximum Supply Air Temperature {C} + ZN_1_FLR_1_SEC_4, !- Control Zone Name + ZN_1_FLR_1_SEC_4 Air Node, !- Zone Node Name + ZN_1_FLR_1_SEC_4 Direct Air Inlet Node, !- Zone Inlet Node Name + ZN_1_FLR_1_SEC_4:Sys Supply Equipment Outlet Node; !- Setpoint Node or NodeList Name + +!***** Process Loads For Zone: ZN_1_FLR_1_SEC_4 ***** + + WaterUse:Connections, + ZN_1_FLR_1_SEC_4SHW_DEFAULT, !- Name + ZN_1_FLR_1_SEC_4SHW_DEFAULT Water Inlet Node, !- Inlet Node Name + ZN_1_FLR_1_SEC_4SHW_DEFAULT Water Outlet Node, !- Outlet Node Name + , !- Supply Water Storage Tank Name + , !- Reclamation Water Storage Tank Name + , !- Hot Water Supply Temperature Schedule Name + , !- Cold Water Supply Temperature Schedule Name + , !- Drain Water Heat Exchanger Type + , !- Drain Water Heat Exchanger Destination + , !- Drain Water Heat Exchanger U-Factor Times Area {W/K} + ZN_1_FLR_1_SEC_4SHW_DEFAULT; !- Water Use Equipment 1 Name + + WaterUse:Equipment, + ZN_1_FLR_1_SEC_4SHW_DEFAULT, !- Name + SHW_DEFAULT, !- End-Use Subcategory + 1.72185666291403E-6, !- Peak Flow Rate {m3/s} + HOURS_OF_OPERATION, !- Flow Rate Fraction Schedule Name + ZN_1_FLR_1_SEC_4SHW_DEFAULT Temp Sched, !- Target Temperature Schedule Name + ZN_1_FLR_1_SEC_4SHW_DEFAULTHot Supply Temp Sched, !- Hot Water Supply Temperature Schedule Name + , !- Cold Water Supply Temperature Schedule Name + ZN_1_FLR_1_SEC_4, !- Zone Name + ZN_1_FLR_1_SEC_4SHW_DEFAULT Sensible fract sched, !- Sensible Fraction Schedule Name + ZN_1_FLR_1_SEC_4SHW_DEFAULT Latent fract sched; !- Latent Fraction Schedule Name + + Schedule:Compact, + ZN_1_FLR_1_SEC_4SHW_DEFAULT Latent fract sched, !- Name + Fraction, !- Schedule Type Limits Name + Through: 12/31, !- Field 1 + For: AllDays, !- Field 2 + Until: 24:00,0.05; !- Field 3 + + Schedule:Compact, + ZN_1_FLR_1_SEC_4SHW_DEFAULT Sensible fract sched, !- Name + Fraction, !- Schedule Type Limits Name + Through: 12/31, !- Field 1 + For: AllDays, !- Field 2 + Until: 24:00,0.2; !- Field 3 + + Schedule:Compact, + ZN_1_FLR_1_SEC_4SHW_DEFAULT Temp Sched, !- Name + Temperature, !- Schedule Type Limits Name + Through: 12/31, !- Field 1 + For: AllDays, !- Field 2 + Until: 24:00,40; !- Field 3 + + Schedule:Compact, + ZN_1_FLR_1_SEC_4SHW_DEFAULTHot Supply Temp Sched, !- Name + Temperature, !- Schedule Type Limits Name + Through: 12/31, !- Field 1 + For: AllDays, !- Field 2 + Until: 24:00,55; !- Field 3 + + Zone, + ZN_1_FLR_1_SEC_5, !- Name + 0.0000, !- Direction of Relative North {deg} + 4.5700, !- X Origin {m} + 4.5700, !- Y Origin {m} + 0.0000, !- Z Origin {m} + 1, !- Type + 1.0000, !- Multiplier + 5.0088, !- Ceiling Height {m} + 555.7240, !- Volume {m3} + autocalculate, !- Floor Area {m2} + , !- Zone Inside Convection Algorithm + , !- Zone Outside Convection Algorithm + YES; !- Part of Total Floor Area + + BuildingSurface:Detailed, + ZN_1_FLR_1_SEC_5_Wall_1, !- Name + wall, !- Surface Type + ASHRAE 90.1-2004_Sec 5.5-3ab_Interior Wall_Int-Wall, !- Construction Name + ZN_1_FLR_1_SEC_5, !- Zone Name + Surface, !- Outside Boundary Condition + ZN_1_FLR_1_SEC_1_Wall_3, !- Outside Boundary Condition Object + NoSun, !- Sun Exposure + NoWind, !- Wind Exposure + 0.0000, !- View Factor to Ground + 4, !- Number of Vertices + 0.000,0.000,5.009, !- X,Y,Z ==> Vertex 1 {m} + 0.000,0.000,0.000, !- X,Y,Z ==> Vertex 2 {m} + 12.616,0.000,0.000, !- X,Y,Z ==> Vertex 3 {m} + 12.616,0.000,5.009; !- X,Y,Z ==> Vertex 4 {m} + + BuildingSurface:Detailed, + ZN_1_FLR_1_SEC_5_Wall_2, !- Name + wall, !- Surface Type + ASHRAE 90.1-2004_Sec 5.5-3ab_Interior Wall_Int-Wall, !- Construction Name + ZN_1_FLR_1_SEC_5, !- Zone Name + Surface, !- Outside Boundary Condition + ZN_1_FLR_1_SEC_2_Wall_3, !- Outside Boundary Condition Object + NoSun, !- Sun Exposure + NoWind, !- Wind Exposure + 0.0000, !- View Factor to Ground + 4, !- Number of Vertices + 12.616,0.000,5.009, !- X,Y,Z ==> Vertex 1 {m} + 12.616,0.000,0.000, !- X,Y,Z ==> Vertex 2 {m} + 12.616,8.795,0.000, !- X,Y,Z ==> Vertex 3 {m} + 12.616,8.795,5.009; !- X,Y,Z ==> Vertex 4 {m} + + BuildingSurface:Detailed, + ZN_1_FLR_1_SEC_5_Wall_3, !- Name + wall, !- Surface Type + ASHRAE 90.1-2004_Sec 5.5-3ab_Interior Wall_Int-Wall, !- Construction Name + ZN_1_FLR_1_SEC_5, !- Zone Name + Surface, !- Outside Boundary Condition + ZN_1_FLR_1_SEC_3_Wall_1, !- Outside Boundary Condition Object + NoSun, !- Sun Exposure + NoWind, !- Wind Exposure + 0.0000, !- View Factor to Ground + 4, !- Number of Vertices + 12.616,8.795,5.009, !- X,Y,Z ==> Vertex 1 {m} + 12.616,8.795,0.000, !- X,Y,Z ==> Vertex 2 {m} + 0.000,8.795,0.000, !- X,Y,Z ==> Vertex 3 {m} + 0.000,8.795,5.009; !- X,Y,Z ==> Vertex 4 {m} + + BuildingSurface:Detailed, + ZN_1_FLR_1_SEC_5_Wall_4, !- Name + wall, !- Surface Type + ASHRAE 90.1-2004_Sec 5.5-3ab_Interior Wall_Int-Wall, !- Construction Name + ZN_1_FLR_1_SEC_5, !- Zone Name + Surface, !- Outside Boundary Condition + ZN_1_FLR_1_SEC_4_Wall_2, !- Outside Boundary Condition Object + NoSun, !- Sun Exposure + NoWind, !- Wind Exposure + 0.0000, !- View Factor to Ground + 4, !- Number of Vertices + 0.000,8.795,5.009, !- X,Y,Z ==> Vertex 1 {m} + 0.000,8.795,0.000, !- X,Y,Z ==> Vertex 2 {m} + 0.000,0.000,0.000, !- X,Y,Z ==> Vertex 3 {m} + 0.000,0.000,5.009; !- X,Y,Z ==> Vertex 4 {m} + + BuildingSurface:Detailed, + ZN_1_FLR_1_SEC_5_Floor, !- Name + floor, !- Surface Type + ASHRAE 90.1-2004_Sec 5.5-3ab_Unheated_Ext-slab, !- Construction Name + ZN_1_FLR_1_SEC_5, !- Zone Name + Ground, !- Outside Boundary Condition + , !- Outside Boundary Condition Object + NoSun, !- Sun Exposure + NoWind, !- Wind Exposure + 0.0000, !- View Factor to Ground + 4, !- Number of Vertices + 0.000,8.795,0.000, !- X,Y,Z ==> Vertex 1 {m} + 12.616,8.795,0.000, !- X,Y,Z ==> Vertex 2 {m} + 12.616,0.000,0.000, !- X,Y,Z ==> Vertex 3 {m} + 0.000,0.000,0.000; !- X,Y,Z ==> Vertex 4 {m} + + BuildingSurface:Detailed, + ZN_1_FLR_1_SEC_5_Ceiling,!- Name + ceiling, !- Surface Type + ASHRAE 90.1-2004_Sec 5.5-3ab_IEAD_Roof, !- Construction Name + ZN_1_FLR_1_SEC_5, !- Zone Name + Outdoors, !- Outside Boundary Condition + , !- Outside Boundary Condition Object + SunExposed, !- Sun Exposure + WindExposed, !- Wind Exposure + 0.0000, !- View Factor to Ground + 4, !- Number of Vertices + 0.000,0.000,5.009, !- X,Y,Z ==> Vertex 1 {m} + 12.616,0.000,5.009, !- X,Y,Z ==> Vertex 2 {m} + 12.616,8.795,5.009, !- X,Y,Z ==> Vertex 3 {m} + 0.000,8.795,5.009; !- X,Y,Z ==> Vertex 4 {m} + + InternalMass, + ZN_1_FLR_1_SEC_5_InternalMass_1, !- Name + InteriorFurnishings, !- Construction Name + ZN_1_FLR_1_SEC_5, !- Zone or ZoneList Name + 221.8999; !- Surface Area {m2} + + ZoneInfiltration:DesignFlowRate, + ZN_1_FLR_1_SEC_5_Infiltration, !- Name + ZN_1_FLR_1_SEC_5, !- Zone or ZoneList Name + INFIL_SCH, !- Schedule Name + flow/zone, !- Design Flow Rate Calculation Method + 0.0354, !- Design Flow Rate {m3/s} + , !- Flow per Zone Floor Area {m3/s-m2} + , !- Flow per Exterior Surface Area {m3/s-m2} + , !- Air Changes per Hour {1/hr} + 1.0000, !- Constant Term Coefficient + 0.0000, !- Temperature Term Coefficient + 0.0000, !- Velocity Term Coefficient + 0.0000; !- Velocity Squared Term Coefficient + + People, + ZN_1_FLR_1_SEC_5, !- Name + ZN_1_FLR_1_SEC_5, !- Zone or ZoneList Name + BLDG_OCC_SCH, !- Number of People Schedule Name + people, !- Number of People Calculation Method + 0.8531, !- Number of People + , !- People per Zone Floor Area {person/m2} + , !- Zone Floor Area per Person {m2/person} + 0.3000, !- Fraction Radiant + , !- Sensible Heat Fraction + ACTIVITY_SCH, !- Activity Level Schedule Name + 3.82E-8, !- Carbon Dioxide Generation Rate {m3/s-W} + , !- Enable ASHRAE 55 Comfort Warnings + ZoneAveraged, !- Mean Radiant Temperature Calculation Type + , !- Surface Name/Angle Factor List Name + WORK_EFF_SCH, !- Work Efficiency Schedule Name + ClothingInsulationSchedule, !- Clothing Insulation Calculation Method + , !- Clothing Insulation Calculation Method Schedule Name + CLOTHING_SCH, !- Clothing Insulation Schedule Name + AIR_VELO_SCH, !- Air Velocity Schedule Name + FANGER; !- Thermal Comfort Model 1 Type + + Lights, + ZN_1_FLR_1_SEC_5_Lights, !- Name + ZN_1_FLR_1_SEC_5, !- Zone or ZoneList Name + BLDG_LIGHT_SCH, !- Schedule Name + LightingLevel, !- Design Level Calculation Method + 1664.2496, !- Lighting Level {W} + , !- Watts per Zone Floor Area {W/m2} + , !- Watts per Person {W/person} + 0.0000, !- Return Air Fraction + 0.2000, !- Fraction Radiant + 0.2000, !- Fraction Visible + 1.0000, !- Fraction Replaceable + General Lights; !- End-Use Subcategory + + ComponentCost:LineItem, + LIGHTING EQUIP:ZN_1_FLR_1_SEC_5, !- Name + , !- Type + LIGHTS, !- Line Item Type + ZN_1_FLR_1_SEC_5, !- Item Name + , !- Object End-Use Key + , !- Cost per Each {$} + , !- Cost per Area {$/m2} + 1.0000, !- Cost per Unit of Output Capacity {$/kW} + , !- Cost per Unit of Output Capacity per COP {$/kW} + , !- Cost per Volume {$/m3} + , !- Cost per Volume Rate {$/(m3/s)} + , !- Cost per Energy per Temperature Difference {$/(W/K)} + ; !- Quantity {dimensionless} + + ElectricEquipment, + ZN_1_FLR_1_SEC_5_MiscPlug_Equip, !- Name + ZN_1_FLR_1_SEC_5, !- Zone or ZoneList Name + BLDG_EQUIP_SCH, !- Schedule Name + EquipmentLevel, !- Design Level Calculation Method + 658.2385, !- Design Level {W} + , !- Watts per Zone Floor Area {W/m2} + , !- Watts per Person {W/person} + 0.0000, !- Fraction Latent + 0.5000, !- Fraction Radiant + 0.0000, !- Fraction Lost + GeneralEquipment; !- End-Use Subcategory + + GasEquipment, + ZN_1_FLR_1_SEC_5_MiscGas_Equip, !- Name + ZN_1_FLR_1_SEC_5, !- Zone or ZoneList Name + BLDG_EQUIP_SCH, !- Schedule Name + EquipmentLevel, !- Design Level Calculation Method + 260.0734, !- Design Level {W} + , !- Power per Zone Floor Area {W/m2} + , !- Power per Person {W/person} + 0.0000, !- Fraction Latent + 0.2000, !- Fraction Radiant + 0.0000, !- Fraction Lost + 0, !- Carbon Dioxide Generation Rate {m3/s-W} + GeneralEquipment; !- End-Use Subcategory + +!***** Space Conditioning For Zone: ZN_1_FLR_1_SEC_5 ***** + + Sizing:Zone, + ZN_1_FLR_1_SEC_5, !- Zone or ZoneList Name + SupplyAirTemperature, !- Zone Cooling Design Supply Air Temperature Input Method + 14.0, !- Zone Cooling Design Supply Air Temperature {C} + , !- Zone Cooling Design Supply Air Temperature Difference {deltaC} + SupplyAirTemperature, !- Zone Heating Design Supply Air Temperature Input Method + 50.0, !- Zone Heating Design Supply Air Temperature {C} + , !- Zone Heating Design Supply Air Temperature Difference {deltaC} + 0.0085, !- Zone Cooling Design Supply Air Humidity Ratio {kgWater/kgDryAir} + 0.008, !- Zone Heating Design Supply Air Humidity Ratio {kgWater/kgDryAir} + SZ DSOA ZN_1_FLR_1_SEC_5,!- Design Specification Outdoor Air Object Name + 0.0, !- Zone Heating Sizing Factor + 0.0, !- Zone Cooling Sizing Factor + DesignDay, !- Cooling Design Air Flow Method + 0.0, !- Cooling Design Air Flow Rate {m3/s} + , !- Cooling Minimum Air Flow per Zone Floor Area {m3/s-m2} + 0.0, !- Cooling Minimum Air Flow {m3/s} + 0.0, !- Cooling Minimum Air Flow Fraction + DesignDay, !- Heating Design Air Flow Method + 0.0, !- Heating Design Air Flow Rate {m3/s} + , !- Heating Maximum Air Flow per Zone Floor Area {m3/s-m2} + , !- Heating Maximum Air Flow {m3/s} + , !- Heating Maximum Air Flow Fraction + , !- Design Specification Zone Air Distribution Object Name + No, !- Account for Dedicated Outdoor Air System + NeutralSupplyAir, !- Dedicated Outdoor Air System Control Strategy + autosize, !- Dedicated Outdoor Air Low Setpoint Temperature for Design {C} + autosize; !- Dedicated Outdoor Air High Setpoint Temperature for Design {C} + + DesignSpecification:OutdoorAir, + SZ DSOA ZN_1_FLR_1_SEC_5,!- Name + FLOW/ZONE, !- Outdoor Air Method + , !- Outdoor Air Flow per Person {m3/s-person} + 0.0, !- Outdoor Air Flow per Zone Floor Area {m3/s-m2} + 0.104120314886338; !- Outdoor Air Flow per Zone {m3/s} + + ZoneControl:Thermostat, + ZN_1_FLR_1_SEC_5 Thermostat, !- Name + ZN_1_FLR_1_SEC_5, !- Zone or ZoneList Name + Dual Zone Control Type Sched, !- Control Type Schedule Name + ThermostatSetpoint:DualSetpoint, !- Control 1 Object Type + ZN_1_FLR_1_SEC_5 DualSPSched; !- Control 1 Name + + ThermostatSetpoint:DualSetpoint, + ZN_1_FLR_1_SEC_5 DualSPSched, !- Name + HtgSetP_Sch, !- Heating Setpoint Temperature Schedule Name + ClgSetP_Sch; !- Cooling Setpoint Temperature Schedule Name + + ZoneHVAC:EquipmentConnections, + ZN_1_FLR_1_SEC_5, !- Zone Name + ZN_1_FLR_1_SEC_5 Equipment, !- Zone Conditioning Equipment List Name + ZN_1_FLR_1_SEC_5 Inlet Nodes, !- Zone Air Inlet Node or NodeList Name + , !- Zone Air Exhaust Node or NodeList Name + ZN_1_FLR_1_SEC_5 Air Node, !- Zone Air Node Name + ZN_1_FLR_1_SEC_5 Return Air Node; !- Zone Return Air Node or NodeList Name + + NodeList, + ZN_1_FLR_1_SEC_5 Inlet Nodes, !- Name + ZN_1_FLR_1_SEC_5 Direct Air Inlet Node; !- Node 1 Name + + ZoneHVAC:EquipmentList, + ZN_1_FLR_1_SEC_5 Equipment, !- Name + SequentialLoad, !- Load Distribution Scheme + ZoneHVAC:AirDistributionUnit, !- Zone Equipment 1 Object Type + ZN_1_FLR_1_SEC_5 Direct Air ADU, !- Zone Equipment 1 Name + 1, !- Zone Equipment 1 Cooling Sequence + 1, !- Zone Equipment 1 Heating or No-Load Sequence + , !- Zone Equipment 1 Sequential Cooling Fraction Schedule Name + ; !- Zone Equipment 1 Sequential Heating Fraction Schedule Name + + AirTerminal:SingleDuct:ConstantVolume:NoReheat, + ZN_1_FLR_1_SEC_5 Direct Air, !- Name + ALWAYS_ON, !- Availability Schedule Name + ZN_1_FLR_1_SEC_5 Direct Air Inlet Node ATInlet, !- Air Inlet Node Name + ZN_1_FLR_1_SEC_5 Direct Air Inlet Node, !- Air Outlet Node Name + AUTOSIZE, !- Maximum Air Flow Rate {m3/s} + , !- Design Specification Outdoor Air Object Name + ; !- Per Person Ventilation Rate Mode + + ZoneHVAC:AirDistributionUnit, + ZN_1_FLR_1_SEC_5 Direct Air ADU, !- Name + ZN_1_FLR_1_SEC_5 Direct Air Inlet Node, !- Air Distribution Unit Outlet Node Name + AirTerminal:SingleDuct:ConstantVolume:NoReheat, !- Air Terminal Object Type + ZN_1_FLR_1_SEC_5 Direct Air, !- Air Terminal Name + , !- Nominal Upstream Leakage Fraction + , !- Constant Downstream Leakage Fraction + ; !- Design Specification Air Terminal Sizing Object Name + + SetpointManager:SingleZone:Reheat, + SupAirTemp MngrZN_1_FLR_1_SEC_5, !- Name + Temperature, !- Control Variable + 13.0, !- Minimum Supply Air Temperature {C} + 40.0, !- Maximum Supply Air Temperature {C} + ZN_1_FLR_1_SEC_5, !- Control Zone Name + ZN_1_FLR_1_SEC_5 Air Node, !- Zone Node Name + ZN_1_FLR_1_SEC_5 Direct Air Inlet Node, !- Zone Inlet Node Name + ZN_1_FLR_1_SEC_5:Sys Supply Equipment Outlet Node; !- Setpoint Node or NodeList Name + +!***** Process Loads For Zone: ZN_1_FLR_1_SEC_5 ***** + + WaterUse:Connections, + ZN_1_FLR_1_SEC_5SHW_DEFAULT, !- Name + ZN_1_FLR_1_SEC_5SHW_DEFAULT Water Inlet Node, !- Inlet Node Name + ZN_1_FLR_1_SEC_5SHW_DEFAULT Water Outlet Node, !- Outlet Node Name + , !- Supply Water Storage Tank Name + , !- Reclamation Water Storage Tank Name + , !- Hot Water Supply Temperature Schedule Name + , !- Cold Water Supply Temperature Schedule Name + , !- Drain Water Heat Exchanger Type + , !- Drain Water Heat Exchanger Destination + , !- Drain Water Heat Exchanger U-Factor Times Area {W/K} + ZN_1_FLR_1_SEC_5SHW_DEFAULT; !- Water Use Equipment 1 Name + + WaterUse:Equipment, + ZN_1_FLR_1_SEC_5SHW_DEFAULT, !- Name + SHW_DEFAULT, !- End-Use Subcategory + 3.12791457840171E-7, !- Peak Flow Rate {m3/s} + HOURS_OF_OPERATION, !- Flow Rate Fraction Schedule Name + ZN_1_FLR_1_SEC_5SHW_DEFAULT Temp Sched, !- Target Temperature Schedule Name + ZN_1_FLR_1_SEC_5SHW_DEFAULTHot Supply Temp Sched, !- Hot Water Supply Temperature Schedule Name + , !- Cold Water Supply Temperature Schedule Name + ZN_1_FLR_1_SEC_5, !- Zone Name + ZN_1_FLR_1_SEC_5SHW_DEFAULT Sensible fract sched, !- Sensible Fraction Schedule Name + ZN_1_FLR_1_SEC_5SHW_DEFAULT Latent fract sched; !- Latent Fraction Schedule Name + + Schedule:Compact, + ZN_1_FLR_1_SEC_5SHW_DEFAULT Latent fract sched, !- Name + Fraction, !- Schedule Type Limits Name + Through: 12/31, !- Field 1 + For: AllDays, !- Field 2 + Until: 24:00,0.05; !- Field 3 + + Schedule:Compact, + ZN_1_FLR_1_SEC_5SHW_DEFAULT Sensible fract sched, !- Name + Fraction, !- Schedule Type Limits Name + Through: 12/31, !- Field 1 + For: AllDays, !- Field 2 + Until: 24:00,0.2; !- Field 3 + + Schedule:Compact, + ZN_1_FLR_1_SEC_5SHW_DEFAULT Temp Sched, !- Name + Temperature, !- Schedule Type Limits Name + Through: 12/31, !- Field 1 + For: AllDays, !- Field 2 + Until: 24:00,40; !- Field 3 + + Schedule:Compact, + ZN_1_FLR_1_SEC_5SHW_DEFAULTHot Supply Temp Sched, !- Name + Temperature, !- Schedule Type Limits Name + Through: 12/31, !- Field 1 + For: AllDays, !- Field 2 + Until: 24:00,55; !- Field 3 + +!***** Air Loop: ZN_1_FLR_1_SEC_1:Sys ***** + + AirLoopHVAC, + ZN_1_FLR_1_SEC_1:Sys, !- Name + , !- Controller List Name + ZN_1_FLR_1_SEC_1:Sys Availability Manager List, !- Availability Manager List Name + AUTOSIZE, !- Design Supply Air Flow Rate {m3/s} + ZN_1_FLR_1_SEC_1:Sys Air Loop Branches, !- Branch List Name + , !- Connector List Name + ZN_1_FLR_1_SEC_1:Sys Supply Equipment Inlet Node, !- Supply Side Inlet Node Name + ZN_1_FLR_1_SEC_1:Sys Zone Equipment Outlet Node, !- Demand Side Outlet Node Name + ZN_1_FLR_1_SEC_1:Sys Zone Equipment Inlet Node, !- Demand Side Inlet Node Names + ZN_1_FLR_1_SEC_1:Sys Supply Equipment Outlet Node; !- Supply Side Outlet Node Names + + Sizing:System, + ZN_1_FLR_1_SEC_1:Sys, !- AirLoop Name + SENSIBLE, !- Type of Load to Size On + AUTOSIZE, !- Design Outdoor Air Flow Rate {m3/s} + 0.3, !- Central Heating Maximum System Air Flow Ratio + 7.0, !- Preheat Design Temperature {C} + .008, !- Preheat Design Humidity Ratio {kgWater/kgDryAir} + 11.0, !- Precool Design Temperature {C} + .008, !- Precool Design Humidity Ratio {kgWater/kgDryAir} + 12.8, !- Central Cooling Design Supply Air Temperature {C} + 40.0, !- Central Heating Design Supply Air Temperature {C} + NONCOINCIDENT, !- Type of Zone Sum to Use + NO, !- 100% Outdoor Air in Cooling + NO, !- 100% Outdoor Air in Heating + 0.0085, !- Central Cooling Design Supply Air Humidity Ratio {kgWater/kgDryAir} + 0.008, !- Central Heating Design Supply Air Humidity Ratio {kgWater/kgDryAir} + DesignDay, !- Cooling Supply Air Flow Rate Method + 0.0, !- Cooling Supply Air Flow Rate {m3/s} + , !- Cooling Supply Air Flow Rate Per Floor Area {m3/s-m2} + , !- Cooling Fraction of Autosized Cooling Supply Air Flow Rate + , !- Cooling Supply Air Flow Rate Per Unit Cooling Capacity {m3/s-W} + DesignDay, !- Heating Supply Air Flow Rate Method + 0.0, !- Heating Supply Air Flow Rate {m3/s} + , !- Heating Supply Air Flow Rate Per Floor Area {m3/s-m2} + , !- Heating Fraction of Autosized Heating Supply Air Flow Rate + , !- Heating Fraction of Autosized Cooling Supply Air Flow Rate + , !- Heating Supply Air Flow Rate Per Unit Heating Capacity {m3/s-W} + , !- System Outdoor Air Method + 1.0, !- Zone Maximum Outdoor Air Fraction {dimensionless} + CoolingDesignCapacity, !- Cooling Design Capacity Method + autosize, !- Cooling Design Capacity {W} + , !- Cooling Design Capacity Per Floor Area {W/m2} + , !- Fraction of Autosized Cooling Design Capacity + HeatingDesignCapacity, !- Heating Design Capacity Method + autosize, !- Heating Design Capacity {W} + , !- Heating Design Capacity Per Floor Area {W/m2} + , !- Fraction of Autosized Heating Design Capacity + VAV; !- Central Cooling Capacity Control Method + + AvailabilityManagerAssignmentList, + ZN_1_FLR_1_SEC_1:Sys Availability Manager List, !- Name + AvailabilityManager:NightCycle, !- Availability Manager 1 Object Type + ZN_1_FLR_1_SEC_1:Sys Availability Manager; !- Availability Manager 1 Name + + AvailabilityManager:NightCycle, + ZN_1_FLR_1_SEC_1:Sys Availability Manager, !- Name + Always_On, !- Applicability Schedule Name + HVACOperationSchd, !- Fan Schedule Name + CycleOnAny, !- Control Type + 1.0, !- Thermostat Tolerance {deltaC} + FixedRunTime, !- Cycling Run Time Control Type + 7200; !- Cycling Run Time {s} + + BranchList, + ZN_1_FLR_1_SEC_1:Sys Air Loop Branches, !- Name + ZN_1_FLR_1_SEC_1:Sys Air Loop Main Branch; !- Branch 1 Name + + Branch, + ZN_1_FLR_1_SEC_1:Sys Air Loop Main Branch, !- Name + , !- Pressure Drop Curve Name + AirLoopHVAC:OutdoorAirSystem, !- Component 1 Object Type + ZN_1_FLR_1_SEC_1:Sys_OA, !- Component 1 Name + ZN_1_FLR_1_SEC_1:Sys Supply Equipment Inlet Node, !- Component 1 Inlet Node Name + ZN_1_FLR_1_SEC_1:Sys_OA-ZN_1_FLR_1_SEC_1:SysCoolCNode, !- Component 1 Outlet Node Name + CoilSystem:Cooling:DX, !- Component 2 Object Type + ZN_1_FLR_1_SEC_1:SysCoolC, !- Component 2 Name + ZN_1_FLR_1_SEC_1:Sys_OA-ZN_1_FLR_1_SEC_1:SysCoolCNode, !- Component 2 Inlet Node Name + ZN_1_FLR_1_SEC_1:SysCoolC-ZN_1_FLR_1_SEC_1:SysHeatCNode, !- Component 2 Outlet Node Name + Coil:Heating:Electric, !- Component 3 Object Type + ZN_1_FLR_1_SEC_1:SysHeatC, !- Component 3 Name + ZN_1_FLR_1_SEC_1:SysCoolC-ZN_1_FLR_1_SEC_1:SysHeatCNode, !- Component 3 Inlet Node Name + ZN_1_FLR_1_SEC_1:SysHeatC-ZN_1_FLR_1_SEC_1:Sys FanNode, !- Component 3 Outlet Node Name + Fan:ConstantVolume, !- Component 4 Object Type + ZN_1_FLR_1_SEC_1:Sys Fan,!- Component 4 Name + ZN_1_FLR_1_SEC_1:SysHeatC-ZN_1_FLR_1_SEC_1:Sys FanNode, !- Component 4 Inlet Node Name + ZN_1_FLR_1_SEC_1:Sys Supply Equipment Outlet Node; !- Component 4 Outlet Node Name + + AirLoopHVAC:ControllerList, + ZN_1_FLR_1_SEC_1:Sys_OAControllers, !- Name + Controller:OutdoorAir, !- Controller 1 Object Type + ControllerZN_1_FLR_1_SEC_1:Sys_OA; !- Controller 1 Name + + AirLoopHVAC:OutdoorAirSystem:EquipmentList, + ZN_1_FLR_1_SEC_1:Sys_OAEquipment, !- Name + OutdoorAir:Mixer, !- Component 1 Object Type + ZN_1_FLR_1_SEC_1:Sys_OAMixing Box; !- Component 1 Name + + AirLoopHVAC:OutdoorAirSystem, + ZN_1_FLR_1_SEC_1:Sys_OA, !- Name + ZN_1_FLR_1_SEC_1:Sys_OAControllers, !- Controller List Name + ZN_1_FLR_1_SEC_1:Sys_OAEquipment, !- Outdoor Air Equipment List Name + ZN_1_FLR_1_SEC_1:Sys Availability Manager List; !- Availability Manager List Name + + OutdoorAir:NodeList, + ZN_1_FLR_1_SEC_1:Sys_OANode List; !- Node or NodeList Name 1 + + NodeList, + ZN_1_FLR_1_SEC_1:Sys_OANode List, !- Name + ZN_1_FLR_1_SEC_1:Sys_OAInlet Node; !- Node 1 Name + + OutdoorAir:Mixer, + ZN_1_FLR_1_SEC_1:Sys_OAMixing Box, !- Name + ZN_1_FLR_1_SEC_1:Sys_OA-ZN_1_FLR_1_SEC_1:SysCoolCNode, !- Mixed Air Node Name + ZN_1_FLR_1_SEC_1:Sys_OAInlet Node, !- Outdoor Air Stream Node Name + ZN_1_FLR_1_SEC_1:Sys_OARelief Node, !- Relief Air Stream Node Name + ZN_1_FLR_1_SEC_1:Sys Supply Equipment Inlet Node; !- Return Air Stream Node Name + + SetpointManager:MixedAir, + ZN_1_FLR_1_SEC_1:Sys_OAMixed Air Temp Manager, !- Name + Temperature, !- Control Variable + ZN_1_FLR_1_SEC_1:Sys Supply Equipment Outlet Node, !- Reference Setpoint Node Name + ZN_1_FLR_1_SEC_1:SysHeatC-ZN_1_FLR_1_SEC_1:Sys FanNode, !- Fan Inlet Node Name + ZN_1_FLR_1_SEC_1:Sys Supply Equipment Outlet Node, !- Fan Outlet Node Name + ZN_1_FLR_1_SEC_1:Sys_OA-ZN_1_FLR_1_SEC_1:SysCoolCNode; !- Setpoint Node or NodeList Name + + Controller:OutdoorAir, + ControllerZN_1_FLR_1_SEC_1:Sys_OA, !- Name + ZN_1_FLR_1_SEC_1:Sys_OARelief Node, !- Relief Air Outlet Node Name + ZN_1_FLR_1_SEC_1:Sys Supply Equipment Inlet Node, !- Return Air Node Name + ZN_1_FLR_1_SEC_1:Sys_OA-ZN_1_FLR_1_SEC_1:SysCoolCNode, !- Mixed Air Node Name + ZN_1_FLR_1_SEC_1:Sys_OAInlet Node, !- Actuator Node Name + AUTOSIZE, !- Minimum Outdoor Air Flow Rate {m3/s} + AUTOSIZE, !- Maximum Outdoor Air Flow Rate {m3/s} + NoEconomizer, !- Economizer Control Type + ModulateFlow, !- Economizer Control Action Type + 19.0, !- Economizer Maximum Limit Dry-Bulb Temperature {C} + 32000.0, !- Economizer Maximum Limit Enthalpy {J/kg} + , !- Economizer Maximum Limit Dewpoint Temperature {C} + , !- Electronic Enthalpy Limit Curve Name + , !- Economizer Minimum Limit Dry-Bulb Temperature {C} + NoLockout, !- Lockout Type + FixedMinimum, !- Minimum Limit Type + MinOA_Sched; !- Minimum Outdoor Air Schedule Name + + CoilSystem:Cooling:DX, + ZN_1_FLR_1_SEC_1:SysCoolC, !- Name + ALWAYS_ON, !- Availability Schedule Name + ZN_1_FLR_1_SEC_1:Sys_OA-ZN_1_FLR_1_SEC_1:SysCoolCNode, !- DX Cooling Coil System Inlet Node Name + ZN_1_FLR_1_SEC_1:SysCoolC-ZN_1_FLR_1_SEC_1:SysHeatCNode, !- DX Cooling Coil System Outlet Node Name + ZN_1_FLR_1_SEC_1:Sys Supply Equipment Outlet Node, !- DX Cooling Coil System Sensor Node Name + Coil:Cooling:DX:SingleSpeed, !- Cooling Coil Object Type + ZN_1_FLR_1_SEC_1:SysCoolC DXCoil; !- Cooling Coil Name + + Coil:Cooling:DX:SingleSpeed, + ZN_1_FLR_1_SEC_1:SysCoolC DXCoil, !- Name + ALWAYS_ON, !- Availability Schedule Name + AUTOSIZE, !- Gross Rated Total Cooling Capacity {W} + AUTOSIZE, !- Gross Rated Sensible Heat Ratio + 2.7835, !- Gross Rated Cooling COP {W/W} + AUTOSIZE, !- Rated Air Flow Rate {m3/s} + , !- Rated Evaporator Fan Power Per Volume Flow Rate {W/(m3/s)} + ZN_1_FLR_1_SEC_1:Sys_OA-ZN_1_FLR_1_SEC_1:SysCoolCNode, !- Air Inlet Node Name + ZN_1_FLR_1_SEC_1:SysCoolC-ZN_1_FLR_1_SEC_1:SysHeatCNode, !- Air Outlet Node Name + ZN_1_FLR_1_SEC_1:SysCoolCCarrier48TM014_12tons_CapFT, !- Total Cooling Capacity Function of Temperature Curve Name + ZN_1_FLR_1_SEC_1:SysCoolCCarrier48TM014_12tons_FFF, !- Total Cooling Capacity Function of Flow Fraction Curve Name + ZN_1_FLR_1_SEC_1:SysCoolCCarrier48TM014_12tons_EIRFT, !- Energy Input Ratio Function of Temperature Curve Name + ZN_1_FLR_1_SEC_1:SysCoolCCarrier48TM014_12tons_EIRFFF, !- Energy Input Ratio Function of Flow Fraction Curve Name + ZN_1_FLR_1_SEC_1:SysCoolCIEA_HVAC_BESTEST_9ton-PLR; !- Part Load Fraction Correlation Curve Name + + Curve:Biquadratic, + ZN_1_FLR_1_SEC_1:SysCoolCCarrier48TM014_12tons_CapFT, !- Name + 1.39072, !- Coefficient1 Constant + -0.0529058, !- Coefficient2 x + 0.0018423, !- Coefficient3 x**2 + 0.00058267, !- Coefficient4 y + -0.000186814, !- Coefficient5 y**2 + 0.000265159, !- Coefficient6 x*y + 16.5556, !- Minimum Value of x + 22.1111, !- Maximum Value of x + 18.0, !- Minimum Value of y + 47.66, !- Maximum Value of y + , !- Minimum Curve Output + , !- Maximum Curve Output + Temperature, !- Input Unit Type for X + Temperature, !- Input Unit Type for Y + Dimensionless; !- Output Unit Type + + Curve:Biquadratic, + ZN_1_FLR_1_SEC_1:SysCoolCCarrier48TM014_12tons_EIRFT, !- Name + -0.536161, !- Coefficient1 Constant + 0.105138, !- Coefficient2 x + -0.00172659, !- Coefficient3 x**2 + 0.0149848, !- Coefficient4 y + 0.000659948, !- Coefficient5 y**2 + -0.0017385, !- Coefficient6 x*y + 16.5556, !- Minimum Value of x + 22.1111, !- Maximum Value of x + 18.0, !- Minimum Value of y + 47.66, !- Maximum Value of y + , !- Minimum Curve Output + , !- Maximum Curve Output + Temperature, !- Input Unit Type for X + Temperature, !- Input Unit Type for Y + Dimensionless; !- Output Unit Type + + Curve:Quadratic, + ZN_1_FLR_1_SEC_1:SysCoolCCarrier48TM014_12tons_FFF, !- Name + 0.718954, !- Coefficient1 Constant + 0.435436, !- Coefficient2 x + -0.154193, !- Coefficient3 x**2 + 0.75, !- Minimum Value of x + 1.25; !- Maximum Value of x + + Curve:Quadratic, + ZN_1_FLR_1_SEC_1:SysCoolCCarrier48TM014_12tons_EIRFFF, !- Name + 1.19525, !- Coefficient1 Constant + -0.306138, !- Coefficient2 x + 0.110973, !- Coefficient3 x**2 + 0.75, !- Minimum Value of x + 1.25; !- Maximum Value of x + + Curve:Quadratic, + ZN_1_FLR_1_SEC_1:SysCoolCIEA_HVAC_BESTEST_9ton-PLR, !- Name + 0.771, !- Coefficient1 Constant + 0.229, !- Coefficient2 x + 0.0, !- Coefficient3 x**2 + 0.0, !- Minimum Value of x + 1.0; !- Maximum Value of x + + OutdoorAir:Node, + ZN_1_FLR_1_SEC_1:SysCoolCOA Ref node; !- Name + + Coil:Heating:Electric, + ZN_1_FLR_1_SEC_1:SysHeatC, !- Name + ALWAYS_ON, !- Availability Schedule Name + 1.0, !- Efficiency + AUTOSIZE, !- Nominal Capacity {W} + ZN_1_FLR_1_SEC_1:SysCoolC-ZN_1_FLR_1_SEC_1:SysHeatCNode, !- Air Inlet Node Name + ZN_1_FLR_1_SEC_1:SysHeatC-ZN_1_FLR_1_SEC_1:Sys FanNode, !- Air Outlet Node Name + ZN_1_FLR_1_SEC_1:Sys Supply Equipment Outlet Node; !- Temperature Setpoint Node Name + + Fan:ConstantVolume, + ZN_1_FLR_1_SEC_1:Sys Fan,!- Name + HVACOperationSchd, !- Availability Schedule Name + 0.55, !- Fan Total Efficiency + 500, !- Pressure Rise {Pa} + AUTOSIZE, !- Maximum Flow Rate {m3/s} + 0.85, !- Motor Efficiency + 1.0, !- Motor In Airstream Fraction + ZN_1_FLR_1_SEC_1:SysHeatC-ZN_1_FLR_1_SEC_1:Sys FanNode, !- Air Inlet Node Name + ZN_1_FLR_1_SEC_1:Sys Supply Equipment Outlet Node; !- Air Outlet Node Name + + AirLoopHVAC:SupplyPath, + ZN_1_FLR_1_SEC_1:Sys, !- Name + ZN_1_FLR_1_SEC_1:Sys Zone Equipment Inlet Node, !- Supply Air Path Inlet Node Name + AirLoopHVAC:ZoneSplitter,!- Component 1 Object Type + ZN_1_FLR_1_SEC_1:Sys Supply Air Splitter; !- Component 1 Name + + AirLoopHVAC:ZoneSplitter, + ZN_1_FLR_1_SEC_1:Sys Supply Air Splitter, !- Name + ZN_1_FLR_1_SEC_1:Sys Zone Equipment Inlet Node, !- Inlet Node Name + ZN_1_FLR_1_SEC_1 Direct Air Inlet Node ATInlet; !- Outlet 1 Node Name + + AirLoopHVAC:ReturnPath, + ZN_1_FLR_1_SEC_1:Sys Return Air Path, !- Name + ZN_1_FLR_1_SEC_1:Sys Zone Equipment Outlet Node, !- Return Air Path Outlet Node Name + AirLoopHVAC:ZoneMixer, !- Component 1 Object Type + ZN_1_FLR_1_SEC_1:Sys Return Air Mixer; !- Component 1 Name + + AirLoopHVAC:ZoneMixer, + ZN_1_FLR_1_SEC_1:Sys Return Air Mixer, !- Name + ZN_1_FLR_1_SEC_1:Sys Zone Equipment Outlet Node, !- Outlet Node Name + ZN_1_FLR_1_SEC_1 Return Air Node; !- Inlet 1 Node Name + +!***** Air Loop: ZN_1_FLR_1_SEC_2:Sys ***** + + AirLoopHVAC, + ZN_1_FLR_1_SEC_2:Sys, !- Name + , !- Controller List Name + ZN_1_FLR_1_SEC_2:Sys Availability Manager List, !- Availability Manager List Name + AUTOSIZE, !- Design Supply Air Flow Rate {m3/s} + ZN_1_FLR_1_SEC_2:Sys Air Loop Branches, !- Branch List Name + , !- Connector List Name + ZN_1_FLR_1_SEC_2:Sys Supply Equipment Inlet Node, !- Supply Side Inlet Node Name + ZN_1_FLR_1_SEC_2:Sys Zone Equipment Outlet Node, !- Demand Side Outlet Node Name + ZN_1_FLR_1_SEC_2:Sys Zone Equipment Inlet Node, !- Demand Side Inlet Node Names + ZN_1_FLR_1_SEC_2:Sys Supply Equipment Outlet Node; !- Supply Side Outlet Node Names + + Sizing:System, + ZN_1_FLR_1_SEC_2:Sys, !- AirLoop Name + SENSIBLE, !- Type of Load to Size On + AUTOSIZE, !- Design Outdoor Air Flow Rate {m3/s} + 0.3, !- Central Heating Maximum System Air Flow Ratio + 7.0, !- Preheat Design Temperature {C} + .008, !- Preheat Design Humidity Ratio {kgWater/kgDryAir} + 11.0, !- Precool Design Temperature {C} + .008, !- Precool Design Humidity Ratio {kgWater/kgDryAir} + 12.8, !- Central Cooling Design Supply Air Temperature {C} + 40.0, !- Central Heating Design Supply Air Temperature {C} + NONCOINCIDENT, !- Type of Zone Sum to Use + NO, !- 100% Outdoor Air in Cooling + NO, !- 100% Outdoor Air in Heating + 0.0085, !- Central Cooling Design Supply Air Humidity Ratio {kgWater/kgDryAir} + 0.008, !- Central Heating Design Supply Air Humidity Ratio {kgWater/kgDryAir} + DesignDay, !- Cooling Supply Air Flow Rate Method + 0.0, !- Cooling Supply Air Flow Rate {m3/s} + , !- Cooling Supply Air Flow Rate Per Floor Area {m3/s-m2} + , !- Cooling Fraction of Autosized Cooling Supply Air Flow Rate + , !- Cooling Supply Air Flow Rate Per Unit Cooling Capacity {m3/s-W} + DesignDay, !- Heating Supply Air Flow Rate Method + 0.0, !- Heating Supply Air Flow Rate {m3/s} + , !- Heating Supply Air Flow Rate Per Floor Area {m3/s-m2} + , !- Heating Fraction of Autosized Heating Supply Air Flow Rate + , !- Heating Fraction of Autosized Cooling Supply Air Flow Rate + , !- Heating Supply Air Flow Rate Per Unit Heating Capacity {m3/s-W} + , !- System Outdoor Air Method + 1.0, !- Zone Maximum Outdoor Air Fraction {dimensionless} + CoolingDesignCapacity, !- Cooling Design Capacity Method + autosize, !- Cooling Design Capacity {W} + , !- Cooling Design Capacity Per Floor Area {W/m2} + , !- Fraction of Autosized Cooling Design Capacity + HeatingDesignCapacity, !- Heating Design Capacity Method + autosize, !- Heating Design Capacity {W} + , !- Heating Design Capacity Per Floor Area {W/m2} + , !- Fraction of Autosized Heating Design Capacity + VAV; !- Central Cooling Capacity Control Method + + AvailabilityManagerAssignmentList, + ZN_1_FLR_1_SEC_2:Sys Availability Manager List, !- Name + AvailabilityManager:NightCycle, !- Availability Manager 1 Object Type + ZN_1_FLR_1_SEC_2:Sys Availability Manager; !- Availability Manager 1 Name + + AvailabilityManager:NightCycle, + ZN_1_FLR_1_SEC_2:Sys Availability Manager, !- Name + Always_On, !- Applicability Schedule Name + HVACOperationSchd, !- Fan Schedule Name + CycleOnAny, !- Control Type + 1.0, !- Thermostat Tolerance {deltaC} + FixedRunTime, !- Cycling Run Time Control Type + 7200; !- Cycling Run Time {s} + + BranchList, + ZN_1_FLR_1_SEC_2:Sys Air Loop Branches, !- Name + ZN_1_FLR_1_SEC_2:Sys Air Loop Main Branch; !- Branch 1 Name + + Branch, + ZN_1_FLR_1_SEC_2:Sys Air Loop Main Branch, !- Name + , !- Pressure Drop Curve Name + AirLoopHVAC:OutdoorAirSystem, !- Component 1 Object Type + ZN_1_FLR_1_SEC_2:Sys_OA, !- Component 1 Name + ZN_1_FLR_1_SEC_2:Sys Supply Equipment Inlet Node, !- Component 1 Inlet Node Name + ZN_1_FLR_1_SEC_2:Sys_OA-ZN_1_FLR_1_SEC_2:SysCoolCNode, !- Component 1 Outlet Node Name + CoilSystem:Cooling:DX, !- Component 2 Object Type + ZN_1_FLR_1_SEC_2:SysCoolC, !- Component 2 Name + ZN_1_FLR_1_SEC_2:Sys_OA-ZN_1_FLR_1_SEC_2:SysCoolCNode, !- Component 2 Inlet Node Name + ZN_1_FLR_1_SEC_2:SysCoolC-ZN_1_FLR_1_SEC_2:SysHeatCNode, !- Component 2 Outlet Node Name + Coil:Heating:Electric, !- Component 3 Object Type + ZN_1_FLR_1_SEC_2:SysHeatC, !- Component 3 Name + ZN_1_FLR_1_SEC_2:SysCoolC-ZN_1_FLR_1_SEC_2:SysHeatCNode, !- Component 3 Inlet Node Name + ZN_1_FLR_1_SEC_2:SysHeatC-ZN_1_FLR_1_SEC_2:Sys FanNode, !- Component 3 Outlet Node Name + Fan:ConstantVolume, !- Component 4 Object Type + ZN_1_FLR_1_SEC_2:Sys Fan,!- Component 4 Name + ZN_1_FLR_1_SEC_2:SysHeatC-ZN_1_FLR_1_SEC_2:Sys FanNode, !- Component 4 Inlet Node Name + ZN_1_FLR_1_SEC_2:Sys Supply Equipment Outlet Node; !- Component 4 Outlet Node Name + + AirLoopHVAC:ControllerList, + ZN_1_FLR_1_SEC_2:Sys_OAControllers, !- Name + Controller:OutdoorAir, !- Controller 1 Object Type + ControllerZN_1_FLR_1_SEC_2:Sys_OA; !- Controller 1 Name + + AirLoopHVAC:OutdoorAirSystem:EquipmentList, + ZN_1_FLR_1_SEC_2:Sys_OAEquipment, !- Name + OutdoorAir:Mixer, !- Component 1 Object Type + ZN_1_FLR_1_SEC_2:Sys_OAMixing Box; !- Component 1 Name + + AirLoopHVAC:OutdoorAirSystem, + ZN_1_FLR_1_SEC_2:Sys_OA, !- Name + ZN_1_FLR_1_SEC_2:Sys_OAControllers, !- Controller List Name + ZN_1_FLR_1_SEC_2:Sys_OAEquipment, !- Outdoor Air Equipment List Name + ZN_1_FLR_1_SEC_2:Sys Availability Manager List; !- Availability Manager List Name + + OutdoorAir:NodeList, + ZN_1_FLR_1_SEC_2:Sys_OANode List; !- Node or NodeList Name 1 + + NodeList, + ZN_1_FLR_1_SEC_2:Sys_OANode List, !- Name + ZN_1_FLR_1_SEC_2:Sys_OAInlet Node; !- Node 1 Name + + OutdoorAir:Mixer, + ZN_1_FLR_1_SEC_2:Sys_OAMixing Box, !- Name + ZN_1_FLR_1_SEC_2:Sys_OA-ZN_1_FLR_1_SEC_2:SysCoolCNode, !- Mixed Air Node Name + ZN_1_FLR_1_SEC_2:Sys_OAInlet Node, !- Outdoor Air Stream Node Name + ZN_1_FLR_1_SEC_2:Sys_OARelief Node, !- Relief Air Stream Node Name + ZN_1_FLR_1_SEC_2:Sys Supply Equipment Inlet Node; !- Return Air Stream Node Name + + SetpointManager:MixedAir, + ZN_1_FLR_1_SEC_2:Sys_OAMixed Air Temp Manager, !- Name + Temperature, !- Control Variable + ZN_1_FLR_1_SEC_2:Sys Supply Equipment Outlet Node, !- Reference Setpoint Node Name + ZN_1_FLR_1_SEC_2:SysHeatC-ZN_1_FLR_1_SEC_2:Sys FanNode, !- Fan Inlet Node Name + ZN_1_FLR_1_SEC_2:Sys Supply Equipment Outlet Node, !- Fan Outlet Node Name + ZN_1_FLR_1_SEC_2:Sys_OA-ZN_1_FLR_1_SEC_2:SysCoolCNode; !- Setpoint Node or NodeList Name + + Controller:OutdoorAir, + ControllerZN_1_FLR_1_SEC_2:Sys_OA, !- Name + ZN_1_FLR_1_SEC_2:Sys_OARelief Node, !- Relief Air Outlet Node Name + ZN_1_FLR_1_SEC_2:Sys Supply Equipment Inlet Node, !- Return Air Node Name + ZN_1_FLR_1_SEC_2:Sys_OA-ZN_1_FLR_1_SEC_2:SysCoolCNode, !- Mixed Air Node Name + ZN_1_FLR_1_SEC_2:Sys_OAInlet Node, !- Actuator Node Name + AUTOSIZE, !- Minimum Outdoor Air Flow Rate {m3/s} + AUTOSIZE, !- Maximum Outdoor Air Flow Rate {m3/s} + NoEconomizer, !- Economizer Control Type + ModulateFlow, !- Economizer Control Action Type + 19.0, !- Economizer Maximum Limit Dry-Bulb Temperature {C} + 32000.0, !- Economizer Maximum Limit Enthalpy {J/kg} + , !- Economizer Maximum Limit Dewpoint Temperature {C} + , !- Electronic Enthalpy Limit Curve Name + , !- Economizer Minimum Limit Dry-Bulb Temperature {C} + NoLockout, !- Lockout Type + FixedMinimum, !- Minimum Limit Type + MinOA_Sched; !- Minimum Outdoor Air Schedule Name + + CoilSystem:Cooling:DX, + ZN_1_FLR_1_SEC_2:SysCoolC, !- Name + ALWAYS_ON, !- Availability Schedule Name + ZN_1_FLR_1_SEC_2:Sys_OA-ZN_1_FLR_1_SEC_2:SysCoolCNode, !- DX Cooling Coil System Inlet Node Name + ZN_1_FLR_1_SEC_2:SysCoolC-ZN_1_FLR_1_SEC_2:SysHeatCNode, !- DX Cooling Coil System Outlet Node Name + ZN_1_FLR_1_SEC_2:Sys Supply Equipment Outlet Node, !- DX Cooling Coil System Sensor Node Name + Coil:Cooling:DX:SingleSpeed, !- Cooling Coil Object Type + ZN_1_FLR_1_SEC_2:SysCoolC DXCoil; !- Cooling Coil Name + + Coil:Cooling:DX:SingleSpeed, + ZN_1_FLR_1_SEC_2:SysCoolC DXCoil, !- Name + ALWAYS_ON, !- Availability Schedule Name + AUTOSIZE, !- Gross Rated Total Cooling Capacity {W} + AUTOSIZE, !- Gross Rated Sensible Heat Ratio + 2.7835, !- Gross Rated Cooling COP {W/W} + AUTOSIZE, !- Rated Air Flow Rate {m3/s} + , !- Rated Evaporator Fan Power Per Volume Flow Rate {W/(m3/s)} + ZN_1_FLR_1_SEC_2:Sys_OA-ZN_1_FLR_1_SEC_2:SysCoolCNode, !- Air Inlet Node Name + ZN_1_FLR_1_SEC_2:SysCoolC-ZN_1_FLR_1_SEC_2:SysHeatCNode, !- Air Outlet Node Name + ZN_1_FLR_1_SEC_2:SysCoolCCarrier48TM014_12tons_CapFT, !- Total Cooling Capacity Function of Temperature Curve Name + ZN_1_FLR_1_SEC_2:SysCoolCCarrier48TM014_12tons_FFF, !- Total Cooling Capacity Function of Flow Fraction Curve Name + ZN_1_FLR_1_SEC_2:SysCoolCCarrier48TM014_12tons_EIRFT, !- Energy Input Ratio Function of Temperature Curve Name + ZN_1_FLR_1_SEC_2:SysCoolCCarrier48TM014_12tons_EIRFFF, !- Energy Input Ratio Function of Flow Fraction Curve Name + ZN_1_FLR_1_SEC_2:SysCoolCIEA_HVAC_BESTEST_9ton-PLR; !- Part Load Fraction Correlation Curve Name + + Curve:Biquadratic, + ZN_1_FLR_1_SEC_2:SysCoolCCarrier48TM014_12tons_CapFT, !- Name + 1.39072, !- Coefficient1 Constant + -0.0529058, !- Coefficient2 x + 0.0018423, !- Coefficient3 x**2 + 0.00058267, !- Coefficient4 y + -0.000186814, !- Coefficient5 y**2 + 0.000265159, !- Coefficient6 x*y + 16.5556, !- Minimum Value of x + 22.1111, !- Maximum Value of x + 18.0, !- Minimum Value of y + 47.66, !- Maximum Value of y + , !- Minimum Curve Output + , !- Maximum Curve Output + Temperature, !- Input Unit Type for X + Temperature, !- Input Unit Type for Y + Dimensionless; !- Output Unit Type + + Curve:Biquadratic, + ZN_1_FLR_1_SEC_2:SysCoolCCarrier48TM014_12tons_EIRFT, !- Name + -0.536161, !- Coefficient1 Constant + 0.105138, !- Coefficient2 x + -0.00172659, !- Coefficient3 x**2 + 0.0149848, !- Coefficient4 y + 0.000659948, !- Coefficient5 y**2 + -0.0017385, !- Coefficient6 x*y + 16.5556, !- Minimum Value of x + 22.1111, !- Maximum Value of x + 18.0, !- Minimum Value of y + 47.66, !- Maximum Value of y + , !- Minimum Curve Output + , !- Maximum Curve Output + Temperature, !- Input Unit Type for X + Temperature, !- Input Unit Type for Y + Dimensionless; !- Output Unit Type + + Curve:Quadratic, + ZN_1_FLR_1_SEC_2:SysCoolCCarrier48TM014_12tons_FFF, !- Name + 0.718954, !- Coefficient1 Constant + 0.435436, !- Coefficient2 x + -0.154193, !- Coefficient3 x**2 + 0.75, !- Minimum Value of x + 1.25; !- Maximum Value of x + + Curve:Quadratic, + ZN_1_FLR_1_SEC_2:SysCoolCCarrier48TM014_12tons_EIRFFF, !- Name + 1.19525, !- Coefficient1 Constant + -0.306138, !- Coefficient2 x + 0.110973, !- Coefficient3 x**2 + 0.75, !- Minimum Value of x + 1.25; !- Maximum Value of x + + Curve:Quadratic, + ZN_1_FLR_1_SEC_2:SysCoolCIEA_HVAC_BESTEST_9ton-PLR, !- Name + 0.771, !- Coefficient1 Constant + 0.229, !- Coefficient2 x + 0.0, !- Coefficient3 x**2 + 0.0, !- Minimum Value of x + 1.0; !- Maximum Value of x + + OutdoorAir:Node, + ZN_1_FLR_1_SEC_2:SysCoolCOA Ref node; !- Name + + Coil:Heating:Electric, + ZN_1_FLR_1_SEC_2:SysHeatC, !- Name + ALWAYS_ON, !- Availability Schedule Name + 1.0, !- Efficiency + AUTOSIZE, !- Nominal Capacity {W} + ZN_1_FLR_1_SEC_2:SysCoolC-ZN_1_FLR_1_SEC_2:SysHeatCNode, !- Air Inlet Node Name + ZN_1_FLR_1_SEC_2:SysHeatC-ZN_1_FLR_1_SEC_2:Sys FanNode, !- Air Outlet Node Name + ZN_1_FLR_1_SEC_2:Sys Supply Equipment Outlet Node; !- Temperature Setpoint Node Name + + Fan:ConstantVolume, + ZN_1_FLR_1_SEC_2:Sys Fan,!- Name + HVACOperationSchd, !- Availability Schedule Name + 0.55, !- Fan Total Efficiency + 500, !- Pressure Rise {Pa} + AUTOSIZE, !- Maximum Flow Rate {m3/s} + 0.85, !- Motor Efficiency + 1.0, !- Motor In Airstream Fraction + ZN_1_FLR_1_SEC_2:SysHeatC-ZN_1_FLR_1_SEC_2:Sys FanNode, !- Air Inlet Node Name + ZN_1_FLR_1_SEC_2:Sys Supply Equipment Outlet Node; !- Air Outlet Node Name + + AirLoopHVAC:SupplyPath, + ZN_1_FLR_1_SEC_2:Sys, !- Name + ZN_1_FLR_1_SEC_2:Sys Zone Equipment Inlet Node, !- Supply Air Path Inlet Node Name + AirLoopHVAC:ZoneSplitter,!- Component 1 Object Type + ZN_1_FLR_1_SEC_2:Sys Supply Air Splitter; !- Component 1 Name + + AirLoopHVAC:ZoneSplitter, + ZN_1_FLR_1_SEC_2:Sys Supply Air Splitter, !- Name + ZN_1_FLR_1_SEC_2:Sys Zone Equipment Inlet Node, !- Inlet Node Name + ZN_1_FLR_1_SEC_2 Direct Air Inlet Node ATInlet; !- Outlet 1 Node Name + + AirLoopHVAC:ReturnPath, + ZN_1_FLR_1_SEC_2:Sys Return Air Path, !- Name + ZN_1_FLR_1_SEC_2:Sys Zone Equipment Outlet Node, !- Return Air Path Outlet Node Name + AirLoopHVAC:ZoneMixer, !- Component 1 Object Type + ZN_1_FLR_1_SEC_2:Sys Return Air Mixer; !- Component 1 Name + + AirLoopHVAC:ZoneMixer, + ZN_1_FLR_1_SEC_2:Sys Return Air Mixer, !- Name + ZN_1_FLR_1_SEC_2:Sys Zone Equipment Outlet Node, !- Outlet Node Name + ZN_1_FLR_1_SEC_2 Return Air Node; !- Inlet 1 Node Name + +!***** Air Loop: ZN_1_FLR_1_SEC_3:Sys ***** + + AirLoopHVAC, + ZN_1_FLR_1_SEC_3:Sys, !- Name + , !- Controller List Name + ZN_1_FLR_1_SEC_3:Sys Availability Manager List, !- Availability Manager List Name + AUTOSIZE, !- Design Supply Air Flow Rate {m3/s} + ZN_1_FLR_1_SEC_3:Sys Air Loop Branches, !- Branch List Name + , !- Connector List Name + ZN_1_FLR_1_SEC_3:Sys Supply Equipment Inlet Node, !- Supply Side Inlet Node Name + ZN_1_FLR_1_SEC_3:Sys Zone Equipment Outlet Node, !- Demand Side Outlet Node Name + ZN_1_FLR_1_SEC_3:Sys Zone Equipment Inlet Node, !- Demand Side Inlet Node Names + ZN_1_FLR_1_SEC_3:Sys Supply Equipment Outlet Node; !- Supply Side Outlet Node Names + + Sizing:System, + ZN_1_FLR_1_SEC_3:Sys, !- AirLoop Name + SENSIBLE, !- Type of Load to Size On + AUTOSIZE, !- Design Outdoor Air Flow Rate {m3/s} + 0.3, !- Central Heating Maximum System Air Flow Ratio + 7.0, !- Preheat Design Temperature {C} + .008, !- Preheat Design Humidity Ratio {kgWater/kgDryAir} + 11.0, !- Precool Design Temperature {C} + .008, !- Precool Design Humidity Ratio {kgWater/kgDryAir} + 12.8, !- Central Cooling Design Supply Air Temperature {C} + 40.0, !- Central Heating Design Supply Air Temperature {C} + NONCOINCIDENT, !- Type of Zone Sum to Use + NO, !- 100% Outdoor Air in Cooling + NO, !- 100% Outdoor Air in Heating + 0.0085, !- Central Cooling Design Supply Air Humidity Ratio {kgWater/kgDryAir} + 0.008, !- Central Heating Design Supply Air Humidity Ratio {kgWater/kgDryAir} + DesignDay, !- Cooling Supply Air Flow Rate Method + 0.0, !- Cooling Supply Air Flow Rate {m3/s} + , !- Cooling Supply Air Flow Rate Per Floor Area {m3/s-m2} + , !- Cooling Fraction of Autosized Cooling Supply Air Flow Rate + , !- Cooling Supply Air Flow Rate Per Unit Cooling Capacity {m3/s-W} + DesignDay, !- Heating Supply Air Flow Rate Method + 0.0, !- Heating Supply Air Flow Rate {m3/s} + , !- Heating Supply Air Flow Rate Per Floor Area {m3/s-m2} + , !- Heating Fraction of Autosized Heating Supply Air Flow Rate + , !- Heating Fraction of Autosized Cooling Supply Air Flow Rate + , !- Heating Supply Air Flow Rate Per Unit Heating Capacity {m3/s-W} + , !- System Outdoor Air Method + 1.0, !- Zone Maximum Outdoor Air Fraction {dimensionless} + CoolingDesignCapacity, !- Cooling Design Capacity Method + autosize, !- Cooling Design Capacity {W} + , !- Cooling Design Capacity Per Floor Area {W/m2} + , !- Fraction of Autosized Cooling Design Capacity + HeatingDesignCapacity, !- Heating Design Capacity Method + autosize, !- Heating Design Capacity {W} + , !- Heating Design Capacity Per Floor Area {W/m2} + , !- Fraction of Autosized Heating Design Capacity + VAV; !- Central Cooling Capacity Control Method + + AvailabilityManagerAssignmentList, + ZN_1_FLR_1_SEC_3:Sys Availability Manager List, !- Name + AvailabilityManager:NightCycle, !- Availability Manager 1 Object Type + ZN_1_FLR_1_SEC_3:Sys Availability Manager; !- Availability Manager 1 Name + + AvailabilityManager:NightCycle, + ZN_1_FLR_1_SEC_3:Sys Availability Manager, !- Name + Always_On, !- Applicability Schedule Name + HVACOperationSchd, !- Fan Schedule Name + CycleOnAny, !- Control Type + 1.0, !- Thermostat Tolerance {deltaC} + FixedRunTime, !- Cycling Run Time Control Type + 7200; !- Cycling Run Time {s} + + BranchList, + ZN_1_FLR_1_SEC_3:Sys Air Loop Branches, !- Name + ZN_1_FLR_1_SEC_3:Sys Air Loop Main Branch; !- Branch 1 Name + + Branch, + ZN_1_FLR_1_SEC_3:Sys Air Loop Main Branch, !- Name + , !- Pressure Drop Curve Name + AirLoopHVAC:OutdoorAirSystem, !- Component 1 Object Type + ZN_1_FLR_1_SEC_3:Sys_OA, !- Component 1 Name + ZN_1_FLR_1_SEC_3:Sys Supply Equipment Inlet Node, !- Component 1 Inlet Node Name + ZN_1_FLR_1_SEC_3:Sys_OA-ZN_1_FLR_1_SEC_3:SysCoolCNode, !- Component 1 Outlet Node Name + CoilSystem:Cooling:DX, !- Component 2 Object Type + ZN_1_FLR_1_SEC_3:SysCoolC, !- Component 2 Name + ZN_1_FLR_1_SEC_3:Sys_OA-ZN_1_FLR_1_SEC_3:SysCoolCNode, !- Component 2 Inlet Node Name + ZN_1_FLR_1_SEC_3:SysCoolC-ZN_1_FLR_1_SEC_3:SysHeatCNode, !- Component 2 Outlet Node Name + Coil:Heating:Electric, !- Component 3 Object Type + ZN_1_FLR_1_SEC_3:SysHeatC, !- Component 3 Name + ZN_1_FLR_1_SEC_3:SysCoolC-ZN_1_FLR_1_SEC_3:SysHeatCNode, !- Component 3 Inlet Node Name + ZN_1_FLR_1_SEC_3:SysHeatC-ZN_1_FLR_1_SEC_3:Sys FanNode, !- Component 3 Outlet Node Name + Fan:ConstantVolume, !- Component 4 Object Type + ZN_1_FLR_1_SEC_3:Sys Fan,!- Component 4 Name + ZN_1_FLR_1_SEC_3:SysHeatC-ZN_1_FLR_1_SEC_3:Sys FanNode, !- Component 4 Inlet Node Name + ZN_1_FLR_1_SEC_3:Sys Supply Equipment Outlet Node; !- Component 4 Outlet Node Name + + AirLoopHVAC:ControllerList, + ZN_1_FLR_1_SEC_3:Sys_OAControllers, !- Name + Controller:OutdoorAir, !- Controller 1 Object Type + ControllerZN_1_FLR_1_SEC_3:Sys_OA; !- Controller 1 Name + + AirLoopHVAC:OutdoorAirSystem:EquipmentList, + ZN_1_FLR_1_SEC_3:Sys_OAEquipment, !- Name + OutdoorAir:Mixer, !- Component 1 Object Type + ZN_1_FLR_1_SEC_3:Sys_OAMixing Box; !- Component 1 Name + + AirLoopHVAC:OutdoorAirSystem, + ZN_1_FLR_1_SEC_3:Sys_OA, !- Name + ZN_1_FLR_1_SEC_3:Sys_OAControllers, !- Controller List Name + ZN_1_FLR_1_SEC_3:Sys_OAEquipment, !- Outdoor Air Equipment List Name + ZN_1_FLR_1_SEC_3:Sys Availability Manager List; !- Availability Manager List Name + + OutdoorAir:NodeList, + ZN_1_FLR_1_SEC_3:Sys_OANode List; !- Node or NodeList Name 1 + + NodeList, + ZN_1_FLR_1_SEC_3:Sys_OANode List, !- Name + ZN_1_FLR_1_SEC_3:Sys_OAInlet Node; !- Node 1 Name + + OutdoorAir:Mixer, + ZN_1_FLR_1_SEC_3:Sys_OAMixing Box, !- Name + ZN_1_FLR_1_SEC_3:Sys_OA-ZN_1_FLR_1_SEC_3:SysCoolCNode, !- Mixed Air Node Name + ZN_1_FLR_1_SEC_3:Sys_OAInlet Node, !- Outdoor Air Stream Node Name + ZN_1_FLR_1_SEC_3:Sys_OARelief Node, !- Relief Air Stream Node Name + ZN_1_FLR_1_SEC_3:Sys Supply Equipment Inlet Node; !- Return Air Stream Node Name + + SetpointManager:MixedAir, + ZN_1_FLR_1_SEC_3:Sys_OAMixed Air Temp Manager, !- Name + Temperature, !- Control Variable + ZN_1_FLR_1_SEC_3:Sys Supply Equipment Outlet Node, !- Reference Setpoint Node Name + ZN_1_FLR_1_SEC_3:SysHeatC-ZN_1_FLR_1_SEC_3:Sys FanNode, !- Fan Inlet Node Name + ZN_1_FLR_1_SEC_3:Sys Supply Equipment Outlet Node, !- Fan Outlet Node Name + ZN_1_FLR_1_SEC_3:Sys_OA-ZN_1_FLR_1_SEC_3:SysCoolCNode; !- Setpoint Node or NodeList Name + + Controller:OutdoorAir, + ControllerZN_1_FLR_1_SEC_3:Sys_OA, !- Name + ZN_1_FLR_1_SEC_3:Sys_OARelief Node, !- Relief Air Outlet Node Name + ZN_1_FLR_1_SEC_3:Sys Supply Equipment Inlet Node, !- Return Air Node Name + ZN_1_FLR_1_SEC_3:Sys_OA-ZN_1_FLR_1_SEC_3:SysCoolCNode, !- Mixed Air Node Name + ZN_1_FLR_1_SEC_3:Sys_OAInlet Node, !- Actuator Node Name + AUTOSIZE, !- Minimum Outdoor Air Flow Rate {m3/s} + AUTOSIZE, !- Maximum Outdoor Air Flow Rate {m3/s} + NoEconomizer, !- Economizer Control Type + ModulateFlow, !- Economizer Control Action Type + 19.0, !- Economizer Maximum Limit Dry-Bulb Temperature {C} + 32000.0, !- Economizer Maximum Limit Enthalpy {J/kg} + , !- Economizer Maximum Limit Dewpoint Temperature {C} + , !- Electronic Enthalpy Limit Curve Name + , !- Economizer Minimum Limit Dry-Bulb Temperature {C} + NoLockout, !- Lockout Type + FixedMinimum, !- Minimum Limit Type + MinOA_Sched; !- Minimum Outdoor Air Schedule Name + + CoilSystem:Cooling:DX, + ZN_1_FLR_1_SEC_3:SysCoolC, !- Name + ALWAYS_ON, !- Availability Schedule Name + ZN_1_FLR_1_SEC_3:Sys_OA-ZN_1_FLR_1_SEC_3:SysCoolCNode, !- DX Cooling Coil System Inlet Node Name + ZN_1_FLR_1_SEC_3:SysCoolC-ZN_1_FLR_1_SEC_3:SysHeatCNode, !- DX Cooling Coil System Outlet Node Name + ZN_1_FLR_1_SEC_3:Sys Supply Equipment Outlet Node, !- DX Cooling Coil System Sensor Node Name + Coil:Cooling:DX:SingleSpeed, !- Cooling Coil Object Type + ZN_1_FLR_1_SEC_3:SysCoolC DXCoil; !- Cooling Coil Name + + Coil:Cooling:DX:SingleSpeed, + ZN_1_FLR_1_SEC_3:SysCoolC DXCoil, !- Name + ALWAYS_ON, !- Availability Schedule Name + AUTOSIZE, !- Gross Rated Total Cooling Capacity {W} + AUTOSIZE, !- Gross Rated Sensible Heat Ratio + 2.7835, !- Gross Rated Cooling COP {W/W} + AUTOSIZE, !- Rated Air Flow Rate {m3/s} + , !- Rated Evaporator Fan Power Per Volume Flow Rate {W/(m3/s)} + ZN_1_FLR_1_SEC_3:Sys_OA-ZN_1_FLR_1_SEC_3:SysCoolCNode, !- Air Inlet Node Name + ZN_1_FLR_1_SEC_3:SysCoolC-ZN_1_FLR_1_SEC_3:SysHeatCNode, !- Air Outlet Node Name + ZN_1_FLR_1_SEC_3:SysCoolCCarrier48TM014_12tons_CapFT, !- Total Cooling Capacity Function of Temperature Curve Name + ZN_1_FLR_1_SEC_3:SysCoolCCarrier48TM014_12tons_FFF, !- Total Cooling Capacity Function of Flow Fraction Curve Name + ZN_1_FLR_1_SEC_3:SysCoolCCarrier48TM014_12tons_EIRFT, !- Energy Input Ratio Function of Temperature Curve Name + ZN_1_FLR_1_SEC_3:SysCoolCCarrier48TM014_12tons_EIRFFF, !- Energy Input Ratio Function of Flow Fraction Curve Name + ZN_1_FLR_1_SEC_3:SysCoolCIEA_HVAC_BESTEST_9ton-PLR; !- Part Load Fraction Correlation Curve Name + + Curve:Biquadratic, + ZN_1_FLR_1_SEC_3:SysCoolCCarrier48TM014_12tons_CapFT, !- Name + 1.39072, !- Coefficient1 Constant + -0.0529058, !- Coefficient2 x + 0.0018423, !- Coefficient3 x**2 + 0.00058267, !- Coefficient4 y + -0.000186814, !- Coefficient5 y**2 + 0.000265159, !- Coefficient6 x*y + 16.5556, !- Minimum Value of x + 22.1111, !- Maximum Value of x + 18.0, !- Minimum Value of y + 47.66, !- Maximum Value of y + , !- Minimum Curve Output + , !- Maximum Curve Output + Temperature, !- Input Unit Type for X + Temperature, !- Input Unit Type for Y + Dimensionless; !- Output Unit Type + + Curve:Biquadratic, + ZN_1_FLR_1_SEC_3:SysCoolCCarrier48TM014_12tons_EIRFT, !- Name + -0.536161, !- Coefficient1 Constant + 0.105138, !- Coefficient2 x + -0.00172659, !- Coefficient3 x**2 + 0.0149848, !- Coefficient4 y + 0.000659948, !- Coefficient5 y**2 + -0.0017385, !- Coefficient6 x*y + 16.5556, !- Minimum Value of x + 22.1111, !- Maximum Value of x + 18.0, !- Minimum Value of y + 47.66, !- Maximum Value of y + , !- Minimum Curve Output + , !- Maximum Curve Output + Temperature, !- Input Unit Type for X + Temperature, !- Input Unit Type for Y + Dimensionless; !- Output Unit Type + + Curve:Quadratic, + ZN_1_FLR_1_SEC_3:SysCoolCCarrier48TM014_12tons_FFF, !- Name + 0.718954, !- Coefficient1 Constant + 0.435436, !- Coefficient2 x + -0.154193, !- Coefficient3 x**2 + 0.75, !- Minimum Value of x + 1.25; !- Maximum Value of x + + Curve:Quadratic, + ZN_1_FLR_1_SEC_3:SysCoolCCarrier48TM014_12tons_EIRFFF, !- Name + 1.19525, !- Coefficient1 Constant + -0.306138, !- Coefficient2 x + 0.110973, !- Coefficient3 x**2 + 0.75, !- Minimum Value of x + 1.25; !- Maximum Value of x + + Curve:Quadratic, + ZN_1_FLR_1_SEC_3:SysCoolCIEA_HVAC_BESTEST_9ton-PLR, !- Name + 0.771, !- Coefficient1 Constant + 0.229, !- Coefficient2 x + 0.0, !- Coefficient3 x**2 + 0.0, !- Minimum Value of x + 1.0; !- Maximum Value of x + + OutdoorAir:Node, + ZN_1_FLR_1_SEC_3:SysCoolCOA Ref node; !- Name + + Coil:Heating:Electric, + ZN_1_FLR_1_SEC_3:SysHeatC, !- Name + ALWAYS_ON, !- Availability Schedule Name + 1.0, !- Efficiency + AUTOSIZE, !- Nominal Capacity {W} + ZN_1_FLR_1_SEC_3:SysCoolC-ZN_1_FLR_1_SEC_3:SysHeatCNode, !- Air Inlet Node Name + ZN_1_FLR_1_SEC_3:SysHeatC-ZN_1_FLR_1_SEC_3:Sys FanNode, !- Air Outlet Node Name + ZN_1_FLR_1_SEC_3:Sys Supply Equipment Outlet Node; !- Temperature Setpoint Node Name + + Fan:ConstantVolume, + ZN_1_FLR_1_SEC_3:Sys Fan,!- Name + HVACOperationSchd, !- Availability Schedule Name + 0.55, !- Fan Total Efficiency + 500, !- Pressure Rise {Pa} + AUTOSIZE, !- Maximum Flow Rate {m3/s} + 0.85, !- Motor Efficiency + 1.0, !- Motor In Airstream Fraction + ZN_1_FLR_1_SEC_3:SysHeatC-ZN_1_FLR_1_SEC_3:Sys FanNode, !- Air Inlet Node Name + ZN_1_FLR_1_SEC_3:Sys Supply Equipment Outlet Node; !- Air Outlet Node Name + + AirLoopHVAC:SupplyPath, + ZN_1_FLR_1_SEC_3:Sys, !- Name + ZN_1_FLR_1_SEC_3:Sys Zone Equipment Inlet Node, !- Supply Air Path Inlet Node Name + AirLoopHVAC:ZoneSplitter,!- Component 1 Object Type + ZN_1_FLR_1_SEC_3:Sys Supply Air Splitter; !- Component 1 Name + + AirLoopHVAC:ZoneSplitter, + ZN_1_FLR_1_SEC_3:Sys Supply Air Splitter, !- Name + ZN_1_FLR_1_SEC_3:Sys Zone Equipment Inlet Node, !- Inlet Node Name + ZN_1_FLR_1_SEC_3 Direct Air Inlet Node ATInlet; !- Outlet 1 Node Name + + AirLoopHVAC:ReturnPath, + ZN_1_FLR_1_SEC_3:Sys Return Air Path, !- Name + ZN_1_FLR_1_SEC_3:Sys Zone Equipment Outlet Node, !- Return Air Path Outlet Node Name + AirLoopHVAC:ZoneMixer, !- Component 1 Object Type + ZN_1_FLR_1_SEC_3:Sys Return Air Mixer; !- Component 1 Name + + AirLoopHVAC:ZoneMixer, + ZN_1_FLR_1_SEC_3:Sys Return Air Mixer, !- Name + ZN_1_FLR_1_SEC_3:Sys Zone Equipment Outlet Node, !- Outlet Node Name + ZN_1_FLR_1_SEC_3 Return Air Node; !- Inlet 1 Node Name + +!***** Air Loop: ZN_1_FLR_1_SEC_4:Sys ***** + + AirLoopHVAC, + ZN_1_FLR_1_SEC_4:Sys, !- Name + , !- Controller List Name + ZN_1_FLR_1_SEC_4:Sys Availability Manager List, !- Availability Manager List Name + AUTOSIZE, !- Design Supply Air Flow Rate {m3/s} + ZN_1_FLR_1_SEC_4:Sys Air Loop Branches, !- Branch List Name + , !- Connector List Name + ZN_1_FLR_1_SEC_4:Sys Supply Equipment Inlet Node, !- Supply Side Inlet Node Name + ZN_1_FLR_1_SEC_4:Sys Zone Equipment Outlet Node, !- Demand Side Outlet Node Name + ZN_1_FLR_1_SEC_4:Sys Zone Equipment Inlet Node, !- Demand Side Inlet Node Names + ZN_1_FLR_1_SEC_4:Sys Supply Equipment Outlet Node; !- Supply Side Outlet Node Names + + Sizing:System, + ZN_1_FLR_1_SEC_4:Sys, !- AirLoop Name + SENSIBLE, !- Type of Load to Size On + AUTOSIZE, !- Design Outdoor Air Flow Rate {m3/s} + 0.3, !- Central Heating Maximum System Air Flow Ratio + 7.0, !- Preheat Design Temperature {C} + .008, !- Preheat Design Humidity Ratio {kgWater/kgDryAir} + 11.0, !- Precool Design Temperature {C} + .008, !- Precool Design Humidity Ratio {kgWater/kgDryAir} + 12.8, !- Central Cooling Design Supply Air Temperature {C} + 40.0, !- Central Heating Design Supply Air Temperature {C} + NONCOINCIDENT, !- Type of Zone Sum to Use + NO, !- 100% Outdoor Air in Cooling + NO, !- 100% Outdoor Air in Heating + 0.0085, !- Central Cooling Design Supply Air Humidity Ratio {kgWater/kgDryAir} + 0.008, !- Central Heating Design Supply Air Humidity Ratio {kgWater/kgDryAir} + DesignDay, !- Cooling Supply Air Flow Rate Method + 0.0, !- Cooling Supply Air Flow Rate {m3/s} + , !- Cooling Supply Air Flow Rate Per Floor Area {m3/s-m2} + , !- Cooling Fraction of Autosized Cooling Supply Air Flow Rate + , !- Cooling Supply Air Flow Rate Per Unit Cooling Capacity {m3/s-W} + DesignDay, !- Heating Supply Air Flow Rate Method + 0.0, !- Heating Supply Air Flow Rate {m3/s} + , !- Heating Supply Air Flow Rate Per Floor Area {m3/s-m2} + , !- Heating Fraction of Autosized Heating Supply Air Flow Rate + , !- Heating Fraction of Autosized Cooling Supply Air Flow Rate + , !- Heating Supply Air Flow Rate Per Unit Heating Capacity {m3/s-W} + , !- System Outdoor Air Method + 1.0, !- Zone Maximum Outdoor Air Fraction {dimensionless} + CoolingDesignCapacity, !- Cooling Design Capacity Method + autosize, !- Cooling Design Capacity {W} + , !- Cooling Design Capacity Per Floor Area {W/m2} + , !- Fraction of Autosized Cooling Design Capacity + HeatingDesignCapacity, !- Heating Design Capacity Method + autosize, !- Heating Design Capacity {W} + , !- Heating Design Capacity Per Floor Area {W/m2} + , !- Fraction of Autosized Heating Design Capacity + VAV; !- Central Cooling Capacity Control Method + + AvailabilityManagerAssignmentList, + ZN_1_FLR_1_SEC_4:Sys Availability Manager List, !- Name + AvailabilityManager:NightCycle, !- Availability Manager 1 Object Type + ZN_1_FLR_1_SEC_4:Sys Availability Manager; !- Availability Manager 1 Name + + AvailabilityManager:NightCycle, + ZN_1_FLR_1_SEC_4:Sys Availability Manager, !- Name + Always_On, !- Applicability Schedule Name + HVACOperationSchd, !- Fan Schedule Name + CycleOnAny, !- Control Type + 1.0, !- Thermostat Tolerance {deltaC} + FixedRunTime, !- Cycling Run Time Control Type + 7200; !- Cycling Run Time {s} + + BranchList, + ZN_1_FLR_1_SEC_4:Sys Air Loop Branches, !- Name + ZN_1_FLR_1_SEC_4:Sys Air Loop Main Branch; !- Branch 1 Name + + Branch, + ZN_1_FLR_1_SEC_4:Sys Air Loop Main Branch, !- Name + , !- Pressure Drop Curve Name + AirLoopHVAC:OutdoorAirSystem, !- Component 1 Object Type + ZN_1_FLR_1_SEC_4:Sys_OA, !- Component 1 Name + ZN_1_FLR_1_SEC_4:Sys Supply Equipment Inlet Node, !- Component 1 Inlet Node Name + ZN_1_FLR_1_SEC_4:Sys_OA-ZN_1_FLR_1_SEC_4:SysCoolCNode, !- Component 1 Outlet Node Name + CoilSystem:Cooling:DX, !- Component 2 Object Type + ZN_1_FLR_1_SEC_4:SysCoolC, !- Component 2 Name + ZN_1_FLR_1_SEC_4:Sys_OA-ZN_1_FLR_1_SEC_4:SysCoolCNode, !- Component 2 Inlet Node Name + ZN_1_FLR_1_SEC_4:SysCoolC-ZN_1_FLR_1_SEC_4:SysHeatCNode, !- Component 2 Outlet Node Name + Coil:Heating:Electric, !- Component 3 Object Type + ZN_1_FLR_1_SEC_4:SysHeatC, !- Component 3 Name + ZN_1_FLR_1_SEC_4:SysCoolC-ZN_1_FLR_1_SEC_4:SysHeatCNode, !- Component 3 Inlet Node Name + ZN_1_FLR_1_SEC_4:SysHeatC-ZN_1_FLR_1_SEC_4:Sys FanNode, !- Component 3 Outlet Node Name + Fan:ConstantVolume, !- Component 4 Object Type + ZN_1_FLR_1_SEC_4:Sys Fan,!- Component 4 Name + ZN_1_FLR_1_SEC_4:SysHeatC-ZN_1_FLR_1_SEC_4:Sys FanNode, !- Component 4 Inlet Node Name + ZN_1_FLR_1_SEC_4:Sys Supply Equipment Outlet Node; !- Component 4 Outlet Node Name + + AirLoopHVAC:ControllerList, + ZN_1_FLR_1_SEC_4:Sys_OAControllers, !- Name + Controller:OutdoorAir, !- Controller 1 Object Type + ControllerZN_1_FLR_1_SEC_4:Sys_OA; !- Controller 1 Name + + AirLoopHVAC:OutdoorAirSystem:EquipmentList, + ZN_1_FLR_1_SEC_4:Sys_OAEquipment, !- Name + OutdoorAir:Mixer, !- Component 1 Object Type + ZN_1_FLR_1_SEC_4:Sys_OAMixing Box; !- Component 1 Name + + AirLoopHVAC:OutdoorAirSystem, + ZN_1_FLR_1_SEC_4:Sys_OA, !- Name + ZN_1_FLR_1_SEC_4:Sys_OAControllers, !- Controller List Name + ZN_1_FLR_1_SEC_4:Sys_OAEquipment, !- Outdoor Air Equipment List Name + ZN_1_FLR_1_SEC_4:Sys Availability Manager List; !- Availability Manager List Name + + OutdoorAir:NodeList, + ZN_1_FLR_1_SEC_4:Sys_OANode List; !- Node or NodeList Name 1 + + NodeList, + ZN_1_FLR_1_SEC_4:Sys_OANode List, !- Name + ZN_1_FLR_1_SEC_4:Sys_OAInlet Node; !- Node 1 Name + + OutdoorAir:Mixer, + ZN_1_FLR_1_SEC_4:Sys_OAMixing Box, !- Name + ZN_1_FLR_1_SEC_4:Sys_OA-ZN_1_FLR_1_SEC_4:SysCoolCNode, !- Mixed Air Node Name + ZN_1_FLR_1_SEC_4:Sys_OAInlet Node, !- Outdoor Air Stream Node Name + ZN_1_FLR_1_SEC_4:Sys_OARelief Node, !- Relief Air Stream Node Name + ZN_1_FLR_1_SEC_4:Sys Supply Equipment Inlet Node; !- Return Air Stream Node Name + + SetpointManager:MixedAir, + ZN_1_FLR_1_SEC_4:Sys_OAMixed Air Temp Manager, !- Name + Temperature, !- Control Variable + ZN_1_FLR_1_SEC_4:Sys Supply Equipment Outlet Node, !- Reference Setpoint Node Name + ZN_1_FLR_1_SEC_4:SysHeatC-ZN_1_FLR_1_SEC_4:Sys FanNode, !- Fan Inlet Node Name + ZN_1_FLR_1_SEC_4:Sys Supply Equipment Outlet Node, !- Fan Outlet Node Name + ZN_1_FLR_1_SEC_4:Sys_OA-ZN_1_FLR_1_SEC_4:SysCoolCNode; !- Setpoint Node or NodeList Name + + Controller:OutdoorAir, + ControllerZN_1_FLR_1_SEC_4:Sys_OA, !- Name + ZN_1_FLR_1_SEC_4:Sys_OARelief Node, !- Relief Air Outlet Node Name + ZN_1_FLR_1_SEC_4:Sys Supply Equipment Inlet Node, !- Return Air Node Name + ZN_1_FLR_1_SEC_4:Sys_OA-ZN_1_FLR_1_SEC_4:SysCoolCNode, !- Mixed Air Node Name + ZN_1_FLR_1_SEC_4:Sys_OAInlet Node, !- Actuator Node Name + AUTOSIZE, !- Minimum Outdoor Air Flow Rate {m3/s} + AUTOSIZE, !- Maximum Outdoor Air Flow Rate {m3/s} + NoEconomizer, !- Economizer Control Type + ModulateFlow, !- Economizer Control Action Type + 19.0, !- Economizer Maximum Limit Dry-Bulb Temperature {C} + 32000.0, !- Economizer Maximum Limit Enthalpy {J/kg} + , !- Economizer Maximum Limit Dewpoint Temperature {C} + , !- Electronic Enthalpy Limit Curve Name + , !- Economizer Minimum Limit Dry-Bulb Temperature {C} + NoLockout, !- Lockout Type + FixedMinimum, !- Minimum Limit Type + MinOA_Sched; !- Minimum Outdoor Air Schedule Name + + CoilSystem:Cooling:DX, + ZN_1_FLR_1_SEC_4:SysCoolC, !- Name + ALWAYS_ON, !- Availability Schedule Name + ZN_1_FLR_1_SEC_4:Sys_OA-ZN_1_FLR_1_SEC_4:SysCoolCNode, !- DX Cooling Coil System Inlet Node Name + ZN_1_FLR_1_SEC_4:SysCoolC-ZN_1_FLR_1_SEC_4:SysHeatCNode, !- DX Cooling Coil System Outlet Node Name + ZN_1_FLR_1_SEC_4:Sys Supply Equipment Outlet Node, !- DX Cooling Coil System Sensor Node Name + Coil:Cooling:DX:SingleSpeed, !- Cooling Coil Object Type + ZN_1_FLR_1_SEC_4:SysCoolC DXCoil; !- Cooling Coil Name + + Coil:Cooling:DX:SingleSpeed, + ZN_1_FLR_1_SEC_4:SysCoolC DXCoil, !- Name + ALWAYS_ON, !- Availability Schedule Name + AUTOSIZE, !- Gross Rated Total Cooling Capacity {W} + AUTOSIZE, !- Gross Rated Sensible Heat Ratio + 2.7835, !- Gross Rated Cooling COP {W/W} + AUTOSIZE, !- Rated Air Flow Rate {m3/s} + , !- Rated Evaporator Fan Power Per Volume Flow Rate {W/(m3/s)} + ZN_1_FLR_1_SEC_4:Sys_OA-ZN_1_FLR_1_SEC_4:SysCoolCNode, !- Air Inlet Node Name + ZN_1_FLR_1_SEC_4:SysCoolC-ZN_1_FLR_1_SEC_4:SysHeatCNode, !- Air Outlet Node Name + ZN_1_FLR_1_SEC_4:SysCoolCCarrier48TM014_12tons_CapFT, !- Total Cooling Capacity Function of Temperature Curve Name + ZN_1_FLR_1_SEC_4:SysCoolCCarrier48TM014_12tons_FFF, !- Total Cooling Capacity Function of Flow Fraction Curve Name + ZN_1_FLR_1_SEC_4:SysCoolCCarrier48TM014_12tons_EIRFT, !- Energy Input Ratio Function of Temperature Curve Name + ZN_1_FLR_1_SEC_4:SysCoolCCarrier48TM014_12tons_EIRFFF, !- Energy Input Ratio Function of Flow Fraction Curve Name + ZN_1_FLR_1_SEC_4:SysCoolCIEA_HVAC_BESTEST_9ton-PLR; !- Part Load Fraction Correlation Curve Name + + Curve:Biquadratic, + ZN_1_FLR_1_SEC_4:SysCoolCCarrier48TM014_12tons_CapFT, !- Name + 1.39072, !- Coefficient1 Constant + -0.0529058, !- Coefficient2 x + 0.0018423, !- Coefficient3 x**2 + 0.00058267, !- Coefficient4 y + -0.000186814, !- Coefficient5 y**2 + 0.000265159, !- Coefficient6 x*y + 16.5556, !- Minimum Value of x + 22.1111, !- Maximum Value of x + 18.0, !- Minimum Value of y + 47.66, !- Maximum Value of y + , !- Minimum Curve Output + , !- Maximum Curve Output + Temperature, !- Input Unit Type for X + Temperature, !- Input Unit Type for Y + Dimensionless; !- Output Unit Type + + Curve:Biquadratic, + ZN_1_FLR_1_SEC_4:SysCoolCCarrier48TM014_12tons_EIRFT, !- Name + -0.536161, !- Coefficient1 Constant + 0.105138, !- Coefficient2 x + -0.00172659, !- Coefficient3 x**2 + 0.0149848, !- Coefficient4 y + 0.000659948, !- Coefficient5 y**2 + -0.0017385, !- Coefficient6 x*y + 16.5556, !- Minimum Value of x + 22.1111, !- Maximum Value of x + 18.0, !- Minimum Value of y + 47.66, !- Maximum Value of y + , !- Minimum Curve Output + , !- Maximum Curve Output + Temperature, !- Input Unit Type for X + Temperature, !- Input Unit Type for Y + Dimensionless; !- Output Unit Type + + Curve:Quadratic, + ZN_1_FLR_1_SEC_4:SysCoolCCarrier48TM014_12tons_FFF, !- Name + 0.718954, !- Coefficient1 Constant + 0.435436, !- Coefficient2 x + -0.154193, !- Coefficient3 x**2 + 0.75, !- Minimum Value of x + 1.25; !- Maximum Value of x + + Curve:Quadratic, + ZN_1_FLR_1_SEC_4:SysCoolCCarrier48TM014_12tons_EIRFFF, !- Name + 1.19525, !- Coefficient1 Constant + -0.306138, !- Coefficient2 x + 0.110973, !- Coefficient3 x**2 + 0.75, !- Minimum Value of x + 1.25; !- Maximum Value of x + + Curve:Quadratic, + ZN_1_FLR_1_SEC_4:SysCoolCIEA_HVAC_BESTEST_9ton-PLR, !- Name + 0.771, !- Coefficient1 Constant + 0.229, !- Coefficient2 x + 0.0, !- Coefficient3 x**2 + 0.0, !- Minimum Value of x + 1.0; !- Maximum Value of x + + OutdoorAir:Node, + ZN_1_FLR_1_SEC_4:SysCoolCOA Ref node; !- Name + + Coil:Heating:Electric, + ZN_1_FLR_1_SEC_4:SysHeatC, !- Name + ALWAYS_ON, !- Availability Schedule Name + 1.0, !- Efficiency + AUTOSIZE, !- Nominal Capacity {W} + ZN_1_FLR_1_SEC_4:SysCoolC-ZN_1_FLR_1_SEC_4:SysHeatCNode, !- Air Inlet Node Name + ZN_1_FLR_1_SEC_4:SysHeatC-ZN_1_FLR_1_SEC_4:Sys FanNode, !- Air Outlet Node Name + ZN_1_FLR_1_SEC_4:Sys Supply Equipment Outlet Node; !- Temperature Setpoint Node Name + + Fan:ConstantVolume, + ZN_1_FLR_1_SEC_4:Sys Fan,!- Name + HVACOperationSchd, !- Availability Schedule Name + 0.55, !- Fan Total Efficiency + 500, !- Pressure Rise {Pa} + AUTOSIZE, !- Maximum Flow Rate {m3/s} + 0.85, !- Motor Efficiency + 1.0, !- Motor In Airstream Fraction + ZN_1_FLR_1_SEC_4:SysHeatC-ZN_1_FLR_1_SEC_4:Sys FanNode, !- Air Inlet Node Name + ZN_1_FLR_1_SEC_4:Sys Supply Equipment Outlet Node; !- Air Outlet Node Name + + AirLoopHVAC:SupplyPath, + ZN_1_FLR_1_SEC_4:Sys, !- Name + ZN_1_FLR_1_SEC_4:Sys Zone Equipment Inlet Node, !- Supply Air Path Inlet Node Name + AirLoopHVAC:ZoneSplitter,!- Component 1 Object Type + ZN_1_FLR_1_SEC_4:Sys Supply Air Splitter; !- Component 1 Name + + AirLoopHVAC:ZoneSplitter, + ZN_1_FLR_1_SEC_4:Sys Supply Air Splitter, !- Name + ZN_1_FLR_1_SEC_4:Sys Zone Equipment Inlet Node, !- Inlet Node Name + ZN_1_FLR_1_SEC_4 Direct Air Inlet Node ATInlet; !- Outlet 1 Node Name + + AirLoopHVAC:ReturnPath, + ZN_1_FLR_1_SEC_4:Sys Return Air Path, !- Name + ZN_1_FLR_1_SEC_4:Sys Zone Equipment Outlet Node, !- Return Air Path Outlet Node Name + AirLoopHVAC:ZoneMixer, !- Component 1 Object Type + ZN_1_FLR_1_SEC_4:Sys Return Air Mixer; !- Component 1 Name + + AirLoopHVAC:ZoneMixer, + ZN_1_FLR_1_SEC_4:Sys Return Air Mixer, !- Name + ZN_1_FLR_1_SEC_4:Sys Zone Equipment Outlet Node, !- Outlet Node Name + ZN_1_FLR_1_SEC_4 Return Air Node; !- Inlet 1 Node Name + +!***** Air Loop: ZN_1_FLR_1_SEC_5:Sys ***** + + AirLoopHVAC, + ZN_1_FLR_1_SEC_5:Sys, !- Name + , !- Controller List Name + ZN_1_FLR_1_SEC_5:Sys Availability Manager List, !- Availability Manager List Name + AUTOSIZE, !- Design Supply Air Flow Rate {m3/s} + ZN_1_FLR_1_SEC_5:Sys Air Loop Branches, !- Branch List Name + , !- Connector List Name + ZN_1_FLR_1_SEC_5:Sys Supply Equipment Inlet Node, !- Supply Side Inlet Node Name + ZN_1_FLR_1_SEC_5:Sys Zone Equipment Outlet Node, !- Demand Side Outlet Node Name + ZN_1_FLR_1_SEC_5:Sys Zone Equipment Inlet Node, !- Demand Side Inlet Node Names + ZN_1_FLR_1_SEC_5:Sys Supply Equipment Outlet Node; !- Supply Side Outlet Node Names + + Sizing:System, + ZN_1_FLR_1_SEC_5:Sys, !- AirLoop Name + SENSIBLE, !- Type of Load to Size On + AUTOSIZE, !- Design Outdoor Air Flow Rate {m3/s} + 0.3, !- Central Heating Maximum System Air Flow Ratio + 7.0, !- Preheat Design Temperature {C} + .008, !- Preheat Design Humidity Ratio {kgWater/kgDryAir} + 11.0, !- Precool Design Temperature {C} + .008, !- Precool Design Humidity Ratio {kgWater/kgDryAir} + 12.8, !- Central Cooling Design Supply Air Temperature {C} + 40.0, !- Central Heating Design Supply Air Temperature {C} + NONCOINCIDENT, !- Type of Zone Sum to Use + NO, !- 100% Outdoor Air in Cooling + NO, !- 100% Outdoor Air in Heating + 0.0085, !- Central Cooling Design Supply Air Humidity Ratio {kgWater/kgDryAir} + 0.008, !- Central Heating Design Supply Air Humidity Ratio {kgWater/kgDryAir} + DesignDay, !- Cooling Supply Air Flow Rate Method + 0.0, !- Cooling Supply Air Flow Rate {m3/s} + , !- Cooling Supply Air Flow Rate Per Floor Area {m3/s-m2} + , !- Cooling Fraction of Autosized Cooling Supply Air Flow Rate + , !- Cooling Supply Air Flow Rate Per Unit Cooling Capacity {m3/s-W} + DesignDay, !- Heating Supply Air Flow Rate Method + 0.0, !- Heating Supply Air Flow Rate {m3/s} + , !- Heating Supply Air Flow Rate Per Floor Area {m3/s-m2} + , !- Heating Fraction of Autosized Heating Supply Air Flow Rate + , !- Heating Fraction of Autosized Cooling Supply Air Flow Rate + , !- Heating Supply Air Flow Rate Per Unit Heating Capacity {m3/s-W} + , !- System Outdoor Air Method + 1.0, !- Zone Maximum Outdoor Air Fraction {dimensionless} + CoolingDesignCapacity, !- Cooling Design Capacity Method + autosize, !- Cooling Design Capacity {W} + , !- Cooling Design Capacity Per Floor Area {W/m2} + , !- Fraction of Autosized Cooling Design Capacity + HeatingDesignCapacity, !- Heating Design Capacity Method + autosize, !- Heating Design Capacity {W} + , !- Heating Design Capacity Per Floor Area {W/m2} + , !- Fraction of Autosized Heating Design Capacity + VAV; !- Central Cooling Capacity Control Method + + AvailabilityManagerAssignmentList, + ZN_1_FLR_1_SEC_5:Sys Availability Manager List, !- Name + AvailabilityManager:NightCycle, !- Availability Manager 1 Object Type + ZN_1_FLR_1_SEC_5:Sys Availability Manager; !- Availability Manager 1 Name + + AvailabilityManager:NightCycle, + ZN_1_FLR_1_SEC_5:Sys Availability Manager, !- Name + Always_On, !- Applicability Schedule Name + HVACOperationSchd, !- Fan Schedule Name + CycleOnAny, !- Control Type + 1.0, !- Thermostat Tolerance {deltaC} + FixedRunTime, !- Cycling Run Time Control Type + 7200; !- Cycling Run Time {s} + + BranchList, + ZN_1_FLR_1_SEC_5:Sys Air Loop Branches, !- Name + ZN_1_FLR_1_SEC_5:Sys Air Loop Main Branch; !- Branch 1 Name + + Branch, + ZN_1_FLR_1_SEC_5:Sys Air Loop Main Branch, !- Name + , !- Pressure Drop Curve Name + AirLoopHVAC:OutdoorAirSystem, !- Component 1 Object Type + ZN_1_FLR_1_SEC_5:Sys_OA, !- Component 1 Name + ZN_1_FLR_1_SEC_5:Sys Supply Equipment Inlet Node, !- Component 1 Inlet Node Name + ZN_1_FLR_1_SEC_5:Sys_OA-ZN_1_FLR_1_SEC_5:SysCoolCNode, !- Component 1 Outlet Node Name + CoilSystem:Cooling:DX, !- Component 2 Object Type + ZN_1_FLR_1_SEC_5:SysCoolC, !- Component 2 Name + ZN_1_FLR_1_SEC_5:Sys_OA-ZN_1_FLR_1_SEC_5:SysCoolCNode, !- Component 2 Inlet Node Name + ZN_1_FLR_1_SEC_5:SysCoolC-ZN_1_FLR_1_SEC_5:SysHeatCNode, !- Component 2 Outlet Node Name + Coil:Heating:Electric, !- Component 3 Object Type + ZN_1_FLR_1_SEC_5:SysHeatC, !- Component 3 Name + ZN_1_FLR_1_SEC_5:SysCoolC-ZN_1_FLR_1_SEC_5:SysHeatCNode, !- Component 3 Inlet Node Name + ZN_1_FLR_1_SEC_5:SysHeatC-ZN_1_FLR_1_SEC_5:Sys FanNode, !- Component 3 Outlet Node Name + Fan:ConstantVolume, !- Component 4 Object Type + ZN_1_FLR_1_SEC_5:Sys Fan,!- Component 4 Name + ZN_1_FLR_1_SEC_5:SysHeatC-ZN_1_FLR_1_SEC_5:Sys FanNode, !- Component 4 Inlet Node Name + ZN_1_FLR_1_SEC_5:Sys Supply Equipment Outlet Node; !- Component 4 Outlet Node Name + + AirLoopHVAC:ControllerList, + ZN_1_FLR_1_SEC_5:Sys_OAControllers, !- Name + Controller:OutdoorAir, !- Controller 1 Object Type + ControllerZN_1_FLR_1_SEC_5:Sys_OA; !- Controller 1 Name + + AirLoopHVAC:OutdoorAirSystem:EquipmentList, + ZN_1_FLR_1_SEC_5:Sys_OAEquipment, !- Name + OutdoorAir:Mixer, !- Component 1 Object Type + ZN_1_FLR_1_SEC_5:Sys_OAMixing Box; !- Component 1 Name + + AirLoopHVAC:OutdoorAirSystem, + ZN_1_FLR_1_SEC_5:Sys_OA, !- Name + ZN_1_FLR_1_SEC_5:Sys_OAControllers, !- Controller List Name + ZN_1_FLR_1_SEC_5:Sys_OAEquipment, !- Outdoor Air Equipment List Name + ZN_1_FLR_1_SEC_5:Sys Availability Manager List; !- Availability Manager List Name + + OutdoorAir:NodeList, + ZN_1_FLR_1_SEC_5:Sys_OANode List; !- Node or NodeList Name 1 + + NodeList, + ZN_1_FLR_1_SEC_5:Sys_OANode List, !- Name + ZN_1_FLR_1_SEC_5:Sys_OAInlet Node; !- Node 1 Name + + OutdoorAir:Mixer, + ZN_1_FLR_1_SEC_5:Sys_OAMixing Box, !- Name + ZN_1_FLR_1_SEC_5:Sys_OA-ZN_1_FLR_1_SEC_5:SysCoolCNode, !- Mixed Air Node Name + ZN_1_FLR_1_SEC_5:Sys_OAInlet Node, !- Outdoor Air Stream Node Name + ZN_1_FLR_1_SEC_5:Sys_OARelief Node, !- Relief Air Stream Node Name + ZN_1_FLR_1_SEC_5:Sys Supply Equipment Inlet Node; !- Return Air Stream Node Name + + SetpointManager:MixedAir, + ZN_1_FLR_1_SEC_5:Sys_OAMixed Air Temp Manager, !- Name + Temperature, !- Control Variable + ZN_1_FLR_1_SEC_5:Sys Supply Equipment Outlet Node, !- Reference Setpoint Node Name + ZN_1_FLR_1_SEC_5:SysHeatC-ZN_1_FLR_1_SEC_5:Sys FanNode, !- Fan Inlet Node Name + ZN_1_FLR_1_SEC_5:Sys Supply Equipment Outlet Node, !- Fan Outlet Node Name + ZN_1_FLR_1_SEC_5:Sys_OA-ZN_1_FLR_1_SEC_5:SysCoolCNode; !- Setpoint Node or NodeList Name + + Controller:OutdoorAir, + ControllerZN_1_FLR_1_SEC_5:Sys_OA, !- Name + ZN_1_FLR_1_SEC_5:Sys_OARelief Node, !- Relief Air Outlet Node Name + ZN_1_FLR_1_SEC_5:Sys Supply Equipment Inlet Node, !- Return Air Node Name + ZN_1_FLR_1_SEC_5:Sys_OA-ZN_1_FLR_1_SEC_5:SysCoolCNode, !- Mixed Air Node Name + ZN_1_FLR_1_SEC_5:Sys_OAInlet Node, !- Actuator Node Name + AUTOSIZE, !- Minimum Outdoor Air Flow Rate {m3/s} + AUTOSIZE, !- Maximum Outdoor Air Flow Rate {m3/s} + NoEconomizer, !- Economizer Control Type + ModulateFlow, !- Economizer Control Action Type + 19.0, !- Economizer Maximum Limit Dry-Bulb Temperature {C} + 32000.0, !- Economizer Maximum Limit Enthalpy {J/kg} + , !- Economizer Maximum Limit Dewpoint Temperature {C} + , !- Electronic Enthalpy Limit Curve Name + , !- Economizer Minimum Limit Dry-Bulb Temperature {C} + NoLockout, !- Lockout Type + FixedMinimum, !- Minimum Limit Type + MinOA_Sched; !- Minimum Outdoor Air Schedule Name + + CoilSystem:Cooling:DX, + ZN_1_FLR_1_SEC_5:SysCoolC, !- Name + ALWAYS_ON, !- Availability Schedule Name + ZN_1_FLR_1_SEC_5:Sys_OA-ZN_1_FLR_1_SEC_5:SysCoolCNode, !- DX Cooling Coil System Inlet Node Name + ZN_1_FLR_1_SEC_5:SysCoolC-ZN_1_FLR_1_SEC_5:SysHeatCNode, !- DX Cooling Coil System Outlet Node Name + ZN_1_FLR_1_SEC_5:Sys Supply Equipment Outlet Node, !- DX Cooling Coil System Sensor Node Name + Coil:Cooling:DX:SingleSpeed, !- Cooling Coil Object Type + ZN_1_FLR_1_SEC_5:SysCoolC DXCoil; !- Cooling Coil Name + + Coil:Cooling:DX:SingleSpeed, + ZN_1_FLR_1_SEC_5:SysCoolC DXCoil, !- Name + ALWAYS_ON, !- Availability Schedule Name + AUTOSIZE, !- Gross Rated Total Cooling Capacity {W} + AUTOSIZE, !- Gross Rated Sensible Heat Ratio + 2.7835, !- Gross Rated Cooling COP {W/W} + AUTOSIZE, !- Rated Air Flow Rate {m3/s} + , !- Rated Evaporator Fan Power Per Volume Flow Rate {W/(m3/s)} + ZN_1_FLR_1_SEC_5:Sys_OA-ZN_1_FLR_1_SEC_5:SysCoolCNode, !- Air Inlet Node Name + ZN_1_FLR_1_SEC_5:SysCoolC-ZN_1_FLR_1_SEC_5:SysHeatCNode, !- Air Outlet Node Name + ZN_1_FLR_1_SEC_5:SysCoolCCarrier48TM014_12tons_CapFT, !- Total Cooling Capacity Function of Temperature Curve Name + ZN_1_FLR_1_SEC_5:SysCoolCCarrier48TM014_12tons_FFF, !- Total Cooling Capacity Function of Flow Fraction Curve Name + ZN_1_FLR_1_SEC_5:SysCoolCCarrier48TM014_12tons_EIRFT, !- Energy Input Ratio Function of Temperature Curve Name + ZN_1_FLR_1_SEC_5:SysCoolCCarrier48TM014_12tons_EIRFFF, !- Energy Input Ratio Function of Flow Fraction Curve Name + ZN_1_FLR_1_SEC_5:SysCoolCIEA_HVAC_BESTEST_9ton-PLR; !- Part Load Fraction Correlation Curve Name + + Curve:Biquadratic, + ZN_1_FLR_1_SEC_5:SysCoolCCarrier48TM014_12tons_CapFT, !- Name + 1.39072, !- Coefficient1 Constant + -0.0529058, !- Coefficient2 x + 0.0018423, !- Coefficient3 x**2 + 0.00058267, !- Coefficient4 y + -0.000186814, !- Coefficient5 y**2 + 0.000265159, !- Coefficient6 x*y + 16.5556, !- Minimum Value of x + 22.1111, !- Maximum Value of x + 18.0, !- Minimum Value of y + 47.66, !- Maximum Value of y + , !- Minimum Curve Output + , !- Maximum Curve Output + Temperature, !- Input Unit Type for X + Temperature, !- Input Unit Type for Y + Dimensionless; !- Output Unit Type + + Curve:Biquadratic, + ZN_1_FLR_1_SEC_5:SysCoolCCarrier48TM014_12tons_EIRFT, !- Name + -0.536161, !- Coefficient1 Constant + 0.105138, !- Coefficient2 x + -0.00172659, !- Coefficient3 x**2 + 0.0149848, !- Coefficient4 y + 0.000659948, !- Coefficient5 y**2 + -0.0017385, !- Coefficient6 x*y + 16.5556, !- Minimum Value of x + 22.1111, !- Maximum Value of x + 18.0, !- Minimum Value of y + 47.66, !- Maximum Value of y + , !- Minimum Curve Output + , !- Maximum Curve Output + Temperature, !- Input Unit Type for X + Temperature, !- Input Unit Type for Y + Dimensionless; !- Output Unit Type + + Curve:Quadratic, + ZN_1_FLR_1_SEC_5:SysCoolCCarrier48TM014_12tons_FFF, !- Name + 0.718954, !- Coefficient1 Constant + 0.435436, !- Coefficient2 x + -0.154193, !- Coefficient3 x**2 + 0.75, !- Minimum Value of x + 1.25; !- Maximum Value of x + + Curve:Quadratic, + ZN_1_FLR_1_SEC_5:SysCoolCCarrier48TM014_12tons_EIRFFF, !- Name + 1.19525, !- Coefficient1 Constant + -0.306138, !- Coefficient2 x + 0.110973, !- Coefficient3 x**2 + 0.75, !- Minimum Value of x + 1.25; !- Maximum Value of x + + Curve:Quadratic, + ZN_1_FLR_1_SEC_5:SysCoolCIEA_HVAC_BESTEST_9ton-PLR, !- Name + 0.771, !- Coefficient1 Constant + 0.229, !- Coefficient2 x + 0.0, !- Coefficient3 x**2 + 0.0, !- Minimum Value of x + 1.0; !- Maximum Value of x + + OutdoorAir:Node, + ZN_1_FLR_1_SEC_5:SysCoolCOA Ref node; !- Name + + Coil:Heating:Electric, + ZN_1_FLR_1_SEC_5:SysHeatC, !- Name + ALWAYS_ON, !- Availability Schedule Name + 1.0, !- Efficiency + AUTOSIZE, !- Nominal Capacity {W} + ZN_1_FLR_1_SEC_5:SysCoolC-ZN_1_FLR_1_SEC_5:SysHeatCNode, !- Air Inlet Node Name + ZN_1_FLR_1_SEC_5:SysHeatC-ZN_1_FLR_1_SEC_5:Sys FanNode, !- Air Outlet Node Name + ZN_1_FLR_1_SEC_5:Sys Supply Equipment Outlet Node; !- Temperature Setpoint Node Name + + Fan:ConstantVolume, + ZN_1_FLR_1_SEC_5:Sys Fan,!- Name + HVACOperationSchd, !- Availability Schedule Name + 0.55, !- Fan Total Efficiency + 500, !- Pressure Rise {Pa} + AUTOSIZE, !- Maximum Flow Rate {m3/s} + 0.85, !- Motor Efficiency + 1.0, !- Motor In Airstream Fraction + ZN_1_FLR_1_SEC_5:SysHeatC-ZN_1_FLR_1_SEC_5:Sys FanNode, !- Air Inlet Node Name + ZN_1_FLR_1_SEC_5:Sys Supply Equipment Outlet Node; !- Air Outlet Node Name + + AirLoopHVAC:SupplyPath, + ZN_1_FLR_1_SEC_5:Sys, !- Name + ZN_1_FLR_1_SEC_5:Sys Zone Equipment Inlet Node, !- Supply Air Path Inlet Node Name + AirLoopHVAC:ZoneSplitter,!- Component 1 Object Type + ZN_1_FLR_1_SEC_5:Sys Supply Air Splitter; !- Component 1 Name + + AirLoopHVAC:ZoneSplitter, + ZN_1_FLR_1_SEC_5:Sys Supply Air Splitter, !- Name + ZN_1_FLR_1_SEC_5:Sys Zone Equipment Inlet Node, !- Inlet Node Name + ZN_1_FLR_1_SEC_5 Direct Air Inlet Node ATInlet; !- Outlet 1 Node Name + + AirLoopHVAC:ReturnPath, + ZN_1_FLR_1_SEC_5:Sys Return Air Path, !- Name + ZN_1_FLR_1_SEC_5:Sys Zone Equipment Outlet Node, !- Return Air Path Outlet Node Name + AirLoopHVAC:ZoneMixer, !- Component 1 Object Type + ZN_1_FLR_1_SEC_5:Sys Return Air Mixer; !- Component 1 Name + + AirLoopHVAC:ZoneMixer, + ZN_1_FLR_1_SEC_5:Sys Return Air Mixer, !- Name + ZN_1_FLR_1_SEC_5:Sys Zone Equipment Outlet Node, !- Outlet Node Name + ZN_1_FLR_1_SEC_5 Return Air Node; !- Inlet 1 Node Name + +!***** PLANT Loop: SHWSys1 ***** + + PlantLoop, + SHWSys1, !- Name + WATER, !- Fluid Type + , !- User Defined Fluid Type + SHWSys1 Loop Operation Scheme List, !- Plant Equipment Operation Scheme Name + SHWSys1 Supply Outlet Node, !- Loop Temperature Setpoint Node Name + 60.0, !- Maximum Loop Temperature {C} + 10.0, !- Minimum Loop Temperature {C} + AUTOSIZE, !- Maximum Loop Flow Rate {m3/s} + 0.0, !- Minimum Loop Flow Rate {m3/s} + AUTOSIZE, !- Plant Loop Volume {m3} + SHWSys1 Supply Inlet Node, !- Plant Side Inlet Node Name + SHWSys1 Supply Outlet Node, !- Plant Side Outlet Node Name + SHWSys1 Supply Branches, !- Plant Side Branch List Name + SHWSys1 Supply Connectors, !- Plant Side Connector List Name + SHWSys1 Demand Inlet Node, !- Demand Side Inlet Node Name + SHWSys1 Demand Outlet Node, !- Demand Side Outlet Node Name + SHWSys1 Demand Branches, !- Demand Side Branch List Name + SHWSys1 Demand Connectors, !- Demand Side Connector List Name + OPTIMAL; !- Load Distribution Scheme + + Sizing:Plant, + SHWSys1, !- Plant or Condenser Loop Name + HEATING, !- Loop Type + 55, !- Design Loop Exit Temperature {C} + 5.0; !- Loop Design Temperature Difference {deltaC} + + SetpointManager:Scheduled, + SHWSys1 Loop Setpoint Manager, !- Name + Temperature, !- Control Variable + SHWSys1-Loop-Temp-Schedule, !- Schedule Name + SHWSys1 Supply Outlet Node; !- Setpoint Node or NodeList Name + + PlantEquipmentOperationSchemes, + SHWSys1 Loop Operation Scheme List, !- Name + PlantEquipmentOperation:HeatingLoad, !- Control Scheme 1 Object Type + SHWSys1 Operation Scheme,!- Control Scheme 1 Name + PlantOnSched; !- Control Scheme 1 Schedule Name + + PlantEquipmentOperation:HeatingLoad, + SHWSys1 Operation Scheme,!- Name + 0.0, !- Load Range 1 Lower Limit {W} + 1000000000000000, !- Load Range 1 Upper Limit {W} + SHWSys1 Equipment List; !- Range 1 Equipment List Name + + Schedule:Compact, + SHWSys1-Loop-Temp-Schedule, !- Name + Temperature, !- Schedule Type Limits Name + Through: 12/31, !- Field 1 + For: AllDays, !- Field 2 + Until: 24:00,55; !- Field 3 + + PlantEquipmentList, + SHWSys1 Equipment List, !- Name + WaterHeater:Mixed, !- Equipment 1 Object Type + SHWSys1 Water Heater; !- Equipment 1 Name + + BranchList, + SHWSys1 Supply Branches, !- Name + SHWSys1 Supply Inlet Branch, !- Branch 1 Name + SHWSys1 Supply Equipment Branch, !- Branch 2 Name + SHWSys1 Supply Equipment Bypass Branch, !- Branch 3 Name + SHWSys1 Supply Outlet Branch; !- Branch 4 Name + + ConnectorList, + SHWSys1 Supply Connectors, !- Name + Connector:Splitter, !- Connector 1 Object Type + SHWSys1 Supply Splitter, !- Connector 1 Name + Connector:Mixer, !- Connector 2 Object Type + SHWSys1 Supply Mixer; !- Connector 2 Name + + Connector:Splitter, + SHWSys1 Supply Splitter, !- Name + SHWSys1 Supply Inlet Branch, !- Inlet Branch Name + SHWSys1 Supply Equipment Branch, !- Outlet Branch 1 Name + SHWSys1 Supply Equipment Bypass Branch; !- Outlet Branch 2 Name + + Connector:Mixer, + SHWSys1 Supply Mixer, !- Name + SHWSys1 Supply Outlet Branch, !- Outlet Branch Name + SHWSys1 Supply Equipment Branch, !- Inlet Branch 1 Name + SHWSys1 Supply Equipment Bypass Branch; !- Inlet Branch 2 Name + + Branch, + SHWSys1 Supply Inlet Branch, !- Name + , !- Pressure Drop Curve Name + Pump:VariableSpeed, !- Component 1 Object Type + SHWSys1 Pump, !- Component 1 Name + SHWSys1 Supply Inlet Node, !- Component 1 Inlet Node Name + SHWSys1 Pump-SHWSys1 Water HeaterNodeviaConnector; !- Component 1 Outlet Node Name + + Branch, + SHWSys1 Supply Equipment Branch, !- Name + , !- Pressure Drop Curve Name + WaterHeater:Mixed, !- Component 1 Object Type + SHWSys1 Water Heater, !- Component 1 Name + SHWSys1 Pump-SHWSys1 Water HeaterNode, !- Component 1 Inlet Node Name + SHWSys1 Supply Equipment Outlet Node; !- Component 1 Outlet Node Name + + Pump:VariableSpeed, + SHWSys1 Pump, !- Name + SHWSys1 Supply Inlet Node, !- Inlet Node Name + SHWSys1 Pump-SHWSys1 Water HeaterNodeviaConnector, !- Outlet Node Name + AUTOSIZE, !- Design Maximum Flow Rate {m3/s} + 179352, !- Design Pump Head {Pa} + AUTOSIZE, !- Design Power Consumption {W} + 1, !- Motor Efficiency + 0.0, !- Fraction of Motor Inefficiencies to Fluid Stream + 0, !- Coefficient 1 of the Part Load Performance Curve + 1, !- Coefficient 2 of the Part Load Performance Curve + 0, !- Coefficient 3 of the Part Load Performance Curve + 0, !- Coefficient 4 of the Part Load Performance Curve + 0.0, !- Design Minimum Flow Rate {m3/s} + INTERMITTENT; !- Pump Control Type + + WaterHeater:Mixed, + SHWSys1 Water Heater, !- Name + 0.9, !- Tank Volume {m3} + SHWSys1 Water Heater Setpoint Temperature Schedule, !- Setpoint Temperature Schedule Name + 2.0, !- Deadband Temperature Difference {deltaC} + 82.2222, !- Maximum Temperature Limit {C} + CYCLE, !- Heater Control Type + 4500, !- Heater Maximum Capacity {W} + , !- Heater Minimum Capacity {W} + , !- Heater Ignition Minimum Flow Rate {m3/s} + , !- Heater Ignition Delay {s} + Electricity, !- Heater Fuel Type + 0.595, !- Heater Thermal Efficiency + , !- Part Load Factor Curve Name + 20, !- Off Cycle Parasitic Fuel Consumption Rate {W} + Electricity, !- Off Cycle Parasitic Fuel Type + 0.595, !- Off Cycle Parasitic Heat Fraction to Tank + , !- On Cycle Parasitic Fuel Consumption Rate {W} + Electricity, !- On Cycle Parasitic Fuel Type + , !- On Cycle Parasitic Heat Fraction to Tank + SCHEDULE, !- Ambient Temperature Indicator + SHWSys1 Water Heater Ambient Temperature Schedule, !- Ambient Temperature Schedule Name + , !- Ambient Temperature Zone Name + , !- Ambient Temperature Outdoor Air Node Name + 6.0, !- Off Cycle Loss Coefficient to Ambient Temperature {W/K} + , !- Off Cycle Loss Fraction to Zone + 6.0, !- On Cycle Loss Coefficient to Ambient Temperature {W/K} + , !- On Cycle Loss Fraction to Zone + , !- Peak Use Flow Rate {m3/s} + , !- Use Flow Rate Fraction Schedule Name + , !- Cold Water Supply Temperature Schedule Name + SHWSys1 Pump-SHWSys1 Water HeaterNode, !- Use Side Inlet Node Name + SHWSys1 Supply Equipment Outlet Node, !- Use Side Outlet Node Name + 1.0, !- Use Side Effectiveness + , !- Source Side Inlet Node Name + , !- Source Side Outlet Node Name + 1.0, !- Source Side Effectiveness + Autosize, !- Use Side Design Flow Rate {m3/s} + , !- Source Side Design Flow Rate {m3/s} + ; !- Indirect Water Heating Recovery Time {hr} + + Schedule:Compact, + SHWSys1 Water Heater Setpoint Temperature Schedule, !- Name + Temperature, !- Schedule Type Limits Name + Through: 12/31, !- Field 1 + For: AllDays, !- Field 2 + Until: 24:00,60.0; !- Field 3 + + Schedule:Compact, + SHWSys1 Water Heater Ambient Temperature Schedule, !- Name + Temperature, !- Schedule Type Limits Name + Through: 12/31, !- Field 1 + For: AllDays, !- Field 2 + Until: 24:00,22.0; !- Field 3 + + Branch, + SHWSys1 Supply Equipment Bypass Branch, !- Name + , !- Pressure Drop Curve Name + Pipe:Adiabatic, !- Component 1 Object Type + SHWSys1 Supply Equipment Bypass Pipe, !- Component 1 Name + SHWSys1 Supply Equip Bypass Inlet Node, !- Component 1 Inlet Node Name + SHWSys1 Supply Equip Bypass Outlet Node; !- Component 1 Outlet Node Name + + Pipe:Adiabatic, + SHWSys1 Supply Equipment Bypass Pipe, !- Name + SHWSys1 Supply Equip Bypass Inlet Node, !- Inlet Node Name + SHWSys1 Supply Equip Bypass Outlet Node; !- Outlet Node Name + + Branch, + SHWSys1 Supply Outlet Branch, !- Name + , !- Pressure Drop Curve Name + Pipe:Adiabatic, !- Component 1 Object Type + SHWSys1 Supply Outlet Pipe, !- Component 1 Name + SHWSys1 Supply Mixer-SHWSys1 Supply Outlet Pipe, !- Component 1 Inlet Node Name + SHWSys1 Supply Outlet Node; !- Component 1 Outlet Node Name + + Pipe:Adiabatic, + SHWSys1 Supply Outlet Pipe, !- Name + SHWSys1 Supply Mixer-SHWSys1 Supply Outlet Pipe, !- Inlet Node Name + SHWSys1 Supply Outlet Node; !- Outlet Node Name + + BranchList, + SHWSys1 Demand Branches, !- Name + SHWSys1 Demand Inlet Branch, !- Branch 1 Name + SHWSys1 Demand Load Branch 1, !- Branch 2 Name + SHWSys1 Demand Load Branch 2, !- Branch 3 Name + SHWSys1 Demand Load Branch 3, !- Branch 4 Name + SHWSys1 Demand Load Branch 4, !- Branch 5 Name + SHWSys1 Demand Load Branch 5, !- Branch 6 Name + SHWSys1 Demand Bypass Branch, !- Branch 7 Name + SHWSys1 Demand Outlet Branch; !- Branch 8 Name + + ConnectorList, + SHWSys1 Demand Connectors, !- Name + Connector:Splitter, !- Connector 1 Object Type + SHWSys1 Demand Splitter, !- Connector 1 Name + Connector:Mixer, !- Connector 2 Object Type + SHWSys1 Demand Mixer; !- Connector 2 Name + + Connector:Splitter, + SHWSys1 Demand Splitter, !- Name + SHWSys1 Demand Inlet Branch, !- Inlet Branch Name + SHWSys1 Demand Load Branch 1, !- Outlet Branch 1 Name + SHWSys1 Demand Load Branch 2, !- Outlet Branch 2 Name + SHWSys1 Demand Load Branch 3, !- Outlet Branch 3 Name + SHWSys1 Demand Load Branch 4, !- Outlet Branch 4 Name + SHWSys1 Demand Load Branch 5, !- Outlet Branch 5 Name + SHWSys1 Demand Bypass Branch; !- Outlet Branch 6 Name + + Connector:Mixer, + SHWSys1 Demand Mixer, !- Name + SHWSys1 Demand Outlet Branch, !- Outlet Branch Name + SHWSys1 Demand Load Branch 1, !- Inlet Branch 1 Name + SHWSys1 Demand Load Branch 2, !- Inlet Branch 2 Name + SHWSys1 Demand Load Branch 3, !- Inlet Branch 3 Name + SHWSys1 Demand Load Branch 4, !- Inlet Branch 4 Name + SHWSys1 Demand Load Branch 5, !- Inlet Branch 5 Name + SHWSys1 Demand Bypass Branch; !- Inlet Branch 6 Name + + Branch, + SHWSys1 Demand Inlet Branch, !- Name + , !- Pressure Drop Curve Name + Pipe:Adiabatic, !- Component 1 Object Type + SHWSys1 Demand Inlet Pipe, !- Component 1 Name + SHWSys1 Demand Inlet Node, !- Component 1 Inlet Node Name + SHWSys1 Demand Inlet Pipe-SHWSys1 Demand Mixer; !- Component 1 Outlet Node Name + + Pipe:Adiabatic, + SHWSys1 Demand Inlet Pipe, !- Name + SHWSys1 Demand Inlet Node, !- Inlet Node Name + SHWSys1 Demand Inlet Pipe-SHWSys1 Demand Mixer; !- Outlet Node Name + + Branch, + SHWSys1 Demand Load Branch 1, !- Name + , !- Pressure Drop Curve Name + WaterUse:Connections, !- Component 1 Object Type + ZN_1_FLR_1_SEC_1SHW_DEFAULT, !- Component 1 Name + ZN_1_FLR_1_SEC_1SHW_DEFAULT Water Inlet Node, !- Component 1 Inlet Node Name + ZN_1_FLR_1_SEC_1SHW_DEFAULT Water Outlet Node; !- Component 1 Outlet Node Name + + Branch, + SHWSys1 Demand Load Branch 2, !- Name + , !- Pressure Drop Curve Name + WaterUse:Connections, !- Component 1 Object Type + ZN_1_FLR_1_SEC_2SHW_DEFAULT, !- Component 1 Name + ZN_1_FLR_1_SEC_2SHW_DEFAULT Water Inlet Node, !- Component 1 Inlet Node Name + ZN_1_FLR_1_SEC_2SHW_DEFAULT Water Outlet Node; !- Component 1 Outlet Node Name + + Branch, + SHWSys1 Demand Load Branch 3, !- Name + , !- Pressure Drop Curve Name + WaterUse:Connections, !- Component 1 Object Type + ZN_1_FLR_1_SEC_3SHW_DEFAULT, !- Component 1 Name + ZN_1_FLR_1_SEC_3SHW_DEFAULT Water Inlet Node, !- Component 1 Inlet Node Name + ZN_1_FLR_1_SEC_3SHW_DEFAULT Water Outlet Node; !- Component 1 Outlet Node Name + + Branch, + SHWSys1 Demand Load Branch 4, !- Name + , !- Pressure Drop Curve Name + WaterUse:Connections, !- Component 1 Object Type + ZN_1_FLR_1_SEC_4SHW_DEFAULT, !- Component 1 Name + ZN_1_FLR_1_SEC_4SHW_DEFAULT Water Inlet Node, !- Component 1 Inlet Node Name + ZN_1_FLR_1_SEC_4SHW_DEFAULT Water Outlet Node; !- Component 1 Outlet Node Name + + Branch, + SHWSys1 Demand Load Branch 5, !- Name + , !- Pressure Drop Curve Name + WaterUse:Connections, !- Component 1 Object Type + ZN_1_FLR_1_SEC_5SHW_DEFAULT, !- Component 1 Name + ZN_1_FLR_1_SEC_5SHW_DEFAULT Water Inlet Node, !- Component 1 Inlet Node Name + ZN_1_FLR_1_SEC_5SHW_DEFAULT Water Outlet Node; !- Component 1 Outlet Node Name + + Branch, + SHWSys1 Demand Bypass Branch, !- Name + , !- Pressure Drop Curve Name + Pipe:Adiabatic, !- Component 1 Object Type + SHWSys1 Demand Bypass Pipe, !- Component 1 Name + SHWSys1 Demand Bypass Pipe Inlet Node, !- Component 1 Inlet Node Name + SHWSys1 Demand Bypass Pipe Outlet Node; !- Component 1 Outlet Node Name + + Pipe:Adiabatic, + SHWSys1 Demand Bypass Pipe, !- Name + SHWSys1 Demand Bypass Pipe Inlet Node, !- Inlet Node Name + SHWSys1 Demand Bypass Pipe Outlet Node; !- Outlet Node Name + + Branch, + SHWSys1 Demand Outlet Branch, !- Name + , !- Pressure Drop Curve Name + Pipe:Adiabatic, !- Component 1 Object Type + SHWSys1 Demand Outlet Pipe, !- Component 1 Name + SHWSys1 Demand Mixer-SHWSys1 Demand Outlet Pipe, !- Component 1 Inlet Node Name + SHWSys1 Demand Outlet Node; !- Component 1 Outlet Node Name + + Pipe:Adiabatic, + SHWSys1 Demand Outlet Pipe, !- Name + SHWSys1 Demand Mixer-SHWSys1 Demand Outlet Pipe, !- Inlet Node Name + SHWSys1 Demand Outlet Node; !- Outlet Node Name + + Exterior:FuelEquipment, + Equipment_SimpleRefrigeration, !- Name + Electricity, !- Fuel Use Type + ALWAYS_ON, !- Schedule Name + 507.2340, !- Design Level {W} + Refrigeration (simple); !- End-Use Subcategory + + Exterior:Lights, + Exterior Facade Lighting,!- Name + ALWAYS_ON, !- Schedule Name + 130.2176, !- Design Level {W} + AstronomicalClock, !- Control Option + Exterior Facade Lighting;!- End-Use Subcategory + + Schedule:Compact, + ReliantEnergySeasonSched,!- Name + number, !- Schedule Type Limits Name + Through: 4/30, !- Field 1 + For: AllDays, !- Field 2 + Until: 24:00,1, !- Field 3 + Through: 10/31, !- Field 5 + For: AllDays, !- Field 6 + Until: 24:00,3, !- Field 7 + Through: 12/31, !- Field 9 + For: AllDays, !- Field 10 + Until: 24:00,1; !- Field 11 + + UtilityCost:Tariff, + ReliantEnergy_PTB-LGS_LargeGeneral, !- Name + Electricity:Facility, !- Output Meter Name + kWh, !- Conversion Factor Choice + , !- Energy Conversion Factor + , !- Demand Conversion Factor + , !- Time of Use Period Schedule Name + ReliantEnergySeasonSched,!- Season Schedule Name + , !- Month Schedule Name + halfHour, !- Demand Window Length + 2936.2, !- Monthly Charge or Variable Name + , !- Minimum Monthly Charge or Variable Name + , !- Real Time Pricing Charge Schedule Name + , !- Customer Baseline Load Schedule Name + Comm Elect; !- Group Name + + UtilityCost:Charge:Simple, + SummerFuelEnergyCharge, !- Utility Cost Charge Simple Name + ReliantEnergy_PTB-LGS_LargeGeneral, !- Tariff Name + totalEnergy, !- Source Variable + Summer, !- Season + EnergyCharges, !- Category Variable Name + 0.0823; !- Cost per Unit Value or Variable Name + + UtilityCost:Charge:Block, + SummerBaseEnergycharge, !- Utility Cost Charge Block Name + ReliantEnergy_PTB-LGS_LargeGeneral, !- Tariff Name + TotalEnergy, !- Source Variable + Summer, !- Season + EnergyCharges, !- Category Variable Name + , !- Remaining Into Variable + TotalDemand, !- Block Size Multiplier Value or Variable Name + 295, !- Block Size 1 Value or Variable Name + 0.0249, !- Block 1 Cost per Unit Value or Variable Name + remaining, !- Block Size 2 Value or Variable Name + 0.0048; !- Block 2 Cost per Unit Value or Variable Name + + UtilityCost:Charge:Simple, + WinterFuelEnergyCharge, !- Utility Cost Charge Simple Name + ReliantEnergy_PTB-LGS_LargeGeneral, !- Tariff Name + totalEnergy, !- Source Variable + Winter, !- Season + EnergyCharges, !- Category Variable Name + 0.0485; !- Cost per Unit Value or Variable Name + + UtilityCost:Charge:Block, + AnnualDemandCharge, !- Utility Cost Charge Block Name + ReliantEnergy_PTB-LGS_LargeGeneral, !- Tariff Name + TotalDemand, !- Source Variable + Annual, !- Season + DemandCharges, !- Category Variable Name + , !- Remaining Into Variable + , !- Block Size Multiplier Value or Variable Name + 400, !- Block Size 1 Value or Variable Name + 0.0, !- Block 1 Cost per Unit Value or Variable Name + remaining, !- Block Size 2 Value or Variable Name + 6.14; !- Block 2 Cost per Unit Value or Variable Name + + UtilityCost:Qualify, + MinDemand400kw, !- Utility Cost Qualify Name + ReliantEnergy_PTB-LGS_LargeGeneral, !- Tariff Name + TotalDemand, !- Variable Name + Minimum, !- Qualify Type + 400, !- Threshold Value or Variable Name + Annual, !- Season + Count, !- Threshold Test + 12; !- Number of Months + + UtilityCost:Charge:Simple, + TaxofEightPtTwoFivePercent, !- Utility Cost Charge Simple Name + ReliantEnergy_PTB-LGS_LargeGeneral, !- Tariff Name + SubTotal, !- Source Variable + Annual, !- Season + Taxes, !- Category Variable Name + 0.0825; !- Cost per Unit Value or Variable Name + +!end ReliantEnergy_PTB-LGS_LargeGeneral + + UtilityCost:Tariff, + ReliantEnergy_PTB-MGS_MiscGeneral, !- Name + Electricity:Facility, !- Output Meter Name + kWh, !- Conversion Factor Choice + , !- Energy Conversion Factor + , !- Demand Conversion Factor + , !- Time of Use Period Schedule Name + ReliantEnergySeasonSched,!- Season Schedule Name + , !- Month Schedule Name + halfHour, !- Demand Window Length + 18.82, !- Monthly Charge or Variable Name + , !- Minimum Monthly Charge or Variable Name + , !- Real Time Pricing Charge Schedule Name + , !- Customer Baseline Load Schedule Name + Comm Elect; !- Group Name + + UtilityCost:Charge:Simple, + SummerFuelEnergyCharge, !- Utility Cost Charge Simple Name + ReliantEnergy_PTB-MGS_MiscGeneral, !- Tariff Name + totalEnergy, !- Source Variable + Summer, !- Season + EnergyCharges, !- Category Variable Name + 0.0823; !- Cost per Unit Value or Variable Name + + UtilityCost:Charge:Block, + SummerBaseEnergycharge, !- Utility Cost Charge Block Name + ReliantEnergy_PTB-MGS_MiscGeneral, !- Tariff Name + TotalEnergy, !- Source Variable + Summer, !- Season + EnergyCharges, !- Category Variable Name + , !- Remaining Into Variable + TotalDemand, !- Block Size Multiplier Value or Variable Name + 125, !- Block Size 1 Value or Variable Name + 0.0521, !- Block 1 Cost per Unit Value or Variable Name + 170, !- Block Size 2 Value or Variable Name + 0.0317, !- Block 2 Cost per Unit Value or Variable Name + remaining, !- Block Size 3 Value or Variable Name + 0.0055; !- Block 3 Cost per Unit Value or Variable Name + + UtilityCost:Charge:Simple, + WinterFuelEnergyCharge, !- Utility Cost Charge Simple Name + ReliantEnergy_PTB-MGS_MiscGeneral, !- Tariff Name + totalEnergy, !- Source Variable + Winter, !- Season + EnergyCharges, !- Category Variable Name + 0.0485; !- Cost per Unit Value or Variable Name + + UtilityCost:Charge:Block, + SummerBaseEnergycharge, !- Utility Cost Charge Block Name + ReliantEnergy_PTB-MGS_MiscGeneral, !- Tariff Name + TotalEnergy, !- Source Variable + Summer, !- Season + EnergyCharges, !- Category Variable Name + , !- Remaining Into Variable + TotalDemand, !- Block Size Multiplier Value or Variable Name + 125, !- Block Size 1 Value or Variable Name + 0.0504, !- Block 1 Cost per Unit Value or Variable Name + 170, !- Block Size 2 Value or Variable Name + 0.0317, !- Block 2 Cost per Unit Value or Variable Name + remaining, !- Block Size 3 Value or Variable Name + 0.0055; !- Block 3 Cost per Unit Value or Variable Name + + UtilityCost:Charge:Block, + AnnualDemandCharge, !- Utility Cost Charge Block Name + ReliantEnergy_PTB-MGS_MiscGeneral, !- Tariff Name + TotalDemand, !- Source Variable + Annual, !- Season + DemandCharges, !- Category Variable Name + , !- Remaining Into Variable + TotalDemand, !- Block Size Multiplier Value or Variable Name + 10, !- Block Size 1 Value or Variable Name + 0.0, !- Block 1 Cost per Unit Value or Variable Name + remaining, !- Block Size 2 Value or Variable Name + 3.04; !- Block 2 Cost per Unit Value or Variable Name + + UtilityCost:Qualify, + MaxDemand400kw, !- Utility Cost Qualify Name + ReliantEnergy_PTB-MGS_MiscGeneral, !- Tariff Name + TotalDemand, !- Variable Name + Maximum, !- Qualify Type + 400, !- Threshold Value or Variable Name + Annual, !- Season + Count, !- Threshold Test + 1; !- Number of Months + + UtilityCost:Charge:Simple, + TaxofEightPtTwoFivePercent, !- Utility Cost Charge Simple Name + ReliantEnergy_PTB-MGS_MiscGeneral, !- Tariff Name + SubTotal, !- Source Variable + Annual, !- Season + Taxes, !- Category Variable Name + 0.0825; !- Cost per Unit Value or Variable Name + +!end ReliantEnergy_PTB-MGS_MiscGeneral + + FuelFactors, + Electricity, !- Existing Fuel Resource Name + kg, !- Units of Measure + , !- Energy per Unit Factor + 3.712, !- Source Energy Factor {J/J} + , !- Source Energy Schedule Name + 184.46090, !- CO2 Emission Factor {g/MJ} + , !- CO2 Emission Factor Schedule Name + 9.63405E+03, !- CO Emission Factor {g/MJ} + , !- CO Emission Factor Schedule Name + 9.70184E-04, !- CH4 Emission Factor {g/MJ} + , !- CH4 Emission Factor Schedule Name + 3.27720E-01, !- NOx Emission Factor {g/MJ} + , !- NOx Emission Factor Schedule Name + 1.83957E-03, !- N2O Emission Factor {g/MJ} + , !- N2O Emission Factor Schedule Name + 4.90888E-01, !- SO2 Emission Factor {g/MJ} + , !- SO2 Emission Factor Schedule Name + 1.73147E-02, !- PM Emission Factor {g/MJ} + , !- PM Emission Factor Schedule Name + 1.71765E-02, !- PM10 Emission Factor {g/MJ} + , !- PM10 Emission Factor Schedule Name + 1.38283E-04, !- PM2.5 Emission Factor {g/MJ} + , !- PM2.5 Emission Factor Schedule Name + 1.26310E-03, !- NH3 Emission Factor {g/MJ} + , !- NH3 Emission Factor Schedule Name + 4.32150E-03, !- NMVOC Emission Factor {g/MJ} + , !- NMVOC Emission Factor Schedule Name + 3.52794E-06, !- Hg Emission Factor {g/MJ} + , !- Hg Emission Factor Schedule Name + 0, !- Pb Emission Factor {g/MJ} + , !- Pb Emission Factor Schedule Name + 0.45499, !- Water Emission Factor {L/MJ} + , !- Water Emission Factor Schedule Name + 0, !- Nuclear High Level Emission Factor {g/MJ} + , !- Nuclear High Level Emission Factor Schedule Name + 0; !- Nuclear Low Level Emission Factor {m3/MJ} + + UtilityCost:Tariff, + TX_EIAMonthlyRateGas, !- Name + NaturalGas:Facility, !- Output Meter Name + MCF, !- Conversion Factor Choice + , !- Energy Conversion Factor + , !- Demand Conversion Factor + , !- Time of Use Period Schedule Name + , !- Season Schedule Name + , !- Month Schedule Name + , !- Demand Window Length + 0.0, !- Monthly Charge or Variable Name + , !- Minimum Monthly Charge or Variable Name + , !- Real Time Pricing Charge Schedule Name + , !- Customer Baseline Load Schedule Name + Comm Gas; !- Group Name + + UtilityCost:Charge:Simple, + MonthlyRateGasCharge, !- Utility Cost Charge Simple Name + TX_EIAMonthlyRateGas, !- Tariff Name + totalEnergy, !- Source Variable + Annual, !- Season + EnergyCharges, !- Category Variable Name + TX_MonthlyGasRates; !- Cost per Unit Value or Variable Name + + UtilityCost:Variable, + TX_MonthlyGasRates, !- Name + TX_EIAMonthlyRateGas, !- Tariff Name + Currency, !- Variable Type + 7.87, !- January Value + 7.73, !- February Value + 7.41, !- March Value + 7.86, !- April Value + 8.05, !- May Value + 8.75, !- June Value + 8.21, !- July Value + 8.34, !- August Value + 8.04, !- September Value + 7.65, !- October Value + 8.24, !- November Value + 7.99; !- December Value + + UtilityCost:Charge:Simple, + TaxofEightPtTwoFivePercent, !- Utility Cost Charge Simple Name + TX_EIAMonthlyRateGas, !- Tariff Name + SubTotal, !- Source Variable + Annual, !- Season + Taxes, !- Category Variable Name + 0.0825; !- Cost per Unit Value or Variable Name + + Output:Surfaces:Drawing,dxf; + + Output:VariableDictionary,IDF; + + Output:Constructions,Constructions; + + OutputControl:Table:Style, + HTML; !- Column Separator + + Output:Table:SummaryReports, + AllSummary; !- Report 1 Name + + Output:Table:Monthly, + Load Center Performance Summary, !- Name + 2, !- Digits After Decimal + Electric Load Center Produced Electricity Rate, !- Variable or Meter 1 Name + HoursNonZero, !- Aggregation Type for Variable or Meter 1 + Electric Load Center Produced Electricity Rate, !- Variable or Meter 2 Name + SumOrAverageDuringHoursShown; !- Aggregation Type for Variable or Meter 2 + + Output:Table:Monthly, + PV Performance Summary, !- Name + 2, !- Digits After Decimal + Generator Produced DC Electricity Rate, !- Variable or Meter 1 Name + HoursNonZero, !- Aggregation Type for Variable or Meter 1 + Generator Produced DC Electricity Rate, !- Variable or Meter 2 Name + SumOrAverageDuringHoursShown, !- Aggregation Type for Variable or Meter 2 + Generator PV Array Efficiency, !- Variable or Meter 3 Name + SumOrAverageDuringHoursShown, !- Aggregation Type for Variable or Meter 3 + Generator Produced DC Electricity Energy, !- Variable or Meter 4 Name + SumOrAverageDuringHoursShown; !- Aggregation Type for Variable or Meter 4 + + Output:Table:Monthly, + Inverter Performance Summary, !- Name + 3, !- Digits After Decimal + Inverter DC Input Electricity Rate, !- Variable or Meter 1 Name + HoursNonZero, !- Aggregation Type for Variable or Meter 1 + Inverter DC Input Electricity Rate, !- Variable or Meter 2 Name + SumOrAverageDuringHoursShown, !- Aggregation Type for Variable or Meter 2 + Inverter AC Output Electricity Rate, !- Variable or Meter 3 Name + SumOrAverageDuringHoursShown, !- Aggregation Type for Variable or Meter 3 + Inverter Thermal Loss Rate, !- Variable or Meter 4 Name + SumOrAverageDuringHoursShown, !- Aggregation Type for Variable or Meter 4 + Inverter DC to AC Efficiency, !- Variable or Meter 5 Name + SumOrAverageDuringHoursShown, !- Aggregation Type for Variable or Meter 5 + Inverter Thermal Loss Rate, !- Variable or Meter 6 Name + SumOrAverageDuringHoursShown; !- Aggregation Type for Variable or Meter 6 + + Output:Table:Monthly, + Electric Storage Performance Summary, !- Name + 2, !- Digits After Decimal + Electric Storage Charge Power, !- Variable or Meter 1 Name + SumOrAverage, !- Aggregation Type for Variable or Meter 1 + Electric Storage Charge Energy, !- Variable or Meter 2 Name + SumOrAverage, !- Aggregation Type for Variable or Meter 2 + Electric Storage Discharge Power, !- Variable or Meter 3 Name + SumOrAverage, !- Aggregation Type for Variable or Meter 3 + Electric Storage Discharge Energy, !- Variable or Meter 4 Name + SumOrAverage, !- Aggregation Type for Variable or Meter 4 + Electric Storage Thermal Loss Rate, !- Variable or Meter 5 Name + SumOrAverage, !- Aggregation Type for Variable or Meter 5 + Electric Storage Thermal Loss Energy, !- Variable or Meter 6 Name + SumOrAverage, !- Aggregation Type for Variable or Meter 6 + Electric Storage Battery Charge State, !- Variable or Meter 7 Name + SumOrAverage; !- Aggregation Type for Variable or Meter 7 + + Output:Table:Monthly, + AC Power Summary, !- Name + 3, !- Digits After Decimal + Facility Total Purchased Electricity Rate, !- Variable or Meter 1 Name + SumOrAverage, !- Aggregation Type for Variable or Meter 1 + Facility Net Purchased Electricity Rate, !- Variable or Meter 2 Name + SumOrAverage, !- Aggregation Type for Variable or Meter 2 + Facility Total Produced Electricity Rate, !- Variable or Meter 3 Name + SumOrAverage, !- Aggregation Type for Variable or Meter 3 + Facility Total Electricity Demand Rate, !- Variable or Meter 4 Name + SumOrAverage, !- Aggregation Type for Variable or Meter 4 + Facility Total Building Electricity Demand Rate, !- Variable or Meter 5 Name + SumOrAverage, !- Aggregation Type for Variable or Meter 5 + Facility Total HVAC Electricity Demand Rate, !- Variable or Meter 6 Name + SumOrAverage; !- Aggregation Type for Variable or Meter 6 + + !!********************************************* + + ElectricLoadCenter:Distribution, + PV Array Load Center, !- Name + Generator List, !- Generator List Name + TrackElectrical, !- Generator Operation Scheme Type + 0, !- Generator Demand Limit Scheme Purchased Electric Demand Limit {W} + , !- Generator Track Schedule Name Scheme Schedule Name + , !- Generator Track Meter Scheme Meter Name + DirectCurrentWithInverterDCStorage, !- Electrical Buss Type + PV Inverter, !- Inverter Name + LiIonBattery, !- Electrical Storage Object Name + , !- Transformer Object Name + TrackFacilityElectricDemandStoreExcessOnSite, !- Storage Operation Scheme + , !- Storage Control Track Meter Name + , !- Storage Converter Object Name + 0.95, !- Maximum Storage State of Charge Fraction + 0.20; !- Minimum Storage State of Charge Fraction + + Curve:DoubleExponentialDecay, + Doubleexponential, !- Name + 1380, !- Coefficient1 C1 + 6834, !- Coefficient2 C2 + -8.75, !- Coefficient3 C3 + 6747, !- Coefficient4 C4 + -6.22, !- Coefficient5 C5 + 0, !- Minimum Value of x + 1, !- Maximum Value of x + , !- Minimum Curve Output + , !- Maximum Curve Output + Dimensionless, !- Input Unit Type for x + Dimensionless; !- Output Unit Type + + ElectricLoadCenter:Storage:LiIonNMCBattery, + LiIonBattery, !- Name + ALWAYS_ON, !- Availability Schedule Name + , !- Zone Name + 0, !- Radiative Fraction + KandlerSmith, !- Lifetime Model + 35, !- Number of Cells in Series + 270, !- Number of Strings in Parallel + 0.7, !- Initial Fractional State of Charge + , !- DC to DC Charging Efficiency + , !- Battery Mass + , !- Battery Surface Area + , !- Battery Specific Heat Capacity + ; !- Heat Transfer Coefficient Between Battery and Ambient + + ElectricLoadCenter:Inverter:LookUpTable, + PV Inverter, !- Name + ALWAYS_ON, !- Availability Schedule Name + , !- Zone Name + 0.25, !- Radiative Fraction + 14000, !- Rated Maximum Continuous Output Power {W} + 200.0, !- Night Tare Loss Power {W} + 368, !- Nominal Voltage Input {V} + 0.839, !- Efficiency at 10% Power and Nominal Voltage + 0.897, !- Efficiency at 20% Power and Nominal Voltage + 0.916, !- Efficiency at 30% Power and Nominal Voltage + 0.931, !- Efficiency at 50% Power and Nominal Voltage + 0.934, !- Efficiency at 75% Power and Nominal Voltage + 0.930; !- Efficiency at 100% Power and Nominal Voltage + + ElectricLoadCenter:Generators, + Generator List, !- Name + PV:ZN_1_FLR_1_SEC_1_Ceiling, !- Generator 1 Name + Generator:Photovoltaic, !- Generator 1 Object Type + 9000.0, !- Generator 1 Rated Electric Power Output {W} + , !- Generator 1 Availability Schedule Name + , !- Generator 1 Rated Thermal to Electrical Power Ratio + PV:ZN_1_FLR_1_SEC_2_Ceiling, !- Generator 2 Name + Generator:Photovoltaic, !- Generator 2 Object Type + 6000.0, !- Generator 2 Rated Electric Power Output {W} + , !- Generator 2 Availability Schedule Name + , !- Generator 2 Rated Thermal to Electrical Power Ratio + PV:ZN_1_FLR_1_SEC_3_Ceiling, !- Generator 3 Name + Generator:Photovoltaic, !- Generator 3 Object Type + 9000.0, !- Generator 3 Rated Electric Power Output {W} + , !- Generator 3 Availability Schedule Name + , !- Generator 3 Rated Thermal to Electrical Power Ratio + PV:ZN_1_FLR_1_SEC_4_Ceiling, !- Generator 4 Name + Generator:Photovoltaic, !- Generator 4 Object Type + 6000.0, !- Generator 4 Rated Electric Power Output {W} + , !- Generator 4 Availability Schedule Name + , !- Generator 4 Rated Thermal to Electrical Power Ratio + PV:ZN_1_FLR_1_SEC_5_Ceiling, !- Generator 5 Name + Generator:Photovoltaic, !- Generator 5 Object Type + 9000.0, !- Generator 5 Rated Electric Power Output {W} + , !- Generator 5 Availability Schedule Name + ; !- Generator 5 Rated Thermal to Electrical Power Ratio + + Generator:Photovoltaic, + PV:ZN_1_FLR_1_SEC_1_Ceiling, !- Name + ZN_1_FLR_1_SEC_1_Ceiling,!- Surface Name + PhotovoltaicPerformance:Simple, !- Photovoltaic Performance Object Type + 20percentEffPVhalfArea, !- Module Performance Name + Decoupled, !- Heat Transfer Integration Mode + 1.0, !- Number of Series Strings in Parallel {dimensionless} + 1.0; !- Number of Modules in Series {dimensionless} + + PhotovoltaicPerformance:Simple, + 20percentEffPVhalfArea, !- Name + 0.5, !- Fraction of Surface Area with Active Solar Cells {dimensionless} + Fixed, !- Conversion Efficiency Input Mode + 0.20, !- Value for Cell Efficiency if Fixed + ; !- Efficiency Schedule Name + + ComponentCost:LineItem, + PV:ZN_1_FLR_1_SEC_1_Ceiling, !- Name + , !- Type + Generator:Photovoltaic, !- Line Item Type + PV:ZN_1_FLR_1_SEC_1_Ceiling, !- Item Name + , !- Object End-Use Key + , !- Cost per Each {$} + , !- Cost per Area {$/m2} + 9000.0000, !- Cost per Unit of Output Capacity {$/kW} + , !- Cost per Unit of Output Capacity per COP {$/kW} + , !- Cost per Volume {$/m3} + , !- Cost per Volume Rate {$/(m3/s)} + , !- Cost per Energy per Temperature Difference {$/(W/K)} + ; !- Quantity {dimensionless} + + Generator:Photovoltaic, + PV:ZN_1_FLR_1_SEC_2_Ceiling, !- Name + ZN_1_FLR_1_SEC_2_Ceiling,!- Surface Name + PhotovoltaicPerformance:Simple, !- Photovoltaic Performance Object Type + 20percentEffPVhalfArea, !- Module Performance Name + Decoupled, !- Heat Transfer Integration Mode + 1.0, !- Number of Series Strings in Parallel {dimensionless} + 1.0; !- Number of Modules in Series {dimensionless} + + ComponentCost:LineItem, + PV:ZN_1_FLR_1_SEC_2_Ceiling, !- Name + , !- Type + Generator:Photovoltaic, !- Line Item Type + PV:ZN_1_FLR_1_SEC_2_Ceiling, !- Item Name + , !- Object End-Use Key + , !- Cost per Each {$} + , !- Cost per Area {$/m2} + 9000.0000, !- Cost per Unit of Output Capacity {$/kW} + , !- Cost per Unit of Output Capacity per COP {$/kW} + , !- Cost per Volume {$/m3} + , !- Cost per Volume Rate {$/(m3/s)} + , !- Cost per Energy per Temperature Difference {$/(W/K)} + ; !- Quantity {dimensionless} + + Generator:Photovoltaic, + PV:ZN_1_FLR_1_SEC_3_Ceiling, !- Name + ZN_1_FLR_1_SEC_3_Ceiling,!- Surface Name + PhotovoltaicPerformance:Simple, !- Photovoltaic Performance Object Type + 20percentEffPVhalfArea, !- Module Performance Name + Decoupled, !- Heat Transfer Integration Mode + 1.0, !- Number of Series Strings in Parallel {dimensionless} + 1.0; !- Number of Modules in Series {dimensionless} + + ComponentCost:LineItem, + PV:ZN_1_FLR_1_SEC_3_Ceiling, !- Name + , !- Type + Generator:Photovoltaic, !- Line Item Type + PV:ZN_1_FLR_1_SEC_3_Ceiling, !- Item Name + , !- Object End-Use Key + , !- Cost per Each {$} + , !- Cost per Area {$/m2} + 9000.0000, !- Cost per Unit of Output Capacity {$/kW} + , !- Cost per Unit of Output Capacity per COP {$/kW} + , !- Cost per Volume {$/m3} + , !- Cost per Volume Rate {$/(m3/s)} + , !- Cost per Energy per Temperature Difference {$/(W/K)} + ; !- Quantity {dimensionless} + + Generator:Photovoltaic, + PV:ZN_1_FLR_1_SEC_4_Ceiling, !- Name + ZN_1_FLR_1_SEC_4_Ceiling,!- Surface Name + PhotovoltaicPerformance:Simple, !- Photovoltaic Performance Object Type + 20percentEffPVhalfArea, !- Module Performance Name + Decoupled, !- Heat Transfer Integration Mode + 1.0, !- Number of Series Strings in Parallel {dimensionless} + 1.0; !- Number of Modules in Series {dimensionless} + + ComponentCost:LineItem, + PV:ZN_1_FLR_1_SEC_4_Ceiling, !- Name + , !- Type + Generator:Photovoltaic, !- Line Item Type + PV:ZN_1_FLR_1_SEC_4_Ceiling, !- Item Name + , !- Object End-Use Key + , !- Cost per Each {$} + , !- Cost per Area {$/m2} + 9000.0000, !- Cost per Unit of Output Capacity {$/kW} + , !- Cost per Unit of Output Capacity per COP {$/kW} + , !- Cost per Volume {$/m3} + , !- Cost per Volume Rate {$/(m3/s)} + , !- Cost per Energy per Temperature Difference {$/(W/K)} + ; !- Quantity {dimensionless} + + Generator:Photovoltaic, + PV:ZN_1_FLR_1_SEC_5_Ceiling, !- Name + ZN_1_FLR_1_SEC_5_Ceiling,!- Surface Name + PhotovoltaicPerformance:Simple, !- Photovoltaic Performance Object Type + 20percentEffPVhalfArea, !- Module Performance Name + Decoupled, !- Heat Transfer Integration Mode + 1.0, !- Number of Series Strings in Parallel {dimensionless} + 1.0; !- Number of Modules in Series {dimensionless} + + ComponentCost:LineItem, + PV:ZN_1_FLR_1_SEC_5_Ceiling, !- Name + , !- Type + Generator:Photovoltaic, !- Line Item Type + PV:ZN_1_FLR_1_SEC_5_Ceiling, !- Item Name + , !- Object End-Use Key + , !- Cost per Each {$} + , !- Cost per Area {$/m2} + 9000.0000, !- Cost per Unit of Output Capacity {$/kW} + , !- Cost per Unit of Output Capacity per COP {$/kW} + , !- Cost per Volume {$/m3} + , !- Cost per Volume Rate {$/(m3/s)} + , !- Cost per Energy per Temperature Difference {$/(W/K)} + ; !- Quantity {dimensionless} + + Output:Variable,*,Inverter DC to AC Efficiency,timestep; + + Output:Variable,*,Inverter DC Input Electricity Rate,timestep; + + Output:Variable,*,Inverter DC Input Electricity Energy,timestep; + + Output:Variable,*,Inverter AC Output Electricity Rate,timestep; + + Output:Variable,*,Electric Storage Degradation Fraction,timestep; + + Output:Variable,*,Electric Storage Charge Fraction,timestep; + + Output:Variable,*,Electric Storage Operating Mode Index,timestep; + + Output:Variable,*,Electric Storage Battery Charge State,timestep; + + Output:Variable,*,Electric Storage Charge Power,timestep; + + Output:Variable,*,Electric Storage Charge Energy,timestep; + + Output:Variable,*,Electric Storage Discharge Power,timestep; + + Output:Variable,*,Electric Storage Discharge Energy,timestep; + + Output:Variable,*,Electric Storage Thermal Loss Rate,timestep; + + Output:Variable,*,Electric Storage Thermal Loss Energy,timestep; + + Output:Variable,*,Electric Storage Total Current,timestep; + + Output:Variable,*,Electric Storage Total Voltage,timestep; + + Output:Variable,*,Electric Load Center Produced Electricity Rate,timestep; + + Output:Variable,*,Electric Load Center Produced Electricity Energy,timestep; + + Output:Variable,*,Electric Load Center Produced Thermal Rate,timestep; + + Output:Variable,*,Electric Load Center Produced Thermal Energy,timestep; + + Output:Variable,*,Facility Total Purchased Electricity Rate,timestep; + + Output:Variable,*,Facility Total Purchased Electricity Energy,timestep; + + Output:Variable,*,Facility Total Surplus Electricity Energy,timestep; + + Output:Variable,*,Facility Net Purchased Electricity Rate,timestep; + + Output:Variable,*,Facility Net Purchased Electricity Energy,timestep; + + Output:Variable,*,Facility Total Building Electricity Demand Rate,timestep; + + Output:Variable,*,Facility Total HVAC Electricity Demand Rate,timestep; + + Output:Variable,*,Facility Total Electricity Demand Rate,timestep; + + Output:Variable,*,Facility Total Produced Electricity Rate,timestep; + + Output:Variable,*,Facility Total Produced Electricity Energy,timestep; + + Output:Variable,*,Generator Produced DC Electricity Rate,timestep; + + Output:Variable,*,Generator Produced DC Electricity Energy,timestep; + + Output:Variable,*,Generator PV Array Efficiency,timestep; + + Output:Variable,*,Generator Requested Electricity Rate,timestep; + + Output:Variable,*,Cooling Coil Electricity Rate,timestep; + + Output:SQLite, + Simple; !- Option Type + +!***** Portions of this file originally Generated by EPXMLPreproc2 ***** +!***** Created on 06/07/2007 02:53:27 ***** +!***** Input File produced by the EnergyPlus Model Example File Generator ***** +!***** Disclaimer & Notice: ***** +!***** The EnergyPlus Example File Generator ("EEFG") is provided by the ***** +!***** National Renewable Energy Laboratory ("NREL") operated by Midwest ***** +!***** Research Institute for the U.S. Department of Energy ("DOE"). ***** +!***** Access to and use of the EEFG shall impose the following obligations ***** +!***** on the user. The user agrees to credit NREL/MRI in any publication(s) ***** +!***** that result from the use of EEFG. The names NREL/MRI/DOE, however, may ***** +!***** not be used in any advertising or publicity to endorse or promote ***** +!***** any products, services or commercial entities unless specific written ***** +!***** permission is obtained from NREL/MRI/DOE. ***** +!***** EEFG IS PROVIDED BY NREL/MRI "AS IS" AND ANY EXPRESS OR IMPLIED ***** +!***** WARRANTIES, INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ***** +!***** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ***** +!***** DISCLAIMED. IN NO EVENT SHALL NREL/MRI/DOE BE LIABLE FOR ANY ***** +!***** SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER, ***** +!***** INCLUDING BUT NOT LIMITED TO CLAIMS ASSOCIATED WITH THE LOSS OF DATA ***** +!***** OR PROFITS, WHICH MAY RESULT FROM AN ACTION IN CONTRACT, NEGLIGENCE ***** +!***** OR OTHER TORTIOUS CLAIM THAT ARISES OUT OF OR IN CONNECTION ***** +!***** WITH THE ACCESS, USE OR PERFORMANCE OF THE EEFG. ***** +!***** Please help us to improve this service. If you have suggestions for ***** +!***** improving this input file, please contact us at ewi_support@nrel.gov. ***** +! Start SimMetaData +! WeatherFileName=USA_OK_Oklahoma.City_TMY2.epw +! CodeStandard=ASHRAE 90.1-2004 +! Std62Version=2004 +! RoofConstruction=Insulation Entirely Above Deck +! ExtWallConstruction=Steel-Framed +! End SimMetaData From 5abcceea9fc003954e91174fdcea2e29e727fc45 Mon Sep 17 00:00:00 2001 From: Noel Merket Date: Tue, 9 Feb 2021 11:18:49 -0700 Subject: [PATCH 45/76] Squashed 'third_party/ssc/' changes from a016268145..8699b47062 8699b47062 Merge remote-tracking branch 'rchintala13/batt_life_new_Jan_2021' into batt_life_new_Jan_2021 a5b8ebc47d use single day_age_of_battery d8b9963740 fix compilation 961196e776 undo renaming 62bdc043c8 use single day_age_of_battery 196f345dab Test entire nmc state with greater precision 65e63857f0 fix minor issues in test 2f9b63939a minor changes; add license header; rename variable 46c7c2f480 clean up thermal_t's analytic calculation of capacity; add lib_battery_test 37b64163e4 Merge branch 'patch' into batt_life_new_Jan_2021 dcf1669a13 turn off all splinter warnings 7a43d76624 fix pvsamv1 tests 534ed5cbc6 Merge branch 'batt_life_new' into batt_life_new_Jan_2021 git-subtree-dir: third_party/ssc git-subtree-split: 8699b47062ab07f029b1b2bcf351d35af5124d69 --- shared/lib_battery.cpp | 29 +++---- shared/lib_battery.h | 6 +- shared/lib_battery_lifetime.cpp | 24 +++++- shared/lib_battery_lifetime.h | 28 ++++++- .../lib_battery_lifetime_calendar_cycle.cpp | 8 +- shared/lib_battery_lifetime_nmc.cpp | 77 +++++++++++-------- shared/lib_battery_lifetime_nmc.h | 54 ++++++++----- shared/logger.cpp | 3 +- splinter/CMakeLists.txt | 1 + ssc/cmod_battery.cpp | 14 ++-- ssc/cmod_battery_stateful.cpp | 2 +- .../lib_battery_dispatch_automatic_btm_test.h | 2 +- .../lib_battery_dispatch_automatic_fom_test.h | 2 +- .../lib_battery_dispatch_manual_test.h | 2 +- .../shared_test/lib_battery_lifetime_test.cpp | 68 +++++++++------- test/shared_test/lib_battery_test.cpp | 22 +++++- test/shared_test/lib_battery_test.h | 5 +- test/ssc_test/cmod_battery_pvsamv1_test.cpp | 3 +- 18 files changed, 226 insertions(+), 124 deletions(-) diff --git a/shared/lib_battery.cpp b/shared/lib_battery.cpp index 9f8716840dd..a42995458c9 100644 --- a/shared/lib_battery.cpp +++ b/shared/lib_battery.cpp @@ -30,14 +30,17 @@ Define Thermal Model */ void thermal_t::initialize() { - if (params->cap_vs_temp.nrows() < 2 || params->cap_vs_temp.ncols() != 2) { + if (!params->analytical_model && (params->cap_vs_temp.nrows() < 2 || params->cap_vs_temp.ncols() != 2)) { throw std::runtime_error("thermal_t: capacity vs temperature matrix must have two columns and at least two rows"); } - size_t n = params->cap_vs_temp.nrows(); - for (int i = 0; i < (int) n; i++) { - params->cap_vs_temp(i, 0); + if (!params->analytical_model) { + size_t n = params->cap_vs_temp.nrows(); + for (int i = 0; i < (int) n; i++) { + params->cap_vs_temp(i, 0); + } } + state = std::make_shared(); if (params->option == thermal_params::SCHEDULE) state->T_room = params->T_room_schedule[0]; @@ -71,10 +74,7 @@ thermal_t::thermal_t(double dt_hour, double mass, double surface_area, double R, thermal_t::thermal_t(double dt_hour, double mass, double surface_area, double R, double Cp, double h, double T_room_C) { - util::matrix_t c_vs_t; - double vals3[] = { -10, 60, 0, 80, 25, 100, 40, 100 }; - c_vs_t.assign(vals3, 4, 2); - params = std::shared_ptr(new thermal_params({dt_hour, mass, surface_area, Cp, h, R, c_vs_t })); + params = std::shared_ptr(new thermal_params({dt_hour, mass, surface_area, Cp, h, R, util::matrix_t()})); params->option = thermal_params::VALUE; params->T_room_init = T_room_C; params->analytical_model = true; @@ -82,11 +82,8 @@ thermal_t::thermal_t(double dt_hour, double mass, double surface_area, double R, } thermal_t::thermal_t(double dt_hour, double mass, double surface_area, double R, double Cp, double h, - std::vector T_room_C) { - util::matrix_t c_vs_t; - double vals3[] = { -10, 60, 0, 80, 25, 100, 40, 100 }; - c_vs_t.assign(vals3, 4, 2); - params = std::shared_ptr(new thermal_params({ dt_hour, mass, surface_area, Cp, h, R, c_vs_t })); + std::vector T_room_C) { + params = std::shared_ptr(new thermal_params({ dt_hour, mass, surface_area, Cp, h, R, util::matrix_t()})); params->option = thermal_params::SCHEDULE; params->T_room_schedule = std::move(T_room_C); params->analytical_model = true; @@ -127,9 +124,9 @@ void thermal_t::replace_battery(size_t lifetimeIndex) { } void thermal_t::calc_capacity() { - double percent; + double percent; if (params->analytical_model) { - percent = 100 * exp(-(Ea_d0_1 / Rug) * (1 /( state->T_batt+273) - 1 / T_ref) - + percent = 100. * exp(-(Ea_d0_1 / Rug) * (1 /( state->T_batt+273) - 1 / T_ref) - (Ea_d0_2 / Rug) * pow((1 / (state->T_batt+273) - 1 / T_ref), 2)); } else @@ -137,8 +134,6 @@ void thermal_t::calc_capacity() { percent = util::linterp_col(params->cap_vs_temp, 0, state->T_batt, 1); } - - if (std::isnan(percent) || percent < 0 || percent > 100) { percent = 100; // log.add("Unable to determine capacity adjustment for temperature, ignoring"); diff --git a/shared/lib_battery.h b/shared/lib_battery.h index e019f0282e6..f668eb5a375 100644 --- a/shared/lib_battery.h +++ b/shared/lib_battery.h @@ -61,8 +61,9 @@ struct thermal_params { double Cp; // [J/KgK] - battery specific heat capacity double h; // [W/m2/K] - general heat transfer coefficient double resistance; // [Ohm] - internal resistance + util::matrix_t cap_vs_temp; - bool analytical_model; + bool analytical_model; // if true, do not use cap_vs_temp enum OPTIONS { VALUE, SCHEDULE @@ -76,13 +77,14 @@ struct thermal_params { class thermal_t { public: + // constructors for capacity as an entry from a cap_vs_temp table thermal_t(double dt_hour, double mass, double surface_area, double R, double Cp, double h, const util::matrix_t &c_vs_t, std::vector T_room_C); thermal_t(double dt_hour, double mass, double surface_area, double R, double Cp, double h, const util::matrix_t &c_vs_t, double T_room_C); - // constructor for analytical model to update capacity + // constructors for capacity as an analytical function thermal_t(double dt_hour, double mass, double surface_area, double R, double Cp, double h, double T_room_C); diff --git a/shared/lib_battery_lifetime.cpp b/shared/lib_battery_lifetime.cpp index cb30938a1cb..6446519af73 100644 --- a/shared/lib_battery_lifetime.cpp +++ b/shared/lib_battery_lifetime.cpp @@ -1,3 +1,24 @@ +/** +BSD-3-Clause +Copyright 2019 Alliance for Sustainable Energy, LLC +Redistribution and use in source and binary forms, with or without modification, are permitted provided +that the following conditions are met : +1. Redistributions of source code must retain the above copyright notice, this list of conditions +and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions +and the following disclaimer in the documentation and/or other materials provided with the distribution. +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse +or promote products derived from this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDER, CONTRIBUTORS, UNITED STATES GOVERNMENT OR UNITED STATES +DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, +OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + #include "lib_battery_lifetime.h" #include "lib_battery_lifetime_calendar_cycle.h" #include "lib_battery_lifetime_nmc.h" @@ -43,7 +64,6 @@ lifetime_state::lifetime_state(const std::shared_ptr& cyc, const st q_relative = fmin(cycle->q_relative_cycle, calendar->q_relative_calendar); } -//Rohit - define constructor for lifetime_state with lifetime_nmc_state as parameter lifetime_state::lifetime_state(const std::shared_ptr& nmc) { q_relative = 0; n_cycles = 0; @@ -51,7 +71,7 @@ lifetime_state::lifetime_state(const std::shared_ptr& nmc) { average_range = 0; day_age_of_battery = 0; nmc_state = nmc; - q_relative = fmin(nmc_state->q_relative_li, nmc_state->q_relative_neg); + q_relative = fmin(nmc->q_relative_li, nmc->q_relative_neg); } diff --git a/shared/lib_battery_lifetime.h b/shared/lib_battery_lifetime.h index 2c225b4b873..94860f41142 100644 --- a/shared/lib_battery_lifetime.h +++ b/shared/lib_battery_lifetime.h @@ -1,3 +1,24 @@ +/** +BSD-3-Clause +Copyright 2019 Alliance for Sustainable Energy, LLC +Redistribution and use in source and binary forms, with or without modification, are permitted provided +that the following conditions are met : +1. Redistributions of source code must retain the above copyright notice, this list of conditions +and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions +and the following disclaimer in the documentation and/or other materials provided with the distribution. +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse +or promote products derived from this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDER, CONTRIBUTORS, UNITED STATES GOVERNMENT OR UNITED STATES +DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, +OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + #ifndef SAM_SIMULATION_CORE_LIB_BATTERY_LIFETIME_H #define SAM_SIMULATION_CORE_LIB_BATTERY_LIFETIME_H @@ -25,7 +46,6 @@ struct lifetime_params { struct cycle_state; struct calendar_state; -// Rohit -add states for lifetime_nmc struct lifetime_nmc_state; struct lifetime_state { @@ -33,11 +53,13 @@ struct lifetime_state { int n_cycles; double range; double average_range; - int day_age_of_battery; + double day_age_of_battery; // CALCYC model state std::shared_ptr calendar; std::shared_ptr cycle; + + // NREL NMC model state std::shared_ptr nmc_state; lifetime_state(); @@ -46,8 +68,6 @@ struct lifetime_state { lifetime_state(const std::shared_ptr& cyc, const std::shared_ptr& cal); - // Rohit - define lifetime_state constructor with lifetime_nmc_state as parameter - lifetime_state(const std::shared_ptr& nmc); lifetime_state &operator=(const lifetime_state &rhs); diff --git a/shared/lib_battery_lifetime_calendar_cycle.cpp b/shared/lib_battery_lifetime_calendar_cycle.cpp index 6b37a1dc475..006ac515c64 100644 --- a/shared/lib_battery_lifetime_calendar_cycle.cpp +++ b/shared/lib_battery_lifetime_calendar_cycle.cpp @@ -409,7 +409,7 @@ double lifetime_calendar_t::capacity_percent() { return state->calendar->q_relat lifetime_state lifetime_calendar_t::get_state() { return *state; } double lifetime_calendar_t::runLifetimeCalendarModel(size_t lifetimeIndex, double T, double SOC) { - state->day_age_of_battery = (int)(lifetimeIndex / (util::hours_per_day / params->dt_hr)); + state->day_age_of_battery = lifetimeIndex / (util::hours_per_day / params->dt_hr); if (params->cal_cyc->calendar_choice == calendar_cycle_params::CALENDAR_CHOICE::MODEL) runLithiumIonModel(T, SOC); @@ -447,11 +447,11 @@ void lifetime_calendar_t::runTableModel() { for (size_t i = 0; i != n_rows; i++) { int day = (int)params->cal_cyc->calendar_matrix.at(i, calendar_cycle_params::DAYS); double capacity = (int) params->cal_cyc->calendar_matrix.at(i, calendar_cycle_params::CAPACITY_CAL); - if (day <= state->day_age_of_battery) { + if (day <= (int)state->day_age_of_battery) { day_lo = day; capacity_lo = capacity; } - if (day > state->day_age_of_battery) { + if (day > (int)state->day_age_of_battery) { day_hi = day; capacity_hi = capacity; break; @@ -464,7 +464,7 @@ void lifetime_calendar_t::runTableModel() { capacity_hi = (int) params->cal_cyc->calendar_matrix.at(n, calendar_cycle_params::CAPACITY_CAL); } - state->calendar->q_relative_calendar = util::interpolate((double) day_lo, capacity_lo, (double) day_hi, capacity_hi, (double) state->day_age_of_battery); + state->calendar->q_relative_calendar = util::interpolate((double) day_lo, capacity_lo, (double) day_hi, capacity_hi, state->day_age_of_battery); } void lifetime_calendar_t::replaceBattery(double replacement_percent) { diff --git a/shared/lib_battery_lifetime_nmc.cpp b/shared/lib_battery_lifetime_nmc.cpp index c7f5eea0042..95ed1ad53e3 100644 --- a/shared/lib_battery_lifetime_nmc.cpp +++ b/shared/lib_battery_lifetime_nmc.cpp @@ -1,3 +1,25 @@ +/** +BSD-3-Clause +Copyright 2019 Alliance for Sustainable Energy, LLC +Redistribution and use in source and binary forms, with or without modification, are permitted provided +that the following conditions are met : +1. Redistributions of source code must retain the above copyright notice, this list of conditions +and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions +and the following disclaimer in the documentation and/or other materials provided with the distribution. +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse +or promote products derived from this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDER, CONTRIBUTORS, UNITED STATES GOVERNMENT OR UNITED STATES +DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, +OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + #include "lib_battery_lifetime_calendar_cycle.h" #include "lib_battery_lifetime_nmc.h" #include "lib_battery_lifetime.h" @@ -5,7 +27,7 @@ #include void lifetime_nmc_t::initialize() { - + // cycle model for counting cycles only, no cycle-only degradation cycle_model = std::unique_ptr(new lifetime_cycle_t(params, state)); // do any state initialization here @@ -14,7 +36,6 @@ void lifetime_nmc_t::initialize() { state->nmc_state->q_relative_neg = 100; state->nmc_state->dq_relative_li_old = 0; state->nmc_state->dq_relative_neg_old = 0; - state->nmc_state->day_age_of_battery_float = 0; state->nmc_state->DOD_max = 50; state->nmc_state->n_cycles_prev_day = 0; state->nmc_state->b1_dt = 0; @@ -53,9 +74,8 @@ lifetime_t * lifetime_nmc_t::clone() { return new lifetime_nmc_t(*this); } -// Rohit - Define negative electrode voltage function -double lifetime_nmc_t::Uneg_computation(double SOC) { - double Uneg = 0.1; +double lifetime_nmc_t::calculate_Uneg(double SOC) { + double Uneg; if (SOC <= 0.1) Uneg = ((0.2420 - 1.2868) / 0.1) * SOC + 1.2868; else @@ -63,9 +83,8 @@ double lifetime_nmc_t::Uneg_computation(double SOC) { return Uneg; } -// Rohit - Define open circuit voltage function -double lifetime_nmc_t::Voc_computation(double SOC) { - double Voc = 0.1; +double lifetime_nmc_t::calculate_Voc(double SOC) { + double Voc; if (SOC <= 0.1) Voc = ((0.4679) / 0.1) * SOC + 3; else if (SOC <= 0.6) @@ -75,12 +94,12 @@ double lifetime_nmc_t::Voc_computation(double SOC) { return Voc; } -double lifetime_nmc_t::runLifetimeNMC_Qli() { +double lifetime_nmc_t::runQli() { double dt_day = 1; int dn_cycles = state->n_cycles - state->nmc_state->n_cycles_prev_day; double k_cal = 0; //double b1 = std::accumulate(state->nmc_state->b1_dt.begin(), state->nmc_state->b1_dt.end(), 0); - double b1 = state->nmc_state->b1_dt; + double b1 = state->nmc_state->b1_dt; double b2 = state->nmc_state->b2_dt; double b3 = state->nmc_state->b3_dt; @@ -103,9 +122,8 @@ double lifetime_nmc_t::runLifetimeNMC_Qli() { return state->nmc_state->q_relative_li; } -double lifetime_nmc_t::runLifetimeNMC_Qneg(double T_battery, double SOC) { - - double DOD = 1 - SOC; +double lifetime_nmc_t::runQneg(double T_battery, double SOC) { + int dn_cycles = state->n_cycles - state->nmc_state->n_cycles_prev_day; double c2 = state->nmc_state->c2_dt; @@ -120,7 +138,7 @@ double lifetime_nmc_t::runLifetimeNMC_Qneg(double T_battery, double SOC) { state->nmc_state->dq_relative_neg_old = dq_new; state->nmc_state->q_relative_neg = (1 - (dq_new)) * 100; - + //return state->nmc_state->q_relative_neg; return 100; } @@ -128,16 +146,14 @@ double lifetime_nmc_t::runLifetimeNMC_Qneg(double T_battery, double SOC) { void lifetime_nmc_t::runLifetimeModels(size_t lifetimeIndex, bool charge_changed, double prev_DOD, double DOD, double T_battery) { double q_last = state->q_relative; - + // update day age of battery - int day_age_of_battery_old = (int)(state->nmc_state->day_age_of_battery_float); - state->nmc_state->day_age_of_battery_float = state->nmc_state->day_age_of_battery_float + - float( params->dt_hr/ util::hours_per_day); - state->day_age_of_battery = (int)(state->nmc_state->day_age_of_battery_float); - - + size_t day_age_of_battery_old = (size_t)(state->day_age_of_battery); + state->day_age_of_battery += params->dt_hr / (double)util::hours_per_day; + auto ts_per_day = (size_t)(util::hours_per_day / params->dt_hr); + // convert battery temperature to Kelvin - T_battery += 273; + T_battery += 273; if (charge_changed) cycle_model->rainflow(prev_DOD); @@ -147,9 +163,9 @@ void lifetime_nmc_t::runLifetimeModels(size_t lifetimeIndex, bool charge_changed //compute open circuit and negative electrode voltage as function of SOC double SOC = 0.01 * (100 - DOD); - double DOD_max = state->nmc_state->DOD_max * 0.01; - double U_neg = Uneg_computation(SOC); - double V_oc = Voc_computation(SOC); + double DOD_max = state->nmc_state->DOD_max * 0.01; + double U_neg = calculate_Uneg(SOC); + double V_oc = calculate_Voc(SOC); // compute lifetime degradation coefficients for current time step, //multiply by timestep in days and populate corresponding vectors @@ -171,15 +187,17 @@ void lifetime_nmc_t::runLifetimeModels(size_t lifetimeIndex, bool charge_changed state->nmc_state->c2_dt += c2_dt_el; //Run capacity degradation model after every 24 hours - if (state->day_age_of_battery - day_age_of_battery_old == 1) { - state->nmc_state->q_relative_li = runLifetimeNMC_Qli(); - state->nmc_state->q_relative_neg = runLifetimeNMC_Qneg(T_battery, SOC); + if (lifetimeIndex % ts_per_day == 23) { + state->nmc_state->q_relative_li = runQli(); + state->nmc_state->q_relative_neg = runQneg(T_battery, SOC); state->q_relative = fmin(state->nmc_state->q_relative_li, state->nmc_state->q_relative_neg); state->nmc_state->n_cycles_prev_day = state->n_cycles; +// printf("%zu, %f, %zu, %f, %f, %f\n", lifetimeIndex, state->day_age_of_battery, (size_t)(day_age_of_battery_old), state->nmc_state->q_relative_li, state->nmc_state->q_relative_neg, state->q_relative); } +// else +// printf("%zu, %f, %zu, %zu\n", lifetimeIndex, state->day_age_of_battery, (size_t)state->day_age_of_battery, day_age_of_battery_old); state->q_relative = fmin(state->q_relative, q_last); - } double lifetime_nmc_t::estimateCycleDamage() { @@ -188,7 +206,6 @@ double lifetime_nmc_t::estimateCycleDamage() { void lifetime_nmc_t::replaceBattery(double percent_to_replace) { state->day_age_of_battery = 0; - state->nmc_state->day_age_of_battery_float = 0; state->nmc_state->dq_relative_li_old = 0; state->nmc_state->dq_relative_neg_old = 0; state->nmc_state->q_relative_li += percent_to_replace; diff --git a/shared/lib_battery_lifetime_nmc.h b/shared/lib_battery_lifetime_nmc.h index c0867cd31d1..eb92977e92f 100644 --- a/shared/lib_battery_lifetime_nmc.h +++ b/shared/lib_battery_lifetime_nmc.h @@ -1,3 +1,24 @@ +/** +BSD-3-Clause +Copyright 2019 Alliance for Sustainable Energy, LLC +Redistribution and use in source and binary forms, with or without modification, are permitted provided +that the following conditions are met : +1. Redistributions of source code must retain the above copyright notice, this list of conditions +and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions +and the following disclaimer in the documentation and/or other materials provided with the distribution. +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse +or promote products derived from this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDER, CONTRIBUTORS, UNITED STATES GOVERNMENT OR UNITED STATES +DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, +OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + #ifndef SAM_SIMULATION_CORE_LIB_BATTERY_LIFETIME_NMC_H #define SAM_SIMULATION_CORE_LIB_BATTERY_LIFETIME_NMC_H @@ -6,25 +27,21 @@ #include "lib_util.h" #include "lib_battery_lifetime_calendar_cycle.h" -// Rohit - add struct for lithiumIonnmc states, SEI degradation (q_relative_li) and cycle degradation (q_relative_neg) - struct lifetime_nmc_state { - double q_relative_li; // % - double q_relative_neg; + double q_relative_li; // %, SEI degradation + double q_relative_neg; // %, cycle degradation double dq_relative_li_old; double dq_relative_neg_old; double DOD_max; int n_cycles_prev_day; - float day_age_of_battery_float; // keep track of age of battery with changing timestep - - // for complex cycling of battery, b1 = summagion of b1_dt * dt_day over a day + // for complex cycling of battery, b1 = summation of b1_dt * dt_day over a day // lifetime capacity updated after 24 hours elapse. - double b1_dt; + double b1_dt; double b2_dt; double b3_dt; - double c2_dt; + double c2_dt; friend std::ostream& operator<<(std::ostream& os, const lifetime_nmc_state& p); }; @@ -49,23 +66,24 @@ class lifetime_nmc_t : public lifetime_t { void replaceBattery(double percent_to_replace) override; /// Calculate negative electrode voltage from SOC - double Uneg_computation(double SOC); + static double calculate_Uneg(double SOC); /// Calculate open circuit voltage from SOC - double Voc_computation(double SOC); - - // Capacity degradation due to SEI - double runLifetimeNMC_Qli(); - - // Capacity degradation due to cycles - double runLifetimeNMC_Qneg(double T_battery, double SOC); + static double calculate_Voc(double SOC); protected: + std::unique_ptr cycle_model; + /// Capacity degradation due to SEI + double runQli(); + + /// Capacity degradation due to cycles + double runQneg(double T_battery, double SOC); + void initialize(); - /// Rohit - Add Li-ion NMC Kandler Smith parameters + /// NMC Kandler Smith parameters double Ea_d0_1 = 4126.0; double b1_ref = 0.003503; double Ea_b_1 = 35392.; diff --git a/shared/logger.cpp b/shared/logger.cpp index e0c6df24c35..0f3c5e3df6b 100644 --- a/shared/logger.cpp +++ b/shared/logger.cpp @@ -105,7 +105,6 @@ std::ostream &operator<<(std::ostream &os, const calendar_state &p) { return os; } -//Rohit std::ostream& operator<<(std::ostream& os, const lifetime_nmc_state& p) { char buf[1024]; sprintf(buf, "\"lifetime_nmc_state\": { \"q_relative_li\": %.3f, " @@ -120,7 +119,7 @@ std::ostream &operator<<(std::ostream &os, const lifetime_state &p) { char buf[1024]; sprintf(buf, R"("lifetime_state": { "q_relative": %f, "n_cycles": %d, "range": %.3f, "average_range": %.3f, )", p.q_relative, p.n_cycles, p.range, p.average_range); - os << buf << *p.cycle << ", " << *p.calendar << " }"; + os << buf << *p.cycle << ", " << *p.calendar << ", " << *p.nmc_state << " }"; return os; } diff --git a/splinter/CMakeLists.txt b/splinter/CMakeLists.txt index 63c1072742f..fba7f7e5d00 100644 --- a/splinter/CMakeLists.txt +++ b/splinter/CMakeLists.txt @@ -37,6 +37,7 @@ set_default_compile_options(splinter) if(MSVC) set_additional_compile_options(splinter "/W2 /wd4267 /wd4244") endif(MSVC) +set_no_warnings(splinter) ##################################################################################################################### diff --git a/ssc/cmod_battery.cpp b/ssc/cmod_battery.cpp index 1f49b916e39..4e7214fa938 100644 --- a/ssc/cmod_battery.cpp +++ b/ssc/cmod_battery.cpp @@ -112,13 +112,13 @@ var_info vtab_battery_inputs[] = { // lifetime inputs { SSC_INPUT, SSC_NUMBER, "batt_life_model", "Battery life model specifier", "0/1", "0=calendar/cycle,1=NMC", "BatteryCell", "en_batt=1", "", "" }, - { SSC_INPUT, SSC_MATRIX, "batt_lifetime_matrix", "Cycles vs capacity at different depths-of-discharge", "", "", "BatteryCell", "batt_life_model=0", "", "" }, - { SSC_INPUT, SSC_NUMBER, "batt_calendar_choice", "Calendar life degradation input option", "0/1/2", "0=NoCalendarDegradation,1=LithiomIonModel,2=InputLossTable", "BatteryCell", "batt_life_model=0", "", "" }, - { SSC_INPUT, SSC_MATRIX, "batt_calendar_lifetime_matrix", "Days vs capacity", "", "", "BatteryCell", "batt_life_model=0&batt_calendar_choice=2", "", "" }, - { SSC_INPUT, SSC_NUMBER, "batt_calendar_q0", "Calendar life model initial capacity cofficient", "", "", "BatteryCell", "batt_life_model=0&batt_calendar_choice=1", "", "" }, - { SSC_INPUT, SSC_NUMBER, "batt_calendar_a", "Calendar life model coefficient", "1/sqrt(day)","", "BatteryCell", "batt_life_model=0&batt_calendar_choice=1", "", "" }, - { SSC_INPUT, SSC_NUMBER, "batt_calendar_b", "Calendar life model coefficient", "K", "", "BatteryCell", "batt_life_model=0&batt_calendar_choice=1", "", "" }, - { SSC_INPUT, SSC_NUMBER, "batt_calendar_c", "Calendar life model coefficient", "K", "", "BatteryCell", "batt_life_model=0&batt_calendar_choice=1", "", "" }, + { SSC_INPUT, SSC_MATRIX, "batt_lifetime_matrix", "Cycles vs capacity at different depths-of-discharge", "", "", "BatteryCell", "en_batt=1&batt_life_model=0", "", "" }, + { SSC_INPUT, SSC_NUMBER, "batt_calendar_choice", "Calendar life degradation input option", "0/1/2", "0=NoCalendarDegradation,1=LithiomIonModel,2=InputLossTable", "BatteryCell", "en_batt=1&batt_life_model=0", "", "" }, + { SSC_INPUT, SSC_MATRIX, "batt_calendar_lifetime_matrix", "Days vs capacity", "", "", "BatteryCell", "en_batt=1&batt_life_model=0&batt_calendar_choice=2", "", "" }, + { SSC_INPUT, SSC_NUMBER, "batt_calendar_q0", "Calendar life model initial capacity cofficient", "", "", "BatteryCell", "en_batt=1&batt_life_model=0&batt_calendar_choice=1", "", "" }, + { SSC_INPUT, SSC_NUMBER, "batt_calendar_a", "Calendar life model coefficient", "1/sqrt(day)","", "BatteryCell", "en_batt=1&batt_life_model=0&batt_calendar_choice=1", "", "" }, + { SSC_INPUT, SSC_NUMBER, "batt_calendar_b", "Calendar life model coefficient", "K", "", "BatteryCell", "en_batt=1&batt_life_model=0&batt_calendar_choice=1", "", "" }, + { SSC_INPUT, SSC_NUMBER, "batt_calendar_c", "Calendar life model coefficient", "K", "", "BatteryCell", "en_batt=1&batt_life_model=0&batt_calendar_choice=1", "", "" }, // replacement inputs { SSC_INPUT, SSC_NUMBER, "batt_replacement_capacity", "Capacity degradation at which to replace battery", "%", "", "BatterySystem", "", "", "" }, diff --git a/ssc/cmod_battery_stateful.cpp b/ssc/cmod_battery_stateful.cpp index 6725ba6cb7d..21f028ba090 100644 --- a/ssc/cmod_battery_stateful.cpp +++ b/ssc/cmod_battery_stateful.cpp @@ -273,7 +273,7 @@ void read_battery_state(battery_state& state, var_table* vt) { vt_get_int(vt, "n_cycles", &lifetime->n_cycles); vt_get_number(vt, "range", &lifetime->range); vt_get_number(vt, "average_range", &lifetime->average_range); - vt_get_int(vt, "day_age_of_battery", &lifetime->day_age_of_battery); + vt_get_number(vt, "day_age_of_battery", &lifetime->day_age_of_battery); vt_get_int(vt, "life_model", &choice); if (choice == lifetime_params::CALCYC) { diff --git a/test/shared_test/lib_battery_dispatch_automatic_btm_test.h b/test/shared_test/lib_battery_dispatch_automatic_btm_test.h index 9d968c267f4..b9e04f87556 100644 --- a/test/shared_test/lib_battery_dispatch_automatic_btm_test.h +++ b/test/shared_test/lib_battery_dispatch_automatic_btm_test.h @@ -18,7 +18,7 @@ class AutoBTMTest_lib_battery_dispatch : public BatteryProperties , public Dispa capacity_lithium_ion_t * capacityModel; voltage_dynamic_t * voltageModel; thermal_t * thermalModel; - lifetime_calendar_cycle_t * lifetimeModel; + lifetime_t * lifetimeModel; losses_t * lossModel; battery_t * batteryModel; BatteryPower * batteryPower; diff --git a/test/shared_test/lib_battery_dispatch_automatic_fom_test.h b/test/shared_test/lib_battery_dispatch_automatic_fom_test.h index 9c2bf7a5e3d..a3179377d4d 100644 --- a/test/shared_test/lib_battery_dispatch_automatic_fom_test.h +++ b/test/shared_test/lib_battery_dispatch_automatic_fom_test.h @@ -16,7 +16,7 @@ class AutoFOM_lib_battery_dispatch : public BatteryProperties , public DispatchP { protected: thermal_t * thermalModel; - lifetime_calendar_cycle_t * lifetimeModel; + lifetime_t * lifetimeModel; BatteryPower * batteryPower; capacity_lithium_ion_t * capacityModel; diff --git a/test/shared_test/lib_battery_dispatch_manual_test.h b/test/shared_test/lib_battery_dispatch_manual_test.h index 585c0f88f85..82792260e84 100644 --- a/test/shared_test/lib_battery_dispatch_manual_test.h +++ b/test/shared_test/lib_battery_dispatch_manual_test.h @@ -19,7 +19,7 @@ class ManualTest_lib_battery_dispatch : public BatteryProperties, public Dispatc capacity_lithium_ion_t* capacityModel; voltage_dynamic_t* voltageModel; thermal_t* thermalModel; - lifetime_calendar_cycle_t* lifetimeModel; + lifetime_t* lifetimeModel; losses_t* lossModel; battery_t* batteryModel; BatteryPower* batteryPower; diff --git a/test/shared_test/lib_battery_lifetime_test.cpp b/test/shared_test/lib_battery_lifetime_test.cpp index 6c50a700553..fe38df55e71 100644 --- a/test/shared_test/lib_battery_lifetime_test.cpp +++ b/test/shared_test/lib_battery_lifetime_test.cpp @@ -169,7 +169,7 @@ TEST_F(lib_battery_lifetime_calendar_matrix_test, runCalendarMatrixTest) { idx++; } lifetime_state s = cal_model->get_state(); - EXPECT_NEAR(s.day_age_of_battery, 20, tol); + EXPECT_NEAR(s.day_age_of_battery, 20.79, tol); EXPECT_NEAR(s.calendar->q_relative_calendar, 99.89, tol); EXPECT_NEAR(s.calendar->dq_relative_calendar_old, 0, tol); @@ -181,7 +181,7 @@ TEST_F(lib_battery_lifetime_calendar_matrix_test, runCalendarMatrixTest) { idx++; } s = cal_model->get_state(); - EXPECT_NEAR(s.day_age_of_battery, 41, tol); + EXPECT_NEAR(s.day_age_of_battery, 41.625, tol); EXPECT_NEAR(s.calendar->q_relative_calendar, 99.775, tol); EXPECT_NEAR(s.calendar->dq_relative_calendar_old, 0, tol); } @@ -197,7 +197,7 @@ TEST_F(lib_battery_lifetime_calendar_matrix_test, replaceBatteryTest) { idx++; } lifetime_state s = cal_model->get_state(); - EXPECT_NEAR(s.day_age_of_battery, 8333, tol); + EXPECT_NEAR(s.day_age_of_battery, 8333.29, tol); EXPECT_NEAR(s.calendar->q_relative_calendar, 41.51, tol); EXPECT_NEAR(s.calendar->dq_relative_calendar_old, 0, tol); @@ -224,7 +224,7 @@ TEST_F(lib_battery_lifetime_calendar_model_test, runCalendarModelTest) { idx++; } lifetime_state s = cal_model->get_state(); - EXPECT_NEAR(s.day_age_of_battery, 20, tol); + EXPECT_NEAR(s.day_age_of_battery, 20.79, tol); EXPECT_NEAR(s.calendar->q_relative_calendar, 101.78, tol); EXPECT_NEAR(s.calendar->dq_relative_calendar_old, 0.00217, tol); @@ -236,7 +236,7 @@ TEST_F(lib_battery_lifetime_calendar_model_test, runCalendarModelTest) { idx++; } s = cal_model->get_state(); - EXPECT_NEAR(s.day_age_of_battery, 41, tol); + EXPECT_NEAR(s.day_age_of_battery, 41.625, tol); EXPECT_NEAR(s.calendar->q_relative_calendar, 101.69, tol); EXPECT_NEAR(s.calendar->dq_relative_calendar_old, 0.00306, tol); } @@ -252,7 +252,7 @@ TEST_F(lib_battery_lifetime_calendar_model_test, replaceBatteryTest) { idx++; } lifetime_state s = cal_model->get_state(); - EXPECT_NEAR(s.day_age_of_battery, 8333, tol); + EXPECT_NEAR(s.day_age_of_battery, 8333.29, tol); EXPECT_NEAR(s.calendar->q_relative_calendar, 97.67, tol); EXPECT_NEAR(s.calendar->dq_relative_calendar_old, 0.043, tol); @@ -358,17 +358,17 @@ TEST_F(lib_battery_lifetime_nmc_test, updateCapacityTest) { ASSERT_EQ(model->get_state().nmc_state->b1_dt, 0); ASSERT_EQ(model->get_state().nmc_state->b2_dt, 0); ASSERT_EQ(model->get_state().nmc_state->b3_dt, 0); - ASSERT_EQ(model->get_state().nmc_state->day_age_of_battery_float, 0); + ASSERT_EQ(model->get_state().day_age_of_battery, 0); //check U_neg, and Voc functions (SOC as a fractional input) - ASSERT_NEAR(model->Uneg_computation(0.1), 0.242, tol); - ASSERT_NEAR(model->Voc_computation(0.1), 3.4679, tol); - ASSERT_NEAR(model->Uneg_computation(0.5), 0.1726, tol); - ASSERT_NEAR(model->Voc_computation(0.5), 3.6912, tol); - ASSERT_NEAR(model->Uneg_computation(0.9), 0.1032, tol); - ASSERT_NEAR(model->Voc_computation(0.9), 4.0818, tol); - - // check number of cycles + ASSERT_NEAR(model->calculate_Uneg(0.1), 0.242, tol); + ASSERT_NEAR(model->calculate_Voc(0.1), 3.4679, tol); + ASSERT_NEAR(model->calculate_Uneg(0.5), 0.1726, tol); + ASSERT_NEAR(model->calculate_Voc(0.5), 3.6912, tol); + ASSERT_NEAR(model->calculate_Uneg(0.9), 0.1032, tol); + ASSERT_NEAR(model->calculate_Voc(0.9), 4.0818, tol); + + // check number of cycles while (idx < 876){ model->runLifetimeModels(idx, true, 5,95, 25); model->runLifetimeModels(idx, true, 95, 5, 25); @@ -377,26 +377,32 @@ TEST_F(lib_battery_lifetime_nmc_test, updateCapacityTest) { idx ++; } - + ASSERT_EQ(model->get_state().n_cycles, 875); } TEST_F(lib_battery_lifetime_nmc_test, NoCyclingCapacityTest) { size_t idx = 0; - double tol = 0.1; + double tol = 0.001; // check capacity degradation with no cycling while (idx < 2400) { model->runLifetimeModels(idx, false, 50, 50, 25); - - auto state = model->get_state(); - idx++; } - //Values compared to MATLAB model - ASSERT_EQ(model->get_state().n_cycles, 0); - ASSERT_NEAR(model->get_state().q_relative, 98.8258,tol); + + auto state = model->get_state(); + EXPECT_EQ(state.n_cycles, 0); + EXPECT_NEAR(state.day_age_of_battery, 100, tol); + EXPECT_NEAR(state.q_relative, 98.825, tol); + EXPECT_NEAR(state.nmc_state->q_relative_li, 98.825, tol); + EXPECT_NEAR(state.nmc_state->q_relative_neg, 100, tol); + EXPECT_NEAR(state.nmc_state->dq_relative_li_old, 0.082, tol); + EXPECT_EQ(state.nmc_state->b1_dt, 0); + EXPECT_EQ(state.nmc_state->b2_dt, 0); + EXPECT_EQ(state.nmc_state->b3_dt, 0); + EXPECT_EQ(state.nmc_state->c2_dt, 0); model = std::unique_ptr(new lifetime_nmc_t(dt_hour)); idx = 0; @@ -404,12 +410,18 @@ TEST_F(lib_battery_lifetime_nmc_test, NoCyclingCapacityTest) { // simulate at battery temperature 35 C for 300 days while (idx < 7200) { model->runLifetimeModels(idx, false, 50, 50, 35); - - auto state = model->get_state(); - idx++; } - ASSERT_EQ(model->get_state().n_cycles, 0); - ASSERT_NEAR(model->get_state().nmc_state->q_relative_li, 92.8315, tol); + state = model->get_state(); + EXPECT_EQ(model->get_state().n_cycles, 0); + EXPECT_NEAR(state.day_age_of_battery, 300, tol); + EXPECT_NEAR(state.q_relative, 92.831, tol); + EXPECT_NEAR(state.nmc_state->q_relative_li, 92.831, tol); + EXPECT_NEAR(state.nmc_state->q_relative_neg, 100, tol); + EXPECT_NEAR(state.nmc_state->dq_relative_li_old, 0.142, tol); + EXPECT_EQ(state.nmc_state->b1_dt, 0); + EXPECT_EQ(state.nmc_state->b2_dt, 0); + EXPECT_EQ(state.nmc_state->b3_dt, 0); + EXPECT_EQ(state.nmc_state->c2_dt, 0); } diff --git a/test/shared_test/lib_battery_test.cpp b/test/shared_test/lib_battery_test.cpp index 23d29df03b4..45af7732231 100644 --- a/test/shared_test/lib_battery_test.cpp +++ b/test/shared_test/lib_battery_test.cpp @@ -231,6 +231,7 @@ TEST_F(lib_battery_test, runTestCycleAt1C){ // the SOC isn't at 5 so it means the controller is not able to calculate a current/voltage at which to discharge to 5 s.capacity = {54.5, 1000, 960.01, 20.25, 0, 5.67, 7.79, 2}; s.batt_voltage = 366.96; + s.lifetime.day_age_of_battery = 0.875; s.lifetime.q_relative = 100; s.lifetime.cycle->q_relative_cycle = 100; s.lifetime.calendar->q_relative_calendar = 101.976; @@ -264,7 +265,7 @@ TEST_F(lib_battery_test, runTestCycleAt1C){ s.lifetime.cycle->rainflow_Xlt = 88.79; s.lifetime.cycle->rainflow_Ylt = 89.30; s.lifetime.cycle->rainflow_jlt = 7; - s.lifetime.day_age_of_battery = 2739; + s.lifetime.day_age_of_battery = 2739.71; s.lifetime.calendar->q_relative_calendar = 98.0; s.lifetime.calendar->dq_relative_calendar_old = 0.039; s.thermal = {96.0, 20.00, 20}; @@ -304,6 +305,7 @@ TEST_F(lib_battery_test, runTestCycleAt3C){ // the SOC isn't at 5 so it means the controller is not able to calculate a current/voltage at which to discharge to 5 s.capacity = {48.01, 1000, 960.11, 26.74, 0, 5.00, 7.78, 2}; s.batt_voltage = 338.91; + s.lifetime.day_age_of_battery = 0.29; s.lifetime.q_relative = 101.98; s.lifetime.calendar->q_relative_calendar = 101.98; s.last_idx = 0; @@ -328,7 +330,7 @@ TEST_F(lib_battery_test, runTestCycleAt3C){ s.capacity = {49.06, 920.77, 883.94, 8.89, 0, 5.55, 6.55, 2}; s.batt_voltage = 362.25; s.lifetime.q_relative = 93.08; - s.lifetime.day_age_of_battery = 2613; + s.lifetime.day_age_of_battery = 2613.08; s.lifetime.cycle->q_relative_cycle = 92.08; s.lifetime.n_cycles = 397; s.lifetime.range = 88.51; @@ -678,6 +680,7 @@ TEST_F(lib_battery_test, AdaptiveTimestep) { EXPECT_NEAR(batt_adaptive->SOC(), 88.67, 1e-2); } + TEST_F(lib_battery_test, AugmentCapacity) { std::vector augmentation_percent = {50, 40, 30}; batteryModel->setupReplacements(augmentation_percent); @@ -733,3 +736,18 @@ TEST_F(lib_battery_test, ReplaceByCapacityTest){ double rep = batteryModel->getNumReplacementYear(); EXPECT_EQ(rep, 1); } + +TEST_F(lib_battery_test, NMCLifeModel) { + auto lifetimeModelNMC = new lifetime_nmc_t(dtHour); + auto thermalModelNMC = new thermal_t(1.0, mass, surface_area, resistance, Cp, h, T_room); + auto capacityModelNMC = new capacity_lithium_ion_t(q, SOC_init, SOC_max, SOC_min, dtHour); + auto voltageModelNMC = new voltage_dynamic_t(n_series, n_strings, Vnom_default, Vfull, Vexp, Vnom, Qfull, Qexp, Qnom, + C_rate, resistance, dtHour); + auto lossModelNMC = new losses_t(monthlyLosses, monthlyLosses, monthlyLosses); + + auto batteryNMC = std::unique_ptr(new battery_t(dtHour, chemistry, capacityModelNMC, voltageModelNMC, lifetimeModelNMC, thermalModelNMC, lossModelNMC)); + double I = Qfull * n_strings * 2; + + batteryNMC->run(0, I); + +} diff --git a/test/shared_test/lib_battery_test.h b/test/shared_test/lib_battery_test.h index ec4bc08bf2f..781fe97b5f2 100644 --- a/test/shared_test/lib_battery_test.h +++ b/test/shared_test/lib_battery_test.h @@ -29,6 +29,7 @@ OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "lib_battery.h" #include "lib_battery_capacity_test.h" #include "lib_battery_lifetime_test.h" +#include "lib_battery_lifetime_nmc.h" static void compareState(thermal_state tested_state, thermal_state expected_state, const std::string& msg){ double tol = 0.02; @@ -197,7 +198,7 @@ class lib_battery_test : public ::testing::Test capacity_lithium_ion_t * capacityModel; voltage_t * voltageModel; thermal_t * thermalModel; - lifetime_calendar_cycle_t * lifetimeModel; + lifetime_t * lifetimeModel; losses_t * lossModel; std::unique_ptr batteryModel; @@ -260,7 +261,7 @@ class lib_battery_test : public ::testing::Test voltageModel = new voltage_dynamic_t(n_series, n_strings, Vnom_default, Vfull, Vexp, Vnom, Qfull, Qexp, Qnom, C_rate, resistance, dtHour); lifetimeModel = new lifetime_calendar_cycle_t(cycleLifeMatrix, dtHour, 1.02, 2.66e-3, -7280, 930); - thermalModel = new thermal_t(1.0, mass, surface_area, resistance, Cp, h, capacityVsTemperature, T_room); + thermalModel = new thermal_t(dtHour, mass, surface_area, resistance, Cp, h, capacityVsTemperature, T_room); lossModel = new losses_t(monthlyLosses, monthlyLosses, monthlyLosses); batteryModel = std::unique_ptr(new battery_t(dtHour, chemistry, capacityModel, voltageModel, lifetimeModel, thermalModel, lossModel)); } diff --git a/test/ssc_test/cmod_battery_pvsamv1_test.cpp b/test/ssc_test/cmod_battery_pvsamv1_test.cpp index ee4239a1200..58937ca330c 100644 --- a/test/ssc_test/cmod_battery_pvsamv1_test.cpp +++ b/test/ssc_test/cmod_battery_pvsamv1_test.cpp @@ -810,7 +810,6 @@ TEST_F(CMPvsamv1BatteryIntegration_cmod_pvsamv1, ResidentialDCBatteryModelPriceS auto batt_q_rel = data_vtab->as_vector_ssc_number_t("batt_capacity_percent"); auto batt_cyc_avg = data_vtab->as_vector_ssc_number_t("batt_DOD_cycle_average"); EXPECT_NEAR(batt_q_rel.back(), 97.836, 1e-2); - EXPECT_NEAR(batt_cyc_avg.back(), 22.62, 0.5); - //EXPECT_NEAR(batt_cyc_avg.back(), 24.72, 0.5); // from patch + EXPECT_NEAR(batt_cyc_avg.back(), 24.72, 0.5); } } From b777b7d2920c45a4a658a70acae6eb8499008ba6 Mon Sep 17 00:00:00 2001 From: xuanluo113 Date: Tue, 9 Feb 2021 16:04:09 -0800 Subject: [PATCH 46/76] unit test --- tst/EnergyPlus/unit/SolarShading.unit.cc | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tst/EnergyPlus/unit/SolarShading.unit.cc b/tst/EnergyPlus/unit/SolarShading.unit.cc index 3917d42c9b4..671a2f16630 100644 --- a/tst/EnergyPlus/unit/SolarShading.unit.cc +++ b/tst/EnergyPlus/unit/SolarShading.unit.cc @@ -2613,3 +2613,22 @@ TEST_F(EnergyPlusFixture, SolarShadingTest_selectActiveWindowShadingControl) activeWindowShadingControl = DataSurfaces::Surface(curSurface).windowShadingControlList[curIndexActiveWindowShadingControl]; EXPECT_EQ(activeWindowShadingControl, 1); } + +TEST_F(EnergyPlusFixture, SolarShadingTest_ShadingFlagTest) +{ + WinShadingType ShadingFlag = WinShadingType::IntShade; + EXPECT_TRUE(IS_SHADED(ShadingFlag)); + EXPECT_TRUE(ANY_SHADE(ShadingFlag)); + EXPECT_TRUE(ANY_SHADE_SCREEN(ShadingFlag)); + EXPECT_TRUE(ANY_INTERIOR_SHADE_BLIND(ShadingFlag)); + EXPECT_FALSE(ANY_BLIND(ShadingFlag)); + EXPECT_FALSE(ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadingFlag)); + EXPECT_FALSE(ANY_BETWEENGLASS_SHADE_BLIND(ShadingFlag)); + + ShadingFlag = WinShadingType::ExtBlind; + EXPECT_TRUE(ANY_BLIND(ShadingFlag)); + EXPECT_TRUE(ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadingFlag)); + + ShadingFlag = WinShadingType::GlassConditionallyLightened; + IS_SHADED_NO_GLARE_CTRL(ANY_BETWEENGLASS_SHADE_BLIND(ShadingFlag)); +} \ No newline at end of file From 6c00742fca390f827806b3cae9678de0aac5beeb Mon Sep 17 00:00:00 2001 From: Noel Merket Date: Wed, 10 Feb 2021 14:01:17 -0700 Subject: [PATCH 47/76] saving my place --- idd/Energy+.idd.in | 9 ++++----- src/EnergyPlus/ElectricPowerServiceManager.cc | 10 +++++----- testfiles/ShopWithPVandLiIonBattery.idf | 4 ++-- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/idd/Energy+.idd.in b/idd/Energy+.idd.in index d5d1a26e9ea..8c0a9b717bd 100644 --- a/idd/Energy+.idd.in +++ b/idd/Energy+.idd.in @@ -88855,17 +88855,16 @@ ElectricLoadCenter:Storage:LiIonNMCBattery, \units Ah \default 3.2 \note move these 3 above Fully Charged Cell Voltage - N15, \field Cell Capacity at End of Exponential Zone as Fraction of Full Cell Capacity + N15, \field Fraction of Cell Capacity Removed at the End of Exponential Zone \type real \minimum> 0.0 \maximum< 1.0 - \default 0.81925 - N16, \field Cell Capacity at End of Nominal Zone as Fraction of Full Cell Capacity + \default 0.8075 + N16, \field Fraction of Cell Capacity Removed at the End of Nominal Zone \type real \minimum> 0.0 \maximum< 1.0 - \default 0.088231 - \note 8.8231% of Qfull + \default 0.976875 N17, \field Rate at Which Voltage vs Capacity Curve Input \type real \minimum> 0 diff --git a/src/EnergyPlus/ElectricPowerServiceManager.cc b/src/EnergyPlus/ElectricPowerServiceManager.cc index a13611c590f..4816b48439a 100644 --- a/src/EnergyPlus/ElectricPowerServiceManager.cc +++ b/src/EnergyPlus/ElectricPowerServiceManager.cc @@ -3165,13 +3165,13 @@ ElectricStorage::ElectricStorage( // main constructor // see lib_battery_voltage.cpp line 268 liIon_Vnom_default_ = DataIPShortCuts::lNumericFieldBlanks(13) ? 3.342 : DataIPShortCuts::rNumericArgs(13); liIon_Qfull_ = DataIPShortCuts::lNumericFieldBlanks(14) ? 3.2 : DataIPShortCuts::rNumericArgs(14); - liIon_Qexp_ = DataIPShortCuts::lNumericFieldBlanks(15) ? 0.81925 * liIon_Qfull_ : DataIPShortCuts::rNumericArgs(15) * liIon_Qfull_; - liIon_Qnom_ = DataIPShortCuts::lNumericFieldBlanks(16) ? 0.088231 * liIon_Qfull_ : DataIPShortCuts::rNumericArgs(16) * liIon_Qfull_; + liIon_Qexp_ = DataIPShortCuts::lNumericFieldBlanks(15) ? 0.8075 * liIon_Qfull_ : DataIPShortCuts::rNumericArgs(15) * liIon_Qfull_; + liIon_Qnom_ = DataIPShortCuts::lNumericFieldBlanks(16) ? 0.976875 * liIon_Qfull_ : DataIPShortCuts::rNumericArgs(16) * liIon_Qfull_; // FIXME: Validate Qexp and Qnom are less than Qfull, and Qnom > Qexp? liIon_C_rate_ = DataIPShortCuts::lNumericFieldBlanks(17) ? 1.0 : DataIPShortCuts::rNumericArgs(17); internalR_ = DataIPShortCuts::lNumericFieldBlanks(18) ? 0.09 : DataIPShortCuts::rNumericArgs(18); - maxAhCapacity_ = liIon_Qfull_ * seriesNum_ * parallelNum_; + maxAhCapacity_ = liIon_Qfull_ * parallelNum_; // Set the Lifetime model in SSC // I'm using a raw pointer here because the the battery_t constructor expects it. @@ -3196,9 +3196,9 @@ ElectricStorage::ElectricStorage( // main constructor battery_params::CHEM::LITHIUM_ION, new capacity_lithium_ion_t( maxAhCapacity_, // Capacity of the whole battery - startingSOC_, + startingSOC_ * 100.0, + 100.0, // Reset later 0.0, // Reset later - 1.0, // Reset later DataHVACGlobals::TimeStepSys ), new voltage_dynamic_t( diff --git a/testfiles/ShopWithPVandLiIonBattery.idf b/testfiles/ShopWithPVandLiIonBattery.idf index 401a5d13211..f85551ffa67 100644 --- a/testfiles/ShopWithPVandLiIonBattery.idf +++ b/testfiles/ShopWithPVandLiIonBattery.idf @@ -5014,8 +5014,8 @@ , !- Zone Name 0, !- Radiative Fraction KandlerSmith, !- Lifetime Model - 35, !- Number of Cells in Series - 270, !- Number of Strings in Parallel + 139, !- Number of Cells in Series + 17360, !- Number of Strings in Parallel 0.7, !- Initial Fractional State of Charge , !- DC to DC Charging Efficiency , !- Battery Mass From b6277f19de93257f24df6cf01a38344d414a8dfa Mon Sep 17 00:00:00 2001 From: Noel Merket Date: Thu, 11 Feb 2021 15:49:08 -0700 Subject: [PATCH 48/76] updating battery to something more standard --- testfiles/ShopWithPVandLiIonBattery.idf | 6 +++--- testfiles/ShopWithPVandStorage.idf | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/testfiles/ShopWithPVandLiIonBattery.idf b/testfiles/ShopWithPVandLiIonBattery.idf index f85551ffa67..fa0c7d4a97c 100644 --- a/testfiles/ShopWithPVandLiIonBattery.idf +++ b/testfiles/ShopWithPVandLiIonBattery.idf @@ -5015,11 +5015,11 @@ 0, !- Radiative Fraction KandlerSmith, !- Lifetime Model 139, !- Number of Cells in Series - 17360, !- Number of Strings in Parallel + 8, !- Number of Strings in Parallel 0.7, !- Initial Fractional State of Charge , !- DC to DC Charging Efficiency - , !- Battery Mass - , !- Battery Surface Area + 114, !- Battery Mass + 1.42, !- Battery Surface Area , !- Battery Specific Heat Capacity ; !- Heat Transfer Coefficient Between Battery and Ambient diff --git a/testfiles/ShopWithPVandStorage.idf b/testfiles/ShopWithPVandStorage.idf index 0f9e33a46b6..a77edd4fdc4 100644 --- a/testfiles/ShopWithPVandStorage.idf +++ b/testfiles/ShopWithPVandStorage.idf @@ -72,7 +72,7 @@ 1, !- Begin Day of Month , !- Begin Year 7, !- End Month - 1, !- End Day of Month + 2, !- End Day of Month , !- End Year Sunday, !- Day of Week for Start Day No, !- Use Weather File Holidays and Special Days From 0e7c4bf182c6e177783eaec452c6da13ef9ecc99 Mon Sep 17 00:00:00 2001 From: Noel Merket Date: Thu, 11 Feb 2021 17:17:09 -0700 Subject: [PATCH 49/76] dealing with sequencing of reinit methods and time check, also making battery bigger --- src/EnergyPlus/ElectricPowerServiceManager.cc | 2 ++ testfiles/ShopWithPVandLiIonBattery.idf | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/EnergyPlus/ElectricPowerServiceManager.cc b/src/EnergyPlus/ElectricPowerServiceManager.cc index 4816b48439a..ad61c0a28df 100644 --- a/src/EnergyPlus/ElectricPowerServiceManager.cc +++ b/src/EnergyPlus/ElectricPowerServiceManager.cc @@ -3385,6 +3385,7 @@ void ElectricStorage::reinitAtBeginEnvironment() } else if (storageModelMode_ == StorageModelType::liIonNmcBattery) { // Copy the initial battery state to the last battery state *ssc_lastBatteryState_ = *ssc_initBatteryState_; + ssc_battery_->set_state(*ssc_lastBatteryState_); } myWarmUpFlag_ = true; } @@ -3425,6 +3426,7 @@ void ElectricStorage::reinitAtEndWarmup() } else if (storageModelMode_ == StorageModelType::liIonNmcBattery) { // Copy the initial battery state to the last battery state *ssc_lastBatteryState_ = *ssc_initBatteryState_; + ssc_battery_->set_state(*ssc_lastBatteryState_); } myWarmUpFlag_ = false; } diff --git a/testfiles/ShopWithPVandLiIonBattery.idf b/testfiles/ShopWithPVandLiIonBattery.idf index fa0c7d4a97c..06977e3dcf0 100644 --- a/testfiles/ShopWithPVandLiIonBattery.idf +++ b/testfiles/ShopWithPVandLiIonBattery.idf @@ -5015,11 +5015,11 @@ 0, !- Radiative Fraction KandlerSmith, !- Lifetime Model 139, !- Number of Cells in Series - 8, !- Number of Strings in Parallel + 25, !- Number of Strings in Parallel 0.7, !- Initial Fractional State of Charge , !- DC to DC Charging Efficiency - 114, !- Battery Mass - 1.42, !- Battery Surface Area + 342, !- Battery Mass + 4.26, !- Battery Surface Area , !- Battery Specific Heat Capacity ; !- Heat Transfer Coefficient Between Battery and Ambient From ae53abf38f3ad5b27f7624feaeddbefc4fadadb6 Mon Sep 17 00:00:00 2001 From: Noel Merket Date: Fri, 12 Feb 2021 08:49:25 -0700 Subject: [PATCH 50/76] adding ) in CMakeLists.txt --- testfiles/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testfiles/CMakeLists.txt b/testfiles/CMakeLists.txt index 1178c7b65a7..f06a762e0c7 100644 --- a/testfiles/CMakeLists.txt +++ b/testfiles/CMakeLists.txt @@ -499,7 +499,7 @@ add_simulation_test(IDF_FILE RetailPackagedTESCoil.idf EPW_FILE USA_IL_Chicago-O add_simulation_test(IDF_FILE RoomAirflowNetwork.idf EPW_FILE USA_IL_Chicago-OHare.Intl.AP.725300_TMY3.epw) add_simulation_test(IDF_FILE SeriesActiveBranch.idf EPW_FILE USA_IL_Chicago-OHare.Intl.AP.725300_TMY3.epw) add_simulation_test(IDF_FILE ShopWithPVandBattery.idf EPW_FILE USA_OK_Oklahoma.City-Will.Rogers.World.AP.723530_TMY3.epw) -add_simulation_test(IDF_FILE ShopWithPVandLiIonBattery.idf EPW_FILE USA_OK_Oklahoma.City-Will.Rogers.World.AP.723530_TMY3.epw +add_simulation_test(IDF_FILE ShopWithPVandLiIonBattery.idf EPW_FILE USA_OK_Oklahoma.City-Will.Rogers.World.AP.723530_TMY3.epw) add_simulation_test(IDF_FILE ShopWithPVandStorage.idf EPW_FILE USA_OK_Oklahoma.City-Will.Rogers.World.AP.723530_TMY3.epw) add_simulation_test(IDF_FILE ShopWithSimplePVT.idf EPW_FILE USA_OK_Oklahoma.City-Will.Rogers.World.AP.723530_TMY3.epw) add_simulation_test(IDF_FILE SingleFamilyHouse_TwoSpeed_ZoneAirBalance.idf EPW_FILE USA_IL_Chicago-OHare.Intl.AP.725300_TMY3.epw) From 3a944d824eabf47f390a1dbac00daa20eefd8cdd Mon Sep 17 00:00:00 2001 From: Noel Merket Date: Fri, 12 Feb 2021 10:09:49 -0700 Subject: [PATCH 51/76] a few minor tweaks to the idd and input processing --- idd/Energy+.idd.in | 26 +++++++++++++------ src/EnergyPlus/ElectricPowerServiceManager.cc | 14 ++++------ 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/idd/Energy+.idd.in b/idd/Energy+.idd.in index 8c0a9b717bd..bfd4bef075b 100644 --- a/idd/Energy+.idd.in +++ b/idd/Energy+.idd.in @@ -88762,6 +88762,7 @@ ElectricLoadCenter:Storage:LiIonNMCBattery, \memo current, and energy losses with charging and discharging during each time step. \memo The cumulative battery damage can be also modeled and reported at the end of \memo each simulation run. + \min-fields 11 A1, \field Name \required-field \type alpha @@ -88789,14 +88790,15 @@ ElectricLoadCenter:Storage:LiIonNMCBattery, N2, \field Number of Cells in Series \type integer \minimum 1 - \default 3 - \note Each cell in a Li-ion battery is 3.6V - \note with a capacity of 3.2 Ah. + \required-field + \note Battery voltage is calculated by multiplying this field + \note by the nominal cell voltage (N13, default 3.342V) N3, \field Number of Strings in Parallel \type integer \minimum 1 - \default 1 - \note TODO + \required-field + \note Capacity (Ah) is determined by multiplying this field + \note by the cell capacity (N14, default 3.2 Ah) N4, \field Initial Fractional State of Charge \type real \minimum 0 @@ -88813,12 +88815,12 @@ ElectricLoadCenter:Storage:LiIonNMCBattery, \type real \minimum> 0 \units kg - \default 95.1255 + \required-field N7, \field Battery Surface Area \type real \minimum> 0 \units m2 - \default 0.5 + \required-field N8, \field Battery Specific Heat Capacity \type real \minimum> 0 @@ -88834,47 +88836,55 @@ ElectricLoadCenter:Storage:LiIonNMCBattery, \minimum> 0 \units V \default 4.2 + \note Most users should not need to change this value. N11, \field Cell Voltage at End of Exponential Zone \type real \minimum> 0 \units V \default 3.53 + \note Most users should not need to change this value. N12, \field Cell Voltage at End of Nominal Zone \type real \minimum> 0 \units V \default 3.342 + \note Most users should not need to change this value. N13, \field Default Nominal Cell Voltage \type real \minimum> 0 \units V \default 3.342 + \note Most users should not need to change this value. N14, \field Fully Charged Cell Capacity \type real \minimum> 0 \units Ah \default 3.2 - \note move these 3 above Fully Charged Cell Voltage + \note Most users should not need to change this value. N15, \field Fraction of Cell Capacity Removed at the End of Exponential Zone \type real \minimum> 0.0 \maximum< 1.0 \default 0.8075 + \note Most users should not need to change this value. N16, \field Fraction of Cell Capacity Removed at the End of Nominal Zone \type real \minimum> 0.0 \maximum< 1.0 \default 0.976875 + \note Most users should not need to change this value. N17, \field Rate at Which Voltage vs Capacity Curve Input \type real \minimum> 0 \default 1 + \note Most users should not need to change this value. N18; \field Battery Cell Internal Electrical Resistance \type real \minimum 0 \units ohms \default 0.09 \note for a single cell + \note Most users should not need to change this value. ElectricLoadCenter:Transformer, \memo a list of meters that can be reported are available after a run on diff --git a/src/EnergyPlus/ElectricPowerServiceManager.cc b/src/EnergyPlus/ElectricPowerServiceManager.cc index ad61c0a28df..23a065a44e7 100644 --- a/src/EnergyPlus/ElectricPowerServiceManager.cc +++ b/src/EnergyPlus/ElectricPowerServiceManager.cc @@ -82,9 +82,6 @@ #include #include -// SSC Headers -#include <../third_party/ssc/shared/lib_battery.h> - namespace EnergyPlus { std::unique_ptr facilityElectricServiceObj; @@ -3150,12 +3147,12 @@ ElectricStorage::ElectricStorage( // main constructor } else { lifeCalculation_ = BatteryDegradationModelType::lifeCalculationNo; } - seriesNum_ = DataIPShortCuts::lNumericFieldBlanks(2) ? 3 : static_cast(DataIPShortCuts::rNumericArgs(2)); - parallelNum_ = DataIPShortCuts::lNumericFieldBlanks(3) ? 1 : static_cast(DataIPShortCuts::rNumericArgs(3)); + seriesNum_ = static_cast(DataIPShortCuts::rNumericArgs(2)); + parallelNum_ = static_cast(DataIPShortCuts::rNumericArgs(3)); startingSOC_ = DataIPShortCuts::lNumericFieldBlanks(4) ? 0.5 : DataIPShortCuts::rNumericArgs(4); liIon_dcToDcChargingEff_ = DataIPShortCuts::lNumericFieldBlanks(5) ? 0.95 : DataIPShortCuts::rNumericArgs(5); - liIon_mass_ = DataIPShortCuts::lNumericFieldBlanks(6) ? 95.1255 : DataIPShortCuts::rNumericArgs(6); - liIon_surfaceArea_ = DataIPShortCuts::lNumericFieldBlanks(7) ? 0.5 : DataIPShortCuts::rNumericArgs(7); + liIon_mass_ = DataIPShortCuts::rNumericArgs(6); + liIon_surfaceArea_ = DataIPShortCuts::rNumericArgs(7); liIon_Cp_ = DataIPShortCuts::lNumericFieldBlanks(8) ? 1500.0 : DataIPShortCuts::rNumericArgs(8); liIon_heatTransferCoef_ = DataIPShortCuts::lNumericFieldBlanks(9) ? 7.5 : DataIPShortCuts::rNumericArgs(9); liIon_Vfull_ = DataIPShortCuts::lNumericFieldBlanks(10) ? 4.2 : DataIPShortCuts::rNumericArgs(10); @@ -3167,7 +3164,7 @@ ElectricStorage::ElectricStorage( // main constructor liIon_Qfull_ = DataIPShortCuts::lNumericFieldBlanks(14) ? 3.2 : DataIPShortCuts::rNumericArgs(14); liIon_Qexp_ = DataIPShortCuts::lNumericFieldBlanks(15) ? 0.8075 * liIon_Qfull_ : DataIPShortCuts::rNumericArgs(15) * liIon_Qfull_; liIon_Qnom_ = DataIPShortCuts::lNumericFieldBlanks(16) ? 0.976875 * liIon_Qfull_ : DataIPShortCuts::rNumericArgs(16) * liIon_Qfull_; - // FIXME: Validate Qexp and Qnom are less than Qfull, and Qnom > Qexp? + // FIXME: Validate Qexp and Qnom are less than Qfull, and Qnom > Qexp liIon_C_rate_ = DataIPShortCuts::lNumericFieldBlanks(17) ? 1.0 : DataIPShortCuts::rNumericArgs(17); internalR_ = DataIPShortCuts::lNumericFieldBlanks(18) ? 0.09 : DataIPShortCuts::rNumericArgs(18); @@ -3290,7 +3287,6 @@ ElectricStorage::ElectricStorage( // main constructor } else if (storageModelMode_ == StorageModelType::kiBaMBattery) { SetupEMSInternalVariable(state, "Electrical Storage Battery Maximum Capacity", name_, "[Ah]", maxAhCapacity_); } - // FIXME: Add EMS Variable for Li-ion battery } if (zoneNum_ > 0) { From 522942e6af3d8f56e9c3a9b9dd08d37c0eaaa2f7 Mon Sep 17 00:00:00 2001 From: Noel Merket Date: Fri, 12 Feb 2021 11:13:11 -0700 Subject: [PATCH 52/76] voltage input validation and test --- src/EnergyPlus/ElectricPowerServiceManager.cc | 112 ++++++++++-------- .../unit/ElectricPowerServiceManager.unit.cc | 40 +++---- 2 files changed, 79 insertions(+), 73 deletions(-) diff --git a/src/EnergyPlus/ElectricPowerServiceManager.cc b/src/EnergyPlus/ElectricPowerServiceManager.cc index 23a065a44e7..84e804c9ff8 100644 --- a/src/EnergyPlus/ElectricPowerServiceManager.cc +++ b/src/EnergyPlus/ElectricPowerServiceManager.cc @@ -3158,8 +3158,15 @@ ElectricStorage::ElectricStorage( // main constructor liIon_Vfull_ = DataIPShortCuts::lNumericFieldBlanks(10) ? 4.2 : DataIPShortCuts::rNumericArgs(10); liIon_Vexp_ = DataIPShortCuts::lNumericFieldBlanks(11) ? 3.53 : DataIPShortCuts::rNumericArgs(11); liIon_Vnom_ = DataIPShortCuts::lNumericFieldBlanks(12) ? 3.342 : DataIPShortCuts::rNumericArgs(12); - // FIXME: Validate Vnom < Vexp - // see lib_battery_voltage.cpp line 268 + if (liIon_Vfull_ < liIon_Vexp_ or liIon_Vexp_ < liIon_Vnom_) { + ShowSevereError(state, routineName + DataIPShortCuts::cCurrentModuleObject + "=\"" + DataIPShortCuts::cAlphaArgs(1) + "\", invalid entry."); + ShowContinueError(state, DataIPShortCuts::cNumericFieldNames(10) + " must be greater than " + DataIPShortCuts::cNumericFieldNames(11) + ","); + ShowContinueError(state, "which must be greater than " + DataIPShortCuts::cNumericFieldNames(12) + "."); + for (int i = 10; i <= 12; ++i) { + ShowContinueError(state, format("{} = {:.3R}", DataIPShortCuts::cNumericFieldNames(i), DataIPShortCuts::rNumericArgs(i))); + } + errorsFound = true; + } liIon_Vnom_default_ = DataIPShortCuts::lNumericFieldBlanks(13) ? 3.342 : DataIPShortCuts::rNumericArgs(13); liIon_Qfull_ = DataIPShortCuts::lNumericFieldBlanks(14) ? 3.2 : DataIPShortCuts::rNumericArgs(14); liIon_Qexp_ = DataIPShortCuts::lNumericFieldBlanks(15) ? 0.8075 * liIon_Qfull_ : DataIPShortCuts::rNumericArgs(15) * liIon_Qfull_; @@ -3170,63 +3177,64 @@ ElectricStorage::ElectricStorage( // main constructor maxAhCapacity_ = liIon_Qfull_ * parallelNum_; - // Set the Lifetime model in SSC - // I'm using a raw pointer here because the the battery_t constructor expects it. - // The pointer is then passed into the battery_t where it is converted into a unique_ptr and persists along with that object. - // Therefore I am not deleting this pointer here because that will be handled by the battery_t class. - lifetime_t* battLifetime; - if (lifeCalculation_ == BatteryDegradationModelType::lifeCalculationYes) { - battLifetime = new lifetime_nmc_t(DataHVACGlobals::TimeStepSys); - } else { - // This sets a lifetime model where the capacity is always 100%. - std::vector tblVals{{20, 0, 100, 20, 5000, 100, 20, 10000, 100, 80, 0, 100, 80, 1000, 100, 80, 2000, 100}}; - util::matrix_t battLifetimeMatrix(6, 3, &tblVals); - battLifetime = new lifetime_calendar_cycle_t(battLifetimeMatrix, DataHVACGlobals::TimeStepSys); - } + if (!errorsFound) { + // Set the Lifetime model in SSC + // I'm using a raw pointer here because the the battery_t constructor expects it. + // The pointer is then passed into the battery_t where it is converted into a unique_ptr and persists along with that object. + // Therefore I am not deleting this pointer here because that will be handled by the battery_t class. + lifetime_t* battLifetime; + if (lifeCalculation_ == BatteryDegradationModelType::lifeCalculationYes) { + battLifetime = new lifetime_nmc_t(DataHVACGlobals::TimeStepSys); + } else { + // This sets a lifetime model where the capacity is always 100%. + std::vector tblVals{{20, 0, 100, 20, 5000, 100, 20, 10000, 100, 80, 0, 100, 80, 1000, 100, 80, 2000, 100}}; + util::matrix_t battLifetimeMatrix(6, 3, &tblVals); + battLifetime = new lifetime_calendar_cycle_t(battLifetimeMatrix, DataHVACGlobals::TimeStepSys); + } + std::vector batt_losses{0}; // using double because SSC expects a double - std::vector batt_losses{0}; // using double because SSC expects a double - - // Create the SSC battery object - ssc_battery_ = std::unique_ptr( - new battery_t( - DataHVACGlobals::TimeStepSys, - battery_params::CHEM::LITHIUM_ION, - new capacity_lithium_ion_t( - maxAhCapacity_, // Capacity of the whole battery - startingSOC_ * 100.0, - 100.0, // Reset later - 0.0, // Reset later - DataHVACGlobals::TimeStepSys + // Create the SSC battery object + ssc_battery_ = std::unique_ptr( + new battery_t( + DataHVACGlobals::TimeStepSys, + battery_params::CHEM::LITHIUM_ION, + new capacity_lithium_ion_t( + maxAhCapacity_, // Capacity of the whole battery + startingSOC_ * 100.0, + 100.0, // Reset later + 0.0, // Reset later + DataHVACGlobals::TimeStepSys ), - new voltage_dynamic_t( - seriesNum_, - parallelNum_, - liIon_Vnom_default_, - liIon_Vfull_, - liIon_Vexp_, - liIon_Vnom_, - liIon_Qfull_, // Capacity of one cell - liIon_Qexp_, - liIon_Qnom_, - liIon_C_rate_, - internalR_, - DataHVACGlobals::TimeStepSys + new voltage_dynamic_t( + seriesNum_, + parallelNum_, + liIon_Vnom_default_, + liIon_Vfull_, + liIon_Vexp_, + liIon_Vnom_, + liIon_Qfull_, // Capacity of one cell + liIon_Qexp_, + liIon_Qnom_, + liIon_C_rate_, + internalR_, + DataHVACGlobals::TimeStepSys ), battLifetime, - new thermal_t( - DataHVACGlobals::TimeStepSys, - liIon_mass_, - liIon_surfaceArea_, - internalR_ * seriesNum_ / parallelNum_, // Electric resistance of the whole battery - liIon_Cp_, - liIon_heatTransferCoef_, - 20.0 // Picking a temperature for now, will reset before each run. + new thermal_t( + DataHVACGlobals::TimeStepSys, + liIon_mass_, + liIon_surfaceArea_, + internalR_ * seriesNum_ / parallelNum_, // Electric resistance of the whole battery + liIon_Cp_, + liIon_heatTransferCoef_, + 20.0 // Picking a temperature for now, will reset before each run. ), - new losses_t(batt_losses) + new losses_t(batt_losses) ) ); - ssc_lastBatteryState_ = std::unique_ptr(new battery_state(ssc_battery_->get_state())); - ssc_initBatteryState_ = std::unique_ptr(new battery_state(ssc_battery_->get_state())); + ssc_lastBatteryState_ = std::unique_ptr(new battery_state(ssc_battery_->get_state())); + ssc_initBatteryState_ = std::unique_ptr(new battery_state(ssc_battery_->get_state())); + } break; } diff --git a/tst/EnergyPlus/unit/ElectricPowerServiceManager.unit.cc b/tst/EnergyPlus/unit/ElectricPowerServiceManager.unit.cc index 85f20d83040..c538e31bba4 100644 --- a/tst/EnergyPlus/unit/ElectricPowerServiceManager.unit.cc +++ b/tst/EnergyPlus/unit/ElectricPowerServiceManager.unit.cc @@ -1033,10 +1033,8 @@ TEST_F(EnergyPlusFixture, Battery_LiIonNmc_Constructor) " , !- Zone Name", " , !- Radiative Fraction", " KandlerSmith, !- Lifetime Model", - " 5, !- Number of Cells in Series", - " 3, !- Number of Strings in Parallel", - " 0.1, !- Minimum Available State of Charge", - " 0.95, !- Maximum Availabls State of Charge", + " 139, !- Number of Cells in Series", + " 8, !- Number of Strings in Parallel", " 0.95, !- Initial Fractional State of Charge", " , !- DC to DC Charging Efficiency", " 100, !- Battery Mass", @@ -1050,11 +1048,17 @@ TEST_F(EnergyPlusFixture, Battery_LiIonNmc_Constructor) " , !- Zone Name", " , !- Radiative Fraction", " None, !- Lifetime Model", - " , !- Number of Cells in Series", - " 3, !- Number of Strings in Parallel", - " 0.9, !- Minimum Available State of Charge", - " 0.1, !- Maximum Availabls State of Charge", - " 0.5; !- Initial Fractional State of Charge", + " 139, !- Number of Cells in Series", + " 10, !- Number of Strings in Parallel", + " 0.5, !- Initial Fractional State of Charge", + " , !- DC to DC Charging Efficiency", + " 100, !- Battery Mass", + " 0.75, !- Battery Surface Area", + " , !- Battery Specific Heat Capacity", + " , !- Heat Transfer Coefficient Between Battery and Ambient", + " 1, !- Fully Charged Cell Voltage", + " 2, !- Cell Voltage at End of Exponential Zone", + " 3; !- Cell Voltage at End of Nominal Zone", }); ASSERT_TRUE(process_idf(idf_objects)); @@ -1064,20 +1068,14 @@ TEST_F(EnergyPlusFixture, Battery_LiIonNmc_Constructor) ASSERT_THROW(ElectricStorage battery2(*state, "Battery2"), EnergyPlus::FatalError); std::string const error_string = delimited_string({ " ** Severe ** ElectricStorage constructor ElectricLoadCenter:Storage:LiIonNMCBattery=\"BATTERY2\", invalid entry.", - " ** ~~~ ** Minimum Available State of Charge should be less than Maximum Available State of Charge", - " ** ~~~ ** Minimum Available State of Charge = 0.900.", - " ** ~~~ ** Maximum Available State of Charge = 0.100.", - " ** Severe ** ElectricStorage constructor ElectricLoadCenter:Storage:LiIonNMCBattery=\"BATTERY2\", invalid entry.", - " ** ~~~ ** Initial Fractional State of Charge should be less than or equal to Maximum Available State of Charge", - " ** ~~~ ** Initial Fractional State of Charge = 0.500.", - " ** ~~~ ** Maximum Available State of Charge = 0.100.", - " ** Severe ** ElectricStorage constructor ElectricLoadCenter:Storage:LiIonNMCBattery=\"BATTERY2\", invalid entry.", - " ** ~~~ ** Initial Fractional State of Charge should be greater than or equal to Minimum Available State of Charge", - " ** ~~~ ** Initial Fractional State of Charge = 0.500.", - " ** ~~~ ** Minimum Available State of Charge = 0.900.", + " ** ~~~ ** Fully Charged Cell Voltage must be greater than Cell Voltage at End of Exponential Zone,", + " ** ~~~ ** which must be greater than Cell Voltage at End of Nominal Zone.", + " ** ~~~ ** Fully Charged Cell Voltage = 1.000", + " ** ~~~ ** Cell Voltage at End of Exponential Zone = 2.000", + " ** ~~~ ** Cell Voltage at End of Nominal Zone = 3.000", " ** Fatal ** ElectricStorage constructor Preceding errors terminate program.", " ...Summary of Errors that led to program termination:", - " ..... Reference severe error count=3", + " ..... Reference severe error count=1", " ..... Last severe error=ElectricStorage constructor ElectricLoadCenter:Storage:LiIonNMCBattery=\"BATTERY2\", invalid entry." }); EXPECT_TRUE(compare_err_stream(error_string, true)); From 19c60b95d81c9e6efdb76dc798cac650cc6f591e Mon Sep 17 00:00:00 2001 From: Noel Merket Date: Fri, 12 Feb 2021 11:26:08 -0700 Subject: [PATCH 53/76] fixing initializing order problem --- src/EnergyPlus/ElectricPowerServiceManager.cc | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/EnergyPlus/ElectricPowerServiceManager.cc b/src/EnergyPlus/ElectricPowerServiceManager.cc index 84e804c9ff8..698e83d6d44 100644 --- a/src/EnergyPlus/ElectricPowerServiceManager.cc +++ b/src/EnergyPlus/ElectricPowerServiceManager.cc @@ -2945,13 +2945,14 @@ ElectricStorage::ElectricStorage( // main constructor energeticEfficCharge_(0.0), energeticEfficDischarge_(0.0), maxPowerDraw_(0.0), maxPowerStore_(0.0), maxEnergyCapacity_(0.0), parallelNum_(0), seriesNum_(0), numBattery_(0), chargeCurveNum_(0), dischargeCurveNum_(0), cycleBinNum_(0), startingSOC_(0.0), maxAhCapacity_(0.0), availableFrac_(0.0), chargeConversionRate_(0.0), chargedOCV_(0.0), dischargedOCV_(0.0), internalR_(0.0), maxDischargeI_(0.0), cutoffV_(0.0), - maxChargeRate_(0.0), lifeCalculation_(BatteryDegradationModelType::degredationNotSet), lifeCurveNum_(0), thisTimeStepStateOfCharge_(0.0), - lastTimeStepStateOfCharge_(0.0), pelNeedFromStorage_(0.0), pelFromStorage_(0.0), pelIntoStorage_(0.0), qdotConvZone_(0.0), qdotRadZone_(0.0), - timeElapsed_(0.0), thisTimeStepAvailable_(0.0), thisTimeStepBound_(0.0), lastTimeStepAvailable_(0.0), lastTimeStepBound_(0.0), - lastTwoTimeStepAvailable_(0.0), lastTwoTimeStepBound_(0.0), count0_(0), electEnergyinStorage_(0.0), thermLossRate_(0.0), thermLossEnergy_(0.0), - storageMode_(0), absoluteSOC_(0.0), fractionSOC_(0.0), batteryCurrent_(0.0), batteryVoltage_(0.0), batteryDamage_(0.0), + maxChargeRate_(0.0), lifeCalculation_(BatteryDegradationModelType::degredationNotSet), lifeCurveNum_(0), liIon_dcToDcChargingEff_(0.0), liIon_mass_(0.0), liIon_surfaceArea_(0.0), liIon_Cp_(0.0), liIon_heatTransferCoef_(0.0), liIon_Vfull_(0.0), - liIon_Vexp_(0.0), liIon_Vnom_(0.0), liIon_Vnom_default_(0.0), liIon_Qfull_(0.0), liIon_Qexp_(0.0), liIon_Qnom_(0.0), liIon_C_rate_(0.0) + liIon_Vexp_(0.0), liIon_Vnom_(0.0), liIon_Vnom_default_(0.0), liIon_Qfull_(0.0), liIon_Qexp_(0.0), liIon_Qnom_(0.0), liIon_C_rate_(0.0), + thisTimeStepStateOfCharge_(0.0), lastTimeStepStateOfCharge_(0.0), pelNeedFromStorage_(0.0), pelFromStorage_(0.0), pelIntoStorage_(0.0), + qdotConvZone_(0.0), qdotRadZone_(0.0), timeElapsed_(0.0), thisTimeStepAvailable_(0.0), thisTimeStepBound_(0.0), lastTimeStepAvailable_(0.0), + lastTimeStepBound_(0.0), lastTwoTimeStepAvailable_(0.0), lastTwoTimeStepBound_(0.0), count0_(0), electEnergyinStorage_(0.0), + thermLossRate_(0.0), thermLossEnergy_(0.0), storageMode_(0), absoluteSOC_(0.0), fractionSOC_(0.0), batteryCurrent_(0.0), batteryVoltage_(0.0), + batteryDamage_(0.0) { std::string const routineName = "ElectricStorage constructor "; @@ -3172,6 +3173,7 @@ ElectricStorage::ElectricStorage( // main constructor liIon_Qexp_ = DataIPShortCuts::lNumericFieldBlanks(15) ? 0.8075 * liIon_Qfull_ : DataIPShortCuts::rNumericArgs(15) * liIon_Qfull_; liIon_Qnom_ = DataIPShortCuts::lNumericFieldBlanks(16) ? 0.976875 * liIon_Qfull_ : DataIPShortCuts::rNumericArgs(16) * liIon_Qfull_; // FIXME: Validate Qexp and Qnom are less than Qfull, and Qnom > Qexp + // Qexp < Qnom < Qfull liIon_C_rate_ = DataIPShortCuts::lNumericFieldBlanks(17) ? 1.0 : DataIPShortCuts::rNumericArgs(17); internalR_ = DataIPShortCuts::lNumericFieldBlanks(18) ? 0.09 : DataIPShortCuts::rNumericArgs(18); From 081e3b43b74b26a2a7d3c82ec44a718c6649b008 Mon Sep 17 00:00:00 2001 From: Noel Merket Date: Fri, 12 Feb 2021 14:43:48 -0700 Subject: [PATCH 54/76] more testing --- idd/Energy+.idd.in | 2 +- src/EnergyPlus/ElectricPowerServiceManager.cc | 7 +- src/EnergyPlus/ElectricPowerServiceManager.hh | 2 + .../unit/ElectricPowerServiceManager.unit.cc | 78 +++++++++++++++++++ 4 files changed, 86 insertions(+), 3 deletions(-) diff --git a/idd/Energy+.idd.in b/idd/Energy+.idd.in index bfd4bef075b..be726d85be8 100644 --- a/idd/Energy+.idd.in +++ b/idd/Energy+.idd.in @@ -88873,7 +88873,7 @@ ElectricLoadCenter:Storage:LiIonNMCBattery, \maximum< 1.0 \default 0.976875 \note Most users should not need to change this value. - N17, \field Rate at Which Voltage vs Capacity Curve Input + N17, \field Charge Rate at Which Voltage vs Capacity Curve Was Generated \type real \minimum> 0 \default 1 diff --git a/src/EnergyPlus/ElectricPowerServiceManager.cc b/src/EnergyPlus/ElectricPowerServiceManager.cc index 698e83d6d44..46c5171b828 100644 --- a/src/EnergyPlus/ElectricPowerServiceManager.cc +++ b/src/EnergyPlus/ElectricPowerServiceManager.cc @@ -3843,8 +3843,6 @@ void ElectricStorage::simulateLiIonNmcBatteryModel(EnergyPlusData &state, Real64 const controlSOCMinFracLimit) { - // FIXME: Do availability schedule check. - // Copy the battery state from the end of last timestep battery_state battState = *ssc_lastBatteryState_; @@ -3937,6 +3935,11 @@ Real64 ElectricStorage::storedEnergy() const return storedEnergy_; } +Real64 ElectricStorage::stateOfChargeFraction() const +{ + return fractionSOC_; +} + bool ElectricStorage::determineCurrentForBatteryDischarge(EnergyPlusData &state, Real64 &curI0, Real64 &curT0, diff --git a/src/EnergyPlus/ElectricPowerServiceManager.hh b/src/EnergyPlus/ElectricPowerServiceManager.hh index cbd17d3af7a..fc7ae981c11 100644 --- a/src/EnergyPlus/ElectricPowerServiceManager.hh +++ b/src/EnergyPlus/ElectricPowerServiceManager.hh @@ -270,6 +270,8 @@ public: // methods Real64 storedEnergy() const; + Real64 stateOfChargeFraction() const; + bool determineCurrentForBatteryDischarge(EnergyPlusData &state, Real64 &curI0, Real64 &curT0, diff --git a/tst/EnergyPlus/unit/ElectricPowerServiceManager.unit.cc b/tst/EnergyPlus/unit/ElectricPowerServiceManager.unit.cc index c538e31bba4..2485a54109c 100644 --- a/tst/EnergyPlus/unit/ElectricPowerServiceManager.unit.cc +++ b/tst/EnergyPlus/unit/ElectricPowerServiceManager.unit.cc @@ -1079,4 +1079,82 @@ TEST_F(EnergyPlusFixture, Battery_LiIonNmc_Constructor) " ..... Last severe error=ElectricStorage constructor ElectricLoadCenter:Storage:LiIonNMCBattery=\"BATTERY2\", invalid entry." }); EXPECT_TRUE(compare_err_stream(error_string, true)); +} + +TEST_F(EnergyPlusFixture, Battery_LiIonNmc_Simulate) +{ + std::string const idf_objects = delimited_string({ + "ElectricLoadCenter:Storage:LiIonNMCBattery,", + " Battery1, !- Name", + " , !- Availability Schedule Name", + " , !- Zone Name", + " , !- Radiative Fraction", + " KandlerSmith, !- Lifetime Model", + " 139, !- Number of Cells in Series", + " 8, !- Number of Strings in Parallel", + " 0.95, !- Initial Fractional State of Charge", + " , !- DC to DC Charging Efficiency", + " 100, !- Battery Mass", + " 0.75, !- Battery Surface Area", + " , !- Battery Specific Heat Capacity", + " ; !- Heat Transfer Coefficient Between Battery and Ambient", + }); + ASSERT_TRUE(process_idf(idf_objects)); + + ElectricStorage battery{*state, "Battery1"}; + + DataHVACGlobals::TimeStepSys = 0.25; + state->dataEnvrn->OutDryBulbTemp = 23.0; + Real64 socMin = 0.1; + Real64 socMax = 0.95; + + Real64 powerCharge = 0.0; + Real64 powerDischarge = 3000.0; + bool charging = false; + bool discharging = true; + + battery.simulate(*state, powerCharge, powerDischarge, charging, discharging, socMax, socMin); + + ASSERT_NEAR(battery.storedPower(), 0.0, 0.1); + ASSERT_NEAR(battery.storedEnergy(), 0.0, 0.1); + ASSERT_NEAR(battery.drawnPower(), powerDischarge, 0.1); + ASSERT_NEAR(battery.drawnEnergy(), powerDischarge * 15 * 60, 0.1); + ASSERT_NEAR(battery.stateOfChargeFraction(), 0.9, 0.01); + + DataHVACGlobals::SysTimeElapsed += DataHVACGlobals::TimeStepSys; + powerDischarge = 0.0; + powerCharge = 5000.0; + charging = true; + discharging = false; + + battery.timeCheckAndUpdate(*state); + battery.simulate(*state, powerCharge, powerDischarge, charging, discharging, socMax, socMin); + + // Doesn't accept all the power, because the battery will be at capacity. + ASSERT_NEAR(battery.storedPower(), 3148.8, 0.1); + ASSERT_NEAR(battery.storedEnergy(), 2833963.1, 0.1); + ASSERT_NEAR(battery.drawnPower(), 0.0, 0.1); + ASSERT_NEAR(battery.drawnEnergy(), 0.0, 0.1); + ASSERT_NEAR(battery.stateOfChargeFraction(), socMax, 0.01); + + // Discharge the battery some more (redo of last timestep) + powerDischarge = 5000.0; + powerCharge = 0.0; + charging = false; + discharging = true; + battery.timeCheckAndUpdate(*state); + battery.simulate(*state, powerCharge, powerDischarge, charging, discharging, socMax, socMin); + ASSERT_NEAR(battery.stateOfChargeFraction(), 0.813, 0.01); + + // See that the battery state is reset at the beginning of a new environment (and also at the end of warmup) + DataHVACGlobals::SysTimeElapsed = 0.0; + battery.reinitAtBeginEnvironment(); + battery.timeCheckAndUpdate(*state); + powerDischarge = 0.0; + powerCharge = 0.0; + charging = false; + discharging = false; + battery.simulate(*state, powerCharge, powerDischarge, charging, discharging, socMax, socMin); + ASSERT_NEAR(battery.stateOfChargeFraction(), 0.95, 0.1); + } \ No newline at end of file From 874ab266527b47e1ecb7b33a81004d6df3620ce0 Mon Sep 17 00:00:00 2001 From: Noel Merket Date: Fri, 12 Feb 2021 15:22:46 -0700 Subject: [PATCH 55/76] checking values of Qexp and Qnom --- src/EnergyPlus/ElectricPowerServiceManager.cc | 10 ++++++++-- .../unit/ElectricPowerServiceManager.unit.cc | 12 ++++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/EnergyPlus/ElectricPowerServiceManager.cc b/src/EnergyPlus/ElectricPowerServiceManager.cc index 46c5171b828..fce72131ca0 100644 --- a/src/EnergyPlus/ElectricPowerServiceManager.cc +++ b/src/EnergyPlus/ElectricPowerServiceManager.cc @@ -3172,8 +3172,14 @@ ElectricStorage::ElectricStorage( // main constructor liIon_Qfull_ = DataIPShortCuts::lNumericFieldBlanks(14) ? 3.2 : DataIPShortCuts::rNumericArgs(14); liIon_Qexp_ = DataIPShortCuts::lNumericFieldBlanks(15) ? 0.8075 * liIon_Qfull_ : DataIPShortCuts::rNumericArgs(15) * liIon_Qfull_; liIon_Qnom_ = DataIPShortCuts::lNumericFieldBlanks(16) ? 0.976875 * liIon_Qfull_ : DataIPShortCuts::rNumericArgs(16) * liIon_Qfull_; - // FIXME: Validate Qexp and Qnom are less than Qfull, and Qnom > Qexp - // Qexp < Qnom < Qfull + if (liIon_Qexp_ >= liIon_Qnom_) { + ShowSevereError(state, routineName + DataIPShortCuts::cCurrentModuleObject + "=\"" + DataIPShortCuts::cAlphaArgs(1) + "\", invalid entry."); + ShowContinueError(state, DataIPShortCuts::cNumericFieldNames(16) + " must be greater than " + DataIPShortCuts::cNumericFieldNames(15) + "."); + for (int i = 15; i <= 16; ++i) { + ShowContinueError(state, format("{} = {:.3R}", DataIPShortCuts::cNumericFieldNames(i), DataIPShortCuts::rNumericArgs(i))); + } + errorsFound = true; + } liIon_C_rate_ = DataIPShortCuts::lNumericFieldBlanks(17) ? 1.0 : DataIPShortCuts::rNumericArgs(17); internalR_ = DataIPShortCuts::lNumericFieldBlanks(18) ? 0.09 : DataIPShortCuts::rNumericArgs(18); diff --git a/tst/EnergyPlus/unit/ElectricPowerServiceManager.unit.cc b/tst/EnergyPlus/unit/ElectricPowerServiceManager.unit.cc index 2485a54109c..c515bf34b7d 100644 --- a/tst/EnergyPlus/unit/ElectricPowerServiceManager.unit.cc +++ b/tst/EnergyPlus/unit/ElectricPowerServiceManager.unit.cc @@ -1058,7 +1058,11 @@ TEST_F(EnergyPlusFixture, Battery_LiIonNmc_Constructor) " , !- Heat Transfer Coefficient Between Battery and Ambient", " 1, !- Fully Charged Cell Voltage", " 2, !- Cell Voltage at End of Exponential Zone", - " 3; !- Cell Voltage at End of Nominal Zone", + " 3, !- Cell Voltage at End of Nominal Zone", + " , !- Default Nominal Cell Voltage", + " , !- Fully Charged Cell Capacity", + " 0.9, !- Fraction of Cell Capacity Removed at the End of Exponential Zone", + " 0.8; !- Fraction of Cell Capacity Removed at the End of Nominal Zone", }); ASSERT_TRUE(process_idf(idf_objects)); @@ -1073,9 +1077,13 @@ TEST_F(EnergyPlusFixture, Battery_LiIonNmc_Constructor) " ** ~~~ ** Fully Charged Cell Voltage = 1.000", " ** ~~~ ** Cell Voltage at End of Exponential Zone = 2.000", " ** ~~~ ** Cell Voltage at End of Nominal Zone = 3.000", + " ** Severe ** ElectricStorage constructor ElectricLoadCenter:Storage:LiIonNMCBattery=\"BATTERY2\", invalid entry.", + " ** ~~~ ** Fraction of Cell Capacity Removed at the End of Nominal Zone must be greater than Fraction of Cell Capacity Removed at the End of Exponential Zone.", + " ** ~~~ ** Fraction of Cell Capacity Removed at the End of Exponential Zone = 0.900", + " ** ~~~ ** Fraction of Cell Capacity Removed at the End of Nominal Zone = 0.800", " ** Fatal ** ElectricStorage constructor Preceding errors terminate program.", " ...Summary of Errors that led to program termination:", - " ..... Reference severe error count=1", + " ..... Reference severe error count=2", " ..... Last severe error=ElectricStorage constructor ElectricLoadCenter:Storage:LiIonNMCBattery=\"BATTERY2\", invalid entry." }); EXPECT_TRUE(compare_err_stream(error_string, true)); From 3689e4cfb3e32f05b43f510748d208205b70ef95 Mon Sep 17 00:00:00 2001 From: Noel Merket Date: Fri, 12 Feb 2021 16:12:48 -0700 Subject: [PATCH 56/76] resetting dt_sec in t_thermal on ChangeTimestep --- third_party/ssc/shared/lib_battery.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/third_party/ssc/shared/lib_battery.cpp b/third_party/ssc/shared/lib_battery.cpp index a42995458c9..587b0955e1c 100644 --- a/third_party/ssc/shared/lib_battery.cpp +++ b/third_party/ssc/shared/lib_battery.cpp @@ -579,6 +579,7 @@ void battery_t::ChangeTimestep(double dt_hr) { params->capacity->dt_hr = dt_hr; params->voltage->dt_hr = dt_hr; params->thermal->dt_hr = dt_hr; + thermal->dt_sec = dt_hr * 3600; params->lifetime->dt_hr = dt_hr; } From 1505b0010092f91d077adfcbf0abc24f61c6f0af Mon Sep 17 00:00:00 2001 From: Noel Merket Date: Fri, 12 Feb 2021 16:16:45 -0700 Subject: [PATCH 57/76] adding battery temperature output --- src/EnergyPlus/ElectricPowerServiceManager.cc | 12 +++++++++++- src/EnergyPlus/ElectricPowerServiceManager.hh | 3 +++ testfiles/ShopWithPVandLiIonBattery.idf | 2 ++ .../unit/ElectricPowerServiceManager.unit.cc | 9 +++++---- 4 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/EnergyPlus/ElectricPowerServiceManager.cc b/src/EnergyPlus/ElectricPowerServiceManager.cc index fce72131ca0..db567296a08 100644 --- a/src/EnergyPlus/ElectricPowerServiceManager.cc +++ b/src/EnergyPlus/ElectricPowerServiceManager.cc @@ -2952,7 +2952,7 @@ ElectricStorage::ElectricStorage( // main constructor qdotConvZone_(0.0), qdotRadZone_(0.0), timeElapsed_(0.0), thisTimeStepAvailable_(0.0), thisTimeStepBound_(0.0), lastTimeStepAvailable_(0.0), lastTimeStepBound_(0.0), lastTwoTimeStepAvailable_(0.0), lastTwoTimeStepBound_(0.0), count0_(0), electEnergyinStorage_(0.0), thermLossRate_(0.0), thermLossEnergy_(0.0), storageMode_(0), absoluteSOC_(0.0), fractionSOC_(0.0), batteryCurrent_(0.0), batteryVoltage_(0.0), - batteryDamage_(0.0) + batteryDamage_(0.0), batteryTemperature_(0.0) { std::string const routineName = "ElectricStorage constructor "; @@ -3304,6 +3304,9 @@ ElectricStorage::ElectricStorage( // main constructor SetupEMSInternalVariable(state, "Electrical Storage Battery Maximum Capacity", name_, "[Ah]", maxAhCapacity_); } } + if (storageModelMode_ == StorageModelType::liIonNmcBattery) { + SetupOutputVariable(state, "Electric Storage Battery Temperature", OutputProcessor::Unit::C, batteryTemperature_, "System", "Average", name_); + } if (zoneNum_ > 0) { switch (storageModelMode_) { @@ -3913,6 +3916,7 @@ void ElectricStorage::simulateLiIonNmcBatteryModel(EnergyPlusData &state, decrementedEnergyStored_ = - storedEnergy_; thermLossRate_ = battState2.thermal->heat_dissipated * 1000.0; // kW -> W thermLossEnergy_ = thermLossRate_ * DataHVACGlobals::TimeStepSys * DataGlobalConstants::SecInHour; + batteryTemperature_ = battState2.thermal->T_batt; // Zone Heat Gains if (zoneNum_ > 0) { // set values for zone heat gains @@ -3946,6 +3950,12 @@ Real64 ElectricStorage::stateOfChargeFraction() const return fractionSOC_; } +Real64 ElectricStorage::batteryTemperature() const +{ + assert(storageModelMode_ == StorageModelType::liIonNmcBattery); + return batteryTemperature_; +} + bool ElectricStorage::determineCurrentForBatteryDischarge(EnergyPlusData &state, Real64 &curI0, Real64 &curT0, diff --git a/src/EnergyPlus/ElectricPowerServiceManager.hh b/src/EnergyPlus/ElectricPowerServiceManager.hh index fc7ae981c11..4a0969fa36b 100644 --- a/src/EnergyPlus/ElectricPowerServiceManager.hh +++ b/src/EnergyPlus/ElectricPowerServiceManager.hh @@ -272,6 +272,8 @@ public: // methods Real64 stateOfChargeFraction() const; + Real64 batteryTemperature() const; + bool determineCurrentForBatteryDischarge(EnergyPlusData &state, Real64 &curI0, Real64 &curT0, @@ -428,6 +430,7 @@ private: // data Real64 batteryCurrent_; // [A] total current Real64 batteryVoltage_; // [V] total voltage Real64 batteryDamage_; // [ ] fractional battery damage + Real64 batteryTemperature_; // [C] battery temperature (only used in Li-ion batteries) }; // ElectricStorage diff --git a/testfiles/ShopWithPVandLiIonBattery.idf b/testfiles/ShopWithPVandLiIonBattery.idf index 06977e3dcf0..60f7adaa483 100644 --- a/testfiles/ShopWithPVandLiIonBattery.idf +++ b/testfiles/ShopWithPVandLiIonBattery.idf @@ -5225,6 +5225,8 @@ Output:Variable,*,Electric Storage Total Voltage,timestep; + Output:Variable,*,Electric Storage Battery Temperature,timestep; + Output:Variable,*,Electric Load Center Produced Electricity Rate,timestep; Output:Variable,*,Electric Load Center Produced Electricity Energy,timestep; diff --git a/tst/EnergyPlus/unit/ElectricPowerServiceManager.unit.cc b/tst/EnergyPlus/unit/ElectricPowerServiceManager.unit.cc index c515bf34b7d..a1a6ec66add 100644 --- a/tst/EnergyPlus/unit/ElectricPowerServiceManager.unit.cc +++ b/tst/EnergyPlus/unit/ElectricPowerServiceManager.unit.cc @@ -1127,7 +1127,8 @@ TEST_F(EnergyPlusFixture, Battery_LiIonNmc_Simulate) ASSERT_NEAR(battery.storedEnergy(), 0.0, 0.1); ASSERT_NEAR(battery.drawnPower(), powerDischarge, 0.1); ASSERT_NEAR(battery.drawnEnergy(), powerDischarge * 15 * 60, 0.1); - ASSERT_NEAR(battery.stateOfChargeFraction(), 0.9, 0.01); + ASSERT_NEAR(battery.stateOfChargeFraction(), 0.929, 0.01); + ASSERT_NEAR(battery.batteryTemperature(), 20.1, 0.1); DataHVACGlobals::SysTimeElapsed += DataHVACGlobals::TimeStepSys; powerDischarge = 0.0; @@ -1139,8 +1140,8 @@ TEST_F(EnergyPlusFixture, Battery_LiIonNmc_Simulate) battery.simulate(*state, powerCharge, powerDischarge, charging, discharging, socMax, socMin); // Doesn't accept all the power, because the battery will be at capacity. - ASSERT_NEAR(battery.storedPower(), 3148.8, 0.1); - ASSERT_NEAR(battery.storedEnergy(), 2833963.1, 0.1); + ASSERT_NEAR(battery.storedPower(), 1330.35, 0.1); + ASSERT_NEAR(battery.storedEnergy(), 1197315.3, 0.1); ASSERT_NEAR(battery.drawnPower(), 0.0, 0.1); ASSERT_NEAR(battery.drawnEnergy(), 0.0, 0.1); ASSERT_NEAR(battery.stateOfChargeFraction(), socMax, 0.01); @@ -1152,7 +1153,7 @@ TEST_F(EnergyPlusFixture, Battery_LiIonNmc_Simulate) discharging = true; battery.timeCheckAndUpdate(*state); battery.simulate(*state, powerCharge, powerDischarge, charging, discharging, socMax, socMin); - ASSERT_NEAR(battery.stateOfChargeFraction(), 0.813, 0.01); + ASSERT_NEAR(battery.stateOfChargeFraction(), 0.837, 0.01); // See that the battery state is reset at the beginning of a new environment (and also at the end of warmup) DataHVACGlobals::SysTimeElapsed = 0.0; From 67cda5a85397407ab2a889235ec2c0db35c56351 Mon Sep 17 00:00:00 2001 From: Noel Merket Date: Fri, 12 Feb 2021 16:57:16 -0700 Subject: [PATCH 58/76] start on ioref --- .../group-electric-load-center-generator.tex | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/doc/input-output-reference/src/overview/group-electric-load-center-generator.tex b/doc/input-output-reference/src/overview/group-electric-load-center-generator.tex index fcee3c9c5a3..3dd5974b0eb 100644 --- a/doc/input-output-reference/src/overview/group-electric-load-center-generator.tex +++ b/doc/input-output-reference/src/overview/group-electric-load-center-generator.tex @@ -1406,6 +1406,105 @@ \subsubsection{Outputs}\label{electricloadcenter-storagebattery-outputs} This output reports the fractional battery life used up at a point of time. For example, a value of 0.4 at the end of one year simulation means that the 40\% of the battery life is used up, so the battery needs to be replaced every two and a half years. +\subsection{ElectricLoadCenter:Storage:LiIonNMCBattery}\label{electricloadcenterstorage-liionbattery} + +This object usses the Li-ion NMC battery model from the System Advisor Model (SAM) software. + +\subsubsection{Inputs} + +\paragraph{Field: Name}\label{liion-name} + +This alpha field contains the identifying name for the battery. + +\paragraph{Field: Availability Schedule Name}\label{liion-avail-sched-name} + +This alpha field contains the schedule name (ref. Schedule objects) that describes when the battery is available. A schedule value greater than 0 (usually 1 is used) indicates that electrical energy can be stored or drawn from the battery. A value less than or equal to 0 (usually 0 is used) denotes that the battery is not available. If this field is blank, the schedule has values of 1 for all time periods. + +\paragraph{Field: Zone Name}\label{liion-zone-name} + +This field contains the name of the thermal zone where the battery is located. Entering a valid name of zone here will direct EnergyPlus to include the energy storage losses as heat gains to the named thermal zone. If the battery is not within a thermal zone, this field can be left blank and the thermal energy associated with storage losses is removed from the building model. + +\paragraph{Field: Radiative Fraction}\label{liion-rad-frac} + +This field contains the fraction of storage losses that enter the zone as long-wave thermal radiation. This numeric filed should have a value between 0.0 and 1.0. The balance of the losses is convective. This field is not used if the previous field for zone name is left blank. + +\paragraph{Field: Lifetime Model}\label{liion-lifetime-model} + +Which lifetime model to use for the battery. Available choices are: + +\begin{itemize} + \item None: The battery doesn't degrate over time + \item KandlerSmith: Use the lifetime model developed by Kandler Smith. +\end{itemize} + +\paragraph{Field: Number of Cells in Series}\label{liion-n-series} + +The number of cells in series. Increasing this number increases the voltage output of the battery. + +\paragraph{Field: Number of Strings in Parallel}\label{liion-n-parallel} + +The number of strings in parallel. + +\paragraph{Field: Initial Fractional State of Charge}\label{liion-init-soc} + +This field describes the initial state of charge in terms of the fraction of maximum capacity. + +\paragraph{Field: DC to DC Charging Efficiency}\label{liion-dc-dc-charg-eff} + +The charging loss coefficient. + +\paragraph{Field: Battery Mass}\label{liion-mass} + +Battery mass (kg) used in thermal calculation. + +\paragraph{Field: Battery Surface Area}\label{liion-surf-area} + +Battery surface area (m\textsuperscript{2}) used in thermal calculations. + +\paragraph{Field: Battery Specific Heat Capacity}\label{liion-cp} + +Specific heat of the battery (J/kg-K) used in the thermal calculation. + +\paragraph{Field: Heat Transfer Coefficient Between Battery and Ambient}\label{liion-h} + +Heat transfer coefficient (W/m\textsuperscript{2}-K)between battery and ambient. + +\paragraph{Field: Fully Charged Cell Voltage}\label{liion-vfull} + +This field is included for those who want to modify the battery chemistry. Most users should leave this field blank or omit it to use the defaults, which are typical of Lithium-ion batteries. + +\paragraph{Field: Cell Voltage at End of Exponential Zone}\label{liion-vexp} + +This field is included for those who want to modify the battery chemistry. Most users should leave this field blank or omit it to use the defaults, which are typical of Lithium-ion batteries. + +\paragraph{Field: Cell Voltage at End of Nominal Zone}\label{liion-vnom} + +This field is included for those who want to modify the battery chemistry. Most users should leave this field blank or omit it to use the defaults, which are typical of Lithium-ion batteries. + +\paragraph{Field: Default Nominal Cell Voltage}\label{liion-vnom-default} + +This field is included for those who want to modify the battery chemistry. Most users should leave this field blank or omit it to use the defaults, which are typical of Lithium-ion batteries. + +\paragraph{Field: Fully Charged Cell Capacity}\label{liion-qfull} + +This field is included for those who want to modify the battery chemistry. Most users should leave this field blank or omit it to use the defaults, which are typical of Lithium-ion batteries. + +\paragraph{Field: Fraction of Cell Capacity Removed at the End of Exponential Zone}\label{liion-qexp} + +This field is included for those who want to modify the battery chemistry. Most users should leave this field blank or omit it to use the defaults, which are typical of Lithium-ion batteries. + +\paragraph{Field: Fraction of Cell Capacity Removed at the End of Nominal Zone}\label{liion-qnom} + +This field is included for those who want to modify the battery chemistry. Most users should leave this field blank or omit it to use the defaults, which are typical of Lithium-ion batteries. + +\paragraph{Field: Charge Rate at Which Voltage vs Capacity Curve Was Generated}\label{liion-crate} + +This field is included for those who want to modify the battery chemistry. Most users should leave this field blank or omit it to use the defaults, which are typical of Lithium-ion batteries. + +\paragraph{Field: Battery Cell Internal Electrical Resistance}\label{liion-internal-r} + +This field is included for those who want to modify the battery chemistry. Most users should leave this field blank or omit it to use the defaults, which are typical of Lithium-ion batteries. + \subsection{Generator:InternalCombustionEngine}\label{generatorinternalcombustionengine} The Internal Combustion (IC) Engine generator uses a modified Otto cycle. This generator model uses the electrical load and rated engine generator size to compute part-load ratios (PLR). Fuel energy input and recoverable jacket and lube oil heat are then computed. Finally, the recoverable exhaust heat is calculated. From 9808d5311cc469ace5c6daee5bc1821c661342ae Mon Sep 17 00:00:00 2001 From: Noel Merket Date: Fri, 12 Feb 2021 17:09:02 -0700 Subject: [PATCH 59/76] changing ShopWithPVandStorage.idf to it's previous state --- testfiles/ShopWithPVandStorage.idf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testfiles/ShopWithPVandStorage.idf b/testfiles/ShopWithPVandStorage.idf index a77edd4fdc4..0f9e33a46b6 100644 --- a/testfiles/ShopWithPVandStorage.idf +++ b/testfiles/ShopWithPVandStorage.idf @@ -72,7 +72,7 @@ 1, !- Begin Day of Month , !- Begin Year 7, !- End Month - 2, !- End Day of Month + 1, !- End Day of Month , !- End Year Sunday, !- Day of Week for Start Day No, !- Use Weather File Holidays and Special Days From 2058dcef15510a634cc477fabab4912c1fd3093d Mon Sep 17 00:00:00 2001 From: Noel Merket Date: Tue, 16 Feb 2021 13:36:41 -0700 Subject: [PATCH 60/76] filling out more of the IORef --- .../group-electric-load-center-generator.tex | 106 +++++++++++++++++- 1 file changed, 105 insertions(+), 1 deletion(-) diff --git a/doc/input-output-reference/src/overview/group-electric-load-center-generator.tex b/doc/input-output-reference/src/overview/group-electric-load-center-generator.tex index 3dd5974b0eb..093938ccfa1 100644 --- a/doc/input-output-reference/src/overview/group-electric-load-center-generator.tex +++ b/doc/input-output-reference/src/overview/group-electric-load-center-generator.tex @@ -1434,7 +1434,7 @@ \subsubsection{Inputs} \begin{itemize} \item None: The battery doesn't degrate over time - \item KandlerSmith: Use the lifetime model developed by Kandler Smith. + \item KandlerSmith: Use the lifetime model developed by Kandler Smith. Details at \url{https://ieeexplore.ieee.org/abstract/document/7963578} \end{itemize} \paragraph{Field: Number of Cells in Series}\label{liion-n-series} @@ -1505,6 +1505,110 @@ \subsubsection{Inputs} This field is included for those who want to modify the battery chemistry. Most users should leave this field blank or omit it to use the defaults, which are typical of Lithium-ion batteries. +An example input of the ElectricLoadCenter:Storage:LiIonNMCBattery is: + +\begin{lstlisting} + + ElectricLoadCenter:Storage:LiIonNMCBattery, + LiIonBattery, !- Name + ALWAYS_ON, !- Availability Schedule Name + , !- Zone Name + 0, !- Radiative Fraction + KandlerSmith, !- Lifetime Model + 139, !- Number of Cells in Series + 25, !- Number of Strings in Parallel + 0.7, !- Initial Fractional State of Charge + , !- DC to DC Charging Efficiency + 342, !- Battery Mass + 4.26, !- Battery Surface Area + , !- Battery Specific Heat Capacity + ; !- Heat Transfer Coefficient Between Battery and Ambient + +\end{lstlisting} + +\subsubsection{Outputs}\label{electricloadcenter-storageliionnmcbatttery-outputs} + +\begin{itemize} + \item + HVAC,Average, Electric Storage Operating Mode Index {[]} + \item + HVAC,Average,Electric Storage Charge State{[}Ah{]} + \item + HVAC,Average, Electric Storage Charge Fraction {[]} + \item + HVAC,Average,Electric Storage Charge Power{[}W{]} + \item + HVAC,Sum,Electric Storage Charge Energy {[}J{]} + \item + HVAC,Average,Electric Storage Discharge Power{[}W{]} + \item + HVAC,Sum,Electric Storage Discharge Energy {[}J{]} + \item + HVAC,Average,Electric Storage Total Current{[}A{]} + \item + HVAC,Average, Electric Storage Total Voltage {[}V{]} + \item + HVAC,Average,Electric Storage Thermal Loss Rate {[}W{]} + \item + HVAC,Average,Electric Storage Degradation Fraction {[]} + \item + HVAC,Sum,Electric Storage Production Decrement Energy {[}J{]} + \item + HVAC,Sum,Electric Storage Thermal Loss Energy {[}J{]} + \item + HVAC,Average,Electric Storage Battery Temperature {[}C{]} +\end{itemize} + +\paragraph{Electric Storage Operating Mode Index {[]}}\label{liion-operating-mode-index} + +This output reports the battery mode of operation: 0 for idle; 1 for discharging; 2 for charging. It is expected that more operation modes would be added when a smart and active power dispatch controller is used in future. + +\paragraph{Electric Storage Charge State {[}Ah{]}}\label{liion-charge-state-ah} + +The state of charge is expressed as the amount of charge stored in the battery at a point of time. It has the same unit as the maximum capacity. This value is given for an individual battery module + +\paragraph{Electric Storage Charge Fraction {[]}}\label{liion-charge-fraction} + +This output is the ratio between the electrical storage state of charge and the maximum capacity. + +\paragraph{Electric Storage Charge Power {[}W{]}}\label{liion-charge-power-w-1} + +\paragraph{Electric Storage Charge Energy {[}J{]}}\label{liion-charge-energy-j-1} + +These outputs are total electricity power or energy fed into the battery. This is the rate of amount of charging. + +\paragraph{Electric Storage Production Decrement Energy {[}J{]}}\label{liion-production-decrement-energy-j-1} + +This output is the total electricity energy decremented from electricity production because it has fed into the battery. This output has the opposite sign of Electric Storage Charge Energy but is otherwise similar. This decrement output variable is also a meter associated with the resource type ElectricityProduced that reduces the metered electricity production to account for power that went into storage after production. + +\paragraph{Electric Storage Discharge Power {[}W{]}}\label{liion-discharge-power-w-1} + +\paragraph{Electric Storage Discharge Energy {[}J{]}}\label{liion-discharge-energy-j-1} + +These outputs are total electricity power or energy drawn from the battery. This is the rate or amount of discharging. The energy from storage output variable is also a meter associated with the resource type ElectricityProduced that increases the metered electricity production to account for power that has come back out of storage. + +\paragraph{Electric Storage Total Current {[}A{]}}\label{liion-total-current-a} + +This output is the current to or from the battery bank depending on whether the battery is in the state of charging or discharging. The value is positive for discharging and negative for charging. + +\paragraph{Electric Storage Total Voltage {[}V{]}}\label{liion-total-voltage-v} + +This output is the total terminal voltage of the battery bank. + +\paragraph{Electric Storage Thermal Loss Rate {[}W{]}}\label{liion-thermal-loss-rate-w-1} + +\paragraph{Electric Storage Thermal Loss Energy {[}J{]}}\label{liion-thermal-loss-energy-j-1} + +These outputs are the thermal power or energy losses from both charging and drawing electrical power in or out of the storage device. These losses are due to the battery internal resistance in charging and discharging. + +\paragraph{Electric Storage Degradation Fraction {[]}}\label{liion-degradation-fraction} + +This output reports the fractional battery life used up at a point of time. For example, a value of 0.4 at the end of one year simulation means that the 40\% of the battery life is used up, so the battery needs to be replaced every two and a half years. + +\paragraph{HVAC,Average,Electric Storage Battery Temperature {[}C{]}}\label{liion-battery-temperature} + +The internal temperature of the battery. + \subsection{Generator:InternalCombustionEngine}\label{generatorinternalcombustionengine} The Internal Combustion (IC) Engine generator uses a modified Otto cycle. This generator model uses the electrical load and rated engine generator size to compute part-load ratios (PLR). Fuel energy input and recoverable jacket and lube oil heat are then computed. Finally, the recoverable exhaust heat is calculated. From 8123282aa830164297a440dd4a59c93350788e05 Mon Sep 17 00:00:00 2001 From: Noel Merket Date: Tue, 16 Feb 2021 16:19:06 -0700 Subject: [PATCH 61/76] adding the internal gain from the li-ion battery to the correct places --- src/EnergyPlus/DisplacementVentMgr.cc | 1 + src/EnergyPlus/InternalHeatGains.cc | 3 ++- src/EnergyPlus/UFADManager.cc | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/EnergyPlus/DisplacementVentMgr.cc b/src/EnergyPlus/DisplacementVentMgr.cc index f5ad91698bd..084ab70a2ce 100644 --- a/src/EnergyPlus/DisplacementVentMgr.cc +++ b/src/EnergyPlus/DisplacementVentMgr.cc @@ -648,6 +648,7 @@ namespace DisplacementVentMgr { IntGainTypeOf_ElectricLoadCenterInverterFunctionOfPower, IntGainTypeOf_ElectricLoadCenterInverterLookUpTable, IntGainTypeOf_ElectricLoadCenterStorageBattery, + IntGainTypeOf_ElectricLoadCenterStorageLiIonNmcBattery, IntGainTypeOf_ElectricLoadCenterStorageSimple, IntGainTypeOf_PipeIndoor, IntGainTypeOf_RefrigerationCase, diff --git a/src/EnergyPlus/InternalHeatGains.cc b/src/EnergyPlus/InternalHeatGains.cc index 479b6010b35..34b90a1eb58 100644 --- a/src/EnergyPlus/InternalHeatGains.cc +++ b/src/EnergyPlus/InternalHeatGains.cc @@ -7082,7 +7082,7 @@ namespace InternalHeatGains { IntGainTypeOf_SecCoolingDXCoilTwoSpeed, IntGainTypeOf_SecCoolingDXCoilMultiSpeed, IntGainTypeOf_SecHeatingDXCoilMultiSpeed}); - static Array1D_int IntGainTypesPowerGen(9, + static Array1D_int IntGainTypesPowerGen(10, {IntGainTypeOf_GeneratorFuelCell, IntGainTypeOf_GeneratorMicroCHP, IntGainTypeOf_ElectricLoadCenterTransformer, @@ -7090,6 +7090,7 @@ namespace InternalHeatGains { IntGainTypeOf_ElectricLoadCenterInverterFunctionOfPower, IntGainTypeOf_ElectricLoadCenterInverterLookUpTable, IntGainTypeOf_ElectricLoadCenterStorageBattery, + IntGainTypeOf_ElectricLoadCenterStorageLiIonNmcBattery, IntGainTypeOf_ElectricLoadCenterStorageSimple, IntGainTypeOf_ElectricLoadCenterConverter}); diff --git a/src/EnergyPlus/UFADManager.cc b/src/EnergyPlus/UFADManager.cc index d6b2cdc156a..3e2174997f9 100644 --- a/src/EnergyPlus/UFADManager.cc +++ b/src/EnergyPlus/UFADManager.cc @@ -992,6 +992,7 @@ namespace UFADManager { IntGainTypeOf_ElectricLoadCenterInverterFunctionOfPower, IntGainTypeOf_ElectricLoadCenterInverterLookUpTable, IntGainTypeOf_ElectricLoadCenterStorageBattery, + IntGainTypeOf_ElectricLoadCenterStorageLiIonNmcBattery, IntGainTypeOf_ElectricLoadCenterStorageSimple, IntGainTypeOf_PipeIndoor, IntGainTypeOf_RefrigerationCase, @@ -1466,6 +1467,7 @@ namespace UFADManager { IntGainTypeOf_ElectricLoadCenterInverterFunctionOfPower, IntGainTypeOf_ElectricLoadCenterInverterLookUpTable, IntGainTypeOf_ElectricLoadCenterStorageBattery, + IntGainTypeOf_ElectricLoadCenterStorageLiIonNmcBattery, IntGainTypeOf_ElectricLoadCenterStorageSimple, IntGainTypeOf_PipeIndoor, IntGainTypeOf_RefrigerationCase, From e4c2034ab4ff698d3d957e54248550208c261e06 Mon Sep 17 00:00:00 2001 From: Noel Merket Date: Tue, 16 Feb 2021 16:30:02 -0700 Subject: [PATCH 62/76] ioref edits --- .../src/overview/group-electric-load-center-generator.tex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/input-output-reference/src/overview/group-electric-load-center-generator.tex b/doc/input-output-reference/src/overview/group-electric-load-center-generator.tex index 093938ccfa1..5ea35ce232f 100644 --- a/doc/input-output-reference/src/overview/group-electric-load-center-generator.tex +++ b/doc/input-output-reference/src/overview/group-electric-load-center-generator.tex @@ -1433,7 +1433,7 @@ \subsubsection{Inputs} Which lifetime model to use for the battery. Available choices are: \begin{itemize} - \item None: The battery doesn't degrate over time + \item None: The battery doesn't degrade over time \item KandlerSmith: Use the lifetime model developed by Kandler Smith. Details at \url{https://ieeexplore.ieee.org/abstract/document/7963578} \end{itemize} @@ -1603,7 +1603,7 @@ \subsubsection{Outputs}\label{electricloadcenter-storageliionnmcbatttery-outputs \paragraph{Electric Storage Degradation Fraction {[]}}\label{liion-degradation-fraction} -This output reports the fractional battery life used up at a point of time. For example, a value of 0.4 at the end of one year simulation means that the 40\% of the battery life is used up, so the battery needs to be replaced every two and a half years. +This output reports the fractional battery life used up at a point of time. For example, a value of 0.4 at the end of one year simulation means that 40\% of the battery life is used up. \paragraph{HVAC,Average,Electric Storage Battery Temperature {[}C{]}}\label{liion-battery-temperature} From 1a6043f3620a26e28a005c602d83ae147fafc66d Mon Sep 17 00:00:00 2001 From: Noel Merket Date: Wed, 17 Feb 2021 16:16:22 +0000 Subject: [PATCH 63/76] adding simulationLiIonNmcBatteryModel to custom check allow list --- scripts/dev/find_byref_bool_override.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/dev/find_byref_bool_override.py b/scripts/dev/find_byref_bool_override.py index b3b4b2e18ca..98eebf43f0d 100755 --- a/scripts/dev/find_byref_bool_override.py +++ b/scripts/dev/find_byref_bool_override.py @@ -191,6 +191,10 @@ "simulateSimpleBucketModel": [ "charging", "discharging" + ], + "simulateLiIonNmcBatteryModel", [ + "charging", + "discharging" ] }, "EMSManager.cc": { From e8e313327c24526c9a2ea62f732ef1b4957069c2 Mon Sep 17 00:00:00 2001 From: Noel Merket Date: Wed, 17 Feb 2021 21:25:18 +0000 Subject: [PATCH 64/76] fixing array errors in internal gains --- idd/Energy+.idd.in | 3 +++ src/EnergyPlus/DataHeatBalance.cc | 8 +++++--- src/EnergyPlus/DisplacementVentMgr.cc | 4 ++-- src/EnergyPlus/InternalHeatGains.cc | 2 +- src/EnergyPlus/UFADManager.cc | 4 ++-- 5 files changed, 13 insertions(+), 8 deletions(-) diff --git a/idd/Energy+.idd.in b/idd/Energy+.idd.in index a1482416d9f..aa79f951aec 100644 --- a/idd/Energy+.idd.in +++ b/idd/Energy+.idd.in @@ -20457,6 +20457,7 @@ RoomAir:Node:AirflowNetwork:InternalGains, \key ElectricLoadCenter:Inverter:Simple \key ElectricLoadCenter:Inverter:FunctionOfPower \key ElectricLoadCenter:Inverter:LookUpTable + \key ElectricLoadCenter:Storage:LiIonNMCBattery \key ElectricLoadCenter:Storage:Battery \key ElectricLoadCenter:Storage:Simple \key ElectricLoadCenter:Storage:Converter @@ -20511,6 +20512,7 @@ RoomAir:Node:AirflowNetwork:InternalGains, \key ElectricLoadCenter:Inverter:Simple \key ElectricLoadCenter:Inverter:FunctionOfPower \key ElectricLoadCenter:Inverter:LookUpTable + \key ElectricLoadCenter:Storage:LiIonNMCBattery \key ElectricLoadCenter:Storage:Battery \key ElectricLoadCenter:Storage:Simple \key ElectricLoadCenter:Storage:Converter @@ -20564,6 +20566,7 @@ RoomAir:Node:AirflowNetwork:InternalGains, \key ElectricLoadCenter:Inverter:Simple \key ElectricLoadCenter:Inverter:FunctionOfPower \key ElectricLoadCenter:Inverter:LookUpTable + \key ElectricLoadCenter:Storage:LiIonNMCBattery \key ElectricLoadCenter:Storage:Battery \key ElectricLoadCenter:Storage:Simple \key ElectricLoadCenter:Storage:Converter diff --git a/src/EnergyPlus/DataHeatBalance.cc b/src/EnergyPlus/DataHeatBalance.cc index b77401db467..e94394de34a 100644 --- a/src/EnergyPlus/DataHeatBalance.cc +++ b/src/EnergyPlus/DataHeatBalance.cc @@ -256,7 +256,7 @@ namespace DataHeatBalance { int const MixingSourceZonesOnly(1); int const AllZones(2); - int const NumZoneIntGainDeviceTypes(53); + int const NumZoneIntGainDeviceTypes(54); Array1D_string const ZoneIntGainDeviceTypes(NumZoneIntGainDeviceTypes, {"PEOPLE", "LIGHTS", @@ -279,6 +279,7 @@ namespace DataHeatBalance { "ELECTRICLOADCENTER:INVERTER:SIMPLE", "ELECTRICLOADCENTER:INVERTER:FUNCTIONOFPOWER", "ELECTRICLOADCENTER:INVERTER:LOOKUPTABLE", + "ELECTRICLOADCENTER:STORAGE:LIIONNMCBATTERY", "ELECTRICLOADCENTER:STORAGE:BATTERY", "ELECTRICLOADCENTER:STORAGE:SIMPLE", "PIPE:INDOOR", @@ -313,7 +314,7 @@ namespace DataHeatBalance { "FAN:SYSTEMMODEL"}); // 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 | 13 | 14 | 15 | 16 // | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | // 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 - // | 48 | 49 | 50 | 51 | 52 | 53 + // | 48 | 49 | 50 | 51 | 52 | 53 | 54 Array1D_string const ccZoneIntGainDeviceTypes(NumZoneIntGainDeviceTypes, {"People", @@ -337,6 +338,7 @@ namespace DataHeatBalance { "ElectricLoadCenter:Inverter:Simple", "ElectricLoadCenter:Inverter:FunctionOfPower", "ElectricLoadCenter:Inverter:LookUpTable", + "ElectricLoadCenter:Storage:LiIonNMCBattery", "ElectricLoadCenter:Storage:Battery", "ElectricLoadCenter:Storage:Simple", "Pipe:Indoor", @@ -371,7 +373,7 @@ namespace DataHeatBalance { "Fan:SystemModel"}); // 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 | 13 | 14 | 15 | // 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | // 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | - // 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 + // 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 int const IntGainTypeOf_People(1); int const IntGainTypeOf_Lights(2); diff --git a/src/EnergyPlus/DisplacementVentMgr.cc b/src/EnergyPlus/DisplacementVentMgr.cc index 084ab70a2ce..d6e0e81a9bf 100644 --- a/src/EnergyPlus/DisplacementVentMgr.cc +++ b/src/EnergyPlus/DisplacementVentMgr.cc @@ -627,7 +627,7 @@ namespace DisplacementVentMgr { int FlagApertures; static Real64 TempDepCoef(0.0); // Formerly CoefSumha, coef in zone temp equation with dimensions of h*A static Real64 TempIndCoef(0.0); // Formerly CoefSumhat, coef in zone temp equation with dimensions of h*A(T1 - static Array1D_int IntGainTypesOccupied(29, + static Array1D_int IntGainTypesOccupied(30, {IntGainTypeOf_People, IntGainTypeOf_WaterHeaterMixed, IntGainTypeOf_WaterHeaterStratified, @@ -647,8 +647,8 @@ namespace DisplacementVentMgr { IntGainTypeOf_ElectricLoadCenterInverterSimple, IntGainTypeOf_ElectricLoadCenterInverterFunctionOfPower, IntGainTypeOf_ElectricLoadCenterInverterLookUpTable, - IntGainTypeOf_ElectricLoadCenterStorageBattery, IntGainTypeOf_ElectricLoadCenterStorageLiIonNmcBattery, + IntGainTypeOf_ElectricLoadCenterStorageBattery, IntGainTypeOf_ElectricLoadCenterStorageSimple, IntGainTypeOf_PipeIndoor, IntGainTypeOf_RefrigerationCase, diff --git a/src/EnergyPlus/InternalHeatGains.cc b/src/EnergyPlus/InternalHeatGains.cc index 34b90a1eb58..62ba0096605 100644 --- a/src/EnergyPlus/InternalHeatGains.cc +++ b/src/EnergyPlus/InternalHeatGains.cc @@ -7089,8 +7089,8 @@ namespace InternalHeatGains { IntGainTypeOf_ElectricLoadCenterInverterSimple, IntGainTypeOf_ElectricLoadCenterInverterFunctionOfPower, IntGainTypeOf_ElectricLoadCenterInverterLookUpTable, - IntGainTypeOf_ElectricLoadCenterStorageBattery, IntGainTypeOf_ElectricLoadCenterStorageLiIonNmcBattery, + IntGainTypeOf_ElectricLoadCenterStorageBattery, IntGainTypeOf_ElectricLoadCenterStorageSimple, IntGainTypeOf_ElectricLoadCenterConverter}); diff --git a/src/EnergyPlus/UFADManager.cc b/src/EnergyPlus/UFADManager.cc index 3e2174997f9..98e06e0f001 100644 --- a/src/EnergyPlus/UFADManager.cc +++ b/src/EnergyPlus/UFADManager.cc @@ -971,7 +971,7 @@ namespace UFADManager { Real64 HeightOccupiedSubzoneAve; // Height of center of occupied air subzone Real64 ZoneMult; // total zone multiplier int ZoneNodeNum; // node number of the HVAC zone node - Array1D_int IntGainTypesOccupied(29, + Array1D_int IntGainTypesOccupied(30, {IntGainTypeOf_People, IntGainTypeOf_WaterHeaterMixed, IntGainTypeOf_WaterHeaterStratified, @@ -991,8 +991,8 @@ namespace UFADManager { IntGainTypeOf_ElectricLoadCenterInverterSimple, IntGainTypeOf_ElectricLoadCenterInverterFunctionOfPower, IntGainTypeOf_ElectricLoadCenterInverterLookUpTable, - IntGainTypeOf_ElectricLoadCenterStorageBattery, IntGainTypeOf_ElectricLoadCenterStorageLiIonNmcBattery, + IntGainTypeOf_ElectricLoadCenterStorageBattery, IntGainTypeOf_ElectricLoadCenterStorageSimple, IntGainTypeOf_PipeIndoor, IntGainTypeOf_RefrigerationCase, From 99224e3e97cc4538183dc94067863ed7a0e7ddb0 Mon Sep 17 00:00:00 2001 From: Noel Merket Date: Fri, 19 Feb 2021 16:55:29 +0000 Subject: [PATCH 65/76] removing semicolon that was causing trouble --- third_party/ssc/shared/lib_util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third_party/ssc/shared/lib_util.h b/third_party/ssc/shared/lib_util.h index 9955b3fdc3b..d31c59294a1 100644 --- a/third_party/ssc/shared/lib_util.h +++ b/third_party/ssc/shared/lib_util.h @@ -816,7 +816,7 @@ namespace util bool translate_schedule(int tod[8760], const matrix_t &wkday, const matrix_t &wkend, int min_val, int max_val); std::vector frequency_table(double* values, size_t n_vals, double bin_width); -}; +} #endif From 318e17ff5ba215c0cf168cf3c3b7f87f24a0f096 Mon Sep 17 00:00:00 2001 From: Noel Merket Date: Fri, 19 Feb 2021 18:25:35 +0000 Subject: [PATCH 66/76] fixing custom check script, my bad --- scripts/dev/find_byref_bool_override.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/dev/find_byref_bool_override.py b/scripts/dev/find_byref_bool_override.py index 810b76e314e..1b637892c88 100755 --- a/scripts/dev/find_byref_bool_override.py +++ b/scripts/dev/find_byref_bool_override.py @@ -192,7 +192,7 @@ "charging", "discharging" ], - "simulateLiIonNmcBatteryModel", [ + "simulateLiIonNmcBatteryModel": [ "charging", "discharging" ] From 30b9694aa411ad8da5bf51b9a52792752600c564 Mon Sep 17 00:00:00 2001 From: Edwin Lee Date: Fri, 19 Feb 2021 14:25:53 -0600 Subject: [PATCH 67/76] Fix int gain count variable --- src/EnergyPlus/DataHeatBalance.cc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/EnergyPlus/DataHeatBalance.cc b/src/EnergyPlus/DataHeatBalance.cc index 65f50137669..06f1b368bab 100644 --- a/src/EnergyPlus/DataHeatBalance.cc +++ b/src/EnergyPlus/DataHeatBalance.cc @@ -257,15 +257,15 @@ namespace DataHeatBalance { int const MixingSourceZonesOnly(1); int const AllZones(2); - int const NumZoneIntGainDeviceTypes(54); // Parameter for zone air flow mass balancing method int const AdjustMixingOnly(1); int const AdjustReturnOnly(2); int const AdjustMixingThenReturn(3); int const AdjustReturnThenMixing(4); int const NoAdjustReturnAndMixing(0); + // | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | - int const NumZoneIntGainDeviceTypes(53); + int const NumZoneIntGainDeviceTypes(54); Array1D_string const ZoneIntGainDeviceTypes(NumZoneIntGainDeviceTypes, {"PEOPLE", "LIGHTS", @@ -321,8 +321,7 @@ namespace DataHeatBalance { "COIL:HEATING:DX:MULTISPEED", "ELECTRICLOADCENTER:STORAGE:CONVERTER", "FAN:SYSTEMMODEL"}); // 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 | 13 | 14 | 15 | 16 - // | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | - // 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 + // 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 // | 48 | 49 | 50 | 51 | 52 | 53 | 54 Array1D_string const ccZoneIntGainDeviceTypes(NumZoneIntGainDeviceTypes, From f3c3b6b6060d6ad64fa2f735c39499a51419a6dc Mon Sep 17 00:00:00 2001 From: Edwin Lee Date: Fri, 19 Feb 2021 14:53:16 -0600 Subject: [PATCH 68/76] Move constructor body into header to fix linker problem...for now --- third_party/ssc/shared/lib_battery.cpp | 12 ++++++------ third_party/ssc/shared/lib_battery.h | 7 ++++++- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/third_party/ssc/shared/lib_battery.cpp b/third_party/ssc/shared/lib_battery.cpp index 587b0955e1c..34d19758b7f 100644 --- a/third_party/ssc/shared/lib_battery.cpp +++ b/third_party/ssc/shared/lib_battery.cpp @@ -214,12 +214,12 @@ losses_t::losses_t(const std::vector& monthly_charge, const std::vector< initialize(); } -losses_t::losses_t(const std::vector& schedule_loss) { - params = std::make_shared(); - params->loss_choice = losses_params::SCHEDULE; - params->schedule_loss = schedule_loss; - initialize(); -} +//losses_t::losses_t(const std::vector& schedule_loss) { +// params = std::make_shared(); +// params->loss_choice = losses_params::SCHEDULE; +// params->schedule_loss = schedule_loss; +// initialize(); +//} losses_t::losses_t(std::shared_ptr p) { params = std::move(p); diff --git a/third_party/ssc/shared/lib_battery.h b/third_party/ssc/shared/lib_battery.h index f668eb5a375..6505756136b 100644 --- a/third_party/ssc/shared/lib_battery.h +++ b/third_party/ssc/shared/lib_battery.h @@ -182,7 +182,12 @@ class losses_t { * * \param[in] schedule_loss vector (size 0 for constant or per timestep) containing battery system losses */ - explicit losses_t(const std::vector& schedule_loss = std::vector(1, 0)); + explicit losses_t(const std::vector& schedule_loss = std::vector(1, 0)) { + params = std::make_shared(); + params->loss_choice = losses_params::SCHEDULE; + params->schedule_loss = schedule_loss; + initialize(); + } explicit losses_t(std::shared_ptr p); From c44e23079c7b1f27944e2206959cc1aa8e346381 Mon Sep 17 00:00:00 2001 From: Noel Merket Date: Mon, 22 Feb 2021 15:34:21 +0000 Subject: [PATCH 69/76] Revert "Move constructor body into header to fix linker problem...for now" This reverts commit f3c3b6b6060d6ad64fa2f735c39499a51419a6dc. --- third_party/ssc/shared/lib_battery.cpp | 12 ++++++------ third_party/ssc/shared/lib_battery.h | 7 +------ 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/third_party/ssc/shared/lib_battery.cpp b/third_party/ssc/shared/lib_battery.cpp index 34d19758b7f..587b0955e1c 100644 --- a/third_party/ssc/shared/lib_battery.cpp +++ b/third_party/ssc/shared/lib_battery.cpp @@ -214,12 +214,12 @@ losses_t::losses_t(const std::vector& monthly_charge, const std::vector< initialize(); } -//losses_t::losses_t(const std::vector& schedule_loss) { -// params = std::make_shared(); -// params->loss_choice = losses_params::SCHEDULE; -// params->schedule_loss = schedule_loss; -// initialize(); -//} +losses_t::losses_t(const std::vector& schedule_loss) { + params = std::make_shared(); + params->loss_choice = losses_params::SCHEDULE; + params->schedule_loss = schedule_loss; + initialize(); +} losses_t::losses_t(std::shared_ptr p) { params = std::move(p); diff --git a/third_party/ssc/shared/lib_battery.h b/third_party/ssc/shared/lib_battery.h index 6505756136b..f668eb5a375 100644 --- a/third_party/ssc/shared/lib_battery.h +++ b/third_party/ssc/shared/lib_battery.h @@ -182,12 +182,7 @@ class losses_t { * * \param[in] schedule_loss vector (size 0 for constant or per timestep) containing battery system losses */ - explicit losses_t(const std::vector& schedule_loss = std::vector(1, 0)) { - params = std::make_shared(); - params->loss_choice = losses_params::SCHEDULE; - params->schedule_loss = schedule_loss; - initialize(); - } + explicit losses_t(const std::vector& schedule_loss = std::vector(1, 0)); explicit losses_t(std::shared_ptr p); From 8fd9ecb103076c746bc4fec48ae555a567c96907 Mon Sep 17 00:00:00 2001 From: Noel Merket Date: Mon, 22 Feb 2021 17:36:49 +0000 Subject: [PATCH 70/76] constructing losses_t in lib_battery.cpp --- src/EnergyPlus/ElectricPowerServiceManager.cc | 3 +-- third_party/ssc/shared/lib_battery.cpp | 6 +++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/EnergyPlus/ElectricPowerServiceManager.cc b/src/EnergyPlus/ElectricPowerServiceManager.cc index db567296a08..d40de1331cb 100644 --- a/src/EnergyPlus/ElectricPowerServiceManager.cc +++ b/src/EnergyPlus/ElectricPowerServiceManager.cc @@ -3199,7 +3199,6 @@ ElectricStorage::ElectricStorage( // main constructor util::matrix_t battLifetimeMatrix(6, 3, &tblVals); battLifetime = new lifetime_calendar_cycle_t(battLifetimeMatrix, DataHVACGlobals::TimeStepSys); } - std::vector batt_losses{0}; // using double because SSC expects a double // Create the SSC battery object ssc_battery_ = std::unique_ptr( @@ -3237,7 +3236,7 @@ ElectricStorage::ElectricStorage( // main constructor liIon_heatTransferCoef_, 20.0 // Picking a temperature for now, will reset before each run. ), - new losses_t(batt_losses) + nullptr ) ); ssc_lastBatteryState_ = std::unique_ptr(new battery_state(ssc_battery_->get_state())); diff --git a/third_party/ssc/shared/lib_battery.cpp b/third_party/ssc/shared/lib_battery.cpp index 587b0955e1c..6fecba0a4d7 100644 --- a/third_party/ssc/shared/lib_battery.cpp +++ b/third_party/ssc/shared/lib_battery.cpp @@ -442,7 +442,11 @@ battery_t::battery_t(double dt_hr, int chem, capacity_t *capacity_model, voltage voltage = std::unique_ptr(voltage_model); lifetime = std::unique_ptr(lifetime_model); thermal = std::unique_ptr(thermal_model); - losses = std::unique_ptr(losses_model); + if (losses_model == nullptr) { + losses = std::unique_ptr(new losses_t()); + } else { + losses = std::unique_ptr(losses_model); + } state = std::make_shared(capacity->state, voltage->state, thermal->state, lifetime->state, losses->state); params = std::make_shared(capacity->params, voltage->params, thermal->params, lifetime->params, losses->params); From ed06b6c81e586619daef7e8427e24d25648a3c3c Mon Sep 17 00:00:00 2001 From: Noel Merket Date: Mon, 22 Feb 2021 21:26:32 +0000 Subject: [PATCH 71/76] Fixing /0 error in lib_battery.cpp --- third_party/ssc/shared/lib_battery.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/third_party/ssc/shared/lib_battery.cpp b/third_party/ssc/shared/lib_battery.cpp index 6fecba0a4d7..c0b0262107c 100644 --- a/third_party/ssc/shared/lib_battery.cpp +++ b/third_party/ssc/shared/lib_battery.cpp @@ -598,7 +598,8 @@ double battery_t::run(size_t lifetimeIndex, double &I) { runThermalModel(I, lifetimeIndex); runCapacityModel(I); - if (fabs(I - I_initial) / fabs(I_initial) > tolerance) { + double numerator = fabs(I - I_initial); + if ((numerator > 0.0) && (numerator / fabs(I_initial) > tolerance)) { *thermal->state = thermal_initial; *capacity->state = capacity_initial; I_initial = I; From 57fe02a74460a99826431b65854d963921adf7c4 Mon Sep 17 00:00:00 2001 From: Noel Merket Date: Mon, 22 Feb 2021 21:28:04 +0000 Subject: [PATCH 72/76] fixing array bound for internal gains again --- src/EnergyPlus/DataHeatBalance.cc | 3 ++- src/EnergyPlus/UFADManager.cc | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/EnergyPlus/DataHeatBalance.cc b/src/EnergyPlus/DataHeatBalance.cc index 06f1b368bab..9c28f631bbc 100644 --- a/src/EnergyPlus/DataHeatBalance.cc +++ b/src/EnergyPlus/DataHeatBalance.cc @@ -321,7 +321,8 @@ namespace DataHeatBalance { "COIL:HEATING:DX:MULTISPEED", "ELECTRICLOADCENTER:STORAGE:CONVERTER", "FAN:SYSTEMMODEL"}); // 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 | 13 | 14 | 15 | 16 - // 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 + // | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | + // 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 // | 48 | 49 | 50 | 51 | 52 | 53 | 54 Array1D_string const ccZoneIntGainDeviceTypes(NumZoneIntGainDeviceTypes, diff --git a/src/EnergyPlus/UFADManager.cc b/src/EnergyPlus/UFADManager.cc index 98e06e0f001..794f457320e 100644 --- a/src/EnergyPlus/UFADManager.cc +++ b/src/EnergyPlus/UFADManager.cc @@ -1446,7 +1446,7 @@ namespace UFADManager { int ZoneNodeNum; // node number of the HVAC zone node static Real64 TempDepCoef(0.0); // Formerly CoefSumha, coef in zone temp equation with dimensions of h*A static Real64 TempIndCoef(0.0); // Formerly CoefSumhat, coef in zone temp equation with dimensions of h*A(T1 - static Array1D_int IntGainTypesOccupied(29, + static Array1D_int IntGainTypesOccupied(30, {IntGainTypeOf_People, IntGainTypeOf_WaterHeaterMixed, IntGainTypeOf_WaterHeaterStratified, From d57f1905bffbddb17b6e9d7a2f242124b6bd4d38 Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Fri, 26 Feb 2021 08:52:15 +0100 Subject: [PATCH 73/76] Remove trailing whitespace in IDD and tabs --- idd/Energy+.idd.in | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/idd/Energy+.idd.in b/idd/Energy+.idd.in index 4fcf08cfc6e..c346616d567 100644 --- a/idd/Energy+.idd.in +++ b/idd/Energy+.idd.in @@ -678,7 +678,7 @@ SurfaceConvectionAlgorithm:Inside, \note for ceiling diffuser configuration with simple natural convection limit \note AdaptiveConvectionAlgorithm = dynamic selection of convection models based on conditions \note ASTMC1340 = mixed convection correlations based on heat flow direction, - \note surface tilt angle, surface characteristic length, and air speed past the surface. + \note surface tilt angle, surface characteristic length, and air speed past the surface. SurfaceConvectionAlgorithm:Outside, \memo Default outside surface heat transfer convection algorithm to be used for all zones @@ -791,29 +791,29 @@ ZoneAirContaminantBalance, \object-list ScheduleNames ZoneAirMassFlowConservation, - \memo Enforces the zone air mass flow balance by either adjusting zone mixing object flow only, - \memo adjusting zone total return flow only, zone mixing and the zone total return flows, - \memo or adjusting the zone total return and zone mixing object flows. Zone infiltration flow air + \memo Enforces the zone air mass flow balance by either adjusting zone mixing object flow only, + \memo adjusting zone total return flow only, zone mixing and the zone total return flows, + \memo or adjusting the zone total return and zone mixing object flows. Zone infiltration flow air \memo flow is increased or decreased depending user selection in the infiltration treatment method. - \memo If either of zone mixing or zone return flow adjusting methods or infiltration is active, - \memo then the zone air mass flow balance calculation will attempt to enforce conservation of + \memo If either of zone mixing or zone return flow adjusting methods or infiltration is active, + \memo then the zone air mass flow balance calculation will attempt to enforce conservation of \memo mass for each zone. If flow balancing method is "None" and infiltration is "None", then the - \memo zone air mass flow calculation defaults to assume self-balanced simple flow mixing and + \memo zone air mass flow calculation defaults to assume self-balanced simple flow mixing and \memo infiltration objects. \unique-object \min-fields 3 A1, \field Adjust Zone Mixing and Return For Air Mass Flow Balance \note If "AdjustMixingOnly", zone mixing object flow rates are adjusted to balance the zone air mass \note flow and zone infiltration air flow may be increased or decreased if required in order to balance - \note the zone air mass flow. If "AdjustReturnOnly", zone total return flow rate is adjusted to balance - \note the zone air mass flow and zone infiltration air flow may be increased or decreased if required - \note in order to balance the zone air mass flow. If "AdjustMixingThenReturn", first the zone mixing - \note objects flow rates are adjusted to balance the zone air flow, second zone total return flow rate + \note the zone air mass flow. If "AdjustReturnOnly", zone total return flow rate is adjusted to balance + \note the zone air mass flow and zone infiltration air flow may be increased or decreased if required + \note in order to balance the zone air mass flow. If "AdjustMixingThenReturn", first the zone mixing + \note objects flow rates are adjusted to balance the zone air flow, second zone total return flow rate \note is adjusted and zone infiltration air flow may be increased or decreased if required in order to - \note balance the zone air mass flow. If "AdjustReturnThenMixing", first zone total return flow rate is - \note adjusted to balance the zone air flow, second the zone mixing object flow rates are adjusted and - \note infiltration air flow may be increased or decreased if required in order to balance the zone - \note air mass flow. + \note balance the zone air mass flow. If "AdjustReturnThenMixing", first zone total return flow rate is + \note adjusted to balance the zone air flow, second the zone mixing object flow rates are adjusted and + \note infiltration air flow may be increased or decreased if required in order to balance the zone + \note air mass flow. \type choice \key AdjustMixingOnly \key AdjustReturnOnly From 501457705beb9af730846eb4b57e54b9acf8382b Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Fri, 26 Feb 2021 09:09:41 +0100 Subject: [PATCH 74/76] Fix #8563 - Wrong reference on `ZoneHVAC:LowTemperatureRadiant:ConstantFlow:Design` --- idd/Energy+.idd.in | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/idd/Energy+.idd.in b/idd/Energy+.idd.in index c346616d567..cacb39ff897 100644 --- a/idd/Energy+.idd.in +++ b/idd/Energy+.idd.in @@ -44351,9 +44351,7 @@ ZoneHVAC:LowTemperatureRadiant:ConstantFlow:Design, \min-fields 11 A1 , \field Name \required-field - \reference-class-name validBranchEquipmentTypes - \reference validBranchEquipmentNames - \reference ZoneEquipmentNames + \reference RadiantDesignObject A2 , \field Fluid to Radiant Surface Heat Transfer Model \note This parameter identifies how the heat transfer between \note fluid being circulated through the radiant system and From 7798bb8619af314202d872a379d60f0741d578f9 Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Fri, 26 Feb 2021 11:39:13 +0100 Subject: [PATCH 75/76] Add test for #8564 - GetLowTempRadiantSystem with one of each type --- .../unit/LowTempRadiantSystem.unit.cc | 213 ++++++++++++++++++ 1 file changed, 213 insertions(+) diff --git a/tst/EnergyPlus/unit/LowTempRadiantSystem.unit.cc b/tst/EnergyPlus/unit/LowTempRadiantSystem.unit.cc index 98391ad07bb..8dc4ac97d90 100644 --- a/tst/EnergyPlus/unit/LowTempRadiantSystem.unit.cc +++ b/tst/EnergyPlus/unit/LowTempRadiantSystem.unit.cc @@ -3563,3 +3563,216 @@ TEST_F(LowTempRadiantSystemTest, calculateUFromISOStandardTest) EXPECT_NEAR(expectedResult, actualResult, allowedDifference); } + + + +TEST_F(LowTempRadiantSystemTest, GetLowTempRadiantSystem_MultipleTypes) +{ + // #8564 - GetLowTempRadiantSystem fails when you have more a LowTempRadVarFlow AND at least one other type + std::string const idf_objects = delimited_string({ + + "ZoneHVAC:LowTemperatureRadiant:VariableFlow,", + " West Zone Radiant Floor, !- Name", + " West Zone Radiant Floor Design, !- Design Object", + " RadiantSysAvailSched, !- Availability Schedule Name", + " West Zone, !- Zone Name", + " West Zone Surface Group, !- Surface Name or Radiant Surface Group Name", + " Autosize, !- Hydronic Tubing Length {m}", + " Autosize, !- Heating Design Capacity {W}", + " Autosize, !- Maximum Hot Water Flow {m3/s}", + " Node 276, !- Heating Water Inlet Node Name", + " Node 277, !- Heating Water Outlet Node Name", + " Autosize, !- Cooling Design Capacity {W}", + " Autosize, !- Maximum Cold Water Flow {m3/s}", + " Node 278, !- Cooling Water Inlet Node Name", + " Node 279, !- Cooling Water Outlet Node Name", + " OnePerSurface, !- Number of Circuits", + " 106.7; !- Circuit Length {m}", + + "ZoneHVAC:LowTemperatureRadiant:VariableFlow:Design,", + " West Zone Radiant Floor Design, !- Name", + " ConvectionOnly, !- Fluid to Radiant Surface Heat Transfer Model", + " 0.013, !- Hydronic Tubing Inside Diameter {m}", + " 0.016, !- Hydronic Tubing Outside Diameter {m}", + " 0.35, !- Hydronic Tubing Conductivity {W/m-K}", + " MeanAirTemperature, !- Temperature Control Type", + " HalfFlowPower, !- Setpoint Control Type", + " HeatingDesignCapacity, !- Heating Design Capacity Method", + " 0, !- Heating Design Capacity Per Floor Area {W/m2}", + " 1, !- Fraction of Autosized Heating Design Capacity", + " 0.5, !- Heating Control Throttling Range {deltaC}", + " Radiant Heating Setpoints, !- Heating Control Temperature Schedule Name", + " CoolingDesignCapacity, !- Cooling Design Capacity Method", + " 0, !- Cooling Design Capacity Per Floor Area {W/m2}", + " 1, !- Fraction of Autosized Cooling Design Capacity", + " 0.5, !- Cooling Control Throttling Range {deltaC}", + " Radiant Cooling Setpoints, !- Cooling Control Temperature Schedule Name", + " SimpleOff, !- Condensation Control Type", + " 1; !- Condensation Control Dewpoint Offset {C}", + + + "ZoneHVAC:LowTemperatureRadiant:ConstantFlow,", + " South Zone LowTempRad, !- Name", + " South Zone LowTempRad Design, !- Design Object", + " RadiantSysAvailSched, !- Availability Schedule Name", + " South Zone, !- Zone Name", + " South Zone Surface Group, !- Surface Name or Radiant Surface Group Name", + " Autosize, !- Hydronic Tubing Length {m}", + " Autosize, !- Rated Flow Rate {m3/s}", + " , !- Pump Flow Rate Schedule Name", + " 179352, !- Rated Pump Head {Pa}", + " , !- Rated Power Consumption {W}", + " , !- Heating Water Inlet Node Name", + " , !- Heating Water Outlet Node Name", + " Radiant Heating Setpoints, !- Heating High Water Temperature Schedule Name", // I'm not testing schedules... + " Radiant Heating Setpoints, !- Heating Low Water Temperature Schedule Name", + " Radiant Heating Setpoints, !- Heating High Control Temperature Schedule Name", + " Radiant Heating Setpoints, !- Heating Low Control Temperature Schedule Name", + " , !- Cooling Water Inlet Node Name", + " , !- Cooling Water Outlet Node Name", + " Radiant Cooling Setpoints, !- Cooling High Water Temperature Schedule Name", + " Radiant Cooling Setpoints, !- Cooling Low Water Temperature Schedule Name", + " Radiant Cooling Setpoints, !- Cooling High Control Temperature Schedule Name", + " Radiant Cooling Setpoints, !- Cooling Low Control Temperature Schedule Name", + " OnePerSurface, !- Number of Circuits", + " 106.7; !- Circuit Length {m}", + + "ZoneHVAC:LowTemperatureRadiant:ConstantFlow:Design,", + " South Zone LowTempRad Design, !- Name", + " ConvectionOnly, !- Fluid to Radiant Surface Heat Transfer Model", + " 0.013, !- Hydronic Tubing Inside Diameter {m}", + " 0.016, !- Hydronic Tubing Outside Diameter {m}", + " 0.35, !- Hydronic Tubing Conductivity {W/m-K}", + " MeanAirTemperature, !- Temperature Control Type", + " 0.8, !- Running Mean Outdoor Dry-Bulb Temperature Weighting Factor", + " 0.9, !- Motor Efficiency", + " 0, !- Fraction of Motor Inefficiencies to Fluid Stream", + " SimpleOff, !- Condensation Control Type", + " 1; !- Condensation Control Dewpoint Offset {C}", + + + " ZoneHVAC:LowTemperatureRadiant:Electric,", + " East Zone Radiant Floor, !- Name", + " RadiantSysAvailSched, !- Availability Schedule Name", + " East Zone, !- Zone Name", + " East Zone Surface Group, !- Surface Name or Radiant Surface Group Name", + " heatingdesigncapacity, !- Heating Design Capacity Method", + " 100, !- Heating Design Capacity{ W }", + " , !- Heating Design Capacity Per Floor Area{ W/m2 }", + " 1.0, !- Fraction of Autosized Heating Design Capacity", + " MeanAirTemperature, !- Temperature Control Type", + " HalfFlowPower, !- Setpoint Type", + " 2.0, !- Heating Throttling Range {deltaC}", + " Radiant Heating Setpoints; !- Heating Control Temperature Schedule Name", + + " ZoneHVAC:LowTemperatureRadiant:SurfaceGroup,", + " East Zone Surface Group, !- Name", + " Zn002:Flr001, !- Surface 1 Name", + " 0.5, !- Flow Fraction for Surface 1", + " Zn002:Flr002, !- Surface 2 Name", + " 0.5; !- Flow Fraction for Surface 2", + + " ZoneHVAC:LowTemperatureRadiant:SurfaceGroup,", + " West Zone Surface Group, !- Name", + " Zn001:Flr001, !- Surface 1 Name", + " 0.5, !- Flow Fraction for Surface 1", + " Zn001:Flr002, !- Surface 2 Name", + " 0.5; !- Flow Fraction for Surface 2", + + " ZoneHVAC:LowTemperatureRadiant:SurfaceGroup,", + " South Zone Surface Group, !- Name", + " Zn003:Flr001, !- Surface 1 Name", + " 0.5, !- Flow Fraction for Surface 1", + " Zn003:Flr002, !- Surface 2 Name", + " 0.5; !- Flow Fraction for Surface 2", + + " Schedule:Compact,", + " RADIANTSYSAVAILSCHED, !- Name", + " FRACTION, !- Schedule Type Limits Name", + " Through: 12/31, !- Field 1", + " For: Alldays, !- Field 2", + " Until: 24:00,1.00; !- Field 3", + + " Schedule:Compact,", + " Radiant Heating Setpoints, !- Name", + " TEMPERATURE, !- Schedule Type Limits Name", + " Through: 12/31, !- Field 1", + " For: Alldays, !- Field 2", + " Until: 24:00,20.0; !- Field 3", + + " Schedule:Compact,", + " Radiant Cooling Setpoints, !- Name", + " TEMPERATURE, !- Schedule Type Limits Name", + " Through: 12/31, !- Field 1", + " For: Alldays, !- Field 2", + " Until: 24:00,15.0; !- Field 3", + + }); + ASSERT_TRUE(process_idf(idf_objects)); + + Zone.allocate(3); + Zone(1).Name = "WEST ZONE"; + Zone(2).Name = "EAST ZONE"; + Zone(3).Name = "SOUTH ZONE"; + + DataSurfaces::TotSurfaces = 6; + Surface.allocate(DataSurfaces::TotSurfaces); + Surface(1).Name = "ZN001:FLR001"; + Surface(1).ZoneName = "WEST ZONE"; + Surface(1).Zone = 1; + Surface(1).Construction = 1; + Surface(2).Name = "ZN001:FLR002"; + Surface(2).ZoneName = "WEST ZONE"; + Surface(2).Zone = 1; + Surface(2).Construction = 1; + Surface(3).Name = "ZN002:FLR001"; + Surface(3).ZoneName = "EAST ZONE"; + Surface(3).Zone = 2; + Surface(3).Construction = 1; + Surface(4).Name = "ZN002:FLR002"; + Surface(4).ZoneName = "EAST ZONE"; + Surface(4).Zone = 2; + Surface(4).Construction = 1; + Surface(5).Name = "ZN003:FLR001"; + Surface(5).ZoneName = "SOUTH ZONE"; + Surface(5).Zone = 3; + Surface(5).Construction = 1; + Surface(6).Name = "ZN003:FLR002"; + Surface(6).ZoneName = "SOUTH ZONE"; + Surface(6).Zone = 3; + Surface(6).Construction = 1; + state->dataConstruction->Construct.allocate(1); + state->dataConstruction->Construct(1).SourceSinkPresent = true; + + GetLowTempRadiantSystem(*state); + + EXPECT_EQ(3, LowTempRadiantSystem::TotalNumOfRadSystems); + + EXPECT_EQ(1, LowTempRadiantSystem::NumOfHydrLowTempRadSys); + EXPECT_EQ(1, LowTempRadiantSystem::NumOfHydrLowTempRadSysDes); + + EXPECT_EQ(1, LowTempRadiantSystem::NumOfCFloLowTempRadSys); + EXPECT_EQ(1, LowTempRadiantSystem::NumOfCFloLowTempRadSysDes); + + EXPECT_EQ(1, LowTempRadiantSystem::NumOfElecLowTempRadSys); + + EXPECT_EQ("WEST ZONE RADIANT FLOOR", RadSysTypes(1).Name); + EXPECT_EQ(LowTempRadiantSystem::SystemType::HydronicSystem, RadSysTypes(1).SystemType); + EXPECT_EQ(LowTempRadiantSystem::HydrRadSys(1).ZoneName, "WEST ZONE"); + EXPECT_EQ(LowTempRadiantSystem::HydrRadSys(1).SurfListName, "WEST ZONE SURFACE GROUP"); + EXPECT_EQ("WEST ZONE RADIANT FLOOR DESIGN", LowTempRadiantSystem::HydrRadSys(1).designObjectName); + EXPECT_EQ(1, LowTempRadiantSystem::HydrRadSys(1).DesignObjectPtr); + + EXPECT_EQ("SOUTH ZONE LOWTEMPRAD", RadSysTypes(2).Name); + EXPECT_EQ(LowTempRadiantSystem::SystemType::ConstantFlowSystem, RadSysTypes(2).SystemType); + EXPECT_EQ(LowTempRadiantSystem::CFloRadSys(1).ZoneName, "SOUTH ZONE"); + EXPECT_EQ(LowTempRadiantSystem::CFloRadSys(1).SurfListName, "SOUTH ZONE SURFACE GROUP"); + EXPECT_EQ("SOUTH ZONE LOWTEMPRAD DESIGN", LowTempRadiantSystem::CFloRadSys(1).designObjectName); + EXPECT_EQ(1, LowTempRadiantSystem::CFloRadSys(1).DesignObjectPtr); + + EXPECT_EQ("EAST ZONE RADIANT FLOOR", RadSysTypes(3).Name); + EXPECT_EQ(LowTempRadiantSystem::SystemType::ElectricSystem, RadSysTypes(3).SystemType); + EXPECT_EQ(LowTempRadiantSystem::ElecRadSys(1).ZoneName, "EAST ZONE"); + EXPECT_EQ(LowTempRadiantSystem::ElecRadSys(1).SurfListName, "EAST ZONE SURFACE GROUP"); + +} From 075c6c76f15e750eda0db2127b9f9111602d7dfd Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Fri, 26 Feb 2021 11:02:55 +0100 Subject: [PATCH 76/76] Fix #8564 - GetLowTempRadiantSystem fails when you have more a LowTempRadVarFlow AND at least one other type --- src/EnergyPlus/LowTempRadiantSystem.cc | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/EnergyPlus/LowTempRadiantSystem.cc b/src/EnergyPlus/LowTempRadiantSystem.cc index 94aeaf0eeac..f2e03b6ff44 100644 --- a/src/EnergyPlus/LowTempRadiantSystem.cc +++ b/src/EnergyPlus/LowTempRadiantSystem.cc @@ -491,17 +491,18 @@ namespace LowTempRadiantSystem { ElecRadSys.allocate(NumOfElecLowTempRadSys); ElecRadSysNumericFields.allocate(NumOfElecLowTempRadSys); + HydronicRadiantSysNumericFields.allocate(NumOfHydrLowTempRadSys); HydronicRadiantSysDesign.allocate(NumOfHydrLowTempRadSysDes); - CflowRadiantSysDesign.allocate(NumOfCFloLowTempRadSysDes); VarFlowRadDesignNames.allocate(NumOfHydrLowTempRadSysDes); + + CflowRadiantSysDesign.allocate(NumOfCFloLowTempRadSysDes); CFlowRadDesignNames.allocate(NumOfCFloLowTempRadSysDes); // make sure data is gotten for surface lists GetNumberOfSurfaceLists(state); // Obtain all of the design data related to hydronic low temperature radiant systems... - BaseNum = 0; CurrentModuleObject = "ZoneHVAC:LowTemperatureRadiant:VariableFlow:Design"; for (Item = 1; Item <= NumOfHydrLowTempRadSysDes; ++Item) { @@ -525,7 +526,6 @@ namespace LowTempRadiantSystem { HydronicRadiantSysDesign(Item).FieldNames = cNumericFields; GlobalNames::VerifyUniqueInterObjectName(state, LowTempRadUniqueNames, Alphas(1), CurrentModuleObject, cAlphaFields(1), ErrorsFound); - ++BaseNum; auto &thisRadSysDesign(HydronicRadiantSysDesign(Item)); // General user input data @@ -896,7 +896,6 @@ namespace LowTempRadiantSystem { } // Obtain all of the design data related to Constant flow low temperature radiant systems... - BaseNum = 0; CurrentModuleObject = "ZoneHVAC:LowTemperatureRadiant:ConstantFlow:Design"; for (Item = 1; Item <= NumOfCFloLowTempRadSysDes; ++Item) { @@ -920,7 +919,6 @@ namespace LowTempRadiantSystem { CflowRadiantSysDesign(Item).FieldNames = cNumericFields; GlobalNames::VerifyUniqueInterObjectName(state, LowTempRadUniqueNames, Alphas(1), CurrentModuleObject, cAlphaFields(1), ErrorsFound); - ++BaseNum; auto &thisRadSysDesign(CflowRadiantSysDesign(Item)); // General user input data @@ -966,7 +964,6 @@ namespace LowTempRadiantSystem { } // Obtain all of the user data related to constant flow (hydronic) low temperature radiant systems... - BaseNum = 0; CurrentModuleObject = "ZoneHVAC:LowTemperatureRadiant:ConstantFlow"; for (Item = 1; Item <= NumOfCFloLowTempRadSys; ++Item) {