From 418ac0a4f7ba3a98f84aa5635864b5829c729924 Mon Sep 17 00:00:00 2001 From: gantian127 Date: Wed, 23 Oct 2024 15:59:59 -0600 Subject: [PATCH 01/18] update notebooks --- notebooks/bmi_era5.ipynb | 11 +++++++++-- notebooks/download.nc | Bin 8836 -> 37844 bytes notebooks/installation.py | 7 +------ 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/notebooks/bmi_era5.ipynb b/notebooks/bmi_era5.ipynb index 9937951..7fce347 100755 --- a/notebooks/bmi_era5.ipynb +++ b/notebooks/bmi_era5.ipynb @@ -152,7 +152,7 @@ "dataset = xarray.open_dataset(\"download.nc\")\n", "\n", "# select 2 metre temperature on 2021-01-01 at 00:00\n", - "air_temp = dataset.t2m.isel(time=0)" + "air_temp = dataset.t2m.isel(valid_time=0)" ] }, { @@ -374,6 +374,13 @@ "source": [ "data_comp.finalize()" ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { @@ -392,7 +399,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.7" + "version": "3.13.0" } }, "nbformat": 4, diff --git a/notebooks/download.nc b/notebooks/download.nc index 24bf19d7afcb498c9f89d3d5cd73e1db818590cd..d211f418c4c369ba98c91dab91e9c571794440d6 100644 GIT binary patch literal 37844 zcmeG_2_ThA+b_qyWxHAwCxnEMQrhg1eQA-369-2eI*X;7J#FfyXi+JZMA}dZC22+7 zNTogHR$5TD6y=|Jm*bq0yMN#P{(I)$&hySb^DHyZ%ri6A+FIF2ON@{Z6ca-T*N3}X zsaS{s9uf9l?31&tm7Ab+nxLQ>8c34BEWOOpmj{Nc_JVk?3AUA zo}s>plsoJuCozrAWYJjczoIWs5kwdiEQaALkj7+%GNRBHT*O;oWME{hXK0{jWZ+?B zXliIkhWID5Ldlj^j^iwC$l){!+1EdSL0h6{pg%?5&{*GaJk{4S)Q`&4Gt!?hN#B4R zL1P7ye^g_JvKhWqHB+*hAB9EHhgsBg$!h+zU>23(y(G$eDK&}-qCrYPTS^G{^il)F zVW=&N2I;7DUr?yGuRj_dMqyAws30ROf<+6VLKr{|4Pa2h0;8ZOoXTL)d?~>oHv-X# zVBf37>yt44L<9r?{Q#Z;m2j2=sK6Xa3Q~-ln8GqJgrozB3n>F!+z%sB?juPezNT1E zCk~aTVtz4s2uT9NaS<4X1%tfs}+XkkJXzY zj0MlZV~O60B45iZ;TIVNlL`ny5rj@6oDxj)^M>T8!Ev#6$_g94B*AzIu;pOUE~VMV-Q5}y z#W_^qvH)TVt3`Y^oU{xl$R~mnv0R1&tgn3Lnafr({L9|8Plht`J0FqU&(W;`dEUm!MPGQg}OMMo{TYY6xg9IRpSOW7F9o zR0f;@$TUAGkO(RU-!KjsE6~h_n6UWb!ooq~P!Rt;=MlX`m74+J*yf2-SpqN-<}`18 znus!hIX)){bO<0)Cq*@%YoR2(&erzUPbd- z^Dw)&lcft(Y`_#q#Uw-xR0Jyp(;^e(n{K2_r?Pzg{HGg(S=&fA(9eJ3bVE3OPY@Xn z8!jM(k0yu+H8Kq3^3;RD2%>0M2&D~k{w=Trh%5_(Ll+#H;m`nwWE{%k5W(R)PrQB{*5I%lhsSZ4 ziNh2e#(9=QLG>I3et?7X8n>U&p^12?u|x_qryXIa8%kY~mQhp^SuVqpun#w>Ic{K3 zV_>k699h#)eqK09SU4KFP%a!Dmy{$RoYXn*%y9d*N384#uQoW&&D*0<-4?5BdI5E zw}%%#&?%pg;=jX(J@J|GP|2$GRdJVTDyGY39~_^lJ%6;Fi_kn@G27Oy>*U|B?S1aM z^i0WtqtqA^|BtJRb~ZOwKY04_^1`u-2TtT$g#PkrYYtK|zfnjNc^)MlAD{kX)~@pI zp$=7b{wF01_G_MU)X$52@nh-AEhVSd`?r~8`6(CducREH=eN9wa3oUhnq4F2&Sb z-+rU!Q=MyL^ec0A-F`B>E=c}vxrDBWEJMub{jvEz)}N6Kp~{`fDGKwQ_6ZNWA?J5> zWaZg|TZ$6zb$KKQcME+CUDi8nSjM$gT373P)!dZx&Kc6ZVwaA5(-Uvsi_l`z@QDO6 z6yNbNz{kM93IjH7wl3)UN)SP}Y_QG~S|!kLP`4jl{DMzZPvnAFG-vgPd%p`ncA^Bh zwgXNZKodtI!x9JY+cxfCjfoI7;|;)56X{?vE@0gTw0u0qm{|1TNzkPc_?A?Py^rc_ z!A4k&fDD4Pp_>B&V7_cdRU?5EK_m>-7iB!QoLQ%tex9Qkqs7973_j-~1pH&GQwc;4 zN99Z$5vjN?NvPEKaBZ^*?+CU!B?v-<{_Xn`zEUB&mI=p#6wU*(kwm})aP_kiUQ z>WK9chxQyEz~Tx08uNYs7i8n)?B^a&RLO<8v=d)9p<28+)Q_b>2+-njwZC7B?~18g zf$4Y&scNY!o$G^$WZ_+3oLD6N{1Y>EK&nL5G$21`liTkdue{H~c!w|C%20OZhz*u(7qW;Oso2866dh^hjWh zhT0aqozNw^v1Mo|!;eO%u)ta#?nz_g8F@eh1C&_KK8K})xw|{M*9E6(I67O|Ia)ip z+c`UVyIYz&Sc9a(*k%`J@0GJFhHnd^8xm5mPNF$hw2%RI`ml=s{2m{t@%_7da8QPg zCwBMfp$t~wAp0b6xPs}4oz3rT9DSQi4#Nesf>8au{b<1C!?Ci!Q4(u}FW7%!(&z!u z24n!&({9!_)^65Lme$@5cJ3a?B#;c^8=5(oR2BlvQP>db2R6p(aQ6ifgYn#Cge5~q zKq}Y^f(~L8y0Xa_B>b3<|NFma%!z&U9p z`2CYs<}m4>+JS@xV3sCv{50$W7z7=$zQ=t1zuKEaE^=^T48sLU{fBb#BUSxIG(6)s z;rP){RnE@ZP%&g^EJ!UZf#PZ$w&PYFD~aMxP!OIw7eG@(2>%1PLk%<}L7|8!tR6@T zSQWJ4!2*cmY8spak|Xea7aQDKh?sz6f7JDUh%tvJx`<;~1Sg1q^K9T)+Yo&31;cRF z6s#IvtIXzj+D8iyJ14lC39UV|uv0%?Bbqmq;Z2k+n}p?5NYY!p#H!o*=ZDcJ&1sxa`IcH^0 zS{tTdM%H|M=aXQ50-{BOpRW!1o%oI-euNewV2q4=9d2Y@1RLmu?LEeXii#i-5C;@& zcfNNLTNK#?OP_)5!JjqS3+!@G)_}mM0D#(MS+H+rnAMe}EGCC|13wIa;i#e30k+g0 z0hR#(^y9`OvtX1SW_6W$nd^jHgk1w-3o$$`QP~x-g|+A)2pIs>l=~RZ0>hIX{O2H_ zVHR!7IITBp*J9)ZOaZdMaYyvv-T)*IVj46CT5#W)o3N2>upOYcaCT^zbS4TJ0|T@W za2gsIe1`^Xn4}e53qJn^j@!s;hxeD8Zaj2H9>El2@CjHD;@KMKZEi{;+?>Ee4uqR} zh$N&O7=F=XB5pY4p(P1P#y#i^&CL@$)aD@@!p&Sf6h@RFbAx)|1q+0m(~;9K#sQyt zxn~2!9`cM2Hn;IG5RYUaOQD#6Wa!nEYUly%jh>!Rg6s#xV*~(*E%a!D`xDSZhaL+A z83{edp=UHUfAWYFQVU~18daE#TMQ5e_apeT+AbanNXIfVfjJcvgi~8l)oULQ^@7gq-^YWp3nDMF5pERhe(@ofw@dJl z1vh1E)&~~ybj^AA;Ua_^r-o(2PxJJ*+B>=u;bt7&rNz}eL`_uxP|Jh;%3PIt9yIx; zZhD2CF~Hd$J=?)emNcp8w>+Hx(P8B$9xC1u3GE#*mM{l_VmCLtJ};D|i1 zVo6-$NS}tKJcq+SrC2t|jXs7dmgq4b0U;<=(2-b1A%wYE1l6epP$7eHf~+vY@;qhq zwtV!a0gyy^m0}2(TYz1z|3Cq1`-TGpoO1}1_dvIKpqLS>6*vmYI6c}qxVq8-vj9h2 zq2MSR9Hj$`M~7MLbI@Oqjgu2A8a+|yN@R*-9l3?7E8Mr%z{mhy|E)F4IkDPbD>Wvw zzD`vmn6mkgolZ2zyMqp?pjZORC7gQrO}$`HhOWPL(=##_qKELFv!A&E0{mR6gh}FP85Nn~+f#2Y2 zCKlPRc+RyPYK+n71Y}6yP&{!#G!XoJt#}qs#bOABlYmk`M2P)I6;C_ZV!#C7S3E0V z*9KKQA3|9Gx+)wQP{p$cX3_py@dN>o3Ii*iX|Nq$T#BbU3;>D&p?HSdt?L3I{{r_P zQao{TAl%eL#3ALtScDECE;!{;#d9t0k%ScB<_UzG+6Xt<5N_r|xGBt|-u!zM&$H)~ zSN=K!e`gEEWIC2r*2EI~P?&vr*qdK3j-TRx3HTjmJh%sr|Kh^q z_zID6|6{a=&Bf_|6Mm~>8YjAona}p21nc1y7VGVruU&H_||ACO!xRQp-e=Tg26*eFY za=S)SnGO#^i|RQ|JJ8Qk*!1FQufGEn(XfdMNp4RFBQJ!{8Nona|__cvkSx5+VN#56FPxWPmM7=-00IU^V|O*L$S!HWAl*;Nv}m-0p!(TAnU^=X%co z>HhxvI%0KZk9NO`^zKIQgO8#Lfe@gx(K>?5_xn5TLjROEy z^?*-ffx!bU6h8bmh~V-j`{pSoXkdg*V^V!X>3&QyxMJr^B^ypLG0-zG1pkx3W)}Ja zq%S3y3ZL>qj}yToMKD(wBQ%%_-gor%1}}gGgo2l==zrz?Jh;w+j)25#NLVOXgXt4r z7$oGMHykf5Mc9ZmJ)vD+>9}Y(?;~M<@%tSQZ9up3=f-EcA`9K}1Rv;1hB` zo4%AD8UZ+78rbB3RStb5mC0uKQ+$8#D|?W~@uyaOx$Ygq_JQ>VS{rr}4ZIIWy!J>Y zZrYMLdIcGKHSG7;2?^OEAk=gTJ0a8&xc%^kBDbG^0T3XB@BUF3;FW(k`(3|annD6c zG5TK)rn&o4=u9VS0Fd->YH$?Ko3jHM&xszAz;T#~BM3Fj=!0G(WVFf3VAOR%Rq%q3p+IfB6nzDe`BFM=U_`+T6tx?~VRN?Kkr( zCxNXWuJ-p=@Ki|>tH%cof4#a=$ zc;z3)>Kfju_+9!xF%=RJ7D7}>LIzrme|z|SU{NoRg~~!d!q5k`?XU-Y#b7mv*?{kh z{DQ_oB>{g|7bOaO>cS%`40~6XpozaPr>_{TQF1u@V*|>sl7#}x0S*$j|K)cUsKwde zfeHpoRR1S5AY9pj`bK}Jm@I189Q2W3?x(y5LI^}EbiCby`8nMZ2GOud6klI9UciQ{=<}~+@W{mvR zjPR-hbYIo@>$4Mjd<@OV^IE?@M_vhXaTHc=(f0M9OJQ)55^MxTTa}9gAhNBf{xm>W z@RZ8e5BtM|XE3J&{(Q}N2VyWJLuB(#o3y`j+60yII#m8Sk7z@oA}ze3!x{ges@(s) zG%@}ef#-|C^Y>&HH3U50OJT7YgDt7QLFfNh{U07KgEC622Vlp!{n(HN0{M=Qfqw`F zc;z4J|KX!LoOve$zWxtJcIXDyHqa>W^Ob&!kL`bv{><0^(Z7!|kXnS||39k#4>&KK>Z)?z~e6&{(sQ_30({R`6UXy-$IG@jlTlG*rNaM@PMUC|EkUR53K+o*F#+% zTu}L6TmpEwSzE(9<-{}01VsPj3XZP9zPYOJ_h(0;A4P~ z0X_!!7~o@oj{!ag{m3J_G=Zd+~4kEGwBp{?2=}-J%;BR`3#QVG^H$Dbg=OtW&y4a{-caBu(v@1IGPb)3u#u!Q5EVmBWFF2XD)@D;dUF!DC)NM~C_Em_w7`NH%PndOF%+z@W`M9~p zd`i~%VJxK5b{I2%!x~xPO+%*?no|vGZa8@VH%Tw$Ew#2JnkW&5W z`1xm(!_{PD{QWOTCr(JLTt0afWSWBnd97NNm8!tVNZF-s zY9=QH65>WBOx~>dP*X{C#B=#~<@?BCW^wYv48m5aj1(l-2(@h&l5Nm3@!gbED4%0z zXW_R)LtMGh$Wd(eY%w!wS0RZGS9x*Ki@*pekiJ$YPA#P_%WvUy$$S#dx*MvP8aoXk5B*D#OvP!9&g^)q7hN*3bp9CW8B6eA3jzEgp z>vxSb!J(10C7(8QQESh;_ZEyK6`j0)QorOKrCNB@i{+)xEav>z^G+Wwrso7*eanp6 zAjmXs|2VF5OUt(L{s)SVnU>~$&a3;dVAq1(%bt3^-sAis!>cRM=QI1ljxE(nw;g^~ z8EJ6qT*afMvGY?8-~E_t*q(N9OP^x2YX0)Xn8&}w>jyM1nA=H<$P9m;zW(T|va^Z4 zpE7c0ubGfxaMXE&w^wTZgy+}W?@nm!a_qdNye@01NS}7Ti}Jpy^J69(T#JfmJn~}W z5-lf(%8iQ*UsJ*)^|O;N9Jo6DIkl8N#B^qpb!E1HZmpJychu(WoW-iOu`aA%=DBwd zH}BjNo7LGDaoY4E&8n=hzUYPIl+>b<6)i5z4=+O6Q)Qf$Z*<61In|b^+$$-uE4utM zTR|tWwPVHSD@T$)ZhH_izG|Vtseq|v)6~Ylo!xNcXwNC9w!Z39&r*u)#~tjQwT}|m zB1?Jv__(q%{hh#s)hfqY7aVRGTDYt%ppofV_3@^ma>486(cL*_*UnD#D=lkms-`bp zyuMmGf)VuNjHZsA=UZC5Pa65ZExMm_Ktkm~bxip%%EJ0xSIZ(YK3v;A?^bnTL|^jM zPpWVyoY_FGS-_#J$ z=dU}T&3YOBvwn<^nrg%Q(=j_b<1e|I4p3ZV33hIC>WHompK~*{M7kWlFgz}< z9yjG+liJZ&0qIk_`V{j&UpBvC_Y-^dGzljbJ7dJ#1?dlSJKu%hK6lhPqxI#}w%XQ4 zx1S!LKg?CH8m2Oht8JkNLPiXwyTk2R0g@8o1V zcl&kky|sB4g?;iuH|fP5Jy)BU1%U_Wt$w-OvwqYo z`InE+ye)FpdQvu}sxNd1ZFbV$)yd6y{*unkGoy@8zux67%{SQL)hsp(X)~+C~fSWYyWZ{%e27y!|9-J_)}L4eFtP z$zFDK)SHl)ALdL*b@mQ#ahsPmsp3si;Lbf6+X_2-D~2|zt$x_iI->L4h6jf(jV@$5 z#B^0Hp8069TUd)N>rs_+fSs1onUAlQQ>&V;Y@^R8&DR+dUc1fvu4$Lop69hcFK6FA z?D@FxLz?DlmBYJ76gACVUY_Q*de*25Sp{di>dqEBsje^EsZhV{)aih_xOJUH*=ao+ z-!v$+6r6}^eskG1W9d@SQ#p>2Dt+&}0|RnfEY96zs|PrTk8n8^&9;iZoImzyUWN0~ zM~8O&c+0Vwa{R=kwc9 zDW*mSX18m5YMz!2T@cZ|b7||Fz|R#YFR4D-U+4a)K4W> ze_U4In7pYgx#Ue+ao4e1U&kgwT;C0nWZ9YfqM%;L{NX_8DwjTwOjauXB=WehI7ah`mCpLtMjyxIE8s*Qg?8-0yJxQV542}bAJVu=rlgnEyiqlb z`e4Bv$5;iU#L&L$yX2go1voKg_E>jRrOp~R^wj6#kmJvMqT8|>C-wxqdUz!E_I2^x z_o@r`wM;ZAWp_R)IoBThbDGMwi`PDy&E6HX&g+QR&9X4R%d7XwcnWy!+qZe%rS7}k z&;3ls>Drf;>9*JJuX}js$4Q|X?;3|Z3dp@KQ(|}IoZf@mN7}WHPA&18ZW!C#!z@3v zbjz`Vkk8KNuB|!ypzr-~eYMzU*J;-;?hJ^vU*vZ`typcr)P0Qow~xNCUv*S^(L&>n z(pL7|`l{rGOLq62o>(xC61?cDWQOC-m70l-iOWAt9$D%Z)z|WQ>QA2b9h+8{M!)X4 z5ht_9IQ@A0#s|LoQ783v=}YRnpRAtl^`)@OB4SRoBW>@}qv6(0PXeyUCwfc$cs}}J ze*2g!rq4H3%RO)&b4_f1nQv>pQpnL6Q%o4O!}DTDXI310dAl=u(Xaxo8NG}z-C6AL zQyW^mdNfA$l+LO-ZTMyFTJia7w;resWSeH}*2|dNBO|uX=Afu{sObjH(dI|y7P`pS zyiV0!BNIQO0#Tctk&+{j6OgZXtgd34nfE#yn`pP2vE~_vXN%olxvSO3G*aGJtX5<5 znN^i%sbsx%v&~u}HK=DI>@BpD+}#w(SAy={tSk!F|!zpqXt&Ft2aO}Ab4$K~gE@2d;0*?2&1QiSKwV@VR4GI=_3 zb6&e1Tc~*3VLCF$ogKMfsBDz_Q$?o>fsy+ePLmuZL=qnDTN{IDRJ|UyLQv?WqV0~Y zK~ECOWv@!mBA44usq`)1H+Vdpcohis>d zEs{^jf4ar(z}AliGe@wlHmnpn)Y$xd|GXi}0*dzIn@6QA9vv*GFmbzK`pUvfMo897 z@ebvTH5)H$EuALsLXX0GS^+|PYq*Z01b=XxF^V^bl4FNY)m z%K(w^@%P)~%{)kFe7V0K0C680^Xn~nU@Xk^_T^9W*GmJ!w;^TZ?{|pd$Mp913j~IX z_e70MAqc20e<&d4-cV2G$GWkZ>d#0!KpNx*#M1heqHqdLT0!D#+sqXitE* zha1!1&5yzKr0<3xp-2oAfdj$(_cLJ(Pv674VZOA0K!~T0H$VvU@b-iKR}Cm|3j}ch z?WYCMd_fR@5X_V2>BWH2X-pa#Mx)dA13Q88Z9u*Kn2Z2Fnhyklg=3Kz3>JZf>SN*h zx=0iRh1N$y5O81$g=H`pSO`Yn0}DZ8XnGJm1Pa(Z0trXZ5FQ@-x*kwJ&#x>@-~F(q zs6c+Q5nZUBE*1et>wVb>8Uh%G@*U-eP(TV05kS7rmmq%MqhXYL%y)c_<9Ed&hBwL^qDTy_)LJr1^mM2QWOn_j@ye2Is$+;cxtv!&h+y1gd&M00FQYz-|D$ z0PF&=6TnUYI{@qeupPj50NVg;1F#jqRsdT7Yypr1AP2x^0Gk190(D{ld?KXnk1bvaW`9L>`6fw&XKNHld>Mgwax;_49SP<|xO+qZH zEi#QSgJ%^SCF0-TX%1~Ls-aJTtKAYO!c$X58r^xZ)pc)SGL}LM$`iVHr+Y*QJ{QNs zUBe$WNWn?K%oUE!gg0q^y zAm}wA%PqrAU3D{1n-Dl;otfpt(1g>FS9c}*j|a77kIORaX8ML-uU&?f zD*L3kwjZyyZRhTbe(3?jUTC+2j^VDelo0|8^8_|vo;X=B-rpb5C|GQlvNg>hhr!y} zS~c-e940udJ9}MiN079N(_)e2E%*fOhakkjAl!AcljpF&BRmb3;1+P5#T% zeXO#~u_JGz-UYv{EzD`SJZ#e-yb!+Zt69+UFlLOyYn4)jT(H`TTAko}=fCr#FpuTsuQnZZ*mmr?9=^K_>nqU#R4g-NV=HQ4F?JY-dbc*t~^ z<_c#HnFLnHZMC&^jopVj?7Yj}BE@L8sR>UR$+D(yT`=a7P9gn4J(D%Bl$+Oo(3HD? zwo@Niaf|3fU1JccO2)vP%)HAFlaHUJ+K@O#wr1(e&CEM(PT8ZZ0%H?ufJ6fK9?ltVW-yb`@OGprP-u?hl$9%T~Y)iV+E>E^+jL85Afj^~A0&i!> z79vU<^Luj`?4r&sqrszcGj<)D`!srkW}br8+)o7%?PRt!*hN|=n`lwU6bZr&EDxiL z0;7sEwPSm49laBnmB}gW*gNuM64NW2E?IrNOr{I6Q68mkJh?s3O~%>XHr_Cg7)U-y zID|b6UU4zdf;F=kt_ zDU~8<-eKH>?SxK3M6_S#X(s4LOI-e=z@_?0!$!`zVd_{?*ZO|xGMNHzVU)^xva4U$ zj+d4p(#GRX{zA}L0%VDkp$cA57=Tc=@Jt`D!a_)bx}UK9mfnM&%Z z4I1mJXGuhC#7{p|--Yp|#_hryr^C_6Ly%iK{@Qwa1g>Z6YL0f@h9ZXyu{>7qotnH% zc1>`Ve&0;*)7&Gi8G~)TE-Ra{om3e+$kvla462MhXDiFLW~+FGz#|CT=#l8iliqWW zr<*kE3OM@D&JU|kbx-2ir_0_n>!=i{Zljzea(DPsOHA`^$W9%u*LP&QE@O|i8nr35 z6~2W|_YaX+8TDnYR?oH%uwR{DttV!`?BhDNdxhggoBfs--48g+S_)x#`bFg9Rtj#t zova~PzcT0VUiK507T?s+qP>m7j|U&7J%2YkE2)H%a}f7Kc&+x3-Zt*YvDL7)LafqE z-6XAf#kghY?AYh07n&oA|4i_@u9e9vX1CXr+ub|Q31Z1rRV;+ySUZo=kJD$iW!R-S zDpCI+A;8-;-fNa>&5oo#HQ`89-6?#Zu=Y=%a6;l0PEbWurtD*MwMMa4({Al-D+QaE zmJ9ChX-;nPyGSm5daj7I$X%G%LVphjcW!ADY;mf3nq`w9o1hvKkPvg5bl0lNrPPvr zS;oRZgmjUZXXQsJ)IWtwun0zKKnTcG1Fp=%c+Jb4>H8mX@7>$u3oLT47lX3e(=JsE z7bukxp5)Z^Eh|`4yZIHZA6%(4wRwY!sJ;~PI5x~+4yCM;xpH8I+KSkfs-NTD%>5nK zJpRBo50*oCHr4D|DK}HjrG6eq3EPluFIY%B9`V+q$m;pvyK!#FcHO<&pVhId!^$%& zGK7ul$@A2H>8h@WZuRe~ZELvey4IiHOaR|R{|SjVk8)$W(JlTU;t6MQnqs+X2e9wZ zf*MJhrE8yvHV(X;-#Hk{uB?y4VsVDKN@i0d0|q{Axm{W85_VhR>W1LfV{Pe8=i1ZSJi3e9j$<{mJtl!S09``D~xs?LDe9YAcT- zVsZ7xjg(xI2hOouCykl#k7S-%v`KhjQEtQi!Yp`(bB#u`YwKTw!#tTMQ|%`TlA9#v z56O|%hmy-It!&e*_M3+oWTD<@I%Bj83Cawdv`zETkE2SQ`IrlzNFa%t?!N7oGEiE zw!C}hj&4_KL2;p)#36B-hKGeN-P|X~s~TU76eJd)?a5)3N)shg%f<88bE56fOx?+P z;9eS9+Qt&i70FO#`KBNfPj(N^Vl*x@3haXoQ!p%p8z=_;@{Y;vFNibi+tw!5i5D%; z+H+?E+vMfGx$e*HWl`53MA^mY#Cv6x^)p6oB!w+5=x&0Gp^NO&FeI%vm;t1_R;kJg zxf36@%pI7(wv=VAest)?zOm=`=ELhkgsxx`rtT5ywg|>6W{kyd$W>hhZnNvh;#8li zsjC@m+@;(kx1vS7!MaL1??9eK`c%Qbwh!qBXS2_@<>j!5x4qKt)|vH`a~WdmA*m)Y zRHto^%|rCkK(|!V)~Bqynaz1dSz#$WUX3WOxBjtInL4E zVr6lBAkrDHjGxtmL55X6DPL2v!N4NjRyPqN83P4Ui$mh|8Mdqi(i zOfX)_M$_Epkx4z?fed64zH8GBP|14gx^+vD^2AxW1$8=djT3|Hg9`jyrW#7FQ z^*Jv}gc~8LHd0>4T*r4tZE3Tiki`uYHl?UcsB%CJDqGsNj~4Wtt6iP15Pv)RLz*=} z{ywoh@pkgPTbS~y4_ff7ZSnLly7N{gvpkDbiv8vURaNznO=mO(`@A|zs483cTe)@jm?U7{h zT}=r|@!V^*7^%o7fMM0zgta8>c> zph|5(-KToXmY35Ol2yye61x;zR0On`up|smm#z!J-h5@Fc?~9rNrUNYiLP5Gs#z)4 zFFGDJ>bmw?m2~yBX$jdqE2U)AR;DZTf#x*fkQ3+toTR?G-mpGBM6g%BKcX$~5%&?d zJ3&A|F~Q7(S69Qk5g8)%vtNlkoBl8&b88CkLE^o-hY`8>%&n(`LWE8S@z4M4my0iv zXKAMZEXhG}@|Osqyf3SNt{G`}RXZjzPChz6(k`4E&ixtFKXwty3+G1XU)8=u2IyWXUjJ{N#LwQkbeh=fHqw_BjmR^he4i;$_ z#g4T5(!YMCgN4!gx=Yvi=idCjouz61e%D-@{U3Sv^LNjWv_gcIp84nXc{CDkt-&slomi}CRYmNV${rYzTzxz}j9_tZ0yhdwYj#p=G+ntckUCLWLihYT| z?_#&OK?{QNLFzm|Vi&-`w}*SxCzrGtfY`OnVR-?u(}fBp4KDmp(o=td;J zikBLzuN~}nzQH2x_UPI diff --git a/notebooks/installation.py b/notebooks/installation.py index 4387924..3b5dc38 100644 --- a/notebooks/installation.py +++ b/notebooks/installation.py @@ -5,7 +5,7 @@ def install_cds(config_path=""): # create configuration file - url = "https://cds.climate.copernicus.eu/api/v2" + url = "https://cds.climate.copernicus.eu/api" key = input("Enter Your CDS API Key: ") config_content = f"url: {url} \nkey: {key}" @@ -16,8 +16,3 @@ def install_cds(config_path=""): config_file.write(config_content) print("CDS API Key file is created.") - - # # install cdsapi - # install = subprocess.run(["pip", "install", "cdsapi"], check=True) - # if install.returncode == 0: - # print('cdsapi package is successfully installed.') From 3080032f8743f8cf3fa4770084cebe7a93d32188 Mon Sep 17 00:00:00 2001 From: gantian127 Date: Wed, 23 Oct 2024 16:03:13 -0600 Subject: [PATCH 02/18] update cdsapi version for dependencies --- pyproject.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index ed8db18..d340ded 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,6 +22,7 @@ classifiers = [ "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", "Programming Language :: Python :: Implementation :: CPython", "Topic :: Scientific/Engineering :: Hydrology", "Topic :: Scientific/Engineering :: Physics", @@ -33,7 +34,7 @@ dependencies = [ "pyyaml", "requests", "xarray", - "cdsapi", + "cdsapi >= 0.7.2", ] dynamic = [ "version", From 014103e20c83cfccd6da513237d4d64153bfc818 Mon Sep 17 00:00:00 2001 From: gantian127 Date: Wed, 23 Oct 2024 16:04:06 -0600 Subject: [PATCH 03/18] add cdsapi version for requirments.txt --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 6728f5f..c47c167 100755 --- a/requirements.txt +++ b/requirements.txt @@ -4,3 +4,4 @@ numpy pyyaml requests xarray +cdsapi>=0.7.2 From 95b563ccf465f0cfdff45948d4f9508550b98c9c Mon Sep 17 00:00:00 2001 From: gantian127 Date: Thu, 24 Oct 2024 11:26:59 -0600 Subject: [PATCH 04/18] update docs example and text --- README.md | 12 ++++++------ docs/source/index.md | 7 ++++--- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 9b1958d..e69d77d 100755 --- a/README.md +++ b/README.md @@ -3,20 +3,20 @@ [![Documentation Status](https://readthedocs.org/projects/bmi_era5/badge/?version=latest)](https://bmi-era5.readthedocs.io/en/latest/?badge=latest) [![MIT license](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/gantian127/bmi_era5/blob/master/LICENSE.txt) -**Please be aware that the CDS platform was upgraded in September 2024, which has resulted in the current bmi_era5 being incompatible with the latest version of the CDS platform. -A new release of bmi_era5 is expected later this year.** +**Please note: starting with release v0.1.5, the New CDS platform is now supported.** bmi_era5 package is an implementation of the Basic Model Interface ([BMI](https://bmi-spec.readthedocs.io/en/latest/)) for the [ERA5](https://confluence.ecmwf.int/display/CKB/ERA5) dataset. -This package uses the [CDS API](https://cds.climate.copernicus.eu/api-how-to) to download the ERA5 dataset and wraps the dataset with BMI for data control and query -(currently support 3 dimensional ERA5 dataset). +This package uses the [CDS API](https://cds.climate.copernicus.eu/how-to-api) to download +the ERA5 dataset and wraps the dataset with BMI for data control and query. +It currently supports 3-dimensional ERA5 datasets defined with dimensions as [valid_time, latitude, longitude]. This package is not implemented for people to use but is the key element to convert the ERA5 dataset into a data component ([pymt_era5](https://pymt-era5.readthedocs.io/)) for the [PyMT](https://pymt.readthedocs.io/en/latest/?badge=latest) modeling framework developed by Community Surface Dynamics Modeling System ([CSDMS](https://csdms.colorado.edu/wiki/Main_Page)). -If you have any suggestion to improve the current function, please create a github issue +If you have any suggestion to improve the current function, please create a GitHub issue [here](https://github.com/gantian127/bmi_era5/issues). @@ -77,7 +77,7 @@ c.retrieve( dataset = xarray.open_dataset("download.nc") # select 2 meter temperature on 2021-01-01 at 00:00 -air_temp = dataset.t2m.isel(time=0) +air_temp = dataset.t2m.isel(valid_time=0) # plot data air_temp.plot(figsize=(9, 5)) diff --git a/docs/source/index.md b/docs/source/index.md index 95da1e2..8af6ef1 100644 --- a/docs/source/index.md +++ b/docs/source/index.md @@ -8,7 +8,8 @@ [bmi_era5 package][bmi_era5-github] is an implementation of the [Basic Model Interface (BMI)][bmi-docs] for the [ERA5][ERA5] dataset. This package uses the [CDS API][cds-api] to download the ERA5 dataset and wraps the -dataset with BMI for data control and query (currently support 3 dimensional ERA5 dataset). +dataset with BMI for data control and query. It currently supports 3-dimensional ERA5 +datasets defined with dimensions as [valid_time, latitude, longitude]. This package is not implemented for people to use but is the key element to convert the ERA5 dataset into a data component ([pymt_era5][pymt_era5]) for the [PyMT][pymt-docs] @@ -80,7 +81,7 @@ c.retrieve( dataset = xarray.open_dataset("download.nc") # select 2 metre temperature on 2021-01-01 at 00:00 -air_temp = dataset.t2m.isel(time=0) +air_temp = dataset.t2m.isel(valid_time=0) # plot data air_temp.plot(figsize=(9, 5)) @@ -179,7 +180,7 @@ data_comp.finalize() [bmi-docs]: https://bmi.readthedocs.io [csdms]: https://csdms.colorado.edu [pymt-docs]: https://pymt.readthedocs.io -[cds-api]: https://cds.climate.copernicus.eu/api-how-to +[cds-api]: https://cds.climate.copernicus.eu/how-to-api [bmi_era5-github]: https://github.com/gantian127/bmi_era5/ [ERA5]: https://confluence.ecmwf.int/display/CKB/ERA5 [bmi_era5-notebook]: https://github.com/gantian127/bmi_era5/blob/master/notebooks/bmi_era5.ipynb From f29af9b86d8e2a7b9005f0e580599a6cd039eeb8 Mon Sep 17 00:00:00 2001 From: gantian127 Date: Thu, 24 Oct 2024 11:49:47 -0600 Subject: [PATCH 05/18] update ci testing for cds api link --- .github/workflows/test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ae6d6ce..1edf1a1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -20,7 +20,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] - python-version: ["3.10", "3.11", "3.12"] + python-version: ["3.10", "3.11", "3.12", "3.13"] steps: - uses: actions/checkout@v4 @@ -34,7 +34,7 @@ jobs: env: CDS_API_KEY: ${{secrets.CDS_API_KEY}} run: | - echo "url: https://cds.climate.copernicus.eu/api/v2" >> .cdsapirc + echo "https://cds.climate.copernicus.eu/api" >> .cdsapirc echo key: $CDS_API_KEY >> .cdsapirc cat .cdsapirc mv .cdsapirc ~/ From 8afce30f958e803376b95e7cd7f9dd1729241918 Mon Sep 17 00:00:00 2001 From: gantian127 Date: Thu, 24 Oct 2024 11:50:20 -0600 Subject: [PATCH 06/18] update unit test for new era5 data content --- tests/util_test.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/util_test.py b/tests/util_test.py index 486bfce..d7124ba 100755 --- a/tests/util_test.py +++ b/tests/util_test.py @@ -62,15 +62,15 @@ def test_get_var_info(tmpdir, name, file, era5_req): era5.get_data(name, era5_req, path) var_info_2 = era5.get_var_info() - assert len(var_info_2) == 2 + assert "Total precipitation" in var_info_2.keys() assert "2 metre temperature" in var_info_2.keys() var = var_info_2["Total precipitation"] assert var["var_name"] == "tp" - assert var["dtype"] == "float64" - assert var["itemsize"] == 2 - assert var["nbytes"] == 1218 + assert var["dtype"] == "float32" + assert var["itemsize"] == 4 + assert var["nbytes"] == 2436 assert var["units"] == "m" assert var["location"] == "node" @@ -87,9 +87,9 @@ def test_get_time_info(tmpdir, name, file, era5_req): era5.get_data(name, era5_req, path) time_info_2 = era5.get_time_info() - assert time_info_2["start_time"] == 1060680 - assert time_info_2["end_time"] == 1060682 - assert time_info_2["time_step"] == 1 + assert time_info_2["start_time"] == 1609459200.0 + assert time_info_2["end_time"] == 1609466400.0 + assert time_info_2["time_step"] == 3600.0 assert time_info_2["total_steps"] == 3 - assert time_info_2["time_units"] == "hours since 1900-01-01 00:00:00.0" - assert time_info_2["calendar"] == "gregorian" + assert time_info_2["time_units"] == "seconds since 1970-01-01" + assert time_info_2["calendar"] == "proleptic_gregorian" From cb5bfacb07020564d2b1273258321d36aa490cfb Mon Sep 17 00:00:00 2001 From: gantian127 Date: Thu, 24 Oct 2024 11:55:02 -0600 Subject: [PATCH 07/18] update utils and bmi for era5 data from new CDS platform --- src/bmi_era5/_version.py | 2 +- src/bmi_era5/bmi.py | 10 ++-------- src/bmi_era5/utils.py | 40 +++++++++++++++++++++------------------- 3 files changed, 24 insertions(+), 28 deletions(-) diff --git a/src/bmi_era5/_version.py b/src/bmi_era5/_version.py index 1073798..6c43b68 100644 --- a/src/bmi_era5/_version.py +++ b/src/bmi_era5/_version.py @@ -1,3 +1,3 @@ from __future__ import annotations -__version__ = "0.1.4" +__version__ = "0.1.5" diff --git a/src/bmi_era5/bmi.py b/src/bmi_era5/bmi.py index 5abfef5..1b80d53 100755 --- a/src/bmi_era5/bmi.py +++ b/src/bmi_era5/bmi.py @@ -462,14 +462,8 @@ def get_value_ptr(self, name: str) -> numpy.ndarray: """ # return a reference of all the value at current time step. # mainly for input data. not useful for scalar value - add_offset = self._dataset[self._var_name_mapping[name]].add_offset - scale_factor = self._dataset[self._var_name_mapping[name]].scale_factor - - return ( - self._dataset[self._var_name_mapping[name]].values[self._time_index] - * scale_factor - + add_offset - ) + + return self._dataset[self._var_name_mapping[name]].values[self._time_index] def get_var_grid(self, name: str) -> int: """Get grid identifier for the given variable. diff --git a/src/bmi_era5/utils.py b/src/bmi_era5/utils.py index c3c233a..474f356 100755 --- a/src/bmi_era5/utils.py +++ b/src/bmi_era5/utils.py @@ -82,15 +82,17 @@ def get_time_info(self): # time values are float in BMI time function if self._data: time_info = { - "start_time": float(self._data.time.values[0]), + "start_time": float(self._data.valid_time.values[0]), "time_step": 0.0 - if len(self._data.time.values) == 1 - else float(self._data.time.values[1] - self._data.time.values[0]), - "end_time": float(self._data.time.values[-1]), - "total_steps": len(self._data.time.values), - "time_units": self._data.time.units, - "calendar": self._data.time.calendar, - "time_value": self._data.time.values.astype("float"), + if len(self._data.valid_time.values) == 1 + else float( + self._data.valid_time.values[1] - self._data.valid_time.values[0] + ), + "end_time": float(self._data.valid_time.values[-1]), + "total_steps": len(self._data.valid_time.values), + "time_units": self._data.valid_time.units, + "calendar": self._data.valid_time.calendar, + "time_value": self._data.valid_time.values.astype("float"), } return time_info @@ -101,16 +103,16 @@ def get_var_info(self): if self._data: for var_name in self._data.data_vars: var = self._data.data_vars[var_name] - - var_info[var.long_name] = { - "var_name": var_name, - "dtype": type(var.scale_factor).__name__ - if "scale_factor" in var.attrs.keys() - else str(var.dtype), - "itemsize": var.values.itemsize, - "nbytes": var.values[0].nbytes, # current time step nbytes - "units": var.units, - "location": "node", - } + if var.ndim >= 3: + var_info[var.long_name] = { + "var_name": var_name, + "dtype": type(var.scale_factor).__name__ + if "scale_factor" in var.attrs.keys() + else str(var.dtype), + "itemsize": var.values.itemsize, + "nbytes": var.values[0].nbytes, # current time step nbytes + "units": var.units, + "location": "node", + } return var_info From 00d5b08aae4b942ebc9cb95c8e65444c58b087df Mon Sep 17 00:00:00 2001 From: gantian127 Date: Thu, 24 Oct 2024 12:03:25 -0600 Subject: [PATCH 08/18] clean up code --- notebooks/bmi_era5.ipynb | 7 ------- requirements.txt | 2 +- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/notebooks/bmi_era5.ipynb b/notebooks/bmi_era5.ipynb index 7fce347..6612e9b 100755 --- a/notebooks/bmi_era5.ipynb +++ b/notebooks/bmi_era5.ipynb @@ -374,13 +374,6 @@ "source": [ "data_comp.finalize()" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { diff --git a/requirements.txt b/requirements.txt index c47c167..89548d7 100755 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ bmipy +cdsapi>=0.7.2 netcdf4 numpy pyyaml requests xarray -cdsapi>=0.7.2 From 0e046fe8befc426f56656632ddbf6beb1a698748 Mon Sep 17 00:00:00 2001 From: gantian127 Date: Thu, 24 Oct 2024 12:19:27 -0600 Subject: [PATCH 09/18] update readme text --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e69d77d..75a8852 100755 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![Documentation Status](https://readthedocs.org/projects/bmi_era5/badge/?version=latest)](https://bmi-era5.readthedocs.io/en/latest/?badge=latest) [![MIT license](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/gantian127/bmi_era5/blob/master/LICENSE.txt) -**Please note: starting with release v0.1.5, the New CDS platform is now supported.** +**Please note: Starting with release v0.2.0, the New CDS platform is now supported.** bmi_era5 package is an implementation of the Basic Model Interface ([BMI](https://bmi-spec.readthedocs.io/en/latest/)) for the [ERA5](https://confluence.ecmwf.int/display/CKB/ERA5) dataset. From 9da1d82511809d9e4080fa6c348cb1a8869602aa Mon Sep 17 00:00:00 2001 From: gantian127 Date: Thu, 24 Oct 2024 12:25:59 -0600 Subject: [PATCH 10/18] update version number --- src/bmi_era5/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bmi_era5/_version.py b/src/bmi_era5/_version.py index 6c43b68..a148ede 100644 --- a/src/bmi_era5/_version.py +++ b/src/bmi_era5/_version.py @@ -1,3 +1,3 @@ from __future__ import annotations -__version__ = "0.1.5" +__version__ = "0.2.0" From 532f1c19be219f91d8e6063f2c60bde048e1fcf1 Mon Sep 17 00:00:00 2001 From: gantian127 Date: Thu, 24 Oct 2024 14:03:03 -0600 Subject: [PATCH 11/18] ci test: check api key file --- .github/workflows/test.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1edf1a1..54272b4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -38,6 +38,8 @@ jobs: echo key: $CDS_API_KEY >> .cdsapirc cat .cdsapirc mv .cdsapirc ~/ + ls ~ + pwd - name: Test run: | From a0cbc349d7259f11d8a328360a20e66f8b0fe988 Mon Sep 17 00:00:00 2001 From: gantian127 Date: Thu, 24 Oct 2024 14:12:42 -0600 Subject: [PATCH 12/18] ci test: copy api key file to folder --- .github/workflows/test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 54272b4..701c9fd 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -37,8 +37,8 @@ jobs: echo "https://cds.climate.copernicus.eu/api" >> .cdsapirc echo key: $CDS_API_KEY >> .cdsapirc cat .cdsapirc - mv .cdsapirc ~/ - ls ~ + cp .cdsapirc /home/runner + ls -a /home/runner pwd - name: Test From 486bbcff3b1b424916a221f9b698ee34c3a23256 Mon Sep 17 00:00:00 2001 From: gantian127 Date: Thu, 24 Oct 2024 14:17:55 -0600 Subject: [PATCH 13/18] ci testing: api key file --- .github/workflows/test.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 701c9fd..4e902e5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -37,9 +37,9 @@ jobs: echo "https://cds.climate.copernicus.eu/api" >> .cdsapirc echo key: $CDS_API_KEY >> .cdsapirc cat .cdsapirc - cp .cdsapirc /home/runner - ls -a /home/runner - pwd + cp .cdsapirc ~/ + ls -a ~ + ls -a - name: Test run: | From a0ea932073785ef2dc1654f957fe461788f19dc3 Mon Sep 17 00:00:00 2001 From: gantian127 Date: Thu, 24 Oct 2024 14:45:46 -0600 Subject: [PATCH 14/18] update nox file and remove api key file in test.yml --- .github/workflows/test.yml | 26 +++++++++++++++----------- noxfile.py | 16 ++++++++++++++++ 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4e902e5..601e83e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -29,19 +29,23 @@ jobs: with: python-version: ${{ matrix.python-version }} - - name: API Key File - shell: bash - env: - CDS_API_KEY: ${{secrets.CDS_API_KEY}} - run: | - echo "https://cds.climate.copernicus.eu/api" >> .cdsapirc - echo key: $CDS_API_KEY >> .cdsapirc - cat .cdsapirc - cp .cdsapirc ~/ - ls -a ~ - ls -a +# - name: API Key File +# shell: bash +# env: +# CDS_API_KEY: ${{secrets.CDS_API_KEY}} +# run: | +# echo "https://cds.climate.copernicus.eu/api" >> .cdsapirc +# echo key: $CDS_API_KEY >> .cdsapirc +# cat .cdsapirc +# cp .cdsapirc ~/ +# cp .cdsapirc ./notebooks +# cp .cdsapirc ./tests +# ls -a ~ +# ls -a - name: Test + env: + CDS_API_KEY: ${{secrets.CDS_API_KEY}} run: | pip install nox pip install --upgrade setuptools diff --git a/noxfile.py b/noxfile.py index 8eb3f80..88714df 100644 --- a/noxfile.py +++ b/noxfile.py @@ -15,6 +15,22 @@ def test(session: nox.Session) -> None: """Run the tests.""" session.install(".[testing]") + + + print(os.environ.get("CDS_API_KEY")) + url = "https://cds.climate.copernicus.eu/api" + key = os.environ.get("CDS_API_KEY") + config_content = f"url: {url} \nkey: {key}" + home_dir = os.path.expanduser("~") + config_path = os.path.join(home_dir, ".cdsapirc") + + with open(config_path, "w") as config_file: + config_file.write(config_content) + + print(os.path.isdir(config_path)) + print(config_path) + print(config_content) + args = ["--cov", PROJECT, "-vvv"] + session.posargs if "CI" in os.environ: From e984f3563bdb2ef4e77559a38bbff3b4bbc73c51 Mon Sep 17 00:00:00 2001 From: gantian127 Date: Thu, 24 Oct 2024 14:55:05 -0600 Subject: [PATCH 15/18] update ci testing noxfile to create api key file --- .github/workflows/test.yml | 14 -------------- noxfile.py | 9 +-------- 2 files changed, 1 insertion(+), 22 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 601e83e..c52d1f1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -29,20 +29,6 @@ jobs: with: python-version: ${{ matrix.python-version }} -# - name: API Key File -# shell: bash -# env: -# CDS_API_KEY: ${{secrets.CDS_API_KEY}} -# run: | -# echo "https://cds.climate.copernicus.eu/api" >> .cdsapirc -# echo key: $CDS_API_KEY >> .cdsapirc -# cat .cdsapirc -# cp .cdsapirc ~/ -# cp .cdsapirc ./notebooks -# cp .cdsapirc ./tests -# ls -a ~ -# ls -a - - name: Test env: CDS_API_KEY: ${{secrets.CDS_API_KEY}} diff --git a/noxfile.py b/noxfile.py index 88714df..2df6ec8 100644 --- a/noxfile.py +++ b/noxfile.py @@ -15,22 +15,15 @@ def test(session: nox.Session) -> None: """Run the tests.""" session.install(".[testing]") - - - print(os.environ.get("CDS_API_KEY")) + # create API key file for ERA5 (need GitHub secret) url = "https://cds.climate.copernicus.eu/api" key = os.environ.get("CDS_API_KEY") config_content = f"url: {url} \nkey: {key}" home_dir = os.path.expanduser("~") config_path = os.path.join(home_dir, ".cdsapirc") - with open(config_path, "w") as config_file: config_file.write(config_content) - print(os.path.isdir(config_path)) - print(config_path) - print(config_content) - args = ["--cov", PROJECT, "-vvv"] + session.posargs if "CI" in os.environ: From 66ee707dc837b142f4ea2e7e69874c542ff0da51 Mon Sep 17 00:00:00 2001 From: gantian127 Date: Tue, 29 Oct 2024 18:19:40 -0600 Subject: [PATCH 16/18] update utils function and unit test to support get time info from time variable defined as 'date' --- src/bmi_era5/utils.py | 54 ++++++++++++++++++++++++++++++++----------- tests/util_test.py | 42 ++++++++++++++++++++++++++++++++- 2 files changed, 82 insertions(+), 14 deletions(-) diff --git a/src/bmi_era5/utils.py b/src/bmi_era5/utils.py index 474f356..055debd 100755 --- a/src/bmi_era5/utils.py +++ b/src/bmi_era5/utils.py @@ -1,8 +1,11 @@ from __future__ import annotations import os.path +from datetime import datetime import cdsapi +import cftime +import numpy as np import xarray as xr @@ -81,19 +84,44 @@ def get_time_info(self): # time values are float in BMI time function if self._data: - time_info = { - "start_time": float(self._data.valid_time.values[0]), - "time_step": 0.0 - if len(self._data.valid_time.values) == 1 - else float( - self._data.valid_time.values[1] - self._data.valid_time.values[0] - ), - "end_time": float(self._data.valid_time.values[-1]), - "total_steps": len(self._data.valid_time.values), - "time_units": self._data.valid_time.units, - "calendar": self._data.valid_time.calendar, - "time_value": self._data.valid_time.values.astype("float"), - } + if "valid_time" in self._data.keys(): + time_info = { + "start_time": float(self._data.valid_time.values[0]), + "time_step": 0.0 + if len(self._data.valid_time.values) == 1 + else float( + self._data.valid_time.values[1] + - self._data.valid_time.values[0] + ), + "end_time": float(self._data.valid_time.values[-1]), + "total_steps": len(self._data.valid_time.values), + "time_units": self._data.valid_time.units, + "calendar": self._data.valid_time.calendar, + "time_value": self._data.valid_time.values.astype("float"), + } + elif "date" in self._data.keys(): + # convert date time to CF convention values + date_objs = [ + datetime.strptime(str(date_value), "%Y%m%d") + for date_value in self._data.date.values + ] + time_units = "seconds since 1970-01-01" + calendar = "proleptic_gregorian" + cf_dates = cftime.date2num( + date_objs, units=time_units, calendar=calendar + ) + + time_info = { + "start_time": float(cf_dates[0]), + "time_step": 0.0 + if len(cf_dates) == 1 + else float(cf_dates[1] - cf_dates[0]), + "end_time": float(cf_dates[-1]), + "total_steps": len(cf_dates), + "time_units": time_units, + "calendar": calendar, + "time_value": np.array(cf_dates, dtype=float), + } return time_info diff --git a/tests/util_test.py b/tests/util_test.py index d7124ba..c2baaa6 100755 --- a/tests/util_test.py +++ b/tests/util_test.py @@ -24,6 +24,23 @@ ) ] +parameters2 = [ + ( + "reanalysis-era5-single-levels-monthly-means", + "monthly_mean.nc", + { + "product_type": ["monthly_averaged_reanalysis"], + "variable": ["2m_dewpoint_temperature"], + "year": ["2022"], + "month": ["01", "02", "03", "04"], + "time": ["00:00"], + "data_format": "netcdf", + "download_format": "unarchived", + "area": [39, -106, 36, -103], + }, + ) +] + @pytest.mark.parametrize("name, file, era5_req", parameters) def test_get_data(tmpdir, name, file, era5_req): @@ -76,7 +93,8 @@ def test_get_var_info(tmpdir, name, file, era5_req): @pytest.mark.parametrize("name, file, era5_req", parameters) -def test_get_time_info(tmpdir, name, file, era5_req): +def test_get_time_info_valid_time(tmpdir, name, file, era5_req): + """Test when time variable is valid_time""" path = os.path.join(tmpdir, file) era5 = Era5Data() @@ -93,3 +111,25 @@ def test_get_time_info(tmpdir, name, file, era5_req): assert time_info_2["total_steps"] == 3 assert time_info_2["time_units"] == "seconds since 1970-01-01" assert time_info_2["calendar"] == "proleptic_gregorian" + + +@pytest.mark.parametrize("name, file, era5_req", parameters2) +def test_get_time_info_date(tmpdir, name, file, era5_req): + """Test when time variable is date""" + + path = os.path.join(tmpdir, file) + + era5 = Era5Data() + time_info_1 = era5.get_time_info() + + assert time_info_1 == {} + + era5.get_data(name, era5_req, path) + time_info_2 = era5.get_time_info() + + assert time_info_2["start_time"] == 1640995200.0 + assert time_info_2["end_time"] == 1648771200.0 + assert time_info_2["time_step"] == 2678400.0 + assert time_info_2["total_steps"] == 4 + assert time_info_2["time_units"] == "seconds since 1970-01-01" + assert time_info_2["calendar"] == "proleptic_gregorian" From 9554bcc157bc39216a8ab4b9cebfa781844bcd21 Mon Sep 17 00:00:00 2001 From: gantian127 Date: Tue, 29 Oct 2024 18:20:36 -0600 Subject: [PATCH 17/18] add cftime pkg for dependency --- pyproject.toml | 1 + requirements.txt | 1 + 2 files changed, 2 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index d340ded..ecce15f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,6 +35,7 @@ dependencies = [ "requests", "xarray", "cdsapi >= 0.7.2", + "cftime", ] dynamic = [ "version", diff --git a/requirements.txt b/requirements.txt index 89548d7..b05bc21 100755 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,6 @@ bmipy cdsapi>=0.7.2 +cftime netcdf4 numpy pyyaml From 2fefd5b16a8b2a86acc72191d45da0fcd906db51 Mon Sep 17 00:00:00 2001 From: gantian127 Date: Wed, 30 Oct 2024 12:37:58 -0600 Subject: [PATCH 18/18] refine text in docs and notebook --- README.md | 3 ++- docs/source/index.md | 2 +- notebooks/bmi_era5.ipynb | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 75a8852..626f4a4 100755 --- a/README.md +++ b/README.md @@ -9,7 +9,8 @@ bmi_era5 package is an implementation of the Basic Model Interface ([BMI](https: for the [ERA5](https://confluence.ecmwf.int/display/CKB/ERA5) dataset. This package uses the [CDS API](https://cds.climate.copernicus.eu/how-to-api) to download the ERA5 dataset and wraps the dataset with BMI for data control and query. -It currently supports 3-dimensional ERA5 datasets defined with dimensions as [valid_time, latitude, longitude]. +It currently supports 3-dimensional ERA5 +datasets defined with dimensions such as valid_time (or date), latitude, and longitude. This package is not implemented for people to use but is the key element to convert the ERA5 dataset into a data component ([pymt_era5](https://pymt-era5.readthedocs.io/)) for diff --git a/docs/source/index.md b/docs/source/index.md index 8af6ef1..9c7a64b 100644 --- a/docs/source/index.md +++ b/docs/source/index.md @@ -9,7 +9,7 @@ the [Basic Model Interface (BMI)][bmi-docs] for the [ERA5][ERA5] dataset. This package uses the [CDS API][cds-api] to download the ERA5 dataset and wraps the dataset with BMI for data control and query. It currently supports 3-dimensional ERA5 -datasets defined with dimensions as [valid_time, latitude, longitude]. +datasets defined with dimensions such as valid_time (or date), latitude, and longitude. This package is not implemented for people to use but is the key element to convert the ERA5 dataset into a data component ([pymt_era5][pymt_era5]) for the [PyMT][pymt-docs] diff --git a/notebooks/bmi_era5.ipynb b/notebooks/bmi_era5.ipynb index 6612e9b..64f48c9 100755 --- a/notebooks/bmi_era5.ipynb +++ b/notebooks/bmi_era5.ipynb @@ -49,7 +49,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "bmi_era5 package is an implementation of the Basic Model Interface ([BMI](https://bmi.readthedocs.io/en/latest/)) for the [ERA5](https://confluence.ecmwf.int/display/CKB/ERA5) dataset. This package uses the [CDS API](https://cds.climate.copernicus.eu/api-how-to) to download the ERA5 dataset and wraps the dataset with BMI for data control and query (currently support 3 dimensional ERA5 dataset). This package is not implemented for people to use but is the key element to convert the ERA5 dataset into a data component for the [PyMT](https://pymt.readthedocs.io/en/latest/?badge=latest) modeling framework developed by Community Surface Dynamics Modeling System ([CSDMS](https://csdms.colorado.edu/wiki/Main_Page)).\n", + "bmi_era5 package is an implementation of the Basic Model Interface ([BMI](https://bmi.readthedocs.io/en/latest/)) for the [ERA5](https://confluence.ecmwf.int/display/CKB/ERA5) dataset. This package uses the [CDS API](https://cds.climate.copernicus.eu/how-to-api) to download the ERA5 dataset and wraps the dataset with BMI for data control and query (currently support 3-dimensional ERA5 dataset). This package is not implemented for people to use but is the key element to convert the ERA5 dataset into a data component for the [PyMT](https://pymt.readthedocs.io/en/latest/?badge=latest) modeling framework developed by Community Surface Dynamics Modeling System ([CSDMS](https://csdms.colorado.edu/wiki/Main_Page)).\n", "\n", " \n", "To install bmi_era5 package, please follow the instructions [here](https://github.com/gantian127/bmi_era5/#install-package)." @@ -59,7 +59,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "You can uncomment the code below to use install_cds( ) to install the CDS API Key file. This file is required for data download. So please make sure you have already created an account at the [CDS registration page](https://cds.climate.copernicus.eu/#!/home) and obtained your CDS API Key. For more details please check [here](https://cds.climate.copernicus.eu/api-how-to)." + "You can uncomment the code below to use install_cds( ) to install the CDS API Key file. This file is required for data download. So please make sure you have already created an account at the [CDS registration page](https://cds.climate.copernicus.eu/#!/home) and obtained your CDS API Key. For more details please check [here](https://cds.climate.copernicus.eu/how-to-api)." ] }, {