From f3c6c8405f343370fa01a5085bb490af5fd74562 Mon Sep 17 00:00:00 2001 From: Jongmin Park Date: Mon, 19 Jul 2021 16:35:26 -0400 Subject: [PATCH 001/308] MODIS snow cover assimilation --- .../GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 index 594e77da..539ce00d 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 @@ -16,7 +16,8 @@ module clsm_ensupd_enkf_update MAPL_TICE USE CATCH_CONSTANTS, ONLY : & - N_gt => CATCH_N_GT + N_gt => CATCH_N_GT, & + N_snow => CATCH_N_SNOW !added jpark50 (07/19/21) use catchment_model, ONLY: & catch_calc_tsurf From edf12820072429d74fc01831798e891418088fe7 Mon Sep 17 00:00:00 2001 From: Jongmin Park Date: Mon, 2 Aug 2021 13:36:00 -0400 Subject: [PATCH 002/308] new updates --- .../.clsm_ensupd_upd_routines.F90.swo | Bin 0 -> 24576 bytes .../clsm_ensupd_enkf_update.F90 | 40 +++ .../clsm_ensupd_upd_routines.F90 | 270 ++++++++++++------ 3 files changed, 222 insertions(+), 88 deletions(-) create mode 100644 src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/.clsm_ensupd_upd_routines.F90.swo diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/.clsm_ensupd_upd_routines.F90.swo b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/.clsm_ensupd_upd_routines.F90.swo new file mode 100644 index 0000000000000000000000000000000000000000..502bc8fc30b7dea6e14664da515bbb1fb6442337 GIT binary patch literal 24576 zcmeHPYmgk(bsk~GU;{Q5gsQ~l_>NNY&d9r(nH54}%|aIKu8`2~%DXEbv2oMe-80i{ zPxq+1N2^s_Cb7%JA+G$$4_AmQ4_96;n^Y2#5W8#=oU&ah9Iz7zVB!bHiXl!U1F<0l zu=AbU=k|2>_UtZ(KX!GOKK0B!_ndp~xvxIw^z2go+JiG<@2*QqxGpG_&U|Ex{;|iN z-}1e4N~N2-y1%@qPLy>o(+&*pxaIF|tXr*AYjvAJr)IiKyGLs*ymnw}Zox72pceQ> zZNJy)damV$L0qmK@NJXIqY~Xk-N5ejiw!5}XqFrFx~4|(yD(Vv#y75ykIP*|X_Kw*Kx0)+(%3ltV8EKpcr z6BY=&drG&U-dSAN;`^4&{YQM+T;9ykf5`MMmw!1!e~IYBpG9jTKh>|HpKn=^x0@pJ)0BrvD&A|6iuhGQIPf=!25~9Mcz={+SH@S*E|2>2KJY z=KlfHRsV0x(7(_0>zV(h4E=wYt}*@S&!pu)!}P;U|C1zB|GW7pu`fberWQP7y83m|2gUy+(_N;2GDClY>9;cd=U$)Y|4yd;KgiJkgX!;P{&UVv^PggR zkLhNH{%xkK@%w6q{y5W@ng5s0OUwTj)0KTbnV~<%bT$4LouB6aCeuxp?`P=WVEPi% zAIi|b&h(p@zV8ju2W9`SF}CnSRy1uz!_`)>*mzl0J|E(GN{Y-b5{zQh( z+iB^oOkcPtEuV{vTVa910)+(%3ltV8EKpdWu)r&{fQ|?HA;@@`9t81Bs{H@Y;`!GH zy1=`D8-VM9eZU@I3-A=4!A}F920jS96SxYv5;zxl7(T!s0UmG^m--+@1KC-6St5O6W@9DJzn1NQ(Q214K%Fb=#9cm_V&)4<)pp8cq1@-`2fcxNR+zwbk1Go^_27Ch#xc3A10k;DdFasO{E(RV)JmMbUZs0e7qd*xr zjd6Jdpz(Q##%Pn5h%Q49jkad!j-gF2mev-w+Tk#l=HA|x!xMJbWf6HifoD5f$FqY0 z%@I#8umru!p9SK`T2FX;JA%{pN?THtysgKFeUj|G!5(s&)bjRMV0 z%gNzbN14&i%KYMtc3k%Zr9xEFvO;ZfDMy%WoBvbxh*;LMNKysW5H-=Y{1D%zQSs7@ z{65gMgM`>OYc_bBzSq$lJ#;)b*+ghNme#`SIqP>Oo)4s!5k)Jnp)BD;(aZ>qx8rjWu+>0V$0E_ z(WI1@r~47`k=j9C3rXFTa?!l*w}f&UhNzgVnJWqU<_g2SYI?q5sd0!$bkeu+UfKZ7 z@Q72+Q)hp&ZLz<+iiG`nujQ$W7F1MW8L;KMU)DiRjk+0w@(aEAiZz&RhVAXCT1tJ zqeqTR&0jTlbaql(oSL4FpDLJqc<#C+Id}TSvtcdI#KP>{b$Lu#9TK|Ii5|te zVFrctEP;*F@mlM)6!Szoe9*NF+X^(dllNGcu$x@1i8qW}j<>Y-7|5UCu7~xiYoX_8 zEz7lh+bFSQrf})z6h{xKzw1^`C@w#OXLB6=r6iw4cr_nDXLTpNmIp1RnTaEZwIc^r z59QbSiOGXU7dFy39vaEBcyRyJMjU-@CCh&7H`v9(AaC=_ADY?uiP_18si{fmOGE7X znyv&%K89DF>dJZ=7#MDT>d=BTWR2IHv8*K-hSfef`y1uA4qT-$_!nP%* z+`#HALCQ6{)6rdlO*gcBv0{g9NtdUDJX@vzA-raD#KEiW!jz9SXdrCc0kJ_5&kc3k z4TO%54xVFa7Y2t2dP~ZEKy^J7x{vN!mT8$H^h)IaQ?Btvfc$@ze|Z7^{bzu?0Ez>2 z0P_3mzz^Zue**Xu;6niU{#O9wz|R7w;Nw3IdG1;TQe1@v3JVk#C@fG|ps+w;fx-fX1qutisum~C5mhYoQyGj015c=?#Lbyz5>bUJ8!C{$7nAA@Mt1cY1 z&^81@43>XfmtIvQgjDagR|6Y?n54L2s67%`A+fM^BcU)eJUSITnClCKgN<)8gfFU8 zx9_t>c8X%ph_P41EdA7Z7&nTp&>gJ|%ZLaVV~g*uiv_DIEnXr=H1vo@UUCR;l)OJG znmKY%JD{V3zStgXrZu;NL0>}72*1QOh1v6Mw*@^ACbXgfqmH$8$19a+;_Q6I7sTM7 z<(kQk<45J8w%i#ttrm!~2HkMM-j1N3jBEOm2b;)<#eu2WsriHZwW;~}x%pvnQ11+j zA#D z%^Qa$7aV*lfLb?-%E)E)vCHa_-hC~kf=Y|!4w|b_vo+SC3Y{wQa};*0bD3^Z+&;qstW#9tfjldS*dF1c!16<(E zz!~K0e-AhWyoB8RbHFL!qrf~c3G4&*0$YJ6(MRg%$AIgB{lJyL6~G<9ZvwXgD?k^R z2BrW3d>uCWUEn(4BH#>i_NRe+fjfb}1X_Rwycsx+-2Exw_ks5UzXH4+*a@5mYy}?M z66N+kj5}Q-y5#((IDBAH97p3=WrfL`xy2#164z!?2&+?6Kd3aSm@h+Nuxz_Ss*bwP zs)kiZ^F($vs$mGtd7=qqnw<#7$at+aGYRPsD-=e7)@K?_AisXLR3a)82K7(uj7puA>{+f4aVft-6Qh(nX#|N5#r^w1?Omwl+b3g+f?V zN@;093Fht5M28*9eQ^|hGkQVjb?lSa8)!4b`omsfM%Cqy7)cv!YdhP)d(0*#fuRj|u(jl{}Clc0?>Yc}209UL!7qd}k&DTL_> zSF^?&WAaSkavB{qfR;(8gSbM}s}xUkV~eA?bR7zKQlg)#$M#CpQgd)v>8|D^HJ+ZP zlmv{YA4IH8PjG#*B!c&Ou~x7pMereqQgzKGY&}3gT1332xR;w;Oi3-$YDX(b=_Btt zy>61U9+hSaam+@!Ps&MRpzs|D2zmHYO0+UIj3KS&B~sTFB->{N)vDz+F8O$k$77}H zL@QfzmxXO&iQ3Io8GGgd76&Iq^!i0W!DKux;V=!tXeQB#jY(LN{MoMl_&trp#io}- zw-DM^%dx|g3$StYK9lSi&2^OU15s`+ClaI<%Wz_`NW}+lXF}~~4Lq2jkxDcKsqJiL zZt~!QSlB-uS-3p@YF<*m@*?)Ccn1~8s38M@Eeqoy@NA&t*@Kd}YKNq47Q3t>yPiyM zVCbgY<>^Qu|K*)AF}iQ$P|q0|t&cXw#55jfWe0gL9g8Zzn*AAeep{arA!HI?GIi8lJCuSaPP^@oZ?bZy3&k*c7&x<_+4xkFNk-AtCCdc0Ec z5|ZIp+~Kk64nF0^#R5HEM})l~?Chs#RV$EyD^EyhTtcLjkW2eQC@)%~3h|XMWR&PB zA$wlFkj5Gzmt=&Ls78F{se&?0)wC+R`%)ruDHcH=^2ErzbEZe5eKC@}v6Lv|omQsN zmlBaPBMl!Y;PhOqSbrVjXPl&R`f3^hwnrZ`po!;wK<>EiBfgW^$+OiX#hvdKvMSTR^o8lYFKfbJTnzn`T$m?B#YiMs|?fv^ENU)9a7SHSGLIBGqU8tCtvW2w|_X6o4hizN-4H7 zPJ?Tvd85zFoSv`&Axu zBgve$Nup`mr`B>uTNVq5z6_K=Thv+!(PqXHa<;C73bZ?|6%cJyEMUN{RYBU{cDp^i zC=w4Gg{Pvo1L7jBW4pbeD*gXY!CyTEpO*apN$H7}NVv*``!`Yw+6OKtF9*{H(* zM@E5;b@=-!b=hrIb>)44N`Y&hjJhzO0_$8uU?{-ve^xC&)f9pesvKtU+g>yNsgrEh za)LOD8te08Hr0Qai5zTYR_?=iyfV3=w4$OCH(SYY?nL%a4-Cz7Ohu{=%f4jBD&1TB zJS0b^GFU2nNg9=>0=%|QA!-Ueliloal_F~N)iIIjfpKMsjp7>_)Oo z&_p5yw18fT?suoQVu3W=;FJ%k!&hEy2m*hlZ*SFtoWWU}i1MTbpBM6@o~e)wQlkAp zjo!*mgObuf-tA_NDb?h>LRj5^Z}&F5w>i@ zD56T~G1+mMh^{pqPY)4Bq?h!oYq}>YsknaMGpts3ATQmskh{oEy?Cm{GnL}>RkZ`a zz*&y6UKI<}l@-hoBruNkYzW87Mik6MO5#`#2?mbKQZ?jmDdRw$!t9Y#C#5-po%VPG zp-$>lDP^_Pw;>r)(-6LdQbWTVbQKBJ$e3~cC`6YMxj{H}!Zc;T7D)pcy2CFyhlUg8 zAa*HLTs}@o@f@F=4Zkxpu-Pfn*Gh$cqdbWyQ{rCcah1Ik)$%-Wk=N2ON_gGLj)_zXv^HV`u%CdfRSBZ zmJ=N{%&4sFcwU#5hSzJgqh*3b69VNBY~atx_pk@|<0;HDk9YY;mXM!|BK;K5SJ4sD zEUHDHq8BdII~-6{eN;1MP^K&u@QW*}JWQNdQw5cN+>U+=C6l%)_{1iS2jrDJ&X)ck DA0yCx literal 0 HcmV?d00001 diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 index 539ce00d..ae66089b 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 @@ -1368,6 +1368,46 @@ subroutine apply_enkf_increments( N_catd, N_ens, update_type, & end do cat_progn_has_changed = .true. + + case(11) select_update_type ! snow update !jpark50 + if (logit) write (logunit,*) 'applying Snow data increments' + + if ( date_time%hour /= 0 .and. & + date_time%min /= 0 .and. & + date_time%sec /= 0 ) then + + if (logit) write (logunit,*) 'no application of increments at this time' + cat_progn_has_changed = .false. + return + + end if + + cat_progn_has_changed = .true. ! conservative initialization + if (logit) write (logunit,*) 'apply_enkf_increments(): applying asnow increments' + if (logit) write (logunit,*) 'entering do loop' + + !Rule-based snow SCF update + do n=1,N_catd ! for each tile + + do n_e=1,N_ens ! for each ensemble member + + do i=1,N_SNOW ! for each snow layer + + cat_progn(n,n_e)%wesn(i) = & + cat_progn(n,n_e)%wesn(i) + cat_progn_incr(n,n_e)%wesn(i) + + cat_progn(n,n_e)%sndz(i) = & + cat_progn(n,n_e)%sndz(i) + cat_progn_incr(n,n_e)%sndz(i) + + cat_progn(n,n_e)%htsn(i) = & + cat_progn(n,n_e)%htsn(i)+ cat_progn_incr(n,n_e)%htsn(i) + end do + + end do + end do + cat_progn_has_changed = .true. + + case default diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index e83d1274..8f1bb614 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -101,7 +101,8 @@ module clsm_ensupd_upd_routines use catch_constants, ONLY: & N_snow => CATCH_N_SNOW, & - N_gt => CATCH_N_GT + N_gt => CATCH_N_GT, & + wemin !jpark50 use StieglitzSnow, ONLY: & StieglitzSnow_calc_asnow @@ -754,7 +755,6 @@ subroutine get_cat_progn_ens_avg(N_catd, N_ens, cat_progn, cat_progn_ensavg) type(cat_progn_type), dimension(N_catd,N_ens), intent(in) :: cat_progn type(cat_progn_type), dimension(N_catd), intent(out) :: cat_progn_ensavg - ! locals integer :: i, n_e @@ -875,6 +875,7 @@ subroutine assemble_obs_cov(N_obs, N_obs_param, obs_param, Observations, Obs_cov ! bug fix ! GDL+reichle, 17 Oct 2014 !Obs_cov(i,j) = Observations(i)%obsvar * fac + !Obs_cov(i,j) = Observations(i)%obsvar * fac Obs_cov(i,j) = sqrt(Observations(i)%obsvar * Observations(j)%obsvar) * fac Obs_cov(j,i) = Obs_cov(i,j) @@ -952,7 +953,6 @@ subroutine get_obs_pred( & real, dimension(:,:), pointer :: Obs_pred_l ! output logical, intent(in), dimension(N_obsl), optional :: obsbias_ok - real, intent(in), optional :: fcsterr_inflation_fac ! -------------------------------------------------------------------------------- @@ -990,7 +990,7 @@ subroutine get_obs_pred( & logical :: get_tp_l logical :: get_Tb_l, get_Tb_lH logical :: get_FT_l, get_FT_lH - + logical :: get_asnow_l, get_asnow_l !jpark50 2021_07_27 type(grid_def_type) :: tile_grid_lH integer, dimension(N_obs_param) :: ind_obsparam2Tbspecies @@ -1105,7 +1105,8 @@ subroutine get_obs_pred( & get_tp_l = .false. get_FT_l = .false. get_Tb_l = .false. - + get_asnow_l = .false. !jpark50 Snow cover assimilation + ! get_*_lH : directly match observed fields get_sfmc_lH = .false. @@ -1113,6 +1114,7 @@ subroutine get_obs_pred( & get_tsurf_lH = .false. get_FT_lH = .false. get_Tb_lH = .false. + get_asnow_lH = .false. !jpark50 Snow cover assimilation ! loop through obs_param b/c obs on local proc may not reflect all obs @@ -1167,6 +1169,10 @@ subroutine get_obs_pred( & get_Tb_lH = .true. + case('asnow') !jpark50 Snow cover assimilation + get_asnow_l = .true. + get_asnow_lH = .true. + case default call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'unknown obs_param%varname') @@ -1336,7 +1342,13 @@ subroutine get_obs_pred( & call catch_calc_FT( N_catl, asnow, tp_l(1,:), tsurf_excl_snow, FT_l(:,n_e)) end if - + + if (get_asnow_l) then !jpark50 + call StieglitzSnow_calc_asnow( N_snow, N_catl, & + catprogn2wesn(N_catl,cat_progn(:,n_e)), & + asnow) + end if + if (get_Tb_l) then ! convert Catchment model variables into inputs suitable for the mwRTM @@ -1365,6 +1377,17 @@ subroutine get_obs_pred( & select case (RTM_id) + case (1) + ! + ! %RTM_ID = ID of radiative transfer model to use for Tb forward modeling + ! (subroutine get_obs_pred()) + ! 0 = none + ! 1 = tau-omega model as in De Lannoy et al. 2013 (doi:10.1175/JHM-D-12-092.1) + ! 2 = same as 1 but without Pellarin atmospheric corrections + ! 3 = ... + + select case (RTM_id) + case (1) ! bug fix: previously, mwRTM_get_Tb() was called without specifying the @@ -1452,6 +1475,7 @@ subroutine get_obs_pred( & if (get_rzmc_lH) allocate(rzmc_lH( N_catlH, N_ens)) if (get_tsurf_lH) allocate(tsurf_lH(N_catlH, N_ens)) if (get_FT_lH) allocate(FT_lH( N_catlH, N_ens)) + if (get_asnow_lH) allocate(asnow_lH(N_catlH, N_ens)) !jpark50 if (get_Tb_lH) allocate(stemp_lH(N_catlH, N_ens)) if (get_Tb_lH) allocate(Tb_h_lH( N_catlH,N_TbuniqFreqAngRTMid,N_ens)) if (get_Tb_lH) allocate(Tb_v_lH( N_catlH,N_TbuniqFreqAngRTMid,N_ens)) @@ -1459,16 +1483,16 @@ subroutine get_obs_pred( & #ifdef LDAS_MPI ! count number of fields that need to be communicated (N_fields), allocate as needed - + ! added get_asnow_lH at the function jpark50 call get_obs_pred_comm_helper( N_catl, N_ens, N_TbuniqFreqAngRTMid, & - get_sfmc_lH, get_rzmc_lH, get_tsurf_lH, get_FT_lH, get_Tb_lH, N_fields) + get_sfmc_lH, get_rzmc_lH, get_tsurf_lH, get_FT_lH, get_asnow_lH, get_Tb_lH, N_fields) ! allocate and assemble tile_data_l - + ! added get_asnow_lH at the function jpark50 if (allocated(tile_data_l)) deallocate(tile_data_l) allocate(tile_data_l(N_catl,N_fields,N_ens)) call get_obs_pred_comm_helper( N_catl, N_ens, N_TbuniqFreqAngRTMid, & - get_sfmc_lH, get_rzmc_lH, get_tsurf_lH, get_FT_lH, get_Tb_lH, N_fields, & + get_sfmc_lH, get_rzmc_lH, get_tsurf_lH, get_FT_lH, get_asnow_lH, get_Tb_lH, N_fields, & option=1, tile_data=tile_data_l, & sfmc=sfmc_l, rzmc=rzmc_l, tsurf=tsurf_l, FT=FT_l, stemp=stemp_l, & Tb_h=Tb_h_l, Tb_v=Tb_v_l ) @@ -1480,11 +1504,11 @@ subroutine get_obs_pred( & N_catlH, tile_data_lH=tile_data_lH ) ! read out sfmc, rzmc, etc. from tile_data_lH - + ! addded asnow option at here call get_obs_pred_comm_helper( N_catlH, N_ens, N_TbuniqFreqAngRTMid, & - get_sfmc_lH, get_rzmc_lH, get_tsurf_lH, get_FT_lH, get_Tb_lH, N_fields, & + get_sfmc_lH, get_rzmc_lH, get_tsurf_lH, get_FT_lH, get_asnow_lH, get_Tb_lH, N_fields, & option=2, tile_data=tile_data_lH, & - sfmc=sfmc_lH, rzmc=rzmc_lH, tsurf=tsurf_lH, FT=FT_l, stemp=stemp_lH, & + sfmc=sfmc_lH, rzmc=rzmc_lH, tsurf=tsurf_lH, asnow=asnow_l, FT=FT_l, stemp=stemp_lH, & Tb_h=Tb_h_lH, Tb_v=Tb_v_lH ) ! clean up @@ -1497,6 +1521,7 @@ subroutine get_obs_pred( & if (get_rzmc_lH) rzmc_lH = rzmc_l if (get_tsurf_lH) tsurf_lH = tsurf_l if (get_FT_lH) FT_lH = FT_l + if (get_asnow_lH) asnow_lH = asnow_l !jpark50 if (get_Tb_lH) stemp_lH = stemp_l if (get_Tb_lH) Tb_h_lH = Tb_h_l if (get_Tb_lH) Tb_v_lH = Tb_v_l @@ -1679,7 +1704,10 @@ subroutine get_obs_pred( & case ('FT') tmp_data(1:N_tmp) = FT_lH( ind_tmp(1:N_tmp), n_e ) - + + case ('asnow') + tmp_data(1:N_tmp) = asnow_lH( ind_tmp(1:N_tmp), n_e) + case('Tb') ! start with QC based on model *soil* temperature, motivated by RFI @@ -1861,6 +1889,7 @@ subroutine get_obs_pred( & if (get_rzmc_lH) deallocate(rzmc_lH) if (get_tsurf_lH) deallocate(tsurf_lH) if (get_FT_lH) deallocate(FT_lH) + if (get_asnow_lH) deallocate(asnow_lH) !jpark50 if (get_Tb_lH) deallocate(stemp_lH) if (get_Tb_lH) deallocate(Tb_h_lH) if (get_Tb_lH) deallocate(Tb_v_lH) @@ -1964,7 +1993,7 @@ end subroutine get_obs_pred subroutine get_obs_pred_comm_helper( & N_cat, N_ens, N_Tb, get_sfmc, get_rzmc, get_tsurf, get_FT, get_Tb, & - N_fields, option, tile_data, sfmc, rzmc, tsurf, FT, stemp, Tb_h, Tb_v ) + N_fields, option, tile_data, sfmc, rzmc, tsurf, FT, asnow, stemp, Tb_h, Tb_v ) ! bundle/unbundle individual fields into/from single array for more ! efficient communication across processors @@ -1982,7 +2011,7 @@ subroutine get_obs_pred_comm_helper( & integer, intent(in) :: N_cat, N_ens, N_Tb - logical, intent(in) :: get_sfmc, get_rzmc, get_tsurf, get_FT, get_Tb + logical, intent(in) :: get_sfmc, get_rzmc, get_tsurf, get_FT, geta_asnow, get_Tb !jpark50 integer, intent(inout) :: N_fields @@ -1991,7 +2020,7 @@ subroutine get_obs_pred_comm_helper( & real, dimension(N_cat,N_fields,N_ens), intent(inout), optional :: tile_data real, dimension(N_cat, N_ens), intent(inout), optional :: sfmc, rzmc - real, dimension(N_cat, N_ens), intent(inout), optional :: tsurf, FT, stemp + real, dimension(N_cat, N_ens), intent(inout), optional :: tsurf, FT, asnow, stemp !jpark50 real, dimension(N_cat,N_Tb, N_ens), intent(inout), optional :: Tb_h, Tb_v ! ----------------------------------- @@ -2022,6 +2051,7 @@ subroutine get_obs_pred_comm_helper( & if ( ((get_sfmc ) .and. (.not. present(sfmc ))) .or. & ((get_rzmc ) .and. (.not. present(rzmc ))) .or. & ((get_tsurf) .and. (.not. present(tsurf))) .or. & + ((get_asnow) .and. (.not. present(asnow))) .or. & !jpark50 ((get_FT) .and. (.not. present(FT ))) .or. & ((get_Tb) .and. (.not. present(stemp))) .or. & ((get_Tb) .and. (.not. present(Tb_h ))) .or. & @@ -2080,6 +2110,16 @@ subroutine get_obs_pred_comm_helper( & if (opt==2) FT = tile_data(1:N_cat,k,1:N_ens) end if + + if (get_asnow) then !jpark50 + + k = k+1 + + if (opt==1) tile_data(1:N_cat,k,1:N_ens) = asnow + + if (opt==2) asnow = tile_data(1:N_cat,k,1:N_ens) + + end if if (get_Tb) then @@ -3381,7 +3421,7 @@ subroutine cat_enkf_increments( & Observations, Obs_pred, Obs_pert, & cat_param, & xcompact, ycompact, fcsterr_inflation_fac, & - cat_progn, cat_progn_incr ) + cat_progn, cat_progn_incr, met_force ) ! get increments for Catchment prognostic variables ! @@ -3389,7 +3429,7 @@ subroutine cat_enkf_increments( & ! reichle, 27 Jul 2005 ! reichle, 18 Oct 2005 - return increments (instead of updated cat_progn) ! reichle, 17 Oct 2011 - added "l2f" for revised (MPI) analysis - ! + ! jpark50, 28 Jul 2020 - added metforce at the subroutine for 1D snow assimilation ! -------------------------------------------------------------- ! IMPORTANT: @@ -3500,7 +3540,15 @@ subroutine cat_enkf_increments( & real, dimension( N_catd) :: tp1_ensavg type(obs_param_type) :: this_obs_param - + + !jpark50 + real, parameter:: cpw = 2065.22 !ice specific heat capacity @ 0C [J/kg/K] + real, parameter:: model_threshold = 0.40 + real, parameter:: obs_threshold = 0.25 + real, parameter:: wesn_added = 12.0 ! mm of SWE + real, parameter:: eps = 1.e-4 + real, parameter:: small = 1.e-20 + ! ----------------------------------------------------------------------- if (logit) write (logunit,*) & @@ -4000,7 +4048,120 @@ subroutine cat_enkf_increments( & end do ! ---------------------------------- - + case (11) select_update_type ! 1d snow (asnow) analysis; MODIS snow cover fraction jpark50 + !============================================================================= + !jpark50: 28-Jul-2021: For asnow update: + !The increment defined here is a direct replacement; there is no use of EnkF + !============================================================================= + if (logit) write (logunit, *) 'get 1d snow(asnow) increments; MODIS SCF' + + do n_e=1,N_ens + call StieglitzSnow_calc_asnow(N_snow, N_catl, & + catprogn2wesn(N_catl, cat_progn(:,n_e)), & + asnow) + end do + + !identify the species ID number of interest + N_select_varnames = 1 + select_varnames(1) = 'asnow' + + call get_select_species( & + N_select_varnames, select_varnames(1:N_select_varnames), & + N_obs_param, obs_param, N_select_species, select_species ) + + !Rule-based snow SCF update + !loop through all tiles and compte increments + + do kk=1,N_catd + + ! find observations for catchment n + select_tilenum(1) = l2f(n) + call get_ind_obs( & + N_obs, Observations, & + 1, select_tilenum, & + N_select_species, select_species(1:N_select_species), & + N_selected_obs, ind_obs ) + + if (N_selected_obs > 0) then + do n_e=1:N_ens ! for each ensemble member + + if(asnow <= Observations(ind_obs(1)%value*model_threshold) then + if (logit) write (logunit,*) 'Add_snow_section: ',& + 'MODIS_SCF = ', observations(ind_obs(1))%value, 'model_SCF = ', asnow + + do i=1,N_SNOW + !a) Snow water equivalent (add equally the snow to all three layers) + cat_progn_incr(kk, n_e)%wesn(i) = & + ( observations(ind_obs(1))%value - & + asnow/model_threshold ) * (wesn_added/float(N_SNOW)) + + !b) snow depth + if(cat_progn(kk,n_e)%sndz(i) > eps) then + + !Determine the fractional snow coverage + wesn_sum_old(kk,n_e) = sum( cat_progn(kk,n_e)%wesn) + areasc_old (kk,n_e) = min(wesn_sum_old(kk,n_e)/wemin,1.) + + !Estimate the density of the ld layers of snow + dens_layer = max(cat_progn(kk,n_e)%wesn(i)/ & + (cat_progn(kk,n_e)%sndz(i)*areasc_old(kk,n_e)),rhofs) + + cat_progn_incr(kk,n_e)%sndz(i)=& + cat_progn_incr(kk,n_e)%wesn(i)/dens_layer + else + dens_layer = rhofs + cat_progn_incr(kk,n_e)%sndz(i) = cat_progn_incr(kk,n_e)%wesn(i)/dens_layer + end if + !c) heat content + TSN=min(met_force(kk)%Tair-Tzero_ice, 0.0) + cat_progn_incr(n,n_e)%hstn(i) = (TSN*cpw-ALHM)*cat_progn_incr(kk,n_e)%wesn(i) + end do + + elseif (Observations(ind_obs(1))%value <= obs_threshold) then + if (logit) write (logunit,*) 'Remove snow section: ', & + 'MODIS_SCF = ', observations(ind_obs(1))%value, 'model_SCF = ', asnow + + do i=1,N_SNOW + cat_progn_incr(kk,n_e)%wesn(i) = & + -cat_progn(n,n_e)%wesn(i)*(1-observations(ind_obs(1))%value/obs_threshold ) + + !b) snow depth + if (cat_progn(kk,n_e)%sndz(i) > eps) then + wesn_sum_old(kk,n_e)=sum(cat_progn(kk,n_e)%wesn) + areasc_old(kk,n_e)=min(wesn_sum_old(kk,n_e)/wemin,1.) + + !Estimate the density of the old layers of snow + dens_layer = max( cat_progn(kk,n_e)%wesn(i)/& + (cat_progn(kk,n_e)%sndz(i)*areasc_old(kk,n_e)),rhofs) + + cat_progn_incr(kk,n_e)%sndz(i)=& + cat_progn_incr(kk,n_e)%wesn(i)/dens_layer + + else + dens_layer = rhofs + cat_progn_incr(kk,n_e)%sndz(i) = cat_progn_incr(kk,n_e)%wesn(i)/dens_layer + end if + !c) heat content + TSN=min(met_force(kk)%Tair-Tzero_ice, 0.0) + cat_progn_incr(kk,n_e)%htsn(i) = -(TSN*cpw-ALHM)*cat_progn_incr(kk,n_e)%wesn(i) + end do + + else + + if (logit) write (logunit, *) 'No_add_No_removal_section: ', & + 'MODIS_SCF = ', observations(ind_obs(1))%value, 'model_SCF = ',cat_diagn(n)%asnow + + do i=1,N_snow + cat_progn_incr(kk,n_e)%wesn(i) = 0.0 + cat_progn_incr(kk,n_e)%sndz(i) = 0.0 + cat_progn_incr(kk,n_e)%htsn(i) = 0.0 + end do + end if + + end do + end if + end do + case (7) select_update_type ! 3d Tskin/ght(1) analysis; tskin obs ! update each tile separately using all observations within @@ -5152,70 +5313,3 @@ end subroutine dist_km2deg ! ! ! ! ------------------------------------------------------------------- ! -! implicit none -! -! integer, intent(in) :: N_ens, N_obs, N_catd -! -! type(cat_param_type), dimension(N_catd), intent(in) :: cat_param -! -! type(obs_type), dimension(N_obs), intent(in) :: Observations -! -! real, dimension(N_obs,N_ens), intent(inout) :: Obs_pert -! -! ! ---------------------------------------------------------------- -! -! ! local variables -! -! integer :: i, n -! -! real :: min_pert, max_pert -! -! ! --------------------------------------------------------------- -! -! do i=1,N_obs -! -! select case (Observations(i)%species) -! -! case (1,2,4,7,8,9,10,11,12) -! -! ! ae_l2_sm_a, ae_l2_sm_d, RedArkOSSE_sm, RedArkOSSE_CLSMsynthSM, -! ! VivianaOK_CLSMsynthSM, ae_sm_LPRM_a_C, ae_sm_LPRM_d_C, -! ! ae_sm_LPRM_a_X, ae_sm_LPRM_d_X -! -! min_pert = -Observations(i)%obs -! max_pert = cat_param(Observations(i)%tilenum)%poros - & -! Observations(i)%obs -! -! do n=1,N_ens -! -! Obs_pert(i,n) = max( Obs_pert(i,n), min_pert ) -! Obs_pert(i,n) = min( Obs_pert(i,n), max_pert ) -! -! end do -! -! case (3) ! isccp_tskin_gswp2_v1 -! -! ! no constraints -! -! case default -! -! call stop_it('check_obs_pert(): unkown obs species.') -! -! !write (logunit,*) 'check_obs_pert(): unkown obs species. STOPPING.' -! !stop -! -! end select -! -! end do -! -! end subroutine check_obs_pert - - ! ********************************************************************** - ! ********************************************************************** - ! ********************************************************************** - -end module clsm_ensupd_upd_routines - - -! **** EOF ****************************************************** - From ca7333950a68069914404f59ec676f9d44eb2e94 Mon Sep 17 00:00:00 2001 From: Jongmin Park Date: Fri, 10 Sep 2021 15:59:21 -0400 Subject: [PATCH 003/308] Debugging completed (still need to include MODIS observation reader) --- .../GEOS_LandAssimGridComp.F90 | 4 +- .../clsm_ensupd_enkf_update.F90 | 20 ++-- .../clsm_ensupd_upd_routines.F90 | 105 ++++++++++-------- 3 files changed, 72 insertions(+), 57 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 index b709351c..d96ea467 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 @@ -1830,8 +1830,8 @@ subroutine RUN ( GC, IMPORT, EXPORT, CLOCK, RC ) if (fresh_incr) then ! apply EnKF increments (incl. call to catch_calc_soil_moist but not to recompute_diagS()) - call apply_enkf_increments( N_catl, NUM_ENSEMBLE, update_type, cat_param, & - cat_progn_incr, cat_progn ) + call apply_enkf_increments(date_time_new, N_catl, NUM_ENSEMBLE, update_type, cat_param, & + cat_progn_incr, cat_progn, cat_diagS ) end if ! fresh_incr diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 index ae66089b..dc138cdd 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 @@ -46,6 +46,7 @@ module clsm_ensupd_enkf_update use catch_types, ONLY: & cat_param_type, & cat_progn_type, & + cat_diagS_type, & catprogn2wesn, & catprogn2htsn, & catprogn2ghtcnt, & @@ -158,7 +159,7 @@ subroutine get_enkf_increments( & cat_progn_incr, fresh_incr, & N_obsf, N_obsl, Observations_l, & N_adapt_R, obs_pert_adapt_param, Pert_adapt_R, & - Obs_pert ) + Obs_pert) ! ------------------------------------------------------------- @@ -308,8 +309,9 @@ subroutine get_enkf_increments( & type(cat_progn_type), allocatable :: tmp_cat_progn_ana(:) type(cat_progn_type), allocatable :: cat_progn_incr_f(:), cat_progn_incr_ana(:,:) type(cat_progn_type), allocatable :: recvBuf(:) - - ! Obs related + type(cat_diagS_type), dimension(nTiles_ana, N_ens), allocatable :: cat_diagS(:) !jpark50 + +! Obs related integer :: nObs_ana integer :: nObsAna_vec(numprocs) integer :: N_obsf_assim, N_obsl_assim @@ -1054,7 +1056,8 @@ subroutine get_enkf_increments( & Obs_pert_tmp, & cat_param_ana, & xcompact, ycompact, fcsterr_inflation_fac, & - cat_progn_ana, cat_progn_incr_ana) + cat_progn_ana, cat_progn_incr_ana, & + met_force, cat_diagS) call cpu_time(t_end) @@ -1248,8 +1251,8 @@ end subroutine addUniqueInts ! ******************************************************************** - subroutine apply_enkf_increments( N_catd, N_ens, update_type, & - cat_param, cat_progn_incr, cat_progn ) + subroutine apply_enkf_increments( date_time, N_catd, N_ens, update_type, & + cat_param, cat_progn_incr, cat_progn, cat_diagS ) implicit none @@ -1265,10 +1268,13 @@ subroutine apply_enkf_increments( N_catd, N_ens, update_type, & type(cat_progn_type), dimension(N_catd,N_ens), intent(in) :: cat_progn_incr type(cat_progn_type), dimension(N_catd,N_ens), intent(inout) :: cat_progn + + type(date_time_type), intent(in) :: date_time !jpark50 + type(cat_diagS_type), dimension(N_catd,N_ens), intent(in) :: cat_diagS !jpark50 ! ----------------- - integer :: n, n_e + integer :: n, n_e, i logical :: cat_progn_has_changed diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index 8f1bb614..f7b86249 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -12,8 +12,9 @@ module clsm_ensupd_upd_routines use MAPL_ConstantsMod, ONLY: & MAPL_TICE, & MAPL_RADIUS, & - MAPL_PI - + MAPL_PI, & + MAPL_ALHF !jpark50 + use LDAS_ensdrv_Globals, ONLY: & logit, & logunit, & @@ -50,6 +51,7 @@ module clsm_ensupd_upd_routines catprogn2wesn, & catprogn2htsn, & catprogn2ghtcnt, & + cat_diagS_type, & assignment (=), & operator (+), & operator (/) @@ -101,11 +103,10 @@ module clsm_ensupd_upd_routines use catch_constants, ONLY: & N_snow => CATCH_N_SNOW, & - N_gt => CATCH_N_GT, & - wemin !jpark50 + N_gt => CATCH_N_GT - use StieglitzSnow, ONLY: & - StieglitzSnow_calc_asnow + use STIEGLITZSNOW, ONLY: & + StieglitzSnow_calc_asnow use LDAS_ensdrv_mpi, ONLY: & numprocs, & @@ -990,7 +991,7 @@ subroutine get_obs_pred( & logical :: get_tp_l logical :: get_Tb_l, get_Tb_lH logical :: get_FT_l, get_FT_lH - logical :: get_asnow_l, get_asnow_l !jpark50 2021_07_27 + logical :: get_asnow_l, get_asnow_lH !jpark50 2021_07_27 type(grid_def_type) :: tile_grid_lH integer, dimension(N_obs_param) :: ind_obsparam2Tbspecies @@ -1018,7 +1019,7 @@ subroutine get_obs_pred( & real, dimension(N_catl,N_ens) :: sfmc_l, rzmc_l real, dimension(N_catl,N_ens) :: tsurf_l, stemp_l - real, dimension(N_catl,N_ens) :: FT_l + real, dimension(N_catl,N_ens) :: FT_l, asnow_l real, dimension(:,:,:), allocatable :: Tb_h_l, Tb_v_l @@ -1037,7 +1038,7 @@ subroutine get_obs_pred( & real, dimension(:,:), allocatable :: sfmc_lH, rzmc_lH real, dimension(:,:), allocatable :: tsurf_lH, stemp_lH - real, dimension(:,:), allocatable :: FT_lH + real, dimension(:,:), allocatable :: FT_lH, asnow_lH real, dimension(:,:,:), allocatable :: Tb_h_lH, Tb_v_lH @@ -1377,17 +1378,6 @@ subroutine get_obs_pred( & select case (RTM_id) - case (1) - ! - ! %RTM_ID = ID of radiative transfer model to use for Tb forward modeling - ! (subroutine get_obs_pred()) - ! 0 = none - ! 1 = tau-omega model as in De Lannoy et al. 2013 (doi:10.1175/JHM-D-12-092.1) - ! 2 = same as 1 but without Pellarin atmospheric corrections - ! 3 = ... - - select case (RTM_id) - case (1) ! bug fix: previously, mwRTM_get_Tb() was called without specifying the @@ -1992,7 +1982,7 @@ end subroutine get_obs_pred ! ***************************************************************** subroutine get_obs_pred_comm_helper( & - N_cat, N_ens, N_Tb, get_sfmc, get_rzmc, get_tsurf, get_FT, get_Tb, & + N_cat, N_ens, N_Tb, get_sfmc, get_rzmc, get_tsurf, get_FT, get_asnow, get_Tb, & N_fields, option, tile_data, sfmc, rzmc, tsurf, FT, asnow, stemp, Tb_h, Tb_v ) ! bundle/unbundle individual fields into/from single array for more @@ -2011,8 +2001,9 @@ subroutine get_obs_pred_comm_helper( & integer, intent(in) :: N_cat, N_ens, N_Tb - logical, intent(in) :: get_sfmc, get_rzmc, get_tsurf, get_FT, geta_asnow, get_Tb !jpark50 - + logical, intent(in) :: get_sfmc, get_rzmc, get_tsurf, get_FT, get_Tb + logical, intent(in) :: get_asnow !jpark50 + integer, intent(inout) :: N_fields integer, intent(in), optional :: option @@ -2059,7 +2050,7 @@ subroutine get_obs_pred_comm_helper( & call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'error 1') end if - if ( (get_sfmc .or. get_rzmc .or. get_tsurf .or. get_FT .or. get_Tb) .and. & + if ( (get_sfmc .or. get_rzmc .or. get_tsurf .or. get_FT .or. get_Tb .or. get_asnow) .and. & (.not. present(tile_data)) & ) then call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'error 2') @@ -3415,13 +3406,13 @@ end subroutine get_obs_pert ! ********************************************************************* subroutine cat_enkf_increments( & - N_ens, N_obs, N_catd, N_obs_param, & + N_ens, N_obs, N_catd, N_obs_param, & update_type, obs_param, & tile_grid_f, tile_coord, l2f, & Observations, Obs_pred, Obs_pert, & cat_param, & xcompact, ycompact, fcsterr_inflation_fac, & - cat_progn, cat_progn_incr, met_force ) + cat_progn, cat_progn_incr, met_force, cat_diagS) ! get increments for Catchment prognostic variables ! @@ -3447,7 +3438,6 @@ subroutine cat_enkf_increments( & ! - reichle, 17 Oct 2011 ! ------------------------------------------------------------------- - implicit none ! inputs @@ -3467,6 +3457,8 @@ subroutine cat_enkf_increments( & real, intent(in), dimension(N_obs,N_ens) :: Obs_pred real, intent(in), dimension(N_obs,N_ens) :: Obs_pert + type(met_force_type), dimension(N_catd), intent(in) :: met_force !jpark50 + type(cat_diagS_type), dimension(N_catd), intent(in) :: cat_diagS !jpark50 type(cat_param_type), dimension(N_catd), intent(in) :: cat_param real, intent(in) :: xcompact, ycompact, fcsterr_inflation_fac @@ -3490,10 +3482,10 @@ subroutine cat_enkf_increments( & real, parameter :: tp1_threshold = -HUGE(1.) ! = 0.2 ! [CELSIUS] - integer :: n, n_e, kk, ii + integer :: n, n_e, kk, ii, i integer :: N_state, N_selected_obs, N_select_varnames, N_select_species - + real :: halo_minlon, halo_maxlon, halo_minlat, halo_maxlat real :: tmp_minlon, tmp_maxlon, tmp_minlat, tmp_maxlat @@ -3541,14 +3533,19 @@ subroutine cat_enkf_increments( & type(obs_param_type) :: this_obs_param - !jpark50 + !jpark50 + real, dimension(N_catd, N_ens) :: wesn_sum_old + real, dimension(N_catd, N_ens) :: areasc_old real, parameter:: cpw = 2065.22 !ice specific heat capacity @ 0C [J/kg/K] real, parameter:: model_threshold = 0.40 real, parameter:: obs_threshold = 0.25 real, parameter:: wesn_added = 12.0 ! mm of SWE real, parameter:: eps = 1.e-4 real, parameter:: small = 1.e-20 - + real, parameter:: rhofs = 150. ! kg/m^3 density of fresh snow + real, parameter:: rhoma = 500. ! kg/m^3 maximum snow density + real, parameter:: wemin = 13. ! kg/m^3 + real :: TSN, dens_layer ! ----------------------------------------------------------------------- if (logit) write (logunit,*) & @@ -4056,8 +4053,8 @@ subroutine cat_enkf_increments( & if (logit) write (logunit, *) 'get 1d snow(asnow) increments; MODIS SCF' do n_e=1,N_ens - call StieglitzSnow_calc_asnow(N_snow, N_catl, & - catprogn2wesn(N_catl, cat_progn(:,n_e)), & + call StieglitzSnow_calc_asnow(N_snow, N_catd, & + catprogn2wesn(N_catd, cat_progn(:,n_e)), & asnow) end do @@ -4082,18 +4079,18 @@ subroutine cat_enkf_increments( & N_select_species, select_species(1:N_select_species), & N_selected_obs, ind_obs ) - if (N_selected_obs > 0) then - do n_e=1:N_ens ! for each ensemble member + if (N_selected_obs == 1) then + do n_e=1,N_ens ! for each ensemble member - if(asnow <= Observations(ind_obs(1)%value*model_threshold) then + if(cat_diagS(kk)%asnow <= Observations(ind_obs(1))%obs * model_threshold) then if (logit) write (logunit,*) 'Add_snow_section: ',& - 'MODIS_SCF = ', observations(ind_obs(1))%value, 'model_SCF = ', asnow + 'MODIS_SCF = ', observations(ind_obs(1))%obs, 'model_SCF = ', cat_diagS(kk)%asnow do i=1,N_SNOW !a) Snow water equivalent (add equally the snow to all three layers) cat_progn_incr(kk, n_e)%wesn(i) = & - ( observations(ind_obs(1))%value - & - asnow/model_threshold ) * (wesn_added/float(N_SNOW)) + ( Observations(ind_obs(1))%obs - & + cat_diagS(kk)%asnow/model_threshold ) * (wesn_added/float(N_SNOW)) !b) snow depth if(cat_progn(kk,n_e)%sndz(i) > eps) then @@ -4113,17 +4110,17 @@ subroutine cat_enkf_increments( & cat_progn_incr(kk,n_e)%sndz(i) = cat_progn_incr(kk,n_e)%wesn(i)/dens_layer end if !c) heat content - TSN=min(met_force(kk)%Tair-Tzero_ice, 0.0) - cat_progn_incr(n,n_e)%hstn(i) = (TSN*cpw-ALHM)*cat_progn_incr(kk,n_e)%wesn(i) + TSN=min(met_force(kk)%Tair-MAPL_TICE, 0.0) + cat_progn_incr(n,n_e)%htsn(i) = (TSN*cpw-MAPL_ALHF)*cat_progn_incr(kk,n_e)%wesn(i) end do - elseif (Observations(ind_obs(1))%value <= obs_threshold) then + elseif (Observations(ind_obs(1))%obs <= obs_threshold) then if (logit) write (logunit,*) 'Remove snow section: ', & - 'MODIS_SCF = ', observations(ind_obs(1))%value, 'model_SCF = ', asnow + 'MODIS_SCF = ', Observations(ind_obs(1))%obs, 'model_SCF = ', cat_diagS(kk)%asnow - do i=1,N_SNOW + do i=1,N_snow cat_progn_incr(kk,n_e)%wesn(i) = & - -cat_progn(n,n_e)%wesn(i)*(1-observations(ind_obs(1))%value/obs_threshold ) + -cat_progn(n,n_e)%wesn(i)*(1-Observations(ind_obs(1))%obs/obs_threshold ) !b) snow depth if (cat_progn(kk,n_e)%sndz(i) > eps) then @@ -4142,14 +4139,14 @@ subroutine cat_enkf_increments( & cat_progn_incr(kk,n_e)%sndz(i) = cat_progn_incr(kk,n_e)%wesn(i)/dens_layer end if !c) heat content - TSN=min(met_force(kk)%Tair-Tzero_ice, 0.0) - cat_progn_incr(kk,n_e)%htsn(i) = -(TSN*cpw-ALHM)*cat_progn_incr(kk,n_e)%wesn(i) + TSN=min(met_force(kk)%Tair-MAPL_TICE, 0.0) + cat_progn_incr(kk,n_e)%htsn(i) = -(TSN*cpw-MAPL_ALHF)*cat_progn_incr(kk,n_e)%wesn(i) end do else if (logit) write (logunit, *) 'No_add_No_removal_section: ', & - 'MODIS_SCF = ', observations(ind_obs(1))%value, 'model_SCF = ',cat_diagn(n)%asnow + 'MODIS_SCF = ', Observations(ind_obs(1))%obs, 'model_SCF = ',cat_diagS(kk)%asnow do i=1,N_snow cat_progn_incr(kk,n_e)%wesn(i) = 0.0 @@ -5313,3 +5310,15 @@ end subroutine dist_km2deg ! ! ! ! ------------------------------------------------------------------- ! +! implicit none +! +! integer, intent(in) :: N_ens, N_obs, N_catd +! +! type(cat_param_type), dimension(N_catd), intent(in) :: cat_param +! +! type(obs_type), dimension(N_obs), intent(in) :: Observations +! +! real, dimension(N_obs,N_ens), intent(inout) :: Obs_pert +! +! ! ---------------------------------------------------------------- +end module clsm_ensupd_upd_routines From e8083f2ec3c730bad7415ad733d791a1d3ac3e61 Mon Sep 17 00:00:00 2001 From: Jongmin Park Date: Thu, 16 Sep 2021 14:02:03 -0400 Subject: [PATCH 004/308] Added 1/2 of the MODIS SCA observation reader --- .../clsm_ensupd_read_obs.F90 | 229 ++++++++++++++++++ 1 file changed, 229 insertions(+) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 0f892960..db57b519 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -83,7 +83,236 @@ module clsm_ensupd_read_obs public :: collect_obs contains + + subroutine read_MODISsca_hdf(& + N_files, fnames, N_data, lon, lat, MODIS_SCA) + + !read snow cover data from daily MOD10C1 data located under lis folder + !writer : jpark50 + !directory: /discover/nobackup/projects/lis/RS_DATA/MODIS_sca/MOD10C1_C6_download/ + ! + ! return ONLY valid data point (excluding no-data-value and CI < 20%) + + implicit none + + integer, intent(in) :: N_files + + character(300), dimension(N_files), intent(in) :: fnames + + integer, intent(out) :: N_data + real, dimension(:), pointer :: lon, lat, MODIS_SCA !output + + !local parameters + integer, parameter:: N_fields = 6 + character(30), dimension(N_fields), parameter:: field_names = (/ & + 'Day_CMG_Snow_Cover', & !1 + 'Day_CMG_Clear_Index', & !2 + 'Day_CMG_Cloud_Obscured', & !3 + 'Snow_Spatial_QA', & !4 + 'Lat', & !5 + 'Lon' /) !6 + + integer, parameter :: nodata = -9999 !note: integer + + ! Quality control step + ! step 1: remove the Snow cover > 100 (e.g., lake, night, inland water, ocean..) + ! step 2: Clear Index (CI): CI > 20% is considered + + !declariations of hdf functions + integer:: hopen, vfstart, vsfatch, vsqfnelt, vsfseek, vsfsfld, vsfread + integer:: vsfdtch, vfend, hclose + + ! declarations of hdf-related parameters and variables + + integer, dimension(N_files) :: file_id, vdata_id + + integer :: status, n_read, n_records, record_pos + + integer, parameter :: num_dds_block = 0 ! only important for writing hdf + integer, parameter :: vdata_ref = 6 + + integer, parameter :: DFACC_READ = 1 ! from hdf.inc + integer, parameter :: FULL_INTERLACE = 0 ! from hdf.inc + + ! local variables + + logical :: must_stop + integer, dimension(N_files) :: N_data_tmp + + integer :: i, j, k, k_off + + integer, dimension(:), allocatable :: Snow_QA + integer, dimension(:), allocatable :: CI_Index, Cloud_index + integer*2, dimension(:), allocatable :: tmpint2vec + real, dimension(:), allocatable :: tmprealvec + + character(len=*), parameter :: Iam = 'read_MOD10C1_hdf' + character(len=400) :: err_msg + + ! determine number of data to be read from each file + + do j=1,N_files + + ! open and "start" hdf file + file_id(j) = hopen( fnames(j), DFACC_READ, num_dds_block ) + status = vfstart(file_id(j)) + + ! select vdata block that contains fields of interest + vdata_id(j) = vsfatch(file_id(j), vdata_ref, 'r') + + ! determine number of records in vdata + status = vsqfnelt(vdata_id(j), n_records) + N_data_tmp(j) = n_records + + end do + + ! allocate pointers (must be deallocated outside this subroutine) + + must_stop = .false. + + if ( associated(lon) .or. associated(lat) .or. associated(MODIS_SCA) ) then + must_stop = .true. + end if + + if (must_stop) then + err_msg = 'output pointers must not be associated/allocated on input.' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + + end if + + allocate(lon(N_data)) + allocate(lat(N_data)) + allocate(MODIS_SCA(N_data)) + + allocate(CI_Index(N_data)) + allocate(Snow_QA(N_data)) + allocate(Cloud_Index(N_data)) + + ! read hdf data into arrays, concatenate data from N_files files + + k_off = 0 + + do j=1,N_files + + allocate(tmprealvec(N_data_tmp(j))) + allocate(tmpint2vec(N_data_tmp(j))) + + do i=1,N_fields + + ! go to start of record (zero-based count) + record_pos = vsfseek(vdata_id(j), 0) + + ! pick the field to be read + status = vsfsfld(vdata_id(j), field_names(i)) + + ! read data + select case (i) + + case (1) + n_read = vsfread( vdata_id(j), tmprealvec, & + N_data_tmp(j), FULL_INTERLACE) + + MODIS_SCA(k_off+1:k_off+N_data_tmp(j)) = tmprealvec + + do k=1,N_data_tmp(j) + + if ( MODIS_SCA(k+k_off) > 100) then + MODIS_SCA(k+k_off) = -1 + end if + end do + + case (2) + + n_read = vsfread( vdata_id(j), tmprealvec, & + N_data_tmp(j), FULL_INTERLACE) + + CI_Index(k_off+1:k_off+N_data_tmp(j)) = tmprealvec + do k=1,N_data_tmp(j) + + if (CI_Index(k+k_off) <20) then + CI_Index(k+k_off) = -1 + end if + end do + case (3) + n_read = vsfread( vdata_id(j) ,tmpint2vec, & + N_data_tmp(j), FULL_INTERLACE) + + Cloud_Index(k_off+1:k_off+N_data_tmp(j)) = tmpint2vec + + case (4) + + n_read = vsfread(vdata_id(j), tmpint2vec, & + N_data_tmp(j), FULL_INTERLACE) + + Snow_QA(k_off+1:k_off+N_data_tmp(j)) = tmpint2vec + + case (5) + + n_read = vsfread(vdata_id(j), tmpint2vec, & + N_data_tmp(j), FULL_INTERLACE) + + lat(k_off+1:k_off+N_data_tmp(j)) = tmpint2vec + + case (6) + n_read = vsfread(vdata_id(j), tmpint2vec, & + N_data_tmp(j), FULL_INTERLACE) + + lon(k_off+1:k_off+N_data_tmp(j)) = tmpint2vec + + case default + + call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'Unknown case') + end select + + if (n_read/=N_data_tmp(j)) & + call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'ERROR reading hdf') + end do + + ! clean up + + deallocate(tmprealvec) + deallocate(tmpint2vec) + + ! close hdf files + + status = vsfdtch(vdata_id(j)) + status = vfend(file_id(j)) + status = hclose(file_id(j)) + + ! prepare next j + k_off = k_off + N_data_tmp(j) + + end do + + ! ------------------------------------- + ! eliminate no-data-values and data that fail initial QC + + j = 0 + + do i=1,N_data + + if ( (MODIS_SCA(i)>0.) .and. & ! any neg is nodata + (CI_Index(i)>20) .and. & ! Ignore obs + (Snow_QA(i)<3) & + ) then + + j=j+1 + + MODIS_SCA(j) = MODIS_SCA(i) + lon(j) = lon(i) + lat(j) = lat(i) + end if + + end do + + N_data = j + + deallocate(CI_Index) + deallocate(Cloud_Index) + deallocate(Snow_QA) + end subroutine read_MODISsca_hdf + ! ***************************************************************** subroutine read_ae_l2_sm_hdf( & From c1c85ee969583690767df828e1d4c6550b01ffae Mon Sep 17 00:00:00 2001 From: Jongmin Park Date: Thu, 30 Sep 2021 11:18:20 -0400 Subject: [PATCH 005/308] Updates on MODIS SCA DA --- .../GEOS_LandAssimGridComp.F90 | 4 +- .../clsm_ensupd_enkf_update.F90 | 17 +- .../clsm_ensupd_read_obs.F90 | 249 +++++++++++++++--- .../clsm_ensupd_upd_routines.F90 | 35 +-- 4 files changed, 248 insertions(+), 57 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 index d96ea467..5f83a652 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 @@ -1830,8 +1830,8 @@ subroutine RUN ( GC, IMPORT, EXPORT, CLOCK, RC ) if (fresh_incr) then ! apply EnKF increments (incl. call to catch_calc_soil_moist but not to recompute_diagS()) - call apply_enkf_increments(date_time_new, N_catl, NUM_ENSEMBLE, update_type, cat_param, & - cat_progn_incr, cat_progn, cat_diagS ) + call apply_enkf_increments( N_catl, NUM_ENSEMBLE, update_type, cat_param, & + cat_progn_incr, cat_progn) end if ! fresh_incr diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 index dc138cdd..f8c930e6 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 @@ -1251,8 +1251,8 @@ end subroutine addUniqueInts ! ******************************************************************** - subroutine apply_enkf_increments( date_time, N_catd, N_ens, update_type, & - cat_param, cat_progn_incr, cat_progn, cat_diagS ) + subroutine apply_enkf_increments( N_catd, N_ens, update_type, & + cat_param, cat_progn_incr, cat_progn) implicit none @@ -1269,9 +1269,9 @@ subroutine apply_enkf_increments( date_time, N_catd, N_ens, update_type, & type(cat_progn_type), dimension(N_catd,N_ens), intent(inout) :: cat_progn - type(date_time_type), intent(in) :: date_time !jpark50 + ! type(date_time_type), intent(in) :: date_time !jpark50 - type(cat_diagS_type), dimension(N_catd,N_ens), intent(in) :: cat_diagS !jpark50 + ! type(cat_diagS_type), dimension(N_catd,N_ens), intent(in) :: cat_diagS !jpark50 ! ----------------- integer :: n, n_e, i @@ -1378,17 +1378,16 @@ subroutine apply_enkf_increments( date_time, N_catd, N_ens, update_type, & case(11) select_update_type ! snow update !jpark50 if (logit) write (logunit,*) 'applying Snow data increments' - if ( date_time%hour /= 0 .and. & - date_time%min /= 0 .and. & - date_time%sec /= 0 ) then + ! if ( date_time%hour /= 0 .and. & + ! date_time%min /= 0 .and. & + ! date_time%sec /= 0 ) then if (logit) write (logunit,*) 'no application of increments at this time' cat_progn_has_changed = .false. return - end if + ! end if - cat_progn_has_changed = .true. ! conservative initialization if (logit) write (logunit,*) 'apply_enkf_increments(): applying asnow increments' if (logit) write (logunit,*) 'entering do loop' diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index db57b519..e9992c3e 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -85,7 +85,8 @@ module clsm_ensupd_read_obs contains subroutine read_MODISsca_hdf(& - N_files, fnames, N_data, lon, lat, MODIS_SCA) + N_files, date_time, fnames, N_data, & + lon, lat, MODIS_SCA) !read snow cover data from daily MOD10C1 data located under lis folder !writer : jpark50 @@ -96,51 +97,65 @@ subroutine read_MODISsca_hdf(& implicit none integer, intent(in) :: N_files - character(300), dimension(N_files), intent(in) :: fnames - integer, intent(out) :: N_data - real, dimension(:), pointer :: lon, lat, MODIS_SCA !output + + real, dimension(:), pointer, allocatable :: lon, lat + real, dimension(:), pointer :: lon_c, lat_c + real, dimension(:), pointer :: MODIS_SCA + + type(date_time_type),intent(in) :: date_time ! loading the UTC hour information to constrain the longitude of MODIS obs. + character(2):: HH !local parameters - integer, parameter:: N_fields = 6 + integer, parameter:: N_fields = 4 character(30), dimension(N_fields), parameter:: field_names = (/ & 'Day_CMG_Snow_Cover', & !1 'Day_CMG_Clear_Index', & !2 'Day_CMG_Cloud_Obscured', & !3 - 'Snow_Spatial_QA', & !4 - 'Lat', & !5 - 'Lon' /) !6 + 'Snow_Spatial_QA'/) !4 integer, parameter :: nodata = -9999 !note: integer ! Quality control step ! step 1: remove the Snow cover > 100 (e.g., lake, night, inland water, ocean..) ! step 2: Clear Index (CI): CI > 20% is considered + ! !declariations of hdf functions integer:: hopen, vfstart, vsfatch, vsqfnelt, vsfseek, vsfsfld, vsfread integer:: vsfdtch, vfend, hclose ! declarations of hdf-related parameters and variables - integer, dimension(N_files) :: file_id, vdata_id - integer :: status, n_read, n_records, record_pos - integer, parameter :: num_dds_block = 0 ! only important for writing hdf - integer, parameter :: vdata_ref = 6 - + integer, parameter :: vdata_ref = 4 integer, parameter :: DFACC_READ = 1 ! from hdf.inc integer, parameter :: FULL_INTERLACE = 0 ! from hdf.inc ! local variables - logical :: must_stop integer, dimension(N_files) :: N_data_tmp - - integer :: i, j, k, k_off - + + ! variables to define latitude and longitude + integer :: i, j, k, k_off, ll, mm, kk + integer :: hh_num, time_index + + integer, parameter :: bin_size = 0.5 + integer, parameter :: XGRID = 3600 + integer, parameter :: YGRID = 7200 + + real :: lat_ind(XGRID) = (/(ll, ll=1, 3600, 1)/) + real :: lon_ind(YGRID) = (/(mm, mm=1, 7200, 1)/) + + !------------------------------------------------------------- + ! UTC | 0000 | 0300 | 0600 | 0900 | 1200 | 1500 | 1800 | 2100 + ! lon | -180 -135| -135 -90| -90 -45 | -45 0| 0 45 | 45 90| 90 135| 135-180 + ! + + real:: lon_subtime(9) = (/(kk, kk=-180, 180, 45)/) + integer, dimension(:), allocatable :: Snow_QA integer, dimension(:), allocatable :: CI_Index, Cloud_index @@ -150,7 +165,15 @@ subroutine read_MODISsca_hdf(& character(len=*), parameter :: Iam = 'read_MOD10C1_hdf' character(len=400) :: err_msg - ! determine number of data to be read from each file + lat_c = (90-bin_size/2)-bin_size*lat_ind + lon_c = (-180+bin_size/2)-bin_size*lon_ind + + do i=1,7200 + lat(3600*(i-1)+1:3600*i)= lat_c + lon(3600*(i-1)+1:3600*i)= lon_c(i) + end do + + ! determine number of data to be read from each file do j=1,N_files @@ -247,18 +270,18 @@ subroutine read_MODISsca_hdf(& Snow_QA(k_off+1:k_off+N_data_tmp(j)) = tmpint2vec - case (5) - - n_read = vsfread(vdata_id(j), tmpint2vec, & - N_data_tmp(j), FULL_INTERLACE) - - lat(k_off+1:k_off+N_data_tmp(j)) = tmpint2vec + ! case (5) + + ! n_read = vsfread(vdata_id(j), tmpint2vec, & + ! N_data_tmp(j), FULL_INTERLACE) - case (6) - n_read = vsfread(vdata_id(j), tmpint2vec, & - N_data_tmp(j), FULL_INTERLACE) + ! lat(k_off+1:k_off+N_data_tmp(j)) = tmpint2vec + + !case (6) + ! n_read = vsfread(vdata_id(j), tmpint2vec, & + ! N_data_tmp(j), FULL_INTERLACE) - lon(k_off+1:k_off+N_data_tmp(j)) = tmpint2vec + !lon(k_off+1:k_off+N_data_tmp(j)) = tmpint2vec case default @@ -269,6 +292,7 @@ subroutine read_MODISsca_hdf(& call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'ERROR reading hdf') end do + ! clean up deallocate(tmprealvec) @@ -285,6 +309,11 @@ subroutine read_MODISsca_hdf(& end do + write(HH, '(i2.2)') date_time%hour + read(HH, '(I10)') hh_num + + time_index = hh_num/3 +1 + ! ------------------------------------- ! eliminate no-data-values and data that fail initial QC @@ -292,9 +321,11 @@ subroutine read_MODISsca_hdf(& do i=1,N_data - if ( (MODIS_SCA(i)>0.) .and. & ! any neg is nodata + if ( (MODIS_SCA(i)>0.) .and. & ! any neg is nodata (CI_Index(i)>20) .and. & ! Ignore obs - (Snow_QA(i)<3) & + (Snow_QA(i)<3) .and. & + (lon(i)>=lon_subtime(time_index)) .and. & + (lon(i) 0) then + + allocate(fnames(N_files)) + + do i=1,N_files + read(10, '(a)') fnames(i) + end do + end if + + close(10, status='delete') + + if (N_files>0) then + + call read_MODISsca_hdf( & + N_files, date_time, fnames, N_tmp, tmp_lon, tmp_lat, tmp_obs) + + if (logit) then + write (logunit, *) 'read_obs_MODISsca :read MODIS datasets file name:', & + fnames + end if + + deallocate(fnames) + + else + N_tmp = 0 + + end if + + if (N_tmp>0) then + + allocate(tmp_tile_num(N_tmp)) + + call get_tile_num_from_latlon(N_catd, tile_coord, & + tile_grid_d, N_tile_in_cell_ij, tile_num_in_cell_ij, & + N_tmp, tmp_lat, tmp_lon, & + tmp_tile_num) + + MODIS_obs = 0. + N_obs_in_tile = 0 + + do i=1,N_tmp + ind = tmp_tile_num(i) + + if (ind>0) then + MODIS_obs(ind) = MODIS_obs(ind) + tmp_obs(i) + N_obs_in_tile(ind) = N_obs_in_tile(ind) + 1 + end if + end do + + do i=1,N_catd + if (N_obs_in_tile(i)>1) then + MODIS_obs(i) = MODIS_obs(i)/real(N_obs_in_tile(i)) + else if (N_obs_in_tile(i) == 0) then + MODIS_obs(i) = this_obs_param%nodata + end if + end do + + if (associated(tmp_tile_num)) deallocate (tmp_tile_num) + + do i=1, N_catd + std_MODIS_obs(i) = this_obs_param%errstd + end do + + if (any(N_obs_in_tile>0)) then + found_obs = .true. + else + found_obs = .false. + end if + + end if + +if (associated(tmp_obs)) deallocate(tmp_obs) + if (associated(tmp_lon)) deallocate(tmp_lon) + if (associated(tmp_lat)) deallocate(tmp_lat) + end subroutine read_obs_MODISsca + + ! ***************************************************************** subroutine read_ae_l2_sm_hdf( & N_files, fnames, N_data, lon, lat, ae_l2_sm, ease_col, ease_row ) @@ -7210,7 +7390,14 @@ subroutine read_obs( & ! choose appropriate reader select case (trim(this_obs_param%descr)) - + + case ('MODIS_SCA') + + call read_obs_MODISsca( & + work_path, date_time, dtstep_assim, N_catd, tile_coord, & + tile_grid_d, N_tile_in_cell_ij, tile_num_in_cell_ij, & + this_obs_param, found_obs, tmp_obs, tmp_std_obs) + case ('ae_l2_sm_a', 'ae_l2_sm_d') call read_obs_ae_l2_sm( & diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index f7b86249..9deaf3ba 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -1485,7 +1485,7 @@ subroutine get_obs_pred( & get_sfmc_lH, get_rzmc_lH, get_tsurf_lH, get_FT_lH, get_asnow_lH, get_Tb_lH, N_fields, & option=1, tile_data=tile_data_l, & sfmc=sfmc_l, rzmc=rzmc_l, tsurf=tsurf_l, FT=FT_l, stemp=stemp_l, & - Tb_h=Tb_h_l, Tb_v=Tb_v_l ) + Tb_h=Tb_h_l, Tb_v=Tb_v_l, asnow=asnow_l ) ! communicate tile_data_l as needed and get tile_data_lH @@ -1498,7 +1498,7 @@ subroutine get_obs_pred( & call get_obs_pred_comm_helper( N_catlH, N_ens, N_TbuniqFreqAngRTMid, & get_sfmc_lH, get_rzmc_lH, get_tsurf_lH, get_FT_lH, get_asnow_lH, get_Tb_lH, N_fields, & option=2, tile_data=tile_data_lH, & - sfmc=sfmc_lH, rzmc=rzmc_lH, tsurf=tsurf_lH, asnow=asnow_l, FT=FT_l, stemp=stemp_lH, & + sfmc=sfmc_lH, rzmc=rzmc_lH, tsurf=tsurf_lH, asnow=asnow_lH, FT=FT_l, stemp=stemp_lH, & Tb_h=Tb_h_lH, Tb_v=Tb_v_lH ) ! clean up @@ -3438,8 +3438,13 @@ subroutine cat_enkf_increments( & ! - reichle, 17 Oct 2011 ! ------------------------------------------------------------------- - implicit none + USE SurfParams, ONLY: WEMIN + USE StieglitzSnow, ONLY: RHOMA_pub, cpw_pub + use Catch_Constants, ONLY: RHOFS => CATCH_SNWALB_RHOFS + + implicit none + ! inputs integer, intent(in) :: N_ens, N_obs, N_catd, N_obs_param, update_type @@ -3536,15 +3541,15 @@ subroutine cat_enkf_increments( & !jpark50 real, dimension(N_catd, N_ens) :: wesn_sum_old real, dimension(N_catd, N_ens) :: areasc_old - real, parameter:: cpw = 2065.22 !ice specific heat capacity @ 0C [J/kg/K] + !real, parameter:: cpw = 2065.22 !ice specific heat capacity @ 0C [J/kg/K] real, parameter:: model_threshold = 0.40 real, parameter:: obs_threshold = 0.25 real, parameter:: wesn_added = 12.0 ! mm of SWE real, parameter:: eps = 1.e-4 real, parameter:: small = 1.e-20 - real, parameter:: rhofs = 150. ! kg/m^3 density of fresh snow - real, parameter:: rhoma = 500. ! kg/m^3 maximum snow density - real, parameter:: wemin = 13. ! kg/m^3 + ! real, parameter:: rhofs = 150. ! kg/m^3 density of fresh snow + ! real, parameter:: rhoma = 500. ! kg/m^3 maximum snow density + ! real, parameter:: wemin = 13. ! kg/m^3 real :: TSN, dens_layer ! ----------------------------------------------------------------------- @@ -4052,11 +4057,11 @@ subroutine cat_enkf_increments( & !============================================================================= if (logit) write (logunit, *) 'get 1d snow(asnow) increments; MODIS SCF' - do n_e=1,N_ens - call StieglitzSnow_calc_asnow(N_snow, N_catd, & - catprogn2wesn(N_catd, cat_progn(:,n_e)), & - asnow) - end do + !do n_e=1,N_ens + ! call StieglitzSnow_calc_asnow(N_snow, N_catd, & + ! catprogn2wesn(N_catd, cat_progn(:,n_e)), & + ! asnow) + !end do !identify the species ID number of interest N_select_varnames = 1 @@ -4101,7 +4106,7 @@ subroutine cat_enkf_increments( & !Estimate the density of the ld layers of snow dens_layer = max(cat_progn(kk,n_e)%wesn(i)/ & - (cat_progn(kk,n_e)%sndz(i)*areasc_old(kk,n_e)),rhofs) + (cat_progn(kk,n_e)%sndz(i)*areasc_old(kk,n_e)),RHOFS) cat_progn_incr(kk,n_e)%sndz(i)=& cat_progn_incr(kk,n_e)%wesn(i)/dens_layer @@ -4111,7 +4116,7 @@ subroutine cat_enkf_increments( & end if !c) heat content TSN=min(met_force(kk)%Tair-MAPL_TICE, 0.0) - cat_progn_incr(n,n_e)%htsn(i) = (TSN*cpw-MAPL_ALHF)*cat_progn_incr(kk,n_e)%wesn(i) + cat_progn_incr(n,n_e)%htsn(i) = (TSN*cpw_pub-MAPL_ALHF)*cat_progn_incr(kk,n_e)%wesn(i) end do elseif (Observations(ind_obs(1))%obs <= obs_threshold) then @@ -4140,7 +4145,7 @@ subroutine cat_enkf_increments( & end if !c) heat content TSN=min(met_force(kk)%Tair-MAPL_TICE, 0.0) - cat_progn_incr(kk,n_e)%htsn(i) = -(TSN*cpw-MAPL_ALHF)*cat_progn_incr(kk,n_e)%wesn(i) + cat_progn_incr(kk,n_e)%htsn(i) = -(TSN*cpw_pub-MAPL_ALHF)*cat_progn_incr(kk,n_e)%wesn(i) end do else From 86a28adb072c729782c6f30e25166d822f332318 Mon Sep 17 00:00:00 2001 From: Jongmin Park Date: Thu, 30 Sep 2021 15:11:00 -0400 Subject: [PATCH 006/308] deleting the swo file --- .../.clsm_ensupd_upd_routines.F90.swo | Bin 24576 -> 0 bytes .../clsm_ensupd_read_obs.F90 | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/.clsm_ensupd_upd_routines.F90.swo diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/.clsm_ensupd_upd_routines.F90.swo b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/.clsm_ensupd_upd_routines.F90.swo deleted file mode 100644 index 502bc8fc30b7dea6e14664da515bbb1fb6442337..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24576 zcmeHPYmgk(bsk~GU;{Q5gsQ~l_>NNY&d9r(nH54}%|aIKu8`2~%DXEbv2oMe-80i{ zPxq+1N2^s_Cb7%JA+G$$4_AmQ4_96;n^Y2#5W8#=oU&ah9Iz7zVB!bHiXl!U1F<0l zu=AbU=k|2>_UtZ(KX!GOKK0B!_ndp~xvxIw^z2go+JiG<@2*QqxGpG_&U|Ex{;|iN z-}1e4N~N2-y1%@qPLy>o(+&*pxaIF|tXr*AYjvAJr)IiKyGLs*ymnw}Zox72pceQ> zZNJy)damV$L0qmK@NJXIqY~Xk-N5ejiw!5}XqFrFx~4|(yD(Vv#y75ykIP*|X_Kw*Kx0)+(%3ltV8EKpcr z6BY=&drG&U-dSAN;`^4&{YQM+T;9ykf5`MMmw!1!e~IYBpG9jTKh>|HpKn=^x0@pJ)0BrvD&A|6iuhGQIPf=!25~9Mcz={+SH@S*E|2>2KJY z=KlfHRsV0x(7(_0>zV(h4E=wYt}*@S&!pu)!}P;U|C1zB|GW7pu`fberWQP7y83m|2gUy+(_N;2GDClY>9;cd=U$)Y|4yd;KgiJkgX!;P{&UVv^PggR zkLhNH{%xkK@%w6q{y5W@ng5s0OUwTj)0KTbnV~<%bT$4LouB6aCeuxp?`P=WVEPi% zAIi|b&h(p@zV8ju2W9`SF}CnSRy1uz!_`)>*mzl0J|E(GN{Y-b5{zQh( z+iB^oOkcPtEuV{vTVa910)+(%3ltV8EKpdWu)r&{fQ|?HA;@@`9t81Bs{H@Y;`!GH zy1=`D8-VM9eZU@I3-A=4!A}F920jS96SxYv5;zxl7(T!s0UmG^m--+@1KC-6St5O6W@9DJzn1NQ(Q214K%Fb=#9cm_V&)4<)pp8cq1@-`2fcxNR+zwbk1Go^_27Ch#xc3A10k;DdFasO{E(RV)JmMbUZs0e7qd*xr zjd6Jdpz(Q##%Pn5h%Q49jkad!j-gF2mev-w+Tk#l=HA|x!xMJbWf6HifoD5f$FqY0 z%@I#8umru!p9SK`T2FX;JA%{pN?THtysgKFeUj|G!5(s&)bjRMV0 z%gNzbN14&i%KYMtc3k%Zr9xEFvO;ZfDMy%WoBvbxh*;LMNKysW5H-=Y{1D%zQSs7@ z{65gMgM`>OYc_bBzSq$lJ#;)b*+ghNme#`SIqP>Oo)4s!5k)Jnp)BD;(aZ>qx8rjWu+>0V$0E_ z(WI1@r~47`k=j9C3rXFTa?!l*w}f&UhNzgVnJWqU<_g2SYI?q5sd0!$bkeu+UfKZ7 z@Q72+Q)hp&ZLz<+iiG`nujQ$W7F1MW8L;KMU)DiRjk+0w@(aEAiZz&RhVAXCT1tJ zqeqTR&0jTlbaql(oSL4FpDLJqc<#C+Id}TSvtcdI#KP>{b$Lu#9TK|Ii5|te zVFrctEP;*F@mlM)6!Szoe9*NF+X^(dllNGcu$x@1i8qW}j<>Y-7|5UCu7~xiYoX_8 zEz7lh+bFSQrf})z6h{xKzw1^`C@w#OXLB6=r6iw4cr_nDXLTpNmIp1RnTaEZwIc^r z59QbSiOGXU7dFy39vaEBcyRyJMjU-@CCh&7H`v9(AaC=_ADY?uiP_18si{fmOGE7X znyv&%K89DF>dJZ=7#MDT>d=BTWR2IHv8*K-hSfef`y1uA4qT-$_!nP%* z+`#HALCQ6{)6rdlO*gcBv0{g9NtdUDJX@vzA-raD#KEiW!jz9SXdrCc0kJ_5&kc3k z4TO%54xVFa7Y2t2dP~ZEKy^J7x{vN!mT8$H^h)IaQ?Btvfc$@ze|Z7^{bzu?0Ez>2 z0P_3mzz^Zue**Xu;6niU{#O9wz|R7w;Nw3IdG1;TQe1@v3JVk#C@fG|ps+w;fx-fX1qutisum~C5mhYoQyGj015c=?#Lbyz5>bUJ8!C{$7nAA@Mt1cY1 z&^81@43>XfmtIvQgjDagR|6Y?n54L2s67%`A+fM^BcU)eJUSITnClCKgN<)8gfFU8 zx9_t>c8X%ph_P41EdA7Z7&nTp&>gJ|%ZLaVV~g*uiv_DIEnXr=H1vo@UUCR;l)OJG znmKY%JD{V3zStgXrZu;NL0>}72*1QOh1v6Mw*@^ACbXgfqmH$8$19a+;_Q6I7sTM7 z<(kQk<45J8w%i#ttrm!~2HkMM-j1N3jBEOm2b;)<#eu2WsriHZwW;~}x%pvnQ11+j zA#D z%^Qa$7aV*lfLb?-%E)E)vCHa_-hC~kf=Y|!4w|b_vo+SC3Y{wQa};*0bD3^Z+&;qstW#9tfjldS*dF1c!16<(E zz!~K0e-AhWyoB8RbHFL!qrf~c3G4&*0$YJ6(MRg%$AIgB{lJyL6~G<9ZvwXgD?k^R z2BrW3d>uCWUEn(4BH#>i_NRe+fjfb}1X_Rwycsx+-2Exw_ks5UzXH4+*a@5mYy}?M z66N+kj5}Q-y5#((IDBAH97p3=WrfL`xy2#164z!?2&+?6Kd3aSm@h+Nuxz_Ss*bwP zs)kiZ^F($vs$mGtd7=qqnw<#7$at+aGYRPsD-=e7)@K?_AisXLR3a)82K7(uj7puA>{+f4aVft-6Qh(nX#|N5#r^w1?Omwl+b3g+f?V zN@;093Fht5M28*9eQ^|hGkQVjb?lSa8)!4b`omsfM%Cqy7)cv!YdhP)d(0*#fuRj|u(jl{}Clc0?>Yc}209UL!7qd}k&DTL_> zSF^?&WAaSkavB{qfR;(8gSbM}s}xUkV~eA?bR7zKQlg)#$M#CpQgd)v>8|D^HJ+ZP zlmv{YA4IH8PjG#*B!c&Ou~x7pMereqQgzKGY&}3gT1332xR;w;Oi3-$YDX(b=_Btt zy>61U9+hSaam+@!Ps&MRpzs|D2zmHYO0+UIj3KS&B~sTFB->{N)vDz+F8O$k$77}H zL@QfzmxXO&iQ3Io8GGgd76&Iq^!i0W!DKux;V=!tXeQB#jY(LN{MoMl_&trp#io}- zw-DM^%dx|g3$StYK9lSi&2^OU15s`+ClaI<%Wz_`NW}+lXF}~~4Lq2jkxDcKsqJiL zZt~!QSlB-uS-3p@YF<*m@*?)Ccn1~8s38M@Eeqoy@NA&t*@Kd}YKNq47Q3t>yPiyM zVCbgY<>^Qu|K*)AF}iQ$P|q0|t&cXw#55jfWe0gL9g8Zzn*AAeep{arA!HI?GIi8lJCuSaPP^@oZ?bZy3&k*c7&x<_+4xkFNk-AtCCdc0Ec z5|ZIp+~Kk64nF0^#R5HEM})l~?Chs#RV$EyD^EyhTtcLjkW2eQC@)%~3h|XMWR&PB zA$wlFkj5Gzmt=&Ls78F{se&?0)wC+R`%)ruDHcH=^2ErzbEZe5eKC@}v6Lv|omQsN zmlBaPBMl!Y;PhOqSbrVjXPl&R`f3^hwnrZ`po!;wK<>EiBfgW^$+OiX#hvdKvMSTR^o8lYFKfbJTnzn`T$m?B#YiMs|?fv^ENU)9a7SHSGLIBGqU8tCtvW2w|_X6o4hizN-4H7 zPJ?Tvd85zFoSv`&Axu zBgve$Nup`mr`B>uTNVq5z6_K=Thv+!(PqXHa<;C73bZ?|6%cJyEMUN{RYBU{cDp^i zC=w4Gg{Pvo1L7jBW4pbeD*gXY!CyTEpO*apN$H7}NVv*``!`Yw+6OKtF9*{H(* zM@E5;b@=-!b=hrIb>)44N`Y&hjJhzO0_$8uU?{-ve^xC&)f9pesvKtU+g>yNsgrEh za)LOD8te08Hr0Qai5zTYR_?=iyfV3=w4$OCH(SYY?nL%a4-Cz7Ohu{=%f4jBD&1TB zJS0b^GFU2nNg9=>0=%|QA!-Ueliloal_F~N)iIIjfpKMsjp7>_)Oo z&_p5yw18fT?suoQVu3W=;FJ%k!&hEy2m*hlZ*SFtoWWU}i1MTbpBM6@o~e)wQlkAp zjo!*mgObuf-tA_NDb?h>LRj5^Z}&F5w>i@ zD56T~G1+mMh^{pqPY)4Bq?h!oYq}>YsknaMGpts3ATQmskh{oEy?Cm{GnL}>RkZ`a zz*&y6UKI<}l@-hoBruNkYzW87Mik6MO5#`#2?mbKQZ?jmDdRw$!t9Y#C#5-po%VPG zp-$>lDP^_Pw;>r)(-6LdQbWTVbQKBJ$e3~cC`6YMxj{H}!Zc;T7D)pcy2CFyhlUg8 zAa*HLTs}@o@f@F=4Zkxpu-Pfn*Gh$cqdbWyQ{rCcah1Ik)$%-Wk=N2ON_gGLj)_zXv^HV`u%CdfRSBZ zmJ=N{%&4sFcwU#5hSzJgqh*3b69VNBY~atx_pk@|<0;HDk9YY;mXM!|BK;K5SJ4sD zEUHDHq8BdII~-6{eN;1MP^K&u@QW*}JWQNdQw5cN+>U+=C6l%)_{1iS2jrDJ&X)ck DA0yCx diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index e9992c3e..ea48aaa9 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -142,7 +142,7 @@ subroutine read_MODISsca_hdf(& integer :: i, j, k, k_off, ll, mm, kk integer :: hh_num, time_index - integer, parameter :: bin_size = 0.5 + integer, parameter :: bin_size = 0.05 integer, parameter :: XGRID = 3600 integer, parameter :: YGRID = 7200 From 765e145faa6ddf803a1af943db83b50073d1a0fc Mon Sep 17 00:00:00 2001 From: Jongmin Park Date: Mon, 11 Oct 2021 23:23:59 -0400 Subject: [PATCH 007/308] Updating the MODIS SCA assimilation based on meeting 10/9/21 --- .../clsm_ensupd_read_obs.F90 | 73 ++++++++++++------- 1 file changed, 47 insertions(+), 26 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index ea48aaa9..5011f427 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -146,15 +146,15 @@ subroutine read_MODISsca_hdf(& integer, parameter :: XGRID = 3600 integer, parameter :: YGRID = 7200 - real :: lat_ind(XGRID) = (/(ll, ll=1, 3600, 1)/) - real :: lon_ind(YGRID) = (/(mm, mm=1, 7200, 1)/) + real :: lat_ind(XGRID) = (/(ll, ll=0, 3600-1, 1)/) + real :: lon_ind(YGRID) = (/(mm, mm=0, 7200-1, 1)/) !------------------------------------------------------------- - ! UTC | 0000 | 0300 | 0600 | 0900 | 1200 | 1500 | 1800 | 2100 - ! lon | -180 -135| -135 -90| -90 -45 | -45 0| 0 45 | 45 90| 90 135| 135-180 + ! UTC | 0000 | 0300 | 0600 | 0900 | 1200 | 1500 | 1800 | 2100 + ! lon | 180 135 | 135 90 | 90 45 | 45 0 | 0 -45| -45 -90| -90 -135| -135 -180 ! - real:: lon_subtime(9) = (/(kk, kk=-180, 180, 45)/) + real:: lon_subtime(9) = (/(kk, kk=180, -180, -45)/) integer, dimension(:), allocatable :: Snow_QA integer, dimension(:), allocatable :: CI_Index, Cloud_index @@ -320,7 +320,9 @@ subroutine read_MODISsca_hdf(& j = 0 do i=1,N_data - + if (logit) write (logunit, *) 'hh_num=', hh_num + if (logit) write (logunit, *) 'time_index =', time_index + if ( (MODIS_SCA(i)>0.) .and. & ! any neg is nodata (CI_Index(i)>20) .and. & ! Ignore obs (Snow_QA(i)<3) .and. & @@ -336,6 +338,11 @@ subroutine read_MODISsca_hdf(& end if end do + + if (logit) write (logunit, *) 'assimilation time', HH + if (logit) write (logunit, *) 'lat = ', lat + if (logit) write (logunit, *) 'lon = ', lon + if (logit) write (logunit, *) 'MODIS_SCA=', MODIS_SCA N_data = j @@ -373,20 +380,22 @@ subroutine read_obs_MODISsca( & real, intent(out), dimension(N_catd):: MODIS_obs real, intent(out), dimension(N_catd):: std_MODIS_obs logical,intent(out) :: found_obs + logical :: file_exists !locals - character(2):: MM, DD + character(2):: MM, HH, MI character(4):: YYYY character(3):: DDD ! Day of Year - character(8):: date_string - character(10):: time_string character(300):: tmpfname1 integer, dimension(N_catd) :: tmp_tile_id integer :: i, ind, N_tmp, N_files - + integer :: hh_num, mi_num + + integer:: dtstep_assim_max=10800 + character(300), dimension(:), allocatable :: fnames real, dimension(:), pointer:: tmp_obs, tmp_lat, tmp_lon @@ -394,41 +403,53 @@ subroutine read_obs_MODISsca( & integer, dimension(N_catd):: N_obs_in_tile + character(len=*), parameter :: Iam = 'read_obs_MODISsca' + character(len=400) :: err_msg + nullify (tmp_obs, tmp_lat, tmp_lon, tmp_tile_num) + write(HH, '(i2.2)') date_time%hour + read(HH, '(I10)') hh_num + + write(MI, '(i2.2)') date_time%min + read(MI, '(I10)') mi_num + + !restricting the assimilation time step not exceeding 3 hr + if (dtstep_assim > dtstep_assim_max) then + err_msg = 'dtstep_assim must not exceed 3 hours' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + end if + + ! restricting the time stamp to only 0z 3z 6z ... + if ((mod(hh_num,3).NE.0) .or. (mi_num .NE. 0)) then + err_msg= 'assimilation timestep does not match' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + end if + !! initializing found_obs = .false. write (YYYY,'(i4.4)') date_time%year write (MM, '(i2.2)') date_time%month - write (DD, '(i2.2)') date_time%day write (DDD, '(i3.3)') date_time%dofyr write (logunit, *) 'Entered read_obs_MODIS' - write (logunit, *) 'Obs time: ', YYYY, MM, DD + write (logunit, *) 'Obs time: ', YYYY, MM write (logunit, *) 'DOY: ', DDD - tmpfname1 = trim(this_obs_param%path) // '/Y' // YYYY // 'MOD10C1.A' // YYYY // DDD // & + tmpfname1 = trim(this_obs_param%path) // YYYY // 'MOD10C1.A' // YYYY // DDD // & '.006.hdf' if (logit) write (logunit, *) 'Trying to read data from', & trim(tmpfname1) - open(10, file=tmpfname1, form='formatted', action='read') - read(10,*), N_files - close(10) - - if (N_files > 0) then + inquire(file=trim(tmpfname1), exist=file_exists) - allocate(fnames(N_files)) - - do i=1,N_files - read(10, '(a)') fnames(i) - end do + if (file_exists) then + N_files= 1 + fnames(N_files) = tmpfname1 end if - close(10, status='delete') - if (N_files>0) then call read_MODISsca_hdf( & @@ -489,7 +510,7 @@ subroutine read_obs_MODISsca( & end if -if (associated(tmp_obs)) deallocate(tmp_obs) + if (associated(tmp_obs)) deallocate(tmp_obs) if (associated(tmp_lon)) deallocate(tmp_lon) if (associated(tmp_lat)) deallocate(tmp_lat) end subroutine read_obs_MODISsca From 580d123b0a865f3bccab5e281afb1d6de2308034 Mon Sep 17 00:00:00 2001 From: Jongmin Park Date: Fri, 15 Oct 2021 09:31:47 -0400 Subject: [PATCH 008/308] pusing the update until 10/15/2021 --- CMakeLists.txt | 2 - .../clsm_ensupd_read_obs.F90 | 190 +++++++++--------- .../clsm_ensupd_upd_routines.F90 | 2 +- 3 files changed, 96 insertions(+), 98 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ef8cb709..ff5a75af 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,5 +52,3 @@ install( FILES ${PROJECT_BINARY_DIR}/.gitignore DESTINATION ${CMAKE_INSTALL_PREFIX} ) - - diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 5011f427..f636b8af 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -85,7 +85,7 @@ module clsm_ensupd_read_obs contains subroutine read_MODISsca_hdf(& - N_files, date_time, fnames, N_data, & + N_files, date_time, N_data, fnames, & lon, lat, MODIS_SCA) !read snow cover data from daily MOD10C1 data located under lis folder @@ -101,11 +101,10 @@ subroutine read_MODISsca_hdf(& integer, intent(out) :: N_data real, dimension(:), pointer, allocatable :: lon, lat - real, dimension(:), pointer :: lon_c, lat_c + ! real, dimension(:), pointer :: lon_c, lat_c, lon_1D, lat_1D real, dimension(:), pointer :: MODIS_SCA type(date_time_type),intent(in) :: date_time ! loading the UTC hour information to constrain the longitude of MODIS obs. - character(2):: HH !local parameters integer, parameter:: N_fields = 4 @@ -121,37 +120,42 @@ subroutine read_MODISsca_hdf(& ! step 1: remove the Snow cover > 100 (e.g., lake, night, inland water, ocean..) ! step 2: Clear Index (CI): CI > 20% is considered ! + integer,parameter :: qc_clear_index_threshold = 20 !screen for sufficiently clear condition + integer,parameter :: qc_snow_spatial_threshold = 3 !screen for basic data quality (e.g., 0:best 1:good 2:OK 3:poor, 4:others) + integer,parameter :: qc_snow_cover_threshold = 100 !screen for areas inland water, ocean, cloud obscured and fill !declariations of hdf functions integer:: hopen, vfstart, vsfatch, vsqfnelt, vsfseek, vsfsfld, vsfread - integer:: vsfdtch, vfend, hclose + integer:: vsfdtch, vfend, hclose, vsffnd ! declarations of hdf-related parameters and variables integer, dimension(N_files) :: file_id, vdata_id - integer :: status, n_read, n_records, record_pos + integer :: status, n_read, record_pos integer, parameter :: num_dds_block = 0 ! only important for writing hdf - integer, parameter :: vdata_ref = 4 + integer, parameter :: vdata_ref = 7 integer, parameter :: DFACC_READ = 1 ! from hdf.inc integer, parameter :: FULL_INTERLACE = 0 ! from hdf.inc ! local variables logical :: must_stop - integer, dimension(N_files) :: N_data_tmp ! variables to define latitude and longitude integer :: i, j, k, k_off, ll, mm, kk - integer :: hh_num, time_index + integer :: time_index - integer, parameter :: bin_size = 0.05 + real, parameter :: bin_size = 0.05 integer, parameter :: XGRID = 3600 integer, parameter :: YGRID = 7200 + integer, dimension(N_files) :: N_data_tmp - real :: lat_ind(XGRID) = (/(ll, ll=0, 3600-1, 1)/) - real :: lon_ind(YGRID) = (/(mm, mm=0, 7200-1, 1)/) - + real :: lat_ind(XGRID) = (/(ll, ll=0, XGRID-1, 1)/) + real :: lon_ind(YGRID) = (/(mm, mm=0, YGRID-1, 1)/) + real, dimension(XGRID) :: lat_c(XGRID) + real, dimension(YGRID) :: lon_c(YGRID) + real, dimension(XGRID*YGRID) :: lat_1D, lon_1D !------------------------------------------------------------- ! UTC | 0000 | 0300 | 0600 | 0900 | 1200 | 1500 | 1800 | 2100 - ! lon | 180 135 | 135 90 | 90 45 | 45 0 | 0 -45| -45 -90| -90 -135| -135 -180 + ! lon | 135 180 | 90 135 | 45 90 | 0 45 | -45 0| -90 -45| -135 -90| -180 -135 ! real:: lon_subtime(9) = (/(kk, kk=180, -180, -45)/) @@ -165,47 +169,43 @@ subroutine read_MODISsca_hdf(& character(len=*), parameter :: Iam = 'read_MOD10C1_hdf' character(len=400) :: err_msg + if (logit) write(logunit,*) 'Entering the hdf reader' + + ! initialize N_data + N_data_tmp(N_files) = 3600*7200 + + if (logit) write(logunit, *) 'N_data_tmp=', N_data_tmp(1) + + N_data = sum(N_data_tmp) + + if (logit) write(logunit, *) 'N_data', N_data + lat_c = (90-bin_size/2)-bin_size*lat_ind - lon_c = (-180+bin_size/2)-bin_size*lon_ind + lon_c = (-180+bin_size/2)+bin_size*lon_ind + + if (logit) write(logunit, *) 'lon_c=', lon_c + do i=1,7200 - lat(3600*(i-1)+1:3600*i)= lat_c - lon(3600*(i-1)+1:3600*i)= lon_c(i) + lat_1D(3600*(i-1)+1:3600*i)= lat_c + lon_1D(3600*(i-1)+1:3600*i)= lon_c(i) end do - ! determine number of data to be read from each file + ! allocate pointers (must be deallocated outside this subroutine) - do j=1,N_files - - ! open and "start" hdf file - file_id(j) = hopen( fnames(j), DFACC_READ, num_dds_block ) - status = vfstart(file_id(j)) - - ! select vdata block that contains fields of interest - vdata_id(j) = vsfatch(file_id(j), vdata_ref, 'r') - - ! determine number of records in vdata - status = vsqfnelt(vdata_id(j), n_records) - N_data_tmp(j) = n_records - - end do - - ! allocate pointers (must be deallocated outside this subroutine) - - must_stop = .false. - - if ( associated(lon) .or. associated(lat) .or. associated(MODIS_SCA) ) then - must_stop = .true. - end if + must_stop = .false. + + if ( associated(lon) .or. associated(lat) .or. associated(MODIS_SCA) ) then + must_stop = .true. + end if - if (must_stop) then - err_msg = 'output pointers must not be associated/allocated on input.' - call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) - - end if + if (must_stop) then + err_msg = 'output pointers must not be associated/allocated on input.' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + end if - allocate(lon(N_data)) allocate(lat(N_data)) + allocate(lon(N_data)) allocate(MODIS_SCA(N_data)) allocate(CI_Index(N_data)) @@ -217,15 +217,21 @@ subroutine read_MODISsca_hdf(& k_off = 0 do j=1,N_files - + ! open and start "hdf file" + if(logit) write(logunit, *) 'fname: ', fnames(j) + file_id(j) = hopen(fnames(j), DFACC_READ, num_dds_block) + status = vfstart(file_id(j)) + allocate(tmprealvec(N_data_tmp(j))) allocate(tmpint2vec(N_data_tmp(j))) - + + vdata_id(j) = vsfatch(file_id(j), vdata_ref, 'r') + if (logit) write (logunit, *) 'vdata_id: ', vdata_id(j) + do i=1,N_fields - ! go to start of record (zero-based count) record_pos = vsfseek(vdata_id(j), 0) - + ! pick the field to be read status = vsfsfld(vdata_id(j), field_names(i)) @@ -240,7 +246,7 @@ subroutine read_MODISsca_hdf(& do k=1,N_data_tmp(j) - if ( MODIS_SCA(k+k_off) > 100) then + if ( MODIS_SCA(k+k_off) > qc_snow_cover_threshold) then MODIS_SCA(k+k_off) = -1 end if end do @@ -251,12 +257,7 @@ subroutine read_MODISsca_hdf(& N_data_tmp(j), FULL_INTERLACE) CI_Index(k_off+1:k_off+N_data_tmp(j)) = tmprealvec - do k=1,N_data_tmp(j) - - if (CI_Index(k+k_off) <20) then - CI_Index(k+k_off) = -1 - end if - end do + case (3) n_read = vsfread( vdata_id(j) ,tmpint2vec, & N_data_tmp(j), FULL_INTERLACE) @@ -292,14 +293,11 @@ subroutine read_MODISsca_hdf(& call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'ERROR reading hdf') end do - ! clean up - deallocate(tmprealvec) deallocate(tmpint2vec) ! close hdf files - status = vsfdtch(vdata_id(j)) status = vfend(file_id(j)) status = hclose(file_id(j)) @@ -309,10 +307,7 @@ subroutine read_MODISsca_hdf(& end do - write(HH, '(i2.2)') date_time%hour - read(HH, '(I10)') hh_num - - time_index = hh_num/3 +1 + time_index = date_time%hour/3 +1 ! ------------------------------------- ! eliminate no-data-values and data that fail initial QC @@ -320,14 +315,13 @@ subroutine read_MODISsca_hdf(& j = 0 do i=1,N_data - if (logit) write (logunit, *) 'hh_num=', hh_num if (logit) write (logunit, *) 'time_index =', time_index - if ( (MODIS_SCA(i)>0.) .and. & ! any neg is nodata - (CI_Index(i)>20) .and. & ! Ignore obs - (Snow_QA(i)<3) .and. & - (lon(i)>=lon_subtime(time_index)) .and. & - (lon(i)0.) .and. & ! any neg is nodata + (CI_Index(i)>qc_clear_index_threshold) .and. & + (Snow_QA(i)lon_subtime(time_index+1)) & !depending on the time info ) then j=j+1 @@ -339,10 +333,11 @@ subroutine read_MODISsca_hdf(& end do - if (logit) write (logunit, *) 'assimilation time', HH - if (logit) write (logunit, *) 'lat = ', lat - if (logit) write (logunit, *) 'lon = ', lon - if (logit) write (logunit, *) 'MODIS_SCA=', MODIS_SCA + ! debugging purpose to check whehter reader works properly or not + if (logit) write (logunit, *) 'assimilation time', date_time%hour + if (logit) write (logunit, *) 'lat = ', lat(1:j) + if (logit) write (logunit, *) 'lon = ', lon(1:j) + if (logit) write (logunit, *) 'MODIS_SCA=', MODIS_SCA(1:j) N_data = j @@ -383,7 +378,7 @@ subroutine read_obs_MODISsca( & logical :: file_exists !locals - character(2):: MM, HH, MI + character(2):: MM character(4):: YYYY character(3):: DDD ! Day of Year @@ -391,11 +386,10 @@ subroutine read_obs_MODISsca( & integer, dimension(N_catd) :: tmp_tile_id - integer :: i, ind, N_tmp, N_files - integer :: hh_num, mi_num - - integer:: dtstep_assim_max=10800 + integer :: i, ind, N_files, N_tmp + integer, parameter :: dtstep_assim_threshold=10800 ! restricting dtstep_assim to 3 hours + character(300), dimension(:), allocatable :: fnames real, dimension(:), pointer:: tmp_obs, tmp_lat, tmp_lon @@ -407,27 +401,21 @@ subroutine read_obs_MODISsca( & character(len=400) :: err_msg nullify (tmp_obs, tmp_lat, tmp_lon, tmp_tile_num) - - write(HH, '(i2.2)') date_time%hour - read(HH, '(I10)') hh_num - - write(MI, '(i2.2)') date_time%min - read(MI, '(I10)') mi_num - - !restricting the assimilation time step not exceeding 3 hr - if (dtstep_assim > dtstep_assim_max) then - err_msg = 'dtstep_assim must not exceed 3 hours' + !restricting the assimilation time step to *only* 3 hr + if (dtstep_assim .NE. dtstep_assim_threshold) then + err_msg = 'dtstep_assim should be equal to 3 hours' call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) end if ! restricting the time stamp to only 0z 3z 6z ... - if ((mod(hh_num,3).NE.0) .or. (mi_num .NE. 0)) then + if ((mod(date_time%hour,3).NE.0) .or. (date_time%min .NE. 0)) then err_msg= 'assimilation timestep does not match' call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) end if !! initializing found_obs = .false. + N_tmp = 3600*7200 write (YYYY,'(i4.4)') date_time%year write (MM, '(i2.2)') date_time%month @@ -437,23 +425,36 @@ subroutine read_obs_MODISsca( & write (logunit, *) 'Obs time: ', YYYY, MM write (logunit, *) 'DOY: ', DDD - tmpfname1 = trim(this_obs_param%path) // YYYY // 'MOD10C1.A' // YYYY // DDD // & + tmpfname1 = trim(this_obs_param%path) // YYYY // '/MOD10C1.A' // YYYY // DDD // & '.006.hdf' if (logit) write (logunit, *) 'Trying to read data from', & trim(tmpfname1) inquire(file=trim(tmpfname1), exist=file_exists) - + + if (logit) write (logunit, *), file_exists + if (file_exists) then + if (logit) write (logunit, *) 'Entering file exist routine' N_files= 1 + allocate(fnames(N_files)) + fnames(N_files) = tmpfname1 end if + if (logit) write (logunit, *) 'N_files = ', N_files + if (logit) write (logunit, *) 'fnames = ', fnames + if (N_files>0) then + if (logit) write (logunit, *) 'calling MODISsca_hdf subroutine' + if (logit) write (logunit, *) 'N_files = ', N_files + if (logit) write (logunit, *) 'N_tmp = ', N_tmp + if (logit) write (logunit, *) 'fnames = ', fnames(N_files) + call read_MODISsca_hdf( & - N_files, date_time, fnames, N_tmp, tmp_lon, tmp_lat, tmp_obs) + N_files, date_time, N_tmp, fnames, tmp_lon, tmp_lat, tmp_obs) if (logit) then write (logunit, *) 'read_obs_MODISsca :read MODIS datasets file name:', & @@ -479,7 +480,7 @@ subroutine read_obs_MODISsca( & MODIS_obs = 0. N_obs_in_tile = 0 - do i=1,N_tmp + do i=1,N_files ind = tmp_tile_num(i) if (ind>0) then @@ -624,7 +625,6 @@ subroutine read_ae_l2_sm_hdf( & do j=1,N_files ! open and "start" hdf file - file_id(j) = hopen( fnames(j), DFACC_READ, num_dds_block ) status = vfstart(file_id(j)) @@ -813,7 +813,7 @@ subroutine read_ae_l2_sm_hdf( & ! ------------------------------------- ! ! eliminate no-data-values and data that fail initial QC - + j = 0 do i=1,N_data diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index 9deaf3ba..e88548fc 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -5086,7 +5086,7 @@ subroutine check_compact_support( & select case (update_type) - case (1,3,4,5,6,9) ! "1d" updates + case (1,3,4,5,6,9,11) ! "1d" updates ! Make xcompact and ycompact just large enough so that ! the EnKF analysis correctly identifies the tiles From 030da9c1c898be873b0a24845c2f2496ed6a53f0 Mon Sep 17 00:00:00 2001 From: Jongmin Park Date: Fri, 29 Oct 2021 09:48:16 -0400 Subject: [PATCH 009/308] Summary of updates regarding on 10/29/2021 1) Updates regarding MODIS obs. reader - Added the description of MODIS obs. reader at the subroutine (Table of longitude band is moved up) - Changed the hdf-related function to read (vdata vs. SDS dataset) : Previous hdf-related functions are cleaned up - Updated and checkced the QC procedure by comparing against Matlab result 2) Updates on subroutine cat_enkf_increment - Removing the cat_diagS at ths subroutine :Cat_diagS is also removed when the subroutine is called (e.g., ensupd_enkf_update.F90) - Computed the snow diagnostics to apply condition when to add/remove snow or no further action needed --- .../clsm_bias_routines.F90 | 1 - .../clsm_ensupd_enkf_update.F90 | 10 +- .../clsm_ensupd_read_obs.F90 | 282 ++++++++++-------- .../clsm_ensupd_upd_routines.F90 | 146 ++++++--- 4 files changed, 254 insertions(+), 185 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_bias_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_bias_routines.F90 index 58fd93da..04dbe3e4 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_bias_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_bias_routines.F90 @@ -1484,7 +1484,6 @@ subroutine obs_bias_upd_bias_and_Obs( & ! --------------------------------------------------------------------- ! get species-dependent time of day index - do i=1,N_obs_param indv_time(i) = bias_time_of_day_index( date_time, obs_param(i)%bias_Npar ) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 index f8c930e6..15c80220 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 @@ -522,7 +522,6 @@ subroutine get_enkf_increments( & if (allocated(obsbias_ok)) deallocate(obsbias_ok) - ! IF NEEDED, INCLUDE WITHHOLDING SUBROUTINE HERE. ! SUCH A SUBROUTINE SHOULD CHANGE Observations(i)%assim TO FALSE ! IF THE OBSERVATION IS TO BE WITHHELD @@ -533,6 +532,7 @@ subroutine get_enkf_increments( & ! count observations across all processors that are left after ! model-based QC (done within get_obs_pred()) + #ifdef LDAS_MPI call MPI_AllReduce( & @@ -542,7 +542,6 @@ subroutine get_enkf_increments( & #else N_obsf = N_obsl #endif - ! check whether any "assim" flag is set in obs_param ! CSD - if want to skip cat_enkf_incr and apply_incr blocks @@ -563,7 +562,6 @@ subroutine get_enkf_increments( & ! Obs bias ! ! B2. Update obs_bias and Observations with the obs bias increment - if ( (N_obsl>0) .and. (N_obsbias_max>0) ) & call obs_bias_upd_bias_and_Obs(date_time, N_catl, N_catf, & N_obsl, N_ens, N_obs_param, N_obsbias_max, f2l, obs_param, & @@ -651,6 +649,7 @@ subroutine get_enkf_increments( & !-AnaLoadBal-Prereq-starts-here- ! Step 1a: identify obs w/ obs%assim==.true. allocate(ind_obsl_assim(N_obsl), source=-99) + call get_ind_obs_assim(N_obsl, Observations_l%assim, N_obsl_assim, ind_obsl_assim) ! its easier to write ptr2indx than ind_obsl_assim(1:N_obsl_assim) ptr2indx => ind_obsl_assim(1:N_obsl_assim) @@ -780,6 +779,7 @@ subroutine get_enkf_increments( & allocate(indObs_ana(N_obsf_assim), source=-99) allocate(tmp_ind_obs(N_obsf_assim), source=-99) nObs_ana = 0 + do ctr=1,nTiles_ana iTile = indTiles_ana(ctr) ! 'full' index halo = get_halo_around_tile(tile_coord_f(iTile), xcompact, ycompact) @@ -990,11 +990,13 @@ subroutine get_enkf_increments( & ! of Observations_l and Obs_pred_l that are "good" ! [allocation of these arrays in get_obs_pred() is larger ! than eventual size] + call get_halo_obs( N_ens, N_catl, N_obsl, & Observations_l(1:N_obsl), Obs_pred_l(1:N_obsl,1:N_ens), & tile_coord_l, xcompact, ycompact, & N_obslH, Observations_lH, Obs_pred_lH ) + #endif ! get observations perturbations for all ensemble members @@ -1057,7 +1059,7 @@ subroutine get_enkf_increments( & cat_param_ana, & xcompact, ycompact, fcsterr_inflation_fac, & cat_progn_ana, cat_progn_incr_ana, & - met_force, cat_diagS) + met_force) call cpu_time(t_end) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index f636b8af..84e89d99 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -88,11 +88,25 @@ subroutine read_MODISsca_hdf(& N_files, date_time, N_data, fnames, & lon, lat, MODIS_SCA) - !read snow cover data from daily MOD10C1 data located under lis folder - !writer : jpark50 - !directory: /discover/nobackup/projects/lis/RS_DATA/MODIS_sca/MOD10C1_C6_download/ - ! - ! return ONLY valid data point (excluding no-data-value and CI < 20%) + !subroutine read_MODISsca_hdf routine description + !a. purpose: read snow cover data from daily MOD10C1 data located under lis folder + !b. MO10C1_C6 directory: /discover/nobackup/projects/lis/RS_DATA/MODIS_sca/MOD10C1_C6_download/ + ! [Note: No additional resampling of the MODIS SCA observation] + ! - daily datasets with spatial resolution of 0.05 deg on CMG grid + !c. dtstep_assim and ref_time is restricted to 3 hr and 00z, respectively + !d. Procedures + ! - Generating the latitude and longitude on CMG grid (1D array for now) + ! - Selection of the longitude band considering MODIS observation + ! time(local time: ~10:30am) + ! Table.Longitude band based on the assimilation time step (in UTC) + !----------------------------------------------------------------------------- + ! UTC | 0000 | 0300 | 0600 | 0900 | 1200 | 1500 | 1800 | 2100 + ! lon | 135 180 | 90 135 | 45 90 | 0 45 | -45 0| -90 -45| -135 -90| -180 -135 + !---------------------------------------------------------------------------- + ! - Quality Procedure + ! step 1: remove the Snow cover > 100 (e.g., lake, night, inland water, ocean..) + ! step 2: Clear Index (CI): CI > 20% is considered + ! step 3: Cloud Index not equal to 252 (which indicates the antartica region) implicit none @@ -101,46 +115,49 @@ subroutine read_MODISsca_hdf(& integer, intent(out) :: N_data real, dimension(:), pointer, allocatable :: lon, lat - ! real, dimension(:), pointer :: lon_c, lat_c, lon_1D, lat_1D + character(1), dimension(:,:), allocatable :: tmp_MODIS_SCA, tmp_CI_Index, tmp_Cloud_index, tmp_Snow_QA real, dimension(:), pointer :: MODIS_SCA type(date_time_type),intent(in) :: date_time ! loading the UTC hour information to constrain the longitude of MODIS obs. !local parameters integer, parameter:: N_fields = 4 + character(18), parameter:: Vdata_name = 'MODIS_CMG_Snow_5km' character(30), dimension(N_fields), parameter:: field_names = (/ & - 'Day_CMG_Snow_Cover', & !1 - 'Day_CMG_Clear_Index', & !2 - 'Day_CMG_Cloud_Obscured', & !3 - 'Snow_Spatial_QA'/) !4 + 'Day_CMG_Snow_Cover ', & !1 + 'Day_CMG_Clear_Index ', & !2 + 'Day_CMG_Cloud_Obscured ', & !3 + 'Snow_Spatial_QA '/) !4 integer, parameter :: nodata = -9999 !note: integer - - ! Quality control step - ! step 1: remove the Snow cover > 100 (e.g., lake, night, inland water, ocean..) - ! step 2: Clear Index (CI): CI > 20% is considered - ! integer,parameter :: qc_clear_index_threshold = 20 !screen for sufficiently clear condition + integer,parameter :: qc_clear_index_max_threshold = 100 ! removing the lake ice, night obs, ocean etc. integer,parameter :: qc_snow_spatial_threshold = 3 !screen for basic data quality (e.g., 0:best 1:good 2:OK 3:poor, 4:others) integer,parameter :: qc_snow_cover_threshold = 100 !screen for areas inland water, ocean, cloud obscured and fill + integer, parameter :: qc_antarctica = 252 ! screen for antarctica !declariations of hdf functions - integer:: hopen, vfstart, vsfatch, vsqfnelt, vsfseek, vsfsfld, vsfread - integer:: vsfdtch, vfend, hclose, vsffnd + integer:: sfstart, sffinfo, sfselect, sfn2index, sfginfo, sfrdata + integer:: sfend, sfendacc ! declarations of hdf-related parameters and variables - integer, dimension(N_files) :: file_id, vdata_id + integer, dimension(N_files) :: file_id, sd_id + integer, dimension(N_fields) :: ind, sds_id + integer:: n_datasets, n_file_attrs, n_attrs, rank, data_type + integer:: dim_sizes(2) + character(100) :: var_name + integer:: start(2), edges(2), stride(2) + integer :: status, n_read, record_pos - integer, parameter :: num_dds_block = 0 ! only important for writing hdf - integer, parameter :: vdata_ref = 7 integer, parameter :: DFACC_READ = 1 ! from hdf.inc + integer, parameter :: DFNT_UINT8 = 21 integer, parameter :: FULL_INTERLACE = 0 ! from hdf.inc ! local variables logical :: must_stop ! variables to define latitude and longitude - integer :: i, j, k, k_off, ll, mm, kk + integer :: i, j, k, k_off, ll, mm, kk, L integer :: time_index real, parameter :: bin_size = 0.05 @@ -153,24 +170,14 @@ subroutine read_MODISsca_hdf(& real, dimension(XGRID) :: lat_c(XGRID) real, dimension(YGRID) :: lon_c(YGRID) real, dimension(XGRID*YGRID) :: lat_1D, lon_1D - !------------------------------------------------------------- - ! UTC | 0000 | 0300 | 0600 | 0900 | 1200 | 1500 | 1800 | 2100 - ! lon | 135 180 | 90 135 | 45 90 | 0 45 | -45 0| -90 -45| -135 -90| -180 -135 - ! real:: lon_subtime(9) = (/(kk, kk=180, -180, -45)/) - integer, dimension(:), allocatable :: Snow_QA - integer, dimension(:), allocatable :: CI_Index, Cloud_index + integer, dimension(:), allocatable :: Snow_QA, CI_Index, Cloud_index - integer*2, dimension(:), allocatable :: tmpint2vec - real, dimension(:), allocatable :: tmprealvec - - character(len=*), parameter :: Iam = 'read_MOD10C1_hdf' + character(len=*), parameter :: Iam = 'read_MODISsca_hdf' character(len=400) :: err_msg - if (logit) write(logunit,*) 'Entering the hdf reader' - ! initialize N_data N_data_tmp(N_files) = 3600*7200 @@ -183,16 +190,12 @@ subroutine read_MODISsca_hdf(& lat_c = (90-bin_size/2)-bin_size*lat_ind lon_c = (-180+bin_size/2)+bin_size*lon_ind - if (logit) write(logunit, *) 'lon_c=', lon_c - - do i=1,7200 lat_1D(3600*(i-1)+1:3600*i)= lat_c lon_1D(3600*(i-1)+1:3600*i)= lon_c(i) end do ! allocate pointers (must be deallocated outside this subroutine) - must_stop = .false. if ( associated(lon) .or. associated(lat) .or. associated(MODIS_SCA) ) then @@ -219,125 +222,140 @@ subroutine read_MODISsca_hdf(& do j=1,N_files ! open and start "hdf file" if(logit) write(logunit, *) 'fname: ', fnames(j) - file_id(j) = hopen(fnames(j), DFACC_READ, num_dds_block) - status = vfstart(file_id(j)) - - allocate(tmprealvec(N_data_tmp(j))) - allocate(tmpint2vec(N_data_tmp(j))) - - vdata_id(j) = vsfatch(file_id(j), vdata_ref, 'r') - if (logit) write (logunit, *) 'vdata_id: ', vdata_id(j) - - do i=1,N_fields - ! go to start of record (zero-based count) - record_pos = vsfseek(vdata_id(j), 0) - ! pick the field to be read - status = vsfsfld(vdata_id(j), field_names(i)) - - ! read data + sd_id(j) = sfstart(fnames(j), DFACC_READ) + if(logit) write (logunit, *), 'sd_id:' , sd_id(j) + + status = sffinfo(sd_id(j), n_datasets, n_file_attrs) + ! if(logit) write(logunit, *) '! Number of data sets in the file and Number of file attributes :' + ! if(logit) write(logunit, *) 'sffinfo: ', status, n_datasets, n_file_attrs + + do i=1,N_fields + + ind(i) = sfn2index(sd_id(j), trim(field_names(i))) + if (logit) write(logunit, *), 'Field_name:', field_names(i) + if (logit) write(logunit, *), 'ind:', ind(i) + + sds_id(i) = sfselect(sd_id(j), ind(i)) + status = sfginfo(sds_id(i), var_name, rank, dim_sizes, data_type, n_attrs) + + start(1)=0 + start(2)=0 + edges(1) = dim_sizes(1) + edges(2) = dim_sizes(2) + stride(1) = 1 + stride(2) = 1 + + ! read data select case (i) case (1) - n_read = vsfread( vdata_id(j), tmprealvec, & - N_data_tmp(j), FULL_INTERLACE) - - MODIS_SCA(k_off+1:k_off+N_data_tmp(j)) = tmprealvec - - do k=1,N_data_tmp(j) + allocate(tmp_MODIS_SCA(dim_sizes(1),dim_sizes(2))) + status = sfrdata(sds_id(i), start, stride, edges, tmp_MODIS_SCA) - if ( MODIS_SCA(k+k_off) > qc_snow_cover_threshold) then - MODIS_SCA(k+k_off) = -1 - end if - end do + L=1 + do k=1, YGRID + do kk=1, XGRID + MODIS_SCA(L) = ichar(tmp_MODIS_SCA(k, kk)) + L=L+1 + end do + end do case (2) - - n_read = vsfread( vdata_id(j), tmprealvec, & - N_data_tmp(j), FULL_INTERLACE) - - CI_Index(k_off+1:k_off+N_data_tmp(j)) = tmprealvec - - case (3) - n_read = vsfread( vdata_id(j) ,tmpint2vec, & - N_data_tmp(j), FULL_INTERLACE) - - Cloud_Index(k_off+1:k_off+N_data_tmp(j)) = tmpint2vec - - case (4) - - n_read = vsfread(vdata_id(j), tmpint2vec, & - N_data_tmp(j), FULL_INTERLACE) - - Snow_QA(k_off+1:k_off+N_data_tmp(j)) = tmpint2vec + allocate(tmp_CI_Index(dim_sizes(1), dim_sizes(2))) + status = sfrdata(sds_id(i), start, stride, edges, tmp_CI_index) - ! case (5) - - ! n_read = vsfread(vdata_id(j), tmpint2vec, & - ! N_data_tmp(j), FULL_INTERLACE) + L=1 + do k=1, YGRID + do kk=1, XGRID + CI_Index(L) = ichar(tmp_CI_index(k,kk)) + L = L+1 + end do + end do + + case (3) + allocate(tmp_Cloud_index(dim_sizes(1), dim_sizes(2))) + status = sfrdata(sds_id(i), start, stride, edges, tmp_Cloud_index) + + L=1 + do k=1, YGRID + do kk=1, XGRID + Cloud_index(L) = ichar(tmp_Cloud_index(k, kk)) + end do + end do - ! lat(k_off+1:k_off+N_data_tmp(j)) = tmpint2vec + if(logit) write(logunit,*) "Cloud_Index (252):", ichar(tmp_Cloud_index(5500,3500)) + if(logit) write(logunit,*) "Cloud_Index (252):", ichar(tmp_Cloud_index(5800,3500)) - !case (6) - ! n_read = vsfread(vdata_id(j), tmpint2vec, & - ! N_data_tmp(j), FULL_INTERLACE) + case (4) + allocate(tmp_Snow_QA(dim_sizes(1),dim_sizes(2))) + status = sfrdata(sds_id(i), start, stride, edges, tmp_Snow_QA) - !lon(k_off+1:k_off+N_data_tmp(j)) = tmpint2vec + L=1 + do k=1, YGRID + do kk=1, XGRID + Snow_QA(L) = ichar(tmp_Snow_QA(k, kk)) + end do + end do case default call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'Unknown case') end select - - if (n_read/=N_data_tmp(j)) & + + if (dim_sizes(1)*dim_sizes(2)/=N_data_tmp(j)) & call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'ERROR reading hdf') + + status = sfendacc(sds_id(i)) + end do ! clean up - deallocate(tmprealvec) - deallocate(tmpint2vec) - + deallocate(tmp_MODIS_SCA) + deallocate(tmp_CI_index) + deallocate(tmp_Cloud_index) + deallocate(tmp_Snow_QA) + ! close hdf files - status = vsfdtch(vdata_id(j)) - status = vfend(file_id(j)) - status = hclose(file_id(j)) - - ! prepare next j - k_off = k_off + N_data_tmp(j) + status = sfend(file_id(j)) end do time_index = date_time%hour/3 +1 - + ! ------------------------------------- ! eliminate no-data-values and data that fail initial QC j = 0 - + if (logit) write (logunit, *) 'time_index =', time_index + if (logit) write (logunit, *) 'lon_subtime_front = ', lon_subtime(time_index) + if (logit) write (logunit, *) 'lon_subtime_back = ', lon_subtime(time_index+1) do i=1,N_data - if (logit) write (logunit, *) 'time_index =', time_index - - if ( (MODIS_SCA(i)>0.) .and. & ! any neg is nodata - (CI_Index(i)>qc_clear_index_threshold) .and. & - (Snow_QA(i)lon_subtime(time_index+1)) & !depending on the time info + if ( (MODIS_SCA(i)>=0 .and. MODIS_SCA(i)<=100) .and. & ! any neg is nodata + (lon_1D(i)<=lon_subtime(time_index)) .and. & !selection of longitudal band + (lon_1D(i)>lon_subtime(time_index+1)) .and. & + (CI_Index(i)>qc_clear_index_threshold) .and. & + (CI_Index(i)<=qc_clear_index_max_threshold) .and. & + (Cloud_index(i)/=qc_antarctica) .and. & + (Snow_QA(i)0) then allocate(tmp_tile_num(N_tmp)) - - call get_tile_num_from_latlon(N_catd, tile_coord, & - tile_grid_d, N_tile_in_cell_ij, tile_num_in_cell_ij, & - N_tmp, tmp_lat, tmp_lon, & - tmp_tile_num) - + + call get_tile_num_for_obs(N_catd, tile_coord, & + tile_grid_d, N_tile_in_cell_ij, tile_num_in_cell_ij, & + N_tmp, tmp_lat(1:N_tmp), tmp_lon(1:N_tmp), & + this_obs_param, & + tmp_tile_num(1:N_tmp) ) + + !if(logit) write(logunit,*) 'tmp_tile_num:', tmp_tile_num + MODIS_obs = 0. N_obs_in_tile = 0 - do i=1,N_files + do i=1,N_tmp ind = tmp_tile_num(i) if (ind>0) then @@ -489,6 +509,7 @@ subroutine read_obs_MODISsca( & end if end do + !normalize do i=1,N_catd if (N_obs_in_tile(i)>1) then MODIS_obs(i) = MODIS_obs(i)/real(N_obs_in_tile(i)) @@ -7371,7 +7392,6 @@ subroutine read_obs( & logical, intent(in) :: write_obslog ! outputs: - real, intent(out), dimension(N_catd) :: tmp_obs real, intent(out), dimension(N_catd) :: tmp_std_obs real, intent(out), dimension(N_catd) :: tmp_lon diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index e88548fc..ae3dbf7e 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -51,7 +51,6 @@ module clsm_ensupd_upd_routines catprogn2wesn, & catprogn2htsn, & catprogn2ghtcnt, & - cat_diagS_type, & assignment (=), & operator (+), & operator (/) @@ -1332,7 +1331,7 @@ subroutine get_obs_pred( & call StieglitzSnow_calc_asnow( N_snow, N_catl, & catprogn2wesn(N_catl,cat_progn(:,n_e)), & - asnow ) + asnow) call catch_calc_tsurf_excl_snow( N_catl, & cat_progn(:,n_e)%tc1, cat_progn(:,n_e)%tc2, cat_progn(:,n_e)%tc4, & @@ -1347,7 +1346,7 @@ subroutine get_obs_pred( & if (get_asnow_l) then !jpark50 call StieglitzSnow_calc_asnow( N_snow, N_catl, & catprogn2wesn(N_catl,cat_progn(:,n_e)), & - asnow) + asnow_l) end if if (get_Tb_l) then @@ -1481,6 +1480,7 @@ subroutine get_obs_pred( & ! added get_asnow_lH at the function jpark50 if (allocated(tile_data_l)) deallocate(tile_data_l) allocate(tile_data_l(N_catl,N_fields,N_ens)) + call get_obs_pred_comm_helper( N_catl, N_ens, N_TbuniqFreqAngRTMid, & get_sfmc_lH, get_rzmc_lH, get_tsurf_lH, get_FT_lH, get_asnow_lH, get_Tb_lH, N_fields, & option=1, tile_data=tile_data_l, & @@ -1488,7 +1488,6 @@ subroutine get_obs_pred( & Tb_h=Tb_h_l, Tb_v=Tb_v_l, asnow=asnow_l ) ! communicate tile_data_l as needed and get tile_data_lH - call get_tiles_in_halo( N_catl, N_fields, N_ens, tile_data_l, tile_coord_l, & N_catf, tile_coord_f, N_catl_vec, low_ind, xhalo, yhalo, & N_catlH, tile_data_lH=tile_data_lH ) @@ -1548,7 +1547,7 @@ subroutine get_obs_pred( & tile_grid_lH, maxval(N_tile_in_cell_ij_lH), tile_num_in_cell_ij_lH ) end if - + if(logit) write(logunit,*) 'Tile change completed' ! ----------------------- allocate(ind_tmp( N_catlH)) @@ -1974,7 +1973,7 @@ subroutine get_obs_pred( & end do end if - + if(logit) write(logunit,*) 'Ending get_obs_pred' ! ---------------------------------------------------------------- end subroutine get_obs_pred @@ -3158,7 +3157,6 @@ subroutine get_obs_pert( N_ens, N_obs, N_obs_param, & ! ----------------------------------------------------------------- nullify(obs_pert_param) - ! determine pert_grid_lH ! - pert_grid_lH is the local grid for which perturbations are needed ! - pert_grid_lH is larger than pert_grid_l by the "halo" @@ -3400,7 +3398,8 @@ subroutine get_obs_pert( N_ens, N_obs, N_obs_param, & !call check_obs_pert( N_ens, N_catd, N_obs, cat_param, Observations, & ! Obs_pert ) - + if(logit) write(logunit, *) 'exit get_obs_pert' + end subroutine get_obs_pert ! ********************************************************************* @@ -3412,7 +3411,7 @@ subroutine cat_enkf_increments( & Observations, Obs_pred, Obs_pert, & cat_param, & xcompact, ycompact, fcsterr_inflation_fac, & - cat_progn, cat_progn_incr, met_force, cat_diagS) + cat_progn, cat_progn_incr, met_force) ! get increments for Catchment prognostic variables ! @@ -3463,7 +3462,7 @@ subroutine cat_enkf_increments( & real, intent(in), dimension(N_obs,N_ens) :: Obs_pert type(met_force_type), dimension(N_catd), intent(in) :: met_force !jpark50 - type(cat_diagS_type), dimension(N_catd), intent(in) :: cat_diagS !jpark50 + !type(cat_diagS_type), dimension(N_catd), intent(in) :: cat_diagS !jpark50 type(cat_param_type), dimension(N_catd), intent(in) :: cat_param real, intent(in) :: xcompact, ycompact, fcsterr_inflation_fac @@ -3535,6 +3534,7 @@ subroutine cat_enkf_increments( & real, dimension( N_catd) :: tsurf_ensavg real, dimension( N_catd) :: SWE_ensavg real, dimension( N_catd) :: tp1_ensavg + real, dimension( N_catd) :: asnow_ensavg type(obs_param_type) :: this_obs_param @@ -3657,19 +3657,21 @@ subroutine cat_enkf_increments( & SWE_ensavg = 0. tsurf_ensavg = 0. tp1_ensavg = 0. - + asnow_ensavg = 0. + do n_e=1,N_ens SWE_ensavg = SWE_ensavg + SWE( :,n_e) tsurf_ensavg = tsurf_ensavg + tsurf( :,n_e) tp1_ensavg = tp1_ensavg + tp( 1,:,n_e) - + asnow_ensavg = asnow_ensavg + asnow( :,n_e) end do SWE_ensavg = SWE_ensavg /real(N_ens) tsurf_ensavg = tsurf_ensavg /real(N_ens) tp1_ensavg = tp1_ensavg /real(N_ens) - + asnow_ensavg = asnow_ensavg /real(N_ens) + ! --------------------------------------------------------------------- select_update_type: select case (update_type) @@ -4066,18 +4068,29 @@ subroutine cat_enkf_increments( & !identify the species ID number of interest N_select_varnames = 1 select_varnames(1) = 'asnow' - + call get_select_species( & N_select_varnames, select_varnames(1:N_select_varnames), & N_obs_param, obs_param, N_select_species, select_species ) + + if(logit) write(logunit,*) 'select_species=', select_species + if(logit) write(logunit,*) 'N_catd=', N_catd !Rule-based snow SCF update - !loop through all tiles and compte increments + allocate(select_tilenum(1)) - do kk=1,N_catd + do n=1,N_catd ! find observations for catchment n + if(logit) write(logunit,*) 'l2f', l2f(n) + if(logit) write(logunit,*) 'n: ', n + if(logit) write(logunit,*) 'Observations%species', Observations(ind_obs(1))%species + if(logit) write(logunit,*) 'N_obs', N_obs + if(logit) write(logunit,*) 'select_tilenum', select_tilenum + if(logit) write(logunit,*) 'N_selected_obs', N_selected_obs + select_tilenum(1) = l2f(n) + call get_ind_obs( & N_obs, Observations, & 1, select_tilenum, & @@ -4085,79 +4098,114 @@ subroutine cat_enkf_increments( & N_selected_obs, ind_obs ) if (N_selected_obs == 1) then + if(logit) write(logunit,*) 'N_selected_obs', N_selected_obs + if(logit) write(logunit,*) 'ind_obs', ind_obs(1) + if(logit) write(logunit,*) 'Observations', Observations(ind_obs(1))%obs + if(logit) write(logunit,*) 'asnow_ensavg', asnow_ensavg(n) do n_e=1,N_ens ! for each ensemble member - if(cat_diagS(kk)%asnow <= Observations(ind_obs(1))%obs * model_threshold) then + if(asnow_ensavg(n) <= Observations(ind_obs(1))%obs * model_threshold) then if (logit) write (logunit,*) 'Add_snow_section: ',& - 'MODIS_SCF = ', observations(ind_obs(1))%obs, 'model_SCF = ', cat_diagS(kk)%asnow + 'MODIS_SCF = ', Observations(ind_obs(1))%obs, 'model_SCF = ', asnow_ensavg(n) - do i=1,N_SNOW + do i=1,N_snow !a) Snow water equivalent (add equally the snow to all three layers) - cat_progn_incr(kk, n_e)%wesn(i) = & + cat_progn_incr(n, n_e)%wesn(i) = & ( Observations(ind_obs(1))%obs - & - cat_diagS(kk)%asnow/model_threshold ) * (wesn_added/float(N_SNOW)) + asnow_ensavg(n)/model_threshold ) * (wesn_added/float(N_snow)) !b) snow depth - if(cat_progn(kk,n_e)%sndz(i) > eps) then + if(cat_progn(n,n_e)%sndz(i) > eps) then !Determine the fractional snow coverage - wesn_sum_old(kk,n_e) = sum( cat_progn(kk,n_e)%wesn) - areasc_old (kk,n_e) = min(wesn_sum_old(kk,n_e)/wemin,1.) + wesn_sum_old(n,n_e) = sum(cat_progn(n,n_e)%wesn) + areasc_old (n,n_e) = min(wesn_sum_old(n,n_e)/wemin,1.) !Estimate the density of the ld layers of snow - dens_layer = max(cat_progn(kk,n_e)%wesn(i)/ & - (cat_progn(kk,n_e)%sndz(i)*areasc_old(kk,n_e)),RHOFS) + dens_layer = max(cat_progn(n,n_e)%wesn(i)/ & + (cat_progn(n,n_e)%sndz(i)*areasc_old(n,n_e)),RHOFS) - cat_progn_incr(kk,n_e)%sndz(i)=& - cat_progn_incr(kk,n_e)%wesn(i)/dens_layer + cat_progn_incr(n,n_e)%sndz(i)=& + cat_progn_incr(n,n_e)%wesn(i)/dens_layer else dens_layer = rhofs - cat_progn_incr(kk,n_e)%sndz(i) = cat_progn_incr(kk,n_e)%wesn(i)/dens_layer + cat_progn_incr(n,n_e)%sndz(i) = cat_progn_incr(n,n_e)%wesn(i)/dens_layer end if !c) heat content - TSN=min(met_force(kk)%Tair-MAPL_TICE, 0.0) - cat_progn_incr(n,n_e)%htsn(i) = (TSN*cpw_pub-MAPL_ALHF)*cat_progn_incr(kk,n_e)%wesn(i) + TSN=min(met_force(n)%Tair-MAPL_TICE, 0.0) + cat_progn_incr(n,n_e)%htsn(i) = (TSN*cpw_pub-MAPL_ALHF)*cat_progn_incr(n,n_e)%wesn(i) end do + if (n== 595) then + if (logit) write (logunit, *) + if (logit) write (logunit, *) '********Adding_Snow***********' + if (logit) write (logunit, *) + if (logit) write (logunit, *) 'tile_number = ',n + if (logit) write (logunit, *) 'add_snow_density = ', dens_layer + if (logit) write (logunit, *) 'added_wesn = ', cat_progn_incr(n,n_e)%wesn + if (logit) write (logunit, *) 'added_sndz = ', cat_progn_incr(n,n_e)%sndz + if (logit) write (logunit, *) 'added_htsn = ', cat_progn_incr(n,n_e)%htsn + endif + elseif (Observations(ind_obs(1))%obs <= obs_threshold) then if (logit) write (logunit,*) 'Remove snow section: ', & - 'MODIS_SCF = ', Observations(ind_obs(1))%obs, 'model_SCF = ', cat_diagS(kk)%asnow + 'MODIS_SCF = ', Observations(ind_obs(1))%obs, 'model_SCF = ', asnow_ensavg(n) do i=1,N_snow - cat_progn_incr(kk,n_e)%wesn(i) = & + cat_progn_incr(n,n_e)%wesn(i) = & -cat_progn(n,n_e)%wesn(i)*(1-Observations(ind_obs(1))%obs/obs_threshold ) !b) snow depth - if (cat_progn(kk,n_e)%sndz(i) > eps) then - wesn_sum_old(kk,n_e)=sum(cat_progn(kk,n_e)%wesn) - areasc_old(kk,n_e)=min(wesn_sum_old(kk,n_e)/wemin,1.) + if (cat_progn(n,n_e)%sndz(i) > eps) then + wesn_sum_old(n,n_e)=sum(cat_progn(n,n_e)%wesn) + areasc_old(n,n_e)=min(wesn_sum_old(n,n_e)/wemin,1.) !Estimate the density of the old layers of snow - dens_layer = max( cat_progn(kk,n_e)%wesn(i)/& - (cat_progn(kk,n_e)%sndz(i)*areasc_old(kk,n_e)),rhofs) + dens_layer = max( cat_progn(n,n_e)%wesn(i)/& + (cat_progn(n,n_e)%sndz(i)*areasc_old(n,n_e)),rhofs) - cat_progn_incr(kk,n_e)%sndz(i)=& - cat_progn_incr(kk,n_e)%wesn(i)/dens_layer + cat_progn_incr(n,n_e)%sndz(i)=& + cat_progn_incr(n,n_e)%wesn(i)/dens_layer else dens_layer = rhofs - cat_progn_incr(kk,n_e)%sndz(i) = cat_progn_incr(kk,n_e)%wesn(i)/dens_layer + cat_progn_incr(n,n_e)%sndz(i) = cat_progn_incr(n,n_e)%wesn(i)/dens_layer end if !c) heat content - TSN=min(met_force(kk)%Tair-MAPL_TICE, 0.0) - cat_progn_incr(kk,n_e)%htsn(i) = -(TSN*cpw_pub-MAPL_ALHF)*cat_progn_incr(kk,n_e)%wesn(i) + TSN=min(met_force(n)%Tair-MAPL_TICE, 0.0) + cat_progn_incr(n,n_e)%htsn(i) = -(TSN*cpw_pub-MAPL_ALHF)*cat_progn_incr(n,n_e)%wesn(i) end do + if (n== 595) then + if (logit) write (logunit, *) + if (logit) write (logunit, *) '********Remove_Snow***********' + if (logit) write (logunit, *) + if (logit) write (logunit, *) 'tile_number = ',n + if (logit) write (logunit, *) 'remove_snow_density = ', dens_layer + if (logit) write (logunit, *) 'remove_wesn = ', cat_progn_incr(n,n_e)%wesn + if (logit) write (logunit, *) 'remove_sndz = ', cat_progn_incr(n,n_e)%sndz + if (logit) write (logunit, *) 'remove_htsn = ', cat_progn_incr(n,n_e)%htsn + endif + else if (logit) write (logunit, *) 'No_add_No_removal_section: ', & - 'MODIS_SCF = ', Observations(ind_obs(1))%obs, 'model_SCF = ',cat_diagS(kk)%asnow + 'MODIS_SCF = ', Observations(ind_obs(1))%obs, 'model_SCF = ',asnow_ensavg(n) do i=1,N_snow - cat_progn_incr(kk,n_e)%wesn(i) = 0.0 - cat_progn_incr(kk,n_e)%sndz(i) = 0.0 - cat_progn_incr(kk,n_e)%htsn(i) = 0.0 + cat_progn_incr(n,n_e)%wesn(i) = 0.0 + cat_progn_incr(n,n_e)%sndz(i) = 0.0 + cat_progn_incr(n,n_e)%htsn(i) = 0.0 end do + if (n== 595) then + if (logit) write (logunit, *) + if (logit) write (logunit, *) '********No_add_or_removal***********' + if (logit) write (logunit, *) + if (logit) write (logunit, *) 'tile_number = ',n + if (logit) write (logunit, *) 'incr_wesn = ', cat_progn_incr(n,n_e)%wesn + if (logit) write (logunit, *) 'incr_sndz = ', cat_progn_incr(n,n_e)%sndz + if (logit) write (logunit, *) 'incr_htsn = ', cat_progn_incr(n,n_e)%htsn + endif end if end do @@ -4603,7 +4651,7 @@ subroutine cat_enkf_increments( & ! NO checks of prognostics after update, this is now done after ! increments have been applied. ! - reichle, 18 Oct 2005 - + if (logit) write(logunit,*) 'Cat_enkf_increment completed' end subroutine cat_enkf_increments ! ********************************************************************** @@ -4725,7 +4773,7 @@ subroutine get_ind_obs( & k = 0 ! counter for selected obs do i=1,N_obs - + if (any(Observations(i)%tilenum == select_tilenum)) then k = k+1 From c1a3f23bcac9eb7814d27c20fa6a4dfe63c8d1c7 Mon Sep 17 00:00:00 2001 From: Jongmin Park Date: Mon, 8 Nov 2021 11:09:58 -0500 Subject: [PATCH 010/308] Summary of the commits made on 11/08/2021 : This commit has been made to update the error status located @ subroutine get_ind_obs() : Basically, not significant change made on the code compared to the previous commit. All the print statements for debugging purposes are commented out : Minor change made on the MODIS SCA reader(in clsm_ensupd_read_obs.F90) to correctly read the MODIS observation : Things need to be done 1) Check the compressed vector ('Observation') lat, long, and tilenum to see whether it correctly calculates or not 2) Check the tile_grid properties --- .../clsm_ensupd_enkf_update.F90 | 2 +- .../clsm_ensupd_read_obs.F90 | 165 ++++++++++-------- .../clsm_ensupd_upd_routines.F90 | 127 ++++++++------ 3 files changed, 170 insertions(+), 124 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 index 15c80220..9afa4e48 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 @@ -320,7 +320,7 @@ subroutine get_enkf_increments( & integer, dimension(:), allocatable, target :: ind_obsl_assim integer, dimension(:), pointer :: ptr2indx => null() type(varLenIntArr) :: indObsAna_vec(numprocs) - integer, dimension(:), allocatable :: tmp_ind_obs + integer, dimension(:), allocatable :: tmp_ind_obs type(obs_type), dimension(:), allocatable :: Obs_f_assim, Obs_ana ! collect obs before distributing for ana real, allocatable :: Obs_pred_f_assim(:), Obs_pred_ana(:,:) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 84e89d99..7fc17c31 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -116,7 +116,7 @@ subroutine read_MODISsca_hdf(& real, dimension(:), pointer, allocatable :: lon, lat character(1), dimension(:,:), allocatable :: tmp_MODIS_SCA, tmp_CI_Index, tmp_Cloud_index, tmp_Snow_QA - real, dimension(:), pointer :: MODIS_SCA + real, dimension(:), pointer :: MODIS_SCA, MODIS_SCA_raw type(date_time_type),intent(in) :: date_time ! loading the UTC hour information to constrain the longitude of MODIS obs. @@ -129,12 +129,12 @@ subroutine read_MODISsca_hdf(& 'Day_CMG_Cloud_Obscured ', & !3 'Snow_Spatial_QA '/) !4 - integer, parameter :: nodata = -9999 !note: integer + integer,parameter :: nodata = -9999 !note: integer integer,parameter :: qc_clear_index_threshold = 20 !screen for sufficiently clear condition integer,parameter :: qc_clear_index_max_threshold = 100 ! removing the lake ice, night obs, ocean etc. integer,parameter :: qc_snow_spatial_threshold = 3 !screen for basic data quality (e.g., 0:best 1:good 2:OK 3:poor, 4:others) integer,parameter :: qc_snow_cover_threshold = 100 !screen for areas inland water, ocean, cloud obscured and fill - integer, parameter :: qc_antarctica = 252 ! screen for antarctica + integer,parameter :: qc_antarctica = 252 ! screen for antarctica !declariations of hdf functions integer:: sfstart, sffinfo, sfselect, sfn2index, sfginfo, sfrdata @@ -154,7 +154,7 @@ subroutine read_MODISsca_hdf(& integer, parameter :: FULL_INTERLACE = 0 ! from hdf.inc ! local variables - logical :: must_stop + logical :: must_stop, keep_data ! variables to define latitude and longitude integer :: i, j, k, k_off, ll, mm, kk, L @@ -181,11 +181,11 @@ subroutine read_MODISsca_hdf(& ! initialize N_data N_data_tmp(N_files) = 3600*7200 - if (logit) write(logunit, *) 'N_data_tmp=', N_data_tmp(1) + !if(logit) write(logunit, *) 'N_data_tmp=', N_data_tmp(1) N_data = sum(N_data_tmp) - if (logit) write(logunit, *) 'N_data', N_data + !if (logit) write(logunit, *) 'N_data', N_data lat_c = (90-bin_size/2)-bin_size*lat_ind lon_c = (-180+bin_size/2)+bin_size*lon_ind @@ -209,7 +209,7 @@ subroutine read_MODISsca_hdf(& allocate(lat(N_data)) allocate(lon(N_data)) - allocate(MODIS_SCA(N_data)) + allocate(MODIS_SCA_raw(N_data)) allocate(CI_Index(N_data)) allocate(Snow_QA(N_data)) @@ -221,10 +221,10 @@ subroutine read_MODISsca_hdf(& do j=1,N_files ! open and start "hdf file" - if(logit) write(logunit, *) 'fname: ', fnames(j) + !if(logit) write(logunit, *) 'fname: ', fnames(j) sd_id(j) = sfstart(fnames(j), DFACC_READ) - if(logit) write (logunit, *), 'sd_id:' , sd_id(j) + !if(logit) write (logunit, *), 'sd_id:' , sd_id(j) status = sffinfo(sd_id(j), n_datasets, n_file_attrs) ! if(logit) write(logunit, *) '! Number of data sets in the file and Number of file attributes :' @@ -233,8 +233,8 @@ subroutine read_MODISsca_hdf(& do i=1,N_fields ind(i) = sfn2index(sd_id(j), trim(field_names(i))) - if (logit) write(logunit, *), 'Field_name:', field_names(i) - if (logit) write(logunit, *), 'ind:', ind(i) + ! if (logit) write(logunit, *), 'Field_name:', field_names(i) + ! if (logit) write(logunit, *), 'ind:', ind(i) sds_id(i) = sfselect(sd_id(j), ind(i)) status = sfginfo(sds_id(i), var_name, rank, dim_sizes, data_type, n_attrs) @@ -253,23 +253,23 @@ subroutine read_MODISsca_hdf(& allocate(tmp_MODIS_SCA(dim_sizes(1),dim_sizes(2))) status = sfrdata(sds_id(i), start, stride, edges, tmp_MODIS_SCA) - L=1 + L=0 do k=1, YGRID do kk=1, XGRID - MODIS_SCA(L) = ichar(tmp_MODIS_SCA(k, kk)) - L=L+1 + L=L+1 + MODIS_SCA_raw(L) = ichar(tmp_MODIS_SCA(k, kk)) end do end do case (2) allocate(tmp_CI_Index(dim_sizes(1), dim_sizes(2))) status = sfrdata(sds_id(i), start, stride, edges, tmp_CI_index) - - L=1 + + L=0 do k=1, YGRID do kk=1, XGRID + L=L+1 CI_Index(L) = ichar(tmp_CI_index(k,kk)) - L = L+1 end do end do @@ -277,23 +277,26 @@ subroutine read_MODISsca_hdf(& allocate(tmp_Cloud_index(dim_sizes(1), dim_sizes(2))) status = sfrdata(sds_id(i), start, stride, edges, tmp_Cloud_index) - L=1 + L=0 do k=1, YGRID do kk=1, XGRID + L = L+1 Cloud_index(L) = ichar(tmp_Cloud_index(k, kk)) end do end do - - if(logit) write(logunit,*) "Cloud_Index (252):", ichar(tmp_Cloud_index(5500,3500)) - if(logit) write(logunit,*) "Cloud_Index (252):", ichar(tmp_Cloud_index(5800,3500)) - + !if(logit) write(logunit,*) "L:", L + !if(logit) write(logunit,*) "size of Cloud_index", size(Cloud_index) + !if(logit) write(logunit,*) "Cloud_Index (252):", ichar(tmp_Cloud_index(5500,3500)) + !if(logit) write(logunit,*) "Cloud_Index (5499*3600+3500):", Cloud_index(19799900) + case (4) allocate(tmp_Snow_QA(dim_sizes(1),dim_sizes(2))) status = sfrdata(sds_id(i), start, stride, edges, tmp_Snow_QA) - L=1 + L=0 do k=1, YGRID do kk=1, XGRID + L = L+1 Snow_QA(L) = ichar(tmp_Snow_QA(k, kk)) end do end do @@ -303,9 +306,10 @@ subroutine read_MODISsca_hdf(& call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'Unknown case') end select - if (dim_sizes(1)*dim_sizes(2)/=N_data_tmp(j)) & - call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'ERROR reading hdf') - + if (dim_sizes(1)*dim_sizes(2)/=N_data_tmp(j)) then + call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'ERROR reading hdf') + end if + status = sfendacc(sds_id(i)) end do @@ -326,42 +330,52 @@ subroutine read_MODISsca_hdf(& ! ------------------------------------- ! eliminate no-data-values and data that fail initial QC - j = 0 - if (logit) write (logunit, *) 'time_index =', time_index - if (logit) write (logunit, *) 'lon_subtime_front = ', lon_subtime(time_index) - if (logit) write (logunit, *) 'lon_subtime_back = ', lon_subtime(time_index+1) + j=0 + allocate(MODIS_SCA(N_data)) + do i=1,N_data - if ( (MODIS_SCA(i)>=0 .and. MODIS_SCA(i)<=100) .and. & ! any neg is nodata - (lon_1D(i)<=lon_subtime(time_index)) .and. & !selection of longitudal band - (lon_1D(i)>lon_subtime(time_index+1)) .and. & - (CI_Index(i)>qc_clear_index_threshold) .and. & - (CI_Index(i)<=qc_clear_index_max_threshold) .and. & - (Cloud_index(i)/=qc_antarctica) .and. & - (Snow_QA(i)=0 .and. MODIS_SCA_raw(i)<=100) .and. & ! any neg is nodata + (lon_1D(i)<=lon_subtime(time_index)) .and. & !selection of longitudal band + (lon_1D(i)>lon_subtime(time_index+1)) .and. & + (CI_Index(i)>qc_clear_index_threshold) .and. & + (CI_Index(i)<=qc_clear_index_max_threshold) .and. & + (Cloud_index(i)/=qc_antarctica) .and. & + (Snow_QA(i)0) then + + ind = tmp_tile_num(i) ! 1<=tmp_tile_num<=N_catd (unless nodata) + + if (ind>0) then ! this step eliminates obs outside domain MODIS_obs(ind) = MODIS_obs(ind) + tmp_obs(i) N_obs_in_tile(ind) = N_obs_in_tile(ind) + 1 end if + end do + !if(logit) write(logunit,*) 'N_obs_in_tile', N_obs_in_tile !normalize do i=1,N_catd - if (N_obs_in_tile(i)>1) then + if (N_obs_in_tile(i)>0) then MODIS_obs(i) = MODIS_obs(i)/real(N_obs_in_tile(i)) + else if (N_obs_in_tile(i) == 0) then MODIS_obs(i) = this_obs_param%nodata end if end do + !if(logit) write(logunit,*), 'MODIS_obs (after normalization)', MODIS_obs + if (associated(tmp_tile_num)) deallocate (tmp_tile_num) do i=1, N_catd @@ -531,7 +553,9 @@ subroutine read_obs_MODISsca( & end if end if - + + !if(logit) write(logunit, *) 'found_obs=', found_obs + if (associated(tmp_obs)) deallocate(tmp_obs) if (associated(tmp_lon)) deallocate(tmp_lon) if (associated(tmp_lat)) deallocate(tmp_lat) @@ -8661,7 +8685,8 @@ subroutine collect_obs( if (scaled_obs) any_scaled_obs = .true. end if - + if (logit) write(logunit,*) 'found_obs (after read_obs)=', found_obs + ! put "tmp_obs" (in "tile" space) into "compressed" vector "Observations_l" ! ! each observation is "managed" ("administered") by the processor that @@ -8929,7 +8954,9 @@ subroutine put_into_Observations( this_obs_param, N_obs_max, N_catd, l2f, & real :: nodatavalue, tol ! ------------------------------------------------------ - + + !if(logit) write(logunit,*) 'Entering put_into_Observations' + nodatavalue = this_obs_param%nodata tol = abs(nodatavalue*nodata_tolfrac_generic) @@ -8954,14 +8981,16 @@ subroutine put_into_Observations( this_obs_param, N_obs_max, N_catd, l2f, & Observations(obs_count)%obsvar = this_obs_param%errstd**2 end if - + !if(logit) write(logunit,*) 'i:', i, 'tilenum', l2f(i) + Observations(obs_count)%tilenum = l2f(i) Observations(obs_count)%time = tmp_time(i) Observations(obs_count)%lat = tmp_lat(i) Observations(obs_count)%lon = tmp_lon(i) - + + !if(logit) write(logunit, *) 'Obs species:', this_obs_param%species Observations(obs_count)%species = this_obs_param%species Observations(obs_count)%assim = this_obs_param%assim .and. tmp_assim(i) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index ae3dbf7e..8e2e0a29 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -1547,7 +1547,7 @@ subroutine get_obs_pred( & tile_grid_lH, maxval(N_tile_in_cell_ij_lH), tile_num_in_cell_ij_lH ) end if - if(logit) write(logunit,*) 'Tile change completed' + !if(logit) write(logunit,*) 'Tile change completed' ! ----------------------- allocate(ind_tmp( N_catlH)) @@ -1973,7 +1973,7 @@ subroutine get_obs_pred( & end do end if - if(logit) write(logunit,*) 'Ending get_obs_pred' + !if(logit) write(logunit,*) 'Ending get_obs_pred' ! ---------------------------------------------------------------- end subroutine get_obs_pred @@ -3398,7 +3398,7 @@ subroutine get_obs_pert( N_ens, N_obs, N_obs_param, & !call check_obs_pert( N_ens, N_catd, N_obs, cat_param, Observations, & ! Obs_pert ) - if(logit) write(logunit, *) 'exit get_obs_pert' + !if(logit) write(logunit, *) 'exit get_obs_pert' end subroutine get_obs_pert @@ -4068,13 +4068,17 @@ subroutine cat_enkf_increments( & !identify the species ID number of interest N_select_varnames = 1 select_varnames(1) = 'asnow' - + + !if(logit) write(logunit,*) 'Entering get_select_species' + call get_select_species( & N_select_varnames, select_varnames(1:N_select_varnames), & N_obs_param, obs_param, N_select_species, select_species ) - if(logit) write(logunit,*) 'select_species=', select_species - if(logit) write(logunit,*) 'N_catd=', N_catd + !if(logit) write(logunit,*) 'output of select_species=', select_species + !if(logit) write(logunit,*) 'output of N_select_species=', N_select_species + + !if(logit) write(logunit,*) 'N_catd=', N_catd !Rule-based snow SCF update allocate(select_tilenum(1)) @@ -4082,14 +4086,15 @@ subroutine cat_enkf_increments( & do n=1,N_catd ! find observations for catchment n - if(logit) write(logunit,*) 'l2f', l2f(n) - if(logit) write(logunit,*) 'n: ', n - if(logit) write(logunit,*) 'Observations%species', Observations(ind_obs(1))%species - if(logit) write(logunit,*) 'N_obs', N_obs - if(logit) write(logunit,*) 'select_tilenum', select_tilenum - if(logit) write(logunit,*) 'N_selected_obs', N_selected_obs + ! if(logit) write(logunit,*) 'l2f', l2f(n) + ! if(logit) write(logunit,*) 'n: ', n + ! if(logit) write(logunit,*) 'N_obs', N_obs select_tilenum(1) = l2f(n) + + ! if(logit) write(logunit,*) 'select_tilenum', select_tilenum(1) + ! if(logit) write(logunit,*) 'Entering get_ind_obs subroutine' + ! if(logit) write(logunit,*) 'size of Observation', size(Observations) call get_ind_obs( & N_obs, Observations, & @@ -4097,16 +4102,19 @@ subroutine cat_enkf_increments( & N_select_species, select_species(1:N_select_species), & N_selected_obs, ind_obs ) + ! if(logit) write(logunit,*) 'Observations%species', Observations(ind_obs(1))%species + if (N_selected_obs == 1) then - if(logit) write(logunit,*) 'N_selected_obs', N_selected_obs - if(logit) write(logunit,*) 'ind_obs', ind_obs(1) - if(logit) write(logunit,*) 'Observations', Observations(ind_obs(1))%obs - if(logit) write(logunit,*) 'asnow_ensavg', asnow_ensavg(n) + + ! if(logit) write(logunit,*) 'N_selected_obs', N_selected_obs + ! if(logit) write(logunit,*) 'ind_obs', ind_obs(1) + ! if(logit) write(logunit,*) 'Observations', Observations(ind_obs(1))%obs + ! if(logit) write(logunit,*) 'asnow_ensavg', asnow_ensavg(n) do n_e=1,N_ens ! for each ensemble member if(asnow_ensavg(n) <= Observations(ind_obs(1))%obs * model_threshold) then - if (logit) write (logunit,*) 'Add_snow_section: ',& - 'MODIS_SCF = ', Observations(ind_obs(1))%obs, 'model_SCF = ', asnow_ensavg(n) + ! if (logit) write (logunit,*) 'Add_snow_section: ',& + ! 'MODIS_SCF = ', Observations(ind_obs(1))%obs, 'model_SCF = ', asnow_ensavg(n) do i=1,N_snow !a) Snow water equivalent (add equally the snow to all three layers) @@ -4136,20 +4144,20 @@ subroutine cat_enkf_increments( & cat_progn_incr(n,n_e)%htsn(i) = (TSN*cpw_pub-MAPL_ALHF)*cat_progn_incr(n,n_e)%wesn(i) end do - if (n== 595) then - if (logit) write (logunit, *) - if (logit) write (logunit, *) '********Adding_Snow***********' - if (logit) write (logunit, *) - if (logit) write (logunit, *) 'tile_number = ',n - if (logit) write (logunit, *) 'add_snow_density = ', dens_layer - if (logit) write (logunit, *) 'added_wesn = ', cat_progn_incr(n,n_e)%wesn - if (logit) write (logunit, *) 'added_sndz = ', cat_progn_incr(n,n_e)%sndz - if (logit) write (logunit, *) 'added_htsn = ', cat_progn_incr(n,n_e)%htsn - endif + ! if (n== 595) then + ! if (logit) write (logunit, *) + ! if (logit) write (logunit, *) '********Adding_Snow***********' + ! if (logit) write (logunit, *) + ! if (logit) write (logunit, *) 'tile_number = ',n + ! if (logit) write (logunit, *) 'add_snow_density = ', dens_layer + ! if (logit) write (logunit, *) 'added_wesn = ', cat_progn_incr(n,n_e)%wesn + ! if (logit) write (logunit, *) 'added_sndz = ', cat_progn_incr(n,n_e)%sndz + ! if (logit) write (logunit, *) 'added_htsn = ', cat_progn_incr(n,n_e)%htsn + ! endif elseif (Observations(ind_obs(1))%obs <= obs_threshold) then - if (logit) write (logunit,*) 'Remove snow section: ', & - 'MODIS_SCF = ', Observations(ind_obs(1))%obs, 'model_SCF = ', asnow_ensavg(n) + ! if (logit) write (logunit,*) 'Remove snow section: ', & + ! 'MODIS_SCF = ', Observations(ind_obs(1))%obs, 'model_SCF = ', asnow_ensavg(n) do i=1,N_snow cat_progn_incr(n,n_e)%wesn(i) = & @@ -4176,36 +4184,36 @@ subroutine cat_enkf_increments( & cat_progn_incr(n,n_e)%htsn(i) = -(TSN*cpw_pub-MAPL_ALHF)*cat_progn_incr(n,n_e)%wesn(i) end do - if (n== 595) then - if (logit) write (logunit, *) - if (logit) write (logunit, *) '********Remove_Snow***********' - if (logit) write (logunit, *) - if (logit) write (logunit, *) 'tile_number = ',n - if (logit) write (logunit, *) 'remove_snow_density = ', dens_layer - if (logit) write (logunit, *) 'remove_wesn = ', cat_progn_incr(n,n_e)%wesn - if (logit) write (logunit, *) 'remove_sndz = ', cat_progn_incr(n,n_e)%sndz - if (logit) write (logunit, *) 'remove_htsn = ', cat_progn_incr(n,n_e)%htsn - endif + ! if (n== 595) then + ! if (logit) write (logunit, *) + ! if (logit) write (logunit, *) '********Remove_Snow***********' + ! if (logit) write (logunit, *) + ! if (logit) write (logunit, *) 'tile_number = ',n + ! if (logit) write (logunit, *) 'remove_snow_density = ', dens_layer + ! if (logit) write (logunit, *) 'remove_wesn = ', cat_progn_incr(n,n_e)%wesn + ! if (logit) write (logunit, *) 'remove_sndz = ', cat_progn_incr(n,n_e)%sndz + ! if (logit) write (logunit, *) 'remove_htsn = ', cat_progn_incr(n,n_e)%htsn + ! endif else - if (logit) write (logunit, *) 'No_add_No_removal_section: ', & - 'MODIS_SCF = ', Observations(ind_obs(1))%obs, 'model_SCF = ',asnow_ensavg(n) + ! if (logit) write (logunit, *) 'No_add_No_removal_section: ', & + ! 'MODIS_SCF = ', Observations(ind_obs(1))%obs, 'model_SCF = ',asnow_ensavg(n) do i=1,N_snow cat_progn_incr(n,n_e)%wesn(i) = 0.0 cat_progn_incr(n,n_e)%sndz(i) = 0.0 cat_progn_incr(n,n_e)%htsn(i) = 0.0 end do - if (n== 595) then - if (logit) write (logunit, *) - if (logit) write (logunit, *) '********No_add_or_removal***********' - if (logit) write (logunit, *) - if (logit) write (logunit, *) 'tile_number = ',n - if (logit) write (logunit, *) 'incr_wesn = ', cat_progn_incr(n,n_e)%wesn - if (logit) write (logunit, *) 'incr_sndz = ', cat_progn_incr(n,n_e)%sndz - if (logit) write (logunit, *) 'incr_htsn = ', cat_progn_incr(n,n_e)%htsn - endif + ! if (n== 595) then + ! if (logit) write (logunit, *) + ! if (logit) write (logunit, *) '********No_add_or_removal***********' + ! if (logit) write (logunit, *) + ! if (logit) write (logunit, *) 'tile_number = ',n + ! if (logit) write (logunit, *) 'incr_wesn = ', cat_progn_incr(n,n_e)%wesn + ! if (logit) write (logunit, *) 'incr_sndz = ', cat_progn_incr(n,n_e)%sndz + ! if (logit) write (logunit, *) 'incr_htsn = ', cat_progn_incr(n,n_e)%htsn + ! endif end if end do @@ -4674,7 +4682,7 @@ subroutine get_select_species( & type(obs_param_type), dimension(N_obs_param), intent(in) :: obs_param integer, intent(out) :: N_select_species - integer, dimension(N_obs_param), intent(out) :: select_species + integer, dimension(N_obs_param), intent(out) :: select_species ! local variables @@ -4689,8 +4697,14 @@ subroutine get_select_species( & kk = 0 if (N_select_varnames > 0) then - + + !if(logit) write(logunit,*) 'N_obs_param:', N_obs_param + !if(logit) write(logunit,*) 'Select_varnames:', select_varnames + do ii=1,N_obs_param + + !if(logit) write(logunit,*) obs_param(ii)%varname + !if(logit) write(logunit,*) select_varnames if (any(trim(obs_param(ii)%varname)==select_varnames)) then @@ -4743,7 +4757,7 @@ subroutine get_ind_obs( & integer, intent(in), dimension(N_select_tilenum) :: select_tilenum integer, intent(in), dimension(N_select_species) :: select_species - + integer, intent(out) :: N_selected_obs integer, intent(out), dimension(N_obs) :: ind_obs @@ -4807,10 +4821,13 @@ subroutine get_ind_obs( & k = 0 ! counter for selected obs do i=1,N_obs + !if(logit) write(logunit,*) 'tilenum:', Observations(i)%tilenum + !if(logit) write(logunit,*) 'species:', Observations(i)%species if ( any(Observations(i)%tilenum == select_tilenum) .and. & any(Observations(i)%species == select_species) ) then - + !if(logit) write(logunit,*) '********Found matching point*********' + k = k+1 ind_obs(k) = i From fbf9703217c76978937373ecb4e7ba41feb40453 Mon Sep 17 00:00:00 2001 From: Jongmin Park Date: Wed, 15 Dec 2021 13:22:15 -0500 Subject: [PATCH 011/308] Request for reviewing the SnowDA code in GEOSldas[12/15/2021] ** Brief updates compared to commits made on 11/08/2021] - No more errors related to the subroutine get_ind_obs() - Checked the details of tilenum, Observation vector, and Obs_pred vector (meeting slide at 11/19/2021) - Another floating error occured when calculating the snow heat content (located within the subroutine clsm_ensupd_upd_routine.F90) code line where showed error: TSN = min(met_force(n)%Tair-MAPL_TICE,0.0) - I've tried to calculate the different between met_force%Tair -MAPL_TICE before entering the loop, and i defined it as deduction (array) and call nth deduction value in the if loop. Still, it revealed a problem. - For the review purpose, It would be great help if you can look close into the subroutine clsm_ensupd_upd_routine.F90 (from line 4076 ot 4261) --- .../GEOS_LandAssimGridComp.F90 | 1 - .../clsm_ensupd_enkf_update.F90 | 44 +++-- .../clsm_ensupd_read_obs.F90 | 92 +++++++---- .../clsm_ensupd_upd_routines.F90 | 156 +++++++++++------- 4 files changed, 187 insertions(+), 106 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 index 5f83a652..929ee656 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 @@ -1827,7 +1827,6 @@ subroutine RUN ( GC, IMPORT, EXPORT, CLOCK, RC ) ! below are dummy for now N_adapt_R, obs_pert_adapt_param, Pert_adapt_R) - if (fresh_incr) then ! apply EnKF increments (incl. call to catch_calc_soil_moist but not to recompute_diagS()) call apply_enkf_increments( N_catl, NUM_ENSEMBLE, update_type, cat_param, & diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 index 9afa4e48..3d78e787 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 @@ -405,6 +405,7 @@ subroutine get_enkf_increments( & call get_tile_num_in_cell_ij( N_catf, & tile_coord_f%hash_i_indg, tile_coord_f%hash_j_indg, & tile_grid_f, maxval(N_tile_in_cell_ij_f), tile_num_in_cell_ij_f ) + else allocate(N_tile_in_cell_ij_f(0,0)) !for debugging end if @@ -439,7 +440,7 @@ subroutine get_enkf_increments( & ! -------------------------------------------------------------------- - + if (logit) write(logunit,*) 'found_obs_f', found_obs_f if (found_obs_f) then ! ++++++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -476,7 +477,7 @@ subroutine get_enkf_increments( & ! B1. Adjust observations to remove the obs bias ! and set obsbias_ok flag - + if(logit) write(logunit,*) 'entering obs_bias_corr_obs' call obs_bias_corr_obs(date_time, N_catl, N_catf, & N_obsl , N_obs_param, N_obsbias_max, f2l, obs_param, & obs_bias, Observations_l, obsbias_ok) @@ -521,6 +522,10 @@ subroutine get_enkf_increments( & fcsterr_inflation_fac ) if (allocated(obsbias_ok)) deallocate(obsbias_ok) + !if(logit) write(logunit,*) 'N_obs_l after obs_pred', N_obsl + !if(logit) write(logunit,*) 'Observations_l length', size(Observations_l) + !if(logit) write(logunit,*) 'Observations_l',Observations_l%ana + !if(logit) write(logunit,*) 'Obs_pred_l', Obs_pred_l ! IF NEEDED, INCLUDE WITHHOLDING SUBROUTINE HERE. ! SUCH A SUBROUTINE SHOULD CHANGE Observations(i)%assim TO FALSE @@ -677,7 +682,7 @@ subroutine get_enkf_increments( & Obs_f_assim, N_obsl_assim_vec, tmp_low_ind-1, MPI_obs_type, & mpicomm, mpierr) !-AnaLoadBal-Prereq-ends-here- - + !if(logit) write(logunit,*) 'Obs_f_assim', Obs_f_assim !-AnaLodaBal-Decomposition-starts-here ! Step 2a: compute nTiles_l, indTiles_l, nTilesl_vec (on root), nTiles_f (on root) ! NOTE: loop over tile_coord_l, if tile has nnz obs, store the 'full' index @@ -1047,7 +1052,20 @@ subroutine get_enkf_increments( & #ifdef LDAS_MPI allocate(cat_progn_incr_ana(nTiles_ana,N_ens)) - + !if(logit) write(logunit,*) 'Entering cat_enkf_increments' + !if(logit) write(logunit,*) 'length of Obs_ana', size(Obs_ana) + !if(logit) write(logunit,*) 'length of Obs_pred_ana', size(Obs_pred_ana) + !if(logit) write(logunit,*) 'length of Obs_pert_tmp', size(Obs_pert_tmp) + !if(logit) write(logunit,*) 'length of tile_coord_ana', size(tile_coord_ana) + !if(logit) write(logunit,*) 'Obs_ana', Obs_ana + !if(logit) write(logunit,*) 'Obs_ana%species', Obs_ana%species + !if(logit) write(logunit,*) 'Obs_ana%tilenum', Obs_ana%tilenum + !if(logit) write(logunit,*) 'Obs_ana%lat', Obs_ana%lat + !if(logit) write(logunit,*) 'Obs_ana%lon', Obs_ana%lon + !if(logit) write(logunit,*) 'Obs_ana%obs', Obs_ana%obs + !if(logit) write(logunit,*) 'Obs_pred_ana', Obs_pred_ana + !if(logit) write(logunit,*) 'Obs_pert_tmp', Obs_pert_tmp + !if(logit) write(logunit,*) 'tile_corrd_ana', tile_coord_ana call cpu_time(t_start) call cat_enkf_increments( & N_ens, nObs_ana, nTiles_ana, N_obs_param, & @@ -1087,7 +1105,7 @@ subroutine get_enkf_increments( & Obs_pert_tmp, & cat_param, & xcompact, ycompact, fcsterr_inflation_fac, & - cat_progn, cat_progn_incr ) + cat_progn, cat_progn_incr, met_force ) #endif #ifdef LDAS_MPI @@ -1286,7 +1304,7 @@ subroutine apply_enkf_increments( N_catd, N_ens, update_type, & ! ---------------------------------------------------------------- ! ! apply increments - + if(logit) write(logunit,*) "apply increment" cat_progn_has_changed = .true. ! conservative initialization select_update_type: select case (update_type) @@ -1380,15 +1398,15 @@ subroutine apply_enkf_increments( N_catd, N_ens, update_type, & case(11) select_update_type ! snow update !jpark50 if (logit) write (logunit,*) 'applying Snow data increments' - ! if ( date_time%hour /= 0 .and. & - ! date_time%min /= 0 .and. & - ! date_time%sec /= 0 ) then + !if ( date_time%hour /= 0 .and. & + ! date_time%min /= 0 .and. & + ! date_time%sec /= 0 ) then - if (logit) write (logunit,*) 'no application of increments at this time' - cat_progn_has_changed = .false. - return + ! if (logit) write (logunit,*) 'no application of increments at this time' + ! cat_progn_has_changed = .false. + ! return - ! end if + !end if if (logit) write (logunit,*) 'apply_enkf_increments(): applying asnow increments' if (logit) write (logunit,*) 'entering do loop' diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 7fc17c31..5e4fdaa6 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -344,19 +344,17 @@ subroutine read_MODISsca_hdf(& (Cloud_index(i)/=qc_antarctica) .and. & (Snow_QA(i)0) then if (logit) write (logunit, *) 'calling MODISsca_hdf subroutine' - if (logit) write (logunit, *) 'N_files = ', N_files - if (logit) write (logunit, *) 'N_tmp = ', N_tmp - if (logit) write (logunit, *) 'fnames = ', fnames(N_files) + !if (logit) write (logunit, *) 'N_files = ', N_files + !if (logit) write (logunit, *) 'N_tmp = ', N_tmp + !if (logit) write (logunit, *) 'fnames = ', fnames(N_files) call read_MODISsca_hdf( & N_files, date_time, N_tmp, fnames, tmp_lon, tmp_lat, tmp_obs) if (logit) write (logunit, *) 'read_obs_MODISsca: read MODIS datasets' - if (logit) write (logunit, *) 'length of tmp_lon', size(tmp_lon) - if (logit) write (logunit, *) 'tmp_lat: ', size(tmp_lat) - if (logit) write (logunit, *) 'tmp_obs: ', size(tmp_obs) - if (logit) write (logunit, *) 'tmp_obs: ', tmp_obs - if (logit) write (logunit, *) 'N_tmp:', N_tmp + !if (logit) write (logunit, *) 'length of tmp_lon', size(tmp_lon) + !if (logit) write (logunit, *) 'tmp_lat: ', size(tmp_lat) + !if (logit) write (logunit, *) 'tmp_obs: ', size(tmp_obs) + !if (logit) write (logunit, *) 'N_tmp:', N_tmp deallocate(fnames) @@ -511,7 +508,7 @@ subroutine read_obs_MODISsca( & this_obs_param, & tmp_tile_num(1:N_tmp) ) - !if(logit) write(logunit,*) 'tmp_tile_num:', tmp_tile_num + !if(logit) write(logunit,*) 'tmp_tile_num:', size(tmp_tile_num) MODIS_obs = 0. N_obs_in_tile = 0 @@ -526,7 +523,9 @@ subroutine read_obs_MODISsca( & end if end do - !if(logit) write(logunit,*) 'N_obs_in_tile', N_obs_in_tile + ! if(logit) write(logunit,*) 'length of MODIS_obs', size(MODIS_obs) + ! if(logit) write(logunit,*) 'length of N_obs_in_tile', size(N_obs_in_tile) + ! if(logit) write(logunit,*) 'N_obs_in_tile', N_obs_in_tile !normalize do i=1,N_catd @@ -538,7 +537,9 @@ subroutine read_obs_MODISsca( & end if end do - !if(logit) write(logunit,*), 'MODIS_obs (after normalization)', MODIS_obs + !if(logit) write(logunit,*) 'N_catd', N_catd + !if(logit) write(logunit,*) 'length of MODIS_obs after super_obsing', size(MODIS_obs) + !if(logit) write(logunit,*) 'MODIS_obs (after normalization)', MODIS_obs if (associated(tmp_tile_num)) deallocate (tmp_tile_num) @@ -564,7 +565,7 @@ end subroutine read_obs_MODISsca ! ***************************************************************** subroutine read_ae_l2_sm_hdf( & N_files, fnames, N_data, lon, lat, ae_l2_sm, ease_col, ease_row ) - + ! read soil moisture data from one or more AMSR-E Land hdf files ! ! return ONLY valid data points (ie. excluding no-data-values) @@ -7457,11 +7458,14 @@ subroutine read_obs( & select case (trim(this_obs_param%descr)) case ('MODIS_SCA') - + ! if(logit) write(logunit,*) 'tile_coord: (read_obs)', tile_coord + ! if(logit) write(logunit,*) 'tile_grid_d: (read_obs)', tile_grid_d call read_obs_MODISsca( & work_path, date_time, dtstep_assim, N_catd, tile_coord, & tile_grid_d, N_tile_in_cell_ij, tile_num_in_cell_ij, & this_obs_param, found_obs, tmp_obs, tmp_std_obs) + + !scaled_obs = .false. case ('ae_l2_sm_a', 'ae_l2_sm_d') @@ -8673,7 +8677,7 @@ subroutine collect_obs( ! (typically global) and returns a vector in (full domain) ! tile space with the values of the observations (at most one ! observation per tile and per species) - + call read_obs( & work_path, exp_id, & date_time, dtstep_assim, N_catf, tile_coord_f, & @@ -8685,7 +8689,14 @@ subroutine collect_obs( if (scaled_obs) any_scaled_obs = .true. end if - if (logit) write(logunit,*) 'found_obs (after read_obs)=', found_obs + + !if(logit) write(logunit,*) 'length of obs after finishing read_obs', size(tmp_obs_f) + !if(logit) write(logunit,*) 'tmp_obs_f after finishing read_obs', tmp_obs_f + !if(logit) write(logunit,*) 'length of lon after finishing read_obs', size(tmp_lon_f) + !if(logit) write(logunit,*) 'length of lat after finishing read_obs', size(tmp_lat_f) + !if(logit) write(logunit,*) 'N_catf', N_catf + !if(logit) write(logunit,*) 'tile_coord_f', tile_coord_f + !if(logit) write(logunit,*) 'found_obs (after read_obs)=', found_obs ! put "tmp_obs" (in "tile" space) into "compressed" vector "Observations_l" ! @@ -8717,11 +8728,22 @@ subroutine collect_obs( ! NOTE: "Observations" here are l(ocal) obs only - + !if(logit) write(logunit,*), 'N_obsl_max:', N_obsl_max + !if(logit) write(logunit,*), 'N_catl:', N_catl + !if(logit) write(logunit,*), 'l2f:', l2f + !if(logit) write(logunit,*), 'tmp_obs', tmp_obs + !if(logit) write(logunit,*), 'size tmp_obs', size(tmp_obs) + !if(logit) write(logunit,*), 'size tmp_lat', size(tmp_lat) + !if(logit) write(logunit,*), 'size tmp_lon', size(tmp_lon) + !if(logit) write(logunit,*), 'obs_count', obs_count + call put_into_Observations( obs_param(species), N_obsl_max, N_catl, l2f, & tmp_obs, tmp_std_obs, tmp_lon, tmp_lat, tmp_time, tmp_assim, & obs_count, Observations_l ) - + !if(logit) write(logunit,*), 'obs_count (after subroutine):', obs_count + !if(logit) write(logunit,*), 'Observations_l:', size(Observations_l) + !if(logit) write(logunit,*), 'Observation_l%obs', Observations_l%obs + !if(logit) write(logunit,*), 'Observations_l%tilenum', Observations_l%tilenum end if end do @@ -8731,7 +8753,7 @@ subroutine collect_obs( call MPI_BCAST(any_scaled_obs, 1, MPI_LOGICAL, 0,mpicomm, mpierr) #endif - + !if(logit) write(logunit,*) 'N_obsl:', obs_count N_obsl = obs_count ! ----------------------------------------------------------------- @@ -8763,11 +8785,12 @@ subroutine collect_obs( ind_start = 1 this_tilenum = Observations_l(ind_start)%tilenum - + do ii=2,N_obsl this_tilenum_new = Observations_l(ii)%tilenum - + !if(logit) write(logunit,*) 'tilenum', this_tilenum_new + if ( (this_tilenum_new/=this_tilenum) .or. (ii==N_obsl) ) then if ( (this_tilenum_new/=this_tilenum) .and. (ii<=N_obsl) ) then @@ -8784,11 +8807,13 @@ subroutine collect_obs( ! of (local) obs with the same tilenum N_tmp = ind_end - ind_start + 1 - + !if(logit) write(logunit,*) 'N_tmp', 'N_tmp' + if (N_tmp>1) then tmp_species(1:N_tmp) = Observations_l(ind_start:ind_end)%species - + !if(logit) write(logunit,*) 'tmp_species', tmp_species + ! get index vector for sorting by species (see NOTES above!) call nr_indexx( N_tmp, real(tmp_species(1:N_tmp)), indx(1:N_tmp) ) @@ -8955,16 +8980,19 @@ subroutine put_into_Observations( this_obs_param, N_obs_max, N_catd, l2f, & ! ------------------------------------------------------ - !if(logit) write(logunit,*) 'Entering put_into_Observations' + if(logit) write(logunit,*) 'Entering put_into_Observations' nodatavalue = this_obs_param%nodata tol = abs(nodatavalue*nodata_tolfrac_generic) - + + !if(logit) write(logunit,*) 'tol:', tol + !if(logit) write(logunit,*) 'N_catd:', N_catd + do i=1,N_catd - + if (abs(tmp_obs(i)-nodatavalue) > tol) then ! check for no-data-value - + obs_count = obs_count+1 ! augment observation counter Observations(obs_count)%obs = tmp_obs(i) @@ -8981,7 +9009,6 @@ subroutine put_into_Observations( this_obs_param, N_obs_max, N_catd, l2f, & Observations(obs_count)%obsvar = this_obs_param%errstd**2 end if - !if(logit) write(logunit,*) 'i:', i, 'tilenum', l2f(i) Observations(obs_count)%tilenum = l2f(i) @@ -8990,7 +9017,6 @@ subroutine put_into_Observations( this_obs_param, N_obs_max, N_catd, l2f, & Observations(obs_count)%lat = tmp_lat(i) Observations(obs_count)%lon = tmp_lon(i) - !if(logit) write(logunit, *) 'Obs species:', this_obs_param%species Observations(obs_count)%species = this_obs_param%species Observations(obs_count)%assim = this_obs_param%assim .and. tmp_assim(i) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index 8e2e0a29..de5dc5a8 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -395,7 +395,6 @@ subroutine read_ens_upd_inputs( & ! extract species into obs_param N_tmp = max( obs_param_nml(i)%N_ang, 1 ) - do k=1,N_tmp j = j + 1 @@ -990,7 +989,7 @@ subroutine get_obs_pred( & logical :: get_tp_l logical :: get_Tb_l, get_Tb_lH logical :: get_FT_l, get_FT_lH - logical :: get_asnow_l, get_asnow_lH !jpark50 2021_07_27 + logical :: get_asnow_l, get_asnow_lH !jpark50 type(grid_def_type) :: tile_grid_lH integer, dimension(N_obs_param) :: ind_obsparam2Tbspecies @@ -1985,7 +1984,7 @@ subroutine get_obs_pred_comm_helper( & N_fields, option, tile_data, sfmc, rzmc, tsurf, FT, asnow, stemp, Tb_h, Tb_v ) ! bundle/unbundle individual fields into/from single array for more - ! efficient communication across processors + ! efficieet communication across processors ! ! option: ! 1 = assemble tile_data from sfmc, rzmc, etc. @@ -3486,7 +3485,7 @@ subroutine cat_enkf_increments( & real, parameter :: tp1_threshold = -HUGE(1.) ! = 0.2 ! [CELSIUS] - integer :: n, n_e, kk, ii, i + integer :: n, n_e, kk, ii, i, j integer :: N_state, N_selected_obs, N_select_varnames, N_select_species @@ -3499,7 +3498,6 @@ subroutine cat_enkf_increments( & real :: fice_plus, tp1_plus, ght1_plus integer, dimension(N_obs) :: ind_obs - real, allocatable, dimension(:,:) :: State_incr real, allocatable, dimension(:,:) :: Obs_cov ! measurement error covariance @@ -3550,7 +3548,8 @@ subroutine cat_enkf_increments( & ! real, parameter:: rhofs = 150. ! kg/m^3 density of fresh snow ! real, parameter:: rhoma = 500. ! kg/m^3 maximum snow density ! real, parameter:: wemin = 13. ! kg/m^3 - real :: TSN, dens_layer + real, allocatable, dimension(:) ::deduction + real ::dens_layer, TSN ! ----------------------------------------------------------------------- if (logit) write (logunit,*) & @@ -3563,7 +3562,30 @@ subroutine cat_enkf_increments( & cat_progn_incr(kk,n_e) = 0. end do end do - + + do kk = 1, N_catd + do n_e =1, N_ens + cat_progn_incr(kk,n_e)%tc1 = 0.0 + cat_progn_incr(kk,n_e)%tc2 = 0.0 + cat_progn_incr(kk,n_e)%tc4 = 0.0 + cat_progn_incr(kk,n_e)%qa1 = 0.0 + cat_progn_incr(kk,n_e)%qa2 = 0.0 + cat_progn_incr(kk,n_e)%qa4 = 0.0 + cat_progn_incr(kk,n_e)%capac = 0.0 + cat_progn_incr(kk,n_e)%catdef = 0.0 + cat_progn_incr(kk,n_e)%rzexc = 0.0 + cat_progn_incr(kk,n_e)%srfexc = 0.0 + do j=1,N_gt + cat_progn_incr(kk,n_e)%ght(j) = 0.0 + end do + do i =1, N_snow + cat_progn_incr(kk,n_e)%wesn(i) = 0.0 + cat_progn_incr(kk,n_e)%htsn(i) = 0.0 + cat_progn_incr(kk,n_e)%sndz(i) = 0.0 + end do + end do + end do + ! avoid unnecessary work or subroutine calls if (N_obs<=0) return ! nothing left to do @@ -3660,7 +3682,6 @@ subroutine cat_enkf_increments( & asnow_ensavg = 0. do n_e=1,N_ens - SWE_ensavg = SWE_ensavg + SWE( :,n_e) tsurf_ensavg = tsurf_ensavg + tsurf( :,n_e) tp1_ensavg = tp1_ensavg + tp( 1,:,n_e) @@ -4059,89 +4080,98 @@ subroutine cat_enkf_increments( & !============================================================================= if (logit) write (logunit, *) 'get 1d snow(asnow) increments; MODIS SCF' - !do n_e=1,N_ens - ! call StieglitzSnow_calc_asnow(N_snow, N_catd, & - ! catprogn2wesn(N_catd, cat_progn(:,n_e)), & - ! asnow) - !end do - !identify the species ID number of interest N_select_varnames = 1 select_varnames(1) = 'asnow' - !if(logit) write(logunit,*) 'Entering get_select_species' - call get_select_species( & N_select_varnames, select_varnames(1:N_select_varnames), & N_obs_param, obs_param, N_select_species, select_species ) - !if(logit) write(logunit,*) 'output of select_species=', select_species - !if(logit) write(logunit,*) 'output of N_select_species=', N_select_species - !if(logit) write(logunit,*) 'N_catd=', N_catd - + !if(logit) write(logunit,*) 'MET forcing length', size(met_force%Tair) + !if(logit) write(logunit,*) 'metforce%Tair', met_force%Tair + !if(logit) write(logunit,*) 'lat', tile_coord%com_lat + !if(logit) write(logunit,*) 'lon', tile_coord%com_lon + !Rule-based snow SCF update allocate(select_tilenum(1)) - - do n=1,N_catd + allocate(deduction(N_catd)) + + deduction = met_force%Tair-MAPL_TICE + !if(logit) write(logunit,*) 'length of deduction:', size(deduction) + !if(logit) write(logunit,*) 'N_catd', N_catd + !if(logit) write(logunit,*) 'deduction: ', deduction + !if(logit) write(logunit,*) 'MAPL_TICE:', MAPL_TICE + + do n=1,N_catd !for each tile ! find observations for catchment n - ! if(logit) write(logunit,*) 'l2f', l2f(n) - ! if(logit) write(logunit,*) 'n: ', n - ! if(logit) write(logunit,*) 'N_obs', N_obs - - select_tilenum(1) = l2f(n) - - ! if(logit) write(logunit,*) 'select_tilenum', select_tilenum(1) - ! if(logit) write(logunit,*) 'Entering get_ind_obs subroutine' - ! if(logit) write(logunit,*) 'size of Observation', size(Observations) - + select_tilenum(1) = l2f(n) + ! if(logit) write(logunit,*) 'n:', n + call get_ind_obs( & N_obs, Observations, & 1, select_tilenum, & N_select_species, select_species(1:N_select_species), & N_selected_obs, ind_obs ) - ! if(logit) write(logunit,*) 'Observations%species', Observations(ind_obs(1))%species - if (N_selected_obs == 1) then - ! if(logit) write(logunit,*) 'N_selected_obs', N_selected_obs - ! if(logit) write(logunit,*) 'ind_obs', ind_obs(1) - ! if(logit) write(logunit,*) 'Observations', Observations(ind_obs(1))%obs - ! if(logit) write(logunit,*) 'asnow_ensavg', asnow_ensavg(n) do n_e=1,N_ens ! for each ensemble member + !if(logit) write(logunit,*) 'MODIS_SCF = ', Observations(ind_obs(1))%obs + !if(logit) write(logunit,*) 'modeled_SCF = ', asnow_ensavg(n) + !if(logit) write(logunit,*) 'RHS= ', Observations(ind_obs(1))%obs*model_threshold - if(asnow_ensavg(n) <= Observations(ind_obs(1))%obs * model_threshold) then - ! if (logit) write (logunit,*) 'Add_snow_section: ',& - ! 'MODIS_SCF = ', Observations(ind_obs(1))%obs, 'model_SCF = ', asnow_ensavg(n) + if(asnow_ensavg(n) < Observations(ind_obs(1))%obs*model_threshold) then - do i=1,N_snow + do i=1,N_snow !a) Snow water equivalent (add equally the snow to all three layers) cat_progn_incr(n, n_e)%wesn(i) = & ( Observations(ind_obs(1))%obs - & asnow_ensavg(n)/model_threshold ) * (wesn_added/float(N_snow)) + + !if(logit) write(logunit,*) 'cat_progn_incr(n_n_e)%wesn = ', cat_progn_incr(n, n_e)%wesn(i) !b) snow depth + !if(logit) write(logunit,*) 'cat_progn(n,n_e)%sndz(i)', cat_progn(n,n_e)%sndz(i) if(cat_progn(n,n_e)%sndz(i) > eps) then !Determine the fractional snow coverage wesn_sum_old(n,n_e) = sum(cat_progn(n,n_e)%wesn) areasc_old (n,n_e) = min(wesn_sum_old(n,n_e)/wemin,1.) + + ! if(logit) write(logunit,*) 'wesn_sum_old(n,n_e)', wesn_sum_old(n,n_e) + ! if(logit) write(logunit,*) 'areasc_old(n,n_e)', areasc_old(n,n_e) !Estimate the density of the ld layers of snow dens_layer = max(cat_progn(n,n_e)%wesn(i)/ & (cat_progn(n,n_e)%sndz(i)*areasc_old(n,n_e)),RHOFS) + !if(logit) write(logunit,*) 'dens_layer', dens_layer + cat_progn_incr(n,n_e)%sndz(i)=& - cat_progn_incr(n,n_e)%wesn(i)/dens_layer + cat_progn_incr(n,n_e)%wesn(i)/dens_layer + !if(logit) write(logunit,*) 'cat_progn_incr(n,n_e)%sndz:', cat_progn_incr(n,n_e)%sndz(i) + else - dens_layer = rhofs + dens_layer = RHOFS cat_progn_incr(n,n_e)%sndz(i) = cat_progn_incr(n,n_e)%wesn(i)/dens_layer end if - !c) heat content - TSN=min(met_force(n)%Tair-MAPL_TICE, 0.0) - cat_progn_incr(n,n_e)%htsn(i) = (TSN*cpw_pub-MAPL_ALHF)*cat_progn_incr(n,n_e)%wesn(i) + + !if(logit) write(logunit,*) 'Deduction:', deduction(n) + !original plan : use the min function --> continuously giving the floating error + !TSN = min( deduction(n), 0.0) + !Second options : replace the min function with if-else statement + if (deduction(n) .gt. 0.0) then + TSN = 0.0 + else + TSN = deduction(n) + end if + !if(logit) write(logunit,*) 'TSN = ',TSN + !if(logit) write(logunit,*) 'wesn increment', cat_progn_incr(n,n_e)%wesn(i) + !if(logit) write(logunit,*) 'cpw_pub: ', cpw_pub, 'MAPL_ALHF', MAPL_ALHF + cat_progn_incr(n,n_e)%htsn(i) = real((TSN*cpw_pub-MAPL_ALHF))*cat_progn_incr(n,n_e)%wesn(i) end do ! if (n== 595) then @@ -4156,8 +4186,8 @@ subroutine cat_enkf_increments( & ! endif elseif (Observations(ind_obs(1))%obs <= obs_threshold) then - ! if (logit) write (logunit,*) 'Remove snow section: ', & - ! 'MODIS_SCF = ', Observations(ind_obs(1))%obs, 'model_SCF = ', asnow_ensavg(n) + if (logit) write (logunit,*) 'Remove snow section: ', & + 'MODIS_SCF = ', Observations(ind_obs(1))%obs, 'model_SCF = ', asnow_ensavg(n) do i=1,N_snow cat_progn_incr(n,n_e)%wesn(i) = & @@ -4170,19 +4200,29 @@ subroutine cat_enkf_increments( & !Estimate the density of the old layers of snow dens_layer = max( cat_progn(n,n_e)%wesn(i)/& - (cat_progn(n,n_e)%sndz(i)*areasc_old(n,n_e)),rhofs) + (cat_progn(n,n_e)%sndz(i)*areasc_old(n,n_e)),RHOFS) cat_progn_incr(n,n_e)%sndz(i)=& cat_progn_incr(n,n_e)%wesn(i)/dens_layer else - dens_layer = rhofs + dens_layer = RHOFS cat_progn_incr(n,n_e)%sndz(i) = cat_progn_incr(n,n_e)%wesn(i)/dens_layer end if !c) heat content - TSN=min(met_force(n)%Tair-MAPL_TICE, 0.0) - cat_progn_incr(n,n_e)%htsn(i) = -(TSN*cpw_pub-MAPL_ALHF)*cat_progn_incr(n,n_e)%wesn(i) - end do + if(deduction(n) .gt. 0.0) then + TSN = 0.0 + else + TSN = deduction(n) + end if + !TSN = min( deduction(n), 0.0) + !if(logit) write(logunit,*) 'TSN: ', TSN + !if(logit) write(logunit,*) 'wesn increment', cat_progn_incr(n,n_e)%wesn(i) + !if(logit) write(logunit,*) 'cpw_pub: ', cpw_pub, 'MAPL_ALHF', MAPL_ALHF + + cat_progn_incr(n,n_e)%htsn(i) = -real((TSN*cpw_pub-MAPL_ALHF))*cat_progn_incr(n,n_e)%wesn(i) + + end do ! do(i=1,N_snow) ! if (n== 595) then ! if (logit) write (logunit, *) @@ -4197,8 +4237,8 @@ subroutine cat_enkf_increments( & else - ! if (logit) write (logunit, *) 'No_add_No_removal_section: ', & - ! 'MODIS_SCF = ', Observations(ind_obs(1))%obs, 'model_SCF = ',asnow_ensavg(n) + if (logit) write (logunit, *) 'No_add_No_removal_section: ', & + 'MODIS_SCF = ', Observations(ind_obs(1))%obs, 'model_SCF = ',asnow_ensavg(n) do i=1,N_snow cat_progn_incr(n,n_e)%wesn(i) = 0.0 @@ -4821,12 +4861,10 @@ subroutine get_ind_obs( & k = 0 ! counter for selected obs do i=1,N_obs - !if(logit) write(logunit,*) 'tilenum:', Observations(i)%tilenum - !if(logit) write(logunit,*) 'species:', Observations(i)%species if ( any(Observations(i)%tilenum == select_tilenum) .and. & any(Observations(i)%species == select_species) ) then - !if(logit) write(logunit,*) '********Found matching point*********' + if(logit) write(logunit,*) '********Found matching point*********' k = k+1 ind_obs(k) = i From d953d2a3edfcd15bdaf7109781d56dee0b654764 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Wed, 15 Dec 2021 15:59:33 -0500 Subject: [PATCH 012/308] cleaned up obsolete cat_diagS changes --- .../GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 index 3d78e787..3bbed62c 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 @@ -46,7 +46,6 @@ module clsm_ensupd_enkf_update use catch_types, ONLY: & cat_param_type, & cat_progn_type, & - cat_diagS_type, & catprogn2wesn, & catprogn2htsn, & catprogn2ghtcnt, & @@ -309,7 +308,6 @@ subroutine get_enkf_increments( & type(cat_progn_type), allocatable :: tmp_cat_progn_ana(:) type(cat_progn_type), allocatable :: cat_progn_incr_f(:), cat_progn_incr_ana(:,:) type(cat_progn_type), allocatable :: recvBuf(:) - type(cat_diagS_type), dimension(nTiles_ana, N_ens), allocatable :: cat_diagS(:) !jpark50 ! Obs related integer :: nObs_ana @@ -1289,9 +1287,6 @@ subroutine apply_enkf_increments( N_catd, N_ens, update_type, & type(cat_progn_type), dimension(N_catd,N_ens), intent(inout) :: cat_progn - ! type(date_time_type), intent(in) :: date_time !jpark50 - - ! type(cat_diagS_type), dimension(N_catd,N_ens), intent(in) :: cat_diagS !jpark50 ! ----------------- integer :: n, n_e, i From d0599e55fa3dc3e934b9047c78ab1befc643dba5 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Wed, 15 Dec 2021 17:58:49 -0500 Subject: [PATCH 013/308] miscellaneous cleanup - fixed typos - fixed indentation - added/edited comments - removed redundant initialization of cat_progn_incr - removed redundant cat_progn_incr%wesn=0 etc in "do nothing" case of snow analysis - undid partial (!) deletion of an old, commented-out subroutine --- .../clsm_ensupd_upd_routines.F90 | 481 ++++++++++-------- 1 file changed, 275 insertions(+), 206 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index de5dc5a8..89e3591e 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -1694,7 +1694,8 @@ subroutine get_obs_pred( & tmp_data(1:N_tmp) = FT_lH( ind_tmp(1:N_tmp), n_e ) case ('asnow') - tmp_data(1:N_tmp) = asnow_lH( ind_tmp(1:N_tmp), n_e) + + tmp_data(1:N_tmp) = asnow_lH( ind_tmp(1:N_tmp), n_e ) case('Tb') @@ -1984,7 +1985,7 @@ subroutine get_obs_pred_comm_helper( & N_fields, option, tile_data, sfmc, rzmc, tsurf, FT, asnow, stemp, Tb_h, Tb_v ) ! bundle/unbundle individual fields into/from single array for more - ! efficieet communication across processors + ! efficient communication across processors ! ! option: ! 1 = assemble tile_data from sfmc, rzmc, etc. @@ -2106,7 +2107,7 @@ subroutine get_obs_pred_comm_helper( & if (opt==1) tile_data(1:N_cat,k,1:N_ens) = asnow - if (opt==2) asnow = tile_data(1:N_cat,k,1:N_ens) + if (opt==2) asnow = tile_data(1:N_cat,k,1:N_ens) end if @@ -3418,7 +3419,7 @@ subroutine cat_enkf_increments( & ! reichle, 27 Jul 2005 ! reichle, 18 Oct 2005 - return increments (instead of updated cat_progn) ! reichle, 17 Oct 2011 - added "l2f" for revised (MPI) analysis - ! jpark50, 28 Jul 2020 - added metforce at the subroutine for 1D snow assimilation + ! jpark50, 28 Jul 2020 - added met_force at the subroutine for 1D snow assimilation ! -------------------------------------------------------------- ! IMPORTANT: @@ -3562,29 +3563,8 @@ subroutine cat_enkf_increments( & cat_progn_incr(kk,n_e) = 0. end do end do - - do kk = 1, N_catd - do n_e =1, N_ens - cat_progn_incr(kk,n_e)%tc1 = 0.0 - cat_progn_incr(kk,n_e)%tc2 = 0.0 - cat_progn_incr(kk,n_e)%tc4 = 0.0 - cat_progn_incr(kk,n_e)%qa1 = 0.0 - cat_progn_incr(kk,n_e)%qa2 = 0.0 - cat_progn_incr(kk,n_e)%qa4 = 0.0 - cat_progn_incr(kk,n_e)%capac = 0.0 - cat_progn_incr(kk,n_e)%catdef = 0.0 - cat_progn_incr(kk,n_e)%rzexc = 0.0 - cat_progn_incr(kk,n_e)%srfexc = 0.0 - do j=1,N_gt - cat_progn_incr(kk,n_e)%ght(j) = 0.0 - end do - do i =1, N_snow - cat_progn_incr(kk,n_e)%wesn(i) = 0.0 - cat_progn_incr(kk,n_e)%htsn(i) = 0.0 - cat_progn_incr(kk,n_e)%sndz(i) = 0.0 - end do - end do - end do + + ! reichle_15Dec2021: removed redundant initialization of cat_progn_incr ! avoid unnecessary work or subroutine calls @@ -4073,193 +4053,226 @@ subroutine cat_enkf_increments( & end do ! ---------------------------------- + + ! reichle_15Dec2021: ultimately, the block associated with case(11) should be moved to a place *after* case(8,10) and case(9) + case (11) select_update_type ! 1d snow (asnow) analysis; MODIS snow cover fraction jpark50 - !============================================================================= - !jpark50: 28-Jul-2021: For asnow update: - !The increment defined here is a direct replacement; there is no use of EnkF - !============================================================================= - if (logit) write (logunit, *) 'get 1d snow(asnow) increments; MODIS SCF' - - !identify the species ID number of interest - N_select_varnames = 1 - select_varnames(1) = 'asnow' + + !============================================================================= + !jpark50: 28-Jul-2021: For asnow update: + !The increment defined here is a direct replacement; there is no use of EnkF + !============================================================================= + if (logit) write (logunit, *) 'get 1d snow(asnow) increments; MODIS SCF' + + !identify the species ID number of interest + N_select_varnames = 1 + select_varnames(1) = 'asnow' - call get_select_species( & - N_select_varnames, select_varnames(1:N_select_varnames), & - N_obs_param, obs_param, N_select_species, select_species ) - - !if(logit) write(logunit,*) 'N_catd=', N_catd - !if(logit) write(logunit,*) 'MET forcing length', size(met_force%Tair) - !if(logit) write(logunit,*) 'metforce%Tair', met_force%Tair - !if(logit) write(logunit,*) 'lat', tile_coord%com_lat - !if(logit) write(logunit,*) 'lon', tile_coord%com_lon - - !Rule-based snow SCF update - allocate(select_tilenum(1)) - allocate(deduction(N_catd)) - - deduction = met_force%Tair-MAPL_TICE - !if(logit) write(logunit,*) 'length of deduction:', size(deduction) - !if(logit) write(logunit,*) 'N_catd', N_catd - !if(logit) write(logunit,*) 'deduction: ', deduction - !if(logit) write(logunit,*) 'MAPL_TICE:', MAPL_TICE - - do n=1,N_catd !for each tile + call get_select_species( & + N_select_varnames, select_varnames(1:N_select_varnames), & + N_obs_param, obs_param, N_select_species, select_species ) + + !if(logit) write(logunit,*) 'N_catd=', N_catd + !if(logit) write(logunit,*) 'MET forcing length', size(met_force%Tair) + !if(logit) write(logunit,*) 'metforce%Tair', met_force%Tair + !if(logit) write(logunit,*) 'lat', tile_coord%com_lat + !if(logit) write(logunit,*) 'lon', tile_coord%com_lon + + !Rule-based snow SCF update + allocate(select_tilenum(1)) + allocate(deduction(N_catd)) - ! find observations for catchment n - select_tilenum(1) = l2f(n) - ! if(logit) write(logunit,*) 'n:', n - - call get_ind_obs( & - N_obs, Observations, & - 1, select_tilenum, & - N_select_species, select_species(1:N_select_species), & - N_selected_obs, ind_obs ) - - if (N_selected_obs == 1) then - - do n_e=1,N_ens ! for each ensemble member - !if(logit) write(logunit,*) 'MODIS_SCF = ', Observations(ind_obs(1))%obs - !if(logit) write(logunit,*) 'modeled_SCF = ', asnow_ensavg(n) - !if(logit) write(logunit,*) 'RHS= ', Observations(ind_obs(1))%obs*model_threshold - - if(asnow_ensavg(n) < Observations(ind_obs(1))%obs*model_threshold) then - - do i=1,N_snow - !a) Snow water equivalent (add equally the snow to all three layers) - cat_progn_incr(n, n_e)%wesn(i) = & - ( Observations(ind_obs(1))%obs - & - asnow_ensavg(n)/model_threshold ) * (wesn_added/float(N_snow)) + deduction = met_force%Tair-MAPL_TICE + !if(logit) write(logunit,*) 'length of deduction:', size(deduction) + !if(logit) write(logunit,*) 'N_catd', N_catd + !if(logit) write(logunit,*) 'deduction: ', deduction + !if(logit) write(logunit,*) 'MAPL_TICE:', MAPL_TICE + + do n=1,N_catd !for each tile + + ! find observations for catchment n + select_tilenum(1) = l2f(n) + ! if(logit) write(logunit,*) 'n:', n + + call get_ind_obs( & + N_obs, Observations, & + 1, select_tilenum, & + N_select_species, select_species(1:N_select_species), & + N_selected_obs, ind_obs ) + + if (N_selected_obs == 1) then - !if(logit) write(logunit,*) 'cat_progn_incr(n_n_e)%wesn = ', cat_progn_incr(n, n_e)%wesn(i) + do n_e=1,N_ens ! for each ensemble member + + !if(logit) write(logunit,*) 'MODIS_SCF = ', Observations(ind_obs(1))%obs + !if(logit) write(logunit,*) 'modeled_SCF = ', asnow_ensavg(n) + !if(logit) write(logunit,*) 'RHS= ', Observations(ind_obs(1))%obs*model_threshold + + if(asnow_ensavg(n) < Observations(ind_obs(1))%obs*model_threshold) then - !b) snow depth - !if(logit) write(logunit,*) 'cat_progn(n,n_e)%sndz(i)', cat_progn(n,n_e)%sndz(i) - if(cat_progn(n,n_e)%sndz(i) > eps) then + ! *** Add snow *** + + do i=1,N_snow + + ! a) Snow water equivalent (add equally the snow to all three layers) + + cat_progn_incr(n, n_e)%wesn(i) = & + ( Observations(ind_obs(1))%obs - & + asnow_ensavg(n)/model_threshold ) * (wesn_added/float(N_snow)) + + !if(logit) write(logunit,*) 'cat_progn_incr(n_n_e)%wesn = ', cat_progn_incr(n, n_e)%wesn(i) + + ! b) snow depth + + !if(logit) write(logunit,*) 'cat_progn(n,n_e)%sndz(i)', cat_progn(n,n_e)%sndz(i) + + if(cat_progn(n,n_e)%sndz(i) > eps) then + + ! Determine the fractional snow coverage + wesn_sum_old(n,n_e) = sum(cat_progn(n,n_e)%wesn) + areasc_old( n,n_e) = min(wesn_sum_old(n,n_e)/wemin,1.) + + ! if(logit) write(logunit,*) 'wesn_sum_old(n,n_e)', wesn_sum_old(n,n_e) + ! if(logit) write(logunit,*) 'areasc_old(n,n_e)', areasc_old(n,n_e) + + ! Estimate the density of the ld layers of snow + dens_layer = max(cat_progn(n,n_e)%wesn(i)/ & + (cat_progn(n,n_e)%sndz(i)*areasc_old(n,n_e)),RHOFS) + + !if(logit) write(logunit,*) 'dens_layer', dens_layer + + cat_progn_incr(n,n_e)%sndz(i)=& + cat_progn_incr(n,n_e)%wesn(i)/dens_layer + + !if(logit) write(logunit,*) 'cat_progn_incr(n,n_e)%sndz:', cat_progn_incr(n,n_e)%sndz(i) + + else + dens_layer = RHOFS + cat_progn_incr(n,n_e)%sndz(i) = cat_progn_incr(n,n_e)%wesn(i)/dens_layer + end if + + ! c) snow heat content + + !if(logit) write(logunit,*) 'Deduction:', deduction(n) + !original plan : use the min function --> continuously giving the floating error + !TSN = min( deduction(n), 0.0) + !Second options : replace the min function with if-else statement + if (deduction(n) .gt. 0.0) then + TSN = 0.0 + else + TSN = deduction(n) + end if + !if(logit) write(logunit,*) 'TSN = ',TSN + !if(logit) write(logunit,*) 'wesn increment', cat_progn_incr(n,n_e)%wesn(i) + !if(logit) write(logunit,*) 'cpw_pub: ', cpw_pub, 'MAPL_ALHF', MAPL_ALHF + cat_progn_incr(n,n_e)%htsn(i) = real((TSN*cpw_pub-MAPL_ALHF))*cat_progn_incr(n,n_e)%wesn(i) + + end do ! i=1,N_snow + + ! if (n== 595) then + ! if (logit) write (logunit, *) + ! if (logit) write (logunit, *) '********Adding_Snow***********' + ! if (logit) write (logunit, *) + ! if (logit) write (logunit, *) 'tile_number = ',n + ! if (logit) write (logunit, *) 'add_snow_density = ', dens_layer + ! if (logit) write (logunit, *) 'added_wesn = ', cat_progn_incr(n,n_e)%wesn + ! if (logit) write (logunit, *) 'added_sndz = ', cat_progn_incr(n,n_e)%sndz + ! if (logit) write (logunit, *) 'added_htsn = ', cat_progn_incr(n,n_e)%htsn + ! endif + + elseif (Observations(ind_obs(1))%obs <= obs_threshold) then + + ! *** Remove snow *** + + if (logit) write (logunit,*) 'Remove snow section: ', & + 'MODIS_SCF = ', Observations(ind_obs(1))%obs, 'model_SCF = ', asnow_ensavg(n) + + do i=1,N_snow - !Determine the fractional snow coverage - wesn_sum_old(n,n_e) = sum(cat_progn(n,n_e)%wesn) - areasc_old (n,n_e) = min(wesn_sum_old(n,n_e)/wemin,1.) - - ! if(logit) write(logunit,*) 'wesn_sum_old(n,n_e)', wesn_sum_old(n,n_e) - ! if(logit) write(logunit,*) 'areasc_old(n,n_e)', areasc_old(n,n_e) - - !Estimate the density of the ld layers of snow - dens_layer = max(cat_progn(n,n_e)%wesn(i)/ & - (cat_progn(n,n_e)%sndz(i)*areasc_old(n,n_e)),RHOFS) - - !if(logit) write(logunit,*) 'dens_layer', dens_layer - - cat_progn_incr(n,n_e)%sndz(i)=& - cat_progn_incr(n,n_e)%wesn(i)/dens_layer - !if(logit) write(logunit,*) 'cat_progn_incr(n,n_e)%sndz:', cat_progn_incr(n,n_e)%sndz(i) - - else - dens_layer = RHOFS - cat_progn_incr(n,n_e)%sndz(i) = cat_progn_incr(n,n_e)%wesn(i)/dens_layer - end if - - !if(logit) write(logunit,*) 'Deduction:', deduction(n) - !original plan : use the min function --> continuously giving the floating error - !TSN = min( deduction(n), 0.0) - !Second options : replace the min function with if-else statement - if (deduction(n) .gt. 0.0) then - TSN = 0.0 - else - TSN = deduction(n) - end if - !if(logit) write(logunit,*) 'TSN = ',TSN - !if(logit) write(logunit,*) 'wesn increment', cat_progn_incr(n,n_e)%wesn(i) - !if(logit) write(logunit,*) 'cpw_pub: ', cpw_pub, 'MAPL_ALHF', MAPL_ALHF - cat_progn_incr(n,n_e)%htsn(i) = real((TSN*cpw_pub-MAPL_ALHF))*cat_progn_incr(n,n_e)%wesn(i) - end do - - ! if (n== 595) then - ! if (logit) write (logunit, *) - ! if (logit) write (logunit, *) '********Adding_Snow***********' - ! if (logit) write (logunit, *) - ! if (logit) write (logunit, *) 'tile_number = ',n - ! if (logit) write (logunit, *) 'add_snow_density = ', dens_layer - ! if (logit) write (logunit, *) 'added_wesn = ', cat_progn_incr(n,n_e)%wesn - ! if (logit) write (logunit, *) 'added_sndz = ', cat_progn_incr(n,n_e)%sndz - ! if (logit) write (logunit, *) 'added_htsn = ', cat_progn_incr(n,n_e)%htsn - ! endif - - elseif (Observations(ind_obs(1))%obs <= obs_threshold) then - if (logit) write (logunit,*) 'Remove snow section: ', & - 'MODIS_SCF = ', Observations(ind_obs(1))%obs, 'model_SCF = ', asnow_ensavg(n) - - do i=1,N_snow - cat_progn_incr(n,n_e)%wesn(i) = & - -cat_progn(n,n_e)%wesn(i)*(1-Observations(ind_obs(1))%obs/obs_threshold ) - - !b) snow depth - if (cat_progn(n,n_e)%sndz(i) > eps) then - wesn_sum_old(n,n_e)=sum(cat_progn(n,n_e)%wesn) - areasc_old(n,n_e)=min(wesn_sum_old(n,n_e)/wemin,1.) - - !Estimate the density of the old layers of snow - dens_layer = max( cat_progn(n,n_e)%wesn(i)/& - (cat_progn(n,n_e)%sndz(i)*areasc_old(n,n_e)),RHOFS) - - cat_progn_incr(n,n_e)%sndz(i)=& - cat_progn_incr(n,n_e)%wesn(i)/dens_layer - - else - dens_layer = RHOFS - cat_progn_incr(n,n_e)%sndz(i) = cat_progn_incr(n,n_e)%wesn(i)/dens_layer - end if - !c) heat content - if(deduction(n) .gt. 0.0) then - TSN = 0.0 - else - TSN = deduction(n) - end if - !TSN = min( deduction(n), 0.0) - !if(logit) write(logunit,*) 'TSN: ', TSN - !if(logit) write(logunit,*) 'wesn increment', cat_progn_incr(n,n_e)%wesn(i) - !if(logit) write(logunit,*) 'cpw_pub: ', cpw_pub, 'MAPL_ALHF', MAPL_ALHF - - cat_progn_incr(n,n_e)%htsn(i) = -real((TSN*cpw_pub-MAPL_ALHF))*cat_progn_incr(n,n_e)%wesn(i) - - end do ! do(i=1,N_snow) - - ! if (n== 595) then - ! if (logit) write (logunit, *) - ! if (logit) write (logunit, *) '********Remove_Snow***********' - ! if (logit) write (logunit, *) - ! if (logit) write (logunit, *) 'tile_number = ',n - ! if (logit) write (logunit, *) 'remove_snow_density = ', dens_layer - ! if (logit) write (logunit, *) 'remove_wesn = ', cat_progn_incr(n,n_e)%wesn - ! if (logit) write (logunit, *) 'remove_sndz = ', cat_progn_incr(n,n_e)%sndz - ! if (logit) write (logunit, *) 'remove_htsn = ', cat_progn_incr(n,n_e)%htsn - ! endif - - else - - if (logit) write (logunit, *) 'No_add_No_removal_section: ', & - 'MODIS_SCF = ', Observations(ind_obs(1))%obs, 'model_SCF = ',asnow_ensavg(n) - - do i=1,N_snow - cat_progn_incr(n,n_e)%wesn(i) = 0.0 - cat_progn_incr(n,n_e)%sndz(i) = 0.0 - cat_progn_incr(n,n_e)%htsn(i) = 0.0 - end do - ! if (n== 595) then - ! if (logit) write (logunit, *) - ! if (logit) write (logunit, *) '********No_add_or_removal***********' - ! if (logit) write (logunit, *) - ! if (logit) write (logunit, *) 'tile_number = ',n - ! if (logit) write (logunit, *) 'incr_wesn = ', cat_progn_incr(n,n_e)%wesn - ! if (logit) write (logunit, *) 'incr_sndz = ', cat_progn_incr(n,n_e)%sndz - ! if (logit) write (logunit, *) 'incr_htsn = ', cat_progn_incr(n,n_e)%htsn - ! endif - end if + ! a) snow water equivalent + + cat_progn_incr(n,n_e)%wesn(i) = & + -cat_progn(n,n_e)%wesn(i)*(1-Observations(ind_obs(1))%obs/obs_threshold ) + + ! b) snow depth + + if (cat_progn(n,n_e)%sndz(i) > eps) then + + wesn_sum_old(n,n_e)=sum(cat_progn(n,n_e)%wesn) + areasc_old(n,n_e)=min(wesn_sum_old(n,n_e)/wemin,1.) + + !Estimate the density of the old layers of snow + dens_layer = max( cat_progn(n,n_e)%wesn(i)/& + (cat_progn(n,n_e)%sndz(i)*areasc_old(n,n_e)),RHOFS) + + cat_progn_incr(n,n_e)%sndz(i)=& + cat_progn_incr(n,n_e)%wesn(i)/dens_layer + + else + dens_layer = RHOFS + cat_progn_incr(n,n_e)%sndz(i) = cat_progn_incr(n,n_e)%wesn(i)/dens_layer + end if + + !c) heat content + + if(deduction(n) .gt. 0.0) then + TSN = 0.0 + else + TSN = deduction(n) + end if + + !TSN = min( deduction(n), 0.0) + !if(logit) write(logunit,*) 'TSN: ', TSN + !if(logit) write(logunit,*) 'wesn increment', cat_progn_incr(n,n_e)%wesn(i) + !if(logit) write(logunit,*) 'cpw_pub: ', cpw_pub, 'MAPL_ALHF', MAPL_ALHF + + cat_progn_incr(n,n_e)%htsn(i) = -real((TSN*cpw_pub-MAPL_ALHF))*cat_progn_incr(n,n_e)%wesn(i) + + end do ! i=1,N_snow + + ! if (n== 595) then + ! if (logit) write (logunit, *) + ! if (logit) write (logunit, *) '********Remove_Snow***********' + ! if (logit) write (logunit, *) + ! if (logit) write (logunit, *) 'tile_number = ',n + ! if (logit) write (logunit, *) 'remove_snow_density = ', dens_layer + ! if (logit) write (logunit, *) 'remove_wesn = ', cat_progn_incr(n,n_e)%wesn + ! if (logit) write (logunit, *) 'remove_sndz = ', cat_progn_incr(n,n_e)%sndz + ! if (logit) write (logunit, *) 'remove_htsn = ', cat_progn_incr(n,n_e)%htsn + ! endif + + else + ! *** Do nothing *** + + if (logit) write (logunit, *) 'No_add_No_removal_section: ', & + 'MODIS_SCF = ', Observations(ind_obs(1))%obs, 'model_SCF = ',asnow_ensavg(n) + + ! reichle_15Dec2021: Do *nothing*! + ! (cat_progn_incr was already initialized to 0) + ! + ! do i=1,N_snow + ! cat_progn_incr(n,n_e)%wesn(i) = 0.0 + ! cat_progn_incr(n,n_e)%sndz(i) = 0.0 + ! cat_progn_incr(n,n_e)%htsn(i) = 0.0 + ! end do + + ! if (n== 595) then + ! if (logit) write (logunit, *) + ! if (logit) write (logunit, *) '********No_add_or_removal***********' + ! if (logit) write (logunit, *) + ! if (logit) write (logunit, *) 'tile_number = ',n + ! if (logit) write (logunit, *) 'incr_wesn = ', cat_progn_incr(n,n_e)%wesn + ! if (logit) write (logunit, *) 'incr_sndz = ', cat_progn_incr(n,n_e)%sndz + ! if (logit) write (logunit, *) 'incr_htsn = ', cat_progn_incr(n,n_e)%htsn + ! endif + + end if + + end do ! n_e=1,N_ens + end if ! (N_selected_obs == 1) end do - end if - end do - + case (7) select_update_type ! 3d Tskin/ght(1) analysis; tskin obs ! update each tile separately using all observations within @@ -5401,6 +5414,8 @@ end subroutine dist_km2deg ! ****************************************************************** + ! reichle_15Dec2021: undid deletion of ~half of the old, commented-out subroutine below + ! abandoned during changes for obs halo ! to reinstate, need to MPI_Gather "cat_param_f" ! @@ -5429,4 +5444,58 @@ end subroutine dist_km2deg ! real, dimension(N_obs,N_ens), intent(inout) :: Obs_pert ! ! ! ---------------------------------------------------------------- +! +! ! local variables +! +! integer :: i, n +! +! real :: min_pert, max_pert +! +! ! --------------------------------------------------------------- +! +! do i=1,N_obs +! +! select case (Observations(i)%species) +! +! case (1,2,4,7,8,9,10,11,12) +! +! ! ae_l2_sm_a, ae_l2_sm_d, RedArkOSSE_sm, RedArkOSSE_CLSMsynthSM, +! ! VivianaOK_CLSMsynthSM, ae_sm_LPRM_a_C, ae_sm_LPRM_d_C, +! ! ae_sm_LPRM_a_X, ae_sm_LPRM_d_X +! +! min_pert = -Observations(i)%obs +! max_pert = cat_param(Observations(i)%tilenum)%poros - & +! Observations(i)%obs +! +! do n=1,N_ens +! +! Obs_pert(i,n) = max( Obs_pert(i,n), min_pert ) +! Obs_pert(i,n) = min( Obs_pert(i,n), max_pert ) +! +! end do +! +! case (3) ! isccp_tskin_gswp2_v1 +! +! ! no constraints +! +! case default +! +! call stop_it('check_obs_pert(): unkown obs species.') +! +! !write (logunit,*) 'check_obs_pert(): unkown obs species. STOPPING.' +! !stop +! +! end select +! +! end do +! +! end subroutine check_obs_pert + + ! ********************************************************************** + ! ********************************************************************** + ! ********************************************************************** + end module clsm_ensupd_upd_routines + + +! **** EOF ****************************************************** From e3ad8f908aa6cb67c8671ec03a534d5c9715ddc2 Mon Sep 17 00:00:00 2001 From: Weiyuan Jiang Date: Thu, 6 Jan 2022 19:31:26 -0500 Subject: [PATCH 014/308] land_assim: yes; pertubation:0; no mwRTM file --- .../GEOS_LandAssimGridComp.F90 | 33 +++++++++++-------- .../GEOS_LandPertGridComp.F90 | 2 ++ 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 index 929ee656..de9b0703 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 @@ -817,7 +817,7 @@ subroutine SetServices ( GC, RC ) ! ! INTERNAL STATE ! - + if (mwRTM) then call MAPL_AddInternalSpec(GC ,& LONG_NAME = 'L-band Microwave RTM: Vegetation class. Type is Unsigned32' ,& UNITS = '1' ,& @@ -980,6 +980,9 @@ subroutine SetServices ( GC, RC ) VLOCATION = MAPL_VLocationNone ,& DEFAULT = nodata_generic ,& RC=STATUS) + else + allocate(mwRTM_param(0)) + endif ! mwRTM File ! call MAPL_GetResource ( MAPL, NUM_ENSEMBLE, Label="NUM_LDAS_ENSEMBLE:", DEFAULT=1, RC=STATUS) @@ -2187,14 +2190,16 @@ subroutine CALC_LAND_TB(gc, import, export, clock, rc) !---------------------- call MAPL_Get(MAPL, INTERNAL_ESMF_STATE=INTERNAL, rc=status) _VERIFY(status) - - call get_mwrtm_param(INTERNAL, N_catl, rc=status) - _VERIFY(STATUS) - ! make sure that at least some mwRTM parameters are not nodata - if (mwRTM_all_nodata) then - _ASSERT(.false., "Tb output requested but all mwRTM parameters are nodata") + + if (mwRTM) then + call get_mwrtm_param(INTERNAL, N_catl, rc=status) + _VERIFY(STATUS) + ! make sure that at least some mwRTM parameters are not nodata + if (mwRTM_all_nodata) then + _ASSERT(.false., "Tb output requested but all mwRTM parameters are nodata") + endif endif - + call MAPL_GetPointer(import, LAI, 'LAI' ,rc=status) _VERIFY(status) call MAPL_GetPointer(import, TP1, 'TP1' ,rc=status) ! units now K, rreichle & borescan, 6 Nov 2020 @@ -2336,13 +2341,15 @@ subroutine OUTPUT_SMAPL4SMLMC(gc, import, export, clock, rc) _VERIFY(status) call esmf2ldas(ModelTimeCur, start_time, rc=status) _VERIFY(status) + + if (mwRTM) then + call get_mwrtm_param(INTERNAL, N_catl, rc=status) + _VERIFY(status) - call get_mwrtm_param(INTERNAL, N_catl, rc=status) - _VERIFY(status) - - call GEOS_output_smapL4SMlmc( GC, start_time, trim(out_path), trim(exp_id), & + call GEOS_output_smapL4SMlmc( GC, start_time, trim(out_path), trim(exp_id), & N_catl, tile_coord_l, cat_param, mwRTM_param ) - first_time = .false. + first_time = .false. + endif _RETURN(_SUCCESS) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/GEOS_LandPertGridComp.F90 b/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/GEOS_LandPertGridComp.F90 index 6b29b15d..d95adc20 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/GEOS_LandPertGridComp.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/GEOS_LandPertGridComp.F90 @@ -902,6 +902,8 @@ subroutine Initialize(gc, import, export, clock, rc) VERIFY_(status) if (internal%PERTURBATIONS == 0) then ! no perturbations + allocate(progn_pert_param(0)) + allocate(force_pert_param(0)) call MAPL_TimerOff(MAPL, "Initialize") call MAPL_TimerOff(MAPL, "TOTAL") RETURN_(ESMF_SUCCESS) From a6aaa4e31eeb587850ed21aec23f1ba1f94dde0f Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Mon, 10 Jan 2022 16:02:40 -0500 Subject: [PATCH 015/308] components.yaml: point to associated GEOSgcm_GridComp branch --- components.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components.yaml b/components.yaml index abf8a17c..c0328ce5 100644 --- a/components.yaml +++ b/components.yaml @@ -36,5 +36,5 @@ GEOSgcm_GridComp: local: ./src/Components/GEOSldas_GridComp/@GEOSgcm_GridComp remote: ../GEOSgcm_GridComp.git sparse: ./config/GEOSgcm_GridComp_ldas.sparse - branch: develop + branch: feature/rreichle/MODIS_snow_cover_fraction_assimilation develop: develop From 3196f307f7abadf85c35d8f953c01d2f7ad0d702 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Mon, 10 Jan 2022 16:06:53 -0500 Subject: [PATCH 016/308] commented out bad and redundant statements in MODIS SCA reader (clsm_ensup_read_obs.F90) --- .../GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 5e4fdaa6..5a5e6a8d 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -360,9 +360,9 @@ subroutine read_MODISsca_hdf(& if (logit) write(logunit,*) 'N_data:', N_data - lat = lat(1:j) - lon = lon(1:j) - MODIS_SCA = MODIS_SCA(1:j) + ! lat = lat(1:j) + ! lon = lon(1:j) + ! MODIS_SCA = MODIS_SCA(1:j) ! if (logit) write(logunit,*) 'readMODISsca_hdf subroutine' ! if (logit) write(logunit,*) 'lat size:', size(lat) From 288f77b343e643c5383f3310f4b3b964f95a39da Mon Sep 17 00:00:00 2001 From: Weiyuan Jiang Date: Thu, 13 Jan 2022 12:01:01 -0500 Subject: [PATCH 017/308] fix read_obs --- .../clsm_ensupd_read_obs.F90 | 69 ++++++++++--------- 1 file changed, 38 insertions(+), 31 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 5a5e6a8d..891ddc56 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -84,9 +84,8 @@ module clsm_ensupd_read_obs contains - subroutine read_MODISsca_hdf(& - N_files, date_time, N_data, fnames, & - lon, lat, MODIS_SCA) + subroutine read_MODISsca_hdf( N_files, date_time, N_data, fnames, & + lon, lat, MODIS_SCA) !subroutine read_MODISsca_hdf routine description !a. purpose: read snow cover data from daily MOD10C1 data located under lis folder @@ -111,14 +110,14 @@ subroutine read_MODISsca_hdf(& implicit none integer, intent(in) :: N_files - character(300), dimension(N_files), intent(in) :: fnames + type(date_time_type),intent(in) :: date_time ! loading the UTC hour information to constrain the longitude of MODIS obs. integer, intent(out) :: N_data - - real, dimension(:), pointer, allocatable :: lon, lat + character(*), dimension(N_files), intent(in) :: fnames + real, dimension(:), pointer :: lon, lat + real, dimension(:), pointer :: MODIS_SCA + real, dimension(:), allocatable :: MODIS_SCA_raw character(1), dimension(:,:), allocatable :: tmp_MODIS_SCA, tmp_CI_Index, tmp_Cloud_index, tmp_Snow_QA - real, dimension(:), pointer :: MODIS_SCA, MODIS_SCA_raw - - type(date_time_type),intent(in) :: date_time ! loading the UTC hour information to constrain the longitude of MODIS obs. + real, allocatable :: MODIS_SCA_tmp(:), lon_tmp(:), lat_tmp(:) !local parameters integer, parameter:: N_fields = 4 @@ -179,11 +178,12 @@ subroutine read_MODISsca_hdf(& character(len=400) :: err_msg ! initialize N_data - N_data_tmp(N_files) = 3600*7200 + N_data_tmp(N_files) = XGRID*YGRID !if(logit) write(logunit, *) 'N_data_tmp=', N_data_tmp(1) - N_data = sum(N_data_tmp) +! N_data = sum(N_data_tmp) + N_data = XGRID*YGRID !if (logit) write(logunit, *) 'N_data', N_data @@ -191,8 +191,8 @@ subroutine read_MODISsca_hdf(& lon_c = (-180+bin_size/2)+bin_size*lon_ind do i=1,7200 - lat_1D(3600*(i-1)+1:3600*i)= lat_c - lon_1D(3600*(i-1)+1:3600*i)= lon_c(i) + lat_1D(3600*(i-1)+1:3600*i)= lat_c + lon_1D(3600*(i-1)+1:3600*i)= lon_c(i) end do ! allocate pointers (must be deallocated outside this subroutine) @@ -207,19 +207,17 @@ subroutine read_MODISsca_hdf(& call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) end if - allocate(lat(N_data)) - allocate(lon(N_data)) - allocate(MODIS_SCA_raw(N_data)) + allocate(MODIS_SCA_raw(N_data)) - allocate(CI_Index(N_data)) - allocate(Snow_QA(N_data)) - allocate(Cloud_Index(N_data)) + allocate(CI_Index(N_data)) + allocate(Snow_QA(N_data)) + allocate(Cloud_Index(N_data)) - ! read hdf data into arrays, concatenate data from N_files files + ! read hdf data into arrays, concatenate data from N_files files - k_off = 0 + k_off = 0 - do j=1,N_files + do j=1,N_files ! open and start "hdf file" !if(logit) write(logunit, *) 'fname: ', fnames(j) @@ -330,8 +328,10 @@ subroutine read_MODISsca_hdf(& ! ------------------------------------- ! eliminate no-data-values and data that fail initial QC + allocate(MODIS_SCA_tmp(N_data)) + allocate(lat_tmp(N_data)) + allocate(lon_tmp(N_data)) j=0 - allocate(MODIS_SCA(N_data)) do i=1,N_data @@ -346,24 +346,31 @@ subroutine read_MODISsca_hdf(& if(keep_data) then j=j+1 - MODIS_SCA(j) = MODIS_SCA_raw(i)/100 - lon(j) = lon_1D(i) - lat(j) = lat_1D(i) + MODIS_SCA_tmp(j) = MODIS_SCA_raw(i)/100 + lon_tmp(j) = lon_1D(i) + lat_tmp(j) = lat_1D(i) end if end do - if (logit) write (logunit, *) 'number of datasets', j + + if (logit) write (logunit, *) 'number of datasets', j N_data = j + + allocate(MODIS_SCA(N_data)) + allocate(lat(N_data)) + allocate(lon(N_data)) + if (logit) write(logunit,*) 'N_data:', N_data - ! lat = lat(1:j) - ! lon = lon(1:j) - ! MODIS_SCA = MODIS_SCA(1:j) + lat = lat_tmp(1:j) + lon = lon_tmp(1:j) + MODIS_SCA = MODIS_SCA_tmp(1:j) + deallocate(lat_tmp, lon_tmp, MODIS_SCA_tmp) ! if (logit) write(logunit,*) 'readMODISsca_hdf subroutine' ! if (logit) write(logunit,*) 'lat size:', size(lat) ! if (logit) write(logunit,*) 'lon size:', size(lon) @@ -386,7 +393,7 @@ subroutine read_obs_MODISsca( & implicit none !inputs - character(200), intent(in) :: work_path + character(*), intent(in) :: work_path type(date_time_type), intent(in):: date_time From 019e31c57d97554e03124d3571f2e38cdc961f52 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Thu, 13 Jan 2022 12:25:16 -0500 Subject: [PATCH 018/308] added "met_force" to Analysis Load Balance in get_enkf_increments() --- .../clsm_ensupd_enkf_update.F90 | 47 ++++++++++++++++--- .../clsm_ensupd_upd_routines.F90 | 7 ++- 2 files changed, 43 insertions(+), 11 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 index 3bbed62c..f6544ce0 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 @@ -112,6 +112,7 @@ module clsm_ensupd_enkf_update apply_adapt_R use LDAS_ensdrv_mpi, ONLY: & + MPI_met_force_type, & MPI_cat_param_type, & MPI_cat_progn_type, & root_proc, & @@ -303,6 +304,7 @@ subroutine get_enkf_increments( & integer, dimension(:), allocatable :: indTiles_l, indTiles_f, indTiles_ana type(varLenIntArr) :: indTilesAna_vec(numprocs) type(tile_coord_type), dimension(:), pointer :: tile_coord_ana ! input to cat_enkf_increment() is a pointer + type(met_force_type), dimension(:), allocatable :: met_force_f, met_force_ana type(cat_param_type), dimension(:), allocatable :: cat_param_f, cat_param_ana type(cat_progn_type), allocatable :: cat_progn_f(:), cat_progn_ana(:,:) type(cat_progn_type), allocatable :: tmp_cat_progn_ana(:) @@ -618,7 +620,7 @@ subroutine get_enkf_increments( & ! them evenly among all procs, indTiles_ana. The corresponding ! numbers are nTiles_l, nTiles_f, nTiles_ana. Root needs ! nTilesAna_vec, indTilesAna_vec (list of nTiles_ana, - ! indTiles_ana on each proc) to distribute cat_param, cat_progn. + ! indTiles_ana on each proc) to distribute cat_param, cat_progn, etc. ! ! IMPORTANT: Regardless of update_type, obs from *all* species are ! considered (ie, N_select_species=0). This could result in @@ -748,7 +750,7 @@ subroutine get_enkf_increments( & if (allocated(indTiles_f)) deallocate(indTiles_f) ! Step 2d: indTiles_ana -> indTilesAna_vec (on root) - ! root needs indTiles_ana from each proc to distribute cat_param, cat_progn etc. + ! root needs indTiles_ana from each proc to distribute cat_param, cat_progn, etc. if (root_proc) then do iproc=1,numprocs allocate(indTilesAna_vec(iproc)%ind(nTilesAna_vec(iproc))) @@ -850,7 +852,36 @@ subroutine get_enkf_increments( & allocate(tile_coord_ana(nTiles_ana)) tile_coord_ana = tile_coord_f(indTiles_ana) - ! Step 4c: cat_param(N_catl) -> cat_param_f (on root) -> cat_param_ana + ! Step 4c: met_force(N_catl) -> met_force_f (on root) -> met_force_ana + if (root_proc) then + allocate(met_force_f(N_catf)) + else + allocate(met_force_f(0)) !for debugging mode + endif + call MPI_Gatherv( & + met_force, N_catl, MPI_met_force_type, & + met_force_f, N_catl_vec, low_ind-1, MPI_met_force_type, & + 0, mpicomm, mpierr ) + allocate(met_force_ana(nTiles_ana)) + if (root_proc) then + met_force_ana = met_force_f(indTilesAna_vec(1)%ind) + do dest=1,numprocs-1 + sendtag = dest + sendct = nTilesAna_vec(dest+1) + call MPI_Send(met_force_f(indTilesAna_vec(dest+1)%ind), & + sendct,MPI_met_force_type, & + dest,sendtag,mpicomm,mpierr) + end do + else + ! source = 0 + recvtag = myid + recvct = nTiles_ana + call MPI_Recv(met_force_ana,recvct,MPI_met_force_type, & + 0,recvtag,mpicomm,mpistatus,mpierr) + end if + if (allocated(met_force_f)) deallocate(met_force_f) + + ! Step 4d: cat_param(N_catl) -> cat_param_f (on root) -> cat_param_ana if (root_proc) then allocate(cat_param_f(N_catf)) else @@ -879,7 +910,7 @@ subroutine get_enkf_increments( & end if if (allocated(cat_param_f)) deallocate(cat_param_f) - ! Step 4d: cat_progn -> cat_progn_f (on root) -> cat_progn_ana + ! Step 4e: cat_progn -> cat_progn_f (on root) -> cat_progn_ana ! one ensemble at a time if (root_proc) then allocate(cat_progn_f(N_catf)) @@ -931,7 +962,7 @@ subroutine get_enkf_increments( & if (allocated( tmp_cat_progn_ana)) deallocate(tmp_cat_progn_ana) if (allocated(cat_progn_f)) deallocate(cat_progn_f) - ! Step 4e: Obs_pred_l (obs%assim=.true.) -> Obs_pred_f_assim (on root) -> Obs_pred_ana + ! Step 4f: Obs_pred_l (obs%assim=.true.) -> Obs_pred_f_assim (on root) -> Obs_pred_ana ! one ensemble at a time if (root_proc) then allocate(Obs_pred_f_assim(N_obsf_assim)) @@ -1072,10 +1103,10 @@ subroutine get_enkf_increments( & Obs_ana, & ! size: nObs_ana Obs_pred_ana, & ! size: (nObs_ana,N_ens) Obs_pert_tmp, & + met_force_ana, & cat_param_ana, & xcompact, ycompact, fcsterr_inflation_fac, & - cat_progn_ana, cat_progn_incr_ana, & - met_force) + cat_progn_ana, cat_progn_incr_ana) call cpu_time(t_end) @@ -1101,6 +1132,7 @@ subroutine get_enkf_increments( & Observations_lH(1:N_obslH), & Obs_pred_lH(1:N_obslH,1:N_ens), & Obs_pert_tmp, & + met_force, & cat_param, & xcompact, ycompact, fcsterr_inflation_fac, & cat_progn, cat_progn_incr, met_force ) @@ -1180,6 +1212,7 @@ subroutine get_enkf_increments( & if (allocated( indObs_ana)) deallocate(indObs_ana) if (allocated( cat_progn_ana)) deallocate(cat_progn_ana) if (allocated( cat_param_ana)) deallocate(cat_param_ana) + if (allocated( met_force_ana)) deallocate(met_force_ana) do iproc=1,numprocs if (allocated(indTilesAna_vec(iproc)%ind)) & deallocate(indTilesAna_vec(iproc)%ind) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index 89e3591e..cff8ac2e 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -3409,9 +3409,9 @@ subroutine cat_enkf_increments( & update_type, obs_param, & tile_grid_f, tile_coord, l2f, & Observations, Obs_pred, Obs_pert, & - cat_param, & + met_force, cat_param, & xcompact, ycompact, fcsterr_inflation_fac, & - cat_progn, cat_progn_incr, met_force) + cat_progn, cat_progn_incr) ! get increments for Catchment prognostic variables ! @@ -3461,8 +3461,7 @@ subroutine cat_enkf_increments( & real, intent(in), dimension(N_obs,N_ens) :: Obs_pred real, intent(in), dimension(N_obs,N_ens) :: Obs_pert - type(met_force_type), dimension(N_catd), intent(in) :: met_force !jpark50 - !type(cat_diagS_type), dimension(N_catd), intent(in) :: cat_diagS !jpark50 + type(met_force_type), dimension(N_catd), intent(in) :: met_force type(cat_param_type), dimension(N_catd), intent(in) :: cat_param real, intent(in) :: xcompact, ycompact, fcsterr_inflation_fac From 99f1801732e5eac7024a69508aa734fcbe4fa96a Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Fri, 28 Jan 2022 10:02:30 -0500 Subject: [PATCH 019/308] fixing previous commit's conflict resolution for components.yaml --- components.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/components.yaml b/components.yaml index c0328ce5..40e3e991 100644 --- a/components.yaml +++ b/components.yaml @@ -5,13 +5,13 @@ GEOSldas: env: local: ./@env remote: ../ESMA_env.git - tag: v3.3.0 + tag: v3.8.0 develop: main cmake: local: ./@cmake remote: ../ESMA_cmake.git - tag: v3.5.0 + tag: v3.8.0 develop: develop ecbuild: @@ -22,19 +22,19 @@ ecbuild: GMAO_Shared: local: ./src/Shared/@GMAO_Shared remote: ../GMAO_Shared.git - sparse: ./config/GMAO_Shared.sparse branch: main + sparse: ./config/GMAO_Shared.sparse develop: main MAPL: local: ./src/Shared/@MAPL remote: ../MAPL.git - tag: v2.7.0 + tag: v2.15.0 develop: develop GEOSgcm_GridComp: local: ./src/Components/GEOSldas_GridComp/@GEOSgcm_GridComp remote: ../GEOSgcm_GridComp.git - sparse: ./config/GEOSgcm_GridComp_ldas.sparse branch: feature/rreichle/MODIS_snow_cover_fraction_assimilation + sparse: ./config/GEOSgcm_GridComp_ldas.sparse develop: develop From c4d9ec2998c880b22d9537f493b37bca586f90af Mon Sep 17 00:00:00 2001 From: "Lauren C. Andrews" Date: Thu, 3 Feb 2022 21:13:46 -0500 Subject: [PATCH 020/308] updates to lines 4518-4619 --- .../clsm_ensupd_upd_routines.F90 | 379 +++++++----------- 1 file changed, 155 insertions(+), 224 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index cff8ac2e..5f8bcffd 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -3439,7 +3439,7 @@ subroutine cat_enkf_increments( & ! ------------------------------------------------------------------- USE SurfParams, ONLY: WEMIN - USE StieglitzSnow, ONLY: RHOMA_pub, cpw_pub + USE StieglitzSnow, ONLY: cpw_pub !Removed RHOMA_pub, unreferenced. LCA 1/28/22 use Catch_Constants, ONLY: RHOFS => CATCH_SNWALB_RHOFS implicit none @@ -3540,9 +3540,10 @@ subroutine cat_enkf_increments( & real, dimension(N_catd, N_ens) :: wesn_sum_old real, dimension(N_catd, N_ens) :: areasc_old !real, parameter:: cpw = 2065.22 !ice specific heat capacity @ 0C [J/kg/K] - real, parameter:: model_threshold = 0.40 - real, parameter:: obs_threshold = 0.25 - real, parameter:: wesn_added = 12.0 ! mm of SWE + real, parameter:: alpha_threshold = 0.20 !lca modified name and value 2/2/22 + real, parameter:: beta_threshold = 0.40 !lca modified name and value 2/2/22 + real, parameter:: wesn_max = 5.0 ! kg m-2 from Toure et al. 2018, lca modified 2/3/22 + real, parameter:: wesn_min = 13.0 ! kg m-2 from Toure et al. 2018, lca added 2/3/22 real, parameter:: eps = 1.e-4 real, parameter:: small = 1.e-20 ! real, parameter:: rhofs = 150. ! kg/m^3 density of fresh snow @@ -4052,226 +4053,6 @@ subroutine cat_enkf_increments( & end do ! ---------------------------------- - - ! reichle_15Dec2021: ultimately, the block associated with case(11) should be moved to a place *after* case(8,10) and case(9) - - case (11) select_update_type ! 1d snow (asnow) analysis; MODIS snow cover fraction jpark50 - - !============================================================================= - !jpark50: 28-Jul-2021: For asnow update: - !The increment defined here is a direct replacement; there is no use of EnkF - !============================================================================= - if (logit) write (logunit, *) 'get 1d snow(asnow) increments; MODIS SCF' - - !identify the species ID number of interest - N_select_varnames = 1 - select_varnames(1) = 'asnow' - - call get_select_species( & - N_select_varnames, select_varnames(1:N_select_varnames), & - N_obs_param, obs_param, N_select_species, select_species ) - - !if(logit) write(logunit,*) 'N_catd=', N_catd - !if(logit) write(logunit,*) 'MET forcing length', size(met_force%Tair) - !if(logit) write(logunit,*) 'metforce%Tair', met_force%Tair - !if(logit) write(logunit,*) 'lat', tile_coord%com_lat - !if(logit) write(logunit,*) 'lon', tile_coord%com_lon - - !Rule-based snow SCF update - allocate(select_tilenum(1)) - allocate(deduction(N_catd)) - - deduction = met_force%Tair-MAPL_TICE - !if(logit) write(logunit,*) 'length of deduction:', size(deduction) - !if(logit) write(logunit,*) 'N_catd', N_catd - !if(logit) write(logunit,*) 'deduction: ', deduction - !if(logit) write(logunit,*) 'MAPL_TICE:', MAPL_TICE - - do n=1,N_catd !for each tile - - ! find observations for catchment n - select_tilenum(1) = l2f(n) - ! if(logit) write(logunit,*) 'n:', n - - call get_ind_obs( & - N_obs, Observations, & - 1, select_tilenum, & - N_select_species, select_species(1:N_select_species), & - N_selected_obs, ind_obs ) - - if (N_selected_obs == 1) then - - do n_e=1,N_ens ! for each ensemble member - - !if(logit) write(logunit,*) 'MODIS_SCF = ', Observations(ind_obs(1))%obs - !if(logit) write(logunit,*) 'modeled_SCF = ', asnow_ensavg(n) - !if(logit) write(logunit,*) 'RHS= ', Observations(ind_obs(1))%obs*model_threshold - - if(asnow_ensavg(n) < Observations(ind_obs(1))%obs*model_threshold) then - - ! *** Add snow *** - - do i=1,N_snow - - ! a) Snow water equivalent (add equally the snow to all three layers) - - cat_progn_incr(n, n_e)%wesn(i) = & - ( Observations(ind_obs(1))%obs - & - asnow_ensavg(n)/model_threshold ) * (wesn_added/float(N_snow)) - - !if(logit) write(logunit,*) 'cat_progn_incr(n_n_e)%wesn = ', cat_progn_incr(n, n_e)%wesn(i) - - ! b) snow depth - - !if(logit) write(logunit,*) 'cat_progn(n,n_e)%sndz(i)', cat_progn(n,n_e)%sndz(i) - - if(cat_progn(n,n_e)%sndz(i) > eps) then - - ! Determine the fractional snow coverage - wesn_sum_old(n,n_e) = sum(cat_progn(n,n_e)%wesn) - areasc_old( n,n_e) = min(wesn_sum_old(n,n_e)/wemin,1.) - - ! if(logit) write(logunit,*) 'wesn_sum_old(n,n_e)', wesn_sum_old(n,n_e) - ! if(logit) write(logunit,*) 'areasc_old(n,n_e)', areasc_old(n,n_e) - - ! Estimate the density of the ld layers of snow - dens_layer = max(cat_progn(n,n_e)%wesn(i)/ & - (cat_progn(n,n_e)%sndz(i)*areasc_old(n,n_e)),RHOFS) - - !if(logit) write(logunit,*) 'dens_layer', dens_layer - - cat_progn_incr(n,n_e)%sndz(i)=& - cat_progn_incr(n,n_e)%wesn(i)/dens_layer - - !if(logit) write(logunit,*) 'cat_progn_incr(n,n_e)%sndz:', cat_progn_incr(n,n_e)%sndz(i) - - else - dens_layer = RHOFS - cat_progn_incr(n,n_e)%sndz(i) = cat_progn_incr(n,n_e)%wesn(i)/dens_layer - end if - - ! c) snow heat content - - !if(logit) write(logunit,*) 'Deduction:', deduction(n) - !original plan : use the min function --> continuously giving the floating error - !TSN = min( deduction(n), 0.0) - !Second options : replace the min function with if-else statement - if (deduction(n) .gt. 0.0) then - TSN = 0.0 - else - TSN = deduction(n) - end if - !if(logit) write(logunit,*) 'TSN = ',TSN - !if(logit) write(logunit,*) 'wesn increment', cat_progn_incr(n,n_e)%wesn(i) - !if(logit) write(logunit,*) 'cpw_pub: ', cpw_pub, 'MAPL_ALHF', MAPL_ALHF - cat_progn_incr(n,n_e)%htsn(i) = real((TSN*cpw_pub-MAPL_ALHF))*cat_progn_incr(n,n_e)%wesn(i) - - end do ! i=1,N_snow - - ! if (n== 595) then - ! if (logit) write (logunit, *) - ! if (logit) write (logunit, *) '********Adding_Snow***********' - ! if (logit) write (logunit, *) - ! if (logit) write (logunit, *) 'tile_number = ',n - ! if (logit) write (logunit, *) 'add_snow_density = ', dens_layer - ! if (logit) write (logunit, *) 'added_wesn = ', cat_progn_incr(n,n_e)%wesn - ! if (logit) write (logunit, *) 'added_sndz = ', cat_progn_incr(n,n_e)%sndz - ! if (logit) write (logunit, *) 'added_htsn = ', cat_progn_incr(n,n_e)%htsn - ! endif - - elseif (Observations(ind_obs(1))%obs <= obs_threshold) then - - ! *** Remove snow *** - - if (logit) write (logunit,*) 'Remove snow section: ', & - 'MODIS_SCF = ', Observations(ind_obs(1))%obs, 'model_SCF = ', asnow_ensavg(n) - - do i=1,N_snow - - ! a) snow water equivalent - - cat_progn_incr(n,n_e)%wesn(i) = & - -cat_progn(n,n_e)%wesn(i)*(1-Observations(ind_obs(1))%obs/obs_threshold ) - - ! b) snow depth - - if (cat_progn(n,n_e)%sndz(i) > eps) then - - wesn_sum_old(n,n_e)=sum(cat_progn(n,n_e)%wesn) - areasc_old(n,n_e)=min(wesn_sum_old(n,n_e)/wemin,1.) - - !Estimate the density of the old layers of snow - dens_layer = max( cat_progn(n,n_e)%wesn(i)/& - (cat_progn(n,n_e)%sndz(i)*areasc_old(n,n_e)),RHOFS) - - cat_progn_incr(n,n_e)%sndz(i)=& - cat_progn_incr(n,n_e)%wesn(i)/dens_layer - - else - dens_layer = RHOFS - cat_progn_incr(n,n_e)%sndz(i) = cat_progn_incr(n,n_e)%wesn(i)/dens_layer - end if - - !c) heat content - - if(deduction(n) .gt. 0.0) then - TSN = 0.0 - else - TSN = deduction(n) - end if - - !TSN = min( deduction(n), 0.0) - !if(logit) write(logunit,*) 'TSN: ', TSN - !if(logit) write(logunit,*) 'wesn increment', cat_progn_incr(n,n_e)%wesn(i) - !if(logit) write(logunit,*) 'cpw_pub: ', cpw_pub, 'MAPL_ALHF', MAPL_ALHF - - cat_progn_incr(n,n_e)%htsn(i) = -real((TSN*cpw_pub-MAPL_ALHF))*cat_progn_incr(n,n_e)%wesn(i) - - end do ! i=1,N_snow - - ! if (n== 595) then - ! if (logit) write (logunit, *) - ! if (logit) write (logunit, *) '********Remove_Snow***********' - ! if (logit) write (logunit, *) - ! if (logit) write (logunit, *) 'tile_number = ',n - ! if (logit) write (logunit, *) 'remove_snow_density = ', dens_layer - ! if (logit) write (logunit, *) 'remove_wesn = ', cat_progn_incr(n,n_e)%wesn - ! if (logit) write (logunit, *) 'remove_sndz = ', cat_progn_incr(n,n_e)%sndz - ! if (logit) write (logunit, *) 'remove_htsn = ', cat_progn_incr(n,n_e)%htsn - ! endif - - else - - ! *** Do nothing *** - - if (logit) write (logunit, *) 'No_add_No_removal_section: ', & - 'MODIS_SCF = ', Observations(ind_obs(1))%obs, 'model_SCF = ',asnow_ensavg(n) - - ! reichle_15Dec2021: Do *nothing*! - ! (cat_progn_incr was already initialized to 0) - ! - ! do i=1,N_snow - ! cat_progn_incr(n,n_e)%wesn(i) = 0.0 - ! cat_progn_incr(n,n_e)%sndz(i) = 0.0 - ! cat_progn_incr(n,n_e)%htsn(i) = 0.0 - ! end do - - ! if (n== 595) then - ! if (logit) write (logunit, *) - ! if (logit) write (logunit, *) '********No_add_or_removal***********' - ! if (logit) write (logunit, *) - ! if (logit) write (logunit, *) 'tile_number = ',n - ! if (logit) write (logunit, *) 'incr_wesn = ', cat_progn_incr(n,n_e)%wesn - ! if (logit) write (logunit, *) 'incr_sndz = ', cat_progn_incr(n,n_e)%sndz - ! if (logit) write (logunit, *) 'incr_htsn = ', cat_progn_incr(n,n_e)%htsn - ! endif - - end if - - end do ! n_e=1,N_ens - end if ! (N_selected_obs == 1) - end do - case (7) select_update_type ! 3d Tskin/ght(1) analysis; tskin obs ! update each tile separately using all observations within @@ -4687,6 +4468,156 @@ subroutine cat_enkf_increments( & end if end do + ! ---------------------------------- + + + case (11) select_update_type ! 1d snow (asnow) analysis; MODIS snow cover fraction jpark50 + + !============================================================================= + !lcandre2: updated 02-Feb-2022 to include appropriate update to mass, heat content, + ! & depth. Then apply relayering following adjustments using GRACE DA. + !jpark50: 28-Jul-2021: For asnow update: + !The increment defined here is a direct replacement; there is no use of EnkF + !============================================================================= + if (logit) write (logunit, *) 'get 1d snow(asnow) increments; MODIS SCF' + + !identify the species ID number of interest + N_select_varnames = 1 select_varnames(1) = 'asnow' + + call get_select_species( & + N_select_varnames, select_varnames(1:N_select_varnames), & + N_obs_param, obs_param, N_select_species, select_species ) + + !if(logit) write(logunit,*) 'N_catd=', N_catd + !if(logit) write(logunit,*) 'MET forcing length', size(met_force%Tair) + !if(logit) write(logunit,*) 'metforce%Tair', met_force%Tair + !if(logit) write(logunit,*) 'lat', tile_coord%com_lat + !if(logit) write(logunit,*) 'lon', tile_coord%com_lon + + !Rule-based snow SCF update + allocate(select_tilenum(1)) + allocate(deduction(N_catd)) + + deduction = met_force%Tair-MAPL_TICE !this can be negative or positive lca 2/2/22, but still not sure what it is for and why it isnt calculated in the catchment for loop + !Print the value and length of 'deduction' + !if(logit) write(logunit,*) 'deduction: ', deduction + !if(logit) write(logunit,*) 'length of deduction:', size(deduction) + + do n=1,N_catd !for each catchment + + ! find observations for catchment n + select_tilenum(1) = l2f(n) + ! if(logit) write(logunit,*) 'n:', n + + call get_ind_obs( & + N_obs, Observations, & + 1, select_tilenum, & + N_select_species, select_species(1:N_select_species), & + N_selected_obs, ind_obs ) + + if (N_selected_obs == 1) then + + do n_e=1,N_ens ! for each ensemble member (1) determine action and + + !*** Add snow *** + !**************** + !if the model SCF is less than the Obs SCF times alpha then ADD snow + !alpha = alpha_threshold = 0.2 + if(asnow_ensavg(n) .lt. Observations(ind_obs(1))%obs * alpha_threshold) then + !if(logit) write (logunit, *) 'Add snow: ' & + ! 'MODIS_SCF = ', Observations(ind_obs(1))%obs, 'model_SCF = ',asnow_ensavg(n) + !tot_swe_init = cat_progn(n,n_e)%wesn(1) + cat_progn(n,n_e)%wesn(2) + cat_progn(n,n_e)%wesn(3) + + areasc_minus = min( (cat_progn(n,n_e)%wesn(1) + cat_progn(n,n_e)%wesn(2) + cat_progn(n,n_e)%wesn(3)) / WEMIN, 1.0) + + + do isnow = 1,N_snow + !1. calculate increment to be added and update SWE + cat_progn_incr(n,n_e)%wesn(isnow) = (wesn_max / float(N_snow)) * & + (observations(ind_obs(1)%obs - asnow_ensavg(n) /alpha_threshold) + + !2. Update wesn + wesn_ratio(isnow) = (cat_progn(n,n_e)%wesn(isnow) + cat_progn_incr(n,n_e)%wesn(isnow) / cat_progn(n,n_e)%wesn(isnow) + + cat_progn(n,n_e)%wesn(isnow) = cat_progn(n,n_e)%wesn(isnow) * wesn_ratio(isnow) + + end do + + !Calculate new snow cover area + areasc_plus = min( ( cat_progn(n,n_e)%wesn(1) + cat_progn(n,n_e)%wesn(2) + cat_progn(n,n_e)%wesn(3)/ WEMIN, 1.0) + + !3. Update snow depth using rules to define density and heat content + do isnow = 1, N_snow + + !Case 1: if the inital area is zero and snow is added then the depth is dependent on updated SWE and fresh density + ! and the heat content is updated assuming the snow is at MAPL_TICE (273.16) + if ( (areasc_minus.eq.0.0) .and. (areasc_plus.gt.0.0) ) then !These can probably be simplified + cat_progn(n,n_e)%sndz(isnow) = cat_progn(n,n_e)%wesn(isnow) /RHOFS + cat_progn(n,n_e)%htsn(isnow) = 0.0 ! heat content = ci * wesn * (Ti-Tm). If assume fresh snow is isothermal and @0*C + endif + !Case 2: if the initial area is less than 1 and final area is less than or equal to 1 + ! then depth increases based on the wesn_ratio (?? check) + if ( (areasc_minus.le.1.0) .and. (areasc_plus.le.1.0) ) then ! These can probably be simplified + cat_progn(n, n_e)%sndz(isnow) = cat_progn(n,n_e)%sndz(isnow) * wesn_ratio(isnow) + cat_progn(n, n_e)%htsn(isnow) = cat_progn(n,n_e%htsn(isnow) * wesn_ratio(isnow) + endif + end do + + !*** Remove snow *** + !******************* + !if the model SCF is greater than or equal to the Obs SCF times alpha + !AND the Observed SCF is less than beta, then REMOVE snow + elseif(asnow_ensavg(n) .ge. Observations(ind_obs(1))%obs * alpha_threshold) .AND. & !!Is the first part of this statement needed? + (Observations(ind_obs(1))%obs .lt. beta_threshold) then + !if (logit) write (logunit, *) 'Remove snow: ', & + ! 'MODIS_SCF = ', Observations(ind_obs(1))%obs, 'model_SCF = ',asnow_ensavg(n) + areasc_minus = min( (cat_progn(n,n_e)%wesn(1) + cat_progn(n,n_e)%wesn(2) + cat_progn(n,n_e)%wesn(3)) / WEMIN, 1.0) + + + do isnow = 1,N_snow + !1. calculate increment to be added and update SWE + cat_progn_incr(n,n_e)%wesn(isnow) = -wesn_min * & + (1 - asnow_ensavg(n) /beta_threshold) !Check this equation!!!! + + !2. Update wesn + wesn_ratio(isnow) = (cat_progn(n,n_e)%wesn(isnow) + cat_progn_incr(n,n_e)%wesn(isnow) / cat_progn(n,n_e)%wesn(isnow) + + cat_progn(n,n_e)%wesn(isnow) = cat_progn(n,n_e)%wesn(isnow) * wesn_ratio(isnow) + + end do + + !Calculate new snow cover area, this is different than add because there needs to be a protection against negative SWE(?) + areasc_plus = max( ( cat_progn(n,n_e)%wesn(1) + cat_progn(n,n_e)%wesn(2) + cat_progn(n,n_e)%wesn(3)/ WEMIN, 0.0) + + !3. Update snow depth using rules to define density and heat content + do isnow = 1, N_snow + + !Case 1: if the inital area is greater than zero and the updated area is zero, then depth and heat content are zero + if ( (areasc_minus.gt.0.0) .and. (areasc_plus.eq.0.0) ) then !These can probably be simplified + cat_progn(n,n_e)%sndz(isnow) = 0.0 + cat_progn(n,n_e)%htsn(isnow) = 0.0 ! heat content = ci * wesn * (Ti-Tm). If assume fresh snow is isothermal and @0*C + endif + !Case 2: if the initial area is less than 1 and final area is less than or equal to 1 + ! then depth increases based on the wesn_ratio (?? check) + if ( (areasc_minus.gt.0.0) .and. (areasc_plus.gt.0.0) ) then ! These can probably be simplified + cat_progn(n, n_e)%sndz(isnow) = cat_progn(n,n_e)%sndz(isnow) * wesn_ratio(isnow) + cat_progn(n, n_e)%htsn(isnow) = cat_progn(n,n_e%htsn(isnow) * wesn_ratio(isnow) + endif + end do + !*** No Add, No remove snow *** + !****************************** + !If neither conditions is met then do nothing ( NO add No remove) + else + !if (logit) write (logunit, *) 'No add No remove: ', & + ! 'MODIS_SCF = ', Observations(ind_obs(1))%obs, 'model_SCF = ',asnow_ensavg(n) + cat_progn_incr(n,n_e)%wesn(isnow) = 0.0 + + end if ! snow actions + + end do ! n_e=1,N_ens + end if ! (N_selected_obs == 1) + end do ! n=1,N_catd + ! ---------------------------------- From 09a2049218696871f42140f18d934db478f1a7cb Mon Sep 17 00:00:00 2001 From: "Lauren C. Andrews" Date: Fri, 27 May 2022 09:36:04 -0400 Subject: [PATCH 021/308] Snow DA modifications to calculate increments --- .../GEOS_LandAssimGridComp.F90 | 10 +- .../clsm_ensupd_upd_routines.F90 | 221 ++++++++---------- 2 files changed, 103 insertions(+), 128 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 index 53741006..14feafff 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 @@ -2395,21 +2395,13 @@ subroutine OUTPUT_SMAPL4SMLMC(gc, import, export, clock, rc) call esmf2ldas(ModelTimeCur, start_time, rc=status) _VERIFY(status) - if (mwRTM) then - call get_mwrtm_param(INTERNAL, N_catl, rc=status) - _VERIFY(status) - -<<<<<<< HEAD - call GEOS_output_smapL4SMlmc( GC, start_time, trim(out_path), trim(exp_id), & -======= call get_mwrtm_param(MAPL, clock, N_catl, INTERNAL, rc=status) _VERIFY(status) call GEOS_output_smapL4SMlmc( GC, start_time, trim(out_path), trim(exp_id), & ->>>>>>> develop N_catl, tile_coord_l, cat_param, mwRTM_param ) first_time = .false. - endif + _RETURN(_SUCCESS) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index 27cb256a..b319625d 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -104,9 +104,12 @@ module clsm_ensupd_upd_routines N_snow => CATCH_N_SNOW, & N_gt => CATCH_N_GT, & PEATCLSM_POROS_THRESHOLD +! N_CONSTIT => CATCH_N_CONSTIT !LCA needed for relayer2 use STIEGLITZSNOW, ONLY: & - StieglitzSnow_calc_asnow + StieglitzSnow_calc_asnow, & + relayer2, & !LCA needed for snow da + N_constit use LDAS_ensdrv_mpi, ONLY: & numprocs, & @@ -3442,8 +3445,11 @@ subroutine cat_enkf_increments( & ! ------------------------------------------------------------------- USE SurfParams, ONLY: WEMIN - USE StieglitzSnow, ONLY: cpw_pub !Removed RHOMA_pub, unreferenced. LCA 1/28/22 - use Catch_Constants, ONLY: RHOFS => CATCH_SNWALB_RHOFS + !!USE StieglitzSnow, ONLY: cpw_pub !cpwpub causing error 6580:Name in only list does not exist or is not accessible + use Catch_Constants, ONLY: & + RHOFS => CATCH_SNWALB_RHOFS + ! N_CONSTIT => CATCH_N_CONSTIT !!LCA added for test... + implicit none @@ -3540,15 +3546,23 @@ subroutine cat_enkf_increments( & type(obs_param_type) :: this_obs_param !jpark50 + real :: asnow_fcst, swe_fcst, swe_ana, asnow_ana, isnow, swe_ratio + real, dimension(N_catd, N_ens) :: swe_incrm real, dimension(N_catd, N_ens) :: wesn_sum_old - real, dimension(N_catd, N_ens) :: areasc_old - !real, parameter:: cpw = 2065.22 !ice specific heat capacity @ 0C [J/kg/K] - real, parameter:: alpha_threshold = 0.20 !lca modified name and value 2/2/22 - real, parameter:: beta_threshold = 0.40 !lca modified name and value 2/2/22 - real, parameter:: wesn_max = 5.0 ! kg m-2 from Toure et al. 2018, lca modified 2/3/22 - real, parameter:: wesn_min = 13.0 ! kg m-2 from Toure et al. 2018, lca added 2/3/22 - real, parameter:: eps = 1.e-4 - real, parameter:: small = 1.e-20 + real, dimension(N_catd, N_ens) :: areasc_old + real, dimension(N_catd, N_ens, N_snow):: tmp_wesn, tmp_htsn, tmp_sndz + !integer, parameter:: N_constit = 9 + real, dimension(N_snow, N_constit) :: rconstit + real, dimension(N_snow), parameter :: DZMAX = (/0.08, 0.5, 0.5/) + !type(cat_progn_type), intent(in), dimension(N_catd, N_ens):: tmp_progn + real, parameter:: cpw = 2065.22 !ice specific heat capacity @ 0C [J/kg/K]THIS seems like it shouldbe defined elsewhere!!! But, will check later lca 5/5/22 + real, parameter:: alpha_threshold = 0.20 !lca modified name and value 2/2/22 + real, parameter:: beta_threshold = 0.40 !lca modified name and value 2/2/22 + real, parameter:: max_incr_swe = 5.0 ! kg m-2 from Toure et al. 2018, lca modified 2/3/22 + real, parameter:: wesn_min = 13.0 ! kg m-2 from Toure et al. 2018, lca added 2/3/22 + real, parameter:: eps = 1.e-4 + real, parameter:: small = 1.e-20 + ! real, parameter:: rhofs = 150. ! kg/m^3 density of fresh snow ! real, parameter:: rhoma = 500. ! kg/m^3 maximum snow density ! real, parameter:: wemin = 13. ! kg/m^3 @@ -4497,27 +4511,24 @@ subroutine cat_enkf_increments( & if (logit) write (logunit, *) 'get 1d snow(asnow) increments; MODIS SCF' !identify the species ID number of interest - N_select_varnames = 1 select_varnames(1) = 'asnow' + N_select_varnames = 1 + select_varnames(1) = 'asnow' call get_select_species( & N_select_varnames, select_varnames(1:N_select_varnames), & N_obs_param, obs_param, N_select_species, select_species ) + !if(logit) write(logunit,*) 'N_catd=', N_catd !if(logit) write(logunit,*) 'MET forcing length', size(met_force%Tair) !if(logit) write(logunit,*) 'metforce%Tair', met_force%Tair !if(logit) write(logunit,*) 'lat', tile_coord%com_lat !if(logit) write(logunit,*) 'lon', tile_coord%com_lon - !Rule-based snow SCF update + ! Rule-based asnow update allocate(select_tilenum(1)) allocate(deduction(N_catd)) - - deduction = met_force%Tair-MAPL_TICE !this can be negative or positive lca 2/2/22, but still not sure what it is for and why it isnt calculated in the catchment for loop - !Print the value and length of 'deduction' - !if(logit) write(logunit,*) 'deduction: ', deduction - !if(logit) write(logunit,*) 'length of deduction:', size(deduction) - + do n=1,N_catd !for each catchment ! find observations for catchment n @@ -4532,114 +4543,86 @@ subroutine cat_enkf_increments( & if (N_selected_obs == 1) then - do n_e=1,N_ens ! for each ensemble member (1) determine action and - - !*** Add snow *** - !**************** - !if the model SCF is less than the Obs SCF times alpha then ADD snow - !alpha = alpha_threshold = 0.2 - if(asnow_ensavg(n) .lt. Observations(ind_obs(1))%obs * alpha_threshold) then - !if(logit) write (logunit, *) 'Add snow: ' & - ! 'MODIS_SCF = ', Observations(ind_obs(1))%obs, 'model_SCF = ',asnow_ensavg(n) - !tot_swe_init = cat_progn(n,n_e)%wesn(1) + cat_progn(n,n_e)%wesn(2) + cat_progn(n,n_e)%wesn(3) - - areasc_minus = min( (cat_progn(n,n_e)%wesn(1) + cat_progn(n,n_e)%wesn(2) + cat_progn(n,n_e)%wesn(3)) / WEMIN, 1.0) - + do n_e=1,N_ens ! for each ensemble member (1) calculate the asnow update - do isnow = 1,N_snow - !1. calculate increment to be added and update SWE - cat_progn_incr(n,n_e)%wesn(isnow) = (wesn_max / float(N_snow)) * & - (observations(ind_obs(1)%obs - asnow_ensavg(n) /alpha_threshold) - - !2. Update wesn - wesn_ratio(isnow) = (cat_progn(n,n_e)%wesn(isnow) + cat_progn_incr(n,n_e)%wesn(isnow) / cat_progn(n,n_e)%wesn(isnow) + ! 1. Calculate the model forecast snow area and swe for each ens + asnow_fcst = asnow(n, n_e) + swe_fcst = sum(cat_progn(n, n_e)%wesn(1:N_snow)) + + ! 2. Calculate the SWE update increment based on Toure et al (2018) eq 1 + if(asnow_fcst .lt. Observations(ind_obs(1))%obs * alpha_threshold) then + ! SCA of model is less than observed SCA, ****ADD SNOW**** + swe_incrm(n, n_e) = max_incr_swe * Observations(ind_obs(1))%obs & + - (asnow_fcst / alpha_threshold) - cat_progn(n,n_e)%wesn(isnow) = cat_progn(n,n_e)%wesn(isnow) * wesn_ratio(isnow) + elseif (Observations(ind_obs(1))%obs .le. beta_threshold) then + !IF SCA of model is greater than observed SCA, ****REMOVE SNOW**** + swe_incrm(n, n_e) = (-1) * swe_fcst * (1 - Observations(ind_obs(1))%obs / beta_threshold) + + else + !If the thresholds are not met, make *****NO CHANGE TO SNOW**** + swe_incrm(n, n_e) = 0.0 + + endif !Toure et al. Eq 1 + + ! 3. Calculate a temporary SWE and SCA for each ensemble members + swe_ana = min(swe_fcst + swe_incrm(n, n_e), 0.0) + !call StieglitzSnow_calc_asnow(N_snow, N_catd, swe_ana, asnow_ana) + asnow_ana = min(swe_ana/wemin, 1.) !This is from StieglitzSnow_calc_asnow + + ! 4. Apply the corrected SWE to each layer and adjust the heat content and snow depth in tmp variable + do isnow = 1, N_snow + if (asnow_fcst .gt. 0.0 .and. asnow_ana .lt. 1.0) then + swe_ratio = swe_ana / swe_fcst + tmp_wesn(n, n_e, isnow) = cat_progn(n, n_e)%wesn(isnow) * swe_ratio + tmp_htsn(n, n_e, isnow) = cat_progn(n, n_e)%htsn(isnow) * swe_ratio + tmp_sndz(n, n_e, isnow) = cat_progn(n, n_e)%sndz(isnow) + + elseif (asnow_fcst .gt. 0.0 .and. asnow_ana .eq. 1.0) then + tmp_wesn(n, n_e, isnow) = swe_ana / swe_fcst + tmp_htsn(n, n_e, isnow) = cat_progn(n, n_e)%htsn(isnow) * swe_ratio + tmp_sndz(n, n_e, isnow) = cat_progn(n, n_e)%sndz(isnow) * swe_ratio + + elseif (asnow_fcst .eq. 0.0 .and. asnow_ana .lt. 1.0) then + tmp_wesn(n, n_e, isnow) = swe_ana / N_snow + tmp_htsn(n, n_e, isnow) = 0.0 !This shuld be changed to use the air temperature if its below freezing + tmp_sndz(n ,n_e, isnow) = (WEMIN * RHOFS) / N_snow !This using the min swe and fresh snow density to calculate depth, then applies it equally over each snow layer + + elseif (asnow_fcst .eq. 0.0 .and. asnow_ana .eq. 1.0) then + tmp_wesn(n, n_e, isnow) = swe_ana / N_snow + tmp_htsn(n, n_e, isnow) = 0.0 !This should be changed to use the air temperature if below freezing + tmp_sndz(n, n_e, isnow) = (swe_ana * RHOFS) / N_snow !Same as above, but allows the depth to increase with SWE because the catchment is snow covered + + else + tmp_wesn(n, n_e, isnow) = cat_progn(n, n_e)%wesn(isnow) + tmp_htsn(n, n_e, isnow) = cat_progn(n ,n_e)%htsn(isnow) + tmp_sndz(n, n_e, isnow) = cat_progn(n, n_e)%sndz(isnow) + + endif !(asnow_fcst .gt. ...) + enddo !isnow = 1, N_snow + + !5. call relayer2 to balance the snow column (check this...) Turned off because of variable definition.... + call relayer2(N_snow, N_constit , DZMAX(1), DZMAX(2:N_snow), & + tmp_htsn(n,n_e,1:N_snow), tmp_wesn(n, n_e, 1:N_snow), tmp_sndz(n, n_e,1:N_snow), rconstit) + + + !6. Calculate useable increments from fcst and temporarily updated swe, htsn, sndz !intent out... for cat_progn_incr + cat_progn_incr(n, n_e)%wesn(1:N_snow) = tmp_wesn(n, n_e, 1:N_snow) - cat_progn(n, n_e)%wesn(1:N_snow) + cat_progn_incr(n, n_e)%htsn(1:N_snow) = tmp_htsn(n, n_e, 1:N_snow) - cat_progn(n, n_e)%htsn(1:N_snow) + cat_progn_incr(n, n_e)%sndz(1:N_snow) = tmp_sndz(n, n_e, 1:N_snow) - cat_progn(n, n_e)%sndz(1:N_snow) + + end do ! n_e = 1, N_ens + end if ! if (N_selected_obs == 1) + end do ! n=1,N_catd - end do - - !Calculate new snow cover area - areasc_plus = min( ( cat_progn(n,n_e)%wesn(1) + cat_progn(n,n_e)%wesn(2) + cat_progn(n,n_e)%wesn(3)/ WEMIN, 1.0) - - !3. Update snow depth using rules to define density and heat content - do isnow = 1, N_snow - - !Case 1: if the inital area is zero and snow is added then the depth is dependent on updated SWE and fresh density - ! and the heat content is updated assuming the snow is at MAPL_TICE (273.16) - if ( (areasc_minus.eq.0.0) .and. (areasc_plus.gt.0.0) ) then !These can probably be simplified - cat_progn(n,n_e)%sndz(isnow) = cat_progn(n,n_e)%wesn(isnow) /RHOFS - cat_progn(n,n_e)%htsn(isnow) = 0.0 ! heat content = ci * wesn * (Ti-Tm). If assume fresh snow is isothermal and @0*C - endif - !Case 2: if the initial area is less than 1 and final area is less than or equal to 1 - ! then depth increases based on the wesn_ratio (?? check) - if ( (areasc_minus.le.1.0) .and. (areasc_plus.le.1.0) ) then ! These can probably be simplified - cat_progn(n, n_e)%sndz(isnow) = cat_progn(n,n_e)%sndz(isnow) * wesn_ratio(isnow) - cat_progn(n, n_e)%htsn(isnow) = cat_progn(n,n_e%htsn(isnow) * wesn_ratio(isnow) - endif - end do - - !*** Remove snow *** - !******************* - !if the model SCF is greater than or equal to the Obs SCF times alpha - !AND the Observed SCF is less than beta, then REMOVE snow - elseif(asnow_ensavg(n) .ge. Observations(ind_obs(1))%obs * alpha_threshold) .AND. & !!Is the first part of this statement needed? - (Observations(ind_obs(1))%obs .lt. beta_threshold) then - !if (logit) write (logunit, *) 'Remove snow: ', & - ! 'MODIS_SCF = ', Observations(ind_obs(1))%obs, 'model_SCF = ',asnow_ensavg(n) - areasc_minus = min( (cat_progn(n,n_e)%wesn(1) + cat_progn(n,n_e)%wesn(2) + cat_progn(n,n_e)%wesn(3)) / WEMIN, 1.0) - - - do isnow = 1,N_snow - !1. calculate increment to be added and update SWE - cat_progn_incr(n,n_e)%wesn(isnow) = -wesn_min * & - (1 - asnow_ensavg(n) /beta_threshold) !Check this equation!!!! - - !2. Update wesn - wesn_ratio(isnow) = (cat_progn(n,n_e)%wesn(isnow) + cat_progn_incr(n,n_e)%wesn(isnow) / cat_progn(n,n_e)%wesn(isnow) - - cat_progn(n,n_e)%wesn(isnow) = cat_progn(n,n_e)%wesn(isnow) * wesn_ratio(isnow) - end do - - !Calculate new snow cover area, this is different than add because there needs to be a protection against negative SWE(?) - areasc_plus = max( ( cat_progn(n,n_e)%wesn(1) + cat_progn(n,n_e)%wesn(2) + cat_progn(n,n_e)%wesn(3)/ WEMIN, 0.0) - - !3. Update snow depth using rules to define density and heat content - do isnow = 1, N_snow - - !Case 1: if the inital area is greater than zero and the updated area is zero, then depth and heat content are zero - if ( (areasc_minus.gt.0.0) .and. (areasc_plus.eq.0.0) ) then !These can probably be simplified - cat_progn(n,n_e)%sndz(isnow) = 0.0 - cat_progn(n,n_e)%htsn(isnow) = 0.0 ! heat content = ci * wesn * (Ti-Tm). If assume fresh snow is isothermal and @0*C - endif - !Case 2: if the initial area is less than 1 and final area is less than or equal to 1 - ! then depth increases based on the wesn_ratio (?? check) - if ( (areasc_minus.gt.0.0) .and. (areasc_plus.gt.0.0) ) then ! These can probably be simplified - cat_progn(n, n_e)%sndz(isnow) = cat_progn(n,n_e)%sndz(isnow) * wesn_ratio(isnow) - cat_progn(n, n_e)%htsn(isnow) = cat_progn(n,n_e%htsn(isnow) * wesn_ratio(isnow) - endif - end do - !*** No Add, No remove snow *** - !****************************** - !If neither conditions is met then do nothing ( NO add No remove) - else - !if (logit) write (logunit, *) 'No add No remove: ', & - ! 'MODIS_SCF = ', Observations(ind_obs(1))%obs, 'model_SCF = ',asnow_ensavg(n) - cat_progn_incr(n,n_e)%wesn(isnow) = 0.0 - - end if ! snow actions - - end do ! n_e=1,N_ens - end if ! (N_selected_obs == 1) - end do ! n=1,N_catd - ! ---------------------------------- - + case default - + call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'unknown update_type') - + end select select_update_type ! clean up From 48a4a303e546328be3f5ed1dc666c0960f077c33 Mon Sep 17 00:00:00 2001 From: Rolf Reichle <54944691+gmao-rreichle@users.noreply.github.com> Date: Fri, 27 May 2022 13:32:17 -0400 Subject: [PATCH 022/308] dummy commit (added one space in components.yaml) --- components.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components.yaml b/components.yaml index 805f588c..53da7d03 100644 --- a/components.yaml +++ b/components.yaml @@ -35,6 +35,6 @@ MAPL: GEOSgcm_GridComp: local: ./src/Components/GEOSldas_GridComp/@GEOSgcm_GridComp remote: ../GEOSgcm_GridComp.git - branch: feature/rreichle/MODIS_snow_cover_fraction_assimilation + branch: feature/rreichle/MODIS_snow_cover_fraction_assimilation sparse: ./config/GEOSgcm_GridComp_ldas.sparse develop: develop From 001bbe1a4f0f5416f50e3341468c0ec1d2131219 Mon Sep 17 00:00:00 2001 From: "Lauren C. Andrews" Date: Fri, 29 Jul 2022 13:49:44 -0400 Subject: [PATCH 023/308] reverting components.yaml --- components.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components.yaml b/components.yaml index aa7c5c12..26b3a0d8 100644 --- a/components.yaml +++ b/components.yaml @@ -35,6 +35,6 @@ MAPL: GEOSgcm_GridComp: local: ./src/Components/GEOSldas_GridComp/@GEOSgcm_GridComp remote: ../GEOSgcm_GridComp.git - branch: feature/rreichle/MODIS_snow_cover_fraction_assimilation + branch: develop sparse: ./config/GEOSgcm_GridComp_ldas.sparse develop: develop From 740cac93ddbffb8bd6c38935534f4e66531f140f Mon Sep 17 00:00:00 2001 From: "Lauren C. Andrews" Date: Thu, 15 Sep 2022 14:39:34 -0400 Subject: [PATCH 024/308] updates to snow da, correct cat_progn_incr --- .../clsm_ensupd_upd_routines.F90 | 72 ++++++++++++++----- 1 file changed, 53 insertions(+), 19 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index b319625d..8fa061c3 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -3546,7 +3546,7 @@ subroutine cat_enkf_increments( & type(obs_param_type) :: this_obs_param !jpark50 - real :: asnow_fcst, swe_fcst, swe_ana, asnow_ana, isnow, swe_ratio + real :: asnow_fcst, swe_fcst, swe_ana, asnow_ana, isnow, swe_ratio, tmp_swe real, dimension(N_catd, N_ens) :: swe_incrm real, dimension(N_catd, N_ens) :: wesn_sum_old real, dimension(N_catd, N_ens) :: areasc_old @@ -4555,9 +4555,9 @@ subroutine cat_enkf_increments( & swe_incrm(n, n_e) = max_incr_swe * Observations(ind_obs(1))%obs & - (asnow_fcst / alpha_threshold) - elseif (Observations(ind_obs(1))%obs .le. beta_threshold) then + elseif (Observations(ind_obs(1))%obs .lt. beta_threshold .AND. asnow_fcst .ge. Observations(ind_obs(1))%obs *alpha_threshold ) then !IF SCA of model is greater than observed SCA, ****REMOVE SNOW**** - swe_incrm(n, n_e) = (-1) * swe_fcst * (1 - Observations(ind_obs(1))%obs / beta_threshold) + swe_incrm(n, n_e) = (-1) * max_incr_swe * (1 - Observations(ind_obs(1))%obs / beta_threshold) else !If the thresholds are not met, make *****NO CHANGE TO SNOW**** @@ -4566,51 +4566,85 @@ subroutine cat_enkf_increments( & endif !Toure et al. Eq 1 ! 3. Calculate a temporary SWE and SCA for each ensemble members - swe_ana = min(swe_fcst + swe_incrm(n, n_e), 0.0) + swe_ana = max(swe_fcst + swe_incrm(n, n_e), 0.0) + !call StieglitzSnow_calc_asnow(N_snow, N_catd, swe_ana, asnow_ana) asnow_ana = min(swe_ana/wemin, 1.) !This is from StieglitzSnow_calc_asnow + if (logit) write (logunit, *) 'asnow_fcst = ', asnow_fcst, & + 'swe_incrm = ', swe_incrm(n, n_e), & + 'swe_ana = ', swe_ana, & + 'asnow_ana = ', asnow_ana, & + '-----------' + ! 4. Apply the corrected SWE to each layer and adjust the heat content and snow depth in tmp variable do isnow = 1, N_snow - if (asnow_fcst .gt. 0.0 .and. asnow_ana .lt. 1.0) then + if (asnow_fcst .ge. 0.0 .and. asnow_ana .eq. 0.0) then + tmp_wesn(n, n_e, isnow) = 0.0 + tmp_htsn(n, n_e, isnow) = 0.0 + tmp_sndz(n, n_e, isnow) = 0.0 + if (logit) write (logunit, *) '%%%%%% asnow_ana = 0.0' + + elseif (asnow_fcst .gt. 0.0 .and. asnow_ana .lt. 1.0) then swe_ratio = swe_ana / swe_fcst tmp_wesn(n, n_e, isnow) = cat_progn(n, n_e)%wesn(isnow) * swe_ratio tmp_htsn(n, n_e, isnow) = cat_progn(n, n_e)%htsn(isnow) * swe_ratio - tmp_sndz(n, n_e, isnow) = cat_progn(n, n_e)%sndz(isnow) + tmp_sndz(n, n_e, isnow) = cat_progn(n, n_e)%sndz(isnow) !In this case, snow depth remains constant and only extent/hc change. + if (logit) write (logunit, *) '%%%%%% asnow_fcst > 0 ; asnow_ana < 1.0' elseif (asnow_fcst .gt. 0.0 .and. asnow_ana .eq. 1.0) then - tmp_wesn(n, n_e, isnow) = swe_ana / swe_fcst + swe_ratio = swe_ana / swe_fcst + tmp_wesn(n, n_e, isnow) = cat_progn(n, n_e)%wesn(isnow) * swe_ratio tmp_htsn(n, n_e, isnow) = cat_progn(n, n_e)%htsn(isnow) * swe_ratio tmp_sndz(n, n_e, isnow) = cat_progn(n, n_e)%sndz(isnow) * swe_ratio - + if (logit) write (logunit, *) '%%%%%% asnow_fcst > 0 ; asnow_ana = 1.0' + elseif (asnow_fcst .eq. 0.0 .and. asnow_ana .lt. 1.0) then tmp_wesn(n, n_e, isnow) = swe_ana / N_snow - tmp_htsn(n, n_e, isnow) = 0.0 !This shuld be changed to use the air temperature if its below freezing - tmp_sndz(n ,n_e, isnow) = (WEMIN * RHOFS) / N_snow !This using the min swe and fresh snow density to calculate depth, then applies it equally over each snow layer - + tmp_htsn(n, n_e, isnow) = (0.0 - MAPL_ALHF)*tmp_wesn(n,n_e,isnow) !This is temporary. Zero should be changed to use the air temperature if its below freezing + tmp_sndz(n ,n_e, isnow) = (WEMIN / RHOFS) / N_snow + if (logit) write (logunit, *) '%%%%%% asnow_fcst = 0 ; asnow_ana < 1.0' + elseif (asnow_fcst .eq. 0.0 .and. asnow_ana .eq. 1.0) then tmp_wesn(n, n_e, isnow) = swe_ana / N_snow - tmp_htsn(n, n_e, isnow) = 0.0 !This should be changed to use the air temperature if below freezing - tmp_sndz(n, n_e, isnow) = (swe_ana * RHOFS) / N_snow !Same as above, but allows the depth to increase with SWE because the catchment is snow covered - + tmp_htsn(n, n_e, isnow) = (0.0 - MAPL_ALHF)*tmp_wesn(n,n_e,isnow) !This assumes that the snow temperature is zero. See above + tmp_sndz(n, n_e, isnow) = (swe_ana / RHOFS) / N_snow !Same as above, but allows the depth to increase with SWE because the catchment is snow covered + if (logit) write (logunit, *) '%%%%%% asnow_fcst = 0 ; asnow_ana = 1.0' + else tmp_wesn(n, n_e, isnow) = cat_progn(n, n_e)%wesn(isnow) tmp_htsn(n, n_e, isnow) = cat_progn(n ,n_e)%htsn(isnow) tmp_sndz(n, n_e, isnow) = cat_progn(n, n_e)%sndz(isnow) + if (logit) write (logunit, *) '%%%%%% else' endif !(asnow_fcst .gt. ...) enddo !isnow = 1, N_snow - !5. call relayer2 to balance the snow column (check this...) Turned off because of variable definition.... - call relayer2(N_snow, N_constit , DZMAX(1), DZMAX(2:N_snow), & - tmp_htsn(n,n_e,1:N_snow), tmp_wesn(n, n_e, 1:N_snow), tmp_sndz(n, n_e,1:N_snow), rconstit) - - + !5. call relayer2 to balance the snow column (check this...) Turned off for simplicity + !call relayer2(N_snow, N_constit , DZMAX(1), DZMAX(2:N_snow), & + ! tmp_htsn(n,n_e,1:N_snow), tmp_wesn(n, n_e, 1:N_snow), tmp_sndz(n, n_e,1:N_snow), rconstit) + + !print the old and new swe, heat content and snow density + if (logit) write (logunit, *) & + 'fcst_wesn = ', cat_progn(n, n_e)%wesn(1:N_snow), & + 'tmp_wesn = ', tmp_wesn(n,n_e, 1:N_snow), & + 'fcst_htsn = ', cat_progn(n, n_e)%htsn(1:N_snow),& + 'tmp_htsn = ', tmp_htsn(n, n_e, 1:N_snow), & + 'fcst_sndz = ', cat_progn(n, n_e)%sndz(1:N_snow), & + 'tmp_sndz = ', tmp_sndz(n ,n_e,1:N_snow), & + '--------------------------------------' !6. Calculate useable increments from fcst and temporarily updated swe, htsn, sndz !intent out... for cat_progn_incr cat_progn_incr(n, n_e)%wesn(1:N_snow) = tmp_wesn(n, n_e, 1:N_snow) - cat_progn(n, n_e)%wesn(1:N_snow) cat_progn_incr(n, n_e)%htsn(1:N_snow) = tmp_htsn(n, n_e, 1:N_snow) - cat_progn(n, n_e)%htsn(1:N_snow) cat_progn_incr(n, n_e)%sndz(1:N_snow) = tmp_sndz(n, n_e, 1:N_snow) - cat_progn(n, n_e)%sndz(1:N_snow) + if (logit) write (logunit, *) & + 'cat_progn_incr WESN = ' ,cat_progn_incr(n, n_e)%wesn(1:N_snow), & + 'cat_progn_incr htsn = ' ,cat_progn_incr(n, n_e)%htsn(1:N_snow), & + 'cat_progn_incr sndz = ' ,cat_progn_incr(n, n_e)%sndz(1:N_snow),& + '******************************' + + end do ! n_e = 1, N_ens end if ! if (N_selected_obs == 1) end do ! n=1,N_catd From 78431e5b7e9fd9b3c1d0c7368202dc5af517a8d5 Mon Sep 17 00:00:00 2001 From: "Lauren C. Andrews" Date: Wed, 21 Sep 2022 10:10:51 -0400 Subject: [PATCH 025/308] updates to snow fraction assimilation --- .../clsm_ensupd_upd_routines.F90 | 39 ++++++------------- 1 file changed, 11 insertions(+), 28 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index 8fa061c3..da38cd73 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -4518,13 +4518,6 @@ subroutine cat_enkf_increments( & N_select_varnames, select_varnames(1:N_select_varnames), & N_obs_param, obs_param, N_select_species, select_species ) - - !if(logit) write(logunit,*) 'N_catd=', N_catd - !if(logit) write(logunit,*) 'MET forcing length', size(met_force%Tair) - !if(logit) write(logunit,*) 'metforce%Tair', met_force%Tair - !if(logit) write(logunit,*) 'lat', tile_coord%com_lat - !if(logit) write(logunit,*) 'lon', tile_coord%com_lon - ! Rule-based asnow update allocate(select_tilenum(1)) allocate(deduction(N_catd)) @@ -4571,11 +4564,6 @@ subroutine cat_enkf_increments( & !call StieglitzSnow_calc_asnow(N_snow, N_catd, swe_ana, asnow_ana) asnow_ana = min(swe_ana/wemin, 1.) !This is from StieglitzSnow_calc_asnow - if (logit) write (logunit, *) 'asnow_fcst = ', asnow_fcst, & - 'swe_incrm = ', swe_incrm(n, n_e), & - 'swe_ana = ', swe_ana, & - 'asnow_ana = ', asnow_ana, & - '-----------' ! 4. Apply the corrected SWE to each layer and adjust the heat content and snow depth in tmp variable do isnow = 1, N_snow @@ -4585,14 +4573,16 @@ subroutine cat_enkf_increments( & tmp_sndz(n, n_e, isnow) = 0.0 if (logit) write (logunit, *) '%%%%%% asnow_ana = 0.0' - elseif (asnow_fcst .gt. 0.0 .and. asnow_ana .lt. 1.0) then - swe_ratio = swe_ana / swe_fcst - tmp_wesn(n, n_e, isnow) = cat_progn(n, n_e)%wesn(isnow) * swe_ratio - tmp_htsn(n, n_e, isnow) = cat_progn(n, n_e)%htsn(isnow) * swe_ratio - tmp_sndz(n, n_e, isnow) = cat_progn(n, n_e)%sndz(isnow) !In this case, snow depth remains constant and only extent/hc change. - if (logit) write (logunit, *) '%%%%%% asnow_fcst > 0 ; asnow_ana < 1.0' - elseif (asnow_fcst .gt. 0.0 .and. asnow_ana .eq. 1.0) then + !Commented out because not updating the snow depth causes the model to fail after the first assimilation step + !elseif (asnow_fcst .gt. 0.0 .and. asnow_ana .lt. 1.0) then + ! swe_ratio = swe_ana / swe_fcst + ! tmp_wesn(n, n_e, isnow) = cat_progn(n, n_e)%wesn(isnow) * swe_ratio + ! tmp_htsn(n, n_e, isnow) = cat_progn(n, n_e)%htsn(isnow) * swe_ratio + ! tmp_sndz(n, n_e, isnow) = cat_progn(n, n_e)%sndz(isnow) !In this case, snow depth remains constant and only extent/hc change. + ! if (logit) write (logunit, *) '%%%%%% asnow_fcst > 0 ; asnow_ana < 1.0' + + elseif (asnow_fcst .gt. 0.0 .and. asnow_ana .le. 1.0) then !Changed this statement from asnow_ana .lt. 1.0 to ansow_ana .le. 1.0 to cover the commented statement above (where analyzed snow fraction is 1.0) swe_ratio = swe_ana / swe_fcst tmp_wesn(n, n_e, isnow) = cat_progn(n, n_e)%wesn(isnow) * swe_ratio tmp_htsn(n, n_e, isnow) = cat_progn(n, n_e)%htsn(isnow) * swe_ratio @@ -4621,8 +4611,8 @@ subroutine cat_enkf_increments( & enddo !isnow = 1, N_snow !5. call relayer2 to balance the snow column (check this...) Turned off for simplicity - !call relayer2(N_snow, N_constit , DZMAX(1), DZMAX(2:N_snow), & - ! tmp_htsn(n,n_e,1:N_snow), tmp_wesn(n, n_e, 1:N_snow), tmp_sndz(n, n_e,1:N_snow), rconstit) + call relayer2(N_snow, N_constit , DZMAX(1), DZMAX(2:N_snow), & + tmp_htsn(n,n_e,1:N_snow), tmp_wesn(n, n_e, 1:N_snow), tmp_sndz(n, n_e,1:N_snow), rconstit) !print the old and new swe, heat content and snow density if (logit) write (logunit, *) & @@ -4638,13 +4628,6 @@ subroutine cat_enkf_increments( & cat_progn_incr(n, n_e)%htsn(1:N_snow) = tmp_htsn(n, n_e, 1:N_snow) - cat_progn(n, n_e)%htsn(1:N_snow) cat_progn_incr(n, n_e)%sndz(1:N_snow) = tmp_sndz(n, n_e, 1:N_snow) - cat_progn(n, n_e)%sndz(1:N_snow) - if (logit) write (logunit, *) & - 'cat_progn_incr WESN = ' ,cat_progn_incr(n, n_e)%wesn(1:N_snow), & - 'cat_progn_incr htsn = ' ,cat_progn_incr(n, n_e)%htsn(1:N_snow), & - 'cat_progn_incr sndz = ' ,cat_progn_incr(n, n_e)%sndz(1:N_snow),& - '******************************' - - end do ! n_e = 1, N_ens end if ! if (N_selected_obs == 1) end do ! n=1,N_catd From 1342aa218d992cb833606a18d7da428e48073b7c Mon Sep 17 00:00:00 2001 From: "Lauren C. Andrews" Date: Fri, 30 Sep 2022 14:37:18 -0400 Subject: [PATCH 026/308] updates to sno depth incr --- .../clsm_ensupd_upd_routines.F90 | 37 +++++++++---------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index da38cd73..c72b71ce 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -3559,6 +3559,7 @@ subroutine cat_enkf_increments( & real, parameter:: alpha_threshold = 0.20 !lca modified name and value 2/2/22 real, parameter:: beta_threshold = 0.40 !lca modified name and value 2/2/22 real, parameter:: max_incr_swe = 5.0 ! kg m-2 from Toure et al. 2018, lca modified 2/3/22 + real, parameter:: smallfcstswe = 0.01 !This keeps the swe_ratio used in data assmilation reasonably small real, parameter:: wesn_min = 13.0 ! kg m-2 from Toure et al. 2018, lca added 2/3/22 real, parameter:: eps = 1.e-4 real, parameter:: small = 1.e-20 @@ -4562,8 +4563,10 @@ subroutine cat_enkf_increments( & swe_ana = max(swe_fcst + swe_incrm(n, n_e), 0.0) !call StieglitzSnow_calc_asnow(N_snow, N_catd, swe_ana, asnow_ana) - asnow_ana = min(swe_ana/wemin, 1.) !This is from StieglitzSnow_calc_asnow + !asnow_ana = min(swe_ana/wemin, 1.) !This is from StieglitzSnow_calc_asnow + swe_ratio = swe_ana / swe_fcst + if (logit) write (logunit, *) '!!!! swe_ratio = ' , swe_ana, swe_fcst, '!!!!' ! 4. Apply the corrected SWE to each layer and adjust the heat content and snow depth in tmp variable do isnow = 1, N_snow @@ -4573,34 +4576,30 @@ subroutine cat_enkf_increments( & tmp_sndz(n, n_e, isnow) = 0.0 if (logit) write (logunit, *) '%%%%%% asnow_ana = 0.0' - - !Commented out because not updating the snow depth causes the model to fail after the first assimilation step - !elseif (asnow_fcst .gt. 0.0 .and. asnow_ana .lt. 1.0) then - ! swe_ratio = swe_ana / swe_fcst - ! tmp_wesn(n, n_e, isnow) = cat_progn(n, n_e)%wesn(isnow) * swe_ratio - ! tmp_htsn(n, n_e, isnow) = cat_progn(n, n_e)%htsn(isnow) * swe_ratio - ! tmp_sndz(n, n_e, isnow) = cat_progn(n, n_e)%sndz(isnow) !In this case, snow depth remains constant and only extent/hc change. - ! if (logit) write (logunit, *) '%%%%%% asnow_fcst > 0 ; asnow_ana < 1.0' - - elseif (asnow_fcst .gt. 0.0 .and. asnow_ana .le. 1.0) then !Changed this statement from asnow_ana .lt. 1.0 to ansow_ana .le. 1.0 to cover the commented statement above (where analyzed snow fraction is 1.0) - swe_ratio = swe_ana / swe_fcst - tmp_wesn(n, n_e, isnow) = cat_progn(n, n_e)%wesn(isnow) * swe_ratio - tmp_htsn(n, n_e, isnow) = cat_progn(n, n_e)%htsn(isnow) * swe_ratio - tmp_sndz(n, n_e, isnow) = cat_progn(n, n_e)%sndz(isnow) * swe_ratio - if (logit) write (logunit, *) '%%%%%% asnow_fcst > 0 ; asnow_ana = 1.0' - elseif (asnow_fcst .eq. 0.0 .and. asnow_ana .lt. 1.0) then tmp_wesn(n, n_e, isnow) = swe_ana / N_snow - tmp_htsn(n, n_e, isnow) = (0.0 - MAPL_ALHF)*tmp_wesn(n,n_e,isnow) !This is temporary. Zero should be changed to use the air temperature if its below freezing + tmp_htsn(n, n_e, isnow) = (0.0 - MAPL_ALHF)*tmp_wesn(n,n_e,isnow) tmp_sndz(n ,n_e, isnow) = (WEMIN / RHOFS) / N_snow if (logit) write (logunit, *) '%%%%%% asnow_fcst = 0 ; asnow_ana < 1.0' elseif (asnow_fcst .eq. 0.0 .and. asnow_ana .eq. 1.0) then tmp_wesn(n, n_e, isnow) = swe_ana / N_snow - tmp_htsn(n, n_e, isnow) = (0.0 - MAPL_ALHF)*tmp_wesn(n,n_e,isnow) !This assumes that the snow temperature is zero. See above + tmp_htsn(n, n_e, isnow) = (0.0 - MAPL_ALHF)*tmp_wesn(n,n_e,isnow) !This assumes that the snow temperature is zero. tmp_sndz(n, n_e, isnow) = (swe_ana / RHOFS) / N_snow !Same as above, but allows the depth to increase with SWE because the catchment is snow covered if (logit) write (logunit, *) '%%%%%% asnow_fcst = 0 ; asnow_ana = 1.0' + elseif (asnow_fcst .gt. smallfcstswe .and. asnow_ana .lt. 1.0) then + tmp_wesn(n, n_e, isnow) = cat_progn(n, n_e)%wesn(isnow) * swe_ratio + tmp_htsn(n, n_e, isnow) = cat_progn(n, n_e)%htsn(isnow) * swe_ratio + tmp_sndz(n, n_e, isnow) = cat_progn(n, n_e)%sndz(isnow) !In this case, snow depth remains constant and only extent/hc change. + if (logit) write (logunit, *) '%%%%%% asnow_fcst > 0 ; asnow_ana < 1.0' + + elseif (asnow_fcst .gt.smallfcstswe .and. asnow_ana .eq. 1.0) then + tmp_wesn(n, n_e, isnow) = cat_progn(n, n_e)%wesn(isnow) * swe_ratio + tmp_htsn(n, n_e, isnow) = cat_progn(n, n_e)%htsn(isnow) * swe_ratio + tmp_sndz(n, n_e, isnow) = cat_progn(n, n_e)%sndz(isnow) + tmp_wesn(n, n_e, isnow) / (cat_progn(n, n_e)%wesn(isnow) / cat_progn(n, n_e)%sndz(isnow)) + if (logit) write (logunit, *) '%%%%%% asnow_fcst > 0 ; asnow_ana = 1.0' + else tmp_wesn(n, n_e, isnow) = cat_progn(n, n_e)%wesn(isnow) tmp_htsn(n, n_e, isnow) = cat_progn(n ,n_e)%htsn(isnow) From 0419be670efcc9d1246f24bf51035663ec4a5106 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Fri, 7 Oct 2022 16:18:16 -0400 Subject: [PATCH 027/308] Additional snow analysis changes (clsm_ensupd_upd_routines.F90): Bug fixes: - Toure et al 2018 equation 1 - Added missing parentheses in ADD SNOW case - Changed 1 to 1. (real number) in REMOVE SNOW case - Changed declaration of isnow from real to integer Cleanup: - Simplified if block logic for computing layer-based analysis - Replaced loop index n with kk for clarity and searchability - Removed unused variables --- .../clsm_ensupd_upd_routines.F90 | 300 ++++++++++-------- 1 file changed, 159 insertions(+), 141 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index c72b71ce..18cab8f0 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -3428,10 +3428,6 @@ subroutine cat_enkf_increments( & ! ! -------------------------------------------------------------- - ! IMPORTANT: - ! on input, cat_progn must contain cat_progn_minus(1:N_catd,1:N_ens) - ! on output, cat_progn_incr contains INCREMENTS - ! type of update is selected by "update_type" ! ********************************************************************* @@ -3444,12 +3440,8 @@ subroutine cat_enkf_increments( & ! ------------------------------------------------------------------- - USE SurfParams, ONLY: WEMIN - !!USE StieglitzSnow, ONLY: cpw_pub !cpwpub causing error 6580:Name in only list does not exist or is not accessible - use Catch_Constants, ONLY: & - RHOFS => CATCH_SNWALB_RHOFS - ! N_CONSTIT => CATCH_N_CONSTIT !!LCA added for test... - + use SurfParams, ONLY: WEMIN + use Catch_Constants, ONLY: RHOFS => CATCH_SNWALB_RHOFS implicit none @@ -3545,30 +3537,28 @@ subroutine cat_enkf_increments( & type(obs_param_type) :: this_obs_param - !jpark50 - real :: asnow_fcst, swe_fcst, swe_ana, asnow_ana, isnow, swe_ratio, tmp_swe - real, dimension(N_catd, N_ens) :: swe_incrm - real, dimension(N_catd, N_ens) :: wesn_sum_old - real, dimension(N_catd, N_ens) :: areasc_old - real, dimension(N_catd, N_ens, N_snow):: tmp_wesn, tmp_htsn, tmp_sndz - !integer, parameter:: N_constit = 9 - real, dimension(N_snow, N_constit) :: rconstit - real, dimension(N_snow), parameter :: DZMAX = (/0.08, 0.5, 0.5/) - !type(cat_progn_type), intent(in), dimension(N_catd, N_ens):: tmp_progn - real, parameter:: cpw = 2065.22 !ice specific heat capacity @ 0C [J/kg/K]THIS seems like it shouldbe defined elsewhere!!! But, will check later lca 5/5/22 - real, parameter:: alpha_threshold = 0.20 !lca modified name and value 2/2/22 - real, parameter:: beta_threshold = 0.40 !lca modified name and value 2/2/22 - real, parameter:: max_incr_swe = 5.0 ! kg m-2 from Toure et al. 2018, lca modified 2/3/22 - real, parameter:: smallfcstswe = 0.01 !This keeps the swe_ratio used in data assmilation reasonably small - real, parameter:: wesn_min = 13.0 ! kg m-2 from Toure et al. 2018, lca added 2/3/22 - real, parameter:: eps = 1.e-4 - real, parameter:: small = 1.e-20 - - ! real, parameter:: rhofs = 150. ! kg/m^3 density of fresh snow - ! real, parameter:: rhoma = 500. ! kg/m^3 maximum snow density - ! real, parameter:: wemin = 13. ! kg/m^3 - real, allocatable, dimension(:) ::deduction - real ::dens_layer, TSN + integer :: isnow + real :: asnow_fcst, swe_fcst, swe_ana, asnow_ana, swe_ratio + real, dimension(N_catd,N_ens) :: swe_incr + real, dimension(N_catd,N_ens,N_snow) :: tmp_wesn, tmp_htsn, tmp_sndz + + real, dimension(N_snow,N_constit) :: rconstit + + ! ------------------------------------------------------------------- + ! Need to clean up and pull these two hardwired numbers from GCM GridComp or MAPL, reichle 20221007 (TO DO) + real, dimension(N_snow), parameter :: DZMAX = (/0.08, 0.5, 0.5/) ! target thickness for relayer2() ! needs to be pulled from Catch GC; would fail with N_snow /= 3; + real, parameter :: cpw = 2065.22 ! ice specific heat capacity @ 0C [J/kg/K] ! already defined in StieglitzSnow.F90; needs to be added to MAPL (or at least pulled from StieglitzSnow.F90 ) + ! ------------------------------------------------------------------- + + ! design parameters for 1d snow cover analysis (Toure et al. 2018) + + ! TO DO: RENAME SO THE USE OF THESE VARIABLES IN SCA ANALYSIS IS MORE OBVIOUS, reichle 20221007 + + real, parameter:: alpha_threshold = 0.20 ! dimensionless DEPENDS ON WEMIN (and might be wrong in Toure et al!!!!) - NEEDS VERIFICATION & CLEANUP + real, parameter:: beta_threshold = 0.40 ! dimensionless + real, parameter:: max_incr_swe = 5.0 ! kg m-2 + real, parameter:: smallfcstswe = 0.01 ! kg m-2 threshold for "no snow" below which the ratio of swe_ana/swe_fcst tends to be unreasonable + ! ----------------------------------------------------------------------- if (logit) write (logunit,*) & @@ -4501,15 +4491,13 @@ subroutine cat_enkf_increments( & ! ---------------------------------- - case (11) select_update_type ! 1d snow (asnow) analysis; MODIS snow cover fraction jpark50 + case (11) select_update_type ! 1d snow analysis (Toure et al. 2018 empirical gain); snow cover fraction obs + + if (logit) write (logunit, *) 'get 1d snow increments (Toure et al. 2018 empirical gain); snow cover fraction obs' + + ! make sure maximum SWE increment is less than WEMIN (adding more snow than WEMIN makes no sense) - !============================================================================= - !lcandre2: updated 02-Feb-2022 to include appropriate update to mass, heat content, - ! & depth. Then apply relayering following adjustments using GRACE DA. - !jpark50: 28-Jul-2021: For asnow update: - !The increment defined here is a direct replacement; there is no use of EnkF - !============================================================================= - if (logit) write (logunit, *) 'get 1d snow(asnow) increments; MODIS SCF' + if (max_swe_incr>WEMIN) call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'must use max_swe_incr<=WEMIN') !identify the species ID number of interest N_select_varnames = 1 @@ -4519,15 +4507,19 @@ subroutine cat_enkf_increments( & N_select_varnames, select_varnames(1:N_select_varnames), & N_obs_param, obs_param, N_select_species, select_species ) - ! Rule-based asnow update allocate(select_tilenum(1)) - allocate(deduction(N_catd)) - - do n=1,N_catd !for each catchment + + swe_incr = 0. ! initialize to NO CHANGE - ! find observations for catchment n - select_tilenum(1) = l2f(n) - ! if(logit) write(logunit,*) 'n:', n + ! loop through tiles and compute increments + + do kk=1,N_catd + + ! find observations for tile kk + + select_tilenum(1) = l2f(kk) + + ! if(logit) write(logunit,*) 'kk:', kk call get_ind_obs( & N_obs, Observations, & @@ -4535,106 +4527,131 @@ subroutine cat_enkf_increments( & N_select_species, select_species(1:N_select_species), & N_selected_obs, ind_obs ) - if (N_selected_obs == 1) then + if (N_selected_obs == 1) then ! COULD THERE EVER BE MORE THAN ONE OBS HERE??? TBD reichle 20221007 - do n_e=1,N_ens ! for each ensemble member (1) calculate the asnow update + do n_e=1,N_ens ! compute analysis separately for each ensemble member + + ! 1. Calculate model forecast snow area and SWE - ! 1. Calculate the model forecast snow area and swe for each ens - asnow_fcst = asnow(n, n_e) - swe_fcst = sum(cat_progn(n, n_e)%wesn(1:N_snow)) - - ! 2. Calculate the SWE update increment based on Toure et al (2018) eq 1 - if(asnow_fcst .lt. Observations(ind_obs(1))%obs * alpha_threshold) then - ! SCA of model is less than observed SCA, ****ADD SNOW**** - swe_incrm(n, n_e) = max_incr_swe * Observations(ind_obs(1))%obs & - - (asnow_fcst / alpha_threshold) - - elseif (Observations(ind_obs(1))%obs .lt. beta_threshold .AND. asnow_fcst .ge. Observations(ind_obs(1))%obs *alpha_threshold ) then - !IF SCA of model is greater than observed SCA, ****REMOVE SNOW**** - swe_incrm(n, n_e) = (-1) * max_incr_swe * (1 - Observations(ind_obs(1))%obs / beta_threshold) - - else - !If the thresholds are not met, make *****NO CHANGE TO SNOW**** - swe_incrm(n, n_e) = 0.0 - - endif !Toure et al. Eq 1 - - ! 3. Calculate a temporary SWE and SCA for each ensemble members - swe_ana = max(swe_fcst + swe_incrm(n, n_e), 0.0) - - !call StieglitzSnow_calc_asnow(N_snow, N_catd, swe_ana, asnow_ana) - !asnow_ana = min(swe_ana/wemin, 1.) !This is from StieglitzSnow_calc_asnow - - swe_ratio = swe_ana / swe_fcst - if (logit) write (logunit, *) '!!!! swe_ratio = ' , swe_ana, swe_fcst, '!!!!' - - ! 4. Apply the corrected SWE to each layer and adjust the heat content and snow depth in tmp variable - do isnow = 1, N_snow - if (asnow_fcst .ge. 0.0 .and. asnow_ana .eq. 0.0) then - tmp_wesn(n, n_e, isnow) = 0.0 - tmp_htsn(n, n_e, isnow) = 0.0 - tmp_sndz(n, n_e, isnow) = 0.0 - if (logit) write (logunit, *) '%%%%%% asnow_ana = 0.0' - - elseif (asnow_fcst .eq. 0.0 .and. asnow_ana .lt. 1.0) then - tmp_wesn(n, n_e, isnow) = swe_ana / N_snow - tmp_htsn(n, n_e, isnow) = (0.0 - MAPL_ALHF)*tmp_wesn(n,n_e,isnow) - tmp_sndz(n ,n_e, isnow) = (WEMIN / RHOFS) / N_snow - if (logit) write (logunit, *) '%%%%%% asnow_fcst = 0 ; asnow_ana < 1.0' - - elseif (asnow_fcst .eq. 0.0 .and. asnow_ana .eq. 1.0) then - tmp_wesn(n, n_e, isnow) = swe_ana / N_snow - tmp_htsn(n, n_e, isnow) = (0.0 - MAPL_ALHF)*tmp_wesn(n,n_e,isnow) !This assumes that the snow temperature is zero. - tmp_sndz(n, n_e, isnow) = (swe_ana / RHOFS) / N_snow !Same as above, but allows the depth to increase with SWE because the catchment is snow covered - if (logit) write (logunit, *) '%%%%%% asnow_fcst = 0 ; asnow_ana = 1.0' - - elseif (asnow_fcst .gt. smallfcstswe .and. asnow_ana .lt. 1.0) then - tmp_wesn(n, n_e, isnow) = cat_progn(n, n_e)%wesn(isnow) * swe_ratio - tmp_htsn(n, n_e, isnow) = cat_progn(n, n_e)%htsn(isnow) * swe_ratio - tmp_sndz(n, n_e, isnow) = cat_progn(n, n_e)%sndz(isnow) !In this case, snow depth remains constant and only extent/hc change. - if (logit) write (logunit, *) '%%%%%% asnow_fcst > 0 ; asnow_ana < 1.0' - - elseif (asnow_fcst .gt.smallfcstswe .and. asnow_ana .eq. 1.0) then - tmp_wesn(n, n_e, isnow) = cat_progn(n, n_e)%wesn(isnow) * swe_ratio - tmp_htsn(n, n_e, isnow) = cat_progn(n, n_e)%htsn(isnow) * swe_ratio - tmp_sndz(n, n_e, isnow) = cat_progn(n, n_e)%sndz(isnow) + tmp_wesn(n, n_e, isnow) / (cat_progn(n, n_e)%wesn(isnow) / cat_progn(n, n_e)%sndz(isnow)) - if (logit) write (logunit, *) '%%%%%% asnow_fcst > 0 ; asnow_ana = 1.0' + asnow_fcst = asnow(kk, n_e) + swe_fcst = sum(cat_progn(kk, n_e)%wesn(1:N_snow)) + + ! 2. Calculate SWE increment based on Toure et al (2018) eq 1 + + if (asnow_fcst .lt. Observations(ind_obs(1))%obs * alpha_threshold) then + + ! ADD SNOW: SCA of model is less than observed SCA + + swe_incr(kk,n_e) & + = max_incr_swe * (Observations(ind_obs(1))%obs - asnow_fcst/alpha_threshold) + + elseif (Observations(ind_obs(1))%obs .lt. beta_threshold) then + + ! REMOVE SNOW: IF SCA of model is greater than observed SCA + + swe_incr(kk,n_e) = (-1.) * max_incr_swe * (1. - Observations(ind_obs(1))%obs/beta_threshold) + + else + + ! NO CHANGE + + endif ! (Toure et al. 2018 Equation 1) + + ! 3. Derive SWE, snow heat content, and snow depth increments for each layer from total SWE increment + + swe_ana = max(swe_fcst + swe_incr(kk, n_e), 0.0) ! total SWE after analysis + + if (swe_fcst>=smallfcstswe) then + swe_ratio = swe_ana / swe_fcst + else + swe_ratio = 1. ! set to neutral just in case, but should not be used if swe_fcst 0 ; asnow_ana < 1.0' + + else + ! compute analysis snow depth assuming forecast snow density + tmp_sndz(kk, n_e, isnow) = cat_progn(kk, n_e)%sndz(isnow) + tmp_wesn(kk, n_e, isnow) / (cat_progn(kk, n_e)%wesn(isnow) / cat_progn(kk, n_e)%sndz(isnow)) + + if (logit) write (logunit, *) '%%%%%% asnow_fcst > 0 ; asnow_ana = 1.0' + + end if + end if + end do ! isnow = 1, N_snow + + ! 4. Relayer to balance the snow column + + call relayer2( N_snow, N_constit , & + DZMAX(1), DZMAX(2:N_snow), & + tmp_htsn(kk, n_e, 1:N_snow), & + tmp_wesn(kk, n_e, 1:N_snow), & + tmp_sndz(kk, n_e, 1:N_snow), & + rconstit ) + + ! print the old and new swe, heat content and snow density + + if (logit) write (logunit, *) & + 'fcst_wesn = ', cat_progn(kk, n_e)%wesn(1:N_snow), & + 'tmp_wesn = ', tmp_wesn( kk,n_e, 1:N_snow), & + 'fcst_htsn = ', cat_progn(kk, n_e)%htsn(1:N_snow), & + 'tmp_htsn = ', tmp_htsn( kk, n_e, 1:N_snow), & + 'fcst_sndz = ', cat_progn(kk, n_e)%sndz(1:N_snow), & + 'tmp_sndz = ', tmp_sndz( kk ,n_e, 1:N_snow), & + '--------------------------------------' + + ! 5. Calculate increments + + cat_progn_incr(kk, n_e)%wesn(1:N_snow) = tmp_wesn(kk, n_e, 1:N_snow) - cat_progn(kk, n_e)%wesn(1:N_snow) + cat_progn_incr(kk, n_e)%htsn(1:N_snow) = tmp_htsn(kk, n_e, 1:N_snow) - cat_progn(kk, n_e)%htsn(1:N_snow) + cat_progn_incr(kk, n_e)%sndz(1:N_snow) = tmp_sndz(kk, n_e, 1:N_snow) - cat_progn(kk, n_e)%sndz(1:N_snow) + + end do ! n_e = 1, N_ens + end if ! if (N_selected_obs == 1) + end do ! kk = 1, N_catd + + + ! ---------------------------------- - + case default call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'unknown update_type') @@ -4657,6 +4674,7 @@ subroutine cat_enkf_increments( & ! increments have been applied. ! - reichle, 18 Oct 2005 if (logit) write(logunit,*) 'Cat_enkf_increment completed' + end subroutine cat_enkf_increments ! ********************************************************************** From 44f78efb9b0a9ff66a9a4b1ccc1777f5dd5c3256 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Fri, 7 Oct 2022 17:09:47 -0400 Subject: [PATCH 028/308] fixed silly errors in previous commmit --- .../GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index 18cab8f0..9b8ca644 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -4497,7 +4497,7 @@ subroutine cat_enkf_increments( & ! make sure maximum SWE increment is less than WEMIN (adding more snow than WEMIN makes no sense) - if (max_swe_incr>WEMIN) call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'must use max_swe_incr<=WEMIN') + if (max_incr_swe>WEMIN) call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'must use max_incr_swe<=WEMIN') !identify the species ID number of interest N_select_varnames = 1 @@ -4567,7 +4567,7 @@ subroutine cat_enkf_increments( & swe_ratio = 1. ! set to neutral just in case, but should not be used if swe_fcst Date: Fri, 14 Oct 2022 14:41:35 -0400 Subject: [PATCH 029/308] Update to re-add asnow_ana --- .../GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index 9b8ca644..555b5cfe 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -4560,14 +4560,17 @@ subroutine cat_enkf_increments( & ! 3. Derive SWE, snow heat content, and snow depth increments for each layer from total SWE increment swe_ana = max(swe_fcst + swe_incr(kk, n_e), 0.0) ! total SWE after analysis - + + asnow_ana = min(swe_ana/wemin, 1.) ! calculate the snow area + if (logit) write (logunit, *) '!!!! asnow_ana = ', asnow_ana, '!!!!' + if (swe_fcst>=smallfcstswe) then swe_ratio = swe_ana / swe_fcst else swe_ratio = 1. ! set to neutral just in case, but should not be used if swe_fcst Date: Wed, 30 Nov 2022 09:20:17 -0500 Subject: [PATCH 030/308] modification to snow DA heat content corr --- .../GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index 555b5cfe..ad2f2ce0 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -4613,7 +4613,7 @@ subroutine cat_enkf_increments( & ! compute analysis snow depth assuming forecast snow density - tmp_sndz(kk, n_e, isnow) = cat_progn(kk, n_e)%sndz(isnow) + tmp_wesn(kk, n_e, isnow) / (cat_progn(kk, n_e)%wesn(isnow) / cat_progn(kk, n_e)%sndz(isnow)) + tmp_sndz(kk, n_e, isnow) = tmp_wesn(kk, n_e, isnow) / (cat_progn(kk, n_e)%wesn(isnow) / cat_progn(kk, n_e)%sndz(isnow)) if (logit) write (logunit, *) '%%%%%% asnow_fcst > 0 ; asnow_ana = 1.0' From ec351dba1a23fb316a7777b4d9a722046d05dd84 Mon Sep 17 00:00:00 2001 From: "Lauren C. Andrews" Date: Thu, 1 Dec 2022 10:41:57 -0500 Subject: [PATCH 031/308] alpha update to 0.4 --- .../GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index ad2f2ce0..a4a9b42b 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -3554,7 +3554,7 @@ subroutine cat_enkf_increments( & ! TO DO: RENAME SO THE USE OF THESE VARIABLES IN SCA ANALYSIS IS MORE OBVIOUS, reichle 20221007 - real, parameter:: alpha_threshold = 0.20 ! dimensionless DEPENDS ON WEMIN (and might be wrong in Toure et al!!!!) - NEEDS VERIFICATION & CLEANUP + real, parameter:: alpha_threshold = 0.40 ! dimensionless DEPENDS ON WEMIN (and might be wrong in Toure et al!!!!) - NEEDS VERIFICATION & CLEANUP real, parameter:: beta_threshold = 0.40 ! dimensionless real, parameter:: max_incr_swe = 5.0 ! kg m-2 real, parameter:: smallfcstswe = 0.01 ! kg m-2 threshold for "no snow" below which the ratio of swe_ana/swe_fcst tends to be unreasonable From 8d83c1bf9e73e99c374bc1938ba0331aa57ff884 Mon Sep 17 00:00:00 2001 From: "Lauren C. Andrews" Date: Fri, 9 Dec 2022 09:47:23 -0500 Subject: [PATCH 032/308] fix to negative sno increment calc --- .../GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index 2a883379..62084059 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -4546,7 +4546,7 @@ subroutine cat_enkf_increments( & ! REMOVE SNOW: IF SCA of model is greater than observed SCA - swe_incr(kk,n_e) = (-1.) * max_incr_swe * (1. - Observations(ind_obs(1))%obs/beta_threshold) + swe_incr(kk,n_e) = (-1.) * max_incr_swe * asnow_fcst * (1. - Observations(ind_obs(1))%obs/beta_threshold) else From 3b0c5f74a5661727f2bf9631d014f74e7153a3b2 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Tue, 13 Dec 2022 18:02:40 -0500 Subject: [PATCH 033/308] update clsm_ensupd_read_obs.F90 --- .../clsm_ensupd_read_obs.F90 | 419 ++++++++++++++++++ 1 file changed, 419 insertions(+) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 5937a6e0..3a4a5f69 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -1548,6 +1548,405 @@ subroutine read_obs_sm_ASCAT( & if (associated(tmp_lat)) deallocate(tmp_lat) end subroutine read_obs_sm_ASCAT + + ! **************************************************************************** + + subroutine read_obs_sm_ASCAT_EUMET( & + work_path, exp_id, & + date_time, dtstep_assim, N_catd, tile_coord, & + tile_grid_d, N_tile_in_cell_ij, tile_num_in_cell_ij, & + this_obs_param, & + found_obs, sm_ASCAT, std_sm_ASCAT ) + + !--------------------------------------------------------------------- + ! + ! Routine to read in ASCAT surface degree of saturation obs. + ! Output is found_obs, sm_ASCAT, std_sm_ASCAT + ! + ! Read in the EUMETSAT level 2 soil mositure product 25 km (SMO), PPF software version 5.0 + ! the data correspond to re-sampled (spatially averaged) sigma0 values, on a 25 km + ! orbit swath grid. The input data files are in BUFR file format. + ! + ! Q. Liu, Nov. 2019. + ! based on read_obs_sm_ASCAT + ! -------------------------------------------------------------------- + + implicit none + + ! inputs: + + character(*), intent(in) :: work_path + character(*), intent(in) :: exp_id + + type(date_time_type), intent(in) :: date_time + + integer, intent(in) :: dtstep_assim, N_catd + + type(tile_coord_type), dimension(:), pointer :: tile_coord ! input + + type(grid_def_type), intent(in) :: tile_grid_d + + integer, dimension(tile_grid_d%N_lon,tile_grid_d%N_lat), intent(in) :: & + N_tile_in_cell_ij + + integer, dimension(:,:,:), pointer :: tile_num_in_cell_ij ! input + + type(obs_param_type), intent(in) :: this_obs_param + + ! outputs: + + real, intent(out), dimension(N_catd) :: sm_ASCAT ! wetness range 0-1 + real, intent(out), dimension(N_catd) :: std_sm_ASCAT + logical, intent(out) :: found_obs + + ! --------------- + + ! Each obs file contains about 1 hour 40 minutes observations + ! file name indicates the start time of the swaths. + ! "ae_time_offset" is used to find the mean time of the the interval + ! which is approximately the time of the equator overpass. + ! This time is assigned to all observations of the swath. + + ! Will need to be updated if using EUMETSAT BUFR files + + integer, parameter :: ae_time_offset = 3600 ! 60 minutes in seconds + + character(4) :: DDHH + character(6) :: YYYYMM + character(8) :: date_string + character(10) :: time_string + character(300) :: tmpfname, tmpfname2 + character(400) :: cmd + + type(date_time_type) :: date_time_tmp + type(date_time_type) :: date_time_low + type(date_time_type) :: date_time_upp + + integer :: i, ind, N_tmp, N_files + + character(300), dimension(:), allocatable :: fnames + + real(8) :: tmp_data, tmp_vdata(4), tmp_time(6) + integer, parameter :: lnbufr = 50 + integer, parameter :: max_rec = 200000 + integer :: idate,iret,kk + integer :: ireadmg,ireadsb + character(8) :: subset + real, dimension(:), allocatable :: tmp1_lon, tmp1_lat, tmp1_obs + + real, dimension(:), pointer :: tmp_obs, tmp_lat, tmp_lon + integer, dimension(:), pointer :: tmp_tile_num + + integer, dimension(N_catd) :: N_obs_in_tile + + real, parameter :: tol = 1e-2 + + character(len=*), parameter :: Iam = 'read_obs_sm_ASCAT_EUMET' + character(len=400) :: err_msg + + ! ------------------------------------------------------------------- + + nullify( tmp_obs, tmp_lat, tmp_lon, tmp_tile_num ) + + ! --------------- + + ! initialize + + found_obs = .false. + + ! find files that are within half-open interval + ! [date_time-dtstep_assim/2,date_time+dtstep_assim/2) + + date_time_low = date_time + call augment_date_time( -(dtstep_assim/2), date_time_low) + date_time_upp = date_time + call augment_date_time( (dtstep_assim/2), date_time_upp) + + ! for ASCAT file name stamp + date_time_tmp = date_time + call augment_date_time( -(dtstep_assim/2 + ae_time_offset), date_time_tmp ) + + ! get tmp file name and remove file if it exists + + call date_and_time(date_string, time_string) ! f90 intrinsic function + + tmpfname = trim(work_path) // '/' // 'tmp.' // trim(exp_id) & + // '.' // date_string // time_string + + cmd = '/bin/rm -f ' // tmpfname + + call Execute_command_line(trim(cmd)) + + ! identify all files within current assimilation interval + ! (list all files within hourly intervals) + + ! Every EUMETSTA BUFR contains data over ~2 hr sensing period. it's necessary to + ! search additional files for obs. + do i=1,(dtstep_assim/3600)+2 + + write (YYYYMM,'(i6.6)') date_time_tmp%year*100 + date_time_tmp%month + write (DDHH, '(i4.4)') date_time_tmp%day *100 + date_time_tmp%hour + + ! EUMETSAT BUFR + cmd = 'ls ' // trim(this_obs_param%path) // '/Y' // YYYYMM(1:4) // & + '/M' // YYYYMM(5:6) // '/' // trim(this_obs_param%name) // '*-'& + // YYYYMM // DDHH // '*Z-*.bfr' + + cmd = trim(cmd) // ' >> ' // trim(tmpfname) + + call Execute_command_line(trim(cmd)) + + call augment_date_time( 3600, date_time_tmp ) + + end do + + ! find out how many need to be read + + tmpfname2 = trim(tmpfname) // '.wc' + + cmd = 'wc -w ' // trim(tmpfname) // ' > ' // trim(tmpfname2) + + call Execute_command_line(trim(cmd)) + + open(10, file=tmpfname2, form='formatted', action='read') + + read(10,*) N_files + + close(10,status='delete') + + ! load file names into "fnames" + + open(10, file=tmpfname, form='formatted', action='read') + + if (N_files>0) then + + allocate(fnames(N_files)) + + do i=1,N_files + read(10,'(a)') fnames(i) + write(logunit,*) trim(fnames(i)) + end do + + end if + + close(10,status='delete') + + ! read observations: + ! + ! 1.) read N_tmp observations and their lat/lon info from file + ! 2.) for each observation + ! a) determine grid cell that contains lat/lon + ! b) determine tile within grid cell that contains lat/lon + ! 3.) compute super-obs for each tile from all obs w/in that tile + ! + ! ---------------------------------------------------------------- + ! + ! 1.) read N_tmp observations and their lat/lon info from file + + ! read and process data if files are found + allocate(tmp1_lon(max_rec)) + allocate(tmp1_lat(max_rec)) + allocate(tmp1_obs(max_rec)) + + if (N_files>0) then + + ! file loop + N_tmp = 0 + do kk = 1,N_files + + ! open on bufr file + call closbf(lnbufr) + open(lnbufr, file=trim(fnames(kk)), action='read',form='unformatted') + call openbf(lnbufr,'SEC3', lnbufr) + call MTINFO( trim(this_obs_param%path) // '/BUFR_mastertable/', 51, 52) + call datelen(10) + + msg_report: do while(ireadmg(lnbufr,subset,idate) ==0) + loop_report: do while(ireadsb(lnbufr) == 0) + ! extract sensing time information + call ufbint(lnbufr,tmp_time,6,1,iret,'YEAR MNTH DAYS HOUR MINU SECO') + date_time_tmp.year = int(tmp_time(1)) + date_time_tmp.month = int(tmp_time(2)) + date_time_tmp.day = int(tmp_time(3)) + date_time_tmp.hour = int(tmp_time(4)) + date_time_tmp.min = int(tmp_time(5)) + date_time_tmp.sec = int(tmp_time(6)) + ! skip if record outside of current assim window + if ( datetime_lt_refdatetime( date_time_low, date_time_tmp ) .and. & + datetime_le_refdatetime( date_time_tmp, date_time_upp )) cycle loop_report + + ! skip if record contain no valid soil moisture value + call ufbint(lnbufr,tmp_data,1,1,iret,'SSOM') + if(tmp_data > 100. .or. tmp_data < 0.) cycle loop_report + + ! EUMETSAT file contains data of both ascending and descending orbits. + ! DOMO - “Direction of motion of moving observing platform” is used to seperate Asc and Desc + ! because the file doesn't contain any explicit orbit indicator variable. + ! according to Pamela Schoebel-Pattiselanno, EUMETSAT User Services Helpdesk + ! "When the value (of DOMO) is between 180 and 270 degrees, it is the descending part + ! of the orbit … when it is between 270 and 360 degrees, it is the ascending part" + call ufbint(lnbufr,tmp_data,1,1,iret,'DOMO') + if (index(this_obs_param%descr,'_A') /=0 .and. (tmp_data < 270 .or. tmp_data > 360)) cycle loop_report + if (index(this_obs_param%descr,'_D') /=0 .and. (tmp_data < 180 .or. tmp_data >= 270)) cycle loop_report + + ! skip if processing flag is set + call ufbint(lnbufr,tmp_data,1,1,iret,'SMPF') + if(int(tmp_data) /= 0) cycle loop_report + + ! skip if correction flag is set + call ufbint(lnbufr,tmp_data,1,1,iret,'SMCF') + if(int(tmp_data) /= 0) cycle loop_report + + ! skip if land fraction is missing or < 0.9 + call ufbint(lnbufr,tmp_data,1,1,iret,'ALFR') + if(tmp_data >1 .or. tmp_data < 0.9 ) cycle loop_report + + ! additioanal QC varibles from file + !call ufbint(lnbufr,tmp_data,1,1,iret,'TPCX') ! topo complexity + !call ufbint(lnbufr,tmp_data,1,1,iret,'IWFR') ! Inundation And Wetland Fraction + !call ufbint(lnbufr,tmp_data,1,1,iret,'SNOC') ! snow cover + !call ufbint(lnbufr,tmp_data,1,1,iret,'FLSF') ! frozen land fraction + + N_tmp = N_tmp + 1 + call ufbint(lnbufr,tmp_vdata,4,1,iret,'CLATH CLONH SSOM EESSM') + tmp1_lat(N_tmp) = tmp_vdata(1) + tmp1_lon(N_tmp) = tmp_vdata(2) + tmp1_obs(N_tmp) = tmp_vdata(3)/100. ! change value from 0-100 to 0-1 + !tmp_obserr(N_tmp) = tmp_vdata(4) + + end do loop_report + + end do msg_report + call closbf(lnbufr) + close(lnbufr) + + end do ! end file loop + + if (logit) then + + write (logunit,*) 'read_obs_sm_ASCAT_EUMET: read ', N_tmp, & + ' at date_time = ', date_time, ' from ' + do i=1,N_files + write (logunit,*) trim(fnames(i)) + end do + write (logunit,*) '----------' + write (logunit,*) 'max(obs)=',maxval(tmp1_obs(1:N_tmp)), 'min(obs)=',minval(tmp1_obs(1:N_tmp)), & + ' avg(obs)=',sum(tmp1_obs(1:N_tmp))/N_tmp + end if + + deallocate(fnames) + else + N_tmp = 0 + + end if + + allocate(tmp_lon(N_tmp)) + allocate(tmp_lat(N_tmp)) + allocate(tmp_obs(N_tmp)) + + tmp_lon = tmp1_lon(1:N_tmp) + tmp_lat = tmp1_lat(1:N_tmp) + tmp_obs = tmp1_obs(1:N_tmp) + + deallocate(tmp1_lon) + deallocate(tmp1_lat) + deallocate(tmp1_obs) + + ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + ! + ! SOME QC SHOULD BE DONE HERE!!! + ! + ! MAKE SURE no-data-values ARE DEALT WITH + ! + ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + ! ---------------------------------------------------------------- + ! + ! 2.) for each observation + ! a) determine grid cell that contains lat/lon + ! b) determine tile within grid cell that contains lat/lon + + if (N_tmp>0) then + + allocate(tmp_tile_num(N_tmp)) + + call get_tile_num_for_obs(N_catd, tile_coord, & + tile_grid_d, N_tile_in_cell_ij, tile_num_in_cell_ij, & + N_tmp, tmp_lat, tmp_lon, & + this_obs_param, & + tmp_tile_num ) + + + ! ---------------------------------------------------------------- + ! + ! 3.) compute super-obs for each tile from all obs w/in that tile + ! (also eliminate observations that are not in domain) + + sm_ASCAT = 0. + N_obs_in_tile = 0 + + do i=1,N_tmp + + ind = tmp_tile_num(i) ! 1<=tmp_tile_num<=N_catd (unless nodata) + + if (ind>0) then ! this step eliminates obs outside domain + + sm_ASCAT(ind) = sm_ASCAT(ind) + tmp_obs(i) + + N_obs_in_tile(ind) = N_obs_in_tile(ind) + 1 + + end if + + end do + + ! normalize + + do i=1,N_catd + + if (N_obs_in_tile(i)>1) then + + sm_ASCAT(i) = sm_ASCAT(i)/real(N_obs_in_tile(i)) + + elseif (N_obs_in_tile(i)==0) then + + sm_ASCAT(i) = this_obs_param%nodata + + end if + + end do + + ! clean up + + if (associated(tmp_tile_num)) deallocate(tmp_tile_num) + + ! -------------------------------- + + ! set observation error standard deviation + + do i=1,N_catd + std_sm_ASCAT(i) = this_obs_param%errstd + enddo + ! -------------------------------- + + if (any(N_obs_in_tile>0)) then + + found_obs = .true. + + else + + found_obs = .false. + + end if + + end if + + ! clean up + + if (associated(tmp_obs)) deallocate(tmp_obs) + if (associated(tmp_lon)) deallocate(tmp_lon) + if (associated(tmp_lat)) deallocate(tmp_lat) + + end subroutine read_obs_sm_ASCAT_EUMET ! *************************************************************************** @@ -7043,6 +7442,26 @@ subroutine read_obs( & tmp_obs, tmp_std_obs ) end if + + case ('ASCAT_META_SM_A', 'ASCAT_META_SM_D','ASCAT_METB_SM_A', 'ASCAT_METB_SM_D' ) + + call read_obs_sm_ASCAT_EUMET( & + work_path, exp_id, & + date_time, dtstep_assim, N_catd, tile_coord, & + tile_grid_d, N_tile_in_cell_ij, tile_num_in_cell_ij, & + this_obs_param, & + found_obs, tmp_obs, tmp_std_obs ) + + ! scale observations to model climatology + + if (this_obs_param%scale .and. found_obs) then + + scaled_obs = .true. + + call scale_obs_sfmc_cdf( N_catd, tile_coord, this_obs_param, & + tmp_obs, tmp_std_obs ) + + end if case ('isccp_tskin_gswp2_v1') From 7352522c103d276bbf7467ce5bc0ea997ea4f40c Mon Sep 17 00:00:00 2001 From: amfox37 Date: Tue, 13 Dec 2022 18:27:21 -0500 Subject: [PATCH 034/308] update clsm_ensupd_glob_param --- .../GEOSlandassim_GridComp/clsm_ensupd_glob_param.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_glob_param.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_glob_param.F90 index d3cdcf16..1183ab4c 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_glob_param.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_glob_param.F90 @@ -44,7 +44,7 @@ module clsm_ensupd_glob_param ! total number of all obs species defined in namelist file ! (regardless of whether "assim" flag is true or false) - integer, parameter :: N_obs_species_nml = 48 + integer, parameter :: N_obs_species_nml = 52 ! ---------------------------------------------------------------------- ! From a264ee92960f1739186e95151c516806873365d1 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Tue, 13 Dec 2022 20:29:07 -0500 Subject: [PATCH 035/308] update componentsyaml and cmakelists --- components.yaml | 6 ++++++ src/Shared/CMakeLists.txt | 7 +++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/components.yaml b/components.yaml index 1ad23995..2347cf33 100644 --- a/components.yaml +++ b/components.yaml @@ -19,6 +19,12 @@ ecbuild: remote: ../ecbuild.git tag: geos/v1.3.0 +NCEP_Shared: + local: ./src/Shared/@NCEP_Shared + remote: ../NCEP_Shared.git + tag: v1.2.0 + develop: main + GMAO_Shared: local: ./src/Shared/@GMAO_Shared remote: ../GMAO_Shared.git diff --git a/src/Shared/CMakeLists.txt b/src/Shared/CMakeLists.txt index 9bb6942b..cbd532d6 100644 --- a/src/Shared/CMakeLists.txt +++ b/src/Shared/CMakeLists.txt @@ -1,2 +1,5 @@ -esma_add_subdirectory (MAPL) -esma_add_subdirectory (GMAO_Shared) +esma_add_subdirectories ( + @MAPL + @GMAO_Shared + @NCEP_Shared + ) From cb628a5f55d1c02d6c63b0c50fb5a20102186ef3 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Wed, 14 Dec 2022 12:51:26 -0500 Subject: [PATCH 036/308] trying to build with bufr --- components.yaml | 3 ++- config/NCEP_Shared.sparse | 8 ++++++++ src/Shared/.gitignore | 3 +++ 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 config/NCEP_Shared.sparse diff --git a/components.yaml b/components.yaml index 2347cf33..23d91e16 100644 --- a/components.yaml +++ b/components.yaml @@ -22,7 +22,8 @@ ecbuild: NCEP_Shared: local: ./src/Shared/@NCEP_Shared remote: ../NCEP_Shared.git - tag: v1.2.0 + tag: v1.1.1 + sparse: ./config/NCEP_Shared.sparse develop: main GMAO_Shared: diff --git a/config/NCEP_Shared.sparse b/config/NCEP_Shared.sparse new file mode 100644 index 00000000..b0801a63 --- /dev/null +++ b/config/NCEP_Shared.sparse @@ -0,0 +1,8 @@ +!/* +/NCEP_sp +/NCEP_w3 +/NCEP_bufr +/NCEP_bacio +/NCEP_sfcio +/NCEP_sigio +/CMakeLists.txt diff --git a/src/Shared/.gitignore b/src/Shared/.gitignore index d5e49170..dba5156e 100644 --- a/src/Shared/.gitignore +++ b/src/Shared/.gitignore @@ -4,3 +4,6 @@ /@MAPL /MAPL /MAPL@ +/@NCEP_Shared +/NCEP_Shared +/NCEP_Shared@ From 792c4b075f46f8fb4cf3de5050ed2cd1be356ccc Mon Sep 17 00:00:00 2001 From: amfox37 Date: Wed, 14 Dec 2022 15:07:49 -0500 Subject: [PATCH 037/308] update GEOSlandassim_GridComp CMakeLists.txt --- .../GEOSldas_GridComp/GEOSlandassim_GridComp/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/CMakeLists.txt b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/CMakeLists.txt index 89684a1e..0afdcb32 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/CMakeLists.txt +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/CMakeLists.txt @@ -16,7 +16,7 @@ find_package(HDF5 REQUIRED COMPONENTS Fortran) esma_add_library (${this} SRCS ${SRCS} SUBCOMPONENTS ${alldirs} - DEPENDENCIES GEOS_LdasShared GEOSens_GridComp GEOSlandpert_GridComp GEOSland_GridComp raster MAPL GMAO_gfio_r4 hdf5hl_fortran hdf5_fortran ${NETCDF_LIBRARIES} + DEPENDENCIES GEOS_LdasShared GEOSens_GridComp GEOSlandpert_GridComp GEOSland_GridComp raster MAPL NCEP_bufr_r4i4 GMAO_gfio_r4 hdf5hl_fortran hdf5_fortran ${NETCDF_LIBRARIES} INCLUDES ${INC_ESMF} ${INC_HDF5}) target_compile_definitions (${this} PRIVATE LDAS_MPI) From 95f4488624b5f0c94cbe647efd950384b913c099 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Wed, 21 Dec 2022 20:15:13 -0500 Subject: [PATCH 038/308] update LDASsa_DEFAULT_inputs_ensupd.nml --- .../LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml | 158 ++++++++++++++++++ 1 file changed, 158 insertions(+) diff --git a/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml b/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml index f8d77eaf..6cfa617a 100644 --- a/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml +++ b/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml @@ -2063,6 +2063,164 @@ obs_param_nml(48)%xcorr = 0.1875 obs_param_nml(48)%ycorr = 0.1875 obs_param_nml(48)%adapt = 0 +! -------------------------------------------------------------------- +! +! 49 = ASCAT_META_SM_A (ASCAT soil moisture ascending) +! +! ASCAT: VV-pol, incidence angle 25-65 deg +! for now keep N_ang=0, pol=0 +! - reichle, 30 Jun 2015 + +obs_param_nml(49)%descr = 'ASCAT_META_SM_A' +obs_param_nml(49)%orbit = 1 +obs_param_nml(49)%pol = 0 +obs_param_nml(49)%N_ang = 0 +obs_param_nml(49)%freq = 5.255e9 +obs_param_nml(49)%FOV = 20. +obs_param_nml(49)%FOV_units = 'km' +obs_param_nml(49)%assim = .false. +obs_param_nml(49)%scale = .false. +obs_param_nml(49)%getinnov = .false. +obs_param_nml(49)%RTM_ID = 0 +obs_param_nml(49)%bias_Npar = 0 +obs_param_nml(49)%bias_trel = 864000 +obs_param_nml(49)%bias_tcut = 432000 +obs_param_nml(49)%nodata = -9999. +obs_param_nml(49)%varname = 'sfmc' +obs_param_nml(49)%units = 'm3/m3' +obs_param_nml(49)%path = '/discover/nobackup/projects/gmao/merra/iau/merra_land/DATA/ASCAT_EUMETSAT/Metop_A/' +obs_param_nml(49)%name = 'M02-ASCA-ASCSMO02' +obs_param_nml(49)%scalepath = '' +obs_param_nml(49)%scalename = '' +obs_param_nml(49)%flistpath = '' +obs_param_nml(49)%flistname = '' +obs_param_nml(49)%errstd = .04 +obs_param_nml(49)%std_normal_max = 2.5 +obs_param_nml(49)%zeromean = .true. +obs_param_nml(49)%coarsen_pert = .false. +obs_param_nml(49)%xcorr = 0.25 +obs_param_nml(49)%ycorr = 0.25 +obs_param_nml(49)%adapt = 0 + +! ------------------- +! +! 50 = ASCAT_META_SM_D (ASCAT soil moisture descending) +! +! TO DO: What is pol of backscatter used in retrieval? +! TO DO: How deal w/ inc angle? +! http://oiswww.eumetsat.org/WEBOPS/eps-pg/ASCAT/ASCAT-PG-4ProdOverview.htm + +obs_param_nml(50)%descr = 'ASCAT_META_SM_D' +obs_param_nml(50)%orbit = 2 +obs_param_nml(50)%pol = 0 +obs_param_nml(50)%N_ang = 0 +obs_param_nml(50)%freq = 5.255e9 +obs_param_nml(50)%FOV = 20. +obs_param_nml(50)%FOV_units = 'km' +obs_param_nml(50)%assim = .false. +obs_param_nml(50)%scale = .false. +obs_param_nml(50)%getinnov = .false. +obs_param_nml(50)%RTM_ID = 0 +obs_param_nml(50)%bias_Npar = 0 +obs_param_nml(50)%bias_trel = 864000 +obs_param_nml(50)%bias_tcut = 432000 +obs_param_nml(50)%nodata = -9999. +obs_param_nml(50)%varname = 'sfmc' +obs_param_nml(50)%units = 'm3/m3' +obs_param_nml(50)%path = '/discover/nobackup/projects/gmao/merra/iau/merra_land/DATA/ASCAT_EUMETSAT/Metop_A/' +obs_param_nml(50)%name = 'M02-ASCA-ASCSMO02' +obs_param_nml(50)%scalepath = '' +obs_param_nml(50)%scalename = '' +obs_param_nml(50)%flistpath = '' +obs_param_nml(50)%flistname = '' +obs_param_nml(50)%errstd = .04 +obs_param_nml(50)%std_normal_max = 2.5 +obs_param_nml(50)%zeromean = .true. +obs_param_nml(50)%coarsen_pert = .false. +obs_param_nml(50)%xcorr = 0.25 +obs_param_nml(50)%ycorr = 0.25 +obs_param_nml(50)%adapt = 0 + +! -------------------------------------------------------------------- +! -------------------------------------------------------------------- +! +! 51 = ASCAT_METB_SM_A (ASCAT soil moisture ascending) +! +! ASCAT: VV-pol, incidence angle 25-65 deg +! for now keep N_ang=0, pol=0 +! - reichle, 30 Jun 2015 + +obs_param_nml(51)%descr = 'ASCAT_METB_SM_A' +obs_param_nml(51)%orbit = 1 +obs_param_nml(51)%pol = 0 +obs_param_nml(51)%N_ang = 0 +obs_param_nml(51)%freq = 5.255e9 +obs_param_nml(51)%FOV = 20. +obs_param_nml(51)%FOV_units = 'km' +obs_param_nml(51)%assim = .false. +obs_param_nml(51)%scale = .false. +obs_param_nml(51)%getinnov = .false. +obs_param_nml(51)%RTM_ID = 0 +obs_param_nml(51)%bias_Npar = 0 +obs_param_nml(51)%bias_trel = 864000 +obs_param_nml(51)%bias_tcut = 432000 +obs_param_nml(51)%nodata = -9999. +obs_param_nml(51)%varname = 'sfmc' +obs_param_nml(51)%units = 'm3/m3' +obs_param_nml(51)%path = '/discover/nobackup/projects/gmao/merra/iau/merra_land/DATA/ASCAT_EUMETSAT/Metop_B/' +obs_param_nml(51)%name = 'M01-ASCA-ASCSMO02' +obs_param_nml(51)%scalepath = '' +obs_param_nml(51)%scalename = '' +obs_param_nml(51)%flistpath = '' +obs_param_nml(51)%flistname = '' +obs_param_nml(51)%errstd = .04 +obs_param_nml(51)%std_normal_max = 2.5 +obs_param_nml(51)%zeromean = .true. +obs_param_nml(51)%coarsen_pert = .false. +obs_param_nml(51)%xcorr = 0.25 +obs_param_nml(51)%ycorr = 0.25 +obs_param_nml(51)%adapt = 0 + +! ------------------- +! +! 52 = ASCAT_METB_SM_D (ASCAT soil moisture descending) +! +! TO DO: What is pol of backscatter used in retrieval? +! TO DO: How deal w/ inc angle? +! http://oiswww.eumetsat.org/WEBOPS/eps-pg/ASCAT/ASCAT-PG-4ProdOverview.htm + +obs_param_nml(52)%descr = 'ASCAT_METB_SM_D' +obs_param_nml(52)%orbit = 2 +obs_param_nml(52)%pol = 0 +obs_param_nml(52)%N_ang = 0 +obs_param_nml(52)%freq = 5.255e9 +obs_param_nml(52)%FOV = 20. +obs_param_nml(52)%FOV_units = 'km' +obs_param_nml(52)%assim = .false. +obs_param_nml(52)%scale = .false. +obs_param_nml(52)%getinnov = .false. +obs_param_nml(52)%RTM_ID = 0 +obs_param_nml(52)%bias_Npar = 0 +obs_param_nml(52)%bias_trel = 864000 +obs_param_nml(52)%bias_tcut = 432000 +obs_param_nml(52)%nodata = -9999. +obs_param_nml(52)%varname = 'sfmc' +obs_param_nml(52)%units = 'm3/m3' +obs_param_nml(52)%path = '/discover/nobackup/projects/gmao/merra/iau/merra_land/DATA/ASCAT_EUMETSAT/Metop_B/' +obs_param_nml(52)%name = 'M01-ASCA-ASCSMO02' +obs_param_nml(52)%scalepath = '' +obs_param_nml(52)%scalename = '' +obs_param_nml(52)%flistpath = '' +obs_param_nml(52)%flistname = '' +obs_param_nml(52)%errstd = .04 +obs_param_nml(52)%std_normal_max = 2.5 +obs_param_nml(52)%zeromean = .true. +obs_param_nml(52)%coarsen_pert = .false. +obs_param_nml(52)%xcorr = 0.25 +obs_param_nml(52)%ycorr = 0.25 +obs_param_nml(52)%adapt = 0 + + ! -------------------------------------------------------------------- / From cc527bee937a94f080634226e6a67e87be3c91d5 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Tue, 31 Jan 2023 13:04:15 -0700 Subject: [PATCH 039/308] Add tpcx and iwfr QC --- .../GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 3a4a5f69..adeb5552 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -1802,8 +1802,13 @@ subroutine read_obs_sm_ASCAT_EUMET( & if(tmp_data >1 .or. tmp_data < 0.9 ) cycle loop_report ! additioanal QC varibles from file - !call ufbint(lnbufr,tmp_data,1,1,iret,'TPCX') ! topo complexity - !call ufbint(lnbufr,tmp_data,1,1,iret,'IWFR') ! Inundation And Wetland Fraction + ! skip if topographic complexity > 10% + call ufbint(lnbufr,tmp_data,1,1,iret,'TPCX') ! topo complexity + if(tmp_data > 10.) cycle loop_report + + ! skip if inudatation and wetland faction > 10% + call ufbint(lnbufr,tmp_data,1,1,iret,'IWFR') ! Inundation And Wetland Fraction + if(tmp_data > 10.) cycle loop_report !call ufbint(lnbufr,tmp_data,1,1,iret,'SNOC') ! snow cover !call ufbint(lnbufr,tmp_data,1,1,iret,'FLSF') ! frozen land fraction From 35b2ef5336cf75126bc5283df8d7f00b373aeebd Mon Sep 17 00:00:00 2001 From: amfox37 Date: Tue, 31 Jan 2023 16:05:22 -0500 Subject: [PATCH 040/308] fix CMakeLists in Shared --- src/Shared/CMakeLists.txt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Shared/CMakeLists.txt b/src/Shared/CMakeLists.txt index e7ace2f3..cbd532d6 100644 --- a/src/Shared/CMakeLists.txt +++ b/src/Shared/CMakeLists.txt @@ -1,3 +1,5 @@ -esma_add_subdirectory (MAPL) -esma_add_subdirectory (GMAO_Shared) -esma_add_subdirectory (GEOS_Util) +esma_add_subdirectories ( + @MAPL + @GMAO_Shared + @NCEP_Shared + ) From 0fefd6be2356e405ca5478d1685bcfa9a4a55d4a Mon Sep 17 00:00:00 2001 From: amfox37 Date: Tue, 31 Jan 2023 16:25:40 -0700 Subject: [PATCH 041/308] updating varname to sfds --- .../LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml | 8 ++++---- .../clsm_ensupd_upd_routines.F90 | 10 ++++++++++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml b/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml index 6cfa617a..1153a8d8 100644 --- a/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml +++ b/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml @@ -2086,7 +2086,7 @@ obs_param_nml(49)%bias_Npar = 0 obs_param_nml(49)%bias_trel = 864000 obs_param_nml(49)%bias_tcut = 432000 obs_param_nml(49)%nodata = -9999. -obs_param_nml(49)%varname = 'sfmc' +obs_param_nml(49)%varname = 'sfds' obs_param_nml(49)%units = 'm3/m3' obs_param_nml(49)%path = '/discover/nobackup/projects/gmao/merra/iau/merra_land/DATA/ASCAT_EUMETSAT/Metop_A/' obs_param_nml(49)%name = 'M02-ASCA-ASCSMO02' @@ -2125,7 +2125,7 @@ obs_param_nml(50)%bias_Npar = 0 obs_param_nml(50)%bias_trel = 864000 obs_param_nml(50)%bias_tcut = 432000 obs_param_nml(50)%nodata = -9999. -obs_param_nml(50)%varname = 'sfmc' +obs_param_nml(50)%varname = 'sfds' obs_param_nml(50)%units = 'm3/m3' obs_param_nml(50)%path = '/discover/nobackup/projects/gmao/merra/iau/merra_land/DATA/ASCAT_EUMETSAT/Metop_A/' obs_param_nml(50)%name = 'M02-ASCA-ASCSMO02' @@ -2165,7 +2165,7 @@ obs_param_nml(51)%bias_Npar = 0 obs_param_nml(51)%bias_trel = 864000 obs_param_nml(51)%bias_tcut = 432000 obs_param_nml(51)%nodata = -9999. -obs_param_nml(51)%varname = 'sfmc' +obs_param_nml(51)%varname = 'sfds' obs_param_nml(51)%units = 'm3/m3' obs_param_nml(51)%path = '/discover/nobackup/projects/gmao/merra/iau/merra_land/DATA/ASCAT_EUMETSAT/Metop_B/' obs_param_nml(51)%name = 'M01-ASCA-ASCSMO02' @@ -2204,7 +2204,7 @@ obs_param_nml(52)%bias_Npar = 0 obs_param_nml(52)%bias_trel = 864000 obs_param_nml(52)%bias_tcut = 432000 obs_param_nml(52)%nodata = -9999. -obs_param_nml(52)%varname = 'sfmc' +obs_param_nml(52)%varname = 'sfds' obs_param_nml(52)%units = 'm3/m3' obs_param_nml(52)%path = '/discover/nobackup/projects/gmao/merra/iau/merra_land/DATA/ASCAT_EUMETSAT/Metop_B/' obs_param_nml(52)%name = 'M01-ASCA-ASCSMO02' diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index d102cdfc..3d14e70a 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -1130,7 +1130,13 @@ subroutine get_obs_pred( & get_sfmc_l = .true. get_sfmc_lH = .true. get_tsurf_l = .true. ! needed for model-based QC + + case ('sfds') + get_sfmc_l = .true. + get_sfmc_lH = .true. + get_tsurf_l = .true. ! needed for model-based QC + case ('rzmc') get_rzmc_l = .true. @@ -1668,6 +1674,10 @@ subroutine get_obs_pred( & case ('sfmc') tmp_data(1:N_tmp) = sfmc_lH( ind_tmp(1:N_tmp), n_e ) + + case ('sfds') + + tmp_data(1:N_tmp) = sfmc_lH( ind_tmp(1:N_tmp), n_e ) case ('rzmc') From 60c07b9f5ab072104351c1d3880363173b43b051 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Tue, 31 Jan 2023 18:10:27 -0700 Subject: [PATCH 042/308] change N_slect_varnames --- .../GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index 3d14e70a..4a992a12 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -3707,9 +3707,10 @@ subroutine cat_enkf_increments( & if (logit) write (logunit,*) 'get 3d soil moisture increments; sfmc obs' - N_select_varnames = 1 + N_select_varnames = 2 select_varnames(1) = 'sfmc' + select_varnames(2) = 'sfds' call get_select_species( & N_select_varnames, select_varnames(1:N_select_varnames), & From 67fb4e5b9388e7aabda67fd3421b63ae0390686b Mon Sep 17 00:00:00 2001 From: amfox37 Date: Wed, 1 Feb 2023 11:36:09 -0700 Subject: [PATCH 043/308] deliberate breaking for test --- .../GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index 4a992a12..832524d5 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -1131,7 +1131,7 @@ subroutine get_obs_pred( & get_sfmc_lH = .true. get_tsurf_l = .true. ! needed for model-based QC - case ('sfds') + case ('sfdsss') get_sfmc_l = .true. get_sfmc_lH = .true. @@ -1675,7 +1675,7 @@ subroutine get_obs_pred( & tmp_data(1:N_tmp) = sfmc_lH( ind_tmp(1:N_tmp), n_e ) - case ('sfds') + case ('sfdsss') tmp_data(1:N_tmp) = sfmc_lH( ind_tmp(1:N_tmp), n_e ) @@ -3710,7 +3710,7 @@ subroutine cat_enkf_increments( & N_select_varnames = 2 select_varnames(1) = 'sfmc' - select_varnames(2) = 'sfds' + select_varnames(2) = 'sfdsss' call get_select_species( & N_select_varnames, select_varnames(1:N_select_varnames), & From 5f5f3bbb6bda5630178def681315a0f7c2ce0f64 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Wed, 1 Feb 2023 15:47:39 -0700 Subject: [PATCH 044/308] sfds fix --- .../GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index 832524d5..d3515a6b 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -1131,7 +1131,7 @@ subroutine get_obs_pred( & get_sfmc_lH = .true. get_tsurf_l = .true. ! needed for model-based QC - case ('sfdsss') + case ('sfds') get_sfmc_l = .true. get_sfmc_lH = .true. @@ -1675,7 +1675,7 @@ subroutine get_obs_pred( & tmp_data(1:N_tmp) = sfmc_lH( ind_tmp(1:N_tmp), n_e ) - case ('sfdsss') + case ('sfds') tmp_data(1:N_tmp) = sfmc_lH( ind_tmp(1:N_tmp), n_e ) @@ -3710,7 +3710,7 @@ subroutine cat_enkf_increments( & N_select_varnames = 2 select_varnames(1) = 'sfmc' - select_varnames(2) = 'sfdsss' + select_varnames(2) = 'sfds' call get_select_species( & N_select_varnames, select_varnames(1:N_select_varnames), & @@ -4848,7 +4848,7 @@ subroutine get_ind_obs_lat_lon_box( & if (N_select_species==0) then ! use all species - do i=1,N_obs + do i=1,N_obs ! determine center-of-mass coordinates for the given observation From 442667444f151aeda60f6e78a489ea6561fb849c Mon Sep 17 00:00:00 2001 From: "Lauren C. Andrews" Date: Thu, 2 Feb 2023 12:02:02 -0500 Subject: [PATCH 045/308] now SCA / CI_Index --- .../GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 29fff30c..acf03ae9 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -346,7 +346,7 @@ subroutine read_MODISsca_hdf( N_files, date_time, N_data, fnames, & if(keep_data) then j=j+1 - MODIS_SCA_tmp(j) = MODIS_SCA_raw(i)/100 + MODIS_SCA_tmp(j) = MODIS_SCA_raw(i)/CI_Index(i) lon_tmp(j) = lon_1D(i) lat_tmp(j) = lat_1D(i) From 264e842777787ec992863d444632f1636950155c Mon Sep 17 00:00:00 2001 From: amfox37 Date: Thu, 2 Feb 2023 13:40:04 -0700 Subject: [PATCH 046/308] units in nml and combine case --- .../LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml | 8 ++++---- .../clsm_ensupd_upd_routines.F90 | 14 ++------------ 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml b/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml index 1153a8d8..b82ff851 100644 --- a/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml +++ b/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml @@ -2087,7 +2087,7 @@ obs_param_nml(49)%bias_trel = 864000 obs_param_nml(49)%bias_tcut = 432000 obs_param_nml(49)%nodata = -9999. obs_param_nml(49)%varname = 'sfds' -obs_param_nml(49)%units = 'm3/m3' +obs_param_nml(49)%units = '%' obs_param_nml(49)%path = '/discover/nobackup/projects/gmao/merra/iau/merra_land/DATA/ASCAT_EUMETSAT/Metop_A/' obs_param_nml(49)%name = 'M02-ASCA-ASCSMO02' obs_param_nml(49)%scalepath = '' @@ -2126,7 +2126,7 @@ obs_param_nml(50)%bias_trel = 864000 obs_param_nml(50)%bias_tcut = 432000 obs_param_nml(50)%nodata = -9999. obs_param_nml(50)%varname = 'sfds' -obs_param_nml(50)%units = 'm3/m3' +obs_param_nml(50)%units = '%' obs_param_nml(50)%path = '/discover/nobackup/projects/gmao/merra/iau/merra_land/DATA/ASCAT_EUMETSAT/Metop_A/' obs_param_nml(50)%name = 'M02-ASCA-ASCSMO02' obs_param_nml(50)%scalepath = '' @@ -2166,7 +2166,7 @@ obs_param_nml(51)%bias_trel = 864000 obs_param_nml(51)%bias_tcut = 432000 obs_param_nml(51)%nodata = -9999. obs_param_nml(51)%varname = 'sfds' -obs_param_nml(51)%units = 'm3/m3' +obs_param_nml(51)%units = '%' obs_param_nml(51)%path = '/discover/nobackup/projects/gmao/merra/iau/merra_land/DATA/ASCAT_EUMETSAT/Metop_B/' obs_param_nml(51)%name = 'M01-ASCA-ASCSMO02' obs_param_nml(51)%scalepath = '' @@ -2205,7 +2205,7 @@ obs_param_nml(52)%bias_trel = 864000 obs_param_nml(52)%bias_tcut = 432000 obs_param_nml(52)%nodata = -9999. obs_param_nml(52)%varname = 'sfds' -obs_param_nml(52)%units = 'm3/m3' +obs_param_nml(52)%units = '%' obs_param_nml(52)%path = '/discover/nobackup/projects/gmao/merra/iau/merra_land/DATA/ASCAT_EUMETSAT/Metop_B/' obs_param_nml(52)%name = 'M01-ASCA-ASCSMO02' obs_param_nml(52)%scalepath = '' diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index d3515a6b..629ef607 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -1125,18 +1125,12 @@ subroutine get_obs_pred( & select case (trim(obs_param(i)%varname)) - case ('sfmc') + case ('sfmc', 'sfds') get_sfmc_l = .true. get_sfmc_lH = .true. get_tsurf_l = .true. ! needed for model-based QC - case ('sfds') - - get_sfmc_l = .true. - get_sfmc_lH = .true. - get_tsurf_l = .true. ! needed for model-based QC - case ('rzmc') get_rzmc_l = .true. @@ -1671,11 +1665,7 @@ subroutine get_obs_pred( & select case (trim(obs_param(this_species)%varname)) - case ('sfmc') - - tmp_data(1:N_tmp) = sfmc_lH( ind_tmp(1:N_tmp), n_e ) - - case ('sfds') + case ('sfmc', 'sfds') tmp_data(1:N_tmp) = sfmc_lH( ind_tmp(1:N_tmp), n_e ) From 74ee3a51cbb78b71679df70e9367e66469b258cc Mon Sep 17 00:00:00 2001 From: "Lauren C. Andrews" Date: Thu, 2 Feb 2023 16:05:18 -0500 Subject: [PATCH 047/308] small updates to read MODIS v06.1 --- .../GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index acf03ae9..e8dbc6ff 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -222,11 +222,11 @@ subroutine read_MODISsca_hdf( N_files, date_time, N_data, fnames, & !if(logit) write(logunit, *) 'fname: ', fnames(j) sd_id(j) = sfstart(fnames(j), DFACC_READ) - !if(logit) write (logunit, *), 'sd_id:' , sd_id(j) + if(logit) write (logunit, *), 'sd_id:' , sd_id(j) status = sffinfo(sd_id(j), n_datasets, n_file_attrs) - ! if(logit) write(logunit, *) '! Number of data sets in the file and Number of file attributes :' - ! if(logit) write(logunit, *) 'sffinfo: ', status, n_datasets, n_file_attrs + !if(logit) write(logunit, *) '! Number of data sets in the file and Number of file attributes :' + !if(logit) write(logunit, *) 'sffinfo: ', status, n_datasets, n_file_attrs do i=1,N_fields @@ -463,7 +463,7 @@ subroutine read_obs_MODISsca( & write (logunit, *) 'DOY: ', DDD tmpfname1 = trim(this_obs_param%path) // YYYY // '/MOD10C1.A' // YYYY // DDD // & - '.006.hdf' + '.061.hdf' if (logit) write (logunit, *) 'Trying to read data from', & trim(tmpfname1) From 243eabeeb7396135da2a7eab1ece303168652501 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Fri, 3 Mar 2023 12:10:07 -0500 Subject: [PATCH 048/308] temp fixes to reader --- .../clsm_ensupd_read_obs.F90 | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index adeb5552..aa77e5b8 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -1795,6 +1795,7 @@ subroutine read_obs_sm_ASCAT_EUMET( & ! skip if correction flag is set call ufbint(lnbufr,tmp_data,1,1,iret,'SMCF') + ! if (.not. (int(tmp_data) == 0 .or. int(tmp_data) == 4)) cycle loop_report if(int(tmp_data) /= 0) cycle loop_report ! skip if land fraction is missing or < 0.9 @@ -7456,7 +7457,19 @@ subroutine read_obs( & tile_grid_d, N_tile_in_cell_ij, tile_num_in_cell_ij, & this_obs_param, & found_obs, tmp_obs, tmp_std_obs ) - + ! Temporay hack to output if ascending/decending instead of tmp_std_obs + select case (trim(this_obs_param%descr)) + + case ('ASCAT_META_SM_A', 'ASCAT_METB_SM_A') + + tmp_std_obs(1:N_catd) = 1 + + case ('ASCAT_META_SM_D', 'ASCAT_METB_SM_D') + + tmp_std_obs(1:N_catd) = 2 + + end select + ! scale observations to model climatology if (this_obs_param%scale .and. found_obs) then From ed82beeb71cc45d221659791eea0da5e3447ee9a Mon Sep 17 00:00:00 2001 From: amfox37 Date: Tue, 14 Mar 2023 12:14:11 -0400 Subject: [PATCH 049/308] minor bug fixes --- .../obs_scaling_params/Run_get_L4_Tb_scale_SMAP.m | 2 +- .../obs_scaling_params/get_ij_ind_from_latlon.m | 7 +++++-- .../get_model_and_obs_clim_stats.m | 5 +++-- .../LDAS_App/util/shared/matlab/pentad_of_year.m | 14 ++++++++++++++ 4 files changed, 23 insertions(+), 5 deletions(-) create mode 100644 src/Applications/LDAS_App/util/shared/matlab/pentad_of_year.m diff --git a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/Run_get_L4_Tb_scale_SMAP.m b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/Run_get_L4_Tb_scale_SMAP.m index 62f54caa..a18bbe12 100644 --- a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/Run_get_L4_Tb_scale_SMAP.m +++ b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/Run_get_L4_Tb_scale_SMAP.m @@ -19,7 +19,7 @@ %exp_run = {'SPL4SM_OL4001'}; %exp_path = '/smap1/qliu/output/SMAP_Nature_v8.3/NRv8.3_innov/S1/'; %exp_run = {'SMAP_NRv8.3_innov'}; -exp_path = '/home/qliu/smap/SMAP_Nature/'; +exp_path = '/discover/nobackup/amfox'; exp_run = {'SPL4SM_OL7000'}; domain = 'SMAP_EASEv2_M09_GLOBAL'; diff --git a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_ij_ind_from_latlon.m b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_ij_ind_from_latlon.m index dc9becfa..8395aa89 100644 --- a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_ij_ind_from_latlon.m +++ b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_ij_ind_from_latlon.m @@ -5,11 +5,11 @@ if (strcmp(tile_grid.gridtype,'EASEv2_M36')) %row, col [j_indg,i_indg] = ... - smapeasev2_latlon2ind(lat,lon,'M36'); + EASEv2_latlon2ind(lat,lon,'M36'); elseif (strcmp(tile_grid.gridtype,'EASEv2_M09')) %row, col [j_indg,i_indg] = ... - smapeasev2_latlon2ind(lat,lon,'M09'); + EASEv2_latlon2ind(lat,lon,'M09'); else error('not ready for this grid'); end @@ -18,6 +18,9 @@ i_ind = i_indg - tile_grid.i_offg - (tile_grid.ind_base - 1); j_ind = j_indg - tile_grid.j_offg - (tile_grid.ind_base - 1); + + i_ind = round(i_ind); + j_ind = round(j_ind); end diff --git a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats.m b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats.m index 52e55f76..03003ee0 100644 --- a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats.m +++ b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats.m @@ -231,8 +231,9 @@ %2) convert back to lat/lon at center of obs if (~isempty(strfind(convert_grid, 'M36')) && ~isempty(strfind(convert_grid, 'EASEv2'))) gridid = 'M36'; - [central_row,central_col] = smapeasev2_latlon2ind(central_lat,central_lon,gridid); - [central_lat,central_lon] = smapeasev2_ind2latlon(central_row,central_col,gridid); + [central_row,central_col] = EASEv2_latlon2ind(central_lat,central_lon,gridid); + central_row = round(central_row); central_col = round(central_col); + [central_lat,central_lon] = EASEv2_ind2latlon(central_row,central_col,gridid); elseif (~isempty(strfind(convert_grid, 'M36')) && ~isempty(strfind(convert_grid, 'EASEv1'))) gridid = 'M36'; [central_row,central_col] = smapeasev1_latlon2ind(central_lat,central_lon,gridid); diff --git a/src/Applications/LDAS_App/util/shared/matlab/pentad_of_year.m b/src/Applications/LDAS_App/util/shared/matlab/pentad_of_year.m new file mode 100644 index 00000000..507cd921 --- /dev/null +++ b/src/Applications/LDAS_App/util/shared/matlab/pentad_of_year.m @@ -0,0 +1,14 @@ + +function pentad = pentad_of_year(day_of_year, year) + +if (is_leap_year(year) & day_of_year>=59) + + pentad = floor((day_of_year-2)/5)+1; + +else + + pentad = floor((day_of_year-1)/5)+1; + +end + +% ======================= EOF ================================== \ No newline at end of file From 19813fa26a70c3dc553ef262df6174f550f3c1d6 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Tue, 14 Mar 2023 12:28:22 -0400 Subject: [PATCH 050/308] update Shared_CMakelists --- src/Shared/CMakeLists.txt | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Shared/CMakeLists.txt b/src/Shared/CMakeLists.txt index cbd532d6..822331ee 100644 --- a/src/Shared/CMakeLists.txt +++ b/src/Shared/CMakeLists.txt @@ -1,5 +1,4 @@ -esma_add_subdirectories ( - @MAPL - @GMAO_Shared - @NCEP_Shared - ) +esma_add_subdirectory (MAPL) +esma_add_subdirectory (GMAO_Shared) +esma_add_subdirectory (GEOS_Util) +esma_add_subdirectory (NCEP_Shared) From e47b9856f41f43fbc59f35df1bbfefdac27c7d86 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Mon, 20 Mar 2023 16:33:25 -0400 Subject: [PATCH 051/308] relaxed QC --- .../GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index aa77e5b8..d6823758 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -1795,8 +1795,8 @@ subroutine read_obs_sm_ASCAT_EUMET( & ! skip if correction flag is set call ufbint(lnbufr,tmp_data,1,1,iret,'SMCF') - ! if (.not. (int(tmp_data) == 0 .or. int(tmp_data) == 4)) cycle loop_report - if(int(tmp_data) /= 0) cycle loop_report + if (.not. (int(tmp_data) == 0 .or. int(tmp_data) == 4)) cycle loop_report + ! if(int(tmp_data) /= 0) cycle loop_report ! skip if land fraction is missing or < 0.9 call ufbint(lnbufr,tmp_data,1,1,iret,'ALFR') From 8506d17843747322cbf82119c134651dd3f5b63d Mon Sep 17 00:00:00 2001 From: amfox37 Date: Wed, 22 Mar 2023 18:42:27 -0400 Subject: [PATCH 052/308] making things generic --- ...P.m => Run_get_model_and_obs_clim_stats.m} | 72 +++---- .../get_model_and_obs_clim_stats.m | 185 ++++++++++++------ .../obs_scaling_params/write_seqbin_file.m | 47 ++--- 3 files changed, 174 insertions(+), 130 deletions(-) rename src/Applications/LDAS_App/util/inputs/obs_scaling_params/{Run_get_L4_Tb_scale_SMAP.m => Run_get_model_and_obs_clim_stats.m} (68%) diff --git a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/Run_get_L4_Tb_scale_SMAP.m b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/Run_get_model_and_obs_clim_stats.m similarity index 68% rename from src/Applications/LDAS_App/util/inputs/obs_scaling_params/Run_get_L4_Tb_scale_SMAP.m rename to src/Applications/LDAS_App/util/inputs/obs_scaling_params/Run_get_model_and_obs_clim_stats.m index a18bbe12..01817fd7 100644 --- a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/Run_get_L4_Tb_scale_SMAP.m +++ b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/Run_get_model_and_obs_clim_stats.m @@ -25,11 +25,11 @@ %Start and end year for each month start_year = [repmat(2016,1,3) repmat(2015,1,9) repmat(2016,1,3) repmat(2015,1,1)]; %corresp to [1:12 1 2] -end_year = [repmat(2022,1,3) repmat(2021,1,9) repmat(2022,1,3) repmat(2021,1,1)]; %runs till end of run_months for end_year +end_year = [repmat(2017,1,3) repmat(2016,1,9) repmat(2017,1,3) repmat(2016,1,1)]; %runs till end of run_months for end_year -orbit = [ 2]; %1=A, 2=D !DO *NOT* USE ASC AND DESC TOGETHER! -pol = [ 1 2 ]; %1=H, 2=V -inc_ang = [ 40.0 ]; +%d orbit = [ 2]; %1=A, 2=D !DO *NOT* USE ASC AND DESC TOGETHER! +%d pol = [ 1 2 ]; %1=H, 2=V +%d inc_ang = [ 40.0 ]; prefix_out = 'L4SM_OL7000_SMAPL1CR17000_zscore_stats_'; @@ -44,18 +44,19 @@ obs_param_fname = [exp_path, '/', exp_run{1}, '/output/', domain, '/rc_out/', ... '/Y2015/M04/',exp_run{1}, '.ldas_obsparam.20150401_0000z.txt']; -var_name = {'Tb'}; +%d var_name = {'Tb'}; % added to identify SMOS or SMAP from runs that include both -descr = 'SMAP_L1C' ; % 'SMOS_fit' +species_names = {'SMAP_L1C_Tbh_A', 'SMAP_L1C_Tbv_A', 'SMAP_L1C_Tbh_D', 'SMAP_L1C_Tbv_D'}; +species_names = {'SMAP_L1C_Tbh_A'}; %====== -if (length(orbit) > 1) - error('ONLY pick one orbit!') -end +%d if (length(orbit) > 1) + %d error('ONLY pick one orbit!' +%d end -if (orbit(1) == 1) int_Asc = 1; end %Asc -if (orbit(1) == 2) int_Asc = 0; end %Desc +%d if (orbit(1) == 1) int_Asc = 1; end %Asc +%d if (orbit(1) == 2) int_Asc = 0; end %Desc %====== %TO GO FROM SMOS TO SMAP ONLY!!! @@ -90,20 +91,25 @@ species =[]; -for oo=1:length(orbit) - for pp=1:length(pol) - for aa=1:length(inc_ang) - - add_species = obs_param(strcmp(var_name,{obs_param.varname}) & ... - orbit(oo) == [obs_param.orbit] & ... - inc_ang(aa) == [obs_param.ang] & ... - pol(pp) == [obs_param.pol] & ... - ~cellfun(@isempty, strfind({obs_param.descr},descr))).species; - - species = union(species,add_species); - - end - end +% for oo=1:length(orbit) +% for pp=1:length(pol) +% for aa=1:length(inc_ang) +% +% add_species = obs_param(strcmp(var_name,{obs_param.varname}) & ... +% orbit(oo) == [obs_param.orbit] & ... +% inc_ang(aa) == [obs_param.ang] & ... +% pol(pp) == [obs_param.pol] & ... +% ~cellfun(@isempty, strfind({obs_param.descr},descr))).species; +% +% species = union(species,add_species); +% +% end +% end +% end + +for i = 1:length(species_names) + add_species = obs_param(strcmp(species_names(i),{obs_param.descr})).species; + species = union(species,add_species); end species @@ -120,11 +126,11 @@ for k=1:length(run_months) - get_model_and_obs_clim_stats( var_name, ... + get_model_and_obs_clim_stats( species_names, ... run_months{k}, exp_path, exp_run{n}, domain, ... start_year, end_year, ... dt_assim, t0_assim, species, obs_param, ... - hscale, inc_ang, int_Asc, w_days, Ndata_min, prefix_out,... + hscale, w_days, Ndata_min, prefix_out,... convert_grid, time_of_day_in_hours(j) ); end @@ -133,10 +139,10 @@ else - get_model_and_obs_clim_stats( var_name, ... + get_model_and_obs_clim_stats( species_names, ... run_months, exp_path, exp_run{n}, domain, start_year, end_year, ... dt_assim, t0_assim, species, obs_param, ... - hscale, inc_ang, int_Asc, w_days, Ndata_min, prefix_out,... + hscale, w_days, Ndata_min, prefix_out,... convert_grid ); end @@ -149,11 +155,11 @@ for k=1:length(run_months) - get_model_and_obs_clim_stats( var_name, ... + get_model_and_obs_clim_stats( species_names, ... run_months{k}, exp_path, exp_run{n}, domain, ... start_year, end_year, ... dt_assim, t0_assim, species, obs_param, ... - hscale, inc_ang, int_Asc, w_days, Ndata_min, prefix_out,... + hscale, w_days, Ndata_min, prefix_out,... time_of_day_in_hours(j) ); end @@ -162,10 +168,10 @@ else - get_model_and_obs_clim_stats( var_name, ... + get_model_and_obs_clim_stats( species_names, ... run_months, exp_path, exp_run{n}, domain, start_year, end_year, ... dt_assim, t0_assim, species, obs_param, ... - hscale, inc_ang, int_Asc, w_days, Ndata_min, prefix_out); + hscale, w_days, Ndata_min, prefix_out); end diff --git a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats.m b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats.m index 03003ee0..8a6b27dd 100644 --- a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats.m +++ b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats.m @@ -1,8 +1,8 @@ -function [] = get_model_and_obs_clim_stats( varname, ... +function [] = get_model_and_obs_clim_stats( species_names, ... run_months, exp_path, exp_run, domain, start_year, end_year, ... dt_assim, t0_assim, species, obs_param, ... - hscale, inc_angle, int_Asc, w_days, Ndata_min, prefix, ... + hscale, w_days, Ndata_min, prefix, ... convert_grid , time_of_day_in_hours ) % @@ -116,13 +116,15 @@ overwrite = 1; -Nf = 5; %5 fields per polarization -N_out_fields = 2*Nf+4; %14; +N_species = length(species); + +Nf = 5; %5 fields per species +N_out_fields = N_species*Nf + N_species * 2; %This includes the debugging fields to replicate SMAP code write_ind_latlon = 'latlon_id'; %'latlon'; -N_angle = length(inc_angle); -N_pol = 2; +%d N_angle = length(inc_angle); +%d N_pol = 2; tmp_shift_lon = 0.01; tmp_shift_lat = 0.005; @@ -185,12 +187,53 @@ '_hscale_', num2str(hscale,'%2.2f'), '_', ... 'W_', num2str(round(w_days/5)),'p_Nmin_', num2str(Ndata_min)]; -%fname_out_base = [fname_out_base, spec_tag]; +% Some clunky code to maintain backwards compatibility with adding orbit +% tag + +% Initialize counters for cells ending in "_A" and cells ending in "_D" +a_count = 0; +d_count = 0; + +% Loop through each cell in the array +for i = 1:numel(species_names) + % Check if the text in the cell ends with either "_A" or "_D" + if endsWith(species_names{i}, '_A') + % If it ends with "_A", increment the "_A" counter + a_count = a_count + 1; + elseif endsWith(species_names{i}, '_D') + % If it ends with "_D", increment the "_D" counter + d_count = d_count + 1; + end + + if startsWith(species_names{i}, 'SMAP') + inc_angle = [40.0]; + else + inc_angle = [-999.9]; + end + +end -if (int_Asc == 1) - Orbit_tag = '_A'; %'_Asc'; +% Determine the output based on the values of the "_A" and "_D" counters +if a_count == numel(species_names) + % Both cells end in "_A" + disp('All species are "_A"'); + Orbit_tag = '_A'; + int_Asc = 1; +elseif d_count == numel(species_names) + % Both cells end in "_D" + disp('All species are "_D"'); + Orbit_tag = '_D'; + int_Asc = 2; +elseif a_count > 0 && d_count > 0 + % There is a mix of "_A" and "_D" + disp('Spcies have a mix of "_A" and "_D"'); + Orbit_tag = '_AD'; + int_Asc = 3; else - Orbit_tag = '_D'; %'_Desc'; + % Neither cell ends in "_A" or "_D" + disp('Neither cell ends in "_A" or "_D"'); + Orbit_tag = '_NoOrbits'; + int_Asc = 4; end fname_out_base = [fname_out_base, Orbit_tag]; @@ -330,13 +373,13 @@ % N_pol and N_angle be specified here. Then subsample specifically % when the files are written out. -o_data = NaN+zeros(N_pol,N_tile_obs,N_angle,w_days); -m_data = NaN+zeros(N_pol,N_tile_obs,N_angle,w_days); -o_data2 = NaN+zeros(N_pol,N_tile_obs,N_angle,w_days); -m_data2 = NaN+zeros(N_pol,N_tile_obs,N_angle,w_days); -N_data = NaN+zeros(N_pol,N_tile_obs,N_angle,w_days); +o_data = NaN+zeros(N_species,N_tile_obs,w_days); +m_data = NaN+zeros(N_species,N_tile_obs,w_days); +o_data2 = NaN+zeros(N_species,N_tile_obs,w_days); +m_data2 = NaN+zeros(N_species,N_tile_obs,w_days); +N_data = NaN+zeros(N_species,N_tile_obs,w_days); -data_out = NaN+zeros(N_out_fields,N_tile_obs,N_angle); +data_out = NaN+zeros(N_out_fields,N_tile_obs); % ------------------------------------------------------------- @@ -437,8 +480,12 @@ % extract species of interest ind = []; + + scnt = 0; for this_species = species + + scnt = scnt + 1; ind = find( obs_species == this_species); @@ -466,7 +513,7 @@ %pol intrinsically gives an index %now find the index for the angle - angle_i = find(angle(1) == inc_angle); + %d angle_i = find(angle(1) == inc_angle); % Only writes lat-lon at exact obs locations, but with % hscale>0, these obs are spread outside their exact @@ -500,15 +547,15 @@ %e.g. at the poles. %**nansum of NaN's** result in zero, this need to be %taken care of - o_data(pol(1),obs_i,angle_i,count) = nansum([o_data(pol(1),obs_i,angle_i,count); obs_obs_i' ]); - m_data(pol(1),obs_i,angle_i,count) = nansum([m_data(pol(1),obs_i,angle_i,count); obs_fcst_i']); + o_data(scnt,obs_i,count) = nansum([o_data(scnt,obs_i,count); obs_obs_i' ]); + m_data(scnt,obs_i,count) = nansum([m_data(scnt,obs_i,count); obs_fcst_i']); %X^2 - o_data2(pol(1),obs_i,angle_i,count) = nansum([o_data2(pol(1),obs_i,angle_i,count); obs_obs_i'.^2 ]); - m_data2(pol(1),obs_i,angle_i,count) = nansum([m_data2(pol(1),obs_i,angle_i,count); obs_fcst_i'.^2]); + o_data2(scnt,obs_i,count) = nansum([o_data2(scnt,obs_i,count); obs_obs_i'.^2 ]); + m_data2(scnt,obs_i,count) = nansum([m_data2(scnt,obs_i,count); obs_fcst_i'.^2]); %Sum of obs or model elements at each location - N_data(pol(1),obs_i,angle_i,count) = nansum([N_data(pol(1),obs_i,angle_i,count); ~isnan([obs_obs_i])']); + N_data(scnt,obs_i,count) = nansum([N_data(scnt,obs_i,count); ~isnan([obs_obs_i])']); else @@ -520,20 +567,20 @@ %hscale_ind =[obs space] % %Sum of X - o_data(pol(1),s_eff,angle_i,count) = ... - nansum([o_data(pol(1),s_eff,angle_i,count); repmat(obs_obs_i(i_ind),1,length(s_eff))]); - m_data(pol(1),s_eff,angle_i,count) = ... + o_data(scnt,obs_i,count) = ... + nansum([o_data(scnt,obs_i,count); repmat(obs_obs_i(i_ind),1,length(s_eff))]); + m_data(scnt,obs_i,count) = ... nansum([m_data(pol(1),s_eff,angle_i,count); repmat(obs_fcst_i(i_ind),1,length(s_eff))]); %Sum of X^2 - o_data2(pol(1),s_eff,angle_i,count) = ... - nansum([o_data2(pol(1),s_eff,angle_i,count); repmat(obs_obs_i(i_ind).^2,1,length(s_eff))]); - m_data2(pol(1),s_eff,angle_i,count) = ... - nansum([m_data2(pol(1),s_eff,angle_i,count); repmat(obs_fcst_i(i_ind).^2,1,length(s_eff))]); + o_data2(scnt,obs_i,count) = ... + nansum([o_data2(scnt,obs_i,count); repmat(obs_obs_i(i_ind).^2,1,length(s_eff))]); + m_data2(scnt,obs_i,count) = ... + nansum([m_data2(scnt,obs_i,count); repmat(obs_fcst_i(i_ind).^2,1,length(s_eff))]); %Sum of obs or model elements at each location - N_data(pol(1),s_eff,angle_i,count) = ... - nansum([N_data(pol(1),s_eff,angle_i,count); repmat(~isnan([obs_obs_i(i_ind)]),1,length(s_eff)) ]); + N_data(scnt,obs_i,count) = ... + nansum([N_data(scnt,obs_i,count); repmat(~isnan([obs_obs_i(i_ind)]),1,length(s_eff)) ]); end @@ -572,48 +619,48 @@ % data_out = zeros(N_out_fields,1:N_tiles,N_angle); - for pol=[0 1] + for i = 0:N_species-1 - pp = pol*Nf; + pp = i*Nf; - N_hscale_window = nansum(N_data(1+pol,:,:,1:w_days),4); + N_hscale_window = nansum(N_data(1+i,:,1:w_days),3); if w_days == 95 - N_hscale_inner_window = nansum(N_data(1+pol,:,:,((w_days+1)/2-15):((w_days+1)/2+15)),4); + N_hscale_inner_window = nansum(N_data(1+i,:,((w_days+1)/2-15):((w_days+1)/2+15)),3); end % OBSERVATIONS %---------------- %o_data is a sum over neighbouring obs above; %here then take a sum over the time steps in the window - data_out(1+pp,:,:) = nansum(o_data(1+pol,:,:,1:w_days),4); + data_out(1+pp,:) = nansum(o_data(1+i,:,1:w_days),3); %then make the average, by dividing over the sum of the number of %timesteps and influencing obs at each location - data_out(1+pp,:,:) = data_out(1+pp,:,:)./N_hscale_window; + data_out(1+pp,:) = data_out(1+pp,:)./N_hscale_window; %stdv_H = sqrt(E[X^2] - E[X]^2) - data_out(2+pp,:,:) = nansum(o_data2(1+pol,:,:,1:w_days),4); - data_out(2+pp,:,:) = data_out(2+pp,:,:)./N_hscale_window; - data_out(2+pp,:,:) = sqrt( data_out(2+pp,:,:) - data_out(1+pp,:,:).^2); + data_out(2+pp,:) = nansum(o_data2(1+i,:,1:w_days),3); + data_out(2+pp,:) = data_out(2+pp,:)./N_hscale_window; + data_out(2+pp,:) = sqrt( data_out(2+pp,:) - data_out(1+pp,:).^2); % MODEL %---------------- - data_out(3+pp,:,:) = nansum(m_data(1+pol,:,:,1:w_days),4); - data_out(3+pp,:,:) = data_out(3+pp,:,:)./N_hscale_window; + data_out(3+pp,:) = nansum(m_data(1+i,:,1:w_days),3); + data_out(3+pp,:) = data_out(3+pp,:)./N_hscale_window; - data_out(4+pp,:,:) = nansum(m_data2(1+pol,:,:,1:w_days),4); - data_out(4+pp,:,:) = data_out(4+pp,:,:)./N_hscale_window; - data_out(4+pp,:,:) = sqrt( data_out(4+pp,:,:) - data_out(3+pp,:,:).^2); + data_out(4+pp,:) = nansum(m_data2(1+i,:,1:w_days),3); + data_out(4+pp,:) = data_out(4+pp,:)./N_hscale_window; + data_out(4+pp,:) = sqrt( data_out(4+pp,:) - data_out(3+pp,:).^2); - data_out(5+pp,:,:) = N_hscale_window; + data_out(5+pp,:) = N_hscale_window; % Toss out stats that are based on too little data - data_out([1:5]+pp,N_hscale_window 1) - data = squeeze(data_org(:,:,j)); - end - - count = fwrite( ifp, fortran_tag, int_precision ); - count = fwrite( ifp, data(i,:), float_precision ); - count = fwrite( ifp, fortran_tag, int_precision ); - - - end - + count = fwrite( ifp, fortran_tag, int_precision ); + count = fwrite( ifp, data(i,:), float_precision ); + count = fwrite( ifp, fortran_tag, int_precision ); end else @@ -287,15 +276,9 @@ end for i=1:N_out_fields - - for j=1:N_angle - - count = fwrite( ifp, fortran_tag, int_precision ); - count = fwrite( ifp, -999.0, float_precision ); - count = fwrite( ifp, fortran_tag, int_precision ); - - end - + count = fwrite( ifp, fortran_tag, int_precision ); + count = fwrite( ifp, -999.0, float_precision ); + count = fwrite( ifp, fortran_tag, int_precision ); end end From 636591065f885d018c0f7ea6f0187e8f79d61198 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Mon, 27 Mar 2023 14:16:32 -0600 Subject: [PATCH 053/308] add metop-C --- .../LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml | 114 ++++++++++++++---- .../clsm_ensupd_glob_param.F90 | 2 +- .../clsm_ensupd_read_obs.F90 | 16 +-- 3 files changed, 92 insertions(+), 40 deletions(-) diff --git a/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml b/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml index b82ff851..f7f4e193 100644 --- a/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml +++ b/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml @@ -2067,15 +2067,13 @@ obs_param_nml(48)%adapt = 0 ! ! 49 = ASCAT_META_SM_A (ASCAT soil moisture ascending) ! -! ASCAT: VV-pol, incidence angle 25-65 deg -! for now keep N_ang=0, pol=0 -! - reichle, 30 Jun 2015 +! https://navigator.eumetsat.int/product/EO:EUM:DAT:METOP:SOMO25 obs_param_nml(49)%descr = 'ASCAT_META_SM_A' obs_param_nml(49)%orbit = 1 obs_param_nml(49)%pol = 0 obs_param_nml(49)%N_ang = 0 -obs_param_nml(49)%freq = 5.255e9 +obs_param_nml(49)%freq = 0 obs_param_nml(49)%FOV = 20. obs_param_nml(49)%FOV_units = 'km' obs_param_nml(49)%assim = .false. @@ -2083,8 +2081,8 @@ obs_param_nml(49)%scale = .false. obs_param_nml(49)%getinnov = .false. obs_param_nml(49)%RTM_ID = 0 obs_param_nml(49)%bias_Npar = 0 -obs_param_nml(49)%bias_trel = 864000 -obs_param_nml(49)%bias_tcut = 432000 +obs_param_nml(49)%bias_trel = 0 +obs_param_nml(49)%bias_tcut = 0 obs_param_nml(49)%nodata = -9999. obs_param_nml(49)%varname = 'sfds' obs_param_nml(49)%units = '%' @@ -2106,15 +2104,13 @@ obs_param_nml(49)%adapt = 0 ! ! 50 = ASCAT_META_SM_D (ASCAT soil moisture descending) ! -! TO DO: What is pol of backscatter used in retrieval? -! TO DO: How deal w/ inc angle? -! http://oiswww.eumetsat.org/WEBOPS/eps-pg/ASCAT/ASCAT-PG-4ProdOverview.htm +! https://navigator.eumetsat.int/product/EO:EUM:DAT:METOP:SOMO25 obs_param_nml(50)%descr = 'ASCAT_META_SM_D' obs_param_nml(50)%orbit = 2 obs_param_nml(50)%pol = 0 obs_param_nml(50)%N_ang = 0 -obs_param_nml(50)%freq = 5.255e9 +obs_param_nml(50)%freq = 0 obs_param_nml(50)%FOV = 20. obs_param_nml(50)%FOV_units = 'km' obs_param_nml(50)%assim = .false. @@ -2122,8 +2118,8 @@ obs_param_nml(50)%scale = .false. obs_param_nml(50)%getinnov = .false. obs_param_nml(50)%RTM_ID = 0 obs_param_nml(50)%bias_Npar = 0 -obs_param_nml(50)%bias_trel = 864000 -obs_param_nml(50)%bias_tcut = 432000 +obs_param_nml(50)%bias_trel = 0 +obs_param_nml(50)%bias_tcut = 0 obs_param_nml(50)%nodata = -9999. obs_param_nml(50)%varname = 'sfds' obs_param_nml(50)%units = '%' @@ -2141,20 +2137,17 @@ obs_param_nml(50)%xcorr = 0.25 obs_param_nml(50)%ycorr = 0.25 obs_param_nml(50)%adapt = 0 -! -------------------------------------------------------------------- ! -------------------------------------------------------------------- ! ! 51 = ASCAT_METB_SM_A (ASCAT soil moisture ascending) ! -! ASCAT: VV-pol, incidence angle 25-65 deg -! for now keep N_ang=0, pol=0 -! - reichle, 30 Jun 2015 +! https://navigator.eumetsat.int/product/EO:EUM:DAT:METOP:SOMO25 obs_param_nml(51)%descr = 'ASCAT_METB_SM_A' obs_param_nml(51)%orbit = 1 obs_param_nml(51)%pol = 0 obs_param_nml(51)%N_ang = 0 -obs_param_nml(51)%freq = 5.255e9 +obs_param_nml(51)%freq = 0 obs_param_nml(51)%FOV = 20. obs_param_nml(51)%FOV_units = 'km' obs_param_nml(51)%assim = .false. @@ -2162,8 +2155,8 @@ obs_param_nml(51)%scale = .false. obs_param_nml(51)%getinnov = .false. obs_param_nml(51)%RTM_ID = 0 obs_param_nml(51)%bias_Npar = 0 -obs_param_nml(51)%bias_trel = 864000 -obs_param_nml(51)%bias_tcut = 432000 +obs_param_nml(51)%bias_trel = 0 +obs_param_nml(51)%bias_tcut = 0 obs_param_nml(51)%nodata = -9999. obs_param_nml(51)%varname = 'sfds' obs_param_nml(51)%units = '%' @@ -2185,15 +2178,13 @@ obs_param_nml(51)%adapt = 0 ! ! 52 = ASCAT_METB_SM_D (ASCAT soil moisture descending) ! -! TO DO: What is pol of backscatter used in retrieval? -! TO DO: How deal w/ inc angle? -! http://oiswww.eumetsat.org/WEBOPS/eps-pg/ASCAT/ASCAT-PG-4ProdOverview.htm +! https://navigator.eumetsat.int/product/EO:EUM:DAT:METOP:SOMO25 obs_param_nml(52)%descr = 'ASCAT_METB_SM_D' obs_param_nml(52)%orbit = 2 obs_param_nml(52)%pol = 0 obs_param_nml(52)%N_ang = 0 -obs_param_nml(52)%freq = 5.255e9 +obs_param_nml(52)%freq = 0 obs_param_nml(52)%FOV = 20. obs_param_nml(52)%FOV_units = 'km' obs_param_nml(52)%assim = .false. @@ -2201,8 +2192,8 @@ obs_param_nml(52)%scale = .false. obs_param_nml(52)%getinnov = .false. obs_param_nml(52)%RTM_ID = 0 obs_param_nml(52)%bias_Npar = 0 -obs_param_nml(52)%bias_trel = 864000 -obs_param_nml(52)%bias_tcut = 432000 +obs_param_nml(52)%bias_trel = 0 +obs_param_nml(52)%bias_tcut = 0 obs_param_nml(52)%nodata = -9999. obs_param_nml(52)%varname = 'sfds' obs_param_nml(52)%units = '%' @@ -2220,6 +2211,79 @@ obs_param_nml(52)%xcorr = 0.25 obs_param_nml(52)%ycorr = 0.25 obs_param_nml(52)%adapt = 0 +! -------------------------------------------------------------------- +! +! 53 = ASCAT_METB_SM_A (ASCAT soil moisture ascending) +! +! https://navigator.eumetsat.int/product/EO:EUM:DAT:METOP:SOMO25 + +obs_param_nml(51)%descr = 'ASCAT_METC_SM_A' +obs_param_nml(51)%orbit = 1 +obs_param_nml(51)%pol = 0 +obs_param_nml(51)%N_ang = 0 +obs_param_nml(51)%freq = 0 +obs_param_nml(51)%FOV = 20. +obs_param_nml(51)%FOV_units = 'km' +obs_param_nml(51)%assim = .false. +obs_param_nml(51)%scale = .false. +obs_param_nml(51)%getinnov = .false. +obs_param_nml(51)%RTM_ID = 0 +obs_param_nml(51)%bias_Npar = 0 +obs_param_nml(51)%bias_trel = 0 +obs_param_nml(51)%bias_tcut = 0 +obs_param_nml(51)%nodata = -9999. +obs_param_nml(51)%varname = 'sfds' +obs_param_nml(51)%units = '%' +obs_param_nml(51)%path = '/discover/nobackup/projects/gmao/merra/iau/merra_land/DATA/ASCAT_EUMETSAT/Metop_C/' +obs_param_nml(51)%name = 'M03-ASCA-ASCSMO02' +obs_param_nml(51)%scalepath = '' +obs_param_nml(51)%scalename = '' +obs_param_nml(51)%flistpath = '' +obs_param_nml(51)%flistname = '' +obs_param_nml(51)%errstd = .04 +obs_param_nml(51)%std_normal_max = 2.5 +obs_param_nml(51)%zeromean = .true. +obs_param_nml(51)%coarsen_pert = .false. +obs_param_nml(51)%xcorr = 0.25 +obs_param_nml(51)%ycorr = 0.25 +obs_param_nml(51)%adapt = 0 + +! ------------------- +! +! 54 = ASCAT_METB_SM_D (ASCAT soil moisture descending) +! +! https://navigator.eumetsat.int/product/EO:EUM:DAT:METOP:SOMO25 + +obs_param_nml(52)%descr = 'ASCAT_METC_SM_D' +obs_param_nml(52)%orbit = 2 +obs_param_nml(52)%pol = 0 +obs_param_nml(52)%N_ang = 0 +obs_param_nml(52)%freq = 0 +obs_param_nml(52)%FOV = 20. +obs_param_nml(52)%FOV_units = 'km' +obs_param_nml(52)%assim = .false. +obs_param_nml(52)%scale = .false. +obs_param_nml(52)%getinnov = .false. +obs_param_nml(52)%RTM_ID = 0 +obs_param_nml(52)%bias_Npar = 0 +obs_param_nml(52)%bias_trel = 0 +obs_param_nml(52)%bias_tcut = 0 +obs_param_nml(52)%nodata = -9999. +obs_param_nml(52)%varname = 'sfds' +obs_param_nml(52)%units = '%' +obs_param_nml(52)%path = '/discover/nobackup/projects/gmao/merra/iau/merra_land/DATA/ASCAT_EUMETSAT/Metop_C/' +obs_param_nml(52)%name = 'M03-ASCA-ASCSMO02' +obs_param_nml(52)%scalepath = '' +obs_param_nml(52)%scalename = '' +obs_param_nml(52)%flistpath = '' +obs_param_nml(52)%flistname = '' +obs_param_nml(52)%errstd = .04 +obs_param_nml(52)%std_normal_max = 2.5 +obs_param_nml(52)%zeromean = .true. +obs_param_nml(52)%coarsen_pert = .false. +obs_param_nml(52)%xcorr = 0.25 +obs_param_nml(52)%ycorr = 0.25 +obs_param_nml(52)%adapt = 0 ! -------------------------------------------------------------------- diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_glob_param.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_glob_param.F90 index 1183ab4c..278fb5e8 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_glob_param.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_glob_param.F90 @@ -44,7 +44,7 @@ module clsm_ensupd_glob_param ! total number of all obs species defined in namelist file ! (regardless of whether "assim" flag is true or false) - integer, parameter :: N_obs_species_nml = 52 + integer, parameter :: N_obs_species_nml = 54 ! ---------------------------------------------------------------------- ! diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index d6823758..05008303 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -7449,26 +7449,14 @@ subroutine read_obs( & end if - case ('ASCAT_META_SM_A', 'ASCAT_META_SM_D','ASCAT_METB_SM_A', 'ASCAT_METB_SM_D' ) + case ('ASCAT_META_SM_A', 'ASCAT_META_SM_D','ASCAT_METB_SM_A', 'ASCAT_METB_SM_D','ASCAT_METC_SM_A', 'ASCAT_METC_SM_D' ) - call read_obs_sm_ASCAT_EUMET( & + call read_obs_sm_ASCAT_EUMET( & work_path, exp_id, & date_time, dtstep_assim, N_catd, tile_coord, & tile_grid_d, N_tile_in_cell_ij, tile_num_in_cell_ij, & this_obs_param, & found_obs, tmp_obs, tmp_std_obs ) - ! Temporay hack to output if ascending/decending instead of tmp_std_obs - select case (trim(this_obs_param%descr)) - - case ('ASCAT_META_SM_A', 'ASCAT_METB_SM_A') - - tmp_std_obs(1:N_catd) = 1 - - case ('ASCAT_META_SM_D', 'ASCAT_METB_SM_D') - - tmp_std_obs(1:N_catd) = 2 - - end select ! scale observations to model climatology From 2711714dad18aabbab6f9080ecd737d01354f91d Mon Sep 17 00:00:00 2001 From: amfox37 Date: Tue, 28 Mar 2023 15:42:23 -0400 Subject: [PATCH 054/308] quick fix --- .../LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml | 120 +++++++++--------- 1 file changed, 60 insertions(+), 60 deletions(-) diff --git a/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml b/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml index f7f4e193..0c580bde 100644 --- a/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml +++ b/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml @@ -2217,36 +2217,36 @@ obs_param_nml(52)%adapt = 0 ! ! https://navigator.eumetsat.int/product/EO:EUM:DAT:METOP:SOMO25 -obs_param_nml(51)%descr = 'ASCAT_METC_SM_A' -obs_param_nml(51)%orbit = 1 -obs_param_nml(51)%pol = 0 -obs_param_nml(51)%N_ang = 0 -obs_param_nml(51)%freq = 0 -obs_param_nml(51)%FOV = 20. -obs_param_nml(51)%FOV_units = 'km' -obs_param_nml(51)%assim = .false. -obs_param_nml(51)%scale = .false. -obs_param_nml(51)%getinnov = .false. -obs_param_nml(51)%RTM_ID = 0 -obs_param_nml(51)%bias_Npar = 0 -obs_param_nml(51)%bias_trel = 0 -obs_param_nml(51)%bias_tcut = 0 -obs_param_nml(51)%nodata = -9999. -obs_param_nml(51)%varname = 'sfds' -obs_param_nml(51)%units = '%' -obs_param_nml(51)%path = '/discover/nobackup/projects/gmao/merra/iau/merra_land/DATA/ASCAT_EUMETSAT/Metop_C/' -obs_param_nml(51)%name = 'M03-ASCA-ASCSMO02' -obs_param_nml(51)%scalepath = '' -obs_param_nml(51)%scalename = '' -obs_param_nml(51)%flistpath = '' -obs_param_nml(51)%flistname = '' -obs_param_nml(51)%errstd = .04 -obs_param_nml(51)%std_normal_max = 2.5 -obs_param_nml(51)%zeromean = .true. -obs_param_nml(51)%coarsen_pert = .false. -obs_param_nml(51)%xcorr = 0.25 -obs_param_nml(51)%ycorr = 0.25 -obs_param_nml(51)%adapt = 0 +obs_param_nml(53)%descr = 'ASCAT_METC_SM_A' +obs_param_nml(53)%orbit = 1 +obs_param_nml(53)%pol = 0 +obs_param_nml(53)%N_ang = 0 +obs_param_nml(53)%freq = 0 +obs_param_nml(53)%FOV = 20. +obs_param_nml(53)%FOV_units = 'km' +obs_param_nml(53)%assim = .false. +obs_param_nml(53)%scale = .false. +obs_param_nml(53)%getinnov = .false. +obs_param_nml(53)%RTM_ID = 0 +obs_param_nml(53)%bias_Npar = 0 +obs_param_nml(53)%bias_trel = 0 +obs_param_nml(53)%bias_tcut = 0 +obs_param_nml(53)%nodata = -9999. +obs_param_nml(53)%varname = 'sfds' +obs_param_nml(53)%units = '%' +obs_param_nml(53)%path = '/discover/nobackup/projects/gmao/merra/iau/merra_land/DATA/ASCAT_EUMETSAT/Metop_C/' +obs_param_nml(53)%name = 'M03-ASCA-ASCSMO02' +obs_param_nml(53)%scalepath = '' +obs_param_nml(53)%scalename = '' +obs_param_nml(53)%flistpath = '' +obs_param_nml(53)%flistname = '' +obs_param_nml(53)%errstd = .04 +obs_param_nml(53)%std_normal_max = 2.5 +obs_param_nml(53)%zeromean = .true. +obs_param_nml(53)%coarsen_pert = .false. +obs_param_nml(53)%xcorr = 0.25 +obs_param_nml(53)%ycorr = 0.25 +obs_param_nml(53)%adapt = 0 ! ------------------- ! @@ -2254,36 +2254,36 @@ obs_param_nml(51)%adapt = 0 ! ! https://navigator.eumetsat.int/product/EO:EUM:DAT:METOP:SOMO25 -obs_param_nml(52)%descr = 'ASCAT_METC_SM_D' -obs_param_nml(52)%orbit = 2 -obs_param_nml(52)%pol = 0 -obs_param_nml(52)%N_ang = 0 -obs_param_nml(52)%freq = 0 -obs_param_nml(52)%FOV = 20. -obs_param_nml(52)%FOV_units = 'km' -obs_param_nml(52)%assim = .false. -obs_param_nml(52)%scale = .false. -obs_param_nml(52)%getinnov = .false. -obs_param_nml(52)%RTM_ID = 0 -obs_param_nml(52)%bias_Npar = 0 -obs_param_nml(52)%bias_trel = 0 -obs_param_nml(52)%bias_tcut = 0 -obs_param_nml(52)%nodata = -9999. -obs_param_nml(52)%varname = 'sfds' -obs_param_nml(52)%units = '%' -obs_param_nml(52)%path = '/discover/nobackup/projects/gmao/merra/iau/merra_land/DATA/ASCAT_EUMETSAT/Metop_C/' -obs_param_nml(52)%name = 'M03-ASCA-ASCSMO02' -obs_param_nml(52)%scalepath = '' -obs_param_nml(52)%scalename = '' -obs_param_nml(52)%flistpath = '' -obs_param_nml(52)%flistname = '' -obs_param_nml(52)%errstd = .04 -obs_param_nml(52)%std_normal_max = 2.5 -obs_param_nml(52)%zeromean = .true. -obs_param_nml(52)%coarsen_pert = .false. -obs_param_nml(52)%xcorr = 0.25 -obs_param_nml(52)%ycorr = 0.25 -obs_param_nml(52)%adapt = 0 +obs_param_nml(54)%descr = 'ASCAT_METC_SM_D' +obs_param_nml(54)%orbit = 2 +obs_param_nml(54)%pol = 0 +obs_param_nml(54)%N_ang = 0 +obs_param_nml(54)%freq = 0 +obs_param_nml(54)%FOV = 20. +obs_param_nml(54)%FOV_units = 'km' +obs_param_nml(54)%assim = .false. +obs_param_nml(54)%scale = .false. +obs_param_nml(54)%getinnov = .false. +obs_param_nml(54)%RTM_ID = 0 +obs_param_nml(54)%bias_Npar = 0 +obs_param_nml(54)%bias_trel = 0 +obs_param_nml(54)%bias_tcut = 0 +obs_param_nml(54)%nodata = -9999. +obs_param_nml(54)%varname = 'sfds' +obs_param_nml(54)%units = '%' +obs_param_nml(54)%path = '/discover/nobackup/projects/gmao/merra/iau/merra_land/DATA/ASCAT_EUMETSAT/Metop_C/' +obs_param_nml(54)%name = 'M03-ASCA-ASCSMO02' +obs_param_nml(54)%scalepath = '' +obs_param_nml(54)%scalename = '' +obs_param_nml(54)%flistpath = '' +obs_param_nml(54)%flistname = '' +obs_param_nml(54)%errstd = .04 +obs_param_nml(54)%std_normal_max = 2.5 +obs_param_nml(54)%zeromean = .true. +obs_param_nml(54)%coarsen_pert = .false. +obs_param_nml(54)%xcorr = 0.25 +obs_param_nml(54)%ycorr = 0.25 +obs_param_nml(54)%adapt = 0 ! -------------------------------------------------------------------- From 4dfc76083876cb9723018a5c5ea3360cf2c010e1 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Wed, 29 Mar 2023 14:28:01 -0400 Subject: [PATCH 055/308] fix typo --- src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml b/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml index 0c580bde..2f530379 100644 --- a/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml +++ b/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml @@ -2213,7 +2213,7 @@ obs_param_nml(52)%adapt = 0 ! -------------------------------------------------------------------- ! -! 53 = ASCAT_METB_SM_A (ASCAT soil moisture ascending) +! 53 = ASCAT_METC_SM_A (ASCAT soil moisture ascending) ! ! https://navigator.eumetsat.int/product/EO:EUM:DAT:METOP:SOMO25 @@ -2250,7 +2250,7 @@ obs_param_nml(53)%adapt = 0 ! ------------------- ! -! 54 = ASCAT_METB_SM_D (ASCAT soil moisture descending) +! 54 = ASCAT_METC_SM_D (ASCAT soil moisture descending) ! ! https://navigator.eumetsat.int/product/EO:EUM:DAT:METOP:SOMO25 From f0f6189b05a582c945d0d14b5972cabb78ffaa11 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Wed, 29 Mar 2023 19:40:27 -0400 Subject: [PATCH 056/308] write out to netcdf --- .../Run_get_model_and_obs_clim_stats.m | 27 +-- .../get_ij_ind_from_latlon.m | 2 +- .../get_model_and_obs_clim_stats.m | 60 +++---- .../obs_scaling_params/get_tile_num_for_obs.m | 2 + .../obs_scaling_params/write_netcdf_file.m | 154 ++++++++++++++++++ 5 files changed, 193 insertions(+), 52 deletions(-) create mode 100644 src/Applications/LDAS_App/util/inputs/obs_scaling_params/write_netcdf_file.m diff --git a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/Run_get_model_and_obs_clim_stats.m b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/Run_get_model_and_obs_clim_stats.m index 01817fd7..070fb597 100644 --- a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/Run_get_model_and_obs_clim_stats.m +++ b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/Run_get_model_and_obs_clim_stats.m @@ -13,25 +13,25 @@ run_months = [1:12 1:4]; %loop through 1:4 again to get complete pentads -%exp_path = '/smap1/qliu/output/SMAP_Nature_v8.3/NRv8.3_innov_RTMv4/'; -%exp_run = {'SMAP_NRv8.3inv_RTMv4'}; -%exp_path = '/hydro/qliu/WORK/output/L4_SM_SMAP/'; -%exp_run = {'SPL4SM_OL4001'}; -%exp_path = '/smap1/qliu/output/SMAP_Nature_v8.3/NRv8.3_innov/S1/'; -%exp_run = {'SMAP_NRv8.3_innov'}; -exp_path = '/discover/nobackup/amfox'; -exp_run = {'SPL4SM_OL7000'}; -domain = 'SMAP_EASEv2_M09_GLOBAL'; +% exp_path = '/discover/nobackup/amfox'; +% exp_run = {'SPL4SM_OL7000'}; +% domain = 'SMAP_EASEv2_M09_GLOBAL'; + +exp_path = '/discover/nobackup/amfox/Experiments/ASCAT_3Y_v2'; +exp_run = {'ASCAT_M36'}; +domain = 'SMAP_EASEv2_M36_GLOBAL'; %Start and end year for each month -start_year = [repmat(2016,1,3) repmat(2015,1,9) repmat(2016,1,3) repmat(2015,1,1)]; %corresp to [1:12 1 2] -end_year = [repmat(2017,1,3) repmat(2016,1,9) repmat(2017,1,3) repmat(2016,1,1)]; %runs till end of run_months for end_year +start_year = [repmat(2016,1,5) repmat(2015,1,7) repmat(2016,1,4)]; %corresp to [1:12 1 2] +end_year = [repmat(2017,1,5) repmat(2016,1,7) repmat(2017,1,4)]; %runs till end of run_months for end_year + %d orbit = [ 2]; %1=A, 2=D !DO *NOT* USE ASC AND DESC TOGETHER! %d pol = [ 1 2 ]; %1=H, 2=V %d inc_ang = [ 40.0 ]; prefix_out = 'L4SM_OL7000_SMAPL1CR17000_zscore_stats_'; +prefix_out = 'M36_zscore_stats_'; dt_assim = 3*60*60; % [seconds] land analysis time step, % same as LANDASSIM_DT in GEOSldas) @@ -42,13 +42,14 @@ %====== obs_param_fname = [exp_path, '/', exp_run{1}, '/output/', domain, '/rc_out/', ... - '/Y2015/M04/',exp_run{1}, '.ldas_obsparam.20150401_0000z.txt']; + '/Y2016/M04/',exp_run{1}, '.ldas_obsparam.20160401_0000z.txt']; %d var_name = {'Tb'}; % added to identify SMOS or SMAP from runs that include both species_names = {'SMAP_L1C_Tbh_A', 'SMAP_L1C_Tbv_A', 'SMAP_L1C_Tbh_D', 'SMAP_L1C_Tbv_D'}; -species_names = {'SMAP_L1C_Tbh_A'}; +species_names = {'ASCAT_META_SM_A','ASCAT_META_SM_D','ASCAT_METB_SM_A','ASCAT_METB_SM_D'}; +species_names = {'ASCAT_META_SM_A','ASCAT_META_SM_D'}; %====== %d if (length(orbit) > 1) diff --git a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_ij_ind_from_latlon.m b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_ij_ind_from_latlon.m index 8395aa89..e64d150f 100644 --- a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_ij_ind_from_latlon.m +++ b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_ij_ind_from_latlon.m @@ -2,7 +2,7 @@ function [i_ind,j_ind] = get_ij_ind_from_latlon( tile_grid, lat, lon) - if (strcmp(tile_grid.gridtype,'EASEv2_M36')) + if (strcmp(tile_grid.gridtype,'EASEv2-M36')) %row, col [j_indg,i_indg] = ... EASEv2_latlon2ind(lat,lon,'M36'); diff --git a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats.m b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats.m index 8a6b27dd..8100c46e 100644 --- a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats.m +++ b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats.m @@ -719,21 +719,24 @@ % Get the actual obs/model at the center point (for debugging only!!) tmp_Nf = N_species*Nf; %Number of actual fields before debug information -for i = 1:N_species +for i = 1:N_species % New species loop rr = tmp_Nf+((i*2)-1); data_out(rr,:) = o_data(1,:,w_days-floor(w_days/2.0))./N_data(1,:,w_days-floor(w_days/2.0)); rr = tmp_Nf+(i*2); data_out(rr,:) = m_data(1,:,w_days-floor(w_days/2.0))./N_data(1,:,w_days-floor(w_days/2.0)); -end - %d data_out(11,:,:) = o_data(1,:,:,w_days-floor(w_days/2.0))./N_data(1,:,:,w_days-floor(w_days/2.0)); - %d data_out(12,:,:) = m_data(1,:,:,w_days-floor(w_days/2.0))./N_data(1,:,:,w_days-floor(w_days/2.0)); - %d data_out(13,:,:) = o_data(2,:,:,w_days-floor(w_days/2.0))./N_data(2,:,:,w_days-floor(w_days/2.0)); - %d data_out(14,:,:) = m_data(2,:,:,w_days-floor(w_days/2.0))./N_data(2,:,:,w_days-floor(w_days/2.0)); - - % Get rid of NaN before writing a file + startrow = ((i-1)*5)+1; + endrow = i*5; + + % Get rid of NaN before writing a file data_out(isnan(data_out)) = nodata; + + + startidx = strfind(fname_out_base, 'z_score_clim//'); + endidx = startidx + length('z_score_clim//'); + + fname_out_base_s = [fname_out_base(1:startidx-1) 'z_score_clim/', char(species_names(i)),'_', fname_out_base(endidx:end)]; %lon_out(isnan(lon_out)) = nodata; %lat_out(isnan(lat_out)) = nodata; @@ -743,36 +746,24 @@ date_time = augment_date_time( -floor(w_days*(24*60*60)/2.0), date_time ); % always 365 files - DOY = date_time.dofyr; - if(is_leap_year(date_time.year) && DOY>=59) - DOY = DOY-1; - error('This code should never hit a leap year'); - end - fname_out = [fname_out_base, '_DOY', num2str(DOY,'%3.3d'), '.bin']; + fname_out = [fname_out_base_s, '_DOY', num2str(DOY,'%3.3d'), '.nc4']; % check whether output file exists - if (exist(fname_out)==2 && overwrite) - disp(['output file exists. overwriting', fname_out]) - elseif (exist(fname_out)==2 && ~overwrite) - disp(['output file exists. not overwriting. returning']) disp(['writing ', fname_out]) return - else - disp(['creating ', fname_out]) - end % compress data before writing in file. @@ -784,38 +775,31 @@ %tile_coord_tile_id_write = tile_coord_tile_id(idx_keep); - % write output for each DOY, sorted by all tiles - - if print_each_DOY - - write_seqbin_file(fname_out, lon_out, lat_out, ... - inc_angle, data_out(:,:), int_Asc, 0, ... %instead of writing the version#, write Ndata_min=0 + % write output for each DOY, sorted by all tile + if print_each_DOY + write_netcdf_file(fname_out, lon_out, lat_out, ... + inc_angle, data_out(startrow:endrow,:), int_Asc, 0, ... %instead of writing the version#, write Ndata_min=0 start_time, end_time, overwrite, ... - N_out_fields, write_ind_latlon, 'scaling',... + Nf, write_ind_latlon, 'scaling',... tile_coord_tile_id) else - % if DOY is at middle of pentad, then copy the DOY to a pentad file % DOY = pentad*5 - 2; ==> pentad = (DOY + 2)/5; - pentad = (DOY + 2)/5; - if mod((DOY + 2),5) == 0 - - write_seqbin_file(fname_out, lon_out, lat_out, ... - inc_angle, data_out(:,:), int_Asc, 0, ... + write_netcdf_file(fname_out, lon_out, lat_out, ... + inc_angle, data_out(startrow:endrow,:), int_Asc, 0, ... start_time, end_time, overwrite, ... - N_out_fields, write_ind_latlon, 'scaling',... + Nf, write_ind_latlon, 'scaling',... tile_coord_tile_id) - fname_out_p = [fname_out_base_p, '_p', num2str(pentad,'%2.2d'), '.bin']; - copyfile(fname_out,fname_out_p); - end end +end % new species loop + %clear idx_keep lon_out_write lat_out_write data_out_write tile_coord_tile_id_write % shift the window by one day and make room for the next day at the end diff --git a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_tile_num_for_obs.m b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_tile_num_for_obs.m index ed1e9b8a..73f68c8f 100644 --- a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_tile_num_for_obs.m +++ b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_tile_num_for_obs.m @@ -67,6 +67,8 @@ % map from i_ind, j_ind to tile_num if ( ~isempty(strfind(tile_grid.gridtype, 'EASE_M')) || ... + ~isempty(strfind(tile_grid.gridtype, 'EASE-M')) || ... + ~isempty(strfind(tile_grid.gridtype, 'EASEv2-M')) || ... ~isempty(strfind(tile_grid.gridtype, 'EASEv2_M')) ) % ASSUMPTION: tiles match EASE or EASEv2 grid cells exactly diff --git a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/write_netcdf_file.m b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/write_netcdf_file.m new file mode 100644 index 00000000..221efe4a --- /dev/null +++ b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/write_netcdf_file.m @@ -0,0 +1,154 @@ + function [] = write_netcdf_file(fname, colind, rowind,... + av_angle_bin, data, asc_flag,... + version, ... + start_time, end_time, overwrite, N_out_fields, ... + write_ind_latlon, data_product,... + tile_id) %last argument is optional + + int_precision = 'NC_INT'; % precision of fortran tag + float_precision = 'NC_DOUBLE'; % precision of data in input file + + % check dimensions + if size(data,1)~=N_out_fields + error('ERROR: size of data incompatible with N_out_fields') + end + + % check for presence of optional input "overwrite" + if ~exist('overwrite','var') + overwrite = 0; % default: do NOT overwrite existing files + end + + % check if file exists + if exist(fname,'file') + if overwrite==0 + disp(['RETURNING!!! -- NOT OVERWRITING EXISTING FILE ', fname]) + return + else + disp(['OVERWRITING ', fname]) + end + else + disp(['writing ', fname]) + end + + % Calculate tmp_start_time tmp_end_time in days since January 1 1950 + d = datetime(start_time.year, start_time.month, start_time.day, start_time.hour, start_time.min, start_time.sec); + % Convert to serial date number + serialNum = datenum(d); + % Subtract serial date number of January 1, 1950 + daysSince1950 = serialNum - datenum('January 1, 1950'); + tmp_start_time = daysSince1950; + + d = datetime(end_time.year, end_time.month, end_time.day, end_time.hour, end_time.min, end_time.sec); + % Convert to serial date number + serialNum = datenum(d); + % Subtract serial date number of January 1, 1950 + daysSince1950 = serialNum - datenum('January 1, 1950'); + tmp_end_time = daysSince1950; + + % determine number of grid cells ; further check dimensions + N_grid = size(data,2); + N_angle= 1; + N_pentad = 1; + + if (strcmp(write_ind_latlon,'latlon_id') && nargin == 14) + if( size(tile_id,1) ~= N_grid ) + error('tile_id dimensions ??') + end + if ( size(tile_id,2) > 1) + disp(['# subgridcells per gridcell: ',num2str(size(tile_id,2))]); + end + end + +% create netCDF file +netcdf.setDefaultFormat('FORMAT_NETCDF4'); +ncid = netcdf.create(fname, 'NETCDF4'); + +% define dimensions +dimid_grid = netcdf.defDim(ncid, 'grid', N_grid); +dimid_angle = netcdf.defDim(ncid, 'angle', N_angle); +dimid_tile = netcdf.defDim(ncid, 'tile', size(tile_id,2)); +dimid_pentad = netcdf.defDim(ncid, 'pentad', N_pentad); + +% define variables +varid_asc_flag = netcdf.defVar(ncid, 'asc_flag', int_precision, []); +varid_version = netcdf.defVar(ncid, 'version', int_precision, []); +varid_pentad = netcdf.defVar(ncid, 'pentad', int_precision, [dimid_pentad]); + +varid_start_time = netcdf.defVar(ncid, 'start_time', float_precision, [dimid_pentad]); +netcdf.putAtt(ncid, varid_start_time, 'standard_name','start time'); +netcdf.putAtt(ncid, varid_start_time, 'long_name','start time'); +netcdf.putAtt(ncid, varid_start_time, 'axis','T'); +netcdf.putAtt(ncid, varid_start_time, 'units','days since 1950-01-01 00:00:00.0 +0000'); + +varid_end_time = netcdf.defVar(ncid, 'end_time',float_precision, [dimid_pentad]); +netcdf.putAtt(ncid, varid_end_time, 'standard_name','end time'); +netcdf.putAtt(ncid, varid_end_time, 'long_name','end time'); +netcdf.putAtt(ncid, varid_end_time, 'axis','T'); +netcdf.putAtt(ncid, varid_end_time, 'units','days since 1950-01-01 00:00:00.0 +0000'); + +varid_N_grid = netcdf.defVar(ncid, 'N_grid', int_precision, []); +varid_N_angle = netcdf.defVar(ncid, 'N_angle', int_precision, []); +varid_tile_id = netcdf.defVar(ncid, 'tile_id', int_precision, [dimid_grid dimid_tile]); +varid_av_angle_bin = netcdf.defVar(ncid, 'av_angle_bin', float_precision, [dimid_angle]); +varid_colind = netcdf.defVar(ncid, 'colind', float_precision, [dimid_grid]); +varid_rowind = netcdf.defVar(ncid, 'rowind', float_precision, [dimid_grid]); + +% Create a new group called 'data' +groupname = 'data'; +grpid = netcdf.defGrp(ncid,groupname); + +varid_om = netcdf.defVar(grpid, 'o_mean', float_precision, [dimid_grid dimid_pentad]); +varid_ov = netcdf.defVar(grpid, 'o_std', float_precision, [dimid_grid dimid_pentad]); +varid_mm = netcdf.defVar(grpid, 'm_mean', float_precision, [dimid_grid dimid_pentad]); +varid_mv = netcdf.defVar(grpid, 'm_std', float_precision, [dimid_grid dimid_pentad]); +varid_ndata = netcdf.defVar(grpid, 'n_data', float_precision, [dimid_grid dimid_pentad]); + +% end define mode +netcdf.endDef(ncid); + +% write data +netcdf.putVar(ncid, varid_asc_flag, asc_flag); +netcdf.putVar(ncid, varid_version, version); +netcdf.putVar(ncid, varid_pentad, start_time.pentad); +netcdf.putVar(ncid, varid_start_time, tmp_start_time); +netcdf.putVar(ncid, varid_end_time, tmp_end_time); +netcdf.putVar(ncid, varid_N_grid, N_grid); +netcdf.putVar(ncid, varid_N_angle, N_angle); + +if (~(strcmp(data_product,'scaling') && strcmp(write_ind_latlon,'latlon_id') && nargin == 14)) + netcdf.putVar(ncid, varid_tile_id, tile_id); +else + netcdf.putVar(ncid, varid_tile_id, permute(tile_id, [2 1])); +end + +netcdf.putVar(ncid, varid_av_angle_bin, squeeze(av_angle_bin(:))); + + if (N_grid >= 1) + +netcdf.putVar(ncid, varid_colind, colind); +netcdf.putVar(ncid, varid_rowind, rowind); + + netcdf.putVar(grpid,varid_om,data(1,:)); +netcdf.putVar(grpid,varid_ov,data(2,:)); +netcdf.putVar(grpid,varid_mm,data(3,:)); +netcdf.putVar(grpid,varid_mv,data(4,:)); +netcdf.putVar(grpid,varid_ndata,data(5,:)); + + else + netcdf.putVar(ncid, varid_colind, 0.0); +netcdf.putVar(ncid, varid_rowind, 0.0); + + netcdf.putVar(grpid,varid_om,-999.0); +netcdf.putVar(grpid,varid_ov,-999.0); +netcdf.putVar(grpid,varid_mm,-999.0); +netcdf.putVar(grpid,varid_mv,-999.0); +netcdf.putVar(grpid,varid_ndata,-999.0); + end + +% close netCDF file +netcdf.close(ncid); + + end + + + From 52cf2b3c31d19bc988680faa17b6f948fcff7ea0 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Mon, 17 Apr 2023 13:43:58 -0600 Subject: [PATCH 057/308] temporary test reader --- .../LDAS_App/test_netcdf_reader.F90 | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 src/Applications/LDAS_App/test_netcdf_reader.F90 diff --git a/src/Applications/LDAS_App/test_netcdf_reader.F90 b/src/Applications/LDAS_App/test_netcdf_reader.F90 new file mode 100644 index 00000000..a8a410c9 --- /dev/null +++ b/src/Applications/LDAS_App/test_netcdf_reader.F90 @@ -0,0 +1,80 @@ +program read_netcdf + use netcdf + implicit none + + integer :: ncid, varid, dimid, status, i, j + integer :: grid, angle, tile, pentad + integer :: asc_flag, version, N_grid, N_angle + real(kind=8) :: start_time(pentad), end_time(pentad) + real(kind=8) :: o_mean(pentad, grid), o_std(pentad, grid) + real(kind=8) :: m_mean(pentad, grid), m_std(pentad, grid) + real(kind=8) :: n_data(pentad, grid), av_angle_bin(angle) + real(kind=8) :: colind(grid), rowind(grid), lon(grid), lat(grid) + + ! Open the netCDF file + status = nf_open("filename.nc", nf_nowrite, ncid) + if (status /= nf90_noerr) then + write(*,*) "Error opening netCDF file" + stop + endif + + ! Get dimension IDs + status = nf_inq_dimid(ncid, "grid", dimid) + status = nf_inq_dimlen(ncid, dimid, grid) + status = nf_inq_dimid(ncid, "angle", dimid) + status = nf_inq_dimlen(ncid, dimid, angle) + status = nf_inq_dimid(ncid, "tile", dimid) + status = nf_inq_dimlen(ncid, dimid, tile) + status = nf_inq_dimid(ncid, "pentad", dimid) + status = nf_inq_dimlen(ncid, dimid, pentad) + + ! Get variable IDs + status = nf_inq_varid(ncid, "asc_flag", varid) + status = nf_inq_varid(ncid, "version", varid) + status = nf_inq_varid(ncid, "pentad", varid) + status = nf_inq_varid(ncid, "start_time", varid) + status = nf_inq_varid(ncid, "end_time", varid) + status = nf_inq_varid(ncid, "N_grid", varid) + status = nf_inq_varid(ncid, "N_angle", varid) + status = nf_inq_varid(ncid, "obs_num", varid) + status = nf_inq_varid(ncid, "av_angle_bin", varid) + status = nf_inq_varid(ncid, "colind", varid) + status = nf_inq_varid(ncid, "rowind", varid) + status = nf_inq_varid(ncid, "lon", varid) + status = nf_inq_varid(ncid, "lat", varid) + status = nf_inq_varid(ncid, "o_mean", varid) + status = nf_inq_varid(ncid, "o_std", varid) + status = nf_inq_varid(ncid, "m_mean", varid) + status = nf_inq_varid(ncid, "m_std", varid) + status = nf_inq_varid(ncid, "n_data", varid) + + ! Read variables + status = nf_get_var(ncid, nf_inq_varid(ncid, "asc_flag", varid), asc_flag) + status = nf_get_var(ncid, nf_inq_varid(ncid, "version", varid), version) + status = nf_get_var(ncid, nf_inq_varid(ncid, "pentad", varid), pentad) + status = nf_get_var(ncid, nf_inq_varid(ncid, "start_time", varid), start_time) + status = nf_get_var(ncid, nf_inq_varid(ncid, "end_time", varid), end_time) + status = nf_get_var(ncid, nf_inq_varid(ncid, "N_grid", varid), N_grid) + status = nf_get_var(ncid, nf_inq_varid(ncid, "N_angle", varid), N_angle) + status = nf_get_var(ncid, nf_inq_varid(ncid, "obs_num", varid), obs_num) + status = nf_get_var(ncid, nf_inq_varid(ncid, "av_angle_bin", varid), av_angle_bin) + status = nf_get_var(ncid, nf_inq_varid(ncid, "colind", varid), colind) + status = nf_get_var(ncid, nf_inq_varid(ncid, "rowind", varid), rowind) + status = nf_get_var(ncid, nf_inq_varid(ncid, "lon", varid), lon) + status = nf_get_var(ncid, nf_inq_varid(ncid, "lat", varid), lat) + status = nf_get_var(ncid, nf_inq_varid(ncid, "o_mean", varid), o_mean) + status = nf_get_var(ncid, nf_inq_varid(ncid, "o_std", varid), o_std) + status = nf_get_var(ncid, nf_inq_varid(ncid, "m_mean", varid), m_mean) + status = nf_get_var(ncid, nf_inq_varid(ncid, "m_std", varid), m_std) + status = nf_get_var(ncid, nf_inq_varid(ncid, "n_data", varid), n_data) + + ! Close the netCDF file + status = nf_close(ncid) + + ! Print some information + write(,) "Number of grids: ", grid + write(,) "Number of pentads: ", pentad + write(,) "Start time for pentad 1: ", start_time(1) + write(,) "End time for pentad 1: ", end_time(1) + + end program read_netcdf \ No newline at end of file From 0736db5b7a6030085f1ad4d33f8b7833ce3e1e98 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Mon, 17 Apr 2023 16:14:50 -0600 Subject: [PATCH 058/308] add obs lat, lon, time to EUMETSAT reader output --- .../clsm_ensupd_read_obs.F90 | 77 +++++++++++++------ 1 file changed, 52 insertions(+), 25 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 05008303..b0f25fc3 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -1556,7 +1556,7 @@ subroutine read_obs_sm_ASCAT_EUMET( & date_time, dtstep_assim, N_catd, tile_coord, & tile_grid_d, N_tile_in_cell_ij, tile_num_in_cell_ij, & this_obs_param, & - found_obs, sm_ASCAT, std_sm_ASCAT ) + found_obs, ASCAT_sm, ASCAT_sm_std , ASCAT_lon, ASCAT_lat, ASCAT_time) !--------------------------------------------------------------------- ! @@ -1594,10 +1594,14 @@ subroutine read_obs_sm_ASCAT_EUMET( & type(obs_param_type), intent(in) :: this_obs_param ! outputs: - - real, intent(out), dimension(N_catd) :: sm_ASCAT ! wetness range 0-1 - real, intent(out), dimension(N_catd) :: std_sm_ASCAT + logical, intent(out) :: found_obs + + real, intent(out), dimension(N_catd) :: ASCAT_sm ! wetness range 0-1 + real, intent(out), dimension(N_catd) :: ASCAT_sm_std + real, intent(out), dimension(N_catd) :: ASCAT_lon, ASCAT_lat + real*8, intent(out), dimension(N_catd) :: ASCAT_time ! J2000 seconds + ! --------------- @@ -1610,6 +1614,7 @@ subroutine read_obs_sm_ASCAT_EUMET( & ! Will need to be updated if using EUMETSAT BUFR files integer, parameter :: ae_time_offset = 3600 ! 60 minutes in seconds + character(4), parameter :: J2000_epoch_id = 'TT12' ! see date_time_util.F90 character(4) :: DDHH character(6) :: YYYYMM @@ -1632,12 +1637,14 @@ subroutine read_obs_sm_ASCAT_EUMET( & integer :: idate,iret,kk integer :: ireadmg,ireadsb character(8) :: subset - real, dimension(:), allocatable :: tmp1_lon, tmp1_lat, tmp1_obs + real, dimension(:), allocatable :: tmp1_lon, tmp1_lat, tmp1_obs + real*8, dimension(:), allocatable :: tmp1_jtime - real, dimension(:), pointer :: tmp_obs, tmp_lat, tmp_lon - integer, dimension(:), pointer :: tmp_tile_num + real, dimension(:), pointer :: tmp_obs, tmp_lat, tmp_lon + real*8, dimension(:), pointer :: tmp_jtime + integer, dimension(:), pointer :: tmp_tile_num - integer, dimension(N_catd) :: N_obs_in_tile + integer, dimension(N_catd) :: N_obs_in_tile real, parameter :: tol = 1e-2 @@ -1646,7 +1653,7 @@ subroutine read_obs_sm_ASCAT_EUMET( & ! ------------------------------------------------------------------- - nullify( tmp_obs, tmp_lat, tmp_lon, tmp_tile_num ) + nullify( tmp_obs, tmp_lat, tmp_lon, tmp_tile_num, tmp_jtime ) ! --------------- @@ -1747,6 +1754,7 @@ subroutine read_obs_sm_ASCAT_EUMET( & allocate(tmp1_lon(max_rec)) allocate(tmp1_lat(max_rec)) allocate(tmp1_obs(max_rec)) + allocate(tmp1_jtime(max_rec)) if (N_files>0) then @@ -1813,7 +1821,10 @@ subroutine read_obs_sm_ASCAT_EUMET( & !call ufbint(lnbufr,tmp_data,1,1,iret,'SNOC') ! snow cover !call ufbint(lnbufr,tmp_data,1,1,iret,'FLSF') ! frozen land fraction - N_tmp = N_tmp + 1 + N_tmp = N_tmp + 1 ! Passed all QC + + tmp1_jtime(N_tmp) = datetime_to_J2000seconds( date_time_tmp, J2000_epoch_id ) + call ufbint(lnbufr,tmp_vdata,4,1,iret,'CLATH CLONH SSOM EESSM') tmp1_lat(N_tmp) = tmp_vdata(1) tmp1_lon(N_tmp) = tmp_vdata(2) @@ -1846,14 +1857,17 @@ subroutine read_obs_sm_ASCAT_EUMET( & end if + allocate(tmp_jtime(N_tmp)) allocate(tmp_lon(N_tmp)) allocate(tmp_lat(N_tmp)) allocate(tmp_obs(N_tmp)) + tmp_jtime = tmp1_jtime(1:N_tmp) tmp_lon = tmp1_lon(1:N_tmp) tmp_lat = tmp1_lat(1:N_tmp) tmp_obs = tmp1_obs(1:N_tmp) + deallocate(tmp1_jtime) deallocate(tmp1_lon) deallocate(tmp1_lat) deallocate(tmp1_obs) @@ -1888,7 +1902,11 @@ subroutine read_obs_sm_ASCAT_EUMET( & ! 3.) compute super-obs for each tile from all obs w/in that tile ! (also eliminate observations that are not in domain) - sm_ASCAT = 0. + ASCAT_sm = 0. + ASCAT_lon = 0. + ASCAT_lat = 0. + ASCAT_time = 0.0D0 + N_obs_in_tile = 0 do i=1,N_tmp @@ -1897,25 +1915,41 @@ subroutine read_obs_sm_ASCAT_EUMET( & if (ind>0) then ! this step eliminates obs outside domain - sm_ASCAT(ind) = sm_ASCAT(ind) + tmp_obs(i) + ASCAT_sm(ind) = ASCAT_sm(ind) + tmp_obs(i) + ASCAT_lon(ind) = ASCAT_lon(ind) + tmp_lon(i) + ASCAT_lat(ind) = ASCAT_lat(ind) + tmp_lat(i) + ASCAT_time(ind) = ASCAT_time(ind) + tmp_jtime(i) - N_obs_in_tile(ind) = N_obs_in_tile(ind) + 1 + N_obs_in_tile(ind) = N_obs_in_tile(ind) + 1 end if end do + + ! -------------------------------- + ! normalize do i=1,N_catd + + ! set observation error standard deviation + ASCAT_sm_std(i) = this_obs_param%errstd if (N_obs_in_tile(i)>1) then - sm_ASCAT(i) = sm_ASCAT(i)/real(N_obs_in_tile(i)) + ASCAT_sm(i) = ASCAT_sm(i)/real(N_obs_in_tile(i)) + ASCAT_lon(i) = ASCAT_lon(i)/real(N_obs_in_tile(i)) + ASCAT_lat(i) = ASCAT_lat(i)/real(N_obs_in_tile(i)) + ASCAT_time(i) = ASCAT_time(i)/real(N_obs_in_tile(i),kind(0.0D0)) elseif (N_obs_in_tile(i)==0) then - sm_ASCAT(i) = this_obs_param%nodata + ASCAT_sm(i) = this_obs_param%nodata + ASCAT_lon(i) = this_obs_param%nodata + ASCAT_lat(i) = this_obs_param%nodata + ASCAT_time(i) = real(this_obs_param%nodata,kind(0.0D0)) + ASCAT_sm_std(i) = this_obs_param%nodata end if @@ -1925,15 +1959,6 @@ subroutine read_obs_sm_ASCAT_EUMET( & if (associated(tmp_tile_num)) deallocate(tmp_tile_num) - ! -------------------------------- - - ! set observation error standard deviation - - do i=1,N_catd - std_sm_ASCAT(i) = this_obs_param%errstd - enddo - ! -------------------------------- - if (any(N_obs_in_tile>0)) then found_obs = .true. @@ -1951,6 +1976,8 @@ subroutine read_obs_sm_ASCAT_EUMET( & if (associated(tmp_obs)) deallocate(tmp_obs) if (associated(tmp_lon)) deallocate(tmp_lon) if (associated(tmp_lat)) deallocate(tmp_lat) + if (associated(tmp_jtime)) deallocate(tmp_jtime) + end subroutine read_obs_sm_ASCAT_EUMET @@ -7456,7 +7483,7 @@ subroutine read_obs( & date_time, dtstep_assim, N_catd, tile_coord, & tile_grid_d, N_tile_in_cell_ij, tile_num_in_cell_ij, & this_obs_param, & - found_obs, tmp_obs, tmp_std_obs ) + found_obs, tmp_obs, tmp_std_obs , tmp_lon, tmp_lat, tmp_time) ! scale observations to model climatology From ebc4e6c2189c045a069ed53a8d09bc3486c79fe1 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Wed, 19 Apr 2023 13:20:18 -0600 Subject: [PATCH 059/308] add scale_obs_sfmc_zscore template --- .../clsm_ensupd_read_obs.F90 | 188 +++++++++++++++++- 1 file changed, 183 insertions(+), 5 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index b0f25fc3..4a2b0266 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -1556,7 +1556,7 @@ subroutine read_obs_sm_ASCAT_EUMET( & date_time, dtstep_assim, N_catd, tile_coord, & tile_grid_d, N_tile_in_cell_ij, tile_num_in_cell_ij, & this_obs_param, & - found_obs, ASCAT_sm, ASCAT_sm_std , ASCAT_lon, ASCAT_lat, ASCAT_time) + found_obs, ASCAT_sm, ASCAT_sm_std, ASCAT_lon, ASCAT_lat, ASCAT_time) !--------------------------------------------------------------------- ! @@ -1976,7 +1976,7 @@ subroutine read_obs_sm_ASCAT_EUMET( & if (associated(tmp_obs)) deallocate(tmp_obs) if (associated(tmp_lon)) deallocate(tmp_lon) if (associated(tmp_lat)) deallocate(tmp_lat) - if (associated(tmp_jtime)) deallocate(tmp_jtime) + if (associated(tmp_jtime)) deallocate(tmp_jtime) end subroutine read_obs_sm_ASCAT_EUMET @@ -7483,7 +7483,7 @@ subroutine read_obs( & date_time, dtstep_assim, N_catd, tile_coord, & tile_grid_d, N_tile_in_cell_ij, tile_num_in_cell_ij, & this_obs_param, & - found_obs, tmp_obs, tmp_std_obs , tmp_lon, tmp_lat, tmp_time) + found_obs, tmp_obs, tmp_std_obs, tmp_lon, tmp_lat, tmp_time) ! scale observations to model climatology @@ -7491,8 +7491,8 @@ subroutine read_obs( & scaled_obs = .true. - call scale_obs_sfmc_cdf( N_catd, tile_coord, this_obs_param, & - tmp_obs, tmp_std_obs ) + call scale_obs_sfmc_zscore( N_catd, tile_coord, this_obs_param, & + tmp_obs, tmp_std_obs, tmp_lon, tmp_lat, tmp_time ) end if @@ -8109,6 +8109,184 @@ subroutine scale_obs_tskin_zscore( N_catd, tile_coord, & end subroutine scale_obs_tskin_zscore + + ! ***************************************************************** + + subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & + date_time, this_obs_param, tmp_obs, & + tmp_std_obs, tmp_lon, tmp_lat, tmp_time) + +! scale tskin obs to model climatology via standard-normal-deviate (zscore) +! scaling +! +! use matlab functions "get_cdf_match_AMSR.m" and "get_model_and_obs_stats.m" +! to create input scaling files +! +! IMPORTANT: Make sure that model and obs data are in the SAME UNITS prior +! to generating the input scaling files with the matlab routines. + +! reichle, 14 Oct 2005 +! +! reichle, 22 Nov 2011 - renamed subroutine, minor clean-up, added comments + +implicit none + +integer, intent(in) :: N_catd + +real, intent(in), dimension(N_catd) :: tmp_lon, tmp_lat +real*8, intent(in), dimension(N_catd) :: tmp_time ! J2000 seconds + +type(tile_coord_type), dimension(:), pointer :: tile_coord ! input + +type(date_time_type), intent(in) :: date_time + +type(obs_param_type), intent(in) :: this_obs_param + +! inout + +real, intent(inout), dimension(N_catd) :: tmp_obs +real, intent(inout), dimension(N_catd) :: tmp_std_obs + +! ---------------------------------------------------------- + +! local variables + +real, parameter :: no_data_stats = -9999. + +real, parameter :: tol = 1e-2 + +character(3), dimension(12) :: month_string = (/ & + 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', & + 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' /) + +! ------------------- + +character(300) :: fname + +character(2) :: tmpchar2 + +integer :: i, ind, N_sclprm + +real :: tmpreal + +integer, dimension(:), allocatable :: sclprm_tile_id + +real, dimension(:), allocatable :: sclprm_lon, sclprm_lat +real, dimension(:), allocatable :: sclprm_mean_obs, sclprm_std_obs +real, dimension(:), allocatable :: sclprm_mean_mod, sclprm_std_mod + +character(len=*), parameter :: Iam = ' scale_obs_sfmc_zscore' +character(len=400) :: err_msg + +! ------------------------------------------------------------------ + +write (tmpchar2, '(i2.2)') date_time%hour + +! read scaling parameters from file + +fname = trim(this_obs_param%scalepath) // '/' // & + trim(this_obs_param%scalename) // & + month_string(date_time% ) // '_' // & + tmpchar2 // 'z.bin' + +if (logit) write (logunit,*) 'scaling obs species ', this_obs_param%species, ':' +if (logit) write (logunit,'(400A)') ' reading ', trim(fname) + +open(10, file=fname, form='unformatted',convert='big_endian', action='read') + +read(10) N_sclprm + +allocate(sclprm_tile_id(N_sclprm)) +allocate(sclprm_lon(N_sclprm)) +allocate(sclprm_lat(N_sclprm)) +allocate(sclprm_mean_obs(N_sclprm)) +allocate(sclprm_std_obs(N_sclprm)) +allocate(sclprm_mean_mod(N_sclprm)) +allocate(sclprm_std_mod(N_sclprm)) + +read(10) sclprm_tile_id +read(10) sclprm_lon +read(10) sclprm_lat +read(10) sclprm_mean_obs +read(10) sclprm_std_obs +read(10) sclprm_mean_mod +read(10) sclprm_std_mod + +close(10,status='keep') + +! minimal consistency check + +if (N_catd>N_sclprm) then + call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'something is wrong') +end if + +! -------------------------------------------------------------- + +! scale observations (at this point all obs are of type +! isccp_tskin_gswp2_v1 because of the way the subroutine is called +! from subroutine read_obs()) + +do i=1,N_catd + + ! check for no-data-values in observation (any neg Tskin is no_data) + + if (tmp_obs(i)>=0.) then + + ! find ind for current tile id in scaling parameters + + do ind=1,N_sclprm + + if (sclprm_tile_id(ind)==tile_coord(i)%tile_id) exit + + end do + + ! sanity check (against accidental use of wrong tile space) + + if ( abs(tile_coord(i)%com_lat-sclprm_lat(ind))>tol .or. & + abs(tile_coord(i)%com_lon-sclprm_lon(ind))>tol ) then + err_msg = 'something wrong' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + end if + + ! check for no-data-values in observation and fit parameters + ! (any negative number could be no-data-value for observations) + + if ( sclprm_mean_obs(ind)>0. .and. & + sclprm_mean_mod(ind)>0. .and. & + sclprm_std_obs(ind)>=0. .and. & + sclprm_std_mod(ind)>=0. ) then + + ! scale via standard normal deviates + + tmpreal = sclprm_std_mod(ind)/sclprm_std_obs(ind) + + tmp_obs(i) = sclprm_mean_mod(ind) & + + tmpreal*(tmp_obs(i)-sclprm_mean_obs(ind)) + + ! scale observation error std + + tmp_std_obs(i) = tmpreal*tmp_std_obs(i) + + else + + tmp_obs(i) = this_obs_param%nodata + + end if + + end if + +end do + +deallocate(sclprm_tile_id) +deallocate(sclprm_lon) +deallocate(sclprm_lat) +deallocate(sclprm_mean_obs) +deallocate(sclprm_std_obs) +deallocate(sclprm_mean_mod) +deallocate(sclprm_std_mod) + +end subroutine scale_obs_sfmc_zscore + ! ******************************************************************************** subroutine scale_obs_Tb_zscore( N_catd, tile_coord, date_time, this_obs_param, & From d4b4d56042bb2841505dc9b0d219e35da4225525 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Wed, 19 Apr 2023 15:57:20 -0400 Subject: [PATCH 060/308] fix typoes --- .../GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 4a2b0266..17b5d52c 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -7491,8 +7491,9 @@ subroutine read_obs( & scaled_obs = .true. - call scale_obs_sfmc_zscore( N_catd, tile_coord, this_obs_param, & - tmp_obs, tmp_std_obs, tmp_lon, tmp_lat, tmp_time ) + call scale_obs_sfmc_zscore( N_catd, tile_coord, & + date_time, this_obs_param, tmp_obs, & + tmp_std_obs, tmp_lon, tmp_lat, tmp_time ) end if @@ -8186,7 +8187,7 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & fname = trim(this_obs_param%scalepath) // '/' // & trim(this_obs_param%scalename) // & - month_string(date_time% ) // '_' // & + month_string(date_time%month) // '_' // & tmpchar2 // 'z.bin' if (logit) write (logunit,*) 'scaling obs species ', this_obs_param%species, ':' From 8e43a4b463f69a5085b14cf41a50cf1e6c1d3d14 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Thu, 20 Apr 2023 15:59:37 -0600 Subject: [PATCH 061/308] add netcdf sclprm read --- .../clsm_ensupd_read_obs.F90 | 76 ++++++++++++------- 1 file changed, 50 insertions(+), 26 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 17b5d52c..4044d3cc 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -8130,6 +8130,7 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & ! ! reichle, 22 Nov 2011 - renamed subroutine, minor clean-up, added comments +use netcdf implicit none integer, intent(in) :: N_catd @@ -8148,6 +8149,16 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & real, intent(inout), dimension(N_catd) :: tmp_obs real, intent(inout), dimension(N_catd) :: tmp_std_obs +! ---------------------------------------------------------- + ! Grid and netcdf parameters (might want to read these from netCDF file?) + +integer, parameter :: N_lon = 1440 +integer, parameter :: N_lat = 720 +real, parameter :: ll_lon = -180.0000 +real, parameter :: ll_lat = -90.0000 +real, parameter :: dlon = 0.25 +real, parameter :: dlat = 0.25 + ! ---------------------------------------------------------- ! local variables @@ -8166,15 +8177,19 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & character(2) :: tmpchar2 -integer :: i, ind, N_sclprm +integer :: i, ind, pp +integer :: ncid, varid, ierr +integer :: pentad_dimid, lon_dimid, lat_dimid +integer :: pentad_varid, o_mean_varid, o_std_varid, m_mean_varid, m_std_varid real :: tmpreal integer, dimension(:), allocatable :: sclprm_tile_id +integer, dimension(:), allocatable :: pentads real, dimension(:), allocatable :: sclprm_lon, sclprm_lat -real, dimension(:), allocatable :: sclprm_mean_obs, sclprm_std_obs -real, dimension(:), allocatable :: sclprm_mean_mod, sclprm_std_mod +real, dimension(:,:), allocatable :: sclprm_mean_obs, sclprm_std_obs +real, dimension(:,:), allocatable :: sclprm_mean_mod, sclprm_std_mod character(len=*), parameter :: Iam = ' scale_obs_sfmc_zscore' character(len=400) :: err_msg @@ -8187,33 +8202,42 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & fname = trim(this_obs_param%scalepath) // '/' // & trim(this_obs_param%scalename) // & - month_string(date_time%month) // '_' // & - tmpchar2 // 'z.bin' + // '.nc4' if (logit) write (logunit,*) 'scaling obs species ', this_obs_param%species, ':' if (logit) write (logunit,'(400A)') ' reading ', trim(fname) -open(10, file=fname, form='unformatted',convert='big_endian', action='read') - -read(10) N_sclprm - -allocate(sclprm_tile_id(N_sclprm)) -allocate(sclprm_lon(N_sclprm)) -allocate(sclprm_lat(N_sclprm)) -allocate(sclprm_mean_obs(N_sclprm)) -allocate(sclprm_std_obs(N_sclprm)) -allocate(sclprm_mean_mod(N_sclprm)) -allocate(sclprm_std_mod(N_sclprm)) - -read(10) sclprm_tile_id -read(10) sclprm_lon -read(10) sclprm_lat -read(10) sclprm_mean_obs -read(10) sclprm_std_obs -read(10) sclprm_mean_mod -read(10) sclprm_std_mod - -close(10,status='keep') +! What pentad do we want? +pp = date_time%pentad + +! open the NetCDF file +ierr = nf_open(fname, nf_nowrite, ncid) + +ierr = nf_inq_dimid(ncid, 'pentad', pentad_dimid) +ierr = nf_inq_dimid(ncid, 'lon', lon_dimid) +ierr = nf_inq_dimid(ncid, 'lat', lat_dimid) + +ierr = nf_inq_varid(ncid, 'lon', lon_varid) +ierr = nf_inq_varid(ncid, 'lat', lat_varid) +ierr = nf_inq_varid(ncid, 'o_mean', o_mean_varid) +ierr = nf_inq_varid(ncid, 'o_std', o_std_varid) +ierr = nf_inq_varid(ncid, 'm_mean', m_mean_varid) +ierr = nf_inq_varid(ncid, 'm_std', m_std_varid) + +! read lon and lat variables +allocate(sclprm_lon(lon_dimid), sclprm_lat(lat_dimid)) +ierr = nf_get_var(ncid, lon_varid, sclprm_lon) +ierr = nf_get_var(ncid, lat_varid, sclprm_lat) + +allocate(sclprm_mean_obs(lon_dimid, lat_dimid), sclprm_std_obs(lon_dimid, lat_dimid), & +sclprm_mean_mod(lon_dimid, lat_dimid), sclprm_std_mod(lon_dimid, lat_dimid)) +ierr = nf_get_var3(ncid, o_mean_varid, (/pp, 1, 1/), (/lon_dimid, lat_dimid/), sclprm_mean_obs) +ierr = nf_get_var3(ncid, o_std_varid, (/pp, 1, 1/), (/lon_dimid, lat_dimid/), sclprm_std_obs) +ierr = nf_get_var3(ncid, m_mean_varid, (/pp, 1, 1/), (/lon_dimid, lat_dimid/), sclprm_mean_mod) +ierr = nf_get_var3(ncid, m_std_varid, (/pp, 1, 1/), (/lon_dimid, lat_dimid/), sclprm_std_mod) + +! close the netcdf file +ierr = nf_close(ncid) ! minimal consistency check From c44c96b4b703ad0b529b7708220dbb4120869fac Mon Sep 17 00:00:00 2001 From: amfox37 Date: Thu, 20 Apr 2023 16:25:32 -0600 Subject: [PATCH 062/308] nf_ to nf90_ --- .../clsm_ensupd_read_obs.F90 | 96 +++++++++---------- 1 file changed, 43 insertions(+), 53 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 4044d3cc..3dec8ce3 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -8175,12 +8175,11 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & character(300) :: fname -character(2) :: tmpchar2 - integer :: i, ind, pp integer :: ncid, varid, ierr integer :: pentad_dimid, lon_dimid, lat_dimid -integer :: pentad_varid, o_mean_varid, o_std_varid, m_mean_varid, m_std_varid +integer :: pentad_varid, lon_varid, lat_varid +integer :: o_mean_varid, o_std_varid, m_mean_varid, m_std_varid real :: tmpreal @@ -8196,8 +8195,6 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & ! ------------------------------------------------------------------ -write (tmpchar2, '(i2.2)') date_time%hour - ! read scaling parameters from file fname = trim(this_obs_param%scalepath) // '/' // & @@ -8211,39 +8208,33 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & pp = date_time%pentad ! open the NetCDF file -ierr = nf_open(fname, nf_nowrite, ncid) +ierr = nf90_open(fname, nf90_nowrite, ncid) -ierr = nf_inq_dimid(ncid, 'pentad', pentad_dimid) -ierr = nf_inq_dimid(ncid, 'lon', lon_dimid) -ierr = nf_inq_dimid(ncid, 'lat', lat_dimid) +ierr = nf90_inq_dimid(ncid, 'pentad', pentad_dimid) +ierr = nf90_inq_dimid(ncid, 'lon', lon_dimid) +ierr = nf90_inq_dimid(ncid, 'lat', lat_dimid) -ierr = nf_inq_varid(ncid, 'lon', lon_varid) -ierr = nf_inq_varid(ncid, 'lat', lat_varid) -ierr = nf_inq_varid(ncid, 'o_mean', o_mean_varid) -ierr = nf_inq_varid(ncid, 'o_std', o_std_varid) -ierr = nf_inq_varid(ncid, 'm_mean', m_mean_varid) -ierr = nf_inq_varid(ncid, 'm_std', m_std_varid) +ierr = nf90_inq_varid(ncid, 'lon', lon_varid) +ierr = nf90_inq_varid(ncid, 'lat', lat_varid) +ierr = nf90_inq_varid(ncid, 'o_mean', o_mean_varid) +ierr = nf90_inq_varid(ncid, 'o_std', o_std_varid) +ierr = nf90_inq_varid(ncid, 'm_mean', m_mean_varid) +ierr = nf90_inq_varid(ncid, 'm_std', m_std_varid) ! read lon and lat variables allocate(sclprm_lon(lon_dimid), sclprm_lat(lat_dimid)) -ierr = nf_get_var(ncid, lon_varid, sclprm_lon) -ierr = nf_get_var(ncid, lat_varid, sclprm_lat) +ierr = nf90_get_var(ncid, lon_varid, sclprm_lon) +ierr = nf90_get_var(ncid, lat_varid, sclprm_lat) allocate(sclprm_mean_obs(lon_dimid, lat_dimid), sclprm_std_obs(lon_dimid, lat_dimid), & sclprm_mean_mod(lon_dimid, lat_dimid), sclprm_std_mod(lon_dimid, lat_dimid)) -ierr = nf_get_var3(ncid, o_mean_varid, (/pp, 1, 1/), (/lon_dimid, lat_dimid/), sclprm_mean_obs) -ierr = nf_get_var3(ncid, o_std_varid, (/pp, 1, 1/), (/lon_dimid, lat_dimid/), sclprm_std_obs) -ierr = nf_get_var3(ncid, m_mean_varid, (/pp, 1, 1/), (/lon_dimid, lat_dimid/), sclprm_mean_mod) -ierr = nf_get_var3(ncid, m_std_varid, (/pp, 1, 1/), (/lon_dimid, lat_dimid/), sclprm_std_mod) +ierr = nf90_get_var3(ncid, o_mean_varid, (/pp, 1, 1/), (/lon_dimid, lat_dimid/), sclprm_mean_obs) +ierr = nf90_get_var3(ncid, o_std_varid, (/pp, 1, 1/), (/lon_dimid, lat_dimid/), sclprm_std_obs) +ierr = nf90_get_var3(ncid, m_mean_varid, (/pp, 1, 1/), (/lon_dimid, lat_dimid/), sclprm_mean_mod) +ierr = nf90_get_var3(ncid, m_std_varid, (/pp, 1, 1/), (/lon_dimid, lat_dimid/), sclprm_std_mod) ! close the netcdf file -ierr = nf_close(ncid) - -! minimal consistency check - -if (N_catd>N_sclprm) then - call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'something is wrong') -end if +ierr = nf90_close(ncid) ! -------------------------------------------------------------- @@ -8259,50 +8250,49 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & ! find ind for current tile id in scaling parameters - do ind=1,N_sclprm + ! do ind=1,N_sclprm - if (sclprm_tile_id(ind)==tile_coord(i)%tile_id) exit + ! if (sclprm_tile_id(ind)==tile_coord(i)%tile_id) exit - end do + ! end do - ! sanity check (against accidental use of wrong tile space) + ! ! sanity check (against accidental use of wrong tile space) - if ( abs(tile_coord(i)%com_lat-sclprm_lat(ind))>tol .or. & - abs(tile_coord(i)%com_lon-sclprm_lon(ind))>tol ) then - err_msg = 'something wrong' - call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) - end if + ! if ( abs(tile_coord(i)%com_lat-sclprm_lat(ind))>tol .or. & + ! abs(tile_coord(i)%com_lon-sclprm_lon(ind))>tol ) then + ! err_msg = 'something wrong' + ! call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + ! end if - ! check for no-data-values in observation and fit parameters - ! (any negative number could be no-data-value for observations) + ! ! check for no-data-values in observation and fit parameters + ! ! (any negative number could be no-data-value for observations) - if ( sclprm_mean_obs(ind)>0. .and. & - sclprm_mean_mod(ind)>0. .and. & - sclprm_std_obs(ind)>=0. .and. & - sclprm_std_mod(ind)>=0. ) then + ! if ( sclprm_mean_obs(ind)>0. .and. & + ! sclprm_mean_mod(ind)>0. .and. & + ! sclprm_std_obs(ind)>=0. .and. & + ! sclprm_std_mod(ind)>=0. ) then - ! scale via standard normal deviates + ! ! scale via standard normal deviates - tmpreal = sclprm_std_mod(ind)/sclprm_std_obs(ind) + ! tmpreal = sclprm_std_mod(ind)/sclprm_std_obs(ind) - tmp_obs(i) = sclprm_mean_mod(ind) & - + tmpreal*(tmp_obs(i)-sclprm_mean_obs(ind)) + ! tmp_obs(i) = sclprm_mean_mod(ind) & + ! + tmpreal*(tmp_obs(i)-sclprm_mean_obs(ind)) - ! scale observation error std + ! ! scale observation error std - tmp_std_obs(i) = tmpreal*tmp_std_obs(i) + ! tmp_std_obs(i) = tmpreal*tmp_std_obs(i) - else + ! else - tmp_obs(i) = this_obs_param%nodata + ! tmp_obs(i) = this_obs_param%nodata - end if + ! end if end if end do -deallocate(sclprm_tile_id) deallocate(sclprm_lon) deallocate(sclprm_lat) deallocate(sclprm_mean_obs) From 33d6e52e6618bc11b4fe2f0f39545b20f82d0996 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Thu, 20 Apr 2023 16:50:12 -0600 Subject: [PATCH 063/308] sort out get_var for 3D array --- .../GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 3dec8ce3..837eef53 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -8228,10 +8228,10 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & allocate(sclprm_mean_obs(lon_dimid, lat_dimid), sclprm_std_obs(lon_dimid, lat_dimid), & sclprm_mean_mod(lon_dimid, lat_dimid), sclprm_std_mod(lon_dimid, lat_dimid)) -ierr = nf90_get_var3(ncid, o_mean_varid, (/pp, 1, 1/), (/lon_dimid, lat_dimid/), sclprm_mean_obs) -ierr = nf90_get_var3(ncid, o_std_varid, (/pp, 1, 1/), (/lon_dimid, lat_dimid/), sclprm_std_obs) -ierr = nf90_get_var3(ncid, m_mean_varid, (/pp, 1, 1/), (/lon_dimid, lat_dimid/), sclprm_mean_mod) -ierr = nf90_get_var3(ncid, m_std_varid, (/pp, 1, 1/), (/lon_dimid, lat_dimid/), sclprm_std_mod) +ierr = nf90_get_var(ncid, o_mean_varid, sclprm_mean_obs, (/pp, 1, 1/), (/1, lon_dimid, lat_dimid/)) +ierr = nf90_get_var(ncid, o_std_varid, sclprm_std_obs, (/pp, 1, 1/), (/1, lon_dimid, lat_dimid/)) +ierr = nf90_get_var(ncid, m_mean_varid, sclprm_mean_mod, (/pp, 1, 1/), (/1, lon_dimid, lat_dimid/)) +ierr = nf90_get_var(ncid, m_std_varid, sclprm_std_mod, (/pp, 1, 1/), (/1, lon_dimid, lat_dimid/)) ! close the netcdf file ierr = nf90_close(ncid) From c193dec200a5bacf958a77ce57ea86a03161e3e4 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Fri, 21 Apr 2023 14:15:09 -0600 Subject: [PATCH 064/308] scale via standard normal deviates --- .../clsm_ensupd_read_obs.F90 | 58 ++++++++++--------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 837eef53..c3eadeea 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -8175,13 +8175,13 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & character(300) :: fname -integer :: i, ind, pp +integer :: i, ind, pp, j_in, i_in integer :: ncid, varid, ierr integer :: pentad_dimid, lon_dimid, lat_dimid integer :: pentad_varid, lon_varid, lat_varid integer :: o_mean_varid, o_std_varid, m_mean_varid, m_std_varid -real :: tmpreal +real :: tmpreal, this_lon, this_lat integer, dimension(:), allocatable :: sclprm_tile_id integer, dimension(:), allocatable :: pentads @@ -8198,8 +8198,7 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & ! read scaling parameters from file fname = trim(this_obs_param%scalepath) // '/' // & - trim(this_obs_param%scalename) // & - // '.nc4' + trim(this_obs_param%scalename) // '.nc4' if (logit) write (logunit,*) 'scaling obs species ', this_obs_param%species, ':' if (logit) write (logunit,'(400A)') ' reading ', trim(fname) @@ -8248,46 +8247,49 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & if (tmp_obs(i)>=0.) then - ! find ind for current tile id in scaling parameters + ! ll_lon and ll_lat refer to lower left corner of grid cell + ! (as opposed to the grid point in the center of the grid cell) + + this_lon = tmp_lon(i) + this_lat = tmp_lat(i) - ! do ind=1,N_sclprm - - ! if (sclprm_tile_id(ind)==tile_coord(i)%tile_id) exit - - ! end do + i_ind = (this_lon - ll_lon)/dlon + j_ind = (this_lat - ll_lat)/dlat + + ! find ind for current tile id in scaling parameters ! ! sanity check (against accidental use of wrong tile space) - ! if ( abs(tile_coord(i)%com_lat-sclprm_lat(ind))>tol .or. & - ! abs(tile_coord(i)%com_lon-sclprm_lon(ind))>tol ) then - ! err_msg = 'something wrong' - ! call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) - ! end if + if ( abs(tile_coord(i)%com_lat-sclprm_lat(j_ind))>tol .or. & + abs(tile_coord(i)%com_lon-sclprm_lon(i_ind))>tol ) then + err_msg = 'something wrong' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + end if ! ! check for no-data-values in observation and fit parameters ! ! (any negative number could be no-data-value for observations) - ! if ( sclprm_mean_obs(ind)>0. .and. & - ! sclprm_mean_mod(ind)>0. .and. & - ! sclprm_std_obs(ind)>=0. .and. & - ! sclprm_std_mod(ind)>=0. ) then + if ( sclprm_mean_obs(i_ind, j_ind)>0. .and. & + sclprm_mean_mod(i_ind, j_ind)>0. .and. & + sclprm_std_obs(i_ind, j_ind)>=0. .and. & + sclprm_std_mod(i_ind, j_ind)>=0. ) then - ! ! scale via standard normal deviates + ! scale via standard normal deviates - ! tmpreal = sclprm_std_mod(ind)/sclprm_std_obs(ind) + tmpreal = sclprm_std_mod(i_ind, j_ind)/sclprm_std_obs(i_ind, j_ind) - ! tmp_obs(i) = sclprm_mean_mod(ind) & - ! + tmpreal*(tmp_obs(i)-sclprm_mean_obs(ind)) + tmp_obs(i) = sclprm_mean_mod(i_ind, j_ind) & + + tmpreal*(tmp_obs(i)-sclprm_mean_obs(i_ind, j_ind)) - ! ! scale observation error std + ! scale observation error std - ! tmp_std_obs(i) = tmpreal*tmp_std_obs(i) + tmp_std_obs(i) = tmpreal*tmp_std_obs(i) - ! else + else - ! tmp_obs(i) = this_obs_param%nodata + tmp_obs(i) = this_obs_param%nodata - ! end if + end if end if From 9a242704211e3ef1ee331f3fad01b092d97bfe4a Mon Sep 17 00:00:00 2001 From: amfox37 Date: Tue, 25 Apr 2023 13:05:33 -0400 Subject: [PATCH 065/308] sort out netcdf dimensions --- .../clsm_ensupd_read_obs.F90 | 36 +++++++++++-------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index c3eadeea..ea2d67db 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -8152,8 +8152,8 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & ! ---------------------------------------------------------- ! Grid and netcdf parameters (might want to read these from netCDF file?) -integer, parameter :: N_lon = 1440 -integer, parameter :: N_lat = 720 +! integer, parameter :: N_lon = 1440 +! integer, parameter :: N_lat = 720 real, parameter :: ll_lon = -180.0000 real, parameter :: ll_lat = -90.0000 real, parameter :: dlon = 0.25 @@ -8165,7 +8165,7 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & real, parameter :: no_data_stats = -9999. -real, parameter :: tol = 1e-2 +real, parameter :: tol = 0.99 character(3), dimension(12) :: month_string = (/ & 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', & @@ -8175,9 +8175,10 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & character(300) :: fname -integer :: i, ind, pp, j_in, i_in +integer :: i, ind, pp, j_ind, i_ind integer :: ncid, varid, ierr integer :: pentad_dimid, lon_dimid, lat_dimid +integer :: N_pentad, N_lon, N_lat integer :: pentad_varid, lon_varid, lat_varid integer :: o_mean_varid, o_std_varid, m_mean_varid, m_std_varid @@ -8213,6 +8214,10 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & ierr = nf90_inq_dimid(ncid, 'lon', lon_dimid) ierr = nf90_inq_dimid(ncid, 'lat', lat_dimid) +ierr = nf90_inquire_dimension(ncid, pentad_dimid, len = N_pentad) +ierr = nf90_inquire_dimension(ncid, lon_dimid, len = N_lon) +ierr = nf90_inquire_dimension(ncid, lat_dimid, len = N_lat) + ierr = nf90_inq_varid(ncid, 'lon', lon_varid) ierr = nf90_inq_varid(ncid, 'lat', lat_varid) ierr = nf90_inq_varid(ncid, 'o_mean', o_mean_varid) @@ -8221,16 +8226,16 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & ierr = nf90_inq_varid(ncid, 'm_std', m_std_varid) ! read lon and lat variables -allocate(sclprm_lon(lon_dimid), sclprm_lat(lat_dimid)) +allocate(sclprm_lon(N_lon), sclprm_lat(N_lat)) ierr = nf90_get_var(ncid, lon_varid, sclprm_lon) ierr = nf90_get_var(ncid, lat_varid, sclprm_lat) -allocate(sclprm_mean_obs(lon_dimid, lat_dimid), sclprm_std_obs(lon_dimid, lat_dimid), & -sclprm_mean_mod(lon_dimid, lat_dimid), sclprm_std_mod(lon_dimid, lat_dimid)) -ierr = nf90_get_var(ncid, o_mean_varid, sclprm_mean_obs, (/pp, 1, 1/), (/1, lon_dimid, lat_dimid/)) -ierr = nf90_get_var(ncid, o_std_varid, sclprm_std_obs, (/pp, 1, 1/), (/1, lon_dimid, lat_dimid/)) -ierr = nf90_get_var(ncid, m_mean_varid, sclprm_mean_mod, (/pp, 1, 1/), (/1, lon_dimid, lat_dimid/)) -ierr = nf90_get_var(ncid, m_std_varid, sclprm_std_mod, (/pp, 1, 1/), (/1, lon_dimid, lat_dimid/)) +allocate(sclprm_mean_obs(N_lon, N_lat), sclprm_std_obs(N_lon, N_lat), & +sclprm_mean_mod(lon_dimid, lat_dimid), sclprm_std_mod(N_lon, N_lat)) +ierr = nf90_get_var(ncid, o_mean_varid, sclprm_mean_obs, (/pp, 1, 1/), (/1, N_lon, N_lat/)) +ierr = nf90_get_var(ncid, o_std_varid, sclprm_std_obs, (/pp, 1, 1/), (/1, N_lon, N_lat/)) +ierr = nf90_get_var(ncid, m_mean_varid, sclprm_mean_mod, (/pp, 1, 1/), (/1, N_lon, N_lat/)) +ierr = nf90_get_var(ncid, m_std_varid, sclprm_std_mod, (/pp, 1, 1/), (/1, N_lon, N_lat/)) ! close the netcdf file ierr = nf90_close(ncid) @@ -8253,15 +8258,18 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & this_lon = tmp_lon(i) this_lat = tmp_lat(i) - i_ind = (this_lon - ll_lon)/dlon - j_ind = (this_lat - ll_lat)/dlat - + i_ind = ceiling((this_lon - ll_lon)/dlon) + j_ind = ceiling((this_lat - ll_lat)/dlat) + ! find ind for current tile id in scaling parameters ! ! sanity check (against accidental use of wrong tile space) if ( abs(tile_coord(i)%com_lat-sclprm_lat(j_ind))>tol .or. & abs(tile_coord(i)%com_lon-sclprm_lon(i_ind))>tol ) then + if (logit) write (logunit,*) 'i = ', i + if (logit) write (logunit,*) 'tile_coord(i)%com_lat, this_lat, sclprm_lat(j_ind)', tile_coord(i)%com_lat, this_lat, sclprm_lat(j_ind) + if (logit) write (logunit,*) 'tile_coord(i)%com_lon, this_lon, sclprm_lon(i_ind)', tile_coord(i)%com_lon, this_lon, sclprm_lon(i_ind) err_msg = 'something wrong' call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) end if From c7a886f944432358a06ce1ad6880db98b9e23524 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Tue, 25 Apr 2023 16:07:00 -0600 Subject: [PATCH 066/308] more netcdf read issues --- .../clsm_ensupd_read_obs.F90 | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index ea2d67db..6bf2e586 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -8231,11 +8231,11 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & ierr = nf90_get_var(ncid, lat_varid, sclprm_lat) allocate(sclprm_mean_obs(N_lon, N_lat), sclprm_std_obs(N_lon, N_lat), & -sclprm_mean_mod(lon_dimid, lat_dimid), sclprm_std_mod(N_lon, N_lat)) -ierr = nf90_get_var(ncid, o_mean_varid, sclprm_mean_obs, (/pp, 1, 1/), (/1, N_lon, N_lat/)) -ierr = nf90_get_var(ncid, o_std_varid, sclprm_std_obs, (/pp, 1, 1/), (/1, N_lon, N_lat/)) -ierr = nf90_get_var(ncid, m_mean_varid, sclprm_mean_mod, (/pp, 1, 1/), (/1, N_lon, N_lat/)) -ierr = nf90_get_var(ncid, m_std_varid, sclprm_std_mod, (/pp, 1, 1/), (/1, N_lon, N_lat/)) +sclprm_mean_mod(N_lon, N_lat), sclprm_std_mod(N_lon, N_lat)) +ierr = nf90_get_var(ncid, o_mean_varid, sclprm_mean_obs, (/1, 1, pp/), (/N_lon, N_lat, 1/)) +ierr = nf90_get_var(ncid, o_std_varid, sclprm_std_obs, (/1, 1, pp/), (/N_lon, N_lat, 1/)) +ierr = nf90_get_var(ncid, m_mean_varid, sclprm_mean_mod, (/1, 1, pp/), (/N_lon, N_lat, 1/)) +ierr = nf90_get_var(ncid, m_std_varid, sclprm_std_mod, (/1, 1, pp/), (/N_lon, N_lat, 1/)) ! close the netcdf file ierr = nf90_close(ncid) @@ -8284,6 +8284,10 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & ! scale via standard normal deviates + if (mod(i, 10) == 0) then + write(logunit,*) i, tmp_obs(i), sclprm_mean_obs(i_ind, j_ind), sclprm_std_mod(i_ind, j_ind), sclprm_std_obs(i_ind, j_ind) + endif + tmpreal = sclprm_std_mod(i_ind, j_ind)/sclprm_std_obs(i_ind, j_ind) tmp_obs(i) = sclprm_mean_mod(i_ind, j_ind) & From e9e698a27a67f4c16f1038ff6439e8e439aac620 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Fri, 28 Apr 2023 13:18:22 -0400 Subject: [PATCH 067/308] sorted netcdf read for 2D grids --- .../clsm_ensupd_read_obs.F90 | 43 +++++++++++-------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 6bf2e586..09c9a4c4 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -8176,11 +8176,13 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & character(300) :: fname integer :: i, ind, pp, j_ind, i_ind -integer :: ncid, varid, ierr +integer :: ncid, varid, ierr, ierr2 integer :: pentad_dimid, lon_dimid, lat_dimid integer :: N_pentad, N_lon, N_lat integer :: pentad_varid, lon_varid, lat_varid integer :: o_mean_varid, o_std_varid, m_mean_varid, m_std_varid +integer, dimension(3) :: start, icount + real :: tmpreal, this_lon, this_lat @@ -8230,12 +8232,17 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & ierr = nf90_get_var(ncid, lon_varid, sclprm_lon) ierr = nf90_get_var(ncid, lat_varid, sclprm_lat) -allocate(sclprm_mean_obs(N_lon, N_lat), sclprm_std_obs(N_lon, N_lat), & -sclprm_mean_mod(N_lon, N_lat), sclprm_std_mod(N_lon, N_lat)) -ierr = nf90_get_var(ncid, o_mean_varid, sclprm_mean_obs, (/1, 1, pp/), (/N_lon, N_lat, 1/)) -ierr = nf90_get_var(ncid, o_std_varid, sclprm_std_obs, (/1, 1, pp/), (/N_lon, N_lat, 1/)) -ierr = nf90_get_var(ncid, m_mean_varid, sclprm_mean_mod, (/1, 1, pp/), (/N_lon, N_lat, 1/)) -ierr = nf90_get_var(ncid, m_std_varid, sclprm_std_mod, (/1, 1, pp/), (/N_lon, N_lat, 1/)) +start = [1, 1, pp] +icount = [N_lat, N_lon, 1] + +allocate(sclprm_mean_obs(N_lat, N_lon), sclprm_std_obs(N_lat, N_lon)) +allocate(sclprm_mean_mod(N_lat, N_lon), sclprm_std_mod(N_lat, N_lon)) + +! ierr = nf90_get_var(ncid, o_mean_varid, sclprm_mean_obs, (/1, 1, pp/), (/N_lon, N_lat, 1/)) +ierr2 = nf90_get_var(ncid, o_mean_varid, sclprm_mean_obs, start, icount) +ierr = nf90_get_var(ncid, o_std_varid, sclprm_std_obs, start, icount) +ierr = nf90_get_var(ncid, m_mean_varid, sclprm_mean_mod, start, icount) +ierr = nf90_get_var(ncid, m_std_varid, sclprm_std_mod, start, icount) ! close the netcdf file ierr = nf90_close(ncid) @@ -8267,9 +8274,11 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & if ( abs(tile_coord(i)%com_lat-sclprm_lat(j_ind))>tol .or. & abs(tile_coord(i)%com_lon-sclprm_lon(i_ind))>tol ) then - if (logit) write (logunit,*) 'i = ', i + if (logit) write (logunit,*) 'ierr2, i = ', ierr2, i + if (logit) write (logunit,*) 'start, icount', start, icount if (logit) write (logunit,*) 'tile_coord(i)%com_lat, this_lat, sclprm_lat(j_ind)', tile_coord(i)%com_lat, this_lat, sclprm_lat(j_ind) if (logit) write (logunit,*) 'tile_coord(i)%com_lon, this_lon, sclprm_lon(i_ind)', tile_coord(i)%com_lon, this_lon, sclprm_lon(i_ind) + if (logit) write (logunit,*) 'pp, sclprm_lon, sclprm_lat, sclprm_mean_obs(328:334,579) ', pp, sclprm_lon(1), sclprm_lat(1), sclprm_mean_obs(328:334, 579) err_msg = 'something wrong' call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) end if @@ -8277,21 +8286,21 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & ! ! check for no-data-values in observation and fit parameters ! ! (any negative number could be no-data-value for observations) - if ( sclprm_mean_obs(i_ind, j_ind)>0. .and. & - sclprm_mean_mod(i_ind, j_ind)>0. .and. & - sclprm_std_obs(i_ind, j_ind)>=0. .and. & - sclprm_std_mod(i_ind, j_ind)>=0. ) then + if ( sclprm_mean_obs(j_ind, i_ind)>0. .and. & + sclprm_mean_mod(j_ind, i_ind)>0. .and. & + sclprm_std_obs(j_ind, i_ind)>=0. .and. & + sclprm_std_mod(j_ind, i_ind)>=0. ) then ! scale via standard normal deviates - if (mod(i, 10) == 0) then - write(logunit,*) i, tmp_obs(i), sclprm_mean_obs(i_ind, j_ind), sclprm_std_mod(i_ind, j_ind), sclprm_std_obs(i_ind, j_ind) + if (mod(i, 100) == 0) then + write(logunit,*) 'Found! ', i, pp, j_ind, i_ind, tmp_obs(i), sclprm_mean_obs(j_ind, i_ind), sclprm_std_mod(j_ind, i_ind), sclprm_std_obs(j_ind, i_ind) endif - tmpreal = sclprm_std_mod(i_ind, j_ind)/sclprm_std_obs(i_ind, j_ind) + tmpreal = sclprm_std_mod(j_ind, i_ind)/sclprm_std_obs(j_ind, i_ind) - tmp_obs(i) = sclprm_mean_mod(i_ind, j_ind) & - + tmpreal*(tmp_obs(i)-sclprm_mean_obs(i_ind, j_ind)) + tmp_obs(i) = sclprm_mean_mod(j_ind, i_ind) & + + tmpreal*(tmp_obs(i)-sclprm_mean_obs(j_ind, i_ind)) ! scale observation error std From e8792dc98a0ba076b9cebe7b70cc17e6d64525e7 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Sun, 30 Apr 2023 16:00:25 -0400 Subject: [PATCH 068/308] new latlon-grid based statistics --- ..._model_and_obs_clim_stats_pentads_latlon.m | 128 +++ ..._model_and_obs_clim_stats_pentads_latlon.m | 730 ++++++++++++++++++ .../obs_scaling_params/write_netcdf_file.m | 81 +- .../write_netcdf_file_2D_grid.m | 223 ++++++ 4 files changed, 1139 insertions(+), 23 deletions(-) create mode 100644 src/Applications/LDAS_App/util/inputs/obs_scaling_params/Run_get_model_and_obs_clim_stats_pentads_latlon.m create mode 100644 src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats_pentads_latlon.m create mode 100644 src/Applications/LDAS_App/util/inputs/obs_scaling_params/write_netcdf_file_2D_grid.m diff --git a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/Run_get_model_and_obs_clim_stats_pentads_latlon.m b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/Run_get_model_and_obs_clim_stats_pentads_latlon.m new file mode 100644 index 00000000..f92cf471 --- /dev/null +++ b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/Run_get_model_and_obs_clim_stats_pentads_latlon.m @@ -0,0 +1,128 @@ +% Calculate scaling files for ASCAT wetness fraction +% +% GDL, 11 Sep 2012 +% QLiu, Dec 2016 +% AMF April 2023 + +%===================================================================== + +clear + +% add path to matlab functions in src/Applications/LDAS_App/util/shared/matlab/ +addpath('../../shared/matlab/'); + +%====== + +run_months = [1:12 1:4]; %loop through 1:4 again to get complete pentads + +exp_path = '/discover/nobackup/amfox/Experiments/ASCAT_3Y_v2'; +exp_run = {'ASCAT_M36'}; +domain = 'SMAP_EASEv2_M36_GLOBAL'; + +%Start and end year for each month +start_year = [repmat(2016,1,5) repmat(2015,1,7) repmat(2016,1,4)]; %corresp to [1:12 1 2] +end_year = [repmat(2017,1,5) repmat(2016,1,7) repmat(2017,1,4)]; %runs till end of run_months for end_year + +prefix_out = 'M36_zscore_stats_'; + +dt_assim = 3*60*60; % [seconds] land analysis time step, + % same as LANDASSIM_DT in GEOSldas) +t0_assim = 0; % [seconds] land analysis "reference" time (offset from 0z), + % same as LANDASSIM_T0 in GEOSldas (except for units), + % typically 0 in offline runs and 1.5*60*60 in LADAS + +%====== + +obs_param_fname = [exp_path, '/', exp_run{1}, '/output/', domain, '/rc_out/', ... + '/Y2016/M04/',exp_run{1}, '.ldas_obsparam.20160401_0000z.txt']; + +% List species to use here +species_names = {'ASCAT_META_SM_A','ASCAT_META_SM_D','ASCAT_METB_SM_A','ASCAT_METB_SM_D'}; + +% Decide here if we're combining statitics across multiple species +combine_species_stats = 1; % Calculate combined statistics for all species in species_names if set to 1. + +if combine_species_stats + disp('Calculating stats by combining muiltiple species'); +end + +%Spatial sampling +hscale = 0.0; % degrees lat/lon + +% Temporal sampling window(days), current hard coded and need to be divisive by 5 and be an odd number +w_days = 75; + +Ndata_min = 20; + +%To limit M09 tiles to administering M36 tiles only (smaller files), +%provide convert_grid +if isempty(strfind(prefix_out,'M09')) + convert_grid='EASEv2_M36'; +end + +if (mod(w_days,10) == 0) + disp('w_days should be 5, 15, 25, 35, ...') + error('Need an odd number of pentads |xxxxx|xxXxx|xxxxx|') +end +if (mod(w_days, 5) > 0) + error('Aiming at pentad files') +end + +% ------------------------------------------------------------------------ + +[N_obs_param, obs_param ] = read_obsparam(obs_param_fname); + +species =[]; + +for i = 1:length(species_names) + add_species = obs_param(strcmp(species_names(i),{obs_param.descr})).species; + species = union(species,add_species); +end + +species +% ------------------ + +for n=1:length(exp_run) + if (exist('convert_grid','var')) + if exist('time_of_day_in_hours','var') + for j=1:length(time_of_day_in_hours) + for k=1:length(run_months) + get_model_and_obs_clim_stats_pentads_latlon( species_names, ... + run_months{k}, exp_path, exp_run{n}, domain, ... + start_year, end_year, ... + dt_assim, t0_assim, species, combine_species_stats, obs_param, ... + hscale, w_days, Ndata_min, prefix_out,... + convert_grid, time_of_day_in_hours(j) ); + end + end + else + get_model_and_obs_clim_stats_pentads_latlon( species_names, ... + run_months, exp_path, exp_run{n}, domain, start_year, end_year, ... + dt_assim, t0_assim, species, combine_species_stats, obs_param, ... + hscale, w_days, Ndata_min, prefix_out,... + convert_grid ); + end + else + if exist('time_of_day_in_hours','var') + for j=1:length(time_of_day_in_hours) + for k=1:length(run_months) + get_model_and_obs_clim_stats_pentads_latlon( species_names,... + run_months{k}, exp_path, exp_run{n}, domain,... + start_year, end_year, ... + dt_assim, t0_assim, species, combine_species_stats, obs_param, ... + hscale, w_days, Ndata_min, prefix_out,... + time_of_day_in_hours(j) ); + end + end + else + get_model_and_obs_clim_stats_pentads_latlon( species_names, ... + run_months, exp_path, exp_run{n}, domain, start_year, end_year, ... + dt_assim, t0_assim, species, combine_species_stats, obs_param, ... + hscale, w_days, Ndata_min, prefix_out); + end + end +end + +% ============= EOF ==================================================== + + diff --git a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats_pentads_latlon.m b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats_pentads_latlon.m new file mode 100644 index 00000000..77f74e6e --- /dev/null +++ b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats_pentads_latlon.m @@ -0,0 +1,730 @@ + +function [] = get_model_and_obs_clim_stats_pentads_latlon( species_names, ... + run_months, exp_path, exp_run, domain, start_year, end_year, ... + dt_assim, t0_assim, species, combine_species_stats, obs_param, ... + hscale, w_days, Ndata_min, prefix, ... + convert_grid , time_of_day_in_hours ) + +% +% get_model_and_obs_clim_stats.m +% +% Compute mean, stdv of model and observations from tile-based +% "innov" files for a selection of species. +% +% The main purpose of this function is to aggregate the information +% from the "innov" files so that the climatology statistics can +% be used in scaling of the observations before assimilation. +% +% One file with statistics is generated for every DOY (1,...,365). +% The temporal smoothing/averaging window (w_days) is given in days. +% +% We calcualte the bias correction factors and write on a regular 0.25 degree +% lat/lon grid as there is no regular grid for ASCAT observations + +% +% ==HEADER== +% N_tiles N_angles +% angles +% +% ==DATA== +% +% %%%% tile ID --> for all tiles (1:N_tiles, not sorted by tile_id!) +% lat +% lon +% +% [for angles] +% mean_obs_H +% std_obs_H +% mean_mod_H +% std_mod_H +% N_data_H +% +% mean_obs_V +% std_obs_V +% mean_mod_V +% std_mod_V +% N_data_V +% +% H_obs +% H_mod +% V_obs +% V_mod +% [end angles] +% +% GDL, 10 sept 2012 +% +% GDL, aug 2013: added 'convert_grid' (= EASEv2_M36, EASE_M36, ...) +% to project the Obs (always M36 for SMOS) and Fcst to M36 +% M09 obs are administered by tiles (0) that could be anywhere +% around the center of the observed pixel (M36) +% ----------- +% | X X X X | +% | X O O X | +% | X O O X | +% | X X X X | +% ----------- +% GDL, jan 2014: the above issue that "any" M09 tile in the center (0) +% could potentially administer the M36 obs is not true +% anymore with later LDASsa-tags. +% => no need to pass on 'convert_grid' for tags later than +% the summer of 2013 +% reichle, qliu, 13 July 2022: +% "convert_grid" is still needed to limit the number of tiles +% in the scaling parameter file. With "convert_grid" turned on, +% only the M09 tile to the northeast of the M36 center point +% is kept in the scaling parameter file, consistent with the +% "tmp_shift_lat" and "tmp_shift_lon" operations in the SMOS +% and SMAP Fortran readers. (It is not clear if this matlab +% function works properly if there is no M09 [land] tile +% immediately to the northeast of the M36 center point. In +% such a case, the Fortran reader assigns the nearest M09 +% land tile as the tile that administers the obs.) +% Presumably, scaling parameters for all M09 tiles could be kept +% if they are stored in (compressed) nc4 format. In this case, +% the NaN values for the scaling parameters of 15 out of each 16 +% M09 tiles can be compressed to almost nothing. +% +% ------------------------------------------------------------------- +% begin user-defined inputs +% ------------------------------------------------------------------- + +% obs species to be processed (see ens_upd_inputs.nml for a list) +% +% (only observation species that represent observations of the same +% model prognostic or diagnostic can be processed together!) + +nodata = -9999; +nodata_tol = 1e-4; + +% minimum number of data points to include in window statistics + +% N_data_min = w_days/10.; % initial screening on minimum # points in a +% % window to calculate a mean or stdv +% include a final decision about "good" stats later, when merging years + +% no-data-value for points that don't have good statistics + +no_data_stats = -9999.; + +disp('ASSUMING ACAT observations/undefined observation grid'); + +% output specs + +overwrite = 1; + +if combine_species_stats + N_species = 1; +else + N_species = length(species); +end + +Nf = 5; %5 fields per species +N_pentads = 73; + +write_ind_latlon = 'latlon_id'; %'latlon'; + +% tmp_shift_lon = 0.01; +% tmp_shift_lat = 0.005; + +% More user switches that could be moved +store_all_025_latlon = 0; +print_each_DOY = 0; +print_each_pentad = 1; +print_all_pentads = 1; + +% ------------------------------------------------------------------- +% end user-defined inputs +% ------------------------------------------------------------------- + +% assemble input and output paths + +%inpath = [ exp_path, '/output/', exp_run, '/', domain ]; +inpath = [ exp_path, '/', exp_run, '/output/', domain ]; + +outpath = [ inpath, '/stats/z_score_clim/' ]; + +% create outpath if it doesn't exist +if exist(outpath)~=2 + eval(['!mkdir -p ', outpath]); +end + +% ------------------------------------------------------------- + +% assemble output file name + +ind = find(start_year == min(start_year)); +mi_m = min(run_months(ind)); +ind = find(end_year == max(end_year)); +ma_m = max(run_months(ind)); + +D(1) = 1; +P(1) = 1; +if mi_m > 1 + D(1) = sum(days_in_month( 2014, [1:mi_m-1]))+1; + P(1) = ceil(D(1)/5); +end +if ma_m > 1 + D(2) = sum(days_in_month( 2014, [1:ma_m])); +else + D(2) = 1; +end +P(2) = floor(D(2)/5); + +if run_months(1) ~= run_months(end) && run_months(2) ~= run_months(end) + disp('WARNING: incomplete pentad-windows; loop through additional months to get complete pentads'); +end + +fname_out_base = [ outpath, '/', prefix, ... + num2str(min(start_year)),'_doy',num2str(D(1)),'_',... + num2str(max(end_year)), '_doy',num2str(D(2)),... + '_hscale_', num2str(hscale,'%2.2f'), '_', ... + 'W_', num2str(w_days),'d_Nmin_', num2str(Ndata_min)]; + +fname_out_base_p = [ outpath, '/', prefix, ... + num2str(min(start_year)),'_p',num2str(P(1)),'_',... + num2str(max(end_year)), '_p',num2str(P(2)),... + '_hscale_', num2str(hscale,'%2.2f'), '_', ... + 'W_', num2str(round(w_days/5)),'p_Nmin_', num2str(Ndata_min)]; + +%============================================================== +% Some clunky code to maintain backwards compatibility with adding orbit +% tag + +% Initialize counters for cells ending in "_A" and cells ending in "_D" +a_count = 0; +d_count = 0; + +% Loop through each cell in the array +for i = 1:numel(species_names) + % Check if the text in the cell ends with either "_A" or "_D" + if endsWith(species_names{i}, '_A') + % If it ends with "_A", increment the "_A" counter + a_count = a_count + 1; + elseif endsWith(species_names{i}, '_D') + % If it ends with "_D", increment the "_D" counter + d_count = d_count + 1; + end + + if startsWith(species_names{i}, 'SMAP') + inc_angle = [40.0]; + else + inc_angle = [-999.9]; + end + +end + +% Determine the output based on the values of the "_A" and "_D" counters +if a_count == numel(species_names) + % Both cells end in "_A" + disp('All species are "_A"'); + Orbit_tag = '_A'; + int_Asc = 1; +elseif d_count == numel(species_names) + % Both cells end in "_D" + disp('All species are "_D"'); + Orbit_tag = '_D'; + int_Asc = 2; +elseif a_count > 0 && d_count > 0 + % There is a mix of "_A" and "_D" + disp('Spcies have a mix of "_A" and "_D"'); + Orbit_tag = '_AD'; + int_Asc = 3; +else + % Neither cell ends in "_A" or "_D" + disp('Neither cell ends in "_A" or "_D"'); + Orbit_tag = '_NoOrbits'; + int_Asc = 4; +end + +fname_out_base = [fname_out_base, Orbit_tag]; +fname_out_base_p = [fname_out_base_p, Orbit_tag]; + +if exist( 'time_of_day_in_hours', 'var') + + fname_out_base = [fname_out_base, '_', num2str(time_of_day_in_hours,'%2.2d'), 'z']; + fname_out_base_p = [fname_out_base_p, '_', num2str(time_of_day_in_hours,'%2.2d'), 'z']; + +end + +%====================================================== + +% ------------------------------------------------------------- +% Define our 1/4 degree lat/lon grid +n_lon = 1440; +n_lat = 720; +ll_lon = -180; +ll_lat = -90; +d_lon = 0.25; +d_lat = 0.25; +ll_lons = linspace(-180, 179.75, 1440); +ll_lats = linspace(-90, 89.75, 720); +i_lon = (1:1440); +j_lat = (1:720); + +grid_idx = zeros(1036800,5); +grid_idx(:,1) = (1:1036800); +cnt = 0; +for i = 1:n_lon + for j = 1:n_lat + cnt = cnt+1; + grid_idx(cnt,2) = i_lon(i); + grid_idx(cnt,3) = j_lat(j); + grid_idx(cnt,4) = ll_lons(i); + grid_idx(cnt,5) = ll_lats(j); + end +end + +% ------------------------------------------------------------- + +obsnum = grid_idx(:,1); +i_out = grid_idx(:,2); +j_out = grid_idx(:,3); +lon_out = grid_idx(:,4); +lat_out = grid_idx(:,5); +N_gridcells = length(grid_idx); + +% Not sure about this as aren't centering lat/lons +if hscale>0 + + for i=1:N_gridcells + + this_lat = lat_out(i); + this_lon = lon_out(i); + + tmp_sq_distance = ... + (lon_out - this_lon).^2 + ... + (lat_out - this_lat).^2; + + hscale_ind{i} = find( tmp_sq_distance <= hscale^2 ); + end + +else + + hscale_ind = num2cell(obsnum); + +end + + +% initialize output statistics +% Note: Rolf suggests to have all species as one dimension, rather than +% N_pol and N_angle be specified here. Then subsample specifically +% when the files are written out. + +o_data = NaN+zeros(N_species, N_gridcells, w_days); +m_data = NaN+zeros(N_species, N_gridcells, w_days); +o_data2 = NaN+zeros(N_species, N_gridcells, w_days); +m_data2 = NaN+zeros(N_species, N_gridcells, w_days); +N_data = NaN+zeros(N_species, N_gridcells, w_days); + +data_out = NaN+zeros(N_species, Nf, N_gridcells, N_pentads); +data2D = NaN+zeros(Nf, N_gridcells); + +% ------------------------------------------------------------- + +% make sure t0_assim is *first* analysis time in a day + +t0_assim = mod( t0_assim, dt_assim ); + +count = 0; + +for imonth = 1:length(run_months) + month = run_months(imonth); + +for day = 1:days_in_month( 2014, month) %2014 = random non-leap year + + if count < w_days + count = count + 1; + else + count = w_days; + end + + for seconds_in_day = t0_assim:dt_assim:(86400-1) + + hour = floor(seconds_in_day/3600); + + % check if diurnal stats are needed + + if exist('time_of_day_in_hours','var') + tmp_hour = time_of_day_in_hours; + else + tmp_hour = hour; % all hours of day will be included + end + + if hour==tmp_hour + + minute = floor( (seconds_in_day-hour*3600)/60 ); + + seconds = seconds_in_day-hour*3600-minute*60; + + if (seconds~=0) + input('something is wrong! Ctrl-c now') + end + + + for year = start_year(imonth):end_year(imonth) + + YYYYMMDD = [ num2str(year, '%4.4d'), ... + num2str(month, '%2.2d'), ... + num2str(day, '%2.2d') ]; + + HHMM = [ num2str(hour, '%2.2d'), ... + num2str(minute, '%2.2d') ]; + + % read innov files + + fname = [ inpath, '/ana/ens_avg/', ... + 'Y', YYYYMMDD(1:4), '/', ... + 'M', YYYYMMDD(5:6), '/', ... + exp_run, '.ens_avg.ldas_ObsFcstAna.', ... + YYYYMMDD, '_', HHMM, 'z.bin' ]; + + ifp = fopen( fname, 'r', 'l' ); + + if (ifp > 0) %Proceed only if file exists (e.g. irregular SMOS swaths!) + + fclose(ifp); + + [date_time, ... + obs_assim, ... + obs_species, ... + obs_tilenum, ... + obs_lon, ... + obs_lat, ... + obs_obs, ... + obs_obsvar, ... + obs_fcst, ... + obs_fcstvar, ... + obs_ana, ... + obs_anavar ... + ] = ... + read_ObsFcstAna( fname ); + + % remove tiles when there is no obs_fcst (obs_fcst == 0 in innov output when + % missing) + + idx = find(obs_fcst == 0); + obs_assim(idx) = []; + obs_species(idx) = []; + obs_tilenum(idx) =[]; + obs_lon(idx) =[]; + obs_lat(idx) = []; + obs_obs(idx) = []; + obs_obsvar(idx) = []; + obs_fcst(idx) = []; + obs_fcstvar(idx) = []; + obs_ana(idx) = []; + obs_anavar(idx) = []; + + % extract species of interest + + ind = []; + + %for this_species = species + for scnt = 1:N_species + + if combine_species_stats % We are combining stats + ind = find(ismember(obs_species, species)); + this_species = species(scnt); % Only first species in list. But only used in determining angle and pol for species, which shouldn't vary between species being combined + else + ind = find( obs_species == this_species); + end + + if (~isempty(ind)) + + obs_tilenum_i = obs_tilenum(ind); + obs_obs_i = obs_obs(ind); + obs_fcst_i = obs_fcst(ind); + obs_lon_i = obs_lon(ind); + obs_lat_i = obs_lat(ind); + + % Check if any location receives more than 1 obs (or 1 species) + + tmp = sort(obs_tilenum_i); + same_tile = find(diff(tmp)==0, 1); + + if (~isempty(same_tile) && combine_species_stats==0) + error('multiple obs of the same species at one location? - only last one in line is used'); + end + + % Organize the data in a big matrix + + pol = obs_param(this_species == [obs_param.species]).pol; + + % Only writes lat-lon at exact obs locations, but with + % hscale>0, these obs are spread outside their exact + % location. This allows to calculate stats at lan-lons + % where no obs are available. + + %lon_out(obs_tilenum_i) = obs_lon_i; + %lat_out(obs_tilenum_i) = obs_lat_i; + + %obs_lat/lon are the actual M36 lat/lons, *not* the + %administering tiles, so the lat/lons for the obs and those + %in the tile_coord would not be identical. + %Still, they should be in the + %neighbourhood, so check here if that is true. +% if (any(abs(tile_coord.com_lat(obs_tilenum_i)-obs_lat_i) > tol) || ... +% any(abs(tile_coord.com_lon(obs_tilenum_i)-obs_lon_i) > tol) ) +% error('Something wrong with tile_lat/lon') +% end + + %map model tiles (e.g. all M09) to observation administering + %tiles (could be a reduced subset of all M09) + %-------------------------------------------------------- +% obs_i = obsnum(obs_tilenum_i); + %-------------------------------------------------------- + + % Put obs lat/lon on our grid and figure out obsnum/grid + % index + + i_idx = floor((obs_lon_i - ll_lon)/d_lon) + 1; + j_idx = floor((obs_lat_i - ll_lat)/d_lat) + 1; + [~, obs_idx] = ismember([i_idx, j_idx], [i_out, j_out], 'rows'); + + obs_i = obsnum(obs_idx); + + if (hscale == 0) + + %11 May 2015: sum the obs and fcst within each day; + %and across years! + %some obs can be found at multiple hours within a day + %e.g. at the poles. + %**nansum of NaN's** result in zero, this need to be + %taken care of + o_data(scnt,obs_i,count) = nansum([o_data(scnt,obs_i,count); obs_obs_i' ]); + m_data(scnt,obs_i,count) = nansum([m_data(scnt,obs_i,count); obs_fcst_i']); + + %X^2 + o_data2(scnt,obs_i,count) = nansum([o_data2(scnt,obs_i,count); obs_obs_i'.^2 ]); + m_data2(scnt,obs_i,count) = nansum([m_data2(scnt,obs_i,count); obs_fcst_i'.^2]); + + %Sum of obs or model elements at each location + N_data(scnt,obs_i,count) = nansum([N_data(scnt,obs_i,count); ~isnan([obs_obs_i])']); + + else + + for i_ind = 1:length(obs_obs_i) + + %introduce a spatial effect of each observation on + %neighbouring statistics (through hscale) + s_eff = unique(hscale_ind{obs_i(i_ind)}); + %hscale_ind =[obs space] % + + %Sum of X + o_data(scnt,obs_i,count) = ... + nansum([o_data(scnt,obs_i,count); repmat(obs_obs_i(i_ind),1,length(s_eff))]); + m_data(scnt,obs_i,count) = ... + nansum([m_data(pol(1),s_eff,angle_i,count); repmat(obs_fcst_i(i_ind),1,length(s_eff))]); + + %Sum of X^2 + o_data2(scnt,obs_i,count) = ... + nansum([o_data2(scnt,obs_i,count); repmat(obs_obs_i(i_ind).^2,1,length(s_eff))]); + m_data2(scnt,obs_i,count) = ... + nansum([m_data2(scnt,obs_i,count); repmat(obs_fcst_i(i_ind).^2,1,length(s_eff))]); + + %Sum of obs or model elements at each location + N_data(scnt,obs_i,count) = ... + nansum([N_data(scnt,obs_i,count); repmat(~isnan([obs_obs_i(i_ind)]),1,length(s_eff)) ]); + + end + + end + + end + + end + + end % if file present + + end % loop over multiple years + + end % time_of_day_in_hours + + end % seconds_in_day + + %count = count+1; + + if count >= w_days %wait initially until enough data is built up + + end_time.year = 2014; + end_time.month = month; + end_time.day = day; + end_time.hour = hour; + end_time.min = minute; + end_time.sec = seconds; + + start_time = augment_date_time( -floor(w_days*(24*60*60)), end_time ); + + % At the end of each day, collect the obs and fcst of the last + % w_day period, and write out a statistics-file at [w_day - floor(w_day/2)] + + o_data(abs(o_data - nodata) <= nodata_tol) = NaN; + m_data(abs(o_data - nodata) <= nodata_tol) = NaN; + + % data_out = zeros(N_out_fields,1:N_tiles,N_angle); + + for i = 1:N_species + + N_hscale_window = nansum(N_data(i,:,1:w_days),3); + + if w_days == 95 + N_hscale_inner_window = nansum(N_data(i,:,((w_days+1)/2-15):((w_days+1)/2+15)),3); + end + + % OBSERVATIONS + %---------------- + %o_data is a sum over neighbouring obs above; + %here then take a sum over the time steps in the window + data2D(1,:) = nansum(o_data(i,:,1:w_days),3); + + %then make the average, by dividing over the sum of the number of + %timesteps and influencing obs at each location + data2D(1,:) = data2D(1,:)./N_hscale_window; + + %stdv_H = sqrt(E[X^2] - E[X]^2) + data2D(2,:) = nansum(o_data2(i,:,1:w_days),3); + data2D(2,:) = data2D(2,:)./N_hscale_window; + data2D(2,:) = sqrt( data2D(2,:) - data2D(1,:).^2); + + % MODEL + %---------------- + data2D(3,:) = nansum(m_data(i,:,1:w_days),3); + data2D(3,:) = data2D(3,:)./N_hscale_window; + + data2D(4,:) = nansum(m_data2(i,:,1:w_days),3); + data2D(4,:) = data2D(4,:)./N_hscale_window; + data2D(4,:) = sqrt( data2D(4,:) - data2D(4,:).^2); + + data2D(5,:) = N_hscale_window; + + % Toss out stats that are based on too little data + + data2D([1:Nf],N_hscale_window=59) + DOY = DOY-1; + error('This code should never hit a leap year'); + end + + + fname_out = [fname_out_base_s, '_DOY', num2str(DOY,'%3.3d'), '.nc4']; + + % check whether output file exists + if (exist(fname_out)==2 && overwrite) + disp(['output file exists. overwriting', fname_out]) + elseif (exist(fname_out)==2 && ~overwrite) + disp(['output file exists. not overwriting. returning']) + disp(['writing ', fname_out]) + return + else + disp(['creating ', fname_out]) + end + + % compress data before writing in file. + + %idx_keep = find(any(abs(data_out -nodata) > nodata_tol,1)); + %lon_out_write = lon_out(idx_keep); + %lat_out_write = lat_out(idx_keep); + %data_out_write = data_out(:,idx_keep); + %tile_coord_tile_id_write = tile_coord_tile_id(idx_keep); + + + % write output for each DOY, sorted by all tile + if print_each_DOY + write_netcdf_file_2D_grid(fname_out, i_out, j_out, lon_out, lat_out, ... + inc_angle, data2D, int_Asc, pentad, ... %instead of writing the version#, write pentad + start_time, end_time, overwrite, ... + Nf, write_ind_latlon, 'scaling',... + obsnum) + else + % if DOY is at middle of pentad, then copy the DOY to a pentad file + % DOY = pentad*5 - 2; ==> pentad = (DOY + 2)/5; + pentad = (DOY + 2)/5; + if mod((DOY + 2),5) == 0 + data_out(i,:,:,pentad) = data2D; + start_time_p(pentad) = start_time; + end_time_p(pentad) = end_time; + if print_each_pentad + write_netcdf_file_2D_grid(fname_out, i_out, j_out, lon_out, lat_out, ... + inc_angle, data2D, int_Asc, pentad, ... + start_time, end_time, overwrite, ... + Nf, write_ind_latlon, 'scaling',... + obsnum) + fname_out_p = [fname_out_base_p, '_p', num2str(pentad,'%2.2d'), '.nc4']; + copyfile(fname_out,fname_out_p); + end + end + + end + + %clear idx_keep lon_out_write lat_out_write data_out_write tile_coord_tile_id_write + + % shift the window by one day and make room for the next day at the end + + o_data(:,:,1:w_days-1) = o_data(:,:,2:w_days); + m_data(:,:,1:w_days-1) = m_data(:,:,2:w_days); + o_data2(:,:,1:w_days-1) = o_data2(:,:,2:w_days); + m_data2(:,:,1:w_days-1) = m_data2(:,:,2:w_days); + N_data(:,:,1:w_days-1) = N_data(:,:,2:w_days); + + o_data(:,:,w_days) = NaN; + m_data(:,:,w_days) = NaN; + o_data2(:,:,w_days) = NaN; + m_data2(:,:,w_days) = NaN; + N_data(:,:,w_days) = NaN; + + data2D = NaN+0.0.*data2D; + + end + + end + +end % day +end % month + +if print_all_pentads + for i = 1:N_species + data_o = squeeze(data_out(i,:,:,:)); + + if combine_species_stats % We are combining stats + fname_out = [fname_out_base(1:startidx-1) 'z_score_clim/combined_all_pentads_', fname_out_base(endidx:end),'.nc4']; + else + fname_out = [fname_out_base(1:startidx-1) 'z_score_clim/', char(species_names(i)),'_all_pentads_', fname_out_base(endidx:end),'.nc4']; + end + + write_netcdf_file_2D_grid(fname_out, i_out, j_out, lon_out, lat_out, ... + inc_angle, data_o, int_Asc, [1:73], ... + start_time_p, end_time_p, overwrite, ... + Nf, write_ind_latlon, 'scaling',... + obsnum) + end +end + + +% ==================== EOF ============================================== diff --git a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/write_netcdf_file.m b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/write_netcdf_file.m index 221efe4a..f8930218 100644 --- a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/write_netcdf_file.m +++ b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/write_netcdf_file.m @@ -1,12 +1,15 @@ function [] = write_netcdf_file(fname, colind, rowind,... + lon_out, lat_out,... av_angle_bin, data, asc_flag,... - version, ... + pentad, ... start_time, end_time, overwrite, N_out_fields, ... write_ind_latlon, data_product,... - tile_id) %last argument is optional + obsnum) %last argument is optional int_precision = 'NC_INT'; % precision of fortran tag float_precision = 'NC_DOUBLE'; % precision of data in input file + + version = 0; % check dimensions if size(data,1)~=N_out_fields @@ -29,16 +32,31 @@ else disp(['writing ', fname]) end - - % Calculate tmp_start_time tmp_end_time in days since January 1 1950 - d = datetime(start_time.year, start_time.month, start_time.day, start_time.hour, start_time.min, start_time.sec); + + % Convert the cell arrays to matrices using cell2mat (to deal with all_pentad case) + year_mat = cell2mat({start_time.year}'); + month_mat = cell2mat({start_time.month}'); + day_mat = cell2mat({start_time.day}'); + hour_mat = cell2mat({start_time.hour}'); + min_mat = cell2mat({start_time.min}'); + sec_mat = cell2mat({start_time.sec}'); + % Use the matrices as input to the datetime function + d = datetime(year_mat, month_mat, day_mat, hour_mat, min_mat, sec_mat); % Convert to serial date number serialNum = datenum(d); % Subtract serial date number of January 1, 1950 daysSince1950 = serialNum - datenum('January 1, 1950'); tmp_start_time = daysSince1950; - d = datetime(end_time.year, end_time.month, end_time.day, end_time.hour, end_time.min, end_time.sec); + % Convert the cell arrays to matrices using cell2mat (to deal with all_pentad case) + year_mat = cell2mat({end_time.year}'); + month_mat = cell2mat({end_time.month}'); + day_mat = cell2mat({end_time.day}'); + hour_mat = cell2mat({end_time.hour}'); + min_mat = cell2mat({end_time.min}'); + sec_mat = cell2mat({end_time.sec}'); + % Use the matrices as input to the datetime function + d = datetime(year_mat, month_mat, day_mat, hour_mat, min_mat, sec_mat); % Convert to serial date number serialNum = datenum(d); % Subtract serial date number of January 1, 1950 @@ -48,14 +66,18 @@ % determine number of grid cells ; further check dimensions N_grid = size(data,2); N_angle= 1; - N_pentad = 1; + if ndims(data) ==2 + N_pentad = 1; + else + N_pentad = 73; + end if (strcmp(write_ind_latlon,'latlon_id') && nargin == 14) - if( size(tile_id,1) ~= N_grid ) + if( size(obsnum,1) ~= N_grid ) error('tile_id dimensions ??') end - if ( size(tile_id,2) > 1) - disp(['# subgridcells per gridcell: ',num2str(size(tile_id,2))]); + if ( size(obsnum,2) > 1) + disp(['# subgridcells per gridcell: ',num2str(size(obsnum,2))]); end end @@ -66,7 +88,7 @@ % define dimensions dimid_grid = netcdf.defDim(ncid, 'grid', N_grid); dimid_angle = netcdf.defDim(ncid, 'angle', N_angle); -dimid_tile = netcdf.defDim(ncid, 'tile', size(tile_id,2)); +dimid_tile = netcdf.defDim(ncid, 'tile', size(obsnum,2)); dimid_pentad = netcdf.defDim(ncid, 'pentad', N_pentad); % define variables @@ -88,10 +110,12 @@ varid_N_grid = netcdf.defVar(ncid, 'N_grid', int_precision, []); varid_N_angle = netcdf.defVar(ncid, 'N_angle', int_precision, []); -varid_tile_id = netcdf.defVar(ncid, 'tile_id', int_precision, [dimid_grid dimid_tile]); +varid_obsnum = netcdf.defVar(ncid, 'obs_num', int_precision, [dimid_grid dimid_tile]); varid_av_angle_bin = netcdf.defVar(ncid, 'av_angle_bin', float_precision, [dimid_angle]); varid_colind = netcdf.defVar(ncid, 'colind', float_precision, [dimid_grid]); varid_rowind = netcdf.defVar(ncid, 'rowind', float_precision, [dimid_grid]); +varid_lon = netcdf.defVar(ncid, 'lon', float_precision, [dimid_grid]); +varid_lat = netcdf.defVar(ncid, 'lat', float_precision, [dimid_grid]); % Create a new group called 'data' groupname = 'data'; @@ -109,16 +133,16 @@ % write data netcdf.putVar(ncid, varid_asc_flag, asc_flag); netcdf.putVar(ncid, varid_version, version); -netcdf.putVar(ncid, varid_pentad, start_time.pentad); +netcdf.putVar(ncid, varid_pentad, pentad); netcdf.putVar(ncid, varid_start_time, tmp_start_time); netcdf.putVar(ncid, varid_end_time, tmp_end_time); netcdf.putVar(ncid, varid_N_grid, N_grid); netcdf.putVar(ncid, varid_N_angle, N_angle); if (~(strcmp(data_product,'scaling') && strcmp(write_ind_latlon,'latlon_id') && nargin == 14)) - netcdf.putVar(ncid, varid_tile_id, tile_id); + netcdf.putVar(ncid, varid_obsnum, obsnum); else - netcdf.putVar(ncid, varid_tile_id, permute(tile_id, [2 1])); + netcdf.putVar(ncid, varid_obsnum, permute(obsnum, [2 1])); end netcdf.putVar(ncid, varid_av_angle_bin, squeeze(av_angle_bin(:))); @@ -127,16 +151,27 @@ netcdf.putVar(ncid, varid_colind, colind); netcdf.putVar(ncid, varid_rowind, rowind); - - netcdf.putVar(grpid,varid_om,data(1,:)); -netcdf.putVar(grpid,varid_ov,data(2,:)); -netcdf.putVar(grpid,varid_mm,data(3,:)); -netcdf.putVar(grpid,varid_mv,data(4,:)); -netcdf.putVar(grpid,varid_ndata,data(5,:)); - +netcdf.putVar(ncid, varid_lon, lon_out); +netcdf.putVar(ncid, varid_lat, lat_out); + +if N_pentad ==1 + netcdf.putVar(grpid,varid_om,data(1,:)); + netcdf.putVar(grpid,varid_ov,data(2,:)); + netcdf.putVar(grpid,varid_mm,data(3,:)); + netcdf.putVar(grpid,varid_mv,data(4,:)); + netcdf.putVar(grpid,varid_ndata,data(5,:)); +else + netcdf.putVar(grpid,varid_om,data(1,:,:)); + netcdf.putVar(grpid,varid_ov,data(2,:,:)); + netcdf.putVar(grpid,varid_mm,data(3,:,:)); + netcdf.putVar(grpid,varid_mv,data(4,:,:)); + netcdf.putVar(grpid,varid_ndata,data(5,:,:)); +end else netcdf.putVar(ncid, varid_colind, 0.0); -netcdf.putVar(ncid, varid_rowind, 0.0); + netcdf.putVar(ncid, varid_rowind, 0.0); + netcdf.putVar(ncid, varid_lon, 0.0); + netcdf.putVar(ncid, varid_lat, 0.0) netcdf.putVar(grpid,varid_om,-999.0); netcdf.putVar(grpid,varid_ov,-999.0); diff --git a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/write_netcdf_file_2D_grid.m b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/write_netcdf_file_2D_grid.m new file mode 100644 index 00000000..79b508ef --- /dev/null +++ b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/write_netcdf_file_2D_grid.m @@ -0,0 +1,223 @@ + function [] = write_netcdf_file_2D_grid(fname, colind, rowind,... + lon_out, lat_out,... + av_angle_bin, data, asc_flag,... + pentad, ... + start_time, end_time, overwrite, N_out_fields, ... + write_ind_latlon, data_product,... + obsnum) %last argument is optional + + int_precision = 'NC_INT'; % precision of fortran tag + float_precision = 'NC_DOUBLE'; % precision of data in input file + + version = 0; + + % check dimensions + if size(data,1)~=N_out_fields + error('ERROR: size of data incompatible with N_out_fields') + end + + % check for presence of optional input "overwrite" + if ~exist('overwrite','var') + overwrite = 0; % default: do NOT overwrite existing files + end + + % check if file exists + if exist(fname,'file') + if overwrite==0 + disp(['RETURNING!!! -- NOT OVERWRITING EXISTING FILE ', fname]) + return + else + disp(['OVERWRITING ', fname]) + end + else + disp(['writing ', fname]) + end + + % Convert the cell arrays to matrices using cell2mat (to deal with all_pentad case) + year_mat = cell2mat({start_time.year}'); + month_mat = cell2mat({start_time.month}'); + day_mat = cell2mat({start_time.day}'); + hour_mat = cell2mat({start_time.hour}'); + min_mat = cell2mat({start_time.min}'); + sec_mat = cell2mat({start_time.sec}'); + % Use the matrices as input to the datetime function + d = datetime(year_mat, month_mat, day_mat, hour_mat, min_mat, sec_mat); + % Convert to serial date number + serialNum = datenum(d); + % Subtract serial date number of January 1, 1950 + daysSince1950 = serialNum - datenum('January 1, 1950'); + tmp_start_time = daysSince1950; + + % Convert the cell arrays to matrices using cell2mat (to deal with all_pentad case) + year_mat = cell2mat({end_time.year}'); + month_mat = cell2mat({end_time.month}'); + day_mat = cell2mat({end_time.day}'); + hour_mat = cell2mat({end_time.hour}'); + min_mat = cell2mat({end_time.min}'); + sec_mat = cell2mat({end_time.sec}'); + % Use the matrices as input to the datetime function + d = datetime(year_mat, month_mat, day_mat, hour_mat, min_mat, sec_mat); + % Convert to serial date number + serialNum = datenum(d); + % Subtract serial date number of January 1, 1950 + daysSince1950 = serialNum - datenum('January 1, 1950'); + tmp_end_time = daysSince1950; + + % determine number of grid cells ; further check dimensions + N_grid = size(data,2); + N_angle= 1; + if ndims(data) ==2 + N_pentad = 1; + else + N_pentad = 73; + end + + N_lon = 1440; + N_lat = 720; + + ll_lons = linspace(-180, 179.75, 1440); + ll_lats = linspace(-90, 89.75, 720); + + if (strcmp(write_ind_latlon,'latlon_id') && nargin == 14) + if( size(obsnum,1) ~= N_grid ) + error('tile_id dimensions ??') + end + if ( size(obsnum,2) > 1) + disp(['# subgridcells per gridcell: ',num2str(size(obsnum,2))]); + end + end + +% create netCDF file +netcdf.setDefaultFormat('FORMAT_NETCDF4'); +ncid = netcdf.create(fname, 'NETCDF4'); + +% define dimensions +dimid_grid = netcdf.defDim(ncid, 'grid', N_grid); +dimid_angle = netcdf.defDim(ncid, 'angle', N_angle); +dimid_tile = netcdf.defDim(ncid, 'tile', size(obsnum,2)); +dimid_pentad = netcdf.defDim(ncid, 'pentad', N_pentad); +dimid_lon = netcdf.defDim(ncid, 'lon', N_lon); +dimid_lat = netcdf.defDim(ncid, 'lat', N_lat); + +% define variables +varid_asc_flag = netcdf.defVar(ncid, 'asc_flag', int_precision, []); +varid_version = netcdf.defVar(ncid, 'version', int_precision, []); +varid_pentad = netcdf.defVar(ncid, 'pentad', int_precision, [dimid_pentad]); + +varid_start_time = netcdf.defVar(ncid, 'start_time', float_precision, [dimid_pentad]); +netcdf.putAtt(ncid, varid_start_time, 'standard_name','start time'); +netcdf.putAtt(ncid, varid_start_time, 'long_name','start time'); +netcdf.putAtt(ncid, varid_start_time, 'axis','T'); +netcdf.putAtt(ncid, varid_start_time, 'units','days since 1950-01-01 00:00:00.0 +0000'); + +varid_end_time = netcdf.defVar(ncid, 'end_time',float_precision, [dimid_pentad]); +netcdf.putAtt(ncid, varid_end_time, 'standard_name','end time'); +netcdf.putAtt(ncid, varid_end_time, 'long_name','end time'); +netcdf.putAtt(ncid, varid_end_time, 'axis','T'); +netcdf.putAtt(ncid, varid_end_time, 'units','days since 1950-01-01 00:00:00.0 +0000'); + +varid_N_grid = netcdf.defVar(ncid, 'N_grid', int_precision, []); +varid_N_angle = netcdf.defVar(ncid, 'N_angle', int_precision, []); +varid_obsnum = netcdf.defVar(ncid, 'obs_num', int_precision, [dimid_grid dimid_tile]); +varid_av_angle_bin = netcdf.defVar(ncid, 'av_angle_bin', float_precision, [dimid_angle]); +varid_colind = netcdf.defVar(ncid, 'colind', float_precision, [dimid_grid]); +varid_rowind = netcdf.defVar(ncid, 'rowind', float_precision, [dimid_grid]); +varid_lon = netcdf.defVar(ncid, 'lon', float_precision, [dimid_lon]); +varid_lat = netcdf.defVar(ncid, 'lat', float_precision, [dimid_lat]); + +% Create a new group called 'data' +% groupname = 'data'; +% grpid = netcdf.defGrp(ncid,groupname); + +% varid_om = netcdf.defVar(grpid, 'o_mean', float_precision, [dimid_lon dimid_lat dimid_pentad]); +% varid_ov = netcdf.defVar(grpid, 'o_std', float_precision, [dimid_lon dimid_lat dimid_pentad]); +% varid_mm = netcdf.defVar(grpid, 'm_mean', float_precision, [dimid_lon dimid_lat dimid_pentad]); +% varid_mv = netcdf.defVar(grpid, 'm_std', float_precision, [dimid_lon dimid_lat dimid_pentad]); +% varid_ndata = netcdf.defVar(grpid, 'n_data', float_precision, [dimid_lon dimid_lat dimid_pentad]); + +varid_om = netcdf.defVar(ncid, 'o_mean', float_precision, [dimid_lat dimid_lon dimid_pentad]); +varid_ov = netcdf.defVar(ncid, 'o_std', float_precision, [dimid_lat dimid_lon dimid_pentad]); +varid_mm = netcdf.defVar(ncid, 'm_mean', float_precision, [dimid_lat dimid_lon dimid_pentad]); +varid_mv = netcdf.defVar(ncid, 'm_std', float_precision, [dimid_lat dimid_lon dimid_pentad]); +varid_ndata = netcdf.defVar(ncid, 'n_data', float_precision, [dimid_lat dimid_lon dimid_pentad]); + + +% end define mode +netcdf.endDef(ncid); + +% write data +netcdf.putVar(ncid, varid_asc_flag, asc_flag); +netcdf.putVar(ncid, varid_version, version); +netcdf.putVar(ncid, varid_pentad, pentad); +netcdf.putVar(ncid, varid_start_time, tmp_start_time); +netcdf.putVar(ncid, varid_end_time, tmp_end_time); +netcdf.putVar(ncid, varid_N_grid, N_grid); +netcdf.putVar(ncid, varid_N_angle, N_angle); + +if (~(strcmp(data_product,'scaling') && strcmp(write_ind_latlon,'latlon_id') && nargin == 14)) + netcdf.putVar(ncid, varid_obsnum, obsnum); +else + netcdf.putVar(ncid, varid_obsnum, permute(obsnum, [2 1])); +end + +netcdf.putVar(ncid, varid_av_angle_bin, squeeze(av_angle_bin(:))); + + if (N_grid >= 1) + +netcdf.putVar(ncid, varid_colind, colind); +netcdf.putVar(ncid, varid_rowind, rowind); +netcdf.putVar(ncid, varid_lon, ll_lons); +netcdf.putVar(ncid, varid_lat, ll_lats); + +if N_pentad ==1 + + data_out = ones(5,N_lat, N_lon) * -999.0; + + for n = 1:5 + for i = 1:length(colind) + data_out(n,rowind(i),colind(i)) = data(n,i); + end + end + + netcdf.putVar(ncid,varid_om,data_out(1, :, :)); + netcdf.putVar(ncid,varid_ov,data_out(2, :, :)); + netcdf.putVar(ncid,varid_mm,data_out(3, :, :)); + netcdf.putVar(ncid,varid_mv,data_out(4, :, :)); + netcdf.putVar(ncid,varid_ndata,data_out(5, :, :)); +else + + data_out = ones(5, N_lat,N_lon,N_pentad) * -999.0; + + for n = 1:5 + for i = 1:length(colind) + data_out(n,rowind(i),colind(i),:) = data(n,i,:); + end + end + + netcdf.putVar(ncid,varid_om,data_out(1, :, :,:)); + netcdf.putVar(ncid,varid_ov,data_out(2, :, :,:)); + netcdf.putVar(ncid,varid_mm,data_out(3, :, :,:)); + netcdf.putVar(ncid,varid_mv,data_out(4, :, :,:)); + netcdf.putVar(ncid,varid_ndata,data_out(5, :, :,:)); +end + + else + netcdf.putVar(ncid, varid_colind, 0.0); + netcdf.putVar(ncid, varid_rowind, 0.0); + netcdf.putVar(ncid, varid_lon, 0.0); + netcdf.putVar(ncid, varid_lat, 0.0) + + netcdf.putVar(ncid,varid_om,-999.0); + netcdf.putVar(ncid,varid_ov,-999.0); + netcdf.putVar(ncid,varid_mm,-999.0); + netcdf.putVar(ncid,varid_mv,-999.0); + netcdf.putVar(ncid,varid_ndata,-999.0); + end + +% close netCDF file +netcdf.close(ncid); + + end + + + From df2c5cf18a3879951eae0128fb0a35e804852cbf Mon Sep 17 00:00:00 2001 From: amfox37 Date: Mon, 1 May 2023 10:28:38 -0600 Subject: [PATCH 069/308] add ncdump header comment to netcdf write --- .../write_netcdf_file_2D_grid.m | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/write_netcdf_file_2D_grid.m b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/write_netcdf_file_2D_grid.m index 79b508ef..ee257858 100644 --- a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/write_netcdf_file_2D_grid.m +++ b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/write_netcdf_file_2D_grid.m @@ -6,6 +6,49 @@ write_ind_latlon, data_product,... obsnum) %last argument is optional + % Current output from ncdump of file generated by this script + % + % ncdump -h combined_all_pentads_M36_zscore_stats_2015_doy152_2017_doy151_hscale_0.00_W_75d_Nmin_20_AD.nc4 + % netcdf combined_all_pentads_M36_zscore_stats_2015_doy152_2017_doy151_hscale_0.00_W_75d_Nmin_20_AD { + % dimensions: + % grid = 1036800 ; + % angle = 1 ; + % tile = 1 ; + % pentad = 73 ; + % lon = 1440 ; + % lat = 720 ; + % variables: + % int asc_flag ; + % int version ; + % int pentad(pentad) ; + % double start_time(pentad) ; + % start_time:standard_name = "start time" ; + % start_time:long_name = "start time" ; + % start_time:axis = "T" ; + % start_time:units = "days since 1950-01-01 00:00:00.0 +0000" ; + % double end_time(pentad) ; + % end_time:standard_name = "end time" ; + % end_time:long_name = "end time" ; + % end_time:axis = "T" ; + % end_time:units = "days since 1950-01-01 00:00:00.0 +0000" ; + % int N_grid ; + % int N_angle ; + % int obs_num(tile, grid) ; + % double av_angle_bin(angle) ; + % double colind(grid) ; + % double rowind(grid) ; + % double lon(lon) ; + % double lat(lat) ; + % double o_mean(pentad, lon, lat) ; + % double o_std(pentad, lon, lat) ; + % double m_mean(pentad, lon, lat) ; + % double m_std(pentad, lon, lat) ; + % double n_data(pentad, lon, lat) ; + % } + + + + int_precision = 'NC_INT'; % precision of fortran tag float_precision = 'NC_DOUBLE'; % precision of data in input file From 26d00f55e9337e99fd6cee94c3cd68811219beec Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Tue, 16 May 2023 17:47:33 -0400 Subject: [PATCH 070/308] added CATCHMENT_SPINUP resource variable --- components.yaml | 2 +- src/Applications/LDAS_App/GEOSldas_LDAS.rc | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/components.yaml b/components.yaml index 72c66f77..c770c767 100644 --- a/components.yaml +++ b/components.yaml @@ -41,6 +41,6 @@ MAPL: GEOSgcm_GridComp: local: ./src/Components/GEOSldas_GridComp/@GEOSgcm_GridComp remote: ../GEOSgcm_GridComp.git - branch: develop + branch: feature/rreichle/catch_spinup_mode sparse: ./config/GEOSgcm_GridComp_ldas.sparse develop: develop diff --git a/src/Applications/LDAS_App/GEOSldas_LDAS.rc b/src/Applications/LDAS_App/GEOSldas_LDAS.rc index 8e35303b..9b462ae1 100644 --- a/src/Applications/LDAS_App/GEOSldas_LDAS.rc +++ b/src/Applications/LDAS_App/GEOSldas_LDAS.rc @@ -25,9 +25,16 @@ CATCHMENT_OFFLINE: 1 # 1 : Catchment model (default) # 2 : CatchmentCN-CLM4.0 # 3 : CatchmentCN-CLM4.5 - +# LSM_CHOICE: 1 +# ---- Catchment/CatchmentCN spinup mode +# +# 0 : None (default) +# 1 : Remove snow every Aug 1 (Northern Hemisphere) or Feb 1 (Southern Hemisphere) +# +CATCHMENT_SPINUP: 0 + # ---- Domain definition # From e4ac89ac2fdfcb66e10e7352965190404d88de43 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Thu, 18 May 2023 17:08:54 -0400 Subject: [PATCH 071/308] Reverting to develop version of components.yaml --- components.yaml | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/components.yaml b/components.yaml index 2b1ca047..d928990d 100644 --- a/components.yaml +++ b/components.yaml @@ -1,15 +1,18 @@ GEOSldas: fixture: true + develop: develop env: local: ./@env remote: ../ESMA_env.git tag: v4.9.1 + develop: main cmake: local: ./@cmake remote: ../ESMA_cmake.git tag: v3.28.0 + develop: develop ecbuild: local: ./@cmake/@ecbuild @@ -19,22 +22,25 @@ ecbuild: GMAO_Shared: local: ./src/Shared/@GMAO_Shared remote: ../GMAO_Shared.git - sparse: ./config/GMAO_Shared.sparse tag: v1.9.0 + sparse: ./config/GMAO_Shared.sparse + develop: main GEOS_Util: local: ./src/Shared/@GMAO_Shared/@GEOS_Util remote: ../GEOS_Util.git tag: v2.0.0 + develop: main MAPL: local: ./src/Shared/@MAPL remote: ../MAPL.git tag: v2.39.1 + develop: develop GEOSgcm_GridComp: local: ./src/Components/GEOSldas_GridComp/@GEOSgcm_GridComp remote: ../GEOSgcm_GridComp.git + branch: develop sparse: ./config/GEOSgcm_GridComp_ldas.sparse - tag: v2.1.1 - + develop: develop From 7beed5cfcb7da5d5bfefcdb23ac9be594ea2c51c Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Fri, 19 May 2023 11:12:06 -0400 Subject: [PATCH 072/308] updating ESMA_env to v4.16.0 --- components.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components.yaml b/components.yaml index d928990d..6f91c112 100644 --- a/components.yaml +++ b/components.yaml @@ -5,7 +5,7 @@ GEOSldas: env: local: ./@env remote: ../ESMA_env.git - tag: v4.9.1 + tag: v4.16.0 develop: main cmake: From b60ed63aa61720cd59b536de149e057f78d1a3aa Mon Sep 17 00:00:00 2001 From: amfox37 Date: Mon, 22 May 2023 14:33:36 -0400 Subject: [PATCH 073/308] remove some debug output --- .../GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 09c9a4c4..bb156389 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -8274,11 +8274,6 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & if ( abs(tile_coord(i)%com_lat-sclprm_lat(j_ind))>tol .or. & abs(tile_coord(i)%com_lon-sclprm_lon(i_ind))>tol ) then - if (logit) write (logunit,*) 'ierr2, i = ', ierr2, i - if (logit) write (logunit,*) 'start, icount', start, icount - if (logit) write (logunit,*) 'tile_coord(i)%com_lat, this_lat, sclprm_lat(j_ind)', tile_coord(i)%com_lat, this_lat, sclprm_lat(j_ind) - if (logit) write (logunit,*) 'tile_coord(i)%com_lon, this_lon, sclprm_lon(i_ind)', tile_coord(i)%com_lon, this_lon, sclprm_lon(i_ind) - if (logit) write (logunit,*) 'pp, sclprm_lon, sclprm_lat, sclprm_mean_obs(328:334,579) ', pp, sclprm_lon(1), sclprm_lat(1), sclprm_mean_obs(328:334, 579) err_msg = 'something wrong' call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) end if @@ -8293,10 +8288,6 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & ! scale via standard normal deviates - if (mod(i, 100) == 0) then - write(logunit,*) 'Found! ', i, pp, j_ind, i_ind, tmp_obs(i), sclprm_mean_obs(j_ind, i_ind), sclprm_std_mod(j_ind, i_ind), sclprm_std_obs(j_ind, i_ind) - endif - tmpreal = sclprm_std_mod(j_ind, i_ind)/sclprm_std_obs(j_ind, i_ind) tmp_obs(i) = sclprm_mean_mod(j_ind, i_ind) & @@ -8305,7 +8296,7 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & ! scale observation error std tmp_std_obs(i) = tmpreal*tmp_std_obs(i) - + else tmp_obs(i) = this_obs_param%nodata @@ -8319,7 +8310,7 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & deallocate(sclprm_lon) deallocate(sclprm_lat) deallocate(sclprm_mean_obs) -deallocate(sclprm_std_obs) +deallocate(sclprm_std_obs) deallocate(sclprm_mean_mod) deallocate(sclprm_std_mod) From 7d7598dd9f7e649aced76cae985e5824df91f48a Mon Sep 17 00:00:00 2001 From: amfox37 Date: Fri, 26 May 2023 17:01:28 -0400 Subject: [PATCH 074/308] bug fix --- .../get_model_and_obs_clim_stats_pentads_latlon.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats_pentads_latlon.m b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats_pentads_latlon.m index 2baf060f..b985caf3 100644 --- a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats_pentads_latlon.m +++ b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats_pentads_latlon.m @@ -591,7 +591,7 @@ data2D(4,:) = nansum(m_data2(i,:,1:w_days),3); data2D(4,:) = data2D(4,:)./N_hscale_window; - data2D(4,:) = sqrt( data2D(4,:) - data2D(4,:).^2); + data2D(4,:) = sqrt( data2D(4,:) - data2D(3,:).^2); data2D(5,:) = N_hscale_window; From 08b3f853b266c35f65b3e68f0e48469d6054ac6e Mon Sep 17 00:00:00 2001 From: amfox37 Date: Wed, 31 May 2023 15:47:57 -0600 Subject: [PATCH 075/308] added timing statements --- .../clsm_ensupd_read_obs.F90 | 49 +++++++++++++++++-- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index bb156389..2505a6e4 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -1551,7 +1551,7 @@ end subroutine read_obs_sm_ASCAT ! **************************************************************************** - subroutine read_obs_sm_ASCAT_EUMET( & + subroutine read_obs_sm_ASCAT_EUMET( & work_path, exp_id, & date_time, dtstep_assim, N_catd, tile_coord, & tile_grid_d, N_tile_in_cell_ij, tile_num_in_cell_ij, & @@ -1569,6 +1569,7 @@ subroutine read_obs_sm_ASCAT_EUMET( & ! ! Q. Liu, Nov. 2019. ! based on read_obs_sm_ASCAT + ! Minor updates A. Fox, march 2023 ! -------------------------------------------------------------------- implicit none @@ -1628,6 +1629,7 @@ subroutine read_obs_sm_ASCAT_EUMET( & type(date_time_type) :: date_time_upp integer :: i, ind, N_tmp, N_files + integer :: start_time, end_time, elapsed_time character(300), dimension(:), allocatable :: fnames @@ -1658,6 +1660,8 @@ subroutine read_obs_sm_ASCAT_EUMET( & ! --------------- ! initialize + + start_time = system_clock() found_obs = .false. @@ -1737,7 +1741,15 @@ subroutine read_obs_sm_ASCAT_EUMET( & end if close(10,status='delete') + + ! Get the end time + end_time = system_clock() + + ! Calculate the elapsed time in milliseconds + elapsed_time = (end_time - start_time) * 1000 / system_clock_rate() + write (logunit,*) 'Elapsed time file names: ', elapsed_time, ' milliseconds' + ! read observations: ! ! 1.) read N_tmp observations and their lat/lon info from file @@ -1750,6 +1762,9 @@ subroutine read_obs_sm_ASCAT_EUMET( & ! ! 1.) read N_tmp observations and their lat/lon info from file + + start_time = system_clock() + ! read and process data if files are found allocate(tmp1_lon(max_rec)) allocate(tmp1_lat(max_rec)) @@ -1872,6 +1887,14 @@ subroutine read_obs_sm_ASCAT_EUMET( & deallocate(tmp1_lat) deallocate(tmp1_obs) + ! Get the end time + end_time = system_clock() + + ! Calculate the elapsed time in milliseconds + elapsed_time = (end_time - start_time) * 1000 / system_clock_rate() + + write (logunit,*) 'Elapsed time bufr read: ', elapsed_time, ' milliseconds' + ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! ! SOME QC SHOULD BE DONE HERE!!! @@ -1886,6 +1909,8 @@ subroutine read_obs_sm_ASCAT_EUMET( & ! a) determine grid cell that contains lat/lon ! b) determine tile within grid cell that contains lat/lon + start_time = system_clock() + if (N_tmp>0) then allocate(tmp_tile_num(N_tmp)) @@ -1970,6 +1995,15 @@ subroutine read_obs_sm_ASCAT_EUMET( & end if end if + + + ! Get the end time + end_time = system_clock() + + ! Calculate the elapsed time in milliseconds + elapsed_time = (end_time - start_time) * 1000 / system_clock_rate() + + write (logunit,*) 'Elapsed time tile allocation: ', elapsed_time, ' milliseconds' ! clean up @@ -8274,6 +8308,11 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & if ( abs(tile_coord(i)%com_lat-sclprm_lat(j_ind))>tol .or. & abs(tile_coord(i)%com_lon-sclprm_lon(i_ind))>tol ) then + if (logit) write (logunit,*) 'ierr2, i = ', ierr2, i + if (logit) write (logunit,*) 'start, icount', start, icount + if (logit) write (logunit,*) 'tile_coord(i)%com_lat, this_lat, sclprm_lat(j_ind)', tile_coord(i)%com_lat, this_lat, sclprm_lat(j_ind) + if (logit) write (logunit,*) 'tile_coord(i)%com_lon, this_lon, sclprm_lon(i_ind)', tile_coord(i)%com_lon, this_lon, sclprm_lon(i_ind) + if (logit) write (logunit,*) 'pp, sclprm_lon, sclprm_lat, sclprm_mean_obs(328:334,579) ', pp, sclprm_lon(1), sclprm_lat(1), sclprm_mean_obs(328:334, 579) err_msg = 'something wrong' call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) end if @@ -8288,6 +8327,10 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & ! scale via standard normal deviates + if (mod(i, 100) == 0) then + write(logunit,*) 'Found! ', i, pp, j_ind, i_ind, tmp_obs(i), sclprm_mean_obs(j_ind, i_ind), sclprm_std_mod(j_ind, i_ind), sclprm_std_obs(j_ind, i_ind) + endif + tmpreal = sclprm_std_mod(j_ind, i_ind)/sclprm_std_obs(j_ind, i_ind) tmp_obs(i) = sclprm_mean_mod(j_ind, i_ind) & @@ -8296,7 +8339,7 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & ! scale observation error std tmp_std_obs(i) = tmpreal*tmp_std_obs(i) - + else tmp_obs(i) = this_obs_param%nodata @@ -8310,7 +8353,7 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & deallocate(sclprm_lon) deallocate(sclprm_lat) deallocate(sclprm_mean_obs) -deallocate(sclprm_std_obs) +deallocate(sclprm_std_obs) deallocate(sclprm_mean_mod) deallocate(sclprm_std_mod) From 9e5d8d416d342e1dd6d2c54f792346e8a9818c00 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Wed, 31 May 2023 19:29:23 -0400 Subject: [PATCH 076/308] fix corruption of LDAS_TileCoordRoutines.F90 --- .../GEOSldas_GridComp/Shared/LDAS_TileCoordRoutines.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/GEOSldas_GridComp/Shared/LDAS_TileCoordRoutines.F90 b/src/Components/GEOSldas_GridComp/Shared/LDAS_TileCoordRoutines.F90 index 488917fa..7ddd5b55 100644 --- a/src/Components/GEOSldas_GridComp/Shared/LDAS_TileCoordRoutines.F90 +++ b/src/Components/GEOSldas_GridComp/Shared/LDAS_TileCoordRoutines.F90 @@ -306,7 +306,7 @@ subroutine LDAS_create_grid_g( gridname, n_lon, n_lat, & i_indg_offset = 0 j_indg_offset = 0 - call init_grid_def_type( ) + call init_grid_def_type(tile_grid) tile_grid%N_lon = N_lon tile_grid%N_lat = N_lat From f5a0b9e081f5ae69ec36a8e5ab7f7e2a91159cdc Mon Sep 17 00:00:00 2001 From: amfox37 Date: Thu, 1 Jun 2023 11:22:44 -0600 Subject: [PATCH 077/308] system_clock calls --- .../clsm_ensupd_read_obs.F90 | 34 ++++++++----------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 2505a6e4..0e1472d8 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -1629,7 +1629,8 @@ subroutine read_obs_sm_ASCAT_EUMET( & type(date_time_type) :: date_time_upp integer :: i, ind, N_tmp, N_files - integer :: start_time, end_time, elapsed_time + integer :: clock_start, clock_end, clock_rate + real(8) :: elapsed_time character(300), dimension(:), allocatable :: fnames @@ -1661,7 +1662,8 @@ subroutine read_obs_sm_ASCAT_EUMET( & ! initialize - start_time = system_clock() + call system_clock(COUNT_RATE=clock_rate) ! Find the rate + call system_clock(COUNT=clock_start) ! Start timing found_obs = .false. @@ -1742,11 +1744,8 @@ subroutine read_obs_sm_ASCAT_EUMET( & close(10,status='delete') - ! Get the end time - end_time = system_clock() - - ! Calculate the elapsed time in milliseconds - elapsed_time = (end_time - start_time) * 1000 / system_clock_rate() + call system_clock(COUNT=clock_end) ! Stop timing + elapsed_time=REAL((clock_end-clock_start)/clock_rate) write (logunit,*) 'Elapsed time file names: ', elapsed_time, ' milliseconds' @@ -1762,8 +1761,8 @@ subroutine read_obs_sm_ASCAT_EUMET( & ! ! 1.) read N_tmp observations and their lat/lon info from file - - start_time = system_clock() + call system_clock(COUNT_RATE=clock_rate) ! Find the rate + call system_clock(COUNT=clock_start) ! Start timing ! read and process data if files are found allocate(tmp1_lon(max_rec)) @@ -1887,11 +1886,8 @@ subroutine read_obs_sm_ASCAT_EUMET( & deallocate(tmp1_lat) deallocate(tmp1_obs) - ! Get the end time - end_time = system_clock() - - ! Calculate the elapsed time in milliseconds - elapsed_time = (end_time - start_time) * 1000 / system_clock_rate() + call system_clock(COUNT=clock_end) ! Stop timing + elapsed_time=REAL((clock_end-clock_start)/clock_rate) write (logunit,*) 'Elapsed time bufr read: ', elapsed_time, ' milliseconds' @@ -1909,7 +1905,8 @@ subroutine read_obs_sm_ASCAT_EUMET( & ! a) determine grid cell that contains lat/lon ! b) determine tile within grid cell that contains lat/lon - start_time = system_clock() + call system_clock(COUNT_RATE=clock_rate) ! Find the rate + call system_clock(COUNT=clock_start) ! Start timing if (N_tmp>0) then @@ -1997,11 +1994,8 @@ subroutine read_obs_sm_ASCAT_EUMET( & end if - ! Get the end time - end_time = system_clock() - - ! Calculate the elapsed time in milliseconds - elapsed_time = (end_time - start_time) * 1000 / system_clock_rate() + call system_clock(COUNT=clock_end) ! Stop timing + elapsed_time=REAL((clock_end-clock_start)/clock_rate) write (logunit,*) 'Elapsed time tile allocation: ', elapsed_time, ' milliseconds' From 3f5ba3334ffbdbcf8eb80a09a71db8fe61123679 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Fri, 2 Jun 2023 17:43:29 -0400 Subject: [PATCH 078/308] clean up obs_scaling_param directory --- ...lim_stats.m => Run_get_L4_Tb_scale_SMAP.m} | 95 ++++---- .../get_ij_ind_from_latlon.m | 5 +- .../get_model_and_obs_clim_stats.m | 230 ++++++++---------- .../obs_scaling_params/write_seqbin_file.m | 47 ++-- 4 files changed, 173 insertions(+), 204 deletions(-) rename src/Applications/LDAS_App/util/inputs/obs_scaling_params/{Run_get_model_and_obs_clim_stats.m => Run_get_L4_Tb_scale_SMAP.m} (59%) diff --git a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/Run_get_model_and_obs_clim_stats.m b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/Run_get_L4_Tb_scale_SMAP.m similarity index 59% rename from src/Applications/LDAS_App/util/inputs/obs_scaling_params/Run_get_model_and_obs_clim_stats.m rename to src/Applications/LDAS_App/util/inputs/obs_scaling_params/Run_get_L4_Tb_scale_SMAP.m index 070fb597..62f54caa 100644 --- a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/Run_get_model_and_obs_clim_stats.m +++ b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/Run_get_L4_Tb_scale_SMAP.m @@ -13,25 +13,25 @@ run_months = [1:12 1:4]; %loop through 1:4 again to get complete pentads -% exp_path = '/discover/nobackup/amfox'; -% exp_run = {'SPL4SM_OL7000'}; -% domain = 'SMAP_EASEv2_M09_GLOBAL'; - -exp_path = '/discover/nobackup/amfox/Experiments/ASCAT_3Y_v2'; -exp_run = {'ASCAT_M36'}; -domain = 'SMAP_EASEv2_M36_GLOBAL'; +%exp_path = '/smap1/qliu/output/SMAP_Nature_v8.3/NRv8.3_innov_RTMv4/'; +%exp_run = {'SMAP_NRv8.3inv_RTMv4'}; +%exp_path = '/hydro/qliu/WORK/output/L4_SM_SMAP/'; +%exp_run = {'SPL4SM_OL4001'}; +%exp_path = '/smap1/qliu/output/SMAP_Nature_v8.3/NRv8.3_innov/S1/'; +%exp_run = {'SMAP_NRv8.3_innov'}; +exp_path = '/home/qliu/smap/SMAP_Nature/'; +exp_run = {'SPL4SM_OL7000'}; +domain = 'SMAP_EASEv2_M09_GLOBAL'; %Start and end year for each month -start_year = [repmat(2016,1,5) repmat(2015,1,7) repmat(2016,1,4)]; %corresp to [1:12 1 2] -end_year = [repmat(2017,1,5) repmat(2016,1,7) repmat(2017,1,4)]; %runs till end of run_months for end_year - +start_year = [repmat(2016,1,3) repmat(2015,1,9) repmat(2016,1,3) repmat(2015,1,1)]; %corresp to [1:12 1 2] +end_year = [repmat(2022,1,3) repmat(2021,1,9) repmat(2022,1,3) repmat(2021,1,1)]; %runs till end of run_months for end_year -%d orbit = [ 2]; %1=A, 2=D !DO *NOT* USE ASC AND DESC TOGETHER! -%d pol = [ 1 2 ]; %1=H, 2=V -%d inc_ang = [ 40.0 ]; +orbit = [ 2]; %1=A, 2=D !DO *NOT* USE ASC AND DESC TOGETHER! +pol = [ 1 2 ]; %1=H, 2=V +inc_ang = [ 40.0 ]; prefix_out = 'L4SM_OL7000_SMAPL1CR17000_zscore_stats_'; -prefix_out = 'M36_zscore_stats_'; dt_assim = 3*60*60; % [seconds] land analysis time step, % same as LANDASSIM_DT in GEOSldas) @@ -42,22 +42,20 @@ %====== obs_param_fname = [exp_path, '/', exp_run{1}, '/output/', domain, '/rc_out/', ... - '/Y2016/M04/',exp_run{1}, '.ldas_obsparam.20160401_0000z.txt']; + '/Y2015/M04/',exp_run{1}, '.ldas_obsparam.20150401_0000z.txt']; -%d var_name = {'Tb'}; +var_name = {'Tb'}; % added to identify SMOS or SMAP from runs that include both -species_names = {'SMAP_L1C_Tbh_A', 'SMAP_L1C_Tbv_A', 'SMAP_L1C_Tbh_D', 'SMAP_L1C_Tbv_D'}; -species_names = {'ASCAT_META_SM_A','ASCAT_META_SM_D','ASCAT_METB_SM_A','ASCAT_METB_SM_D'}; -species_names = {'ASCAT_META_SM_A','ASCAT_META_SM_D'}; +descr = 'SMAP_L1C' ; % 'SMOS_fit' %====== -%d if (length(orbit) > 1) - %d error('ONLY pick one orbit!' -%d end +if (length(orbit) > 1) + error('ONLY pick one orbit!') +end -%d if (orbit(1) == 1) int_Asc = 1; end %Asc -%d if (orbit(1) == 2) int_Asc = 0; end %Desc +if (orbit(1) == 1) int_Asc = 1; end %Asc +if (orbit(1) == 2) int_Asc = 0; end %Desc %====== %TO GO FROM SMOS TO SMAP ONLY!!! @@ -92,25 +90,20 @@ species =[]; -% for oo=1:length(orbit) -% for pp=1:length(pol) -% for aa=1:length(inc_ang) -% -% add_species = obs_param(strcmp(var_name,{obs_param.varname}) & ... -% orbit(oo) == [obs_param.orbit] & ... -% inc_ang(aa) == [obs_param.ang] & ... -% pol(pp) == [obs_param.pol] & ... -% ~cellfun(@isempty, strfind({obs_param.descr},descr))).species; -% -% species = union(species,add_species); -% -% end -% end -% end - -for i = 1:length(species_names) - add_species = obs_param(strcmp(species_names(i),{obs_param.descr})).species; - species = union(species,add_species); +for oo=1:length(orbit) + for pp=1:length(pol) + for aa=1:length(inc_ang) + + add_species = obs_param(strcmp(var_name,{obs_param.varname}) & ... + orbit(oo) == [obs_param.orbit] & ... + inc_ang(aa) == [obs_param.ang] & ... + pol(pp) == [obs_param.pol] & ... + ~cellfun(@isempty, strfind({obs_param.descr},descr))).species; + + species = union(species,add_species); + + end + end end species @@ -127,11 +120,11 @@ for k=1:length(run_months) - get_model_and_obs_clim_stats( species_names, ... + get_model_and_obs_clim_stats( var_name, ... run_months{k}, exp_path, exp_run{n}, domain, ... start_year, end_year, ... dt_assim, t0_assim, species, obs_param, ... - hscale, w_days, Ndata_min, prefix_out,... + hscale, inc_ang, int_Asc, w_days, Ndata_min, prefix_out,... convert_grid, time_of_day_in_hours(j) ); end @@ -140,10 +133,10 @@ else - get_model_and_obs_clim_stats( species_names, ... + get_model_and_obs_clim_stats( var_name, ... run_months, exp_path, exp_run{n}, domain, start_year, end_year, ... dt_assim, t0_assim, species, obs_param, ... - hscale, w_days, Ndata_min, prefix_out,... + hscale, inc_ang, int_Asc, w_days, Ndata_min, prefix_out,... convert_grid ); end @@ -156,11 +149,11 @@ for k=1:length(run_months) - get_model_and_obs_clim_stats( species_names, ... + get_model_and_obs_clim_stats( var_name, ... run_months{k}, exp_path, exp_run{n}, domain, ... start_year, end_year, ... dt_assim, t0_assim, species, obs_param, ... - hscale, w_days, Ndata_min, prefix_out,... + hscale, inc_ang, int_Asc, w_days, Ndata_min, prefix_out,... time_of_day_in_hours(j) ); end @@ -169,10 +162,10 @@ else - get_model_and_obs_clim_stats( species_names, ... + get_model_and_obs_clim_stats( var_name, ... run_months, exp_path, exp_run{n}, domain, start_year, end_year, ... dt_assim, t0_assim, species, obs_param, ... - hscale, w_days, Ndata_min, prefix_out); + hscale, inc_ang, int_Asc, w_days, Ndata_min, prefix_out); end diff --git a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_ij_ind_from_latlon.m b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_ij_ind_from_latlon.m index dbb9c245..9edf5ca2 100644 --- a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_ij_ind_from_latlon.m +++ b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_ij_ind_from_latlon.m @@ -2,7 +2,7 @@ function [i_ind,j_ind] = get_ij_ind_from_latlon( tile_grid, lat, lon) - if (strcmp(tile_grid.gridtype,'EASEv2-M36')) + if (strcmp(tile_grid.gridtype,'EASEv2_M36')) %row, col [j_indg,i_indg] = ... EASEv2_latlon2ind(lat,lon,'M36',1); @@ -18,9 +18,6 @@ i_ind = i_indg - tile_grid.i_offg - (tile_grid.ind_base - 1); j_ind = j_indg - tile_grid.j_offg - (tile_grid.ind_base - 1); - - i_ind = round(i_ind); - j_ind = round(j_ind); end diff --git a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats.m b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats.m index 85736fbd..492839a2 100644 --- a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats.m +++ b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats.m @@ -1,8 +1,8 @@ -function [] = get_model_and_obs_clim_stats( species_names, ... +function [] = get_model_and_obs_clim_stats( varname, ... run_months, exp_path, exp_run, domain, start_year, end_year, ... dt_assim, t0_assim, species, obs_param, ... - hscale, w_days, Ndata_min, prefix, ... + hscale, inc_angle, int_Asc, w_days, Ndata_min, prefix, ... convert_grid , time_of_day_in_hours ) % @@ -116,15 +116,13 @@ overwrite = 1; -N_species = length(species); - -Nf = 5; %5 fields per species -N_out_fields = N_species*Nf + N_species * 2; %This includes the debugging fields to replicate SMAP code +Nf = 5; %5 fields per polarization +N_out_fields = 2*Nf+4; %14; write_ind_latlon = 'latlon_id'; %'latlon'; -%d N_angle = length(inc_angle); -%d N_pol = 2; +N_angle = length(inc_angle); +N_pol = 2; tmp_shift_lon = 0.01; tmp_shift_lat = 0.005; @@ -187,53 +185,12 @@ '_hscale_', num2str(hscale,'%2.2f'), '_', ... 'W_', num2str(round(w_days/5)),'p_Nmin_', num2str(Ndata_min)]; -% Some clunky code to maintain backwards compatibility with adding orbit -% tag - -% Initialize counters for cells ending in "_A" and cells ending in "_D" -a_count = 0; -d_count = 0; - -% Loop through each cell in the array -for i = 1:numel(species_names) - % Check if the text in the cell ends with either "_A" or "_D" - if endsWith(species_names{i}, '_A') - % If it ends with "_A", increment the "_A" counter - a_count = a_count + 1; - elseif endsWith(species_names{i}, '_D') - % If it ends with "_D", increment the "_D" counter - d_count = d_count + 1; - end - - if startsWith(species_names{i}, 'SMAP') - inc_angle = [40.0]; - else - inc_angle = [-999.9]; - end - -end +%fname_out_base = [fname_out_base, spec_tag]; -% Determine the output based on the values of the "_A" and "_D" counters -if a_count == numel(species_names) - % Both cells end in "_A" - disp('All species are "_A"'); - Orbit_tag = '_A'; - int_Asc = 1; -elseif d_count == numel(species_names) - % Both cells end in "_D" - disp('All species are "_D"'); - Orbit_tag = '_D'; - int_Asc = 2; -elseif a_count > 0 && d_count > 0 - % There is a mix of "_A" and "_D" - disp('Spcies have a mix of "_A" and "_D"'); - Orbit_tag = '_AD'; - int_Asc = 3; +if (int_Asc == 1) + Orbit_tag = '_A'; %'_Asc'; else - % Neither cell ends in "_A" or "_D" - disp('Neither cell ends in "_A" or "_D"'); - Orbit_tag = '_NoOrbits'; - int_Asc = 4; + Orbit_tag = '_D'; %'_Desc'; end fname_out_base = [fname_out_base, Orbit_tag]; @@ -275,6 +232,7 @@ if (~isempty(strfind(convert_grid, 'M36')) && ~isempty(strfind(convert_grid, 'EASEv2'))) gridid = 'M36'; [central_row,central_col] = EASEv2_latlon2ind(central_lat,central_lon,gridid,1); + [central_lat,central_lon] = EASEv2_ind2latlon(central_row,central_col,gridid); elseif (~isempty(strfind(convert_grid, 'M36')) && ~isempty(strfind(convert_grid, 'EASEv1'))) error('Must provide smapeasev1_latlon2ind() and smapeasev1_ind2latlon()!') gridid = 'M36'; @@ -372,13 +330,13 @@ % N_pol and N_angle be specified here. Then subsample specifically % when the files are written out. -o_data = NaN+zeros(N_species,N_tile_obs,w_days); -m_data = NaN+zeros(N_species,N_tile_obs,w_days); -o_data2 = NaN+zeros(N_species,N_tile_obs,w_days); -m_data2 = NaN+zeros(N_species,N_tile_obs,w_days); -N_data = NaN+zeros(N_species,N_tile_obs,w_days); +o_data = NaN+zeros(N_pol,N_tile_obs,N_angle,w_days); +m_data = NaN+zeros(N_pol,N_tile_obs,N_angle,w_days); +o_data2 = NaN+zeros(N_pol,N_tile_obs,N_angle,w_days); +m_data2 = NaN+zeros(N_pol,N_tile_obs,N_angle,w_days); +N_data = NaN+zeros(N_pol,N_tile_obs,N_angle,w_days); -data_out = NaN+zeros(N_out_fields,N_tile_obs); +data_out = NaN+zeros(N_out_fields,N_tile_obs,N_angle); % ------------------------------------------------------------- @@ -479,12 +437,8 @@ % extract species of interest ind = []; - - scnt = 0; for this_species = species - - scnt = scnt + 1; ind = find( obs_species == this_species); @@ -512,7 +466,7 @@ %pol intrinsically gives an index %now find the index for the angle - %d angle_i = find(angle(1) == inc_angle); + angle_i = find(angle(1) == inc_angle); % Only writes lat-lon at exact obs locations, but with % hscale>0, these obs are spread outside their exact @@ -546,15 +500,15 @@ %e.g. at the poles. %**nansum of NaN's** result in zero, this need to be %taken care of - o_data(scnt,obs_i,count) = nansum([o_data(scnt,obs_i,count); obs_obs_i' ]); - m_data(scnt,obs_i,count) = nansum([m_data(scnt,obs_i,count); obs_fcst_i']); + o_data(pol(1),obs_i,angle_i,count) = nansum([o_data(pol(1),obs_i,angle_i,count); obs_obs_i' ]); + m_data(pol(1),obs_i,angle_i,count) = nansum([m_data(pol(1),obs_i,angle_i,count); obs_fcst_i']); %X^2 - o_data2(scnt,obs_i,count) = nansum([o_data2(scnt,obs_i,count); obs_obs_i'.^2 ]); - m_data2(scnt,obs_i,count) = nansum([m_data2(scnt,obs_i,count); obs_fcst_i'.^2]); + o_data2(pol(1),obs_i,angle_i,count) = nansum([o_data2(pol(1),obs_i,angle_i,count); obs_obs_i'.^2 ]); + m_data2(pol(1),obs_i,angle_i,count) = nansum([m_data2(pol(1),obs_i,angle_i,count); obs_fcst_i'.^2]); %Sum of obs or model elements at each location - N_data(scnt,obs_i,count) = nansum([N_data(scnt,obs_i,count); ~isnan([obs_obs_i])']); + N_data(pol(1),obs_i,angle_i,count) = nansum([N_data(pol(1),obs_i,angle_i,count); ~isnan([obs_obs_i])']); else @@ -566,20 +520,20 @@ %hscale_ind =[obs space] % %Sum of X - o_data(scnt,obs_i,count) = ... - nansum([o_data(scnt,obs_i,count); repmat(obs_obs_i(i_ind),1,length(s_eff))]); - m_data(scnt,obs_i,count) = ... + o_data(pol(1),s_eff,angle_i,count) = ... + nansum([o_data(pol(1),s_eff,angle_i,count); repmat(obs_obs_i(i_ind),1,length(s_eff))]); + m_data(pol(1),s_eff,angle_i,count) = ... nansum([m_data(pol(1),s_eff,angle_i,count); repmat(obs_fcst_i(i_ind),1,length(s_eff))]); %Sum of X^2 - o_data2(scnt,obs_i,count) = ... - nansum([o_data2(scnt,obs_i,count); repmat(obs_obs_i(i_ind).^2,1,length(s_eff))]); - m_data2(scnt,obs_i,count) = ... - nansum([m_data2(scnt,obs_i,count); repmat(obs_fcst_i(i_ind).^2,1,length(s_eff))]); + o_data2(pol(1),s_eff,angle_i,count) = ... + nansum([o_data2(pol(1),s_eff,angle_i,count); repmat(obs_obs_i(i_ind).^2,1,length(s_eff))]); + m_data2(pol(1),s_eff,angle_i,count) = ... + nansum([m_data2(pol(1),s_eff,angle_i,count); repmat(obs_fcst_i(i_ind).^2,1,length(s_eff))]); %Sum of obs or model elements at each location - N_data(scnt,obs_i,count) = ... - nansum([N_data(scnt,obs_i,count); repmat(~isnan([obs_obs_i(i_ind)]),1,length(s_eff)) ]); + N_data(pol(1),s_eff,angle_i,count) = ... + nansum([N_data(pol(1),s_eff,angle_i,count); repmat(~isnan([obs_obs_i(i_ind)]),1,length(s_eff)) ]); end @@ -618,48 +572,48 @@ % data_out = zeros(N_out_fields,1:N_tiles,N_angle); - for i = 0:N_species-1 + for pol=[0 1] - pp = i*Nf; + pp = pol*Nf; - N_hscale_window = nansum(N_data(1+i,:,1:w_days),3); + N_hscale_window = nansum(N_data(1+pol,:,:,1:w_days),4); if w_days == 95 - N_hscale_inner_window = nansum(N_data(1+i,:,((w_days+1)/2-15):((w_days+1)/2+15)),3); + N_hscale_inner_window = nansum(N_data(1+pol,:,:,((w_days+1)/2-15):((w_days+1)/2+15)),4); end % OBSERVATIONS %---------------- %o_data is a sum over neighbouring obs above; %here then take a sum over the time steps in the window - data_out(1+pp,:) = nansum(o_data(1+i,:,1:w_days),3); + data_out(1+pp,:,:) = nansum(o_data(1+pol,:,:,1:w_days),4); %then make the average, by dividing over the sum of the number of %timesteps and influencing obs at each location - data_out(1+pp,:) = data_out(1+pp,:)./N_hscale_window; + data_out(1+pp,:,:) = data_out(1+pp,:,:)./N_hscale_window; %stdv_H = sqrt(E[X^2] - E[X]^2) - data_out(2+pp,:) = nansum(o_data2(1+i,:,1:w_days),3); - data_out(2+pp,:) = data_out(2+pp,:)./N_hscale_window; - data_out(2+pp,:) = sqrt( data_out(2+pp,:) - data_out(1+pp,:).^2); + data_out(2+pp,:,:) = nansum(o_data2(1+pol,:,:,1:w_days),4); + data_out(2+pp,:,:) = data_out(2+pp,:,:)./N_hscale_window; + data_out(2+pp,:,:) = sqrt( data_out(2+pp,:,:) - data_out(1+pp,:,:).^2); % MODEL %---------------- - data_out(3+pp,:) = nansum(m_data(1+i,:,1:w_days),3); - data_out(3+pp,:) = data_out(3+pp,:)./N_hscale_window; + data_out(3+pp,:,:) = nansum(m_data(1+pol,:,:,1:w_days),4); + data_out(3+pp,:,:) = data_out(3+pp,:,:)./N_hscale_window; - data_out(4+pp,:) = nansum(m_data2(1+i,:,1:w_days),3); - data_out(4+pp,:) = data_out(4+pp,:)./N_hscale_window; - data_out(4+pp,:) = sqrt( data_out(4+pp,:) - data_out(3+pp,:).^2); + data_out(4+pp,:,:) = nansum(m_data2(1+pol,:,:,1:w_days),4); + data_out(4+pp,:,:) = data_out(4+pp,:,:)./N_hscale_window; + data_out(4+pp,:,:) = sqrt( data_out(4+pp,:,:) - data_out(3+pp,:,:).^2); - data_out(5+pp,:) = N_hscale_window; + data_out(5+pp,:,:) = N_hscale_window; % Toss out stats that are based on too little data - data_out([1:Nf]+pp,N_hscale_window=59) + DOY = DOY-1; + error('This code should never hit a leap year'); + end - fname_out = [fname_out_base_s, '_DOY', num2str(DOY,'%3.3d'), '.nc4']; + fname_out = [fname_out_base, '_DOY', num2str(DOY,'%3.3d'), '.bin']; % check whether output file exists + if (exist(fname_out)==2 && overwrite) + disp(['output file exists. overwriting', fname_out]) + elseif (exist(fname_out)==2 && ~overwrite) + disp(['output file exists. not overwriting. returning']) disp(['writing ', fname_out]) return + else + disp(['creating ', fname_out]) + end % compress data before writing in file. @@ -774,46 +729,53 @@ %tile_coord_tile_id_write = tile_coord_tile_id(idx_keep); - % write output for each DOY, sorted by all tile - if print_each_DOY - write_netcdf_file(fname_out, lon_out, lat_out, ... - inc_angle, data_out(startrow:endrow,:), int_Asc, 0, ... %instead of writing the version#, write Ndata_min=0 + % write output for each DOY, sorted by all tiles + + if print_each_DOY + + write_seqbin_file(fname_out, lon_out, lat_out, ... + inc_angle, data_out(:,:,:), int_Asc, 0, ... %instead of writing the version#, write Ndata_min=0 start_time, end_time, overwrite, ... - Nf, write_ind_latlon, 'scaling',... + N_out_fields, write_ind_latlon, 'scaling',... tile_coord_tile_id) else + % if DOY is at middle of pentad, then copy the DOY to a pentad file % DOY = pentad*5 - 2; ==> pentad = (DOY + 2)/5; + pentad = (DOY + 2)/5; + if mod((DOY + 2),5) == 0 - write_netcdf_file(fname_out, lon_out, lat_out, ... - inc_angle, data_out(startrow:endrow,:), int_Asc, 0, ... + + write_seqbin_file(fname_out, lon_out, lat_out, ... + inc_angle, data_out(:,:,:), int_Asc, 0, ... start_time, end_time, overwrite, ... - Nf, write_ind_latlon, 'scaling',... + N_out_fields, write_ind_latlon, 'scaling',... tile_coord_tile_id) + fname_out_p = [fname_out_base_p, '_p', num2str(pentad,'%2.2d'), '.bin']; + copyfile(fname_out,fname_out_p); + end end -end % new species loop - %clear idx_keep lon_out_write lat_out_write data_out_write tile_coord_tile_id_write % shift the window by one day and make room for the next day at the end - o_data(:,:,1:w_days-1) = o_data(:,:,2:w_days); - m_data(:,:,1:w_days-1) = m_data(:,:,2:w_days); - o_data2(:,:,1:w_days-1) = o_data2(:,:,2:w_days); - m_data2(:,:,1:w_days-1) = m_data2(:,:,2:w_days); - N_data(:,:,1:w_days-1) = N_data(:,:,2:w_days); - - o_data(:,:,w_days) = NaN; - m_data(:,:,w_days) = NaN; - o_data2(:,:,w_days) = NaN; - m_data2(:,:,w_days) = NaN; - N_data(:,:,w_days) = NaN; + o_data(:,:,:,1:w_days-1) = o_data(:,:,:,2:w_days); + m_data(:,:,:,1:w_days-1) = m_data(:,:,:,2:w_days); + o_data2(:,:,:,1:w_days-1) = o_data2(:,:,:,2:w_days); + m_data2(:,:,:,1:w_days-1) = m_data2(:,:,:,2:w_days); + N_data(:,:,:,1:w_days-1) = N_data(:,:,:,2:w_days); + + o_data(:,:,:,w_days) = NaN; + m_data(:,:,:,w_days) = NaN; + o_data2(:,:,:,w_days) = NaN; + m_data2(:,:,:,w_days) = NaN; + N_data(:,:,:,w_days) = NaN; data_out = NaN+0.0.*data_out; diff --git a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/write_seqbin_file.m b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/write_seqbin_file.m index e93e2ecb..14153721 100644 --- a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/write_seqbin_file.m +++ b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/write_seqbin_file.m @@ -1,5 +1,5 @@ function [] = write_seqbin_file(fname, colind, rowind,... - av_angle_bin, data, asc_flag,... + av_angle_bin, data, asc_flag, ... version, ... start_time, end_time, overwrite, N_out_fields, ... write_ind_latlon, data_product,... @@ -111,14 +111,14 @@ N_grid = size(data,2); N_angle= 1; -% if (length(size(data)) == 3) -% N_angle = size(data,3); -% data_org = data; -% if (N_angle ~= length(av_angle_bin)) -% disp(['ERROR in N_angle']) -% return -% end -% end +if (length(size(data)) == 3) + N_angle = size(data,3); + data_org = data; + if (N_angle ~= length(av_angle_bin)) + disp(['ERROR in N_angle']) + return + end +end if (strcmp(write_ind_latlon,'latlon_id') && nargin == 14) @@ -220,9 +220,20 @@ fortran_tag = N_grid*4; for i=1:N_out_fields - count = fwrite( ifp, fortran_tag, int_precision ); - count = fwrite( ifp, data(i,:), float_precision ); - count = fwrite( ifp, fortran_tag, int_precision ); + + for j=1:N_angle + + if (N_angle > 1) + data = squeeze(data_org(:,:,j)); + end + + count = fwrite( ifp, fortran_tag, int_precision ); + count = fwrite( ifp, data(i,:), float_precision ); + count = fwrite( ifp, fortran_tag, int_precision ); + + + end + end else @@ -276,9 +287,15 @@ end for i=1:N_out_fields - count = fwrite( ifp, fortran_tag, int_precision ); - count = fwrite( ifp, -999.0, float_precision ); - count = fwrite( ifp, fortran_tag, int_precision ); + + for j=1:N_angle + + count = fwrite( ifp, fortran_tag, int_precision ); + count = fwrite( ifp, -999.0, float_precision ); + count = fwrite( ifp, fortran_tag, int_precision ); + + end + end end From 578a5f2c559df222ca09252afcab1d169c836605 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Fri, 2 Jun 2023 18:58:08 -0400 Subject: [PATCH 079/308] timing statements --- .../LDAS_App/test_netcdf_reader.F90 | 80 ------------------- .../clsm_ensupd_read_obs.F90 | 72 ++++++++++------- 2 files changed, 42 insertions(+), 110 deletions(-) delete mode 100644 src/Applications/LDAS_App/test_netcdf_reader.F90 diff --git a/src/Applications/LDAS_App/test_netcdf_reader.F90 b/src/Applications/LDAS_App/test_netcdf_reader.F90 deleted file mode 100644 index a8a410c9..00000000 --- a/src/Applications/LDAS_App/test_netcdf_reader.F90 +++ /dev/null @@ -1,80 +0,0 @@ -program read_netcdf - use netcdf - implicit none - - integer :: ncid, varid, dimid, status, i, j - integer :: grid, angle, tile, pentad - integer :: asc_flag, version, N_grid, N_angle - real(kind=8) :: start_time(pentad), end_time(pentad) - real(kind=8) :: o_mean(pentad, grid), o_std(pentad, grid) - real(kind=8) :: m_mean(pentad, grid), m_std(pentad, grid) - real(kind=8) :: n_data(pentad, grid), av_angle_bin(angle) - real(kind=8) :: colind(grid), rowind(grid), lon(grid), lat(grid) - - ! Open the netCDF file - status = nf_open("filename.nc", nf_nowrite, ncid) - if (status /= nf90_noerr) then - write(*,*) "Error opening netCDF file" - stop - endif - - ! Get dimension IDs - status = nf_inq_dimid(ncid, "grid", dimid) - status = nf_inq_dimlen(ncid, dimid, grid) - status = nf_inq_dimid(ncid, "angle", dimid) - status = nf_inq_dimlen(ncid, dimid, angle) - status = nf_inq_dimid(ncid, "tile", dimid) - status = nf_inq_dimlen(ncid, dimid, tile) - status = nf_inq_dimid(ncid, "pentad", dimid) - status = nf_inq_dimlen(ncid, dimid, pentad) - - ! Get variable IDs - status = nf_inq_varid(ncid, "asc_flag", varid) - status = nf_inq_varid(ncid, "version", varid) - status = nf_inq_varid(ncid, "pentad", varid) - status = nf_inq_varid(ncid, "start_time", varid) - status = nf_inq_varid(ncid, "end_time", varid) - status = nf_inq_varid(ncid, "N_grid", varid) - status = nf_inq_varid(ncid, "N_angle", varid) - status = nf_inq_varid(ncid, "obs_num", varid) - status = nf_inq_varid(ncid, "av_angle_bin", varid) - status = nf_inq_varid(ncid, "colind", varid) - status = nf_inq_varid(ncid, "rowind", varid) - status = nf_inq_varid(ncid, "lon", varid) - status = nf_inq_varid(ncid, "lat", varid) - status = nf_inq_varid(ncid, "o_mean", varid) - status = nf_inq_varid(ncid, "o_std", varid) - status = nf_inq_varid(ncid, "m_mean", varid) - status = nf_inq_varid(ncid, "m_std", varid) - status = nf_inq_varid(ncid, "n_data", varid) - - ! Read variables - status = nf_get_var(ncid, nf_inq_varid(ncid, "asc_flag", varid), asc_flag) - status = nf_get_var(ncid, nf_inq_varid(ncid, "version", varid), version) - status = nf_get_var(ncid, nf_inq_varid(ncid, "pentad", varid), pentad) - status = nf_get_var(ncid, nf_inq_varid(ncid, "start_time", varid), start_time) - status = nf_get_var(ncid, nf_inq_varid(ncid, "end_time", varid), end_time) - status = nf_get_var(ncid, nf_inq_varid(ncid, "N_grid", varid), N_grid) - status = nf_get_var(ncid, nf_inq_varid(ncid, "N_angle", varid), N_angle) - status = nf_get_var(ncid, nf_inq_varid(ncid, "obs_num", varid), obs_num) - status = nf_get_var(ncid, nf_inq_varid(ncid, "av_angle_bin", varid), av_angle_bin) - status = nf_get_var(ncid, nf_inq_varid(ncid, "colind", varid), colind) - status = nf_get_var(ncid, nf_inq_varid(ncid, "rowind", varid), rowind) - status = nf_get_var(ncid, nf_inq_varid(ncid, "lon", varid), lon) - status = nf_get_var(ncid, nf_inq_varid(ncid, "lat", varid), lat) - status = nf_get_var(ncid, nf_inq_varid(ncid, "o_mean", varid), o_mean) - status = nf_get_var(ncid, nf_inq_varid(ncid, "o_std", varid), o_std) - status = nf_get_var(ncid, nf_inq_varid(ncid, "m_mean", varid), m_mean) - status = nf_get_var(ncid, nf_inq_varid(ncid, "m_std", varid), m_std) - status = nf_get_var(ncid, nf_inq_varid(ncid, "n_data", varid), n_data) - - ! Close the netCDF file - status = nf_close(ncid) - - ! Print some information - write(,) "Number of grids: ", grid - write(,) "Number of pentads: ", pentad - write(,) "Start time for pentad 1: ", start_time(1) - write(,) "End time for pentad 1: ", end_time(1) - - end program read_netcdf \ No newline at end of file diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 0e1472d8..8cc30d63 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -1629,8 +1629,8 @@ subroutine read_obs_sm_ASCAT_EUMET( & type(date_time_type) :: date_time_upp integer :: i, ind, N_tmp, N_files - integer :: clock_start, clock_end, clock_rate - real(8) :: elapsed_time + integer :: clock_start, clock_start_sr, clock_end, clock_end_sr, clock_rate, clock_rate_sr + real(8) :: elapsed_time, elapsed_time_sr character(300), dimension(:), allocatable :: fnames @@ -1661,12 +1661,11 @@ subroutine read_obs_sm_ASCAT_EUMET( & ! --------------- ! initialize - - call system_clock(COUNT_RATE=clock_rate) ! Find the rate - call system_clock(COUNT=clock_start) ! Start timing found_obs = .false. + call system_clock(clock_start_sr) ! Start timing + ! find files that are within half-open interval ! [date_time-dtstep_assim/2,date_time+dtstep_assim/2) @@ -1744,10 +1743,9 @@ subroutine read_obs_sm_ASCAT_EUMET( & close(10,status='delete') - call system_clock(COUNT=clock_end) ! Stop timing - elapsed_time=REAL((clock_end-clock_start)/clock_rate) - - write (logunit,*) 'Elapsed time file names: ', elapsed_time, ' milliseconds' + call system_clock(clock_end, clock_rate) ! Stop timing + elapsed_time=(real(clock_end-clock_start_sr)/real(clock_rate)) + write (logunit,*) 'Elapsed time filenames from start: ', elapsed_time, ' seconds' ! read observations: ! @@ -1761,8 +1759,8 @@ subroutine read_obs_sm_ASCAT_EUMET( & ! ! 1.) read N_tmp observations and their lat/lon info from file - call system_clock(COUNT_RATE=clock_rate) ! Find the rate - call system_clock(COUNT=clock_start) ! Start timing +! call system_clock(COUNT_RATE=clock_rate) ! Find the rate +! call system_clock(COUNT=clock_start) ! Start timing ! read and process data if files are found allocate(tmp1_lon(max_rec)) @@ -1771,6 +1769,7 @@ subroutine read_obs_sm_ASCAT_EUMET( & allocate(tmp1_jtime(max_rec)) if (N_files>0) then + call system_clock(clock_start) ! file loop N_tmp = 0 @@ -1886,10 +1885,10 @@ subroutine read_obs_sm_ASCAT_EUMET( & deallocate(tmp1_lat) deallocate(tmp1_obs) - call system_clock(COUNT=clock_end) ! Stop timing - elapsed_time=REAL((clock_end-clock_start)/clock_rate) - - write (logunit,*) 'Elapsed time bufr read: ', elapsed_time, ' milliseconds' + call system_clock(clock_end, clock_rate) ! Stop timing + elapsed_time_sr=(real(clock_end-clock_start)/real(clock_rate)) + write (logunit,*) 'Elapsed time bufr read from start: ', elapsed_time_sr, ' seconds' + ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! @@ -1905,8 +1904,8 @@ subroutine read_obs_sm_ASCAT_EUMET( & ! a) determine grid cell that contains lat/lon ! b) determine tile within grid cell that contains lat/lon - call system_clock(COUNT_RATE=clock_rate) ! Find the rate - call system_clock(COUNT=clock_start) ! Start timing +! call system_clock(COUNT_RATE=clock_rate) ! Find the rate +! call system_clock(COUNT=clock_start) ! Start timing if (N_tmp>0) then @@ -1949,7 +1948,9 @@ subroutine read_obs_sm_ASCAT_EUMET( & end do ! -------------------------------- - + call system_clock(clock_end, clock_rate) ! Stop timing + elapsed_time=(real(clock_end-clock_start_sr)/real(clock_rate)) + write (logunit,*) 'Elapsed time after n_obs_in_tile from start: ', elapsed_time, ' seconds' ! normalize @@ -1976,7 +1977,12 @@ subroutine read_obs_sm_ASCAT_EUMET( & end if end do - + + + call system_clock(clock_end, clock_rate) ! Stop timing + elapsed_time=(real(clock_end-clock_start_sr)/real(clock_rate)) + write (logunit,*) 'Elapsed time 4 from start: ', elapsed_time, ' seconds' + ! clean up if (associated(tmp_tile_num)) deallocate(tmp_tile_num) @@ -1993,19 +1999,19 @@ subroutine read_obs_sm_ASCAT_EUMET( & end if + call system_clock(clock_end, clock_rate) ! Stop timing + elapsed_time=(real(clock_end-clock_start_sr)/real(clock_rate)) + write (logunit,*) 'Elapsed time in read_obs_sm_ASCAT_EUMET: ', elapsed_time, ' seconds' + + elapsed_time = (elapsed_time_sr/elapsed_time)*100 + write (logunit,*) 'We spent ', elapsed_time, '% of time in bufr read' - call system_clock(COUNT=clock_end) ! Stop timing - elapsed_time=REAL((clock_end-clock_start)/clock_rate) - - write (logunit,*) 'Elapsed time tile allocation: ', elapsed_time, ' milliseconds' - ! clean up if (associated(tmp_obs)) deallocate(tmp_obs) if (associated(tmp_lon)) deallocate(tmp_lon) if (associated(tmp_lat)) deallocate(tmp_lat) if (associated(tmp_jtime)) deallocate(tmp_jtime) - end subroutine read_obs_sm_ASCAT_EUMET @@ -8157,6 +8163,9 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & ! reichle, 14 Oct 2005 ! ! reichle, 22 Nov 2011 - renamed subroutine, minor clean-up, added comments +! +! Modified for ASCAT observations A M Fox, April 2023, + use netcdf implicit none @@ -8211,6 +8220,8 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & integer :: o_mean_varid, o_std_varid, m_mean_varid, m_std_varid integer, dimension(3) :: start, icount +integer :: clock_start, clock_end, clock_rate +real(8) :: elapsed_time real :: tmpreal, this_lon, this_lat @@ -8228,6 +8239,8 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & ! read scaling parameters from file +call system_clock(clock_start) ! Start timing + fname = trim(this_obs_param%scalepath) // '/' // & trim(this_obs_param%scalename) // '.nc4' @@ -8306,7 +8319,6 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & if (logit) write (logunit,*) 'start, icount', start, icount if (logit) write (logunit,*) 'tile_coord(i)%com_lat, this_lat, sclprm_lat(j_ind)', tile_coord(i)%com_lat, this_lat, sclprm_lat(j_ind) if (logit) write (logunit,*) 'tile_coord(i)%com_lon, this_lon, sclprm_lon(i_ind)', tile_coord(i)%com_lon, this_lon, sclprm_lon(i_ind) - if (logit) write (logunit,*) 'pp, sclprm_lon, sclprm_lat, sclprm_mean_obs(328:334,579) ', pp, sclprm_lon(1), sclprm_lat(1), sclprm_mean_obs(328:334, 579) err_msg = 'something wrong' call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) end if @@ -8321,10 +8333,6 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & ! scale via standard normal deviates - if (mod(i, 100) == 0) then - write(logunit,*) 'Found! ', i, pp, j_ind, i_ind, tmp_obs(i), sclprm_mean_obs(j_ind, i_ind), sclprm_std_mod(j_ind, i_ind), sclprm_std_obs(j_ind, i_ind) - endif - tmpreal = sclprm_std_mod(j_ind, i_ind)/sclprm_std_obs(j_ind, i_ind) tmp_obs(i) = sclprm_mean_mod(j_ind, i_ind) & @@ -8351,6 +8359,10 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & deallocate(sclprm_mean_mod) deallocate(sclprm_std_mod) +call system_clock(clock_end, clock_rate) ! Stop timing +elapsed_time=(real(clock_end-clock_start)/real(clock_rate)) +write (logunit,*) 'Elapsed time in scale_obs_sfmc_zscore: ', elapsed_time, ' seconds' + end subroutine scale_obs_sfmc_zscore ! ******************************************************************************** From 38db8c1b97697d1909fafa4d3e9bf00a0ccaf27e Mon Sep 17 00:00:00 2001 From: amfox37 Date: Tue, 6 Jun 2023 13:49:03 -0600 Subject: [PATCH 080/308] switch to fname list reader --- .../clsm_ensupd_read_obs.F90 | 138 ++++++++++++------ 1 file changed, 92 insertions(+), 46 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 0e1472d8..fc653f1f 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -1614,13 +1614,16 @@ subroutine read_obs_sm_ASCAT_EUMET( & ! Will need to be updated if using EUMETSAT BUFR files - integer, parameter :: ae_time_offset = 3600 ! 60 minutes in seconds +! integer, parameter :: ae_time_offset = 3600 ! 60 minutes in seconds + integer, parameter :: N_fnames_max = 20 + character(4), parameter :: J2000_epoch_id = 'TT12' ! see date_time_util.F90 - character(4) :: DDHH - character(6) :: YYYYMM - character(8) :: date_string - character(10) :: time_string + character( 4) :: DDHH + character( 6) :: YYYYMM + character( 8) :: date_string + character( 10) :: time_string + character( 80) :: fname_of_fname_list character(300) :: tmpfname, tmpfname2 character(400) :: cmd @@ -1629,6 +1632,7 @@ subroutine read_obs_sm_ASCAT_EUMET( & type(date_time_type) :: date_time_upp integer :: i, ind, N_tmp, N_files + integer :: N_fnames, N_fnames_tmp integer :: clock_start, clock_end, clock_rate real(8) :: elapsed_time @@ -1640,6 +1644,9 @@ subroutine read_obs_sm_ASCAT_EUMET( & integer :: idate,iret,kk integer :: ireadmg,ireadsb character(8) :: subset + + character(100), dimension(2*N_fnames_max) :: fname_list ! max 2 days of files + real, dimension(:), allocatable :: tmp1_lon, tmp1_lat, tmp1_obs real*8, dimension(:), allocatable :: tmp1_jtime @@ -1675,74 +1682,113 @@ subroutine read_obs_sm_ASCAT_EUMET( & date_time_upp = date_time call augment_date_time( (dtstep_assim/2), date_time_upp) - ! for ASCAT file name stamp - date_time_tmp = date_time - call augment_date_time( -(dtstep_assim/2 + ae_time_offset), date_time_tmp ) +! read file with list of ASCAT file names for first day + + fname_of_fname_list = 'dummy' ! Make sure its in the obs_param nml - ! get tmp file name and remove file if it exists + call read_obs_SMAP_fnames( date_time_low, this_obs_param, & + fname_of_fname_list, N_fnames_max, & + N_fnames, fname_list(1:N_fnames_max) ) - call date_and_time(date_string, time_string) ! f90 intrinsic function + ! if needed, read file with list of ASCAT file names for second day and add + ! file names into "fname_list" - tmpfname = trim(work_path) // '/' // 'tmp.' // trim(exp_id) & - // '.' // date_string // time_string + if (date_time_low%day /= date_time_upp%day) then + + call read_obs_SMAP_fnames( date_time_upp, this_obs_param, & + fname_of_fname_list, N_fnames_max, & + N_fnames_tmp, fname_list((N_fnames+1):(N_fnames+N_fnames_max)) ) + + N_fnames = N_fnames + N_fnames_tmp + + end if - cmd = '/bin/rm -f ' // tmpfname + fnames = fname_list + N_files = N_fnames + + do kk = 1,N_files + tmpfname = fnames(kk) + ! Remove the '/D03/' from the directory part as using "read_obs_SMAP_fnames" + ind = scan(tmpfname, "/D03/") + if (ind > 0) then + tmpfname2 = tmpfname(1:ind-1) // tmpfname(ind+5:) + end if + fnames(kk) = trim(this_obs_param%path) // '/' // trim(tmpfname2) + end do + + write (logunit,*) 'File names from list: ', fnames + + ! Find files with obs within the assimilation window (need to check this AMF) + + + ! ! for ASCAT file name stamp + ! date_time_tmp = date_time + ! call augment_date_time( -(dtstep_assim/2 + ae_time_offset), date_time_tmp ) - call Execute_command_line(trim(cmd)) + ! ! get tmp file name and remove file if it exists - ! identify all files within current assimilation interval - ! (list all files within hourly intervals) + ! call date_and_time(date_string, time_string) ! f90 intrinsic function + + ! tmpfname = trim(work_path) // '/' // 'tmp.' // trim(exp_id) & + ! // '.' // date_string // time_string + + ! cmd = '/bin/rm -f ' // tmpfname + + ! call Execute_command_line(trim(cmd)) + + ! ! identify all files within current assimilation interval + ! ! (list all files within hourly intervals) - ! Every EUMETSTA BUFR contains data over ~2 hr sensing period. it's necessary to - ! search additional files for obs. - do i=1,(dtstep_assim/3600)+2 + ! ! Every EUMETSTA BUFR contains data over ~2 hr sensing period. it's necessary to + ! ! search additional files for obs. + ! do i=1,(dtstep_assim/3600)+2 - write (YYYYMM,'(i6.6)') date_time_tmp%year*100 + date_time_tmp%month - write (DDHH, '(i4.4)') date_time_tmp%day *100 + date_time_tmp%hour + ! write (YYYYMM,'(i6.6)') date_time_tmp%year*100 + date_time_tmp%month + ! write (DDHH, '(i4.4)') date_time_tmp%day *100 + date_time_tmp%hour - ! EUMETSAT BUFR - cmd = 'ls ' // trim(this_obs_param%path) // '/Y' // YYYYMM(1:4) // & - '/M' // YYYYMM(5:6) // '/' // trim(this_obs_param%name) // '*-'& - // YYYYMM // DDHH // '*Z-*.bfr' + ! ! EUMETSAT BUFR + ! cmd = 'ls ' // trim(this_obs_param%path) // '/Y' // YYYYMM(1:4) // & + ! '/M' // YYYYMM(5:6) // '/' // trim(this_obs_param%name) // '*-'& + ! // YYYYMM // DDHH // '*Z-*.bfr' - cmd = trim(cmd) // ' >> ' // trim(tmpfname) + ! cmd = trim(cmd) // ' >> ' // trim(tmpfname) - call Execute_command_line(trim(cmd)) + ! call Execute_command_line(trim(cmd)) - call augment_date_time( 3600, date_time_tmp ) + ! call augment_date_time( 3600, date_time_tmp ) - end do + ! end do - ! find out how many need to be read + ! ! find out how many need to be read - tmpfname2 = trim(tmpfname) // '.wc' + ! tmpfname2 = trim(tmpfname) // '.wc' - cmd = 'wc -w ' // trim(tmpfname) // ' > ' // trim(tmpfname2) + ! cmd = 'wc -w ' // trim(tmpfname) // ' > ' // trim(tmpfname2) - call Execute_command_line(trim(cmd)) + ! call Execute_command_line(trim(cmd)) - open(10, file=tmpfname2, form='formatted', action='read') + ! open(10, file=tmpfname2, form='formatted', action='read') - read(10,*) N_files + ! read(10,*) N_files - close(10,status='delete') + ! close(10,status='delete') - ! load file names into "fnames" + ! ! load file names into "fnames" - open(10, file=tmpfname, form='formatted', action='read') + ! open(10, file=tmpfname, form='formatted', action='read') - if (N_files>0) then + ! if (N_files>0) then - allocate(fnames(N_files)) + ! allocate(fnames(N_files)) - do i=1,N_files - read(10,'(a)') fnames(i) - write(logunit,*) trim(fnames(i)) - end do + ! do i=1,N_files + ! read(10,'(a)') fnames(i) + ! write(logunit,*) trim(fnames(i)) + ! end do - end if + ! end if - close(10,status='delete') + ! close(10,status='delete') call system_clock(COUNT=clock_end) ! Stop timing elapsed_time=REAL((clock_end-clock_start)/clock_rate) From b954682d1d29a3fac7ceb7bb4cd076ff31085565 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Tue, 6 Jun 2023 15:59:01 -0400 Subject: [PATCH 081/308] timing in read_obs --- .../clsm_ensupd_read_obs.F90 | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 8cc30d63..6869e87b 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -7425,6 +7425,9 @@ subroutine read_obs( & character(len=*), parameter :: Iam = 'read_obs' character(len=400) :: err_msg + integer :: clock_start, clock_end, clock_rate + real(8) :: elapsed_time + ! ------------------------------------------------------------- scaled_obs = .false. ! initialize @@ -7511,6 +7514,8 @@ subroutine read_obs( & end if case ('ASCAT_META_SM_A', 'ASCAT_META_SM_D','ASCAT_METB_SM_A', 'ASCAT_METB_SM_D','ASCAT_METC_SM_A', 'ASCAT_METC_SM_D' ) + + call system_clock(clock_start) ! Start timing call read_obs_sm_ASCAT_EUMET( & work_path, exp_id, & @@ -7531,6 +7536,12 @@ subroutine read_obs( & end if + + call system_clock(clock_end, clock_rate) ! Stop timing + elapsed_time=(real(clock_end-clock_start)/real(clock_rate)) + write (logunit,*) '**** Elapsed time in obs_read: ', elapsed_time, ' seconds ****' + + case ('isccp_tskin_gswp2_v1') call read_obs_isccp_tskin_gswp2_v1( & @@ -7704,6 +7715,8 @@ subroutine read_obs( & 'SMAP_L2AP_Tbh_A', 'SMAP_L2AP_Tbv_A', & 'SMAP_L2AP_Tbh_D', 'SMAP_L2AP_Tbv_D' ) + call system_clock(clock_start) + call read_obs_SMAP_halforbit_Tb( & date_time, N_catd, this_obs_param, & dtstep_assim, tile_coord, tile_grid_d, & @@ -7720,7 +7733,11 @@ subroutine read_obs( & this_obs_param, tmp_obs, tmp_std_obs, tmp_assim ) end if - + + call system_clock(clock_end, clock_rate) ! Stop timi + elapsed_time=(real(clock_end-clock_start)/real(clock_rate)) + write (logunit,*) '**** Elapsed time in obs_read: ', elapsed_time, ' seconds ****' + case('LaRC_tskin-GOESW', 'LaRC_tskin-GOESE', 'LaRC_tskin-MET09', & 'LaRC_tskin-FY2E-', 'LaRC_tskin-MTST2') From d05c5de3d076ed8b03f7b9c79f4908867990fb03 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Thu, 8 Jun 2023 16:44:43 -0400 Subject: [PATCH 082/308] fname from list working but slow --- .../clsm_ensupd_read_obs.F90 | 44 +++++++++---------- 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 3599859a..ba80df0d 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -1633,8 +1633,8 @@ subroutine read_obs_sm_ASCAT_EUMET( & integer :: i, ind, N_tmp, N_files integer :: N_fnames, N_fnames_tmp - integer :: clock_start, clock_end, clock_rate - real(8) :: elapsed_time + integer :: clock_start, clock_end, clock_rate, clock_start_sr, clock_end_sr, clock_rate_sr + real(8) :: elapsed_time, elapsed_time_sr character(300), dimension(:), allocatable :: fnames @@ -1702,20 +1702,27 @@ subroutine read_obs_sm_ASCAT_EUMET( & end if - fnames = fname_list + fnames = fname_list(1:N_fnames) N_files = N_fnames + + write (logunit,*) 'File names from list (1): ', fnames do kk = 1,N_files tmpfname = fnames(kk) + write (logunit,*) 'tmpfname: ', tmpfname ! Remove the '/D03/' from the directory part as using "read_obs_SMAP_fnames" - ind = scan(tmpfname, "/D03/") + ind = index(tmpfname, "/D") + write (logunit,*) 'ind: ', ind if (ind > 0) then - tmpfname2 = tmpfname(1:ind-1) // tmpfname(ind+5:) + write (logunit,*) 'tmpfname(1:ind): ', tmpfname(1:ind) + write (logunit,*) 'tmpfname(ind+5:): ', tmpfname(ind+5:) + tmpfname2 = tmpfname(1:ind) // tmpfname(ind+5:) + write (logunit,*) 'tmpfname2: ', tmpfname2 end if fnames(kk) = trim(this_obs_param%path) // '/' // trim(tmpfname2) end do - write (logunit,*) 'File names from list: ', fnames + write (logunit,*) 'File names from list (2): ', fnames ! Find files with obs within the assimilation window (need to check this AMF) @@ -1760,8 +1767,8 @@ subroutine read_obs_sm_ASCAT_EUMET( & ! close(10,status='delete') - call system_clock(COUNT=clock_end) ! Stop timing - elapsed_time=REAL((clock_end-clock_start)/clock_rate) + call system_clock(clock_end, clock_rate) ! Stop timing + elapsed_time=REAL((clock_end-clock_start_sr)/clock_rate) write (logunit,*) 'Elapsed time file names: ', elapsed_time, ' milliseconds' @@ -1904,8 +1911,8 @@ subroutine read_obs_sm_ASCAT_EUMET( & deallocate(tmp1_obs) call system_clock(clock_end, clock_rate) ! Stop timing - elapsed_time_sr=(real(clock_end-clock_start)/real(clock_rate)) - write (logunit,*) 'Elapsed time bufr read from start: ', elapsed_time_sr, ' seconds' + elapsed_time=(real(clock_end-clock_start)/real(clock_rate)) + write (logunit,*) 'Elapsed time bufr read from start: ', elapsed_time, ' seconds' ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! @@ -1922,9 +1929,6 @@ subroutine read_obs_sm_ASCAT_EUMET( & ! a) determine grid cell that contains lat/lon ! b) determine tile within grid cell that contains lat/lon -! call system_clock(COUNT_RATE=clock_rate) ! Find the rate -! call system_clock(COUNT=clock_start) ! Start timing - if (N_tmp>0) then allocate(tmp_tile_num(N_tmp)) @@ -1966,9 +1970,6 @@ subroutine read_obs_sm_ASCAT_EUMET( & end do ! -------------------------------- - call system_clock(clock_end, clock_rate) ! Stop timing - elapsed_time=(real(clock_end-clock_start_sr)/real(clock_rate)) - write (logunit,*) 'Elapsed time after n_obs_in_tile from start: ', elapsed_time, ' seconds' ! normalize @@ -1995,11 +1996,6 @@ subroutine read_obs_sm_ASCAT_EUMET( & end if end do - - - call system_clock(clock_end, clock_rate) ! Stop timing - elapsed_time=(real(clock_end-clock_start_sr)/real(clock_rate)) - write (logunit,*) 'Elapsed time 4 from start: ', elapsed_time, ' seconds' ! clean up @@ -2018,10 +2014,10 @@ subroutine read_obs_sm_ASCAT_EUMET( & end if call system_clock(clock_end, clock_rate) ! Stop timing - elapsed_time=(real(clock_end-clock_start_sr)/real(clock_rate)) + elapsed_time_sr=(real(clock_end-clock_start_sr)/real(clock_rate)) write (logunit,*) 'Elapsed time in read_obs_sm_ASCAT_EUMET: ', elapsed_time, ' seconds' - elapsed_time = (elapsed_time_sr/elapsed_time)*100 + elapsed_time = (elapsed_time/elapsed_time_sr)*100 write (logunit,*) 'We spent ', elapsed_time, '% of time in bufr read' ! clean up @@ -7243,7 +7239,7 @@ subroutine read_obs_SMAP_fnames( date_time, this_obs_param, & if (istat/=0) then err_msg = 'cannot open file ' // trim(fname) - call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + ! call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) end if if (logit) write(logunit,'(400A)') 'reading file ' // trim(fname) From c3ace9adca2f10f02d4a0c6942b7b5ee905b5c99 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Sun, 11 Jun 2023 18:44:07 -0400 Subject: [PATCH 083/308] fname list read working and tidied --- .../clsm_ensupd_read_obs.F90 | 159 ++++++------------ 1 file changed, 52 insertions(+), 107 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index ba80df0d..f71270dc 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -1622,26 +1622,25 @@ subroutine read_obs_sm_ASCAT_EUMET( & character( 4) :: DDHH character( 6) :: YYYYMM character( 8) :: date_string - character( 10) :: time_string + character( 10) :: time_stringi + character( 15) :: str_date_time character( 80) :: fname_of_fname_list character(300) :: tmpfname, tmpfname2 character(400) :: cmd type(date_time_type) :: date_time_tmp - type(date_time_type) :: date_time_low - type(date_time_type) :: date_time_upp + type(date_time_type) :: date_time_low, date_time_low_fname + type(date_time_type) :: date_time_up - integer :: i, ind, N_tmp, N_files + integer :: i, ind, N_tmp, N_files, kk integer :: N_fnames, N_fnames_tmp - integer :: clock_start, clock_end, clock_rate, clock_start_sr, clock_end_sr, clock_rate_sr - real(8) :: elapsed_time, elapsed_time_sr - character(300), dimension(:), allocatable :: fnames + character(300), dimension(:), allocatable :: fnames, tmpfnames real(8) :: tmp_data, tmp_vdata(4), tmp_time(6) integer, parameter :: lnbufr = 50 integer, parameter :: max_rec = 200000 - integer :: idate,iret,kk + integer :: idate,iret integer :: ireadmg,ireadsb character(8) :: subset @@ -1671,30 +1670,33 @@ subroutine read_obs_sm_ASCAT_EUMET( & found_obs = .false. - call system_clock(clock_start_sr) ! Start timing - ! find files that are within half-open interval ! [date_time-dtstep_assim/2,date_time+dtstep_assim/2) date_time_low = date_time call augment_date_time( -(dtstep_assim/2), date_time_low) - date_time_upp = date_time - call augment_date_time( (dtstep_assim/2), date_time_upp) + date_time_up = date_time + call augment_date_time( (dtstep_assim/2), date_time_up) + + ! Calculate an "extra" date_time_low to catch files with time stamps before window but containing relevant obs -! read file with list of ASCAT file names for first day + date_time_low_fname = date_time + call augment_date_time( -(dtstep_assim), date_time_low) + + ! read file with list of ASCAT file names for first day fname_of_fname_list = 'dummy' ! Make sure its in the obs_param nml - call read_obs_SMAP_fnames( date_time_low, this_obs_param, & + call read_obs_SMAP_fnames( date_time_low_fname, this_obs_param, & fname_of_fname_list, N_fnames_max, & N_fnames, fname_list(1:N_fnames_max) ) ! if needed, read file with list of ASCAT file names for second day and add ! file names into "fname_list" - if (date_time_low%day /= date_time_upp%day) then + if (date_time_low_fname%day /= date_time_up%day) then - call read_obs_SMAP_fnames( date_time_upp, this_obs_param, & + call read_obs_SMAP_fnames( date_time_up, this_obs_param, & fname_of_fname_list, N_fnames_max, & N_fnames_tmp, fname_list((N_fnames+1):(N_fnames+N_fnames_max)) ) @@ -1702,90 +1704,38 @@ subroutine read_obs_sm_ASCAT_EUMET( & end if - fnames = fname_list(1:N_fnames) - N_files = N_fnames - - write (logunit,*) 'File names from list (1): ', fnames + tmpfnames = fname_list(1:N_fnames) - do kk = 1,N_files - tmpfname = fnames(kk) - write (logunit,*) 'tmpfname: ', tmpfname + N_tmp = 0 + + do kk = 1,N_fnames + tmpfname = fname_list(kk) + ! Are we in the required assimilation window? + !e.g. Y2019/M07/D02/M01-ASCA-ASCSMO02-NA-5.0-20190702075700.000000000Z-20190702084627-1350204.bfr + str_date_time = tmpfname(40:53) + + read(str_date_time(1:4), *) date_time_tmp%year + read(str_date_time(5:6), *) date_time_tmp%month + read(str_date_time(7:8), *) date_time_tmp%day + read(str_date_time(9:10), *) date_time_tmp%hour + read(str_date_time(11:12), *) date_time_tmp%min + read(str_date_time(13:14), *) date_time_tmp%sec + + if ( datetime_lt_refdatetime( date_time_low_fname, date_time_tmp ) .and. & + datetime_le_refdatetime( date_time_tmp, date_time_up )) then + N_tmp = N_tmp + 1 ! Remove the '/D03/' from the directory part as using "read_obs_SMAP_fnames" ind = index(tmpfname, "/D") - write (logunit,*) 'ind: ', ind + if (ind > 0) then - write (logunit,*) 'tmpfname(1:ind): ', tmpfname(1:ind) - write (logunit,*) 'tmpfname(ind+5:): ', tmpfname(ind+5:) tmpfname2 = tmpfname(1:ind) // tmpfname(ind+5:) - write (logunit,*) 'tmpfname2: ', tmpfname2 end if - fnames(kk) = trim(this_obs_param%path) // '/' // trim(tmpfname2) - end do - - write (logunit,*) 'File names from list (2): ', fnames - - ! Find files with obs within the assimilation window (need to check this AMF) - - - ! ! for ASCAT file name stamp - ! date_time_tmp = date_time - ! call augment_date_time( -(dtstep_assim/2 + ae_time_offset), date_time_tmp ) - - ! ! get tmp file name and remove file if it exists - - ! call date_and_time(date_string, time_string) ! f90 intrinsic function - - ! tmpfname = trim(work_path) // '/' // 'tmp.' // trim(exp_id) & - ! // '.' // date_string // time_string - - ! cmd = '/bin/rm -f ' // tmpfname - - ! call Execute_command_line(trim(cmd)) - - ! ! identify all files within current assimilation interval - ! ! (list all files within hourly intervals) + tmpfnames(N_tmp) = trim(this_obs_param%path) // '/' // trim(tmpfname2) + end if + end do - ! ! Every EUMETSTA BUFR contains data over ~2 hr sensing period. it's necessary to - ! ! search additional files for obs. - ! do i=1,(dtstep_assim/3600)+2 - - ! write (YYYYMM,'(i6.6)') date_time_tmp%year*100 + date_time_tmp%month - ! write (DDHH, '(i4.4)') date_time_tmp%day *100 + date_time_tmp%hour - - ! ! EUMETSAT BUFR - ! cmd = 'ls ' // trim(this_obs_param%path) // '/Y' // YYYYMM(1:4) // & - ! '/M' // YYYYMM(5:6) // '/' // trim(this_obs_param%name) // '*-'& - ! // YYYYMM // DDHH // '*Z-*.bfr' - - ! cmd = trim(cmd) // ' >> ' // trim(tmpfname) - - ! call Execute_command_line(trim(cmd)) - - ! call augment_date_time( 3600, date_time_tmp ) - - ! end do - - ! close(10,status='delete') - - call system_clock(clock_end, clock_rate) ! Stop timing - elapsed_time=REAL((clock_end-clock_start_sr)/clock_rate) - - write (logunit,*) 'Elapsed time file names: ', elapsed_time, ' milliseconds' - - ! read observations: - ! - ! 1.) read N_tmp observations and their lat/lon info from file - ! 2.) for each observation - ! a) determine grid cell that contains lat/lon - ! b) determine tile within grid cell that contains lat/lon - ! 3.) compute super-obs for each tile from all obs w/in that tile - ! - ! ---------------------------------------------------------------- - ! - ! 1.) read N_tmp observations and their lat/lon info from file - -! call system_clock(COUNT_RATE=clock_rate) ! Find the rate -! call system_clock(COUNT=clock_start) ! Start timing + fnames = tmpfnames(1:N_tmp) + N_files = N_tmp ! read and process data if files are found allocate(tmp1_lon(max_rec)) @@ -1794,7 +1744,6 @@ subroutine read_obs_sm_ASCAT_EUMET( & allocate(tmp1_jtime(max_rec)) if (N_files>0) then - call system_clock(clock_start) ! file loop N_tmp = 0 @@ -1817,10 +1766,11 @@ subroutine read_obs_sm_ASCAT_EUMET( & date_time_tmp.hour = int(tmp_time(4)) date_time_tmp.min = int(tmp_time(5)) date_time_tmp.sec = int(tmp_time(6)) + ! skip if record outside of current assim window - if ( datetime_lt_refdatetime( date_time_low, date_time_tmp ) .and. & - datetime_le_refdatetime( date_time_tmp, date_time_upp )) cycle loop_report - + if ( datetime_lt_refdatetime( date_time_tmp, date_time_low ) .and. & + datetime_le_refdatetime( date_time_up, date_time_tmp )) cycle loop_report + ! skip if record contain no valid soil moisture value call ufbint(lnbufr,tmp_data,1,1,iret,'SSOM') if(tmp_data > 100. .or. tmp_data < 0.) cycle loop_report @@ -1910,11 +1860,6 @@ subroutine read_obs_sm_ASCAT_EUMET( & deallocate(tmp1_lat) deallocate(tmp1_obs) - call system_clock(clock_end, clock_rate) ! Stop timing - elapsed_time=(real(clock_end-clock_start)/real(clock_rate)) - write (logunit,*) 'Elapsed time bufr read from start: ', elapsed_time, ' seconds' - - ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! ! SOME QC SHOULD BE DONE HERE!!! @@ -2013,12 +1958,12 @@ subroutine read_obs_sm_ASCAT_EUMET( & end if - call system_clock(clock_end, clock_rate) ! Stop timing - elapsed_time_sr=(real(clock_end-clock_start_sr)/real(clock_rate)) - write (logunit,*) 'Elapsed time in read_obs_sm_ASCAT_EUMET: ', elapsed_time, ' seconds' +! call system_clock(clock_end, clock_rate) ! Stop timing +! elapsed_time_sr=(real(clock_end-clock_start_sr)/real(clock_rate)) +! write (logunit,*) 'Elapsed time in read_obs_sm_ASCAT_EUMET: ', elapsed_time, ' seconds' - elapsed_time = (elapsed_time/elapsed_time_sr)*100 - write (logunit,*) 'We spent ', elapsed_time, '% of time in bufr read' +! elapsed_time = (elapsed_time/elapsed_time_sr)*100 +! write (logunit,*) 'We spent ', elapsed_time, '% of time in bufr read' ! clean up From 532a7775b1a9acd171a55c1675cffe6c4ce84615 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Thu, 15 Jun 2023 15:33:23 -0400 Subject: [PATCH 084/308] fix date_time_low_fname bug --- .../GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index f71270dc..7b0bd8b7 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -1680,8 +1680,8 @@ subroutine read_obs_sm_ASCAT_EUMET( & ! Calculate an "extra" date_time_low to catch files with time stamps before window but containing relevant obs - date_time_low_fname = date_time - call augment_date_time( -(dtstep_assim), date_time_low) + date_time_low_fname = date_time_low + call augment_date_time( -(110*60), date_time_low_fname) ! read file with list of ASCAT file names for first day From cab71d78dbc3e338b7ca1d29cb3aafdca1f12b53 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Wed, 21 Jun 2023 14:00:13 -0400 Subject: [PATCH 085/308] reinstate exit on error --- .../clsm_ensupd_read_obs.F90 | 93 ++++++++++--------- 1 file changed, 51 insertions(+), 42 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 7b0bd8b7..cbfa1a10 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -1637,9 +1637,9 @@ subroutine read_obs_sm_ASCAT_EUMET( & character(300), dimension(:), allocatable :: fnames, tmpfnames - real(8) :: tmp_data, tmp_vdata(4), tmp_time(6) + real(8) :: tmp_data(7), tmp_vdata(4), tmp_time(6) integer, parameter :: lnbufr = 50 - integer, parameter :: max_rec = 200000 + integer, parameter :: max_rec = 20000 integer :: idate,iret integer :: ireadmg,ireadsb character(8) :: subset @@ -1737,14 +1737,16 @@ subroutine read_obs_sm_ASCAT_EUMET( & fnames = tmpfnames(1:N_tmp) N_files = N_tmp - ! read and process data if files are found - allocate(tmp1_lon(max_rec)) - allocate(tmp1_lat(max_rec)) - allocate(tmp1_obs(max_rec)) - allocate(tmp1_jtime(max_rec)) - if (N_files>0) then + + + ! read and process data if files are found + allocate(tmp1_lon(max_rec)) + allocate(tmp1_lat(max_rec)) + allocate(tmp1_obs(max_rec)) + allocate(tmp1_jtime(max_rec)) + call MTINFO( trim(this_obs_param%path) // '/BUFR_mastertable/', 51, 52) ! file loop N_tmp = 0 do kk = 1,N_files @@ -1756,7 +1758,7 @@ subroutine read_obs_sm_ASCAT_EUMET( & call MTINFO( trim(this_obs_param%path) // '/BUFR_mastertable/', 51, 52) call datelen(10) - msg_report: do while(ireadmg(lnbufr,subset,idate) ==0) + msg_report: do while(ireadmg(lnbufr,subset,idate) ==0) loop_report: do while(ireadsb(lnbufr) == 0) ! extract sensing time information call ufbint(lnbufr,tmp_time,6,1,iret,'YEAR MNTH DAYS HOUR MINU SECO') @@ -1770,10 +1772,14 @@ subroutine read_obs_sm_ASCAT_EUMET( & ! skip if record outside of current assim window if ( datetime_lt_refdatetime( date_time_tmp, date_time_low ) .and. & datetime_le_refdatetime( date_time_up, date_time_tmp )) cycle loop_report + + + call ufbint(lnbufr,tmp_data,7,1,iret,'SSOM DOMO SMPF SMCF ALFR TPCX IWFR') + ! skip if record contain no valid soil moisture value - call ufbint(lnbufr,tmp_data,1,1,iret,'SSOM') - if(tmp_data > 100. .or. tmp_data < 0.) cycle loop_report +! call ufbint(lnbufr,tmp_data,1,1,iret,'SSOM') + if(tmp_data(1) > 100. .or. tmp_data(1) < 0.) cycle loop_report ! EUMETSAT file contains data of both ascending and descending orbits. ! DOMO - “Direction of motion of moving observing platform” is used to seperate Asc and Desc @@ -1781,31 +1787,31 @@ subroutine read_obs_sm_ASCAT_EUMET( & ! according to Pamela Schoebel-Pattiselanno, EUMETSAT User Services Helpdesk ! "When the value (of DOMO) is between 180 and 270 degrees, it is the descending part ! of the orbit … when it is between 270 and 360 degrees, it is the ascending part" - call ufbint(lnbufr,tmp_data,1,1,iret,'DOMO') - if (index(this_obs_param%descr,'_A') /=0 .and. (tmp_data < 270 .or. tmp_data > 360)) cycle loop_report - if (index(this_obs_param%descr,'_D') /=0 .and. (tmp_data < 180 .or. tmp_data >= 270)) cycle loop_report +! call ufbint(lnbufr,tmp_data,1,1,iret,'DOMO') + if (index(this_obs_param%descr,'_A') /=0 .and. (tmp_data(2) < 270 .or. tmp_data(2) > 360)) cycle loop_report + if (index(this_obs_param%descr,'_D') /=0 .and. (tmp_data(2) < 180 .or. tmp_data(2) >= 270)) cycle loop_report ! skip if processing flag is set - call ufbint(lnbufr,tmp_data,1,1,iret,'SMPF') - if(int(tmp_data) /= 0) cycle loop_report +! call ufbint(lnbufr,tmp_data,1,1,iret,'SMPF') + if(int(tmp_data(3)) /= 0) cycle loop_report ! skip if correction flag is set - call ufbint(lnbufr,tmp_data,1,1,iret,'SMCF') - if (.not. (int(tmp_data) == 0 .or. int(tmp_data) == 4)) cycle loop_report +! call ufbint(lnbufr,tmp_data,1,1,iret,'SMCF') + if (.not. (int(tmp_data(4)) == 0 .or. int(tmp_data(4)) == 4)) cycle loop_report ! if(int(tmp_data) /= 0) cycle loop_report ! skip if land fraction is missing or < 0.9 - call ufbint(lnbufr,tmp_data,1,1,iret,'ALFR') - if(tmp_data >1 .or. tmp_data < 0.9 ) cycle loop_report +! call ufbint(lnbufr,tmp_data,1,1,iret,'ALFR') + if(tmp_data(5) >1 .or. tmp_data(5) < 0.9 ) cycle loop_report ! additioanal QC varibles from file ! skip if topographic complexity > 10% - call ufbint(lnbufr,tmp_data,1,1,iret,'TPCX') ! topo complexity - if(tmp_data > 10.) cycle loop_report +! call ufbint(lnbufr,tmp_data,1,1,iret,'TPCX') ! topo complexity + if(tmp_data(6) > 10.) cycle loop_report ! skip if inudatation and wetland faction > 10% - call ufbint(lnbufr,tmp_data,1,1,iret,'IWFR') ! Inundation And Wetland Fraction - if(tmp_data > 10.) cycle loop_report +! call ufbint(lnbufr,tmp_data,1,1,iret,'IWFR') ! Inundation And Wetland Fraction + if(tmp_data(7) > 10.) cycle loop_report !call ufbint(lnbufr,tmp_data,1,1,iret,'SNOC') ! snow cover !call ufbint(lnbufr,tmp_data,1,1,iret,'FLSF') ! frozen land fraction @@ -1822,6 +1828,7 @@ subroutine read_obs_sm_ASCAT_EUMET( & end do loop_report end do msg_report + call closbf(lnbufr) close(lnbufr) @@ -1840,25 +1847,27 @@ subroutine read_obs_sm_ASCAT_EUMET( & end if deallocate(fnames) - else - N_tmp = 0 - - end if - allocate(tmp_jtime(N_tmp)) - allocate(tmp_lon(N_tmp)) - allocate(tmp_lat(N_tmp)) - allocate(tmp_obs(N_tmp)) + allocate(tmp_jtime(N_tmp)) + allocate(tmp_lon(N_tmp)) + allocate(tmp_lat(N_tmp)) + allocate(tmp_obs(N_tmp)) - tmp_jtime = tmp1_jtime(1:N_tmp) - tmp_lon = tmp1_lon(1:N_tmp) - tmp_lat = tmp1_lat(1:N_tmp) - tmp_obs = tmp1_obs(1:N_tmp) + tmp_jtime = tmp1_jtime(1:N_tmp) + tmp_lon = tmp1_lon(1:N_tmp) + tmp_lat = tmp1_lat(1:N_tmp) + tmp_obs = tmp1_obs(1:N_tmp) - deallocate(tmp1_jtime) - deallocate(tmp1_lon) - deallocate(tmp1_lat) - deallocate(tmp1_obs) + deallocate(tmp1_jtime) + deallocate(tmp1_lon) + deallocate(tmp1_lat) + deallocate(tmp1_obs) + + else + N_tmp = 0 + + end if + ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! @@ -7181,10 +7190,10 @@ subroutine read_obs_SMAP_fnames( date_time, this_obs_param, & fname = trim(fpath_tmp) // '/' // YYYYMMDDdir // trim(fname_tmp) open( 10, file=fname, form='formatted', action='read', iostat=istat) - + if (istat/=0) then err_msg = 'cannot open file ' // trim(fname) - ! call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) end if if (logit) write(logunit,'(400A)') 'reading file ' // trim(fname) From 5c3a4011f0b657143a1be2bb40fdeb789bb867b9 Mon Sep 17 00:00:00 2001 From: Rolf Reichle <54944691+gmao-rreichle@users.noreply.github.com> Date: Thu, 22 Jun 2023 12:18:46 -0400 Subject: [PATCH 086/308] Change to GEOS_Util v2.0.1 (components.yaml) --- components.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components.yaml b/components.yaml index 6f91c112..b3d29462 100644 --- a/components.yaml +++ b/components.yaml @@ -29,7 +29,7 @@ GMAO_Shared: GEOS_Util: local: ./src/Shared/@GMAO_Shared/@GEOS_Util remote: ../GEOS_Util.git - tag: v2.0.0 + tag: v2.0.1 develop: main MAPL: From 4fd7d22c7efafa357e1f590b90fc2d522f99e4b2 Mon Sep 17 00:00:00 2001 From: Rolf Reichle <54944691+gmao-rreichle@users.noreply.github.com> Date: Fri, 23 Jun 2023 08:48:02 -0400 Subject: [PATCH 087/308] Moved and edited block for CATCHMENT_SPINUP (GEOSldas_LDAS.rc) --- src/Applications/LDAS_App/GEOSldas_LDAS.rc | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/Applications/LDAS_App/GEOSldas_LDAS.rc b/src/Applications/LDAS_App/GEOSldas_LDAS.rc index 9b462ae1..3c290a17 100644 --- a/src/Applications/LDAS_App/GEOSldas_LDAS.rc +++ b/src/Applications/LDAS_App/GEOSldas_LDAS.rc @@ -11,7 +11,7 @@ #################################################################################### -# ---- Using Catchment/CatchmentCN offline? +# ---- Using Catchment[CN] offline? # # 0: DEFAULT for GCM, (WW,CH,CM,CQ,FR) are required in Catchment restart file # 1: DEFAULT for GEOSldas, (WW,CH,CM,CQ,FR) are optional @@ -20,6 +20,15 @@ # CATCHMENT_OFFLINE: 1 + +# ---- Catchment[CN] spinup mode +# +# 0 : No spinup (default) +# 1 : remove snow every Aug 1 in N. Hemisphere and every Feb 1 in S. Hemisphere +# +CATCHMENT_SPINUP: 0 + + # ---- Choice of land surface model # # 1 : Catchment model (default) @@ -28,13 +37,6 @@ CATCHMENT_OFFLINE: 1 # LSM_CHOICE: 1 -# ---- Catchment/CatchmentCN spinup mode -# -# 0 : None (default) -# 1 : Remove snow every Aug 1 (Northern Hemisphere) or Feb 1 (Southern Hemisphere) -# -CATCHMENT_SPINUP: 0 - # ---- Domain definition # From 7f6e047ba1b2db7fcc455abf69ae478f8e36591d Mon Sep 17 00:00:00 2001 From: amfox37 Date: Fri, 23 Jun 2023 14:08:26 -0600 Subject: [PATCH 088/308] add dt_ASCAT_obsfile parameter --- components.yaml | 2 +- .../GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 | 10 +++------- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/components.yaml b/components.yaml index 82eb317c..b6169e0b 100644 --- a/components.yaml +++ b/components.yaml @@ -36,7 +36,7 @@ GMAO_Shared: GEOS_Util: local: ./src/Shared/@GMAO_Shared/@GEOS_Util remote: ../GEOS_Util.git - tag: v2.0.0 + tag: v2.0.1 develop: main MAPL: diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index cbfa1a10..5c2340f2 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -1606,15 +1606,11 @@ subroutine read_obs_sm_ASCAT_EUMET( & ! --------------- - ! Each obs file contains about 1 hour 40 minutes observations + ! Each obs file contains about 100 - 110 minutes of observations. Code as dt_ASCAT_obsfile ! file name indicates the start time of the swaths. - ! "ae_time_offset" is used to find the mean time of the the interval - ! which is approximately the time of the equator overpass. - ! This time is assigned to all observations of the swath. - ! Will need to be updated if using EUMETSAT BUFR files + integer, parameter :: dt_ASCAT_obsfile = 110*60 ! seconds -! integer, parameter :: ae_time_offset = 3600 ! 60 minutes in seconds integer, parameter :: N_fnames_max = 20 character(4), parameter :: J2000_epoch_id = 'TT12' ! see date_time_util.F90 @@ -1681,7 +1677,7 @@ subroutine read_obs_sm_ASCAT_EUMET( & ! Calculate an "extra" date_time_low to catch files with time stamps before window but containing relevant obs date_time_low_fname = date_time_low - call augment_date_time( -(110*60), date_time_low_fname) + call augment_date_time( -dt_ASCAT_obsfile, date_time_low_fname) ! read file with list of ASCAT file names for first day From 40ee3287d38650e27b58cd18ca79d983ca9d85bb Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Sat, 24 Jun 2023 08:57:33 -0400 Subject: [PATCH 089/308] add documentation for release v17.13.1 (CHANGELOG.md) --- doc/CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index 0861c4bf..54b2545d 100644 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -33,6 +33,18 @@ This README file contains the history of stable GEOSldas versions ("tags") in Gi Overview of Git Releases: ============================ +[v17.13.1](https://github.com/GEOS-ESM/GEOSldas/releases/tag/v17.13.1) - 2023-06-26 +------------------------------ + +- 0-diff vs. v17.13.0. + +- Infrastructure: + - GEOS_Util v2.0.1 ([PR #657](https://github.com/GEOS-ESM/GEOSldas/pull/657), [PR #658](https://github.com/GEOS-ESM/GEOSldas/pull/658)). + +- Bug fixes: + - Fixed error in remapping of restarts with GEOSldas (GEOSgcm_Util [PR#23](https://github.com/GEOS-ESM/GEOSgcm_Util/pull/23)). + +------------------------------ [v17.13.0](https://github.com/GEOS-ESM/GEOSldas/releases/tag/v17.13.0) - 2023-05-18 ------------------------------ From e57f0de454032414d1d0b06915f541f2de0cee45 Mon Sep 17 00:00:00 2001 From: biljanaorescanin Date: Wed, 28 Jun 2023 15:10:33 -0400 Subject: [PATCH 090/308] catchcn needed file; path change --- src/Applications/LDAS_App/ldas_setup | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Applications/LDAS_App/ldas_setup b/src/Applications/LDAS_App/ldas_setup index 54d50070..e2ecbabd 100755 --- a/src/Applications/LDAS_App/ldas_setup +++ b/src/Applications/LDAS_App/ldas_setup @@ -788,7 +788,7 @@ class LDASsetup: os.symlink(bc,myBC) if ("catchcn" in self.catch): - os.symlink('/discover/nobackup/projects/gmao/bcs_shared/make_bcs_inputs/land/CO2/v1/CO2_MonthlyMean_DiurnalCycle.nc4', \ + os.symlink(self.rqdExeInp['BCS_PATH']+'../land/shared/CO2_MonthlyMean_DiurnalCycle.nc4', \ self.inpdir+'/CO2_MonthlyMean_DiurnalCycle.nc4') # create and link restart From 8972493cb33adc84be9cfe9a3fadf66634150599 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Mon, 3 Jul 2023 13:54:13 -0400 Subject: [PATCH 091/308] bug fix in matlab reader (MAPL_ReadForcing_fullfile.m) --- .../LDAS_App/util/shared/matlab/MAPL_ReadForcing_fullfile.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Applications/LDAS_App/util/shared/matlab/MAPL_ReadForcing_fullfile.m b/src/Applications/LDAS_App/util/shared/matlab/MAPL_ReadForcing_fullfile.m index 0e5b6227..14f8cc6c 100644 --- a/src/Applications/LDAS_App/util/shared/matlab/MAPL_ReadForcing_fullfile.m +++ b/src/Applications/LDAS_App/util/shared/matlab/MAPL_ReadForcing_fullfile.m @@ -12,10 +12,10 @@ % % check whether no-data variables are available on input -if ~exist('nodata'), nodata = 1.e15; end % default: MAPL_UNDEF -if ~exist('nodata_tolfrac'), nodata_tolfrac = 1.e-4; end +if ~exist('nodata', 'var'), nodata = 1.e15; end % default: MAPL_UNDEF +if ~exist('nodata_tolfrac', 'var'), nodata_tolfrac = 1.e-4; end -nodata_tol = abs( nodata*nodata_tol_frac ); +nodata_tol = abs( nodata*nodata_tolfrac ); % ------------------------------------------------------------------------- From affc04fe17570cec4e5e0cd590b37b5154953889 Mon Sep 17 00:00:00 2001 From: Matthew Thompson Date: Mon, 3 Jul 2023 19:41:29 -0400 Subject: [PATCH 092/308] Update components.yaml to match GEOSgcm --- .github/workflows/enforce-labels.yml | 7 +++---- .github/workflows/push-to-develop.yml | 4 ++-- .github/workflows/release-tarball.yml | 4 ++-- components.yaml | 8 ++++---- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/.github/workflows/enforce-labels.yml b/.github/workflows/enforce-labels.yml index 3e27600d..86f4bb4e 100644 --- a/.github/workflows/enforce-labels.yml +++ b/.github/workflows/enforce-labels.yml @@ -8,20 +8,20 @@ jobs: require-label: runs-on: ubuntu-latest steps: - - uses: mheap/github-action-required-labels@v3 + - uses: mheap/github-action-required-labels@v5 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: mode: minimum count: 1 - labels: "0 diff,0 diff trivial,Non 0-diff,0 diff structural,0-diff trivial,Not 0-diff,0-diff,automatic,0-diff uncoupled" + labels: "0 diff,0 diff trivial,Non 0-diff,0 diff structural,0-diff trivial,Not 0-diff,0-diff,automatic,0-diff uncoupled,github_actions" add_comment: true message: "This PR is being prevented from merging because you have not added one of our required labels: {{ provided }}. Please add one so that the PR can be merged." blocking-label: runs-on: ubuntu-latest steps: - - uses: mheap/github-action-required-labels@v3 + - uses: mheap/github-action-required-labels@v5 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: @@ -30,4 +30,3 @@ jobs: labels: "Contingent - DNA,Needs Lead Approval,Contingent -- Do Not Approve" add_comment: true message: "This PR is being prevented from merging because you have added one of our blocking labels: {{ provided }}. You'll need to remove it before this PR can be merged." - diff --git a/.github/workflows/push-to-develop.yml b/.github/workflows/push-to-develop.yml index 59424134..fd525b2a 100644 --- a/.github/workflows/push-to-develop.yml +++ b/.github/workflows/push-to-develop.yml @@ -11,11 +11,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repo - uses: actions/checkout@v2 + uses: actions/checkout@v3.3.0 with: fetch-depth: 0 - name: Run the action - uses: devops-infra/action-pull-request@v0.4 + uses: devops-infra/action-pull-request@v0.5.5 with: github_token: ${{ secrets.GITHUB_TOKEN }} source_branch: develop diff --git a/.github/workflows/release-tarball.yml b/.github/workflows/release-tarball.yml index 467370db..41f28389 100644 --- a/.github/workflows/release-tarball.yml +++ b/.github/workflows/release-tarball.yml @@ -10,12 +10,12 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3.3.0 with: path: ${{ github.event.repository.name }}-${{ github.event.release.tag_name }} - name: Checkout mepo - uses: actions/checkout@v2 + uses: actions/checkout@v3.3.0 with: repository: GEOS-ESM/mepo path: mepo diff --git a/components.yaml b/components.yaml index b3d29462..23b91951 100644 --- a/components.yaml +++ b/components.yaml @@ -5,13 +5,13 @@ GEOSldas: env: local: ./@env remote: ../ESMA_env.git - tag: v4.16.0 + tag: v4.17.0 develop: main cmake: local: ./@cmake remote: ../ESMA_cmake.git - tag: v3.28.0 + tag: v3.30.0 develop: develop ecbuild: @@ -22,7 +22,7 @@ ecbuild: GMAO_Shared: local: ./src/Shared/@GMAO_Shared remote: ../GMAO_Shared.git - tag: v1.9.0 + tag: v1.9.1 sparse: ./config/GMAO_Shared.sparse develop: main @@ -35,7 +35,7 @@ GEOS_Util: MAPL: local: ./src/Shared/@MAPL remote: ../MAPL.git - tag: v2.39.1 + tag: v2.39.4 develop: develop GEOSgcm_GridComp: From b7b148bb7e9f104444934bd90f5891349eb9bce5 Mon Sep 17 00:00:00 2001 From: Matthew Thompson Date: Mon, 3 Jul 2023 19:47:58 -0400 Subject: [PATCH 093/308] Update Baselibs in CI --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 096c8ed0..f886bcce 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,7 +1,7 @@ version: 2.1 # Anchor to prevent forgetting to update a version -baselibs_version: &baselibs_version v7.7.0 +baselibs_version: &baselibs_version v7.13.0 orbs: ci: geos-esm/circleci-tools@1 From ff413f11a317505f16217026401db5ba6cdc6345 Mon Sep 17 00:00:00 2001 From: Matthew Thompson Date: Tue, 4 Jul 2023 13:32:27 -0400 Subject: [PATCH 094/308] Update to GEOS_Util v2.0.2 --- components.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components.yaml b/components.yaml index 23b91951..5ca4fecb 100644 --- a/components.yaml +++ b/components.yaml @@ -29,7 +29,7 @@ GMAO_Shared: GEOS_Util: local: ./src/Shared/@GMAO_Shared/@GEOS_Util remote: ../GEOS_Util.git - tag: v2.0.1 + tag: v2.0.2 develop: main MAPL: From dd2b9474462ea3d65534a8a8a7b8956d6790daf3 Mon Sep 17 00:00:00 2001 From: Matthew Thompson Date: Thu, 6 Jul 2023 12:52:52 -0400 Subject: [PATCH 095/308] Move GEOSldas.F90 to use fArgParse --- src/Applications/LDAS_App/GEOSldas.F90 | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/Applications/LDAS_App/GEOSldas.F90 b/src/Applications/LDAS_App/GEOSldas.F90 index 4605aaad..5a09b3bc 100644 --- a/src/Applications/LDAS_App/GEOSldas.F90 +++ b/src/Applications/LDAS_App/GEOSldas.F90 @@ -4,7 +4,7 @@ program LDAS_Main - + ! !USES: use MAPL use GEOS_LDASGridCompMod, only: ROOT_SetServices => SetServices @@ -13,16 +13,15 @@ program LDAS_Main character(len=*), parameter :: Iam = "LDAS_Main" type (MAPL_Cap) :: cap - type (MAPL_FlapCLI) :: cli + type (MAPL_FargparseCLI) :: cli type (MAPL_CapOptions) :: cap_options integer :: status !EOP !---------------------------------------------------------------------- !BOC - - cli = MAPL_FlapCLI(description = 'GEOS LDAS', & - authors = 'GMAO') + + cli = MAPL_FargparseCLI() cap_options = MAPL_CapOptions(cli) cap_options%egress_file = 'EGRESS.ldas' @@ -31,5 +30,5 @@ program LDAS_Main !call MAPL_CAP(ROOT_SetServices, FinalFile='EGRESS.ldas', rc=status) !VERIFY_(status) - + end program LDAS_Main From 2698c97c92adfb1487a75e3171e5d099e2e45c23 Mon Sep 17 00:00:00 2001 From: "Lauren C. Andrews" Date: Mon, 10 Jul 2023 21:49:00 -0400 Subject: [PATCH 096/308] clean up of modis scf assimilation --- .../LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml | 10 +- src/Applications/LDAS_App/tile_bin2nc4.F90 | 14 +- .../clsm_ensupd_enkf_update.F90 | 20 +- .../clsm_ensupd_read_obs.F90 | 1012 +++++++++-------- .../clsm_ensupd_upd_routines.F90 | 74 +- 5 files changed, 568 insertions(+), 562 deletions(-) diff --git a/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml b/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml index 259eeb52..dcc2f6b1 100644 --- a/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml +++ b/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml @@ -1157,10 +1157,10 @@ obs_param_nml(24)%adapt = 0 ! -------------------------------------------------------------------- ! -! 21 = MODIS SCF +! 25 = MODIS SCF ! -! TO DO: which platform? -! TO DO: figure out orbit (day!) +! platform: SCF assimilation is currently set up to use MOD10C1.061 (MODIS/Terra 0.05deg CMG, V61) +! specs: The assimilation occurs at +/-3h passover time (10:30am local). The assimilation only contains a single member. obs_param_nml(25)%descr = 'MODIS_SCF' obs_param_nml(25)%orbit = 0 @@ -1179,13 +1179,13 @@ obs_param_nml(25)%bias_tcut = 432000 obs_param_nml(25)%nodata = -9999. obs_param_nml(25)%varname = 'asnow' obs_param_nml(25)%units = 'm2/m2' -obs_param_nml(25)%path = '' +obs_param_nml(25)%path = '/discover/nobackup/projects/S2SHMA/MODIS/MOD10C1_C61/' obs_param_nml(25)%name = '' obs_param_nml(25)%scalepath = '' obs_param_nml(25)%scalename = '' obs_param_nml(25)%flistpath = '' obs_param_nml(25)%flistname = '' -obs_param_nml(25)%errstd = .0 +obs_param_nml(25)%errstd = 0.0004 obs_param_nml(25)%std_normal_max = 2.5 obs_param_nml(25)%zeromean = .true. obs_param_nml(25)%coarsen_pert = .false. diff --git a/src/Applications/LDAS_App/tile_bin2nc4.F90 b/src/Applications/LDAS_App/tile_bin2nc4.F90 index e50a9eb5..3a56e61f 100644 --- a/src/Applications/LDAS_App/tile_bin2nc4.F90 +++ b/src/Applications/LDAS_App/tile_bin2nc4.F90 @@ -250,12 +250,12 @@ FUNCTION getAttribute (SHORT_NAME, LNAME, UNT) result (str_atr) case ('TB_LAND_1410MHZ_40DEG_VPOL'); LONG_NAME = 'brightness_temperature_land_1410MHz_40deg_Vpol'; UNITS = 'K' ! Done for SM_L4 - + case ('Tair'); LONG_NAME = 'air_temperature_at_RefH'; UNITS = 'K' case ('TA'); LONG_NAME = 'air_temperature_at_RefH'; UNITS = 'K' case ('Qair'); LONG_NAME = 'specific_humidity_at_RefH'; UNITS = 'kg kg-1' case ('QA'); LONG_NAME = 'specific_humidity_at_RefH'; UNITS = 'kg kg-1' - case ('LWdown'); LONG_NAME = 'downward_longwave_radiation"'; UNITS = 'W m-2' + case ('LWdown'); LONG_NAME = 'downward_longwave_radiation'; UNITS = 'W m-2' case ('LWDNSRF'); LONG_NAME = 'perturbed_surface_downwelling_longwave_flux'; UNITS = 'W m-2' case ('SWdown'); LONG_NAME = 'downward_shortwave_radiation'; UNITS = 'W m-2' case ('Wind'); LONG_NAME = 'wind_speed_at_RefH'; UNITS = 'm s-1' @@ -275,6 +275,16 @@ FUNCTION getAttribute (SHORT_NAME, LNAME, UNT) result (str_atr) case ('WESNN1'); LONG_NAME = 'snow_mass_layer_1'; UNITS = 'kg m-2' case ('WESNN2'); LONG_NAME = 'snow_mass_layer_2'; UNITS = 'kg m-2' case ('WESNN3'); LONG_NAME = 'snow_mass_layer_3'; UNITS = 'kg m-2' + case ('HTSNNN1'); LONG_NAME = 'heat_content_snow_layer_1'; UNITS = 'J m-2' + case ('HTSNNN2'); LONG_NAME = 'heat_content_snow_layer_2'; UNITS = 'J m-2' + case ('HTSNNN3'); LONG_NAME = 'heat_content_snow_layer_3'; UNITS = 'J m-2' + case ('SNDZN1'); LONG_NAME = 'snow_depth_layer_1'; UNITS = 'm' + case ('SNDZN2'); LONG_NAME = 'snow_depth_layer_2'; UNITS = 'm' + case ('SNDZN3'); LONG_NAME = 'snow_depth_layer_3'; UNITS = 'm' + case ('ALBVR'); LONG_NAME = 'surface_albedo_visible_beam'; UNITS = '1' + case ('ALBVF'); LONG_NAME = 'surface_albedo_visible_diffuse'; UNITS = '1' + case ('ALBNR'); LONG_NAME = 'surface_albedo_near_infared_beam'; UNITS = '1' + case ('ALBNF'); LONG_NAME = 'surface_albedo_near_infrared_diffuse'; UNITS = '1' case ('HLWUP'); LONG_NAME = 'surface_outgoing_longwave_flux'; UNITS = 'W m-2' case ('GWETPROF'); LONG_NAME = 'ave_prof_soil_wetness'; UNITS = '1' case ('GWETROOT'); LONG_NAME = 'root_zone_soil_wetness'; UNITS = '1' diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 index 40894afe..c3062c68 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 @@ -17,7 +17,7 @@ module clsm_ensupd_enkf_update USE CATCH_CONSTANTS, ONLY : & N_gt => CATCH_N_GT, & - N_snow => CATCH_N_SNOW !added jpark50 (07/19/21) + N_snow => CATCH_N_SNOW use catchment_model, ONLY: & catch_calc_tsurf @@ -1423,22 +1423,8 @@ subroutine apply_enkf_increments( N_catd, N_ens, update_type, & cat_progn_has_changed = .true. - case(11) select_update_type ! snow update !jpark50 - if (logit) write (logunit,*) 'applying Snow data increments' - - !if ( date_time%hour /= 0 .and. & - ! date_time%min /= 0 .and. & - ! date_time%sec /= 0 ) then - - ! if (logit) write (logunit,*) 'no application of increments at this time' - ! cat_progn_has_changed = .false. - ! return - - !end if - - if (logit) write (logunit,*) 'apply_enkf_increments(): applying asnow increments' - if (logit) write (logunit,*) 'entering do loop' - + case(11) select_update_type ! MODIS SCF update + !Rule-based snow SCF update do n=1,N_catd ! for each tile diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index e8dbc6ff..3713eb20 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -7,6 +7,8 @@ ! reichle, 1 Jul 2015 - clarified definition of obs time stamp ! (J2000 seconds w/ 'TT12' epoch) +!lcandre2, 10 Jul 2021 - confirmed and cleaned up MODIS obs + ! added work_path to inputs of many subroutines so that "tmpfname" ! (needed several times for reading AMSR-E hdf files) is distinct for each job ! reichle, 27 Aug 2005 @@ -84,491 +86,6 @@ module clsm_ensupd_read_obs contains - subroutine read_MODISsca_hdf( N_files, date_time, N_data, fnames, & - lon, lat, MODIS_SCA) - - !subroutine read_MODISsca_hdf routine description - !a. purpose: read snow cover data from daily MOD10C1 data located under lis folder - !b. MO10C1_C6 directory: /discover/nobackup/projects/lis/RS_DATA/MODIS_sca/MOD10C1_C6_download/ - ! [Note: No additional resampling of the MODIS SCA observation] - ! - daily datasets with spatial resolution of 0.05 deg on CMG grid - !c. dtstep_assim and ref_time is restricted to 3 hr and 00z, respectively - !d. Procedures - ! - Generating the latitude and longitude on CMG grid (1D array for now) - ! - Selection of the longitude band considering MODIS observation - ! time(local time: ~10:30am) - ! Table.Longitude band based on the assimilation time step (in UTC) - !----------------------------------------------------------------------------- - ! UTC | 0000 | 0300 | 0600 | 0900 | 1200 | 1500 | 1800 | 2100 - ! lon | 135 180 | 90 135 | 45 90 | 0 45 | -45 0| -90 -45| -135 -90| -180 -135 - !---------------------------------------------------------------------------- - ! - Quality Procedure - ! step 1: remove the Snow cover > 100 (e.g., lake, night, inland water, ocean..) - ! step 2: Clear Index (CI): CI > 20% is considered - ! step 3: Cloud Index not equal to 252 (which indicates the antartica region) - - implicit none - - integer, intent(in) :: N_files - type(date_time_type),intent(in) :: date_time ! loading the UTC hour information to constrain the longitude of MODIS obs. - integer, intent(out) :: N_data - character(*), dimension(N_files), intent(in) :: fnames - real, dimension(:), pointer :: lon, lat - real, dimension(:), pointer :: MODIS_SCA - real, dimension(:), allocatable :: MODIS_SCA_raw - character(1), dimension(:,:), allocatable :: tmp_MODIS_SCA, tmp_CI_Index, tmp_Cloud_index, tmp_Snow_QA - real, allocatable :: MODIS_SCA_tmp(:), lon_tmp(:), lat_tmp(:) - - !local parameters - integer, parameter:: N_fields = 4 - character(18), parameter:: Vdata_name = 'MODIS_CMG_Snow_5km' - character(30), dimension(N_fields), parameter:: field_names = (/ & - 'Day_CMG_Snow_Cover ', & !1 - 'Day_CMG_Clear_Index ', & !2 - 'Day_CMG_Cloud_Obscured ', & !3 - 'Snow_Spatial_QA '/) !4 - - integer,parameter :: nodata = -9999 !note: integer - integer,parameter :: qc_clear_index_threshold = 20 !screen for sufficiently clear condition - integer,parameter :: qc_clear_index_max_threshold = 100 ! removing the lake ice, night obs, ocean etc. - integer,parameter :: qc_snow_spatial_threshold = 3 !screen for basic data quality (e.g., 0:best 1:good 2:OK 3:poor, 4:others) - integer,parameter :: qc_snow_cover_threshold = 100 !screen for areas inland water, ocean, cloud obscured and fill - integer,parameter :: qc_antarctica = 252 ! screen for antarctica - - !declariations of hdf functions - integer:: sfstart, sffinfo, sfselect, sfn2index, sfginfo, sfrdata - integer:: sfend, sfendacc - - ! declarations of hdf-related parameters and variables - integer, dimension(N_files) :: file_id, sd_id - integer, dimension(N_fields) :: ind, sds_id - integer:: n_datasets, n_file_attrs, n_attrs, rank, data_type - integer:: dim_sizes(2) - character(100) :: var_name - integer:: start(2), edges(2), stride(2) - - integer :: status, n_read, record_pos - integer, parameter :: DFACC_READ = 1 ! from hdf.inc - integer, parameter :: DFNT_UINT8 = 21 - integer, parameter :: FULL_INTERLACE = 0 ! from hdf.inc - - ! local variables - logical :: must_stop, keep_data - - ! variables to define latitude and longitude - integer :: i, j, k, k_off, ll, mm, kk, L - integer :: time_index - - real, parameter :: bin_size = 0.05 - integer, parameter :: XGRID = 3600 - integer, parameter :: YGRID = 7200 - integer, dimension(N_files) :: N_data_tmp - - real :: lat_ind(XGRID) = (/(ll, ll=0, XGRID-1, 1)/) - real :: lon_ind(YGRID) = (/(mm, mm=0, YGRID-1, 1)/) - real, dimension(XGRID) :: lat_c(XGRID) - real, dimension(YGRID) :: lon_c(YGRID) - real, dimension(XGRID*YGRID) :: lat_1D, lon_1D - - real:: lon_subtime(9) = (/(kk, kk=180, -180, -45)/) - - integer, dimension(:), allocatable :: Snow_QA, CI_Index, Cloud_index - - character(len=*), parameter :: Iam = 'read_MODISsca_hdf' - character(len=400) :: err_msg - - ! initialize N_data - N_data_tmp(N_files) = XGRID*YGRID - - !if(logit) write(logunit, *) 'N_data_tmp=', N_data_tmp(1) - -! N_data = sum(N_data_tmp) - N_data = XGRID*YGRID - - !if (logit) write(logunit, *) 'N_data', N_data - - lat_c = (90-bin_size/2)-bin_size*lat_ind - lon_c = (-180+bin_size/2)+bin_size*lon_ind - - do i=1,7200 - lat_1D(3600*(i-1)+1:3600*i)= lat_c - lon_1D(3600*(i-1)+1:3600*i)= lon_c(i) - end do - - ! allocate pointers (must be deallocated outside this subroutine) - must_stop = .false. - - if ( associated(lon) .or. associated(lat) .or. associated(MODIS_SCA) ) then - must_stop = .true. - end if - - if (must_stop) then - err_msg = 'output pointers must not be associated/allocated on input.' - call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) - end if - - allocate(MODIS_SCA_raw(N_data)) - - allocate(CI_Index(N_data)) - allocate(Snow_QA(N_data)) - allocate(Cloud_Index(N_data)) - - ! read hdf data into arrays, concatenate data from N_files files - - k_off = 0 - - do j=1,N_files - ! open and start "hdf file" - !if(logit) write(logunit, *) 'fname: ', fnames(j) - - sd_id(j) = sfstart(fnames(j), DFACC_READ) - if(logit) write (logunit, *), 'sd_id:' , sd_id(j) - - status = sffinfo(sd_id(j), n_datasets, n_file_attrs) - !if(logit) write(logunit, *) '! Number of data sets in the file and Number of file attributes :' - !if(logit) write(logunit, *) 'sffinfo: ', status, n_datasets, n_file_attrs - - do i=1,N_fields - - ind(i) = sfn2index(sd_id(j), trim(field_names(i))) - ! if (logit) write(logunit, *), 'Field_name:', field_names(i) - ! if (logit) write(logunit, *), 'ind:', ind(i) - - sds_id(i) = sfselect(sd_id(j), ind(i)) - status = sfginfo(sds_id(i), var_name, rank, dim_sizes, data_type, n_attrs) - - start(1)=0 - start(2)=0 - edges(1) = dim_sizes(1) - edges(2) = dim_sizes(2) - stride(1) = 1 - stride(2) = 1 - - ! read data - select case (i) - - case (1) - allocate(tmp_MODIS_SCA(dim_sizes(1),dim_sizes(2))) - status = sfrdata(sds_id(i), start, stride, edges, tmp_MODIS_SCA) - - L=0 - do k=1, YGRID - do kk=1, XGRID - L=L+1 - MODIS_SCA_raw(L) = ichar(tmp_MODIS_SCA(k, kk)) - end do - end do - - case (2) - allocate(tmp_CI_Index(dim_sizes(1), dim_sizes(2))) - status = sfrdata(sds_id(i), start, stride, edges, tmp_CI_index) - - L=0 - do k=1, YGRID - do kk=1, XGRID - L=L+1 - CI_Index(L) = ichar(tmp_CI_index(k,kk)) - end do - end do - - case (3) - allocate(tmp_Cloud_index(dim_sizes(1), dim_sizes(2))) - status = sfrdata(sds_id(i), start, stride, edges, tmp_Cloud_index) - - L=0 - do k=1, YGRID - do kk=1, XGRID - L = L+1 - Cloud_index(L) = ichar(tmp_Cloud_index(k, kk)) - end do - end do - !if(logit) write(logunit,*) "L:", L - !if(logit) write(logunit,*) "size of Cloud_index", size(Cloud_index) - !if(logit) write(logunit,*) "Cloud_Index (252):", ichar(tmp_Cloud_index(5500,3500)) - !if(logit) write(logunit,*) "Cloud_Index (5499*3600+3500):", Cloud_index(19799900) - - case (4) - allocate(tmp_Snow_QA(dim_sizes(1),dim_sizes(2))) - status = sfrdata(sds_id(i), start, stride, edges, tmp_Snow_QA) - - L=0 - do k=1, YGRID - do kk=1, XGRID - L = L+1 - Snow_QA(L) = ichar(tmp_Snow_QA(k, kk)) - end do - end do - - case default - - call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'Unknown case') - end select - - if (dim_sizes(1)*dim_sizes(2)/=N_data_tmp(j)) then - call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'ERROR reading hdf') - end if - - status = sfendacc(sds_id(i)) - - end do - - ! clean up - deallocate(tmp_MODIS_SCA) - deallocate(tmp_CI_index) - deallocate(tmp_Cloud_index) - deallocate(tmp_Snow_QA) - - ! close hdf files - status = sfend(file_id(j)) - - end do - - time_index = date_time%hour/3 +1 - - ! ------------------------------------- - ! eliminate no-data-values and data that fail initial QC - - allocate(MODIS_SCA_tmp(N_data)) - allocate(lat_tmp(N_data)) - allocate(lon_tmp(N_data)) - j=0 - - do i=1,N_data - - keep_data = & - (MODIS_SCA_raw(i)>=0 .and. MODIS_SCA_raw(i)<=100) .and. & ! any neg is nodata - (lon_1D(i)<=lon_subtime(time_index)) .and. & !selection of longitudal band - (lon_1D(i)>lon_subtime(time_index+1)) .and. & - (CI_Index(i)>qc_clear_index_threshold) .and. & - (CI_Index(i)<=qc_clear_index_max_threshold) .and. & - (Cloud_index(i)/=qc_antarctica) .and. & - (Snow_QA(i)0) then - - allocate(tmp_tile_num(N_tmp)) - - call get_tile_num_for_obs(N_catd, tile_coord, & - tile_grid_d, N_tile_in_cell_ij, tile_num_in_cell_ij, & - N_tmp, tmp_lat, tmp_lon, & - this_obs_param, & - tmp_tile_num(1:N_tmp) ) - - !if(logit) write(logunit,*) 'tmp_tile_num:', size(tmp_tile_num) - - MODIS_obs = 0. - N_obs_in_tile = 0 - - do i=1,N_tmp - - ind = tmp_tile_num(i) ! 1<=tmp_tile_num<=N_catd (unless nodata) - - if (ind>0) then ! this step eliminates obs outside domain - MODIS_obs(ind) = MODIS_obs(ind) + tmp_obs(i) - N_obs_in_tile(ind) = N_obs_in_tile(ind) + 1 - end if - - end do - ! if(logit) write(logunit,*) 'length of MODIS_obs', size(MODIS_obs) - ! if(logit) write(logunit,*) 'length of N_obs_in_tile', size(N_obs_in_tile) - ! if(logit) write(logunit,*) 'N_obs_in_tile', N_obs_in_tile - - !normalize - do i=1,N_catd - if (N_obs_in_tile(i)>0) then - MODIS_obs(i) = MODIS_obs(i)/real(N_obs_in_tile(i)) - - else if (N_obs_in_tile(i) == 0) then - MODIS_obs(i) = this_obs_param%nodata - end if - end do - - !if(logit) write(logunit,*) 'N_catd', N_catd - !if(logit) write(logunit,*) 'length of MODIS_obs after super_obsing', size(MODIS_obs) - !if(logit) write(logunit,*) 'MODIS_obs (after normalization)', MODIS_obs - - if (associated(tmp_tile_num)) deallocate (tmp_tile_num) - - do i=1, N_catd - std_MODIS_obs(i) = this_obs_param%errstd - end do - - if (any(N_obs_in_tile>0)) then - found_obs = .true. - else - found_obs = .false. - end if - - end if - - !if(logit) write(logunit, *) 'found_obs=', found_obs - - if (associated(tmp_obs)) deallocate(tmp_obs) - if (associated(tmp_lon)) deallocate(tmp_lon) - if (associated(tmp_lat)) deallocate(tmp_lat) - end subroutine read_obs_MODISsca - ! ***************************************************************** subroutine read_ae_l2_sm_hdf( & N_files, fnames, N_data, lon, lat, ae_l2_sm, ease_col, ease_row ) @@ -5067,7 +4584,509 @@ subroutine read_obs_SMOS( date_time, N_catd, this_obs_param, & end subroutine read_obs_SMOS + + ! ***************************************************************** + + + subroutine read_MODISscf_hdf( N_files, date_time, N_data, fnames, & + lon, lat, MODIS_SCF) + + !subroutine read_MODISscf_hdf routine description + ! Purpose: read preprocessed (renamed) snow cover data from daily MODIS Terra MOD10C1, version 6.1 (https://nsidc.org/data/mod10c1/versions/61) + ! - Data currently located at /discover/nobackup/projects/S2SHMA/MODIS/MOD10C1_V61/ (2010-2022) + ! - Daily dataset with spatial resolution of 0.05 deg on CMG grid, missing days 2016 d. 50-58 + ! + ! Procedures: + ! - dtstep_assim and ref_time is restricted to 3 hr and 00z, respectively + ! - Generate the latitude and longitude on CMG grid + ! - Select longitude band considering MODIS observation time (local time: ~10:30am) + + ! Table. Longitude band based on the assimilation time step (in UTC) + !----------------------------------------------------------------------------- + ! UTC | 0000 | 0300 | 0600 | 0900 | 1200 | 1500 | 1800 | 2100 + ! lon | 135 180 | 90 135 | 45 90 | 0 45 | -45 0| -90 -45| -135 -90| -180 -135 + !---------------------------------------------------------------------------- + ! QC: + ! - Use Day_CMG_Snow_Cover > 100 (snow cover only) + ! - Use Day_CMG_Clear_Index > 20% (at least 20% clear sky) + ! - Use Day_CMG_Cloud_Obscured /= 252 (remove antarctica, not technically needed because this would be done by Snow_Spatial_QA) + ! - Use Snow_Spatial_QA <= 3 (use all data) + + + implicit none + + integer, intent(in) :: N_files + type(date_time_type), intent(in) :: date_time ! loading the UTC hour information to constrain the longitude of MODIS obs. + character(*), dimension(N_files), intent(in) :: fnames + integer, intent(out) :: N_data + + real, dimension(:), pointer :: lon, lat + real, dimension(:), pointer :: MODIS_SCF + real, dimension(:), allocatable :: MODIS_SCF_raw + + character(1), dimension(:,:), allocatable :: tmp_MODIS_SCF, tmp_CI_Index, tmp_Cloud_index, tmp_Snow_QA + + real, allocatable :: MODIS_SCF_tmp(:), lon_tmp(:), lat_tmp(:) + + !local parameters + integer, parameter:: N_fields = 4 + character(18), parameter:: Vdata_name = 'MODIS_CMG_Snow_5km' + character(30), dimension(N_fields), parameter:: field_names = (/ & + 'Day_CMG_Snow_Cover ', & !1 + 'Day_CMG_Clear_Index ', & !2 + 'Day_CMG_Cloud_Obscured ', & !3 + 'Snow_Spatial_QA '/) !4 + + integer, parameter :: nodata = -9999 !integer + + integer, parameter :: qc_snow_cover_threshold = 100 !screen for areas inland water, ocean, cloud obscured and fill + integer, parameter :: qc_clear_index_threshold = 20 !screen for sufficiently clear condition + integer, parameter :: qc_clear_index_max_threshold = 100 ! screen for lake ice, night obs, ocean + integer, parameter :: qc_antarctica = 252 ! screen for antarctica + integer, parameter :: qc_snow_spatial_threshold = 3 !screen for basic data quality (e.g., 0:best 1:good 2:OK 3:poor, 4:others) + + + !declariations of hdf functions + integer:: sfstart, sffinfo, sfselect, sfn2index, sfginfo, sfrdata + integer:: sfend, sfendacc + + ! declarations of hdf-related parameters and variables + integer, dimension(N_files) :: file_id, sd_id + integer, dimension(N_fields) :: ind, sds_id + integer :: n_datasets, n_file_attrs, n_attrs, rank, data_type + integer :: dim_sizes(2) + integer :: start(2), edges(2), stride(2) + character(100) :: var_name + + integer :: status, n_read, record_pos + integer, parameter :: DFACC_READ = 1 ! from hdf.inc + integer, parameter :: DFNT_UINT8 = 21 + integer, parameter :: FULL_INTERLACE = 0 ! from hdf.inc + + ! local variables + logical :: must_stop, keep_data + + ! variables to define latitude and longitude + integer :: i, j, k, k_off, ll, mm, kk, L + integer :: time_index + + real, parameter :: bin_size = 0.05 + integer, parameter :: XGRID = 3600 + integer, parameter :: YGRID = 7200 + integer, dimension(N_files) :: N_data_tmp + + real :: lat_ind(XGRID) = (/(ll, ll=0, XGRID-1, 1)/) + real :: lon_ind(YGRID) = (/(mm, mm=0, YGRID-1, 1)/) + real, dimension(XGRID) :: lat_c(XGRID) + real, dimension(YGRID) :: lon_c(YGRID) + real,dimension(XGRID*YGRID) :: lat_1D, lon_1D + real :: lon_subtime(9) = (/(kk, kk=180, -180, -45)/) + + integer, dimension(:), allocatable :: Snow_QA, CI_Index, Cloud_Index + character(len=*), parameter :: Iam = 'read_MODISsca_hdf' + character(len=400) :: err_msg + + ! initialize N_data + N_data_tmp(N_files) = XGRID*YGRID + N_data = XGRID*YGRID + + ! Define latitude and longitude + lat_c = (90-bin_size/2)-bin_size*lat_ind + lon_c = (-180+bin_size/2)+bin_size*lon_ind + + ! Create a 1D structure for lat and lon (could change to remove this) + do i=1,7200 + + lat_1D(3600*(i-1)+1:3600*i)= lat_c + lon_1D(3600*(i-1)+1:3600*i)= lon_c(i) + + end do !i + + ! allocate pointers (must be deallocated outside this subroutine) + must_stop = .false. + + if ( associated(lon) .or. associated(lat) .or. associated(MODIS_SCF) ) then + + must_stop = .true. + + end if !(associated(lon) + + + if (must_stop) then + + err_msg = 'output pointers must not be associated/allocated on input.' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + + end if !(must_stop) + + !Allocate SCF and QC vectors + allocate(MODIS_SCF_raw(N_data)) + allocate(CI_Index(N_data)) + allocate(Snow_QA(N_data)) + allocate(Cloud_Index(N_data)) + + ! read hdf data into arrays, concatenate data from N_files files + + k_off = 0 + + do j=1,N_files + + ! open and start "hdf file" + sd_id(j) = sfstart(fnames(j), DFACC_READ) + + if(logit) write (logunit, *), 'sd_id:' , sd_id(j) + + status = sffinfo(sd_id(j), n_datasets, n_file_attrs) + + + do i=1,N_fields + + ind(i) = sfn2index(sd_id(j), trim(field_names(i))) + ! if (logit) write(logunit, *), 'Field_name:', field_names(i) + ! if (logit) write(logunit, *), 'ind:', ind(i) + + sds_id(i) = sfselect(sd_id(j), ind(i)) + status = sfginfo(sds_id(i), var_name, rank, dim_sizes, data_type, n_attrs) + + start(1) = 0 + start(2) = 0 + edges(1) = dim_sizes(1) + edges(2) = dim_sizes(2) + stride(1) = 1 + stride(2) = 1 + + ! read data + select case (i) + + case (1) !Observed SCF (in percent) + allocate(tmp_MODIS_SCF(dim_sizes(1),dim_sizes(2))) + status = sfrdata(sds_id(i), start, stride, edges, tmp_MODIS_SCF) + + L=0 + do k=1, YGRID + + do kk=1, XGRID + L=L+1 + MODIS_SCF_raw(L) = ichar(tmp_MODIS_SCF(k, kk)) + end do !kk + + end do !k, case (1) + + case (2) !Clear Index + allocate(tmp_CI_Index(dim_sizes(1), dim_sizes(2))) + status = sfrdata(sds_id(i), start, stride, edges, tmp_CI_Index) + + L=0 + do k=1, YGRID + + do kk=1, XGRID + L=L+1 + CI_Index(L) = ichar(tmp_CI_index(k,kk)) + end do !kk + + end do !k, case (2) + + case (3) !Cloud Index + allocate(tmp_Cloud_Index(dim_sizes(1), dim_sizes(2))) + status = sfrdata(sds_id(i), start, stride, edges, tmp_Cloud_Index) + + L=0 + do k=1, YGRID + + do kk=1, XGRID + L = L+1 + Cloud_Index(L) = ichar(tmp_Cloud_Index(k, kk)) + end do !kk + + end do !k, case (2) + + case (4) !Snow_QA + allocate(tmp_Snow_QA(dim_sizes(1),dim_sizes(2))) + status = sfrdata(sds_id(i), start, stride, edges, tmp_Snow_QA) + + L=0 + do k=1, YGRID + + do kk=1, XGRID + L = L+1 + Snow_QA(L) = ichar(tmp_Snow_QA(k, kk)) + end do !kk + + end do !k, case (4) + + case default + + call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'Unknown case') + + end select + + if (dim_sizes(1)*dim_sizes(2)/=N_data_tmp(j)) then + + call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'ERROR reading hdf') + + end if + + status = sfendacc(sds_id(i)) + + end do !i + + ! clean up + deallocate(tmp_MODIS_SCF) + deallocate(tmp_CI_index) + deallocate(tmp_Cloud_index) + deallocate(tmp_Snow_QA) + + ! close hdf files + status = sfend(file_id(j)) + + end do !j + + time_index = date_time%hour/3 + 1 + + ! ------------------------------------- + ! eliminate no-data-values and data that fail initial QC + + allocate(MODIS_SCF_tmp(N_data)) + allocate(lat_tmp(N_data)) + allocate(lon_tmp(N_data)) + j=0 + + do i=1,N_data + + keep_data = & + (MODIS_SCF_raw(i)>=0 .and. MODIS_SCF_raw(i)<=100) .and. & ! any neg is nodata + (lon_1D(i)<=lon_subtime(time_index)) .and. & !selection of longitudal band + (lon_1D(i)>lon_subtime(time_index+1)) .and. & + (CI_Index(i)>qc_clear_index_threshold) .and. & + (CI_Index(i)<=qc_clear_index_max_threshold) .and. & + (Cloud_index(i)/=qc_antarctica) .and. & + (Snow_QA(i)0) then + + !if (logit) write (logunit, *) 'calling MODISscf_hdf subroutine' + + call read_MODISscf_hdf(N_files, date_time, N_tmp, fnames, & + tmp_lon, tmp_lat, tmp_obs) + + !if (logit) write (logunit, *) 'read_obs_MODISscf: read MODIS datasets' + + deallocate(fnames) + + else + + N_tmp = 0 + + end if ! (N_files>0) + + if (N_tmp>0) then + + allocate(tmp_tile_num(N_tmp)) + + call get_tile_num_for_obs(N_catd, tile_coord, & + tile_grid_d, N_tile_in_cell_ij, & + tile_num_in_cell_ij, & + N_tmp, tmp_lat, tmp_lon, & + this_obs_param, & + tmp_tile_num(1:N_tmp)) + + + MODIS_obs = 0. + N_obs_in_tile = 0 + + do i=1,N_tmp + + ind = tmp_tile_num(i) ! 1<=tmp_tile_num<=N_catd (unless nodata) + + if (ind>0) then ! this step eliminates obs outside domain + + MODIS_obs(ind) = MODIS_obs(ind) + tmp_obs(i) + N_obs_in_tile(ind) = N_obs_in_tile(ind) + 1 + + end if !(ind>0) + + end do !i + + !normalize + do i=1,N_catd + if (N_obs_in_tile(i)>0) then + + MODIS_obs(i) = MODIS_obs(i)/real(N_obs_in_tile(i)) + + else if (N_obs_in_tile(i) == 0) then + + MODIS_obs(i) = this_obs_param%nodata + + end if !(N_obs_in_tile(i)>0 + end do !i + + if (associated(tmp_tile_num)) deallocate (tmp_tile_num) + + do i=1, N_catd + + std_MODIS_obs(i) = this_obs_param%errstd + + end do !i + + if (any(N_obs_in_tile>0)) then + + found_obs = .true. + + else + + found_obs = .false. + + end if !(any(N_obs_in_tile>0) + + end if ! (associated(tmp_tile_num) + + if (associated(tmp_obs)) deallocate(tmp_obs) + if (associated(tmp_lon)) deallocate(tmp_lon) + if (associated(tmp_lat)) deallocate(tmp_lat) + + end subroutine read_obs_MODISscf + + + ! ***************************************************************** + subroutine read_obs_SMAP_FT( date_time, N_catd, this_obs_param, & dtstep_assim, tile_coord, tile_grid_d, & @@ -7463,17 +7482,7 @@ subroutine read_obs( & ! choose appropriate reader select case (trim(this_obs_param%descr)) - - case ('MODIS_SCA') - ! if(logit) write(logunit,*) 'tile_coord: (read_obs)', tile_coord - ! if(logit) write(logunit,*) 'tile_grid_d: (read_obs)', tile_grid_d - call read_obs_MODISsca( & - work_path, date_time, dtstep_assim, N_catd, tile_coord, & - tile_grid_d, N_tile_in_cell_ij, tile_num_in_cell_ij, & - this_obs_param, found_obs, tmp_obs, tmp_std_obs) - - !scaled_obs = .false. - + case ('ae_l2_sm_a', 'ae_l2_sm_d') call read_obs_ae_l2_sm( & @@ -7700,7 +7709,16 @@ subroutine read_obs( & end if - case('SMAP_L1C_Tbh_A', 'SMAP_L1C_Tbv_A', & + case ('MODIS_SCF') + + call read_obs_MODISscf( & + work_path, date_time, dtstep_assim, N_catd, tile_coord, & + tile_grid_d, N_tile_in_cell_ij, tile_num_in_cell_ij, & + this_obs_param, found_obs, tmp_obs, tmp_std_obs) + + !scaled_obs = .false. + + case('SMAP_L1C_Tbh_A', 'SMAP_L1C_Tbv_A', & 'SMAP_L1C_Tbh_D', 'SMAP_L1C_Tbv_D', & 'SMAP_L1C_Tbh_E09_A', 'SMAP_L1C_Tbv_E09_A', & 'SMAP_L1C_Tbh_E09_D', 'SMAP_L1C_Tbv_E09_D', & diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index 824aa8fd..a70562a1 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -13,7 +13,7 @@ module clsm_ensupd_upd_routines MAPL_TICE, & MAPL_RADIUS, & MAPL_PI, & - MAPL_ALHF !jpark50 + MAPL_ALHF use LDAS_ensdrv_Globals, ONLY: & logit, & @@ -103,13 +103,15 @@ module clsm_ensupd_upd_routines use catch_constants, ONLY: & N_snow => CATCH_N_SNOW, & N_gt => CATCH_N_GT, & + CATCH_DZ1MAX, & PEATCLSM_POROS_THRESHOLD -! N_CONSTIT => CATCH_N_CONSTIT !LCA needed for relayer2 use STIEGLITZSNOW, ONLY: & StieglitzSnow_calc_asnow, & - relayer2, & !LCA needed for snow da - N_constit + relayer2, & + N_constit + !topthick, & + !thickdist use LDAS_ensdrv_mpi, ONLY: & numprocs, & @@ -1346,7 +1348,7 @@ subroutine get_obs_pred( & end if - if (get_asnow_l) then !jpark50 + if (get_asnow_l) then call StieglitzSnow_calc_asnow( N_snow, N_catl, & catprogn2wesn(N_catl,cat_progn(:,n_e)), & asnow_l) @@ -1452,12 +1454,10 @@ subroutine get_obs_pred( & #ifdef LDAS_MPI ! count number of fields that need to be communicated (N_fields), allocate as needed - ! added get_asnow_lH at the function jpark50 call get_obs_pred_comm_helper( N_catl, N_ens, N_TbuniqFreqAngRTMid, & get_sfmc_lH, get_rzmc_lH, get_tsurf_lH, get_FT_lH, get_asnow_lH, get_Tb_lH, N_fields) ! allocate and assemble tile_data_l - ! added get_asnow_lH at the function jpark50 if (allocated(tile_data_l)) deallocate(tile_data_l) allocate(tile_data_l(N_catl,N_fields,N_ens)) @@ -1473,7 +1473,6 @@ subroutine get_obs_pred( & N_catlH, tile_data_lH=tile_data_lH ) ! read out sfmc, rzmc, etc. from tile_data_lH - ! addded asnow option at here call get_obs_pred_comm_helper( N_catlH, N_ens, N_TbuniqFreqAngRTMid, & get_sfmc_lH, get_rzmc_lH, get_tsurf_lH, get_FT_lH, get_asnow_lH, get_Tb_lH, N_fields, & option=2, tile_data=tile_data_lH, & @@ -1490,7 +1489,7 @@ subroutine get_obs_pred( & if (get_rzmc_lH) rzmc_lH = rzmc_l if (get_tsurf_lH) tsurf_lH = tsurf_l if (get_FT_lH) FT_lH = FT_l - if (get_asnow_lH) asnow_lH = asnow_l !jpark50 + if (get_asnow_lH) asnow_lH = asnow_l if (get_Tb_lH) stemp_lH = stemp_l if (get_Tb_lH) Tb_h_lH = Tb_h_l if (get_Tb_lH) Tb_v_lH = Tb_v_l @@ -1857,7 +1856,7 @@ subroutine get_obs_pred( & if (get_rzmc_lH) deallocate(rzmc_lH) if (get_tsurf_lH) deallocate(tsurf_lH) if (get_FT_lH) deallocate(FT_lH) - if (get_asnow_lH) deallocate(asnow_lH) !jpark50 + if (get_asnow_lH) deallocate(asnow_lH) if (get_Tb_lH) deallocate(stemp_lH) if (get_Tb_lH) deallocate(Tb_h_lH) if (get_Tb_lH) deallocate(Tb_v_lH) @@ -1979,8 +1978,7 @@ subroutine get_obs_pred_comm_helper( & integer, intent(in) :: N_cat, N_ens, N_Tb - logical, intent(in) :: get_sfmc, get_rzmc, get_tsurf, get_FT, get_Tb - logical, intent(in) :: get_asnow !jpark50 + logical, intent(in) :: get_sfmc, get_rzmc, get_tsurf, get_FT, get_Tb, get_asnow integer, intent(inout) :: N_fields @@ -1989,7 +1987,7 @@ subroutine get_obs_pred_comm_helper( & real, dimension(N_cat,N_fields,N_ens), intent(inout), optional :: tile_data real, dimension(N_cat, N_ens), intent(inout), optional :: sfmc, rzmc - real, dimension(N_cat, N_ens), intent(inout), optional :: tsurf, FT, asnow, stemp !jpark50 + real, dimension(N_cat, N_ens), intent(inout), optional :: tsurf, FT, asnow, stemp real, dimension(N_cat,N_Tb, N_ens), intent(inout), optional :: Tb_h, Tb_v ! ----------------------------------- @@ -2020,7 +2018,7 @@ subroutine get_obs_pred_comm_helper( & if ( ((get_sfmc ) .and. (.not. present(sfmc ))) .or. & ((get_rzmc ) .and. (.not. present(rzmc ))) .or. & ((get_tsurf) .and. (.not. present(tsurf))) .or. & - ((get_asnow) .and. (.not. present(asnow))) .or. & !jpark50 + ((get_asnow) .and. (.not. present(asnow))) .or. & ((get_FT) .and. (.not. present(FT ))) .or. & ((get_Tb) .and. (.not. present(stemp))) .or. & ((get_Tb) .and. (.not. present(Tb_h ))) .or. & @@ -2080,7 +2078,7 @@ subroutine get_obs_pred_comm_helper( & end if - if (get_asnow) then !jpark50 + if (get_asnow) then k = k+1 @@ -3519,16 +3517,13 @@ subroutine cat_enkf_increments( & ! ------------------------------------------------------------------- ! Need to clean up and pull these two hardwired numbers from GCM GridComp or MAPL, reichle 20221007 (TO DO) real, dimension(N_snow), parameter :: DZMAX = (/0.08, 0.5, 0.5/) ! target thickness for relayer2() ! needs to be pulled from Catch GC; would fail with N_snow /= 3; - real, parameter :: cpw = 2065.22 ! ice specific heat capacity @ 0C [J/kg/K] ! already defined in StieglitzSnow.F90; needs to be added to MAPL (or at least pulled from StieglitzSnow.F90 ) + ! ------------------------------------------------------------------- - ! design parameters for 1d snow cover analysis (Toure et al. 2018) - - ! TO DO: RENAME SO THE USE OF THESE VARIABLES IN SCA ANALYSIS IS MORE OBVIOUS, reichle 20221007 - - real, parameter:: alpha_threshold = 0.40 ! dimensionless DEPENDS ON WEMIN (and might be wrong in Toure et al!!!!) - NEEDS VERIFICATION & CLEANUP - real, parameter:: beta_threshold = 0.40 ! dimensionless - real, parameter:: max_incr_swe = 5.0 ! kg m-2 + ! design parameters for 1d snow cover analysis modified from Toure et al. 2018 + real, parameter:: modis_scf_alpha_threshold = 0.60 ! dimensionless, Obs_scf * scf_alpha_threshold below which snow is added + real, parameter:: modis_scf_beta_threshold = 0.55 ! dimensionless, Obs threshold below which to remove snow + real, parameter:: modis_max_incr_swe = 5.0 ! kg m-2 real, parameter:: smallfcstswe = 0.01 ! kg m-2 threshold for "no snow" below which the ratio of swe_ana/swe_fcst tends to be unreasonable ! ----------------------------------------------------------------------- @@ -4469,7 +4464,7 @@ subroutine cat_enkf_increments( & ! make sure maximum SWE increment is less than WEMIN (adding more snow than WEMIN makes no sense) - if (max_incr_swe>WEMIN) call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'must use max_incr_swe<=WEMIN') + if (modis_max_incr_swe>WEMIN) call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'must use max_incr_swe<=WEMIN') !identify the species ID number of interest N_select_varnames = 1 @@ -4510,18 +4505,18 @@ subroutine cat_enkf_increments( & ! 2. Calculate SWE increment based on Toure et al (2018) eq 1 - if (asnow_fcst .lt. Observations(ind_obs(1))%obs * alpha_threshold) then + if (asnow_fcst .lt. Observations(ind_obs(1))%obs * modis_scf_alpha_threshold) then ! ADD SNOW: SCA of model is less than observed SCA swe_incr(kk,n_e) & - = max_incr_swe * (Observations(ind_obs(1))%obs - asnow_fcst/alpha_threshold) + = modis_max_incr_swe * (Observations(ind_obs(1))%obs - asnow_fcst/modis_scf_alpha_threshold) - elseif (Observations(ind_obs(1))%obs .lt. beta_threshold) then + elseif (Observations(ind_obs(1))%obs .lt. modis_scf_beta_threshold) then ! REMOVE SNOW: IF SCA of model is greater than observed SCA - swe_incr(kk,n_e) = (-1.) * max_incr_swe * asnow_fcst * (1. - Observations(ind_obs(1))%obs/beta_threshold) + swe_incr(kk,n_e) = (-1.) * modis_max_incr_swe * asnow_fcst * (1. - Observations(ind_obs(1))%obs/modis_scf_beta_threshold) else @@ -4540,9 +4535,7 @@ subroutine cat_enkf_increments( & swe_ratio = swe_ana / swe_fcst else swe_ratio = 1. ! set to neutral just in case, but should not be used if swe_fcst 0 ; asnow_ana < 1.0' + else @@ -4587,7 +4579,7 @@ subroutine cat_enkf_increments( & tmp_sndz(kk, n_e, isnow) = tmp_wesn(kk, n_e, isnow) / (cat_progn(kk, n_e)%wesn(isnow) / cat_progn(kk, n_e)%sndz(isnow)) - if (logit) write (logunit, *) '%%%%%% asnow_fcst > 0 ; asnow_ana = 1.0' + end if end if @@ -4596,7 +4588,7 @@ subroutine cat_enkf_increments( & ! 4. Relayer to balance the snow column call relayer2( N_snow, N_constit , & - DZMAX(1), DZMAX(2:N_snow), & + CATCH_DZ1MAX, DZMAX(2:N_snow), & tmp_htsn(kk, n_e, 1:N_snow), & tmp_wesn(kk, n_e, 1:N_snow), & tmp_sndz(kk, n_e, 1:N_snow), & From 1974d0cec1134e626f4c4560042b71457e2cbbd1 Mon Sep 17 00:00:00 2001 From: Biljana Orescanin <68251545+biljanaorescanin@users.noreply.github.com> Date: Wed, 12 Jul 2023 15:25:58 -0400 Subject: [PATCH 097/308] Update components.yaml Revert components yaml prior to merge --- components.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components.yaml b/components.yaml index 845ccce4..5ca4fecb 100644 --- a/components.yaml +++ b/components.yaml @@ -41,6 +41,6 @@ MAPL: GEOSgcm_GridComp: local: ./src/Components/GEOSldas_GridComp/@GEOSgcm_GridComp remote: ../GEOSgcm_GridComp.git - branch: feature/rreichle/catch_spinup_mode + branch: develop sparse: ./config/GEOSgcm_GridComp_ldas.sparse develop: develop From 437320093d68763644a4672525684fa736091ce4 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Wed, 12 Jul 2023 15:51:10 -0600 Subject: [PATCH 098/308] the intention --- src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml b/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml index cd3dbeca..210f321e 100644 --- a/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml +++ b/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml @@ -32,6 +32,7 @@ ! update_type = 8: 3d soil moisture/Tskin/ght(1); TB obs ! update_type = 9: 1d Tskin/ght1 update; FT obs ! update_type = 10: 3d soil moisture/Tskin/ght(1) excl. catdef unless PEATCLSM tile; TB obs +! update_type = 11: Multivariate combination of 2 and 10; sfmc and TB obs update_type = 0 From 3a2619ce3db40ca175fd2238b6d1416ec8e7056f Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Fri, 14 Jul 2023 16:18:12 -0400 Subject: [PATCH 099/308] make longnames for albedo consistent with recent HISTORY updates for R21C (tile_bin2nc4.F90) --- src/Applications/LDAS_App/tile_bin2nc4.F90 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Applications/LDAS_App/tile_bin2nc4.F90 b/src/Applications/LDAS_App/tile_bin2nc4.F90 index 3a56e61f..6a06e5d7 100644 --- a/src/Applications/LDAS_App/tile_bin2nc4.F90 +++ b/src/Applications/LDAS_App/tile_bin2nc4.F90 @@ -281,10 +281,10 @@ FUNCTION getAttribute (SHORT_NAME, LNAME, UNT) result (str_atr) case ('SNDZN1'); LONG_NAME = 'snow_depth_layer_1'; UNITS = 'm' case ('SNDZN2'); LONG_NAME = 'snow_depth_layer_2'; UNITS = 'm' case ('SNDZN3'); LONG_NAME = 'snow_depth_layer_3'; UNITS = 'm' - case ('ALBVR'); LONG_NAME = 'surface_albedo_visible_beam'; UNITS = '1' - case ('ALBVF'); LONG_NAME = 'surface_albedo_visible_diffuse'; UNITS = '1' - case ('ALBNR'); LONG_NAME = 'surface_albedo_near_infared_beam'; UNITS = '1' - case ('ALBNF'); LONG_NAME = 'surface_albedo_near_infrared_diffuse'; UNITS = '1' + case ('ALBVR'); LONG_NAME = 'surface_reflectivity_for_visible_beam'; UNITS = '1' + case ('ALBVF'); LONG_NAME = 'surface_reflectivity_for_visible_diffuse'; UNITS = '1' + case ('ALBNR'); LONG_NAME = 'surface_reflectivity_for_near_infared_beam'; UNITS = '1' + case ('ALBNF'); LONG_NAME = 'surface_reflectivity_for_near_infrared_diffuse'; UNITS = '1' case ('HLWUP'); LONG_NAME = 'surface_outgoing_longwave_flux'; UNITS = 'W m-2' case ('GWETPROF'); LONG_NAME = 'ave_prof_soil_wetness'; UNITS = '1' case ('GWETROOT'); LONG_NAME = 'root_zone_soil_wetness'; UNITS = '1' From 73b37a538da94563cd30dcf2350f9a0d1676a1d9 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Fri, 14 Jul 2023 17:21:28 -0400 Subject: [PATCH 100/308] cleaned up ensupd nml specs for MODIS Terra SCF obs --- .../LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml | 51 ++++++++----------- .../clsm_ensupd_read_obs.F90 | 24 +++++++-- 2 files changed, 42 insertions(+), 33 deletions(-) diff --git a/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml b/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml index dcc2f6b1..1498b7c3 100644 --- a/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml +++ b/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml @@ -90,7 +90,7 @@ fcsterr_inflation_fac = -9999. ! 1 = horizontal ! 2 = vertical ! 3 = ... -! %N_ang = # angles in species +! %N_ang = # angles in species (for radiance data) ! %ang = vector of angles ! %freq = frequency [Hz] ! %FOV = field-of-view *radius*, see NOTES below @@ -234,8 +234,7 @@ fcsterr_inflation_fac = -9999. obs_param_nml( 1)%descr = 'ae_l2_sm_a' obs_param_nml( 1)%orbit = 1 obs_param_nml( 1)%pol = 0 -obs_param_nml( 1)%N_ang = 1 -obs_param_nml( 1)%ang(1) = 55. +obs_param_nml( 1)%N_ang = 0 obs_param_nml( 1)%freq = 10.65e9 obs_param_nml( 1)%FOV = 20. obs_param_nml( 1)%FOV_units = 'km' @@ -270,8 +269,7 @@ obs_param_nml( 1)%adapt = 0 obs_param_nml( 2)%descr = 'ae_l2_sm_d' obs_param_nml( 2)%orbit = 2 obs_param_nml( 2)%pol = 0 -obs_param_nml( 2)%N_ang = 1 -obs_param_nml( 2)%ang(1) = 55. +obs_param_nml( 2)%N_ang = 0 obs_param_nml( 2)%freq = 10.65e9 obs_param_nml( 2)%FOV = 20. obs_param_nml( 2)%FOV_units = 'km' @@ -516,8 +514,7 @@ obs_param_nml( 8)%adapt = 0 obs_param_nml( 9)%descr = 'ae_sm_LPRM_a_C' obs_param_nml( 9)%orbit = 1 obs_param_nml( 9)%pol = 0 -obs_param_nml( 9)%N_ang = 1 -obs_param_nml( 9)%ang(1) = 55. +obs_param_nml( 9)%N_ang = 0 obs_param_nml( 9)%freq = 6.925e9 obs_param_nml( 9)%FOV = 20. obs_param_nml( 9)%FOV_units = 'km' @@ -552,8 +549,7 @@ obs_param_nml( 9)%adapt = 0 obs_param_nml(10)%descr = 'ae_sm_LPRM_d_C' obs_param_nml(10)%orbit = 2 obs_param_nml(10)%pol = 0 -obs_param_nml(10)%N_ang = 1 -obs_param_nml(10)%ang(1) = 55. +obs_param_nml(10)%N_ang = 0 obs_param_nml(10)%freq = 6.925e9 obs_param_nml(10)%FOV = 20. obs_param_nml(10)%FOV_units = 'km' @@ -588,8 +584,7 @@ obs_param_nml(10)%adapt = 0 obs_param_nml(11)%descr = 'ae_sm_LPRM_a_X' obs_param_nml(11)%orbit = 1 obs_param_nml(11)%pol = 0 -obs_param_nml(11)%N_ang = 1 -obs_param_nml(11)%ang(1) = 55. +obs_param_nml(11)%N_ang = 0 obs_param_nml(11)%freq = 10.65e9 obs_param_nml(11)%FOV = 20. obs_param_nml(11)%FOV_units = 'km' @@ -624,8 +619,7 @@ obs_param_nml(11)%adapt = 0 obs_param_nml(12)%descr = 'ae_sm_LPRM_d_X' obs_param_nml(12)%orbit = 2 obs_param_nml(12)%pol = 0 -obs_param_nml(12)%N_ang = 1 -obs_param_nml(12)%ang(1) = 55. +obs_param_nml(12)%N_ang = 0 obs_param_nml(12)%freq = 10.65e9 obs_param_nml(12)%FOV = 20. obs_param_nml(12)%FOV_units = 'km' @@ -1157,17 +1151,18 @@ obs_param_nml(24)%adapt = 0 ! -------------------------------------------------------------------- ! -! 25 = MODIS SCF +! 25 = MODIS Terra snow cover area fraction (SCF) ! -! platform: SCF assimilation is currently set up to use MOD10C1.061 (MODIS/Terra 0.05deg CMG, V61) -! specs: The assimilation occurs at +/-3h passover time (10:30am local). The assimilation only contains a single member. - -obs_param_nml(25)%descr = 'MODIS_SCF' -obs_param_nml(25)%orbit = 0 +! MOD10C1.*.061: MODIS Terra SCF, 0.05deg CMG, daytime (10:30am local) descending overpass, version V61 +! +! for rule-based snow cover analysis (no obs error/pert specs) + +obs_param_nml(25)%descr = 'MOD10C1' +obs_param_nml(25)%orbit = 2 obs_param_nml(25)%pol = 0 obs_param_nml(25)%N_ang = 0 obs_param_nml(25)%freq = 0. -obs_param_nml(25)%FOV = 0. +obs_param_nml(25)%FOV = 0.025 obs_param_nml(25)%FOV_units = 'deg' obs_param_nml(25)%assim = .false. obs_param_nml(25)%scale = .false. @@ -1179,15 +1174,15 @@ obs_param_nml(25)%bias_tcut = 432000 obs_param_nml(25)%nodata = -9999. obs_param_nml(25)%varname = 'asnow' obs_param_nml(25)%units = 'm2/m2' -obs_param_nml(25)%path = '/discover/nobackup/projects/S2SHMA/MODIS/MOD10C1_C61/' -obs_param_nml(25)%name = '' +obs_param_nml(25)%path = '/discover/nobackup/projects/S2SHMA/MODIS/MOD10C1_V61/' +obs_param_nml(25)%name = 'MOD10C1.Ayyyyddd.061.hdf' obs_param_nml(25)%scalepath = '' obs_param_nml(25)%scalename = '' obs_param_nml(25)%flistpath = '' obs_param_nml(25)%flistname = '' -obs_param_nml(25)%errstd = 0.0004 -obs_param_nml(25)%std_normal_max = 2.5 -obs_param_nml(25)%zeromean = .true. +obs_param_nml(25)%errstd = -9999. +obs_param_nml(25)%std_normal_max = -9999. +obs_param_nml(25)%zeromean = .false. obs_param_nml(25)%coarsen_pert = .false. obs_param_nml(25)%xcorr = 0. obs_param_nml(25)%ycorr = 0. @@ -1689,8 +1684,7 @@ obs_param_nml(38)%adapt = 0 obs_param_nml(39)%descr = 'SMAP_L2AP_FT_A' obs_param_nml(39)%orbit = 1 obs_param_nml(39)%pol = 0 -obs_param_nml(39)%N_ang = 1 -obs_param_nml(39)%ang(1) = 40. +obs_param_nml(39)%N_ang = 0 obs_param_nml(39)%freq = 1.26e9 obs_param_nml(39)%FOV = 5. obs_param_nml(39)%FOV_units = 'km' @@ -1725,8 +1719,7 @@ obs_param_nml(39)%adapt = 0 obs_param_nml(40)%descr = 'SMAP_L2AP_FT_D' obs_param_nml(40)%orbit = 2 obs_param_nml(40)%pol = 0 -obs_param_nml(40)%N_ang = 1 -obs_param_nml(40)%ang(1) = 40. +obs_param_nml(40)%N_ang = 0 obs_param_nml(40)%freq = 1.26e9 obs_param_nml(40)%FOV = 5. obs_param_nml(40)%FOV_units = 'km' diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 3713eb20..1e2dfd4e 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -4983,11 +4983,27 @@ subroutine read_obs_MODISscf( & write (logunit, *) 'Obs time: ', YYYY, MM write (logunit, *) 'DOY: ', DDD - - tmpfname1 = trim(this_obs_param%path) // YYYY // '/MOD10C1.A' // YYYY // DDD // & - '.061.hdf' !note the MODIS data version included here - if (logit) write (logunit, *) 'Reading data from', trim(tmpfname1) + ! In the ensupd nml file, specify the file "name" according to the following template: + ! + ! %name = 'MOD10C1.Ayyyyddd.061.hdf' + ! + ! 1 2 + ! 123456789012345678901234 + ! + ! MOD10C1 = MODIS product name + ! .A = "acquisition time" indicator + ! yyyyddd = placeholder for year/day-of-year + ! .061 = version (Collection) indicator + ! .hdf = file name extension + ! + ! Assuming the MODIS file naming convention remains unchanged, the version can then + ! be specified in the nml file. + + tmpfname1 = trim(this_obs_param%path) // '/' // YYYY // '/' & + // this_obs_param%name(1:9) // YYYY // DDD // this_obs_param%name(17:24) + + if (logit) write (logunit, *) 'Reading data from', trim(tmpfname1) inquire(file=trim(tmpfname1), exist=file_exists) if (logit) write (logunit, *), file_exists From 098ece10ee9276d61cbf816c23b2e771d1f9909a Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Fri, 14 Jul 2023 17:24:17 -0400 Subject: [PATCH 101/308] undoing white-space changes in GEOS_LandAssimGridComp.F90 by reverting back to "develop" version --- .../GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 index 80f6ab4a..f13c1bfc 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 @@ -877,7 +877,7 @@ subroutine SetServices ( GC, RC ) ! ! INTERNAL STATE ! - + call MAPL_AddInternalSpec(GC ,& LONG_NAME = 'L-band Microwave RTM: Vegetation class. Type is Unsigned32' ,& UNITS = '1' ,& @@ -1926,7 +1926,7 @@ subroutine RUN ( GC, IMPORT, EXPORT, CLOCK, RC ) if (fresh_incr) then ! apply EnKF increments (incl. call to catch_calc_soil_moist but not to recompute_diagS()) call apply_enkf_increments( N_catl, NUM_ENSEMBLE, update_type, cat_param, & - cat_progn_incr, cat_progn) + cat_progn_incr, cat_progn ) end if ! fresh_incr @@ -2503,14 +2503,13 @@ subroutine OUTPUT_SMAPL4SMLMC(gc, import, export, clock, rc) _VERIFY(status) call esmf2ldas(ModelTimeCur, start_time, rc=status) _VERIFY(status) - + call get_mwrtm_param(MAPL, clock, N_catl, INTERNAL, rc=status) _VERIFY(status) call GEOS_output_smapL4SMlmc( GC, start_time, trim(out_path), trim(exp_id), & N_catl, tile_coord_l, cat_param, mwRTM_param ) - first_time = .false. - + first_time = .false. _RETURN(_SUCCESS) From 3a823ec00464a21107cb3b0d67b623eecd825eb8 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Fri, 14 Jul 2023 17:26:08 -0400 Subject: [PATCH 102/308] undoing superfluous white-space changes in clsm_bias_routines.F90 by reverting back to "develop" version --- .../GEOSlandassim_GridComp/clsm_bias_routines.F90 | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_bias_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_bias_routines.F90 index 3aecdc0e..bee99863 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_bias_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_bias_routines.F90 @@ -1489,6 +1489,7 @@ subroutine obs_bias_upd_bias_and_Obs( & ! --------------------------------------------------------------------- ! get species-dependent time of day index + do i=1,N_obs_param indv_time(i) = bias_time_of_day_index( date_time, obs_param(i)%bias_Npar ) From ae7d88be851389e5567898e8a9f29ba26ca746db Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Fri, 14 Jul 2023 17:47:24 -0400 Subject: [PATCH 103/308] minor clean-up for MODIS SCF DA, incl white-space changes to minimize diffs with develop (clsm_ensupd_enkf_update.F90) --- .../clsm_ensupd_enkf_update.F90 | 81 +++++++++---------- 1 file changed, 40 insertions(+), 41 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 index c3062c68..135ffbf0 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 @@ -158,7 +158,7 @@ subroutine get_enkf_increments( & cat_progn_incr, fresh_incr, & N_obsf, N_obsl, Observations_l, & N_adapt_R, obs_pert_adapt_param, Pert_adapt_R, & - Obs_pert) + Obs_pert ) ! ------------------------------------------------------------- @@ -310,7 +310,7 @@ subroutine get_enkf_increments( & type(cat_progn_type), allocatable :: cat_progn_incr_f(:), cat_progn_incr_ana(:,:) type(cat_progn_type), allocatable :: recvBuf(:) -! Obs related + ! obs related integer :: nObs_ana integer :: nObsAna_vec(numprocs) integer :: N_obsf_assim, N_obsl_assim @@ -319,7 +319,7 @@ subroutine get_enkf_increments( & integer, dimension(:), allocatable, target :: ind_obsl_assim integer, dimension(:), pointer :: ptr2indx => null() type(varLenIntArr) :: indObsAna_vec(numprocs) - integer, dimension(:), allocatable :: tmp_ind_obs + integer, dimension(:), allocatable :: tmp_ind_obs type(obs_type), dimension(:), allocatable :: Obs_f_assim, Obs_ana ! collect obs before distributing for ana real, allocatable :: Obs_pred_f_assim(:), Obs_pred_ana(:,:) @@ -331,8 +331,8 @@ subroutine get_enkf_increments( & character(12) :: tmpstr12 - character(len=*), parameter :: Iam = 'get_enkf_increments' - character(len=400) :: err_msg + character(len=*), parameter :: Iam = 'get_enkf_increments' + character(len=400) :: err_msg ! ********************************************************************** ! @@ -438,7 +438,7 @@ subroutine get_enkf_increments( & ! -------------------------------------------------------------------- - if (logit) write(logunit,*) 'found_obs_f', found_obs_f + if (found_obs_f) then ! ++++++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -475,7 +475,7 @@ subroutine get_enkf_increments( & ! B1. Adjust observations to remove the obs bias ! and set obsbias_ok flag - if(logit) write(logunit,*) 'entering obs_bias_corr_obs' + call obs_bias_corr_obs(date_time, N_catl, N_catf, & N_obsl , N_obs_param, N_obsbias_max, f2l, obs_param, & obs_bias, Observations_l, obsbias_ok) @@ -520,6 +520,7 @@ subroutine get_enkf_increments( & fcsterr_inflation_fac ) if (allocated(obsbias_ok)) deallocate(obsbias_ok) + !if(logit) write(logunit,*) 'N_obs_l after obs_pred', N_obsl !if(logit) write(logunit,*) 'Observations_l length', size(Observations_l) !if(logit) write(logunit,*) 'Observations_l',Observations_l%ana @@ -534,7 +535,6 @@ subroutine get_enkf_increments( & ! count observations across all processors that are left after ! model-based QC (done within get_obs_pred()) - #ifdef LDAS_MPI @@ -545,6 +545,7 @@ subroutine get_enkf_increments( & #else N_obsf = N_obsl #endif + ! check whether any "assim" flag is set in obs_param ! CSD - if want to skip cat_enkf_incr and apply_incr blocks @@ -565,6 +566,7 @@ subroutine get_enkf_increments( & ! Obs bias ! ! B2. Update obs_bias and Observations with the obs bias increment + if ( (N_obsl>0) .and. (N_obsbias_max>0) ) & call obs_bias_upd_bias_and_Obs(date_time, N_catl, N_catf, & N_obsl, N_ens, N_obs_param, N_obsbias_max, f2l, obs_param, & @@ -651,8 +653,7 @@ subroutine get_enkf_increments( & !-AnaLoadBal-Prereq-starts-here- ! Step 1a: identify obs w/ obs%assim==.true. - allocate(ind_obsl_assim(N_obsl), source=-99) - + allocate(ind_obsl_assim(N_obsl), source=-99) call get_ind_obs_assim(N_obsl, Observations_l%assim, N_obsl_assim, ind_obsl_assim) ! its easier to write ptr2indx than ind_obsl_assim(1:N_obsl_assim) ptr2indx => ind_obsl_assim(1:N_obsl_assim) @@ -680,7 +681,7 @@ subroutine get_enkf_increments( & Obs_f_assim, N_obsl_assim_vec, tmp_low_ind-1, MPI_obs_type, & mpicomm, mpierr) !-AnaLoadBal-Prereq-ends-here- - !if(logit) write(logunit,*) 'Obs_f_assim', Obs_f_assim + !-AnaLodaBal-Decomposition-starts-here ! Step 2a: compute nTiles_l, indTiles_l, nTilesl_vec (on root), nTiles_f (on root) ! NOTE: loop over tile_coord_l, if tile has nnz obs, store the 'full' index @@ -782,7 +783,6 @@ subroutine get_enkf_increments( & allocate(indObs_ana(N_obsf_assim), source=-99) allocate(tmp_ind_obs(N_obsf_assim), source=-99) nObs_ana = 0 - do ctr=1,nTiles_ana iTile = indTiles_ana(ctr) ! 'full' index halo = get_halo_around_tile(tile_coord_f(iTile), xcompact, ycompact) @@ -1028,7 +1028,6 @@ subroutine get_enkf_increments( & tile_coord_l, xcompact, ycompact, & N_obslH, Observations_lH, Obs_pred_lH ) - #endif ! get observations perturbations for all ensemble members @@ -1079,20 +1078,22 @@ subroutine get_enkf_increments( & #ifdef LDAS_MPI allocate(cat_progn_incr_ana(nTiles_ana,N_ens)) + !if(logit) write(logunit,*) 'Entering cat_enkf_increments' - !if(logit) write(logunit,*) 'length of Obs_ana', size(Obs_ana) - !if(logit) write(logunit,*) 'length of Obs_pred_ana', size(Obs_pred_ana) - !if(logit) write(logunit,*) 'length of Obs_pert_tmp', size(Obs_pert_tmp) - !if(logit) write(logunit,*) 'length of tile_coord_ana', size(tile_coord_ana) - !if(logit) write(logunit,*) 'Obs_ana', Obs_ana - !if(logit) write(logunit,*) 'Obs_ana%species', Obs_ana%species - !if(logit) write(logunit,*) 'Obs_ana%tilenum', Obs_ana%tilenum - !if(logit) write(logunit,*) 'Obs_ana%lat', Obs_ana%lat - !if(logit) write(logunit,*) 'Obs_ana%lon', Obs_ana%lon - !if(logit) write(logunit,*) 'Obs_ana%obs', Obs_ana%obs - !if(logit) write(logunit,*) 'Obs_pred_ana', Obs_pred_ana - !if(logit) write(logunit,*) 'Obs_pert_tmp', Obs_pert_tmp - !if(logit) write(logunit,*) 'tile_corrd_ana', tile_coord_ana + !if(logit) write(logunit,*) 'length of Obs_ana: ', size(Obs_ana) + !if(logit) write(logunit,*) 'length of Obs_pred_ana: ', size(Obs_pred_ana) + !if(logit) write(logunit,*) 'length of Obs_pert_tmp: ', size(Obs_pert_tmp) + !if(logit) write(logunit,*) 'length of tile_coord_ana: ', size(tile_coord_ana) + !if(logit) write(logunit,*) 'Obs_ana: ', Obs_ana + !if(logit) write(logunit,*) 'Obs_ana%species: ', Obs_ana%species + !if(logit) write(logunit,*) 'Obs_ana%tilenum: ', Obs_ana%tilenum + !if(logit) write(logunit,*) 'Obs_ana%lat: ', Obs_ana%lat + !if(logit) write(logunit,*) 'Obs_ana%lon: ', Obs_ana%lon + !if(logit) write(logunit,*) 'Obs_ana%obs: ', Obs_ana%obs + !if(logit) write(logunit,*) 'Obs_pred_ana: ', Obs_pred_ana + !if(logit) write(logunit,*) 'Obs_pert_tmp: ', Obs_pert_tmp + !if(logit) write(logunit,*) 'tile_corrd_ana: ', tile_coord_ana + call cpu_time(t_start) call cat_enkf_increments( & N_ens, nObs_ana, nTiles_ana, N_obs_param, & @@ -1301,7 +1302,7 @@ end subroutine addUniqueInts ! ******************************************************************** subroutine apply_enkf_increments( N_catd, N_ens, update_type, & - cat_param, cat_progn_incr, cat_progn) + cat_param, cat_progn_incr, cat_progn ) implicit none @@ -1317,10 +1318,10 @@ subroutine apply_enkf_increments( N_catd, N_ens, update_type, & type(cat_progn_type), dimension(N_catd,N_ens), intent(in) :: cat_progn_incr type(cat_progn_type), dimension(N_catd,N_ens), intent(inout) :: cat_progn - + ! ----------------- - integer :: n, n_e, i + integer :: n, n_e, ii logical :: cat_progn_has_changed @@ -1330,7 +1331,7 @@ subroutine apply_enkf_increments( N_catd, N_ens, update_type, & ! ---------------------------------------------------------------- ! ! apply increments - if(logit) write(logunit,*) "apply increment" + cat_progn_has_changed = .true. ! conservative initialization select_update_type: select case (update_type) @@ -1423,30 +1424,28 @@ subroutine apply_enkf_increments( N_catd, N_ens, update_type, & cat_progn_has_changed = .true. - case(11) select_update_type ! MODIS SCF update + case(11) select_update_type ! empirical MODIS SCF update - !Rule-based snow SCF update do n=1,N_catd ! for each tile do n_e=1,N_ens ! for each ensemble member - do i=1,N_SNOW ! for each snow layer + do ii=1,N_SNOW ! for each snow layer - cat_progn(n,n_e)%wesn(i) = & - cat_progn(n,n_e)%wesn(i) + cat_progn_incr(n,n_e)%wesn(i) + cat_progn(n,n_e)%wesn(ii) = & + cat_progn(n,n_e)%wesn(ii) + cat_progn_incr(n,n_e)%wesn(ii) - cat_progn(n,n_e)%sndz(i) = & - cat_progn(n,n_e)%sndz(i) + cat_progn_incr(n,n_e)%sndz(i) + cat_progn(n,n_e)%sndz(ii) = & + cat_progn(n,n_e)%sndz(ii) + cat_progn_incr(n,n_e)%sndz(ii) - cat_progn(n,n_e)%htsn(i) = & - cat_progn(n,n_e)%htsn(i)+ cat_progn_incr(n,n_e)%htsn(i) + cat_progn(n,n_e)%htsn(ii) = & + cat_progn(n,n_e)%htsn(ii) + cat_progn_incr(n,n_e)%htsn(ii) end do end do end do - cat_progn_has_changed = .true. - + cat_progn_has_changed = .true. case default From f3cd1c38a7161c2f47646545fca8f8d9e1eb6a2e Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Fri, 14 Jul 2023 18:34:45 -0400 Subject: [PATCH 104/308] minor cleanup of MODIS SCF DA: removed obsolete log statements and comments, white-space changes to minimize diffs with "develop" branch (clsm_ensupd_enkf_update.F90, clsm_ensupd_read_obs.F90, clsm_ensupd_upd_routines.F90) --- .../clsm_ensupd_enkf_update.F90 | 5 -- .../clsm_ensupd_read_obs.F90 | 61 +++++-------------- .../clsm_ensupd_upd_routines.F90 | 59 +++++++++--------- 3 files changed, 46 insertions(+), 79 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 index 135ffbf0..41adac85 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 @@ -521,11 +521,6 @@ subroutine get_enkf_increments( & if (allocated(obsbias_ok)) deallocate(obsbias_ok) - !if(logit) write(logunit,*) 'N_obs_l after obs_pred', N_obsl - !if(logit) write(logunit,*) 'Observations_l length', size(Observations_l) - !if(logit) write(logunit,*) 'Observations_l',Observations_l%ana - !if(logit) write(logunit,*) 'Obs_pred_l', Obs_pred_l - ! IF NEEDED, INCLUDE WITHHOLDING SUBROUTINE HERE. ! SUCH A SUBROUTINE SHOULD CHANGE Observations(i)%assim TO FALSE ! IF THE OBSERVATION IS TO BE WITHHELD diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 1e2dfd4e..f1263c22 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -2,12 +2,11 @@ ! this file contains subroutines for reading and processing observations ! for the GEOS5 land EnKF update algorithm ! -! reichle, 27 Jan 2005 -! reichle, 10 Jan 2011 - replaced "UVA" with "LPRM" -! reichle, 1 Jul 2015 - clarified definition of obs time stamp +! reichle, 27 Jan 2005 +! reichle, 10 Jan 2011 - replaced "UVA" with "LPRM" +! reichle, 1 Jul 2015 - clarified definition of obs time stamp ! (J2000 seconds w/ 'TT12' epoch) - -!lcandre2, 10 Jul 2021 - confirmed and cleaned up MODIS obs +! lcandre2, 10 Jul 2021 - confirmed and cleaned up MODIS obs ! added work_path to inputs of many subroutines so that "tmpfname" ! (needed several times for reading AMSR-E hdf files) is distinct for each job @@ -87,9 +86,10 @@ module clsm_ensupd_read_obs contains ! ***************************************************************** + subroutine read_ae_l2_sm_hdf( & N_files, fnames, N_data, lon, lat, ae_l2_sm, ease_col, ease_row ) - + ! read soil moisture data from one or more AMSR-E Land hdf files ! ! return ONLY valid data points (ie. excluding no-data-values) @@ -195,6 +195,7 @@ subroutine read_ae_l2_sm_hdf( & do j=1,N_files ! open and "start" hdf file + file_id(j) = hopen( fnames(j), DFACC_READ, num_dds_block ) status = vfstart(file_id(j)) @@ -383,7 +384,7 @@ subroutine read_ae_l2_sm_hdf( & ! ------------------------------------- ! ! eliminate no-data-values and data that fail initial QC - + j = 0 do i=1,N_data @@ -4587,11 +4588,9 @@ end subroutine read_obs_SMOS ! ***************************************************************** - - subroutine read_MODISscf_hdf( N_files, date_time, N_data, fnames, & + subroutine read_MODISscf_hdf( N_files, date_time, N_data, fnames, & lon, lat, MODIS_SCF) - !subroutine read_MODISscf_hdf routine description ! Purpose: read preprocessed (renamed) snow cover data from daily MODIS Terra MOD10C1, version 6.1 (https://nsidc.org/data/mod10c1/versions/61) ! - Data currently located at /discover/nobackup/projects/S2SHMA/MODIS/MOD10C1_V61/ (2010-2022) ! - Daily dataset with spatial resolution of 0.05 deg on CMG grid, missing days 2016 d. 50-58 @@ -4891,11 +4890,11 @@ subroutine read_MODISscf_hdf( N_files, date_time, N_data, fnames, & deallocate(Snow_QA) deallocate(MODIS_SCf_raw) - end subroutine read_MODISscf_hdf + end subroutine read_MODISscf_hdf ! ***************************************************************** - subroutine read_obs_MODISscf( & + subroutine read_obs_MODISscf( & work_path, date_time, dtstep_assim, N_catd, tile_coord, & tile_grid_d, N_tile_in_cell_ij, tile_num_in_cell_ij, & this_obs_param, found_obs, MODIS_obs, std_MODIS_obs) @@ -5100,9 +5099,7 @@ subroutine read_obs_MODISscf( & end subroutine read_obs_MODISscf - ! ***************************************************************** - subroutine read_obs_SMAP_FT( date_time, N_catd, this_obs_param, & dtstep_assim, tile_coord, tile_grid_d, & @@ -7459,6 +7456,7 @@ subroutine read_obs( & logical, intent(in) :: write_obslog ! outputs: + real, intent(out), dimension(N_catd) :: tmp_obs real, intent(out), dimension(N_catd) :: tmp_std_obs real, intent(out), dimension(N_catd) :: tmp_lon @@ -8730,15 +8728,7 @@ subroutine collect_obs( if (scaled_obs) any_scaled_obs = .true. end if - - !if(logit) write(logunit,*) 'length of obs after finishing read_obs', size(tmp_obs_f) - !if(logit) write(logunit,*) 'tmp_obs_f after finishing read_obs', tmp_obs_f - !if(logit) write(logunit,*) 'length of lon after finishing read_obs', size(tmp_lon_f) - !if(logit) write(logunit,*) 'length of lat after finishing read_obs', size(tmp_lat_f) - !if(logit) write(logunit,*) 'N_catf', N_catf - !if(logit) write(logunit,*) 'tile_coord_f', tile_coord_f - !if(logit) write(logunit,*) 'found_obs (after read_obs)=', found_obs - + ! put "tmp_obs" (in "tile" space) into "compressed" vector "Observations_l" ! ! each observation is "managed" ("administered") by the processor that @@ -8769,22 +8759,11 @@ subroutine collect_obs( ! NOTE: "Observations" here are l(ocal) obs only - !if(logit) write(logunit,*), 'N_obsl_max:', N_obsl_max - !if(logit) write(logunit,*), 'N_catl:', N_catl - !if(logit) write(logunit,*), 'l2f:', l2f - !if(logit) write(logunit,*), 'tmp_obs', tmp_obs - !if(logit) write(logunit,*), 'size tmp_obs', size(tmp_obs) - !if(logit) write(logunit,*), 'size tmp_lat', size(tmp_lat) - !if(logit) write(logunit,*), 'size tmp_lon', size(tmp_lon) - !if(logit) write(logunit,*), 'obs_count', obs_count - + call put_into_Observations( obs_param(species), N_obsl_max, N_catl, l2f, & tmp_obs, tmp_std_obs, tmp_lon, tmp_lat, tmp_time, tmp_assim, & obs_count, Observations_l ) - !if(logit) write(logunit,*), 'obs_count (after subroutine):', obs_count - !if(logit) write(logunit,*), 'Observations_l:', size(Observations_l) - !if(logit) write(logunit,*), 'Observation_l%obs', Observations_l%obs - !if(logit) write(logunit,*), 'Observations_l%tilenum', Observations_l%tilenum + end if end do @@ -8794,7 +8773,7 @@ subroutine collect_obs( call MPI_BCAST(any_scaled_obs, 1, MPI_LOGICAL, 0,mpicomm, mpierr) #endif - !if(logit) write(logunit,*) 'N_obsl:', obs_count + N_obsl = obs_count ! ----------------------------------------------------------------- @@ -8830,7 +8809,6 @@ subroutine collect_obs( do ii=2,N_obsl this_tilenum_new = Observations_l(ii)%tilenum - !if(logit) write(logunit,*) 'tilenum', this_tilenum_new if ( (this_tilenum_new/=this_tilenum) .or. (ii==N_obsl) ) then @@ -8848,12 +8826,10 @@ subroutine collect_obs( ! of (local) obs with the same tilenum N_tmp = ind_end - ind_start + 1 - !if(logit) write(logunit,*) 'N_tmp', 'N_tmp' if (N_tmp>1) then tmp_species(1:N_tmp) = Observations_l(ind_start:ind_end)%species - !if(logit) write(logunit,*) 'tmp_species', tmp_species ! get index vector for sorting by species (see NOTES above!) @@ -9021,15 +8997,10 @@ subroutine put_into_Observations( this_obs_param, N_obs_max, N_catd, l2f, & ! ------------------------------------------------------ - if(logit) write(logunit,*) 'Entering put_into_Observations' - nodatavalue = this_obs_param%nodata tol = abs(nodatavalue*nodata_tolfrac_generic) - !if(logit) write(logunit,*) 'tol:', tol - !if(logit) write(logunit,*) 'N_catd:', N_catd - do i=1,N_catd if (abs(tmp_obs(i)-nodatavalue) > tol) then ! check for no-data-value diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index a70562a1..2d09f9d0 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -401,6 +401,7 @@ subroutine read_ens_upd_inputs( & ! extract species into obs_param N_tmp = max( obs_param_nml(i)%N_ang, 1 ) + do k=1,N_tmp j = j + 1 @@ -760,6 +761,7 @@ subroutine get_cat_progn_ens_avg(N_catd, N_ens, cat_progn, cat_progn_ensavg) type(cat_progn_type), dimension(N_catd,N_ens), intent(in) :: cat_progn type(cat_progn_type), dimension(N_catd), intent(out) :: cat_progn_ensavg + ! locals integer :: i, n_e @@ -880,7 +882,7 @@ subroutine assemble_obs_cov(N_obs, N_obs_param, obs_param, Observations, Obs_cov ! bug fix ! GDL+reichle, 17 Oct 2014 !Obs_cov(i,j) = Observations(i)%obsvar * fac - !Obs_cov(i,j) = Observations(i)%obsvar * fac + Obs_cov(i,j) = sqrt(Observations(i)%obsvar * Observations(j)%obsvar) * fac Obs_cov(j,i) = Obs_cov(i,j) @@ -957,7 +959,8 @@ subroutine get_obs_pred( & real, dimension(:,:), pointer :: Obs_pred_l ! output - logical, intent(in), dimension(N_obsl), optional :: obsbias_ok + logical, intent(in), dimension(N_obsl), optional :: obsbias_ok + real, intent(in), optional :: fcsterr_inflation_fac ! -------------------------------------------------------------------------------- @@ -995,7 +998,7 @@ subroutine get_obs_pred( & logical :: get_tp_l logical :: get_Tb_l, get_Tb_lH logical :: get_FT_l, get_FT_lH - logical :: get_asnow_l, get_asnow_lH !jpark50 + logical :: get_asnow_l, get_asnow_lH type(grid_def_type) :: tile_grid_lH integer, dimension(N_obs_param) :: ind_obsparam2Tbspecies @@ -1110,7 +1113,7 @@ subroutine get_obs_pred( & get_tp_l = .false. get_FT_l = .false. get_Tb_l = .false. - get_asnow_l = .false. !jpark50 Snow cover assimilation + get_asnow_l = .false. ! get_*_lH : directly match observed fields @@ -1119,7 +1122,7 @@ subroutine get_obs_pred( & get_tsurf_lH = .false. get_FT_lH = .false. get_Tb_lH = .false. - get_asnow_lH = .false. !jpark50 Snow cover assimilation + get_asnow_lH = .false. ! loop through obs_param b/c obs on local proc may not reflect all obs @@ -1174,7 +1177,8 @@ subroutine get_obs_pred( & get_Tb_lH = .true. - case('asnow') !jpark50 Snow cover assimilation + case('asnow') + get_asnow_l = .true. get_asnow_lH = .true. @@ -1336,7 +1340,7 @@ subroutine get_obs_pred( & call StieglitzSnow_calc_asnow( N_snow, N_catl, & catprogn2wesn(N_catl,cat_progn(:,n_e)), & - asnow) + asnow ) call catch_calc_tsurf_excl_snow( N_catl, & cat_progn(:,n_e)%tc1, cat_progn(:,n_e)%tc2, cat_progn(:,n_e)%tc4, & @@ -1349,9 +1353,11 @@ subroutine get_obs_pred( & end if if (get_asnow_l) then - call StieglitzSnow_calc_asnow( N_snow, N_catl, & - catprogn2wesn(N_catl,cat_progn(:,n_e)), & - asnow_l) + + call StieglitzSnow_calc_asnow( N_snow, N_catl, & + catprogn2wesn(N_catl,cat_progn(:,n_e)), & + asnow_l(:,n_e) ) + end if if (get_Tb_l) then @@ -1951,7 +1957,7 @@ subroutine get_obs_pred( & end do end if - !if(logit) write(logunit,*) 'Ending get_obs_pred' + ! ---------------------------------------------------------------- end subroutine get_obs_pred @@ -3134,6 +3140,7 @@ subroutine get_obs_pert( N_ens, N_obs, N_obs_param, & ! ----------------------------------------------------------------- nullify(obs_pert_param) + ! determine pert_grid_lH ! - pert_grid_lH is the local grid for which perturbations are needed ! - pert_grid_lH is larger than pert_grid_l by the "halo" @@ -3374,14 +3381,13 @@ subroutine get_obs_pert( N_ens, N_obs, N_obs_param, & !call check_obs_pert( N_ens, N_catd, N_obs, cat_param, Observations, & ! Obs_pert ) - !if(logit) write(logunit, *) 'exit get_obs_pert' end subroutine get_obs_pert ! ********************************************************************* subroutine cat_enkf_increments( & - N_ens, N_obs, N_catd, N_obs_param, & + N_ens, N_obs, N_catd, N_obs_param, & update_type, obs_param, & tile_coord, l2f, & Observations, Obs_pred, Obs_pert, & @@ -3395,10 +3401,14 @@ subroutine cat_enkf_increments( & ! reichle, 27 Jul 2005 ! reichle, 18 Oct 2005 - return increments (instead of updated cat_progn) ! reichle, 17 Oct 2011 - added "l2f" for revised (MPI) analysis - ! jpark50, 28 Jul 2020 - added met_force at the subroutine for 1D snow assimilation + ! jpark50, 28 Jul 2020 - added met_force to argument list for MODIS SCF assimilation ! reichle, 20 Feb 2022 - modified update_type 10 for PEATCLSM ! ! -------------------------------------------------------------- + + ! IMPORTANT: + ! on input, cat_progn must contain cat_progn_minus(1:N_catd,1:N_ens) + ! on output, cat_progn_incr contains INCREMENTS ! type of update is selected by "update_type" @@ -3538,8 +3548,6 @@ subroutine cat_enkf_increments( & cat_progn_incr(kk,n_e) = 0. end do end do - - ! reichle_15Dec2021: removed redundant initialization of cat_progn_incr ! avoid unnecessary work or subroutine calls @@ -3637,10 +3645,12 @@ subroutine cat_enkf_increments( & asnow_ensavg = 0. do n_e=1,N_ens + SWE_ensavg = SWE_ensavg + SWE( :,n_e) tsurf_ensavg = tsurf_ensavg + tsurf( :,n_e) tp1_ensavg = tp1_ensavg + tp( 1,:,n_e) asnow_ensavg = asnow_ensavg + asnow( :,n_e) + end do SWE_ensavg = SWE_ensavg /real(N_ens) @@ -4028,6 +4038,7 @@ subroutine cat_enkf_increments( & end do ! ---------------------------------- + case (7) select_update_type ! 3d Tskin/ght(1) analysis; tskin obs ! update each tile separately using all observations within @@ -4588,7 +4599,7 @@ subroutine cat_enkf_increments( & ! 4. Relayer to balance the snow column call relayer2( N_snow, N_constit , & - CATCH_DZ1MAX, DZMAX(2:N_snow), & + CATCH_DZ1MAX, DZMAX(2:N_snow), & tmp_htsn(kk, n_e, 1:N_snow), & tmp_wesn(kk, n_e, 1:N_snow), & tmp_sndz(kk, n_e, 1:N_snow), & @@ -4640,7 +4651,6 @@ subroutine cat_enkf_increments( & ! NO checks of prognostics after update, this is now done after ! increments have been applied. ! - reichle, 18 Oct 2005 - if (logit) write(logunit,*) 'Cat_enkf_increment completed' end subroutine cat_enkf_increments @@ -4664,7 +4674,7 @@ subroutine get_select_species( & type(obs_param_type), dimension(N_obs_param), intent(in) :: obs_param integer, intent(out) :: N_select_species - integer, dimension(N_obs_param), intent(out) :: select_species + integer, dimension(N_obs_param), intent(out) :: select_species ! local variables @@ -4680,13 +4690,7 @@ subroutine get_select_species( & if (N_select_varnames > 0) then - !if(logit) write(logunit,*) 'N_obs_param:', N_obs_param - !if(logit) write(logunit,*) 'Select_varnames:', select_varnames - do ii=1,N_obs_param - - !if(logit) write(logunit,*) obs_param(ii)%varname - !if(logit) write(logunit,*) select_varnames if (any(trim(obs_param(ii)%varname)==select_varnames)) then @@ -4806,8 +4810,7 @@ subroutine get_ind_obs( & if ( any(Observations(i)%tilenum == select_tilenum) .and. & any(Observations(i)%species == select_species) ) then - if(logit) write(logunit,*) '********Found matching point*********' - + k = k+1 ind_obs(k) = i @@ -5343,8 +5346,6 @@ end subroutine dist_km2deg ! ****************************************************************** - ! reichle_15Dec2021: undid deletion of ~half of the old, commented-out subroutine below - ! abandoned during changes for obs halo ! to reinstate, need to MPI_Gather "cat_param_f" ! From 90780689edd00a09b87604e671a40b1d085f3512 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Fri, 14 Jul 2023 18:55:58 -0400 Subject: [PATCH 105/308] additional minor cleanup for MODIS SCF DA (clsm_ensupd_enkf_update.F90, clsm_ensupd_upd_routines.F90) --- .../clsm_ensupd_enkf_update.F90 | 38 +++++++------------ .../clsm_ensupd_upd_routines.F90 | 8 ++-- 2 files changed, 18 insertions(+), 28 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 index 41adac85..3b532c76 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 @@ -302,9 +302,12 @@ subroutine get_enkf_increments( & integer :: nTiles_ana, nTilesAna_vec(numprocs) integer, dimension(:), allocatable :: indTiles_l, indTiles_f, indTiles_ana type(varLenIntArr) :: indTilesAna_vec(numprocs) + type(tile_coord_type), dimension(:), pointer :: tile_coord_ana ! input to cat_enkf_increment() is a pointer + type(met_force_type), dimension(:), allocatable :: met_force_f, met_force_ana type(cat_param_type), dimension(:), allocatable :: cat_param_f, cat_param_ana + type(cat_progn_type), allocatable :: cat_progn_f(:), cat_progn_ana(:,:) type(cat_progn_type), allocatable :: tmp_cat_progn_ana(:) type(cat_progn_type), allocatable :: cat_progn_incr_f(:), cat_progn_incr_ana(:,:) @@ -405,7 +408,7 @@ subroutine get_enkf_increments( & tile_coord_f%pert_i_indg, tile_coord_f%pert_j_indg, & pert_grid_f, maxval(N_tile_in_cell_ij_f), tile_num_in_cell_ij_f ) else - allocate(N_tile_in_cell_ij_f(0,0)) !for debugging + allocate(N_tile_in_cell_ij_f(0,0)) ! for debugging end if ! ********************************************************************* @@ -706,7 +709,7 @@ subroutine get_enkf_increments( & if (root_proc) then allocate(indTiles_f(nTiles_f), source=-99) else - allocate(indTiles_f(0)) ! for debugging mode + allocate(indTiles_f(0)) ! for debugging mode endif if (root_proc) then @@ -841,7 +844,7 @@ subroutine get_enkf_increments( & Obs_ana = Obs_f_assim(indObs_ana(1:nObs_ana)) if (allocated(Obs_f_assim)) deallocate(Obs_f_assim) - ! step 4b: tile_coord_ana + ! Step 4b: tile_coord_ana allocate(tile_coord_ana(nTiles_ana)) tile_coord_ana = tile_coord_f(indTiles_ana) @@ -849,7 +852,7 @@ subroutine get_enkf_increments( & if (root_proc) then allocate(met_force_f(N_catf)) else - allocate(met_force_f(0)) !for debugging mode + allocate(met_force_f(0)) ! for debugging mode endif call MPI_Gatherv( & met_force, N_catl, MPI_met_force_type, & @@ -878,7 +881,7 @@ subroutine get_enkf_increments( & if (root_proc) then allocate(cat_param_f(N_catf)) else - allocate(cat_param_f(0)) !for debugging mode + allocate(cat_param_f(0)) ! for debugging mode endif call MPI_Gatherv( & cat_param, N_catl, MPI_cat_param_type, & @@ -908,7 +911,7 @@ subroutine get_enkf_increments( & if (root_proc) then allocate(cat_progn_f(N_catf)) else - allocate(cat_progn_f(0)) ! for debugging mode + allocate(cat_progn_f(0)) ! for debugging mode endif allocate(cat_progn_ana(nTiles_ana,N_ens)) @@ -960,7 +963,7 @@ subroutine get_enkf_increments( & if (root_proc) then allocate(Obs_pred_f_assim(N_obsf_assim)) else - allocate(Obs_pred_f_assim(0)) ! for debugging mode + allocate(Obs_pred_f_assim(0)) ! for debugging mode endif allocate(Obs_pred_ana(nObs_ana,N_ens), source=0.) if (root_proc) then @@ -1074,21 +1077,6 @@ subroutine get_enkf_increments( & #ifdef LDAS_MPI allocate(cat_progn_incr_ana(nTiles_ana,N_ens)) - !if(logit) write(logunit,*) 'Entering cat_enkf_increments' - !if(logit) write(logunit,*) 'length of Obs_ana: ', size(Obs_ana) - !if(logit) write(logunit,*) 'length of Obs_pred_ana: ', size(Obs_pred_ana) - !if(logit) write(logunit,*) 'length of Obs_pert_tmp: ', size(Obs_pert_tmp) - !if(logit) write(logunit,*) 'length of tile_coord_ana: ', size(tile_coord_ana) - !if(logit) write(logunit,*) 'Obs_ana: ', Obs_ana - !if(logit) write(logunit,*) 'Obs_ana%species: ', Obs_ana%species - !if(logit) write(logunit,*) 'Obs_ana%tilenum: ', Obs_ana%tilenum - !if(logit) write(logunit,*) 'Obs_ana%lat: ', Obs_ana%lat - !if(logit) write(logunit,*) 'Obs_ana%lon: ', Obs_ana%lon - !if(logit) write(logunit,*) 'Obs_ana%obs: ', Obs_ana%obs - !if(logit) write(logunit,*) 'Obs_pred_ana: ', Obs_pred_ana - !if(logit) write(logunit,*) 'Obs_pert_tmp: ', Obs_pert_tmp - !if(logit) write(logunit,*) 'tile_corrd_ana: ', tile_coord_ana - call cpu_time(t_start) call cat_enkf_increments( & N_ens, nObs_ana, nTiles_ana, N_obs_param, & @@ -1142,7 +1130,7 @@ subroutine get_enkf_increments( & allocate(cat_progn_incr_f(N_catf)) allocate(recvBuf(maxval(nTilesAna_vec))) ! temp storage of incoming data else - allocate(cat_progn_incr_f(0)) ! for debugging + allocate(cat_progn_incr_f(0)) ! for debugging end if do iEns=1,N_ens ! cat_progn_incr_ana -> cat_progn_incr_f @@ -1425,7 +1413,7 @@ subroutine apply_enkf_increments( N_catd, N_ens, update_type, & do n_e=1,N_ens ! for each ensemble member - do ii=1,N_SNOW ! for each snow layer + do ii=1,N_snow ! for each snow layer cat_progn(n,n_e)%wesn(ii) = & cat_progn(n,n_e)%wesn(ii) + cat_progn_incr(n,n_e)%wesn(ii) @@ -1435,8 +1423,8 @@ subroutine apply_enkf_increments( N_catd, N_ens, update_type, & cat_progn(n,n_e)%htsn(ii) = & cat_progn(n,n_e)%htsn(ii) + cat_progn_incr(n,n_e)%htsn(ii) - end do + end do end do end do diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index 2d09f9d0..febe39d4 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -882,7 +882,6 @@ subroutine assemble_obs_cov(N_obs, N_obs_param, obs_param, Observations, Obs_cov ! bug fix ! GDL+reichle, 17 Oct 2014 !Obs_cov(i,j) = Observations(i)%obsvar * fac - Obs_cov(i,j) = sqrt(Observations(i)%obsvar * Observations(j)%obsvar) * fac Obs_cov(j,i) = Obs_cov(i,j) @@ -1460,13 +1459,14 @@ subroutine get_obs_pred( & #ifdef LDAS_MPI ! count number of fields that need to be communicated (N_fields), allocate as needed + call get_obs_pred_comm_helper( N_catl, N_ens, N_TbuniqFreqAngRTMid, & get_sfmc_lH, get_rzmc_lH, get_tsurf_lH, get_FT_lH, get_asnow_lH, get_Tb_lH, N_fields) ! allocate and assemble tile_data_l + if (allocated(tile_data_l)) deallocate(tile_data_l) allocate(tile_data_l(N_catl,N_fields,N_ens)) - call get_obs_pred_comm_helper( N_catl, N_ens, N_TbuniqFreqAngRTMid, & get_sfmc_lH, get_rzmc_lH, get_tsurf_lH, get_FT_lH, get_asnow_lH, get_Tb_lH, N_fields, & option=1, tile_data=tile_data_l, & @@ -1474,11 +1474,13 @@ subroutine get_obs_pred( & Tb_h=Tb_h_l, Tb_v=Tb_v_l, asnow=asnow_l ) ! communicate tile_data_l as needed and get tile_data_lH + call get_tiles_in_halo( N_catl, N_fields, N_ens, tile_data_l, tile_coord_l, & N_catf, tile_coord_f, N_catl_vec, low_ind, xhalo, yhalo, & N_catlH, tile_data_lH=tile_data_lH ) ! read out sfmc, rzmc, etc. from tile_data_lH + call get_obs_pred_comm_helper( N_catlH, N_ens, N_TbuniqFreqAngRTMid, & get_sfmc_lH, get_rzmc_lH, get_tsurf_lH, get_FT_lH, get_asnow_lH, get_Tb_lH, N_fields, & option=2, tile_data=tile_data_lH, & @@ -3393,7 +3395,7 @@ subroutine cat_enkf_increments( & Observations, Obs_pred, Obs_pert, & met_force, cat_param, & xcompact, ycompact, fcsterr_inflation_fac, & - cat_progn, cat_progn_incr) + cat_progn, cat_progn_incr ) ! get increments for Catchment prognostic variables ! From 91c948a4f6c560486ea78b13faf70bc03d991ffd Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Sat, 15 Jul 2023 08:42:30 -0400 Subject: [PATCH 106/308] cleanup of MODIS SCF analysis subroutine and other minor cleanup (clsm_ensupd_upd_routines.F90, clsm_ensupd_glob_param.F90, clsm_ensupd_read_obs.F90) --- .../clsm_ensupd_glob_param.F90 | 11 +- .../clsm_ensupd_read_obs.F90 | 18 +- .../clsm_ensupd_upd_routines.F90 | 218 ++++++++++-------- 3 files changed, 139 insertions(+), 108 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_glob_param.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_glob_param.F90 index d3cdcf16..a882e887 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_glob_param.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_glob_param.F90 @@ -93,7 +93,7 @@ module clsm_ensupd_glob_param ! ---------------------------------------------------------------- ! - ! parameter for freeze/thaw (FT) analysis + ! parameters for freeze/thaw (FT) analysis real, parameter :: FT_ANA_FT_THRESHOLD = 0.5 @@ -103,6 +103,15 @@ module clsm_ensupd_glob_param real, parameter :: FT_ANA_UPPERBOUND_TEFF = +1.0 + MAPL_TICE ! [Kelvin] ! ---------------------------------------------------------------- + ! + ! parameters for snow cover area fraction (SCF) analysis (modified from Toure et al. 2018) + + real, parameter :: SCF_ANA_ALPHA = 0.60 ! [-] add snow if asnow_fcst < asnow_obs*SCF_ANA_alpha ("bias" adjustment for obs) + real, parameter :: SCF_ANA_BETA = 0.55 ! [-] remove snow if asnow_fcst > asnow_obs*SCF_ANA_alpha .AND. asnow_obs < SCF_ANA_beta + real, parameter :: SCF_ANA_MAXINCRSWE = 5.0 ! [kg/m2] max total SWE increment + real, parameter :: SCF_ANA_MINFCSTSWE = 0.01 ! [kg/m2] threshold below which the ratio of swe_ana/swe_fcst tends to be unreasonable + + ! ---------------------------------------------------------------- contains diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index f1263c22..9ddc9dd1 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -7722,17 +7722,15 @@ subroutine read_obs( & this_obs_param, tmp_obs, tmp_std_obs, tmp_assim ) end if - - case ('MODIS_SCF') - - call read_obs_MODISscf( & - work_path, date_time, dtstep_assim, N_catd, tile_coord, & - tile_grid_d, N_tile_in_cell_ij, tile_num_in_cell_ij, & - this_obs_param, found_obs, tmp_obs, tmp_std_obs) - - !scaled_obs = .false. + + case ('MODIS_SCF') + + call read_obs_MODISscf( & + work_path, date_time, dtstep_assim, N_catd, tile_coord, & + tile_grid_d, N_tile_in_cell_ij, tile_num_in_cell_ij, & + this_obs_param, found_obs, tmp_obs, tmp_std_obs) - case('SMAP_L1C_Tbh_A', 'SMAP_L1C_Tbv_A', & + case('SMAP_L1C_Tbh_A', 'SMAP_L1C_Tbv_A', & 'SMAP_L1C_Tbh_D', 'SMAP_L1C_Tbv_D', & 'SMAP_L1C_Tbh_E09_A', 'SMAP_L1C_Tbv_E09_A', & 'SMAP_L1C_Tbh_E09_D', 'SMAP_L1C_Tbv_E09_D', & diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index febe39d4..df48180e 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -32,7 +32,11 @@ module clsm_ensupd_upd_routines FT_ANA_FT_THRESHOLD, & FT_ANA_LOWERBOUND_ASNOW, & FT_ANA_LOWERBOUND_TEFF, & - FT_ANA_UPPERBOUND_TEFF + FT_ANA_UPPERBOUND_TEFF, & + SCF_ANA_ALPHA, & + SCF_ANA_BETA, & + SCF_ANA_MAXINCRSWE, & + SCF_ANA_MINFCSTSWE use my_matrix_functions, ONLY: & row_variance, & @@ -103,15 +107,17 @@ module clsm_ensupd_upd_routines use catch_constants, ONLY: & N_snow => CATCH_N_SNOW, & N_gt => CATCH_N_GT, & + RHOFS => CATCH_SNWALB_RHOFS, & CATCH_DZ1MAX, & PEATCLSM_POROS_THRESHOLD + + use SurfParams, ONLY: & + WEMIN - use STIEGLITZSNOW, ONLY: & + use STIEGLITZSNOW, ONLY: & StieglitzSnow_calc_asnow, & relayer2, & N_constit - !topthick, & - !thickdist use LDAS_ensdrv_mpi, ONLY: & numprocs, & @@ -1534,7 +1540,7 @@ subroutine get_obs_pred( & tile_grid_lH, maxval(N_tile_in_cell_ij_lH), tile_num_in_cell_ij_lH ) end if - !if(logit) write(logunit,*) 'Tile change completed' + ! ----------------------- allocate(ind_tmp( N_catlH)) @@ -1966,8 +1972,8 @@ end subroutine get_obs_pred ! ***************************************************************** - subroutine get_obs_pred_comm_helper( & - N_cat, N_ens, N_Tb, get_sfmc, get_rzmc, get_tsurf, get_FT, get_asnow, get_Tb, & + subroutine get_obs_pred_comm_helper( & + N_cat, N_ens, N_Tb, get_sfmc, get_rzmc, get_tsurf, get_FT, get_asnow, get_Tb, & N_fields, option, tile_data, sfmc, rzmc, tsurf, FT, asnow, stemp, Tb_h, Tb_v ) ! bundle/unbundle individual fields into/from single array for more @@ -3424,9 +3430,6 @@ subroutine cat_enkf_increments( & ! ------------------------------------------------------------------- - use SurfParams, ONLY: WEMIN - use Catch_Constants, ONLY: RHOFS => CATCH_SNWALB_RHOFS - implicit none ! inputs @@ -3481,6 +3484,7 @@ subroutine cat_enkf_increments( & real :: fice_plus, tp1_plus, ght1_plus integer, dimension(N_obs) :: ind_obs + real, allocatable, dimension(:,:) :: State_incr real, allocatable, dimension(:,:) :: Obs_cov ! measurement error covariance @@ -3520,24 +3524,16 @@ subroutine cat_enkf_increments( & type(obs_param_type) :: this_obs_param integer :: isnow - real :: asnow_fcst, swe_fcst, swe_ana, asnow_ana, swe_ratio + real :: asnow_fcst, swe_fcst, swe_ratio + real :: asnow_ana, swe_ana + real, dimension(1) :: asnow_ana_array ! StieglitzSnow_calc_asnow() requires array + real, dimension(1, 1) :: swe_ana_array ! StieglitzSnow_calc_asnow() requires array real, dimension(N_catd,N_ens) :: swe_incr real, dimension(N_catd,N_ens,N_snow) :: tmp_wesn, tmp_htsn, tmp_sndz + real, dimenions(N_snow) :: targetthick ! for snow model relayer real, dimension(N_snow,N_constit) :: rconstit - ! ------------------------------------------------------------------- - ! Need to clean up and pull these two hardwired numbers from GCM GridComp or MAPL, reichle 20221007 (TO DO) - real, dimension(N_snow), parameter :: DZMAX = (/0.08, 0.5, 0.5/) ! target thickness for relayer2() ! needs to be pulled from Catch GC; would fail with N_snow /= 3; - - ! ------------------------------------------------------------------- - - ! design parameters for 1d snow cover analysis modified from Toure et al. 2018 - real, parameter:: modis_scf_alpha_threshold = 0.60 ! dimensionless, Obs_scf * scf_alpha_threshold below which snow is added - real, parameter:: modis_scf_beta_threshold = 0.55 ! dimensionless, Obs threshold below which to remove snow - real, parameter:: modis_max_incr_swe = 5.0 ! kg m-2 - real, parameter:: smallfcstswe = 0.01 ! kg m-2 threshold for "no snow" below which the ratio of swe_ana/swe_fcst tends to be unreasonable - ! ----------------------------------------------------------------------- if (logit) write (logunit,*) & @@ -4468,19 +4464,30 @@ subroutine cat_enkf_increments( & end if end do - ! ---------------------------------- - + ! ---------------------------------- + case (11) select_update_type ! 1d snow analysis (Toure et al. 2018 empirical gain); snow cover fraction obs if (logit) write (logunit, *) 'get 1d snow increments (Toure et al. 2018 empirical gain); snow cover fraction obs' - ! make sure maximum SWE increment is less than WEMIN (adding more snow than WEMIN makes no sense) + ! ensure that max SWE increment parameter is less than WEMIN; larger increments make no sense because + ! at SWE=WEMIN, the tile is fully snow covered (asnow=1) - if (modis_max_incr_swe>WEMIN) call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'must use max_incr_swe<=WEMIN') + if (SCF_ANA_MAXINCRSWE>WEMIN) call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'must use SCF_ANA_MAXINCRSWE<=WEMIN') + + ! get target for snow layer thickness + + targetthick(1) = CATCH_DZ1MAX - !identify the species ID number of interest + do i=2,N_snow + targetthick(i)=1./(N_snow-1.) + end do + + ! identify the obs species of interest + N_select_varnames = 1 + select_varnames(1) = 'asnow' call get_select_species( & @@ -4489,8 +4496,8 @@ subroutine cat_enkf_increments( & allocate(select_tilenum(1)) - swe_incr = 0. ! initialize to NO CHANGE - + swe_incr = 0. ! total SWE increment; initialize to NO CHANGE + ! loop through tiles and compute increments do kk=1,N_catd @@ -4499,37 +4506,55 @@ subroutine cat_enkf_increments( & select_tilenum(1) = l2f(kk) - ! if(logit) write(logunit,*) 'kk:', kk - call get_ind_obs( & N_obs, Observations, & 1, select_tilenum, & N_select_species, select_species(1:N_select_species), & N_selected_obs, ind_obs ) - if (N_selected_obs == 1) then ! COULD THERE EVER BE MORE THAN ONE OBS HERE??? TBD reichle 20221007 + if (N_selected_obs > 0) then - do n_e=1,N_ens ! compute analysis separately for each ensemble member + ! NEED TO ALLOW FOR MULTIPLE asnow OBS (I.E., FROM MULTIPLE SENSORS, SAY, MODIS AND VIIRS) + ! + ! if statement added to maintain 0-diff for now; can be removed later + ! (that is, compute average even when N_selected_obs=1) + + if (N_selected_obs > 1) then + + ! compute average obs value + + tmp_obs = sum(Observations(ind_obs(1:N_selected_obs))%obs) + + tmp_obs = tmp_obs/real(N_selected_obs) + + else - ! 1. Calculate model forecast snow area and SWE + tmp_obs = Observations(ind_obs(1))%obs + + end if + + + do n_e=1,N_ens ! compute analysis separately for each ensemble member + + ! 1. Get model forecast snow cover area fraction and total SWE - asnow_fcst = asnow(kk, n_e) - swe_fcst = sum(cat_progn(kk, n_e)%wesn(1:N_snow)) + asnow_fcst = asnow(kk,n_e) + swe_fcst = sum(cat_progn(kk,n_e)%wesn(1:N_snow)) ! 2. Calculate SWE increment based on Toure et al (2018) eq 1 - if (asnow_fcst .lt. Observations(ind_obs(1))%obs * modis_scf_alpha_threshold) then + if (asnow_fcst .lt. tmp_obs * SCF_ANA_ALPHA) then - ! ADD SNOW: SCA of model is less than observed SCA + ! ADD SNOW: Forecast SCF is less than observed SCF (after "bias" adjustment with alpha) - swe_incr(kk,n_e) & - = modis_max_incr_swe * (Observations(ind_obs(1))%obs - asnow_fcst/modis_scf_alpha_threshold) + swe_incr(kk,n_e) = SCF_ANA_MAXINCRSWE * (tmp_obs - asnow_fcst/SCF_ANA_ALPHA) - elseif (Observations(ind_obs(1))%obs .lt. modis_scf_beta_threshold) then + elseif (tmp_obs .lt. SCF_ANA_BETA) then - ! REMOVE SNOW: IF SCA of model is greater than observed SCA + ! REMOVE SNOW: Simulated SCF is greater than observed SCF (after "bias" adjustment) + ! and observed SCF is less than beta threshold - swe_incr(kk,n_e) = (-1.) * modis_max_incr_swe * asnow_fcst * (1. - Observations(ind_obs(1))%obs/modis_scf_beta_threshold) + swe_incr(kk,n_e) = (-1.) * SCF_ANA_MAXINCRSWE * asnow_fcst * (1. - tmp_obs/SCF_ANA_BETA) else @@ -4539,96 +4564,95 @@ subroutine cat_enkf_increments( & ! 3. Derive SWE, snow heat content, and snow depth increments for each layer from total SWE increment - swe_ana = max(swe_fcst + swe_incr(kk, n_e), 0.0) ! total SWE after analysis + swe_ana = max(swe_fcst + swe_incr(kk,n_e), 0.0) ! total SWE after analysis - asnow_ana = min(swe_ana/wemin, 1.) ! calculate the snow area - if (logit) write (logunit, *) '!!!! asnow_ana = ', asnow_ana, '!!!!' - - if (swe_fcst>=smallfcstswe) then + swe_ana_array(1,1) = swe_ana + + call StieglitzSnow_calc_asnow( 1, 1, swe_ana_array, asnow_ana_array ) + + asnow_ana = asnow_ana_array(1) ! asnow after analysis + + if (swe_fcst>=SCF_ANA_MINFCSTSWE) then swe_ratio = swe_ana / swe_fcst else - swe_ratio = 1. ! set to neutral just in case, but should not be used if swe_fcst 0) + + end do ! kk = 1, N_catd ! ---------------------------------- From c44a71bc947dcbbf637f615d06ed12a7d17de67c Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Sat, 15 Jul 2023 15:16:25 -0400 Subject: [PATCH 107/308] fixed build errors in previous commit (clsm_ensupd_upd_routines.F90, clsm_ensupd_glob_param.F90) --- .../GEOSlandassim_GridComp/clsm_ensupd_glob_param.F90 | 10 +++++++--- .../clsm_ensupd_upd_routines.F90 | 4 ++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_glob_param.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_glob_param.F90 index a882e887..72c5a509 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_glob_param.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_glob_param.F90 @@ -36,6 +36,10 @@ module clsm_ensupd_glob_param public :: FT_ANA_LOWERBOUND_ASNOW public :: FT_ANA_LOWERBOUND_TEFF public :: FT_ANA_UPPERBOUND_TEFF + public :: SCF_ANA_ALPHA + public :: SCF_ANA_BETA + public :: SCF_ANA_MAXINCRSWE + public :: SCF_ANA_MINFCSTSWE public :: echo_clsm_ensupd_glob_param @@ -106,10 +110,10 @@ module clsm_ensupd_glob_param ! ! parameters for snow cover area fraction (SCF) analysis (modified from Toure et al. 2018) - real, parameter :: SCF_ANA_ALPHA = 0.60 ! [-] add snow if asnow_fcst < asnow_obs*SCF_ANA_alpha ("bias" adjustment for obs) - real, parameter :: SCF_ANA_BETA = 0.55 ! [-] remove snow if asnow_fcst > asnow_obs*SCF_ANA_alpha .AND. asnow_obs < SCF_ANA_beta + real, parameter :: SCF_ANA_ALPHA = 0.60 ! [-] add snow if asnow_fcst < asnow_obs*SCF_ANA_alpha (w/ "bias" adjustment for obs) + real, parameter :: SCF_ANA_BETA = 0.55 ! [-] remove snow if asnow_fcst > asnow_obs*SCF_ANA_alpha .AND. asnow_obs < SCF_ANA_beta real, parameter :: SCF_ANA_MAXINCRSWE = 5.0 ! [kg/m2] max total SWE increment - real, parameter :: SCF_ANA_MINFCSTSWE = 0.01 ! [kg/m2] threshold below which the ratio of swe_ana/swe_fcst tends to be unreasonable + real, parameter :: SCF_ANA_MINFCSTSWE = 0.01 ! [kg/m2] threshold below which the ratio of swe_ana/swe_fcst becomes unreasonable ! ---------------------------------------------------------------- diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index df48180e..cc3b807b 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -1457,7 +1457,7 @@ subroutine get_obs_pred( & if (get_rzmc_lH) allocate(rzmc_lH( N_catlH, N_ens)) if (get_tsurf_lH) allocate(tsurf_lH(N_catlH, N_ens)) if (get_FT_lH) allocate(FT_lH( N_catlH, N_ens)) - if (get_asnow_lH) allocate(asnow_lH(N_catlH, N_ens)) !jpark50 + if (get_asnow_lH) allocate(asnow_lH(N_catlH, N_ens)) if (get_Tb_lH) allocate(stemp_lH(N_catlH, N_ens)) if (get_Tb_lH) allocate(Tb_h_lH( N_catlH,N_TbuniqFreqAngRTMid,N_ens)) if (get_Tb_lH) allocate(Tb_v_lH( N_catlH,N_TbuniqFreqAngRTMid,N_ens)) @@ -3531,7 +3531,7 @@ subroutine cat_enkf_increments( & real, dimension(N_catd,N_ens) :: swe_incr real, dimension(N_catd,N_ens,N_snow) :: tmp_wesn, tmp_htsn, tmp_sndz - real, dimenions(N_snow) :: targetthick ! for snow model relayer + real, dimension(N_snow) :: targetthick ! for snow model relayer real, dimension(N_snow,N_constit) :: rconstit ! ----------------------------------------------------------------------- From d89cf9d1904879c55e7bd33335c078f238199962 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Sat, 15 Jul 2023 15:32:14 -0400 Subject: [PATCH 108/308] fixed build error in earlier commit (clsm_ensupd_upd_routines.F90) --- .../GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index cc3b807b..4f40b1b7 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -4476,13 +4476,11 @@ subroutine cat_enkf_increments( & if (SCF_ANA_MAXINCRSWE>WEMIN) call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'must use SCF_ANA_MAXINCRSWE<=WEMIN') - ! get target for snow layer thickness + ! get target for snow layer thickness (as used in Catchment over land tiles) - targetthick(1) = CATCH_DZ1MAX + targetthick(1) = CATCH_DZ1MAX - do i=2,N_snow - targetthick(i)=1./(N_snow-1.) - end do + targetthick(2:N_snow) = 1./(N_snow-1.) ! identify the obs species of interest From 1416f9e4dc9edacdb34b8fdfc3604a3b9f0ee928 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Sat, 15 Jul 2023 17:27:52 -0400 Subject: [PATCH 109/308] initial cleanup of MODIS SCF reader (variable names, some simplifications, etc) (clsm_ensupd_read_obs.F90) --- .../clsm_ensupd_read_obs.F90 | 486 +++++++++--------- 1 file changed, 250 insertions(+), 236 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 9ddc9dd1..24951ae8 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -4587,10 +4587,10 @@ end subroutine read_obs_SMOS ! ***************************************************************** - + subroutine read_MODISscf_hdf( N_files, date_time, N_data, fnames, & - lon, lat, MODIS_SCF) - + MODIS_lon, MODIS_lat, MODIS_SCF) + ! Purpose: read preprocessed (renamed) snow cover data from daily MODIS Terra MOD10C1, version 6.1 (https://nsidc.org/data/mod10c1/versions/61) ! - Data currently located at /discover/nobackup/projects/S2SHMA/MODIS/MOD10C1_V61/ (2010-2022) ! - Daily dataset with spatial resolution of 0.05 deg on CMG grid, missing days 2016 d. 50-58 @@ -4598,58 +4598,62 @@ subroutine read_MODISscf_hdf( N_files, date_time, N_data, fnames, & ! Procedures: ! - dtstep_assim and ref_time is restricted to 3 hr and 00z, respectively ! - Generate the latitude and longitude on CMG grid - ! - Select longitude band considering MODIS observation time (local time: ~10:30am) - + ! - Select longitude band considering MODIS observation time (local time: ~10:30am) ! HARDWIRED OVERPASS TIME, WHAT ABOUT AQUA !?!?!!?!?!?!?! + ! ! Table. Longitude band based on the assimilation time step (in UTC) !----------------------------------------------------------------------------- ! UTC | 0000 | 0300 | 0600 | 0900 | 1200 | 1500 | 1800 | 2100 ! lon | 135 180 | 90 135 | 45 90 | 0 45 | -45 0| -90 -45| -135 -90| -180 -135 - !---------------------------------------------------------------------------- + !----------------------------------------------------------------------------- + ! ! QC: - ! - Use Day_CMG_Snow_Cover > 100 (snow cover only) - ! - Use Day_CMG_Clear_Index > 20% (at least 20% clear sky) - ! - Use Day_CMG_Cloud_Obscured /= 252 (remove antarctica, not technically needed because this would be done by Snow_Spatial_QA) - ! - Use Snow_Spatial_QA <= 3 (use all data) - - + ! - Use Day_CMG_Snow_Cover <= 100 (snow cover only) + ! - Use Day_CMG_Clear_Index > 20% (at least 20% clear sky) + ! - Use Day_CMG_Cloud_Obscured /= 252 (remove Antarctica, not technically needed because this would be done by Snow_Spatial_QA) + ! - Use Snow_Spatial_QA <= 2 (use "best", "good", "ok"; exclude "poor", "other", etc) + implicit none integer, intent(in) :: N_files - type(date_time_type), intent(in) :: date_time ! loading the UTC hour information to constrain the longitude of MODIS obs. + type(date_time_type), intent(in) :: date_time ! need UTC hour to constrain longitude of MODIS obs character(*), dimension(N_files), intent(in) :: fnames + integer, intent(out) :: N_data - real, dimension(:), pointer :: lon, lat - real, dimension(:), pointer :: MODIS_SCF - real, dimension(:), allocatable :: MODIS_SCF_raw + real, dimension(:), pointer :: MODIS_lon, MODIS_lat, MODIS_SCF ! output + + ! locals + + real, dimension(:), allocatable :: SCF_raw, SCF_tmp, lon_tmp, lat_tmp character(1), dimension(:,:), allocatable :: tmp_MODIS_SCF, tmp_CI_Index, tmp_Cloud_index, tmp_Snow_QA - real, allocatable :: MODIS_SCF_tmp(:), lon_tmp(:), lat_tmp(:) - - !local parameters - integer, parameter:: N_fields = 4 - character(18), parameter:: Vdata_name = 'MODIS_CMG_Snow_5km' - character(30), dimension(N_fields), parameter:: field_names = (/ & - 'Day_CMG_Snow_Cover ', & !1 - 'Day_CMG_Clear_Index ', & !2 - 'Day_CMG_Cloud_Obscured ', & !3 - 'Snow_Spatial_QA '/) !4 - - integer, parameter :: nodata = -9999 !integer + ! local parameters + + integer, parameter:: N_fields = 4 + character(18), parameter:: Vdata_name = 'MODIS_CMG_Snow_5km' + character(30), dimension(N_fields), parameter:: field_names = (/ & + 'Day_CMG_Snow_Cover ', & ! 1 + 'Day_CMG_Clear_Index ', & ! 2 + 'Day_CMG_Cloud_Obscured ', & ! 3 + 'Snow_Spatial_QA '/) ! 4 + + integer, parameter :: nodata = -9999 - integer, parameter :: qc_snow_cover_threshold = 100 !screen for areas inland water, ocean, cloud obscured and fill - integer, parameter :: qc_clear_index_threshold = 20 !screen for sufficiently clear condition - integer, parameter :: qc_clear_index_max_threshold = 100 ! screen for lake ice, night obs, ocean - integer, parameter :: qc_antarctica = 252 ! screen for antarctica - integer, parameter :: qc_snow_spatial_threshold = 3 !screen for basic data quality (e.g., 0:best 1:good 2:OK 3:poor, 4:others) + integer, parameter :: qc_snow_cover_min = 0 ! any negative value is no-data + integer, parameter :: qc_snow_cover_max = 100 ! screen for areas inland water, ocean, cloud obscured and fill + integer, parameter :: qc_clear_index_min = 20 ! screen for sufficiently clear condition + integer, parameter :: qc_clear_index_max = 100 ! screen for lake ice, night, inland water, ocean, etc + integer, parameter :: qc_antarctica = 252 ! screen for antarctica + integer, parameter :: qc_snow_spatial_max = 2 ! screen for basic data quality (0=best, 1=good, 2=OK, 3=poor, 4=other) + ! hdf functions - !declariations of hdf functions integer:: sfstart, sffinfo, sfselect, sfn2index, sfginfo, sfrdata integer:: sfend, sfendacc - ! declarations of hdf-related parameters and variables + ! hdf-related parameters and variables + integer, dimension(N_files) :: file_id, sd_id integer, dimension(N_fields) :: ind, sds_id integer :: n_datasets, n_file_attrs, n_attrs, rank, data_type @@ -4658,20 +4662,22 @@ subroutine read_MODISscf_hdf( N_files, date_time, N_data, fnames, & character(100) :: var_name integer :: status, n_read, record_pos - integer, parameter :: DFACC_READ = 1 ! from hdf.inc - integer, parameter :: DFNT_UINT8 = 21 - integer, parameter :: FULL_INTERLACE = 0 ! from hdf.inc + + integer, parameter :: DFACC_READ = 1 ! from hdf.inc + integer, parameter :: DFNT_UINT8 = 21 + integer, parameter :: FULL_INTERLACE = 0 ! from hdf.inc - ! local variables - logical :: must_stop, keep_data + logical :: keep_data ! variables to define latitude and longitude + integer :: i, j, k, k_off, ll, mm, kk, L integer :: time_index real, parameter :: bin_size = 0.05 - integer, parameter :: XGRID = 3600 - integer, parameter :: YGRID = 7200 + integer, parameter :: XGRID = 3600 + integer, parameter :: YGRID = 7200 + integer, dimension(N_files) :: N_data_tmp real :: lat_ind(XGRID) = (/(ll, ll=0, XGRID-1, 1)/) @@ -4682,209 +4688,214 @@ subroutine read_MODISscf_hdf( N_files, date_time, N_data, fnames, & real :: lon_subtime(9) = (/(kk, kk=180, -180, -45)/) integer, dimension(:), allocatable :: Snow_QA, CI_Index, Cloud_Index - character(len=*), parameter :: Iam = 'read_MODISsca_hdf' + character(len=*), parameter :: Iam = 'read_MODISscf_hdf' character(len=400) :: err_msg + ! ------------------------------------------------------------------------- + ! initialize N_data - N_data_tmp(N_files) = XGRID*YGRID + + N_data_tmp(N_files) = XGRID*YGRID !?!?!?! WHY ONLY FOR LAST ELEMENT???? N_data = XGRID*YGRID ! Define latitude and longitude - lat_c = (90-bin_size/2)-bin_size*lat_ind + ! + ! VERIFY THAT lat/lon DEFINITION HERE IS CONSISTENT WITH lat/lon STORED IN FILE ????? + ! PER FILE SPECS: + ! Lat = Upper left X coordinate for each grid cell in degrees north + ! Lon = Upper left Y coordinate for each grid cell in degrees east + + lat_c = ( 90-bin_size/2)-bin_size*lat_ind lon_c = (-180+bin_size/2)+bin_size*lon_ind ! Create a 1D structure for lat and lon (could change to remove this) + do i=1,7200 - lat_1D(3600*(i-1)+1:3600*i)= lat_c + lat_1D(3600*(i-1)+1:3600*i)= lat_c lon_1D(3600*(i-1)+1:3600*i)= lon_c(i) - end do !i - - ! allocate pointers (must be deallocated outside this subroutine) - must_stop = .false. - - if ( associated(lon) .or. associated(lat) .or. associated(MODIS_SCF) ) then - - must_stop = .true. - - end if !(associated(lon) + end do - - if (must_stop) then + ! Ensure output pointers are not allocated (must be deallocated outside this subroutine) - err_msg = 'output pointers must not be associated/allocated on input.' - call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + if ( associated(MODIS_lon) .or. associated(MODIS_lat) .or. associated(MODIS_SCF) ) then - end if !(must_stop) + err_msg = 'output pointers must not be associated/allocated on input.' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + + end if + + ! Allocate SCF and QC vectors - !Allocate SCF and QC vectors - allocate(MODIS_SCF_raw(N_data)) - allocate(CI_Index(N_data)) - allocate(Snow_QA(N_data)) + allocate(SCF_raw( N_data)) + allocate(CI_Index( N_data)) + allocate(Snow_QA( N_data)) allocate(Cloud_Index(N_data)) - ! read hdf data into arrays, concatenate data from N_files files + ! read hdf data into arrays, concatenate data from N_files files !?!?!?!?! NOT HAPPENING... k_off = 0 do j=1,N_files - - ! open and start "hdf file" - sd_id(j) = sfstart(fnames(j), DFACC_READ) - if(logit) write (logunit, *), 'sd_id:' , sd_id(j) - - status = sffinfo(sd_id(j), n_datasets, n_file_attrs) - - - do i=1,N_fields - - ind(i) = sfn2index(sd_id(j), trim(field_names(i))) - ! if (logit) write(logunit, *), 'Field_name:', field_names(i) - ! if (logit) write(logunit, *), 'ind:', ind(i) - - sds_id(i) = sfselect(sd_id(j), ind(i)) - status = sfginfo(sds_id(i), var_name, rank, dim_sizes, data_type, n_attrs) - - start(1) = 0 - start(2) = 0 - edges(1) = dim_sizes(1) - edges(2) = dim_sizes(2) - stride(1) = 1 - stride(2) = 1 - - ! read data - select case (i) - - case (1) !Observed SCF (in percent) - allocate(tmp_MODIS_SCF(dim_sizes(1),dim_sizes(2))) - status = sfrdata(sds_id(i), start, stride, edges, tmp_MODIS_SCF) - - L=0 - do k=1, YGRID - - do kk=1, XGRID - L=L+1 - MODIS_SCF_raw(L) = ichar(tmp_MODIS_SCF(k, kk)) - end do !kk - - end do !k, case (1) - - case (2) !Clear Index - allocate(tmp_CI_Index(dim_sizes(1), dim_sizes(2))) - status = sfrdata(sds_id(i), start, stride, edges, tmp_CI_Index) + ! open and start "hdf file" + + sd_id(j) = sfstart(fnames(j), DFACC_READ) + + !if (logit) write (logunit,*), 'sd_id:' , sd_id(j) + + status = sffinfo( sd_id(j), n_datasets, n_file_attrs ) + + do i=1,N_fields + + ind(i) = sfn2index(sd_id(j), trim(field_names(i))) + sds_id(i) = sfselect( sd_id(j), ind(i)) + + status = sfginfo( sds_id(i), var_name, rank, dim_sizes, data_type, n_attrs ) + + start(1) = 0 + start(2) = 0 + edges(1) = dim_sizes(1) + edges(2) = dim_sizes(2) + stride(1) = 1 + stride(2) = 1 + + ! read 2-dim data and convert to 1-dim arrays (!?!?!?!? WOULD MAKE SENSE IF CONCATENATING DATA FROM MULTIPLE FILES) - L=0 - do k=1, YGRID - - do kk=1, XGRID - L=L+1 - CI_Index(L) = ichar(tmp_CI_index(k,kk)) - end do !kk + select case (i) - end do !k, case (2) + case (1) ! Observed SCF (in percent) - case (3) !Cloud Index - allocate(tmp_Cloud_Index(dim_sizes(1), dim_sizes(2))) - status = sfrdata(sds_id(i), start, stride, edges, tmp_Cloud_Index) - - L=0 - do k=1, YGRID - - do kk=1, XGRID - L = L+1 - Cloud_Index(L) = ichar(tmp_Cloud_Index(k, kk)) - end do !kk - - end do !k, case (2) - - case (4) !Snow_QA - allocate(tmp_Snow_QA(dim_sizes(1),dim_sizes(2))) - status = sfrdata(sds_id(i), start, stride, edges, tmp_Snow_QA) + allocate(tmp_MODIS_SCF(dim_sizes(1),dim_sizes(2))) + status = sfrdata(sds_id(i), start, stride, edges, tmp_MODIS_SCF) + + L=0 + do k=1,YGRID + do kk=1,XGRID + L=L+1 + SCF_raw(L) = ichar(tmp_MODIS_SCF(k,kk)) ! !?!?!?!!? ichar()??? GNU manual: ICHAR(C) returns the code for the character in the first character position of C in the system’s native character set. The correspondence between characters and their codes is not necessarily the same across different GNU Fortran implementations. + end do + + end do + + case (2) ! Clear Index - L=0 - do k=1, YGRID + allocate(tmp_CI_Index(dim_sizes(1),dim_sizes(2))) + status = sfrdata(sds_id(i), start, stride, edges, tmp_CI_Index) - do kk=1, XGRID - L = L+1 - Snow_QA(L) = ichar(tmp_Snow_QA(k, kk)) - end do !kk - - end do !k, case (4) + L=0 + do k=1,YGRID + do kk=1,XGRID + L=L+1 + CI_Index(L) = ichar(tmp_CI_index(k,kk)) + end do + + end do + + case (3) ! Cloud Index - case default + allocate(tmp_Cloud_Index(dim_sizes(1),dim_sizes(2))) + status = sfrdata(sds_id(i), start, stride, edges, tmp_Cloud_Index) + + L=0 + do k=1,YGRID + do kk=1,XGRID + L = L+1 + Cloud_Index(L) = ichar(tmp_Cloud_Index(k,kk)) + end do + + end do + + case (4) ! Snow_QA + + allocate(tmp_Snow_QA(dim_sizes(1),dim_sizes(2))) + status = sfrdata(sds_id(i), start, stride, edges, tmp_Snow_QA) - call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'Unknown case') + L=0 + do k=1,YGRID + do kk=1,XGRID + L = L+1 + Snow_QA(L) = ichar(tmp_Snow_QA(k,kk)) + end do + + end do + + case default + + call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'Unknown case') + + end select - end select - - if (dim_sizes(1)*dim_sizes(2)/=N_data_tmp(j)) then + if (dim_sizes(1)*dim_sizes(2)/=N_data_tmp(j)) then + + call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'ERROR reading hdf') + + end if - call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'ERROR reading hdf') - - end if - status = sfendacc(sds_id(i)) - - end do !i + + end do ! i=1,N_fields ! clean up + deallocate(tmp_MODIS_SCF) deallocate(tmp_CI_index) deallocate(tmp_Cloud_index) deallocate(tmp_Snow_QA) - + ! close hdf files + status = sfend(file_id(j)) - end do !j + end do ! j=1,N_files ! IF MORE THAN ONE FILE IS READ, DATA ARE OVERWRITTEN !?!?!?!?!? - time_index = date_time%hour/3 + 1 - + time_index = date_time%hour/3 + 1 ! HARDWIRED 3-HOUR TIME STEP !?!?!?!?!? + ! ------------------------------------- + ! ! eliminate no-data-values and data that fail initial QC - allocate(MODIS_SCF_tmp(N_data)) + allocate(SCF_tmp(N_data)) allocate(lat_tmp(N_data)) allocate(lon_tmp(N_data)) - j=0 - - do i=1,N_data - keep_data = & - (MODIS_SCF_raw(i)>=0 .and. MODIS_SCF_raw(i)<=100) .and. & ! any neg is nodata - (lon_1D(i)<=lon_subtime(time_index)) .and. & !selection of longitudal band - (lon_1D(i)>lon_subtime(time_index+1)) .and. & - (CI_Index(i)>qc_clear_index_threshold) .and. & - (CI_Index(i)<=qc_clear_index_max_threshold) .and. & - (Cloud_index(i)/=qc_antarctica) .and. & - (Snow_QA(i)= qc_snow_cover_min ) .and. & + ( SCF_raw(i) <= qc_snow_cover_max ) .and. & + ( lon_1D(i) <= lon_subtime(time_index) ) .and. & ! selection of longitudal band + ( lon_1D(i) > lon_subtime(time_index+1) ) .and. & + ( CI_Index(i) > qc_clear_index_min ) .and. & + ( CI_Index(i) <= qc_clear_index_max ) .and. & + ( Cloud_index(i) /= qc_antarctica ) .and. & + ( Snow_QA(i) < qc_snow_spatial_max ) + + if (keep_data) then + + j=j+1 + SCF_tmp(j) = SCF_raw(i)/CI_Index(i) ! raw SCF includes cloud cover + lon_tmp(j) = lon_1D(i) + lat_tmp(j) = lat_1D(i) + + end if - end do !i - - - !if (logit) write (logunit, *) 'number of datasets', j + end do ! i=1,N_data + N_data = j + + allocate(MODIS_lon(N_data)) + allocate(MODIS_lat(N_data)) allocate(MODIS_SCF(N_data)) - allocate(lat(N_data)) - allocate(lon(N_data)) - !if (logit) write(logunit,*) 'N_data:', N_data - lat = lat_tmp(1:j) - lon = lon_tmp(1:j) - MODIS_SCF = MODIS_SCF_tmp(1:j) + MODIS_lon = lon_tmp(1:j) + MODIS_lat = lat_tmp(1:j) + MODIS_SCF = SCF_tmp(1:j) - deallocate(lat_tmp, lon_tmp, MODIS_SCF_tmp) + deallocate(lon_tmp, lat_tmp, SCF_tmp) deallocate(CI_Index) deallocate(Cloud_Index) deallocate(Snow_QA) @@ -4893,42 +4904,44 @@ subroutine read_MODISscf_hdf( N_files, date_time, N_data, fnames, & end subroutine read_MODISscf_hdf ! ***************************************************************** - - subroutine read_obs_MODISscf( & - work_path, date_time, dtstep_assim, N_catd, tile_coord, & - tile_grid_d, N_tile_in_cell_ij, tile_num_in_cell_ij, & - this_obs_param, found_obs, MODIS_obs, std_MODIS_obs) - + + subroutine read_obs_MODISscf( & + work_path, date_time, dtstep_assim, N_catd, tile_coord, & + tile_grid_d, N_tile_in_cell_ij, tile_num_in_cell_ij, & + this_obs_param, found_obs, MODIS_obs, std_MODIS_obs ) + implicit none !inputs + character(*), intent(in) :: work_path type(date_time_type), intent(in) :: date_time integer, intent(in) :: dtstep_assim, N_catd - type(tile_coord_type), dimension(:), pointer:: tile_coord !input - + type(tile_coord_type), dimension(:), pointer:: tile_coord ! input + type(grid_def_type), intent(in) :: tile_grid_d - + integer, dimension(tile_grid_d%N_lon, tile_grid_d%N_lat), intent(in):: & N_tile_in_cell_ij - integer, dimension(:,:,:), pointer:: tile_num_in_cell_ij !input + integer, dimension(:,:,:), pointer:: tile_num_in_cell_ij ! input type(obs_param_type), intent(in) :: this_obs_param ! output - real, intent(out), dimension(N_catd):: MODIS_obs - real, intent(out), dimension(N_catd):: std_MODIS_obs - logical, intent(out) :: found_obs - logical :: file_exists + real, intent(out), dimension(N_catd) :: MODIS_obs + real, intent(out), dimension(N_catd) :: std_MODIS_obs + logical, intent(out) :: found_obs + logical :: file_exists !locals + character(2) :: MM character(4) :: YYYY - character(3) :: DDD ! Day of Year + character(3) :: DDD ! Day of Year character(300) :: tmpfname1 integer, dimension(N_catd) :: tmp_tile_id @@ -4939,40 +4952,45 @@ subroutine read_obs_MODISscf( & character(300), dimension(:), allocatable :: fnames - real, dimension(:), pointer:: tmp_lat, tmp_lon - integer, dimension(:), pointer:: tmp_tile_num - real, dimension(:), pointer:: tmp_obs + real, dimension(:), pointer :: tmp_lat, tmp_lon + integer, dimension(:), pointer :: tmp_tile_num + real, dimension(:), pointer :: tmp_obs - integer, dimension(N_catd):: N_obs_in_tile + integer, dimension(N_catd) :: N_obs_in_tile - character(len=*), parameter :: Iam = 'read_obs_MODISscf' - character(len=400) :: err_msg + character(len=*), parameter :: Iam = 'read_obs_MODISscf' + character(len=400) :: err_msg ! -------------- nullify (tmp_obs, tmp_lat, tmp_lon, tmp_tile_num) ! -------------- + ! + ! restricting the assimilation time step to *only* 3 hr - !restricting the assimilation time step to *only* 3 hr if (dtstep_assim .NE. dtstep_assim_threshold) then - err_msg = 'dtstep_assim should be equal to 3 hours' + err_msg = 'dtstep_assim must be equal to 3 hours' call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) end if - ! restricting the time stamp to only 0z 3z 6z ... - if ((mod(date_time%hour,3).NE.0) .or. (date_time%min .NE. 0)) then - - err_msg= 'assimilation timestep does not match' - call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) - + ! restricting current time to only 0z, 3z, ..., 21z + + if ( (mod(date_time%hour,3) .NE. 0) .or. & + (date_time%min .NE. 0) .or. & + (date_time%sec .NE. 0) ) then + + err_msg = 'analysis time must be 0z, 3z, ..., 21z' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + end if - + ! -------------- + ! ! Initialize - + found_obs = .false. N_tmp = 3600*7200 @@ -4980,8 +4998,7 @@ subroutine read_obs_MODISscf( & write (MM, '(i2.2)') date_time%month write (DDD, '(i3.3)') date_time%dofyr - write (logunit, *) 'Obs time: ', YYYY, MM - write (logunit, *) 'DOY: ', DDD + write (logunit,*) 'Obs time (year/month/day-of-year): ', YYYY, MM, DDD ! In the ensupd nml file, specify the file "name" according to the following template: ! @@ -5002,14 +5019,15 @@ subroutine read_obs_MODISscf( & tmpfname1 = trim(this_obs_param%path) // '/' // YYYY // '/' & // this_obs_param%name(1:9) // YYYY // DDD // this_obs_param%name(17:24) - if (logit) write (logunit, *) 'Reading data from', trim(tmpfname1) - + if (logit) write (logunit,*) 'Reading data from ', trim(tmpfname1) + inquire(file=trim(tmpfname1), exist=file_exists) - if (logit) write (logunit, *), file_exists - + + if (logit) write (logunit,*), file_exists + if (file_exists) then - N_files= 1 + N_files = 1 !?!?!?!?!?! READS NO MORE THAN ONE FILE allocate(fnames(N_files)) fnames(N_files) = tmpfname1 @@ -5017,21 +5035,17 @@ subroutine read_obs_MODISscf( & if (N_files>0) then - !if (logit) write (logunit, *) 'calling MODISscf_hdf subroutine' - call read_MODISscf_hdf(N_files, date_time, N_tmp, fnames, & tmp_lon, tmp_lat, tmp_obs) - !if (logit) write (logunit, *) 'read_obs_MODISscf: read MODIS datasets' - - deallocate(fnames) - + deallocate(fnames) + else - + N_tmp = 0 - + end if ! (N_files>0) - + if (N_tmp>0) then allocate(tmp_tile_num(N_tmp)) From bae24fac7fd0a2b268f06f95e0b44c5139e07709 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Sat, 15 Jul 2023 17:58:06 -0400 Subject: [PATCH 110/308] fixed build error in previous commit; additional minor cleanup (clsm_ensupd_read_obs.F90) --- .../clsm_ensupd_read_obs.F90 | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 24951ae8..bcf49945 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -4661,7 +4661,7 @@ subroutine read_MODISscf_hdf( N_files, date_time, N_data, fnames, & integer :: start(2), edges(2), stride(2) character(100) :: var_name - integer :: status, n_read, record_pos + integer :: status integer, parameter :: DFACC_READ = 1 ! from hdf.inc integer, parameter :: DFNT_UINT8 = 21 @@ -4899,22 +4899,21 @@ subroutine read_MODISscf_hdf( N_files, date_time, N_data, fnames, & deallocate(CI_Index) deallocate(Cloud_Index) deallocate(Snow_QA) - deallocate(MODIS_SCf_raw) + deallocate(SCF_raw) end subroutine read_MODISscf_hdf ! ***************************************************************** subroutine read_obs_MODISscf( & - work_path, date_time, dtstep_assim, N_catd, tile_coord, & + date_time, dtstep_assim, N_catd, tile_coord, & tile_grid_d, N_tile_in_cell_ij, tile_num_in_cell_ij, & this_obs_param, found_obs, MODIS_obs, std_MODIS_obs ) implicit none - !inputs + ! inputs - character(*), intent(in) :: work_path type(date_time_type), intent(in) :: date_time integer, intent(in) :: dtstep_assim, N_catd @@ -4944,9 +4943,7 @@ subroutine read_obs_MODISscf( & character(3) :: DDD ! Day of Year character(300) :: tmpfname1 - integer, dimension(N_catd) :: tmp_tile_id - - integer :: i, ind, N_files, N_tmp + integer :: i, ind, N_files, N_tmp integer, parameter :: dtstep_assim_threshold = 10800 ! restricting dtstep_assim to 3 hours @@ -7740,7 +7737,7 @@ subroutine read_obs( & case ('MODIS_SCF') call read_obs_MODISscf( & - work_path, date_time, dtstep_assim, N_catd, tile_coord, & + date_time, dtstep_assim, N_catd, tile_coord, & tile_grid_d, N_tile_in_cell_ij, tile_num_in_cell_ij, & this_obs_param, found_obs, tmp_obs, tmp_std_obs) From 33cf274de013a6b2a9b46e2b6d5aa4e9f4a516fd Mon Sep 17 00:00:00 2001 From: amfox37 Date: Thu, 20 Jul 2023 13:41:35 -0600 Subject: [PATCH 111/308] read all subsets to memory before qc --- .../clsm_ensupd_read_obs.F90 | 144 +++++++++--------- 1 file changed, 70 insertions(+), 74 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 5c2340f2..7df0b2b5 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -1628,14 +1628,15 @@ subroutine read_obs_sm_ASCAT_EUMET( & type(date_time_type) :: date_time_low, date_time_low_fname type(date_time_type) :: date_time_up - integer :: i, ind, N_tmp, N_files, kk + integer :: i, ind, N_tmp, N_files, kk, N_obs integer :: N_fnames, N_fnames_tmp character(300), dimension(:), allocatable :: fnames, tmpfnames - real(8) :: tmp_data(7), tmp_vdata(4), tmp_time(6) + real*8, dimension(15) :: tmp_vdata integer, parameter :: lnbufr = 50 - integer, parameter :: max_rec = 20000 + integer, parameter :: max_rec = 20000 + integer, parameter :: max_obs = 250000 integer :: idate,iret integer :: ireadmg,ireadsb character(8) :: subset @@ -1644,6 +1645,7 @@ subroutine read_obs_sm_ASCAT_EUMET( & real, dimension(:), allocatable :: tmp1_lon, tmp1_lat, tmp1_obs real*8, dimension(:), allocatable :: tmp1_jtime + real*8, dimension(:,:), allocatable :: tmp_data real, dimension(:), pointer :: tmp_obs, tmp_lat, tmp_lon real*8, dimension(:), pointer :: tmp_jtime @@ -1729,7 +1731,7 @@ subroutine read_obs_sm_ASCAT_EUMET( & tmpfnames(N_tmp) = trim(this_obs_param%path) // '/' // trim(tmpfname2) end if end do - + fnames = tmpfnames(1:N_tmp) N_files = N_tmp @@ -1741,85 +1743,27 @@ subroutine read_obs_sm_ASCAT_EUMET( & allocate(tmp1_lat(max_rec)) allocate(tmp1_obs(max_rec)) allocate(tmp1_jtime(max_rec)) + + allocate(tmp_data(max_obs, 15)) - call MTINFO( trim(this_obs_param%path) // '/BUFR_mastertable/', 51, 52) ! file loop - N_tmp = 0 - do kk = 1,N_files + N_obs = 0 + do kk = 1,N_files + ! open on bufr file call closbf(lnbufr) open(lnbufr, file=trim(fnames(kk)), action='read',form='unformatted') call openbf(lnbufr,'SEC3', lnbufr) - call MTINFO( trim(this_obs_param%path) // '/BUFR_mastertable/', 51, 52) + call mtinfo( trim(this_obs_param%path) // '/BUFR_mastertable/', 51, 52) call datelen(10) msg_report: do while(ireadmg(lnbufr,subset,idate) ==0) - loop_report: do while(ireadsb(lnbufr) == 0) - ! extract sensing time information - call ufbint(lnbufr,tmp_time,6,1,iret,'YEAR MNTH DAYS HOUR MINU SECO') - date_time_tmp.year = int(tmp_time(1)) - date_time_tmp.month = int(tmp_time(2)) - date_time_tmp.day = int(tmp_time(3)) - date_time_tmp.hour = int(tmp_time(4)) - date_time_tmp.min = int(tmp_time(5)) - date_time_tmp.sec = int(tmp_time(6)) - - ! skip if record outside of current assim window - if ( datetime_lt_refdatetime( date_time_tmp, date_time_low ) .and. & - datetime_le_refdatetime( date_time_up, date_time_tmp )) cycle loop_report - - - call ufbint(lnbufr,tmp_data,7,1,iret,'SSOM DOMO SMPF SMCF ALFR TPCX IWFR') - - - ! skip if record contain no valid soil moisture value -! call ufbint(lnbufr,tmp_data,1,1,iret,'SSOM') - if(tmp_data(1) > 100. .or. tmp_data(1) < 0.) cycle loop_report - - ! EUMETSAT file contains data of both ascending and descending orbits. - ! DOMO - “Direction of motion of moving observing platform” is used to seperate Asc and Desc - ! because the file doesn't contain any explicit orbit indicator variable. - ! according to Pamela Schoebel-Pattiselanno, EUMETSAT User Services Helpdesk - ! "When the value (of DOMO) is between 180 and 270 degrees, it is the descending part - ! of the orbit … when it is between 270 and 360 degrees, it is the ascending part" -! call ufbint(lnbufr,tmp_data,1,1,iret,'DOMO') - if (index(this_obs_param%descr,'_A') /=0 .and. (tmp_data(2) < 270 .or. tmp_data(2) > 360)) cycle loop_report - if (index(this_obs_param%descr,'_D') /=0 .and. (tmp_data(2) < 180 .or. tmp_data(2) >= 270)) cycle loop_report - - ! skip if processing flag is set -! call ufbint(lnbufr,tmp_data,1,1,iret,'SMPF') - if(int(tmp_data(3)) /= 0) cycle loop_report - - ! skip if correction flag is set -! call ufbint(lnbufr,tmp_data,1,1,iret,'SMCF') - if (.not. (int(tmp_data(4)) == 0 .or. int(tmp_data(4)) == 4)) cycle loop_report - ! if(int(tmp_data) /= 0) cycle loop_report - - ! skip if land fraction is missing or < 0.9 -! call ufbint(lnbufr,tmp_data,1,1,iret,'ALFR') - if(tmp_data(5) >1 .or. tmp_data(5) < 0.9 ) cycle loop_report - - ! additioanal QC varibles from file - ! skip if topographic complexity > 10% -! call ufbint(lnbufr,tmp_data,1,1,iret,'TPCX') ! topo complexity - if(tmp_data(6) > 10.) cycle loop_report - - ! skip if inudatation and wetland faction > 10% -! call ufbint(lnbufr,tmp_data,1,1,iret,'IWFR') ! Inundation And Wetland Fraction - if(tmp_data(7) > 10.) cycle loop_report - !call ufbint(lnbufr,tmp_data,1,1,iret,'SNOC') ! snow cover - !call ufbint(lnbufr,tmp_data,1,1,iret,'FLSF') ! frozen land fraction - - N_tmp = N_tmp + 1 ! Passed all QC + loop_report: do while(ireadsb(lnbufr) == 0) - tmp1_jtime(N_tmp) = datetime_to_J2000seconds( date_time_tmp, J2000_epoch_id ) - - call ufbint(lnbufr,tmp_vdata,4,1,iret,'CLATH CLONH SSOM EESSM') - tmp1_lat(N_tmp) = tmp_vdata(1) - tmp1_lon(N_tmp) = tmp_vdata(2) - tmp1_obs(N_tmp) = tmp_vdata(3)/100. ! change value from 0-100 to 0-1 - !tmp_obserr(N_tmp) = tmp_vdata(4) + call ufbint(lnbufr,tmp_vdata,15,1,iret,'YEAR MNTH DAYS HOUR MINU SECO SSOM DOMO SMPF SMCF ALFR TPCX IWFR CLATH CLONH') + N_obs = N_obs + 1 + tmp_data(N_obs,:) = tmp_vdata end do loop_report @@ -1830,6 +1774,58 @@ subroutine read_obs_sm_ASCAT_EUMET( & end do ! end file loop + N_tmp = 0 + + do kk = 1,N_obs + + date_time_tmp%year = int(tmp_data(kk, 1)) + date_time_tmp%month = int(tmp_data(kk, 2)) + date_time_tmp%day = int(tmp_data(kk, 3)) + date_time_tmp%hour = int(tmp_data(kk, 4)) + date_time_tmp%min = int(tmp_data(kk, 5)) + date_time_tmp%sec = int(tmp_data(kk, 6)) + + ! skip if record outside of current assim window + if ( datetime_lt_refdatetime( date_time_tmp, date_time_low ) .and. & + datetime_le_refdatetime( date_time_up, date_time_tmp )) cycle + + ! skip if record contain no valid soil moisture value + if(tmp_data(kk, 7) > 100. .or. tmp_data(kk, 7) < 0.) cycle + + ! EUMETSAT file contains data of both ascending and descending orbits. + ! DOMO - “Direction of motion of moving observing platform” is used to seperate Asc and Desc + ! because the file doesn't contain any explicit orbit indicator variable. + ! according to Pamela Schoebel-Pattiselanno, EUMETSAT User Services Helpdesk + ! "When the value (of DOMO) is between 180 and 270 degrees, it is the descending part + ! of the orbit … when it is between 270 and 360 degrees, it is the ascending part" + if (index(this_obs_param%descr,'_A') /=0 .and. (tmp_data(kk, 8) < 270 .or. tmp_data(kk, 8) > 360)) cycle + if (index(this_obs_param%descr,'_D') /=0 .and. (tmp_data(kk, 8) < 180 .or. tmp_data(kk, 8) >= 270)) cycle + + ! skip if processing flag is set + if(int(tmp_data(kk, 9)) /= 0) cycle + + ! skip if correction flag is set + if (.not. (int(tmp_data(kk, 10)) == 0 .or. int(tmp_data(kk, 10)) == 4)) cycle + + ! skip if land fraction is missing or < 0.9 + if(tmp_data(kk, 11) >1 .or. tmp_data(kk, 11) < 0.9 ) cycle + + ! skip if topographic complexity > 10% + if(tmp_data(kk, 12) > 10.) cycle + + ! skip if inudatation and wetland faction > 10% + if(tmp_data(kk, 13) > 10.) cycle + + N_tmp = N_tmp + 1 ! Passed all QC + + tmp1_jtime(N_tmp) = datetime_to_J2000seconds( date_time_tmp, J2000_epoch_id ) + + tmp1_lat(N_tmp) = tmp_data(kk, 14) + tmp1_lon(N_tmp) = tmp_data(kk, 15) + tmp1_obs(N_tmp) = tmp_data(kk, 7)/100. ! change value from 0-100 to 0-1 + + end do + if (logit) then write (logunit,*) 'read_obs_sm_ASCAT_EUMET: read ', N_tmp, & @@ -1857,7 +1853,8 @@ subroutine read_obs_sm_ASCAT_EUMET( & deallocate(tmp1_jtime) deallocate(tmp1_lon) deallocate(tmp1_lat) - deallocate(tmp1_obs) + deallocate(tmp1_obs) + deallocate(tmp_data) else N_tmp = 0 @@ -9392,4 +9389,3 @@ end program test ! ******* EOF ************************************************************* - From a6e3341267d1438241363514de4aae2c04aaacbb Mon Sep 17 00:00:00 2001 From: amfox37 Date: Thu, 27 Jul 2023 11:13:04 -0600 Subject: [PATCH 112/308] new update_type --- .../clsm_ensupd_upd_routines.F90 | 180 +++++++++++++++++- 1 file changed, 179 insertions(+), 1 deletion(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index 603c5768..af132f0a 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -3426,7 +3426,7 @@ subroutine cat_enkf_increments( & integer :: n, n_e, kk, ii - integer :: N_state_max, N_state, N_selected_obs, N_select_varnames, N_select_species + integer :: N_state_max, N_state, N_selected_obs, N_select_varnames, N_select_species, N_varnames real :: halo_minlon, halo_maxlon, halo_minlat, halo_maxlat real :: tmp_minlon, tmp_maxlon, tmp_minlat, tmp_maxlat @@ -3496,6 +3496,7 @@ subroutine cat_enkf_increments( & N_select_varnames = 0 N_select_species = 0 + N_varnames = 0 select_varnames = '' select_species = -8888 ! intentionally differs from init in get_select_species() @@ -4405,6 +4406,183 @@ subroutine cat_enkf_increments( & end do ! ---------------------------------- + + case (13) select_update_type ! All observation types from obs_param + + ! update each tile separately using all observations within customized halo around each tile + ! + ! amfox, 27 July 2023 + + if (logit) write (logunit,*) 'Get increments for all observation types in obs_param' + + N_select_varnames = 1 + + if (any(obs_param%varname == 'Tb')) then + N_varnames = N_varnames + 1 + select_varnames(N_varnames) = 'Tb' + end if + + if (any(obs_param%varname == 'sfds')) then + N_varnames = N_varnames + 1 + select_varnames(N_varnames) = 'sfds' + end if + + do ii = 1,N_varnames + + call get_select_species( & + N_select_varnames, select_varnames(ii), & + N_obs_param, obs_param, N_select_species, select_species ) + + if (select_varnames(ii)=='Tb') then + N_state_max = 7 + elseif (select_varnames(ii)=='sfds') then + N_state_max = 3 + N_state = 3 + else + err_msg = 'Dont know what state to use with this observation type.' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + end if + + allocate( State_incr(N_state_max,N_ens)) + allocate( State_lon( N_state_max )) + allocate( State_lat( N_state_max )) + + do kk=1,N_catd + + ! compute increments only snow-free and non-frozen tiles + + if ( (SWE_ensavg(kk) < SWE_threshold) .and. & + (tp1_ensavg(kk) > tp1_threshold) ) then + + ! find observations within halo around tile kk + + halo_minlon = tile_coord(kk)%com_lon - xcompact + halo_maxlon = tile_coord(kk)%com_lon + xcompact + halo_minlat = tile_coord(kk)%com_lat - ycompact + halo_maxlat = tile_coord(kk)%com_lat + ycompact + + ! simple approach to dateline issue (cut halo back to at most -180:180, -90:90) + ! - reichle, 28 May 2013 + + halo_minlon = max(halo_minlon,-180.) + halo_maxlon = min(halo_maxlon, 180.) + halo_minlat = max(halo_minlat, -90.) + halo_maxlat = min(halo_maxlat, 90.) + + call get_ind_obs_lat_lon_box( & + N_obs, Observations, & + halo_minlon, halo_maxlon, halo_minlat, halo_maxlat, & + N_select_species, select_species(1:N_select_species), & + N_selected_obs, ind_obs ) + + if (N_selected_obs>0) then + + if (N_state_max==7 .and. cat_param(kk)%poros>=PEATCLSM_POROS_THRESHOLD) then + + N_state = 7 ! srfexc, rzexc, catdef, tc1, tc2, tc4, ght1 + + elseif (N_state_max==7 .and. cat_param(kk)%poros= Date: Thu, 27 Jul 2023 13:32:33 -0400 Subject: [PATCH 113/308] fix if then --- .../GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index af132f0a..6f0e4796 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -4477,11 +4477,11 @@ subroutine cat_enkf_increments( & if (N_selected_obs>0) then - if (N_state_max==7 .and. cat_param(kk)%poros>=PEATCLSM_POROS_THRESHOLD) then + if ((N_state_max==7 .and. cat_param(kk)%poros>=PEATCLSM_POROS_THRESHOLD)) then N_state = 7 ! srfexc, rzexc, catdef, tc1, tc2, tc4, ght1 - elseif (N_state_max==7 .and. cat_param(kk)%poros= Date: Thu, 27 Jul 2023 11:56:24 -0600 Subject: [PATCH 114/308] apply ASCAT _OR_ SMAP increment --- .../clsm_ensupd_enkf_update.F90 | 5 +- .../clsm_ensupd_upd_routines.F90 | 52 +++++++------------ 2 files changed, 23 insertions(+), 34 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 index 86d6449d..b49fc5e3 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 @@ -1337,9 +1337,10 @@ subroutine apply_enkf_increments( N_catd, N_ens, update_type, & cat_progn_has_changed = .false. - case (6,8,9,10) select_update_type ! soil moisture and temperature update + case (6,8,9,10,13) select_update_type ! soil moisture and temperature update - ! for update_type 10, catdef increments may be zero by design + ! for update_type 10, catdef increments may be zero by design + ! for updagte_type 13, could be multiple zero increments if (logit) write (logunit,*) & 'apply_enkf_increments(): applying soil moisture and Tskin/ght1 increments' diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index 6f0e4796..2f668050 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -4416,6 +4416,11 @@ subroutine cat_enkf_increments( & if (logit) write (logunit,*) 'Get increments for all observation types in obs_param' N_select_varnames = 1 + N_state_max = 7 ! Needs to be constant size for applying increment, potential for lots of zeros + + allocate( State_incr(N_state_max,N_ens)) + allocate( State_lon( N_state_max )) + allocate( State_lat( N_state_max )) if (any(obs_param%varname == 'Tb')) then N_varnames = N_varnames + 1 @@ -4432,21 +4437,7 @@ subroutine cat_enkf_increments( & call get_select_species( & N_select_varnames, select_varnames(ii), & N_obs_param, obs_param, N_select_species, select_species ) - - if (select_varnames(ii)=='Tb') then - N_state_max = 7 - elseif (select_varnames(ii)=='sfds') then - N_state_max = 3 - N_state = 3 - else - err_msg = 'Dont know what state to use with this observation type.' - call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) - end if - - allocate( State_incr(N_state_max,N_ens)) - allocate( State_lon( N_state_max )) - allocate( State_lat( N_state_max )) - + do kk=1,N_catd ! compute increments only snow-free and non-frozen tiles @@ -4476,17 +4467,18 @@ subroutine cat_enkf_increments( & N_selected_obs, ind_obs ) if (N_selected_obs>0) then - - if ((N_state_max==7 .and. cat_param(kk)%poros>=PEATCLSM_POROS_THRESHOLD)) then - - N_state = 7 ! srfexc, rzexc, catdef, tc1, tc2, tc4, ght1 - - elseif ((N_state_max==7 .and. cat_param(kk)%poros=PEATCLSM_POROS_THRESHOLD) then + N_state = 7 + elseif (select_varnames(ii)=='Tb' .and. cat_param(kk)%poros Date: Fri, 11 Aug 2023 13:43:28 -0400 Subject: [PATCH 115/308] fix check_compact_support --- .../GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index 2f668050..d480a48b 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -5142,7 +5142,7 @@ subroutine check_compact_support( & Iam // '(): reset for 1d update_type: ycompact = ', ycompact if (logit) write (logunit,*) - case (2,7,8,10) ! "3d" updates, check consistency of xcompact, ycompact + case (2,7,8,10, 13) ! "3d" updates, check consistency of xcompact, ycompact ! check xcompact/ycompact against corr scales of model error From 6e079f87060592c02749725681986a1543e90b52 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Thu, 17 Aug 2023 18:50:11 -0400 Subject: [PATCH 116/308] test read decode_ASCAT_ssom.x --- src/Applications/LDAS_App/CMakeLists.txt | 5 ++ .../LDAS_App/decode_ASCAT_ssom.F90 | 47 +++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 src/Applications/LDAS_App/decode_ASCAT_ssom.F90 diff --git a/src/Applications/LDAS_App/CMakeLists.txt b/src/Applications/LDAS_App/CMakeLists.txt index f2f5ed36..99d5028e 100644 --- a/src/Applications/LDAS_App/CMakeLists.txt +++ b/src/Applications/LDAS_App/CMakeLists.txt @@ -18,6 +18,11 @@ ecbuild_add_executable ( TARGET mwrtm_bin2nc4.x SOURCES util/inputs/mwRTM_params/mwrtm_bin2nc4.F90 LIBS GEOSlandassim_GridComp) + +ecbuild_add_executable ( + TARGET decode_ASCAT_ssom.x + SOURCES decode_ASCAT_ssom.F90 + LIBS NCEP_bufr_r4i4) set (scripts ldas_setup diff --git a/src/Applications/LDAS_App/decode_ASCAT_ssom.F90 b/src/Applications/LDAS_App/decode_ASCAT_ssom.F90 new file mode 100644 index 00000000..64d43ad5 --- /dev/null +++ b/src/Applications/LDAS_App/decode_ASCAT_ssom.F90 @@ -0,0 +1,47 @@ +program decode_ASCAT_ssom + + implicit none + + real*8, dimension(15) :: tmp_vdata + real*8, dimension(:,:), allocatable :: tmp_data + + integer, parameter :: lnbufr = 50 + integer, parameter :: max_obs = 250000 + integer :: idate,iret + integer :: ireadmg,ireadsb + integer :: N_obs + + character(8) :: subset + character(300) :: fname, mastertable_path + +! ------------------------------------------------------------------------- + + fname = '/home/amfox/smap/SMAP_Nature/ASCAT_EUMETSAT/Metop_C/Y2023/M03/' // & + 'M03-ASCA-ASCSMO02-NA-5.0-20230301090900.000000000Z-20230301105557-4839070.bfr' + mastertable_path = '/home/amfox/smap/SMAP_Nature/ASCAT_EUMETSAT' + +! Allocate the tmp_data array + allocate(tmp_data(max_obs, 15)) + + open(lnbufr, file=trim(fname), action='read',form='unformatted') + + call openbf(lnbufr,'SEC3', lnbufr) + call mtinfo( trim(mastertable_path) // '/BUFR_mastertable/', 51, 52) + call datelen(10) + + N_obs = 0 + msg_report: do while(ireadmg(lnbufr,subset,idate) ==0) + loop_report: do while(ireadsb(lnbufr) == 0) + call ufbint(lnbufr,tmp_vdata,15,1,iret,'YEAR MNTH DAYS HOUR MINU SECO SSOM DOMO SMPF SMCF ALFR TPCX IWFR CLATH CLONH') + N_obs = N_obs + 1 + tmp_data(N_obs,:) = tmp_vdata + end do loop_report + end do msg_report + + write(*,*) 'N_obs = ', N_obs + write(*,*) tmp_vdata + + call closbf(lnbufr) + close(lnbufr) + +end program decode_ASCAT_ssom From 42972eed5eedfe65a5ecb07905427f13700afb62 Mon Sep 17 00:00:00 2001 From: "Lauren C. Andrews" Date: Fri, 25 Aug 2023 13:54:21 -0400 Subject: [PATCH 117/308] fix to clsm_ensup_read_obs for modis file name --- components.yaml | 2 +- .../GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/components.yaml b/components.yaml index 5ca4fecb..ccf1521c 100644 --- a/components.yaml +++ b/components.yaml @@ -41,6 +41,6 @@ MAPL: GEOSgcm_GridComp: local: ./src/Components/GEOSldas_GridComp/@GEOSgcm_GridComp remote: ../GEOSgcm_GridComp.git - branch: develop + branch: feature/lcandre2/newsnowexports sparse: ./config/GEOSgcm_GridComp_ldas.sparse develop: develop diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index bcf49945..05be518d 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -4739,8 +4739,8 @@ subroutine read_MODISscf_hdf( N_files, date_time, N_data, fnames, & do j=1,N_files - ! open and start "hdf file" - + ! open and start "hdf file" + sd_id(j) = sfstart(fnames(j), DFACC_READ) !if (logit) write (logunit,*), 'sd_id:' , sd_id(j) @@ -5013,9 +5013,12 @@ subroutine read_obs_MODISscf( & ! Assuming the MODIS file naming convention remains unchanged, the version can then ! be specified in the nml file. - tmpfname1 = trim(this_obs_param%path) // '/' // YYYY // '/' & - // this_obs_param%name(1:9) // YYYY // DDD // this_obs_param%name(17:24) + !tmpfname1 = trim(this_obs_param%path) // '/' // YYYY // '/' & + ! // this_obs_param%name(1:9) // YYYY // DDD // this_obs_param%name(17:24) + tmpfname1 = trim(this_obs_param%path) // YYYY // '/MOD10C1.A' // YYYY // DDD // & + '.061.hdf' !note the MODIS data version included here + if (logit) write (logunit,*) 'Reading data from ', trim(tmpfname1) inquire(file=trim(tmpfname1), exist=file_exists) From f26332c31f44d36c62a4e06639e5ed7ae4b82704 Mon Sep 17 00:00:00 2001 From: Rolf Reichle <54944691+gmao-rreichle@users.noreply.github.com> Date: Fri, 25 Aug 2023 14:06:54 -0400 Subject: [PATCH 118/308] minor fix to MODISscf obs file name (clsm_ensupd_read_obs.F90) Added '/' after path and before YYYY dir so path does not have to be specified without trailing '/' This has no effect if the path does include the trailing '/' --- .../GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 05be518d..f536f263 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -5016,7 +5016,7 @@ subroutine read_obs_MODISscf( & !tmpfname1 = trim(this_obs_param%path) // '/' // YYYY // '/' & ! // this_obs_param%name(1:9) // YYYY // DDD // this_obs_param%name(17:24) - tmpfname1 = trim(this_obs_param%path) // YYYY // '/MOD10C1.A' // YYYY // DDD // & + tmpfname1 = trim(this_obs_param%path) // '/' // YYYY // '/MOD10C1.A' // YYYY // DDD // & '.061.hdf' !note the MODIS data version included here if (logit) write (logunit,*) 'Reading data from ', trim(tmpfname1) From ef970abb705e008ef636f4296f155432d86dd8a7 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Wed, 13 Sep 2023 17:24:22 -0600 Subject: [PATCH 119/308] added State_incr_cum --- .../clsm_ensupd_upd_routines.F90 | 104 ++++++++++-------- 1 file changed, 59 insertions(+), 45 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index d480a48b..f3a27971 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -3438,7 +3438,7 @@ subroutine cat_enkf_increments( & integer, dimension(N_obs) :: ind_obs - real, allocatable, dimension(:,:) :: State_incr + real, allocatable, dimension(:,:) :: State_incr, State_incr_cum real, allocatable, dimension(:,:) :: Obs_cov ! measurement error covariance real, allocatable, dimension(:) :: State_lon, State_lat @@ -3474,6 +3474,8 @@ subroutine cat_enkf_increments( & real, dimension( N_catd) :: tp1_ensavg type(obs_param_type) :: this_obs_param + + logical :: nonZeroFound ! ----------------------------------------------------------------------- @@ -4418,7 +4420,8 @@ subroutine cat_enkf_increments( & N_select_varnames = 1 N_state_max = 7 ! Needs to be constant size for applying increment, potential for lots of zeros - allocate( State_incr(N_state_max,N_ens)) + allocate( State_incr(N_state_max,N_ens)) + allocate( State_incr_cum(N_state_max,N_ens)) allocate( State_lon( N_state_max )) allocate( State_lat( N_state_max )) @@ -4432,14 +4435,16 @@ subroutine cat_enkf_increments( & select_varnames(N_varnames) = 'sfds' end if - do ii = 1,N_varnames + do kk=1,N_catd - call get_select_species( & - N_select_varnames, select_varnames(ii), & - N_obs_param, obs_param, N_select_species, select_species ) - - do kk=1,N_catd - + State_incr_cum = 0.0 + + do ii = 1,N_varnames + + call get_select_species( & + N_select_varnames, select_varnames(ii), & + N_obs_param, obs_param, N_select_species, select_species ) + ! compute increments only snow-free and non-frozen tiles if ( (SWE_ensavg(kk) < SWE_threshold) .and. & @@ -4460,7 +4465,7 @@ subroutine cat_enkf_increments( & halo_minlat = max(halo_minlat, -90.) halo_maxlat = min(halo_maxlat, 90.) - call get_ind_obs_lat_lon_box( & + call get_ind_obs_lat_lon_box( & N_obs, Observations, & halo_minlon, halo_maxlon, halo_minlat, halo_maxlat, & N_select_species, select_species(1:N_select_species), & @@ -4484,34 +4489,34 @@ subroutine cat_enkf_increments( & if (N_state==3) then - State_incr(1,:) = cat_progn( kk,:)%srfexc/scale_srfexc - State_incr(2,:) = cat_progn( kk,:)%rzexc /scale_rzexc - State_incr(3,:) = cat_progn( kk,:)%catdef/scale_catdef + State_incr(1,:) = (cat_progn( kk,:)%srfexc/scale_srfexc) + State_incr_cum(1,:) + State_incr(2,:) = (cat_progn( kk,:)%rzexc /scale_rzexc) + State_incr_cum(2,:) + State_incr(3,:) = (cat_progn( kk,:)%catdef/scale_catdef) + State_incr_cum(3,:) elseif ( N_state==7 ) then - State_incr(1,:) = cat_progn( kk,:)%srfexc/scale_srfexc - State_incr(2,:) = cat_progn( kk,:)%rzexc /scale_rzexc - State_incr(3,:) = cat_progn( kk,:)%catdef/scale_catdef ! catdef in State - State_incr(4,:) = cat_progn( kk,:)%tc1 /scale_temp - State_incr(5,:) = cat_progn( kk,:)%tc2 /scale_temp - State_incr(6,:) = cat_progn( kk,:)%tc4 /scale_temp - State_incr(7,:) = cat_progn( kk,:)%ght(1)/scale_ght1 + State_incr(1,:) = (cat_progn( kk,:)%srfexc/scale_srfexc) + State_incr_cum(1,:) + State_incr(2,:) = (cat_progn( kk,:)%rzexc /scale_rzexc) + State_incr_cum(2,:) + State_incr(3,:) = (cat_progn( kk,:)%catdef/scale_catdef) + State_incr_cum(3,:) ! catdef in State + State_incr(4,:) = (cat_progn( kk,:)%tc1 /scale_temp) + State_incr_cum(4,:) + State_incr(5,:) = (cat_progn( kk,:)%tc2 /scale_temp) + State_incr_cum(5,:) + State_incr(6,:) = (cat_progn( kk,:)%tc4 /scale_temp) + State_incr_cum(6,:) + State_incr(7,:) = (cat_progn( kk,:)%ght(1)/scale_ght1) + State_incr_cum(7,:) else ! N_state == 6 - State_incr(1,:) = cat_progn( kk,:)%srfexc/scale_srfexc - State_incr(2,:) = cat_progn( kk,:)%rzexc /scale_rzexc - State_incr(3,:) = cat_progn( kk,:)%tc1 /scale_temp - State_incr(4,:) = cat_progn( kk,:)%tc2 /scale_temp - State_incr(5,:) = cat_progn( kk,:)%tc4 /scale_temp - State_incr(6,:) = cat_progn( kk,:)%ght(1)/scale_ght1 + State_incr(1,:) = (cat_progn( kk,:)%srfexc/scale_srfexc) + State_incr_cum(1,:) + State_incr(2,:) = (cat_progn( kk,:)%rzexc /scale_rzexc) + State_incr_cum(2,:) + State_incr(3,:) = (cat_progn( kk,:)%tc1 /scale_temp) + State_incr_cum(3,:) + State_incr(4,:) = (cat_progn( kk,:)%tc2 /scale_temp) + State_incr_cum(4,:) + State_incr(5,:) = (cat_progn( kk,:)%tc4 /scale_temp) + State_incr_cum(5,:) + State_incr(6,:) = (cat_progn( kk,:)%ght(1)/scale_ght1) + State_incr_cum(6,:) end if State_lon( :) = tile_coord(kk )%com_lon State_lat( :) = tile_coord(kk )%com_lat - + allocate(Obs_cov(N_selected_obs,N_selected_obs)) call assemble_obs_cov( N_selected_obs, N_obs_param, obs_param, & @@ -4532,33 +4537,41 @@ subroutine cat_enkf_increments( & fcsterr_inflation_fac ) deallocate(Obs_cov) + + State_incr_cum(1:N_state,:) = State_incr_cum(1:N_state,:) + State_incr(1:N_state,:) + + nonZeroFound = ANY(cat_progn_incr(kk,:)%srfexc /= 0.0) + if (nonZeroFound) then + write (logunit,*) "Non-zero values found. ii = ", ii, & + " kk = ", kk, "State_lon = ", State_lon(1), "State_lat = ", State_lat(1) + end if ! assemble cat_progn increments if (N_state==3) then - cat_progn_incr(kk,:)%srfexc = State_incr(1,:)*scale_srfexc - cat_progn_incr(kk,:)%rzexc = State_incr(2,:)*scale_rzexc - cat_progn_incr(kk,:)%catdef = State_incr(3,:)*scale_catdef + cat_progn_incr(kk,:)%srfexc = State_incr_cum(1,:)*scale_srfexc + cat_progn_incr(kk,:)%rzexc = State_incr_cum(2,:)*scale_rzexc + cat_progn_incr(kk,:)%catdef = State_incr_cum(3,:)*scale_catdef elseif (N_state==7) then - cat_progn_incr(kk,:)%srfexc = State_incr(1,:)*scale_srfexc - cat_progn_incr(kk,:)%rzexc = State_incr(2,:)*scale_rzexc - cat_progn_incr(kk,:)%catdef = State_incr(3,:)*scale_catdef ! catdef in State - cat_progn_incr(kk,:)%tc1 = State_incr(4,:)*scale_temp - cat_progn_incr(kk,:)%tc2 = State_incr(5,:)*scale_temp - cat_progn_incr(kk,:)%tc4 = State_incr(6,:)*scale_temp - cat_progn_incr(kk,:)%ght(1) = State_incr(7,:)*scale_ght1 + cat_progn_incr(kk,:)%srfexc = State_incr_cum(1,:)*scale_srfexc + cat_progn_incr(kk,:)%rzexc = State_incr_cum(2,:)*scale_rzexc + cat_progn_incr(kk,:)%catdef = State_incr_cum(3,:)*scale_catdef ! catdef in State + cat_progn_incr(kk,:)%tc1 = State_incr_cum(4,:)*scale_temp + cat_progn_incr(kk,:)%tc2 = State_incr_cum(5,:)*scale_temp + cat_progn_incr(kk,:)%tc4 = State_incr_cum(6,:)*scale_temp + cat_progn_incr(kk,:)%ght(1) = State_incr_cum(7,:)*scale_ght1 else - cat_progn_incr(kk,:)%srfexc = State_incr(1,:)*scale_srfexc - cat_progn_incr(kk,:)%rzexc = State_incr(2,:)*scale_rzexc - cat_progn_incr(kk,:)%tc1 = State_incr(3,:)*scale_temp - cat_progn_incr(kk,:)%tc2 = State_incr(4,:)*scale_temp - cat_progn_incr(kk,:)%tc4 = State_incr(5,:)*scale_temp - cat_progn_incr(kk,:)%ght(1) = State_incr(6,:)*scale_ght1 + cat_progn_incr(kk,:)%srfexc = State_incr_cum(1,:)*scale_srfexc + cat_progn_incr(kk,:)%rzexc = State_incr_cum(2,:)*scale_rzexc + cat_progn_incr(kk,:)%tc1 = State_incr_cum(3,:)*scale_temp + cat_progn_incr(kk,:)%tc2 = State_incr_cum(4,:)*scale_temp + cat_progn_incr(kk,:)%tc4 = State_incr_cum(5,:)*scale_temp + cat_progn_incr(kk,:)%ght(1) = State_incr_cum(6,:)*scale_ght1 end if @@ -4566,9 +4579,9 @@ subroutine cat_enkf_increments( & end if ! thresholds - end do + end do ! varnames - end do !var_names + end do ! N_catd ! ---------------------------------- @@ -4581,6 +4594,7 @@ subroutine cat_enkf_increments( & ! clean up if (allocated( State_incr )) deallocate( State_incr ) + if (allocated( State_incr_cum )) deallocate( State_incr_cum ) if (allocated( State_lon )) deallocate( State_lon ) if (allocated( State_lat )) deallocate( State_lat ) if (allocated( select_tilenum )) deallocate( select_tilenum ) From 1747641ce9845d50e898c89c56288abf2c4b3670 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Tue, 19 Sep 2023 12:01:35 -0400 Subject: [PATCH 120/308] fixed LONG_NAME for longwave variables (GEOS_MetforceGridComp.F90, tile_bin2nc4.F90) --- src/Applications/LDAS_App/tile_bin2nc4.F90 | 8 ++++---- .../GEOSmetforce_GridComp/GEOS_MetforceGridComp.F90 | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Applications/LDAS_App/tile_bin2nc4.F90 b/src/Applications/LDAS_App/tile_bin2nc4.F90 index e50a9eb5..3f2aef3b 100644 --- a/src/Applications/LDAS_App/tile_bin2nc4.F90 +++ b/src/Applications/LDAS_App/tile_bin2nc4.F90 @@ -227,7 +227,7 @@ FUNCTION getAttribute (SHORT_NAME, LNAME, UNT) result (str_atr) case ('net_downward_shortwave_flux'); LONG_NAME = 'Net_shortwave_land'; UNITS = 'W m-2' case ('net_downward_longwave_flux'); LONG_NAME = 'Net_longwave_land'; UNITS = 'W m-2' case ('radiation_shortwave_downward_flux');LONG_NAME = 'Incident_shortwave_land'; UNITS = 'W m-2' - case ('radiation_longwave_absorbed_flux'); LONG_NAME = 'perturbed_surface_downwelling_longwave_flux'; UNITS = 'W m-2' + case ('radiation_longwave_absorbed_flux'); LONG_NAME = 'surface_absorbed_longwave_flux'; UNITS = 'W m-2' case ('precipitation_total_surface_flux'); LONG_NAME = 'RainfSnowf'; UNITS = 'kg m-2 s-1' case ('snowfall_surface_flux'); LONG_NAME = 'snowfall'; UNITS = 'kg m-2 s-1' case ('surface_pressure'); LONG_NAME = 'surface_pressure'; UNITS = 'Pa' @@ -255,8 +255,8 @@ FUNCTION getAttribute (SHORT_NAME, LNAME, UNT) result (str_atr) case ('TA'); LONG_NAME = 'air_temperature_at_RefH'; UNITS = 'K' case ('Qair'); LONG_NAME = 'specific_humidity_at_RefH'; UNITS = 'kg kg-1' case ('QA'); LONG_NAME = 'specific_humidity_at_RefH'; UNITS = 'kg kg-1' - case ('LWdown'); LONG_NAME = 'downward_longwave_radiation"'; UNITS = 'W m-2' - case ('LWDNSRF'); LONG_NAME = 'perturbed_surface_downwelling_longwave_flux'; UNITS = 'W m-2' + case ('LWdown'); LONG_NAME = 'surface_absorbed_longwave_flux'; UNITS = 'W m-2' + case ('LWDNSRF'); LONG_NAME = 'surface_absorbed_longwave_flux'; UNITS = 'W m-2' case ('SWdown'); LONG_NAME = 'downward_shortwave_radiation'; UNITS = 'W m-2' case ('Wind'); LONG_NAME = 'wind_speed_at_RefH'; UNITS = 'm s-1' case ('UU'); LONG_NAME = 'wind_speed_at_RefH'; UNITS = 'm s-1' @@ -275,7 +275,7 @@ FUNCTION getAttribute (SHORT_NAME, LNAME, UNT) result (str_atr) case ('WESNN1'); LONG_NAME = 'snow_mass_layer_1'; UNITS = 'kg m-2' case ('WESNN2'); LONG_NAME = 'snow_mass_layer_2'; UNITS = 'kg m-2' case ('WESNN3'); LONG_NAME = 'snow_mass_layer_3'; UNITS = 'kg m-2' - case ('HLWUP'); LONG_NAME = 'surface_outgoing_longwave_flux'; UNITS = 'W m-2' + case ('HLWUP'); LONG_NAME = 'surface_emitted_longwave_flux'; UNITS = 'W m-2' case ('GWETPROF'); LONG_NAME = 'ave_prof_soil_wetness'; UNITS = '1' case ('GWETROOT'); LONG_NAME = 'root_zone_soil_wetness'; UNITS = '1' case ('GWETTOP'); LONG_NAME = 'surface_soil_wetness'; UNITS = '1' diff --git a/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/GEOS_MetforceGridComp.F90 b/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/GEOS_MetforceGridComp.F90 index 78d3cf81..b306e9fd 100644 --- a/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/GEOS_MetforceGridComp.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/GEOS_MetforceGridComp.F90 @@ -215,8 +215,8 @@ subroutine SetServices(gc, rc) call MAPL_AddExportSpec( & gc, & - SHORT_NAME = "RainfSnowf", & - LONG_NAME = "rainf+snowf", & + SHORT_NAME = "RainfSnowf", & + LONG_NAME = "rainf+snowf", & UNITS = "kg m-2 s-1", & DIMS = MAPL_DimsTileOnly, & VLOCATION = MAPL_VlocationNone, & @@ -227,7 +227,7 @@ subroutine SetServices(gc, rc) call MAPL_AddExportSpec( & gc, & SHORT_NAME = "LWdown", & - LONG_NAME = "downward_longwave_radiation", & + LONG_NAME = "surface_absorbed_longwave_flux", & UNITS = "W m-2", & DIMS = MAPL_DimsTileOnly, & VLOCATION = MAPL_VlocationNone, & From ac4bbf7f4dc622d245cc68eefb0a755abf6e6dca Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Tue, 19 Sep 2023 17:38:20 -0400 Subject: [PATCH 121/308] changed defaults of %bias_trel and %bias_tcut for ASCAT sm retrievals in LDASsa_DEFAULT_inputs_ensupd.nml (not used, but changed for consistency with other obs species) --- .../LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml b/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml index cd3dbeca..826f568a 100644 --- a/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml +++ b/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml @@ -2082,8 +2082,8 @@ obs_param_nml(49)%scale = .false. obs_param_nml(49)%getinnov = .false. obs_param_nml(49)%RTM_ID = 0 obs_param_nml(49)%bias_Npar = 0 -obs_param_nml(49)%bias_trel = 0 -obs_param_nml(49)%bias_tcut = 0 +obs_param_nml(49)%bias_trel = 864000 +obs_param_nml(49)%bias_tcut = 432000 obs_param_nml(49)%nodata = -9999. obs_param_nml(49)%varname = 'sfds' obs_param_nml(49)%units = '%' @@ -2119,8 +2119,8 @@ obs_param_nml(50)%scale = .false. obs_param_nml(50)%getinnov = .false. obs_param_nml(50)%RTM_ID = 0 obs_param_nml(50)%bias_Npar = 0 -obs_param_nml(50)%bias_trel = 0 -obs_param_nml(50)%bias_tcut = 0 +obs_param_nml(50)%bias_trel = 864000 +obs_param_nml(50)%bias_tcut = 432000 obs_param_nml(50)%nodata = -9999. obs_param_nml(50)%varname = 'sfds' obs_param_nml(50)%units = '%' @@ -2156,8 +2156,8 @@ obs_param_nml(51)%scale = .false. obs_param_nml(51)%getinnov = .false. obs_param_nml(51)%RTM_ID = 0 obs_param_nml(51)%bias_Npar = 0 -obs_param_nml(51)%bias_trel = 0 -obs_param_nml(51)%bias_tcut = 0 +obs_param_nml(51)%bias_trel = 864000 +obs_param_nml(51)%bias_tcut = 432000 obs_param_nml(51)%nodata = -9999. obs_param_nml(51)%varname = 'sfds' obs_param_nml(51)%units = '%' @@ -2193,8 +2193,8 @@ obs_param_nml(52)%scale = .false. obs_param_nml(52)%getinnov = .false. obs_param_nml(52)%RTM_ID = 0 obs_param_nml(52)%bias_Npar = 0 -obs_param_nml(52)%bias_trel = 0 -obs_param_nml(52)%bias_tcut = 0 +obs_param_nml(52)%bias_trel = 864000 +obs_param_nml(52)%bias_tcut = 432000 obs_param_nml(52)%nodata = -9999. obs_param_nml(52)%varname = 'sfds' obs_param_nml(52)%units = '%' @@ -2230,8 +2230,8 @@ obs_param_nml(53)%scale = .false. obs_param_nml(53)%getinnov = .false. obs_param_nml(53)%RTM_ID = 0 obs_param_nml(53)%bias_Npar = 0 -obs_param_nml(53)%bias_trel = 0 -obs_param_nml(53)%bias_tcut = 0 +obs_param_nml(53)%bias_trel = 864000 +obs_param_nml(53)%bias_tcut = 432000 obs_param_nml(53)%nodata = -9999. obs_param_nml(53)%varname = 'sfds' obs_param_nml(53)%units = '%' @@ -2267,8 +2267,8 @@ obs_param_nml(54)%scale = .false. obs_param_nml(54)%getinnov = .false. obs_param_nml(54)%RTM_ID = 0 obs_param_nml(54)%bias_Npar = 0 -obs_param_nml(54)%bias_trel = 0 -obs_param_nml(54)%bias_tcut = 0 +obs_param_nml(54)%bias_trel = 864000 +obs_param_nml(54)%bias_tcut = 432000 obs_param_nml(54)%nodata = -9999. obs_param_nml(54)%varname = 'sfds' obs_param_nml(54)%units = '%' From 364e5ddff35c815e5973dd76e71ed06a5054853d Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Wed, 20 Sep 2023 14:14:56 -0400 Subject: [PATCH 122/308] cleanup of subroutine read_obs_sm_ASCAT_EUMET() in clsm_ensupd_read_obs.F90: - removed obsolete variables - improved documentation - fixed units error - cleaned-up indentation --- .../clsm_ensupd_read_obs.F90 | 472 +++++++++--------- 1 file changed, 249 insertions(+), 223 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 7df0b2b5..3bd275da 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -1551,34 +1551,31 @@ end subroutine read_obs_sm_ASCAT ! **************************************************************************** - subroutine read_obs_sm_ASCAT_EUMET( & - work_path, exp_id, & - date_time, dtstep_assim, N_catd, tile_coord, & - tile_grid_d, N_tile_in_cell_ij, tile_num_in_cell_ij, & - this_obs_param, & - found_obs, ASCAT_sm, ASCAT_sm_std, ASCAT_lon, ASCAT_lat, ASCAT_time) + subroutine read_obs_sm_ASCAT_EUMET( & + date_time, dtstep_assim, N_catd, tile_coord, & + tile_grid_d, N_tile_in_cell_ij, tile_num_in_cell_ij, & + this_obs_param, & + found_obs, ASCAT_sm, ASCAT_sm_std, ASCAT_lon, ASCAT_lat, ASCAT_time ) !--------------------------------------------------------------------- ! - ! Routine to read in ASCAT surface degree of saturation obs. - ! Output is found_obs, sm_ASCAT, std_sm_ASCAT + ! Routine to read in ASCAT surface degree of saturation (sfds) obs. ! - ! Read in the EUMETSAT level 2 soil mositure product 25 km (SMO), PPF software version 5.0 - ! the data correspond to re-sampled (spatially averaged) sigma0 values, on a 25 km - ! orbit swath grid. The input data files are in BUFR file format. + ! Read in EUMETSAT level 2 soil moisture product 25 km (SMO), PPF software version 5.0. + ! Data correspond to re-sampled (spatially averaged) backscatter (sigma0) values + ! on a 25-km orbit swath grid. Input data files are in BUFR file format. + ! + ! ASCAT_sm and ASCAT_sm_std outputs are in wetness fraction (i.e., 0-1) units! + ! + ! Q. Liu, Nov 2019 - based on read_obs_sm_ASCAT + ! A. Fox, reichle, Sep 2023 - updated ! - ! Q. Liu, Nov. 2019. - ! based on read_obs_sm_ASCAT - ! Minor updates A. Fox, march 2023 ! -------------------------------------------------------------------- implicit none ! inputs: - character(*), intent(in) :: work_path - character(*), intent(in) :: exp_id - type(date_time_type), intent(in) :: date_time integer, intent(in) :: dtstep_assim, N_catd @@ -1598,65 +1595,65 @@ subroutine read_obs_sm_ASCAT_EUMET( & logical, intent(out) :: found_obs - real, intent(out), dimension(N_catd) :: ASCAT_sm ! wetness range 0-1 - real, intent(out), dimension(N_catd) :: ASCAT_sm_std + real, intent(out), dimension(N_catd) :: ASCAT_sm ! sfds obs [fraction] (i.e., 0-1) + real, intent(out), dimension(N_catd) :: ASCAT_sm_std ! sfds obs err std [fraction] (i.e., 0-1) real, intent(out), dimension(N_catd) :: ASCAT_lon, ASCAT_lat real*8, intent(out), dimension(N_catd) :: ASCAT_time ! J2000 seconds - ! --------------- - ! Each obs file contains about 100 - 110 minutes of observations. Code as dt_ASCAT_obsfile - ! file name indicates the start time of the swaths. - - integer, parameter :: dt_ASCAT_obsfile = 110*60 ! seconds - - integer, parameter :: N_fnames_max = 20 + ! Each obs file contains ~100-110 minutes (1 full orbit?) of observations (dt_ASCAT_obsfile). + ! File name indicates start time of swath. + + integer, parameter :: dt_ASCAT_obsfile = 110*60 ! seconds + + integer, parameter :: N_fnames_max = 15 ! max number of files per day - character(4), parameter :: J2000_epoch_id = 'TT12' ! see date_time_util.F90 + character(4), parameter :: J2000_epoch_id = 'TT12' ! see date_time_util.F90 - character( 4) :: DDHH - character( 6) :: YYYYMM - character( 8) :: date_string - character( 10) :: time_stringi character( 15) :: str_date_time character( 80) :: fname_of_fname_list character(300) :: tmpfname, tmpfname2 - character(400) :: cmd type(date_time_type) :: date_time_tmp type(date_time_type) :: date_time_low, date_time_low_fname type(date_time_type) :: date_time_up - integer :: i, ind, N_tmp, N_files, kk, N_obs - integer :: N_fnames, N_fnames_tmp - + integer :: ii, ind, N_tmp, N_files, kk, N_obs, N_fnames, N_fnames_tmp + character(300), dimension(:), allocatable :: fnames, tmpfnames - - real*8, dimension(15) :: tmp_vdata - integer, parameter :: lnbufr = 50 - integer, parameter :: max_rec = 20000 - integer, parameter :: max_obs = 250000 - integer :: idate,iret - integer :: ireadmg,ireadsb - character(8) :: subset + + ! -------------------- + ! + ! variables for BUFR read + + real*8, dimension(15) :: tmp_vdata + + integer, parameter :: lnbufr = 50 ! BUFR file unit number + integer, parameter :: max_rec = 20000 ! max number of obs after QC + integer, parameter :: max_obs = 250000 ! max number of obs read by subroutine + + integer :: idate, iret, ireadmg, ireadsb + + character(8) :: subset + + ! -------------------- character(100), dimension(2*N_fnames_max) :: fname_list ! max 2 days of files - real, dimension(:), allocatable :: tmp1_lon, tmp1_lat, tmp1_obs + real, dimension(:), allocatable :: tmp1_obs, tmp1_lat, tmp1_lon real*8, dimension(:), allocatable :: tmp1_jtime real*8, dimension(:,:), allocatable :: tmp_data - real, dimension(:), pointer :: tmp_obs, tmp_lat, tmp_lon + real, dimension(:), pointer :: tmp_obs, tmp_lat, tmp_lon real*8, dimension(:), pointer :: tmp_jtime - integer, dimension(:), pointer :: tmp_tile_num - integer, dimension(N_catd) :: N_obs_in_tile + integer, dimension(:), pointer :: tmp_tile_num - real, parameter :: tol = 1e-2 + integer, dimension(N_catd) :: N_obs_in_tile - character(len=*), parameter :: Iam = 'read_obs_sm_ASCAT_EUMET' - character(len=400) :: err_msg + character(len=*), parameter :: Iam = 'read_obs_sm_ASCAT_EUMET' + character(len=400) :: err_msg ! ------------------------------------------------------------------- @@ -1667,30 +1664,33 @@ subroutine read_obs_sm_ASCAT_EUMET( & ! initialize found_obs = .false. - + ! find files that are within half-open interval - ! [date_time-dtstep_assim/2,date_time+dtstep_assim/2) + ! [date_time-dtstep_assim/2,date_time+dtstep_assim/2) date_time_low = date_time call augment_date_time( -(dtstep_assim/2), date_time_low) date_time_up = date_time call augment_date_time( (dtstep_assim/2), date_time_up) - ! Calculate an "extra" date_time_low to catch files with time stamps before window but containing relevant obs - + ! calculate "extra" date_time_low to catch files w/ time swath start stamps before window + ! but containing relevant obs + date_time_low_fname = date_time_low call augment_date_time( -dt_ASCAT_obsfile, date_time_low_fname) - + + ! ---------------------------------------------------------------- + ! ! read file with list of ASCAT file names for first day - - fname_of_fname_list = 'dummy' ! Make sure its in the obs_param nml + + fname_of_fname_list = 'dummy' ! make sure it is properly defined in obs_param nml call read_obs_SMAP_fnames( date_time_low_fname, this_obs_param, & fname_of_fname_list, N_fnames_max, & N_fnames, fname_list(1:N_fnames_max) ) ! if needed, read file with list of ASCAT file names for second day and add - ! file names into "fname_list" + ! file names into "fname_list" if (date_time_low_fname%day /= date_time_up%day) then @@ -1701,174 +1701,198 @@ subroutine read_obs_sm_ASCAT_EUMET( & N_fnames = N_fnames + N_fnames_tmp end if - + tmpfnames = fname_list(1:N_fnames) - + + ! ---------------------------------------------------------------- + ! + ! find files that have obs within assimilation window + N_tmp = 0 - + do kk = 1,N_fnames - tmpfname = fname_list(kk) - ! Are we in the required assimilation window? - !e.g. Y2019/M07/D02/M01-ASCA-ASCSMO02-NA-5.0-20190702075700.000000000Z-20190702084627-1350204.bfr - str_date_time = tmpfname(40:53) - - read(str_date_time(1:4), *) date_time_tmp%year - read(str_date_time(5:6), *) date_time_tmp%month - read(str_date_time(7:8), *) date_time_tmp%day - read(str_date_time(9:10), *) date_time_tmp%hour - read(str_date_time(11:12), *) date_time_tmp%min - read(str_date_time(13:14), *) date_time_tmp%sec - - if ( datetime_lt_refdatetime( date_time_low_fname, date_time_tmp ) .and. & - datetime_le_refdatetime( date_time_tmp, date_time_up )) then - N_tmp = N_tmp + 1 - ! Remove the '/D03/' from the directory part as using "read_obs_SMAP_fnames" - ind = index(tmpfname, "/D") + + tmpfname = fname_list(kk) + + ! Are we in the required assimilation window? + ! + ! e.g. Y2019/M07/M01-ASCA-ASCSMO02-NA-5.0-20190702075700.000000000Z-20190702084627-1350204.bfr + ! + ! 12345678901234567890123456789012345678901234567890123456789012345678901234567890 + ! 1 2 3 4 5 6 7 + + str_date_time = tmpfname(40:53) - if (ind > 0) then - tmpfname2 = tmpfname(1:ind) // tmpfname(ind+5:) - end if - tmpfnames(N_tmp) = trim(this_obs_param%path) // '/' // trim(tmpfname2) - end if - end do + read(str_date_time( 1: 4), *) date_time_tmp%year + read(str_date_time( 5: 6), *) date_time_tmp%month + read(str_date_time( 7: 8), *) date_time_tmp%day + read(str_date_time( 9:10), *) date_time_tmp%hour + read(str_date_time(11:12), *) date_time_tmp%min + read(str_date_time(13:14), *) date_time_tmp%sec + + if ( datetime_lt_refdatetime( date_time_low_fname, date_time_tmp ) .and. & + datetime_le_refdatetime( date_time_tmp, date_time_up ) ) then - fnames = tmpfnames(1:N_tmp) - N_files = N_tmp + N_tmp = N_tmp + 1 + + ! Remove the '/D03/' from the directory part as using "read_obs_SMAP_fnames" + + ind = index(tmpfname, "/D") + + if (ind > 0) then + tmpfname2 = tmpfname(1:ind) // tmpfname(ind+5:) + end if + tmpfnames(N_tmp) = trim(this_obs_param%path) // '/' // trim(tmpfname2) + + end if + + end do + + fnames = tmpfnames(1:N_tmp) + N_files = N_tmp + + ! ---------------------------------------------------------------- + ! + ! loop through files and read obs + metadata into tmp_data + if (N_files>0) then - ! read and process data if files are found - allocate(tmp1_lon(max_rec)) - allocate(tmp1_lat(max_rec)) - allocate(tmp1_obs(max_rec)) - allocate(tmp1_jtime(max_rec)) - allocate(tmp_data(max_obs, 15)) + allocate(tmp1_lon( max_rec )) + allocate(tmp1_lat( max_rec )) + allocate(tmp1_obs( max_rec )) + allocate(tmp1_jtime(max_rec )) + + allocate(tmp_data( max_obs,15)) - ! file loop N_obs = 0 - + do kk = 1,N_files - ! open on bufr file - call closbf(lnbufr) - open(lnbufr, file=trim(fnames(kk)), action='read',form='unformatted') - call openbf(lnbufr,'SEC3', lnbufr) - call mtinfo( trim(this_obs_param%path) // '/BUFR_mastertable/', 51, 52) + ! open bufr file + + call closbf(lnbufr) ! if a file with unit number lnbufr is open in (or "linked" with) BUFR, close it + open(lnbufr, file=trim(fnames(kk)), action='read', form='unformatted') + call openbf(lnbufr, 'SEC3', lnbufr) + call mtinfo( trim(this_obs_param%path) // '/BUFR_mastertable/', lnbufr+1, lnbufr+2) call datelen(10) - - msg_report: do while(ireadmg(lnbufr,subset,idate) ==0) - loop_report: do while(ireadsb(lnbufr) == 0) + + msg_report: do while( ireadmg(lnbufr,subset,idate) == 0 ) + + loop_report: do while( ireadsb(lnbufr) == 0 ) + + ! columns of tmp_data: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - call ufbint(lnbufr,tmp_vdata,15,1,iret,'YEAR MNTH DAYS HOUR MINU SECO SSOM DOMO SMPF SMCF ALFR TPCX IWFR CLATH CLONH') - N_obs = N_obs + 1 - tmp_data(N_obs,:) = tmp_vdata + call ufbint(lnbufr,tmp_vdata,15,1,iret,'YEAR MNTH DAYS HOUR MINU SECO SSOM DOMO SMPF SMCF ALFR TPCX IWFR CLATH CLONH') - end do loop_report + N_obs = N_obs + 1 + tmp_data(N_obs,:) = tmp_vdata + + end do loop_report end do msg_report - + call closbf(lnbufr) close(lnbufr) - + end do ! end file loop + ! ---------------------------------------------------------------- + ! + ! select obs within assimilation window and from desired orbit direction; apply basic QC based on obs info + N_tmp = 0 - + do kk = 1,N_obs - - date_time_tmp%year = int(tmp_data(kk, 1)) - date_time_tmp%month = int(tmp_data(kk, 2)) - date_time_tmp%day = int(tmp_data(kk, 3)) - date_time_tmp%hour = int(tmp_data(kk, 4)) - date_time_tmp%min = int(tmp_data(kk, 5)) - date_time_tmp%sec = int(tmp_data(kk, 6)) - - ! skip if record outside of current assim window - if ( datetime_lt_refdatetime( date_time_tmp, date_time_low ) .and. & - datetime_le_refdatetime( date_time_up, date_time_tmp )) cycle - - ! skip if record contain no valid soil moisture value - if(tmp_data(kk, 7) > 100. .or. tmp_data(kk, 7) < 0.) cycle - - ! EUMETSAT file contains data of both ascending and descending orbits. - ! DOMO - “Direction of motion of moving observing platform” is used to seperate Asc and Desc - ! because the file doesn't contain any explicit orbit indicator variable. - ! according to Pamela Schoebel-Pattiselanno, EUMETSAT User Services Helpdesk - ! "When the value (of DOMO) is between 180 and 270 degrees, it is the descending part - ! of the orbit … when it is between 270 and 360 degrees, it is the ascending part" - if (index(this_obs_param%descr,'_A') /=0 .and. (tmp_data(kk, 8) < 270 .or. tmp_data(kk, 8) > 360)) cycle - if (index(this_obs_param%descr,'_D') /=0 .and. (tmp_data(kk, 8) < 180 .or. tmp_data(kk, 8) >= 270)) cycle - - ! skip if processing flag is set - if(int(tmp_data(kk, 9)) /= 0) cycle - - ! skip if correction flag is set - if (.not. (int(tmp_data(kk, 10)) == 0 .or. int(tmp_data(kk, 10)) == 4)) cycle - - ! skip if land fraction is missing or < 0.9 - if(tmp_data(kk, 11) >1 .or. tmp_data(kk, 11) < 0.9 ) cycle - - ! skip if topographic complexity > 10% - if(tmp_data(kk, 12) > 10.) cycle - - ! skip if inudatation and wetland faction > 10% - if(tmp_data(kk, 13) > 10.) cycle - - N_tmp = N_tmp + 1 ! Passed all QC + + date_time_tmp%year = int(tmp_data(kk, 1)) + date_time_tmp%month = int(tmp_data(kk, 2)) + date_time_tmp%day = int(tmp_data(kk, 3)) + date_time_tmp%hour = int(tmp_data(kk, 4)) + date_time_tmp%min = int(tmp_data(kk, 5)) + date_time_tmp%sec = int(tmp_data(kk, 6)) + + ! skip if record outside of current assim window + if ( datetime_lt_refdatetime( date_time_tmp, date_time_low ) .and. & + datetime_le_refdatetime( date_time_up, date_time_tmp ) ) cycle + + ! skip if record contains invalid soil moisture value + if ( tmp_data(kk, 7) > 100. .or. tmp_data(kk, 7) < 0. ) cycle + + ! EUMETSAT file contains data of both ascending and descending half-orbits. + ! DOMO ("Direction of motion of moving observing platform") is used to separate Asc and Desc + ! because the file doesn't contain any explicit orbit indicator variable. + ! According to Pamela Schoebel-Pattiselanno, EUMETSAT User Services Helpdesk: + ! "When the value (of DOMO) is between 180 and 270 degrees, it is the descending part + ! of the orbit. When it is between 270 and 360 degrees, it is the ascending part." + if (index(this_obs_param%descr,'_A') /=0 .and. (tmp_data(kk, 8) < 270 .or. tmp_data(kk, 8) > 360)) cycle + if (index(this_obs_param%descr,'_D') /=0 .and. (tmp_data(kk, 8) < 180 .or. tmp_data(kk, 8) >= 270)) cycle + + ! skip if processing flag is set + if(int(tmp_data(kk, 9)) /= 0) cycle + + ! skip if correction flag is set ("good" values are 0 and 4) + if (.not. ( (int(tmp_data(kk, 10)) == 0) .or. (int(tmp_data(kk, 10)) == 4)) ) cycle + + ! skip if land fraction is missing or < 0.9 + if(tmp_data(kk, 11) > 1. .or. tmp_data(kk, 11) < 0.9 ) cycle + + ! skip if topographic complexity > 10% + if(tmp_data(kk, 12) > 10.) cycle + + ! skip if inundation and wetland fraction > 10% + if(tmp_data(kk, 13) > 10.) cycle + + N_tmp = N_tmp + 1 ! passed all QC - tmp1_jtime(N_tmp) = datetime_to_J2000seconds( date_time_tmp, J2000_epoch_id ) - - tmp1_lat(N_tmp) = tmp_data(kk, 14) - tmp1_lon(N_tmp) = tmp_data(kk, 15) - tmp1_obs(N_tmp) = tmp_data(kk, 7)/100. ! change value from 0-100 to 0-1 + tmp1_jtime(N_tmp) = datetime_to_J2000seconds( date_time_tmp, J2000_epoch_id ) + + tmp1_lat( N_tmp) = tmp_data(kk, 14) + tmp1_lon( N_tmp) = tmp_data(kk, 15) + tmp1_obs( N_tmp) = tmp_data(kk, 7)/100. ! change units from percent (0-100) to fraction (0-1) + end do if (logit) then - write (logunit,*) 'read_obs_sm_ASCAT_EUMET: read ', N_tmp, & - ' at date_time = ', date_time, ' from ' - do i=1,N_files - write (logunit,*) trim(fnames(i)) + write (logunit,*) 'read_obs_sm_ASCAT_EUMET: read ', N_tmp, ' at date_time = ', date_time, ' from:' + do ii=1,N_files + write (logunit,*) trim(fnames(ii)) end do write (logunit,*) '----------' - write (logunit,*) 'max(obs)=',maxval(tmp1_obs(1:N_tmp)), 'min(obs)=',minval(tmp1_obs(1:N_tmp)), & - ' avg(obs)=',sum(tmp1_obs(1:N_tmp))/N_tmp + write (logunit,*) 'max(obs)=',maxval(tmp1_obs(1:N_tmp)), ', min(obs)=',minval(tmp1_obs(1:N_tmp)), & + ', avg(obs)=',sum(tmp1_obs(1:N_tmp))/N_tmp + end if - + deallocate(fnames) + ! copy "good" obs with lat/lon/time into tmp_* (pointers) + allocate(tmp_jtime(N_tmp)) - allocate(tmp_lon(N_tmp)) - allocate(tmp_lat(N_tmp)) - allocate(tmp_obs(N_tmp)) + allocate(tmp_lon( N_tmp)) + allocate(tmp_lat( N_tmp)) + allocate(tmp_obs( N_tmp)) tmp_jtime = tmp1_jtime(1:N_tmp) - tmp_lon = tmp1_lon(1:N_tmp) - tmp_lat = tmp1_lat(1:N_tmp) - tmp_obs = tmp1_obs(1:N_tmp) + tmp_lon = tmp1_lon( 1:N_tmp) + tmp_lat = tmp1_lat( 1:N_tmp) + tmp_obs = tmp1_obs( 1:N_tmp) deallocate(tmp1_jtime) deallocate(tmp1_lon) deallocate(tmp1_lat) deallocate(tmp1_obs) deallocate(tmp_data) - - else + + else + N_tmp = 0 - - end if - - - ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - ! - ! SOME QC SHOULD BE DONE HERE!!! - ! - ! MAKE SURE no-data-values ARE DEALT WITH - ! - ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + end if ! ---------------------------------------------------------------- ! @@ -1885,65 +1909,68 @@ subroutine read_obs_sm_ASCAT_EUMET( & N_tmp, tmp_lat, tmp_lon, & this_obs_param, & tmp_tile_num ) - + ! ---------------------------------------------------------------- ! ! 3.) compute super-obs for each tile from all obs w/in that tile ! (also eliminate observations that are not in domain) - ASCAT_sm = 0. - ASCAT_lon = 0. - ASCAT_lat = 0. + ASCAT_sm = 0. + ASCAT_lon = 0. + ASCAT_lat = 0. ASCAT_time = 0.0D0 - - N_obs_in_tile = 0 - do i=1,N_tmp + N_obs_in_tile = 0 + + do ii=1,N_tmp - ind = tmp_tile_num(i) ! 1<=tmp_tile_num<=N_catd (unless nodata) + ind = tmp_tile_num(ii) ! 1<=tmp_tile_num<=N_catd (unless nodata) if (ind>0) then ! this step eliminates obs outside domain - ASCAT_sm(ind) = ASCAT_sm(ind) + tmp_obs(i) - ASCAT_lon(ind) = ASCAT_lon(ind) + tmp_lon(i) - ASCAT_lat(ind) = ASCAT_lat(ind) + tmp_lat(i) - ASCAT_time(ind) = ASCAT_time(ind) + tmp_jtime(i) + ASCAT_sm( ind) = ASCAT_sm( ind) + tmp_obs( ii) + ASCAT_lon( ind) = ASCAT_lon( ind) + tmp_lon( ii) + ASCAT_lat( ind) = ASCAT_lat( ind) + tmp_lat( ii) + ASCAT_time(ind) = ASCAT_time(ind) + tmp_jtime(ii) - N_obs_in_tile(ind) = N_obs_in_tile(ind) + 1 + N_obs_in_tile(ind) = N_obs_in_tile(ind) + 1 end if end do - - ! -------------------------------- ! normalize - do i=1,N_catd - - ! set observation error standard deviation - ASCAT_sm_std(i) = this_obs_param%errstd + do ii=1,N_catd - if (N_obs_in_tile(i)>1) then - - ASCAT_sm(i) = ASCAT_sm(i)/real(N_obs_in_tile(i)) - ASCAT_lon(i) = ASCAT_lon(i)/real(N_obs_in_tile(i)) - ASCAT_lat(i) = ASCAT_lat(i)/real(N_obs_in_tile(i)) - ASCAT_time(i) = ASCAT_time(i)/real(N_obs_in_tile(i),kind(0.0D0)) + ! set observation error standard deviation - elseif (N_obs_in_tile(i)==0) then + ASCAT_sm_std(ii) = this_obs_param%errstd/100. ! change units from percent (0-100) to fraction (0-1) + + if (N_obs_in_tile(ii)>1) then + + ASCAT_sm( ii) = ASCAT_sm( ii)/real(N_obs_in_tile(ii)) + ASCAT_lon( ii) = ASCAT_lon( ii)/real(N_obs_in_tile(ii)) + ASCAT_lat( ii) = ASCAT_lat( ii)/real(N_obs_in_tile(ii)) + ASCAT_time(ii) = ASCAT_time(ii)/real(N_obs_in_tile(ii),kind(0.0D0)) + + elseif (N_obs_in_tile(ii)==0) then - ASCAT_sm(i) = this_obs_param%nodata - ASCAT_lon(i) = this_obs_param%nodata - ASCAT_lat(i) = this_obs_param%nodata - ASCAT_time(i) = real(this_obs_param%nodata,kind(0.0D0)) - ASCAT_sm_std(i) = this_obs_param%nodata + ASCAT_sm( ii) = this_obs_param%nodata + ASCAT_lon( ii) = this_obs_param%nodata + ASCAT_lat( ii) = this_obs_param%nodata + ASCAT_time( ii) = real(this_obs_param%nodata,kind(0.0D0)) + ASCAT_sm_std(ii) = this_obs_param%nodata + + else + + ! nothing to do if N_obs_in_tile(ii)==1 (and assuming N_obs_in_tile is never negative) end if end do - + ! clean up if (associated(tmp_tile_num)) deallocate(tmp_tile_num) @@ -1959,23 +1986,23 @@ subroutine read_obs_sm_ASCAT_EUMET( & end if end if - -! call system_clock(clock_end, clock_rate) ! Stop timing -! elapsed_time_sr=(real(clock_end-clock_start_sr)/real(clock_rate)) -! write (logunit,*) 'Elapsed time in read_obs_sm_ASCAT_EUMET: ', elapsed_time, ' seconds' - -! elapsed_time = (elapsed_time/elapsed_time_sr)*100 -! write (logunit,*) 'We spent ', elapsed_time, '% of time in bufr read' - + + ! call system_clock(clock_end, clock_rate) ! Stop timing + ! elapsed_time_sr=(real(clock_end-clock_start_sr)/real(clock_rate)) + ! write (logunit,*) 'Elapsed time in read_obs_sm_ASCAT_EUMET: ', elapsed_time, ' seconds' + + ! elapsed_time = (elapsed_time/elapsed_time_sr)*100 + ! write (logunit,*) 'We spent ', elapsed_time, '% of time in bufr read' + ! clean up if (associated(tmp_obs)) deallocate(tmp_obs) if (associated(tmp_lon)) deallocate(tmp_lon) if (associated(tmp_lat)) deallocate(tmp_lat) if (associated(tmp_jtime)) deallocate(tmp_jtime) - + end subroutine read_obs_sm_ASCAT_EUMET - + ! *************************************************************************** subroutine read_sm_ASCAT_bin( & @@ -7479,7 +7506,6 @@ subroutine read_obs( & call system_clock(clock_start) ! Start timing call read_obs_sm_ASCAT_EUMET( & - work_path, exp_id, & date_time, dtstep_assim, N_catd, tile_coord, & tile_grid_d, N_tile_in_cell_ij, tile_num_in_cell_ij, & this_obs_param, & From 5844ce9bb1380fae93a36784c349e3a173d5769d Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Thu, 21 Sep 2023 08:37:16 -0400 Subject: [PATCH 123/308] fix default obs_param values of non-MODIS-SCF species to match "develop" branch (LDASsa_DEFAULT_inputs_ensupd.nml) --- .../LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml b/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml index 1498b7c3..75148b3a 100644 --- a/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml +++ b/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml @@ -90,8 +90,8 @@ fcsterr_inflation_fac = -9999. ! 1 = horizontal ! 2 = vertical ! 3 = ... -! %N_ang = # angles in species (for radiance data) -! %ang = vector of angles +! %N_ang = # satellite viewing angles in species +! %ang = vector of satellite viewing angles ! %freq = frequency [Hz] ! %FOV = field-of-view *radius*, see NOTES below ! (if FOV==0. equate obs footprint w/ tile) @@ -234,7 +234,8 @@ fcsterr_inflation_fac = -9999. obs_param_nml( 1)%descr = 'ae_l2_sm_a' obs_param_nml( 1)%orbit = 1 obs_param_nml( 1)%pol = 0 -obs_param_nml( 1)%N_ang = 0 +obs_param_nml( 1)%N_ang = 1 +obs_param_nml( 1)%ang(1) = 55. obs_param_nml( 1)%freq = 10.65e9 obs_param_nml( 1)%FOV = 20. obs_param_nml( 1)%FOV_units = 'km' @@ -269,7 +270,8 @@ obs_param_nml( 1)%adapt = 0 obs_param_nml( 2)%descr = 'ae_l2_sm_d' obs_param_nml( 2)%orbit = 2 obs_param_nml( 2)%pol = 0 -obs_param_nml( 2)%N_ang = 0 +obs_param_nml( 2)%N_ang = 1 +obs_param_nml( 2)%ang(1) = 55. obs_param_nml( 2)%freq = 10.65e9 obs_param_nml( 2)%FOV = 20. obs_param_nml( 2)%FOV_units = 'km' @@ -514,7 +516,8 @@ obs_param_nml( 8)%adapt = 0 obs_param_nml( 9)%descr = 'ae_sm_LPRM_a_C' obs_param_nml( 9)%orbit = 1 obs_param_nml( 9)%pol = 0 -obs_param_nml( 9)%N_ang = 0 +obs_param_nml( 9)%N_ang = 1 +obs_param_nml( 9)%ang(1) = 55. obs_param_nml( 9)%freq = 6.925e9 obs_param_nml( 9)%FOV = 20. obs_param_nml( 9)%FOV_units = 'km' @@ -549,7 +552,8 @@ obs_param_nml( 9)%adapt = 0 obs_param_nml(10)%descr = 'ae_sm_LPRM_d_C' obs_param_nml(10)%orbit = 2 obs_param_nml(10)%pol = 0 -obs_param_nml(10)%N_ang = 0 +obs_param_nml(10)%N_ang = 1 +obs_param_nml(10)%ang(1) = 55. obs_param_nml(10)%freq = 6.925e9 obs_param_nml(10)%FOV = 20. obs_param_nml(10)%FOV_units = 'km' @@ -584,7 +588,8 @@ obs_param_nml(10)%adapt = 0 obs_param_nml(11)%descr = 'ae_sm_LPRM_a_X' obs_param_nml(11)%orbit = 1 obs_param_nml(11)%pol = 0 -obs_param_nml(11)%N_ang = 0 +obs_param_nml(11)%N_ang = 1 +obs_param_nml(11)%ang(1) = 55. obs_param_nml(11)%freq = 10.65e9 obs_param_nml(11)%FOV = 20. obs_param_nml(11)%FOV_units = 'km' @@ -619,7 +624,8 @@ obs_param_nml(11)%adapt = 0 obs_param_nml(12)%descr = 'ae_sm_LPRM_d_X' obs_param_nml(12)%orbit = 2 obs_param_nml(12)%pol = 0 -obs_param_nml(12)%N_ang = 0 +obs_param_nml(12)%N_ang = 1 +obs_param_nml(12)%ang(1) = 55. obs_param_nml(12)%freq = 10.65e9 obs_param_nml(12)%FOV = 20. obs_param_nml(12)%FOV_units = 'km' @@ -1684,7 +1690,8 @@ obs_param_nml(38)%adapt = 0 obs_param_nml(39)%descr = 'SMAP_L2AP_FT_A' obs_param_nml(39)%orbit = 1 obs_param_nml(39)%pol = 0 -obs_param_nml(39)%N_ang = 0 +obs_param_nml(39)%N_ang = 1 +obs_param_nml(39)%ang(1) = 40. obs_param_nml(39)%freq = 1.26e9 obs_param_nml(39)%FOV = 5. obs_param_nml(39)%FOV_units = 'km' @@ -1719,7 +1726,8 @@ obs_param_nml(39)%adapt = 0 obs_param_nml(40)%descr = 'SMAP_L2AP_FT_D' obs_param_nml(40)%orbit = 2 obs_param_nml(40)%pol = 0 -obs_param_nml(40)%N_ang = 0 +obs_param_nml(40)%N_ang = 1 +obs_param_nml(40)%ang(1) = 40. obs_param_nml(40)%freq = 1.26e9 obs_param_nml(40)%FOV = 5. obs_param_nml(40)%FOV_units = 'km' From 3ac6d3bc44d7bbaca129952775faf14b4b4e9bef Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Thu, 21 Sep 2023 08:59:08 -0400 Subject: [PATCH 124/308] Revert "fix default obs_param values of non-MODIS-SCF species to match "develop" branch (LDASsa_DEFAULT_inputs_ensupd.nml)" This reverts commit 5844ce9bb1380fae93a36784c349e3a173d5769d. --- .../LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml | 28 +++++++------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml b/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml index 75148b3a..1498b7c3 100644 --- a/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml +++ b/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml @@ -90,8 +90,8 @@ fcsterr_inflation_fac = -9999. ! 1 = horizontal ! 2 = vertical ! 3 = ... -! %N_ang = # satellite viewing angles in species -! %ang = vector of satellite viewing angles +! %N_ang = # angles in species (for radiance data) +! %ang = vector of angles ! %freq = frequency [Hz] ! %FOV = field-of-view *radius*, see NOTES below ! (if FOV==0. equate obs footprint w/ tile) @@ -234,8 +234,7 @@ fcsterr_inflation_fac = -9999. obs_param_nml( 1)%descr = 'ae_l2_sm_a' obs_param_nml( 1)%orbit = 1 obs_param_nml( 1)%pol = 0 -obs_param_nml( 1)%N_ang = 1 -obs_param_nml( 1)%ang(1) = 55. +obs_param_nml( 1)%N_ang = 0 obs_param_nml( 1)%freq = 10.65e9 obs_param_nml( 1)%FOV = 20. obs_param_nml( 1)%FOV_units = 'km' @@ -270,8 +269,7 @@ obs_param_nml( 1)%adapt = 0 obs_param_nml( 2)%descr = 'ae_l2_sm_d' obs_param_nml( 2)%orbit = 2 obs_param_nml( 2)%pol = 0 -obs_param_nml( 2)%N_ang = 1 -obs_param_nml( 2)%ang(1) = 55. +obs_param_nml( 2)%N_ang = 0 obs_param_nml( 2)%freq = 10.65e9 obs_param_nml( 2)%FOV = 20. obs_param_nml( 2)%FOV_units = 'km' @@ -516,8 +514,7 @@ obs_param_nml( 8)%adapt = 0 obs_param_nml( 9)%descr = 'ae_sm_LPRM_a_C' obs_param_nml( 9)%orbit = 1 obs_param_nml( 9)%pol = 0 -obs_param_nml( 9)%N_ang = 1 -obs_param_nml( 9)%ang(1) = 55. +obs_param_nml( 9)%N_ang = 0 obs_param_nml( 9)%freq = 6.925e9 obs_param_nml( 9)%FOV = 20. obs_param_nml( 9)%FOV_units = 'km' @@ -552,8 +549,7 @@ obs_param_nml( 9)%adapt = 0 obs_param_nml(10)%descr = 'ae_sm_LPRM_d_C' obs_param_nml(10)%orbit = 2 obs_param_nml(10)%pol = 0 -obs_param_nml(10)%N_ang = 1 -obs_param_nml(10)%ang(1) = 55. +obs_param_nml(10)%N_ang = 0 obs_param_nml(10)%freq = 6.925e9 obs_param_nml(10)%FOV = 20. obs_param_nml(10)%FOV_units = 'km' @@ -588,8 +584,7 @@ obs_param_nml(10)%adapt = 0 obs_param_nml(11)%descr = 'ae_sm_LPRM_a_X' obs_param_nml(11)%orbit = 1 obs_param_nml(11)%pol = 0 -obs_param_nml(11)%N_ang = 1 -obs_param_nml(11)%ang(1) = 55. +obs_param_nml(11)%N_ang = 0 obs_param_nml(11)%freq = 10.65e9 obs_param_nml(11)%FOV = 20. obs_param_nml(11)%FOV_units = 'km' @@ -624,8 +619,7 @@ obs_param_nml(11)%adapt = 0 obs_param_nml(12)%descr = 'ae_sm_LPRM_d_X' obs_param_nml(12)%orbit = 2 obs_param_nml(12)%pol = 0 -obs_param_nml(12)%N_ang = 1 -obs_param_nml(12)%ang(1) = 55. +obs_param_nml(12)%N_ang = 0 obs_param_nml(12)%freq = 10.65e9 obs_param_nml(12)%FOV = 20. obs_param_nml(12)%FOV_units = 'km' @@ -1690,8 +1684,7 @@ obs_param_nml(38)%adapt = 0 obs_param_nml(39)%descr = 'SMAP_L2AP_FT_A' obs_param_nml(39)%orbit = 1 obs_param_nml(39)%pol = 0 -obs_param_nml(39)%N_ang = 1 -obs_param_nml(39)%ang(1) = 40. +obs_param_nml(39)%N_ang = 0 obs_param_nml(39)%freq = 1.26e9 obs_param_nml(39)%FOV = 5. obs_param_nml(39)%FOV_units = 'km' @@ -1726,8 +1719,7 @@ obs_param_nml(39)%adapt = 0 obs_param_nml(40)%descr = 'SMAP_L2AP_FT_D' obs_param_nml(40)%orbit = 2 obs_param_nml(40)%pol = 0 -obs_param_nml(40)%N_ang = 1 -obs_param_nml(40)%ang(1) = 40. +obs_param_nml(40)%N_ang = 0 obs_param_nml(40)%freq = 1.26e9 obs_param_nml(40)%FOV = 5. obs_param_nml(40)%FOV_units = 'km' From c7dcf27ae146f5d6de9313341037e3980ab14d52 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Thu, 21 Sep 2023 09:05:13 -0400 Subject: [PATCH 125/308] additional edits re. comments about satellite viewing angles in obs_param --- src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml | 4 ++-- src/Components/GEOSldas_GridComp/Shared/enkf_types.F90 | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml b/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml index 1498b7c3..187413a3 100644 --- a/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml +++ b/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml @@ -90,8 +90,8 @@ fcsterr_inflation_fac = -9999. ! 1 = horizontal ! 2 = vertical ! 3 = ... -! %N_ang = # angles in species (for radiance data) -! %ang = vector of angles +! %N_ang = # satellite viewing angles in species (radiance obs only) +! %ang = vector of satellite viewing angles ! %freq = frequency [Hz] ! %FOV = field-of-view *radius*, see NOTES below ! (if FOV==0. equate obs footprint w/ tile) diff --git a/src/Components/GEOSldas_GridComp/Shared/enkf_types.F90 b/src/Components/GEOSldas_GridComp/Shared/enkf_types.F90 index 46e5ef5b..a1a78532 100644 --- a/src/Components/GEOSldas_GridComp/Shared/enkf_types.F90 +++ b/src/Components/GEOSldas_GridComp/Shared/enkf_types.F90 @@ -104,10 +104,10 @@ module enkf_types ! 3 = ... ! [add 3rd/4th Stokes, HH, HV, VH, VV] - integer :: N_ang ! # angles in species + integer :: N_ang ! # satellite viewing angles in species (radiance obs only) real, & - dimension(N_obs_ang_max) :: ang ! vector of angles + dimension(N_obs_ang_max) :: ang ! vector of satellite viewing angles real :: freq ! frequency [Hz] From cf25d174ba181ac4069c5a593872d8930d36e304 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Thu, 21 Sep 2023 09:27:07 -0400 Subject: [PATCH 126/308] minor fix in comment about SCF_ANA_BETA parameter (clsm_ensupd_glob_param.F90) --- .../GEOSlandassim_GridComp/clsm_ensupd_glob_param.F90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_glob_param.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_glob_param.F90 index 72c5a509..96d72402 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_glob_param.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_glob_param.F90 @@ -110,8 +110,8 @@ module clsm_ensupd_glob_param ! ! parameters for snow cover area fraction (SCF) analysis (modified from Toure et al. 2018) - real, parameter :: SCF_ANA_ALPHA = 0.60 ! [-] add snow if asnow_fcst < asnow_obs*SCF_ANA_alpha (w/ "bias" adjustment for obs) - real, parameter :: SCF_ANA_BETA = 0.55 ! [-] remove snow if asnow_fcst > asnow_obs*SCF_ANA_alpha .AND. asnow_obs < SCF_ANA_beta + real, parameter :: SCF_ANA_ALPHA = 0.60 ! [-] add snow if asnow_fcst < asnow_obs*SCF_ANA_alpha (w/ "bias" adjustment for obs) + real, parameter :: SCF_ANA_BETA = 0.55 ! [-] remove snow if asnow_fcst >= asnow_obs*SCF_ANA_alpha .AND. asnow_obs < SCF_ANA_beta real, parameter :: SCF_ANA_MAXINCRSWE = 5.0 ! [kg/m2] max total SWE increment real, parameter :: SCF_ANA_MINFCSTSWE = 0.01 ! [kg/m2] threshold below which the ratio of swe_ana/swe_fcst becomes unreasonable From e02ac5f61367086bb2408b02a8668b3130d1f184 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Thu, 21 Sep 2023 11:40:31 -0400 Subject: [PATCH 127/308] fixed indentation (clsm_ensupd_enkf_update.F90) --- .../clsm_ensupd_enkf_update.F90 | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 index 3b532c76..e4160dea 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 @@ -1398,42 +1398,42 @@ subroutine apply_enkf_increments( N_catd, N_ens, update_type, & cat_progn(n,n_e)%tc2 + cat_progn_incr(n,n_e)%tc2 cat_progn(n,n_e)%tc4 = & cat_progn(n,n_e)%tc4 + cat_progn_incr(n,n_e)%tc4 - + cat_progn(n,n_e)%ght(1) = & cat_progn(n,n_e)%ght(1) + cat_progn_incr(n,n_e)%ght(1) - + end do end do cat_progn_has_changed = .true. - - case(11) select_update_type ! empirical MODIS SCF update + + case(11) select_update_type ! empirical MODIS SCF update do n=1,N_catd ! for each tile - + do n_e=1,N_ens ! for each ensemble member - + do ii=1,N_snow ! for each snow layer - + cat_progn(n,n_e)%wesn(ii) = & cat_progn(n,n_e)%wesn(ii) + cat_progn_incr(n,n_e)%wesn(ii) - + cat_progn(n,n_e)%sndz(ii) = & cat_progn(n,n_e)%sndz(ii) + cat_progn_incr(n,n_e)%sndz(ii) - + cat_progn(n,n_e)%htsn(ii) = & cat_progn(n,n_e)%htsn(ii) + cat_progn_incr(n,n_e)%htsn(ii) - + end do end do end do - + cat_progn_has_changed = .true. - + case default call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'unknown update_type') - + end select select_update_type ! ------------------------------------------------------------------ From 3f95ee02780cf30259b9a2ea85eceb000822a7e7 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Thu, 21 Sep 2023 12:36:20 -0600 Subject: [PATCH 128/308] Review response - change half-open interval comment - read_obs_SMAP_fnames -> read_obs_fnames - optional argument in read_obs_fnames to write YYYY/MM/filename - update date from string parse to reflect this change - add error out if maxobs exceeded - add /100. after initial read of errstd --- .../clsm_ensupd_read_obs.F90 | 90 +++++++++++-------- 1 file changed, 53 insertions(+), 37 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 3bd275da..02244e42 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -1619,7 +1619,7 @@ subroutine read_obs_sm_ASCAT_EUMET( & type(date_time_type) :: date_time_low, date_time_low_fname type(date_time_type) :: date_time_up - integer :: ii, ind, N_tmp, N_files, kk, N_obs, N_fnames, N_fnames_tmp + integer :: ii, ind, N_tmp, N_files, kk, N_obs, N_fnames, N_fnames_tmp, obs_dir_hier character(300), dimension(:), allocatable :: fnames, tmpfnames @@ -1630,8 +1630,8 @@ subroutine read_obs_sm_ASCAT_EUMET( & real*8, dimension(15) :: tmp_vdata integer, parameter :: lnbufr = 50 ! BUFR file unit number - integer, parameter :: max_rec = 20000 ! max number of obs after QC - integer, parameter :: max_obs = 250000 ! max number of obs read by subroutine + integer, parameter :: max_rec = 20000 ! max number of obs after QC (expecting < 6 hr assim window) + integer, parameter :: max_obs = 250000 ! max number of obs read by subroutine (expecting < 6 hr assim window) integer :: idate, iret, ireadmg, ireadsb @@ -1666,7 +1666,7 @@ subroutine read_obs_sm_ASCAT_EUMET( & found_obs = .false. ! find files that are within half-open interval - ! [date_time-dtstep_assim/2,date_time+dtstep_assim/2) + ! (date_time-dtstep_assim/2,date_time+dtstep_assim/2] date_time_low = date_time call augment_date_time( -(dtstep_assim/2), date_time_low) @@ -1684,19 +1684,21 @@ subroutine read_obs_sm_ASCAT_EUMET( & ! read file with list of ASCAT file names for first day fname_of_fname_list = 'dummy' ! make sure it is properly defined in obs_param nml + + obs_dir_hier = 1 - call read_obs_SMAP_fnames( date_time_low_fname, this_obs_param, & + call read_obs_fnames( date_time_low_fname, this_obs_param, & fname_of_fname_list, N_fnames_max, & - N_fnames, fname_list(1:N_fnames_max) ) + N_fnames, fname_list(1:N_fnames_max), obs_dir_hier ) ! if needed, read file with list of ASCAT file names for second day and add ! file names into "fname_list" if (date_time_low_fname%day /= date_time_up%day) then - call read_obs_SMAP_fnames( date_time_up, this_obs_param, & + call read_obs_fnames( date_time_up, this_obs_param, & fname_of_fname_list, N_fnames_max, & - N_fnames_tmp, fname_list((N_fnames+1):(N_fnames+N_fnames_max)) ) + N_fnames_tmp, fname_list((N_fnames+1):(N_fnames+N_fnames_max)), obs_dir_hier ) N_fnames = N_fnames + N_fnames_tmp @@ -1721,7 +1723,7 @@ subroutine read_obs_sm_ASCAT_EUMET( & ! 12345678901234567890123456789012345678901234567890123456789012345678901234567890 ! 1 2 3 4 5 6 7 - str_date_time = tmpfname(40:53) + str_date_time = tmpfname(36:49) read(str_date_time( 1: 4), *) date_time_tmp%year read(str_date_time( 5: 6), *) date_time_tmp%month @@ -1734,16 +1736,8 @@ subroutine read_obs_sm_ASCAT_EUMET( & datetime_le_refdatetime( date_time_tmp, date_time_up ) ) then N_tmp = N_tmp + 1 - - ! Remove the '/D03/' from the directory part as using "read_obs_SMAP_fnames" - - ind = index(tmpfname, "/D") - - if (ind > 0) then - tmpfname2 = tmpfname(1:ind) // tmpfname(ind+5:) - end if - tmpfnames(N_tmp) = trim(this_obs_param%path) // '/' // trim(tmpfname2) + tmpfnames(N_tmp) = trim(this_obs_param%path) // '/' // trim(tmpfname) end if @@ -1789,6 +1783,11 @@ subroutine read_obs_sm_ASCAT_EUMET( & N_obs = N_obs + 1 + if (N_obs > max_obs) then + err_msg = 'Attempting to read too many obs - how long is your assimilation window?' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + end if + tmp_data(N_obs,:) = tmp_vdata end do loop_report @@ -1819,7 +1818,7 @@ subroutine read_obs_sm_ASCAT_EUMET( & datetime_le_refdatetime( date_time_up, date_time_tmp ) ) cycle ! skip if record contains invalid soil moisture value - if ( tmp_data(kk, 7) > 100. .or. tmp_data(kk, 7) < 0. ) cycle + if ( tmp_data(kk, 7) > 100. .or. tmp_data(kk, 7) < 0. ) cycle ! EUMETSAT file contains data of both ascending and descending half-orbits. ! DOMO ("Direction of motion of moving observing platform") is used to separate Asc and Desc @@ -1944,16 +1943,15 @@ subroutine read_obs_sm_ASCAT_EUMET( & do ii=1,N_catd - ! set observation error standard deviation - - ASCAT_sm_std(ii) = this_obs_param%errstd/100. ! change units from percent (0-100) to fraction (0-1) + ! set observation error standard deviation if (N_obs_in_tile(ii)>1) then - ASCAT_sm( ii) = ASCAT_sm( ii)/real(N_obs_in_tile(ii)) - ASCAT_lon( ii) = ASCAT_lon( ii)/real(N_obs_in_tile(ii)) - ASCAT_lat( ii) = ASCAT_lat( ii)/real(N_obs_in_tile(ii)) - ASCAT_time(ii) = ASCAT_time(ii)/real(N_obs_in_tile(ii),kind(0.0D0)) + ASCAT_sm( ii) = ASCAT_sm( ii)/real(N_obs_in_tile(ii)) + ASCAT_lon( ii) = ASCAT_lon( ii)/real(N_obs_in_tile(ii)) + ASCAT_lat( ii) = ASCAT_lat( ii)/real(N_obs_in_tile(ii)) + ASCAT_time( ii) = ASCAT_time(ii)/real(N_obs_in_tile(ii),kind(0.0D0)) + ASCAT_sm_std(ii) = this_obs_param%errstd/100. ! change units from percent (0-100) to fraction (0-1) elseif (N_obs_in_tile(ii)==0) then @@ -5275,7 +5273,7 @@ subroutine read_obs_SMAP_FT( date_time, N_catd, this_obs_param, & ! read file with list of SMAP file names for first day - call read_obs_SMAP_fnames( date_time_low_fname, this_obs_param, & + call read_obs_fnames( date_time_low_fname, this_obs_param, & fname_of_fname_list, N_halforbits_max, & N_fnames, fname_list(1:N_halforbits_max) ) @@ -5284,7 +5282,7 @@ subroutine read_obs_SMAP_FT( date_time, N_catd, this_obs_param, & if (date_time_low_fname%day /= date_time_upp%day) then - call read_obs_SMAP_fnames( date_time_upp, this_obs_param, & + call read_obs_fnames( date_time_upp, this_obs_param, & fname_of_fname_list, N_halforbits_max, & N_fnames_tmp, fname_list((N_fnames+1):(N_fnames+N_halforbits_max)) ) @@ -6111,7 +6109,7 @@ subroutine read_obs_SMAP_halforbit_Tb( date_time, N_catd, this_obs_param, & ! read file with list of SMAP file names for first day - call read_obs_SMAP_fnames( date_time_low_fname, this_obs_param, & + call read_obs_fnames( date_time_low_fname, this_obs_param, & fname_of_fname_list, N_halforbits_max, & N_fnames, fname_list(1:N_halforbits_max) ) @@ -6120,7 +6118,7 @@ subroutine read_obs_SMAP_halforbit_Tb( date_time, N_catd, this_obs_param, & if (date_time_low_fname%day /= date_time_upp%day) then - call read_obs_SMAP_fnames( date_time_upp, this_obs_param, & + call read_obs_fnames( date_time_upp, this_obs_param, & fname_of_fname_list, N_halforbits_max, & N_fnames_tmp, fname_list((N_fnames+1):(N_fnames+N_halforbits_max)) ) @@ -7148,8 +7146,8 @@ end subroutine turn_off_assim_SMAP_L1CTb ! ***************************************************************** - subroutine read_obs_SMAP_fnames( date_time, this_obs_param, & - fname_of_fname_list, N_max, N_fnames, fname_list ) + subroutine read_obs_fnames( date_time, this_obs_param, & + fname_of_fname_list, N_max, N_fnames, fname_list, obs_dir_hier ) ! read the file within a SMAP Yyyyy/Mmm/Ddd directory that lists ! the SMAP h5 file names; preface file names with "Yyyyy/Mmm/Ddd" @@ -7165,13 +7163,15 @@ subroutine read_obs_SMAP_fnames( date_time, this_obs_param, & type(obs_param_type), intent(in) :: this_obs_param - character( *), intent(in) :: fname_of_fname_list + character( *), intent(in) :: fname_of_fname_list integer, intent(in) :: N_max integer, intent(out) :: N_fnames character(100), dimension(N_max), intent(out) :: fname_list + + integer, optional, intent(in) :: obs_dir_hier ! local variables @@ -7181,12 +7181,13 @@ subroutine read_obs_SMAP_fnames( date_time, this_obs_param, & character( 80) :: tmpstr80 character( 14) :: YYYYMMDDdir + character( 10) :: YYYYMMdir character( 4) :: YYYY character( 2) :: MM, DD integer :: ii, istat - character(len=*), parameter :: Iam = 'read_obs_SMAP_fnames' + character(len=*), parameter :: Iam = 'read_obs_fnames' character(len=400) :: err_msg ! --------------------------------------------------------------------- @@ -7196,6 +7197,7 @@ subroutine read_obs_SMAP_fnames( date_time, this_obs_param, & write (DD ,'(i2.2)') date_time%day YYYYMMDDdir = 'Y' // YYYY // '/M' // MM // '/D' // DD // '/' + YYYYMMdir = 'Y' // YYYY // '/M' // MM // '/' ! initialize default values @@ -7236,9 +7238,23 @@ subroutine read_obs_SMAP_fnames( date_time, this_obs_param, & call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) end if - ! preface file names with "Yyyyy/Mmm/Ddd" + if (present(obs_dir_hier) .and. obs_dir_hier == 1) then + + ! preface file names with "Yyyyy/Mmm" + + fname_list(ii) = YYYYMMdir // trim(tmpstr80) + + elseif (present(obs_dir_hier) .and. obs_dir_hier /= 1) then + + err_msg = 'Unrecognized obs_dir_hier #' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) - fname_list(ii) = YYYYMMDDdir // trim(tmpstr80) + else + ! preface file names with "Yyyyy/Mmm/Ddd" Default for SMAP obs + + fname_list(ii) = YYYYMMDDdir // trim(tmpstr80) + + end if else @@ -7252,7 +7268,7 @@ subroutine read_obs_SMAP_fnames( date_time, this_obs_param, & N_fnames = ii - end subroutine read_obs_SMAP_fnames + end subroutine read_obs_fnames ! ***************************************************************** From 546b0c67ef3aaae425fc901802789e2731eb3754 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Fri, 22 Sep 2023 13:10:12 -0600 Subject: [PATCH 129/308] Remove asc v desc species differentiation - remove bufr read of DOMO and its use to differentiate orbits in qc - update default nml for three species - change error to 9% in nml - change N_obs_species_nml to 51 --- .../LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml | 145 ++---------------- .../clsm_ensupd_glob_param.F90 | 2 +- .../clsm_ensupd_read_obs.F90 | 80 +++------- 3 files changed, 42 insertions(+), 185 deletions(-) diff --git a/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml b/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml index 826f568a..43d2e800 100644 --- a/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml +++ b/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml @@ -2066,12 +2066,12 @@ obs_param_nml(48)%adapt = 0 ! -------------------------------------------------------------------- ! -! 49 = ASCAT_META_SM_A (ASCAT soil moisture ascending) +! 49 = ASCAT_META_SM (ASCAT soil moisture ascending and descending orbits) ! ! https://navigator.eumetsat.int/product/EO:EUM:DAT:METOP:SOMO25 -obs_param_nml(49)%descr = 'ASCAT_META_SM_A' -obs_param_nml(49)%orbit = 1 +obs_param_nml(49)%descr = 'ASCAT_META_SM' +obs_param_nml(49)%orbit = 3 obs_param_nml(49)%pol = 0 obs_param_nml(49)%N_ang = 0 obs_param_nml(49)%freq = 0 @@ -2093,7 +2093,7 @@ obs_param_nml(49)%scalepath = '' obs_param_nml(49)%scalename = '' obs_param_nml(49)%flistpath = '' obs_param_nml(49)%flistname = '' -obs_param_nml(49)%errstd = .04 +obs_param_nml(49)%errstd = 9. obs_param_nml(49)%std_normal_max = 2.5 obs_param_nml(49)%zeromean = .true. obs_param_nml(49)%coarsen_pert = .false. @@ -2101,14 +2101,14 @@ obs_param_nml(49)%xcorr = 0.25 obs_param_nml(49)%ycorr = 0.25 obs_param_nml(49)%adapt = 0 -! ------------------- +! -------------------------------------------------------------------- ! -! 50 = ASCAT_META_SM_D (ASCAT soil moisture descending) +! 50 = ASCAT_METB_SM (ASCAT soil moisture ascending and descending orbits) ! ! https://navigator.eumetsat.int/product/EO:EUM:DAT:METOP:SOMO25 -obs_param_nml(50)%descr = 'ASCAT_META_SM_D' -obs_param_nml(50)%orbit = 2 +obs_param_nml(50)%descr = 'ASCAT_METB_SM' +obs_param_nml(50)%orbit = 3 obs_param_nml(50)%pol = 0 obs_param_nml(50)%N_ang = 0 obs_param_nml(50)%freq = 0 @@ -2124,13 +2124,13 @@ obs_param_nml(50)%bias_tcut = 432000 obs_param_nml(50)%nodata = -9999. obs_param_nml(50)%varname = 'sfds' obs_param_nml(50)%units = '%' -obs_param_nml(50)%path = '/discover/nobackup/projects/gmao/merra/iau/merra_land/DATA/ASCAT_EUMETSAT/Metop_A/' -obs_param_nml(50)%name = 'M02-ASCA-ASCSMO02' +obs_param_nml(50)%path = '/discover/nobackup/projects/gmao/merra/iau/merra_land/DATA/ASCAT_EUMETSAT/Metop_B/' +obs_param_nml(50)%name = 'M01-ASCA-ASCSMO02' obs_param_nml(50)%scalepath = '' obs_param_nml(50)%scalename = '' obs_param_nml(50)%flistpath = '' obs_param_nml(50)%flistname = '' -obs_param_nml(50)%errstd = .04 +obs_param_nml(50)%errstd = 9. obs_param_nml(50)%std_normal_max = 2.5 obs_param_nml(50)%zeromean = .true. obs_param_nml(50)%coarsen_pert = .false. @@ -2140,12 +2140,12 @@ obs_param_nml(50)%adapt = 0 ! -------------------------------------------------------------------- ! -! 51 = ASCAT_METB_SM_A (ASCAT soil moisture ascending) +! 51 = ASCAT_METC_SM (ASCAT soil moisture ascending and descending orbits) ! ! https://navigator.eumetsat.int/product/EO:EUM:DAT:METOP:SOMO25 -obs_param_nml(51)%descr = 'ASCAT_METB_SM_A' -obs_param_nml(51)%orbit = 1 +obs_param_nml(51)%descr = 'ASCAT_METC_SM' +obs_param_nml(51)%orbit = 3 obs_param_nml(51)%pol = 0 obs_param_nml(51)%N_ang = 0 obs_param_nml(51)%freq = 0 @@ -2161,13 +2161,13 @@ obs_param_nml(51)%bias_tcut = 432000 obs_param_nml(51)%nodata = -9999. obs_param_nml(51)%varname = 'sfds' obs_param_nml(51)%units = '%' -obs_param_nml(51)%path = '/discover/nobackup/projects/gmao/merra/iau/merra_land/DATA/ASCAT_EUMETSAT/Metop_B/' -obs_param_nml(51)%name = 'M01-ASCA-ASCSMO02' +obs_param_nml(51)%path = '/discover/nobackup/projects/gmao/merra/iau/merra_land/DATA/ASCAT_EUMETSAT/Metop_C/' +obs_param_nml(51)%name = 'M03-ASCA-ASCSMO02' obs_param_nml(51)%scalepath = '' obs_param_nml(51)%scalename = '' obs_param_nml(51)%flistpath = '' obs_param_nml(51)%flistname = '' -obs_param_nml(51)%errstd = .04 +obs_param_nml(51)%errstd = 9. obs_param_nml(51)%std_normal_max = 2.5 obs_param_nml(51)%zeromean = .true. obs_param_nml(51)%coarsen_pert = .false. @@ -2175,117 +2175,6 @@ obs_param_nml(51)%xcorr = 0.25 obs_param_nml(51)%ycorr = 0.25 obs_param_nml(51)%adapt = 0 -! ------------------- -! -! 52 = ASCAT_METB_SM_D (ASCAT soil moisture descending) -! -! https://navigator.eumetsat.int/product/EO:EUM:DAT:METOP:SOMO25 - -obs_param_nml(52)%descr = 'ASCAT_METB_SM_D' -obs_param_nml(52)%orbit = 2 -obs_param_nml(52)%pol = 0 -obs_param_nml(52)%N_ang = 0 -obs_param_nml(52)%freq = 0 -obs_param_nml(52)%FOV = 20. -obs_param_nml(52)%FOV_units = 'km' -obs_param_nml(52)%assim = .false. -obs_param_nml(52)%scale = .false. -obs_param_nml(52)%getinnov = .false. -obs_param_nml(52)%RTM_ID = 0 -obs_param_nml(52)%bias_Npar = 0 -obs_param_nml(52)%bias_trel = 864000 -obs_param_nml(52)%bias_tcut = 432000 -obs_param_nml(52)%nodata = -9999. -obs_param_nml(52)%varname = 'sfds' -obs_param_nml(52)%units = '%' -obs_param_nml(52)%path = '/discover/nobackup/projects/gmao/merra/iau/merra_land/DATA/ASCAT_EUMETSAT/Metop_B/' -obs_param_nml(52)%name = 'M01-ASCA-ASCSMO02' -obs_param_nml(52)%scalepath = '' -obs_param_nml(52)%scalename = '' -obs_param_nml(52)%flistpath = '' -obs_param_nml(52)%flistname = '' -obs_param_nml(52)%errstd = .04 -obs_param_nml(52)%std_normal_max = 2.5 -obs_param_nml(52)%zeromean = .true. -obs_param_nml(52)%coarsen_pert = .false. -obs_param_nml(52)%xcorr = 0.25 -obs_param_nml(52)%ycorr = 0.25 -obs_param_nml(52)%adapt = 0 - -! -------------------------------------------------------------------- -! -! 53 = ASCAT_METC_SM_A (ASCAT soil moisture ascending) -! -! https://navigator.eumetsat.int/product/EO:EUM:DAT:METOP:SOMO25 - -obs_param_nml(53)%descr = 'ASCAT_METC_SM_A' -obs_param_nml(53)%orbit = 1 -obs_param_nml(53)%pol = 0 -obs_param_nml(53)%N_ang = 0 -obs_param_nml(53)%freq = 0 -obs_param_nml(53)%FOV = 20. -obs_param_nml(53)%FOV_units = 'km' -obs_param_nml(53)%assim = .false. -obs_param_nml(53)%scale = .false. -obs_param_nml(53)%getinnov = .false. -obs_param_nml(53)%RTM_ID = 0 -obs_param_nml(53)%bias_Npar = 0 -obs_param_nml(53)%bias_trel = 864000 -obs_param_nml(53)%bias_tcut = 432000 -obs_param_nml(53)%nodata = -9999. -obs_param_nml(53)%varname = 'sfds' -obs_param_nml(53)%units = '%' -obs_param_nml(53)%path = '/discover/nobackup/projects/gmao/merra/iau/merra_land/DATA/ASCAT_EUMETSAT/Metop_C/' -obs_param_nml(53)%name = 'M03-ASCA-ASCSMO02' -obs_param_nml(53)%scalepath = '' -obs_param_nml(53)%scalename = '' -obs_param_nml(53)%flistpath = '' -obs_param_nml(53)%flistname = '' -obs_param_nml(53)%errstd = .04 -obs_param_nml(53)%std_normal_max = 2.5 -obs_param_nml(53)%zeromean = .true. -obs_param_nml(53)%coarsen_pert = .false. -obs_param_nml(53)%xcorr = 0.25 -obs_param_nml(53)%ycorr = 0.25 -obs_param_nml(53)%adapt = 0 - -! ------------------- -! -! 54 = ASCAT_METC_SM_D (ASCAT soil moisture descending) -! -! https://navigator.eumetsat.int/product/EO:EUM:DAT:METOP:SOMO25 - -obs_param_nml(54)%descr = 'ASCAT_METC_SM_D' -obs_param_nml(54)%orbit = 2 -obs_param_nml(54)%pol = 0 -obs_param_nml(54)%N_ang = 0 -obs_param_nml(54)%freq = 0 -obs_param_nml(54)%FOV = 20. -obs_param_nml(54)%FOV_units = 'km' -obs_param_nml(54)%assim = .false. -obs_param_nml(54)%scale = .false. -obs_param_nml(54)%getinnov = .false. -obs_param_nml(54)%RTM_ID = 0 -obs_param_nml(54)%bias_Npar = 0 -obs_param_nml(54)%bias_trel = 864000 -obs_param_nml(54)%bias_tcut = 432000 -obs_param_nml(54)%nodata = -9999. -obs_param_nml(54)%varname = 'sfds' -obs_param_nml(54)%units = '%' -obs_param_nml(54)%path = '/discover/nobackup/projects/gmao/merra/iau/merra_land/DATA/ASCAT_EUMETSAT/Metop_C/' -obs_param_nml(54)%name = 'M03-ASCA-ASCSMO02' -obs_param_nml(54)%scalepath = '' -obs_param_nml(54)%scalename = '' -obs_param_nml(54)%flistpath = '' -obs_param_nml(54)%flistname = '' -obs_param_nml(54)%errstd = .04 -obs_param_nml(54)%std_normal_max = 2.5 -obs_param_nml(54)%zeromean = .true. -obs_param_nml(54)%coarsen_pert = .false. -obs_param_nml(54)%xcorr = 0.25 -obs_param_nml(54)%ycorr = 0.25 -obs_param_nml(54)%adapt = 0 - ! -------------------------------------------------------------------- / diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_glob_param.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_glob_param.F90 index 278fb5e8..b1a22716 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_glob_param.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_glob_param.F90 @@ -44,7 +44,7 @@ module clsm_ensupd_glob_param ! total number of all obs species defined in namelist file ! (regardless of whether "assim" flag is true or false) - integer, parameter :: N_obs_species_nml = 54 + integer, parameter :: N_obs_species_nml = 51 ! ---------------------------------------------------------------------- ! diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 02244e42..d4616d9b 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -1759,7 +1759,7 @@ subroutine read_obs_sm_ASCAT_EUMET( & allocate(tmp1_obs( max_rec )) allocate(tmp1_jtime(max_rec )) - allocate(tmp_data( max_obs,15)) + allocate(tmp_data( max_obs,14)) N_obs = 0 @@ -1777,9 +1777,9 @@ subroutine read_obs_sm_ASCAT_EUMET( & loop_report: do while( ireadsb(lnbufr) == 0 ) - ! columns of tmp_data: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + ! columns of tmp_data: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 - call ufbint(lnbufr,tmp_vdata,15,1,iret,'YEAR MNTH DAYS HOUR MINU SECO SSOM DOMO SMPF SMCF ALFR TPCX IWFR CLATH CLONH') + call ufbint(lnbufr,tmp_vdata,15,1,iret,'YEAR MNTH DAYS HOUR MINU SECO SSOM SMPF SMCF ALFR TPCX IWFR CLATH CLONH') N_obs = N_obs + 1 @@ -1826,30 +1826,35 @@ subroutine read_obs_sm_ASCAT_EUMET( & ! According to Pamela Schoebel-Pattiselanno, EUMETSAT User Services Helpdesk: ! "When the value (of DOMO) is between 180 and 270 degrees, it is the descending part ! of the orbit. When it is between 270 and 360 degrees, it is the ascending part." - if (index(this_obs_param%descr,'_A') /=0 .and. (tmp_data(kk, 8) < 270 .or. tmp_data(kk, 8) > 360)) cycle - if (index(this_obs_param%descr,'_D') /=0 .and. (tmp_data(kk, 8) < 180 .or. tmp_data(kk, 8) >= 270)) cycle + ! if (index(this_obs_param%descr,'_A') /=0 .and. (tmp_data(kk, 8) < 270 .or. tmp_data(kk, 8) > 360)) cycle + ! if (index(this_obs_param%descr,'_D') /=0 .and. (tmp_data(kk, 8) < 180 .or. tmp_data(kk, 8) >= 270)) cycle ! skip if processing flag is set - if(int(tmp_data(kk, 9)) /= 0) cycle + if(int(tmp_data(kk, 8)) /= 0) cycle ! skip if correction flag is set ("good" values are 0 and 4) - if (.not. ( (int(tmp_data(kk, 10)) == 0) .or. (int(tmp_data(kk, 10)) == 4)) ) cycle + if (.not. ( (int(tmp_data(kk, 9)) == 0) .or. (int(tmp_data(kk, 9)) == 4)) ) cycle ! skip if land fraction is missing or < 0.9 - if(tmp_data(kk, 11) > 1. .or. tmp_data(kk, 11) < 0.9 ) cycle + if(tmp_data(kk, 10) > 1. .or. tmp_data(kk, 10) < 0.9 ) cycle ! skip if topographic complexity > 10% - if(tmp_data(kk, 12) > 10.) cycle + if(tmp_data(kk, 11) > 10.) cycle ! skip if inundation and wetland fraction > 10% - if(tmp_data(kk, 13) > 10.) cycle + if(tmp_data(kk, 12) > 10.) cycle N_tmp = N_tmp + 1 ! passed all QC + + if (N_tmp > max_rec) then + err_msg = 'Too many obs have passed QC - how long is your assimilation window?' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + end if tmp1_jtime(N_tmp) = datetime_to_J2000seconds( date_time_tmp, J2000_epoch_id ) - tmp1_lat( N_tmp) = tmp_data(kk, 14) - tmp1_lon( N_tmp) = tmp_data(kk, 15) + tmp1_lat( N_tmp) = tmp_data(kk, 13) + tmp1_lon( N_tmp) = tmp_data(kk, 14) tmp1_obs( N_tmp) = tmp_data(kk, 7)/100. ! change units from percent (0-100) to fraction (0-1) @@ -1985,13 +1990,6 @@ subroutine read_obs_sm_ASCAT_EUMET( & end if - ! call system_clock(clock_end, clock_rate) ! Stop timing - ! elapsed_time_sr=(real(clock_end-clock_start_sr)/real(clock_rate)) - ! write (logunit,*) 'Elapsed time in read_obs_sm_ASCAT_EUMET: ', elapsed_time, ' seconds' - - ! elapsed_time = (elapsed_time/elapsed_time_sr)*100 - ! write (logunit,*) 'We spent ', elapsed_time, '% of time in bufr read' - ! clean up if (associated(tmp_obs)) deallocate(tmp_obs) @@ -7429,9 +7427,6 @@ subroutine read_obs( & character(len=*), parameter :: Iam = 'read_obs' character(len=400) :: err_msg - integer :: clock_start, clock_end, clock_rate - real(8) :: elapsed_time - ! ------------------------------------------------------------- scaled_obs = .false. ! initialize @@ -7517,10 +7512,8 @@ subroutine read_obs( & end if - case ('ASCAT_META_SM_A', 'ASCAT_META_SM_D','ASCAT_METB_SM_A', 'ASCAT_METB_SM_D','ASCAT_METC_SM_A', 'ASCAT_METC_SM_D' ) + case ('ASCAT_META_SM','ASCAT_METB_SM','ASCAT_METC_SM' ) - call system_clock(clock_start) ! Start timing - call read_obs_sm_ASCAT_EUMET( & date_time, dtstep_assim, N_catd, tile_coord, & tile_grid_d, N_tile_in_cell_ij, tile_num_in_cell_ij, & @@ -7539,12 +7532,6 @@ subroutine read_obs( & end if - - call system_clock(clock_end, clock_rate) ! Stop timing - elapsed_time=(real(clock_end-clock_start)/real(clock_rate)) - write (logunit,*) '**** Elapsed time in obs_read: ', elapsed_time, ' seconds ****' - - case ('isccp_tskin_gswp2_v1') call read_obs_isccp_tskin_gswp2_v1( & @@ -7717,8 +7704,6 @@ subroutine read_obs( & 'SMAP_L1C_Tbh_E27_D', 'SMAP_L1C_Tbv_E27_D', & 'SMAP_L2AP_Tbh_A', 'SMAP_L2AP_Tbv_A', & 'SMAP_L2AP_Tbh_D', 'SMAP_L2AP_Tbv_D' ) - - call system_clock(clock_start) call read_obs_SMAP_halforbit_Tb( & date_time, N_catd, this_obs_param, & @@ -7736,10 +7721,6 @@ subroutine read_obs( & this_obs_param, tmp_obs, tmp_std_obs, tmp_assim ) end if - - call system_clock(clock_end, clock_rate) ! Stop timi - elapsed_time=(real(clock_end-clock_start)/real(clock_rate)) - write (logunit,*) '**** Elapsed time in obs_read: ', elapsed_time, ' seconds ****' case('LaRC_tskin-GOESW', 'LaRC_tskin-GOESE', 'LaRC_tskin-MET09', & 'LaRC_tskin-FY2E-', 'LaRC_tskin-MTST2') @@ -8240,27 +8221,22 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & integer :: o_mean_varid, o_std_varid, m_mean_varid, m_std_varid integer, dimension(3) :: start, icount -integer :: clock_start, clock_end, clock_rate -real(8) :: elapsed_time - real :: tmpreal, this_lon, this_lat integer, dimension(:), allocatable :: sclprm_tile_id integer, dimension(:), allocatable :: pentads -real, dimension(:), allocatable :: sclprm_lon, sclprm_lat -real, dimension(:,:), allocatable :: sclprm_mean_obs, sclprm_std_obs -real, dimension(:,:), allocatable :: sclprm_mean_mod, sclprm_std_mod +real, dimension(:), allocatable :: sclprm_lon, sclprm_lat +real, dimension(:,:), allocatable :: sclprm_mean_obs, sclprm_std_obs +real, dimension(:,:), allocatable :: sclprm_mean_mod, sclprm_std_mod -character(len=*), parameter :: Iam = ' scale_obs_sfmc_zscore' +character(len=*), parameter :: Iam = ' scale_obs_sfmc_zscore' character(len=400) :: err_msg ! ------------------------------------------------------------------ ! read scaling parameters from file -call system_clock(clock_start) ! Start timing - fname = trim(this_obs_param%scalepath) // '/' // & trim(this_obs_param%scalename) // '.nc4' @@ -8334,11 +8310,7 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & ! ! sanity check (against accidental use of wrong tile space) if ( abs(tile_coord(i)%com_lat-sclprm_lat(j_ind))>tol .or. & - abs(tile_coord(i)%com_lon-sclprm_lon(i_ind))>tol ) then - if (logit) write (logunit,*) 'ierr2, i = ', ierr2, i - if (logit) write (logunit,*) 'start, icount', start, icount - if (logit) write (logunit,*) 'tile_coord(i)%com_lat, this_lat, sclprm_lat(j_ind)', tile_coord(i)%com_lat, this_lat, sclprm_lat(j_ind) - if (logit) write (logunit,*) 'tile_coord(i)%com_lon, this_lon, sclprm_lon(i_ind)', tile_coord(i)%com_lon, this_lon, sclprm_lon(i_ind) + abs(tile_coord(i)%com_lon-sclprm_lon(i_ind))>tol ) then err_msg = 'something wrong' call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) end if @@ -8357,7 +8329,7 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & tmp_obs(i) = sclprm_mean_mod(j_ind, i_ind) & + tmpreal*(tmp_obs(i)-sclprm_mean_obs(j_ind, i_ind)) - + ! scale observation error std tmp_std_obs(i) = tmpreal*tmp_std_obs(i) @@ -8379,10 +8351,6 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & deallocate(sclprm_mean_mod) deallocate(sclprm_std_mod) -call system_clock(clock_end, clock_rate) ! Stop timing -elapsed_time=(real(clock_end-clock_start)/real(clock_rate)) -write (logunit,*) 'Elapsed time in scale_obs_sfmc_zscore: ', elapsed_time, ' seconds' - end subroutine scale_obs_sfmc_zscore ! ******************************************************************************** From 01d41bce3b0cf22ac63aca300ef295dba2bf1dc7 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Fri, 22 Sep 2023 13:29:04 -0600 Subject: [PATCH 130/308] Fix dimension size in ufbint call --- .../GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index d4616d9b..6df6e8eb 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -1779,7 +1779,7 @@ subroutine read_obs_sm_ASCAT_EUMET( & ! columns of tmp_data: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 - call ufbint(lnbufr,tmp_vdata,15,1,iret,'YEAR MNTH DAYS HOUR MINU SECO SSOM SMPF SMCF ALFR TPCX IWFR CLATH CLONH') + call ufbint(lnbufr,tmp_vdata,14,1,iret,'YEAR MNTH DAYS HOUR MINU SECO SSOM SMPF SMCF ALFR TPCX IWFR CLATH CLONH') N_obs = N_obs + 1 From 012c979e13d4f41952188728ede21afe9d48faaa Mon Sep 17 00:00:00 2001 From: "Lauren C. Andrews" Date: Fri, 22 Sep 2023 16:06:08 -0400 Subject: [PATCH 131/308] updated snow depth increment calculation --- .../GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index 4f40b1b7..55296a1b 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -4604,15 +4604,15 @@ subroutine cat_enkf_increments( & tmp_htsn(kk,n_e,isnow) = cat_progn(kk,n_e)%htsn(isnow) * swe_ratio ! What if fcst snow is at 0 deg C and contains liquid water? TBD reichle 20221007, could update as: !tmp_htsn(kk, n_e, isnow) = (cpw * tpsn(kkm n_e, isnow) - fices(kk, n_e, isnow) * MAPL_ALHF) * tmp_wesn(kk, n_e, isnow) - if (asnow_ana < 1.) then + if (asnow_ana < 1. .and. asnow_fcst < 1.) then tmp_sndz(kk,n_e,isnow) = cat_progn(kk,n_e)%sndz(isnow) ! snow depth remains constant b/c swe_ana<1. else - ! compute analysis snow depth from (layer-specific) forecast snow density + ! compute analysis snow depth from (layer-specific) forecast snow density with inclusion of ansnow_ana to correctly parse snow depth - tmp_sndz(kk,n_e,isnow) = tmp_wesn(kk,n_e,isnow) / ( cat_progn(kk,n_e)%wesn(isnow) / cat_progn(kk,n_e)%sndz(isnow) ) + tmp_sndz(kk,n_e,isnow) = tmp_wesn(kk,n_e,isnow) / ( cat_progn(kk,n_e)%wesn(isnow) / cat_progn(kk,n_e)%sndz(isnow) ) / asnow_ana end if From bd3bd06bd198c3a4419526689b4019b435997199 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Fri, 22 Sep 2023 14:24:18 -0600 Subject: [PATCH 132/308] fix tmp_vdata dimension --- .../GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 6df6e8eb..e0fa55b0 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -1627,7 +1627,7 @@ subroutine read_obs_sm_ASCAT_EUMET( & ! ! variables for BUFR read - real*8, dimension(15) :: tmp_vdata + real*8, dimension(14) :: tmp_vdata integer, parameter :: lnbufr = 50 ! BUFR file unit number integer, parameter :: max_rec = 20000 ! max number of obs after QC (expecting < 6 hr assim window) From aad96aa1176f8c3098c74efd17578c7e1c72c5ba Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Fri, 22 Sep 2023 17:50:03 -0400 Subject: [PATCH 133/308] additional clean-up of ASCAT EUMETSAT BUFR reader --- .../LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml | 2 +- .../clsm_ensupd_read_obs.F90 | 477 +++++++++--------- .../GEOSldas_GridComp/Shared/enkf_types.F90 | 7 +- 3 files changed, 248 insertions(+), 238 deletions(-) diff --git a/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml b/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml index 43d2e800..b2266730 100644 --- a/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml +++ b/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml @@ -83,7 +83,7 @@ fcsterr_inflation_fac = -9999. ! 0 = n/a [eg., in situ obs] ! 1 = ascending ! 2 = descending -! 3 = ascending and descending +! 3 = ascending or descending ! 4 = geostationary ! %pol = polarization ! 0 = n/a [eg., multi-pol. retrieval] diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index e0fa55b0..8845f1ea 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -1559,13 +1559,21 @@ subroutine read_obs_sm_ASCAT_EUMET( & !--------------------------------------------------------------------- ! - ! Routine to read in ASCAT surface degree of saturation (sfds) obs. + ! Routine to read in ASCAT surface degree of saturation (sfds) obs from + ! BUFR files that both ascending and descending passes. + ! + ! ASCAT_sm and ASCAT_sm_std outputs from this subroutine are in wetness fraction (i.e., 0-1) units! ! ! Read in EUMETSAT level 2 soil moisture product 25 km (SMO), PPF software version 5.0. - ! Data correspond to re-sampled (spatially averaged) backscatter (sigma0) values - ! on a 25-km orbit swath grid. Input data files are in BUFR file format. + ! Data correspond to re-sampled (spatially averaged) backscatter (sigma0) values + ! on a 25-km orbit swath grid. Input data files are in BUFR file format. ! - ! ASCAT_sm and ASCAT_sm_std outputs are in wetness fraction (i.e., 0-1) units! + ! EUMETSAT BUFR files contain data for both ascending and descending half-orbits. + ! The BUFR field DOMO ("Direction of motion of moving observing platform") could be used to + ! separate Asc and Desc. (The BUFR files do not contain any explicit orbit indicator variable.) + ! According to Pamela Schoebel-Pattiselanno, EUMETSAT User Services Helpdesk: + ! "When the value (of DOMO) is between 180 and 270 degrees, it is the descending part + ! of the orbit. When it is between 270 and 360 degrees, it is the ascending part." ! ! Q. Liu, Nov 2019 - based on read_obs_sm_ASCAT ! A. Fox, reichle, Sep 2023 - updated @@ -1771,7 +1779,7 @@ subroutine read_obs_sm_ASCAT_EUMET( & open(lnbufr, file=trim(fnames(kk)), action='read', form='unformatted') call openbf(lnbufr, 'SEC3', lnbufr) call mtinfo( trim(this_obs_param%path) // '/BUFR_mastertable/', lnbufr+1, lnbufr+2) - call datelen(10) + call datelen(10) ! select date/time format with 4-digit year (YYYYMMDDHH) msg_report: do while( ireadmg(lnbufr,subset,idate) == 0 ) @@ -1820,12 +1828,11 @@ subroutine read_obs_sm_ASCAT_EUMET( & ! skip if record contains invalid soil moisture value if ( tmp_data(kk, 7) > 100. .or. tmp_data(kk, 7) < 0. ) cycle - ! EUMETSAT file contains data of both ascending and descending half-orbits. - ! DOMO ("Direction of motion of moving observing platform") is used to separate Asc and Desc - ! because the file doesn't contain any explicit orbit indicator variable. - ! According to Pamela Schoebel-Pattiselanno, EUMETSAT User Services Helpdesk: - ! "When the value (of DOMO) is between 180 and 270 degrees, it is the descending part - ! of the orbit. When it is between 270 and 360 degrees, it is the ascending part." + ! to distinguish orbit directions, must read "DOMO" from BUFR file + ! + ! 180 <= DOMO < 270 : descending + ! 270 < DOMO <= 360 : ascending + ! ! if (index(this_obs_param%descr,'_A') /=0 .and. (tmp_data(kk, 8) < 270 .or. tmp_data(kk, 8) > 360)) cycle ! if (index(this_obs_param%descr,'_D') /=0 .and. (tmp_data(kk, 8) < 180 .or. tmp_data(kk, 8) >= 270)) cycle @@ -7145,13 +7152,23 @@ end subroutine turn_off_assim_SMAP_L1CTb ! ***************************************************************** subroutine read_obs_fnames( date_time, this_obs_param, & - fname_of_fname_list, N_max, N_fnames, fname_list, obs_dir_hier ) + fname_of_fname_list, N_max, N_fnames, fname_list, & + obs_dir_hier ) - ! read the file within a SMAP Yyyyy/Mmm/Ddd directory that lists - ! the SMAP h5 file names; preface file names with "Yyyyy/Mmm/Ddd" + ! read the file within an obs Yyyyy/Mmm/Ddd directory that lists + ! the obs file names, preface file names with "Yyyyy/Mmm/Ddd", + ! and return in "fname_list" + ! + ! optional input argument: + ! obs_dir_hier==1 : preface file names with "Yyyyy/Mmm" instead + ! + ! this subroutine is needed when obs file names cannot be predicted + ! and must be provided in a short text file that lists the file names + ! (e.g., SMAP Tb or soil moisture h5 files, ASCAT soil moisture BUFR files) ! ! reichle, 3 Jan 2014 ! reichle, 8 Jun 2017: Use "%flistpath" and "%flistname" from "obs_param_type". + ! A M Fox, reichle, 22 Sep 2023: added optional argument obs_dir_hier ! ! --------------------------------------------------------------------------------- @@ -7168,7 +7185,7 @@ subroutine read_obs_fnames( date_time, this_obs_param, & integer, intent(out) :: N_fnames character(100), dimension(N_max), intent(out) :: fname_list - + integer, optional, intent(in) :: obs_dir_hier ! local variables @@ -7236,28 +7253,30 @@ subroutine read_obs_fnames( date_time, this_obs_param, & call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) end if - if (present(obs_dir_hier) .and. obs_dir_hier == 1) then - - ! preface file names with "Yyyyy/Mmm" - - fname_list(ii) = YYYYMMdir // trim(tmpstr80) - - elseif (present(obs_dir_hier) .and. obs_dir_hier /= 1) then - - err_msg = 'Unrecognized obs_dir_hier #' - call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) - - else - ! preface file names with "Yyyyy/Mmm/Ddd" Default for SMAP obs - - fname_list(ii) = YYYYMMDDdir // trim(tmpstr80) + ! preface file names with "Yyyyy/Mmm/Ddd" (default) + + fname_list(ii) = YYYYMMDDdir // trim(tmpstr80) + if (present(obs_dir_hier)) then + + if (obs_dir_hier == 1) then + + ! preface file names with "Yyyyy/Mmm" + + fname_list(ii) = YYYYMMdir // trim(tmpstr80) + + else + + err_msg = 'Unrecognized value of optional argument obs_dir_hier' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + + end if end if else exit - + end if end do @@ -7518,7 +7537,8 @@ subroutine read_obs( & date_time, dtstep_assim, N_catd, tile_coord, & tile_grid_d, N_tile_in_cell_ij, tile_num_in_cell_ij, & this_obs_param, & - found_obs, tmp_obs, tmp_std_obs, tmp_lon, tmp_lat, tmp_time) + found_obs, tmp_obs, tmp_std_obs, tmp_lon, tmp_lat, & + tmp_time) ! scale observations to model climatology @@ -7526,9 +7546,9 @@ subroutine read_obs( & scaled_obs = .true. - call scale_obs_sfmc_zscore( N_catd, tile_coord, & - date_time, this_obs_param, tmp_obs, & - tmp_std_obs, tmp_lon, tmp_lat, tmp_time ) + call scale_obs_sfmc_zscore( N_catd, tile_coord, & + date_time, this_obs_param, tmp_lon, tmp_lat, tmp_time, & + tmp_obs, tmp_std_obs ) end if @@ -8148,211 +8168,196 @@ end subroutine scale_obs_tskin_zscore ! ***************************************************************** - subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & - date_time, this_obs_param, tmp_obs, & - tmp_std_obs, tmp_lon, tmp_lat, tmp_time) - -! scale tskin obs to model climatology via standard-normal-deviate (zscore) -! scaling -! -! use matlab functions "get_cdf_match_AMSR.m" and "get_model_and_obs_stats.m" -! to create input scaling files -! -! IMPORTANT: Make sure that model and obs data are in the SAME UNITS prior -! to generating the input scaling files with the matlab routines. - -! reichle, 14 Oct 2005 -! -! reichle, 22 Nov 2011 - renamed subroutine, minor clean-up, added comments -! -! Modified for ASCAT observations A M Fox, April 2023, - - -use netcdf -implicit none - -integer, intent(in) :: N_catd - -real, intent(in), dimension(N_catd) :: tmp_lon, tmp_lat -real*8, intent(in), dimension(N_catd) :: tmp_time ! J2000 seconds + subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & + date_time, this_obs_param, tmp_lon, tmp_lat, tmp_time, & + tmp_obs, tmp_std_obs ) -type(tile_coord_type), dimension(:), pointer :: tile_coord ! input - -type(date_time_type), intent(in) :: date_time - -type(obs_param_type), intent(in) :: this_obs_param - -! inout - -real, intent(inout), dimension(N_catd) :: tmp_obs -real, intent(inout), dimension(N_catd) :: tmp_std_obs + ! scale sfmc obs to model climatology via standard-normal-deviate (zscore) + ! scaling using seasonally varying (pentad) stats + ! + ! scaling parameters are on 0.25 deg lat/lon grid + ! + ! intended for scaling of ASCAT "sfds" observations + ! + ! A M Fox, reichle, April 2023 + + use netcdf + implicit none + + integer, intent(in) :: N_catd + + type(tile_coord_type), dimension(:), pointer :: tile_coord ! input + + type(date_time_type), intent(in) :: date_time + + type(obs_param_type), intent(in) :: this_obs_param -! ---------------------------------------------------------- + real, intent(in), dimension(N_catd) :: tmp_lon, tmp_lat + real*8, intent(in), dimension(N_catd) :: tmp_time ! J2000 seconds + + ! inout + + real, intent(inout), dimension(N_catd) :: tmp_obs + real, intent(inout), dimension(N_catd) :: tmp_std_obs + + ! ---------------------------------------------------------- ! Grid and netcdf parameters (might want to read these from netCDF file?) -! integer, parameter :: N_lon = 1440 -! integer, parameter :: N_lat = 720 -real, parameter :: ll_lon = -180.0000 -real, parameter :: ll_lat = -90.0000 -real, parameter :: dlon = 0.25 -real, parameter :: dlat = 0.25 - -! ---------------------------------------------------------- - -! local variables - -real, parameter :: no_data_stats = -9999. - -real, parameter :: tol = 0.99 - -character(3), dimension(12) :: month_string = (/ & - 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', & - 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' /) - -! ------------------- - -character(300) :: fname - -integer :: i, ind, pp, j_ind, i_ind -integer :: ncid, varid, ierr, ierr2 -integer :: pentad_dimid, lon_dimid, lat_dimid -integer :: N_pentad, N_lon, N_lat -integer :: pentad_varid, lon_varid, lat_varid -integer :: o_mean_varid, o_std_varid, m_mean_varid, m_std_varid -integer, dimension(3) :: start, icount - -real :: tmpreal, this_lon, this_lat - -integer, dimension(:), allocatable :: sclprm_tile_id -integer, dimension(:), allocatable :: pentads - -real, dimension(:), allocatable :: sclprm_lon, sclprm_lat -real, dimension(:,:), allocatable :: sclprm_mean_obs, sclprm_std_obs -real, dimension(:,:), allocatable :: sclprm_mean_mod, sclprm_std_mod - -character(len=*), parameter :: Iam = ' scale_obs_sfmc_zscore' -character(len=400) :: err_msg - -! ------------------------------------------------------------------ - -! read scaling parameters from file - -fname = trim(this_obs_param%scalepath) // '/' // & - trim(this_obs_param%scalename) // '.nc4' - -if (logit) write (logunit,*) 'scaling obs species ', this_obs_param%species, ':' -if (logit) write (logunit,'(400A)') ' reading ', trim(fname) - -! What pentad do we want? -pp = date_time%pentad - -! open the NetCDF file -ierr = nf90_open(fname, nf90_nowrite, ncid) - -ierr = nf90_inq_dimid(ncid, 'pentad', pentad_dimid) -ierr = nf90_inq_dimid(ncid, 'lon', lon_dimid) -ierr = nf90_inq_dimid(ncid, 'lat', lat_dimid) - -ierr = nf90_inquire_dimension(ncid, pentad_dimid, len = N_pentad) -ierr = nf90_inquire_dimension(ncid, lon_dimid, len = N_lon) -ierr = nf90_inquire_dimension(ncid, lat_dimid, len = N_lat) - -ierr = nf90_inq_varid(ncid, 'lon', lon_varid) -ierr = nf90_inq_varid(ncid, 'lat', lat_varid) -ierr = nf90_inq_varid(ncid, 'o_mean', o_mean_varid) -ierr = nf90_inq_varid(ncid, 'o_std', o_std_varid) -ierr = nf90_inq_varid(ncid, 'm_mean', m_mean_varid) -ierr = nf90_inq_varid(ncid, 'm_std', m_std_varid) - -! read lon and lat variables -allocate(sclprm_lon(N_lon), sclprm_lat(N_lat)) -ierr = nf90_get_var(ncid, lon_varid, sclprm_lon) -ierr = nf90_get_var(ncid, lat_varid, sclprm_lat) - -start = [1, 1, pp] -icount = [N_lat, N_lon, 1] - -allocate(sclprm_mean_obs(N_lat, N_lon), sclprm_std_obs(N_lat, N_lon)) -allocate(sclprm_mean_mod(N_lat, N_lon), sclprm_std_mod(N_lat, N_lon)) - -! ierr = nf90_get_var(ncid, o_mean_varid, sclprm_mean_obs, (/1, 1, pp/), (/N_lon, N_lat, 1/)) -ierr2 = nf90_get_var(ncid, o_mean_varid, sclprm_mean_obs, start, icount) -ierr = nf90_get_var(ncid, o_std_varid, sclprm_std_obs, start, icount) -ierr = nf90_get_var(ncid, m_mean_varid, sclprm_mean_mod, start, icount) -ierr = nf90_get_var(ncid, m_std_varid, sclprm_std_mod, start, icount) - -! close the netcdf file -ierr = nf90_close(ncid) - -! -------------------------------------------------------------- - -! scale observations (at this point all obs are of type -! isccp_tskin_gswp2_v1 because of the way the subroutine is called -! from subroutine read_obs()) - -do i=1,N_catd - - ! check for no-data-values in observation (any neg Tskin is no_data) - - if (tmp_obs(i)>=0.) then - - ! ll_lon and ll_lat refer to lower left corner of grid cell - ! (as opposed to the grid point in the center of the grid cell) + ! integer, parameter :: N_lon = 1440 + ! integer, parameter :: N_lat = 720 + real, parameter :: ll_lon = -180.0000 + real, parameter :: ll_lat = -90.0000 + real, parameter :: dlon = 0.25 + real, parameter :: dlat = 0.25 + + ! ---------------------------------------------------------- + + ! local variables + + real, parameter :: tol = 0.99 + + ! ------------------- + + character(300) :: fname + + integer :: i, ind, pp, j_ind, i_ind + integer :: ncid, varid, ierr, ierr2 + integer :: pentad_dimid, lon_dimid, lat_dimid + integer :: N_pentad, N_lon, N_lat + integer :: pentad_varid, lon_varid, lat_varid + integer :: o_mean_varid, o_std_varid, m_mean_varid, m_std_varid + integer, dimension(3) :: start, icount + + real :: tmpreal, this_lon, this_lat + + integer, dimension(:), allocatable :: sclprm_tile_id + integer, dimension(:), allocatable :: pentads + + real, dimension(:), allocatable :: sclprm_lon, sclprm_lat + real, dimension(:,:), allocatable :: sclprm_mean_obs, sclprm_std_obs + real, dimension(:,:), allocatable :: sclprm_mean_mod, sclprm_std_mod + + character(len=*), parameter :: Iam = ' scale_obs_sfmc_zscore' + character(len=400) :: err_msg + + ! ------------------------------------------------------------------ + + ! read scaling parameters from file + + fname = trim(this_obs_param%scalepath) // '/' // & + trim(this_obs_param%scalename) // '.nc4' + + if (logit) write (logunit,*) 'scaling obs species ', this_obs_param%species, ':' + if (logit) write (logunit,'(400A)') ' reading ', trim(fname) + + ! What pentad do we want? + pp = date_time%pentad + + ! open the NetCDF file + ierr = nf90_open(fname, nf90_nowrite, ncid) + + ierr = nf90_inq_dimid(ncid, 'pentad', pentad_dimid) + ierr = nf90_inq_dimid(ncid, 'lon', lon_dimid) + ierr = nf90_inq_dimid(ncid, 'lat', lat_dimid) + + ierr = nf90_inquire_dimension(ncid, pentad_dimid, len = N_pentad) + ierr = nf90_inquire_dimension(ncid, lon_dimid, len = N_lon) + ierr = nf90_inquire_dimension(ncid, lat_dimid, len = N_lat) + + ierr = nf90_inq_varid(ncid, 'lon', lon_varid) + ierr = nf90_inq_varid(ncid, 'lat', lat_varid) + ierr = nf90_inq_varid(ncid, 'o_mean', o_mean_varid) + ierr = nf90_inq_varid(ncid, 'o_std', o_std_varid) + ierr = nf90_inq_varid(ncid, 'm_mean', m_mean_varid) + ierr = nf90_inq_varid(ncid, 'm_std', m_std_varid) + + ! read lon and lat variables + allocate(sclprm_lon(N_lon), sclprm_lat(N_lat)) + ierr = nf90_get_var(ncid, lon_varid, sclprm_lon) + ierr = nf90_get_var(ncid, lat_varid, sclprm_lat) + + start = [1, 1, pp] + icount = [N_lat, N_lon, 1] + + allocate(sclprm_mean_obs(N_lat, N_lon), sclprm_std_obs(N_lat, N_lon)) + allocate(sclprm_mean_mod(N_lat, N_lon), sclprm_std_mod(N_lat, N_lon)) + + ierr2 = nf90_get_var(ncid, o_mean_varid, sclprm_mean_obs, start, icount) + ierr = nf90_get_var(ncid, o_std_varid, sclprm_std_obs, start, icount) + ierr = nf90_get_var(ncid, m_mean_varid, sclprm_mean_mod, start, icount) + ierr = nf90_get_var(ncid, m_std_varid, sclprm_std_mod, start, icount) + + ! close the netcdf file + ierr = nf90_close(ncid) + + ! -------------------------------------------------------------- + + ! scale observations (at this point all obs are of same type because + ! of the way the subroutine is called from subroutine read_obs() + + do i=1,N_catd - this_lon = tmp_lon(i) - this_lat = tmp_lat(i) - - i_ind = ceiling((this_lon - ll_lon)/dlon) - j_ind = ceiling((this_lat - ll_lat)/dlat) - - ! find ind for current tile id in scaling parameters - - ! ! sanity check (against accidental use of wrong tile space) - - if ( abs(tile_coord(i)%com_lat-sclprm_lat(j_ind))>tol .or. & - abs(tile_coord(i)%com_lon-sclprm_lon(i_ind))>tol ) then - err_msg = 'something wrong' - call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) - end if - - ! ! check for no-data-values in observation and fit parameters - ! ! (any negative number could be no-data-value for observations) - - if ( sclprm_mean_obs(j_ind, i_ind)>0. .and. & - sclprm_mean_mod(j_ind, i_ind)>0. .and. & - sclprm_std_obs(j_ind, i_ind)>=0. .and. & - sclprm_std_mod(j_ind, i_ind)>=0. ) then - - ! scale via standard normal deviates - - tmpreal = sclprm_std_mod(j_ind, i_ind)/sclprm_std_obs(j_ind, i_ind) - - tmp_obs(i) = sclprm_mean_mod(j_ind, i_ind) & - + tmpreal*(tmp_obs(i)-sclprm_mean_obs(j_ind, i_ind)) - - ! scale observation error std - - tmp_std_obs(i) = tmpreal*tmp_std_obs(i) - - else - - tmp_obs(i) = this_obs_param%nodata - - end if - - end if - -end do - -deallocate(sclprm_lon) -deallocate(sclprm_lat) -deallocate(sclprm_mean_obs) -deallocate(sclprm_std_obs) -deallocate(sclprm_mean_mod) -deallocate(sclprm_std_mod) - -end subroutine scale_obs_sfmc_zscore - + ! check for no-data-values in observation (any neg value is no_data) + + if (tmp_obs(i)>=0.) then + + ! ll_lon and ll_lat refer to lower left corner of grid cell + ! (as opposed to the grid point in the center of the grid cell) + + this_lon = tmp_lon(i) + this_lat = tmp_lat(i) + + i_ind = ceiling((this_lon - ll_lon)/dlon) + j_ind = ceiling((this_lat - ll_lat)/dlat) + + ! find ind for current tile id in scaling parameters + + ! sanity check (against accidental use of wrong tile space) + + if ( abs(tile_coord(i)%com_lat-sclprm_lat(j_ind))>tol .or. & + abs(tile_coord(i)%com_lon-sclprm_lon(i_ind))>tol ) then + err_msg = 'something wrong' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + end if + + ! check for no-data-values in observation and fit parameters + ! (any negative number could be no-data-value for observations) + + if ( sclprm_mean_obs(j_ind, i_ind)>0. .and. & + sclprm_mean_mod(j_ind, i_ind)>0. .and. & + sclprm_std_obs(j_ind, i_ind)>=0. .and. & + sclprm_std_mod(j_ind, i_ind)>=0. ) then + + ! scale via standard normal deviates + + tmpreal = sclprm_std_mod(j_ind, i_ind)/sclprm_std_obs(j_ind, i_ind) + + tmp_obs(i) = sclprm_mean_mod(j_ind, i_ind) & + + tmpreal*(tmp_obs(i)-sclprm_mean_obs(j_ind, i_ind)) + + ! scale observation error std + + tmp_std_obs(i) = tmpreal*tmp_std_obs(i) + + else + + tmp_obs(i) = this_obs_param%nodata + + end if + + end if + + end do + + deallocate(sclprm_lon) + deallocate(sclprm_lat) + deallocate(sclprm_mean_obs) + deallocate(sclprm_std_obs) + deallocate(sclprm_mean_mod) + deallocate(sclprm_std_mod) + + end subroutine scale_obs_sfmc_zscore + ! ******************************************************************************** subroutine scale_obs_Tb_zscore( N_catd, tile_coord, date_time, this_obs_param, & @@ -8791,7 +8796,7 @@ subroutine collect_obs( implicit none - character(*), intent(in) :: work_path + character(*), intent(in) :: work_path character(*), intent(in) :: exp_id type(date_time_type), intent(in) :: date_time diff --git a/src/Components/GEOSldas_GridComp/Shared/enkf_types.F90 b/src/Components/GEOSldas_GridComp/Shared/enkf_types.F90 index 46e5ef5b..c36f7127 100644 --- a/src/Components/GEOSldas_GridComp/Shared/enkf_types.F90 +++ b/src/Components/GEOSldas_GridComp/Shared/enkf_types.F90 @@ -53,7 +53,7 @@ module enkf_types ! added OminusA information for adaptive filtering - reichle, 1 Feb 2007 ! added "varname" field to "obs_param_type" - reichle 14 Jun 2011 ! major revisions to "obs_type" fields - reichle 16 Jun 2011 - ! added "units" field to "obs_param_tpye" - reichle 22 Nov 2011 + ! added "units" field to "obs_param_type" - reichle 22 Nov 2011 type :: obs_type @@ -96,6 +96,11 @@ module enkf_types integer :: species ! identifier for type of measurement integer :: orbit ! type of (half-)orbit + ! 0 = n/a [eg., in situ obs] + ! 1 = ascending + ! 2 = descending + ! 3 = ascending or descending + ! 4 = geostationary integer :: pol ! polarization ! 0 = n/a [eg., multi-pol. retrieval] From 48af04b48bf26f99cf7ef808b87533a0873094ac Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Fri, 22 Sep 2023 17:59:24 -0400 Subject: [PATCH 134/308] removed obsolete variable declaration (clsm_ensupd_read_obs.F90) --- .../GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 8845f1ea..1d8aea8f 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -1621,7 +1621,7 @@ subroutine read_obs_sm_ASCAT_EUMET( & character( 15) :: str_date_time character( 80) :: fname_of_fname_list - character(300) :: tmpfname, tmpfname2 + character(300) :: tmpfname type(date_time_type) :: date_time_tmp type(date_time_type) :: date_time_low, date_time_low_fname From eedea53cabeb660d8652ddd1e975465fd9a7ac73 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Wed, 27 Sep 2023 14:58:37 -0400 Subject: [PATCH 135/308] fixed indentation (clsm_ensupd_upd_routines.F90) --- .../clsm_ensupd_upd_routines.F90 | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index 55296a1b..a8239b63 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -4473,7 +4473,7 @@ subroutine cat_enkf_increments( & ! ensure that max SWE increment parameter is less than WEMIN; larger increments make no sense because ! at SWE=WEMIN, the tile is fully snow covered (asnow=1) - + if (SCF_ANA_MAXINCRSWE>WEMIN) call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'must use SCF_ANA_MAXINCRSWE<=WEMIN') ! get target for snow layer thickness (as used in Catchment over land tiles) @@ -4483,11 +4483,11 @@ subroutine cat_enkf_increments( & targetthick(2:N_snow) = 1./(N_snow-1.) ! identify the obs species of interest - + N_select_varnames = 1 - + select_varnames(1) = 'asnow' - + call get_select_species( & N_select_varnames, select_varnames(1:N_select_varnames), & N_obs_param, obs_param, N_select_species, select_species ) @@ -4524,23 +4524,23 @@ subroutine cat_enkf_increments( & tmp_obs = sum(Observations(ind_obs(1:N_selected_obs))%obs) tmp_obs = tmp_obs/real(N_selected_obs) - + else tmp_obs = Observations(ind_obs(1))%obs end if - - + + do n_e=1,N_ens ! compute analysis separately for each ensemble member ! 1. Get model forecast snow cover area fraction and total SWE - + asnow_fcst = asnow(kk,n_e) swe_fcst = sum(cat_progn(kk,n_e)%wesn(1:N_snow)) ! 2. Calculate SWE increment based on Toure et al (2018) eq 1 - + if (asnow_fcst .lt. tmp_obs * SCF_ANA_ALPHA) then ! ADD SNOW: Forecast SCF is less than observed SCF (after "bias" adjustment with alpha) @@ -4569,12 +4569,12 @@ subroutine cat_enkf_increments( & call StieglitzSnow_calc_asnow( 1, 1, swe_ana_array, asnow_ana_array ) asnow_ana = asnow_ana_array(1) ! asnow after analysis - + if (swe_fcst>=SCF_ANA_MINFCSTSWE) then swe_ratio = swe_ana / swe_fcst else swe_ratio = 1. ! not used when swe_fcst Date: Wed, 27 Sep 2023 17:51:13 -0400 Subject: [PATCH 136/308] fixed error (I think) in update of snow depth (missing division by asnow_fcst); cleanup of SCF analysis (clsm_ensupd_upd_routines.F90) --- .../clsm_ensupd_upd_routines.F90 | 94 ++++++++++++------- 1 file changed, 59 insertions(+), 35 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index a8239b63..e3c3620b 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -3524,7 +3524,7 @@ subroutine cat_enkf_increments( & type(obs_param_type) :: this_obs_param integer :: isnow - real :: asnow_fcst, swe_fcst, swe_ratio + real :: asnow_fcst, swe_fcst, swe_ratio, snow_dens real :: asnow_ana, swe_ana real, dimension(1) :: asnow_ana_array ! StieglitzSnow_calc_asnow() requires array real, dimension(1, 1) :: swe_ana_array ! StieglitzSnow_calc_asnow() requires array @@ -4476,7 +4476,7 @@ subroutine cat_enkf_increments( & if (SCF_ANA_MAXINCRSWE>WEMIN) call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'must use SCF_ANA_MAXINCRSWE<=WEMIN') - ! get target for snow layer thickness (as used in Catchment over land tiles) + ! get target for snow layer thickness (as used in subroutine catchment() over land tiles) targetthick(1) = CATCH_DZ1MAX @@ -4512,34 +4512,20 @@ subroutine cat_enkf_increments( & if (N_selected_obs > 0) then - ! NEED TO ALLOW FOR MULTIPLE asnow OBS (I.E., FROM MULTIPLE SENSORS, SAY, MODIS AND VIIRS) - ! - ! if statement added to maintain 0-diff for now; can be removed later - ! (that is, compute average even when N_selected_obs=1) + ! average in case there are multiple "asnow" obs (e.g., from MODIS and VIIRS) - if (N_selected_obs > 1) then - - ! compute average obs value - - tmp_obs = sum(Observations(ind_obs(1:N_selected_obs))%obs) - - tmp_obs = tmp_obs/real(N_selected_obs) - - else - - tmp_obs = Observations(ind_obs(1))%obs - - end if + tmp_obs = sum(Observations(ind_obs(1:N_selected_obs))%obs) + if (N_selected_obs > 1) tmp_obs = tmp_obs/real(N_selected_obs) do n_e=1,N_ens ! compute analysis separately for each ensemble member - ! 1. Get model forecast snow cover area fraction and total SWE + ! 1. Diagnose model forecast snow cover area fraction and total SWE asnow_fcst = asnow(kk,n_e) swe_fcst = sum(cat_progn(kk,n_e)%wesn(1:N_snow)) - ! 2. Calculate SWE increment based on Toure et al (2018) eq 1 + ! 2. Calculate SWE increment based on modified eq 1 of Toure et al (2018) if (asnow_fcst .lt. tmp_obs * SCF_ANA_ALPHA) then @@ -4550,7 +4536,7 @@ subroutine cat_enkf_increments( & elseif (tmp_obs .lt. SCF_ANA_BETA) then ! REMOVE SNOW: Simulated SCF is greater than observed SCF (after "bias" adjustment) - ! and observed SCF is less than beta threshold + ! and observed SCF is less than beta threshold swe_incr(kk,n_e) = (-1.) * SCF_ANA_MAXINCRSWE * asnow_fcst * (1. - tmp_obs/SCF_ANA_BETA) @@ -4558,13 +4544,13 @@ subroutine cat_enkf_increments( & ! NO CHANGE - endif ! (Toure et al. 2018 Equation 1) + endif ! (Toure et al. 2018 Equation 1) ! 3. Derive SWE, snow heat content, and snow depth increments for each layer from total SWE increment swe_ana = max(swe_fcst + swe_incr(kk,n_e), 0.0) ! total SWE after analysis - swe_ana_array(1,1) = swe_ana + swe_ana_array(1,1) = swe_ana ! StieglitzSnow_calc_asnow requires arrays call StieglitzSnow_calc_asnow( 1, 1, swe_ana_array, asnow_ana_array ) @@ -4573,7 +4559,7 @@ subroutine cat_enkf_increments( & if (swe_fcst>=SCF_ANA_MINFCSTSWE) then swe_ratio = swe_ana / swe_fcst else - swe_ratio = 1. ! not used when swe_fcst 0) - end do ! kk = 1, N_catd + end do ! kk=1,N_catd ! ---------------------------------- From c886542ddebc688f25ff29a25e781e5d6f93b98d Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Wed, 27 Sep 2023 18:13:04 -0400 Subject: [PATCH 137/308] if total SWE incr is zero, skip unnecessary layer-specific snow increment calcs (clsm_ensupd_upd_routines.F90) --- .../GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index e3c3620b..1d2fc68a 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -4542,7 +4542,7 @@ subroutine cat_enkf_increments( & else - ! NO CHANGE + cycle ! NO CHANGE, skip rest of increment calcs and go straight to next ens member endif ! (Toure et al. 2018 Equation 1) From c0cd075579c43871c5ab68fdf1e1926a25ef7efb Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Fri, 29 Sep 2023 10:18:48 -0400 Subject: [PATCH 138/308] minor white space fixes (clsm_ensupd_upd_routines.F90) --- .../clsm_ensupd_upd_routines.F90 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index 1d2fc68a..5f3c3185 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -115,10 +115,10 @@ module clsm_ensupd_upd_routines WEMIN use STIEGLITZSNOW, ONLY: & - StieglitzSnow_calc_asnow, & - relayer2, & - N_constit - + StieglitzSnow_calc_asnow, & + relayer2, & + N_constit + use LDAS_ensdrv_mpi, ONLY: & numprocs, & myid, & @@ -4646,7 +4646,7 @@ subroutine cat_enkf_increments( & ! 4. Relayer to balance the snow column - call relayer2( N_snow, N_constit , & + call relayer2( N_snow, N_constit, & targetthick(1), targetthick(2:N_snow), & tmp_htsn(kk,n_e,1:N_snow), & tmp_wesn(kk,n_e,1:N_snow), & From 7c89b2b7c67612434a01bdc076da2f3c1beeb7d7 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Fri, 29 Sep 2023 10:22:06 -0400 Subject: [PATCH 139/308] GEOSldas branch for testing of GCM GC branch feature/rreichle/snow_check_after_apply_LDAS_incr --- components.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/components.yaml b/components.yaml index 5ca4fecb..f26418a4 100644 --- a/components.yaml +++ b/components.yaml @@ -41,6 +41,5 @@ MAPL: GEOSgcm_GridComp: local: ./src/Components/GEOSldas_GridComp/@GEOSgcm_GridComp remote: ../GEOSgcm_GridComp.git - branch: develop + branch: feature/rreichle/snow_check_after_apply_LDAS_incr sparse: ./config/GEOSgcm_GridComp_ldas.sparse - develop: develop From 2916f0c1e66a660cd082b18bce13f8c462d83639 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Fri, 29 Sep 2023 11:48:09 -0400 Subject: [PATCH 140/308] fixed use statement (clsm_ensupd_upd_routines.F90) --- .../GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index 5f3c3185..db17940a 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -8,6 +8,9 @@ module clsm_ensupd_upd_routines use nr_ran2_gasdev, ONLY: & NRANDSEED + + use MAPL_BaseMod, ONLY: & + MAPL_UNDEF use MAPL_ConstantsMod, ONLY: & MAPL_TICE, & From 7e505afe07a1f3bc9bf72472b4224e692cea51ab Mon Sep 17 00:00:00 2001 From: amfox37 Date: Fri, 29 Sep 2023 16:12:30 -0400 Subject: [PATCH 141/308] increase max_rec size --- .../GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 1d8aea8f..8b90c4df 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -1638,7 +1638,7 @@ subroutine read_obs_sm_ASCAT_EUMET( & real*8, dimension(14) :: tmp_vdata integer, parameter :: lnbufr = 50 ! BUFR file unit number - integer, parameter :: max_rec = 20000 ! max number of obs after QC (expecting < 6 hr assim window) + integer, parameter :: max_rec = 50000 ! max number of obs after QC (expecting < 6 hr assim window) integer, parameter :: max_obs = 250000 ! max number of obs read by subroutine (expecting < 6 hr assim window) integer :: idate, iret, ireadmg, ireadsb From d896270a2ef3bf79fb291288d0224ba1c74c5c52 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Fri, 29 Sep 2023 18:39:32 -0400 Subject: [PATCH 142/308] minimal tweak to comment re. unconventional use of StieglitzSnow_calc_asnow (clsm_ensupd_upd_routines.F90) --- .../GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index db17940a..d3152860 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -4555,7 +4555,7 @@ subroutine cat_enkf_increments( & swe_ana_array(1,1) = swe_ana ! StieglitzSnow_calc_asnow requires arrays - call StieglitzSnow_calc_asnow( 1, 1, swe_ana_array, asnow_ana_array ) + call StieglitzSnow_calc_asnow( 1, 1, swe_ana_array, asnow_ana_array ) ! swe_ana_array = sum of SWE over layers asnow_ana = asnow_ana_array(1) ! asnow after analysis From d33ff1de478df84ecea4223a5e906ea421546d78 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Fri, 29 Sep 2023 18:50:15 -0400 Subject: [PATCH 143/308] turn off snow checks introduced in associated GCM GC branch (to maintain 0-diff of SMAP Tb DA test case) --- .../clsm_ensdrv_drv_routines.F90 | 7 +++++-- .../clsm_ensupd_enkf_update.F90 | 18 +++++++++++------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensdrv_drv_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensdrv_drv_routines.F90 index 3c1436a6..a5d417a6 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensdrv_drv_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensdrv_drv_routines.F90 @@ -68,13 +68,15 @@ module clsm_ensdrv_drv_routines ! ******************************************************************** - subroutine check_cat_progn( N_cat, cat_param, cat_progn ) + subroutine check_cat_progn( check_snow, N_cat, cat_param, cat_progn ) ! wrapper for subroutine check_catch_progn() which has been ! moved to "catch_iau.F90" in GEOScatch_GridComp - reichle, 3 Apr 2012 implicit none + logical, intent(in) :: check_snow + integer, intent(in) :: N_cat type(cat_param_type), dimension(N_cat), intent(in) :: cat_param @@ -124,7 +126,8 @@ subroutine check_cat_progn( N_cat, cat_param, cat_progn ) cat_progn%qa1, cat_progn%qa2, cat_progn%qa4, & cat_progn%capac, cat_progn%catdef, & cat_progn%rzexc, cat_progn%srfexc, & - ghtcnt, wesn, htsn, sndz ) + ghtcnt, wesn, htsn, sndz, & + check_snow=check_snow) ! copy 2-d arrays back into cat_progn fields diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 index 86d6449d..c6bcc18e 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 @@ -1268,7 +1268,7 @@ subroutine apply_enkf_increments( N_catd, N_ens, update_type, & integer :: n, n_e - logical :: cat_progn_has_changed + logical :: cat_progn_has_changed, check_snow character(len=*), parameter :: Iam = 'apply_enkf_increments' character(len=400) :: err_msg @@ -1278,17 +1278,19 @@ subroutine apply_enkf_increments( N_catd, N_ens, update_type, & ! apply increments cat_progn_has_changed = .true. ! conservative initialization - + + check_snow = .true. ! conservative initialization + select_update_type: select case (update_type) - + case (1,2) select_update_type ! soil moisture update - + if (logit) write (logunit,*) & 'apply_enkf_increments(): applying soil moisture increments' - + do n=1,N_catd do n_e=1,N_ens - + cat_progn(n,n_e)%srfexc = & cat_progn(n,n_e)%srfexc + cat_progn_incr(n,n_e)%srfexc cat_progn(n,n_e)%rzexc = & @@ -1369,6 +1371,8 @@ subroutine apply_enkf_increments( N_catd, N_ens, update_type, & cat_progn_has_changed = .true. + check_snow = .false. ! turn off for now to maintain 0-diff w/ SMAP Tb DA test case + case default call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'unknown update_type') @@ -1383,7 +1387,7 @@ subroutine apply_enkf_increments( N_catd, N_ens, update_type, & do n_e=1,N_ens - call check_cat_progn( N_catd, cat_param, cat_progn(:,n_e) ) + call check_cat_progn( check_snow, N_catd, cat_param, cat_progn(:,n_e) ) end do From 7b55020a94a8896e9ca868456eecee57cee3f669 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Sat, 30 Sep 2023 05:54:56 -0400 Subject: [PATCH 144/308] edit components.yaml --- components.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/components.yaml b/components.yaml index f26418a4..f53c05aa 100644 --- a/components.yaml +++ b/components.yaml @@ -43,3 +43,4 @@ GEOSgcm_GridComp: remote: ../GEOSgcm_GridComp.git branch: feature/rreichle/snow_check_after_apply_LDAS_incr sparse: ./config/GEOSgcm_GridComp_ldas.sparse + develop: develop From 3d6615fab1ce5d349773a5d653b880a1854d1fba Mon Sep 17 00:00:00 2001 From: amfox37 Date: Wed, 4 Oct 2023 17:15:05 -0400 Subject: [PATCH 145/308] combining obs --- .../clsm_ensupd_upd_routines.F90 | 298 +++++++++++++++--- 1 file changed, 251 insertions(+), 47 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index d480a48b..f357a388 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -3349,7 +3349,7 @@ end subroutine get_obs_pert ! ********************************************************************* - subroutine cat_enkf_increments( & + subroutine cat_enkf_increments( & N_ens, N_obs, N_catd, N_obs_param, & update_type, obs_param, & tile_coord, l2f, & @@ -3438,7 +3438,7 @@ subroutine cat_enkf_increments( & integer, dimension(N_obs) :: ind_obs - real, allocatable, dimension(:,:) :: State_incr + real, allocatable, dimension(:,:) :: State_incr, State_incr_cum real, allocatable, dimension(:,:) :: Obs_cov ! measurement error covariance real, allocatable, dimension(:) :: State_lon, State_lat @@ -3474,6 +3474,8 @@ subroutine cat_enkf_increments( & real, dimension( N_catd) :: tp1_ensavg type(obs_param_type) :: this_obs_param + + logical :: nonZeroFound ! ----------------------------------------------------------------------- @@ -4407,7 +4409,197 @@ subroutine cat_enkf_increments( & ! ---------------------------------- - case (13) select_update_type ! All observation types from obs_param + case (13) select_update_type ! 3d analysis + + ! update each tile separately using all observations within customized halo around each tile + ! + ! amfox, 14 September 2023 + + if (logit) write (logunit,*) 'Get increments for all observation types in obs_param' + + N_select_varnames = 0 + + if (any(obs_param%varname == 'Tb')) then + N_select_varnames = N_select_varnames + 1 + select_varnames(N_select_varnames) = 'Tb' + end if + + if (any(obs_param%varname == 'sfds')) then + N_select_varnames = N_select_varnames + 1 + select_varnames(N_select_varnames) = 'sfds' + end if + + ! Will get all species associated with Tb or sfds observations + + call get_select_species( & + N_select_varnames, select_varnames(1:N_select_varnames), & + N_obs_param, obs_param, N_select_species, select_species ) + + N_state_max = 7 + + allocate( State_incr(N_state_max,N_ens)) + allocate( State_lon( N_state_max )) + allocate( State_lat( N_state_max )) + + do kk=1,N_catd + + N_state = 0 + + ! compute increments only snow-free and non-frozen tiles + + if ( (SWE_ensavg(kk) < SWE_threshold) .and. & + (tp1_ensavg(kk) > tp1_threshold) ) then + + ! find observations within halo around tile kk + + halo_minlon = tile_coord(kk)%com_lon - xcompact + halo_maxlon = tile_coord(kk)%com_lon + xcompact + halo_minlat = tile_coord(kk)%com_lat - ycompact + halo_maxlat = tile_coord(kk)%com_lat + ycompact + + ! simple approach to dateline issue (cut halo back to at most -180:180, -90:90) + ! - reichle, 28 May 2013 + + halo_minlon = max(halo_minlon,-180.) + halo_maxlon = min(halo_maxlon, 180.) + halo_minlat = max(halo_minlat, -90.) + halo_maxlat = min(halo_maxlat, 90.) + + call get_ind_obs_lat_lon_box( & + N_obs, Observations, & + halo_minlon, halo_maxlon, halo_minlat, halo_maxlat, & + N_select_species, select_species(1:N_select_species), & + N_selected_obs, ind_obs ) + + if (N_selected_obs>0) then + + ! call get_select_species(1, 'sfds', N_obs_param, obs_param, N_select_species, select_species ) + + ! do ii = 1,N_select_species + ! if ( any(select_species(ii) == Observations(ind_obs(1:N_selected_obs))%species)) then + ! N_state = max(3, N_state) ! Keep 6 or 7 if we have Tb _and_ sfds obs) + ! if ( N_state > 3) then + ! write (logunit,*) "Two obs types in Catchment = ", kk + ! end if + ! end if + ! end do + + ! ! Determine which observation species are actually selected + ! call get_select_species(1, 'Tb', N_obs_param, obs_param, N_select_species, select_species ) + + ! do ii = 1,N_select_species + ! if ( any(select_species(ii) == Observations(ind_obs(1:N_selected_obs))%species)) then + ! if (cat_param(kk)%poros>=PEATCLSM_POROS_THRESHOLD) then + ! N_state = 7 + ! else + ! N_state = 6 + ! end if + ! end if + ! end do + + N_state = 6 + + if ( N_state == 0 ) then + err_msg = 'Dont know what state to use with this observation type' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + end if + + ! assemble State_minus + ! (on input, cat_progn contains cat_progn_minus) + + if ( N_state==3 ) then + + State_incr(1,:) = (cat_progn( kk,:)%srfexc/scale_srfexc) + State_incr(2,:) = (cat_progn( kk,:)%rzexc /scale_rzexc) + State_incr(3,:) = (cat_progn( kk,:)%catdef/scale_catdef) + + elseif ( N_state==7 ) then + + State_incr(1,:) = cat_progn( kk,:)%srfexc/scale_srfexc + State_incr(2,:) = cat_progn( kk,:)%rzexc /scale_rzexc + State_incr(3,:) = cat_progn( kk,:)%catdef/scale_catdef ! catdef in State + + State_incr(4,:) = cat_progn( kk,:)%tc1 /scale_temp + State_incr(5,:) = cat_progn( kk,:)%tc2 /scale_temp + State_incr(6,:) = cat_progn( kk,:)%tc4 /scale_temp + State_incr(7,:) = cat_progn( kk,:)%ght(1)/scale_ght1 + + else + + State_incr(1,:) = cat_progn( kk,:)%srfexc/scale_srfexc + State_incr(2,:) = cat_progn( kk,:)%rzexc /scale_rzexc + + State_incr(3,:) = cat_progn( kk,:)%tc1 /scale_temp + State_incr(4,:) = cat_progn( kk,:)%tc2 /scale_temp + State_incr(5,:) = cat_progn( kk,:)%tc4 /scale_temp + State_incr(6,:) = cat_progn( kk,:)%ght(1)/scale_ght1 + + end if + + State_lon( :) = tile_coord(kk )%com_lon + State_lat( :) = tile_coord(kk )%com_lat + + allocate(Obs_cov(N_selected_obs,N_selected_obs)) + + call assemble_obs_cov( N_selected_obs, N_obs_param, obs_param, & + Observations(ind_obs(1:N_selected_obs)), Obs_cov ) + + ! EnKF update + write (logunit,*) "N_state = ", N_state + + call enkf_increments( & + N_state, N_selected_obs, N_ens, & + Observations(ind_obs(1:N_selected_obs)), & + Obs_pred(ind_obs(1:N_selected_obs),:), & + Obs_pert(ind_obs(1:N_selected_obs),:), & + Obs_cov, & + State_incr(1:N_state,:), & + State_lon( 1:N_state ), & + State_lat( 1:N_state ), & + xcompact, ycompact, & + fcsterr_inflation_fac ) + + deallocate(Obs_cov) + + ! assemble cat_progn increments + if ( N_state==3 ) then + + cat_progn_incr(kk,:)%srfexc = State_incr(1,:)*scale_srfexc + cat_progn_incr(kk,:)%rzexc = State_incr(2,:)*scale_rzexc + cat_progn_incr(kk,:)%catdef = State_incr(3,:)*scale_catdef + + elseif ( N_state==7 ) then + + cat_progn_incr(kk,:)%srfexc = State_incr(1,:)*scale_srfexc + cat_progn_incr(kk,:)%rzexc = State_incr(2,:)*scale_rzexc + cat_progn_incr(kk,:)%catdef = State_incr(3,:)*scale_catdef ! catdef in State + + cat_progn_incr(kk,:)%tc1 = State_incr(4,:)*scale_temp + cat_progn_incr(kk,:)%tc2 = State_incr(5,:)*scale_temp + cat_progn_incr(kk,:)%tc4 = State_incr(6,:)*scale_temp + cat_progn_incr(kk,:)%ght(1) = State_incr(7,:)*scale_ght1 + + else + + cat_progn_incr(kk,:)%srfexc = State_incr(1,:)*scale_srfexc + cat_progn_incr(kk,:)%rzexc = State_incr(2,:)*scale_rzexc + + cat_progn_incr(kk,:)%tc1 = State_incr(3,:)*scale_temp + cat_progn_incr(kk,:)%tc2 = State_incr(4,:)*scale_temp + cat_progn_incr(kk,:)%tc4 = State_incr(5,:)*scale_temp + cat_progn_incr(kk,:)%ght(1) = State_incr(6,:)*scale_ght1 + + end if + + end if + + end if ! thresholds + + end do + + ! ---------------------------------- + + case (33) select_update_type ! All observation types from obs_param ! update each tile separately using all observations within customized halo around each tile ! @@ -4418,7 +4610,8 @@ subroutine cat_enkf_increments( & N_select_varnames = 1 N_state_max = 7 ! Needs to be constant size for applying increment, potential for lots of zeros - allocate( State_incr(N_state_max,N_ens)) + allocate( State_incr(N_state_max,N_ens)) + allocate( State_incr_cum(N_state_max,N_ens)) allocate( State_lon( N_state_max )) allocate( State_lat( N_state_max )) @@ -4432,14 +4625,16 @@ subroutine cat_enkf_increments( & select_varnames(N_varnames) = 'sfds' end if - do ii = 1,N_varnames + do kk=1,N_catd - call get_select_species( & - N_select_varnames, select_varnames(ii), & - N_obs_param, obs_param, N_select_species, select_species ) - - do kk=1,N_catd - + State_incr_cum = 0.0 + + do ii = 1,N_varnames + + call get_select_species( & + N_select_varnames, select_varnames(ii), & + N_obs_param, obs_param, N_select_species, select_species ) + ! compute increments only snow-free and non-frozen tiles if ( (SWE_ensavg(kk) < SWE_threshold) .and. & @@ -4460,7 +4655,7 @@ subroutine cat_enkf_increments( & halo_minlat = max(halo_minlat, -90.) halo_maxlat = min(halo_maxlat, 90.) - call get_ind_obs_lat_lon_box( & + call get_ind_obs_lat_lon_box( & N_obs, Observations, & halo_minlon, halo_maxlon, halo_minlat, halo_maxlat, & N_select_species, select_species(1:N_select_species), & @@ -4484,34 +4679,34 @@ subroutine cat_enkf_increments( & if (N_state==3) then - State_incr(1,:) = cat_progn( kk,:)%srfexc/scale_srfexc - State_incr(2,:) = cat_progn( kk,:)%rzexc /scale_rzexc - State_incr(3,:) = cat_progn( kk,:)%catdef/scale_catdef + State_incr(1,:) = (cat_progn( kk,:)%srfexc/scale_srfexc) + State_incr_cum(1,:) + State_incr(2,:) = (cat_progn( kk,:)%rzexc /scale_rzexc) + State_incr_cum(2,:) + State_incr(3,:) = (cat_progn( kk,:)%catdef/scale_catdef) + State_incr_cum(3,:) elseif ( N_state==7 ) then - State_incr(1,:) = cat_progn( kk,:)%srfexc/scale_srfexc - State_incr(2,:) = cat_progn( kk,:)%rzexc /scale_rzexc - State_incr(3,:) = cat_progn( kk,:)%catdef/scale_catdef ! catdef in State - State_incr(4,:) = cat_progn( kk,:)%tc1 /scale_temp - State_incr(5,:) = cat_progn( kk,:)%tc2 /scale_temp - State_incr(6,:) = cat_progn( kk,:)%tc4 /scale_temp - State_incr(7,:) = cat_progn( kk,:)%ght(1)/scale_ght1 + State_incr(1,:) = (cat_progn( kk,:)%srfexc/scale_srfexc) + State_incr_cum(1,:) + State_incr(2,:) = (cat_progn( kk,:)%rzexc /scale_rzexc) + State_incr_cum(2,:) + State_incr(3,:) = (cat_progn( kk,:)%catdef/scale_catdef) + State_incr_cum(3,:) ! catdef in State + State_incr(4,:) = (cat_progn( kk,:)%tc1 /scale_temp) + State_incr_cum(4,:) + State_incr(5,:) = (cat_progn( kk,:)%tc2 /scale_temp) + State_incr_cum(5,:) + State_incr(6,:) = (cat_progn( kk,:)%tc4 /scale_temp) + State_incr_cum(6,:) + State_incr(7,:) = (cat_progn( kk,:)%ght(1)/scale_ght1) + State_incr_cum(7,:) else ! N_state == 6 - State_incr(1,:) = cat_progn( kk,:)%srfexc/scale_srfexc - State_incr(2,:) = cat_progn( kk,:)%rzexc /scale_rzexc - State_incr(3,:) = cat_progn( kk,:)%tc1 /scale_temp - State_incr(4,:) = cat_progn( kk,:)%tc2 /scale_temp - State_incr(5,:) = cat_progn( kk,:)%tc4 /scale_temp - State_incr(6,:) = cat_progn( kk,:)%ght(1)/scale_ght1 + State_incr(1,:) = (cat_progn( kk,:)%srfexc/scale_srfexc) + State_incr_cum(1,:) + State_incr(2,:) = (cat_progn( kk,:)%rzexc /scale_rzexc) + State_incr_cum(2,:) + State_incr(3,:) = (cat_progn( kk,:)%tc1 /scale_temp) + State_incr_cum(3,:) + State_incr(4,:) = (cat_progn( kk,:)%tc2 /scale_temp) + State_incr_cum(4,:) + State_incr(5,:) = (cat_progn( kk,:)%tc4 /scale_temp) + State_incr_cum(5,:) + State_incr(6,:) = (cat_progn( kk,:)%ght(1)/scale_ght1) + State_incr_cum(6,:) end if State_lon( :) = tile_coord(kk )%com_lon State_lat( :) = tile_coord(kk )%com_lat - + allocate(Obs_cov(N_selected_obs,N_selected_obs)) call assemble_obs_cov( N_selected_obs, N_obs_param, obs_param, & @@ -4532,33 +4727,41 @@ subroutine cat_enkf_increments( & fcsterr_inflation_fac ) deallocate(Obs_cov) + + State_incr_cum(1:N_state,:) = State_incr_cum(1:N_state,:) + State_incr(1:N_state,:) + + nonZeroFound = ANY(cat_progn_incr(kk,:)%srfexc /= 0.0) + if (nonZeroFound) then + write (logunit,*) "Non-zero values found. ii = ", ii, & + " kk = ", kk, "State_lon = ", State_lon(1), "State_lat = ", State_lat(1) + end if ! assemble cat_progn increments if (N_state==3) then - cat_progn_incr(kk,:)%srfexc = State_incr(1,:)*scale_srfexc - cat_progn_incr(kk,:)%rzexc = State_incr(2,:)*scale_rzexc - cat_progn_incr(kk,:)%catdef = State_incr(3,:)*scale_catdef + cat_progn_incr(kk,:)%srfexc = State_incr_cum(1,:)*scale_srfexc + cat_progn_incr(kk,:)%rzexc = State_incr_cum(2,:)*scale_rzexc + cat_progn_incr(kk,:)%catdef = State_incr_cum(3,:)*scale_catdef elseif (N_state==7) then - cat_progn_incr(kk,:)%srfexc = State_incr(1,:)*scale_srfexc - cat_progn_incr(kk,:)%rzexc = State_incr(2,:)*scale_rzexc - cat_progn_incr(kk,:)%catdef = State_incr(3,:)*scale_catdef ! catdef in State - cat_progn_incr(kk,:)%tc1 = State_incr(4,:)*scale_temp - cat_progn_incr(kk,:)%tc2 = State_incr(5,:)*scale_temp - cat_progn_incr(kk,:)%tc4 = State_incr(6,:)*scale_temp - cat_progn_incr(kk,:)%ght(1) = State_incr(7,:)*scale_ght1 + cat_progn_incr(kk,:)%srfexc = State_incr_cum(1,:)*scale_srfexc + cat_progn_incr(kk,:)%rzexc = State_incr_cum(2,:)*scale_rzexc + cat_progn_incr(kk,:)%catdef = State_incr_cum(3,:)*scale_catdef ! catdef in State + cat_progn_incr(kk,:)%tc1 = State_incr_cum(4,:)*scale_temp + cat_progn_incr(kk,:)%tc2 = State_incr_cum(5,:)*scale_temp + cat_progn_incr(kk,:)%tc4 = State_incr_cum(6,:)*scale_temp + cat_progn_incr(kk,:)%ght(1) = State_incr_cum(7,:)*scale_ght1 else - cat_progn_incr(kk,:)%srfexc = State_incr(1,:)*scale_srfexc - cat_progn_incr(kk,:)%rzexc = State_incr(2,:)*scale_rzexc - cat_progn_incr(kk,:)%tc1 = State_incr(3,:)*scale_temp - cat_progn_incr(kk,:)%tc2 = State_incr(4,:)*scale_temp - cat_progn_incr(kk,:)%tc4 = State_incr(5,:)*scale_temp - cat_progn_incr(kk,:)%ght(1) = State_incr(6,:)*scale_ght1 + cat_progn_incr(kk,:)%srfexc = State_incr_cum(1,:)*scale_srfexc + cat_progn_incr(kk,:)%rzexc = State_incr_cum(2,:)*scale_rzexc + cat_progn_incr(kk,:)%tc1 = State_incr_cum(3,:)*scale_temp + cat_progn_incr(kk,:)%tc2 = State_incr_cum(4,:)*scale_temp + cat_progn_incr(kk,:)%tc4 = State_incr_cum(5,:)*scale_temp + cat_progn_incr(kk,:)%ght(1) = State_incr_cum(6,:)*scale_ght1 end if @@ -4566,9 +4769,9 @@ subroutine cat_enkf_increments( & end if ! thresholds - end do + end do ! varnames - end do !var_names + end do ! N_catd ! ---------------------------------- @@ -4581,6 +4784,7 @@ subroutine cat_enkf_increments( & ! clean up if (allocated( State_incr )) deallocate( State_incr ) + if (allocated( State_incr_cum )) deallocate( State_incr_cum ) if (allocated( State_lon )) deallocate( State_lon ) if (allocated( State_lat )) deallocate( State_lat ) if (allocated( select_tilenum )) deallocate( select_tilenum ) From 0f4da4f64ec8482fe782b8e775d981bdb60f71f4 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Fri, 6 Oct 2023 16:43:27 -0400 Subject: [PATCH 146/308] added more export variable defs to tile_bin2nc4.F90 --- src/Applications/LDAS_App/tile_bin2nc4.F90 | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/Applications/LDAS_App/tile_bin2nc4.F90 b/src/Applications/LDAS_App/tile_bin2nc4.F90 index 3f2aef3b..d26a0160 100644 --- a/src/Applications/LDAS_App/tile_bin2nc4.F90 +++ b/src/Applications/LDAS_App/tile_bin2nc4.F90 @@ -275,6 +275,19 @@ FUNCTION getAttribute (SHORT_NAME, LNAME, UNT) result (str_atr) case ('WESNN1'); LONG_NAME = 'snow_mass_layer_1'; UNITS = 'kg m-2' case ('WESNN2'); LONG_NAME = 'snow_mass_layer_2'; UNITS = 'kg m-2' case ('WESNN3'); LONG_NAME = 'snow_mass_layer_3'; UNITS = 'kg m-2' + case ('HTSNNN1'); LONG_NAME = 'heat_content_snow_layer_1'; UNITS = 'J m-2' + case ('HTSNNN2'); LONG_NAME = 'heat_content_snow_layer_2'; UNITS = 'J m-2' + case ('HTSNNN3'); LONG_NAME = 'heat_content_snow_layer_3'; UNITS = 'J m-2' + case ('SNDZN1'); LONG_NAME = 'snow_depth_layer_1'; UNITS = 'm' + case ('SNDZN2'); LONG_NAME = 'snow_depth_layer_2'; UNITS = 'm' + case ('SNDZN3'); LONG_NAME = 'snow_depth_layer_3'; UNITS = 'm' + case ('FICE1'); LONG_NAME = 'snow_frozen_fraction_layer_1'; UNITS = '1' + case ('FICE2'); LONG_NAME = 'snow_frozen_fraction_layer_2'; UNITS = '1' + case ('FICE3'); LONG_NAME = 'snow_frozen_fraction_layer_3'; UNITS = '1' + case ('ALBVR'); LONG_NAME = 'surface_reflectivity_for_visible_beam'; UNITS = '1' + case ('ALBVF'); LONG_NAME = 'surface_reflectivity_for_visible_diffuse'; UNITS = '1' + case ('ALBNR'); LONG_NAME = 'surface_reflectivity_for_near_infared_beam'; UNITS = '1' + case ('ALBNF'); LONG_NAME = 'surface_reflectivity_for_near_infrared_diffuse'; UNITS = '1' case ('HLWUP'); LONG_NAME = 'surface_emitted_longwave_flux'; UNITS = 'W m-2' case ('GWETPROF'); LONG_NAME = 'ave_prof_soil_wetness'; UNITS = '1' case ('GWETROOT'); LONG_NAME = 'root_zone_soil_wetness'; UNITS = '1' From 7291692c4bbdd2327af9647537550e17ef3729eb Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Fri, 6 Oct 2023 16:59:13 -0400 Subject: [PATCH 147/308] adjust to new interfaces of cleaned-up StieglitzSnow module (clsm_ensupd_upd_routines.F90) --- .../clsm_ensupd_upd_routines.F90 | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index d3152860..4870d46e 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -111,7 +111,6 @@ module clsm_ensupd_upd_routines N_snow => CATCH_N_SNOW, & N_gt => CATCH_N_GT, & RHOFS => CATCH_SNWALB_RHOFS, & - CATCH_DZ1MAX, & PEATCLSM_POROS_THRESHOLD use SurfParams, ONLY: & @@ -119,7 +118,8 @@ module clsm_ensupd_upd_routines use STIEGLITZSNOW, ONLY: & StieglitzSnow_calc_asnow, & - relayer2, & + StieglitzSnow_targetthick_land, & + StieglitzSnow_relayer, & N_constit use LDAS_ensdrv_mpi, ONLY: & @@ -4479,12 +4479,10 @@ subroutine cat_enkf_increments( & if (SCF_ANA_MAXINCRSWE>WEMIN) call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'must use SCF_ANA_MAXINCRSWE<=WEMIN') - ! get target for snow layer thickness (as used in subroutine catchment() over land tiles) - - targetthick(1) = CATCH_DZ1MAX - - targetthick(2:N_snow) = 1./(N_snow-1.) + ! get target for snow layer thickness + call StieglitzSnow_targetthick_land( N_snow, targetthick ) + ! identify the obs species of interest N_select_varnames = 1 @@ -4649,11 +4647,11 @@ subroutine cat_enkf_increments( & ! 4. Relayer to balance the snow column - call relayer2( N_snow, N_constit, & - targetthick(1), targetthick(2:N_snow), & - tmp_htsn(kk,n_e,1:N_snow), & - tmp_wesn(kk,n_e,1:N_snow), & - tmp_sndz(kk,n_e,1:N_snow), & + call StieglitzSnow_relayer( N_snow, N_constit, & + targetthick(1), targetthick(2:N_snow), & + tmp_htsn(kk,n_e,1:N_snow), & + tmp_wesn(kk,n_e,1:N_snow), & + tmp_sndz(kk,n_e,1:N_snow), & rconstit ) ! print the old and new swe, heat content and snow density From ff473244ae77f4b685bf80ca32aff956e4a7af27 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Sat, 7 Oct 2023 17:04:47 -0400 Subject: [PATCH 148/308] determine snow heat content analysis by keeping snow temperature constant (rather than by using "swe_ratio") (clsm_ensupd_upd_routines.F90) --- .../clsm_ensupd_upd_routines.F90 | 30 +++++++------------ 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index 4870d46e..5106d150 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -119,7 +119,8 @@ module clsm_ensupd_upd_routines use STIEGLITZSNOW, ONLY: & StieglitzSnow_calc_asnow, & StieglitzSnow_targetthick_land, & - StieglitzSnow_relayer, & + StieglitzSnow_relayer, & + StieglitzSnow_CPW, & N_constit use LDAS_ensdrv_mpi, ONLY: & @@ -3527,8 +3528,9 @@ subroutine cat_enkf_increments( & type(obs_param_type) :: this_obs_param integer :: isnow - real :: asnow_fcst, swe_fcst, swe_ratio, snow_dens + real :: asnow_fcst, swe_fcst, swe_ratio, snow_dens, snow_temp, fice_snow real :: asnow_ana, swe_ana + logical :: log_dum, log_dum2 real, dimension(1) :: asnow_ana_array ! StieglitzSnow_calc_asnow() requires array real, dimension(1, 1) :: swe_ana_array ! StieglitzSnow_calc_asnow() requires array real, dimension(N_catd,N_ens) :: swe_incr @@ -4582,7 +4584,7 @@ subroutine cat_enkf_increments( & tmp_wesn(kk,n_e,isnow) = swe_ana / N_snow ! distribute SWE evenly across layers ! assign heat content for snow at 0 deg C and without liquid water content (100% frozen) - ! (based on StieglitzSnow: htsn = (cpw*tsnow - fice*MAPL_ALHF)*swe ) + ! (based on StieglitzSnow: htsn = (CPW*tsnow - fice*MAPL_ALHF)*swe ) tmp_htsn(kk,n_e,isnow) = (0.0 - MAPL_ALHF)*tmp_wesn(kk,n_e,isnow) @@ -4595,25 +4597,15 @@ subroutine cat_enkf_increments( & ! snow in forecast and analysis, derive properties of analysis snow from properties of forecast snow ! update SWE: - + tmp_wesn(kk,n_e,isnow) = cat_progn(kk,n_e)%wesn(isnow) * swe_ratio - ! update snow heat content: - - ! reichle, 27 Sep 2023: not sure if we can/should update htsn using swe_ratio; - ! what if fcst snowpack contains liquid water? - ! in this case, would it make more sense to keep the temperature constant? - ! that is, do something like: - ! - ! call StieglitzSnow_calc_tpsnow(1, cat_progn(kk,n_e)%htsn(isnow), cat_progn(kk,n_e)%wesn(isnow), snow_temp, fice) - ! - ! tmp_htsn(kk, n_e, isnow) = (cpw*snow_temp - fice*MAPL_ALHF)*tmp_wesn(kk,n_e,isnow) - ! - ! but not sure if the latter equation is correct - ! - ! for now, keep multiplication with swe_ratio: + ! update snow heat content (keep snow temperature constant): + + call StieglitzSnow_calc_tpsnow( cat_progn(kk,n_e)%htsn(isnow), cat_progn(kk,n_e)%wesn(isnow), & + snow_temp, fice_snow, log_dum, log_dum2, .false. ) - tmp_htsn(kk,n_e,isnow) = cat_progn(kk,n_e)%htsn(isnow) * swe_ratio + tmp_htsn(kk,n_e,isnow) = (StieglitzSnow_CPW*snow_temp - fice_snow*MAPL_ALHF)*tmp_wesn(kk,n_e,isnow) ! update snow depth: From e8f85d7cbe3f6542b07d4588ad465c97e76a90c9 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Sat, 7 Oct 2023 17:10:35 -0400 Subject: [PATCH 149/308] simplify using improved interface of StieglitzSnow_calc_asnow() (clsm_ensupd_upd_routines.F90) --- .../GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index 5106d150..67796005 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -3531,8 +3531,6 @@ subroutine cat_enkf_increments( & real :: asnow_fcst, swe_fcst, swe_ratio, snow_dens, snow_temp, fice_snow real :: asnow_ana, swe_ana logical :: log_dum, log_dum2 - real, dimension(1) :: asnow_ana_array ! StieglitzSnow_calc_asnow() requires array - real, dimension(1, 1) :: swe_ana_array ! StieglitzSnow_calc_asnow() requires array real, dimension(N_catd,N_ens) :: swe_incr real, dimension(N_catd,N_ens,N_snow) :: tmp_wesn, tmp_htsn, tmp_sndz @@ -4553,11 +4551,7 @@ subroutine cat_enkf_increments( & swe_ana = max(swe_fcst + swe_incr(kk,n_e), 0.0) ! total SWE after analysis - swe_ana_array(1,1) = swe_ana ! StieglitzSnow_calc_asnow requires arrays - - call StieglitzSnow_calc_asnow( 1, 1, swe_ana_array, asnow_ana_array ) ! swe_ana_array = sum of SWE over layers - - asnow_ana = asnow_ana_array(1) ! asnow after analysis + call StieglitzSnow_calc_asnow( swe_ana, asnow_ana ) ! asnow after analysis if (swe_fcst>=SCF_ANA_MINFCSTSWE) then swe_ratio = swe_ana / swe_fcst From 0d2c860a94e798e12dff652df53fc88be27d7809 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Sat, 7 Oct 2023 17:23:52 -0400 Subject: [PATCH 150/308] add missing use statement for StieglitzSnow_calc_tpsnow() (clsm_ensupd_upd_routines.F90) --- .../GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index 67796005..b594d503 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -118,6 +118,7 @@ module clsm_ensupd_upd_routines use STIEGLITZSNOW, ONLY: & StieglitzSnow_calc_asnow, & + StieglitzSnow_calc_tpsnow, & StieglitzSnow_targetthick_land, & StieglitzSnow_relayer, & StieglitzSnow_CPW, & From dca3bf0216b34d27184a359ea5e02e2c8e42864b Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Sat, 14 Oct 2023 10:07:18 -0400 Subject: [PATCH 151/308] make work with latest modifications of associated GCM GC branch --- .../clsm_ensupd_upd_routines.F90 | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index b594d503..f0811907 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -10,7 +10,8 @@ module clsm_ensupd_upd_routines NRANDSEED use MAPL_BaseMod, ONLY: & - MAPL_UNDEF + MAPL_UNDEF, & + MAPL_LAND use MAPL_ConstantsMod, ONLY: & MAPL_TICE, & @@ -110,7 +111,7 @@ module clsm_ensupd_upd_routines use catch_constants, ONLY: & N_snow => CATCH_N_SNOW, & N_gt => CATCH_N_GT, & - RHOFS => CATCH_SNWALB_RHOFS, & + RHOFS => CATCH_SNOW_RHOFS, & PEATCLSM_POROS_THRESHOLD use SurfParams, ONLY: & @@ -119,9 +120,9 @@ module clsm_ensupd_upd_routines use STIEGLITZSNOW, ONLY: & StieglitzSnow_calc_asnow, & StieglitzSnow_calc_tpsnow, & - StieglitzSnow_targetthick_land, & StieglitzSnow_relayer, & StieglitzSnow_CPW, & + StieglitzSnow_DZPARAM, & N_constit use LDAS_ensdrv_mpi, ONLY: & @@ -3535,7 +3536,7 @@ subroutine cat_enkf_increments( & real, dimension(N_catd,N_ens) :: swe_incr real, dimension(N_catd,N_ens,N_snow) :: tmp_wesn, tmp_htsn, tmp_sndz - real, dimension(N_snow) :: targetthick ! for snow model relayer + real, dimension(N_snow) :: tpsn, fice_snow_vec ! for snow model relayer real, dimension(N_snow,N_constit) :: rconstit ! ----------------------------------------------------------------------- @@ -4480,10 +4481,6 @@ subroutine cat_enkf_increments( & if (SCF_ANA_MAXINCRSWE>WEMIN) call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'must use SCF_ANA_MAXINCRSWE<=WEMIN') - ! get target for snow layer thickness - - call StieglitzSnow_targetthick_land( N_snow, targetthick ) - ! identify the obs species of interest N_select_varnames = 1 @@ -4630,16 +4627,16 @@ subroutine cat_enkf_increments( & end if - end do ! isnow=1,N_snow (compute SWE, snow heat content, and snow depth analysis for each layer) + end do ! isnow=1,N_snow (compute SWE, snow heat content, and snow depth analysis for each layer) - ! 4. Relayer to balance the snow column + ! 4. Relayer to balance the snow column (call with optional args for adjustment of htsnn) call StieglitzSnow_relayer( N_snow, N_constit, & - targetthick(1), targetthick(2:N_snow), & + MAPL_LAND, CATCH_SNOW_DZPARAM, & tmp_htsn(kk,n_e,1:N_snow), & tmp_wesn(kk,n_e,1:N_snow), & tmp_sndz(kk,n_e,1:N_snow), & - rconstit ) + rconstit, tpsn, fice_snow_vec ) ! print the old and new swe, heat content and snow density From b836c19172cb113584e8fb48297bfca4fd95e8f4 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Tue, 17 Oct 2023 17:19:56 -0400 Subject: [PATCH 152/308] replaced SCF_ANA_MINFCSTSWE (=0.01) with StieglitzSnow_MINSWE (=0.013) for computation of snow analysis increments (clsm_ensupd_upd_routines.F90) --- .../GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index f0811907..8f0c865c 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -39,8 +39,7 @@ module clsm_ensupd_upd_routines FT_ANA_UPPERBOUND_TEFF, & SCF_ANA_ALPHA, & SCF_ANA_BETA, & - SCF_ANA_MAXINCRSWE, & - SCF_ANA_MINFCSTSWE + SCF_ANA_MAXINCRSWE use my_matrix_functions, ONLY: & row_variance, & @@ -123,6 +122,7 @@ module clsm_ensupd_upd_routines StieglitzSnow_relayer, & StieglitzSnow_CPW, & StieglitzSnow_DZPARAM, & + StieglitzSnow_MINSWE, & N_constit use LDAS_ensdrv_mpi, ONLY: & @@ -4551,7 +4551,7 @@ subroutine cat_enkf_increments( & call StieglitzSnow_calc_asnow( swe_ana, asnow_ana ) ! asnow after analysis - if (swe_fcst>=SCF_ANA_MINFCSTSWE) then + if (swe_fcst>=StieglitzSnow_MINSWE) then swe_ratio = swe_ana / swe_fcst else swe_ratio = MAPL_UNDEF ! swe_ratio unreliable; set to MAPL_UNDEF to expose inadvertent use @@ -4569,7 +4569,7 @@ subroutine cat_enkf_increments( & tmp_htsn(kk,n_e,isnow) = 0.0 tmp_sndz(kk,n_e,isnow) = 0.0 - elseif (swe_fcst < SCF_ANA_MINFCSTSWE) then + elseif (swe_fcst < StieglitzSnow_MINSWE) then ! too little snow in forecast, use generic properties for added snow From 9dc2d120ed4813ba15dde33d2b0eadcd96158233 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Tue, 17 Oct 2023 18:37:49 -0400 Subject: [PATCH 153/308] fix use statement for CATCH_SNOW_DZPARAM (clsm_ensupd_upd_routines.F90) --- .../GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index 8f0c865c..f0bf80ec 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -111,6 +111,7 @@ module clsm_ensupd_upd_routines N_snow => CATCH_N_SNOW, & N_gt => CATCH_N_GT, & RHOFS => CATCH_SNOW_RHOFS, & + CATCH_SNOW_DZPARAM, & PEATCLSM_POROS_THRESHOLD use SurfParams, ONLY: & @@ -121,7 +122,6 @@ module clsm_ensupd_upd_routines StieglitzSnow_calc_tpsnow, & StieglitzSnow_relayer, & StieglitzSnow_CPW, & - StieglitzSnow_DZPARAM, & StieglitzSnow_MINSWE, & N_constit From 5922225d39ace537220b46aff33c31d5063f93e4 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Wed, 18 Oct 2023 09:43:07 -0400 Subject: [PATCH 154/308] reverting GEOSgcm_GridComp branch back to develop (components.yaml) --- components.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components.yaml b/components.yaml index f53c05aa..5ca4fecb 100644 --- a/components.yaml +++ b/components.yaml @@ -41,6 +41,6 @@ MAPL: GEOSgcm_GridComp: local: ./src/Components/GEOSldas_GridComp/@GEOSgcm_GridComp remote: ../GEOSgcm_GridComp.git - branch: feature/rreichle/snow_check_after_apply_LDAS_incr + branch: develop sparse: ./config/GEOSgcm_GridComp_ldas.sparse develop: develop From 11cf7d02325ff84f34da881baac82ec45327b3c4 Mon Sep 17 00:00:00 2001 From: Rolf Reichle <54944691+gmao-rreichle@users.noreply.github.com> Date: Wed, 18 Oct 2023 09:46:15 -0400 Subject: [PATCH 155/308] reverting GCM GC branch back to develop (components.yaml) --- components.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components.yaml b/components.yaml index f53c05aa..5ca4fecb 100644 --- a/components.yaml +++ b/components.yaml @@ -41,6 +41,6 @@ MAPL: GEOSgcm_GridComp: local: ./src/Components/GEOSldas_GridComp/@GEOSgcm_GridComp remote: ../GEOSgcm_GridComp.git - branch: feature/rreichle/snow_check_after_apply_LDAS_incr + branch: develop sparse: ./config/GEOSgcm_GridComp_ldas.sparse develop: develop From e01aa2e09004508ebb8778dd292ed9be8a42a80b Mon Sep 17 00:00:00 2001 From: Weiyuan Jiang Date: Wed, 18 Oct 2023 15:24:41 -0400 Subject: [PATCH 156/308] clean up and add check of FFT --- .../GEOSldas_GridComp/GEOS_LdasGridComp.F90 | 6 +- .../GEOS_LandAssimGridComp.F90 | 50 +++--------- .../clsm_ensupd_enkf_update.F90 | 76 ++++++------------- .../clsm_ensupd_read_obs.F90 | 20 +---- .../clsm_ensupd_upd_routines.F90 | 23 +++--- .../GEOS_LandPertGridComp.F90 | 17 ++--- .../LDAS_PertRoutines.F90 | 5 +- .../GEOSlandpert_GridComp/land_pert.F90 | 2 - .../GEOSlandpert_GridComp/random_fields.F90 | 29 +++++-- 9 files changed, 82 insertions(+), 146 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOS_LdasGridComp.F90 b/src/Components/GEOSldas_GridComp/GEOS_LdasGridComp.F90 index a8ff3631..c0608c08 100644 --- a/src/Components/GEOSldas_GridComp/GEOS_LdasGridComp.F90 +++ b/src/Components/GEOSldas_GridComp/GEOS_LdasGridComp.F90 @@ -80,8 +80,6 @@ subroutine SetServices(gc, rc) integer :: i, k integer :: ens_id type(MAPL_MetaComp), pointer :: MAPL=>null() - type(ESMF_GridComp), pointer :: gcs(:)=>null() ! Children gridcomps - character(len=ESMF_MAXSTR), pointer :: gcnames(:)=>null() ! Children's names ! ErrLog variables integer :: status character(len=ESMF_MAXSTR) :: Iam @@ -400,7 +398,6 @@ subroutine Initialize(gc, import, export, clock, rc) logical :: IamRoot type(tile_coord_type), dimension(:), pointer :: tile_coord_f => null() - type(tile_coord_type), dimension(:), pointer :: tile_coord_l => null() integer,dimension(:),pointer :: f2g integer :: N_catf @@ -408,7 +405,7 @@ subroutine Initialize(gc, import, export, clock, rc) type(grid_def_type) :: tile_grid_g, pert_grid_g type(grid_def_type) :: tile_grid_f, pert_grid_f - type(grid_def_type) :: tile_grid_l, pert_grid_l + type(grid_def_type) :: pert_grid_l type(date_time_type):: start_time type(ESMF_Time) :: CurrentTime @@ -827,7 +824,6 @@ subroutine Run(gc, import, export, clock, rc) ! Misc variables integer :: igc,i, ens_id, FIRST_ENS_ID, ens_id_width logical :: IAmRoot - integer :: mpierr integer :: LSM_CHOICE type (ESMF_Field) :: field diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 index f13c1bfc..a44ef2f1 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 @@ -146,9 +146,8 @@ subroutine SetServices ( GC, RC ) ! Local Variables type(MAPL_MetaComp), pointer :: MAPL=>null() - type(ESMF_Config) :: CF character(len=ESMF_MAXSTR) :: LAND_ASSIM_STR, mwRTM_file - character(len=ESMF_MAXSTR) :: ensid_string,childname, fmt_str + character(len=ESMF_MAXSTR) :: ensid_string,childname integer :: i, ens_id_width, FIRST_ENS_ID, NUM_ENSEMBLE integer :: ens_id, export_id @@ -1111,7 +1110,7 @@ subroutine Initialize(gc, import, export, clock, rc) type(MAPL_MetaComp), pointer :: CHILD_MAPL=>null() ! Child's MAPL obj type(ESMF_GridComp), pointer :: gcs(:) - character(len=300) :: out_path,fname + character(len=300) :: out_path character(len=ESMF_MAXSTR) :: exp_id, GridName integer :: model_dtstep type(date_time_type) :: start_time @@ -1120,7 +1119,6 @@ subroutine Initialize(gc, import, export, clock, rc) type(T_TILECOORD_STATE), pointer :: tcinternal type(TILECOORD_WRAP) :: tcwrap - type(tile_coord_type), dimension(:), pointer :: tile_coord_f => null() type(tile_coord_type), dimension(:), pointer :: tile_coord_l => null() integer :: land_nt_local,i,mpierr, ens, ens_id_width @@ -1129,7 +1127,6 @@ subroutine Initialize(gc, import, export, clock, rc) integer, allocatable :: f2rf(:) ! mapping re-orderd rf to f for the LDASsa output character(len=300) :: seed_fname character(len=300) :: fname_tpl - character(len=14) :: datestamp character(len=ESMF_MAXSTR) :: ensid_string integer :: nymd, nhms, yy, mm, dd, h, m, s @@ -1464,7 +1461,7 @@ subroutine RUN ( GC, IMPORT, EXPORT, CLOCK, RC ) ! ! time ! - type(ESMF_Time) :: ModelTimeCur, ModelTimeNxt + type(ESMF_Time) :: ModelTimeCur type(ESMF_Alarm) :: LandAssimAlarm type(ESMF_TimeInterval) :: ModelTimeStep @@ -1484,8 +1481,6 @@ subroutine RUN ( GC, IMPORT, EXPORT, CLOCK, RC ) character(len=300) :: out_path character(len=ESMF_MAXSTR) :: exp_id - character(40) :: exp_domain - integer :: model_dtstep type(met_force_type), dimension(:), allocatable :: met_force @@ -1905,12 +1900,11 @@ subroutine RUN ( GC, IMPORT, EXPORT, CLOCK, RC ) call get_enkf_increments( & date_time_new, & NUM_ENSEMBLE, N_catl, N_catf, N_obsl_max, & - trim(out_path), trim(exp_id), exp_domain, & + trim(out_path), trim(exp_id), & met_force, lai, cat_param, mwRTM_param, & tile_coord_l, tile_coord_rf, & tcinternal%tgrid_g, tcinternal%pgrid_f, tcinternal%pgrid_g, & N_catl_vec, low_ind, l2rf, rf2l, & - N_force_pert, N_progn_pert, force_pert_param, progn_pert_param, & update_type, & LandAssimDTstep, & xcompact, ycompact, fcsterr_inflation_fac, & @@ -1942,14 +1936,14 @@ subroutine RUN ( GC, IMPORT, EXPORT, CLOCK, RC ) if (.true.) then ! replace obsolete check for analysis time with "if true" to keep indents call output_incr_etc( out_ObsFcstAna, & - date_time_new, trim(out_path), trim(exp_id), & + date_time_new, trim(exp_id), & N_obsl, N_obs_param, NUM_ENSEMBLE, & N_catl, tile_coord_l, & - N_catf, tile_coord_rf, tcinternal%pgrid_f, tcinternal%pgrid_g, & - N_catl_vec, low_ind, rf2l, N_catg, rf2g, & + N_catf, tile_coord_rf, tcinternal%pgrid_g, & + N_catl_vec, low_ind, rf2l, & obs_param, & met_force, lai, & - cat_param, cat_progn, cat_progn_incr, mwRTM_param, & + cat_param, cat_progn, mwRTM_param, & Observations_l, rf2f=rf2f ) do ii = 1, N_catl @@ -2058,9 +2052,9 @@ subroutine RUN ( GC, IMPORT, EXPORT, CLOCK, RC ) ! increments were computed) if (out_smapL4SMaup) & - call write_smapL4SMaup( 'analysis', date_time_new, trim(out_path), & + call write_smapL4SMaup( 'analysis', date_time_new, & trim(exp_id), NUM_ENSEMBLE, N_catl, N_catf, N_obsl, tile_coord_rf, & - tcinternal%tgrid_g, N_catl_vec, low_ind, & + tcinternal%tgrid_g, N_catl_vec, low_ind, & N_obs_param, obs_param, Observations_l, cat_param, cat_progn ) end if ! end if (.true.) @@ -2103,7 +2097,6 @@ subroutine UPDATE_ASSIM(gc, import, export, clock, rc) ! ESMF variables type(ESMF_Alarm) :: LandAssimAlarm - type(ESMF_VM) :: vm ! MAPL variables type(MAPL_MetaComp), pointer :: MAPL=>null() ! MAPL obj @@ -2268,25 +2261,6 @@ subroutine CALC_LAND_TB(gc, import, export, clock, rc) real, dimension(:), pointer :: WCSF real, dimension(:), pointer :: SWE - real, dimension(:), pointer :: VEGCLS - real, dimension(:), pointer :: SOILCLS - real, dimension(:), pointer :: SAND - real, dimension(:), pointer :: CLAY - real, dimension(:), pointer :: mw_POROS - real, dimension(:), pointer :: WANGWT - real, dimension(:), pointer :: WANGWP - real, dimension(:), pointer :: RGHHMIN - real, dimension(:), pointer :: RGHHMAX - real, dimension(:), pointer :: RGHWMAX - real, dimension(:), pointer :: RGHWMIN - real, dimension(:), pointer :: RGHNRH - real, dimension(:), pointer :: RGHNRV - real, dimension(:), pointer :: RGHPOLMIX - real, dimension(:), pointer :: OMEGA - real, dimension(:), pointer :: BH - real, dimension(:), pointer :: BV - real, dimension(:), pointer :: LEWT - ! export real, dimension(:), pointer :: TB_H_enavg real, dimension(:), pointer :: TB_V_enavg @@ -2298,7 +2272,7 @@ subroutine CALC_LAND_TB(gc, import, export, clock, rc) real, allocatable, dimension(:) :: Tb_h_tmp, TB_v_tmp - integer :: N_catl, n, mpierr + integer :: N_catl type(MAPL_LocStream) :: locstream call ESMF_GridCompGet ( GC, name=COMP_NAME, RC=STATUS ) @@ -2647,7 +2621,7 @@ subroutine read_pert_rseed(ensid_string,seed_fname,pert_rseed_r8) character(len=*),intent(in) :: seed_fname real(kind=ESMF_KIND_R8),intent(inout) :: pert_rseed_r8(:) - integer :: ncid, s_varid, en_dim, n_ens, id_varid, i, pos + integer :: ncid, s_varid logical :: file_exist character(len=ESMF_MAXSTR) :: tmpstr diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 index 86d6449d..24d62c58 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 @@ -140,12 +140,11 @@ module clsm_ensupd_enkf_update subroutine get_enkf_increments( & date_time, & N_ens, N_catl, N_catf, N_obsl_max, & - work_path, exp_id, exp_domain, & + work_path, exp_id, & met_force, lai, cat_param, mwRTM_param, & tile_coord_l, tile_coord_f, & tile_grid_g, pert_grid_f, pert_grid_g, & N_catl_vec, low_ind, l2f, f2l, & - N_force_pert, N_progn_pert, force_pert_param, progn_pert_param, & update_type, & dtstep_assim, & xcompact, ycompact, fcsterr_inflation_fac, & @@ -177,7 +176,7 @@ subroutine get_enkf_increments( & integer, intent(in) :: N_obsl_max ! max number of observations allowed character(*), intent(in) :: work_path - character(*), intent(in) :: exp_id, exp_domain + character(*), intent(in) :: exp_id ! Meteorological forcings, Catchment model and microwave RTM parameters @@ -200,11 +199,6 @@ subroutine get_enkf_increments( & integer, intent(in), dimension(N_catf) :: f2l - integer, intent(in) :: N_force_pert, N_progn_pert - - type(pert_param_type), dimension(:), pointer :: force_pert_param ! input - type(pert_param_type), dimension(:), pointer :: progn_pert_param ! input - integer, intent(in) :: update_type, dtstep_assim real, intent(in) :: xcompact, ycompact, fcsterr_inflation_fac @@ -252,8 +246,6 @@ subroutine get_enkf_increments( & ! local variables - integer :: N_obslH - logical :: found_obs_f, assimflag type(obs_type), dimension(:), pointer :: Observations_lH => null() ! obs w/in halo @@ -417,8 +409,8 @@ subroutine get_enkf_increments( & if (out_smapL4SMaup) & call output_smapL4SMaup( date_time, work_path, exp_id, dtstep_assim, & - N_ens, N_catl, N_catf, N_obsl, N_obsl_max, & - tile_coord_f, tile_coord_l, tile_grid_g, pert_grid_f, & + N_ens, N_catl, N_catf, N_obsl_max, & + tile_coord_f, tile_grid_g, pert_grid_f, & N_catl_vec, low_ind, l2f, N_tile_in_cell_ij_f, tile_num_in_cell_ij_f, & N_obs_param, obs_param, Observations_l, cat_param, cat_progn ) @@ -426,7 +418,7 @@ subroutine get_enkf_increments( & call collect_obs( & work_path, exp_id, date_time, dtstep_assim, & - N_catl, tile_coord_l, & + N_catl, & N_catf, tile_coord_f, pert_grid_f, & N_tile_in_cell_ij_f, tile_num_in_cell_ij_f, & N_catl_vec, low_ind, l2f, & @@ -986,7 +978,7 @@ subroutine get_enkf_increments( & ! of Observations_l and Obs_pred_l that are "good" ! [allocation of these arrays in get_obs_pred() is larger ! than eventual size] - call get_halo_obs( N_ens, N_catl, N_obsl, & + call get_halo_obs( N_ens, N_obsl, & Observations_l(1:N_obsl), Obs_pred_l(1:N_obsl,1:N_ens), & tile_coord_l, xcompact, ycompact, & N_obslH, Observations_lH, Obs_pred_lH ) @@ -1195,7 +1187,7 @@ subroutine get_enkf_increments( & ! into SMAP L4_SM aup file if (out_smapL4SMaup) & - call write_smapL4SMaup( 'obs_fcst', date_time, work_path, exp_id, N_ens, & + call write_smapL4SMaup( 'obs_fcst', date_time, exp_id, N_ens, & N_catl, N_catf, N_obsl, tile_coord_f, tile_grid_g, N_catl_vec, low_ind, & N_obs_param, obs_param, Observations_l, cat_param, cat_progn ) @@ -1271,7 +1263,6 @@ subroutine apply_enkf_increments( N_catd, N_ens, update_type, & logical :: cat_progn_has_changed character(len=*), parameter :: Iam = 'apply_enkf_increments' - character(len=400) :: err_msg ! ---------------------------------------------------------------- ! @@ -1393,8 +1384,8 @@ end subroutine apply_enkf_increments ! ******************************************************************** - subroutine output_ObsFcstAna(date_time, work_path, exp_id, & - N_obsl, Observations_l, N_obs_param, obs_param, rf2f) + subroutine output_ObsFcstAna(date_time, exp_id, & + N_obsl, Observations_l, N_obs_param, rf2f) ! obs space output: observations, obs space forecast, obs space analysis, and ! associated error variances @@ -1403,16 +1394,14 @@ subroutine output_ObsFcstAna(date_time, work_path, exp_id, & implicit none - character(*), intent(in) :: work_path + type(date_time_type), intent(in) :: date_time character(*), intent(in) :: exp_id integer, intent(in) :: N_obsl, N_obs_param - type(date_time_type), intent(in) :: date_time type(obs_type), dimension(N_obsl), intent(in) :: Observations_l - type(obs_param_type), dimension(N_obs_param), intent(in) :: obs_param integer, dimension(:), optional, intent(in) :: rf2f ! --------------------- @@ -1430,7 +1419,6 @@ subroutine output_ObsFcstAna(date_time, work_path, exp_id, & integer, dimension(numprocs) :: N_obsl_vec, tmp_low_ind character(300) :: fname - integer :: i #ifdef LDAS_MPI integer :: this_species, ind_tmp, j @@ -1623,13 +1611,13 @@ end subroutine output_ObsFcstAna ! ********************************************************************** subroutine output_incr_etc( out_ObsFcstAna, & - date_time, work_path, exp_id, & + date_time, exp_id, & N_obsl, N_obs_param, N_ens, & N_catl, tile_coord_l, & - N_catf, tile_coord_f, pert_grid_f, pert_grid_g, & - N_catl_vec, low_ind, f2l, N_catg, f2g, & + N_catf, tile_coord_f, pert_grid_g, & + N_catl_vec, low_ind, f2l, & obs_param, & - met_force, lai, cat_param, cat_progn, cat_progn_incr, mwRTM_param, & + met_force, lai, cat_param, cat_progn, mwRTM_param, & Observations_l, rf2f ) implicit none @@ -1646,23 +1634,19 @@ subroutine output_incr_etc( out_ObsFcstAna, & type(date_time_type), intent(in) :: date_time - character(len=*), intent(in) :: work_path character(len=*), intent(in) :: exp_id - integer, intent(in) :: N_obsl, N_obs_param, N_ens, N_catl, N_catf, N_catg + integer, intent(in) :: N_obsl, N_obs_param, N_ens, N_catl, N_catf type(tile_coord_type), dimension(:), pointer :: tile_coord_l ! input type(tile_coord_type), dimension(:), pointer :: tile_coord_f ! input - type(grid_def_type), intent(in) :: pert_grid_f type(grid_def_type), intent(in) :: pert_grid_g integer, dimension(numprocs), intent(in) :: N_catl_vec, low_ind integer, dimension(N_catf), intent(in) :: f2l - integer, dimension(N_catf), intent(in) :: f2g - type(obs_param_type), dimension(N_obs_param), intent(in) :: & obs_param @@ -1672,7 +1656,6 @@ subroutine output_incr_etc( out_ObsFcstAna, & type(cat_param_type), dimension(N_catl), intent(in) :: cat_param type(cat_progn_type), dimension(N_catl,N_ens), intent(in) :: cat_progn - type(cat_progn_type), dimension(N_catl,N_ens), intent(in) :: cat_progn_incr type(mwRTM_param_type), dimension(N_catl), intent(in) :: mwRTM_param @@ -1685,19 +1668,10 @@ subroutine output_incr_etc( out_ObsFcstAna, & real, dimension(:,:), pointer :: Obs_pred_l => null() - integer :: i, n_e, N_obsl_tmp - - type(cat_progn_type), dimension(N_catl) :: cat_progn_incr_ensavg - - type(cat_progn_type), dimension(:), allocatable :: cat_progn_incr_f - type(cat_progn_type), dimension(:), allocatable :: cat_progn_incr_tmp + integer :: N_obsl_tmp - type(cat_progn_type), dimension(:), allocatable :: cat_progn_incr_g - - character(40) :: file_tag, dir_name character(len=*), parameter :: Iam = 'output_incr_etc' - character(len=400) :: err_msg ! -------------------------------------------------------------- @@ -1727,8 +1701,8 @@ subroutine output_incr_etc( out_ObsFcstAna, & ! write out model, observations, and "OminusA" information - call output_ObsFcstAna( date_time, work_path, exp_id, N_obsl, & - Observations_l(1:N_obsl), N_obs_param, obs_param, rf2f=rf2f ) + call output_ObsFcstAna( date_time, exp_id, N_obsl, & + Observations_l(1:N_obsl), N_obs_param, rf2f=rf2f ) end if @@ -1830,8 +1804,8 @@ end subroutine output_incr_etc ! ********************************************************************** subroutine output_smapL4SMaup( date_time, work_path, exp_id, dtstep_assim, & - N_ens, N_catl, N_catf, N_obsl, N_obsl_max, & - tile_coord_f, tile_coord_l, tile_grid_g, pert_grid_f, & + N_ens, N_catl, N_catf, N_obsl_max, & + tile_coord_f, tile_grid_g, pert_grid_f, & N_catl_vec, low_ind, l2f, N_tile_in_cell_ij_f, tile_num_in_cell_ij_f, & N_obs_param, obs_param, Observations_l, cat_param, cat_progn ) @@ -1855,10 +1829,9 @@ subroutine output_smapL4SMaup( date_time, work_path, exp_id, dtstep_assim, & integer, intent(in) :: dtstep_assim integer, intent(in) :: N_ens, N_catl, N_catf - integer, intent(in) :: N_obsl, N_obsl_max, N_obs_param + integer, intent(in) :: N_obsl_max, N_obs_param type(tile_coord_type), dimension(:), pointer :: tile_coord_f ! input - type(tile_coord_type), dimension(:), pointer :: tile_coord_l ! input type(grid_def_type), intent(in) :: tile_grid_g type(grid_def_type), intent(in) :: pert_grid_f @@ -1935,7 +1908,7 @@ subroutine output_smapL4SMaup( date_time, work_path, exp_id, dtstep_assim, & call collect_obs( & work_path, exp_id, date_time, dtstep_assim, & - N_catl, tile_coord_l, & + N_catl, & N_catf, tile_coord_f, pert_grid_f, & N_tile_in_cell_ij_f, tile_num_in_cell_ij_f, & N_catl_vec, low_ind, l2f, & @@ -1944,7 +1917,7 @@ subroutine output_smapL4SMaup( date_time, work_path, exp_id, dtstep_assim, & ! write appropriate fields (according to 'option') into file - call write_smapL4SMaup( 'orig_obs', date_time, work_path, exp_id, N_ens, & + call write_smapL4SMaup( 'orig_obs', date_time, exp_id, N_ens, & N_catl, N_catf, N_obsl_tmp, tile_coord_f, tile_grid_g, & N_catl_vec, low_ind, & N_obs_param_tmp, obs_param_tmp(1:N_obs_param_tmp), Observations_l, & @@ -1954,7 +1927,7 @@ end subroutine output_smapL4SMaup ! ********************************************************************** - subroutine write_smapL4SMaup( option, date_time, work_path, exp_id, N_ens, & + subroutine write_smapL4SMaup( option, date_time, exp_id, N_ens, & N_catl, N_catf, N_obsl, tile_coord_f, tile_grid_g, N_catl_vec, low_ind, & N_obs_param, obs_param, Observations_l, cat_param, cat_progn ) @@ -2026,7 +1999,6 @@ subroutine write_smapL4SMaup( option, date_time, work_path, exp_id, N_ens, & type(date_time_type), intent(in) :: date_time - character(*), intent(in) :: work_path character(*), intent(in) :: exp_id integer, intent(in) :: N_ens, N_catl, N_catf diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 5937a6e0..50e0fbf8 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -496,7 +496,6 @@ subroutine read_obs_ae_l2_sm( & integer, dimension(N_catd) :: N_obs_in_tile character(len=*), parameter :: Iam = 'read_obs_ae_l2_sm' - character(len=400) :: err_msg ! ------------------------------------------------------------------- @@ -1009,7 +1008,6 @@ subroutine read_obs_ae_sm_LPRM( & integer, dimension(N_catd) :: N_obs_in_tile character(len=*), parameter :: Iam = 'read_obs_ae_sm_LPRM' - character(len=400) :: err_msg ! ------------------------------------------------------------------- @@ -1320,7 +1318,6 @@ subroutine read_obs_sm_ASCAT( & real, parameter :: tol = 1e-2 character(len=*), parameter :: Iam = 'read_obs_sm_ASCAT' - character(len=400) :: err_msg ! ------------------------------------------------------------------- @@ -1431,7 +1428,7 @@ subroutine read_obs_sm_ASCAT( & if (N_files>0) then call read_sm_ASCAT_bin( & - this_obs_param, N_files, fnames, & + N_files, fnames, & N_tmp, tmp_lon, tmp_lat, tmp_obs ) if (logit) then @@ -1552,7 +1549,7 @@ end subroutine read_obs_sm_ASCAT ! *************************************************************************** subroutine read_sm_ASCAT_bin( & - this_obs_param, N_files, fnames, N_data, lon, lat, sm_ASCAT, ease_col, ease_row ) + N_files, fnames, N_data, lon, lat, sm_ASCAT, ease_col, ease_row ) ! read soil moisture data from one or more ASCAT bin files ! @@ -1569,8 +1566,6 @@ subroutine read_sm_ASCAT_bin( & implicit none - type(obs_param_type), intent(in) :: this_obs_param - integer, intent(in) :: N_files character(*), dimension(N_files), intent(in) :: fnames @@ -1740,7 +1735,6 @@ end subroutine read_sm_ASCAT_bin ! ***************************************************************** subroutine read_obs_LaRC_Tskin( & - work_path, exp_id, & date_time, dtstep_assim, N_catd, tile_coord, & tile_grid_d, N_tile_in_cell_ij, tile_num_in_cell_ij, & this_obs_param, & @@ -1757,9 +1751,6 @@ subroutine read_obs_LaRC_Tskin( & ! inputs: - character(*), intent(in) :: work_path - character(*), intent(in) :: exp_id - type(date_time_type), intent(in) :: date_time integer, intent(in) :: dtstep_assim, N_catd @@ -1817,7 +1808,6 @@ subroutine read_obs_LaRC_Tskin( & integer :: MM character(len=*), parameter :: Iam = 'read_obs_LaRC_Tskin' - character(len=400) :: err_msg ! ------------------------------------------------------------------- @@ -6370,7 +6360,6 @@ subroutine turn_off_assim_SMAP_L1CTb(N_obs_param, obs_param, N_obsl, Observation logical, dimension(:,:), allocatable :: mask_h_D, mask_v_D character(len=*), parameter :: Iam = 'turn_off_assim_SMAP_L1CTb' - character(len=400) :: err_msg ! ------------------------------------------------------------------------------ @@ -7238,7 +7227,6 @@ subroutine read_obs( & 'LaRC_tskin-FY2E-', 'LaRC_tskin-MTST2') call read_obs_LaRC_Tskin( & - work_path, exp_id, & date_time, dtstep_assim, N_catd, tile_coord, & tile_grid_d, N_tile_in_cell_ij, tile_num_in_cell_ij, & this_obs_param, & @@ -8074,7 +8062,7 @@ end subroutine scale_obs_Tb_zscore subroutine collect_obs( & work_path, exp_id, date_time, dtstep_assim, & - N_catl, tile_coord_l, & + N_catl, & N_catf, tile_coord_f, tile_grid_f, N_tile_in_cell_ij_f, tile_num_in_cell_ij_f, & N_catl_vec, low_ind, l2f, & N_obs_param, obs_param, N_obsl_max, write_obslog, & @@ -8109,7 +8097,7 @@ subroutine collect_obs( ! tile_coord_f of catchments in domain (length N_catf) - type(tile_coord_type), dimension(:), pointer :: tile_coord_l, tile_coord_f ! input + type(tile_coord_type), dimension(:), pointer :: tile_coord_f ! input type(grid_def_type), intent(in) :: tile_grid_f diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index 6b8726ad..d7940820 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -1057,7 +1057,6 @@ subroutine get_obs_pred( & character(len=*), parameter :: Iam = 'get_obs_pred' character(len=400) :: err_msg - character(len= 10) :: tmpstring10 ! -------------------------------------------------------------- ! @@ -1423,7 +1422,7 @@ subroutine get_obs_pred( & ! allocate and assemble tile_data_l allocate(tile_data_l(0,0,0)) ! for debugging to pass call get_tiles_in_halo( N_catl, N_fields, N_ens, tile_data_l, tile_coord_l, & - N_catf, tile_coord_f, N_catl_vec, low_ind, xhalo, yhalo, & + tile_coord_f, N_catl_vec, low_ind, xhalo, yhalo, & N_catlH, tile_coord_lH=tile_coord_lH ) if (get_sfmc_lH) allocate(sfmc_lH( N_catlH, N_ens)) @@ -1454,7 +1453,7 @@ subroutine get_obs_pred( & ! communicate tile_data_l as needed and get tile_data_lH call get_tiles_in_halo( N_catl, N_fields, N_ens, tile_data_l, tile_coord_l, & - N_catf, tile_coord_f, N_catl_vec, low_ind, xhalo, yhalo, & + tile_coord_f, N_catl_vec, low_ind, xhalo, yhalo, & N_catlH, tile_data_lH=tile_data_lH ) ! read out sfmc, rzmc, etc. from tile_data_lH @@ -1977,7 +1976,6 @@ subroutine get_obs_pred_comm_helper( & integer :: k, ks, opt character(len=*), parameter :: Iam = 'get_obs_pred_comm_helper' - character(len=400) :: err_msg ! ------------------------------------------------------------------------- @@ -2342,7 +2340,7 @@ end subroutine qc_model_based_for_Tb ! ********************************************************************* - subroutine get_halo_obs( N_ens, N_catl, N_obsl, Observations_l, Obs_pred_l, & + subroutine get_halo_obs( N_ens, N_obsl, Observations_l, Obs_pred_l, & tile_coord_l, xcompact, ycompact, & N_obslH, Observations_lH, Obs_pred_lH ) @@ -2375,7 +2373,7 @@ subroutine get_halo_obs( N_ens, N_catl, N_obsl, Observations_l, Obs_pred_l, & implicit none - integer, intent(in) :: N_ens, N_catl, N_obsl + integer, intent(in) :: N_ens, N_obsl type(obs_type), dimension(N_obsl), intent(in) :: Observations_l @@ -2766,7 +2764,7 @@ end subroutine get_halo_obs ! ********************************************************************* subroutine get_tiles_in_halo( N_catl, N_fields, N_ens, tile_data_l, tile_coord_l, & - N_catf, tile_coord_f, N_catl_vec, low_ind, xhalo, yhalo, & + tile_coord_f, N_catl_vec, low_ind, xhalo, yhalo, & N_catlH, tile_coord_lH, tile_data_lH ) ! collect (bundled) tile_data from other local domains (processors) that are @@ -2787,7 +2785,7 @@ subroutine get_tiles_in_halo( N_catl, N_fields, N_ens, tile_data_l, tile_coord_l implicit none integer, intent(in) :: N_catl, N_fields - integer, intent(in) :: N_ens, N_catf + integer, intent(in) :: N_ens real, dimension(N_catl,N_fields,N_ens), intent(in) :: tile_data_l @@ -3453,7 +3451,6 @@ subroutine cat_enkf_increments( & integer, dimension(:,:,:), pointer :: tile_num_in_cell_ij => null() character(len=*), parameter :: Iam = 'cat_enkf_increments' - character(len=400) :: err_msg real, dimension( N_catd) :: r_x, tmp_dlon real :: r_y, tmp_dlat @@ -4527,10 +4524,10 @@ subroutine get_ind_obs( & ! locals - integer :: i, j, k, m - - logical :: selected_obs + integer :: i, k + + ! -------------------------------------------------------------- if (N_select_species==0 .and. N_select_tilenum==0) then @@ -4802,7 +4799,7 @@ subroutine get_ind_obs_lat_lon_box( & ! locals - integer :: i, j, k + integer :: i, k real :: lon_obs, lat_obs diff --git a/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/GEOS_LandPertGridComp.F90 b/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/GEOS_LandPertGridComp.F90 index 08f60083..17470a5c 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/GEOS_LandPertGridComp.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/GEOS_LandPertGridComp.F90 @@ -859,13 +859,11 @@ subroutine Initialize(gc, import, export, clock, rc) real(kind=ESMF_KIND_R8), pointer :: pert_rseed_r8(:)=>null() ! Misc variables - integer :: imjm(7), imjm_global(7) ! we need just the first 2 integer :: model_dtstep - integer :: land_nt_local,m,n, i1, in, j1, jn + integer :: land_nt_local,n,m,i1, in, j1, jn logical :: IAmRoot, f_exist - integer :: ipert,n_lon,n_lat, n_lon_g, n_lat_g + integer :: n_lon,n_lat, n_lon_g, n_lat_g integer, allocatable :: pert_rseed(:) - real :: dlon, dlat,locallat,locallon type(ESMF_Grid) :: Grid character(len=ESMF_MAXSTR) :: id_string integer :: ens_id_width @@ -1320,9 +1318,8 @@ subroutine Phase2_Initialize(gc, import, export, clock, rc) real, allocatable :: fpert_grid(:,:,:), ppert_grid(:,:,:) integer,allocatable :: pert_rseed(:) - integer :: land_nt_local,n,ipert,i,j,n_lon,n_lat + integer :: land_nt_local,ipert,n_lon,n_lat logical :: IAmRoot - real :: locallat,locallon ! Begin... ! phase2_initialized is a global variables shared by all ensemble member @@ -1837,12 +1834,11 @@ subroutine ApplyForcePert(gc, import, export, clock, rc) type(tile_coord_type), pointer :: tile_coord(:)=>null() integer :: n_lon,n_lat - integer :: ipert, itile + integer :: ipert integer, allocatable :: pert_rseed(:) logical :: IAmRoot integer :: land_nt_local type(pert_param_type), pointer :: PertParam=>null() ! pert param - real :: tmpRealArrDim1(1) real, allocatable :: tmpreal(:) ! Begin... @@ -2275,14 +2271,13 @@ subroutine ApplyPrognPert(gc, import, export, clock, rc) type(tile_coord_type), pointer :: tile_coord(:)=>null() integer :: n_lon,n_lat - integer :: ipert,ntiles + integer :: ipert integer, allocatable :: pert_rseed(:) logical :: IAmRoot integer :: land_nt_local type(pert_param_type), pointer :: PertParam=>null() ! pert param integer :: model_dtstep real :: dtmh - integer :: m ! Begin... ! Get my name and setup traceback handle @@ -2667,7 +2662,7 @@ subroutine Finalize(gc, import, export, clock, rc) type(MAPL_LocStream) :: locstream type(TILECOORD_WRAP) :: tcwrap type(T_TILECOORD_STATE), pointer :: tcinternal - integer :: m,n_lon,n_lat, land_nt_local, ens_id_width + integer :: m,land_nt_local, ens_id_width integer :: nfpert, nppert, n_tile type(tile_coord_type), pointer :: tile_coord_f(:)=>null() diff --git a/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/LDAS_PertRoutines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/LDAS_PertRoutines.F90 index 00eece74..cac58cdb 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/LDAS_PertRoutines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/LDAS_PertRoutines.F90 @@ -287,7 +287,6 @@ subroutine read_ens_prop_inputs( & type(force_pert_ccor_type) :: ccorr_force_pert ! Errlong variables - integer :: rc, status character(len=*), parameter :: Iam = 'read_ens_prop_inputs' ! MPI variables @@ -995,7 +994,6 @@ subroutine get_force_pert_inputs( pert_grid_l, & integer :: xstart, xcount, ystart, ycount ! for computing local indices ! Errlong variables - integer :: rc, status character(len=*), parameter :: Iam = 'get_force_pert_inputs' ! MPI variables @@ -1385,7 +1383,6 @@ subroutine get_progn_pert_inputs( pert_grid_l, & integer :: xstart, xcount, ystart, ycount ! for computing local indices ! Errlong variables - integer :: rc, status character(len=*), parameter :: Iam = 'get_progn_pert_inputs' ! MPI variables @@ -1902,7 +1899,7 @@ subroutine get_pert_select( N_pert_max, pert_grid_l, std_pert, & ! ! local variables - integer :: i,j,k, ierr + integer :: k, ierr ! --------------------------------------------------------------- ! diff --git a/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/land_pert.F90 b/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/land_pert.F90 index 1a6fe537..5b9323d7 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/land_pert.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/land_pert.F90 @@ -361,8 +361,6 @@ subroutine get_init_Pert_rseed( ens_id, init_Pert_rseed ) ! ! local variables - integer :: m, n, i, j - character(len=*), parameter :: Iam = 'get_init_Pert_rseed' character(len=400) :: err_msg diff --git a/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/random_fields.F90 b/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/random_fields.F90 index 61252d50..835f469a 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/random_fields.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/random_fields.F90 @@ -45,7 +45,7 @@ module random_fields_class NRANDSEED, & nr_ran2_2d, & nr_gasdev - + implicit none private @@ -98,9 +98,9 @@ subroutine initialize(this, Nx, Ny, var, lx, ly, dx, dy, comm) integer, optional, intent(in) :: comm ! local variable - integer :: mklstat, ierror, i, j + integer :: mklstat, ierror integer :: rank, npes, local_dim1, local_dim2, remainer - integer :: N1, N2, gcount(2), lstart(2), Stride(2) + integer :: N1, N2, Stride(2) ! set obj param vals this%N_x = Nx @@ -134,6 +134,12 @@ subroutine initialize(this, Nx, Ny, var, lx, ly, dx, dy, comm) N1 = this%fft_lens(1) N2 = this%fft_lens(2) + if (npes > minval([N1, N2]) ) then + print*, " Two many processors are acquired in a node for parallel FFT" + print*, " The number of processors acquired in a node should be smaller than or equal to FFT grid size: ", minval([N1, N2]) + call quit('Parallel FFT failed') + endif + call this%win_allocate(N1, N2) ! distribution of the grid for fft @@ -153,23 +159,35 @@ subroutine initialize(this, Nx, Ny, var, lx, ly, dx, dy, comm) mklstat = DftiCreateDescriptor(this%Desc_Handle_Dim1, DFTI_SINGLE,& DFTI_COMPLEX, 1, N1 ) + if (mklstat/= DFTI_NO_ERROR) call quit('DftiCreate dim1 failed!') mklstat = DftiCreateDescriptor(this%Desc_Handle_Dim2, DFTI_SINGLE,& DFTI_COMPLEX, 1, N2 ) + if (mklstat/= DFTI_NO_ERROR) call quit('DftiCreate dim2 failed!') ! perform local_dim2 one-dimensional transforms along 1st dimension mklstat = DftiSetValue( this%Desc_Handle_Dim1, DFTI_NUMBER_OF_TRANSFORMS, local_dim2 ) + if (mklstat/= DFTI_NO_ERROR) call quit('DftiSetValue DFTI_NUMBER_OF_TRANSFORMS failed!') mklstat = DftiSetValue( this%Desc_Handle_Dim1, DFTI_INPUT_DISTANCE, N1 ) + if (mklstat/= DFTI_NO_ERROR) call quit('DftiSetValue N1 failed!') mklstat = DftiSetValue( this%Desc_Handle_Dim1, DFTI_OUTPUT_DISTANCE, N1 ) + if (mklstat/= DFTI_NO_ERROR) call quit('DftiSetValue N2 failed!') mklstat = DftiCommitDescriptor( this%Desc_Handle_Dim1 ) + if (mklstat/= DFTI_NO_ERROR) call quit('DftiCommit dim1 failed!') ! mklstat = DftiComputeForward( this%Desc_Handle_Dim1, X ) ! local_dim1 one-dimensional transforms along 2nd dimension Stride(1) = 0; Stride(2) = local_dim1 mklstat = DftiSetValue( this%Desc_Handle_Dim2, DFTI_NUMBER_OF_TRANSFORMS, local_dim1) + if (mklstat/= DFTI_NO_ERROR) call quit('DftiSetValue local_dim1 failed!') mklstat = DftiSetValue( this%Desc_Handle_Dim2, DFTI_INPUT_DISTANCE, 1 ) + if (mklstat/= DFTI_NO_ERROR) call quit('DftiSetValue in distance failed!') mklstat = DftiSetValue( this%Desc_Handle_Dim2, DFTI_OUTPUT_DISTANCE, 1 ) + if (mklstat/= DFTI_NO_ERROR) call quit('DftiSetValue out distance failed!') mklstat = DftiSetValue( this%Desc_Handle_Dim2, DFTI_INPUT_STRIDES, Stride ) + if (mklstat/= DFTI_NO_ERROR) call quit('DftiSetValue in_stride failed!') mklstat = DftiSetValue( this%Desc_Handle_Dim2, DFTI_OUTPUT_STRIDES, Stride ) + if (mklstat/= DFTI_NO_ERROR) call quit('DftiSetValue outstride failed!') mklstat = DftiCommitDescriptor( this%Desc_Handle_Dim2 ) + if (mklstat/= DFTI_NO_ERROR) call quit('DftiCommit Dim2 failed!') !mklstat = DftiComputeForward( this%Desc_Handle_Dim2, X ) else this%comm = MPI_COMM_NULL @@ -194,7 +212,7 @@ subroutine finalize(this) class(random_fields), intent(inout) :: this ! local variable - integer :: mklstat, i , npes, ierror + integer :: mklstat ! deallocate memory if(allocated(this%field1_fft)) deallocate(this%field1_fft) @@ -515,6 +533,7 @@ subroutine rfg2d_fft(this, rseed, rfield, rfield2) cptr = c_loc(tmp_field_dim1(1,1)) call c_f_pointer (cptr, X, [ldim1*N_y_fft]) mklstat = DftiComputeBackward( this%Desc_Handle_Dim2, X ) + if (mklstat/= DFTI_NO_ERROR) call quit('DftiComputeBackward dim2 failed!') call MPI_Barrier(this%node_comm, ierror) tmp_field(n1:n2,:) = tmp_field_dim1 @@ -528,6 +547,7 @@ subroutine rfg2d_fft(this, rseed, rfield, rfield2) cptr = c_loc(tmp_field_dim2(1,1)) call c_f_pointer (cptr, X, [N_x_fft*ldim2]) mklstat = DftiComputeBackward( this%Desc_Handle_Dim1, X ) + if (mklstat/= DFTI_NO_ERROR) call quit('DftiComputeBackward dim1 failed!') tmp_field(:,n1:n2) = tmp_field_dim2/N_xy_fft_real call MPI_Win_fence(0, this%win, ierror) @@ -648,7 +668,6 @@ subroutine win_allocate(this, nx, ny) integer(kind=MPI_ADDRESS_KIND) :: windowsize integer :: disp_unit,status, Rank integer(kind=MPI_ADDRESS_KIND) :: n_bytes - integer :: int_size call MPI_Comm_rank( this%node_comm, rank, status) From 64d1e24f70ce313eb5d3fcddae966eb74733b0cb Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Fri, 20 Oct 2023 20:00:06 -0400 Subject: [PATCH 157/308] added very rough draft of revised MODIS SCF reader (commented out with CPP directive for now) --- .../clsm_ensupd_read_obs.F90 | 709 ++++++++++++++++++ 1 file changed, 709 insertions(+) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index f536f263..00e09be6 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -16,6 +16,9 @@ module clsm_ensupd_read_obs + use MAPL_BaseMod, ONLY: & + MAPL_UNDEF + use MAPL_ConstantsMod, ONLY: & MAPL_TICE @@ -5114,7 +5117,713 @@ subroutine read_obs_MODISscf( & end subroutine read_obs_MODISscf ! ***************************************************************** + ! ***************************************************************** + +#IF 0 + + subroutine read_obs_MODIS_SCF( & + date_time, dtstep_assim, N_catd, tile_coord, & + tile_grid_d, N_tile_in_cell_ij, tile_num_in_cell_ij, & + this_obs_param, & + found_obs, MODIS_obs, std_MODIS_obs ) + + ! read MODIS snow cover fraction observations on MODIS 0.05-degree climate + ! modeling grid (CMG) + ! + ! Terra: MOD10C1 + ! Aqua: MYD10C1 + ! + ! For now, assume that MODIS resolution is finer than Catchment tile space + ! and super-ob data to tile space, with lat/lon coords of obs matching + ! lat/lon coords of tiles + ! + ! reichle, 18 Oct 2023 + ! + ! ------------------------------------------------------------------------------ + + implicit none + + ! inputs + + type(date_time_type), intent(in) :: date_time + + integer, intent(in) :: dtstep_assim ! [seconds] + integer, intent(in) :: N_catd + + type(tile_coord_type), dimension(:), pointer :: tile_coord ! input + + type(grid_def_type), intent(in) :: tile_grid_d + + integer, dimension(tile_grid_d%N_lon,tile_grid_d%N_lat), intent(in) :: N_tile_in_cell_ij + + integer, dimension(:,:,:), pointer :: tile_num_in_cell_ij ! input + + type(obs_param_type), intent(in) :: this_obs_param + + ! output + + logical, intent(out) :: found_obs + + real, dimension(N_catd), intent(out) :: MODIS_obs, std_MODIS_obs + + ! ------------------------------------------------------------------------ + + ! locals + + integer, parameter :: dtstep_assim_max = 21600 ! [seconds] avoid assim window spanning >=180 deg lon + + integer, parameter :: N_CMG_lat = 3600 ! always read obs in pole-to-pole longitude strips + + real, parameter :: CMG_dlon = 0.05 ! [degrees] longitude spacing of MODIS CMG grid + + character(7) :: MODIS_product_ID + + real :: overpass_hour, tmp_delta + + integer :: N_files, N_lon + + + + + + type(date_time_type) :: date_time_beg, date_time_end + type(date_time_type) :: date_time_beg_MODIS, date_time_end_MODIS + + real :: lon_beg, lon_end + real :: lon_beg_MODIS, lon_end_MODIS + + integer :: delta_day_beg, delta_day_end + integer, :: delta_day_beg_MODIS, delta_day_end_MODIS + + + real, dimension(2) :: lon_min_vec, lon_max_vec + + integer, dimension(2) :: N_lon_vec, year_vec, dofyr_vec + + + real, dimension(:,:), allocatable :: CMG_obs, CMG_lat, CMG_lon + + + + + + + +! logical :: file_exists +! +! character(2) :: MM +! character(4) :: YYYY +! character(3) :: DDD ! Day of Year +! character(300) :: tmpfname1 +! +! integer :: ii, ind, N_files, N_tmp +! +! character(400), dimension(2), allocatable :: fnames +! +! integer, dimension(:,:), allocatable :: tmp_tile_num +! +! integer, dimension(N_catd) :: N_obs_in_tile + + + + + + character(len=*), parameter :: Iam = 'read_obs_MODISscf' + character(len=400) :: err_msg + + ! ---------------------------------------------------------------------------------- + ! + ! restrict assimilation time step to max allowed + + if (dtstep_assim > dtstep_assim_max) then + + err_msg = 'dtstep_assim exceeds max allowed of ' // dtstep_assim_max + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + + end if + + + ! initialize + + found_obs = .false. + + + ! identify MODIS product and overpass hour + + MODIS_product_ID = this_obs_param%name(1:7) + + select case (MODIS_product_ID) + + case('MOD10C1') overpass_hour = 10.5 ! [hours] Terra: 10:30am local time + + case('MYD10C1') overpass_hour = 13.5 ! [hours] Aqua: 1:30pm local time + + end select + + + ! determine beginning and end of assimilation window + + date_time_beg = date_time + date_time_end = date_time + + call augment_date_time( -dtstep_assim/2, date_time_beg ) + call augment_date_time( dtstep_assim/2, date_time_end ) + + + ! determine longitude band associated with assimilation window and local overpass hour + ! + ! observations will be returned only for tiles with lon_end < tile_coord%com_lon <= lon_beg + + call localtime2longitude( date_time_beg, overpass_hour, lon_beg, delta_day_beg ) + call localtime2longitude( date_time_end, overpass_hour, lon_end, delta_day_end ) + + ! NEEDS FINISHING ??? + + +! if (lon_beg < lon_end) then +! +! +! +! end if + + + ! determine (rough) longitude band for which MODIS obs need to be read + ! + ! --> because tiles have a non-zero extent, need to read MODIS obs in CMG grid cells located + ! in a wider band (lon_min-delta:lon_max+delta), + ! where delta should be somewhat larger than max( tile_coord%max_lon - tile_coord%min_lon ) + + tmp_delta = 3.*maxval( tile_coord(1:N_catd)%max_lon - tile_coord(1:N_catd)%min_lon ) ! [degrees] + + tmp_delta = tmp_delta/360.*86400. ! [seconds] + + date_time_beg_MODIS = date_time_beg + date_time_end_MODIS = date_time_end + + call augment_date_time( -nint(tmp_delta), date_time_beg_MODIS ) + call augment_date_time( nint(tmp_delta), date_time_end_MODIS ) + + call localtime2longitude( date_time_beg_MODIS, overpass_hour, lon_beg_MODIS, delta_day_beg_MODIS ) + call localtime2longitude( date_time_end_MODIS, overpass_hour, lon_end_MODIS, delta_day_end_MODIS ) + + ! adjust date_time_*_MODIS to reflect calendar date at lon_*_MODIS + + call augment_date_time( delta_day_beg_MODIS*86400, date_time_beg_MODIS ) + call augment_date_time( delta_day_end_MODIS*86400, date_time_end_MODIS ) + + ! put together arguments for call(s) to read_MODIS_SCF_hdf() + + ! TO DO: + ! + ! - deal with lon_*_MODIS hitting exactly -180/+180 deg longitude + ! - check that delta_lon is in range consistent with dtstep_assim + ! - does N_lon give the right array size? + ! - what if date changes when N_files=1?? + ! --> check delta_day_beg_MODIS and delta_day_end_MODIS and process accordingly + ! - is CMG DE or DC grid? + + lon_min_vec = MAPL_UNDEF + lon_max_vec = MAPL_UNDEF + + year_vec = -9999 + dofyr_vec = -9999 + + N_lon_vec = 0 + + if (lon_end_MODIS < lon_beg_MODIS) then + + if ( date_time_end_MODIS%dofyr == date_time_beg_MODIS%dofyr ) then + + ! need only one daily MODIS file and longitude band + + N_files = 1 + + lon_min_vec(1) = lon_end_MODIS + lon_max_vec(1) = lon_beg_MODIS + + year_vec( 1) = date_time_beg_MODIS%year + dofyr_vec( 1) = date_time_beg_MODIS%dofyr + + else + + ! this should never happen for dtstep_assim_max=21600 and overpass_hour=10:30am or 1:30pm + + write (logunit,*) 'overpass_hour = ', overpass_hour + write (logunit,*) 'date_time = ', date_time + write (logunit,*) 'date_time_beg = ', date_time_beg + write (logunit,*) 'date_time_end = ', date_time_end + write (logunit,*) 'date_time_beg_MODIS = ', date_time_beg_MODIS + write (logunit,*) 'date_time_end_MODIS = ', date_time_end_MODIS + write (logunit,*) 'lon_beg = ', lon_beg + write (logunit,*) 'lon_end = ', lon_end + write (logunit,*) 'lon_beg_MODIS = ', lon_beg_MODIS + write (logunit,*) 'lon_end_MODIS = ', lon_end_MODIS + + err_msg = 'encountered unexpected condition!!!' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + + end if + + else + + ! longitude band wraps around dateline, two daily MODIS files are needed + ! (this could also occur if lon_*_MODIS=180., which would result in an + ! empty first longitude band, but because of tmp_delta>0, this should + ! never happen) + + N_files = 2 + + lon_min_vec(1) = lon_end_MODIS + lon_max_vec(1) = 180. + + year_vec( 1) = date_time_end_MODIS%year + dofyr_vec( 1) = date_time_end_MODIS%dofyr + + lon_min_vec(2) = -180. + lon_max_vec(2) = lon_beg_MODIS + + year_vec( 2) = date_time_beg_MODIS%year + dofyr_vec( 2) = date_time_beg_MODIS%dofyr + + end if + + N_lon_vec = ceiling( (lon_max_vec - lon_min_vec)/CMG_dlon ) ! # CMG grid cells in lon bands + + N_lon = sum( N_lon_vec(1:N_files) ) + + + ! allocate arrays for MODIS CMG data + + allocate( CMG_obs(N_lon,N_CMG_lat) ) + allocate( CMG_lon(N_lon,N_CMG_lat) ) + allocate( CMG_lat(N_lon,N_CMG_lat) ) + + + + + + + + + + ! determine MODIS file name(s) + + write (YYYY,'(i4.4)') date_time%year + write (MM, '(i2.2)') date_time%month + write (DDD, '(i3.3)') date_time%dofyr + + + + + + + + + write (logunit,*) 'Obs time (year/month/day-of-year): ', YYYY, MM, DDD + + ! In the ensupd nml file, specify the file "name" according to the following template: + ! + ! %name = 'MOD10C1.Ayyyyddd.061.hdf' + ! + ! 1 2 + ! 123456789012345678901234 + ! + ! MOD10C1 = MODIS product name + ! .A = "acquisition time" indicator + ! yyyyddd = placeholder for year/day-of-year + ! .061 = version (Collection) indicator + ! .hdf = file name extension + ! + ! Assuming the MODIS file naming convention remains unchanged, the version can then + ! be specified in the nml file. + + !tmpfname1 = trim(this_obs_param%path) // '/' // YYYY // '/' & + ! // this_obs_param%name(1:9) // YYYY // DDD // this_obs_param%name(17:24) + + tmpfname1 = trim(this_obs_param%path) // '/' // YYYY // '/MOD10C1.A' // YYYY // DDD // & + '.061.hdf' !note the MODIS data version included here + + if (logit) write (logunit,*) 'Reading data from ', trim(tmpfname1) + + inquire(file=trim(tmpfname1), exist=file_exists) + + if (logit) write (logunit,*), file_exists + + if (file_exists) then + + N_files = 1 !?!?!?!?!?! READS NO MORE THAN ONE FILE + allocate(fnames(N_files)) + fnames(N_files) = tmpfname1 + + end if !(file_exists) + + if (N_files>0) then + + call read_MODISscf_hdf(N_files, date_time, N_tmp, fnames, & + tmp_lon, tmp_lat, tmp_obs) + + deallocate(fnames) + + else + + N_tmp = 0 + + end if ! (N_files>0) + + if (N_tmp>0) then + + allocate(tmp_tile_num(N_tmp)) + + call get_tile_num_for_obs(N_catd, tile_coord, & + tile_grid_d, N_tile_in_cell_ij, & + tile_num_in_cell_ij, & + N_tmp, tmp_lat, tmp_lon, & + this_obs_param, & + tmp_tile_num(1:N_tmp)) + + + MODIS_obs = 0. + N_obs_in_tile = 0 + + do i=1,N_tmp + + ind = tmp_tile_num(i) ! 1<=tmp_tile_num<=N_catd (unless nodata) + + if (ind>0) then ! this step eliminates obs outside domain + + MODIS_obs(ind) = MODIS_obs(ind) + tmp_obs(i) + N_obs_in_tile(ind) = N_obs_in_tile(ind) + 1 + + end if !(ind>0) + + end do !i + + !normalize + do i=1,N_catd + if (N_obs_in_tile(i)>0) then + + MODIS_obs(i) = MODIS_obs(i)/real(N_obs_in_tile(i)) + + else if (N_obs_in_tile(i) == 0) then + + MODIS_obs(i) = this_obs_param%nodata + + end if !(N_obs_in_tile(i)>0 + end do !i + + if (associated(tmp_tile_num)) deallocate (tmp_tile_num) + + do i=1, N_catd + + std_MODIS_obs(i) = this_obs_param%errstd + + end do !i + + if (any(N_obs_in_tile>0)) then + + found_obs = .true. + + else + + found_obs = .false. + + end if !(any(N_obs_in_tile>0) + + end if ! (associated(tmp_tile_num) + + if (associated(tmp_obs)) deallocate(tmp_obs) + if (associated(tmp_lon)) deallocate(tmp_lon) + if (associated(tmp_lat)) deallocate(tmp_lat) + + end subroutine read_obs_MODIS_SCF + + ! ******************************************************************************************************* + + subroutine localtime2longitude( date_time, local_hour, longitude, delta_day ) + + ! for date_time in UTC, find the longitude where the local time is local_hour; + ! delta_day is the offset between the UTC calendar day and the calendar + ! day at the returned longitude + ! when UTC and local time are exactly 12 hours offset, always return longitude=+180. + ! + ! - reichle, 19 Oct 2023 + + implicit none + + type(date_time_type), intent(in) :: date_time ! current date and time in UTC + + real, intent(in) :: local_hour ! fractional local hour (e.g., 1:30pm is 13.5); range=[0,24) + + real, intent(out) :: longitude ! [degree] -180 < longitude <= 180 + + integer, intent(out) :: delta_day ! [days] -1 <= delta_day <= 1 + + ! ---------------------------------------------- + + real :: UTC_hour, time_diff + + character(len=*), parameter :: Iam = 'localtime2longitude' + character(len=400) :: err_msg + + ! --------------------------------------------------------------------------- + + ! make sure local_hour is within permissible range: 0 <= local_hour < 24 + + if ( (local_hour < 0.) .or. (local_hour >= 24.) ) then + + err_msg = 'input local_hour falls outside allowed range of 0:24; local_hour=' // local_hour + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + + end if + + ! initialize + + delta_day = 0 + + ! determine fractional UTC hour and time difference with local_hour + + UTC_hour = ( date_time%hour*3600 + date_time%min*60 + date_time%sec )/3600. ! 0 <= UTC_hour < 24 + + time_diff = local_hour - UTC_hour + + ! enforce -12. < time_diff <= 12. and determine associated date difference, if any + + if (time_diff <= -12.) then + + delta_day = 1 + + time_diff = time_diff + 24. + + elseif (time_diff > 12.) then + + delta_day = -1 + + time_diff = time_diff - 24. + + end if + + ! determine longitude + + longitude = time_diff/24.*360. + + end subroutine localtime2longitude + + ! ***************************************************************** + +! subroutine ensure_longitude_range( lon ) +! +! ! reset longitude to fall within range of -180:180 +! ! +! ! - reichle, 18 Oct 2023 +! +! implicit none +! +! real, intent(inout) :: lon +! +! ! ---------------------------------------------------------- +! +! character(len=*), parameter :: Iam = 'ensure_longitude_range' +! character(len=400) :: err_msg +! +! ! this subroutine only works if input longitude is -540:540; +! ! extending the functionality beyond this range would require a modulus calculation; +! ! for now, just check that output longitude falls in permissible range +! +! if ( (lon < -540.) .or. (lon > 540.) ) then +! +! err_msg = 'input longitude falls outside allowed range of -540:540; lon=' // lon +! call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) +! +! end if +! +! ! reset longitude to fall within range of -180:180 +! +! if (lon < -180.) lon = lon + 360. +! if (lon > 180.) lon = lon - 360. +! +! end subroutine ensure_longitude_range + + ! ***************************************************************** + + subroutine read_MODIS_hdf( fname, N_lon, N_lat, lon_min, lon_max, lat_min, lat_max, & + MODIS_lon, MODIS_lat, MODIS_SCF ) + + ! return snow cover data from daily MODIS Terra MOD10C1, version 6.1 (https://nsidc.org/data/mod10c1/versions/61) + ! - (renamed) data files currently located at /discover/nobackup/projects/S2SHMA/MODIS/MOD10C1_V61/ (2010-2022) + ! - daily data with spatial resolution of 0.05 deg on CMG grid, missing days 2016 d. 50-58 + ! - data are read for the requested lat/lon bands + ! - QC applied: + ! - Day_CMG_Snow_Cover <= 100 (snow cover only) + ! - Day_CMG_Clear_Index > 20% (at least 20% clear sky) + ! - Day_CMG_Cloud_Obscured /= 252 (remove Antarctica) + ! - Snow_Spatial_QA <= 2 (use "best", "good", "ok"; exclude "poor", "other", etc) + ! + ! reichle, 20 Oct 2023 + ! + ! ------------------------------------------------------------------------------------------------- + + implicit none + + character(*), intent(in) :: fname ! MODIS file name with full path + + integer, intent(in) :: N_lon, N_lat + + real, intent(in) :: lon_min, lon_max, lat_min, lat_max + + real, dimension(N_lon,N_lat), intent(out) :: MODIS_lon, MODIS_lat, MODIS_SCF ! NOTE: lon-by-lat + + ! ------------------------------------------------- + + ! local parameters + + ! ll/ur_lon/lat simply indicate the extent of the MODIS CMG grid + ! + ! index increases from (-180,90) to (180,-90) (southward and eastward) + + real, parameter :: CMG_ll_lon = -180. + real, parameter :: CMG_ll_lat = -90. + + real, parameter :: CMG_ur_lon = 180. + real, parameter :: CMG_ur_lat = 90. + + real, parameter :: CMG_dlon = 0.05 + real, parameter :: CMG_dlat = 0.05 + + integer, parameter :: N_fields = 4 + + character(22), dimension(N_fields), parameter :: field_names = (/ & + 'Day_CMG_Snow_Cover ', & ! 1 + 'Day_CMG_Clear_Index ', & ! 2 + 'Day_CMG_Cloud_Obscured', & ! 3 + 'Snow_Spatial_QA '/) ! 4 + + ! 1234567890123456789012 + ! 1 2 + +!! integer, parameter :: nodata = -9999 + + integer, parameter :: qc_snow_cover_max = 100 ! screen for inland water, ocean, cloud obscured, and fill value + integer, parameter :: qc_clear_index_min = 20 ! screen for sufficiently clear condition + integer, parameter :: qc_clear_index_max = 100 ! screen for lake ice, night, inland water, ocean, etc + integer, parameter :: qc_antarctica = 252 ! screen for antarctica + integer, parameter :: qc_snow_spatial_max = 2 ! screen for basic data quality (0=best, 1=good, 2=OK, 3=poor, 4=other) + + integer, parameter :: DFACC_READ = 1 ! from hdf.inc + + ! local variables + + integer :: ii, jj, nn + + real, dimension(N_lat) :: lat_c + real, dimension(N_lon) :: lon_c + + real dimension(N_lat) :: lat_ind = (/(jj, jj=0, N_lat-1, 1)/) + real dimension(N_lon) :: lon_ind = (/(ii, ii=0, N_lon-1, 1)/) + + integer :: status, file_id, sds_id, this_ind + + integer, dimension(2) :: start, edge, stride + + logical :: keep_data + + integer :: sfstart, sfselect, sfn2index, sfrdata, sfend, sfendacc ! hdf functions + + unsigned(KIND=1), dimension(N_lat,N_lon) :: uint8_MODIS_SCF + unsigned(KIND=1), dimension(N_lat,N_lon) :: uint8_CI_Index + unsigned(KIND=1), dimension(N_lat,N_lon) :: uint8_Cloud_Index + unsigned(KIND=1), dimension(N_lat,N_lon) :: uint8_Snow_QA + + character(len=*), parameter :: Iam = 'read_MODISscf_hdf' + character(len=400) :: err_msg + + ! ------------------------------------------------------------------------- + ! + ! MODIS CMG hdf files: + ! - lat-by-lon (!) + ! - index values increase eastward and southward + + start(1) = (lat_max - CMG_ur_lat)/CMG_dlat ! 0-based [as required for hdf reads] + start(2) = (lon_min - CMG_ll_lon)/CMG_dlon ! 0-based [as required for hdf reads] + + edge(1) = N_lat + edge(2) = N_lon + + stride(1) = 1 + stride(2) = 1 + + ! lat_c, lon_c are lat/lon at center of CMG grid cell + + lat_c = CMG_ur_lat - 0.5*CMG_dlat - (start(1)+lat_ind)*CMG_dlat + lon_c = CMG_ll_lon + 0.5*CMG_dlon + (start(2)+lon_ind)*CMG_dlon + + + ! open and start "hdf file" + + file_id = sfstart(trim(fname), DFACC_READ) + + do nn=1,N_fields + + this_ind = sfn2index( file_id, trim(field_names(nn)) ) + sds_id = sfselect( file_id, this_ind ) + + select case (nn) + + case (1) status = sfrdata( sds_id, start, stride, edge, uint8_MODIS_SCF ) + case (2) status = sfrdata( sds_id, start, stride, edge, uint8_CI_Index ) + case (3) status = sfrdata( sds_id, start, stride, edge, uint8_Cloud_Index ) + case (4) status = sfrdata( sds_id, start, stride, edge, uint8_Snow_QA ) + + case default call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'unknown field') + + end select + + status = sfendacc(sds_id) + + end do ! i=1,N_fields + + ! close hdf file + + status = sfend(file_id) + + ! ------------------------------------- + ! + ! apply QC and put obs into output array + + do jj=1,N_lat + do ii=1,N_lon + + ! note: uint8 >= 0, no check for minimum needed + + keep_data = & + ( uint8_MODIS_SCF( jj,ii) <= qc_snow_cover_max ) .and. & + ( uint8_CI_Index( jj,ii) > qc_clear_index_min ) .and. & + ( uint8_CI_Index( jj,ii) <= qc_clear_index_max ) .and. & + ( uint8_Cloud_Index(jj,ii) /= qc_antarctica ) .and. & + ( uint8_Snow_QA( jj,ii) < qc_snow_spatial_max ) + + + ! NOTE: + ! - raw SCF value includes cloud cover + ! - transpose from lat-by-lon to lon-by-lat + + if (keep_data) MODIS_SCF(ii,jj) = real(uint8_MODIS_SCF(jj,ii))/real(uint8_CI_Index(jj,ii)) + + end do + end do + + N_data = j + + ADD GOOD DATA COUNTER + VERIFY WITH MATLAB + + end subroutine read_MODIS_hdf + +#ENDIF + + ! ***************************************************************** + ! ***************************************************************** + subroutine read_obs_SMAP_FT( date_time, N_catd, this_obs_param, & dtstep_assim, tile_coord, tile_grid_d, & N_tile_in_cell_ij, tile_num_in_cell_ij, write_obslog, & From f493541f96afa9741e0376d0904fa35faffd4a82 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Mon, 23 Oct 2023 09:18:00 -0400 Subject: [PATCH 158/308] more work on MODIS SCF reader (clsm_ensupd_upd_routines.F90) --- .../clsm_ensupd_read_obs.F90 | 576 ++++++++++-------- 1 file changed, 322 insertions(+), 254 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 00e09be6..1e0cfc44 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -5117,10 +5117,6 @@ subroutine read_obs_MODISscf( & end subroutine read_obs_MODISscf ! ***************************************************************** - ! ***************************************************************** - - -#IF 0 subroutine read_obs_MODIS_SCF( & date_time, dtstep_assim, N_catd, tile_coord, & @@ -5173,19 +5169,17 @@ subroutine read_obs_MODIS_SCF( & integer, parameter :: dtstep_assim_max = 21600 ! [seconds] avoid assim window spanning >=180 deg lon - integer, parameter :: N_CMG_lat = 3600 ! always read obs in pole-to-pole longitude strips - - real, parameter :: CMG_dlon = 0.05 ! [degrees] longitude spacing of MODIS CMG grid - + real, parameter :: CMG_dlat = 0.05 ! [degrees] latitude spacing of MODIS CMG grid + real, parameter :: CMG_dlon = 0.05 ! [degrees] longitude spacing of MODIS CMG grid + + real, parameter :: CMG_ll_lat = -90. ! [degrees] lower-left latitude of MODIS CMG grid + real, parameter :: CMG_ll_lon = -180. ! [degrees] lower-left longitude of MODIS CMG grid + character(7) :: MODIS_product_ID real :: overpass_hour, tmp_delta - integer :: N_files, N_lon - - - - + integer :: N_files, N_lon, N_lat, nn, N_cmg_obs, N_good_data type(date_time_type) :: date_time_beg, date_time_end type(date_time_type) :: date_time_beg_MODIS, date_time_end_MODIS @@ -5196,17 +5190,16 @@ subroutine read_obs_MODIS_SCF( & integer :: delta_day_beg, delta_day_end integer, :: delta_day_beg_MODIS, delta_day_end_MODIS + real :: lat_min, lat_max - real, dimension(2) :: lon_min_vec, lon_max_vec - - integer, dimension(2) :: N_lon_vec, year_vec, dofyr_vec - - - real, dimension(:,:), allocatable :: CMG_obs, CMG_lat, CMG_lon + integer :: N_lat, N_CMG_obs + real, dimension(2) :: lon_min_vec, lon_max_vec + integer, dimension(2) :: N_lon_vec, year_vec, dofyr_vec, start_ind, last_ind + real, dimension(:), allocatable :: CMG_obs, CMG_lat, CMG_lon, tmp_tile_num @@ -5387,47 +5380,43 @@ subroutine read_obs_MODIS_SCF( & dofyr_vec( 2) = date_time_beg_MODIS%dofyr end if - - N_lon_vec = ceiling( (lon_max_vec - lon_min_vec)/CMG_dlon ) ! # CMG grid cells in lon bands - - N_lon = sum( N_lon_vec(1:N_files) ) - - - ! allocate arrays for MODIS CMG data - - allocate( CMG_obs(N_lon,N_CMG_lat) ) - allocate( CMG_lon(N_lon,N_CMG_lat) ) - allocate( CMG_lat(N_lon,N_CMG_lat) ) - - - - - - + + lat_min = minval( tile_coord(1:N_catd)%min_lat ) + lat_max = maxval( tile_coord(1:N_catd)%max_lat ) + + ! determine # CMG grid cells in lat/lon bands + start_ind(1) = (CMG_ur_lat - lat_max )/CMG_dlat + last_ind(1) = (CMG_ur_lat - lat_min )/CMG_dlat + + N_lat = last_ind(1) - start_ind(1) + 1 - ! determine MODIS file name(s) - - write (YYYY,'(i4.4)') date_time%year - write (MM, '(i2.2)') date_time%month - write (DDD, '(i3.3)') date_time%dofyr + start_ind = (lon_min_vec - CMG_ll_lon)/CMG_dlon + last_ind = (lon_max_vec - CMG_ll_lon)/CMG_dlon + N_lon_vec = last_ind - start_ind + 1 + N_lon = sum( N_lon_vec(1:N_files) ) + ! allocate arrays for MODIS CMG data (max size that could possibly be needed for obs from both files) + allocate( CMG_obs(N_lon*N_lat) ) + allocate( CMG_lon(N_lon*N_lat) ) + allocate( CMG_lat(N_lon*N_lat) ) - - write (logunit,*) 'Obs time (year/month/day-of-year): ', YYYY, MM, DDD - - ! In the ensupd nml file, specify the file "name" according to the following template: + ! read MODIS SCF obs + ! + ! - (renamed) files currently located at /discover/nobackup/projects/S2SHMA/MODIS/MOD10C1_V61/ (2010-2022) + ! + ! - in ensupd nml file, specify the file "name" according to the following template: ! - ! %name = 'MOD10C1.Ayyyyddd.061.hdf' + ! %name = 'MOD10C1.Ayyyyddd.061.hdf' ! - ! 1 2 - ! 123456789012345678901234 + ! 1 2 + ! 123456789012345678901234 ! ! MOD10C1 = MODIS product name ! .A = "acquisition time" indicator @@ -5438,103 +5427,97 @@ subroutine read_obs_MODIS_SCF( & ! Assuming the MODIS file naming convention remains unchanged, the version can then ! be specified in the nml file. - !tmpfname1 = trim(this_obs_param%path) // '/' // YYYY // '/' & - ! // this_obs_param%name(1:9) // YYYY // DDD // this_obs_param%name(17:24) + N_cmg_obs = 0 ! initialize counter for "good" obs returned by read_MODIS_SCF_hdf() - tmpfname1 = trim(this_obs_param%path) // '/' // YYYY // '/MOD10C1.A' // YYYY // DDD // & - '.061.hdf' !note the MODIS data version included here + do nn=1,N_files ! loop through longitude bands + + ! determine MODIS file name(s) + + write (YYYY,'(i4.4)') year_vec( nn) + write (DDD, '(i3.3)') dofyr_vec(nn) + + fname = & + trim(this_obs_param%path) // '/' // YYYY // '/' // & + this_obs_param%name(1:9) // YYYY // DDD // this_obs_param%name(17:24) + + ! determine sub-array of CMG_* + + tmp_ind_start = N_cmg_obs + 1 + tmp_ind_last = N_cmg_obs + N_lon_vec(nn)*N_lat + + call read_MODIS_SCF_hdf( fname, & + lon_min_vec(nn), lon_max_vec(nn), lat_min, lat_max, & + N_good_data, & + CMG_lon(tmp_ind_start:tmp_ind_last), & + CMG_lat(tmp_ind_start:tmp_ind_last), & + CMG_obs(tmp_ind_start:tmp_ind_last), ) + - if (logit) write (logunit,*) 'Reading data from ', trim(tmpfname1) + N_cmg_obs = N_cmg_obs + N_good_data + + end do - inquire(file=trim(tmpfname1), exist=file_exists) - if (logit) write (logunit,*), file_exists + ! map to tile space - if (file_exists) then - - N_files = 1 !?!?!?!?!?! READS NO MORE THAN ONE FILE - allocate(fnames(N_files)) - fnames(N_files) = tmpfname1 - - end if !(file_exists) - - if (N_files>0) then - - call read_MODISscf_hdf(N_files, date_time, N_tmp, fnames, & - tmp_lon, tmp_lat, tmp_obs) - - deallocate(fnames) - - else + allocate(tmp_tile_num(N_cmg_obs)) + + call get_tile_num_for_obs( N_catd, tile_coord, & + tile_grid_d, N_tile_in_cell_ij, & + tile_num_in_cell_ij, & + N_cmg_obs, CMG_lat(1:N_cmg_obs), CMG_lon(1:N_cmg_obs), & + this_obs_param, & + tmp_tile_num ) + + + std_MODIS_obs = this_obs_param%errstd + + MODIS_obs = 0. + N_obs_in_tile = 0 + + do kk=1,N_cmg_obs - N_tmp = 0 + ind = tmp_tile_num(kk) ! 1<=tmp_tile_num<=N_catd (unless nodata) - end if ! (N_files>0) + if (ind>0) then ! this condition eliminates obs outside domain + + MODIS_obs( ind) = MODIS_obs( ind) + tmp_obs(kk) + N_obs_in_tile(ind) = N_obs_in_tile(ind) + 1 + + end if + + end do - if (N_tmp>0) then + ! normalize - allocate(tmp_tile_num(N_tmp)) - - call get_tile_num_for_obs(N_catd, tile_coord, & - tile_grid_d, N_tile_in_cell_ij, & - tile_num_in_cell_ij, & - N_tmp, tmp_lat, tmp_lon, & - this_obs_param, & - tmp_tile_num(1:N_tmp)) - - - MODIS_obs = 0. - N_obs_in_tile = 0 - - do i=1,N_tmp - - ind = tmp_tile_num(i) ! 1<=tmp_tile_num<=N_catd (unless nodata) - - if (ind>0) then ! this step eliminates obs outside domain + do kk=1,N_catd + if (N_obs_in_tile(kk)>0) then - MODIS_obs(ind) = MODIS_obs(ind) + tmp_obs(i) - N_obs_in_tile(ind) = N_obs_in_tile(ind) + 1 - - end if !(ind>0) - - end do !i - - !normalize - do i=1,N_catd - if (N_obs_in_tile(i)>0) then - - MODIS_obs(i) = MODIS_obs(i)/real(N_obs_in_tile(i)) + MODIS_obs(kk) = MODIS_obs(kk)/real(N_obs_in_tile(kk)) - else if (N_obs_in_tile(i) == 0) then - - MODIS_obs(i) = this_obs_param%nodata - - end if !(N_obs_in_tile(i)>0 - end do !i + else if (N_obs_in_tile(kk)==0) then - if (associated(tmp_tile_num)) deallocate (tmp_tile_num) - - do i=1, N_catd - - std_MODIS_obs(i) = this_obs_param%errstd - - end do !i - - if (any(N_obs_in_tile>0)) then + MODIS_obs(kk) = this_obs_param%nodata - found_obs = .true. + end if + end do + + if (any(N_obs_in_tile>0)) then - else + found_obs = .true. - found_obs = .false. + else - end if !(any(N_obs_in_tile>0) + found_obs = .false. - end if ! (associated(tmp_tile_num) - - if (associated(tmp_obs)) deallocate(tmp_obs) - if (associated(tmp_lon)) deallocate(tmp_lon) - if (associated(tmp_lat)) deallocate(tmp_lat) + end if + + + deallocate(tmp_tile_num) + + deallocate(CMG_obs) + deallocate(CMG_lon) + deallocate(CMG_lat) end subroutine read_obs_MODIS_SCF @@ -5568,7 +5551,7 @@ subroutine localtime2longitude( date_time, local_hour, longitude, delta_day ) ! --------------------------------------------------------------------------- - ! make sure local_hour is within permissible range: 0 <= local_hour < 24 + ! make sure local_hour is within range: 0 <= local_hour < 24 if ( (local_hour < 0.) .or. (local_hour >= 24.) ) then @@ -5608,70 +5591,34 @@ subroutine localtime2longitude( date_time, local_hour, longitude, delta_day ) longitude = time_diff/24.*360. end subroutine localtime2longitude - - ! ***************************************************************** - -! subroutine ensure_longitude_range( lon ) -! -! ! reset longitude to fall within range of -180:180 -! ! -! ! - reichle, 18 Oct 2023 -! -! implicit none -! -! real, intent(inout) :: lon -! -! ! ---------------------------------------------------------- -! -! character(len=*), parameter :: Iam = 'ensure_longitude_range' -! character(len=400) :: err_msg -! -! ! this subroutine only works if input longitude is -540:540; -! ! extending the functionality beyond this range would require a modulus calculation; -! ! for now, just check that output longitude falls in permissible range -! -! if ( (lon < -540.) .or. (lon > 540.) ) then -! -! err_msg = 'input longitude falls outside allowed range of -540:540; lon=' // lon -! call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) -! -! end if -! -! ! reset longitude to fall within range of -180:180 -! -! if (lon < -180.) lon = lon + 360. -! if (lon > 180.) lon = lon - 360. -! -! end subroutine ensure_longitude_range - + ! ***************************************************************** - subroutine read_MODIS_hdf( fname, N_lon, N_lat, lon_min, lon_max, lat_min, lat_max, & - MODIS_lon, MODIS_lat, MODIS_SCF ) - - ! return snow cover data from daily MODIS Terra MOD10C1, version 6.1 (https://nsidc.org/data/mod10c1/versions/61) - ! - (renamed) data files currently located at /discover/nobackup/projects/S2SHMA/MODIS/MOD10C1_V61/ (2010-2022) - ! - daily data with spatial resolution of 0.05 deg on CMG grid, missing days 2016 d. 50-58 - ! - data are read for the requested lat/lon bands - ! - QC applied: - ! - Day_CMG_Snow_Cover <= 100 (snow cover only) - ! - Day_CMG_Clear_Index > 20% (at least 20% clear sky) - ! - Day_CMG_Cloud_Obscured /= 252 (remove Antarctica) - ! - Snow_Spatial_QA <= 2 (use "best", "good", "ok"; exclude "poor", "other", etc) + subroutine read_MODIS_SCF_hdf( fname, lon_min, lon_max, lat_min, lat_max, & + N_good_data, MODIS_lon, MODIS_lat, MODIS_SCF ) + + ! read snow cover area fraction (SCF) obs from daily MODIS Terra or Aqua M?D10C1, version 6.1 + ! - Terra: https://nsidc.org/data/mod10c1/versions/61 + ! - Aqua: https://nsidc.org/data/myd10c1/versions/61 + ! - daily data with spatial resolution of 0.05 deg on MODIS climate modeling grid (CMG) + ! - Terra: missing days 2016 d. 50-58 + ! - data are read for the requested lat/lon range + ! - apply QC ! ! reichle, 20 Oct 2023 ! ! ------------------------------------------------------------------------------------------------- implicit none - - character(*), intent(in) :: fname ! MODIS file name with full path - integer, intent(in) :: N_lon, N_lat - - real, intent(in) :: lon_min, lon_max, lat_min, lat_max + character(*), intent(in) :: fname ! MODIS file name with full path - real, dimension(N_lon,N_lat), intent(out) :: MODIS_lon, MODIS_lat, MODIS_SCF ! NOTE: lon-by-lat + real, intent(in) :: lon_min, lon_max ! -180 <= lon_* <= 180 + real, intent(in) :: lat_min, lat_max ! -90 <= lat_* <= 90 + + integer, intent(out) :: N_good_data + + real, dimension(:), intent(out) :: MODIS_lon, MODIS_lat, MODIS_SCF ! NOTE: lon-by-lat ! ------------------------------------------------- @@ -5680,146 +5627,267 @@ subroutine read_MODIS_hdf( fname, N_lon, N_lat, lon_min, lon_max, lat_min, lat_m ! ll/ur_lon/lat simply indicate the extent of the MODIS CMG grid ! ! index increases from (-180,90) to (180,-90) (southward and eastward) - - real, parameter :: CMG_ll_lon = -180. - real, parameter :: CMG_ll_lat = -90. - real, parameter :: CMG_ur_lon = 180. - real, parameter :: CMG_ur_lat = 90. + integer, parameter :: CMG_N_lon = 7200 + integer, parameter :: CMG_N_lat = 3600 + + real, parameter :: CMG_ll_lon = -180. + real, parameter :: CMG_ll_lat = -90. - real, parameter :: CMG_dlon = 0.05 - real, parameter :: CMG_dlat = 0.05 + real, parameter :: CMG_ur_lon = 180. + real, parameter :: CMG_ur_lat = 90. - integer, parameter :: N_fields = 4 + real, parameter :: CMG_dlon = 0.05 + real, parameter :: CMG_dlat = 0.05 + + integer, parameter :: N_fields = 3 character(22), dimension(N_fields), parameter :: field_names = (/ & 'Day_CMG_Snow_Cover ', & ! 1 'Day_CMG_Clear_Index ', & ! 2 - 'Day_CMG_Cloud_Obscured', & ! 3 - 'Snow_Spatial_QA '/) ! 4 + 'Snow_Spatial_QA '/) ! 3 ! 1234567890123456789012 ! 1 2 -!! integer, parameter :: nodata = -9999 + integer, parameter :: SCF_nodata = -9999. - integer, parameter :: qc_snow_cover_max = 100 ! screen for inland water, ocean, cloud obscured, and fill value - integer, parameter :: qc_clear_index_min = 20 ! screen for sufficiently clear condition - integer, parameter :: qc_clear_index_max = 100 ! screen for lake ice, night, inland water, ocean, etc - integer, parameter :: qc_antarctica = 252 ! screen for antarctica - integer, parameter :: qc_snow_spatial_max = 2 ! screen for basic data quality (0=best, 1=good, 2=OK, 3=poor, 4=other) + integer, parameter :: qc_snow_cover_max = 100 ! exclude lake ice, night, inland water, ocean, etc + integer, parameter :: qc_clear_index_min = 20 ! ensure sufficiently clear conditions + integer, parameter :: qc_snow_spatial_max = 2 ! screen for basic data quality (0=best, 1=good, 2=OK, 3=poor, 4=other) - integer, parameter :: DFACC_READ = 1 ! from hdf.inc + integer, parameter :: DFACC_READ = 1 ! from hdf.inc ! local variables - integer :: ii, jj, nn + integer :: N_lat, N_lon, N_tmp, ii, jj, kk, nn - real, dimension(N_lat) :: lat_c - real, dimension(N_lon) :: lon_c + real, dimension(:), allocatable :: lat_c + real, dimension(:), allocatable :: lon_c - real dimension(N_lat) :: lat_ind = (/(jj, jj=0, N_lat-1, 1)/) - real dimension(N_lon) :: lon_ind = (/(ii, ii=0, N_lon-1, 1)/) + real dimension(:), allocatable :: lat_ind + real dimension(:), allocatable :: lon_ind - integer :: status, file_id, sds_id, this_ind + integer, dimension(2) :: start, edge, stride, last - integer, dimension(2) :: start, edge, stride - - logical :: keep_data + logical :: file_exists, keep_data - integer :: sfstart, sfselect, sfn2index, sfrdata, sfend, sfendacc ! hdf functions + integer :: status, sd_id, sds_ind, sds_idex - unsigned(KIND=1), dimension(N_lat,N_lon) :: uint8_MODIS_SCF - unsigned(KIND=1), dimension(N_lat,N_lon) :: uint8_CI_Index - unsigned(KIND=1), dimension(N_lat,N_lon) :: uint8_Cloud_Index - unsigned(KIND=1), dimension(N_lat,N_lon) :: uint8_Snow_QA + integer :: SDstart, SDselect, SDnametoindex + integer :: SDreaddata, SDend, SDendacc + + unsigned(KIND=1), dimension(:,:), allocatable :: uint8_Snow_Cover + unsigned(KIND=1), dimension(:,:), allocatable :: uint8_Clear_Index + unsigned(KIND=1), dimension(:,:), allocatable :: uint8_Snow_Spatial_QA + + character(len=*), parameter :: Iam = 'read_MODISscf_hdf' + character(len=400) :: err_msg - character(len=*), parameter :: Iam = 'read_MODISscf_hdf' - character(len=400) :: err_msg - ! ------------------------------------------------------------------------- ! + ! make sure file exists + + inquire( file=trim(fname), exist=file_exists ) + + if (.not. file_exists ) then + + if (logit) then + write (logunit,*) trim(Iam), ': cannot find file ', trim(fname) + write (logunit,*) 'not reading MODIS SCF obs' + end if + + return + + else + + if (logit) then + write (logunit,*) trim(Iam), ': reading MODIS SCF obs from ', trim(fname) + write (logunit,*) 'lon_min, lon_max, lat_min, lat_max = ', & + lon_min, lon_max, lat_min, lat_max + end if + + end if + + ! ensure lat_* and lon_* inputs are within range + + if ( (lon_min < CMG_ll_lon) .or. & + (lon_max > CMG_ur_lon) .or. & + (lat_min < CMG_ll_lat) .or. & + (lat_max > CMG_ur_lat) ) then + + err_msg = 'lat/lon min/max inputs out of range' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + + end if + + ! determine MODIS CMG array indices for requested lat/lon_min/max range + ! MODIS CMG hdf files: ! - lat-by-lon (!) ! - index values increase eastward and southward - start(1) = (lat_max - CMG_ur_lat)/CMG_dlat ! 0-based [as required for hdf reads] - start(2) = (lon_min - CMG_ll_lon)/CMG_dlon ! 0-based [as required for hdf reads] - + start(1) = (CMG_ur_lat - lat_max )/CMG_dlat ! 0-based [as required for hdf read] + start(2) = (lon_min - CMG_ll_lon)/CMG_dlon ! 0-based [as required for hdf read] + + last(1) = (CMG_ur_lat - lat_min )/CMG_dlat ! 0-based [as required for hdf read] + last(2) = (lon_max - CMG_ll_lon)/CMG_dlon ! 0-based [as required for hdf read] + + N_lat = last(1) - start(1) + 1 + N_lon = last(2) - start(2) + 1 + edge(1) = N_lat edge(2) = N_lon stride(1) = 1 stride(2) = 1 + + ! checks array dimensions + + N_tmp = N_lat*N_lon + + if ( (N_tmp /= size(MODIS_lon)) .or. & + (N_tmp /= size(MODIS_lat)) .or. & + (N_tmp /= size(MODIS_SCF)) ) then + + err_msg = 'inconsistent array dimensions' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + + end if + + ! check array bounds + + if ( ( start(1) < 0 ) .or. ( start(1) > CMG_N_lat - 1 ) .or. & + ( start(2) < 0 ) .or. ( start(2) > CMG_N_lon - 1 ) .or. & + ( last( 1) < 0 ) .or. ( last( 1) > CMG_N_lat - 1 ) .or. & + ( last( 2) < 0 ) .or. ( last( 2) > CMG_N_lon - 1 ) .or. & + ( start(1) > last(1) ) .or. ( start(2) > last(2) ) & + ) then + + err_msg = 'start/edge indices out of bounds' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + + end if + + + ! allocate arrays + + allocate(lat_c( N_lat)) + allocate(lon_c( N_lon)) + + allocate(lat_ind(N_lat)) + allocate(lon_ind(N_lon)) + + allocate(uint8_Snow_Cover (N_lat,N_lon)) ! lat-by-lon !! + allocate(uint8_Clear_Index (N_lat,N_lon)) ! lat-by-lon !! + allocate(uint8_Snow_Spatial_QA(N_lat,N_lon)) ! lat-by-lon !! + + ! -------------------------- + + ! determine center lat/lon of CMG cells + + lat_ind = (/(jj, jj=0, N_lat-1, 1)/) ! =0:(N_lat-1) + lon_ind = (/(ii, ii=0, N_lon-1, 1)/) ! =0:(N_lon-1) ! lat_c, lon_c are lat/lon at center of CMG grid cell lat_c = CMG_ur_lat - 0.5*CMG_dlat - (start(1)+lat_ind)*CMG_dlat lon_c = CMG_ll_lon + 0.5*CMG_dlon + (start(2)+lon_ind)*CMG_dlon + + ! -------------------------- - - ! open and start "hdf file" + ! open hdf file (read-only) and initialize SD interface - file_id = sfstart(trim(fname), DFACC_READ) + sd_id = SDstart(trim(fname), DFACC_READ) + + if (sd_id<0) then + + err_msg = 'cannot SDstart (open) file: ' // trim(fname) + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + + end if + ! read data + do nn=1,N_fields - this_ind = sfn2index( file_id, trim(field_names(nn)) ) - sds_id = sfselect( file_id, this_ind ) + sds_index = SDnametoindex( sd_id, trim(field_names(nn)) ) + sds_id = SDselect( sd_id, sds_index ) select case (nn) - case (1) status = sfrdata( sds_id, start, stride, edge, uint8_MODIS_SCF ) - case (2) status = sfrdata( sds_id, start, stride, edge, uint8_CI_Index ) - case (3) status = sfrdata( sds_id, start, stride, edge, uint8_Cloud_Index ) - case (4) status = sfrdata( sds_id, start, stride, edge, uint8_Snow_QA ) - + case (1) status = SDreaddata( sds_id, start, stride, edge, uint8_Snow_Cover ) + case (2) status = SDreaddata( sds_id, start, stride, edge, uint8_Clear_Index ) + case (3) status = SDreaddata( sds_id, start, stride, edge, uint8_Snow_Spatial_QA ) + case default call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'unknown field') end select - status = sfendacc(sds_id) + status = SDendacc(sds_id) ! terminate access to SDS (field) - end do ! i=1,N_fields + end do - ! close hdf file - - status = sfend(file_id) + status = SDend(sd_id) ! close hdf file and SD interface ! ------------------------------------- ! - ! apply QC and put obs into output array + ! apply QC and put SCF obs into output array + MODIS_lon = SCF_nodata ! initialize + MODIS_lat = SCF_nodata ! initialize + MODIS_SCF = SCF_nodata ! initialize + + kk = 0 ! initialize counter for "good" data + do jj=1,N_lat do ii=1,N_lon - ! note: uint8 >= 0, no check for minimum needed - - keep_data = & - ( uint8_MODIS_SCF( jj,ii) <= qc_snow_cover_max ) .and. & - ( uint8_CI_Index( jj,ii) > qc_clear_index_min ) .and. & - ( uint8_CI_Index( jj,ii) <= qc_clear_index_max ) .and. & - ( uint8_Cloud_Index(jj,ii) /= qc_antarctica ) .and. & - ( uint8_Snow_QA( jj,ii) < qc_snow_spatial_max ) + ! note: uint8_Snow_Cover >= 0 per Fortran type, no need to check for minimum + keep_data = & + (uint8_Snow_Cover( jj,ii) <= qc_snow_cover_max ) .and. & ! 0<=SCF<=100 (1) + (uint8_Clear_Index( jj,ii) > qc_clear_index_min ) .and. & ! sufficiently clear sky (2) + (uint8_Snow_Spatial_QA(jj,ii) < qc_snow_spatial_max) ! keep "best", "good", or "OK" quality (3) + ! (1) excludes "lake ice", "night", "inland water", "ocean", "cloud obscured water", "data not mapped", "fill" + ! (2) clear_index>100 already removed via qc_snow_cover_max + ! (3) excludes Antarctica + ! NOTE: - ! - raw SCF value includes cloud cover - ! - transpose from lat-by-lon to lon-by-lat + ! - raw SCF value is for clear portion of the grid cell only, need to normalized with Clear_Index + ! - transpose from lat-by-lon uint8 array to lon-by-lat output array - if (keep_data) MODIS_SCF(ii,jj) = real(uint8_MODIS_SCF(jj,ii))/real(uint8_CI_Index(jj,ii)) + if (keep_data) then + + kk = kk + 1 + + MODIS_SCF(kk) = real(uint8_Snow_Cover(jj,ii))/real(uint8_Clear_Index(jj,ii)) + + MODIS_lon(kk) = lon_c(ii) + MODIS_lat(kk) = lat_c(jj) + + end if - end do - end do + end do + end do - N_data = j + N_good_data = kk - ADD GOOD DATA COUNTER - VERIFY WITH MATLAB + if (logit) write (logunit,*) 'N_good_data = ', N_good_data - end subroutine read_MODIS_hdf + + deallocate(lat_c) + deallocate(lon_c) + + deallocate(lat_ind) + deallocate(lon_ind) + + deallocate(uint8_Snow_Cover ) + deallocate(uint8_Clear_Index ) + deallocate(uint8_Snow_Spatial_QA) -#ENDIF + end subroutine read_MODIS_SCF_hdf ! ***************************************************************** ! ***************************************************************** From 446041b2dd1303fb5afce520668e55330bf993b0 Mon Sep 17 00:00:00 2001 From: Weiyuan Jiang Date: Mon, 23 Oct 2023 09:59:28 -0400 Subject: [PATCH 159/308] 1)save FFT allocation 2) add max_cat_daigS --- .../GEOS_LandAssimGridComp.F90 | 3 +- .../GEOS_LandPertGridComp.F90 | 3 +- .../LDAS_PertRoutines.F90 | 4 +- .../GEOSlandpert_GridComp/land_pert.F90 | 128 +++-- .../GEOSlandpert_GridComp/random_fields.F90 | 466 +++++++++--------- .../GEOSldas_GridComp/Shared/catch_types.F90 | 33 ++ 6 files changed, 355 insertions(+), 282 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 index a44ef2f1..4d4d67c5 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 @@ -51,6 +51,7 @@ module GEOS_LandAssimGridCompMod use catch_types, only: cat_progn_type use catch_types, only: cat_param_type use catch_types, only: cat_diagS_type + use catch_types, only: max_cat_diagS use catch_types, only: cat_diagS_sqrt use catch_types, only: assignment(=), operator (+), operator (-), operator (*), operator (/) use clsm_bias_routines, only: initialize_obs_bias @@ -2009,7 +2010,7 @@ subroutine RUN ( GC, IMPORT, EXPORT, CLOCK, RC ) cat_diagS_ensavg(ii) = cat_diagS_ensavg(ii)/real(NUM_ENSEMBLE) ! normalize --> ens avg - cat_diagS_ensstd(ii) = cat_diagS_sqrt( cat_diagS_ensstd(ii)/Nm1 - NdivNm1*(cat_diagS_ensavg(ii)*cat_diagS_ensavg(ii)) ) + cat_diagS_ensstd(ii) = cat_diagS_sqrt( max_cat_diagS(0.0, cat_diagS_ensstd(ii)/Nm1 - NdivNm1*(cat_diagS_ensavg(ii)*cat_diagS_ensavg(ii))) ) end do diff --git a/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/GEOS_LandPertGridComp.F90 b/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/GEOS_LandPertGridComp.F90 index 17470a5c..94d542c0 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/GEOS_LandPertGridComp.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/GEOS_LandPertGridComp.F90 @@ -24,7 +24,7 @@ module GEOS_LandPertGridCompMod use LDAS_TileCoordType, only: tile_coord_type use LDAS_TileCoordType, only: T_TILECOORD_STATE use LDAS_TileCoordType, only: TILECOORD_WRAP - use land_pert_routines, only: get_pert, propagate_pert + use land_pert_routines, only: get_pert, propagate_pert, clear_rf use land_pert_routines, only: get_init_pert_rseed use LDAS_PertRoutinesMod, only: apply_pert use LDAS_PertRoutinesMod, only: get_force_pert_param @@ -2807,6 +2807,7 @@ subroutine Finalize(gc, import, export, clock, rc) VERIFY_(status) end if + call clear_rf() ! Call Finalize for every child call MAPL_GenericFinalize(gc, import, export, clock, rc=status) VERIFY_(status) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/LDAS_PertRoutines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/LDAS_PertRoutines.F90 index cac58cdb..fafee341 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/LDAS_PertRoutines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/LDAS_PertRoutines.F90 @@ -2017,7 +2017,7 @@ end subroutine echo_pert_param ! WY noted :: -l is changed to _g. Only read part was kept subroutine io_pert_rstrt( action, work_path, exp_id, ens_id, & - date_time, tile_coord_g, pert_grid_g, pert_grid_f, & + date_time, pert_grid_g, pert_grid_f, & N_force_pert, N_progn_pert, Pert_rseed, & Force_pert_ntrmdt_g, Progn_pert_ntrmdt_g, rc ) @@ -2037,8 +2037,6 @@ subroutine io_pert_rstrt( action, work_path, exp_id, ens_id, & integer, intent(in) :: ens_id, N_force_pert, N_progn_pert - type(tile_coord_type), dimension(:), pointer :: tile_coord_g ! input - type(grid_def_type), intent(in) :: pert_grid_g, pert_grid_f integer, dimension(NRANDSEED), intent(inout) :: Pert_rseed diff --git a/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/land_pert.F90 b/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/land_pert.F90 index 5b9323d7..ff4cfb5a 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/land_pert.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/land_pert.F90 @@ -37,7 +37,8 @@ module land_pert_routines NRANDSEED, & init_randseed - use random_fields_class + use Random_FieldsMod + use StringRandom_fieldsMapMod use nr_jacobi, ONLY: & jacobi @@ -50,7 +51,8 @@ module land_pert_routines LDAS_GENERIC_ERROR use LDAS_ensdrv_Globals, only: root_logit, logunit - + + use MAPL implicit none ! everything is private by default unless made public @@ -62,9 +64,12 @@ module land_pert_routines public :: assemble_forcepert_param public :: get_sqrt_corr_matrix public :: get_init_Pert_rseed + public :: clear_rf ! ********************************************************************** + type(StringRandom_fieldsMap) :: random_fieldsMap + contains ! ********************************************************************** @@ -450,7 +455,7 @@ subroutine propagate_pert( & ! ! ---------------------- - integer :: i, j, m, n, rNlon, rNlat, xStride, yStride, imax, jmax + integer :: i, j, m, n, Nx, Ny, Nx_fft, Ny_fft, xStride, yStride, imax, jmax real :: cc, dd, xCorr, yCorr, tCorr, tmpReal, rdlon, rdlat @@ -462,7 +467,8 @@ subroutine propagate_pert( & integer :: tmpInt, xstart, xend, ystart, yend - type(random_fields) :: rf + type(random_fields), pointer :: rf + type(ESMF_VM) :: vm integer :: mpicomm, status @@ -501,36 +507,11 @@ subroutine propagate_pert( & ! get grid parameters for generation of new random fields on ! possibly coarsened grid - if (pert_param(m)%coarsen) then - - xStride = max( 1, floor(coarsen_param * xCorr / pert_grid_f%dlon) ) - yStride = max( 1, floor(coarsen_param * yCorr / pert_grid_f%dlat) ) - - ! NOTE: Latitude spacing is undefined for *local* EASE grids! - - else - - xStride = 1 - yStride = 1 - - end if - - rdlon = real(xStride)*pert_grid_f%dlon - rdlat = real(yStride)*pert_grid_f%dlat - - ! NOTE: number of grid cells of coarsened grid might not evenly divide - ! that of pert_grid_f - - rNlon = pert_grid_f%N_lon / xStride - rNlat = pert_grid_f%N_lat / yStride - - if (mod(pert_grid_f%N_lon,xStride)>0) rNlon = rNlon + 1 - if (mod(pert_grid_f%N_lat,yStride)>0) rNlat = rNlat + 1 + call calc_fft_grid(pert_param(m), pert_grid_f, Nx, Ny, Nx_fft, Ny_fft, xStride, yStride, rdlon, rdlat) ptr2rfield => rfield( 1:pert_grid_f%N_lon:xStride,1:pert_grid_f%N_lat:yStride) ptr2rfield2 => rfield2(1:pert_grid_f%N_lon:xStride,1:pert_grid_f%N_lat:yStride) - ! generate new random fields and propagate AR(1) ! ! Note that rfg2d always produces a pair of random fields! @@ -546,9 +527,9 @@ subroutine propagate_pert( & ! this needs to be done for each pert field #ifdef MKL_AVAILABLE ! W.J Note: hardcoded comm = mpicomm to activate parallel fft - call rf%initialize(rNlon, rNlat, 1., xCorr, yCorr, rdlon, rdlat, comm=mpicomm ) + rf => find_rf(Nx, Ny, Nx_fft, Ny_fft, comm=mpicomm ) #else - call rf%initialize(rNlon, rNlat, 1., xCorr, yCorr, rdlon, rdlat ) + rf => find_rf(Nx, Ny, Nx_fft, Ny_fft) #endif do n=1,N_ens @@ -559,14 +540,13 @@ subroutine propagate_pert( & call rf%generate_white_field(Pert_rseed(:,n), ptr2rfield) - else ! spatially correlated random fields ! NOTE: rfg2d_fft() relies on CXML math library (22 Feb 05) ! rfg2d_fft() now relies on Intel MKL (19 Jun 13) if (.not. stored_field) then - call rf%rfg2d_fft(Pert_rseed(:,n), ptr2rfield, ptr2rfield2) + call rf%rfg2d_fft(Pert_rseed(:,n), ptr2rfield, ptr2rfield2, xCorr, yCorr, rdlon, rdlat) stored_field = .true. else rfield = rfield2 @@ -632,12 +612,55 @@ subroutine propagate_pert( & end do ! n=1,N_ens ! finalize rf - call rf%finalize + ! The rf map will be destroy in the finalize of GEOSLandperp_Gridcomp + !call rf%finalize end do ! m=1,N_pert end subroutine propagate_pert + subroutine calc_fft_grid(pert_param, pert_grid_f, Nx, Ny, N_x_fft, N_y_fft, xStride, yStride, rdlon, rdlat) + type(pert_param_type), intent(in) :: pert_param + type(grid_def_type), intent(in) :: pert_grid_f + integer, intent(out) :: Nx, Ny, N_x_fft, N_y_fft, xStride, yStride + real, intent(out) :: rdlon, rdlat + + integer :: Nx_fft, Ny_fft + real, parameter :: mult_of_xcorr = 2. + real, parameter :: mult_of_ycorr = 2. + real, parameter :: coarsen_param = 0.8 + real :: xCorr, yCorr + + xCorr = pert_param%xcorr + yCorr = pert_param%ycorr + + xStride = 1 + yStride = 1 + if (pert_param%coarsen) then + xStride = max( 1, floor(coarsen_param * xCorr / pert_grid_f%dlon) ) + yStride = max( 1, floor(coarsen_param * yCorr / pert_grid_f%dlat) ) + endif + rdlon = real(xStride)*pert_grid_f%dlon + rdlat = real(yStride)*pert_grid_f%dlat + + ! NOTE: number of grid cells of coarsened grid might not evenly divide + ! that of pert_grid_f + + Nx = pert_grid_f%N_lon / xStride + Ny = pert_grid_f%N_lat / yStride + + if (mod(pert_grid_f%N_lon,xStride)>0) Nx = Nx + 1 + if (mod(pert_grid_f%N_lat,yStride)>0) Ny = Ny + 1 + + ! add minimum required correlation lengths + Nx_fft = Nx + ceiling(mult_of_xcorr*xCorr/rdlon) + Ny_fft = Ny + ceiling(mult_of_ycorr*yCorr/rdlat) + + ! ensure N_x_fft, N_y_fft are powers of two + N_x_fft = 2**ceiling(log(real(Nx_fft))/log(2.)) + N_y_fft = 2**ceiling(log(real(Ny_fft))/log(2.)) + + end subroutine ! ****************************************************************** subroutine truncate_std_normal( N_x, N_y, std_normal_max, grid_data ) @@ -1238,7 +1261,40 @@ subroutine get_sqrt_corr_matrix( N, A, S ) end subroutine get_sqrt_corr_matrix ! ************************************************************************ - + + function find_rf(Nx, Ny, Nx_fft, Ny_fft, comm) result (rf) + type(random_fields), pointer :: rf + integer, intent(in) :: Nx, Ny, Nx_fft, Ny_fft + integer, optional, intent(in) :: comm + + type(StringRandom_fieldsMapIterator) :: iter + Character(len=:), allocatable :: id_string + type(random_fields) :: rf_tmp + + id_string = i_to_string(Nx)//":"//i_to_string(Ny)//":"//i_to_string(Nx_fft)//":"//i_to_string(Ny_fft) + iter = random_fieldsMap%find(id_string) + if (iter == random_fieldsMap%end() ) then + rf_tmp = random_fields(Nx, Ny, Nx_fft, Ny_fft, comm=comm) + call random_fieldsMap%insert(id_string, rf_tmp) + iter = random_fieldsMap%find(id_string) + endif + rf => iter%value() + + end function + + subroutine clear_rf() + type(StringRandom_fieldsMapIterator) :: iter + type(random_fields), pointer :: rf_ptr + iter = random_fieldsMap%begin() + do while (iter /= random_fieldsMap%end()) + rf_ptr => iter%value() + call rf_ptr%finalize() + ! remove the files + call random_fieldsMap%erase(iter) + iter = random_fieldsMap%begin() + enddo + end subroutine + end module land_pert_routines ! *************************************************************************** diff --git a/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/random_fields.F90 b/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/random_fields.F90 index 835f469a..d270d04d 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/random_fields.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/random_fields.F90 @@ -30,7 +30,10 @@ #define NR_FALLBACK #endif -module random_fields_class +#include "MAPL_ErrLog.h" +#include "unused_dummy.H" + +module random_fieldsMod #ifdef MKL_AVAILABLE use, intrinsic :: iso_c_binding, only: c_loc, c_f_pointer, c_ptr, c_sizeof, C_NULL_PTR @@ -46,6 +49,8 @@ module random_fields_class nr_ran2_2d, & nr_gasdev + use MAPL_ExceptionHandling + implicit none private @@ -56,7 +61,6 @@ module random_fields_class type, public :: random_fields private integer :: N_x, N_y - real :: var, lx, ly, dx, dy integer :: N_x_fft, N_y_fft ! computed by calc_fft_grid real, allocatable :: field1_fft(:,:), field2_fft(:,:) integer :: fft_lens(2) ! length of each dim for 2D transform @@ -73,146 +77,137 @@ module random_fields_class integer, allocatable :: dim2_counts(:) #endif contains - procedure, public :: initialize +! procedure, public :: initialize procedure, public :: finalize procedure, public :: rfg2d_fft procedure, public :: generate_white_field procedure, private :: sqrt_gauss_spectrum_2d - procedure, private :: calc_fft_grid #ifdef MKL_AVAILABLE procedure, private :: win_allocate procedure, private :: win_deallocate #endif end type random_fields + + interface random_fields + module procedure new_random_fields + end interface contains ! constructor (set parameter values), allocate memory - subroutine initialize(this, Nx, Ny, var, lx, ly, dx, dy, comm) + function new_random_fields(Nx, Ny, Nx_fft, Ny_fft, comm, rc) result (rf) ! input/output variables [NEED class(random_fields) ! instead of type(random_fields)] - F2003 quirk?!? - class(random_fields), intent(inout) :: this - integer, intent(in) :: Nx, Ny - real, intent(in) :: var, lx, ly, dx, dy + type(random_fields) :: rf + integer, intent(in) :: Nx, Ny, Nx_fft, Ny_fft integer, optional, intent(in) :: comm - + integer, optional, intent(out) :: rc ! local variable - integer :: mklstat, ierror + integer :: status, ierror integer :: rank, npes, local_dim1, local_dim2, remainer - integer :: N1, N2, Stride(2) + integer :: Stride(2) ! set obj param vals - this%N_x = Nx - this%N_y = Ny - this%var = var - this%dx = dx - this%dy = dy - this%lx = lx - this%ly = ly + rf%N_x = Nx + rf%N_y = Ny - ! calculate fft grid (N_x_fft, N_y_fft) - call this%calc_fft_grid + ! ensure N_x_fft, N_y_fft are powers of two + rf%N_x_fft = Nx_fft + rf%N_y_fft = Ny_fft - ! lengths of transform in each dimension - this%fft_lens(1) = this%N_x_fft - this%fft_lens(2) = this%N_y_fft ! allocate memory - allocate(this%field1_fft(this%N_x_fft, this%N_y_fft)) - allocate(this%field2_fft(this%N_x_fft, this%N_y_fft)) + allocate(rf%field1_fft(rf%N_x_fft, rf%N_y_fft)) + allocate(rf%field2_fft(rf%N_x_fft, rf%N_y_fft)) #ifdef MKL_AVAILABLE if (present(comm)) then - this%comm = comm - - call MPI_Comm_split_type(this%comm, MPI_COMM_TYPE_SHARED, 0, MPI_INFO_NULL, this%Node_Comm,ierror) - call MPI_Comm_size(this%Node_Comm, npes,ierror) - call MPI_Comm_rank(this%Node_Comm, rank, ierror) + rf%comm = comm + call MPI_Comm_split_type(rf%comm, MPI_COMM_TYPE_SHARED, 0, MPI_INFO_NULL, rf%Node_Comm,ierror) + call MPI_Comm_size(rf%Node_Comm, npes,ierror) + call MPI_Comm_rank(rf%Node_Comm, rank, ierror) - N1 = this%fft_lens(1) - N2 = this%fft_lens(2) - - if (npes > minval([N1, N2]) ) then + if (npes > minval([Nx_fft, Ny_fft]) ) then print*, " Two many processors are acquired in a node for parallel FFT" - print*, " The number of processors acquired in a node should be smaller than or equal to FFT grid size: ", minval([N1, N2]) - call quit('Parallel FFT failed') + print*, " The number of processors acquired in a node should be smaller than or equal to FFT grid size: ", minval([Nx_fft, Ny_fft]) + _FAIL('Parallel FFT failed') endif - call this%win_allocate(N1, N2) + call rf%win_allocate(Nx_fft, Ny_fft, _RC) ! distribution of the grid for fft - allocate(this%dim1_counts(npes),this%dim2_counts(npes)) - local_dim1 = N1/npes - this%dim1_counts = local_dim1 - remainer = mod(N1, npes) - this%dim1_counts(1:remainer) = local_dim1 + 1 - local_dim1 = this%dim1_counts(rank+1) - - local_dim2 = N2/npes - this%dim2_counts = local_dim2 - remainer = mod(N2, npes) - this%dim2_counts(1:remainer) = local_dim2 + 1 - local_dim2 = this%dim2_counts(rank+1) - - - mklstat = DftiCreateDescriptor(this%Desc_Handle_Dim1, DFTI_SINGLE,& - DFTI_COMPLEX, 1, N1 ) - if (mklstat/= DFTI_NO_ERROR) call quit('DftiCreate dim1 failed!') - mklstat = DftiCreateDescriptor(this%Desc_Handle_Dim2, DFTI_SINGLE,& - DFTI_COMPLEX, 1, N2 ) - if (mklstat/= DFTI_NO_ERROR) call quit('DftiCreate dim2 failed!') + allocate(rf%dim1_counts(npes),rf%dim2_counts(npes)) + local_dim1 = Nx_fft/npes + rf%dim1_counts = local_dim1 + remainer = mod(Nx_fft, npes) + rf%dim1_counts(1:remainer) = local_dim1 + 1 + local_dim1 = rf%dim1_counts(rank+1) + + local_dim2 = Ny_fft/npes + rf%dim2_counts = local_dim2 + remainer = mod(Ny_fft, npes) + rf%dim2_counts(1:remainer) = local_dim2 + 1 + local_dim2 = rf%dim2_counts(rank+1) + + + status = DftiCreateDescriptor(rf%Desc_Handle_Dim1, DFTI_SINGLE,& + DFTI_COMPLEX, 1, Nx_fft ) + _VERIFY(status) + status = DftiCreateDescriptor(rf%Desc_Handle_Dim2, DFTI_SINGLE,& + DFTI_COMPLEX, 1, Ny_fft ) + _VERIFY(status) ! perform local_dim2 one-dimensional transforms along 1st dimension - mklstat = DftiSetValue( this%Desc_Handle_Dim1, DFTI_NUMBER_OF_TRANSFORMS, local_dim2 ) - if (mklstat/= DFTI_NO_ERROR) call quit('DftiSetValue DFTI_NUMBER_OF_TRANSFORMS failed!') - mklstat = DftiSetValue( this%Desc_Handle_Dim1, DFTI_INPUT_DISTANCE, N1 ) - if (mklstat/= DFTI_NO_ERROR) call quit('DftiSetValue N1 failed!') - mklstat = DftiSetValue( this%Desc_Handle_Dim1, DFTI_OUTPUT_DISTANCE, N1 ) - if (mklstat/= DFTI_NO_ERROR) call quit('DftiSetValue N2 failed!') - mklstat = DftiCommitDescriptor( this%Desc_Handle_Dim1 ) - if (mklstat/= DFTI_NO_ERROR) call quit('DftiCommit dim1 failed!') - ! mklstat = DftiComputeForward( this%Desc_Handle_Dim1, X ) + status = DftiSetValue( rf%Desc_Handle_Dim1, DFTI_NUMBER_OF_TRANSFORMS, local_dim2 ) + _VERIFY(status) + status = DftiSetValue( rf%Desc_Handle_Dim1, DFTI_INPUT_DISTANCE, Nx_fft ) + _VERIFY(status) + status = DftiSetValue( rf%Desc_Handle_Dim1, DFTI_OUTPUT_DISTANCE, Nx_fft ) + _VERIFY(status) + status = DftiCommitDescriptor( rf%Desc_Handle_Dim1 ) + _VERIFY(status) + ! status = DftiComputeForward( rf%Desc_Handle_Dim1, X ) ! local_dim1 one-dimensional transforms along 2nd dimension Stride(1) = 0; Stride(2) = local_dim1 - mklstat = DftiSetValue( this%Desc_Handle_Dim2, DFTI_NUMBER_OF_TRANSFORMS, local_dim1) - if (mklstat/= DFTI_NO_ERROR) call quit('DftiSetValue local_dim1 failed!') - mklstat = DftiSetValue( this%Desc_Handle_Dim2, DFTI_INPUT_DISTANCE, 1 ) - if (mklstat/= DFTI_NO_ERROR) call quit('DftiSetValue in distance failed!') - mklstat = DftiSetValue( this%Desc_Handle_Dim2, DFTI_OUTPUT_DISTANCE, 1 ) - if (mklstat/= DFTI_NO_ERROR) call quit('DftiSetValue out distance failed!') - mklstat = DftiSetValue( this%Desc_Handle_Dim2, DFTI_INPUT_STRIDES, Stride ) - if (mklstat/= DFTI_NO_ERROR) call quit('DftiSetValue in_stride failed!') - mklstat = DftiSetValue( this%Desc_Handle_Dim2, DFTI_OUTPUT_STRIDES, Stride ) - if (mklstat/= DFTI_NO_ERROR) call quit('DftiSetValue outstride failed!') - mklstat = DftiCommitDescriptor( this%Desc_Handle_Dim2 ) - if (mklstat/= DFTI_NO_ERROR) call quit('DftiCommit Dim2 failed!') - !mklstat = DftiComputeForward( this%Desc_Handle_Dim2, X ) + status = DftiSetValue( rf%Desc_Handle_Dim2, DFTI_NUMBER_OF_TRANSFORMS, local_dim1) + _VERIFY(status) + status = DftiSetValue( rf%Desc_Handle_Dim2, DFTI_INPUT_DISTANCE, 1 ) + _VERIFY(status) + status = DftiSetValue( rf%Desc_Handle_Dim2, DFTI_OUTPUT_DISTANCE, 1 ) + _VERIFY(status) + status = DftiSetValue( rf%Desc_Handle_Dim2, DFTI_INPUT_STRIDES, Stride ) + _VERIFY(status) + status = DftiSetValue( rf%Desc_Handle_Dim2, DFTI_OUTPUT_STRIDES, Stride ) + _VERIFY(status) + status = DftiCommitDescriptor( rf%Desc_Handle_Dim2 ) + _VERIFY(status) + !status = DftiComputeForward( rf%Desc_Handle_Dim2, X ) else - this%comm = MPI_COMM_NULL + rf%comm = MPI_COMM_NULL ! allocate mem and init mkl dft - mklstat = DftiCreateDescriptor(this%Desc_Handle, DFTI_SINGLE, DFTI_COMPLEX, 2, this%fft_lens) - if (mklstat/=DFTI_NO_ERROR) call quit('DftiCreateDescriptor failed!') + status = DftiCreateDescriptor(rf%Desc_Handle, DFTI_SINGLE, DFTI_COMPLEX, 2, [Nx_fft, Ny_fft]) + _VERIFY(status) ! initialize for actual dft computation - mklstat = DftiCommitDescriptor(this%Desc_Handle) - if (mklstat/=DFTI_NO_ERROR) call quit('DftiCommitDescriptor failed!') + status = DftiCommitDescriptor(rf%Desc_Handle) + _VERIFY(status) endif #endif - - end subroutine initialize + _RETURN(_SUCCESS) + end function new_random_fields ! destructor - deallocate memory - subroutine finalize(this) + subroutine finalize(this, rc) ! input/output variables class(random_fields), intent(inout) :: this - + integer, optional, intent(out) :: rc ! local variable - integer :: mklstat + integer :: status ! deallocate memory if(allocated(this%field1_fft)) deallocate(this%field1_fft) @@ -220,16 +215,16 @@ subroutine finalize(this) #ifdef MKL_AVAILABLE if (this%comm == MPI_COMM_NULL) then - mklstat = DftiFreeDescriptor(this%Desc_Handle) - if (mklstat/=DFTI_NO_ERROR) call quit('DftiFreeDescriptor failed!') + status = DftiFreeDescriptor(this%Desc_Handle) + _VERIFY(status) else - mklstat = DftiFreeDescriptor(this%Desc_Handle_dim1) - if (mklstat/=DFTI_NO_ERROR) call quit('DftiFreeDescriptor dim1 failed!') - mklstat = DftiFreeDescriptor(this%Desc_Handle_dim2) - if (mklstat/=DFTI_NO_ERROR) call quit('DftiFreeDescriptor dim2 failed!') + status = DftiFreeDescriptor(this%Desc_Handle_dim1) + _VERIFY(status) + status = DftiFreeDescriptor(this%Desc_Handle_dim2) + _VERIFY(status) - call this%win_deallocate() + call this%win_deallocate( _RC) deallocate(this%dim1_counts, this%dim2_counts) endif @@ -238,44 +233,6 @@ subroutine finalize(this) end subroutine finalize - - ! calculate fft grid (N_x_fft, N_y_fft) that extends - ! beyond the desired random field by about two correlation - ! lengths. its dimensions should be powers of 2 - subroutine calc_fft_grid(this) - - ! input/output variables - class(random_fields), intent(inout) :: this - - ! local variables - real, parameter :: mult_of_xcorr = 2. - real, parameter :: mult_of_ycorr = 2. - integer :: Nx_fft, Ny_fft - - ! add minimum required correlation lengths - Nx_fft = this%N_x + ceiling(mult_of_xcorr*this%lx/this%dx) - Ny_fft = this%N_y + ceiling(mult_of_ycorr*this%ly/this%dy) - - ! ensure N_x_fft, N_y_fft are powers of two - this%N_x_fft = 2**ceiling(log(real(Nx_fft))/log(2.)) - this%N_y_fft = 2**ceiling(log(real(Ny_fft))/log(2.)) - -#if TEST_RFG2D - write (*,*) - write (*,*) 'desired random field:' - write (*,*) 'N_x = ', this%N_x, ' N_y = ', this%N_y - write (*,*) 'dx = ', this%dx, ' dy = ', this%dy - write (*,*) 'xcorr = ', this%lx, ' ycorr = ', this%ly - write (*,*) - write (*,*) 'grid used for fft: ' - write (*,*) 'N_x_fft = ', this%N_x_fft, ' N_y_fft = ', this%N_y_fft - write (*,*) -#endif - - end subroutine calc_fft_grid - - - ! subroutine sqrt_gauss_spectrum_2d() ! ! get SQUARE ROOT of 2d Gaussian spectrum (incl volume element) @@ -307,24 +264,26 @@ end subroutine calc_fft_grid ! lambda_y : decorrelation length in y direction ! ! modifies this%field1_fft - subroutine sqrt_gauss_spectrum_2d(this) + subroutine sqrt_gauss_spectrum_2d(this, lx, ly, dx, dy) ! input/output variables class(random_fields), intent(inout) :: this + real, intent(in) :: lx, ly, dx, dy ! local variables real :: dkx, dky, fac, lamx2dkx2, lamy2dky2 real :: lx2kx2(this%N_x_fft), ly2ky2(this%N_y_fft) integer :: i, j, i1, i2, rank, ierror - + real :: var + var = 1.0 ! start - dkx = (TWO_PI)/(float(this%N_x_fft)*this%dx) - dky = (TWO_PI)/(float(this%N_y_fft)*this%dy) + dkx = (TWO_PI)/(float(this%N_x_fft)*dx) + dky = (TWO_PI)/(float(this%N_y_fft)*dy) ! factor includes sqrt of volume element of ifft integral - fac = sqrt(this%var*this%lx*this%ly/(TWO_PI)*dkx*dky ) - lamx2dkx2 = this%lx*this%lx*dkx*dkx - lamy2dky2 = this%ly*this%ly*dky*dky + fac = sqrt(var*lx*ly/(TWO_PI)*dkx*dky ) + lamx2dkx2 = lx*lx*dkx*dkx + lamy2dky2 = ly*ly*dky*dky ! precompute (lambda_x*k_x)^2 in "wrap-around" ! order suitable for CXML fft @@ -416,12 +375,13 @@ end subroutine sqrt_gauss_spectrum_2d ! The individual sample variances within each pair vary from ! realization to realization. ! - subroutine rfg2d_fft(this, rseed, rfield, rfield2) + subroutine rfg2d_fft(this, rseed, rfield, rfield2, lx, ly, dx, dy) ! input/output variables class(random_fields), intent(inout) :: this ! ffield*_fft is modified integer, intent(inout) :: rseed(NRANDSEED) ! nr_ran2 modifies rseed real, dimension(this%N_x,this%N_y), intent(out) :: rfield, rfield2 + real, intent(in) :: lx, ly, dx, dy ! local variables !real :: theta, ran_num ! rng @@ -431,7 +391,7 @@ subroutine rfg2d_fft(this, rseed, rfield, rfield2) integer :: N_x_fft, N_y_fft real :: N_xy_fft_real #ifdef MKL_AVAILABLE - integer :: mklstat + integer :: status complex, allocatable :: z_inout(:) complex, pointer :: tmp_field(:,:) complex, pointer :: tmp_field_dim1(:,:) @@ -451,7 +411,7 @@ subroutine rfg2d_fft(this, rseed, rfield, rfield2) ! compute dZ = H * exp(i*theta) * sqrt(d2k) ! start with square root of spectrum (factor H*sqrt(d2k)), put into field1 ! modify this%field1_fft - call this%sqrt_gauss_spectrum_2d + call this%sqrt_gauss_spectrum_2d(lx, ly, dx, dy) ! multiply by random phase angle !! do j=1,N_y_fft @@ -508,8 +468,8 @@ subroutine rfg2d_fft(this, rseed, rfield, rfield2) ! compute in-place backward transform (scale=1) ! NOTE: MKL backward transform is the same as NR forward transform - mklstat = DftiComputeBackward(this%Desc_Handle, z_inout) - if (mklstat/= DFTI_NO_ERROR) call quit('DftiComputeBackward failed!') + status = DftiComputeBackward(this%Desc_Handle, z_inout) + if (status/= DFTI_NO_ERROR) call quit('DftiComputeBackward failed!') ! extract random fields from z_inout z_inout = z_inout/N_xy_fft_real @@ -532,8 +492,8 @@ subroutine rfg2d_fft(this, rseed, rfield, rfield2) tmp_field_dim1 = cmplx(this%field1_fft(n1:n2,:),this%field2_fft(n1:n2,:)) cptr = c_loc(tmp_field_dim1(1,1)) call c_f_pointer (cptr, X, [ldim1*N_y_fft]) - mklstat = DftiComputeBackward( this%Desc_Handle_Dim2, X ) - if (mklstat/= DFTI_NO_ERROR) call quit('DftiComputeBackward dim2 failed!') + status = DftiComputeBackward( this%Desc_Handle_Dim2, X ) + if (status/= DFTI_NO_ERROR) call quit('DftiComputeBackward dim2 failed!') call MPI_Barrier(this%node_comm, ierror) tmp_field(n1:n2,:) = tmp_field_dim1 @@ -546,8 +506,8 @@ subroutine rfg2d_fft(this, rseed, rfield, rfield2) tmp_field_dim2 = tmp_field(:,n1:n2) cptr = c_loc(tmp_field_dim2(1,1)) call c_f_pointer (cptr, X, [N_x_fft*ldim2]) - mklstat = DftiComputeBackward( this%Desc_Handle_Dim1, X ) - if (mklstat/= DFTI_NO_ERROR) call quit('DftiComputeBackward dim1 failed!') + status = DftiComputeBackward( this%Desc_Handle_Dim1, X ) + if (status/= DFTI_NO_ERROR) call quit('DftiComputeBackward dim1 failed!') tmp_field(:,n1:n2) = tmp_field_dim2/N_xy_fft_real call MPI_Win_fence(0, this%win, ierror) @@ -646,8 +606,6 @@ subroutine generate_white_field(this, rseed, rfield) end if end subroutine generate_white_field - - ! a local, small stop routine subroutine quit(message) @@ -661,9 +619,10 @@ subroutine quit(message) end subroutine quit - subroutine win_allocate(this, nx, ny) + subroutine win_allocate(this, nx, ny, rc) class(random_fields), intent(inout) :: this integer, intent(in) :: nx, ny + integer, optional, intent(out) :: rc complex :: dummy integer(kind=MPI_ADDRESS_KIND) :: windowsize integer :: disp_unit,status, Rank @@ -677,117 +636,142 @@ subroutine win_allocate(this, nx, ny) disp_unit = 4 call MPI_Win_allocate_shared(windowsize, disp_unit, MPI_INFO_NULL, this%node_comm, & this%base_address, this%win, status) - + _VERIFY(status) if (rank /=0) CALL MPI_Win_shared_query(this%win, 0, windowsize, disp_unit, this%base_address, status) call MPI_Win_fence(0, this%win, status) + _VERIFY(status) call MPI_Barrier(this%node_comm, status) + _VERIFY(status) + _RETURN(_SUCCESS) end subroutine win_allocate - subroutine win_deallocate(this) + subroutine win_deallocate(this, rc) class(random_fields), intent(inout) :: this + integer, optional, intent(out) :: rc integer :: status call MPI_Win_fence(0, this%win, status) - call MPI_Win_free(this%win,status) + _VERIFY(status) + call MPI_Win_free(this%win, status) + _VERIFY(status) call MPI_comm_free(this%node_comm, status) + _VERIFY(status) end subroutine win_deallocate -end module random_fields_class +end module Random_fieldsMod +module StringRandom_fieldsMapMod + use Random_fieldsMod +#include "types/key_deferredLengthString.inc" +#define _value type (random_fields) +#define _value_equal_defined -#ifdef TEST_RFG2D +#define _map StringRandom_fieldsMap +#define _iterator StringRandom_fieldsMapIterator -program test_rfg2d - - use random_fields_class - use nr_ran2_gasdev - - implicit none - - integer :: N_x, N_y, i, j, n_e, N_e_tot - real :: dx, dy, lx, ly, var - real, allocatable, dimension(:,:) :: field1, field2 - - character(300) :: file_name - character(10) :: n_e_string - character(100) :: output_format - character(10) :: tmp_string +#define _alt - integer :: RSEEDCONST - integer, dimension(NRANDSEED) :: rseed - - character(5) :: fft_tag - - ! instance of random_fields - type(random_fields) :: rf - - ! start - RSEEDCONST = -777 - rseed(1) = RSEEDCONST - write (*,*) RSEEDCONST - call init_randseed(rseed) - - N_x = 144 - N_y = 91 - dx = 5000. - dy = 5000. - lx = 45000. - ly = 45000. - var = 1. - - - allocate(field1(N_x,N_y)) - allocate(field2(N_x,N_y)) - -#ifdef MKL_AVAILABLE - fft_tag = 'mklx.' -#else - fft_tag = 'nrxx.' -#endif +#include "templates/map.inc" - ! get N_e fields - N_e_tot = 10 - do n_e=1,N_e_tot,2 - - call rf%initialize(N_x, N_y, var, lx, ly, dx, dy) - call rf%rfg2d_fft(rseed, field1, field2) - !call rf%generate_white_field(rseed, field1) - call rf%finalize - - ! write to file - ! field1 - write(n_e_string, '(i3.3)') n_e - file_name = 'rf.'//fft_tag// n_e_string(1:len_trim(n_e_string)) // '.dat' - write(tmp_string, '(i3.3)') N_y - output_format = '(' // tmp_string(1:len_trim(tmp_string)) // '(1x,e13.5))' - open (10,file=file_name,status='unknown') - do i=1,N_x - write (10,output_format(1:len_trim(output_format))) (field1(i,j), j=1,N_y) - end do - close (10,status='keep') - - ! field2 - write(n_e_string, '(i3.3)') n_e+1 - file_name = 'rf.' //fft_tag// n_e_string(1:len_trim(n_e_string)) // '.dat' - write(tmp_string, '(i3.3)') N_y - output_format = '(' // tmp_string(1:len_trim(tmp_string)) // '(1x,e13.5))' - open (10,file=file_name,status='unknown') - do i=1,N_x - write (10,output_format(1:len_trim(output_format))) (field2(i,j), j=1,N_y) - end do - close (10,status='keep') - - end do - -end program test_rfg2d +#undef _alt +#undef _iterator +#undef _map +#undef _value +#undef _key +#undef _value_equal_defined +end module StringRandom_fieldsMapMod -#endif +#ifdef TEST_RFG2D +!program test_rfg2d +! +! use Random_fieldsMod +! use nr_ran2_gasdev +! +! implicit none +! +! integer :: N_x, N_y, i, j, n_e, N_e_tot +! real :: dx, dy, lx, ly, var +! real, allocatable, dimension(:,:) :: field1, field2 +! +! character(300) :: file_name +! character(10) :: n_e_string +! character(100) :: output_format +! character(10) :: tmp_string +! +! integer :: RSEEDCONST +! integer, dimension(NRANDSEED) :: rseed +! +! character(5) :: fft_tag +! +! ! instance of random_fields +! type(random_fields) :: rf +! +! ! start +! RSEEDCONST = -777 +! rseed(1) = RSEEDCONST +! write (*,*) RSEEDCONST +! call init_randseed(rseed) +! +! N_x = 144 +! N_y = 91 +! dx = 5000. +! dy = 5000. +! lx = 45000. +! ly = 45000. +! var = 1. +! +! +! allocate(field1(N_x,N_y)) +! allocate(field2(N_x,N_y)) +! +!#ifdef MKL_AVAILABLE +! fft_tag = 'mklx.' +!#else +! fft_tag = 'nrxx.' +!#endif +! +! ! get N_e fields +! N_e_tot = 10 +! do n_e=1,N_e_tot,2 +! +! rf = random_fields(N_x, N_y, Nx_fft, Ny_fft) +! call rf%rfg2d_fft(rseed, field1, field2, lx, ly, dx, dy) +! !call rf%generate_white_field(rseed, field1) +! call rf%finalize +! +! ! write to file +! ! field1 +! write(n_e_string, '(i3.3)') n_e +! file_name = 'rf.'//fft_tag// n_e_string(1:len_trim(n_e_string)) // '.dat' +! write(tmp_string, '(i3.3)') N_y +! output_format = '(' // tmp_string(1:len_trim(tmp_string)) // '(1x,e13.5))' +! open (10,file=file_name,status='unknown') +! do i=1,N_x +! write (10,output_format(1:len_trim(output_format))) (field1(i,j), j=1,N_y) +! end do +! close (10,status='keep') +! +! ! field2 +! write(n_e_string, '(i3.3)') n_e+1 +! file_name = 'rf.' //fft_tag// n_e_string(1:len_trim(n_e_string)) // '.dat' +! write(tmp_string, '(i3.3)') N_y +! output_format = '(' // tmp_string(1:len_trim(tmp_string)) // '(1x,e13.5))' +! open (10,file=file_name,status='unknown') +! do i=1,N_x +! write (10,output_format(1:len_trim(output_format))) (field2(i,j), j=1,N_y) +! end do +! close (10,status='keep') +! +! end do +! +!end program test_rfg2d -! ======= EOF ================================================== +#endif +! ======= EOF ================================================== diff --git a/src/Components/GEOSldas_GridComp/Shared/catch_types.F90 b/src/Components/GEOSldas_GridComp/Shared/catch_types.F90 index df22a2b3..569050b7 100644 --- a/src/Components/GEOSldas_GridComp/Shared/catch_types.F90 +++ b/src/Components/GEOSldas_GridComp/Shared/catch_types.F90 @@ -41,6 +41,7 @@ module catch_types public :: cat_diagS_sqrt public :: catprogn2wesn, catprogn2htsn, catprogn2sndz, catprogn2ghtcnt + public :: max_cat_diagS ! ------------------------------------------------------------------------- ! @@ -1368,6 +1369,38 @@ function catprogn2ghtcnt(N_cat, cat_progn) end function catprogn2ghtcnt ! *********************************************************************** + + function max_cat_diagS( scalar, cat_diagS ) + + implicit none + + type(cat_diagS_type) :: max_cat_diagS + type(cat_diagS_type), intent(in) :: cat_diagS + + real, intent(in) :: scalar + + integer :: i ! local + + max_cat_diagS%ar1 = max(scalar, cat_diagS%ar1) + max_cat_diagS%ar2 = max(scalar, cat_diagS%ar2) + + max_cat_diagS%asnow = max(scalar, cat_diagS%asnow) + + max_cat_diagS%sfmc = max(scalar, cat_diagS%sfmc) + max_cat_diagS%rzmc = max(scalar, cat_diagS%rzmc) + max_cat_diagS%prmc = max(scalar, cat_diagS%prmc) + + max_cat_diagS%tsurf = max(scalar, cat_diagS%tsurf) + + do i=1,N_gt + max_cat_diagS%tp(i) = max(scalar, cat_diagS%tp(i)) + end do + + do i=1,N_snow + max_cat_diagS%tpsn(i) = max(scalar, cat_diagS%tpsn(i)) + end do + + end function max_cat_diagS end module catch_types From 5095b32fb8e29d7e37e58f0aa1117cf71121e25c Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Tue, 24 Oct 2023 13:41:54 -0400 Subject: [PATCH 160/308] preliminary version of revised MODIS SCF reader --- .../clsm_ensupd_read_obs.F90 | 818 ++++-------------- 1 file changed, 166 insertions(+), 652 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 1e0cfc44..fe9da260 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -4589,540 +4589,13 @@ subroutine read_obs_SMOS( date_time, N_catd, this_obs_param, & end subroutine read_obs_SMOS - ! ***************************************************************** - - subroutine read_MODISscf_hdf( N_files, date_time, N_data, fnames, & - MODIS_lon, MODIS_lat, MODIS_SCF) - - ! Purpose: read preprocessed (renamed) snow cover data from daily MODIS Terra MOD10C1, version 6.1 (https://nsidc.org/data/mod10c1/versions/61) - ! - Data currently located at /discover/nobackup/projects/S2SHMA/MODIS/MOD10C1_V61/ (2010-2022) - ! - Daily dataset with spatial resolution of 0.05 deg on CMG grid, missing days 2016 d. 50-58 - ! - ! Procedures: - ! - dtstep_assim and ref_time is restricted to 3 hr and 00z, respectively - ! - Generate the latitude and longitude on CMG grid - ! - Select longitude band considering MODIS observation time (local time: ~10:30am) ! HARDWIRED OVERPASS TIME, WHAT ABOUT AQUA !?!?!!?!?!?!?! - ! - ! Table. Longitude band based on the assimilation time step (in UTC) - !----------------------------------------------------------------------------- - ! UTC | 0000 | 0300 | 0600 | 0900 | 1200 | 1500 | 1800 | 2100 - ! lon | 135 180 | 90 135 | 45 90 | 0 45 | -45 0| -90 -45| -135 -90| -180 -135 - !----------------------------------------------------------------------------- - ! - ! QC: - ! - Use Day_CMG_Snow_Cover <= 100 (snow cover only) - ! - Use Day_CMG_Clear_Index > 20% (at least 20% clear sky) - ! - Use Day_CMG_Cloud_Obscured /= 252 (remove Antarctica, not technically needed because this would be done by Snow_Spatial_QA) - ! - Use Snow_Spatial_QA <= 2 (use "best", "good", "ok"; exclude "poor", "other", etc) - - implicit none - - integer, intent(in) :: N_files - type(date_time_type), intent(in) :: date_time ! need UTC hour to constrain longitude of MODIS obs - character(*), dimension(N_files), intent(in) :: fnames - - integer, intent(out) :: N_data - - real, dimension(:), pointer :: MODIS_lon, MODIS_lat, MODIS_SCF ! output - - ! locals - - real, dimension(:), allocatable :: SCF_raw, SCF_tmp, lon_tmp, lat_tmp - - character(1), dimension(:,:), allocatable :: tmp_MODIS_SCF, tmp_CI_Index, tmp_Cloud_index, tmp_Snow_QA - - ! local parameters - - integer, parameter:: N_fields = 4 - character(18), parameter:: Vdata_name = 'MODIS_CMG_Snow_5km' - character(30), dimension(N_fields), parameter:: field_names = (/ & - 'Day_CMG_Snow_Cover ', & ! 1 - 'Day_CMG_Clear_Index ', & ! 2 - 'Day_CMG_Cloud_Obscured ', & ! 3 - 'Snow_Spatial_QA '/) ! 4 - - integer, parameter :: nodata = -9999 - - integer, parameter :: qc_snow_cover_min = 0 ! any negative value is no-data - integer, parameter :: qc_snow_cover_max = 100 ! screen for areas inland water, ocean, cloud obscured and fill - integer, parameter :: qc_clear_index_min = 20 ! screen for sufficiently clear condition - integer, parameter :: qc_clear_index_max = 100 ! screen for lake ice, night, inland water, ocean, etc - integer, parameter :: qc_antarctica = 252 ! screen for antarctica - integer, parameter :: qc_snow_spatial_max = 2 ! screen for basic data quality (0=best, 1=good, 2=OK, 3=poor, 4=other) - - ! hdf functions - - integer:: sfstart, sffinfo, sfselect, sfn2index, sfginfo, sfrdata - integer:: sfend, sfendacc - - ! hdf-related parameters and variables - - integer, dimension(N_files) :: file_id, sd_id - integer, dimension(N_fields) :: ind, sds_id - integer :: n_datasets, n_file_attrs, n_attrs, rank, data_type - integer :: dim_sizes(2) - integer :: start(2), edges(2), stride(2) - character(100) :: var_name - - integer :: status - - integer, parameter :: DFACC_READ = 1 ! from hdf.inc - integer, parameter :: DFNT_UINT8 = 21 - integer, parameter :: FULL_INTERLACE = 0 ! from hdf.inc - - logical :: keep_data - - ! variables to define latitude and longitude - - integer :: i, j, k, k_off, ll, mm, kk, L - integer :: time_index - - real, parameter :: bin_size = 0.05 - integer, parameter :: XGRID = 3600 - integer, parameter :: YGRID = 7200 - - integer, dimension(N_files) :: N_data_tmp - - real :: lat_ind(XGRID) = (/(ll, ll=0, XGRID-1, 1)/) - real :: lon_ind(YGRID) = (/(mm, mm=0, YGRID-1, 1)/) - real, dimension(XGRID) :: lat_c(XGRID) - real, dimension(YGRID) :: lon_c(YGRID) - real,dimension(XGRID*YGRID) :: lat_1D, lon_1D - real :: lon_subtime(9) = (/(kk, kk=180, -180, -45)/) - - integer, dimension(:), allocatable :: Snow_QA, CI_Index, Cloud_Index - character(len=*), parameter :: Iam = 'read_MODISscf_hdf' - character(len=400) :: err_msg - - ! ------------------------------------------------------------------------- - - ! initialize N_data - - N_data_tmp(N_files) = XGRID*YGRID !?!?!?! WHY ONLY FOR LAST ELEMENT???? - N_data = XGRID*YGRID - - ! Define latitude and longitude - ! - ! VERIFY THAT lat/lon DEFINITION HERE IS CONSISTENT WITH lat/lon STORED IN FILE ????? - ! PER FILE SPECS: - ! Lat = Upper left X coordinate for each grid cell in degrees north - ! Lon = Upper left Y coordinate for each grid cell in degrees east - - lat_c = ( 90-bin_size/2)-bin_size*lat_ind - lon_c = (-180+bin_size/2)+bin_size*lon_ind - - ! Create a 1D structure for lat and lon (could change to remove this) - - do i=1,7200 - - lat_1D(3600*(i-1)+1:3600*i)= lat_c - lon_1D(3600*(i-1)+1:3600*i)= lon_c(i) - - end do - - ! Ensure output pointers are not allocated (must be deallocated outside this subroutine) - - if ( associated(MODIS_lon) .or. associated(MODIS_lat) .or. associated(MODIS_SCF) ) then - - err_msg = 'output pointers must not be associated/allocated on input.' - call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) - - end if - - ! Allocate SCF and QC vectors - - allocate(SCF_raw( N_data)) - allocate(CI_Index( N_data)) - allocate(Snow_QA( N_data)) - allocate(Cloud_Index(N_data)) - - ! read hdf data into arrays, concatenate data from N_files files !?!?!?!?! NOT HAPPENING... - - k_off = 0 - - do j=1,N_files - - ! open and start "hdf file" - - sd_id(j) = sfstart(fnames(j), DFACC_READ) - - !if (logit) write (logunit,*), 'sd_id:' , sd_id(j) - - status = sffinfo( sd_id(j), n_datasets, n_file_attrs ) - - do i=1,N_fields - - ind(i) = sfn2index(sd_id(j), trim(field_names(i))) - sds_id(i) = sfselect( sd_id(j), ind(i)) - - status = sfginfo( sds_id(i), var_name, rank, dim_sizes, data_type, n_attrs ) - - start(1) = 0 - start(2) = 0 - edges(1) = dim_sizes(1) - edges(2) = dim_sizes(2) - stride(1) = 1 - stride(2) = 1 - - ! read 2-dim data and convert to 1-dim arrays (!?!?!?!? WOULD MAKE SENSE IF CONCATENATING DATA FROM MULTIPLE FILES) - - select case (i) - - case (1) ! Observed SCF (in percent) - - allocate(tmp_MODIS_SCF(dim_sizes(1),dim_sizes(2))) - status = sfrdata(sds_id(i), start, stride, edges, tmp_MODIS_SCF) - - L=0 - do k=1,YGRID - do kk=1,XGRID - L=L+1 - SCF_raw(L) = ichar(tmp_MODIS_SCF(k,kk)) ! !?!?!?!!? ichar()??? GNU manual: ICHAR(C) returns the code for the character in the first character position of C in the system’s native character set. The correspondence between characters and their codes is not necessarily the same across different GNU Fortran implementations. - end do - - end do - - case (2) ! Clear Index - - allocate(tmp_CI_Index(dim_sizes(1),dim_sizes(2))) - status = sfrdata(sds_id(i), start, stride, edges, tmp_CI_Index) - - L=0 - do k=1,YGRID - do kk=1,XGRID - L=L+1 - CI_Index(L) = ichar(tmp_CI_index(k,kk)) - end do - - end do - - case (3) ! Cloud Index - - allocate(tmp_Cloud_Index(dim_sizes(1),dim_sizes(2))) - status = sfrdata(sds_id(i), start, stride, edges, tmp_Cloud_Index) - - L=0 - do k=1,YGRID - do kk=1,XGRID - L = L+1 - Cloud_Index(L) = ichar(tmp_Cloud_Index(k,kk)) - end do - - end do - - case (4) ! Snow_QA - - allocate(tmp_Snow_QA(dim_sizes(1),dim_sizes(2))) - status = sfrdata(sds_id(i), start, stride, edges, tmp_Snow_QA) - - L=0 - do k=1,YGRID - do kk=1,XGRID - L = L+1 - Snow_QA(L) = ichar(tmp_Snow_QA(k,kk)) - end do - - end do - - case default - - call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'Unknown case') - - end select - - if (dim_sizes(1)*dim_sizes(2)/=N_data_tmp(j)) then - - call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'ERROR reading hdf') - - end if - - status = sfendacc(sds_id(i)) - - end do ! i=1,N_fields - - ! clean up - - deallocate(tmp_MODIS_SCF) - deallocate(tmp_CI_index) - deallocate(tmp_Cloud_index) - deallocate(tmp_Snow_QA) - - ! close hdf files - - status = sfend(file_id(j)) - - end do ! j=1,N_files ! IF MORE THAN ONE FILE IS READ, DATA ARE OVERWRITTEN !?!?!?!?!? - - time_index = date_time%hour/3 + 1 ! HARDWIRED 3-HOUR TIME STEP !?!?!?!?!? - - ! ------------------------------------- - ! - ! eliminate no-data-values and data that fail initial QC - - allocate(SCF_tmp(N_data)) - allocate(lat_tmp(N_data)) - allocate(lon_tmp(N_data)) - - j=0 - - do i=1,N_data - - keep_data = & - ( SCF_raw(i) >= qc_snow_cover_min ) .and. & - ( SCF_raw(i) <= qc_snow_cover_max ) .and. & - ( lon_1D(i) <= lon_subtime(time_index) ) .and. & ! selection of longitudal band - ( lon_1D(i) > lon_subtime(time_index+1) ) .and. & - ( CI_Index(i) > qc_clear_index_min ) .and. & - ( CI_Index(i) <= qc_clear_index_max ) .and. & - ( Cloud_index(i) /= qc_antarctica ) .and. & - ( Snow_QA(i) < qc_snow_spatial_max ) - - if (keep_data) then - - j=j+1 - SCF_tmp(j) = SCF_raw(i)/CI_Index(i) ! raw SCF includes cloud cover - lon_tmp(j) = lon_1D(i) - lat_tmp(j) = lat_1D(i) - - end if - - end do ! i=1,N_data - - N_data = j - - allocate(MODIS_lon(N_data)) - allocate(MODIS_lat(N_data)) - allocate(MODIS_SCF(N_data)) - - MODIS_lon = lon_tmp(1:j) - MODIS_lat = lat_tmp(1:j) - MODIS_SCF = SCF_tmp(1:j) - - deallocate(lon_tmp, lat_tmp, SCF_tmp) - deallocate(CI_Index) - deallocate(Cloud_Index) - deallocate(Snow_QA) - deallocate(SCF_raw) - - end subroutine read_MODISscf_hdf - - ! ***************************************************************** - - subroutine read_obs_MODISscf( & - date_time, dtstep_assim, N_catd, tile_coord, & - tile_grid_d, N_tile_in_cell_ij, tile_num_in_cell_ij, & - this_obs_param, found_obs, MODIS_obs, std_MODIS_obs ) - - implicit none - - ! inputs - - type(date_time_type), intent(in) :: date_time - - integer, intent(in) :: dtstep_assim, N_catd - - type(tile_coord_type), dimension(:), pointer:: tile_coord ! input - - type(grid_def_type), intent(in) :: tile_grid_d - - integer, dimension(tile_grid_d%N_lon, tile_grid_d%N_lat), intent(in):: & - N_tile_in_cell_ij - - integer, dimension(:,:,:), pointer:: tile_num_in_cell_ij ! input - - type(obs_param_type), intent(in) :: this_obs_param - - ! output - - real, intent(out), dimension(N_catd) :: MODIS_obs - real, intent(out), dimension(N_catd) :: std_MODIS_obs - logical, intent(out) :: found_obs - logical :: file_exists - - !locals - - character(2) :: MM - character(4) :: YYYY - character(3) :: DDD ! Day of Year - character(300) :: tmpfname1 - - integer :: i, ind, N_files, N_tmp - - integer, parameter :: dtstep_assim_threshold = 10800 ! restricting dtstep_assim to 3 hours - - character(300), dimension(:), allocatable :: fnames - - real, dimension(:), pointer :: tmp_lat, tmp_lon - integer, dimension(:), pointer :: tmp_tile_num - real, dimension(:), pointer :: tmp_obs - - integer, dimension(N_catd) :: N_obs_in_tile - - character(len=*), parameter :: Iam = 'read_obs_MODISscf' - character(len=400) :: err_msg - - ! -------------- - - nullify (tmp_obs, tmp_lat, tmp_lon, tmp_tile_num) - - ! -------------- - ! - ! restricting the assimilation time step to *only* 3 hr - - if (dtstep_assim .NE. dtstep_assim_threshold) then - - err_msg = 'dtstep_assim must be equal to 3 hours' - call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) - - end if - - ! restricting current time to only 0z, 3z, ..., 21z - - if ( (mod(date_time%hour,3) .NE. 0) .or. & - (date_time%min .NE. 0) .or. & - (date_time%sec .NE. 0) ) then - - err_msg = 'analysis time must be 0z, 3z, ..., 21z' - call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) - - end if - - ! -------------- - ! - ! Initialize - - found_obs = .false. - N_tmp = 3600*7200 - - write (YYYY,'(i4.4)') date_time%year - write (MM, '(i2.2)') date_time%month - write (DDD, '(i3.3)') date_time%dofyr - - write (logunit,*) 'Obs time (year/month/day-of-year): ', YYYY, MM, DDD - - ! In the ensupd nml file, specify the file "name" according to the following template: - ! - ! %name = 'MOD10C1.Ayyyyddd.061.hdf' - ! - ! 1 2 - ! 123456789012345678901234 - ! - ! MOD10C1 = MODIS product name - ! .A = "acquisition time" indicator - ! yyyyddd = placeholder for year/day-of-year - ! .061 = version (Collection) indicator - ! .hdf = file name extension - ! - ! Assuming the MODIS file naming convention remains unchanged, the version can then - ! be specified in the nml file. - - !tmpfname1 = trim(this_obs_param%path) // '/' // YYYY // '/' & - ! // this_obs_param%name(1:9) // YYYY // DDD // this_obs_param%name(17:24) - - tmpfname1 = trim(this_obs_param%path) // '/' // YYYY // '/MOD10C1.A' // YYYY // DDD // & - '.061.hdf' !note the MODIS data version included here - - if (logit) write (logunit,*) 'Reading data from ', trim(tmpfname1) - - inquire(file=trim(tmpfname1), exist=file_exists) - - if (logit) write (logunit,*), file_exists - - if (file_exists) then - - N_files = 1 !?!?!?!?!?! READS NO MORE THAN ONE FILE - allocate(fnames(N_files)) - fnames(N_files) = tmpfname1 - - end if !(file_exists) - - if (N_files>0) then - - call read_MODISscf_hdf(N_files, date_time, N_tmp, fnames, & - tmp_lon, tmp_lat, tmp_obs) - - deallocate(fnames) - - else - - N_tmp = 0 - - end if ! (N_files>0) - - if (N_tmp>0) then - - allocate(tmp_tile_num(N_tmp)) - - call get_tile_num_for_obs(N_catd, tile_coord, & - tile_grid_d, N_tile_in_cell_ij, & - tile_num_in_cell_ij, & - N_tmp, tmp_lat, tmp_lon, & - this_obs_param, & - tmp_tile_num(1:N_tmp)) - - - MODIS_obs = 0. - N_obs_in_tile = 0 - - do i=1,N_tmp - - ind = tmp_tile_num(i) ! 1<=tmp_tile_num<=N_catd (unless nodata) - - if (ind>0) then ! this step eliminates obs outside domain - - MODIS_obs(ind) = MODIS_obs(ind) + tmp_obs(i) - N_obs_in_tile(ind) = N_obs_in_tile(ind) + 1 - - end if !(ind>0) - - end do !i - - !normalize - do i=1,N_catd - if (N_obs_in_tile(i)>0) then - - MODIS_obs(i) = MODIS_obs(i)/real(N_obs_in_tile(i)) - - else if (N_obs_in_tile(i) == 0) then - - MODIS_obs(i) = this_obs_param%nodata - - end if !(N_obs_in_tile(i)>0 - end do !i - - if (associated(tmp_tile_num)) deallocate (tmp_tile_num) - - do i=1, N_catd - - std_MODIS_obs(i) = this_obs_param%errstd - - end do !i - - if (any(N_obs_in_tile>0)) then - - found_obs = .true. - - else - - found_obs = .false. - - end if !(any(N_obs_in_tile>0) - - end if ! (associated(tmp_tile_num) - - if (associated(tmp_obs)) deallocate(tmp_obs) - if (associated(tmp_lon)) deallocate(tmp_lon) - if (associated(tmp_lat)) deallocate(tmp_lat) - - end subroutine read_obs_MODISscf - ! ***************************************************************** subroutine read_obs_MODIS_SCF( & date_time, dtstep_assim, N_catd, tile_coord, & tile_grid_d, N_tile_in_cell_ij, tile_num_in_cell_ij, & this_obs_param, & - found_obs, MODIS_obs, std_MODIS_obs ) + found_obs, MODIS_obs, std_MODIS_obs, MODIS_lon, MODIS_lat ) ! read MODIS snow cover fraction observations on MODIS 0.05-degree climate ! modeling grid (CMG) @@ -5161,7 +4634,7 @@ subroutine read_obs_MODIS_SCF( & logical, intent(out) :: found_obs - real, dimension(N_catd), intent(out) :: MODIS_obs, std_MODIS_obs + real, dimension(N_catd), intent(out) :: MODIS_obs, std_MODIS_obs, MODIS_lon, MODIS_lat ! ------------------------------------------------------------------------ @@ -5172,14 +4645,20 @@ subroutine read_obs_MODIS_SCF( & real, parameter :: CMG_dlat = 0.05 ! [degrees] latitude spacing of MODIS CMG grid real, parameter :: CMG_dlon = 0.05 ! [degrees] longitude spacing of MODIS CMG grid - real, parameter :: CMG_ll_lat = -90. ! [degrees] lower-left latitude of MODIS CMG grid - real, parameter :: CMG_ll_lon = -180. ! [degrees] lower-left longitude of MODIS CMG grid - + real, parameter :: CMG_ur_lat = 90. ! [degrees] upper-right latitude of MODIS CMG grid + real, parameter :: CMG_ll_lon = -180. ! [degrees] lower-left longitude of MODIS CMG grid + character(7) :: MODIS_product_ID + + character(4) :: YYYY + character(3) :: DDD ! day of year + + character(400) :: fname - real :: overpass_hour, tmp_delta + real :: overpass_hour, tmp_delta, tmp_real, max_delta_lon - integer :: N_files, N_lon, N_lat, nn, N_cmg_obs, N_good_data + integer :: N_files, N_lon, N_lat, nn, kk, ind + integer :: N_CMG_obs, N_good_data, tmp_ind_start, tmp_ind_last type(date_time_type) :: date_time_beg, date_time_end type(date_time_type) :: date_time_beg_MODIS, date_time_end_MODIS @@ -5188,42 +4667,22 @@ subroutine read_obs_MODIS_SCF( & real :: lon_beg_MODIS, lon_end_MODIS integer :: delta_day_beg, delta_day_end - integer, :: delta_day_beg_MODIS, delta_day_end_MODIS + integer :: delta_day_beg_MODIS, delta_day_end_MODIS real :: lat_min, lat_max - integer :: N_lat, N_CMG_obs - real, dimension(2) :: lon_min_vec, lon_max_vec integer, dimension(2) :: N_lon_vec, year_vec, dofyr_vec, start_ind, last_ind + real, dimension(:), allocatable :: CMG_obs, CMG_lat, CMG_lon - real, dimension(:), allocatable :: CMG_obs, CMG_lat, CMG_lon, tmp_tile_num + integer, dimension(:), allocatable :: tmp_tile_num + integer, dimension(N_catd) :: N_obs_in_tile - -! logical :: file_exists -! -! character(2) :: MM -! character(4) :: YYYY -! character(3) :: DDD ! Day of Year -! character(300) :: tmpfname1 -! -! integer :: ii, ind, N_files, N_tmp -! -! character(400), dimension(2), allocatable :: fnames -! -! integer, dimension(:,:), allocatable :: tmp_tile_num -! -! integer, dimension(N_catd) :: N_obs_in_tile - - - - - - character(len=*), parameter :: Iam = 'read_obs_MODISscf' - character(len=400) :: err_msg + character(len=*), parameter :: Iam = 'read_obs_MODISscf' + character(len=400) :: err_msg ! ---------------------------------------------------------------------------------- ! @@ -5231,7 +4690,7 @@ subroutine read_obs_MODIS_SCF( & if (dtstep_assim > dtstep_assim_max) then - err_msg = 'dtstep_assim exceeds max allowed of ' // dtstep_assim_max + err_msg = 'dtstep_assim exceeds max allowed' call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) end if @@ -5248,9 +4707,9 @@ subroutine read_obs_MODIS_SCF( & select case (MODIS_product_ID) - case('MOD10C1') overpass_hour = 10.5 ! [hours] Terra: 10:30am local time + case('MOD10C1'); overpass_hour = 10.5 ! [hours] Terra: 10:30am local time - case('MYD10C1') overpass_hour = 13.5 ! [hours] Aqua: 1:30pm local time + case('MYD10C1'); overpass_hour = 13.5 ! [hours] Aqua: 1:30pm local time end select @@ -5271,15 +4730,6 @@ subroutine read_obs_MODIS_SCF( & call localtime2longitude( date_time_beg, overpass_hour, lon_beg, delta_day_beg ) call localtime2longitude( date_time_end, overpass_hour, lon_end, delta_day_end ) - ! NEEDS FINISHING ??? - - -! if (lon_beg < lon_end) then -! -! -! -! end if - ! determine (rough) longitude band for which MODIS obs need to be read ! @@ -5307,15 +4757,6 @@ subroutine read_obs_MODIS_SCF( & ! put together arguments for call(s) to read_MODIS_SCF_hdf() - ! TO DO: - ! - ! - deal with lon_*_MODIS hitting exactly -180/+180 deg longitude - ! - check that delta_lon is in range consistent with dtstep_assim - ! - does N_lon give the right array size? - ! - what if date changes when N_files=1?? - ! --> check delta_day_beg_MODIS and delta_day_end_MODIS and process accordingly - ! - is CMG DE or DC grid? - lon_min_vec = MAPL_UNDEF lon_max_vec = MAPL_UNDEF @@ -5353,7 +4794,7 @@ subroutine read_obs_MODIS_SCF( & write (logunit,*) 'lon_beg_MODIS = ', lon_beg_MODIS write (logunit,*) 'lon_end_MODIS = ', lon_end_MODIS - err_msg = 'encountered unexpected condition!!!' + err_msg = 'encountered unexpected condition for longitude band!!!' call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) end if @@ -5380,12 +4821,31 @@ subroutine read_obs_MODIS_SCF( & dofyr_vec( 2) = date_time_beg_MODIS%dofyr end if - + + ! verify that longitude bands do not exceed max expected expected width + ! (add 0.1 degree of wiggle room) + + max_delta_lon = real(dtstep_assim_max + 2*nint(tmp_delta))/86400.*360. + 0.1 ! [degree] + + do nn=1,N_files + + if ( lon_max_vec(nn) - lon_min_vec(nn) > max_delta_lon ) then + + err_msg = 'longitude band too wide' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + + end if + + end do + + + ! determine latitude band covered by domain (no need to read obs outside domain) + lat_min = minval( tile_coord(1:N_catd)%min_lat ) lat_max = maxval( tile_coord(1:N_catd)%max_lat ) - ! determine # CMG grid cells in lat/lon bands + ! determine N_lat and N_lon[_vec] (# CMG grid cells in lat/lon bands ) start_ind(1) = (CMG_ur_lat - lat_max )/CMG_dlat last_ind(1) = (CMG_ur_lat - lat_min )/CMG_dlat @@ -5427,7 +4887,7 @@ subroutine read_obs_MODIS_SCF( & ! Assuming the MODIS file naming convention remains unchanged, the version can then ! be specified in the nml file. - N_cmg_obs = 0 ! initialize counter for "good" obs returned by read_MODIS_SCF_hdf() + N_CMG_obs = 0 ! initialize counter for "good" obs returned by calls to read_MODIS_SCF_hdf() do nn=1,N_files ! loop through longitude bands @@ -5442,30 +4902,29 @@ subroutine read_obs_MODIS_SCF( & ! determine sub-array of CMG_* - tmp_ind_start = N_cmg_obs + 1 - tmp_ind_last = N_cmg_obs + N_lon_vec(nn)*N_lat + tmp_ind_start = N_CMG_obs + 1 + tmp_ind_last = N_CMG_obs + N_lon_vec(nn)*N_lat call read_MODIS_SCF_hdf( fname, & lon_min_vec(nn), lon_max_vec(nn), lat_min, lat_max, & N_good_data, & CMG_lon(tmp_ind_start:tmp_ind_last), & CMG_lat(tmp_ind_start:tmp_ind_last), & - CMG_obs(tmp_ind_start:tmp_ind_last), ) - + CMG_obs(tmp_ind_start:tmp_ind_last) ) - N_cmg_obs = N_cmg_obs + N_good_data + N_CMG_obs = N_CMG_obs + N_good_data end do ! map to tile space - allocate(tmp_tile_num(N_cmg_obs)) + allocate(tmp_tile_num(N_CMG_obs)) call get_tile_num_for_obs( N_catd, tile_coord, & tile_grid_d, N_tile_in_cell_ij, & tile_num_in_cell_ij, & - N_cmg_obs, CMG_lat(1:N_cmg_obs), CMG_lon(1:N_cmg_obs), & + N_CMG_obs, CMG_lat(1:N_CMG_obs), CMG_lon(1:N_CMG_obs), & this_obs_param, & tmp_tile_num ) @@ -5475,13 +4934,16 @@ subroutine read_obs_MODIS_SCF( & MODIS_obs = 0. N_obs_in_tile = 0 - do kk=1,N_cmg_obs + do kk=1,N_CMG_obs ind = tmp_tile_num(kk) ! 1<=tmp_tile_num<=N_catd (unless nodata) if (ind>0) then ! this condition eliminates obs outside domain - MODIS_obs( ind) = MODIS_obs( ind) + tmp_obs(kk) + MODIS_obs( ind) = MODIS_obs( ind) + CMG_obs(kk) + MODIS_lon( ind) = MODIS_lon( ind) + CMG_lon(kk) + MODIS_lat( ind) = MODIS_lat( ind) + CMG_lat(kk) + N_obs_in_tile(ind) = N_obs_in_tile(ind) + 1 end if @@ -5493,11 +4955,17 @@ subroutine read_obs_MODIS_SCF( & do kk=1,N_catd if (N_obs_in_tile(kk)>0) then - MODIS_obs(kk) = MODIS_obs(kk)/real(N_obs_in_tile(kk)) + tmp_real = real(N_obs_in_tile(kk)) + + MODIS_obs(kk) = MODIS_obs(kk)/tmp_real + MODIS_lon(kk) = MODIS_lon(kk)/tmp_real + MODIS_lat(kk) = MODIS_lat(kk)/tmp_real else if (N_obs_in_tile(kk)==0) then MODIS_obs(kk) = this_obs_param%nodata + MODIS_lon(kk) = this_obs_param%nodata + MODIS_lat(kk) = this_obs_param%nodata end if end do @@ -5512,13 +4980,40 @@ subroutine read_obs_MODIS_SCF( & end if - deallocate(tmp_tile_num) - deallocate(CMG_obs) + deallocate(CMG_obs) deallocate(CMG_lon) deallocate(CMG_lat) - + + ! to avoid double-counting of MODIS CMG obs, remove obs for tiles with center-of-mass longitude + ! falling outside the longitude band associated with assimilation window + + if (lon_end < lon_beg) then + + ! need only one longitude band (keep obs when lon_end<=com_lon<=lon_beg) + + do kk=1,N_catd + + if ( (tile_coord(kk)%com_lonlon_beg) ) & + MODIS_obs(kk) = this_obs_param%nodata + + end do + + else + + ! longitude band wraps around dateline (keep obs when -180<=com_lon<=lon_beg or lon_end<=com_lon<=180) + + do kk=1,N_catd + + if ( (tile_coord(kk)%com_lon>lon_beg) .and. (tile_coord(kk)%com_lon= 24.) ) then - err_msg = 'input local_hour falls outside allowed range of 0:24; local_hour=' // local_hour + err_msg = 'input local_hour falls outside allowed range of 0:24' call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) end if @@ -5658,31 +5153,37 @@ subroutine read_MODIS_SCF_hdf( fname, lon_min, lon_max, lat_min, lat_max, & integer, parameter :: DFACC_READ = 1 ! from hdf.inc + integer, parameter :: uint8_min = 0 + integer, parameter :: uint8_max = 255 + + ! local variables - integer :: N_lat, N_lon, N_tmp, ii, jj, kk, nn + integer :: N_lat, N_lon, N_tmp, ii, jj, kk, nn - real, dimension(:), allocatable :: lat_c - real, dimension(:), allocatable :: lon_c + real, dimension(:), allocatable :: lat_c + real, dimension(:), allocatable :: lon_c - real dimension(:), allocatable :: lat_ind - real dimension(:), allocatable :: lon_ind + real, dimension(:), allocatable :: lat_ind + real, dimension(:), allocatable :: lon_ind - integer, dimension(2) :: start, edge, stride, last + integer, dimension(2) :: start, edge, stride, last - logical :: file_exists, keep_data + logical :: file_exists, keep_data - integer :: status, sd_id, sds_ind, sds_idex + integer :: status, sd_id, sds_id, sds_index - integer :: SDstart, SDselect, SDnametoindex - integer :: SDreaddata, SDend, SDendacc + integer :: sfstart, sfn2index, sfselect + integer :: sfrdata, sfendacc, sfend - unsigned(KIND=1), dimension(:,:), allocatable :: uint8_Snow_Cover - unsigned(KIND=1), dimension(:,:), allocatable :: uint8_Clear_Index - unsigned(KIND=1), dimension(:,:), allocatable :: uint8_Snow_Spatial_QA + integer(KIND=2), dimension(:,:), allocatable :: Snow_Cover + integer(KIND=2), dimension(:,:), allocatable :: Clear_Index + integer(KIND=2), dimension(:,:), allocatable :: Snow_Spatial_QA - character(len=*), parameter :: Iam = 'read_MODISscf_hdf' - character(len=400) :: err_msg + character(1), dimension(:,:), allocatable :: tmp_char1 + + character(len=*), parameter :: Iam = 'read_MODISscf_hdf' + character(len=400) :: err_msg ! ------------------------------------------------------------------------- ! @@ -5699,14 +5200,6 @@ subroutine read_MODIS_SCF_hdf( fname, lon_min, lon_max, lat_min, lat_max, & return - else - - if (logit) then - write (logunit,*) trim(Iam), ': reading MODIS SCF obs from ', trim(fname) - write (logunit,*) 'lon_min, lon_max, lat_min, lat_max = ', & - lon_min, lon_max, lat_min, lat_max - end if - end if ! ensure lat_* and lon_* inputs are within range @@ -5769,6 +5262,12 @@ subroutine read_MODIS_SCF_hdf( fname, lon_min, lon_max, lat_min, lat_max, & end if + if (logit) then + write (logunit,*) trim(Iam), ': reading MODIS SCF obs from ', trim(fname) + write (logunit,*) 'N_lon, N_lat, lon_min, lon_max, lat_min, lat_max = ', & + N_lon, N_lat, lon_min, lon_max, lat_min, lat_max + end if + ! allocate arrays @@ -5778,9 +5277,11 @@ subroutine read_MODIS_SCF_hdf( fname, lon_min, lon_max, lat_min, lat_max, & allocate(lat_ind(N_lat)) allocate(lon_ind(N_lon)) - allocate(uint8_Snow_Cover (N_lat,N_lon)) ! lat-by-lon !! - allocate(uint8_Clear_Index (N_lat,N_lon)) ! lat-by-lon !! - allocate(uint8_Snow_Spatial_QA(N_lat,N_lon)) ! lat-by-lon !! + allocate(Snow_Cover (N_lat,N_lon)) ! lat-by-lon !! + allocate(Clear_Index (N_lat,N_lon)) ! lat-by-lon !! + allocate(Snow_Spatial_QA(N_lat,N_lon)) ! lat-by-lon !! + + allocate(tmp_char1( N_lat,N_lon)) ! lat-by-lon !! ! -------------------------- @@ -5798,11 +5299,11 @@ subroutine read_MODIS_SCF_hdf( fname, lon_min, lon_max, lat_min, lat_max, & ! open hdf file (read-only) and initialize SD interface - sd_id = SDstart(trim(fname), DFACC_READ) + sd_id = sfstart(trim(fname), DFACC_READ) if (sd_id<0) then - err_msg = 'cannot SDstart (open) file: ' // trim(fname) + err_msg = 'cannot sfstart (open) file: ' // trim(fname) call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) end if @@ -5811,24 +5312,38 @@ subroutine read_MODIS_SCF_hdf( fname, lon_min, lon_max, lat_min, lat_max, & do nn=1,N_fields - sds_index = SDnametoindex( sd_id, trim(field_names(nn)) ) - sds_id = SDselect( sd_id, sds_index ) + sds_index = sfn2index( sd_id, trim(field_names(nn)) ) + sds_id = sfselect( sd_id, sds_index ) select case (nn) - case (1) status = SDreaddata( sds_id, start, stride, edge, uint8_Snow_Cover ) - case (2) status = SDreaddata( sds_id, start, stride, edge, uint8_Clear_Index ) - case (3) status = SDreaddata( sds_id, start, stride, edge, uint8_Snow_Spatial_QA ) + case (1); status = sfrdata( sds_id, start, stride, edge, tmp_char1 ); Snow_Cover = ichar(tmp_char1,2) + case (2); status = sfrdata( sds_id, start, stride, edge, tmp_char1 ); Clear_Index = ichar(tmp_char1,2) + case (3); status = sfrdata( sds_id, start, stride, edge, tmp_char1 ); Snow_Spatial_QA = ichar(tmp_char1,2) - case default call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'unknown field') + case default; call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'unknown field') end select - status = SDendacc(sds_id) ! terminate access to SDS (field) + status = sfendacc(sds_id) ! terminate access to SDS (field) end do - status = SDend(sd_id) ! close hdf file and SD interface + status = sfend(sd_id) ! close hdf file and SD interface + + ! check range (make sure uint8 from hdf file is correctly translated into Fortran integer) + + if ( any(Snow_Cover < uint8_min) .or. & + any(Snow_Cover > uint8_max) .or. & + any(Clear_Index < uint8_min) .or. & + any(Clear_Index > uint8_max) .or. & + any(Snow_Spatial_QA < uint8_min) .or. & + any(Snow_Spatial_QA > uint8_max) ) then + + err_msg = 'unexpected range in data from hdf file' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + + end if ! ------------------------------------- ! @@ -5843,26 +5358,24 @@ subroutine read_MODIS_SCF_hdf( fname, lon_min, lon_max, lat_min, lat_max, & do jj=1,N_lat do ii=1,N_lon - ! note: uint8_Snow_Cover >= 0 per Fortran type, no need to check for minimum + ! note: Snow_Cover >= 0 per range check above, no need to check for minimum - keep_data = & - (uint8_Snow_Cover( jj,ii) <= qc_snow_cover_max ) .and. & ! 0<=SCF<=100 (1) - (uint8_Clear_Index( jj,ii) > qc_clear_index_min ) .and. & ! sufficiently clear sky (2) - (uint8_Snow_Spatial_QA(jj,ii) < qc_snow_spatial_max) ! keep "best", "good", or "OK" quality (3) + keep_data = & + (Snow_Cover( jj,ii) <= qc_snow_cover_max ) .and. & ! 0<=SCF<=100 (1) + (Clear_Index( jj,ii) > qc_clear_index_min ) .and. & ! sufficiently clear sky (2) + (Snow_Spatial_QA(jj,ii) < qc_snow_spatial_max) ! keep "best", "good", or "OK" quality (3) ! (1) excludes "lake ice", "night", "inland water", "ocean", "cloud obscured water", "data not mapped", "fill" ! (2) clear_index>100 already removed via qc_snow_cover_max ! (3) excludes Antarctica - ! NOTE: - ! - raw SCF value is for clear portion of the grid cell only, need to normalized with Clear_Index - ! - transpose from lat-by-lon uint8 array to lon-by-lat output array - if (keep_data) then kk = kk + 1 + + ! raw SCF value is for clear portion of grid cell only, need to normalize with Clear_Index - MODIS_SCF(kk) = real(uint8_Snow_Cover(jj,ii))/real(uint8_Clear_Index(jj,ii)) + MODIS_SCF(kk) = real(Snow_Cover(jj,ii))/real(Clear_Index(jj,ii)) MODIS_lon(kk) = lon_c(ii) MODIS_lat(kk) = lat_c(jj) @@ -5883,9 +5396,9 @@ subroutine read_MODIS_SCF_hdf( fname, lon_min, lon_max, lat_min, lat_max, & deallocate(lat_ind) deallocate(lon_ind) - deallocate(uint8_Snow_Cover ) - deallocate(uint8_Clear_Index ) - deallocate(uint8_Snow_Spatial_QA) + deallocate(Snow_Cover ) + deallocate(Clear_Index ) + deallocate(Snow_Spatial_QA) end subroutine read_MODIS_SCF_hdf @@ -8503,7 +8016,7 @@ subroutine read_obs( & N_tile_in_cell_ij, tile_num_in_cell_ij, write_obslog, & found_obs, tmp_obs, tmp_std_obs, tmp_lon, tmp_lat ) - ! scale observations to model climatology XXXXXXX + ! scale observations to model climatology if (this_obs_param%scale .and. found_obs) then @@ -8516,10 +8029,11 @@ subroutine read_obs( & case ('MODIS_SCF') - call read_obs_MODISscf( & + call read_obs_MODIS_SCF( & date_time, dtstep_assim, N_catd, tile_coord, & tile_grid_d, N_tile_in_cell_ij, tile_num_in_cell_ij, & - this_obs_param, found_obs, tmp_obs, tmp_std_obs) + this_obs_param, & + found_obs, tmp_obs, tmp_std_obs, tmp_lon, tmp_lat ) case('SMAP_L1C_Tbh_A', 'SMAP_L1C_Tbv_A', & 'SMAP_L1C_Tbh_D', 'SMAP_L1C_Tbv_D', & @@ -8536,7 +8050,7 @@ subroutine read_obs( & N_tile_in_cell_ij, tile_num_in_cell_ij, write_obslog, & found_obs, tmp_obs, tmp_std_obs, tmp_lon, tmp_lat, tmp_time ) - ! scale observations to model climatology XXXXXXX + ! scale observations to model climatology if (this_obs_param%scale .and. found_obs) then From ff0b9a0c3e4ff124fb43db2e8078300cffa2a374 Mon Sep 17 00:00:00 2001 From: Weiyuan Jiang Date: Wed, 25 Oct 2023 15:23:04 -0400 Subject: [PATCH 161/308] adapt to new bcs structure --- src/Applications/LDAS_App/ldas_setup | 61 +++++++++++++++------------- 1 file changed, 33 insertions(+), 28 deletions(-) diff --git a/src/Applications/LDAS_App/ldas_setup b/src/Applications/LDAS_App/ldas_setup index e2ecbabd..0207e634 100755 --- a/src/Applications/LDAS_App/ldas_setup +++ b/src/Applications/LDAS_App/ldas_setup @@ -115,6 +115,10 @@ class LDASsetup: self.in_rstfile = None self.in_tilefile = 'None' # default string self.ens_id_width = 6 # _eXXXX + self.bcs_land = '' + self.bcs_geom = '' + self.bcs_landshared = '' + # ------ # Read exe input file which is required to set up the dir # ------ @@ -244,9 +248,10 @@ class LDASsetup: _d = _d+ _difftime # make sure path is path - if self.rqdExeInp['BCS_PATH'][-1] != '/': - self.rqdExeInp['BCS_PATH'] = self.rqdExeInp['BCS_PATH']+'/' - self.rqdExeInp['BCS_PATH'] = self.rqdExeInp['BCS_PATH']+self.rqdExeInp['BCS_RESOLUTION']+'/' + self.bcs_land = self.rqdExeInp['BCS_PATH']+ '/land/' + self.rqdExeInp['BCS_RESOLUTION']+'/' + self.bcs_geom = self.rqdExeInp['BCS_PATH']+ '/geometry/' + self.rqdExeInp['BCS_RESOLUTION']+'/' + self.bcs_landshared = self.rqdExeInp['BCS_PATH']+ '/land/shared/' + if self.rqdExeInp['MET_PATH'][-1] != '/': self.rqdExeInp['MET_PATH'] = self.rqdExeInp['MET_PATH']+'/' if self.rqdExeInp['RESTART_PATH'][-1] != '/': @@ -254,7 +259,7 @@ class LDASsetup: # make sure catchment and vegdyn restart files ( at least one for each) exist if 'CATCH_DEF_FILE' not in self.rqdExeInp: - self.rqdExeInp['CATCH_DEF_FILE']=self.rqdExeInp['BCS_PATH']+'clsm/catchment.def' + self.rqdExeInp['CATCH_DEF_FILE']= self.bcs_land + 'clsm/catchment.def' assert os.path.isfile(self.rqdExeInp['CATCH_DEF_FILE']),"[%s] file does not exist " % self.rqdExeInp['CATCH_DEF_FILE'] self.rqdExeInp['RST_FROM_GLOBAL'] = 1 @@ -273,21 +278,21 @@ class LDASsetup: self.rqdExeInp['LNFM_FILE'] = '' if int(self.rqdExeInp['RST_FROM_GLOBAL']) == 1 : - self.rqdExeInp['TILING_FILE'] =glob.glob(self.rqdExeInp['BCS_PATH']+'*.til')[0] - self.rqdExeInp['GRN_FILE']= glob.glob(self.rqdExeInp['BCS_PATH']+'green_clim_*.data')[0] - self.rqdExeInp['LAI_FILE']= glob.glob(self.rqdExeInp['BCS_PATH']+'lai_clim_*.data')[0] - tmp_ = glob.glob(self.rqdExeInp['BCS_PATH']+'lnfm_clim_*.data') + self.rqdExeInp['TILING_FILE'] =glob.glob(self.bcs_geom + '*.til')[0] + self.rqdExeInp['GRN_FILE']= glob.glob(self.bcs_land + 'green_clim_*.data')[0] + self.rqdExeInp['LAI_FILE']= glob.glob(self.bcs_land + 'lai_clim_*.data')[0] + tmp_ = glob.glob(self.bcs_land + 'lnfm_clim_*.data') if (len(tmp_) ==1) : self.rqdExeInp['LNFM_FILE'] = tmp_[0] - self.rqdExeInp['NDVI_FILE']= glob.glob(self.rqdExeInp['BCS_PATH']+'ndvi_clim_*.data')[0] - self.rqdExeInp['NIRDF_FILE']= glob.glob(self.rqdExeInp['BCS_PATH']+'nirdf_*.dat')[0] - self.rqdExeInp['VISDF_FILE']= glob.glob(self.rqdExeInp['BCS_PATH']+'visdf_*.dat')[0] + self.rqdExeInp['NDVI_FILE'] = glob.glob(self.bcs_land + 'ndvi_clim_*.data')[0] + self.rqdExeInp['NIRDF_FILE']= glob.glob(self.bcs_land + 'nirdf_*.dat')[0] + self.rqdExeInp['VISDF_FILE']= glob.glob(self.bcs_land + 'visdf_*.dat')[0] else : inpdir=self.rqdExeInp['RESTART_PATH']+self.rqdExeInp['RESTART_ID']+'/input/' self.rqdExeInp['TILING_FILE'] =os.path.realpath(glob.glob(inpdir+'*tile.data')[0]) self.rqdExeInp['GRN_FILE']= os.path.realpath(glob.glob(inpdir+'green*data')[0]) self.rqdExeInp['LAI_FILE']= os.path.realpath(glob.glob(inpdir+'lai*data')[0]) - tmp_ = glob.glob(self.rqdExeInp['BCS_PATH']+'lnfm_clim_*.data') + tmp_ = glob.glob(self.bcs_land + 'lnfm_clim_*.data') if (len(tmp_) == 1) : self.rqdExeInp['LNFM_FILE'] = tmp_[0] self.rqdExeInp['NDVI_FILE']= os.path.realpath(glob.glob(inpdir+'ndvi*data')[0]) @@ -311,16 +316,16 @@ class LDASsetup: if os.path.isfile(ldas_domain) : _numd = int(linecache.getline(ldas_domain, 1).strip()) - self.rqdExeInp['TILING_FILE'] =glob.glob(self.rqdExeInp['BCS_PATH']+'*.til')[0] - self.rqdExeInp['GRN_FILE']= glob.glob(self.rqdExeInp['BCS_PATH']+'green_clim_*.data')[0] - self.rqdExeInp['LAI_FILE']= glob.glob(self.rqdExeInp['BCS_PATH']+'lai_clim_*.data')[0] - tmp_ = glob.glob(self.rqdExeInp['BCS_PATH']+'lnfm_clim_*.data') + self.rqdExeInp['TILING_FILE'] =glob.glob(self.bcs_geom + '*.til')[0] + self.rqdExeInp['GRN_FILE']= glob.glob(self.bcs_land + 'green_clim_*.data')[0] + self.rqdExeInp['LAI_FILE']= glob.glob(self.bcs_land + 'lai_clim_*.data')[0] + tmp_ = glob.glob(self.bcs_land + 'lnfm_clim_*.data') if (len(tmp_) == 1) : self.rqdExeInp['LNFM_FILE'] = tmp_[0] - self.rqdExeInp['LNFM_FILE']= glob.glob(self.rqdExeInp['BCS_PATH']+'lnfm_clim_*.data')[0] - self.rqdExeInp['NDVI_FILE']= glob.glob(self.rqdExeInp['BCS_PATH']+'ndvi_clim_*.data')[0] - self.rqdExeInp['NIRDF_FILE']= glob.glob(self.rqdExeInp['BCS_PATH']+'nirdf_*.dat')[0] - self.rqdExeInp['VISDF_FILE']= glob.glob(self.rqdExeInp['BCS_PATH']+'visdf_*.dat')[0] + self.rqdExeInp['LNFM_FILE'] = glob.glob(self.bcs_land + 'lnfm_clim_*.data')[0] + self.rqdExeInp['NDVI_FILE'] = glob.glob(self.bcs_land + 'ndvi_clim_*.data')[0] + self.rqdExeInp['NIRDF_FILE']= glob.glob(self.bcs_land + 'nirdf_*.dat')[0] + self.rqdExeInp['VISDF_FILE']= glob.glob(self.bcs_land + 'visdf_*.dat')[0] if 'GRIDNAME' not in self.rqdExeInp : tmptile =self.rqdExeInp['TILING_FILE'] @@ -788,7 +793,7 @@ class LDASsetup: os.symlink(bc,myBC) if ("catchcn" in self.catch): - os.symlink(self.rqdExeInp['BCS_PATH']+'../land/shared/CO2_MonthlyMean_DiurnalCycle.nc4', \ + os.symlink(self.bcs_landshared + 'CO2_MonthlyMean_DiurnalCycle.nc4', \ self.inpdir+'/CO2_MonthlyMean_DiurnalCycle.nc4') # create and link restart @@ -831,9 +836,9 @@ class LDASsetup: os.symlink(_seeds, myRstDir+ '/landassim_obspertrseed'+ _ensid +'_rst') self.has_landassim_seed = True mk_outdir = self.exphome+'/'+exp_id+'/mk_restarts/' - cmd= ' '.join(['./process_rst.csh', sponsorid, exp_id, mk_outdir, - out_bcdir, out_tilefile, self.catch, RESTART_str, YYYYMMDDHH, - self.in_rstfile, self.in_tilefile, dzsf, wemin_in, wemin_out]) + #cmd= ' '.join(['./process_rst.csh', sponsorid, exp_id, mk_outdir, + # out_bcdir, out_tilefile, self.catch, RESTART_str, YYYYMMDDHH, + # self.in_rstfile, self.in_tilefile, dzsf, wemin_in, wemin_out]) if (RESTART_str != '1'): remap_tpl = os.path.dirname(os.path.realpath(__file__)) + '/remap_params.tpl' @@ -853,7 +858,7 @@ class LDASsetup: config['output']['shared']['out_dir'] = mk_outdir config['output']['surface']['catch_remap'] = True config['output']['surface']['catch_tilefile'] = self.rqdExeInp['TILING_FILE'] - config['output']['shared']['bcs_dir'] = self.rqdExeInp['BCS_PATH'] + config['output']['shared']['bcs_dir'] = self.bcs_geom config['output']['shared']['expid'] = self.rqdExeInp['EXP_ID'] config['output']['surface']['surflay'] = dzsf config['output']['surface']['wemin'] = wemin_out @@ -895,16 +900,16 @@ class LDASsetup: if self.rqdExeInp['RESTART'].isdigit() : if int(self.rqdExeInp['RESTART']) == 0 or int(self.rqdExeInp['RESTART']) == 2 : - vegdynRstFile = glob.glob(self.rqdExeInp['BCS_PATH']+'vegdyn_*.dat')[0] + vegdynRstFile = glob.glob(self.bcs_land + 'vegdyn_*.dat')[0] catchRstFile = glob.glob(self.exphome+'/'+exp_id+'/mk_restarts/*'+self.catch+'_internal_rst.'+YYYYMMDD+'*')[0] else : # RESTART == 1 catchRstFile = rstpath+ensdir +'/'+ y4m2+'/'+self.rqdExeInp['RESTART_ID']+'.'+self.catch+'_internal_rst.'+y4m2d2_h2m2 vegdynRstFile= rstpath+ensdir +'/'+self.rqdExeInp['RESTART_ID']+ '.vegdyn_internal_rst' if not os.path.isfile(vegdynRstFile): # no vegdyn restart from LDASsa if not os.path.isfile(vegdynRstFile0): - vegdynRstFile = glob.glob(self.rqdExeInp['BCS_PATH']+'vegdyn_*.dat')[0] + vegdynRstFile = glob.glob(self.bcs_land + 'vegdyn_*.dat')[0] else : - vegdynRstFile = glob.glob(self.rqdExeInp['BCS_PATH']+'vegdyn_*.dat')[0] + vegdynRstFile = glob.glob(self.bcs_land + 'vegdyn_*.dat')[0] catchRstFile = glob.glob(self.exphome+'/'+exp_id+'/mk_restarts/*'+self.catch+'_internal_rst.'+YYYYMMDD+'*')[0] # catchment restart file From 59b4b17041d007dfd0fdccffb32ac3a71ae372ff Mon Sep 17 00:00:00 2001 From: biljanaorescanin Date: Thu, 26 Oct 2023 09:54:20 -0400 Subject: [PATCH 162/308] update repos, add option to ldas_setup --- components.yaml | 10 +++++----- src/Applications/LDAS_App/ldas_setup | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/components.yaml b/components.yaml index 5ca4fecb..6a4e5964 100644 --- a/components.yaml +++ b/components.yaml @@ -5,13 +5,13 @@ GEOSldas: env: local: ./@env remote: ../ESMA_env.git - tag: v4.17.0 + tag: v4.20.3 develop: main cmake: local: ./@cmake remote: ../ESMA_cmake.git - tag: v3.30.0 + tag: v3.35.0 develop: develop ecbuild: @@ -22,20 +22,20 @@ ecbuild: GMAO_Shared: local: ./src/Shared/@GMAO_Shared remote: ../GMAO_Shared.git - tag: v1.9.1 + tag: v1.9.5 sparse: ./config/GMAO_Shared.sparse develop: main GEOS_Util: local: ./src/Shared/@GMAO_Shared/@GEOS_Util remote: ../GEOS_Util.git - tag: v2.0.2 + tag: v2.0.3 develop: main MAPL: local: ./src/Shared/@MAPL remote: ../MAPL.git - tag: v2.39.4 + tag: v2.41.1 develop: develop GEOSgcm_GridComp: diff --git a/src/Applications/LDAS_App/ldas_setup b/src/Applications/LDAS_App/ldas_setup index e2ecbabd..06c21766 100755 --- a/src/Applications/LDAS_App/ldas_setup +++ b/src/Applications/LDAS_App/ldas_setup @@ -1336,7 +1336,7 @@ class LDASsetup: if int(self.rqdRmInp['ntasks-per-node']) > 40: fout.write("#SBATCH --constraint=cas\n") if (28 < int(self.rqdRmInp['ntasks-per-node']) and int(self.rqdRmInp['ntasks-per-node']) <= 40) : - fout.write("#SBATCH --constraint=sky\n") + fout.write("#SBATCH --constraint=sky|cas\n") elif 'MY_OSERVER_NODES' in line : fout.write(line.replace('MY_OSERVER_NODES',str(self.optRmInp['oserver_nodes']))) elif 'MY_WRITERS_NPES' in line : From fd5c9e44cd7ef8c3c2615222c222aee648cb94c5 Mon Sep 17 00:00:00 2001 From: Matthew Thompson Date: Thu, 26 Oct 2023 10:42:03 -0400 Subject: [PATCH 163/308] Update Baselibs in CI --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index f886bcce..45aaa3a8 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,7 +1,7 @@ version: 2.1 # Anchor to prevent forgetting to update a version -baselibs_version: &baselibs_version v7.13.0 +baselibs_version: &baselibs_version v7.14.0 orbs: ci: geos-esm/circleci-tools@1 From 4b157b44c72d1b2206cd9e02ffeab2f055f6719f Mon Sep 17 00:00:00 2001 From: Matthew Thompson Date: Thu, 26 Oct 2023 11:04:35 -0400 Subject: [PATCH 164/308] Update to ESMA_env v4.20.5 --- components.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components.yaml b/components.yaml index 6a4e5964..4ed074dd 100644 --- a/components.yaml +++ b/components.yaml @@ -5,7 +5,7 @@ GEOSldas: env: local: ./@env remote: ../ESMA_env.git - tag: v4.20.3 + tag: v4.20.5 develop: main cmake: From d5674fbb0d2a7546f36a11cb50f0582267ea4891 Mon Sep 17 00:00:00 2001 From: Matthew Thompson Date: Thu, 26 Oct 2023 11:04:47 -0400 Subject: [PATCH 165/308] Add code for Milan --- src/Applications/LDAS_App/ldas_setup | 233 ++++++++++++++------------- 1 file changed, 118 insertions(+), 115 deletions(-) diff --git a/src/Applications/LDAS_App/ldas_setup b/src/Applications/LDAS_App/ldas_setup index 06c21766..f44a4bc1 100755 --- a/src/Applications/LDAS_App/ldas_setup +++ b/src/Applications/LDAS_App/ldas_setup @@ -36,10 +36,10 @@ class LDASsetup: # Required exe input fields # These fields are needed to pre-compute exp dir structure # ------ - rqdExeInpKeys = ['EXP_ID', 'EXP_DOMAIN', 'NUM_LDAS_ENSEMBLE', + rqdExeInpKeys = ['EXP_ID', 'EXP_DOMAIN', 'NUM_LDAS_ENSEMBLE', 'BEG_DATE', 'END_DATE','RESTART_PATH', 'RESTART_DOMAIN','RESTART_ID','MET_TAG','MET_PATH','FORCE_DTSTEP','BCS_PATH', 'BCS_RESOLUTION'] - rqdExeInpKeys_rst = ['EXP_ID', 'EXP_DOMAIN', 'NUM_LDAS_ENSEMBLE', + rqdExeInpKeys_rst = ['EXP_ID', 'EXP_DOMAIN', 'NUM_LDAS_ENSEMBLE', 'BEG_DATE', 'END_DATE','MET_TAG','MET_PATH','FORCE_DTSTEP','BCS_PATH', 'BCS_RESOLUTION'] # These keywords are excluded from LDAS.rc (i.e., only needed in pre- or post-processing) @@ -151,7 +151,7 @@ class LDASsetup: assert self.nens>0, 'NUM_LDAS_ENSEMBLE [%d] <= 0' % self.nens _mydir = self.exphome + '/' + self.rqdExeInp['EXP_ID'] assert not os.path.isdir(_mydir), 'Dir [%s] already exists!' % _mydir - _mydir = None + _mydir = None self.ladas_coupling = int(self.rqdExeInp.get('LADAS_COUPLING',0)) if self.ladas_coupling > 0: assert 'ADAS_EXPDIR' in self.rqdExeInp, " need ADAS_EXPDIR in the input file %s" %(self.exeinpfile) @@ -163,7 +163,7 @@ class LDASsetup: self.ensdirs = ['ens%04d'%iens for iens in range(self.first_ens_id, self.nens + self.first_ens_id)] # if self.ens_id_width = 4, _width = '_e%04d' _width = '_e%0{}d'.format(self.ens_id_width-2) - # self.ensids will be a list of [_e0000, _e0001, ...] + # self.ensids will be a list of [_e0000, _e0001, ...] self.ensids = [ _width%iens for iens in range(self.first_ens_id, self.nens + self.first_ens_id)] if (self.nens == 1) : self.ensdirs_avg = self.ensdirs @@ -246,7 +246,7 @@ class LDASsetup: # make sure path is path if self.rqdExeInp['BCS_PATH'][-1] != '/': self.rqdExeInp['BCS_PATH'] = self.rqdExeInp['BCS_PATH']+'/' - self.rqdExeInp['BCS_PATH'] = self.rqdExeInp['BCS_PATH']+self.rqdExeInp['BCS_RESOLUTION']+'/' + self.rqdExeInp['BCS_PATH'] = self.rqdExeInp['BCS_PATH']+self.rqdExeInp['BCS_RESOLUTION']+'/' if self.rqdExeInp['MET_PATH'][-1] != '/': self.rqdExeInp['MET_PATH'] = self.rqdExeInp['MET_PATH']+'/' if self.rqdExeInp['RESTART_PATH'][-1] != '/': @@ -267,8 +267,8 @@ class LDASsetup: '/output/'+self.rqdExeInp['RESTART_DOMAIN']+'/rc_out/'+self.rqdExeInp['RESTART_ID']+'.ldas_domain.txt' if os.path.isfile(ldas_domain) : _numd = int(linecache.getline(ldas_domain, 1).strip()) - - if _numg != _numd : + + if _numg != _numd : self.rqdExeInp['RST_FROM_GLOBAL'] = 0 self.rqdExeInp['LNFM_FILE'] = '' @@ -308,7 +308,7 @@ class LDASsetup: if len(in_tilefiles_) == 0 : in_tilefiles_ = glob.glob(inpdir+'/*.til') self.in_tilefile =os.path.realpath(in_tilefiles_[0]) - + if os.path.isfile(ldas_domain) : _numd = int(linecache.getline(ldas_domain, 1).strip()) self.rqdExeInp['TILING_FILE'] =glob.glob(self.rqdExeInp['BCS_PATH']+'*.til')[0] @@ -320,8 +320,8 @@ class LDASsetup: self.rqdExeInp['LNFM_FILE']= glob.glob(self.rqdExeInp['BCS_PATH']+'lnfm_clim_*.data')[0] self.rqdExeInp['NDVI_FILE']= glob.glob(self.rqdExeInp['BCS_PATH']+'ndvi_clim_*.data')[0] self.rqdExeInp['NIRDF_FILE']= glob.glob(self.rqdExeInp['BCS_PATH']+'nirdf_*.dat')[0] - self.rqdExeInp['VISDF_FILE']= glob.glob(self.rqdExeInp['BCS_PATH']+'visdf_*.dat')[0] - + self.rqdExeInp['VISDF_FILE']= glob.glob(self.rqdExeInp['BCS_PATH']+'visdf_*.dat')[0] + if 'GRIDNAME' not in self.rqdExeInp : tmptile =self.rqdExeInp['TILING_FILE'] self.rqdExeInp['GRIDNAME'] = linecache.getline(tmptile, 3).strip() @@ -333,7 +333,7 @@ class LDASsetup: self.catch = 'catch' if int(self.rqdExeInp['LSM_CHOICE']) == 2 : self.catch = 'catchcnclm40' - if int(self.rqdExeInp['LSM_CHOICE']) == 3 : + if int(self.rqdExeInp['LSM_CHOICE']) == 3 : self.catch = 'catchcnclm45' if 'POSTPROC_HIST' not in self.rqdExeInp: self.rqdExeInp['POSTPROC_HIST'] = 0 @@ -342,7 +342,7 @@ class LDASsetup: self.rqdExeInp['LADAS_COUPLING'] = 0 if 'RUN_IRRIG' not in self.rqdExeInp: - self.rqdExeInp['RUN_IRRIG'] = 0 + self.rqdExeInp['RUN_IRRIG'] = 0 if 'AEROSOL_DEPOSITION' not in self.rqdExeInp: self.rqdExeInp['AEROSOL_DEPOSITION'] = 0 @@ -354,7 +354,7 @@ class LDASsetup: _domain_dic['MAXLAT']= 90. _domain_dic['EXCLUDE_FILE']= "''" _domain_dic['INCLUDE_FILE']= "''" - + for key,val in _domain_dic.items() : if key in self.rqdExeInp : _domain_dic[key]= self.rqdExeInp[key] @@ -368,7 +368,7 @@ class LDASsetup: else : fout.write(keyn+ valn +'\n') fout.write('/\n') - + # make sure bcs files exist if self.rqdExeInp['RESTART'].isdigit() : if int(self.rqdExeInp['RESTART']) >= 1 : @@ -379,18 +379,18 @@ class LDASsetup: tmpRstDir=self.rqdExeInp['RESTART_PATH']+'/'.join([self.rqdExeInp['RESTART_ID'],'output', self.rqdExeInp['RESTART_DOMAIN'],'rs',self.ensdirs[0],y4m2]) catchRstFile=tmpRstDir+'/'+tmpFile - + assert os.path.isfile(catchRstFile), self.catch+'_internal_rst file [%s] does not exist!' %(catchRstFile) self.in_rstfile = catchRstFile - + if int(self.rqdExeInp['RESTART']) == 1 : tmpFile=self.rqdExeInp['RESTART_ID']+'.vegdyn_internal_rst' tmpRstDir=self.rqdExeInp['RESTART_PATH']+'/'.join([self.rqdExeInp['RESTART_ID'],'output', - self.rqdExeInp['RESTART_DOMAIN'],'rs',self.ensdirs[0]]) + self.rqdExeInp['RESTART_DOMAIN'],'rs',self.ensdirs[0]]) vegdynRstFile=tmpRstDir+'/'+tmpFile if not os.path.isfile(vegdynRstFile): assert int(self.rqdExeInp['RST_FROM_GLOBAL']) == 1, 'restart from LDASsa should be global' - + tmpFile=self.rqdExeInp['RESTART_ID']+'.landpert_internal_rst.'+y4m2d2_h2m2 tmpRstDir=self.rqdExeInp['RESTART_PATH']+'/'.join([self.rqdExeInp['RESTART_ID'],'output', self.rqdExeInp['RESTART_DOMAIN'],'rs',self.ensdirs[0],y4m2]) @@ -398,15 +398,15 @@ class LDASsetup: if ( os.path.isfile(landpertRstFile)) : self.has_geos_pert = True - elif (int(self.rqdExeInp['RESTART']) == 0) : + elif (int(self.rqdExeInp['RESTART']) == 0) : if (self.catch == 'catch'): self.in_rstfile = '/discover/nobackup/projects/gmao/ssd/land/l_data/LandRestarts_for_Regridding' \ - '/Catch/M09/20170101/catch_internal_rst' + '/Catch/M09/20170101/catch_internal_rst' self.in_tilefile = '/discover/nobackup/projects/gmao/ssd/land/l_data/geos5/bcs/CLSM_params' \ '/mkCatchParam_SMAP_L4SM_v002/SMAP_EASEv2_M09/SMAP_EASEv2_M09_3856x1624.til' elif (self.catch == 'catchcnclm40'): self.in_rstfile = '/discover/nobackup/projects/gmao/ssd/land/l_data/LandRestarts_for_Regridding' \ - '/CatchCN/M36/20150301_0000/catchcnclm40_internal_dummy' + '/CatchCN/M36/20150301_0000/catchcnclm40_internal_dummy' self.in_tilefile = '/discover/nobackup/projects/gmao/bcs_shared/legacy_bcs/Heracles-NL/SMAP_EASEv2_M36/SMAP_EASEv2_M36_964x406.til' elif (self.catch == 'catchcnclm45'): self.in_rstfile = '/discover/nobackup/projects/gmao/ssd/land/l_data/LandRestarts_for_Regridding' \ @@ -416,7 +416,7 @@ class LDASsetup: sys.exit('need to provide at least dummy files') self.in_rstfile = None self.in_tilefile = None - + # DEAL WITH mwRTM input from exec self.assim = True if self.rqdExeInp.get('LAND_ASSIM', 'NO').upper() == 'YES' else False # verify mwrtm file @@ -427,15 +427,15 @@ class LDASsetup: if os.path.isfile(mwrtm_param_file_) : self.has_mwrtm = True self.mwrtm_file = mwrtm_param_file_ - else : - assert not mwrtm_param_file_.strip(), ' MWRTM_PATH: %s should contain mwRTM_param.nc4'% self.rqdExeInp['MWRTM_PATH'] + else : + assert not mwrtm_param_file_.strip(), ' MWRTM_PATH: %s should contain mwRTM_param.nc4'% self.rqdExeInp['MWRTM_PATH'] del self.rqdExeInp['MWRTM_PATH'] if os.path.isfile(vegopacity_file_) : self.has_vegopacity = True self.rqdExeInp['VEGOPACITY_FILE'] = vegopacity_file_ - + # DEAL WITH optional input from exec - + # ------ # Read rm input file # Read (and pop from inpfile) the input required fields in to @@ -479,7 +479,7 @@ class LDASsetup: _printdict(self.optRmInp) # ------ - # set top level directories + # set top level directories # rundir, inpdir, outdir, blddir # executable # exefyl @@ -517,7 +517,7 @@ class LDASsetup: # default is set to 0 ( no output server) if 'oserver_nodes' not in self.optRmInp : self.optRmInp['oserver_nodes'] = 0 - + self.optRmInp['nodes'] = my_nodes + int(self.optRmInp['oserver_nodes']) if (int(self.optRmInp['oserver_nodes']) >=1) : @@ -527,7 +527,7 @@ class LDASsetup: self.optRmInp['writers-per-node'] = 5 else: self.optRmInp['writers-per-node'] = 0 - + def _parseInputFile(self, inpfile): """ @@ -692,14 +692,14 @@ class LDASsetup: print ('\nCorrect the tile file if it is an old EASE tile format... \n') EASEtile=self.bcsdir+'/MAPL_'+short_tile - cmd = './preprocess_ldas.x correctease '+ tile + ' '+ EASEtile + cmd = './preprocess_ldas.x correctease '+ tile + ' '+ EASEtile print ("cmd: " + cmd) sp.call(shlex.split(cmd)) if os.path.isfile(EASEtile) : #update tile file name short_tile ='MAPL_'+short_tile - tile=EASEtile + tile=EASEtile # setup BC files if os.path.isfile('f2g.txt'): os.remove('f2g.txt') @@ -717,13 +717,13 @@ class LDASsetup: # These are dummy values for *cold* restart: wemin_in = '13' # WEmin input/output for scale_catch(cn), - wemin_out = '13' # + wemin_out = '13' # if 'WEMIN_IN' in self.rqdExeInp : wemin_in = self.rqdExeInp['WEMIN_IN'] if 'WEMIN_OUT' in self.rqdExeInp : wemin_out = self.rqdExeInp['WEMIN_OUT'] - + cmd = './preprocess_ldas.x c_f2g ' + tile + ' ' + domain_def + ' '+ self.out_path + ' ' + catchment_def + ' ' + exp_id + ' ' + _y4m2d2h2m2 + ' '+ dzsf print ('Creating f2g.txt....\n') @@ -740,12 +740,12 @@ class LDASsetup: newlocalTile = tile+'.domain' print ("\nCreating local tile file :"+ newlocalTile) print ("\n by excluding land type MAPL_Land_ExcludeFromDomain=1100...\n") - cmd = './preprocess_ldas.x c_localtile ' + tile + ' ' + newlocalTile + cmd = './preprocess_ldas.x c_localtile ' + tile + ' ' + newlocalTile print ("cmd: " + cmd) sp.call(shlex.split(cmd)) short_tile=short_tile +'.domain' tile = newlocalTile - + myTile=self.inpdir+'/tile.data' os.symlink(tile,myTile) @@ -777,7 +777,7 @@ class LDASsetup: # link BC - print ("linking bcs...") + print ("linking bcs...") bcnames=['green','lai','ndvi','nirdf','visdf'] if (self.rqdExeInp['LNFM_FILE'] != ''): bcnames += ['lnfm'] @@ -791,7 +791,7 @@ class LDASsetup: os.symlink(self.rqdExeInp['BCS_PATH']+'../land/shared/CO2_MonthlyMean_DiurnalCycle.nc4', \ self.inpdir+'/CO2_MonthlyMean_DiurnalCycle.nc4') - # create and link restart + # create and link restart print ("Creating and linking restart...") _start = self.begDates[0] @@ -819,18 +819,18 @@ class LDASsetup: rstid = self.rqdExeInp['RESTART_ID'] rstdomain = self.rqdExeInp['RESTART_DOMAIN'] rstpath0 = self.rqdExeInp['RESTART_PATH'] - + # just copy the landassim pert seed if it exists for iens in range(self.nens) : _ensdir = self.ensdirs[iens] _ensid = self.ensids[iens] landassim_seeds = rstpath + _ensdir + '/' + y4m2+'/' + rstid + '.landassim_obspertrseed_rst.'+y4m2d2_h2m2 if os.path.isfile(landassim_seeds) and self.assim : - _seeds = self.rstdir + _ensdir + '/' + y4m2+'/' + exp_id + '.landassim_obspertrseed_rst.'+y4m2d2_h2m2 + _seeds = self.rstdir + _ensdir + '/' + y4m2+'/' + exp_id + '.landassim_obspertrseed_rst.'+y4m2d2_h2m2 shutil.copy(landassim_seeds, _seeds) os.symlink(_seeds, myRstDir+ '/landassim_obspertrseed'+ _ensid +'_rst') self.has_landassim_seed = True - mk_outdir = self.exphome+'/'+exp_id+'/mk_restarts/' + mk_outdir = self.exphome+'/'+exp_id+'/mk_restarts/' cmd= ' '.join(['./process_rst.csh', sponsorid, exp_id, mk_outdir, out_bcdir, out_tilefile, self.catch, RESTART_str, YYYYMMDDHH, self.in_rstfile, self.in_tilefile, dzsf, wemin_in, wemin_out]) @@ -839,8 +839,8 @@ class LDASsetup: remap_tpl = os.path.dirname(os.path.realpath(__file__)) + '/remap_params.tpl' config = yaml_to_config(remap_tpl) - config['slurm']['account'] = self.rqdRmInp['account'] - config['slurm']['qos'] = 'debug' + config['slurm']['account'] = self.rqdRmInp['account'] + config['slurm']['qos'] = 'debug' config['slurm']['qos'] = 'cas' config['input']['surface']['catch_tilefile'] = self.in_tilefile @@ -858,7 +858,7 @@ class LDASsetup: config['output']['surface']['surflay'] = dzsf config['output']['surface']['wemin'] = wemin_out - config = remap_config_ldas( config, RESTART_str, self.rqdExeInp['RESTART_PATH'], self.rqdExeInp['RESTART_ID']) + config = remap_config_ldas( config, RESTART_str, self.rqdExeInp['RESTART_PATH'], self.rqdExeInp['RESTART_ID']) catch_obj = catchANDcn(config_obj = config) catch_obj.remap() @@ -912,7 +912,7 @@ class LDASsetup: catchLocal = self.rstdir+ensdir +'/'+ y4m2+'/'+self.rqdExeInp['EXP_ID']+'.'+self.catch+'_internal_rst.'+y4m2d2_h2m2 if self.islocal : print( "Creating local catchment restart file... \n") - cmd='./preprocess_ldas.x c_localcatchrst '+ catchRstFile +' ' + catchLocal + cmd='./preprocess_ldas.x c_localcatchrst '+ catchRstFile +' ' + catchLocal print ("cmd: "+cmd) sp.call(shlex.split(cmd)) else : @@ -922,7 +922,7 @@ class LDASsetup: if '0000' in ensdir : catchRstFile0 = catchRstFile - else : # re-use 0000 catch file + else : # re-use 0000 catch file catchRstFile = catchRstFile0 # vegdyn restart file @@ -930,7 +930,7 @@ class LDASsetup: vegdynLocal = self.rstdir+ensdir +'/'+self.rqdExeInp['EXP_ID']+'.vegdyn_internal_rst' if self.islocal : print ("Creating the local veg restart file... \n") - cmd='./preprocess_ldas.x c_localvegrst '+ vegdynRstFile +' ' + vegdynLocal + cmd='./preprocess_ldas.x c_localvegrst '+ vegdynRstFile +' ' + vegdynLocal print ("cmd: " + cmd) sp.call(shlex.split(cmd)) else : @@ -940,7 +940,7 @@ class LDASsetup: if '0000' in ensdir : vegdynRstFile0 = vegdynRstFile - else : + else : vegdynRstFile = vegdynRstFile0 if (self.has_geos_pert and self.perturb == 1) : @@ -965,7 +965,7 @@ class LDASsetup: mwRTMLocal = self.bcsdir+'/'+ y4m2+'/'+self.rqdExeInp['EXP_ID']+'.ldas_mwRTMparam.'+y4m2d2_h2m2+'z.nc4' if self.islocal : print ("Creating the local mwRTM restart file... \n") - cmd='./preprocess_ldas.x c_localmwrtmrst '+ mwRTMRstFile +' ' + mwRTMLocal + cmd='./preprocess_ldas.x c_localmwrtmrst '+ mwRTMRstFile +' ' + mwRTMLocal print ("cmd: " + cmd) sp.call(shlex.split(cmd)) else : @@ -980,7 +980,7 @@ class LDASsetup: self.rqdExeInp['RESTART_PATH'] = myRstDir if os.path.isfile('f2g.txt'): os.remove('f2g.txt') - + status = True return status @@ -1036,7 +1036,7 @@ class LDASsetup: # get optimzed NX and IMS if os.path.isfile('optimized_distribution'): os.remove('optimized_distribution') - + print ("Optimizing... decomposition of processes.... \n") cmd = './preprocess_ldas.x optimize '+ self.inpdir+'/tile.data '+ str(self.rqdRmInp['ntasks_model']) print ("cmd: " + cmd) @@ -1046,12 +1046,12 @@ class LDASsetup: if int(optinxny['NY']) != int(self.rqdRmInp['ntasks_model']): self.rqdRmInp['ntasks_model']=optinxny['NY'] print ('adjust ntasks_model %d for cubed-sphere grid' % int(self.rqdRmInp['ntasks_model'])) - + if os.path.isfile('IMS.rc') : shutil.move('IMS.rc', self.rundir+'/') if os.path.isfile('JMS.rc') : shutil.move('JMS.rc', self.rundir+'/') - + os.remove('optimized_distribution') # DEFAULT rc files @@ -1086,17 +1086,17 @@ class LDASsetup: ' ' + GRID + ' ' + str(self.rqdExeInp['RUN_IRRIG']) + ' ' + _assim + ' '+ str(self.nens) print(cmd) #os.system(cmd) - sp.call(shlex.split(cmd)) + sp.call(shlex.split(cmd)) for line in fileinput.input(tmprcfile,inplace=True): print (line.rstrip().replace('GEOSldas_expid',self.rqdExeInp['EXP_ID'])) # just copy an empty ExtData.rc if shortfile=='ExtData.rc' : shutil.copy2(rcfile, self.rundir+'/'+shortfile) - - if shortfile == 'CAP.rc': + + if shortfile == 'CAP.rc': tmprcfile = self.rundir+'/CAP.rc' shutil.copy2(rcfile,tmprcfile) - + _num_sgmt = int(self.rqdExeInp['NUM_SGMT']) for line in fileinput.input(tmprcfile,inplace=True): @@ -1107,15 +1107,15 @@ class LDASsetup: print (line.rstrip().replace('BEG_DATE:',self.begDates[0].strftime('BEG_DATE: %Y%m%d %H%M%S'))) for line in fileinput.input(tmprcfile,inplace=True): print (line.rstrip().replace('END_DATE:',self.endDates[-1].strftime('END_DATE: %Y%m%d %H%M%S'))) - + if shortfile == 'LDAS.rc' : ldasrcInp = OrderedDict() - # land default + # land default default_surfrcInp = self._parseInputFile(etcdir+'/GEOS_SurfaceGridComp.rc') for key,val in default_surfrcInp.items() : ldasrcInp[key] = val - # ldas default, may overwrite land default + # ldas default, may overwrite land default default_ldasrcInp = self._parseInputFile(rcfile) for key,val in default_ldasrcInp.items() : ldasrcInp[key] = val @@ -1132,7 +1132,7 @@ class LDASsetup: # create BC in rc file tmpl_ = '' if self.nens >1 : - tmpl_='%s' + tmpl_='%s' if self.perturb == 1: ldasrcInp['PERTURBATIONS'] ='1' bcval=['../input/green','../input/lai','../input/lnfm','../input/ndvi','../input/nirdf','../input/visdf'] @@ -1156,15 +1156,15 @@ class LDASsetup: if 'VEGDYN_INTERNAL_RESTART_TYPE' in ldasrcInp : # avoid duplicate del ldasrcInp['VEGDYN_INTERNAL_RESTART_TYPE'] - + rstkey=[catch_,'VEGDYN'] rstval=[self.catch,'vegdyn'] - if self.has_mwrtm : + if self.has_mwrtm : keyn='LANDASSIM_INTERNAL_RESTART_FILE' valn='../input/restart/mwrtm_param_rst' ldasrcInp[keyn]= valn - if self.has_vegopacity : + if self.has_vegopacity : keyn='VEGOPACITY_FILE' valn='../input/vegopacity.data' ldasrcInp[keyn]= valn @@ -1179,16 +1179,16 @@ class LDASsetup: valn='../input/restart/landassim_obspertrseed'+tmpl_+'_rst' ldasrcInp[keyn]= valn - if self.assim: + if self.assim: keyn='LANDASSIM_OBSPERTRSEED_CHECKPOINT_FILE' valn='landassim_obspertrseed'+tmpl_+'_checkpoint' ldasrcInp[keyn]= valn - + for key,val in zip(rstkey,rstval) : keyn = key+ '_INTERNAL_RESTART_FILE' valn = '../input/restart/'+val+tmpl_+'_internal_rst' ldasrcInp[keyn]= valn - + # checkpoint file and its type keyn = catch_ + '_INTERNAL_CHECKPOINT_FILE' valn = self.catch+tmpl_+'_internal_checkpoint' @@ -1200,12 +1200,12 @@ class LDASsetup: valn = '../input/restart/landpert'+tmpl_+'_internal_rst' ldasrcInp[keyn]= valn # for lat/lon and EASE tile space, specify LANDPERT checkpoint file here (via MAPL); - # for cube-sphere tile space, Landpert GC will set up LANDPERT checkpoint file + # for cube-sphere tile space, Landpert GC will set up LANDPERT checkpoint file if ('-CF' not in self.rqdExeInp['GRIDNAME']): keyn = 'LANDPERT_INTERNAL_CHECKPOINT_FILE' valn = 'landpert'+tmpl_+'_internal_checkpoint' ldasrcInp[keyn]= valn - + # write LDAS.rc fout =open(self.rundir+'/'+shortfile,'w') # ldasrcInp['NUM_LDAS_ENSEMBLE']=ldasrcInp.pop('NUM_ENSEMBLE') @@ -1219,9 +1219,9 @@ class LDASsetup: fout.write("EXP_ID:".ljust(36)+self.rqdExeInp['EXP_ID']+'\n') fout.write("TILING_FILE:".ljust(36)+"../input/tile.data\n") - fout.close() + fout.close() - fout=open(self.rundir+'/'+'cap_restart','w') + fout=open(self.rundir+'/'+'cap_restart','w') #fout.write(self.rqdExeInp['BEG_DATE']) fout.write(self.begDates[0].strftime('%Y%m%d %H%M%S')) fout.close() @@ -1276,7 +1276,7 @@ class LDASsetup: fout.write("\nsed -i 's/#if($capdate<$enddate) sbatch/if($capdate<$enddate) sbatch /g' lenkf.j") fout.close() - sp.call(['chmod', '755', self.rundir+'/ldas_batchrun.j']) + sp.call(['chmod', '755', self.rundir+'/ldas_batchrun.j']) status = True return status @@ -1333,9 +1333,11 @@ class LDASsetup: elif 'MY_NODES' in line : line_ = line.replace('MY_NODES',str(self.optRmInp['nodes'])) fout.write(line_.replace('MY_NTASKS_PER_NODE',str(self.rqdRmInp['ntasks-per-node']))) - if int(self.rqdRmInp['ntasks-per-node']) > 40: + if int(self.rqdRmInp['ntasks-per-node']) > 46: + fout.write("#SBATCH --constraint=mil\n") + elif int(self.rqdRmInp['ntasks-per-node']) > 40: fout.write("#SBATCH --constraint=cas\n") - if (28 < int(self.rqdRmInp['ntasks-per-node']) and int(self.rqdRmInp['ntasks-per-node']) <= 40) : + elif (28 < int(self.rqdRmInp['ntasks-per-node']) and int(self.rqdRmInp['ntasks-per-node']) <= 40) : fout.write("#SBATCH --constraint=sky|cas\n") elif 'MY_OSERVER_NODES' in line : fout.write(line.replace('MY_OSERVER_NODES',str(self.optRmInp['oserver_nodes']))) @@ -1357,7 +1359,7 @@ class LDASsetup: elif 'MY_MODEL' in line : fout.write(line.replace('MY_MODEL',self.catch)) elif 'MY_POSTPROC_HIST' in line : - fout.write(line.replace('MY_POSTPROC_HIST',str(self.rqdExeInp['POSTPROC_HIST']))) + fout.write(line.replace('MY_POSTPROC_HIST',str(self.rqdExeInp['POSTPROC_HIST']))) elif 'MY_FIRST_ENS_ID' in line : fout.write(line.replace('MY_FIRST_ENS_ID',str(self.first_ens_id))) elif 'MY_LADAS_COUPLING' in line : @@ -1367,12 +1369,12 @@ class LDASsetup: elif 'MY_ADAS_EXPDIR' in line : if self.ladas_coupling > 0: fout.write(line.replace('MY_ADAS_EXPDIR', self.rqdExeInp['ADAS_EXPDIR'])) - - + + else : fout.write(line.replace('MY_EXPDIR',self.exphome+'/$EXPID')) - - sp.call(['chmod', '755', 'lenkf.j']) + + sp.call(['chmod', '755', 'lenkf.j']) expdir = '/'.join(self.rundir.rstrip('/').split('/')[:-1]) print ('\nExperiment directory: %s' % expdir) @@ -1393,7 +1395,7 @@ def _printExeInputKeys(rqdExeInpKeys): Private method: print sample exe input """ - print ('####################################################################################') + print ('####################################################################################') print ('# #') print ('# REQUIRED INPUTS #') print ('# #') @@ -1401,7 +1403,7 @@ def _printExeInputKeys(rqdExeInpKeys): print ('# #') print ('####################################################################################') print () - print ('############################################################') + print ('############################################################') print ('# #') print ('# EXPERIMENT INFO #') print ('# #') @@ -1422,14 +1424,14 @@ def _printExeInputKeys(rqdExeInpKeys): print ('# (i) Select "RESTART" option: #') print ('# #') print ('# Use one of the following options if you *have* a #') - print ('# GEOSldas restart file: #') + print ('# GEOSldas restart file: #') print ('# #') print ('# RESTART: 1 #') print ('# YES, have restart file from GEOSldas #') print ('# in SAME tile space (grid) with SAME boundary #') print ('# conditions and SAME snow model parameter (WEMIN). #') print ('# The restart domain can be for the same or #') - print ('# a larger one. #') + print ('# a larger one. #') print ('# #') print ('# RESTART: 2 #') print ('# YES, have restart file from GEOSldas but #') @@ -1439,17 +1441,17 @@ def _printExeInputKeys(rqdExeInpKeys): print ('# Restart *must* be for the GLOBAL domain. #') print ('# #') print ('# Use one of the following options if you DO NOT have a #') - print ('# GEOSldas restart file #') + print ('# GEOSldas restart file #') print ('# (works for global domain ONLY!): #') print ('# #') print ('# RESTART: 0 #') print ('# Cold start from some old restart for Jan 1, 0z. #') print ('# #') print ('# RESTART: M #') - print ('# Re-tile from archived MERRA-2 restart file. #') + print ('# Re-tile from archived MERRA-2 restart file. #') print ('# #') print ('# RESTART: F #') - print ('# Re-tile from FP (Forward Processing) restart file. #') + print ('# Re-tile from FP (Forward Processing) restart file. #') print ('# #') print ('# RESTART: G #') print ('# Re-tile from any AGCM catch[cnclmxx]_internal_rst file.#') @@ -1459,19 +1461,19 @@ def _printExeInputKeys(rqdExeInpKeys): print ('# Except for RESTART=1, SPIN-UP is REQUIRED in almost #') print ('# all cases. #') print ('# -------------------------------------------------------- #') - print ('# #') - print ('# #') + print ('# #') + print ('# #') print ('# (ii) Specify experiment ID/location of restart file: #') print ('# #') print ('# For RESTART=1 or RESTART=2: #') print ('# Specify RESTART_ID, RESTART_PATH, RESTART_DOMAIN with #') print ('# restarts stored as follows: #') print ('# RESTART_PATH/RESTART_ID/output/RESTART_DOMAIN/rs/ #') - print ('# #') + print ('# #') print ('# For RESTART=0 or RESTART=M or RESTART=F: #') print ('# There is no need to specify RESTART_ID, RESTART_PATH, #') print ('# and RESTART_DOMAIN. #') - print ('# #') + print ('# #') print ('# For RESTART=G: #') print ('# RESTART_ID : full_path_to_AGCM_experiment_directory #') print ('# RESTART_PATH : full_path_of_the_AGCM_restart_file #') @@ -1492,7 +1494,7 @@ def _printExeInputKeys(rqdExeInpKeys): print ('# #') print ('# For more information, see: #') print ('# GEOSldas/doc/README.MetForcing_and_BCS.md #') - print ('# #') + print ('# #') print ('############################################################') print () print ('MET_TAG:') @@ -1522,26 +1524,26 @@ def _printExeInputKeys(rqdExeInpKeys): print ('# #') print ('# 0 -- LDAS not coupled with ADAS (default) #') print ('# 1 -- LDAS coupled with central member of ADAS #') - print ('# 2 -- LDAS coupled with ens component of ADAS #') - print ('# #') + print ('# 2 -- LDAS coupled with ens component of ADAS #') + print ('# #') print ('# Requirements for LADAS_COUPLING > 0: #') - print ('# #') + print ('# #') print ('# (0) Specify ADAS_EXPDIR = [full_path]/[ADAS_EXPID] #') print ('# #') print ('# (1) BEG_DATE must be consistent with first cycle date #') print ('# and time of ADAS experiment (time is typically #') print ('# 3z, 9z, 15z, or 21z) #') - print ('# #') + print ('# #') print ('# (2) EXP_DOMAIN must be global CS grid as in ADAS exp #') print ('# #') print ('# (3) MET_TAG must be set to [ADAS_EXPID]__Nx+- #') print ('# MET_PATH must be set as follows for #') - print ('# LADAS_COUPLING = 1: #') - print ('# [full_path]/[LDAS_EXPID]/scratch/ #') - print ('# LADAS_COUPLING = 2: #') + print ('# LADAS_COUPLING = 1: #') + print ('# [full_path]/[LDAS_EXPID]/scratch/ #') + print ('# LADAS_COUPLING = 2: #') print ('# [ADAS_EXPDIR]/atmens/ensdiag/forc #') - print ('# After ldas exp setup, verify the following link: #') - print ('# ../input/met_forcing/forc -> [MET_PATH] #') + print ('# After ldas exp setup, verify the following link: #') + print ('# ../input/met_forcing/forc -> [MET_PATH] #') print ('# #') print ('# (4) BCS_PATH must be consistent with that of #') print ('# [ADAS_EXPDIR][/run/lnbcs #') @@ -1555,7 +1557,7 @@ def _printExeInputKeys(rqdExeInpKeys): print ('# - instantaneous "catch_progn_incr" must be in #') print ('# HISTORY collection #') print ('# - time step must match that of LDAS analysis #') - print ('# - for LADAS_COUPLING=2, HISTORY must include #') + print ('# - for LADAS_COUPLING=2, HISTORY must include #') print ('# "catch_progn_incr[ENS_INDEX]" #') print ('# #') print ('############################################################') @@ -1595,12 +1597,12 @@ def _printExeInputKeys(rqdExeInpKeys): i_ += 1 print () print () - + def _printRmInputKeys(rqdRmInpKeys, optRmInpKeys): """ Private method: print sample resource manager input """ - + print ('#') print ('# REQUIRED inputs') print ('#') @@ -1609,9 +1611,10 @@ def _printRmInputKeys(rqdRmInpKeys, optRmInpKeys): print ('# [At NCCS: Use command "getsponsor" to see available account number(s).]' ) print ('# - walltime = walltime requested; format is HH:MM:SS (hours/minutes/seconds)') print ('# - ntasks_model = number of processors requested for the model (typically 112; output server is not included)') - print ('# - ntasks-per-node = number of tasks per node (typically 46 for cascade lake*, 40 for skylake, and 28 for haswell nodes)') - print ('# [If >40, cascade lake nodes will be allocated, if >28, cascade or skylake, else cascade, skylake or haswell.]') - print ('# [*NCCS recommends <=46 cores per node on SCU16 (cascade lake) due to OS issues (as of 6 Oct 2021).]') + print ('# - ntasks-per-node = number of tasks per node (typically 126 for milan*, 46 for cascade lake**, and 40 for skylake)') + print ('# [If >46, milan nodes will be allocated; >40, cascade lake nodes will be allocated; if >28, cascade or skylake.]') + print ('# [*NCCS recommends <=126 cores per node on SCU17 (milan) due to OS issues (as of 6 Oct 2021).]') + print ('# [**NCCS recommends <=46 cores per node on SCU16 (cascade lake) due to OS issues (as of 6 Oct 2021).]') print ('#') for key in rqdRmInpKeys: print (key + ':') @@ -1629,7 +1632,7 @@ def _printRmInputKeys(rqdRmInpKeys, optRmInpKeys): print ('#') for key in optRmInpKeys: print ('#'+key + ':') - + def parseCmdLine(): """ parse command line arguments and return a dict of options @@ -1647,14 +1650,14 @@ def parseCmdLine(): # subparser: sample command p_sample = p_sub.add_parser( - 'sample', + 'sample', help='write sample input files', description='Print sample input files - either for the '\ 'Fortran executable or the resource manager (SLURM)', ) group = p_sample.add_mutually_exclusive_group(required=True) group.add_argument( - '--exeinp', + '--exeinp', help='print sample input file used to generate RC files for GEOSldas App.', action='store_true', ) @@ -1665,25 +1668,25 @@ def parseCmdLine(): ) # subparser: setup command p_setup = p_sub.add_parser( - 'setup', + 'setup', help='setup LDAS experiment', description="The 'setup' sub-command is used to setup a GEOSldas " \ "experiment. The positional argument 'exphome' is used to create " \ "work_path (exphome+/output) and run_path (exphome+/run)." ) p_setup.add_argument( - '-v', - '--verbose', - help='verbose output', + '-v', + '--verbose', + help='verbose output', action='store_true', ) p_setup.add_argument('exphome', help='experiment location') p_setup.add_argument( - 'exeinpfile', + 'exeinpfile', help='input file with arguments used to generate RC files for GEOSldas App', ) p_setup.add_argument( - 'batinpfile', + 'batinpfile', help='input file with arguments for SLURM', ) p_setup.add_argument( @@ -1719,7 +1722,7 @@ if __name__=='__main__': #print "reading params...." args = vars(parseCmdLine()) # vars converts to dict ld = LDASsetup(args) - + print ("creating dir structure") status = ld.createDirStructure() assert(status) From 06bde97488d19a0a01a8cb8a8a183b59b62b9490 Mon Sep 17 00:00:00 2001 From: Matthew Thompson Date: Thu, 26 Oct 2023 11:11:36 -0400 Subject: [PATCH 166/308] Some update for the readme --- README.md | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 172d3dfd..a3303ae5 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ This document explains how to build, set up, and run the GEOS land modeling and ## How to Build GEOSldas -### Step 1: Load the Build Modules +### Step 1: Load the Build Modules Load the `GEOSenv` module provided by the GMAO Software Infrastructure team. It contains the latest `git`, `CMake`, and `mepo` modules and must be loaded in any interactive window that is used to check out and build the model. @@ -13,7 +13,7 @@ module use -a (path) module load GEOSenv ``` -where `(path)` depends on the computer and operating system: +where `(path)` depends on the computer and operating system: | System | Path | | ------------- |---------------------------------------------------| @@ -28,7 +28,7 @@ For development work, clone the _entire_ repository and use the `develop` branch ``` git clone -b develop git@github.com:GEOS-ESM/GEOSldas.git ``` -For science runs, you can also obtain a specific tag or branch _only_ (as opposed to the _entire_ repository), e.g.: +For science runs, you can also obtain a specific tag or branch _only_ (as opposed to the _entire_ repository), e.g.: ``` git clone -b v17.9.1 --single-branch git@github.com:GEOS-ESM/GEOSldas.git ``` @@ -40,13 +40,25 @@ To build the model in a single step, do the following: ``` cd ./GEOSldas parallel_build.csh -``` -from a head node. Doing so will check out all the external repositories of the model (albeit only on the first run, [see subsection on mepo below](#mepo)!) and build the model. When done, the resulting model build will be found in `build/` and the installation will be found in `install/`, with setup scripts like `ldas_setup` in `install/bin`. +``` +from a head node. Doing so will check out all the external repositories of the model (albeit only on the first run, [see subsection on mepo below](#mepo)!) and build the model. When done, the resulting model build will be found in `build-SLES12/` and the installation will be found in `install-SLES12/`, with setup scripts like `ldas_setup` in `install-SLES12/bin`. -To obtain a build that is suitable for debugging, use `parallel_build.csh -debug`, which will build in `build-Debug/` and install in `install-Debug/`. There is also an option for aggressive optimization. For details, see [GEOSldas Wiki](https://github.com/GEOS-ESM/GEOSldas/wiki). +To obtain a build that is suitable for debugging, use `parallel_build.csh -debug`, which will build in `build-Debug-SLES12/` and install in `install-Debug-SLES12/`. There is also an option for aggressive optimization. For details, see [GEOSldas Wiki](https://github.com/GEOS-ESM/GEOSldas/wiki). See below for how to build the model in multiple steps. +#### Running on Milans at NCCS + +By default, `parallel_build.csh` will build on SLES12 nodes at discover (either Skylake or Cascade Lake). However, Milan nodes were +recently installed at discover, which use SLES15 as their operating system. Because of this OS difference, if you want to run on the +Milans, you must build on the Milans. To do so you can run `parallel_build.csh` with the `-mil` flag, e.g.: + +``` +parallel_build.csh -mil +``` + +This will by default build in `build-SLES15` and install to `install-SLES15`. + --- ## How to Set Up (Configure) and Run GEOSldas @@ -57,7 +69,7 @@ a) Set up the job as follows: cd (build_path)/GEOSldas/install/bin source g5_modules [for bash or zsh: source g5_modules.[z]sh] ./ldas_setup setup [-v] (exp_path) ("exe"_input_filename) ("bat"_input_filename) -``` +``` where @@ -70,14 +82,14 @@ where The three arguments for `ldas_setup` are positional and must be ordered as indicated above. -The latter two files contain essential information about the experiment setup. +The latter two files contain essential information about the experiment setup. Sample files can be generated as follows: -``` +``` ldas_setup sample --exeinp > YOUR_exeinp.txt ldas_setup sample --batinp > YOUR_batinp.txt ``` -Edit these sample files following the examples and comments within the sample files. +Edit these sample files following the examples and comments within the sample files. The ldas_setup script creates a run directory and other directories at: `[exp_path]/[exp_name]` @@ -156,7 +168,7 @@ and CMake will install there. ``` make -j6 install ``` -If you are at NCCS, you **should** run `make -j6 install` on an interactive _compute_ node. +If you are at NCCS, you **should** run `make -j6 install` on an interactive _compute_ node. ## Contributing From c911d23b24e65812def818001bcfbaf554678e88 Mon Sep 17 00:00:00 2001 From: Rolf Reichle <54944691+gmao-rreichle@users.noreply.github.com> Date: Thu, 26 Oct 2023 11:14:01 -0400 Subject: [PATCH 167/308] relaxing SBATCH constraints (ldas_setup) --- src/Applications/LDAS_App/ldas_setup | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Applications/LDAS_App/ldas_setup b/src/Applications/LDAS_App/ldas_setup index f44a4bc1..88191974 100755 --- a/src/Applications/LDAS_App/ldas_setup +++ b/src/Applications/LDAS_App/ldas_setup @@ -1336,9 +1336,9 @@ class LDASsetup: if int(self.rqdRmInp['ntasks-per-node']) > 46: fout.write("#SBATCH --constraint=mil\n") elif int(self.rqdRmInp['ntasks-per-node']) > 40: - fout.write("#SBATCH --constraint=cas\n") + fout.write("#SBATCH --constraint=mil|cas\n") elif (28 < int(self.rqdRmInp['ntasks-per-node']) and int(self.rqdRmInp['ntasks-per-node']) <= 40) : - fout.write("#SBATCH --constraint=sky|cas\n") + fout.write("#SBATCH --constraint=mil|cas|sky\n") elif 'MY_OSERVER_NODES' in line : fout.write(line.replace('MY_OSERVER_NODES',str(self.optRmInp['oserver_nodes']))) elif 'MY_WRITERS_NPES' in line : From 2006fa2d1c1542da32aa93ed41947d7126df8990 Mon Sep 17 00:00:00 2001 From: biljanaorescanin Date: Thu, 26 Oct 2023 11:46:18 -0400 Subject: [PATCH 168/308] milan nodes are on SLES15 cas and sky on SLES12 --- src/Applications/LDAS_App/ldas_setup | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Applications/LDAS_App/ldas_setup b/src/Applications/LDAS_App/ldas_setup index 88191974..7cd5767f 100755 --- a/src/Applications/LDAS_App/ldas_setup +++ b/src/Applications/LDAS_App/ldas_setup @@ -1336,9 +1336,9 @@ class LDASsetup: if int(self.rqdRmInp['ntasks-per-node']) > 46: fout.write("#SBATCH --constraint=mil\n") elif int(self.rqdRmInp['ntasks-per-node']) > 40: - fout.write("#SBATCH --constraint=mil|cas\n") + fout.write("#SBATCH --constraint=cas\n") elif (28 < int(self.rqdRmInp['ntasks-per-node']) and int(self.rqdRmInp['ntasks-per-node']) <= 40) : - fout.write("#SBATCH --constraint=mil|cas|sky\n") + fout.write("#SBATCH --constraint=cas|sky\n") elif 'MY_OSERVER_NODES' in line : fout.write(line.replace('MY_OSERVER_NODES',str(self.optRmInp['oserver_nodes']))) elif 'MY_WRITERS_NPES' in line : From b1ce78c9e276eccc12330b96157ac1403a4cac0c Mon Sep 17 00:00:00 2001 From: amfox37 Date: Thu, 26 Oct 2023 10:46:52 -0600 Subject: [PATCH 169/308] add range to scaled obs --- .../clsm_ensupd_read_obs.F90 | 157 +++++++++++++----- 1 file changed, 118 insertions(+), 39 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 8b90c4df..f6039a60 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -8174,10 +8174,43 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & ! scale sfmc obs to model climatology via standard-normal-deviate (zscore) ! scaling using seasonally varying (pentad) stats + ! Grid information is read from a NetCDF file ! - ! scaling parameters are on 0.25 deg lat/lon grid - ! - ! intended for scaling of ASCAT "sfds" observations + ! Scaling parameters are read from a NetCDF file that contains the following: + ! variables: + ! int version ; + ! double ll_lon ; + ! ll_lon:standard_name = "longitude of lower left corner" ; + ! double ll_lat ; + ! ll_lat:standard_name = "latitude of lower left corner" ; + ! double d_lon ; + ! d_lon:standard_name = "longitude grid spacing" ; + ! double d_lat ; + ! d_lat:standard_name = "latitude grid spacing" ; + ! int pentad(pentad) ; + ! pentad:standard_name = "pentad" ; + ! double start_time(pentad) ; + ! start_time:standard_name = "start time" ; + ! double end_time(pentad) ; + ! end_time:standard_name = "end time" ; + ! double lon(lon) ; + ! lon:standard_name = "longitude" ; + ! double lat(lat) ; + ! lat:standard_name = "latitude" ; + ! double o_mean(pentad, lon, lat) ; + ! o_mean:standard_name = "observation mean" ; + ! double o_std(pentad, lon, lat) ; + ! o_std:standard_name = "observation standard deviation" ; + ! double m_mean(pentad, lon, lat) ; + ! m_mean:standard_name = "model mean" ; + ! double m_std(pentad, lon, lat) ; + ! m_std:standard_name = "model standard deviation" ; + ! double m_min(lon, lat) ; + ! m_min:standard_name = "model minimum" ; + ! double m_max(lon, lat) ; + ! m_max:standard_name = "model maximum" ; + ! double n_data(pentad, lon, lat) ; + ! n_data:standard_name = "number of data points" ; ! ! A M Fox, reichle, April 2023 @@ -8199,17 +8232,7 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & real, intent(inout), dimension(N_catd) :: tmp_obs real, intent(inout), dimension(N_catd) :: tmp_std_obs - - ! ---------------------------------------------------------- - ! Grid and netcdf parameters (might want to read these from netCDF file?) - - ! integer, parameter :: N_lon = 1440 - ! integer, parameter :: N_lat = 720 - real, parameter :: ll_lon = -180.0000 - real, parameter :: ll_lat = -90.0000 - real, parameter :: dlon = 0.25 - real, parameter :: dlat = 0.25 - + ! ---------------------------------------------------------- ! local variables @@ -8225,10 +8248,13 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & integer :: pentad_dimid, lon_dimid, lat_dimid integer :: N_pentad, N_lon, N_lat integer :: pentad_varid, lon_varid, lat_varid - integer :: o_mean_varid, o_std_varid, m_mean_varid, m_std_varid + integer :: o_mean_varid, o_std_varid, m_mean_varid, m_std_varid, m_min_varid, m_max_varid + integer :: ll_lon_varid, ll_lat_varid, dlon_varid, dlat_varid integer, dimension(3) :: start, icount + + logical :: file_exists - real :: tmpreal, this_lon, this_lat + real :: tmpreal, this_lon, this_lat, ll_lon, ll_lat, dlon, dlat integer, dimension(:), allocatable :: sclprm_tile_id integer, dimension(:), allocatable :: pentads @@ -8236,26 +8262,49 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & real, dimension(:), allocatable :: sclprm_lon, sclprm_lat real, dimension(:,:), allocatable :: sclprm_mean_obs, sclprm_std_obs real, dimension(:,:), allocatable :: sclprm_mean_mod, sclprm_std_mod + real, dimension(:,:), allocatable :: sclprm_min_mod, sclprm_max_mod character(len=*), parameter :: Iam = ' scale_obs_sfmc_zscore' character(len=400) :: err_msg ! ------------------------------------------------------------------ - ! read scaling parameters from file - + ! Read scaling parameters from file + fname = trim(this_obs_param%scalepath) // '/' // & trim(this_obs_param%scalename) // '.nc4' if (logit) write (logunit,*) 'scaling obs species ', this_obs_param%species, ':' if (logit) write (logunit,'(400A)') ' reading ', trim(fname) + + ! Check if file exists + + inquire(file=fname, exist=file_exists) + + if (.not. file_exists) then + + err_msg = 'Scaling parameter file not found' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + + end if - ! What pentad do we want? + ! Determine pentad to use + pp = date_time%pentad - ! open the NetCDF file + ! Open the NetCDF file + ierr = nf90_open(fname, nf90_nowrite, ncid) - + + ! Get the dimension and variable IDs + + ierr = nf90_inq_varid(ncid, 'll_lon', ll_lon_varid) + ierr = nf90_inq_varid(ncid, 'll_lat', ll_lat_varid) + ierr = nf90_inq_varid(ncid, 'dlon', dlon_varid) + ierr = nf90_inq_varid(ncid, 'dlat', dlat_varid) + + ! Get the dimension sizes + ierr = nf90_inq_dimid(ncid, 'pentad', pentad_dimid) ierr = nf90_inq_dimid(ncid, 'lon', lon_dimid) ierr = nf90_inq_dimid(ncid, 'lat', lat_dimid) @@ -8264,14 +8313,26 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & ierr = nf90_inquire_dimension(ncid, lon_dimid, len = N_lon) ierr = nf90_inquire_dimension(ncid, lat_dimid, len = N_lat) + ! Get the variable IDs + ierr = nf90_inq_varid(ncid, 'lon', lon_varid) ierr = nf90_inq_varid(ncid, 'lat', lat_varid) ierr = nf90_inq_varid(ncid, 'o_mean', o_mean_varid) ierr = nf90_inq_varid(ncid, 'o_std', o_std_varid) ierr = nf90_inq_varid(ncid, 'm_mean', m_mean_varid) ierr = nf90_inq_varid(ncid, 'm_std', m_std_varid) + ierr = nf90_inq_varid(ncid, 'm_min', m_min_varid) + ierr = nf90_inq_varid(ncid, 'm_max', m_max_varid) + + ! Read grid variables + + ierr = nf90_get_var(ncid, ll_lon_varid, ll_lon) + ierr = nf90_get_var(ncid, ll_lat_varid, ll_lat) + ierr = nf90_get_var(ncid, dlon_varid, dlon) + ierr = nf90_get_var(ncid, dlat_varid, dlat) - ! read lon and lat variables + ! Read lon and lat variables + allocate(sclprm_lon(N_lon), sclprm_lat(N_lat)) ierr = nf90_get_var(ncid, lon_varid, sclprm_lon) ierr = nf90_get_var(ncid, lat_varid, sclprm_lat) @@ -8279,26 +8340,32 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & start = [1, 1, pp] icount = [N_lat, N_lon, 1] + ! Read mean and std variables + allocate(sclprm_mean_obs(N_lat, N_lon), sclprm_std_obs(N_lat, N_lon)) allocate(sclprm_mean_mod(N_lat, N_lon), sclprm_std_mod(N_lat, N_lon)) - - ierr2 = nf90_get_var(ncid, o_mean_varid, sclprm_mean_obs, start, icount) + allocate(sclprm_min_mod(N_lat, N_lon), sclprm_max_mod(N_lat, N_lon)) + + ierr = nf90_get_var(ncid, o_mean_varid, sclprm_mean_obs, start, icount) ierr = nf90_get_var(ncid, o_std_varid, sclprm_std_obs, start, icount) ierr = nf90_get_var(ncid, m_mean_varid, sclprm_mean_mod, start, icount) ierr = nf90_get_var(ncid, m_std_varid, sclprm_std_mod, start, icount) - - ! close the netcdf file + ierr = nf90_get_var(ncid, m_min_varid, sclprm_min_mod) + ierr = nf90_get_var(ncid, m_max_varid, sclprm_max_mod) + + ! Close the netcdf file + ierr = nf90_close(ncid) ! -------------------------------------------------------------- - ! scale observations (at this point all obs are of same type because - ! of the way the subroutine is called from subroutine read_obs() + ! Scale observations (at this point all obs are of same type because + ! of the way the subroutine is called from subroutine read_obs() do i=1,N_catd - ! check for no-data-values in observation (any neg value is no_data) - + ! Check for no-data-values in observation (any neg value is no_data) + if (tmp_obs(i)>=0.) then ! ll_lon and ll_lat refer to lower left corner of grid cell @@ -8307,20 +8374,22 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & this_lon = tmp_lon(i) this_lat = tmp_lat(i) + ! Find indices for current tile lat and lon on scaling parameter grid + i_ind = ceiling((this_lon - ll_lon)/dlon) j_ind = ceiling((this_lat - ll_lat)/dlat) - ! find ind for current tile id in scaling parameters - - ! sanity check (against accidental use of wrong tile space) - + ! Sanity check (against accidental use of wrong tile space) + if ( abs(tile_coord(i)%com_lat-sclprm_lat(j_ind))>tol .or. & abs(tile_coord(i)%com_lon-sclprm_lon(i_ind))>tol ) then + err_msg = 'something wrong' call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + end if - ! check for no-data-values in observation and fit parameters + ! Check for no-data-values in observation and fit parameters ! (any negative number could be no-data-value for observations) if ( sclprm_mean_obs(j_ind, i_ind)>0. .and. & @@ -8328,14 +8397,22 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & sclprm_std_obs(j_ind, i_ind)>=0. .and. & sclprm_std_mod(j_ind, i_ind)>=0. ) then - ! scale via standard normal deviates + ! Scale via standard normal deviates tmpreal = sclprm_std_mod(j_ind, i_ind)/sclprm_std_obs(j_ind, i_ind) tmp_obs(i) = sclprm_mean_mod(j_ind, i_ind) & + tmpreal*(tmp_obs(i)-sclprm_mean_obs(j_ind, i_ind)) - ! scale observation error std + ! Check of tmp_obs is within range of model climatology + + if (tmp_obs(i)sclprm_max_mod(j_ind, i_ind)) then + tmp_obs(i) = sclprm_max_mod(j_ind, i_ind) + end if + + ! Scale observation error std tmp_std_obs(i) = tmpreal*tmp_std_obs(i) @@ -8348,13 +8425,15 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & end if end do - + deallocate(sclprm_lon) deallocate(sclprm_lat) deallocate(sclprm_mean_obs) deallocate(sclprm_std_obs) deallocate(sclprm_mean_mod) - deallocate(sclprm_std_mod) + deallocate(sclprm_std_mod) + deallocate(sclprm_min_mod) + deallocate(sclprm_max_mod) end subroutine scale_obs_sfmc_zscore From 42918e67d21d1e69d5f8be914f62cb987e651aa5 Mon Sep 17 00:00:00 2001 From: saraqzhang Date: Thu, 26 Oct 2023 14:32:41 -0400 Subject: [PATCH 170/308] update the path for forcing in case of coupling with adas modified: Applications/LDAS_App/lenkf.j.template --- src/Applications/LDAS_App/lenkf.j.template | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Applications/LDAS_App/lenkf.j.template b/src/Applications/LDAS_App/lenkf.j.template index 5ec5e2ef..455abe4f 100644 --- a/src/Applications/LDAS_App/lenkf.j.template +++ b/src/Applications/LDAS_App/lenkf.j.template @@ -130,10 +130,9 @@ if ( $LADAS_COUPLING == 1 ) then cd $SCRDIR else - # copy central-simulation forcing from $FVWORK to scratch dir - - echo "copying lfo_Nx+- met forcing from $FVWORK to $SCRDIR" - /bin/cp -f $FVWORK/*lfo_Nx+-*nc4 $SCRDIR/. + # move central-simulation forcing held in met_forcing to scratch dir + echo "move lfo_Nx+- met forcing from met_forcing to $SCRDIR" + /bin/mv $EXPDIR/input/met_forcing/*lfo_Nx+-*nc4 $SCRDIR/. endif endif From a9873c2fb461263b353e83db298e6d33257a9c3d Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Thu, 26 Oct 2023 14:43:23 -0400 Subject: [PATCH 171/308] more fixes for MODIS SCF reader (clsm_ensupd_read_obs.F90) --- .../clsm_ensupd_read_obs.F90 | 210 ++++++++++++------ 1 file changed, 148 insertions(+), 62 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index fe9da260..0234f9a2 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -4642,11 +4642,11 @@ subroutine read_obs_MODIS_SCF( & integer, parameter :: dtstep_assim_max = 21600 ! [seconds] avoid assim window spanning >=180 deg lon - real, parameter :: CMG_dlat = 0.05 ! [degrees] latitude spacing of MODIS CMG grid real, parameter :: CMG_dlon = 0.05 ! [degrees] longitude spacing of MODIS CMG grid + real, parameter :: CMG_dlat = 0.05 ! [degrees] latitude spacing of MODIS CMG grid - real, parameter :: CMG_ur_lat = 90. ! [degrees] upper-right latitude of MODIS CMG grid real, parameter :: CMG_ll_lon = -180. ! [degrees] lower-left longitude of MODIS CMG grid + real, parameter :: CMG_ur_lat = 90. ! [degrees] upper-right latitude of MODIS CMG grid character(7) :: MODIS_product_ID @@ -4657,7 +4657,7 @@ subroutine read_obs_MODIS_SCF( & real :: overpass_hour, tmp_delta, tmp_real, max_delta_lon - integer :: N_files, N_lon, N_lat, nn, kk, ind + integer :: N_files, N_lon, N_lat, N_tmp, nn, kk, ind integer :: N_CMG_obs, N_good_data, tmp_ind_start, tmp_ind_last type(date_time_type) :: date_time_beg, date_time_end @@ -4675,13 +4675,13 @@ subroutine read_obs_MODIS_SCF( & integer, dimension(2) :: N_lon_vec, year_vec, dofyr_vec, start_ind, last_ind - real, dimension(:), allocatable :: CMG_obs, CMG_lat, CMG_lon + real, dimension(:), allocatable :: CMG_obs, CMG_lon, CMG_lat integer, dimension(:), allocatable :: tmp_tile_num integer, dimension(N_catd) :: N_obs_in_tile - character(len=*), parameter :: Iam = 'read_obs_MODISscf' + character(len=*), parameter :: Iam = 'read_obs_MODIS_SCF' character(len=400) :: err_msg ! ---------------------------------------------------------------------------------- @@ -4809,7 +4809,7 @@ subroutine read_obs_MODIS_SCF( & N_files = 2 lon_min_vec(1) = lon_end_MODIS - lon_max_vec(1) = 180. + lon_max_vec(1) = 179.999 ! use 179.999 such that zero-based last_ind<=N_lon-1 (see below) year_vec( 1) = date_time_end_MODIS%year dofyr_vec( 1) = date_time_end_MODIS%dofyr @@ -4860,11 +4860,30 @@ subroutine read_obs_MODIS_SCF( & N_lon = sum( N_lon_vec(1:N_files) ) + + ! ! dbg ! ! write (*,*) '###############################################################################' + ! ! dbg ! ! write (*,*) Iam // '():' + ! ! dbg ! ! write (*,*) 'lon_min_vec = ', lon_min_vec + ! ! dbg ! ! write (*,*) 'lon_max_vec = ', lon_max_vec + ! ! dbg ! ! write (*,*) 'start_ind = ', start_ind + ! ! dbg ! ! write (*,*) 'last_ind = ', last_ind + ! ! dbg ! ! write (*,*) 'lat_min = ', lat_min + ! ! dbg ! ! write (*,*) 'lat_max = ', lat_max + ! ! dbg ! ! write (*,*) 'year_vec = ', year_vec + ! ! dbg ! ! write (*,*) 'dofyr_vec = ', dofyr_vec + ! ! dbg ! ! write (*,*) 'N_lon_vec = ', N_lon_vec + ! ! dbg ! ! write (*,*) 'N_lat = ', N_lat + ! ! dbg ! ! write (*,*) '###############################################################################' + + + ! allocate arrays for MODIS CMG data (max size that could possibly be needed for obs from both files) - allocate( CMG_obs(N_lon*N_lat) ) - allocate( CMG_lon(N_lon*N_lat) ) - allocate( CMG_lat(N_lon*N_lat) ) + N_tmp = N_lon*N_lat + + allocate( CMG_obs(N_tmp) ) + allocate( CMG_lon(N_tmp) ) + allocate( CMG_lat(N_tmp) ) ! read MODIS SCF obs @@ -5145,44 +5164,48 @@ subroutine read_MODIS_SCF_hdf( fname, lon_min, lon_max, lat_min, lat_max, & ! 1234567890123456789012 ! 1 2 - integer, parameter :: SCF_nodata = -9999. + integer, parameter :: SCF_nodata = -9999. - integer, parameter :: qc_snow_cover_max = 100 ! exclude lake ice, night, inland water, ocean, etc - integer, parameter :: qc_clear_index_min = 20 ! ensure sufficiently clear conditions - integer, parameter :: qc_snow_spatial_max = 2 ! screen for basic data quality (0=best, 1=good, 2=OK, 3=poor, 4=other) + integer(KIND=2), parameter :: qc_snow_cover_max = 100 ! exclude lake ice, night, inland water, ocean, etc + integer(KIND=2), parameter :: qc_clear_index_min = 20 ! ensure sufficiently clear conditions + integer(KIND=2), parameter :: qc_snow_spatial_max = 2 ! data quality (0=best, 1=good, 2=OK, 3=poor, 4=other) - integer, parameter :: DFACC_READ = 1 ! from hdf.inc + integer, parameter :: DFACC_READ = 1 ! from hdf.inc - integer, parameter :: uint8_min = 0 - integer, parameter :: uint8_max = 255 + integer, parameter :: uint8_min = 0 + integer, parameter :: uint8_max = 255 ! local variables - integer :: N_lat, N_lon, N_tmp, ii, jj, kk, nn + integer :: N_lon, N_lat, N_tmp, ii, jj, kk, nn - real, dimension(:), allocatable :: lat_c real, dimension(:), allocatable :: lon_c + real, dimension(:), allocatable :: lat_c - real, dimension(:), allocatable :: lat_ind real, dimension(:), allocatable :: lon_ind + real, dimension(:), allocatable :: lat_ind - integer, dimension(2) :: start, edge, stride, last + integer, dimension(2) :: start, edge, stride, last, dimsizes logical :: file_exists, keep_data integer :: status, sd_id, sds_id, sds_index - integer :: sfstart, sfn2index, sfselect + integer :: sfstart, sfn2index, sfselect, sfginfo integer :: sfrdata, sfendacc, sfend + character(64) :: sds_name + + integer :: rank, data_type, num_attrs + integer(KIND=2), dimension(:,:), allocatable :: Snow_Cover integer(KIND=2), dimension(:,:), allocatable :: Clear_Index integer(KIND=2), dimension(:,:), allocatable :: Snow_Spatial_QA character(1), dimension(:,:), allocatable :: tmp_char1 - character(len=*), parameter :: Iam = 'read_MODISscf_hdf' + character(len=*), parameter :: Iam = 'read_MODIS_SCF_hdf' character(len=400) :: err_msg ! ------------------------------------------------------------------------- @@ -5194,15 +5217,15 @@ subroutine read_MODIS_SCF_hdf( fname, lon_min, lon_max, lat_min, lat_max, & if (.not. file_exists ) then if (logit) then - write (logunit,*) trim(Iam), ': cannot find file ', trim(fname) - write (logunit,*) 'not reading MODIS SCF obs' + write (logunit,'(400A)') trim(Iam), ': cannot find file ', trim(fname) + write (logunit,* ) 'not reading MODIS SCF obs' end if return end if - ! ensure lat_* and lon_* inputs are within range + ! ensure lon_* and lat_* inputs are within range if ( (lon_min < CMG_ll_lon) .or. & (lon_max > CMG_ur_lon) .or. & @@ -5217,27 +5240,43 @@ subroutine read_MODIS_SCF_hdf( fname, lon_min, lon_max, lat_min, lat_max, & ! determine MODIS CMG array indices for requested lat/lon_min/max range ! MODIS CMG hdf files: - ! - lat-by-lon (!) + ! - lon-by-lat (NOTE: The metadata "s.Vgroup(1).Vgroup(1).SDS(1).Dims.Size" returned + ! by Matlab's hdfinfo() confusingly suggests that CMG files are + ! lat-by-lon, which is not the case!) ! - index values increase eastward and southward - start(1) = (CMG_ur_lat - lat_max )/CMG_dlat ! 0-based [as required for hdf read] - start(2) = (lon_min - CMG_ll_lon)/CMG_dlon ! 0-based [as required for hdf read] + start(1) = (lon_min - CMG_ll_lon)/CMG_dlon ! 0-based [as required for hdf read] + start(2) = (CMG_ur_lat - lat_max )/CMG_dlat ! 0-based [as required for hdf read] - last(1) = (CMG_ur_lat - lat_min )/CMG_dlat ! 0-based [as required for hdf read] - last(2) = (lon_max - CMG_ll_lon)/CMG_dlon ! 0-based [as required for hdf read] + last(1) = (lon_max - CMG_ll_lon)/CMG_dlon ! 0-based [as required for hdf read] + last(2) = (CMG_ur_lat - lat_min )/CMG_dlat ! 0-based [as required for hdf read] - N_lat = last(1) - start(1) + 1 - N_lon = last(2) - start(2) + 1 + N_lon = last(1) - start(1) + 1 + N_lat = last(2) - start(2) + 1 - edge(1) = N_lat - edge(2) = N_lon + edge(1) = N_lon + edge(2) = N_lat stride(1) = 1 stride(2) = 1 + + + ! ! dbg ! ! write (*,*) '###############################################################################' + ! ! dbg ! ! write (*,*) Iam // '():' + ! ! dbg ! ! write (*,*) 'size(MODIS_SCF), N_lon, N_lat = ', size(MODIS_SCF), N_lon, N_lat + ! ! dbg ! ! write (*,*) 'lon_min, lon_max = ', lon_min, lon_max + ! ! dbg ! ! write (*,*) 'lat_min, lat_max = ', lat_min, lat_max + ! ! dbg ! ! write (*,*) 'start [lon, lat] = ', start + ! ! dbg ! ! write (*,*) 'last [lon, lat] = ', last + ! ! dbg ! ! write (*,*) 'edge [lon, lat] = ', edge + ! ! dbg ! ! write (*,*) '###############################################################################' + + + ! checks array dimensions - N_tmp = N_lat*N_lon + N_tmp = N_lon*N_lat if ( (N_tmp /= size(MODIS_lon)) .or. & (N_tmp /= size(MODIS_lat)) .or. & @@ -5250,10 +5289,10 @@ subroutine read_MODIS_SCF_hdf( fname, lon_min, lon_max, lat_min, lat_max, & ! check array bounds - if ( ( start(1) < 0 ) .or. ( start(1) > CMG_N_lat - 1 ) .or. & - ( start(2) < 0 ) .or. ( start(2) > CMG_N_lon - 1 ) .or. & - ( last( 1) < 0 ) .or. ( last( 1) > CMG_N_lat - 1 ) .or. & - ( last( 2) < 0 ) .or. ( last( 2) > CMG_N_lon - 1 ) .or. & + if ( ( start(1) < 0 ) .or. ( start(1) > CMG_N_lon - 1 ) .or. & + ( start(2) < 0 ) .or. ( start(2) > CMG_N_lat - 1 ) .or. & + ( last( 1) < 0 ) .or. ( last( 1) > CMG_N_lon - 1 ) .or. & + ( last( 2) < 0 ) .or. ( last( 2) > CMG_N_lat - 1 ) .or. & ( start(1) > last(1) ) .or. ( start(2) > last(2) ) & ) then @@ -5263,37 +5302,37 @@ subroutine read_MODIS_SCF_hdf( fname, lon_min, lon_max, lat_min, lat_max, & end if if (logit) then - write (logunit,*) trim(Iam), ': reading MODIS SCF obs from ', trim(fname) - write (logunit,*) 'N_lon, N_lat, lon_min, lon_max, lat_min, lat_max = ', & - N_lon, N_lat, lon_min, lon_max, lat_min, lat_max + write (logunit,'(400A)') trim(Iam), '(): reading MODIS SCF obs from ', trim(fname) + write (logunit,* ) ' N_lon, N_lat, lon_min, lon_max, lat_min, lat_max = ' + write (logunit,* ) N_lon, N_lat, lon_min, lon_max, lat_min, lat_max end if ! allocate arrays - allocate(lat_c( N_lat)) allocate(lon_c( N_lon)) + allocate(lat_c( N_lat)) - allocate(lat_ind(N_lat)) allocate(lon_ind(N_lon)) + allocate(lat_ind(N_lat)) - allocate(Snow_Cover (N_lat,N_lon)) ! lat-by-lon !! - allocate(Clear_Index (N_lat,N_lon)) ! lat-by-lon !! - allocate(Snow_Spatial_QA(N_lat,N_lon)) ! lat-by-lon !! + allocate(Snow_Cover (N_lon,N_lat)) + allocate(Clear_Index (N_lon,N_lat)) + allocate(Snow_Spatial_QA(N_lon,N_lat)) - allocate(tmp_char1( N_lat,N_lon)) ! lat-by-lon !! + allocate(tmp_char1( N_lon,N_lat)) ! -------------------------- ! determine center lat/lon of CMG cells - lat_ind = (/(jj, jj=0, N_lat-1, 1)/) ! =0:(N_lat-1) lon_ind = (/(ii, ii=0, N_lon-1, 1)/) ! =0:(N_lon-1) + lat_ind = (/(jj, jj=0, N_lat-1, 1)/) ! =0:(N_lat-1) ! lat_c, lon_c are lat/lon at center of CMG grid cell - lat_c = CMG_ur_lat - 0.5*CMG_dlat - (start(1)+lat_ind)*CMG_dlat - lon_c = CMG_ll_lon + 0.5*CMG_dlon + (start(2)+lon_ind)*CMG_dlon + lon_c = CMG_ll_lon + 0.5*CMG_dlon + (start(1)+lon_ind)*CMG_dlon + lat_c = CMG_ur_lat - 0.5*CMG_dlat - (start(2)+lat_ind)*CMG_dlat ! -------------------------- @@ -5314,6 +5353,24 @@ subroutine read_MODIS_SCF_hdf( fname, lon_min, lon_max, lat_min, lat_max, & sds_index = sfn2index( sd_id, trim(field_names(nn)) ) sds_id = sfselect( sd_id, sds_index ) + + + status = sfginfo( sds_id, sds_name, rank, dimsizes, data_type, num_attrs ) + + if ( (dimsizes(1)/=CMG_N_lon) .or. (dimsizes(2)/=CMG_N_lat) ) then + + err_msg = 'dimensions in hdf file doe not match CMG_N_lon and/or CMG_N_lat' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + + end if + + + ! ######################################################### + ! ! dbg ! ! write (*,*) 'sds_name = ', trim(sds_name) + ! ! dbg ! ! write (*,*) 'rank, data_type, num_attrs = ', rank, data_type, num_attrs + ! ! dbg ! ! write (*,*) 'dimsizes = ', dimsizes + ! ######################################################### + select case (nn) @@ -5325,12 +5382,42 @@ subroutine read_MODIS_SCF_hdf( fname, lon_min, lon_max, lat_min, lat_max, & end select + if (status/=0) then + + err_msg = 'error reading data from hdf file: ' // trim(fname) + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + + end if + status = sfendacc(sds_id) ! terminate access to SDS (field) end do status = sfend(sd_id) ! close hdf file and SD interface + + ! ################################################################################# + ! ! dbg ! ! write (*,*) 'Snow_Cover(1:10,1:5)=' + ! ! dbg ! ! write (*,*) Snow_Cover(1:10,1:5) + ! ! dbg ! ! write (*,*) 'Clear_Index(1:10,1:5)=' + ! ! dbg ! ! write (*,*) Clear_Index(1:10,1:5) + ! ! dbg ! ! write (*,*) 'Snow_Spatial_QA(1:10,1:5)=' + ! ! dbg ! ! write (*,*) Snow_Spatial_QA(1:10,1:5) + + ! ! dbg ! ! !if ( (lon_min>-138) .and. (lon_min<-134) ) then + ! ! dbg ! ! if (.false.) then + ! ! dbg ! ! do jj=1,N_lat + ! ! dbg ! ! write(997) Snow_Cover( jj,:) + ! ! dbg ! ! write(998) Clear_Index( jj,:) + ! ! dbg ! ! write(999) Snow_Spatial_QA(jj,:) + ! ! dbg ! ! end do + ! ! dbg ! ! write (*,*) 'stopping after file dump ' + ! ! dbg ! ! stop + ! ! dbg ! ! end if + ! ################################################################################# + + + ! check range (make sure uint8 from hdf file is correctly translated into Fortran integer) if ( any(Snow_Cover < uint8_min) .or. & @@ -5355,27 +5442,27 @@ subroutine read_MODIS_SCF_hdf( fname, lon_min, lon_max, lat_min, lat_max, & kk = 0 ! initialize counter for "good" data - do jj=1,N_lat - do ii=1,N_lon + do ii=1,N_lon + do jj=1,N_lat ! note: Snow_Cover >= 0 per range check above, no need to check for minimum keep_data = & - (Snow_Cover( jj,ii) <= qc_snow_cover_max ) .and. & ! 0<=SCF<=100 (1) - (Clear_Index( jj,ii) > qc_clear_index_min ) .and. & ! sufficiently clear sky (2) - (Snow_Spatial_QA(jj,ii) < qc_snow_spatial_max) ! keep "best", "good", or "OK" quality (3) + (Snow_Cover( ii,jj) <= qc_snow_cover_max ) .and. & ! 0<=SCF<=100 (1) + (Clear_Index( ii,jj) > qc_clear_index_min ) .and. & ! sufficiently clear sky (2) + (Snow_Spatial_QA(ii,jj) <= qc_snow_spatial_max) ! keep "best", "good", or "OK" quality (3) ! (1) excludes "lake ice", "night", "inland water", "ocean", "cloud obscured water", "data not mapped", "fill" ! (2) clear_index>100 already removed via qc_snow_cover_max ! (3) excludes Antarctica - + if (keep_data) then kk = kk + 1 - + ! raw SCF value is for clear portion of grid cell only, need to normalize with Clear_Index - MODIS_SCF(kk) = real(Snow_Cover(jj,ii))/real(Clear_Index(jj,ii)) + MODIS_SCF(kk) = real(Snow_Cover(ii,jj))/real(Clear_Index(ii,jj)) MODIS_lon(kk) = lon_c(ii) MODIS_lat(kk) = lat_c(jj) @@ -5388,8 +5475,7 @@ subroutine read_MODIS_SCF_hdf( fname, lon_min, lon_max, lat_min, lat_max, & N_good_data = kk if (logit) write (logunit,*) 'N_good_data = ', N_good_data - - + deallocate(lat_c) deallocate(lon_c) @@ -8027,7 +8113,7 @@ subroutine read_obs( & end if - case ('MODIS_SCF') + case ('MOD10C1','MYD10C1') call read_obs_MODIS_SCF( & date_time, dtstep_assim, N_catd, tile_coord, & From c4719c440b2c589386ae6cd23bcf43d286964aed Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Thu, 26 Oct 2023 14:53:20 -0400 Subject: [PATCH 172/308] change FOV for MODIS SCF obs back to 0. (LDASsa_DEFAULT_inputs_ensupd.nml) --- src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml b/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml index 187413a3..f50487bb 100644 --- a/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml +++ b/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml @@ -1162,7 +1162,7 @@ obs_param_nml(25)%orbit = 2 obs_param_nml(25)%pol = 0 obs_param_nml(25)%N_ang = 0 obs_param_nml(25)%freq = 0. -obs_param_nml(25)%FOV = 0.025 +obs_param_nml(25)%FOV = 0. obs_param_nml(25)%FOV_units = 'deg' obs_param_nml(25)%assim = .false. obs_param_nml(25)%scale = .false. From 4bce2dd42cf134565d153e8da4a0ff1bce42e27e Mon Sep 17 00:00:00 2001 From: Rolf Reichle <54944691+gmao-rreichle@users.noreply.github.com> Date: Thu, 26 Oct 2023 19:17:28 -0400 Subject: [PATCH 173/308] minimal edit in echo string (lenkf.j.template) --- src/Applications/LDAS_App/lenkf.j.template | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Applications/LDAS_App/lenkf.j.template b/src/Applications/LDAS_App/lenkf.j.template index 455abe4f..11a1ddfb 100644 --- a/src/Applications/LDAS_App/lenkf.j.template +++ b/src/Applications/LDAS_App/lenkf.j.template @@ -131,7 +131,7 @@ if ( $LADAS_COUPLING == 1 ) then else # move central-simulation forcing held in met_forcing to scratch dir - echo "move lfo_Nx+- met forcing from met_forcing to $SCRDIR" + echo "move lfo_Nx+- met forcing from $EXPDIR/input/met_forcing to $SCRDIR" /bin/mv $EXPDIR/input/met_forcing/*lfo_Nx+-*nc4 $SCRDIR/. endif From c098c87e2aa41b09f593c37672ad2e5841223545 Mon Sep 17 00:00:00 2001 From: Weiyuan Jiang Date: Fri, 27 Oct 2023 11:04:13 -0400 Subject: [PATCH 174/308] change according to the change in remap_restarts packge --- src/Applications/LDAS_App/CMakeLists.txt | 2 +- src/Applications/LDAS_App/ldas_setup | 21 ++----------------- .../{process_rst.py => remap_config_ldas.py} | 6 +++--- 3 files changed, 6 insertions(+), 23 deletions(-) rename src/Applications/LDAS_App/{process_rst.py => remap_config_ldas.py} (92%) diff --git a/src/Applications/LDAS_App/CMakeLists.txt b/src/Applications/LDAS_App/CMakeLists.txt index f2f5ed36..d295dfc7 100644 --- a/src/Applications/LDAS_App/CMakeLists.txt +++ b/src/Applications/LDAS_App/CMakeLists.txt @@ -22,7 +22,7 @@ ecbuild_add_executable ( set (scripts ldas_setup process_hist.csh - process_rst.py + remap_config_ldas.py ens_forcing/average_ensemble_forcing.py ens_forcing/ensemble_forc.py ens_forcing/regrid_forc.csh diff --git a/src/Applications/LDAS_App/ldas_setup b/src/Applications/LDAS_App/ldas_setup index 0207e634..6da9a7d8 100755 --- a/src/Applications/LDAS_App/ldas_setup +++ b/src/Applications/LDAS_App/ldas_setup @@ -812,7 +812,7 @@ class LDASsetup: self.rqdExeInp['RESTART_ID'] + \ '/output/'+self.rqdExeInp['RESTART_DOMAIN']+'/rc_out/' - # pass into process_rst + # pass into remap_config_ldas sponsorid = self.rqdRmInp['account'] exp_id = self.rqdExeInp['EXP_ID'] exp_dir = self.exphome @@ -836,9 +836,6 @@ class LDASsetup: os.symlink(_seeds, myRstDir+ '/landassim_obspertrseed'+ _ensid +'_rst') self.has_landassim_seed = True mk_outdir = self.exphome+'/'+exp_id+'/mk_restarts/' - #cmd= ' '.join(['./process_rst.csh', sponsorid, exp_id, mk_outdir, - # out_bcdir, out_tilefile, self.catch, RESTART_str, YYYYMMDDHH, - # self.in_rstfile, self.in_tilefile, dzsf, wemin_in, wemin_out]) if (RESTART_str != '1'): remap_tpl = os.path.dirname(os.path.realpath(__file__)) + '/remap_params.tpl' @@ -858,7 +855,7 @@ class LDASsetup: config['output']['shared']['out_dir'] = mk_outdir config['output']['surface']['catch_remap'] = True config['output']['surface']['catch_tilefile'] = self.rqdExeInp['TILING_FILE'] - config['output']['shared']['bcs_dir'] = self.bcs_geom + config['output']['shared']['bcs_dir'] = self.bcs_land config['output']['shared']['expid'] = self.rqdExeInp['EXP_ID'] config['output']['surface']['surflay'] = dzsf config['output']['surface']['wemin'] = wemin_out @@ -868,20 +865,6 @@ class LDASsetup: catch_obj = catchANDcn(config_obj = config) catch_obj.remap() - #print "cmd: " + cmd - #os.system(cmd) - - #done_rst=self.exphome+'/'+exp_id+'/mk_restarts/done_rst_file' - #print "Please hold on for a while until the restart file is created ....." - #_animation = "|/-\\" - #_idx = 0 - #while not os.path.isfile(done_rst): - # sys.stdout.write('\r'+_animation[_idx % len(_animation)]) - # sys.stdout.flush() - # _idx += 1 - # time.sleep(1.) - - #for ens in self.ensdirs : catchRstFile0 = '' vegdynRstFile0 = '' diff --git a/src/Applications/LDAS_App/process_rst.py b/src/Applications/LDAS_App/remap_config_ldas.py similarity index 92% rename from src/Applications/LDAS_App/process_rst.py rename to src/Applications/LDAS_App/remap_config_ldas.py index a3ebd194..8b990a38 100644 --- a/src/Applications/LDAS_App/process_rst.py +++ b/src/Applications/LDAS_App/remap_config_ldas.py @@ -16,7 +16,7 @@ def remap_config_ldas(config, RESTART_str, RESTART_PATH, RESTART_ID): config['input']['shared'] = merra2_expid(config['input']['shared']) config['input']['shared']['rst_dir'] = out_dir+ '/merra2_tmp_'+ yyyymmddhh config['input']['surface']['wemin'] = 26 - config['input']['shared']['bcs_dir'] = '/discover/nobackup/projects/gmao/bcs_shared/legacy_bcs/Ganymed-4_0/Ganymed-4_0_MERRA-2/CF0180x6C_DE1440xPE0720/' + config['input']['shared']['bcs_dir'] = '/discover/nobackup/projects/gmao/bcs_shared/fvInput/ExtData/esm/tiles/GM4/land/CF0180x6C_DE1440xPE0720/' if RESTART_str == "G" : # WY note: it is a bad idea to overload restart_path and restart_id @@ -39,7 +39,7 @@ def remap_config_ldas(config, RESTART_str, RESTART_PATH, RESTART_ID): print( " Please select RESTART: M and use MERRA-2, instead.") sys.exit(1) - config['input']['shared']['bcs_dir'] = '/discover/nobackup/projects/gmao/bcs_shared/legacy_bcs/Icarus/Icarus_Ostia/CF0720x6C_CF0720x6C/' + config['input']['shared']['bcs_dir'] = '/discover/nobackup/projects/gmao/bcs_shared/fvInput/ExtData/esm/tiles/ICA/land/CF0720x6C_CF0720x6C/' config['input']['surface']['wemin'] = 26 config['input']['shared']['rst_dir'] = out_dir+'/InData'+ '/' suffix = '_21z.tar' @@ -47,7 +47,7 @@ def remap_config_ldas(config, RESTART_str, RESTART_PATH, RESTART_ID): if ((date_16 <= expdate) and (expdate < date_17)): fpver = 'GEOS-5.16/GEOSadas-5_16/' fplab = 'f516_fp' - config['input']['shared']['bcs_dir'] = '/discover/nobackup/projects/gmao/bcs_shared/legacy_bcs/Ganymed-4_0/Ganymed-4_0_Ostia/CF0720x6C_DE2880xPE1440/' + config['input']['shared']['bcs_dir'] = '/discover/nobackup/projects/gmao/bcs_shared/fvInput/ExtData/esm/tiles/GM4/land/CF0720x6C_DE2880xPE1440/' suffix = '_21z.bin' if ((date_17 <= expdate) and (expdate < date_21)): From 43455e5251ebb349d0c8ec8018a71e60f11ca70a Mon Sep 17 00:00:00 2001 From: amfox37 Date: Fri, 27 Oct 2023 12:48:53 -0400 Subject: [PATCH 175/308] add latlon grid clim stats matlab scripts --- ...get_model_and_obs_clim_stats_latlon_grid.m | 108 +++ ..._model_and_obs_clim_stats_pentads_latlon.m | 127 --- ...get_model_and_obs_clim_stats_latlon_grid.m | 344 ++++++++ ..._model_and_obs_clim_stats_pentads_latlon.m | 736 ------------------ .../obs_scaling_params/write_netcdf_file.m | 189 ----- .../write_netcdf_file_2D_grid.m | 266 ------- .../write_netcdf_latlon_grid.m | 222 ++++++ .../clsm_ensupd_read_obs.F90 | 24 +- 8 files changed, 688 insertions(+), 1328 deletions(-) create mode 100644 src/Applications/LDAS_App/util/inputs/obs_scaling_params/Run_get_model_and_obs_clim_stats_latlon_grid.m delete mode 100644 src/Applications/LDAS_App/util/inputs/obs_scaling_params/Run_get_model_and_obs_clim_stats_pentads_latlon.m create mode 100644 src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats_latlon_grid.m delete mode 100644 src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats_pentads_latlon.m delete mode 100644 src/Applications/LDAS_App/util/inputs/obs_scaling_params/write_netcdf_file.m delete mode 100644 src/Applications/LDAS_App/util/inputs/obs_scaling_params/write_netcdf_file_2D_grid.m create mode 100644 src/Applications/LDAS_App/util/inputs/obs_scaling_params/write_netcdf_latlon_grid.m diff --git a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/Run_get_model_and_obs_clim_stats_latlon_grid.m b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/Run_get_model_and_obs_clim_stats_latlon_grid.m new file mode 100644 index 00000000..826b4737 --- /dev/null +++ b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/Run_get_model_and_obs_clim_stats_latlon_grid.m @@ -0,0 +1,108 @@ +clear + +% addpath('../../shared/matlab/'); +addpath('/discover/nobackup/amfox/current_GEOSldas/GEOSldas/src/Applications/LDAS_App/util/shared/matlab') + +% ------------------------------------------------------------------- +% Begin user-defined inputs +% ------------------------------------------------------------------- + +% Define the Open Loop experiment path, run name, domain, and output prefix + +exp_path = '/discover/nobackup/amfox/Experiments/OLv7_M36_ascat'; +exp_run = {'OLv7_M36_ascat'}; +domain = 'SMAP_EASEv2_M36_GLOBAL'; +prefix_out = 'M36_zscore_stats_'; + +% Define the Open Loop experiment start and end dates + +start_month = 4; +start_year = 2015; +end_month = 3; +end_year = 2021; + +% Define the species names + +species_names = {'ASCAT_META_SM','ASCAT_METB_SM','ASCAT_METC_SM'}; + +% Define whether to combine species + +combine_species_stats = 1; % 1 to combine all species into single set of statistics + +% Define the grid resolution (degrees) + +grid_resolution = 0.25; + +% Define moving window size over which statistics are calculated, +% and minimum number of data points required to calculate statistics + +w_days = 75; +Ndata_min = 5; + +% Define the assimilation time step and initial time + +dt_assim = 3*60*60; +t0_assim = 0; + +% Define print intervals + +print_each_DOY = 1; +print_each_pentad = 0; +print_all_pentads = 1; + +% Define output directory (takes form "domain"/stats/"out_dir") +out_dir = 'z_score_clim_quarter_degree'; + +% ------------------------------------------------------------------- +% End user-defined inputs +% ------------------------------------------------------------------- + +% Define the months to run over, 1:12, plus a number of months required to complete the window +run_months = [1:12 1:ceil(w_days/30)]; + +% Calculate the earliest and latest years for each month in the experiment +earliest_year = zeros(length(run_months),1); +latest_year = zeros(length(run_months),1); + +cnt = 0; +for month = run_months + % Initialize the earliest and latest year variables + cnt = cnt + 1; + + % Check if the current year/month combination is earlier than the earliest + if datenum(start_year, month, 1) < datenum(start_year, start_month, 1) + earliest_year(cnt) = start_year+1; + else + earliest_year(cnt) = start_year; + end + + % Check if the current year/month combination is later than the latest + if datenum(end_year, month, 1) > datenum(end_year, end_month,1) + latest_year(cnt) = end_year-1; + else + latest_year(cnt) = end_year; + end +end + +obs_param_fname = [exp_path, '/', exp_run{1}, '/output/', domain, '/rc_out/', ... + '/Y2016/M04/',exp_run{1}, '.ldas_obsparam.20160401_0000z.txt']; + +[N_obs_param, obs_param ] = read_obsparam(obs_param_fname); + +species =[]; + +for i = 1:length(species_names) + add_species = obs_param(strcmp(species_names(i),{obs_param.descr})).species; + species = union(species,add_species); +end + +if combine_species_stats + disp('Calculating stats by combining multiple species'); +end + +% Calculate the climatology statistics + +get_model_and_obs_clim_stats_latlon_grid( species_names, run_months, exp_path, exp_run{1}, domain, earliest_year, ... + latest_year, dt_assim, t0_assim, species, combine_species_stats, ... + grid_resolution, w_days, Ndata_min, prefix_out, print_each_DOY, ... + print_each_pentad, print_all_pentads, out_dir ); diff --git a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/Run_get_model_and_obs_clim_stats_pentads_latlon.m b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/Run_get_model_and_obs_clim_stats_pentads_latlon.m deleted file mode 100644 index dc3c62f8..00000000 --- a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/Run_get_model_and_obs_clim_stats_pentads_latlon.m +++ /dev/null @@ -1,127 +0,0 @@ -% Calculate scaling files for ASCAT wetness fraction -% -% GDL, 11 Sep 2012 -% QLiu, Dec 2016 -% AMF April 2023 - -%===================================================================== - -clear - -% add path to matlab functions in src/Applications/LDAS_App/util/shared/matlab/ -addpath('../../shared/matlab/'); - -%====== - run_months = [1:12 1:4]; %loop through 1:4 again to get complete pentads - -exp_path = '/discover/nobackup/amfox/Experiments/ASCAT_noscale_test_debug'; -exp_run = {'ASCAT_M36'}; -domain = 'SMAP_EASEv2_M36_GLOBAL'; - -%Start and end year for each month -start_year = [repmat(2016,1,6) repmat(2015,1,6) repmat(2016,1,4)]; %corresp to [1:12 1 2] -end_year = [repmat(2017,1,6) repmat(2016,1,6) repmat(2017,1,4)]; %runs till end of run_months for end_year - -prefix_out = 'M36_zscore_stats_'; - -dt_assim = 3*60*60; % [seconds] land analysis time step, - % same as LANDASSIM_DT in GEOSldas) -t0_assim = 0; % [seconds] land analysis "reference" time (offset from 0z), - % same as LANDASSIM_T0 in GEOSldas (except for units), - % typically 0 in offline runs and 1.5*60*60 in LADAS - -%====== - -obs_param_fname = [exp_path, '/', exp_run{1}, '/output/', domain, '/rc_out/', ... - '/Y2016/M04/',exp_run{1}, '.ldas_obsparam.20160401_0000z.txt']; - -% List species to use here -species_names = {'ASCAT_META_SM_A','ASCAT_META_SM_D','ASCAT_METB_SM_A','ASCAT_METB_SM_D'}; - -% Decide here if we're combining statitics across multiple species -combine_species_stats = 1; % Calculate combined statistics for all species in species_names if set to 1. - -if combine_species_stats - disp('Calculating stats by combining muiltiple species'); -end - -%Spatial sampling -hscale = 0.0; % degrees lat/lon - -% Temporal sampling window(days), current hard coded and need to be divisive by 5 and be an odd number -w_days = 75; - -Ndata_min = 5; - -%To limit M09 tiles to administering M36 tiles only (smaller files), -%provide convert_grid -if isempty(strfind(prefix_out,'M09')) - convert_grid='EASEv2_M36'; -end - -if (mod(w_days,10) == 0) - disp('w_days should be 5, 15, 25, 35, ...') - error('Need an odd number of pentads |xxxxx|xxXxx|xxxxx|') -end -if (mod(w_days, 5) > 0) - error('Aiming at pentad files') -end - -% ------------------------------------------------------------------------ - -[N_obs_param, obs_param ] = read_obsparam(obs_param_fname); - -species =[]; - -for i = 1:length(species_names) - add_species = obs_param(strcmp(species_names(i),{obs_param.descr})).species; - species = union(species,add_species); -end - -species -% ------------------ - -for n=1:length(exp_run) - if (exist('convert_grid','var')) - if exist('time_of_day_in_hours','var') - for j=1:length(time_of_day_in_hours) - for k=1:length(run_months) - get_model_and_obs_clim_stats_pentads_latlon( species_names, ... - run_months{k}, exp_path, exp_run{n}, domain, ... - start_year, end_year, ... - dt_assim, t0_assim, species, combine_species_stats, obs_param, ... - hscale, w_days, Ndata_min, prefix_out,... - convert_grid, time_of_day_in_hours(j) ); - end - end - else - get_model_and_obs_clim_stats_pentads_latlon( species_names, ... - run_months, exp_path, exp_run{n}, domain, start_year, end_year, ... - dt_assim, t0_assim, species, combine_species_stats, obs_param, ... - hscale, w_days, Ndata_min, prefix_out,... - convert_grid ); - end - else - if exist('time_of_day_in_hours','var') - for j=1:length(time_of_day_in_hours) - for k=1:length(run_months) - get_model_and_obs_clim_stats_pentads_latlon( species_names,... - run_months{k}, exp_path, exp_run{n}, domain,... - start_year, end_year, ... - dt_assim, t0_assim, species, combine_species_stats, obs_param, ... - hscale, w_days, Ndata_min, prefix_out,... - time_of_day_in_hours(j) ); - end - end - else - get_model_and_obs_clim_stats_pentads_latlon( species_names, ... - run_months, exp_path, exp_run{n}, domain, start_year, end_year, ... - dt_assim, t0_assim, species, combine_species_stats, obs_param, ... - hscale, w_days, Ndata_min, prefix_out); - end - end -end - -% ============= EOF ==================================================== - - diff --git a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats_latlon_grid.m b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats_latlon_grid.m new file mode 100644 index 00000000..ba3012b5 --- /dev/null +++ b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats_latlon_grid.m @@ -0,0 +1,344 @@ + +function [] = get_model_and_obs_clim_stats_latlon_grid( species_names, ... + run_months, exp_path, exp_run, domain, start_year, end_year, ... + dt_assim, t0_assim, species, combine_species_stats, ... + resol, w_days, Ndata_min, prefix, print_each_DOY, ... + print_each_pentad, print_all_pentads,out_dir ) +% +% get_model_and_obs_clim_stats.m +% +% Compute mean, stdv of model and observations from tile-based +% "innov" files for a selection of species. +% +% The main purpose of this function is to aggregate the information +% from the "innov" files so that the climatology statistics can +% be used in scaling of the observations before assimilation. +% +% One file with statistics is generated for every DOY (1,...,365). +% The temporal smoothing/averaging window (w_days) is given in days. +% +% We calcualte the bias correction factors and write on a regular 0.25 degree +% lat/lon grid as there is no regular grid for ASCAT observations +% +% ------------------------------------------------------------------- +% begin user-defined inputs +% ------------------------------------------------------------------- + +nodata = -9999; +nodata_tol = 1e-4; +overwrite = 1; +Nf = 7; +N_pentads = 73; + +disp('ASSUMING ACAT observations/undefined observation grid'); +disp(['Calculating scaling parameters on grid with resolution = ', num2str(resol) , ' degrees']); + +if combine_species_stats + N_species = 1; +else + N_species = length(species); +end + +inpath = [ exp_path, '/', exp_run, '/output/', domain ]; + +outpath = [ inpath, '/stats/', out_dir ]; + +% create outpath if it doesn't exist +if ~exist(outpath, 'dir') + mkdir(outpath); +end + +% assemble output file name +ind = start_year == min(start_year); +mi_m = min(run_months(ind)); +ind = end_year == max(end_year); +ma_m = max(run_months(ind)); + +D(1) = 1; +P(1) = 1; +if mi_m > 1 + D(1) = sum(days_in_month(2014, 1:mi_m-1)) + 1; + P(1) = ceil(D(1) / 5); +end +D(2) = sum(days_in_month(2014, 1:ma_m)); +P(2) = floor(D(2) / 5); + +fname_out_base_d = [outpath, '/', prefix, ... + num2str(min(start_year)), '_doy', num2str(D(1)), '_', ... + num2str(max(end_year)), '_doy', num2str(D(2)), ... + '_W_', num2str(w_days), 'd_Nmin_', num2str(Ndata_min)]; + +fname_out_base_p = [outpath, '/', prefix, ... + num2str(min(start_year)), '_p', num2str(P(1)), '_', ... + num2str(max(end_year)), '_p', num2str(P(2)), ... + '_W_', num2str(round(w_days/5)), 'p_Nmin_', num2str(Ndata_min)]; + +%====================================================== + +% Define 1/4 degree lat/lon grid +% Define lower-left corner coordinates and grid cell size +ll_lon = -180; +ll_lat = -90; + +d_lon = resol; +d_lat = resol; + +% Calculate number of longitude and latitude grid cells +n_lon = round(360/ d_lon); +n_lat = round(180 / d_lat); + +% Calculate longitude and latitude values for the grid +ll_lons = linspace(ll_lon, ll_lon + (n_lon-1)*d_lon, n_lon); +ll_lats = linspace(ll_lat, ll_lat + (n_lat-1)*d_lat, n_lat); + +% Create grid index +obsnum = (1:n_lon*n_lat)'; +[i_out, j_out] = ind2sub([n_lon, n_lat], obsnum); +lon_out = ll_lons(i_out)'; +lat_out = ll_lats(j_out)'; +N_gridcells = length(obsnum); + +% initialize output statistics +o_data_sum = NaN(N_species, N_gridcells, w_days); +m_data_sum = NaN(N_species, N_gridcells, w_days); +o_data_sum2 = NaN(N_species, N_gridcells, w_days); +m_data_sum2 = NaN(N_species, N_gridcells, w_days); +m_data_min = NaN(N_species, N_gridcells, w_days); +m_data_max = NaN(N_species, N_gridcells, w_days); +N_data = NaN(N_species, N_gridcells, w_days); + +data_out = NaN(N_species, Nf, N_gridcells, N_pentads); +data2D = NaN(Nf, N_gridcells); + +% ------------------------------------------------------------- + +% make sure t0_assim is *first* analysis time in a day + +t0_assim = mod( t0_assim, dt_assim ); + +count = 0; + +for imonth = 1:length(run_months) + + month = run_months(imonth); + + for day = 1:days_in_month( 2014, month) %2014 = random non-leap year + + if count < w_days + count = count + 1; + else + count = w_days; + end + + for seconds_in_day = t0_assim:dt_assim:(86400-1) + + hour = floor(seconds_in_day/3600); + minute = floor((seconds_in_day-hour*3600)/60); + seconds = seconds_in_day-hour*3600-minute*60; + + if (seconds ~= 0) + input('something is wrong! Ctrl-c now') + end + + for year = start_year(imonth):end_year(imonth) + + YYYYMMDD = [num2str(year, '%4.4d'), num2str(month, '%2.2d'), num2str(day, '%2.2d')]; + HHMM = [num2str(hour, '%2.2d'), num2str(minute, '%2.2d')]; + + % read innov files + fname = [inpath, '/ana/ens_avg/', 'Y', YYYYMMDD(1:4), '/', 'M', YYYYMMDD(5:6), '/', exp_run, '.ens_avg.ldas_ObsFcstAna.', YYYYMMDD, '_', HHMM, 'z.bin']; + ifp = fopen(fname, 'r', 'l'); + + if (ifp > 0) % Proceed only if file exists + fclose(ifp); + [date_time, obs_assim, obs_species, obs_tilenum, obs_lon, obs_lat, obs_obs, obs_obsvar, obs_fcst, obs_fcstvar, obs_ana, obs_anavar] = read_ObsFcstAna(fname); + + % remove tiles when there is no obs_fcst (obs_fcst == 0 in innov output when missing) + idx = find(obs_fcst == 0); + obs_assim(idx) = []; + obs_species(idx) = []; + obs_tilenum(idx) = []; + obs_lon(idx) = []; + obs_lat(idx) = []; + obs_obs(idx) = []; + obs_obsvar(idx) = []; + obs_fcst(idx) = []; + obs_fcstvar(idx) = []; + obs_ana(idx) = []; + obs_anavar(idx) = []; + + % extract species of interest + ind = []; + for scnt = 1:N_species + + if combine_species_stats + ind = find(ismember(obs_species, species)); + else + this_species = species(scnt); + ind = find(obs_species == this_species); + end + + if ~isempty(ind) + obs_tilenum_i = obs_tilenum(ind); + obs_obs_i = obs_obs(ind); + obs_fcst_i = obs_fcst(ind); + obs_lon_i = obs_lon(ind); + obs_lat_i = obs_lat(ind); + + % Check if any location receives more than 1 obs (or 1 species) + tmp = sort(obs_tilenum_i); + same_tile = find(diff(tmp) == 0, 1); + if ~isempty(same_tile) && ~combine_species_stats + error('multiple obs of the same species at one location? - only last one in line is used'); + end + + % Put obs lat/lon on our grid and figure out obsnum/grid index + i_idx = floor((obs_lon_i - ll_lon) / d_lon) + 1; + j_idx = floor((obs_lat_i - ll_lat) / d_lat) + 1; + [~, obs_idx] = ismember([i_idx, j_idx], [i_out, j_out], 'rows'); + obs_i = obsnum(obs_idx); + + o_data_sum(scnt, obs_i, count) = nansum([o_data_sum(scnt, obs_i, count); obs_obs_i']); + m_data_sum(scnt, obs_i, count) = nansum([m_data_sum(scnt, obs_i, count); obs_fcst_i']); + o_data_sum2(scnt, obs_i, count) = nansum([o_data_sum2(scnt, obs_i, count); obs_obs_i'.^2]); + m_data_sum2(scnt, obs_i, count) = nansum([m_data_sum2(scnt, obs_i, count); obs_fcst_i'.^2]); + m_data_min(scnt, obs_i, count) = min([m_data_min(scnt, obs_i, count); obs_fcst_i']); + m_data_max(scnt, obs_i, count) = max([m_data_max(scnt, obs_i, count); obs_fcst_i']); + N_data(scnt, obs_i, count) = nansum([N_data(scnt, obs_i, count); ~isnan(obs_obs_i)']); + end + end + end + end + end + + if count >= w_days %wait initially until enough data is built up + end_time.year = 2014; + end_time.month = month; + end_time.day = day; + end_time.hour = hour; + end_time.min = minute; + end_time.sec = seconds; + + start_time = augment_date_time( -floor(w_days*(24*60*60)), end_time ); + + % At the end of each day, collect the obs and fcst of the last + % w_day period, and write out a statistics-file at [w_day - floor(w_day/2)] + o_data_sum(abs(o_data_sum - nodata) <= nodata_tol) = NaN; + m_data_sum(abs(m_data_sum - nodata) <= nodata_tol) = NaN; + + for i = 1:N_species + N_window = nansum(N_data(i,:,1:w_days),3); + data2D(1,:) = nansum(o_data_sum(i,:,1:w_days),3); + data2D(1,:) = data2D(1,:)./N_window; + data2D(2,:) = sqrt(nansum(o_data_sum2(i,:,1:w_days),3)./N_window - data2D(1,:).^2); + data2D(3,:) = nansum(m_data_sum(i,:,1:w_days),3)./N_window; + data2D(4,:) = sqrt(nansum(m_data_sum2(i,:,1:w_days),3)./N_window - data2D(3,:).^2); + data2D(5,:) = N_window; + data2D(6,:) = min(m_data_min(i,:,1:w_days),[],3); % Want to use minimum mean daily value + data2D(7,:) = max(m_data_max(i,:,1:w_days),[],3); % Want to use maximum mean daily value + + % Set NaNs where there is not enough data + data2D([1:Nf],N_window=59) + error('This code should never hit a leap year'); + end + + if print_each_DOY + pentad = floor((DOY + 2)/5); + if combine_species_stats + fname_out = [fname_out_base_d, '_sp_ALL_DOY', num2str(DOY,'%3.3d'), '.nc4']; + else + fname_out = [fname_out_base_d,'_sp_', char(species_names(i)),'_DOY', num2str(DOY,'%3.3d'), '.nc4']; + end + if (exist(fname_out)==2 && overwrite) + disp(['Output file exists. overwriting', fname_out]) + elseif (exist(fname_out)==2 && ~overwrite) + disp(['Output file exists. not overwriting. returning']) + disp(['Writing ', fname_out]) + return + else + disp(['Creating ', fname_out]) + end + + % Write out the data + write_netcdf_latlon_grid( fname_out, i_out, j_out, ll_lons, ll_lats, data2D, pentad, ... + start_time, end_time, overwrite, Nf, ll_lon, ll_lat, d_lon, d_lat) + end + + if mod((DOY + 2),5) == 0 + pentad = (DOY + 2)/5; + data_out(i,:,:,pentad) = data2D; + start_time_p(pentad) = start_time; + end_time_p(pentad) = end_time; + if print_each_pentad + if combine_species_stats + fname_out = [fname_out_base_p, '_sp_ALL_p', num2str(pentad,'%2.2d'), '.nc4']; + else + fname_out = [fname_out_base_p, '_sp_', char(species_names(i)),'_p', num2str(pentad,'%2.2d'), '.nc4']; + end + if (exist(fname_out)==2 && overwrite) + disp(['Output file exists. overwriting', fname_out]) + elseif (exist(fname_out)==2 && ~overwrite) + disp(['Output file exists. not overwriting. returning']) + disp(['Writing ', fname_out]) + return + else + disp(['Creating ', fname_out]) + end + + % Write out the data + write_netcdf_latlon_grid( fname_out, i_out, j_out, ll_lons, ll_lats, data2D, pentad, ... + start_time, end_time, overwrite, Nf, ll_lon, ll_lat, d_lon, d_lat ) + end + end + + % Shift the data in the window to make room for next day + o_data_sum(i,:,1:w_days-1) = o_data_sum(i,:,2:w_days); + m_data_sum(i,:,1:w_days-1) = m_data_sum(i,:,2:w_days); + o_data_sum2(i,:,1:w_days-1) = o_data_sum2(i,:,2:w_days); + m_data_sum2(i,:,1:w_days-1) = m_data_sum2(i,:,2:w_days); + m_data_min(i,:,1:w_days-1) = m_data_min(i,:,2:w_days); + m_data_max(i,:,1:w_days-1) = m_data_max(i,:,2:w_days); + N_data(i,:,1:w_days-1) = N_data(i,:,2:w_days); + o_data_sum(i,:,w_days) = NaN; + m_data_sum(i,:,w_days) = NaN; + o_data_sum2(i,:,w_days) = NaN; + m_data_sum2(i,:,w_days) = NaN; + m_data_min(i,:,w_days) = NaN; + m_data_max(i,:,w_days) = NaN; + N_data(i,:,w_days) = NaN; + data2D = NaN+0.0.*data2D; + end + end % count >= w_days + end % day +end % month + +if print_all_pentads + for i = 1:N_species + data_o = squeeze(data_out(i,:,:,:)); + + if combine_species_stats + fname_out = [fname_out_base_d, '_sp_ALL_all_pentads.nc4']; + else + fname_out = [fname_out_base_d,'_sp_', char(species_names(i)),'_all_pentads.nc4']; + end + + if (exist(fname_out)==2 && overwrite) + disp(['Output file exists. overwriting', fname_out]) + elseif (exist(fname_out)==2 && ~overwrite) + disp(['Output file exists. not overwriting. returning']) + disp(['Writing ', fname_out]) + return + else + disp(['Creating ', fname_out]) + end + + write_netcdf_latlon_grid( fname_out, i_out, j_out, ll_lons, ll_lats, data_o, [1:73], ... + start_time_p, end_time_p, overwrite, Nf, ll_lon, ll_lat, d_lon, d_lat ) + end +end + + +% ==================== EOF ============================================== diff --git a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats_pentads_latlon.m b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats_pentads_latlon.m deleted file mode 100644 index b985caf3..00000000 --- a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats_pentads_latlon.m +++ /dev/null @@ -1,736 +0,0 @@ - -function [] = get_model_and_obs_clim_stats_pentads_latlon( species_names, ... - run_months, exp_path, exp_run, domain, start_year, end_year, ... - dt_assim, t0_assim, species, combine_species_stats, obs_param, ... - hscale, w_days, Ndata_min, prefix, ... - convert_grid , time_of_day_in_hours ) - -% -% get_model_and_obs_clim_stats.m -% -% Compute mean, stdv of model and observations from tile-based -% "innov" files for a selection of species. -% -% The main purpose of this function is to aggregate the information -% from the "innov" files so that the climatology statistics can -% be used in scaling of the observations before assimilation. -% -% One file with statistics is generated for every DOY (1,...,365). -% The temporal smoothing/averaging window (w_days) is given in days. -% -% We calcualte the bias correction factors and write on a regular 0.25 degree -% lat/lon grid as there is no regular grid for ASCAT observations - -% -% ==HEADER== -% N_tiles N_angles -% angles -% -% ==DATA== -% -% %%%% tile ID --> for all tiles (1:N_tiles, not sorted by tile_id!) -% lat -% lon -% -% [for angles] -% mean_obs_H -% std_obs_H -% mean_mod_H -% std_mod_H -% N_data_H -% -% mean_obs_V -% std_obs_V -% mean_mod_V -% std_mod_V -% N_data_V -% -% H_obs -% H_mod -% V_obs -% V_mod -% [end angles] -% -% GDL, 10 sept 2012 -% -% GDL, aug 2013: added 'convert_grid' (= EASEv2_M36, EASE_M36, ...) -% to project the Obs (always M36 for SMOS) and Fcst to M36 -% M09 obs are administered by tiles (0) that could be anywhere -% around the center of the observed pixel (M36) -% ----------- -% | X X X X | -% | X O O X | -% | X O O X | -% | X X X X | -% ----------- -% GDL, jan 2014: the above issue that "any" M09 tile in the center (0) -% could potentially administer the M36 obs is not true -% anymore with later LDASsa-tags. -% => no need to pass on 'convert_grid' for tags later than -% the summer of 2013 -% reichle, qliu, 13 July 2022: -% "convert_grid" is still needed to limit the number of tiles -% in the scaling parameter file. With "convert_grid" turned on, -% only the M09 tile to the northeast of the M36 center point -% is kept in the scaling parameter file, consistent with the -% "tmp_shift_lat" and "tmp_shift_lon" operations in the SMOS -% and SMAP Fortran readers. (It is not clear if this matlab -% function works properly if there is no M09 [land] tile -% immediately to the northeast of the M36 center point. In -% such a case, the Fortran reader assigns the nearest M09 -% land tile as the tile that administers the obs.) -% Presumably, scaling parameters for all M09 tiles could be kept -% if they are stored in (compressed) nc4 format. In this case, -% the NaN values for the scaling parameters of 15 out of each 16 -% M09 tiles can be compressed to almost nothing. -% -% ------------------------------------------------------------------- -% begin user-defined inputs -% ------------------------------------------------------------------- - -% obs species to be processed (see ens_upd_inputs.nml for a list) -% -% (only observation species that represent observations of the same -% model prognostic or diagnostic can be processed together!) - -nodata = -9999; -nodata_tol = 1e-4; - -% minimum number of data points to include in window statistics - -% N_data_min = w_days/10.; % initial screening on minimum # points in a -% % window to calculate a mean or stdv -% include a final decision about "good" stats later, when merging years - -% no-data-value for points that don't have good statistics - -no_data_stats = -9999.; - -disp('ASSUMING ACAT observations/undefined observation grid'); - -% output specs - -overwrite = 1; - -if combine_species_stats - N_species = 1; -else - N_species = length(species); -end - -Nf = 5; %5 fields per species -N_pentads = 73; - -write_ind_latlon = 'latlon_id'; %'latlon'; - -% tmp_shift_lon = 0.01; -% tmp_shift_lat = 0.005; - -% More user switches that could be moved -store_all_025_latlon = 0; -print_each_DOY = 0; -print_each_pentad = 1; -print_all_pentads = 1; - -% ------------------------------------------------------------------- -% end user-defined inputs -% ------------------------------------------------------------------- - -% assemble input and output paths - -%inpath = [ exp_path, '/output/', exp_run, '/', domain ]; -inpath = [ exp_path, '/', exp_run, '/output/', domain ]; - -outpath = [ inpath, '/stats/z_score_clim/' ]; - -% create outpath if it doesn't exist -if exist(outpath)~=2 - eval(['!mkdir -p ', outpath]); -end - -% ------------------------------------------------------------- - -% assemble output file name - -ind = find(start_year == min(start_year)); -mi_m = min(run_months(ind)); -ind = find(end_year == max(end_year)); -ma_m = max(run_months(ind)); - -D(1) = 1; -P(1) = 1; -if mi_m > 1 - D(1) = sum(days_in_month( 2014, [1:mi_m-1]))+1; - P(1) = ceil(D(1)/5); -end -if ma_m > 1 - D(2) = sum(days_in_month( 2014, [1:ma_m])); -else - D(2) = 1; -end -P(2) = floor(D(2)/5); - -if run_months(1) ~= run_months(end) && run_months(2) ~= run_months(end) - disp('WARNING: incomplete pentad-windows; loop through additional months to get complete pentads'); -end - -fname_out_base = [ outpath, '/', prefix, ... - num2str(min(start_year)),'_doy',num2str(D(1)),'_',... - num2str(max(end_year)), '_doy',num2str(D(2)),... - '_W_', num2str(w_days),'d_Nmin_', num2str(Ndata_min)]; - -fname_out_base_p = [ outpath, '/', prefix, ... - num2str(min(start_year)),'_p',num2str(P(1)),'_',... - num2str(max(end_year)), '_p',num2str(P(2)),... - '_W_', num2str(round(w_days/5)),'p_Nmin_', num2str(Ndata_min)]; - -%============================================================== -% Some clunky code to maintain backwards compatibility with adding orbit -% tag - -% Initialize counters for cells ending in "_A" and cells ending in "_D" -a_count = 0; -d_count = 0; - -% Loop through each cell in the array -for i = 1:numel(species_names) - % Check if the text in the cell ends with either "_A" or "_D" - if endsWith(species_names{i}, '_A') - % If it ends with "_A", increment the "_A" counter - a_count = a_count + 1; - elseif endsWith(species_names{i}, '_D') - % If it ends with "_D", increment the "_D" counter - d_count = d_count + 1; - end - - if startsWith(species_names{i}, 'SMAP') - inc_angle = [40.0]; - else - inc_angle = [-999.9]; - end - -end - -% Determine the output based on the values of the "_A" and "_D" counters -if a_count == numel(species_names) - % Both cells end in "_A" - disp('All species are "_A"'); - Orbit_tag = '_A'; - int_Asc = 1; -elseif d_count == numel(species_names) - % Both cells end in "_D" - disp('All species are "_D"'); - Orbit_tag = '_D'; - int_Asc = 2; -elseif a_count > 0 && d_count > 0 - % There is a mix of "_A" and "_D" - disp('Species have a mix of "_A" and "_D"'); - Orbit_tag = '_AD'; - int_Asc = 3; -else - % Neither cell ends in "_A" or "_D" - disp('Neither cell ends in "_A" or "_D"'); - Orbit_tag = '_NoOrbits'; - int_Asc = 4; -end - -fname_out_base = [fname_out_base, Orbit_tag]; -fname_out_base_p = [fname_out_base_p, Orbit_tag]; - -if exist( 'time_of_day_in_hours', 'var') - - fname_out_base = [fname_out_base, '_', num2str(time_of_day_in_hours,'%2.2d'), 'z']; - fname_out_base_p = [fname_out_base_p, '_', num2str(time_of_day_in_hours,'%2.2d'), 'z']; - -end - -%====================================================== - -% ------------------------------------------------------------- -% Define our 1/4 degree lat/lon grid -n_lon = 1440; -n_lat = 720; -ll_lon = -180; -ll_lat = -90; -d_lon = 0.25; -d_lat = 0.25; -ll_lons = linspace(-180, 179.75, 1440); -ll_lats = linspace(-90, 89.75, 720); -i_lon = (1:1440); -j_lat = (1:720); - -grid_idx = zeros(1036800,5); -grid_idx(:,1) = (1:1036800); -cnt = 0; -for i = 1:n_lon - for j = 1:n_lat - cnt = cnt+1; - grid_idx(cnt,2) = i_lon(i); - grid_idx(cnt,3) = j_lat(j); - grid_idx(cnt,4) = ll_lons(i); - grid_idx(cnt,5) = ll_lats(j); - end -end - -% ------------------------------------------------------------- - -obsnum = grid_idx(:,1); -i_out = grid_idx(:,2); -j_out = grid_idx(:,3); -lon_out = grid_idx(:,4); -lat_out = grid_idx(:,5); -N_gridcells = length(grid_idx); - -% Not sure about this as aren't centering lat/lons -if hscale>0 - - for i=1:N_gridcells - - this_lat = lat_out(i); - this_lon = lon_out(i); - - tmp_sq_distance = ... - (lon_out - this_lon).^2 + ... - (lat_out - this_lat).^2; - - hscale_ind{i} = find( tmp_sq_distance <= hscale^2 ); - end - -else - - hscale_ind = num2cell(obsnum); - -end - - -% initialize output statistics -% Note: Rolf suggests to have all species as one dimension, rather than -% N_pol and N_angle be specified here. Then subsample specifically -% when the files are written out. - -o_data = NaN+zeros(N_species, N_gridcells, w_days); -m_data = NaN+zeros(N_species, N_gridcells, w_days); -o_data2 = NaN+zeros(N_species, N_gridcells, w_days); -m_data2 = NaN+zeros(N_species, N_gridcells, w_days); -N_data = NaN+zeros(N_species, N_gridcells, w_days); - -data_out = NaN+zeros(N_species, Nf, N_gridcells, N_pentads); -data2D = NaN+zeros(Nf, N_gridcells); - -% ------------------------------------------------------------- - -% make sure t0_assim is *first* analysis time in a day - -t0_assim = mod( t0_assim, dt_assim ); - -count = 0; - -for imonth = 1:length(run_months) - month = run_months(imonth); - -for day = 1:days_in_month( 2014, month) %2014 = random non-leap year - - if count < w_days - count = count + 1; - else - count = w_days; - end - - for seconds_in_day = t0_assim:dt_assim:(86400-1) - - hour = floor(seconds_in_day/3600); - - % check if diurnal stats are needed - - if exist('time_of_day_in_hours','var') - tmp_hour = time_of_day_in_hours; - else - tmp_hour = hour; % all hours of day will be included - end - - if hour==tmp_hour - - minute = floor( (seconds_in_day-hour*3600)/60 ); - - seconds = seconds_in_day-hour*3600-minute*60; - - if (seconds~=0) - input('something is wrong! Ctrl-c now') - end - - - for year = start_year(imonth):end_year(imonth) - - YYYYMMDD = [ num2str(year, '%4.4d'), ... - num2str(month, '%2.2d'), ... - num2str(day, '%2.2d') ]; - - HHMM = [ num2str(hour, '%2.2d'), ... - num2str(minute, '%2.2d') ]; - - % read innov files - - fname = [ inpath, '/ana/ens_avg/', ... - 'Y', YYYYMMDD(1:4), '/', ... - 'M', YYYYMMDD(5:6), '/', ... - exp_run, '.ens_avg.ldas_ObsFcstAna.', ... - YYYYMMDD, '_', HHMM, 'z.bin' ]; - - ifp = fopen( fname, 'r', 'l' ); - - if (ifp > 0) %Proceed only if file exists (e.g. irregular SMOS swaths!) - - fclose(ifp); - - [date_time, ... - obs_assim, ... - obs_species, ... - obs_tilenum, ... - obs_lon, ... - obs_lat, ... - obs_obs, ... - obs_obsvar, ... - obs_fcst, ... - obs_fcstvar, ... - obs_ana, ... - obs_anavar ... - ] = ... - read_ObsFcstAna( fname ); - - % remove tiles when there is no obs_fcst (obs_fcst == 0 in innov output when - % missing) - - idx = find(obs_fcst == 0); - obs_assim(idx) = []; - obs_species(idx) = []; - obs_tilenum(idx) =[]; - obs_lon(idx) =[]; - obs_lat(idx) = []; - obs_obs(idx) = []; - obs_obsvar(idx) = []; - obs_fcst(idx) = []; - obs_fcstvar(idx) = []; - obs_ana(idx) = []; - obs_anavar(idx) = []; - - % extract species of interest - - ind = []; - - %for this_species = species - for scnt = 1:N_species - - if combine_species_stats % We are combining stats - ind = find(ismember(obs_species, species)); - this_species = species(scnt); % Only first species in list. But only used in determining angle and pol for species, which shouldn't vary between species being combined - else - ind = find( obs_species == this_species); - end - - if (~isempty(ind)) - - obs_tilenum_i = obs_tilenum(ind); - obs_obs_i = obs_obs(ind); - obs_fcst_i = obs_fcst(ind); - obs_lon_i = obs_lon(ind); - obs_lat_i = obs_lat(ind); - - % Check if any location receives more than 1 obs (or 1 species) - - tmp = sort(obs_tilenum_i); - same_tile = find(diff(tmp)==0, 1); - - if (~isempty(same_tile) && combine_species_stats==0) - error('multiple obs of the same species at one location? - only last one in line is used'); - end - - % Organize the data in a big matrix - - pol = obs_param(this_species == [obs_param.species]).pol; - - % Only writes lat-lon at exact obs locations, but with - % hscale>0, these obs are spread outside their exact - % location. This allows to calculate stats at lan-lons - % where no obs are available. - - %lon_out(obs_tilenum_i) = obs_lon_i; - %lat_out(obs_tilenum_i) = obs_lat_i; - - %obs_lat/lon are the actual M36 lat/lons, *not* the - %administering tiles, so the lat/lons for the obs and those - %in the tile_coord would not be identical. - %Still, they should be in the - %neighbourhood, so check here if that is true. -% if (any(abs(tile_coord.com_lat(obs_tilenum_i)-obs_lat_i) > tol) || ... -% any(abs(tile_coord.com_lon(obs_tilenum_i)-obs_lon_i) > tol) ) -% error('Something wrong with tile_lat/lon') -% end - - %map model tiles (e.g. all M09) to observation administering - %tiles (could be a reduced subset of all M09) - %-------------------------------------------------------- -% obs_i = obsnum(obs_tilenum_i); - %-------------------------------------------------------- - - % Put obs lat/lon on our grid and figure out obsnum/grid - % index - - i_idx = floor((obs_lon_i - ll_lon)/d_lon) + 1; - j_idx = floor((obs_lat_i - ll_lat)/d_lat) + 1; - [~, obs_idx] = ismember([i_idx, j_idx], [i_out, j_out], 'rows'); - - obs_i = obsnum(obs_idx); - - if (hscale == 0) - - %11 May 2015: sum the obs and fcst within each day; - %and across years! - %some obs can be found at multiple hours within a day - %e.g. at the poles. - %**nansum of NaN's** result in zero, this need to be - %taken care of - o_data(scnt,obs_i,count) = nansum([o_data(scnt,obs_i,count); obs_obs_i' ]); - m_data(scnt,obs_i,count) = nansum([m_data(scnt,obs_i,count); obs_fcst_i']); - - %X^2 - o_data2(scnt,obs_i,count) = nansum([o_data2(scnt,obs_i,count); obs_obs_i'.^2 ]); - m_data2(scnt,obs_i,count) = nansum([m_data2(scnt,obs_i,count); obs_fcst_i'.^2]); - - %Sum of obs or model elements at each location - N_data(scnt,obs_i,count) = nansum([N_data(scnt,obs_i,count); ~isnan([obs_obs_i])']); - - else - - for i_ind = 1:length(obs_obs_i) - - %introduce a spatial effect of each observation on - %neighbouring statistics (through hscale) - s_eff = unique(hscale_ind{obs_i(i_ind)}); - %hscale_ind =[obs space] % - - %Sum of X - o_data(scnt,obs_i,count) = ... - nansum([o_data(scnt,obs_i,count); repmat(obs_obs_i(i_ind),1,length(s_eff))]); - m_data(scnt,obs_i,count) = ... - nansum([m_data(pol(1),s_eff,angle_i,count); repmat(obs_fcst_i(i_ind),1,length(s_eff))]); - - %Sum of X^2 - o_data2(scnt,obs_i,count) = ... - nansum([o_data2(scnt,obs_i,count); repmat(obs_obs_i(i_ind).^2,1,length(s_eff))]); - m_data2(scnt,obs_i,count) = ... - nansum([m_data2(scnt,obs_i,count); repmat(obs_fcst_i(i_ind).^2,1,length(s_eff))]); - - %Sum of obs or model elements at each location - N_data(scnt,obs_i,count) = ... - nansum([N_data(scnt,obs_i,count); repmat(~isnan([obs_obs_i(i_ind)]),1,length(s_eff)) ]); - - end - - end - - end - - end - - end % if file present - - end % loop over multiple years - - end % time_of_day_in_hours - - end % seconds_in_day - - %count = count+1; - - if count >= w_days %wait initially until enough data is built up - - end_time.year = 2014; - end_time.month = month; - end_time.day = day; - end_time.hour = hour; - end_time.min = minute; - end_time.sec = seconds; - - start_time = augment_date_time( -floor(w_days*(24*60*60)), end_time ); - - % At the end of each day, collect the obs and fcst of the last - % w_day period, and write out a statistics-file at [w_day - floor(w_day/2)] - - o_data(abs(o_data - nodata) <= nodata_tol) = NaN; - m_data(abs(o_data - nodata) <= nodata_tol) = NaN; - - % data_out = zeros(N_out_fields,1:N_tiles,N_angle); - - for i = 1:N_species - - N_hscale_window = nansum(N_data(i,:,1:w_days),3); - - if w_days == 95 - N_hscale_inner_window = nansum(N_data(i,:,((w_days+1)/2-15):((w_days+1)/2+15)),3); - end - - % OBSERVATIONS - %---------------- - %o_data is a sum over neighbouring obs above; - %here then take a sum over the time steps in the window - data2D(1,:) = nansum(o_data(i,:,1:w_days),3); - - %then make the average, by dividing over the sum of the number of - %timesteps and influencing obs at each location - data2D(1,:) = data2D(1,:)./N_hscale_window; - - %stdv_H = sqrt(E[X^2] - E[X]^2) - data2D(2,:) = nansum(o_data2(i,:,1:w_days),3); - data2D(2,:) = data2D(2,:)./N_hscale_window; - data2D(2,:) = sqrt( data2D(2,:) - data2D(1,:).^2); - - % MODEL - %---------------- - data2D(3,:) = nansum(m_data(i,:,1:w_days),3); - data2D(3,:) = data2D(3,:)./N_hscale_window; - - data2D(4,:) = nansum(m_data2(i,:,1:w_days),3); - data2D(4,:) = data2D(4,:)./N_hscale_window; - data2D(4,:) = sqrt( data2D(4,:) - data2D(3,:).^2); - - data2D(5,:) = N_hscale_window; - - % Toss out stats that are based on too little data - - data2D([1:Nf],N_hscale_window=59) - DOY = DOY-1; - error('This code should never hit a leap year'); - end - - - fname_out = [fname_out_base_s, '_DOY', num2str(DOY,'%3.3d'), '.nc4']; - - % compress data before writing in file. - - %idx_keep = find(any(abs(data_out -nodata) > nodata_tol,1)); - %lon_out_write = lon_out(idx_keep); - %lat_out_write = lat_out(idx_keep); - %data_out_write = data_out(:,idx_keep); - %tile_coord_tile_id_write = tile_coord_tile_id(idx_keep); - - - % write output for each DOY, sorted by all tile - if print_each_DOY - % check whether output file exists - if (exist(fname_out)==2 && overwrite) - disp(['output file exists. overwriting', fname_out]) - elseif (exist(fname_out)==2 && ~overwrite) - disp(['output file exists. not overwriting. returning']) - disp(['writing ', fname_out]) - return - else - disp(['creating ', fname_out]) - end - write_netcdf_file_2D_grid(fname_out, i_out, j_out, lon_out, lat_out, ... - inc_angle, data2D, int_Asc, pentad, ... %instead of writing the version#, write pentad - start_time, end_time, overwrite, ... - Nf, write_ind_latlon, 'scaling',... - obsnum) - else - % if DOY is at middle of pentad, then copy the DOY to a pentad file - % DOY = pentad*5 - 2; ==> pentad = (DOY + 2)/5; - pentad = (DOY + 2)/5; - if mod((DOY + 2),5) == 0 - data_out(i,:,:,pentad) = data2D; - start_time_p(pentad) = start_time; - end_time_p(pentad) = end_time; - if print_each_pentad - fname_out = [fname_out_base_p, '_p', num2str(pentad,'%2.2d'), '.nc4']; - % check whether output file exists - if (exist(fname_out)==2 && overwrite) - disp(['output file exists. overwriting', fname_out]) - elseif (exist(fname_out)==2 && ~overwrite) - disp(['output file exists. not overwriting. returning']) - disp(['writing ', fname_out]) - return - else - disp(['creating ', fname_out]) - end - write_netcdf_file_2D_grid(fname_out, i_out, j_out, lon_out, lat_out, ... - inc_angle, data2D, int_Asc, pentad, ... - start_time, end_time, overwrite, ... - Nf, write_ind_latlon, 'scaling',... - obsnum) - end - end - - end - - %clear idx_keep lon_out_write lat_out_write data_out_write tile_coord_tile_id_write - - % shift the window by one day and make room for the next day at the end - - o_data(:,:,1:w_days-1) = o_data(:,:,2:w_days); - m_data(:,:,1:w_days-1) = m_data(:,:,2:w_days); - o_data2(:,:,1:w_days-1) = o_data2(:,:,2:w_days); - m_data2(:,:,1:w_days-1) = m_data2(:,:,2:w_days); - N_data(:,:,1:w_days-1) = N_data(:,:,2:w_days); - - o_data(:,:,w_days) = NaN; - m_data(:,:,w_days) = NaN; - o_data2(:,:,w_days) = NaN; - m_data2(:,:,w_days) = NaN; - N_data(:,:,w_days) = NaN; - - data2D = NaN+0.0.*data2D; - - end - - end - -end % day -end % month - -if print_all_pentads - for i = 1:N_species - data_o = squeeze(data_out(i,:,:,:)); - - if combine_species_stats % We are combining stats - fname_out = [fname_out_base(1:startidx-1) 'z_score_clim/combined_all_pentads_', fname_out_base(endidx:end),'.nc4']; - else - fname_out = [fname_out_base(1:startidx-1) 'z_score_clim/', char(species_names(i)),'_all_pentads_', fname_out_base(endidx:end),'.nc4']; - end - - write_netcdf_file_2D_grid(fname_out, i_out, j_out, lon_out, lat_out, ... - inc_angle, data_o, int_Asc, [1:73], ... - start_time_p, end_time_p, overwrite, ... - Nf, write_ind_latlon, 'scaling',... - obsnum) - end -end - - -% ==================== EOF ============================================== diff --git a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/write_netcdf_file.m b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/write_netcdf_file.m deleted file mode 100644 index f8930218..00000000 --- a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/write_netcdf_file.m +++ /dev/null @@ -1,189 +0,0 @@ - function [] = write_netcdf_file(fname, colind, rowind,... - lon_out, lat_out,... - av_angle_bin, data, asc_flag,... - pentad, ... - start_time, end_time, overwrite, N_out_fields, ... - write_ind_latlon, data_product,... - obsnum) %last argument is optional - - int_precision = 'NC_INT'; % precision of fortran tag - float_precision = 'NC_DOUBLE'; % precision of data in input file - - version = 0; - - % check dimensions - if size(data,1)~=N_out_fields - error('ERROR: size of data incompatible with N_out_fields') - end - - % check for presence of optional input "overwrite" - if ~exist('overwrite','var') - overwrite = 0; % default: do NOT overwrite existing files - end - - % check if file exists - if exist(fname,'file') - if overwrite==0 - disp(['RETURNING!!! -- NOT OVERWRITING EXISTING FILE ', fname]) - return - else - disp(['OVERWRITING ', fname]) - end - else - disp(['writing ', fname]) - end - - % Convert the cell arrays to matrices using cell2mat (to deal with all_pentad case) - year_mat = cell2mat({start_time.year}'); - month_mat = cell2mat({start_time.month}'); - day_mat = cell2mat({start_time.day}'); - hour_mat = cell2mat({start_time.hour}'); - min_mat = cell2mat({start_time.min}'); - sec_mat = cell2mat({start_time.sec}'); - % Use the matrices as input to the datetime function - d = datetime(year_mat, month_mat, day_mat, hour_mat, min_mat, sec_mat); - % Convert to serial date number - serialNum = datenum(d); - % Subtract serial date number of January 1, 1950 - daysSince1950 = serialNum - datenum('January 1, 1950'); - tmp_start_time = daysSince1950; - - % Convert the cell arrays to matrices using cell2mat (to deal with all_pentad case) - year_mat = cell2mat({end_time.year}'); - month_mat = cell2mat({end_time.month}'); - day_mat = cell2mat({end_time.day}'); - hour_mat = cell2mat({end_time.hour}'); - min_mat = cell2mat({end_time.min}'); - sec_mat = cell2mat({end_time.sec}'); - % Use the matrices as input to the datetime function - d = datetime(year_mat, month_mat, day_mat, hour_mat, min_mat, sec_mat); - % Convert to serial date number - serialNum = datenum(d); - % Subtract serial date number of January 1, 1950 - daysSince1950 = serialNum - datenum('January 1, 1950'); - tmp_end_time = daysSince1950; - - % determine number of grid cells ; further check dimensions - N_grid = size(data,2); - N_angle= 1; - if ndims(data) ==2 - N_pentad = 1; - else - N_pentad = 73; - end - - if (strcmp(write_ind_latlon,'latlon_id') && nargin == 14) - if( size(obsnum,1) ~= N_grid ) - error('tile_id dimensions ??') - end - if ( size(obsnum,2) > 1) - disp(['# subgridcells per gridcell: ',num2str(size(obsnum,2))]); - end - end - -% create netCDF file -netcdf.setDefaultFormat('FORMAT_NETCDF4'); -ncid = netcdf.create(fname, 'NETCDF4'); - -% define dimensions -dimid_grid = netcdf.defDim(ncid, 'grid', N_grid); -dimid_angle = netcdf.defDim(ncid, 'angle', N_angle); -dimid_tile = netcdf.defDim(ncid, 'tile', size(obsnum,2)); -dimid_pentad = netcdf.defDim(ncid, 'pentad', N_pentad); - -% define variables -varid_asc_flag = netcdf.defVar(ncid, 'asc_flag', int_precision, []); -varid_version = netcdf.defVar(ncid, 'version', int_precision, []); -varid_pentad = netcdf.defVar(ncid, 'pentad', int_precision, [dimid_pentad]); - -varid_start_time = netcdf.defVar(ncid, 'start_time', float_precision, [dimid_pentad]); -netcdf.putAtt(ncid, varid_start_time, 'standard_name','start time'); -netcdf.putAtt(ncid, varid_start_time, 'long_name','start time'); -netcdf.putAtt(ncid, varid_start_time, 'axis','T'); -netcdf.putAtt(ncid, varid_start_time, 'units','days since 1950-01-01 00:00:00.0 +0000'); - -varid_end_time = netcdf.defVar(ncid, 'end_time',float_precision, [dimid_pentad]); -netcdf.putAtt(ncid, varid_end_time, 'standard_name','end time'); -netcdf.putAtt(ncid, varid_end_time, 'long_name','end time'); -netcdf.putAtt(ncid, varid_end_time, 'axis','T'); -netcdf.putAtt(ncid, varid_end_time, 'units','days since 1950-01-01 00:00:00.0 +0000'); - -varid_N_grid = netcdf.defVar(ncid, 'N_grid', int_precision, []); -varid_N_angle = netcdf.defVar(ncid, 'N_angle', int_precision, []); -varid_obsnum = netcdf.defVar(ncid, 'obs_num', int_precision, [dimid_grid dimid_tile]); -varid_av_angle_bin = netcdf.defVar(ncid, 'av_angle_bin', float_precision, [dimid_angle]); -varid_colind = netcdf.defVar(ncid, 'colind', float_precision, [dimid_grid]); -varid_rowind = netcdf.defVar(ncid, 'rowind', float_precision, [dimid_grid]); -varid_lon = netcdf.defVar(ncid, 'lon', float_precision, [dimid_grid]); -varid_lat = netcdf.defVar(ncid, 'lat', float_precision, [dimid_grid]); - -% Create a new group called 'data' -groupname = 'data'; -grpid = netcdf.defGrp(ncid,groupname); - -varid_om = netcdf.defVar(grpid, 'o_mean', float_precision, [dimid_grid dimid_pentad]); -varid_ov = netcdf.defVar(grpid, 'o_std', float_precision, [dimid_grid dimid_pentad]); -varid_mm = netcdf.defVar(grpid, 'm_mean', float_precision, [dimid_grid dimid_pentad]); -varid_mv = netcdf.defVar(grpid, 'm_std', float_precision, [dimid_grid dimid_pentad]); -varid_ndata = netcdf.defVar(grpid, 'n_data', float_precision, [dimid_grid dimid_pentad]); - -% end define mode -netcdf.endDef(ncid); - -% write data -netcdf.putVar(ncid, varid_asc_flag, asc_flag); -netcdf.putVar(ncid, varid_version, version); -netcdf.putVar(ncid, varid_pentad, pentad); -netcdf.putVar(ncid, varid_start_time, tmp_start_time); -netcdf.putVar(ncid, varid_end_time, tmp_end_time); -netcdf.putVar(ncid, varid_N_grid, N_grid); -netcdf.putVar(ncid, varid_N_angle, N_angle); - -if (~(strcmp(data_product,'scaling') && strcmp(write_ind_latlon,'latlon_id') && nargin == 14)) - netcdf.putVar(ncid, varid_obsnum, obsnum); -else - netcdf.putVar(ncid, varid_obsnum, permute(obsnum, [2 1])); -end - -netcdf.putVar(ncid, varid_av_angle_bin, squeeze(av_angle_bin(:))); - - if (N_grid >= 1) - -netcdf.putVar(ncid, varid_colind, colind); -netcdf.putVar(ncid, varid_rowind, rowind); -netcdf.putVar(ncid, varid_lon, lon_out); -netcdf.putVar(ncid, varid_lat, lat_out); - -if N_pentad ==1 - netcdf.putVar(grpid,varid_om,data(1,:)); - netcdf.putVar(grpid,varid_ov,data(2,:)); - netcdf.putVar(grpid,varid_mm,data(3,:)); - netcdf.putVar(grpid,varid_mv,data(4,:)); - netcdf.putVar(grpid,varid_ndata,data(5,:)); -else - netcdf.putVar(grpid,varid_om,data(1,:,:)); - netcdf.putVar(grpid,varid_ov,data(2,:,:)); - netcdf.putVar(grpid,varid_mm,data(3,:,:)); - netcdf.putVar(grpid,varid_mv,data(4,:,:)); - netcdf.putVar(grpid,varid_ndata,data(5,:,:)); -end - else - netcdf.putVar(ncid, varid_colind, 0.0); - netcdf.putVar(ncid, varid_rowind, 0.0); - netcdf.putVar(ncid, varid_lon, 0.0); - netcdf.putVar(ncid, varid_lat, 0.0) - - netcdf.putVar(grpid,varid_om,-999.0); -netcdf.putVar(grpid,varid_ov,-999.0); -netcdf.putVar(grpid,varid_mm,-999.0); -netcdf.putVar(grpid,varid_mv,-999.0); -netcdf.putVar(grpid,varid_ndata,-999.0); - end - -% close netCDF file -netcdf.close(ncid); - - end - - - diff --git a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/write_netcdf_file_2D_grid.m b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/write_netcdf_file_2D_grid.m deleted file mode 100644 index ee257858..00000000 --- a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/write_netcdf_file_2D_grid.m +++ /dev/null @@ -1,266 +0,0 @@ - function [] = write_netcdf_file_2D_grid(fname, colind, rowind,... - lon_out, lat_out,... - av_angle_bin, data, asc_flag,... - pentad, ... - start_time, end_time, overwrite, N_out_fields, ... - write_ind_latlon, data_product,... - obsnum) %last argument is optional - - % Current output from ncdump of file generated by this script - % - % ncdump -h combined_all_pentads_M36_zscore_stats_2015_doy152_2017_doy151_hscale_0.00_W_75d_Nmin_20_AD.nc4 - % netcdf combined_all_pentads_M36_zscore_stats_2015_doy152_2017_doy151_hscale_0.00_W_75d_Nmin_20_AD { - % dimensions: - % grid = 1036800 ; - % angle = 1 ; - % tile = 1 ; - % pentad = 73 ; - % lon = 1440 ; - % lat = 720 ; - % variables: - % int asc_flag ; - % int version ; - % int pentad(pentad) ; - % double start_time(pentad) ; - % start_time:standard_name = "start time" ; - % start_time:long_name = "start time" ; - % start_time:axis = "T" ; - % start_time:units = "days since 1950-01-01 00:00:00.0 +0000" ; - % double end_time(pentad) ; - % end_time:standard_name = "end time" ; - % end_time:long_name = "end time" ; - % end_time:axis = "T" ; - % end_time:units = "days since 1950-01-01 00:00:00.0 +0000" ; - % int N_grid ; - % int N_angle ; - % int obs_num(tile, grid) ; - % double av_angle_bin(angle) ; - % double colind(grid) ; - % double rowind(grid) ; - % double lon(lon) ; - % double lat(lat) ; - % double o_mean(pentad, lon, lat) ; - % double o_std(pentad, lon, lat) ; - % double m_mean(pentad, lon, lat) ; - % double m_std(pentad, lon, lat) ; - % double n_data(pentad, lon, lat) ; - % } - - - - - int_precision = 'NC_INT'; % precision of fortran tag - float_precision = 'NC_DOUBLE'; % precision of data in input file - - version = 0; - - % check dimensions - if size(data,1)~=N_out_fields - error('ERROR: size of data incompatible with N_out_fields') - end - - % check for presence of optional input "overwrite" - if ~exist('overwrite','var') - overwrite = 0; % default: do NOT overwrite existing files - end - - % check if file exists - if exist(fname,'file') - if overwrite==0 - disp(['RETURNING!!! -- NOT OVERWRITING EXISTING FILE ', fname]) - return - else - disp(['OVERWRITING ', fname]) - end - else - disp(['writing ', fname]) - end - - % Convert the cell arrays to matrices using cell2mat (to deal with all_pentad case) - year_mat = cell2mat({start_time.year}'); - month_mat = cell2mat({start_time.month}'); - day_mat = cell2mat({start_time.day}'); - hour_mat = cell2mat({start_time.hour}'); - min_mat = cell2mat({start_time.min}'); - sec_mat = cell2mat({start_time.sec}'); - % Use the matrices as input to the datetime function - d = datetime(year_mat, month_mat, day_mat, hour_mat, min_mat, sec_mat); - % Convert to serial date number - serialNum = datenum(d); - % Subtract serial date number of January 1, 1950 - daysSince1950 = serialNum - datenum('January 1, 1950'); - tmp_start_time = daysSince1950; - - % Convert the cell arrays to matrices using cell2mat (to deal with all_pentad case) - year_mat = cell2mat({end_time.year}'); - month_mat = cell2mat({end_time.month}'); - day_mat = cell2mat({end_time.day}'); - hour_mat = cell2mat({end_time.hour}'); - min_mat = cell2mat({end_time.min}'); - sec_mat = cell2mat({end_time.sec}'); - % Use the matrices as input to the datetime function - d = datetime(year_mat, month_mat, day_mat, hour_mat, min_mat, sec_mat); - % Convert to serial date number - serialNum = datenum(d); - % Subtract serial date number of January 1, 1950 - daysSince1950 = serialNum - datenum('January 1, 1950'); - tmp_end_time = daysSince1950; - - % determine number of grid cells ; further check dimensions - N_grid = size(data,2); - N_angle= 1; - if ndims(data) ==2 - N_pentad = 1; - else - N_pentad = 73; - end - - N_lon = 1440; - N_lat = 720; - - ll_lons = linspace(-180, 179.75, 1440); - ll_lats = linspace(-90, 89.75, 720); - - if (strcmp(write_ind_latlon,'latlon_id') && nargin == 14) - if( size(obsnum,1) ~= N_grid ) - error('tile_id dimensions ??') - end - if ( size(obsnum,2) > 1) - disp(['# subgridcells per gridcell: ',num2str(size(obsnum,2))]); - end - end - -% create netCDF file -netcdf.setDefaultFormat('FORMAT_NETCDF4'); -ncid = netcdf.create(fname, 'NETCDF4'); - -% define dimensions -dimid_grid = netcdf.defDim(ncid, 'grid', N_grid); -dimid_angle = netcdf.defDim(ncid, 'angle', N_angle); -dimid_tile = netcdf.defDim(ncid, 'tile', size(obsnum,2)); -dimid_pentad = netcdf.defDim(ncid, 'pentad', N_pentad); -dimid_lon = netcdf.defDim(ncid, 'lon', N_lon); -dimid_lat = netcdf.defDim(ncid, 'lat', N_lat); - -% define variables -varid_asc_flag = netcdf.defVar(ncid, 'asc_flag', int_precision, []); -varid_version = netcdf.defVar(ncid, 'version', int_precision, []); -varid_pentad = netcdf.defVar(ncid, 'pentad', int_precision, [dimid_pentad]); - -varid_start_time = netcdf.defVar(ncid, 'start_time', float_precision, [dimid_pentad]); -netcdf.putAtt(ncid, varid_start_time, 'standard_name','start time'); -netcdf.putAtt(ncid, varid_start_time, 'long_name','start time'); -netcdf.putAtt(ncid, varid_start_time, 'axis','T'); -netcdf.putAtt(ncid, varid_start_time, 'units','days since 1950-01-01 00:00:00.0 +0000'); - -varid_end_time = netcdf.defVar(ncid, 'end_time',float_precision, [dimid_pentad]); -netcdf.putAtt(ncid, varid_end_time, 'standard_name','end time'); -netcdf.putAtt(ncid, varid_end_time, 'long_name','end time'); -netcdf.putAtt(ncid, varid_end_time, 'axis','T'); -netcdf.putAtt(ncid, varid_end_time, 'units','days since 1950-01-01 00:00:00.0 +0000'); - -varid_N_grid = netcdf.defVar(ncid, 'N_grid', int_precision, []); -varid_N_angle = netcdf.defVar(ncid, 'N_angle', int_precision, []); -varid_obsnum = netcdf.defVar(ncid, 'obs_num', int_precision, [dimid_grid dimid_tile]); -varid_av_angle_bin = netcdf.defVar(ncid, 'av_angle_bin', float_precision, [dimid_angle]); -varid_colind = netcdf.defVar(ncid, 'colind', float_precision, [dimid_grid]); -varid_rowind = netcdf.defVar(ncid, 'rowind', float_precision, [dimid_grid]); -varid_lon = netcdf.defVar(ncid, 'lon', float_precision, [dimid_lon]); -varid_lat = netcdf.defVar(ncid, 'lat', float_precision, [dimid_lat]); - -% Create a new group called 'data' -% groupname = 'data'; -% grpid = netcdf.defGrp(ncid,groupname); - -% varid_om = netcdf.defVar(grpid, 'o_mean', float_precision, [dimid_lon dimid_lat dimid_pentad]); -% varid_ov = netcdf.defVar(grpid, 'o_std', float_precision, [dimid_lon dimid_lat dimid_pentad]); -% varid_mm = netcdf.defVar(grpid, 'm_mean', float_precision, [dimid_lon dimid_lat dimid_pentad]); -% varid_mv = netcdf.defVar(grpid, 'm_std', float_precision, [dimid_lon dimid_lat dimid_pentad]); -% varid_ndata = netcdf.defVar(grpid, 'n_data', float_precision, [dimid_lon dimid_lat dimid_pentad]); - -varid_om = netcdf.defVar(ncid, 'o_mean', float_precision, [dimid_lat dimid_lon dimid_pentad]); -varid_ov = netcdf.defVar(ncid, 'o_std', float_precision, [dimid_lat dimid_lon dimid_pentad]); -varid_mm = netcdf.defVar(ncid, 'm_mean', float_precision, [dimid_lat dimid_lon dimid_pentad]); -varid_mv = netcdf.defVar(ncid, 'm_std', float_precision, [dimid_lat dimid_lon dimid_pentad]); -varid_ndata = netcdf.defVar(ncid, 'n_data', float_precision, [dimid_lat dimid_lon dimid_pentad]); - - -% end define mode -netcdf.endDef(ncid); - -% write data -netcdf.putVar(ncid, varid_asc_flag, asc_flag); -netcdf.putVar(ncid, varid_version, version); -netcdf.putVar(ncid, varid_pentad, pentad); -netcdf.putVar(ncid, varid_start_time, tmp_start_time); -netcdf.putVar(ncid, varid_end_time, tmp_end_time); -netcdf.putVar(ncid, varid_N_grid, N_grid); -netcdf.putVar(ncid, varid_N_angle, N_angle); - -if (~(strcmp(data_product,'scaling') && strcmp(write_ind_latlon,'latlon_id') && nargin == 14)) - netcdf.putVar(ncid, varid_obsnum, obsnum); -else - netcdf.putVar(ncid, varid_obsnum, permute(obsnum, [2 1])); -end - -netcdf.putVar(ncid, varid_av_angle_bin, squeeze(av_angle_bin(:))); - - if (N_grid >= 1) - -netcdf.putVar(ncid, varid_colind, colind); -netcdf.putVar(ncid, varid_rowind, rowind); -netcdf.putVar(ncid, varid_lon, ll_lons); -netcdf.putVar(ncid, varid_lat, ll_lats); - -if N_pentad ==1 - - data_out = ones(5,N_lat, N_lon) * -999.0; - - for n = 1:5 - for i = 1:length(colind) - data_out(n,rowind(i),colind(i)) = data(n,i); - end - end - - netcdf.putVar(ncid,varid_om,data_out(1, :, :)); - netcdf.putVar(ncid,varid_ov,data_out(2, :, :)); - netcdf.putVar(ncid,varid_mm,data_out(3, :, :)); - netcdf.putVar(ncid,varid_mv,data_out(4, :, :)); - netcdf.putVar(ncid,varid_ndata,data_out(5, :, :)); -else - - data_out = ones(5, N_lat,N_lon,N_pentad) * -999.0; - - for n = 1:5 - for i = 1:length(colind) - data_out(n,rowind(i),colind(i),:) = data(n,i,:); - end - end - - netcdf.putVar(ncid,varid_om,data_out(1, :, :,:)); - netcdf.putVar(ncid,varid_ov,data_out(2, :, :,:)); - netcdf.putVar(ncid,varid_mm,data_out(3, :, :,:)); - netcdf.putVar(ncid,varid_mv,data_out(4, :, :,:)); - netcdf.putVar(ncid,varid_ndata,data_out(5, :, :,:)); -end - - else - netcdf.putVar(ncid, varid_colind, 0.0); - netcdf.putVar(ncid, varid_rowind, 0.0); - netcdf.putVar(ncid, varid_lon, 0.0); - netcdf.putVar(ncid, varid_lat, 0.0) - - netcdf.putVar(ncid,varid_om,-999.0); - netcdf.putVar(ncid,varid_ov,-999.0); - netcdf.putVar(ncid,varid_mm,-999.0); - netcdf.putVar(ncid,varid_mv,-999.0); - netcdf.putVar(ncid,varid_ndata,-999.0); - end - -% close netCDF file -netcdf.close(ncid); - - end - - - diff --git a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/write_netcdf_latlon_grid.m b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/write_netcdf_latlon_grid.m new file mode 100644 index 00000000..348a9b6d --- /dev/null +++ b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/write_netcdf_latlon_grid.m @@ -0,0 +1,222 @@ +function [] = write_netcdf_latlon_grid( fname, colind, rowind,ll_lons, ll_lats, ... + data, pentad, start_time, end_time, overwrite, N_out_fields, ll_lon, ll_lat, d_lon, d_lat ) + +int_precision = 'NC_INT'; % precision of fortran tag +float_precision = 'NC_DOUBLE'; % precision of data in input file + +% Define the compression level (0-9, where 0 is no compression and 9 is maximum compression) +compression_level = 5; + +version = 0; + +% check dimensions +if size(data,1)~=N_out_fields + error('ERROR: size of data incompatible with N_out_fields') +end + +% check for presence of optional input "overwrite" +if ~exist('overwrite','var') + overwrite = 0; % default: do NOT overwrite existing files +end + +% check if file exists +if exist(fname,'file') + if overwrite==0 + disp(['RETURNING!!! -- NOT OVERWRITING EXISTING FILE ', fname]) + return + else + disp(['OVERWRITING ', fname]) + end +else + disp(['writing ', fname]) +end + +% Convert the cell arrays to matrices using cell2mat (to deal with all_pentad case) +year_mat = cell2mat({start_time.year}'); +month_mat = cell2mat({start_time.month}'); +day_mat = cell2mat({start_time.day}'); +hour_mat = cell2mat({start_time.hour}'); +min_mat = cell2mat({start_time.min}'); +sec_mat = cell2mat({start_time.sec}'); +% Use the matrices as input to the datetime function +d = datetime(year_mat, month_mat, day_mat, hour_mat, min_mat, sec_mat); +% Convert to serial date number +serialNum = datenum(d); +% Subtract serial date number of January 1, 1950 +daysSince1950 = serialNum - datenum('January 1, 1950'); +tmp_start_time = daysSince1950; + +% Convert the cell arrays to matrices using cell2mat (to deal with all_pentad case) +year_mat = cell2mat({end_time.year}'); +month_mat = cell2mat({end_time.month}'); +day_mat = cell2mat({end_time.day}'); +hour_mat = cell2mat({end_time.hour}'); +min_mat = cell2mat({end_time.min}'); +sec_mat = cell2mat({end_time.sec}'); +% Use the matrices as input to the datetime function +d = datetime(year_mat, month_mat, day_mat, hour_mat, min_mat, sec_mat); +% Convert to serial date number +serialNum = datenum(d); +% Subtract serial date number of January 1, 1950 +daysSince1950 = serialNum - datenum('January 1, 1950'); +tmp_end_time = daysSince1950; + +N_lon = length(ll_lons); +N_lat = length(ll_lats); + +% Have we got multiple pentads +if ismatrix(data) + N_pentad = 1; +else + N_pentad = size(data,3); +end + +% create netCDF file +netcdf.setDefaultFormat('FORMAT_NETCDF4'); +ncid = netcdf.create(fname, 'NETCDF4'); + +% define dimensions +dimid_pentad = netcdf.defDim(ncid, 'pentad', N_pentad); +dimid_lon = netcdf.defDim(ncid, 'lon', N_lon); +dimid_lat = netcdf.defDim(ncid, 'lat', N_lat); + +% define variables +varid_version = netcdf.defVar(ncid, 'version', int_precision, []); +varid_ll_lon = netcdf.defVar(ncid, 'll_lon', float_precision, []); +netcdf.putAtt(ncid, varid_ll_lon, 'standard_name','longitude of lower left corner'); +netcdf.putAtt(ncid, varid_ll_lon, 'long_name','longitude of lower left corner'); +netcdf.putAtt(ncid, varid_ll_lon, 'units','degrees_east'); +netcdf.putAtt(ncid, varid_ll_lon, 'axis','X'); +varid_ll_lat = netcdf.defVar(ncid, 'll_lat', float_precision, []); +netcdf.putAtt(ncid, varid_ll_lat, 'standard_name','latitude of lower left corner'); +netcdf.putAtt(ncid, varid_ll_lat, 'long_name','latitude of lower left corner'); +netcdf.putAtt(ncid, varid_ll_lat, 'units','degrees_north'); +netcdf.putAtt(ncid, varid_ll_lat, 'axis','Y'); +varid_d_lon = netcdf.defVar(ncid, 'd_lon', float_precision, []); +netcdf.putAtt(ncid, varid_d_lon, 'standard_name','longitude grid spacing'); +netcdf.putAtt(ncid, varid_d_lon, 'long_name','longitude grid spacing'); +netcdf.putAtt(ncid, varid_d_lon, 'units','degrees'); +netcdf.putAtt(ncid, varid_d_lon, 'axis','X'); +varid_d_lat = netcdf.defVar(ncid, 'd_lat', float_precision, []); +netcdf.putAtt(ncid, varid_d_lat, 'standard_name','latitude grid spacing'); +netcdf.putAtt(ncid, varid_d_lat, 'long_name','latitude grid spacing'); +netcdf.putAtt(ncid, varid_d_lat, 'units','degrees'); +netcdf.putAtt(ncid, varid_d_lat, 'axis','Y'); +varid_pentad = netcdf.defVar(ncid, 'pentad', int_precision, [dimid_pentad]); +netcdf.putAtt(ncid, varid_pentad, 'standard_name','pentad'); +netcdf.putAtt(ncid, varid_pentad, 'long_name','pentad'); +netcdf.putAtt(ncid, varid_pentad, 'units','1'); +netcdf.putAtt(ncid, varid_pentad, 'axis','T'); +varid_start_time = netcdf.defVar(ncid, 'start_time', float_precision, [dimid_pentad]); +netcdf.putAtt(ncid, varid_start_time, 'standard_name','start time'); +netcdf.putAtt(ncid, varid_start_time, 'long_name','start time'); +netcdf.putAtt(ncid, varid_start_time, 'axis','T'); +netcdf.putAtt(ncid, varid_start_time, 'units','days since 1950-01-01 00:00:00.0 +0000'); +varid_end_time = netcdf.defVar(ncid, 'end_time',float_precision, [dimid_pentad]); +netcdf.putAtt(ncid, varid_end_time, 'standard_name','end time'); +netcdf.putAtt(ncid, varid_end_time, 'long_name','end time'); +netcdf.putAtt(ncid, varid_end_time, 'axis','T'); +netcdf.putAtt(ncid, varid_end_time, 'units','days since 1950-01-01 00:00:00.0 +0000'); +varid_lon = netcdf.defVar(ncid, 'lon', float_precision, [dimid_lon]); +netcdf.putAtt(ncid, varid_lon, 'standard_name','longitude'); +netcdf.putAtt(ncid, varid_lon, 'long_name','loswer left longitude of gridcell'); +netcdf.putAtt(ncid, varid_lon, 'units','degrees_east'); +netcdf.putAtt(ncid, varid_lon, 'axis','X'); +varid_lat = netcdf.defVar(ncid, 'lat', float_precision, [dimid_lat]); +netcdf.putAtt(ncid, varid_lat, 'standard_name','latitude'); +netcdf.putAtt(ncid, varid_lat, 'long_name','loswer left latitude of gridcell'); +netcdf.putAtt(ncid, varid_lat, 'units','degrees_north'); +netcdf.putAtt(ncid, varid_lat, 'axis','Y'); +varid_om = netcdf.defVar(ncid, 'o_mean', float_precision, [dimid_lat dimid_lon dimid_pentad]); +netcdf.defVarDeflate(ncid,varid_om,true,true,compression_level); +netcdf.putAtt(ncid, varid_om, 'standard_name','observation mean'); +netcdf.putAtt(ncid, varid_om, 'long_name','Observation mean for pentad calculated over all years for window length'); +netcdf.putAtt(ncid, varid_om, 'units','Degree of saturation (0-1)'); +varid_ov = netcdf.defVar(ncid, 'o_std', float_precision, [dimid_lat dimid_lon dimid_pentad]); +netcdf.defVarDeflate(ncid,varid_ov,true,true,compression_level); +netcdf.putAtt(ncid, varid_ov, 'standard_name','observation standard deviation'); +netcdf.putAtt(ncid, varid_ov, 'long_name','Observation standard deviation for pentad calculated over all years for window length'); +netcdf.putAtt(ncid, varid_ov, 'units','Degree of saturation (0-1)'); +varid_mm = netcdf.defVar(ncid, 'm_mean', float_precision, [dimid_lat dimid_lon dimid_pentad]); +netcdf.defVarDeflate(ncid,varid_mm,true,true,compression_level); +netcdf.putAtt(ncid, varid_mm, 'standard_name','model mean'); +netcdf.putAtt(ncid, varid_mm, 'long_name','Model mean for pentad calculated over all years for window length'); +netcdf.putAtt(ncid, varid_mm, 'units','Surface soil moisture (m^3 m^-3)'); +varid_mv = netcdf.defVar(ncid, 'm_std', float_precision, [dimid_lat dimid_lon dimid_pentad]); +netcdf.defVarDeflate(ncid,varid_mv,true,true,compression_level); +netcdf.putAtt(ncid, varid_mv, 'standard_name','model standard deviation'); +netcdf.putAtt(ncid, varid_mv, 'long_name','Model standard deviation for pentad calculated over all years for window length'); +netcdf.putAtt(ncid, varid_mv, 'units','Surface soil moisture (m^3 m^-3)'); +varid_mi = netcdf.defVar(ncid, 'm_min', float_precision, [dimid_lat dimid_lon]); +netcdf.defVarDeflate(ncid,varid_mi,true,true,compression_level); +netcdf.putAtt(ncid, varid_mi, 'standard_name','model minimum'); +netcdf.putAtt(ncid, varid_mi, 'long_name','Model minimum calculated over all years'); +netcdf.putAtt(ncid, varid_mi, 'units','Surface soil moisture (m^3 m^-3)'); +varid_ma = netcdf.defVar(ncid, 'm_max', float_precision, [dimid_lat dimid_lon]); +netcdf.defVarDeflate(ncid,varid_ma,true,true,compression_level); +netcdf.putAtt(ncid, varid_ma, 'standard_name','model maximum'); +netcdf.putAtt(ncid, varid_ma, 'long_name','Model maximum calculated over all years'); +netcdf.putAtt(ncid, varid_ma, 'units','Surface soil moisture (m^3 m^-3)'); +varid_ndata = netcdf.defVar(ncid, 'n_data', float_precision, [dimid_lat dimid_lon dimid_pentad]); +netcdf.defVarDeflate(ncid,varid_ndata,true,true,compression_level); +netcdf.putAtt(ncid, varid_ndata, 'standard_name','number of data points'); +netcdf.putAtt(ncid, varid_ndata, 'long_name','Number of data points for pentad calculated over all years for window length'); +netcdf.putAtt(ncid, varid_ndata, 'units','1'); + +% end define mode +netcdf.endDef(ncid); + +% write data +netcdf.putVar(ncid, varid_pentad, pentad); +netcdf.putVar(ncid, varid_start_time, tmp_start_time); +netcdf.putVar(ncid, varid_end_time, tmp_end_time); + +netcdf.putVar(ncid, varid_lon, ll_lons); +netcdf.putVar(ncid, varid_lat, ll_lats); +netcdf.putVar(ncid, varid_ll_lon, ll_lon); +netcdf.putVar(ncid, varid_ll_lat, ll_lat); +netcdf.putVar(ncid, varid_d_lon, d_lon); +netcdf.putVar(ncid, varid_d_lat, d_lat); + +if N_pentad ==1 + + data_out = ones(N_out_fields,N_lat, N_lon) * -999.0; + + for n = 1:N_out_fields + for i = 1:length(colind) + data_out(n,rowind(i),colind(i)) = data(n,i); + end + end + + netcdf.putVar(ncid,varid_om,data_out(1, :, :)); + netcdf.putVar(ncid,varid_ov,data_out(2, :, :)); + netcdf.putVar(ncid,varid_mm,data_out(3, :, :)); + netcdf.putVar(ncid,varid_mv,data_out(4, :, :)); + netcdf.putVar(ncid,varid_mi,data_out(6, :, :)); + netcdf.putVar(ncid,varid_ma,data_out(7, :, :)); + netcdf.putVar(ncid,varid_ndata,data_out(5, :, :)); +else + + data_out = ones(N_out_fields, N_lat,N_lon,N_pentad) * -999.0; + + for n = 1:N_out_fields + for i = 1:length(colind) + data_out(n,rowind(i),colind(i),:) = data(n,i,:); + end + end + + netcdf.putVar(ncid,varid_om,data_out(1, :, :,:)); + netcdf.putVar(ncid,varid_ov,data_out(2, :, :,:)); + netcdf.putVar(ncid,varid_mm,data_out(3, :, :,:)); + netcdf.putVar(ncid,varid_mv,data_out(4, :, :,:)); + netcdf.putVar(ncid,varid_ndata,data_out(5, :, :,:)) + netcdf.putVar(ncid,varid_ma, max(data_out(7, :, :,:),[],4)); % Max over all pentads, always only 2D + min_data = squeeze(data_out(6, :, :,:)); min_data(min_data < -9998) = NaN; % Need to switch current missing value to NaN before calculating min + min_data_out = min(min_data,[],3); min_data_out(isnan(min_data_out)) = -9999.; + netcdf.putVar(ncid,varid_mi,min_data_out); % Min over all pentads, always only 2D +end + +% close netCDF file +netcdf.close(ncid); + +end diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index f6039a60..4ac7100c 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -8300,8 +8300,8 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & ierr = nf90_inq_varid(ncid, 'll_lon', ll_lon_varid) ierr = nf90_inq_varid(ncid, 'll_lat', ll_lat_varid) - ierr = nf90_inq_varid(ncid, 'dlon', dlon_varid) - ierr = nf90_inq_varid(ncid, 'dlat', dlat_varid) + ierr = nf90_inq_varid(ncid, 'd_lon', dlon_varid) + ierr = nf90_inq_varid(ncid, 'd_lat', dlat_varid) ! Get the dimension sizes @@ -8383,18 +8383,18 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & if ( abs(tile_coord(i)%com_lat-sclprm_lat(j_ind))>tol .or. & abs(tile_coord(i)%com_lon-sclprm_lon(i_ind))>tol ) then - - err_msg = 'something wrong' - call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + + err_msg = 'Lat/lon diff beyond tolerance' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) end if ! Check for no-data-values in observation and fit parameters ! (any negative number could be no-data-value for observations) - if ( sclprm_mean_obs(j_ind, i_ind)>0. .and. & - sclprm_mean_mod(j_ind, i_ind)>0. .and. & - sclprm_std_obs(j_ind, i_ind)>=0. .and. & + if ( sclprm_mean_obs(j_ind, i_ind)>0. .and. & + sclprm_mean_mod(j_ind, i_ind)>0. .and. & + sclprm_std_obs(j_ind, i_ind)>=0. .and. & sclprm_std_mod(j_ind, i_ind)>=0. ) then ! Scale via standard normal deviates @@ -8407,10 +8407,14 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & ! Check of tmp_obs is within range of model climatology if (tmp_obs(i)sclprm_max_mod(j_ind, i_ind)) then + + elseif (tmp_obs(i)>sclprm_max_mod(j_ind, i_ind)) then + tmp_obs(i) = sclprm_max_mod(j_ind, i_ind) - end if + + end if ! Scale observation error std From 4b24e3191972654089afbb5ee78c547b8b783891 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Fri, 27 Oct 2023 17:33:06 -0400 Subject: [PATCH 176/308] fixed missing init of lat/lon in MODIS SCF reader; changed variable name for clarity (clsm_ensupd_read_obs.F90) --- .../clsm_ensupd_read_obs.F90 | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 0234f9a2..53488bdb 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -4951,6 +4951,9 @@ subroutine read_obs_MODIS_SCF( & std_MODIS_obs = this_obs_param%errstd MODIS_obs = 0. + MODIS_lon = 0. + MODIS_lat = 0. + N_obs_in_tile = 0 do kk=1,N_CMG_obs @@ -5109,7 +5112,7 @@ end subroutine localtime2longitude ! ***************************************************************** subroutine read_MODIS_SCF_hdf( fname, lon_min, lon_max, lat_min, lat_max, & - N_good_data, MODIS_lon, MODIS_lat, MODIS_SCF ) + N_good_data, CMG_lon, CMG_lat, CMG_SCF ) ! read snow cover area fraction (SCF) obs from daily MODIS Terra or Aqua M?D10C1, version 6.1 ! - Terra: https://nsidc.org/data/mod10c1/versions/61 @@ -5132,7 +5135,7 @@ subroutine read_MODIS_SCF_hdf( fname, lon_min, lon_max, lat_min, lat_max, & integer, intent(out) :: N_good_data - real, dimension(:), intent(out) :: MODIS_lon, MODIS_lat, MODIS_SCF ! NOTE: lon-by-lat + real, dimension(:), intent(out) :: CMG_lon, CMG_lat, CMG_SCF ! NOTE: 1-dim array on CMG grid ! ------------------------------------------------- @@ -5264,7 +5267,7 @@ subroutine read_MODIS_SCF_hdf( fname, lon_min, lon_max, lat_min, lat_max, & ! ! dbg ! ! write (*,*) '###############################################################################' ! ! dbg ! ! write (*,*) Iam // '():' - ! ! dbg ! ! write (*,*) 'size(MODIS_SCF), N_lon, N_lat = ', size(MODIS_SCF), N_lon, N_lat + ! ! dbg ! ! write (*,*) 'size(CMG_SCF), N_lon, N_lat = ', size(CMG_SCF), N_lon, N_lat ! ! dbg ! ! write (*,*) 'lon_min, lon_max = ', lon_min, lon_max ! ! dbg ! ! write (*,*) 'lat_min, lat_max = ', lat_min, lat_max ! ! dbg ! ! write (*,*) 'start [lon, lat] = ', start @@ -5278,9 +5281,9 @@ subroutine read_MODIS_SCF_hdf( fname, lon_min, lon_max, lat_min, lat_max, & N_tmp = N_lon*N_lat - if ( (N_tmp /= size(MODIS_lon)) .or. & - (N_tmp /= size(MODIS_lat)) .or. & - (N_tmp /= size(MODIS_SCF)) ) then + if ( (N_tmp /= size(CMG_lon)) .or. & + (N_tmp /= size(CMG_lat)) .or. & + (N_tmp /= size(CMG_SCF)) ) then err_msg = 'inconsistent array dimensions' call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) @@ -5436,9 +5439,9 @@ subroutine read_MODIS_SCF_hdf( fname, lon_min, lon_max, lat_min, lat_max, & ! ! apply QC and put SCF obs into output array - MODIS_lon = SCF_nodata ! initialize - MODIS_lat = SCF_nodata ! initialize - MODIS_SCF = SCF_nodata ! initialize + CMG_lon = SCF_nodata ! initialize + CMG_lat = SCF_nodata ! initialize + CMG_SCF = SCF_nodata ! initialize kk = 0 ! initialize counter for "good" data @@ -5462,10 +5465,10 @@ subroutine read_MODIS_SCF_hdf( fname, lon_min, lon_max, lat_min, lat_max, & ! raw SCF value is for clear portion of grid cell only, need to normalize with Clear_Index - MODIS_SCF(kk) = real(Snow_Cover(ii,jj))/real(Clear_Index(ii,jj)) + CMG_SCF(kk) = real(Snow_Cover(ii,jj))/real(Clear_Index(ii,jj)) - MODIS_lon(kk) = lon_c(ii) - MODIS_lat(kk) = lat_c(jj) + CMG_lon(kk) = lon_c(ii) + CMG_lat(kk) = lat_c(jj) end if @@ -5488,7 +5491,6 @@ subroutine read_MODIS_SCF_hdf( fname, lon_min, lon_max, lat_min, lat_max, & end subroutine read_MODIS_SCF_hdf - ! ***************************************************************** ! ***************************************************************** subroutine read_obs_SMAP_FT( date_time, N_catd, this_obs_param, & From 6806251866462ccd2a30c524869ad8fd366af51a Mon Sep 17 00:00:00 2001 From: Weiyuan Jiang Date: Wed, 1 Nov 2023 13:38:55 -0400 Subject: [PATCH 177/308] fix import name --- src/Applications/LDAS_App/ldas_setup | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Applications/LDAS_App/ldas_setup b/src/Applications/LDAS_App/ldas_setup index 6da9a7d8..3dab5080 100755 --- a/src/Applications/LDAS_App/ldas_setup +++ b/src/Applications/LDAS_App/ldas_setup @@ -19,7 +19,7 @@ from collections import OrderedDict from dateutil.relativedelta import relativedelta from remap_utils import * from remap_catchANDcn import * -from process_rst import * +from remap_config_ldas import * """ This script is intended to be run from any installed directory with GEOSldas.x and ldas_setup From 9ad2a3640254eb63a2ea078fcf0043952b19086a Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Mon, 6 Nov 2023 15:51:22 -0500 Subject: [PATCH 178/308] minimal white space change --- src/Components/GEOSldas_GridComp/GEOS_LdasGridComp.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/GEOSldas_GridComp/GEOS_LdasGridComp.F90 b/src/Components/GEOSldas_GridComp/GEOS_LdasGridComp.F90 index c0608c08..4c1b13ed 100644 --- a/src/Components/GEOSldas_GridComp/GEOS_LdasGridComp.F90 +++ b/src/Components/GEOSldas_GridComp/GEOS_LdasGridComp.F90 @@ -405,7 +405,7 @@ subroutine Initialize(gc, import, export, clock, rc) type(grid_def_type) :: tile_grid_g, pert_grid_g type(grid_def_type) :: tile_grid_f, pert_grid_f - type(grid_def_type) :: pert_grid_l + type(grid_def_type) :: pert_grid_l type(date_time_type):: start_time type(ESMF_Time) :: CurrentTime From 552ba4644a2f33c1bd3a1d85fdcac387c2be9beb Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Mon, 6 Nov 2023 16:09:49 -0500 Subject: [PATCH 179/308] renamed output_incr_etc() to output_ObsFcstAna_wrapper() for clarity (clsm_ensupd_enkf_update.F90, GEOS_LandAssimGridComp.F90) --- .../GEOS_LandAssimGridComp.F90 | 4 +- .../clsm_ensupd_enkf_update.F90 | 101 +----------------- 2 files changed, 6 insertions(+), 99 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 index 4d4d67c5..7aab782c 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 @@ -62,7 +62,7 @@ module GEOS_LandAssimGridCompMod use clsm_ensupd_glob_param, only: echo_clsm_ensupd_glob_param use clsm_ensupd_enkf_update, only: get_enkf_increments use clsm_ensupd_enkf_update, only: apply_enkf_increments - use clsm_ensupd_enkf_update, only: output_incr_etc + use clsm_ensupd_enkf_update, only: output_ObsFcstAna_wrapper use clsm_ensupd_enkf_update, only: write_smapL4SMaup use clsm_ensdrv_out_routines, only: init_log, GEOS_output_smapL4SMlmc use clsm_ensdrv_drv_routines, only: recompute_diagS @@ -1936,7 +1936,7 @@ subroutine RUN ( GC, IMPORT, EXPORT, CLOCK, RC ) if (.true.) then ! replace obsolete check for analysis time with "if true" to keep indents - call output_incr_etc( out_ObsFcstAna, & + call output_ObsFcstAna_wrapper( out_ObsFcstAna, & date_time_new, trim(exp_id), & N_obsl, N_obs_param, NUM_ENSEMBLE, & N_catl, tile_coord_l, & diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 index 54c430e6..8982e250 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 @@ -132,7 +132,7 @@ module clsm_ensupd_enkf_update public :: get_enkf_increments public :: apply_enkf_increments - public :: output_incr_etc + public :: output_ObsFcstAna_wrapper public :: write_smapL4SMaup contains @@ -1614,7 +1614,7 @@ end subroutine output_ObsFcstAna ! ********************************************************************** - subroutine output_incr_etc( out_ObsFcstAna, & + subroutine output_ObsFcstAna_wrapper( out_ObsFcstAna, & date_time, exp_id, & N_obsl, N_obs_param, N_ens, & N_catl, tile_coord_l, & @@ -1675,7 +1675,7 @@ subroutine output_incr_etc( out_ObsFcstAna, & integer :: N_obsl_tmp - character(len=*), parameter :: Iam = 'output_incr_etc' + character(len=*), parameter :: Iam = 'output_ObsFcstAna_wrapper' ! -------------------------------------------------------------- @@ -1710,100 +1710,7 @@ subroutine output_incr_etc( out_ObsFcstAna, & end if - ! ---------------------------------------------------------------- - - ! output ens avg increments - -!! if (out_incr) then -!! -!! ! compute increments for local domain -!! -!! do i=1,N_catl -!! cat_progn_incr_ensavg(i) = 0. -!! do n_e=1,N_ens -!! cat_progn_incr_ensavg(i) = cat_progn_incr_ensavg(i) & -!! + cat_progn_incr(i,n_e) -!! end do -!! cat_progn_incr_ensavg(i) = cat_progn_incr_ensavg(i)/real(N_ens) -!! end do -!! -!! -!! ! gather and write to file -!! -!! file_tag = 'ldas_incr' -!! dir_name = 'ana' -!! -!! if (root_proc) allocate(cat_progn_incr_f(N_catf)) -!! -!!#ifdef LDAS_MPI -!! -!! call MPI_GATHERV( & -!! cat_progn_incr_ensavg, N_catl, MPI_cat_progn_type, & -!! cat_progn_incr_f, N_catl_vec, low_ind-1, MPI_cat_progn_type, & -!! 0, mpicomm, mpierr ) -!! -!!#else -!! cat_progn_incr_f = cat_progn_incr_ensavg -!!#endif -!! if (root_proc) then -!! -!! -!! select case (out_incr_format) -!! -!! case (0) -!! -!! ! output increments in LDASsa domain and in LDASsa tile order (standard LDASsa) -!! if(present(rf2f)) then -!! allocate(cat_progn_incr_tmp(N_catf)) -!! cat_progn_incr_tmp(:) = cat_progn_incr_f(rf2f(:)) -!! cat_progn_incr_f = cat_progn_incr_tmp -!! deallocate(cat_progn_incr_tmp) -!! endif -!! -!! call io_rstrt( 'w', work_path, exp_id, -1, date_time, & -!! N_catf, cat_progn_incr_f, file_tag, dir_name=dir_name) -!! -!! case (1) -!! -!! ! output increments on global domain in GEOS-5 global tile order -!! ! suitable for reading into GEOS-5 GCM as land incremental analysis -!! ! update (LIAU) -!! -!! allocate(cat_progn_incr_g(N_catg)) -!! -!! ! initialize -!! -!! do i=1,N_catg -!! cat_progn_incr_g(i) = 0.0 -!! end do -!! -!! ! reorder increments to GEOS-5 gcm global tile order -!! -!! do i=1,N_catf -!! cat_progn_incr_g(f2g(i)) = cat_progn_incr_f(i) -!! end do -!! -!! file_tag = trim(file_tag) // 'LIAU' -!! -!! call io_rstrt( 'w', work_path, exp_id, -1, date_time, & -!! N_catg, cat_progn_incr_g, file_tag, dir_name=dir_name, & -!! is_little_endian=.true. ) -!! -!! deallocate(cat_progn_incr_g) -!! -!! case default -!! -!! call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'unknown out_incr_format') -!! -!! end select -!! -!! deallocate(cat_progn_incr_f) -!! -!! end if ! root_proc -!! -!! end if ! out_incr - - end subroutine output_incr_etc + end subroutine output_ObsFcstAna_wrapper ! ********************************************************************** From 3ca8d48a505bf46437426e3252d472648d121587 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Mon, 6 Nov 2023 16:15:33 -0500 Subject: [PATCH 180/308] renamed max_cat_diagS() to cat_diagS_max() for consistency with cat_diagS_sqrt() (catch_types.F90, GEOS_LandAssimGridComp.F90) --- .../GEOS_LandAssimGridComp.F90 | 5 ++-- .../GEOSldas_GridComp/Shared/catch_types.F90 | 27 +++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 index 7aab782c..896f1410 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 @@ -1,6 +1,7 @@ #include "MAPL_Generic.h" !============================================================================= + module GEOS_LandAssimGridCompMod !BOP @@ -51,7 +52,7 @@ module GEOS_LandAssimGridCompMod use catch_types, only: cat_progn_type use catch_types, only: cat_param_type use catch_types, only: cat_diagS_type - use catch_types, only: max_cat_diagS + use catch_types, only: cat_diagS_max use catch_types, only: cat_diagS_sqrt use catch_types, only: assignment(=), operator (+), operator (-), operator (*), operator (/) use clsm_bias_routines, only: initialize_obs_bias @@ -2010,7 +2011,7 @@ subroutine RUN ( GC, IMPORT, EXPORT, CLOCK, RC ) cat_diagS_ensavg(ii) = cat_diagS_ensavg(ii)/real(NUM_ENSEMBLE) ! normalize --> ens avg - cat_diagS_ensstd(ii) = cat_diagS_sqrt( max_cat_diagS(0.0, cat_diagS_ensstd(ii)/Nm1 - NdivNm1*(cat_diagS_ensavg(ii)*cat_diagS_ensavg(ii))) ) + cat_diagS_ensstd(ii) = cat_diagS_sqrt( cat_diagS_max(0.0, cat_diagS_ensstd(ii)/Nm1 - NdivNm1*(cat_diagS_ensavg(ii)*cat_diagS_ensavg(ii))) ) end do diff --git a/src/Components/GEOSldas_GridComp/Shared/catch_types.F90 b/src/Components/GEOSldas_GridComp/Shared/catch_types.F90 index 569050b7..d26e5521 100644 --- a/src/Components/GEOSldas_GridComp/Shared/catch_types.F90 +++ b/src/Components/GEOSldas_GridComp/Shared/catch_types.F90 @@ -38,10 +38,9 @@ module catch_types public :: assignment (=), operator (*), operator (/), operator (+), operator (-) - public :: cat_diagS_sqrt + public :: cat_diagS_sqrt, cat_diagS_max public :: catprogn2wesn, catprogn2htsn, catprogn2sndz, catprogn2ghtcnt - public :: max_cat_diagS ! ------------------------------------------------------------------------- ! @@ -1370,37 +1369,37 @@ end function catprogn2ghtcnt ! *********************************************************************** - function max_cat_diagS( scalar, cat_diagS ) + function cat_diagS_max( scalar, cat_diagS ) implicit none - type(cat_diagS_type) :: max_cat_diagS + type(cat_diagS_type) :: cat_diagS_max type(cat_diagS_type), intent(in) :: cat_diagS real, intent(in) :: scalar integer :: i ! local - max_cat_diagS%ar1 = max(scalar, cat_diagS%ar1) - max_cat_diagS%ar2 = max(scalar, cat_diagS%ar2) + cat_diagS_max%ar1 = max(scalar, cat_diagS%ar1) + cat_diagS_max%ar2 = max(scalar, cat_diagS%ar2) - max_cat_diagS%asnow = max(scalar, cat_diagS%asnow) + cat_diagS_max%asnow = max(scalar, cat_diagS%asnow) - max_cat_diagS%sfmc = max(scalar, cat_diagS%sfmc) - max_cat_diagS%rzmc = max(scalar, cat_diagS%rzmc) - max_cat_diagS%prmc = max(scalar, cat_diagS%prmc) + cat_diagS_max%sfmc = max(scalar, cat_diagS%sfmc) + cat_diagS_max%rzmc = max(scalar, cat_diagS%rzmc) + cat_diagS_max%prmc = max(scalar, cat_diagS%prmc) - max_cat_diagS%tsurf = max(scalar, cat_diagS%tsurf) + cat_diagS_max%tsurf = max(scalar, cat_diagS%tsurf) do i=1,N_gt - max_cat_diagS%tp(i) = max(scalar, cat_diagS%tp(i)) + cat_diagS_max%tp(i) = max(scalar, cat_diagS%tp(i)) end do do i=1,N_snow - max_cat_diagS%tpsn(i) = max(scalar, cat_diagS%tpsn(i)) + cat_diagS_max%tpsn(i) = max(scalar, cat_diagS%tpsn(i)) end do - end function max_cat_diagS + end function cat_diagS_max end module catch_types From 288913af6dda986f18f50bcd3226abf44f3d5fbd Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Mon, 6 Nov 2023 16:50:50 -0500 Subject: [PATCH 181/308] fixed typos in comments, white-space/indent changes (GEOS_LandAssimGridComp.F90, clsm_ensupd_enkf_update.F90, GEOS_LandPertGridComp.F90, LDAS_PertRoutines.F90, land_pert.F90, random_fields.F90) --- .../GEOS_LandAssimGridComp.F90 | 9 +- .../clsm_ensupd_enkf_update.F90 | 20 ++--- .../GEOS_LandPertGridComp.F90 | 6 +- .../LDAS_PertRoutines.F90 | 2 +- .../GEOSlandpert_GridComp/land_pert.F90 | 69 +++++++++------ .../GEOSlandpert_GridComp/random_fields.F90 | 85 ++++++++++--------- 6 files changed, 107 insertions(+), 84 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 index 896f1410..e4519095 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 @@ -149,7 +149,7 @@ subroutine SetServices ( GC, RC ) ! Local Variables type(MAPL_MetaComp), pointer :: MAPL=>null() character(len=ESMF_MAXSTR) :: LAND_ASSIM_STR, mwRTM_file - character(len=ESMF_MAXSTR) :: ensid_string,childname + character(len=ESMF_MAXSTR) :: ensid_string, childname integer :: i, ens_id_width, FIRST_ENS_ID, NUM_ENSEMBLE integer :: ens_id, export_id @@ -2011,8 +2011,11 @@ subroutine RUN ( GC, IMPORT, EXPORT, CLOCK, RC ) cat_diagS_ensavg(ii) = cat_diagS_ensavg(ii)/real(NUM_ENSEMBLE) ! normalize --> ens avg - cat_diagS_ensstd(ii) = cat_diagS_sqrt( cat_diagS_max(0.0, cat_diagS_ensstd(ii)/Nm1 - NdivNm1*(cat_diagS_ensavg(ii)*cat_diagS_ensavg(ii))) ) - + cat_diagS_ensstd(ii) = & + cat_diagS_sqrt( & + cat_diagS_max( 0., cat_diagS_ensstd(ii)/Nm1 - NdivNm1*(cat_diagS_ensavg(ii)*cat_diagS_ensavg(ii))) & + ) + end do else ! NUM_ENSEMBLE = 1 diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 index 8982e250..93b30847 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 @@ -1397,32 +1397,34 @@ subroutine output_ObsFcstAna(date_time, exp_id, & ! - reichle, 16 Jun 2011 implicit none + + type(date_time_type), intent(in) :: date_time + + character(*), intent(in) :: exp_id - type(date_time_type), intent(in) :: date_time - character(*), intent(in) :: exp_id - - integer, intent(in) :: N_obsl, N_obs_param + integer, intent(in) :: N_obsl, N_obs_param type(obs_type), dimension(N_obsl), intent(in) :: Observations_l - integer, dimension(:), optional, intent(in) :: rf2f + integer, dimension(:), optional, intent(in) :: rf2f ! --------------------- ! locals - character(40), parameter :: file_tag = 'ldas_ObsFcstAna' - character(40), parameter :: dir_name = 'ana' + character(40), parameter :: file_tag = 'ldas_ObsFcstAna' + character(40), parameter :: dir_name = 'ana' type(obs_type), dimension(:), allocatable :: Observations_f, Observations_tmp integer :: n, N_obsf - integer, dimension(:), allocatable :: rf_tilenums, tilenums + integer, dimension(:), allocatable :: rf_tilenums, tilenums integer, dimension(numprocs) :: N_obsl_vec, tmp_low_ind character(300) :: fname + #ifdef LDAS_MPI integer :: this_species, ind_tmp, j @@ -1433,8 +1435,6 @@ subroutine output_ObsFcstAna(date_time, exp_id, & #endif - - ! -------------------------------------------------------------------- if (logit) write (logunit,*) 'writing ' // trim(file_tag) //' file' diff --git a/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/GEOS_LandPertGridComp.F90 b/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/GEOS_LandPertGridComp.F90 index 94d542c0..e2d7cf87 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/GEOS_LandPertGridComp.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/GEOS_LandPertGridComp.F90 @@ -860,9 +860,9 @@ subroutine Initialize(gc, import, export, clock, rc) ! Misc variables integer :: model_dtstep - integer :: land_nt_local,n,m,i1, in, j1, jn + integer :: land_nt_local, m, n, i1, in, j1, jn logical :: IAmRoot, f_exist - integer :: n_lon,n_lat, n_lon_g, n_lat_g + integer :: n_lon, n_lat, n_lon_g, n_lat_g integer, allocatable :: pert_rseed(:) type(ESMF_Grid) :: Grid character(len=ESMF_MAXSTR) :: id_string @@ -2662,7 +2662,7 @@ subroutine Finalize(gc, import, export, clock, rc) type(MAPL_LocStream) :: locstream type(TILECOORD_WRAP) :: tcwrap type(T_TILECOORD_STATE), pointer :: tcinternal - integer :: m,land_nt_local, ens_id_width + integer :: m, land_nt_local, ens_id_width integer :: nfpert, nppert, n_tile type(tile_coord_type), pointer :: tile_coord_f(:)=>null() diff --git a/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/LDAS_PertRoutines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/LDAS_PertRoutines.F90 index fafee341..a351dde8 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/LDAS_PertRoutines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/LDAS_PertRoutines.F90 @@ -2017,7 +2017,7 @@ end subroutine echo_pert_param ! WY noted :: -l is changed to _g. Only read part was kept subroutine io_pert_rstrt( action, work_path, exp_id, ens_id, & - date_time, pert_grid_g, pert_grid_f, & + date_time, pert_grid_g, pert_grid_f, & N_force_pert, N_progn_pert, Pert_rseed, & Force_pert_ntrmdt_g, Progn_pert_ntrmdt_g, rc ) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/land_pert.F90 b/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/land_pert.F90 index ff4cfb5a..ee948e0e 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/land_pert.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/land_pert.F90 @@ -612,24 +612,30 @@ subroutine propagate_pert( & end do ! n=1,N_ens ! finalize rf - ! The rf map will be destroy in the finalize of GEOSLandperp_Gridcomp + ! The rf map will be destroyed in the finalize of GEOSLandperp_Gridcomp !call rf%finalize end do ! m=1,N_pert end subroutine propagate_pert + ! ****************************************************************************************** + subroutine calc_fft_grid(pert_param, pert_grid_f, Nx, Ny, N_x_fft, N_y_fft, xStride, yStride, rdlon, rdlat) - type(pert_param_type), intent(in) :: pert_param - type(grid_def_type), intent(in) :: pert_grid_f - integer, intent(out) :: Nx, Ny, N_x_fft, N_y_fft, xStride, yStride - real, intent(out) :: rdlon, rdlat - integer :: Nx_fft, Ny_fft + type(pert_param_type), intent(in) :: pert_param + type(grid_def_type), intent(in) :: pert_grid_f + + integer, intent(out) :: Nx, Ny, N_x_fft, N_y_fft, xStride, yStride + real, intent(out) :: rdlon, rdlat + + ! local variables + + integer :: Nx_fft, Ny_fft real, parameter :: mult_of_xcorr = 2. real, parameter :: mult_of_ycorr = 2. real, parameter :: coarsen_param = 0.8 - real :: xCorr, yCorr + real :: xCorr, yCorr xCorr = pert_param%xcorr yCorr = pert_param%ycorr @@ -661,6 +667,7 @@ subroutine calc_fft_grid(pert_param, pert_grid_f, Nx, Ny, N_x_fft, N_y_fft, xStr N_y_fft = 2**ceiling(log(real(Ny_fft))/log(2.)) end subroutine + ! ****************************************************************** subroutine truncate_std_normal( N_x, N_y, std_normal_max, grid_data ) @@ -1263,38 +1270,46 @@ end subroutine get_sqrt_corr_matrix ! ************************************************************************ function find_rf(Nx, Ny, Nx_fft, Ny_fft, comm) result (rf) - type(random_fields), pointer :: rf - integer, intent(in) :: Nx, Ny, Nx_fft, Ny_fft - integer, optional, intent(in) :: comm - + + type(random_fields), pointer :: rf + integer, intent(in) :: Nx, Ny, Nx_fft, Ny_fft + integer, optional, intent(in) :: comm + + ! local variables + type(StringRandom_fieldsMapIterator) :: iter Character(len=:), allocatable :: id_string type(random_fields) :: rf_tmp - + id_string = i_to_string(Nx)//":"//i_to_string(Ny)//":"//i_to_string(Nx_fft)//":"//i_to_string(Ny_fft) iter = random_fieldsMap%find(id_string) if (iter == random_fieldsMap%end() ) then - rf_tmp = random_fields(Nx, Ny, Nx_fft, Ny_fft, comm=comm) - call random_fieldsMap%insert(id_string, rf_tmp) - iter = random_fieldsMap%find(id_string) + rf_tmp = random_fields(Nx, Ny, Nx_fft, Ny_fft, comm=comm) + call random_fieldsMap%insert(id_string, rf_tmp) + iter = random_fieldsMap%find(id_string) endif rf => iter%value() - - end function - + + end function find_rf + + ! ************************************************************************ + subroutine clear_rf() - type(StringRandom_fieldsMapIterator) :: iter - type(random_fields), pointer :: rf_ptr + + type(StringRandom_fieldsMapIterator) :: iter + type(random_fields), pointer :: rf_ptr + iter = random_fieldsMap%begin() do while (iter /= random_fieldsMap%end()) - rf_ptr => iter%value() - call rf_ptr%finalize() - ! remove the files - call random_fieldsMap%erase(iter) - iter = random_fieldsMap%begin() + rf_ptr => iter%value() + call rf_ptr%finalize() + ! remove the files + call random_fieldsMap%erase(iter) + iter = random_fieldsMap%begin() enddo - end subroutine - + end subroutine clear_rf + + end module land_pert_routines ! *************************************************************************** diff --git a/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/random_fields.F90 b/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/random_fields.F90 index d270d04d..3ed12e69 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/random_fields.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/random_fields.F90 @@ -34,7 +34,7 @@ #include "unused_dummy.H" module random_fieldsMod - + #ifdef MKL_AVAILABLE use, intrinsic :: iso_c_binding, only: c_loc, c_f_pointer, c_ptr, c_sizeof, C_NULL_PTR use mpi @@ -46,7 +46,7 @@ module random_fieldsMod use nr_ran2_gasdev, ONLY: & NRANDSEED, & - nr_ran2_2d, & + nr_ran2_2d, & nr_gasdev use MAPL_ExceptionHandling @@ -69,15 +69,17 @@ module random_fieldsMod integer :: node_comm integer :: win type (c_ptr) :: base_address - + type(DFTI_DESCRIPTOR), pointer :: Desc_Handle type(DFTI_DESCRIPTOR), pointer :: Desc_Handle_dim1 type(DFTI_DESCRIPTOR), pointer :: Desc_Handle_dim2 integer, allocatable :: dim1_counts(:) integer, allocatable :: dim2_counts(:) #endif + contains -! procedure, public :: initialize + + ! procedure, public :: initialize procedure, public :: finalize procedure, public :: rfg2d_fft procedure, public :: generate_white_field @@ -90,24 +92,25 @@ module random_fieldsMod interface random_fields module procedure new_random_fields - end interface + end interface random_fields contains - + ! constructor (set parameter values), allocate memory function new_random_fields(Nx, Ny, Nx_fft, Ny_fft, comm, rc) result (rf) - + ! input/output variables [NEED class(random_fields) - ! instead of type(random_fields)] - F2003 quirk?!? - type(random_fields) :: rf - integer, intent(in) :: Nx, Ny, Nx_fft, Ny_fft - integer, optional, intent(in) :: comm + ! instead of type(random_fields)] - F2003 quirk?!? + type(random_fields) :: rf + integer, intent(in) :: Nx, Ny, Nx_fft, Ny_fft + integer, optional, intent(in) :: comm integer, optional, intent(out) :: rc - ! local variable + + ! local variables integer :: status, ierror - integer :: rank, npes, local_dim1, local_dim2, remainer + integer :: rank, npes, local_dim1, local_dim2, remainder integer :: Stride(2) - + ! set obj param vals rf%N_x = Nx rf%N_y = Ny @@ -124,11 +127,11 @@ function new_random_fields(Nx, Ny, Nx_fft, Ny_fft, comm, rc) result (rf) #ifdef MKL_AVAILABLE if (present(comm)) then rf%comm = comm - + call MPI_Comm_split_type(rf%comm, MPI_COMM_TYPE_SHARED, 0, MPI_INFO_NULL, rf%Node_Comm,ierror) - call MPI_Comm_size(rf%Node_Comm, npes,ierror) + call MPI_Comm_size(rf%Node_Comm, npes, ierror) call MPI_Comm_rank(rf%Node_Comm, rank, ierror) - + if (npes > minval([Nx_fft, Ny_fft]) ) then print*, " Two many processors are acquired in a node for parallel FFT" print*, " The number of processors acquired in a node should be smaller than or equal to FFT grid size: ", minval([Nx_fft, Ny_fft]) @@ -141,14 +144,14 @@ function new_random_fields(Nx, Ny, Nx_fft, Ny_fft, comm, rc) result (rf) allocate(rf%dim1_counts(npes),rf%dim2_counts(npes)) local_dim1 = Nx_fft/npes rf%dim1_counts = local_dim1 - remainer = mod(Nx_fft, npes) - rf%dim1_counts(1:remainer) = local_dim1 + 1 + remainder = mod(Nx_fft, npes) + rf%dim1_counts(1:remainder) = local_dim1 + 1 local_dim1 = rf%dim1_counts(rank+1) local_dim2 = Ny_fft/npes rf%dim2_counts = local_dim2 - remainer = mod(Ny_fft, npes) - rf%dim2_counts(1:remainer) = local_dim2 + 1 + remainder = mod(Ny_fft, npes) + rf%dim2_counts(1:remainder) = local_dim2 + 1 local_dim2 = rf%dim2_counts(rank+1) @@ -197,9 +200,9 @@ function new_random_fields(Nx, Ny, Nx_fft, Ny_fft, comm, rc) result (rf) #endif _RETURN(_SUCCESS) end function new_random_fields - - - + + ! ************************************************************************** + ! destructor - deallocate memory subroutine finalize(this, rc) @@ -212,26 +215,26 @@ subroutine finalize(this, rc) ! deallocate memory if(allocated(this%field1_fft)) deallocate(this%field1_fft) if(allocated(this%field2_fft)) deallocate(this%field2_fft) - + #ifdef MKL_AVAILABLE if (this%comm == MPI_COMM_NULL) then status = DftiFreeDescriptor(this%Desc_Handle) _VERIFY(status) else - + status = DftiFreeDescriptor(this%Desc_Handle_dim1) _VERIFY(status) status = DftiFreeDescriptor(this%Desc_Handle_dim2) _VERIFY(status) - + call this%win_deallocate( _RC) - + deallocate(this%dim1_counts, this%dim2_counts) endif #endif end subroutine finalize - + ! subroutine sqrt_gauss_spectrum_2d() ! @@ -264,17 +267,19 @@ end subroutine finalize ! lambda_y : decorrelation length in y direction ! ! modifies this%field1_fft + subroutine sqrt_gauss_spectrum_2d(this, lx, ly, dx, dy) ! input/output variables class(random_fields), intent(inout) :: this - real, intent(in) :: lx, ly, dx, dy + real, intent(in) :: lx, ly, dx, dy ! local variables - real :: dkx, dky, fac, lamx2dkx2, lamy2dky2 - real :: lx2kx2(this%N_x_fft), ly2ky2(this%N_y_fft) + real :: dkx, dky, fac, lamx2dkx2, lamy2dky2 + real :: lx2kx2(this%N_x_fft), ly2ky2(this%N_y_fft) integer :: i, j, i1, i2, rank, ierror - real :: var + real :: var + var = 1.0 ! start dkx = (TWO_PI)/(float(this%N_x_fft)*dx) @@ -319,7 +324,7 @@ subroutine sqrt_gauss_spectrum_2d(this, lx, ly, dx, dy) return end subroutine sqrt_gauss_spectrum_2d - + ! ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ! ---------------------------------------------------------------------- @@ -374,14 +379,14 @@ end subroutine sqrt_gauss_spectrum_2d ! (before re-scaling with sqrt(2)). ! The individual sample variances within each pair vary from ! realization to realization. - ! + subroutine rfg2d_fft(this, rseed, rfield, rfield2, lx, ly, dx, dy) - + ! input/output variables - class(random_fields), intent(inout) :: this ! ffield*_fft is modified - integer, intent(inout) :: rseed(NRANDSEED) ! nr_ran2 modifies rseed - real, dimension(this%N_x,this%N_y), intent(out) :: rfield, rfield2 - real, intent(in) :: lx, ly, dx, dy + class(random_fields), intent(inout) :: this ! ffield*_fft is modified + integer, intent(inout) :: rseed(NRANDSEED) ! nr_ran2 modifies rseed + real, dimension(this%N_x,this%N_y), intent(out) :: rfield, rfield2 + real, intent(in) :: lx, ly, dx, dy ! local variables !real :: theta, ran_num ! rng From b5fe7b17881dce61f1a8aa12c8948d11d49e1ecc Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Mon, 6 Nov 2023 16:56:57 -0500 Subject: [PATCH 182/308] minimal white-space changes (clsm_ensupd_upd_routines.F90) --- .../GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index d7940820..64b29673 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -1422,7 +1422,7 @@ subroutine get_obs_pred( & ! allocate and assemble tile_data_l allocate(tile_data_l(0,0,0)) ! for debugging to pass call get_tiles_in_halo( N_catl, N_fields, N_ens, tile_data_l, tile_coord_l, & - tile_coord_f, N_catl_vec, low_ind, xhalo, yhalo, & + tile_coord_f, N_catl_vec, low_ind, xhalo, yhalo, & N_catlH, tile_coord_lH=tile_coord_lH ) if (get_sfmc_lH) allocate(sfmc_lH( N_catlH, N_ens)) @@ -1453,7 +1453,7 @@ subroutine get_obs_pred( & ! communicate tile_data_l as needed and get tile_data_lH call get_tiles_in_halo( N_catl, N_fields, N_ens, tile_data_l, tile_coord_l, & - tile_coord_f, N_catl_vec, low_ind, xhalo, yhalo, & + tile_coord_f, N_catl_vec, low_ind, xhalo, yhalo, & N_catlH, tile_data_lH=tile_data_lH ) ! read out sfmc, rzmc, etc. from tile_data_lH @@ -2341,7 +2341,7 @@ end subroutine qc_model_based_for_Tb ! ********************************************************************* subroutine get_halo_obs( N_ens, N_obsl, Observations_l, Obs_pred_l, & - tile_coord_l, xcompact, ycompact, & + tile_coord_l, xcompact, ycompact, & N_obslH, Observations_lH, Obs_pred_lH ) ! collect observations from other local domains (processors) that are @@ -2764,7 +2764,7 @@ end subroutine get_halo_obs ! ********************************************************************* subroutine get_tiles_in_halo( N_catl, N_fields, N_ens, tile_data_l, tile_coord_l, & - tile_coord_f, N_catl_vec, low_ind, xhalo, yhalo, & + tile_coord_f, N_catl_vec, low_ind, xhalo, yhalo, & N_catlH, tile_coord_lH, tile_data_lH ) ! collect (bundled) tile_data from other local domains (processors) that are From cab8a57ad56759ed07a03bf61d1ac4302dcff283 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Tue, 7 Nov 2023 16:23:35 -0500 Subject: [PATCH 183/308] make update type 1 work --- .../GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index 603c5768..7503ee07 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -3604,9 +3604,10 @@ subroutine cat_enkf_increments( & if (logit) write (logunit,*) 'get 1d soil moisture increments; sfmc obs' - N_select_varnames = 1 + N_select_varnames = 2 select_varnames(1) = 'sfmc' + select_varnames(2) = 'sfds' call get_select_species( & N_select_varnames, select_varnames(1:N_select_varnames), & From 89cdbf5359b9fa07743ec0210544c0a33094fc85 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Thu, 9 Nov 2023 16:32:58 -0500 Subject: [PATCH 184/308] update NCEP_Shared to v1.3.0 --- components.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components.yaml b/components.yaml index 7757734c..12f92e0f 100644 --- a/components.yaml +++ b/components.yaml @@ -22,7 +22,7 @@ ecbuild: NCEP_Shared: local: ./src/Shared/@NCEP_Shared remote: ../NCEP_Shared.git - tag: v1.1.1 + tag: v1.3.0 sparse: ./config/NCEP_Shared.sparse develop: main From 8ad334afbe1550e2ea1115ef59f6f05e9abeae08 Mon Sep 17 00:00:00 2001 From: Rolf Reichle <54944691+gmao-rreichle@users.noreply.github.com> Date: Mon, 13 Nov 2023 18:24:15 -0500 Subject: [PATCH 185/308] Bug fix in new MODIS SCF obs reader (clsm_ensupd_read_obs.F90) --- .../GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 0efda45b..e23d789a 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -5213,7 +5213,9 @@ subroutine read_MODIS_SCF_hdf( fname, lon_min, lon_max, lat_min, lat_max, & write (logunit,'(400A)') trim(Iam), ': cannot find file ', trim(fname) write (logunit,* ) 'not reading MODIS SCF obs' end if - + + N_good_data = 0 + return end if From 3eb985e359ec7ecf2f39e25df7dce21118d9dce9 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Tue, 14 Nov 2023 09:50:56 -0500 Subject: [PATCH 186/308] minor edit to optimize MODIS SCF obs reader (clsm_ensupd_read_obs.F90) --- .../GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index e23d789a..3377f093 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -4925,7 +4925,12 @@ subroutine read_obs_MODIS_SCF( & end do - + + ! return if no MODIS obs were found (found_obs=.false. per initialization above) + + if (N_CMG_obs==0) return + + ! map to tile space allocate(tmp_tile_num(N_CMG_obs)) @@ -5435,7 +5440,7 @@ subroutine read_MODIS_SCF_hdf( fname, lon_min, lon_max, lat_min, lat_max, & CMG_lat = SCF_nodata ! initialize CMG_SCF = SCF_nodata ! initialize - kk = 0 ! initialize counter for "good" data + kk = 0 ! initialize counter for "good" data do ii=1,N_lon do jj=1,N_lat From 4c5e2831efeebd384548c46c90c6009ea2fe7af5 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Wed, 22 Nov 2023 15:39:40 -0500 Subject: [PATCH 187/308] allocation of mwRTM_param --- .../GEOS_LandAssimGridComp.F90 | 31 +++++++++++++------ 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 index e4519095..a65efa28 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 @@ -1886,19 +1886,30 @@ subroutine RUN ( GC, IMPORT, EXPORT, CLOCK, RC ) ) _VERIFY(status) - ! mwRTM_param already contains static parameters, only need vegopacity. - - call get_vegopacity(MAPL, clock, N_catl, rc=status) - _VERIFY(STATUS) + + if ( mwRTM ) then - ! Check no-data consistency of vegetation attenuation parameter values. - ! Good values are allowed for either the relevant static parameters - ! (bh, bv, lewt) or for the vegopacity values from the file, but not both. + ! mwRTM_param already contains static parameters, only need vegopacity. - do ii=1,N_catl - call mwRTM_param_nodata_check( mwRTM_param(ii) ) - end do + call get_vegopacity(MAPL, clock, N_catl, rc=status) + _VERIFY(STATUS) + ! Check no-data consistency of vegetation attenuation parameter values. + ! Good values are allowed for either the relevant static parameters + ! (bh, bv, lewt) or for the vegopacity values from the file, but not both. + + do ii=1,N_catl + call mwRTM_param_nodata_check( mwRTM_param(ii) ) + end do + + endif + + if(.not. allocated(mwRTM_param)) then + + allocate(mwRTM_param(1)) + + endif + call get_enkf_increments( & date_time_new, & NUM_ENSEMBLE, N_catl, N_catf, N_obsl_max, & From e251abe078f9f322791b0b190d9a1a92b8799117 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Wed, 22 Nov 2023 15:40:39 -0500 Subject: [PATCH 188/308] bugfix for ASCAT_sm_std --- .../GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 5c13abbc..60c6900c 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -1953,14 +1953,15 @@ subroutine read_obs_sm_ASCAT_EUMET( & do ii=1,N_catd ! set observation error standard deviation - + + ASCAT_sm_std(ii) = this_obs_param%errstd/100. ! change units from percent (0-100) to fraction (0-1) + if (N_obs_in_tile(ii)>1) then ASCAT_sm( ii) = ASCAT_sm( ii)/real(N_obs_in_tile(ii)) ASCAT_lon( ii) = ASCAT_lon( ii)/real(N_obs_in_tile(ii)) ASCAT_lat( ii) = ASCAT_lat( ii)/real(N_obs_in_tile(ii)) ASCAT_time( ii) = ASCAT_time(ii)/real(N_obs_in_tile(ii),kind(0.0D0)) - ASCAT_sm_std(ii) = this_obs_param%errstd/100. ! change units from percent (0-100) to fraction (0-1) elseif (N_obs_in_tile(ii)==0) then From 1d4806bdfa0eaa68165a4542e576d7a04bad2be7 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Wed, 22 Nov 2023 14:13:52 -0700 Subject: [PATCH 189/308] 1. Move call get_vegopacity and nod_data_check into conditional 2. Allocate mwRTM_param if not done so before --- .../GEOS_LandAssimGridComp.F90 | 30 ++++++++++++------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 index e4519095..79b78ce5 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 @@ -1886,19 +1886,29 @@ subroutine RUN ( GC, IMPORT, EXPORT, CLOCK, RC ) ) _VERIFY(status) - ! mwRTM_param already contains static parameters, only need vegopacity. + if ( mwRTM ) then - call get_vegopacity(MAPL, clock, N_catl, rc=status) - _VERIFY(STATUS) + ! mwRTM_param already contains static parameters, only need vegopacity. - ! Check no-data consistency of vegetation attenuation parameter values. - ! Good values are allowed for either the relevant static parameters - ! (bh, bv, lewt) or for the vegopacity values from the file, but not both. - - do ii=1,N_catl - call mwRTM_param_nodata_check( mwRTM_param(ii) ) - end do + call get_vegopacity(MAPL, clock, N_catl, rc=status) + _VERIFY(STATUS) + ! Check no-data consistency of vegetation attenuation parameter values. + ! Good values are allowed for either the relevant static parameters + ! (bh, bv, lewt) or for the vegopacity values from the file, but not both. + + do ii=1,N_catl + call mwRTM_param_nodata_check( mwRTM_param(ii) ) + end do + + endif + + if(.not. allocated(mwRTM_param)) then + + allocate(mwRTM_param(1)) + + endif + call get_enkf_increments( & date_time_new, & NUM_ENSEMBLE, N_catl, N_catf, N_obsl_max, & From f98cee7f18a6a50181f850325bc69e24a6093e60 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Thu, 30 Nov 2023 15:43:37 -0500 Subject: [PATCH 190/308] removed code and text related to haswell nodes (extinct) and milan nodes (GEOSldas not yet ready for milan) --- README.md | 12 -- src/Applications/LDAS_App/ldas_setup | 233 +++++++++++++-------------- 2 files changed, 114 insertions(+), 131 deletions(-) diff --git a/README.md b/README.md index a3303ae5..5b81ce44 100644 --- a/README.md +++ b/README.md @@ -47,18 +47,6 @@ To obtain a build that is suitable for debugging, use `parallel_build.csh -debug See below for how to build the model in multiple steps. -#### Running on Milans at NCCS - -By default, `parallel_build.csh` will build on SLES12 nodes at discover (either Skylake or Cascade Lake). However, Milan nodes were -recently installed at discover, which use SLES15 as their operating system. Because of this OS difference, if you want to run on the -Milans, you must build on the Milans. To do so you can run `parallel_build.csh` with the `-mil` flag, e.g.: - -``` -parallel_build.csh -mil -``` - -This will by default build in `build-SLES15` and install to `install-SLES15`. - --- ## How to Set Up (Configure) and Run GEOSldas diff --git a/src/Applications/LDAS_App/ldas_setup b/src/Applications/LDAS_App/ldas_setup index 7cd5767f..f8860681 100755 --- a/src/Applications/LDAS_App/ldas_setup +++ b/src/Applications/LDAS_App/ldas_setup @@ -36,10 +36,10 @@ class LDASsetup: # Required exe input fields # These fields are needed to pre-compute exp dir structure # ------ - rqdExeInpKeys = ['EXP_ID', 'EXP_DOMAIN', 'NUM_LDAS_ENSEMBLE', + rqdExeInpKeys = ['EXP_ID', 'EXP_DOMAIN', 'NUM_LDAS_ENSEMBLE', 'BEG_DATE', 'END_DATE','RESTART_PATH', 'RESTART_DOMAIN','RESTART_ID','MET_TAG','MET_PATH','FORCE_DTSTEP','BCS_PATH', 'BCS_RESOLUTION'] - rqdExeInpKeys_rst = ['EXP_ID', 'EXP_DOMAIN', 'NUM_LDAS_ENSEMBLE', + rqdExeInpKeys_rst = ['EXP_ID', 'EXP_DOMAIN', 'NUM_LDAS_ENSEMBLE', 'BEG_DATE', 'END_DATE','MET_TAG','MET_PATH','FORCE_DTSTEP','BCS_PATH', 'BCS_RESOLUTION'] # These keywords are excluded from LDAS.rc (i.e., only needed in pre- or post-processing) @@ -151,7 +151,7 @@ class LDASsetup: assert self.nens>0, 'NUM_LDAS_ENSEMBLE [%d] <= 0' % self.nens _mydir = self.exphome + '/' + self.rqdExeInp['EXP_ID'] assert not os.path.isdir(_mydir), 'Dir [%s] already exists!' % _mydir - _mydir = None + _mydir = None self.ladas_coupling = int(self.rqdExeInp.get('LADAS_COUPLING',0)) if self.ladas_coupling > 0: assert 'ADAS_EXPDIR' in self.rqdExeInp, " need ADAS_EXPDIR in the input file %s" %(self.exeinpfile) @@ -163,7 +163,7 @@ class LDASsetup: self.ensdirs = ['ens%04d'%iens for iens in range(self.first_ens_id, self.nens + self.first_ens_id)] # if self.ens_id_width = 4, _width = '_e%04d' _width = '_e%0{}d'.format(self.ens_id_width-2) - # self.ensids will be a list of [_e0000, _e0001, ...] + # self.ensids will be a list of [_e0000, _e0001, ...] self.ensids = [ _width%iens for iens in range(self.first_ens_id, self.nens + self.first_ens_id)] if (self.nens == 1) : self.ensdirs_avg = self.ensdirs @@ -246,7 +246,7 @@ class LDASsetup: # make sure path is path if self.rqdExeInp['BCS_PATH'][-1] != '/': self.rqdExeInp['BCS_PATH'] = self.rqdExeInp['BCS_PATH']+'/' - self.rqdExeInp['BCS_PATH'] = self.rqdExeInp['BCS_PATH']+self.rqdExeInp['BCS_RESOLUTION']+'/' + self.rqdExeInp['BCS_PATH'] = self.rqdExeInp['BCS_PATH']+self.rqdExeInp['BCS_RESOLUTION']+'/' if self.rqdExeInp['MET_PATH'][-1] != '/': self.rqdExeInp['MET_PATH'] = self.rqdExeInp['MET_PATH']+'/' if self.rqdExeInp['RESTART_PATH'][-1] != '/': @@ -267,8 +267,8 @@ class LDASsetup: '/output/'+self.rqdExeInp['RESTART_DOMAIN']+'/rc_out/'+self.rqdExeInp['RESTART_ID']+'.ldas_domain.txt' if os.path.isfile(ldas_domain) : _numd = int(linecache.getline(ldas_domain, 1).strip()) - - if _numg != _numd : + + if _numg != _numd : self.rqdExeInp['RST_FROM_GLOBAL'] = 0 self.rqdExeInp['LNFM_FILE'] = '' @@ -308,7 +308,7 @@ class LDASsetup: if len(in_tilefiles_) == 0 : in_tilefiles_ = glob.glob(inpdir+'/*.til') self.in_tilefile =os.path.realpath(in_tilefiles_[0]) - + if os.path.isfile(ldas_domain) : _numd = int(linecache.getline(ldas_domain, 1).strip()) self.rqdExeInp['TILING_FILE'] =glob.glob(self.rqdExeInp['BCS_PATH']+'*.til')[0] @@ -320,8 +320,8 @@ class LDASsetup: self.rqdExeInp['LNFM_FILE']= glob.glob(self.rqdExeInp['BCS_PATH']+'lnfm_clim_*.data')[0] self.rqdExeInp['NDVI_FILE']= glob.glob(self.rqdExeInp['BCS_PATH']+'ndvi_clim_*.data')[0] self.rqdExeInp['NIRDF_FILE']= glob.glob(self.rqdExeInp['BCS_PATH']+'nirdf_*.dat')[0] - self.rqdExeInp['VISDF_FILE']= glob.glob(self.rqdExeInp['BCS_PATH']+'visdf_*.dat')[0] - + self.rqdExeInp['VISDF_FILE']= glob.glob(self.rqdExeInp['BCS_PATH']+'visdf_*.dat')[0] + if 'GRIDNAME' not in self.rqdExeInp : tmptile =self.rqdExeInp['TILING_FILE'] self.rqdExeInp['GRIDNAME'] = linecache.getline(tmptile, 3).strip() @@ -333,7 +333,7 @@ class LDASsetup: self.catch = 'catch' if int(self.rqdExeInp['LSM_CHOICE']) == 2 : self.catch = 'catchcnclm40' - if int(self.rqdExeInp['LSM_CHOICE']) == 3 : + if int(self.rqdExeInp['LSM_CHOICE']) == 3 : self.catch = 'catchcnclm45' if 'POSTPROC_HIST' not in self.rqdExeInp: self.rqdExeInp['POSTPROC_HIST'] = 0 @@ -342,7 +342,7 @@ class LDASsetup: self.rqdExeInp['LADAS_COUPLING'] = 0 if 'RUN_IRRIG' not in self.rqdExeInp: - self.rqdExeInp['RUN_IRRIG'] = 0 + self.rqdExeInp['RUN_IRRIG'] = 0 if 'AEROSOL_DEPOSITION' not in self.rqdExeInp: self.rqdExeInp['AEROSOL_DEPOSITION'] = 0 @@ -354,7 +354,7 @@ class LDASsetup: _domain_dic['MAXLAT']= 90. _domain_dic['EXCLUDE_FILE']= "''" _domain_dic['INCLUDE_FILE']= "''" - + for key,val in _domain_dic.items() : if key in self.rqdExeInp : _domain_dic[key]= self.rqdExeInp[key] @@ -368,7 +368,7 @@ class LDASsetup: else : fout.write(keyn+ valn +'\n') fout.write('/\n') - + # make sure bcs files exist if self.rqdExeInp['RESTART'].isdigit() : if int(self.rqdExeInp['RESTART']) >= 1 : @@ -379,18 +379,18 @@ class LDASsetup: tmpRstDir=self.rqdExeInp['RESTART_PATH']+'/'.join([self.rqdExeInp['RESTART_ID'],'output', self.rqdExeInp['RESTART_DOMAIN'],'rs',self.ensdirs[0],y4m2]) catchRstFile=tmpRstDir+'/'+tmpFile - + assert os.path.isfile(catchRstFile), self.catch+'_internal_rst file [%s] does not exist!' %(catchRstFile) self.in_rstfile = catchRstFile - + if int(self.rqdExeInp['RESTART']) == 1 : tmpFile=self.rqdExeInp['RESTART_ID']+'.vegdyn_internal_rst' tmpRstDir=self.rqdExeInp['RESTART_PATH']+'/'.join([self.rqdExeInp['RESTART_ID'],'output', - self.rqdExeInp['RESTART_DOMAIN'],'rs',self.ensdirs[0]]) + self.rqdExeInp['RESTART_DOMAIN'],'rs',self.ensdirs[0]]) vegdynRstFile=tmpRstDir+'/'+tmpFile if not os.path.isfile(vegdynRstFile): assert int(self.rqdExeInp['RST_FROM_GLOBAL']) == 1, 'restart from LDASsa should be global' - + tmpFile=self.rqdExeInp['RESTART_ID']+'.landpert_internal_rst.'+y4m2d2_h2m2 tmpRstDir=self.rqdExeInp['RESTART_PATH']+'/'.join([self.rqdExeInp['RESTART_ID'],'output', self.rqdExeInp['RESTART_DOMAIN'],'rs',self.ensdirs[0],y4m2]) @@ -398,15 +398,15 @@ class LDASsetup: if ( os.path.isfile(landpertRstFile)) : self.has_geos_pert = True - elif (int(self.rqdExeInp['RESTART']) == 0) : + elif (int(self.rqdExeInp['RESTART']) == 0) : if (self.catch == 'catch'): self.in_rstfile = '/discover/nobackup/projects/gmao/ssd/land/l_data/LandRestarts_for_Regridding' \ - '/Catch/M09/20170101/catch_internal_rst' + '/Catch/M09/20170101/catch_internal_rst' self.in_tilefile = '/discover/nobackup/projects/gmao/ssd/land/l_data/geos5/bcs/CLSM_params' \ '/mkCatchParam_SMAP_L4SM_v002/SMAP_EASEv2_M09/SMAP_EASEv2_M09_3856x1624.til' elif (self.catch == 'catchcnclm40'): self.in_rstfile = '/discover/nobackup/projects/gmao/ssd/land/l_data/LandRestarts_for_Regridding' \ - '/CatchCN/M36/20150301_0000/catchcnclm40_internal_dummy' + '/CatchCN/M36/20150301_0000/catchcnclm40_internal_dummy' self.in_tilefile = '/discover/nobackup/projects/gmao/bcs_shared/legacy_bcs/Heracles-NL/SMAP_EASEv2_M36/SMAP_EASEv2_M36_964x406.til' elif (self.catch == 'catchcnclm45'): self.in_rstfile = '/discover/nobackup/projects/gmao/ssd/land/l_data/LandRestarts_for_Regridding' \ @@ -416,7 +416,7 @@ class LDASsetup: sys.exit('need to provide at least dummy files') self.in_rstfile = None self.in_tilefile = None - + # DEAL WITH mwRTM input from exec self.assim = True if self.rqdExeInp.get('LAND_ASSIM', 'NO').upper() == 'YES' else False # verify mwrtm file @@ -427,15 +427,15 @@ class LDASsetup: if os.path.isfile(mwrtm_param_file_) : self.has_mwrtm = True self.mwrtm_file = mwrtm_param_file_ - else : - assert not mwrtm_param_file_.strip(), ' MWRTM_PATH: %s should contain mwRTM_param.nc4'% self.rqdExeInp['MWRTM_PATH'] + else : + assert not mwrtm_param_file_.strip(), ' MWRTM_PATH: %s should contain mwRTM_param.nc4'% self.rqdExeInp['MWRTM_PATH'] del self.rqdExeInp['MWRTM_PATH'] if os.path.isfile(vegopacity_file_) : self.has_vegopacity = True self.rqdExeInp['VEGOPACITY_FILE'] = vegopacity_file_ - + # DEAL WITH optional input from exec - + # ------ # Read rm input file # Read (and pop from inpfile) the input required fields in to @@ -479,7 +479,7 @@ class LDASsetup: _printdict(self.optRmInp) # ------ - # set top level directories + # set top level directories # rundir, inpdir, outdir, blddir # executable # exefyl @@ -517,7 +517,7 @@ class LDASsetup: # default is set to 0 ( no output server) if 'oserver_nodes' not in self.optRmInp : self.optRmInp['oserver_nodes'] = 0 - + self.optRmInp['nodes'] = my_nodes + int(self.optRmInp['oserver_nodes']) if (int(self.optRmInp['oserver_nodes']) >=1) : @@ -527,7 +527,7 @@ class LDASsetup: self.optRmInp['writers-per-node'] = 5 else: self.optRmInp['writers-per-node'] = 0 - + def _parseInputFile(self, inpfile): """ @@ -692,14 +692,14 @@ class LDASsetup: print ('\nCorrect the tile file if it is an old EASE tile format... \n') EASEtile=self.bcsdir+'/MAPL_'+short_tile - cmd = './preprocess_ldas.x correctease '+ tile + ' '+ EASEtile + cmd = './preprocess_ldas.x correctease '+ tile + ' '+ EASEtile print ("cmd: " + cmd) sp.call(shlex.split(cmd)) if os.path.isfile(EASEtile) : #update tile file name short_tile ='MAPL_'+short_tile - tile=EASEtile + tile=EASEtile # setup BC files if os.path.isfile('f2g.txt'): os.remove('f2g.txt') @@ -717,13 +717,13 @@ class LDASsetup: # These are dummy values for *cold* restart: wemin_in = '13' # WEmin input/output for scale_catch(cn), - wemin_out = '13' # + wemin_out = '13' # if 'WEMIN_IN' in self.rqdExeInp : wemin_in = self.rqdExeInp['WEMIN_IN'] if 'WEMIN_OUT' in self.rqdExeInp : wemin_out = self.rqdExeInp['WEMIN_OUT'] - + cmd = './preprocess_ldas.x c_f2g ' + tile + ' ' + domain_def + ' '+ self.out_path + ' ' + catchment_def + ' ' + exp_id + ' ' + _y4m2d2h2m2 + ' '+ dzsf print ('Creating f2g.txt....\n') @@ -740,12 +740,12 @@ class LDASsetup: newlocalTile = tile+'.domain' print ("\nCreating local tile file :"+ newlocalTile) print ("\n by excluding land type MAPL_Land_ExcludeFromDomain=1100...\n") - cmd = './preprocess_ldas.x c_localtile ' + tile + ' ' + newlocalTile + cmd = './preprocess_ldas.x c_localtile ' + tile + ' ' + newlocalTile print ("cmd: " + cmd) sp.call(shlex.split(cmd)) short_tile=short_tile +'.domain' tile = newlocalTile - + myTile=self.inpdir+'/tile.data' os.symlink(tile,myTile) @@ -777,7 +777,7 @@ class LDASsetup: # link BC - print ("linking bcs...") + print ("linking bcs...") bcnames=['green','lai','ndvi','nirdf','visdf'] if (self.rqdExeInp['LNFM_FILE'] != ''): bcnames += ['lnfm'] @@ -791,7 +791,7 @@ class LDASsetup: os.symlink(self.rqdExeInp['BCS_PATH']+'../land/shared/CO2_MonthlyMean_DiurnalCycle.nc4', \ self.inpdir+'/CO2_MonthlyMean_DiurnalCycle.nc4') - # create and link restart + # create and link restart print ("Creating and linking restart...") _start = self.begDates[0] @@ -819,18 +819,18 @@ class LDASsetup: rstid = self.rqdExeInp['RESTART_ID'] rstdomain = self.rqdExeInp['RESTART_DOMAIN'] rstpath0 = self.rqdExeInp['RESTART_PATH'] - + # just copy the landassim pert seed if it exists for iens in range(self.nens) : _ensdir = self.ensdirs[iens] _ensid = self.ensids[iens] landassim_seeds = rstpath + _ensdir + '/' + y4m2+'/' + rstid + '.landassim_obspertrseed_rst.'+y4m2d2_h2m2 if os.path.isfile(landassim_seeds) and self.assim : - _seeds = self.rstdir + _ensdir + '/' + y4m2+'/' + exp_id + '.landassim_obspertrseed_rst.'+y4m2d2_h2m2 + _seeds = self.rstdir + _ensdir + '/' + y4m2+'/' + exp_id + '.landassim_obspertrseed_rst.'+y4m2d2_h2m2 shutil.copy(landassim_seeds, _seeds) os.symlink(_seeds, myRstDir+ '/landassim_obspertrseed'+ _ensid +'_rst') self.has_landassim_seed = True - mk_outdir = self.exphome+'/'+exp_id+'/mk_restarts/' + mk_outdir = self.exphome+'/'+exp_id+'/mk_restarts/' cmd= ' '.join(['./process_rst.csh', sponsorid, exp_id, mk_outdir, out_bcdir, out_tilefile, self.catch, RESTART_str, YYYYMMDDHH, self.in_rstfile, self.in_tilefile, dzsf, wemin_in, wemin_out]) @@ -839,8 +839,8 @@ class LDASsetup: remap_tpl = os.path.dirname(os.path.realpath(__file__)) + '/remap_params.tpl' config = yaml_to_config(remap_tpl) - config['slurm']['account'] = self.rqdRmInp['account'] - config['slurm']['qos'] = 'debug' + config['slurm']['account'] = self.rqdRmInp['account'] + config['slurm']['qos'] = 'debug' config['slurm']['qos'] = 'cas' config['input']['surface']['catch_tilefile'] = self.in_tilefile @@ -858,7 +858,7 @@ class LDASsetup: config['output']['surface']['surflay'] = dzsf config['output']['surface']['wemin'] = wemin_out - config = remap_config_ldas( config, RESTART_str, self.rqdExeInp['RESTART_PATH'], self.rqdExeInp['RESTART_ID']) + config = remap_config_ldas( config, RESTART_str, self.rqdExeInp['RESTART_PATH'], self.rqdExeInp['RESTART_ID']) catch_obj = catchANDcn(config_obj = config) catch_obj.remap() @@ -912,7 +912,7 @@ class LDASsetup: catchLocal = self.rstdir+ensdir +'/'+ y4m2+'/'+self.rqdExeInp['EXP_ID']+'.'+self.catch+'_internal_rst.'+y4m2d2_h2m2 if self.islocal : print( "Creating local catchment restart file... \n") - cmd='./preprocess_ldas.x c_localcatchrst '+ catchRstFile +' ' + catchLocal + cmd='./preprocess_ldas.x c_localcatchrst '+ catchRstFile +' ' + catchLocal print ("cmd: "+cmd) sp.call(shlex.split(cmd)) else : @@ -922,7 +922,7 @@ class LDASsetup: if '0000' in ensdir : catchRstFile0 = catchRstFile - else : # re-use 0000 catch file + else : # re-use 0000 catch file catchRstFile = catchRstFile0 # vegdyn restart file @@ -930,7 +930,7 @@ class LDASsetup: vegdynLocal = self.rstdir+ensdir +'/'+self.rqdExeInp['EXP_ID']+'.vegdyn_internal_rst' if self.islocal : print ("Creating the local veg restart file... \n") - cmd='./preprocess_ldas.x c_localvegrst '+ vegdynRstFile +' ' + vegdynLocal + cmd='./preprocess_ldas.x c_localvegrst '+ vegdynRstFile +' ' + vegdynLocal print ("cmd: " + cmd) sp.call(shlex.split(cmd)) else : @@ -940,7 +940,7 @@ class LDASsetup: if '0000' in ensdir : vegdynRstFile0 = vegdynRstFile - else : + else : vegdynRstFile = vegdynRstFile0 if (self.has_geos_pert and self.perturb == 1) : @@ -965,7 +965,7 @@ class LDASsetup: mwRTMLocal = self.bcsdir+'/'+ y4m2+'/'+self.rqdExeInp['EXP_ID']+'.ldas_mwRTMparam.'+y4m2d2_h2m2+'z.nc4' if self.islocal : print ("Creating the local mwRTM restart file... \n") - cmd='./preprocess_ldas.x c_localmwrtmrst '+ mwRTMRstFile +' ' + mwRTMLocal + cmd='./preprocess_ldas.x c_localmwrtmrst '+ mwRTMRstFile +' ' + mwRTMLocal print ("cmd: " + cmd) sp.call(shlex.split(cmd)) else : @@ -980,7 +980,7 @@ class LDASsetup: self.rqdExeInp['RESTART_PATH'] = myRstDir if os.path.isfile('f2g.txt'): os.remove('f2g.txt') - + status = True return status @@ -1036,7 +1036,7 @@ class LDASsetup: # get optimzed NX and IMS if os.path.isfile('optimized_distribution'): os.remove('optimized_distribution') - + print ("Optimizing... decomposition of processes.... \n") cmd = './preprocess_ldas.x optimize '+ self.inpdir+'/tile.data '+ str(self.rqdRmInp['ntasks_model']) print ("cmd: " + cmd) @@ -1046,12 +1046,12 @@ class LDASsetup: if int(optinxny['NY']) != int(self.rqdRmInp['ntasks_model']): self.rqdRmInp['ntasks_model']=optinxny['NY'] print ('adjust ntasks_model %d for cubed-sphere grid' % int(self.rqdRmInp['ntasks_model'])) - + if os.path.isfile('IMS.rc') : shutil.move('IMS.rc', self.rundir+'/') if os.path.isfile('JMS.rc') : shutil.move('JMS.rc', self.rundir+'/') - + os.remove('optimized_distribution') # DEFAULT rc files @@ -1086,17 +1086,17 @@ class LDASsetup: ' ' + GRID + ' ' + str(self.rqdExeInp['RUN_IRRIG']) + ' ' + _assim + ' '+ str(self.nens) print(cmd) #os.system(cmd) - sp.call(shlex.split(cmd)) + sp.call(shlex.split(cmd)) for line in fileinput.input(tmprcfile,inplace=True): print (line.rstrip().replace('GEOSldas_expid',self.rqdExeInp['EXP_ID'])) # just copy an empty ExtData.rc if shortfile=='ExtData.rc' : shutil.copy2(rcfile, self.rundir+'/'+shortfile) - - if shortfile == 'CAP.rc': + + if shortfile == 'CAP.rc': tmprcfile = self.rundir+'/CAP.rc' shutil.copy2(rcfile,tmprcfile) - + _num_sgmt = int(self.rqdExeInp['NUM_SGMT']) for line in fileinput.input(tmprcfile,inplace=True): @@ -1107,15 +1107,15 @@ class LDASsetup: print (line.rstrip().replace('BEG_DATE:',self.begDates[0].strftime('BEG_DATE: %Y%m%d %H%M%S'))) for line in fileinput.input(tmprcfile,inplace=True): print (line.rstrip().replace('END_DATE:',self.endDates[-1].strftime('END_DATE: %Y%m%d %H%M%S'))) - + if shortfile == 'LDAS.rc' : ldasrcInp = OrderedDict() - # land default + # land default default_surfrcInp = self._parseInputFile(etcdir+'/GEOS_SurfaceGridComp.rc') for key,val in default_surfrcInp.items() : ldasrcInp[key] = val - # ldas default, may overwrite land default + # ldas default, may overwrite land default default_ldasrcInp = self._parseInputFile(rcfile) for key,val in default_ldasrcInp.items() : ldasrcInp[key] = val @@ -1132,7 +1132,7 @@ class LDASsetup: # create BC in rc file tmpl_ = '' if self.nens >1 : - tmpl_='%s' + tmpl_='%s' if self.perturb == 1: ldasrcInp['PERTURBATIONS'] ='1' bcval=['../input/green','../input/lai','../input/lnfm','../input/ndvi','../input/nirdf','../input/visdf'] @@ -1156,15 +1156,15 @@ class LDASsetup: if 'VEGDYN_INTERNAL_RESTART_TYPE' in ldasrcInp : # avoid duplicate del ldasrcInp['VEGDYN_INTERNAL_RESTART_TYPE'] - + rstkey=[catch_,'VEGDYN'] rstval=[self.catch,'vegdyn'] - if self.has_mwrtm : + if self.has_mwrtm : keyn='LANDASSIM_INTERNAL_RESTART_FILE' valn='../input/restart/mwrtm_param_rst' ldasrcInp[keyn]= valn - if self.has_vegopacity : + if self.has_vegopacity : keyn='VEGOPACITY_FILE' valn='../input/vegopacity.data' ldasrcInp[keyn]= valn @@ -1179,16 +1179,16 @@ class LDASsetup: valn='../input/restart/landassim_obspertrseed'+tmpl_+'_rst' ldasrcInp[keyn]= valn - if self.assim: + if self.assim: keyn='LANDASSIM_OBSPERTRSEED_CHECKPOINT_FILE' valn='landassim_obspertrseed'+tmpl_+'_checkpoint' ldasrcInp[keyn]= valn - + for key,val in zip(rstkey,rstval) : keyn = key+ '_INTERNAL_RESTART_FILE' valn = '../input/restart/'+val+tmpl_+'_internal_rst' ldasrcInp[keyn]= valn - + # checkpoint file and its type keyn = catch_ + '_INTERNAL_CHECKPOINT_FILE' valn = self.catch+tmpl_+'_internal_checkpoint' @@ -1200,12 +1200,12 @@ class LDASsetup: valn = '../input/restart/landpert'+tmpl_+'_internal_rst' ldasrcInp[keyn]= valn # for lat/lon and EASE tile space, specify LANDPERT checkpoint file here (via MAPL); - # for cube-sphere tile space, Landpert GC will set up LANDPERT checkpoint file + # for cube-sphere tile space, Landpert GC will set up LANDPERT checkpoint file if ('-CF' not in self.rqdExeInp['GRIDNAME']): keyn = 'LANDPERT_INTERNAL_CHECKPOINT_FILE' valn = 'landpert'+tmpl_+'_internal_checkpoint' ldasrcInp[keyn]= valn - + # write LDAS.rc fout =open(self.rundir+'/'+shortfile,'w') # ldasrcInp['NUM_LDAS_ENSEMBLE']=ldasrcInp.pop('NUM_ENSEMBLE') @@ -1219,9 +1219,9 @@ class LDASsetup: fout.write("EXP_ID:".ljust(36)+self.rqdExeInp['EXP_ID']+'\n') fout.write("TILING_FILE:".ljust(36)+"../input/tile.data\n") - fout.close() + fout.close() - fout=open(self.rundir+'/'+'cap_restart','w') + fout=open(self.rundir+'/'+'cap_restart','w') #fout.write(self.rqdExeInp['BEG_DATE']) fout.write(self.begDates[0].strftime('%Y%m%d %H%M%S')) fout.close() @@ -1276,7 +1276,7 @@ class LDASsetup: fout.write("\nsed -i 's/#if($capdate<$enddate) sbatch/if($capdate<$enddate) sbatch /g' lenkf.j") fout.close() - sp.call(['chmod', '755', self.rundir+'/ldas_batchrun.j']) + sp.call(['chmod', '755', self.rundir+'/ldas_batchrun.j']) status = True return status @@ -1333,12 +1333,8 @@ class LDASsetup: elif 'MY_NODES' in line : line_ = line.replace('MY_NODES',str(self.optRmInp['nodes'])) fout.write(line_.replace('MY_NTASKS_PER_NODE',str(self.rqdRmInp['ntasks-per-node']))) - if int(self.rqdRmInp['ntasks-per-node']) > 46: - fout.write("#SBATCH --constraint=mil\n") - elif int(self.rqdRmInp['ntasks-per-node']) > 40: + if int(self.rqdRmInp['ntasks-per-node']) > 40: fout.write("#SBATCH --constraint=cas\n") - elif (28 < int(self.rqdRmInp['ntasks-per-node']) and int(self.rqdRmInp['ntasks-per-node']) <= 40) : - fout.write("#SBATCH --constraint=cas|sky\n") elif 'MY_OSERVER_NODES' in line : fout.write(line.replace('MY_OSERVER_NODES',str(self.optRmInp['oserver_nodes']))) elif 'MY_WRITERS_NPES' in line : @@ -1359,7 +1355,7 @@ class LDASsetup: elif 'MY_MODEL' in line : fout.write(line.replace('MY_MODEL',self.catch)) elif 'MY_POSTPROC_HIST' in line : - fout.write(line.replace('MY_POSTPROC_HIST',str(self.rqdExeInp['POSTPROC_HIST']))) + fout.write(line.replace('MY_POSTPROC_HIST',str(self.rqdExeInp['POSTPROC_HIST']))) elif 'MY_FIRST_ENS_ID' in line : fout.write(line.replace('MY_FIRST_ENS_ID',str(self.first_ens_id))) elif 'MY_LADAS_COUPLING' in line : @@ -1369,12 +1365,12 @@ class LDASsetup: elif 'MY_ADAS_EXPDIR' in line : if self.ladas_coupling > 0: fout.write(line.replace('MY_ADAS_EXPDIR', self.rqdExeInp['ADAS_EXPDIR'])) - - + + else : fout.write(line.replace('MY_EXPDIR',self.exphome+'/$EXPID')) - - sp.call(['chmod', '755', 'lenkf.j']) + + sp.call(['chmod', '755', 'lenkf.j']) expdir = '/'.join(self.rundir.rstrip('/').split('/')[:-1]) print ('\nExperiment directory: %s' % expdir) @@ -1395,7 +1391,7 @@ def _printExeInputKeys(rqdExeInpKeys): Private method: print sample exe input """ - print ('####################################################################################') + print ('####################################################################################') print ('# #') print ('# REQUIRED INPUTS #') print ('# #') @@ -1403,7 +1399,7 @@ def _printExeInputKeys(rqdExeInpKeys): print ('# #') print ('####################################################################################') print () - print ('############################################################') + print ('############################################################') print ('# #') print ('# EXPERIMENT INFO #') print ('# #') @@ -1424,14 +1420,14 @@ def _printExeInputKeys(rqdExeInpKeys): print ('# (i) Select "RESTART" option: #') print ('# #') print ('# Use one of the following options if you *have* a #') - print ('# GEOSldas restart file: #') + print ('# GEOSldas restart file: #') print ('# #') print ('# RESTART: 1 #') print ('# YES, have restart file from GEOSldas #') print ('# in SAME tile space (grid) with SAME boundary #') print ('# conditions and SAME snow model parameter (WEMIN). #') print ('# The restart domain can be for the same or #') - print ('# a larger one. #') + print ('# a larger one. #') print ('# #') print ('# RESTART: 2 #') print ('# YES, have restart file from GEOSldas but #') @@ -1441,17 +1437,17 @@ def _printExeInputKeys(rqdExeInpKeys): print ('# Restart *must* be for the GLOBAL domain. #') print ('# #') print ('# Use one of the following options if you DO NOT have a #') - print ('# GEOSldas restart file #') + print ('# GEOSldas restart file #') print ('# (works for global domain ONLY!): #') print ('# #') print ('# RESTART: 0 #') print ('# Cold start from some old restart for Jan 1, 0z. #') print ('# #') print ('# RESTART: M #') - print ('# Re-tile from archived MERRA-2 restart file. #') + print ('# Re-tile from archived MERRA-2 restart file. #') print ('# #') print ('# RESTART: F #') - print ('# Re-tile from FP (Forward Processing) restart file. #') + print ('# Re-tile from FP (Forward Processing) restart file. #') print ('# #') print ('# RESTART: G #') print ('# Re-tile from any AGCM catch[cnclmxx]_internal_rst file.#') @@ -1461,19 +1457,19 @@ def _printExeInputKeys(rqdExeInpKeys): print ('# Except for RESTART=1, SPIN-UP is REQUIRED in almost #') print ('# all cases. #') print ('# -------------------------------------------------------- #') - print ('# #') - print ('# #') + print ('# #') + print ('# #') print ('# (ii) Specify experiment ID/location of restart file: #') print ('# #') print ('# For RESTART=1 or RESTART=2: #') print ('# Specify RESTART_ID, RESTART_PATH, RESTART_DOMAIN with #') print ('# restarts stored as follows: #') print ('# RESTART_PATH/RESTART_ID/output/RESTART_DOMAIN/rs/ #') - print ('# #') + print ('# #') print ('# For RESTART=0 or RESTART=M or RESTART=F: #') print ('# There is no need to specify RESTART_ID, RESTART_PATH, #') print ('# and RESTART_DOMAIN. #') - print ('# #') + print ('# #') print ('# For RESTART=G: #') print ('# RESTART_ID : full_path_to_AGCM_experiment_directory #') print ('# RESTART_PATH : full_path_of_the_AGCM_restart_file #') @@ -1494,7 +1490,7 @@ def _printExeInputKeys(rqdExeInpKeys): print ('# #') print ('# For more information, see: #') print ('# GEOSldas/doc/README.MetForcing_and_BCS.md #') - print ('# #') + print ('# #') print ('############################################################') print () print ('MET_TAG:') @@ -1524,26 +1520,26 @@ def _printExeInputKeys(rqdExeInpKeys): print ('# #') print ('# 0 -- LDAS not coupled with ADAS (default) #') print ('# 1 -- LDAS coupled with central member of ADAS #') - print ('# 2 -- LDAS coupled with ens component of ADAS #') - print ('# #') + print ('# 2 -- LDAS coupled with ens component of ADAS #') + print ('# #') print ('# Requirements for LADAS_COUPLING > 0: #') - print ('# #') + print ('# #') print ('# (0) Specify ADAS_EXPDIR = [full_path]/[ADAS_EXPID] #') print ('# #') print ('# (1) BEG_DATE must be consistent with first cycle date #') print ('# and time of ADAS experiment (time is typically #') print ('# 3z, 9z, 15z, or 21z) #') - print ('# #') + print ('# #') print ('# (2) EXP_DOMAIN must be global CS grid as in ADAS exp #') print ('# #') print ('# (3) MET_TAG must be set to [ADAS_EXPID]__Nx+- #') print ('# MET_PATH must be set as follows for #') - print ('# LADAS_COUPLING = 1: #') - print ('# [full_path]/[LDAS_EXPID]/scratch/ #') - print ('# LADAS_COUPLING = 2: #') + print ('# LADAS_COUPLING = 1: #') + print ('# [full_path]/[LDAS_EXPID]/scratch/ #') + print ('# LADAS_COUPLING = 2: #') print ('# [ADAS_EXPDIR]/atmens/ensdiag/forc #') - print ('# After ldas exp setup, verify the following link: #') - print ('# ../input/met_forcing/forc -> [MET_PATH] #') + print ('# After ldas exp setup, verify the following link: #') + print ('# ../input/met_forcing/forc -> [MET_PATH] #') print ('# #') print ('# (4) BCS_PATH must be consistent with that of #') print ('# [ADAS_EXPDIR][/run/lnbcs #') @@ -1557,7 +1553,7 @@ def _printExeInputKeys(rqdExeInpKeys): print ('# - instantaneous "catch_progn_incr" must be in #') print ('# HISTORY collection #') print ('# - time step must match that of LDAS analysis #') - print ('# - for LADAS_COUPLING=2, HISTORY must include #') + print ('# - for LADAS_COUPLING=2, HISTORY must include #') print ('# "catch_progn_incr[ENS_INDEX]" #') print ('# #') print ('############################################################') @@ -1597,12 +1593,12 @@ def _printExeInputKeys(rqdExeInpKeys): i_ += 1 print () print () - + def _printRmInputKeys(rqdRmInpKeys, optRmInpKeys): """ Private method: print sample resource manager input """ - + print ('#') print ('# REQUIRED inputs') print ('#') @@ -1611,10 +1607,9 @@ def _printRmInputKeys(rqdRmInpKeys, optRmInpKeys): print ('# [At NCCS: Use command "getsponsor" to see available account number(s).]' ) print ('# - walltime = walltime requested; format is HH:MM:SS (hours/minutes/seconds)') print ('# - ntasks_model = number of processors requested for the model (typically 112; output server is not included)') - print ('# - ntasks-per-node = number of tasks per node (typically 126 for milan*, 46 for cascade lake**, and 40 for skylake)') - print ('# [If >46, milan nodes will be allocated; >40, cascade lake nodes will be allocated; if >28, cascade or skylake.]') - print ('# [*NCCS recommends <=126 cores per node on SCU17 (milan) due to OS issues (as of 6 Oct 2021).]') - print ('# [**NCCS recommends <=46 cores per node on SCU16 (cascade lake) due to OS issues (as of 6 Oct 2021).]') + print ('# - ntasks-per-node = number of tasks per node (typically 46 for cascade* and 40 for skylake nodes)') + print ('# [If >40, cascade nodes will be allocated, else cascade or skylake.]') + print ('# [*NCCS recommends <=46 cores per node on SCU16 (cascade) due to OS issues (as of 6 Oct 2021).]') print ('#') for key in rqdRmInpKeys: print (key + ':') @@ -1632,7 +1627,7 @@ def _printRmInputKeys(rqdRmInpKeys, optRmInpKeys): print ('#') for key in optRmInpKeys: print ('#'+key + ':') - + def parseCmdLine(): """ parse command line arguments and return a dict of options @@ -1650,14 +1645,14 @@ def parseCmdLine(): # subparser: sample command p_sample = p_sub.add_parser( - 'sample', + 'sample', help='write sample input files', description='Print sample input files - either for the '\ 'Fortran executable or the resource manager (SLURM)', ) group = p_sample.add_mutually_exclusive_group(required=True) group.add_argument( - '--exeinp', + '--exeinp', help='print sample input file used to generate RC files for GEOSldas App.', action='store_true', ) @@ -1668,25 +1663,25 @@ def parseCmdLine(): ) # subparser: setup command p_setup = p_sub.add_parser( - 'setup', + 'setup', help='setup LDAS experiment', description="The 'setup' sub-command is used to setup a GEOSldas " \ "experiment. The positional argument 'exphome' is used to create " \ "work_path (exphome+/output) and run_path (exphome+/run)." ) p_setup.add_argument( - '-v', - '--verbose', - help='verbose output', + '-v', + '--verbose', + help='verbose output', action='store_true', ) p_setup.add_argument('exphome', help='experiment location') p_setup.add_argument( - 'exeinpfile', + 'exeinpfile', help='input file with arguments used to generate RC files for GEOSldas App', ) p_setup.add_argument( - 'batinpfile', + 'batinpfile', help='input file with arguments for SLURM', ) p_setup.add_argument( @@ -1722,7 +1717,7 @@ if __name__=='__main__': #print "reading params...." args = vars(parseCmdLine()) # vars converts to dict ld = LDASsetup(args) - + print ("creating dir structure") status = ld.createDirStructure() assert(status) From 32a035480cca5365609b0932f51e606bc0c482db Mon Sep 17 00:00:00 2001 From: Rolf Reichle <54944691+gmao-rreichle@users.noreply.github.com> Date: Thu, 30 Nov 2023 17:02:44 -0500 Subject: [PATCH 191/308] minimal edits of comment lines in ASCAT reader (clsm_ensupd_read_obs.F90) --- .../GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 60c6900c..98b5e60f 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -1947,15 +1947,17 @@ subroutine read_obs_sm_ASCAT_EUMET( & end if end do - - ! normalize - + + ! normalize and set obs error std-dev + do ii=1,N_catd ! set observation error standard deviation ASCAT_sm_std(ii) = this_obs_param%errstd/100. ! change units from percent (0-100) to fraction (0-1) - + + ! normalize + if (N_obs_in_tile(ii)>1) then ASCAT_sm( ii) = ASCAT_sm( ii)/real(N_obs_in_tile(ii)) From 1963bc2c4de6beb886aa4f4a3279ea3112e7a6d4 Mon Sep 17 00:00:00 2001 From: biljanaorescanin Date: Fri, 1 Dec 2023 09:09:56 -0500 Subject: [PATCH 192/308] update repos --- components.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components.yaml b/components.yaml index 4ed074dd..642ab88a 100644 --- a/components.yaml +++ b/components.yaml @@ -5,13 +5,13 @@ GEOSldas: env: local: ./@env remote: ../ESMA_env.git - tag: v4.20.5 + tag: v4.23.0 develop: main cmake: local: ./@cmake remote: ../ESMA_cmake.git - tag: v3.35.0 + tag: v3.36.0 develop: develop ecbuild: @@ -22,7 +22,7 @@ ecbuild: GMAO_Shared: local: ./src/Shared/@GMAO_Shared remote: ../GMAO_Shared.git - tag: v1.9.5 + tag: v1.9.6 sparse: ./config/GMAO_Shared.sparse develop: main @@ -35,7 +35,7 @@ GEOS_Util: MAPL: local: ./src/Shared/@MAPL remote: ../MAPL.git - tag: v2.41.1 + tag: v2.42.1 develop: develop GEOSgcm_GridComp: From 6ca92d1ed57ac91ca11220e95649a967774de8fd Mon Sep 17 00:00:00 2001 From: biljanaorescanin Date: Fri, 1 Dec 2023 12:42:53 -0500 Subject: [PATCH 193/308] update baselibs --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 45aaa3a8..23de0f65 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,7 +1,7 @@ version: 2.1 # Anchor to prevent forgetting to update a version -baselibs_version: &baselibs_version v7.14.0 +baselibs_version: &baselibs_version v7.16.0 orbs: ci: geos-esm/circleci-tools@1 From 82a1b90cdd0b39985f5f783a40366160d5612aa6 Mon Sep 17 00:00:00 2001 From: Weiyuan Jiang Date: Mon, 4 Dec 2023 12:30:24 -0500 Subject: [PATCH 194/308] adapt to new remap_restart --- src/Applications/LDAS_App/ldas_setup | 12 +++++++++-- .../LDAS_App/remap_config_ldas.py | 20 +++++++++++++++---- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/Applications/LDAS_App/ldas_setup b/src/Applications/LDAS_App/ldas_setup index fa8eb622..8af526ab 100755 --- a/src/Applications/LDAS_App/ldas_setup +++ b/src/Applications/LDAS_App/ldas_setup @@ -838,12 +838,17 @@ class LDASsetup: mk_outdir = self.exphome+'/'+exp_id+'/mk_restarts/' if (RESTART_str != '1'): + bcs_path = self.rqdExeInp['BCS_PATH'] + while bcs_path[-1] == '/' : bcs_path = bcs_path[0:-1] + bc_base = os.path.dirname(bcs_path) + bc_version = os.path.basename(bcs_path) + remap_tpl = os.path.dirname(os.path.realpath(__file__)) + '/remap_params.tpl' config = yaml_to_config(remap_tpl) config['slurm']['account'] = self.rqdRmInp['account'] config['slurm']['qos'] = 'debug' - config['slurm']['qos'] = 'cas' + config['slurm']['partition'] = 'cas|sky' config['input']['surface']['catch_tilefile'] = self.in_tilefile config['input']['shared']['expid'] = self.rqdExeInp['RESTART_ID'] @@ -855,7 +860,10 @@ class LDASsetup: config['output']['shared']['out_dir'] = mk_outdir config['output']['surface']['catch_remap'] = True config['output']['surface']['catch_tilefile'] = self.rqdExeInp['TILING_FILE'] - config['output']['shared']['bcs_dir'] = self.bcs_land + config['output']['shared']['bc_base'] = bc_base + config['output']['shared']['bc_version'] = bc_version + config['output']['surface']['EASE_grid'] = self.rqdExeInp['BCS_RESOLUTION'] + config['output']['shared']['expid'] = self.rqdExeInp['EXP_ID'] config['output']['surface']['surflay'] = dzsf config['output']['surface']['wemin'] = wemin_out diff --git a/src/Applications/LDAS_App/remap_config_ldas.py b/src/Applications/LDAS_App/remap_config_ldas.py index 8b990a38..9848916b 100644 --- a/src/Applications/LDAS_App/remap_config_ldas.py +++ b/src/Applications/LDAS_App/remap_config_ldas.py @@ -16,8 +16,12 @@ def remap_config_ldas(config, RESTART_str, RESTART_PATH, RESTART_ID): config['input']['shared'] = merra2_expid(config['input']['shared']) config['input']['shared']['rst_dir'] = out_dir+ '/merra2_tmp_'+ yyyymmddhh config['input']['surface']['wemin'] = 26 - config['input']['shared']['bcs_dir'] = '/discover/nobackup/projects/gmao/bcs_shared/fvInput/ExtData/esm/tiles/GM4/land/CF0180x6C_DE1440xPE0720/' - + config['input']['shared']['bc_base'] = '/discover/nobackup/projects/gmao/bcs_shared/fvInput/ExtData/esm/tiles' + config['input']['shared']['bc_version'] = 'GM4' + config['input']['shared']['agrid'] = 'C180' + config['input']['shared']['ogrid'] = '1440x720' + config['input']['shared']['omodel'] = 'data' + if RESTART_str == "G" : # WY note: it is a bad idea to overload restart_path and restart_id config['input']['surface']['catch_tilefile'] = os.path.realpath(RESTART_ID+'scratch/tile.data') @@ -39,7 +43,11 @@ def remap_config_ldas(config, RESTART_str, RESTART_PATH, RESTART_ID): print( " Please select RESTART: M and use MERRA-2, instead.") sys.exit(1) - config['input']['shared']['bcs_dir'] = '/discover/nobackup/projects/gmao/bcs_shared/fvInput/ExtData/esm/tiles/ICA/land/CF0720x6C_CF0720x6C/' + config['input']['shared']['bc_base'] = '/discover/nobackup/projects/gmao/bcs_shared/fvInput/ExtData/esm/tiles' + config['input']['shared']['bc_version'] = 'ICA' + config['input']['shared']['agrid'] = 'C720' + config['input']['shared']['ogrid'] = 'C720' + config['input']['surface']['wemin'] = 26 config['input']['shared']['rst_dir'] = out_dir+'/InData'+ '/' suffix = '_21z.tar' @@ -47,7 +55,11 @@ def remap_config_ldas(config, RESTART_str, RESTART_PATH, RESTART_ID): if ((date_16 <= expdate) and (expdate < date_17)): fpver = 'GEOS-5.16/GEOSadas-5_16/' fplab = 'f516_fp' - config['input']['shared']['bcs_dir'] = '/discover/nobackup/projects/gmao/bcs_shared/fvInput/ExtData/esm/tiles/GM4/land/CF0720x6C_DE2880xPE1440/' + config['input']['shared']['bc_base'] = '/discover/nobackup/projects/gmao/bcs_shared/fvInput/ExtData/esm/tiles' + config['input']['shared']['bc_version'] = 'GM4' + config['input']['shared']['agrid'] = 'C720' + config['input']['shared']['ogrid'] = '2880x1440' + suffix = '_21z.bin' if ((date_17 <= expdate) and (expdate < date_21)): From 1e55616764abc72a476a687c2446a6c13cfe977a Mon Sep 17 00:00:00 2001 From: Qing Liu Date: Mon, 4 Dec 2023 12:53:33 -0500 Subject: [PATCH 195/308] Add reading GEOSIT forcing data --- .../GEOSmetforce_GridComp/LDAS_Forcing.F90 | 92 ++++++++++++++++++- 1 file changed, 88 insertions(+), 4 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 b/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 index dd6d4a23..53915d1d 100755 --- a/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 @@ -3170,6 +3170,7 @@ subroutine get_GEOS( date_time, force_dtstep, met_path, met_tag, & real, parameter :: nodata_GEOSgcm = 1.e15 character(40), dimension(N_G5DAS_vars, N_defs_cols) :: G5DAS_defs + character(40), dimension(N_G5DAS_vars, N_defs_cols) :: GEOSIT_defs character(40), dimension(N_MERRA_vars, N_defs_cols) :: MERRA_defs character(40), dimension(N_MERRA2plusAerosol_vars, N_defs_cols) :: M2INT_defs character(40), dimension(N_MERRA2plusAerosol_vars, N_defs_cols) :: M2COR_defs @@ -3243,6 +3244,33 @@ subroutine get_GEOS( date_time, force_dtstep, met_path, met_tag, & G5DAS_defs(11,:)=[character(len=40):: 'QLML ','inst','inst1_2d_lfo_Nx','diag','S'] G5DAS_defs(12,:)=[character(len=40):: 'SPEEDLML','inst','inst1_2d_lfo_Nx','diag','S'] + ! ----------------------------------------------------------------------- + ! + ! define GEOSIT file specs + ! + ! columns of GEOSgcm_defs are as follows: + ! 1 - short variable name in gfio file + ! 2 - averaging mode in G5DAS/MERRA file ('tavg' or 'inst') + ! 3 - file tag (eg. 'bkg.sfc' or 'diag_sfc', or 'tavg1_2d_rad_Nx') + ! 4 - file dir ('ana' or 'diag') + ! 5 - treated as S="state" or F="flux" in subroutine interpolate_to_timestep() + + ! GEOSIT file specs (default, unless otherwise specified via "met_tag") + + + GEOSIT_defs( 1,:)=[character(len=40):: 'SWGDN ','tavg','lfo_tavg_1hr_glo_L576x361_slv','diag','F'] + GEOSIT_defs( 2,:)=[character(len=40):: 'LWGAB ','tavg','lfo_tavg_1hr_glo_L576x361_slv','diag','F'] + GEOSIT_defs( 3,:)=[character(len=40):: 'PARDR ','tavg','lfo_tavg_1hr_glo_L576x361_slv','diag','F'] + GEOSIT_defs( 4,:)=[character(len=40):: 'PARDF ','tavg','lfo_tavg_1hr_glo_L576x361_slv','diag','F'] + GEOSIT_defs( 5,:)=[character(len=40):: 'PRECCU ','tavg','lfo_tavg_1hr_glo_L576x361_slv','diag','F'] + GEOSIT_defs( 6,:)=[character(len=40):: 'PRECLS ','tavg','lfo_tavg_1hr_glo_L576x361_slv','diag','F'] + GEOSIT_defs( 7,:)=[character(len=40):: 'PRECSNO ','tavg','lfo_tavg_1hr_glo_L576x361_slv','diag','F'] + GEOSIT_defs( 8,:)=[character(len=40):: 'PS ','inst','lfo_inst_1hr_glo_L576x361_slv','diag','S'] + GEOSIT_defs( 9,:)=[character(len=40):: 'HLML ','inst','lfo_inst_1hr_glo_L576x361_slv','diag','S'] + GEOSIT_defs(10,:)=[character(len=40):: 'TLML ','inst','lfo_inst_1hr_glo_L576x361_slv','diag','S'] + GEOSIT_defs(11,:)=[character(len=40):: 'QLML ','inst','lfo_inst_1hr_glo_L576x361_slv','diag','S'] + GEOSIT_defs(12,:)=[character(len=40):: 'SPEEDLML','inst','lfo_inst_1hr_glo_L576x361_slv','diag','S'] + ! MERRA-2 file specs with uncorrected (AGCM) precip from the "int" Collection ! (ie, the precip generated by the AGCM within the MERRA-2 system) @@ -3576,8 +3604,12 @@ subroutine get_GEOS( date_time, force_dtstep, met_path, met_tag, & allocate(GEOSgcm_defs(N_GEOSgcm_vars,N_defs_cols)) - GEOSgcm_defs(1:N_G5DAS_vars, :) = G5DAS_defs - + if (index(met_tag, 'GEOSIT') > 0 .or. index(met_tag, 'geosit') > 0) then + GEOSgcm_defs(1:N_G5DAS_vars, :) = GEOSIT_defs + else + GEOSgcm_defs(1:N_G5DAS_vars, :) = G5DAS_defs + end if + call parse_G5DAS_met_tag( met_path, met_tag, date_time_inst, & met_path_inst, prec_path_inst, met_tag_inst, use_prec_corr, & use_Predictor ) @@ -4658,6 +4690,10 @@ subroutine parse_G5DAS_met_tag( met_path_in, met_tag_in, date_time, & type(date_time_type) :: dt_end_d5124_rpit2 type(date_time_type) :: dt_end_d5124_rpit3 + type(date_time_type) :: dt_end_d5294_geosit1 + type(date_time_type) :: dt_end_d5294_geosit2 + type(date_time_type) :: dt_end_d5294_geosit3 + type(date_time_type) :: dt_end_e5110_fp type(date_time_type) :: dt_end_e5130_fp type(date_time_type) :: dt_end_e5131_fp @@ -4738,6 +4774,33 @@ subroutine parse_G5DAS_met_tag( met_path_in, met_tag_in, date_time, & dt_end_d5124_rpit3%min = 0 dt_end_d5124_rpit3%sec = 0 + ! | stream start | stream end + ! ---------------------------------------- + ! d5294_geosit1 | 1 Jan 1998 | 1 Jan 2008 + ! d5294_geosit2 | 1 Jan 2008 | 1 Jan 2018 + ! d5294_geosit3 | 1 Jan 2018 | (present) + + dt_end_d5294_geosit1%year = 2008 + dt_end_d5294_geosit1%month = 1 + dt_end_d5294_geosit1%day = 1 + dt_end_d5294_geosit1%hour = 0 + dt_end_d5294_geosit1%min = 0 + dt_end_d5294_geosit1%sec = 0 + + dt_end_d5294_geosit2%year = 2018 + dt_end_d5294_geosit2%month = 1 + dt_end_d5294_geosit2%day = 1 + dt_end_d5294_geosit2%hour = 0 + dt_end_d5294_geosit2%min = 0 + dt_end_d5294_geosit2%sec = 0 + + dt_end_d5294_geosit3%year = 9999 + dt_end_d5294_geosit3%month = 1 + dt_end_d5294_geosit3%day = 1 + dt_end_d5294_geosit3%hour = 0 + dt_end_d5294_geosit3%min = 0 + dt_end_d5294_geosit3%sec = 0 + ! --------------------------------- ! ! FP streams @@ -4957,6 +5020,23 @@ subroutine parse_G5DAS_met_tag( met_path_in, met_tag_in, date_time, & end if + elseif (met_tag_out(1:18)=='cross_GEOSIT') then + + if (datetime_lt_refdatetime( date_time, dt_end_d5294_geosit1 )) then + + stream = 'd5294_geosit_jan98' ! use d5294_geosit stream 1 + + elseif (datetime_lt_refdatetime( date_time, dt_end_d5294_geosit2 )) then + + stream = 'd5294_geosit_jan08' ! use d5294_geosit stream 2 + + else + + stream = 'd5294_geosit_jan18' ! use d5294_geosit stream 2 + + end if + + elseif (met_tag_out(1:8)=='cross_FP') then if (datetime_lt_refdatetime( date_time, dt_end_e5110_fp )) then @@ -5103,7 +5183,7 @@ subroutine get_GEOS_forcing_filename(fname_full,file_exists, date_time, daily_fi ! local variables character(300) :: fname, fname_full_tmp1, fname_full_tmp2 - character( 14) :: time_stamp + character( 20) :: time_stamp character( 4) :: YYYY, HHMM, day_dir character( 2) :: MM, DD @@ -5131,8 +5211,12 @@ subroutine get_GEOS_forcing_filename(fname_full,file_exists, date_time, daily_fi time_stamp(1:8) = YYYY // MM // DD - else + elseif (index(met_tag,'GEOSIT') > 0 .or. index(met_tag,'geosit') > 0) then + time_stamp = YYYY //'-'// MM //'-'// DD // 'T' // trim(HHMM) // 'Z' + + else + time_stamp = YYYY // MM // DD // '_' // trim(HHMM) // 'z' end if From 472bbb3343f9a275c85a5b737bc57340a02b3551 Mon Sep 17 00:00:00 2001 From: Qing Liu Date: Tue, 5 Dec 2023 10:28:44 -0500 Subject: [PATCH 196/308] fix minor typo --- .../GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 b/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 index 53915d1d..b0968aa0 100755 --- a/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 @@ -5020,7 +5020,7 @@ subroutine parse_G5DAS_met_tag( met_path_in, met_tag_in, date_time, & end if - elseif (met_tag_out(1:18)=='cross_GEOSIT') then + elseif (met_tag_out(1:12)=='cross_GEOSIT') then if (datetime_lt_refdatetime( date_time, dt_end_d5294_geosit1 )) then @@ -5032,7 +5032,7 @@ subroutine parse_G5DAS_met_tag( met_path_in, met_tag_in, date_time, & else - stream = 'd5294_geosit_jan18' ! use d5294_geosit stream 2 + stream = 'd5294_geosit_jan18' ! use d5294_geosit stream 3 end if From 51b900d6d121710fb9f2b644fa5fd032b551a149 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Tue, 5 Dec 2023 17:49:34 -0500 Subject: [PATCH 197/308] minor edits for GEOS-IT forcing (LDAS_Forcing.F90) --- .../GEOSmetforce_GridComp/LDAS_Forcing.F90 | 76 +++++++++---------- 1 file changed, 37 insertions(+), 39 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 b/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 index b0968aa0..d71ba2f8 100755 --- a/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 @@ -3090,6 +3090,7 @@ subroutine get_GEOS( date_time, force_dtstep, met_path, met_tag, & ! (for MERRA-2, always point to publicly available files) ! - updated comments ! + ! qliu+reichle, 5 Dec 2023 - added GEOS-IT ! ! ----------------------------------- ! @@ -3246,30 +3247,24 @@ subroutine get_GEOS( date_time, force_dtstep, met_path, met_tag, & ! ----------------------------------------------------------------------- ! - ! define GEOSIT file specs + ! define GEOS-IT file specs ! - ! columns of GEOSgcm_defs are as follows: - ! 1 - short variable name in gfio file - ! 2 - averaging mode in G5DAS/MERRA file ('tavg' or 'inst') - ! 3 - file tag (eg. 'bkg.sfc' or 'diag_sfc', or 'tavg1_2d_rad_Nx') - ! 4 - file dir ('ana' or 'diag') - ! 5 - treated as S="state" or F="flux" in subroutine interpolate_to_timestep() - - ! GEOSIT file specs (default, unless otherwise specified via "met_tag") + ! same as G5DAS except for file tag (column 3) + GEOSIT_defs = G5DAS_defs - GEOSIT_defs( 1,:)=[character(len=40):: 'SWGDN ','tavg','lfo_tavg_1hr_glo_L576x361_slv','diag','F'] - GEOSIT_defs( 2,:)=[character(len=40):: 'LWGAB ','tavg','lfo_tavg_1hr_glo_L576x361_slv','diag','F'] - GEOSIT_defs( 3,:)=[character(len=40):: 'PARDR ','tavg','lfo_tavg_1hr_glo_L576x361_slv','diag','F'] - GEOSIT_defs( 4,:)=[character(len=40):: 'PARDF ','tavg','lfo_tavg_1hr_glo_L576x361_slv','diag','F'] - GEOSIT_defs( 5,:)=[character(len=40):: 'PRECCU ','tavg','lfo_tavg_1hr_glo_L576x361_slv','diag','F'] - GEOSIT_defs( 6,:)=[character(len=40):: 'PRECLS ','tavg','lfo_tavg_1hr_glo_L576x361_slv','diag','F'] - GEOSIT_defs( 7,:)=[character(len=40):: 'PRECSNO ','tavg','lfo_tavg_1hr_glo_L576x361_slv','diag','F'] - GEOSIT_defs( 8,:)=[character(len=40):: 'PS ','inst','lfo_inst_1hr_glo_L576x361_slv','diag','S'] - GEOSIT_defs( 9,:)=[character(len=40):: 'HLML ','inst','lfo_inst_1hr_glo_L576x361_slv','diag','S'] - GEOSIT_defs(10,:)=[character(len=40):: 'TLML ','inst','lfo_inst_1hr_glo_L576x361_slv','diag','S'] - GEOSIT_defs(11,:)=[character(len=40):: 'QLML ','inst','lfo_inst_1hr_glo_L576x361_slv','diag','S'] - GEOSIT_defs(12,:)=[character(len=40):: 'SPEEDLML','inst','lfo_inst_1hr_glo_L576x361_slv','diag','S'] + GEOSIT_defs( 1,3)=[character(len=40):: 'lfo_tavg_1hr_glo_L576x361_slv'] + GEOSIT_defs( 2,3)=[character(len=40):: 'lfo_tavg_1hr_glo_L576x361_slv'] + GEOSIT_defs( 3,3)=[character(len=40):: 'lfo_tavg_1hr_glo_L576x361_slv'] + GEOSIT_defs( 4,3)=[character(len=40):: 'lfo_tavg_1hr_glo_L576x361_slv'] + GEOSIT_defs( 5,3)=[character(len=40):: 'lfo_tavg_1hr_glo_L576x361_slv'] + GEOSIT_defs( 6,3)=[character(len=40):: 'lfo_tavg_1hr_glo_L576x361_slv'] + GEOSIT_defs( 7,3)=[character(len=40):: 'lfo_tavg_1hr_glo_L576x361_slv'] + GEOSIT_defs( 8,3)=[character(len=40):: 'lfo_inst_1hr_glo_L576x361_slv'] + GEOSIT_defs( 9,3)=[character(len=40):: 'lfo_inst_1hr_glo_L576x361_slv'] + GEOSIT_defs(10,3)=[character(len=40):: 'lfo_inst_1hr_glo_L576x361_slv'] + GEOSIT_defs(11,3)=[character(len=40):: 'lfo_inst_1hr_glo_L576x361_slv'] + GEOSIT_defs(12,3)=[character(len=40):: 'lfo_inst_1hr_glo_L576x361_slv'] ! MERRA-2 file specs with uncorrected (AGCM) precip from the "int" Collection @@ -3604,10 +3599,10 @@ subroutine get_GEOS( date_time, force_dtstep, met_path, met_tag, & allocate(GEOSgcm_defs(N_GEOSgcm_vars,N_defs_cols)) - if (index(met_tag, 'GEOSIT') > 0 .or. index(met_tag, 'geosit') > 0) then - GEOSgcm_defs(1:N_G5DAS_vars, :) = GEOSIT_defs + if ( (index(met_tag, 'GEOSIT') > 0) .or. (index(met_tag, 'geosit') > 0) ) then + GEOSgcm_defs(1:N_G5DAS_vars,:) = GEOSIT_defs else - GEOSgcm_defs(1:N_G5DAS_vars, :) = G5DAS_defs + GEOSgcm_defs(1:N_G5DAS_vars,:) = G5DAS_defs end if call parse_G5DAS_met_tag( met_path, met_tag, date_time_inst, & @@ -4639,8 +4634,8 @@ subroutine parse_G5DAS_met_tag( met_path_in, met_tag_in, date_time, & ! where {__prec[PREC]} and {__Nx+-} are optional and where ! ! G5DAS-NAME : name of standard G5DAS forcing (must not contain "__"!) - ! e.g., "e5110_fp", "d591_rpit1", "d591_fpit", ... - ! for cross-stream forcing, use "cross_d5124_RPFPIT" or "cross_FP" + ! e.g., "e5110_fp", "d591_rpit1", "d591_fpit", "d5294_geosit", ... + ! for cross-stream forcing, use "cross_d5294_GEOSIT", "cross_d5124_RPFPIT", "cross_FP" ! PREC : identifier for precip corrections to G5DAS forcing (eg., 'GPCPv1.1') ! ! If {__Nx+-} is present, set flag for use forcing files from the DAS/GCM Predictor @@ -4658,6 +4653,7 @@ subroutine parse_G5DAS_met_tag( met_path_in, met_tag_in, date_time, & ! reichle, 10 Oct 2019: added FP transition from f521 to f522 ! reichle, 17 Jan 2020: added FP transition from f522 to f525 ! reichle, 3 Apr 2020: added FP transition from f525 to f525_p5 + ! qliu+reichle, 5 Dec 2023: added GEOS-IT ! ! --------------------------------------------------------------------------- @@ -4709,7 +4705,7 @@ subroutine parse_G5DAS_met_tag( met_path_in, met_tag_in, date_time, & ! ---------------------------------------------------------- ! - ! define transition times between RP-IT, FP-IT or FP streams + ! define transition times between RP-IT, FP-IT, GEOS-IT, or FP streams ! if "cross-stream" forcing is requested ! ! | stream start | stream end (as of 5 Dec 2014) @@ -4774,11 +4770,13 @@ subroutine parse_G5DAS_met_tag( met_path_in, met_tag_in, date_time, & dt_end_d5124_rpit3%min = 0 dt_end_d5124_rpit3%sec = 0 - ! | stream start | stream end + ! | stream start | stream end + ! | (excl 1-yr | + ! | spinup) | ! ---------------------------------------- - ! d5294_geosit1 | 1 Jan 1998 | 1 Jan 2008 - ! d5294_geosit2 | 1 Jan 2008 | 1 Jan 2018 - ! d5294_geosit3 | 1 Jan 2018 | (present) + ! d5294_geosit1 | 1 Jan 1998 | 1 Jan 2008 + ! d5294_geosit2 | 1 Jan 2008 | 1 Jan 2018 + ! d5294_geosit3 | 1 Jan 2018 | (present) dt_end_d5294_geosit1%year = 2008 dt_end_d5294_geosit1%month = 1 @@ -5020,19 +5018,19 @@ subroutine parse_G5DAS_met_tag( met_path_in, met_tag_in, date_time, & end if - elseif (met_tag_out(1:12)=='cross_GEOSIT') then + elseif (met_tag_out(1:18)=='cross_d5924_GEOSIT') then if (datetime_lt_refdatetime( date_time, dt_end_d5294_geosit1 )) then - stream = 'd5294_geosit_jan98' ! use d5294_geosit stream 1 + stream = 'd5294_geosit_jan98' ! use d5294 GEOS-IT stream 1 elseif (datetime_lt_refdatetime( date_time, dt_end_d5294_geosit2 )) then - stream = 'd5294_geosit_jan08' ! use d5294_geosit stream 2 + stream = 'd5294_geosit_jan08' ! use d5294 GEOS-IT stream 2 else - stream = 'd5294_geosit_jan18' ! use d5294_geosit stream 3 + stream = 'd5294_geosit_jan18' ! use d5294 GEOS-IT stream 3 end if @@ -5183,7 +5181,7 @@ subroutine get_GEOS_forcing_filename(fname_full,file_exists, date_time, daily_fi ! local variables character(300) :: fname, fname_full_tmp1, fname_full_tmp2 - character( 20) :: time_stamp + character( 16) :: time_stamp character( 4) :: YYYY, HHMM, day_dir character( 2) :: MM, DD @@ -5209,15 +5207,15 @@ subroutine get_GEOS_forcing_filename(fname_full,file_exists, date_time, daily_fi if (daily_file) then - time_stamp(1:8) = YYYY // MM // DD + time_stamp(1:8) = YYYY // MM // DD elseif (index(met_tag,'GEOSIT') > 0 .or. index(met_tag,'geosit') > 0) then - time_stamp = YYYY //'-'// MM //'-'// DD // 'T' // trim(HHMM) // 'Z' + time_stamp(1:16) = YYYY //'-'// MM //'-'// DD // 'T' // trim(HHMM) // 'Z' else - time_stamp = YYYY // MM // DD // '_' // trim(HHMM) // 'z' + time_stamp(1:14) = YYYY // MM // DD // '_' // trim(HHMM) // 'z' end if From a8227f1fbc2772964d42c9459847cf05db0e9f86 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Tue, 5 Dec 2023 18:23:09 -0500 Subject: [PATCH 198/308] fixed character array syntax for GEOSIT_defs (LDAS_Forcing.F90) --- .../GEOSmetforce_GridComp/LDAS_Forcing.F90 | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 b/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 index d71ba2f8..86f976e0 100755 --- a/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 @@ -3250,21 +3250,24 @@ subroutine get_GEOS( date_time, force_dtstep, met_path, met_tag, & ! define GEOS-IT file specs ! ! same as G5DAS except for file tag (column 3) - - GEOSIT_defs = G5DAS_defs - - GEOSIT_defs( 1,3)=[character(len=40):: 'lfo_tavg_1hr_glo_L576x361_slv'] - GEOSIT_defs( 2,3)=[character(len=40):: 'lfo_tavg_1hr_glo_L576x361_slv'] - GEOSIT_defs( 3,3)=[character(len=40):: 'lfo_tavg_1hr_glo_L576x361_slv'] - GEOSIT_defs( 4,3)=[character(len=40):: 'lfo_tavg_1hr_glo_L576x361_slv'] - GEOSIT_defs( 5,3)=[character(len=40):: 'lfo_tavg_1hr_glo_L576x361_slv'] - GEOSIT_defs( 6,3)=[character(len=40):: 'lfo_tavg_1hr_glo_L576x361_slv'] - GEOSIT_defs( 7,3)=[character(len=40):: 'lfo_tavg_1hr_glo_L576x361_slv'] - GEOSIT_defs( 8,3)=[character(len=40):: 'lfo_inst_1hr_glo_L576x361_slv'] - GEOSIT_defs( 9,3)=[character(len=40):: 'lfo_inst_1hr_glo_L576x361_slv'] - GEOSIT_defs(10,3)=[character(len=40):: 'lfo_inst_1hr_glo_L576x361_slv'] - GEOSIT_defs(11,3)=[character(len=40):: 'lfo_inst_1hr_glo_L576x361_slv'] - GEOSIT_defs(12,3)=[character(len=40):: 'lfo_inst_1hr_glo_L576x361_slv'] + ! + ! GEOSIT character(40): + ! + ! 1 2 3 4 + ! 1234567890123456789012345678901234567890 + + GEOSIT_defs( 1,3) = 'lfo_tavg_1hr_glo_L576x361_slv ' + GEOSIT_defs( 2,3) = 'lfo_tavg_1hr_glo_L576x361_slv ' + GEOSIT_defs( 3,3) = 'lfo_tavg_1hr_glo_L576x361_slv ' + GEOSIT_defs( 4,3) = 'lfo_tavg_1hr_glo_L576x361_slv ' + GEOSIT_defs( 5,3) = 'lfo_tavg_1hr_glo_L576x361_slv ' + GEOSIT_defs( 6,3) = 'lfo_tavg_1hr_glo_L576x361_slv ' + GEOSIT_defs( 7,3) = 'lfo_tavg_1hr_glo_L576x361_slv ' + GEOSIT_defs( 8,3) = 'lfo_inst_1hr_glo_L576x361_slv ' + GEOSIT_defs( 9,3) = 'lfo_inst_1hr_glo_L576x361_slv ' + GEOSIT_defs(10,3) = 'lfo_inst_1hr_glo_L576x361_slv ' + GEOSIT_defs(11,3) = 'lfo_inst_1hr_glo_L576x361_slv ' + GEOSIT_defs(12,3) = 'lfo_inst_1hr_glo_L576x361_slv ' ! MERRA-2 file specs with uncorrected (AGCM) precip from the "int" Collection From 9377a7b405677645b7bc06fe5784b95274a76eb1 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Tue, 5 Dec 2023 18:33:06 -0500 Subject: [PATCH 199/308] nicer way of character array constructor for GEOSIT_defs (LDAS_Forcing.F90) --- .../GEOSmetforce_GridComp/LDAS_Forcing.F90 | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 b/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 index 86f976e0..9955c38b 100755 --- a/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 @@ -3176,6 +3176,8 @@ subroutine get_GEOS( date_time, force_dtstep, met_path, met_tag, & character(40), dimension(N_MERRA2plusAerosol_vars, N_defs_cols) :: M2INT_defs character(40), dimension(N_MERRA2plusAerosol_vars, N_defs_cols) :: M2COR_defs + character(40), dimension(N_G5DAS_vars) :: GEOSIT_ftag + character(40), dimension(:,:), allocatable :: GEOSgcm_defs ! NOTE: met_path, prec_path, and met_tag for current ('inst') time and fwd and bkwd 'tavg' @@ -3249,26 +3251,24 @@ subroutine get_GEOS( date_time, force_dtstep, met_path, met_tag, & ! ! define GEOS-IT file specs ! - ! same as G5DAS except for file tag (column 3) - ! - ! GEOSIT character(40): - ! - ! 1 2 3 4 - ! 1234567890123456789012345678901234567890 + ! same as G5DAS except for file tags (column 3) + + GEOSIT_defs = G5DAS_defs - GEOSIT_defs( 1,3) = 'lfo_tavg_1hr_glo_L576x361_slv ' - GEOSIT_defs( 2,3) = 'lfo_tavg_1hr_glo_L576x361_slv ' - GEOSIT_defs( 3,3) = 'lfo_tavg_1hr_glo_L576x361_slv ' - GEOSIT_defs( 4,3) = 'lfo_tavg_1hr_glo_L576x361_slv ' - GEOSIT_defs( 5,3) = 'lfo_tavg_1hr_glo_L576x361_slv ' - GEOSIT_defs( 6,3) = 'lfo_tavg_1hr_glo_L576x361_slv ' - GEOSIT_defs( 7,3) = 'lfo_tavg_1hr_glo_L576x361_slv ' - GEOSIT_defs( 8,3) = 'lfo_inst_1hr_glo_L576x361_slv ' - GEOSIT_defs( 9,3) = 'lfo_inst_1hr_glo_L576x361_slv ' - GEOSIT_defs(10,3) = 'lfo_inst_1hr_glo_L576x361_slv ' - GEOSIT_defs(11,3) = 'lfo_inst_1hr_glo_L576x361_slv ' - GEOSIT_defs(12,3) = 'lfo_inst_1hr_glo_L576x361_slv ' + GEOSIT_ftag( 1,3)=[character(len=40):: 'lfo_tavg_1hr_glo_L576x361_slv'] + GEOSIT_ftag( 2,3)=[character(len=40):: 'lfo_tavg_1hr_glo_L576x361_slv'] + GEOSIT_ftag( 3,3)=[character(len=40):: 'lfo_tavg_1hr_glo_L576x361_slv'] + GEOSIT_ftag( 4,3)=[character(len=40):: 'lfo_tavg_1hr_glo_L576x361_slv'] + GEOSIT_ftag( 5,3)=[character(len=40):: 'lfo_tavg_1hr_glo_L576x361_slv'] + GEOSIT_ftag( 6,3)=[character(len=40):: 'lfo_tavg_1hr_glo_L576x361_slv'] + GEOSIT_ftag( 7,3)=[character(len=40):: 'lfo_tavg_1hr_glo_L576x361_slv'] + GEOSIT_ftag( 8,3)=[character(len=40):: 'lfo_inst_1hr_glo_L576x361_slv'] + GEOSIT_ftag( 9,3)=[character(len=40):: 'lfo_inst_1hr_glo_L576x361_slv'] + GEOSIT_ftag(10,3)=[character(len=40):: 'lfo_inst_1hr_glo_L576x361_slv'] + GEOSIT_ftag(11,3)=[character(len=40):: 'lfo_inst_1hr_glo_L576x361_slv'] + GEOSIT_ftag(12,3)=[character(len=40):: 'lfo_inst_1hr_glo_L576x361_slv'] + GEOSIT_defs(:,3) = GEOSIT_ftag ! MERRA-2 file specs with uncorrected (AGCM) precip from the "int" Collection ! (ie, the precip generated by the AGCM within the MERRA-2 system) From f31328e514d7a7d16ebfb2e8d93601cae6198ff6 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Tue, 5 Dec 2023 18:36:22 -0500 Subject: [PATCH 200/308] fix error in previous commit for GEOS-IT (LDAS_Forcing.F90) --- .../GEOSmetforce_GridComp/LDAS_Forcing.F90 | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 b/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 index 9955c38b..8dfdcfa8 100755 --- a/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 @@ -3255,18 +3255,18 @@ subroutine get_GEOS( date_time, force_dtstep, met_path, met_tag, & GEOSIT_defs = G5DAS_defs - GEOSIT_ftag( 1,3)=[character(len=40):: 'lfo_tavg_1hr_glo_L576x361_slv'] - GEOSIT_ftag( 2,3)=[character(len=40):: 'lfo_tavg_1hr_glo_L576x361_slv'] - GEOSIT_ftag( 3,3)=[character(len=40):: 'lfo_tavg_1hr_glo_L576x361_slv'] - GEOSIT_ftag( 4,3)=[character(len=40):: 'lfo_tavg_1hr_glo_L576x361_slv'] - GEOSIT_ftag( 5,3)=[character(len=40):: 'lfo_tavg_1hr_glo_L576x361_slv'] - GEOSIT_ftag( 6,3)=[character(len=40):: 'lfo_tavg_1hr_glo_L576x361_slv'] - GEOSIT_ftag( 7,3)=[character(len=40):: 'lfo_tavg_1hr_glo_L576x361_slv'] - GEOSIT_ftag( 8,3)=[character(len=40):: 'lfo_inst_1hr_glo_L576x361_slv'] - GEOSIT_ftag( 9,3)=[character(len=40):: 'lfo_inst_1hr_glo_L576x361_slv'] - GEOSIT_ftag(10,3)=[character(len=40):: 'lfo_inst_1hr_glo_L576x361_slv'] - GEOSIT_ftag(11,3)=[character(len=40):: 'lfo_inst_1hr_glo_L576x361_slv'] - GEOSIT_ftag(12,3)=[character(len=40):: 'lfo_inst_1hr_glo_L576x361_slv'] + GEOSIT_ftag( 1)=[character(len=40):: 'lfo_tavg_1hr_glo_L576x361_slv'] + GEOSIT_ftag( 2)=[character(len=40):: 'lfo_tavg_1hr_glo_L576x361_slv'] + GEOSIT_ftag( 3)=[character(len=40):: 'lfo_tavg_1hr_glo_L576x361_slv'] + GEOSIT_ftag( 4)=[character(len=40):: 'lfo_tavg_1hr_glo_L576x361_slv'] + GEOSIT_ftag( 5)=[character(len=40):: 'lfo_tavg_1hr_glo_L576x361_slv'] + GEOSIT_ftag( 6)=[character(len=40):: 'lfo_tavg_1hr_glo_L576x361_slv'] + GEOSIT_ftag( 7)=[character(len=40):: 'lfo_tavg_1hr_glo_L576x361_slv'] + GEOSIT_ftag( 8)=[character(len=40):: 'lfo_inst_1hr_glo_L576x361_slv'] + GEOSIT_ftag( 9)=[character(len=40):: 'lfo_inst_1hr_glo_L576x361_slv'] + GEOSIT_ftag(10)=[character(len=40):: 'lfo_inst_1hr_glo_L576x361_slv'] + GEOSIT_ftag(11)=[character(len=40):: 'lfo_inst_1hr_glo_L576x361_slv'] + GEOSIT_ftag(12)=[character(len=40):: 'lfo_inst_1hr_glo_L576x361_slv'] GEOSIT_defs(:,3) = GEOSIT_ftag From 1d854d41d6d74fe8238a75ab0a45abdebecf308a Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Wed, 6 Dec 2023 09:03:16 -0500 Subject: [PATCH 201/308] reverting back to earlier approach for assembling GEOSIT_defs (LDAS_Forcing.F90) --- .../GEOSmetforce_GridComp/LDAS_Forcing.F90 | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 b/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 index 8dfdcfa8..86f976e0 100755 --- a/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 @@ -3176,8 +3176,6 @@ subroutine get_GEOS( date_time, force_dtstep, met_path, met_tag, & character(40), dimension(N_MERRA2plusAerosol_vars, N_defs_cols) :: M2INT_defs character(40), dimension(N_MERRA2plusAerosol_vars, N_defs_cols) :: M2COR_defs - character(40), dimension(N_G5DAS_vars) :: GEOSIT_ftag - character(40), dimension(:,:), allocatable :: GEOSgcm_defs ! NOTE: met_path, prec_path, and met_tag for current ('inst') time and fwd and bkwd 'tavg' @@ -3251,24 +3249,26 @@ subroutine get_GEOS( date_time, force_dtstep, met_path, met_tag, & ! ! define GEOS-IT file specs ! - ! same as G5DAS except for file tags (column 3) - - GEOSIT_defs = G5DAS_defs + ! same as G5DAS except for file tag (column 3) + ! + ! GEOSIT character(40): + ! + ! 1 2 3 4 + ! 1234567890123456789012345678901234567890 - GEOSIT_ftag( 1)=[character(len=40):: 'lfo_tavg_1hr_glo_L576x361_slv'] - GEOSIT_ftag( 2)=[character(len=40):: 'lfo_tavg_1hr_glo_L576x361_slv'] - GEOSIT_ftag( 3)=[character(len=40):: 'lfo_tavg_1hr_glo_L576x361_slv'] - GEOSIT_ftag( 4)=[character(len=40):: 'lfo_tavg_1hr_glo_L576x361_slv'] - GEOSIT_ftag( 5)=[character(len=40):: 'lfo_tavg_1hr_glo_L576x361_slv'] - GEOSIT_ftag( 6)=[character(len=40):: 'lfo_tavg_1hr_glo_L576x361_slv'] - GEOSIT_ftag( 7)=[character(len=40):: 'lfo_tavg_1hr_glo_L576x361_slv'] - GEOSIT_ftag( 8)=[character(len=40):: 'lfo_inst_1hr_glo_L576x361_slv'] - GEOSIT_ftag( 9)=[character(len=40):: 'lfo_inst_1hr_glo_L576x361_slv'] - GEOSIT_ftag(10)=[character(len=40):: 'lfo_inst_1hr_glo_L576x361_slv'] - GEOSIT_ftag(11)=[character(len=40):: 'lfo_inst_1hr_glo_L576x361_slv'] - GEOSIT_ftag(12)=[character(len=40):: 'lfo_inst_1hr_glo_L576x361_slv'] + GEOSIT_defs( 1,3) = 'lfo_tavg_1hr_glo_L576x361_slv ' + GEOSIT_defs( 2,3) = 'lfo_tavg_1hr_glo_L576x361_slv ' + GEOSIT_defs( 3,3) = 'lfo_tavg_1hr_glo_L576x361_slv ' + GEOSIT_defs( 4,3) = 'lfo_tavg_1hr_glo_L576x361_slv ' + GEOSIT_defs( 5,3) = 'lfo_tavg_1hr_glo_L576x361_slv ' + GEOSIT_defs( 6,3) = 'lfo_tavg_1hr_glo_L576x361_slv ' + GEOSIT_defs( 7,3) = 'lfo_tavg_1hr_glo_L576x361_slv ' + GEOSIT_defs( 8,3) = 'lfo_inst_1hr_glo_L576x361_slv ' + GEOSIT_defs( 9,3) = 'lfo_inst_1hr_glo_L576x361_slv ' + GEOSIT_defs(10,3) = 'lfo_inst_1hr_glo_L576x361_slv ' + GEOSIT_defs(11,3) = 'lfo_inst_1hr_glo_L576x361_slv ' + GEOSIT_defs(12,3) = 'lfo_inst_1hr_glo_L576x361_slv ' - GEOSIT_defs(:,3) = GEOSIT_ftag ! MERRA-2 file specs with uncorrected (AGCM) precip from the "int" Collection ! (ie, the precip generated by the AGCM within the MERRA-2 system) From 597b804531b3c3457de13d73165097e7bcce9b6d Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Wed, 6 Dec 2023 09:12:50 -0500 Subject: [PATCH 202/308] fix GEOSIT_defs (LDAS_Forcing.F90) --- .../GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 b/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 index 86f976e0..055d0e9e 100755 --- a/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 @@ -3250,7 +3250,9 @@ subroutine get_GEOS( date_time, force_dtstep, met_path, met_tag, & ! define GEOS-IT file specs ! ! same as G5DAS except for file tag (column 3) - ! + + GEOSIT_defs = G5DAS_defs + ! GEOSIT character(40): ! ! 1 2 3 4 From cc3fbcd93b4b55192f1f79814555f8b4b950789e Mon Sep 17 00:00:00 2001 From: Qing Liu Date: Wed, 6 Dec 2023 10:09:55 -0500 Subject: [PATCH 203/308] fix typo --- .../GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 b/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 index 055d0e9e..772183dc 100755 --- a/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 @@ -5023,7 +5023,7 @@ subroutine parse_G5DAS_met_tag( met_path_in, met_tag_in, date_time, & end if - elseif (met_tag_out(1:18)=='cross_d5924_GEOSIT') then + elseif (met_tag_out(1:18)=='cross_d5294_GEOSIT') then if (datetime_lt_refdatetime( date_time, dt_end_d5294_geosit1 )) then From c38975fcac0bdeb8f59406729ecea2da69acc2b7 Mon Sep 17 00:00:00 2001 From: Rolf Reichle <54944691+gmao-rreichle@users.noreply.github.com> Date: Wed, 6 Dec 2023 10:23:35 -0500 Subject: [PATCH 204/308] fix SLURM directive (ldas_setup) --- src/Applications/LDAS_App/ldas_setup | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Applications/LDAS_App/ldas_setup b/src/Applications/LDAS_App/ldas_setup index 8af526ab..b112c8e0 100755 --- a/src/Applications/LDAS_App/ldas_setup +++ b/src/Applications/LDAS_App/ldas_setup @@ -848,7 +848,7 @@ class LDASsetup: config['slurm']['account'] = self.rqdRmInp['account'] config['slurm']['qos'] = 'debug' - config['slurm']['partition'] = 'cas|sky' + config['slurm']['constraint'] = 'cas|sky' config['input']['surface']['catch_tilefile'] = self.in_tilefile config['input']['shared']['expid'] = self.rqdExeInp['RESTART_ID'] From 718a55af227d42d7f361566542bab8659d242507 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Wed, 6 Dec 2023 11:52:19 -0700 Subject: [PATCH 205/308] add select_species_Tb --- .../clsm_ensupd_upd_routines.F90 | 260 ++++-------------- 1 file changed, 46 insertions(+), 214 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index 8188bdab..0640f998 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -3422,9 +3422,9 @@ subroutine cat_enkf_increments( & real, parameter :: tp1_threshold = -HUGE(1.) ! = 0.2 ! [CELSIUS] - integer :: n, n_e, kk, ii + integer :: n, n_e, kk, ii, jj - integer :: N_state_max, N_state, N_selected_obs, N_select_varnames, N_select_species, N_varnames + integer :: N_state_max, N_state, N_selected_obs, N_select_varnames, N_select_species, N_varnames, N_select_species_Tb real :: halo_minlon, halo_maxlon, halo_minlat, halo_maxlat real :: tmp_minlon, tmp_maxlon, tmp_minlat, tmp_maxlat @@ -3441,7 +3441,7 @@ subroutine cat_enkf_increments( & real, allocatable, dimension(:) :: State_lon, State_lat - integer, dimension(N_obs_param) :: select_species ! alloc max possible length + integer, dimension(N_obs_param) :: select_species, select_species_Tb ! alloc max possible length character(40), dimension(N_obs_param) :: select_varnames ! alloc max possible length @@ -3451,6 +3451,7 @@ subroutine cat_enkf_increments( & integer, dimension(:,:,:), pointer :: tile_num_in_cell_ij => null() character(len=*), parameter :: Iam = 'cat_enkf_increments' + character(len=400) :: err_msg real, dimension( N_catd) :: r_x, tmp_dlon real :: r_y, tmp_dlat @@ -3472,7 +3473,7 @@ subroutine cat_enkf_increments( & type(obs_param_type) :: this_obs_param - logical :: nonZeroFound + logical :: nonZeroFound, found, smap_obs, ascat_obs ! ----------------------------------------------------------------------- @@ -4433,6 +4434,10 @@ subroutine cat_enkf_increments( & N_select_varnames, select_varnames(1:N_select_varnames), & N_obs_param, obs_param, N_select_species, select_species ) + ! Determine which species are Tb + call get_select_species(1, 'Tb', N_obs_param, obs_param, N_select_species_Tb, select_species_Tb ) + + N_state_max = 7 allocate( State_incr(N_state_max,N_ens)) @@ -4471,37 +4476,30 @@ subroutine cat_enkf_increments( & if (N_selected_obs>0) then - ! call get_select_species(1, 'sfds', N_obs_param, obs_param, N_select_species, select_species ) - - ! do ii = 1,N_select_species - ! if ( any(select_species(ii) == Observations(ind_obs(1:N_selected_obs))%species)) then - ! N_state = max(3, N_state) ! Keep 6 or 7 if we have Tb _and_ sfds obs) - ! if ( N_state > 3) then - ! write (logunit,*) "Two obs types in Catchment = ", kk - ! end if - ! end if - ! end do - - ! ! Determine which observation species are actually selected - ! call get_select_species(1, 'Tb', N_obs_param, obs_param, N_select_species, select_species ) - - ! do ii = 1,N_select_species - ! if ( any(select_species(ii) == Observations(ind_obs(1:N_selected_obs))%species)) then - ! if (cat_param(kk)%poros>=PEATCLSM_POROS_THRESHOLD) then - ! N_state = 7 - ! else - ! N_state = 6 - ! end if - ! end if - ! end do - - N_state = 6 - - if ( N_state == 0 ) then - err_msg = 'Dont know what state to use with this observation type' - call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) - end if - + ! Determine if Tb observations are present + + do ii = 1,N_select_species_Tb + do jj = 1,N_selected_obs + if (select_species_Tb(ii) == Observations(ind_obs(jj))%species) then + found = .true. + exit + end if + end do + if (found) then + exit + end if + end do + + if (found) then + if (cat_param(kk)%poros>=PEATCLSM_POROS_THRESHOLD) then + N_state = 7 + else + N_state = 6 + end if + else + N_state = 3 + end if + ! assemble State_minus ! (on input, cat_progn contains cat_progn_minus) @@ -4543,8 +4541,15 @@ subroutine cat_enkf_increments( & Observations(ind_obs(1:N_selected_obs)), Obs_cov ) ! EnKF update - write (logunit,*) "N_state = ", N_state + ! smap_obs = any(Observations(ind_obs(1:N_selected_obs))%species < 5) + ! ascat_obs = any(Observations(ind_obs(1:N_selected_obs))%species > 4) + + ! if (smap_obs .and. ascat_obs) then + ! write (logunit,*) "Found tile with both obs types. Tile = ", halo_minlon, halo_maxlon, halo_minlat, halo_maxlat + ! write (logunit,*) "Observations(ind_obs(1:N_selected_obs))%species = ", Observations(ind_obs(1:N_selected_obs))%species + ! end if + call enkf_increments( & N_state, N_selected_obs, N_ens, & Observations(ind_obs(1:N_selected_obs)), & @@ -4564,23 +4569,26 @@ subroutine cat_enkf_increments( & cat_progn_incr(kk,:)%srfexc = State_incr(1,:)*scale_srfexc cat_progn_incr(kk,:)%rzexc = State_incr(2,:)*scale_rzexc - cat_progn_incr(kk,:)%catdef = State_incr(3,:)*scale_catdef + cat_progn_incr(kk,:)%catdef = State_incr(3,:)*scale_catdef + write(logunit,*) 'N3 After cat_progn_incr(kk,:)%srfexc = ', cat_progn_incr(kk,5)%srfexc elseif ( N_state==7 ) then cat_progn_incr(kk,:)%srfexc = State_incr(1,:)*scale_srfexc cat_progn_incr(kk,:)%rzexc = State_incr(2,:)*scale_rzexc cat_progn_incr(kk,:)%catdef = State_incr(3,:)*scale_catdef ! catdef in State + write(logunit,*) 'N7 After cat_progn_incr(kk,:)%srfexc = ', cat_progn_incr(kk,5)%srfexc cat_progn_incr(kk,:)%tc1 = State_incr(4,:)*scale_temp cat_progn_incr(kk,:)%tc2 = State_incr(5,:)*scale_temp cat_progn_incr(kk,:)%tc4 = State_incr(6,:)*scale_temp cat_progn_incr(kk,:)%ght(1) = State_incr(7,:)*scale_ght1 - + else cat_progn_incr(kk,:)%srfexc = State_incr(1,:)*scale_srfexc cat_progn_incr(kk,:)%rzexc = State_incr(2,:)*scale_rzexc + write(logunit,*) 'N6 After cat_progn_incr(kk,:)%srfexc = ', cat_progn_incr(kk,5)%srfexc cat_progn_incr(kk,:)%tc1 = State_incr(3,:)*scale_temp cat_progn_incr(kk,:)%tc2 = State_incr(4,:)*scale_temp @@ -4597,182 +4605,6 @@ subroutine cat_enkf_increments( & ! ---------------------------------- - case (33) select_update_type ! All observation types from obs_param - - ! update each tile separately using all observations within customized halo around each tile - ! - ! amfox, 27 July 2023 - - if (logit) write (logunit,*) 'Get increments for all observation types in obs_param' - - N_select_varnames = 1 - N_state_max = 7 ! Needs to be constant size for applying increment, potential for lots of zeros - - allocate( State_incr(N_state_max,N_ens)) - allocate( State_incr_cum(N_state_max,N_ens)) - allocate( State_lon( N_state_max )) - allocate( State_lat( N_state_max )) - - if (any(obs_param%varname == 'Tb')) then - N_varnames = N_varnames + 1 - select_varnames(N_varnames) = 'Tb' - end if - - if (any(obs_param%varname == 'sfds')) then - N_varnames = N_varnames + 1 - select_varnames(N_varnames) = 'sfds' - end if - - do kk=1,N_catd - - State_incr_cum = 0.0 - - do ii = 1,N_varnames - - call get_select_species( & - N_select_varnames, select_varnames(ii), & - N_obs_param, obs_param, N_select_species, select_species ) - - ! compute increments only snow-free and non-frozen tiles - - if ( (SWE_ensavg(kk) < SWE_threshold) .and. & - (tp1_ensavg(kk) > tp1_threshold) ) then - - ! find observations within halo around tile kk - - halo_minlon = tile_coord(kk)%com_lon - xcompact - halo_maxlon = tile_coord(kk)%com_lon + xcompact - halo_minlat = tile_coord(kk)%com_lat - ycompact - halo_maxlat = tile_coord(kk)%com_lat + ycompact - - ! simple approach to dateline issue (cut halo back to at most -180:180, -90:90) - ! - reichle, 28 May 2013 - - halo_minlon = max(halo_minlon,-180.) - halo_maxlon = min(halo_maxlon, 180.) - halo_minlat = max(halo_minlat, -90.) - halo_maxlat = min(halo_maxlat, 90.) - - call get_ind_obs_lat_lon_box( & - N_obs, Observations, & - halo_minlon, halo_maxlon, halo_minlat, halo_maxlat, & - N_select_species, select_species(1:N_select_species), & - N_selected_obs, ind_obs ) - - if (N_selected_obs>0) then - - if (select_varnames(ii)=='Tb' .and. cat_param(kk)%poros>=PEATCLSM_POROS_THRESHOLD) then - N_state = 7 - elseif (select_varnames(ii)=='Tb' .and. cat_param(kk)%poros0. .and. & sclprm_mean_mod(j_ind, i_ind)>0. .and. & sclprm_std_obs(j_ind, i_ind)>=0. .and. & - sclprm_std_mod(j_ind, i_ind)>=0. ) then + sclprm_std_mod(j_ind, i_ind)>=0. ) then ! Scale via standard normal deviates From 185436bf8d100604126649a5ed2a2efbc156f177 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Mon, 18 Dec 2023 15:29:12 -0500 Subject: [PATCH 209/308] added minor comment to (ASCAT) sfmc zscore scaling subroutine (clsm_ensupd_read_obs.F90) --- .../GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 7fcaf01f..77d9d63a 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -8163,7 +8163,7 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & date_time, this_obs_param, tmp_lon, tmp_lat, tmp_time, & tmp_obs, tmp_std_obs ) - ! scale sfmc obs to model climatology via standard-normal-deviate (zscore) + ! scale sfmc or sfds obs to model climatology via standard-normal-deviate (zscore) ! scaling using seasonally varying (pentad) stats ! Grid information is read from a NetCDF file ! @@ -8228,7 +8228,7 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & ! local variables - real, parameter :: tol = 0.99 + real, parameter :: tol = 0.99 ! [degree lat/lon] for sanity check (should never kick in) ! ------------------- From c643b6be25bd201b0200657a9db225ca82262845 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Tue, 19 Dec 2023 13:07:38 -0500 Subject: [PATCH 210/308] moved lines with user-defined inputs into corresponding block of code --- ...get_model_and_obs_clim_stats_latlon_grid.m | 58 ++++++++++--------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/Run_get_model_and_obs_clim_stats_latlon_grid.m b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/Run_get_model_and_obs_clim_stats_latlon_grid.m index 826b4737..0d332e39 100644 --- a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/Run_get_model_and_obs_clim_stats_latlon_grid.m +++ b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/Run_get_model_and_obs_clim_stats_latlon_grid.m @@ -1,12 +1,12 @@ clear -% addpath('../../shared/matlab/'); -addpath('/discover/nobackup/amfox/current_GEOSldas/GEOSldas/src/Applications/LDAS_App/util/shared/matlab') - % ------------------------------------------------------------------- % Begin user-defined inputs % ------------------------------------------------------------------- +% addpath('../../shared/matlab/'); +addpath('/discover/nobackup/amfox/current_GEOSldas/GEOSldas/src/Applications/LDAS_App/util/shared/matlab') + % Define the Open Loop experiment path, run name, domain, and output prefix exp_path = '/discover/nobackup/amfox/Experiments/OLv7_M36_ascat'; @@ -16,9 +16,9 @@ % Define the Open Loop experiment start and end dates -start_month = 4; +start_month = 4; start_year = 2015; -end_month = 3; +end_month = 3; end_year = 2021; % Define the species names @@ -37,7 +37,7 @@ % and minimum number of data points required to calculate statistics w_days = 75; -Ndata_min = 5; +Ndata_min = 5; % Define the assimilation time step and initial time @@ -53,13 +53,16 @@ % Define output directory (takes form "domain"/stats/"out_dir") out_dir = 'z_score_clim_quarter_degree'; +% Define the months to run over, 1:12, plus a number of months required to complete the window +run_months = [1:12 1:ceil(w_days/30)]; + +obs_param_fname = [exp_path, '/', exp_run{1}, '/output/', domain, '/rc_out/', ... + '/Y2016/M04/',exp_run{1}, '.ldas_obsparam.20160401_0000z.txt']; + % ------------------------------------------------------------------- % End user-defined inputs % ------------------------------------------------------------------- -% Define the months to run over, 1:12, plus a number of months required to complete the window -run_months = [1:12 1:ceil(w_days/30)]; - % Calculate the earliest and latest years for each month in the experiment earliest_year = zeros(length(run_months),1); latest_year = zeros(length(run_months),1); @@ -69,24 +72,21 @@ % Initialize the earliest and latest year variables cnt = cnt + 1; - % Check if the current year/month combination is earlier than the earliest - if datenum(start_year, month, 1) < datenum(start_year, start_month, 1) - earliest_year(cnt) = start_year+1; - else - earliest_year(cnt) = start_year; - end - - % Check if the current year/month combination is later than the latest - if datenum(end_year, month, 1) > datenum(end_year, end_month,1) - latest_year(cnt) = end_year-1; - else - latest_year(cnt) = end_year; - end + % Check if the current year/month combination is earlier than the earliest + if datenum(start_year, month, 1) < datenum(start_year, start_month, 1) + earliest_year(cnt) = start_year+1; + else + earliest_year(cnt) = start_year; + end + + % Check if the current year/month combination is later than the latest + if datenum(end_year, month, 1) > datenum(end_year, end_month,1) + latest_year(cnt) = end_year-1; + else + latest_year(cnt) = end_year; + end end -obs_param_fname = [exp_path, '/', exp_run{1}, '/output/', domain, '/rc_out/', ... - '/Y2016/M04/',exp_run{1}, '.ldas_obsparam.20160401_0000z.txt']; - [N_obs_param, obs_param ] = read_obsparam(obs_param_fname); species =[]; @@ -103,6 +103,8 @@ % Calculate the climatology statistics get_model_and_obs_clim_stats_latlon_grid( species_names, run_months, exp_path, exp_run{1}, domain, earliest_year, ... - latest_year, dt_assim, t0_assim, species, combine_species_stats, ... - grid_resolution, w_days, Ndata_min, prefix_out, print_each_DOY, ... - print_each_pentad, print_all_pentads, out_dir ); + latest_year, dt_assim, t0_assim, species, combine_species_stats, ... + grid_resolution, w_days, Ndata_min, prefix_out, print_each_DOY, ... + print_each_pentad, print_all_pentads, out_dir ); + +% ================= EOF ========================================================================= From 810f8716cf79d1e6b0022372712bbb20e4d0065a Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Tue, 19 Dec 2023 13:10:53 -0500 Subject: [PATCH 211/308] cleanup of functions to get obs scaling parameters (get_model_and_obs_clim_stats*.m): - fixed indentation - improved vertical alignment of equations - minor edits of comments - removed obsolete code --- .../get_model_and_obs_clim_stats.m | 952 ++++++++---------- ...get_model_and_obs_clim_stats_latlon_grid.m | 477 ++++----- 2 files changed, 689 insertions(+), 740 deletions(-) diff --git a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats.m b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats.m index 492839a2..3a5cd478 100644 --- a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats.m +++ b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats.m @@ -1,8 +1,8 @@ -function [] = get_model_and_obs_clim_stats( varname, ... +function [] = get_model_and_obs_clim_stats( varname, ... run_months, exp_path, exp_run, domain, start_year, end_year, ... - dt_assim, t0_assim, species, obs_param, ... - hscale, inc_angle, int_Asc, w_days, Ndata_min, prefix, ... + dt_assim, t0_assim, species, obs_param, ... + hscale, inc_angle, int_Asc, w_days, Ndata_min, prefix, ... convert_grid , time_of_day_in_hours ) % @@ -107,19 +107,20 @@ disp('ASSUMING EASEv2 M36 observations'); if ~isempty(strfind(domain,'M36')) && isempty(strfind(obs_param(species(1)).descr, '_E')) - tol = 1E-3; + tol = 1E-3; else - tol = 2; + tol = 2; end % output specs -overwrite = 1; +overwrite = 1; + +Nf = 5; %5 fields per polarization -Nf = 5; %5 fields per polarization N_out_fields = 2*Nf+4; %14; -write_ind_latlon = 'latlon_id'; %'latlon'; +write_ind_latlon = 'latlon_id'; %'latlon'; N_angle = length(inc_angle); N_pol = 2; @@ -159,46 +160,46 @@ D(1) = 1; P(1) = 1; if mi_m > 1 - D(1) = sum(days_in_month( 2014, [1:mi_m-1]))+1; - P(1) = ceil(D(1)/5); + D(1) = sum(days_in_month( 2014, [1:mi_m-1]))+1; + P(1) = ceil(D(1)/5); end if ma_m > 1 - D(2) = sum(days_in_month( 2014, [1:ma_m])); + D(2) = sum(days_in_month( 2014, [1:ma_m])); else - D(2) = 1; + D(2) = 1; end P(2) = floor(D(2)/5); if run_months(1) ~= run_months(end) && run_months(2) ~= run_months(end) - disp('WARNING: incomplete pentad-windows; loop through additional months to get complete pentads'); + disp('WARNING: incomplete pentad-windows; loop through additional months to get complete pentads'); end -fname_out_base = [ outpath, '/', prefix, ... - num2str(min(start_year)),'_doy',num2str(D(1)),'_',... - num2str(max(end_year)), '_doy',num2str(D(2)),... - '_hscale_', num2str(hscale,'%2.2f'), '_', ... - 'W_', num2str(w_days),'d_Nmin_', num2str(Ndata_min)]; +fname_out_base = [ outpath, '/', prefix, ... + num2str(min(start_year)),'_doy',num2str(D(1)),'_', ... + num2str(max(end_year)), '_doy',num2str(D(2)), ... + '_hscale_', num2str(hscale,'%2.2f'), '_', ... + 'W_', num2str(w_days),'d_Nmin_', num2str(Ndata_min)]; -fname_out_base_p = [ outpath, '/', prefix, ... - num2str(min(start_year)),'_p',num2str(P(1)),'_',... - num2str(max(end_year)), '_p',num2str(P(2)),... - '_hscale_', num2str(hscale,'%2.2f'), '_', ... - 'W_', num2str(round(w_days/5)),'p_Nmin_', num2str(Ndata_min)]; +fname_out_base_p = [ outpath, '/', prefix, ... + num2str(min(start_year)),'_p',num2str(P(1)),'_', ... + num2str(max(end_year)), '_p',num2str(P(2)), ... + '_hscale_', num2str(hscale,'%2.2f'), '_', ... + 'W_', num2str(round(w_days/5)),'p_Nmin_', num2str(Ndata_min)]; %fname_out_base = [fname_out_base, spec_tag]; if (int_Asc == 1) - Orbit_tag = '_A'; %'_Asc'; + Orbit_tag = '_A'; %'_Asc'; else - Orbit_tag = '_D'; %'_Desc'; + Orbit_tag = '_D'; %'_Desc'; end -fname_out_base = [fname_out_base, Orbit_tag]; +fname_out_base = [fname_out_base, Orbit_tag]; fname_out_base_p = [fname_out_base_p, Orbit_tag]; - + if exist( 'time_of_day_in_hours', 'var') - fname_out_base = [fname_out_base, '_', num2str(time_of_day_in_hours,'%2.2d'), 'z']; + fname_out_base = [fname_out_base, '_', num2str(time_of_day_in_hours,'%2.2d'), 'z']; fname_out_base_p = [fname_out_base_p, '_', num2str(time_of_day_in_hours,'%2.2d'), 'z']; end @@ -210,7 +211,7 @@ fname = [inpath, '/rc_out/', exp_run, '.ldas_tilecoord.bin']; fnameg= [inpath, '/rc_out/', exp_run, '.ldas_tilegrids.bin']; -[ tile_coord ] = read_tilecoord( fname ); +[ tile_coord ] = read_tilecoord( fname ); [ tile_grid ] = read_tilegrids( fnameg ); N_tile = length(tile_coord.tile_id); @@ -226,101 +227,101 @@ tile_coord_tile_id = tile_coord.tile_id; if (exist('convert_grid')) - - %1) convert to M36 EASE indices - %2) convert back to lat/lon at center of obs - if (~isempty(strfind(convert_grid, 'M36')) && ~isempty(strfind(convert_grid, 'EASEv2'))) - gridid = 'M36'; - [central_row,central_col] = EASEv2_latlon2ind(central_lat,central_lon,gridid,1); - [central_lat,central_lon] = EASEv2_ind2latlon(central_row,central_col,gridid); - elseif (~isempty(strfind(convert_grid, 'M36')) && ~isempty(strfind(convert_grid, 'EASEv1'))) - error('Must provide smapeasev1_latlon2ind() and smapeasev1_ind2latlon()!') - gridid = 'M36'; - [central_row,central_col] = smapeasev1_latlon2ind(central_lat,central_lon,gridid); - [central_lat,central_lon] = smapeasev1_ind2latlon(central_row,central_col,gridid); - else - error(['Unable to convert to ',convert_grid]) - end - - row_col_tmp = [central_row central_col]; - [unique_rc, ia, ic] = unique(row_col_tmp,'rows'); - - max_Hx_c = length(find(mode(ic)==ic)); - - %know which exact M09 tiles are actually administering the obs - %------------------- - tmp_lon = central_lon(ia)+tmp_shift_lon; - tmp_lat = central_lat(ia)+tmp_shift_lat; - - [N_tile_in_cell_ij, tile_num_in_cell_ij] = get_tile_num_in_cell_ij(... - tile_coord, tile_grid); + + %1) convert to M36 EASE indices + %2) convert back to lat/lon at center of obs + if (~isempty(strfind(convert_grid, 'M36')) && ~isempty(strfind(convert_grid, 'EASEv2'))) + gridid = 'M36'; + [central_row,central_col] = EASEv2_latlon2ind(central_lat,central_lon,gridid,1); + [central_lat,central_lon] = EASEv2_ind2latlon(central_row,central_col,gridid); + elseif (~isempty(strfind(convert_grid, 'M36')) && ~isempty(strfind(convert_grid, 'EASEv1'))) + error('Must provide smapeasev1_latlon2ind() and smapeasev1_ind2latlon()!') + gridid = 'M36'; + [central_row,central_col] = smapeasev1_latlon2ind(central_lat,central_lon,gridid); + [central_lat,central_lon] = smapeasev1_ind2latlon(central_row,central_col,gridid); + else + error(['Unable to convert to ',convert_grid]) + end + + row_col_tmp = [central_row central_col]; + [unique_rc, ia, ic] = unique(row_col_tmp,'rows'); + + max_Hx_c = length(find(mode(ic)==ic)); + + %know which exact M09 tiles are actually administering the obs + %------------------- + tmp_lon = central_lon(ia)+tmp_shift_lon; + tmp_lat = central_lat(ia)+tmp_shift_lat; + + [N_tile_in_cell_ij, tile_num_in_cell_ij] = get_tile_num_in_cell_ij( ... + tile_coord, tile_grid); + + this_FOV = 20; + option = 'FOV_in_km'; + %overwrite ia with actual administering tile number + [ia] = get_tile_num_for_obs( tile_coord, tile_grid, ... + N_tile_in_cell_ij, tile_num_in_cell_ij, ... + option, this_FOV, tmp_lat, tmp_lon); + + ia = ia(ia>0 & ~isnan(ia)); + + obsnum = NaN+zeros(length(ic),1); + obsnum(ia) = [1:length(ia)]; + + N_tile_obs = length(ia); + + %------------------- + + if store_all_M09inM36 - this_FOV = 20; - option = 'FOV_in_km'; - %overwrite ia with actual administering tile number - [ia] = get_tile_num_for_obs(tile_coord, tile_grid,... - N_tile_in_cell_ij, tile_num_in_cell_ij,... - option, this_FOV, tmp_lat, tmp_lon); - - ia = ia(ia>0 & ~isnan(ia)); - - obsnum = NaN+zeros(length(ic),1); - obsnum(ia) = [1:length(ia)]; - - N_tile_obs = length(ia); - - %------------------- - - if store_all_M09inM36 - - %Not maintained/elaborated - tile_coord_tile_id = zeros(N_tile_obs,max_Hx_c); - - disp(['centralizing obs on ',convert_grid,' grid before doing stats: max ',num2str(max_Hx_c),'tiles per obs cell']) - - for i=1:N_tile_obs - - tmp_ind = find(row_col_tmp(:,1) == unique_rc(i,1) & row_col_tmp(:,2) == unique_rc(i,2)); - tile_coord_tile_id(i,1:length(tmp_ind)) = tile_coord.tile_id(tmp_ind); - - end - - else - - tile_coord_tile_id = tile_coord.tile_id(ia); - - end - + %Not maintained/elaborated + tile_coord_tile_id = zeros(N_tile_obs,max_Hx_c); + + disp(['centralizing obs on ',convert_grid,' grid before doing stats: max ',num2str(max_Hx_c),'tiles per obs cell']) + + for i=1:N_tile_obs + + tmp_ind = find(row_col_tmp(:,1) == unique_rc(i,1) & row_col_tmp(:,2) == unique_rc(i,2)); + + tile_coord_tile_id(i,1:length(tmp_ind)) = tile_coord.tile_id(tmp_ind); + + end + + else + + tile_coord_tile_id = tile_coord.tile_id(ia); + + end + else - - N_tile_obs = N_tile; - ia = 1:N_tile; - ic = 1:N_tile; - obsnum = 1:N_tile; - + + N_tile_obs = N_tile; + ia = 1:N_tile; + ic = 1:N_tile; + obsnum = 1:N_tile; + end -lon_out = tile_coord.com_lon(ia); %NaN+zeros(N_tile,1); -lat_out = tile_coord.com_lat(ia); %NaN+zeros(N_tile,1); - +lon_out = tile_coord.com_lon(ia); %NaN+zeros(N_tile,1); +lat_out = tile_coord.com_lat(ia); %NaN+zeros(N_tile,1); if hscale>0 - - for i=1:N_tile_obs - - this_lat = lat_out(i); - this_lon = lon_out(i); - - tmp_sq_distance = ... + + for i=1:N_tile_obs + + this_lat = lat_out(i); + this_lon = lon_out(i); + + tmp_sq_distance = ... (central_lon - this_lon).^2 + ... (central_lat - this_lat).^2; - - hscale_ind{i} = find( tmp_sq_distance <= hscale^2 ); - end - + + hscale_ind{i} = find( tmp_sq_distance <= hscale^2 ); + end + else - - hscale_ind = num2cell(ia); + + hscale_ind = num2cell(ia); end @@ -330,13 +331,13 @@ % N_pol and N_angle be specified here. Then subsample specifically % when the files are written out. -o_data = NaN+zeros(N_pol,N_tile_obs,N_angle,w_days); -m_data = NaN+zeros(N_pol,N_tile_obs,N_angle,w_days); -o_data2 = NaN+zeros(N_pol,N_tile_obs,N_angle,w_days); -m_data2 = NaN+zeros(N_pol,N_tile_obs,N_angle,w_days); -N_data = NaN+zeros(N_pol,N_tile_obs,N_angle,w_days); +o_data = NaN+zeros(N_pol,N_tile_obs,N_angle,w_days); +m_data = NaN+zeros(N_pol,N_tile_obs,N_angle,w_days); +o_data2 = NaN+zeros(N_pol,N_tile_obs,N_angle,w_days); +m_data2 = NaN+zeros(N_pol,N_tile_obs,N_angle,w_days); +N_data = NaN+zeros(N_pol,N_tile_obs,N_angle,w_days); -data_out = NaN+zeros(N_out_fields,N_tile_obs,N_angle); +data_out = NaN+zeros(N_out_fields,N_tile_obs,N_angle); % ------------------------------------------------------------- @@ -347,441 +348,382 @@ count = 0; for imonth = 1:length(run_months) - month = run_months(imonth); - -for day = 1:days_in_month( 2014, month) %2014 = random non-leap year + month = run_months(imonth); + + for day = 1:days_in_month( 2014, month) %2014 = random non-leap year + if count < w_days - count = count + 1; - else - count = w_days; - end - - for seconds_in_day = t0_assim:dt_assim:(86400-1) - - hour = floor(seconds_in_day/3600); - - % check if diurnal stats are needed - - if exist('time_of_day_in_hours','var') - tmp_hour = time_of_day_in_hours; + count = count + 1; else - tmp_hour = hour; % all hours of day will be included + count = w_days; end - - if hour==tmp_hour - - minute = floor( (seconds_in_day-hour*3600)/60 ); - - seconds = seconds_in_day-hour*3600-minute*60; - - if (seconds~=0) - input('something is wrong! Ctrl-c now') + + for seconds_in_day = t0_assim:dt_assim:(86400-1) + + hour = floor(seconds_in_day/3600); + + % check if diurnal stats are needed + + if exist('time_of_day_in_hours','var') + tmp_hour = time_of_day_in_hours; + else + tmp_hour = hour; % all hours of day will be included end - - - for year = start_year(imonth):end_year(imonth) - + + if hour==tmp_hour + + minute = floor( (seconds_in_day-hour*3600)/60 ); + + seconds = seconds_in_day-hour*3600-minute*60; + + if (seconds~=0) + input('something is wrong! Ctrl-c now') + end + + for year = start_year(imonth):end_year(imonth) + YYYYMMDD = [ num2str(year, '%4.4d'), ... - num2str(month, '%2.2d'), ... - num2str(day, '%2.2d') ]; - + num2str(month, '%2.2d'), ... + num2str(day, '%2.2d') ]; + HHMM = [ num2str(hour, '%2.2d'), ... - num2str(minute, '%2.2d') ]; - + num2str(minute, '%2.2d') ]; + % read innov files - - fname = [ inpath, '/ana/ens_avg/', ... - 'Y', YYYYMMDD(1:4), '/', ... - 'M', YYYYMMDD(5:6), '/', ... - exp_run, '.ens_avg.ldas_ObsFcstAna.', ... - YYYYMMDD, '_', HHMM, 'z.bin' ]; - - ifp = fopen( fname, 'r', 'l' ); - - if (ifp > 0) %Proceed only if file exists (e.g. irregular SMOS swaths!) - - fclose(ifp); - - [date_time, ... - obs_assim, ... - obs_species, ... - obs_tilenum, ... - obs_lon, ... - obs_lat, ... - obs_obs, ... - obs_obsvar, ... - obs_fcst, ... - obs_fcstvar, ... - obs_ana, ... - obs_anavar ... - ] = ... - read_ObsFcstAna( fname ); - - % remove tiles when there is no obs_fcst (obs_fcst == 0 in innov output when - % missing) - idx = find(obs_fcst == 0); - obs_assim(idx) = []; - obs_species(idx) = []; - obs_tilenum(idx) =[]; - obs_lon(idx) =[]; - obs_lat(idx) = []; - obs_obs(idx) = []; - obs_obsvar(idx) = []; - obs_fcst(idx) = []; - obs_fcstvar(idx) = []; - obs_ana(idx) = []; - obs_anavar(idx) = []; - - % extract species of interest + fname = [ inpath, '/ana/ens_avg/', ... + 'Y', YYYYMMDD(1:4), '/', ... + 'M', YYYYMMDD(5:6), '/', ... + exp_run, '.ens_avg.ldas_ObsFcstAna.', ... + YYYYMMDD, '_', HHMM, 'z.bin' ]; - ind = []; - - for this_species = species - - ind = find( obs_species == this_species); - - if (~isempty(ind)) - + ifp = fopen( fname, 'r', 'l' ); + + if (ifp > 0) % Proceed only if file exists (e.g. irregular SMOS swaths!) + + fclose(ifp); + + [ date_time, ... + obs_assim, ... + obs_species, ... + obs_tilenum, ... + obs_lon, ... + obs_lat, ... + obs_obs, ... + obs_obsvar, ... + obs_fcst, ... + obs_fcstvar, ... + obs_ana, ... + obs_anavar ... + ] = ... + read_ObsFcstAna( fname ); + + % remove tiles when there is no obs_fcst (obs_fcst == 0 in innov output when + % missing) + + idx = find(obs_fcst == 0); + + obs_assim( idx) = []; + obs_species(idx) = []; + obs_tilenum(idx) = []; + obs_lon( idx) = []; + obs_lat( idx) = []; + obs_obs( idx) = []; + obs_obsvar( idx) = []; + obs_fcst( idx) = []; + obs_fcstvar(idx) = []; + obs_ana( idx) = []; + obs_anavar( idx) = []; + + % extract species of interest + + ind = []; + + for this_species = species + + ind = find( obs_species == this_species); + + if (~isempty(ind)) + obs_tilenum_i = obs_tilenum(ind); obs_obs_i = obs_obs(ind); obs_fcst_i = obs_fcst(ind); obs_lon_i = obs_lon(ind); obs_lat_i = obs_lat(ind); - + % Check if any location receives more than 1 obs (or 1 species) - + tmp = sort(obs_tilenum_i); same_tile = find(diff(tmp)==0); - + if (~isempty(same_tile)) - error('multiple obs of the same species at one location? - only last one in line is used'); + error('multiple obs of the same species at one location? - only last one in line is used'); end - + % Organize the data in a big matrix - + angle = obs_param(this_species == [obs_param.species]).ang; pol = obs_param(this_species == [obs_param.species]).pol; - - %pol intrinsically gives an index - %now find the index for the angle + + % pol intrinsically gives an index + % now find the index for the angle angle_i = find(angle(1) == inc_angle); - + % Only writes lat-lon at exact obs locations, but with % hscale>0, these obs are spread outside their exact % location. This allows to calculate stats at lan-lons % where no obs are available. - + %lon_out(obs_tilenum_i) = obs_lon_i; %lat_out(obs_tilenum_i) = obs_lat_i; - - %obs_lat/lon are the actual M36 lat/lons, *not* the - %administering tiles, so the lat/lons for the obs and those - %in the tile_coord would not be identical. - %Still, they should be in the - %neighbourhood, so check here if that is true. + + % obs_lat/lon are the actual M36 lat/lons, *not* the + % administering tiles, so the lat/lons for the obs and those + % in the tile_coord would not be identical. + % Still, they should be in the + % neighbourhood, so check here if that is true. if (any(abs(tile_coord.com_lat(obs_tilenum_i)-obs_lat_i) > tol) || ... any(abs(tile_coord.com_lon(obs_tilenum_i)-obs_lon_i) > tol) ) - error('Something wrong with tile_lat/lon') + error('Something wrong with tile_lat/lon') end - - %map model tiles (e.g. all M09) to observation administering - %tiles (could be a reduced subset of all M09) - %-------------------------------------------------------- + + % map model tiles (e.g. all M09) to observation administering + % tiles (could be a reduced subset of all M09) + % -------------------------------------------------------- obs_i = obsnum(obs_tilenum_i); - %-------------------------------------------------------- + % -------------------------------------------------------- if (hscale == 0) - - %11 May 2015: sum the obs and fcst within each day; - %and across years! - %some obs can be found at multiple hours within a day - %e.g. at the poles. - %**nansum of NaN's** result in zero, this need to be - %taken care of - o_data(pol(1),obs_i,angle_i,count) = nansum([o_data(pol(1),obs_i,angle_i,count); obs_obs_i' ]); - m_data(pol(1),obs_i,angle_i,count) = nansum([m_data(pol(1),obs_i,angle_i,count); obs_fcst_i']); - - %X^2 - o_data2(pol(1),obs_i,angle_i,count) = nansum([o_data2(pol(1),obs_i,angle_i,count); obs_obs_i'.^2 ]); - m_data2(pol(1),obs_i,angle_i,count) = nansum([m_data2(pol(1),obs_i,angle_i,count); obs_fcst_i'.^2]); - - %Sum of obs or model elements at each location - N_data(pol(1),obs_i,angle_i,count) = nansum([N_data(pol(1),obs_i,angle_i,count); ~isnan([obs_obs_i])']); - + + % 11 May 2015: sum the obs and fcst within each day; + % and across years! + % some obs can be found at multiple hours within a day + % e.g. at the poles. + % **nansum of NaN's** result in zero, this need to be + % taken care of + o_data( pol(1),obs_i,angle_i,count) = nansum([o_data( pol(1),obs_i,angle_i,count); obs_obs_i' ]); + m_data( pol(1),obs_i,angle_i,count) = nansum([m_data( pol(1),obs_i,angle_i,count); obs_fcst_i']); + + % X^2 + o_data2(pol(1),obs_i,angle_i,count) = nansum([o_data2(pol(1),obs_i,angle_i,count); obs_obs_i'.^2 ]); + m_data2(pol(1),obs_i,angle_i,count) = nansum([m_data2(pol(1),obs_i,angle_i,count); obs_fcst_i'.^2]); + + % Sum of obs or model elements at each location + N_data(pol(1),obs_i,angle_i,count) = nansum( [N_data( pol(1),obs_i,angle_i,count); ~isnan([obs_obs_i])']); + else - - for i_ind = 1:length(obs_obs_i) - - %introduce a spatial effect of each observation on - %neighbouring statistics (through hscale) - s_eff = unique(hscale_ind{obs_i(i_ind)}); - %hscale_ind =[obs space] % - - %Sum of X - o_data(pol(1),s_eff,angle_i,count) = ... - nansum([o_data(pol(1),s_eff,angle_i,count); repmat(obs_obs_i(i_ind),1,length(s_eff))]); - m_data(pol(1),s_eff,angle_i,count) = ... - nansum([m_data(pol(1),s_eff,angle_i,count); repmat(obs_fcst_i(i_ind),1,length(s_eff))]); - - %Sum of X^2 - o_data2(pol(1),s_eff,angle_i,count) = ... - nansum([o_data2(pol(1),s_eff,angle_i,count); repmat(obs_obs_i(i_ind).^2,1,length(s_eff))]); - m_data2(pol(1),s_eff,angle_i,count) = ... - nansum([m_data2(pol(1),s_eff,angle_i,count); repmat(obs_fcst_i(i_ind).^2,1,length(s_eff))]); - - %Sum of obs or model elements at each location - N_data(pol(1),s_eff,angle_i,count) = ... - nansum([N_data(pol(1),s_eff,angle_i,count); repmat(~isnan([obs_obs_i(i_ind)]),1,length(s_eff)) ]); - - end - - end - - end - - end - + + for i_ind = 1:length(obs_obs_i) + + % introduce a spatial effect of each observation on + % neighbouring statistics (through hscale) + s_eff = unique(hscale_ind{obs_i(i_ind)}); + %hscale_ind =[obs space] % + + % Sum of X + o_data(pol(1),s_eff,angle_i,count) = ... + nansum([o_data( pol(1),s_eff,angle_i,count); repmat(obs_obs_i( i_ind), 1,length(s_eff))]); + m_data(pol(1),s_eff,angle_i,count) = ... + nansum([m_data( pol(1),s_eff,angle_i,count); repmat(obs_fcst_i(i_ind), 1,length(s_eff))]); + + % Sum of X^2 + o_data2(pol(1),s_eff,angle_i,count) = ... + nansum([o_data2(pol(1),s_eff,angle_i,count); repmat(obs_obs_i( i_ind).^2,1,length(s_eff))]); + m_data2(pol(1),s_eff,angle_i,count) = ... + nansum([m_data2(pol(1),s_eff,angle_i,count); repmat(obs_fcst_i(i_ind).^2,1,length(s_eff))]); + + % Sum of obs or model elements at each location + N_data(pol(1),s_eff,angle_i,count) = ... + nansum([N_data( pol(1),s_eff,angle_i,count); repmat(~isnan([obs_obs_i(i_ind)]),1,length(s_eff)) ]); + + end + + end % (hscale == 0) + + end % ~isempty(ind) + + end % species + end % if file present - - end % loop over multiple years - - end % time_of_day_in_hours - - end % seconds_in_day - - %count = count+1; - - if count >= w_days %wait initially until enough data is built up - - end_time.year = 2014; - end_time.month = month; - end_time.day = day; - end_time.hour = hour; - end_time.min = minute; - end_time.sec = seconds; - - start_time = augment_date_time( -floor(w_days*(24*60*60)), end_time ); - - % At the end of each day, collect the obs and fcst of the last - % w_day period, and write out a statistics-file at [w_day - floor(w_day/2)] - - o_data(abs(o_data - nodata) <= nodata_tol) = NaN; - m_data(abs(o_data - nodata) <= nodata_tol) = NaN; - - % data_out = zeros(N_out_fields,1:N_tiles,N_angle); - - for pol=[0 1] - - pp = pol*Nf; - - N_hscale_window = nansum(N_data(1+pol,:,:,1:w_days),4); - - if w_days == 95 - N_hscale_inner_window = nansum(N_data(1+pol,:,:,((w_days+1)/2-15):((w_days+1)/2+15)),4); - end + + end % loop over multiple years + + end % hour == tmp_hour (time_of_day_in_hours) - % OBSERVATIONS - %---------------- - %o_data is a sum over neighbouring obs above; - %here then take a sum over the time steps in the window - data_out(1+pp,:,:) = nansum(o_data(1+pol,:,:,1:w_days),4); - - %then make the average, by dividing over the sum of the number of - %timesteps and influencing obs at each location - data_out(1+pp,:,:) = data_out(1+pp,:,:)./N_hscale_window; - - %stdv_H = sqrt(E[X^2] - E[X]^2) - data_out(2+pp,:,:) = nansum(o_data2(1+pol,:,:,1:w_days),4); - data_out(2+pp,:,:) = data_out(2+pp,:,:)./N_hscale_window; - data_out(2+pp,:,:) = sqrt( data_out(2+pp,:,:) - data_out(1+pp,:,:).^2); - - % MODEL - %---------------- - data_out(3+pp,:,:) = nansum(m_data(1+pol,:,:,1:w_days),4); - data_out(3+pp,:,:) = data_out(3+pp,:,:)./N_hscale_window; - - data_out(4+pp,:,:) = nansum(m_data2(1+pol,:,:,1:w_days),4); - data_out(4+pp,:,:) = data_out(4+pp,:,:)./N_hscale_window; - data_out(4+pp,:,:) = sqrt( data_out(4+pp,:,:) - data_out(3+pp,:,:).^2); - - data_out(5+pp,:,:) = N_hscale_window; - - % Toss out stats that are based on too little data - - data_out([1:5]+pp,N_hscale_window= w_days %wait initially until enough data is built up + + end_time.year = 2014; + end_time.month = month; + end_time.day = day; + end_time.hour = hour; + end_time.min = minute; + end_time.sec = seconds; + + start_time = augment_date_time( -floor(w_days*(24*60*60)), end_time ); + + % At the end of each day, collect the obs and fcst of the last + % w_day period, and write out a statistics-file at [w_day - floor(w_day/2)] - if w_days == 95 + o_data(abs(o_data - nodata) <= nodata_tol) = NaN; + m_data(abs(o_data - nodata) <= nodata_tol) = NaN; + + % data_out = zeros(N_out_fields,1:N_tiles,N_angle); + + for pol=[0 1] + + pp = pol*Nf; + + N_hscale_window = nansum(N_data(1+pol,:,:,1:w_days),4); + + if w_days == 95 + N_hscale_inner_window = nansum(N_data(1+pol,:,:,((w_days+1)/2-15):((w_days+1)/2+15)),4); + end + + % OBSERVATIONS + %---------------- + % o_data is a sum over neighbouring obs above; + % here then take a sum over the time steps in the window + data_out(1+pp,:,:) = nansum(o_data(1+pol,:,:,1:w_days),4); + + % then make the average, by dividing over the sum of the number of + % timesteps and influencing obs at each location + data_out(1+pp,:,:) = data_out(1+pp,:,:)./N_hscale_window; + + %stdv_H = sqrt(E[X^2] - E[X]^2) + data_out(2+pp,:,:) = nansum(o_data2(1+pol,:,:,1:w_days),4); + data_out(2+pp,:,:) = data_out(2+pp,:,:)./N_hscale_window; + data_out(2+pp,:,:) = sqrt( data_out(2+pp,:,:) - data_out(1+pp,:,:).^2); + + % MODEL + %---------------- + data_out(3+pp,:,:) = nansum(m_data(1+pol,:,:,1:w_days),4); + data_out(3+pp,:,:) = data_out(3+pp,:,:)./N_hscale_window; + + data_out(4+pp,:,:) = nansum(m_data2(1+pol,:,:,1:w_days),4); + data_out(4+pp,:,:) = data_out(4+pp,:,:)./N_hscale_window; + data_out(4+pp,:,:) = sqrt( data_out(4+pp,:,:) - data_out(3+pp,:,:).^2); + + data_out(5+pp,:,:) = N_hscale_window; + + % Toss out stats that are based on too little data + + data_out([1:5]+pp,N_hscale_windowM09_lon(ii)-1e-4 & lon_outM09_lat(ii)-1e-4 & lat_out 1) -% disp('something is wrong, M36 might be overwritten') -% pause -% end -% -% data_out(kk,s_eff) = repmat(this_data, 1, length(s_eff)); -% -% end -% end -% end - - - % Get the actual obs/model at the center point (for debugging only!!) - - data_out(11,:,:) = o_data(1,:,:,w_days-floor(w_days/2.0))./N_data(1,:,:,w_days-floor(w_days/2.0)); - data_out(12,:,:) = m_data(1,:,:,w_days-floor(w_days/2.0))./N_data(1,:,:,w_days-floor(w_days/2.0)); - data_out(13,:,:) = o_data(2,:,:,w_days-floor(w_days/2.0))./N_data(2,:,:,w_days-floor(w_days/2.0)); - data_out(14,:,:) = m_data(2,:,:,w_days-floor(w_days/2.0))./N_data(2,:,:,w_days-floor(w_days/2.0)); - - % Get rid of NaN before writing a file - - data_out(isnan(data_out)) = nodata; - %lon_out(isnan(lon_out)) = nodata; - %lat_out(isnan(lat_out)) = nodata; - - % write output file - - date_time = end_time; - date_time = augment_date_time( -floor(w_days*(24*60*60)/2.0), date_time ); - - % always 365 files - - DOY = date_time.dofyr; - - if(is_leap_year(date_time.year) && DOY>=59) - - DOY = DOY-1; - - error('This code should never hit a leap year'); + % Get the actual obs/model at the center point (for debugging only!!) - end - - - fname_out = [fname_out_base, '_DOY', num2str(DOY,'%3.3d'), '.bin']; - - % check whether output file exists - - if (exist(fname_out)==2 && overwrite) - - disp(['output file exists. overwriting', fname_out]) - - elseif (exist(fname_out)==2 && ~overwrite) - - disp(['output file exists. not overwriting. returning']) - disp(['writing ', fname_out]) - return - - else - - disp(['creating ', fname_out]) - - end - - % compress data before writing in file. - - %idx_keep = find(any(abs(data_out -nodata) > nodata_tol,1)); - %lon_out_write = lon_out(idx_keep); - %lat_out_write = lat_out(idx_keep); - %data_out_write = data_out(:,idx_keep); - %tile_coord_tile_id_write = tile_coord_tile_id(idx_keep); - - - % write output for each DOY, sorted by all tiles - - if print_each_DOY + data_out(11,:,:) = o_data(1,:,:,w_days-floor(w_days/2.0))./N_data(1,:,:,w_days-floor(w_days/2.0)); + data_out(12,:,:) = m_data(1,:,:,w_days-floor(w_days/2.0))./N_data(1,:,:,w_days-floor(w_days/2.0)); + data_out(13,:,:) = o_data(2,:,:,w_days-floor(w_days/2.0))./N_data(2,:,:,w_days-floor(w_days/2.0)); + data_out(14,:,:) = m_data(2,:,:,w_days-floor(w_days/2.0))./N_data(2,:,:,w_days-floor(w_days/2.0)); + + % Get rid of NaN before writing a file + + data_out(isnan(data_out)) = nodata; + %lon_out(isnan(lon_out)) = nodata; + %lat_out(isnan(lat_out)) = nodata; + + % write output file + + date_time = end_time; + date_time = augment_date_time( -floor(w_days*(24*60*60)/2.0), date_time ); + + % always 365 files + + DOY = date_time.dofyr; + + if(is_leap_year(date_time.year) && DOY>=59) - write_seqbin_file(fname_out, lon_out, lat_out, ... - inc_angle, data_out(:,:,:), int_Asc, 0, ... %instead of writing the version#, write Ndata_min=0 - start_time, end_time, overwrite, ... - N_out_fields, write_ind_latlon, 'scaling',... - tile_coord_tile_id) - else + DOY = DOY-1; + + error('This code should never hit a leap year'); + + end + + + fname_out = [fname_out_base, '_DOY', num2str(DOY,'%3.3d'), '.bin']; - % if DOY is at middle of pentad, then copy the DOY to a pentad file - % DOY = pentad*5 - 2; ==> pentad = (DOY + 2)/5; - - pentad = (DOY + 2)/5; + % check whether output file exists + + if (exist(fname_out)==2 && overwrite) + + disp(['output file exists. overwriting', fname_out]) + + elseif (exist(fname_out)==2 && ~overwrite) + + disp(['output file exists. not overwriting. returning']) + disp(['writing ', fname_out]) + return + + else + + disp(['creating ', fname_out]) + + end - if mod((DOY + 2),5) == 0 + % write output for each DOY, sorted by all tiles - write_seqbin_file(fname_out, lon_out, lat_out, ... - inc_angle, data_out(:,:,:), int_Asc, 0, ... - start_time, end_time, overwrite, ... - N_out_fields, write_ind_latlon, 'scaling',... - tile_coord_tile_id) + if print_each_DOY + + write_seqbin_file(fname_out, lon_out, lat_out, ... + inc_angle, data_out(:,:,:), int_Asc, 0, ... % instead of writing the version#, write Ndata_min=0 + start_time, end_time, overwrite, ... + N_out_fields, write_ind_latlon, 'scaling', ... + tile_coord_tile_id) + else + + % if DOY is at middle of pentad, then copy the DOY to a pentad file + % DOY = pentad*5 - 2; ==> pentad = (DOY + 2)/5; + + pentad = (DOY + 2)/5; + + if mod((DOY + 2),5) == 0 + + write_seqbin_file(fname_out, lon_out, lat_out, ... + inc_angle, data_out(:,:,:), int_Asc, 0, ... + start_time, end_time, overwrite, ... + N_out_fields, write_ind_latlon, 'scaling', ... + tile_coord_tile_id) + + fname_out_p = [fname_out_base_p, '_p', num2str(pentad,'%2.2d'), '.bin']; + + copyfile(fname_out,fname_out_p); + + end - fname_out_p = [fname_out_base_p, '_p', num2str(pentad,'%2.2d'), '.bin']; - - copyfile(fname_out,fname_out_p); - end - end - - %clear idx_keep lon_out_write lat_out_write data_out_write tile_coord_tile_id_write - - % shift the window by one day and make room for the next day at the end - - o_data(:,:,:,1:w_days-1) = o_data(:,:,:,2:w_days); - m_data(:,:,:,1:w_days-1) = m_data(:,:,:,2:w_days); - o_data2(:,:,:,1:w_days-1) = o_data2(:,:,:,2:w_days); - m_data2(:,:,:,1:w_days-1) = m_data2(:,:,:,2:w_days); - N_data(:,:,:,1:w_days-1) = N_data(:,:,:,2:w_days); - - o_data(:,:,:,w_days) = NaN; - m_data(:,:,:,w_days) = NaN; - o_data2(:,:,:,w_days) = NaN; - m_data2(:,:,:,w_days) = NaN; - N_data(:,:,:,w_days) = NaN; - - data_out = NaN+0.0.*data_out; - - end - -end % day + %clear idx_keep lon_out_write lat_out_write data_out_write tile_coord_tile_id_write + + % shift the window by one day and make room for the next day at the end + + o_data( :,:,:,1:w_days-1) = o_data( :,:,:,2:w_days); + m_data( :,:,:,1:w_days-1) = m_data( :,:,:,2:w_days); + o_data2(:,:,:,1:w_days-1) = o_data2(:,:,:,2:w_days); + m_data2(:,:,:,1:w_days-1) = m_data2(:,:,:,2:w_days); + N_data( :,:,:,1:w_days-1) = N_data( :,:,:,2:w_days); + + o_data( :,:,:,w_days) = NaN; + m_data( :,:,:,w_days) = NaN; + o_data2(:,:,:,w_days) = NaN; + m_data2(:,:,:,w_days) = NaN; + N_data( :,:,:,w_days) = NaN; + + data_out = NaN+0.0.*data_out; + + end + + end % day end % month diff --git a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats_latlon_grid.m b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats_latlon_grid.m index ba3012b5..24e2b694 100644 --- a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats_latlon_grid.m +++ b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats_latlon_grid.m @@ -1,14 +1,15 @@ function [] = get_model_and_obs_clim_stats_latlon_grid( species_names, ... - run_months, exp_path, exp_run, domain, start_year, end_year, ... - dt_assim, t0_assim, species, combine_species_stats, ... - resol, w_days, Ndata_min, prefix, print_each_DOY, ... + run_months, exp_path, exp_run, domain, start_year, end_year, ... + dt_assim, t0_assim, species, combine_species_stats, ... + resol, w_days, Ndata_min, prefix, print_each_DOY, ... print_each_pentad, print_all_pentads,out_dir ) % -% get_model_and_obs_clim_stats.m +% Adapted from get_model_and_obs_clim_stats.m % % Compute mean, stdv of model and observations from tile-based -% "innov" files for a selection of species. +% "innov" files for a selection of species on an Earth-fixed global +% lat/lon grid with resolution "resol". % % The main purpose of this function is to aggregate the information % from the "innov" files so that the climatology statistics can @@ -17,26 +18,29 @@ % One file with statistics is generated for every DOY (1,...,365). % The temporal smoothing/averaging window (w_days) is given in days. % -% We calcualte the bias correction factors and write on a regular 0.25 degree -% lat/lon grid as there is no regular grid for ASCAT observations +% We calculate the bias correction factors (scaling parameters) and +% write on an Earth-fixed lat/lon grid as there is no Earth-fixed +% regular grid for ASCAT observations. % +% A. M. Fox - 27 Oct 2023 +% % ------------------------------------------------------------------- % begin user-defined inputs % ------------------------------------------------------------------- -nodata = -9999; +nodata = -9999; nodata_tol = 1e-4; -overwrite = 1; -Nf = 7; -N_pentads = 73; +overwrite = 1; +Nf = 7; +N_pentads = 73; -disp('ASSUMING ACAT observations/undefined observation grid'); +disp('ASSUMING obs are not on Earth-fixed regular grid (e.g., ASCAT)'); disp(['Calculating scaling parameters on grid with resolution = ', num2str(resol) , ' degrees']); if combine_species_stats - N_species = 1; + N_species = 1; else - N_species = length(species); + N_species = length(species); end inpath = [ exp_path, '/', exp_run, '/output/', domain ]; @@ -45,7 +49,7 @@ % create outpath if it doesn't exist if ~exist(outpath, 'dir') - mkdir(outpath); + mkdir(outpath); end % assemble output file name @@ -57,34 +61,34 @@ D(1) = 1; P(1) = 1; if mi_m > 1 - D(1) = sum(days_in_month(2014, 1:mi_m-1)) + 1; - P(1) = ceil(D(1) / 5); + D(1) = sum(days_in_month(2014, 1:mi_m-1)) + 1; + P(1) = ceil(D(1) / 5); end D(2) = sum(days_in_month(2014, 1:ma_m)); P(2) = floor(D(2) / 5); -fname_out_base_d = [outpath, '/', prefix, ... - num2str(min(start_year)), '_doy', num2str(D(1)), '_', ... - num2str(max(end_year)), '_doy', num2str(D(2)), ... - '_W_', num2str(w_days), 'd_Nmin_', num2str(Ndata_min)]; +fname_out_base_d = [outpath, '/', prefix, ... + num2str(min(start_year)), '_doy', num2str(D(1)), '_', ... + num2str(max(end_year)), '_doy', num2str(D(2)), ... + '_W_', num2str(w_days), 'd_Nmin_', num2str(Ndata_min)]; -fname_out_base_p = [outpath, '/', prefix, ... - num2str(min(start_year)), '_p', num2str(P(1)), '_', ... - num2str(max(end_year)), '_p', num2str(P(2)), ... - '_W_', num2str(round(w_days/5)), 'p_Nmin_', num2str(Ndata_min)]; +fname_out_base_p = [outpath, '/', prefix, ... + num2str(min(start_year)), '_p', num2str(P(1)), '_', ... + num2str(max(end_year)), '_p', num2str(P(2)), ... + '_W_', num2str(round(w_days/5)), 'p_Nmin_', num2str(Ndata_min)]; %====================================================== -% Define 1/4 degree lat/lon grid +% Define lat/lon grid (dateline-on-edge, pole-on-edge) % Define lower-left corner coordinates and grid cell size ll_lon = -180; -ll_lat = -90; +ll_lat = -90; d_lon = resol; d_lat = resol; % Calculate number of longitude and latitude grid cells -n_lon = round(360/ d_lon); +n_lon = round(360 / d_lon); n_lat = round(180 / d_lat); % Calculate longitude and latitude values for the grid @@ -107,8 +111,8 @@ m_data_max = NaN(N_species, N_gridcells, w_days); N_data = NaN(N_species, N_gridcells, w_days); -data_out = NaN(N_species, Nf, N_gridcells, N_pentads); -data2D = NaN(Nf, N_gridcells); +data_out = NaN(N_species, Nf, N_gridcells, N_pentads); +data2D = NaN(Nf, N_gridcells); % ------------------------------------------------------------- @@ -120,224 +124,227 @@ for imonth = 1:length(run_months) - month = run_months(imonth); - - for day = 1:days_in_month( 2014, month) %2014 = random non-leap year - - if count < w_days - count = count + 1; - else - count = w_days; - end - - for seconds_in_day = t0_assim:dt_assim:(86400-1) - - hour = floor(seconds_in_day/3600); - minute = floor((seconds_in_day-hour*3600)/60); - seconds = seconds_in_day-hour*3600-minute*60; - - if (seconds ~= 0) - input('something is wrong! Ctrl-c now') + month = run_months(imonth); + + for day = 1:days_in_month( 2014, month) %2014 = random non-leap year + + if count < w_days + count = count + 1; + else + count = w_days; + end + + for seconds_in_day = t0_assim:dt_assim:(86400-1) + + hour = floor( seconds_in_day/3600); + minute = floor((seconds_in_day-hour*3600)/60); + seconds = seconds_in_day-hour*3600-minute*60; + + if (seconds ~= 0) + input('something is wrong! Ctrl-c now') + end + + for year = start_year(imonth):end_year(imonth) + + YYYYMMDD = [num2str(year, '%4.4d'), num2str(month, '%2.2d'), num2str(day, '%2.2d')]; + HHMM = [num2str(hour, '%2.2d'), num2str(minute, '%2.2d')]; + + % read innov files + fname = [inpath, '/ana/ens_avg/', 'Y', YYYYMMDD(1:4), '/', 'M', YYYYMMDD(5:6), '/', exp_run, '.ens_avg.ldas_ObsFcstAna.', YYYYMMDD, '_', HHMM, 'z.bin']; + ifp = fopen(fname, 'r', 'l'); + + if (ifp > 0) % Proceed only if file exists + fclose(ifp); + [date_time, obs_assim, obs_species, obs_tilenum, obs_lon, obs_lat, obs_obs, obs_obsvar, obs_fcst, obs_fcstvar, obs_ana, obs_anavar] = read_ObsFcstAna(fname); + + % remove tiles when there is no obs_fcst (obs_fcst == 0 in innov output when missing) + idx = find(obs_fcst == 0); + + obs_assim( idx) = []; + obs_species(idx) = []; + obs_tilenum(idx) = []; + obs_lon( idx) = []; + obs_lat( idx) = []; + obs_obs( idx) = []; + obs_obsvar( idx) = []; + obs_fcst( idx) = []; + obs_fcstvar(idx) = []; + obs_ana( idx) = []; + obs_anavar( idx) = []; + + % extract species of interest + ind = []; + for scnt = 1:N_species + + if combine_species_stats + ind = find(ismember(obs_species, species)); + else + this_species = species(scnt); + ind = find(obs_species == this_species); end - - for year = start_year(imonth):end_year(imonth) - - YYYYMMDD = [num2str(year, '%4.4d'), num2str(month, '%2.2d'), num2str(day, '%2.2d')]; - HHMM = [num2str(hour, '%2.2d'), num2str(minute, '%2.2d')]; - - % read innov files - fname = [inpath, '/ana/ens_avg/', 'Y', YYYYMMDD(1:4), '/', 'M', YYYYMMDD(5:6), '/', exp_run, '.ens_avg.ldas_ObsFcstAna.', YYYYMMDD, '_', HHMM, 'z.bin']; - ifp = fopen(fname, 'r', 'l'); - - if (ifp > 0) % Proceed only if file exists - fclose(ifp); - [date_time, obs_assim, obs_species, obs_tilenum, obs_lon, obs_lat, obs_obs, obs_obsvar, obs_fcst, obs_fcstvar, obs_ana, obs_anavar] = read_ObsFcstAna(fname); - - % remove tiles when there is no obs_fcst (obs_fcst == 0 in innov output when missing) - idx = find(obs_fcst == 0); - obs_assim(idx) = []; - obs_species(idx) = []; - obs_tilenum(idx) = []; - obs_lon(idx) = []; - obs_lat(idx) = []; - obs_obs(idx) = []; - obs_obsvar(idx) = []; - obs_fcst(idx) = []; - obs_fcstvar(idx) = []; - obs_ana(idx) = []; - obs_anavar(idx) = []; - - % extract species of interest - ind = []; - for scnt = 1:N_species - - if combine_species_stats - ind = find(ismember(obs_species, species)); - else - this_species = species(scnt); - ind = find(obs_species == this_species); - end - - if ~isempty(ind) - obs_tilenum_i = obs_tilenum(ind); - obs_obs_i = obs_obs(ind); - obs_fcst_i = obs_fcst(ind); - obs_lon_i = obs_lon(ind); - obs_lat_i = obs_lat(ind); - - % Check if any location receives more than 1 obs (or 1 species) - tmp = sort(obs_tilenum_i); - same_tile = find(diff(tmp) == 0, 1); - if ~isempty(same_tile) && ~combine_species_stats - error('multiple obs of the same species at one location? - only last one in line is used'); - end - - % Put obs lat/lon on our grid and figure out obsnum/grid index - i_idx = floor((obs_lon_i - ll_lon) / d_lon) + 1; - j_idx = floor((obs_lat_i - ll_lat) / d_lat) + 1; - [~, obs_idx] = ismember([i_idx, j_idx], [i_out, j_out], 'rows'); - obs_i = obsnum(obs_idx); - - o_data_sum(scnt, obs_i, count) = nansum([o_data_sum(scnt, obs_i, count); obs_obs_i']); - m_data_sum(scnt, obs_i, count) = nansum([m_data_sum(scnt, obs_i, count); obs_fcst_i']); - o_data_sum2(scnt, obs_i, count) = nansum([o_data_sum2(scnt, obs_i, count); obs_obs_i'.^2]); - m_data_sum2(scnt, obs_i, count) = nansum([m_data_sum2(scnt, obs_i, count); obs_fcst_i'.^2]); - m_data_min(scnt, obs_i, count) = min([m_data_min(scnt, obs_i, count); obs_fcst_i']); - m_data_max(scnt, obs_i, count) = max([m_data_max(scnt, obs_i, count); obs_fcst_i']); - N_data(scnt, obs_i, count) = nansum([N_data(scnt, obs_i, count); ~isnan(obs_obs_i)']); - end - end - end + + if ~isempty(ind) + obs_tilenum_i = obs_tilenum(ind); + obs_obs_i = obs_obs( ind); + obs_fcst_i = obs_fcst( ind); + obs_lon_i = obs_lon( ind); + obs_lat_i = obs_lat( ind); + + % Check if any location receives more than 1 obs (or 1 species) + tmp = sort(obs_tilenum_i); + same_tile = find(diff(tmp) == 0, 1); + if ~isempty(same_tile) && ~combine_species_stats + error('multiple obs of the same species at one location? - only last one in line is used'); + end + + % Put obs lat/lon on our grid and figure out obsnum/grid index + i_idx = floor((obs_lon_i - ll_lon) / d_lon) + 1; + j_idx = floor((obs_lat_i - ll_lat) / d_lat) + 1; + [~, obs_idx] = ismember([i_idx, j_idx], [i_out, j_out], 'rows'); + obs_i = obsnum(obs_idx); + + o_data_sum( scnt, obs_i, count) = nansum([o_data_sum( scnt, obs_i, count); obs_obs_i']); + m_data_sum( scnt, obs_i, count) = nansum([m_data_sum( scnt, obs_i, count); obs_fcst_i']); + o_data_sum2(scnt, obs_i, count) = nansum([o_data_sum2(scnt, obs_i, count); obs_obs_i'.^2]); + m_data_sum2(scnt, obs_i, count) = nansum([m_data_sum2(scnt, obs_i, count); obs_fcst_i'.^2]); + m_data_min( scnt, obs_i, count) = min( [m_data_min( scnt, obs_i, count); obs_fcst_i']); + m_data_max( scnt, obs_i, count) = max( [m_data_max( scnt, obs_i, count); obs_fcst_i']); + N_data( scnt, obs_i, count) = nansum([N_data( scnt, obs_i, count); ~isnan(obs_obs_i)']); end + end end - - if count >= w_days %wait initially until enough data is built up - end_time.year = 2014; - end_time.month = month; - end_time.day = day; - end_time.hour = hour; - end_time.min = minute; - end_time.sec = seconds; - - start_time = augment_date_time( -floor(w_days*(24*60*60)), end_time ); - - % At the end of each day, collect the obs and fcst of the last - % w_day period, and write out a statistics-file at [w_day - floor(w_day/2)] - o_data_sum(abs(o_data_sum - nodata) <= nodata_tol) = NaN; - m_data_sum(abs(m_data_sum - nodata) <= nodata_tol) = NaN; + end + end + + if count >= w_days %wait initially until enough data is built up + end_time.year = 2014; + end_time.month = month; + end_time.day = day; + end_time.hour = hour; + end_time.min = minute; + end_time.sec = seconds; + + start_time = augment_date_time( -floor(w_days*(24*60*60)), end_time ); + + % At the end of each day, collect the obs and fcst of the last + % w_day period, and write out a statistics-file at [w_day - floor(w_day/2)] + o_data_sum(abs(o_data_sum - nodata) <= nodata_tol) = NaN; + m_data_sum(abs(m_data_sum - nodata) <= nodata_tol) = NaN; + + for i = 1:N_species - for i = 1:N_species - N_window = nansum(N_data(i,:,1:w_days),3); - data2D(1,:) = nansum(o_data_sum(i,:,1:w_days),3); - data2D(1,:) = data2D(1,:)./N_window; - data2D(2,:) = sqrt(nansum(o_data_sum2(i,:,1:w_days),3)./N_window - data2D(1,:).^2); - data2D(3,:) = nansum(m_data_sum(i,:,1:w_days),3)./N_window; - data2D(4,:) = sqrt(nansum(m_data_sum2(i,:,1:w_days),3)./N_window - data2D(3,:).^2); - data2D(5,:) = N_window; - data2D(6,:) = min(m_data_min(i,:,1:w_days),[],3); % Want to use minimum mean daily value - data2D(7,:) = max(m_data_max(i,:,1:w_days),[],3); % Want to use maximum mean daily value - - % Set NaNs where there is not enough data - data2D([1:Nf],N_window=59) - error('This code should never hit a leap year'); - end - - if print_each_DOY - pentad = floor((DOY + 2)/5); - if combine_species_stats - fname_out = [fname_out_base_d, '_sp_ALL_DOY', num2str(DOY,'%3.3d'), '.nc4']; - else - fname_out = [fname_out_base_d,'_sp_', char(species_names(i)),'_DOY', num2str(DOY,'%3.3d'), '.nc4']; - end - if (exist(fname_out)==2 && overwrite) - disp(['Output file exists. overwriting', fname_out]) - elseif (exist(fname_out)==2 && ~overwrite) - disp(['Output file exists. not overwriting. returning']) - disp(['Writing ', fname_out]) - return - else - disp(['Creating ', fname_out]) - end - - % Write out the data - write_netcdf_latlon_grid( fname_out, i_out, j_out, ll_lons, ll_lats, data2D, pentad, ... - start_time, end_time, overwrite, Nf, ll_lon, ll_lat, d_lon, d_lat) - end - - if mod((DOY + 2),5) == 0 - pentad = (DOY + 2)/5; - data_out(i,:,:,pentad) = data2D; - start_time_p(pentad) = start_time; - end_time_p(pentad) = end_time; - if print_each_pentad - if combine_species_stats - fname_out = [fname_out_base_p, '_sp_ALL_p', num2str(pentad,'%2.2d'), '.nc4']; - else - fname_out = [fname_out_base_p, '_sp_', char(species_names(i)),'_p', num2str(pentad,'%2.2d'), '.nc4']; - end - if (exist(fname_out)==2 && overwrite) - disp(['Output file exists. overwriting', fname_out]) - elseif (exist(fname_out)==2 && ~overwrite) - disp(['Output file exists. not overwriting. returning']) - disp(['Writing ', fname_out]) - return - else - disp(['Creating ', fname_out]) - end - - % Write out the data - write_netcdf_latlon_grid( fname_out, i_out, j_out, ll_lons, ll_lats, data2D, pentad, ... - start_time, end_time, overwrite, Nf, ll_lon, ll_lat, d_lon, d_lat ) - end - end - - % Shift the data in the window to make room for next day - o_data_sum(i,:,1:w_days-1) = o_data_sum(i,:,2:w_days); - m_data_sum(i,:,1:w_days-1) = m_data_sum(i,:,2:w_days); - o_data_sum2(i,:,1:w_days-1) = o_data_sum2(i,:,2:w_days); - m_data_sum2(i,:,1:w_days-1) = m_data_sum2(i,:,2:w_days); - m_data_min(i,:,1:w_days-1) = m_data_min(i,:,2:w_days); - m_data_max(i,:,1:w_days-1) = m_data_max(i,:,2:w_days); - N_data(i,:,1:w_days-1) = N_data(i,:,2:w_days); - o_data_sum(i,:,w_days) = NaN; - m_data_sum(i,:,w_days) = NaN; - o_data_sum2(i,:,w_days) = NaN; - m_data_sum2(i,:,w_days) = NaN; - m_data_min(i,:,w_days) = NaN; - m_data_max(i,:,w_days) = NaN; - N_data(i,:,w_days) = NaN; - data2D = NaN+0.0.*data2D; - end - end % count >= w_days - end % day -end % month - -if print_all_pentads - for i = 1:N_species - data_o = squeeze(data_out(i,:,:,:)); - - if combine_species_stats - fname_out = [fname_out_base_d, '_sp_ALL_all_pentads.nc4']; - else - fname_out = [fname_out_base_d,'_sp_', char(species_names(i)),'_all_pentads.nc4']; + N_window = nansum(N_data(i,:,1:w_days),3); + + data2D(1,:) = nansum(o_data_sum( i,:,1:w_days),3)./N_window; + data2D(2,:) = sqrt(nansum(o_data_sum2(i,:,1:w_days),3)./N_window - data2D(1,:).^2); + data2D(3,:) = nansum(m_data_sum( i,:,1:w_days),3)./N_window; + data2D(4,:) = sqrt(nansum(m_data_sum2(i,:,1:w_days),3)./N_window - data2D(3,:).^2); + data2D(5,:) = N_window; + data2D(6,:) = min(m_data_min(i,:,1:w_days),[],3); % Want to use minimum mean daily value + data2D(7,:) = max(m_data_max(i,:,1:w_days),[],3); % Want to use maximum mean daily value + + % Set NaNs where there is not enough data + data2D([1:Nf],N_window=59) + error('This code should never hit a leap year'); end - - if (exist(fname_out)==2 && overwrite) + + if print_each_DOY + pentad = floor((DOY + 2)/5); + if combine_species_stats + fname_out = [fname_out_base_d, '_sp_ALL_DOY', num2str(DOY,'%3.3d'), '.nc4']; + else + fname_out = [fname_out_base_d,'_sp_', char(species_names(i)),'_DOY', num2str(DOY,'%3.3d'), '.nc4']; + end + if (exist(fname_out)==2 && overwrite) disp(['Output file exists. overwriting', fname_out]) - elseif (exist(fname_out)==2 && ~overwrite) + elseif (exist(fname_out)==2 && ~overwrite) disp(['Output file exists. not overwriting. returning']) disp(['Writing ', fname_out]) return - else + else disp(['Creating ', fname_out]) + end + + % Write out the data + write_netcdf_latlon_grid( fname_out, i_out, j_out, ll_lons, ll_lats, data2D, pentad, ... + start_time, end_time, overwrite, Nf, ll_lon, ll_lat, d_lon, d_lat) + end + + if mod((DOY + 2),5) == 0 + pentad = (DOY + 2)/5; + data_out(i,:,:,pentad) = data2D; + start_time_p(pentad) = start_time; + end_time_p(pentad) = end_time; + if print_each_pentad + if combine_species_stats + fname_out = [fname_out_base_p, '_sp_ALL_p', num2str(pentad,'%2.2d'), '.nc4']; + else + fname_out = [fname_out_base_p, '_sp_', char(species_names(i)),'_p', num2str(pentad,'%2.2d'), '.nc4']; + end + if (exist(fname_out)==2 && overwrite) + disp(['Output file exists. overwriting', fname_out]) + elseif (exist(fname_out)==2 && ~overwrite) + disp(['Output file exists. not overwriting. returning']) + disp(['Writing ', fname_out]) + return + else + disp(['Creating ', fname_out]) + end + + % Write out the data + write_netcdf_latlon_grid( fname_out, i_out, j_out, ll_lons, ll_lats, data2D, pentad, ... + start_time, end_time, overwrite, Nf, ll_lon, ll_lat, d_lon, d_lat ) + end end + + % Shift the data in the window to make room for next day + o_data_sum( i,:,1:w_days-1) = o_data_sum( i,:,2:w_days); + m_data_sum( i,:,1:w_days-1) = m_data_sum( i,:,2:w_days); + o_data_sum2(i,:,1:w_days-1) = o_data_sum2(i,:,2:w_days); + m_data_sum2(i,:,1:w_days-1) = m_data_sum2(i,:,2:w_days); + m_data_min( i,:,1:w_days-1) = m_data_min( i,:,2:w_days); + m_data_max( i,:,1:w_days-1) = m_data_max( i,:,2:w_days); + N_data( i,:,1:w_days-1) = N_data( i,:,2:w_days); + o_data_sum( i,:,w_days ) = NaN; + m_data_sum( i,:,w_days ) = NaN; + o_data_sum2(i,:,w_days ) = NaN; + m_data_sum2(i,:,w_days ) = NaN; + m_data_min( i,:,w_days ) = NaN; + m_data_max( i,:,w_days ) = NaN; + N_data( i,:,w_days ) = NaN; + + data2D = NaN+0.0.*data2D; + end + end % count >= w_days + end % day +end % month - write_netcdf_latlon_grid( fname_out, i_out, j_out, ll_lons, ll_lats, data_o, [1:73], ... - start_time_p, end_time_p, overwrite, Nf, ll_lon, ll_lat, d_lon, d_lat ) +if print_all_pentads + for i = 1:N_species + data_o = squeeze(data_out(i,:,:,:)); + + if combine_species_stats + fname_out = [fname_out_base_d, '_sp_ALL_all_pentads.nc4']; + else + fname_out = [fname_out_base_d,'_sp_', char(species_names(i)),'_all_pentads.nc4']; + end + + if (exist(fname_out)==2 && overwrite) + disp(['Output file exists. overwriting', fname_out]) + elseif (exist(fname_out)==2 && ~overwrite) + disp(['Output file exists. not overwriting. returning']) + disp(['Writing ', fname_out]) + return + else + disp(['Creating ', fname_out]) end + + write_netcdf_latlon_grid( fname_out, i_out, j_out, ll_lons, ll_lats, data_o, [1:73], ... + start_time_p, end_time_p, overwrite, Nf, ll_lon, ll_lat, d_lon, d_lat ) + end end From 612dc574a8bae951d24a6d06fb46057d9bfcd9f9 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Tue, 19 Dec 2023 13:12:44 -0500 Subject: [PATCH 212/308] minimal white space changes (get_tile_num_for_obs.m, pentad_of_year.m) --- .../util/inputs/obs_scaling_params/get_tile_num_for_obs.m | 8 ++++---- .../LDAS_App/util/shared/matlab/pentad_of_year.m | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_tile_num_for_obs.m b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_tile_num_for_obs.m index 73f68c8f..559853cf 100644 --- a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_tile_num_for_obs.m +++ b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_tile_num_for_obs.m @@ -66,10 +66,10 @@ % map from i_ind, j_ind to tile_num - if ( ~isempty(strfind(tile_grid.gridtype, 'EASE_M')) || ... - ~isempty(strfind(tile_grid.gridtype, 'EASE-M')) || ... - ~isempty(strfind(tile_grid.gridtype, 'EASEv2-M')) || ... - ~isempty(strfind(tile_grid.gridtype, 'EASEv2_M')) ) + if ( ~isempty(strfind(tile_grid.gridtype, 'EASE_M')) || ... + ~isempty(strfind(tile_grid.gridtype, 'EASE-M')) || ... + ~isempty(strfind(tile_grid.gridtype, 'EASEv2-M')) || ... + ~isempty(strfind(tile_grid.gridtype, 'EASEv2_M')) ) % ASSUMPTION: tiles match EASE or EASEv2 grid cells exactly % (unless "outside" the domain, eg. water surface) diff --git a/src/Applications/LDAS_App/util/shared/matlab/pentad_of_year.m b/src/Applications/LDAS_App/util/shared/matlab/pentad_of_year.m index 507cd921..cc827841 100644 --- a/src/Applications/LDAS_App/util/shared/matlab/pentad_of_year.m +++ b/src/Applications/LDAS_App/util/shared/matlab/pentad_of_year.m @@ -11,4 +11,4 @@ end -% ======================= EOF ================================== \ No newline at end of file +% ======================= EOF ================================== From 319905aaa8eb9f20a4aecf76b6dd6f91233f3d01 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Tue, 19 Dec 2023 13:14:06 -0500 Subject: [PATCH 213/308] cleanup of netcdf writer for (ASCAT) obs scaling parameters (write_netcdf_latlon_grid.m): - fixed indentation - improved vertical alignment of equations - fixed typo in 'long_name' of 'lat', 'lon' variables --- .../write_netcdf_latlon_grid.m | 428 +++++++++--------- 1 file changed, 226 insertions(+), 202 deletions(-) diff --git a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/write_netcdf_latlon_grid.m b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/write_netcdf_latlon_grid.m index 348a9b6d..7e64d72d 100644 --- a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/write_netcdf_latlon_grid.m +++ b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/write_netcdf_latlon_grid.m @@ -1,222 +1,246 @@ -function [] = write_netcdf_latlon_grid( fname, colind, rowind,ll_lons, ll_lats, ... +function [] = write_netcdf_latlon_grid( fname, colind, rowind, ll_lons, ll_lats, ... data, pentad, start_time, end_time, overwrite, N_out_fields, ll_lon, ll_lat, d_lon, d_lat ) -int_precision = 'NC_INT'; % precision of fortran tag -float_precision = 'NC_DOUBLE'; % precision of data in input file + int_precision = 'NC_INT'; % precision of fortran tag + float_precision = 'NC_DOUBLE'; % precision of data in input file -% Define the compression level (0-9, where 0 is no compression and 9 is maximum compression) -compression_level = 5; - -version = 0; - -% check dimensions -if size(data,1)~=N_out_fields - error('ERROR: size of data incompatible with N_out_fields') -end - -% check for presence of optional input "overwrite" -if ~exist('overwrite','var') - overwrite = 0; % default: do NOT overwrite existing files -end + % Define the compression level (0-9, where 0 is no compression and 9 is maximum compression) + compression_level = 5; + + version = 0; + + % check dimensions + if size(data,1)~=N_out_fields + error('ERROR: size of data incompatible with N_out_fields') + end + + % check for presence of optional input "overwrite" + if ~exist('overwrite','var') + overwrite = 0; % default: do NOT overwrite existing files + end -% check if file exists -if exist(fname,'file') - if overwrite==0 - disp(['RETURNING!!! -- NOT OVERWRITING EXISTING FILE ', fname]) - return + % check if file exists + if exist(fname,'file') + if overwrite==0 + disp(['RETURNING!!! -- NOT OVERWRITING EXISTING FILE ', fname]) + return + else + disp(['OVERWRITING ', fname]) + end else - disp(['OVERWRITING ', fname]) + disp(['writing ', fname]) end -else - disp(['writing ', fname]) -end - -% Convert the cell arrays to matrices using cell2mat (to deal with all_pentad case) -year_mat = cell2mat({start_time.year}'); -month_mat = cell2mat({start_time.month}'); -day_mat = cell2mat({start_time.day}'); -hour_mat = cell2mat({start_time.hour}'); -min_mat = cell2mat({start_time.min}'); -sec_mat = cell2mat({start_time.sec}'); -% Use the matrices as input to the datetime function -d = datetime(year_mat, month_mat, day_mat, hour_mat, min_mat, sec_mat); -% Convert to serial date number -serialNum = datenum(d); -% Subtract serial date number of January 1, 1950 -daysSince1950 = serialNum - datenum('January 1, 1950'); -tmp_start_time = daysSince1950; - -% Convert the cell arrays to matrices using cell2mat (to deal with all_pentad case) -year_mat = cell2mat({end_time.year}'); -month_mat = cell2mat({end_time.month}'); -day_mat = cell2mat({end_time.day}'); -hour_mat = cell2mat({end_time.hour}'); -min_mat = cell2mat({end_time.min}'); -sec_mat = cell2mat({end_time.sec}'); -% Use the matrices as input to the datetime function -d = datetime(year_mat, month_mat, day_mat, hour_mat, min_mat, sec_mat); -% Convert to serial date number -serialNum = datenum(d); -% Subtract serial date number of January 1, 1950 -daysSince1950 = serialNum - datenum('January 1, 1950'); -tmp_end_time = daysSince1950; - -N_lon = length(ll_lons); -N_lat = length(ll_lats); -% Have we got multiple pentads -if ismatrix(data) - N_pentad = 1; -else - N_pentad = size(data,3); -end - -% create netCDF file -netcdf.setDefaultFormat('FORMAT_NETCDF4'); -ncid = netcdf.create(fname, 'NETCDF4'); - -% define dimensions -dimid_pentad = netcdf.defDim(ncid, 'pentad', N_pentad); -dimid_lon = netcdf.defDim(ncid, 'lon', N_lon); -dimid_lat = netcdf.defDim(ncid, 'lat', N_lat); - -% define variables -varid_version = netcdf.defVar(ncid, 'version', int_precision, []); -varid_ll_lon = netcdf.defVar(ncid, 'll_lon', float_precision, []); -netcdf.putAtt(ncid, varid_ll_lon, 'standard_name','longitude of lower left corner'); -netcdf.putAtt(ncid, varid_ll_lon, 'long_name','longitude of lower left corner'); -netcdf.putAtt(ncid, varid_ll_lon, 'units','degrees_east'); -netcdf.putAtt(ncid, varid_ll_lon, 'axis','X'); -varid_ll_lat = netcdf.defVar(ncid, 'll_lat', float_precision, []); -netcdf.putAtt(ncid, varid_ll_lat, 'standard_name','latitude of lower left corner'); -netcdf.putAtt(ncid, varid_ll_lat, 'long_name','latitude of lower left corner'); -netcdf.putAtt(ncid, varid_ll_lat, 'units','degrees_north'); -netcdf.putAtt(ncid, varid_ll_lat, 'axis','Y'); -varid_d_lon = netcdf.defVar(ncid, 'd_lon', float_precision, []); -netcdf.putAtt(ncid, varid_d_lon, 'standard_name','longitude grid spacing'); -netcdf.putAtt(ncid, varid_d_lon, 'long_name','longitude grid spacing'); -netcdf.putAtt(ncid, varid_d_lon, 'units','degrees'); -netcdf.putAtt(ncid, varid_d_lon, 'axis','X'); -varid_d_lat = netcdf.defVar(ncid, 'd_lat', float_precision, []); -netcdf.putAtt(ncid, varid_d_lat, 'standard_name','latitude grid spacing'); -netcdf.putAtt(ncid, varid_d_lat, 'long_name','latitude grid spacing'); -netcdf.putAtt(ncid, varid_d_lat, 'units','degrees'); -netcdf.putAtt(ncid, varid_d_lat, 'axis','Y'); -varid_pentad = netcdf.defVar(ncid, 'pentad', int_precision, [dimid_pentad]); -netcdf.putAtt(ncid, varid_pentad, 'standard_name','pentad'); -netcdf.putAtt(ncid, varid_pentad, 'long_name','pentad'); -netcdf.putAtt(ncid, varid_pentad, 'units','1'); -netcdf.putAtt(ncid, varid_pentad, 'axis','T'); -varid_start_time = netcdf.defVar(ncid, 'start_time', float_precision, [dimid_pentad]); -netcdf.putAtt(ncid, varid_start_time, 'standard_name','start time'); -netcdf.putAtt(ncid, varid_start_time, 'long_name','start time'); -netcdf.putAtt(ncid, varid_start_time, 'axis','T'); -netcdf.putAtt(ncid, varid_start_time, 'units','days since 1950-01-01 00:00:00.0 +0000'); -varid_end_time = netcdf.defVar(ncid, 'end_time',float_precision, [dimid_pentad]); -netcdf.putAtt(ncid, varid_end_time, 'standard_name','end time'); -netcdf.putAtt(ncid, varid_end_time, 'long_name','end time'); -netcdf.putAtt(ncid, varid_end_time, 'axis','T'); -netcdf.putAtt(ncid, varid_end_time, 'units','days since 1950-01-01 00:00:00.0 +0000'); -varid_lon = netcdf.defVar(ncid, 'lon', float_precision, [dimid_lon]); -netcdf.putAtt(ncid, varid_lon, 'standard_name','longitude'); -netcdf.putAtt(ncid, varid_lon, 'long_name','loswer left longitude of gridcell'); -netcdf.putAtt(ncid, varid_lon, 'units','degrees_east'); -netcdf.putAtt(ncid, varid_lon, 'axis','X'); -varid_lat = netcdf.defVar(ncid, 'lat', float_precision, [dimid_lat]); -netcdf.putAtt(ncid, varid_lat, 'standard_name','latitude'); -netcdf.putAtt(ncid, varid_lat, 'long_name','loswer left latitude of gridcell'); -netcdf.putAtt(ncid, varid_lat, 'units','degrees_north'); -netcdf.putAtt(ncid, varid_lat, 'axis','Y'); -varid_om = netcdf.defVar(ncid, 'o_mean', float_precision, [dimid_lat dimid_lon dimid_pentad]); -netcdf.defVarDeflate(ncid,varid_om,true,true,compression_level); -netcdf.putAtt(ncid, varid_om, 'standard_name','observation mean'); -netcdf.putAtt(ncid, varid_om, 'long_name','Observation mean for pentad calculated over all years for window length'); -netcdf.putAtt(ncid, varid_om, 'units','Degree of saturation (0-1)'); -varid_ov = netcdf.defVar(ncid, 'o_std', float_precision, [dimid_lat dimid_lon dimid_pentad]); -netcdf.defVarDeflate(ncid,varid_ov,true,true,compression_level); -netcdf.putAtt(ncid, varid_ov, 'standard_name','observation standard deviation'); -netcdf.putAtt(ncid, varid_ov, 'long_name','Observation standard deviation for pentad calculated over all years for window length'); -netcdf.putAtt(ncid, varid_ov, 'units','Degree of saturation (0-1)'); -varid_mm = netcdf.defVar(ncid, 'm_mean', float_precision, [dimid_lat dimid_lon dimid_pentad]); -netcdf.defVarDeflate(ncid,varid_mm,true,true,compression_level); -netcdf.putAtt(ncid, varid_mm, 'standard_name','model mean'); -netcdf.putAtt(ncid, varid_mm, 'long_name','Model mean for pentad calculated over all years for window length'); -netcdf.putAtt(ncid, varid_mm, 'units','Surface soil moisture (m^3 m^-3)'); -varid_mv = netcdf.defVar(ncid, 'm_std', float_precision, [dimid_lat dimid_lon dimid_pentad]); -netcdf.defVarDeflate(ncid,varid_mv,true,true,compression_level); -netcdf.putAtt(ncid, varid_mv, 'standard_name','model standard deviation'); -netcdf.putAtt(ncid, varid_mv, 'long_name','Model standard deviation for pentad calculated over all years for window length'); -netcdf.putAtt(ncid, varid_mv, 'units','Surface soil moisture (m^3 m^-3)'); -varid_mi = netcdf.defVar(ncid, 'm_min', float_precision, [dimid_lat dimid_lon]); -netcdf.defVarDeflate(ncid,varid_mi,true,true,compression_level); -netcdf.putAtt(ncid, varid_mi, 'standard_name','model minimum'); -netcdf.putAtt(ncid, varid_mi, 'long_name','Model minimum calculated over all years'); -netcdf.putAtt(ncid, varid_mi, 'units','Surface soil moisture (m^3 m^-3)'); -varid_ma = netcdf.defVar(ncid, 'm_max', float_precision, [dimid_lat dimid_lon]); -netcdf.defVarDeflate(ncid,varid_ma,true,true,compression_level); -netcdf.putAtt(ncid, varid_ma, 'standard_name','model maximum'); -netcdf.putAtt(ncid, varid_ma, 'long_name','Model maximum calculated over all years'); -netcdf.putAtt(ncid, varid_ma, 'units','Surface soil moisture (m^3 m^-3)'); -varid_ndata = netcdf.defVar(ncid, 'n_data', float_precision, [dimid_lat dimid_lon dimid_pentad]); -netcdf.defVarDeflate(ncid,varid_ndata,true,true,compression_level); -netcdf.putAtt(ncid, varid_ndata, 'standard_name','number of data points'); -netcdf.putAtt(ncid, varid_ndata, 'long_name','Number of data points for pentad calculated over all years for window length'); -netcdf.putAtt(ncid, varid_ndata, 'units','1'); - -% end define mode -netcdf.endDef(ncid); - -% write data -netcdf.putVar(ncid, varid_pentad, pentad); -netcdf.putVar(ncid, varid_start_time, tmp_start_time); -netcdf.putVar(ncid, varid_end_time, tmp_end_time); + % Convert the cell arrays to matrices using cell2mat (to deal with all_pentad case) + year_mat = cell2mat({start_time.year}'); + month_mat = cell2mat({start_time.month}'); + day_mat = cell2mat({start_time.day}'); + hour_mat = cell2mat({start_time.hour}'); + min_mat = cell2mat({start_time.min}'); + sec_mat = cell2mat({start_time.sec}'); + % Use the matrices as input to the datetime function + d = datetime(year_mat, month_mat, day_mat, hour_mat, min_mat, sec_mat); + % Convert to serial date number + serialNum = datenum(d); + % Subtract serial date number of January 1, 1950 + daysSince1950 = serialNum - datenum('January 1, 1950'); + tmp_start_time = daysSince1950; + + % Convert the cell arrays to matrices using cell2mat (to deal with all_pentad case) + year_mat = cell2mat({end_time.year}'); + month_mat = cell2mat({end_time.month}'); + day_mat = cell2mat({end_time.day}'); + hour_mat = cell2mat({end_time.hour}'); + min_mat = cell2mat({end_time.min}'); + sec_mat = cell2mat({end_time.sec}'); + % Use the matrices as input to the datetime function + d = datetime(year_mat, month_mat, day_mat, hour_mat, min_mat, sec_mat); + % Convert to serial date number + serialNum = datenum(d); + % Subtract serial date number of January 1, 1950 + daysSince1950 = serialNum - datenum('January 1, 1950'); + tmp_end_time = daysSince1950; + + N_lon = length(ll_lons); + N_lat = length(ll_lats); + + % Have we got multiple pentads + if ismatrix(data) + N_pentad = 1; + else + N_pentad = size(data,3); + end -netcdf.putVar(ncid, varid_lon, ll_lons); -netcdf.putVar(ncid, varid_lat, ll_lats); -netcdf.putVar(ncid, varid_ll_lon, ll_lon); -netcdf.putVar(ncid, varid_ll_lat, ll_lat); -netcdf.putVar(ncid, varid_d_lon, d_lon); -netcdf.putVar(ncid, varid_d_lat, d_lat); + % create netCDF file + netcdf.setDefaultFormat('FORMAT_NETCDF4'); + ncid = netcdf.create(fname, 'NETCDF4'); + + % define dimensions + dimid_pentad = netcdf.defDim(ncid, 'pentad', N_pentad); + dimid_lon = netcdf.defDim(ncid, 'lon', N_lon); + dimid_lat = netcdf.defDim(ncid, 'lat', N_lat); + + % define variables + + varid_version = netcdf.defVar(ncid, 'version', int_precision, []); -if N_pentad ==1 + varid_ll_lon = netcdf.defVar(ncid, 'll_lon', float_precision, []); + netcdf.putAtt(ncid, varid_ll_lon, 'standard_name', 'longitude of lower left corner'); + netcdf.putAtt(ncid, varid_ll_lon, 'long_name', 'longitude of lower left corner'); + netcdf.putAtt(ncid, varid_ll_lon, 'units', 'degrees_east'); + netcdf.putAtt(ncid, varid_ll_lon, 'axis', 'X'); + + varid_ll_lat = netcdf.defVar(ncid, 'll_lat', float_precision, []); + netcdf.putAtt(ncid, varid_ll_lat, 'standard_name', 'latitude of lower left corner'); + netcdf.putAtt(ncid, varid_ll_lat, 'long_name', 'latitude of lower left corner'); + netcdf.putAtt(ncid, varid_ll_lat, 'units', 'degrees_north'); + netcdf.putAtt(ncid, varid_ll_lat, 'axis', 'Y'); + + varid_d_lon = netcdf.defVar(ncid, 'd_lon', float_precision, []); + netcdf.putAtt(ncid, varid_d_lon, 'standard_name', 'longitude grid spacing'); + netcdf.putAtt(ncid, varid_d_lon, 'long_name', 'longitude grid spacing'); + netcdf.putAtt(ncid, varid_d_lon, 'units', 'degrees'); + netcdf.putAtt(ncid, varid_d_lon, 'axis', 'X'); + + varid_d_lat = netcdf.defVar(ncid, 'd_lat', float_precision, []); + netcdf.putAtt(ncid, varid_d_lat, 'standard_name', 'latitude grid spacing'); + netcdf.putAtt(ncid, varid_d_lat, 'long_name', 'latitude grid spacing'); + netcdf.putAtt(ncid, varid_d_lat, 'units', 'degrees'); + netcdf.putAtt(ncid, varid_d_lat, 'axis', 'Y'); + + varid_pentad = netcdf.defVar(ncid, 'pentad', int_precision, [dimid_pentad]); + netcdf.putAtt(ncid, varid_pentad, 'standard_name', 'pentad'); + netcdf.putAtt(ncid, varid_pentad, 'long_name', 'pentad'); + netcdf.putAtt(ncid, varid_pentad, 'units', '1'); + netcdf.putAtt(ncid, varid_pentad, 'axis', 'T'); + + varid_start_time = netcdf.defVar(ncid, 'start_time', float_precision, [dimid_pentad]); + netcdf.putAtt(ncid, varid_start_time, 'standard_name', 'start time'); + netcdf.putAtt(ncid, varid_start_time, 'long_name', 'start time'); + netcdf.putAtt(ncid, varid_start_time, 'axis', 'T'); + netcdf.putAtt(ncid, varid_start_time, 'units', 'days since 1950-01-01 00:00:00.0 +0000'); + + varid_end_time = netcdf.defVar(ncid, 'end_time', float_precision, [dimid_pentad]); + netcdf.putAtt(ncid, varid_end_time, 'standard_name', 'end time'); + netcdf.putAtt(ncid, varid_end_time, 'long_name', 'end time'); + netcdf.putAtt(ncid, varid_end_time, 'axis', 'T'); + netcdf.putAtt(ncid, varid_end_time, 'units', 'days since 1950-01-01 00:00:00.0 +0000'); + + varid_lon = netcdf.defVar(ncid, 'lon', float_precision, [dimid_lon]); + netcdf.putAtt(ncid, varid_lon, 'standard_name', 'longitude'); + netcdf.putAtt(ncid, varid_lon, 'long_name', 'lower left longitude of gridcell'); + netcdf.putAtt(ncid, varid_lon, 'units', 'degrees_east'); + netcdf.putAtt(ncid, varid_lon, 'axis', 'X'); + + varid_lat = netcdf.defVar(ncid, 'lat', float_precision, [dimid_lat]); + netcdf.putAtt(ncid, varid_lat, 'standard_name', 'latitude'); + netcdf.putAtt(ncid, varid_lat, 'long_name', 'lower left latitude of gridcell'); + netcdf.putAtt(ncid, varid_lat, 'units', 'degrees_north'); + netcdf.putAtt(ncid, varid_lat, 'axis', 'Y'); + + varid_om = netcdf.defVar(ncid, 'o_mean', float_precision, [dimid_lat dimid_lon dimid_pentad]); + netcdf.defVarDeflate(ncid,varid_om,true,true,compression_level); + netcdf.putAtt(ncid, varid_om, 'standard_name', 'observation mean'); + netcdf.putAtt(ncid, varid_om, 'long_name', 'Observation mean for pentad calculated over all years for window length'); + netcdf.putAtt(ncid, varid_om, 'units', 'Degree of saturation (0-1)'); + + varid_ov = netcdf.defVar(ncid, 'o_std', float_precision, [dimid_lat dimid_lon dimid_pentad]); + netcdf.defVarDeflate(ncid,varid_ov,true,true,compression_level); + netcdf.putAtt(ncid, varid_ov, 'standard_name', 'observation standard deviation'); + netcdf.putAtt(ncid, varid_ov, 'long_name', 'Observation standard deviation for pentad calculated over all years for window length'); + netcdf.putAtt(ncid, varid_ov, 'units', 'Degree of saturation (0-1)'); + + varid_mm = netcdf.defVar(ncid, 'm_mean', float_precision, [dimid_lat dimid_lon dimid_pentad]); + netcdf.defVarDeflate(ncid,varid_mm,true,true,compression_level); + netcdf.putAtt(ncid, varid_mm, 'standard_name', 'model mean'); + netcdf.putAtt(ncid, varid_mm, 'long_name', 'Model mean for pentad calculated over all years for window length'); + netcdf.putAtt(ncid, varid_mm, 'units', 'Surface soil moisture (m^3 m^-3)'); + + varid_mv = netcdf.defVar(ncid, 'm_std', float_precision, [dimid_lat dimid_lon dimid_pentad]); + netcdf.defVarDeflate(ncid,varid_mv,true,true,compression_level); + netcdf.putAtt(ncid, varid_mv, 'standard_name', 'model standard deviation'); + netcdf.putAtt(ncid, varid_mv, 'long_name', 'Model standard deviation for pentad calculated over all years for window length'); + netcdf.putAtt(ncid, varid_mv, 'units', 'Surface soil moisture (m^3 m^-3)'); - data_out = ones(N_out_fields,N_lat, N_lon) * -999.0; + varid_mi = netcdf.defVar(ncid, 'm_min', float_precision, [dimid_lat dimid_lon]); + netcdf.defVarDeflate(ncid,varid_mi,true,true,compression_level); + netcdf.putAtt(ncid, varid_mi, 'standard_name', 'model minimum'); + netcdf.putAtt(ncid, varid_mi, 'long_name', 'Model minimum calculated over all years'); + netcdf.putAtt(ncid, varid_mi, 'units', 'Surface soil moisture (m^3 m^-3)'); - for n = 1:N_out_fields - for i = 1:length(colind) - data_out(n,rowind(i),colind(i)) = data(n,i); + varid_ma = netcdf.defVar(ncid, 'm_max', float_precision, [dimid_lat dimid_lon]); + netcdf.defVarDeflate(ncid,varid_ma,true,true,compression_level); + netcdf.putAtt(ncid, varid_ma, 'standard_name', 'model maximum'); + netcdf.putAtt(ncid, varid_ma, 'long_name', 'Model maximum calculated over all years'); + netcdf.putAtt(ncid, varid_ma, 'units', 'Surface soil moisture (m^3 m^-3)'); + + varid_ndata = netcdf.defVar(ncid, 'n_data', float_precision, [dimid_lat dimid_lon dimid_pentad]); + netcdf.defVarDeflate(ncid,varid_ndata,true,true,compression_level); + netcdf.putAtt(ncid, varid_ndata, 'standard_name', 'number of data points'); + netcdf.putAtt(ncid, varid_ndata, 'long_name', 'Number of data points for pentad calculated over all years for window length'); + netcdf.putAtt(ncid, varid_ndata, 'units', '1'); + + % end define mode + netcdf.endDef(ncid); + + % write data + netcdf.putVar(ncid, varid_pentad, pentad); + netcdf.putVar(ncid, varid_start_time, tmp_start_time); + netcdf.putVar(ncid, varid_end_time, tmp_end_time); + + netcdf.putVar(ncid, varid_lon, ll_lons); + netcdf.putVar(ncid, varid_lat, ll_lats); + netcdf.putVar(ncid, varid_ll_lon, ll_lon); + netcdf.putVar(ncid, varid_ll_lat, ll_lat); + netcdf.putVar(ncid, varid_d_lon, d_lon); + netcdf.putVar(ncid, varid_d_lat, d_lat); + + if N_pentad ==1 + + data_out = ones(N_out_fields,N_lat,N_lon ) * -999.0; + + for n = 1:N_out_fields + for i = 1:length(colind) + data_out(n,rowind(i),colind(i)) = data(n,i); + end end - end - netcdf.putVar(ncid,varid_om,data_out(1, :, :)); - netcdf.putVar(ncid,varid_ov,data_out(2, :, :)); - netcdf.putVar(ncid,varid_mm,data_out(3, :, :)); - netcdf.putVar(ncid,varid_mv,data_out(4, :, :)); - netcdf.putVar(ncid,varid_mi,data_out(6, :, :)); - netcdf.putVar(ncid,varid_ma,data_out(7, :, :)); - netcdf.putVar(ncid,varid_ndata,data_out(5, :, :)); -else + netcdf.putVar(ncid,varid_om, data_out(1,:,:) ); + netcdf.putVar(ncid,varid_ov, data_out(2,:,:) ); + netcdf.putVar(ncid,varid_mm, data_out(3,:,:) ); + netcdf.putVar(ncid,varid_mv, data_out(4,:,:) ); + netcdf.putVar(ncid,varid_mi, data_out(6,:,:) ); + netcdf.putVar(ncid,varid_ma, data_out(7,:,:) ); + netcdf.putVar(ncid,varid_ndata, data_out(5,:,:) ); + + else - data_out = ones(N_out_fields, N_lat,N_lon,N_pentad) * -999.0; + data_out = ones(N_out_fields,N_lat,N_lon,N_pentad) * -999.0; - for n = 1:N_out_fields - for i = 1:length(colind) - data_out(n,rowind(i),colind(i),:) = data(n,i,:); + for n = 1:N_out_fields + for i = 1:length(colind) + data_out(n,rowind(i),colind(i),:) = data(n,i,:); + end end + + netcdf.putVar(ncid,varid_om, data_out(1,:,:,:) ); + netcdf.putVar(ncid,varid_ov, data_out(2,:,:,:) ); + netcdf.putVar(ncid,varid_mm, data_out(3,:,:,:) ); + netcdf.putVar(ncid,varid_mv, data_out(4,:,:,:) ); + netcdf.putVar(ncid,varid_ndata, data_out(5,:,:,:) ); + netcdf.putVar(ncid,varid_ma, max(data_out(7,:,:,:),[],4)); % Max over all pentads, always only 2D + + min_data = squeeze(data_out(6, :, :,:)); + min_data(min_data < -9998) = NaN; % Switch current missing value to NaN before calculating min + min_data_out = min(min_data,[],3); + min_data_out(isnan(min_data_out)) = -9999.; + + netcdf.putVar(ncid,varid_mi, min_data_out); % Min over all pentads, always only 2D end + + % close netCDF file + netcdf.close(ncid); - netcdf.putVar(ncid,varid_om,data_out(1, :, :,:)); - netcdf.putVar(ncid,varid_ov,data_out(2, :, :,:)); - netcdf.putVar(ncid,varid_mm,data_out(3, :, :,:)); - netcdf.putVar(ncid,varid_mv,data_out(4, :, :,:)); - netcdf.putVar(ncid,varid_ndata,data_out(5, :, :,:)) - netcdf.putVar(ncid,varid_ma, max(data_out(7, :, :,:),[],4)); % Max over all pentads, always only 2D - min_data = squeeze(data_out(6, :, :,:)); min_data(min_data < -9998) = NaN; % Need to switch current missing value to NaN before calculating min - min_data_out = min(min_data,[],3); min_data_out(isnan(min_data_out)) = -9999.; - netcdf.putVar(ncid,varid_mi,min_data_out); % Min over all pentads, always only 2D end -% close netCDF file -netcdf.close(ncid); - -end +% ================ EOF ======================================================== From 3ffee32c6b6bc092d9ea74200de33494ba0ed891 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Tue, 19 Dec 2023 13:59:20 -0500 Subject: [PATCH 214/308] replaced deprecated Matlab functions "nanmean", "nanstd", and "nansum" with "mean", "std", and "sum"; avoids dependency on Stats toolbox (various *.m) --- .../Create_vegopacity_8day_clim.m | 6 +-- .../get_L2_RTM_constants_tile_data.m | 4 +- .../get_model_and_obs_clim_stats.m | 48 +++++++++---------- ...get_model_and_obs_clim_stats_latlon_grid.m | 28 +++++------ .../climatology/get_model_clim_stats.m | 10 ++-- .../LDAS_App/util/postproc/write_smapL4SMqa.m | 1 - 6 files changed, 48 insertions(+), 49 deletions(-) diff --git a/src/Applications/LDAS_App/util/inputs/mwRTM_params/Create_vegopacity_8day_clim.m b/src/Applications/LDAS_App/util/inputs/mwRTM_params/Create_vegopacity_8day_clim.m index 3c243b27..13272941 100644 --- a/src/Applications/LDAS_App/util/inputs/mwRTM_params/Create_vegopacity_8day_clim.m +++ b/src/Applications/LDAS_App/util/inputs/mwRTM_params/Create_vegopacity_8day_clim.m @@ -241,7 +241,7 @@ header = [y1 m1 d1 0 0 0 y2 m2 d2 0 0 0 tc.N_tile 1]; - tile_data = nanmean(L2_tau_tile([nidx_pre nidx nidx_nxt],:),1); + tile_data = mean(L2_tau_tile([nidx_pre nidx nidx_nxt],:),1,"omitnan"); tile_data(isnan(tile_data)) = 1.e15; fwrite( ifp, 14*4, int_precision ); % fortran_tag @@ -260,7 +260,7 @@ end % ======================== -% The final vegopacity.bin file contains data averaged (nanmean) of Asc +% The final vegopacity.bin file contains data averaged (mean) of Asc % and Des tau climatology. VOD is climatology,the other 2 parameters are % time constant with maximum spatial coverage data_clim_tile = NaN + ones(48, tc.N_tile,2); @@ -295,7 +295,7 @@ data_clim_tile(data_clim_tile < 0.) = 0.; % set small negative values to 0 % averaging A, D values -tile_data = nanmean(data_clim_tile,3); +tile_data = mean(data_clim_tile,3,"omitnan"); fname_out = strrep(fname, L2_Ascdes,'_AD_'); if fill_small_gaps diff --git a/src/Applications/LDAS_App/util/inputs/mwRTM_params/get_L2_RTM_constants_tile_data.m b/src/Applications/LDAS_App/util/inputs/mwRTM_params/get_L2_RTM_constants_tile_data.m index c717b9be..3125e892 100644 --- a/src/Applications/LDAS_App/util/inputs/mwRTM_params/get_L2_RTM_constants_tile_data.m +++ b/src/Applications/LDAS_App/util/inputs/mwRTM_params/get_L2_RTM_constants_tile_data.m @@ -4,7 +4,7 @@ L2_version,start_time, end_time) % function to compute the 2 RTM constant variables: Albedo and Roughness(H) based on the -% preprocessed data. Constants are taken as the long term temporal nanmean +% preprocessed data. Constants are taken as the long term temporal mean % with maximum coverage across Asc/Desc passes. % Q. Liu 18 Jul 2022 @@ -212,7 +212,7 @@ data_clim_tile(data_clim_tile < 0.) = 0.; % set small negative values to 0 % averaging A, D values - tile_data = nanmean(data_clim_tile,2); + tile_data = mean(data_clim_tile,2,"omitnan"); eval(['out_mwRTM.',out_Para{iPara},'=tile_data;']) end diff --git a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats.m b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats.m index 3a5cd478..9d0a7ebb 100644 --- a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats.m +++ b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats.m @@ -500,17 +500,17 @@ % and across years! % some obs can be found at multiple hours within a day % e.g. at the poles. - % **nansum of NaN's** result in zero, this need to be + % **sum(...,"omitnan") of NaNs** results in zero, this need to be % taken care of - o_data( pol(1),obs_i,angle_i,count) = nansum([o_data( pol(1),obs_i,angle_i,count); obs_obs_i' ]); - m_data( pol(1),obs_i,angle_i,count) = nansum([m_data( pol(1),obs_i,angle_i,count); obs_fcst_i']); + o_data( pol(1),obs_i,angle_i,count) = sum([o_data( pol(1),obs_i,angle_i,count); obs_obs_i' ], "omitnan"); + m_data( pol(1),obs_i,angle_i,count) = sum([m_data( pol(1),obs_i,angle_i,count); obs_fcst_i' ], "omitnan"); % X^2 - o_data2(pol(1),obs_i,angle_i,count) = nansum([o_data2(pol(1),obs_i,angle_i,count); obs_obs_i'.^2 ]); - m_data2(pol(1),obs_i,angle_i,count) = nansum([m_data2(pol(1),obs_i,angle_i,count); obs_fcst_i'.^2]); + o_data2(pol(1),obs_i,angle_i,count) = sum([o_data2(pol(1),obs_i,angle_i,count); obs_obs_i'.^2 ], "omitnan"); + m_data2(pol(1),obs_i,angle_i,count) = sum([m_data2(pol(1),obs_i,angle_i,count); obs_fcst_i'.^2 ], "omitnan"); % Sum of obs or model elements at each location - N_data(pol(1),obs_i,angle_i,count) = nansum( [N_data( pol(1),obs_i,angle_i,count); ~isnan([obs_obs_i])']); + N_data(pol(1), obs_i,angle_i,count) = sum([N_data( pol(1),obs_i,angle_i,count); ~isnan([obs_obs_i])'], "omitnan"); else @@ -523,19 +523,19 @@ % Sum of X o_data(pol(1),s_eff,angle_i,count) = ... - nansum([o_data( pol(1),s_eff,angle_i,count); repmat(obs_obs_i( i_ind), 1,length(s_eff))]); + sum([o_data( pol(1),s_eff,angle_i,count); repmat( obs_obs_i( i_ind), 1,length(s_eff))], "omitnan"); m_data(pol(1),s_eff,angle_i,count) = ... - nansum([m_data( pol(1),s_eff,angle_i,count); repmat(obs_fcst_i(i_ind), 1,length(s_eff))]); + sum([m_data( pol(1),s_eff,angle_i,count); repmat( obs_fcst_i(i_ind), 1,length(s_eff))], "omitnan"); % Sum of X^2 o_data2(pol(1),s_eff,angle_i,count) = ... - nansum([o_data2(pol(1),s_eff,angle_i,count); repmat(obs_obs_i( i_ind).^2,1,length(s_eff))]); + sum([o_data2(pol(1),s_eff,angle_i,count); repmat( obs_obs_i( i_ind).^2,1,length(s_eff))], "omitnan"); m_data2(pol(1),s_eff,angle_i,count) = ... - nansum([m_data2(pol(1),s_eff,angle_i,count); repmat(obs_fcst_i(i_ind).^2,1,length(s_eff))]); + sum([m_data2(pol(1),s_eff,angle_i,count); repmat( obs_fcst_i(i_ind).^2,1,length(s_eff))], "omitnan"); % Sum of obs or model elements at each location N_data(pol(1),s_eff,angle_i,count) = ... - nansum([N_data( pol(1),s_eff,angle_i,count); repmat(~isnan([obs_obs_i(i_ind)]),1,length(s_eff)) ]); + sum([N_data( pol(1),s_eff,angle_i,count); repmat(~isnan([obs_obs_i(i_ind)]), 1,length(s_eff))], "omitnan"); end @@ -578,41 +578,41 @@ pp = pol*Nf; - N_hscale_window = nansum(N_data(1+pol,:,:,1:w_days),4); + N_hscale_window = sum(N_data(1+pol,:,:,1:w_days), 4,"omitnan"); if w_days == 95 - N_hscale_inner_window = nansum(N_data(1+pol,:,:,((w_days+1)/2-15):((w_days+1)/2+15)),4); + N_hscale_inner_window = sum(N_data(1+pol,:,:,((w_days+1)/2-15):((w_days+1)/2+15)),4,"omitnan"); end % OBSERVATIONS %---------------- % o_data is a sum over neighbouring obs above; % here then take a sum over the time steps in the window - data_out(1+pp,:,:) = nansum(o_data(1+pol,:,:,1:w_days),4); + data_out(1+pp,:,:) = sum( o_data( 1+pol,:,:,1:w_days),4,"omitnan"); % then make the average, by dividing over the sum of the number of % timesteps and influencing obs at each location - data_out(1+pp,:,:) = data_out(1+pp,:,:)./N_hscale_window; + data_out(1+pp,:,:) = data_out( 1+pp, :,:)./N_hscale_window; %stdv_H = sqrt(E[X^2] - E[X]^2) - data_out(2+pp,:,:) = nansum(o_data2(1+pol,:,:,1:w_days),4); - data_out(2+pp,:,:) = data_out(2+pp,:,:)./N_hscale_window; - data_out(2+pp,:,:) = sqrt( data_out(2+pp,:,:) - data_out(1+pp,:,:).^2); + data_out(2+pp,:,:) = sum( o_data2( 1+pol,:,:,1:w_days),4,"omitnan"); + data_out(2+pp,:,:) = data_out( 2+pp, :,:)./N_hscale_window; + data_out(2+pp,:,:) = sqrt( data_out( 2+pp, :,:) - data_out(1+pp,:,:).^2); % MODEL %---------------- - data_out(3+pp,:,:) = nansum(m_data(1+pol,:,:,1:w_days),4); - data_out(3+pp,:,:) = data_out(3+pp,:,:)./N_hscale_window; + data_out(3+pp,:,:) = sum( m_data( 1+pol,:,:,1:w_days),4,"omitnan"); + data_out(3+pp,:,:) = data_out( 3+pp, :,:)./N_hscale_window; - data_out(4+pp,:,:) = nansum(m_data2(1+pol,:,:,1:w_days),4); - data_out(4+pp,:,:) = data_out(4+pp,:,:)./N_hscale_window; - data_out(4+pp,:,:) = sqrt( data_out(4+pp,:,:) - data_out(3+pp,:,:).^2); + data_out(4+pp,:,:) = sum( m_data2( 1+pol,:,:,1:w_days),4,"omitnan"); + data_out(4+pp,:,:) = data_out( 4+pp, :,:)./N_hscale_window; + data_out(4+pp,:,:) = sqrt( data_out( 4+pp, :,:) - data_out(3+pp,:,:).^2); data_out(5+pp,:,:) = N_hscale_window; % Toss out stats that are based on too little data - data_out([1:5]+pp,N_hscale_window Date: Tue, 19 Dec 2023 14:15:52 -0500 Subject: [PATCH 215/308] construct "ldas_obsparam" file name from user-defined inputs (Run_get_model_and_obs_clim_stats_latlon_grid.m) --- .../Run_get_model_and_obs_clim_stats_latlon_grid.m | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/Run_get_model_and_obs_clim_stats_latlon_grid.m b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/Run_get_model_and_obs_clim_stats_latlon_grid.m index 0d332e39..015f6762 100644 --- a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/Run_get_model_and_obs_clim_stats_latlon_grid.m +++ b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/Run_get_model_and_obs_clim_stats_latlon_grid.m @@ -56,9 +56,6 @@ % Define the months to run over, 1:12, plus a number of months required to complete the window run_months = [1:12 1:ceil(w_days/30)]; -obs_param_fname = [exp_path, '/', exp_run{1}, '/output/', domain, '/rc_out/', ... - '/Y2016/M04/',exp_run{1}, '.ldas_obsparam.20160401_0000z.txt']; - % ------------------------------------------------------------------- % End user-defined inputs % ------------------------------------------------------------------- @@ -87,6 +84,14 @@ end end +% assume "ldas_obsparam" file is available at 0z on first day of start_month/start_year + +YYYY = num2str( start_year, '%4.4d' ); +MM = num2str( start_month, '%2.2d' ); + +obs_param_fname = [exp_path, '/', exp_run{1}, '/output/', domain, '/rc_out/Y', YYYY, ... + '/M', MM, '/',exp_run{1}, '.ldas_obsparam.', YYYY, MM, '01_0000z.txt']; + [N_obs_param, obs_param ] = read_obsparam(obs_param_fname); species =[]; From 565c8682e3c1aead0dfc7263e89eee4110336138 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Fri, 22 Dec 2023 13:56:29 -0500 Subject: [PATCH 216/308] fix bad no-data check (get_model_and_obs_clim_stats*.m) --- .../inputs/obs_scaling_params/get_model_and_obs_clim_stats.m | 5 ++--- .../get_model_and_obs_clim_stats_latlon_grid.m | 5 +++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats.m b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats.m index 9d0a7ebb..8d8b242e 100644 --- a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats.m +++ b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats.m @@ -419,10 +419,9 @@ ] = ... read_ObsFcstAna( fname ); - % remove tiles when there is no obs_fcst (obs_fcst == 0 in innov output when - % missing) + % remove tiles where obs_fcst is no-data (note: read_ObsFcstAna() returns NaN) - idx = find(obs_fcst == 0); + idx = isnan(obs_fcst); obs_assim( idx) = []; obs_species(idx) = []; diff --git a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats_latlon_grid.m b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats_latlon_grid.m index 0ff0e534..1d3a0c74 100644 --- a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats_latlon_grid.m +++ b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats_latlon_grid.m @@ -157,8 +157,9 @@ fclose(ifp); [date_time, obs_assim, obs_species, obs_tilenum, obs_lon, obs_lat, obs_obs, obs_obsvar, obs_fcst, obs_fcstvar, obs_ana, obs_anavar] = read_ObsFcstAna(fname); - % remove tiles when there is no obs_fcst (obs_fcst == 0 in innov output when missing) - idx = find(obs_fcst == 0); + % remove tiles where obs_fcst is no-data (note: read_ObsFcstAna() returns NaN) + + idx = isnan(obs_fcst); obs_assim( idx) = []; obs_species(idx) = []; From b9dc1dfe6b1e82e972397f162884e27d36577ce1 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Fri, 22 Dec 2023 16:47:12 -0500 Subject: [PATCH 217/308] allocate(0) --- .../GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 index a65efa28..6d3bd67f 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 @@ -1906,7 +1906,7 @@ subroutine RUN ( GC, IMPORT, EXPORT, CLOCK, RC ) if(.not. allocated(mwRTM_param)) then - allocate(mwRTM_param(1)) + allocate(mwRTM_param(0)) endif From 544a119cdf58f83b37204028c97eeea77d9ce9c5 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Fri, 22 Dec 2023 16:58:24 -0700 Subject: [PATCH 218/308] remove lat lon vectors from matlab write remove lat lon vectors from read_obs remove insane sanity check --- .../write_netcdf_latlon_grid.m | 16 +-------- .../clsm_ensupd_read_obs.F90 | 34 +------------------ 2 files changed, 2 insertions(+), 48 deletions(-) diff --git a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/write_netcdf_latlon_grid.m b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/write_netcdf_latlon_grid.m index 7e64d72d..49969ad5 100644 --- a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/write_netcdf_latlon_grid.m +++ b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/write_netcdf_latlon_grid.m @@ -125,19 +125,7 @@ netcdf.putAtt(ncid, varid_end_time, 'long_name', 'end time'); netcdf.putAtt(ncid, varid_end_time, 'axis', 'T'); netcdf.putAtt(ncid, varid_end_time, 'units', 'days since 1950-01-01 00:00:00.0 +0000'); - - varid_lon = netcdf.defVar(ncid, 'lon', float_precision, [dimid_lon]); - netcdf.putAtt(ncid, varid_lon, 'standard_name', 'longitude'); - netcdf.putAtt(ncid, varid_lon, 'long_name', 'lower left longitude of gridcell'); - netcdf.putAtt(ncid, varid_lon, 'units', 'degrees_east'); - netcdf.putAtt(ncid, varid_lon, 'axis', 'X'); - - varid_lat = netcdf.defVar(ncid, 'lat', float_precision, [dimid_lat]); - netcdf.putAtt(ncid, varid_lat, 'standard_name', 'latitude'); - netcdf.putAtt(ncid, varid_lat, 'long_name', 'lower left latitude of gridcell'); - netcdf.putAtt(ncid, varid_lat, 'units', 'degrees_north'); - netcdf.putAtt(ncid, varid_lat, 'axis', 'Y'); - + varid_om = netcdf.defVar(ncid, 'o_mean', float_precision, [dimid_lat dimid_lon dimid_pentad]); netcdf.defVarDeflate(ncid,varid_om,true,true,compression_level); netcdf.putAtt(ncid, varid_om, 'standard_name', 'observation mean'); @@ -188,8 +176,6 @@ netcdf.putVar(ncid, varid_start_time, tmp_start_time); netcdf.putVar(ncid, varid_end_time, tmp_end_time); - netcdf.putVar(ncid, varid_lon, ll_lons); - netcdf.putVar(ncid, varid_lat, ll_lats); netcdf.putVar(ncid, varid_ll_lon, ll_lon); netcdf.putVar(ncid, varid_ll_lat, ll_lat); netcdf.putVar(ncid, varid_d_lon, d_lon); diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 77d9d63a..e7647e4c 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -8184,10 +8184,6 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & ! start_time:standard_name = "start time" ; ! double end_time(pentad) ; ! end_time:standard_name = "end time" ; - ! double lon(lon) ; - ! lon:standard_name = "longitude" ; - ! double lat(lat) ; - ! lat:standard_name = "latitude" ; ! double o_mean(pentad, lon, lat) ; ! o_mean:standard_name = "observation mean" ; ! double o_std(pentad, lon, lat) ; @@ -8224,12 +8220,6 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & real, intent(inout), dimension(N_catd) :: tmp_obs real, intent(inout), dimension(N_catd) :: tmp_std_obs - ! ---------------------------------------------------------- - - ! local variables - - real, parameter :: tol = 0.99 ! [degree lat/lon] for sanity check (should never kick in) - ! ------------------- character(300) :: fname @@ -8250,7 +8240,6 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & integer, dimension(:), allocatable :: sclprm_tile_id integer, dimension(:), allocatable :: pentads - real, dimension(:), allocatable :: sclprm_lon, sclprm_lat real, dimension(:,:), allocatable :: sclprm_mean_obs, sclprm_std_obs real, dimension(:,:), allocatable :: sclprm_mean_mod, sclprm_std_mod real, dimension(:,:), allocatable :: sclprm_min_mod, sclprm_max_mod @@ -8306,8 +8295,6 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & ! Get the variable IDs - ierr = nf90_inq_varid(ncid, 'lon', lon_varid) - ierr = nf90_inq_varid(ncid, 'lat', lat_varid) ierr = nf90_inq_varid(ncid, 'o_mean', o_mean_varid) ierr = nf90_inq_varid(ncid, 'o_std', o_std_varid) ierr = nf90_inq_varid(ncid, 'm_mean', m_mean_varid) @@ -8322,13 +8309,6 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & ierr = nf90_get_var(ncid, dlon_varid, dlon) ierr = nf90_get_var(ncid, dlat_varid, dlat) - ! Read lon and lat variables - - allocate(sclprm_lon(N_lon), sclprm_lat(N_lat)) - - ierr = nf90_get_var(ncid, lon_varid, sclprm_lon) - ierr = nf90_get_var(ncid, lat_varid, sclprm_lat) - start = [1, 1, pp] icount = [N_lat, N_lon, 1 ] @@ -8371,16 +8351,6 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & i_ind = ceiling((this_lon - ll_lon)/dlon) j_ind = ceiling((this_lat - ll_lat)/dlat) - ! Sanity check (against accidental use of wrong tile space) - - if ( abs(tile_coord(i)%com_lat-sclprm_lat(j_ind))>tol .or. & - abs(tile_coord(i)%com_lon-sclprm_lon(i_ind))>tol ) then - - err_msg = 'Lat/lon diff beyond tolerance' - call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) - - end if - ! Check for no-data-values in observation and fit parameters ! (any negative number could be no-data-value for observations) @@ -8421,9 +8391,7 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & end if end do - - deallocate(sclprm_lon) - deallocate(sclprm_lat) + deallocate(sclprm_mean_obs) deallocate(sclprm_std_obs) deallocate(sclprm_mean_mod) From 47503eb81950b778660c3d9deea3e7df0773ec68 Mon Sep 17 00:00:00 2001 From: Weiyuan Jiang Date: Fri, 12 Jan 2024 10:01:41 -0500 Subject: [PATCH 219/308] added openmpi flags to make it run faster on SLES15 ( it doesn't hurt on SLES12) --- src/Applications/LDAS_App/lenkf.j.template | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/Applications/LDAS_App/lenkf.j.template b/src/Applications/LDAS_App/lenkf.j.template index 11a1ddfb..4e478f8b 100644 --- a/src/Applications/LDAS_App/lenkf.j.template +++ b/src/Applications/LDAS_App/lenkf.j.template @@ -40,7 +40,23 @@ setenv argv source $GEOSBIN/g5_modules -setenv I_MPI_DAPL_UD enable +# OPENMPI flags +# Turn off warning about TMPDIR on NFS +setenv OMPI_MCA_shmem_mmap_enable_nfs_warning 0 +# pre-connect MPI procs on mpi_init +setenv OMPI_MCA_mpi_preconnect_all 1 +setenv OMPI_MCA_coll_tuned_bcast_algorithm 7 +setenv OMPI_MCA_coll_tuned_scatter_algorithm 2 +setenv OMPI_MCA_coll_tuned_reduce_scatter_algorithm 3 +setenv OMPI_MCA_coll_tuned_allreduce_algorithm 3 +setenv OMPI_MCA_coll_tuned_allgather_algorithm 4 +setenv OMPI_MCA_coll_tuned_allgatherv_algorithm 3 +setenv OMPI_MCA_coll_tuned_gather_algorithm 1 +setenv OMPI_MCA_coll_tuned_barrier_algorithm 0 +# required for a tuned flag to be effective +setenv OMPI_MCA_coll_tuned_use_dynamic_rules 1 +# disable file locks +setenv OMPI_MCA_sharedfp "^lockedfile,individual" # By default, ensure 0-diff across processor architecture by limiting MKL's freedom to pick algorithms. # As of June 2021, MKL_CBWR=AVX2 is fastest setting that works for both haswell and skylake at NCCS. From 0b981471ce0dfd01edfb76986c6772955f93eb7e Mon Sep 17 00:00:00 2001 From: Weiyuan Jiang Date: Fri, 12 Jan 2024 11:33:32 -0500 Subject: [PATCH 220/308] submit job to where it is built --- src/Applications/LDAS_App/CMakeLists.txt | 5 ++++- src/Applications/LDAS_App/ldas_setup | 15 +++++++++++++-- src/Applications/LDAS_App/lenkf.j.template | 2 ++ 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/Applications/LDAS_App/CMakeLists.txt b/src/Applications/LDAS_App/CMakeLists.txt index f2f5ed36..b3b5a4a1 100644 --- a/src/Applications/LDAS_App/CMakeLists.txt +++ b/src/Applications/LDAS_App/CMakeLists.txt @@ -20,7 +20,6 @@ ecbuild_add_executable ( LIBS GEOSlandassim_GridComp) set (scripts - ldas_setup process_hist.csh process_rst.py ens_forcing/average_ensemble_forcing.py @@ -35,6 +34,10 @@ install ( DESTINATION bin ) +set(file ldas_setup) +configure_file(${file} ${file} @ONLY) +install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/${file} DESTINATION bin) + file(GLOB rc_files GEOSldas_*rc) file(GLOB nml_files LDASsa_DEFAULT*nml) diff --git a/src/Applications/LDAS_App/ldas_setup b/src/Applications/LDAS_App/ldas_setup index f8860681..e15b8105 100755 --- a/src/Applications/LDAS_App/ldas_setup +++ b/src/Applications/LDAS_App/ldas_setup @@ -51,6 +51,13 @@ class LDASsetup: 'MINLON','MAXLON','MINLAT','MAXLAT','EXCLUDE_FILE','INCLUDE_FILE','MWRTM_PATH','GRIDNAME', 'ADAS_EXPDIR', 'BCS_RESOLUTION' ] + # if build on sles15, BUILT_ON_SLES15 is "NOYES" + BUILT_ON_SLES15 = "NO@BUILT_ON_SLES15@" + + if BUILT_ON_SLES15== "NO": + slef.BUILT_ON_SLES15 = False + else: + self.BUILT_ON_SLES15 = True # ------ # Required resource manager input fields @@ -1365,8 +1372,12 @@ class LDASsetup: elif 'MY_ADAS_EXPDIR' in line : if self.ladas_coupling > 0: fout.write(line.replace('MY_ADAS_EXPDIR', self.rqdExeInp['ADAS_EXPDIR'])) - - + elif 'MY_CONSTRAINT' in line: + if self.BUILD_ON_SLES15 : + fout.write(line.replace('MY_CONSTRAINT', 'mil')) + else: + fout.write(line.replace('MY_CONSTRAINT', '"[cas|sky]"')) + else : fout.write(line.replace('MY_EXPDIR',self.exphome+'/$EXPID')) diff --git a/src/Applications/LDAS_App/lenkf.j.template b/src/Applications/LDAS_App/lenkf.j.template index 4e478f8b..aed32135 100644 --- a/src/Applications/LDAS_App/lenkf.j.template +++ b/src/Applications/LDAS_App/lenkf.j.template @@ -15,6 +15,8 @@ #SBATCH --nodes=MY_NODES --ntasks-per-node=MY_NTASKS_PER_NODE #SBATCH --job-name=MY_JOB #SBATCH --qos=MY_QOS +#SBATCH --constraint=MY_CONSTRAINT + ####################################################################### # System Settings and Architecture Specific Environment Variables From 78f923b1f5f9b42a497edf71bedea4107bdf1b5b Mon Sep 17 00:00:00 2001 From: Weiyuan Jiang Date: Fri, 12 Jan 2024 14:17:35 -0500 Subject: [PATCH 221/308] typo fix --- src/Applications/LDAS_App/ldas_setup | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Applications/LDAS_App/ldas_setup b/src/Applications/LDAS_App/ldas_setup index e15b8105..f6f3b9a9 100755 --- a/src/Applications/LDAS_App/ldas_setup +++ b/src/Applications/LDAS_App/ldas_setup @@ -51,13 +51,13 @@ class LDASsetup: 'MINLON','MAXLON','MINLAT','MAXLAT','EXCLUDE_FILE','INCLUDE_FILE','MWRTM_PATH','GRIDNAME', 'ADAS_EXPDIR', 'BCS_RESOLUTION' ] - # if build on sles15, BUILT_ON_SLES15 is "NOYES" - BUILT_ON_SLES15 = "NO@BUILT_ON_SLES15@" + # if build on sles15, BUILT_ON_SLES15 is "TRUE", else emply "" + BUILT_ON_SLES15 = "@BUILT_ON_SLES15@" - if BUILT_ON_SLES15== "NO": - slef.BUILT_ON_SLES15 = False + if BUILT_ON_SLES15 == "TRUE": + slef.BUILT_ON_SLES15 = True else: - self.BUILT_ON_SLES15 = True + self.BUILT_ON_SLES15 = False # ------ # Required resource manager input fields @@ -1373,7 +1373,7 @@ class LDASsetup: if self.ladas_coupling > 0: fout.write(line.replace('MY_ADAS_EXPDIR', self.rqdExeInp['ADAS_EXPDIR'])) elif 'MY_CONSTRAINT' in line: - if self.BUILD_ON_SLES15 : + if self.BUILT_ON_SLES15 : fout.write(line.replace('MY_CONSTRAINT', 'mil')) else: fout.write(line.replace('MY_CONSTRAINT', '"[cas|sky]"')) From fcbcb2e90b00dd711c78f95ba091a91202606f9e Mon Sep 17 00:00:00 2001 From: Weiyuan Jiang Date: Fri, 12 Jan 2024 14:44:20 -0500 Subject: [PATCH 222/308] more typo fix --- src/Applications/LDAS_App/ldas_setup | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Applications/LDAS_App/ldas_setup b/src/Applications/LDAS_App/ldas_setup index f6f3b9a9..c39bbffb 100755 --- a/src/Applications/LDAS_App/ldas_setup +++ b/src/Applications/LDAS_App/ldas_setup @@ -55,7 +55,7 @@ class LDASsetup: BUILT_ON_SLES15 = "@BUILT_ON_SLES15@" if BUILT_ON_SLES15 == "TRUE": - slef.BUILT_ON_SLES15 = True + self.BUILT_ON_SLES15 = True else: self.BUILT_ON_SLES15 = False @@ -700,7 +700,11 @@ class LDASsetup: print ('\nCorrect the tile file if it is an old EASE tile format... \n') EASEtile=self.bcsdir+'/MAPL_'+short_tile cmd = './preprocess_ldas.x correctease '+ tile + ' '+ EASEtile - print ("cmd: " + cmd) + if self.BUILT_ON_SLES15 : + print ("Executables are built on SLES15 and should be run on SLES15: " + cmd) + else: + print ("cmd: " + cmd) + sp.call(shlex.split(cmd)) if os.path.isfile(EASEtile) : From 8c28f2a8c84fffa97421d6f8112a75c28b0e1453 Mon Sep 17 00:00:00 2001 From: Weiyuan Jiang Date: Wed, 17 Jan 2024 14:12:17 -0500 Subject: [PATCH 223/308] add constraint based on BUILT_ON_SLES15 --- src/Applications/LDAS_App/ldas_setup | 15 +++++++-------- src/Applications/LDAS_App/lenkf.j.template | 2 -- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/Applications/LDAS_App/ldas_setup b/src/Applications/LDAS_App/ldas_setup index c39bbffb..e4262a9d 100755 --- a/src/Applications/LDAS_App/ldas_setup +++ b/src/Applications/LDAS_App/ldas_setup @@ -1344,8 +1344,13 @@ class LDASsetup: elif 'MY_NODES' in line : line_ = line.replace('MY_NODES',str(self.optRmInp['nodes'])) fout.write(line_.replace('MY_NTASKS_PER_NODE',str(self.rqdRmInp['ntasks-per-node']))) - if int(self.rqdRmInp['ntasks-per-node']) > 40: - fout.write("#SBATCH --constraint=cas\n") + + if self.BUILT_ON_SLES15 : + fout.write("#SBATCH --constraint=mil\n") + else: + assert int(self.rqdRmInp['ntasks-per-node']) <= 46, 'ntasks-per-node should be smaller than 46 for cas' + fout.write("#SBATCH --constraint=cas\n") + elif 'MY_OSERVER_NODES' in line : fout.write(line.replace('MY_OSERVER_NODES',str(self.optRmInp['oserver_nodes']))) elif 'MY_WRITERS_NPES' in line : @@ -1376,12 +1381,6 @@ class LDASsetup: elif 'MY_ADAS_EXPDIR' in line : if self.ladas_coupling > 0: fout.write(line.replace('MY_ADAS_EXPDIR', self.rqdExeInp['ADAS_EXPDIR'])) - elif 'MY_CONSTRAINT' in line: - if self.BUILT_ON_SLES15 : - fout.write(line.replace('MY_CONSTRAINT', 'mil')) - else: - fout.write(line.replace('MY_CONSTRAINT', '"[cas|sky]"')) - else : fout.write(line.replace('MY_EXPDIR',self.exphome+'/$EXPID')) diff --git a/src/Applications/LDAS_App/lenkf.j.template b/src/Applications/LDAS_App/lenkf.j.template index aed32135..4e478f8b 100644 --- a/src/Applications/LDAS_App/lenkf.j.template +++ b/src/Applications/LDAS_App/lenkf.j.template @@ -15,8 +15,6 @@ #SBATCH --nodes=MY_NODES --ntasks-per-node=MY_NTASKS_PER_NODE #SBATCH --job-name=MY_JOB #SBATCH --qos=MY_QOS -#SBATCH --constraint=MY_CONSTRAINT - ####################################################################### # System Settings and Architecture Specific Environment Variables From c1e0cc50dcc7c0d62452e166a379c938baea72be Mon Sep 17 00:00:00 2001 From: Rolf Reichle <54944691+gmao-rreichle@users.noreply.github.com> Date: Wed, 17 Jan 2024 14:39:06 -0500 Subject: [PATCH 224/308] minor edits of SLES15 comments (ldas_setup) --- src/Applications/LDAS_App/ldas_setup | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Applications/LDAS_App/ldas_setup b/src/Applications/LDAS_App/ldas_setup index e4262a9d..12a72d27 100755 --- a/src/Applications/LDAS_App/ldas_setup +++ b/src/Applications/LDAS_App/ldas_setup @@ -51,7 +51,7 @@ class LDASsetup: 'MINLON','MAXLON','MINLAT','MAXLAT','EXCLUDE_FILE','INCLUDE_FILE','MWRTM_PATH','GRIDNAME', 'ADAS_EXPDIR', 'BCS_RESOLUTION' ] - # if build on sles15, BUILT_ON_SLES15 is "TRUE", else emply "" + # if built on sles15, BUILT_ON_SLES15 is "TRUE", else empty "" BUILT_ON_SLES15 = "@BUILT_ON_SLES15@" if BUILT_ON_SLES15 == "TRUE": @@ -701,7 +701,7 @@ class LDASsetup: EASEtile=self.bcsdir+'/MAPL_'+short_tile cmd = './preprocess_ldas.x correctease '+ tile + ' '+ EASEtile if self.BUILT_ON_SLES15 : - print ("Executables are built on SLES15 and should be run on SLES15: " + cmd) + print ("Executables were built on SLES15 and must be run on SLES15: " + cmd) else: print ("cmd: " + cmd) @@ -1348,7 +1348,7 @@ class LDASsetup: if self.BUILT_ON_SLES15 : fout.write("#SBATCH --constraint=mil\n") else: - assert int(self.rqdRmInp['ntasks-per-node']) <= 46, 'ntasks-per-node should be smaller than 46 for cas' + assert int(self.rqdRmInp['ntasks-per-node']) <= 46, 'ntasks-per-node should be <=46 for cas' fout.write("#SBATCH --constraint=cas\n") elif 'MY_OSERVER_NODES' in line : From 87079d78aa151cf916d4141b8451cd7f048fff85 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Sat, 20 Jan 2024 13:06:05 -0500 Subject: [PATCH 225/308] updated README.md for use of Milan nodes (SLES15) at NCCS --- README.md | 43 +++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 5b81ce44..84ca1cf8 100644 --- a/README.md +++ b/README.md @@ -13,18 +13,20 @@ module use -a (path) module load GEOSenv ``` -where `(path)` depends on the computer and operating system: +where `(path)` depends on the computing system; at NCCS, `(path)` also depends on the operating system (SLES12 on Skylake and Cascade Lake nodes; SLES15 on Milan nodes, as of Jan. 2024): | System | Path | | ------------- |---------------------------------------------------| -| NCCS | `/discover/swdev/gmao_SIteam/modulefiles-SLES12` | +| NCCS Discover | `/discover/swdev/gmao_SIteam/modulefiles-SLES12` | +| | `/discover/swdev/gmao_SIteam/modulefiles-SLES15` | | NAS | `/nobackup/gmao_SIteam/modulefiles` | | GMAO desktops | `/ford1/share/gmao_SIteam/modulefiles` | +Step 1 can be coded into the user's shell configuration file (e.g., `.bashrc` or `.cshrc`). See the [GEOSgcm Wiki](https://github.com/GEOS-ESM/GEOSgcm/wiki/) for sample shell configuration files. ### Step 2: Obtain the Model -For development work, clone the _entire_ repository and use the `develop` branch as your starting point (equivalent to the `UNSTABLE` tag in the old CVS repository): +For development work, clone the _entire_ repository and use the `develop` branch as your starting point: ``` git clone -b develop git@github.com:GEOS-ESM/GEOSldas.git ``` @@ -36,25 +38,32 @@ git clone -b v17.9.1 --single-branch git@github.com:GEOS-ESM/GEOSldas.git ### Step 3: Build the Model -To build the model in a single step, do the following: +To build the model in a single step, do the following from a head node: ``` cd ./GEOSldas parallel_build.csh ``` -from a head node. Doing so will check out all the external repositories of the model (albeit only on the first run, [see subsection on mepo below](#mepo)!) and build the model. When done, the resulting model build will be found in `build-SLES12/` and the installation will be found in `install-SLES12/`, with setup scripts like `ldas_setup` in `install-SLES12/bin`. +This checks out all the external repositories of the model (albeit only on the first run, [see subsection on mepo below](#mepo)!) and then builds and installs the model. -To obtain a build that is suitable for debugging, use `parallel_build.csh -debug`, which will build in `build-Debug-SLES12/` and install in `install-Debug-SLES12/`. There is also an option for aggressive optimization. For details, see [GEOSldas Wiki](https://github.com/GEOS-ESM/GEOSldas/wiki). +At **NCCS**, the default is to build GEOSldas on SLES12 (Skylake or Cascade Lake nodes); to build GEOSldas on SLES15 (Milan nodes), use `parallel_build.csh -mil`. -See below for how to build the model in multiple steps. +The resulting model build is found in `build[-SLESxx]/`, and the installation is found in `install[-SLESxx]/`, with setup scripts like `ldas_setup` in `install[-SLESxx]/bin`. + +To obtain a build that is suitable for debugging, use `parallel_build.csh -debug`, which builds in `build-Debug[-SLESxx]/` and installs in `install-Debug[-SLESxx]/`. There is also an option for aggressive optimization. For details, see the [GEOSldas Wiki](https://github.com/GEOS-ESM/GEOSldas/wiki). + +Instructions for building the model in multiple steps are provided below. --- ## How to Set Up (Configure) and Run GEOSldas -a) Set up the job as follows: + +a) At **NCCS**, GEOSldas must be built, configured, and run on the same operating system. To run GEOSldas on Milan nodes (SLES15), start with `ssh discover-mil`. + +b) Set up the job as follows: ``` -cd (build_path)/GEOSldas/install/bin +cd (build_path)/GEOSldas/install[-SLESxx]/bin source g5_modules [for bash or zsh: source g5_modules.[z]sh] ./ldas_setup setup [-v] (exp_path) ("exe"_input_filename) ("bat"_input_filename) ``` @@ -82,7 +91,7 @@ Edit these sample files following the examples and comments within the sample fi The ldas_setup script creates a run directory and other directories at: `[exp_path]/[exp_name]` -Configuration input files will be created at: +Configuration input files are created at: `[exp_path]/[exp_name]/run` For more options and documentation, use any of the following: @@ -92,16 +101,19 @@ ldas_setup sample -h ldas_setup setup -h ``` -b) Configure the experiment output by editing the ```./run/HISTORY.rc``` file as needed. +c) Configure the experiment output by editing the ```./run/HISTORY.rc``` file as needed. -c) Run the job: +d) Run the job: ``` cd [exp_path]/[exp_name]/run/ sbatch lenkf.j ``` -For more information, see the files in `./doc/`. -Moreover, descriptions of the configuration (resource) parameters are included in the sample "exeinp" and "batinp" files that can be generated using `ldas_setup`. +At **NCCS**, the appropriate SLURM directive `#SBATCH --constraint=[xxx]` is automatically added into `lenkf.j` depending on the operating system. + +For more information, see the files in `./doc/`. Moreover, descriptions of the configuration (resource) parameters are included in the sample "exeinp" and "batinp" files that can be generated using `ldas_setup`. + + ----------------------------------------------------------------------------------- @@ -138,7 +150,6 @@ We currently do not allow in-source builds of GEOSldas. So we must make a direct ``` mkdir build ``` -The advantages of this is that you can build both a Debug and Release version with the same clone if desired. #### Run CMake CMake generates the Makefiles needed to build the model. @@ -146,7 +157,7 @@ CMake generates the Makefiles needed to build the model. cd build cmake .. -DBASEDIR=$BASEDIR/Linux -DCMAKE_Fortran_COMPILER=ifort -DCMAKE_INSTALL_PREFIX=../install ``` -This will install to a directory parallel to your `build` directory. If you prefer to install elsewhere change the path in: +This installs into a directory parallel to your `build` directory. If you prefer to install elsewhere change the path in: ``` -DCMAKE_INSTALL_PREFIX= ``` From 729a3fa73acfba7bba981f6be2fdb2ff27b0786d Mon Sep 17 00:00:00 2001 From: Matthew Thompson Date: Fri, 26 Jan 2024 08:26:28 -0500 Subject: [PATCH 226/308] Update CircleCI to use Orb v2 This PR updates the CircleCI config the v2 orb. This has updated needed for changes in GEOSgcm_App and Baselibs --- .circleci/config.yml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 23de0f65..cb24b2ed 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,14 +1,16 @@ version: 2.1 -# Anchor to prevent forgetting to update a version -baselibs_version: &baselibs_version v7.16.0 +# Anchors in case we need to override the defaults from the orb +#baselibs_version: &baselibs_version v7.17.0 +#bcs_version: &bcs_version v11.4.0 orbs: - ci: geos-esm/circleci-tools@1 + ci: geos-esm/circleci-tools@2 workflows: build-test: jobs: + # Build GEOSldas - ci/build: name: build-GEOSldas-on-<< matrix.compiler >> context: @@ -16,7 +18,7 @@ workflows: matrix: parameters: compiler: [ifort, gfortran] - baselibs_version: *baselibs_version + #baselibs_version: *baselibs_version repo: GEOSldas mepodevelop: false persist_workspace: false # Needs to be true to run fv3/gcm experiment, costs extra From e883a23efb4200374d570e2916c9fb5a0b466843 Mon Sep 17 00:00:00 2001 From: Biljana Orescanin <68251545+biljanaorescanin@users.noreply.github.com> Date: Wed, 31 Jan 2024 13:18:22 -0500 Subject: [PATCH 227/308] generic nco --- src/Applications/LDAS_App/lenkf.j.template | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Applications/LDAS_App/lenkf.j.template b/src/Applications/LDAS_App/lenkf.j.template index 4e478f8b..5113b5e4 100644 --- a/src/Applications/LDAS_App/lenkf.j.template +++ b/src/Applications/LDAS_App/lenkf.j.template @@ -70,7 +70,7 @@ setenv MKL_CBWR "AVX2" setenv LD_LIBRARY_PATH ${BASEDIR}/${ARCH}/lib:${ESMADIR}/lib:${LD_LIBRARY_PATH} if ( -e /etc/os-release ) then - module load nco/4.8.1 + module load nco else module load other/nco-4.6.8-gcc-5.3-sp3 endif From d82e82c26ab32704617369e51a20b06421f32851 Mon Sep 17 00:00:00 2001 From: Biljana Orescanin <68251545+biljanaorescanin@users.noreply.github.com> Date: Wed, 31 Jan 2024 13:26:24 -0500 Subject: [PATCH 228/308] remove obsolete if --- src/Applications/LDAS_App/lenkf.j.template | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/Applications/LDAS_App/lenkf.j.template b/src/Applications/LDAS_App/lenkf.j.template index 5113b5e4..6f77c5c2 100644 --- a/src/Applications/LDAS_App/lenkf.j.template +++ b/src/Applications/LDAS_App/lenkf.j.template @@ -69,11 +69,8 @@ setenv MKL_CBWR "AVX2" # reversed sequence for LADAS_COUPLING (Sep 2020) (needed when coupling with ADAS using different BASEDIR) setenv LD_LIBRARY_PATH ${BASEDIR}/${ARCH}/lib:${ESMADIR}/lib:${LD_LIBRARY_PATH} -if ( -e /etc/os-release ) then - module load nco -else - module load other/nco-4.6.8-gcc-5.3-sp3 -endif +module load nco + setenv RUN_CMD "$GEOSBIN/esma_mpirun -np " ####################################################################### From f75033b064f1ecdebeb6504531c74c8993e18bc8 Mon Sep 17 00:00:00 2001 From: saraqzhang Date: Thu, 1 Feb 2024 15:04:19 -0500 Subject: [PATCH 229/308] update generate_catchincr_hist.py and LADAS example documents in LDAS_App/ --- .../LADAS/HISTORY.rc.atmens | 1662 ++++++++--------- .../LADAS/exeinp.txt.Hy4dEnVar.central | 2 +- .../util/config/generate_catchincr_hist.py | 87 +- 3 files changed, 850 insertions(+), 901 deletions(-) diff --git a/src/Applications/LDAS_App/sample_config_files/LADAS/HISTORY.rc.atmens b/src/Applications/LDAS_App/sample_config_files/LADAS/HISTORY.rc.atmens index 8a21db30..62f3d1ac 100644 --- a/src/Applications/LDAS_App/sample_config_files/LADAS/HISTORY.rc.atmens +++ b/src/Applications/LDAS_App/sample_config_files/LADAS/HISTORY.rc.atmens @@ -1,3 +1,4 @@ + # # Sample GEOSldas HISTORY.rc file for LADAS (atm ensemble) # @@ -8,18 +9,14 @@ # with the utility script "generate_catchincr_hist.py", with the number of # ensemble members and their indexing matching those of the atmospheric # ensemble component of the Hy4dEnVar ADAS. -# (2) The "catch_progn_incr" output is in tile space. Its definition is generic +# (2) The "catch_progn_incr" output is in tile space. Its definition is generic # for any LADAS resolution. -# (3) The resolution of the "lndfcstana" output should be adjusted to match that -# of the LADAS. # ################################################################################## -VERSION: 1 -EXPID: MyGEOSldasAtmEns +EXPID: MyGEOSldasAtmEns COLLECTIONS: -'inst3_2d_lndfcstana_Nx' 'catch_progn_incr0001' 'catch_progn_incr0002' 'catch_progn_incr0003' @@ -53,88 +50,36 @@ COLLECTIONS: 'catch_progn_incr0031' 'catch_progn_incr0032' -:: -GRID_LABELS: PC720x361-DC - PC576x361-DC - PC288x181-DC -:: - -PC720x361-DC.GRID_TYPE: LatLon -PC720x361-DC.IM_WORLD: 720 -PC720x361-DC.JM_WORLD: 361 -PC720x361-DC.POLE: PC -PC720x361-DC.DATELINE: DC -PC720x361-DC.LM: 1 - -PC576x361-DC.GRID_TYPE: LatLon -PC576x361-DC.IM_WORLD: 576 -PC576x361-DC.JM_WORLD: 361 -PC576x361-DC.POLE: PC -PC576x361-DC.DATELINE: DC -PC576x361-DC.LM: 1 - -PC288x181-DC.GRID_TYPE: LatLon -PC288x181-DC.IM_WORLD: 288 -PC288x181-DC.JM_WORLD: 181 -PC288x181-DC.POLE: PC -PC288x181-DC.DATELINE: DC -PC288x181-DC.LM: 1 - - -inst3_2d_lndfcstana_Nx.descr: '2d,3-Hourly,Instantaneous,Single-Level,Assimilation,Ensemble-average Land Forecast and Analysis Diagnostics', -inst3_2d_lndfcstana_Nx.template: '%y4%m2%d2_%h2%n2z.nc4', -inst3_2d_lndfcstana_Nx.mode: 'instantaneous', -inst3_2d_lndfcstana_Nx.frequency: 030000, -inst3_2d_lndfcstana_Nx.ref_time: 013000, -inst3_2d_lndfcstana_Nx.format: 'CFIO', -inst3_2d_lndfcstana_Nx.regrid_exch: '../input/tile.data', -inst3_2d_lndfcstana_Nx.regrid_name: 'PE90x540-CF', -inst3_2d_lndfcstana_Nx.grid_label: PC288x181-DC, -inst3_2d_lndfcstana_Nx.deflate: 2, -inst3_2d_lndfcstana_Nx.fields: 'WCSF' , 'ENSAVG' , 'SFMC_FCST' , - 'WCRZ' , 'ENSAVG' , 'RZMC_FCST' , - 'WCPR' , 'ENSAVG' , 'PRMC_FCST' , - 'TPSURF' , 'ENSAVG' , 'TSURF_FCST' , - 'TSOIL1TILE' , 'ENSAVG' , 'TSOIL1_FCST' , - 'WCSF_ANA' , 'LANDASSIM' , 'SFMC_ANA' , - 'WCRZ_ANA' , 'LANDASSIM' , 'RZMC_ANA' , - 'WCPR_ANA' , 'LANDASSIM' , 'PRMC_ANA' , - 'TPSURF_ANA' , 'LANDASSIM' , 'TSURF_ANA' , - 'TSOIL1_ANA' , 'LANDASSIM' , 'TSOIL1_ANA' , - :: - - - catch_progn_incr0001.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', catch_progn_incr0001.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0001.mode: 'instantaneous', catch_progn_incr0001.frequency: 030000, catch_progn_incr0001.ref_time: 013000, -catch_progn_incr0001.fields: 'TCFSAT_INCR' , 'CATCHINCR0001' , - 'TCFTRN_INCR' , 'CATCHINCR0001' , - 'TCFWLT_INCR' , 'CATCHINCR0001' , - 'QCFSAT_INCR' , 'CATCHINCR0001' , - 'QCFTRN_INCR' , 'CATCHINCR0001' , - 'QCFWLT_INCR' , 'CATCHINCR0001' , - 'CAPAC_INCR' , 'CATCHINCR0001' , - 'CATDEF_INCR' , 'CATCHINCR0001' , - 'RZEXC_INCR' , 'CATCHINCR0001' , - 'SRFEXC_INCR' , 'CATCHINCR0001' , - 'GHTCNT1_INCR' , 'CATCHINCR0001' , - 'GHTCNT2_INCR' , 'CATCHINCR0001' , - 'GHTCNT3_INCR' , 'CATCHINCR0001' , - 'GHTCNT4_INCR' , 'CATCHINCR0001' , - 'GHTCNT5_INCR' , 'CATCHINCR0001' , - 'GHTCNT6_INCR' , 'CATCHINCR0001' , - 'WESNN1_INCR' , 'CATCHINCR0001' , - 'WESNN2_INCR' , 'CATCHINCR0001' , - 'WESNN3_INCR' , 'CATCHINCR0001' , - 'HTSNNN1_INCR' , 'CATCHINCR0001' , - 'HTSNNN2_INCR' , 'CATCHINCR0001' , - 'HTSNNN3_INCR' , 'CATCHINCR0001' , - 'SNDZN1_INCR' , 'CATCHINCR0001' , - 'SNDZN2_INCR' , 'CATCHINCR0001' , - 'SNDZN3_INCR' , 'CATCHINCR0001' , +catch_progn_incr0001.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0001' , + 'TCFTRN_INCR' , 'CATCHINCR_e0001' , + 'TCFWLT_INCR' , 'CATCHINCR_e0001' , + 'QCFSAT_INCR' , 'CATCHINCR_e0001' , + 'QCFTRN_INCR' , 'CATCHINCR_e0001' , + 'QCFWLT_INCR' , 'CATCHINCR_e0001' , + 'CAPAC_INCR' , 'CATCHINCR_e0001' , + 'CATDEF_INCR' , 'CATCHINCR_e0001' , + 'RZEXC_INCR' , 'CATCHINCR_e0001' , + 'SRFEXC_INCR' , 'CATCHINCR_e0001' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0001' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0001' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0001' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0001' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0001' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0001' , + 'WESNN1_INCR' , 'CATCHINCR_e0001' , + 'WESNN2_INCR' , 'CATCHINCR_e0001' , + 'WESNN3_INCR' , 'CATCHINCR_e0001' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0001' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0001' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0001' , + 'SNDZN1_INCR' , 'CATCHINCR_e0001' , + 'SNDZN2_INCR' , 'CATCHINCR_e0001' , + 'SNDZN3_INCR' , 'CATCHINCR_e0001' , :: catch_progn_incr0002.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -142,31 +87,31 @@ catch_progn_incr0002.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0002.mode: 'instantaneous', catch_progn_incr0002.frequency: 030000, catch_progn_incr0002.ref_time: 013000, -catch_progn_incr0002.fields: 'TCFSAT_INCR' , 'CATCHINCR0002' , - 'TCFTRN_INCR' , 'CATCHINCR0002' , - 'TCFWLT_INCR' , 'CATCHINCR0002' , - 'QCFSAT_INCR' , 'CATCHINCR0002' , - 'QCFTRN_INCR' , 'CATCHINCR0002' , - 'QCFWLT_INCR' , 'CATCHINCR0002' , - 'CAPAC_INCR' , 'CATCHINCR0002' , - 'CATDEF_INCR' , 'CATCHINCR0002' , - 'RZEXC_INCR' , 'CATCHINCR0002' , - 'SRFEXC_INCR' , 'CATCHINCR0002' , - 'GHTCNT1_INCR' , 'CATCHINCR0002' , - 'GHTCNT2_INCR' , 'CATCHINCR0002' , - 'GHTCNT3_INCR' , 'CATCHINCR0002' , - 'GHTCNT4_INCR' , 'CATCHINCR0002' , - 'GHTCNT5_INCR' , 'CATCHINCR0002' , - 'GHTCNT6_INCR' , 'CATCHINCR0002' , - 'WESNN1_INCR' , 'CATCHINCR0002' , - 'WESNN2_INCR' , 'CATCHINCR0002' , - 'WESNN3_INCR' , 'CATCHINCR0002' , - 'HTSNNN1_INCR' , 'CATCHINCR0002' , - 'HTSNNN2_INCR' , 'CATCHINCR0002' , - 'HTSNNN3_INCR' , 'CATCHINCR0002' , - 'SNDZN1_INCR' , 'CATCHINCR0002' , - 'SNDZN2_INCR' , 'CATCHINCR0002' , - 'SNDZN3_INCR' , 'CATCHINCR0002' , +catch_progn_incr0002.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0002' , + 'TCFTRN_INCR' , 'CATCHINCR_e0002' , + 'TCFWLT_INCR' , 'CATCHINCR_e0002' , + 'QCFSAT_INCR' , 'CATCHINCR_e0002' , + 'QCFTRN_INCR' , 'CATCHINCR_e0002' , + 'QCFWLT_INCR' , 'CATCHINCR_e0002' , + 'CAPAC_INCR' , 'CATCHINCR_e0002' , + 'CATDEF_INCR' , 'CATCHINCR_e0002' , + 'RZEXC_INCR' , 'CATCHINCR_e0002' , + 'SRFEXC_INCR' , 'CATCHINCR_e0002' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0002' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0002' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0002' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0002' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0002' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0002' , + 'WESNN1_INCR' , 'CATCHINCR_e0002' , + 'WESNN2_INCR' , 'CATCHINCR_e0002' , + 'WESNN3_INCR' , 'CATCHINCR_e0002' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0002' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0002' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0002' , + 'SNDZN1_INCR' , 'CATCHINCR_e0002' , + 'SNDZN2_INCR' , 'CATCHINCR_e0002' , + 'SNDZN3_INCR' , 'CATCHINCR_e0002' , :: catch_progn_incr0003.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -174,31 +119,31 @@ catch_progn_incr0003.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0003.mode: 'instantaneous', catch_progn_incr0003.frequency: 030000, catch_progn_incr0003.ref_time: 013000, -catch_progn_incr0003.fields: 'TCFSAT_INCR' , 'CATCHINCR0003' , - 'TCFTRN_INCR' , 'CATCHINCR0003' , - 'TCFWLT_INCR' , 'CATCHINCR0003' , - 'QCFSAT_INCR' , 'CATCHINCR0003' , - 'QCFTRN_INCR' , 'CATCHINCR0003' , - 'QCFWLT_INCR' , 'CATCHINCR0003' , - 'CAPAC_INCR' , 'CATCHINCR0003' , - 'CATDEF_INCR' , 'CATCHINCR0003' , - 'RZEXC_INCR' , 'CATCHINCR0003' , - 'SRFEXC_INCR' , 'CATCHINCR0003' , - 'GHTCNT1_INCR' , 'CATCHINCR0003' , - 'GHTCNT2_INCR' , 'CATCHINCR0003' , - 'GHTCNT3_INCR' , 'CATCHINCR0003' , - 'GHTCNT4_INCR' , 'CATCHINCR0003' , - 'GHTCNT5_INCR' , 'CATCHINCR0003' , - 'GHTCNT6_INCR' , 'CATCHINCR0003' , - 'WESNN1_INCR' , 'CATCHINCR0003' , - 'WESNN2_INCR' , 'CATCHINCR0003' , - 'WESNN3_INCR' , 'CATCHINCR0003' , - 'HTSNNN1_INCR' , 'CATCHINCR0003' , - 'HTSNNN2_INCR' , 'CATCHINCR0003' , - 'HTSNNN3_INCR' , 'CATCHINCR0003' , - 'SNDZN1_INCR' , 'CATCHINCR0003' , - 'SNDZN2_INCR' , 'CATCHINCR0003' , - 'SNDZN3_INCR' , 'CATCHINCR0003' , +catch_progn_incr0003.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0003' , + 'TCFTRN_INCR' , 'CATCHINCR_e0003' , + 'TCFWLT_INCR' , 'CATCHINCR_e0003' , + 'QCFSAT_INCR' , 'CATCHINCR_e0003' , + 'QCFTRN_INCR' , 'CATCHINCR_e0003' , + 'QCFWLT_INCR' , 'CATCHINCR_e0003' , + 'CAPAC_INCR' , 'CATCHINCR_e0003' , + 'CATDEF_INCR' , 'CATCHINCR_e0003' , + 'RZEXC_INCR' , 'CATCHINCR_e0003' , + 'SRFEXC_INCR' , 'CATCHINCR_e0003' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0003' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0003' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0003' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0003' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0003' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0003' , + 'WESNN1_INCR' , 'CATCHINCR_e0003' , + 'WESNN2_INCR' , 'CATCHINCR_e0003' , + 'WESNN3_INCR' , 'CATCHINCR_e0003' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0003' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0003' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0003' , + 'SNDZN1_INCR' , 'CATCHINCR_e0003' , + 'SNDZN2_INCR' , 'CATCHINCR_e0003' , + 'SNDZN3_INCR' , 'CATCHINCR_e0003' , :: catch_progn_incr0004.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -206,31 +151,31 @@ catch_progn_incr0004.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0004.mode: 'instantaneous', catch_progn_incr0004.frequency: 030000, catch_progn_incr0004.ref_time: 013000, -catch_progn_incr0004.fields: 'TCFSAT_INCR' , 'CATCHINCR0004' , - 'TCFTRN_INCR' , 'CATCHINCR0004' , - 'TCFWLT_INCR' , 'CATCHINCR0004' , - 'QCFSAT_INCR' , 'CATCHINCR0004' , - 'QCFTRN_INCR' , 'CATCHINCR0004' , - 'QCFWLT_INCR' , 'CATCHINCR0004' , - 'CAPAC_INCR' , 'CATCHINCR0004' , - 'CATDEF_INCR' , 'CATCHINCR0004' , - 'RZEXC_INCR' , 'CATCHINCR0004' , - 'SRFEXC_INCR' , 'CATCHINCR0004' , - 'GHTCNT1_INCR' , 'CATCHINCR0004' , - 'GHTCNT2_INCR' , 'CATCHINCR0004' , - 'GHTCNT3_INCR' , 'CATCHINCR0004' , - 'GHTCNT4_INCR' , 'CATCHINCR0004' , - 'GHTCNT5_INCR' , 'CATCHINCR0004' , - 'GHTCNT6_INCR' , 'CATCHINCR0004' , - 'WESNN1_INCR' , 'CATCHINCR0004' , - 'WESNN2_INCR' , 'CATCHINCR0004' , - 'WESNN3_INCR' , 'CATCHINCR0004' , - 'HTSNNN1_INCR' , 'CATCHINCR0004' , - 'HTSNNN2_INCR' , 'CATCHINCR0004' , - 'HTSNNN3_INCR' , 'CATCHINCR0004' , - 'SNDZN1_INCR' , 'CATCHINCR0004' , - 'SNDZN2_INCR' , 'CATCHINCR0004' , - 'SNDZN3_INCR' , 'CATCHINCR0004' , +catch_progn_incr0004.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0004' , + 'TCFTRN_INCR' , 'CATCHINCR_e0004' , + 'TCFWLT_INCR' , 'CATCHINCR_e0004' , + 'QCFSAT_INCR' , 'CATCHINCR_e0004' , + 'QCFTRN_INCR' , 'CATCHINCR_e0004' , + 'QCFWLT_INCR' , 'CATCHINCR_e0004' , + 'CAPAC_INCR' , 'CATCHINCR_e0004' , + 'CATDEF_INCR' , 'CATCHINCR_e0004' , + 'RZEXC_INCR' , 'CATCHINCR_e0004' , + 'SRFEXC_INCR' , 'CATCHINCR_e0004' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0004' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0004' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0004' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0004' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0004' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0004' , + 'WESNN1_INCR' , 'CATCHINCR_e0004' , + 'WESNN2_INCR' , 'CATCHINCR_e0004' , + 'WESNN3_INCR' , 'CATCHINCR_e0004' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0004' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0004' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0004' , + 'SNDZN1_INCR' , 'CATCHINCR_e0004' , + 'SNDZN2_INCR' , 'CATCHINCR_e0004' , + 'SNDZN3_INCR' , 'CATCHINCR_e0004' , :: catch_progn_incr0005.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -238,31 +183,31 @@ catch_progn_incr0005.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0005.mode: 'instantaneous', catch_progn_incr0005.frequency: 030000, catch_progn_incr0005.ref_time: 013000, -catch_progn_incr0005.fields: 'TCFSAT_INCR' , 'CATCHINCR0005' , - 'TCFTRN_INCR' , 'CATCHINCR0005' , - 'TCFWLT_INCR' , 'CATCHINCR0005' , - 'QCFSAT_INCR' , 'CATCHINCR0005' , - 'QCFTRN_INCR' , 'CATCHINCR0005' , - 'QCFWLT_INCR' , 'CATCHINCR0005' , - 'CAPAC_INCR' , 'CATCHINCR0005' , - 'CATDEF_INCR' , 'CATCHINCR0005' , - 'RZEXC_INCR' , 'CATCHINCR0005' , - 'SRFEXC_INCR' , 'CATCHINCR0005' , - 'GHTCNT1_INCR' , 'CATCHINCR0005' , - 'GHTCNT2_INCR' , 'CATCHINCR0005' , - 'GHTCNT3_INCR' , 'CATCHINCR0005' , - 'GHTCNT4_INCR' , 'CATCHINCR0005' , - 'GHTCNT5_INCR' , 'CATCHINCR0005' , - 'GHTCNT6_INCR' , 'CATCHINCR0005' , - 'WESNN1_INCR' , 'CATCHINCR0005' , - 'WESNN2_INCR' , 'CATCHINCR0005' , - 'WESNN3_INCR' , 'CATCHINCR0005' , - 'HTSNNN1_INCR' , 'CATCHINCR0005' , - 'HTSNNN2_INCR' , 'CATCHINCR0005' , - 'HTSNNN3_INCR' , 'CATCHINCR0005' , - 'SNDZN1_INCR' , 'CATCHINCR0005' , - 'SNDZN2_INCR' , 'CATCHINCR0005' , - 'SNDZN3_INCR' , 'CATCHINCR0005' , +catch_progn_incr0005.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0005' , + 'TCFTRN_INCR' , 'CATCHINCR_e0005' , + 'TCFWLT_INCR' , 'CATCHINCR_e0005' , + 'QCFSAT_INCR' , 'CATCHINCR_e0005' , + 'QCFTRN_INCR' , 'CATCHINCR_e0005' , + 'QCFWLT_INCR' , 'CATCHINCR_e0005' , + 'CAPAC_INCR' , 'CATCHINCR_e0005' , + 'CATDEF_INCR' , 'CATCHINCR_e0005' , + 'RZEXC_INCR' , 'CATCHINCR_e0005' , + 'SRFEXC_INCR' , 'CATCHINCR_e0005' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0005' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0005' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0005' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0005' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0005' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0005' , + 'WESNN1_INCR' , 'CATCHINCR_e0005' , + 'WESNN2_INCR' , 'CATCHINCR_e0005' , + 'WESNN3_INCR' , 'CATCHINCR_e0005' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0005' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0005' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0005' , + 'SNDZN1_INCR' , 'CATCHINCR_e0005' , + 'SNDZN2_INCR' , 'CATCHINCR_e0005' , + 'SNDZN3_INCR' , 'CATCHINCR_e0005' , :: catch_progn_incr0006.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -270,31 +215,31 @@ catch_progn_incr0006.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0006.mode: 'instantaneous', catch_progn_incr0006.frequency: 030000, catch_progn_incr0006.ref_time: 013000, -catch_progn_incr0006.fields: 'TCFSAT_INCR' , 'CATCHINCR0006' , - 'TCFTRN_INCR' , 'CATCHINCR0006' , - 'TCFWLT_INCR' , 'CATCHINCR0006' , - 'QCFSAT_INCR' , 'CATCHINCR0006' , - 'QCFTRN_INCR' , 'CATCHINCR0006' , - 'QCFWLT_INCR' , 'CATCHINCR0006' , - 'CAPAC_INCR' , 'CATCHINCR0006' , - 'CATDEF_INCR' , 'CATCHINCR0006' , - 'RZEXC_INCR' , 'CATCHINCR0006' , - 'SRFEXC_INCR' , 'CATCHINCR0006' , - 'GHTCNT1_INCR' , 'CATCHINCR0006' , - 'GHTCNT2_INCR' , 'CATCHINCR0006' , - 'GHTCNT3_INCR' , 'CATCHINCR0006' , - 'GHTCNT4_INCR' , 'CATCHINCR0006' , - 'GHTCNT5_INCR' , 'CATCHINCR0006' , - 'GHTCNT6_INCR' , 'CATCHINCR0006' , - 'WESNN1_INCR' , 'CATCHINCR0006' , - 'WESNN2_INCR' , 'CATCHINCR0006' , - 'WESNN3_INCR' , 'CATCHINCR0006' , - 'HTSNNN1_INCR' , 'CATCHINCR0006' , - 'HTSNNN2_INCR' , 'CATCHINCR0006' , - 'HTSNNN3_INCR' , 'CATCHINCR0006' , - 'SNDZN1_INCR' , 'CATCHINCR0006' , - 'SNDZN2_INCR' , 'CATCHINCR0006' , - 'SNDZN3_INCR' , 'CATCHINCR0006' , +catch_progn_incr0006.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0006' , + 'TCFTRN_INCR' , 'CATCHINCR_e0006' , + 'TCFWLT_INCR' , 'CATCHINCR_e0006' , + 'QCFSAT_INCR' , 'CATCHINCR_e0006' , + 'QCFTRN_INCR' , 'CATCHINCR_e0006' , + 'QCFWLT_INCR' , 'CATCHINCR_e0006' , + 'CAPAC_INCR' , 'CATCHINCR_e0006' , + 'CATDEF_INCR' , 'CATCHINCR_e0006' , + 'RZEXC_INCR' , 'CATCHINCR_e0006' , + 'SRFEXC_INCR' , 'CATCHINCR_e0006' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0006' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0006' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0006' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0006' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0006' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0006' , + 'WESNN1_INCR' , 'CATCHINCR_e0006' , + 'WESNN2_INCR' , 'CATCHINCR_e0006' , + 'WESNN3_INCR' , 'CATCHINCR_e0006' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0006' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0006' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0006' , + 'SNDZN1_INCR' , 'CATCHINCR_e0006' , + 'SNDZN2_INCR' , 'CATCHINCR_e0006' , + 'SNDZN3_INCR' , 'CATCHINCR_e0006' , :: catch_progn_incr0007.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -302,31 +247,31 @@ catch_progn_incr0007.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0007.mode: 'instantaneous', catch_progn_incr0007.frequency: 030000, catch_progn_incr0007.ref_time: 013000, -catch_progn_incr0007.fields: 'TCFSAT_INCR' , 'CATCHINCR0007' , - 'TCFTRN_INCR' , 'CATCHINCR0007' , - 'TCFWLT_INCR' , 'CATCHINCR0007' , - 'QCFSAT_INCR' , 'CATCHINCR0007' , - 'QCFTRN_INCR' , 'CATCHINCR0007' , - 'QCFWLT_INCR' , 'CATCHINCR0007' , - 'CAPAC_INCR' , 'CATCHINCR0007' , - 'CATDEF_INCR' , 'CATCHINCR0007' , - 'RZEXC_INCR' , 'CATCHINCR0007' , - 'SRFEXC_INCR' , 'CATCHINCR0007' , - 'GHTCNT1_INCR' , 'CATCHINCR0007' , - 'GHTCNT2_INCR' , 'CATCHINCR0007' , - 'GHTCNT3_INCR' , 'CATCHINCR0007' , - 'GHTCNT4_INCR' , 'CATCHINCR0007' , - 'GHTCNT5_INCR' , 'CATCHINCR0007' , - 'GHTCNT6_INCR' , 'CATCHINCR0007' , - 'WESNN1_INCR' , 'CATCHINCR0007' , - 'WESNN2_INCR' , 'CATCHINCR0007' , - 'WESNN3_INCR' , 'CATCHINCR0007' , - 'HTSNNN1_INCR' , 'CATCHINCR0007' , - 'HTSNNN2_INCR' , 'CATCHINCR0007' , - 'HTSNNN3_INCR' , 'CATCHINCR0007' , - 'SNDZN1_INCR' , 'CATCHINCR0007' , - 'SNDZN2_INCR' , 'CATCHINCR0007' , - 'SNDZN3_INCR' , 'CATCHINCR0007' , +catch_progn_incr0007.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0007' , + 'TCFTRN_INCR' , 'CATCHINCR_e0007' , + 'TCFWLT_INCR' , 'CATCHINCR_e0007' , + 'QCFSAT_INCR' , 'CATCHINCR_e0007' , + 'QCFTRN_INCR' , 'CATCHINCR_e0007' , + 'QCFWLT_INCR' , 'CATCHINCR_e0007' , + 'CAPAC_INCR' , 'CATCHINCR_e0007' , + 'CATDEF_INCR' , 'CATCHINCR_e0007' , + 'RZEXC_INCR' , 'CATCHINCR_e0007' , + 'SRFEXC_INCR' , 'CATCHINCR_e0007' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0007' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0007' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0007' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0007' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0007' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0007' , + 'WESNN1_INCR' , 'CATCHINCR_e0007' , + 'WESNN2_INCR' , 'CATCHINCR_e0007' , + 'WESNN3_INCR' , 'CATCHINCR_e0007' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0007' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0007' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0007' , + 'SNDZN1_INCR' , 'CATCHINCR_e0007' , + 'SNDZN2_INCR' , 'CATCHINCR_e0007' , + 'SNDZN3_INCR' , 'CATCHINCR_e0007' , :: catch_progn_incr0008.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -334,31 +279,31 @@ catch_progn_incr0008.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0008.mode: 'instantaneous', catch_progn_incr0008.frequency: 030000, catch_progn_incr0008.ref_time: 013000, -catch_progn_incr0008.fields: 'TCFSAT_INCR' , 'CATCHINCR0008' , - 'TCFTRN_INCR' , 'CATCHINCR0008' , - 'TCFWLT_INCR' , 'CATCHINCR0008' , - 'QCFSAT_INCR' , 'CATCHINCR0008' , - 'QCFTRN_INCR' , 'CATCHINCR0008' , - 'QCFWLT_INCR' , 'CATCHINCR0008' , - 'CAPAC_INCR' , 'CATCHINCR0008' , - 'CATDEF_INCR' , 'CATCHINCR0008' , - 'RZEXC_INCR' , 'CATCHINCR0008' , - 'SRFEXC_INCR' , 'CATCHINCR0008' , - 'GHTCNT1_INCR' , 'CATCHINCR0008' , - 'GHTCNT2_INCR' , 'CATCHINCR0008' , - 'GHTCNT3_INCR' , 'CATCHINCR0008' , - 'GHTCNT4_INCR' , 'CATCHINCR0008' , - 'GHTCNT5_INCR' , 'CATCHINCR0008' , - 'GHTCNT6_INCR' , 'CATCHINCR0008' , - 'WESNN1_INCR' , 'CATCHINCR0008' , - 'WESNN2_INCR' , 'CATCHINCR0008' , - 'WESNN3_INCR' , 'CATCHINCR0008' , - 'HTSNNN1_INCR' , 'CATCHINCR0008' , - 'HTSNNN2_INCR' , 'CATCHINCR0008' , - 'HTSNNN3_INCR' , 'CATCHINCR0008' , - 'SNDZN1_INCR' , 'CATCHINCR0008' , - 'SNDZN2_INCR' , 'CATCHINCR0008' , - 'SNDZN3_INCR' , 'CATCHINCR0008' , +catch_progn_incr0008.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0008' , + 'TCFTRN_INCR' , 'CATCHINCR_e0008' , + 'TCFWLT_INCR' , 'CATCHINCR_e0008' , + 'QCFSAT_INCR' , 'CATCHINCR_e0008' , + 'QCFTRN_INCR' , 'CATCHINCR_e0008' , + 'QCFWLT_INCR' , 'CATCHINCR_e0008' , + 'CAPAC_INCR' , 'CATCHINCR_e0008' , + 'CATDEF_INCR' , 'CATCHINCR_e0008' , + 'RZEXC_INCR' , 'CATCHINCR_e0008' , + 'SRFEXC_INCR' , 'CATCHINCR_e0008' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0008' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0008' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0008' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0008' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0008' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0008' , + 'WESNN1_INCR' , 'CATCHINCR_e0008' , + 'WESNN2_INCR' , 'CATCHINCR_e0008' , + 'WESNN3_INCR' , 'CATCHINCR_e0008' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0008' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0008' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0008' , + 'SNDZN1_INCR' , 'CATCHINCR_e0008' , + 'SNDZN2_INCR' , 'CATCHINCR_e0008' , + 'SNDZN3_INCR' , 'CATCHINCR_e0008' , :: catch_progn_incr0009.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -366,31 +311,31 @@ catch_progn_incr0009.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0009.mode: 'instantaneous', catch_progn_incr0009.frequency: 030000, catch_progn_incr0009.ref_time: 013000, -catch_progn_incr0009.fields: 'TCFSAT_INCR' , 'CATCHINCR0009' , - 'TCFTRN_INCR' , 'CATCHINCR0009' , - 'TCFWLT_INCR' , 'CATCHINCR0009' , - 'QCFSAT_INCR' , 'CATCHINCR0009' , - 'QCFTRN_INCR' , 'CATCHINCR0009' , - 'QCFWLT_INCR' , 'CATCHINCR0009' , - 'CAPAC_INCR' , 'CATCHINCR0009' , - 'CATDEF_INCR' , 'CATCHINCR0009' , - 'RZEXC_INCR' , 'CATCHINCR0009' , - 'SRFEXC_INCR' , 'CATCHINCR0009' , - 'GHTCNT1_INCR' , 'CATCHINCR0009' , - 'GHTCNT2_INCR' , 'CATCHINCR0009' , - 'GHTCNT3_INCR' , 'CATCHINCR0009' , - 'GHTCNT4_INCR' , 'CATCHINCR0009' , - 'GHTCNT5_INCR' , 'CATCHINCR0009' , - 'GHTCNT6_INCR' , 'CATCHINCR0009' , - 'WESNN1_INCR' , 'CATCHINCR0009' , - 'WESNN2_INCR' , 'CATCHINCR0009' , - 'WESNN3_INCR' , 'CATCHINCR0009' , - 'HTSNNN1_INCR' , 'CATCHINCR0009' , - 'HTSNNN2_INCR' , 'CATCHINCR0009' , - 'HTSNNN3_INCR' , 'CATCHINCR0009' , - 'SNDZN1_INCR' , 'CATCHINCR0009' , - 'SNDZN2_INCR' , 'CATCHINCR0009' , - 'SNDZN3_INCR' , 'CATCHINCR0009' , +catch_progn_incr0009.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0009' , + 'TCFTRN_INCR' , 'CATCHINCR_e0009' , + 'TCFWLT_INCR' , 'CATCHINCR_e0009' , + 'QCFSAT_INCR' , 'CATCHINCR_e0009' , + 'QCFTRN_INCR' , 'CATCHINCR_e0009' , + 'QCFWLT_INCR' , 'CATCHINCR_e0009' , + 'CAPAC_INCR' , 'CATCHINCR_e0009' , + 'CATDEF_INCR' , 'CATCHINCR_e0009' , + 'RZEXC_INCR' , 'CATCHINCR_e0009' , + 'SRFEXC_INCR' , 'CATCHINCR_e0009' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0009' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0009' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0009' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0009' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0009' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0009' , + 'WESNN1_INCR' , 'CATCHINCR_e0009' , + 'WESNN2_INCR' , 'CATCHINCR_e0009' , + 'WESNN3_INCR' , 'CATCHINCR_e0009' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0009' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0009' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0009' , + 'SNDZN1_INCR' , 'CATCHINCR_e0009' , + 'SNDZN2_INCR' , 'CATCHINCR_e0009' , + 'SNDZN3_INCR' , 'CATCHINCR_e0009' , :: catch_progn_incr0010.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -398,31 +343,31 @@ catch_progn_incr0010.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0010.mode: 'instantaneous', catch_progn_incr0010.frequency: 030000, catch_progn_incr0010.ref_time: 013000, -catch_progn_incr0010.fields: 'TCFSAT_INCR' , 'CATCHINCR0010' , - 'TCFTRN_INCR' , 'CATCHINCR0010' , - 'TCFWLT_INCR' , 'CATCHINCR0010' , - 'QCFSAT_INCR' , 'CATCHINCR0010' , - 'QCFTRN_INCR' , 'CATCHINCR0010' , - 'QCFWLT_INCR' , 'CATCHINCR0010' , - 'CAPAC_INCR' , 'CATCHINCR0010' , - 'CATDEF_INCR' , 'CATCHINCR0010' , - 'RZEXC_INCR' , 'CATCHINCR0010' , - 'SRFEXC_INCR' , 'CATCHINCR0010' , - 'GHTCNT1_INCR' , 'CATCHINCR0010' , - 'GHTCNT2_INCR' , 'CATCHINCR0010' , - 'GHTCNT3_INCR' , 'CATCHINCR0010' , - 'GHTCNT4_INCR' , 'CATCHINCR0010' , - 'GHTCNT5_INCR' , 'CATCHINCR0010' , - 'GHTCNT6_INCR' , 'CATCHINCR0010' , - 'WESNN1_INCR' , 'CATCHINCR0010' , - 'WESNN2_INCR' , 'CATCHINCR0010' , - 'WESNN3_INCR' , 'CATCHINCR0010' , - 'HTSNNN1_INCR' , 'CATCHINCR0010' , - 'HTSNNN2_INCR' , 'CATCHINCR0010' , - 'HTSNNN3_INCR' , 'CATCHINCR0010' , - 'SNDZN1_INCR' , 'CATCHINCR0010' , - 'SNDZN2_INCR' , 'CATCHINCR0010' , - 'SNDZN3_INCR' , 'CATCHINCR0010' , +catch_progn_incr0010.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0010' , + 'TCFTRN_INCR' , 'CATCHINCR_e0010' , + 'TCFWLT_INCR' , 'CATCHINCR_e0010' , + 'QCFSAT_INCR' , 'CATCHINCR_e0010' , + 'QCFTRN_INCR' , 'CATCHINCR_e0010' , + 'QCFWLT_INCR' , 'CATCHINCR_e0010' , + 'CAPAC_INCR' , 'CATCHINCR_e0010' , + 'CATDEF_INCR' , 'CATCHINCR_e0010' , + 'RZEXC_INCR' , 'CATCHINCR_e0010' , + 'SRFEXC_INCR' , 'CATCHINCR_e0010' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0010' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0010' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0010' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0010' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0010' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0010' , + 'WESNN1_INCR' , 'CATCHINCR_e0010' , + 'WESNN2_INCR' , 'CATCHINCR_e0010' , + 'WESNN3_INCR' , 'CATCHINCR_e0010' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0010' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0010' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0010' , + 'SNDZN1_INCR' , 'CATCHINCR_e0010' , + 'SNDZN2_INCR' , 'CATCHINCR_e0010' , + 'SNDZN3_INCR' , 'CATCHINCR_e0010' , :: catch_progn_incr0011.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -430,31 +375,31 @@ catch_progn_incr0011.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0011.mode: 'instantaneous', catch_progn_incr0011.frequency: 030000, catch_progn_incr0011.ref_time: 013000, -catch_progn_incr0011.fields: 'TCFSAT_INCR' , 'CATCHINCR0011' , - 'TCFTRN_INCR' , 'CATCHINCR0011' , - 'TCFWLT_INCR' , 'CATCHINCR0011' , - 'QCFSAT_INCR' , 'CATCHINCR0011' , - 'QCFTRN_INCR' , 'CATCHINCR0011' , - 'QCFWLT_INCR' , 'CATCHINCR0011' , - 'CAPAC_INCR' , 'CATCHINCR0011' , - 'CATDEF_INCR' , 'CATCHINCR0011' , - 'RZEXC_INCR' , 'CATCHINCR0011' , - 'SRFEXC_INCR' , 'CATCHINCR0011' , - 'GHTCNT1_INCR' , 'CATCHINCR0011' , - 'GHTCNT2_INCR' , 'CATCHINCR0011' , - 'GHTCNT3_INCR' , 'CATCHINCR0011' , - 'GHTCNT4_INCR' , 'CATCHINCR0011' , - 'GHTCNT5_INCR' , 'CATCHINCR0011' , - 'GHTCNT6_INCR' , 'CATCHINCR0011' , - 'WESNN1_INCR' , 'CATCHINCR0011' , - 'WESNN2_INCR' , 'CATCHINCR0011' , - 'WESNN3_INCR' , 'CATCHINCR0011' , - 'HTSNNN1_INCR' , 'CATCHINCR0011' , - 'HTSNNN2_INCR' , 'CATCHINCR0011' , - 'HTSNNN3_INCR' , 'CATCHINCR0011' , - 'SNDZN1_INCR' , 'CATCHINCR0011' , - 'SNDZN2_INCR' , 'CATCHINCR0011' , - 'SNDZN3_INCR' , 'CATCHINCR0011' , +catch_progn_incr0011.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0011' , + 'TCFTRN_INCR' , 'CATCHINCR_e0011' , + 'TCFWLT_INCR' , 'CATCHINCR_e0011' , + 'QCFSAT_INCR' , 'CATCHINCR_e0011' , + 'QCFTRN_INCR' , 'CATCHINCR_e0011' , + 'QCFWLT_INCR' , 'CATCHINCR_e0011' , + 'CAPAC_INCR' , 'CATCHINCR_e0011' , + 'CATDEF_INCR' , 'CATCHINCR_e0011' , + 'RZEXC_INCR' , 'CATCHINCR_e0011' , + 'SRFEXC_INCR' , 'CATCHINCR_e0011' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0011' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0011' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0011' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0011' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0011' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0011' , + 'WESNN1_INCR' , 'CATCHINCR_e0011' , + 'WESNN2_INCR' , 'CATCHINCR_e0011' , + 'WESNN3_INCR' , 'CATCHINCR_e0011' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0011' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0011' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0011' , + 'SNDZN1_INCR' , 'CATCHINCR_e0011' , + 'SNDZN2_INCR' , 'CATCHINCR_e0011' , + 'SNDZN3_INCR' , 'CATCHINCR_e0011' , :: catch_progn_incr0012.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -462,31 +407,31 @@ catch_progn_incr0012.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0012.mode: 'instantaneous', catch_progn_incr0012.frequency: 030000, catch_progn_incr0012.ref_time: 013000, -catch_progn_incr0012.fields: 'TCFSAT_INCR' , 'CATCHINCR0012' , - 'TCFTRN_INCR' , 'CATCHINCR0012' , - 'TCFWLT_INCR' , 'CATCHINCR0012' , - 'QCFSAT_INCR' , 'CATCHINCR0012' , - 'QCFTRN_INCR' , 'CATCHINCR0012' , - 'QCFWLT_INCR' , 'CATCHINCR0012' , - 'CAPAC_INCR' , 'CATCHINCR0012' , - 'CATDEF_INCR' , 'CATCHINCR0012' , - 'RZEXC_INCR' , 'CATCHINCR0012' , - 'SRFEXC_INCR' , 'CATCHINCR0012' , - 'GHTCNT1_INCR' , 'CATCHINCR0012' , - 'GHTCNT2_INCR' , 'CATCHINCR0012' , - 'GHTCNT3_INCR' , 'CATCHINCR0012' , - 'GHTCNT4_INCR' , 'CATCHINCR0012' , - 'GHTCNT5_INCR' , 'CATCHINCR0012' , - 'GHTCNT6_INCR' , 'CATCHINCR0012' , - 'WESNN1_INCR' , 'CATCHINCR0012' , - 'WESNN2_INCR' , 'CATCHINCR0012' , - 'WESNN3_INCR' , 'CATCHINCR0012' , - 'HTSNNN1_INCR' , 'CATCHINCR0012' , - 'HTSNNN2_INCR' , 'CATCHINCR0012' , - 'HTSNNN3_INCR' , 'CATCHINCR0012' , - 'SNDZN1_INCR' , 'CATCHINCR0012' , - 'SNDZN2_INCR' , 'CATCHINCR0012' , - 'SNDZN3_INCR' , 'CATCHINCR0012' , +catch_progn_incr0012.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0012' , + 'TCFTRN_INCR' , 'CATCHINCR_e0012' , + 'TCFWLT_INCR' , 'CATCHINCR_e0012' , + 'QCFSAT_INCR' , 'CATCHINCR_e0012' , + 'QCFTRN_INCR' , 'CATCHINCR_e0012' , + 'QCFWLT_INCR' , 'CATCHINCR_e0012' , + 'CAPAC_INCR' , 'CATCHINCR_e0012' , + 'CATDEF_INCR' , 'CATCHINCR_e0012' , + 'RZEXC_INCR' , 'CATCHINCR_e0012' , + 'SRFEXC_INCR' , 'CATCHINCR_e0012' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0012' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0012' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0012' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0012' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0012' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0012' , + 'WESNN1_INCR' , 'CATCHINCR_e0012' , + 'WESNN2_INCR' , 'CATCHINCR_e0012' , + 'WESNN3_INCR' , 'CATCHINCR_e0012' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0012' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0012' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0012' , + 'SNDZN1_INCR' , 'CATCHINCR_e0012' , + 'SNDZN2_INCR' , 'CATCHINCR_e0012' , + 'SNDZN3_INCR' , 'CATCHINCR_e0012' , :: catch_progn_incr0013.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -494,31 +439,31 @@ catch_progn_incr0013.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0013.mode: 'instantaneous', catch_progn_incr0013.frequency: 030000, catch_progn_incr0013.ref_time: 013000, -catch_progn_incr0013.fields: 'TCFSAT_INCR' , 'CATCHINCR0013' , - 'TCFTRN_INCR' , 'CATCHINCR0013' , - 'TCFWLT_INCR' , 'CATCHINCR0013' , - 'QCFSAT_INCR' , 'CATCHINCR0013' , - 'QCFTRN_INCR' , 'CATCHINCR0013' , - 'QCFWLT_INCR' , 'CATCHINCR0013' , - 'CAPAC_INCR' , 'CATCHINCR0013' , - 'CATDEF_INCR' , 'CATCHINCR0013' , - 'RZEXC_INCR' , 'CATCHINCR0013' , - 'SRFEXC_INCR' , 'CATCHINCR0013' , - 'GHTCNT1_INCR' , 'CATCHINCR0013' , - 'GHTCNT2_INCR' , 'CATCHINCR0013' , - 'GHTCNT3_INCR' , 'CATCHINCR0013' , - 'GHTCNT4_INCR' , 'CATCHINCR0013' , - 'GHTCNT5_INCR' , 'CATCHINCR0013' , - 'GHTCNT6_INCR' , 'CATCHINCR0013' , - 'WESNN1_INCR' , 'CATCHINCR0013' , - 'WESNN2_INCR' , 'CATCHINCR0013' , - 'WESNN3_INCR' , 'CATCHINCR0013' , - 'HTSNNN1_INCR' , 'CATCHINCR0013' , - 'HTSNNN2_INCR' , 'CATCHINCR0013' , - 'HTSNNN3_INCR' , 'CATCHINCR0013' , - 'SNDZN1_INCR' , 'CATCHINCR0013' , - 'SNDZN2_INCR' , 'CATCHINCR0013' , - 'SNDZN3_INCR' , 'CATCHINCR0013' , +catch_progn_incr0013.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0013' , + 'TCFTRN_INCR' , 'CATCHINCR_e0013' , + 'TCFWLT_INCR' , 'CATCHINCR_e0013' , + 'QCFSAT_INCR' , 'CATCHINCR_e0013' , + 'QCFTRN_INCR' , 'CATCHINCR_e0013' , + 'QCFWLT_INCR' , 'CATCHINCR_e0013' , + 'CAPAC_INCR' , 'CATCHINCR_e0013' , + 'CATDEF_INCR' , 'CATCHINCR_e0013' , + 'RZEXC_INCR' , 'CATCHINCR_e0013' , + 'SRFEXC_INCR' , 'CATCHINCR_e0013' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0013' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0013' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0013' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0013' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0013' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0013' , + 'WESNN1_INCR' , 'CATCHINCR_e0013' , + 'WESNN2_INCR' , 'CATCHINCR_e0013' , + 'WESNN3_INCR' , 'CATCHINCR_e0013' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0013' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0013' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0013' , + 'SNDZN1_INCR' , 'CATCHINCR_e0013' , + 'SNDZN2_INCR' , 'CATCHINCR_e0013' , + 'SNDZN3_INCR' , 'CATCHINCR_e0013' , :: catch_progn_incr0014.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -526,31 +471,31 @@ catch_progn_incr0014.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0014.mode: 'instantaneous', catch_progn_incr0014.frequency: 030000, catch_progn_incr0014.ref_time: 013000, -catch_progn_incr0014.fields: 'TCFSAT_INCR' , 'CATCHINCR0014' , - 'TCFTRN_INCR' , 'CATCHINCR0014' , - 'TCFWLT_INCR' , 'CATCHINCR0014' , - 'QCFSAT_INCR' , 'CATCHINCR0014' , - 'QCFTRN_INCR' , 'CATCHINCR0014' , - 'QCFWLT_INCR' , 'CATCHINCR0014' , - 'CAPAC_INCR' , 'CATCHINCR0014' , - 'CATDEF_INCR' , 'CATCHINCR0014' , - 'RZEXC_INCR' , 'CATCHINCR0014' , - 'SRFEXC_INCR' , 'CATCHINCR0014' , - 'GHTCNT1_INCR' , 'CATCHINCR0014' , - 'GHTCNT2_INCR' , 'CATCHINCR0014' , - 'GHTCNT3_INCR' , 'CATCHINCR0014' , - 'GHTCNT4_INCR' , 'CATCHINCR0014' , - 'GHTCNT5_INCR' , 'CATCHINCR0014' , - 'GHTCNT6_INCR' , 'CATCHINCR0014' , - 'WESNN1_INCR' , 'CATCHINCR0014' , - 'WESNN2_INCR' , 'CATCHINCR0014' , - 'WESNN3_INCR' , 'CATCHINCR0014' , - 'HTSNNN1_INCR' , 'CATCHINCR0014' , - 'HTSNNN2_INCR' , 'CATCHINCR0014' , - 'HTSNNN3_INCR' , 'CATCHINCR0014' , - 'SNDZN1_INCR' , 'CATCHINCR0014' , - 'SNDZN2_INCR' , 'CATCHINCR0014' , - 'SNDZN3_INCR' , 'CATCHINCR0014' , +catch_progn_incr0014.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0014' , + 'TCFTRN_INCR' , 'CATCHINCR_e0014' , + 'TCFWLT_INCR' , 'CATCHINCR_e0014' , + 'QCFSAT_INCR' , 'CATCHINCR_e0014' , + 'QCFTRN_INCR' , 'CATCHINCR_e0014' , + 'QCFWLT_INCR' , 'CATCHINCR_e0014' , + 'CAPAC_INCR' , 'CATCHINCR_e0014' , + 'CATDEF_INCR' , 'CATCHINCR_e0014' , + 'RZEXC_INCR' , 'CATCHINCR_e0014' , + 'SRFEXC_INCR' , 'CATCHINCR_e0014' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0014' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0014' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0014' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0014' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0014' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0014' , + 'WESNN1_INCR' , 'CATCHINCR_e0014' , + 'WESNN2_INCR' , 'CATCHINCR_e0014' , + 'WESNN3_INCR' , 'CATCHINCR_e0014' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0014' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0014' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0014' , + 'SNDZN1_INCR' , 'CATCHINCR_e0014' , + 'SNDZN2_INCR' , 'CATCHINCR_e0014' , + 'SNDZN3_INCR' , 'CATCHINCR_e0014' , :: catch_progn_incr0015.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -558,31 +503,31 @@ catch_progn_incr0015.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0015.mode: 'instantaneous', catch_progn_incr0015.frequency: 030000, catch_progn_incr0015.ref_time: 013000, -catch_progn_incr0015.fields: 'TCFSAT_INCR' , 'CATCHINCR0015' , - 'TCFTRN_INCR' , 'CATCHINCR0015' , - 'TCFWLT_INCR' , 'CATCHINCR0015' , - 'QCFSAT_INCR' , 'CATCHINCR0015' , - 'QCFTRN_INCR' , 'CATCHINCR0015' , - 'QCFWLT_INCR' , 'CATCHINCR0015' , - 'CAPAC_INCR' , 'CATCHINCR0015' , - 'CATDEF_INCR' , 'CATCHINCR0015' , - 'RZEXC_INCR' , 'CATCHINCR0015' , - 'SRFEXC_INCR' , 'CATCHINCR0015' , - 'GHTCNT1_INCR' , 'CATCHINCR0015' , - 'GHTCNT2_INCR' , 'CATCHINCR0015' , - 'GHTCNT3_INCR' , 'CATCHINCR0015' , - 'GHTCNT4_INCR' , 'CATCHINCR0015' , - 'GHTCNT5_INCR' , 'CATCHINCR0015' , - 'GHTCNT6_INCR' , 'CATCHINCR0015' , - 'WESNN1_INCR' , 'CATCHINCR0015' , - 'WESNN2_INCR' , 'CATCHINCR0015' , - 'WESNN3_INCR' , 'CATCHINCR0015' , - 'HTSNNN1_INCR' , 'CATCHINCR0015' , - 'HTSNNN2_INCR' , 'CATCHINCR0015' , - 'HTSNNN3_INCR' , 'CATCHINCR0015' , - 'SNDZN1_INCR' , 'CATCHINCR0015' , - 'SNDZN2_INCR' , 'CATCHINCR0015' , - 'SNDZN3_INCR' , 'CATCHINCR0015' , +catch_progn_incr0015.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0015' , + 'TCFTRN_INCR' , 'CATCHINCR_e0015' , + 'TCFWLT_INCR' , 'CATCHINCR_e0015' , + 'QCFSAT_INCR' , 'CATCHINCR_e0015' , + 'QCFTRN_INCR' , 'CATCHINCR_e0015' , + 'QCFWLT_INCR' , 'CATCHINCR_e0015' , + 'CAPAC_INCR' , 'CATCHINCR_e0015' , + 'CATDEF_INCR' , 'CATCHINCR_e0015' , + 'RZEXC_INCR' , 'CATCHINCR_e0015' , + 'SRFEXC_INCR' , 'CATCHINCR_e0015' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0015' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0015' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0015' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0015' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0015' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0015' , + 'WESNN1_INCR' , 'CATCHINCR_e0015' , + 'WESNN2_INCR' , 'CATCHINCR_e0015' , + 'WESNN3_INCR' , 'CATCHINCR_e0015' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0015' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0015' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0015' , + 'SNDZN1_INCR' , 'CATCHINCR_e0015' , + 'SNDZN2_INCR' , 'CATCHINCR_e0015' , + 'SNDZN3_INCR' , 'CATCHINCR_e0015' , :: catch_progn_incr0016.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -590,31 +535,31 @@ catch_progn_incr0016.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0016.mode: 'instantaneous', catch_progn_incr0016.frequency: 030000, catch_progn_incr0016.ref_time: 013000, -catch_progn_incr0016.fields: 'TCFSAT_INCR' , 'CATCHINCR0016' , - 'TCFTRN_INCR' , 'CATCHINCR0016' , - 'TCFWLT_INCR' , 'CATCHINCR0016' , - 'QCFSAT_INCR' , 'CATCHINCR0016' , - 'QCFTRN_INCR' , 'CATCHINCR0016' , - 'QCFWLT_INCR' , 'CATCHINCR0016' , - 'CAPAC_INCR' , 'CATCHINCR0016' , - 'CATDEF_INCR' , 'CATCHINCR0016' , - 'RZEXC_INCR' , 'CATCHINCR0016' , - 'SRFEXC_INCR' , 'CATCHINCR0016' , - 'GHTCNT1_INCR' , 'CATCHINCR0016' , - 'GHTCNT2_INCR' , 'CATCHINCR0016' , - 'GHTCNT3_INCR' , 'CATCHINCR0016' , - 'GHTCNT4_INCR' , 'CATCHINCR0016' , - 'GHTCNT5_INCR' , 'CATCHINCR0016' , - 'GHTCNT6_INCR' , 'CATCHINCR0016' , - 'WESNN1_INCR' , 'CATCHINCR0016' , - 'WESNN2_INCR' , 'CATCHINCR0016' , - 'WESNN3_INCR' , 'CATCHINCR0016' , - 'HTSNNN1_INCR' , 'CATCHINCR0016' , - 'HTSNNN2_INCR' , 'CATCHINCR0016' , - 'HTSNNN3_INCR' , 'CATCHINCR0016' , - 'SNDZN1_INCR' , 'CATCHINCR0016' , - 'SNDZN2_INCR' , 'CATCHINCR0016' , - 'SNDZN3_INCR' , 'CATCHINCR0016' , +catch_progn_incr0016.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0016' , + 'TCFTRN_INCR' , 'CATCHINCR_e0016' , + 'TCFWLT_INCR' , 'CATCHINCR_e0016' , + 'QCFSAT_INCR' , 'CATCHINCR_e0016' , + 'QCFTRN_INCR' , 'CATCHINCR_e0016' , + 'QCFWLT_INCR' , 'CATCHINCR_e0016' , + 'CAPAC_INCR' , 'CATCHINCR_e0016' , + 'CATDEF_INCR' , 'CATCHINCR_e0016' , + 'RZEXC_INCR' , 'CATCHINCR_e0016' , + 'SRFEXC_INCR' , 'CATCHINCR_e0016' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0016' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0016' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0016' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0016' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0016' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0016' , + 'WESNN1_INCR' , 'CATCHINCR_e0016' , + 'WESNN2_INCR' , 'CATCHINCR_e0016' , + 'WESNN3_INCR' , 'CATCHINCR_e0016' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0016' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0016' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0016' , + 'SNDZN1_INCR' , 'CATCHINCR_e0016' , + 'SNDZN2_INCR' , 'CATCHINCR_e0016' , + 'SNDZN3_INCR' , 'CATCHINCR_e0016' , :: catch_progn_incr0017.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -622,31 +567,31 @@ catch_progn_incr0017.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0017.mode: 'instantaneous', catch_progn_incr0017.frequency: 030000, catch_progn_incr0017.ref_time: 013000, -catch_progn_incr0017.fields: 'TCFSAT_INCR' , 'CATCHINCR0017' , - 'TCFTRN_INCR' , 'CATCHINCR0017' , - 'TCFWLT_INCR' , 'CATCHINCR0017' , - 'QCFSAT_INCR' , 'CATCHINCR0017' , - 'QCFTRN_INCR' , 'CATCHINCR0017' , - 'QCFWLT_INCR' , 'CATCHINCR0017' , - 'CAPAC_INCR' , 'CATCHINCR0017' , - 'CATDEF_INCR' , 'CATCHINCR0017' , - 'RZEXC_INCR' , 'CATCHINCR0017' , - 'SRFEXC_INCR' , 'CATCHINCR0017' , - 'GHTCNT1_INCR' , 'CATCHINCR0017' , - 'GHTCNT2_INCR' , 'CATCHINCR0017' , - 'GHTCNT3_INCR' , 'CATCHINCR0017' , - 'GHTCNT4_INCR' , 'CATCHINCR0017' , - 'GHTCNT5_INCR' , 'CATCHINCR0017' , - 'GHTCNT6_INCR' , 'CATCHINCR0017' , - 'WESNN1_INCR' , 'CATCHINCR0017' , - 'WESNN2_INCR' , 'CATCHINCR0017' , - 'WESNN3_INCR' , 'CATCHINCR0017' , - 'HTSNNN1_INCR' , 'CATCHINCR0017' , - 'HTSNNN2_INCR' , 'CATCHINCR0017' , - 'HTSNNN3_INCR' , 'CATCHINCR0017' , - 'SNDZN1_INCR' , 'CATCHINCR0017' , - 'SNDZN2_INCR' , 'CATCHINCR0017' , - 'SNDZN3_INCR' , 'CATCHINCR0017' , +catch_progn_incr0017.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0017' , + 'TCFTRN_INCR' , 'CATCHINCR_e0017' , + 'TCFWLT_INCR' , 'CATCHINCR_e0017' , + 'QCFSAT_INCR' , 'CATCHINCR_e0017' , + 'QCFTRN_INCR' , 'CATCHINCR_e0017' , + 'QCFWLT_INCR' , 'CATCHINCR_e0017' , + 'CAPAC_INCR' , 'CATCHINCR_e0017' , + 'CATDEF_INCR' , 'CATCHINCR_e0017' , + 'RZEXC_INCR' , 'CATCHINCR_e0017' , + 'SRFEXC_INCR' , 'CATCHINCR_e0017' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0017' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0017' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0017' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0017' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0017' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0017' , + 'WESNN1_INCR' , 'CATCHINCR_e0017' , + 'WESNN2_INCR' , 'CATCHINCR_e0017' , + 'WESNN3_INCR' , 'CATCHINCR_e0017' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0017' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0017' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0017' , + 'SNDZN1_INCR' , 'CATCHINCR_e0017' , + 'SNDZN2_INCR' , 'CATCHINCR_e0017' , + 'SNDZN3_INCR' , 'CATCHINCR_e0017' , :: catch_progn_incr0018.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -654,31 +599,31 @@ catch_progn_incr0018.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0018.mode: 'instantaneous', catch_progn_incr0018.frequency: 030000, catch_progn_incr0018.ref_time: 013000, -catch_progn_incr0018.fields: 'TCFSAT_INCR' , 'CATCHINCR0018' , - 'TCFTRN_INCR' , 'CATCHINCR0018' , - 'TCFWLT_INCR' , 'CATCHINCR0018' , - 'QCFSAT_INCR' , 'CATCHINCR0018' , - 'QCFTRN_INCR' , 'CATCHINCR0018' , - 'QCFWLT_INCR' , 'CATCHINCR0018' , - 'CAPAC_INCR' , 'CATCHINCR0018' , - 'CATDEF_INCR' , 'CATCHINCR0018' , - 'RZEXC_INCR' , 'CATCHINCR0018' , - 'SRFEXC_INCR' , 'CATCHINCR0018' , - 'GHTCNT1_INCR' , 'CATCHINCR0018' , - 'GHTCNT2_INCR' , 'CATCHINCR0018' , - 'GHTCNT3_INCR' , 'CATCHINCR0018' , - 'GHTCNT4_INCR' , 'CATCHINCR0018' , - 'GHTCNT5_INCR' , 'CATCHINCR0018' , - 'GHTCNT6_INCR' , 'CATCHINCR0018' , - 'WESNN1_INCR' , 'CATCHINCR0018' , - 'WESNN2_INCR' , 'CATCHINCR0018' , - 'WESNN3_INCR' , 'CATCHINCR0018' , - 'HTSNNN1_INCR' , 'CATCHINCR0018' , - 'HTSNNN2_INCR' , 'CATCHINCR0018' , - 'HTSNNN3_INCR' , 'CATCHINCR0018' , - 'SNDZN1_INCR' , 'CATCHINCR0018' , - 'SNDZN2_INCR' , 'CATCHINCR0018' , - 'SNDZN3_INCR' , 'CATCHINCR0018' , +catch_progn_incr0018.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0018' , + 'TCFTRN_INCR' , 'CATCHINCR_e0018' , + 'TCFWLT_INCR' , 'CATCHINCR_e0018' , + 'QCFSAT_INCR' , 'CATCHINCR_e0018' , + 'QCFTRN_INCR' , 'CATCHINCR_e0018' , + 'QCFWLT_INCR' , 'CATCHINCR_e0018' , + 'CAPAC_INCR' , 'CATCHINCR_e0018' , + 'CATDEF_INCR' , 'CATCHINCR_e0018' , + 'RZEXC_INCR' , 'CATCHINCR_e0018' , + 'SRFEXC_INCR' , 'CATCHINCR_e0018' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0018' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0018' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0018' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0018' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0018' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0018' , + 'WESNN1_INCR' , 'CATCHINCR_e0018' , + 'WESNN2_INCR' , 'CATCHINCR_e0018' , + 'WESNN3_INCR' , 'CATCHINCR_e0018' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0018' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0018' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0018' , + 'SNDZN1_INCR' , 'CATCHINCR_e0018' , + 'SNDZN2_INCR' , 'CATCHINCR_e0018' , + 'SNDZN3_INCR' , 'CATCHINCR_e0018' , :: catch_progn_incr0019.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -686,31 +631,31 @@ catch_progn_incr0019.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0019.mode: 'instantaneous', catch_progn_incr0019.frequency: 030000, catch_progn_incr0019.ref_time: 013000, -catch_progn_incr0019.fields: 'TCFSAT_INCR' , 'CATCHINCR0019' , - 'TCFTRN_INCR' , 'CATCHINCR0019' , - 'TCFWLT_INCR' , 'CATCHINCR0019' , - 'QCFSAT_INCR' , 'CATCHINCR0019' , - 'QCFTRN_INCR' , 'CATCHINCR0019' , - 'QCFWLT_INCR' , 'CATCHINCR0019' , - 'CAPAC_INCR' , 'CATCHINCR0019' , - 'CATDEF_INCR' , 'CATCHINCR0019' , - 'RZEXC_INCR' , 'CATCHINCR0019' , - 'SRFEXC_INCR' , 'CATCHINCR0019' , - 'GHTCNT1_INCR' , 'CATCHINCR0019' , - 'GHTCNT2_INCR' , 'CATCHINCR0019' , - 'GHTCNT3_INCR' , 'CATCHINCR0019' , - 'GHTCNT4_INCR' , 'CATCHINCR0019' , - 'GHTCNT5_INCR' , 'CATCHINCR0019' , - 'GHTCNT6_INCR' , 'CATCHINCR0019' , - 'WESNN1_INCR' , 'CATCHINCR0019' , - 'WESNN2_INCR' , 'CATCHINCR0019' , - 'WESNN3_INCR' , 'CATCHINCR0019' , - 'HTSNNN1_INCR' , 'CATCHINCR0019' , - 'HTSNNN2_INCR' , 'CATCHINCR0019' , - 'HTSNNN3_INCR' , 'CATCHINCR0019' , - 'SNDZN1_INCR' , 'CATCHINCR0019' , - 'SNDZN2_INCR' , 'CATCHINCR0019' , - 'SNDZN3_INCR' , 'CATCHINCR0019' , +catch_progn_incr0019.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0019' , + 'TCFTRN_INCR' , 'CATCHINCR_e0019' , + 'TCFWLT_INCR' , 'CATCHINCR_e0019' , + 'QCFSAT_INCR' , 'CATCHINCR_e0019' , + 'QCFTRN_INCR' , 'CATCHINCR_e0019' , + 'QCFWLT_INCR' , 'CATCHINCR_e0019' , + 'CAPAC_INCR' , 'CATCHINCR_e0019' , + 'CATDEF_INCR' , 'CATCHINCR_e0019' , + 'RZEXC_INCR' , 'CATCHINCR_e0019' , + 'SRFEXC_INCR' , 'CATCHINCR_e0019' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0019' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0019' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0019' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0019' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0019' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0019' , + 'WESNN1_INCR' , 'CATCHINCR_e0019' , + 'WESNN2_INCR' , 'CATCHINCR_e0019' , + 'WESNN3_INCR' , 'CATCHINCR_e0019' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0019' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0019' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0019' , + 'SNDZN1_INCR' , 'CATCHINCR_e0019' , + 'SNDZN2_INCR' , 'CATCHINCR_e0019' , + 'SNDZN3_INCR' , 'CATCHINCR_e0019' , :: catch_progn_incr0020.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -718,31 +663,31 @@ catch_progn_incr0020.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0020.mode: 'instantaneous', catch_progn_incr0020.frequency: 030000, catch_progn_incr0020.ref_time: 013000, -catch_progn_incr0020.fields: 'TCFSAT_INCR' , 'CATCHINCR0020' , - 'TCFTRN_INCR' , 'CATCHINCR0020' , - 'TCFWLT_INCR' , 'CATCHINCR0020' , - 'QCFSAT_INCR' , 'CATCHINCR0020' , - 'QCFTRN_INCR' , 'CATCHINCR0020' , - 'QCFWLT_INCR' , 'CATCHINCR0020' , - 'CAPAC_INCR' , 'CATCHINCR0020' , - 'CATDEF_INCR' , 'CATCHINCR0020' , - 'RZEXC_INCR' , 'CATCHINCR0020' , - 'SRFEXC_INCR' , 'CATCHINCR0020' , - 'GHTCNT1_INCR' , 'CATCHINCR0020' , - 'GHTCNT2_INCR' , 'CATCHINCR0020' , - 'GHTCNT3_INCR' , 'CATCHINCR0020' , - 'GHTCNT4_INCR' , 'CATCHINCR0020' , - 'GHTCNT5_INCR' , 'CATCHINCR0020' , - 'GHTCNT6_INCR' , 'CATCHINCR0020' , - 'WESNN1_INCR' , 'CATCHINCR0020' , - 'WESNN2_INCR' , 'CATCHINCR0020' , - 'WESNN3_INCR' , 'CATCHINCR0020' , - 'HTSNNN1_INCR' , 'CATCHINCR0020' , - 'HTSNNN2_INCR' , 'CATCHINCR0020' , - 'HTSNNN3_INCR' , 'CATCHINCR0020' , - 'SNDZN1_INCR' , 'CATCHINCR0020' , - 'SNDZN2_INCR' , 'CATCHINCR0020' , - 'SNDZN3_INCR' , 'CATCHINCR0020' , +catch_progn_incr0020.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0020' , + 'TCFTRN_INCR' , 'CATCHINCR_e0020' , + 'TCFWLT_INCR' , 'CATCHINCR_e0020' , + 'QCFSAT_INCR' , 'CATCHINCR_e0020' , + 'QCFTRN_INCR' , 'CATCHINCR_e0020' , + 'QCFWLT_INCR' , 'CATCHINCR_e0020' , + 'CAPAC_INCR' , 'CATCHINCR_e0020' , + 'CATDEF_INCR' , 'CATCHINCR_e0020' , + 'RZEXC_INCR' , 'CATCHINCR_e0020' , + 'SRFEXC_INCR' , 'CATCHINCR_e0020' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0020' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0020' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0020' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0020' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0020' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0020' , + 'WESNN1_INCR' , 'CATCHINCR_e0020' , + 'WESNN2_INCR' , 'CATCHINCR_e0020' , + 'WESNN3_INCR' , 'CATCHINCR_e0020' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0020' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0020' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0020' , + 'SNDZN1_INCR' , 'CATCHINCR_e0020' , + 'SNDZN2_INCR' , 'CATCHINCR_e0020' , + 'SNDZN3_INCR' , 'CATCHINCR_e0020' , :: catch_progn_incr0021.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -750,31 +695,31 @@ catch_progn_incr0021.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0021.mode: 'instantaneous', catch_progn_incr0021.frequency: 030000, catch_progn_incr0021.ref_time: 013000, -catch_progn_incr0021.fields: 'TCFSAT_INCR' , 'CATCHINCR0021' , - 'TCFTRN_INCR' , 'CATCHINCR0021' , - 'TCFWLT_INCR' , 'CATCHINCR0021' , - 'QCFSAT_INCR' , 'CATCHINCR0021' , - 'QCFTRN_INCR' , 'CATCHINCR0021' , - 'QCFWLT_INCR' , 'CATCHINCR0021' , - 'CAPAC_INCR' , 'CATCHINCR0021' , - 'CATDEF_INCR' , 'CATCHINCR0021' , - 'RZEXC_INCR' , 'CATCHINCR0021' , - 'SRFEXC_INCR' , 'CATCHINCR0021' , - 'GHTCNT1_INCR' , 'CATCHINCR0021' , - 'GHTCNT2_INCR' , 'CATCHINCR0021' , - 'GHTCNT3_INCR' , 'CATCHINCR0021' , - 'GHTCNT4_INCR' , 'CATCHINCR0021' , - 'GHTCNT5_INCR' , 'CATCHINCR0021' , - 'GHTCNT6_INCR' , 'CATCHINCR0021' , - 'WESNN1_INCR' , 'CATCHINCR0021' , - 'WESNN2_INCR' , 'CATCHINCR0021' , - 'WESNN3_INCR' , 'CATCHINCR0021' , - 'HTSNNN1_INCR' , 'CATCHINCR0021' , - 'HTSNNN2_INCR' , 'CATCHINCR0021' , - 'HTSNNN3_INCR' , 'CATCHINCR0021' , - 'SNDZN1_INCR' , 'CATCHINCR0021' , - 'SNDZN2_INCR' , 'CATCHINCR0021' , - 'SNDZN3_INCR' , 'CATCHINCR0021' , +catch_progn_incr0021.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0021' , + 'TCFTRN_INCR' , 'CATCHINCR_e0021' , + 'TCFWLT_INCR' , 'CATCHINCR_e0021' , + 'QCFSAT_INCR' , 'CATCHINCR_e0021' , + 'QCFTRN_INCR' , 'CATCHINCR_e0021' , + 'QCFWLT_INCR' , 'CATCHINCR_e0021' , + 'CAPAC_INCR' , 'CATCHINCR_e0021' , + 'CATDEF_INCR' , 'CATCHINCR_e0021' , + 'RZEXC_INCR' , 'CATCHINCR_e0021' , + 'SRFEXC_INCR' , 'CATCHINCR_e0021' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0021' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0021' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0021' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0021' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0021' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0021' , + 'WESNN1_INCR' , 'CATCHINCR_e0021' , + 'WESNN2_INCR' , 'CATCHINCR_e0021' , + 'WESNN3_INCR' , 'CATCHINCR_e0021' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0021' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0021' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0021' , + 'SNDZN1_INCR' , 'CATCHINCR_e0021' , + 'SNDZN2_INCR' , 'CATCHINCR_e0021' , + 'SNDZN3_INCR' , 'CATCHINCR_e0021' , :: catch_progn_incr0022.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -782,31 +727,31 @@ catch_progn_incr0022.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0022.mode: 'instantaneous', catch_progn_incr0022.frequency: 030000, catch_progn_incr0022.ref_time: 013000, -catch_progn_incr0022.fields: 'TCFSAT_INCR' , 'CATCHINCR0022' , - 'TCFTRN_INCR' , 'CATCHINCR0022' , - 'TCFWLT_INCR' , 'CATCHINCR0022' , - 'QCFSAT_INCR' , 'CATCHINCR0022' , - 'QCFTRN_INCR' , 'CATCHINCR0022' , - 'QCFWLT_INCR' , 'CATCHINCR0022' , - 'CAPAC_INCR' , 'CATCHINCR0022' , - 'CATDEF_INCR' , 'CATCHINCR0022' , - 'RZEXC_INCR' , 'CATCHINCR0022' , - 'SRFEXC_INCR' , 'CATCHINCR0022' , - 'GHTCNT1_INCR' , 'CATCHINCR0022' , - 'GHTCNT2_INCR' , 'CATCHINCR0022' , - 'GHTCNT3_INCR' , 'CATCHINCR0022' , - 'GHTCNT4_INCR' , 'CATCHINCR0022' , - 'GHTCNT5_INCR' , 'CATCHINCR0022' , - 'GHTCNT6_INCR' , 'CATCHINCR0022' , - 'WESNN1_INCR' , 'CATCHINCR0022' , - 'WESNN2_INCR' , 'CATCHINCR0022' , - 'WESNN3_INCR' , 'CATCHINCR0022' , - 'HTSNNN1_INCR' , 'CATCHINCR0022' , - 'HTSNNN2_INCR' , 'CATCHINCR0022' , - 'HTSNNN3_INCR' , 'CATCHINCR0022' , - 'SNDZN1_INCR' , 'CATCHINCR0022' , - 'SNDZN2_INCR' , 'CATCHINCR0022' , - 'SNDZN3_INCR' , 'CATCHINCR0022' , +catch_progn_incr0022.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0022' , + 'TCFTRN_INCR' , 'CATCHINCR_e0022' , + 'TCFWLT_INCR' , 'CATCHINCR_e0022' , + 'QCFSAT_INCR' , 'CATCHINCR_e0022' , + 'QCFTRN_INCR' , 'CATCHINCR_e0022' , + 'QCFWLT_INCR' , 'CATCHINCR_e0022' , + 'CAPAC_INCR' , 'CATCHINCR_e0022' , + 'CATDEF_INCR' , 'CATCHINCR_e0022' , + 'RZEXC_INCR' , 'CATCHINCR_e0022' , + 'SRFEXC_INCR' , 'CATCHINCR_e0022' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0022' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0022' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0022' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0022' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0022' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0022' , + 'WESNN1_INCR' , 'CATCHINCR_e0022' , + 'WESNN2_INCR' , 'CATCHINCR_e0022' , + 'WESNN3_INCR' , 'CATCHINCR_e0022' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0022' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0022' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0022' , + 'SNDZN1_INCR' , 'CATCHINCR_e0022' , + 'SNDZN2_INCR' , 'CATCHINCR_e0022' , + 'SNDZN3_INCR' , 'CATCHINCR_e0022' , :: catch_progn_incr0023.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -814,31 +759,31 @@ catch_progn_incr0023.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0023.mode: 'instantaneous', catch_progn_incr0023.frequency: 030000, catch_progn_incr0023.ref_time: 013000, -catch_progn_incr0023.fields: 'TCFSAT_INCR' , 'CATCHINCR0023' , - 'TCFTRN_INCR' , 'CATCHINCR0023' , - 'TCFWLT_INCR' , 'CATCHINCR0023' , - 'QCFSAT_INCR' , 'CATCHINCR0023' , - 'QCFTRN_INCR' , 'CATCHINCR0023' , - 'QCFWLT_INCR' , 'CATCHINCR0023' , - 'CAPAC_INCR' , 'CATCHINCR0023' , - 'CATDEF_INCR' , 'CATCHINCR0023' , - 'RZEXC_INCR' , 'CATCHINCR0023' , - 'SRFEXC_INCR' , 'CATCHINCR0023' , - 'GHTCNT1_INCR' , 'CATCHINCR0023' , - 'GHTCNT2_INCR' , 'CATCHINCR0023' , - 'GHTCNT3_INCR' , 'CATCHINCR0023' , - 'GHTCNT4_INCR' , 'CATCHINCR0023' , - 'GHTCNT5_INCR' , 'CATCHINCR0023' , - 'GHTCNT6_INCR' , 'CATCHINCR0023' , - 'WESNN1_INCR' , 'CATCHINCR0023' , - 'WESNN2_INCR' , 'CATCHINCR0023' , - 'WESNN3_INCR' , 'CATCHINCR0023' , - 'HTSNNN1_INCR' , 'CATCHINCR0023' , - 'HTSNNN2_INCR' , 'CATCHINCR0023' , - 'HTSNNN3_INCR' , 'CATCHINCR0023' , - 'SNDZN1_INCR' , 'CATCHINCR0023' , - 'SNDZN2_INCR' , 'CATCHINCR0023' , - 'SNDZN3_INCR' , 'CATCHINCR0023' , +catch_progn_incr0023.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0023' , + 'TCFTRN_INCR' , 'CATCHINCR_e0023' , + 'TCFWLT_INCR' , 'CATCHINCR_e0023' , + 'QCFSAT_INCR' , 'CATCHINCR_e0023' , + 'QCFTRN_INCR' , 'CATCHINCR_e0023' , + 'QCFWLT_INCR' , 'CATCHINCR_e0023' , + 'CAPAC_INCR' , 'CATCHINCR_e0023' , + 'CATDEF_INCR' , 'CATCHINCR_e0023' , + 'RZEXC_INCR' , 'CATCHINCR_e0023' , + 'SRFEXC_INCR' , 'CATCHINCR_e0023' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0023' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0023' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0023' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0023' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0023' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0023' , + 'WESNN1_INCR' , 'CATCHINCR_e0023' , + 'WESNN2_INCR' , 'CATCHINCR_e0023' , + 'WESNN3_INCR' , 'CATCHINCR_e0023' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0023' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0023' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0023' , + 'SNDZN1_INCR' , 'CATCHINCR_e0023' , + 'SNDZN2_INCR' , 'CATCHINCR_e0023' , + 'SNDZN3_INCR' , 'CATCHINCR_e0023' , :: catch_progn_incr0024.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -846,31 +791,31 @@ catch_progn_incr0024.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0024.mode: 'instantaneous', catch_progn_incr0024.frequency: 030000, catch_progn_incr0024.ref_time: 013000, -catch_progn_incr0024.fields: 'TCFSAT_INCR' , 'CATCHINCR0024' , - 'TCFTRN_INCR' , 'CATCHINCR0024' , - 'TCFWLT_INCR' , 'CATCHINCR0024' , - 'QCFSAT_INCR' , 'CATCHINCR0024' , - 'QCFTRN_INCR' , 'CATCHINCR0024' , - 'QCFWLT_INCR' , 'CATCHINCR0024' , - 'CAPAC_INCR' , 'CATCHINCR0024' , - 'CATDEF_INCR' , 'CATCHINCR0024' , - 'RZEXC_INCR' , 'CATCHINCR0024' , - 'SRFEXC_INCR' , 'CATCHINCR0024' , - 'GHTCNT1_INCR' , 'CATCHINCR0024' , - 'GHTCNT2_INCR' , 'CATCHINCR0024' , - 'GHTCNT3_INCR' , 'CATCHINCR0024' , - 'GHTCNT4_INCR' , 'CATCHINCR0024' , - 'GHTCNT5_INCR' , 'CATCHINCR0024' , - 'GHTCNT6_INCR' , 'CATCHINCR0024' , - 'WESNN1_INCR' , 'CATCHINCR0024' , - 'WESNN2_INCR' , 'CATCHINCR0024' , - 'WESNN3_INCR' , 'CATCHINCR0024' , - 'HTSNNN1_INCR' , 'CATCHINCR0024' , - 'HTSNNN2_INCR' , 'CATCHINCR0024' , - 'HTSNNN3_INCR' , 'CATCHINCR0024' , - 'SNDZN1_INCR' , 'CATCHINCR0024' , - 'SNDZN2_INCR' , 'CATCHINCR0024' , - 'SNDZN3_INCR' , 'CATCHINCR0024' , +catch_progn_incr0024.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0024' , + 'TCFTRN_INCR' , 'CATCHINCR_e0024' , + 'TCFWLT_INCR' , 'CATCHINCR_e0024' , + 'QCFSAT_INCR' , 'CATCHINCR_e0024' , + 'QCFTRN_INCR' , 'CATCHINCR_e0024' , + 'QCFWLT_INCR' , 'CATCHINCR_e0024' , + 'CAPAC_INCR' , 'CATCHINCR_e0024' , + 'CATDEF_INCR' , 'CATCHINCR_e0024' , + 'RZEXC_INCR' , 'CATCHINCR_e0024' , + 'SRFEXC_INCR' , 'CATCHINCR_e0024' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0024' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0024' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0024' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0024' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0024' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0024' , + 'WESNN1_INCR' , 'CATCHINCR_e0024' , + 'WESNN2_INCR' , 'CATCHINCR_e0024' , + 'WESNN3_INCR' , 'CATCHINCR_e0024' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0024' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0024' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0024' , + 'SNDZN1_INCR' , 'CATCHINCR_e0024' , + 'SNDZN2_INCR' , 'CATCHINCR_e0024' , + 'SNDZN3_INCR' , 'CATCHINCR_e0024' , :: catch_progn_incr0025.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -878,31 +823,31 @@ catch_progn_incr0025.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0025.mode: 'instantaneous', catch_progn_incr0025.frequency: 030000, catch_progn_incr0025.ref_time: 013000, -catch_progn_incr0025.fields: 'TCFSAT_INCR' , 'CATCHINCR0025' , - 'TCFTRN_INCR' , 'CATCHINCR0025' , - 'TCFWLT_INCR' , 'CATCHINCR0025' , - 'QCFSAT_INCR' , 'CATCHINCR0025' , - 'QCFTRN_INCR' , 'CATCHINCR0025' , - 'QCFWLT_INCR' , 'CATCHINCR0025' , - 'CAPAC_INCR' , 'CATCHINCR0025' , - 'CATDEF_INCR' , 'CATCHINCR0025' , - 'RZEXC_INCR' , 'CATCHINCR0025' , - 'SRFEXC_INCR' , 'CATCHINCR0025' , - 'GHTCNT1_INCR' , 'CATCHINCR0025' , - 'GHTCNT2_INCR' , 'CATCHINCR0025' , - 'GHTCNT3_INCR' , 'CATCHINCR0025' , - 'GHTCNT4_INCR' , 'CATCHINCR0025' , - 'GHTCNT5_INCR' , 'CATCHINCR0025' , - 'GHTCNT6_INCR' , 'CATCHINCR0025' , - 'WESNN1_INCR' , 'CATCHINCR0025' , - 'WESNN2_INCR' , 'CATCHINCR0025' , - 'WESNN3_INCR' , 'CATCHINCR0025' , - 'HTSNNN1_INCR' , 'CATCHINCR0025' , - 'HTSNNN2_INCR' , 'CATCHINCR0025' , - 'HTSNNN3_INCR' , 'CATCHINCR0025' , - 'SNDZN1_INCR' , 'CATCHINCR0025' , - 'SNDZN2_INCR' , 'CATCHINCR0025' , - 'SNDZN3_INCR' , 'CATCHINCR0025' , +catch_progn_incr0025.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0025' , + 'TCFTRN_INCR' , 'CATCHINCR_e0025' , + 'TCFWLT_INCR' , 'CATCHINCR_e0025' , + 'QCFSAT_INCR' , 'CATCHINCR_e0025' , + 'QCFTRN_INCR' , 'CATCHINCR_e0025' , + 'QCFWLT_INCR' , 'CATCHINCR_e0025' , + 'CAPAC_INCR' , 'CATCHINCR_e0025' , + 'CATDEF_INCR' , 'CATCHINCR_e0025' , + 'RZEXC_INCR' , 'CATCHINCR_e0025' , + 'SRFEXC_INCR' , 'CATCHINCR_e0025' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0025' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0025' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0025' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0025' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0025' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0025' , + 'WESNN1_INCR' , 'CATCHINCR_e0025' , + 'WESNN2_INCR' , 'CATCHINCR_e0025' , + 'WESNN3_INCR' , 'CATCHINCR_e0025' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0025' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0025' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0025' , + 'SNDZN1_INCR' , 'CATCHINCR_e0025' , + 'SNDZN2_INCR' , 'CATCHINCR_e0025' , + 'SNDZN3_INCR' , 'CATCHINCR_e0025' , :: catch_progn_incr0026.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -910,31 +855,31 @@ catch_progn_incr0026.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0026.mode: 'instantaneous', catch_progn_incr0026.frequency: 030000, catch_progn_incr0026.ref_time: 013000, -catch_progn_incr0026.fields: 'TCFSAT_INCR' , 'CATCHINCR0026' , - 'TCFTRN_INCR' , 'CATCHINCR0026' , - 'TCFWLT_INCR' , 'CATCHINCR0026' , - 'QCFSAT_INCR' , 'CATCHINCR0026' , - 'QCFTRN_INCR' , 'CATCHINCR0026' , - 'QCFWLT_INCR' , 'CATCHINCR0026' , - 'CAPAC_INCR' , 'CATCHINCR0026' , - 'CATDEF_INCR' , 'CATCHINCR0026' , - 'RZEXC_INCR' , 'CATCHINCR0026' , - 'SRFEXC_INCR' , 'CATCHINCR0026' , - 'GHTCNT1_INCR' , 'CATCHINCR0026' , - 'GHTCNT2_INCR' , 'CATCHINCR0026' , - 'GHTCNT3_INCR' , 'CATCHINCR0026' , - 'GHTCNT4_INCR' , 'CATCHINCR0026' , - 'GHTCNT5_INCR' , 'CATCHINCR0026' , - 'GHTCNT6_INCR' , 'CATCHINCR0026' , - 'WESNN1_INCR' , 'CATCHINCR0026' , - 'WESNN2_INCR' , 'CATCHINCR0026' , - 'WESNN3_INCR' , 'CATCHINCR0026' , - 'HTSNNN1_INCR' , 'CATCHINCR0026' , - 'HTSNNN2_INCR' , 'CATCHINCR0026' , - 'HTSNNN3_INCR' , 'CATCHINCR0026' , - 'SNDZN1_INCR' , 'CATCHINCR0026' , - 'SNDZN2_INCR' , 'CATCHINCR0026' , - 'SNDZN3_INCR' , 'CATCHINCR0026' , +catch_progn_incr0026.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0026' , + 'TCFTRN_INCR' , 'CATCHINCR_e0026' , + 'TCFWLT_INCR' , 'CATCHINCR_e0026' , + 'QCFSAT_INCR' , 'CATCHINCR_e0026' , + 'QCFTRN_INCR' , 'CATCHINCR_e0026' , + 'QCFWLT_INCR' , 'CATCHINCR_e0026' , + 'CAPAC_INCR' , 'CATCHINCR_e0026' , + 'CATDEF_INCR' , 'CATCHINCR_e0026' , + 'RZEXC_INCR' , 'CATCHINCR_e0026' , + 'SRFEXC_INCR' , 'CATCHINCR_e0026' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0026' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0026' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0026' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0026' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0026' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0026' , + 'WESNN1_INCR' , 'CATCHINCR_e0026' , + 'WESNN2_INCR' , 'CATCHINCR_e0026' , + 'WESNN3_INCR' , 'CATCHINCR_e0026' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0026' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0026' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0026' , + 'SNDZN1_INCR' , 'CATCHINCR_e0026' , + 'SNDZN2_INCR' , 'CATCHINCR_e0026' , + 'SNDZN3_INCR' , 'CATCHINCR_e0026' , :: catch_progn_incr0027.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -942,31 +887,31 @@ catch_progn_incr0027.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0027.mode: 'instantaneous', catch_progn_incr0027.frequency: 030000, catch_progn_incr0027.ref_time: 013000, -catch_progn_incr0027.fields: 'TCFSAT_INCR' , 'CATCHINCR0027' , - 'TCFTRN_INCR' , 'CATCHINCR0027' , - 'TCFWLT_INCR' , 'CATCHINCR0027' , - 'QCFSAT_INCR' , 'CATCHINCR0027' , - 'QCFTRN_INCR' , 'CATCHINCR0027' , - 'QCFWLT_INCR' , 'CATCHINCR0027' , - 'CAPAC_INCR' , 'CATCHINCR0027' , - 'CATDEF_INCR' , 'CATCHINCR0027' , - 'RZEXC_INCR' , 'CATCHINCR0027' , - 'SRFEXC_INCR' , 'CATCHINCR0027' , - 'GHTCNT1_INCR' , 'CATCHINCR0027' , - 'GHTCNT2_INCR' , 'CATCHINCR0027' , - 'GHTCNT3_INCR' , 'CATCHINCR0027' , - 'GHTCNT4_INCR' , 'CATCHINCR0027' , - 'GHTCNT5_INCR' , 'CATCHINCR0027' , - 'GHTCNT6_INCR' , 'CATCHINCR0027' , - 'WESNN1_INCR' , 'CATCHINCR0027' , - 'WESNN2_INCR' , 'CATCHINCR0027' , - 'WESNN3_INCR' , 'CATCHINCR0027' , - 'HTSNNN1_INCR' , 'CATCHINCR0027' , - 'HTSNNN2_INCR' , 'CATCHINCR0027' , - 'HTSNNN3_INCR' , 'CATCHINCR0027' , - 'SNDZN1_INCR' , 'CATCHINCR0027' , - 'SNDZN2_INCR' , 'CATCHINCR0027' , - 'SNDZN3_INCR' , 'CATCHINCR0027' , +catch_progn_incr0027.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0027' , + 'TCFTRN_INCR' , 'CATCHINCR_e0027' , + 'TCFWLT_INCR' , 'CATCHINCR_e0027' , + 'QCFSAT_INCR' , 'CATCHINCR_e0027' , + 'QCFTRN_INCR' , 'CATCHINCR_e0027' , + 'QCFWLT_INCR' , 'CATCHINCR_e0027' , + 'CAPAC_INCR' , 'CATCHINCR_e0027' , + 'CATDEF_INCR' , 'CATCHINCR_e0027' , + 'RZEXC_INCR' , 'CATCHINCR_e0027' , + 'SRFEXC_INCR' , 'CATCHINCR_e0027' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0027' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0027' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0027' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0027' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0027' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0027' , + 'WESNN1_INCR' , 'CATCHINCR_e0027' , + 'WESNN2_INCR' , 'CATCHINCR_e0027' , + 'WESNN3_INCR' , 'CATCHINCR_e0027' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0027' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0027' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0027' , + 'SNDZN1_INCR' , 'CATCHINCR_e0027' , + 'SNDZN2_INCR' , 'CATCHINCR_e0027' , + 'SNDZN3_INCR' , 'CATCHINCR_e0027' , :: catch_progn_incr0028.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -974,31 +919,31 @@ catch_progn_incr0028.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0028.mode: 'instantaneous', catch_progn_incr0028.frequency: 030000, catch_progn_incr0028.ref_time: 013000, -catch_progn_incr0028.fields: 'TCFSAT_INCR' , 'CATCHINCR0028' , - 'TCFTRN_INCR' , 'CATCHINCR0028' , - 'TCFWLT_INCR' , 'CATCHINCR0028' , - 'QCFSAT_INCR' , 'CATCHINCR0028' , - 'QCFTRN_INCR' , 'CATCHINCR0028' , - 'QCFWLT_INCR' , 'CATCHINCR0028' , - 'CAPAC_INCR' , 'CATCHINCR0028' , - 'CATDEF_INCR' , 'CATCHINCR0028' , - 'RZEXC_INCR' , 'CATCHINCR0028' , - 'SRFEXC_INCR' , 'CATCHINCR0028' , - 'GHTCNT1_INCR' , 'CATCHINCR0028' , - 'GHTCNT2_INCR' , 'CATCHINCR0028' , - 'GHTCNT3_INCR' , 'CATCHINCR0028' , - 'GHTCNT4_INCR' , 'CATCHINCR0028' , - 'GHTCNT5_INCR' , 'CATCHINCR0028' , - 'GHTCNT6_INCR' , 'CATCHINCR0028' , - 'WESNN1_INCR' , 'CATCHINCR0028' , - 'WESNN2_INCR' , 'CATCHINCR0028' , - 'WESNN3_INCR' , 'CATCHINCR0028' , - 'HTSNNN1_INCR' , 'CATCHINCR0028' , - 'HTSNNN2_INCR' , 'CATCHINCR0028' , - 'HTSNNN3_INCR' , 'CATCHINCR0028' , - 'SNDZN1_INCR' , 'CATCHINCR0028' , - 'SNDZN2_INCR' , 'CATCHINCR0028' , - 'SNDZN3_INCR' , 'CATCHINCR0028' , +catch_progn_incr0028.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0028' , + 'TCFTRN_INCR' , 'CATCHINCR_e0028' , + 'TCFWLT_INCR' , 'CATCHINCR_e0028' , + 'QCFSAT_INCR' , 'CATCHINCR_e0028' , + 'QCFTRN_INCR' , 'CATCHINCR_e0028' , + 'QCFWLT_INCR' , 'CATCHINCR_e0028' , + 'CAPAC_INCR' , 'CATCHINCR_e0028' , + 'CATDEF_INCR' , 'CATCHINCR_e0028' , + 'RZEXC_INCR' , 'CATCHINCR_e0028' , + 'SRFEXC_INCR' , 'CATCHINCR_e0028' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0028' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0028' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0028' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0028' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0028' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0028' , + 'WESNN1_INCR' , 'CATCHINCR_e0028' , + 'WESNN2_INCR' , 'CATCHINCR_e0028' , + 'WESNN3_INCR' , 'CATCHINCR_e0028' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0028' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0028' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0028' , + 'SNDZN1_INCR' , 'CATCHINCR_e0028' , + 'SNDZN2_INCR' , 'CATCHINCR_e0028' , + 'SNDZN3_INCR' , 'CATCHINCR_e0028' , :: catch_progn_incr0029.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -1006,31 +951,31 @@ catch_progn_incr0029.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0029.mode: 'instantaneous', catch_progn_incr0029.frequency: 030000, catch_progn_incr0029.ref_time: 013000, -catch_progn_incr0029.fields: 'TCFSAT_INCR' , 'CATCHINCR0029' , - 'TCFTRN_INCR' , 'CATCHINCR0029' , - 'TCFWLT_INCR' , 'CATCHINCR0029' , - 'QCFSAT_INCR' , 'CATCHINCR0029' , - 'QCFTRN_INCR' , 'CATCHINCR0029' , - 'QCFWLT_INCR' , 'CATCHINCR0029' , - 'CAPAC_INCR' , 'CATCHINCR0029' , - 'CATDEF_INCR' , 'CATCHINCR0029' , - 'RZEXC_INCR' , 'CATCHINCR0029' , - 'SRFEXC_INCR' , 'CATCHINCR0029' , - 'GHTCNT1_INCR' , 'CATCHINCR0029' , - 'GHTCNT2_INCR' , 'CATCHINCR0029' , - 'GHTCNT3_INCR' , 'CATCHINCR0029' , - 'GHTCNT4_INCR' , 'CATCHINCR0029' , - 'GHTCNT5_INCR' , 'CATCHINCR0029' , - 'GHTCNT6_INCR' , 'CATCHINCR0029' , - 'WESNN1_INCR' , 'CATCHINCR0029' , - 'WESNN2_INCR' , 'CATCHINCR0029' , - 'WESNN3_INCR' , 'CATCHINCR0029' , - 'HTSNNN1_INCR' , 'CATCHINCR0029' , - 'HTSNNN2_INCR' , 'CATCHINCR0029' , - 'HTSNNN3_INCR' , 'CATCHINCR0029' , - 'SNDZN1_INCR' , 'CATCHINCR0029' , - 'SNDZN2_INCR' , 'CATCHINCR0029' , - 'SNDZN3_INCR' , 'CATCHINCR0029' , +catch_progn_incr0029.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0029' , + 'TCFTRN_INCR' , 'CATCHINCR_e0029' , + 'TCFWLT_INCR' , 'CATCHINCR_e0029' , + 'QCFSAT_INCR' , 'CATCHINCR_e0029' , + 'QCFTRN_INCR' , 'CATCHINCR_e0029' , + 'QCFWLT_INCR' , 'CATCHINCR_e0029' , + 'CAPAC_INCR' , 'CATCHINCR_e0029' , + 'CATDEF_INCR' , 'CATCHINCR_e0029' , + 'RZEXC_INCR' , 'CATCHINCR_e0029' , + 'SRFEXC_INCR' , 'CATCHINCR_e0029' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0029' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0029' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0029' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0029' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0029' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0029' , + 'WESNN1_INCR' , 'CATCHINCR_e0029' , + 'WESNN2_INCR' , 'CATCHINCR_e0029' , + 'WESNN3_INCR' , 'CATCHINCR_e0029' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0029' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0029' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0029' , + 'SNDZN1_INCR' , 'CATCHINCR_e0029' , + 'SNDZN2_INCR' , 'CATCHINCR_e0029' , + 'SNDZN3_INCR' , 'CATCHINCR_e0029' , :: catch_progn_incr0030.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -1038,31 +983,31 @@ catch_progn_incr0030.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0030.mode: 'instantaneous', catch_progn_incr0030.frequency: 030000, catch_progn_incr0030.ref_time: 013000, -catch_progn_incr0030.fields: 'TCFSAT_INCR' , 'CATCHINCR0030' , - 'TCFTRN_INCR' , 'CATCHINCR0030' , - 'TCFWLT_INCR' , 'CATCHINCR0030' , - 'QCFSAT_INCR' , 'CATCHINCR0030' , - 'QCFTRN_INCR' , 'CATCHINCR0030' , - 'QCFWLT_INCR' , 'CATCHINCR0030' , - 'CAPAC_INCR' , 'CATCHINCR0030' , - 'CATDEF_INCR' , 'CATCHINCR0030' , - 'RZEXC_INCR' , 'CATCHINCR0030' , - 'SRFEXC_INCR' , 'CATCHINCR0030' , - 'GHTCNT1_INCR' , 'CATCHINCR0030' , - 'GHTCNT2_INCR' , 'CATCHINCR0030' , - 'GHTCNT3_INCR' , 'CATCHINCR0030' , - 'GHTCNT4_INCR' , 'CATCHINCR0030' , - 'GHTCNT5_INCR' , 'CATCHINCR0030' , - 'GHTCNT6_INCR' , 'CATCHINCR0030' , - 'WESNN1_INCR' , 'CATCHINCR0030' , - 'WESNN2_INCR' , 'CATCHINCR0030' , - 'WESNN3_INCR' , 'CATCHINCR0030' , - 'HTSNNN1_INCR' , 'CATCHINCR0030' , - 'HTSNNN2_INCR' , 'CATCHINCR0030' , - 'HTSNNN3_INCR' , 'CATCHINCR0030' , - 'SNDZN1_INCR' , 'CATCHINCR0030' , - 'SNDZN2_INCR' , 'CATCHINCR0030' , - 'SNDZN3_INCR' , 'CATCHINCR0030' , +catch_progn_incr0030.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0030' , + 'TCFTRN_INCR' , 'CATCHINCR_e0030' , + 'TCFWLT_INCR' , 'CATCHINCR_e0030' , + 'QCFSAT_INCR' , 'CATCHINCR_e0030' , + 'QCFTRN_INCR' , 'CATCHINCR_e0030' , + 'QCFWLT_INCR' , 'CATCHINCR_e0030' , + 'CAPAC_INCR' , 'CATCHINCR_e0030' , + 'CATDEF_INCR' , 'CATCHINCR_e0030' , + 'RZEXC_INCR' , 'CATCHINCR_e0030' , + 'SRFEXC_INCR' , 'CATCHINCR_e0030' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0030' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0030' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0030' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0030' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0030' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0030' , + 'WESNN1_INCR' , 'CATCHINCR_e0030' , + 'WESNN2_INCR' , 'CATCHINCR_e0030' , + 'WESNN3_INCR' , 'CATCHINCR_e0030' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0030' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0030' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0030' , + 'SNDZN1_INCR' , 'CATCHINCR_e0030' , + 'SNDZN2_INCR' , 'CATCHINCR_e0030' , + 'SNDZN3_INCR' , 'CATCHINCR_e0030' , :: catch_progn_incr0031.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -1070,31 +1015,31 @@ catch_progn_incr0031.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0031.mode: 'instantaneous', catch_progn_incr0031.frequency: 030000, catch_progn_incr0031.ref_time: 013000, -catch_progn_incr0031.fields: 'TCFSAT_INCR' , 'CATCHINCR0031' , - 'TCFTRN_INCR' , 'CATCHINCR0031' , - 'TCFWLT_INCR' , 'CATCHINCR0031' , - 'QCFSAT_INCR' , 'CATCHINCR0031' , - 'QCFTRN_INCR' , 'CATCHINCR0031' , - 'QCFWLT_INCR' , 'CATCHINCR0031' , - 'CAPAC_INCR' , 'CATCHINCR0031' , - 'CATDEF_INCR' , 'CATCHINCR0031' , - 'RZEXC_INCR' , 'CATCHINCR0031' , - 'SRFEXC_INCR' , 'CATCHINCR0031' , - 'GHTCNT1_INCR' , 'CATCHINCR0031' , - 'GHTCNT2_INCR' , 'CATCHINCR0031' , - 'GHTCNT3_INCR' , 'CATCHINCR0031' , - 'GHTCNT4_INCR' , 'CATCHINCR0031' , - 'GHTCNT5_INCR' , 'CATCHINCR0031' , - 'GHTCNT6_INCR' , 'CATCHINCR0031' , - 'WESNN1_INCR' , 'CATCHINCR0031' , - 'WESNN2_INCR' , 'CATCHINCR0031' , - 'WESNN3_INCR' , 'CATCHINCR0031' , - 'HTSNNN1_INCR' , 'CATCHINCR0031' , - 'HTSNNN2_INCR' , 'CATCHINCR0031' , - 'HTSNNN3_INCR' , 'CATCHINCR0031' , - 'SNDZN1_INCR' , 'CATCHINCR0031' , - 'SNDZN2_INCR' , 'CATCHINCR0031' , - 'SNDZN3_INCR' , 'CATCHINCR0031' , +catch_progn_incr0031.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0031' , + 'TCFTRN_INCR' , 'CATCHINCR_e0031' , + 'TCFWLT_INCR' , 'CATCHINCR_e0031' , + 'QCFSAT_INCR' , 'CATCHINCR_e0031' , + 'QCFTRN_INCR' , 'CATCHINCR_e0031' , + 'QCFWLT_INCR' , 'CATCHINCR_e0031' , + 'CAPAC_INCR' , 'CATCHINCR_e0031' , + 'CATDEF_INCR' , 'CATCHINCR_e0031' , + 'RZEXC_INCR' , 'CATCHINCR_e0031' , + 'SRFEXC_INCR' , 'CATCHINCR_e0031' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0031' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0031' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0031' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0031' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0031' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0031' , + 'WESNN1_INCR' , 'CATCHINCR_e0031' , + 'WESNN2_INCR' , 'CATCHINCR_e0031' , + 'WESNN3_INCR' , 'CATCHINCR_e0031' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0031' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0031' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0031' , + 'SNDZN1_INCR' , 'CATCHINCR_e0031' , + 'SNDZN2_INCR' , 'CATCHINCR_e0031' , + 'SNDZN3_INCR' , 'CATCHINCR_e0031' , :: catch_progn_incr0032.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -1102,31 +1047,30 @@ catch_progn_incr0032.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0032.mode: 'instantaneous', catch_progn_incr0032.frequency: 030000, catch_progn_incr0032.ref_time: 013000, -catch_progn_incr0032.fields: 'TCFSAT_INCR' , 'CATCHINCR0031' , - 'TCFTRN_INCR' , 'CATCHINCR0032' , - 'TCFWLT_INCR' , 'CATCHINCR0032' , - 'QCFSAT_INCR' , 'CATCHINCR0032' , - 'QCFTRN_INCR' , 'CATCHINCR0032' , - 'QCFWLT_INCR' , 'CATCHINCR0032' , - 'CAPAC_INCR' , 'CATCHINCR0032' , - 'CATDEF_INCR' , 'CATCHINCR0032' , - 'RZEXC_INCR' , 'CATCHINCR0032' , - 'SRFEXC_INCR' , 'CATCHINCR0032' , - 'GHTCNT1_INCR' , 'CATCHINCR0032' , - 'GHTCNT2_INCR' , 'CATCHINCR0032' , - 'GHTCNT3_INCR' , 'CATCHINCR0032' , - 'GHTCNT4_INCR' , 'CATCHINCR0032' , - 'GHTCNT5_INCR' , 'CATCHINCR0032' , - 'GHTCNT6_INCR' , 'CATCHINCR0032' , - 'WESNN1_INCR' , 'CATCHINCR0032' , - 'WESNN2_INCR' , 'CATCHINCR0032' , - 'WESNN3_INCR' , 'CATCHINCR0032' , - 'HTSNNN1_INCR' , 'CATCHINCR0032' , - 'HTSNNN2_INCR' , 'CATCHINCR0032' , - 'HTSNNN3_INCR' , 'CATCHINCR0032' , - 'SNDZN1_INCR' , 'CATCHINCR0032' , - 'SNDZN2_INCR' , 'CATCHINCR0032' , - 'SNDZN3_INCR' , 'CATCHINCR0032' , +catch_progn_incr0032.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0032' , + 'TCFTRN_INCR' , 'CATCHINCR_e0032' , + 'TCFWLT_INCR' , 'CATCHINCR_e0032' , + 'QCFSAT_INCR' , 'CATCHINCR_e0032' , + 'QCFTRN_INCR' , 'CATCHINCR_e0032' , + 'QCFWLT_INCR' , 'CATCHINCR_e0032' , + 'CAPAC_INCR' , 'CATCHINCR_e0032' , + 'CATDEF_INCR' , 'CATCHINCR_e0032' , + 'RZEXC_INCR' , 'CATCHINCR_e0032' , + 'SRFEXC_INCR' , 'CATCHINCR_e0032' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0032' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0032' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0032' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0032' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0032' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0032' , + 'WESNN1_INCR' , 'CATCHINCR_e0032' , + 'WESNN2_INCR' , 'CATCHINCR_e0032' , + 'WESNN3_INCR' , 'CATCHINCR_e0032' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0032' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0032' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0032' , + 'SNDZN1_INCR' , 'CATCHINCR_e0032' , + 'SNDZN2_INCR' , 'CATCHINCR_e0032' , + 'SNDZN3_INCR' , 'CATCHINCR_e0032' , :: - diff --git a/src/Applications/LDAS_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.central b/src/Applications/LDAS_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.central index 34d69d97..c30c880a 100644 --- a/src/Applications/LDAS_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.central +++ b/src/Applications/LDAS_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.central @@ -16,7 +16,7 @@ LADAS_COUPLING: 1 ADAS_EXPDIR: [full_path]/[ADAS_EXPDIR] MET_TAG: [ADAS_EXPID]__Nx+- -MET_PATH: [ADAS_EXPDIR]/lana/forc +MET_PATH: ../../scratch # option to use perturbed forcing created from central simulation and atm ensemble # MET_PATH: [ADAS_EXPDIR]/atmens/rgdlfo diff --git a/src/Applications/LDAS_App/util/config/generate_catchincr_hist.py b/src/Applications/LDAS_App/util/config/generate_catchincr_hist.py index 8d6d6d51..56baf9d9 100644 --- a/src/Applications/LDAS_App/util/config/generate_catchincr_hist.py +++ b/src/Applications/LDAS_App/util/config/generate_catchincr_hist.py @@ -7,24 +7,27 @@ import subprocess as sp heads = """ -VERSION: 1 -EXPID: GEOSldas_expid -EXPDSC: GEOSldas_output -EXPSRC: GEOSldas +# +# Sample GEOSldas HISTORY.rc file for LADAS (atm ensemble) +# +# This sample is for the GEOSldas instance that is coupled with the atmospheric +# ensemble component of the Hy4dEnVar ADAS: +# +# (1) The definition of the "catch_progn_incr" ensemble collection was generated +# with the utility script "generate_catchincr_hist.py", with the number of +# ensemble members and their indexing matching those of the atmospheric +# ensemble component of the Hy4dEnVar ADAS. +# (2) The "catch_progn_incr" output is in tile space. Its definition is generic +# for any LADAS resolution. +# +################################################################################## + +EXPID: MyGEOSldasAtmEns COLLECTIONS: """ label = """ -:: -GRID_LABELS: PC720x361-DC -:: -PC720x361-DC.GRID_TYPE: LatLon -PC720x361-DC.IM_WORLD: 720 -PC720x361-DC.JM_WORLD: 361 -PC720x361-DC.POLE: PC -PC720x361-DC.DATELINE: DC -PC720x361-DC.LM: 1 """ hist_template = """ @@ -34,32 +37,32 @@ template: '%y4%m2%d2_%h2%n2z.bin', mode: 'instantaneous', frequency: 030000, -ref_time: 000000, -fields: 'TCFSAT_INCR' , 'CATCHINCR' , - 'TCFTRN_INCR' , 'CATCHINCR' , - 'TCFWLT_INCR' , 'CATCHINCR' , - 'QCFSAT_INCR' , 'CATCHINCR' , - 'QCFTRN_INCR' , 'CATCHINCR' , - 'QCFWLT_INCR' , 'CATCHINCR' , - 'CAPAC_INCR' , 'CATCHINCR' , - 'CATDEF_INCR' , 'CATCHINCR' , - 'RZEXC_INCR' , 'CATCHINCR' , - 'SRFEXC_INCR' , 'CATCHINCR' , - 'GHTCNT1_INCR' , 'CATCHINCR' , - 'GHTCNT2_INCR' , 'CATCHINCR' , - 'GHTCNT3_INCR' , 'CATCHINCR' , - 'GHTCNT4_INCR' , 'CATCHINCR' , - 'GHTCNT5_INCR' , 'CATCHINCR' , - 'GHTCNT6_INCR' , 'CATCHINCR' , - 'WESNN1_INCR' , 'CATCHINCR' , - 'WESNN2_INCR' , 'CATCHINCR' , - 'WESNN3_INCR' , 'CATCHINCR' , - 'HTSNNN1_INCR' , 'CATCHINCR' , - 'HTSNNN2_INCR' , 'CATCHINCR' , - 'HTSNNN3_INCR' , 'CATCHINCR' , - 'SNDZN1_INCR' , 'CATCHINCR' , - 'SNDZN2_INCR' , 'CATCHINCR' , - 'SNDZN3_INCR' , 'CATCHINCR' , +ref_time: 013000, +fields: 'TCFSAT_INCR' , 'CATCHINCR_e' , + 'TCFTRN_INCR' , 'CATCHINCR_e' , + 'TCFWLT_INCR' , 'CATCHINCR_e' , + 'QCFSAT_INCR' , 'CATCHINCR_e' , + 'QCFTRN_INCR' , 'CATCHINCR_e' , + 'QCFWLT_INCR' , 'CATCHINCR_e' , + 'CAPAC_INCR' , 'CATCHINCR_e' , + 'CATDEF_INCR' , 'CATCHINCR_e' , + 'RZEXC_INCR' , 'CATCHINCR_e' , + 'SRFEXC_INCR' , 'CATCHINCR_e' , + 'GHTCNT1_INCR' , 'CATCHINCR_e' , + 'GHTCNT2_INCR' , 'CATCHINCR_e' , + 'GHTCNT3_INCR' , 'CATCHINCR_e' , + 'GHTCNT4_INCR' , 'CATCHINCR_e' , + 'GHTCNT5_INCR' , 'CATCHINCR_e' , + 'GHTCNT6_INCR' , 'CATCHINCR_e' , + 'WESNN1_INCR' , 'CATCHINCR_e' , + 'WESNN2_INCR' , 'CATCHINCR_e' , + 'WESNN3_INCR' , 'CATCHINCR_e' , + 'HTSNNN1_INCR' , 'CATCHINCR_e' , + 'HTSNNN2_INCR' , 'CATCHINCR_e' , + 'HTSNNN3_INCR' , 'CATCHINCR_e' , + 'SNDZN1_INCR' , 'CATCHINCR_e' , + 'SNDZN2_INCR' , 'CATCHINCR_e' , + 'SNDZN3_INCR' , 'CATCHINCR_e' , """ nens = 32 @@ -68,17 +71,19 @@ collection, body = hist_template.split('::\n') collection = collection.strip('\n').strip("'") for i in range(nens): + i = i +1 ids = collection+f'{i:04}' f.write(f"'{ids}'\n") f.write(label) lines = body.split('\n') for i in range(nens): + i = i+1 collect= collection+f'{i:04}.' for line in lines: newline = line if ":" in line : newline = collect+line - if "CATCHINCR" in newline: - newline = newline.replace('CATCHINCR',f'CATCHINCR{i:04}') + if "CATCHINCR_e" in newline: + newline = newline.replace('CATCHINCR_e',f'CATCHINCR_e{i:04}') f.write(newline+'\n') f.write('::\n') From 4b8b7823ff58281e7f97ec39037115b421e7dafd Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Thu, 1 Feb 2024 17:50:53 -0500 Subject: [PATCH 230/308] edited documentation re. GEOSldas HISTORY output needed for Hybrid-4DEnVar atm ensemble (generate_catchincr_hist.py) --- .../util/config/generate_catchincr_hist.py | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) mode change 100644 => 100755 src/Applications/LDAS_App/util/config/generate_catchincr_hist.py diff --git a/src/Applications/LDAS_App/util/config/generate_catchincr_hist.py b/src/Applications/LDAS_App/util/config/generate_catchincr_hist.py old mode 100644 new mode 100755 index 56baf9d9..e661c4b6 --- a/src/Applications/LDAS_App/util/config/generate_catchincr_hist.py +++ b/src/Applications/LDAS_App/util/config/generate_catchincr_hist.py @@ -2,6 +2,10 @@ # # module load python/GEOSpyD/Ana2019.03_py3.7 # +# This script generates a sample HISTORY.rc file for GEOSldas to write Catchment +# model analysis increments in ensemble space, as needed in the weakly-coupled +# Hybrid-4DEnVar land-atm DAS (LADAS). + import os import glob import subprocess as sp @@ -10,15 +14,21 @@ # # Sample GEOSldas HISTORY.rc file for LADAS (atm ensemble) # -# This sample is for the GEOSldas instance that is coupled with the atmospheric -# ensemble component of the Hy4dEnVar ADAS: +# - This sample HISTORY.rc is for the GEOSldas instance that is weakly coupled with the +# atmospheric ensemble component of the Hybrid-4DEnVar ADAS (ADASens). +# +# - The sample file was generated with the utility script +# "GEOSldas/src/Applications/LDAS_App/util/config/generate_catchincr_hist.py". +# +# - The sample file triggers output of the GEOSldas "catch_progn_incr" collection in +# ensemble space, which is needed by ADASens. +# +# - The IDs of the ensemble members and their total number in GEOSldas must match +# those of ADASens. +# +# - The "catch_progn_incr" output is in tile space, which must be the same for +# GEOSldas and ADASens. # -# (1) The definition of the "catch_progn_incr" ensemble collection was generated -# with the utility script "generate_catchincr_hist.py", with the number of -# ensemble members and their indexing matching those of the atmospheric -# ensemble component of the Hy4dEnVar ADAS. -# (2) The "catch_progn_incr" output is in tile space. Its definition is generic -# for any LADAS resolution. # ################################################################################## @@ -27,9 +37,6 @@ COLLECTIONS: """ -label = """ -""" - hist_template = """ 'catch_progn_incr' :: @@ -74,7 +81,6 @@ i = i +1 ids = collection+f'{i:04}' f.write(f"'{ids}'\n") - f.write(label) lines = body.split('\n') for i in range(nens): i = i+1 From 3724d843fe8bda15aa4e9965bdde95f05fea6929 Mon Sep 17 00:00:00 2001 From: saraqzhang Date: Thu, 1 Feb 2024 21:50:15 -0500 Subject: [PATCH 231/308] merge the text edit in py, re-generated HISTORY.rc.atmens --- .../LADAS/HISTORY.rc.atmens | 22 ++++++++++------ .../util/config/generate_catchincr_hist.py | 26 +++++++++++++------ 2 files changed, 32 insertions(+), 16 deletions(-) diff --git a/src/Applications/LDAS_App/sample_config_files/LADAS/HISTORY.rc.atmens b/src/Applications/LDAS_App/sample_config_files/LADAS/HISTORY.rc.atmens index 62f3d1ac..498fcfcc 100644 --- a/src/Applications/LDAS_App/sample_config_files/LADAS/HISTORY.rc.atmens +++ b/src/Applications/LDAS_App/sample_config_files/LADAS/HISTORY.rc.atmens @@ -2,15 +2,21 @@ # # Sample GEOSldas HISTORY.rc file for LADAS (atm ensemble) # -# This sample is for the GEOSldas instance that is coupled with the atmospheric -# ensemble component of the Hy4dEnVar ADAS: +# - This sample HISTORY.rc is for the GEOSldas instance that is weakly coupled with the +# atmospheric ensemble component of the Hybrid-4DEnVar ADAS (ADASens). +# +# - The sample file was generated with the utility script +# "GEOSldas/src/Applications/LDAS_App/util/config/generate_catchincr_hist.py". +# +# - The sample file triggers output of the GEOSldas "catch_progn_incr" collection in +# ensemble space, which is needed by ADASens. +# +# - The IDs of the ensemble members and their total number in GEOSldas must match +# those of ADASens. +# +# - The "catch_progn_incr" output is in tile space, which must be the same for +# GEOSldas and ADASens. # -# (1) The definition of the "catch_progn_incr" ensemble collection was generated -# with the utility script "generate_catchincr_hist.py", with the number of -# ensemble members and their indexing matching those of the atmospheric -# ensemble component of the Hy4dEnVar ADAS. -# (2) The "catch_progn_incr" output is in tile space. Its definition is generic -# for any LADAS resolution. # ################################################################################## diff --git a/src/Applications/LDAS_App/util/config/generate_catchincr_hist.py b/src/Applications/LDAS_App/util/config/generate_catchincr_hist.py index 56baf9d9..1e36ba86 100644 --- a/src/Applications/LDAS_App/util/config/generate_catchincr_hist.py +++ b/src/Applications/LDAS_App/util/config/generate_catchincr_hist.py @@ -2,6 +2,10 @@ # # module load python/GEOSpyD/Ana2019.03_py3.7 # +# This script generates a sample HISTORY.rc file for GEOSldas to write Catchment +# model analysis increments in ensemble space, as needed in the weakly-coupled +# Hybrid-4DEnVar land-atm DAS (LADAS). + import os import glob import subprocess as sp @@ -10,15 +14,21 @@ # # Sample GEOSldas HISTORY.rc file for LADAS (atm ensemble) # -# This sample is for the GEOSldas instance that is coupled with the atmospheric -# ensemble component of the Hy4dEnVar ADAS: +# - This sample HISTORY.rc is for the GEOSldas instance that is weakly coupled with the +# atmospheric ensemble component of the Hybrid-4DEnVar ADAS (ADASens). +# +# - The sample file was generated with the utility script +# "GEOSldas/src/Applications/LDAS_App/util/config/generate_catchincr_hist.py". +# +# - The sample file triggers output of the GEOSldas "catch_progn_incr" collection in +# ensemble space, which is needed by ADASens. +# +# - The IDs of the ensemble members and their total number in GEOSldas must match +# those of ADASens. +# +# - The "catch_progn_incr" output is in tile space, which must be the same for +# GEOSldas and ADASens. # -# (1) The definition of the "catch_progn_incr" ensemble collection was generated -# with the utility script "generate_catchincr_hist.py", with the number of -# ensemble members and their indexing matching those of the atmospheric -# ensemble component of the Hy4dEnVar ADAS. -# (2) The "catch_progn_incr" output is in tile space. Its definition is generic -# for any LADAS resolution. # ################################################################################## From 8341312db3ef5197918f1db7fa9b4fbd3fb6225b Mon Sep 17 00:00:00 2001 From: saraqzhang Date: Thu, 1 Feb 2024 22:32:40 -0500 Subject: [PATCH 232/308] incorporate edits in py and re-generate HISTORY.rc --- .../LDAS_App/sample_config_files/LADAS/HISTORY.rc.atmens | 1 + .../LDAS_App/util/config/generate_catchincr_hist.py | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/src/Applications/LDAS_App/sample_config_files/LADAS/HISTORY.rc.atmens b/src/Applications/LDAS_App/sample_config_files/LADAS/HISTORY.rc.atmens index 498fcfcc..0f3e7f1e 100644 --- a/src/Applications/LDAS_App/sample_config_files/LADAS/HISTORY.rc.atmens +++ b/src/Applications/LDAS_App/sample_config_files/LADAS/HISTORY.rc.atmens @@ -56,6 +56,7 @@ COLLECTIONS: 'catch_progn_incr0031' 'catch_progn_incr0032' +:: catch_progn_incr0001.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', catch_progn_incr0001.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0001.mode: 'instantaneous', diff --git a/src/Applications/LDAS_App/util/config/generate_catchincr_hist.py b/src/Applications/LDAS_App/util/config/generate_catchincr_hist.py index e661c4b6..76cdea35 100755 --- a/src/Applications/LDAS_App/util/config/generate_catchincr_hist.py +++ b/src/Applications/LDAS_App/util/config/generate_catchincr_hist.py @@ -37,6 +37,10 @@ COLLECTIONS: """ +label = """ +:: +""" + hist_template = """ 'catch_progn_incr' :: @@ -81,6 +85,7 @@ i = i +1 ids = collection+f'{i:04}' f.write(f"'{ids}'\n") + f.write(label) lines = body.split('\n') for i in range(nens): i = i+1 From edabf78343d22f3dc7e0ad548665f7b0f6c813c9 Mon Sep 17 00:00:00 2001 From: Matthew Thompson Date: Tue, 6 Feb 2024 10:57:48 -0500 Subject: [PATCH 233/308] Update to ESMA_cmake v3.40.0 --- components.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components.yaml b/components.yaml index 664ce5a3..fa43e03d 100644 --- a/components.yaml +++ b/components.yaml @@ -11,7 +11,7 @@ env: cmake: local: ./@cmake remote: ../ESMA_cmake.git - tag: v3.36.0 + tag: v3.40.0 develop: develop ecbuild: From 4b878f053e8321017c4b27bbfe4fe74fdb47d65c Mon Sep 17 00:00:00 2001 From: amfox37 Date: Tue, 6 Feb 2024 15:58:25 -0700 Subject: [PATCH 234/308] LDAS_App tidy up --- src/Applications/LDAS_App/CMakeLists.txt | 5 -- .../LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml | 2 +- .../LDAS_App/decode_ASCAT_ssom.F90 | 47 ------------------- 3 files changed, 1 insertion(+), 53 deletions(-) delete mode 100644 src/Applications/LDAS_App/decode_ASCAT_ssom.F90 diff --git a/src/Applications/LDAS_App/CMakeLists.txt b/src/Applications/LDAS_App/CMakeLists.txt index 99d5028e..f2f5ed36 100644 --- a/src/Applications/LDAS_App/CMakeLists.txt +++ b/src/Applications/LDAS_App/CMakeLists.txt @@ -18,11 +18,6 @@ ecbuild_add_executable ( TARGET mwrtm_bin2nc4.x SOURCES util/inputs/mwRTM_params/mwrtm_bin2nc4.F90 LIBS GEOSlandassim_GridComp) - -ecbuild_add_executable ( - TARGET decode_ASCAT_ssom.x - SOURCES decode_ASCAT_ssom.F90 - LIBS NCEP_bufr_r4i4) set (scripts ldas_setup diff --git a/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml b/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml index 4772ce58..b849d51d 100644 --- a/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml +++ b/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml @@ -32,7 +32,7 @@ ! update_type = 8: 3d soil moisture/Tskin/ght(1); TB obs ! update_type = 9: 1d Tskin/ght1 update; FT obs ! update_type = 10: 3d soil moisture/Tskin/ght(1) excl. catdef unless PEATCLSM tile; TB obs -! update_type = 11: Multivariate combination of 2 and 10; sfmc and TB obs +! update_type = 13: Multivariate combination of 2 and 10; sfmc and TB obs update_type = 0 diff --git a/src/Applications/LDAS_App/decode_ASCAT_ssom.F90 b/src/Applications/LDAS_App/decode_ASCAT_ssom.F90 deleted file mode 100644 index 64d43ad5..00000000 --- a/src/Applications/LDAS_App/decode_ASCAT_ssom.F90 +++ /dev/null @@ -1,47 +0,0 @@ -program decode_ASCAT_ssom - - implicit none - - real*8, dimension(15) :: tmp_vdata - real*8, dimension(:,:), allocatable :: tmp_data - - integer, parameter :: lnbufr = 50 - integer, parameter :: max_obs = 250000 - integer :: idate,iret - integer :: ireadmg,ireadsb - integer :: N_obs - - character(8) :: subset - character(300) :: fname, mastertable_path - -! ------------------------------------------------------------------------- - - fname = '/home/amfox/smap/SMAP_Nature/ASCAT_EUMETSAT/Metop_C/Y2023/M03/' // & - 'M03-ASCA-ASCSMO02-NA-5.0-20230301090900.000000000Z-20230301105557-4839070.bfr' - mastertable_path = '/home/amfox/smap/SMAP_Nature/ASCAT_EUMETSAT' - -! Allocate the tmp_data array - allocate(tmp_data(max_obs, 15)) - - open(lnbufr, file=trim(fname), action='read',form='unformatted') - - call openbf(lnbufr,'SEC3', lnbufr) - call mtinfo( trim(mastertable_path) // '/BUFR_mastertable/', 51, 52) - call datelen(10) - - N_obs = 0 - msg_report: do while(ireadmg(lnbufr,subset,idate) ==0) - loop_report: do while(ireadsb(lnbufr) == 0) - call ufbint(lnbufr,tmp_vdata,15,1,iret,'YEAR MNTH DAYS HOUR MINU SECO SSOM DOMO SMPF SMCF ALFR TPCX IWFR CLATH CLONH') - N_obs = N_obs + 1 - tmp_data(N_obs,:) = tmp_vdata - end do loop_report - end do msg_report - - write(*,*) 'N_obs = ', N_obs - write(*,*) tmp_vdata - - call closbf(lnbufr) - close(lnbufr) - -end program decode_ASCAT_ssom From 7cc37353b8f650576ffa808223bc2660585b3678 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Tue, 6 Feb 2024 17:24:40 -0700 Subject: [PATCH 235/308] tidy up unused variables and debugging --- .../clsm_ensupd_enkf_update.F90 | 2 +- .../clsm_ensupd_upd_routines.F90 | 23 +++++-------------- 2 files changed, 7 insertions(+), 18 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 index 6e1d3aea..30610618 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 @@ -1333,7 +1333,7 @@ subroutine apply_enkf_increments( N_catd, N_ens, update_type, & case (6,8,9,10,13) select_update_type ! soil moisture and temperature update ! for update_type 10, catdef increments may be zero by design - ! for updagte_type 13, could be multiple zero increments + ! for update_type 13, could be multiple zero increments if (logit) write (logunit,*) & 'apply_enkf_increments(): applying soil moisture and Tskin/ght1 increments' diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index a8d19913..cf3f39d0 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -3347,7 +3347,7 @@ end subroutine get_obs_pert ! ********************************************************************* - subroutine cat_enkf_increments( & + subroutine cat_enkf_increments( & N_ens, N_obs, N_catd, N_obs_param, & update_type, obs_param, & tile_coord, l2f, & @@ -3363,6 +3363,7 @@ subroutine cat_enkf_increments( & ! reichle, 18 Oct 2005 - return increments (instead of updated cat_progn) ! reichle, 17 Oct 2011 - added "l2f" for revised (MPI) analysis ! reichle, 20 Feb 2022 - modified update_type 10 for PEATCLSM + ! amfox, 6 Feb 2024 - added update type 13 for combination of ASCAT SM and SMAP Tb ! ! -------------------------------------------------------------- @@ -3424,7 +3425,7 @@ subroutine cat_enkf_increments( & integer :: n, n_e, kk, ii, jj - integer :: N_state_max, N_state, N_selected_obs, N_select_varnames, N_select_species, N_varnames, N_select_species_Tb + integer :: N_state_max, N_state, N_selected_obs, N_select_varnames, N_select_species, N_select_species_Tb real :: halo_minlon, halo_maxlon, halo_minlat, halo_maxlat real :: tmp_minlon, tmp_maxlon, tmp_minlat, tmp_maxlat @@ -3436,7 +3437,7 @@ subroutine cat_enkf_increments( & integer, dimension(N_obs) :: ind_obs - real, allocatable, dimension(:,:) :: State_incr, State_incr_cum + real, allocatable, dimension(:,:) :: State_incr real, allocatable, dimension(:,:) :: Obs_cov ! measurement error covariance real, allocatable, dimension(:) :: State_lon, State_lat @@ -3473,7 +3474,7 @@ subroutine cat_enkf_increments( & type(obs_param_type) :: this_obs_param - logical :: nonZeroFound, found, smap_obs, ascat_obs + logical :: found ! ----------------------------------------------------------------------- @@ -3496,7 +3497,6 @@ subroutine cat_enkf_increments( & N_select_varnames = 0 N_select_species = 0 - N_varnames = 0 select_varnames = '' select_species = -8888 ! intentionally differs from init in get_select_species() @@ -4539,16 +4539,6 @@ subroutine cat_enkf_increments( & call assemble_obs_cov( N_selected_obs, N_obs_param, obs_param, & Observations(ind_obs(1:N_selected_obs)), Obs_cov ) - - ! EnKF update - - ! smap_obs = any(Observations(ind_obs(1:N_selected_obs))%species < 5) - ! ascat_obs = any(Observations(ind_obs(1:N_selected_obs))%species > 4) - - ! if (smap_obs .and. ascat_obs) then - ! write (logunit,*) "Found tile with both obs types. Tile = ", halo_minlon, halo_maxlon, halo_minlat, halo_maxlat - ! write (logunit,*) "Observations(ind_obs(1:N_selected_obs))%species = ", Observations(ind_obs(1:N_selected_obs))%species - ! end if call enkf_increments( & N_state, N_selected_obs, N_ens, & @@ -4614,7 +4604,6 @@ subroutine cat_enkf_increments( & ! clean up if (allocated( State_incr )) deallocate( State_incr ) - if (allocated( State_incr_cum )) deallocate( State_incr_cum ) if (allocated( State_lon )) deallocate( State_lon ) if (allocated( State_lat )) deallocate( State_lat ) if (allocated( select_tilenum )) deallocate( select_tilenum ) @@ -5176,7 +5165,7 @@ subroutine check_compact_support( & Iam // '(): reset for 1d update_type: ycompact = ', ycompact if (logit) write (logunit,*) - case (2,7,8,10, 13) ! "3d" updates, check consistency of xcompact, ycompact + case (2,7,8,10,13) ! "3d" updates, check consistency of xcompact, ycompact ! check xcompact/ycompact against corr scales of model error From 3f1842012c3518e9ca4c87647d16baf08503b0b1 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Tue, 6 Feb 2024 17:29:49 -0700 Subject: [PATCH 236/308] more tidying --- .../clsm_ensupd_upd_routines.F90 | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index cf3f39d0..17c91b9f 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -3452,7 +3452,6 @@ subroutine cat_enkf_increments( & integer, dimension(:,:,:), pointer :: tile_num_in_cell_ij => null() character(len=*), parameter :: Iam = 'cat_enkf_increments' - character(len=400) :: err_msg real, dimension( N_catd) :: r_x, tmp_dlon real :: r_y, tmp_dlat @@ -4559,16 +4558,14 @@ subroutine cat_enkf_increments( & cat_progn_incr(kk,:)%srfexc = State_incr(1,:)*scale_srfexc cat_progn_incr(kk,:)%rzexc = State_incr(2,:)*scale_rzexc - cat_progn_incr(kk,:)%catdef = State_incr(3,:)*scale_catdef - write(logunit,*) 'N3 After cat_progn_incr(kk,:)%srfexc = ', cat_progn_incr(kk,5)%srfexc + cat_progn_incr(kk,:)%catdef = State_incr(3,:)*scale_catdef elseif ( N_state==7 ) then cat_progn_incr(kk,:)%srfexc = State_incr(1,:)*scale_srfexc cat_progn_incr(kk,:)%rzexc = State_incr(2,:)*scale_rzexc - cat_progn_incr(kk,:)%catdef = State_incr(3,:)*scale_catdef ! catdef in State - write(logunit,*) 'N7 After cat_progn_incr(kk,:)%srfexc = ', cat_progn_incr(kk,5)%srfexc - + cat_progn_incr(kk,:)%catdef = State_incr(3,:)*scale_catdef ! catdef in State + cat_progn_incr(kk,:)%tc1 = State_incr(4,:)*scale_temp cat_progn_incr(kk,:)%tc2 = State_incr(5,:)*scale_temp cat_progn_incr(kk,:)%tc4 = State_incr(6,:)*scale_temp @@ -4578,7 +4575,6 @@ subroutine cat_enkf_increments( & cat_progn_incr(kk,:)%srfexc = State_incr(1,:)*scale_srfexc cat_progn_incr(kk,:)%rzexc = State_incr(2,:)*scale_rzexc - write(logunit,*) 'N6 After cat_progn_incr(kk,:)%srfexc = ', cat_progn_incr(kk,5)%srfexc cat_progn_incr(kk,:)%tc1 = State_incr(3,:)*scale_temp cat_progn_incr(kk,:)%tc2 = State_incr(4,:)*scale_temp From 96373047d2faf807ee17488683500bda7bb15a50 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Tue, 6 Feb 2024 17:32:44 -0700 Subject: [PATCH 237/308] remove white space --- .../GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index 17c91b9f..ba42aafa 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -4449,8 +4449,8 @@ subroutine cat_enkf_increments( & ! compute increments only snow-free and non-frozen tiles - if ( (SWE_ensavg(kk) < SWE_threshold) .and. & - (tp1_ensavg(kk) > tp1_threshold) ) then + if ( (SWE_ensavg(kk) < SWE_threshold) .and. & + (tp1_ensavg(kk) > tp1_threshold)) then ! find observations within halo around tile kk From 40329fc620d93ca391c5266483455f0c06b367f6 Mon Sep 17 00:00:00 2001 From: saraqzhang Date: Thu, 8 Feb 2024 12:49:46 -0500 Subject: [PATCH 238/308] generate_catchincr_hist.py using python module version in g5_module --- .../util/config/generate_catchincr_hist.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/Applications/LDAS_App/util/config/generate_catchincr_hist.py b/src/Applications/LDAS_App/util/config/generate_catchincr_hist.py index 76cdea35..3e918711 100755 --- a/src/Applications/LDAS_App/util/config/generate_catchincr_hist.py +++ b/src/Applications/LDAS_App/util/config/generate_catchincr_hist.py @@ -1,6 +1,7 @@ #!/usr/bin/env python # -# module load python/GEOSpyD/Ana2019.03_py3.7 +# This code works with the python version loaded by ldas v17.13.1 g5_module: +# python/GEOSpyD/Min4.11.0_py3.9_AND_Min4.8.3_py2.7 # # This script generates a sample HISTORY.rc file for GEOSldas to write Catchment # model analysis increments in ensemble space, as needed in the weakly-coupled @@ -83,18 +84,22 @@ collection = collection.strip('\n').strip("'") for i in range(nens): i = i +1 - ids = collection+f'{i:04}' - f.write(f"'{ids}'\n") + sfx = '%04d'%(i) + ids = collection+sfx + f.write(ids+'\n') f.write(label) lines = body.split('\n') for i in range(nens): i = i+1 - collect= collection+f'{i:04}.' + sfx = '%04d'%(i) + collect= collection+sfx for line in lines: newline = line if ":" in line : newline = collect+line if "CATCHINCR_e" in newline: - newline = newline.replace('CATCHINCR_e',f'CATCHINCR_e{i:04}') + sfx = '%04d'%(i) + frep = 'CATCHINCR_e'+sfx + newline = newline.replace('CATCHINCR_e',frep) f.write(newline+'\n') f.write('::\n') From 8d46fd7955baa957ddc5504e999613c0f8c622f5 Mon Sep 17 00:00:00 2001 From: Rolf Reichle <54944691+gmao-rreichle@users.noreply.github.com> Date: Thu, 8 Feb 2024 17:07:48 -0500 Subject: [PATCH 239/308] Update comment in generate_catchincr_hist.py --- .../LDAS_App/util/config/generate_catchincr_hist.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Applications/LDAS_App/util/config/generate_catchincr_hist.py b/src/Applications/LDAS_App/util/config/generate_catchincr_hist.py index 3e918711..cfd35037 100755 --- a/src/Applications/LDAS_App/util/config/generate_catchincr_hist.py +++ b/src/Applications/LDAS_App/util/config/generate_catchincr_hist.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # -# This code works with the python version loaded by ldas v17.13.1 g5_module: -# python/GEOSpyD/Min4.11.0_py3.9_AND_Min4.8.3_py2.7 +# This code works with the python version loaded by g5_modules associated with GEOSldas v17.13.1: +# python/GEOSpyD/Min4.11.0_py3.9_AND_Min4.8.3_py2.7 # # This script generates a sample HISTORY.rc file for GEOSldas to write Catchment # model analysis increments in ensemble space, as needed in the weakly-coupled From b0a7a2f499ecaee0a08ab05fdeebdb96e6d403b3 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Thu, 8 Feb 2024 17:16:41 -0500 Subject: [PATCH 240/308] fixed bugs in previous commit (generate_catchincr_hist.py) --- .../LDAS_App/util/config/generate_catchincr_hist.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Applications/LDAS_App/util/config/generate_catchincr_hist.py b/src/Applications/LDAS_App/util/config/generate_catchincr_hist.py index cfd35037..a0efaf09 100755 --- a/src/Applications/LDAS_App/util/config/generate_catchincr_hist.py +++ b/src/Applications/LDAS_App/util/config/generate_catchincr_hist.py @@ -85,14 +85,14 @@ for i in range(nens): i = i +1 sfx = '%04d'%(i) - ids = collection+sfx + ids = "'"+collection+sfx+"'" f.write(ids+'\n') f.write(label) lines = body.split('\n') for i in range(nens): i = i+1 sfx = '%04d'%(i) - collect= collection+sfx + collect= collection+sfx+"." for line in lines: newline = line if ":" in line : From 01d069beaaa74d7d9d89e9ecd9554dba639990fc Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Thu, 8 Feb 2024 17:31:59 -0500 Subject: [PATCH 241/308] additional documentation of generate_catchincr_hist.py --- .../util/config/generate_catchincr_hist.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/Applications/LDAS_App/util/config/generate_catchincr_hist.py b/src/Applications/LDAS_App/util/config/generate_catchincr_hist.py index a0efaf09..ce15d61f 100755 --- a/src/Applications/LDAS_App/util/config/generate_catchincr_hist.py +++ b/src/Applications/LDAS_App/util/config/generate_catchincr_hist.py @@ -11,6 +11,16 @@ import glob import subprocess as sp +# ------------------------------------------------------------------ +# +# specify number of ensemble members here: + +nens = 32 + +# ------------------------------------------------------------------ +# +# some definitions of text elements in HISTORY.rc file + heads = """ # # Sample GEOSldas HISTORY.rc file for LADAS (atm ensemble) @@ -77,7 +87,11 @@ 'SNDZN3_INCR' , 'CATCHINCR_e' , """ -nens = 32 +# ------------------------------------------------------------------ +# +# write file "HISTORY.rc" with nens "catch_progn_incrXXXX" collections, +# one for each ensemble member + with open('HISTORY.rc', 'w') as f: f.write(heads) collection, body = hist_template.split('::\n') @@ -103,3 +117,5 @@ newline = newline.replace('CATCHINCR_e',frep) f.write(newline+'\n') f.write('::\n') + +# ====================== EOF ===================================== From bc0cef5f0ecf04ada191e77caebf55bee92d0871 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Fri, 9 Feb 2024 18:02:36 -0500 Subject: [PATCH 242/308] minor edits for new update_type=13 (clsm_ensupd_upd_routines.F90): - added 'sfmc' obs - added/edited comments - fixed indent - minor simplifications --- .../clsm_ensupd_upd_routines.F90 | 370 +++++++++--------- 1 file changed, 187 insertions(+), 183 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index ba42aafa..87db1a7f 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -3363,7 +3363,7 @@ subroutine cat_enkf_increments( & ! reichle, 18 Oct 2005 - return increments (instead of updated cat_progn) ! reichle, 17 Oct 2011 - added "l2f" for revised (MPI) analysis ! reichle, 20 Feb 2022 - modified update_type 10 for PEATCLSM - ! amfox, 6 Feb 2024 - added update type 13 for combination of ASCAT SM and SMAP Tb + ! amfox, 6 Feb 2024 - added update type 13 for combination of ASCAT SM and SMAP Tb ! ! -------------------------------------------------------------- @@ -3473,7 +3473,7 @@ subroutine cat_enkf_increments( & type(obs_param_type) :: this_obs_param - logical :: found + logical :: found_Tb_obs ! ----------------------------------------------------------------------- @@ -3666,7 +3666,7 @@ subroutine cat_enkf_increments( & end do - case (2) select_update_type ! 3d soil moisture analysis; sfmc and/or sfds obs + case (2) select_update_type ! 3d soil moisture analysis; sfmc+sfds obs ! update each tile separately using all observations within ! the customized halo around each tile @@ -4407,190 +4407,194 @@ subroutine cat_enkf_increments( & ! ---------------------------------- - case (13) select_update_type ! 3d analysis - - ! update each tile separately using all observations within customized halo around each tile - ! - ! amfox, 14 September 2023 - - if (logit) write (logunit,*) 'Get increments for all observation types in obs_param' - - N_select_varnames = 0 - - if (any(obs_param%varname == 'Tb')) then - N_select_varnames = N_select_varnames + 1 - select_varnames(N_select_varnames) = 'Tb' - end if - - if (any(obs_param%varname == 'sfds')) then - N_select_varnames = N_select_varnames + 1 - select_varnames(N_select_varnames) = 'sfds' - end if - - ! Will get all species associated with Tb or sfds observations - - call get_select_species( & - N_select_varnames, select_varnames(1:N_select_varnames), & - N_obs_param, obs_param, N_select_species, select_species ) - - ! Determine which species are Tb - call get_select_species(1, 'Tb', N_obs_param, obs_param, N_select_species_Tb, select_species_Tb ) - - - N_state_max = 7 - - allocate( State_incr(N_state_max,N_ens)) - allocate( State_lon( N_state_max )) - allocate( State_lat( N_state_max )) - - do kk=1,N_catd - - N_state = 0 - - ! compute increments only snow-free and non-frozen tiles - - if ( (SWE_ensavg(kk) < SWE_threshold) .and. & - (tp1_ensavg(kk) > tp1_threshold)) then - - ! find observations within halo around tile kk - - halo_minlon = tile_coord(kk)%com_lon - xcompact - halo_maxlon = tile_coord(kk)%com_lon + xcompact - halo_minlat = tile_coord(kk)%com_lat - ycompact - halo_maxlat = tile_coord(kk)%com_lat + ycompact - - ! simple approach to dateline issue (cut halo back to at most -180:180, -90:90) - ! - reichle, 28 May 2013 - - halo_minlon = max(halo_minlon,-180.) - halo_maxlon = min(halo_maxlon, 180.) - halo_minlat = max(halo_minlat, -90.) - halo_maxlat = min(halo_maxlat, 90.) - - call get_ind_obs_lat_lon_box( & - N_obs, Observations, & - halo_minlon, halo_maxlon, halo_minlat, halo_maxlat, & - N_select_species, select_species(1:N_select_species), & - N_selected_obs, ind_obs ) - - if (N_selected_obs>0) then - - ! Determine if Tb observations are present - - do ii = 1,N_select_species_Tb - do jj = 1,N_selected_obs - if (select_species_Tb(ii) == Observations(ind_obs(jj))%species) then - found = .true. - exit - end if - end do - if (found) then - exit - end if - end do - - if (found) then - if (cat_param(kk)%poros>=PEATCLSM_POROS_THRESHOLD) then - N_state = 7 - else - N_state = 6 - end if - else - N_state = 3 - end if - - ! assemble State_minus - ! (on input, cat_progn contains cat_progn_minus) - - if ( N_state==3 ) then - - State_incr(1,:) = (cat_progn( kk,:)%srfexc/scale_srfexc) - State_incr(2,:) = (cat_progn( kk,:)%rzexc /scale_rzexc) - State_incr(3,:) = (cat_progn( kk,:)%catdef/scale_catdef) - - elseif ( N_state==7 ) then - - State_incr(1,:) = cat_progn( kk,:)%srfexc/scale_srfexc - State_incr(2,:) = cat_progn( kk,:)%rzexc /scale_rzexc - State_incr(3,:) = cat_progn( kk,:)%catdef/scale_catdef ! catdef in State - - State_incr(4,:) = cat_progn( kk,:)%tc1 /scale_temp - State_incr(5,:) = cat_progn( kk,:)%tc2 /scale_temp - State_incr(6,:) = cat_progn( kk,:)%tc4 /scale_temp - State_incr(7,:) = cat_progn( kk,:)%ght(1)/scale_ght1 - - else - - State_incr(1,:) = cat_progn( kk,:)%srfexc/scale_srfexc - State_incr(2,:) = cat_progn( kk,:)%rzexc /scale_rzexc - - State_incr(3,:) = cat_progn( kk,:)%tc1 /scale_temp - State_incr(4,:) = cat_progn( kk,:)%tc2 /scale_temp - State_incr(5,:) = cat_progn( kk,:)%tc4 /scale_temp - State_incr(6,:) = cat_progn( kk,:)%ght(1)/scale_ght1 - - end if - - State_lon( :) = tile_coord(kk )%com_lon - State_lat( :) = tile_coord(kk )%com_lat - - allocate(Obs_cov(N_selected_obs,N_selected_obs)) - - call assemble_obs_cov( N_selected_obs, N_obs_param, obs_param, & - Observations(ind_obs(1:N_selected_obs)), Obs_cov ) - - call enkf_increments( & - N_state, N_selected_obs, N_ens, & - Observations(ind_obs(1:N_selected_obs)), & - Obs_pred(ind_obs(1:N_selected_obs),:), & - Obs_pert(ind_obs(1:N_selected_obs),:), & - Obs_cov, & - State_incr(1:N_state,:), & - State_lon( 1:N_state ), & - State_lat( 1:N_state ), & - xcompact, ycompact, & - fcsterr_inflation_fac ) - - deallocate(Obs_cov) - - ! assemble cat_progn increments - if ( N_state==3 ) then - - cat_progn_incr(kk,:)%srfexc = State_incr(1,:)*scale_srfexc - cat_progn_incr(kk,:)%rzexc = State_incr(2,:)*scale_rzexc - cat_progn_incr(kk,:)%catdef = State_incr(3,:)*scale_catdef - - elseif ( N_state==7 ) then - - cat_progn_incr(kk,:)%srfexc = State_incr(1,:)*scale_srfexc - cat_progn_incr(kk,:)%rzexc = State_incr(2,:)*scale_rzexc - cat_progn_incr(kk,:)%catdef = State_incr(3,:)*scale_catdef ! catdef in State - - cat_progn_incr(kk,:)%tc1 = State_incr(4,:)*scale_temp - cat_progn_incr(kk,:)%tc2 = State_incr(5,:)*scale_temp - cat_progn_incr(kk,:)%tc4 = State_incr(6,:)*scale_temp - cat_progn_incr(kk,:)%ght(1) = State_incr(7,:)*scale_ght1 + case (13) select_update_type ! 3d soil moisture/Tskin/ght(1) analysis; Tb+sfmc+sfds obs + + ! combines update_types 2 and 10 + ! + ! update each tile separately using all observations within customized halo around each tile + ! + ! amfox, 14 September 2023 + + if (logit) write (logunit,*) 'get 3d soil moisture/Tskin/ght(1) increments; Tb+sfmc obs' + + N_select_varnames = 0 + + if (any(obs_param%varname == 'Tb')) then + N_select_varnames = N_select_varnames + 1 + select_varnames(N_select_varnames) = 'Tb' + end if + + if (any(obs_param%varname == 'sfmc')) then + N_select_varnames = N_select_varnames + 1 + select_varnames(N_select_varnames) = 'sfmc' + end if - else - - cat_progn_incr(kk,:)%srfexc = State_incr(1,:)*scale_srfexc - cat_progn_incr(kk,:)%rzexc = State_incr(2,:)*scale_rzexc - - cat_progn_incr(kk,:)%tc1 = State_incr(3,:)*scale_temp - cat_progn_incr(kk,:)%tc2 = State_incr(4,:)*scale_temp - cat_progn_incr(kk,:)%tc4 = State_incr(5,:)*scale_temp - cat_progn_incr(kk,:)%ght(1) = State_incr(6,:)*scale_ght1 - - end if - - end if + if (any(obs_param%varname == 'sfds')) then + N_select_varnames = N_select_varnames + 1 + select_varnames(N_select_varnames) = 'sfds' + end if + + ! Will get all species associated with Tb or sfds observations + + call get_select_species( & + N_select_varnames, select_varnames(1:N_select_varnames), & + N_obs_param, obs_param, N_select_species, select_species ) + + ! Determine which species are Tb + + call get_select_species(1, 'Tb', N_obs_param, obs_param, N_select_species_Tb, select_species_Tb ) + + N_state_max = 7 + + allocate( State_incr(N_state_max,N_ens)) + allocate( State_lon( N_state_max )) + allocate( State_lat( N_state_max )) + + do kk=1,N_catd + + N_state = 3 ! for now, assume only sfmc and/or sfds obs + + ! compute increments only snow-free and non-frozen tiles + + if ( (SWE_ensavg(kk) < SWE_threshold) .and. & + (tp1_ensavg(kk) > tp1_threshold)) then + + ! find observations within halo around tile kk + + halo_minlon = tile_coord(kk)%com_lon - xcompact + halo_maxlon = tile_coord(kk)%com_lon + xcompact + halo_minlat = tile_coord(kk)%com_lat - ycompact + halo_maxlat = tile_coord(kk)%com_lat + ycompact + + ! simple approach to dateline issue (cut halo back to at most -180:180, -90:90) + ! - reichle, 28 May 2013 + + halo_minlon = max(halo_minlon,-180.) + halo_maxlon = min(halo_maxlon, 180.) + halo_minlat = max(halo_minlat, -90.) + halo_maxlat = min(halo_maxlat, 90.) + + call get_ind_obs_lat_lon_box( & + N_obs, Observations, & + halo_minlon, halo_maxlon, halo_minlat, halo_maxlat, & + N_select_species, select_species(1:N_select_species), & + N_selected_obs, ind_obs ) + + if (N_selected_obs>0) then + + ! Determine if Tb observations are present + + do ii = 1,N_select_species_Tb + do jj = 1,N_selected_obs + if (select_species_Tb(ii) == Observations(ind_obs(jj))%species) then + found_Tb_obs = .true. + exit + end if + end do + if (found_Tb_obs) exit + end do + + if (found_Tb_obs) then + if (cat_param(kk)%poros>=PEATCLSM_POROS_THRESHOLD) then + N_state = 7 + else + N_state = 6 + end if + end if + + ! assemble State_minus + ! (on input, cat_progn contains cat_progn_minus) + + if ( N_state==3 ) then + + State_incr(1,:) = (cat_progn( kk,:)%srfexc/scale_srfexc) + State_incr(2,:) = (cat_progn( kk,:)%rzexc /scale_rzexc) + State_incr(3,:) = (cat_progn( kk,:)%catdef/scale_catdef) + + elseif ( N_state==7 ) then + + State_incr(1,:) = cat_progn( kk,:)%srfexc/scale_srfexc + State_incr(2,:) = cat_progn( kk,:)%rzexc /scale_rzexc + State_incr(3,:) = cat_progn( kk,:)%catdef/scale_catdef ! catdef in State + + State_incr(4,:) = cat_progn( kk,:)%tc1 /scale_temp + State_incr(5,:) = cat_progn( kk,:)%tc2 /scale_temp + State_incr(6,:) = cat_progn( kk,:)%tc4 /scale_temp + State_incr(7,:) = cat_progn( kk,:)%ght(1)/scale_ght1 + + else + + State_incr(1,:) = cat_progn( kk,:)%srfexc/scale_srfexc + State_incr(2,:) = cat_progn( kk,:)%rzexc /scale_rzexc + + State_incr(3,:) = cat_progn( kk,:)%tc1 /scale_temp + State_incr(4,:) = cat_progn( kk,:)%tc2 /scale_temp + State_incr(5,:) = cat_progn( kk,:)%tc4 /scale_temp + State_incr(6,:) = cat_progn( kk,:)%ght(1)/scale_ght1 + + end if + + State_lon( :) = tile_coord(kk )%com_lon + State_lat( :) = tile_coord(kk )%com_lat + + allocate(Obs_cov(N_selected_obs,N_selected_obs)) - end if ! thresholds - - end do + call assemble_obs_cov( N_selected_obs, N_obs_param, obs_param, & + Observations(ind_obs(1:N_selected_obs)), Obs_cov ) + + call enkf_increments( & + N_state, N_selected_obs, N_ens, & + Observations(ind_obs(1:N_selected_obs)), & + Obs_pred(ind_obs(1:N_selected_obs),:), & + Obs_pert(ind_obs(1:N_selected_obs),:), & + Obs_cov, & + State_incr(1:N_state,:), & + State_lon( 1:N_state ), & + State_lat( 1:N_state ), & + xcompact, ycompact, & + fcsterr_inflation_fac ) + + deallocate(Obs_cov) + + ! assemble cat_progn increments + if ( N_state==3 ) then + + cat_progn_incr(kk,:)%srfexc = State_incr(1,:)*scale_srfexc + cat_progn_incr(kk,:)%rzexc = State_incr(2,:)*scale_rzexc + cat_progn_incr(kk,:)%catdef = State_incr(3,:)*scale_catdef + + elseif ( N_state==7 ) then + + cat_progn_incr(kk,:)%srfexc = State_incr(1,:)*scale_srfexc + cat_progn_incr(kk,:)%rzexc = State_incr(2,:)*scale_rzexc + cat_progn_incr(kk,:)%catdef = State_incr(3,:)*scale_catdef ! catdef in State + + cat_progn_incr(kk,:)%tc1 = State_incr(4,:)*scale_temp + cat_progn_incr(kk,:)%tc2 = State_incr(5,:)*scale_temp + cat_progn_incr(kk,:)%tc4 = State_incr(6,:)*scale_temp + cat_progn_incr(kk,:)%ght(1) = State_incr(7,:)*scale_ght1 + + else + + cat_progn_incr(kk,:)%srfexc = State_incr(1,:)*scale_srfexc + cat_progn_incr(kk,:)%rzexc = State_incr(2,:)*scale_rzexc + + cat_progn_incr(kk,:)%tc1 = State_incr(3,:)*scale_temp + cat_progn_incr(kk,:)%tc2 = State_incr(4,:)*scale_temp + cat_progn_incr(kk,:)%tc4 = State_incr(5,:)*scale_temp + cat_progn_incr(kk,:)%ght(1) = State_incr(6,:)*scale_ght1 + + end if + + end if + + end if ! thresholds + + end do + ! ---------------------------------- - + case default call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'unknown update_type') From 09e3f05e9e4f43e2571992f0fd94ac1e9a314f56 Mon Sep 17 00:00:00 2001 From: Weiyuan Jiang Date: Tue, 13 Feb 2024 10:48:54 -0500 Subject: [PATCH 243/308] add NAS site --- src/Applications/LDAS_App/ldas_setup | 40 ++++++++++++++++------ src/Applications/LDAS_App/lenkf.j.template | 10 ++++++ 2 files changed, 39 insertions(+), 11 deletions(-) diff --git a/src/Applications/LDAS_App/ldas_setup b/src/Applications/LDAS_App/ldas_setup index 12a72d27..f4214411 100755 --- a/src/Applications/LDAS_App/ldas_setup +++ b/src/Applications/LDAS_App/ldas_setup @@ -53,12 +53,13 @@ class LDASsetup: # if built on sles15, BUILT_ON_SLES15 is "TRUE", else empty "" BUILT_ON_SLES15 = "@BUILT_ON_SLES15@" - if BUILT_ON_SLES15 == "TRUE": self.BUILT_ON_SLES15 = True else: self.BUILT_ON_SLES15 = False + self.GEOS_SITE = "@GEOS_SITE@" + # ------ # Required resource manager input fields # ------ @@ -852,7 +853,6 @@ class LDASsetup: config['slurm']['account'] = self.rqdRmInp['account'] config['slurm']['qos'] = 'debug' - config['slurm']['qos'] = 'cas' config['input']['surface']['catch_tilefile'] = self.in_tilefile config['input']['shared']['expid'] = self.rqdExeInp['RESTART_ID'] @@ -1249,8 +1249,11 @@ class LDASsetup: fout =open(self.rundir+'/ldas_batchrun.j','w') fout.write("#!/bin/bash -f\n") jobid = None + SBATCHQSUB = 'sbatch' expid = self.rqdExeInp['EXP_ID'] - fout.write("\nsed -i 's/if($capdate<$enddate) sbatch /#if($capdate<$enddate) sbatch /g' lenkf.j\n\n") + if self.GEOS_SITE == 'NAS': + SBATCHQSUB = 'qsub' + fout.write("\nsed -i 's/if($capdate<$enddate) "//SBATCHQSUB//" /#if($capdate<$enddate) qsub /g' lenkf.j\n\n") nSegments = self.nSegments for iseg in range(nSegments): if iseg ==0 : @@ -1303,6 +1306,7 @@ class LDASsetup: shutil.copy(lenkf,'lenkf.j') my_qos='allnccs' + if self.GEOS_SITE == 'NAS': my_qos = 'normal' if 'qos' in self.optRmInp : my_qos = self.optRmInp['qos'] @@ -1337,26 +1341,40 @@ class LDASsetup: with open(lenkf,'rt') as fin: with open('lenkf.j','wt') as fout : for line in fin : + if self.GEOS_SITE == 'NAS': + if '#SBATCH' in line: + continue + if 'sbatch $HOMDIR/lenkf.j' in line: + continue + + if self.GEOS_SITE == 'NCCS': + if '#PBS' in line: + continue + if 'qsub $HOMDIR/lenkf.j' in line: + continue + if 'MY_ACCOUNT' in line : fout.write(line.replace('MY_ACCOUNT',self.rqdRmInp['account'])) elif 'MY_WALLTIME' in line : fout.write(line.replace('MY_WALLTIME',self.rqdRmInp['walltime'])) elif 'MY_NODES' in line : line_ = line.replace('MY_NODES',str(self.optRmInp['nodes'])) - fout.write(line_.replace('MY_NTASKS_PER_NODE',str(self.rqdRmInp['ntasks-per-node']))) - - if self.BUILT_ON_SLES15 : - fout.write("#SBATCH --constraint=mil\n") - else: - assert int(self.rqdRmInp['ntasks-per-node']) <= 46, 'ntasks-per-node should be <=46 for cas' - fout.write("#SBATCH --constraint=cas\n") + line_ = line_.replace('MY_NTASKS_PER_NODE',str(self.rqdRmInp['ntasks-per-node'])) + line_ = line_.replace('MY_CONSTRAINT', 'cas_ait') + fout.write(line_) + if self.GEOS_SITE == "NCCS" : + if self.BUILT_ON_SLES15 : + fout.write("#SBATCH --constraint=mil\n") + else: + assert int(self.rqdRmInp['ntasks-per-node']) <= 46, 'ntasks-per-node should be <=46 for cas' + fout.write("#SBATCH --constraint=cas\n") elif 'MY_OSERVER_NODES' in line : fout.write(line.replace('MY_OSERVER_NODES',str(self.optRmInp['oserver_nodes']))) elif 'MY_WRITERS_NPES' in line : fout.write(line.replace('MY_WRITERS_NPES', str(self.optRmInp['writers-per-node']))) elif 'MY_QOS' in line : - if 'allnccs' not in my_qos: + if 'allnccs' not in my_qos or 'normal' not in my_qos: fout.write(line.replace('MY_QOS',my_qos)) elif 'MY_JOB' in line : fout.write(line.replace('MY_JOB',my_job)) diff --git a/src/Applications/LDAS_App/lenkf.j.template b/src/Applications/LDAS_App/lenkf.j.template index 4e478f8b..5e5975c7 100644 --- a/src/Applications/LDAS_App/lenkf.j.template +++ b/src/Applications/LDAS_App/lenkf.j.template @@ -16,6 +16,15 @@ #SBATCH --job-name=MY_JOB #SBATCH --qos=MY_QOS +#PBS -l walltime=MY_WALLTIME +#PBS -l select=MY_NODES:ncpus=40:mpiprocs=40:model=MY_CONSTRAINT +#PBS -N MY_JOB +#PBS -q MY_QOS +#PBS -W group_list=MY_ACCOUNT +#PBS -o ../scratch/GEOSldas_log_txt +#PBS -e ../scratch/GEOSldas_err_txt +#PBS -j oe + ####################################################################### # System Settings and Architecture Specific Environment Variables ####################################################################### @@ -834,5 +843,6 @@ else cd $HOMDIR #don't change below line(not even extra space) if($capdate<$enddate) sbatch $HOMDIR/lenkf.j + if($capdate<$enddate) qsub $HOMDIR/lenkf.j endif endif From 69307cc2f5ab3504a8de97acb56d5b25260d185c Mon Sep 17 00:00:00 2001 From: gmao-jkolassa Date: Tue, 13 Feb 2024 12:22:32 -0500 Subject: [PATCH 244/308] disable Catchment-CN4.5 option for GEOSldas --- src/Applications/LDAS_App/GEOSldas_LDAS.rc | 1 - src/Applications/LDAS_App/ldas_setup | 5 +++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Applications/LDAS_App/GEOSldas_LDAS.rc b/src/Applications/LDAS_App/GEOSldas_LDAS.rc index 3c290a17..df92fdb0 100644 --- a/src/Applications/LDAS_App/GEOSldas_LDAS.rc +++ b/src/Applications/LDAS_App/GEOSldas_LDAS.rc @@ -33,7 +33,6 @@ CATCHMENT_SPINUP: 0 # # 1 : Catchment model (default) # 2 : CatchmentCN-CLM4.0 -# 3 : CatchmentCN-CLM4.5 # LSM_CHOICE: 1 diff --git a/src/Applications/LDAS_App/ldas_setup b/src/Applications/LDAS_App/ldas_setup index 12a72d27..87eb9e14 100755 --- a/src/Applications/LDAS_App/ldas_setup +++ b/src/Applications/LDAS_App/ldas_setup @@ -340,8 +340,9 @@ class LDASsetup: self.catch = 'catch' if int(self.rqdExeInp['LSM_CHOICE']) == 2 : self.catch = 'catchcnclm40' - if int(self.rqdExeInp['LSM_CHOICE']) == 3 : - self.catch = 'catchcnclm45' + + assert int(self.rqdExeInp['LSM_CHOICE']) <= 2, "\nLSM_CHOICE=3 (Catchment-CN4.5) is no longer supported. Please set LSM_CHOICE to 1 (Catchment) or 2 (Catchment-CN4.0)" + if 'POSTPROC_HIST' not in self.rqdExeInp: self.rqdExeInp['POSTPROC_HIST'] = 0 From c2ff5fbaf15b2f00d0c2a418da30e0f60e295448 Mon Sep 17 00:00:00 2001 From: gmao-jkolassa Date: Tue, 13 Feb 2024 13:35:23 -0500 Subject: [PATCH 245/308] use GEOSgcm_GridComp branch implementing CN45 disabling --- components.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components.yaml b/components.yaml index fa43e03d..3ac07866 100644 --- a/components.yaml +++ b/components.yaml @@ -48,6 +48,6 @@ MAPL: GEOSgcm_GridComp: local: ./src/Components/GEOSldas_GridComp/@GEOSgcm_GridComp remote: ../GEOSgcm_GridComp.git - branch: develop + branch: feature/jkolassa_disable_cn45 sparse: ./config/GEOSgcm_GridComp_ldas.sparse develop: develop From e4fc89fee9934055030dc9534a4de5e40d0cf8e3 Mon Sep 17 00:00:00 2001 From: Rolf Reichle <54944691+gmao-rreichle@users.noreply.github.com> Date: Wed, 14 Feb 2024 19:12:35 -0500 Subject: [PATCH 246/308] Fix error in components.yaml of #707 --- components.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components.yaml b/components.yaml index 3ac07866..fa43e03d 100644 --- a/components.yaml +++ b/components.yaml @@ -48,6 +48,6 @@ MAPL: GEOSgcm_GridComp: local: ./src/Components/GEOSldas_GridComp/@GEOSgcm_GridComp remote: ../GEOSgcm_GridComp.git - branch: feature/jkolassa_disable_cn45 + branch: develop sparse: ./config/GEOSgcm_GridComp_ldas.sparse develop: develop From 4d5c786e544f28f5a999d8d7e0d4ad5722244ef8 Mon Sep 17 00:00:00 2001 From: Weiyuan Jiang Date: Thu, 15 Feb 2024 11:17:31 -0500 Subject: [PATCH 247/308] sparse checkout of GEOS_util --- components.yaml | 1 + config/GEOS_Util.sparse | 3 +++ 2 files changed, 4 insertions(+) create mode 100644 config/GEOS_Util.sparse diff --git a/components.yaml b/components.yaml index fa43e03d..a4c189d7 100644 --- a/components.yaml +++ b/components.yaml @@ -37,6 +37,7 @@ GEOS_Util: local: ./src/Shared/@GMAO_Shared/@GEOS_Util remote: ../GEOS_Util.git tag: v2.0.3 + sparse: ./config/GEOS_Util.sparse develop: main MAPL: diff --git a/config/GEOS_Util.sparse b/config/GEOS_Util.sparse new file mode 100644 index 00000000..44ea2be3 --- /dev/null +++ b/config/GEOS_Util.sparse @@ -0,0 +1,3 @@ +/CMakeLists.txt +/pre/remap_restart +/pre/CMakeLists.txt From 2895dc59a24ad649038e876b899ac3771f422694 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Fri, 16 Feb 2024 09:20:09 -0500 Subject: [PATCH 248/308] renamed GEOSldas_GridComp/Shared to GEOSldas_GridComp/LDAS_Shared --- src/Components/GEOSldas_GridComp/CMakeLists.txt | 2 +- .../GEOSldas_GridComp/{Shared => LDAS_Shared}/CMakeLists.txt | 0 .../GEOSldas_GridComp/{Shared => LDAS_Shared}/LDAS_Convert.F90 | 0 .../{Shared => LDAS_Shared}/LDAS_DriverTypes.F90 | 0 .../{Shared => LDAS_Shared}/LDAS_Exceptions.F90 | 0 .../{Shared => LDAS_Shared}/LDAS_PertTypes.F90 | 0 .../{Shared => LDAS_Shared}/LDAS_RepairForcing.F90 | 0 .../{Shared => LDAS_Shared}/LDAS_TileCoordRoutines.F90 | 0 .../{Shared => LDAS_Shared}/LDAS_TileCoordType.F90 | 0 .../{Shared => LDAS_Shared}/LDAS_ensdrv_Globals.F90 | 0 .../{Shared => LDAS_Shared}/LDAS_ensdrv_functions.F90 | 0 .../{Shared => LDAS_Shared}/LDAS_ensdrv_mpi.F90 | 0 .../GEOSldas_GridComp/{Shared => LDAS_Shared}/catch_types.F90 | 0 .../GEOSldas_GridComp/{Shared => LDAS_Shared}/enkf_types.F90 | 0 .../GEOSldas_GridComp/{Shared => LDAS_Shared}/my_lu_decomp.f | 0 .../{Shared => LDAS_Shared}/my_matrix_functions.F90 | 0 .../GEOSldas_GridComp/{Shared => LDAS_Shared}/nr_indexx.f | 0 17 files changed, 1 insertion(+), 1 deletion(-) rename src/Components/GEOSldas_GridComp/{Shared => LDAS_Shared}/CMakeLists.txt (100%) rename src/Components/GEOSldas_GridComp/{Shared => LDAS_Shared}/LDAS_Convert.F90 (100%) rename src/Components/GEOSldas_GridComp/{Shared => LDAS_Shared}/LDAS_DriverTypes.F90 (100%) rename src/Components/GEOSldas_GridComp/{Shared => LDAS_Shared}/LDAS_Exceptions.F90 (100%) rename src/Components/GEOSldas_GridComp/{Shared => LDAS_Shared}/LDAS_PertTypes.F90 (100%) rename src/Components/GEOSldas_GridComp/{Shared => LDAS_Shared}/LDAS_RepairForcing.F90 (100%) rename src/Components/GEOSldas_GridComp/{Shared => LDAS_Shared}/LDAS_TileCoordRoutines.F90 (100%) rename src/Components/GEOSldas_GridComp/{Shared => LDAS_Shared}/LDAS_TileCoordType.F90 (100%) rename src/Components/GEOSldas_GridComp/{Shared => LDAS_Shared}/LDAS_ensdrv_Globals.F90 (100%) rename src/Components/GEOSldas_GridComp/{Shared => LDAS_Shared}/LDAS_ensdrv_functions.F90 (100%) rename src/Components/GEOSldas_GridComp/{Shared => LDAS_Shared}/LDAS_ensdrv_mpi.F90 (100%) rename src/Components/GEOSldas_GridComp/{Shared => LDAS_Shared}/catch_types.F90 (100%) rename src/Components/GEOSldas_GridComp/{Shared => LDAS_Shared}/enkf_types.F90 (100%) rename src/Components/GEOSldas_GridComp/{Shared => LDAS_Shared}/my_lu_decomp.f (100%) rename src/Components/GEOSldas_GridComp/{Shared => LDAS_Shared}/my_matrix_functions.F90 (100%) rename src/Components/GEOSldas_GridComp/{Shared => LDAS_Shared}/nr_indexx.f (100%) diff --git a/src/Components/GEOSldas_GridComp/CMakeLists.txt b/src/Components/GEOSldas_GridComp/CMakeLists.txt index 05ddb49b..d6a7018a 100644 --- a/src/Components/GEOSldas_GridComp/CMakeLists.txt +++ b/src/Components/GEOSldas_GridComp/CMakeLists.txt @@ -12,6 +12,6 @@ set (alldirs esma_add_library(${this} SRCS GEOS_LdasGridComp.F90 SUBCOMPONENTS ${alldirs} - SUBDIRS Shared + SUBDIRS LDAS_Shared DEPENDENCIES GEOSland_GridComp makebcs MAPL INCLUDES ${INC_ESMF}) diff --git a/src/Components/GEOSldas_GridComp/Shared/CMakeLists.txt b/src/Components/GEOSldas_GridComp/LDAS_Shared/CMakeLists.txt similarity index 100% rename from src/Components/GEOSldas_GridComp/Shared/CMakeLists.txt rename to src/Components/GEOSldas_GridComp/LDAS_Shared/CMakeLists.txt diff --git a/src/Components/GEOSldas_GridComp/Shared/LDAS_Convert.F90 b/src/Components/GEOSldas_GridComp/LDAS_Shared/LDAS_Convert.F90 similarity index 100% rename from src/Components/GEOSldas_GridComp/Shared/LDAS_Convert.F90 rename to src/Components/GEOSldas_GridComp/LDAS_Shared/LDAS_Convert.F90 diff --git a/src/Components/GEOSldas_GridComp/Shared/LDAS_DriverTypes.F90 b/src/Components/GEOSldas_GridComp/LDAS_Shared/LDAS_DriverTypes.F90 similarity index 100% rename from src/Components/GEOSldas_GridComp/Shared/LDAS_DriverTypes.F90 rename to src/Components/GEOSldas_GridComp/LDAS_Shared/LDAS_DriverTypes.F90 diff --git a/src/Components/GEOSldas_GridComp/Shared/LDAS_Exceptions.F90 b/src/Components/GEOSldas_GridComp/LDAS_Shared/LDAS_Exceptions.F90 similarity index 100% rename from src/Components/GEOSldas_GridComp/Shared/LDAS_Exceptions.F90 rename to src/Components/GEOSldas_GridComp/LDAS_Shared/LDAS_Exceptions.F90 diff --git a/src/Components/GEOSldas_GridComp/Shared/LDAS_PertTypes.F90 b/src/Components/GEOSldas_GridComp/LDAS_Shared/LDAS_PertTypes.F90 similarity index 100% rename from src/Components/GEOSldas_GridComp/Shared/LDAS_PertTypes.F90 rename to src/Components/GEOSldas_GridComp/LDAS_Shared/LDAS_PertTypes.F90 diff --git a/src/Components/GEOSldas_GridComp/Shared/LDAS_RepairForcing.F90 b/src/Components/GEOSldas_GridComp/LDAS_Shared/LDAS_RepairForcing.F90 similarity index 100% rename from src/Components/GEOSldas_GridComp/Shared/LDAS_RepairForcing.F90 rename to src/Components/GEOSldas_GridComp/LDAS_Shared/LDAS_RepairForcing.F90 diff --git a/src/Components/GEOSldas_GridComp/Shared/LDAS_TileCoordRoutines.F90 b/src/Components/GEOSldas_GridComp/LDAS_Shared/LDAS_TileCoordRoutines.F90 similarity index 100% rename from src/Components/GEOSldas_GridComp/Shared/LDAS_TileCoordRoutines.F90 rename to src/Components/GEOSldas_GridComp/LDAS_Shared/LDAS_TileCoordRoutines.F90 diff --git a/src/Components/GEOSldas_GridComp/Shared/LDAS_TileCoordType.F90 b/src/Components/GEOSldas_GridComp/LDAS_Shared/LDAS_TileCoordType.F90 similarity index 100% rename from src/Components/GEOSldas_GridComp/Shared/LDAS_TileCoordType.F90 rename to src/Components/GEOSldas_GridComp/LDAS_Shared/LDAS_TileCoordType.F90 diff --git a/src/Components/GEOSldas_GridComp/Shared/LDAS_ensdrv_Globals.F90 b/src/Components/GEOSldas_GridComp/LDAS_Shared/LDAS_ensdrv_Globals.F90 similarity index 100% rename from src/Components/GEOSldas_GridComp/Shared/LDAS_ensdrv_Globals.F90 rename to src/Components/GEOSldas_GridComp/LDAS_Shared/LDAS_ensdrv_Globals.F90 diff --git a/src/Components/GEOSldas_GridComp/Shared/LDAS_ensdrv_functions.F90 b/src/Components/GEOSldas_GridComp/LDAS_Shared/LDAS_ensdrv_functions.F90 similarity index 100% rename from src/Components/GEOSldas_GridComp/Shared/LDAS_ensdrv_functions.F90 rename to src/Components/GEOSldas_GridComp/LDAS_Shared/LDAS_ensdrv_functions.F90 diff --git a/src/Components/GEOSldas_GridComp/Shared/LDAS_ensdrv_mpi.F90 b/src/Components/GEOSldas_GridComp/LDAS_Shared/LDAS_ensdrv_mpi.F90 similarity index 100% rename from src/Components/GEOSldas_GridComp/Shared/LDAS_ensdrv_mpi.F90 rename to src/Components/GEOSldas_GridComp/LDAS_Shared/LDAS_ensdrv_mpi.F90 diff --git a/src/Components/GEOSldas_GridComp/Shared/catch_types.F90 b/src/Components/GEOSldas_GridComp/LDAS_Shared/catch_types.F90 similarity index 100% rename from src/Components/GEOSldas_GridComp/Shared/catch_types.F90 rename to src/Components/GEOSldas_GridComp/LDAS_Shared/catch_types.F90 diff --git a/src/Components/GEOSldas_GridComp/Shared/enkf_types.F90 b/src/Components/GEOSldas_GridComp/LDAS_Shared/enkf_types.F90 similarity index 100% rename from src/Components/GEOSldas_GridComp/Shared/enkf_types.F90 rename to src/Components/GEOSldas_GridComp/LDAS_Shared/enkf_types.F90 diff --git a/src/Components/GEOSldas_GridComp/Shared/my_lu_decomp.f b/src/Components/GEOSldas_GridComp/LDAS_Shared/my_lu_decomp.f similarity index 100% rename from src/Components/GEOSldas_GridComp/Shared/my_lu_decomp.f rename to src/Components/GEOSldas_GridComp/LDAS_Shared/my_lu_decomp.f diff --git a/src/Components/GEOSldas_GridComp/Shared/my_matrix_functions.F90 b/src/Components/GEOSldas_GridComp/LDAS_Shared/my_matrix_functions.F90 similarity index 100% rename from src/Components/GEOSldas_GridComp/Shared/my_matrix_functions.F90 rename to src/Components/GEOSldas_GridComp/LDAS_Shared/my_matrix_functions.F90 diff --git a/src/Components/GEOSldas_GridComp/Shared/nr_indexx.f b/src/Components/GEOSldas_GridComp/LDAS_Shared/nr_indexx.f similarity index 100% rename from src/Components/GEOSldas_GridComp/Shared/nr_indexx.f rename to src/Components/GEOSldas_GridComp/LDAS_Shared/nr_indexx.f From 7e5b3c8e3b02352d4e4a698e39a898f93ebf10f0 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Mon, 19 Feb 2024 14:31:58 -0700 Subject: [PATCH 249/308] add trim when selecting by varname --- .../clsm_ensupd_upd_routines.F90 | 30 +++++++++++-------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index 87db1a7f..c8710d6e 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -4419,20 +4419,24 @@ subroutine cat_enkf_increments( & N_select_varnames = 0 - if (any(obs_param%varname == 'Tb')) then - N_select_varnames = N_select_varnames + 1 - select_varnames(N_select_varnames) = 'Tb' - end if - - if (any(obs_param%varname == 'sfmc')) then - N_select_varnames = N_select_varnames + 1 - select_varnames(N_select_varnames) = 'sfmc' - end if + do ii = 1,N_obs_param + + if (trim(obs_param(ii)%varname) == 'Tb') then + N_select_varnames = N_select_varnames + 1 + select_varnames(N_select_varnames) = 'Tb' + end if + + if (trim(obs_param(ii)%varname) == 'sfmc') then + N_select_varnames = N_select_varnames + 1 + select_varnames(N_select_varnames) = 'sfmc' + end if + + if (trim(obs_param(ii)%varname) == 'sfds') then + N_select_varnames = N_select_varnames + 1 + select_varnames(N_select_varnames) = 'sfds' + end if - if (any(obs_param%varname == 'sfds')) then - N_select_varnames = N_select_varnames + 1 - select_varnames(N_select_varnames) = 'sfds' - end if + end do ! Will get all species associated with Tb or sfds observations From f4780912f1912c26612f7504d0fbdb8fcff12c48 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Mon, 19 Feb 2024 14:38:37 -0700 Subject: [PATCH 250/308] Clarify comments in clsm_ensupd_enkf_update.F90 --- .../GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 index 30610618..16449a65 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 @@ -1333,8 +1333,8 @@ subroutine apply_enkf_increments( N_catd, N_ens, update_type, & case (6,8,9,10,13) select_update_type ! soil moisture and temperature update ! for update_type 10, catdef increments may be zero by design - ! for update_type 13, could be multiple zero increments - + ! for update_type 13, could produce multiple zero increments (i.e. tc1, tc2, tc4 will be unchanged if soil moisture observations only) + if (logit) write (logunit,*) & 'apply_enkf_increments(): applying soil moisture and Tskin/ght1 increments' From e78cc6bedb1c0a6834c3e7ef6bde4cef5a5a1702 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Mon, 19 Feb 2024 20:59:55 -0700 Subject: [PATCH 251/308] Fix issue with select_varnames --- .../clsm_ensupd_upd_routines.F90 | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index c8710d6e..8ff56681 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -4420,22 +4420,27 @@ subroutine cat_enkf_increments( & N_select_varnames = 0 do ii = 1,N_obs_param - if (trim(obs_param(ii)%varname) == 'Tb') then N_select_varnames = N_select_varnames + 1 - select_varnames(N_select_varnames) = 'Tb' + select_varnames(N_select_varnames) = 'Tb' + exit end if + end do + do ii = 1,N_obs_param if (trim(obs_param(ii)%varname) == 'sfmc') then N_select_varnames = N_select_varnames + 1 - select_varnames(N_select_varnames) = 'sfmc' + select_varnames(N_select_varnames) = 'sfmc' + exit end if + end do + do ii = 1,N_obs_param if (trim(obs_param(ii)%varname) == 'sfds') then N_select_varnames = N_select_varnames + 1 - select_varnames(N_select_varnames) = 'sfds' - end if - + select_varnames(N_select_varnames) = 'sfds' + exit + end if end do ! Will get all species associated with Tb or sfds observations From f1431489f7e7a46a71a3286ce01b1c39811403f3 Mon Sep 17 00:00:00 2001 From: Qing Liu Date: Wed, 21 Feb 2024 09:33:35 -0500 Subject: [PATCH 252/308] read precipcor daily nc files --- .../GEOSmetforce_GridComp/LDAS_Forcing.F90 | 35 +++++++++++++------ 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 b/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 index 772183dc..39bc99f2 100755 --- a/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 @@ -3207,7 +3207,7 @@ subroutine get_GEOS( date_time, force_dtstep, met_path, met_tag, & logical :: minimize_shift, use_prec_corr, use_Predictor, tmp_init - logical :: daily_met_files + logical :: daily_met_files, daily_precipcorr_files integer :: nv_id, ierr, icount(3), istart(3), lonid, latid @@ -3696,9 +3696,9 @@ subroutine get_GEOS( date_time, force_dtstep, met_path, met_tag, & if ( (use_prec_corr) .and. (GEOSgcm_defs(GEOSgcm_var,1)(1:4)=='PREC') ) then call get_GEOS_corr_prec_filename(fname_full,file_exists,date_time_tmp, & - prec_path_tmp, met_tag_tmp, GEOSgcm_defs(GEOSgcm_var,:), precip_corr_file_ext ) + prec_path_tmp, met_tag_tmp, GEOSgcm_defs(GEOSgcm_var,:), precip_corr_file_ext,daily_precipcorr_files ) - single_time_in_file = .true. ! corr precip files are always hourly (incl. MERRA-2) + single_time_in_file = .not. daily_precipcorr_files ! corr precip files are always hourly (incl. MERRA-2) else @@ -5622,26 +5622,27 @@ subroutine GEOS_closefile(fid) ! **************************************************************** subroutine get_GEOS_corr_prec_filename(fname_full,file_exists, date_time, met_path, met_tag, & - GEOSgcm_defs, file_ext ) + GEOSgcm_defs, file_ext,daily_files ) implicit none character(*), intent(inout) :: fname_full logical,intent(out) :: file_exists + logical,intent(out) :: daily_files type(date_time_type), intent(in) :: date_time character(*), intent(in) :: met_path character(*), intent(in) :: met_tag character( 40), dimension(5), intent(in) :: GEOSgcm_defs character(*), intent(in) :: file_ext - + ! local variables - character(100) :: fname + character(100) :: fname, fname_tmp character(200) :: fdir - character(300) :: fname_full_tmp1, fname_full_tmp2 + character(300) :: fname_full_tmp1, fname_full_tmp2, fname_full_tmp3 character( 4) :: YYYY, HHMM character( 2) :: MM, DD - integer :: tmpind, tmpindend + integer :: tmpind, tmpindend,is character(len=*), parameter :: Iam = 'get_GEOS_corr_prec_filename' @@ -5678,7 +5679,7 @@ subroutine get_GEOS_corr_prec_filename(fname_full,file_exists, date_time, met_pa ! ----------------------------------------------------------------------- file_exists = .false. ! initialize - + daily_files = .false. ! first try: look for file in year/month dir ! (LDAS standard for corrected G5DAS precip) @@ -5691,8 +5692,20 @@ subroutine get_GEOS_corr_prec_filename(fname_full,file_exists, date_time, met_pa fname_full_tmp1 = trim(fname_full) ! remember for error log below + ! second try: look for daily file in year/month dir + is = index(fname,'z.nc') + fname_tmp = fname(1:is-6)//'.'//trim(file_ext) + fname_full = trim(fdir) // 'M' // MM // '/' // trim(fname_tmp) - ! second try: *without* "/Mmm" (month) dir + inquire(file=fname_full, exist=file_exists) + + if (file_exists) then + daily_files = .true. + return + endif ! done + fname_full_tmp2 = trim(fname_full) ! remember for error log below + + ! third try: *without* "/Mmm" (month) dir ! THIS TRY IS PROBABLY OBSOLETE BUT COULD EASILY BE TWEAKED TO LOOK ! IN year/month/day DIRECTORY (WHICH POSSIBLY APPLIES TO CORRECTED @@ -5705,7 +5718,7 @@ subroutine get_GEOS_corr_prec_filename(fname_full,file_exists, date_time, met_pa if (file_exists) return ! done - fname_full_tmp2 = trim(fname_full) ! remember for error log below + fname_full_tmp3 = trim(fname_full) ! remember for error log below ! last try: for GEOS FP with generic file names, try product counter '.V02.' in year/month dir From 38700d8b2e8b62b0295badfdac105c0850826300 Mon Sep 17 00:00:00 2001 From: Weiyuan Jiang Date: Wed, 21 Feb 2024 15:59:37 -0500 Subject: [PATCH 253/308] fix bug "+" string --- src/Applications/LDAS_App/ldas_setup | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Applications/LDAS_App/ldas_setup b/src/Applications/LDAS_App/ldas_setup index 3fc0aec3..f021f77d 100755 --- a/src/Applications/LDAS_App/ldas_setup +++ b/src/Applications/LDAS_App/ldas_setup @@ -1254,7 +1254,7 @@ class LDASsetup: expid = self.rqdExeInp['EXP_ID'] if self.GEOS_SITE == 'NAS': SBATCHQSUB = 'qsub' - fout.write("\nsed -i 's/if($capdate<$enddate) "//SBATCHQSUB//" /#if($capdate<$enddate) qsub /g' lenkf.j\n\n") + fout.write("\nsed -i 's/if($capdate<$enddate) "+SBATCHQSUB+"/#if($capdate<$enddate) "+SBATCHQSUB+"/g' lenkf.j\n\n") nSegments = self.nSegments for iseg in range(nSegments): if iseg ==0 : @@ -1288,7 +1288,7 @@ class LDASsetup: #fout.write("jobid%d=$(echo $(sbatch --dependency=afterany:$jobid%d --output=%s --error=%s lenkf.j) | cut -d' ' -f 4)\n"%(iseg,iseg-1,_logfile, _errfile)) fout.write("jobid%d=$(echo $(sbatch --dependency=afterok:$jobid%d lenkf.j) | cut -d' ' -f 4)\n"%(iseg,iseg-1)) fout.write("echo $jobid%d\n"%iseg ) - fout.write("\nsed -i 's/#if($capdate<$enddate) sbatch/if($capdate<$enddate) sbatch /g' lenkf.j") + fout.write("\nsed -i 's/#if($capdate<$enddate) "+SBATCHQSUB+"/if($capdate<$enddate) "+SBATCHQSUB+"/g' lenkf.j\n\n") fout.close() sp.call(['chmod', '755', self.rundir+'/ldas_batchrun.j']) From 2bc470831e4030409595b7905a045ad6816f9b78 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Wed, 21 Feb 2024 18:00:06 -0500 Subject: [PATCH 254/308] updated components.yaml with GEOS_Util v2.0.6 release that supports sparse checkout and new bcs layout --- components.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components.yaml b/components.yaml index a4c189d7..661b3b84 100644 --- a/components.yaml +++ b/components.yaml @@ -36,7 +36,7 @@ GMAO_Shared: GEOS_Util: local: ./src/Shared/@GMAO_Shared/@GEOS_Util remote: ../GEOS_Util.git - tag: v2.0.3 + tag: v2.0.6 sparse: ./config/GEOS_Util.sparse develop: main From b537d385748f1b8dce5eaa9458e0e57ca25f116a Mon Sep 17 00:00:00 2001 From: Weiyuan Jiang Date: Thu, 22 Feb 2024 12:47:10 -0800 Subject: [PATCH 255/308] get npes form PBS or SLURM --- src/Applications/LDAS_App/lenkf.j.template | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Applications/LDAS_App/lenkf.j.template b/src/Applications/LDAS_App/lenkf.j.template index 8659955d..7f6afcb0 100644 --- a/src/Applications/LDAS_App/lenkf.j.template +++ b/src/Applications/LDAS_App/lenkf.j.template @@ -419,7 +419,11 @@ while ( $counter <= ${NUM_SGMT} ) @ oserver_nodes = MY_OSERVER_NODES @ writers = MY_WRITERS_NPES - set total_npes = $SLURM_NTASKS + if (! $?SLURM_NTASKS) then + set total_npes = `wc -l $PBS_NODEFILE | awk '{print $1}'` + else + set total_npes = $SLURM_NTASKS + endif if ($oserver_nodes == 0) then set oserver_options = "" From 911a37a6ad48ed923bf2578141ade59420cd9c32 Mon Sep 17 00:00:00 2001 From: Qing Liu Date: Fri, 23 Feb 2024 08:29:04 -0500 Subject: [PATCH 256/308] update filename parse --- .../GEOSmetforce_GridComp/LDAS_Forcing.F90 | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 b/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 index 39bc99f2..349430d9 100755 --- a/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 @@ -5663,12 +5663,18 @@ subroutine get_GEOS_corr_prec_filename(fname_full,file_exists, date_time, met_pa fname = trim(met_tag) // '.' // trim(GEOSgcm_defs(3)) // '_corr.' // & YYYY // MM // DD // '_' // trim(HHMM) // '.V01.' // trim(file_ext) - + + fname_tmp = trim(met_tag) // '.' // trim(GEOSgcm_defs(3)) // '_corr.' // & + YYYY // MM // DD // '.V01.' // trim(file_ext) + else fname = trim(met_tag) // '.' // trim(GEOSgcm_defs(3)) // '_corr.' // & YYYY // MM // DD // '_' // trim(HHMM) // 'z.' // trim(file_ext) - + + fname_tmp = trim(met_tag) // '.' // trim(GEOSgcm_defs(3)) // '_corr.' // & + YYYY // MM // DD // '.' // trim(file_ext) + end if ! assemble dir name with "/Yyy" (year) dir but without "/Mmm" (month) dir @@ -5693,8 +5699,6 @@ subroutine get_GEOS_corr_prec_filename(fname_full,file_exists, date_time, met_pa fname_full_tmp1 = trim(fname_full) ! remember for error log below ! second try: look for daily file in year/month dir - is = index(fname,'z.nc') - fname_tmp = fname(1:is-6)//'.'//trim(file_ext) fname_full = trim(fdir) // 'M' // MM // '/' // trim(fname_tmp) inquire(file=fname_full, exist=file_exists) From 74f0ffb1699697444a9f7881b9733bb06604f23a Mon Sep 17 00:00:00 2001 From: "Lauren C. Andrews" Date: Fri, 23 Feb 2024 18:33:57 -0500 Subject: [PATCH 257/308] Add Aqua to DEFAULT.nml and change N_obs_species --- .../LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml | 39 +++++++++++++++++++ .../clsm_ensupd_glob_param.F90 | 2 +- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml b/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml index 0cf5fadf..6de70d4a 100644 --- a/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml +++ b/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml @@ -2168,6 +2168,45 @@ obs_param_nml(51)%xcorr = 0.25 obs_param_nml(51)%ycorr = 0.25 obs_param_nml(51)%adapt = 0 +! -------------------------------------------------------------------- +! +! 52 = MODIS Aqua snow cover area fraction (SCF) +! +! MOD10C1.*.061: MODIS Aqua SCF, 0.05deg CMG, daytime (01:30pm local) ascending overpass, version V61 +! +! for rule-based snow cover analysis (no obs error/pert specs) + +obs_param_nml(52)%descr = 'MYD10C1' +obs_param_nml(52)%orbit = 1 +obs_param_nml(52)%pol = 0 +obs_param_nml(52)%N_ang = 0 +obs_param_nml(52)%freq = 0. +obs_param_nml(52)%FOV = 0. +obs_param_nml(52)%FOV_units = 'deg' +obs_param_nml(52)%assim = .false. +obs_param_nml(52)%scale = .false. +obs_param_nml(52)%getinnov = .false. +obs_param_nml(52)%RTM_ID = 0 +obs_param_nml(52)%bias_Npar = 0 +obs_param_nml(52)%bias_trel = 864000 +obs_param_nml(52)%bias_tcut = 432000 +obs_param_nml(52)%nodata = -9999. +obs_param_nml(52)%varname = 'asnow' +obs_param_nml(52)%units = 'm2/m2' +obs_param_nml(52)%path = '/discover/nobackup/projects/S2SHMA/MODIS/MYD10C1_V61/' +obs_param_nml(52)%name = 'MYD10C1.Ayyyyddd.061.hdf' +obs_param_nml(52)%scalepath = '' +obs_param_nml(52)%scalename = '' +obs_param_nml(52)%flistpath = '' +obs_param_nml(52)%flistname = '' +obs_param_nml(52)%errstd = -9999. +obs_param_nml(52)%std_normal_max = -9999. +obs_param_nml(52)%zeromean = .false. +obs_param_nml(52)%coarsen_pert = .false. +obs_param_nml(52)%xcorr = 0. +obs_param_nml(52)%ycorr = 0. +obs_param_nml(52)%adapt = 0 + ! -------------------------------------------------------------------- / diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_glob_param.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_glob_param.F90 index 3d16c82b..db08e3a9 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_glob_param.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_glob_param.F90 @@ -48,7 +48,7 @@ module clsm_ensupd_glob_param ! total number of all obs species defined in namelist file ! (regardless of whether "assim" flag is true or false) - integer, parameter :: N_obs_species_nml = 51 + integer, parameter :: N_obs_species_nml = 52 ! ---------------------------------------------------------------------- ! From d31e5cbd54c4f5db3997f19ce6a9a9b598ece5c7 Mon Sep 17 00:00:00 2001 From: Rolf Reichle <54944691+gmao-rreichle@users.noreply.github.com> Date: Sat, 24 Feb 2024 09:20:57 -0500 Subject: [PATCH 258/308] minimal cleanup (white space, alignment, unnecessary declaration) from previous commits (LDAS_Forcing.F90) --- .../GEOSmetforce_GridComp/LDAS_Forcing.F90 | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 b/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 index 349430d9..c2290547 100755 --- a/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 @@ -3696,7 +3696,7 @@ subroutine get_GEOS( date_time, force_dtstep, met_path, met_tag, & if ( (use_prec_corr) .and. (GEOSgcm_defs(GEOSgcm_var,1)(1:4)=='PREC') ) then call get_GEOS_corr_prec_filename(fname_full,file_exists,date_time_tmp, & - prec_path_tmp, met_tag_tmp, GEOSgcm_defs(GEOSgcm_var,:), precip_corr_file_ext,daily_precipcorr_files ) + prec_path_tmp, met_tag_tmp, GEOSgcm_defs(GEOSgcm_var,:), precip_corr_file_ext, daily_precipcorr_files) single_time_in_file = .not. daily_precipcorr_files ! corr precip files are always hourly (incl. MERRA-2) @@ -5622,7 +5622,7 @@ subroutine GEOS_closefile(fid) ! **************************************************************** subroutine get_GEOS_corr_prec_filename(fname_full,file_exists, date_time, met_path, met_tag, & - GEOSgcm_defs, file_ext,daily_files ) + GEOSgcm_defs, file_ext, daily_files) implicit none character(*), intent(inout) :: fname_full @@ -5642,7 +5642,7 @@ subroutine get_GEOS_corr_prec_filename(fname_full,file_exists, date_time, met_pa character( 4) :: YYYY, HHMM character( 2) :: MM, DD - integer :: tmpind, tmpindend,is + integer :: tmpind, tmpindend character(len=*), parameter :: Iam = 'get_GEOS_corr_prec_filename' @@ -5661,19 +5661,19 @@ subroutine get_GEOS_corr_prec_filename(fname_full,file_exists, date_time, met_pa ! (as of 7 May 2020, no V02 or higher was issued for GEOS FP "lfo" products ! going back to Jun 2013) - fname = trim(met_tag) // '.' // trim(GEOSgcm_defs(3)) // '_corr.' // & + fname = trim(met_tag) // '.' // trim(GEOSgcm_defs(3)) // '_corr.' // & YYYY // MM // DD // '_' // trim(HHMM) // '.V01.' // trim(file_ext) fname_tmp = trim(met_tag) // '.' // trim(GEOSgcm_defs(3)) // '_corr.' // & - YYYY // MM // DD // '.V01.' // trim(file_ext) + YYYY // MM // DD // '.V01.' // trim(file_ext) else - fname = trim(met_tag) // '.' // trim(GEOSgcm_defs(3)) // '_corr.' // & + fname = trim(met_tag) // '.' // trim(GEOSgcm_defs(3)) // '_corr.' // & YYYY // MM // DD // '_' // trim(HHMM) // 'z.' // trim(file_ext) fname_tmp = trim(met_tag) // '.' // trim(GEOSgcm_defs(3)) // '_corr.' // & - YYYY // MM // DD // '.' // trim(file_ext) + YYYY // MM // DD // '.' // trim(file_ext) end if @@ -5705,8 +5705,9 @@ subroutine get_GEOS_corr_prec_filename(fname_full,file_exists, date_time, met_pa if (file_exists) then daily_files = .true. - return - endif ! done + return ! done + endif + fname_full_tmp2 = trim(fname_full) ! remember for error log below ! third try: *without* "/Mmm" (month) dir From d0b04fb58a391d0624e34b813c0af5d2183b3c4d Mon Sep 17 00:00:00 2001 From: Rolf Reichle <54944691+gmao-rreichle@users.noreply.github.com> Date: Sat, 24 Feb 2024 09:24:35 -0500 Subject: [PATCH 259/308] Fixed error log associated with previous changes in get_GEOS_corr_prec_filename() (LDAS_Forcing.F90) --- .../GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 b/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 index c2290547..b87e6734 100755 --- a/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 @@ -5754,6 +5754,7 @@ subroutine get_GEOS_corr_prec_filename(fname_full,file_exists, date_time, met_pa print '(400A)', trim(Iam) // ': Could not find any of the following files:' print '(400A)', trim(fname_full_tmp1) print '(400A)', trim(fname_full_tmp2) + print '(400A)', trim(fname_full_tmp3) print '(400A)', trim(fname_full) endif endif From 47d4bb98203011c98702c15f4a9282bf280b339f Mon Sep 17 00:00:00 2001 From: amfox37 Date: Mon, 26 Feb 2024 12:46:18 -0700 Subject: [PATCH 260/308] remove catdef from state for non-peatland tiles --- .../clsm_ensupd_upd_routines.F90 | 30 ++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index 8ff56681..05474126 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -4461,7 +4461,7 @@ subroutine cat_enkf_increments( & do kk=1,N_catd - N_state = 3 ! for now, assume only sfmc and/or sfds obs + N_state = 2 ! for now, assume only sfmc and/or sfds observations an no peatland catchments ! compute increments only snow-free and non-frozen tiles @@ -4490,6 +4490,12 @@ subroutine cat_enkf_increments( & N_selected_obs, ind_obs ) if (N_selected_obs>0) then + + ! Determine if peatland catchment and set N_state accordingly for SM observations + + if (cat_param(kk)%poros>=PEATCLSM_POROS_THRESHOLD) then + N_state = 3 + end if ! Determine if Tb observations are present @@ -4514,11 +4520,16 @@ subroutine cat_enkf_increments( & ! assemble State_minus ! (on input, cat_progn contains cat_progn_minus) - if ( N_state==3 ) then + if ( N_state==2 ) then + + State_incr(1,:) = cat_progn( kk,:)%srfexc/scale_srfexc + State_incr(2,:) = cat_progn( kk,:)%rzexc /scale_rzexc + + elseif ( N_state==3 ) then - State_incr(1,:) = (cat_progn( kk,:)%srfexc/scale_srfexc) - State_incr(2,:) = (cat_progn( kk,:)%rzexc /scale_rzexc) - State_incr(3,:) = (cat_progn( kk,:)%catdef/scale_catdef) + State_incr(1,:) = cat_progn( kk,:)%srfexc/scale_srfexc + State_incr(2,:) = cat_progn( kk,:)%rzexc /scale_rzexc + State_incr(3,:) = cat_progn( kk,:)%catdef/scale_catdef ! catdef in State elseif ( N_state==7 ) then @@ -4567,11 +4578,16 @@ subroutine cat_enkf_increments( & ! assemble cat_progn increments - if ( N_state==3 ) then + if ( N_state==2 ) then + + cat_progn_incr(kk,:)%srfexc = State_incr(1,:)*scale_srfexc + cat_progn_incr(kk,:)%rzexc = State_incr(2,:)*scale_rzexc + + elseif ( N_state==3 ) then cat_progn_incr(kk,:)%srfexc = State_incr(1,:)*scale_srfexc cat_progn_incr(kk,:)%rzexc = State_incr(2,:)*scale_rzexc - cat_progn_incr(kk,:)%catdef = State_incr(3,:)*scale_catdef + cat_progn_incr(kk,:)%catdef = State_incr(3,:)*scale_catdef ! catdef in State elseif ( N_state==7 ) then From af7d2ac311a79254e644d84ff1ccb638f3dff88b Mon Sep 17 00:00:00 2001 From: amfox37 Date: Mon, 26 Feb 2024 16:51:16 -0700 Subject: [PATCH 261/308] add ascat mask to read_obs --- .../clsm_ensupd_read_obs.F90 | 93 ++++++++++++++++++- 1 file changed, 91 insertions(+), 2 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index e7647e4c..963ecb5d 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -1576,7 +1576,8 @@ subroutine read_obs_sm_ASCAT_EUMET( & ! A. Fox, reichle, Sep 2023 - updated ! ! -------------------------------------------------------------------- - + + use netcdf implicit none ! inputs: @@ -1642,6 +1643,22 @@ subroutine read_obs_sm_ASCAT_EUMET( & character(8) :: subset + ! -------------------- + ! + ! Variables for mask read + + real, dimension(:), allocatable :: lat_mask, lon_mask + real :: lat_target, lon_target, dist, dist_min + + integer(kind=1), dimension(:), allocatable :: mask + integer :: ncid, varid_mask, ierr, varid_lat, varid_lon, gpi_dimid + integer :: N_mask, idx_nearest + + character(300) :: mask_filename + character(300) :: mask_name + + logical :: file_exists + ! -------------------- character(100), dimension(2*N_fnames_max) :: fname_list ! max 2 days of files @@ -1803,6 +1820,57 @@ subroutine read_obs_sm_ASCAT_EUMET( & end do ! end file loop + ! ---------------------------------------------------------------- + ! + ! Read in ASCAT mask file + + ! TODO: Decide how to handle mask file name and path (e.g., from obs_param nml) + mask_filename = trim(this_obs_param%flistpath) // '/' // 'ASCAT_mask' // '.nc' + ! mask_filename = trim(this_obs_param%flistpath) // '/' // & + ! 'subsurface_scattering_ASCAT_ERA5_Land' // '.nc' + + if (logit) write (logunit,'(400A)') ' reading ', trim(mask_filename) + + ! Check if file exists + + inquire(file=mask_filename, exist=file_exists) + + if (.not. file_exists) then + err_msg = 'Mask file not found' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + end if + + ! Openthe netCDF mask file + ierr = nf90_open(mask_filename, nf90_nowrite, ncid) + + ! TODO: Check how to handle alternative mask names + ! Get the variable ID + mask_name = 'mask' ! Case using "ASCAT_mask.nc" + ! mask_name = 'subsurface_mask' ! Case using "subsurface_scattering_ASCAT_ERA5_Land.nc" + + ierr = nf90_inq_varid(ncid, mask_name, varid_mask) + ierr = nf90_inq_varid(ncid, 'lat', varid_lat) + ierr = nf90_inq_varid(ncid, 'lon', varid_lon) + + ! Get the variable dimensions + ierr = nf90_inq_dimid(ncid, 'gpi', gpi_dimid) + + ! Get the dimension size + ierr = nf90_inquire_dimension(ncid, gpi_dimid, len = N_mask) + + ! Allocate memory for the variables + allocate(mask(N_mask)) + allocate(lat_mask(N_mask)) + allocate(lon_mask(N_mask)) + + ! Read the variables + ierr = nf90_get_var(ncid, varid_mask, mask) + ierr = nf90_get_var(ncid, varid_lat, lat_mask) + ierr = nf90_get_var(ncid, varid_lon, lon_mask) + + ! Close the netCDF mask file + ierr = nf90_close(ncid) + ! ---------------------------------------------------------------- ! ! select obs within assimilation window and from desired orbit direction; apply basic QC based on obs info @@ -1847,6 +1915,24 @@ subroutine read_obs_sm_ASCAT_EUMET( & ! skip if inundation and wetland fraction > 10% if(tmp_data(kk, 12) > 10.) cycle + + ! skip if masked + lat_target = tmp_data(kk, 13) + lon_target = tmp_data(kk, 14) + + dist_min = huge(dist_min) + idx_nearest = 0 + + ! find nearest mask point (probably slow) + do ii = 1,N_mask + dist = (lat_mask(ii)-lat_target)**2 + (lon_mask(ii)-lon_target)**2 + if (dist < dist_min) then + dist_min = dist + idx_nearest = ii + end if + end do + + if (mask(idx_nearest) /= 0) cycle N_tmp = N_tmp + 1 ! passed all QC @@ -1894,7 +1980,10 @@ subroutine read_obs_sm_ASCAT_EUMET( & deallocate(tmp1_lon) deallocate(tmp1_lat) deallocate(tmp1_obs) - deallocate(tmp_data) + deallocate(tmp_data) + deallocate(mask) + deallocate(lat_mask) + deallocate(lon_mask) else From 9f02392ce6dc5766477a5fc5ff82619e8e2aa032 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Tue, 27 Feb 2024 07:51:06 -0500 Subject: [PATCH 262/308] disabled updated_type=[1,2]; cleanup of new update_type=13 (clsm_ensupd_upd_routines.F90, clsm_ensupd_enkf_update.F90, LDASsa_DEFAULT_inputs_ensupd.nml) --- .../LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml | 30 +++++----- .../clsm_ensupd_enkf_update.F90 | 5 +- .../clsm_ensupd_upd_routines.F90 | 59 +++++++++++-------- 3 files changed, 54 insertions(+), 40 deletions(-) diff --git a/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml b/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml index b849d51d..afacd0f3 100644 --- a/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml +++ b/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml @@ -19,20 +19,22 @@ ! update type - for details see subroutine cat_enkf_update() ! (note: all 3d updates use compact support) ! -! local = "1d", regional = "3d" -! -! update_type = 0: NO assimilation, NO bias correction -! update_type = 1: 1d soil moisture analysis; sfmc obs -! update_type = 2: 3d soil moisture analysis; sfmc obs -! update_type = 3: 1d Tskin (assim incr NOT applied, use w/ bias corr) analysis; Tskin obs -! update_type = 4: 1d Tskin/ght1 (assim incr applied, use w/ or w/o bias corr) analysis; Tskin obs -! update_type = 5: 1d Tskin/ght1 (assim incr NOT applied, use w/ bias corr) analysis; Tskin obs -! update_type = 6: 1d soil moisture/Tskin/ght(1); TB obs -! update_type = 7: 3d Tskin/ght1 update; Tskin obs -! update_type = 8: 3d soil moisture/Tskin/ght(1); TB obs -! update_type = 9: 1d Tskin/ght1 update; FT obs -! update_type = 10: 3d soil moisture/Tskin/ght(1) excl. catdef unless PEATCLSM tile; TB obs -! update_type = 13: Multivariate combination of 2 and 10; sfmc and TB obs +! local = "1d", regional = "3d" +! +! # = no longer supported +! +! update_type = 0: NO assimilation, NO bias correction +! # update_type = 1: 1d soil moisture analysis; sfmc obs +! # update_type = 2: 3d soil moisture analysis; sfmc obs +! update_type = 3: 1d Tskin (assim incr NOT applied, use w/ bias corr) analysis; Tskin obs +! update_type = 4: 1d Tskin/ght1 (assim incr applied, use w/ or w/o bias corr) analysis; Tskin obs +! update_type = 5: 1d Tskin/ght1 (assim incr NOT applied, use w/ bias corr) analysis; Tskin obs +! update_type = 6: 1d soil moisture/Tskin/ght(1); TB obs +! update_type = 7: 3d Tskin/ght1 update; Tskin obs +! update_type = 8: 3d soil moisture/Tskin/ght(1); TB obs +! update_type = 9: 1d Tskin/ght1 update; FT obs +! update_type = 10: 3d soil moisture/Tskin/ght(1) excl. catdef unless PEATCLSM tile; TB obs +! update_type = 13: 3d soil moisture/Tskin/ght(1) excl. catdef unless PEATCLSM tile; sfmc and TB obs update_type = 0 diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 index 16449a65..d90ae7cc 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 @@ -1332,8 +1332,9 @@ subroutine apply_enkf_increments( N_catd, N_ens, update_type, & case (6,8,9,10,13) select_update_type ! soil moisture and temperature update - ! for update_type 10, catdef increments may be zero by design - ! for update_type 13, could produce multiple zero increments (i.e. tc1, tc2, tc4 will be unchanged if soil moisture observations only) + ! some of the increments fields below may be zero by design + ! (e.g., tc[X]=ght(1)=0 in update_type=13 when only sfmc or sfds obs are assimilated; + ! or catdef=0 in update_type 10 or 13 when tile has mineral soil) if (logit) write (logunit,*) & 'apply_enkf_increments(): applying soil moisture and Tskin/ght1 increments' diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index 05474126..c402cbf8 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -3604,6 +3604,10 @@ subroutine cat_enkf_increments( & if (logit) write (logunit,*) 'get 1d soil moisture increments; sfmc obs' + ! disable update_type=1 (b/c it includes catdef in state vector for mineral soil) + + call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'update_type=1 no longer supported; use update_type=13 instead') + N_select_varnames = 2 select_varnames(1) = 'sfmc' @@ -3673,6 +3677,10 @@ subroutine cat_enkf_increments( & if (logit) write (logunit,*) 'get 3d soil moisture increments; sfmc obs' + ! disable update_type=2 (b/c it includes catdef in state vector for mineral soil) + + call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'update_type=2 no longer supported; use update_type=13 instead') + N_select_varnames = 2 select_varnames(1) = 'sfmc' @@ -4409,11 +4417,18 @@ subroutine cat_enkf_increments( & case (13) select_update_type ! 3d soil moisture/Tskin/ght(1) analysis; Tb+sfmc+sfds obs - ! combines update_types 2 and 10 - ! ! update each tile separately using all observations within customized halo around each tile ! - ! amfox, 14 September 2023 + ! state vector differs for each tile depending on assimilated obs and soil type + ! + ! obs | soil | N_state | state vector + ! ---------------------------------------------------------------------- + ! sfcm/sfds only | mineral | 2 | srfexc, rzexc + ! sfcm/sfds only | peat | 3 | srfexc, rzexc, catdef, + ! sfcm/sfds & Tb | mineral | 6 | srfexc, rzexc, tc[x], ght(1) + ! sfcm/sfds & Tb | peat | 7 | srfexc, rzexc, catdef, tc[x], ght(1) + ! + ! amfox+rreichle, 26 Feb 2024 if (logit) write (logunit,*) 'get 3d soil moisture/Tskin/ght(1) increments; Tb+sfmc obs' @@ -4461,12 +4476,12 @@ subroutine cat_enkf_increments( & do kk=1,N_catd - N_state = 2 ! for now, assume only sfmc and/or sfds observations an no peatland catchments + N_state = 2 ! initialize (always have srfexc and rzexc in state vector) - ! compute increments only snow-free and non-frozen tiles + ! compute increments only for snow-free and non-frozen tiles - if ( (SWE_ensavg(kk) < SWE_threshold) .and. & - (tp1_ensavg(kk) > tp1_threshold)) then + if ( (SWE_ensavg(kk) < SWE_threshold) .and. & + (tp1_ensavg(kk) > tp1_threshold) ) then ! find observations within halo around tile kk @@ -4491,14 +4506,10 @@ subroutine cat_enkf_increments( & if (N_selected_obs>0) then - ! Determine if peatland catchment and set N_state accordingly for SM observations - - if (cat_param(kk)%poros>=PEATCLSM_POROS_THRESHOLD) then - N_state = 3 - end if - ! Determine if Tb observations are present + found_Tb_obs = .false. + do ii = 1,N_select_species_Tb do jj = 1,N_selected_obs if (select_species_Tb(ii) == Observations(ind_obs(jj))%species) then @@ -4509,13 +4520,13 @@ subroutine cat_enkf_increments( & if (found_Tb_obs) exit end do - if (found_Tb_obs) then - if (cat_param(kk)%poros>=PEATCLSM_POROS_THRESHOLD) then - N_state = 7 - else - N_state = 6 - end if - end if + ! if Tb_obs are present, add tc[X] and ght(1) to state vector + + if (found_Tb_obs) N_state = N_state + 4 + + ! for peatland tile, add catdef to state vector + + if (cat_param(kk)%poros>=PEATCLSM_POROS_THRESHOLD) N_state = N_state + 1 ! assemble State_minus ! (on input, cat_progn contains cat_progn_minus) @@ -4531,11 +4542,10 @@ subroutine cat_enkf_increments( & State_incr(2,:) = cat_progn( kk,:)%rzexc /scale_rzexc State_incr(3,:) = cat_progn( kk,:)%catdef/scale_catdef ! catdef in State - elseif ( N_state==7 ) then + elseif ( N_state==6 ) then State_incr(1,:) = cat_progn( kk,:)%srfexc/scale_srfexc State_incr(2,:) = cat_progn( kk,:)%rzexc /scale_rzexc - State_incr(3,:) = cat_progn( kk,:)%catdef/scale_catdef ! catdef in State State_incr(4,:) = cat_progn( kk,:)%tc1 /scale_temp State_incr(5,:) = cat_progn( kk,:)%tc2 /scale_temp @@ -4546,6 +4556,7 @@ subroutine cat_enkf_increments( & State_incr(1,:) = cat_progn( kk,:)%srfexc/scale_srfexc State_incr(2,:) = cat_progn( kk,:)%rzexc /scale_rzexc + State_incr(3,:) = cat_progn( kk,:)%catdef/scale_catdef ! catdef in State State_incr(3,:) = cat_progn( kk,:)%tc1 /scale_temp State_incr(4,:) = cat_progn( kk,:)%tc2 /scale_temp @@ -4589,11 +4600,10 @@ subroutine cat_enkf_increments( & cat_progn_incr(kk,:)%rzexc = State_incr(2,:)*scale_rzexc cat_progn_incr(kk,:)%catdef = State_incr(3,:)*scale_catdef ! catdef in State - elseif ( N_state==7 ) then + elseif ( N_state==6 ) then cat_progn_incr(kk,:)%srfexc = State_incr(1,:)*scale_srfexc cat_progn_incr(kk,:)%rzexc = State_incr(2,:)*scale_rzexc - cat_progn_incr(kk,:)%catdef = State_incr(3,:)*scale_catdef ! catdef in State cat_progn_incr(kk,:)%tc1 = State_incr(4,:)*scale_temp cat_progn_incr(kk,:)%tc2 = State_incr(5,:)*scale_temp @@ -4604,6 +4614,7 @@ subroutine cat_enkf_increments( & cat_progn_incr(kk,:)%srfexc = State_incr(1,:)*scale_srfexc cat_progn_incr(kk,:)%rzexc = State_incr(2,:)*scale_rzexc + cat_progn_incr(kk,:)%catdef = State_incr(3,:)*scale_catdef ! catdef in State cat_progn_incr(kk,:)%tc1 = State_incr(3,:)*scale_temp cat_progn_incr(kk,:)%tc2 = State_incr(4,:)*scale_temp From 399c6b08ff3ae5e72946c6d3da71ec355b0708a5 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Tue, 27 Feb 2024 17:42:05 -0700 Subject: [PATCH 263/308] replace loops with minloc --- .../clsm_ensupd_read_obs.F90 | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 963ecb5d..82ab8301 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -1647,8 +1647,8 @@ subroutine read_obs_sm_ASCAT_EUMET( & ! ! Variables for mask read - real, dimension(:), allocatable :: lat_mask, lon_mask - real :: lat_target, lon_target, dist, dist_min + real, dimension(:), allocatable :: lat_mask, lon_mask, dist + real :: lat_target, lon_target, dist_min integer(kind=1), dimension(:), allocatable :: mask integer :: ncid, varid_mask, ierr, varid_lat, varid_lon, gpi_dimid @@ -1862,6 +1862,7 @@ subroutine read_obs_sm_ASCAT_EUMET( & allocate(mask(N_mask)) allocate(lat_mask(N_mask)) allocate(lon_mask(N_mask)) + allocate(dist(N_mask)) ! Read the variables ierr = nf90_get_var(ncid, varid_mask, mask) @@ -1924,13 +1925,16 @@ subroutine read_obs_sm_ASCAT_EUMET( & idx_nearest = 0 ! find nearest mask point (probably slow) - do ii = 1,N_mask - dist = (lat_mask(ii)-lat_target)**2 + (lon_mask(ii)-lon_target)**2 - if (dist < dist_min) then - dist_min = dist - idx_nearest = ii - end if - end do + ! do ii = 1,N_mask + ! dist = (lat_mask(ii)-lat_target)**2 + (lon_mask(ii)-lon_target)**2 + ! if (dist < dist_min) then + ! dist_min = dist + ! idx_nearest = ii + ! end if + ! end do + + dist = sqrt((lat_mask-lat_target)**2 + (lon_mask-lon_target)**2) + idx_nearest = minloc(dist, dim=1) if (mask(idx_nearest) /= 0) cycle @@ -1984,6 +1988,7 @@ subroutine read_obs_sm_ASCAT_EUMET( & deallocate(mask) deallocate(lat_mask) deallocate(lon_mask) + deallocate(dist) else From f208e3fba71a4d34cebdeda96a586c6e74d85832 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Tue, 27 Feb 2024 21:44:52 -0700 Subject: [PATCH 264/308] move to fixed lat/lon ascat mask --- .../clsm_ensupd_read_obs.F90 | 73 ++++++++++--------- 1 file changed, 37 insertions(+), 36 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 82ab8301..cc2aefcd 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -1647,12 +1647,14 @@ subroutine read_obs_sm_ASCAT_EUMET( & ! ! Variables for mask read - real, dimension(:), allocatable :: lat_mask, lon_mask, dist - real :: lat_target, lon_target, dist_min + real :: lat_target, lon_target, ll_lon, ll_lat, dlon, dlat - integer(kind=1), dimension(:), allocatable :: mask - integer :: ncid, varid_mask, ierr, varid_lat, varid_lon, gpi_dimid - integer :: N_mask, idx_nearest + integer(kind=1), dimension(:,:), allocatable :: mask + integer :: ncid, ierr, j_ind, i_ind + integer :: N_lon, N_lat + integer :: lon_dimid, lat_dimid + integer :: lon_varid, lat_varid, mask_varid + integer :: ll_lon_varid, ll_lat_varid, dlon_varid, dlat_varid character(300) :: mask_filename character(300) :: mask_name @@ -1844,30 +1846,42 @@ subroutine read_obs_sm_ASCAT_EUMET( & ierr = nf90_open(mask_filename, nf90_nowrite, ncid) ! TODO: Check how to handle alternative mask names + ! Get the variable ID mask_name = 'mask' ! Case using "ASCAT_mask.nc" ! mask_name = 'subsurface_mask' ! Case using "subsurface_scattering_ASCAT_ERA5_Land.nc" - ierr = nf90_inq_varid(ncid, mask_name, varid_mask) - ierr = nf90_inq_varid(ncid, 'lat', varid_lat) - ierr = nf90_inq_varid(ncid, 'lon', varid_lon) + ierr = nf90_inq_varid(ncid, mask_name, mask_varid) + ierr = nf90_inq_varid(ncid, 'll_lon', ll_lon_varid) + ierr = nf90_inq_varid(ncid, 'll_lat', ll_lat_varid) + ierr = nf90_inq_varid(ncid, 'd_lon', dlon_varid) + ierr = nf90_inq_varid(ncid, 'd_lat', dlat_varid) ! Get the variable dimensions - ierr = nf90_inq_dimid(ncid, 'gpi', gpi_dimid) + ierr = nf90_inq_dimid(ncid, 'lon', lon_dimid) + ierr = nf90_inq_dimid(ncid, 'lat', lat_dimid) ! Get the dimension size - ierr = nf90_inquire_dimension(ncid, gpi_dimid, len = N_mask) + ierr = nf90_inquire_dimension(ncid, lon_dimid, len = N_lon) + ierr = nf90_inquire_dimension(ncid, lat_dimid, len = N_lat) + + ! Get the mask ID + mask_name = 'mask' ! Case using "ASCAT_mask.nc" + ! mask_name = 'subsurface_mask' ! Case using "subsurface_scattering_ASCAT_ERA5_Land.nc" + ierr = nf90_inq_varid(ncid, mask_name, mask_varid) + + ! Read grid variables + + ierr = nf90_get_var(ncid, ll_lon_varid, ll_lon) + ierr = nf90_get_var(ncid, ll_lat_varid, ll_lat) + ierr = nf90_get_var(ncid, dlon_varid, dlon) + ierr = nf90_get_var(ncid, dlat_varid, dlat) - ! Allocate memory for the variables - allocate(mask(N_mask)) - allocate(lat_mask(N_mask)) - allocate(lon_mask(N_mask)) - allocate(dist(N_mask)) + ! Allocate memory for the mask + allocate(mask(N_lat, N_lon)) - ! Read the variables - ierr = nf90_get_var(ncid, varid_mask, mask) - ierr = nf90_get_var(ncid, varid_lat, lat_mask) - ierr = nf90_get_var(ncid, varid_lon, lon_mask) + ! Read the mask + ierr = nf90_get_var(ncid, mask_varid, mask) ! Close the netCDF mask file ierr = nf90_close(ncid) @@ -1920,23 +1934,13 @@ subroutine read_obs_sm_ASCAT_EUMET( & ! skip if masked lat_target = tmp_data(kk, 13) lon_target = tmp_data(kk, 14) - - dist_min = huge(dist_min) - idx_nearest = 0 - ! find nearest mask point (probably slow) - ! do ii = 1,N_mask - ! dist = (lat_mask(ii)-lat_target)**2 + (lon_mask(ii)-lon_target)**2 - ! if (dist < dist_min) then - ! dist_min = dist - ! idx_nearest = ii - ! end if - ! end do + ! Find indices for ASCAT mask for this observation lat/lon - dist = sqrt((lat_mask-lat_target)**2 + (lon_mask-lon_target)**2) - idx_nearest = minloc(dist, dim=1) + i_ind = ceiling((lon_target - ll_lon)/dlon) + j_ind = ceiling((lat_target - ll_lat)/dlat) - if (mask(idx_nearest) /= 0) cycle + if (mask(j_ind, i_ind) /= 0) cycle N_tmp = N_tmp + 1 ! passed all QC @@ -1986,9 +1990,6 @@ subroutine read_obs_sm_ASCAT_EUMET( & deallocate(tmp1_obs) deallocate(tmp_data) deallocate(mask) - deallocate(lat_mask) - deallocate(lon_mask) - deallocate(dist) else From 6f6b52ae8695d459356549bf1ba0dc5dd61afeca Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Wed, 28 Feb 2024 14:11:43 -0500 Subject: [PATCH 265/308] moved MODIS SCF species into adjacent blocks in LDASsa_DEFAULT_inputs_ensupd.nml --- .../LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml | 92 +++++++++++++------ .../clsm_ensupd_glob_param.F90 | 4 +- 2 files changed, 66 insertions(+), 30 deletions(-) diff --git a/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml b/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml index 06c9ccdc..fc9016d7 100644 --- a/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml +++ b/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml @@ -1154,42 +1154,38 @@ obs_param_nml(24)%adapt = 0 ! -------------------------------------------------------------------- ! -! 25 = MODIS Terra snow cover area fraction (SCF) -! -! MOD10C1.*.061: MODIS Terra SCF, 0.05deg CMG, daytime (10:30am local) descending overpass, version V61 -! -! for rule-based snow cover analysis (no obs error/pert specs) - -obs_param_nml(25)%descr = 'MOD10C1' -obs_param_nml(25)%orbit = 2 -obs_param_nml(25)%pol = 0 -obs_param_nml(25)%N_ang = 0 -obs_param_nml(25)%freq = 0. -obs_param_nml(25)%FOV = 0. -obs_param_nml(25)%FOV_units = 'deg' +! 25 = [empty] + +obs_param_nml(25)%descr = 'NULL' +obs_param_nml(25)%orbit = -9999 +obs_param_nml(25)%pol = -9999 +obs_param_nml(25)%N_ang = -9999 +obs_param_nml(25)%freq = -9999. +obs_param_nml(25)%FOV = -9999. +obs_param_nml(25)%FOV_units = 'NULL' obs_param_nml(25)%assim = .false. obs_param_nml(25)%scale = .false. obs_param_nml(25)%getinnov = .false. -obs_param_nml(25)%RTM_ID = 0 -obs_param_nml(25)%bias_Npar = 0 -obs_param_nml(25)%bias_trel = 864000 -obs_param_nml(25)%bias_tcut = 432000 +obs_param_nml(25)%RTM_ID = -9999 +obs_param_nml(25)%bias_Npar = -9999 +obs_param_nml(25)%bias_trel = -9999 +obs_param_nml(25)%bias_tcut = -9999 obs_param_nml(25)%nodata = -9999. -obs_param_nml(25)%varname = 'asnow' -obs_param_nml(25)%units = 'm2/m2' -obs_param_nml(25)%path = '/discover/nobackup/projects/S2SHMA/MODIS/MOD10C1_V61/' -obs_param_nml(25)%name = 'MOD10C1.Ayyyyddd.061.hdf' -obs_param_nml(25)%scalepath = '' -obs_param_nml(25)%scalename = '' -obs_param_nml(25)%flistpath = '' -obs_param_nml(25)%flistname = '' +obs_param_nml(25)%varname = 'NULL' +obs_param_nml(25)%units = 'NULL' +obs_param_nml(25)%path = 'NULL' +obs_param_nml(25)%name = 'NULL' +obs_param_nml(25)%scalepath = 'NULL' +obs_param_nml(25)%scalename = 'NULL' +obs_param_nml(25)%flistpath = 'NULL' +obs_param_nml(25)%flistname = 'NULL' obs_param_nml(25)%errstd = -9999. obs_param_nml(25)%std_normal_max = -9999. obs_param_nml(25)%zeromean = .false. obs_param_nml(25)%coarsen_pert = .false. -obs_param_nml(25)%xcorr = 0. -obs_param_nml(25)%ycorr = 0. -obs_param_nml(25)%adapt = 0 +obs_param_nml(25)%xcorr = -9999. +obs_param_nml(25)%ycorr = -9999. +obs_param_nml(25)%adapt = -9999 ! -------------------------------------------------------------------- ! @@ -2210,6 +2206,46 @@ obs_param_nml(52)%xcorr = 0. obs_param_nml(52)%ycorr = 0. obs_param_nml(52)%adapt = 0 +! -------------------------------------------------------------------- +! +! 53 = MODIS Terra snow cover area fraction (SCF) +! +! MOD10C1.*.061: MODIS Terra SCF, 0.05deg CMG, daytime (10:30am local) descending overpass, version V61 +! +! for rule-based snow cover analysis (no obs error/pert specs) + +obs_param_nml(53)%descr = 'MOD10C1' +obs_param_nml(53)%orbit = 2 +obs_param_nml(53)%pol = 0 +obs_param_nml(53)%N_ang = 0 +obs_param_nml(53)%freq = 0. +obs_param_nml(53)%FOV = 0. +obs_param_nml(53)%FOV_units = 'deg' +obs_param_nml(53)%assim = .false. +obs_param_nml(53)%scale = .false. +obs_param_nml(53)%getinnov = .false. +obs_param_nml(53)%RTM_ID = 0 +obs_param_nml(53)%bias_Npar = 0 +obs_param_nml(53)%bias_trel = 864000 +obs_param_nml(53)%bias_tcut = 432000 +obs_param_nml(53)%nodata = -9999. +obs_param_nml(53)%varname = 'asnow' +obs_param_nml(53)%units = 'm2/m2' +obs_param_nml(53)%path = '/discover/nobackup/projects/S2SHMA/MODIS/MOD10C1_V61/' +obs_param_nml(53)%name = 'MOD10C1.Ayyyyddd.061.hdf' +obs_param_nml(53)%scalepath = '' +obs_param_nml(53)%scalename = '' +obs_param_nml(53)%flistpath = '' +obs_param_nml(53)%flistname = '' +obs_param_nml(53)%errstd = -9999. +obs_param_nml(53)%std_normal_max = -9999. +obs_param_nml(53)%zeromean = .false. +obs_param_nml(53)%coarsen_pert = .false. +obs_param_nml(53)%xcorr = 0. +obs_param_nml(53)%ycorr = 0. +obs_param_nml(53)%adapt = 0 + + ! -------------------------------------------------------------------- / diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_glob_param.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_glob_param.F90 index db08e3a9..678a0978 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_glob_param.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_glob_param.F90 @@ -45,10 +45,10 @@ module clsm_ensupd_glob_param ! ----------------------------------------------------------------------- ! - ! total number of all obs species defined in namelist file + ! total number of all obs species defined in "ensupd" namelist file ! (regardless of whether "assim" flag is true or false) - integer, parameter :: N_obs_species_nml = 52 + integer, parameter :: N_obs_species_nml = 53 ! ---------------------------------------------------------------------- ! From 85733b7b96e322739f999deb4d8f35b8b939b722 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Wed, 28 Feb 2024 16:51:22 -0500 Subject: [PATCH 266/308] ascat mask tidy up --- .../clsm_ensupd_read_obs.F90 | 31 ++++++------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index cc2aefcd..8080c8c2 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -1827,9 +1827,7 @@ subroutine read_obs_sm_ASCAT_EUMET( & ! Read in ASCAT mask file ! TODO: Decide how to handle mask file name and path (e.g., from obs_param nml) - mask_filename = trim(this_obs_param%flistpath) // '/' // 'ASCAT_mask' // '.nc' - ! mask_filename = trim(this_obs_param%flistpath) // '/' // & - ! 'subsurface_scattering_ASCAT_ERA5_Land' // '.nc' + mask_filename = trim(this_obs_param%flistpath) // '/' // 'ascat_subsurface_mask' // '.nc' if (logit) write (logunit,'(400A)') ' reading ', trim(mask_filename) @@ -1845,17 +1843,12 @@ subroutine read_obs_sm_ASCAT_EUMET( & ! Openthe netCDF mask file ierr = nf90_open(mask_filename, nf90_nowrite, ncid) - ! TODO: Check how to handle alternative mask names - - ! Get the variable ID - mask_name = 'mask' ! Case using "ASCAT_mask.nc" - ! mask_name = 'subsurface_mask' ! Case using "subsurface_scattering_ASCAT_ERA5_Land.nc" - - ierr = nf90_inq_varid(ncid, mask_name, mask_varid) - ierr = nf90_inq_varid(ncid, 'll_lon', ll_lon_varid) - ierr = nf90_inq_varid(ncid, 'll_lat', ll_lat_varid) - ierr = nf90_inq_varid(ncid, 'd_lon', dlon_varid) - ierr = nf90_inq_varid(ncid, 'd_lat', dlat_varid) + ! Get the variable IDs + ierr = nf90_inq_varid(ncid, 'mask', mask_varid) + ierr = nf90_inq_varid(ncid, 'll_lon', ll_lon_varid) + ierr = nf90_inq_varid(ncid, 'll_lat', ll_lat_varid) + ierr = nf90_inq_varid(ncid, 'd_lon', dlon_varid) + ierr = nf90_inq_varid(ncid, 'd_lat', dlat_varid) ! Get the variable dimensions ierr = nf90_inq_dimid(ncid, 'lon', lon_dimid) @@ -1865,13 +1858,7 @@ subroutine read_obs_sm_ASCAT_EUMET( & ierr = nf90_inquire_dimension(ncid, lon_dimid, len = N_lon) ierr = nf90_inquire_dimension(ncid, lat_dimid, len = N_lat) - ! Get the mask ID - mask_name = 'mask' ! Case using "ASCAT_mask.nc" - ! mask_name = 'subsurface_mask' ! Case using "subsurface_scattering_ASCAT_ERA5_Land.nc" - ierr = nf90_inq_varid(ncid, mask_name, mask_varid) - ! Read grid variables - ierr = nf90_get_var(ncid, ll_lon_varid, ll_lon) ierr = nf90_get_var(ncid, ll_lat_varid, ll_lat) ierr = nf90_get_var(ncid, dlon_varid, dlon) @@ -1931,15 +1918,15 @@ subroutine read_obs_sm_ASCAT_EUMET( & ! skip if inundation and wetland fraction > 10% if(tmp_data(kk, 12) > 10.) cycle - ! skip if masked + ! observation lat/lon lat_target = tmp_data(kk, 13) lon_target = tmp_data(kk, 14) ! Find indices for ASCAT mask for this observation lat/lon - i_ind = ceiling((lon_target - ll_lon)/dlon) j_ind = ceiling((lat_target - ll_lat)/dlat) + ! skip masked if (mask(j_ind, i_ind) /= 0) cycle N_tmp = N_tmp + 1 ! passed all QC From 9687ac9894cc042d6b216c1c5abd14e011a53d28 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Wed, 28 Feb 2024 17:30:15 -0500 Subject: [PATCH 267/308] remove mask_name declaration --- .../GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 8080c8c2..6e76af18 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -1657,7 +1657,6 @@ subroutine read_obs_sm_ASCAT_EUMET( & integer :: ll_lon_varid, ll_lat_varid, dlon_varid, dlat_varid character(300) :: mask_filename - character(300) :: mask_name logical :: file_exists From 0a07f81a88f41e6b784067338f29d95ac0319a7c Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Wed, 28 Feb 2024 18:58:07 -0500 Subject: [PATCH 268/308] renamed variables for ASCAT mask for clarity (clsm_ensupd_read_obs.F90) --- .../clsm_ensupd_read_obs.F90 | 79 +++++++++---------- 1 file changed, 38 insertions(+), 41 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 6e76af18..08726fc1 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -1574,6 +1574,7 @@ subroutine read_obs_sm_ASCAT_EUMET( & ! ! Q. Liu, Nov 2019 - based on read_obs_sm_ASCAT ! A. Fox, reichle, Sep 2023 - updated + ! A. Fox, reichle, Feb 2024 - added ASCAT obs mask ! ! -------------------------------------------------------------------- @@ -1645,20 +1646,20 @@ subroutine read_obs_sm_ASCAT_EUMET( & ! -------------------- ! - ! Variables for mask read + ! variables for obs mask read - real :: lat_target, lon_target, ll_lon, ll_lat, dlon, dlat - - integer(kind=1), dimension(:,:), allocatable :: mask - integer :: ncid, ierr, j_ind, i_ind - integer :: N_lon, N_lat - integer :: lon_dimid, lat_dimid - integer :: lon_varid, lat_varid, mask_varid - integer :: ll_lon_varid, ll_lat_varid, dlon_varid, dlat_varid + integer(kind=1), dimension(:,:), allocatable :: mask_data + + real :: mask_ll_lon, mask_ll_lat, mask_dlon, mask_dlat + + integer :: ncid, ierr + integer :: mask_N_lon, mask_N_lat, mask_lon_ind, mask_lat_ind + integer :: lon_dimid, lat_dimid + integer :: mask_varid, ll_lon_varid, ll_lat_varid, dlon_varid, dlat_varid character(300) :: mask_filename - logical :: file_exists + logical :: file_exists ! -------------------- @@ -1823,53 +1824,53 @@ subroutine read_obs_sm_ASCAT_EUMET( & ! ---------------------------------------------------------------- ! - ! Read in ASCAT mask file + ! read mask file for ASCAT obs (netcdf format, regular lat/lon grid) ! TODO: Decide how to handle mask file name and path (e.g., from obs_param nml) mask_filename = trim(this_obs_param%flistpath) // '/' // 'ascat_subsurface_mask' // '.nc' - if (logit) write (logunit,'(400A)') ' reading ', trim(mask_filename) + if (logit) write (logunit,'(400A)') ' reading mask for ASCAT obs from ', trim(mask_filename) - ! Check if file exists + ! check if file exists inquire(file=mask_filename, exist=file_exists) if (.not. file_exists) then - err_msg = 'Mask file not found' + err_msg = 'Mask file for ASCAT obs not found!' call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) end if - ! Openthe netCDF mask file + ! open netCDF mask file ierr = nf90_open(mask_filename, nf90_nowrite, ncid) - ! Get the variable IDs + ! get variable IDs ierr = nf90_inq_varid(ncid, 'mask', mask_varid) ierr = nf90_inq_varid(ncid, 'll_lon', ll_lon_varid) ierr = nf90_inq_varid(ncid, 'll_lat', ll_lat_varid) ierr = nf90_inq_varid(ncid, 'd_lon', dlon_varid) ierr = nf90_inq_varid(ncid, 'd_lat', dlat_varid) - ! Get the variable dimensions + ! get variable dimension IDs ierr = nf90_inq_dimid(ncid, 'lon', lon_dimid) ierr = nf90_inq_dimid(ncid, 'lat', lat_dimid) - ! Get the dimension size - ierr = nf90_inquire_dimension(ncid, lon_dimid, len = N_lon) - ierr = nf90_inquire_dimension(ncid, lat_dimid, len = N_lat) + ! get dimension size + ierr = nf90_inquire_dimension(ncid, lon_dimid, len=mask_N_lon) + ierr = nf90_inquire_dimension(ncid, lat_dimid, len=mask_N_lat) - ! Read grid variables - ierr = nf90_get_var(ncid, ll_lon_varid, ll_lon) - ierr = nf90_get_var(ncid, ll_lat_varid, ll_lat) - ierr = nf90_get_var(ncid, dlon_varid, dlon) - ierr = nf90_get_var(ncid, dlat_varid, dlat) + ! read grid parameters + ierr = nf90_get_var(ncid, ll_lon_varid, mask_ll_lon) + ierr = nf90_get_var(ncid, ll_lat_varid, mask_ll_lat) + ierr = nf90_get_var(ncid, dlon_varid, mask_dlon) + ierr = nf90_get_var(ncid, dlat_varid, mask_dlat) - ! Allocate memory for the mask - allocate(mask(N_lat, N_lon)) + ! allocate memory for mask + allocate(mask_data(mask_N_lat, mask_N_lon)) ! note: lat-by-lon !!! - ! Read the mask - ierr = nf90_get_var(ncid, mask_varid, mask) + ! read mask + ierr = nf90_get_var(ncid, mask_varid, mask_data) - ! Close the netCDF mask file + ! close netCDF mask file ierr = nf90_close(ncid) ! ---------------------------------------------------------------- @@ -1916,17 +1917,13 @@ subroutine read_obs_sm_ASCAT_EUMET( & ! skip if inundation and wetland fraction > 10% if(tmp_data(kk, 12) > 10.) cycle - - ! observation lat/lon - lat_target = tmp_data(kk, 13) - lon_target = tmp_data(kk, 14) - ! Find indices for ASCAT mask for this observation lat/lon - i_ind = ceiling((lon_target - ll_lon)/dlon) - j_ind = ceiling((lat_target - ll_lat)/dlat) + ! find lat/lon indices of ASCAT mask for this observation lat/lon + mask_lat_ind = max( min( ceiling((tmp_data(kk, 13) - mask_ll_lat)/mask_dlat), mask_N_lat ), 1) + mask_lon_ind = max( min( ceiling((tmp_data(kk, 14) - mask_ll_lon)/mask_dlon), mask_N_lon ), 1) - ! skip masked - if (mask(j_ind, i_ind) /= 0) cycle + ! skip if masked + if (mask_data( mask_lat_ind, mask_lon_ind ) /= 0) cycle ! note: lat-by-lon !!! N_tmp = N_tmp + 1 ! passed all QC @@ -1975,7 +1972,7 @@ subroutine read_obs_sm_ASCAT_EUMET( & deallocate(tmp1_lat) deallocate(tmp1_obs) deallocate(tmp_data) - deallocate(mask) + deallocate(mask_data) else @@ -8309,7 +8306,7 @@ subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & integer :: ncid, varid, ierr, ierr2 integer :: pentad_dimid, lon_dimid, lat_dimid integer :: N_pentad, N_lon, N_lat - integer :: pentad_varid, lon_varid, lat_varid + integer :: pentad_varid integer :: o_mean_varid, o_std_varid, m_mean_varid, m_std_varid, m_min_varid, m_max_varid integer :: ll_lon_varid, ll_lat_varid, dlon_varid, dlat_varid integer, dimension(3) :: start, icount From bd32c8e15d7e448ae6a66210076de93d692f98e4 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Wed, 28 Feb 2024 20:02:06 -0500 Subject: [PATCH 269/308] added %maskpath and %maskname fields to obs_param (enkf_types.F90, LDAS_ensdrv_mpi.F90, LDASsa_DEFAULT_inputs_ensupd.nml, read_obsparam.m, clsm_ensupd_read_obs.F90) --- .../LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml | 104 ++++++++++++++++++ .../util/shared/matlab/read_obsparam.m | 6 +- .../clsm_ensupd_read_obs.F90 | 3 +- .../LDAS_Shared/LDAS_ensdrv_mpi.F90 | 4 +- .../LDAS_Shared/enkf_types.F90 | 6 + 5 files changed, 119 insertions(+), 4 deletions(-) diff --git a/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml b/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml index afacd0f3..c5395c6d 100644 --- a/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml +++ b/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml @@ -118,6 +118,8 @@ fcsterr_inflation_fac = -9999. ! %units = units (eg., 'K' or 'm3/m3') ! %path = path to measurement files ! %name = name identifier for file containing measurements +! %maskpath = path to obs mask file +! %maskname = filename for obs mask ! %scalepath = path to file(s) with scaling parameters ! %scalename = filename for scaling parameters ! %flistpath = path to file with list of obs file names @@ -254,6 +256,8 @@ obs_param_nml( 1)%varname = 'sfmc' obs_param_nml( 1)%units = 'm3/m3' obs_param_nml( 1)%path = '/land/l_data/AMSR/data/AMSR_E_L2_Land_V001/' obs_param_nml( 1)%name = 'AMSR_E_L2_Land_' +obs_param_nml( 1)%maskpath = '' +obs_param_nml( 1)%maskname = '' obs_param_nml( 1)%scalepath = '' obs_param_nml( 1)%scalename = '' obs_param_nml( 1)%flistpath = '' @@ -290,6 +294,8 @@ obs_param_nml( 2)%varname = 'sfmc' obs_param_nml( 2)%units = 'm3/m3' obs_param_nml( 2)%path = '/land/l_data/AMSR/data/AMSR_E_L2_Land_V001/' obs_param_nml( 2)%name = 'AMSR_E_L2_Land_' +obs_param_nml( 2)%maskpath = '' +obs_param_nml( 2)%maskname = '' obs_param_nml( 2)%scalepath = '' obs_param_nml( 2)%scalename = '' obs_param_nml( 2)%flistpath = '' @@ -325,6 +331,8 @@ obs_param_nml( 3)%varname = 'tsurf' obs_param_nml( 3)%units = 'K' obs_param_nml( 3)%path = '/land/l_data/ISCCP/GSWP2_1by1_V1/' obs_param_nml( 3)%name = 'isccpdx_tskin.' +obs_param_nml( 3)%maskpath = '' +obs_param_nml( 3)%maskname = '' obs_param_nml( 3)%scalepath = '' obs_param_nml( 3)%scalename = '' obs_param_nml( 3)%flistpath = '' @@ -360,6 +368,8 @@ obs_param_nml( 4)%varname = 'sfmc' obs_param_nml( 4)%units = 'm3/m3' obs_param_nml( 4)%path = '/land/l_data/RedArk/Retrievals_36km/retrievals_20060508/' obs_param_nml( 4)%name = 'SM_retrieval.' +obs_param_nml( 4)%maskpath = '' +obs_param_nml( 4)%maskname = '' obs_param_nml( 4)%scalepath = '.' obs_param_nml( 4)%scalename = '.' obs_param_nml( 4)%flistpath = '' @@ -395,6 +405,8 @@ obs_param_nml( 5)%varname = 'sfmc' obs_param_nml( 5)%units = 'm3/m3' obs_param_nml( 5)%path = '/land/l_data/RedArk/Truth/50mm_Soil_Moisture_Truth/' obs_param_nml( 5)%name = 'red_ark_50mm.sm.' +obs_param_nml( 5)%maskpath = '' +obs_param_nml( 5)%maskname = '' obs_param_nml( 5)%scalepath = '.' obs_param_nml( 5)%scalename = '.' obs_param_nml( 5)%flistpath = '' @@ -430,6 +442,8 @@ obs_param_nml( 6)%varname = 'rzmc' obs_param_nml( 6)%units = 'm3/m3' obs_param_nml( 6)%path = '/land/l_data/RedArk/Truth/400mm_Soil_Moisture_Truth/' obs_param_nml( 6)%name = 'red_ark_400mm.sm.' +obs_param_nml( 6)%maskpath = '' +obs_param_nml( 6)%maskname = '' obs_param_nml( 6)%scalepath = '.' obs_param_nml( 6)%scalename = '.' obs_param_nml( 6)%flistpath = '' @@ -465,6 +479,8 @@ obs_param_nml( 7)%varname = 'sfmc' obs_param_nml( 7)%units = 'm3/m3' obs_param_nml( 7)%path = '/land/l_data/RedArk_OSSE/data/Retrievals_CLSM_synth/M0001_P0001_R0001_URI/std_synth_obs_0.020/' obs_param_nml( 7)%name = 'CLSM_synth_sm.' +obs_param_nml( 7)%maskpath = '' +obs_param_nml( 7)%maskname = '' obs_param_nml( 7)%scalepath = '.' obs_param_nml( 7)%scalename = '.' obs_param_nml( 7)%flistpath = '' @@ -500,6 +516,8 @@ obs_param_nml( 8)%varname = 'sfmc' obs_param_nml( 8)%units = 'm3/m3' obs_param_nml( 8)%path = '/discover/nobackup/vmaggion/Synth_sfmc/radar_sim/std_synth_sfmc_0.040/' obs_param_nml( 8)%name = 'synth_sfmc_VivianaOK_' +obs_param_nml( 8)%maskpath = '' +obs_param_nml( 8)%maskname = '' obs_param_nml( 8)%scalepath = '.' obs_param_nml( 8)%scalename = '.' obs_param_nml( 8)%flistpath = '' @@ -536,6 +554,8 @@ obs_param_nml( 9)%varname = 'sfmc' obs_param_nml( 9)%units = 'm3/m3' obs_param_nml( 9)%path = '/land/l_data/AMSR/data/AMSR_E_sm_LPRM/L2_EASE/bin/' obs_param_nml( 9)%name = 'AMSRsmUVA.EASE.v03.' +obs_param_nml( 9)%maskpath = '' +obs_param_nml( 9)%maskname = '' obs_param_nml( 9)%scalepath = '' obs_param_nml( 9)%scalename = '' obs_param_nml( 9)%flistpath = '' @@ -572,6 +592,8 @@ obs_param_nml(10)%varname = 'sfmc' obs_param_nml(10)%units = 'm3/m3' obs_param_nml(10)%path = '/land/l_data/AMSR/data/AMSR_E_sm_LPRM/L2_EASE/bin/' obs_param_nml(10)%name = 'AMSRsmUVA.EASE.v03.' +obs_param_nml(10)%maskpath = '' +obs_param_nml(10)%maskname = '' obs_param_nml(10)%scalepath = '' obs_param_nml(10)%scalename = '' obs_param_nml(10)%flistpath = '' @@ -608,6 +630,8 @@ obs_param_nml(11)%varname = 'sfmc' obs_param_nml(11)%units = 'm3/m3' obs_param_nml(11)%path = '/land/l_data/AMSR/data/AMSR_E_sm_LPRM/L2_EASE/bin/' obs_param_nml(11)%name = 'AMSRsmUVA.EASE.v03.' +obs_param_nml(11)%maskpath = '' +obs_param_nml(11)%maskname = '' obs_param_nml(11)%scalepath = '' obs_param_nml(11)%scalename = '' obs_param_nml(11)%flistpath = '' @@ -644,6 +668,8 @@ obs_param_nml(12)%varname = 'sfmc' obs_param_nml(12)%units = 'm3/m3' obs_param_nml(12)%path = '/land/l_data/AMSR/data/AMSR_E_sm_LPRM/L2_EASE/bin/' obs_param_nml(12)%name = 'AMSRsmUVA.EASE.v03.' +obs_param_nml(12)%maskpath = '' +obs_param_nml(12)%maskname = '' obs_param_nml(12)%scalepath = '' obs_param_nml(12)%scalename = '' obs_param_nml(12)%flistpath = '' @@ -683,6 +709,8 @@ obs_param_nml(13)%varname = 'sfmc' obs_param_nml(13)%units = 'm3/m3' obs_param_nml(13)%path = '/discover/nobackup/rreichle/l_data/ASCAT/TUW_W5.4/EASE/CONUS/bin/' obs_param_nml(13)%name = 'SDS_' +obs_param_nml(13)%maskpath = '' +obs_param_nml(13)%maskname = '' obs_param_nml(13)%scalepath = '' obs_param_nml(13)%scalename = '' obs_param_nml(13)%flistpath = '' @@ -722,6 +750,8 @@ obs_param_nml(14)%varname = 'sfmc' obs_param_nml(14)%units = 'm3/m3' obs_param_nml(14)%path = '/discover/nobackup/rreichle/l_data/ASCAT/TUW_W5.4/EASE/CONUS/bin/' obs_param_nml(14)%name = 'SDS_' +obs_param_nml(14)%maskpath = '' +obs_param_nml(14)%maskname = '' obs_param_nml(14)%scalepath = '' obs_param_nml(14)%scalename = '' obs_param_nml(14)%flistpath = '' @@ -757,6 +787,8 @@ obs_param_nml(15)%varname = 'sfmc' obs_param_nml(15)%units = 'm3/m3' obs_param_nml(15)%path = '/discover/nobackup/projects/gmao/ssd/land/l_data/SMOS/EASEv2/ESA_REPR/SMOS_M36_SMUDP2/' obs_param_nml(15)%name = '' +obs_param_nml(15)%maskpath = '' +obs_param_nml(15)%maskname = '' obs_param_nml(15)%scalepath = '' obs_param_nml(15)%scalename = '' obs_param_nml(15)%flistpath = '' @@ -792,6 +824,8 @@ obs_param_nml(16)%varname = 'sfmc' obs_param_nml(16)%units = 'm3/m3' obs_param_nml(16)%path = '/discover/nobackup/projects/gmao/ssd/land/l_data/SMOS/EASEv2/ESA_REPR/SMOS_M36_SMUDP2/' obs_param_nml(16)%name = '' +obs_param_nml(16)%maskpath = '' +obs_param_nml(16)%maskname = '' obs_param_nml(16)%scalepath = '' obs_param_nml(16)%scalename = '' obs_param_nml(16)%flistpath = '' @@ -875,6 +909,8 @@ obs_param_nml(17)%varname = 'Tb' obs_param_nml(17)%units = 'K' obs_param_nml(17)%path = '/discover/nobackup/projects/gmao/ssd/land/l_data/SMOS/EASEv2/ESA_REPR/SMOS_M36_SCLF1C_reg_nosky_noatm_v620_ESA_v102/' obs_param_nml(17)%name = '' +obs_param_nml(17)%maskpath = '' +obs_param_nml(17)%maskname = '' obs_param_nml(17)%scalepath = '' obs_param_nml(17)%scalename = '' obs_param_nml(17)%flistpath = '' @@ -917,6 +953,8 @@ obs_param_nml(18)%varname = 'Tb' obs_param_nml(18)%units = 'K' obs_param_nml(18)%path = '/discover/nobackup/projects/gmao/ssd/land/l_data/SMOS/EASEv2/ESA_REPR/SMOS_M36_SCLF1C_reg_nosky_noatm_v620_ESA_v102/' obs_param_nml(18)%name = '' +obs_param_nml(18)%maskpath = '' +obs_param_nml(18)%maskname = '' obs_param_nml(18)%scalepath = '' obs_param_nml(18)%scalename = '' obs_param_nml(18)%flistpath = '' @@ -959,6 +997,8 @@ obs_param_nml(19)%varname = 'Tb' obs_param_nml(19)%units = 'K' obs_param_nml(19)%path = '/discover/nobackup/projects/gmao/ssd/land/l_data/SMOS/EASEv2/ESA_REPR/SMOS_M36_SCLF1C_reg_nosky_noatm_v620_ESA_v102/' obs_param_nml(19)%name = '' +obs_param_nml(19)%maskpath = '' +obs_param_nml(19)%maskname = '' obs_param_nml(19)%scalepath = '' obs_param_nml(19)%scalename = '' obs_param_nml(19)%flistpath = '' @@ -1001,6 +1041,8 @@ obs_param_nml(20)%varname = 'Tb' obs_param_nml(20)%units = 'K' obs_param_nml(20)%path = '/discover/nobackup/projects/gmao/ssd/land/l_data/SMOS/EASEv2/ESA_REPR/SMOS_M36_SCLF1C_reg_nosky_noatm_v620_ESA_v102/' obs_param_nml(20)%name = '' +obs_param_nml(20)%maskpath = '' +obs_param_nml(20)%maskname = '' obs_param_nml(20)%scalepath = '' obs_param_nml(20)%scalename = '' obs_param_nml(20)%flistpath = '' @@ -1037,6 +1079,8 @@ obs_param_nml(21)%varname = 'Tb' obs_param_nml(21)%units = 'K' obs_param_nml(21)%path = '/discover/nobackup/projects/gmao/ssd/land/l_data/SMOS/EASEv2/ESA_REPR/SMOS_M36_SCLF1C_fit_nosky_noatm_v620_ESA_v102/SMOS_fit_poly2/' obs_param_nml(21)%name = '' +obs_param_nml(21)%maskpath = '' +obs_param_nml(21)%maskname = '' obs_param_nml(21)%scalepath = '' obs_param_nml(21)%scalename = '' obs_param_nml(21)%flistpath = '' @@ -1073,6 +1117,8 @@ obs_param_nml(22)%varname = 'Tb' obs_param_nml(22)%units = 'K' obs_param_nml(22)%path = '/discover/nobackup/projects/gmao/ssd/land/l_data/SMOS/EASEv2/ESA_REPR/SMOS_M36_SCLF1C_fit_nosky_noatm_v620_ESA_v102/SMOS_fit_poly2/' obs_param_nml(22)%name = '' +obs_param_nml(22)%maskpath = '' +obs_param_nml(22)%maskname = '' obs_param_nml(22)%scalepath = '' obs_param_nml(22)%scalename = '' obs_param_nml(22)%flistpath = '' @@ -1109,6 +1155,8 @@ obs_param_nml(23)%varname = 'Tb' obs_param_nml(23)%units = 'K' obs_param_nml(23)%path = '/discover/nobackup/projects/gmao/ssd/land/l_data/SMOS/EASEv2/ESA_REPR/SMOS_M36_SCLF1C_fit_nosky_noatm_v620_ESA_v102/SMOS_fit_poly2/' obs_param_nml(23)%name = '' +obs_param_nml(23)%maskpath = '' +obs_param_nml(23)%maskname = '' obs_param_nml(23)%scalepath = '' obs_param_nml(23)%scalename = '' obs_param_nml(23)%flistpath = '' @@ -1145,6 +1193,8 @@ obs_param_nml(24)%varname = 'Tb' obs_param_nml(24)%units = 'K' obs_param_nml(24)%path = '/discover/nobackup/projects/gmao/ssd/land/l_data/SMOS/EASEv2/ESA_REPR/SMOS_M36_SCLF1C_fit_nosky_noatm_v620_ESA_v102/SMOS_fit_poly2/' obs_param_nml(24)%name = '' +obs_param_nml(24)%maskpath = '' +obs_param_nml(24)%maskname = '' obs_param_nml(24)%scalepath = '' obs_param_nml(24)%scalename = '' obs_param_nml(24)%flistpath = '' @@ -1184,6 +1234,8 @@ obs_param_nml(25)%varname = 'asnow' obs_param_nml(25)%units = 'm2/m2' obs_param_nml(25)%path = '' obs_param_nml(25)%name = '' +obs_param_nml(25)%maskpath = '' +obs_param_nml(25)%maskname = '' obs_param_nml(25)%scalepath = '' obs_param_nml(25)%scalename = '' obs_param_nml(25)%flistpath = '' @@ -1220,6 +1272,8 @@ obs_param_nml(26)%varname = 'tsurf' obs_param_nml(26)%units = 'K' obs_param_nml(26)%path = '/discover/nobackup/csdraper/LaRC_float/GOES-WEST/' obs_param_nml(26)%name = 'larc-v3.inst3_g15_Nch.' +obs_param_nml(26)%maskpath = '' +obs_param_nml(26)%maskname = '' obs_param_nml(26)%scalepath = '' obs_param_nml(26)%scalename = '' obs_param_nml(26)%flistpath = '' @@ -1256,6 +1310,8 @@ obs_param_nml(27)%varname = 'tsurf' obs_param_nml(27)%units = 'K' obs_param_nml(27)%path = '/discover/nobackup/csdraper/LaRC_float/v4/GOES-EAST/' obs_param_nml(27)%name = 'larc-v3.inst3_g13_Nch.' +obs_param_nml(27)%maskpath = '' +obs_param_nml(27)%maskname = '' obs_param_nml(27)%scalepath = '' obs_param_nml(27)%scalename = '' obs_param_nml(27)%flistpath = '' @@ -1292,6 +1348,8 @@ obs_param_nml(28)%varname = 'tsurf' obs_param_nml(28)%units = 'K' obs_param_nml(28)%path = '/discover/nobackup/csdraper/LaRC_float/MET09/' obs_param_nml(28)%name = 'larc-v3.inst3_mt9_Nch.' +obs_param_nml(28)%maskpath = '' +obs_param_nml(28)%maskname = '' obs_param_nml(28)%scalepath = '' obs_param_nml(28)%scalename = '' obs_param_nml(28)%flistpath = '' @@ -1328,6 +1386,8 @@ obs_param_nml(29)%varname = 'tsurf' obs_param_nml(29)%units = 'K' obs_param_nml(29)%path = '/discover/nobackup/csdraper/LaRC_float/FY2E/' obs_param_nml(29)%name = 'larc-v3.inst3_fye_Nch.' +obs_param_nml(29)%maskpath = '' +obs_param_nml(29)%maskname = '' obs_param_nml(29)%scalepath = '' obs_param_nml(29)%scalename = '' obs_param_nml(29)%flistpath = '' @@ -1364,6 +1424,8 @@ obs_param_nml(30)%varname = 'tsurf' obs_param_nml(30)%units = 'K' obs_param_nml(30)%path = '/discover/nobackup/csdraper/LaRC_float/MTSAT-2/' obs_param_nml(30)%name = 'larc-v3.inst3_mt2_Nch.' +obs_param_nml(30)%maskpath = '' +obs_param_nml(30)%maskname = '' obs_param_nml(30)%scalepath = '' obs_param_nml(30)%scalename = '' obs_param_nml(30)%flistpath = '' @@ -1410,6 +1472,8 @@ obs_param_nml(31)%varname = 'Tb' obs_param_nml(31)%units = 'K' obs_param_nml(31)%path = '/discover/nobackup/projects/gmao/smap/SMAP_L4/SMAP/L1C_TB/' obs_param_nml(31)%name = '' +obs_param_nml(31)%maskpath = '' +obs_param_nml(31)%maskname = '' obs_param_nml(31)%scalepath = '' obs_param_nml(31)%scalename = '' obs_param_nml(31)%flistpath = '' @@ -1446,6 +1510,8 @@ obs_param_nml(32)%varname = 'Tb' obs_param_nml(32)%units = 'K' obs_param_nml(32)%path = '/discover/nobackup/projects/gmao/smap/SMAP_L4/SMAP/L1C_TB/' obs_param_nml(32)%name = '' +obs_param_nml(32)%maskpath = '' +obs_param_nml(32)%maskname = '' obs_param_nml(32)%scalepath = '' obs_param_nml(32)%scalename = '' obs_param_nml(32)%flistpath = '' @@ -1482,6 +1548,8 @@ obs_param_nml(33)%varname = 'Tb' obs_param_nml(33)%units = 'K' obs_param_nml(33)%path = '/discover/nobackup/projects/gmao/smap/SMAP_L4/SMAP/L1C_TB/' obs_param_nml(33)%name = '' +obs_param_nml(33)%maskpath = '' +obs_param_nml(33)%maskname = '' obs_param_nml(33)%scalepath = '' obs_param_nml(33)%scalename = '' obs_param_nml(33)%flistpath = '' @@ -1518,6 +1586,8 @@ obs_param_nml(34)%varname = 'Tb' obs_param_nml(34)%units = 'K' obs_param_nml(34)%path = '/discover/nobackup/projects/gmao/smap/SMAP_L4/SMAP/L1C_TB/' obs_param_nml(34)%name = '' +obs_param_nml(34)%maskpath = '' +obs_param_nml(34)%maskname = '' obs_param_nml(34)%scalepath = '' obs_param_nml(34)%scalename = '' obs_param_nml(34)%flistpath = '' @@ -1565,6 +1635,8 @@ obs_param_nml(35)%varname = 'Tb' obs_param_nml(35)%units = 'K' obs_param_nml(35)%path = '/discover/nobackup/projects/gmao/smap/SMAP_L4/SMAP/L2_SM_AP/' obs_param_nml(35)%name = '' +obs_param_nml(35)%maskpath = '' +obs_param_nml(35)%maskname = '' obs_param_nml(35)%scalepath = '' obs_param_nml(35)%scalename = '' obs_param_nml(35)%flistpath = '' @@ -1601,6 +1673,8 @@ obs_param_nml(36)%varname = 'Tb' obs_param_nml(36)%units = 'K' obs_param_nml(36)%path = '/discover/nobackup/projects/gmao/smap/SMAP_L4/SMAP/L2_SM_AP/' obs_param_nml(36)%name = '' +obs_param_nml(36)%maskpath = '' +obs_param_nml(36)%maskname = '' obs_param_nml(36)%scalepath = '' obs_param_nml(36)%scalename = '' obs_param_nml(36)%flistpath = '' @@ -1637,6 +1711,8 @@ obs_param_nml(37)%varname = 'Tb' obs_param_nml(37)%units = 'K' obs_param_nml(37)%path = '/discover/nobackup/projects/gmao/smap/SMAP_L4/SMAP/L2_SM_AP/' obs_param_nml(37)%name = '' +obs_param_nml(37)%maskpath = '' +obs_param_nml(37)%maskname = '' obs_param_nml(37)%scalepath = '' obs_param_nml(37)%scalename = '' obs_param_nml(37)%flistpath = '' @@ -1673,6 +1749,8 @@ obs_param_nml(38)%varname = 'Tb' obs_param_nml(38)%units = 'K' obs_param_nml(38)%path = '/discover/nobackup/projects/gmao/smap/SMAP_L4/SMAP/L2_SM_AP/' obs_param_nml(38)%name = '' +obs_param_nml(38)%maskpath = '' +obs_param_nml(38)%maskname = '' obs_param_nml(38)%scalepath = '' obs_param_nml(38)%scalename = '' obs_param_nml(38)%flistpath = '' @@ -1709,6 +1787,8 @@ obs_param_nml(39)%varname = 'FT' obs_param_nml(39)%units = '-' obs_param_nml(39)%path = '/discover/nobackup/projects/gmao/smap/SMAP_L4/SMAP/L2_SM_AP/' obs_param_nml(39)%name = '' +obs_param_nml(39)%maskpath = '' +obs_param_nml(39)%maskname = '' obs_param_nml(39)%scalepath = '' obs_param_nml(39)%scalename = '' obs_param_nml(39)%flistpath = '' @@ -1745,6 +1825,8 @@ obs_param_nml(40)%varname = 'FT' obs_param_nml(40)%units = '-' obs_param_nml(40)%path = '/discover/nobackup/projects/gmao/smap/SMAP_L4/SMAP/L2_SM_AP/' obs_param_nml(40)%name = '' +obs_param_nml(40)%maskpath = '' +obs_param_nml(40)%maskname = '' obs_param_nml(40)%scalepath = '' obs_param_nml(40)%scalename = '' obs_param_nml(40)%flistpath = '' @@ -1803,6 +1885,8 @@ obs_param_nml(41)%varname = 'Tb' obs_param_nml(41)%units = 'K' obs_param_nml(41)%path = '/discover/nobackup/projects/gmao/smap/SMAP_L4/SMAP/L1C_TB_E/' obs_param_nml(41)%name = '' +obs_param_nml(41)%maskpath = '' +obs_param_nml(41)%maskname = '' obs_param_nml(41)%scalepath = '' obs_param_nml(41)%scalename = '' obs_param_nml(41)%flistpath = '' @@ -1839,6 +1923,8 @@ obs_param_nml(42)%varname = 'Tb' obs_param_nml(42)%units = 'K' obs_param_nml(42)%path = '/discover/nobackup/projects/gmao/smap/SMAP_L4/SMAP/L1C_TB_E/' obs_param_nml(42)%name = '' +obs_param_nml(42)%maskpath = '' +obs_param_nml(42)%maskname = '' obs_param_nml(42)%scalepath = '' obs_param_nml(42)%scalename = '' obs_param_nml(42)%flistpath = '' @@ -1875,6 +1961,8 @@ obs_param_nml(43)%varname = 'Tb' obs_param_nml(43)%units = 'K' obs_param_nml(43)%path = '/discover/nobackup/projects/gmao/smap/SMAP_L4/SMAP/L1C_TB_E/' obs_param_nml(43)%name = '' +obs_param_nml(43)%maskpath = '' +obs_param_nml(43)%maskname = '' obs_param_nml(43)%scalepath = '' obs_param_nml(43)%scalename = '' obs_param_nml(43)%flistpath = '' @@ -1911,6 +1999,8 @@ obs_param_nml(44)%varname = 'Tb' obs_param_nml(44)%units = 'K' obs_param_nml(44)%path = '/discover/nobackup/projects/gmao/smap/SMAP_L4/SMAP/L1C_TB_E/' obs_param_nml(44)%name = '' +obs_param_nml(44)%maskpath = '' +obs_param_nml(44)%maskname = '' obs_param_nml(44)%scalepath = '' obs_param_nml(44)%scalename = '' obs_param_nml(44)%flistpath = '' @@ -1947,6 +2037,8 @@ obs_param_nml(45)%varname = 'Tb' obs_param_nml(45)%units = 'K' obs_param_nml(45)%path = '/discover/nobackup/projects/gmao/smap/SMAP_L4/SMAP/L1C_TB_E/' obs_param_nml(45)%name = '' +obs_param_nml(45)%maskpath = '' +obs_param_nml(45)%maskname = '' obs_param_nml(45)%scalepath = '' obs_param_nml(45)%scalename = '' obs_param_nml(45)%flistpath = '' @@ -1983,6 +2075,8 @@ obs_param_nml(46)%varname = 'Tb' obs_param_nml(46)%units = 'K' obs_param_nml(46)%path = '/discover/nobackup/projects/gmao/smap/SMAP_L4/SMAP/L1C_TB_E/' obs_param_nml(46)%name = '' +obs_param_nml(46)%maskpath = '' +obs_param_nml(46)%maskname = '' obs_param_nml(46)%scalepath = '' obs_param_nml(46)%scalename = '' obs_param_nml(46)%flistpath = '' @@ -2019,6 +2113,8 @@ obs_param_nml(47)%varname = 'Tb' obs_param_nml(47)%units = 'K' obs_param_nml(47)%path = '/discover/nobackup/projects/gmao/smap/SMAP_L4/SMAP/L1C_TB_E/' obs_param_nml(47)%name = '' +obs_param_nml(47)%maskpath = '' +obs_param_nml(47)%maskname = '' obs_param_nml(47)%scalepath = '' obs_param_nml(47)%scalename = '' obs_param_nml(47)%flistpath = '' @@ -2055,6 +2151,8 @@ obs_param_nml(48)%varname = 'Tb' obs_param_nml(48)%units = 'K' obs_param_nml(48)%path = '/discover/nobackup/projects/gmao/smap/SMAP_L4/SMAP/L1C_TB_E/' obs_param_nml(48)%name = '' +obs_param_nml(48)%maskpath = '' +obs_param_nml(48)%maskname = '' obs_param_nml(48)%scalepath = '' obs_param_nml(48)%scalename = '' obs_param_nml(48)%flistpath = '' @@ -2092,6 +2190,8 @@ obs_param_nml(49)%varname = 'sfds' obs_param_nml(49)%units = '%' obs_param_nml(49)%path = '/discover/nobackup/projects/gmao/merra/iau/merra_land/DATA/ASCAT_EUMETSAT/Metop_A/' obs_param_nml(49)%name = 'M02-ASCA-ASCSMO02' +obs_param_nml(49)%maskpath = '' +obs_param_nml(49)%maskname = '' obs_param_nml(49)%scalepath = '' obs_param_nml(49)%scalename = '' obs_param_nml(49)%flistpath = '' @@ -2129,6 +2229,8 @@ obs_param_nml(50)%varname = 'sfds' obs_param_nml(50)%units = '%' obs_param_nml(50)%path = '/discover/nobackup/projects/gmao/merra/iau/merra_land/DATA/ASCAT_EUMETSAT/Metop_B/' obs_param_nml(50)%name = 'M01-ASCA-ASCSMO02' +obs_param_nml(50)%maskpath = '' +obs_param_nml(50)%maskname = '' obs_param_nml(50)%scalepath = '' obs_param_nml(50)%scalename = '' obs_param_nml(50)%flistpath = '' @@ -2166,6 +2268,8 @@ obs_param_nml(51)%varname = 'sfds' obs_param_nml(51)%units = '%' obs_param_nml(51)%path = '/discover/nobackup/projects/gmao/merra/iau/merra_land/DATA/ASCAT_EUMETSAT/Metop_C/' obs_param_nml(51)%name = 'M03-ASCA-ASCSMO02' +obs_param_nml(51)%maskpath = '' +obs_param_nml(51)%maskname = '' obs_param_nml(51)%scalepath = '' obs_param_nml(51)%scalename = '' obs_param_nml(51)%flistpath = '' diff --git a/src/Applications/LDAS_App/util/shared/matlab/read_obsparam.m b/src/Applications/LDAS_App/util/shared/matlab/read_obsparam.m index 3c0447e1..19e66056 100644 --- a/src/Applications/LDAS_App/util/shared/matlab/read_obsparam.m +++ b/src/Applications/LDAS_App/util/shared/matlab/read_obsparam.m @@ -42,6 +42,8 @@ obs_param(i).units = fscanf(fid, '%s ', 1); obs_param(i).path = fscanf(fid, '%s ', 1); obs_param(i).name = fscanf(fid, '%s ', 1); + obs_param(i).maskpath = fscanf(fid, '%s ', 1); + obs_param(i).maskname = fscanf(fid, '%s ', 1); obs_param(i).scalepath = fscanf(fid, '%s ', 1); obs_param(i).scalename = fscanf(fid, '%s ', 1); obs_param(i).flistpath = fscanf(fid, '%s ', 1); @@ -59,9 +61,11 @@ obs_param(i).descr = obs_param(i).descr( 2:end-1); obs_param(i).FOV_units = obs_param(i).FOV_units(2:end-1); obs_param(i).varname = obs_param(i).varname( 2:end-1); + obs_param(i).units = obs_param(i).units( 2:end-1); obs_param(i).path = obs_param(i).path( 2:end-1); obs_param(i).name = obs_param(i).name( 2:end-1); - obs_param(i).units = obs_param(i).units( 2:end-1); + obs_param(i).maskpath = obs_param(i).maskpath( 2:end-1); + obs_param(i).maskname = obs_param(i).maskname( 2:end-1); obs_param(i).scalepath = obs_param(i).scalepath(2:end-1); obs_param(i).scalename = obs_param(i).scalename(2:end-1); obs_param(i).flistpath = obs_param(i).flistpath(2:end-1); diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 08726fc1..a7787fc9 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -1826,8 +1826,7 @@ subroutine read_obs_sm_ASCAT_EUMET( & ! ! read mask file for ASCAT obs (netcdf format, regular lat/lon grid) - ! TODO: Decide how to handle mask file name and path (e.g., from obs_param nml) - mask_filename = trim(this_obs_param%flistpath) // '/' // 'ascat_subsurface_mask' // '.nc' + mask_filename = trim(this_obs_param%maskpath) // '/' // trim(this_obs_param%maskfile) if (logit) write (logunit,'(400A)') ' reading mask for ASCAT obs from ', trim(mask_filename) diff --git a/src/Components/GEOSldas_GridComp/LDAS_Shared/LDAS_ensdrv_mpi.F90 b/src/Components/GEOSldas_GridComp/LDAS_Shared/LDAS_ensdrv_mpi.F90 index 8dd53c20..07cf17bd 100644 --- a/src/Components/GEOSldas_GridComp/LDAS_Shared/LDAS_ensdrv_mpi.F90 +++ b/src/Components/GEOSldas_GridComp/LDAS_Shared/LDAS_ensdrv_mpi.F90 @@ -741,6 +741,8 @@ subroutine init_MPI_types() ! character(40) :: units ! character(200) :: path ! character(80) :: name + ! character(200) :: maskpath + ! character(80) :: maskname ! character(200) :: scalepath ! character(80) :: scalename ! character(200) :: flistpath @@ -779,7 +781,7 @@ subroutine init_MPI_types() iblock( 5) = 3 iblock( 6) = 4 iblock( 7) = 1 - iblock( 8) = 40+40+200+80+200+80+200+80 + iblock( 8) = 40+40+200+80+200+80+200+80+200+80 iblock( 9) = 2 iblock(10) = 2 iblock(11) = 2 diff --git a/src/Components/GEOSldas_GridComp/LDAS_Shared/enkf_types.F90 b/src/Components/GEOSldas_GridComp/LDAS_Shared/enkf_types.F90 index c36f7127..8f2c8c8c 100644 --- a/src/Components/GEOSldas_GridComp/LDAS_Shared/enkf_types.F90 +++ b/src/Components/GEOSldas_GridComp/LDAS_Shared/enkf_types.F90 @@ -21,6 +21,8 @@ module enkf_types ! ! reichle, 8 Jun 2017: added "%flistpath" and "%flistname" to "obs_param_type" ! + ! reichle,28 Feb 2024: added "%maskpath" and "%maskname" to "obs_param_type" + ! ! ------------------------------------------------------------------- implicit none @@ -138,6 +140,8 @@ module enkf_types character(200) :: path ! path to measurements file character(80) :: name ! name identifier for measurements + character(200) :: maskpath ! path to obs mask file + character(80) :: maskname ! filename for obs mask character(200) :: scalepath ! path to file with scaling parameters character(80) :: scalename ! filename for scaling parameters character(200) :: flistpath ! path to file with list of obs file names @@ -201,6 +205,8 @@ subroutine write_obs_param(unitnumber, N_obs_param, obs_param) write (unitnumber, '(42A)') "'" // trim(obs_param(i)%units) // "'" write (unitnumber,'(202A)') "'" // trim(obs_param(i)%path) // "'" write (unitnumber, '(82A)') "'" // trim(obs_param(i)%name) // "'" + write (unitnumber,'(202A)') "'" // trim(obs_param(i)%maskpath) // "'" + write (unitnumber, '(82A)') "'" // trim(obs_param(i)%maskname) // "'" write (unitnumber,'(202A)') "'" // trim(obs_param(i)%scalepath) // "'" write (unitnumber, '(82A)') "'" // trim(obs_param(i)%scalename) // "'" write (unitnumber,'(202A)') "'" // trim(obs_param(i)%flistpath) // "'" From bcfbbe279578cc15d833665fa710bc59b875a4a5 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Wed, 28 Feb 2024 20:29:52 -0500 Subject: [PATCH 270/308] fix typo in previous commit (clsm_ensupd_read_obs.F90) --- .../GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index a7787fc9..64a9cb66 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -1826,7 +1826,7 @@ subroutine read_obs_sm_ASCAT_EUMET( & ! ! read mask file for ASCAT obs (netcdf format, regular lat/lon grid) - mask_filename = trim(this_obs_param%maskpath) // '/' // trim(this_obs_param%maskfile) + mask_filename = trim(this_obs_param%maskpath) // '/' // trim(this_obs_param%maskname) if (logit) write (logunit,'(400A)') ' reading mask for ASCAT obs from ', trim(mask_filename) From 4a526c8818d033e6e5ce80f6147148a73f62ebd9 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Wed, 28 Feb 2024 23:07:17 -0500 Subject: [PATCH 271/308] switch to lon-by-lat --- .../GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 64a9cb66..ed72600a 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -1864,7 +1864,7 @@ subroutine read_obs_sm_ASCAT_EUMET( & ierr = nf90_get_var(ncid, dlat_varid, mask_dlat) ! allocate memory for mask - allocate(mask_data(mask_N_lat, mask_N_lon)) ! note: lat-by-lon !!! + allocate(mask_data(mask_N_lon, mask_N_lat)) ! note: lon-by-lat ! read mask ierr = nf90_get_var(ncid, mask_varid, mask_data) @@ -1922,7 +1922,7 @@ subroutine read_obs_sm_ASCAT_EUMET( & mask_lon_ind = max( min( ceiling((tmp_data(kk, 14) - mask_ll_lon)/mask_dlon), mask_N_lon ), 1) ! skip if masked - if (mask_data( mask_lat_ind, mask_lon_ind ) /= 0) cycle ! note: lat-by-lon !!! + if (mask_data( mask_lon_ind, mask_lat_ind ) /= 0) cycle ! note: lon-by-lat N_tmp = N_tmp + 1 ! passed all QC From fd87ebf1a67c8cc3da6f0d21fe4e7aed1b322cdb Mon Sep 17 00:00:00 2001 From: Rolf Reichle <54944691+gmao-rreichle@users.noreply.github.com> Date: Thu, 29 Feb 2024 11:22:20 -0500 Subject: [PATCH 272/308] Update utilities versions (components.yaml): ESMA_env v4.26.0 ESMA_cmake v3.41.0 GMAO_Shared v1.9.7 GEOS_Util v2.0.7 MAPL v2.44.0 --- components.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/components.yaml b/components.yaml index 661b3b84..77e67ff7 100644 --- a/components.yaml +++ b/components.yaml @@ -5,13 +5,13 @@ GEOSldas: env: local: ./@env remote: ../ESMA_env.git - tag: v4.23.0 + tag: v4.26.0 develop: main cmake: local: ./@cmake remote: ../ESMA_cmake.git - tag: v3.40.0 + tag: v3.41.0 develop: develop ecbuild: @@ -29,21 +29,21 @@ NCEP_Shared: GMAO_Shared: local: ./src/Shared/@GMAO_Shared remote: ../GMAO_Shared.git - tag: v1.9.6 + tag: v1.9.7 sparse: ./config/GMAO_Shared.sparse develop: main GEOS_Util: local: ./src/Shared/@GMAO_Shared/@GEOS_Util remote: ../GEOS_Util.git - tag: v2.0.6 + tag: v2.0.7 sparse: ./config/GEOS_Util.sparse develop: main MAPL: local: ./src/Shared/@MAPL remote: ../MAPL.git - tag: v2.42.1 + tag: v2.44.0 develop: develop GEOSgcm_GridComp: From 822589c64a3575437d8a96ffdb6eac2ab411fc5c Mon Sep 17 00:00:00 2001 From: Rolf Reichle <54944691+gmao-rreichle@users.noreply.github.com> Date: Fri, 1 Mar 2024 08:57:06 -0500 Subject: [PATCH 273/308] reverting back to ESMA_env v4.23.0 --- components.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components.yaml b/components.yaml index 77e67ff7..b5fee251 100644 --- a/components.yaml +++ b/components.yaml @@ -5,7 +5,7 @@ GEOSldas: env: local: ./@env remote: ../ESMA_env.git - tag: v4.26.0 + tag: v4.23.0 develop: main cmake: From 4c3062bd4d6d81076fed280b96e39ba233943c7c Mon Sep 17 00:00:00 2001 From: amfox37 Date: Mon, 11 Mar 2024 14:56:57 -0600 Subject: [PATCH 274/308] add ascat mask maker --- src/Applications/LDAS_App/CMakeLists.txt | 6 + .../inputs/ascat_mask/ascat_mask_maker.F90 | 168 ++++++++++++++++++ 2 files changed, 174 insertions(+) create mode 100644 src/Applications/LDAS_App/util/inputs/ascat_mask/ascat_mask_maker.F90 diff --git a/src/Applications/LDAS_App/CMakeLists.txt b/src/Applications/LDAS_App/CMakeLists.txt index 2d0b55b1..1c5b4dc9 100644 --- a/src/Applications/LDAS_App/CMakeLists.txt +++ b/src/Applications/LDAS_App/CMakeLists.txt @@ -13,6 +13,12 @@ ecbuild_add_executable ( TARGET tile_bin2nc4.x SOURCES tile_bin2nc4.F90 LIBS MAPL) + +ecbuild_add_executable ( + TARGET ascat_mask_maker.x + SOURCES util/inputs/ascat_mask/ascat_mask_maker.F90 + LIBS MAPL +) ecbuild_add_executable ( TARGET mwrtm_bin2nc4.x diff --git a/src/Applications/LDAS_App/util/inputs/ascat_mask/ascat_mask_maker.F90 b/src/Applications/LDAS_App/util/inputs/ascat_mask/ascat_mask_maker.F90 new file mode 100644 index 00000000..5b348de2 --- /dev/null +++ b/src/Applications/LDAS_App/util/inputs/ascat_mask/ascat_mask_maker.F90 @@ -0,0 +1,168 @@ +program ascat_mask_maker + + use netcdf + + implicit none + + integer :: ncid, varid, dimid, ierr, len, N_gpi, dimids(2) + integer :: i, j, closest_index + + integer(kind=1), dimension(:,:), allocatable :: mask_out + integer(kind=1) :: missing_value + + real, dimension(:), allocatable :: asc_lon, asc_lat, cold_mask, wet_mask, veg_mask, subsurface_mask, combined_mask + real, dimension(:), allocatable :: lon, lat, distances + real :: d_lon, d_lat, ll_lon, ll_lat + + ! Open the NetCDF file + ierr = nf90_open('/Users/amfox/Desktop/GEOSldas_diagnostics/test_data/clsm/subsurface_scattering_ASCAT_ERA5_Land.nc', nf90_nowrite, ncid) + if (ierr /= nf90_noerr) stop 'Error opening file' + + ! Get the dimension ID + ierr = nf90_inq_dimid(ncid, 'gpi', dimid) + if (ierr /= nf90_noerr) stop 'Error getting dimension ID' + + ! Get the length of the dimension + ierr = nf90_inquire_dimension(ncid, dimid, len = N_gpi) + if (ierr /= nf90_noerr) stop 'Error inquiring dimension' + + print*, 'N_gpi = ', N_gpi + + ! Allocate the arrays + allocate(asc_lon(N_gpi)) + allocate(asc_lat(N_gpi)) + allocate(cold_mask(N_gpi)) + allocate(wet_mask(N_gpi)) + allocate(veg_mask(N_gpi)) + allocate(subsurface_mask(N_gpi)) + allocate(combined_mask(N_gpi)) + + ! Get the variable IDs and read the variables + ierr = nf90_inq_varid(ncid, 'lon', varid) + ierr = nf90_get_var(ncid, varid, asc_lon) + ierr = nf90_inq_varid(ncid, 'lat', varid) + ierr = nf90_get_var(ncid, varid, asc_lat) + ierr = nf90_inq_varid(ncid, 'cold_mask', varid) + ierr = nf90_get_var(ncid, varid, cold_mask) + ierr = nf90_inq_varid(ncid, 'wet_mask', varid) + ierr = nf90_get_var(ncid, varid, wet_mask) + ierr = nf90_inq_varid(ncid, 'veg_mask', varid) + ierr = nf90_get_var(ncid, varid, veg_mask) + ierr = nf90_inq_varid(ncid, 'subsurface_mask', varid) + ierr = nf90_get_var(ncid, varid, subsurface_mask) + + ! Close the NetCDF file + ierr = nf90_close(ncid) + if (ierr /= nf90_noerr) stop 'Error closing file' + + ! Combine the masks + where (wet_mask == 1) + combined_mask = 1 + elsewhere + combined_mask = subsurface_mask + end where + + d_lon = 0.1 + d_lat = 0.1 + ll_lon = -180.0 + ll_lat = -90.0 + missing_value = -128 + + allocate(lon(int(360.0 / d_lon))) + allocate(lat(int(180.0 / d_lat))) + + lon = [(ll_lon + i * d_lon, i = 0, size(lon) - 1)] + lat = [(ll_lat + i * d_lat, i = 0, size(lat) - 1)] + + allocate(mask_out(size(lon), size(lat))) + + do i = 1, size(lon) + print*, lon(i) + do j = 1, size(lat) + allocate(distances(size(asc_lon))) + distances = sqrt((asc_lon - lon(i))**2 + (asc_lat - lat(j))**2) + closest_index = minloc(distances, dim = 1) + if (distances(closest_index) > 0.14) then + mask_out(i, j) = missing_value + else + mask_out(i, j) = combined_mask(closest_index) + end if + deallocate(distances) + end do + end do + + ! Write out the mask to netcdf + ierr = nf90_create('ascat_combined_mask_p1_f90.nc', nf90_clobber, ncid) + if (ierr /= nf90_noerr) stop 'Error creating file' + + ! Define the dimensions + ierr = nf90_def_dim(ncid, 'lon', size(lon), dimids(1)) + ierr = nf90_def_dim(ncid, 'lat', size(lat), dimids(2)) + + ! Define the variables + ierr = nf90_def_var(ncid, 'lat', nf90_real, dimids(2), varid) + ierr = nf90_put_att(ncid, varid, 'standard_name', 'latitude') + ierr = nf90_put_att(ncid, varid, 'long_name', 'latitude') + ierr = nf90_put_att(ncid, varid, 'units', 'degrees_north') + ierr = nf90_put_att(ncid, varid, 'axis', 'Y') + + ierr = nf90_def_var(ncid, 'lon', nf90_real, dimids(1), varid) + ierr = nf90_put_att(ncid, varid, 'standard_name', 'longitude') + ierr = nf90_put_att(ncid, varid, 'long_name', 'longitude') + ierr = nf90_put_att(ncid, varid, 'units', 'degrees_east') + ierr = nf90_put_att(ncid, varid, 'axis', 'X') + + ierr = nf90_def_var(ncid, 'mask', nf90_byte, dimids, varid) + ierr = nf90_put_att(ncid, varid, 'standard_name', 'subsurface_mask') + ierr = nf90_put_att(ncid, varid, 'long_name', 'Mask accounting for subsurface scattering') + ierr = nf90_put_att(ncid, varid, 'units', 'boolean') + ierr = nf90_put_att(ncid, varid, '_FillValue', missing_value) + + ierr = nf90_def_var(ncid, 'll_lon', nf90_real, varid) + ierr = nf90_put_att(ncid, varid, 'standard_name', 'longitude of lower left corner') + ierr = nf90_put_att(ncid, varid, 'long_name', 'longitude of lower left corner') + ierr = nf90_put_att(ncid, varid, 'units', 'degrees_east') + ierr = nf90_put_att(ncid, varid, 'axis', 'X') + + ierr = nf90_def_var(ncid, 'll_lat', nf90_real, varid) + ierr = nf90_put_att(ncid, varid, 'standard_name', 'latitude of lower left corner') + ierr = nf90_put_att(ncid, varid, 'long_name', 'latitude of lower left corner') + ierr = nf90_put_att(ncid, varid, 'units', 'degrees_north') + ierr = nf90_put_att(ncid, varid, 'axis', 'Y') + + ierr = nf90_def_var(ncid, 'd_lon', nf90_real, varid) + ierr = nf90_put_att(ncid, varid, 'standard_name', 'longitude grid spacing') + ierr = nf90_put_att(ncid, varid, 'long_name', 'longitude grid spacing') + ierr = nf90_put_att(ncid, varid, 'units', 'degrees') + ierr = nf90_put_att(ncid, varid, 'axis', 'X') + + ierr = nf90_def_var(ncid, 'd_lat', nf90_real, varid) + ierr = nf90_put_att(ncid, varid, 'long_name', 'latitude grid spacing') + ierr = nf90_put_att(ncid, varid, 'units', 'degrees') + ierr = nf90_put_att(ncid, varid, 'axis', 'Y') + + ! End define mode + ierr = nf90_enddef(ncid) + + ! Write the variables + ierr = nf90_inq_varid(ncid, 'lat', varid) + ierr = nf90_put_var(ncid, varid, lat) + ierr = nf90_inq_varid(ncid, 'lon', varid) + ierr = nf90_put_var(ncid, varid, lon) + ierr = nf90_inq_varid(ncid, 'mask', varid) + ierr = nf90_put_var(ncid, varid, mask_out) + if (ierr /= nf90_noerr) stop 'Error writing variable' + ierr = nf90_inq_varid(ncid, 'll_lon', varid) + ierr = nf90_put_var(ncid, varid, ll_lon) + ierr = nf90_inq_varid(ncid, 'll_lat', varid) + ierr = nf90_put_var(ncid, varid, ll_lat) + ierr = nf90_inq_varid(ncid, 'd_lon', varid) + ierr = nf90_put_var(ncid, varid, d_lon) + ierr = nf90_inq_varid(ncid, 'd_lat', varid) + ierr = nf90_put_var(ncid, varid, d_lat) + + ! Close the NetCDF file + ierr = nf90_close(ncid) + if (ierr /= nf90_noerr) stop 'Error closing file' + +end program ascat_mask_maker \ No newline at end of file From 53065bba3a558b15bc6d4046345625cbe68d14d3 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Tue, 12 Mar 2024 13:49:43 -0400 Subject: [PATCH 275/308] discover filepath --- .../LDAS_App/util/inputs/ascat_mask/ascat_mask_maker.F90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Applications/LDAS_App/util/inputs/ascat_mask/ascat_mask_maker.F90 b/src/Applications/LDAS_App/util/inputs/ascat_mask/ascat_mask_maker.F90 index 5b348de2..6034206d 100644 --- a/src/Applications/LDAS_App/util/inputs/ascat_mask/ascat_mask_maker.F90 +++ b/src/Applications/LDAS_App/util/inputs/ascat_mask/ascat_mask_maker.F90 @@ -15,7 +15,7 @@ program ascat_mask_maker real :: d_lon, d_lat, ll_lon, ll_lat ! Open the NetCDF file - ierr = nf90_open('/Users/amfox/Desktop/GEOSldas_diagnostics/test_data/clsm/subsurface_scattering_ASCAT_ERA5_Land.nc', nf90_nowrite, ncid) + ierr = nf90_open('/discover/nobackup/amfox/subsurface_scattering_ASCAT_ERA5_Land.nc', nf90_nowrite, ncid) if (ierr /= nf90_noerr) stop 'Error opening file' ! Get the dimension ID @@ -165,4 +165,4 @@ program ascat_mask_maker ierr = nf90_close(ncid) if (ierr /= nf90_noerr) stop 'Error closing file' -end program ascat_mask_maker \ No newline at end of file +end program ascat_mask_maker From ff241e71c0e8105b54bb82469f2d79e6ac8fa084 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Tue, 12 Mar 2024 14:04:44 -0600 Subject: [PATCH 276/308] added header comment --- .../util/inputs/ascat_mask/ascat_mask_maker.F90 | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/Applications/LDAS_App/util/inputs/ascat_mask/ascat_mask_maker.F90 b/src/Applications/LDAS_App/util/inputs/ascat_mask/ascat_mask_maker.F90 index 6034206d..a3f1944f 100644 --- a/src/Applications/LDAS_App/util/inputs/ascat_mask/ascat_mask_maker.F90 +++ b/src/Applications/LDAS_App/util/inputs/ascat_mask/ascat_mask_maker.F90 @@ -1,3 +1,14 @@ +! This program reads in a NetCDF file containing ASCAT soil moisture masks available from: +! Lindorfer, R., Wagner, W., Hahn, S., Kim, H., Vreugdenhil, M., Gruber, A., Fischer, M., & Trnka, M. (2023). +! Global Scale Maps of Subsurface Scattering Signals Impacting ASCAT Soil Moisture Retrievals (1.0.0) [Data set]. +! TU Wien. https://doi.org/10.48436/9a2y9-e5z14 + +! It provides the possibility to combine different masks (default case is combination of subsurface and wetland masks) +! and interpolates onto a regular grid with a (hardwired) 0.1 degree lat/lon resolution and -90/-180 degree lower left +! corner used for quick indexing in the ASCAT observation reader QC routine. + +! Author: AM Fox, March, 2024 + program ascat_mask_maker use netcdf From ae97130435b698c5c163993f4e2422ba874e1cf8 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Tue, 12 Mar 2024 14:07:36 -0600 Subject: [PATCH 277/308] change default file write to current directory --- .../LDAS_App/util/inputs/ascat_mask/ascat_mask_maker.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Applications/LDAS_App/util/inputs/ascat_mask/ascat_mask_maker.F90 b/src/Applications/LDAS_App/util/inputs/ascat_mask/ascat_mask_maker.F90 index a3f1944f..06570135 100644 --- a/src/Applications/LDAS_App/util/inputs/ascat_mask/ascat_mask_maker.F90 +++ b/src/Applications/LDAS_App/util/inputs/ascat_mask/ascat_mask_maker.F90 @@ -103,7 +103,7 @@ program ascat_mask_maker end do ! Write out the mask to netcdf - ierr = nf90_create('ascat_combined_mask_p1_f90.nc', nf90_clobber, ncid) + ierr = nf90_create('ascat_combined_mask_p1.nc', nf90_clobber, ncid) if (ierr /= nf90_noerr) stop 'Error creating file' ! Define the dimensions From 3276a8a8fd766b75653ae03d15aac11bc0d91e40 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Tue, 12 Mar 2024 16:15:58 -0400 Subject: [PATCH 278/308] updated documentation in prep for release v18.0.0-beta (CHANGELOG.md, README.MetForcing_and_BCS.md) --- doc/CHANGELOG.md | 74 +++++++++++++++++++++++++- doc/README.MetForcing_and_BCS.md | 89 +++++++++++++++++++++++++------- 2 files changed, 143 insertions(+), 20 deletions(-) diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index 54b2545d..27de4efe 100644 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -27,12 +27,84 @@ this period, LDASsa and GEOSldas development continued in parallel. In 2019, GEOS LDAS version control transferred from CVS to Git. -This README file contains the history of stable GEOSldas versions ("tags") in Git, followed by older, CVS LDASsa and GEOSldas versions and change logs. +This README file contains the history of stable GEOSldas Releases in Git, followed by older, CVS LDASsa tags and GEOSldas versions and change logs. Overview of Git Releases: ============================ +[v18.0.0-beta](https://github.com/GEOS-ESM/GEOSldas/releases/tag/v18.0.0-beta) - 2024-03-13 +------------------------------ + +- Not 0-diff vs. v17.13.1 because of ([snow model fixes](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/813)). + +- Notes: + - Release is designated "beta" because a tag (SMAP_NRv11.1) is used for GEOSgcm_GridComp in components.yaml (awaiting official GEOSgcm_GridComp release that includes [non-0-diff snow model fixes](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/813)). + - Release uses original GEOSldas repository structure. Final release is expected to use revised GEOSldas repository structure. + +- Science changes: + - Added MODIS snow cover fraction assimilation ([PR #512](https://github.com/GEOS-ESM/GEOSldas/pull/512)). + - Added ASCAT soil moisture assimilation ([PR #656](https://github.com/GEOS-ESM/GEOSldas/pull/656), [PR #703](https://github.com/GEOS-ESM/GEOSldas/pull/703), [PR #723](https://github.com/GEOS-ESM/GEOSldas/pull/723)). + - New update_type=13 for ASCAT soil moisture and SMAP brightness temperature assimilation ([PR #703](https://github.com/GEOS-ESM/GEOSldas/pull/703)). + - New update_type=13 replaces update_type=[1,2], which was disabled. + - Requires ASCAT mask file ([PR #723](https://github.com/GEOS-ESM/GEOSldas/pull/723)). + - Disabled CatchmentCNCLM45 model option (LSM_CHOICE=3) ([PR #707](https://github.com/GEOS-ESM/GEOSldas/pull/707), [GEOSgcm_GridComp PR #900](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/900)). + - Added support for GEOS-IT surface met forcing ([PR #688](https://github.com/GEOS-ESM/GEOSldas/pull/688)). + - Added CATCHMENT_SPINUP mode ([PR #647](https://github.com/GEOS-ESM/GEOSldas/pull/647), [GEOSgcm_GridComp PR #751](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/751)). + +- GEOSgcm_GridComp: + - Tag: SMAP_NRv11.1 + - Improved MODIS-based snow albedo (v2) in make_bcs package ([GEOSgcm_GridComp PR #687](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/687)). + - Major source code cleanup: + - Stieglitz_snow: + - 0-diff ([GEOSgcm_GridComp PR #834](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/834)). + - Non-0-diff: revised snow compaction and cleanup ([GEOSgcm_GridComp PR #813](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/813)). + - make_bcs package ([GEOSgcm_GridComp PR #763](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/763), [GEOSgcm_GridComp PR #786](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/786), [GEOSgcm_GridComp PR #846](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/846)). + - coeffsib ([GEOSgcm_GridComp PR #845](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/845)). + - Fixed CDCR2 long_name ([GEOSgcm_GridComp PR #818](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/818)). + - Optional checks of snow states after application of LDAS increments ([GEOSgcm_GridComp PR #834](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/834)). + - Refined check for allowable bcs versions for CatchCN ([GEOSgcm_GridComp PR #882](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/882)). + - Fixed treatment of atmospheric CO2 input file for CatchCN ([PR #663](https://github.com/GEOS-ESM/GEOSldas/pull/663), [GEOSgcm_GridComp PR #771](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/771)). + - Fixed bug when reading vegetation type ity from restart ([GEOSgcm_GridComp PR #757](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/757)). + - Fixed bug to correct vegetation fraction assessment in GetIds_carbon (getids.F90) for CatchCN ([GEOSgcm_GridComp PR #770](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/770)). + +- Interface: + - Use boundary conditions inputs in revised directory layout and naming convention ([PR #680](https://github.com/GEOS-ESM/GEOSldas/pull/680)). + +- Utilities: + - GMAO_Shared v1.9.7 ([PR #725](https://github.com/GEOS-ESM/GEOSldas/pull/725)). + - GEOS_Util v2.0.7 ([PR #725](https://github.com/GEOS-ESM/GEOSldas/pull/725)). + - Sparse checkout of GEOS_Util ([PR #711](https://github.com/GEOS-ESM/GEOSldas/pull/711)). + - Added NCEP_Shared v1.3.0 ([PR #656](https://github.com/GEOS-ESM/GEOSldas/pull/656)). + +- Infrastructure: + - Updated for NCCS/Discover hardware: + - Added support for SLES15/Milan nodes ([PR #693](https://github.com/GEOS-ESM/GEOSldas/pull/693)). + - Removed support for Haswell nodes ([PR #681](https://github.com/GEOS-ESM/GEOSldas/pull/681)). + - Support for running GEOSldas at the NASA Advanced Supercomputing (NAS) facility ([PR #706](https://github.com/GEOS-ESM/GEOSldas/pull/706)). + - ESMA_env v4.23.0, Baselibs v7.16.0 ([PR #681](https://github.com/GEOS-ESM/GEOSldas/pull/681)). + - ESMA_cmake v3.41.0 ([PR #725](https://github.com/GEOS-ESM/GEOSldas/pull/725)). + - MAPL v2.44.0 ([PR #725](https://github.com/GEOS-ESM/GEOSldas/pull/725)). + - CircleCI Orb v2 ([PR #694](https://github.com/GEOS-ESM/GEOSldas/pull/694)). + - Replace FLAP with fArgParse ([PR #669](https://github.com/GEOS-ESM/GEOSldas/pull/669)). + +- Documentation: + - Minor updates and corrections. + +- Bug fixes and other minor changes: + - Removed requirement for mwRTM parameter input files ([PR #685](https://github.com/GEOS-ESM/GEOSldas/pull/685)). + - Support for reading corrected precipitation from aggregated daily netcdf files ([PR #718](https://github.com/GEOS-ESM/GEOSldas/pull/718)). + - Updated generate_catchincr_hist.py and sample documents for coupled land-atmosphere data assimilation ([PR #698](https://github.com/GEOS-ESM/GEOSldas/pull/698)). + - Bug fix to avoid NaN for ens std-dev in debug mode ([PR #679](https://github.com/GEOS-ESM/GEOSldas/pull/679)). + - Implementation changes for FFT used in perturbations ([PR #679](https://github.com/GEOS-ESM/GEOSldas/pull/679)). + - Some cleanup of unused variables ([PR #679](https://github.com/GEOS-ESM/GEOSldas/pull/679)). + - Updated met forcing path when coupled with ADAS ([PR #682](https://github.com/GEOS-ESM/GEOSldas/pull/682)). + - Added more export variable definitions to tile_bin2nc4.F90 ([PR #676](https://github.com/GEOS-ESM/GEOSldas/pull/676)). + - Fixed LONG_NAME for longwave variables ([PR #674](https://github.com/GEOS-ESM/GEOSldas/pull/674), [GEOSgcm_GridComp PR #764](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/764)). + - Fixed bug in matlab reader MAPL_ReadForcing_fullfile.m ([PR #665](https://github.com/GEOS-ESM/GEOSldas/pull/665)). + - Renamed GEOSldas_GridComp/Shared to GEOSldas_GridComp/LDAS_Shared ([PR #714](https://github.com/GEOS-ESM/GEOSldas/pull/714)). + +------------------------------ [v17.13.1](https://github.com/GEOS-ESM/GEOSldas/releases/tag/v17.13.1) - 2023-06-26 ------------------------------ diff --git a/doc/README.MetForcing_and_BCS.md b/doc/README.MetForcing_and_BCS.md index 5ed10ab3..04aa264b 100644 --- a/doc/README.MetForcing_and_BCS.md +++ b/doc/README.MetForcing_and_BCS.md @@ -76,22 +76,27 @@ COMMONLY USED values for `MET_PATH`: MET_PATH : /discover/nobackup/projects/gmao/merra/iau/merra_land/MERRA2_land_forcing/ ``` -#### SMAP_Nature_v03 +#### SMAP Nature Run v03 ``` MET_PATH : /discover/nobackup/projects/gmao/merra/iau/merra_land/GEOS5_land_forcing/ ``` -#### SMAP_Nature_v04, SMAP_Nature_v04.1 +#### SMAP Nature Run v04, v04.1 ``` MET_PATH : /discover/nobackup/projects/gmao/merra/iau/merra_land/GEOS5_land_forcing/ ``` -#### SMAP_Nature_v05, v7.2, v8.1, v8.3; SMAP L4_SM Version 4 +#### SMAP Nature Run v05, v7.2, v8.1, v8.3, v9.1, v10.0, v11.1; SMAP L4_SM Version 4 ``` MET_PATH : /discover/nobackup/projects/gmao/merra/iau/merra_land/MERRA2_land_forcing/ ! before 1/1/2015 MET_PATH : /discover/nobackup/projects/gmao/merra/iau/merra_land/GEOS5_land_forcing/ ! after 1/1/2015 ``` +#### SMAP L4_SM Version 5, 6, 7 +``` + MET_PATH : /discover/nobackup/projects/gmao/smap/SMAP_L4/GEOS/FP/ +``` + #### GEOS FP forcing with "seamless" file names, for use with MET_TAG=GEOS.fp.asm[__prec*] (__PREFERRED__) ``` MET_PATH : /discover/nobackup/projects/gmao/smap/SMAP_L4/GEOS/FP/ @@ -102,6 +107,11 @@ COMMONLY USED values for `MET_PATH`: MET_PATH : /discover/nobackup/projects/gmao/merra/iau/merra_land/GEOS5_land_forcing/ ``` +#### GEOS-IT forcing (including precip-corrected GEOS-IT forcing) +``` + MET_PATH : /discover/nobackup/projects/gmao/[???????] +``` + #### Forcing from post-processed output of the GEOS S2S system (FCST, AODAS) ``` @@ -220,6 +230,11 @@ COMMONLY USED values for `MET_TAG`: MET_TAG : GEOS.fp.asm ! "seamless" FP files (published/generic file names, ~same result as cross_FP, PREFERRED) ``` +#### GEOS FP-IT +``` + MET_TAG : GEOSIT???????? +``` + #### With precip corrections: #### Pre-beta SMAP L4_SM @@ -227,25 +242,25 @@ COMMONLY USED values for `MET_TAG`: MET_TAG : cross_FP__precCPCUG5FPv2 ``` -#### SMAP_Nature_v03 +#### SMAP Nature Run v03 ``` MET_TAG : cross_RPFPIT__precCPCUG5RPFPITv1 ! before 1/1/2014 MET_TAG : cross_FP__precCPCUG5FPv1 ! after 1/1/2014 ``` -#### SMAP_Nature_v04 +#### SMAP Nature Run v04 ``` MET_TAG : cross_d591_RPFPIT__precCPCUG5RPFPITv2 ! before 1/1/2014 MET_TAG : cross_FP__precCPCUG5FPv2 ! after 1/1/2014 ``` -#### SMAP_Nature_v04.1 +#### SMAP Nature Run v04.1 ``` MET_TAG : cross_d5124_RPFPIT__precCPCUG5RPFPITv2.1 ! before 1/1/2015 MET_TAG : cross_FP__precCPCUG5FPv2 ! after 1/1/2015 ``` -#### SMAP_Nature_v05, v7.2, v8.1, v8.3; SMAP L4_SM Version 4 +#### SMAP Nature Run v05, v7.2, v8.1, v8.3; SMAP L4_SM Version 4 ``` MET_TAG : M2COR_cross__precCPCUGPCP22clim_MERRA2_BMTXS ! before 1/1/2015 MET_TAG : cross_FP__precCPCUG5FPv3 ! after 1/1/2015 @@ -257,11 +272,25 @@ COMMONLY USED values for `MET_TAG`: MET_TAG : GEOS.fp.asm__precCPCUFLKG5FPv3 ! (precip corr with first-look CPCU) ``` -#### SMAP L4_SM Version 6 +#### SMAP Nature Run v9.1; SMAP L4_SM Version 6 ``` MET_TAG : GEOS.fp.asm__precCPCU_IMGFinal_IMGFclim_G5FP ! (precip corr with IMERG-Final and late-look CPCU) MET_TAG : GEOS.fp.asm__precCPCULLK_IMERGLateV06b_fp_v1 ! (precip corr with IMERG-Late and late-look CPCU) MET_TAG : GEOS.fp.asm__precCPCUFLK_IMERGLateV06b_fp_v1 ! (precip corr with IMERG-Late and first-look CPCU) + MET_TAG : GEOS.fp.asm__precCPCUFLK_IMERGLateV06c_fp_v1 ! (precip corr with IMERG-Late and first-look CPCU) +``` + +#### SMAP Nature Run v10.0; SMAP L4_SM Version 7 +``` + MET_TAG : GEOS.fp.asm__precCPCU_IMGFinal_IMGFclim_G5FP ! (precip corr with IMERG-Final and late-look CPCU) + MET_TAG : GEOS.fp.asm__precCPCUFLK_IMERGLateV06b_fp_v1 ! (precip corr with IMERG-Late and first-look CPCU) + MET_TAG : GEOS.fp.asm__precCPCUFLK_IMERGLateV06c_fp_v1 ! (precip corr with IMERG-Late and first-look CPCU) + +``` + +#### SMAP Nature Run v11.1 +``` + MET_TAG : GEOS.fp.asm__precIMGv7BFnCPCUcorrv1 ``` #### Forcing from post-processed output of the GEOS S2S system @@ -313,10 +342,12 @@ For "land" tiles, the discretization (tile-space) is constructed in one of two 2. Directly on a regular grid, e.g., `SMAP_EASEv2_M09`. -Note: GEOSldas can be run with older bcs. Note, however, that GEOSldas requires some bcs - files (NDVI and vegdyn) that did not exist in earlier bcs versions. Upon request, - older bcs directories can be patched up to work with GEOSldas (and still work with - LDASsa). +IMPORTANT: Beginning with GEOSldas release v18.0.0, bcs must be provided in a revised + directory layout and naming convention. Such bcs are available at NCCS/Discover here: +``` + BCS_PATH : /discover/nobackup/projects/gmao/bcs_shared/fvInput/ExtData/esm/tiles/ +``` + COMMONLY USED boundary conditions (bcs): @@ -327,7 +358,7 @@ COMMONLY USED boundary conditions (bcs): BCS_PATH : /discover/nobackup/projects/gmao/ssd/land/l_data/geos5/bcs/SiB2_V2_bad_lon_onDL/DC/ ``` -#### MERRA2 +#### Ganymed-4_0 (GM4): MERRA2 ``` BCS_PATH : /discover/nobackup/projects/gmao/bcs_shared/legacy_bcs/Ganymed-4_0/Ganymed-4_0_MERRA-2/ ``` @@ -349,17 +380,17 @@ COMMONLY USED boundary conditions (bcs): BCS_PATH : /discover/nobackup/projects/gmao/ssd/land/l_data/geos5/bcs/CLSM_params/mkCatchParam_SMAP_L4SM_v002/ ``` -#### Icarus-NL ("New Land"), SMAP_Nature_v7.2 +#### Icarus-NL ("New Land"): SMAP Nature Run v7.2 ``` BCS_PATH : /discover/nobackup/projects/gmao/bcs_shared/legacy_bcs/Icarus-NL/Icarus-NL_[XXXX]/ ``` Notes: -- _DON'T USE_ unless to replicate previous experiments. There is "missing" data in green*.data, nirdf*.dat, and visdf*.dat files. +- _DO NOT USE_ unless to replicate previous experiments. There is "missing" data in green*.data, nirdf*.dat, and visdf*.dat files. - This path remains in place to permit recreating experiments that have used this path. - The sub-directory "Icarus-NL_MERRA-2/" contains the "new land" bcs. The string "MERRA-2" in this sub-directory name refers to ocean bcs that are not relevant for GEOSldas. -#### Icarus-NLv2, SMAP L4_SM Version 4 +#### Icarus-NLv2: SMAP L4_SM Version 4 ``` BCS_PATH : /discover/nobackup/projects/gmao/bcs_shared/legacy_bcs/Icarus-NLv2/Icarus-NLv2_[XXXX]/ ``` @@ -368,7 +399,7 @@ Notes: - Icarus-NLv2 is a update to Icarus-NL bcs. A patch has been applied to files green*.data, nirdf*.dat, and visdf*.dat. - DEFAULT for GEOSldas v17.8.0 -#### Icarus-NLv3, SMAP_Nature_v8.1 +#### Icarus-NLv3 (NL3): SMAP Nature Run v8.1, GEOS-FP 5.25, 5.27, 5.29, GEOS-IT ``` BCS_PATH : /discover/nobackup/projects/gmao/bcs_shared/legacy_bcs/Icarus-NLv3/Icarus-NLv3_[XXXX]/ ``` @@ -384,7 +415,7 @@ Notes: - DEFAULT for GEOSldas AFTER v17.8.0 - Used in GEOS FP 5.25, 5.27, 5.29 -#### Icarus-NLv4, SMAP_Nature_v8.3, SMAP L4_SM Version 5, SMAP_Nature_v9.1, SMAP L4_SM Version 6 +#### Icarus-NLv4 (NL4): SMAP Nature Run v8.3, v9.1, SMAP L4_SM Version 5, 6 ``` BCS_PATH : /discover/nobackup/projects/gmao/smap/SMAP_L4/L4_SM/bcs/CLSM_params/Icarus-NLv4_EASE/ ``` @@ -393,7 +424,27 @@ Notes: - Icarus-NLv4 is identical to Icarus-NLv3 except that NLv4 reinstates veg heights from JPL/Simard et al. 2011 Lidar data. - Generated with GEOSldas tag v17.9.0-beta.7 under SLES11 O/S. - + +#### Icarus-NLv5 (NL5): SMAP Nature Run v10.0, SMAP L4_SM Version 7 +``` + BCS_PATH : /discover/nobackup/projects/gmao/smap/SMAP_L4/L4_SM/bcs/CLSM_params/Icarus-NLv5_EASE/ +``` + +Notes: +- Icarus-NLv5 is identical to Icarus-NLv4 except for parameters associated with PEATCLSM. + + +#### v11: SMAP Nature Run v11.1 +``` + BCS_PATH : /discover/nobackup/projects/gmao/bcs_shared/fvInput/ExtData/esm/tiles/v11/ +``` + +Notes: +- v11 is identical to Icarus-NLv5 (within roundoff) except for new MODIS-based snow albedo v2 parameters. + + + + From 30a61ad4cd22769b7915cf1f96b76b340931b233 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Tue, 12 Mar 2024 16:39:18 -0400 Subject: [PATCH 279/308] added MET_PATH and MET_TAG for GEOS-IT forcing (README.MetForcing_and_BCS.md) --- doc/README.MetForcing_and_BCS.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/README.MetForcing_and_BCS.md b/doc/README.MetForcing_and_BCS.md index 04aa264b..bea6058d 100644 --- a/doc/README.MetForcing_and_BCS.md +++ b/doc/README.MetForcing_and_BCS.md @@ -109,7 +109,7 @@ COMMONLY USED values for `MET_PATH`: #### GEOS-IT forcing (including precip-corrected GEOS-IT forcing) ``` - MET_PATH : /discover/nobackup/projects/gmao/[???????] + MET_PATH : /discover/nobackup/projects/gmao/merra/iau/merra_land/GEOSIT_land_forcing/ ``` #### Forcing from post-processed output of the GEOS S2S system (FCST, AODAS) @@ -232,7 +232,7 @@ COMMONLY USED values for `MET_TAG`: #### GEOS FP-IT ``` - MET_TAG : GEOSIT???????? + MET_TAG : cross_d5294_GEOSIT ``` #### With precip corrections: From 199c730d1e35acda8617a0510476fedc23d77d03 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Tue, 12 Mar 2024 17:50:43 -0400 Subject: [PATCH 280/308] minor cleanup and documentation (ascat_mask_maker.F90, CMakeLists.txt) --- src/Applications/LDAS_App/CMakeLists.txt | 2 +- .../ascat_mask_maker.F90 | 60 ++++++++++++------- 2 files changed, 41 insertions(+), 21 deletions(-) rename src/Applications/LDAS_App/util/inputs/{ascat_mask => ASCAT_sm_mask}/ascat_mask_maker.F90 (82%) diff --git a/src/Applications/LDAS_App/CMakeLists.txt b/src/Applications/LDAS_App/CMakeLists.txt index 1c5b4dc9..9f43cdd9 100644 --- a/src/Applications/LDAS_App/CMakeLists.txt +++ b/src/Applications/LDAS_App/CMakeLists.txt @@ -16,7 +16,7 @@ ecbuild_add_executable ( ecbuild_add_executable ( TARGET ascat_mask_maker.x - SOURCES util/inputs/ascat_mask/ascat_mask_maker.F90 + SOURCES util/inputs/ASCAT_sm_mask/ascat_mask_maker.F90 LIBS MAPL ) diff --git a/src/Applications/LDAS_App/util/inputs/ascat_mask/ascat_mask_maker.F90 b/src/Applications/LDAS_App/util/inputs/ASCAT_sm_mask/ascat_mask_maker.F90 similarity index 82% rename from src/Applications/LDAS_App/util/inputs/ascat_mask/ascat_mask_maker.F90 rename to src/Applications/LDAS_App/util/inputs/ASCAT_sm_mask/ascat_mask_maker.F90 index 06570135..b1849a7d 100644 --- a/src/Applications/LDAS_App/util/inputs/ascat_mask/ascat_mask_maker.F90 +++ b/src/Applications/LDAS_App/util/inputs/ASCAT_sm_mask/ascat_mask_maker.F90 @@ -2,11 +2,11 @@ ! Lindorfer, R., Wagner, W., Hahn, S., Kim, H., Vreugdenhil, M., Gruber, A., Fischer, M., & Trnka, M. (2023). ! Global Scale Maps of Subsurface Scattering Signals Impacting ASCAT Soil Moisture Retrievals (1.0.0) [Data set]. ! TU Wien. https://doi.org/10.48436/9a2y9-e5z14 - +! ! It provides the possibility to combine different masks (default case is combination of subsurface and wetland masks) -! and interpolates onto a regular grid with a (hardwired) 0.1 degree lat/lon resolution and -90/-180 degree lower left +! and interpolates onto a regular grid with a (hardwired) 0.1 degree lat/lon spacing and -90/-180 degree lower left ! corner used for quick indexing in the ASCAT observation reader QC routine. - +! ! Author: AM Fox, March, 2024 program ascat_mask_maker @@ -25,9 +25,33 @@ program ascat_mask_maker real, dimension(:), allocatable :: lon, lat, distances real :: d_lon, d_lat, ll_lon, ll_lat + character(400) :: fname_in + + ! -------------------------------------------------------------------------------- + ! + ! hardwired variables + + ! ASCAT soil moisture mask file from Lindorfer et al 2023 + + fname_in = '/discover/nobackup/amfox/subsurface_scattering_ASCAT_ERA5_Land.nc' + + ! Specification of output grid and missing value + + d_lon = 0.1 + d_lat = 0.1 + ll_lon = -180.0 + ll_lat = -90.0 + + missing_value = -128 + + ! ------------------------------- + ! Open the NetCDF file - ierr = nf90_open('/discover/nobackup/amfox/subsurface_scattering_ASCAT_ERA5_Land.nc', nf90_nowrite, ncid) + ierr = nf90_open(fname_in, nf90_nowrite, ncid) if (ierr /= nf90_noerr) stop 'Error opening file' + + ! Data in original mask file are on the 12.5 km fixed Earth grid used for ASCAT (WARP5 grid) and + ! stored in the NetCDF file as 1-dimensional arrays of length N_gpi (over land only). ! Get the dimension ID ierr = nf90_inq_dimid(ncid, 'gpi', dimid) @@ -40,13 +64,13 @@ program ascat_mask_maker print*, 'N_gpi = ', N_gpi ! Allocate the arrays - allocate(asc_lon(N_gpi)) - allocate(asc_lat(N_gpi)) - allocate(cold_mask(N_gpi)) - allocate(wet_mask(N_gpi)) - allocate(veg_mask(N_gpi)) + allocate(asc_lon( N_gpi)) + allocate(asc_lat( N_gpi)) + allocate(cold_mask( N_gpi)) + allocate(wet_mask( N_gpi)) + allocate(veg_mask( N_gpi)) allocate(subsurface_mask(N_gpi)) - allocate(combined_mask(N_gpi)) + allocate(combined_mask( N_gpi)) ! Get the variable IDs and read the variables ierr = nf90_inq_varid(ncid, 'lon', varid) @@ -66,18 +90,14 @@ program ascat_mask_maker ierr = nf90_close(ncid) if (ierr /= nf90_noerr) stop 'Error closing file' - ! Combine the masks + ! Combine the masks (1-dim arrays) where (wet_mask == 1) combined_mask = 1 elsewhere combined_mask = subsurface_mask end where - d_lon = 0.1 - d_lat = 0.1 - ll_lon = -180.0 - ll_lat = -90.0 - missing_value = -128 + ! Re-map "combined_mask" from WARP5 input grid to regular lat/lon output grid (2-dim array) allocate(lon(int(360.0 / d_lon))) allocate(lat(int(180.0 / d_lat))) @@ -91,9 +111,9 @@ program ascat_mask_maker print*, lon(i) do j = 1, size(lat) allocate(distances(size(asc_lon))) - distances = sqrt((asc_lon - lon(i))**2 + (asc_lat - lat(j))**2) + distances = (asc_lon - lon(i))**2 + (asc_lat - lat(j))**2 closest_index = minloc(distances, dim = 1) - if (distances(closest_index) > 0.14) then + if (distances(closest_index) > 0.14**2) then mask_out(i, j) = missing_value else mask_out(i, j) = combined_mask(closest_index) @@ -124,8 +144,8 @@ program ascat_mask_maker ierr = nf90_put_att(ncid, varid, 'axis', 'X') ierr = nf90_def_var(ncid, 'mask', nf90_byte, dimids, varid) - ierr = nf90_put_att(ncid, varid, 'standard_name', 'subsurface_mask') - ierr = nf90_put_att(ncid, varid, 'long_name', 'Mask accounting for subsurface scattering') + ierr = nf90_put_att(ncid, varid, 'standard_name', 'combined_mask') + ierr = nf90_put_att(ncid, varid, 'long_name', 'Combined mask') ierr = nf90_put_att(ncid, varid, 'units', 'boolean') ierr = nf90_put_att(ncid, varid, '_FillValue', missing_value) From a6bad3a43b3f182190bc09fd9471c792fdfae7d6 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Tue, 12 Mar 2024 18:12:11 -0400 Subject: [PATCH 281/308] updated EASEv2_M09 grid name (README.MetForcing_and_BCS.md) --- doc/README.MetForcing_and_BCS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/README.MetForcing_and_BCS.md b/doc/README.MetForcing_and_BCS.md index bea6058d..f1eda241 100644 --- a/doc/README.MetForcing_and_BCS.md +++ b/doc/README.MetForcing_and_BCS.md @@ -339,7 +339,7 @@ For "land" tiles, the discretization (tile-space) is constructed in one of two 0.5-degree ("c180") cube-sphere grid used by the atmospheric model in the MERRA-2 reanalysis: `CF0180x6C_DE1440xPE0720`. - 2. Directly on a regular grid, e.g., `SMAP_EASEv2_M09`. + 2. Directly on a regular grid, e.g., `EASEv2_M09`. IMPORTANT: Beginning with GEOSldas release v18.0.0, bcs must be provided in a revised From 9aa8ec7b2c8c812d404cde1e878a9408dfbe32c9 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Wed, 13 Mar 2024 09:26:44 -0600 Subject: [PATCH 282/308] declare mask variables as integers --- .../util/inputs/ASCAT_sm_mask/ascat_mask_maker.F90 | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Applications/LDAS_App/util/inputs/ASCAT_sm_mask/ascat_mask_maker.F90 b/src/Applications/LDAS_App/util/inputs/ASCAT_sm_mask/ascat_mask_maker.F90 index b1849a7d..4d909411 100644 --- a/src/Applications/LDAS_App/util/inputs/ASCAT_sm_mask/ascat_mask_maker.F90 +++ b/src/Applications/LDAS_App/util/inputs/ASCAT_sm_mask/ascat_mask_maker.F90 @@ -15,13 +15,14 @@ program ascat_mask_maker implicit none - integer :: ncid, varid, dimid, ierr, len, N_gpi, dimids(2) - integer :: i, j, closest_index + integer :: ncid, varid, dimid, ierr, len, N_gpi, dimids(2) + integer :: i, j, closest_index + integer, dimension(:), allocatable :: cold_mask, wet_mask, veg_mask, subsurface_mask, combined_mask integer(kind=1), dimension(:,:), allocatable :: mask_out integer(kind=1) :: missing_value - real, dimension(:), allocatable :: asc_lon, asc_lat, cold_mask, wet_mask, veg_mask, subsurface_mask, combined_mask + real, dimension(:), allocatable :: asc_lon, asc_lat real, dimension(:), allocatable :: lon, lat, distances real :: d_lon, d_lat, ll_lon, ll_lat From 94973d476f9795a0905194c181f622618d36f610 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Wed, 13 Mar 2024 13:13:58 -0400 Subject: [PATCH 283/308] additional corrections and updates (README.MetForcing_and_BCS.md) --- doc/README.MetForcing_and_BCS.md | 198 ++++++++++++++----------------- 1 file changed, 89 insertions(+), 109 deletions(-) diff --git a/doc/README.MetForcing_and_BCS.md b/doc/README.MetForcing_and_BCS.md index f1eda241..03e3dfb4 100644 --- a/doc/README.MetForcing_and_BCS.md +++ b/doc/README.MetForcing_and_BCS.md @@ -12,29 +12,26 @@ Author: - jperket (10 Dec 2019) - converted to markdown -Met Forcing -========= - -Surface meteorological forcing data +Surface Meteorological Forcing +================================================================================ The forcing time step is controlled with the configurable resource variable __FORCE_DTSTEP__ and __must match the frequency of the input forcing files__. -Specify FORCE_DTSTEP=3600 [seconds] for GEOS products, incl. MERRA, MERRA-2, FP, and FP-IT/RP-IT, which are 1-hourly datasets. +Specify FORCE_DTSTEP=3600 [seconds] for most GEOS products, incl. MERRA, MERRA-2, FP, FP-IT/RP-IT, and GEOS-IT, which are 1-hourly datasets. The spatial (horizontal) interpolation method for the met forcing is controlled by `MET_HINTERP` (see optional parameters in `exeinp` input file to ldas_setup). `MET_PATH` and `MET_TAG` must be consistent: - - `MET_PATH` is the full path to the forcing data set + - `MET_PATH` is the full path to the forcing data set. - - `MET_TAG` is an identifier for the forcing data set + - `MET_TAG` is an identifier for the forcing data set. - - Available non-MERRA and non-GEOS forcing data sets are pre-defined - in subroutine get_forcing() + - Available non-GEOS forcing data sets are pre-defined in subroutine get_forcing(). - - For MERRA and other GEOS forcing datasets, see special `MET_TAG` + - For GEOS forcing datasets, see special `MET_TAG` parsing conventions in subroutines parse_MERRA_met_tag(), parse_MERRA2_met_tag() - and parse_G5DAS_met_tag() + and parse_G5DAS_met_tag(). - For details on corrected precipitation data see also (https://gmao.gsfc.nasa.gov/pubs/): - Reichle and Liu (2014), @@ -64,49 +61,34 @@ COMMONLY USED values for `MET_PATH`: MET_PATH : /discover/nobackup/projects/lis/MET_FORCING/ERA5/ ``` -### GEOS-based datasets +### GEOS datasets #### MERRA forcing (including precip-corrected MERRA forcing) ``` MET_PATH : /discover/nobackup/projects/gmao/merra/iau/merra_land/MERRA_land_forcing/ ``` -#### MERRA2 forcing (including precip-corrected MERRA forcing) +#### MERRA2 forcing (including precip-corrected MERRA2 forcing) ``` MET_PATH : /discover/nobackup/projects/gmao/merra/iau/merra_land/MERRA2_land_forcing/ ``` -#### SMAP Nature Run v03 -``` - MET_PATH : /discover/nobackup/projects/gmao/merra/iau/merra_land/GEOS5_land_forcing/ -``` - -#### SMAP Nature Run v04, v04.1 -``` - MET_PATH : /discover/nobackup/projects/gmao/merra/iau/merra_land/GEOS5_land_forcing/ -``` - -#### SMAP Nature Run v05, v7.2, v8.1, v8.3, v9.1, v10.0, v11.1; SMAP L4_SM Version 4 -``` - MET_PATH : /discover/nobackup/projects/gmao/merra/iau/merra_land/MERRA2_land_forcing/ ! before 1/1/2015 - MET_PATH : /discover/nobackup/projects/gmao/merra/iau/merra_land/GEOS5_land_forcing/ ! after 1/1/2015 -``` - -#### SMAP L4_SM Version 5, 6, 7 -``` - MET_PATH : /discover/nobackup/projects/gmao/smap/SMAP_L4/GEOS/FP/ -``` +Note: Used for SMAP Nature Run v05, v7.2, v8.1, v8.3, v9.1, v10.0, v11.1 (before 1/1/2015) #### GEOS FP forcing with "seamless" file names, for use with MET_TAG=GEOS.fp.asm[__prec*] (__PREFERRED__) ``` MET_PATH : /discover/nobackup/projects/gmao/smap/SMAP_L4/GEOS/FP/ ``` +Note: Used for SMAP Nature Run v8.1, v8.3, v9.1, v10.0, v11.1 (after 1/1/2015); SMAP L4_SM Version 5, 6, 7. + #### GEOS forcing with experiment-specific file names, incl. FP (__DEPRECATED__), FP-IT/RP-IT, and precip-corrected GEOS forcing ``` MET_PATH : /discover/nobackup/projects/gmao/merra/iau/merra_land/GEOS5_land_forcing/ ``` +Note: Used for SMAP Nature Run v03, v04, v04.1, v05, v7.2 (after 1/1/2015); SMAP L4_SM Version 4 + #### GEOS-IT forcing (including precip-corrected GEOS-IT forcing) ``` MET_PATH : /discover/nobackup/projects/gmao/merra/iau/merra_land/GEOSIT_land_forcing/ @@ -116,7 +98,7 @@ COMMONLY USED values for `MET_PATH`: ``` MET_PATH : [check with GMAO S2S group] -``` +``` @@ -136,7 +118,7 @@ COMMONLY USED values for `MET_TAG`: MET_TAG : ERA5_LIS ``` -### GEOS-based datasets +### GEOS datasets #### MERRA ``` @@ -150,32 +132,32 @@ COMMONLY USED values for `MET_TAG`: #### MERRA-2 - - All MERRA-2 options use native MERRA-2 "lfo" files for all surface met forcing fields - *except* precipitation. + - All MERRA-2 options use native MERRA-2 "lfo" files for all surface met forcing fields *except* precipitation. - Option 1a: Use corrected precip seen by the land w/in the MERRA-2 system (i.e., native MERRA-2 "lfo" files). Precip is as corrected within the MERRA-2 system. Closest to land-only MERRA-2 replay. ``` - MET_TAG : M2COR_cross - MET_TAG : M2COR_100 - MET_TAG : M2COR_200 - MET_TAG : M2COR_300 - MET_TAG : M2COR_400 - ``` - - Option 1b: + MET_TAG : M2COR_cross ! all streams + MET_TAG : M2COR_100 ! stream 1 only + MET_TAG : M2COR_200 ! stream 2 only + MET_TAG : M2COR_300 ! stream 3 only + MET_TAG : M2COR_400 ! stream 4 only + ``` + +- Option 1b: Use corrected precip forcing constructed in post-processing using MERRA-2 as background. Background precip is typically from MERRA-2 "int" data, but corrected precip is stored in files that look like MERRA-2 "lfo" files. For example, select corrected precip version "CPCUGPCP22clim_MERRA2_BMTXS" as follows: ``` - MET_TAG : M2COR_cross__precCPCUGPCP22clim_MERRA2_BMTXS - MET_TAG : M2COR_100__precCPCUGPCP22clim_MERRA2_BMTXS - MET_TAG : M2COR_200__precCPCUGPCP22clim_MERRA2_BMTXS - MET_TAG : M2COR_300__precCPCUGPCP22clim_MERRA2_BMTXS - MET_TAG : M2COR_400__precCPCUGPCP22clim_MERRA2_BMTXS + MET_TAG : M2COR_cross__precCPCUGPCP22clim_MERRA2_BMTXS ! all streams + MET_TAG : M2COR_100__precCPCUGPCP22clim_MERRA2_BMTXS ! stream 1 only + MET_TAG : M2COR_200__precCPCUGPCP22clim_MERRA2_BMTXS ! stream 2 only + MET_TAG : M2COR_300__precCPCUGPCP22clim_MERRA2_BMTXS ! stream 3 only + MET_TAG : M2COR_400__precCPCUGPCP22clim_MERRA2_BMTXS ! stream 4 only ``` This particular version uses as background the MERRA-2 model ("int") precip, rescaled to @@ -188,32 +170,35 @@ COMMONLY USED values for `MET_TAG`: Use uncorrected precip generated by the AGCM w/in the MERRA-2 system (i.e., native MERRA-2 "int" files). ``` - MET_TAG : M2INT_cross - MET_TAG : M2INT_100 - MET_TAG : M2INT_200 - MET_TAG : M2INT_300 - MET_TAG : M2INT_400 - ``` + MET_TAG : M2INT_cross ! all streams + MET_TAG : M2INT_100 ! stream 1 only + MET_TAG : M2INT_200 ! stream 2 only + MET_TAG : M2INT_300 ! stream 3 only + MET_TAG : M2INT_400 ! stream 4 only + ``` #### RP-IT/FP-IT (d591) -``` - MET_TAG : d591_rpit1_jan00 - MET_TAG : d591_rpit2_jun06 - MET_TAG : d591_rpit3_jan11 - MET_TAG : d591_fpit - MET_TAG : cross_d591_RPFPIT + ``` + MET_TAG : cross_d591_RPFPIT ! all streams + MET_TAG : d591_rpit1_jan00 ! stream 1 only + MET_TAG : d591_rpit2_jun06 ! stream 2 only + MET_TAG : d591_rpit3_jan11 ! stream 3 only + MET_TAG : d591_fpit ! stream 4 only ``` #### RP-IT/FP-IT (d5124) ``` - MET_TAG : d5124_rpit1_jan00 - MET_TAG : d5124_rpit2_jun04 - MET_TAG : d5124_rpit3_jan12 ! updated through present - MET_TAG : cross_d5124_RPFPIT ! uses "late-look" through present + MET_TAG : cross_d5124_RPFPIT ! all streams - uses "late-look" through present + MET_TAG : d5124_rpit1_jan00 ! stream 1 only + MET_TAG : d5124_rpit2_jun04 ! stream 2 only + MET_TAG : d5124_rpit3_jan12 ! stream 3 only - updated through present ``` #### GEOS FP ``` + MET_TAG : GEOS.fp.asm ! PREFERRED: "seamless" FP files (published/generic file names, ~same result as cross_FP) + + MET_TAG : cross_FP ! DEPRECATED: stitch FP experiment names across years MET_TAG : e5110_fp ! starting 11 Jun 2013 MET_TAG : e5130_fp ! starting 20 Aug 2014 MET_TAG : e5131_fp ! starting 1 May 2015 @@ -224,18 +209,45 @@ COMMONLY USED values for `MET_TAG`: MET_TAG : f525_fp ! starting 30 Jan 2020 MET_TAG : f525_p5_fp ! starting 7 Apr 2020 ... - - MET_TAG : cross_FP ! stitch FP experiment names across years (DEPRECATED) - - MET_TAG : GEOS.fp.asm ! "seamless" FP files (published/generic file names, ~same result as cross_FP, PREFERRED) ``` -#### GEOS FP-IT +#### GEOS-IT ``` MET_TAG : cross_d5294_GEOSIT ``` -#### With precip corrections: +#### Forcing from post-processed output of the GEOS S2S system + + - Forcing derived through post-processing of daily average output from the GEOS S2S system, + including S2S hindcasts/forecasts ("FCST") and the "AODAS" used for S2S initialization. + + S2S output is from the geosgcm_vis2d and geosgcm_surf Collections for FCST and from the + geosgcm_rad and geosgcm_surf Collections for AODAS (see GMAO Office Note No. 16). + + For FCST, post-processing includes a monthly bias correction to the MERRA-2 climatology. + + Daily data are disaggregated to 6-hourly (FCST) or 1-hourly (AODAS) using the MERRA-2 + climatological diurnal cycle. + + For FCST, MET_TAG must specify S2S ensemble member ('ensX'; currently: 'ens1', 'ens2', + 'ens3', or 'ens4') and month/day of forecast initialization ('MMMDD'; e.g., 'jan01'), + separated by double underscores. + + As of 14 Jun 2021: + - Preparation of S2S forcing data ignores the 3-hour offset between S2S daily averages + (21z-21z) and the MERRA-2 daily averages (0z-0z) used for the temporal disaggregration. + - The processing of the S2S output incorrectly partitioned total precipitation into snowfall + and convective precipitation. Therefore, rainfall and snowfall are determined in the + S2S forcing reader from total precipitation and air temperature. Convective rainfall is + set to 0. (As of now, only total rainfall is used by Catchment.) + +``` + MET_TAG : GEOSs2sFCST__[ensX]__[MMMDD] + MET_TAG : GEOSs2sAODAS +``` + + +#### SMAP L4_SM #### Pre-beta SMAP L4_SM ``` @@ -245,7 +257,7 @@ COMMONLY USED values for `MET_TAG`: #### SMAP Nature Run v03 ``` MET_TAG : cross_RPFPIT__precCPCUG5RPFPITv1 ! before 1/1/2014 - MET_TAG : cross_FP__precCPCUG5FPv1 ! after 1/1/2014 + MET_TAG : cross_FP__precCPCUG5FPv1 ! after 1/1/2014 ``` #### SMAP Nature Run v04 @@ -293,41 +305,12 @@ COMMONLY USED values for `MET_TAG`: MET_TAG : GEOS.fp.asm__precIMGv7BFnCPCUcorrv1 ``` -#### Forcing from post-processed output of the GEOS S2S system - - - Forcing derived through post-processing of daily average output from the GEOS S2S system, - including S2S hindcasts/forecasts ("FCST") and the "AODAS" used for S2S initialization. - - S2S output is from the geosgcm_vis2d and geosgcm_surf Collections for FCST and from the - geosgcm_rad and geosgcm_surf Collections for AODAS (see GMAO Office Note No. 16). - - For FCST, post-processing includes a monthly bias correction to the MERRA-2 climatology. - - Daily data are disaggregated to 6-hourly (FCST) or 1-hourly (AODAS) using the MERRA-2 - climatological diurnal cycle. - - For FCST, MET_TAG must specify S2S ensemble member ('ensX'; currently: 'ens1', 'ens2', - 'ens3', or 'ens4') and month/day of forecast initialization ('MMMDD'; e.g., 'jan01'), - separated by double underscores. - - As of 14 Jun 2021: - - Preparation of S2S forcing data ignores the 3-hour offset between S2S daily averages - (21z-21z) and the MERRA-2 daily averages (0z-0z) used for the temporal disaggregration. - - The processing of the S2S output incorrectly partitioned total precipitation into snowfall - and convective precipitation. Therefore, rainfall and snowfall are determined in the - S2S forcing reader from total precipitation and air temperature. Convective rainfall is - set to 0. (As of now, only total rainfall is used by Catchment.) - -``` - MET_TAG : GEOSs2sFCST__[ensX]__[MMMDD] - MET_TAG : GEOSs2sAODAS -``` Boundary Conditions ================================================================================ Boundary conditions (bcs) are tile-space model parameters that are provided in a - set of files located in `BCS_PATH/BCS_RESOLUTION`. + set of files located in `BCS_PATH` for a given `BCS_RESOLUTION`. For "land" tiles, the discretization (tile-space) is constructed in one of two different ways: @@ -342,8 +325,8 @@ For "land" tiles, the discretization (tile-space) is constructed in one of two 2. Directly on a regular grid, e.g., `EASEv2_M09`. -IMPORTANT: Beginning with GEOSldas release v18.0.0, bcs must be provided in a revised - directory layout and naming convention. Such bcs are available at NCCS/Discover here: +**IMPORTANT**: Beginning with GEOSldas release v18.0.0, bcs must be provided in a revised + directory layout and naming convention. On NCCS/Discover, use: ``` BCS_PATH : /discover/nobackup/projects/gmao/bcs_shared/fvInput/ExtData/esm/tiles/ ``` @@ -386,7 +369,7 @@ COMMONLY USED boundary conditions (bcs): ``` Notes: -- _DO NOT USE_ unless to replicate previous experiments. There is "missing" data in green*.data, nirdf*.dat, and visdf*.dat files. +- _DO NOT USE_ unless replicating previous experiments. There is "missing" data in green*.data, nirdf*.dat, and visdf*.dat files. - This path remains in place to permit recreating experiments that have used this path. - The sub-directory "Icarus-NL_MERRA-2/" contains the "new land" bcs. The string "MERRA-2" in this sub-directory name refers to ocean bcs that are not relevant for GEOSldas. @@ -397,7 +380,6 @@ Notes: Notes: - Icarus-NLv2 is a update to Icarus-NL bcs. A patch has been applied to files green*.data, nirdf*.dat, and visdf*.dat. -- DEFAULT for GEOSldas v17.8.0 #### Icarus-NLv3 (NL3): SMAP Nature Run v8.1, GEOS-FP 5.25, 5.27, 5.29, GEOS-IT ``` @@ -407,13 +389,11 @@ Notes: Notes: - Soil parameters for a small fraction (< 0.05%) of tiles changed to correct "Mali" bug. - Vegdyn.data now netcdf4; reverts to using Dorman/Sellers veg heights (abandons JPL/Simard et al. 2011 Lidar data). -- Some underlying ASCII data files are now grouped to netcdf4. I.e., data in ar.new, bf.dat, ts.dat, etc are now in: +- Some underlying ASCII data files are now grouped into a netcdf4 file. I.e., data in ar.new, bf.dat, ts.dat, etc are now in: - clsm/catch_params.nc4 (for Catch) - clsm/catchcn_params.nc4 (for CatchCN) - Generated with cvs tag Jason-3_0_LANDBCS -- DEFAULT for GEOSldas AFTER v17.8.0 -- Used in GEOS FP 5.25, 5.27, 5.29 #### Icarus-NLv4 (NL4): SMAP Nature Run v8.3, v9.1, SMAP L4_SM Version 5, 6 ``` From 0187745e304e285deb2481d786585377ba436559 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Wed, 13 Mar 2024 13:19:51 -0400 Subject: [PATCH 284/308] white-space changes to fix alignment (README.MetForcing_and_BCS.md) --- doc/README.MetForcing_and_BCS.md | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/doc/README.MetForcing_and_BCS.md b/doc/README.MetForcing_and_BCS.md index 03e3dfb4..5560e476 100644 --- a/doc/README.MetForcing_and_BCS.md +++ b/doc/README.MetForcing_and_BCS.md @@ -146,7 +146,7 @@ COMMONLY USED values for `MET_TAG`: MET_TAG : M2COR_400 ! stream 4 only ``` -- Option 1b: + - Option 1b: Use corrected precip forcing constructed in post-processing using MERRA-2 as background. Background precip is typically from MERRA-2 "int" data, but corrected precip is stored in files that look like MERRA-2 "lfo" files. @@ -155,9 +155,9 @@ COMMONLY USED values for `MET_TAG`: ``` MET_TAG : M2COR_cross__precCPCUGPCP22clim_MERRA2_BMTXS ! all streams MET_TAG : M2COR_100__precCPCUGPCP22clim_MERRA2_BMTXS ! stream 1 only - MET_TAG : M2COR_200__precCPCUGPCP22clim_MERRA2_BMTXS ! stream 2 only - MET_TAG : M2COR_300__precCPCUGPCP22clim_MERRA2_BMTXS ! stream 3 only - MET_TAG : M2COR_400__precCPCUGPCP22clim_MERRA2_BMTXS ! stream 4 only + MET_TAG : M2COR_200__precCPCUGPCP22clim_MERRA2_BMTXS ! stream 2 only + MET_TAG : M2COR_300__precCPCUGPCP22clim_MERRA2_BMTXS ! stream 3 only + MET_TAG : M2COR_400__precCPCUGPCP22clim_MERRA2_BMTXS ! stream 4 only ``` This particular version uses as background the MERRA-2 model ("int") precip, rescaled to @@ -184,18 +184,18 @@ COMMONLY USED values for `MET_TAG`: MET_TAG : d591_rpit2_jun06 ! stream 2 only MET_TAG : d591_rpit3_jan11 ! stream 3 only MET_TAG : d591_fpit ! stream 4 only -``` + ``` #### RP-IT/FP-IT (d5124) -``` + ``` MET_TAG : cross_d5124_RPFPIT ! all streams - uses "late-look" through present MET_TAG : d5124_rpit1_jan00 ! stream 1 only MET_TAG : d5124_rpit2_jun04 ! stream 2 only MET_TAG : d5124_rpit3_jan12 ! stream 3 only - updated through present -``` + ``` #### GEOS FP -``` + ``` MET_TAG : GEOS.fp.asm ! PREFERRED: "seamless" FP files (published/generic file names, ~same result as cross_FP) MET_TAG : cross_FP ! DEPRECATED: stitch FP experiment names across years @@ -209,12 +209,12 @@ COMMONLY USED values for `MET_TAG`: MET_TAG : f525_fp ! starting 30 Jan 2020 MET_TAG : f525_p5_fp ! starting 7 Apr 2020 ... -``` + ``` #### GEOS-IT -``` + ``` MET_TAG : cross_d5294_GEOSIT -``` + ``` #### Forcing from post-processed output of the GEOS S2S system @@ -241,10 +241,10 @@ COMMONLY USED values for `MET_TAG`: S2S forcing reader from total precipitation and air temperature. Convective rainfall is set to 0. (As of now, only total rainfall is used by Catchment.) -``` - MET_TAG : GEOSs2sFCST__[ensX]__[MMMDD] - MET_TAG : GEOSs2sAODAS -``` + ``` + MET_TAG : GEOSs2sFCST__[ensX]__[MMMDD] + MET_TAG : GEOSs2sAODAS + ``` #### SMAP L4_SM From cd114d11168c7781d09db2eb419673825ba29d56 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Wed, 13 Mar 2024 13:42:37 -0400 Subject: [PATCH 285/308] additional minor edits (README.MetForcing_and_BCS.md) --- doc/README.MetForcing_and_BCS.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/doc/README.MetForcing_and_BCS.md b/doc/README.MetForcing_and_BCS.md index 5560e476..9c6bc3c2 100644 --- a/doc/README.MetForcing_and_BCS.md +++ b/doc/README.MetForcing_and_BCS.md @@ -4,7 +4,7 @@ README.metforcing_and_bcs Description: --------------- -Information about met forcing and boundary conditions for GEOSldas. +Information about surface meteorological forcing and boundary conditions for GEOSldas. Author: --------------- @@ -73,7 +73,7 @@ COMMONLY USED values for `MET_PATH`: MET_PATH : /discover/nobackup/projects/gmao/merra/iau/merra_land/MERRA2_land_forcing/ ``` -Note: Used for SMAP Nature Run v05, v7.2, v8.1, v8.3, v9.1, v10.0, v11.1 (before 1/1/2015) +Note: Used for SMAP Nature Run v05, v7.2, v8.1, v8.3, v9.1, v10.0, v11.1 (before 1/1/2015). #### GEOS FP forcing with "seamless" file names, for use with MET_TAG=GEOS.fp.asm[__prec*] (__PREFERRED__) ``` @@ -87,7 +87,7 @@ Note: Used for SMAP Nature Run v8.1, v8.3, v9.1, v10.0, v11.1 (after 1/1/2015); MET_PATH : /discover/nobackup/projects/gmao/merra/iau/merra_land/GEOS5_land_forcing/ ``` -Note: Used for SMAP Nature Run v03, v04, v04.1, v05, v7.2 (after 1/1/2015); SMAP L4_SM Version 4 +Note: Used for SMAP Nature Run v03, v04, v04.1, v05, v7.2 (after 1/1/2015); SMAP L4_SM Version 4. #### GEOS-IT forcing (including precip-corrected GEOS-IT forcing) ``` @@ -96,7 +96,7 @@ Note: Used for SMAP Nature Run v03, v04, v04.1, v05, v7.2 (after 1/1/2015); SMAP #### Forcing from post-processed output of the GEOS S2S system (FCST, AODAS) -``` +``` MET_PATH : [check with GMAO S2S group] ``` @@ -147,7 +147,7 @@ COMMONLY USED values for `MET_TAG`: ``` - Option 1b: - Use corrected precip forcing constructed in post-processing using MERRA-2 as background. + Use corrected precip forcing constructed in post-processing using MERRA-2 as background. Background precip is typically from MERRA-2 "int" data, but corrected precip is stored in files that look like MERRA-2 "lfo" files. @@ -257,16 +257,16 @@ COMMONLY USED values for `MET_TAG`: #### SMAP Nature Run v03 ``` MET_TAG : cross_RPFPIT__precCPCUG5RPFPITv1 ! before 1/1/2014 - MET_TAG : cross_FP__precCPCUG5FPv1 ! after 1/1/2014 + MET_TAG : cross_FP__precCPCUG5FPv1 ! after 1/1/2014 ``` -#### SMAP Nature Run v04 +#### SMAP Nature Run v04 ``` MET_TAG : cross_d591_RPFPIT__precCPCUG5RPFPITv2 ! before 1/1/2014 MET_TAG : cross_FP__precCPCUG5FPv2 ! after 1/1/2014 ``` -#### SMAP Nature Run v04.1 +#### SMAP Nature Run v04.1 ``` MET_TAG : cross_d5124_RPFPIT__precCPCUG5RPFPITv2.1 ! before 1/1/2015 MET_TAG : cross_FP__precCPCUG5FPv2 ! after 1/1/2015 @@ -306,7 +306,7 @@ COMMONLY USED values for `MET_TAG`: ``` -Boundary Conditions +Boundary Conditions ================================================================================ Boundary conditions (bcs) are tile-space model parameters that are provided in a @@ -390,8 +390,8 @@ Notes: - Soil parameters for a small fraction (< 0.05%) of tiles changed to correct "Mali" bug. - Vegdyn.data now netcdf4; reverts to using Dorman/Sellers veg heights (abandons JPL/Simard et al. 2011 Lidar data). - Some underlying ASCII data files are now grouped into a netcdf4 file. I.e., data in ar.new, bf.dat, ts.dat, etc are now in: - - clsm/catch_params.nc4 (for Catch) - - clsm/catchcn_params.nc4 (for CatchCN) + - clsm/catch_params.nc4 + - clsm/catchcn_params.nc4 (additional parameters for CatchCN) - Generated with cvs tag Jason-3_0_LANDBCS From ccaf9f5b90aae10094ed9a8e84c9ac16fe486438 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Wed, 13 Mar 2024 13:55:28 -0400 Subject: [PATCH 286/308] minor edits re. release v18.0.0-beta (CHANGELOG.md) --- doc/CHANGELOG.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index 27de4efe..fba3ac50 100644 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -33,10 +33,10 @@ This README file contains the history of stable GEOSldas Releases in Git, follow Overview of Git Releases: ============================ -[v18.0.0-beta](https://github.com/GEOS-ESM/GEOSldas/releases/tag/v18.0.0-beta) - 2024-03-13 +[v18.0.0-beta](https://github.com/GEOS-ESM/GEOSldas/releases/tag/v18.0.0-beta) - 2024-03-14 ------------------------------ -- Not 0-diff vs. v17.13.1 because of ([snow model fixes](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/813)). +- Not 0-diff vs. v17.13.1 because of [snow model fixes](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/813). - Notes: - Release is designated "beta" because a tag (SMAP_NRv11.1) is used for GEOSgcm_GridComp in components.yaml (awaiting official GEOSgcm_GridComp release that includes [non-0-diff snow model fixes](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/813)). @@ -46,7 +46,7 @@ Overview of Git Releases: - Added MODIS snow cover fraction assimilation ([PR #512](https://github.com/GEOS-ESM/GEOSldas/pull/512)). - Added ASCAT soil moisture assimilation ([PR #656](https://github.com/GEOS-ESM/GEOSldas/pull/656), [PR #703](https://github.com/GEOS-ESM/GEOSldas/pull/703), [PR #723](https://github.com/GEOS-ESM/GEOSldas/pull/723)). - New update_type=13 for ASCAT soil moisture and SMAP brightness temperature assimilation ([PR #703](https://github.com/GEOS-ESM/GEOSldas/pull/703)). - - New update_type=13 replaces update_type=[1,2], which was disabled. + - New update_type=13 replaces update_type=[1,2], which has been disabled. - Requires ASCAT mask file ([PR #723](https://github.com/GEOS-ESM/GEOSldas/pull/723)). - Disabled CatchmentCNCLM45 model option (LSM_CHOICE=3) ([PR #707](https://github.com/GEOS-ESM/GEOSldas/pull/707), [GEOSgcm_GridComp PR #900](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/900)). - Added support for GEOS-IT surface met forcing ([PR #688](https://github.com/GEOS-ESM/GEOSldas/pull/688)). @@ -89,7 +89,7 @@ Overview of Git Releases: - Replace FLAP with fArgParse ([PR #669](https://github.com/GEOS-ESM/GEOSldas/pull/669)). - Documentation: - - Minor updates and corrections. + - Updates and corrections ([PR #728](https://github.com/GEOS-ESM/GEOSldas/pull/728)). - Bug fixes and other minor changes: - Removed requirement for mwRTM parameter input files ([PR #685](https://github.com/GEOS-ESM/GEOSldas/pull/685)). @@ -100,7 +100,7 @@ Overview of Git Releases: - Some cleanup of unused variables ([PR #679](https://github.com/GEOS-ESM/GEOSldas/pull/679)). - Updated met forcing path when coupled with ADAS ([PR #682](https://github.com/GEOS-ESM/GEOSldas/pull/682)). - Added more export variable definitions to tile_bin2nc4.F90 ([PR #676](https://github.com/GEOS-ESM/GEOSldas/pull/676)). - - Fixed LONG_NAME for longwave variables ([PR #674](https://github.com/GEOS-ESM/GEOSldas/pull/674), [GEOSgcm_GridComp PR #764](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/764)). + - Fixed LONG_NAME for longwave radiation variables ([PR #674](https://github.com/GEOS-ESM/GEOSldas/pull/674), [GEOSgcm_GridComp PR #764](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/764)). - Fixed bug in matlab reader MAPL_ReadForcing_fullfile.m ([PR #665](https://github.com/GEOS-ESM/GEOSldas/pull/665)). - Renamed GEOSldas_GridComp/Shared to GEOSldas_GridComp/LDAS_Shared ([PR #714](https://github.com/GEOS-ESM/GEOSldas/pull/714)). From 013598d01071aa6325e33cb56645d5efb65b611f Mon Sep 17 00:00:00 2001 From: Rolf Reichle <54944691+gmao-rreichle@users.noreply.github.com> Date: Wed, 13 Mar 2024 14:24:38 -0400 Subject: [PATCH 287/308] Point to GEOSgcm_GridComp branch with non-0-diff snow model fixes (components.yaml) --- components.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components.yaml b/components.yaml index b5fee251..9ccb6dad 100644 --- a/components.yaml +++ b/components.yaml @@ -49,6 +49,6 @@ MAPL: GEOSgcm_GridComp: local: ./src/Components/GEOSldas_GridComp/@GEOSgcm_GridComp remote: ../GEOSgcm_GridComp.git - branch: develop + branch: bugfix/rreichle/snow_excs sparse: ./config/GEOSgcm_GridComp_ldas.sparse develop: develop From a1b5a3b9bd9ca787924ce41c66f45d8552e83e2f Mon Sep 17 00:00:00 2001 From: Rolf Reichle <54944691+gmao-rreichle@users.noreply.github.com> Date: Thu, 14 Mar 2024 13:16:45 -0400 Subject: [PATCH 288/308] reverting to "develop" branch for GEOSgcm_GridComp (components.yaml) --- components.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components.yaml b/components.yaml index 9ccb6dad..b5fee251 100644 --- a/components.yaml +++ b/components.yaml @@ -49,6 +49,6 @@ MAPL: GEOSgcm_GridComp: local: ./src/Components/GEOSldas_GridComp/@GEOSgcm_GridComp remote: ../GEOSgcm_GridComp.git - branch: bugfix/rreichle/snow_excs + branch: develop sparse: ./config/GEOSgcm_GridComp_ldas.sparse develop: develop From 409cd2cb668477b57ce8df96dfcd4a2a1bf313d2 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Sun, 17 Mar 2024 15:05:28 -0400 Subject: [PATCH 289/308] move lat/lon to grid cell center --- .../LDAS_App/util/inputs/ASCAT_sm_mask/ascat_mask_maker.F90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Applications/LDAS_App/util/inputs/ASCAT_sm_mask/ascat_mask_maker.F90 b/src/Applications/LDAS_App/util/inputs/ASCAT_sm_mask/ascat_mask_maker.F90 index 4d909411..3f0e3c60 100644 --- a/src/Applications/LDAS_App/util/inputs/ASCAT_sm_mask/ascat_mask_maker.F90 +++ b/src/Applications/LDAS_App/util/inputs/ASCAT_sm_mask/ascat_mask_maker.F90 @@ -103,8 +103,8 @@ program ascat_mask_maker allocate(lon(int(360.0 / d_lon))) allocate(lat(int(180.0 / d_lat))) - lon = [(ll_lon + i * d_lon, i = 0, size(lon) - 1)] - lat = [(ll_lat + i * d_lat, i = 0, size(lat) - 1)] + lon = [((ll_lon + (d_lon / 2)) + i * d_lon, i = 0, size(lon) - 1)] + lat = [((ll_lat + (d_lat / 2)) + i * d_lat, i = 0, size(lat) - 1)] allocate(mask_out(size(lon), size(lat))) From 17a3c91f66bd07adaa34e925a83f94b693c3b6d1 Mon Sep 17 00:00:00 2001 From: Matthew Thompson Date: Mon, 18 Mar 2024 14:01:27 -0400 Subject: [PATCH 290/308] Use tempfile for domain def --- src/Applications/LDAS_App/ldas_setup | 235 ++++++++++++++------------- 1 file changed, 119 insertions(+), 116 deletions(-) diff --git a/src/Applications/LDAS_App/ldas_setup b/src/Applications/LDAS_App/ldas_setup index 503d0a70..46145bfc 100755 --- a/src/Applications/LDAS_App/ldas_setup +++ b/src/Applications/LDAS_App/ldas_setup @@ -12,6 +12,7 @@ import time import resource import subprocess as sp import shlex +import tempfile from dateutil import rrule from datetime import datetime from datetime import timedelta @@ -36,10 +37,10 @@ class LDASsetup: # Required exe input fields # These fields are needed to pre-compute exp dir structure # ------ - rqdExeInpKeys = ['EXP_ID', 'EXP_DOMAIN', 'NUM_LDAS_ENSEMBLE', + rqdExeInpKeys = ['EXP_ID', 'EXP_DOMAIN', 'NUM_LDAS_ENSEMBLE', 'BEG_DATE', 'END_DATE','RESTART_PATH', 'RESTART_DOMAIN','RESTART_ID','MET_TAG','MET_PATH','FORCE_DTSTEP','BCS_PATH', 'BCS_RESOLUTION'] - rqdExeInpKeys_rst = ['EXP_ID', 'EXP_DOMAIN', 'NUM_LDAS_ENSEMBLE', + rqdExeInpKeys_rst = ['EXP_ID', 'EXP_DOMAIN', 'NUM_LDAS_ENSEMBLE', 'BEG_DATE', 'END_DATE','MET_TAG','MET_PATH','FORCE_DTSTEP','BCS_PATH', 'BCS_RESOLUTION'] # These keywords are excluded from LDAS.rc (i.e., only needed in pre- or post-processing) @@ -163,7 +164,7 @@ class LDASsetup: assert self.nens>0, 'NUM_LDAS_ENSEMBLE [%d] <= 0' % self.nens _mydir = self.exphome + '/' + self.rqdExeInp['EXP_ID'] assert not os.path.isdir(_mydir), 'Dir [%s] already exists!' % _mydir - _mydir = None + _mydir = None self.ladas_coupling = int(self.rqdExeInp.get('LADAS_COUPLING',0)) if self.ladas_coupling > 0: assert 'ADAS_EXPDIR' in self.rqdExeInp, " need ADAS_EXPDIR in the input file %s" %(self.exeinpfile) @@ -175,7 +176,7 @@ class LDASsetup: self.ensdirs = ['ens%04d'%iens for iens in range(self.first_ens_id, self.nens + self.first_ens_id)] # if self.ens_id_width = 4, _width = '_e%04d' _width = '_e%0{}d'.format(self.ens_id_width-2) - # self.ensids will be a list of [_e0000, _e0001, ...] + # self.ensids will be a list of [_e0000, _e0001, ...] self.ensids = [ _width%iens for iens in range(self.first_ens_id, self.nens + self.first_ens_id)] if (self.nens == 1) : self.ensdirs_avg = self.ensdirs @@ -280,8 +281,8 @@ class LDASsetup: '/output/'+self.rqdExeInp['RESTART_DOMAIN']+'/rc_out/'+self.rqdExeInp['RESTART_ID']+'.ldas_domain.txt' if os.path.isfile(ldas_domain) : _numd = int(linecache.getline(ldas_domain, 1).strip()) - - if _numg != _numd : + + if _numg != _numd : self.rqdExeInp['RST_FROM_GLOBAL'] = 0 self.rqdExeInp['LNFM_FILE'] = '' @@ -321,7 +322,7 @@ class LDASsetup: if len(in_tilefiles_) == 0 : in_tilefiles_ = glob.glob(inpdir+'/*.til') self.in_tilefile =os.path.realpath(in_tilefiles_[0]) - + if os.path.isfile(ldas_domain) : _numd = int(linecache.getline(ldas_domain, 1).strip()) self.rqdExeInp['TILING_FILE'] =glob.glob(self.bcs_geom + '*.til')[0] @@ -333,8 +334,8 @@ class LDASsetup: self.rqdExeInp['LNFM_FILE'] = glob.glob(self.bcs_land + 'lnfm_clim_*.data')[0] self.rqdExeInp['NDVI_FILE'] = glob.glob(self.bcs_land + 'ndvi_clim_*.data')[0] self.rqdExeInp['NIRDF_FILE']= glob.glob(self.bcs_land + 'nirdf_*.dat')[0] - self.rqdExeInp['VISDF_FILE']= glob.glob(self.bcs_land + 'visdf_*.dat')[0] - + self.rqdExeInp['VISDF_FILE']= glob.glob(self.bcs_land + 'visdf_*.dat')[0] + if 'GRIDNAME' not in self.rqdExeInp : tmptile =self.rqdExeInp['TILING_FILE'] self.rqdExeInp['GRIDNAME'] = linecache.getline(tmptile, 3).strip() @@ -356,7 +357,7 @@ class LDASsetup: self.rqdExeInp['LADAS_COUPLING'] = 0 if 'RUN_IRRIG' not in self.rqdExeInp: - self.rqdExeInp['RUN_IRRIG'] = 0 + self.rqdExeInp['RUN_IRRIG'] = 0 if 'AEROSOL_DEPOSITION' not in self.rqdExeInp: self.rqdExeInp['AEROSOL_DEPOSITION'] = 0 @@ -368,21 +369,24 @@ class LDASsetup: _domain_dic['MAXLAT']= 90. _domain_dic['EXCLUDE_FILE']= "''" _domain_dic['INCLUDE_FILE']= "''" - + for key,val in _domain_dic.items() : if key in self.rqdExeInp : _domain_dic[key]= self.rqdExeInp[key] - fout =open('LDAS_domain_def.nml','w') - fout.write('&domain_inputs\n') + # This file is opened in the install/bin directory + # which might not be writable to all users. So + # we instead use a named temporary file + domain_def = tempfile.NamedTemporaryFile(delete=False) + domain_def.write('&domain_inputs\n') for key,val in _domain_dic.items() : keyn=(key+" = ").ljust(16) valn = str(val) if '_FILE' in key: - fout.write(keyn+ "'"+valn+"'"+'\n') + domain_def.write(keyn+ "'"+valn+"'"+'\n') else : - fout.write(keyn+ valn +'\n') - fout.write('/\n') - + domain_def.write(keyn+ valn +'\n') + domain_def.write('/\n') + # make sure bcs files exist if self.rqdExeInp['RESTART'].isdigit() : if int(self.rqdExeInp['RESTART']) >= 1 : @@ -393,18 +397,18 @@ class LDASsetup: tmpRstDir=self.rqdExeInp['RESTART_PATH']+'/'.join([self.rqdExeInp['RESTART_ID'],'output', self.rqdExeInp['RESTART_DOMAIN'],'rs',self.ensdirs[0],y4m2]) catchRstFile=tmpRstDir+'/'+tmpFile - + assert os.path.isfile(catchRstFile), self.catch+'_internal_rst file [%s] does not exist!' %(catchRstFile) self.in_rstfile = catchRstFile - + if int(self.rqdExeInp['RESTART']) == 1 : tmpFile=self.rqdExeInp['RESTART_ID']+'.vegdyn_internal_rst' tmpRstDir=self.rqdExeInp['RESTART_PATH']+'/'.join([self.rqdExeInp['RESTART_ID'],'output', - self.rqdExeInp['RESTART_DOMAIN'],'rs',self.ensdirs[0]]) + self.rqdExeInp['RESTART_DOMAIN'],'rs',self.ensdirs[0]]) vegdynRstFile=tmpRstDir+'/'+tmpFile if not os.path.isfile(vegdynRstFile): assert int(self.rqdExeInp['RST_FROM_GLOBAL']) == 1, 'restart from LDASsa should be global' - + tmpFile=self.rqdExeInp['RESTART_ID']+'.landpert_internal_rst.'+y4m2d2_h2m2 tmpRstDir=self.rqdExeInp['RESTART_PATH']+'/'.join([self.rqdExeInp['RESTART_ID'],'output', self.rqdExeInp['RESTART_DOMAIN'],'rs',self.ensdirs[0],y4m2]) @@ -412,15 +416,15 @@ class LDASsetup: if ( os.path.isfile(landpertRstFile)) : self.has_geos_pert = True - elif (int(self.rqdExeInp['RESTART']) == 0) : + elif (int(self.rqdExeInp['RESTART']) == 0) : if (self.catch == 'catch'): self.in_rstfile = '/discover/nobackup/projects/gmao/ssd/land/l_data/LandRestarts_for_Regridding' \ - '/Catch/M09/20170101/catch_internal_rst' + '/Catch/M09/20170101/catch_internal_rst' self.in_tilefile = '/discover/nobackup/projects/gmao/ssd/land/l_data/geos5/bcs/CLSM_params' \ '/mkCatchParam_SMAP_L4SM_v002/SMAP_EASEv2_M09/SMAP_EASEv2_M09_3856x1624.til' elif (self.catch == 'catchcnclm40'): self.in_rstfile = '/discover/nobackup/projects/gmao/ssd/land/l_data/LandRestarts_for_Regridding' \ - '/CatchCN/M36/20150301_0000/catchcnclm40_internal_dummy' + '/CatchCN/M36/20150301_0000/catchcnclm40_internal_dummy' self.in_tilefile = '/discover/nobackup/projects/gmao/bcs_shared/legacy_bcs/Heracles-NL/SMAP_EASEv2_M36/SMAP_EASEv2_M36_964x406.til' elif (self.catch == 'catchcnclm45'): self.in_rstfile = '/discover/nobackup/projects/gmao/ssd/land/l_data/LandRestarts_for_Regridding' \ @@ -430,7 +434,7 @@ class LDASsetup: sys.exit('need to provide at least dummy files') self.in_rstfile = None self.in_tilefile = None - + # DEAL WITH mwRTM input from exec self.assim = True if self.rqdExeInp.get('LAND_ASSIM', 'NO').upper() == 'YES' else False # verify mwrtm file @@ -441,15 +445,15 @@ class LDASsetup: if os.path.isfile(mwrtm_param_file_) : self.has_mwrtm = True self.mwrtm_file = mwrtm_param_file_ - else : - assert not mwrtm_param_file_.strip(), ' MWRTM_PATH: %s should contain mwRTM_param.nc4'% self.rqdExeInp['MWRTM_PATH'] + else : + assert not mwrtm_param_file_.strip(), ' MWRTM_PATH: %s should contain mwRTM_param.nc4'% self.rqdExeInp['MWRTM_PATH'] del self.rqdExeInp['MWRTM_PATH'] if os.path.isfile(vegopacity_file_) : self.has_vegopacity = True self.rqdExeInp['VEGOPACITY_FILE'] = vegopacity_file_ - + # DEAL WITH optional input from exec - + # ------ # Read rm input file # Read (and pop from inpfile) the input required fields in to @@ -493,7 +497,7 @@ class LDASsetup: _printdict(self.optRmInp) # ------ - # set top level directories + # set top level directories # rundir, inpdir, outdir, blddir # executable # exefyl @@ -531,7 +535,7 @@ class LDASsetup: # default is set to 0 ( no output server) if 'oserver_nodes' not in self.optRmInp : self.optRmInp['oserver_nodes'] = 0 - + self.optRmInp['nodes'] = my_nodes + int(self.optRmInp['oserver_nodes']) if (int(self.optRmInp['oserver_nodes']) >=1) : @@ -541,7 +545,7 @@ class LDASsetup: self.optRmInp['writers-per-node'] = 5 else: self.optRmInp['writers-per-node'] = 0 - + def _parseInputFile(self, inpfile): """ @@ -706,7 +710,7 @@ class LDASsetup: print ('\nCorrect the tile file if it is an old EASE tile format... \n') EASEtile=self.bcsdir+'/MAPL_'+short_tile - cmd = './preprocess_ldas.x correctease '+ tile + ' '+ EASEtile + cmd = './preprocess_ldas.x correctease '+ tile + ' '+ EASEtile if self.BUILT_ON_SLES15 : print ("Executables were built on SLES15 and must be run on SLES15: " + cmd) else: @@ -717,12 +721,11 @@ class LDASsetup: if os.path.isfile(EASEtile) : #update tile file name short_tile ='MAPL_'+short_tile - tile=EASEtile + tile=EASEtile # setup BC files if os.path.isfile('f2g.txt'): os.remove('f2g.txt') - domain_def = 'LDAS_domain_def.nml' catchment_def = self.rqdExeInp['CATCH_DEF_FILE'] exp_id = self.rqdExeInp['EXP_ID'] @@ -735,14 +738,14 @@ class LDASsetup: # These are dummy values for *cold* restart: wemin_in = '13' # WEmin input/output for scale_catch(cn), - wemin_out = '13' # + wemin_out = '13' # if 'WEMIN_IN' in self.rqdExeInp : wemin_in = self.rqdExeInp['WEMIN_IN'] if 'WEMIN_OUT' in self.rqdExeInp : wemin_out = self.rqdExeInp['WEMIN_OUT'] - - cmd = './preprocess_ldas.x c_f2g ' + tile + ' ' + domain_def + ' '+ self.out_path + ' ' + catchment_def + ' ' + exp_id + ' ' + _y4m2d2h2m2 + ' '+ dzsf + + cmd = './preprocess_ldas.x c_f2g ' + tile + ' ' + domain_def.name + ' '+ self.out_path + ' ' + catchment_def + ' ' + exp_id + ' ' + _y4m2d2h2m2 + ' '+ dzsf print ('Creating f2g.txt....\n') print ("cmd: " + cmd) @@ -758,12 +761,12 @@ class LDASsetup: newlocalTile = tile+'.domain' print ("\nCreating local tile file :"+ newlocalTile) print ("\n by excluding land type MAPL_Land_ExcludeFromDomain=1100...\n") - cmd = './preprocess_ldas.x c_localtile ' + tile + ' ' + newlocalTile + cmd = './preprocess_ldas.x c_localtile ' + tile + ' ' + newlocalTile print ("cmd: " + cmd) sp.call(shlex.split(cmd)) short_tile=short_tile +'.domain' tile = newlocalTile - + myTile=self.inpdir+'/tile.data' os.symlink(tile,myTile) @@ -795,7 +798,7 @@ class LDASsetup: # link BC - print ("linking bcs...") + print ("linking bcs...") bcnames=['green','lai','ndvi','nirdf','visdf'] if (self.rqdExeInp['LNFM_FILE'] != ''): bcnames += ['lnfm'] @@ -809,7 +812,7 @@ class LDASsetup: os.symlink(self.bcs_landshared + 'CO2_MonthlyMean_DiurnalCycle.nc4', \ self.inpdir+'/CO2_MonthlyMean_DiurnalCycle.nc4') - # create and link restart + # create and link restart print ("Creating and linking restart...") _start = self.begDates[0] @@ -837,18 +840,18 @@ class LDASsetup: rstid = self.rqdExeInp['RESTART_ID'] rstdomain = self.rqdExeInp['RESTART_DOMAIN'] rstpath0 = self.rqdExeInp['RESTART_PATH'] - + # just copy the landassim pert seed if it exists for iens in range(self.nens) : _ensdir = self.ensdirs[iens] _ensid = self.ensids[iens] landassim_seeds = rstpath + _ensdir + '/' + y4m2+'/' + rstid + '.landassim_obspertrseed_rst.'+y4m2d2_h2m2 if os.path.isfile(landassim_seeds) and self.assim : - _seeds = self.rstdir + _ensdir + '/' + y4m2+'/' + exp_id + '.landassim_obspertrseed_rst.'+y4m2d2_h2m2 + _seeds = self.rstdir + _ensdir + '/' + y4m2+'/' + exp_id + '.landassim_obspertrseed_rst.'+y4m2d2_h2m2 shutil.copy(landassim_seeds, _seeds) os.symlink(_seeds, myRstDir+ '/landassim_obspertrseed'+ _ensid +'_rst') self.has_landassim_seed = True - mk_outdir = self.exphome+'/'+exp_id+'/mk_restarts/' + mk_outdir = self.exphome+'/'+exp_id+'/mk_restarts/' if (RESTART_str != '1'): bcs_path = self.rqdExeInp['BCS_PATH'] @@ -859,8 +862,8 @@ class LDASsetup: remap_tpl = os.path.dirname(os.path.realpath(__file__)) + '/remap_params.tpl' config = yaml_to_config(remap_tpl) - config['slurm']['account'] = self.rqdRmInp['account'] - config['slurm']['qos'] = 'debug' + config['slurm']['account'] = self.rqdRmInp['account'] + config['slurm']['qos'] = 'debug' config['input']['surface']['catch_tilefile'] = self.in_tilefile config['input']['shared']['expid'] = self.rqdExeInp['RESTART_ID'] @@ -875,12 +878,12 @@ class LDASsetup: config['output']['shared']['bc_base'] = bc_base config['output']['shared']['bc_version'] = bc_version config['output']['surface']['EASE_grid'] = self.rqdExeInp['BCS_RESOLUTION'] - + config['output']['shared']['expid'] = self.rqdExeInp['EXP_ID'] config['output']['surface']['surflay'] = dzsf config['output']['surface']['wemin'] = wemin_out - config = remap_config_ldas( config, RESTART_str, self.rqdExeInp['RESTART_PATH'], self.rqdExeInp['RESTART_ID']) + config = remap_config_ldas( config, RESTART_str, self.rqdExeInp['RESTART_PATH'], self.rqdExeInp['RESTART_ID']) catch_obj = catchANDcn(config_obj = config) catch_obj.remap() @@ -920,7 +923,7 @@ class LDASsetup: catchLocal = self.rstdir+ensdir +'/'+ y4m2+'/'+self.rqdExeInp['EXP_ID']+'.'+self.catch+'_internal_rst.'+y4m2d2_h2m2 if self.islocal : print( "Creating local catchment restart file... \n") - cmd='./preprocess_ldas.x c_localcatchrst '+ catchRstFile +' ' + catchLocal + cmd='./preprocess_ldas.x c_localcatchrst '+ catchRstFile +' ' + catchLocal print ("cmd: "+cmd) sp.call(shlex.split(cmd)) else : @@ -930,7 +933,7 @@ class LDASsetup: if '0000' in ensdir : catchRstFile0 = catchRstFile - else : # re-use 0000 catch file + else : # re-use 0000 catch file catchRstFile = catchRstFile0 # vegdyn restart file @@ -938,7 +941,7 @@ class LDASsetup: vegdynLocal = self.rstdir+ensdir +'/'+self.rqdExeInp['EXP_ID']+'.vegdyn_internal_rst' if self.islocal : print ("Creating the local veg restart file... \n") - cmd='./preprocess_ldas.x c_localvegrst '+ vegdynRstFile +' ' + vegdynLocal + cmd='./preprocess_ldas.x c_localvegrst '+ vegdynRstFile +' ' + vegdynLocal print ("cmd: " + cmd) sp.call(shlex.split(cmd)) else : @@ -948,7 +951,7 @@ class LDASsetup: if '0000' in ensdir : vegdynRstFile0 = vegdynRstFile - else : + else : vegdynRstFile = vegdynRstFile0 if (self.has_geos_pert and self.perturb == 1) : @@ -973,7 +976,7 @@ class LDASsetup: mwRTMLocal = self.bcsdir+'/'+ y4m2+'/'+self.rqdExeInp['EXP_ID']+'.ldas_mwRTMparam.'+y4m2d2_h2m2+'z.nc4' if self.islocal : print ("Creating the local mwRTM restart file... \n") - cmd='./preprocess_ldas.x c_localmwrtmrst '+ mwRTMRstFile +' ' + mwRTMLocal + cmd='./preprocess_ldas.x c_localmwrtmrst '+ mwRTMRstFile +' ' + mwRTMLocal print ("cmd: " + cmd) sp.call(shlex.split(cmd)) else : @@ -988,7 +991,7 @@ class LDASsetup: self.rqdExeInp['RESTART_PATH'] = myRstDir if os.path.isfile('f2g.txt'): os.remove('f2g.txt') - + status = True return status @@ -1044,7 +1047,7 @@ class LDASsetup: # get optimzed NX and IMS if os.path.isfile('optimized_distribution'): os.remove('optimized_distribution') - + print ("Optimizing... decomposition of processes.... \n") cmd = './preprocess_ldas.x optimize '+ self.inpdir+'/tile.data '+ str(self.rqdRmInp['ntasks_model']) print ("cmd: " + cmd) @@ -1054,12 +1057,12 @@ class LDASsetup: if int(optinxny['NY']) != int(self.rqdRmInp['ntasks_model']): self.rqdRmInp['ntasks_model']=optinxny['NY'] print ('adjust ntasks_model %d for cubed-sphere grid' % int(self.rqdRmInp['ntasks_model'])) - + if os.path.isfile('IMS.rc') : shutil.move('IMS.rc', self.rundir+'/') if os.path.isfile('JMS.rc') : shutil.move('JMS.rc', self.rundir+'/') - + os.remove('optimized_distribution') # DEFAULT rc files @@ -1094,17 +1097,17 @@ class LDASsetup: ' ' + GRID + ' ' + str(self.rqdExeInp['RUN_IRRIG']) + ' ' + _assim + ' '+ str(self.nens) print(cmd) #os.system(cmd) - sp.call(shlex.split(cmd)) + sp.call(shlex.split(cmd)) for line in fileinput.input(tmprcfile,inplace=True): print (line.rstrip().replace('GEOSldas_expid',self.rqdExeInp['EXP_ID'])) # just copy an empty ExtData.rc if shortfile=='ExtData.rc' : shutil.copy2(rcfile, self.rundir+'/'+shortfile) - - if shortfile == 'CAP.rc': + + if shortfile == 'CAP.rc': tmprcfile = self.rundir+'/CAP.rc' shutil.copy2(rcfile,tmprcfile) - + _num_sgmt = int(self.rqdExeInp['NUM_SGMT']) for line in fileinput.input(tmprcfile,inplace=True): @@ -1115,15 +1118,15 @@ class LDASsetup: print (line.rstrip().replace('BEG_DATE:',self.begDates[0].strftime('BEG_DATE: %Y%m%d %H%M%S'))) for line in fileinput.input(tmprcfile,inplace=True): print (line.rstrip().replace('END_DATE:',self.endDates[-1].strftime('END_DATE: %Y%m%d %H%M%S'))) - + if shortfile == 'LDAS.rc' : ldasrcInp = OrderedDict() - # land default + # land default default_surfrcInp = self._parseInputFile(etcdir+'/GEOS_SurfaceGridComp.rc') for key,val in default_surfrcInp.items() : ldasrcInp[key] = val - # ldas default, may overwrite land default + # ldas default, may overwrite land default default_ldasrcInp = self._parseInputFile(rcfile) for key,val in default_ldasrcInp.items() : ldasrcInp[key] = val @@ -1140,7 +1143,7 @@ class LDASsetup: # create BC in rc file tmpl_ = '' if self.nens >1 : - tmpl_='%s' + tmpl_='%s' if self.perturb == 1: ldasrcInp['PERTURBATIONS'] ='1' bcval=['../input/green','../input/lai','../input/lnfm','../input/ndvi','../input/nirdf','../input/visdf'] @@ -1164,15 +1167,15 @@ class LDASsetup: if 'VEGDYN_INTERNAL_RESTART_TYPE' in ldasrcInp : # avoid duplicate del ldasrcInp['VEGDYN_INTERNAL_RESTART_TYPE'] - + rstkey=[catch_,'VEGDYN'] rstval=[self.catch,'vegdyn'] - if self.has_mwrtm : + if self.has_mwrtm : keyn='LANDASSIM_INTERNAL_RESTART_FILE' valn='../input/restart/mwrtm_param_rst' ldasrcInp[keyn]= valn - if self.has_vegopacity : + if self.has_vegopacity : keyn='VEGOPACITY_FILE' valn='../input/vegopacity.data' ldasrcInp[keyn]= valn @@ -1187,16 +1190,16 @@ class LDASsetup: valn='../input/restart/landassim_obspertrseed'+tmpl_+'_rst' ldasrcInp[keyn]= valn - if self.assim: + if self.assim: keyn='LANDASSIM_OBSPERTRSEED_CHECKPOINT_FILE' valn='landassim_obspertrseed'+tmpl_+'_checkpoint' ldasrcInp[keyn]= valn - + for key,val in zip(rstkey,rstval) : keyn = key+ '_INTERNAL_RESTART_FILE' valn = '../input/restart/'+val+tmpl_+'_internal_rst' ldasrcInp[keyn]= valn - + # checkpoint file and its type keyn = catch_ + '_INTERNAL_CHECKPOINT_FILE' valn = self.catch+tmpl_+'_internal_checkpoint' @@ -1208,12 +1211,12 @@ class LDASsetup: valn = '../input/restart/landpert'+tmpl_+'_internal_rst' ldasrcInp[keyn]= valn # for lat/lon and EASE tile space, specify LANDPERT checkpoint file here (via MAPL); - # for cube-sphere tile space, Landpert GC will set up LANDPERT checkpoint file + # for cube-sphere tile space, Landpert GC will set up LANDPERT checkpoint file if ('-CF' not in self.rqdExeInp['GRIDNAME']): keyn = 'LANDPERT_INTERNAL_CHECKPOINT_FILE' valn = 'landpert'+tmpl_+'_internal_checkpoint' ldasrcInp[keyn]= valn - + # write LDAS.rc fout =open(self.rundir+'/'+shortfile,'w') # ldasrcInp['NUM_LDAS_ENSEMBLE']=ldasrcInp.pop('NUM_ENSEMBLE') @@ -1227,9 +1230,9 @@ class LDASsetup: fout.write("EXP_ID:".ljust(36)+self.rqdExeInp['EXP_ID']+'\n') fout.write("TILING_FILE:".ljust(36)+"../input/tile.data\n") - fout.close() + fout.close() - fout=open(self.rundir+'/'+'cap_restart','w') + fout=open(self.rundir+'/'+'cap_restart','w') #fout.write(self.rqdExeInp['BEG_DATE']) fout.write(self.begDates[0].strftime('%Y%m%d %H%M%S')) fout.close() @@ -1287,7 +1290,7 @@ class LDASsetup: fout.write("\nsed -i 's/#if($capdate<$enddate) "+SBATCHQSUB+"/if($capdate<$enddate) "+SBATCHQSUB+"/g' lenkf.j\n\n") fout.close() - sp.call(['chmod', '755', self.rundir+'/ldas_batchrun.j']) + sp.call(['chmod', '755', self.rundir+'/ldas_batchrun.j']) status = True return status @@ -1359,13 +1362,13 @@ class LDASsetup: line_ = line_.replace('MY_NTASKS_PER_NODE',str(self.rqdRmInp['ntasks-per-node'])) line_ = line_.replace('MY_CONSTRAINT', 'cas_ait') fout.write(line_) - if self.GEOS_SITE == "NCCS" : + if self.GEOS_SITE == "NCCS" : if self.BUILT_ON_SLES15 : fout.write("#SBATCH --constraint=mil\n") else: assert int(self.rqdRmInp['ntasks-per-node']) <= 46, 'ntasks-per-node should be <=46 for cas' fout.write("#SBATCH --constraint=cas\n") - + elif 'MY_OSERVER_NODES' in line : fout.write(line.replace('MY_OSERVER_NODES',str(self.optRmInp['oserver_nodes']))) elif 'MY_WRITERS_NPES' in line : @@ -1386,7 +1389,7 @@ class LDASsetup: elif 'MY_MODEL' in line : fout.write(line.replace('MY_MODEL',self.catch)) elif 'MY_POSTPROC_HIST' in line : - fout.write(line.replace('MY_POSTPROC_HIST',str(self.rqdExeInp['POSTPROC_HIST']))) + fout.write(line.replace('MY_POSTPROC_HIST',str(self.rqdExeInp['POSTPROC_HIST']))) elif 'MY_FIRST_ENS_ID' in line : fout.write(line.replace('MY_FIRST_ENS_ID',str(self.first_ens_id))) elif 'MY_LADAS_COUPLING' in line : @@ -1398,8 +1401,8 @@ class LDASsetup: fout.write(line.replace('MY_ADAS_EXPDIR', self.rqdExeInp['ADAS_EXPDIR'])) else : fout.write(line.replace('MY_EXPDIR',self.exphome+'/$EXPID')) - - sp.call(['chmod', '755', 'lenkf.j']) + + sp.call(['chmod', '755', 'lenkf.j']) expdir = '/'.join(self.rundir.rstrip('/').split('/')[:-1]) print ('\nExperiment directory: %s' % expdir) @@ -1420,7 +1423,7 @@ def _printExeInputKeys(rqdExeInpKeys): Private method: print sample exe input """ - print ('####################################################################################') + print ('####################################################################################') print ('# #') print ('# REQUIRED INPUTS #') print ('# #') @@ -1428,7 +1431,7 @@ def _printExeInputKeys(rqdExeInpKeys): print ('# #') print ('####################################################################################') print () - print ('############################################################') + print ('############################################################') print ('# #') print ('# EXPERIMENT INFO #') print ('# #') @@ -1449,14 +1452,14 @@ def _printExeInputKeys(rqdExeInpKeys): print ('# (i) Select "RESTART" option: #') print ('# #') print ('# Use one of the following options if you *have* a #') - print ('# GEOSldas restart file: #') + print ('# GEOSldas restart file: #') print ('# #') print ('# RESTART: 1 #') print ('# YES, have restart file from GEOSldas #') print ('# in SAME tile space (grid) with SAME boundary #') print ('# conditions and SAME snow model parameter (WEMIN). #') print ('# The restart domain can be for the same or #') - print ('# a larger one. #') + print ('# a larger one. #') print ('# #') print ('# RESTART: 2 #') print ('# YES, have restart file from GEOSldas but #') @@ -1466,17 +1469,17 @@ def _printExeInputKeys(rqdExeInpKeys): print ('# Restart *must* be for the GLOBAL domain. #') print ('# #') print ('# Use one of the following options if you DO NOT have a #') - print ('# GEOSldas restart file #') + print ('# GEOSldas restart file #') print ('# (works for global domain ONLY!): #') print ('# #') print ('# RESTART: 0 #') print ('# Cold start from some old restart for Jan 1, 0z. #') print ('# #') print ('# RESTART: M #') - print ('# Re-tile from archived MERRA-2 restart file. #') + print ('# Re-tile from archived MERRA-2 restart file. #') print ('# #') print ('# RESTART: F #') - print ('# Re-tile from FP (Forward Processing) restart file. #') + print ('# Re-tile from FP (Forward Processing) restart file. #') print ('# #') print ('# RESTART: G #') print ('# Re-tile from any AGCM catch[cnclmxx]_internal_rst file.#') @@ -1486,19 +1489,19 @@ def _printExeInputKeys(rqdExeInpKeys): print ('# Except for RESTART=1, SPIN-UP is REQUIRED in almost #') print ('# all cases. #') print ('# -------------------------------------------------------- #') - print ('# #') - print ('# #') + print ('# #') + print ('# #') print ('# (ii) Specify experiment ID/location of restart file: #') print ('# #') print ('# For RESTART=1 or RESTART=2: #') print ('# Specify RESTART_ID, RESTART_PATH, RESTART_DOMAIN with #') print ('# restarts stored as follows: #') print ('# RESTART_PATH/RESTART_ID/output/RESTART_DOMAIN/rs/ #') - print ('# #') + print ('# #') print ('# For RESTART=0 or RESTART=M or RESTART=F: #') print ('# There is no need to specify RESTART_ID, RESTART_PATH, #') print ('# and RESTART_DOMAIN. #') - print ('# #') + print ('# #') print ('# For RESTART=G: #') print ('# RESTART_ID : full_path_to_AGCM_experiment_directory #') print ('# RESTART_PATH : full_path_of_the_AGCM_restart_file #') @@ -1519,7 +1522,7 @@ def _printExeInputKeys(rqdExeInpKeys): print ('# #') print ('# For more information, see: #') print ('# GEOSldas/doc/README.MetForcing_and_BCS.md #') - print ('# #') + print ('# #') print ('############################################################') print () print ('MET_TAG:') @@ -1549,26 +1552,26 @@ def _printExeInputKeys(rqdExeInpKeys): print ('# #') print ('# 0 -- LDAS not coupled with ADAS (default) #') print ('# 1 -- LDAS coupled with central member of ADAS #') - print ('# 2 -- LDAS coupled with ens component of ADAS #') - print ('# #') + print ('# 2 -- LDAS coupled with ens component of ADAS #') + print ('# #') print ('# Requirements for LADAS_COUPLING > 0: #') - print ('# #') + print ('# #') print ('# (0) Specify ADAS_EXPDIR = [full_path]/[ADAS_EXPID] #') print ('# #') print ('# (1) BEG_DATE must be consistent with first cycle date #') print ('# and time of ADAS experiment (time is typically #') print ('# 3z, 9z, 15z, or 21z) #') - print ('# #') + print ('# #') print ('# (2) EXP_DOMAIN must be global CS grid as in ADAS exp #') print ('# #') print ('# (3) MET_TAG must be set to [ADAS_EXPID]__Nx+- #') print ('# MET_PATH must be set as follows for #') - print ('# LADAS_COUPLING = 1: #') - print ('# [full_path]/[LDAS_EXPID]/scratch/ #') - print ('# LADAS_COUPLING = 2: #') + print ('# LADAS_COUPLING = 1: #') + print ('# [full_path]/[LDAS_EXPID]/scratch/ #') + print ('# LADAS_COUPLING = 2: #') print ('# [ADAS_EXPDIR]/atmens/ensdiag/forc #') - print ('# After ldas exp setup, verify the following link: #') - print ('# ../input/met_forcing/forc -> [MET_PATH] #') + print ('# After ldas exp setup, verify the following link: #') + print ('# ../input/met_forcing/forc -> [MET_PATH] #') print ('# #') print ('# (4) BCS_PATH must be consistent with that of #') print ('# [ADAS_EXPDIR][/run/lnbcs #') @@ -1582,7 +1585,7 @@ def _printExeInputKeys(rqdExeInpKeys): print ('# - instantaneous "catch_progn_incr" must be in #') print ('# HISTORY collection #') print ('# - time step must match that of LDAS analysis #') - print ('# - for LADAS_COUPLING=2, HISTORY must include #') + print ('# - for LADAS_COUPLING=2, HISTORY must include #') print ('# "catch_progn_incr[ENS_INDEX]" #') print ('# #') print ('############################################################') @@ -1622,12 +1625,12 @@ def _printExeInputKeys(rqdExeInpKeys): i_ += 1 print () print () - + def _printRmInputKeys(rqdRmInpKeys, optRmInpKeys): """ Private method: print sample resource manager input """ - + print ('#') print ('# REQUIRED inputs') print ('#') @@ -1656,7 +1659,7 @@ def _printRmInputKeys(rqdRmInpKeys, optRmInpKeys): print ('#') for key in optRmInpKeys: print ('#'+key + ':') - + def parseCmdLine(): """ parse command line arguments and return a dict of options @@ -1674,14 +1677,14 @@ def parseCmdLine(): # subparser: sample command p_sample = p_sub.add_parser( - 'sample', + 'sample', help='write sample input files', description='Print sample input files - either for the '\ 'Fortran executable or the resource manager (SLURM)', ) group = p_sample.add_mutually_exclusive_group(required=True) group.add_argument( - '--exeinp', + '--exeinp', help='print sample input file used to generate RC files for GEOSldas App.', action='store_true', ) @@ -1692,25 +1695,25 @@ def parseCmdLine(): ) # subparser: setup command p_setup = p_sub.add_parser( - 'setup', + 'setup', help='setup LDAS experiment', description="The 'setup' sub-command is used to setup a GEOSldas " \ "experiment. The positional argument 'exphome' is used to create " \ "work_path (exphome+/output) and run_path (exphome+/run)." ) p_setup.add_argument( - '-v', - '--verbose', - help='verbose output', + '-v', + '--verbose', + help='verbose output', action='store_true', ) p_setup.add_argument('exphome', help='experiment location') p_setup.add_argument( - 'exeinpfile', + 'exeinpfile', help='input file with arguments used to generate RC files for GEOSldas App', ) p_setup.add_argument( - 'batinpfile', + 'batinpfile', help='input file with arguments for SLURM', ) p_setup.add_argument( @@ -1746,7 +1749,7 @@ if __name__=='__main__': #print "reading params...." args = vars(parseCmdLine()) # vars converts to dict ld = LDASsetup(args) - + print ("creating dir structure") status = ld.createDirStructure() assert(status) From d9fdcdee2d41ef71a4db7fe7f0b231bc30844754 Mon Sep 17 00:00:00 2001 From: Matthew Thompson Date: Mon, 18 Mar 2024 14:02:24 -0400 Subject: [PATCH 291/308] Close the file --- src/Applications/LDAS_App/ldas_setup | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Applications/LDAS_App/ldas_setup b/src/Applications/LDAS_App/ldas_setup index 46145bfc..07edb3d1 100755 --- a/src/Applications/LDAS_App/ldas_setup +++ b/src/Applications/LDAS_App/ldas_setup @@ -373,9 +373,6 @@ class LDASsetup: for key,val in _domain_dic.items() : if key in self.rqdExeInp : _domain_dic[key]= self.rqdExeInp[key] - # This file is opened in the install/bin directory - # which might not be writable to all users. So - # we instead use a named temporary file domain_def = tempfile.NamedTemporaryFile(delete=False) domain_def.write('&domain_inputs\n') for key,val in _domain_dic.items() : @@ -755,6 +752,7 @@ class LDASsetup: head=[next(f2gfile) for x in range(2)] if(head[0].strip() != head[1].strip()) : self.islocal= True + domain_def.close() # update tile domain if self.islocal: From eae930be0630992182c0063c1994fb61f05efe34 Mon Sep 17 00:00:00 2001 From: Matthew Thompson Date: Mon, 18 Mar 2024 14:09:03 -0400 Subject: [PATCH 292/308] Use os.remove --- src/Applications/LDAS_App/ldas_setup | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Applications/LDAS_App/ldas_setup b/src/Applications/LDAS_App/ldas_setup index 07edb3d1..71199157 100755 --- a/src/Applications/LDAS_App/ldas_setup +++ b/src/Applications/LDAS_App/ldas_setup @@ -373,7 +373,7 @@ class LDASsetup: for key,val in _domain_dic.items() : if key in self.rqdExeInp : _domain_dic[key]= self.rqdExeInp[key] - domain_def = tempfile.NamedTemporaryFile(delete=False) + domain_def = tempfile.NamedTemporaryFile(mode='w', delete=False) domain_def.write('&domain_inputs\n') for key,val in _domain_dic.items() : keyn=(key+" = ").ljust(16) @@ -383,6 +383,7 @@ class LDASsetup: else : domain_def.write(keyn+ valn +'\n') domain_def.write('/\n') + domain_def.close() # make sure bcs files exist if self.rqdExeInp['RESTART'].isdigit() : @@ -752,7 +753,7 @@ class LDASsetup: head=[next(f2gfile) for x in range(2)] if(head[0].strip() != head[1].strip()) : self.islocal= True - domain_def.close() + os.remove(domain_def.name) # update tile domain if self.islocal: From 4d90892b0774d9b803336ea293ee2a903bcd6c7d Mon Sep 17 00:00:00 2001 From: Matthew Thompson Date: Mon, 18 Mar 2024 16:24:25 -0400 Subject: [PATCH 293/308] Fix binary + bit shaving bug --- components.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components.yaml b/components.yaml index 9ccb6dad..4c394cfa 100644 --- a/components.yaml +++ b/components.yaml @@ -43,7 +43,7 @@ GEOS_Util: MAPL: local: ./src/Shared/@MAPL remote: ../MAPL.git - tag: v2.44.0 + branch: hotfix/bmauer/fixes-#2657 develop: develop GEOSgcm_GridComp: From e0f3655c4de9e80aded7659b7649a14053ff8934 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Mon, 18 Mar 2024 16:15:58 -0600 Subject: [PATCH 294/308] add combination choices --- .../inputs/ASCAT_sm_mask/ascat_mask_maker.F90 | 61 +++++++++++++++---- 1 file changed, 49 insertions(+), 12 deletions(-) diff --git a/src/Applications/LDAS_App/util/inputs/ASCAT_sm_mask/ascat_mask_maker.F90 b/src/Applications/LDAS_App/util/inputs/ASCAT_sm_mask/ascat_mask_maker.F90 index 3f0e3c60..a67e1803 100644 --- a/src/Applications/LDAS_App/util/inputs/ASCAT_sm_mask/ascat_mask_maker.F90 +++ b/src/Applications/LDAS_App/util/inputs/ASCAT_sm_mask/ascat_mask_maker.F90 @@ -16,7 +16,7 @@ program ascat_mask_maker implicit none integer :: ncid, varid, dimid, ierr, len, N_gpi, dimids(2) - integer :: i, j, closest_index + integer :: i, j, closest_index, mask_mode integer, dimension(:), allocatable :: cold_mask, wet_mask, veg_mask, subsurface_mask, combined_mask integer(kind=1), dimension(:,:), allocatable :: mask_out @@ -26,7 +26,7 @@ program ascat_mask_maker real, dimension(:), allocatable :: lon, lat, distances real :: d_lon, d_lat, ll_lon, ll_lat - character(400) :: fname_in + character(200) :: fname_in, mask_description, fname_out ! -------------------------------------------------------------------------------- ! @@ -34,8 +34,16 @@ program ascat_mask_maker ! ASCAT soil moisture mask file from Lindorfer et al 2023 - fname_in = '/discover/nobackup/amfox/subsurface_scattering_ASCAT_ERA5_Land.nc' + fname_in = '/discover/nobackup/amfox/subsurface_scattering_ASCAT_ERA5_Land.nc' + ! Specification of how to combine the masks + ! Mask_mode = 1 (default) combines subsurface and wetland masks + ! Mask_mode = 2 uses only the subsurface mask + ! Mask_mode = 3 uses only the wetland mask + ! Mask_mode = 4 combines subsurface, wetland and vegetation masks + + mask_mode = 1 + ! Specification of output grid and missing value d_lon = 0.1 @@ -44,6 +52,9 @@ program ascat_mask_maker ll_lat = -90.0 missing_value = -128 + + ! Specify the NetCDF file name for the output mask + fname_out = 'ascat_combined_mask_p1.nc' ! ------------------------------- @@ -92,18 +103,39 @@ program ascat_mask_maker if (ierr /= nf90_noerr) stop 'Error closing file' ! Combine the masks (1-dim arrays) - where (wet_mask == 1) - combined_mask = 1 - elsewhere - combined_mask = subsurface_mask - end where + select case (mask_mode) + case (1) + ! Combine wet_mask and subsurface_mask + mask_description = 'Combined subsurface and wetland mask' + where (wet_mask == 1) + combined_mask = 1 + elsewhere + combined_mask = subsurface_mask + end where + case (2) + ! Use only subsurface_mask + mask_description = 'Used only subsurface mask' + combined_mask = subsurface_mask + case (3) + ! Use only wet_mask + mask_description = 'Used only wetland mask' + combined_mask = wet_mask + case (4) + ! Combine subsurface_mask, wet_mask, and veg_mask + mask_description = 'Combined subsurface, wetland, and vegetation mask' + where (wet_mask == 1 .or. veg_mask == 1) + combined_mask = 1 + elsewhere + combined_mask = subsurface_mask + end where + end select ! Re-map "combined_mask" from WARP5 input grid to regular lat/lon output grid (2-dim array) allocate(lon(int(360.0 / d_lon))) allocate(lat(int(180.0 / d_lat))) - lon = [((ll_lon + (d_lon / 2)) + i * d_lon, i = 0, size(lon) - 1)] + lon = [((ll_lon + (d_lon / 2)) + i * d_lon, i = 0, size(lon) - 1)] ! NB using grid cell centers for nearest neighbor search lat = [((ll_lat + (d_lat / 2)) + i * d_lat, i = 0, size(lat) - 1)] allocate(mask_out(size(lon), size(lat))) @@ -124,23 +156,28 @@ program ascat_mask_maker end do ! Write out the mask to netcdf - ierr = nf90_create('ascat_combined_mask_p1.nc', nf90_clobber, ncid) + ierr = nf90_create(fname_out, nf90_clobber, ncid) if (ierr /= nf90_noerr) stop 'Error creating file' ! Define the dimensions ierr = nf90_def_dim(ncid, 'lon', size(lon), dimids(1)) ierr = nf90_def_dim(ncid, 'lat', size(lat), dimids(2)) + ! Define the global attributes + ierr = nf90_put_att(ncid, nf90_global, 'title', 'ASCAT combined mask') + ierr = nf90_put_att(ncid, nf90_global, 'source', 'Lindorfer et al 2023') + ierr = nf90_put_att(ncid, nf90_global, 'description', mask_description) + ! Define the variables ierr = nf90_def_var(ncid, 'lat', nf90_real, dimids(2), varid) ierr = nf90_put_att(ncid, varid, 'standard_name', 'latitude') - ierr = nf90_put_att(ncid, varid, 'long_name', 'latitude') + ierr = nf90_put_att(ncid, varid, 'long_name', 'grid cell center latitude') ierr = nf90_put_att(ncid, varid, 'units', 'degrees_north') ierr = nf90_put_att(ncid, varid, 'axis', 'Y') ierr = nf90_def_var(ncid, 'lon', nf90_real, dimids(1), varid) ierr = nf90_put_att(ncid, varid, 'standard_name', 'longitude') - ierr = nf90_put_att(ncid, varid, 'long_name', 'longitude') + ierr = nf90_put_att(ncid, varid, 'long_name', 'grid cell center longitude') ierr = nf90_put_att(ncid, varid, 'units', 'degrees_east') ierr = nf90_put_att(ncid, varid, 'axis', 'X') From 5805a55f9b74e299880bd7deff97fddfa958a3c7 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Tue, 19 Mar 2024 11:44:59 -0400 Subject: [PATCH 295/308] additional cleanup and documentation of ascat_mask_maker.F90: - clarified comments and error messages - change "== 1" to "/= 0" for consistency with ASCAT EUMETSAT reader - avoid repeated allocate/deallocate within i,j loop - use nint() to avoid risky integer division when calculating N_lon, N_lat --- .../inputs/ASCAT_sm_mask/ascat_mask_maker.F90 | 53 ++++++++++--------- 1 file changed, 29 insertions(+), 24 deletions(-) diff --git a/src/Applications/LDAS_App/util/inputs/ASCAT_sm_mask/ascat_mask_maker.F90 b/src/Applications/LDAS_App/util/inputs/ASCAT_sm_mask/ascat_mask_maker.F90 index a67e1803..83760b65 100644 --- a/src/Applications/LDAS_App/util/inputs/ASCAT_sm_mask/ascat_mask_maker.F90 +++ b/src/Applications/LDAS_App/util/inputs/ASCAT_sm_mask/ascat_mask_maker.F90 @@ -1,9 +1,11 @@ -! This program reads in a NetCDF file containing ASCAT soil moisture masks available from: +! This program produces a combined mask for use with the assimilation of ASCAT soil moisture retrievals in GEOSldas. +! The combined mask is based on component masks from: +! ! Lindorfer, R., Wagner, W., Hahn, S., Kim, H., Vreugdenhil, M., Gruber, A., Fischer, M., & Trnka, M. (2023). ! Global Scale Maps of Subsurface Scattering Signals Impacting ASCAT Soil Moisture Retrievals (1.0.0) [Data set]. ! TU Wien. https://doi.org/10.48436/9a2y9-e5z14 ! -! It provides the possibility to combine different masks (default case is combination of subsurface and wetland masks) +! The program provides the possibility to combine different masks (default is combination of subsurface and wetland masks) ! and interpolates onto a regular grid with a (hardwired) 0.1 degree lat/lon spacing and -90/-180 degree lower left ! corner used for quick indexing in the ASCAT observation reader QC routine. ! @@ -15,7 +17,7 @@ program ascat_mask_maker implicit none - integer :: ncid, varid, dimid, ierr, len, N_gpi, dimids(2) + integer :: ncid, varid, dimid, ierr, len, N_gpi, dimids(2), N_lon, N_lat integer :: i, j, closest_index, mask_mode integer, dimension(:), allocatable :: cold_mask, wet_mask, veg_mask, subsurface_mask, combined_mask @@ -48,19 +50,20 @@ program ascat_mask_maker d_lon = 0.1 d_lat = 0.1 - ll_lon = -180.0 - ll_lat = -90.0 + ll_lon = -180.0 ! longitude of boundary of lower-left grid cell (longitude of lower left corner of grid) + ll_lat = -90.0 ! latitude of boundary of lower-left grid cell (latitude of lower left corner of grid) missing_value = -128 ! Specify the NetCDF file name for the output mask + fname_out = 'ascat_combined_mask_p1.nc' ! ------------------------------- - ! Open the NetCDF file + ! Open the NetCDF input file ierr = nf90_open(fname_in, nf90_nowrite, ncid) - if (ierr /= nf90_noerr) stop 'Error opening file' + if (ierr /= nf90_noerr) stop 'Error opening file: ' // trim(fname_in) ! Data in original mask file are on the 12.5 km fixed Earth grid used for ASCAT (WARP5 grid) and ! stored in the NetCDF file as 1-dimensional arrays of length N_gpi (over land only). @@ -83,6 +86,7 @@ program ascat_mask_maker allocate(veg_mask( N_gpi)) allocate(subsurface_mask(N_gpi)) allocate(combined_mask( N_gpi)) + allocate(distances( N_gpi)) ! Get the variable IDs and read the variables ierr = nf90_inq_varid(ncid, 'lon', varid) @@ -107,7 +111,7 @@ program ascat_mask_maker case (1) ! Combine wet_mask and subsurface_mask mask_description = 'Combined subsurface and wetland mask' - where (wet_mask == 1) + where (wet_mask /= 0) combined_mask = 1 elsewhere combined_mask = subsurface_mask @@ -123,7 +127,7 @@ program ascat_mask_maker case (4) ! Combine subsurface_mask, wet_mask, and veg_mask mask_description = 'Combined subsurface, wetland, and vegetation mask' - where (wet_mask == 1 .or. veg_mask == 1) + where (wet_mask /= 0 .or. veg_mask /= 0) combined_mask = 1 elsewhere combined_mask = subsurface_mask @@ -132,40 +136,41 @@ program ascat_mask_maker ! Re-map "combined_mask" from WARP5 input grid to regular lat/lon output grid (2-dim array) - allocate(lon(int(360.0 / d_lon))) - allocate(lat(int(180.0 / d_lat))) + N_lon = nint( 360.0 / d_lon ) + N_lat = nint( 180.0 / d_lat ) + + allocate(lon(N_lon)) + allocate(lat(N_lat)) - lon = [((ll_lon + (d_lon / 2)) + i * d_lon, i = 0, size(lon) - 1)] ! NB using grid cell centers for nearest neighbor search - lat = [((ll_lat + (d_lat / 2)) + i * d_lat, i = 0, size(lat) - 1)] + lon = [((ll_lon + (d_lon / 2)) + i * d_lon, i = 0, N_lon - 1)] ! NB using grid cell centers for nearest neighbor search + lat = [((ll_lat + (d_lat / 2)) + i * d_lat, i = 0, N_lat - 1)] - allocate(mask_out(size(lon), size(lat))) + allocate(mask_out( N_lon, N_lat)) - do i = 1, size(lon) + do i = 1, N_lon print*, lon(i) - do j = 1, size(lat) - allocate(distances(size(asc_lon))) + do j = 1, N_lat distances = (asc_lon - lon(i))**2 + (asc_lat - lat(j))**2 closest_index = minloc(distances, dim = 1) if (distances(closest_index) > 0.14**2) then - mask_out(i, j) = missing_value + mask_out(i, j) = missing_value ! Note: ASCAT EUMETSAT reader masks everything .ne. 0 else mask_out(i, j) = combined_mask(closest_index) end if - deallocate(distances) end do end do ! Write out the mask to netcdf ierr = nf90_create(fname_out, nf90_clobber, ncid) - if (ierr /= nf90_noerr) stop 'Error creating file' + if (ierr /= nf90_noerr) stop 'Error creating file: ' // fname_out ! Define the dimensions - ierr = nf90_def_dim(ncid, 'lon', size(lon), dimids(1)) - ierr = nf90_def_dim(ncid, 'lat', size(lat), dimids(2)) + ierr = nf90_def_dim(ncid, 'lon', N_lon, dimids(1)) + ierr = nf90_def_dim(ncid, 'lat', N_lat, dimids(2)) ! Define the global attributes ierr = nf90_put_att(ncid, nf90_global, 'title', 'ASCAT combined mask') - ierr = nf90_put_att(ncid, nf90_global, 'source', 'Lindorfer et al 2023') + ierr = nf90_put_att(ncid, nf90_global, 'source', 'Lindorfer et al 2023 doi:10.48436/9a2y9-e5z14') ierr = nf90_put_att(ncid, nf90_global, 'description', mask_description) ! Define the variables @@ -183,7 +188,7 @@ program ascat_mask_maker ierr = nf90_def_var(ncid, 'mask', nf90_byte, dimids, varid) ierr = nf90_put_att(ncid, varid, 'standard_name', 'combined_mask') - ierr = nf90_put_att(ncid, varid, 'long_name', 'Combined mask') + ierr = nf90_put_att(ncid, varid, 'long_name', 'combined mask') ierr = nf90_put_att(ncid, varid, 'units', 'boolean') ierr = nf90_put_att(ncid, varid, '_FillValue', missing_value) From f7d0750067af8bb263fdfffdb6a6119641ecd87b Mon Sep 17 00:00:00 2001 From: amfox37 Date: Tue, 19 Mar 2024 13:16:11 -0600 Subject: [PATCH 296/308] CMakeLists to build without install --- src/Applications/LDAS_App/CMakeLists.txt | 8 ++------ .../LDAS_App/util/inputs/ASCAT_sm_mask/CMakeLists.txt | 4 ++++ 2 files changed, 6 insertions(+), 6 deletions(-) create mode 100644 src/Applications/LDAS_App/util/inputs/ASCAT_sm_mask/CMakeLists.txt diff --git a/src/Applications/LDAS_App/CMakeLists.txt b/src/Applications/LDAS_App/CMakeLists.txt index 9f43cdd9..1075229e 100644 --- a/src/Applications/LDAS_App/CMakeLists.txt +++ b/src/Applications/LDAS_App/CMakeLists.txt @@ -14,12 +14,6 @@ ecbuild_add_executable ( SOURCES tile_bin2nc4.F90 LIBS MAPL) -ecbuild_add_executable ( - TARGET ascat_mask_maker.x - SOURCES util/inputs/ASCAT_sm_mask/ascat_mask_maker.F90 - LIBS MAPL -) - ecbuild_add_executable ( TARGET mwrtm_bin2nc4.x SOURCES util/inputs/mwRTM_params/mwrtm_bin2nc4.F90 @@ -51,3 +45,5 @@ install( FILES ${rc_files} ${nml_files} lenkf.j.template DESTINATION etc ) + +esma_add_subdirectories(util/inputs/ASCAT_sm_mask) diff --git a/src/Applications/LDAS_App/util/inputs/ASCAT_sm_mask/CMakeLists.txt b/src/Applications/LDAS_App/util/inputs/ASCAT_sm_mask/CMakeLists.txt new file mode 100644 index 00000000..ac0fbd08 --- /dev/null +++ b/src/Applications/LDAS_App/util/inputs/ASCAT_sm_mask/CMakeLists.txt @@ -0,0 +1,4 @@ +# build without installation + +add_executable(ascat_mask_maker.x ascat_mask_maker.F90) +target_link_libraries(ascat_mask_maker.x MAPL) \ No newline at end of file From 48c5ece1894ca7a7817c6a924ad628ebaf0f5f79 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Tue, 19 Mar 2024 16:31:33 -0400 Subject: [PATCH 297/308] updated paths to ASCAT EUMETSAT soil moisture retrieval data and mask file (LDASsa_DEFAULT_inputs_ensupd.nml, ascat_mask_maker.F90) --- src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml | 6 +++--- .../LDAS_App/util/inputs/ASCAT_sm_mask/CMakeLists.txt | 2 +- .../LDAS_App/util/inputs/ASCAT_sm_mask/ascat_mask_maker.F90 | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml b/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml index 0234887a..ece206c4 100644 --- a/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml +++ b/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml @@ -2177,7 +2177,7 @@ obs_param_nml(49)%bias_tcut = 432000 obs_param_nml(49)%nodata = -9999. obs_param_nml(49)%varname = 'sfds' obs_param_nml(49)%units = '%' -obs_param_nml(49)%path = '/discover/nobackup/projects/gmao/merra/iau/merra_land/DATA/ASCAT_EUMETSAT/Metop_A/' +obs_param_nml(49)%path = '/discover/nobackup/projects/gmao/smap/SMAP_Nature/ASCAT_EUMETSAT/Metop_A/' obs_param_nml(49)%name = 'M02-ASCA-ASCSMO02' obs_param_nml(49)%maskpath = '' obs_param_nml(49)%maskname = '' @@ -2216,7 +2216,7 @@ obs_param_nml(50)%bias_tcut = 432000 obs_param_nml(50)%nodata = -9999. obs_param_nml(50)%varname = 'sfds' obs_param_nml(50)%units = '%' -obs_param_nml(50)%path = '/discover/nobackup/projects/gmao/merra/iau/merra_land/DATA/ASCAT_EUMETSAT/Metop_B/' +obs_param_nml(50)%path = '/discover/nobackup/projects/gmao/smap/SMAP_Nature/ASCAT_EUMETSAT/Metop_B/' obs_param_nml(50)%name = 'M01-ASCA-ASCSMO02' obs_param_nml(50)%maskpath = '' obs_param_nml(50)%maskname = '' @@ -2255,7 +2255,7 @@ obs_param_nml(51)%bias_tcut = 432000 obs_param_nml(51)%nodata = -9999. obs_param_nml(51)%varname = 'sfds' obs_param_nml(51)%units = '%' -obs_param_nml(51)%path = '/discover/nobackup/projects/gmao/merra/iau/merra_land/DATA/ASCAT_EUMETSAT/Metop_C/' +obs_param_nml(51)%path = '/discover/nobackup/projects/gmao/smap/SMAP_Nature/ASCAT_EUMETSAT/Metop_C/' obs_param_nml(51)%name = 'M03-ASCA-ASCSMO02' obs_param_nml(51)%maskpath = '' obs_param_nml(51)%maskname = '' diff --git a/src/Applications/LDAS_App/util/inputs/ASCAT_sm_mask/CMakeLists.txt b/src/Applications/LDAS_App/util/inputs/ASCAT_sm_mask/CMakeLists.txt index ac0fbd08..11114b07 100644 --- a/src/Applications/LDAS_App/util/inputs/ASCAT_sm_mask/CMakeLists.txt +++ b/src/Applications/LDAS_App/util/inputs/ASCAT_sm_mask/CMakeLists.txt @@ -1,4 +1,4 @@ # build without installation add_executable(ascat_mask_maker.x ascat_mask_maker.F90) -target_link_libraries(ascat_mask_maker.x MAPL) \ No newline at end of file +target_link_libraries(ascat_mask_maker.x MAPL) diff --git a/src/Applications/LDAS_App/util/inputs/ASCAT_sm_mask/ascat_mask_maker.F90 b/src/Applications/LDAS_App/util/inputs/ASCAT_sm_mask/ascat_mask_maker.F90 index 83760b65..e9b4bbd0 100644 --- a/src/Applications/LDAS_App/util/inputs/ASCAT_sm_mask/ascat_mask_maker.F90 +++ b/src/Applications/LDAS_App/util/inputs/ASCAT_sm_mask/ascat_mask_maker.F90 @@ -36,7 +36,7 @@ program ascat_mask_maker ! ASCAT soil moisture mask file from Lindorfer et al 2023 - fname_in = '/discover/nobackup/amfox/subsurface_scattering_ASCAT_ERA5_Land.nc' + fname_in = '/discover/nobackup/projects/gmao/smap/SMAP_Nature/ASCAT_EUMETSAT/Mask/subsurface_scattering_ASCAT_ERA5_Land.nc' ! Specification of how to combine the masks ! Mask_mode = 1 (default) combines subsurface and wetland masks From 5462216a46b38d0cb0c7596e409f50bd6a965cd7 Mon Sep 17 00:00:00 2001 From: Biljana Orescanin <68251545+biljanaorescanin@users.noreply.github.com> Date: Tue, 19 Mar 2024 18:58:48 -0400 Subject: [PATCH 298/308] use develop for GEOSgcm_GridComp --- components.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components.yaml b/components.yaml index 4c394cfa..98df1017 100644 --- a/components.yaml +++ b/components.yaml @@ -49,6 +49,6 @@ MAPL: GEOSgcm_GridComp: local: ./src/Components/GEOSldas_GridComp/@GEOSgcm_GridComp remote: ../GEOSgcm_GridComp.git - branch: bugfix/rreichle/snow_excs + branch: develop sparse: ./config/GEOSgcm_GridComp_ldas.sparse develop: develop From 13b9b94feb2d421f99ad3913244ef0ed62372410 Mon Sep 17 00:00:00 2001 From: Matthew Thompson Date: Wed, 20 Mar 2024 09:52:42 -0400 Subject: [PATCH 299/308] Update to MAPL 2.44.1 --- components.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components.yaml b/components.yaml index 98df1017..36d4d1e6 100644 --- a/components.yaml +++ b/components.yaml @@ -43,7 +43,7 @@ GEOS_Util: MAPL: local: ./src/Shared/@MAPL remote: ../MAPL.git - branch: hotfix/bmauer/fixes-#2657 + tag: v2.44.1 develop: develop GEOSgcm_GridComp: From 5e7fde7cabffad3053393405c89d116f08dd7400 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Wed, 20 Mar 2024 11:47:00 -0400 Subject: [PATCH 300/308] updated documentation of Release v18.0.0 (CHANGELOG.md) --- doc/CHANGELOG.md | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index fba3ac50..e8e6199a 100644 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -33,18 +33,17 @@ This README file contains the history of stable GEOSldas Releases in Git, follow Overview of Git Releases: ============================ -[v18.0.0-beta](https://github.com/GEOS-ESM/GEOSldas/releases/tag/v18.0.0-beta) - 2024-03-14 +[v18.0.0](https://github.com/GEOS-ESM/GEOSldas/releases/tag/v18.0.0) - 2024-03-21 ------------------------------ -- Not 0-diff vs. v17.13.1 because of [snow model fixes](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/813). +- 0-diff vs. v17.13.1 (except for MAPL bug fix ([PR #734](https://github.com/GEOS-ESM/GEOSldas/pull/734))) - Notes: - - Release is designated "beta" because a tag (SMAP_NRv11.1) is used for GEOSgcm_GridComp in components.yaml (awaiting official GEOSgcm_GridComp release that includes [non-0-diff snow model fixes](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/813)). - - Release uses original GEOSldas repository structure. Final release is expected to use revised GEOSldas repository structure. + - Release uses original GEOSldas repository structure. Next release is expected to use a revised repository structure. - Science changes: - Added MODIS snow cover fraction assimilation ([PR #512](https://github.com/GEOS-ESM/GEOSldas/pull/512)). - - Added ASCAT soil moisture assimilation ([PR #656](https://github.com/GEOS-ESM/GEOSldas/pull/656), [PR #703](https://github.com/GEOS-ESM/GEOSldas/pull/703), [PR #723](https://github.com/GEOS-ESM/GEOSldas/pull/723)). + - Added ASCAT soil moisture assimilation ([PR #656](https://github.com/GEOS-ESM/GEOSldas/pull/656), [PR #703](https://github.com/GEOS-ESM/GEOSldas/pull/703), [PR #723](https://github.com/GEOS-ESM/GEOSldas/pull/723), [PR #729](https://github.com/GEOS-ESM/GEOSldas/pull/729)). - New update_type=13 for ASCAT soil moisture and SMAP brightness temperature assimilation ([PR #703](https://github.com/GEOS-ESM/GEOSldas/pull/703)). - New update_type=13 replaces update_type=[1,2], which has been disabled. - Requires ASCAT mask file ([PR #723](https://github.com/GEOS-ESM/GEOSldas/pull/723)). @@ -52,13 +51,10 @@ Overview of Git Releases: - Added support for GEOS-IT surface met forcing ([PR #688](https://github.com/GEOS-ESM/GEOSldas/pull/688)). - Added CATCHMENT_SPINUP mode ([PR #647](https://github.com/GEOS-ESM/GEOSldas/pull/647), [GEOSgcm_GridComp PR #751](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/751)). -- GEOSgcm_GridComp: - - Tag: SMAP_NRv11.1 +- GEOSgcm_GridComp v2.5.2: - Improved MODIS-based snow albedo (v2) in make_bcs package ([GEOSgcm_GridComp PR #687](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/687)). - Major source code cleanup: - - Stieglitz_snow: - - 0-diff ([GEOSgcm_GridComp PR #834](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/834)). - - Non-0-diff: revised snow compaction and cleanup ([GEOSgcm_GridComp PR #813](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/813)). + - Stieglitz snow model ([GEOSgcm_GridComp PR #834](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/834)). - make_bcs package ([GEOSgcm_GridComp PR #763](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/763), [GEOSgcm_GridComp PR #786](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/786), [GEOSgcm_GridComp PR #846](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/846)). - coeffsib ([GEOSgcm_GridComp PR #845](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/845)). - Fixed CDCR2 long_name ([GEOSgcm_GridComp PR #818](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/818)). @@ -84,7 +80,8 @@ Overview of Git Releases: - Support for running GEOSldas at the NASA Advanced Supercomputing (NAS) facility ([PR #706](https://github.com/GEOS-ESM/GEOSldas/pull/706)). - ESMA_env v4.23.0, Baselibs v7.16.0 ([PR #681](https://github.com/GEOS-ESM/GEOSldas/pull/681)). - ESMA_cmake v3.41.0 ([PR #725](https://github.com/GEOS-ESM/GEOSldas/pull/725)). - - MAPL v2.44.0 ([PR #725](https://github.com/GEOS-ESM/GEOSldas/pull/725)). + - MAPL v2.44.1 ([PR #734](https://github.com/GEOS-ESM/GEOSldas/pull/734)). + - Fixes bug that degrades simulation when writing (binary) instantaneous output with bit shaving. - CircleCI Orb v2 ([PR #694](https://github.com/GEOS-ESM/GEOSldas/pull/694)). - Replace FLAP with fArgParse ([PR #669](https://github.com/GEOS-ESM/GEOSldas/pull/669)). From e324d8022fa7c4b9ac4d846c603fe1bce8325fb3 Mon Sep 17 00:00:00 2001 From: Weiyuan Jiang Date: Wed, 20 Mar 2024 13:39:01 -0400 Subject: [PATCH 301/308] add more tmp file --- src/Applications/LDAS_App/ldas_setup | 49 ++++++++--------- src/Applications/LDAS_App/preprocess_ldas.F90 | 26 +++++---- .../LDAS_App/preprocess_ldas_routines.F90 | 54 +++++++++++-------- 3 files changed, 71 insertions(+), 58 deletions(-) diff --git a/src/Applications/LDAS_App/ldas_setup b/src/Applications/LDAS_App/ldas_setup index 71199157..e64496ee 100755 --- a/src/Applications/LDAS_App/ldas_setup +++ b/src/Applications/LDAS_App/ldas_setup @@ -373,17 +373,17 @@ class LDASsetup: for key,val in _domain_dic.items() : if key in self.rqdExeInp : _domain_dic[key]= self.rqdExeInp[key] - domain_def = tempfile.NamedTemporaryFile(mode='w', delete=False) - domain_def.write('&domain_inputs\n') + self.domain_def = tempfile.NamedTemporaryFile(mode='w', delete=False) + self.domain_def.write('&domain_inputs\n') for key,val in _domain_dic.items() : keyn=(key+" = ").ljust(16) valn = str(val) if '_FILE' in key: - domain_def.write(keyn+ "'"+valn+"'"+'\n') + self.domain_def.write(keyn+ "'"+valn+"'"+'\n') else : - domain_def.write(keyn+ valn +'\n') - domain_def.write('/\n') - domain_def.close() + self.domain_def.write(keyn+ valn +'\n') + self.domain_def.write('/\n') + self.domain_def.close() # make sure bcs files exist if self.rqdExeInp['RESTART'].isdigit() : @@ -501,13 +501,12 @@ class LDASsetup: # exefyl # ------ - cwd = os.getcwd() - self.blddir = cwd.rsplit('/',1)[0] + self.bindir = os.path.dirname(os.path.realpath(__file__)) + self.blddir = self.bindir.rsplit('/',1)[0] exefyl = '/bin/GEOSldas.x' tmp_execfyl= self.blddir+exefyl assert os.path.isfile(tmp_execfyl),\ 'Executable [%s] does not exist!' % tmp_execfyl - tmp_expid = self.rqdExeInp['EXP_ID'] tmp_expdir = os.path.abspath(self.exphome + '/' + self.rqdExeInp['EXP_ID']) self.rundir = tmp_expdir + '/run' @@ -708,7 +707,7 @@ class LDASsetup: print ('\nCorrect the tile file if it is an old EASE tile format... \n') EASEtile=self.bcsdir+'/MAPL_'+short_tile - cmd = './preprocess_ldas.x correctease '+ tile + ' '+ EASEtile + cmd = self.bindir + '/preprocess_ldas.x correctease '+ tile + ' '+ EASEtile if self.BUILT_ON_SLES15 : print ("Executables were built on SLES15 and must be run on SLES15: " + cmd) else: @@ -721,8 +720,6 @@ class LDASsetup: short_tile ='MAPL_'+short_tile tile=EASEtile # setup BC files - if os.path.isfile('f2g.txt'): - os.remove('f2g.txt') catchment_def = self.rqdExeInp['CATCH_DEF_FILE'] exp_id = self.rqdExeInp['EXP_ID'] @@ -743,24 +740,25 @@ class LDASsetup: wemin_out = self.rqdExeInp['WEMIN_OUT'] - cmd = './preprocess_ldas.x c_f2g ' + tile + ' ' + domain_def.name + ' '+ self.out_path + ' ' + catchment_def + ' ' + exp_id + ' ' + _y4m2d2h2m2 + ' '+ dzsf + tmp_f2g_file = tempfile.NamedTemporaryFile() + cmd = self.bindir +'/preprocess_ldas.x c_f2g ' + tile + ' ' + self.domain_def.name + ' '+ self.out_path + ' ' + catchment_def + ' ' + exp_id + ' ' + _y4m2d2h2m2 + ' '+ dzsf + ' ' + tmp_f2g_file.name - print ('Creating f2g.txt....\n') + print ('Creating f2g file: '+ tmp_f2g_file.name +'....\n') print ("cmd: " + cmd) sp.call(shlex.split(cmd)) # check if it is local or global - with open('f2g.txt') as f2gfile : + with open(tmp_f2g_file.name) as f2gfile : head=[next(f2gfile) for x in range(2)] if(head[0].strip() != head[1].strip()) : self.islocal= True - os.remove(domain_def.name) + os.remove(self.domain_def.name) # update tile domain if self.islocal: newlocalTile = tile+'.domain' print ("\nCreating local tile file :"+ newlocalTile) print ("\n by excluding land type MAPL_Land_ExcludeFromDomain=1100...\n") - cmd = './preprocess_ldas.x c_localtile ' + tile + ' ' + newlocalTile + cmd = self.bindir +'/preprocess_ldas.x c_localtile ' + tile + ' ' + newlocalTile + ' '+ tmp_f2g_file.name print ("cmd: " + cmd) sp.call(shlex.split(cmd)) short_tile=short_tile +'.domain' @@ -789,7 +787,7 @@ class LDASsetup: print ("Creating the boundary files for the simulation domain...\n") bcs_tmp=[] for bcf in bcs : - cmd = './preprocess_ldas.x c_localbc ' + bcf + ' '+ bcf+'.domain' + cmd = self.bindir +'/preprocess_ldas.x c_localbc ' + bcf + ' '+ bcf+'.domain' + ' '+ tmp_f2g_file.name print ("cmd: " + cmd) sp.call(shlex.split(cmd)) bcs_tmp=bcs_tmp+[bcf+'.domain'] @@ -922,7 +920,7 @@ class LDASsetup: catchLocal = self.rstdir+ensdir +'/'+ y4m2+'/'+self.rqdExeInp['EXP_ID']+'.'+self.catch+'_internal_rst.'+y4m2d2_h2m2 if self.islocal : print( "Creating local catchment restart file... \n") - cmd='./preprocess_ldas.x c_localcatchrst '+ catchRstFile +' ' + catchLocal + cmd=self.bindir +'/preprocess_ldas.x c_localcatchrst '+ catchRstFile +' ' + catchLocal + ' '+ tmp_f2g_file.name print ("cmd: "+cmd) sp.call(shlex.split(cmd)) else : @@ -940,7 +938,7 @@ class LDASsetup: vegdynLocal = self.rstdir+ensdir +'/'+self.rqdExeInp['EXP_ID']+'.vegdyn_internal_rst' if self.islocal : print ("Creating the local veg restart file... \n") - cmd='./preprocess_ldas.x c_localvegrst '+ vegdynRstFile +' ' + vegdynLocal + cmd=self.bindir + '/preprocess_ldas.x c_localvegrst '+ vegdynRstFile +' ' + vegdynLocal + ' '+ tmp_f2g_file.name print ("cmd: " + cmd) sp.call(shlex.split(cmd)) else : @@ -975,7 +973,8 @@ class LDASsetup: mwRTMLocal = self.bcsdir+'/'+ y4m2+'/'+self.rqdExeInp['EXP_ID']+'.ldas_mwRTMparam.'+y4m2d2_h2m2+'z.nc4' if self.islocal : print ("Creating the local mwRTM restart file... \n") - cmd='./preprocess_ldas.x c_localmwrtmrst '+ mwRTMRstFile +' ' + mwRTMLocal + cmd= self.bindir +'/preprocess_ldas.x c_localmwrtmrst '+ mwRTMRstFile +' ' + mwRTMLocal + ' '+ tmp_f2g_file.name + print ("cmd: " + cmd) sp.call(shlex.split(cmd)) else : @@ -988,9 +987,7 @@ class LDASsetup: # update 'restart_path' to use relative path from outdir print ("Updating restart path...") self.rqdExeInp['RESTART_PATH'] = myRstDir - if os.path.isfile('f2g.txt'): - os.remove('f2g.txt') - + os.remove(tmp_f2g_file.name) status = True return status @@ -1048,7 +1045,7 @@ class LDASsetup: os.remove('optimized_distribution') print ("Optimizing... decomposition of processes.... \n") - cmd = './preprocess_ldas.x optimize '+ self.inpdir+'/tile.data '+ str(self.rqdRmInp['ntasks_model']) + cmd = self.bindir + '/preprocess_ldas.x optimize '+ self.inpdir+'/tile.data '+ str(self.rqdRmInp['ntasks_model']) print ("cmd: " + cmd) sp.call(shlex.split(cmd)) optinxny=self._parseInputFile('optimized_distribution') @@ -1092,7 +1089,7 @@ class LDASsetup: if '-CF' in self.rqdExeInp['GRIDNAME'] : GRID ='CUBE ' + self.rqdExeInp['GRIDNAME'] + ' ' +tmprcfile _assim = '1' if self.assim else '0' - cmd ='./process_hist.csh '+ str(self.rqdExeInp['LSM_CHOICE']) + ' ' + str(self.rqdExeInp['AEROSOL_DEPOSITION']) + \ + cmd =self.bindir +'/process_hist.csh '+ str(self.rqdExeInp['LSM_CHOICE']) + ' ' + str(self.rqdExeInp['AEROSOL_DEPOSITION']) + \ ' ' + GRID + ' ' + str(self.rqdExeInp['RUN_IRRIG']) + ' ' + _assim + ' '+ str(self.nens) print(cmd) #os.system(cmd) diff --git a/src/Applications/LDAS_App/preprocess_ldas.F90 b/src/Applications/LDAS_App/preprocess_ldas.F90 index 30a68f97..6293354a 100644 --- a/src/Applications/LDAS_App/preprocess_ldas.F90 +++ b/src/Applications/LDAS_App/preprocess_ldas.F90 @@ -25,6 +25,7 @@ program main character(len=512) :: arg5 character(len=512) :: arg6 character(len=512) :: arg7 + character(len=512) :: arg8 character(len=512) :: orig_tile character(len=512) :: new_tile @@ -42,6 +43,7 @@ program main character(len=512) :: new_veg character(len=512) :: orig_ease character(len=512) :: new_ease + character(len=512) :: f2g_file character(len=12 ) :: ymdhm character(len=12 ) :: SURFLAY @@ -53,6 +55,7 @@ program main call get_command_argument(6,arg5) call get_command_argument(7,arg6) call get_command_argument(8,arg7) + call get_command_argument(9,arg8) if( trim(option) == "c_f2g") then @@ -66,43 +69,48 @@ program main exp_id = arg5 ymdhm = trim(adjustl(arg6)) SURFLAY = trim(adjustl(arg7)) + f2g_file = arg8 - call createf2g(orig_tile,domain_def_file,trim(out_path),catch_def_file,trim(exp_id),ymdhm, SURFLAY) + call createf2g(orig_tile,domain_def_file,trim(out_path),catch_def_file,trim(exp_id),ymdhm, SURFLAY, f2g_file) else if (trim(option) == "c_localtile") then orig_tile = arg1 new_tile = arg2 - - call createLocalTilefile(orig_tile,new_tile) + f2g_file = arg3 + call createLocalTilefile(f2g_file, orig_tile,new_tile) else if (trim(option) == "c_localbc" ) then - orig_BC = arg1 - new_BC = arg2 + orig_BC = arg1 + new_BC = arg2 + f2g_file = arg3 - call createLocalBC(orig_BC, new_BC) + call createLocalBC(f2g_file, orig_BC, new_BC) else if (trim(option) == "c_localvegrst") then orig_veg = arg1 new_veg = arg2 + f2g_file = arg3 - call createLocalVegRestart(orig_veg, new_veg) + call createLocalVegRestart(f2g_file, orig_veg, new_veg) else if (trim(option) == "c_localmwrtmrst") then orig_rtm = arg1 new_rtm = arg2 + f2g_file = arg3 - call createLocalmwRTMRestart(orig_rtm, new_rtm) + call createLocalmwRTMRestart(f2g_file, orig_rtm, new_rtm) else if (trim(option) == "c_localcatchrst") then orig_catch = arg1 new_catch = arg2 + f2g_file = arg3 - call createLocalCatchRestart(orig_catch, new_catch) + call createLocalCatchRestart(f2g_file, orig_catch, new_catch) else if (trim(option)=="correctease") then diff --git a/src/Applications/LDAS_App/preprocess_ldas_routines.F90 b/src/Applications/LDAS_App/preprocess_ldas_routines.F90 index 4796b4a9..771dc63d 100644 --- a/src/Applications/LDAS_App/preprocess_ldas_routines.F90 +++ b/src/Applications/LDAS_App/preprocess_ldas_routines.F90 @@ -106,7 +106,7 @@ module preprocess_ldas_routines ! ******************************************************************** - subroutine createf2g(orig_tile,domain_def,out_path,catch_def_file,exp_id,ymdhm, SURFLAY) + subroutine createf2g(orig_tile,domain_def,out_path,catch_def_file,exp_id,ymdhm, SURFLAY, f2g_file) implicit none character(*) :: orig_tile @@ -116,6 +116,7 @@ subroutine createf2g(orig_tile,domain_def,out_path,catch_def_file,exp_id,ymdhm, character(*) :: exp_id character(*) :: ymdhm character(*) :: SURFLAY + character(*) :: f2g_file real :: minlon,maxlon,minlat,maxlat character(len=512):: exclude_file,include_file @@ -211,7 +212,7 @@ subroutine createf2g(orig_tile,domain_def,out_path,catch_def_file,exp_id,ymdhm, else d2f = d2g endif - open(40,file='f2g.txt',form='formatted',action='write') + open(40,file=f2g_file,form='formatted',action='write') write(40,*)N_catf write(40,*)N_catd do n=1,N_catd @@ -1494,17 +1495,18 @@ end subroutine createf2g ! ******************************************************************** - subroutine readsize(N_catg,N_catf) + subroutine readsize(f2g_file, N_catg,N_catf) implicit none + character(*), intent(in):: f2g_file integer,intent(out) :: N_catg integer,intent(out) :: N_catf logical :: file_exist - inquire(file=trim('f2g.txt'),exist=file_exist) + inquire(file=f2g_file,exist=file_exist) if(file_exist) then - open(40,file='f2g.txt',form='formatted',action='read',status='old') + open(40,file= f2g_file,form='formatted',action='read',status='old') read(40,*)N_catg read(40,*)N_catf close(40) @@ -1515,9 +1517,10 @@ end subroutine readsize ! ******************************************************************** - subroutine readf2g(N_catf,f2g) + subroutine readf2g(f2g_file, N_catf,f2g) implicit none + character(*), intent(in):: f2g_file integer,intent(in) :: N_catf integer,dimension(N_catf),intent(inout) :: f2g @@ -1525,9 +1528,9 @@ subroutine readf2g(N_catf,f2g) logical :: file_exist integer :: local_size,n - inquire(file=trim('f2g.txt'),exist=file_exist) + inquire(file=f2g_file,exist=file_exist) if(file_exist) then - open(40,file='f2g.txt',form='formatted',action='read',status='old') + open(40,file= f2g_file,form='formatted',action='read',status='old') read(40,*)N_catg read(40,*)local_size @@ -1551,9 +1554,10 @@ end subroutine readf2g ! ******************************************************************** - subroutine createLocalTilefile(orig_tile,new_tile) + subroutine createLocalTilefile(f2g_file, orig_tile,new_tile) implicit none + character(*), intent(in) :: f2g_file character(*), intent(in) :: orig_tile character(*), intent(in) :: new_tile @@ -1596,13 +1600,13 @@ subroutine createLocalTilefile(orig_tile,new_tile) if( .not. file_exist) stop ("original tile file does not exist") ! Set default local tile file name - call readsize(N_catg,N_catf) + call readsize( f2g_file, N_catg,N_catf) if(N_catg == N_catf) then print*, "It is global domain..." return endif allocate(f2g(N_catf)) - call readf2g(N_catf,f2g) + call readf2g(f2g_file, N_catf,f2g) open(40,file=trim(orig_tile),action="read") open(50,file=trim(new_tile),action="write") @@ -1659,9 +1663,10 @@ end subroutine createLocalTilefile ! ******************************************************************** - subroutine createLocalBC(orig_BC, new_BC) + subroutine createLocalBC(f2g_file, orig_BC, new_BC) implicit none + character(*),intent(in) :: f2g_file character(*),intent(in) :: orig_BC character(*),intent(in) :: new_BC @@ -1670,10 +1675,10 @@ subroutine createLocalBC(orig_BC, new_BC) integer :: istat, N_catg,N_catf integer,dimension(:),allocatable :: f2g - call readsize(N_catg,N_catf) + call readsize(f2g_file, N_catg,N_catf) if(N_catg==N_catf) return allocate(f2g(N_catf)) - call readf2g(N_catf,f2g) + call readf2g(f2g_file, N_catf,f2g) allocate(tmpvec(N_catg)) open(10,file=trim(orig_BC),form='unformatted',action='read',status='old',iostat=istat) @@ -1693,9 +1698,10 @@ end subroutine createLocalBC ! ******************************************************************** - subroutine createLocalCatchRestart(orig_catch, new_catch) + subroutine createLocalCatchRestart(f2g_file, orig_catch, new_catch) implicit none + character(*),intent(in):: f2g_file character(*),intent(in):: orig_catch character(*),intent(in):: new_catch integer,parameter :: subtile=4 @@ -1714,10 +1720,10 @@ subroutine createLocalCatchRestart(orig_catch, new_catch) integer ::n, N_catg,N_catf integer,dimension(:),allocatable :: f2g - call readsize(N_catg,N_catf) + call readsize(f2g_file, N_catg,N_catf) if(N_catg == N_catf) return allocate(f2g(N_catf)) - call readf2g(N_catf,f2g) + call readf2g(f2g_file, N_catf,f2g) allocate(tmp1(N_catg)) allocate(tmp2(N_catg,subtile)) @@ -1824,9 +1830,10 @@ end subroutine createLocalCatchRestart ! ******************************************************************** - subroutine createLocalmwRTMRestart(orig_mwrtm, new_mwrtm) + subroutine createLocalmwRTMRestart(f2g_file, orig_mwrtm, new_mwrtm) implicit none + character(*),intent(in):: f2g_file character(*),intent(in):: orig_mwrtm character(*),intent(in):: new_mwrtm integer,parameter :: subtile=4 @@ -1842,10 +1849,10 @@ subroutine createLocalmwRTMRestart(orig_mwrtm, new_mwrtm) integer :: N_catg,N_catf integer,dimension(:),allocatable :: f2g - call readsize(N_catg,N_catf) + call readsize(f2g_file, N_catg,N_catf) if(N_catg == N_catf) return allocate(f2g(N_catf)) - call readf2g(N_catf,f2g) + call readf2g(f2g_file, N_catf,f2g) allocate(tmp1(N_catg)) @@ -1877,9 +1884,10 @@ end subroutine createLocalmwRTMRestart ! ******************************************************************** - subroutine createLocalVegRestart(orig_veg, new_veg) + subroutine createLocalVegRestart(f2g_file, orig_veg, new_veg) implicit none + character(*),intent(in):: f2g_file character(*),intent(in):: orig_veg character(*),intent(in):: new_veg integer :: istat @@ -1900,10 +1908,10 @@ subroutine createLocalVegRestart(orig_veg, new_veg) character(len=:), pointer :: vname integer :: rc - call readsize(N_catg,N_catf) + call readsize(f2g_file, N_catg,N_catf) if(N_catg == N_catf) return allocate(f2g(N_catf)) - call readf2g(N_catf,f2g) + call readf2g(f2g_file, N_catf,f2g) allocate(rity(N_catg)) allocate(z2(N_catg)) From def6df937783237eb351eec5a50482f75d2deaa3 Mon Sep 17 00:00:00 2001 From: Weiyuan Jiang Date: Wed, 20 Mar 2024 15:24:02 -0400 Subject: [PATCH 302/308] more files in tempfile --- src/Applications/LDAS_App/ldas_setup | 30 +++++++++++-------- src/Applications/LDAS_App/preprocess_ldas.F90 | 3 +- .../LDAS_App/preprocess_ldas_routines.F90 | 18 +++++++---- 3 files changed, 31 insertions(+), 20 deletions(-) diff --git a/src/Applications/LDAS_App/ldas_setup b/src/Applications/LDAS_App/ldas_setup index e64496ee..1d1e8332 100755 --- a/src/Applications/LDAS_App/ldas_setup +++ b/src/Applications/LDAS_App/ldas_setup @@ -740,7 +740,7 @@ class LDASsetup: wemin_out = self.rqdExeInp['WEMIN_OUT'] - tmp_f2g_file = tempfile.NamedTemporaryFile() + tmp_f2g_file = tempfile.NamedTemporaryFile(delete=False) cmd = self.bindir +'/preprocess_ldas.x c_f2g ' + tile + ' ' + self.domain_def.name + ' '+ self.out_path + ' ' + catchment_def + ' ' + exp_id + ' ' + _y4m2d2h2m2 + ' '+ dzsf + ' ' + tmp_f2g_file.name print ('Creating f2g file: '+ tmp_f2g_file.name +'....\n') @@ -751,7 +751,7 @@ class LDASsetup: head=[next(f2gfile) for x in range(2)] if(head[0].strip() != head[1].strip()) : self.islocal= True - os.remove(self.domain_def.name) + #os.remove(self.domain_def.name) # update tile domain if self.islocal: @@ -987,7 +987,8 @@ class LDASsetup: # update 'restart_path' to use relative path from outdir print ("Updating restart path...") self.rqdExeInp['RESTART_PATH'] = myRstDir - os.remove(tmp_f2g_file.name) + #if os.path.isfile(tmp_f2g_file.name): + # os.remove(tmp_f2g_file.name) status = True return status @@ -1041,25 +1042,28 @@ class LDASsetup: shutil.copy2(nmlfile, self.rundir+'/'+shortfile) # get optimzed NX and IMS - if os.path.isfile('optimized_distribution'): - os.remove('optimized_distribution') - + optimized_distribution_file = tempfile.NamedTemporaryFile(delete=False) + tmp_path = os.path.dirname(optimized_distribution_file.name ) + print("tmp_path:"+tmp_path) print ("Optimizing... decomposition of processes.... \n") - cmd = self.bindir + '/preprocess_ldas.x optimize '+ self.inpdir+'/tile.data '+ str(self.rqdRmInp['ntasks_model']) + cmd = self.bindir + '/preprocess_ldas.x optimize '+ self.inpdir+'/tile.data '+ str(self.rqdRmInp['ntasks_model']) + ' ' + optimized_distribution_file.name print ("cmd: " + cmd) sp.call(shlex.split(cmd)) - optinxny=self._parseInputFile('optimized_distribution') + optinxny=self._parseInputFile(optimized_distribution_file.name) if (int(optinxny['NX']) == 1): if int(optinxny['NY']) != int(self.rqdRmInp['ntasks_model']): self.rqdRmInp['ntasks_model']=optinxny['NY'] print ('adjust ntasks_model %d for cubed-sphere grid' % int(self.rqdRmInp['ntasks_model'])) - if os.path.isfile('IMS.rc') : - shutil.move('IMS.rc', self.rundir+'/') - if os.path.isfile('JMS.rc') : - shutil.move('JMS.rc', self.rundir+'/') + if os.path.isfile( tmp_path+'/IMS.rc') : + shutil.move(tmp_path+'/IMS.rc', self.rundir+'/') + print("move file: " + tmp_path+'/IMS.rc') + if os.path.isfile( tmp_path+'/JMS.rc') : + shutil.move(tmp_path+'/JMS.rc', self.rundir+'/') + print("move file: " + tmp_path+'/JMS.rc') + - os.remove('optimized_distribution') + #os.remove(optimized_distribution_file.name) # DEFAULT rc files default_rc = glob.glob(etcdir+'/GEOSldas_*.rc') diff --git a/src/Applications/LDAS_App/preprocess_ldas.F90 b/src/Applications/LDAS_App/preprocess_ldas.F90 index 6293354a..47b51bcd 100644 --- a/src/Applications/LDAS_App/preprocess_ldas.F90 +++ b/src/Applications/LDAS_App/preprocess_ldas.F90 @@ -128,7 +128,8 @@ program main else if (trim(option) == "optimize") then - call optimize_latlon(arg1,arg2) + + call optimize_latlon(arg1,arg2, arg3) else diff --git a/src/Applications/LDAS_App/preprocess_ldas_routines.F90 b/src/Applications/LDAS_App/preprocess_ldas_routines.F90 index 771dc63d..58ae048c 100644 --- a/src/Applications/LDAS_App/preprocess_ldas_routines.F90 +++ b/src/Applications/LDAS_App/preprocess_ldas_routines.F90 @@ -2042,12 +2042,13 @@ end subroutine correctEase ! NY: N_proc 1 ! JMS.rc IMS.rc - subroutine optimize_latlon(fname_tilefile, N_proc_string) + subroutine optimize_latlon(fname_tilefile, N_proc_string, optimized_file) implicit none character(*), intent(in) :: fname_tilefile ! file name (with path) of tile file (*.til) character(*), intent(in) :: N_proc_string ! *string* w/ no. of processors (or tasks), excl. OSERVER tasks + character(*), intent(in) :: optimized_file ! local variables integer :: N_proc @@ -2067,6 +2068,7 @@ subroutine optimize_latlon(fname_tilefile, N_proc_string) integer :: IMGLOB, JMGLOB integer :: face(6),face_land(6) logical :: forward + character(len=:), allocatable :: IMS_file, JMS_File ! ----------------------------- @@ -2273,8 +2275,8 @@ subroutine optimize_latlon(fname_tilefile, N_proc_string) enddo if( k /=6 ) stop ("one or more processes may accross the face") - - open(10,file="optimized_distribution",action='write') + + open(10,file=optimized_file,action='write') write(10,'(A)') "GEOSldas.GRIDNAME: " // trim(gridname) write(10,'(A)') "GEOSldas.GRID_TYPE: Cubed-Sphere" write(10,'(A)') "GEOSldas.NF: 6" @@ -2285,7 +2287,9 @@ subroutine optimize_latlon(fname_tilefile, N_proc_string) write(10,'(A)') "GEOSldas.JMS_FILE: JMS.rc" close(10) - open(10,file="JMS.rc",action='write') + n = index(optimized_file, '/', back=.true.) + JMS_file = optimized_file(1:n)//"JMS.rc" + open(10,file=JMS_file ,action='write') write(10,'(I5,I5)') N_proc, maxval(face) do n=1,N_proc write(10,'(I8)') JMS(n) @@ -2464,7 +2468,7 @@ subroutine optimize_latlon(fname_tilefile, N_proc_string) enddo if( any(IMS <=1) ) stop ("Each processor must have at least 2 longitude stripes. Request fewer processors.") - open(10,file="optimized_distribution",action='write') + open(10,file=optimized_file, action='write') write(10,'(A)') "GEOSldas.GRID_TYPE: LatLon" write(10,'(A)') "GEOSldas.GRIDNAME: "//trim(gridname) write(10,'(A)') "GEOSldas.LM: 1" @@ -2479,7 +2483,9 @@ subroutine optimize_latlon(fname_tilefile, N_proc_string) write(10,'(A)') "GEOSldas.IMS_FILE: IMS.rc" close(10) - open(10,file="IMS.rc",action='write') + n = index(optimized_file, '/', back=.True.) + IMS_file = optimized_file(1:n)//"IMS.rc" + open(10,file=IMS_file,action='write') write(10,'(I5)') N_proc do n=1,N_proc write(10,'(I8)') IMS(n) From bbba559300a5034f5871a885154e22a8a1708729 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Wed, 20 Mar 2024 20:22:19 -0400 Subject: [PATCH 303/308] additional updates for Release v18.0.0 (CHANGELOG.md) --- doc/CHANGELOG.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index e8e6199a..67da9611 100644 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -36,7 +36,7 @@ Overview of Git Releases: [v18.0.0](https://github.com/GEOS-ESM/GEOSldas/releases/tag/v18.0.0) - 2024-03-21 ------------------------------ -- 0-diff vs. v17.13.1 (except for MAPL bug fix ([PR #734](https://github.com/GEOS-ESM/GEOSldas/pull/734))) +- 0-diff vs. v17.13.1 except for MAPL bug fix ([PR #734](https://github.com/GEOS-ESM/GEOSldas/pull/734)). - Notes: - Release uses original GEOSldas repository structure. Next release is expected to use a revised repository structure. @@ -46,7 +46,7 @@ Overview of Git Releases: - Added ASCAT soil moisture assimilation ([PR #656](https://github.com/GEOS-ESM/GEOSldas/pull/656), [PR #703](https://github.com/GEOS-ESM/GEOSldas/pull/703), [PR #723](https://github.com/GEOS-ESM/GEOSldas/pull/723), [PR #729](https://github.com/GEOS-ESM/GEOSldas/pull/729)). - New update_type=13 for ASCAT soil moisture and SMAP brightness temperature assimilation ([PR #703](https://github.com/GEOS-ESM/GEOSldas/pull/703)). - New update_type=13 replaces update_type=[1,2], which has been disabled. - - Requires ASCAT mask file ([PR #723](https://github.com/GEOS-ESM/GEOSldas/pull/723)). + - Requires ASCAT mask file ([PR #723](https://github.com/GEOS-ESM/GEOSldas/pull/723), [PR #729](https://github.com/GEOS-ESM/GEOSldas/pull/729)). - Disabled CatchmentCNCLM45 model option (LSM_CHOICE=3) ([PR #707](https://github.com/GEOS-ESM/GEOSldas/pull/707), [GEOSgcm_GridComp PR #900](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/900)). - Added support for GEOS-IT surface met forcing ([PR #688](https://github.com/GEOS-ESM/GEOSldas/pull/688)). - Added CATCHMENT_SPINUP mode ([PR #647](https://github.com/GEOS-ESM/GEOSldas/pull/647), [GEOSgcm_GridComp PR #751](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/751)). @@ -78,10 +78,10 @@ Overview of Git Releases: - Added support for SLES15/Milan nodes ([PR #693](https://github.com/GEOS-ESM/GEOSldas/pull/693)). - Removed support for Haswell nodes ([PR #681](https://github.com/GEOS-ESM/GEOSldas/pull/681)). - Support for running GEOSldas at the NASA Advanced Supercomputing (NAS) facility ([PR #706](https://github.com/GEOS-ESM/GEOSldas/pull/706)). + - Allow setting up of experiments from other users' build ([PR #733](https://github.com/GEOS-ESM/GEOSldas/pull/733)). - ESMA_env v4.23.0, Baselibs v7.16.0 ([PR #681](https://github.com/GEOS-ESM/GEOSldas/pull/681)). - ESMA_cmake v3.41.0 ([PR #725](https://github.com/GEOS-ESM/GEOSldas/pull/725)). - MAPL v2.44.1 ([PR #734](https://github.com/GEOS-ESM/GEOSldas/pull/734)). - - Fixes bug that degrades simulation when writing (binary) instantaneous output with bit shaving. - CircleCI Orb v2 ([PR #694](https://github.com/GEOS-ESM/GEOSldas/pull/694)). - Replace FLAP with fArgParse ([PR #669](https://github.com/GEOS-ESM/GEOSldas/pull/669)). @@ -89,6 +89,7 @@ Overview of Git Releases: - Updates and corrections ([PR #728](https://github.com/GEOS-ESM/GEOSldas/pull/728)). - Bug fixes and other minor changes: + - Fixed bug that degraded simulation when writing (MAPL-binary) instantaneous output with bit shaving ([PR #734](https://github.com/GEOS-ESM/GEOSldas/pull/734)). - Removed requirement for mwRTM parameter input files ([PR #685](https://github.com/GEOS-ESM/GEOSldas/pull/685)). - Support for reading corrected precipitation from aggregated daily netcdf files ([PR #718](https://github.com/GEOS-ESM/GEOSldas/pull/718)). - Updated generate_catchincr_hist.py and sample documents for coupled land-atmosphere data assimilation ([PR #698](https://github.com/GEOS-ESM/GEOSldas/pull/698)). From 1d1aa1234481dbbf46d13623d7c97b3335ba9743 Mon Sep 17 00:00:00 2001 From: Matthew Thompson Date: Thu, 21 Mar 2024 07:37:45 -0400 Subject: [PATCH 304/308] Update some GitHub Actions versions --- .github/workflows/push-to-develop.yml | 2 +- .github/workflows/release-tarball.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/push-to-develop.yml b/.github/workflows/push-to-develop.yml index fd525b2a..ebbd3109 100644 --- a/.github/workflows/push-to-develop.yml +++ b/.github/workflows/push-to-develop.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repo - uses: actions/checkout@v3.3.0 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Run the action diff --git a/.github/workflows/release-tarball.yml b/.github/workflows/release-tarball.yml index 41f28389..3866b8dd 100644 --- a/.github/workflows/release-tarball.yml +++ b/.github/workflows/release-tarball.yml @@ -10,12 +10,12 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3.3.0 + uses: actions/checkout@v4 with: path: ${{ github.event.repository.name }}-${{ github.event.release.tag_name }} - name: Checkout mepo - uses: actions/checkout@v3.3.0 + uses: actions/checkout@v4 with: repository: GEOS-ESM/mepo path: mepo From 07c9ae79f52eeb5eff1e0abb4d613f523f56d3b5 Mon Sep 17 00:00:00 2001 From: Weiyuan Jiang Date: Thu, 21 Mar 2024 08:27:27 -0400 Subject: [PATCH 305/308] create IMS.rc or JMS.rc directly on run_dir --- src/Applications/LDAS_App/ldas_setup | 12 ++---------- src/Applications/LDAS_App/preprocess_ldas.F90 | 2 +- .../LDAS_App/preprocess_ldas_routines.F90 | 9 ++++----- 3 files changed, 7 insertions(+), 16 deletions(-) diff --git a/src/Applications/LDAS_App/ldas_setup b/src/Applications/LDAS_App/ldas_setup index 1d1e8332..6c1eada8 100755 --- a/src/Applications/LDAS_App/ldas_setup +++ b/src/Applications/LDAS_App/ldas_setup @@ -1043,11 +1043,10 @@ class LDASsetup: # get optimzed NX and IMS optimized_distribution_file = tempfile.NamedTemporaryFile(delete=False) - tmp_path = os.path.dirname(optimized_distribution_file.name ) - print("tmp_path:"+tmp_path) print ("Optimizing... decomposition of processes.... \n") - cmd = self.bindir + '/preprocess_ldas.x optimize '+ self.inpdir+'/tile.data '+ str(self.rqdRmInp['ntasks_model']) + ' ' + optimized_distribution_file.name + cmd = self.bindir + '/preprocess_ldas.x optimize '+ self.inpdir+'/tile.data '+ str(self.rqdRmInp['ntasks_model']) + ' ' + optimized_distribution_file.name + ' ' + self.rundir print ("cmd: " + cmd) + print ("IMS.rc or JMS.rc would be generated on " + self.rundir) sp.call(shlex.split(cmd)) optinxny=self._parseInputFile(optimized_distribution_file.name) if (int(optinxny['NX']) == 1): @@ -1055,13 +1054,6 @@ class LDASsetup: self.rqdRmInp['ntasks_model']=optinxny['NY'] print ('adjust ntasks_model %d for cubed-sphere grid' % int(self.rqdRmInp['ntasks_model'])) - if os.path.isfile( tmp_path+'/IMS.rc') : - shutil.move(tmp_path+'/IMS.rc', self.rundir+'/') - print("move file: " + tmp_path+'/IMS.rc') - if os.path.isfile( tmp_path+'/JMS.rc') : - shutil.move(tmp_path+'/JMS.rc', self.rundir+'/') - print("move file: " + tmp_path+'/JMS.rc') - #os.remove(optimized_distribution_file.name) diff --git a/src/Applications/LDAS_App/preprocess_ldas.F90 b/src/Applications/LDAS_App/preprocess_ldas.F90 index 47b51bcd..4d5725e6 100644 --- a/src/Applications/LDAS_App/preprocess_ldas.F90 +++ b/src/Applications/LDAS_App/preprocess_ldas.F90 @@ -129,7 +129,7 @@ program main else if (trim(option) == "optimize") then - call optimize_latlon(arg1,arg2, arg3) + call optimize_latlon(arg1,arg2, arg3, arg4) else diff --git a/src/Applications/LDAS_App/preprocess_ldas_routines.F90 b/src/Applications/LDAS_App/preprocess_ldas_routines.F90 index 58ae048c..4a7e9ec1 100644 --- a/src/Applications/LDAS_App/preprocess_ldas_routines.F90 +++ b/src/Applications/LDAS_App/preprocess_ldas_routines.F90 @@ -2042,13 +2042,14 @@ end subroutine correctEase ! NY: N_proc 1 ! JMS.rc IMS.rc - subroutine optimize_latlon(fname_tilefile, N_proc_string, optimized_file) + subroutine optimize_latlon(fname_tilefile, N_proc_string, optimized_file, run_dir) implicit none character(*), intent(in) :: fname_tilefile ! file name (with path) of tile file (*.til) character(*), intent(in) :: N_proc_string ! *string* w/ no. of processors (or tasks), excl. OSERVER tasks character(*), intent(in) :: optimized_file + character(*), intent(in) :: run_dir ! local variables integer :: N_proc @@ -2287,8 +2288,7 @@ subroutine optimize_latlon(fname_tilefile, N_proc_string, optimized_file) write(10,'(A)') "GEOSldas.JMS_FILE: JMS.rc" close(10) - n = index(optimized_file, '/', back=.true.) - JMS_file = optimized_file(1:n)//"JMS.rc" + JMS_file = trim(run_dir)//"/JMS.rc" open(10,file=JMS_file ,action='write') write(10,'(I5,I5)') N_proc, maxval(face) do n=1,N_proc @@ -2483,8 +2483,7 @@ subroutine optimize_latlon(fname_tilefile, N_proc_string, optimized_file) write(10,'(A)') "GEOSldas.IMS_FILE: IMS.rc" close(10) - n = index(optimized_file, '/', back=.True.) - IMS_file = optimized_file(1:n)//"IMS.rc" + IMS_file = trim(run_dir)//"/IMS.rc" open(10,file=IMS_file,action='write') write(10,'(I5)') N_proc do n=1,N_proc From a956a120fb2f06222a1cf04c78a0959d2676a1c3 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Thu, 21 Mar 2024 16:43:18 -0400 Subject: [PATCH 306/308] more documentation updates in prep for v18.0.0 (CHANGELOG.md, README.MetForcing_and_BCS.md) --- doc/CHANGELOG.md | 7 +++++-- doc/README.MetForcing_and_BCS.md | 32 ++++++++++++++++---------------- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index 67da9611..93ef46dc 100644 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -71,6 +71,7 @@ Overview of Git Releases: - GMAO_Shared v1.9.7 ([PR #725](https://github.com/GEOS-ESM/GEOSldas/pull/725)). - GEOS_Util v2.0.7 ([PR #725](https://github.com/GEOS-ESM/GEOSldas/pull/725)). - Sparse checkout of GEOS_Util ([PR #711](https://github.com/GEOS-ESM/GEOSldas/pull/711)). + - Improved remap_restarts package ([GEOS_Util PR #43](https://github.com/GEOS-ESM/GEOS_Util/pull/19), [GEOS_Util PR #43](https://github.com/GEOS-ESM/GEOS_Util/pull/43), [GEOS_Util PR #53](https://github.com/GEOS-ESM/GEOS_Util/pull/53)) - Added NCEP_Shared v1.3.0 ([PR #656](https://github.com/GEOS-ESM/GEOSldas/pull/656)). - Infrastructure: @@ -78,12 +79,14 @@ Overview of Git Releases: - Added support for SLES15/Milan nodes ([PR #693](https://github.com/GEOS-ESM/GEOSldas/pull/693)). - Removed support for Haswell nodes ([PR #681](https://github.com/GEOS-ESM/GEOSldas/pull/681)). - Support for running GEOSldas at the NASA Advanced Supercomputing (NAS) facility ([PR #706](https://github.com/GEOS-ESM/GEOSldas/pull/706)). - - Allow setting up of experiments from other users' build ([PR #733](https://github.com/GEOS-ESM/GEOSldas/pull/733)). + - Allow experiment setup from another user's build ([PR #733](https://github.com/GEOS-ESM/GEOSldas/pull/733)). - ESMA_env v4.23.0, Baselibs v7.16.0 ([PR #681](https://github.com/GEOS-ESM/GEOSldas/pull/681)). - ESMA_cmake v3.41.0 ([PR #725](https://github.com/GEOS-ESM/GEOSldas/pull/725)). - MAPL v2.44.1 ([PR #734](https://github.com/GEOS-ESM/GEOSldas/pull/734)). - CircleCI Orb v2 ([PR #694](https://github.com/GEOS-ESM/GEOSldas/pull/694)). - - Replace FLAP with fArgParse ([PR #669](https://github.com/GEOS-ESM/GEOSldas/pull/669)). + - Replaced FLAP with fArgParse ([PR #669](https://github.com/GEOS-ESM/GEOSldas/pull/669)). + - Updated versions of GitHub Actions ([PR #739](https://github.com/GEOS-ESM/GEOSldas/pull/739)). + - Documentation: - Updates and corrections ([PR #728](https://github.com/GEOS-ESM/GEOSldas/pull/728)). diff --git a/doc/README.MetForcing_and_BCS.md b/doc/README.MetForcing_and_BCS.md index 9c6bc3c2..fa0dd307 100644 --- a/doc/README.MetForcing_and_BCS.md +++ b/doc/README.MetForcing_and_BCS.md @@ -73,14 +73,14 @@ COMMONLY USED values for `MET_PATH`: MET_PATH : /discover/nobackup/projects/gmao/merra/iau/merra_land/MERRA2_land_forcing/ ``` -Note: Used for SMAP Nature Run v05, v7.2, v8.1, v8.3, v9.1, v10.0, v11.1 (before 1/1/2015). +Note: Used for SMAP Nature Run v05, v7.2, v8.1, v8.3, v9.1, v10.0 (before 1/1/2015). #### GEOS FP forcing with "seamless" file names, for use with MET_TAG=GEOS.fp.asm[__prec*] (__PREFERRED__) ``` MET_PATH : /discover/nobackup/projects/gmao/smap/SMAP_L4/GEOS/FP/ ``` -Note: Used for SMAP Nature Run v8.1, v8.3, v9.1, v10.0, v11.1 (after 1/1/2015); SMAP L4_SM Version 5, 6, 7. +Note: Used for SMAP Nature Run v8.1, v8.3, v9.1, v10.0 (after 1/1/2015); SMAP L4_SM Version 5, 6, 7. #### GEOS forcing with experiment-specific file names, incl. FP (__DEPRECATED__), FP-IT/RP-IT, and precip-corrected GEOS forcing ``` @@ -286,24 +286,24 @@ COMMONLY USED values for `MET_TAG`: #### SMAP Nature Run v9.1; SMAP L4_SM Version 6 ``` - MET_TAG : GEOS.fp.asm__precCPCU_IMGFinal_IMGFclim_G5FP ! (precip corr with IMERG-Final and late-look CPCU) - MET_TAG : GEOS.fp.asm__precCPCULLK_IMERGLateV06b_fp_v1 ! (precip corr with IMERG-Late and late-look CPCU) - MET_TAG : GEOS.fp.asm__precCPCUFLK_IMERGLateV06b_fp_v1 ! (precip corr with IMERG-Late and first-look CPCU) - MET_TAG : GEOS.fp.asm__precCPCUFLK_IMERGLateV06c_fp_v1 ! (precip corr with IMERG-Late and first-look CPCU) + MET_TAG : M2COR_cross__precSMAPv6_CGIM2 ! before 01/01/2015 + MET_TAG : GEOS.fp.asm__precCPCU_IMGFinal_IMGFclim_G5FP ! before 06/30/2021 (precip corr with IMERG-Final and late-look CPCU) + MET_TAG : GEOS.fp.asm__precCPCULLK_IMERGLateV06b_fp_v1 ! before 10/27/2021 (precip corr with IMERG-Late and late-look CPCU) + MET_TAG : GEOS.fp.asm__precCPCUFLK_IMERGLateV06b_fp_v1 ! before 05/09/2022 (precip corr with IMERG-Late and first-look CPCU) + MET_TAG : GEOS.fp.asm__precCPCUFLK_IMERGLateV06c_fp_v1 ! (precip corr with IMERG-Late and first-look CPCU) ``` -#### SMAP Nature Run v10.0; SMAP L4_SM Version 7 +#### SMAP Nature Run v10.0*; SMAP L4_SM Version 7 ``` - MET_TAG : GEOS.fp.asm__precCPCU_IMGFinal_IMGFclim_G5FP ! (precip corr with IMERG-Final and late-look CPCU) - MET_TAG : GEOS.fp.asm__precCPCUFLK_IMERGLateV06b_fp_v1 ! (precip corr with IMERG-Late and first-look CPCU) - MET_TAG : GEOS.fp.asm__precCPCUFLK_IMERGLateV06c_fp_v1 ! (precip corr with IMERG-Late and first-look CPCU) + MET_TAG : M2COR_cross__precSMAPv6_CGIM2 ! before 01/01/2015 + MET_TAG : GEOS.fp.asm__precCPCU_IMGFinal_IMGFclim_G5FP ! before 09/30/2021 (precip corr with IMERG-Final and late-look CPCU) + MET_TAG : GEOS.fp.asm__precCPCUFLK_IMERGLateV06b_fp_v1 ! before 05/09/2022 (precip corr with IMERG-Late and first-look CPCU) + MET_TAG : GEOS.fp.asm__precCPCUFLK_IMERGLateV06c_fp_v1 ! before 07/02/2023 (precip corr with IMERG-Late and first-look CPCU) + MET_TAG : GEOS.fp.asm__precCPCUFLK_IMERGLateV06d_fp_v1 ! before 11/07/2023 (precip corr with IMERG-Late and first-look CPCU) + MET_TAG : GEOS.fp.asm__precCPCUFLK_IMERGLateV06e_fp_v1 ! (precip corr with IMERG-Late and first-look CPCU) ``` - -#### SMAP Nature Run v11.1 -``` - MET_TAG : GEOS.fp.asm__precIMGv7BFnCPCUcorrv1 -``` +*Transitions dates are for L4_SM Version 7. Transition dates for NRv10.0 may differ somewhat. Boundary Conditions @@ -414,7 +414,7 @@ Notes: - Icarus-NLv5 is identical to Icarus-NLv4 except for parameters associated with PEATCLSM. -#### v11: SMAP Nature Run v11.1 +#### v11 ``` BCS_PATH : /discover/nobackup/projects/gmao/bcs_shared/fvInput/ExtData/esm/tiles/v11/ ``` From d8a1cf9aba34113910b995895cb9c07e98b8cd15 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Thu, 21 Mar 2024 18:50:38 -0400 Subject: [PATCH 307/308] mininmal updates of Release v18.0.0 documentation (CHANGELOG.md) --- doc/CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index 93ef46dc..5626d2ef 100644 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -33,7 +33,7 @@ This README file contains the history of stable GEOSldas Releases in Git, follow Overview of Git Releases: ============================ -[v18.0.0](https://github.com/GEOS-ESM/GEOSldas/releases/tag/v18.0.0) - 2024-03-21 +[v18.0.0](https://github.com/GEOS-ESM/GEOSldas/releases/tag/v18.0.0) - 2024-03-22 ------------------------------ - 0-diff vs. v17.13.1 except for MAPL bug fix ([PR #734](https://github.com/GEOS-ESM/GEOSldas/pull/734)). @@ -79,7 +79,7 @@ Overview of Git Releases: - Added support for SLES15/Milan nodes ([PR #693](https://github.com/GEOS-ESM/GEOSldas/pull/693)). - Removed support for Haswell nodes ([PR #681](https://github.com/GEOS-ESM/GEOSldas/pull/681)). - Support for running GEOSldas at the NASA Advanced Supercomputing (NAS) facility ([PR #706](https://github.com/GEOS-ESM/GEOSldas/pull/706)). - - Allow experiment setup from another user's build ([PR #733](https://github.com/GEOS-ESM/GEOSldas/pull/733)). + - Allow experiment setup from another user's build ([PR #733](https://github.com/GEOS-ESM/GEOSldas/pull/733), [PR #740](https://github.com/GEOS-ESM/GEOSldas/pull/740)). - ESMA_env v4.23.0, Baselibs v7.16.0 ([PR #681](https://github.com/GEOS-ESM/GEOSldas/pull/681)). - ESMA_cmake v3.41.0 ([PR #725](https://github.com/GEOS-ESM/GEOSldas/pull/725)). - MAPL v2.44.1 ([PR #734](https://github.com/GEOS-ESM/GEOSldas/pull/734)). From 487c133c893dd923d83a599eedaeffbbc1379626 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Fri, 22 Mar 2024 07:49:39 -0400 Subject: [PATCH 308/308] updating components.yaml file in prep for merge into main (components.yaml) --- components.yaml | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/components.yaml b/components.yaml index 36d4d1e6..c041aafc 100644 --- a/components.yaml +++ b/components.yaml @@ -1,18 +1,15 @@ GEOSldas: fixture: true - develop: develop env: local: ./@env remote: ../ESMA_env.git tag: v4.23.0 - develop: main cmake: local: ./@cmake remote: ../ESMA_cmake.git tag: v3.41.0 - develop: develop ecbuild: local: ./@cmake/@ecbuild @@ -24,31 +21,27 @@ NCEP_Shared: remote: ../NCEP_Shared.git tag: v1.3.0 sparse: ./config/NCEP_Shared.sparse - develop: main GMAO_Shared: local: ./src/Shared/@GMAO_Shared remote: ../GMAO_Shared.git tag: v1.9.7 sparse: ./config/GMAO_Shared.sparse - develop: main GEOS_Util: local: ./src/Shared/@GMAO_Shared/@GEOS_Util remote: ../GEOS_Util.git tag: v2.0.7 sparse: ./config/GEOS_Util.sparse - develop: main MAPL: local: ./src/Shared/@MAPL remote: ../MAPL.git tag: v2.44.1 - develop: develop GEOSgcm_GridComp: local: ./src/Components/GEOSldas_GridComp/@GEOSgcm_GridComp remote: ../GEOSgcm_GridComp.git - branch: develop + tag: v2.5.2 sparse: ./config/GEOSgcm_GridComp_ldas.sparse - develop: develop +