From 5cec2190f59624e36079602f6cc24e5b7fca4582 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Thu, 31 Oct 2024 10:39:30 -0600 Subject: [PATCH 001/107] add snow to update type 13 --- .../clsm_ensupd_upd_routines.F90 | 245 ++++++++++++++++-- 1 file changed, 222 insertions(+), 23 deletions(-) diff --git a/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index c8398b61..e7dd848a 100644 --- a/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -3524,6 +3524,7 @@ subroutine cat_enkf_increments( & real, dimension( N_catd) :: SWE_ensavg real, dimension( N_catd) :: tp1_ensavg real, dimension( N_catd) :: asnow_ensavg + real, dimension( N_catd) :: swe_incr_ensavg type(obs_param_type) :: this_obs_param @@ -3537,7 +3538,7 @@ subroutine cat_enkf_increments( & real, dimension(N_snow) :: tpsn, fice_snow_vec ! for snow model relayer real, dimension(N_snow,N_constit) :: rconstit - logical :: found_Tb_obs + logical :: found_Tb_obs, unique, has_asnow ! ----------------------------------------------------------------------- @@ -4690,31 +4691,228 @@ subroutine cat_enkf_increments( & if (logit) write (logunit,*) 'get 3d soil moisture/Tskin/ght(1) increments; Tb+sfmc obs' - N_select_varnames = 0 - - do ii = 1,N_obs_param - if (trim(obs_param(ii)%varname) == 'Tb') then + N_select_varnames = 0 + + do ii = 1, N_obs_param + unique = .true. + do jj = 1, N_select_varnames + if (trim(obs_param(ii)%varname) == trim(select_varnames(jj))) then + unique = .false. + exit + end if + end do + if (unique) then N_select_varnames = N_select_varnames + 1 - select_varnames(N_select_varnames) = 'Tb' - exit + select_varnames(N_select_varnames) = trim(obs_param(ii)%varname) 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' + end do + + ! Check if we potentially have snow fraction observations by looking for 'asnow' in select_varnames + + do ii = 1, N_select_varnames + if (trim(select_varnames(ii)) == 'asnow') then + has_asnow = .true. exit end if - end do + 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' - exit - end if - end do + ! If we have snow fraction observations, we need to calculate the increments for the snow layers + + if (has_asnow) then + + if (logit) write (logunit, *) 'get 1d snow increments (Toure et al. 2018 empirical gain); snow cover fraction obs' + + ! 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') + + ! 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 ) + + allocate(select_tilenum(1)) + + swe_incr = 0. ! total SWE increment; initialize to NO CHANGE + swe_incr_ensavg = 0. ! total SWE ensemble average increment; initialize to NO CHANGE + + ! loop through tiles and compute increments + + do kk=1,N_catd + + ! find observations for tile kk + + select_tilenum(1) = l2f(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 > 0) then + + ! average in case there are multiple "asnow" obs (e.g., from MODIS and VIIRS) + + 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. 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 modified eq 1 of Toure et al (2018) + + if (asnow_fcst .lt. tmp_obs * SCF_ANA_ALPHA) then + + ! ADD SNOW: Forecast SCF is less than observed SCF (after "bias" adjustment with alpha) + + swe_incr(kk,n_e) = SCF_ANA_MAXINCRSWE * (tmp_obs - asnow_fcst/SCF_ANA_ALPHA) + + 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 + + swe_incr(kk,n_e) = (-1.) * SCF_ANA_MAXINCRSWE * asnow_fcst * (1. - tmp_obs/SCF_ANA_BETA) + + else + + cycle ! NO CHANGE, skip rest of increment calcs and go straight to next ens member + + 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 + + call StieglitzSnow_calc_asnow( swe_ana, asnow_ana ) ! asnow after analysis + + 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 + end if + + ! loop through snow layers and compute SWE, snow heat content, and snow depth analysis for each layer + + do isnow=1,N_snow + + if (asnow_ana == 0.0) then + + ! no snow in analysis, remove all snow + + tmp_wesn(kk,n_e,isnow) = 0.0 + tmp_htsn(kk,n_e,isnow) = 0.0 + tmp_sndz(kk,n_e,isnow) = 0.0 + + elseif (swe_fcst < StieglitzSnow_MINSWE) then + + ! too little snow in forecast, use generic properties for added snow + + 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 ) + + tmp_htsn(kk,n_e,isnow) = (0.0 - MAPL_ALHF)*tmp_wesn(kk,n_e,isnow) + + ! assign snow depth consistent with density of freshly fallen snow (must have SCF_ANA_MAXINCRSWE<=WEMIN) + + tmp_sndz(kk,n_e,isnow) = (WEMIN / RHOFS) / N_snow + + else + + ! 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 (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) = (StieglitzSnow_CPW*snow_temp - fice_snow*MAPL_ALHF)*tmp_wesn(kk,n_e,isnow) + + ! update snow depth: + + if (asnow_ana < 1. .and. asnow_fcst < 1.) then + + ! keep snow depth constant when less than full snow cover in fcst and ana + + tmp_sndz(kk,n_e,isnow) = cat_progn(kk,n_e)%sndz(isnow) + + else + + ! compute analysis snow depth by keeping snow density constant + ! + ! in this case, it is possible that either asnow_fcst<1 or asnow_ana<1; + ! when computing density or depth, make sure that SWE value (which is per unit area) is + ! adjusted to reflect SWE value (per unit area) in the snow-covered fraction of the tile + + ! i) diagnose (layer-specific) forecast snow density + + snow_dens = ( cat_progn(kk,n_e)%wesn(isnow)/asnow_fcst ) / cat_progn(kk,n_e)%sndz(isnow) + + ! ii) diagnose analysis snow depth using forecast density + + tmp_sndz(kk,n_e,isnow) = ( tmp_wesn(kk,n_e,isnow)/asnow_ana ) / snow_dens + + end if + + end if + + 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 (call with optional args for adjustment of htsnn) + + call StieglitzSnow_relayer( N_snow, N_constit, & + 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, tpsn, fice_snow_vec ) + + ! 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. Diagnose 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 > 0) + + end do ! kk=1,N_catd + + end if ! if (has_asnow) + + ! Calculate swe_incr_ensavg as the average of the ensemble members to add to check if tile is snow-free + + swe_incr_ensavg = sum(swe_incr, dim=2) / real(N_ens) ! Will get all species associated with Tb or sfds observations @@ -4738,8 +4936,9 @@ subroutine cat_enkf_increments( & ! 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. & + (swe_incr_ensavg(kk) < SWE_threshold) .and. & + (tp1_ensavg(kk) > tp1_threshold) ) then ! find observations within halo around tile kk From b4a29c85ae4d495ece49a26321131f6753d0f938 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Sun, 3 Nov 2024 19:22:01 -0500 Subject: [PATCH 002/107] working code --- .../clsm_ensupd_enkf_update.F90 | 16 +++++++- .../clsm_ensupd_upd_routines.F90 | 41 +++++++++++++++++-- 2 files changed, 53 insertions(+), 4 deletions(-) diff --git a/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 b/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 index ea0be949..c7fce5a7 100644 --- a/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 +++ b/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 @@ -1396,7 +1396,21 @@ subroutine apply_enkf_increments( N_catd, N_ens, update_type, & cat_progn(n,n_e)%ght(1) = & cat_progn(n,n_e)%ght(1) + cat_progn_incr(n,n_e)%ght(1) - + + 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 diff --git a/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index e52aac65..5e9e8c55 100644 --- a/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -4689,7 +4689,6 @@ subroutine cat_enkf_increments( & ! ! amfox+rreichle, 26 Feb 2024 - if (logit) write (logunit,*) 'get 3d soil moisture/Tskin/ght(1) increments; Tb+sfmc obs' N_select_varnames = 0 @@ -4757,7 +4756,9 @@ subroutine cat_enkf_increments( & N_selected_obs, ind_obs ) if (N_selected_obs > 0) then - + + write(*,*) 'Doing snow DA' + ! average in case there are multiple "asnow" obs (e.g., from MODIS and VIIRS) tmp_obs = sum(Observations(ind_obs(1:N_selected_obs))%obs) @@ -4795,7 +4796,9 @@ 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 - + + write (*,*) 'swe_incr(kk,n_e): ',swe_incr(kk,n_e) + call StieglitzSnow_calc_asnow( swe_ana, asnow_ana ) ! asnow after analysis if (swe_fcst>=StieglitzSnow_MINSWE) then @@ -4915,12 +4918,40 @@ subroutine cat_enkf_increments( & swe_incr_ensavg = sum(swe_incr, dim=2) / real(N_ens) ! Will get all species associated with Tb or sfds observations + + 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' + 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' + 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' + exit + end if + end do + 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 + + if (logit) write (logunit,*) 'get 3d soil moisture/Tskin/ght(1) increments; Tb+sfmc obs' call get_select_species(1, 'Tb', N_obs_param, obs_param, N_select_species_Tb, select_species_Tb ) @@ -4963,6 +4994,8 @@ subroutine cat_enkf_increments( & if (N_selected_obs>0) then + write(*,*) 'Doing SM DA' + ! Determine if Tb observations are present found_Tb_obs = .false. @@ -5079,6 +5112,8 @@ subroutine cat_enkf_increments( & cat_progn_incr(kk,:)%ght(1) = State_incr(7,:)*scale_ght1 end if + + write (*,*) 'State_incr: ', State_incr(1,1) end if From 995a414d2e487c3eaf5cb6385d3944d491d58413 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Wed, 6 Nov 2024 17:48:36 -0700 Subject: [PATCH 003/107] single do loop --- .../clsm_ensupd_upd_routines.F90 | 495 +++++++++--------- 1 file changed, 240 insertions(+), 255 deletions(-) diff --git a/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index 5e9e8c55..dbb144ed 100644 --- a/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -3478,7 +3478,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_select_species_Tb + integer :: N_state_max, N_state, N_selected_obs, N_select_varnames, N_select_species, N_select_species_Tb, N_select_species_asnow real :: halo_minlon, halo_maxlon, halo_minlat, halo_maxlat real :: tmp_minlon, tmp_maxlon, tmp_minlat, tmp_maxlat @@ -3495,7 +3495,7 @@ subroutine cat_enkf_increments( & real, allocatable, dimension(:) :: State_lon, State_lat - integer, dimension(N_obs_param) :: select_species, select_species_Tb ! alloc max possible length + integer, dimension(N_obs_param) :: select_species, select_species_Tb, select_species_asnow ! alloc max possible length character(40), dimension(N_obs_param) :: select_varnames ! alloc max possible length @@ -3538,7 +3538,7 @@ subroutine cat_enkf_increments( & real, dimension(N_snow) :: tpsn, fice_snow_vec ! for snow model relayer real, dimension(N_snow,N_constit) :: rconstit - logical :: found_Tb_obs, unique, has_asnow + logical :: found_Tb_obs, unique, has_asnow, has_Tb, has_sfmc, has_sfds ! ----------------------------------------------------------------------- @@ -3564,6 +3564,8 @@ subroutine cat_enkf_increments( & select_varnames = '' select_species = -8888 ! intentionally differs from init in get_select_species() + select_species_Tb = -8888 ! intentionally differs from init in get_select_species() + select_species_asnow = -8888 ! intentionally differs from init in get_select_species() ! ---------------------------------------------------------------------- ! @@ -4688,34 +4690,67 @@ subroutine cat_enkf_increments( & ! sfcm/sfds & Tb | peat | 7 | srfexc, rzexc, catdef, tc[x], ght(1) ! ! amfox+rreichle, 26 Feb 2024 + + ! Figure out what types of observtion we have - - N_select_varnames = 0 - - do ii = 1, N_obs_param - unique = .true. - do jj = 1, N_select_varnames - if (trim(obs_param(ii)%varname) == trim(select_varnames(jj))) then - unique = .false. - exit - end if - end do - if (unique) then - N_select_varnames = N_select_varnames + 1 - select_varnames(N_select_varnames) = trim(obs_param(ii)%varname) - 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' + has_Tb = .true. + 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' + has_sfmc = .true. + exit + end if end do - ! Check if we potentially have snow fraction observations by looking for 'asnow' in select_varnames + 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' + has_sfds = .true. + exit + end if + end do - do ii = 1, N_select_varnames - if (trim(select_varnames(ii)) == 'asnow') then + do ii = 1,N_obs_param + if (trim(obs_param(ii)%varname) == 'asnow') then has_asnow = .true. - exit - end if - end do + exit + end if + end do - ! If we have snow fraction observations, we need to calculate the increments for the snow layers + ! If we have any of the soil moisture observtions we need to get the species ID + + if (N_select_varnames > 0) then ! We have soil moisture observations + + if (logit) write (logunit,*) 'get 3d soil moisture/Tskin/ght(1) increments; Tb+sfmc obs' + + call get_select_species( & + N_select_varnames, select_varnames(1:N_select_varnames), & + N_obs_param, obs_param, N_select_species, select_species ) + + ! If we have Tb observations we need to get the species ID + if (has_Tb) then + call get_select_species(1, 'Tb', N_obs_param, obs_param, N_select_species_Tb, select_species_Tb ) + end if + + N_state_max = 7 + + allocate( State_incr(N_state_max,N_ens)) + allocate( State_lon( N_state_max )) + allocate( State_lat( N_state_max )) + + end if + + ! If we have snow observations we need to get the species ID if (has_asnow) then @@ -4725,40 +4760,34 @@ subroutine cat_enkf_increments( & ! 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') - - ! 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 ) - + allocate(select_tilenum(1)) swe_incr = 0. ! total SWE increment; initialize to NO CHANGE swe_incr_ensavg = 0. ! total SWE ensemble average increment; initialize to NO CHANGE - + + call get_select_species(1, 'asnow', N_obs_param, obs_param, N_select_species_asnow, select_species_asnow ) + end if ! loop through tiles and compute increments - do kk=1,N_catd - + do kk=1,N_catd + + if (has_asnow) then + ! find observations for tile kk select_tilenum(1) = l2f(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 ) + N_obs, Observations, & + 1, select_tilenum, & + N_select_species_asnow, select_species_asnow(1:N_select_species_asnow), & + N_selected_obs, ind_obs ) if (N_selected_obs > 0) then - + write(*,*) 'Doing snow DA' - + ! average in case there are multiple "asnow" obs (e.g., from MODIS and VIIRS) tmp_obs = sum(Observations(ind_obs(1:N_selected_obs))%obs) @@ -4824,14 +4853,14 @@ subroutine cat_enkf_increments( & ! too little snow in forecast, use generic properties for added snow 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 ) - + tmp_htsn(kk,n_e,isnow) = (0.0 - MAPL_ALHF)*tmp_wesn(kk,n_e,isnow) - + ! assign snow depth consistent with density of freshly fallen snow (must have SCF_ANA_MAXINCRSWE<=WEMIN) - + tmp_sndz(kk,n_e,isnow) = (WEMIN / RHOFS) / N_snow else @@ -4841,16 +4870,16 @@ subroutine cat_enkf_increments( & ! update SWE: tmp_wesn(kk,n_e,isnow) = cat_progn(kk,n_e)%wesn(isnow) * 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. ) + snow_temp, fice_snow, log_dum, log_dum2, .false. ) tmp_htsn(kk,n_e,isnow) = (StieglitzSnow_CPW*snow_temp - fice_snow*MAPL_ALHF)*tmp_wesn(kk,n_e,isnow) ! update snow depth: - + if (asnow_ana < 1. .and. asnow_fcst < 1.) then ! keep snow depth constant when less than full snow cover in fcst and ana @@ -4870,7 +4899,7 @@ subroutine cat_enkf_increments( & snow_dens = ( cat_progn(kk,n_e)%wesn(isnow)/asnow_fcst ) / cat_progn(kk,n_e)%sndz(isnow) ! ii) diagnose analysis snow depth using forecast density - + tmp_sndz(kk,n_e,isnow) = ( tmp_wesn(kk,n_e,isnow)/asnow_ana ) / snow_dens end if @@ -4882,11 +4911,11 @@ subroutine cat_enkf_increments( & ! 4. Relayer to balance the snow column (call with optional args for adjustment of htsnn) call StieglitzSnow_relayer( N_snow, N_constit, & - 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, tpsn, fice_snow_vec ) + 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, tpsn, fice_snow_vec ) ! print the old and new swe, heat content and snow density @@ -4909,217 +4938,173 @@ subroutine cat_enkf_increments( & end if ! if (N_selected_obs > 0) - end do ! kk=1,N_catd + end if ! if (has_asnow) - end if ! if (has_asnow) + ! Calculate swe_incr_ensavg as the average of the ensemble members to add to check if tile is snow-free - ! Calculate swe_incr_ensavg as the average of the ensemble members to add to check if tile is snow-free + swe_incr_ensavg(kk) = sum((swe_incr(kk,:))) / real(N_ens) - swe_incr_ensavg = sum(swe_incr, dim=2) / real(N_ens) + if (N_select_species > 0) then ! We have soil moisture observations - ! Will get all species associated with Tb or sfds observations - - 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' - 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' - exit - end if - end do + N_state = 2 ! initialize (always have srfexc and rzexc in state vector) + + ! compute increments only for snow-free and non-frozen tiles + + if ( (SWE_ensavg(kk) < SWE_threshold) .and. & + (swe_incr_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 - 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' - exit - end if - end do + write(*,*) 'Doing SM DA' - 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 + ! Determine if Tb observations are present + + found_Tb_obs = .false. - if (logit) write (logunit,*) 'get 3d soil moisture/Tskin/ght(1) increments; Tb+sfmc obs' - - 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 = 2 ! initialize (always have srfexc and rzexc in state vector) - - ! compute increments only for snow-free and non-frozen tiles - - if ( (SWE_ensavg(kk) < SWE_threshold) .and. & - (swe_incr_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 + 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 Tb_obs are present, add tc[X] and ght(1) to state vector - write(*,*) 'Doing SM DA' + 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) + + if ( N_state==2 ) then + + State_incr(1,:) = cat_progn( kk,:)%srfexc/scale_srfexc + State_incr(2,:) = cat_progn( kk,:)%rzexc /scale_rzexc - ! Determine if Tb observations are present - - found_Tb_obs = .false. + 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 ! catdef in State + + 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,:)%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 + + 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,:)%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 + + 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 - 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 Tb_obs are present, add tc[X] and ght(1) to state vector + 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 - 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) - - 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 + + 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 + + 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,:)%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 + + 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,:)%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 + + end if - 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 ! catdef in State - - 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,:)%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 - - 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,:)%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 - - 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)) + write (*,*) 'State_incr: ', State_incr(1,1) + + end if ! if (N_selected_obs > 0) - 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 + end if ! thresholds - 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 ! catdef in State - - 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,:)%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 - - 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,:)%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 - - end if - - write (*,*) 'State_incr: ', State_incr(1,1) - - end if - - end if ! thresholds + end if ! if (N_select_species > 0) - end do + end do ! kk=1,N_catd ! ---------------------------------- From d3546c8e6666b5663fac71917aae45818fface69 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Fri, 8 Nov 2024 15:39:33 -0700 Subject: [PATCH 004/107] rename to update type 14 --- .../clsm_ensupd_enkf_update.F90 | 66 ++++-- .../clsm_ensupd_upd_routines.F90 | 218 +++++++++++++++++- 2 files changed, 267 insertions(+), 17 deletions(-) diff --git a/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 b/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 index c7fce5a7..17b598a4 100644 --- a/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 +++ b/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 @@ -1395,22 +1395,7 @@ subroutine apply_enkf_increments( N_catd, N_ens, update_type, & 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) - - 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 - - + cat_progn(n,n_e)%ght(1) + cat_progn_incr(n,n_e)%ght(1) end do end do @@ -1441,6 +1426,55 @@ subroutine apply_enkf_increments( N_catd, N_ens, update_type, & cat_progn_has_changed = .true. + case (14) select_update_type ! soil moisture, temperature and snow cover update + + ! 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' + + 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 = & + cat_progn(n,n_e)%rzexc + cat_progn_incr(n,n_e)%rzexc + cat_progn(n,n_e)%catdef = & + cat_progn(n,n_e)%catdef + cat_progn_incr(n,n_e)%catdef + + cat_progn(n,n_e)%tc1 = & + cat_progn(n,n_e)%tc1 + cat_progn_incr(n,n_e)%tc1 + cat_progn(n,n_e)%tc2 = & + 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) + + 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. + + 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') diff --git a/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index dbb144ed..ed0293b0 100644 --- a/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -4676,7 +4676,223 @@ subroutine cat_enkf_increments( & ! ---------------------------------- - case (13) select_update_type ! 3d soil moisture/Tskin/ght(1) analysis; Tb+sfmc+sfds obs + case (13) select_update_type ! 3d soil moisture/Tskin/ght(1) analysis; Tb+sfmc+sfds obs + + ! update each tile separately using all observations within customized halo around each tile + ! + ! 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' + + 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' + 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' + 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' + exit + end if + end do + + ! 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 = 2 ! initialize (always have srfexc and rzexc in state vector) + + ! compute increments only for 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 + + 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 + found_Tb_obs = .true. + exit + end if + end do + if (found_Tb_obs) exit + end do + + ! 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) + + 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 ! catdef in State + + 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,:)%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 + + 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,:)%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 + + 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==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 ! catdef in State + + 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,:)%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 + + 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,:)%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 + + end if + + end if + + end if ! thresholds + + end do + + ! ---------------------------------- + + case (14) select_update_type ! 3d soil moisture/Tskin/ght(1) analysis; Tb+sfmc+sfds obs ! update each tile separately using all observations within customized halo around each tile ! From 7d8c26b82127dc9e213c4a191fb8a246e16f741e Mon Sep 17 00:00:00 2001 From: amfox37 Date: Fri, 8 Nov 2024 19:38:15 -0500 Subject: [PATCH 005/107] add update type to check_compact_support --- GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index ed0293b0..331fd831 100644 --- a/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -5894,7 +5894,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,14) ! "3d" updates, check consistency of xcompact, ycompact ! check xcompact/ycompact against corr scales of model error From 1a678a386f2abaa9fec7d534d46c031b9ffaa6b1 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Mon, 18 Nov 2024 15:00:17 -0700 Subject: [PATCH 006/107] minor edits --- .../clsm_ensupd_upd_routines.F90 | 60 ++++++++++--------- 1 file changed, 33 insertions(+), 27 deletions(-) diff --git a/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index ed0293b0..8a40786a 100644 --- a/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -4893,9 +4893,20 @@ subroutine cat_enkf_increments( & ! ---------------------------------- case (14) select_update_type ! 3d soil moisture/Tskin/ght(1) analysis; Tb+sfmc+sfds obs + ! 1d snow analysis (Toure et al. 2018 empirical gain); snow cover fraction obs + ! this case is a combination of cases 11 and 13 + ! first, obs_param%varname is checked to determine if snow and/or soil moisture obs are potentially in the analysis + ! then, if in the analysis the species ID is determined for each type of soil moisture observation + ! if snow observations are in the analysis, the species ID is determined and the snow analysis is performed + ! finally, if soil moisture observations are in the analysis, the soil moisture analysis is performed + + ! in the case of the snow analysis: + ! update each tile separately using all observations associated with that tile + ! loops through ensemble members and compute analysis separately for each ensemble member + + ! in the case of the 3d soil moisture/Tskin/ght(1) analysis: ! update each tile separately using all observations within customized halo around each tile - ! ! state vector differs for each tile depending on assimilated obs and soil type ! ! obs | soil | N_state | state vector @@ -4941,13 +4952,11 @@ subroutine cat_enkf_increments( & has_asnow = .true. exit end if - end do + end do ! If we have any of the soil moisture observtions we need to get the species ID - if (N_select_varnames > 0) then ! We have soil moisture observations - - if (logit) write (logunit,*) 'get 3d soil moisture/Tskin/ght(1) increments; Tb+sfmc obs' + if (has_Tb .or. has_sfmc .or. has_sfds) then ! We have soil moisture observations call get_select_species( & N_select_varnames, select_varnames(1:N_select_varnames), & @@ -4982,27 +4991,28 @@ subroutine cat_enkf_increments( & swe_incr = 0. ! total SWE increment; initialize to NO CHANGE swe_incr_ensavg = 0. ! total SWE ensemble average increment; initialize to NO CHANGE - call get_select_species(1, 'asnow', N_obs_param, obs_param, N_select_species_asnow, select_species_asnow ) + call get_select_species(1, 'asnow', N_obs_param, obs_param, N_select_species_asnow, select_species_asnow ) + end if - ! loop through tiles and compute increments + + ! loop through tiles and compute increments do kk=1,N_catd if (has_asnow) then - ! find observations for tile kk + ! find snow observations for tile kk select_tilenum(1) = l2f(kk) - call get_ind_obs( & - N_obs, Observations, & - 1, select_tilenum, & - N_select_species_asnow, select_species_asnow(1:N_select_species_asnow), & + call get_ind_obs( & + N_obs, Observations, & + 1, select_tilenum, & + N_select_species_asnow, & + select_species_asnow(1:N_select_species_asnow), & N_selected_obs, ind_obs ) if (N_selected_obs > 0) then - - write(*,*) 'Doing snow DA' ! average in case there are multiple "asnow" obs (e.g., from MODIS and VIIRS) @@ -5041,8 +5051,6 @@ 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 - - write (*,*) 'swe_incr(kk,n_e): ',swe_incr(kk,n_e) call StieglitzSnow_calc_asnow( swe_ana, asnow_ana ) ! asnow after analysis @@ -5160,13 +5168,15 @@ subroutine cat_enkf_increments( & swe_incr_ensavg(kk) = sum((swe_incr(kk,:))) / real(N_ens) - if (N_select_species > 0) then ! We have soil moisture observations + if (has_Tb .or. has_sfmc .or. has_sfds) then ! Have soil moisture observations + + if (logit) write (logunit,*) 'get 3d soil moisture/Tskin/ght(1) increments; Tb+sfmc obs' N_state = 2 ! initialize (always have srfexc and rzexc in state vector) ! compute increments only for snow-free and non-frozen tiles - if ( (SWE_ensavg(kk) < SWE_threshold) .and. & + if ( (SWE_ensavg(kk) < SWE_threshold) .and. & (swe_incr_ensavg(kk) < SWE_threshold) .and. & (tp1_ensavg(kk) > tp1_threshold) ) then @@ -5185,16 +5195,14 @@ subroutine cat_enkf_increments( & halo_minlat = max(halo_minlat, -90.) halo_maxlat = min(halo_maxlat, 90.) - call get_ind_obs_lat_lon_box( & - N_obs, Observations, & + 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 - write(*,*) 'Doing SM DA' - ! Determine if Tb observations are present found_Tb_obs = .false. @@ -5262,7 +5270,7 @@ 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 ) - call enkf_increments( & + 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),:), & @@ -5311,14 +5319,12 @@ subroutine cat_enkf_increments( & cat_progn_incr(kk,:)%ght(1) = State_incr(7,:)*scale_ght1 end if - - write (*,*) 'State_incr: ', State_incr(1,1) - end if ! if (N_selected_obs > 0) + end if ! if (N_selected_obs > 0) end if ! thresholds - end if ! if (N_select_species > 0) + end if ! if (have soil moisture observations) end do ! kk=1,N_catd From d94d405030fbf51a4aebf374899516f8ee16d8d7 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Mon, 18 Nov 2024 16:24:54 -0700 Subject: [PATCH 007/107] edit comments --- GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index 3418ffa5..012305d8 100644 --- a/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -4896,10 +4896,12 @@ subroutine cat_enkf_increments( & ! 1d snow analysis (Toure et al. 2018 empirical gain); snow cover fraction obs ! this case is a combination of cases 11 and 13 - ! first, obs_param%varname is checked to determine if snow and/or soil moisture obs are potentially in the analysis - ! then, if in the analysis the species ID is determined for each type of soil moisture observation - ! if snow observations are in the analysis, the species ID is determined and the snow analysis is performed - ! finally, if soil moisture observations are in the analysis, the soil moisture analysis is performed + ! 1. obs_param%varname is checked to determine if snow and/or soil moisture obs are potentially in the analysis + ! 2. if sm obs are in the analysis the species ID is determined for each type + ! 3. if snow observations are in the analysis, their species ID is determined + ! 4. start looping through all the tiles + ! 5. if snow obs are in the analysis, check for snow obs with each tile, and if found perform the snow analysis + ! 6. if sm obs are in the analysis, check for SM obs around each tile, and if found perform sm analysis ! in the case of the snow analysis: ! update each tile separately using all observations associated with that tile From aa4c6013ebf5ba1a954996f76f73f10082a9f427 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Mon, 18 Nov 2024 17:19:47 -0700 Subject: [PATCH 008/107] update log message when adding increments --- GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 b/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 index 17b598a4..1929ccd0 100644 --- a/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 +++ b/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 @@ -1433,7 +1433,7 @@ subroutine apply_enkf_increments( N_catd, N_ens, update_type, & ! 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' + 'apply_enkf_increments(): applying soil moisture, Tskin/ght1 and snow increments' do n=1,N_catd do n_e=1,N_ens From fdf417fa1e7c95938cecf4df6138be40fe910735 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Mon, 18 Nov 2024 17:25:23 -0700 Subject: [PATCH 009/107] try to fix white space change --- GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index 012305d8..10a2a327 100644 --- a/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -4675,7 +4675,7 @@ subroutine cat_enkf_increments( & end do ! kk=1,N_catd ! ---------------------------------- - + case (13) select_update_type ! 3d soil moisture/Tskin/ght(1) analysis; Tb+sfmc+sfds obs ! update each tile separately using all observations within customized halo around each tile From 321f5e9e3353627748d0fbb0982268bf8ab1e661 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Mon, 18 Nov 2024 18:07:55 -0700 Subject: [PATCH 010/107] try to fix to enable easy Github diff --- .../clsm_ensupd_upd_routines.F90 | 436 +++++++++--------- 1 file changed, 218 insertions(+), 218 deletions(-) diff --git a/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index 10a2a327..12b6a8a5 100644 --- a/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -3524,7 +3524,7 @@ subroutine cat_enkf_increments( & real, dimension( N_catd) :: SWE_ensavg real, dimension( N_catd) :: tp1_ensavg real, dimension( N_catd) :: asnow_ensavg - real, dimension( N_catd) :: swe_incr_ensavg + real, dimension( N_catd) :: swe_incr_ensavg type(obs_param_type) :: this_obs_param @@ -3538,7 +3538,7 @@ subroutine cat_enkf_increments( & real, dimension(N_snow) :: tpsn, fice_snow_vec ! for snow model relayer real, dimension(N_snow,N_constit) :: rconstit - logical :: found_Tb_obs, unique, has_asnow, has_Tb, has_sfmc, has_sfds + logical :: found_Tb_obs, has_asnow, has_Tb, has_sfmc, has_sfds ! ----------------------------------------------------------------------- @@ -3564,8 +3564,8 @@ subroutine cat_enkf_increments( & select_varnames = '' select_species = -8888 ! intentionally differs from init in get_select_species() - select_species_Tb = -8888 ! intentionally differs from init in get_select_species() - select_species_asnow = -8888 ! intentionally differs from init in get_select_species() + select_species_Tb = -8888 + select_species_asnow = -8888 ! ---------------------------------------------------------------------- ! @@ -4675,221 +4675,221 @@ subroutine cat_enkf_increments( & end do ! kk=1,N_catd ! ---------------------------------- - - case (13) select_update_type ! 3d soil moisture/Tskin/ght(1) analysis; Tb+sfmc+sfds obs - - ! update each tile separately using all observations within customized halo around each tile - ! - ! 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' - - 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' - 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' - 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' - exit - end if - end do - - ! 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 )) + + case (13) select_update_type ! 3d soil moisture/Tskin/ght(1) analysis; Tb+sfmc+sfds obs + + ! update each tile separately using all observations within customized halo around each tile + ! + ! 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' + + 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' + exit + end if + end do - do kk=1,N_catd - - N_state = 2 ! initialize (always have srfexc and rzexc in state vector) - - ! compute increments only for 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 - - 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 - found_Tb_obs = .true. - exit - end if - end do - if (found_Tb_obs) exit - end do - - ! 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) - - 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 ! catdef in State - - 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,:)%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 - - 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,:)%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 - - 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==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 ! catdef in State - - 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,:)%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 - - 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,:)%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 - - end if - - end if + 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' + 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' + exit + end if + end do + + ! 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 = 2 ! initialize (always have srfexc and rzexc in state vector) + + ! compute increments only for 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 + + 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 + found_Tb_obs = .true. + exit + end if + end do + if (found_Tb_obs) exit + end do + + ! 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) + + 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 ! catdef in State + + 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,:)%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 + + 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,:)%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 + + 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==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 ! catdef in State + + 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,:)%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 + + 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,:)%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 + + end if + + end if + + end if ! thresholds + + end do + ! ---------------------------------- case (14) select_update_type ! 3d soil moisture/Tskin/ght(1) analysis; Tb+sfmc+sfds obs @@ -5331,7 +5331,7 @@ subroutine cat_enkf_increments( & end do ! kk=1,N_catd ! ---------------------------------- - + case default call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'unknown update_type') From 541508919d37107bd2c749b9dec0a4fe13713515 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Tue, 26 Nov 2024 16:51:50 -0500 Subject: [PATCH 011/107] add obs_param%assim logical --- GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index 12b6a8a5..5104e6f0 100644 --- a/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -4918,12 +4918,12 @@ subroutine cat_enkf_increments( & ! 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 + ! amfox+rreichle, Dec 2024 ! Figure out what types of observtion we have do ii = 1,N_obs_param - if (trim(obs_param(ii)%varname) == 'Tb') then + if (trim(obs_param(ii)%varname) == 'Tb' .and. obs_param(ii)%assim) then N_select_varnames = N_select_varnames + 1 select_varnames(N_select_varnames) = 'Tb' has_Tb = .true. @@ -4932,7 +4932,7 @@ subroutine cat_enkf_increments( & end do do ii = 1,N_obs_param - if (trim(obs_param(ii)%varname) == 'sfmc') then + if (trim(obs_param(ii)%varname) == 'sfmc' .and. obs_param(ii)%assim) then N_select_varnames = N_select_varnames + 1 select_varnames(N_select_varnames) = 'sfmc' has_sfmc = .true. @@ -4941,7 +4941,7 @@ subroutine cat_enkf_increments( & end do do ii = 1,N_obs_param - if (trim(obs_param(ii)%varname) == 'sfds') then + if (trim(obs_param(ii)%varname) == 'sfds' .and. obs_param(ii)%assim) then N_select_varnames = N_select_varnames + 1 select_varnames(N_select_varnames) = 'sfds' has_sfds = .true. @@ -4950,7 +4950,7 @@ subroutine cat_enkf_increments( & end do do ii = 1,N_obs_param - if (trim(obs_param(ii)%varname) == 'asnow') then + if (trim(obs_param(ii)%varname) == 'asnow' .and. obs_param(ii)%assim) then has_asnow = .true. exit end if From 1f7f6a6bdb0419f40ba26f4fc57d0be9252eb1c1 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Tue, 26 Nov 2024 16:01:36 -0700 Subject: [PATCH 012/107] add update types 11 and 14 description to default nml --- GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml b/GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml index ece206c4..53e428f7 100644 --- a/GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml +++ b/GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml @@ -34,7 +34,10 @@ ! 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: 1d snow analysis (Toure et al. 2018 empirical gain); SCF obs ! update_type = 13: 3d soil moisture/Tskin/ght(1) excl. catdef unless PEATCLSM tile; sfmc and TB obs +! update_type = 14: 3d soil moisture/Tskin/ght(1) excl. catdef unless PEATCLSM tile & +! 1d snow analysis (Toure et al. 2018 empirical gain); sfmc, TB and SCF obs update_type = 0 From 13e5f63062aa72fd38117551f1c9dda47627a0b6 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Fri, 29 Nov 2024 14:37:08 -0500 Subject: [PATCH 013/107] edited new update_type for soil moisture, soil temperature, and snow analysis: - changed number associated with update_type 14 --> 12 - modified "check_snow" (maintains 0-diff for update_type=10 only!) - simplified how species of interest are obtained - added check of consistency between update_type and obs_param%assim - additional clean-up (log messages, indentation) --- .../clsm_ensupd_enkf_update.F90 | 54 +- .../clsm_ensupd_upd_routines.F90 | 890 +++++++++--------- GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml | 35 +- 3 files changed, 489 insertions(+), 490 deletions(-) diff --git a/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 b/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 index 1929ccd0..65e762a2 100644 --- a/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 +++ b/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 @@ -1339,6 +1339,8 @@ subroutine apply_enkf_increments( N_catd, N_ens, update_type, & cat_progn_has_changed = .false. + ! ------------------------------------------------------------------ + case (4,7) select_update_type ! Tskin/ght1 update if (logit) write (logunit,*) & @@ -1361,6 +1363,8 @@ subroutine apply_enkf_increments( N_catd, N_ens, update_type, & cat_progn_has_changed = .true. + ! ------------------------------------------------------------------ + case (5) select_update_type ! Tskin/ght1 update if (logit) write (logunit,*) & @@ -1368,6 +1372,8 @@ subroutine apply_enkf_increments( N_catd, N_ens, update_type, & cat_progn_has_changed = .false. + ! ------------------------------------------------------------------ + case (6,8,9,10,13) select_update_type ! soil moisture and temperature update ! some of the increments fields below may be zero by design @@ -1401,13 +1407,21 @@ 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 + if (select_update_type==10) then + + check_snow = .false. ! turn off for now to maintain 0-diff w/ SMAP Tb DA test case - case(11) select_update_type ! empirical MODIS SCF update + end if + + ! ------------------------------------------------------------------ + + case(11) select_update_type ! snow update - do n=1,N_catd ! for each tile + if (logit) write (logunit,*) 'apply_enkf_increments(): applying snow increments' + + do n=1,N_catd ! for each tile - do n_e=1,N_ens ! for each ensemble member + do n_e=1,N_ens ! for each ensemble member do ii=1,N_snow ! for each snow layer @@ -1426,7 +1440,9 @@ subroutine apply_enkf_increments( N_catd, N_ens, update_type, & cat_progn_has_changed = .true. - case (14) select_update_type ! soil moisture, temperature and snow cover update + ! ------------------------------------------------------------------ + + case (12) select_update_type ! soil moisture, temperature, and snow update ! 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; @@ -1455,26 +1471,26 @@ subroutine apply_enkf_increments( N_catd, N_ens, update_type, & cat_progn(n,n_e)%ght(1) = & cat_progn(n,n_e)%ght(1) + cat_progn_incr(n,n_e)%ght(1) - 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 + 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. - 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') diff --git a/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index 5104e6f0..95bad86c 100644 --- a/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -3478,7 +3478,8 @@ 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_select_species_Tb, N_select_species_asnow + integer :: N_state_max, N_state, N_selected_obs, N_select_varnames + integer :: N_select_species, N_select_species_smTb, N_select_species_Tb, N_select_species_asnow real :: halo_minlon, halo_maxlon, halo_minlat, halo_maxlat real :: tmp_minlon, tmp_maxlon, tmp_minlat, tmp_maxlat @@ -3495,7 +3496,8 @@ subroutine cat_enkf_increments( & real, allocatable, dimension(:) :: State_lon, State_lat - integer, dimension(N_obs_param) :: select_species, select_species_Tb, select_species_asnow ! alloc max possible length + integer, dimension(N_obs_param) :: select_species ! alloc max possible length + integer, dimension(N_obs_param) :: select_species_smTb, select_species_Tb, select_species_asnow ! alloc max possible length character(40), dimension(N_obs_param) :: select_varnames ! alloc max possible length @@ -3538,7 +3540,7 @@ subroutine cat_enkf_increments( & real, dimension(N_snow) :: tpsn, fice_snow_vec ! for snow model relayer real, dimension(N_snow,N_constit) :: rconstit - logical :: found_Tb_obs, has_asnow, has_Tb, has_sfmc, has_sfds + logical :: found_Tb_obs ! ----------------------------------------------------------------------- @@ -3559,13 +3561,19 @@ subroutine cat_enkf_increments( & ! more initializations - N_select_varnames = 0 - N_select_species = 0 + N_select_varnames = 0 - select_varnames = '' - select_species = -8888 ! intentionally differs from init in get_select_species() - select_species_Tb = -8888 - select_species_asnow = -8888 + N_select_species = 0 + N_select_species_smTb = 0 + N_select_species_Tb = 0 + N_select_species_asnow = 0 + + select_varnames = '' + + select_species = -8888 ! intentionally differs from init in get_select_species() + select_species_smTb = -8888 + select_species_Tb = -8888 + select_species_asnow = -8888 ! ---------------------------------------------------------------------- ! @@ -3740,6 +3748,8 @@ subroutine cat_enkf_increments( & end do + ! ---------------------------------------------------------------------------------------------------------------------- + case (2) select_update_type ! 3d soil moisture analysis; sfmc+sfds obs ! update each tile separately using all observations within @@ -3829,7 +3839,7 @@ subroutine cat_enkf_increments( & end do - ! ---------------------------------- + ! ---------------------------------------------------------------------------------------------------------------------- case (3) select_update_type ! 1d Tskin analysis; tskin obs @@ -3900,7 +3910,7 @@ subroutine cat_enkf_increments( & end do - ! ---------------------------------- + ! ---------------------------------------------------------------------------------------------------------------------- case (4,5) select_update_type ! 1d Tskin/ght(1) analysis; tskin obs @@ -3974,7 +3984,7 @@ subroutine cat_enkf_increments( & end do - ! ---------------------------------- + ! ---------------------------------------------------------------------------------------------------------------------- case (6) select_update_type ! 1d soil moisture/Tskin/ght(1) analysis; Tb obs @@ -4053,7 +4063,7 @@ subroutine cat_enkf_increments( & end do - ! ---------------------------------- + ! ---------------------------------------------------------------------------------------------------------------------- case (7) select_update_type ! 3d Tskin/ght(1) analysis; tskin obs @@ -4144,7 +4154,7 @@ subroutine cat_enkf_increments( & end do - ! ---------------------------------- + ! ---------------------------------------------------------------------------------------------------------------------- case (8,10) select_update_type ! 3d soil moisture/Tskin/ght(1) analysis; Tb obs @@ -4302,7 +4312,7 @@ subroutine cat_enkf_increments( & end do - ! ---------------------------------- + ! ---------------------------------------------------------------------------------------------------------------------- case (9) select_update_type ! 1d Tskin/ght(1) analysis; FT obs @@ -4483,7 +4493,7 @@ subroutine cat_enkf_increments( & end do - ! ---------------------------------- + ! ---------------------------------------------------------------------------------------------------------------------- case (11) select_update_type ! 1d snow analysis (Toure et al. 2018 empirical gain); snow cover fraction obs @@ -4674,7 +4684,7 @@ subroutine cat_enkf_increments( & end do ! kk=1,N_catd - ! ---------------------------------- + ! ---------------------------------------------------------------------------------------------------------------------- case (13) select_update_type ! 3d soil moisture/Tskin/ght(1) analysis; Tb+sfmc+sfds obs @@ -4691,35 +4701,15 @@ subroutine cat_enkf_increments( & ! ! amfox+rreichle, 26 Feb 2024 - if (logit) write (logunit,*) 'get 3d soil moisture/Tskin/ght(1) increments; Tb+sfmc obs' + if (logit) write (logunit,*) 'get 3d soil moisture/Tskin/ght(1) increments; Tb+sfmc+sfds obs' - 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' - 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' - exit - end if - end do + ! Get all species associated with *assimilated* Tb, sfmc, and sfds observations - 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' - exit - end if - end do + N_select_varnames = 3 - ! Will get all species associated with Tb or sfds observations + select_varnames(1) = 'Tb' + select_varnames(2) = 'sfmc' + select_varnames(3) = 'sfds' call get_select_species( & N_select_varnames, select_varnames(1:N_select_varnames), & @@ -4890,389 +4880,374 @@ subroutine cat_enkf_increments( & end do - ! ---------------------------------- - - case (14) select_update_type ! 3d soil moisture/Tskin/ght(1) analysis; Tb+sfmc+sfds obs - ! 1d snow analysis (Toure et al. 2018 empirical gain); snow cover fraction obs + ! ---------------------------------------------------------------------------------------------------------------------- - ! this case is a combination of cases 11 and 13 - ! 1. obs_param%varname is checked to determine if snow and/or soil moisture obs are potentially in the analysis - ! 2. if sm obs are in the analysis the species ID is determined for each type - ! 3. if snow observations are in the analysis, their species ID is determined - ! 4. start looping through all the tiles - ! 5. if snow obs are in the analysis, check for snow obs with each tile, and if found perform the snow analysis - ! 6. if sm obs are in the analysis, check for SM obs around each tile, and if found perform sm analysis + case (12) select_update_type ! 3d soil moisture/Tskin/ght(1) analysis; Tb+sfmc+sfds obs + ! & 1d snow analysis (Toure et al. 2018 empirical gain); snow cover fraction obs - ! in the case of the snow analysis: - ! update each tile separately using all observations associated with that tile - ! loops through ensemble members and compute analysis separately for each ensemble member - - ! in the case of the 3d soil moisture/Tskin/ght(1) analysis: - ! update each tile separately using all observations within customized halo around each tile - ! state vector differs for each tile depending on assimilated obs and soil type + ! update_type 12 is a combination of update_type 11 and update_type 13: ! - ! 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) + ! Loop through tiles, first apply 1d snow update, then apply 3d soil moisture update. + ! + ! 1d snow analysis: + ! Update each tile separately using all observations associated with the tile. + ! Loop through ensemble members and compute analysis separately for each ensemble member. + ! + ! 3d soil moisture/Tskin/ght(1) analysis: + ! Update each tile separately using all observations within customized halo around the tile. + ! State vector of each tile depends 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, Dec 2024 + ! + ! ------------------------------------------------------------------------------------------------------- - ! Figure out what types of observtion we have + if (logit) write (logunit, *) 'get increments: update_type = ', select_update_type - do ii = 1,N_obs_param - if (trim(obs_param(ii)%varname) == 'Tb' .and. obs_param(ii)%assim) then - N_select_varnames = N_select_varnames + 1 - select_varnames(N_select_varnames) = 'Tb' - has_Tb = .true. - exit - end if - end do - - do ii = 1,N_obs_param - if (trim(obs_param(ii)%varname) == 'sfmc' .and. obs_param(ii)%assim) then - N_select_varnames = N_select_varnames + 1 - select_varnames(N_select_varnames) = 'sfmc' - has_sfmc = .true. - exit - end if - end do - - do ii = 1,N_obs_param - if (trim(obs_param(ii)%varname) == 'sfds' .and. obs_param(ii)%assim) then - N_select_varnames = N_select_varnames + 1 - select_varnames(N_select_varnames) = 'sfds' - has_sfds = .true. - exit - end if - end do - - do ii = 1,N_obs_param - if (trim(obs_param(ii)%varname) == 'asnow' .and. obs_param(ii)%assim) then - has_asnow = .true. - exit - end if - end do - - ! If we have any of the soil moisture observtions we need to get the species ID - - if (has_Tb .or. has_sfmc .or. has_sfds) then ! We have soil moisture observations - - call get_select_species( & - N_select_varnames, select_varnames(1:N_select_varnames), & - N_obs_param, obs_param, N_select_species, select_species ) - - ! If we have Tb observations we need to get the species ID - if (has_Tb) then - call get_select_species(1, 'Tb', N_obs_param, obs_param, N_select_species_Tb, select_species_Tb ) - end if - - N_state_max = 7 - - allocate( State_incr(N_state_max,N_ens)) - allocate( State_lon( N_state_max )) - allocate( State_lat( N_state_max )) - - end if - - ! If we have snow observations we need to get the species ID - - if (has_asnow) then - - if (logit) write (logunit, *) 'get 1d snow increments (Toure et al. 2018 empirical gain); snow cover fraction obs' + ! determine species of assimilated obs associated with snow analysis - ! 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') - - allocate(select_tilenum(1)) + call get_select_species(1, 'asnow', N_obs_param, obs_param, N_select_species_asnow, select_species_asnow ) + + if (N_select_species_asnow>0) then + + if (logit) write (logunit, *) '- get 1d snow increments (Toure et al. 2018 empirical gain); snow cover fraction obs' + + ! 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') + + allocate(select_tilenum(1)) + + swe_incr = 0. ! total SWE increment; initialize to NO CHANGE + swe_incr_ensavg = 0. ! total SWE ensemble average increment; initialize to NO CHANGE - swe_incr = 0. ! total SWE increment; initialize to NO CHANGE - swe_incr_ensavg = 0. ! total SWE ensemble average increment; initialize to NO CHANGE - - call get_select_species(1, 'asnow', N_obs_param, obs_param, N_select_species_asnow, select_species_asnow ) - - end if + + end if + + ! determine species of assimilated obs associated with soil moisture (+Tskin/ght(1)) analysis: + + N_select_varnames = 3 + + select_varnames(1) = 'Tb' + select_varnames(2) = 'sfmc' + select_varnames(3) = 'sfds' + + call get_select_species( & + N_select_varnames, select_varnames(1:N_select_varnames), & + N_obs_param, obs_param, N_select_species_smTb, select_species_smTb ) + + ! determine which species are Tb, if any + + call get_select_species(1, 'Tb', N_obs_param, obs_param, N_select_species_Tb, select_species_Tb ) + + if (N_select_species_smTb>0) then + + if (logit) write (logunit, *) '- get 1d snow increments (Toure et al. 2018 empirical gain); snow cover fraction obs' + + end if - ! loop through tiles and compute increments - - do kk=1,N_catd + ! check consistency of update_type and obs_param%assim config + + if ( N_select_species_asnow==0 .and. N_select_species_smTb==0 ) then + + call ldas_abort(LDAS_GENERIC_ERROR, Iam, & + 'update_type inconsistent with obs_param%assim==.false. for all asnow/Tb/sfmc/sfds species') + + end if + + ! allocate State_* - if (has_asnow) then - - ! find snow observations for tile kk - - select_tilenum(1) = l2f(kk) - - call get_ind_obs( & + N_state_max = 7 + + allocate( State_incr(N_state_max,N_ens)) + allocate( State_lon( N_state_max )) + allocate( State_lat( N_state_max )) + + ! ---------------------------------------------------- + ! + ! loop through tiles and compute increments + + do kk=1,N_catd + + if (N_select_species_asnow>0) then ! assimilate snow observations + + ! find snow observations for tile kk + + select_tilenum(1) = l2f(kk) + + call get_ind_obs( & N_obs, Observations, & 1, select_tilenum, & N_select_species_asnow, & select_species_asnow(1:N_select_species_asnow), & N_selected_obs, ind_obs ) - - if (N_selected_obs > 0) then - - ! average in case there are multiple "asnow" obs (e.g., from MODIS and VIIRS) - - 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. 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 modified eq 1 of Toure et al (2018) - - if (asnow_fcst .lt. tmp_obs * SCF_ANA_ALPHA) then - - ! ADD SNOW: Forecast SCF is less than observed SCF (after "bias" adjustment with alpha) - - swe_incr(kk,n_e) = SCF_ANA_MAXINCRSWE * (tmp_obs - asnow_fcst/SCF_ANA_ALPHA) - - 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 - - swe_incr(kk,n_e) = (-1.) * SCF_ANA_MAXINCRSWE * asnow_fcst * (1. - tmp_obs/SCF_ANA_BETA) - - else - - cycle ! NO CHANGE, skip rest of increment calcs and go straight to next ens member - - 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 - - call StieglitzSnow_calc_asnow( swe_ana, asnow_ana ) ! asnow after analysis - - 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 - end if - - ! loop through snow layers and compute SWE, snow heat content, and snow depth analysis for each layer - - do isnow=1,N_snow - - if (asnow_ana == 0.0) then - - ! no snow in analysis, remove all snow - - tmp_wesn(kk,n_e,isnow) = 0.0 - tmp_htsn(kk,n_e,isnow) = 0.0 - tmp_sndz(kk,n_e,isnow) = 0.0 - - elseif (swe_fcst < StieglitzSnow_MINSWE) then - - ! too little snow in forecast, use generic properties for added snow - - 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 ) - - tmp_htsn(kk,n_e,isnow) = (0.0 - MAPL_ALHF)*tmp_wesn(kk,n_e,isnow) - - ! assign snow depth consistent with density of freshly fallen snow (must have SCF_ANA_MAXINCRSWE<=WEMIN) - - tmp_sndz(kk,n_e,isnow) = (WEMIN / RHOFS) / N_snow - - else - - ! 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 (keep snow temperature constant): - - call StieglitzSnow_calc_tpsnow( cat_progn(kk,n_e)%htsn(isnow), cat_progn(kk,n_e)%wesn(isnow), & + + if (N_selected_obs > 0) then + + ! average in case there are multiple "asnow" obs (e.g., from MODIS and VIIRS) + + 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. 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 modified eq 1 of Toure et al (2018) + + if (asnow_fcst .lt. tmp_obs * SCF_ANA_ALPHA) then + + ! ADD SNOW: Forecast SCF is less than observed SCF (after "bias" adjustment with alpha) + + swe_incr(kk,n_e) = SCF_ANA_MAXINCRSWE * (tmp_obs - asnow_fcst/SCF_ANA_ALPHA) + + 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 + + swe_incr(kk,n_e) = (-1.) * SCF_ANA_MAXINCRSWE * asnow_fcst * (1. - tmp_obs/SCF_ANA_BETA) + + else + + cycle ! NO CHANGE, skip rest of increment calcs and go straight to next ens member + + 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 + + call StieglitzSnow_calc_asnow( swe_ana, asnow_ana ) ! asnow after analysis + + 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 + end if + + ! loop through snow layers and compute SWE, snow heat content, and snow depth analysis for each layer + + do isnow=1,N_snow + + if (asnow_ana == 0.0) then + + ! no snow in analysis, remove all snow + + tmp_wesn(kk,n_e,isnow) = 0.0 + tmp_htsn(kk,n_e,isnow) = 0.0 + tmp_sndz(kk,n_e,isnow) = 0.0 + + elseif (swe_fcst < StieglitzSnow_MINSWE) then + + ! too little snow in forecast, use generic properties for added snow + + 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 ) + + tmp_htsn(kk,n_e,isnow) = (0.0 - MAPL_ALHF)*tmp_wesn(kk,n_e,isnow) + + ! assign snow depth consistent with density of freshly fallen snow (must have SCF_ANA_MAXINCRSWE<=WEMIN) + + tmp_sndz(kk,n_e,isnow) = (WEMIN / RHOFS) / N_snow + + else + + ! 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 (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) = (StieglitzSnow_CPW*snow_temp - fice_snow*MAPL_ALHF)*tmp_wesn(kk,n_e,isnow) - - ! update snow depth: - - if (asnow_ana < 1. .and. asnow_fcst < 1.) then - - ! keep snow depth constant when less than full snow cover in fcst and ana - - tmp_sndz(kk,n_e,isnow) = cat_progn(kk,n_e)%sndz(isnow) - - else - - ! compute analysis snow depth by keeping snow density constant - ! - ! in this case, it is possible that either asnow_fcst<1 or asnow_ana<1; - ! when computing density or depth, make sure that SWE value (which is per unit area) is - ! adjusted to reflect SWE value (per unit area) in the snow-covered fraction of the tile - - ! i) diagnose (layer-specific) forecast snow density - - snow_dens = ( cat_progn(kk,n_e)%wesn(isnow)/asnow_fcst ) / cat_progn(kk,n_e)%sndz(isnow) - - ! ii) diagnose analysis snow depth using forecast density - - tmp_sndz(kk,n_e,isnow) = ( tmp_wesn(kk,n_e,isnow)/asnow_ana ) / snow_dens - - end if - - end if - - 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 (call with optional args for adjustment of htsnn) - - call StieglitzSnow_relayer( N_snow, N_constit, & + + tmp_htsn(kk,n_e,isnow) = (StieglitzSnow_CPW*snow_temp - fice_snow*MAPL_ALHF)*tmp_wesn(kk,n_e,isnow) + + ! update snow depth: + + if (asnow_ana < 1. .and. asnow_fcst < 1.) then + + ! keep snow depth constant when less than full snow cover in fcst and ana + + tmp_sndz(kk,n_e,isnow) = cat_progn(kk,n_e)%sndz(isnow) + + else + + ! compute analysis snow depth by keeping snow density constant + ! + ! in this case, it is possible that either asnow_fcst<1 or asnow_ana<1; + ! when computing density or depth, make sure that SWE value (which is per unit area) is + ! adjusted to reflect SWE value (per unit area) in the snow-covered fraction of the tile + + ! i) diagnose (layer-specific) forecast snow density + + snow_dens = ( cat_progn(kk,n_e)%wesn(isnow)/asnow_fcst ) / cat_progn(kk,n_e)%sndz(isnow) + + ! ii) diagnose analysis snow depth using forecast density + + tmp_sndz(kk,n_e,isnow) = ( tmp_wesn(kk,n_e,isnow)/asnow_ana ) / snow_dens + + end if + + end if + + 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 (call with optional args for adjustment of htsnn) + + call StieglitzSnow_relayer( N_snow, N_constit, & 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, tpsn, fice_snow_vec ) - - ! 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. Diagnose 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 > 0) - - end if ! if (has_asnow) - - ! Calculate swe_incr_ensavg as the average of the ensemble members to add to check if tile is snow-free - + + ! 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. Diagnose 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 > 0) + + end if ! if (N_select_species_asnow>0) [assimilate snow observations for tile kk] + + ! Calculate swe_incr_ensavg as the average of the ensemble members to add to check if tile is snow-free + swe_incr_ensavg(kk) = sum((swe_incr(kk,:))) / real(N_ens) + + ! ------------------------------------------------------------------------------------------ - if (has_Tb .or. has_sfmc .or. has_sfds) then ! Have soil moisture observations - - if (logit) write (logunit,*) 'get 3d soil moisture/Tskin/ght(1) increments; Tb+sfmc obs' - - N_state = 2 ! initialize (always have srfexc and rzexc in state vector) - - ! compute increments only for snow-free and non-frozen tiles - - if ( (SWE_ensavg(kk) < SWE_threshold) .and. & + if (N_select_species_smTb>0) then ! assimilate soil moisture observations + + N_state = 2 ! initialize (always have srfexc and rzexc in state vector) + + ! compute increments only for snow-free and non-frozen tiles + + if ( (SWE_ensavg(kk) < SWE_threshold) .and. & (swe_incr_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), & + + ! 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_smTb, select_species_smTb(1:N_select_species_smTb), & N_selected_obs, ind_obs ) - - if (N_selected_obs>0) then - - ! 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 - found_Tb_obs = .true. - exit - end if - end do - if (found_Tb_obs) exit - end do - - ! 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) - - 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 ! catdef in State - - 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,:)%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 - - 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,:)%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 - - 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, & + + if (N_selected_obs>0) then + + ! 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 + found_Tb_obs = .true. + exit + end if + end do + if (found_Tb_obs) exit + end do + + ! 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) + + 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 ! catdef in State + + 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,:)%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 + + 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,:)%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 + + 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( & + + 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),:), & @@ -5283,55 +5258,55 @@ subroutine cat_enkf_increments( & State_lat( 1:N_state ), & xcompact, ycompact, & fcsterr_inflation_fac ) - - deallocate(Obs_cov) - - ! assemble cat_progn increments - - 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 ! catdef in State - - 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,:)%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 - - 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,:)%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 - - end if - - end if ! if (N_selected_obs > 0) - - end if ! thresholds - - end if ! if (have soil moisture observations) + + deallocate(Obs_cov) + + ! assemble cat_progn increments + + 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 ! catdef in State + + 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,:)%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 + + 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,:)%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 + + end if + + end if ! if (N_selected_obs > 0) + + end if ! thresholds + + end if ! if (N_select_species_smTb>0) [assimilate soil moisture observations for tile kk] - end do ! kk=1,N_catd + end do ! kk=1,N_catd + + ! ---------------------------------------------------------------------------------------------------------------------- - ! ---------------------------------- - case default call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'unknown update_type') @@ -5362,9 +5337,18 @@ subroutine get_select_species( & N_select_varnames, select_varnames, N_obs_param, obs_param, & N_select_species, select_species ) - ! find out obs species ID numbers ("obs_param%species") that correspond - ! to a set of obs species variables names ("obs_param%varname") - ! - reichle, 16 Oct 2014 + ! find out obs species ID numbers ("obs_param%species") that correspond to a set of + ! obs variables names ("obs_param%varname") with obs_param(species)%assim==.true. + + ! original version -- reichle, 16 Oct 2014 + ! + ! added constraint obs_param%assim==.true. + ! --> excludes obs species that are categorically not assimilated (per obs_param); + ! before this change, this constraint was applied at a later stage of + ! selecting the assimilated obs; + ! with this change, N_select_species==0 can be used to check if + ! any obs with select_varnames are assimilated. + ! -reichle, 29 Nov 2024 implicit none @@ -5394,7 +5378,7 @@ subroutine get_select_species( & do ii=1,N_obs_param - if (any(trim(obs_param(ii)%varname)==select_varnames)) then + if ( any(trim(obs_param(ii)%varname)==select_varnames) .and. obs_param(ii)%assim ) then kk = kk+1 @@ -5455,9 +5439,7 @@ subroutine get_ind_obs( & ! locals integer :: i, k - - - + ! -------------------------------------------------------------- if (N_select_species==0 .and. N_select_tilenum==0) then @@ -5528,7 +5510,7 @@ end subroutine get_ind_obs ! ********************************************************************** - + subroutine get_ind_obs_assim( N_obs, assim_flag, N_obs_assim, ind_obs_assim ) ! loop through Observations%assim and construct an index vector that maps to @@ -5902,7 +5884,7 @@ subroutine check_compact_support( & Iam // '(): reset for 1d update_type: ycompact = ', ycompact if (logit) write (logunit,*) - case (2,7,8,10,13,14) ! "3d" updates, check consistency of xcompact, ycompact + case (2,7,8,10,12,13) ! "3d" updates, check consistency of xcompact, ycompact ! check xcompact/ycompact against corr scales of model error diff --git a/GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml b/GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml index 53e428f7..6f4951a0 100644 --- a/GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml +++ b/GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml @@ -9,11 +9,10 @@ ! 7 May 2021 - removed "dtstep_assim" and "centered_update"; replaced with MAPL ! resource parameters "LANDASSIM_DT" and "LANDASSIM_T0" (in LDAS.rc) ! -! -------------------------------------------------------------------- +! ---------------------------------------------------------------------- &ens_upd_inputs - ! ---------------------------------------------------------------------- ! ! update type - for details see subroutine cat_enkf_update() @@ -23,21 +22,23 @@ ! ! # = 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 = 11: 1d snow analysis (Toure et al. 2018 empirical gain); SCF obs -! update_type = 13: 3d soil moisture/Tskin/ght(1) excl. catdef unless PEATCLSM tile; sfmc and TB obs -! update_type = 14: 3d soil moisture/Tskin/ght(1) excl. catdef unless PEATCLSM tile & -! 1d snow analysis (Toure et al. 2018 empirical gain); sfmc, TB and SCF obs +! update_type | analysis state vector | assimilated obs +! ------------------------------------------------------------------------------------------------- +! 0 | NO assimilation, NO bias correction | n/a +! # 1 | 1d soil moisture | sfmc +! # 2 | 3d soil moisture | sfmc +! 3 | 1d Tskin (assim incr NOT applied, use w/ bias corr) | Tskin +! 4 | 1d Tskin/ght1 (assim incr applied, use w/ or w/o bias corr) | Tskin +! 5 | 1d Tskin/ght1 (assim incr NOT applied, use w/ bias corr) | Tskin +! 6 | 1d soil moisture/Tskin/ght(1) | Tb +! 7 | 3d Tskin/ght1 update | Tskin +! 8 | 3d soil moisture/Tskin/ght(1) | Tb +! 9 | 1d Tskin/ght1 update | FT +! 10 | 3d soil moisture/Tskin/ght(1) excl. catdef unless PEATCLSM tile | Tb +! 11 | 1d snow analysis (Toure et al. 2018 empirical gain) | SCF +! 12 | 3d soil moisture/Tskin/ght(1) excl. catdef unless PEATCLSM tile | sfmc/sfds, Tb, SCF +! | & 1d snow analysis (Toure et al. 2018 empirical gain) | +! 13 | 3d soil moisture/Tskin/ght(1) excl. catdef unless PEATCLSM tile | sfmc/sfds, Tb update_type = 0 From a1b9ca2240c61312f137663433cbd3d25943067a Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Fri, 29 Nov 2024 14:51:45 -0500 Subject: [PATCH 014/107] changed error message to warning (inconsistent update_type and obs_param%assim) --- GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index 95bad86c..af669555 100644 --- a/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -3507,6 +3507,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 @@ -3542,6 +3543,8 @@ subroutine cat_enkf_increments( & logical :: found_Tb_obs + + ! ----------------------------------------------------------------------- if (logit) write (logunit,*) & @@ -4957,8 +4960,12 @@ subroutine cat_enkf_increments( & if ( N_select_species_asnow==0 .and. N_select_species_smTb==0 ) then - call ldas_abort(LDAS_GENERIC_ERROR, Iam, & - 'update_type inconsistent with obs_param%assim==.false. for all asnow/Tb/sfmc/sfds species') + err_msg = & + 'update_type not consistent with obs_param%assim==.false. for all asnow/Tb/sfmc/sfds species ' & + // '(may be intentional for "innovations" run, i.e., with obs_param%innov==.true.)' + + call ldas_warn(LDAS_GENERIC_ERROR, Iam, & + end if From c88b2a2c2da1d7f7bc0f609368effc93fbe616d2 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Fri, 29 Nov 2024 17:08:35 -0500 Subject: [PATCH 015/107] updated CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d07a99f4..55fce114 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- New update_type for joint 3d soil moisture and 1d snow analysis (Tb+sfmc+sfds+SCF obs) + ### Changed ### Fixed From f4e9626f545fecc7e913a4d450f91352c625362a Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Fri, 29 Nov 2024 18:59:21 -0500 Subject: [PATCH 016/107] fixed syntax error in previous commit --- GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index af669555..13f2acea 100644 --- a/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -4964,7 +4964,7 @@ subroutine cat_enkf_increments( & 'update_type not consistent with obs_param%assim==.false. for all asnow/Tb/sfmc/sfds species ' & // '(may be intentional for "innovations" run, i.e., with obs_param%innov==.true.)' - call ldas_warn(LDAS_GENERIC_ERROR, Iam, & + call ldas_warn(LDAS_GENERIC_ERROR, Iam, err_msg) end if From e7c91e11718b466a3f0c1db661aa5bb9dca4aa48 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Sat, 30 Nov 2024 08:55:33 -0500 Subject: [PATCH 017/107] fixed build error in previous commit --- GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index 13f2acea..52958e05 100644 --- a/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -4911,7 +4911,7 @@ subroutine cat_enkf_increments( & ! ! ------------------------------------------------------------------------------------------------------- - if (logit) write (logunit, *) 'get increments: update_type = ', select_update_type + if (logit) write (logunit, *) 'get increments: update_type = ', update_type ! determine species of assimilated obs associated with snow analysis From bced10ad21585e06f05d36689c8ac66e6b88960b Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Sat, 30 Nov 2024 09:27:51 -0500 Subject: [PATCH 018/107] fixed build error in previous commit --- GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 b/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 index 65e762a2..eedd28c8 100644 --- a/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 +++ b/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 @@ -1407,11 +1407,7 @@ subroutine apply_enkf_increments( N_catd, N_ens, update_type, & cat_progn_has_changed = .true. - if (select_update_type==10) then - - check_snow = .false. ! turn off for now to maintain 0-diff w/ SMAP Tb DA test case - - end if + if (update_type==10) check_snow = .false. ! turn off for now to maintain 0-diff w/ SMAP Tb DA test case ! ------------------------------------------------------------------ From c4a1826e68fc16cb7893455e1f9d60fadd39b718 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Sat, 30 Nov 2024 10:25:22 -0500 Subject: [PATCH 019/107] fixing linking error in previous commit --- GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 | 1 + 1 file changed, 1 insertion(+) diff --git a/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index 52958e05..3a9e1821 100644 --- a/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -135,6 +135,7 @@ module clsm_ensupd_upd_routines use LDAS_ExceptionsMod, ONLY: & ldas_abort, & + ldas_warn, & LDAS_GENERIC_ERROR use enkf_general, ONLY: & From 067305fd0ebd16508e27a26a32d8e3efc32f4779 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Mon, 2 Dec 2024 14:25:39 -0500 Subject: [PATCH 020/107] fixed log statement for soil moisture analysis in new update_type=12 (clsm_ensupd_upd_routines.F90) --- GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index 3a9e1821..85e7c1c1 100644 --- a/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -4951,12 +4951,9 @@ subroutine cat_enkf_increments( & call get_select_species(1, 'Tb', N_obs_param, obs_param, N_select_species_Tb, select_species_Tb ) - if (N_select_species_smTb>0) then - - if (logit) write (logunit, *) '- get 1d snow increments (Toure et al. 2018 empirical gain); snow cover fraction obs' + if ((N_select_species_smTb>0) .and. logit) & + write (logunit, *) '- get 3d soil moisture/Tskin/ght(1) increments; Tb+sfmc+sfds obs' - end if - ! check consistency of update_type and obs_param%assim config if ( N_select_species_asnow==0 .and. N_select_species_smTb==0 ) then From 829f229baa6b7bd1613c7120465d286059787708 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Mon, 2 Dec 2024 14:29:55 -0500 Subject: [PATCH 021/107] switched order of code blocks for update_type=13 and update_type=12 in "select case" (clsm_ensupd_upd_routines.F90) --- .../clsm_ensupd_upd_routines.F90 | 394 +++++++++--------- 1 file changed, 197 insertions(+), 197 deletions(-) diff --git a/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index 85e7c1c1..0ab23b8c 100644 --- a/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -4690,202 +4690,6 @@ subroutine cat_enkf_increments( & ! ---------------------------------------------------------------------------------------------------------------------- - case (13) select_update_type ! 3d soil moisture/Tskin/ght(1) analysis; Tb+sfmc+sfds obs - - ! update each tile separately using all observations within customized halo around each tile - ! - ! 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+sfds obs' - - ! Get all species associated with *assimilated* Tb, sfmc, and sfds observations - - N_select_varnames = 3 - - select_varnames(1) = 'Tb' - select_varnames(2) = 'sfmc' - select_varnames(3) = 'sfds' - - 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 = 2 ! initialize (always have srfexc and rzexc in state vector) - - ! compute increments only for 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 - - 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 - found_Tb_obs = .true. - exit - end if - end do - if (found_Tb_obs) exit - end do - - ! 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) - - 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 ! catdef in State - - 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,:)%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 - - 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,:)%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 - - 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==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 ! catdef in State - - 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,:)%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 - - 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,:)%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 - - end if - - end if - - end if ! thresholds - - end do - - ! ---------------------------------------------------------------------------------------------------------------------- - case (12) select_update_type ! 3d soil moisture/Tskin/ght(1) analysis; Tb+sfmc+sfds obs ! & 1d snow analysis (Toure et al. 2018 empirical gain); snow cover fraction obs @@ -5308,7 +5112,203 @@ subroutine cat_enkf_increments( & end if ! if (N_select_species_smTb>0) [assimilate soil moisture observations for tile kk] - end do ! kk=1,N_catd + end do ! kk=1,N_catd + + ! ---------------------------------------------------------------------------------------------------------------------- + + case (13) select_update_type ! 3d soil moisture/Tskin/ght(1) analysis; Tb+sfmc+sfds obs + + ! update each tile separately using all observations within customized halo around each tile + ! + ! 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+sfds obs' + + ! Get all species associated with *assimilated* Tb, sfmc, and sfds observations + + N_select_varnames = 3 + + select_varnames(1) = 'Tb' + select_varnames(2) = 'sfmc' + select_varnames(3) = 'sfds' + + 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 = 2 ! initialize (always have srfexc and rzexc in state vector) + + ! compute increments only for 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 + + 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 + found_Tb_obs = .true. + exit + end if + end do + if (found_Tb_obs) exit + end do + + ! 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) + + 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 ! catdef in State + + 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,:)%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 + + 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,:)%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 + + 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==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 ! catdef in State + + 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,:)%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 + + 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,:)%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 + + end if + + end if + + end if ! thresholds + + end do ! kk=1,N_catd ! ---------------------------------------------------------------------------------------------------------------------- From 82dc428416a963e39376e90876de36e24826a9ed Mon Sep 17 00:00:00 2001 From: amfox37 Date: Mon, 2 Dec 2024 14:46:39 -0700 Subject: [PATCH 022/107] updates to ASCAT obs reader --- .../clsm_ensupd_read_obs.F90 | 52 ++++++++++++++----- GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml | 6 +-- 2 files changed, 43 insertions(+), 15 deletions(-) diff --git a/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index e87b3df4..2c30f96d 100644 --- a/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -1667,7 +1667,7 @@ subroutine read_obs_sm_ASCAT_EUMET( & ! -------------------- - character(100), dimension(2*N_fnames_max) :: fname_list ! max 2 days of files + character(200), dimension(2*N_fnames_max) :: fname_list ! max 2 days of files real, dimension(:), allocatable :: tmp1_obs, tmp1_lat, tmp1_lon real*8, dimension(:), allocatable :: tmp1_jtime @@ -1747,19 +1747,47 @@ subroutine read_obs_sm_ASCAT_EUMET( & ! Are we in the required assimilation window? ! ! e.g. Y2019/M07/M01-ASCA-ASCSMO02-NA-5.0-20190702075700.000000000Z-20190702084627-1350204.bfr + ! Y2024/M02/W_XX-EUMETSAT-Darmstadt,SOUNDING+SATELLITE,METOPC+ASCAT_C_EUMR_20240229095700_27567_eps_o_250_ssm_l2.bin ! - ! 12345678901234567890123456789012345678901234567890123456789012345678901234567890 - ! 1 2 3 4 5 6 7 + ! 123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 + ! 1 2 3 4 5 6 7 8 9 10 11 12 - str_date_time = tmpfname(36:49) - + ! Check if tmpfname contains "ASCA-ASCSMO02" or "W_XX-EUMETSAT", error if neither + + if (index(tmpfname, "ASCA-ASCSMO02") /= 0) then + str_date_time = tmpfname(36:49) + else if (index(tmpfname, "W_XX-EUMETSAT") /= 0) then + str_date_time = tmpfname(74:87) + else + err_msg = 'Unknown ASCAT observation filename format' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + end if + + ! Check that str_date_time only contains numeric characters + + do ii = 1, len(str_date_time) + if (ichar(str_date_time(ii:ii)) < ichar('0') .or. ichar(str_date_time(ii:ii)) > ichar('9')) then + err_msg = 'The date-time string parsed from the ASCAT observation filename contains non-numeric characters' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + 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 + + ! Check if date_time_tmp%year and date_time_tmp%month and date_time_tmp%day are valid + if (date_time_tmp%year < 1900 .or. date_time_tmp%year > 2100 .or. & + date_time_tmp%month < 1 .or. date_time_tmp%month > 12 .or. & + date_time_tmp%day < 1 .or. date_time_tmp%day > 31) then + err_msg = 'A valid date-time string has not been successfully parsed from the ASCAT observation filename' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + end if + if ( datetime_lt_refdatetime( date_time_low_fname, date_time_tmp ) .and. & datetime_le_refdatetime( date_time_tmp, date_time_up ) ) then @@ -6132,7 +6160,7 @@ subroutine read_obs_SMAP_FT( date_time, N_catd, this_obs_param, & character(100) :: dset_name_lon, dset_name_lat character(100) :: dset_name_time, dset_name_ft, dset_name_ft_qual_flag - character(100), dimension(2*N_halforbits_max) :: fname_list ! max 2 days of files + character(200), dimension(2*N_halforbits_max) :: fname_list ! max 2 days of files integer, dimension(7) :: dset_size integer, dimension(N_fnames_max) :: N_obs_kept @@ -6839,7 +6867,7 @@ subroutine read_obs_SMAP_halforbit_Tb( date_time, N_catd, this_obs_param, & character(100) :: dset_name_time_1, dset_name_tb_1, dset_name_tb_qual_flag_1 character(100) :: dset_name_time_2, dset_name_tb_2, dset_name_tb_qual_flag_2 - character(100), dimension(2*N_halforbits_max) :: fname_list ! max 2 days of files + character(200), dimension(2*N_halforbits_max) :: fname_list ! max 2 days of files integer, dimension(7) :: dset_size integer, dimension(N_fnames_max) :: N_obs_kept @@ -8167,7 +8195,7 @@ subroutine read_obs_fnames( date_time, this_obs_param, & integer, intent(out) :: N_fnames - character(100), dimension(N_max), intent(out) :: fname_list + character(200), dimension(N_max), intent(out) :: fname_list integer, optional, intent(in) :: obs_dir_hier @@ -8176,7 +8204,7 @@ subroutine read_obs_fnames( date_time, this_obs_param, & character(300) :: fname character(200) :: fpath_tmp character( 80) :: fname_tmp - character( 80) :: tmpstr80 + character(200) :: tmpstr200 character( 14) :: YYYYMMDDdir character( 10) :: YYYYMMdir @@ -8225,7 +8253,7 @@ subroutine read_obs_fnames( date_time, this_obs_param, & do while (istat==0) - read(10,*,iostat=istat) tmpstr80 + read(10, '(A)',iostat=istat) tmpstr200 if (istat==0) then @@ -8238,7 +8266,7 @@ subroutine read_obs_fnames( date_time, this_obs_param, & ! preface file names with "Yyyyy/Mmm/Ddd" (default) - fname_list(ii) = YYYYMMDDdir // trim(tmpstr80) + fname_list(ii) = YYYYMMDDdir // trim(tmpstr200) if (present(obs_dir_hier)) then @@ -8246,7 +8274,7 @@ subroutine read_obs_fnames( date_time, this_obs_param, & ! preface file names with "Yyyyy/Mmm" - fname_list(ii) = YYYYMMdir // trim(tmpstr80) + fname_list(ii) = YYYYMMdir // trim(tmpstr200) else diff --git a/GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml b/GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml index ece206c4..b93496e1 100644 --- a/GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml +++ b/GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml @@ -2178,7 +2178,7 @@ 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/smap/SMAP_Nature/ASCAT_EUMETSAT/Metop_A/' -obs_param_nml(49)%name = 'M02-ASCA-ASCSMO02' +obs_param_nml(49)%name = '' obs_param_nml(49)%maskpath = '' obs_param_nml(49)%maskname = '' obs_param_nml(49)%scalepath = '' @@ -2217,7 +2217,7 @@ 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/smap/SMAP_Nature/ASCAT_EUMETSAT/Metop_B/' -obs_param_nml(50)%name = 'M01-ASCA-ASCSMO02' +obs_param_nml(50)%name = '' obs_param_nml(50)%maskpath = '' obs_param_nml(50)%maskname = '' obs_param_nml(50)%scalepath = '' @@ -2256,7 +2256,7 @@ 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/smap/SMAP_Nature/ASCAT_EUMETSAT/Metop_C/' -obs_param_nml(51)%name = 'M03-ASCA-ASCSMO02' +obs_param_nml(51)%name = '' obs_param_nml(51)%maskpath = '' obs_param_nml(51)%maskname = '' obs_param_nml(51)%scalepath = '' From 2ba02ca132767514ddb983a1dcbb40b2776bc289 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Mon, 2 Dec 2024 16:09:04 -0700 Subject: [PATCH 023/107] len(trim(str_date_time)) --- GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 2c30f96d..3dc348fd 100644 --- a/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -1765,12 +1765,12 @@ subroutine read_obs_sm_ASCAT_EUMET( & ! Check that str_date_time only contains numeric characters - do ii = 1, len(str_date_time) - if (ichar(str_date_time(ii:ii)) < ichar('0') .or. ichar(str_date_time(ii:ii)) > ichar('9')) then - err_msg = 'The date-time string parsed from the ASCAT observation filename contains non-numeric characters' - call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) - end if - end do + do ii = 1, len(trim(str_date_time)) + if (ichar(str_date_time(ii:ii)) < ichar('0') .or. ichar(str_date_time(ii:ii)) > ichar('9')) then + err_msg = 'The date-time string parsed from the ASCAT observation filename contains non-numeric characters' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + end if + end do read(str_date_time( 1: 4), *) date_time_tmp%year read(str_date_time( 5: 6), *) date_time_tmp%month From b0555b3fb1358596fb65117e137cc14211f1a113 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Mon, 2 Dec 2024 18:55:52 -0700 Subject: [PATCH 024/107] changemod edit --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d07a99f4..0df11624 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- Updated read_obs_sm_ASCAT_EUMET to work with both new and old filename formats. + ### Fixed ### Removed From 01c541ddaea508c707b8bbc243c22e2a3c51ffb1 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Wed, 11 Dec 2024 13:02:20 -0500 Subject: [PATCH 025/107] additional documentation and minor cleanup for ASCAT soil moisture reader updates --- CHANGELOG.md | 2 +- .../clsm_ensupd_read_obs.F90 | 47 +++++++++++-------- GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml | 8 +++- 3 files changed, 35 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d1e8aca0..5ab148b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed -- Updated read_obs_sm_ASCAT_EUMET to work with both new and old filename formats. +- Updated read_obs_sm_ASCAT_EUMET to work with both original and revised file name templates. ### Fixed diff --git a/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 3dc348fd..05eeaf66 100644 --- a/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -1741,34 +1741,41 @@ subroutine read_obs_sm_ASCAT_EUMET( & N_tmp = 0 do kk = 1,N_fnames - + tmpfname = fname_list(kk) - + ! Are we in the required assimilation window? ! + ! NOTE: EUMETSAT changed the file name template sometime in 2023 or 2024. + ! There was no change to the file contents. + ! Files from the original download (through data day ~1 Jun 2023) have + ! the original file name template ("M0[X]-ASCA..."), more recently downloaded + ! files have the revised template ("W_XX-EUMETSAT..."). + ! This reader accommodates both templates: + ! ! e.g. Y2019/M07/M01-ASCA-ASCSMO02-NA-5.0-20190702075700.000000000Z-20190702084627-1350204.bfr ! Y2024/M02/W_XX-EUMETSAT-Darmstadt,SOUNDING+SATELLITE,METOPC+ASCAT_C_EUMR_20240229095700_27567_eps_o_250_ssm_l2.bin ! ! 123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 ! 1 2 3 4 5 6 7 8 9 10 11 12 - - ! Check if tmpfname contains "ASCA-ASCSMO02" or "W_XX-EUMETSAT", error if neither - + + ! check if tmpfname contains "ASCA-ASCSMO02" or "W_XX-EUMETSAT", error if neither + if (index(tmpfname, "ASCA-ASCSMO02") /= 0) then - str_date_time = tmpfname(36:49) + str_date_time = tmpfname(36:49) else if (index(tmpfname, "W_XX-EUMETSAT") /= 0) then - str_date_time = tmpfname(74:87) + str_date_time = tmpfname(74:87) else - err_msg = 'Unknown ASCAT observation filename format' - call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + err_msg = 'Unknown ASCAT observation file name format' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) end if - ! Check that str_date_time only contains numeric characters - + ! check if str_date_time only contains numeric characters + do ii = 1, len(trim(str_date_time)) if (ichar(str_date_time(ii:ii)) < ichar('0') .or. ichar(str_date_time(ii:ii)) > ichar('9')) then - err_msg = 'The date-time string parsed from the ASCAT observation filename contains non-numeric characters' - call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + err_msg = 'Date-time string parsed from ASCAT sm obs file name contains non-numeric characters' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) end if end do @@ -1779,15 +1786,15 @@ subroutine read_obs_sm_ASCAT_EUMET( & read(str_date_time(11:12), *) date_time_tmp%min read(str_date_time(13:14), *) date_time_tmp%sec - ! Check if date_time_tmp%year and date_time_tmp%month and date_time_tmp%day are valid + ! check if year, month, and day are valid - if (date_time_tmp%year < 1900 .or. date_time_tmp%year > 2100 .or. & - date_time_tmp%month < 1 .or. date_time_tmp%month > 12 .or. & - date_time_tmp%day < 1 .or. date_time_tmp%day > 31) then - err_msg = 'A valid date-time string has not been successfully parsed from the ASCAT observation filename' + if ( date_time_tmp%year < 2007 .or. date_time_tmp%year > 2100 .or. & + date_time_tmp%month < 1 .or. date_time_tmp%month > 12 .or. & + date_time_tmp%day < 1 .or. date_time_tmp%day > 31 ) then + err_msg = 'Could not parse valid date-time string from ASCAT obs file name' call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) - end if - + end if + if ( datetime_lt_refdatetime( date_time_low_fname, date_time_tmp ) .and. & datetime_le_refdatetime( date_time_tmp, date_time_up ) ) then diff --git a/GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml b/GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml index a6de8e0c..50850985 100644 --- a/GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml +++ b/GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml @@ -2158,7 +2158,13 @@ obs_param_nml(48)%xcorr = 0.1875 obs_param_nml(48)%ycorr = 0.1875 obs_param_nml(48)%adapt = 0 -! -------------------------------------------------------------------- +! -------------------------------------------------------------------------------------------------------------- +! +! ASCAT_MET[X]_SM soil moisture observations from EUMETSAT +! +! Leave %name blank. Provide text files that contain file names via %flistpath and %flistname. +! +! ------------------- ! ! 49 = ASCAT_META_SM (ASCAT soil moisture ascending and descending orbits) ! From feddbcd67358164905e3fb380def36f93792c23a Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Mon, 16 Dec 2024 17:37:39 -0500 Subject: [PATCH 026/107] update file specs to match M21C: - update LONG_NAME attributes (GEOS_EnsGridComp.F90) - update lnd Collection in HISTORY template (GEOSldas_HIST.rc) --- GEOSens_GridComp/GEOS_EnsGridComp.F90 | 134 ++++++++++++---------- GEOSldas_App/GEOSldas_HIST.rc | 154 ++++++++++++++------------ 2 files changed, 159 insertions(+), 129 deletions(-) diff --git a/GEOSens_GridComp/GEOS_EnsGridComp.F90 b/GEOSens_GridComp/GEOS_EnsGridComp.F90 index e38d8cb2..eb3848aa 100644 --- a/GEOSens_GridComp/GEOS_EnsGridComp.F90 +++ b/GEOSens_GridComp/GEOS_EnsGridComp.F90 @@ -152,7 +152,7 @@ subroutine SetServices(gc, rc) VERIFY_(STATUS) call MAPL_AddExportSpec(GC ,& - LONG_NAME = 'interception_reservoir_capac',& + LONG_NAME = 'vegetation_interception_water_storage',& UNITS = 'kg m-2' ,& SHORT_NAME = 'CAPAC' ,& ! FRIENDLYTO = trim(COMP_NAME) ,& @@ -459,7 +459,7 @@ subroutine SetServices(gc, rc) VERIFY_(STATUS) call MAPL_AddExportSpec(GC, & - LONG_NAME = 'runoff_flux' ,& + LONG_NAME = 'runoff_total_flux' ,& UNITS = 'kg m-2 s-1' ,& SHORT_NAME = 'RUNOFF' ,& DIMS = MAPL_DimsTileOnly ,& @@ -468,7 +468,7 @@ subroutine SetServices(gc, rc) VERIFY_(STATUS) call MAPL_AddExportSpec(GC, & - LONG_NAME = 'interception_loss_energy_flux',& + LONG_NAME = 'interception_loss_latent_heat_flux',& UNITS = 'W m-2' ,& SHORT_NAME = 'EVPINT' ,& DIMS = MAPL_DimsTileOnly ,& @@ -477,7 +477,7 @@ subroutine SetServices(gc, rc) VERIFY_(STATUS) call MAPL_AddExportSpec(GC, & - LONG_NAME = 'baresoil_evap_energy_flux' ,& + LONG_NAME = 'baresoil_evaporation_latent_heat_flux' ,& UNITS = 'W m-2' ,& SHORT_NAME = 'EVPSOI' ,& DIMS = MAPL_DimsTileOnly ,& @@ -486,7 +486,7 @@ subroutine SetServices(gc, rc) VERIFY_(STATUS) call MAPL_AddExportSpec(GC, & - LONG_NAME = 'transpiration_energy_flux' ,& + LONG_NAME = 'transpiration_latent_heat_flux' ,& UNITS = 'W m-2' ,& SHORT_NAME = 'EVPVEG' ,& DIMS = MAPL_DimsTileOnly ,& @@ -495,7 +495,7 @@ subroutine SetServices(gc, rc) VERIFY_(STATUS) call MAPL_AddExportSpec(GC, & - LONG_NAME = 'snow_ice_evaporation_energy_flux',& + LONG_NAME = 'snowpack_evaporation_latent_heat_flux',& UNITS = 'W m-2' ,& SHORT_NAME = 'EVPICE' ,& DIMS = MAPL_DimsTileOnly ,& @@ -514,7 +514,7 @@ subroutine SetServices(gc, rc) VERIFY_(STATUS) call MAPL_AddExportSpec(GC, & - LONG_NAME = 'totoal soil moisture' ,& + LONG_NAME = 'total_soil_moisture' ,& UNITS = 'kg m-2' ,& SHORT_NAME = 'WATSOI' ,& DIMS = MAPL_DimsTileOnly ,& @@ -532,7 +532,7 @@ subroutine SetServices(gc, rc) VERIFY_(STATUS) call MAPL_AddExportSpec(GC, & - LONG_NAME = 'snowpack_evaporation_energy_flux',& + LONG_NAME = 'snowpack_evaporation_latent_heat_flux',& UNITS = 'W m-2' ,& SHORT_NAME = 'EVPSNO' ,& DIMS = MAPL_DimsTileOnly ,& @@ -540,7 +540,7 @@ subroutine SetServices(gc, rc) RC=STATUS ) VERIFY_(STATUS) call MAPL_AddExportSpec(GC, & - LONG_NAME = 'baseflow_flux' ,& + LONG_NAME = 'baseflow_flux_land' ,& UNITS = 'kg m-2 s-1' ,& SHORT_NAME = 'BASEFLOW' ,& DIMS = MAPL_DimsTileOnly ,& @@ -567,7 +567,7 @@ subroutine SetServices(gc, rc) VERIFY_(STATUS) call MAPL_AddExportSpec(GC, & - LONG_NAME = 'surface_outgoing_longwave_flux',& + LONG_NAME = 'surface_emitted_longwave_flux',& UNITS = 'W m-2' ,& SHORT_NAME = 'HLWUP' ,& DIMS = MAPL_DimsTileOnly ,& @@ -595,7 +595,7 @@ subroutine SetServices(gc, rc) call MAPL_AddExportSpec(GC, & - LONG_NAME = 'total_latent_energy_flux' ,& + LONG_NAME = 'total_latent_heat_flux_consistent_with_evaporation_from_turbulence' ,& UNITS = 'W m-2' ,& SHORT_NAME = 'HLATN' ,& DIMS = MAPL_DimsTileOnly ,& @@ -649,7 +649,7 @@ subroutine SetServices(gc, rc) VERIFY_(STATUS) call MAPL_AddExportSpec(GC, & - LONG_NAME = 'ave_catchment_temp_incl_snw',& + LONG_NAME = 'surface_temperature_of_land_incl_snow',& UNITS = 'K' ,& SHORT_NAME = 'TPSURF' ,& DIMS = MAPL_DimsTileOnly ,& @@ -658,7 +658,7 @@ subroutine SetServices(gc, rc) VERIFY_(STATUS) call MAPL_AddExportSpec(GC, & - LONG_NAME = 'ave_catchment_temp_incl_snw_ensstd',& + LONG_NAME = 'surface_temperature_of_land_incl_snow_ensstd',& UNITS = 'K' ,& SHORT_NAME = 'TPSURF_ENSSTD' ,& DIMS = MAPL_DimsTileOnly ,& @@ -667,7 +667,7 @@ subroutine SetServices(gc, rc) VERIFY_(STATUS) call MAPL_AddExportSpec(GC, & - LONG_NAME = 'temperature_top_snow_layer',& + LONG_NAME = 'surface_temperature_of_snow_on_land',& UNITS = 'K' ,& SHORT_NAME = 'TPSNOW' ,& DIMS = MAPL_DimsTileOnly ,& @@ -676,7 +676,7 @@ subroutine SetServices(gc, rc) VERIFY_(STATUS) call MAPL_AddExportSpec(GC, & - LONG_NAME = 'temperature_unsaturated_zone',& + LONG_NAME = 'surface_temperature_of_unsaturated_zone',& UNITS = 'K' ,& SHORT_NAME = 'TPUNST' ,& DIMS = MAPL_DimsTileOnly ,& @@ -685,7 +685,7 @@ subroutine SetServices(gc, rc) VERIFY_(STATUS) call MAPL_AddExportSpec(GC, & - LONG_NAME = 'temperature_saturated_zone',& + LONG_NAME = 'surface_temperature_of_saturated_zone',& UNITS = 'K' ,& SHORT_NAME = 'TPSAT' ,& DIMS = MAPL_DimsTileOnly ,& @@ -694,7 +694,7 @@ subroutine SetServices(gc, rc) VERIFY_(STATUS) call MAPL_AddExportSpec(GC, & - LONG_NAME = 'temperature_wilted_zone' ,& + LONG_NAME = 'surface_temperature_of_wilting_zone' ,& UNITS = 'K' ,& SHORT_NAME = 'TPWLT' ,& DIMS = MAPL_DimsTileOnly ,& @@ -703,7 +703,7 @@ subroutine SetServices(gc, rc) VERIFY_(STATUS) call MAPL_AddExportSpec(GC, & - LONG_NAME = 'fractional_area_of_land_snowcover',& + LONG_NAME = 'fractional_area_of_snow_on_land',& UNITS = '1' ,& SHORT_NAME = 'ASNOW' ,& DIMS = MAPL_DimsTileOnly ,& @@ -766,7 +766,7 @@ subroutine SetServices(gc, rc) VERIFY_(STATUS) call MAPL_AddExportSpec(GC, & - LONG_NAME = 'snow_depth' ,& + LONG_NAME = 'snow_depth_within_snow_covered_area_fraction_on_land' ,& UNITS = 'm' ,& SHORT_NAME = 'SNOWDP' ,& DIMS = MAPL_DimsTileOnly ,& @@ -775,7 +775,7 @@ subroutine SetServices(gc, rc) VERIFY_(STATUS) call MAPL_AddExportSpec(GC, & - LONG_NAME = 'surface_soil_wetness' ,& + LONG_NAME = 'soil_wetness_surface' ,& UNITS = '1' ,& SHORT_NAME = 'WET1' ,& DIMS = MAPL_DimsTileOnly ,& @@ -784,7 +784,7 @@ subroutine SetServices(gc, rc) VERIFY_(STATUS) call MAPL_AddExportSpec(GC, & - LONG_NAME = 'root_zone_soil_wetness' ,& + LONG_NAME = 'soil_wetness_rootzone' ,& UNITS = '1' ,& SHORT_NAME = 'WET2' ,& DIMS = MAPL_DimsTileOnly ,& @@ -793,7 +793,7 @@ subroutine SetServices(gc, rc) VERIFY_(STATUS) call MAPL_AddExportSpec(GC, & - LONG_NAME = 'ave_prof_soil__moisture' ,& + LONG_NAME = 'soil_wetness_profile' ,& UNITS = '1' ,& SHORT_NAME = 'WET3' ,& DIMS = MAPL_DimsTileOnly ,& @@ -802,7 +802,7 @@ subroutine SetServices(gc, rc) VERIFY_(STATUS) call MAPL_AddExportSpec(GC, & - LONG_NAME = 'water_surface_layer' ,& + LONG_NAME = 'soil_moisture_surface' ,& UNITS = 'm3 m-3' ,& SHORT_NAME = 'WCSF' ,& DIMS = MAPL_DimsTileOnly ,& @@ -811,7 +811,7 @@ subroutine SetServices(gc, rc) VERIFY_(STATUS) call MAPL_AddExportSpec(GC, & - LONG_NAME = 'water_surface_layer_ensstd' ,& + LONG_NAME = 'soil_moisture_surface_ensstd' ,& UNITS = 'm3 m-3' ,& SHORT_NAME = 'WCSF_ENSSTD' ,& DIMS = MAPL_DimsTileOnly ,& @@ -820,7 +820,7 @@ subroutine SetServices(gc, rc) VERIFY_(STATUS) call MAPL_AddExportSpec(GC, & - LONG_NAME = 'water_root_zone' ,& + LONG_NAME = 'soil_moisture_rootzone' ,& UNITS = 'm3 m-3' ,& SHORT_NAME = 'WCRZ' ,& DIMS = MAPL_DimsTileOnly ,& @@ -829,7 +829,7 @@ subroutine SetServices(gc, rc) VERIFY_(STATUS) call MAPL_AddExportSpec(GC, & - LONG_NAME = 'water_root_zone_ensstd' ,& + LONG_NAME = 'soil_moisture_rootzone_ensstd' ,& UNITS = 'm3 m-3' ,& SHORT_NAME = 'WCRZ_ENSSTD' ,& DIMS = MAPL_DimsTileOnly ,& @@ -839,7 +839,7 @@ subroutine SetServices(gc, rc) call MAPL_AddExportSpec(GC, & - LONG_NAME = 'water_ave_prof' ,& + LONG_NAME = 'soil_moisture_profile' ,& UNITS = 'm3 m-3' ,& SHORT_NAME = 'WCPR' ,& DIMS = MAPL_DimsTileOnly ,& @@ -848,7 +848,7 @@ subroutine SetServices(gc, rc) VERIFY_(STATUS) call MAPL_AddExportSpec(GC, & - LONG_NAME = 'water_ave_prof_ensstd' ,& + LONG_NAME = 'soil_moisture_profile_ensstd' ,& UNITS = 'm3 m-3' ,& SHORT_NAME = 'WCPR_ENSSTD' ,& DIMS = MAPL_DimsTileOnly ,& @@ -857,7 +857,7 @@ subroutine SetServices(gc, rc) VERIFY_(STATUS) call MAPL_AddExportSpec(GC, & - LONG_NAME = 'soil_temperatures_layer_1' ,& + LONG_NAME = 'soil_temperature_layer_1' ,& UNITS = 'K' ,& SHORT_NAME = 'TSOIL1TILE' ,& DIMS = MAPL_DimsTileOnly ,& @@ -866,7 +866,7 @@ subroutine SetServices(gc, rc) VERIFY_(STATUS) call MAPL_AddExportSpec(GC, & - LONG_NAME = 'soil_temperatures_layer_1_ensstd' ,& + LONG_NAME = 'soil_temperature_layer_1_ensstd' ,& UNITS = 'K' ,& SHORT_NAME = 'TSOIL1TILE_ENSSTD' ,& DIMS = MAPL_DimsTileOnly ,& @@ -875,7 +875,7 @@ subroutine SetServices(gc, rc) VERIFY_(STATUS) call MAPL_AddExportSpec(GC, & - LONG_NAME = 'soil_temperatures_layer_2' ,& + LONG_NAME = 'soil_temperature_layer_2' ,& UNITS = 'K' ,& SHORT_NAME = 'TSOIL2TILE' ,& DIMS = MAPL_DimsTileOnly ,& @@ -884,7 +884,7 @@ subroutine SetServices(gc, rc) VERIFY_(STATUS) call MAPL_AddExportSpec(GC, & - LONG_NAME = 'soil_temperatures_layer_3' ,& + LONG_NAME = 'soil_temperature_layer_3' ,& UNITS = 'K' ,& SHORT_NAME = 'TSOIL3TILE' ,& DIMS = MAPL_DimsTileOnly ,& @@ -893,7 +893,7 @@ subroutine SetServices(gc, rc) VERIFY_(STATUS) call MAPL_AddExportSpec(GC, & - LONG_NAME = 'soil_temperatures_layer_4' ,& + LONG_NAME = 'soil_temperature_layer_4' ,& UNITS = 'K' ,& SHORT_NAME = 'TSOIL4TILE' ,& DIMS = MAPL_DimsTileOnly ,& @@ -902,7 +902,7 @@ subroutine SetServices(gc, rc) VERIFY_(STATUS) call MAPL_AddExportSpec(GC, & - LONG_NAME = 'soil_temperatures_layer_5' ,& + LONG_NAME = 'soil_temperature_layer_5' ,& UNITS = 'K' ,& SHORT_NAME = 'TSOIL5TILE' ,& DIMS = MAPL_DimsTileOnly ,& @@ -911,7 +911,7 @@ subroutine SetServices(gc, rc) VERIFY_(STATUS) call MAPL_AddExportSpec(GC, & - LONG_NAME = 'soil_temperatures_layer_6' ,& + LONG_NAME = 'soil_temperature_layer_6' ,& UNITS = 'K' ,& SHORT_NAME = 'TSOIL6TILE' ,& DIMS = MAPL_DimsTileOnly ,& @@ -929,7 +929,7 @@ subroutine SetServices(gc, rc) VERIFY_(STATUS) call MAPL_AddExportSpec(GC, & - LONG_NAME = 'surface_albedo_visible_beam',& + LONG_NAME = 'surface_reflectivity_visible_beam',& UNITS = '1' ,& SHORT_NAME = 'ALBVR' ,& DIMS = MAPL_DimsTileOnly ,& @@ -938,7 +938,7 @@ subroutine SetServices(gc, rc) VERIFY_(STATUS) call MAPL_AddExportSpec(GC, & - LONG_NAME = 'surface_albedo_visible_diffuse',& + LONG_NAME = 'surface_reflectivity_visible_diffuse',& UNITS = '1' ,& SHORT_NAME = 'ALBVF' ,& DIMS = MAPL_DimsTileOnly ,& @@ -947,7 +947,7 @@ subroutine SetServices(gc, rc) VERIFY_(STATUS) call MAPL_AddExportSpec(GC, & - LONG_NAME = 'surface_albedo_near_infrared_beam',& + LONG_NAME = 'surface_reflectivity_near_infrared_beam',& UNITS = '1' ,& SHORT_NAME = 'ALBNR' ,& DIMS = MAPL_DimsTileOnly ,& @@ -956,7 +956,7 @@ subroutine SetServices(gc, rc) VERIFY_(STATUS) call MAPL_AddExportSpec(GC, & - LONG_NAME = 'surface_albedo_near_infrared_diffuse',& + LONG_NAME = 'surface_reflectivity_near_infrared_diffuse',& UNITS = '1' ,& SHORT_NAME = 'ALBNF' ,& DIMS = MAPL_DimsTileOnly ,& @@ -1238,7 +1238,7 @@ subroutine SetServices(gc, rc) call MAPL_AddExportSpec(GC, & SHORT_NAME = 'EVLAND', & - LONG_NAME = 'Evaporation_land', & + LONG_NAME = 'total_evapotranspiration_land', & UNITS = 'kg m-2 s-1', & DIMS = MAPL_DimsTileOnly, & VLOCATION = MAPL_VLocationNone, & @@ -1265,7 +1265,7 @@ subroutine SetServices(gc, rc) call MAPL_AddExportSpec(GC, & SHORT_NAME = 'DRPARLAND', & - LONG_NAME = 'surface_downwelling_par_beam_flux', & + LONG_NAME = 'surface_downwelling_PAR_beam_flux', & UNITS = 'W m-2', & DIMS = MAPL_DimsTileOnly, & VLOCATION = MAPL_VLocationNone, & @@ -1274,7 +1274,7 @@ subroutine SetServices(gc, rc) call MAPL_AddExportSpec(GC, & SHORT_NAME = 'DFPARLAND', & - LONG_NAME = 'surface_downwelling_par_diffuse_flux', & + LONG_NAME = 'surface_downwelling_PAR_diffuse_flux', & UNITS = 'W m-2', & DIMS = MAPL_DimsTileOnly, & VLOCATION = MAPL_VLocationNone, & @@ -1292,8 +1292,8 @@ subroutine SetServices(gc, rc) call MAPL_AddExportSpec(GC, & - SHORT_NAME = 'SWNETSNOW', & - LONG_NAME = 'Net_shortwave_snow', & + SHORT_NAME = 'SWNETSNOW', & + LONG_NAME = 'Net_shortwave_flux_snow', & UNITS = 'W m-2', & DIMS = MAPL_DimsTileOnly, & VLOCATION = MAPL_VLocationNone, & @@ -1303,7 +1303,7 @@ subroutine SetServices(gc, rc) call MAPL_AddExportSpec(GC, & SHORT_NAME = 'LWUPSNOW', & - LONG_NAME = 'Net_longwave_snow', & + LONG_NAME = 'surface_emitted_longwave_flux_snow', & UNITS = 'W m-2', & DIMS = MAPL_DimsTileOnly, & VLOCATION = MAPL_VLocationNone, & @@ -1312,7 +1312,7 @@ subroutine SetServices(gc, rc) call MAPL_AddExportSpec(GC, & SHORT_NAME = 'LWDNSNOW', & - LONG_NAME = 'Net_longwave_snow', & + LONG_NAME = 'surface_absorbed_longwave_flux_snow', & UNITS = 'W m-2', & DIMS = MAPL_DimsTileOnly, & VLOCATION = MAPL_VLocationNone, & @@ -1377,7 +1377,7 @@ subroutine SetServices(gc, rc) call MAPL_AddExportSpec(GC, & SHORT_NAME = 'SWLAND', & - LONG_NAME = 'Net_shortwave_land', & + LONG_NAME = 'Net_shortwave_flux_land', & UNITS = 'W m-2', & DIMS = MAPL_DimsTileOnly, & VLOCATION = MAPL_VLocationNone, & @@ -1386,7 +1386,7 @@ subroutine SetServices(gc, rc) call MAPL_AddExportSpec(GC, & SHORT_NAME = 'SWDOWNLAND', & - LONG_NAME = 'Incident_shortwave_land', & + LONG_NAME = 'Incident_shortwave_flux_land', & UNITS = 'W m-2', & DIMS = MAPL_DimsTileOnly, & VLOCATION = MAPL_VLocationNone, & @@ -1396,7 +1396,7 @@ subroutine SetServices(gc, rc) call MAPL_AddExportSpec(GC, & SHORT_NAME = 'LWLAND', & - LONG_NAME = 'Net_longwave_land', & + LONG_NAME = 'Net_longwave_flux_land', & UNITS = 'W m-2', & DIMS = MAPL_DimsTileOnly, & VLOCATION = MAPL_VLocationNone, & @@ -1406,7 +1406,7 @@ subroutine SetServices(gc, rc) call MAPL_AddExportSpec(GC, & SHORT_NAME = 'GHLAND', & - LONG_NAME = 'Ground_heating_land', & + LONG_NAME = 'Ground_heating_flux_land', & UNITS = 'W m-2', & DIMS = MAPL_DimsTileOnly, & VLOCATION = MAPL_VLocationNone, & @@ -1415,7 +1415,7 @@ subroutine SetServices(gc, rc) call MAPL_AddExportSpec(GC, & SHORT_NAME = 'GHTSKIN', & - LONG_NAME = 'Ground_heating_skin_temp', & + LONG_NAME = 'Ground_heating_flux_for_skin_temp_land', & UNITS = 'W m-2', & DIMS = MAPL_DimsTileOnly, & VLOCATION = MAPL_VLocationNone, & @@ -1434,7 +1434,7 @@ subroutine SetServices(gc, rc) call MAPL_AddExportSpec(GC, & SHORT_NAME = 'TWLAND', & - LONG_NAME = 'Avail_water_storage_land', & + LONG_NAME = 'total_water_storage_land', & UNITS = 'kg m-2', & DIMS = MAPL_DimsTileOnly, & VLOCATION = MAPL_VLocationNone, & @@ -1480,7 +1480,16 @@ subroutine SetServices(gc, rc) call MAPL_AddExportSpec(GC, & SHORT_NAME = 'SPLAND', & - LONG_NAME = 'rate_of_spurious_land_energy_source',& + LONG_NAME = 'Spurious_sensible_heat_flux_land',& + UNITS = 'W m-2', & + DIMS = MAPL_DimsTileOnly, & + VLOCATION = MAPL_VLocationNone, & + RC=STATUS ) + VERIFY_(STATUS) + + call MAPL_AddExportSpec(GC, & + SHORT_NAME = 'SPLH', & + LONG_NAME = 'Spurious_latent_heat_flux_land',& UNITS = 'W m-2', & DIMS = MAPL_DimsTileOnly, & VLOCATION = MAPL_VLocationNone, & @@ -1489,7 +1498,7 @@ subroutine SetServices(gc, rc) call MAPL_AddExportSpec(GC, & SHORT_NAME = 'SPWATR', & - LONG_NAME = 'rate_of_spurious_land_water_source',& + LONG_NAME = 'Spurious_evapotranspiration_flux_land',& UNITS = 'kg m-2 s-1', & DIMS = MAPL_DimsTileOnly, & VLOCATION = MAPL_VLocationNone, & @@ -1498,7 +1507,7 @@ subroutine SetServices(gc, rc) call MAPL_AddExportSpec(GC, & SHORT_NAME = 'SPSNOW', & - LONG_NAME = 'rate_of_spurious_snow_energy',& + LONG_NAME = 'Spurious_snow_energy_flux_land',& UNITS = 'W m-2', & DIMS = MAPL_DimsTileOnly, & VLOCATION = MAPL_VLocationNone, & @@ -1838,7 +1847,7 @@ subroutine SetServices(gc, rc) call MAPL_AddExportSpec( & gc, & SHORT_NAME = "DRPAR", & - LONG_NAME = "surface_downwelling_par_beam_flux", & + LONG_NAME = "surface_downwelling_PAR_beam_flux", & UNITS = "W m-2", & DIMS = MAPL_DimsTileOnly, & VLOCATION = MAPL_VlocationNone, & @@ -1849,7 +1858,7 @@ subroutine SetServices(gc, rc) call MAPL_AddExportSpec( & gc, & SHORT_NAME = "DFPAR", & - LONG_NAME = "surface_downwelling_par_diffuse_flux", & + LONG_NAME = "surface_downwelling_PAR_diffuse_flux", & UNITS = "W m-2", & DIMS = MAPL_DimsTileOnly, & VLOCATION = MAPL_VlocationNone, & @@ -1904,7 +1913,7 @@ subroutine SetServices(gc, rc) call MAPL_AddExportSpec( & gc, & SHORT_NAME = "LWDNSRF", & - LONG_NAME = "perturbed_surface_downwelling_longwave_flux", & + LONG_NAME = "perturbed_surface_absorbed_longwave_flux", & UNITS = "W m-2", & DIMS = MAPL_DimsTileOnly, & VLOCATION = MAPL_VlocationNone, & @@ -2419,6 +2428,7 @@ subroutine Collect_land_ens(gc, import, export, clock, rc) real, dimension(:),pointer :: DWLAND,DWLAND_enavg real, dimension(:),pointer :: DHLAND,DHLAND_enavg real, dimension(:),pointer :: SPLAND,SPLAND_enavg + real, dimension(:),pointer :: SPLH, SPLH_enavg real, dimension(:),pointer :: SPWATR,SPWATR_enavg real, dimension(:),pointer :: SPSNOW,SPSNOW_enavg real, dimension(:),pointer :: PEATCLSM_WATERLEVEL,PEATCLSM_WATERLEVEL_enavg @@ -2782,6 +2792,8 @@ subroutine Collect_land_ens(gc, import, export, clock, rc) VERIFY_(status) call MAPL_GetPointer(import, SPLAND, 'SPLAND' ,rc=status) VERIFY_(status) + call MAPL_GetPointer(import, SPLH, 'SPLH' ,rc=status) + VERIFY_(status) call MAPL_GetPointer(import, SPWATR, 'SPWATR' ,rc=status) VERIFY_(status) call MAPL_GetPointer(import, SPSNOW, 'SPSNOW' ,rc=status) @@ -3084,6 +3096,8 @@ subroutine Collect_land_ens(gc, import, export, clock, rc) VERIFY_(status) call MAPL_GetPointer(export, SPLAND_enavg, 'SPLAND' ,rc=status) VERIFY_(status) + call MAPL_GetPointer(export, SPLH_enavg, 'SPLH' ,rc=status) + VERIFY_(status) call MAPL_GetPointer(export, SPWATR_enavg, 'SPWATR' ,rc=status) VERIFY_(status) call MAPL_GetPointer(export, SPSNOW_enavg, 'SPSNOW' ,rc=status) @@ -3253,6 +3267,7 @@ subroutine Collect_land_ens(gc, import, export, clock, rc) if(associated(DWLAND_enavg)) DWLAND_enavg = 0.0 if(associated(DHLAND_enavg)) DHLAND_enavg = 0.0 if(associated(SPLAND_enavg)) SPLAND_enavg = 0.0 + if(associated(SPLH_enavg)) SPLH_enavg = 0.0 if(associated(SPWATR_enavg)) SPWATR_enavg = 0.0 if(associated(SPSNOW_enavg)) SPSNOW_enavg = 0.0 if(associated(PEATCLSM_WATERLEVEL_enavg)) PEATCLSM_WATERLEVEL_enavg = 0.0 @@ -3546,6 +3561,8 @@ subroutine Collect_land_ens(gc, import, export, clock, rc) DHLAND_enavg = DHLAND_enavg + DHLAND if(associated(SPLAND_enavg) .and. associated(SPLAND)) & SPLAND_enavg = SPLAND_enavg + SPLAND + if(associated(SPLH_enavg) .and. associated(SPLH)) & + SPLH_enavg = SPLH_enavg + SPLH if(associated(SPWATR_enavg) .and. associated(SPWATR)) & SPWATR_enavg = SPWATR_enavg + SPWATR if(associated(SPSNOW_enavg) .and. associated(SPSNOW)) & @@ -3786,6 +3803,7 @@ subroutine Collect_land_ens(gc, import, export, clock, rc) if(associated(DWLAND_enavg)) DWLAND_enavg = DWLAND_enavg/NUM_ENSEMBLE if(associated(DHLAND_enavg)) DHLAND_enavg = DHLAND_enavg/NUM_ENSEMBLE if(associated(SPLAND_enavg)) SPLAND_enavg = SPLAND_enavg/NUM_ENSEMBLE + if(associated(SPLH_enavg)) SPLH_enavg = SPLH_enavg /NUM_ENSEMBLE if(associated(SPWATR_enavg)) SPWATR_enavg = SPWATR_enavg/NUM_ENSEMBLE if(associated(SPSNOW_enavg)) SPSNOW_enavg = SPSNOW_enavg/NUM_ENSEMBLE if(associated(PEATCLSM_WATERLEVEL_enavg)) PEATCLSM_WATERLEVEL_enavg = PEATCLSM_WATERLEVEL_enavg/NUM_ENSEMBLE diff --git a/GEOSldas_App/GEOSldas_HIST.rc b/GEOSldas_App/GEOSldas_HIST.rc index adb52654..f6534f80 100644 --- a/GEOSldas_App/GEOSldas_HIST.rc +++ b/GEOSldas_App/GEOSldas_HIST.rc @@ -26,6 +26,7 @@ COLLECTIONS: :: #CUBE GRID_LABELS: PC720x361-DC +#CUBE GRID_LABELS: PC1440x721-DC #CUBE :: @@ -36,6 +37,13 @@ COLLECTIONS: #CUBE PC720x361-DC.DATELINE: DC #CUBE PC720x361-DC.LM: 1 +#CUBE PC1440x721-DC.GRID_TYPE: LatLon +#CUBE PC1440x721-DC.IM_WORLD: 1440 +#CUBE PC1440x721-DC.JM_WORLD: 721 +#CUBE PC1440x721-DC.POLE: PC +#CUBE PC1440x721-DC.DATELINE: DC +#CUBE PC1440x721-DC.LM: 1 + # Detailed definition of the collections listed above # # Bit shaving: Retain only scientifically meaningful precision and modify meaningless @@ -107,46 +115,47 @@ COLLECTIONS: :: tavg24_1d_lnd_Nt.descr: 'Tile-space,Daily,Time-Averaged,Single-Level,Assimilation,Land Surface Diagnostics', - tavg24_1d_lnd_Nt.nbits: 12, +# tavg24_1d_lnd_Nt.nbits: 12, tavg24_1d_lnd_Nt.template: '%y4%m2%d2_%h2%n2z.bin', tavg24_1d_lnd_Nt.mode: 'time-averaged', tavg24_1d_lnd_Nt.frequency: 240000, tavg24_1d_lnd_Nt.ref_time: 000000, - tavg24_1d_lnd_Nt.fields: 'WET3' , 'GridComp' , 'GWETPROF' , + tavg24_1d_lnd_Nt.fields: 'GRN' , 'VEGDYN' , + 'LAI' , 'VEGDYN' , + 'WET3' , 'GridComp' , 'GWETPROF' , 'WET2' , 'GridComp' , 'GWETROOT' , 'WET1' , 'GridComp' , 'GWETTOP' , 'WCPR' , 'GridComp' , 'PRMC' , 'WCRZ' , 'GridComp' , 'RZMC' , 'WCSF' , 'GridComp' , 'SFMC' , - 'TPSNOW' , 'GridComp' , - 'TPUNST' , 'GridComp' , 'TUNST' , - 'TPSAT' , 'GridComp' , 'TSAT' , - 'TPWLT' , 'GridComp' , 'TWLT' , - 'TPSURF' , 'GridComp' , 'TSURF' , - 'GRN' , 'VEGDYN' , - 'LAI' , 'VEGDYN' , - 'TP1' , 'GridComp' , - 'TP2' , 'GridComp' , - 'TP3' , 'GridComp' , - 'TP4' , 'GridComp' , - 'TP5' , 'GridComp' , - 'TP6' , 'GridComp' , - 'PRLAND' , 'GridComp' , 'PRECTOTLAND' , - 'SNOLAND' , 'GridComp' , 'PRECSNOLAND' , - 'TSLAND' , 'GridComp' , 'SNOMAS' , - 'SNOWDP' , 'GridComp' , 'SNODP' , - 'EVPSOI' , 'GridComp' , 'EVPSOIL' , - 'EVPVEG' , 'GridComp' , 'EVPTRNS' , - 'EVPINT' , 'GridComp' , 'EVPINTR' , - 'EVPICE' , 'GridComp' , 'EVPSBLN' , - 'RUNSURF' , 'GridComp' , 'RUNOFF' , - 'BASEFLOW' , 'GridComp' , + 'CAPAC' , 'GridComp' , 'INTRWATR' , + 'TPSNOW' , 'GridComp' , 'TPSNOWLAND' , + 'TPUNST' , 'GridComp' , 'TUNSTLAND' , + 'TPSAT' , 'GridComp' , 'TSATLAND' , + 'TPWLT' , 'GridComp' , 'TWLTLAND' , + 'TPSURF' , 'GridComp' , 'TSURFLAND' , + 'TP1' , 'GridComp' , 'TSOIL1' , ! CATCH GC: TP1, ENS GC: TSOIL1TILE + 'TP2' , 'GridComp' , 'TSOIL2' , ! ... + 'TP3' , 'GridComp' , 'TSOIL3' , ! ... + 'TP4' , 'GridComp' , 'TSOIL4' , ! ... + 'TP5' , 'GridComp' , 'TSOIL5' , ! ... + 'TP6' , 'GridComp' , 'TSOIL6' , ! ... + 'PRLAND' , 'GridComp' , 'PRECTOTCORRLAND' , ! assume "corrected" precip + 'SNOLAND' , 'GridComp' , 'PRECSNOCORRLAND' , ! assume "corrected" precip + 'TSLAND' , 'GridComp' , 'SNOMASLAND' , + 'SNOWDP' , 'GridComp' , 'SNODPLAND' , + 'EVPSOI' , 'GridComp' , 'LHLANDSOIL' , + 'EVPVEG' , 'GridComp' , 'LHLANDTRNS' , + 'EVPINT' , 'GridComp' , 'LHLANDINTR' , + 'EVPICE' , 'GridComp' , 'LHLANDSBLN' , + 'RUNSURF' , 'GridComp' , 'RUNSURFLAND' , + 'BASEFLOW' , 'GridComp' , 'BASEFLOWLAND' , 'SMLAND' , 'GridComp' , - 'QINFIL' , 'GridComp' , - 'FRUST' , 'GridComp' , 'FRUNST' , - 'FRSAT' , 'GridComp' , - 'ASNOW' , 'GridComp' , 'FRSNO' , - 'FRWLT' , 'GridComp' , + 'QINFIL' , 'GridComp' , 'QINFILLAND' , + 'FRUST' , 'GridComp' , 'FRLANDUNST' , + 'FRSAT' , 'GridComp' , 'FRLANDSAT' , + 'ASNOW' , 'GridComp' , 'FRLANDSNO' , + 'FRWLT' , 'GridComp' , 'FRLANDWLT' , 'DFPARLAND' , 'GridComp' , 'PARDFLAND' , 'DRPARLAND' , 'GridComp' , 'PARDRLAND' , 'SHLAND' , 'GridComp' , @@ -157,11 +166,12 @@ COLLECTIONS: 'GHLAND' , 'GridComp' , 'TWLAND' , 'GridComp' , 'TELAND' , 'GridComp' , - 'DWLAND' , 'GridComp' , 'WCHANGE' , - 'DHLAND' , 'GridComp' , 'ECHANGE' , - 'SPLAND' , 'GridComp' , - 'SPWATR' , 'GridComp' , - 'SPSNOW' , 'GridComp' , + 'DWLAND' , 'GridComp' , 'WCHANGELAND' , + 'DHLAND' , 'GridComp' , 'ECHANGELAND' , + 'SPLAND' , 'GridComp' , 'SPSHLAND' , + 'SPLH' , 'GridComp' , 'SPLHLAND' , + 'SPWATR' , 'GridComp' , 'SPEVLAND' , + 'SPSNOW' , 'GridComp' , 'SPSNLAND' , 'PEATCLSM_WATERLEVEL', 'GridComp' , 'PEATCLSM_FSWCHANGE' , 'GridComp' , >>>HIST_AEROSOL<<< 'RMELTDU001' , 'GridComp' , @@ -203,52 +213,53 @@ COLLECTIONS: >>>HIST_IRRIG<<< 'IRRIGRATE' , 'GridComp' , :: + tavg24_2d_lnd_Nx.format: 'CFIO', tavg24_2d_lnd_Nx.descr: '2d,Daily,Time-Averaged,Single-Level,Assimilation,Land Surface Diagnostics', - tavg24_2d_lnd_Nx.nbits: 12, +# tavg24_2d_lnd_Nx.nbits: 12, tavg24_2d_lnd_Nx.template: '%y4%m2%d2_%h2%n2z.nc4', tavg24_2d_lnd_Nx.mode: 'time-averaged', tavg24_2d_lnd_Nx.frequency: 240000, tavg24_2d_lnd_Nx.ref_time: 000000, - tavg24_2d_lnd_Nx.format: 'CFIO', tavg24_2d_lnd_Nx.regrid_exch: '../input/tile.data' tavg24_2d_lnd_Nx.regrid_name: 'GRIDNAME' tavg24_2d_lnd_Nx.grid_label: PC720x361-DC tavg24_2d_lnd_Nx.deflate: 2, - tavg24_2d_lnd_Nx.fields: 'WET3' , 'GridComp' , 'GWETPROF' , + tavg24_2d_lnd_Nx.fields: 'GRN' , 'VEGDYN' , + 'LAI' , 'VEGDYN' , + 'WET3' , 'GridComp' , 'GWETPROF' , 'WET2' , 'GridComp' , 'GWETROOT' , 'WET1' , 'GridComp' , 'GWETTOP' , 'WCPR' , 'GridComp' , 'PRMC' , 'WCRZ' , 'GridComp' , 'RZMC' , 'WCSF' , 'GridComp' , 'SFMC' , - 'TPSNOW' , 'GridComp' , - 'TPUNST' , 'GridComp' , 'TUNST' , - 'TPSAT' , 'GridComp' , 'TSAT' , - 'TPWLT' , 'GridComp' , 'TWLT' , - 'TPSURF' , 'GridComp' , 'TSURF' , - 'GRN' , 'VEGDYN' , - 'LAI' , 'VEGDYN' , - 'TP1' , 'GridComp' , - 'TP2' , 'GridComp' , - 'TP3' , 'GridComp' , - 'TP4' , 'GridComp' , - 'TP5' , 'GridComp' , - 'TP6' , 'GridComp' , - 'PRLAND' , 'GridComp' , 'PRECTOTLAND' , - 'SNOLAND' , 'GridComp' , 'PRECSNOLAND' , - 'TSLAND' , 'GridComp' , 'SNOMAS' , - 'SNOWDP' , 'GridComp' , 'SNODP' , - 'EVPSOI' , 'GridComp' , 'EVPSOIL' , - 'EVPVEG' , 'GridComp' , 'EVPTRNS' , - 'EVPINT' , 'GridComp' , 'EVPINTR' , - 'EVPICE' , 'GridComp' , 'EVPSBLN' , - 'RUNSURF' , 'GridComp' , 'RUNOFF' , - 'BASEFLOW' , 'GridComp' , + 'CAPAC' , 'GridComp' , 'INTRWATR' , + 'TPSNOW' , 'GridComp' , 'TPSNOWLAND' , + 'TPUNST' , 'GridComp' , 'TUNSTLAND' , + 'TPSAT' , 'GridComp' , 'TSATLAND' , + 'TPWLT' , 'GridComp' , 'TWLTLAND' , + 'TPSURF' , 'GridComp' , 'TSURFLAND' , + 'TP1' , 'GridComp' , 'TSOIL1' , ! CATCH GC: TP1, ENS GC: TSOIL1TILE + 'TP2' , 'GridComp' , 'TSOIL2' , ! ... + 'TP3' , 'GridComp' , 'TSOIL3' , ! ... + 'TP4' , 'GridComp' , 'TSOIL4' , ! ... + 'TP5' , 'GridComp' , 'TSOIL5' , ! ... + 'TP6' , 'GridComp' , 'TSOIL6' , ! ... + 'PRLAND' , 'GridComp' , 'PRECTOTCORRLAND' , ! assume "corrected" precip + 'SNOLAND' , 'GridComp' , 'PRECSNOCORRLAND' , ! assume "corrected" precip + 'TSLAND' , 'GridComp' , 'SNOMASLAND' , + 'SNOWDP' , 'GridComp' , 'SNODPLAND' , + 'EVPSOI' , 'GridComp' , 'LHLANDSOIL' , + 'EVPVEG' , 'GridComp' , 'LHLANDTRNS' , + 'EVPINT' , 'GridComp' , 'LHLANDINTR' , + 'EVPICE' , 'GridComp' , 'LHLANDSBLN' , + 'RUNSURF' , 'GridComp' , 'RUNSURFLAND' , + 'BASEFLOW' , 'GridComp' , 'BASEFLOWLAND' , 'SMLAND' , 'GridComp' , - 'QINFIL' , 'GridComp' , - 'FRUST' , 'GridComp' , 'FRUNST' , - 'FRSAT' , 'GridComp' , - 'ASNOW' , 'GridComp' , 'FRSNO' , - 'FRWLT' , 'GridComp' , + 'QINFIL' , 'GridComp' , 'QINFILLAND' , + 'FRUST' , 'GridComp' , 'FRLANDUNST' , + 'FRSAT' , 'GridComp' , 'FRLANDSAT' , + 'ASNOW' , 'GridComp' , 'FRLANDSNO' , + 'FRWLT' , 'GridComp' , 'FRLANDWLT' , 'DFPARLAND' , 'GridComp' , 'PARDFLAND' , 'DRPARLAND' , 'GridComp' , 'PARDRLAND' , 'SHLAND' , 'GridComp' , @@ -259,11 +270,12 @@ COLLECTIONS: 'GHLAND' , 'GridComp' , 'TWLAND' , 'GridComp' , 'TELAND' , 'GridComp' , - 'DWLAND' , 'GridComp' , 'WCHANGE' , - 'DHLAND' , 'GridComp' , 'ECHANGE' , - 'SPLAND' , 'GridComp' , - 'SPWATR' , 'GridComp' , - 'SPSNOW' , 'GridComp' , + 'DWLAND' , 'GridComp' , 'WCHANGELAND' , + 'DHLAND' , 'GridComp' , 'ECHANGELAND' , + 'SPLAND' , 'GridComp' , 'SPSHLAND' , + 'SPLH' , 'GridComp' , 'SPLHLAND' , + 'SPWATR' , 'GridComp' , 'SPEVLAND' , + 'SPSNOW' , 'GridComp' , 'SPSNLAND' , 'PEATCLSM_WATERLEVEL', 'GridComp' , 'PEATCLSM_FSWCHANGE' , 'GridComp' , >>>HIST_AEROSOL<<< 'RMELTDU001' , 'GridComp' , From 5b155b746488479c9cfe98bea77140fadfcef7f9 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Tue, 17 Dec 2024 12:21:30 -0500 Subject: [PATCH 027/107] Additional updates of file specs to match M21C (GEOS_EnsGridComp.F90, GEOS_LandAssimGridComp.F90, GEOS_ExportCatchIncrGridComp.F90, tile_bin2nc4.F90) --- CHANGELOG.md | 3 +- GEOSens_GridComp/GEOS_EnsGridComp.F90 | 2 +- .../GEOS_LandAssimGridComp.F90 | 18 +- .../GEOS_ExportCatchIncrGridComp.F90 | 14 +- GEOSldas_App/tile_bin2nc4.F90 | 485 +++++++++--------- 5 files changed, 267 insertions(+), 255 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ab148b6..fa7f4704 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed -- Updated read_obs_sm_ASCAT_EUMET to work with both original and revised file name templates. +- Updated subroutine read_obs_sm_ASCAT_EUMET() to work with both original and revised file name templates. +- Revised variable names (SHORT_NAME) and descriptions (LONG_NAME) to match M21C file specs. ### Fixed diff --git a/GEOSens_GridComp/GEOS_EnsGridComp.F90 b/GEOSens_GridComp/GEOS_EnsGridComp.F90 index eb3848aa..1e8b0036 100644 --- a/GEOSens_GridComp/GEOS_EnsGridComp.F90 +++ b/GEOSens_GridComp/GEOS_EnsGridComp.F90 @@ -604,7 +604,7 @@ subroutine SetServices(gc, rc) VERIFY_(STATUS) call MAPL_AddExportSpec(GC, & - LONG_NAME = 'rainwater_infiltration_flux',& + LONG_NAME = 'soil_water_infiltration_rate',& UNITS = 'kg m-2 s-1' ,& SHORT_NAME = 'QINFIL' ,& DIMS = MAPL_DimsTileOnly ,& diff --git a/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 b/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 index f24124fd..91fe0be1 100644 --- a/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 +++ b/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 @@ -540,7 +540,7 @@ subroutine SetServices ( GC, RC ) ! Exports for Catchment prognostics increments call MAPL_AddExportSpec(GC ,& - LONG_NAME = 'increment_canopy_temperature_saturated_zone' ,& + LONG_NAME = 'increment_surface_temperature_of_saturated_zone' ,& UNITS = 'K' ,& SHORT_NAME = 'TCFSAT_INCR' ,& DIMS = MAPL_DimsTileOnly ,& @@ -549,7 +549,7 @@ subroutine SetServices ( GC, RC ) _VERIFY(STATUS) call MAPL_AddExportSpec(GC ,& - LONG_NAME = 'increment_canopy_temperature_transition_zone' ,& + LONG_NAME = 'increment_surface_temperature_of_unsaturated_zone' ,& UNITS = 'K' ,& SHORT_NAME = 'TCFTRN_INCR' ,& DIMS = MAPL_DimsTileOnly ,& @@ -558,7 +558,7 @@ subroutine SetServices ( GC, RC ) _VERIFY(STATUS) call MAPL_AddExportSpec(GC ,& - LONG_NAME = 'increment_canopy_temperature_wilting_zone' ,& + LONG_NAME = 'increment_surface_temperature_of_wilting_zone' ,& UNITS = 'K' ,& SHORT_NAME = 'TCFWLT_INCR' ,& DIMS = MAPL_DimsTileOnly ,& @@ -567,7 +567,7 @@ subroutine SetServices ( GC, RC ) _VERIFY(STATUS) call MAPL_AddExportSpec(GC ,& - LONG_NAME = 'increment_canopy_specific_humidity_saturated_zone' ,& + LONG_NAME = 'increment_surface_specific_humidity_of_saturated_zone' ,& UNITS = 'kg kg-1' ,& SHORT_NAME = 'QCFSAT_INCR' ,& DIMS = MAPL_DimsTileOnly ,& @@ -576,7 +576,7 @@ subroutine SetServices ( GC, RC ) _VERIFY(STATUS) call MAPL_AddExportSpec(GC ,& - LONG_NAME = 'increment_canopy_specific_humidity_transition_zone' ,& + LONG_NAME = 'increment_surface_specific_humidity_of_unsaturated_zone' ,& UNITS = 'kg kg-1' ,& SHORT_NAME = 'QCFTRN_INCR' ,& DIMS = MAPL_DimsTileOnly ,& @@ -585,7 +585,7 @@ subroutine SetServices ( GC, RC ) _VERIFY(STATUS) call MAPL_AddExportSpec(GC ,& - LONG_NAME = 'increment_canopy_specific_humidity_wilting_zone' ,& + LONG_NAME = 'increment_surface_specific_humidity_of_wilting_zone' ,& UNITS = 'kg kg-1' ,& SHORT_NAME = 'QCFWLT_INCR' ,& DIMS = MAPL_DimsTileOnly ,& @@ -594,7 +594,7 @@ subroutine SetServices ( GC, RC ) _VERIFY(STATUS) call MAPL_AddExportSpec(GC ,& - LONG_NAME = 'increment_interception_reservoir_capac' ,& + LONG_NAME = 'increment_vegetation_interception_water_storage' ,& UNITS = 'kg m-2' ,& SHORT_NAME = 'CAPAC_INCR' ,& DIMS = MAPL_DimsTileOnly ,& @@ -847,7 +847,7 @@ subroutine SetServices ( GC, RC ) VERIFY_(STATUS) call MAPL_AddExportSpec(GC ,& - LONG_NAME = 'soil_temperatures_layer_1_analysis' ,& + LONG_NAME = 'soil_temperature_layer_1_analysis' ,& UNITS = 'K' ,& SHORT_NAME = 'TSOIL1_ANA' ,& DIMS = MAPL_DimsTileOnly ,& @@ -856,7 +856,7 @@ subroutine SetServices ( GC, RC ) VERIFY_(STATUS) call MAPL_AddExportSpec(GC ,& - LONG_NAME = 'soil_temperatures_layer_1_analysis_ensstd' ,& + LONG_NAME = 'soil_temperature_layer_1_analysis_ensstd' ,& UNITS = 'K' ,& SHORT_NAME = 'TSOIL1_ANA_ENSSTD' ,& DIMS = MAPL_DimsTileOnly ,& diff --git a/GEOSlandassim_GridComp/GEOSexportcatchincr_GridComp/GEOS_ExportCatchIncrGridComp.F90 b/GEOSlandassim_GridComp/GEOSexportcatchincr_GridComp/GEOS_ExportCatchIncrGridComp.F90 index 8ea79574..cbbec5f9 100644 --- a/GEOSlandassim_GridComp/GEOSexportcatchincr_GridComp/GEOS_ExportCatchIncrGridComp.F90 +++ b/GEOSlandassim_GridComp/GEOSexportcatchincr_GridComp/GEOS_ExportCatchIncrGridComp.F90 @@ -88,7 +88,7 @@ subroutine SetServices ( GC, RC ) ! Exports for Catchment prognostics increments call MAPL_AddExportSpec(GC ,& - LONG_NAME = 'increment_canopy_temperature_saturated_zone' ,& + LONG_NAME = 'increment_surface_temperature_saturated_zone' ,& UNITS = 'K' ,& SHORT_NAME = 'TCFSAT_INCR' ,& DIMS = MAPL_DimsTileOnly ,& @@ -97,7 +97,7 @@ subroutine SetServices ( GC, RC ) _VERIFY(STATUS) call MAPL_AddExportSpec(GC ,& - LONG_NAME = 'increment_canopy_temperature_transition_zone' ,& + LONG_NAME = 'increment_surface_temperature_of_unsaturated_zone' ,& UNITS = 'K' ,& SHORT_NAME = 'TCFTRN_INCR' ,& DIMS = MAPL_DimsTileOnly ,& @@ -106,7 +106,7 @@ subroutine SetServices ( GC, RC ) _VERIFY(STATUS) call MAPL_AddExportSpec(GC ,& - LONG_NAME = 'increment_canopy_temperature_wilting_zone' ,& + LONG_NAME = 'increment_surface_temperature_of_wilting_zone' ,& UNITS = 'K' ,& SHORT_NAME = 'TCFWLT_INCR' ,& DIMS = MAPL_DimsTileOnly ,& @@ -115,7 +115,7 @@ subroutine SetServices ( GC, RC ) _VERIFY(STATUS) call MAPL_AddExportSpec(GC ,& - LONG_NAME = 'increment_canopy_specific_humidity_saturated_zone' ,& + LONG_NAME = 'increment_surface_specific_humidity_of_saturated_zone' ,& UNITS = 'kg kg-1' ,& SHORT_NAME = 'QCFSAT_INCR' ,& DIMS = MAPL_DimsTileOnly ,& @@ -124,7 +124,7 @@ subroutine SetServices ( GC, RC ) _VERIFY(STATUS) call MAPL_AddExportSpec(GC ,& - LONG_NAME = 'increment_canopy_specific_humidity_transition_zone' ,& + LONG_NAME = 'increment_surface_specific_humidity_of_unsaturated_zone' ,& UNITS = 'kg kg-1' ,& SHORT_NAME = 'QCFTRN_INCR' ,& DIMS = MAPL_DimsTileOnly ,& @@ -133,7 +133,7 @@ subroutine SetServices ( GC, RC ) _VERIFY(STATUS) call MAPL_AddExportSpec(GC ,& - LONG_NAME = 'increment_canopy_specific_humidity_wilting_zone' ,& + LONG_NAME = 'increment_surface_specific_humidity_of_wilting_zone' ,& UNITS = 'kg kg-1' ,& SHORT_NAME = 'QCFWLT_INCR' ,& DIMS = MAPL_DimsTileOnly ,& @@ -142,7 +142,7 @@ subroutine SetServices ( GC, RC ) _VERIFY(STATUS) call MAPL_AddExportSpec(GC ,& - LONG_NAME = 'increment_interception_reservoir_capac' ,& + LONG_NAME = 'increment_vegetation_interception_water_storage' ,& UNITS = 'kg m-2' ,& SHORT_NAME = 'CAPAC_INCR' ,& DIMS = MAPL_DimsTileOnly ,& diff --git a/GEOSldas_App/tile_bin2nc4.F90 b/GEOSldas_App/tile_bin2nc4.F90 index df52c8be..0aae4099 100644 --- a/GEOSldas_App/tile_bin2nc4.F90 +++ b/GEOSldas_App/tile_bin2nc4.F90 @@ -3,18 +3,21 @@ PROGRAM tile_bin2nc4 implicit none INCLUDE 'netcdf.inc' - integer :: i,k, n, NTILES - integer :: NCFOutID, Vid, STATUS, CellID, TimID, nVars - character(256) :: Usage="tile_bin2nc4.x BINFILE DESCRIPTOR TILECOORD" + integer :: i,k, n, NTILES + integer :: NCFOutID, Vid, STATUS, CellID, TimID, nVars + character(256) :: Usage="tile_bin2nc4.x BINFILE DESCRIPTOR TILECOORD" ! DESCRIPTOR = GrADS ctl file generated by MAPL from HISTORY.rc character(512) :: BINFILE, TILECOORD, DESCRIPTOR, arg(3) character(128) :: MYNAME, BUF - integer, dimension(8) :: date_time_values + + integer, dimension(8) :: date_time_values character (22) :: time_stamp - real, allocatable, dimension (:) :: lons, lats, var + real, allocatable, dimension (:) :: lons, lats, var integer, allocatable, dimension (:) :: tileid, i_index, j_index + integer :: myunit1, myunit2 - real :: undef - ! processing command line agruments + real :: undef + + ! process command line arguments I = command_argument_count() @@ -28,7 +31,8 @@ PROGRAM tile_bin2nc4 call get_command_argument(n,arg(n)) enddo - call get_environment_variable ("MYNAME" ,MYNAME ) + call get_environment_variable ("MYNAME", MYNAME) + read(arg(1),'(a)') BINFILE read(arg(2),'(a)') DESCRIPTOR read(arg(3),'(a)') TILECOORD @@ -38,10 +42,11 @@ PROGRAM tile_bin2nc4 ! print *,trim(DESCRIPTOR) ! print *,trim(TILECOORD) - ! reading TILECOORD + ! read TILECOORD file open (newunit=myunit1, file = trim(TILECOORD), form = 'unformatted', action ='read') read (myunit1) NTILES + allocate (lons (1:NTILES)) allocate (lats (1:NTILES)) allocate (tileid (1:NTILES)) @@ -63,7 +68,7 @@ PROGRAM tile_bin2nc4 close (myunit1,status = 'keep') - ! read binary and write NC4 + ! read DESCRIPTOR file (=GrADS ctl file generated by MAPL from HISTORY.rc file) open (newunit=myunit1, file = trim(DESCRIPTOR), form ='formatted', action = 'read') nVars = 0 @@ -86,6 +91,8 @@ PROGRAM tile_bin2nc4 end do + ! prep nc4 file + status = NF_CREATE (trim(BINFILE)//'.nc4', NF_NETCDF4, NCFOutID) status = NF_DEF_DIM(NCFOutID, 'tile' , NTILES, CellID) status = NF_DEF_DIM(NCFOutID, 'time' , NF_UNLIMITED, TimID) @@ -102,8 +109,8 @@ PROGRAM tile_bin2nc4 status = NF_DEF_VAR(NCFOutID, 'JG' , NF_INT, 1 ,CellID, vid) status = NF_PUT_ATT_TEXT(NCFOutID, vid, 'long_name', & LEN_TRIM('J_INDEX'), 'J_INDEX') - do n = 1, nVars + do n = 1, nVars read(myunit1, '(a)', iostat=status) buf status = NF_DEF_VAR(NCFOutID,buf(1:index(buf,' ') -1) , NF_FLOAT, 2 ,(/CellID, TimID/), vid) status = NF_PUT_ATT_TEXT(NCFOutID, vid, 'long_name', & @@ -115,7 +122,6 @@ PROGRAM tile_bin2nc4 status = nf_put_att_real(NCFOutID, vid, '_FillValue',NF_FLOAT, 1, undef) end do - call date_and_time(VALUES=date_time_values) write (time_stamp,'(i4.4,a1,i2.2,a1,i2.2,1x,a2,1x,i2.2,a1,i2.2,a1,i2.2)') & @@ -133,7 +139,7 @@ PROGRAM tile_bin2nc4 status = NF_PUT_VARA_INT (NCFOutID,VarID(NCFOutID,'IG' ) ,(/1/),(/NTILES/),i_index ) status = NF_PUT_VARA_INT (NCFOutID,VarID(NCFOutID,'JG' ) ,(/1/),(/NTILES/),j_index ) - ! reading and writing + ! read data from binary file and write into nc4 file open (newunit=myunit2, file = trim(BINFILE)//'.bin', form = 'unformatted', action = 'read') @@ -152,47 +158,47 @@ PROGRAM tile_bin2nc4 close (myunit1) close (myunit2) - contains - - ! ---------------------------------------------------------------------- - - integer function VarID (NCFID, VNAME) - - integer, intent (in) :: NCFID - character(*), intent (in) :: VNAME - integer :: status - - STATUS = NF_INQ_VARID (NCFID, trim(VNAME) ,VarID) - IF (STATUS .NE. NF_NOERR) & - CALL HANDLE_ERR(STATUS, trim(VNAME)) - - end function VarID - +contains + + ! ---------------------------------------------------------------------- + + integer function VarID (NCFID, VNAME) + + integer, intent (in) :: NCFID + character(*), intent (in) :: VNAME + integer :: status + + STATUS = NF_INQ_VARID (NCFID, trim(VNAME) ,VarID) + IF (STATUS .NE. NF_NOERR) & + CALL HANDLE_ERR(STATUS, trim(VNAME)) + + end function VarID + ! ----------------------------------------------------------------------- - - SUBROUTINE HANDLE_ERR(STATUS, Line) - - INTEGER, INTENT (IN) :: STATUS - CHARACTER(*), INTENT (IN) :: Line - - IF (STATUS .NE. NF_NOERR) THEN - PRINT *, trim(Line),': ',NF_STRERROR(STATUS) - STOP 'Stopped' - ENDIF - - END SUBROUTINE HANDLE_ERR - - ! *********************************************************************** - + + SUBROUTINE HANDLE_ERR(STATUS, Line) + + INTEGER, INTENT (IN) :: STATUS + CHARACTER(*), INTENT (IN) :: Line + + IF (STATUS .NE. NF_NOERR) THEN + PRINT *, trim(Line),': ',NF_STRERROR(STATUS) + STOP 'Stopped' + ENDIF + + END SUBROUTINE HANDLE_ERR + + ! *********************************************************************** + FUNCTION getAttribute (SHORT_NAME, LNAME, UNT) result (str_atr) - + character(*), intent(in) :: SHORT_NAME integer, intent (in), optional :: LNAME, UNT character(128) :: str_atr, LONG_NAME, UNITS - + SELECT case (trim(SHORT_NAME)) - - ! For SM_L4 + + ! For L4_SM ! reichle, 20 May 2020: verified SHORT_NAME and corrected UNITS to match SMAP L4_SM Product Specs; LONG_NAME (mostly) from GEOS_CatchGridComp.F90 ! reichle, 14 Feb 2022: added "WATERTABLED" (now: "PEATCLSM_WATERLEVEL") and "FSWCHANGE" (now: "PEATCLSM_FSWCHANGE") ! reichle, 21 Feb 2022: added "mwrtm_vegopacity" @@ -249,206 +255,211 @@ FUNCTION getAttribute (SHORT_NAME, LNAME, UNT) result (str_atr) case ('TB_LAND_1410MHZ_40DEG_HPOL'); LONG_NAME = 'brightness_temperature_land_1410MHz_40deg_Hpol'; UNITS = 'K' 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 = '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' - case ('Psurf'); LONG_NAME = 'surface_pressure'; UNITS = 'Pa' - case ('PS'); LONG_NAME = 'surface_pressure'; UNITS = 'Pa' - case ('Rainf_C'); LONG_NAME = 'convective_rainfall'; UNITS = 'kg m-2 s-1' - case ('Rainf'); LONG_NAME = 'liquid_water_precipitation'; UNITS = 'kg m-2 s-1' - case ('Snowf'); LONG_NAME = 'total_snowfall'; UNITS = 'kg m-2 s-1' - case ('RainfSnowf'); LONG_NAME = 'RainfSnowf'; UNITS = 'kg m-2 s-1' - case ('SWnet'); LONG_NAME = 'downward_net_shortwave_radiation'; UNITS = 'W m-2' - case ('RefH'); LONG_NAME = 'reference_height_for_Tair_Qair_Wind'; UNITS = 'm' - case ('DZ'); LONG_NAME = 'reference_height_for_Tair_Qair_Wind'; UNITS = 'm' - case ('CATDEF'); LONG_NAME = 'catchment_deficit'; UNITS = 'kg m-2' - case ('RZEXC'); LONG_NAME = 'root_zone_excess'; UNITS = 'kg m-2' - case ('SRFEXC'); LONG_NAME = 'surface_excess'; UNITS = 'kg m-2' - 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' - case ('GWETTOP'); LONG_NAME = 'surface_soil_wetness'; UNITS = '1' - case ('PRMC'); LONG_NAME = 'water_ave_prof'; UNITS = 'm3 m-3' - case ('RZMC'); LONG_NAME = 'water_root_zone'; UNITS = 'm3 m-3' - case ('SFMC'); LONG_NAME = 'water_surface_layer'; UNITS = 'm3 m-3' - case ('TPSNOW'); LONG_NAME = 'temperature_top_snow_layer'; UNITS = 'K' - case ('TUNST'); LONG_NAME = 'temperature_unsaturated_zone'; UNITS = 'K' - case ('TSAT'); LONG_NAME = 'temperature_saturated_zone'; UNITS = 'K' - case ('TWLT'); LONG_NAME = 'temperature_wilted_zone'; UNITS = 'K' - case ('TSURF'); LONG_NAME = 'ave_catchment_temp_incl_snw'; UNITS = 'K' - case ('TPSURF'); LONG_NAME = 'ave_catchment_temp_incl_snw'; UNITS = 'K' - case ('GRN'); LONG_NAME = 'greeness_fraction'; UNITS = '1' - case ('LAI'); LONG_NAME = 'leaf_area_index'; UNITS = '1' - case ('TP1'); LONG_NAME = 'soil_temperatures_layer_1'; UNITS = 'K' ! units now K, rreichle & borescan, 6 Nov 2020 - case ('TP2'); LONG_NAME = 'soil_temperatures_layer_2'; UNITS = 'K' ! units now K, rreichle & borescan, 6 Nov 2020 - case ('TP3'); LONG_NAME = 'soil_temperatures_layer_3'; UNITS = 'K' ! units now K, rreichle & borescan, 6 Nov 2020 - case ('TP4'); LONG_NAME = 'soil_temperatures_layer_4'; UNITS = 'K' ! units now K, rreichle & borescan, 6 Nov 2020 - case ('TP5'); LONG_NAME = 'soil_temperatures_layer_5'; UNITS = 'K' ! units now K, rreichle & borescan, 6 Nov 2020 - case ('TP6'); LONG_NAME = 'soil_temperatures_layer_6'; UNITS = 'K' ! units now K, rreichle & borescan, 6 Nov 2020 - case ('PRECTOTLAND');LONG_NAME = 'Total_precipitation_land'; UNITS = 'kg m-2 s-1' - case ('PRECSNOLAND');LONG_NAME = 'snowfall_land'; UNITS = 'kg m-2 s-1' - case ('SNOWMASS') ;LONG_NAME = 'snow_mass'; UNITS = 'kg m-2' - case ('SNOMAS') ;LONG_NAME = 'snow_mass'; UNITS = 'kg m-2' - case ('SNO'); LONG_NAME = 'snowfall'; UNITS = 'kg m-2 s-1' - case ('SNODP'); LONG_NAME = 'snow_depth_in_snow_covered_area'; UNITS = 'm' - case ('EVPSOIL'); LONG_NAME = 'baresoil_evap_energy_flux'; UNITS = 'W m-2' - case ('EVPTRNS'); LONG_NAME = 'transpiration_energy_flux'; UNITS = 'W m-2' - case ('EVPINTR'); LONG_NAME = 'interception_loss_energy_flux'; UNITS = 'W m-2' - case ('EVPSBLN'); LONG_NAME = 'snow_ice_evaporation_energy_flux'; UNITS = 'W m-2' - case ('RUNOFF'); LONG_NAME = 'runoff_flux'; UNITS = 'kg m-2 s-1' - case ('BASEFLOW'); LONG_NAME = 'baseflow_flux'; UNITS = 'kg m-2 s-1' - case ('SMLAND'); LONG_NAME = 'Snowmelt_flux_land'; UNITS = 'kg m-2 s-1' - case ('QINFIL'); LONG_NAME = 'rainwater_infiltration_flux'; UNITS = 'kg m-2 s-1' - case ('FRUNST'); LONG_NAME = 'fractional_area_of_unsaturated_zone'; UNITS = '1' - case ('FRSAT'); LONG_NAME = 'fractional_area_of_saturated_zone'; UNITS = '1' - case ('FRSNO'); LONG_NAME = 'fractional_area_of_land_snowcover'; UNITS = '1' - case ('FRWLT'); LONG_NAME = 'fractional_area_of_wilting_zone'; UNITS = '1' - case ('PARDFLAND'); LONG_NAME = 'surface_downwelling_par_diffuse_flux'; UNITS = 'W m-2' - case ('PARDRLAND'); LONG_NAME = 'surface_downwelling_par_beam_flux'; UNITS = 'W m-2' - case ('SHLAND'); LONG_NAME = 'Sensible_heat_flux_land'; UNITS = 'W m-2' - case ('LHLAND'); LONG_NAME = 'Latent_heat_flux_land'; UNITS = 'W m-2' - case ('EVLAND'); LONG_NAME = 'Evaporation_land'; UNITS = 'kg m-2 s-1' - case ('LWLAND'); LONG_NAME = 'Net_longwave_land'; UNITS = 'W m-2' - case ('SWLAND'); LONG_NAME = 'Net_shortwave_land'; UNITS = 'W m-2' - case ('SWDOWNLAND'); LONG_NAME = 'Incident_shortwave_land'; UNITS = 'W m-2' - case ('GHLAND'); LONG_NAME = 'Ground_heating_land'; UNITS = 'W m-2' - case ('TWLAND'); LONG_NAME = 'Avail_water_storage_land'; UNITS = 'kg m-2' - case ('TSLAND'); LONG_NAME = 'Total_snow_storage_land'; UNITS = 'kg m-2' - case ('TELAND'); LONG_NAME = 'Total_energy_storage_land'; UNITS = 'J m-2' - case ('WCHANGE'); LONG_NAME = 'rate_of_change_of_total_land_water'; UNITS = 'kg m-2 s-1' - case ('ECHANGE'); LONG_NAME = 'rate_of_change_of_total_land_energy'; UNITS = 'W m-2' - case ('SPLAND'); LONG_NAME = 'rate_of_spurious_land_energy_source'; UNITS = 'W m-2' - case ('SPWATR'); LONG_NAME = 'rate_of_spurious_land_water_source'; UNITS = 'kg m-2 s-1' - case ('SPSNOW'); LONG_NAME = 'rate_of_spurious_snow_energy'; UNITS = 'W m-2' - case ('PEATCLSM_WATERLEVEL');LONG_NAME = 'depth_to_water_table_from_surface_in_peat'; UNITS = 'm' - case ('PEATCLSM_FSWCHANGE'); LONG_NAME = 'change_in_free_surface_water_reservoir_on_peat'; UNITS = 'kg m-2 s-1' - case ('CNLAI'); LONG_NAME = 'CN_exposed_leaf-area_index'; UNITS = '1' - case ('CNTLAI'); LONG_NAME = 'CN_total_leaf-area_index'; UNITS = '1' - case ('CNSAI'); LONG_NAME = 'CN_exposed_stem-area_index'; UNITS = '1' - case ('CNTOTC'); LONG_NAME = 'CN_total_carbon'; UNITS = 'kg m-2' - case ('CNVEGC'); LONG_NAME = 'CN_total_vegetation_carbon'; UNITS = 'kg m-2' - case ('CNROOT'); LONG_NAME = 'CN_total_root_carbon'; UNITS = 'kg m-2' - case ('CNNPP'); LONG_NAME = 'CN_net_primary_production'; UNITS = 'kg m-2 s-1' - case ('CNGPP'); LONG_NAME = 'CN_gross_primary_production'; UNITS = 'kg m-2 s-1' - case ('CNSR'); LONG_NAME = 'CN_total_soil_respiration'; UNITS = 'kg m-2 s-1' - case ('CNNEE'); LONG_NAME = 'CN_net_ecosystem_exchange'; UNITS = 'kg m-2 s-1' - case ('CNXSMR'); LONG_NAME = 'abstract_C_pool_to_meet_excess_MR_demand'; UNITS = 'kg m-2' - case ('CNADD'); LONG_NAME = 'CN_added_to_maintain_positive_C'; UNITS = 'kg m-2 s-1' - case ('PARABS'); LONG_NAME = 'absorbed_PAR'; UNITS = 'W m-2' - case ('PARINC'); LONG_NAME = 'incident_PAR'; UNITS = 'W m-2' - case ('SCSAT'); LONG_NAME = 'saturated_stomatal_conductance'; UNITS = 'm s-1' - case ('SCUNS'); LONG_NAME = 'unstressed_stomatal_conductance'; UNITS = 'm s-1' - case ('BTRAN'); LONG_NAME = 'transpiration coefficient'; UNITS = '1' - case ('SIF'); LONG_NAME = 'solar induced fluorescence'; UNITS = 'umol m-2 sm s-1' - case ('CLOSS'); LONG_NAME = 'CN_carbon_loss_to_fire'; UNITS = 'kg m-2 s-1' - case ('BURN'); LONG_NAME = 'CN_fractional_area_burn_rate'; UNITS = 's-1' - case ('FSEL'); LONG_NAME = 'fire season length'; UNITS = 'days' - case ('EVPSNO'); LONG_NAME = 'snowpack_evaporation_energy_flux'; UNITS = 'W m-2' - case ('GHTSKIN'); LONG_NAME = 'Ground_heating_skin_temp'; UNITS = 'W m-2' - case ('WAT10CM'); LONG_NAME = 'soil moisture in Upper 10cm'; UNITS = 'kg m-2' - case ('WATSOI'); LONG_NAME = 'totoal soil moisture'; UNITS = 'kg m-2' - case ('ICESOI'); LONG_NAME = 'soil frozen water content'; UNITS = 'kg m-2' - case ('RMELTDU001'); LONG_NAME = 'flushed_out_dust_mass_flux_from_the_bottom_layer_bin_1'; UNITS = 'kg m-2 s-1' - case ('RMELTDU002'); LONG_NAME = 'flushed_out_dust_mass_flux_from_the_bottom_layer_bin_2'; UNITS = 'kg m-2 s-1' - case ('RMELTDU003'); LONG_NAME = 'flushed_out_dust_mass_flux_from_the_bottom_layer_bin_3'; UNITS = 'kg m-2 s-1' - case ('RMELTDU004'); LONG_NAME = 'flushed_out_dust_mass_flux_from_the_bottom_layer_bin_4'; UNITS = 'kg m-2 s-1' - case ('RMELTDU005'); LONG_NAME = 'flushed_out_dust_mass_flux_from_the_bottom_layer_bin_5'; UNITS = 'kg m-2 s-1' - case ('RMELTBC001'); LONG_NAME = 'flushed_out_black_carbon_mass_flux_from_the_bottom_layer_bin_1'; UNITS = 'kg m-2 s-1' - case ('RMELTBC002'); LONG_NAME = 'flushed_out_black_carbon_mass_flux_from_the_bottom_layer_bin_2'; UNITS = 'kg m-2 s-1' - case ('RMELTOC001'); LONG_NAME = 'flushed_out_organic_carbon_mass_flux_from_the_bottom_layer_bin_1'; UNITS = 'kg m-2 s-1' - case ('RMELTOC002'); LONG_NAME = 'flushed_out_organic_carbon_mass_flux_from_the_bottom_layer_bin_2'; UNITS = 'kg m-2 s-1' + ! End L4_SM ------------------------------------------------------------------------------------------------------------------------------------------------- + + 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 = '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' + case ('Psurf'); LONG_NAME = 'surface_pressure'; UNITS = 'Pa' + case ('PS'); LONG_NAME = 'surface_pressure'; UNITS = 'Pa' + case ('Rainf_C'); LONG_NAME = 'convective_rainfall'; UNITS = 'kg m-2 s-1' + case ('Rainf'); LONG_NAME = 'liquid_water_precipitation'; UNITS = 'kg m-2 s-1' + case ('Snowf'); LONG_NAME = 'total_snowfall'; UNITS = 'kg m-2 s-1' + case ('RainfSnowf'); LONG_NAME = 'RainfSnowf'; UNITS = 'kg m-2 s-1' + case ('SWnet'); LONG_NAME = 'downward_net_shortwave_radiation'; UNITS = 'W m-2' + case ('RefH'); LONG_NAME = 'reference_height_for_Tair_Qair_Wind'; UNITS = 'm' + case ('DZ'); LONG_NAME = 'reference_height_for_Tair_Qair_Wind'; UNITS = 'm' + case ('CATDEF'); LONG_NAME = 'catchment_deficit'; UNITS = 'kg m-2' + case ('RZEXC'); LONG_NAME = 'root_zone_excess'; UNITS = 'kg m-2' + case ('SRFEXC'); LONG_NAME = 'surface_excess'; UNITS = 'kg m-2' + case ('CAPAC', 'INTRWATR'); LONG_NAME = 'vegetation_interception_water_storage'; UNITS = 'kg m-2' + 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 = 'soil_wetness_profile'; UNITS = '1' + case ('GWETROOT'); LONG_NAME = 'soil_wetness_rootzone'; UNITS = '1' + case ('GWETTOP'); LONG_NAME = 'soil_wetness_surface'; UNITS = '1' + case ('PRMC'); LONG_NAME = 'soil_moisture_profile'; UNITS = 'm3 m-3' + case ('RZMC'); LONG_NAME = 'soil_moisture_rootzone'; UNITS = 'm3 m-3' + case ('SFMC'); LONG_NAME = 'soil_moisture_surface'; UNITS = 'm3 m-3' + case ('TPSNOW', 'TPSNOWLAND'); LONG_NAME = 'surface_temperature_of_snow'; UNITS = 'K' + case ('TUNST' , 'TUNSTLAND'); LONG_NAME = 'surface_temperature_of_unsaturated_zone'; UNITS = 'K' + case ('TSAT' , 'TSATLAND'); LONG_NAME = 'surface_temperature_of_saturated_zone'; UNITS = 'K' + case ('TWLT' , 'TWLTLAND'); LONG_NAME = 'surface_temperature_of_wilting_zone'; UNITS = 'K' + case ('TSURF', 'TPSURF', 'TPSURFLAND'); LONG_NAME = 'surface_temperature_of_land_incl_snow'; UNITS = 'K' + case ('GRN'); LONG_NAME = 'vegetation_greenness_fraction'; UNITS = '1' + case ('LAI'); LONG_NAME = 'leaf_area_index'; UNITS = '1' + case ('TP1', 'TSOIL1'); LONG_NAME = 'soil_temperature_layer_1'; UNITS = 'K' ! units now K, rreichle & borescan, 6 Nov 2020 + case ('TP2', 'TSOIL2'); LONG_NAME = 'soil_temperature_layer_2'; UNITS = 'K' ! units now K, rreichle & borescan, 6 Nov 2020 + case ('TP3', 'TSOIL3'); LONG_NAME = 'soil_temperature_layer_3'; UNITS = 'K' ! units now K, rreichle & borescan, 6 Nov 2020 + case ('TP4', 'TSOIL4'); LONG_NAME = 'soil_temperature_layer_4'; UNITS = 'K' ! units now K, rreichle & borescan, 6 Nov 2020 + case ('TP5', 'TSOIL5'); LONG_NAME = 'soil_temperature_layer_5'; UNITS = 'K' ! units now K, rreichle & borescan, 6 Nov 2020 + case ('TP6', 'TSOIL6'); LONG_NAME = 'soil_temperature_layer_6'; UNITS = 'K' ! units now K, rreichle & borescan, 6 Nov 2020 + case ('PRECTOTLAND'); LONG_NAME = 'Total_precipitation_land'; UNITS = 'kg m-2 s-1' + case ('PRECSNOLAND'); LONG_NAME = 'snowfall_land'; UNITS = 'kg m-2 s-1' + case ('PRECTOTCORRLAND'); LONG_NAME = 'Total_precipitation_corrected_land'; UNITS = 'kg m-2 s-1' + case ('PRECSNOCORRLAND'); LONG_NAME = 'snowfall_corrected_land'; UNITS = 'kg m-2 s-1' + case ('SNOWMASS', 'SNOMAS'); LONG_NAME = 'snow_mass'; UNITS = 'kg m-2' + case ('TSLAND', 'SNOMASLAND'); LONG_NAME = 'Total_snow_storage_land'; UNITS = 'kg m-2' + case ('SNO'); LONG_NAME = 'snowfall'; UNITS = 'kg m-2 s-1' + case ('SNODP'); LONG_NAME = 'snow_depth_within_snow_covered_area_fraction'; UNITS = 'm' + case ('SNODPLAND'); LONG_NAME = 'snow_depth_within_snow_covered_area_fraction_on_land'; UNITS = 'm' + case ('EVPSOIL', 'LHLANDSOIL'); LONG_NAME = 'baresoil_evaporation_latent_heat_flux'; UNITS = 'W m-2' + case ('EVPTRNS', 'LHLANDTRNS'); LONG_NAME = 'transpiration_latent_heat_flux'; UNITS = 'W m-2' + case ('EVPINTR', 'LHLANDINTR'); LONG_NAME = 'interception_loss_latent_heat_flux'; UNITS = 'W m-2' + case ('EVPSBLN', 'LHLANDSBLN'); LONG_NAME = 'snowpack_evaporation_latent_heat_flux'; UNITS = 'W m-2' + case ('RUNOFF'); LONG_NAME = 'runoff_total_flux'; UNITS = 'kg m-2 s-1' + case ('RUNSURF'); LONG_NAME = 'overland runoff including throughflow'; UNITS = 'kg m-2 s-1' + case ('BASEFLOW'); LONG_NAME = 'baseflow_flux'; UNITS = 'kg m-2 s-1' + case ('BASEFLOWLAND'); LONG_NAME = 'baseflow_flux_land'; UNITS = 'kg m-2 s-1' + case ('SMLAND'); LONG_NAME = 'Snowmelt_flux_land'; UNITS = 'kg m-2 s-1' + case ('QINFIL', 'QINFILLAND'); LONG_NAME = 'soil_water_infiltration_rate'; UNITS = 'kg m-2 s-1' + case ('FRUNST', 'FRUNSTLAND'); LONG_NAME = 'fractional_area_of_unsaturated_zone'; UNITS = '1' + case ('FRSAT' , 'FRSATLAND' ); LONG_NAME = 'fractional_area_of_saturated_zone'; UNITS = '1' + case ('FRSNO' , 'FRSNOLAND' ); LONG_NAME = 'fractional_area_of_snow_on_land'; UNITS = '1' + case ('FRWLT' , 'FRWLTLAND' ); LONG_NAME = 'fractional_area_of_wilting_zone'; UNITS = '1' + case ('PARDFLAND'); LONG_NAME = 'surface_downwelling_PAR_diffuse_flux'; UNITS = 'W m-2' + case ('PARDRLAND'); LONG_NAME = 'surface_downwelling_PAR_beam_flux'; UNITS = 'W m-2' + case ('SHLAND'); LONG_NAME = 'Sensible_heat_flux_land'; UNITS = 'W m-2' + case ('LHLAND'); LONG_NAME = 'Latent_heat_flux_land'; UNITS = 'W m-2' + case ('EVLAND'); LONG_NAME = 'Total_evaporation_land'; UNITS = 'kg m-2 s-1' + case ('LWLAND'); LONG_NAME = 'Net_longwave_flux_land'; UNITS = 'W m-2' + case ('SWLAND'); LONG_NAME = 'Net_shortwave_flux_land'; UNITS = 'W m-2' + case ('SWDOWNLAND'); LONG_NAME = 'Incident_shortwave_flux_land'; UNITS = 'W m-2' + case ('GHLAND'); LONG_NAME = 'Ground_heating_flux_land'; UNITS = 'W m-2' + case ('TWLAND'); LONG_NAME = 'Total_water_storage_land'; UNITS = 'kg m-2' + case ('TELAND'); LONG_NAME = 'Total_energy_storage_land'; UNITS = 'J m-2' + case ('WCHANGE','WCHANGELAND'); LONG_NAME = 'rate_of_change_of_total_land_water'; UNITS = 'kg m-2 s-1' + case ('ECHANGE','ECHANGELAND'); LONG_NAME = 'rate_of_change_of_total_land_energy'; UNITS = 'W m-2' + case ('SPLAND', 'SPSHLAND'); LONG_NAME = 'Spurious_sensible_heat_flux_land'; UNITS = 'W m-2' + case ('SPLH' , 'SPLHLAND'); LONG_NAME = 'Spurious_latent_heat_flux_land'; UNITS = 'W m-2' + case ('SPWATR', 'SPEVLAND'); LONG_NAME = 'Spurious_evapotranspiration_flux_land'; UNITS = 'kg m-2 s-1' + case ('SPSNOW', 'SPSNLAND'); LONG_NAME = 'Spurious_snow_energy_flux_land'; UNITS = 'W m-2' + case ('PEATCLSM_WATERLEVEL'); LONG_NAME = 'depth_to_water_table_from_surface_in_peat'; UNITS = 'm' + case ('PEATCLSM_FSWCHANGE'); LONG_NAME = 'change_in_free_surface_water_reservoir_on_peat'; UNITS = 'kg m-2 s-1' + case ('CNLAI'); LONG_NAME = 'CN_exposed_leaf-area_index'; UNITS = '1' + case ('CNTLAI'); LONG_NAME = 'CN_total_leaf-area_index'; UNITS = '1' + case ('CNSAI'); LONG_NAME = 'CN_exposed_stem-area_index'; UNITS = '1' + case ('CNTOTC'); LONG_NAME = 'CN_total_carbon'; UNITS = 'kg m-2' + case ('CNVEGC'); LONG_NAME = 'CN_total_vegetation_carbon'; UNITS = 'kg m-2' + case ('CNROOT'); LONG_NAME = 'CN_total_root_carbon'; UNITS = 'kg m-2' + case ('CNNPP'); LONG_NAME = 'CN_net_primary_production'; UNITS = 'kg m-2 s-1' + case ('CNGPP'); LONG_NAME = 'CN_gross_primary_production'; UNITS = 'kg m-2 s-1' + case ('CNSR'); LONG_NAME = 'CN_total_soil_respiration'; UNITS = 'kg m-2 s-1' + case ('CNNEE'); LONG_NAME = 'CN_net_ecosystem_exchange'; UNITS = 'kg m-2 s-1' + case ('CNXSMR'); LONG_NAME = 'abstract_C_pool_to_meet_excess_MR_demand'; UNITS = 'kg m-2' + case ('CNADD'); LONG_NAME = 'CN_added_to_maintain_positive_C'; UNITS = 'kg m-2 s-1' + case ('PARABS'); LONG_NAME = 'absorbed_PAR'; UNITS = 'W m-2' + case ('PARINC'); LONG_NAME = 'incident_PAR'; UNITS = 'W m-2' + case ('SCSAT'); LONG_NAME = 'saturated_stomatal_conductance'; UNITS = 'm s-1' + case ('SCUNS'); LONG_NAME = 'unstressed_stomatal_conductance'; UNITS = 'm s-1' + case ('BTRAN'); LONG_NAME = 'transpiration coefficient'; UNITS = '1' + case ('SIF'); LONG_NAME = 'solar induced fluorescence'; UNITS = 'umol m-2 sm s-1' + case ('CLOSS'); LONG_NAME = 'CN_carbon_loss_to_fire'; UNITS = 'kg m-2 s-1' + case ('BURN'); LONG_NAME = 'CN_fractional_area_burn_rate'; UNITS = 's-1' + case ('FSEL'); LONG_NAME = 'fire season length'; UNITS = 'days' + case ('EVPSNO'); LONG_NAME = 'snowpack_evaporation_latent_heat_flux'; UNITS = 'W m-2' + case ('GHTSKIN'); LONG_NAME = 'Ground_heating_flux_for_skin_temp_land'; UNITS = 'W m-2' + case ('WAT10CM'); LONG_NAME = 'soil moisture in Upper 10cm'; UNITS = 'kg m-2' + case ('WATSOI'); LONG_NAME = 'total soil moisture'; UNITS = 'kg m-2' + case ('ICESOI'); LONG_NAME = 'soil frozen water content'; UNITS = 'kg m-2' + case ('RMELTDU001'); LONG_NAME = 'flushed_out_dust_mass_flux_from_the_bottom_layer_bin_1'; UNITS = 'kg m-2 s-1' + case ('RMELTDU002'); LONG_NAME = 'flushed_out_dust_mass_flux_from_the_bottom_layer_bin_2'; UNITS = 'kg m-2 s-1' + case ('RMELTDU003'); LONG_NAME = 'flushed_out_dust_mass_flux_from_the_bottom_layer_bin_3'; UNITS = 'kg m-2 s-1' + case ('RMELTDU004'); LONG_NAME = 'flushed_out_dust_mass_flux_from_the_bottom_layer_bin_4'; UNITS = 'kg m-2 s-1' + case ('RMELTDU005'); LONG_NAME = 'flushed_out_dust_mass_flux_from_the_bottom_layer_bin_5'; UNITS = 'kg m-2 s-1' + case ('RMELTBC001'); LONG_NAME = 'flushed_out_black_carbon_mass_flux_from_the_bottom_layer_bin_1'; UNITS = 'kg m-2 s-1' + case ('RMELTBC002'); LONG_NAME = 'flushed_out_black_carbon_mass_flux_from_the_bottom_layer_bin_2'; UNITS = 'kg m-2 s-1' + case ('RMELTOC001'); LONG_NAME = 'flushed_out_organic_carbon_mass_flux_from_the_bottom_layer_bin_1'; UNITS = 'kg m-2 s-1' + case ('RMELTOC002'); LONG_NAME = 'flushed_out_organic_carbon_mass_flux_from_the_bottom_layer_bin_2'; UNITS = 'kg m-2 s-1' ! land assimilation increments for Catchment prognostic variables in coupled land-atmosphere DAS (#sqz 2020-01) - case ('TCFSAT_INCR'); LONG_NAME = 'increment_canopy_temperature_saturated_zone'; UNITS = 'K' - case ('TCFTRN_INCR'); LONG_NAME = 'increment_canopy_temperature_transition_zone'; UNITS = 'K' - case ('TCFWLT_INCR'); LONG_NAME = 'increment_canopy_temperature_wilting_zone'; UNITS = 'K' - case ('QCFSAT_INCR'); LONG_NAME = 'increment_canopy_specific_humidity_saturated_zone'; UNITS = 'kg kg-1' - case ('QCFTRN_INCR'); LONG_NAME = 'increment_canopy_specific_humidity_transition_zone'; UNITS = 'kg kg-1' - case ('QCFWLT_INCR'); LONG_NAME = 'increment_canopy_specific_humidity_wilting_zone'; UNITS = 'kg kg-1' - case ('CAPAC_INCR'); LONG_NAME = 'increment_interception_reservoir_capac'; UNITS = 'kg m-2' - case ('CATDEF_INCR'); LONG_NAME = 'increment_catchment_deficit'; UNITS = 'kg m-2' - case ('RZEXC_INCR'); LONG_NAME = 'increment_root_zone_excess'; UNITS = 'kg m-2' - case ('SRFEXC_INCR'); LONG_NAME = 'increment_surface_excess'; UNITS = 'kg m-2' - case ('GHTCNT1_INCR'); LONG_NAME = 'increment_soil_heat_content_layer_1'; UNITS = 'J m-2' - case ('GHTCNT2_INCR'); LONG_NAME = 'increment_soil_heat_content_layer_2'; UNITS = 'J m-2' - case ('GHTCNT3_INCR'); LONG_NAME = 'increment_soil_heat_content_layer_3'; UNITS = 'J m-2' - case ('GHTCNT4_INCR'); LONG_NAME = 'increment_soil_heat_content_layer_4'; UNITS = 'J m-2' - case ('GHTCNT5_INCR'); LONG_NAME = 'increment_soil_heat_content_layer_5'; UNITS = 'J m-2' - case ('GHTCNT6_INCR'); LONG_NAME = 'increment_soil_heat_content_layer_6'; UNITS = 'J m-2' - case ('WESNN1_INCR'); LONG_NAME = 'increment_snow_mass_layer_1'; UNITS = 'kg m-2' - case ('WESNN2_INCR'); LONG_NAME = 'increment_snow_mass_layer_2'; UNITS = 'kg m-2' - case ('WESNN3_INCR'); LONG_NAME = 'increment_snow_mass_layer_3'; UNITS = 'kg m-2' - case ('HTSNNN1_INCR'); LONG_NAME = 'increment_heat_content_snow_layer_1'; UNITS = 'J m-2' - case ('HTSNNN2_INCR'); LONG_NAME = 'increment_heat_content_snow_layer_2'; UNITS = 'J m-2' - case ('HTSNNN3_INCR'); LONG_NAME = 'increment_heat_content_snow_layer_3'; UNITS = 'J m-2' - case ('SNDZN1_INCR'); LONG_NAME = 'increment_snow_depth_layer_1'; UNITS = 'm' - case ('SNDZN2_INCR'); LONG_NAME = 'increment_snow_depth_layer_2'; UNITS = 'm' - case ('SNDZN3_INCR'); LONG_NAME = 'increment_snow_depth_layer_3'; UNITS = 'm' + case ('TCFSAT_INCR'); LONG_NAME = 'increment_surface_temperature_of_saturated_zone'; UNITS = 'K' + case ('TCFTRN_INCR'); LONG_NAME = 'increment_surface_temperature_of_transition_zone'; UNITS = 'K' + case ('TCFWLT_INCR'); LONG_NAME = 'increment_surface_temperature_of_wilting_zone'; UNITS = 'K' + case ('QCFSAT_INCR'); LONG_NAME = 'increment_surface_specific_humidity_of_saturated_zone'; UNITS = 'kg kg-1' + case ('QCFTRN_INCR'); LONG_NAME = 'increment_surface_specific_humidity_of_transition_zone'; UNITS = 'kg kg-1' + case ('QCFWLT_INCR'); LONG_NAME = 'increment_surface_specific_humidity_of_wilting_zone'; UNITS = 'kg kg-1' + case ('CAPAC_INCR'); LONG_NAME = 'increment_vegetation_interception_water_storage'; UNITS = 'kg m-2' + case ('CATDEF_INCR'); LONG_NAME = 'increment_catchment_deficit'; UNITS = 'kg m-2' + case ('RZEXC_INCR'); LONG_NAME = 'increment_root_zone_excess'; UNITS = 'kg m-2' + case ('SRFEXC_INCR'); LONG_NAME = 'increment_surface_excess'; UNITS = 'kg m-2' + case ('GHTCNT1_INCR'); LONG_NAME = 'increment_soil_heat_content_layer_1'; UNITS = 'J m-2' + case ('GHTCNT2_INCR'); LONG_NAME = 'increment_soil_heat_content_layer_2'; UNITS = 'J m-2' + case ('GHTCNT3_INCR'); LONG_NAME = 'increment_soil_heat_content_layer_3'; UNITS = 'J m-2' + case ('GHTCNT4_INCR'); LONG_NAME = 'increment_soil_heat_content_layer_4'; UNITS = 'J m-2' + case ('GHTCNT5_INCR'); LONG_NAME = 'increment_soil_heat_content_layer_5'; UNITS = 'J m-2' + case ('GHTCNT6_INCR'); LONG_NAME = 'increment_soil_heat_content_layer_6'; UNITS = 'J m-2' + case ('WESNN1_INCR'); LONG_NAME = 'increment_snow_mass_layer_1'; UNITS = 'kg m-2' + case ('WESNN2_INCR'); LONG_NAME = 'increment_snow_mass_layer_2'; UNITS = 'kg m-2' + case ('WESNN3_INCR'); LONG_NAME = 'increment_snow_mass_layer_3'; UNITS = 'kg m-2' + case ('HTSNNN1_INCR'); LONG_NAME = 'increment_heat_content_snow_layer_1'; UNITS = 'J m-2' + case ('HTSNNN2_INCR'); LONG_NAME = 'increment_heat_content_snow_layer_2'; UNITS = 'J m-2' + case ('HTSNNN3_INCR'); LONG_NAME = 'increment_heat_content_snow_layer_3'; UNITS = 'J m-2' + case ('SNDZN1_INCR'); LONG_NAME = 'increment_snow_depth_layer_1'; UNITS = 'm' + case ('SNDZN2_INCR'); LONG_NAME = 'increment_snow_depth_layer_2'; UNITS = 'm' + case ('SNDZN3_INCR'); LONG_NAME = 'increment_snow_depth_layer_3'; UNITS = 'm' ! land assimilation forecast and analysis for Catchment model diagnostics - case ('SFMC_FCST'); LONG_NAME = 'soil_moisture_surface_forecast'; UNITS = 'm3 m-3' - case ('RZMC_FCST'); LONG_NAME = 'soil_moisture_rootzone_forecast'; UNITS = 'm3 m-3' - case ('PRMC_FCST'); LONG_NAME = 'soil_moisture_profile_forecast'; UNITS = 'm3 m-3' - case ('TSURF_FCST'); LONG_NAME = 'ave_catchment_temp_incl_snw_forecast'; UNITS = 'K' - case ('TSOIL1_FCST'); LONG_NAME = 'soil_temperatures_layer_1_forecast'; UNITS = 'K' - - case ('SFMC_FCST_ENSSTD'); LONG_NAME = 'soil_moisture_surface_forecast_ensstd'; UNITS = 'm3 m-3' - case ('RZMC_FCST_ENSSTD'); LONG_NAME = 'soil_moisture_rootzone_forecast_ensstd'; UNITS = 'm3 m-3' - case ('PRMC_FCST_ENSSTD'); LONG_NAME = 'soil_moisture_profile_forecast_ensstd'; UNITS = 'm3 m-3' - case ('TSURF_FCST_ENSSTD'); LONG_NAME = 'ave_catchment_temp_incl_snw_forecast_ensstd'; UNITS = 'K' - case ('TSOIL1_FCST_ENSSTD'); LONG_NAME = 'soil_temperatures_layer_1_forecast_ensstd'; UNITS = 'K' - - case ('SFMC_ANA'); LONG_NAME = 'soil_moisture_surface_analysis'; UNITS = 'm3 m-3' - case ('RZMC_ANA'); LONG_NAME = 'soil_moisture_rootzone_analysis'; UNITS = 'm3 m-3' - case ('PRMC_ANA'); LONG_NAME = 'soil_moisture_profile_analysis'; UNITS = 'm3 m-3' - case ('TSURF_ANA'); LONG_NAME = 'ave_catchment_temp_incl_snw_analysis'; UNITS = 'K' - case ('TSOIL1_ANA'); LONG_NAME = 'soil_temperatures_layer_1_analysis'; UNITS = 'K' - - case ('SFMC_ANA_ENSSTD'); LONG_NAME = 'soil_moisture_surface_analysis_ensstd'; UNITS = 'm3 m-3' - case ('RZMC_ANA_ENSSTD'); LONG_NAME = 'soil_moisture_rootzone_analysis_ensstd'; UNITS = 'm3 m-3' - case ('PRMC_ANA_ENSSTD'); LONG_NAME = 'soil_moisture_profile_analysis_ensstd'; UNITS = 'm3 m-3' - case ('TSURF_ANA_ENSSTD'); LONG_NAME = 'ave_catchment_temp_incl_snw_analysis_ensstd'; UNITS = 'K' - case ('TSOIL1_ANA_ENSSTD'); LONG_NAME = 'soil_temperatures_layer_1_analysis_ensstd'; UNITS = 'K' - - ! other land assimilation fields - - case ('MWRTM_VEGOPACITY'); LONG_NAME = 'Lband_microwave_vegopacity_normalized_with_cos_inc_angle'; UNITS = '1' + case ('SFMC_FCST'); LONG_NAME = 'soil_moisture_surface_forecast'; UNITS = 'm3 m-3' + case ('RZMC_FCST'); LONG_NAME = 'soil_moisture_rootzone_forecast'; UNITS = 'm3 m-3' + case ('PRMC_FCST'); LONG_NAME = 'soil_moisture_profile_forecast'; UNITS = 'm3 m-3' + case ('TSURF_FCST'); LONG_NAME = 'surface_temperature_of_land_incl_snow_forecast'; UNITS = 'K' + case ('TSOIL1_FCST'); LONG_NAME = 'soil_temperature_layer_1_forecast'; UNITS = 'K' + + case ('SFMC_FCST_ENSSTD'); LONG_NAME = 'soil_moisture_surface_forecast_ensstd'; UNITS = 'm3 m-3' + case ('RZMC_FCST_ENSSTD'); LONG_NAME = 'soil_moisture_rootzone_forecast_ensstd'; UNITS = 'm3 m-3' + case ('PRMC_FCST_ENSSTD'); LONG_NAME = 'soil_moisture_profile_forecast_ensstd'; UNITS = 'm3 m-3' + case ('TSURF_FCST_ENSSTD'); LONG_NAME = 'surface_temperature_of_land_incl_snow_forecast_ensstd'; UNITS = 'K' + case ('TSOIL1_FCST_ENSSTD'); LONG_NAME = 'soil_temperature_layer_1_forecast_ensstd'; UNITS = 'K' + + case ('SFMC_ANA'); LONG_NAME = 'soil_moisture_surface_analysis'; UNITS = 'm3 m-3' + case ('RZMC_ANA'); LONG_NAME = 'soil_moisture_rootzone_analysis'; UNITS = 'm3 m-3' + case ('PRMC_ANA'); LONG_NAME = 'soil_moisture_profile_analysis'; UNITS = 'm3 m-3' + case ('TSURF_ANA'); LONG_NAME = 'surface_temperature_of_land_incl_snow_analysis'; UNITS = 'K' + case ('TSOIL1_ANA'); LONG_NAME = 'soil_temperature_layer_1_analysis'; UNITS = 'K' + + case ('SFMC_ANA_ENSSTD'); LONG_NAME = 'soil_moisture_surface_analysis_ensstd'; UNITS = 'm3 m-3' + case ('RZMC_ANA_ENSSTD'); LONG_NAME = 'soil_moisture_rootzone_analysis_ensstd'; UNITS = 'm3 m-3' + case ('PRMC_ANA_ENSSTD'); LONG_NAME = 'soil_moisture_profile_analysis_ensstd'; UNITS = 'm3 m-3' + case ('TSURF_ANA_ENSSTD'); LONG_NAME = 'surface_temperature_of_land_incl_snow_ensstd'; UNITS = 'K' + case ('TSOIL1_ANA_ENSSTD'); LONG_NAME = 'soil_temperature_layer_1_analysis_ensstd'; UNITS = 'K' + + ! other land assimilation fields + + case ('MWRTM_VEGOPACITY'); LONG_NAME = 'Lband_microwave_vegopacity_normalized_with_cos_inc_angle'; UNITS = '1' ! default LONG_NAME and UNITS for nc4 files created by tile_bin2nc4.F90 (used for any SHORT_NAME not listed above): - case default; LONG_NAME = 'not defined in tile_bin2nc4.F90'; UNITS = 'not defined in tile_bin2nc4.F90'; - + case default; LONG_NAME = 'not defined in tile_bin2nc4.F90'; UNITS = 'not defined in tile_bin2nc4.F90'; + end select - + if (present(LNAME)) str_atr = trim (LONG_NAME) if (present(UNT)) str_atr = trim (UNITS ) - + END FUNCTION getAttribute - + END PROGRAM tile_bin2nc4 From 1d48a99b1cbf9b012b1486199ade45567f3e6b76 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Tue, 17 Dec 2024 14:48:27 -0500 Subject: [PATCH 028/107] minor cleanup of comments and indentation (GEOS_EnsGridComp.F90) --- GEOSens_GridComp/GEOS_EnsGridComp.F90 | 215 ++++++++++++++------------ 1 file changed, 115 insertions(+), 100 deletions(-) diff --git a/GEOSens_GridComp/GEOS_EnsGridComp.F90 b/GEOSens_GridComp/GEOS_EnsGridComp.F90 index 1e8b0036..f0eef36b 100644 --- a/GEOSens_GridComp/GEOS_EnsGridComp.F90 +++ b/GEOSens_GridComp/GEOS_EnsGridComp.F90 @@ -4,7 +4,8 @@ module GEOS_EnsGridCompMod ! !USES - !! This grid comp behaves like a coupler. The set service, initialization are compliant with MAPL grid comp concept. + !! This grid comp behaves like a coupler; SetServices() and Initialize() are compliant with MAPL's GridComp concept. + use ESMF use MAPL_Mod use catch_constants, only: DZGT => CATCH_DZGT @@ -31,22 +32,22 @@ module GEOS_EnsGridCompMod integer, parameter :: NUM_SUBTILES=4 real :: enavg_nodata_threshold - type(cat_progn_type),dimension(:,:), allocatable :: catch_progn - type(cat_param_type),dimension(: ), allocatable :: catch_param - - + type(cat_progn_type), dimension(:,:), allocatable :: catch_progn + type(cat_param_type), dimension(: ), allocatable :: catch_param ! 1d only, assumes no parameter perturbations! + + contains - + !BOP - - ! !IROTUINE: SetServices -- Set ESMF services for this component - + + ! !ROUTINE: SetServices -- Set ESMF services for this component + ! !INTERFACE: - + subroutine SetServices(gc, rc) - + ! !ARGUMENTS: - + type(ESMF_GridComp), intent(inout) :: gc ! gridded component integer, optional :: rc ! return code @@ -73,7 +74,7 @@ subroutine SetServices(gc, rc) ) VERIFY_(status) - ! phase one: collect forcing ensemble + ! phase 1: collect forcing ensemble call MAPL_GridCompSetEntryPoint( & gc, & ESMF_METHOD_RUN, & @@ -82,7 +83,7 @@ subroutine SetServices(gc, rc) ) VERIFY_(status) - ! phase two : collect ensemble out from land + ! phase 2: collect ensemble out from land call MAPL_GridCompSetEntryPoint( & gc, & ESMF_METHOD_RUN, & @@ -91,11 +92,11 @@ subroutine SetServices(gc, rc) ) VERIFY_(status) - !phase 3 : get cat_param + ! phase 3: get catch_param call MAPL_GridCompSetEntryPoint( & gc, & ESMF_METHOD_RUN, & - GET_CATCH_PARAM , & + GET_CATCH_PARAM , & rc=status & ) VERIFY_(status) @@ -1224,21 +1225,19 @@ subroutine SetServices(gc, rc) VLOCATION = MAPL_VLocationNone, & RC=STATUS ) VERIFY_(STATUS) - - - call MAPL_AddExportSpec(GC, & - SHORT_NAME = 'ACCUM', & - LONG_NAME = 'net_ice_accumulation_rate', & - UNITS = 'kg m-2 s-1', & - DIMS = MAPL_DimsTileOnly, & - VLOCATION = MAPL_VLocationNone, & - RC=STATUS ) - VERIFY_(STATUS) - - + + call MAPL_AddExportSpec(GC, & + SHORT_NAME = 'ACCUM', & + LONG_NAME = 'net_ice_accumulation_rate', & + UNITS = 'kg m-2 s-1', & + DIMS = MAPL_DimsTileOnly, & + VLOCATION = MAPL_VLocationNone, & + RC=STATUS ) + VERIFY_(STATUS) + call MAPL_AddExportSpec(GC, & SHORT_NAME = 'EVLAND', & - LONG_NAME = 'total_evapotranspiration_land', & + LONG_NAME = 'total_evapotranspiration_land', & UNITS = 'kg m-2 s-1', & DIMS = MAPL_DimsTileOnly, & VLOCATION = MAPL_VLocationNone, & @@ -1950,10 +1949,11 @@ subroutine SetServices(gc, rc) end subroutine SetServices - + ! ------------------------------------------------------------------------------------------------------------ + ! !BOP - - ! !IROTUINE: Initialize -- initialize method for LDAS GC + ! + ! !ROUTINE: Initialize -- initialize method for LDAS Ens GC ! !INTERFACE: @@ -2020,10 +2020,11 @@ subroutine Initialize(gc, import, export, clock, rc) end subroutine Initialize - + ! ------------------------------------------------------------------------------------------------------------ + ! !BOP - - ! !IROTUINE: collecting and averaging + ! + ! !ROUTINE: collect and average surface met forcing ensemble subroutine Collect_force_ens(gc, import, export, clock, rc) @@ -2097,7 +2098,6 @@ subroutine Collect_force_ens(gc, import, export, clock, rc) call MAPL_TimerOn(MAPL, "TOTAL") call MAPL_TimerOn(MAPL, "Collect_force") - call MAPL_GetPointer(import, TApert, 'TApert', rc=status) VERIFY_(status) call MAPL_GetPointer(import, QApert, 'QApert', rc=status) @@ -2242,6 +2242,10 @@ subroutine Collect_force_ens(gc, import, export, clock, rc) end subroutine Collect_force_ens + ! ------------------------------------------------------------------------------------------------------------ + ! + ! !ROUTINE: collect and average land ensemble + subroutine Collect_land_ens(gc, import, export, clock, rc) ! !ARGUMENTS: @@ -3868,7 +3872,10 @@ subroutine Collect_land_ens(gc, import, export, clock, rc) RETURN_(ESMF_SUCCESS) end subroutine Collect_land_ens - + + ! ------------------------------------------------------------------------------------------------------------ + ! + ! !ROUTINE: collect Catchment model parameters subroutine GET_CATCH_PARAM( GC, IMPORT, EXPORT, CLOCK, RC ) @@ -3893,38 +3900,38 @@ subroutine GET_CATCH_PARAM( GC, IMPORT, EXPORT, CLOCK, RC ) logical :: firsttime = .true. real, pointer :: poros(:) =>null() - real, pointer :: cond(:) =>null() - real, pointer :: psis(:) =>null() - real, pointer :: bee(:) =>null() + real, pointer :: cond(:) =>null() + real, pointer :: psis(:) =>null() + real, pointer :: bee(:) =>null() real, pointer :: wpwet(:) =>null() - real, pointer :: gnu(:) =>null() - real, pointer :: vgwmax(:) =>null() - real, pointer :: bf1(:) =>null() - real, pointer :: bf2(:) =>null() - real, pointer :: bf3(:) =>null() + real, pointer :: gnu(:) =>null() + real, pointer :: vgwmax(:)=>null() + real, pointer :: bf1(:) =>null() + real, pointer :: bf2(:) =>null() + real, pointer :: bf3(:) =>null() real, pointer :: cdcr1(:) =>null() real, pointer :: cdcr2(:) =>null() - real, pointer :: ars1(:) =>null() - real, pointer :: ars2(:) =>null() - real, pointer :: ars3(:) =>null() - real, pointer :: ara1(:) =>null() - real, pointer :: ara2(:) =>null() - real, pointer :: ara3(:) =>null() - real, pointer :: ara4(:) =>null() - real, pointer :: arw1(:) =>null() - real, pointer :: arw2(:) =>null() - real, pointer :: arw3(:) =>null() - real, pointer :: arw4(:) =>null() - real, pointer :: tsa1(:) =>null() - real, pointer :: tsa2(:) =>null() - real, pointer :: tsb1(:) =>null() - real, pointer :: tsb2(:) =>null() - real, pointer :: atau(:) =>null() - real, pointer :: btau(:) =>null() - real, pointer :: ity(:) =>null() - real, pointer :: z2ch(:) =>null() - - real :: SURFLAY, x + real, pointer :: ars1(:) =>null() + real, pointer :: ars2(:) =>null() + real, pointer :: ars3(:) =>null() + real, pointer :: ara1(:) =>null() + real, pointer :: ara2(:) =>null() + real, pointer :: ara3(:) =>null() + real, pointer :: ara4(:) =>null() + real, pointer :: arw1(:) =>null() + real, pointer :: arw2(:) =>null() + real, pointer :: arw3(:) =>null() + real, pointer :: arw4(:) =>null() + real, pointer :: tsa1(:) =>null() + real, pointer :: tsa2(:) =>null() + real, pointer :: tsb1(:) =>null() + real, pointer :: tsb2(:) =>null() + real, pointer :: atau(:) =>null() + real, pointer :: btau(:) =>null() + real, pointer :: ity(:) =>null() + real, pointer :: z2ch(:) =>null() + + real :: SURFLAY, x integer :: i if (firsttime) then @@ -4001,46 +4008,48 @@ subroutine GET_CATCH_PARAM( GC, IMPORT, EXPORT, CLOCK, RC ) catch_param(:)%dzgt(4) = dzgt(4) catch_param(:)%dzgt(5) = dzgt(5) catch_param(:)%dzgt(6) = dzgt(6) - catch_param(:)%poros = poros - catch_param(:)%cond = cond - catch_param(:)%psis = psis - catch_param(:)%bee = bee - catch_param(:)%wpwet = wpwet - catch_param(:)%gnu = gnu - catch_param(:)%vgwmax= vgwmax - catch_param(:)%bf1 = bf1 - catch_param(:)%bf2 = bf2 - catch_param(:)%bf3 = bf3 - catch_param(:)%cdcr1 = cdcr1 - catch_param(:)%cdcr2 = cdcr2 - catch_param(:)%ars1 = ars1 - catch_param(:)%ars2 = ars2 - catch_param(:)%ars3 = ars3 - catch_param(:)%ara1 = ara1 - catch_param(:)%ara2 = ara2 - catch_param(:)%ara3 = ara3 - catch_param(:)%ara4 = ara4 - catch_param(:)%arw1 = arw1 - catch_param(:)%arw2 = arw2 - catch_param(:)%arw3 = arw3 - catch_param(:)%arw4 = arw4 - catch_param(:)%tsa1 = tsa1 - catch_param(:)%tsa2 = tsa2 - catch_param(:)%tsb1 = tsb1 - catch_param(:)%tsb2 = tsb2 - catch_param(:)%atau = atau - catch_param(:)%btau = btau + catch_param(:)%poros = poros + catch_param(:)%cond = cond + catch_param(:)%psis = psis + catch_param(:)%bee = bee + catch_param(:)%wpwet = wpwet + catch_param(:)%gnu = gnu + catch_param(:)%vgwmax = vgwmax + catch_param(:)%bf1 = bf1 + catch_param(:)%bf2 = bf2 + catch_param(:)%bf3 = bf3 + catch_param(:)%cdcr1 = cdcr1 + catch_param(:)%cdcr2 = cdcr2 + catch_param(:)%ars1 = ars1 + catch_param(:)%ars2 = ars2 + catch_param(:)%ars3 = ars3 + catch_param(:)%ara1 = ara1 + catch_param(:)%ara2 = ara2 + catch_param(:)%ara3 = ara3 + catch_param(:)%ara4 = ara4 + catch_param(:)%arw1 = arw1 + catch_param(:)%arw2 = arw2 + catch_param(:)%arw3 = arw3 + catch_param(:)%arw4 = arw4 + catch_param(:)%tsa1 = tsa1 + catch_param(:)%tsa2 = tsa2 + catch_param(:)%tsb1 = tsb1 + catch_param(:)%tsb2 = tsb2 + catch_param(:)%atau = atau + catch_param(:)%btau = btau catch_param(:)%vegcls = nint(ity) catch_param(:)%veghght = z2ch call MAPL_GetResource(MAPL, SURFLAY, Label="SURFLAY:", DEFAULT=50.0, rc=status) - catch_param(:)%dzsf = SURFLAY - catch_param(:)%dzpr = (cdcr2/(1.-wpwet)) / poros - catch_param(:)%dzrz = vgwmax/poros + catch_param(:)%dzsf = SURFLAY + catch_param(:)%dzpr = (cdcr2/(1.-wpwet)) / poros + catch_param(:)%dzrz = vgwmax/poros + + ! assign NaN to other fields - !assign NaN to other fields x = ieee_value(x,ieee_quiet_nan) + catch_param(:)%soilcls30 = transfer(x,i) catch_param(:)%soilcls100 = transfer(x,i) catch_param(:)%gravel30 = x @@ -4053,10 +4062,14 @@ subroutine GET_CATCH_PARAM( GC, IMPORT, EXPORT, CLOCK, RC ) catch_param(:)%wpwet30 = x catch_param(:)%poros30 = x catch_param(:)%dpth = x + endif + RETURN_(ESMF_SUCCESS) -end subroutine GET_CATCH_PARAM + end subroutine GET_CATCH_PARAM + + ! ------------------------------------------------------------------------------------------------------------ subroutine Finalize(gc, import, export, clock, rc) @@ -4096,3 +4109,5 @@ subroutine Finalize(gc, import, export, clock, rc) end subroutine Finalize end module GEOS_EnsGridCompMod + +! ============================= EOF ====================================================================== From 9ebcc45cfc48275c1239ce8203a4456e6a8428b7 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Tue, 17 Dec 2024 14:49:32 -0500 Subject: [PATCH 029/107] added land constants collection to GEOSldas_HIST.rc --- GEOSldas_App/GEOSldas_HIST.rc | 57 +++++++++++++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 2 deletions(-) diff --git a/GEOSldas_App/GEOSldas_HIST.rc b/GEOSldas_App/GEOSldas_HIST.rc index f6534f80..e1f560d7 100644 --- a/GEOSldas_App/GEOSldas_HIST.rc +++ b/GEOSldas_App/GEOSldas_HIST.rc @@ -23,6 +23,8 @@ COLLECTIONS: # 'catch_progn_incr' # 'inst3_1d_lndfcstana_Nt' # 'inst3_2d_lndfcstana_Nx' +# 'const_1d_lnd_Nt' +# 'const_2d_lnd_Nx' :: #CUBE GRID_LABELS: PC720x361-DC @@ -134,7 +136,7 @@ COLLECTIONS: 'TPSAT' , 'GridComp' , 'TSATLAND' , 'TPWLT' , 'GridComp' , 'TWLTLAND' , 'TPSURF' , 'GridComp' , 'TSURFLAND' , - 'TP1' , 'GridComp' , 'TSOIL1' , ! CATCH GC: TP1, ENS GC: TSOIL1TILE + 'TP1' , 'GridComp' , 'TSOIL1' , ! CATCH GC: TP1, ENSAVG GC: TSOIL1TILE 'TP2' , 'GridComp' , 'TSOIL2' , ! ... 'TP3' , 'GridComp' , 'TSOIL3' , ! ... 'TP4' , 'GridComp' , 'TSOIL4' , ! ... @@ -238,7 +240,7 @@ COLLECTIONS: 'TPSAT' , 'GridComp' , 'TSATLAND' , 'TPWLT' , 'GridComp' , 'TWLTLAND' , 'TPSURF' , 'GridComp' , 'TSURFLAND' , - 'TP1' , 'GridComp' , 'TSOIL1' , ! CATCH GC: TP1, ENS GC: TSOIL1TILE + 'TP1' , 'GridComp' , 'TSOIL1' , ! CATCH GC: TP1, ENSAVG GC: TSOIL1TILE 'TP2' , 'GridComp' , 'TSOIL2' , ! ... 'TP3' , 'GridComp' , 'TSOIL3' , ! ... 'TP4' , 'GridComp' , 'TSOIL4' , ! ... @@ -317,6 +319,57 @@ COLLECTIONS: >>>HIST_IRRIG<<< 'IRRIGRATE' , 'GridComp' , :: + + const_1d_lnd_Nt.descr: 'Tile-space,Constant,Time-invariant,Single-Level,Assimilation,Land Surface Model Parameters', + const_1d_lnd_Nt.template: '%y4%m2%d2_%h2%n2z.bin', + const_1d_lnd_Nt.mode: 'instantaneous', + const_1d_lnd_Nt.frequency: 240000, + const_1d_lnd_Nt.ref_time: 240000, + const_1d_lnd_Nt.fields: 'DZGT1' , 'GridComp' , + 'DZGT2' , 'GridComp' , + 'DZGT3' , 'GridComp' , + 'DZGT4' , 'GridComp' , + 'DZGT5' , 'GridComp' , + 'DZGT6' , 'GridComp' , + 'DZPR' , 'GridComp' , + 'DZRZ' , 'GridComp' , + 'DZSF' , 'GridComp' , + 'DZTS' , 'GridComp' , + 'WPWET' , 'GridComp' , + 'WPEMW' , 'GridComp' , + 'WPMC' , 'GridComp' , + 'CDCR2' , 'GridComp' , + 'POROS' , 'GridComp' , + :: + + const_2d_lnd_Nx.format: 'CFIO', + const_2d_lnd_Nx.descr: '2d,Constant,Time-invariant,Single-Level,Assimilation,Land Surface Model Parameters', + const_2d_lnd_Nx.template: '%y4%m2%d2_%h2%n2z.nc4', + const_2d_lnd_Nx.mode: 'instantaneous', + const_2d_lnd_Nx.frequency: 240000, + const_2d_lnd_Nx.ref_time: 240000, + const_2d_lnd_Nx.regrid_exch: '../input/tile.data' + const_2d_lnd_Nx.regrid_name: 'GRIDNAME' + const_2d_lnd_Nx.grid_label: PC720x361-DC + const_2d_lnd_Nx.deflate: 2, + const_2d_lnd_Nx.fields: 'DZGT1' , 'GridComp' , + 'DZGT2' , 'GridComp' , + 'DZGT3' , 'GridComp' , + 'DZGT4' , 'GridComp' , + 'DZGT5' , 'GridComp' , + 'DZGT6' , 'GridComp' , + 'DZPR' , 'GridComp' , + 'DZRZ' , 'GridComp' , + 'DZSF' , 'GridComp' , + 'DZTS' , 'GridComp' , + 'WPWET' , 'GridComp' , + 'WPEMW' , 'GridComp' , + 'WPMC' , 'GridComp' , + 'CDCR2' , 'GridComp' , + 'POROS' , 'GridComp' , + :: + + SMAP_L4_SM_gph.descr: 'Tile-space,3-Hourly,Time-Averaged,Single-Level,Assimilation,SMAP L4_SM Land Geophysical Diagnostics', SMAP_L4_SM_gph.nbits: 12, SMAP_L4_SM_gph.template: '%y4%m2%d2_%h2%n2z.bin', From 542b8432e52521ba75ba234f5e04083f46f463bf Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Tue, 17 Dec 2024 14:53:36 -0500 Subject: [PATCH 030/107] added land constants variable names and definitions to tile_bin2nc4.F90 --- GEOSldas_App/tile_bin2nc4.F90 | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/GEOSldas_App/tile_bin2nc4.F90 b/GEOSldas_App/tile_bin2nc4.F90 index 0aae4099..619a8848 100644 --- a/GEOSldas_App/tile_bin2nc4.F90 +++ b/GEOSldas_App/tile_bin2nc4.F90 @@ -393,6 +393,24 @@ FUNCTION getAttribute (SHORT_NAME, LNAME, UNT) result (str_atr) case ('RMELTOC001'); LONG_NAME = 'flushed_out_organic_carbon_mass_flux_from_the_bottom_layer_bin_1'; UNITS = 'kg m-2 s-1' case ('RMELTOC002'); LONG_NAME = 'flushed_out_organic_carbon_mass_flux_from_the_bottom_layer_bin_2'; UNITS = 'kg m-2 s-1' + ! land constants + + case ('CDCR2'); LONG_NAME = 'maximum soil water content above wilting point'; UNITS = 'kg m-2' + case ('DZGT1'); LONG_NAME = 'thickness_of_soil_layer_associated_with_TSOIL1'; UNITS = 'm' + case ('DZGT2'); LONG_NAME = 'thickness_of_soil_layer_associated_with_TSOIL2'; UNITS = 'm' + case ('DZGT3'); LONG_NAME = 'thickness_of_soil_layer_associated_with_TSOIL3'; UNITS = 'm' + case ('DZGT4'); LONG_NAME = 'thickness_of_soil_layer_associated_with_TSOIL4'; UNITS = 'm' + case ('DZGT5'); LONG_NAME = 'thickness_of_soil_layer_associated_with_TSOIL5'; UNITS = 'm' + case ('DZGT6'); LONG_NAME = 'thickness_of_soil_layer_associated_with_TSOIL6'; UNITS = 'm' + case ('DZPR'); LONG_NAME = 'thickness_of_soil_layer_associated_with_PRMC_and_GWETPROF'; UNITS = 'm' + case ('DZRZ'); LONG_NAME = 'thickness_of_soil_layer_associated_with_RZMC_and_GWETROOT'; UNITS = 'm' + case ('DZSF'); LONG_NAME = 'thickness_of_soil_layer_associated_with_SFMC_and_GWETTOP'; UNITS = 'm' + case ('DZTS'); LONG_NAME = 'thickness_of_soil_layer_associated_with_TSATLAND_TUNSTLAND_and_TWLTLAND'; UNITS = 'm' + case ('POROS'); LONG_NAME = 'soil_porosity'; UNITS = 'm3 m-3' + case ('WPEMW'); LONG_NAME = 'soil_wilting_point_in_equivalent_mass_of_total_profile_water'; UNITS = 'kg m-2' + case ('WPMC'); LONG_NAME = 'soil_wilting_point_in_volumetric_units'; UNITS = 'm3 m-3' + case ('WPWET'); LONG_NAME = 'soil_wilting_point_in_degree_of_saturation_units'; UNITS = '1' + ! land assimilation increments for Catchment prognostic variables in coupled land-atmosphere DAS (#sqz 2020-01) case ('TCFSAT_INCR'); LONG_NAME = 'increment_surface_temperature_of_saturated_zone'; UNITS = 'K' From a2dd1177eea71e6b16fc89c206bb6eb0fb2c2c54 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Tue, 17 Dec 2024 16:00:19 -0700 Subject: [PATCH 031/107] enforce time range for ASCAT and SMAP obs reader --- .../clsm_ensupd_read_obs.F90 | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 05eeaf66..fb3ffb2f 100644 --- a/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -1629,6 +1629,7 @@ subroutine read_obs_sm_ASCAT_EUMET( & 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 + type(date_time_type) :: date_time_first_obs, date_time_last_obs integer :: ii, ind, N_tmp, N_files, kk, N_obs, N_fnames, N_fnames_tmp, obs_dir_hier @@ -1688,6 +1689,38 @@ subroutine read_obs_sm_ASCAT_EUMET( & nullify( tmp_obs, tmp_lat, tmp_lon, tmp_tile_num, tmp_jtime ) ! --------------- + + ! check if we are within time periods when observations are available for metop-a, metop-b, or metop-c + ! if not, then return + + if (trim(this_obs_param%descr) == 'ASCAT_META_SM') then + date_time_first_obs = date_time_type(2007, 6, 1, 1,31, 0, 0, 0) + date_time_last_obs = date_time_type(2021,11,15, 9, 0, 0, 0, 0) + elseif (trim(this_obs_param%descr) == 'ASCAT_METB_SM') then + date_time_first_obs = date_time_type(2013, 4,24, 8, 0, 0, 0, 0) + date_time_last_obs = date_time_type(2100, 1, 1, 0, 0, 0, 0, 0) + elseif (trim(this_obs_param%descr) == 'ASCAT_METC_SM') then + date_time_first_obs = date_time_type(2019,11,25,12, 0, 0, 0, 0) + date_time_last_obs = date_time_type(2100, 1, 1, 0, 0, 0, 0, 0) + else + err_msg = 'Unknown observation time range for this ASCAT observation type' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + end if + + if (datetime_lt_refdatetime(date_time, date_time_first_obs) .or. & + datetime_lt_refdatetime(date_time_last_obs, date_time)) then + found_obs = .false. + ASCAT_sm = this_obs_param%nodata + ASCAT_lon = this_obs_param%nodata + ASCAT_lat = this_obs_param%nodata + ASCAT_time = real(this_obs_param%nodata,kind(0.0D0)) + ASCAT_sm_std = this_obs_param%nodata + + err_msg = 'Looking for ' // trim(this_obs_param%descr) // ' observations before/after they are available' + call ldas_warn(LDAS_GENERIC_WARNING, Iam, err_msg) + + return + end if ! initialize @@ -6849,6 +6882,7 @@ subroutine read_obs_SMAP_halforbit_Tb( date_time, N_catd, this_obs_param, & type(date_time_type) :: date_time_low, date_time_upp type(date_time_type) :: date_time_low_fname, date_time_tmp + type(date_time_type) :: date_time_first_obs integer :: ii, jj, kk, nn, mm integer :: N_fnames, N_fnames_tmp, N_obs_tmp @@ -6900,6 +6934,24 @@ subroutine read_obs_SMAP_halforbit_Tb( date_time, N_catd, this_obs_param, & ! ------------------------------------------------------------------- + ! check if we are in the time range of SMAP observations which start on 2015-03-31 + + date_time_first_obs = date_time_type(2015, 3,31, 0, 0, 0, 0, 0) + + if (datetime_lt_refdatetime(date_time, date_time_first_obs)) then + found_obs = .false. + SMAP_data = this_obs_param%nodata + SMAP_lon = this_obs_param%nodata + SMAP_lat = this_obs_param%nodata + SMAP_time = real(this_obs_param%nodata,kind(0.0D0)) + std_SMAP_data = this_obs_param%nodata + + err_msg = 'Looking for SMAP observations before 2015-03-31' + call ldas_warn(LDAS_GENERIC_WARNING, Iam, err_msg) + + return + end if + ! check inputs ! the subroutine makes sense only if dtstep_assim <= 3 hours From fd4c3bca94f33d2fdf759d2c4bac553b047a8d71 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Wed, 18 Dec 2024 15:53:03 -0500 Subject: [PATCH 032/107] minor fixes to previous commits (GEOSldas_HIST.rc, tile_bin2nc4.F90) --- GEOSldas_App/GEOSldas_HIST.rc | 4 ++-- GEOSldas_App/tile_bin2nc4.F90 | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/GEOSldas_App/GEOSldas_HIST.rc b/GEOSldas_App/GEOSldas_HIST.rc index e1f560d7..ed60da1e 100644 --- a/GEOSldas_App/GEOSldas_HIST.rc +++ b/GEOSldas_App/GEOSldas_HIST.rc @@ -324,7 +324,7 @@ COLLECTIONS: const_1d_lnd_Nt.template: '%y4%m2%d2_%h2%n2z.bin', const_1d_lnd_Nt.mode: 'instantaneous', const_1d_lnd_Nt.frequency: 240000, - const_1d_lnd_Nt.ref_time: 240000, + const_1d_lnd_Nt.ref_time: 000000, const_1d_lnd_Nt.fields: 'DZGT1' , 'GridComp' , 'DZGT2' , 'GridComp' , 'DZGT3' , 'GridComp' , @@ -347,7 +347,7 @@ COLLECTIONS: const_2d_lnd_Nx.template: '%y4%m2%d2_%h2%n2z.nc4', const_2d_lnd_Nx.mode: 'instantaneous', const_2d_lnd_Nx.frequency: 240000, - const_2d_lnd_Nx.ref_time: 240000, + const_2d_lnd_Nx.ref_time: 000000, const_2d_lnd_Nx.regrid_exch: '../input/tile.data' const_2d_lnd_Nx.regrid_name: 'GRIDNAME' const_2d_lnd_Nx.grid_label: PC720x361-DC diff --git a/GEOSldas_App/tile_bin2nc4.F90 b/GEOSldas_App/tile_bin2nc4.F90 index 619a8848..6ca5d492 100644 --- a/GEOSldas_App/tile_bin2nc4.F90 +++ b/GEOSldas_App/tile_bin2nc4.F90 @@ -306,7 +306,7 @@ FUNCTION getAttribute (SHORT_NAME, LNAME, UNT) result (str_atr) case ('TUNST' , 'TUNSTLAND'); LONG_NAME = 'surface_temperature_of_unsaturated_zone'; UNITS = 'K' case ('TSAT' , 'TSATLAND'); LONG_NAME = 'surface_temperature_of_saturated_zone'; UNITS = 'K' case ('TWLT' , 'TWLTLAND'); LONG_NAME = 'surface_temperature_of_wilting_zone'; UNITS = 'K' - case ('TSURF', 'TPSURF', 'TPSURFLAND'); LONG_NAME = 'surface_temperature_of_land_incl_snow'; UNITS = 'K' + case ('TSURF', 'TPSURF', 'TSURFLAND'); LONG_NAME = 'surface_temperature_of_land_incl_snow'; UNITS = 'K' case ('GRN'); LONG_NAME = 'vegetation_greenness_fraction'; UNITS = '1' case ('LAI'); LONG_NAME = 'leaf_area_index'; UNITS = '1' case ('TP1', 'TSOIL1'); LONG_NAME = 'soil_temperature_layer_1'; UNITS = 'K' ! units now K, rreichle & borescan, 6 Nov 2020 @@ -329,15 +329,15 @@ FUNCTION getAttribute (SHORT_NAME, LNAME, UNT) result (str_atr) case ('EVPINTR', 'LHLANDINTR'); LONG_NAME = 'interception_loss_latent_heat_flux'; UNITS = 'W m-2' case ('EVPSBLN', 'LHLANDSBLN'); LONG_NAME = 'snowpack_evaporation_latent_heat_flux'; UNITS = 'W m-2' case ('RUNOFF'); LONG_NAME = 'runoff_total_flux'; UNITS = 'kg m-2 s-1' - case ('RUNSURF'); LONG_NAME = 'overland runoff including throughflow'; UNITS = 'kg m-2 s-1' + case ('RUNSURF', 'RUNSURFLAND'); LONG_NAME = 'overland runoff including throughflow'; UNITS = 'kg m-2 s-1' case ('BASEFLOW'); LONG_NAME = 'baseflow_flux'; UNITS = 'kg m-2 s-1' case ('BASEFLOWLAND'); LONG_NAME = 'baseflow_flux_land'; UNITS = 'kg m-2 s-1' case ('SMLAND'); LONG_NAME = 'Snowmelt_flux_land'; UNITS = 'kg m-2 s-1' case ('QINFIL', 'QINFILLAND'); LONG_NAME = 'soil_water_infiltration_rate'; UNITS = 'kg m-2 s-1' - case ('FRUNST', 'FRUNSTLAND'); LONG_NAME = 'fractional_area_of_unsaturated_zone'; UNITS = '1' - case ('FRSAT' , 'FRSATLAND' ); LONG_NAME = 'fractional_area_of_saturated_zone'; UNITS = '1' - case ('FRSNO' , 'FRSNOLAND' ); LONG_NAME = 'fractional_area_of_snow_on_land'; UNITS = '1' - case ('FRWLT' , 'FRWLTLAND' ); LONG_NAME = 'fractional_area_of_wilting_zone'; UNITS = '1' + case ('FRUNST', 'FRLANDUNST'); LONG_NAME = 'fractional_area_of_unsaturated_zone'; UNITS = '1' + case ('FRSAT' , 'FRLANDSAT' ); LONG_NAME = 'fractional_area_of_saturated_zone'; UNITS = '1' + case ('FRSNO' , 'FRLANDSNO' ); LONG_NAME = 'fractional_area_of_snow_on_land'; UNITS = '1' + case ('FRWLT' , 'FRLANDWLT' ); LONG_NAME = 'fractional_area_of_wilting_zone'; UNITS = '1' case ('PARDFLAND'); LONG_NAME = 'surface_downwelling_PAR_diffuse_flux'; UNITS = 'W m-2' case ('PARDRLAND'); LONG_NAME = 'surface_downwelling_PAR_beam_flux'; UNITS = 'W m-2' case ('SHLAND'); LONG_NAME = 'Sensible_heat_flux_land'; UNITS = 'W m-2' From dce573cf0c89e378cf4a97c97b3add6aebf050e0 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Wed, 18 Dec 2024 13:57:53 -0700 Subject: [PATCH 033/107] added dates for SMOS and MODIS SCF --- .../clsm_ensupd_read_obs.F90 | 48 +++++++++++++++++-- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index fb3ffb2f..634dc665 100644 --- a/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -1691,7 +1691,6 @@ subroutine read_obs_sm_ASCAT_EUMET( & ! --------------- ! check if we are within time periods when observations are available for metop-a, metop-b, or metop-c - ! if not, then return if (trim(this_obs_param%descr) == 'ASCAT_META_SM') then date_time_first_obs = date_time_type(2007, 6, 1, 1,31, 0, 0, 0) @@ -4498,6 +4497,7 @@ subroutine read_obs_SMOS( date_time, N_catd, this_obs_param, & real :: tmpreal, Tb_std_max type(date_time_type) :: date_time_low, date_time_upp + type(date_time_type) :: date_time_first_obs character( 2) :: MM, DD, HH, MI, orbit_tag character( 4) :: YYYY @@ -4526,6 +4526,23 @@ subroutine read_obs_SMOS( date_time, N_catd, this_obs_param, & ! ------------------------------------------------------------------- + ! check if we are in the time range of SMOS observations which start on 2010-05-24 + + date_time_first_obs = date_time_type(2010, 5,24, 0, 0, 0, 0, 0) + + if (datetime_lt_refdatetime(date_time, date_time_first_obs)) then + found_obs = .false. + SMOS_data = this_obs_param%nodata + SMOS_lon = this_obs_param%nodata + SMOS_lat = this_obs_param%nodata + std_SMOS_data = this_obs_param%nodata + + err_msg = 'Looking for SMOS observations before 2010-05-24' + call ldas_warn(LDAS_GENERIC_WARNING, Iam, err_msg) + + return + end if + ! initialize found_obs = .false. @@ -5257,6 +5274,7 @@ subroutine read_obs_MODIS_SCF( & type(date_time_type) :: date_time_beg, date_time_end type(date_time_type) :: date_time_beg_MODIS, date_time_end_MODIS + type(date_time_type) :: date_time_first_obs real :: lon_beg, lon_end real :: lon_beg_MODIS, lon_end_MODIS @@ -5278,7 +5296,31 @@ subroutine read_obs_MODIS_SCF( & character(len=*), parameter :: Iam = 'read_obs_MODIS_SCF' character(len=400) :: err_msg - + + ! check if we are in the time range of MODIS observations which start on 2000-02-24 for Terra and 2002-07-04 for Aqua + + if (trim(this_obs_param%descr) == 'MOD10C1') then + date_time_first_obs = date_time_type(2000, 2,24, 1,31, 0, 0, 0) + elseif (trim(this_obs_param%descr) == 'MYD10C1') then + date_time_first_obs = date_time_type(2002, 7, 4, 8, 0, 0, 0, 0) + else + err_msg = 'Unknown observation time range for this MODIS SCF observation type' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + end if + + if (datetime_lt_refdatetime(date_time, date_time_first_obs)) then + found_obs = .false. + MODIS_obs = this_obs_param%nodata + MODIS_lon = this_obs_param%nodata + MODIS_lat = this_obs_param%nodata + std_MODIS_obs = this_obs_param%nodata + + err_msg = 'Looking for ' // trim(this_obs_param%descr) // ' SCF observations before they are avaiable' + call ldas_warn(LDAS_GENERIC_WARNING, Iam, err_msg) + + return + end if + ! ---------------------------------------------------------------------------------- ! ! restrict assimilation time step to max allowed @@ -6939,7 +6981,7 @@ subroutine read_obs_SMAP_halforbit_Tb( date_time, N_catd, this_obs_param, & date_time_first_obs = date_time_type(2015, 3,31, 0, 0, 0, 0, 0) if (datetime_lt_refdatetime(date_time, date_time_first_obs)) then - found_obs = .false. + found_obs = .false. SMAP_data = this_obs_param%nodata SMAP_lon = this_obs_param%nodata SMAP_lat = this_obs_param%nodata From 60d0d5c7d83a32da67cdafaa9d6143f40ac15d4c Mon Sep 17 00:00:00 2001 From: amfox37 Date: Wed, 18 Dec 2024 14:11:47 -0700 Subject: [PATCH 034/107] update changelog.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ab148b6..730784d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Updated read_obs_sm_ASCAT_EUMET to work with both original and revised file name templates. +- Updated subroutines read_obs_sm_ASCAT_EUMET(), read_obs_SMAP_halforbit_Tb(), read_obs_SMOS() and read_obs_MODIS_SCF() with hardcoded time ranges for when observations are available and should be read. ### Fixed From 4a0860c503e9db97230e70c3e9044673deb806c3 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Thu, 19 Dec 2024 09:39:22 -0500 Subject: [PATCH 035/107] additional fixes of previous commit (GEOS_EnsGridComp.F90, GEOSldas_HIST.rc, tile_bin2nc4.F90) --- GEOSens_GridComp/GEOS_EnsGridComp.F90 | 4 +-- GEOSldas_App/GEOSldas_HIST.rc | 44 ++++++++++++++------------- GEOSldas_App/tile_bin2nc4.F90 | 8 ++--- 3 files changed, 29 insertions(+), 27 deletions(-) diff --git a/GEOSens_GridComp/GEOS_EnsGridComp.F90 b/GEOSens_GridComp/GEOS_EnsGridComp.F90 index f0eef36b..57f38650 100644 --- a/GEOSens_GridComp/GEOS_EnsGridComp.F90 +++ b/GEOSens_GridComp/GEOS_EnsGridComp.F90 @@ -496,7 +496,7 @@ subroutine SetServices(gc, rc) VERIFY_(STATUS) call MAPL_AddExportSpec(GC, & - LONG_NAME = 'snowpack_evaporation_latent_heat_flux',& + LONG_NAME = 'snowpack_evaporation_latent_heat_flux_on_land',& UNITS = 'W m-2' ,& SHORT_NAME = 'EVPICE' ,& DIMS = MAPL_DimsTileOnly ,& @@ -605,7 +605,7 @@ subroutine SetServices(gc, rc) VERIFY_(STATUS) call MAPL_AddExportSpec(GC, & - LONG_NAME = 'soil_water_infiltration_rate',& + LONG_NAME = 'Soil_water_infiltration_rate',& UNITS = 'kg m-2 s-1' ,& SHORT_NAME = 'QINFIL' ,& DIMS = MAPL_DimsTileOnly ,& diff --git a/GEOSldas_App/GEOSldas_HIST.rc b/GEOSldas_App/GEOSldas_HIST.rc index ed60da1e..15ba59d5 100644 --- a/GEOSldas_App/GEOSldas_HIST.rc +++ b/GEOSldas_App/GEOSldas_HIST.rc @@ -215,17 +215,18 @@ COLLECTIONS: >>>HIST_IRRIG<<< 'IRRIGRATE' , 'GridComp' , :: - tavg24_2d_lnd_Nx.format: 'CFIO', - tavg24_2d_lnd_Nx.descr: '2d,Daily,Time-Averaged,Single-Level,Assimilation,Land Surface Diagnostics', -# tavg24_2d_lnd_Nx.nbits: 12, - tavg24_2d_lnd_Nx.template: '%y4%m2%d2_%h2%n2z.nc4', - tavg24_2d_lnd_Nx.mode: 'time-averaged', - tavg24_2d_lnd_Nx.frequency: 240000, - tavg24_2d_lnd_Nx.ref_time: 000000, - tavg24_2d_lnd_Nx.regrid_exch: '../input/tile.data' - tavg24_2d_lnd_Nx.regrid_name: 'GRIDNAME' - tavg24_2d_lnd_Nx.grid_label: PC720x361-DC - tavg24_2d_lnd_Nx.deflate: 2, + tavg24_2d_lnd_Nx.format: 'CFIO', + tavg24_2d_lnd_Nx.descr: '2d,Daily,Time-Averaged,Single-Level,Assimilation,Land Surface Diagnostics', +# tavg24_2d_lnd_Nx.nbits: 12, + tavg24_2d_lnd_Nx.template: '%y4%m2%d2_%h2%n2z.nc4', + tavg24_2d_lnd_Nx.mode: 'time-averaged', + tavg24_2d_lnd_Nx.frequency: 240000, + tavg24_2d_lnd_Nx.ref_time: 000000, + tavg24_2d_lnd_Nx.regrid_exch: '../input/tile.data' + tavg24_2d_lnd_Nx.regrid_name: 'GRIDNAME' + tavg24_2d_lnd_Nx.regrid_method: 'BILINEAR_MONOTONIC' , + tavg24_2d_lnd_Nx.grid_label: PC720x361-DC + tavg24_2d_lnd_Nx.deflate: 2, tavg24_2d_lnd_Nx.fields: 'GRN' , 'VEGDYN' , 'LAI' , 'VEGDYN' , 'WET3' , 'GridComp' , 'GWETPROF' , @@ -342,16 +343,17 @@ COLLECTIONS: 'POROS' , 'GridComp' , :: - const_2d_lnd_Nx.format: 'CFIO', - const_2d_lnd_Nx.descr: '2d,Constant,Time-invariant,Single-Level,Assimilation,Land Surface Model Parameters', - const_2d_lnd_Nx.template: '%y4%m2%d2_%h2%n2z.nc4', - const_2d_lnd_Nx.mode: 'instantaneous', - const_2d_lnd_Nx.frequency: 240000, - const_2d_lnd_Nx.ref_time: 000000, - const_2d_lnd_Nx.regrid_exch: '../input/tile.data' - const_2d_lnd_Nx.regrid_name: 'GRIDNAME' - const_2d_lnd_Nx.grid_label: PC720x361-DC - const_2d_lnd_Nx.deflate: 2, + const_2d_lnd_Nx.format: 'CFIO', + const_2d_lnd_Nx.descr: '2d,Constant,Time-invariant,Single-Level,Assimilation,Land Surface Model Parameters', + const_2d_lnd_Nx.template: '%y4%m2%d2_%h2%n2z.nc4', + const_2d_lnd_Nx.mode: 'instantaneous', + const_2d_lnd_Nx.frequency: 240000, + const_2d_lnd_Nx.ref_time: 000000, + const_2d_lnd_Nx.regrid_exch: '../input/tile.data' + const_2d_lnd_Nx.regrid_name: 'GRIDNAME' + const_2d_lnd_Nx.regrid_method: 'BILINEAR_MONOTONIC' , + const_2d_lnd_Nx.grid_label: PC720x361-DC + const_2d_lnd_Nx.deflate: 2, const_2d_lnd_Nx.fields: 'DZGT1' , 'GridComp' , 'DZGT2' , 'GridComp' , 'DZGT3' , 'GridComp' , diff --git a/GEOSldas_App/tile_bin2nc4.F90 b/GEOSldas_App/tile_bin2nc4.F90 index 6ca5d492..ae632879 100644 --- a/GEOSldas_App/tile_bin2nc4.F90 +++ b/GEOSldas_App/tile_bin2nc4.F90 @@ -327,13 +327,14 @@ FUNCTION getAttribute (SHORT_NAME, LNAME, UNT) result (str_atr) case ('EVPSOIL', 'LHLANDSOIL'); LONG_NAME = 'baresoil_evaporation_latent_heat_flux'; UNITS = 'W m-2' case ('EVPTRNS', 'LHLANDTRNS'); LONG_NAME = 'transpiration_latent_heat_flux'; UNITS = 'W m-2' case ('EVPINTR', 'LHLANDINTR'); LONG_NAME = 'interception_loss_latent_heat_flux'; UNITS = 'W m-2' - case ('EVPSBLN', 'LHLANDSBLN'); LONG_NAME = 'snowpack_evaporation_latent_heat_flux'; UNITS = 'W m-2' - case ('RUNOFF'); LONG_NAME = 'runoff_total_flux'; UNITS = 'kg m-2 s-1' + case ('EVPSBLN', 'LHLANDSBLN'); LONG_NAME = 'snowpack_evaporation_latent_heat_flux_on_land'; UNITS = 'W m-2' + case ('EVPSNO'); LONG_NAME = 'snowpack_evaporation_latent_heat_flux'; UNITS = 'W m-2' ! avg across all tile types + case ('RUNOFF'); LONG_NAME = 'runoff_total_flux'; UNITS = 'kg m-2 s-1' ! avg across all tile types case ('RUNSURF', 'RUNSURFLAND'); LONG_NAME = 'overland runoff including throughflow'; UNITS = 'kg m-2 s-1' case ('BASEFLOW'); LONG_NAME = 'baseflow_flux'; UNITS = 'kg m-2 s-1' case ('BASEFLOWLAND'); LONG_NAME = 'baseflow_flux_land'; UNITS = 'kg m-2 s-1' case ('SMLAND'); LONG_NAME = 'Snowmelt_flux_land'; UNITS = 'kg m-2 s-1' - case ('QINFIL', 'QINFILLAND'); LONG_NAME = 'soil_water_infiltration_rate'; UNITS = 'kg m-2 s-1' + case ('QINFIL', 'QINFILLAND'); LONG_NAME = 'Soil_water_infiltration_rate'; UNITS = 'kg m-2 s-1' case ('FRUNST', 'FRLANDUNST'); LONG_NAME = 'fractional_area_of_unsaturated_zone'; UNITS = '1' case ('FRSAT' , 'FRLANDSAT' ); LONG_NAME = 'fractional_area_of_saturated_zone'; UNITS = '1' case ('FRSNO' , 'FRLANDSNO' ); LONG_NAME = 'fractional_area_of_snow_on_land'; UNITS = '1' @@ -378,7 +379,6 @@ FUNCTION getAttribute (SHORT_NAME, LNAME, UNT) result (str_atr) case ('CLOSS'); LONG_NAME = 'CN_carbon_loss_to_fire'; UNITS = 'kg m-2 s-1' case ('BURN'); LONG_NAME = 'CN_fractional_area_burn_rate'; UNITS = 's-1' case ('FSEL'); LONG_NAME = 'fire season length'; UNITS = 'days' - case ('EVPSNO'); LONG_NAME = 'snowpack_evaporation_latent_heat_flux'; UNITS = 'W m-2' case ('GHTSKIN'); LONG_NAME = 'Ground_heating_flux_for_skin_temp_land'; UNITS = 'W m-2' case ('WAT10CM'); LONG_NAME = 'soil moisture in Upper 10cm'; UNITS = 'kg m-2' case ('WATSOI'); LONG_NAME = 'total soil moisture'; UNITS = 'kg m-2' From 5d32a932284bbe2201b28ef0202896813f82e94c Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Thu, 19 Dec 2024 11:34:21 -0500 Subject: [PATCH 036/107] simplified previous commit (clsm_ensupd_read_obs.F90) --- .../clsm_ensupd_read_obs.F90 | 136 +++++++----------- 1 file changed, 53 insertions(+), 83 deletions(-) diff --git a/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 634dc665..e272d3ef 100644 --- a/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -1629,7 +1629,7 @@ subroutine read_obs_sm_ASCAT_EUMET( & 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 - type(date_time_type) :: date_time_first_obs, date_time_last_obs + type(date_time_type) :: date_time_obs_beg, date_time_obs_end integer :: ii, ind, N_tmp, N_files, kk, N_obs, N_fnames, N_fnames_tmp, obs_dir_hier @@ -1690,40 +1690,32 @@ subroutine read_obs_sm_ASCAT_EUMET( & ! --------------- - ! check if we are within time periods when observations are available for metop-a, metop-b, or metop-c + ! initialize + + found_obs = .false. + + ! determine operating time range of sensor - if (trim(this_obs_param%descr) == 'ASCAT_META_SM') then - date_time_first_obs = date_time_type(2007, 6, 1, 1,31, 0, 0, 0) - date_time_last_obs = date_time_type(2021,11,15, 9, 0, 0, 0, 0) + if (trim(this_obs_param%descr) == 'ASCAT_META_SM') then + date_time_obs_beg = date_time_type(2007, 6, 1, 1,31, 0,-9999,-9999) + date_time_obs_end = date_time_type(2021,11,15, 9, 0, 0,-9999,-9999) elseif (trim(this_obs_param%descr) == 'ASCAT_METB_SM') then - date_time_first_obs = date_time_type(2013, 4,24, 8, 0, 0, 0, 0) - date_time_last_obs = date_time_type(2100, 1, 1, 0, 0, 0, 0, 0) + date_time_obs_beg = date_time_type(2013, 4,24, 8, 0, 0,-9999,-9999) + date_time_obs_end = date_time_type(2100, 1, 1, 0, 0, 0,-9999,-9999) elseif (trim(this_obs_param%descr) == 'ASCAT_METC_SM') then - date_time_first_obs = date_time_type(2019,11,25,12, 0, 0, 0, 0) - date_time_last_obs = date_time_type(2100, 1, 1, 0, 0, 0, 0, 0) + date_time_obs_beg = date_time_type(2019,11,25,12, 0, 0,-9999,-9999) + date_time_obs_end = date_time_type(2100, 1, 1, 0, 0, 0,-9999,-9999) else - err_msg = 'Unknown observation time range for this ASCAT observation type' + err_msg = 'Unknown obs_param%descr: ' // trim(this_obs_param%descr) call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) end if - - if (datetime_lt_refdatetime(date_time, date_time_first_obs) .or. & - datetime_lt_refdatetime(date_time_last_obs, date_time)) then - found_obs = .false. - ASCAT_sm = this_obs_param%nodata - ASCAT_lon = this_obs_param%nodata - ASCAT_lat = this_obs_param%nodata - ASCAT_time = real(this_obs_param%nodata,kind(0.0D0)) - ASCAT_sm_std = this_obs_param%nodata - - err_msg = 'Looking for ' // trim(this_obs_param%descr) // ' observations before/after they are available' - call ldas_warn(LDAS_GENERIC_WARNING, Iam, err_msg) - - return - end if - ! initialize + ! return if date_time falls outside operating time range - found_obs = .false. + if ( datetime_lt_refdatetime(date_time, date_time_obs_beg) .or. & + datetime_lt_refdatetime(date_time_obs_end, date_time) ) return + + ! --------------- ! find files that are within half-open interval ! (date_time-dtstep_assim/2,date_time+dtstep_assim/2] @@ -4497,7 +4489,7 @@ subroutine read_obs_SMOS( date_time, N_catd, this_obs_param, & real :: tmpreal, Tb_std_max type(date_time_type) :: date_time_low, date_time_upp - type(date_time_type) :: date_time_first_obs + type(date_time_type) :: date_time_obs_beg character( 2) :: MM, DD, HH, MI, orbit_tag character( 4) :: YYYY @@ -4526,26 +4518,20 @@ subroutine read_obs_SMOS( date_time, N_catd, this_obs_param, & ! ------------------------------------------------------------------- - ! check if we are in the time range of SMOS observations which start on 2010-05-24 - - date_time_first_obs = date_time_type(2010, 5,24, 0, 0, 0, 0, 0) + ! initialize + + found_obs = .false. - if (datetime_lt_refdatetime(date_time, date_time_first_obs)) then - found_obs = .false. - SMOS_data = this_obs_param%nodata - SMOS_lon = this_obs_param%nodata - SMOS_lat = this_obs_param%nodata - std_SMOS_data = this_obs_param%nodata + ! determine operating time range of sensor - err_msg = 'Looking for SMOS observations before 2010-05-24' - call ldas_warn(LDAS_GENERIC_WARNING, Iam, err_msg) + date_time_obs_beg = date_time_type(2010, 5,24, 0, 0, 0,-9999,-9999) - return - end if + ! return if date_time falls outside operating time range - ! initialize + if (datetime_lt_refdatetime(date_time, date_time_obs_beg)) return - found_obs = .false. + ! ------------------------------ + ! read soil moisture or brightness temperature files? @@ -5274,7 +5260,7 @@ subroutine read_obs_MODIS_SCF( & type(date_time_type) :: date_time_beg, date_time_end type(date_time_type) :: date_time_beg_MODIS, date_time_end_MODIS - type(date_time_type) :: date_time_first_obs + type(date_time_type) :: date_time_obs_beg real :: lon_beg, lon_end real :: lon_beg_MODIS, lon_end_MODIS @@ -5297,29 +5283,26 @@ subroutine read_obs_MODIS_SCF( & character(len=*), parameter :: Iam = 'read_obs_MODIS_SCF' character(len=400) :: err_msg - ! check if we are in the time range of MODIS observations which start on 2000-02-24 for Terra and 2002-07-04 for Aqua + ! ------------------------------------------------------------------------------------ + ! + ! initialize + + found_obs = .false. + + ! determine operating time range of sensor - if (trim(this_obs_param%descr) == 'MOD10C1') then - date_time_first_obs = date_time_type(2000, 2,24, 1,31, 0, 0, 0) + if (trim(this_obs_param%descr) == 'MOD10C1') then + date_time_obs_beg = date_time_type(2000, 2,24, 1,31, 0,-9999,-9999) ! Terra elseif (trim(this_obs_param%descr) == 'MYD10C1') then - date_time_first_obs = date_time_type(2002, 7, 4, 8, 0, 0, 0, 0) + date_time_obs_beg = date_time_type(2002, 7, 4, 8, 0, 0,-9999,-9999) ! Aqua else - err_msg = 'Unknown observation time range for this MODIS SCF observation type' + err_msg = 'Unknown obs_param%descr: ' // trim(this_obs_param%descr) call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) end if - if (datetime_lt_refdatetime(date_time, date_time_first_obs)) then - found_obs = .false. - MODIS_obs = this_obs_param%nodata - MODIS_lon = this_obs_param%nodata - MODIS_lat = this_obs_param%nodata - std_MODIS_obs = this_obs_param%nodata + ! return if date_time falls outside operating time range - err_msg = 'Looking for ' // trim(this_obs_param%descr) // ' SCF observations before they are avaiable' - call ldas_warn(LDAS_GENERIC_WARNING, Iam, err_msg) - - return - end if + if (datetime_lt_refdatetime(date_time, date_time_obs_beg)) return ! ---------------------------------------------------------------------------------- ! @@ -5332,12 +5315,6 @@ subroutine read_obs_MODIS_SCF( & end if - - ! initialize - - found_obs = .false. - - ! identify MODIS product and overpass hour MODIS_product_ID = this_obs_param%name(1:7) @@ -6924,7 +6901,7 @@ subroutine read_obs_SMAP_halforbit_Tb( date_time, N_catd, this_obs_param, & type(date_time_type) :: date_time_low, date_time_upp type(date_time_type) :: date_time_low_fname, date_time_tmp - type(date_time_type) :: date_time_first_obs + type(date_time_type) :: date_time_obs_beg integer :: ii, jj, kk, nn, mm integer :: N_fnames, N_fnames_tmp, N_obs_tmp @@ -6976,23 +6953,19 @@ subroutine read_obs_SMAP_halforbit_Tb( date_time, N_catd, this_obs_param, & ! ------------------------------------------------------------------- - ! check if we are in the time range of SMAP observations which start on 2015-03-31 + ! initialize + + found_obs = .false. - date_time_first_obs = date_time_type(2015, 3,31, 0, 0, 0, 0, 0) + ! determine operating time range of sensor - if (datetime_lt_refdatetime(date_time, date_time_first_obs)) then - found_obs = .false. - SMAP_data = this_obs_param%nodata - SMAP_lon = this_obs_param%nodata - SMAP_lat = this_obs_param%nodata - SMAP_time = real(this_obs_param%nodata,kind(0.0D0)) - std_SMAP_data = this_obs_param%nodata + date_time_obs_beg = date_time_type(2015, 3,31, 0, 0, 0,-9999,-9999) - err_msg = 'Looking for SMAP observations before 2015-03-31' - call ldas_warn(LDAS_GENERIC_WARNING, Iam, err_msg) + ! return if date_time falls outside operating time range - return - end if + if (datetime_lt_refdatetime(date_time, date_time_obs_beg)) return + + ! ---------------- ! check inputs @@ -7007,9 +6980,6 @@ subroutine read_obs_SMAP_halforbit_Tb( date_time, N_catd, this_obs_param, & call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) end if - ! initialize - - found_obs = .false. ! read Tbs from L1C_TB, L1C_TB_E, or L2_SM_AP files? From 9e6a770a80a1333dbc83598f2e7e0273676c7d7e Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Thu, 19 Dec 2024 13:44:13 -0500 Subject: [PATCH 037/107] additional LONG_NAME fixes (tile_bin2nc4.F90) --- GEOSldas_App/tile_bin2nc4.F90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GEOSldas_App/tile_bin2nc4.F90 b/GEOSldas_App/tile_bin2nc4.F90 index ae632879..797189b4 100644 --- a/GEOSldas_App/tile_bin2nc4.F90 +++ b/GEOSldas_App/tile_bin2nc4.F90 @@ -302,7 +302,7 @@ FUNCTION getAttribute (SHORT_NAME, LNAME, UNT) result (str_atr) case ('PRMC'); LONG_NAME = 'soil_moisture_profile'; UNITS = 'm3 m-3' case ('RZMC'); LONG_NAME = 'soil_moisture_rootzone'; UNITS = 'm3 m-3' case ('SFMC'); LONG_NAME = 'soil_moisture_surface'; UNITS = 'm3 m-3' - case ('TPSNOW', 'TPSNOWLAND'); LONG_NAME = 'surface_temperature_of_snow'; UNITS = 'K' + case ('TPSNOW', 'TPSNOWLAND'); LONG_NAME = 'surface_temperature_of_snow_on_land'; UNITS = 'K' case ('TUNST' , 'TUNSTLAND'); LONG_NAME = 'surface_temperature_of_unsaturated_zone'; UNITS = 'K' case ('TSAT' , 'TSATLAND'); LONG_NAME = 'surface_temperature_of_saturated_zone'; UNITS = 'K' case ('TWLT' , 'TWLTLAND'); LONG_NAME = 'surface_temperature_of_wilting_zone'; UNITS = 'K' @@ -348,7 +348,7 @@ FUNCTION getAttribute (SHORT_NAME, LNAME, UNT) result (str_atr) case ('SWLAND'); LONG_NAME = 'Net_shortwave_flux_land'; UNITS = 'W m-2' case ('SWDOWNLAND'); LONG_NAME = 'Incident_shortwave_flux_land'; UNITS = 'W m-2' case ('GHLAND'); LONG_NAME = 'Ground_heating_flux_land'; UNITS = 'W m-2' - case ('TWLAND'); LONG_NAME = 'Total_water_storage_land'; UNITS = 'kg m-2' + case ('TWLAND'); LONG_NAME = 'total_water_storage_land'; UNITS = 'kg m-2' case ('TELAND'); LONG_NAME = 'Total_energy_storage_land'; UNITS = 'J m-2' case ('WCHANGE','WCHANGELAND'); LONG_NAME = 'rate_of_change_of_total_land_water'; UNITS = 'kg m-2 s-1' case ('ECHANGE','ECHANGELAND'); LONG_NAME = 'rate_of_change_of_total_land_energy'; UNITS = 'W m-2' From b7071fca2934b9e4b86538226daaa4e5ab5f1a21 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Thu, 19 Dec 2024 13:59:25 -0500 Subject: [PATCH 038/107] removed "corrected" from LONG_NAME attributes of PREC*CORRLAND for consistency w/ M21C (tile_bin2nc4.F90) --- GEOSldas_App/tile_bin2nc4.F90 | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/GEOSldas_App/tile_bin2nc4.F90 b/GEOSldas_App/tile_bin2nc4.F90 index 797189b4..cf3f2fbc 100644 --- a/GEOSldas_App/tile_bin2nc4.F90 +++ b/GEOSldas_App/tile_bin2nc4.F90 @@ -315,10 +315,8 @@ FUNCTION getAttribute (SHORT_NAME, LNAME, UNT) result (str_atr) case ('TP4', 'TSOIL4'); LONG_NAME = 'soil_temperature_layer_4'; UNITS = 'K' ! units now K, rreichle & borescan, 6 Nov 2020 case ('TP5', 'TSOIL5'); LONG_NAME = 'soil_temperature_layer_5'; UNITS = 'K' ! units now K, rreichle & borescan, 6 Nov 2020 case ('TP6', 'TSOIL6'); LONG_NAME = 'soil_temperature_layer_6'; UNITS = 'K' ! units now K, rreichle & borescan, 6 Nov 2020 - case ('PRECTOTLAND'); LONG_NAME = 'Total_precipitation_land'; UNITS = 'kg m-2 s-1' - case ('PRECSNOLAND'); LONG_NAME = 'snowfall_land'; UNITS = 'kg m-2 s-1' - case ('PRECTOTCORRLAND'); LONG_NAME = 'Total_precipitation_corrected_land'; UNITS = 'kg m-2 s-1' - case ('PRECSNOCORRLAND'); LONG_NAME = 'snowfall_corrected_land'; UNITS = 'kg m-2 s-1' + case ('PRECTOTLAND', 'PRECTOTCORRLAND'); LONG_NAME = 'Total_precipitation_land'; UNITS = 'kg m-2 s-1' + case ('PRECSNOLAND', 'PRECSNOCORRLAND'); LONG_NAME = 'snowfall_land'; UNITS = 'kg m-2 s-1' case ('SNOWMASS', 'SNOMAS'); LONG_NAME = 'snow_mass'; UNITS = 'kg m-2' case ('TSLAND', 'SNOMASLAND'); LONG_NAME = 'Total_snow_storage_land'; UNITS = 'kg m-2' case ('SNO'); LONG_NAME = 'snowfall'; UNITS = 'kg m-2 s-1' From b5759b333e200f51c0fec345a89e6144829b0505 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Sat, 21 Dec 2024 11:55:37 -0500 Subject: [PATCH 039/107] first edits towards reading M21C surface met forcing (NOT YET COMPLETE) (LDAS_Forcing.F90) --- GEOSmetforce_GridComp/LDAS_Forcing.F90 | 69 +++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 2 deletions(-) diff --git a/GEOSmetforce_GridComp/LDAS_Forcing.F90 b/GEOSmetforce_GridComp/LDAS_Forcing.F90 index b87e6734..f7fe8f4b 100755 --- a/GEOSmetforce_GridComp/LDAS_Forcing.F90 +++ b/GEOSmetforce_GridComp/LDAS_Forcing.F90 @@ -3091,6 +3091,8 @@ subroutine get_GEOS( date_time, force_dtstep, met_path, met_tag, & ! - updated comments ! ! qliu+reichle, 5 Dec 2023 - added GEOS-IT + ! + ! rreichle, 18 Dec 2024 - added M21C ! ! ----------------------------------- ! @@ -3163,6 +3165,7 @@ subroutine get_GEOS( date_time, force_dtstep, met_path, met_tag, & integer, parameter :: N_MERRA_vars = 13 integer, parameter :: N_MERRA2_vars = 12 ! same as for G5DAS (excl Aerosol vars) integer, parameter :: N_Aerosol_vars = 60 ! additional aerosol forcing vars for GOSWIM (w/ MERRA-2 only for now) + integer, parameter :: N_M21C_vars = 12 integer, parameter :: N_MERRA2plusAerosol_vars = N_MERRA2_vars + N_Aerosol_vars @@ -3175,6 +3178,8 @@ subroutine get_GEOS( date_time, force_dtstep, met_path, met_tag, & 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 + character(40), dimension(N_M21C_vars, N_defs_cols) :: M21CINT_defs + character(40), dimension(N_M21C_vars, N_defs_cols) :: M21CCOR_defs character(40), dimension(:,:), allocatable :: GEOSgcm_defs @@ -3272,6 +3277,64 @@ subroutine get_GEOS( date_time, force_dtstep, met_path, met_tag, & GEOSIT_defs(12,3) = 'lfo_inst_1hr_glo_L576x361_slv ' + ! ----------------------------------------------------------------------- + ! + ! define M21C file specs + ! + ! M21C file specs with uncorrected (AGCM) precip from the "int" Collection + ! (ie, the precip generated by the AGCM within the M21C system) + ! + ! NOTE: This is *NOT* the precipitation seen by the land surface in the M21C system. + ! +? ! NOTE: Use SWGDN from the "rad" Collection because SWGDN in MERRA-2 "lfo" +? ! is averaged over land tiles only, unlike all other variables, +? ! which are global, as is SWGDN in the FP "lfo" files. +? ! - reichle, 7 Dec 2015 + + M21CINT_defs( 1,:)=[character(len=40):: 'SWGDN ','tavg','tavg1_2d_rad_Nx','diag','F'] ! use "rad" Collection + M21CINT_defs( 2,:)=[character(len=40):: 'LWGAB ','tavg','tavg1_2d_lfo_Nx','diag','F'] + M21CINT_defs( 3,:)=[character(len=40):: 'PARDR ','tavg','tavg1_2d_lfo_Nx','diag','F'] + M21CINT_defs( 4,:)=[character(len=40):: 'PARDF ','tavg','tavg1_2d_lfo_Nx','diag','F'] + M21CINT_defs( 5,:)=[character(len=40):: 'PRECCU ','tavg','tavg1_2d_int_Nx','diag','F'] ! uncorrected + M21CINT_defs( 6,:)=[character(len=40):: 'PRECLS ','tavg','tavg1_2d_int_Nx','diag','F'] ! uncorrected + M21CINT_defs( 7,:)=[character(len=40):: 'PRECSN ','tavg','tavg1_2d_int_Nx','diag','F'] ! uncorrected + M21CINT_defs( 8,:)=[character(len=40):: 'PS ','inst','inst1_2d_lfo_Nx','diag','S'] + M21CINT_defs( 9,:)=[character(len=40):: 'HLML ','inst','inst1_2d_lfo_Nx','diag','S'] + M21CINT_defs(10,:)=[character(len=40):: 'TLML ','inst','inst1_2d_lfo_Nx','diag','S'] + M21CINT_defs(11,:)=[character(len=40):: 'QLML ','inst','inst1_2d_lfo_Nx','diag','S'] + M21CINT_defs(12,:)=[character(len=40):: 'SPEEDLML','inst','inst1_2d_lfo_Nx','diag','S'] + + + ! MERRA-2 file specs with corrected precip, which could be either + ! - native (ie, the precip seen by the land surface in the MERRA-2 system), or + ! - corrected in post-processing using MERRA-2 (uncorrected) precip as the background + ! The default is to use MERRA-2 native precip corrections. If the "met_tag" includes + ! an optional "__prec[xyz]" string, the precip corrections specified by [xyz] are used. + ! + ! NOTE: This is *NOT* the same as the corrected precipitation of the off-line + ! spin-up run used to generate the MERRA-2 land surface initial conditions + ! for each stream. These precip files used for that have a MERRA background. + ! + ! NOTE: Use SWGDN from the "rad" Collection (see comment above). + + M21CCOR_defs( 1,:)=[character(len=40):: 'SWGDN ','tavg','tavg1_2d_rad_Nx','diag','F'] ! use "rad" Collection + M21CCOR_defs( 2,:)=[character(len=40):: 'LWGAB ','tavg','tavg1_2d_lfo_Nx','diag','F'] + M21CCOR_defs( 3,:)=[character(len=40):: 'PARDR ','tavg','tavg1_2d_lfo_Nx','diag','F'] + M21CCOR_defs( 4,:)=[character(len=40):: 'PARDF ','tavg','tavg1_2d_lfo_Nx','diag','F'] + M21CCOR_defs( 5,:)=[character(len=40):: 'PRECCUCORR ','tavg','tavg1_2d_lfo_Nx','diag','F'] ! MERRA-2 built-in corrections + M21CCOR_defs( 6,:)=[character(len=40):: 'PRECLSCORR ','tavg','tavg1_2d_lfo_Nx','diag','F'] ! MERRA-2 built-in corrections + M21CCOR_defs( 7,:)=[character(len=40):: 'PRECSNOCORR','tavg','tavg1_2d_lfo_Nx','diag','F'] ! MERRA-2 built-in corrections + M21CCOR_defs( 8,:)=[character(len=40):: 'PS ','inst','inst1_2d_lfo_Nx','diag','S'] + M21CCOR_defs( 9,:)=[character(len=40):: 'HLML ','inst','inst1_2d_lfo_Nx','diag','S'] + M21CCOR_defs(10,:)=[character(len=40):: 'TLML ','inst','inst1_2d_lfo_Nx','diag','S'] + M21CCOR_defs(11,:)=[character(len=40):: 'QLML ','inst','inst1_2d_lfo_Nx','diag','S'] + M21CCOR_defs(12,:)=[character(len=40):: 'SPEEDLML ','inst','inst1_2d_lfo_Nx','diag','S'] + + + ! ----------------------------------------------------------------------- + ! + ! define MERRA-2 file specs + ! ! MERRA-2 file specs with uncorrected (AGCM) precip from the "int" Collection ! (ie, the precip generated by the AGCM within the MERRA-2 system) ! @@ -3443,8 +3506,10 @@ subroutine get_GEOS( date_time, force_dtstep, met_path, met_tag, & M2COR_defs(71,:)=[character(len=40):: 'SSSD004 ','tavg','tavg1_2d_adg_Nx','diag','F'] M2COR_defs(72,:)=[character(len=40):: 'SSSD005 ','tavg','tavg1_2d_adg_Nx','diag','F'] - - ! MERRA file specs + + ! ----------------------------------------------------------------------- + ! + ! define (original) MERRA file specs ! ! use *only* "tavg" files b/c "bkg.sfc" files are available only every 6h ! From 73d49b8791d231710fba2981d73d2a8ee8fa112d Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Wed, 25 Dec 2024 07:57:39 -0500 Subject: [PATCH 040/107] For 0-diff testing, reinstated bit-shaving and default regrid_method for lnd Collections (GEOSldas_HIST.rc) --- GEOSldas_App/GEOSldas_HIST.rc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/GEOSldas_App/GEOSldas_HIST.rc b/GEOSldas_App/GEOSldas_HIST.rc index 15ba59d5..aa072cae 100644 --- a/GEOSldas_App/GEOSldas_HIST.rc +++ b/GEOSldas_App/GEOSldas_HIST.rc @@ -117,7 +117,7 @@ COLLECTIONS: :: tavg24_1d_lnd_Nt.descr: 'Tile-space,Daily,Time-Averaged,Single-Level,Assimilation,Land Surface Diagnostics', -# tavg24_1d_lnd_Nt.nbits: 12, + tavg24_1d_lnd_Nt.nbits: 12, tavg24_1d_lnd_Nt.template: '%y4%m2%d2_%h2%n2z.bin', tavg24_1d_lnd_Nt.mode: 'time-averaged', tavg24_1d_lnd_Nt.frequency: 240000, @@ -217,14 +217,14 @@ COLLECTIONS: tavg24_2d_lnd_Nx.format: 'CFIO', tavg24_2d_lnd_Nx.descr: '2d,Daily,Time-Averaged,Single-Level,Assimilation,Land Surface Diagnostics', -# tavg24_2d_lnd_Nx.nbits: 12, + tavg24_2d_lnd_Nx.nbits: 12, tavg24_2d_lnd_Nx.template: '%y4%m2%d2_%h2%n2z.nc4', tavg24_2d_lnd_Nx.mode: 'time-averaged', tavg24_2d_lnd_Nx.frequency: 240000, tavg24_2d_lnd_Nx.ref_time: 000000, tavg24_2d_lnd_Nx.regrid_exch: '../input/tile.data' tavg24_2d_lnd_Nx.regrid_name: 'GRIDNAME' - tavg24_2d_lnd_Nx.regrid_method: 'BILINEAR_MONOTONIC' , +# tavg24_2d_lnd_Nx.regrid_method: 'BILINEAR_MONOTONIC' , tavg24_2d_lnd_Nx.grid_label: PC720x361-DC tavg24_2d_lnd_Nx.deflate: 2, tavg24_2d_lnd_Nx.fields: 'GRN' , 'VEGDYN' , From 0d9b413ae3bd6194075401d0ecde9721306754f9 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Mon, 6 Jan 2025 14:53:35 -0500 Subject: [PATCH 041/107] fix syntax error in GEOSldas_HIST.rc from previous commit --- GEOSldas_App/GEOSldas_HIST.rc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GEOSldas_App/GEOSldas_HIST.rc b/GEOSldas_App/GEOSldas_HIST.rc index aa072cae..c638f97d 100644 --- a/GEOSldas_App/GEOSldas_HIST.rc +++ b/GEOSldas_App/GEOSldas_HIST.rc @@ -28,7 +28,7 @@ COLLECTIONS: :: #CUBE GRID_LABELS: PC720x361-DC -#CUBE GRID_LABELS: PC1440x721-DC +#CUBE PC1440x721-DC #CUBE :: From b0532ca2e29f31cffa9244fc0b0ecc67121d7b91 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Mon, 6 Jan 2025 15:52:14 -0500 Subject: [PATCH 042/107] fixed previous commits in GEOSldas_HIST.rc: commented out SPLH [not ready for CatchCN], fixed comment character --- GEOSldas_App/GEOSldas_HIST.rc | 38 +++++++++++++++++------------------ 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/GEOSldas_App/GEOSldas_HIST.rc b/GEOSldas_App/GEOSldas_HIST.rc index c638f97d..8e2647f4 100644 --- a/GEOSldas_App/GEOSldas_HIST.rc +++ b/GEOSldas_App/GEOSldas_HIST.rc @@ -136,14 +136,14 @@ COLLECTIONS: 'TPSAT' , 'GridComp' , 'TSATLAND' , 'TPWLT' , 'GridComp' , 'TWLTLAND' , 'TPSURF' , 'GridComp' , 'TSURFLAND' , - 'TP1' , 'GridComp' , 'TSOIL1' , ! CATCH GC: TP1, ENSAVG GC: TSOIL1TILE - 'TP2' , 'GridComp' , 'TSOIL2' , ! ... - 'TP3' , 'GridComp' , 'TSOIL3' , ! ... - 'TP4' , 'GridComp' , 'TSOIL4' , ! ... - 'TP5' , 'GridComp' , 'TSOIL5' , ! ... - 'TP6' , 'GridComp' , 'TSOIL6' , ! ... - 'PRLAND' , 'GridComp' , 'PRECTOTCORRLAND' , ! assume "corrected" precip - 'SNOLAND' , 'GridComp' , 'PRECSNOCORRLAND' , ! assume "corrected" precip + 'TP1' , 'GridComp' , 'TSOIL1' , # CATCH GC: TP1, ENSAVG GC: TSOIL1TILE + 'TP2' , 'GridComp' , 'TSOIL2' , # ... + 'TP3' , 'GridComp' , 'TSOIL3' , # ... + 'TP4' , 'GridComp' , 'TSOIL4' , # ... + 'TP5' , 'GridComp' , 'TSOIL5' , # ... + 'TP6' , 'GridComp' , 'TSOIL6' , # ... + 'PRLAND' , 'GridComp' , 'PRECTOTCORRLAND' , # assume "corrected" precip + 'SNOLAND' , 'GridComp' , 'PRECSNOCORRLAND' , # assume "corrected" precip 'TSLAND' , 'GridComp' , 'SNOMASLAND' , 'SNOWDP' , 'GridComp' , 'SNODPLAND' , 'EVPSOI' , 'GridComp' , 'LHLANDSOIL' , @@ -171,7 +171,7 @@ COLLECTIONS: 'DWLAND' , 'GridComp' , 'WCHANGELAND' , 'DHLAND' , 'GridComp' , 'ECHANGELAND' , 'SPLAND' , 'GridComp' , 'SPSHLAND' , - 'SPLH' , 'GridComp' , 'SPLHLAND' , +# 'SPLH' , 'GridComp' , 'SPLHLAND' , # works for Catch only, not yet for CatchCN (comment out as needed) 'SPWATR' , 'GridComp' , 'SPEVLAND' , 'SPSNOW' , 'GridComp' , 'SPSNLAND' , 'PEATCLSM_WATERLEVEL', 'GridComp' , @@ -224,7 +224,7 @@ COLLECTIONS: tavg24_2d_lnd_Nx.ref_time: 000000, tavg24_2d_lnd_Nx.regrid_exch: '../input/tile.data' tavg24_2d_lnd_Nx.regrid_name: 'GRIDNAME' -# tavg24_2d_lnd_Nx.regrid_method: 'BILINEAR_MONOTONIC' , +# tavg24_2d_lnd_Nx.regrid_method: 'BILINEAR_MONOTONIC' , tavg24_2d_lnd_Nx.grid_label: PC720x361-DC tavg24_2d_lnd_Nx.deflate: 2, tavg24_2d_lnd_Nx.fields: 'GRN' , 'VEGDYN' , @@ -241,14 +241,14 @@ COLLECTIONS: 'TPSAT' , 'GridComp' , 'TSATLAND' , 'TPWLT' , 'GridComp' , 'TWLTLAND' , 'TPSURF' , 'GridComp' , 'TSURFLAND' , - 'TP1' , 'GridComp' , 'TSOIL1' , ! CATCH GC: TP1, ENSAVG GC: TSOIL1TILE - 'TP2' , 'GridComp' , 'TSOIL2' , ! ... - 'TP3' , 'GridComp' , 'TSOIL3' , ! ... - 'TP4' , 'GridComp' , 'TSOIL4' , ! ... - 'TP5' , 'GridComp' , 'TSOIL5' , ! ... - 'TP6' , 'GridComp' , 'TSOIL6' , ! ... - 'PRLAND' , 'GridComp' , 'PRECTOTCORRLAND' , ! assume "corrected" precip - 'SNOLAND' , 'GridComp' , 'PRECSNOCORRLAND' , ! assume "corrected" precip + 'TP1' , 'GridComp' , 'TSOIL1' , # CATCH GC: TP1, ENSAVG GC: TSOIL1TILE + 'TP2' , 'GridComp' , 'TSOIL2' , # ... + 'TP3' , 'GridComp' , 'TSOIL3' , # ... + 'TP4' , 'GridComp' , 'TSOIL4' , # ... + 'TP5' , 'GridComp' , 'TSOIL5' , # ... + 'TP6' , 'GridComp' , 'TSOIL6' , # ... + 'PRLAND' , 'GridComp' , 'PRECTOTCORRLAND' , # assume "corrected" precip + 'SNOLAND' , 'GridComp' , 'PRECSNOCORRLAND' , # assume "corrected" precip 'TSLAND' , 'GridComp' , 'SNOMASLAND' , 'SNOWDP' , 'GridComp' , 'SNODPLAND' , 'EVPSOI' , 'GridComp' , 'LHLANDSOIL' , @@ -276,7 +276,7 @@ COLLECTIONS: 'DWLAND' , 'GridComp' , 'WCHANGELAND' , 'DHLAND' , 'GridComp' , 'ECHANGELAND' , 'SPLAND' , 'GridComp' , 'SPSHLAND' , - 'SPLH' , 'GridComp' , 'SPLHLAND' , +# 'SPLH' , 'GridComp' , 'SPLHLAND' , # works for Catch only, not yet for CatchCN (comment out as needed) 'SPWATR' , 'GridComp' , 'SPEVLAND' , 'SPSNOW' , 'GridComp' , 'SPSNLAND' , 'PEATCLSM_WATERLEVEL', 'GridComp' , From e1add91d9fc8efdb63451fbe70effb984bdaf402 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Mon, 6 Jan 2025 15:56:43 -0500 Subject: [PATCH 043/107] minimal cleanup of comment from previous commit --- GEOSldas_App/GEOSldas_HIST.rc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GEOSldas_App/GEOSldas_HIST.rc b/GEOSldas_App/GEOSldas_HIST.rc index 8e2647f4..55149828 100644 --- a/GEOSldas_App/GEOSldas_HIST.rc +++ b/GEOSldas_App/GEOSldas_HIST.rc @@ -171,7 +171,7 @@ COLLECTIONS: 'DWLAND' , 'GridComp' , 'WCHANGELAND' , 'DHLAND' , 'GridComp' , 'ECHANGELAND' , 'SPLAND' , 'GridComp' , 'SPSHLAND' , -# 'SPLH' , 'GridComp' , 'SPLHLAND' , # works for Catch only, not yet for CatchCN (comment out as needed) +# 'SPLH' , 'GridComp' , 'SPLHLAND' , # works for Catch only, not yet for CatchCN 'SPWATR' , 'GridComp' , 'SPEVLAND' , 'SPSNOW' , 'GridComp' , 'SPSNLAND' , 'PEATCLSM_WATERLEVEL', 'GridComp' , @@ -276,7 +276,7 @@ COLLECTIONS: 'DWLAND' , 'GridComp' , 'WCHANGELAND' , 'DHLAND' , 'GridComp' , 'ECHANGELAND' , 'SPLAND' , 'GridComp' , 'SPSHLAND' , -# 'SPLH' , 'GridComp' , 'SPLHLAND' , # works for Catch only, not yet for CatchCN (comment out as needed) +# 'SPLH' , 'GridComp' , 'SPLHLAND' , # works for Catch only, not yet for CatchCN 'SPWATR' , 'GridComp' , 'SPEVLAND' , 'SPSNOW' , 'GridComp' , 'SPSNLAND' , 'PEATCLSM_WATERLEVEL', 'GridComp' , From c9ec1919790c11acd243183cc7c1436447f41a02 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Wed, 8 Jan 2025 11:04:25 -0500 Subject: [PATCH 044/107] renamed TSOIL[x]TILE in EnsGridComp to TP[x] for consistency with CatchGridComp (GEOS_EnsGridComp.F90, GEOS_LandAssimGridComp.F90, GEOSldas_HIST.rc, process_hist.csh) --- GEOSens_GridComp/GEOS_EnsGridComp.F90 | 28 ++++++++--------- .../GEOS_LandAssimGridComp.F90 | 16 +++++----- GEOSldas_App/GEOSldas_HIST.rc | 30 +++++++++---------- GEOSldas_App/process_hist.csh | 12 ++++---- 4 files changed, 43 insertions(+), 43 deletions(-) mode change 100755 => 100644 GEOSldas_App/process_hist.csh diff --git a/GEOSens_GridComp/GEOS_EnsGridComp.F90 b/GEOSens_GridComp/GEOS_EnsGridComp.F90 index 57f38650..7dd65533 100644 --- a/GEOSens_GridComp/GEOS_EnsGridComp.F90 +++ b/GEOSens_GridComp/GEOS_EnsGridComp.F90 @@ -860,7 +860,7 @@ subroutine SetServices(gc, rc) call MAPL_AddExportSpec(GC, & LONG_NAME = 'soil_temperature_layer_1' ,& UNITS = 'K' ,& - SHORT_NAME = 'TSOIL1TILE' ,& + SHORT_NAME = 'TP1' ,& DIMS = MAPL_DimsTileOnly ,& VLOCATION = MAPL_VLocationNone ,& RC=STATUS ) @@ -869,7 +869,7 @@ subroutine SetServices(gc, rc) call MAPL_AddExportSpec(GC, & LONG_NAME = 'soil_temperature_layer_1_ensstd' ,& UNITS = 'K' ,& - SHORT_NAME = 'TSOIL1TILE_ENSSTD' ,& + SHORT_NAME = 'TP1_ENSSTD' ,& DIMS = MAPL_DimsTileOnly ,& VLOCATION = MAPL_VLocationNone ,& RC=STATUS ) @@ -878,7 +878,7 @@ subroutine SetServices(gc, rc) call MAPL_AddExportSpec(GC, & LONG_NAME = 'soil_temperature_layer_2' ,& UNITS = 'K' ,& - SHORT_NAME = 'TSOIL2TILE' ,& + SHORT_NAME = 'TP2' ,& DIMS = MAPL_DimsTileOnly ,& VLOCATION = MAPL_VLocationNone ,& RC=STATUS ) @@ -887,7 +887,7 @@ subroutine SetServices(gc, rc) call MAPL_AddExportSpec(GC, & LONG_NAME = 'soil_temperature_layer_3' ,& UNITS = 'K' ,& - SHORT_NAME = 'TSOIL3TILE' ,& + SHORT_NAME = 'TP3' ,& DIMS = MAPL_DimsTileOnly ,& VLOCATION = MAPL_VLocationNone ,& RC=STATUS ) @@ -896,7 +896,7 @@ subroutine SetServices(gc, rc) call MAPL_AddExportSpec(GC, & LONG_NAME = 'soil_temperature_layer_4' ,& UNITS = 'K' ,& - SHORT_NAME = 'TSOIL4TILE' ,& + SHORT_NAME = 'TP4' ,& DIMS = MAPL_DimsTileOnly ,& VLOCATION = MAPL_VLocationNone ,& RC=STATUS ) @@ -905,7 +905,7 @@ subroutine SetServices(gc, rc) call MAPL_AddExportSpec(GC, & LONG_NAME = 'soil_temperature_layer_5' ,& UNITS = 'K' ,& - SHORT_NAME = 'TSOIL5TILE' ,& + SHORT_NAME = 'TP5' ,& DIMS = MAPL_DimsTileOnly ,& VLOCATION = MAPL_VLocationNone ,& RC=STATUS ) @@ -914,7 +914,7 @@ subroutine SetServices(gc, rc) call MAPL_AddExportSpec(GC, & LONG_NAME = 'soil_temperature_layer_6' ,& UNITS = 'K' ,& - SHORT_NAME = 'TSOIL6TILE' ,& + SHORT_NAME = 'TP6' ,& DIMS = MAPL_DimsTileOnly ,& VLOCATION = MAPL_VLocationNone ,& RC=STATUS ) @@ -2966,19 +2966,19 @@ subroutine Collect_land_ens(gc, import, export, clock, rc) VERIFY_(status) call MAPL_GetPointer(export, WCPR_enstd, 'WCPR_ENSSTD' ,rc=status) VERIFY_(status) - call MAPL_GetPointer(export, TP1_enavg, 'TSOIL1TILE' ,rc=status) + call MAPL_GetPointer(export, TP1_enavg, 'TP1' ,rc=status) VERIFY_(status) - call MAPL_GetPointer(export, TP1_enstd, 'TSOIL1TILE_ENSSTD' ,rc=status) + call MAPL_GetPointer(export, TP1_enstd, 'TP1_ENSSTD' ,rc=status) VERIFY_(status) - call MAPL_GetPointer(export, TP2_enavg, 'TSOIL2TILE' ,rc=status) + call MAPL_GetPointer(export, TP2_enavg, 'TP2' ,rc=status) VERIFY_(status) - call MAPL_GetPointer(export, TP3_enavg, 'TSOIL3TILE' ,rc=status) + call MAPL_GetPointer(export, TP3_enavg, 'TP3' ,rc=status) VERIFY_(status) - call MAPL_GetPointer(export, TP4_enavg, 'TSOIL4TILE' ,rc=status) + call MAPL_GetPointer(export, TP4_enavg, 'TP4' ,rc=status) VERIFY_(status) - call MAPL_GetPointer(export, TP5_enavg, 'TSOIL5TILE' ,rc=status) + call MAPL_GetPointer(export, TP5_enavg, 'TP5' ,rc=status) VERIFY_(status) - call MAPL_GetPointer(export, TP6_enavg, 'TSOIL6TILE' ,rc=status) + call MAPL_GetPointer(export, TP6_enavg, 'TP6' ,rc=status) VERIFY_(status) call MAPL_GetPointer(export, EMIS_enavg, 'EMIS' ,rc=status) VERIFY_(status) diff --git a/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 b/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 index 91fe0be1..c7904fca 100644 --- a/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 +++ b/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 @@ -849,7 +849,7 @@ subroutine SetServices ( GC, RC ) call MAPL_AddExportSpec(GC ,& LONG_NAME = 'soil_temperature_layer_1_analysis' ,& UNITS = 'K' ,& - SHORT_NAME = 'TSOIL1_ANA' ,& + SHORT_NAME = 'TP1_ANA' ,& DIMS = MAPL_DimsTileOnly ,& VLOCATION = MAPL_VLocationNone ,& RC=STATUS ) @@ -858,7 +858,7 @@ subroutine SetServices ( GC, RC ) call MAPL_AddExportSpec(GC ,& LONG_NAME = 'soil_temperature_layer_1_analysis_ensstd' ,& UNITS = 'K' ,& - SHORT_NAME = 'TSOIL1_ANA_ENSSTD' ,& + SHORT_NAME = 'TP1_ANA_ENSSTD' ,& DIMS = MAPL_DimsTileOnly ,& VLOCATION = MAPL_VLocationNone ,& RC=STATUS ) @@ -1531,13 +1531,13 @@ subroutine RUN ( GC, IMPORT, EXPORT, CLOCK, RC ) real, dimension(:),pointer :: RZMC_ana=>null() ! rootzone soil moisture real, dimension(:),pointer :: PRMC_ana=>null() ! profile soil moisture real, dimension(:),pointer :: TPSURF_ana=>null() ! tpsurf - real, dimension(:),pointer :: TSOIL1_ana=>null() ! tsoil1 + real, dimension(:),pointer :: TP1_ana=>null() ! tsoil1 real, dimension(:),pointer :: SFMC_ana_ensstd=>null() ! surface soil moisture real, dimension(:),pointer :: RZMC_ana_ensstd=>null() ! rootzone soil moisture real, dimension(:),pointer :: PRMC_ana_ensstd=>null() ! profile soil moisture real, dimension(:),pointer :: TPSURF_ana_ensstd=>null() ! tpsurf - real, dimension(:),pointer :: TSOIL1_ana_ensstd=>null() ! tsoil1 + real, dimension(:),pointer :: TP1_ana_ensstd=>null() ! tsoil1 !! export for microwave radiative transfer model (mwRTM) @@ -1699,7 +1699,7 @@ subroutine RUN ( GC, IMPORT, EXPORT, CLOCK, RC ) call MAPL_GetPointer(export, TPSURF_ana, 'TPSURF_ANA' ,rc=status) VERIFY_(status) - call MAPL_GetPointer(export, TSOIL1_ana, 'TSOIL1_ANA' ,rc=status) + call MAPL_GetPointer(export, TP1_ana, 'TP1_ANA' ,rc=status) VERIFY_(status) call MAPL_GetPointer(export, SFMC_ana, 'WCSF_ANA' ,rc=status) VERIFY_(status) @@ -1709,7 +1709,7 @@ subroutine RUN ( GC, IMPORT, EXPORT, CLOCK, RC ) VERIFY_(status) call MAPL_GetPointer(export, TPSURF_ana_ensstd, 'TPSURF_ANA_ENSSTD' ,rc=status) VERIFY_(status) - call MAPL_GetPointer(export, TSOIL1_ana_ensstd, 'TSOIL1_ANA_ENSSTD' ,rc=status) + call MAPL_GetPointer(export, TP1_ana_ensstd, 'TP1_ANA_ENSSTD' ,rc=status) VERIFY_(status) call MAPL_GetPointer(export, SFMC_ana_ensstd, 'WCSF_ANA_ENSSTD' ,rc=status) VERIFY_(status) @@ -2046,13 +2046,13 @@ subroutine RUN ( GC, IMPORT, EXPORT, CLOCK, RC ) if(associated(RZMC_ana)) RZMC_ana(:) = cat_diagS_ensavg(:)%rzmc if(associated(PRMC_ana)) PRMC_ana(:) = cat_diagS_ensavg(:)%prmc if(associated(TPSURF_ana)) TPSURF_ana(:) = cat_diagS_ensavg(:)%tsurf - if(associated(TSOIL1_ana)) TSOIL1_ana(:) = cat_diagS_ensavg(:)%tp(1) + MAPL_TICE ! convert to K + if(associated(TP1_ana)) TP1_ana(:) = cat_diagS_ensavg(:)%tp(1) + MAPL_TICE ! convert to K if(associated(SFMC_ana_ensstd)) SFMC_ana_ensstd(:) = max( cat_diagS_ensstd(:)%sfmc , 0. ) if(associated(RZMC_ana_ensstd)) RZMC_ana_ensstd(:) = max( cat_diagS_ensstd(:)%rzmc , 0. ) if(associated(PRMC_ana_ensstd)) PRMC_ana_ensstd(:) = max( cat_diagS_ensstd(:)%prmc , 0. ) if(associated(TPSURF_ana_ensstd)) TPSURF_ana_ensstd(:) = max( cat_diagS_ensstd(:)%tsurf , 0. ) - if(associated(TSOIL1_ana_ensstd)) TSOIL1_ana_ensstd(:) = max( cat_diagS_ensstd(:)%tp(1) , 0. ) + if(associated(TP1_ana_ensstd)) TP1_ana_ensstd(:) = max( cat_diagS_ensstd(:)%tp(1) , 0. ) if(associated(MWRTM_VEGOPACITY)) MWRTM_VEGOPACITY(:) = mwRTM_param(:)%VEGOPACITY diff --git a/GEOSldas_App/GEOSldas_HIST.rc b/GEOSldas_App/GEOSldas_HIST.rc index 55149828..ce692ffb 100644 --- a/GEOSldas_App/GEOSldas_HIST.rc +++ b/GEOSldas_App/GEOSldas_HIST.rc @@ -385,12 +385,12 @@ COLLECTIONS: 'WET2' , 'ENSAVG' , 'sm_rootzone_wetness' , 'WET3' , 'ENSAVG' , 'sm_profile_wetness' , 'TPSURF' , 'ENSAVG' , 'surface_temp' , - 'TSOIL1TILE' , 'ENSAVG' , 'soil_temp_layer1' , - 'TSOIL2TILE' , 'ENSAVG' , 'soil_temp_layer2' , - 'TSOIL3TILE' , 'ENSAVG' , 'soil_temp_layer3' , - 'TSOIL4TILE' , 'ENSAVG' , 'soil_temp_layer4' , - 'TSOIL5TILE' , 'ENSAVG' , 'soil_temp_layer5' , - 'TSOIL6TILE' , 'ENSAVG' , 'soil_temp_layer6' , + 'TP1' , 'ENSAVG' , 'soil_temp_layer1' , + 'TP2' , 'ENSAVG' , 'soil_temp_layer2' , + 'TP3' , 'ENSAVG' , 'soil_temp_layer3' , + 'TP4' , 'ENSAVG' , 'soil_temp_layer4' , + 'TP5' , 'ENSAVG' , 'soil_temp_layer5' , + 'TP6' , 'ENSAVG' , 'soil_temp_layer6' , 'SNOWMASS' , 'ENSAVG' , 'snow_mass' , 'SNOWDP' , 'ENSAVG' , 'snow_depth' , 'EVLAND' , 'ENSAVG' , 'land_evapotranspiration_flux' , @@ -430,7 +430,7 @@ COLLECTIONS: inst1_1d_lnr_Nt.frequency: 010000 , inst1_1d_lnr_Nt.ref_time: 000000, inst1_1d_lnr_Nt.fields: 'TPSURF' , 'ENSAVG' , 'surface_temp' , - 'TSOIL1TILE' , 'ENSAVG' , 'soil_temp_layer1' , + 'TP1' , 'ENSAVG' , 'soil_temp_layer1' , 'TPSNOW' , 'ENSAVG' , 'snow_temp_layer1' , 'TB_LAND_1410MHZ_40DEG_HPOL' , 'LANDASSIM' , 'tb_h' , 'TB_LAND_1410MHZ_40DEG_VPOL' , 'LANDASSIM' , 'tb_v' , @@ -487,22 +487,22 @@ COLLECTIONS: 'WCRZ' , 'ENSAVG' , 'RZMC_FCST' , 'WCPR' , 'ENSAVG' , 'PRMC_FCST' , 'TPSURF' , 'ENSAVG' , 'TSURF_FCST' , - 'TSOIL1TILE' , 'ENSAVG' , 'TSOIL1_FCST' , + 'TP1' , 'ENSAVG' , 'TSOIL1_FCST' , 'WCSF_ENSSTD' , 'ENSAVG' , 'SFMC_FCST_ENSSTD' , 'WCRZ_ENSSTD' , 'ENSAVG' , 'RZMC_FCST_ENSSTD' , 'WCPR_ENSSTD' , 'ENSAVG' , 'PRMC_FCST_ENSSTD' , 'TPSURF_ENSSTD' , 'ENSAVG' , 'TSURF_FCST_ENSSTD' , - 'TSOIL1TILE_ENSSTD' , 'ENSAVG' , 'TSOIL1_FCST_ENSSTD' , + 'TP1_ENSSTD' , 'ENSAVG' , 'TSOIL1_FCST_ENSSTD' , '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' , + 'TP1_ANA' , 'LANDASSIM' , 'TSOIL1_ANA' , 'WCSF_ANA_ENSSTD' , 'LANDASSIM' , 'SFMC_ANA_ENSSTD' , 'WCRZ_ANA_ENSSTD' , 'LANDASSIM' , 'RZMC_ANA_ENSSTD' , 'WCPR_ANA_ENSSTD' , 'LANDASSIM' , 'PRMC_ANA_ENSSTD' , 'TPSURF_ANA_ENSSTD' , 'LANDASSIM' , 'TSURF_ANA_ENSSTD' , - 'TSOIL1_ANA_ENSSTD' , 'LANDASSIM' , 'TSOIL1_ANA_ENSSTD' + 'TP1_ANA_ENSSTD' , 'LANDASSIM' , 'TSOIL1_ANA_ENSSTD' :: # For lndfcstana, *.frequency and *.ref_time must be consistent with the LDAS.rc resource @@ -526,22 +526,22 @@ COLLECTIONS: 'WCRZ' , 'ENSAVG' , 'RZMC_FCST' , 'WCPR' , 'ENSAVG' , 'PRMC_FCST' , 'TPSURF' , 'ENSAVG' , 'TSURF_FCST' , - 'TSOIL1TILE' , 'ENSAVG' , 'TSOIL1_FCST' , + 'TP1' , 'ENSAVG' , 'TSOIL1_FCST' , 'WCSF_ENSSTD' , 'ENSAVG' , 'SFMC_FCST_ENSSTD' , 'WCRZ_ENSSTD' , 'ENSAVG' , 'RZMC_FCST_ENSSTD' , 'WCPR_ENSSTD' , 'ENSAVG' , 'PRMC_FCST_ENSSTD' , 'TPSURF_ENSSTD' , 'ENSAVG' , 'TSURF_FCST_ENSSTD' , - 'TSOIL1TILE_ENSSTD' , 'ENSAVG' , 'TSOIL1_FCST_ENSSTD' , + 'TP1_ENSSTD' , 'ENSAVG' , 'TSOIL1_FCST_ENSSTD' , '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' , + 'TP1_ANA' , 'LANDASSIM' , 'TSOIL1_ANA' , 'WCSF_ANA_ENSSTD' , 'LANDASSIM' , 'SFMC_ANA_ENSSTD' , 'WCRZ_ANA_ENSSTD' , 'LANDASSIM' , 'RZMC_ANA_ENSSTD' , 'WCPR_ANA_ENSSTD' , 'LANDASSIM' , 'PRMC_ANA_ENSSTD' , 'TPSURF_ANA_ENSSTD' , 'LANDASSIM' , 'TSURF_ANA_ENSSTD' , - 'TSOIL1_ANA_ENSSTD' , 'LANDASSIM' , 'TSOIL1_ANA_ENSSTD' + 'TP1_ANA_ENSSTD' , 'LANDASSIM' , 'TSOIL1_ANA_ENSSTD' :: # ========================== EOF ============================================================== diff --git a/GEOSldas_App/process_hist.csh b/GEOSldas_App/process_hist.csh old mode 100755 new mode 100644 index 73d3b421..4c6516ff --- a/GEOSldas_App/process_hist.csh +++ b/GEOSldas_App/process_hist.csh @@ -54,12 +54,12 @@ endif if($NENS > 1) then set GridComp = ENSAVG sed -i 's|VEGDYN|'VEGDYN_e0000'|g' $HISTRC - sed -i 's|TP1|'TSOIL1TILE'|g' $HISTRC - sed -i 's|TP2|'TSOIL2TILE'|g' $HISTRC - sed -i 's|TP3|'TSOIL3TILE'|g' $HISTRC - sed -i 's|TP4|'TSOIL4TILE'|g' $HISTRC - sed -i 's|TP5|'TSOIL5TILE'|g' $HISTRC - sed -i 's|TP6|'TSOIL6TILE'|g' $HISTRC +# sed -i 's|TP1|'TSOIL1TILE'|g' $HISTRC +# sed -i 's|TP2|'TSOIL2TILE'|g' $HISTRC +# sed -i 's|TP3|'TSOIL3TILE'|g' $HISTRC +# sed -i 's|TP4|'TSOIL4TILE'|g' $HISTRC +# sed -i 's|TP5|'TSOIL5TILE'|g' $HISTRC +# sed -i 's|TP6|'TSOIL6TILE'|g' $HISTRC # sed -i 's|DATAATM|'DATAATM0000'|g' $HISTRC endif From 791b3466021ef30b7da3ac762f89bbed5ab25369 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Wed, 8 Jan 2025 17:54:26 -0700 Subject: [PATCH 045/107] read_obs_sm_CYGNSS stub --- .../clsm_ensupd_read_obs.F90 | 115 +++++++++++++++--- 1 file changed, 100 insertions(+), 15 deletions(-) diff --git a/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 05eeaf66..03baa46b 100644 --- a/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -1830,19 +1830,19 @@ subroutine read_obs_sm_ASCAT_EUMET( & ! 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) ! select date/time format with 4-digit year (YYYYMMDDHH) +! 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) ! select date/time format with 4-digit year (YYYYMMDDHH) - 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 ) +! 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 - call ufbint(lnbufr,tmp_vdata,14,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 @@ -1853,11 +1853,11 @@ subroutine read_obs_sm_ASCAT_EUMET( & tmp_data(N_obs,:) = tmp_vdata - end do loop_report - end do msg_report +! end do loop_report +! end do msg_report - call closbf(lnbufr) - close(lnbufr) +! call closbf(lnbufr) +! close(lnbufr) end do ! end file loop @@ -2121,7 +2121,72 @@ subroutine read_obs_sm_ASCAT_EUMET( & if (associated(tmp_jtime)) deallocate(tmp_jtime) end subroutine read_obs_sm_ASCAT_EUMET - + + ! **************************************************************************** + + subroutine read_obs_sm_CYGNSS( & + 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, CYGNSS_sm, CYGNSS_sm_std, CYGNSS_lon, CYGNSS_lat, CYGNSS_time ) + +!--------------------------------------------------------------------- +! +! Routine to read in ASCAT surface degree of saturation (sfds) obs from +! BUFR files for 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. +! Soil moisture derived from re-sampled (spatially averaged) backscatter (sigma0) values +! on a 25-km orbit swath grid. Input data files are in BUFR file format. +! +! 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 +! A. Fox, reichle, Feb 2024 - added ASCAT obs mask +! +! -------------------------------------------------------------------- + + use netcdf + 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 + + ! outputs: + + logical, intent(out) :: found_obs + + real, intent(out), dimension(N_catd) :: CYGNSS_sm ! sfds obs [fraction] (i.e., 0-1) + real, intent(out), dimension(N_catd) :: CYGNSS_sm_std ! sfds obs err std [fraction] (i.e., 0-1) + real, intent(out), dimension(N_catd) :: CYGNSS_lon, CYGNSS_lat + real*8, intent(out), dimension(N_catd) :: CYGNSS_time ! J2000 seconds + + ! --------------- + + end subroutine read_obs_sm_CYGNSS + ! *************************************************************************** subroutine read_sm_ASCAT_bin( & @@ -2307,7 +2372,6 @@ subroutine read_sm_ASCAT_bin( & end subroutine read_sm_ASCAT_bin - ! ***************************************************************** subroutine read_obs_LaRC_Tskin( & @@ -8568,7 +8632,28 @@ subroutine read_obs( & date_time, this_obs_param, tmp_lon, tmp_lat, tmp_time, & tmp_obs, tmp_std_obs ) - end if + end if + + case ('CYGNSS_SM','CYGNSS_SM_daily') + + call read_obs_sm_CYGNSS( & + 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) + + ! scale observations to model climatology + + if (this_obs_param%scale .and. found_obs) then + + scaled_obs = .true. + + 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 case ('isccp_tskin_gswp2_v1') From 9ffc47ae93740a43b2b8e3bb392f23093dc05837 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Wed, 8 Jan 2025 18:06:33 -0700 Subject: [PATCH 046/107] edit description --- .../clsm_ensupd_read_obs.F90 | 30 +++++-------------- 1 file changed, 7 insertions(+), 23 deletions(-) diff --git a/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 03baa46b..3609731a 100644 --- a/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -2130,29 +2130,13 @@ subroutine read_obs_sm_CYGNSS( & this_obs_param, & found_obs, CYGNSS_sm, CYGNSS_sm_std, CYGNSS_lon, CYGNSS_lat, CYGNSS_time ) -!--------------------------------------------------------------------- -! -! Routine to read in ASCAT surface degree of saturation (sfds) obs from -! BUFR files for 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. -! Soil moisture derived from re-sampled (spatially averaged) backscatter (sigma0) values -! on a 25-km orbit swath grid. Input data files are in BUFR file format. -! -! 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 -! A. Fox, reichle, Feb 2024 - added ASCAT obs mask -! -! -------------------------------------------------------------------- + !--------------------------------------------------------------------- + ! + ! Routine to read in CYGNSS soil moisture obs from netCDF files. + ! + ! A. Fox, Jan 2025 + ! + ! -------------------------------------------------------------------- use netcdf implicit none From 05eb461b5746e90da05222bf311c8acdd1bb76a0 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Thu, 9 Jan 2025 12:36:48 -0700 Subject: [PATCH 047/107] add a new type of obs --- .../clsm_ensupd_glob_param.F90 | 2 +- .../clsm_ensupd_read_obs.F90 | 40 ++++++++++++++++++- GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml | 38 ++++++++++++++++++ 3 files changed, 77 insertions(+), 3 deletions(-) diff --git a/GEOSlandassim_GridComp/clsm_ensupd_glob_param.F90 b/GEOSlandassim_GridComp/clsm_ensupd_glob_param.F90 index 678a0978..6d1ef60f 100644 --- a/GEOSlandassim_GridComp/clsm_ensupd_glob_param.F90 +++ b/GEOSlandassim_GridComp/clsm_ensupd_glob_param.F90 @@ -48,7 +48,7 @@ module clsm_ensupd_glob_param ! 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 = 53 + integer, parameter :: N_obs_species_nml = 54 ! ---------------------------------------------------------------------- ! diff --git a/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 253528fb..d79e2795 100644 --- a/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -2186,13 +2186,49 @@ subroutine read_obs_sm_CYGNSS( & logical, intent(out) :: found_obs - real, intent(out), dimension(N_catd) :: CYGNSS_sm ! sfds obs [fraction] (i.e., 0-1) - real, intent(out), dimension(N_catd) :: CYGNSS_sm_std ! sfds obs err std [fraction] (i.e., 0-1) + real, intent(out), dimension(N_catd) :: CYGNSS_sm ! sm obs [cm3 cm-3] + real, intent(out), dimension(N_catd) :: CYGNSS_sm_std ! sm obs err std [cm3 cm-3] real, intent(out), dimension(N_catd) :: CYGNSS_lon, CYGNSS_lat real*8, intent(out), dimension(N_catd) :: CYGNSS_time ! J2000 seconds ! --------------- + character(4), parameter :: J2000_epoch_id = 'TT12' ! see date_time_util.F90 + + type(date_time_type) :: date_time_obs_beg, date_time_obs_end + type(date_time_type) :: date_time_up, date_time_low + + character(len=*), parameter :: Iam = 'read_obs_sm_CYGNSS' + character(len=400) :: err_msg + + ! ------------------------------------------------------------------- + + ! initialize + + found_obs = .false. + + ! determine operating time range of sensor + + if (trim(this_obs_param%descr) == 'CYGNSS_SM') then + date_time_obs_beg = date_time_type(2018, 8, 1, 0, 0, 0,-9999,-9999) + date_time_obs_end = date_time_type(2100, 1, 1, 0, 0, 0,-9999,-9999) + else + err_msg = 'Unknown obs_param%descr: ' // trim(this_obs_param%descr) + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + end if + + ! return if date_time falls outside operating time range + + if ( datetime_lt_refdatetime(date_time, date_time_obs_beg) .or. & + datetime_lt_refdatetime(date_time_obs_end, date_time) ) return + + ! cygnss sm subdaily observations are for 4 timeslices per day - 00-06, 06-12, 12-18, 18-24 UTC + ! we will assimilate these at 03, 09, 15, 21 UTC + + write (logunit,*) 'This is where we will read CYGNSS obs at YY:', date_time%year, ' DD:', date_time%day, ' HH:', date_time%hour + + return + end subroutine read_obs_sm_CYGNSS ! *************************************************************************** diff --git a/GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml b/GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml index 50850985..c6cf01db 100644 --- a/GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml +++ b/GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml @@ -2363,6 +2363,44 @@ obs_param_nml(53)%xcorr = 0. obs_param_nml(53)%ycorr = 0. obs_param_nml(53)%adapt = 0 +! -------------------------------------------------------------------------------------------------------------- +! +! 54 = CYGNSS_SM (CYGNSS Level 3 soil moisture version 3.2) +! +! https://podaac.jpl.nasa.gov/dataset/CYGNSS_L3_SOIL_MOISTURE_V3.2 + +obs_param_nml(49)%descr = 'CYGNSS_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 +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 = 'cm3 cm-3' +obs_param_nml(49)%path = '/discover/nobackup/amfox/CYGNSS_obs/' +obs_param_nml(49)%name = '' +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 = '' +obs_param_nml(49)%flistname = '' +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. +obs_param_nml(49)%xcorr = 0.25 +obs_param_nml(49)%ycorr = 0.25 +obs_param_nml(49)%adapt = 0 ! -------------------------------------------------------------------- From 7fa8180134306f46187b59fa694424df86ddfa78 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Thu, 9 Jan 2025 14:39:37 -0700 Subject: [PATCH 048/107] fix number in ensupd.nml --- GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml | 64 +++++++++---------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml b/GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml index c6cf01db..3724d023 100644 --- a/GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml +++ b/GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml @@ -2369,38 +2369,38 @@ obs_param_nml(53)%adapt = 0 ! ! https://podaac.jpl.nasa.gov/dataset/CYGNSS_L3_SOIL_MOISTURE_V3.2 -obs_param_nml(49)%descr = 'CYGNSS_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 -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 = 'cm3 cm-3' -obs_param_nml(49)%path = '/discover/nobackup/amfox/CYGNSS_obs/' -obs_param_nml(49)%name = '' -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 = '' -obs_param_nml(49)%flistname = '' -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. -obs_param_nml(49)%xcorr = 0.25 -obs_param_nml(49)%ycorr = 0.25 -obs_param_nml(49)%adapt = 0 +obs_param_nml(54)%descr = 'CYGNSS_SM' +obs_param_nml(54)%orbit = 3 +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 = 'sfmc' +obs_param_nml(54)%units = 'cm3 cm-3' +obs_param_nml(54)%path = '/discover/nobackup/amfox/CYGNSS_obs/' +obs_param_nml(54)%name = '' +obs_param_nml(54)%maskpath = '' +obs_param_nml(54)%maskname = '' +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 = 9. +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 e6b1dc8d01d3316d9217af072ef1fba1ca20a10b Mon Sep 17 00:00:00 2001 From: amfox37 Date: Fri, 10 Jan 2025 12:41:21 -0700 Subject: [PATCH 049/107] open and read netcdf file --- .../clsm_ensupd_read_obs.F90 | 200 +++++++++++++++++- 1 file changed, 191 insertions(+), 9 deletions(-) diff --git a/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index d79e2795..f664ce36 100644 --- a/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -2190,26 +2190,53 @@ subroutine read_obs_sm_CYGNSS( & real, intent(out), dimension(N_catd) :: CYGNSS_sm_std ! sm obs err std [cm3 cm-3] real, intent(out), dimension(N_catd) :: CYGNSS_lon, CYGNSS_lat real*8, intent(out), dimension(N_catd) :: CYGNSS_time ! J2000 seconds + + ! ------------------------------------------------------------------- + ! local variables: - ! --------------- - - character(4), parameter :: J2000_epoch_id = 'TT12' ! see date_time_util.F90 + integer, parameter :: max_obs = 100000 ! max number of obs read by subroutine (expecting < 6 hr assim window) + character(4), parameter :: J2000_epoch_id = 'TT12' ! see date_time_util.F90 + character(len=*), parameter :: Iam = 'read_obs_sm_CYGNSS' type(date_time_type) :: date_time_obs_beg, date_time_obs_end type(date_time_type) :: date_time_up, date_time_low - character(len=*), parameter :: Iam = 'read_obs_sm_CYGNSS' - character(len=400) :: err_msg - + character(400) :: err_msg + character(300) :: tmpfname, tmpname + character( 2) :: MM, DD, HH, MI + character( 4) :: YYYY + + integer :: pos, i, idx, N_obs, j, HHcnt + integer :: ierr, ncid + integer :: lon_dimid, lat_dimid, time_dimid, timeslices_dimid, startstop_dimid + integer :: sm_d_varid, sm_subd_varid, sigma_d_varid, sigma_subd_varid, timeintervals_varid, lat_varid, lon_varid + integer :: N_lon, N_lat, N_time, N_timeslices, N_startstop + + logical :: file_exists + logical :: HH03, HH09, HH12, HH15, HH21 + + real, dimension(:), pointer :: tmp_lon(:), tmp_lat(:), tmp_obs(:), tmp_err(:), tmp_time(:) + + real, allocatable :: sm_d(:,:,:), sm_subd(:,:,:), sigma_d(:,:,:), sigma_subd(:,:,:) + real, allocatable :: timeintervals(:,:), latitudes(:,:), longitudes(:,:) + real :: tmp1_lon(max_obs), tmp1_lat(max_obs), tmp1_obs(max_obs), tmp1_err(max_obs), tmp1_time(max_obs) + ! ------------------------------------------------------------------- ! initialize + nullify( tmp_lon, tmp_lat, tmp_obs, tmp_err, tmp_time ) + found_obs = .false. + HH03 = .false. + HH09 = .false. + HH12 = .false. + HH15 = .false. + HH21 = .false. ! determine operating time range of sensor - if (trim(this_obs_param%descr) == 'CYGNSS_SM') then + if (trim(this_obs_param%descr) == 'CYGNSS_SM' .or. trim(this_obs_param%descr) == 'CYGNSS_SM_daily') then date_time_obs_beg = date_time_type(2018, 8, 1, 0, 0, 0,-9999,-9999) date_time_obs_end = date_time_type(2100, 1, 1, 0, 0, 0,-9999,-9999) else @@ -2222,12 +2249,167 @@ subroutine read_obs_sm_CYGNSS( & if ( datetime_lt_refdatetime(date_time, date_time_obs_beg) .or. & datetime_lt_refdatetime(date_time_obs_end, date_time) ) return + ! find the time bounds of the assimilation window + ! (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) + + ! establish if assimilation window encompasses 12:00 UTC (daily CYGNSS obs time) + + if (date_time_low%hour < 12 .and. date_time_up%hour >= 12) then + HH12 = .true. + end if + + ! return if assimilating daily obs and HH12 is false + + if (trim(this_obs_param%descr) == 'CYGNSS_SM_daily' .and. .not. HH12) return + ! cygnss sm subdaily observations are for 4 timeslices per day - 00-06, 06-12, 12-18, 18-24 UTC ! we will assimilate these at 03, 09, 15, 21 UTC + + HHcnt = 0 + + if (date_time_low%hour < 3 .and. date_time_up%hour >= 3) then + HH03 = .true. + HHcnt = HHcnt + 1 + end if + if (date_time_low%hour > 21 .and. date_time_up%hour >= 3) then ! wrap-around from previous day + HH03 = .true. + HHcnt = HHcnt + 1 + end if + if (date_time_low%hour < 9 .and. date_time_up%hour >= 9) then + HH09 = .true. + HHcnt = HHcnt + 1 + end if + if (date_time_low%hour < 15 .and. date_time_up%hour >= 15) then + HH15 = .true. + HHcnt = HHcnt + 1 + end if + if (date_time_low%hour < 21 .and. date_time_up%hour >= 21) then + HH21 = .true. + HHcnt = HHcnt + 1 + end if + + ! return if assimilating subdaily obs and no HH is true + + if (trim(this_obs_param%descr) == 'CYGNSS_SM' .and. .not. (HH03 .or. HH09 .or. HH15 .or. HH21)) return + + ! if assimilation window encompasses more than one time sllice, abort + + if (HHcnt > 1) then + err_msg = 'Can not assimilate subdaily CYGNSS obs from more than one time slice' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + end if + + ! determine filename for CYGNSS obs file + + write (YYYY,'(i4.4)') date_time%year + write (MM, '(i2.2)') date_time%month + write (DD, '(i2.2)') date_time%day + write (HH, '(i2.2)') date_time%hour + write (MI, '(i2.2)') date_time%min + + tmpname = trim(this_obs_param%name) + + ! Replace s20180801 with sYYYYMMDD + pos = index(tmpname, "s20180801") + if (pos > 0) then + tmpname = tmpname(1:pos-1) // "s" // YYYY // MM // DD // tmpname(pos+9:) + endif + + ! Replace e20180801 with eYYYYMMDD + pos = index(tmpname, "e20180801") + if (pos > 0) then + tmpname = tmpname(1:pos-1) // "e" // YYYY // MM // DD // tmpname(pos+9:) + endif + + tmpfname = trim(this_obs_param%path) // '/Y' // YYYY // '/M' // MM // '/' // trim(tmpname) // '.nc' + + if (logit) write (logunit, '(400A)') 'Reading CYGNSS soil moisture data from file: ', trim(tmpfname) + + ! Check if file exists + + inquire(file=tmpfname, exist=file_exists) + + if (.not. file_exists) then + err_msg = 'CYGNSS SM obs file not found!' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + end if + + ! Open the NetCDF observation file + ierr = nf90_open(trim(tmpfname), nf90_nowrite, ncid) + + ! get variable dimension IDs + ierr = nf90_inq_dimid(ncid, 'lon', lon_dimid) + ierr = nf90_inq_dimid(ncid, 'lat', lat_dimid) + ierr = nf90_inq_dimid(ncid, 'time', time_dimid) + ierr = nf90_inq_dimid(ncid, 'timeslices', timeslices_dimid) + ierr = nf90_inq_dimid(ncid, 'startstop', startstop_dimid) + + ! dimensions sizes + ierr = nf90_inquire_dimension(ncid, lon_dimid, len=N_lon) + ierr = nf90_inquire_dimension(ncid, lat_dimid, len=N_lat) + ierr = nf90_inquire_dimension(ncid, time_dimid, len=N_time) + ierr = nf90_inquire_dimension(ncid, timeslices_dimid, len=N_timeslices) + ierr = nf90_inquire_dimension(ncid, startstop_dimid, len=N_startstop) + + ! get variable IDs + ierr = nf90_inq_varid(ncid, 'SM_daily', sm_d_varid) + ierr = nf90_inq_varid(ncid, 'SM_subdaily', sm_subd_varid) + ierr = nf90_inq_varid(ncid, 'SIGMA_daily', sigma_d_varid) + ierr = nf90_inq_varid(ncid, 'SIGMA_subdaily', sigma_subd_varid) + ierr = nf90_inq_varid(ncid, 'timeintervals', timeintervals_varid) + ierr = nf90_inq_varid(ncid, 'latitude', lat_varid) + ierr = nf90_inq_varid(ncid, 'longitude', lon_varid) + + ! allocate memory for the variables + allocate(sm_d(N_lon, N_lat, N_time)) + allocate(sm_subd(N_lon, N_lat, N_timeslices)) + allocate(sigma_d(N_lon, N_lat, N_time)) + allocate(sigma_subd(N_lon, N_lat, N_timeslices)) + allocate(timeintervals(N_startstop, N_timeslices)) + allocate(latitudes(N_lon, N_lat)) + allocate(longitudes(N_lon, N_lat)) + + ! read the variables + ierr = nf90_get_var(ncid, sm_d_varid, sm_d) + if (ierr /= nf90_noerr) then + write(*,*) 'Error reading sm_d:', ierr + end if + ierr = nf90_get_var(ncid, sm_subd_varid, sm_subd) + if (ierr /= nf90_noerr) then + write(*,*) 'Error reading sm_subd:', ierr + end if + ierr = nf90_get_var(ncid, sigma_d_varid, sigma_d) + if (ierr /= nf90_noerr) then + write(*,*) 'Error reading sigma_d:', ierr + end if + ierr = nf90_get_var(ncid, sigma_subd_varid, sigma_subd) + if (ierr /= nf90_noerr) then + write(*,*) 'Error reading sigma_subd:', ierr + end if + ierr = nf90_get_var(ncid, timeintervals_varid, timeintervals) + if (ierr /= nf90_noerr) then + write(*,*) 'Error reading timeintervals:', ierr + end if + ierr = nf90_get_var(ncid, lat_varid, latitudes) + if (ierr /= nf90_noerr) then + write(*,*) 'Error reading latitudes:', ierr + end if + ierr = nf90_get_var(ncid, lon_varid, longitudes) + if (ierr /= nf90_noerr) then + write(*,*) 'Error reading longitudes:', ierr + end if + + ! close the file + ierr = nf90_close(ncid) - write (logunit,*) 'This is where we will read CYGNSS obs at YY:', date_time%year, ' DD:', date_time%day, ' HH:', date_time%hour + write (logunit,*) 'This is where we will read CYGNSS obs at YY:', date_time%year, ' DD:', date_time%day, ' HH:', date_time%hour - return + return end subroutine read_obs_sm_CYGNSS From f3b15a0a7cb9369d1ef5dcc65ef4b3560bd45d65 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Fri, 10 Jan 2025 18:56:20 -0700 Subject: [PATCH 050/107] read mask and fill temp arrays --- .../clsm_ensupd_read_obs.F90 | 182 +++++++++++++++--- 1 file changed, 150 insertions(+), 32 deletions(-) diff --git a/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index f664ce36..2721b024 100644 --- a/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -2194,31 +2194,36 @@ subroutine read_obs_sm_CYGNSS( & ! ------------------------------------------------------------------- ! local variables: - integer, parameter :: max_obs = 100000 ! max number of obs read by subroutine (expecting < 6 hr assim window) - character(4), parameter :: J2000_epoch_id = 'TT12' ! see date_time_util.F90 + integer, parameter :: max_obs = 50000 ! max number of obs read by subroutine (expecting < 6 hr assim window) + character(4), parameter :: J2000_epoch_id = 'TT12' ! see date_time_util.F90 character(len=*), parameter :: Iam = 'read_obs_sm_CYGNSS' type(date_time_type) :: date_time_obs_beg, date_time_obs_end type(date_time_type) :: date_time_up, date_time_low character(400) :: err_msg - character(300) :: tmpfname, tmpname + character(300) :: tmpfname, tmpname, tmpmaskname character( 2) :: MM, DD, HH, MI character( 4) :: YYYY integer :: pos, i, idx, N_obs, j, HHcnt integer :: ierr, ncid - integer :: lon_dimid, lat_dimid, time_dimid, timeslices_dimid, startstop_dimid + integer :: lon_dimid, lat_dimid, time_dimid, timeslices_dimid, startstop_dimid, lon_dimid_m, lat_dimid_m integer :: sm_d_varid, sm_subd_varid, sigma_d_varid, sigma_subd_varid, timeintervals_varid, lat_varid, lon_varid - integer :: N_lon, N_lat, N_time, N_timeslices, N_startstop + integer :: N_lon, N_lat, N_time, N_timeslices, N_startstop, N_lon_m, N_lat_m + integer :: longitudes_m_varid, latitudes_m_varid, small_SM_range_varid, poor_SMAP_varid, high_ubrmsd_varid, few_obs_varid, low_signal_varid + integer, allocatable :: small_SM_range_flag(:,:), poor_SMAP_flag(:,:), high_ubrmsd_flag(:,:), few_obs_flag(:,:), low_signal_flag(:,:) logical :: file_exists logical :: HH03, HH09, HH12, HH15, HH21 - real, dimension(:), pointer :: tmp_lon(:), tmp_lat(:), tmp_obs(:), tmp_err(:), tmp_time(:) + real, dimension(:), pointer :: tmp_lon(:), tmp_lat(:), tmp_obs(:), tmp_err(:), tmp_time(:) real, allocatable :: sm_d(:,:,:), sm_subd(:,:,:), sigma_d(:,:,:), sigma_subd(:,:,:) - real, allocatable :: timeintervals(:,:), latitudes(:,:), longitudes(:,:) + real, allocatable :: timeintervals(:,:), latitudes(:,:), longitudes(:,:), tmp_sm(:,:), tmp_sigma(:,:) + real, allocatable :: time(:), timeslices(:,:) + real, allocatable :: latitudes_m(:,:), longitudes_m(:,:) + real :: tmp1_lon(max_obs), tmp1_lat(max_obs), tmp1_obs(max_obs), tmp1_err(max_obs), tmp1_time(max_obs) ! ------------------------------------------------------------------- @@ -2373,39 +2378,152 @@ subroutine read_obs_sm_CYGNSS( & allocate(timeintervals(N_startstop, N_timeslices)) allocate(latitudes(N_lon, N_lat)) allocate(longitudes(N_lon, N_lat)) + allocate(tmp_sm(N_lon, N_lat)) + allocate(tmp_sigma(N_lon, N_lat)) ! read the variables - ierr = nf90_get_var(ncid, sm_d_varid, sm_d) - if (ierr /= nf90_noerr) then - write(*,*) 'Error reading sm_d:', ierr - end if - ierr = nf90_get_var(ncid, sm_subd_varid, sm_subd) - if (ierr /= nf90_noerr) then - write(*,*) 'Error reading sm_subd:', ierr - end if - ierr = nf90_get_var(ncid, sigma_d_varid, sigma_d) - if (ierr /= nf90_noerr) then - write(*,*) 'Error reading sigma_d:', ierr - end if - ierr = nf90_get_var(ncid, sigma_subd_varid, sigma_subd) - if (ierr /= nf90_noerr) then - write(*,*) 'Error reading sigma_subd:', ierr - end if ierr = nf90_get_var(ncid, timeintervals_varid, timeintervals) - if (ierr /= nf90_noerr) then - write(*,*) 'Error reading timeintervals:', ierr - end if ierr = nf90_get_var(ncid, lat_varid, latitudes) - if (ierr /= nf90_noerr) then - write(*,*) 'Error reading latitudes:', ierr - end if ierr = nf90_get_var(ncid, lon_varid, longitudes) - if (ierr /= nf90_noerr) then - write(*,*) 'Error reading longitudes:', ierr + + ! read either subdaily or daily soil moisture and sigma variables + if (this_obs_param%descr == 'CYGNSS_SM' ) then + + ! subdaily observations required + ierr = nf90_get_var(ncid, sm_subd_varid, sm_subd) + ierr = nf90_get_var(ncid, sigma_subd_varid, sigma_subd) + + ! find the time slice that corresponds to the assimilation window + idx = -1 + do i = 1, N_timeslices + if ((date_time%hour == 3 .and. timeintervals(1,i) == 0.0) .or. & + (date_time%hour == 9 .and. timeintervals(1,i) == 0.25) .or. & + (date_time%hour == 15 .and. timeintervals(1,i) == 0.5) .or. & + (date_time%hour == 21 .and. timeintervals(1,i) == 0.75)) then + idx = i + exit + end if + end do + if (idx == -1) then + err_msg = 'Error: No matching time interval found for HH = ' // HH + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + else + write(*,*) 'Index of matching time interval: ', idx + end if + tmp_sm = sm_subd(:,:,idx) + tmp_sigma = sigma_subd(:,:,idx) + else + + ! daily observations required + ierr = nf90_get_var(ncid, sm_d_varid, sm_d) + ierr = nf90_get_var(ncid, sigma_d_varid, sigma_d) + tmp_sm = sm_d(:,:,1) + tmp_sigma = sigma_d(:,:,1) end if - ! close the file + ! close the obs file ierr = nf90_close(ncid) + + ! get name for CYGNSS mask file + + tmpmaskname = trim(this_obs_param%maskpath) // '/' // trim(this_obs_param%maskname) // '.nc' + + inquire(file=tmpfname, exist=file_exists) + + if (.not. file_exists) then + err_msg = 'CYGNSS mask file not found!' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + end if + + ! open the CYGNSS mask file + + ierr = nf90_open(trim(tmpmaskname), nf90_nowrite, ncid) + + ! get variable dimension IDs + ierr = nf90_inq_dimid(ncid, 'lon', lon_dimid) + ierr = nf90_inq_dimid(ncid, 'lat', lat_dimid) + + ! dimensions sizes + ierr = nf90_inquire_dimension(ncid, lon_dimid, len=N_lon_m) + ierr = nf90_inquire_dimension(ncid, lat_dimid, len=N_lat_m) + + ! get variable IDs + ierr = nf90_inq_varid(ncid, 'longitude', longitudes_m_varid) + ierr = nf90_inq_varid(ncid, 'latitude', latitudes_m_varid) + ierr = nf90_inq_varid(ncid, 'flag_small_SM_range', small_SM_range_varid) + ierr = nf90_inq_varid(ncid, 'flag_poor_SMAP', poor_SMAP_varid) + ierr = nf90_inq_varid(ncid, 'flag_high_ubrmsd', high_ubrmsd_varid) + ierr = nf90_inq_varid(ncid, 'flag_few_obs', few_obs_varid) + ierr = nf90_inq_varid(ncid, 'flag_low_signal', low_signal_varid) + + + ! allocate memory for the variables + allocate(latitudes_m(N_lon_m, N_lat_m)) + allocate(longitudes_m(N_lon_m, N_lat_m)) + allocate(small_SM_range_flag(N_lon_m, N_lat_m)) + allocate(poor_SMAP_flag(N_lon_m, N_lat_m)) + allocate(high_ubrmsd_flag(N_lon_m, N_lat_m)) + allocate(few_obs_flag(N_lon_m, N_lat_m)) + allocate(low_signal_flag(N_lon_m, N_lat_m)) + + ! read the variables + ierr = nf90_get_var(ncid, latitudes_m_varid, latitudes_m) + ierr = nf90_get_var(ncid, longitudes_m_varid, longitudes_m) + ierr = nf90_get_var(ncid, small_SM_range_varid, small_SM_range_flag) + ierr = nf90_get_var(ncid, poor_SMAP_varid, poor_SMAP_flag) + ierr = nf90_get_var(ncid, high_ubrmsd_varid, high_ubrmsd_flag) + ierr = nf90_get_var(ncid, few_obs_varid, few_obs_flag) + ierr = nf90_get_var(ncid, low_signal_varid, low_signal_flag) + + ! close the mask file + ierr = nf90_close(ncid) + + ! check the obs data and mask data are the same resolution + if (N_lon /= N_lon_m .or. N_lat /= N_lat_m) then + err_msg = 'The mask file ' // trim(this_obs_param%maskname) // ' does not match the obs resolution' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + end if + + ! fill tmp arrays + N_obs = 0 + + do i = 1, N_lon + do j = 1, N_lat + if (tmp_sm(i,j) .ne. this_obs_param%nodata .and. & + small_SM_range_flag(i,j) .ne. 1 .and. & + poor_SMAP_flag(i,j) .ne. 1 .and. & + high_ubrmsd_flag(i,j) .ne. 1 .and. & + few_obs_flag(i,j) .ne. 1 .and. & + low_signal_flag(i,j) .ne. 1 ) then + + ! valid observation + 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 + tmp1_lon(N_obs) = longitudes(i,j) + tmp1_lat(N_obs) = latitudes(i,j) + tmp1_obs(N_obs) = tmp_sm(i,j) + tmp1_err(N_obs) = tmp_sigma(i,j) + tmp1_time(N_obs) = date_time%year + end if + end do + end do + + write(*,*) 'Number of observations: ', N_obs + + allocate(tmp_lon(N_obs)) + allocate(tmp_lat(N_obs)) + allocate(tmp_obs(N_obs)) + allocate(tmp_err(N_obs)) + allocate(tmp_time(N_obs)) + + tmp_lon = tmp1_lon(1:N_obs) + tmp_lat = tmp1_lat(1:N_obs) + tmp_obs = tmp1_obs(1:N_obs) + tmp_err = tmp1_err(1:N_obs) + tmp_time = tmp1_time(1:N_obs) write (logunit,*) 'This is where we will read CYGNSS obs at YY:', date_time%year, ' DD:', date_time%day, ' HH:', date_time%hour From 3f9a03ceb36dd55bbdf041aac3de9b7b6084c83c Mon Sep 17 00:00:00 2001 From: amfox37 Date: Mon, 13 Jan 2025 11:51:31 -0700 Subject: [PATCH 051/107] add CYGNSS_SM_daily --- .../clsm_ensupd_glob_param.F90 | 2 +- GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml | 40 +++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/GEOSlandassim_GridComp/clsm_ensupd_glob_param.F90 b/GEOSlandassim_GridComp/clsm_ensupd_glob_param.F90 index 6d1ef60f..aebfb3e1 100644 --- a/GEOSlandassim_GridComp/clsm_ensupd_glob_param.F90 +++ b/GEOSlandassim_GridComp/clsm_ensupd_glob_param.F90 @@ -48,7 +48,7 @@ module clsm_ensupd_glob_param ! 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 = 54 + integer, parameter :: N_obs_species_nml = 55 ! ---------------------------------------------------------------------- ! diff --git a/GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml b/GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml index 3724d023..c6ac56bb 100644 --- a/GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml +++ b/GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml @@ -2402,8 +2402,48 @@ obs_param_nml(54)%xcorr = 0.25 obs_param_nml(54)%ycorr = 0.25 obs_param_nml(54)%adapt = 0 +! -------------------------------------------------------------------------------------------------------------- +! +! 55 = CYGNSS_SM_daily (CYGNSS Level 3 soil moisture version 3.2) +! +! https://podaac.jpl.nasa.gov/dataset/CYGNSS_L3_SOIL_MOISTURE_V3.2 + +obs_param_nml(55)%descr = 'CYGNSS_SM_daily' +obs_param_nml(55)%orbit = 3 +obs_param_nml(55)%pol = 0 +obs_param_nml(55)%N_ang = 0 +obs_param_nml(55)%freq = 0 +obs_param_nml(55)%FOV = 20. +obs_param_nml(55)%FOV_units = 'km' +obs_param_nml(55)%assim = .false. +obs_param_nml(55)%scale = .false. +obs_param_nml(55)%getinnov = .false. +obs_param_nml(55)%RTM_ID = 0 +obs_param_nml(55)%bias_Npar = 0 +obs_param_nml(55)%bias_trel = 864000 +obs_param_nml(55)%bias_tcut = 432000 +obs_param_nml(55)%nodata = -9999. +obs_param_nml(55)%varname = 'sfmc' +obs_param_nml(55)%units = 'cm3 cm-3' +obs_param_nml(55)%path = '/discover/nobackup/amfox/CYGNSS_obs/' +obs_param_nml(55)%name = '' +obs_param_nml(55)%maskpath = '' +obs_param_nml(55)%maskname = '' +obs_param_nml(55)%scalepath = '' +obs_param_nml(55)%scalename = '' +obs_param_nml(55)%flistpath = '' +obs_param_nml(55)%flistname = '' +obs_param_nml(55)%errstd = 9. +obs_param_nml(55)%std_normal_max = 2.5 +obs_param_nml(55)%zeromean = .true. +obs_param_nml(55)%coarsen_pert = .false. +obs_param_nml(55)%xcorr = 0.25 +obs_param_nml(55)%ycorr = 0.25 +obs_param_nml(55)%adapt = 0 + ! -------------------------------------------------------------------- + / ! =========================== EOF ======================================= From caf2d253d6560dec2a4baed6516374ae94cf5435 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Mon, 13 Jan 2025 16:54:17 -0700 Subject: [PATCH 052/107] tile space --- .../clsm_ensupd_read_obs.F90 | 146 +++++++++++++++--- 1 file changed, 126 insertions(+), 20 deletions(-) diff --git a/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 2721b024..c5dbb1be 100644 --- a/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -2206,31 +2206,33 @@ subroutine read_obs_sm_CYGNSS( & character( 2) :: MM, DD, HH, MI character( 4) :: YYYY - integer :: pos, i, idx, N_obs, j, HHcnt + integer :: pos, i, idx, N_obs, j, HHcnt, ind, ii integer :: ierr, ncid integer :: lon_dimid, lat_dimid, time_dimid, timeslices_dimid, startstop_dimid, lon_dimid_m, lat_dimid_m integer :: sm_d_varid, sm_subd_varid, sigma_d_varid, sigma_subd_varid, timeintervals_varid, lat_varid, lon_varid integer :: N_lon, N_lat, N_time, N_timeslices, N_startstop, N_lon_m, N_lat_m integer :: longitudes_m_varid, latitudes_m_varid, small_SM_range_varid, poor_SMAP_varid, high_ubrmsd_varid, few_obs_varid, low_signal_varid - integer, allocatable :: small_SM_range_flag(:,:), poor_SMAP_flag(:,:), high_ubrmsd_flag(:,:), few_obs_flag(:,:), low_signal_flag(:,:) + integer, allocatable :: small_SM_range_flag(:,:), poor_SMAP_flag(:,:), high_ubrmsd_flag(:,:), few_obs_flag(:,:), low_signal_flag(:,:) logical :: file_exists logical :: HH03, HH09, HH12, HH15, HH21 - real, dimension(:), pointer :: tmp_lon(:), tmp_lat(:), tmp_obs(:), tmp_err(:), tmp_time(:) - + real, dimension(:), pointer :: tmp_lon(:), tmp_lat(:), tmp_obs(:), tmp_err(:), tmp_jtime(:) + integer, dimension(:), pointer :: tmp_tile_num + integer, dimension(N_catd) :: N_obs_in_tile + real, allocatable :: sm_d(:,:,:), sm_subd(:,:,:), sigma_d(:,:,:), sigma_subd(:,:,:) real, allocatable :: timeintervals(:,:), latitudes(:,:), longitudes(:,:), tmp_sm(:,:), tmp_sigma(:,:) real, allocatable :: time(:), timeslices(:,:) real, allocatable :: latitudes_m(:,:), longitudes_m(:,:) - real :: tmp1_lon(max_obs), tmp1_lat(max_obs), tmp1_obs(max_obs), tmp1_err(max_obs), tmp1_time(max_obs) + real :: tmp1_lon(max_obs), tmp1_lat(max_obs), tmp1_obs(max_obs), tmp1_err(max_obs), tmp1_jtime(max_obs) ! ------------------------------------------------------------------- ! initialize - nullify( tmp_lon, tmp_lat, tmp_obs, tmp_err, tmp_time ) + nullify( tmp_lon, tmp_lat, tmp_obs, tmp_err, tmp_jtime ) found_obs = .false. HH03 = .false. @@ -2502,32 +2504,136 @@ subroutine read_obs_sm_CYGNSS( & 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 - tmp1_lon(N_obs) = longitudes(i,j) - tmp1_lat(N_obs) = latitudes(i,j) - tmp1_obs(N_obs) = tmp_sm(i,j) - tmp1_err(N_obs) = tmp_sigma(i,j) - tmp1_time(N_obs) = date_time%year + tmp1_lon( N_obs) = longitudes(i,j) + tmp1_lat( N_obs) = latitudes(i,j) + tmp1_obs( N_obs) = tmp_sm(i,j) + tmp1_err( N_obs) = tmp_sigma(i,j) + tmp1_jtime(N_obs) = datetime_to_J2000seconds( date_time, J2000_epoch_id ) end if end do end do - write(*,*) 'Number of observations: ', N_obs + if (logit) then + + write (logunit,*) 'read_obs_sm_CYGNSS: read ', N_obs, ' at date_time = ', date_time, ' from: ', tmpfname + write (logunit,*) '----------' + write (logunit,*) 'max(obs)=',maxval(tmp1_obs(1:N_obs)), ', min(obs)=',minval(tmp1_obs(1:N_obs)), & + ', avg(obs)=',sum(tmp1_obs(1:N_obs))/N_obs + + end if allocate(tmp_lon(N_obs)) allocate(tmp_lat(N_obs)) allocate(tmp_obs(N_obs)) allocate(tmp_err(N_obs)) - allocate(tmp_time(N_obs)) + allocate(tmp_jtime(N_obs)) + + tmp_lon = tmp1_lon(1:N_obs) + tmp_lat = tmp1_lat(1:N_obs) + tmp_obs = tmp1_obs(1:N_obs) + tmp_err = tmp1_err(1:N_obs) + tmp_jtime = tmp1_jtime(1:N_obs) + + ! ---------------------------------------------------------------- + ! + ! 2.) for each observation + ! a) determine grid cell that contains lat/lon + ! b) determine tile within grid cell that contains lat/lon + + if (N_obs>0) then + + allocate(tmp_tile_num(N_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_obs, 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) + + CYGNSS_sm = 0. + CYGNSS_lon = 0. + CYGNSS_lat = 0. + CYGNSS_time = 0.0D0 + + N_obs_in_tile = 0 + + do ii=1,N_obs + + ind = tmp_tile_num(ii) ! 1<=tmp_tile_num<=N_catd (unless nodata) + + if (ind>0) then ! this step eliminates obs outside domain + + CYGNSS_sm( ind) = CYGNSS_sm( ind) + tmp_obs( ii) + CYGNSS_lon( ind) = CYGNSS_lon( ind) + tmp_lon( ii) + CYGNSS_lat( ind) = CYGNSS_lat( ind) + tmp_lat( ii) + CYGNSS_time(ind) = CYGNSS_time(ind) + tmp_jtime(ii) + + N_obs_in_tile(ind) = N_obs_in_tile(ind) + 1 + + end if + + end do - tmp_lon = tmp1_lon(1:N_obs) - tmp_lat = tmp1_lat(1:N_obs) - tmp_obs = tmp1_obs(1:N_obs) - tmp_err = tmp1_err(1:N_obs) - tmp_time = tmp1_time(1:N_obs) + ! normalize and set obs error std-dev + + do ii=1,N_catd - write (logunit,*) 'This is where we will read CYGNSS obs at YY:', date_time%year, ' DD:', date_time%day, ' HH:', date_time%hour + ! set observation error standard deviation + + CYGNSS_sm_std(ii) = this_obs_param%errstd/100. ! change units from percent (0-100) to fraction (0-1) + + ! normalize - return + if (N_obs_in_tile(ii)>1) then + + CYGNSS_sm( ii) = CYGNSS_sm( ii)/real(N_obs_in_tile(ii)) + CYGNSS_lon( ii) = CYGNSS_lon( ii)/real(N_obs_in_tile(ii)) + CYGNSS_lat( ii) = CYGNSS_lat( ii)/real(N_obs_in_tile(ii)) + CYGNSS_time( ii) = CYGNSS_time(ii)/real(N_obs_in_tile(ii),kind(0.0D0)) + + elseif (N_obs_in_tile(ii)==0) then + + CYGNSS_sm( ii) = this_obs_param%nodata + CYGNSS_lon( ii) = this_obs_param%nodata + CYGNSS_lat( ii) = this_obs_param%nodata + CYGNSS_time( ii) = real(this_obs_param%nodata,kind(0.0D0)) + CYGNSS_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) + + 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) + if (associated(tmp_jtime)) deallocate(tmp_jtime) end subroutine read_obs_sm_CYGNSS From 2085488be49d4348630b18a597287d3da39a230d Mon Sep 17 00:00:00 2001 From: amfox37 Date: Fri, 17 Jan 2025 15:09:25 -0700 Subject: [PATCH 053/107] comments and error units --- .../clsm_ensupd_read_obs.F90 | 44 ++++++++++++------- GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml | 4 +- 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index c5dbb1be..b0050a47 100644 --- a/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -1854,19 +1854,19 @@ subroutine read_obs_sm_ASCAT_EUMET( & ! 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) ! select date/time format with 4-digit year (YYYYMMDDHH) + 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) ! select date/time format with 4-digit year (YYYYMMDDHH) -! 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 ) + 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 -! call ufbint(lnbufr,tmp_vdata,14,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 @@ -1877,11 +1877,11 @@ subroutine read_obs_sm_ASCAT_EUMET( & tmp_data(N_obs,:) = tmp_vdata -! end do loop_report -! end do msg_report + end do loop_report + end do msg_report -! call closbf(lnbufr) -! close(lnbufr) + call closbf(lnbufr) + close(lnbufr) end do ! end file loop @@ -2148,7 +2148,7 @@ end subroutine read_obs_sm_ASCAT_EUMET ! **************************************************************************** - subroutine read_obs_sm_CYGNSS( & + subroutine read_obs_sm_CYGNSS( & date_time, dtstep_assim, N_catd, tile_coord, & tile_grid_d, N_tile_in_cell_ij, tile_num_in_cell_ij, & this_obs_param, & @@ -2156,7 +2156,17 @@ subroutine read_obs_sm_CYGNSS( & !--------------------------------------------------------------------- ! - ! Routine to read in CYGNSS soil moisture obs from netCDF files. + ! Routine to read in CYGNSS soil moisture obs from netCDF files and apply mask. + ! https://podaac.jpl.nasa.gov/dataset/CYGNSS_L3_SOIL_MOISTURE_V3.2 + ! CYGNSS soil moisture obs are in volumetric units (cm3 cm-3) with a spatial + ! resolution of 0.3 Decimal Degrees x 0.37 Decimal Degrees. + ! They are daily files countaining daily (obs_param_nml(54)%descr = CYGNSS_SM_daily) + ! and subdaily SM estimates (obs_param_nml(53)%descr = CYGNSS_SM). The + ! subdaily values are for 6 hr time intervals, 0-6hr, 6-12hr, 12-18hr, 18-24hr. + ! The subdaily values are assimilated at 3z, 9z, 15z, 21z. If the assimilation + ! window is more than 6 hr the code will error out. The daily values are assimilated + ! at 12z. The assumption is that either the daily or subdaily values are assimilated, + ! but the code will assimilate both if in the nml. ! ! A. Fox, Jan 2025 ! @@ -2536,7 +2546,7 @@ subroutine read_obs_sm_CYGNSS( & ! ---------------------------------------------------------------- ! - ! 2.) for each observation + ! for each observation ! a) determine grid cell that contains lat/lon ! b) determine tile within grid cell that contains lat/lon @@ -2552,7 +2562,7 @@ subroutine read_obs_sm_CYGNSS( & ! ---------------------------------------------------------------- ! - ! 3.) compute super-obs for each tile from all obs w/in that tile + ! compute super-obs for each tile from all obs w/in that tile ! (also eliminate observations that are not in domain) CYGNSS_sm = 0. @@ -2585,7 +2595,7 @@ subroutine read_obs_sm_CYGNSS( & ! set observation error standard deviation - CYGNSS_sm_std(ii) = this_obs_param%errstd/100. ! change units from percent (0-100) to fraction (0-1) + CYGNSS_sm_std(ii) = this_obs_param%errstd ! fraction units (cm3 cm-3) ! normalize diff --git a/GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml b/GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml index c6ac56bb..d42301db 100644 --- a/GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml +++ b/GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml @@ -2394,7 +2394,7 @@ 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 = 9. +obs_param_nml(54)%errstd = 0.1 obs_param_nml(54)%std_normal_max = 2.5 obs_param_nml(54)%zeromean = .true. obs_param_nml(54)%coarsen_pert = .false. @@ -2433,7 +2433,7 @@ obs_param_nml(55)%scalepath = '' obs_param_nml(55)%scalename = '' obs_param_nml(55)%flistpath = '' obs_param_nml(55)%flistname = '' -obs_param_nml(55)%errstd = 9. +obs_param_nml(55)%errstd = 0.1 obs_param_nml(55)%std_normal_max = 2.5 obs_param_nml(55)%zeromean = .true. obs_param_nml(55)%coarsen_pert = .false. From cb49cb0b81ba65591d5009432fd25a84f44990a1 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Fri, 17 Jan 2025 15:16:48 -0700 Subject: [PATCH 054/107] todo: scaling --- GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index b0050a47..9421b7c4 100644 --- a/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -9149,9 +9149,7 @@ subroutine read_obs( & scaled_obs = .true. - 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 ) + ! TODO: implement scaling for CYGNSS obs end if From 9ca0f0f4eff79f3731148ce8660a20dea4430cb8 Mon Sep 17 00:00:00 2001 From: Rolf Reichle <54944691+gmao-rreichle@users.noreply.github.com> Date: Mon, 20 Jan 2025 13:20:52 -0500 Subject: [PATCH 055/107] Fixed typos and alignment in new CYGNSS soil moisture obs reader (clsm_ensupd_read_obs.F90) --- .../clsm_ensupd_read_obs.F90 | 85 ++++++++++--------- 1 file changed, 44 insertions(+), 41 deletions(-) diff --git a/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 9421b7c4..97fbd59a 100644 --- a/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -2158,10 +2158,10 @@ subroutine read_obs_sm_CYGNSS( & ! ! Routine to read in CYGNSS soil moisture obs from netCDF files and apply mask. ! https://podaac.jpl.nasa.gov/dataset/CYGNSS_L3_SOIL_MOISTURE_V3.2 - ! CYGNSS soil moisture obs are in volumetric units (cm3 cm-3) with a spatial + ! CYGNSS soil moisture obs are in volumetric units (m3 m-3) with a spatial ! resolution of 0.3 Decimal Degrees x 0.37 Decimal Degrees. - ! They are daily files countaining daily (obs_param_nml(54)%descr = CYGNSS_SM_daily) - ! and subdaily SM estimates (obs_param_nml(53)%descr = CYGNSS_SM). The + ! They are daily files containing daily (obs_param_nml(.)%descr = CYGNSS_SM_daily) + ! and subdaily SM estimates (obs_param_nml(.)%descr = CYGNSS_SM). The ! subdaily values are for 6 hr time intervals, 0-6hr, 6-12hr, 12-18hr, 18-24hr. ! The subdaily values are assimilated at 3z, 9z, 15z, 21z. If the assimilation ! window is more than 6 hr the code will error out. The daily values are assimilated @@ -2245,6 +2245,7 @@ subroutine read_obs_sm_CYGNSS( & nullify( tmp_lon, tmp_lat, tmp_obs, tmp_err, tmp_jtime ) found_obs = .false. + HH03 = .false. HH09 = .false. HH12 = .false. @@ -2314,7 +2315,7 @@ subroutine read_obs_sm_CYGNSS( & if (trim(this_obs_param%descr) == 'CYGNSS_SM' .and. .not. (HH03 .or. HH09 .or. HH15 .or. HH21)) return - ! if assimilation window encompasses more than one time sllice, abort + ! if assimilation window encompasses more than one time slice, abort if (HHcnt > 1) then err_msg = 'Can not assimilate subdaily CYGNSS obs from more than one time slice' @@ -2383,15 +2384,15 @@ subroutine read_obs_sm_CYGNSS( & ierr = nf90_inq_varid(ncid, 'longitude', lon_varid) ! allocate memory for the variables - allocate(sm_d(N_lon, N_lat, N_time)) - allocate(sm_subd(N_lon, N_lat, N_timeslices)) - allocate(sigma_d(N_lon, N_lat, N_time)) - allocate(sigma_subd(N_lon, N_lat, N_timeslices)) - allocate(timeintervals(N_startstop, N_timeslices)) - allocate(latitudes(N_lon, N_lat)) - allocate(longitudes(N_lon, N_lat)) - allocate(tmp_sm(N_lon, N_lat)) - allocate(tmp_sigma(N_lon, N_lat)) + allocate(sm_d( N_lon, N_lat, N_time )) + allocate(sm_subd( N_lon, N_lat, N_timeslices )) + allocate(sigma_d( N_lon, N_lat, N_time )) + allocate(sigma_subd( N_lon, N_lat, N_timeslices )) + allocate(timeintervals(N_startstop, N_timeslices )) + allocate(latitudes( N_lon, N_lat )) + allocate(longitudes( N_lon, N_lat )) + allocate(tmp_sm( N_lon, N_lat )) + allocate(tmp_sigma( N_lon, N_lat )) ! read the variables ierr = nf90_get_var(ncid, timeintervals_varid, timeintervals) @@ -2399,19 +2400,19 @@ subroutine read_obs_sm_CYGNSS( & ierr = nf90_get_var(ncid, lon_varid, longitudes) ! read either subdaily or daily soil moisture and sigma variables - if (this_obs_param%descr == 'CYGNSS_SM' ) then + if ( trim(this_obs_param%descr) == 'CYGNSS_SM' ) then ! subdaily observations required - ierr = nf90_get_var(ncid, sm_subd_varid, sm_subd) + ierr = nf90_get_var(ncid, sm_subd_varid, sm_subd) ierr = nf90_get_var(ncid, sigma_subd_varid, sigma_subd) ! find the time slice that corresponds to the assimilation window idx = -1 do i = 1, N_timeslices - if ((date_time%hour == 3 .and. timeintervals(1,i) == 0.0) .or. & - (date_time%hour == 9 .and. timeintervals(1,i) == 0.25) .or. & - (date_time%hour == 15 .and. timeintervals(1,i) == 0.5) .or. & - (date_time%hour == 21 .and. timeintervals(1,i) == 0.75)) then + if ((date_time%hour == 3 .and. timeintervals(1,i) == 0.0 ) .or. & + (date_time%hour == 9 .and. timeintervals(1,i) == 0.25) .or. & + (date_time%hour == 15 .and. timeintervals(1,i) == 0.5 ) .or. & + (date_time%hour == 21 .and. timeintervals(1,i) == 0.75) ) then idx = i exit end if @@ -2422,15 +2423,17 @@ subroutine read_obs_sm_CYGNSS( & else write(*,*) 'Index of matching time interval: ', idx end if - tmp_sm = sm_subd(:,:,idx) + tmp_sm = sm_subd( :,:,idx) tmp_sigma = sigma_subd(:,:,idx) + else ! daily observations required - ierr = nf90_get_var(ncid, sm_d_varid, sm_d) + ierr = nf90_get_var(ncid, sm_d_varid, sm_d) ierr = nf90_get_var(ncid, sigma_d_varid, sigma_d) - tmp_sm = sm_d(:,:,1) + tmp_sm = sm_d( :,:,1) tmp_sigma = sigma_d(:,:,1) + end if ! close the obs file @@ -2470,13 +2473,13 @@ subroutine read_obs_sm_CYGNSS( & ! allocate memory for the variables - allocate(latitudes_m(N_lon_m, N_lat_m)) - allocate(longitudes_m(N_lon_m, N_lat_m)) + allocate(latitudes_m( N_lon_m, N_lat_m)) + allocate(longitudes_m( N_lon_m, N_lat_m)) allocate(small_SM_range_flag(N_lon_m, N_lat_m)) - allocate(poor_SMAP_flag(N_lon_m, N_lat_m)) - allocate(high_ubrmsd_flag(N_lon_m, N_lat_m)) - allocate(few_obs_flag(N_lon_m, N_lat_m)) - allocate(low_signal_flag(N_lon_m, N_lat_m)) + allocate(poor_SMAP_flag( N_lon_m, N_lat_m)) + allocate(high_ubrmsd_flag( N_lon_m, N_lat_m)) + allocate(few_obs_flag( N_lon_m, N_lat_m)) + allocate(low_signal_flag( N_lon_m, N_lat_m)) ! read the variables ierr = nf90_get_var(ncid, latitudes_m_varid, latitudes_m) @@ -2514,10 +2517,10 @@ subroutine read_obs_sm_CYGNSS( & 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 - tmp1_lon( N_obs) = longitudes(i,j) - tmp1_lat( N_obs) = latitudes(i,j) - tmp1_obs( N_obs) = tmp_sm(i,j) - tmp1_err( N_obs) = tmp_sigma(i,j) + tmp1_lon( N_obs) = longitudes(i,j) + tmp1_lat( N_obs) = latitudes( i,j) + tmp1_obs( N_obs) = tmp_sm( i,j) + tmp1_err( N_obs) = tmp_sigma( i,j) tmp1_jtime(N_obs) = datetime_to_J2000seconds( date_time, J2000_epoch_id ) end if end do @@ -2532,16 +2535,16 @@ subroutine read_obs_sm_CYGNSS( & end if - allocate(tmp_lon(N_obs)) - allocate(tmp_lat(N_obs)) - allocate(tmp_obs(N_obs)) - allocate(tmp_err(N_obs)) + allocate(tmp_lon( N_obs)) + allocate(tmp_lat( N_obs)) + allocate(tmp_obs( N_obs)) + allocate(tmp_err( N_obs)) allocate(tmp_jtime(N_obs)) - tmp_lon = tmp1_lon(1:N_obs) - tmp_lat = tmp1_lat(1:N_obs) - tmp_obs = tmp1_obs(1:N_obs) - tmp_err = tmp1_err(1:N_obs) + tmp_lon = tmp1_lon( 1:N_obs) + tmp_lat = tmp1_lat( 1:N_obs) + tmp_obs = tmp1_obs( 1:N_obs) + tmp_err = tmp1_err( 1:N_obs) tmp_jtime = tmp1_jtime(1:N_obs) ! ---------------------------------------------------------------- @@ -2595,7 +2598,7 @@ subroutine read_obs_sm_CYGNSS( & ! set observation error standard deviation - CYGNSS_sm_std(ii) = this_obs_param%errstd ! fraction units (cm3 cm-3) + CYGNSS_sm_std(ii) = this_obs_param%errstd ! volumetric units (m3 m-3) ! normalize From 95775040705d67b04be11bcb9a004765a2021e55 Mon Sep 17 00:00:00 2001 From: Rolf Reichle <54944691+gmao-rreichle@users.noreply.github.com> Date: Mon, 20 Jan 2025 13:51:22 -0500 Subject: [PATCH 056/107] Changed units of CYGNSS soil moisture obs to SI standard (LDASsa_DEFAULT_inputs_ensupd.nml) --- GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml b/GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml index d42301db..a4bfe27e 100644 --- a/GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml +++ b/GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml @@ -2385,7 +2385,7 @@ 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 = 'sfmc' -obs_param_nml(54)%units = 'cm3 cm-3' +obs_param_nml(54)%units = 'm3 m-3' obs_param_nml(54)%path = '/discover/nobackup/amfox/CYGNSS_obs/' obs_param_nml(54)%name = '' obs_param_nml(54)%maskpath = '' @@ -2424,7 +2424,7 @@ obs_param_nml(55)%bias_trel = 864000 obs_param_nml(55)%bias_tcut = 432000 obs_param_nml(55)%nodata = -9999. obs_param_nml(55)%varname = 'sfmc' -obs_param_nml(55)%units = 'cm3 cm-3' +obs_param_nml(55)%units = 'm3 m-3' obs_param_nml(55)%path = '/discover/nobackup/amfox/CYGNSS_obs/' obs_param_nml(55)%name = '' obs_param_nml(55)%maskpath = '' From dc679fe7a793e8492b8d1f796a704db9cfdb4b40 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Wed, 22 Jan 2025 17:58:15 -0500 Subject: [PATCH 057/107] additional edits towards using M21C surface met forcing (LDAS_Forcing.F90) --- CHANGELOG.md | 3 +- GEOSmetforce_GridComp/LDAS_Forcing.F90 | 309 +++++++++++++++++++++---- 2 files changed, 269 insertions(+), 43 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ab148b6..8f4ad3af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- New update_type for joint 3d soil moisture and 1d snow analysis (Tb+sfmc+sfds+SCF obs) +- New update_type for joint 3d soil moisture and 1d snow analysis (Tb+sfmc+sfds+SCF obs). +- Use M21C surface met forcing. ### Changed diff --git a/GEOSmetforce_GridComp/LDAS_Forcing.F90 b/GEOSmetforce_GridComp/LDAS_Forcing.F90 index f7fe8f4b..5c7bca72 100755 --- a/GEOSmetforce_GridComp/LDAS_Forcing.F90 +++ b/GEOSmetforce_GridComp/LDAS_Forcing.F90 @@ -3180,6 +3180,8 @@ subroutine get_GEOS( date_time, force_dtstep, met_path, met_tag, & character(40), dimension(N_MERRA2plusAerosol_vars, N_defs_cols) :: M2COR_defs character(40), dimension(N_M21C_vars, N_defs_cols) :: M21CINT_defs character(40), dimension(N_M21C_vars, N_defs_cols) :: M21CCOR_defs + character(40), dimension(N_M21C_vars, N_defs_cols) :: M21CCSINT_defs + character(40), dimension(N_M21C_vars, N_defs_cols) :: M21CCSCOR_defs character(40), dimension(:,:), allocatable :: GEOSgcm_defs @@ -3285,50 +3287,69 @@ subroutine get_GEOS( date_time, force_dtstep, met_path, met_tag, & ! (ie, the precip generated by the AGCM within the M21C system) ! ! NOTE: This is *NOT* the precipitation seen by the land surface in the M21C system. - ! -? ! NOTE: Use SWGDN from the "rad" Collection because SWGDN in MERRA-2 "lfo" -? ! is averaged over land tiles only, unlike all other variables, -? ! which are global, as is SWGDN in the FP "lfo" files. -? ! - reichle, 7 Dec 2015 - - M21CINT_defs( 1,:)=[character(len=40):: 'SWGDN ','tavg','tavg1_2d_rad_Nx','diag','F'] ! use "rad" Collection - M21CINT_defs( 2,:)=[character(len=40):: 'LWGAB ','tavg','tavg1_2d_lfo_Nx','diag','F'] - M21CINT_defs( 3,:)=[character(len=40):: 'PARDR ','tavg','tavg1_2d_lfo_Nx','diag','F'] - M21CINT_defs( 4,:)=[character(len=40):: 'PARDF ','tavg','tavg1_2d_lfo_Nx','diag','F'] - M21CINT_defs( 5,:)=[character(len=40):: 'PRECCU ','tavg','tavg1_2d_int_Nx','diag','F'] ! uncorrected - M21CINT_defs( 6,:)=[character(len=40):: 'PRECLS ','tavg','tavg1_2d_int_Nx','diag','F'] ! uncorrected - M21CINT_defs( 7,:)=[character(len=40):: 'PRECSN ','tavg','tavg1_2d_int_Nx','diag','F'] ! uncorrected - M21CINT_defs( 8,:)=[character(len=40):: 'PS ','inst','inst1_2d_lfo_Nx','diag','S'] - M21CINT_defs( 9,:)=[character(len=40):: 'HLML ','inst','inst1_2d_lfo_Nx','diag','S'] - M21CINT_defs(10,:)=[character(len=40):: 'TLML ','inst','inst1_2d_lfo_Nx','diag','S'] - M21CINT_defs(11,:)=[character(len=40):: 'QLML ','inst','inst1_2d_lfo_Nx','diag','S'] - M21CINT_defs(12,:)=[character(len=40):: 'SPEEDLML','inst','inst1_2d_lfo_Nx','diag','S'] - - ! MERRA-2 file specs with corrected precip, which could be either - ! - native (ie, the precip seen by the land surface in the MERRA-2 system), or - ! - corrected in post-processing using MERRA-2 (uncorrected) precip as the background - ! The default is to use MERRA-2 native precip corrections. If the "met_tag" includes + M21CINT_defs( 1,:)=[character(len=40):: 'SWGDN ', 'tavg','lfo_tavg_1hr_glo_L1152x721_slv', 'diag','F'] + M21CINT_defs( 2,:)=[character(len=40):: 'LWGAB ', 'tavg','lfo_tavg_1hr_glo_L1152x721_slv', 'diag','F'] + M21CINT_defs( 3,:)=[character(len=40):: 'PARDR ', 'tavg','lfo_tavg_1hr_glo_L1152x721_slv', 'diag','F'] + M21CINT_defs( 4,:)=[character(len=40):: 'PARDF ', 'tavg','lfo_tavg_1hr_glo_L1152x721_slv', 'diag','F'] + M21CINT_defs( 5,:)=[character(len=40):: 'PRECRAINCU', 'tavg','int_tavg_1hr_glo_L1152x721_slv', 'diag','F'] ! uncorrected + M21CINT_defs( 6,:)=[character(len=40):: 'PRECRAINLS', 'tavg','int_tavg_1hr_glo_L1152x721_slv', 'diag','F'] ! uncorrected + M21CINT_defs( 7,:)=[character(len=40):: 'PRECSNO ', 'tavg','int_tavg_1hr_glo_L1152x721_slv', 'diag','F'] ! uncorrected + M21CINT_defs( 8,:)=[character(len=40):: 'PS ', 'inst','lfo_inst_1hr_glo_L1152x721_slv', 'diag','S'] + M21CINT_defs( 9,:)=[character(len=40):: 'HLML ', 'inst','lfo_inst_1hr_glo_L1152x721_slv', 'diag','S'] + M21CINT_defs( 10,:)=[character(len=40):: 'TLML ', 'inst','lfo_inst_1hr_glo_L1152x721_slv', 'diag','S'] + M21CINT_defs( 11,:)=[character(len=40):: 'QLML ', 'inst','lfo_inst_1hr_glo_L1152x721_slv', 'diag','S'] + M21CINT_defs( 12,:)=[character(len=40):: 'SPEEDLML ', 'inst','lfo_inst_1hr_glo_L1152x721_slv', 'diag','S'] + + ! same but for cube-sphere lfo (only works when using matching c360 tile space for simulation) + + M21CCSINT_defs = M21CINT_defs + + M21CCSINT_defs( 1,3)=[character(len=40):: 'lfo_tavg_1hr_glo_C360x360x6_slv' ] + M21CCSINT_defs( 2,3)=[character(len=40):: 'lfo_tavg_1hr_glo_C360x360x6_slv' ] + M21CCSINT_defs( 3,3)=[character(len=40):: 'lfo_tavg_1hr_glo_C360x360x6_slv' ] + M21CCSINT_defs( 4,3)=[character(len=40):: 'lfo_tavg_1hr_glo_C360x360x6_slv' ] + M21CCSINT_defs( 5,3)=[character(len=40):: 'int_tavg_1hr_glo_C360x360x6_slv' ] ! uncorrected + M21CCSINT_defs( 6,3)=[character(len=40):: 'int_tavg_1hr_glo_C360x360x6_slv' ] ! uncorrected + M21CCSINT_defs( 7,3)=[character(len=40):: 'int_tavg_1hr_glo_C360x360x6_slv' ] ! uncorrected + M21CCSINT_defs( 8,3)=[character(len=40):: 'lfo_inst_1hr_glo_C360x360x6_slv' ] + M21CCSINT_defs( 9,3)=[character(len=40):: 'lfo_inst_1hr_glo_C360x360x6_slv' ] + M21CCSINT_defs(10,3)=[character(len=40):: 'lfo_inst_1hr_glo_C360x360x6_slv' ] + M21CCSINT_defs(11,3)=[character(len=40):: 'lfo_inst_1hr_glo_C360x360x6_slv' ] + M21CCSINT_defs(12,3)=[character(len=40):: 'lfo_inst_1hr_glo_C360x360x6_slv' ] + + ! M21C file specs with corrected precip, which could be either + ! - native (ie, the precip seen by the land surface in the M21C system), or + ! - corrected in post-processing using M21C (uncorrected) precip as the background + ! The default is to use M21C native precip corrections. If the "met_tag" includes ! an optional "__prec[xyz]" string, the precip corrections specified by [xyz] are used. ! - ! NOTE: This is *NOT* the same as the corrected precipitation of the off-line - ! spin-up run used to generate the MERRA-2 land surface initial conditions - ! for each stream. These precip files used for that have a MERRA background. - ! - ! NOTE: Use SWGDN from the "rad" Collection (see comment above). + ! NOTE: This is *NOT* the same as the corrected precipitation of the off-line + ! spin-up run used to generate the M21C land surface initial conditions + ! for each stream. These precip files used for that have a MERRA-2 background. + + M21CCOR_defs = M21CINT_defs + + M21CCOR_defs( 5,:)=[character(len=40):: 'PRECRAINCUCORR','tavg','lfo_tavg_1hr_glo_L1152x721_slv', 'diag','F'] ! M21C built-in corrections + M21CCOR_defs( 6,:)=[character(len=40):: 'PRECRAINLSCORR','tavg','lfo_tavg_1hr_glo_L1152x721_slv', 'diag','F'] ! M21C built-in corrections + M21CCOR_defs( 7,:)=[character(len=40):: 'PRECSNOCORR ','tavg','lfo_tavg_1hr_glo_L1152x721_slv', 'diag','F'] ! M21C built-in corrections + + ! same but for cube-sphere lfo (only works when using matching c360 tile space for simulation) - M21CCOR_defs( 1,:)=[character(len=40):: 'SWGDN ','tavg','tavg1_2d_rad_Nx','diag','F'] ! use "rad" Collection - M21CCOR_defs( 2,:)=[character(len=40):: 'LWGAB ','tavg','tavg1_2d_lfo_Nx','diag','F'] - M21CCOR_defs( 3,:)=[character(len=40):: 'PARDR ','tavg','tavg1_2d_lfo_Nx','diag','F'] - M21CCOR_defs( 4,:)=[character(len=40):: 'PARDF ','tavg','tavg1_2d_lfo_Nx','diag','F'] - M21CCOR_defs( 5,:)=[character(len=40):: 'PRECCUCORR ','tavg','tavg1_2d_lfo_Nx','diag','F'] ! MERRA-2 built-in corrections - M21CCOR_defs( 6,:)=[character(len=40):: 'PRECLSCORR ','tavg','tavg1_2d_lfo_Nx','diag','F'] ! MERRA-2 built-in corrections - M21CCOR_defs( 7,:)=[character(len=40):: 'PRECSNOCORR','tavg','tavg1_2d_lfo_Nx','diag','F'] ! MERRA-2 built-in corrections - M21CCOR_defs( 8,:)=[character(len=40):: 'PS ','inst','inst1_2d_lfo_Nx','diag','S'] - M21CCOR_defs( 9,:)=[character(len=40):: 'HLML ','inst','inst1_2d_lfo_Nx','diag','S'] - M21CCOR_defs(10,:)=[character(len=40):: 'TLML ','inst','inst1_2d_lfo_Nx','diag','S'] - M21CCOR_defs(11,:)=[character(len=40):: 'QLML ','inst','inst1_2d_lfo_Nx','diag','S'] - M21CCOR_defs(12,:)=[character(len=40):: 'SPEEDLML ','inst','inst1_2d_lfo_Nx','diag','S'] + M21CCSCOR_defs = M21CCOR_defs + + M21CCSCOR_defs( 1,3)=[character(len=40):: 'lfo_tavg_1hr_glo_C360x360x6_slv' ] + M21CCSCOR_defs( 2,3)=[character(len=40):: 'lfo_tavg_1hr_glo_C360x360x6_slv' ] + M21CCSCOR_defs( 3,3)=[character(len=40):: 'lfo_tavg_1hr_glo_C360x360x6_slv' ] + M21CCSCOR_defs( 4,3)=[character(len=40):: 'lfo_tavg_1hr_glo_C360x360x6_slv' ] + M21CCSCOR_defs( 5,3)=[character(len=40):: 'lfo_tavg_1hr_glo_C360x360x6_slv' ] ! M21C built-in corrections + M21CCSCOR_defs( 6,3)=[character(len=40):: 'lfo_tavg_1hr_glo_C360x360x6_slv' ] ! M21C built-in corrections + M21CCSCOR_defs( 7,3)=[character(len=40):: 'lfo_tavg_1hr_glo_C360x360x6_slv' ] ! M21C built-in corrections + M21CCSCOR_defs( 8,3)=[character(len=40):: 'lfo_inst_1hr_glo_C360x360x6_slv' ] + M21CCSCOR_defs( 9,3)=[character(len=40):: 'lfo_inst_1hr_glo_C360x360x6_slv' ] + M21CCSCOR_defs(10,3)=[character(len=40):: 'lfo_inst_1hr_glo_C360x360x6_slv' ] + M21CCSCOR_defs(11,3)=[character(len=40):: 'lfo_inst_1hr_glo_C360x360x6_slv' ] + M21CCSCOR_defs(12,3)=[character(len=40):: 'lfo_inst_1hr_glo_C360x360x6_slv' ] ! ----------------------------------------------------------------------- @@ -3614,6 +3635,47 @@ subroutine get_GEOS( date_time, force_dtstep, met_path, met_tag, & call parse_MERRA_met_tag( met_path, met_tag, date_time_bkwd, & met_path_bkwd, prec_path_bkwd, met_tag_bkwd, use_prec_corr ) + + elseif (met_tag(1:4)=='M21C') then ! M21C (must check M21C before MERRA-2 because MERRA2 uses "M2") + + N_GEOSgcm_vars = N_M21C_vars + + allocate(GEOSgcm_defs(N_GEOSgcm_vars,N_defs_cols)) + + if (met_tag(1:7)=='M21CINT') then + + GEOSgcm_defs(1:N_GEOSgcm_vars,:) = M21CINT_defs( 1:N_GEOSgcm_vars,:) + + elseif (met_tag(1:7)=='M21CCOR') then + + GEOSgcm_defs(1:N_GEOSgcm_vars,:) = M21CCOR_defs( 1:N_GEOSgcm_vars,:) + + elseif (met_tag(1:9)=='M21CCSINT') then + + GEOSgcm_defs(1:N_GEOSgcm_vars,:) = M21CCSINT_defs(1:N_GEOSgcm_vars,:) + + elseif (met_tag(1:9)=='M21CCSCOR') then + + GEOSgcm_defs(1:N_GEOSgcm_vars,:) = M21CCSCOR_defs(1:N_GEOSgcm_vars,:) + + else + + call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'unknown "M21C[xxx]" met_tag') + + end if + + daily_met_files = .false. ! might change to daily upon public distribution? + + call parse_M21C_met_tag( met_path, met_tag, date_time_inst, & + met_path_inst, prec_path_inst, met_tag_inst, use_prec_corr ) + + call parse_M21C_met_tag( met_path, met_tag, date_time_fwd, & + met_path_fwd, prec_path_fwd, met_tag_fwd, use_prec_corr ) + + call parse_M21C_met_tag( met_path, met_tag, date_time_bkwd, & + met_path_bkwd, prec_path_bkwd, met_tag_bkwd, use_prec_corr ) + + elseif (met_tag(1:2)=='M2') then ! MERRA-2 select case (AEROSOL_DEPOSITION) @@ -3660,6 +3722,7 @@ subroutine get_GEOS( date_time, force_dtstep, met_path, met_tag, & call parse_MERRA2_met_tag( met_path, met_tag, date_time_bkwd, & met_path_bkwd, prec_path_bkwd, met_tag_bkwd, use_prec_corr ) + else ! GEOS ADAS (FP) @@ -4689,6 +4752,161 @@ subroutine parse_MERRA2_met_tag( met_path_in, met_tag_in, date_time, & end subroutine parse_MERRA2_met_tag + ! **************************************************************** + + subroutine parse_M21C_met_tag( met_path_in, met_tag_in, date_time, & + met_path_default, met_path_prec, met_tag_out, use_prec_corr ) + + ! reichle, 15 Jan 2025 + + ! parse M21C "met_tag", extract M21C stream, assemble data paths + ! + ! met_tag = "M21C[CS][xxx]_[STREAM]{__prec[PREC]}" + ! + ! where {__prec[PREC]} is optional and where + ! + ! [xxx] = 'INT' or 'COR' + ! [CS] = cube-sphere forcing (optional; works only with matching c360 tile space for simulation) + ! [STREAM] = 'jan98', 'jan08', 'jan18', or 'cross' + ! [PREC] = indicates corrected precip dataset + ! + ! examples: + ! + ! STREAM = 'jan08' : use only Stream 2 M21C data + ! STREAM = 'cross' : integrate across more than one M21C stream + ! + ! --------------------------------------------------------------------------- + + implicit none + + character(*), intent(in) :: met_path_in + character(*), intent(in) :: met_tag_in + + type(date_time_type), intent(in) :: date_time + + character(200), intent(out) :: met_path_default, met_path_prec + character( 80), intent(out) :: met_tag_out + + logical, intent(out) :: use_prec_corr + + ! local variables + + integer :: is, tmpind + + type(date_time_type) :: dt1, dt2 + + character( 5) :: tmpstream + character(16) :: stream + character(80) :: prec_tag + + character(len=*), parameter :: Iam = 'parse_M21C_met_tag' + character(len=400) :: err_msg + + ! ---------------------------------------------------------- + + ! define intervals that determine which MERRA-2 stream is used + ! in integrations that "cross" multiple streams + ! + ! 1/1/1998 - 12/31/2007: e5303_m21c_jan98 (Stream 1) + ! 1/1/2008 - 12/31/2017: e5303_m21c_jan08 (Stream 2) + ! 1/1/2018 - present: e5303_m21c_jan18 (Stream 3) + + ! dates before dt1 use Stream 1 + + dt1%year = 2008 + dt1%month = 1 + dt1%day = 1 + dt1%hour = 0 + dt1%min = 0 + dt1%sec = 0 + + ! otherwise, dates before dt2 use Stream 2 + + dt2%year = 2018 + dt2%month = 1 + dt2%day = 1 + dt2%hour = 0 + dt2%min = 0 + dt2%sec = 0 + + ! ---------------------------------------------------- + + ! initialize + + met_tag_out = repeat(' ', len(met_tag_out)) + + stream = repeat(' ', len(stream )) + + ! define which stream to use + + tmpind = 9 + + if (met_tag_in(5:6) = 'CS') tmpind = tmpind + 2 + + tmpstream = met_tag_in(tmpind:tmpind+4) + + if (tmpstream=='cross') then + + if (datetime_lt_refdatetime( date_time, dt1 )) then + + tmpstream = 'jan98' + + elseif (datetime_lt_refdatetime( date_time, dt2 )) then + + tmpstream = 'jan08' + + else + + tmpstream = 'jan18' + + end if + + end if + + met_tag_out = 'e5303_m21c_' // tmpstream + + met_path_default = trim(met_path_in) // '/' + + ! ----------------------------------------------------- + ! + ! identify which precip corrections to use, + ! assemble met_path accordingly + ! + ! met_tag = "M21C[CS][xxx]_[STREAM]{__prec[PREC]}" + ! + ! where {__prec[PREC]} is optional + + is = index( met_tag_in, '__') + + if (is>0) then ! using precip corrections + + prec_tag = met_tag_in(is+6:len(met_tag_in)) + + met_path_prec = trim(met_path_in) // '/precip_corr_' // trim(prec_tag) // '/' + + use_prec_corr = .true. + + else ! not using precip corrections + + prec_tag = repeat(' ', len(prec_tag)) + + met_path_prec = met_path_default + + use_prec_corr = .false. + + ! check if prec_tag was accidentally appended with a single underscore + + if (len_trim(met_tag_in)>tmpind+6) then + + err_msg = 'questionable met_tag_in, not enough double underscores' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + + end if + + end if + + end subroutine parse_M21C_met_tag + ! **************************************************************** subroutine parse_G5DAS_met_tag( met_path_in, met_tag_in, date_time, & @@ -5279,12 +5497,19 @@ subroutine get_GEOS_forcing_filename(fname_full,file_exists, date_time, daily_fi time_stamp(1:8) = YYYY // MM // DD - elseif (index(met_tag,'GEOSIT') > 0 .or. index(met_tag,'geosit') > 0) then + elseif ( & + index(met_tag,'GEOSIT') > 0 .or. index(met_tag,'geosit') > 0 & + index(met_tag,'M21C' ) > 0 .or. index(met_tag,'m21c' ) > 0 & + ) then + + ! newer time stamp format (GEOS-IT, M21C, ...) time_stamp(1:16) = YYYY //'-'// MM //'-'// DD // 'T' // trim(HHMM) // 'Z' - + else + ! old time stamp format (MERRA, MERRA-2, FP) + time_stamp(1:14) = YYYY // MM // DD // '_' // trim(HHMM) // 'z' end if From d224e6a70bd840e6e77d982e3ca25e628a56fe6a Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Thu, 23 Jan 2025 11:39:55 -0500 Subject: [PATCH 058/107] fixing errors in previous commit (LDAS_Forcing.F90) --- GEOSmetforce_GridComp/LDAS_Forcing.F90 | 61 ++++++++++++++------------ 1 file changed, 34 insertions(+), 27 deletions(-) diff --git a/GEOSmetforce_GridComp/LDAS_Forcing.F90 b/GEOSmetforce_GridComp/LDAS_Forcing.F90 index 5c7bca72..c2aeff1d 100755 --- a/GEOSmetforce_GridComp/LDAS_Forcing.F90 +++ b/GEOSmetforce_GridComp/LDAS_Forcing.F90 @@ -3260,8 +3260,7 @@ subroutine get_GEOS( date_time, force_dtstep, met_path, met_tag, & GEOSIT_defs = G5DAS_defs - ! GEOSIT character(40): - ! + ! character(40): ! 1 2 3 4 ! 1234567890123456789012345678901234567890 @@ -3305,18 +3304,22 @@ subroutine get_GEOS( date_time, force_dtstep, met_path, met_tag, & M21CCSINT_defs = M21CINT_defs - M21CCSINT_defs( 1,3)=[character(len=40):: 'lfo_tavg_1hr_glo_C360x360x6_slv' ] - M21CCSINT_defs( 2,3)=[character(len=40):: 'lfo_tavg_1hr_glo_C360x360x6_slv' ] - M21CCSINT_defs( 3,3)=[character(len=40):: 'lfo_tavg_1hr_glo_C360x360x6_slv' ] - M21CCSINT_defs( 4,3)=[character(len=40):: 'lfo_tavg_1hr_glo_C360x360x6_slv' ] - M21CCSINT_defs( 5,3)=[character(len=40):: 'int_tavg_1hr_glo_C360x360x6_slv' ] ! uncorrected - M21CCSINT_defs( 6,3)=[character(len=40):: 'int_tavg_1hr_glo_C360x360x6_slv' ] ! uncorrected - M21CCSINT_defs( 7,3)=[character(len=40):: 'int_tavg_1hr_glo_C360x360x6_slv' ] ! uncorrected - M21CCSINT_defs( 8,3)=[character(len=40):: 'lfo_inst_1hr_glo_C360x360x6_slv' ] - M21CCSINT_defs( 9,3)=[character(len=40):: 'lfo_inst_1hr_glo_C360x360x6_slv' ] - M21CCSINT_defs(10,3)=[character(len=40):: 'lfo_inst_1hr_glo_C360x360x6_slv' ] - M21CCSINT_defs(11,3)=[character(len=40):: 'lfo_inst_1hr_glo_C360x360x6_slv' ] - M21CCSINT_defs(12,3)=[character(len=40):: 'lfo_inst_1hr_glo_C360x360x6_slv' ] + ! character(40): + ! 1 2 3 4 + ! 1234567890123456789012345678901234567890 + + M21CCSINT_defs( 1,3) = 'lfo_tavg_1hr_glo_C360x360x6_slv ' + M21CCSINT_defs( 2,3) = 'lfo_tavg_1hr_glo_C360x360x6_slv ' + M21CCSINT_defs( 3,3) = 'lfo_tavg_1hr_glo_C360x360x6_slv ' + M21CCSINT_defs( 4,3) = 'lfo_tavg_1hr_glo_C360x360x6_slv ' + M21CCSINT_defs( 5,3) = 'int_tavg_1hr_glo_C360x360x6_slv ' ! uncorrected + M21CCSINT_defs( 6,3) = 'int_tavg_1hr_glo_C360x360x6_slv ' ! uncorrected + M21CCSINT_defs( 7,3) = 'int_tavg_1hr_glo_C360x360x6_slv ' ! uncorrected + M21CCSINT_defs( 8,3) = 'lfo_inst_1hr_glo_C360x360x6_slv ' + M21CCSINT_defs( 9,3) = 'lfo_inst_1hr_glo_C360x360x6_slv ' + M21CCSINT_defs(10,3) = 'lfo_inst_1hr_glo_C360x360x6_slv ' + M21CCSINT_defs(11,3) = 'lfo_inst_1hr_glo_C360x360x6_slv ' + M21CCSINT_defs(12,3) = 'lfo_inst_1hr_glo_C360x360x6_slv ' ! M21C file specs with corrected precip, which could be either ! - native (ie, the precip seen by the land surface in the M21C system), or @@ -3338,18 +3341,22 @@ subroutine get_GEOS( date_time, force_dtstep, met_path, met_tag, & M21CCSCOR_defs = M21CCOR_defs - M21CCSCOR_defs( 1,3)=[character(len=40):: 'lfo_tavg_1hr_glo_C360x360x6_slv' ] - M21CCSCOR_defs( 2,3)=[character(len=40):: 'lfo_tavg_1hr_glo_C360x360x6_slv' ] - M21CCSCOR_defs( 3,3)=[character(len=40):: 'lfo_tavg_1hr_glo_C360x360x6_slv' ] - M21CCSCOR_defs( 4,3)=[character(len=40):: 'lfo_tavg_1hr_glo_C360x360x6_slv' ] - M21CCSCOR_defs( 5,3)=[character(len=40):: 'lfo_tavg_1hr_glo_C360x360x6_slv' ] ! M21C built-in corrections - M21CCSCOR_defs( 6,3)=[character(len=40):: 'lfo_tavg_1hr_glo_C360x360x6_slv' ] ! M21C built-in corrections - M21CCSCOR_defs( 7,3)=[character(len=40):: 'lfo_tavg_1hr_glo_C360x360x6_slv' ] ! M21C built-in corrections - M21CCSCOR_defs( 8,3)=[character(len=40):: 'lfo_inst_1hr_glo_C360x360x6_slv' ] - M21CCSCOR_defs( 9,3)=[character(len=40):: 'lfo_inst_1hr_glo_C360x360x6_slv' ] - M21CCSCOR_defs(10,3)=[character(len=40):: 'lfo_inst_1hr_glo_C360x360x6_slv' ] - M21CCSCOR_defs(11,3)=[character(len=40):: 'lfo_inst_1hr_glo_C360x360x6_slv' ] - M21CCSCOR_defs(12,3)=[character(len=40):: 'lfo_inst_1hr_glo_C360x360x6_slv' ] + ! character(40): + ! 1 2 3 4 + ! 1234567890123456789012345678901234567890 + + M21CCSCOR_defs( 1,3) = 'lfo_tavg_1hr_glo_C360x360x6_slv ' + M21CCSCOR_defs( 2,3) = 'lfo_tavg_1hr_glo_C360x360x6_slv ' + M21CCSCOR_defs( 3,3) = 'lfo_tavg_1hr_glo_C360x360x6_slv ' + M21CCSCOR_defs( 4,3) = 'lfo_tavg_1hr_glo_C360x360x6_slv ' + M21CCSCOR_defs( 5,3) = 'lfo_tavg_1hr_glo_C360x360x6_slv ' ! M21C built-in corrections + M21CCSCOR_defs( 6,3) = 'lfo_tavg_1hr_glo_C360x360x6_slv ' ! M21C built-in corrections + M21CCSCOR_defs( 7,3) = 'lfo_tavg_1hr_glo_C360x360x6_slv ' ! M21C built-in corrections + M21CCSCOR_defs( 8,3) = 'lfo_inst_1hr_glo_C360x360x6_slv ' + M21CCSCOR_defs( 9,3) = 'lfo_inst_1hr_glo_C360x360x6_slv ' + M21CCSCOR_defs(10,3) = 'lfo_inst_1hr_glo_C360x360x6_slv ' + M21CCSCOR_defs(11,3) = 'lfo_inst_1hr_glo_C360x360x6_slv ' + M21CCSCOR_defs(12,3) = 'lfo_inst_1hr_glo_C360x360x6_slv ' ! ----------------------------------------------------------------------- @@ -4841,7 +4848,7 @@ subroutine parse_M21C_met_tag( met_path_in, met_tag_in, date_time, & tmpind = 9 - if (met_tag_in(5:6) = 'CS') tmpind = tmpind + 2 + if (met_tag_in(5:6) == 'CS') tmpind = tmpind + 2 tmpstream = met_tag_in(tmpind:tmpind+4) From 5d40715c78642bbde7da92714421339b3e0db29a Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Thu, 23 Jan 2025 12:15:36 -0500 Subject: [PATCH 059/107] fixing another syntax error in previous commit (LDAS_Forcing.F90) --- GEOSmetforce_GridComp/LDAS_Forcing.F90 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/GEOSmetforce_GridComp/LDAS_Forcing.F90 b/GEOSmetforce_GridComp/LDAS_Forcing.F90 index c2aeff1d..6ac6a58f 100755 --- a/GEOSmetforce_GridComp/LDAS_Forcing.F90 +++ b/GEOSmetforce_GridComp/LDAS_Forcing.F90 @@ -5504,9 +5504,9 @@ subroutine get_GEOS_forcing_filename(fname_full,file_exists, date_time, daily_fi time_stamp(1:8) = YYYY // MM // DD - elseif ( & - index(met_tag,'GEOSIT') > 0 .or. index(met_tag,'geosit') > 0 & - index(met_tag,'M21C' ) > 0 .or. index(met_tag,'m21c' ) > 0 & + elseif ( & + index(met_tag,'GEOSIT') > 0 .or. index(met_tag,'geosit') > 0 .or. & + index(met_tag,'M21C' ) > 0 .or. index(met_tag,'m21c' ) > 0 & ) then ! newer time stamp format (GEOS-IT, M21C, ...) From f930ece2fb18806b278c59339cdc50e1fe6362e6 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Fri, 24 Jan 2025 16:17:37 -0500 Subject: [PATCH 060/107] added clarification to "sample exe input" file about requirement of matching cs tile space when using surface met forcing on cs grid (ldas_setup) --- GEOSldas_App/ldas_setup | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/GEOSldas_App/ldas_setup b/GEOSldas_App/ldas_setup index 0c495d89..dfbe28ea 100755 --- a/GEOSldas_App/ldas_setup +++ b/GEOSldas_App/ldas_setup @@ -1504,6 +1504,11 @@ def _printExeInputKeys(rqdExeInpKeys): print ('# #') print ('# Surface meteorological forcing time step is in seconds. #') print ('# #') + print ('# NOTE: #') + print ('# When forcing is on cube-sphere (CS) grid, must use: #') + print ('# - Model tile space (BCS) derived from same CS grid. #') + print ('# - Nearest-neighbor interpolation (MET_HINTERP: 0). #') + print ('# #') print ('# For more information, see: #') print ('# GEOSldas/doc/README.MetForcing_and_BCS.md #') print ('# #') From 6fe11e9892ce24fe8f32eb96995bdd6f5b472c98 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Fri, 24 Jan 2025 16:38:51 -0700 Subject: [PATCH 061/107] first pass at addressing review comments --- CHANGELOG.md | 1 + .../clsm_ensupd_read_obs.F90 | 82 +++++++++++-------- 2 files changed, 50 insertions(+), 33 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 390b7899..c7bea22d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- CYGNSS soil moisture reader - New update_type for joint 3d soil moisture and 1d snow analysis (Tb+sfmc+sfds+SCF obs) ### Changed diff --git a/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 97fbd59a..31ed9a01 100644 --- a/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -2161,7 +2161,7 @@ subroutine read_obs_sm_CYGNSS( & ! CYGNSS soil moisture obs are in volumetric units (m3 m-3) with a spatial ! resolution of 0.3 Decimal Degrees x 0.37 Decimal Degrees. ! They are daily files containing daily (obs_param_nml(.)%descr = CYGNSS_SM_daily) - ! and subdaily SM estimates (obs_param_nml(.)%descr = CYGNSS_SM). The + ! and subdaily SM estimates (obs_param_nml(.)%descr = CYGNSS_SM_6hr). The ! subdaily values are for 6 hr time intervals, 0-6hr, 6-12hr, 12-18hr, 18-24hr. ! The subdaily values are assimilated at 3z, 9z, 15z, 21z. If the assimilation ! window is more than 6 hr the code will error out. The daily values are assimilated @@ -2204,8 +2204,9 @@ subroutine read_obs_sm_CYGNSS( & ! ------------------------------------------------------------------- ! local variables: - integer, parameter :: max_obs = 50000 ! max number of obs read by subroutine (expecting < 6 hr assim window) - character(4), parameter :: J2000_epoch_id = 'TT12' ! see date_time_util.F90 + + integer, parameter :: max_obs = 50000 ! max number of daily obs read by subroutine (expecting > 6 hr assim window) + character(4), parameter :: J2000_epoch_id = 'TT12' ! see date_time_util.F90 character(len=*), parameter :: Iam = 'read_obs_sm_CYGNSS' type(date_time_type) :: date_time_obs_beg, date_time_obs_end @@ -2254,7 +2255,7 @@ subroutine read_obs_sm_CYGNSS( & ! determine operating time range of sensor - if (trim(this_obs_param%descr) == 'CYGNSS_SM' .or. trim(this_obs_param%descr) == 'CYGNSS_SM_daily') then + if (trim(this_obs_param%descr) == 'CYGNSS_SM_6hr' .or. trim(this_obs_param%descr) == 'CYGNSS_SM_daily') then date_time_obs_beg = date_time_type(2018, 8, 1, 0, 0, 0,-9999,-9999) date_time_obs_end = date_time_type(2100, 1, 1, 0, 0, 0,-9999,-9999) else @@ -2294,7 +2295,7 @@ subroutine read_obs_sm_CYGNSS( & HH03 = .true. HHcnt = HHcnt + 1 end if - if (date_time_low%hour > 21 .and. date_time_up%hour >= 3) then ! wrap-around from previous day + if (date_time_low%hour > 21 .and. date_time_up%hour >= 3) then ! wrap-around from previous day for 3 hr < assim window <= 6 hr HH03 = .true. HHcnt = HHcnt + 1 end if @@ -2310,10 +2311,14 @@ subroutine read_obs_sm_CYGNSS( & HH21 = .true. HHcnt = HHcnt + 1 end if + if (date_time_low%hour < 21 .and. date_time_up%hour < 3) then ! wrap-around into next day for 3 hr < assim window <= 6 hr + HH21 = .true. + HHcnt = HHcnt + 1 + end if ! return if assimilating subdaily obs and no HH is true - if (trim(this_obs_param%descr) == 'CYGNSS_SM' .and. .not. (HH03 .or. HH09 .or. HH15 .or. HH21)) return + if (trim(this_obs_param%descr) == 'CYGNSS_SM_6hr' .and. .not. (HH03 .or. HH09 .or. HH15 .or. HH21)) return ! if assimilation window encompasses more than one time slice, abort @@ -2330,25 +2335,15 @@ subroutine read_obs_sm_CYGNSS( & write (HH, '(i2.2)') date_time%hour write (MI, '(i2.2)') date_time%min - tmpname = trim(this_obs_param%name) - - ! Replace s20180801 with sYYYYMMDD - pos = index(tmpname, "s20180801") - if (pos > 0) then - tmpname = tmpname(1:pos-1) // "s" // YYYY // MM // DD // tmpname(pos+9:) - endif + ! construct the file name using hardwired name and date_time - ! Replace e20180801 with eYYYYMMDD - pos = index(tmpname, "e20180801") - if (pos > 0) then - tmpname = tmpname(1:pos-1) // "e" // YYYY // MM // DD // tmpname(pos+9:) - endif + tmpname = 'cyg.ddmi.s'// YYYY // MM // DD //'-030000-e'// YYYY // MM // DD //'-210000.l3.grid-soil-moisture-36km.a32.d33.nc' tmpfname = trim(this_obs_param%path) // '/Y' // YYYY // '/M' // MM // '/' // trim(tmpname) // '.nc' if (logit) write (logunit, '(400A)') 'Reading CYGNSS soil moisture data from file: ', trim(tmpfname) - ! Check if file exists + ! check if file exists inquire(file=tmpfname, exist=file_exists) @@ -2357,7 +2352,7 @@ subroutine read_obs_sm_CYGNSS( & call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) end if - ! Open the NetCDF observation file + ! open the NetCDF observation file ierr = nf90_open(trim(tmpfname), nf90_nowrite, ncid) ! get variable dimension IDs @@ -2383,11 +2378,7 @@ subroutine read_obs_sm_CYGNSS( & ierr = nf90_inq_varid(ncid, 'latitude', lat_varid) ierr = nf90_inq_varid(ncid, 'longitude', lon_varid) - ! allocate memory for the variables - allocate(sm_d( N_lon, N_lat, N_time )) - allocate(sm_subd( N_lon, N_lat, N_timeslices )) - allocate(sigma_d( N_lon, N_lat, N_time )) - allocate(sigma_subd( N_lon, N_lat, N_timeslices )) + ! allocate memory for universal variables allocate(timeintervals(N_startstop, N_timeslices )) allocate(latitudes( N_lon, N_lat )) allocate(longitudes( N_lon, N_lat )) @@ -2400,7 +2391,11 @@ subroutine read_obs_sm_CYGNSS( & ierr = nf90_get_var(ncid, lon_varid, longitudes) ! read either subdaily or daily soil moisture and sigma variables - if ( trim(this_obs_param%descr) == 'CYGNSS_SM' ) then + if ( trim(this_obs_param%descr) == 'CYGNSS_SM_6hr' ) then + + ! allocate memory for subdaily variables + allocate(sm_subd( N_lon, N_lat, N_timeslices )) + allocate(sigma_subd(N_lon, N_lat, N_timeslices )) ! subdaily observations required ierr = nf90_get_var(ncid, sm_subd_varid, sm_subd) @@ -2409,10 +2404,10 @@ subroutine read_obs_sm_CYGNSS( & ! find the time slice that corresponds to the assimilation window idx = -1 do i = 1, N_timeslices - if ((date_time%hour == 3 .and. timeintervals(1,i) == 0.0 ) .or. & - (date_time%hour == 9 .and. timeintervals(1,i) == 0.25) .or. & - (date_time%hour == 15 .and. timeintervals(1,i) == 0.5 ) .or. & - (date_time%hour == 21 .and. timeintervals(1,i) == 0.75) ) then + if ((HH03 .and. timeintervals(1,i) == 0.0 ) .or. & + (HH09 .and. timeintervals(1,i) == 0.25) .or. & + (HH15 .and. timeintervals(1,i) == 0.5 ) .or. & + (HH21 .and. timeintervals(1,i) == 0.75) ) then idx = i exit end if @@ -2428,6 +2423,10 @@ subroutine read_obs_sm_CYGNSS( & else + ! allocate memory for daily variables + allocate(sm_d( N_lon, N_lat, N_time )) + allocate(sigma_d(N_lon, N_lat, N_time )) + ! daily observations required ierr = nf90_get_var(ncid, sm_d_varid, sm_d) ierr = nf90_get_var(ncid, sigma_d_varid, sigma_d) @@ -2584,7 +2583,7 @@ subroutine read_obs_sm_CYGNSS( & CYGNSS_sm( ind) = CYGNSS_sm( ind) + tmp_obs( ii) CYGNSS_lon( ind) = CYGNSS_lon( ind) + tmp_lon( ii) CYGNSS_lat( ind) = CYGNSS_lat( ind) + tmp_lat( ii) - CYGNSS_time(ind) = CYGNSS_time(ind) + tmp_jtime(ii) + CYGNSS_time(ind) = tmp_jtime(ii) ! time is the same for all observations N_obs_in_tile(ind) = N_obs_in_tile(ind) + 1 @@ -2607,7 +2606,6 @@ subroutine read_obs_sm_CYGNSS( & CYGNSS_sm( ii) = CYGNSS_sm( ii)/real(N_obs_in_tile(ii)) CYGNSS_lon( ii) = CYGNSS_lon( ii)/real(N_obs_in_tile(ii)) CYGNSS_lat( ii) = CYGNSS_lat( ii)/real(N_obs_in_tile(ii)) - CYGNSS_time( ii) = CYGNSS_time(ii)/real(N_obs_in_tile(ii),kind(0.0D0)) elseif (N_obs_in_tile(ii)==0) then @@ -2642,6 +2640,24 @@ subroutine read_obs_sm_CYGNSS( & end if ! clean up + + deallocate(timeintervals) + deallocate(latitudes) + deallocate(longitudes) + deallocate(tmp_sm) + deallocate(tmp_sigma) + deallocate(latitudes_m) + deallocate(longitudes_m) + deallocate(small_SM_range_flag) + deallocate(poor_SMAP_flag) + deallocate(high_ubrmsd_flag) + deallocate(few_obs_flag) + deallocate(low_signal_flag) + + if (allocated(sm_d)) deallocate(sm_d) + if (allocated(sm_subd)) deallocate(sm_subd) + if (allocated(sigma_d)) deallocate(sigma_d) + if (allocated(sigma_subd)) deallocate(sigma_subd) if (associated(tmp_obs)) deallocate(tmp_obs) if (associated(tmp_lon)) deallocate(tmp_lon) @@ -9137,7 +9153,7 @@ subroutine read_obs( & end if - case ('CYGNSS_SM','CYGNSS_SM_daily') + case ('CYGNSS_SM_6hr','CYGNSS_SM_daily') call read_obs_sm_CYGNSS( & date_time, dtstep_assim, N_catd, tile_coord, & From a27412edd816384f9c4902d790685c452ffd2fc5 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Fri, 24 Jan 2025 20:16:05 -0500 Subject: [PATCH 062/107] bugfix in fname --- GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 31ed9a01..4d0d0875 100644 --- a/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -2339,7 +2339,7 @@ subroutine read_obs_sm_CYGNSS( & tmpname = 'cyg.ddmi.s'// YYYY // MM // DD //'-030000-e'// YYYY // MM // DD //'-210000.l3.grid-soil-moisture-36km.a32.d33.nc' - tmpfname = trim(this_obs_param%path) // '/Y' // YYYY // '/M' // MM // '/' // trim(tmpname) // '.nc' + tmpfname = trim(this_obs_param%path) // '/Y' // YYYY // '/M' // MM // '/' // trim(tmpname) if (logit) write (logunit, '(400A)') 'Reading CYGNSS soil moisture data from file: ', trim(tmpfname) From ab7fb1d0edc492f125b83ce1874bdcfb7846539a Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Sun, 26 Jan 2025 17:20:44 -0500 Subject: [PATCH 063/107] added matlab reader for tile file (ASCII and nc4) --- .../util/shared/matlab/read_tile_file_ASCII.m | 375 ++++++++++++++++++ .../util/shared/matlab/read_tile_file_nc4.m | 42 ++ 2 files changed, 417 insertions(+) create mode 100644 GEOSldas_App/util/shared/matlab/read_tile_file_ASCII.m create mode 100644 GEOSldas_App/util/shared/matlab/read_tile_file_nc4.m diff --git a/GEOSldas_App/util/shared/matlab/read_tile_file_ASCII.m b/GEOSldas_App/util/shared/matlab/read_tile_file_ASCII.m new file mode 100644 index 00000000..3dab7c3e --- /dev/null +++ b/GEOSldas_App/util/shared/matlab/read_tile_file_ASCII.m @@ -0,0 +1,375 @@ +function [ tile_coord ] = read_til_file_ASCII( fname_til, fname_catchmentdef ) + +% read tile coordinates from "til" file (EASEv2 and cube-sphere) and +% put data into tile_coord structure (similar to that defined in GEOSldas) +% +% inputs: +% fname_til : Name (with full path) of ASCII tile file (see examples below). +% fname_catchmentdef : OPTIONAL, name of matching catchment.def file +% Do NOT specify if tile file is from bcs in new layout; will be +% assembled from fname_til. +% +% fname_til examples: +% '/discover/nobackup/projects/gmao/bcs_shared/fvInput/ExtData/esm/tiles/v12/geometry/EASEv2_M36/EASEv2_M36_964x406.til' +% '/discover/nobackup/projects/gmao/bcs_shared/fvInput/ExtData/esm/tiles/v12/geometry/CF0360x6C_DE1440xPE0720/CF0360x6C_DE1440xPE0720-Pfafstetter.til' +% +% +% IMPORTANT: +% This reader is designed to work for bcs versions NL5, v11, v12, and newer (beginning ~2022). +% It should be backward-compatible for most older bcs versions, but there is no +% expectation that it will work universally across all old and new versions. +% +% reichle, 24 Jan 2025 +% +% ------------------------------------------------------------- + +% determine fname_catchmentdef + +%%%if ~exist( fname_catchmentdef ) + + ind=strfind(fname_til,'/'); + + % verify that tile file is from bcs in new layout and naming convention + + if ~strcmp( fname_til(ind(end-2)+1:ind(end-1)-1), 'geometry' ) + + error('cannot derive fname_catchmentdef') + + end + + resolution = fname_til(ind(end-1)+1:ind(end)-1); + + fname_catchmentdef = [ fname_til(1:ind(end-2)), 'land/', resolution, '/clsm/catchment.def' ]; + +%%%end + +% ------------------------------------------------------------- +% +% read tile file + +disp(['reading from ', fname_til]) + +ifp = fopen( fname_til, 'r' ); + +% ------------------------------------------------------------- +% +% EASE grid tile space? + +isEASE = 0; + +if ~isempty(findstr('EASE',fname_til)), isEASE=1; end + +% -------------- +% +% determine number of data columns + +if isEASE + + % NOTE: very old EASE versions have N_data_col=8 + % + % between SMAP bcs v001 (through Vv3030) and SMAP bcs v003[a] (from Vv4030), + % a new (9th) column was added in the *.til file + + N_data_col = 9; + +else + + N_data_col = 12; + +end + +% ------------------------------------------------------------- +% +% Number of integers in first header line depends on bcs version: + +N_headerline1 = 4; % for bcs versions after ~2022 + +old_versions = { 'Fortuna', ... + 'Ganymed', ... + 'Heracles', ... + 'Icarus', ... + 'Jason', ... + 'DYAMOND2', ... + 'FV3-1_0', ... + 'NL3', ... + 'NL4', ... + }; + +for kk=1:length(old_versions) + + if ~isempty( strfind( fname_til, old_versions{kk} )) + + N_headerline1 = 3; + + disp([ 'detected old bcs version ', old_versions{kk} ]) + + end +end + +% make exception for select "new" versions (stored in legacy bcs directory) that would otherwise +% be classified as "old" per the loop above + +new_versions = { 'Icarus-NLv5', ... + 'DYAMOND', ... + }; + +for kk=1:length(new_versions) + + if ~isempty( strfind( fname_til, new_versions{kk} )) + + N_headerline1 = 4; + + disp([ 'detected exception for new bcs version ', new_versions{kk} ]) + + end +end + +% echo final value of N_headerline1 + +disp(['using N_headerline1 = ', num2str(N_headerline1) ]) + +% ------------------------------------------------------------- +% +% read header + +% header line 1: + +tmpdata = fscanf( ifp, '%f', N_headerline1 ); + +N_tile_tmp = tmpdata(1); + +if N_headerline1==4 + + tile_coord.N_PfafCat = tmpdata(2); + tile_coord.raster_nx = tmpdata(3); + tile_coord.raster_ny = tmpdata(4); + +elseif N_headerline1==3 + + tile_coord.N_PfafCat = NaN; + tile_coord.raster_nx = tmpdata(2); + tile_coord.raster_ny = tmpdata(3); + +end + +% -------------- +% +% header line 2: + +tile_coord.N_grids = fscanf( ifp, '%f', 1 ); + +% verify N_grids (should be 1 for EASE and 2 for non-EASE) + +if isEASE & tile_coord.N_grids~=1, error(['unexpected N_grids for EASE tile space: ', num2str(tile_coord.N_grids)]), end + +if ~isEASE & tile_coord.N_grids~=2, error(['unexpected N_grids for non-EASE tile space: ', num2str(tile_coord.N_grids)]), end + +% Deal with older EASE bcs versions having (useless) header lines for grid 2, +% despite having the correct value of N_grids=1 in header line 2. + +if isEASE & ( ~isempty(findstr('NL3',fname_til)) | ~isempty(findstr('NL4',fname_til)) ) + + tmp_n_grids = 2; + +else + + tmp_n_grids = tile_coord.N_grids; + +end + +% -------------- +% +% header lines 3-5: + +tile_coord.Grid_Name = fscanf( ifp, '%s', 1 ); +tile_coord.IM = fscanf( ifp, '%f', 1 ); +tile_coord.JM = fscanf( ifp, '%f', 1 ); + +% -------------- +% +% header lines 6-8 (if present): + +if tmp_n_grids==2 + + % NOTE: EASE NL3 and NL4 contain additional header lines for second grid, despite (correct) N_grids=1 + + tile_coord.Grid2_Name = fscanf( ifp, '%s', 1 ); + tile_coord.IM2 = fscanf( ifp, '%f', 1 ); + tile_coord.JM2 = fscanf( ifp, '%f', 1 ); + +end + +% -------------- +% +% read data + +tmpdata = fscanf( ifp, '%f' ); + +fclose(ifp); + +disp('done reading "til" file') + +% verify N_tile*N_data_col against number of data read + +if length(tmpdata)~=N_tile_tmp*N_data_col, error('something wrong with N_tile*N_data_col'), end + +% convert into 2d array + +tmpdata = transpose( reshape(tmpdata, [N_data_col, N_tile_tmp]) ); + +% -------------------------------------------------- +% +% assign tile_id +% +% by convention, tile_id is equal to index number of tile in *.til file + +tmp_tileid = transpose(1:N_tile_tmp); + +% -------------------------------------------------- +% +% subset (if requested) + +%ind = find(tmpdata(:,1)==100); % keep only land +%ind = find(tmpdata(:,1)== 19); % keep only lakes +%ind = find(tmpdata(:,1)== 20); % keep only ice +%ind = find(tmpdata(:,1)~= 0); % keep land, lake, landice + +%tmpdata = tmpdata( ind,:); + +%tmp_tileid = tmp_tileid( ind, 1); + +% -------------------------------------------------- +% +% copy data into tile_coord structure + +tile_coord.N_tile = size(tmpdata,1); % number of tiles (assign here in case of subsetting above) + +% the following are universal (for EASE and non-EASE, all tile types) + +tile_coord.tile_id = tmp_tileid; % tile ID + +tile_coord.typ = tmpdata(:, 1); % tile type + +tile_coord.com_lon = tmpdata(:, 3); % center-of-mass longitude of tile +tile_coord.com_lat = tmpdata(:, 4); % center-of-mass latitude of tile + +tile_coord.i_indg = tmpdata(:, 5); % i index of tile on global "atm" (or EASE) grid +tile_coord.j_indg = tmpdata(:, 6); % j index of tile on global "atm" (or EASE) grid +tile_coord.frac_cell = tmpdata(:, 7); % area fraction of "atm" (or EASE) grid cell + +% initialize remaining fields (to be filled below) + +tmpNaN = NaN*ones(tile_coord.N_tile,1); + +tile_coord.min_lon = tmpNaN; % min longitude of tile +tile_coord.max_lon = tmpNaN; % max longitude of tile +tile_coord.min_lat = tmpNaN; % min latitude of tile +tile_coord.max_lat = tmpNaN; % max latitude of tile + +tile_coord.elev = tmpNaN; % elevation of tile + +tile_coord.area = tmpNaN; % area of "atm" grid cell +tile_coord.pfaf = tmpNaN; % index of (hydrological) Pfafstetter catchment +tile_coord.frac_pfaf = tmpNaN; % area fraction of Pfafstetter catchment + +if ~isEASE + + tile_coord.i_indg2 = tmpNaN; % i index of tile on global "ocean" grid (grid 2) + tile_coord.j_indg2 = tmpNaN; % j index of tile on global "ocean" grid (grid 2) + tile_coord.frac_cell2 = tmpNaN; % area fraction of "ocean" grid cell (grid 2) + +end + +% -------------------------------------------------- +% +% get indices for tile types + +ind_land = find( tile_coord.typ == 100); +ind_lake = find( tile_coord.typ == 19); +ind_landice = find( tile_coord.typ == 20); +ind_ocean = find( tile_coord.typ == 0); + +ind_NOTland = find( tile_coord.typ ~= 100); +ind_NOTocean = find( tile_coord.typ ~= 0); + +if isEASE + + col_area = NaN; + col_pfaf = 2; % land tiles only + col_frac_pfaf = NaN; % land tiles only + +else + + col_area = 2; + col_pfaf = 9; % land tiles only + col_frac_pfaf = 11; + +end + + +if ~isnan(col_area) + + tile_coord.area = tmpdata(:, col_area); % tile area + +end + +tile_coord.pfaf( ind_NOTocean) = tmpdata(ind_NOTocean, col_pfaf); + +% ------------------------------------------------- +% +% EASE grid tile file: +% +% column 8: Pfafstetter index (same as column 2) +% column 9: Pfafstetter ID +% +% non-EASE grid tile file: +% +% column 9: i_indg2 [for ocean tiles] *OR* pfaf [for non-ocean tiles] +% column 10: j_indg2 +% column 11: frac_cell2 [for ocean tiles] *OR* frac_pfaf [for non-ocean tiles] +% column 12: dummy_index2 + +if ~isEASE + + tile_coord.frac_pfaf( ind_NOTocean) = tmpdata(ind_NOTocean, col_frac_pfaf); + + tile_coord.i_indg2( ind_ocean) = tmpdata(ind_ocean, 9); + tile_coord.j_indg2( ind_ocean) = tmpdata(ind_ocean, 10); + tile_coord.frac_cell2(ind_ocean) = tmpdata(ind_ocean, 11); + +end + +% ------------------------------------------------- +% +% get additional info from (land-only) "catchment.def" file + +tctmp = read_catchmentdef( fname_catchmentdef ); + +% verify consistency of catchment.def file and tile file + +if tctmp.N_tile~=length(ind_land) + + error('mismatch between tile file and catchment.def file: N_tile') + +end + +if ( any(tile_coord.tile_id(ind_land) - tctmp.tile_id) | ... + any(tile_coord.pfaf( ind_land) - tctmp.pfaf ) ... + ) + + error('mismatch between tile file and catchment.def file: tile_id or pfaf') + +end + +% fill tile_coord with relevant info from catchment.def + +tile_coord.min_lon(ind_land) = tctmp.min_lon; +tile_coord.max_lon(ind_land) = tctmp.max_lon; +tile_coord.min_lat(ind_land) = tctmp.min_lat; +tile_coord.max_lat(ind_land) = tctmp.max_lat; + +tile_coord.elev( ind_land) = tctmp.elev; + + +% ========== EOF =================================================== + diff --git a/GEOSldas_App/util/shared/matlab/read_tile_file_nc4.m b/GEOSldas_App/util/shared/matlab/read_tile_file_nc4.m new file mode 100644 index 00000000..e28b3432 --- /dev/null +++ b/GEOSldas_App/util/shared/matlab/read_tile_file_nc4.m @@ -0,0 +1,42 @@ +function [ tile_coord ] = read_til_file_nc4( fname ) + +% read tile coordinates from nc4 "til" file (EASEv2 and cube-sphere) +% +% reichle, 24 Jan 2025 +% +% ------------------------------------------------------------- + +disp(['reading from ', fname]) + +s = ncinfo( fname ); + +tile_coord.N_tile = s.Dimensions.Length; + +varnames = {s.Variables.Name} + +for kk=1:length(varnames) + + this_varname = varnames{kk}; + + tmpdata = ncread( fname, this_varname ); + + % rename some fields + + if strcmp(this_varname,'pfaf_index' ), this_varname = 'pfaf'; end + if strcmp(this_varname,'i_indg1' ), this_varname = 'i_indg'; end + if strcmp(this_varname,'j_indg1' ), this_varname = 'j_indg'; end + if strcmp(this_varname,'frac_cell1' ), this_varname = 'frac_cell'; end + if strcmp(this_varname,'dummy_index1'), this_varname = 'dummy_index'; end + + cmd = ['tile_coord.', this_varname, ' = tmpdata;']; + + %disp(cmd) + eval(cmd) + +end + + + + + +% ========== EOF =================================================== From be03a284455f379d153dae7b042f17e44e0c710f Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Sun, 26 Jan 2025 17:22:27 -0500 Subject: [PATCH 064/107] rename tile_coord%pfaf to tile_coord%pfaf_index --- GEOSldas_App/preprocess_ldas_routines.F90 | 20 ++-- .../util/shared/matlab/read_tilecoord.m | 100 +++++++++--------- LDAS_Shared/LDAS_TileCoordType.F90 | 34 +++--- LDAS_Shared/LDAS_ensdrv_mpi.F90 | 2 +- 4 files changed, 78 insertions(+), 78 deletions(-) diff --git a/GEOSldas_App/preprocess_ldas_routines.F90 b/GEOSldas_App/preprocess_ldas_routines.F90 index 70af1d7a..ea34807c 100644 --- a/GEOSldas_App/preprocess_ldas_routines.F90 +++ b/GEOSldas_App/preprocess_ldas_routines.F90 @@ -409,7 +409,7 @@ subroutine domain_setup( & ! locals - integer :: n, this_tileid, this_catpfaf, N_exclude, N_include, indomain, rc + integer :: n, this_tileid, N_exclude, N_include, indomain, rc integer, dimension(N_cat_global) :: ExcludeList, IncludeList, tmp_d2g @@ -2964,7 +2964,7 @@ subroutine LDAS_read_til_file( tile_file, catch_file, tile_grid_g, tile_coord_la read (tmpline,*) & tile_coord(i)%typ, & ! 1 - tile_coord(i)%pfaf, & ! 2 + tile_coord(i)%pfaf_index, & ! 2 tile_coord(i)%com_lon, & ! 3 tile_coord(i)%com_lat, & ! 4 tile_coord(i)%i_indg, & ! 5 @@ -2985,7 +2985,7 @@ subroutine LDAS_read_til_file( tile_file, catch_file, tile_grid_g, tile_coord_la read (tmpline,*) & tile_coord(i)%typ, & ! 1 - tile_coord(i)%pfaf, & ! 2 * + tile_coord(i)%pfaf_index, & ! 2 * tile_coord(i)%com_lon, & ! 3 tile_coord(i)%com_lat, & ! 4 tile_coord(i)%i_indg, & ! 5 @@ -3009,7 +3009,7 @@ subroutine LDAS_read_til_file( tile_file, catch_file, tile_grid_g, tile_coord_la tile_coord(i)%j_indg, & ! 6 tile_coord(i)%frac_cell, & ! 7 tmpint1, & ! 8 - tile_coord(i)%pfaf, & ! 9 * + tile_coord(i)%pfaf_index, & ! 9 * tmpint2, & ! 10 tile_coord(i)%frac_pfaf, & ! 11 tmpint3 ! 12 * (previously "tile_id") @@ -3250,7 +3250,7 @@ subroutine read_catchment_def( catchment_def_file, N_tile, tile_coord ) ! ! Header line: N_tile ! - ! Columns: tile_id, Pfaf, min_lon, max_lon, min_lat, max_lat, [elev] + ! Columns: tile_id, pfaf_index, min_lon, max_lon, min_lat, max_lat, [elev] ! ! Elevation [m] is ONLY available for EASE grid tile definitions @@ -3266,7 +3266,7 @@ subroutine read_catchment_def( catchment_def_file, N_tile, tile_coord ) integer :: i, istat, tmpint1, sweep - integer, dimension(N_tile) :: tmp_tileid, tmp_pfaf + integer, dimension(N_tile) :: tmp_tileid, tmp_pfafindex character(len=*), parameter :: Iam = 'read_catchment_def' character(len=400) :: err_msg @@ -3305,7 +3305,7 @@ subroutine read_catchment_def( catchment_def_file, N_tile, tile_coord ) ! read 7 columns, avoid using exact format specification - read (10,*, iostat=istat) tmp_tileid(i), tmp_pfaf(i), & + read (10,*, iostat=istat) tmp_tileid(i), tmp_pfafindex(i), & tile_coord(i)%min_lon, & tile_coord(i)%max_lon, & tile_coord(i)%min_lat, & @@ -3316,7 +3316,7 @@ subroutine read_catchment_def( catchment_def_file, N_tile, tile_coord ) ! read 6 columns, avoid using exact format specification - read (10,*, iostat=istat) tmp_tileid(i), tmp_pfaf(i), & + read (10,*, iostat=istat) tmp_tileid(i), tmp_pfafindex(i), & tile_coord(i)%min_lon, & tile_coord(i)%max_lon, & tile_coord(i)%min_lat, & @@ -3358,8 +3358,8 @@ subroutine read_catchment_def( catchment_def_file, N_tile, tile_coord ) end do ! loop through sweeps - if ( any(tile_coord(1:N_tile)%tile_id/=tmp_tileid) .or. & - any(tile_coord(1:N_tile)%pfaf /=tmp_pfaf) ) then + if ( any(tile_coord(1:N_tile)%tile_id /=tmp_tileid) .or. & + any(tile_coord(1:N_tile)%pfaf_index/=tmp_pfafindex) ) then err_msg = 'tile_coord_file and catchment_def_file mismatch. (2)' call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) diff --git a/GEOSldas_App/util/shared/matlab/read_tilecoord.m b/GEOSldas_App/util/shared/matlab/read_tilecoord.m index 422f6fb8..61cb646e 100644 --- a/GEOSldas_App/util/shared/matlab/read_tilecoord.m +++ b/GEOSldas_App/util/shared/matlab/read_tilecoord.m @@ -76,71 +76,71 @@ ifp = fopen( fname, 'r', machfmt); - fortran_tag = fread( ifp, 1, int_precision ); - tile_coord.N_tile = fread( ifp, 1, int_precision ); - fortran_tag = fread( ifp, 1, int_precision ); + fortran_tag = fread( ifp, 1, int_precision ); + tile_coord.N_tile = fread( ifp, 1, int_precision ); + fortran_tag = fread( ifp, 1, int_precision ); Nt = tile_coord.N_tile; - fortran_tag = fread( ifp, 1, int_precision ); - tile_coord.tile_id = fread( ifp, Nt, int_precision ); - fortran_tag = fread( ifp, 1, int_precision ); + fortran_tag = fread( ifp, 1, int_precision ); + tile_coord.tile_id = fread( ifp, Nt, int_precision ); + fortran_tag = fread( ifp, 1, int_precision ); - fortran_tag = fread( ifp, 1, int_precision ); - tile_coord.typ = fread( ifp, Nt, int_precision ); - fortran_tag = fread( ifp, 1, int_precision ); + fortran_tag = fread( ifp, 1, int_precision ); + tile_coord.typ = fread( ifp, Nt, int_precision ); + fortran_tag = fread( ifp, 1, int_precision ); - fortran_tag = fread( ifp, 1, int_precision ); - tile_coord.pfaf = fread( ifp, Nt, int_precision ); - fortran_tag = fread( ifp, 1, int_precision ); + fortran_tag = fread( ifp, 1, int_precision ); + tile_coord.pfaf_index = fread( ifp, Nt, int_precision ); + fortran_tag = fread( ifp, 1, int_precision ); - fortran_tag = fread( ifp, 1, int_precision ); - tile_coord.com_lon = fread( ifp, Nt, float_precision ); - fortran_tag = fread( ifp, 1, int_precision ); + fortran_tag = fread( ifp, 1, int_precision ); + tile_coord.com_lon = fread( ifp, Nt, float_precision ); + fortran_tag = fread( ifp, 1, int_precision ); - fortran_tag = fread( ifp, 1, int_precision ); - tile_coord.com_lat = fread( ifp, Nt, float_precision ); - fortran_tag = fread( ifp, 1, int_precision ); + fortran_tag = fread( ifp, 1, int_precision ); + tile_coord.com_lat = fread( ifp, Nt, float_precision ); + fortran_tag = fread( ifp, 1, int_precision ); - fortran_tag = fread( ifp, 1, int_precision ); - tile_coord.min_lon = fread( ifp, Nt, float_precision ); - fortran_tag = fread( ifp, 1, int_precision ); + fortran_tag = fread( ifp, 1, int_precision ); + tile_coord.min_lon = fread( ifp, Nt, float_precision ); + fortran_tag = fread( ifp, 1, int_precision ); - fortran_tag = fread( ifp, 1, int_precision ); - tile_coord.max_lon = fread( ifp, Nt, float_precision ); - fortran_tag = fread( ifp, 1, int_precision ); + fortran_tag = fread( ifp, 1, int_precision ); + tile_coord.max_lon = fread( ifp, Nt, float_precision ); + fortran_tag = fread( ifp, 1, int_precision ); - fortran_tag = fread( ifp, 1, int_precision ); - tile_coord.min_lat = fread( ifp, Nt, float_precision ); - fortran_tag = fread( ifp, 1, int_precision ); + fortran_tag = fread( ifp, 1, int_precision ); + tile_coord.min_lat = fread( ifp, Nt, float_precision ); + fortran_tag = fread( ifp, 1, int_precision ); - fortran_tag = fread( ifp, 1, int_precision ); - tile_coord.max_lat = fread( ifp, Nt, float_precision ); - fortran_tag = fread( ifp, 1, int_precision ); + fortran_tag = fread( ifp, 1, int_precision ); + tile_coord.max_lat = fread( ifp, Nt, float_precision ); + fortran_tag = fread( ifp, 1, int_precision ); - fortran_tag = fread( ifp, 1, int_precision ); - tile_coord.i_indg = fread( ifp, Nt, int_precision ); - fortran_tag = fread( ifp, 1, int_precision ); + fortran_tag = fread( ifp, 1, int_precision ); + tile_coord.i_indg = fread( ifp, Nt, int_precision ); + fortran_tag = fread( ifp, 1, int_precision ); - fortran_tag = fread( ifp, 1, int_precision ); - tile_coord.j_indg = fread( ifp, Nt, int_precision ); - fortran_tag = fread( ifp, 1, int_precision ); + fortran_tag = fread( ifp, 1, int_precision ); + tile_coord.j_indg = fread( ifp, Nt, int_precision ); + fortran_tag = fread( ifp, 1, int_precision ); - fortran_tag = fread( ifp, 1, int_precision ); - tile_coord.frac_cell = fread( ifp, Nt, float_precision ); - fortran_tag = fread( ifp, 1, int_precision ); + fortran_tag = fread( ifp, 1, int_precision ); + tile_coord.frac_cell = fread( ifp, Nt, float_precision ); + fortran_tag = fread( ifp, 1, int_precision ); - fortran_tag = fread( ifp, 1, int_precision ); - tile_coord.frac_pfaf = fread( ifp, Nt, float_precision ); - fortran_tag = fread( ifp, 1, int_precision ); + fortran_tag = fread( ifp, 1, int_precision ); + tile_coord.frac_pfaf = fread( ifp, Nt, float_precision ); + fortran_tag = fread( ifp, 1, int_precision ); - fortran_tag = fread( ifp, 1, int_precision ); - tile_coord.area = fread( ifp, Nt, float_precision ); - fortran_tag = fread( ifp, 1, int_precision ); + fortran_tag = fread( ifp, 1, int_precision ); + tile_coord.area = fread( ifp, Nt, float_precision ); + fortran_tag = fread( ifp, 1, int_precision ); - fortran_tag = fread( ifp, 1, int_precision ); - tile_coord.elev = fread( ifp, Nt, float_precision ); - fortran_tag = fread( ifp, 1, int_precision ); + fortran_tag = fread( ifp, 1, int_precision ); + tile_coord.elev = fread( ifp, Nt, float_precision ); + fortran_tag = fread( ifp, 1, int_precision ); % if requested, convert to ASCII (txt) file @@ -166,7 +166,7 @@ '%5i%5i%13.6f%13.6f%13.4f%13.4f\n'], ... [tile_coord.tile_id(ii), ... tile_coord.typ(ii), ... - tile_coord.pfaf(ii), ... + tile_coord.pfaf_index(ii), ... tile_coord.com_lon(ii), ... tile_coord.com_lat(ii), ... tile_coord.min_lon(ii), ... @@ -208,7 +208,7 @@ tile_coord.tile_id = tmpdata(:, 1); tile_coord.typ = tmpdata(:, 2); - tile_coord.pfaf = tmpdata(:, 3); + tile_coord.pfaf_index = tmpdata(:, 3); tile_coord.com_lon = tmpdata(:, 4); tile_coord.com_lat = tmpdata(:, 5); tile_coord.min_lon = tmpdata(:, 6); diff --git a/LDAS_Shared/LDAS_TileCoordType.F90 b/LDAS_Shared/LDAS_TileCoordType.F90 index 4861ddce..f89aa5e7 100644 --- a/LDAS_Shared/LDAS_TileCoordType.F90 +++ b/LDAS_Shared/LDAS_TileCoordType.F90 @@ -50,7 +50,7 @@ module LDAS_TileCoordType integer :: tile_id ! unique tile ID integer :: f_num ! full domain ID integer :: typ ! (0=MAPL_Ocean, 100=MAPL_Land, 19=MAPL_Lake, 20=MAPL_LandIce) - integer :: pfaf ! Pfafstetter number (for land tiles, NOT unique) + integer :: pfaf_index ! index of Pfafstetter catchment (for land tiles, NOT unique) real :: com_lon ! center-of-mass longitude real :: com_lat ! center-of-mass latitude real :: min_lon ! minimum longitude (bounding box for tile) @@ -398,21 +398,21 @@ subroutine io_tile_coord_type( action, unitnum, N_tile, tile_coord ) write (unitnum) N_tile - write (unitnum) (tile_coord(n)%tile_id, n=1,N_tile) - write (unitnum) (tile_coord(n)%typ, n=1,N_tile) - write (unitnum) (tile_coord(n)%pfaf, n=1,N_tile) - write (unitnum) (tile_coord(n)%com_lon, n=1,N_tile) - write (unitnum) (tile_coord(n)%com_lat, n=1,N_tile) - write (unitnum) (tile_coord(n)%min_lon, n=1,N_tile) - write (unitnum) (tile_coord(n)%max_lon, n=1,N_tile) - write (unitnum) (tile_coord(n)%min_lat, n=1,N_tile) - write (unitnum) (tile_coord(n)%max_lat, n=1,N_tile) - write (unitnum) (tile_coord(n)%i_indg, n=1,N_tile) - write (unitnum) (tile_coord(n)%j_indg, n=1,N_tile) - write (unitnum) (tile_coord(n)%frac_cell, n=1,N_tile) - write (unitnum) (tile_coord(n)%frac_pfaf, n=1,N_tile) - write (unitnum) (tile_coord(n)%area, n=1,N_tile) - write (unitnum) (tile_coord(n)%elev, n=1,N_tile) + write (unitnum) (tile_coord(n)%tile_id, n=1,N_tile) + write (unitnum) (tile_coord(n)%typ, n=1,N_tile) + write (unitnum) (tile_coord(n)%pfaf_index, n=1,N_tile) + write (unitnum) (tile_coord(n)%com_lon, n=1,N_tile) + write (unitnum) (tile_coord(n)%com_lat, n=1,N_tile) + write (unitnum) (tile_coord(n)%min_lon, n=1,N_tile) + write (unitnum) (tile_coord(n)%max_lon, n=1,N_tile) + write (unitnum) (tile_coord(n)%min_lat, n=1,N_tile) + write (unitnum) (tile_coord(n)%max_lat, n=1,N_tile) + write (unitnum) (tile_coord(n)%i_indg, n=1,N_tile) + write (unitnum) (tile_coord(n)%j_indg, n=1,N_tile) + write (unitnum) (tile_coord(n)%frac_cell, n=1,N_tile) + write (unitnum) (tile_coord(n)%frac_pfaf, n=1,N_tile) + write (unitnum) (tile_coord(n)%area, n=1,N_tile) + write (unitnum) (tile_coord(n)%elev, n=1,N_tile) case ('r','R') @@ -437,7 +437,7 @@ subroutine io_tile_coord_type( action, unitnum, N_tile, tile_coord ) read (unitnum, iostat=istat) tmp_int; if (istat>0) call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) tile_coord(:)%typ = tmp_int(:) read (unitnum, iostat=istat) tmp_int; if (istat>0) call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) - tile_coord(:)%pfaf = tmp_int(:) + tile_coord(:)%pfaf_index = tmp_int(:) read (unitnum, iostat=istat) tmp_real; if (istat>0) call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) tile_coord(:)%com_lon = tmp_real(:) diff --git a/LDAS_Shared/LDAS_ensdrv_mpi.F90 b/LDAS_Shared/LDAS_ensdrv_mpi.F90 index 07cf17bd..1da40cdf 100644 --- a/LDAS_Shared/LDAS_ensdrv_mpi.F90 +++ b/LDAS_Shared/LDAS_ensdrv_mpi.F90 @@ -129,7 +129,7 @@ subroutine init_MPI_types() ! integer :: tile_id ! unique tile ID ! integer :: f_num ! full domain ID ! integer :: typ ! (0=MAPL_Ocean, 100=MAPL_Land, 19=MAPL_Lake, 20=MAPL_LandIce) - ! integer :: pfaf ! Pfafstetter number (for land tiles, NOT unique) + ! integer :: pfaf_index ! index of Pfafstetter catchment (for land tiles, NOT unique) ! real :: com_lon ! center-of-mass longitude ! real :: com_lat ! center-of-mass latitude ! real :: min_lon ! minimum longitude (bounding box for tile) From 8f370ac44af6c1b342899125a54abe7feba86e17 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Sun, 26 Jan 2025 18:00:09 -0500 Subject: [PATCH 065/107] fix optional input arg in matlab ASCII tile file reader (read_tile_file_ASCII.m) --- GEOSldas_App/util/shared/matlab/read_tile_file_ASCII.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GEOSldas_App/util/shared/matlab/read_tile_file_ASCII.m b/GEOSldas_App/util/shared/matlab/read_tile_file_ASCII.m index 3dab7c3e..a092e6af 100644 --- a/GEOSldas_App/util/shared/matlab/read_tile_file_ASCII.m +++ b/GEOSldas_App/util/shared/matlab/read_tile_file_ASCII.m @@ -25,7 +25,7 @@ % determine fname_catchmentdef -%%%if ~exist( fname_catchmentdef ) +if ~exist('fname_catchmentdef','var') ind=strfind(fname_til,'/'); @@ -41,7 +41,7 @@ fname_catchmentdef = [ fname_til(1:ind(end-2)), 'land/', resolution, '/clsm/catchment.def' ]; -%%%end +end % ------------------------------------------------------------- % From d7a9a7513255a78cd3f9e194da05ccf3f9c40667 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Sun, 26 Jan 2025 18:15:16 -0500 Subject: [PATCH 066/107] add reading of attributes to matlab nc4 tile file reader (read_tile_file_nc4.m) --- .../util/shared/matlab/read_tile_file_nc4.m | 36 ++++++++++++++++--- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/GEOSldas_App/util/shared/matlab/read_tile_file_nc4.m b/GEOSldas_App/util/shared/matlab/read_tile_file_nc4.m index e28b3432..31fd1d34 100644 --- a/GEOSldas_App/util/shared/matlab/read_tile_file_nc4.m +++ b/GEOSldas_App/util/shared/matlab/read_tile_file_nc4.m @@ -10,9 +10,39 @@ s = ncinfo( fname ); +% dimensions + tile_coord.N_tile = s.Dimensions.Length; -varnames = {s.Variables.Name} +% --------------------------------- + +% read tile space attributes + +attnames = {s.Attributes.Name}; + +for kk=1:length(attnames) + + this_attname = attnames{kk}; + + % skip select attributes + + if strcmp(this_attname,'NCO' ), continue, end + if strcmp(this_attname,'history'), continue, end + + tmpdata = ncreadatt( fname, '/', this_attname ); + + cmd = ['tile_coord.', this_attname, ' = tmpdata;']; + + %disp(cmd) + eval(cmd) + +end + +% --------------------------------- + +% read tile variables + +varnames = {s.Variables.Name}; for kk=1:length(varnames) @@ -35,8 +65,4 @@ end - - - - % ========== EOF =================================================== From ca60151b43c0938a578b02a78f25ca0a89ed406b Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Mon, 27 Jan 2025 07:09:33 -0500 Subject: [PATCH 067/107] renamed matlab tile file reader (single reader for nc4 and ASCII) --- ...ead_tile_file_ASCII.m => read_tile_file.m} | 0 .../util/shared/matlab/read_tile_file_nc4.m | 68 ------------------- 2 files changed, 68 deletions(-) rename GEOSldas_App/util/shared/matlab/{read_tile_file_ASCII.m => read_tile_file.m} (100%) delete mode 100644 GEOSldas_App/util/shared/matlab/read_tile_file_nc4.m diff --git a/GEOSldas_App/util/shared/matlab/read_tile_file_ASCII.m b/GEOSldas_App/util/shared/matlab/read_tile_file.m similarity index 100% rename from GEOSldas_App/util/shared/matlab/read_tile_file_ASCII.m rename to GEOSldas_App/util/shared/matlab/read_tile_file.m diff --git a/GEOSldas_App/util/shared/matlab/read_tile_file_nc4.m b/GEOSldas_App/util/shared/matlab/read_tile_file_nc4.m deleted file mode 100644 index 31fd1d34..00000000 --- a/GEOSldas_App/util/shared/matlab/read_tile_file_nc4.m +++ /dev/null @@ -1,68 +0,0 @@ -function [ tile_coord ] = read_til_file_nc4( fname ) - -% read tile coordinates from nc4 "til" file (EASEv2 and cube-sphere) -% -% reichle, 24 Jan 2025 -% -% ------------------------------------------------------------- - -disp(['reading from ', fname]) - -s = ncinfo( fname ); - -% dimensions - -tile_coord.N_tile = s.Dimensions.Length; - -% --------------------------------- - -% read tile space attributes - -attnames = {s.Attributes.Name}; - -for kk=1:length(attnames) - - this_attname = attnames{kk}; - - % skip select attributes - - if strcmp(this_attname,'NCO' ), continue, end - if strcmp(this_attname,'history'), continue, end - - tmpdata = ncreadatt( fname, '/', this_attname ); - - cmd = ['tile_coord.', this_attname, ' = tmpdata;']; - - %disp(cmd) - eval(cmd) - -end - -% --------------------------------- - -% read tile variables - -varnames = {s.Variables.Name}; - -for kk=1:length(varnames) - - this_varname = varnames{kk}; - - tmpdata = ncread( fname, this_varname ); - - % rename some fields - - if strcmp(this_varname,'pfaf_index' ), this_varname = 'pfaf'; end - if strcmp(this_varname,'i_indg1' ), this_varname = 'i_indg'; end - if strcmp(this_varname,'j_indg1' ), this_varname = 'j_indg'; end - if strcmp(this_varname,'frac_cell1' ), this_varname = 'frac_cell'; end - if strcmp(this_varname,'dummy_index1'), this_varname = 'dummy_index'; end - - cmd = ['tile_coord.', this_varname, ' = tmpdata;']; - - %disp(cmd) - eval(cmd) - -end - -% ========== EOF =================================================== From dd70d8234d691395ffab043771dd7c937642fae8 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Mon, 27 Jan 2025 07:10:36 -0500 Subject: [PATCH 068/107] merged matlab tile file readers for ASCII and nc4 into single matlab script (read_tile_file.m) --- .../util/shared/matlab/read_tile_file.m | 736 ++++++++++-------- 1 file changed, 407 insertions(+), 329 deletions(-) diff --git a/GEOSldas_App/util/shared/matlab/read_tile_file.m b/GEOSldas_App/util/shared/matlab/read_tile_file.m index a092e6af..23122293 100644 --- a/GEOSldas_App/util/shared/matlab/read_tile_file.m +++ b/GEOSldas_App/util/shared/matlab/read_tile_file.m @@ -1,375 +1,453 @@ -function [ tile_coord ] = read_til_file_ASCII( fname_til, fname_catchmentdef ) +function [ tile_coord ] = read_til_file( fname_til, fname_catchmentdef ) -% read tile coordinates from "til" file (EASEv2 and cube-sphere) and +% read tile coordinates from tile file ("til") file (nc4 or ASCII, EASEv2 or cube-sphere) and % put data into tile_coord structure (similar to that defined in GEOSldas) % % inputs: -% fname_til : Name (with full path) of ASCII tile file (see examples below). -% fname_catchmentdef : OPTIONAL, name of matching catchment.def file -% Do NOT specify if tile file is from bcs in new layout; will be -% assembled from fname_til. +% fname_til : Name (with full path) of nc4 or ASCII tile file (see examples below). +% +% fname_catchmentdef : Name of matching catchment.def file. +% OPTIONAL, for use with ASCII tile file from bcs in legacy layout +% (assembled from fname_til if tile file is from bcs in new layout). % % fname_til examples: % '/discover/nobackup/projects/gmao/bcs_shared/fvInput/ExtData/esm/tiles/v12/geometry/EASEv2_M36/EASEv2_M36_964x406.til' % '/discover/nobackup/projects/gmao/bcs_shared/fvInput/ExtData/esm/tiles/v12/geometry/CF0360x6C_DE1440xPE0720/CF0360x6C_DE1440xPE0720-Pfafstetter.til' % -% % IMPORTANT: % This reader is designed to work for bcs versions NL5, v11, v12, and newer (beginning ~2022). % It should be backward-compatible for most older bcs versions, but there is no % expectation that it will work universally across all old and new versions. % -% reichle, 24 Jan 2025 +% reichle, 27 Jan 2025 % % ------------------------------------------------------------- -% determine fname_catchmentdef - -if ~exist('fname_catchmentdef','var') - - ind=strfind(fname_til,'/'); - - % verify that tile file is from bcs in new layout and naming convention - - if ~strcmp( fname_til(ind(end-2)+1:ind(end-1)-1), 'geometry' ) - - error('cannot derive fname_catchmentdef') - - end - - resolution = fname_til(ind(end-1)+1:ind(end)-1); - - fname_catchmentdef = [ fname_til(1:ind(end-2)), 'land/', resolution, '/clsm/catchment.def' ]; - -end - -% ------------------------------------------------------------- -% -% read tile file - disp(['reading from ', fname_til]) -ifp = fopen( fname_til, 'r' ); +% detect nc4 vs ASCII -% ------------------------------------------------------------- -% -% EASE grid tile space? +is_nc4 = 1; -isEASE = 0; - -if ~isempty(findstr('EASE',fname_til)), isEASE=1; end - -% -------------- -% -% determine number of data columns - -if isEASE - - % NOTE: very old EASE versions have N_data_col=8 - % - % between SMAP bcs v001 (through Vv3030) and SMAP bcs v003[a] (from Vv4030), - % a new (9th) column was added in the *.til file - - N_data_col = 9; - -else - - N_data_col = 12; - -end +if ~strcmp(fname_til(end-2:end),'nc4'), is_nc4=0; end % ------------------------------------------------------------- -% -% Number of integers in first header line depends on bcs version: - -N_headerline1 = 4; % for bcs versions after ~2022 -old_versions = { 'Fortuna', ... - 'Ganymed', ... - 'Heracles', ... - 'Icarus', ... - 'Jason', ... - 'DYAMOND2', ... - 'FV3-1_0', ... - 'NL3', ... - 'NL4', ... - }; +if is_nc4 -for kk=1:length(old_versions) + % read nc4 file - if ~isempty( strfind( fname_til, old_versions{kk} )) + s = ncinfo( fname_til ); - N_headerline1 = 3; + % dimensions - disp([ 'detected old bcs version ', old_versions{kk} ]) + tile_coord.N_tile = s.Dimensions.Length; + + % --------------------------------- + + % read tile space attributes + + attnames = {s.Attributes.Name}; + + for kk=1:length(attnames) + + this_attname = attnames{kk}; + + % skip select attributes + + if strcmp(this_attname,'NCO' ), continue, end + if strcmp(this_attname,'history'), continue, end + + tmpdata = ncreadatt( fname_til, '/', this_attname ); + + cmd = ['tile_coord.', this_attname, ' = tmpdata;']; + + %disp(cmd) + eval(cmd) end -end -% make exception for select "new" versions (stored in legacy bcs directory) that would otherwise -% be classified as "old" per the loop above - -new_versions = { 'Icarus-NLv5', ... - 'DYAMOND', ... - }; + % --------------------------------- + + % read tile variables + + varnames = {s.Variables.Name}; + + for kk=1:length(varnames) + + this_varname = varnames{kk}; + + tmpdata = ncread( fname_til, this_varname ); + + % rename some fields + + if strcmp(this_varname,'pfaf_index' ), this_varname = 'pfaf'; end + if strcmp(this_varname,'i_indg1' ), this_varname = 'i_indg'; end + if strcmp(this_varname,'j_indg1' ), this_varname = 'j_indg'; end + if strcmp(this_varname,'frac_cell1' ), this_varname = 'frac_cell'; end + if strcmp(this_varname,'dummy_index1'), this_varname = 'dummy_index'; end + + cmd = ['tile_coord.', this_varname, ' = tmpdata;']; -for kk=1:length(new_versions) + %disp(cmd) + eval(cmd) + + end - if ~isempty( strfind( fname_til, new_versions{kk} )) +else - N_headerline1 = 4; + % ------------------------------------------------------------- + % + % read ASCII file - disp([ 'detected exception for new bcs version ', new_versions{kk} ]) + % determine fname_catchmentdef + + if ~exist('fname_catchmentdef','var') + + ind=strfind(fname_til,'/'); + + % verify that tile file is from bcs in new layout and naming convention + + if ~strcmp( fname_til(ind(end-2)+1:ind(end-1)-1), 'geometry' ) + error('cannot derive fname_catchmentdef; try using optional input argument') + + end + + resolution = fname_til(ind(end-1)+1:ind(end)-1); + + fname_catchmentdef = [ fname_til(1:ind(end-2)), 'land/', resolution, '/clsm/catchment.def' ]; + end -end - -% echo final value of N_headerline1 - -disp(['using N_headerline1 = ', num2str(N_headerline1) ]) - -% ------------------------------------------------------------- -% -% read header - -% header line 1: - -tmpdata = fscanf( ifp, '%f', N_headerline1 ); - -N_tile_tmp = tmpdata(1); - -if N_headerline1==4 - - tile_coord.N_PfafCat = tmpdata(2); - tile_coord.raster_nx = tmpdata(3); - tile_coord.raster_ny = tmpdata(4); - -elseif N_headerline1==3 - - tile_coord.N_PfafCat = NaN; - tile_coord.raster_nx = tmpdata(2); - tile_coord.raster_ny = tmpdata(3); - -end - -% -------------- -% -% header line 2: - -tile_coord.N_grids = fscanf( ifp, '%f', 1 ); - -% verify N_grids (should be 1 for EASE and 2 for non-EASE) - -if isEASE & tile_coord.N_grids~=1, error(['unexpected N_grids for EASE tile space: ', num2str(tile_coord.N_grids)]), end - -if ~isEASE & tile_coord.N_grids~=2, error(['unexpected N_grids for non-EASE tile space: ', num2str(tile_coord.N_grids)]), end - -% Deal with older EASE bcs versions having (useless) header lines for grid 2, -% despite having the correct value of N_grids=1 in header line 2. - -if isEASE & ( ~isempty(findstr('NL3',fname_til)) | ~isempty(findstr('NL4',fname_til)) ) - - tmp_n_grids = 2; - -else - - tmp_n_grids = tile_coord.N_grids; - -end - -% -------------- -% -% header lines 3-5: - -tile_coord.Grid_Name = fscanf( ifp, '%s', 1 ); -tile_coord.IM = fscanf( ifp, '%f', 1 ); -tile_coord.JM = fscanf( ifp, '%f', 1 ); - -% -------------- -% -% header lines 6-8 (if present): - -if tmp_n_grids==2 - - % NOTE: EASE NL3 and NL4 contain additional header lines for second grid, despite (correct) N_grids=1 + + % ------------------------------------------------------------- + % + % read tile file + + disp(['reading from ', fname_til]) + + ifp = fopen( fname_til, 'r' ); + + % ------------------------------------------------------------- + % + % EASE grid tile space? + + isEASE = 0; + + if ~isempty(findstr('EASE',fname_til)), isEASE=1; end + + % -------------- + % + % determine number of data columns + + if isEASE + + % NOTE: very old EASE versions have N_data_col=8 + % + % between SMAP bcs v001 (through Vv3030) and SMAP bcs v003[a] (from Vv4030), + % a new (9th) column was added in the *.til file + + N_data_col = 9; + + else + + N_data_col = 12; + + end + + % ------------------------------------------------------------- + % + % Number of integers in first header line depends on bcs version: + + N_headerline1 = 4; % for bcs versions after ~2022 + + old_versions = { 'Fortuna', ... + 'Ganymed', ... + 'Heracles', ... + 'Icarus', ... + 'Jason', ... + 'DYAMOND2', ... + 'FV3-1_0', ... + 'NL3', ... + 'NL4', ... + }; + + for kk=1:length(old_versions) + + if ~isempty( strfind( fname_til, old_versions{kk} )) + + N_headerline1 = 3; + + disp([ 'detected old bcs version ', old_versions{kk} ]) + + end + end + + % make exception for select "new" versions (stored in legacy bcs directory) that would otherwise + % be classified as "old" per the loop above + + new_versions = { 'Icarus-NLv5', ... + 'DYAMOND', ... + }; + + for kk=1:length(new_versions) + + if ~isempty( strfind( fname_til, new_versions{kk} )) + + N_headerline1 = 4; + + disp([ 'detected exception for new bcs version ', new_versions{kk} ]) + + end + end + + % echo final value of N_headerline1 + + disp(['using N_headerline1 = ', num2str(N_headerline1) ]) + + % ------------------------------------------------------------- + % + % read header + + % header line 1: + + tmpdata = fscanf( ifp, '%f', N_headerline1 ); + + N_tile_tmp = tmpdata(1); - tile_coord.Grid2_Name = fscanf( ifp, '%s', 1 ); - tile_coord.IM2 = fscanf( ifp, '%f', 1 ); + if N_headerline1==4 + + tile_coord.N_PfafCat = tmpdata(2); + tile_coord.raster_nx = tmpdata(3); + tile_coord.raster_ny = tmpdata(4); + + elseif N_headerline1==3 + + tile_coord.N_PfafCat = NaN; + tile_coord.raster_nx = tmpdata(2); + tile_coord.raster_ny = tmpdata(3); + + end + + % -------------- + % + % header line 2: + + tile_coord.N_grids = fscanf( ifp, '%f', 1 ); + + % verify N_grids (should be 1 for EASE and 2 for non-EASE) + + if isEASE & tile_coord.N_grids~=1, error(['unexpected N_grids for EASE tile space: ', num2str(tile_coord.N_grids)]), end + + if ~isEASE & tile_coord.N_grids~=2, error(['unexpected N_grids for non-EASE tile space: ', num2str(tile_coord.N_grids)]), end + + % Deal with older EASE bcs versions having (useless) header lines for grid 2, + % despite having the correct value of N_grids=1 in header line 2. + + if isEASE & ( ~isempty(findstr('NL3',fname_til)) | ~isempty(findstr('NL4',fname_til)) ) + + tmp_n_grids = 2; + + else + + tmp_n_grids = tile_coord.N_grids; + + end + + % -------------- + % + % header lines 3-5: + + tile_coord.Grid_Name = fscanf( ifp, '%s', 1 ); + tile_coord.IM = fscanf( ifp, '%f', 1 ); + tile_coord.JM = fscanf( ifp, '%f', 1 ); + + % -------------- + % + % header lines 6-8 (if present): + + if tmp_n_grids==2 + + % NOTE: EASE NL3 and NL4 contain additional header lines for second grid, despite (correct) N_grids=1 + + tile_coord.Grid2_Name = fscanf( ifp, '%s', 1 ); + tile_coord.IM2 = fscanf( ifp, '%f', 1 ); tile_coord.JM2 = fscanf( ifp, '%f', 1 ); -end - -% -------------- -% -% read data - -tmpdata = fscanf( ifp, '%f' ); - -fclose(ifp); - -disp('done reading "til" file') - -% verify N_tile*N_data_col against number of data read - -if length(tmpdata)~=N_tile_tmp*N_data_col, error('something wrong with N_tile*N_data_col'), end - -% convert into 2d array - -tmpdata = transpose( reshape(tmpdata, [N_data_col, N_tile_tmp]) ); - -% -------------------------------------------------- -% -% assign tile_id -% -% by convention, tile_id is equal to index number of tile in *.til file - -tmp_tileid = transpose(1:N_tile_tmp); - -% -------------------------------------------------- -% -% subset (if requested) - -%ind = find(tmpdata(:,1)==100); % keep only land -%ind = find(tmpdata(:,1)== 19); % keep only lakes -%ind = find(tmpdata(:,1)== 20); % keep only ice -%ind = find(tmpdata(:,1)~= 0); % keep land, lake, landice - -%tmpdata = tmpdata( ind,:); - -%tmp_tileid = tmp_tileid( ind, 1); - -% -------------------------------------------------- -% -% copy data into tile_coord structure - -tile_coord.N_tile = size(tmpdata,1); % number of tiles (assign here in case of subsetting above) - -% the following are universal (for EASE and non-EASE, all tile types) - -tile_coord.tile_id = tmp_tileid; % tile ID - -tile_coord.typ = tmpdata(:, 1); % tile type - -tile_coord.com_lon = tmpdata(:, 3); % center-of-mass longitude of tile -tile_coord.com_lat = tmpdata(:, 4); % center-of-mass latitude of tile - -tile_coord.i_indg = tmpdata(:, 5); % i index of tile on global "atm" (or EASE) grid -tile_coord.j_indg = tmpdata(:, 6); % j index of tile on global "atm" (or EASE) grid -tile_coord.frac_cell = tmpdata(:, 7); % area fraction of "atm" (or EASE) grid cell - -% initialize remaining fields (to be filled below) - -tmpNaN = NaN*ones(tile_coord.N_tile,1); - -tile_coord.min_lon = tmpNaN; % min longitude of tile -tile_coord.max_lon = tmpNaN; % max longitude of tile -tile_coord.min_lat = tmpNaN; % min latitude of tile -tile_coord.max_lat = tmpNaN; % max latitude of tile - -tile_coord.elev = tmpNaN; % elevation of tile - -tile_coord.area = tmpNaN; % area of "atm" grid cell -tile_coord.pfaf = tmpNaN; % index of (hydrological) Pfafstetter catchment -tile_coord.frac_pfaf = tmpNaN; % area fraction of Pfafstetter catchment - -if ~isEASE - - tile_coord.i_indg2 = tmpNaN; % i index of tile on global "ocean" grid (grid 2) - tile_coord.j_indg2 = tmpNaN; % j index of tile on global "ocean" grid (grid 2) - tile_coord.frac_cell2 = tmpNaN; % area fraction of "ocean" grid cell (grid 2) - -end - -% -------------------------------------------------- -% -% get indices for tile types - -ind_land = find( tile_coord.typ == 100); -ind_lake = find( tile_coord.typ == 19); -ind_landice = find( tile_coord.typ == 20); -ind_ocean = find( tile_coord.typ == 0); - -ind_NOTland = find( tile_coord.typ ~= 100); -ind_NOTocean = find( tile_coord.typ ~= 0); - -if isEASE - - col_area = NaN; - col_pfaf = 2; % land tiles only - col_frac_pfaf = NaN; % land tiles only - -else - - col_area = 2; - col_pfaf = 9; % land tiles only - col_frac_pfaf = 11; + end -end - - -if ~isnan(col_area) - - tile_coord.area = tmpdata(:, col_area); % tile area + % -------------- + % + % read data -end - -tile_coord.pfaf( ind_NOTocean) = tmpdata(ind_NOTocean, col_pfaf); - -% ------------------------------------------------- -% -% EASE grid tile file: -% -% column 8: Pfafstetter index (same as column 2) -% column 9: Pfafstetter ID -% -% non-EASE grid tile file: -% -% column 9: i_indg2 [for ocean tiles] *OR* pfaf [for non-ocean tiles] -% column 10: j_indg2 -% column 11: frac_cell2 [for ocean tiles] *OR* frac_pfaf [for non-ocean tiles] -% column 12: dummy_index2 - -if ~isEASE - - tile_coord.frac_pfaf( ind_NOTocean) = tmpdata(ind_NOTocean, col_frac_pfaf); - - tile_coord.i_indg2( ind_ocean) = tmpdata(ind_ocean, 9); - tile_coord.j_indg2( ind_ocean) = tmpdata(ind_ocean, 10); - tile_coord.frac_cell2(ind_ocean) = tmpdata(ind_ocean, 11); - -end - -% ------------------------------------------------- -% -% get additional info from (land-only) "catchment.def" file - -tctmp = read_catchmentdef( fname_catchmentdef ); - -% verify consistency of catchment.def file and tile file - -if tctmp.N_tile~=length(ind_land) - - error('mismatch between tile file and catchment.def file: N_tile') - -end - -if ( any(tile_coord.tile_id(ind_land) - tctmp.tile_id) | ... - any(tile_coord.pfaf( ind_land) - tctmp.pfaf ) ... - ) - - error('mismatch between tile file and catchment.def file: tile_id or pfaf') - -end - -% fill tile_coord with relevant info from catchment.def - -tile_coord.min_lon(ind_land) = tctmp.min_lon; -tile_coord.max_lon(ind_land) = tctmp.max_lon; -tile_coord.min_lat(ind_land) = tctmp.min_lat; -tile_coord.max_lat(ind_land) = tctmp.max_lat; - -tile_coord.elev( ind_land) = tctmp.elev; + tmpdata = fscanf( ifp, '%f' ); + + fclose(ifp); + + disp('done reading "til" file') + + % verify N_tile*N_data_col against number of data read + + if length(tmpdata)~=N_tile_tmp*N_data_col, error('something wrong with N_tile*N_data_col'), end + + % convert into 2d array + + tmpdata = transpose( reshape(tmpdata, [N_data_col, N_tile_tmp]) ); + + % -------------------------------------------------- + % + % assign tile_id + % + % by convention, tile_id is equal to index number of tile in *.til file + + tmp_tileid = transpose(1:N_tile_tmp); + + % -------------------------------------------------- + % + % subset (if requested) + + %ind = find(tmpdata(:,1)==100); % keep only land + %ind = find(tmpdata(:,1)== 19); % keep only lakes + %ind = find(tmpdata(:,1)== 20); % keep only ice + %ind = find(tmpdata(:,1)~= 0); % keep land, lake, landice + + %tmpdata = tmpdata( ind,:); + + %tmp_tileid = tmp_tileid( ind, 1); + + % -------------------------------------------------- + % + % copy data into tile_coord structure + + tile_coord.N_tile = size(tmpdata,1); % number of tiles (assign here in case of subsetting above) + + % the following are universal (for EASE and non-EASE, all tile types) + + tile_coord.tile_id = tmp_tileid; % tile ID + + tile_coord.typ = tmpdata(:, 1); % tile type + + tile_coord.com_lon = tmpdata(:, 3); % center-of-mass longitude of tile + tile_coord.com_lat = tmpdata(:, 4); % center-of-mass latitude of tile + + tile_coord.i_indg = tmpdata(:, 5); % i index of tile on global "atm" (or EASE) grid + tile_coord.j_indg = tmpdata(:, 6); % j index of tile on global "atm" (or EASE) grid + tile_coord.frac_cell = tmpdata(:, 7); % area fraction of "atm" (or EASE) grid cell + + % initialize remaining fields (to be filled below) + + tmpNaN = NaN*ones(tile_coord.N_tile,1); + + tile_coord.min_lon = tmpNaN; % min longitude of tile + tile_coord.max_lon = tmpNaN; % max longitude of tile + tile_coord.min_lat = tmpNaN; % min latitude of tile + tile_coord.max_lat = tmpNaN; % max latitude of tile + + tile_coord.elev = tmpNaN; % elevation of tile + + tile_coord.area = tmpNaN; % area of "atm" grid cell + tile_coord.pfaf = tmpNaN; % index of (hydrological) Pfafstetter catchment + tile_coord.frac_pfaf = tmpNaN; % area fraction of Pfafstetter catchment + + if ~isEASE + + tile_coord.i_indg2 = tmpNaN; % i index of tile on global "ocean" grid (grid 2) + tile_coord.j_indg2 = tmpNaN; % j index of tile on global "ocean" grid (grid 2) + tile_coord.frac_cell2 = tmpNaN; % area fraction of "ocean" grid cell (grid 2) + + end + + % -------------------------------------------------- + % + % get indices for tile types + + ind_land = find( tile_coord.typ == 100); + ind_lake = find( tile_coord.typ == 19); + ind_landice = find( tile_coord.typ == 20); + ind_ocean = find( tile_coord.typ == 0); + + ind_NOTland = find( tile_coord.typ ~= 100); + ind_NOTocean = find( tile_coord.typ ~= 0); + + if isEASE + + col_area = NaN; + col_pfaf = 2; % land tiles only + col_frac_pfaf = NaN; % land tiles only + + else + + col_area = 2; + col_pfaf = 9; % land tiles only + col_frac_pfaf = 11; + + end + + + if ~isnan(col_area) + + tile_coord.area = tmpdata(:, col_area); % tile area + + end + + tile_coord.pfaf( ind_NOTocean) = tmpdata(ind_NOTocean, col_pfaf); + + % ------------------------------------------------- + % + % EASE grid tile file: + % + % column 8: Pfafstetter index (same as column 2) + % column 9: Pfafstetter ID + % + % non-EASE grid tile file: + % + % column 9: i_indg2 [for ocean tiles] *OR* pfaf [for non-ocean tiles] + % column 10: j_indg2 + % column 11: frac_cell2 [for ocean tiles] *OR* frac_pfaf [for non-ocean tiles] + % column 12: dummy_index2 + + if ~isEASE + + tile_coord.frac_pfaf( ind_NOTocean) = tmpdata(ind_NOTocean, col_frac_pfaf); + + tile_coord.i_indg2( ind_ocean) = tmpdata(ind_ocean, 9); + tile_coord.j_indg2( ind_ocean) = tmpdata(ind_ocean, 10); + tile_coord.frac_cell2(ind_ocean) = tmpdata(ind_ocean, 11); + + end + + % ------------------------------------------------- + % + % get additional info from (land-only) "catchment.def" file + + tctmp = read_catchmentdef( fname_catchmentdef ); + + % verify consistency of catchment.def file and tile file + + if tctmp.N_tile~=length(ind_land) + + error('mismatch between tile file and catchment.def file: N_tile') + + end + + if ( any(tile_coord.tile_id(ind_land) - tctmp.tile_id) | ... + any(tile_coord.pfaf( ind_land) - tctmp.pfaf ) ... + ) + + error('mismatch between tile file and catchment.def file: tile_id or pfaf') + + end + + % fill tile_coord with relevant info from catchment.def + + tile_coord.min_lon(ind_land) = tctmp.min_lon; + tile_coord.max_lon(ind_land) = tctmp.max_lon; + tile_coord.min_lat(ind_land) = tctmp.min_lat; + tile_coord.max_lat(ind_land) = tctmp.max_lat; + + tile_coord.elev( ind_land) = tctmp.elev; +end % if is_nc4 % ========== EOF =================================================== From 0a60096de1c07e9a27c1c585a5133efc736b7580 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Mon, 27 Jan 2025 07:26:09 -0500 Subject: [PATCH 069/107] updated CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 390b7899..9e388166 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Updated subroutine read_obs_sm_ASCAT_EUMET() to work with both original and revised file name templates. - Updated subroutines read_obs_sm_ASCAT_EUMET(), read_obs_SMAP_halforbit_Tb(), read_obs_SMOS() and read_obs_MODIS_SCF() with hardcoded time ranges for when observations are available and should be read. - Revised variable names (SHORT_NAME) and descriptions (LONG_NAME) to match M21C file specs. +- Renamed tilecoord%pfaf to %pfaf_index; added matlab tile file reader. ### Fixed From fa232ef9c7ddac203f218943df81b28ad5fbccf7 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Mon, 27 Jan 2025 09:37:20 -0500 Subject: [PATCH 070/107] added matlab reader for catchment.def file; fixed name of tile coord field "pfaf_index" in read_tile_file.m --- .../util/shared/matlab/read_catchmentdef.m | 46 +++++++++++++++++++ .../util/shared/matlab/read_tile_file.m | 25 +++++----- 2 files changed, 58 insertions(+), 13 deletions(-) create mode 100644 GEOSldas_App/util/shared/matlab/read_catchmentdef.m diff --git a/GEOSldas_App/util/shared/matlab/read_catchmentdef.m b/GEOSldas_App/util/shared/matlab/read_catchmentdef.m new file mode 100644 index 00000000..3a12c93d --- /dev/null +++ b/GEOSldas_App/util/shared/matlab/read_catchmentdef.m @@ -0,0 +1,46 @@ +function [tile_coord ] = read_catchmentdef( fname ) + +% read (land) tile properties from "catchment.def" file (EASEv2 and cube-sphere) +% +% reichle, 24 Jan 2025 +% +% ------------------------------------------------------------- + +% read file + +disp(['reading from ', fname]) + +ifp = fopen( fname, 'r' ); + +% read header line + +tmpdata = fscanf( ifp, '%f', 1 ); + +tile_coord.N_tile = tmpdata(1); + +% read rest of data + +tmpdata = fscanf( ifp, '%f' ); + +fclose(ifp); + +disp('done reading "catchment.def" file') + +% -------------------------------------------------- + +% process data + +tmpdata = reshape(tmpdata, [7, tile_coord.N_tile])'; + +tile_coord.tile_id = tmpdata(:,1); +tile_coord.pfaf_index = tmpdata(:,2); + +tile_coord.min_lon = tmpdata(:,3); +tile_coord.max_lon = tmpdata(:,4); +tile_coord.min_lat = tmpdata(:,5); +tile_coord.max_lat = tmpdata(:,6); + +tile_coord.elev = tmpdata(:,7); + +% ========== EOF =================================================== + diff --git a/GEOSldas_App/util/shared/matlab/read_tile_file.m b/GEOSldas_App/util/shared/matlab/read_tile_file.m index 23122293..e4fff6bf 100644 --- a/GEOSldas_App/util/shared/matlab/read_tile_file.m +++ b/GEOSldas_App/util/shared/matlab/read_tile_file.m @@ -81,7 +81,6 @@ % rename some fields - if strcmp(this_varname,'pfaf_index' ), this_varname = 'pfaf'; end if strcmp(this_varname,'i_indg1' ), this_varname = 'i_indg'; end if strcmp(this_varname,'j_indg1' ), this_varname = 'j_indg'; end if strcmp(this_varname,'frac_cell1' ), this_varname = 'frac_cell'; end @@ -346,7 +345,7 @@ tile_coord.elev = tmpNaN; % elevation of tile tile_coord.area = tmpNaN; % area of "atm" grid cell - tile_coord.pfaf = tmpNaN; % index of (hydrological) Pfafstetter catchment + tile_coord.pfaf_index = tmpNaN; % index of (hydrological) Pfafstetter catchment tile_coord.frac_pfaf = tmpNaN; % area fraction of Pfafstetter catchment if ~isEASE @@ -372,14 +371,14 @@ if isEASE col_area = NaN; - col_pfaf = 2; % land tiles only - col_frac_pfaf = NaN; % land tiles only + col_pfafindex = 2; % land tiles only + col_fracpfaf = NaN; % land tiles only else col_area = 2; - col_pfaf = 9; % land tiles only - col_frac_pfaf = 11; + col_pfafindex = 9; % land tiles only + col_fracpfaf = 11; end @@ -390,7 +389,7 @@ end - tile_coord.pfaf( ind_NOTocean) = tmpdata(ind_NOTocean, col_pfaf); + tile_coord.pfaf_index( ind_NOTocean) = tmpdata(ind_NOTocean, col_pfafindex); % ------------------------------------------------- % @@ -401,14 +400,14 @@ % % non-EASE grid tile file: % - % column 9: i_indg2 [for ocean tiles] *OR* pfaf [for non-ocean tiles] + % column 9: i_indg2 [for ocean tiles] *OR* pfaf_index [for non-ocean tiles] % column 10: j_indg2 - % column 11: frac_cell2 [for ocean tiles] *OR* frac_pfaf [for non-ocean tiles] + % column 11: frac_cell2 [for ocean tiles] *OR* frac_pfaf [for non-ocean tiles] % column 12: dummy_index2 if ~isEASE - tile_coord.frac_pfaf( ind_NOTocean) = tmpdata(ind_NOTocean, col_frac_pfaf); + tile_coord.frac_pfaf( ind_NOTocean) = tmpdata(ind_NOTocean, col_fracpfaf); tile_coord.i_indg2( ind_ocean) = tmpdata(ind_ocean, 9); tile_coord.j_indg2( ind_ocean) = tmpdata(ind_ocean, 10); @@ -430,11 +429,11 @@ end - if ( any(tile_coord.tile_id(ind_land) - tctmp.tile_id) | ... - any(tile_coord.pfaf( ind_land) - tctmp.pfaf ) ... + if ( any(tile_coord.tile_id( ind_land) - tctmp.tile_id ) | ... + any(tile_coord.pfaf_index(ind_land) - tctmp.pfaf_index) ... ) - error('mismatch between tile file and catchment.def file: tile_id or pfaf') + error('mismatch between tile file and catchment.def file: tile_id or pfaf_index') end From 3638e93452312e2539f95b98b9ee489c7cb44ea0 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Mon, 27 Jan 2025 17:03:24 -0700 Subject: [PATCH 071/107] further improvements after review --- .../clsm_ensupd_read_obs.F90 | 171 ++++++++---------- GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml | 12 +- 2 files changed, 78 insertions(+), 105 deletions(-) diff --git a/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 4d0d0875..9770e0b3 100644 --- a/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -2205,7 +2205,7 @@ subroutine read_obs_sm_CYGNSS( & ! local variables: - integer, parameter :: max_obs = 50000 ! max number of daily obs read by subroutine (expecting > 6 hr assim window) + integer, parameter :: max_obs = 50000 ! max number of daily obs read by subroutine (assim window <= 24 hr) character(4), parameter :: J2000_epoch_id = 'TT12' ! see date_time_util.F90 character(len=*), parameter :: Iam = 'read_obs_sm_CYGNSS' @@ -2217,26 +2217,26 @@ subroutine read_obs_sm_CYGNSS( & character( 2) :: MM, DD, HH, MI character( 4) :: YYYY - integer :: pos, i, idx, N_obs, j, HHcnt, ind, ii + integer :: i, idx, N_obs, j, ind, ii, dt_obs, obs_hour integer :: ierr, ncid integer :: lon_dimid, lat_dimid, time_dimid, timeslices_dimid, startstop_dimid, lon_dimid_m, lat_dimid_m integer :: sm_d_varid, sm_subd_varid, sigma_d_varid, sigma_subd_varid, timeintervals_varid, lat_varid, lon_varid integer :: N_lon, N_lat, N_time, N_timeslices, N_startstop, N_lon_m, N_lat_m integer :: longitudes_m_varid, latitudes_m_varid, small_SM_range_varid, poor_SMAP_varid, high_ubrmsd_varid, few_obs_varid, low_signal_varid + integer :: start(3), count(3) integer, allocatable :: small_SM_range_flag(:,:), poor_SMAP_flag(:,:), high_ubrmsd_flag(:,:), few_obs_flag(:,:), low_signal_flag(:,:) logical :: file_exists - logical :: HH03, HH09, HH12, HH15, HH21 real, dimension(:), pointer :: tmp_lon(:), tmp_lat(:), tmp_obs(:), tmp_err(:), tmp_jtime(:) integer, dimension(:), pointer :: tmp_tile_num integer, dimension(N_catd) :: N_obs_in_tile - real, allocatable :: sm_d(:,:,:), sm_subd(:,:,:), sigma_d(:,:,:), sigma_subd(:,:,:) real, allocatable :: timeintervals(:,:), latitudes(:,:), longitudes(:,:), tmp_sm(:,:), tmp_sigma(:,:) real, allocatable :: time(:), timeslices(:,:) real, allocatable :: latitudes_m(:,:), longitudes_m(:,:) + real :: date_time_low_hour, date_time_up_hour real :: tmp1_lon(max_obs), tmp1_lat(max_obs), tmp1_obs(max_obs), tmp1_err(max_obs), tmp1_jtime(max_obs) ! ------------------------------------------------------------------- @@ -2247,12 +2247,6 @@ subroutine read_obs_sm_CYGNSS( & found_obs = .false. - HH03 = .false. - HH09 = .false. - HH12 = .false. - HH15 = .false. - HH21 = .false. - ! determine operating time range of sensor if (trim(this_obs_param%descr) == 'CYGNSS_SM_6hr' .or. trim(this_obs_param%descr) == 'CYGNSS_SM_daily') then @@ -2268,64 +2262,57 @@ subroutine read_obs_sm_CYGNSS( & if ( datetime_lt_refdatetime(date_time, date_time_obs_beg) .or. & datetime_lt_refdatetime(date_time_obs_end, date_time) ) return + ! determine if reading daily or subdaily obs + + if (trim(this_obs_param%descr) == 'CYGNSS_SM_daily') then + dt_obs = 24 ! obs frequency in hours + elseif (trim(this_obs_param%descr) == 'CYGNSS_SM_6hr') then + dt_obs = 6 + else + err_msg = 'Unknown obs_param%descr: ' // trim(this_obs_param%descr) + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + end if + ! find the time bounds of the assimilation window ! (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) - - ! establish if assimilation window encompasses 12:00 UTC (daily CYGNSS obs time) + 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) - if (date_time_low%hour < 12 .and. date_time_up%hour >= 12) then - HH12 = .true. - end if - - ! return if assimilating daily obs and HH12 is false - - if (trim(this_obs_param%descr) == 'CYGNSS_SM_daily' .and. .not. HH12) return + ! account for minutes and seconds in date_time_low and date_time_up - ! cygnss sm subdaily observations are for 4 timeslices per day - 00-06, 06-12, 12-18, 18-24 UTC - ! we will assimilate these at 03, 09, 15, 21 UTC + date_time_low_hour = date_time_low%hour + date_time_low%min/60.0 + date_time_low%sec/3600.0 + date_time_up_hour = date_time_up%hour + date_time_up%min/60.0 + date_time_up%sec/3600.0 - HHcnt = 0 + ! deal with assimilation window that spans 0z - if (date_time_low%hour < 3 .and. date_time_up%hour >= 3) then - HH03 = .true. - HHcnt = HHcnt + 1 - end if - if (date_time_low%hour > 21 .and. date_time_up%hour >= 3) then ! wrap-around from previous day for 3 hr < assim window <= 6 hr - HH03 = .true. - HHcnt = HHcnt + 1 - end if - if (date_time_low%hour < 9 .and. date_time_up%hour >= 9) then - HH09 = .true. - HHcnt = HHcnt + 1 - end if - if (date_time_low%hour < 15 .and. date_time_up%hour >= 15) then - HH15 = .true. - HHcnt = HHcnt + 1 - end if - if (date_time_low%hour < 21 .and. date_time_up%hour >= 21) then - HH21 = .true. - HHcnt = HHcnt + 1 - end if - if (date_time_low%hour < 21 .and. date_time_up%hour < 3) then ! wrap-around into next day for 3 hr < assim window <= 6 hr - HH21 = .true. - HHcnt = HHcnt + 1 + if (date_time_low_hour > date_time_up_hour) then + date_time_low_hour = date_time_low_hour - 24.0 end if - ! return if assimilating subdaily obs and no HH is true - - if (trim(this_obs_param%descr) == 'CYGNSS_SM_6hr' .and. .not. (HH03 .or. HH09 .or. HH15 .or. HH21)) return + obs_hour = -9999 + + if (dt_obs == 6) then ! subdaily obs + if (date_time_low_hour < 3.0 .and. date_time_up_hour >= 3.0) then + obs_hour = 3 + elseif (date_time_low_hour < 9.0 .and. date_time_up_hour >= 9.0) then + obs_hour = 9 + elseif (date_time_low_hour < 15.0 .and. date_time_up_hour >= 15.0) then + obs_hour = 15 + elseif (date_time_low_hour < 21.0 .and. date_time_up_hour >= 21.0) then + obs_hour = 21 + end if + else ! daily obs + if (date_time_low_hour < 12.0 .and. date_time_up_hour >= 12.0) then + obs_hour = 12 + end if + end if - ! if assimilation window encompasses more than one time slice, abort + ! return if assimilation window does not encompass any obs - if (HHcnt > 1) then - err_msg = 'Can not assimilate subdaily CYGNSS obs from more than one time slice' - call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) - end if + if (obs_hour < 0) return ! determine filename for CYGNSS obs file @@ -2385,55 +2372,46 @@ subroutine read_obs_sm_CYGNSS( & allocate(tmp_sm( N_lon, N_lat )) allocate(tmp_sigma( N_lon, N_lat )) + ! define the count array for the NetCDF read operations + count = (/ N_lon, N_lat, 1 /) + ! read the variables ierr = nf90_get_var(ncid, timeintervals_varid, timeintervals) ierr = nf90_get_var(ncid, lat_varid, latitudes) ierr = nf90_get_var(ncid, lon_varid, longitudes) - ! read either subdaily or daily soil moisture and sigma variables - if ( trim(this_obs_param%descr) == 'CYGNSS_SM_6hr' ) then + idx = -1 - ! allocate memory for subdaily variables - allocate(sm_subd( N_lon, N_lat, N_timeslices )) - allocate(sigma_subd(N_lon, N_lat, N_timeslices )) - - ! subdaily observations required - ierr = nf90_get_var(ncid, sm_subd_varid, sm_subd) - ierr = nf90_get_var(ncid, sigma_subd_varid, sigma_subd) - - ! find the time slice that corresponds to the assimilation window - idx = -1 + ! read either subdaily or daily soil moisture and sigma variables + + if (dt_obs == 6) then do i = 1, N_timeslices - if ((HH03 .and. timeintervals(1,i) == 0.0 ) .or. & - (HH09 .and. timeintervals(1,i) == 0.25) .or. & - (HH15 .and. timeintervals(1,i) == 0.5 ) .or. & - (HH21 .and. timeintervals(1,i) == 0.75) ) then - idx = i - exit - end if + if ((obs_hour == 3 .and. timeintervals(1,i) == 0.0 ) .or. & + (obs_hour == 9 .and. timeintervals(1,i) == 0.25) .or. & + (obs_hour == 15 .and. timeintervals(1,i) == 0.5 ) .or. & + (obs_hour == 21 .and. timeintervals(1,i) == 0.75) ) then + idx = i + exit + end if end do - if (idx == -1) then - err_msg = 'Error: No matching time interval found for HH = ' // HH - call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) - else - write(*,*) 'Index of matching time interval: ', idx - end if - tmp_sm = sm_subd( :,:,idx) - tmp_sigma = sigma_subd(:,:,idx) - else + if (idx == -1) then + write(err_msg, '(A,I2)') 'Error: No matching time interval found for obs_hour = ', obs_hour + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + endif - ! allocate memory for daily variables - allocate(sm_d( N_lon, N_lat, N_time )) - allocate(sigma_d(N_lon, N_lat, N_time )) + start = (/ 1, 1, idx /) + ierr = nf90_get_var(ncid, sm_subd_varid, tmp_sm, start=start, count=count) + ierr = nf90_get_var(ncid, sigma_subd_varid, tmp_sigma, start=start, count=count) + + else ! daily obs + idx = 1 - ! daily observations required - ierr = nf90_get_var(ncid, sm_d_varid, sm_d) - ierr = nf90_get_var(ncid, sigma_d_varid, sigma_d) - tmp_sm = sm_d( :,:,1) - tmp_sigma = sigma_d(:,:,1) + start = (/ 1, 1, idx /) + ierr = nf90_get_var(ncid, sm_d_varid, tmp_sm, start=start, count=count) + ierr = nf90_get_var(ncid, sigma_d_varid, tmp_sigma, start=start, count=count) - end if + endif ! close the obs file ierr = nf90_close(ncid) @@ -2653,11 +2631,6 @@ subroutine read_obs_sm_CYGNSS( & deallocate(high_ubrmsd_flag) deallocate(few_obs_flag) deallocate(low_signal_flag) - - if (allocated(sm_d)) deallocate(sm_d) - if (allocated(sm_subd)) deallocate(sm_subd) - if (allocated(sigma_d)) deallocate(sigma_d) - if (allocated(sigma_subd)) deallocate(sigma_subd) if (associated(tmp_obs)) deallocate(tmp_obs) if (associated(tmp_lon)) deallocate(tmp_lon) diff --git a/GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml b/GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml index a4bfe27e..c8d4b4b7 100644 --- a/GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml +++ b/GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml @@ -2365,11 +2365,11 @@ obs_param_nml(53)%adapt = 0 ! -------------------------------------------------------------------------------------------------------------- ! -! 54 = CYGNSS_SM (CYGNSS Level 3 soil moisture version 3.2) +! 54 = CYGNSS_SM_6hr (CYGNSS Level 3 soil moisture version 3.2) ! ! https://podaac.jpl.nasa.gov/dataset/CYGNSS_L3_SOIL_MOISTURE_V3.2 -obs_param_nml(54)%descr = 'CYGNSS_SM' +obs_param_nml(54)%descr = 'CYGNSS_SM_6hr' obs_param_nml(54)%orbit = 3 obs_param_nml(54)%pol = 0 obs_param_nml(54)%N_ang = 0 @@ -2394,10 +2394,10 @@ 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 = 0.1 +obs_param_nml(54)%errstd = 0.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)%coarsen_pert = .true. obs_param_nml(54)%xcorr = 0.25 obs_param_nml(54)%ycorr = 0.25 obs_param_nml(54)%adapt = 0 @@ -2433,10 +2433,10 @@ obs_param_nml(55)%scalepath = '' obs_param_nml(55)%scalename = '' obs_param_nml(55)%flistpath = '' obs_param_nml(55)%flistname = '' -obs_param_nml(55)%errstd = 0.1 +obs_param_nml(55)%errstd = 0.04 obs_param_nml(55)%std_normal_max = 2.5 obs_param_nml(55)%zeromean = .true. -obs_param_nml(55)%coarsen_pert = .false. +obs_param_nml(55)%coarsen_pert = .true. obs_param_nml(55)%xcorr = 0.25 obs_param_nml(55)%ycorr = 0.25 obs_param_nml(55)%adapt = 0 From 0800e544e46767b5e7d6aaa9645984a13c795d2e Mon Sep 17 00:00:00 2001 From: saraqzhang Date: Tue, 28 Jan 2025 14:10:36 -0500 Subject: [PATCH 072/107] updates for integrated setup and coupled run of LADAS --- GEOSldas_App/ldas_setup | 40 ++++++++++++++----- GEOSldas_App/lenkf_j_template.py | 5 --- .../LADAS/exeinp.txt.Hy4dEnVar.atmens | 6 ++- .../LADAS/exeinp.txt.Hy4dEnVar.central | 4 +- GEOSldas_App/util/config/rewind_GEOSldas.csh | 24 +++++------ 5 files changed, 50 insertions(+), 29 deletions(-) diff --git a/GEOSldas_App/ldas_setup b/GEOSldas_App/ldas_setup index dfbe28ea..2804c060 100755 --- a/GEOSldas_App/ldas_setup +++ b/GEOSldas_App/ldas_setup @@ -94,6 +94,7 @@ class LDASsetup: exphome_ = cmdLineArgs['exphome'].rstrip('/') assert os.path.isdir(exphome_) # exphome should exist self.exphome = os.path.abspath(exphome_) + self.nymdb = cmdLineArgs[ 'nymdb' ] self.verbose = cmdLineArgs['verbose'] self.runmodel = cmdLineArgs['runmodel'] if self.runmodel : @@ -153,6 +154,9 @@ class LDASsetup: for key in rqdExeInpKeys : assert key in self.rqdExeInp,' "%s" is required in the input file %s' % (key,self.exeinpfile) + if cmdLineArgs['nymdb' ] != 'None' : + self.date = f"{self.nymdb} 210000" + self.rqdExeInp[ 'BEG_DATE' ] = self.date # print rqd exe inputs if self.verbose: @@ -168,8 +172,16 @@ class LDASsetup: self.ladas_coupling = int(self.rqdExeInp.get('LADAS_COUPLING',0)) self.adas_expdir ='' if self.ladas_coupling > 0: - assert 'ADAS_EXPDIR' in self.rqdExeInp, " need ADAS_EXPDIR in the input file %s" %(self.exeinpfile) - self.adas_expdir = self.rqdExeInp['ADAS_EXPDIR'] + self.adas_expdir = os.path.dirname(self.exphome) + self.rqdExeInp['ADAS_EXPDIR'] = self.adas_expdir + self.adas_expid = os.path.basename(self.adas_expdir) + self.rqdExeInp[ 'MET_TAG' ] = self.adas_expid + '__Nx+-' + if self.ladas_coupling == 1: + self.rqdExeInp[ 'EXP_ID' ] = self.adas_expid + '_LDAS' + if self.ladas_coupling == 2: + self.rqdExeInp[ 'EXP_ID' ] = self.adas_expid + '_LDAS4ens' + self.rqdExeInp[ 'MET_PATH' ] = self.adas_expdir +'/atmens/ensdiag/mem' + self.first_ens_id = int(self.rqdExeInp.get('FIRST_ENS_ID',0)) self.perturb = int(self.rqdExeInp.get('PERTURBATIONS',0)) if self.nens > 1: @@ -1112,6 +1124,14 @@ class LDASsetup: sp.call(shlex.split(cmd)) for line in fileinput.input(tmprcfile,inplace=True): print (line.rstrip().replace('GEOSldas_expid',self.rqdExeInp['EXP_ID'])) + if (self.ladas_coupling == 1) : + for line in fileinput.input(tmprcfile,inplace=True): + print (line.rstrip().replace("# 'catch_progn_incr'"," 'catch_progn_incr'")) + for line in fileinput.input(tmprcfile,inplace=True): + print (line.rstrip().replace('catch_progn_incr.ref_time: 000000,','catch_progn_incr.ref_time: 013000,')) + for line in fileinput.input(tmprcfile,inplace=True): + print (line.rstrip().replace("'SMAP_L4_SM_gph'","# 'SMAP_L4_SM_gph'")) + # just copy an empty ExtData.rc if shortfile=='ExtData.rc' : shutil.copy2(rcfile, self.rundir+'/'+shortfile) @@ -1504,11 +1524,6 @@ def _printExeInputKeys(rqdExeInpKeys): print ('# #') print ('# Surface meteorological forcing time step is in seconds. #') print ('# #') - print ('# NOTE: #') - print ('# When forcing is on cube-sphere (CS) grid, must use: #') - print ('# - Model tile space (BCS) derived from same CS grid. #') - print ('# - Nearest-neighbor interpolation (MET_HINTERP: 0). #') - print ('# #') print ('# For more information, see: #') print ('# GEOSldas/doc/README.MetForcing_and_BCS.md #') print ('# #') @@ -1556,11 +1571,11 @@ def _printExeInputKeys(rqdExeInpKeys): 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 ('# ../../../../recycle/holdpredout #') print ('# LADAS_COUPLING = 2: #') - print ('# [ADAS_EXPDIR]/atmens/ensdiag/forc #') + print ('# [ADAS_EXPDIR]/atmens/ensdiag/mem #') print ('# After ldas exp setup, verify the following link: #') - print ('# ../input/met_forcing/forc -> [MET_PATH] #') + print ('# ../input/met_forcing/* -> [MET_PATH] #') print ('# #') print ('# (4) BCS_PATH must be consistent with that of #') print ('# [ADAS_EXPDIR][/run/lnbcs #') @@ -1710,6 +1725,11 @@ def parseCmdLine(): help='replace computing/sponsor account in batinp file', type=str, default='None' ) + p_setup.add_argument( + '--nymdb', + help='replace BEG_DATE in expinp file ', + type=str, default='None' + ) p_setup.add_argument( '--runmodel', help='Obsolete.', diff --git a/GEOSldas_App/lenkf_j_template.py b/GEOSldas_App/lenkf_j_template.py index 0182edb0..7dc9b4e5 100644 --- a/GEOSldas_App/lenkf_j_template.py +++ b/GEOSldas_App/lenkf_j_template.py @@ -179,11 +179,6 @@ setenv GRID $forcgrid $GEOSBIN/enpert_forc.csh cd $SCRDIR - else - - # move central-simulation forcing held in met_forcing to scratch dir - echo "move lfo_Nx+- met forcing from $EXPDIR/input/met_forcing to $SCRDIR" - /bin/mv $EXPDIR/input/met_forcing/*lfo_Nx+-*nc4 $SCRDIR/. endif endif diff --git a/GEOSldas_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.atmens b/GEOSldas_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.atmens index bf4e17a9..b7cbf739 100644 --- a/GEOSldas_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.atmens +++ b/GEOSldas_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.atmens @@ -11,7 +11,9 @@ # ############################################################################## -NUM_LDAS_ENSEMBLE: [NUM_ATM_ENSEMBLE] +EXP_DOMAIN: CF00[ADAS_ATMENS_GRID e.g. 90]x6C_GLOBAL + +NUM_LDAS_ENSEMBLE: [NUM_ATMENS_ENSEMBLE] LADAS_COUPLING: 2 @@ -34,4 +36,6 @@ ENSEMBLE_FORCING: YES JOB_SGMT: 00000000 060000 NUM_SGMT: 1 +HISTRC_FILE: [path of GEOSldas_GridComp/GEOSldas_App/sample_config_files/LADAS]/GEOSldas_HIST.rc.atmens + ################################# EOF ######################################## diff --git a/GEOSldas_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.central b/GEOSldas_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.central index c30c880a..6265f162 100644 --- a/GEOSldas_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.central +++ b/GEOSldas_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.central @@ -11,12 +11,14 @@ # ############################################################################## +EXP_DOMAIN: CF0[ADAS_CENTRAL_GRID e.g. 360]x6C_GLOBAL + LADAS_COUPLING: 1 ADAS_EXPDIR: [full_path]/[ADAS_EXPDIR] MET_TAG: [ADAS_EXPID]__Nx+- -MET_PATH: ../../scratch +MET_PATH: ../../../../recycle/holdpredout # option to use perturbed forcing created from central simulation and atm ensemble # MET_PATH: [ADAS_EXPDIR]/atmens/rgdlfo diff --git a/GEOSldas_App/util/config/rewind_GEOSldas.csh b/GEOSldas_App/util/config/rewind_GEOSldas.csh index a52a1951..38e383e9 100755 --- a/GEOSldas_App/util/config/rewind_GEOSldas.csh +++ b/GEOSldas_App/util/config/rewind_GEOSldas.csh @@ -70,24 +70,24 @@ while ($inens <= $NENS) if ($inens < 10) then set ENSDIR = `echo ens000${inens}` - set catin = `echo catch000${inens}` - set pertin = `echo landpert000${inens}` - set seedin = `echo obspertrseed000${inens}` + set catin = `echo catch_e000${inens}` + set pertin = `echo landpert_e000${inens}` + set seedin = `echo obspertrseed_e000${inens}` else if($inens < 100) then set ENSDIR = `echo ens00${inens}` - set catin = `echo catch00${inens}` - set pertin = `echo landpert00${inens}` - set seedin = `echo obspertrseed00${inens}` + set catin = `echo catch_e00${inens}` + set pertin = `echo landpert_e00${inens}` + set seedin = `echo obspertrseed_e00${inens}` else if($inens < 1000) then set ENSDIR = `echo ens0${inens}` - set catin = `echo catch0${inens}` - set pertin = `echo landpert0${inens}` - set seedin = `echo obspertrseed0${inens}` + set catin = `echo catch_e0${inens}` + set pertin = `echo landpert_e0${inens}` + set seedin = `echo obspertrseed_e0${inens}` else set ENSDIR = `echo ens${inens}` - set catin = `echo catch${inens}` - set pertin = `echo landpert${inens}` - set seedin = `echo obspertrseed${inens}` + set catin = `echo catch_e${inens}` + set pertin = `echo landpert_e${inens}` + set seedin = `echo obspertrseed_e${inens}` endif /bin/ln -s ${rsout}/${ENSDIR}/Y${yin}/M${min}/${expid}.catch_internal_rst.${date} ${catin}_internal_rst From 5496e35d64df5e01820d3b195b3d638712675fe6 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Wed, 29 Jan 2025 13:06:59 -0500 Subject: [PATCH 073/107] in matlab tile file reader, synchronize field names with latest make_bcs commits (read_tile_file.m) --- .../util/shared/matlab/read_tile_file.m | 72 +++++++++---------- 1 file changed, 33 insertions(+), 39 deletions(-) diff --git a/GEOSldas_App/util/shared/matlab/read_tile_file.m b/GEOSldas_App/util/shared/matlab/read_tile_file.m index e4fff6bf..874d6894 100644 --- a/GEOSldas_App/util/shared/matlab/read_tile_file.m +++ b/GEOSldas_App/util/shared/matlab/read_tile_file.m @@ -79,13 +79,6 @@ tmpdata = ncread( fname_til, this_varname ); - % rename some fields - - if strcmp(this_varname,'i_indg1' ), this_varname = 'i_indg'; end - if strcmp(this_varname,'j_indg1' ), this_varname = 'j_indg'; end - if strcmp(this_varname,'frac_cell1' ), this_varname = 'frac_cell'; end - if strcmp(this_varname,'dummy_index1'), this_varname = 'dummy_index'; end - cmd = ['tile_coord.', this_varname, ' = tmpdata;']; %disp(cmd) @@ -232,16 +225,16 @@ % % header line 2: - tile_coord.N_grids = fscanf( ifp, '%f', 1 ); + tile_coord.N_Grids = fscanf( ifp, '%f', 1 ); - % verify N_grids (should be 1 for EASE and 2 for non-EASE) + % verify N_Grids (should be 1 for EASE and 2 for non-EASE) - if isEASE & tile_coord.N_grids~=1, error(['unexpected N_grids for EASE tile space: ', num2str(tile_coord.N_grids)]), end + if isEASE & tile_coord.N_Grids~=1, error(['unexpected N_Grids for EASE tile space: ', num2str(tile_coord.N_Grids)]), end - if ~isEASE & tile_coord.N_grids~=2, error(['unexpected N_grids for non-EASE tile space: ', num2str(tile_coord.N_grids)]), end + if ~isEASE & tile_coord.N_Grids~=2, error(['unexpected N_Grids for non-EASE tile space: ', num2str(tile_coord.N_Grids)]), end % Deal with older EASE bcs versions having (useless) header lines for grid 2, - % despite having the correct value of N_grids=1 in header line 2. + % despite having the correct value of N_Grids=1 in header line 2. if isEASE & ( ~isempty(findstr('NL3',fname_til)) | ~isempty(findstr('NL4',fname_til)) ) @@ -249,7 +242,7 @@ else - tmp_n_grids = tile_coord.N_grids; + tmp_n_grids = tile_coord.N_Grids; end @@ -267,11 +260,12 @@ if tmp_n_grids==2 - % NOTE: EASE NL3 and NL4 contain additional header lines for second grid, despite (correct) N_grids=1 + % NOTE: EASE NL3 and NL4 contain additional header lines for second grid, despite (correct) N_Grids=1 + % For these old versions, read (and then ignore) additional header lines. - tile_coord.Grid2_Name = fscanf( ifp, '%s', 1 ); - tile_coord.IM2 = fscanf( ifp, '%f', 1 ); - tile_coord.JM2 = fscanf( ifp, '%f', 1 ); + tile_coord.Grid_ocn_Name = fscanf( ifp, '%s', 1 ); + tile_coord.IM_ocn = fscanf( ifp, '%f', 1 ); + tile_coord.JM_ocn = fscanf( ifp, '%f', 1 ); end @@ -318,41 +312,41 @@ % % copy data into tile_coord structure - tile_coord.N_tile = size(tmpdata,1); % number of tiles (assign here in case of subsetting above) + tile_coord.N_tile = size(tmpdata,1); % number of tiles (assign here in case of subsetting above) % the following are universal (for EASE and non-EASE, all tile types) - tile_coord.tile_id = tmp_tileid; % tile ID + tile_coord.tile_id = tmp_tileid; % tile ID - tile_coord.typ = tmpdata(:, 1); % tile type + tile_coord.typ = tmpdata(:, 1); % tile type - tile_coord.com_lon = tmpdata(:, 3); % center-of-mass longitude of tile - tile_coord.com_lat = tmpdata(:, 4); % center-of-mass latitude of tile + tile_coord.com_lon = tmpdata(:, 3); % center-of-mass longitude of tile + tile_coord.com_lat = tmpdata(:, 4); % center-of-mass latitude of tile - tile_coord.i_indg = tmpdata(:, 5); % i index of tile on global "atm" (or EASE) grid - tile_coord.j_indg = tmpdata(:, 6); % j index of tile on global "atm" (or EASE) grid - tile_coord.frac_cell = tmpdata(:, 7); % area fraction of "atm" (or EASE) grid cell + tile_coord.i_indg = tmpdata(:, 5); % i index of tile on global "atm" (or EASE) grid + tile_coord.j_indg = tmpdata(:, 6); % j index of tile on global "atm" (or EASE) grid + tile_coord.frac_cell = tmpdata(:, 7); % area fraction of "atm" (or EASE) grid cell % initialize remaining fields (to be filled below) tmpNaN = NaN*ones(tile_coord.N_tile,1); - tile_coord.min_lon = tmpNaN; % min longitude of tile - tile_coord.max_lon = tmpNaN; % max longitude of tile - tile_coord.min_lat = tmpNaN; % min latitude of tile - tile_coord.max_lat = tmpNaN; % max latitude of tile + tile_coord.min_lon = tmpNaN; % min longitude of tile + tile_coord.max_lon = tmpNaN; % max longitude of tile + tile_coord.min_lat = tmpNaN; % min latitude of tile + tile_coord.max_lat = tmpNaN; % max latitude of tile - tile_coord.elev = tmpNaN; % elevation of tile + tile_coord.elev = tmpNaN; % elevation of tile - tile_coord.area = tmpNaN; % area of "atm" grid cell - tile_coord.pfaf_index = tmpNaN; % index of (hydrological) Pfafstetter catchment - tile_coord.frac_pfaf = tmpNaN; % area fraction of Pfafstetter catchment + tile_coord.area = tmpNaN; % area of "atm" grid cell + tile_coord.pfaf_index = tmpNaN; % index of (hydrological) Pfafstetter catchment + tile_coord.frac_pfaf = tmpNaN; % area fraction of Pfafstetter catchment if ~isEASE - tile_coord.i_indg2 = tmpNaN; % i index of tile on global "ocean" grid (grid 2) - tile_coord.j_indg2 = tmpNaN; % j index of tile on global "ocean" grid (grid 2) - tile_coord.frac_cell2 = tmpNaN; % area fraction of "ocean" grid cell (grid 2) + tile_coord.i_indg_ocn = tmpNaN; % i index of tile on global "ocean" grid (grid 2) + tile_coord.j_indg_ocn = tmpNaN; % j index of tile on global "ocean" grid (grid 2) + tile_coord.frac_cell_ocn = tmpNaN; % area fraction of "ocean" grid cell (grid 2) end @@ -409,9 +403,9 @@ tile_coord.frac_pfaf( ind_NOTocean) = tmpdata(ind_NOTocean, col_fracpfaf); - tile_coord.i_indg2( ind_ocean) = tmpdata(ind_ocean, 9); - tile_coord.j_indg2( ind_ocean) = tmpdata(ind_ocean, 10); - tile_coord.frac_cell2(ind_ocean) = tmpdata(ind_ocean, 11); + tile_coord.i_indg_ocn( ind_ocean) = tmpdata(ind_ocean, 9); + tile_coord.j_indg_ocn( ind_ocean) = tmpdata(ind_ocean, 10); + tile_coord.frac_cell_ocn(ind_ocean) = tmpdata(ind_ocean, 11); end From a676245a22d5d241e85306c5446e812cded95ab2 Mon Sep 17 00:00:00 2001 From: Rolf Reichle <54944691+gmao-rreichle@users.noreply.github.com> Date: Thu, 30 Jan 2025 09:09:34 -0500 Subject: [PATCH 074/107] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a99df3a..6ee77c02 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- New update_type for joint 3d soil moisture and 1d snow analysis (Tb+sfmc+sfds+SCF obs). - Added CYGNSS soil moisture reader. - Added M21C surface met forcing. From 0599e292c0c20a074b1c2e5d062f35b3a9230aad Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Thu, 30 Jan 2025 09:35:41 -0500 Subject: [PATCH 075/107] minimal cleanup of CYGNSS obs reader (clsm_ensupd_read_obs.F90) --- .../clsm_ensupd_read_obs.F90 | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 9770e0b3..2e2fd6f5 100644 --- a/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -2222,7 +2222,9 @@ subroutine read_obs_sm_CYGNSS( & integer :: lon_dimid, lat_dimid, time_dimid, timeslices_dimid, startstop_dimid, lon_dimid_m, lat_dimid_m integer :: sm_d_varid, sm_subd_varid, sigma_d_varid, sigma_subd_varid, timeintervals_varid, lat_varid, lon_varid integer :: N_lon, N_lat, N_time, N_timeslices, N_startstop, N_lon_m, N_lat_m - integer :: longitudes_m_varid, latitudes_m_varid, small_SM_range_varid, poor_SMAP_varid, high_ubrmsd_varid, few_obs_varid, low_signal_varid + integer :: longitudes_m_varid, latitudes_m_varid, small_SM_range_varid, poor_SMAP_varid, high_ubrmsd_varid + integer :: few_obs_varid, low_signal_varid + integer :: start(3), count(3) integer, allocatable :: small_SM_range_flag(:,:), poor_SMAP_flag(:,:), high_ubrmsd_flag(:,:), few_obs_flag(:,:), low_signal_flag(:,:) @@ -2230,7 +2232,8 @@ subroutine read_obs_sm_CYGNSS( & real, dimension(:), pointer :: tmp_lon(:), tmp_lat(:), tmp_obs(:), tmp_err(:), 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, allocatable :: timeintervals(:,:), latitudes(:,:), longitudes(:,:), tmp_sm(:,:), tmp_sigma(:,:) real, allocatable :: time(:), timeslices(:,:) @@ -2243,7 +2246,7 @@ subroutine read_obs_sm_CYGNSS( & ! initialize - nullify( tmp_lon, tmp_lat, tmp_obs, tmp_err, tmp_jtime ) + nullify( tmp_lon, tmp_lat, tmp_obs, tmp_err, tmp_jtime, tmp_tile_num ) found_obs = .false. @@ -2281,7 +2284,7 @@ subroutine read_obs_sm_CYGNSS( & date_time_up = date_time call augment_date_time( (dtstep_assim/2), date_time_up) - ! account for minutes and seconds in date_time_low and date_time_up + ! get fractional time-of-day (hours) date_time_low_hour = date_time_low%hour + date_time_low%min/60.0 + date_time_low%sec/3600.0 date_time_up_hour = date_time_up%hour + date_time_up%min/60.0 + date_time_up%sec/3600.0 @@ -2295,17 +2298,17 @@ subroutine read_obs_sm_CYGNSS( & obs_hour = -9999 if (dt_obs == 6) then ! subdaily obs - if (date_time_low_hour < 3.0 .and. date_time_up_hour >= 3.0) then - obs_hour = 3 - elseif (date_time_low_hour < 9.0 .and. date_time_up_hour >= 9.0) then - obs_hour = 9 + if (date_time_low_hour < 3.0 .and. date_time_up_hour >= 3.0) then + obs_hour = 3 + elseif (date_time_low_hour < 9.0 .and. date_time_up_hour >= 9.0) then + obs_hour = 9 elseif (date_time_low_hour < 15.0 .and. date_time_up_hour >= 15.0) then obs_hour = 15 elseif (date_time_low_hour < 21.0 .and. date_time_up_hour >= 21.0) then obs_hour = 21 end if else ! daily obs - if (date_time_low_hour < 12.0 .and. date_time_up_hour >= 12.0) then + if (date_time_low_hour < 12.0 .and. date_time_up_hour >= 12.0) then obs_hour = 12 end if end if @@ -2405,11 +2408,10 @@ subroutine read_obs_sm_CYGNSS( & ierr = nf90_get_var(ncid, sigma_subd_varid, tmp_sigma, start=start, count=count) else ! daily obs - idx = 1 - start = (/ 1, 1, idx /) - ierr = nf90_get_var(ncid, sm_d_varid, tmp_sm, start=start, count=count) - ierr = nf90_get_var(ncid, sigma_d_varid, tmp_sigma, start=start, count=count) + start = (/ 1, 1, 1 /) + ierr = nf90_get_var(ncid, sm_d_varid, tmp_sm, start=start, count=count) + ierr = nf90_get_var(ncid, sigma_d_varid, tmp_sigma, start=start, count=count) endif @@ -2448,7 +2450,6 @@ subroutine read_obs_sm_CYGNSS( & ierr = nf90_inq_varid(ncid, 'flag_few_obs', few_obs_varid) ierr = nf90_inq_varid(ncid, 'flag_low_signal', low_signal_varid) - ! allocate memory for the variables allocate(latitudes_m( N_lon_m, N_lat_m)) allocate(longitudes_m( N_lon_m, N_lat_m)) From d8665db54a0af61d1e8fa5171c2e8c3e7388608a Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Thu, 30 Jan 2025 10:11:56 -0500 Subject: [PATCH 076/107] check that CYGNSS daily and subdaily sm obs are not both assimilated; check that dtstep_assim<=6h for CYGNSS sm obs (clsm_ensupd_read_obs.F90, clsm_ensupd_upd_routines.F90) --- .../clsm_ensupd_read_obs.F90 | 32 ++++++++++++------- .../clsm_ensupd_upd_routines.F90 | 23 +++++++++++++ 2 files changed, 43 insertions(+), 12 deletions(-) diff --git a/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 2e2fd6f5..23675b39 100644 --- a/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -2156,19 +2156,20 @@ subroutine read_obs_sm_CYGNSS( & !--------------------------------------------------------------------- ! - ! Routine to read in CYGNSS soil moisture obs from netCDF files and apply mask. + ! Routine to read CYGNSS soil moisture obs from netCDF file and apply mask. ! https://podaac.jpl.nasa.gov/dataset/CYGNSS_L3_SOIL_MOISTURE_V3.2 - ! CYGNSS soil moisture obs are in volumetric units (m3 m-3) with a spatial - ! resolution of 0.3 Decimal Degrees x 0.37 Decimal Degrees. - ! They are daily files containing daily (obs_param_nml(.)%descr = CYGNSS_SM_daily) - ! and subdaily SM estimates (obs_param_nml(.)%descr = CYGNSS_SM_6hr). The - ! subdaily values are for 6 hr time intervals, 0-6hr, 6-12hr, 12-18hr, 18-24hr. - ! The subdaily values are assimilated at 3z, 9z, 15z, 21z. If the assimilation - ! window is more than 6 hr the code will error out. The daily values are assimilated - ! at 12z. The assumption is that either the daily or subdaily values are assimilated, - ! but the code will assimilate both if in the nml. - ! - ! A. Fox, Jan 2025 + ! CYGNSS soil moisture obs are in volumetric units (m3 m-3) on the + ! 36-km EASEv2 global cylindrical grid. + ! Obs are in files containing daily (obs_param_nml(.)%descr = CYGNSS_SM_daily) + ! and subdaily SM estimates (obs_param_nml(.)%descr = CYGNSS_SM_6hr). + ! Daily values are for 0-24z and assimilated at 12z. + ! Subdaily values are for 6 hr time intervals, 0-6z, 6-12z, 12-18z, and 18-24z + ! and assimilated at 3z, 9z, 15z, 21z. + ! Assimilation window must not be longer than 6 hours. + ! Subroutine read_ens_upd_inputs() ensures that only daily *or* subdaily + ! obs are assimilated. + ! + ! A. Fox, reichle, Jan 2025 ! ! -------------------------------------------------------------------- @@ -2265,6 +2266,13 @@ subroutine read_obs_sm_CYGNSS( & if ( datetime_lt_refdatetime(date_time, date_time_obs_beg) .or. & datetime_lt_refdatetime(date_time_obs_end, date_time) ) return + ! make sure assimilation window is no longer than 6 hours + + if (dtstep_assim>6*60*60) then + err_msg = 'dtstep_assim too long for CYGNSS soil moisture obs' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + end if + ! determine if reading daily or subdaily obs if (trim(this_obs_param%descr) == 'CYGNSS_SM_daily') then diff --git a/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index 0ab23b8c..d078df46 100644 --- a/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -617,7 +617,30 @@ subroutine read_ens_upd_inputs( & end if + ! make sure only sub-daily or daily CYGNSS sm obs are assimilated + k=0 + + do i=1,N_obs_param + + if (obs_param(i)%assim) then + + select case (trim(obs_param(i)%descr)) + + case('CYGNSS_SM_daily','CYGNSS_SM_6hr'); k=k+1 + + end select + + end if + + end do + + if (k>1) then + + err_msg = 'cannot assimilate CYGNSS_SM_daily *and* CYGNSS_SM_6hr' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + + end if ! ------------------------------------------------------------- ! From 220de4ec0b30308376d9d42c558a389c815f20df Mon Sep 17 00:00:00 2001 From: amfox37 Date: Thu, 30 Jan 2025 11:27:16 -0700 Subject: [PATCH 077/107] update obs file location --- GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml b/GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml index c8d4b4b7..b1c1764d 100644 --- a/GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml +++ b/GEOSldas_App/LDASsa_DEFAULT_inputs_ensupd.nml @@ -2386,7 +2386,7 @@ obs_param_nml(54)%bias_tcut = 432000 obs_param_nml(54)%nodata = -9999. obs_param_nml(54)%varname = 'sfmc' obs_param_nml(54)%units = 'm3 m-3' -obs_param_nml(54)%path = '/discover/nobackup/amfox/CYGNSS_obs/' +obs_param_nml(54)%path = '/discover/nobackup/projects/gmao/smap/SMAP_Nature/CYGNSS/' obs_param_nml(54)%name = '' obs_param_nml(54)%maskpath = '' obs_param_nml(54)%maskname = '' @@ -2425,7 +2425,7 @@ obs_param_nml(55)%bias_tcut = 432000 obs_param_nml(55)%nodata = -9999. obs_param_nml(55)%varname = 'sfmc' obs_param_nml(55)%units = 'm3 m-3' -obs_param_nml(55)%path = '/discover/nobackup/amfox/CYGNSS_obs/' +obs_param_nml(55)%path = '/discover/nobackup/projects/gmao/smap/SMAP_Nature/CYGNSS/' obs_param_nml(55)%name = '' obs_param_nml(55)%maskpath = '' obs_param_nml(55)%maskname = '' From e2747183fc6ab31675c121e8bd2ca48c374c9a50 Mon Sep 17 00:00:00 2001 From: amfox37 Date: Thu, 30 Jan 2025 11:29:15 -0700 Subject: [PATCH 078/107] update flag values and tolerance in float compare --- .../clsm_ensupd_read_obs.F90 | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 23675b39..98f9c74b 100644 --- a/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -2209,6 +2209,7 @@ subroutine read_obs_sm_CYGNSS( & integer, parameter :: max_obs = 50000 ! max number of daily obs read by subroutine (assim window <= 24 hr) character(4), parameter :: J2000_epoch_id = 'TT12' ! see date_time_util.F90 character(len=*), parameter :: Iam = 'read_obs_sm_CYGNSS' + real, parameter :: tolerance = 1.0e-6 ! tolerance for floating point comparisons type(date_time_type) :: date_time_obs_beg, date_time_obs_end type(date_time_type) :: date_time_up, date_time_low @@ -2224,7 +2225,7 @@ subroutine read_obs_sm_CYGNSS( & integer :: sm_d_varid, sm_subd_varid, sigma_d_varid, sigma_subd_varid, timeintervals_varid, lat_varid, lon_varid integer :: N_lon, N_lat, N_time, N_timeslices, N_startstop, N_lon_m, N_lat_m integer :: longitudes_m_varid, latitudes_m_varid, small_SM_range_varid, poor_SMAP_varid, high_ubrmsd_varid - integer :: few_obs_varid, low_signal_varid + integer :: few_obs_varid, low_signal_varid, good_flag_value integer :: start(3), count(3) integer, allocatable :: small_SM_range_flag(:,:), poor_SMAP_flag(:,:), high_ubrmsd_flag(:,:), few_obs_flag(:,:), low_signal_flag(:,:) @@ -2397,10 +2398,10 @@ subroutine read_obs_sm_CYGNSS( & if (dt_obs == 6) then do i = 1, N_timeslices - if ((obs_hour == 3 .and. timeintervals(1,i) == 0.0 ) .or. & - (obs_hour == 9 .and. timeintervals(1,i) == 0.25) .or. & - (obs_hour == 15 .and. timeintervals(1,i) == 0.5 ) .or. & - (obs_hour == 21 .and. timeintervals(1,i) == 0.75) ) then + if ((obs_hour == 3 .and. (abs(timeintervals(1,i) - 0.0 ) < tolerance)) .or. & + (obs_hour == 9 .and. (abs(timeintervals(1,i) - 0.25) < tolerance)) .or. & + (obs_hour == 15 .and. (abs(timeintervals(1,i) - 0.5 ) < tolerance)) .or. & + (obs_hour == 21 .and. (abs(timeintervals(1,i) - 0.75) < tolerance)) ) then idx = i exit end if @@ -2485,17 +2486,19 @@ subroutine read_obs_sm_CYGNSS( & call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) end if + good_flag_value = 255 ! should really be 0 but is 255 because of unsigned v. signed byte issues + ! fill tmp arrays N_obs = 0 do i = 1, N_lon do j = 1, N_lat - if (tmp_sm(i,j) .ne. this_obs_param%nodata .and. & - small_SM_range_flag(i,j) .ne. 1 .and. & - poor_SMAP_flag(i,j) .ne. 1 .and. & - high_ubrmsd_flag(i,j) .ne. 1 .and. & - few_obs_flag(i,j) .ne. 1 .and. & - low_signal_flag(i,j) .ne. 1 ) then + if (tmp_sm(i,j) .ne. this_obs_param%nodata .and. & + small_SM_range_flag(i,j) == good_flag_value .and. & + poor_SMAP_flag(i,j) == good_flag_value .and. & + high_ubrmsd_flag(i,j) == good_flag_value .and. & + few_obs_flag(i,j) == good_flag_value .and. & + low_signal_flag(i,j) == good_flag_value ) then ! valid observation N_obs = N_obs + 1 From 9a1d6edff9c3eca9bc31e5f2b56dcc8bc6e5050b Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Fri, 31 Jan 2025 11:31:23 -0500 Subject: [PATCH 079/107] for CYGNSS sm obs, added call to scale_obs_sfmc_zscore() (clsm_ensupd_read_obs.F90) --- .../clsm_ensupd_read_obs.F90 | 116 +++++++++--------- 1 file changed, 59 insertions(+), 57 deletions(-) diff --git a/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 98f9c74b..22ab792d 100644 --- a/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -9098,65 +9098,67 @@ subroutine read_obs( & case ('ASCAT_SM_A', 'ASCAT_SM_D' ) - - call read_obs_sm_ASCAT( & - 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 - + + call read_obs_sm_ASCAT( & + 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 ('ASCAT_META_SM','ASCAT_METB_SM','ASCAT_METC_SM' ) - - 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, & - this_obs_param, & - found_obs, tmp_obs, tmp_std_obs, tmp_lon, tmp_lat, & - tmp_time) - - ! scale observations to model climatology - - if (this_obs_param%scale .and. found_obs) then - - scaled_obs = .true. - - 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 - + + 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, & + this_obs_param, & + found_obs, tmp_obs, tmp_std_obs, tmp_lon, tmp_lat, & + tmp_time) + + ! scale observations to model climatology + + if (this_obs_param%scale .and. found_obs) then + + scaled_obs = .true. + + 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 + case ('CYGNSS_SM_6hr','CYGNSS_SM_daily') - - call read_obs_sm_CYGNSS( & - 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) - - ! scale observations to model climatology - - if (this_obs_param%scale .and. found_obs) then - - scaled_obs = .true. - - ! TODO: implement scaling for CYGNSS obs - - end if - + + call read_obs_sm_CYGNSS( & + 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) + + ! scale observations to model climatology + + if (this_obs_param%scale .and. found_obs) then + + scaled_obs = .true. + + 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 + case ('isccp_tskin_gswp2_v1') call read_obs_isccp_tskin_gswp2_v1( & From 7fe7a898aad5dbed6cd1378e84187e270c9cb7c8 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Fri, 7 Feb 2025 13:43:21 -0500 Subject: [PATCH 080/107] fixed loss of some text from underlying develop version of ldas_setup --- GEOSldas_App/ldas_setup | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/GEOSldas_App/ldas_setup b/GEOSldas_App/ldas_setup index 2804c060..50442aa1 100755 --- a/GEOSldas_App/ldas_setup +++ b/GEOSldas_App/ldas_setup @@ -1524,6 +1524,11 @@ def _printExeInputKeys(rqdExeInpKeys): print ('# #') print ('# Surface meteorological forcing time step is in seconds. #') print ('# #') + print ('# NOTE: #') + print ('# When forcing is on cube-sphere (CS) grid, must use: #') + print ('# - Model tile space (BCS) derived from same CS grid. #') + print ('# - Nearest-neighbor interpolation (MET_HINTERP: 0). #') + print ('# #') print ('# For more information, see: #') print ('# GEOSldas/doc/README.MetForcing_and_BCS.md #') print ('# #') From 76795ca7afaafd6890a8b5294eccd116359be25e Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Fri, 7 Feb 2025 14:16:20 -0500 Subject: [PATCH 081/107] minimal cleanup re. LADAS coupling (ldas_setup, exeinp.txt.Hy4dEnVar.*) --- GEOSldas_App/ldas_setup | 6 ++---- .../sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.atmens | 3 ++- .../sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.central | 3 ++- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/GEOSldas_App/ldas_setup b/GEOSldas_App/ldas_setup index 50442aa1..6de77923 100755 --- a/GEOSldas_App/ldas_setup +++ b/GEOSldas_App/ldas_setup @@ -173,7 +173,7 @@ class LDASsetup: self.adas_expdir ='' if self.ladas_coupling > 0: self.adas_expdir = os.path.dirname(self.exphome) - self.rqdExeInp['ADAS_EXPDIR'] = self.adas_expdir + self.rqdExeInp[ 'ADAS_EXPDIR'] = self.adas_expdir self.adas_expid = os.path.basename(self.adas_expdir) self.rqdExeInp[ 'MET_TAG' ] = self.adas_expid + '__Nx+-' if self.ladas_coupling == 1: @@ -1576,11 +1576,9 @@ def _printExeInputKeys(rqdExeInpKeys): 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 ('# ../../../../recycle/holdpredout #') + print ('# ../../../../recycle/holdpredout/ #') print ('# LADAS_COUPLING = 2: #') print ('# [ADAS_EXPDIR]/atmens/ensdiag/mem #') - print ('# After ldas exp setup, verify the following link: #') - print ('# ../input/met_forcing/* -> [MET_PATH] #') print ('# #') print ('# (4) BCS_PATH must be consistent with that of #') print ('# [ADAS_EXPDIR][/run/lnbcs #') diff --git a/GEOSldas_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.atmens b/GEOSldas_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.atmens index b7cbf739..4e95f58d 100644 --- a/GEOSldas_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.atmens +++ b/GEOSldas_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.atmens @@ -11,7 +11,8 @@ # ############################################################################## -EXP_DOMAIN: CF00[ADAS_ATMENS_GRID e.g. 90]x6C_GLOBAL +# e.g., ATMENS_AGCM_GRID = CF0090x6C +EXP_DOMAIN: [ATMENS_AGCM_GRID]_GLOBAL NUM_LDAS_ENSEMBLE: [NUM_ATMENS_ENSEMBLE] diff --git a/GEOSldas_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.central b/GEOSldas_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.central index 6265f162..b25e5105 100644 --- a/GEOSldas_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.central +++ b/GEOSldas_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.central @@ -11,7 +11,8 @@ # ############################################################################## -EXP_DOMAIN: CF0[ADAS_CENTRAL_GRID e.g. 360]x6C_GLOBAL +# e.g., CENTRAL_AGCM_GRID = CF0360x6C +EXP_DOMAIN: [CENTRAL_AGCM_GRID]_GLOBAL LADAS_COUPLING: 1 From 1d416fa7a3a4e485e2ea0b13624512cadce7c11b Mon Sep 17 00:00:00 2001 From: saraqzhang Date: Wed, 12 Feb 2025 20:26:32 -0500 Subject: [PATCH 082/107] first iteration of changes for the option of using bkg lfo in ladas modified: GEOSldas_App/ldas_setup modified: GEOSmetforce_GridComp/LDAS_Forcing.F90 --- GEOSldas_App/ldas_setup | 32 +++++++--- GEOSmetforce_GridComp/LDAS_Forcing.F90 | 82 ++++++++++++++++++++++---- 2 files changed, 96 insertions(+), 18 deletions(-) diff --git a/GEOSldas_App/ldas_setup b/GEOSldas_App/ldas_setup index 6de77923..b3af3caf 100755 --- a/GEOSldas_App/ldas_setup +++ b/GEOSldas_App/ldas_setup @@ -94,7 +94,9 @@ class LDASsetup: exphome_ = cmdLineArgs['exphome'].rstrip('/') assert os.path.isdir(exphome_) # exphome should exist self.exphome = os.path.abspath(exphome_) - self.nymdb = cmdLineArgs[ 'nymdb' ] + self.nymdb = cmdLineArgs['nymdb'] + self.nhmsb = cmdLineArgs['nhmsb'] + self.lfotag = cmdLineArgs['lfotag'] self.verbose = cmdLineArgs['verbose'] self.runmodel = cmdLineArgs['runmodel'] if self.runmodel : @@ -154,9 +156,11 @@ class LDASsetup: for key in rqdExeInpKeys : assert key in self.rqdExeInp,' "%s" is required in the input file %s' % (key,self.exeinpfile) - if cmdLineArgs['nymdb' ] != 'None' : - self.date = f"{self.nymdb} 210000" + if cmdLineArgs['nymdb'] != 'None' and cmdLineArgs['nhmsb'] != 'None' : + self.date = f"{self.nymdb} {self.nhmsb}" self.rqdExeInp[ 'BEG_DATE' ] = self.date + if cmdLineArgs['lfotag' ] != 'None' : + self.lfotag = f"{self.lfotag}" # print rqd exe inputs if self.verbose: @@ -171,16 +175,20 @@ class LDASsetup: _mydir = None self.ladas_coupling = int(self.rqdExeInp.get('LADAS_COUPLING',0)) self.adas_expdir ='' - if self.ladas_coupling > 0: + if self.ladas_coupling > 0 : self.adas_expdir = os.path.dirname(self.exphome) self.rqdExeInp[ 'ADAS_EXPDIR'] = self.adas_expdir self.adas_expid = os.path.basename(self.adas_expdir) self.rqdExeInp[ 'MET_TAG' ] = self.adas_expid + '__Nx+-' - if self.ladas_coupling == 1: + if self.lfotag == 'bkg' : + self.rqdExeInp[ 'MET_TAG' ] = self.adas_expid + '__bkg' + if self.ladas_coupling == 1 : self.rqdExeInp[ 'EXP_ID' ] = self.adas_expid + '_LDAS' - if self.ladas_coupling == 2: + if self.ladas_coupling == 2 : self.rqdExeInp[ 'EXP_ID' ] = self.adas_expid + '_LDAS4ens' self.rqdExeInp[ 'MET_PATH' ] = self.adas_expdir +'/atmens/ensdiag/mem' + if self.lfotag == 'bkg' : + self.rqdExeInp[ 'MET_PATH' ] = self.adas_expdir +'/atmens/mem' self.first_ens_id = int(self.rqdExeInp.get('FIRST_ENS_ID',0)) self.perturb = int(self.rqdExeInp.get('PERTURBATIONS',0)) @@ -1730,7 +1738,17 @@ def parseCmdLine(): ) p_setup.add_argument( '--nymdb', - help='replace BEG_DATE in expinp file ', + help='replaces BEG_DATE date in exeinp file ', + type=str, default='None' + ) + p_setup.add_argument( + '--nhmsb', + help='replaces BEG_DATE time in exeinp file ', + type=str, default='None' + ) + p_setup.add_argument( + '--lfotag', + help='use adas bkg lfo forcing ', type=str, default='None' ) p_setup.add_argument( diff --git a/GEOSmetforce_GridComp/LDAS_Forcing.F90 b/GEOSmetforce_GridComp/LDAS_Forcing.F90 index 6ac6a58f..11b1b366 100755 --- a/GEOSmetforce_GridComp/LDAS_Forcing.F90 +++ b/GEOSmetforce_GridComp/LDAS_Forcing.F90 @@ -3093,7 +3093,6 @@ subroutine get_GEOS( date_time, force_dtstep, met_path, met_tag, & ! qliu+reichle, 5 Dec 2023 - added GEOS-IT ! ! rreichle, 18 Dec 2024 - added M21C - ! ! ----------------------------------- ! ! Read surface met forcing from MERRA, MERRA-2 or GEOS-5 DAS (i.e., FP) based on parsing of "met_tag". @@ -3173,7 +3172,8 @@ 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) :: G5DAS_defs + character(40), dimension(N_G5DAS_vars, N_defs_cols) :: G5LADAS_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 @@ -3212,7 +3212,7 @@ subroutine get_GEOS( date_time, force_dtstep, met_path, met_tag, & integer :: j, k, GEOSgcm_var, fid, km, lm, nvars, ngatts, rc, YYYYMMDD, HHMMSS - logical :: minimize_shift, use_prec_corr, use_Predictor, tmp_init + logical :: minimize_shift, use_prec_corr, use_Predictor, use_bkg,tmp_init logical :: daily_met_files, daily_precipcorr_files @@ -3252,6 +3252,46 @@ 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 LADAS file specs + ! + ! same as G5DAS except for file tag (column 3) + + G5LADAS_defs = G5DAS_defs + + ! character(40): + ! 1 2 3 4 + ! 1234567890123456789012345678901234567890 + + G5LADAS_defs( 1,3) = 'bkg.tavg1_2d_lfo ' + G5LADAS_defs( 2,3) = 'bkg.tavg1_2d_lfo ' + G5LADAS_defs( 3,3) = 'bkg.tavg1_2d_lfo ' + G5LADAS_defs( 4,3) = 'bkg.tavg1_2d_lfo ' + G5LADAS_defs( 5,3) = 'bkg.tavg1_2d_lfo ' + G5LADAS_defs( 6,3) = 'bkg.tavg1_2d_lfo ' + G5LADAS_defs( 7,3) = 'bkg.tavg1_2d_lfo ' + G5LADAS_defs( 8,3) = 'bkg.inst1_2d_lfo ' + G5LADAS_defs( 9,3) = 'bkg.inst1_2d_lfo ' + G5LADAS_defs(10,3) = 'bkg.inst1_2d_lfo ' + G5LADAS_defs(11,3) = 'bkg.inst1_2d_lfo ' + G5LADAS_defs(12,3) = 'bkg.inst1_2d_lfo ' + + G5LADAS_defs( 1,4) = 'rs ' + G5LADAS_defs( 2,4) = 'rs ' + G5LADAS_defs( 3,4) = 'rs ' + G5LADAS_defs( 4,4) = 'rs ' + G5LADAS_defs( 5,4) = 'rs ' + G5LADAS_defs( 6,4) = 'rs ' + G5LADAS_defs( 7,4) = 'rs ' + G5LADAS_defs( 8,4) = 'rs ' + G5LADAS_defs( 9,4) = 'rs ' + G5LADAS_defs(10,4) = 'rs ' + G5LADAS_defs(11,4) = 'rs ' + G5LADAS_defs(12,4) = 'rs ' + + ! ----------------------------------------------------------------------- ! ! define GEOS-IT file specs @@ -3739,6 +3779,7 @@ 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 else @@ -3747,15 +3788,15 @@ subroutine get_GEOS( date_time, force_dtstep, met_path, met_tag, & 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 ) + use_Predictor, use_bkg ) call parse_G5DAS_met_tag( met_path, met_tag, date_time_fwd, & met_path_fwd, prec_path_fwd, met_tag_fwd, use_prec_corr, & - use_Predictor ) + use_Predictor, use_bkg ) call parse_G5DAS_met_tag( met_path, met_tag, date_time_bkwd, & met_path_bkwd, prec_path_bkwd, met_tag_bkwd, use_prec_corr, & - use_Predictor ) + use_Predictor, use_bkg ) if (use_Predictor) then @@ -3768,6 +3809,17 @@ subroutine get_GEOS( date_time, force_dtstep, met_path, met_tag, & end do end if + + if (use_bkg) then + + do j=1,N_GEOSgcm_vars + + GEOSgcm_defs(j,3) = G5LADAS_defs(j,3) + GEOSgcm_defs(j,4) = G5LADAS_defs(j,4) + + end do + + end if end if @@ -4918,7 +4970,7 @@ end subroutine parse_M21C_met_tag subroutine parse_G5DAS_met_tag( met_path_in, met_tag_in, date_time, & met_path_default, met_path_prec, met_tag_out, use_prec_corr, & - use_Predictor ) + use_Predictor, use_bkg ) ! parse G5DAS "met_tag" ! @@ -4949,7 +5001,7 @@ subroutine parse_G5DAS_met_tag( met_path_in, met_tag_in, date_time, & ! 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 - ! + ! sqz Jan 2025: added G5DAS bkg ! --------------------------------------------------------------------------- implicit none @@ -4964,6 +5016,7 @@ subroutine parse_G5DAS_met_tag( met_path_in, met_tag_in, date_time, & logical, intent(out) :: use_prec_corr logical, intent(out) :: use_Predictor + logical, intent(out) :: use_bkg ! local variables @@ -5219,6 +5272,8 @@ subroutine parse_G5DAS_met_tag( met_path_in, met_tag_in, date_time, & use_Predictor = .false. + use_bkg = .false. + ! ----------------------------------------------------- ! ! identify "GCM" tag and whether to use precip corrections and/or @@ -5405,8 +5460,11 @@ subroutine parse_G5DAS_met_tag( met_path_in, met_tag_in, date_time, & use_Predictor = .true. - else - + elseif (tmp_tag(ii)(1:3)=='bkg') then + + use_bkg = .true. + + else err_msg = 'invalid met_tag_in, unknown optional tag segment' call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) @@ -5585,7 +5643,6 @@ subroutine get_GEOS_forcing_filename(fname_full,file_exists, date_time, daily_fi fname_full_tmp2 = trim(fname_full) ! remember for error log below - ! last try: for GEOS FP with generic file names, try product counter '.V02.' in year/month/day dir if (trim(met_tag(1:11))=='GEOS.fp.asm') then @@ -6634,6 +6691,7 @@ program ut_parse_G5DAS_met_tag logical :: use_prec_corr logical :: use_Predictor + logical :: use_bkg ! other @@ -6646,6 +6704,7 @@ program ut_parse_G5DAS_met_tag met_tag_in_vec = (/ & 'gcmexpname' , & 'gcmexpname__Nx+-' , & + 'gcmexpname__bkg' , & 'gcmexpname__precCORRPREC', & 'gcmexpname__precCORRPREC__Nx+-' , & 'gcmexpname__Nx+-__precCORRPREC' , & @@ -6668,6 +6727,7 @@ program ut_parse_G5DAS_met_tag write (*,*) 'met_tag_out = ', trim(met_tag_out) write (*,*) 'use_prec_corr = ', use_prec_corr write (*,*) 'use_Predictor = ', use_Predictor + write (*,*) 'use_bkg = ', use_bkg end do From 3614242d3360b8e9f9d4115efecbd71afedf736a Mon Sep 17 00:00:00 2001 From: saraqzhang Date: Tue, 25 Feb 2025 14:55:57 -0500 Subject: [PATCH 083/107] for ladas lfo with bkg tag,and use HISTdet.rc, HISTens.rc modified: GEOSldas_App/ldas_setup --- GEOSldas_App/ldas_setup | 43 +++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/GEOSldas_App/ldas_setup b/GEOSldas_App/ldas_setup index b3af3caf..47198940 100755 --- a/GEOSldas_App/ldas_setup +++ b/GEOSldas_App/ldas_setup @@ -96,7 +96,6 @@ class LDASsetup: self.exphome = os.path.abspath(exphome_) self.nymdb = cmdLineArgs['nymdb'] self.nhmsb = cmdLineArgs['nhmsb'] - self.lfotag = cmdLineArgs['lfotag'] self.verbose = cmdLineArgs['verbose'] self.runmodel = cmdLineArgs['runmodel'] if self.runmodel : @@ -159,8 +158,6 @@ class LDASsetup: if cmdLineArgs['nymdb'] != 'None' and cmdLineArgs['nhmsb'] != 'None' : self.date = f"{self.nymdb} {self.nhmsb}" self.rqdExeInp[ 'BEG_DATE' ] = self.date - if cmdLineArgs['lfotag' ] != 'None' : - self.lfotag = f"{self.lfotag}" # print rqd exe inputs if self.verbose: @@ -179,16 +176,12 @@ class LDASsetup: self.adas_expdir = os.path.dirname(self.exphome) self.rqdExeInp[ 'ADAS_EXPDIR'] = self.adas_expdir self.adas_expid = os.path.basename(self.adas_expdir) - self.rqdExeInp[ 'MET_TAG' ] = self.adas_expid + '__Nx+-' - if self.lfotag == 'bkg' : - self.rqdExeInp[ 'MET_TAG' ] = self.adas_expid + '__bkg' + self.rqdExeInp[ 'MET_TAG' ] = self.adas_expid + '__bkg' if self.ladas_coupling == 1 : self.rqdExeInp[ 'EXP_ID' ] = self.adas_expid + '_LDAS' if self.ladas_coupling == 2 : self.rqdExeInp[ 'EXP_ID' ] = self.adas_expid + '_LDAS4ens' - self.rqdExeInp[ 'MET_PATH' ] = self.adas_expdir +'/atmens/ensdiag/mem' - if self.lfotag == 'bkg' : - self.rqdExeInp[ 'MET_PATH' ] = self.adas_expdir +'/atmens/mem' + self.rqdExeInp[ 'MET_PATH' ] = self.adas_expdir +'/atmens/mem' self.first_ens_id = int(self.rqdExeInp.get('FIRST_ENS_ID',0)) self.perturb = int(self.rqdExeInp.get('PERTURBATIONS',0)) @@ -1132,13 +1125,22 @@ class LDASsetup: sp.call(shlex.split(cmd)) for line in fileinput.input(tmprcfile,inplace=True): print (line.rstrip().replace('GEOSldas_expid',self.rqdExeInp['EXP_ID'])) - if (self.ladas_coupling == 1) : - for line in fileinput.input(tmprcfile,inplace=True): - print (line.rstrip().replace("# 'catch_progn_incr'"," 'catch_progn_incr'")) - for line in fileinput.input(tmprcfile,inplace=True): - print (line.rstrip().replace('catch_progn_incr.ref_time: 000000,','catch_progn_incr.ref_time: 013000,')) - for line in fileinput.input(tmprcfile,inplace=True): - print (line.rstrip().replace("'SMAP_L4_SM_gph'","# 'SMAP_L4_SM_gph'")) + + # take HISTdet or HISTens if ladas + if shortfile =='HISTdet.rc' and self.ladas_coupling == 1 : + tmprcfile=self.rundir+'/HISTORY.rc' + histrc_file=rcfile + shutil.copy2(rcfile, tmprcfile) + for line in fileinput.input(tmprcfile,inplace=True): + print (line.rstrip().replace('GEOSldas_expid',self.rqdExeInp['EXP_ID'])) + for line in fileinput.input(tmprcfile,inplace=True): + print (line.rstrip().replace('GEOSldas_expid',self.rqdExeInp['EXP_ID'])) + if shortfile =='HISTens.rc' and self.ladas_coupling == 2 : + tmprcfile=self.rundir+'/HISTORY.rc' + histrc_file=rcfile + shutil.copy2(rcfile, tmprcfile) + 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' : @@ -1581,12 +1583,12 @@ def _printExeInputKeys(rqdExeInpKeys): 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 ('# (3) MET_TAG must be set to [ADAS_EXPID]__bkg #') print ('# MET_PATH must be set as follows for #') print ('# LADAS_COUPLING = 1: #') print ('# ../../../../recycle/holdpredout/ #') print ('# LADAS_COUPLING = 2: #') - print ('# [ADAS_EXPDIR]/atmens/ensdiag/mem #') + print ('# [ADAS_EXPDIR]/atmens/mem #') print ('# #') print ('# (4) BCS_PATH must be consistent with that of #') print ('# [ADAS_EXPDIR][/run/lnbcs #') @@ -1746,11 +1748,6 @@ def parseCmdLine(): help='replaces BEG_DATE time in exeinp file ', type=str, default='None' ) - p_setup.add_argument( - '--lfotag', - help='use adas bkg lfo forcing ', - type=str, default='None' - ) p_setup.add_argument( '--runmodel', help='Obsolete.', From e622d0f3553d3951c77d0f9cc88326992af1bd57 Mon Sep 17 00:00:00 2001 From: saraqzhang Date: Tue, 25 Feb 2025 15:02:34 -0500 Subject: [PATCH 084/107] new file: GEOSldas_HISTdet.rc --- GEOSldas_App/GEOSldas_HISTdet.rc | 70 ++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 GEOSldas_App/GEOSldas_HISTdet.rc diff --git a/GEOSldas_App/GEOSldas_HISTdet.rc b/GEOSldas_App/GEOSldas_HISTdet.rc new file mode 100644 index 00000000..c84b39fe --- /dev/null +++ b/GEOSldas_App/GEOSldas_HISTdet.rc @@ -0,0 +1,70 @@ +# +# Sample GEOSldas HISTORY.rc file for LADAS (central simulation) +# +# This sample is for the GEOSldas instance that is coupled with the central +# simulation component of the Hy4dEnVar ADAS: +# +# (1) The "catch_progn_incr" is output is the ensemble average. +# (2) The "catch_progn_incr" output is in tile space. Its definition is generic +# +################################################################################## + +VERSION: 1 +EXPID: GEOSldas_expid + +COLLECTIONS: + 'catch_progn_incr' + :: + +GRID_LABELS: PC720x361-DC + PC576x361-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 + + +catch_progn_incr.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation,Ensemble-Average Land Prognostics Increments', +catch_progn_incr.template: '%y4%m2%d2_%h2%n2z.bin', +catch_progn_incr.mode: 'instantaneous', +catch_progn_incr.frequency: 030000, +catch_progn_incr.ref_time: 013000, +catch_progn_incr.fields: 'TCFSAT_INCR' , 'LANDASSIM' , + 'TCFTRN_INCR' , 'LANDASSIM' , + 'TCFWLT_INCR' , 'LANDASSIM' , + 'QCFSAT_INCR' , 'LANDASSIM' , + 'QCFTRN_INCR' , 'LANDASSIM' , + 'QCFWLT_INCR' , 'LANDASSIM' , + 'CAPAC_INCR' , 'LANDASSIM' , + 'CATDEF_INCR' , 'LANDASSIM' , + 'RZEXC_INCR' , 'LANDASSIM' , + 'SRFEXC_INCR' , 'LANDASSIM' , + 'GHTCNT1_INCR' , 'LANDASSIM' , + 'GHTCNT2_INCR' , 'LANDASSIM' , + 'GHTCNT3_INCR' , 'LANDASSIM' , + 'GHTCNT4_INCR' , 'LANDASSIM' , + 'GHTCNT5_INCR' , 'LANDASSIM' , + 'GHTCNT6_INCR' , 'LANDASSIM' , + 'WESNN1_INCR' , 'LANDASSIM' , + 'WESNN2_INCR' , 'LANDASSIM' , + 'WESNN3_INCR' , 'LANDASSIM' , + 'HTSNNN1_INCR' , 'LANDASSIM' , + 'HTSNNN2_INCR' , 'LANDASSIM' , + 'HTSNNN3_INCR' , 'LANDASSIM' , + 'SNDZN1_INCR' , 'LANDASSIM' , + 'SNDZN2_INCR' , 'LANDASSIM' , + 'SNDZN3_INCR' , 'LANDASSIM' , + :: + +# ========================== EOF ============================================== From 14a6d64c3c5573797179753e4796096a84df3130 Mon Sep 17 00:00:00 2001 From: saraqzhang Date: Tue, 25 Feb 2025 15:03:06 -0500 Subject: [PATCH 085/107] new file: GEOSldas_HISTens.rc --- GEOSldas_App/GEOSldas_HISTens.rc | 1083 ++++++++++++++++++++++++++++++ 1 file changed, 1083 insertions(+) create mode 100644 GEOSldas_App/GEOSldas_HISTens.rc diff --git a/GEOSldas_App/GEOSldas_HISTens.rc b/GEOSldas_App/GEOSldas_HISTens.rc new file mode 100644 index 00000000..25aa0908 --- /dev/null +++ b/GEOSldas_App/GEOSldas_HISTens.rc @@ -0,0 +1,1083 @@ + +# +# Sample GEOSldas HISTORY.rc file for LADAS (atm ensemble) +# +# - 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/Components/GEOSldas_GridComp/GEOSldas_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. +# +# +################################################################################## + +EXPID: GEOSldas_expid + +COLLECTIONS: +'catch_progn_incr0001' +'catch_progn_incr0002' +'catch_progn_incr0003' +'catch_progn_incr0004' +'catch_progn_incr0005' +'catch_progn_incr0006' +'catch_progn_incr0007' +'catch_progn_incr0008' +'catch_progn_incr0009' +'catch_progn_incr0010' +'catch_progn_incr0011' +'catch_progn_incr0012' +'catch_progn_incr0013' +'catch_progn_incr0014' +'catch_progn_incr0015' +'catch_progn_incr0016' +'catch_progn_incr0017' +'catch_progn_incr0018' +'catch_progn_incr0019' +'catch_progn_incr0020' +'catch_progn_incr0021' +'catch_progn_incr0022' +'catch_progn_incr0023' +'catch_progn_incr0024' +'catch_progn_incr0025' +'catch_progn_incr0026' +'catch_progn_incr0027' +'catch_progn_incr0028' +'catch_progn_incr0029' +'catch_progn_incr0030' +'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', +catch_progn_incr0001.frequency: 030000, +catch_progn_incr0001.ref_time: 013000, +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', +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' , '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', +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' , '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', +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' , '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', +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' , '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', +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' , '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', +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' , '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', +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' , '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', +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' , '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', +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' , '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', +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' , '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', +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' , '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', +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' , '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', +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' , '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', +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' , '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', +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' , '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', +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' , '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', +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' , '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', +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' , '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', +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' , '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', +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' , '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', +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' , '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', +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' , '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', +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' , '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', +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' , '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', +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' , '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', +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' , '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', +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' , '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', +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' , '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', +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' , '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', +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' , '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', +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' , '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' , + +:: From 54bed5d3de9ff5dac406d12a6f4624953a538cde Mon Sep 17 00:00:00 2001 From: saraqzhang Date: Tue, 25 Feb 2025 15:52:43 -0500 Subject: [PATCH 086/107] cleanup and a fix in ldas_setup --- GEOSldas_App/ldas_setup | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/GEOSldas_App/ldas_setup b/GEOSldas_App/ldas_setup index 47198940..918e2a43 100755 --- a/GEOSldas_App/ldas_setup +++ b/GEOSldas_App/ldas_setup @@ -1092,7 +1092,7 @@ class LDASsetup: # DEFAULT rc files default_rc = glob.glob(etcdir+'/GEOSldas_*.rc') - assert len(default_rc)==4 + assert len(default_rc)==6 print (default_rc) for rcfile in default_rc: shortfile=rcfile.rsplit('GEOSldas_',1)[1] @@ -1133,8 +1133,6 @@ class LDASsetup: shutil.copy2(rcfile, tmprcfile) for line in fileinput.input(tmprcfile,inplace=True): print (line.rstrip().replace('GEOSldas_expid',self.rqdExeInp['EXP_ID'])) - for line in fileinput.input(tmprcfile,inplace=True): - print (line.rstrip().replace('GEOSldas_expid',self.rqdExeInp['EXP_ID'])) if shortfile =='HISTens.rc' and self.ladas_coupling == 2 : tmprcfile=self.rundir+'/HISTORY.rc' histrc_file=rcfile From 2d6d069146ce58611a2ba3a26606a1df91a58b43 Mon Sep 17 00:00:00 2001 From: saraqzhang Date: Tue, 25 Feb 2025 16:44:28 -0500 Subject: [PATCH 087/107] update to bkg lfo in exeinp.txt.Hy4dEnVar.atmens & exeinp.txt.Hy4dEnVar.central --- .../sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.atmens | 6 ++---- .../sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.central | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/GEOSldas_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.atmens b/GEOSldas_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.atmens index 4e95f58d..c39d4a82 100644 --- a/GEOSldas_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.atmens +++ b/GEOSldas_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.atmens @@ -20,8 +20,8 @@ LADAS_COUPLING: 2 ADAS_EXPDIR: [full_path]/[ADAS_EXPDIR] -MET_TAG: [ADAS_EXPID]__Nx+- -MET_PATH: [ADAS_EXPDIR]/atmens/ensdiag/mem +MET_TAG: [ADAS_EXPID]__bkg +MET_PATH: [ADAS_EXPDIR]/atmens/mem MET_HINTERP: 0 @@ -37,6 +37,4 @@ ENSEMBLE_FORCING: YES JOB_SGMT: 00000000 060000 NUM_SGMT: 1 -HISTRC_FILE: [path of GEOSldas_GridComp/GEOSldas_App/sample_config_files/LADAS]/GEOSldas_HIST.rc.atmens - ################################# EOF ######################################## diff --git a/GEOSldas_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.central b/GEOSldas_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.central index b25e5105..8f9edbc1 100644 --- a/GEOSldas_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.central +++ b/GEOSldas_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.central @@ -18,7 +18,7 @@ LADAS_COUPLING: 1 ADAS_EXPDIR: [full_path]/[ADAS_EXPDIR] -MET_TAG: [ADAS_EXPID]__Nx+- +MET_TAG: [ADAS_EXPID]__bkg MET_PATH: ../../../../recycle/holdpredout # option to use perturbed forcing created from central simulation and atm ensemble # MET_PATH: [ADAS_EXPDIR]/atmens/rgdlfo From 50771588c08a7b937252548c21ddee930a9a4d98 Mon Sep 17 00:00:00 2001 From: Weiyuan Jiang Date: Fri, 28 Feb 2025 12:39:40 -0500 Subject: [PATCH 088/107] remove support for SLES12 --- GEOSldas_App/ldas_setup | 18 +++--------------- GEOSldas_App/lenkf_j_template.py | 8 ++------ 2 files changed, 5 insertions(+), 21 deletions(-) diff --git a/GEOSldas_App/ldas_setup b/GEOSldas_App/ldas_setup index dfbe28ea..30649d01 100755 --- a/GEOSldas_App/ldas_setup +++ b/GEOSldas_App/ldas_setup @@ -51,12 +51,6 @@ class LDASsetup: 'MINLON','MAXLON','MINLAT','MAXLAT','EXCLUDE_FILE','INCLUDE_FILE','MWRTM_PATH','GRIDNAME', 'ADAS_EXPDIR', 'BCS_RESOLUTION' ] - # 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@" @@ -705,10 +699,7 @@ class LDASsetup: print ('\nCorrect the tile file if it is an old EASE tile format... \n') EASEtile=self.bcsdir+'/MAPL_'+short_tile 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: - print ("cmd: " + cmd) + print ("cmd: " + cmd) sp.call(shlex.split(cmd)) @@ -1358,10 +1349,8 @@ class LDASsetup: constraint='cas' if self.GEOS_SITE == "NAS": constraint = 'cas_ait' - elif self.BUILT_ON_SLES15: - constraint = 'mil' - else: - assert int(self.rqdRmInp['ntasks-per-node']) <= 46, 'ntasks-per-node should be <=46 for cas' + elif self.GEOS_SITE == "NCCS": + constraint = '"[mil|cas]"' SBATCHQSUB = 'sbatch' if self.GEOS_SITE == 'NAS': @@ -1393,7 +1382,6 @@ class LDASsetup: MY_ADAS_EXPDIR = self.adas_expdir, MY_EXPDIR = self.expdir, DETECTED_MPI_STACK = DETECTED_MPI_STACK, - BUILT_ON_SLES15 = str(self.BUILT_ON_SLES15).upper() ) with open('lenkf.j','wt') as fout : diff --git a/GEOSldas_App/lenkf_j_template.py b/GEOSldas_App/lenkf_j_template.py index 0182edb0..45abc2e9 100644 --- a/GEOSldas_App/lenkf_j_template.py +++ b/GEOSldas_App/lenkf_j_template.py @@ -87,12 +87,8 @@ else if ( ${{MPI_STACK}} == "intelmpi" ) then - setenv BUILT_ON_SLES15 {BUILT_ON_SLES15} - - if ( ${{BUILT_ON_SLES15}} == TRUE ) then - setenv I_MPI_FABRICS shm:ofi - setenv I_MPI_OFI_PROVIDER psm3 - endif # BUILT_ON_SLES15 + setenv I_MPI_FABRICS shm:ofi + setenv I_MPI_OFI_PROVIDER psm3 endif # MPI_STACK From e7215a935bf605061ee29c6f38d307714c8a90b2 Mon Sep 17 00:00:00 2001 From: Weiyuan Jiang Date: Fri, 28 Feb 2025 13:25:24 -0500 Subject: [PATCH 089/107] change log --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 38bbef5d..941fddeb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- NCCS has retired SLES12, so the conditions on SLES12 and SLES15 are removed - Updated subroutine read_obs_sm_ASCAT_EUMET() to work with both original and revised file name templates. - Updated subroutines read_obs_sm_ASCAT_EUMET(), read_obs_SMAP_halforbit_Tb(), read_obs_SMOS() and read_obs_MODIS_SCF() with hardcoded time ranges for when observations are available and should be read. - Revised variable names (SHORT_NAME) and descriptions (LONG_NAME) to match M21C file specs. From 96325229b4104dad84998268c773f46a500b7d9f Mon Sep 17 00:00:00 2001 From: Rolf Reichle <54944691+gmao-rreichle@users.noreply.github.com> Date: Wed, 19 Mar 2025 17:10:14 -0400 Subject: [PATCH 090/107] Update CHANGELOG.md --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 941fddeb..1dbb905a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed -- NCCS has retired SLES12, so the conditions on SLES12 and SLES15 are removed - Updated subroutine read_obs_sm_ASCAT_EUMET() to work with both original and revised file name templates. - Updated subroutines read_obs_sm_ASCAT_EUMET(), read_obs_SMAP_halforbit_Tb(), read_obs_SMOS() and read_obs_MODIS_SCF() with hardcoded time ranges for when observations are available and should be read. - Revised variable names (SHORT_NAME) and descriptions (LONG_NAME) to match M21C file specs. @@ -27,6 +26,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Removed +- Removed support for SLES12 operating system at NCCS. + ### Deprecated ----------------------------- From 0a3cd3ce7d36a8095bf6caa997cf1e54a92c5b4f Mon Sep 17 00:00:00 2001 From: saraqzhang Date: Thu, 27 Mar 2025 08:52:38 -0400 Subject: [PATCH 091/107] edits responding to comments at PR#81 modified: GEOSldas_App/GEOSldas_HISTdet.rc modified: GEOSldas_App/ldas_setup modified: GEOSmetforce_GridComp/LDAS_Forcing.F90 --- GEOSldas_App/GEOSldas_HISTdet.rc | 105 ++++++++++++++++++++++++- GEOSldas_App/ldas_setup | 2 + GEOSmetforce_GridComp/LDAS_Forcing.F90 | 4 +- 3 files changed, 106 insertions(+), 5 deletions(-) diff --git a/GEOSldas_App/GEOSldas_HISTdet.rc b/GEOSldas_App/GEOSldas_HISTdet.rc index c84b39fe..5972a292 100644 --- a/GEOSldas_App/GEOSldas_HISTdet.rc +++ b/GEOSldas_App/GEOSldas_HISTdet.rc @@ -6,14 +6,15 @@ # # (1) The "catch_progn_incr" is output is the ensemble average. # (2) The "catch_progn_incr" output is in tile space. Its definition is generic -# ################################################################################## VERSION: 1 -EXPID: GEOSldas_expid +EXPID: hybd_ladas_LDAS COLLECTIONS: 'catch_progn_incr' + 'tavg3_1d_lnd_Nt' + # 'inst3_2d_lndfcstana_Nx' :: GRID_LABELS: PC720x361-DC @@ -65,6 +66,102 @@ catch_progn_incr.fields: 'TCFSAT_INCR' , 'LANDASSIM' , 'SNDZN1_INCR' , 'LANDASSIM' , 'SNDZN2_INCR' , 'LANDASSIM' , 'SNDZN3_INCR' , 'LANDASSIM' , - :: + :: + + tavg3_1d_lnd_Nt.descr: 'Tile-space,Time-Averaged,Single-Level,Assimilation,Land Surface Diagnostics', + tavg3_1d_lnd_Nt.nbits: 12, + tavg3_1d_lnd_Nt.template: '%y4%m2%d2_%h2%n2z.bin', + tavg3_1d_lnd_Nt.mode: 'time-averaged', + tavg3_1d_lnd_Nt.frequency: 030000, + tavg3_1d_lnd_Nt.ref_time: 013000, + tavg3_1d_lnd_Nt.fields: 'WET3' , 'ENSAVG' , 'GWETPROF' , + 'WET2' , 'ENSAVG' , 'GWETROOT' , + 'WET1' , 'ENSAVG' , 'GWETTOP' , + 'WCPR' , 'ENSAVG' , 'PRMC' , + 'WCRZ' , 'ENSAVG' , 'RZMC' , + 'WCSF' , 'ENSAVG' , 'SFMC' , + 'TPSNOW' , 'ENSAVG' , + 'TPUNST' , 'ENSAVG' , 'TUNST' , + 'TPSAT' , 'ENSAVG' , 'TSAT' , + 'TPWLT' , 'ENSAVG' , 'TWLT' , + 'TPSURF' , 'ENSAVG' , 'TSURF' , + 'GRN' , 'VEGDYN_e0001' , + 'LAI' , 'VEGDYN_e0001' , + 'TP1' , 'ENSAVG' , + 'TP2' , 'ENSAVG' , + 'TP3' , 'ENSAVG' , + 'TP4' , 'ENSAVG' , + 'TP5' , 'ENSAVG' , + 'TP6' , 'ENSAVG' , + 'PRLAND' , 'ENSAVG' , 'PRECTOTLAND' , + 'SNOLAND' , 'ENSAVG' , 'PRECSNOLAND' , + 'TSLAND' , 'ENSAVG' , 'SNOMAS' , + 'SNOWDP' , 'ENSAVG' , 'SNODP' , + 'EVPSOI' , 'ENSAVG' , 'EVPSOIL' , + 'EVPVEG' , 'ENSAVG' , 'EVPTRNS' , + 'EVPINT' , 'ENSAVG' , 'EVPINTR' , + 'EVPICE' , 'ENSAVG' , 'EVPSBLN' , + 'RUNSURF' , 'ENSAVG' , 'RUNOFF' , + 'BASEFLOW' , 'ENSAVG' , + 'SMLAND' , 'ENSAVG' , + 'QINFIL' , 'ENSAVG' , + 'FRUST' , 'ENSAVG' , 'FRUNST' , + 'FRSAT' , 'ENSAVG' , + 'ASNOW' , 'ENSAVG' , 'FRSNO' , + 'FRWLT' , 'ENSAVG' , + 'DFPARLAND' , 'ENSAVG' , 'PARDFLAND' , + 'DRPARLAND' , 'ENSAVG' , 'PARDRLAND' , + 'SHLAND' , 'ENSAVG' , + 'LHLAND' , 'ENSAVG' , + 'EVLAND' , 'ENSAVG' , + 'LWLAND' , 'ENSAVG' , + 'SWLAND' , 'ENSAVG' , + 'GHLAND' , 'ENSAVG' , + 'TWLAND' , 'ENSAVG' , + 'TELAND' , 'ENSAVG' , + 'DWLAND' , 'ENSAVG' , 'WCHANGE' , + 'DHLAND' , 'ENSAVG' , 'ECHANGE' , + 'SPLAND' , 'ENSAVG' , + 'SPWATR' , 'ENSAVG' , + 'SPSNOW' , 'ENSAVG' , + 'PEATCLSM_WATERLEVEL', 'ENSAVG' , + 'PEATCLSM_FSWCHANGE' , 'ENSAVG' , + :: + + + inst3_2d_lndfcstana_Nx.descr: '2d,3-Hourly,Instantaneous,Single-Level,Assimilation,Ensemble Land Forecast and Analysis Diagnostics', + inst3_2d_lndfcstana_Nx.nbits: 12, + inst3_2d_lndfcstana_Nx.template: '%y4%m2%d2_%h2%n2z.nc4', + inst3_2d_lndfcstana_Nx.archive: '%c/Y%y4', + 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: 'PE360x2160-CF', + inst3_2d_lndfcstana_Nx.grid_label: PC720x361-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' , + 'TP1' , 'ENSAVG' , 'TSOIL1_FCST' , + 'WCSF_ENSSTD' , 'ENSAVG' , 'SFMC_FCST_ENSSTD' , + 'WCRZ_ENSSTD' , 'ENSAVG' , 'RZMC_FCST_ENSSTD' , + 'WCPR_ENSSTD' , 'ENSAVG' , 'PRMC_FCST_ENSSTD' , + 'TPSURF_ENSSTD' , 'ENSAVG' , 'TSURF_FCST_ENSSTD' , + 'TP1_ENSSTD' , 'ENSAVG' , 'TSOIL1_FCST_ENSSTD' , + 'WCSF_ANA' , 'LANDASSIM' , 'SFMC_ANA' , + 'WCRZ_ANA' , 'LANDASSIM' , 'RZMC_ANA' , + 'WCPR_ANA' , 'LANDASSIM' , 'PRMC_ANA' , + 'TPSURF_ANA' , 'LANDASSIM' , 'TSURF_ANA' , + 'TP1_ANA' , 'LANDASSIM' , 'TSOIL1_ANA' , + 'WCSF_ANA_ENSSTD' , 'LANDASSIM' , 'SFMC_ANA_ENSSTD' , + 'WCRZ_ANA_ENSSTD' , 'LANDASSIM' , 'RZMC_ANA_ENSSTD' , + 'WCPR_ANA_ENSSTD' , 'LANDASSIM' , 'PRMC_ANA_ENSSTD' , + 'TPSURF_ANA_ENSSTD' , 'LANDASSIM' , 'TSURF_ANA_ENSSTD' , + 'TP1_ANA_ENSSTD' , 'LANDASSIM' , 'TSOIL1_ANA_ENSSTD' + :: + -# ========================== EOF ============================================== +# ========================== EOF ============================================================== diff --git a/GEOSldas_App/ldas_setup b/GEOSldas_App/ldas_setup index 918e2a43..c94715ac 100755 --- a/GEOSldas_App/ldas_setup +++ b/GEOSldas_App/ldas_setup @@ -1133,6 +1133,8 @@ class LDASsetup: shutil.copy2(rcfile, tmprcfile) for line in fileinput.input(tmprcfile,inplace=True): print (line.rstrip().replace('GEOSldas_expid',self.rqdExeInp['EXP_ID'])) + for line in fileinput.input(tmprcfile,inplace=True): + print (line.rstrip().replace('GRIDNAME',self.rqdExeInp['GRIDNAME'])) if shortfile =='HISTens.rc' and self.ladas_coupling == 2 : tmprcfile=self.rundir+'/HISTORY.rc' histrc_file=rcfile diff --git a/GEOSmetforce_GridComp/LDAS_Forcing.F90 b/GEOSmetforce_GridComp/LDAS_Forcing.F90 index 11b1b366..76fd5ef7 100755 --- a/GEOSmetforce_GridComp/LDAS_Forcing.F90 +++ b/GEOSmetforce_GridComp/LDAS_Forcing.F90 @@ -3782,7 +3782,9 @@ subroutine get_GEOS( date_time, force_dtstep, met_path, met_tag, & if ( (index(met_tag, 'GEOSIT') > 0) .or. (index(met_tag, 'geosit') > 0) ) then GEOSgcm_defs(1:N_G5DAS_vars,:) = GEOSIT_defs - else + else if (index(met_tag, 'bkg') > 0) then + GEOSgcm_defs(1:N_G5DAS_vars,:) = G5LADAS_defs + else GEOSgcm_defs(1:N_G5DAS_vars,:) = G5DAS_defs end if From c0c12f27b31dd240b24bbd21c34aad9514ad884c Mon Sep 17 00:00:00 2001 From: saraqzhang Date: Thu, 27 Mar 2025 09:01:19 -0400 Subject: [PATCH 092/107] name fix in GEOSldas_HISTdet.rc --- GEOSldas_App/GEOSldas_HISTdet.rc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/GEOSldas_App/GEOSldas_HISTdet.rc b/GEOSldas_App/GEOSldas_HISTdet.rc index 5972a292..55995fc3 100644 --- a/GEOSldas_App/GEOSldas_HISTdet.rc +++ b/GEOSldas_App/GEOSldas_HISTdet.rc @@ -9,12 +9,12 @@ ################################################################################## VERSION: 1 -EXPID: hybd_ladas_LDAS +EXPID: GEOSldas_expid COLLECTIONS: 'catch_progn_incr' 'tavg3_1d_lnd_Nt' - # 'inst3_2d_lndfcstana_Nx' + 'inst3_2d_lndfcstana_Nx' :: GRID_LABELS: PC720x361-DC @@ -138,7 +138,7 @@ catch_progn_incr.fields: 'TCFSAT_INCR' , 'LANDASSIM' , 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: 'PE360x2160-CF', + inst3_2d_lndfcstana_Nx.regrid_name: 'GRIDNAME', inst3_2d_lndfcstana_Nx.grid_label: PC720x361-DC, inst3_2d_lndfcstana_Nx.deflate: 2, inst3_2d_lndfcstana_Nx.fields: 'WCSF' , 'ENSAVG' , 'SFMC_FCST' , From 4170567bcbd5547ff5b9bea4f9be08536b49c9fd Mon Sep 17 00:00:00 2001 From: saraqzhang Date: Mon, 31 Mar 2025 16:43:50 -0400 Subject: [PATCH 093/107] add comments on fvsetup-provided resource parameters modified: exeinp.txt.Hy4dEnVar.atmens modified: exeinp.txt.Hy4dEnVar.central --- .../LADAS/exeinp.txt.Hy4dEnVar.atmens | 10 +++++++++- .../LADAS/exeinp.txt.Hy4dEnVar.central | 12 ++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/GEOSldas_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.atmens b/GEOSldas_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.atmens index c39d4a82..410505dd 100644 --- a/GEOSldas_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.atmens +++ b/GEOSldas_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.atmens @@ -9,6 +9,14 @@ # # (2) Use the resource parameter settings below when editing MY_exeinp.txt # +# (3) The following resource parameters are provided via fvsetup, +# which supersede the default in MY_exeinp.txt: +# ADAS_EXPDIR +# ADAS_EXPID +# EXP_ID +# MET_TAG +# BEG_DATE +# GID ############################################################################## # e.g., ATMENS_AGCM_GRID = CF0090x6C @@ -18,7 +26,7 @@ NUM_LDAS_ENSEMBLE: [NUM_ATMENS_ENSEMBLE] LADAS_COUPLING: 2 -ADAS_EXPDIR: [full_path]/[ADAS_EXPDIR] +ADAS_EXPDIR: [full_path]/[ADAS_EXPID] MET_TAG: [ADAS_EXPID]__bkg MET_PATH: [ADAS_EXPDIR]/atmens/mem diff --git a/GEOSldas_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.central b/GEOSldas_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.central index 8f9edbc1..0c682821 100644 --- a/GEOSldas_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.central +++ b/GEOSldas_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.central @@ -7,8 +7,16 @@ # (1) Create exeinp template using: # ldas_setup sample --exeinp > MY_exeinp.txt # -# (2) Use the resource parameter settings below when editing MY_exeinp.txt +# (2) Use the resource parameter settings below when editing MY_exeinp.txt # +# (3) The following resource parameters are provided via fvsetup, +# which supersede the default in MY_exeinp.txt +# ADAS_EXPDIR +# ADAS_EXPID +# EXP_ID +# MET_TAG +# BEG_DATE +# GID ############################################################################## # e.g., CENTRAL_AGCM_GRID = CF0360x6C @@ -16,7 +24,7 @@ EXP_DOMAIN: [CENTRAL_AGCM_GRID]_GLOBAL LADAS_COUPLING: 1 -ADAS_EXPDIR: [full_path]/[ADAS_EXPDIR] +ADAS_EXPDIR: [full_path]/[ADAS_EXPID] MET_TAG: [ADAS_EXPID]__bkg MET_PATH: ../../../../recycle/holdpredout From 9ffda3d65d1361a31777a462b89ce7127cf0a1d3 Mon Sep 17 00:00:00 2001 From: Matthew Thompson Date: Thu, 3 Apr 2025 08:23:44 -0400 Subject: [PATCH 094/107] Add Github Actions CI --- .github/workflows/spack-ci.yml | 116 +++++++++++++++++++++++++++++++++ .github/workflows/workflow.yml | 78 ++++++++++++++++++++++ 2 files changed, 194 insertions(+) create mode 100644 .github/workflows/spack-ci.yml create mode 100644 .github/workflows/workflow.yml diff --git a/.github/workflows/spack-ci.yml b/.github/workflows/spack-ci.yml new file mode 100644 index 00000000..cb38a474 --- /dev/null +++ b/.github/workflows/spack-ci.yml @@ -0,0 +1,116 @@ +name: Spack CI GCC Build + +on: + pull_request: + types: [opened, synchronize, reopened] + # Do not run if the only files changed cannot affect the build + paths-ignore: + - "**.md" + - "**.pro" + - "**.sh" + - "**.perl" + - ".github/CODEOWNERS" + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} + +jobs: + build_ldas: + name: Spack CI GCC Build + runs-on: ubuntu-24.04 + steps: + + - name: Checkout LDAS + uses: actions/checkout@v4 + with: + fetch-depth: 1 + filter: blob:none + repository: GEOS-ESM/GEOSldas + + - name: Set all directories as git safe + run: | + git config --global --add safe.directory '*' + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: '3.13' + + - name: Pip install mepo + run: | + python -m pip install --upgrade pip + pip install mepo + mepo --version + + - name: Mepo clone external repos + run: | + ls + mepo clone --partial blobless + mepo status + + - name: Update other branches + if: + "!contains('refs/heads/main,refs/heads/develop', github.ref)" + run: | + mepo checkout-if-exists ${GITHUB_HEAD_REF} + mepo status + + - name: Set up Spack + uses: spack/setup-spack@v2 + with: + ref: develop # Spack version (examples: develop, releases/v0.21) + color: true # Force color output (SPACK_COLOR=always) + path: spack # Where to clone Spack + buildcache: false # Do not use the spack buildcache + + - name: Find compilers + shell: spack-bash {0} + run: | + spack compiler find + + - name: Set default compiler and target + shell: spack-bash {0} + run: | + spack config add 'packages:all:compiler:[gcc@14.2.0]' + spack config add 'packages:all:require:target=x86_64_v3' + + - name: Create Spack environment + shell: spack-bash {0} + run: | + spack env create spack-env + spack env activate spack-env + + - name: Login + shell: spack-bash {0} + run: | + spack -e spack-env mirror add geos-buildcache oci://ghcr.io/GEOS-ESM/geos-buildcache + spack -e spack-env mirror set --oci-username ${{ github.actor }} --oci-password "${{ secrets.BUILDCACHE_TOKEN }}" geos-buildcache + spack -e spack-env mirror list + spack -e spack-env buildcache update-index geos-buildcache + spack -e spack-env buildcache list --allarch + + - name: Concretize + shell: spack-bash {0} + run: | + spack -e spack-env concretize + + - name: Install + shell: spack-bash {0} + run: | + spack -e spack-env install --add --no-check-signature --use-buildcache only \ + esmf gftl gftl-shared fargparse pflogger pfunit yafyaml ecbuild udunits openblas + + - name: Build with Cmake + shell: spack-bash {0} + run: | + spack env activate spack-env + spack load \ + esmf gftl gftl-shared fargparse pflogger pfunit yafyaml ecbuild udunits openblas + spack find --loaded + FC=gfortran-14 CC=gcc-14 CXX=g++-14 + cmake -B build -S . -DCMAKE_INSTALL_PREFIX=$PWD/install -DCMAKE_BUILD_TYPE=Debug -DUSE_F2PY=OFF -DCMAKE_Fortran_COMPILER=${FC} -DCMAKE_C_COMPILER=${CC} -DCMAKE_CXX_COMPILER=${CXX} + cmake --build build -j 4 + cmake --install build + diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml new file mode 100644 index 00000000..b594390a --- /dev/null +++ b/.github/workflows/workflow.yml @@ -0,0 +1,78 @@ +name: Build Tests + +on: + pull_request: + types: [opened, synchronize, reopened] + # Do not run if the only files changed cannot affect the build + paths-ignore: + - "**.md" + - "**.pro" + - "**.sh" + - "**.perl" + - ".github/CODEOWNERS" + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} + +jobs: + build_ldas: + name: Build GEOSldas + if: "!contains(github.event.pull_request.labels.*.name, '0 diff trivial')" + runs-on: ubuntu-24.04 + container: + image: gmao/ubuntu24-geos-env:v7.32.0-intelmpi_2021.13-ifort_2021.13 + # Per https://github.com/actions/virtual-environments/issues/1445#issuecomment-713861495 + # It seems like we might not need secrets on GitHub Actions which is good for forked + # pull requests + #credentials: + #username: ${{ secrets.DOCKERHUB_USERNAME }} + #password: ${{ secrets.DOCKERHUB_TOKEN }} + + env: + OMPI_ALLOW_RUN_AS_ROOT: 1 + OMPI_ALLOW_RUN_AS_ROOT_CONFIRM: 1 + OMPI_MCA_btl_vader_single_copy_mechanism: none + + steps: + # https://github.com/orgs/community/discussions/25678#discussioncomment-5242449 + - name: Delete huge unnecessary tools folder + run: rm -rf /opt/hostedtoolcache + + - name: Checkout LDAS + uses: actions/checkout@v4 + with: + fetch-depth: 1 + filter: blob:none + repository: GEOS-ESM/GEOSldas + + - name: Set all directories as git safe + run: | + git config --global --add safe.directory '*' + + - name: Versions etc. + run: | + ifort --version + mpirun --version + echo $BASEDIR + + - name: Mepo clone external repos + run: | + mepo clone --partial blobless + mepo status + + - name: Update other branches + if: + "!contains('refs/heads/main,refs/heads/develop', github.ref)" + run: | + mepo checkout-if-exists ${GITHUB_HEAD_REF} + mepo status + + - name: CMake + run: | + cmake -B build -S . --install-prefix=${pwd}/install -DCMAKE_Fortran_COMPILER=ifort -DCMAKE_BUILD_TYPE=Debug -DMPIEXEC_PREFLAGS='--oversubscribe' -DUSE_F2PY=OFF + + - name: Build + run: | + cmake --build build -j 4 + cmake --install build From ab28724bf6422c262eaa6598690eb7f6f8573243 Mon Sep 17 00:00:00 2001 From: Matthew Thompson Date: Thu, 3 Apr 2025 08:25:38 -0400 Subject: [PATCH 095/107] Update changelog --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1dbb905a..8c745779 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,10 +14,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - New update_type for joint 3d soil moisture and 1d snow analysis (Tb+sfmc+sfds+SCF obs). - Added CYGNSS soil moisture reader. - Added M21C surface met forcing. +- Add Github Actions workflow for testing and building GEOSldas_GridComp. ### Changed -- Updated subroutine read_obs_sm_ASCAT_EUMET() to work with both original and revised file name templates. +- Updated subroutine read_obs_sm_ASCAT_EUMET() to work with both original and revised file name templates. - Updated subroutines read_obs_sm_ASCAT_EUMET(), read_obs_SMAP_halforbit_Tb(), read_obs_SMOS() and read_obs_MODIS_SCF() with hardcoded time ranges for when observations are available and should be read. - Revised variable names (SHORT_NAME) and descriptions (LONG_NAME) to match M21C file specs. - Renamed tilecoord%pfaf to %pfaf_index; added matlab tile file reader. From 96af721a415e16dc9b537d0aa20ee545a7a5503c Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Tue, 8 Apr 2025 08:57:23 -0400 Subject: [PATCH 096/107] removed execute permissions from LDAS_Forcing.F90 --- GEOSmetforce_GridComp/LDAS_Forcing.F90 | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 GEOSmetforce_GridComp/LDAS_Forcing.F90 diff --git a/GEOSmetforce_GridComp/LDAS_Forcing.F90 b/GEOSmetforce_GridComp/LDAS_Forcing.F90 old mode 100755 new mode 100644 From fdef165115f6ee471ec86ff128dbbf23364ef40b Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Tue, 8 Apr 2025 18:36:39 -0400 Subject: [PATCH 097/107] cleaned up "Nx+-" forcing option (replaced by "bkg.lfo_*") (LDAS_Forcing.F90) --- GEOSmetforce_GridComp/LDAS_Forcing.F90 | 175 +++++++++++-------------- 1 file changed, 73 insertions(+), 102 deletions(-) diff --git a/GEOSmetforce_GridComp/LDAS_Forcing.F90 b/GEOSmetforce_GridComp/LDAS_Forcing.F90 index 76fd5ef7..24126b59 100644 --- a/GEOSmetforce_GridComp/LDAS_Forcing.F90 +++ b/GEOSmetforce_GridComp/LDAS_Forcing.F90 @@ -3093,6 +3093,9 @@ subroutine get_GEOS( date_time, force_dtstep, met_path, met_tag, & ! qliu+reichle, 5 Dec 2023 - added GEOS-IT ! ! rreichle, 18 Dec 2024 - added M21C + ! + ! sqzhang+rreichle, 8 Apr 2025 - added "bkg.lfo_[inst,tavg]" for coupled land/atm DAS (replacing "Nx+-") + ! ! ----------------------------------- ! ! Read surface met forcing from MERRA, MERRA-2 or GEOS-5 DAS (i.e., FP) based on parsing of "met_tag". @@ -3173,7 +3176,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) :: G5LADAS_defs + character(40), dimension(N_G5DAS_vars, N_defs_cols) :: G5BKG_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 @@ -3212,7 +3215,7 @@ subroutine get_GEOS( date_time, force_dtstep, met_path, met_tag, & integer :: j, k, GEOSgcm_var, fid, km, lm, nvars, ngatts, rc, YYYYMMDD, HHMMSS - logical :: minimize_shift, use_prec_corr, use_Predictor, use_bkg,tmp_init + logical :: minimize_shift, use_prec_corr, use_bkg, tmp_init logical :: daily_met_files, daily_precipcorr_files @@ -3255,41 +3258,41 @@ subroutine get_GEOS( date_time, force_dtstep, met_path, met_tag, & ! ----------------------------------------------------------------------- ! - ! define LADAS file specs + ! define coupled land/atm DAS file specs (i.e., use bkg.lfo_* files) ! ! same as G5DAS except for file tag (column 3) - G5LADAS_defs = G5DAS_defs + G5BKG_defs = G5DAS_defs ! character(40): - ! 1 2 3 4 - ! 1234567890123456789012345678901234567890 - - G5LADAS_defs( 1,3) = 'bkg.tavg1_2d_lfo ' - G5LADAS_defs( 2,3) = 'bkg.tavg1_2d_lfo ' - G5LADAS_defs( 3,3) = 'bkg.tavg1_2d_lfo ' - G5LADAS_defs( 4,3) = 'bkg.tavg1_2d_lfo ' - G5LADAS_defs( 5,3) = 'bkg.tavg1_2d_lfo ' - G5LADAS_defs( 6,3) = 'bkg.tavg1_2d_lfo ' - G5LADAS_defs( 7,3) = 'bkg.tavg1_2d_lfo ' - G5LADAS_defs( 8,3) = 'bkg.inst1_2d_lfo ' - G5LADAS_defs( 9,3) = 'bkg.inst1_2d_lfo ' - G5LADAS_defs(10,3) = 'bkg.inst1_2d_lfo ' - G5LADAS_defs(11,3) = 'bkg.inst1_2d_lfo ' - G5LADAS_defs(12,3) = 'bkg.inst1_2d_lfo ' + ! 1 2 3 4 + ! 1234567890123456789012345678901234567890 + + G5BKG_defs( 1,3) = 'bkg.tavg1_2d_lfo ' + G5BKG_defs( 2,3) = 'bkg.tavg1_2d_lfo ' + G5BKG_defs( 3,3) = 'bkg.tavg1_2d_lfo ' + G5BKG_defs( 4,3) = 'bkg.tavg1_2d_lfo ' + G5BKG_defs( 5,3) = 'bkg.tavg1_2d_lfo ' + G5BKG_defs( 6,3) = 'bkg.tavg1_2d_lfo ' + G5BKG_defs( 7,3) = 'bkg.tavg1_2d_lfo ' + G5BKG_defs( 8,3) = 'bkg.inst1_2d_lfo ' + G5BKG_defs( 9,3) = 'bkg.inst1_2d_lfo ' + G5BKG_defs(10,3) = 'bkg.inst1_2d_lfo ' + G5BKG_defs(11,3) = 'bkg.inst1_2d_lfo ' + G5BKG_defs(12,3) = 'bkg.inst1_2d_lfo ' - G5LADAS_defs( 1,4) = 'rs ' - G5LADAS_defs( 2,4) = 'rs ' - G5LADAS_defs( 3,4) = 'rs ' - G5LADAS_defs( 4,4) = 'rs ' - G5LADAS_defs( 5,4) = 'rs ' - G5LADAS_defs( 6,4) = 'rs ' - G5LADAS_defs( 7,4) = 'rs ' - G5LADAS_defs( 8,4) = 'rs ' - G5LADAS_defs( 9,4) = 'rs ' - G5LADAS_defs(10,4) = 'rs ' - G5LADAS_defs(11,4) = 'rs ' - G5LADAS_defs(12,4) = 'rs ' + G5BKG_defs( 1,4) = 'rs ' + G5BKG_defs( 2,4) = 'rs ' + G5BKG_defs( 3,4) = 'rs ' + G5BKG_defs( 4,4) = 'rs ' + G5BKG_defs( 5,4) = 'rs ' + G5BKG_defs( 6,4) = 'rs ' + G5BKG_defs( 7,4) = 'rs ' + G5BKG_defs( 8,4) = 'rs ' + G5BKG_defs( 9,4) = 'rs ' + G5BKG_defs(10,4) = 'rs ' + G5BKG_defs(11,4) = 'rs ' + G5BKG_defs(12,4) = 'rs ' ! ----------------------------------------------------------------------- @@ -3771,60 +3774,36 @@ subroutine get_GEOS( date_time, force_dtstep, met_path, met_tag, & met_path_bkwd, prec_path_bkwd, met_tag_bkwd, use_prec_corr ) - else ! GEOS ADAS (FP) + else ! GEOS ADAS (FP, GEOSIT) + + 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_bkg ) + + call parse_G5DAS_met_tag( met_path, met_tag, date_time_fwd, & + met_path_fwd, prec_path_fwd, met_tag_fwd, use_prec_corr, & + use_bkg ) + call parse_G5DAS_met_tag( met_path, met_tag, date_time_bkwd, & + met_path_bkwd, prec_path_bkwd, met_tag_bkwd, use_prec_corr, & + use_bkg ) + ! AEROSOL_DEPOSITION /= 0 is NOT supported N_GEOSgcm_vars = N_G5DAS_vars allocate(GEOSgcm_defs(N_GEOSgcm_vars,N_defs_cols)) - - if ( (index(met_tag, 'GEOSIT') > 0) .or. (index(met_tag, 'geosit') > 0) ) then + if ( (index(met_tag, 'GEOSIT') > 0) .or. (index(met_tag, 'geosit') > 0) ) then GEOSgcm_defs(1:N_G5DAS_vars,:) = GEOSIT_defs - else if (index(met_tag, 'bkg') > 0) then - GEOSgcm_defs(1:N_G5DAS_vars,:) = G5LADAS_defs + else if ( use_bkg ) then + GEOSgcm_defs(1:N_G5DAS_vars,:) = G5BKG_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, use_bkg ) - - call parse_G5DAS_met_tag( met_path, met_tag, date_time_fwd, & - met_path_fwd, prec_path_fwd, met_tag_fwd, use_prec_corr, & - use_Predictor, use_bkg ) - - call parse_G5DAS_met_tag( met_path, met_tag, date_time_bkwd, & - met_path_bkwd, prec_path_bkwd, met_tag_bkwd, use_prec_corr, & - use_Predictor, use_bkg ) - - if (use_Predictor) then - - ! append "+-" to GCM file tag (ie, replace "Nx" with "Nx+-") - - do j=1,N_GEOSgcm_vars - - GEOSgcm_defs(j,3) = trim(GEOSgcm_defs(j,3)) // '+-' - - end do - - end if - - if (use_bkg) then - - do j=1,N_GEOSgcm_vars - - GEOSgcm_defs(j,3) = G5LADAS_defs(j,3) - GEOSgcm_defs(j,4) = G5LADAS_defs(j,4) - - end do - - end if - end if - + allocate(force_array(N_catd,N_GEOSgcm_vars)) ! --------------------------------------------------------------------------- @@ -4970,9 +4949,9 @@ end subroutine parse_M21C_met_tag ! **************************************************************** - subroutine parse_G5DAS_met_tag( met_path_in, met_tag_in, date_time, & - met_path_default, met_path_prec, met_tag_out, use_prec_corr, & - use_Predictor, use_bkg ) + subroutine parse_G5DAS_met_tag( met_path_in, met_tag_in, date_time, & + met_path_default, met_path_prec, met_tag_out, use_prec_corr, & + use_bkg ) ! parse G5DAS "met_tag" ! @@ -5003,13 +4982,14 @@ subroutine parse_G5DAS_met_tag( met_path_in, met_tag_in, date_time, & ! 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 - ! sqz Jan 2025: added G5DAS bkg + ! sqz+reichle, 8 Apr 2025: added G5BKG (replacing "Nx+-") + ! ! --------------------------------------------------------------------------- implicit none - character(*), intent(in) :: met_path_in - character(*), intent(in) :: met_tag_in + character(*), intent(in) :: met_path_in + character(*), intent(in) :: met_tag_in type(date_time_type), intent(in) :: date_time @@ -5017,7 +4997,6 @@ subroutine parse_G5DAS_met_tag( met_path_in, met_tag_in, date_time, & character( 80), intent(out) :: met_tag_out logical, intent(out) :: use_prec_corr - logical, intent(out) :: use_Predictor logical, intent(out) :: use_bkg ! local variables @@ -5272,8 +5251,6 @@ subroutine parse_G5DAS_met_tag( met_path_in, met_tag_in, date_time, & use_prec_corr = .false. - use_Predictor = .false. - use_bkg = .false. ! ----------------------------------------------------- @@ -5457,16 +5434,13 @@ subroutine parse_G5DAS_met_tag( met_path_in, met_tag_in, date_time, & use_prec_corr = .true. prec_tag = tmp_tag(ii)(5:len(tmp_tag(ii))) - - elseif (tmp_tag(ii)(1:4)=='Nx+-') then - - use_Predictor = .true. elseif (tmp_tag(ii)(1:3)=='bkg') then - use_bkg = .true. - - else + use_bkg = .true. + + else + err_msg = 'invalid met_tag_in, unknown optional tag segment' call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) @@ -5503,13 +5477,13 @@ subroutine parse_G5DAS_met_tag( met_path_in, met_tag_in, date_time, & end if - if ((.not. use_Predictor) .and. (index( met_tag_in, 'Nx+-')>0)) then + if ((.not. use_bkg) .and. (index( met_tag_in, 'bkg')>0)) then - err_msg = 'questionable met_tag_in: includes "Nx+-" but use_Predictor=.false.' + err_msg = 'questionable met_tag_in: includes "bkg" but use_bkg=.false.' call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) - + end if - + end subroutine parse_G5DAS_met_tag ! **************************************************************** @@ -6692,9 +6666,7 @@ program ut_parse_G5DAS_met_tag character( 80) :: met_tag_out logical :: use_prec_corr - logical :: use_Predictor logical :: use_bkg - ! other integer :: ii @@ -6705,12 +6677,12 @@ program ut_parse_G5DAS_met_tag met_tag_in_vec = (/ & 'gcmexpname' , & - 'gcmexpname__Nx+-' , & + 'gcmexpname__bkg' , & 'gcmexpname__bkg' , & 'gcmexpname__precCORRPREC', & - 'gcmexpname__precCORRPREC__Nx+-' , & - 'gcmexpname__Nx+-__precCORRPREC' , & - 'gcmexpname__qrecCORRPREC__Nx+-' /) + 'gcmexpname__precCORRPREC__bkg' , & + 'gcmexpname__bkg__precCORRPREC' , & + 'gcmexpname__qrecCORRPREC__bgk' /) do ii=1,N_met_tag_in @@ -6722,14 +6694,13 @@ program ut_parse_G5DAS_met_tag write (*,*) 'met_tag_in = ', trim(met_tag_in) call parse_G5DAS_met_tag( met_path_in, met_tag_in, & - met_path_default, met_path_prec, met_tag_out, use_prec_corr, use_Predictor ) + met_path_default, met_path_prec, met_tag_out, use_prec_corr, use_bkg ) write (*,*) 'met_path_default = ', trim(met_path_default) write (*,*) 'met_path_prec = ', trim(met_path_prec) write (*,*) 'met_tag_out = ', trim(met_tag_out) - write (*,*) 'use_prec_corr = ', use_prec_corr - write (*,*) 'use_Predictor = ', use_Predictor - write (*,*) 'use_bkg = ', use_bkg + write (*,*) 'use_prec_corr = ', use_prec_corr + write (*,*) 'use_bkg = ', use_bkg end do From 6a10dae708edf44a75f428593e26073ffa329351 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Tue, 8 Apr 2025 18:48:04 -0400 Subject: [PATCH 098/107] updated CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1dbb905a..42e521f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Updated subroutines read_obs_sm_ASCAT_EUMET(), read_obs_SMAP_halforbit_Tb(), read_obs_SMOS() and read_obs_MODIS_SCF() with hardcoded time ranges for when observations are available and should be read. - Revised variable names (SHORT_NAME) and descriptions (LONG_NAME) to match M21C file specs. - Renamed tilecoord%pfaf to %pfaf_index; added matlab tile file reader. +- Updated nomenclature of met forcing files for coupled land/atm DAS config ("Nx+-" --> "bkg.lfo_*"). ### Fixed From 2001f7a70ea8cf1b1bfea7fee28d6c725f42eb12 Mon Sep 17 00:00:00 2001 From: Matthew Thompson Date: Thu, 10 Apr 2025 09:36:48 -0400 Subject: [PATCH 099/107] Try to fix Github Actions --- .github/actions/ci-build/action.yml | 63 ++++++++++++++ .github/workflows/spack-ci.yml | 116 -------------------------- .github/workflows/workflow.yml | 122 +++++++++++++++++----------- 3 files changed, 136 insertions(+), 165 deletions(-) create mode 100644 .github/actions/ci-build/action.yml delete mode 100644 .github/workflows/spack-ci.yml diff --git a/.github/actions/ci-build/action.yml b/.github/actions/ci-build/action.yml new file mode 100644 index 00000000..d7c7f37f --- /dev/null +++ b/.github/actions/ci-build/action.yml @@ -0,0 +1,63 @@ +name: "Build and Test GEOSldas" +description: "Build and test GEOSldas" + +# Define the inputs for this action +inputs: + fortran-compiler: + description: "The Fortran compiler to use" + required: true + cmake-build-type: + description: "The CMake build type" + required: true + cmake-generator: + description: "The CMake generator to use" + required: true + extra-cmake-args: + description: "Extra CMake arguments" + required: false + +runs: + using: "composite" + + steps: + # https://github.com/orgs/community/discussions/25678#discussioncomment-5242449 + - name: Delete huge unnecessary tools folder + shell: bash + run: rm -rf /opt/hostedtoolcache + + - name: Set all directories as git safe + shell: bash + run: | + git config --global --add safe.directory '*' + + - name: Versions etc. + shell: bash + run: | + ${{ inputs.fortran-compiler }} --version + mpirun --version + echo $BASEDIR + + - name: Mepo clone external repos + shell: bash + run: | + mepo clone --partial blobless + mepo status + + - name: Update other branches + shell: bash + if: + "!contains('refs/heads/main,refs/heads/develop', github.ref)" + run: | + mepo checkout-if-exists ${GITHUB_HEAD_REF} + mepo status + + - name: CMake + shell: bash + run: | + cmake -B build -DCMAKE_Fortran_COMPILER=${{ inputs.fortran-compiler }} -DCMAKE_INSTALL_PREFIX=install -DCMAKE_BUILD_TYPE=${{ inputs.cmake-build-type }} -DUSE_F2PY=OFF -G "${{ inputs.cmake-generator }}" "${{ inputs.extra-cmake-args }}" + + - name: Build + shell: bash + run: | + cmake --build build --parallel 4 + cmake --install build diff --git a/.github/workflows/spack-ci.yml b/.github/workflows/spack-ci.yml deleted file mode 100644 index cb38a474..00000000 --- a/.github/workflows/spack-ci.yml +++ /dev/null @@ -1,116 +0,0 @@ -name: Spack CI GCC Build - -on: - pull_request: - types: [opened, synchronize, reopened] - # Do not run if the only files changed cannot affect the build - paths-ignore: - - "**.md" - - "**.pro" - - "**.sh" - - "**.perl" - - ".github/CODEOWNERS" - workflow_dispatch: - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} - -jobs: - build_ldas: - name: Spack CI GCC Build - runs-on: ubuntu-24.04 - steps: - - - name: Checkout LDAS - uses: actions/checkout@v4 - with: - fetch-depth: 1 - filter: blob:none - repository: GEOS-ESM/GEOSldas - - - name: Set all directories as git safe - run: | - git config --global --add safe.directory '*' - - - name: Setup Python - uses: actions/setup-python@v5 - with: - python-version: '3.13' - - - name: Pip install mepo - run: | - python -m pip install --upgrade pip - pip install mepo - mepo --version - - - name: Mepo clone external repos - run: | - ls - mepo clone --partial blobless - mepo status - - - name: Update other branches - if: - "!contains('refs/heads/main,refs/heads/develop', github.ref)" - run: | - mepo checkout-if-exists ${GITHUB_HEAD_REF} - mepo status - - - name: Set up Spack - uses: spack/setup-spack@v2 - with: - ref: develop # Spack version (examples: develop, releases/v0.21) - color: true # Force color output (SPACK_COLOR=always) - path: spack # Where to clone Spack - buildcache: false # Do not use the spack buildcache - - - name: Find compilers - shell: spack-bash {0} - run: | - spack compiler find - - - name: Set default compiler and target - shell: spack-bash {0} - run: | - spack config add 'packages:all:compiler:[gcc@14.2.0]' - spack config add 'packages:all:require:target=x86_64_v3' - - - name: Create Spack environment - shell: spack-bash {0} - run: | - spack env create spack-env - spack env activate spack-env - - - name: Login - shell: spack-bash {0} - run: | - spack -e spack-env mirror add geos-buildcache oci://ghcr.io/GEOS-ESM/geos-buildcache - spack -e spack-env mirror set --oci-username ${{ github.actor }} --oci-password "${{ secrets.BUILDCACHE_TOKEN }}" geos-buildcache - spack -e spack-env mirror list - spack -e spack-env buildcache update-index geos-buildcache - spack -e spack-env buildcache list --allarch - - - name: Concretize - shell: spack-bash {0} - run: | - spack -e spack-env concretize - - - name: Install - shell: spack-bash {0} - run: | - spack -e spack-env install --add --no-check-signature --use-buildcache only \ - esmf gftl gftl-shared fargparse pflogger pfunit yafyaml ecbuild udunits openblas - - - name: Build with Cmake - shell: spack-bash {0} - run: | - spack env activate spack-env - spack load \ - esmf gftl gftl-shared fargparse pflogger pfunit yafyaml ecbuild udunits openblas - spack find --loaded - FC=gfortran-14 CC=gcc-14 CXX=g++-14 - cmake -B build -S . -DCMAKE_INSTALL_PREFIX=$PWD/install -DCMAKE_BUILD_TYPE=Debug -DUSE_F2PY=OFF -DCMAKE_Fortran_COMPILER=${FC} -DCMAKE_C_COMPILER=${CC} -DCMAKE_CXX_COMPILER=${CXX} - cmake --build build -j 4 - cmake --install build - diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index b594390a..5ce76d8a 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -10,69 +10,93 @@ on: - "**.sh" - "**.perl" - ".github/CODEOWNERS" - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} + - ".github/PULL_REQUEST_TEMPLATE.md" + - ".editorconfig" + - ".codebuild/**" + - ".circleci/**" jobs: - build_ldas: - name: Build GEOSldas - if: "!contains(github.event.pull_request.labels.*.name, '0 diff trivial')" - runs-on: ubuntu-24.04 + build_test_ldas_gnu: + name: gfortran / ${{ matrix.cmake-build-type }} / ${{ matrix.cmake-generator }} + runs-on: ubuntu-latest container: - image: gmao/ubuntu24-geos-env:v7.32.0-intelmpi_2021.13-ifort_2021.13 - # Per https://github.com/actions/virtual-environments/issues/1445#issuecomment-713861495 - # It seems like we might not need secrets on GitHub Actions which is good for forked - # pull requests - #credentials: - #username: ${{ secrets.DOCKERHUB_USERNAME }} - #password: ${{ secrets.DOCKERHUB_TOKEN }} - + image: gmao/ubuntu24-geos-env-mkl:v7.32.0-openmpi_5.0.5-gcc_14.2.0 + strategy: + fail-fast: false + matrix: + cmake-build-type: [Debug, Release] + cmake-generator: [Unix Makefiles] env: OMPI_ALLOW_RUN_AS_ROOT: 1 OMPI_ALLOW_RUN_AS_ROOT_CONFIRM: 1 OMPI_MCA_btl_vader_single_copy_mechanism: none - steps: - # https://github.com/orgs/community/discussions/25678#discussioncomment-5242449 - - name: Delete huge unnecessary tools folder - run: rm -rf /opt/hostedtoolcache - - - name: Checkout LDAS + - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 1 filter: blob:none repository: GEOS-ESM/GEOSldas - - name: Set all directories as git safe - run: | - git config --global --add safe.directory '*' - - - name: Versions etc. - run: | - ifort --version - mpirun --version - echo $BASEDIR - - - name: Mepo clone external repos - run: | - mepo clone --partial blobless - mepo status + - name: Build and Test GEOSldas + uses: ./.github/actions/ci-build + with: + cmake-build-type: ${{ matrix.cmake-build-type }} + cmake-generator: ${{ matrix.cmake-generator }} + fortran-compiler: gfortran + extra-cmake-args: -DMPIEXEC_PREFLAGS='--oversubscribe' - - name: Update other branches - if: - "!contains('refs/heads/main,refs/heads/develop', github.ref)" - run: | - mepo checkout-if-exists ${GITHUB_HEAD_REF} - mepo status + build_test_geosldas_ifort: + name: ifort / ${{ matrix.cmake-build-type }} / ${{ matrix.cmake-generator }} + runs-on: ubuntu-latest + container: + image: gmao/ubuntu24-geos-env:v7.32.0-intelmpi_2021.13-ifort_2021.13 + strategy: + fail-fast: false + matrix: + cmake-build-type: [Debug, Release] + cmake-generator: [Unix Makefiles] + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 1 + filter: blob:none + repository: GEOS-ESM/GEOSldas - - name: CMake - run: | - cmake -B build -S . --install-prefix=${pwd}/install -DCMAKE_Fortran_COMPILER=ifort -DCMAKE_BUILD_TYPE=Debug -DMPIEXEC_PREFLAGS='--oversubscribe' -DUSE_F2PY=OFF + - name: Build and Test GEOSldas + uses: ./.github/actions/ci-build + with: + cmake-build-type: ${{ matrix.cmake-build-type }} + cmake-generator: ${{ matrix.cmake-generator }} + fortran-compiler: ifort - - name: Build - run: | - cmake --build build -j 4 - cmake --install build + # We cannot currently test with ifx because HDF4 Fortran interface + # cannot be compiled with ifx. The HDF4 Fortran interface is required + # for the GEOSldas + ################################################################################ + # build_test_geosldas_ifx: # + # name: ifx / ${{ matrix.cmake-build-type }} / ${{ matrix.cmake-generator }} # + # runs-on: ubuntu-latest # + # container: # + # image: gmao/ubuntu24-geos-env:v7.32.0-intelmpi_2021.14-ifx_2025.0 # + # strategy: # + # fail-fast: false # + # matrix: # + # cmake-build-type: [Debug, Release] # + # cmake-generator: [Unix Makefiles] # + # steps: # + # - name: Checkout # + # uses: actions/checkout@v4 # + # with: # + # fetch-depth: 1 # + # filter: blob:none # + # repository: GEOS-ESM/GEOSldas # + # # + # - name: Build and Test GEOSldas # + # uses: ./.github/actions/ci-build # + # with: # + # cmake-build-type: ${{ matrix.cmake-build-type }} # + # cmake-generator: ${{ matrix.cmake-generator }} # + # fortran-compiler: ifx # + ################################################################################ From 7a11aa45342ab03eae9ebdbdfc5ee5ec3acead1c Mon Sep 17 00:00:00 2001 From: Matthew Thompson Date: Thu, 10 Apr 2025 10:06:48 -0400 Subject: [PATCH 100/107] Back to old-school --- .github/actions/ci-build/action.yml | 63 ----------- .github/workflows/workflow.yml | 163 ++++++++++++++++------------ 2 files changed, 95 insertions(+), 131 deletions(-) delete mode 100644 .github/actions/ci-build/action.yml diff --git a/.github/actions/ci-build/action.yml b/.github/actions/ci-build/action.yml deleted file mode 100644 index d7c7f37f..00000000 --- a/.github/actions/ci-build/action.yml +++ /dev/null @@ -1,63 +0,0 @@ -name: "Build and Test GEOSldas" -description: "Build and test GEOSldas" - -# Define the inputs for this action -inputs: - fortran-compiler: - description: "The Fortran compiler to use" - required: true - cmake-build-type: - description: "The CMake build type" - required: true - cmake-generator: - description: "The CMake generator to use" - required: true - extra-cmake-args: - description: "Extra CMake arguments" - required: false - -runs: - using: "composite" - - steps: - # https://github.com/orgs/community/discussions/25678#discussioncomment-5242449 - - name: Delete huge unnecessary tools folder - shell: bash - run: rm -rf /opt/hostedtoolcache - - - name: Set all directories as git safe - shell: bash - run: | - git config --global --add safe.directory '*' - - - name: Versions etc. - shell: bash - run: | - ${{ inputs.fortran-compiler }} --version - mpirun --version - echo $BASEDIR - - - name: Mepo clone external repos - shell: bash - run: | - mepo clone --partial blobless - mepo status - - - name: Update other branches - shell: bash - if: - "!contains('refs/heads/main,refs/heads/develop', github.ref)" - run: | - mepo checkout-if-exists ${GITHUB_HEAD_REF} - mepo status - - - name: CMake - shell: bash - run: | - cmake -B build -DCMAKE_Fortran_COMPILER=${{ inputs.fortran-compiler }} -DCMAKE_INSTALL_PREFIX=install -DCMAKE_BUILD_TYPE=${{ inputs.cmake-build-type }} -DUSE_F2PY=OFF -G "${{ inputs.cmake-generator }}" "${{ inputs.extra-cmake-args }}" - - - name: Build - shell: bash - run: | - cmake --build build --parallel 4 - cmake --install build diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 5ce76d8a..4ae6a952 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -10,93 +10,120 @@ on: - "**.sh" - "**.perl" - ".github/CODEOWNERS" - - ".github/PULL_REQUEST_TEMPLATE.md" - - ".editorconfig" - - ".codebuild/**" - - ".circleci/**" + - ".circleci/config.yml" + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} jobs: - build_test_ldas_gnu: - name: gfortran / ${{ matrix.cmake-build-type }} / ${{ matrix.cmake-generator }} - runs-on: ubuntu-latest + build_ldas_ifort: + name: Build GEOSldas with ifort + if: "!contains(github.event.pull_request.labels.*.name, '0 diff trivial')" + runs-on: ubuntu-24.04 container: - image: gmao/ubuntu24-geos-env-mkl:v7.32.0-openmpi_5.0.5-gcc_14.2.0 - strategy: - fail-fast: false - matrix: - cmake-build-type: [Debug, Release] - cmake-generator: [Unix Makefiles] + image: gmao/ubuntu24-geos-env:v7.32.0-intelmpi_2021.13-ifort_2021.13 + env: OMPI_ALLOW_RUN_AS_ROOT: 1 OMPI_ALLOW_RUN_AS_ROOT_CONFIRM: 1 OMPI_MCA_btl_vader_single_copy_mechanism: none + steps: - - name: Checkout + # https://github.com/orgs/community/discussions/25678#discussioncomment-5242449 + - name: Delete huge unnecessary tools folder + run: rm -rf /opt/hostedtoolcache + + - name: Checkout LDAS uses: actions/checkout@v4 with: fetch-depth: 1 filter: blob:none repository: GEOS-ESM/GEOSldas - - name: Build and Test GEOSldas - uses: ./.github/actions/ci-build - with: - cmake-build-type: ${{ matrix.cmake-build-type }} - cmake-generator: ${{ matrix.cmake-generator }} - fortran-compiler: gfortran - extra-cmake-args: -DMPIEXEC_PREFLAGS='--oversubscribe' - - build_test_geosldas_ifort: - name: ifort / ${{ matrix.cmake-build-type }} / ${{ matrix.cmake-generator }} - runs-on: ubuntu-latest + - name: Set all directories as git safe + run: | + git config --global --add safe.directory '*' + + - name: Versions etc. + run: | + ifort --version + mpirun --version + echo $BASEDIR + + - name: Mepo clone external repos + run: | + mepo clone --partial blobless + mepo status + + - name: Update other branches + if: + "!contains('refs/heads/main,refs/heads/develop', github.ref)" + run: | + mepo checkout-if-exists ${GITHUB_HEAD_REF} + mepo status + + - name: CMake + run: | + cmake -B build -S . --install-prefix=${pwd}/install -DCMAKE_Fortran_COMPILER=ifort -DCMAKE_BUILD_TYPE=Debug -DMPIEXEC_PREFLAGS='--oversubscribe' -DUSE_F2PY=OFF + + - name: Build + run: | + cmake --build build -j 4 + cmake --install build + + + build_ldas_gfortran: + name: Build GEOSldas with gfortran + if: "!contains(github.event.pull_request.labels.*.name, '0 diff trivial')" + runs-on: ubuntu-24.04 container: - image: gmao/ubuntu24-geos-env:v7.32.0-intelmpi_2021.13-ifort_2021.13 - strategy: - fail-fast: false - matrix: - cmake-build-type: [Debug, Release] - cmake-generator: [Unix Makefiles] + image: gmao/ubuntu24-geos-env:v7.32.0-openmpi_5.0.5-gcc_14.2.0 + + env: + OMPI_ALLOW_RUN_AS_ROOT: 1 + OMPI_ALLOW_RUN_AS_ROOT_CONFIRM: 1 + OMPI_MCA_btl_vader_single_copy_mechanism: none + steps: - - name: Checkout + # https://github.com/orgs/community/discussions/25678#discussioncomment-5242449 + - name: Delete huge unnecessary tools folder + run: rm -rf /opt/hostedtoolcache + + - name: Checkout LDAS uses: actions/checkout@v4 with: fetch-depth: 1 filter: blob:none repository: GEOS-ESM/GEOSldas - - name: Build and Test GEOSldas - uses: ./.github/actions/ci-build - with: - cmake-build-type: ${{ matrix.cmake-build-type }} - cmake-generator: ${{ matrix.cmake-generator }} - fortran-compiler: ifort - - # We cannot currently test with ifx because HDF4 Fortran interface - # cannot be compiled with ifx. The HDF4 Fortran interface is required - # for the GEOSldas - ################################################################################ - # build_test_geosldas_ifx: # - # name: ifx / ${{ matrix.cmake-build-type }} / ${{ matrix.cmake-generator }} # - # runs-on: ubuntu-latest # - # container: # - # image: gmao/ubuntu24-geos-env:v7.32.0-intelmpi_2021.14-ifx_2025.0 # - # strategy: # - # fail-fast: false # - # matrix: # - # cmake-build-type: [Debug, Release] # - # cmake-generator: [Unix Makefiles] # - # steps: # - # - name: Checkout # - # uses: actions/checkout@v4 # - # with: # - # fetch-depth: 1 # - # filter: blob:none # - # repository: GEOS-ESM/GEOSldas # - # # - # - name: Build and Test GEOSldas # - # uses: ./.github/actions/ci-build # - # with: # - # cmake-build-type: ${{ matrix.cmake-build-type }} # - # cmake-generator: ${{ matrix.cmake-generator }} # - # fortran-compiler: ifx # - ################################################################################ + - name: Set all directories as git safe + run: | + git config --global --add safe.directory '*' + + - name: Versions etc. + run: | + gfortran --version + mpirun --version + echo $BASEDIR + + - name: Mepo clone external repos + run: | + mepo clone --partial blobless + mepo status + + - name: Update other branches + if: + "!contains('refs/heads/main,refs/heads/develop', github.ref)" + run: | + mepo checkout-if-exists ${GITHUB_HEAD_REF} + mepo status + + - name: CMake + run: | + cmake -B build -S . --install-prefix=${pwd}/install -DCMAKE_Fortran_COMPILER=gfortran -DCMAKE_BUILD_TYPE=Debug -DMPIEXEC_PREFLAGS='--oversubscribe' -DUSE_F2PY=OFF + + - name: Build + run: | + cmake --build build -j 4 + cmake --install build From cc295ba08ea9fb72dce7ae5c5d2b09035538f700 Mon Sep 17 00:00:00 2001 From: Matthew Thompson Date: Thu, 10 Apr 2025 13:25:34 -0400 Subject: [PATCH 101/107] Use MKL image --- .github/workflows/workflow.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 4ae6a952..9ae989ef 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -78,7 +78,7 @@ jobs: if: "!contains(github.event.pull_request.labels.*.name, '0 diff trivial')" runs-on: ubuntu-24.04 container: - image: gmao/ubuntu24-geos-env:v7.32.0-openmpi_5.0.5-gcc_14.2.0 + image: gmao/ubuntu24-geos-env-mkl:v7.32.0-openmpi_5.0.5-gcc_14.2.0 env: OMPI_ALLOW_RUN_AS_ROOT: 1 From f670c37cce002866727c936e89c374cdf8b9a527 Mon Sep 17 00:00:00 2001 From: saraqzhang Date: Thu, 10 Apr 2025 16:37:53 -0400 Subject: [PATCH 102/107] addtional collections to HISTens.rc and forcing filename bkg.lfo_ modified: GEOSldas_App/GEOSldas_HISTens.rc modified: GEOSldas_App/ldas_setup modified: GEOSmetforce_GridComp/LDAS_Forcing.F90 --- GEOSldas_App/GEOSldas_HISTens.rc | 130 ++++++++++++++++++++++++- GEOSldas_App/ldas_setup | 2 + GEOSmetforce_GridComp/LDAS_Forcing.F90 | 24 ++--- 3 files changed, 142 insertions(+), 14 deletions(-) diff --git a/GEOSldas_App/GEOSldas_HISTens.rc b/GEOSldas_App/GEOSldas_HISTens.rc index 25aa0908..e61e25f9 100644 --- a/GEOSldas_App/GEOSldas_HISTens.rc +++ b/GEOSldas_App/GEOSldas_HISTens.rc @@ -19,7 +19,7 @@ # # ################################################################################## - +VERSION: 1 EXPID: GEOSldas_expid COLLECTIONS: @@ -55,8 +55,36 @@ COLLECTIONS: 'catch_progn_incr0030' 'catch_progn_incr0031' 'catch_progn_incr0032' - +'inst3_2d_lndfcstana_Nx' +'tavg3_1d_lnd_Nt' :: + +GRID_LABELS: PC720x361-DC + PC576x361-DC + PC360x181-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 + +PC360x181-DC.GRID_TYPE: LatLon +PC360x181-DC.IM_WORLD: 360 +PC360x181-DC.JM_WORLD: 181 +PC360x181-DC.POLE: PC +PC360x181-DC.DATELINE: DC +PC360x181-DC.LM: 1 + + 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', @@ -1081,3 +1109,101 @@ catch_progn_incr0032.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0032' , 'SNDZN3_INCR' , 'CATCHINCR_e0032' , :: + + tavg3_1d_lnd_Nt.descr: 'Tile-space,Time-Averaged,Single-Level,Assimilation,Land Surface Diagnostics', + tavg3_1d_lnd_Nt.nbits: 12, + tavg3_1d_lnd_Nt.template: '%y4%m2%d2_%h2%n2z.bin', + tavg3_1d_lnd_Nt.mode: 'time-averaged', + tavg3_1d_lnd_Nt.frequency: 030000, + tavg3_1d_lnd_Nt.ref_time: 000000, + tavg3_1d_lnd_Nt.fields: 'WET3' , 'ENSAVG' , 'GWETPROF' , + 'WET2' , 'ENSAVG' , 'GWETROOT' , + 'WET1' , 'ENSAVG' , 'GWETTOP' , + 'WCPR' , 'ENSAVG' , 'PRMC' , + 'WCRZ' , 'ENSAVG' , 'RZMC' , + 'WCSF' , 'ENSAVG' , 'SFMC' , + 'TPSNOW' , 'ENSAVG' , + 'TPUNST' , 'ENSAVG' , 'TUNST' , + 'TPSAT' , 'ENSAVG' , 'TSAT' , + 'TPWLT' , 'ENSAVG' , 'TWLT' , + 'TPSURF' , 'ENSAVG' , 'TSURF' , + 'GRN' , 'VEGDYN_e0001' , + 'LAI' , 'VEGDYN_e0001' , + 'TP1' , 'ENSAVG' , + 'TP2' , 'ENSAVG' , + 'TP3' , 'ENSAVG' , + 'TP4' , 'ENSAVG' , + 'TP5' , 'ENSAVG' , + 'TP6' , 'ENSAVG' , + 'PRLAND' , 'ENSAVG' , 'PRECTOTLAND' , + 'SNOLAND' , 'ENSAVG' , 'PRECSNOLAND' , + 'TSLAND' , 'ENSAVG' , 'SNOMAS' , + 'SNOWDP' , 'ENSAVG' , 'SNODP' , + 'EVPSOI' , 'ENSAVG' , 'EVPSOIL' , + 'EVPVEG' , 'ENSAVG' , 'EVPTRNS' , + 'EVPINT' , 'ENSAVG' , 'EVPINTR' , + 'EVPICE' , 'ENSAVG' , 'EVPSBLN' , + 'RUNSURF' , 'ENSAVG' , 'RUNOFF' , + 'BASEFLOW' , 'ENSAVG' , + 'SMLAND' , 'ENSAVG' , + 'QINFIL' , 'ENSAVG' , + 'FRUST' , 'ENSAVG' , 'FRUNST' , + 'FRSAT' , 'ENSAVG' , + 'ASNOW' , 'ENSAVG' , 'FRSNO' , + 'FRWLT' , 'ENSAVG' , + 'DFPARLAND' , 'ENSAVG' , 'PARDFLAND' , + 'DRPARLAND' , 'ENSAVG' , 'PARDRLAND' , + 'SHLAND' , 'ENSAVG' , + 'LHLAND' , 'ENSAVG' , + 'EVLAND' , 'ENSAVG' , + 'LWLAND' , 'ENSAVG' , + 'SWLAND' , 'ENSAVG' , + 'GHLAND' , 'ENSAVG' , + 'TWLAND' , 'ENSAVG' , + 'TELAND' , 'ENSAVG' , + 'DWLAND' , 'ENSAVG' , 'WCHANGE' , + 'DHLAND' , 'ENSAVG' , 'ECHANGE' , + 'SPLAND' , 'ENSAVG' , + 'SPWATR' , 'ENSAVG' , + 'SPSNOW' , 'ENSAVG' , + 'PEATCLSM_WATERLEVEL', 'ENSAVG' , + 'PEATCLSM_FSWCHANGE' , 'ENSAVG' , +:: + + inst3_2d_lndfcstana_Nx.descr: '2d,3-Hourly,Instantaneous,Single-Level,Assimilation,Ensemble Land Forecast and Analysis Diagnostics', + inst3_2d_lndfcstana_Nx.nbits: 12, + inst3_2d_lndfcstana_Nx.template: '%y4%m2%d2_%h2%n2z.nc4', + inst3_2d_lndfcstana_Nx.archive: '%c/Y%y4', + 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: 'GRIDNAME', + inst3_2d_lndfcstana_Nx.grid_label: PC360x181-DC, + inst3_2d_lndfcstana_Nx.deflate: 2, + 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' , + 'TP1' , 'ENSAVG' , 'TSOIL1_FCST' , + 'WCSF_ENSSTD' , 'ENSAVG' , 'SFMC_FCST_ENSSTD' , + 'WCRZ_ENSSTD' , 'ENSAVG' , 'RZMC_FCST_ENSSTD' , + 'WCPR_ENSSTD' , 'ENSAVG' , 'PRMC_FCST_ENSSTD' , + 'TPSURF_ENSSTD' , 'ENSAVG' , 'TSURF_FCST_ENSSTD' , + 'TP1_ENSSTD' , 'ENSAVG' , 'TSOIL1_FCST_ENSSTD' , + 'WCSF_ANA' , 'LANDASSIM' , 'SFMC_ANA' , + 'WCRZ_ANA' , 'LANDASSIM' , 'RZMC_ANA' , + 'WCPR_ANA' , 'LANDASSIM' , 'PRMC_ANA' , + 'TPSURF_ANA' , 'LANDASSIM' , 'TSURF_ANA' , + 'TP1_ANA' , 'LANDASSIM' , 'TSOIL1_ANA' , + 'WCSF_ANA_ENSSTD' , 'LANDASSIM' , 'SFMC_ANA_ENSSTD' , + 'WCRZ_ANA_ENSSTD' , 'LANDASSIM' , 'RZMC_ANA_ENSSTD' , + 'WCPR_ANA_ENSSTD' , 'LANDASSIM' , 'PRMC_ANA_ENSSTD' , + 'TPSURF_ANA_ENSSTD' , 'LANDASSIM' , 'TSURF_ANA_ENSSTD' , + 'TP1_ANA_ENSSTD' , 'LANDASSIM' , 'TSOIL1_ANA_ENSSTD' + :: + + + diff --git a/GEOSldas_App/ldas_setup b/GEOSldas_App/ldas_setup index 9bde285a..aeb152d4 100755 --- a/GEOSldas_App/ldas_setup +++ b/GEOSldas_App/ldas_setup @@ -1132,6 +1132,8 @@ class LDASsetup: shutil.copy2(rcfile, tmprcfile) for line in fileinput.input(tmprcfile,inplace=True): print (line.rstrip().replace('GEOSldas_expid',self.rqdExeInp['EXP_ID'])) + for line in fileinput.input(tmprcfile,inplace=True): + print (line.rstrip().replace('GRIDNAME',self.rqdExeInp['GRIDNAME'])) # just copy an empty ExtData.rc if shortfile=='ExtData.rc' : diff --git a/GEOSmetforce_GridComp/LDAS_Forcing.F90 b/GEOSmetforce_GridComp/LDAS_Forcing.F90 index 24126b59..b5fc1ea6 100644 --- a/GEOSmetforce_GridComp/LDAS_Forcing.F90 +++ b/GEOSmetforce_GridComp/LDAS_Forcing.F90 @@ -3268,18 +3268,18 @@ subroutine get_GEOS( date_time, force_dtstep, met_path, met_tag, & ! 1 2 3 4 ! 1234567890123456789012345678901234567890 - G5BKG_defs( 1,3) = 'bkg.tavg1_2d_lfo ' - G5BKG_defs( 2,3) = 'bkg.tavg1_2d_lfo ' - G5BKG_defs( 3,3) = 'bkg.tavg1_2d_lfo ' - G5BKG_defs( 4,3) = 'bkg.tavg1_2d_lfo ' - G5BKG_defs( 5,3) = 'bkg.tavg1_2d_lfo ' - G5BKG_defs( 6,3) = 'bkg.tavg1_2d_lfo ' - G5BKG_defs( 7,3) = 'bkg.tavg1_2d_lfo ' - G5BKG_defs( 8,3) = 'bkg.inst1_2d_lfo ' - G5BKG_defs( 9,3) = 'bkg.inst1_2d_lfo ' - G5BKG_defs(10,3) = 'bkg.inst1_2d_lfo ' - G5BKG_defs(11,3) = 'bkg.inst1_2d_lfo ' - G5BKG_defs(12,3) = 'bkg.inst1_2d_lfo ' + G5BKG_defs( 1,3) = 'bkg.lfo_tavg ' + G5BKG_defs( 2,3) = 'bkg.lfo_tavg ' + G5BKG_defs( 3,3) = 'bkg.lfo_tavg ' + G5BKG_defs( 4,3) = 'bkg.lfo_tavg ' + G5BKG_defs( 5,3) = 'bkg.lfo_tavg ' + G5BKG_defs( 6,3) = 'bkg.lfo_tavg ' + G5BKG_defs( 7,3) = 'bkg.lfo_tavg ' + G5BKG_defs( 8,3) = 'bkg.lfo_inst ' + G5BKG_defs( 9,3) = 'bkg.lfo_inst ' + G5BKG_defs(10,3) = 'bkg.lfo_inst ' + G5BKG_defs(11,3) = 'bkg.lfo_inst ' + G5BKG_defs(12,3) = 'bkg.lfo_inst ' G5BKG_defs( 1,4) = 'rs ' G5BKG_defs( 2,4) = 'rs ' From 88da354ddbb25cf390543d929b5cf190de2112b8 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Fri, 11 Apr 2025 11:38:02 -0400 Subject: [PATCH 103/107] commented out lndfcstana collection (so not written by default), moved lnd and lndfcstana collection defs to top of file, cleaned up indent (GEOSldas_HISTens.rc) --- GEOSldas_App/GEOSldas_HISTens.rc | 204 +++++++++++++++---------------- 1 file changed, 101 insertions(+), 103 deletions(-) diff --git a/GEOSldas_App/GEOSldas_HISTens.rc b/GEOSldas_App/GEOSldas_HISTens.rc index e61e25f9..872be4ca 100644 --- a/GEOSldas_App/GEOSldas_HISTens.rc +++ b/GEOSldas_App/GEOSldas_HISTens.rc @@ -1,11 +1,10 @@ - # # Sample GEOSldas HISTORY.rc file for LADAS (atm ensemble) # # - 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 +# - The catch_progn_incr portion of the sample file was generated with the utility script # "GEOSldas/src/Components/GEOSldas_GridComp/GEOSldas_App/util/config/generate_catchincr_hist.py". # # - The sample file triggers output of the GEOSldas "catch_progn_incr" collection in @@ -17,12 +16,13 @@ # - The "catch_progn_incr" output is in tile space, which must be the same for # GEOSldas and ADASens. # -# ################################################################################## -VERSION: 1 + EXPID: GEOSldas_expid COLLECTIONS: +'tavg3_1d_lnd_Nt' +#'inst3_2d_lndfcstana_Nx' 'catch_progn_incr0001' 'catch_progn_incr0002' 'catch_progn_incr0003' @@ -55,8 +55,6 @@ COLLECTIONS: 'catch_progn_incr0030' 'catch_progn_incr0031' 'catch_progn_incr0032' -'inst3_2d_lndfcstana_Nx' -'tavg3_1d_lnd_Nt' :: GRID_LABELS: PC720x361-DC @@ -85,6 +83,103 @@ PC360x181-DC.DATELINE: DC PC360x181-DC.LM: 1 +tavg3_1d_lnd_Nt.descr: 'Tile-space,Time-Averaged,Single-Level,Assimilation,Land Surface Diagnostics', +tavg3_1d_lnd_Nt.nbits: 12, +tavg3_1d_lnd_Nt.template: '%y4%m2%d2_%h2%n2z.bin', +tavg3_1d_lnd_Nt.mode: 'time-averaged', +tavg3_1d_lnd_Nt.frequency: 030000, +tavg3_1d_lnd_Nt.ref_time: 000000, +tavg3_1d_lnd_Nt.fields: 'WET3' , 'ENSAVG' , 'GWETPROF' , + 'WET2' , 'ENSAVG' , 'GWETROOT' , + 'WET1' , 'ENSAVG' , 'GWETTOP' , + 'WCPR' , 'ENSAVG' , 'PRMC' , + 'WCRZ' , 'ENSAVG' , 'RZMC' , + 'WCSF' , 'ENSAVG' , 'SFMC' , + 'TPSNOW' , 'ENSAVG' , + 'TPUNST' , 'ENSAVG' , 'TUNST' , + 'TPSAT' , 'ENSAVG' , 'TSAT' , + 'TPWLT' , 'ENSAVG' , 'TWLT' , + 'TPSURF' , 'ENSAVG' , 'TSURF' , + 'GRN' , 'VEGDYN_e0001' , + 'LAI' , 'VEGDYN_e0001' , + 'TP1' , 'ENSAVG' , + 'TP2' , 'ENSAVG' , + 'TP3' , 'ENSAVG' , + 'TP4' , 'ENSAVG' , + 'TP5' , 'ENSAVG' , + 'TP6' , 'ENSAVG' , + 'PRLAND' , 'ENSAVG' , 'PRECTOTLAND' , + 'SNOLAND' , 'ENSAVG' , 'PRECSNOLAND' , + 'TSLAND' , 'ENSAVG' , 'SNOMAS' , + 'SNOWDP' , 'ENSAVG' , 'SNODP' , + 'EVPSOI' , 'ENSAVG' , 'EVPSOIL' , + 'EVPVEG' , 'ENSAVG' , 'EVPTRNS' , + 'EVPINT' , 'ENSAVG' , 'EVPINTR' , + 'EVPICE' , 'ENSAVG' , 'EVPSBLN' , + 'RUNSURF' , 'ENSAVG' , 'RUNOFF' , + 'BASEFLOW' , 'ENSAVG' , + 'SMLAND' , 'ENSAVG' , + 'QINFIL' , 'ENSAVG' , + 'FRUST' , 'ENSAVG' , 'FRUNST' , + 'FRSAT' , 'ENSAVG' , + 'ASNOW' , 'ENSAVG' , 'FRSNO' , + 'FRWLT' , 'ENSAVG' , + 'DFPARLAND' , 'ENSAVG' , 'PARDFLAND' , + 'DRPARLAND' , 'ENSAVG' , 'PARDRLAND' , + 'SHLAND' , 'ENSAVG' , + 'LHLAND' , 'ENSAVG' , + 'EVLAND' , 'ENSAVG' , + 'LWLAND' , 'ENSAVG' , + 'SWLAND' , 'ENSAVG' , + 'GHLAND' , 'ENSAVG' , + 'TWLAND' , 'ENSAVG' , + 'TELAND' , 'ENSAVG' , + 'DWLAND' , 'ENSAVG' , 'WCHANGE' , + 'DHLAND' , 'ENSAVG' , 'ECHANGE' , + 'SPLAND' , 'ENSAVG' , + 'SPWATR' , 'ENSAVG' , + 'SPSNOW' , 'ENSAVG' , + 'PEATCLSM_WATERLEVEL', 'ENSAVG' , + 'PEATCLSM_FSWCHANGE' , 'ENSAVG' , +:: + + +inst3_2d_lndfcstana_Nx.descr: '2d,3-Hourly,Instantaneous,Single-Level,Assimilation,Ensemble Land Forecast and Analysis Diagnostics', +inst3_2d_lndfcstana_Nx.nbits: 12, +inst3_2d_lndfcstana_Nx.template: '%y4%m2%d2_%h2%n2z.nc4', +inst3_2d_lndfcstana_Nx.archive: '%c/Y%y4', +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: 'GRIDNAME', +inst3_2d_lndfcstana_Nx.grid_label: PC360x181-DC, +inst3_2d_lndfcstana_Nx.deflate: 2, +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' , + 'TP1' , 'ENSAVG' , 'TSOIL1_FCST' , + 'WCSF_ENSSTD' , 'ENSAVG' , 'SFMC_FCST_ENSSTD' , + 'WCRZ_ENSSTD' , 'ENSAVG' , 'RZMC_FCST_ENSSTD' , + 'WCPR_ENSSTD' , 'ENSAVG' , 'PRMC_FCST_ENSSTD' , + 'TPSURF_ENSSTD' , 'ENSAVG' , 'TSURF_FCST_ENSSTD' , + 'TP1_ENSSTD' , 'ENSAVG' , 'TSOIL1_FCST_ENSSTD' , + 'WCSF_ANA' , 'LANDASSIM' , 'SFMC_ANA' , + 'WCRZ_ANA' , 'LANDASSIM' , 'RZMC_ANA' , + 'WCPR_ANA' , 'LANDASSIM' , 'PRMC_ANA' , + 'TPSURF_ANA' , 'LANDASSIM' , 'TSURF_ANA' , + 'TP1_ANA' , 'LANDASSIM' , 'TSOIL1_ANA' , + 'WCSF_ANA_ENSSTD' , 'LANDASSIM' , 'SFMC_ANA_ENSSTD' , + 'WCRZ_ANA_ENSSTD' , 'LANDASSIM' , 'RZMC_ANA_ENSSTD' , + 'WCPR_ANA_ENSSTD' , 'LANDASSIM' , 'PRMC_ANA_ENSSTD' , + 'TPSURF_ANA_ENSSTD' , 'LANDASSIM' , 'TSURF_ANA_ENSSTD' , + 'TP1_ANA_ENSSTD' , 'LANDASSIM' , 'TSOIL1_ANA_ENSSTD' +:: + + 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', @@ -1110,100 +1205,3 @@ catch_progn_incr0032.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0032' , :: - tavg3_1d_lnd_Nt.descr: 'Tile-space,Time-Averaged,Single-Level,Assimilation,Land Surface Diagnostics', - tavg3_1d_lnd_Nt.nbits: 12, - tavg3_1d_lnd_Nt.template: '%y4%m2%d2_%h2%n2z.bin', - tavg3_1d_lnd_Nt.mode: 'time-averaged', - tavg3_1d_lnd_Nt.frequency: 030000, - tavg3_1d_lnd_Nt.ref_time: 000000, - tavg3_1d_lnd_Nt.fields: 'WET3' , 'ENSAVG' , 'GWETPROF' , - 'WET2' , 'ENSAVG' , 'GWETROOT' , - 'WET1' , 'ENSAVG' , 'GWETTOP' , - 'WCPR' , 'ENSAVG' , 'PRMC' , - 'WCRZ' , 'ENSAVG' , 'RZMC' , - 'WCSF' , 'ENSAVG' , 'SFMC' , - 'TPSNOW' , 'ENSAVG' , - 'TPUNST' , 'ENSAVG' , 'TUNST' , - 'TPSAT' , 'ENSAVG' , 'TSAT' , - 'TPWLT' , 'ENSAVG' , 'TWLT' , - 'TPSURF' , 'ENSAVG' , 'TSURF' , - 'GRN' , 'VEGDYN_e0001' , - 'LAI' , 'VEGDYN_e0001' , - 'TP1' , 'ENSAVG' , - 'TP2' , 'ENSAVG' , - 'TP3' , 'ENSAVG' , - 'TP4' , 'ENSAVG' , - 'TP5' , 'ENSAVG' , - 'TP6' , 'ENSAVG' , - 'PRLAND' , 'ENSAVG' , 'PRECTOTLAND' , - 'SNOLAND' , 'ENSAVG' , 'PRECSNOLAND' , - 'TSLAND' , 'ENSAVG' , 'SNOMAS' , - 'SNOWDP' , 'ENSAVG' , 'SNODP' , - 'EVPSOI' , 'ENSAVG' , 'EVPSOIL' , - 'EVPVEG' , 'ENSAVG' , 'EVPTRNS' , - 'EVPINT' , 'ENSAVG' , 'EVPINTR' , - 'EVPICE' , 'ENSAVG' , 'EVPSBLN' , - 'RUNSURF' , 'ENSAVG' , 'RUNOFF' , - 'BASEFLOW' , 'ENSAVG' , - 'SMLAND' , 'ENSAVG' , - 'QINFIL' , 'ENSAVG' , - 'FRUST' , 'ENSAVG' , 'FRUNST' , - 'FRSAT' , 'ENSAVG' , - 'ASNOW' , 'ENSAVG' , 'FRSNO' , - 'FRWLT' , 'ENSAVG' , - 'DFPARLAND' , 'ENSAVG' , 'PARDFLAND' , - 'DRPARLAND' , 'ENSAVG' , 'PARDRLAND' , - 'SHLAND' , 'ENSAVG' , - 'LHLAND' , 'ENSAVG' , - 'EVLAND' , 'ENSAVG' , - 'LWLAND' , 'ENSAVG' , - 'SWLAND' , 'ENSAVG' , - 'GHLAND' , 'ENSAVG' , - 'TWLAND' , 'ENSAVG' , - 'TELAND' , 'ENSAVG' , - 'DWLAND' , 'ENSAVG' , 'WCHANGE' , - 'DHLAND' , 'ENSAVG' , 'ECHANGE' , - 'SPLAND' , 'ENSAVG' , - 'SPWATR' , 'ENSAVG' , - 'SPSNOW' , 'ENSAVG' , - 'PEATCLSM_WATERLEVEL', 'ENSAVG' , - 'PEATCLSM_FSWCHANGE' , 'ENSAVG' , -:: - - inst3_2d_lndfcstana_Nx.descr: '2d,3-Hourly,Instantaneous,Single-Level,Assimilation,Ensemble Land Forecast and Analysis Diagnostics', - inst3_2d_lndfcstana_Nx.nbits: 12, - inst3_2d_lndfcstana_Nx.template: '%y4%m2%d2_%h2%n2z.nc4', - inst3_2d_lndfcstana_Nx.archive: '%c/Y%y4', - 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: 'GRIDNAME', - inst3_2d_lndfcstana_Nx.grid_label: PC360x181-DC, - inst3_2d_lndfcstana_Nx.deflate: 2, - 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' , - 'TP1' , 'ENSAVG' , 'TSOIL1_FCST' , - 'WCSF_ENSSTD' , 'ENSAVG' , 'SFMC_FCST_ENSSTD' , - 'WCRZ_ENSSTD' , 'ENSAVG' , 'RZMC_FCST_ENSSTD' , - 'WCPR_ENSSTD' , 'ENSAVG' , 'PRMC_FCST_ENSSTD' , - 'TPSURF_ENSSTD' , 'ENSAVG' , 'TSURF_FCST_ENSSTD' , - 'TP1_ENSSTD' , 'ENSAVG' , 'TSOIL1_FCST_ENSSTD' , - 'WCSF_ANA' , 'LANDASSIM' , 'SFMC_ANA' , - 'WCRZ_ANA' , 'LANDASSIM' , 'RZMC_ANA' , - 'WCPR_ANA' , 'LANDASSIM' , 'PRMC_ANA' , - 'TPSURF_ANA' , 'LANDASSIM' , 'TSURF_ANA' , - 'TP1_ANA' , 'LANDASSIM' , 'TSOIL1_ANA' , - 'WCSF_ANA_ENSSTD' , 'LANDASSIM' , 'SFMC_ANA_ENSSTD' , - 'WCRZ_ANA_ENSSTD' , 'LANDASSIM' , 'RZMC_ANA_ENSSTD' , - 'WCPR_ANA_ENSSTD' , 'LANDASSIM' , 'PRMC_ANA_ENSSTD' , - 'TPSURF_ANA_ENSSTD' , 'LANDASSIM' , 'TSURF_ANA_ENSSTD' , - 'TP1_ANA_ENSSTD' , 'LANDASSIM' , 'TSOIL1_ANA_ENSSTD' - :: - - - From 185f057a35b91dcfdf11ee1b6589241eed11d2f5 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Mon, 14 Apr 2025 15:19:56 -0400 Subject: [PATCH 104/107] re-instated "Nx+-" functionality for optional segment in MET_TAG to ensure backward compatibility with LDAS regression tests (to be cleaned up later) (LDAS_Forcing.F90) --- GEOSmetforce_GridComp/LDAS_Forcing.F90 | 34 +++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/GEOSmetforce_GridComp/LDAS_Forcing.F90 b/GEOSmetforce_GridComp/LDAS_Forcing.F90 index b5fc1ea6..607dbcf0 100644 --- a/GEOSmetforce_GridComp/LDAS_Forcing.F90 +++ b/GEOSmetforce_GridComp/LDAS_Forcing.F90 @@ -3798,6 +3798,19 @@ subroutine get_GEOS( date_time, force_dtstep, met_path, met_tag, & GEOSgcm_defs(1:N_G5DAS_vars,:) = GEOSIT_defs else if ( use_bkg ) then GEOSgcm_defs(1:N_G5DAS_vars,:) = G5BKG_defs + + ! +++++++++++++++++++++++++++++ + ! for now, keep 'Nx+-' to ensure backward compatibility w/ regression tests; 'Nx+-' is obsolete otherwise + ! - reichle, 14 Apr 2025 + if (index(met_tag, 'Nx+-') > 0) then ! "met_tag" here is as specified in LDAS.rc, incl. optional tag segments + GEOSgcm_defs(1:N_G5DAS_vars,:) = G5DAS_defs + ! append "+-" to GCM file tag (ie, replace "Nx" with "Nx+-") + do j=1,N_GEOSgcm_vars + GEOSgcm_defs(j,3) = trim(GEOSgcm_defs(j,3)) // '+-' + end do + end if + ! +++++++++++++++++++++++++++++ + else GEOSgcm_defs(1:N_G5DAS_vars,:) = G5DAS_defs end if @@ -5435,8 +5448,12 @@ subroutine parse_G5DAS_met_tag( met_path_in, met_tag_in, date_time, & prec_tag = tmp_tag(ii)(5:len(tmp_tag(ii))) - elseif (tmp_tag(ii)(1:3)=='bkg') then - + elseif ( (tmp_tag(ii)(1:3)=='bkg') .or. (tmp_tag(ii)(1:4)=='Nx+-') ) then + ! ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + ! for now, keep 'Nx+-' to ensure backward compatibility w/ regression tests; 'Nx+-' is obsolete otherwise + ! - reichle, 14 Apr 2025 + ! +++++++++++++++++++++++++++++ + use_bkg = .true. else @@ -5467,7 +5484,7 @@ subroutine parse_G5DAS_met_tag( met_path_in, met_tag_in, date_time, & ! Double-check if optional tag segments were somehow missed, e.g., ! because they were accidentally appended with single underscores. ! Assumes that "prec" and "Nx+-" never appear in GEOS-5 product names. - ! Does NOT protect against spelling errors, e.g., "__perc" or "__Nx-+". + ! Does NOT protect against spelling errors, e.g., "__perc" or "__bgk" or "__Nx-+". ! - reichle, 24 Nov 2015 if ((.not. use_prec_corr) .and. (index( met_tag_in, 'prec')>0)) then @@ -5483,7 +5500,16 @@ subroutine parse_G5DAS_met_tag( met_path_in, met_tag_in, date_time, & call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) end if - + + ! +++++++++++++++++++++++++++++ + ! for now, keep 'Nx+-' to ensure backward compatibility w/ regression tests; 'Nx+-' is obsolete otherwise + ! - reichle, 14 Apr 2025 + if ((.not. use_bkg) .and. (index( met_tag_in, 'Nx+-')>0)) then + err_msg = 'questionable met_tag_in: includes "Nx+-" but use_bkg=.false.' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + end if + ! +++++++++++++++++++++++++++++ + end subroutine parse_G5DAS_met_tag ! **************************************************************** From f239bc74354730f4212e53cc309fd489c0bb24b5 Mon Sep 17 00:00:00 2001 From: Rolf Reichle <54944691+gmao-rreichle@users.noreply.github.com> Date: Mon, 14 Apr 2025 16:24:49 -0400 Subject: [PATCH 105/107] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4038dee2..c72a175b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,7 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Updated subroutines read_obs_sm_ASCAT_EUMET(), read_obs_SMAP_halforbit_Tb(), read_obs_SMOS() and read_obs_MODIS_SCF() with hardcoded time ranges for when observations are available and should be read. - Revised variable names (SHORT_NAME) and descriptions (LONG_NAME) to match M21C file specs. - Renamed tilecoord%pfaf to %pfaf_index; added matlab tile file reader. -- Updated nomenclature of met forcing files for coupled land/atm DAS config ("Nx+-" --> "bkg.lfo_*"). +- Improved setup of coupled land/atm DAS (incl. changed nomenclature of met forcing files: "Nx+-" --> "bkg.lfo_*"). ### Fixed From 44bea7091e123b872594da7b9d9fdfea0e9a2439 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Tue, 15 Apr 2025 11:50:25 -0400 Subject: [PATCH 106/107] edited change log in prep for release v2.0.0 (CHANGELOG.md) --- CHANGELOG.md | 52 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c72a175b..6a2193db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,48 +11,60 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- New update_type for joint 3d soil moisture and 1d snow analysis (Tb+sfmc+sfds+SCF obs). -- Added CYGNSS soil moisture reader. -- Added M21C surface met forcing. -- Add Github Actions workflow for testing and building GEOSldas_GridComp. - ### Changed -- Updated subroutine read_obs_sm_ASCAT_EUMET() to work with both original and revised file name templates. -- Updated subroutines read_obs_sm_ASCAT_EUMET(), read_obs_SMAP_halforbit_Tb(), read_obs_SMOS() and read_obs_MODIS_SCF() with hardcoded time ranges for when observations are available and should be read. -- Revised variable names (SHORT_NAME) and descriptions (LONG_NAME) to match M21C file specs. -- Renamed tilecoord%pfaf to %pfaf_index; added matlab tile file reader. -- Improved setup of coupled land/atm DAS (incl. changed nomenclature of met forcing files: "Nx+-" --> "bkg.lfo_*"). - ### Fixed ### Removed -- Removed support for SLES12 operating system at NCCS. - ### Deprecated ----------------------------- +## [v2.0.0] - 2025-04-15 + +- 0-diff vs. v1.1.0 + +### Added + +- New update_type for joint 3d soil moisture and 1d snow analysis (Tb+sfmc+sfds+SCF obs) ([PR #68](https://github.com/GEOS-ESM/GEOSldas_GridComp/pull/68)). +- Updated subroutine read_obs_sm_ASCAT_EUMET() to work with both original and revised file name templates ([PR #69](https://github.com/GEOS-ESM/GEOSldas_GridComp/pull/69)). +- Added CYGNSS soil moisture reader ([PR #76](https://github.com/GEOS-ESM/GEOSldas_GridComp/pull/76)). +- Added M21C surface met forcing ([PR #77](https://github.com/GEOS-ESM/GEOSldas_GridComp/pull/77)). +- Added Github Actions workflow for testing and building GEOSldas_GridComp ([PR #86](https://github.com/GEOS-ESM/GEOSldas_GridComp/pull/86)). + +### Changed + +- Revised variable names (SHORT_NAME) and descriptions (LONG_NAME) to match M21C file specs ([PR #72](https://github.com/GEOS-ESM/GEOSldas_GridComp/pull/72)). +- Updated subroutines read_obs_sm_ASCAT_EUMET(), read_obs_SMAP_halforbit_Tb(), read_obs_SMOS() and read_obs_MODIS_SCF() with hardcoded time ranges for when observations are available and should be read ([PR #73](https://github.com/GEOS-ESM/GEOSldas_GridComp/pull/73)). +- Renamed tilecoord%pfaf to %pfaf_index; added matlab tile file reader ([PR #78](https://github.com/GEOS-ESM/GEOSldas_GridComp/pull/78)). +- Improved setup of coupled land/atm DAS (incl. changed nomenclature of met forcing files: "Nx+-" --> "bkg.lfo_*") ([PR #81](https://github.com/GEOS-ESM/GEOSldas_GridComp/pull/81)). + +### Removed + +- Removed support for SLES12 operating system at NCCS ([PR #83](https://github.com/GEOS-ESM/GEOSldas_GridComp/pull/83)). + +----------------------------- + ## [v1.1.0] - 2024-11-05 - 0-diff vs. v1.0.2 except for data assimilation in cube-sphere tile space ([PR #41](https://github.com/GEOS-ESM/GEOSldas_GridComp/pull/41)). ### Changed -- More optimal distribution of tiles on processors for cubed-sphere tile space. -- Updates to scripting to allow for Intel MPI. +- More optimal distribution of tiles on processors for cubed-sphere tile space ([PR #41](https://github.com/GEOS-ESM/GEOSldas_GridComp/pull/41)). +- Updates to scripting to allow for Intel MPI ([PR #57](https://github.com/GEOS-ESM/GEOSldas_GridComp/pull/57)). ### Fixed -- Do not increment CO2_YEAR when it is a no-data-value. For Catchment simulations, exclude CatchCN-specific resource variables from LDAS.rc. -- Bug fix and improved efficiency in matlab script for generation of mwRTM_param. -- Changed EXPDIR to absolute path for POSTPROC_HIST>0 option to work. -- Support HISTORY output of ASNOW alone from ENSAVG Gridcomp. +- Do not increment CO2_YEAR when it is a no-data-value; for Catchment simulations, exclude CatchCN-specific resource variables from LDAS.rc ([PR #51](https://github.com/GEOS-ESM/GEOSldas_GridComp/pull/51)). +- Bug fix and improved efficiency in matlab script for generation of mwRTM_param ([PR #46](https://github.com/GEOS-ESM/GEOSldas_GridComp/pull/46)). +- Changed EXPDIR to absolute path for POSTPROC_HIST>0 option to work ([PR #42](https://github.com/GEOS-ESM/GEOSldas_GridComp/pull/42)). +- Support HISTORY output of ASNOW alone from ENSAVG Gridcomp ([PR #49](https://github.com/GEOS-ESM/GEOSldas_GridComp/pull/49)). ### Removed -- Remove restart options F and G. +- Remove restart options F and G ([PR #40](https://github.com/GEOS-ESM/GEOSldas_GridComp/pull/40)). ----------------------------- From 25f0f3b625f205be089f6f729854a38f37a23dda Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Tue, 15 Apr 2025 11:54:36 -0400 Subject: [PATCH 107/107] minimal edit (CHANGELOG.md) --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a2193db..949a160c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,7 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [v2.0.0] - 2025-04-15 -- 0-diff vs. v1.1.0 +- 0-diff vs. v1.1.0. ### Added